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);
|
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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) */
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user