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:
Oliver Hartkopp 2022-09-12 19:07:23 +02:00 committed by Marc Kleine-Budde
parent 1a3e3034c0
commit fb08cba12b
4 changed files with 101 additions and 20 deletions

View File

@ -187,6 +187,20 @@ void can_free_echo_skb(struct net_device *dev, unsigned int idx,
} }
EXPORT_SYMBOL_GPL(can_free_echo_skb); 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 *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
{ {
struct sk_buff *skb; 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->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST; init_can_skb_reserve(skb);
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)->ifindex = dev->ifindex; can_skb_prv(skb)->ifindex = dev->ifindex;
can_skb_prv(skb)->skbcnt = 0;
*cf = skb_put_zero(skb, sizeof(struct can_frame)); *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->protocol = htons(ETH_P_CANFD);
skb->pkt_type = PACKET_BROADCAST; init_can_skb_reserve(skb);
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)->ifindex = dev->ifindex; can_skb_prv(skb)->ifindex = dev->ifindex;
can_skb_prv(skb)->skbcnt = 0;
*cfd = skb_put_zero(skb, sizeof(struct canfd_frame)); *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); 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 *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
{ {
struct sk_buff *skb; struct sk_buff *skb;
@ -319,6 +350,11 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
goto inval_skb; goto inval_skb;
break; break;
case ETH_P_CANXL:
if (!can_is_canxl_skb(skb))
goto inval_skb;
break;
default: default:
goto inval_skb; goto inval_skb;
} }

View File

@ -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_can_skb(struct net_device *dev, struct can_frame **cf);
struct sk_buff *alloc_canfd_skb(struct net_device *dev, struct sk_buff *alloc_canfd_skb(struct net_device *dev,
struct canfd_frame **cfd); 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 sk_buff *alloc_can_err_skb(struct net_device *dev,
struct can_frame **cf); struct can_frame **cf);
bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb); 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); 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) 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; const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
if (can_is_canxl_skb(skb))
return cxl->len;
return cfd->len; return cfd->len;
} }

View File

@ -138,6 +138,7 @@
#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */ #define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */
#define ETH_P_CAN 0x000C /* CAN: Controller Area Network */ #define ETH_P_CAN 0x000C /* CAN: Controller Area Network */
#define ETH_P_CANFD 0x000D /* CANFD: CAN flexible data rate*/ #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_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/
#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */ #define ETH_P_TR_802_2 0x0011 /* 802.2 frames */
#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */ #define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */

View File

@ -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; struct can_pkg_stats *pkg_stats = dev_net(skb->dev)->can.pkg_stats;
int err = -EINVAL; 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); skb->protocol = htons(ETH_P_CAN);
} else if (can_is_canfd_skb(skb)) { } else if (can_is_canfd_skb(skb)) {
struct canfd_frame *cfd = (struct canfd_frame *)skb->data; 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; 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 */ /* af_can protocol functions */
/** /**
@ -826,6 +843,11 @@ static struct packet_type canfd_packet __read_mostly = {
.func = canfd_rcv, .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 = { static const struct net_proto_family can_family_ops = {
.family = PF_CAN, .family = PF_CAN,
.create = can_create, .create = can_create,
@ -865,6 +887,7 @@ static __init int can_init(void)
dev_add_pack(&can_packet); dev_add_pack(&can_packet);
dev_add_pack(&canfd_packet); dev_add_pack(&canfd_packet);
dev_add_pack(&canxl_packet);
return 0; return 0;