Skip to content

Commit

Permalink
can: canxl: update CAN infrastructure for CAN XL frames
Browse files Browse the repository at this point in the history
- 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>
  • Loading branch information
Oliver Hartkopp authored and Marc Kleine-Budde committed Sep 15, 2022
1 parent 1a3e303 commit fb08cba
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 20 deletions.
72 changes: 54 additions & 18 deletions drivers/net/can/dev/skb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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));

Expand All @@ -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));

Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
23 changes: 22 additions & 1 deletion include/linux/can/skb.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/if_ether.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) */
Expand Down
25 changes: 24 additions & 1 deletion net/can/af_can.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 */

/**
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit fb08cba

Please sign in to comment.