can: canxl: update CAN infrastructure for CAN XL frames
- add new ETH_P_CANXL ethernet protocol type - update skb checks for CAN XL - add alloc_canxl_skb() which now needs a data length parameter - introduce init_can_skb_reserve() to reduce code duplication Acked-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr> Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Link: https://lore.kernel.org/all/20220912170725.120748-6-socketcan@hartkopp.net Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
parent
1a3e3034c0
commit
fb08cba12b
@ -187,6 +187,20 @@ void can_free_echo_skb(struct net_device *dev, unsigned int idx,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_free_echo_skb);
|
||||
|
||||
/* fill common values for CAN sk_buffs */
|
||||
static void init_can_skb_reserve(struct sk_buff *skb)
|
||||
{
|
||||
skb->pkt_type = PACKET_BROADCAST;
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_transport_header(skb);
|
||||
|
||||
can_skb_reserve(skb);
|
||||
can_skb_prv(skb)->skbcnt = 0;
|
||||
}
|
||||
|
||||
struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
@ -200,16 +214,8 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
|
||||
}
|
||||
|
||||
skb->protocol = htons(ETH_P_CAN);
|
||||
skb->pkt_type = PACKET_BROADCAST;
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_transport_header(skb);
|
||||
|
||||
can_skb_reserve(skb);
|
||||
init_can_skb_reserve(skb);
|
||||
can_skb_prv(skb)->ifindex = dev->ifindex;
|
||||
can_skb_prv(skb)->skbcnt = 0;
|
||||
|
||||
*cf = skb_put_zero(skb, sizeof(struct can_frame));
|
||||
|
||||
@ -231,16 +237,8 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
|
||||
}
|
||||
|
||||
skb->protocol = htons(ETH_P_CANFD);
|
||||
skb->pkt_type = PACKET_BROADCAST;
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_transport_header(skb);
|
||||
|
||||
can_skb_reserve(skb);
|
||||
init_can_skb_reserve(skb);
|
||||
can_skb_prv(skb)->ifindex = dev->ifindex;
|
||||
can_skb_prv(skb)->skbcnt = 0;
|
||||
|
||||
*cfd = skb_put_zero(skb, sizeof(struct canfd_frame));
|
||||
|
||||
@ -251,6 +249,39 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(alloc_canfd_skb);
|
||||
|
||||
struct sk_buff *alloc_canxl_skb(struct net_device *dev,
|
||||
struct canxl_frame **cxl,
|
||||
unsigned int data_len)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (data_len < CANXL_MIN_DLEN || data_len > CANXL_MAX_DLEN)
|
||||
goto out_error;
|
||||
|
||||
skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
|
||||
CANXL_HDR_SIZE + data_len);
|
||||
if (unlikely(!skb))
|
||||
goto out_error;
|
||||
|
||||
skb->protocol = htons(ETH_P_CANXL);
|
||||
init_can_skb_reserve(skb);
|
||||
can_skb_prv(skb)->ifindex = dev->ifindex;
|
||||
|
||||
*cxl = skb_put_zero(skb, CANXL_HDR_SIZE + data_len);
|
||||
|
||||
/* set CAN XL flag and length information by default */
|
||||
(*cxl)->flags = CANXL_XLF;
|
||||
(*cxl)->len = data_len;
|
||||
|
||||
return skb;
|
||||
|
||||
out_error:
|
||||
*cxl = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(alloc_canxl_skb);
|
||||
|
||||
struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
@ -319,6 +350,11 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
|
||||
goto inval_skb;
|
||||
break;
|
||||
|
||||
case ETH_P_CANXL:
|
||||
if (!can_is_canxl_skb(skb))
|
||||
goto inval_skb;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto inval_skb;
|
||||
}
|
||||
|
@ -30,6 +30,9 @@ void can_free_echo_skb(struct net_device *dev, unsigned int idx,
|
||||
struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf);
|
||||
struct sk_buff *alloc_canfd_skb(struct net_device *dev,
|
||||
struct canfd_frame **cfd);
|
||||
struct sk_buff *alloc_canxl_skb(struct net_device *dev,
|
||||
struct canxl_frame **cxl,
|
||||
unsigned int data_len);
|
||||
struct sk_buff *alloc_can_err_skb(struct net_device *dev,
|
||||
struct can_frame **cf);
|
||||
bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb);
|
||||
@ -114,11 +117,29 @@ static inline bool can_is_canfd_skb(const struct sk_buff *skb)
|
||||
return (skb->len == CANFD_MTU && cfd->len <= CANFD_MAX_DLEN);
|
||||
}
|
||||
|
||||
/* get length element value from can[fd]_frame structure */
|
||||
static inline bool can_is_canxl_skb(const struct sk_buff *skb)
|
||||
{
|
||||
const struct canxl_frame *cxl = (struct canxl_frame *)skb->data;
|
||||
|
||||
if (skb->len < CANXL_HDR_SIZE + CANXL_MIN_DLEN || skb->len > CANXL_MTU)
|
||||
return false;
|
||||
|
||||
/* this also checks valid CAN XL data length boundaries */
|
||||
if (skb->len != CANXL_HDR_SIZE + cxl->len)
|
||||
return false;
|
||||
|
||||
return cxl->flags & CANXL_XLF;
|
||||
}
|
||||
|
||||
/* get length element value from can[|fd|xl]_frame structure */
|
||||
static inline unsigned int can_skb_get_len_val(struct sk_buff *skb)
|
||||
{
|
||||
const struct canxl_frame *cxl = (struct canxl_frame *)skb->data;
|
||||
const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
|
||||
if (can_is_canxl_skb(skb))
|
||||
return cxl->len;
|
||||
|
||||
return cfd->len;
|
||||
}
|
||||
|
||||
|
@ -138,6 +138,7 @@
|
||||
#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */
|
||||
#define ETH_P_CAN 0x000C /* CAN: Controller Area Network */
|
||||
#define ETH_P_CANFD 0x000D /* CANFD: CAN flexible data rate*/
|
||||
#define ETH_P_CANXL 0x000E /* CANXL: eXtended frame Length */
|
||||
#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/
|
||||
#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */
|
||||
#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */
|
||||
|
@ -202,7 +202,9 @@ int can_send(struct sk_buff *skb, int loop)
|
||||
struct can_pkg_stats *pkg_stats = dev_net(skb->dev)->can.pkg_stats;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (can_is_can_skb(skb)) {
|
||||
if (can_is_canxl_skb(skb)) {
|
||||
skb->protocol = htons(ETH_P_CANXL);
|
||||
} else if (can_is_can_skb(skb)) {
|
||||
skb->protocol = htons(ETH_P_CAN);
|
||||
} else if (can_is_canfd_skb(skb)) {
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
@ -702,6 +704,21 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
return NET_RX_SUCCESS;
|
||||
}
|
||||
|
||||
static int canxl_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *pt, struct net_device *orig_dev)
|
||||
{
|
||||
if (unlikely(dev->type != ARPHRD_CAN || (!can_is_canxl_skb(skb)))) {
|
||||
pr_warn_once("PF_CAN: dropped non conform CAN XL skbuff: dev type %d, len %d\n",
|
||||
dev->type, skb->len);
|
||||
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
can_receive(skb, dev);
|
||||
return NET_RX_SUCCESS;
|
||||
}
|
||||
|
||||
/* af_can protocol functions */
|
||||
|
||||
/**
|
||||
@ -826,6 +843,11 @@ static struct packet_type canfd_packet __read_mostly = {
|
||||
.func = canfd_rcv,
|
||||
};
|
||||
|
||||
static struct packet_type canxl_packet __read_mostly = {
|
||||
.type = cpu_to_be16(ETH_P_CANXL),
|
||||
.func = canxl_rcv,
|
||||
};
|
||||
|
||||
static const struct net_proto_family can_family_ops = {
|
||||
.family = PF_CAN,
|
||||
.create = can_create,
|
||||
@ -865,6 +887,7 @@ static __init int can_init(void)
|
||||
|
||||
dev_add_pack(&can_packet);
|
||||
dev_add_pack(&canfd_packet);
|
||||
dev_add_pack(&canxl_packet);
|
||||
|
||||
return 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user