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

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>

authored by

Oliver Hartkopp and committed by
Marc Kleine-Budde
fb08cba1 1a3e3034

+101 -20
+54 -18
drivers/net/can/dev/skb.c
··· 187 187 } 188 188 EXPORT_SYMBOL_GPL(can_free_echo_skb); 189 189 190 + /* fill common values for CAN sk_buffs */ 191 + static void init_can_skb_reserve(struct sk_buff *skb) 192 + { 193 + skb->pkt_type = PACKET_BROADCAST; 194 + skb->ip_summed = CHECKSUM_UNNECESSARY; 195 + 196 + skb_reset_mac_header(skb); 197 + skb_reset_network_header(skb); 198 + skb_reset_transport_header(skb); 199 + 200 + can_skb_reserve(skb); 201 + can_skb_prv(skb)->skbcnt = 0; 202 + } 203 + 190 204 struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) 191 205 { 192 206 struct sk_buff *skb; ··· 214 200 } 215 201 216 202 skb->protocol = htons(ETH_P_CAN); 217 - skb->pkt_type = PACKET_BROADCAST; 218 - skb->ip_summed = CHECKSUM_UNNECESSARY; 219 - 220 - skb_reset_mac_header(skb); 221 - skb_reset_network_header(skb); 222 - skb_reset_transport_header(skb); 223 - 224 - can_skb_reserve(skb); 203 + init_can_skb_reserve(skb); 225 204 can_skb_prv(skb)->ifindex = dev->ifindex; 226 - can_skb_prv(skb)->skbcnt = 0; 227 205 228 206 *cf = skb_put_zero(skb, sizeof(struct can_frame)); 229 207 ··· 237 231 } 238 232 239 233 skb->protocol = htons(ETH_P_CANFD); 240 - skb->pkt_type = PACKET_BROADCAST; 241 - skb->ip_summed = CHECKSUM_UNNECESSARY; 242 - 243 - skb_reset_mac_header(skb); 244 - skb_reset_network_header(skb); 245 - skb_reset_transport_header(skb); 246 - 247 - can_skb_reserve(skb); 234 + init_can_skb_reserve(skb); 248 235 can_skb_prv(skb)->ifindex = dev->ifindex; 249 - can_skb_prv(skb)->skbcnt = 0; 250 236 251 237 *cfd = skb_put_zero(skb, sizeof(struct canfd_frame)); 252 238 ··· 248 250 return skb; 249 251 } 250 252 EXPORT_SYMBOL_GPL(alloc_canfd_skb); 253 + 254 + struct sk_buff *alloc_canxl_skb(struct net_device *dev, 255 + struct canxl_frame **cxl, 256 + unsigned int data_len) 257 + { 258 + struct sk_buff *skb; 259 + 260 + if (data_len < CANXL_MIN_DLEN || data_len > CANXL_MAX_DLEN) 261 + goto out_error; 262 + 263 + skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + 264 + CANXL_HDR_SIZE + data_len); 265 + if (unlikely(!skb)) 266 + goto out_error; 267 + 268 + skb->protocol = htons(ETH_P_CANXL); 269 + init_can_skb_reserve(skb); 270 + can_skb_prv(skb)->ifindex = dev->ifindex; 271 + 272 + *cxl = skb_put_zero(skb, CANXL_HDR_SIZE + data_len); 273 + 274 + /* set CAN XL flag and length information by default */ 275 + (*cxl)->flags = CANXL_XLF; 276 + (*cxl)->len = data_len; 277 + 278 + return skb; 279 + 280 + out_error: 281 + *cxl = NULL; 282 + 283 + return NULL; 284 + } 285 + EXPORT_SYMBOL_GPL(alloc_canxl_skb); 251 286 252 287 struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf) 253 288 { ··· 347 316 348 317 case ETH_P_CANFD: 349 318 if (!can_is_canfd_skb(skb)) 319 + goto inval_skb; 320 + break; 321 + 322 + case ETH_P_CANXL: 323 + if (!can_is_canxl_skb(skb)) 350 324 goto inval_skb; 351 325 break; 352 326
+22 -1
include/linux/can/skb.h
··· 30 30 struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf); 31 31 struct sk_buff *alloc_canfd_skb(struct net_device *dev, 32 32 struct canfd_frame **cfd); 33 + struct sk_buff *alloc_canxl_skb(struct net_device *dev, 34 + struct canxl_frame **cxl, 35 + unsigned int data_len); 33 36 struct sk_buff *alloc_can_err_skb(struct net_device *dev, 34 37 struct can_frame **cf); 35 38 bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb); ··· 117 114 return (skb->len == CANFD_MTU && cfd->len <= CANFD_MAX_DLEN); 118 115 } 119 116 120 - /* get length element value from can[fd]_frame structure */ 117 + static inline bool can_is_canxl_skb(const struct sk_buff *skb) 118 + { 119 + const struct canxl_frame *cxl = (struct canxl_frame *)skb->data; 120 + 121 + if (skb->len < CANXL_HDR_SIZE + CANXL_MIN_DLEN || skb->len > CANXL_MTU) 122 + return false; 123 + 124 + /* this also checks valid CAN XL data length boundaries */ 125 + if (skb->len != CANXL_HDR_SIZE + cxl->len) 126 + return false; 127 + 128 + return cxl->flags & CANXL_XLF; 129 + } 130 + 131 + /* get length element value from can[|fd|xl]_frame structure */ 121 132 static inline unsigned int can_skb_get_len_val(struct sk_buff *skb) 122 133 { 134 + const struct canxl_frame *cxl = (struct canxl_frame *)skb->data; 123 135 const struct canfd_frame *cfd = (struct canfd_frame *)skb->data; 136 + 137 + if (can_is_canxl_skb(skb)) 138 + return cxl->len; 124 139 125 140 return cfd->len; 126 141 }
+1
include/uapi/linux/if_ether.h
··· 138 138 #define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */ 139 139 #define ETH_P_CAN 0x000C /* CAN: Controller Area Network */ 140 140 #define ETH_P_CANFD 0x000D /* CANFD: CAN flexible data rate*/ 141 + #define ETH_P_CANXL 0x000E /* CANXL: eXtended frame Length */ 141 142 #define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/ 142 143 #define ETH_P_TR_802_2 0x0011 /* 802.2 frames */ 143 144 #define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */
+24 -1
net/can/af_can.c
··· 202 202 struct can_pkg_stats *pkg_stats = dev_net(skb->dev)->can.pkg_stats; 203 203 int err = -EINVAL; 204 204 205 - if (can_is_can_skb(skb)) { 205 + if (can_is_canxl_skb(skb)) { 206 + skb->protocol = htons(ETH_P_CANXL); 207 + } else if (can_is_can_skb(skb)) { 206 208 skb->protocol = htons(ETH_P_CAN); 207 209 } else if (can_is_canfd_skb(skb)) { 208 210 struct canfd_frame *cfd = (struct canfd_frame *)skb->data; ··· 704 702 return NET_RX_SUCCESS; 705 703 } 706 704 705 + static int canxl_rcv(struct sk_buff *skb, struct net_device *dev, 706 + struct packet_type *pt, struct net_device *orig_dev) 707 + { 708 + if (unlikely(dev->type != ARPHRD_CAN || (!can_is_canxl_skb(skb)))) { 709 + pr_warn_once("PF_CAN: dropped non conform CAN XL skbuff: dev type %d, len %d\n", 710 + dev->type, skb->len); 711 + 712 + kfree_skb(skb); 713 + return NET_RX_DROP; 714 + } 715 + 716 + can_receive(skb, dev); 717 + return NET_RX_SUCCESS; 718 + } 719 + 707 720 /* af_can protocol functions */ 708 721 709 722 /** ··· 843 826 .func = canfd_rcv, 844 827 }; 845 828 829 + static struct packet_type canxl_packet __read_mostly = { 830 + .type = cpu_to_be16(ETH_P_CANXL), 831 + .func = canxl_rcv, 832 + }; 833 + 846 834 static const struct net_proto_family can_family_ops = { 847 835 .family = PF_CAN, 848 836 .create = can_create, ··· 887 865 888 866 dev_add_pack(&can_packet); 889 867 dev_add_pack(&canfd_packet); 868 + dev_add_pack(&canxl_packet); 890 869 891 870 return 0; 892 871