Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

can: skb: unify skb CAN frame identification helpers

Replace open coded checks for sk_buffs containing Classical CAN and
CAN FD frame structures as a preparation for CAN XL support.

With the added length check the unintended processing of CAN XL frames
having the CANXL_XLF bit set can be suppressed even when the skb->len
fits to non CAN XL frames.

The CAN_RAW socket needs a rework to use these helpers. Therefore the
use of these helpers is postponed to the CAN_RAW CAN XL integration.

The J1939 protocol gets a check for Classical CAN frames too.

Acked-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://lore.kernel.org/all/20220912170725.120748-2-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Oliver Hartkopp and committed by
Marc Kleine-Budde
96a7457a 1c679f91

+45 -54
+10 -8
drivers/net/can/dev/skb.c
··· 299 299 /* Drop a given socketbuffer if it does not contain a valid CAN frame. */ 300 300 bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb) 301 301 { 302 - const struct canfd_frame *cfd = (struct canfd_frame *)skb->data; 303 302 struct can_priv *priv = netdev_priv(dev); 304 303 305 - if (skb->protocol == htons(ETH_P_CAN)) { 306 - if (unlikely(skb->len != CAN_MTU || 307 - cfd->len > CAN_MAX_DLEN)) 304 + switch (ntohs(skb->protocol)) { 305 + case ETH_P_CAN: 306 + if (!can_is_can_skb(skb)) 308 307 goto inval_skb; 309 - } else if (skb->protocol == htons(ETH_P_CANFD)) { 310 - if (unlikely(skb->len != CANFD_MTU || 311 - cfd->len > CANFD_MAX_DLEN)) 308 + break; 309 + 310 + case ETH_P_CANFD: 311 + if (!can_is_canfd_skb(skb)) 312 312 goto inval_skb; 313 - } else { 313 + break; 314 + 315 + default: 314 316 goto inval_skb; 315 317 } 316 318
+11 -1
include/linux/can/skb.h
··· 97 97 return nskb; 98 98 } 99 99 100 + static inline bool can_is_can_skb(const struct sk_buff *skb) 101 + { 102 + struct can_frame *cf = (struct can_frame *)skb->data; 103 + 104 + /* the CAN specific type of skb is identified by its data length */ 105 + return (skb->len == CAN_MTU && cf->len <= CAN_MAX_DLEN); 106 + } 107 + 100 108 static inline bool can_is_canfd_skb(const struct sk_buff *skb) 101 109 { 110 + struct canfd_frame *cfd = (struct canfd_frame *)skb->data; 111 + 102 112 /* the CAN specific type of skb is identified by its data length */ 103 - return skb->len == CANFD_MTU; 113 + return (skb->len == CANFD_MTU && cfd->len <= CANFD_MAX_DLEN); 104 114 } 105 115 106 116 #endif /* !_CAN_SKB_H */
+10 -40
net/can/af_can.c
··· 199 199 int can_send(struct sk_buff *skb, int loop) 200 200 { 201 201 struct sk_buff *newskb = NULL; 202 - struct canfd_frame *cfd = (struct canfd_frame *)skb->data; 203 202 struct can_pkg_stats *pkg_stats = dev_net(skb->dev)->can.pkg_stats; 204 203 int err = -EINVAL; 205 204 206 - if (skb->len == CAN_MTU) { 205 + if (can_is_can_skb(skb)) { 207 206 skb->protocol = htons(ETH_P_CAN); 208 - if (unlikely(cfd->len > CAN_MAX_DLEN)) 209 - goto inval_skb; 210 - } else if (skb->len == CANFD_MTU) { 207 + } else if (can_is_canfd_skb(skb)) { 211 208 skb->protocol = htons(ETH_P_CANFD); 212 - if (unlikely(cfd->len > CANFD_MAX_DLEN)) 213 - goto inval_skb; 214 209 } else { 215 210 goto inval_skb; 216 211 } 217 212 218 - /* Make sure the CAN frame can pass the selected CAN netdevice. 219 - * As structs can_frame and canfd_frame are similar, we can provide 220 - * CAN FD frames to legacy CAN drivers as long as the length is <= 8 221 - */ 222 - if (unlikely(skb->len > skb->dev->mtu && cfd->len > CAN_MAX_DLEN)) { 213 + /* Make sure the CAN frame can pass the selected CAN netdevice. */ 214 + if (unlikely(skb->len > skb->dev->mtu)) { 223 215 err = -EMSGSIZE; 224 216 goto inval_skb; 225 217 } ··· 670 678 static int can_rcv(struct sk_buff *skb, struct net_device *dev, 671 679 struct packet_type *pt, struct net_device *orig_dev) 672 680 { 673 - struct canfd_frame *cfd = (struct canfd_frame *)skb->data; 674 - 675 - if (unlikely(dev->type != ARPHRD_CAN || skb->len != CAN_MTU)) { 681 + if (unlikely(dev->type != ARPHRD_CAN || (!can_is_can_skb(skb)))) { 676 682 pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d\n", 677 683 dev->type, skb->len); 678 - goto free_skb; 679 - } 680 684 681 - /* This check is made separately since cfd->len would be uninitialized if skb->len = 0. */ 682 - if (unlikely(cfd->len > CAN_MAX_DLEN)) { 683 - pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d, datalen %d\n", 684 - dev->type, skb->len, cfd->len); 685 - goto free_skb; 685 + kfree_skb(skb); 686 + return NET_RX_DROP; 686 687 } 687 688 688 689 can_receive(skb, dev); 689 690 return NET_RX_SUCCESS; 690 - 691 - free_skb: 692 - kfree_skb(skb); 693 - return NET_RX_DROP; 694 691 } 695 692 696 693 static int canfd_rcv(struct sk_buff *skb, struct net_device *dev, 697 694 struct packet_type *pt, struct net_device *orig_dev) 698 695 { 699 - struct canfd_frame *cfd = (struct canfd_frame *)skb->data; 700 - 701 - if (unlikely(dev->type != ARPHRD_CAN || skb->len != CANFD_MTU)) { 696 + if (unlikely(dev->type != ARPHRD_CAN || (!can_is_canfd_skb(skb)))) { 702 697 pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d\n", 703 698 dev->type, skb->len); 704 - goto free_skb; 705 - } 706 699 707 - /* This check is made separately since cfd->len would be uninitialized if skb->len = 0. */ 708 - if (unlikely(cfd->len > CANFD_MAX_DLEN)) { 709 - pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d, datalen %d\n", 710 - dev->type, skb->len, cfd->len); 711 - goto free_skb; 700 + kfree_skb(skb); 701 + return NET_RX_DROP; 712 702 } 713 703 714 704 can_receive(skb, dev); 715 705 return NET_RX_SUCCESS; 716 - 717 - free_skb: 718 - kfree_skb(skb); 719 - return NET_RX_DROP; 720 706 } 721 707 722 708 /* af_can protocol functions */
+7 -2
net/can/bcm.c
··· 648 648 return; 649 649 650 650 /* make sure to handle the correct frame type (CAN / CAN FD) */ 651 - if (skb->len != op->cfsiz) 652 - return; 651 + if (op->flags & CAN_FD_FRAME) { 652 + if (!can_is_canfd_skb(skb)) 653 + return; 654 + } else { 655 + if (!can_is_can_skb(skb)) 656 + return; 657 + } 653 658 654 659 /* disable timeout */ 655 660 hrtimer_cancel(&op->timer);
+2 -2
net/can/gw.c
··· 463 463 464 464 /* process strictly Classic CAN or CAN FD frames */ 465 465 if (gwj->flags & CGW_FLAGS_CAN_FD) { 466 - if (skb->len != CANFD_MTU) 466 + if (!can_is_canfd_skb(skb)) 467 467 return; 468 468 } else { 469 - if (skb->len != CAN_MTU) 469 + if (!can_is_can_skb(skb)) 470 470 return; 471 471 } 472 472
+1 -1
net/can/isotp.c
··· 669 669 if (cf->len <= CAN_MAX_DLEN) { 670 670 isotp_rcv_sf(sk, cf, SF_PCI_SZ4 + ae, skb, sf_dl); 671 671 } else { 672 - if (skb->len == CANFD_MTU) { 672 + if (can_is_canfd_skb(skb)) { 673 673 /* We have a CAN FD frame and CAN_DL is greater than 8: 674 674 * Only frames with the SF_DL == 0 ESC value are valid. 675 675 *
+4
net/can/j1939/main.c
··· 42 42 struct j1939_sk_buff_cb *skcb, *iskcb; 43 43 struct can_frame *cf; 44 44 45 + /* make sure we only get Classical CAN frames */ 46 + if (!can_is_can_skb(iskb)) 47 + return; 48 + 45 49 /* create a copy of the skb 46 50 * j1939 only delivers the real data bytes, 47 51 * the header goes into sockaddr.