From d4fb6514ff8ed6912a71294e6b66a5d59ee88007 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sun, 1 Feb 2026 15:33:16 +0100 Subject: can: use skb hash instead of private variable in headroom The can_skb_priv::skbcnt variable is used to identify CAN skbs in the RX path analogue to the skb->hash. As the skb hash is not filled in CAN skbs move the private skbcnt value to skb->hash and set skb->sw_hash accordingly. The skb->hash is a value used for RPS to identify skbs. Use it as intended. Signed-off-by: Marc Kleine-Budde Signed-off-by: Oliver Hartkopp Link: https://patch.msgid.link/20260201-can_skb_ext-v8-1-3635d790fe8b@hartkopp.net Signed-off-by: Paolo Abeni --- include/linux/can/core.h | 1 + include/linux/can/skb.h | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/can/core.h b/include/linux/can/core.h index 5fb8d0e3f9c1..3287232e3cad 100644 --- a/include/linux/can/core.h +++ b/include/linux/can/core.h @@ -58,6 +58,7 @@ extern void can_rx_unregister(struct net *net, struct net_device *dev, void *data); extern int can_send(struct sk_buff *skb, int loop); +void can_set_skb_uid(struct sk_buff *skb); void can_sock_destruct(struct sock *sk); #endif /* !_CAN_CORE_H */ diff --git a/include/linux/can/skb.h b/include/linux/can/skb.h index 1abc25a8d144..869ea574a40a 100644 --- a/include/linux/can/skb.h +++ b/include/linux/can/skb.h @@ -49,13 +49,11 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb); /** * struct can_skb_priv - private additional data inside CAN sk_buffs * @ifindex: ifindex of the first interface the CAN frame appeared on - * @skbcnt: atomic counter to have an unique id together with skb pointer * @frame_len: length of CAN frame in data link layer * @cf: align to the following CAN frame at skb->data */ struct can_skb_priv { int ifindex; - int skbcnt; unsigned int frame_len; struct can_frame cf[]; }; -- cgit v1.2.3 From 96ea3a1e2d317e7ecb6b65dc65c9dd917905a6a8 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sun, 1 Feb 2026 15:33:17 +0100 Subject: can: add CAN skb extension infrastructure To remove the private CAN bus skb headroom infrastructure 8 bytes need to be stored in the skb. The skb extensions are a common pattern and an easy and efficient way to hold private data travelling along with the skb. We only need the skb_ext_add() and skb_ext_find() functions to allocate and access CAN specific content as the skb helpers to copy/clone/free skbs automatically take care of skb extensions and their final removal. This patch introduces the complete CAN skb extensions infrastructure: - add struct can_skb_ext in new file include/net/can.h - add include/net/can.h in MAINTAINERS - add SKB_EXT_CAN to skbuff.c and skbuff.h - select SKB_EXTENSIONS in Kconfig when CONFIG_CAN is enabled - check for existing CAN skb extensions in can_rcv() in af_can.c - add CAN skb extensions allocation at every skb_alloc() location - duplicate the skb extensions if cloning outgoing skbs (framelen/gw_hops) - introduce can_skb_ext_add() and can_skb_ext_find() helpers The patch also corrects an indention issue in the original code from 2018: Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202602010426.PnGrYAk3-lkp@intel.com/ Signed-off-by: Marc Kleine-Budde Signed-off-by: Oliver Hartkopp Link: https://patch.msgid.link/20260201-can_skb_ext-v8-2-3635d790fe8b@hartkopp.net Signed-off-by: Paolo Abeni --- MAINTAINERS | 1 + drivers/net/can/dev/skb.c | 56 +++++++++++++++++++++++++++++++++++++---------- drivers/net/can/vxcan.c | 13 +++++++++++ include/linux/can/skb.h | 17 ++++++++++++++ include/linux/skbuff.h | 3 +++ include/net/can.h | 28 ++++++++++++++++++++++++ net/can/Kconfig | 1 + net/can/af_can.c | 9 +++++--- net/can/bcm.c | 15 +++++++++++++ net/can/gw.c | 17 ++++++++++++++ net/can/isotp.c | 25 +++++++++++++++++++++ net/can/j1939/socket.c | 9 ++++++++ net/can/j1939/transport.c | 26 ++++++++++++++++++++++ net/can/raw.c | 9 ++++++++ net/core/skbuff.c | 4 ++++ 15 files changed, 219 insertions(+), 14 deletions(-) create mode 100644 include/net/can.h (limited to 'include/linux') diff --git a/MAINTAINERS b/MAINTAINERS index ac417870c477..ce6f49c054c7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5634,6 +5634,7 @@ F: Documentation/networking/iso15765-2.rst F: include/linux/can/can-ml.h F: include/linux/can/core.h F: include/linux/can/skb.h +F: include/net/can.h F: include/net/netns/can.h F: include/uapi/linux/can.h F: include/uapi/linux/can/bcm.h diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c index 0da615afa04d..c572745565f6 100644 --- a/drivers/net/can/dev/skb.c +++ b/drivers/net/can/dev/skb.c @@ -6,6 +6,7 @@ #include #include +#include #define MOD_DESC "CAN device driver interface" @@ -207,13 +208,17 @@ static void init_can_skb_reserve(struct sk_buff *skb) struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) { struct sk_buff *skb; + struct can_skb_ext *csx; skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + sizeof(struct can_frame)); - if (unlikely(!skb)) { - *cf = NULL; + if (unlikely(!skb)) + goto out_error_cc; - return NULL; + csx = can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + goto out_error_cc; } skb->protocol = htons(ETH_P_CAN); @@ -223,6 +228,11 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) *cf = skb_put_zero(skb, sizeof(struct can_frame)); return skb; + +out_error_cc: + *cf = NULL; + + return NULL; } EXPORT_SYMBOL_GPL(alloc_can_skb); @@ -230,13 +240,17 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev, struct canfd_frame **cfd) { struct sk_buff *skb; + struct can_skb_ext *csx; skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + sizeof(struct canfd_frame)); - if (unlikely(!skb)) { - *cfd = NULL; + if (unlikely(!skb)) + goto out_error_fd; - return NULL; + csx = can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + goto out_error_fd; } skb->protocol = htons(ETH_P_CANFD); @@ -249,6 +263,11 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev, (*cfd)->flags = CANFD_FDF; return skb; + +out_error_fd: + *cfd = NULL; + + return NULL; } EXPORT_SYMBOL_GPL(alloc_canfd_skb); @@ -257,14 +276,21 @@ struct sk_buff *alloc_canxl_skb(struct net_device *dev, unsigned int data_len) { struct sk_buff *skb; + struct can_skb_ext *csx; if (data_len < CANXL_MIN_DLEN || data_len > CANXL_MAX_DLEN) - goto out_error; + goto out_error_xl; skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + CANXL_HDR_SIZE + data_len); if (unlikely(!skb)) - goto out_error; + goto out_error_xl; + + csx = can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + goto out_error_xl; + } skb->protocol = htons(ETH_P_CANXL); init_can_skb_reserve(skb); @@ -278,7 +304,7 @@ struct sk_buff *alloc_canxl_skb(struct net_device *dev, return skb; -out_error: +out_error_xl: *cxl = NULL; return NULL; @@ -303,13 +329,21 @@ EXPORT_SYMBOL_GPL(alloc_can_err_skb); /* Check for outgoing skbs that have not been created by the CAN subsystem */ static bool can_skb_headroom_valid(struct net_device *dev, struct sk_buff *skb) { + struct can_skb_ext *csx = can_skb_ext_find(skb); + /* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */ if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv))) return false; /* af_packet does not apply CAN skb specific settings */ - if (skb->ip_summed == CHECKSUM_NONE) { - /* init headroom */ + if (skb->ip_summed == CHECKSUM_NONE || !csx) { + /* init CAN skb content */ + if (!csx) { + csx = can_skb_ext_add(skb); + if (!csx) + return false; + } + can_skb_prv(skb)->ifindex = dev->ifindex; skb->ip_summed = CHECKSUM_UNNECESSARY; diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index f14c6f02b662..ac2211f8070c 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #define DRV_NAME "vxcan" @@ -39,6 +40,7 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, struct net_device *dev) struct vxcan_priv *priv = netdev_priv(dev); struct net_device *peer; struct net_device_stats *peerstats, *srcstats = &dev->stats; + struct can_skb_ext *csx; struct sk_buff *skb; unsigned int len; @@ -63,6 +65,17 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, struct net_device *dev) goto out_unlock; } + /* the cloned skb points to the skb extension of the already cloned + * oskb with an increased refcount. skb_ext_add() creates a copy to + * separate the skb extension data which is needed to start with a + * fresh can_gw_hops counter in the other namespace. + */ + csx = skb_ext_add(skb, SKB_EXT_CAN); + if (!csx) { + kfree_skb(skb); + goto out_unlock; + } + /* reset CAN GW hop counter */ skb->csum_start = 0; skb->pkt_type = PACKET_BROADCAST; diff --git a/include/linux/can/skb.h b/include/linux/can/skb.h index 869ea574a40a..68c0f24e6914 100644 --- a/include/linux/can/skb.h +++ b/include/linux/can/skb.h @@ -14,6 +14,7 @@ #include #include #include +#include #include void can_flush_echo_skb(struct net_device *dev); @@ -68,6 +69,22 @@ static inline void can_skb_reserve(struct sk_buff *skb) skb_reserve(skb, sizeof(struct can_skb_priv)); } +static inline struct can_skb_ext *can_skb_ext_add(struct sk_buff *skb) +{ + struct can_skb_ext *csx = skb_ext_add(skb, SKB_EXT_CAN); + + /* skb_ext_add() returns uninitialized space */ + if (csx) + csx->can_gw_hops = 0; + + return csx; +} + +static inline struct can_skb_ext *can_skb_ext_find(struct sk_buff *skb) +{ + return skb_ext_find(skb, SKB_EXT_CAN); +} + static inline void can_skb_set_owner(struct sk_buff *skb, struct sock *sk) { /* If the socket has already been closed by user space, the diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 8b399ddf1b9b..ef56dc6318d3 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -4989,6 +4989,9 @@ enum skb_ext_id { #endif #if IS_ENABLED(CONFIG_INET_PSP) SKB_EXT_PSP, +#endif +#if IS_ENABLED(CONFIG_CAN) + SKB_EXT_CAN, #endif SKB_EXT_NUM, /* must be last */ }; diff --git a/include/net/can.h b/include/net/can.h new file mode 100644 index 000000000000..6db9e826f0e0 --- /dev/null +++ b/include/net/can.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * net/can.h + * + * Definitions for the CAN network socket buffer extensions + * + * Copyright (C) 2026 Oliver Hartkopp + * + */ + +#ifndef _NET_CAN_H +#define _NET_CAN_H + +/** + * struct can_skb_ext - skb extensions for CAN specific content + * @can_iif: ifindex of the first interface the CAN frame appeared on + * @can_framelen: cached echo CAN frame length for bql + * @can_gw_hops: can-gw CAN frame time-to-live counter + * @can_ext_flags: CAN skb extensions flags + */ +struct can_skb_ext { + int can_iif; + u16 can_framelen; + u8 can_gw_hops; + u8 can_ext_flags; +}; + +#endif /* _NET_CAN_H */ diff --git a/net/can/Kconfig b/net/can/Kconfig index af64a6f76458..abbb4be7ad21 100644 --- a/net/can/Kconfig +++ b/net/can/Kconfig @@ -5,6 +5,7 @@ menuconfig CAN tristate "CAN bus subsystem support" + select SKB_EXTENSIONS help Controller Area Network (CAN) is a slow (up to 1Mbit/s) serial communications protocol. Development of the CAN bus started in diff --git a/net/can/af_can.c b/net/can/af_can.c index 70659987ef4d..22c65a014861 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -687,7 +687,8 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev) static int can_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_get_ml_priv(dev) || !can_is_can_skb(skb))) { + if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || + !can_skb_ext_find(skb) || !can_is_can_skb(skb))) { pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d\n", dev->type, skb->len); @@ -702,7 +703,8 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev, static int canfd_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_get_ml_priv(dev) || !can_is_canfd_skb(skb))) { + if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || + !can_skb_ext_find(skb) || !can_is_canfd_skb(skb))) { pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d\n", dev->type, skb->len); @@ -717,7 +719,8 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev, 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_get_ml_priv(dev) || !can_is_canxl_skb(skb))) { + if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || + !can_skb_ext_find(skb) || !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); diff --git a/net/can/bcm.c b/net/can/bcm.c index 8ed60f18c2ea..38452069dea8 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include @@ -291,6 +292,7 @@ static int bcm_proc_show(struct seq_file *m, void *v) static void bcm_can_tx(struct bcm_op *op) { struct sk_buff *skb; + struct can_skb_ext *csx; struct net_device *dev; struct canfd_frame *cf; int err; @@ -314,6 +316,12 @@ static void bcm_can_tx(struct bcm_op *op) if (!skb) goto out; + csx = can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + goto out; + } + can_skb_reserve(skb); can_skb_prv(skb)->ifindex = dev->ifindex; @@ -1317,6 +1325,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk, int cfsiz) { struct sk_buff *skb; + struct can_skb_ext *csx; struct net_device *dev; int err; @@ -1328,6 +1337,12 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk, if (!skb) return -ENOMEM; + csx = can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + return -ENOMEM; + } + can_skb_reserve(skb); err = memcpy_from_msg(skb_put(skb, cfsiz), msg, cfsiz); diff --git a/net/can/gw.c b/net/can/gw.c index 55eccb1c7620..191afe3b673c 100644 --- a/net/can/gw.c +++ b/net/can/gw.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -459,6 +460,7 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) struct cgw_job *gwj = (struct cgw_job *)data; struct canfd_frame *cf; struct sk_buff *nskb; + struct can_skb_ext *csx, *ncsx; struct cf_mod *mod; int modidx = 0; @@ -471,6 +473,10 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) return; } + csx = can_skb_ext_find(skb); + if (!csx) + return; + /* Do not handle CAN frames routed more than 'max_hops' times. * In general we should never catch this delimiter which is intended * to cover a misconfiguration protection (e.g. circular CAN routes). @@ -518,6 +524,17 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) return; } + /* the cloned/copied nskb points to the skb extension of the original + * skb with an increased refcount. skb_ext_add() creates a copy to + * separate the skb extension data to modify the can_gw_hops. + */ + ncsx = skb_ext_add(nskb, SKB_EXT_CAN); + if (!ncsx) { + kfree_skb(nskb); + gwj->dropped_frames++; + return; + } + /* put the incremented hop counter in the cloned skb */ cgw_hops(nskb) = cgw_hops(skb) + 1; diff --git a/net/can/isotp.c b/net/can/isotp.c index 4bb60b8f9b96..1346dac0f382 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -69,6 +69,7 @@ #include #include #include +#include #include #include @@ -214,6 +215,7 @@ static int isotp_send_fc(struct sock *sk, int ae, u8 flowstatus) { struct net_device *dev; struct sk_buff *nskb; + struct can_skb_ext *csx; struct canfd_frame *ncf; struct isotp_sock *so = isotp_sk(sk); int can_send_ret; @@ -222,6 +224,12 @@ static int isotp_send_fc(struct sock *sk, int ae, u8 flowstatus) if (!nskb) return 1; + csx = can_skb_ext_add(nskb); + if (!csx) { + kfree_skb(nskb); + return 1; + } + dev = dev_get_by_index(sock_net(sk), so->ifindex); if (!dev) { kfree_skb(nskb); @@ -762,6 +770,7 @@ static void isotp_send_cframe(struct isotp_sock *so) { struct sock *sk = &so->sk; struct sk_buff *skb; + struct can_skb_ext *csx; struct net_device *dev; struct canfd_frame *cf; int can_send_ret; @@ -777,6 +786,13 @@ static void isotp_send_cframe(struct isotp_sock *so) return; } + csx = can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + netdev_put(dev, NULL); + return; + } + can_skb_reserve(skb); can_skb_prv(skb)->ifindex = dev->ifindex; @@ -938,6 +954,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) struct sock *sk = sock->sk; struct isotp_sock *so = isotp_sk(sk); struct sk_buff *skb; + struct can_skb_ext *csx; struct net_device *dev; struct canfd_frame *cf; int ae = (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0; @@ -1005,6 +1022,14 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) goto err_out_drop; } + csx = can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + netdev_put(dev, NULL); + err = -ENOMEM; + goto err_out_drop; + } + can_skb_reserve(skb); can_skb_prv(skb)->ifindex = dev->ifindex; diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c index 1589e8ca634e..b7fbc6512f16 100644 --- a/net/can/j1939/socket.c +++ b/net/can/j1939/socket.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "j1939-priv.h" @@ -884,6 +885,7 @@ static struct sk_buff *j1939_sk_alloc_skb(struct net_device *ndev, struct j1939_sock *jsk = j1939_sk(sk); struct j1939_sk_buff_cb *skcb; struct sk_buff *skb; + struct can_skb_ext *csx; int ret; skb = sock_alloc_send_skb(sk, @@ -895,6 +897,13 @@ static struct sk_buff *j1939_sk_alloc_skb(struct net_device *ndev, if (!skb) goto failure; + csx = can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + ret = -ENOMEM; + goto failure; + } + can_skb_reserve(skb); can_skb_prv(skb)->ifindex = ndev->ifindex; skb_reserve(skb, offsetof(struct can_frame, data)); diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c index d5d3e5320f7a..03fea5bf0f73 100644 --- a/net/can/j1939/transport.c +++ b/net/can/j1939/transport.c @@ -9,6 +9,7 @@ // Oleksij Rempel #include +#include #include "j1939-priv.h" @@ -591,6 +592,7 @@ sk_buff *j1939_tp_tx_dat_new(struct j1939_priv *priv, bool swap_src_dst) { struct sk_buff *skb; + struct can_skb_ext *csx; struct j1939_sk_buff_cb *skcb; skb = alloc_skb(sizeof(struct can_frame) + sizeof(struct can_skb_priv), @@ -598,6 +600,12 @@ sk_buff *j1939_tp_tx_dat_new(struct j1939_priv *priv, if (unlikely(!skb)) return ERR_PTR(-ENOMEM); + csx = can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + return ERR_PTR(-ENOMEM); + } + skb->dev = priv->ndev; can_skb_reserve(skb); can_skb_prv(skb)->ifindex = priv->ndev->ifindex; @@ -1051,6 +1059,17 @@ static int j1939_simple_txnext(struct j1939_session *session) goto out_free; } + /* the cloned skb points to the skb extension of the original se_skb + * with an increased refcount. skb_ext_add() creates a copy to + * separate the skb extension data which is needed to modify the + * can_framelen in can_put_echo_skb(). + */ + if (!skb_ext_add(skb, SKB_EXT_CAN)) { + kfree_skb(skb); + ret = -ENOMEM; + goto out_free; + } + can_skb_set_owner(skb, se_skb->sk); j1939_tp_set_rxtimeout(session, J1939_SIMPLE_ECHO_TIMEOUT_MS); @@ -1525,6 +1544,7 @@ j1939_session *j1939_session_fresh_new(struct j1939_priv *priv, const struct j1939_sk_buff_cb *rel_skcb) { struct sk_buff *skb; + struct can_skb_ext *csx; struct j1939_sk_buff_cb *skcb; struct j1939_session *session; @@ -1532,6 +1552,12 @@ j1939_session *j1939_session_fresh_new(struct j1939_priv *priv, if (unlikely(!skb)) return NULL; + csx = can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + return NULL; + } + skb->dev = priv->ndev; can_skb_reserve(skb); can_skb_prv(skb)->ifindex = priv->ndev->ifindex; diff --git a/net/can/raw.c b/net/can/raw.c index fb4f9c854df0..c63af48495b7 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -918,6 +919,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) struct raw_sock *ro = raw_sk(sk); struct sockcm_cookie sockc; struct sk_buff *skb; + struct can_skb_ext *csx; struct net_device *dev; unsigned int txmtu; int ifindex; @@ -956,6 +958,13 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) if (!skb) goto put_dev; + csx = can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + err = -ENOMEM; + goto put_dev; + } + can_skb_reserve(skb); can_skb_prv(skb)->ifindex = dev->ifindex; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 4d3920e5b141..648c20e19038 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -78,6 +78,7 @@ #include #include #include +#include #include #include #include @@ -5139,6 +5140,9 @@ static const u8 skb_ext_type_len[] = { #if IS_ENABLED(CONFIG_INET_PSP) [SKB_EXT_PSP] = SKB_EXT_CHUNKSIZEOF(struct psp_skb_ext), #endif +#if IS_ENABLED(CONFIG_CAN) + [SKB_EXT_CAN] = SKB_EXT_CHUNKSIZEOF(struct can_skb_ext), +#endif }; static __always_inline unsigned int skb_ext_total_length(void) -- cgit v1.2.3 From 9f10374bb024593a611e6845847f0444841a231b Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sun, 1 Feb 2026 15:33:20 +0100 Subject: can: remove private CAN skb headroom infrastructure This patch removes struct can_skb_priv which was stored at skb->head and the can_skb_reserve() helper which was used to shift skb->head. Signed-off-by: Marc Kleine-Budde Signed-off-by: Oliver Hartkopp Link: https://patch.msgid.link/20260201-can_skb_ext-v8-5-3635d790fe8b@hartkopp.net Signed-off-by: Paolo Abeni --- drivers/net/can/dev/skb.c | 31 +++++++++---------------------- include/linux/can/skb.h | 31 ------------------------------- net/can/bcm.c | 7 ++----- net/can/isotp.c | 12 ++++-------- net/can/j1939/socket.c | 4 +--- net/can/j1939/transport.c | 7 ++----- net/can/raw.c | 5 ++--- 7 files changed, 20 insertions(+), 77 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c index 408ee49abce1..95fcdc1026f8 100644 --- a/drivers/net/can/dev/skb.c +++ b/drivers/net/can/dev/skb.c @@ -206,16 +206,10 @@ 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) +static void init_can_skb(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); } struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) @@ -223,8 +217,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) struct sk_buff *skb; struct can_skb_ext *csx; - skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + - sizeof(struct can_frame)); + skb = netdev_alloc_skb(dev, sizeof(struct can_frame)); if (unlikely(!skb)) goto out_error_cc; @@ -235,7 +228,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) } skb->protocol = htons(ETH_P_CAN); - init_can_skb_reserve(skb); + init_can_skb(skb); csx->can_iif = dev->ifindex; *cf = skb_put_zero(skb, sizeof(struct can_frame)); @@ -255,8 +248,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev, struct sk_buff *skb; struct can_skb_ext *csx; - skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + - sizeof(struct canfd_frame)); + skb = netdev_alloc_skb(dev, sizeof(struct canfd_frame)); if (unlikely(!skb)) goto out_error_fd; @@ -267,7 +259,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev, } skb->protocol = htons(ETH_P_CANFD); - init_can_skb_reserve(skb); + init_can_skb(skb); csx->can_iif = dev->ifindex; *cfd = skb_put_zero(skb, sizeof(struct canfd_frame)); @@ -294,8 +286,7 @@ struct sk_buff *alloc_canxl_skb(struct net_device *dev, if (data_len < CANXL_MIN_DLEN || data_len > CANXL_MAX_DLEN) goto out_error_xl; - skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + - CANXL_HDR_SIZE + data_len); + skb = netdev_alloc_skb(dev, CANXL_HDR_SIZE + data_len); if (unlikely(!skb)) goto out_error_xl; @@ -306,7 +297,7 @@ struct sk_buff *alloc_canxl_skb(struct net_device *dev, } skb->protocol = htons(ETH_P_CANXL); - init_can_skb_reserve(skb); + init_can_skb(skb); csx->can_iif = dev->ifindex; *cxl = skb_put_zero(skb, CANXL_HDR_SIZE + data_len); @@ -340,14 +331,10 @@ struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf) EXPORT_SYMBOL_GPL(alloc_can_err_skb); /* Check for outgoing skbs that have not been created by the CAN subsystem */ -static bool can_skb_headroom_valid(struct net_device *dev, struct sk_buff *skb) +static bool can_skb_init_valid(struct net_device *dev, struct sk_buff *skb) { struct can_skb_ext *csx = can_skb_ext_find(skb); - /* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */ - if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv))) - return false; - /* af_packet does not apply CAN skb specific settings */ if (skb->ip_summed == CHECKSUM_NONE || !csx) { /* init CAN skb content */ @@ -405,7 +392,7 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb) goto inval_skb; } - if (!can_skb_headroom_valid(dev, skb)) + if (!can_skb_init_valid(dev, skb)) goto inval_skb; return false; diff --git a/include/linux/can/skb.h b/include/linux/can/skb.h index 68c0f24e6914..a70a02967071 100644 --- a/include/linux/can/skb.h +++ b/include/linux/can/skb.h @@ -38,37 +38,6 @@ 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); -/* - * The struct can_skb_priv is used to transport additional information along - * with the stored struct can(fd)_frame that can not be contained in existing - * struct sk_buff elements. - * N.B. that this information must not be modified in cloned CAN sk_buffs. - * To modify the CAN frame content or the struct can_skb_priv content - * skb_copy() needs to be used instead of skb_clone(). - */ - -/** - * struct can_skb_priv - private additional data inside CAN sk_buffs - * @ifindex: ifindex of the first interface the CAN frame appeared on - * @frame_len: length of CAN frame in data link layer - * @cf: align to the following CAN frame at skb->data - */ -struct can_skb_priv { - int ifindex; - unsigned int frame_len; - struct can_frame cf[]; -}; - -static inline struct can_skb_priv *can_skb_prv(struct sk_buff *skb) -{ - return (struct can_skb_priv *)(skb->head); -} - -static inline void can_skb_reserve(struct sk_buff *skb) -{ - skb_reserve(skb, sizeof(struct can_skb_priv)); -} - static inline struct can_skb_ext *can_skb_ext_add(struct sk_buff *skb) { struct can_skb_ext *csx = skb_ext_add(skb, SKB_EXT_CAN); diff --git a/net/can/bcm.c b/net/can/bcm.c index f102d17e8619..b7324e9c955b 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -312,7 +312,7 @@ static void bcm_can_tx(struct bcm_op *op) return; } - skb = alloc_skb(op->cfsiz + sizeof(struct can_skb_priv), gfp_any()); + skb = alloc_skb(op->cfsiz, gfp_any()); if (!skb) goto out; @@ -322,7 +322,6 @@ static void bcm_can_tx(struct bcm_op *op) goto out; } - can_skb_reserve(skb); csx->can_iif = dev->ifindex; skb_put_data(skb, cf, op->cfsiz); @@ -1333,7 +1332,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk, if (!ifindex) return -ENODEV; - skb = alloc_skb(cfsiz + sizeof(struct can_skb_priv), GFP_KERNEL); + skb = alloc_skb(cfsiz, GFP_KERNEL); if (!skb) return -ENOMEM; @@ -1343,8 +1342,6 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk, return -ENOMEM; } - can_skb_reserve(skb); - err = memcpy_from_msg(skb_put(skb, cfsiz), msg, cfsiz); if (err < 0) { kfree_skb(skb); diff --git a/net/can/isotp.c b/net/can/isotp.c index 164c4fbf3e23..da3b72e7afcc 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -220,7 +220,7 @@ static int isotp_send_fc(struct sock *sk, int ae, u8 flowstatus) struct isotp_sock *so = isotp_sk(sk); int can_send_ret; - nskb = alloc_skb(so->ll.mtu + sizeof(struct can_skb_priv), gfp_any()); + nskb = alloc_skb(so->ll.mtu, gfp_any()); if (!nskb) return 1; @@ -236,9 +236,7 @@ static int isotp_send_fc(struct sock *sk, int ae, u8 flowstatus) return 1; } - can_skb_reserve(nskb); csx->can_iif = dev->ifindex; - nskb->dev = dev; can_skb_set_owner(nskb, sk); ncf = (struct canfd_frame *)nskb->data; @@ -780,7 +778,7 @@ static void isotp_send_cframe(struct isotp_sock *so) if (!dev) return; - skb = alloc_skb(so->ll.mtu + sizeof(struct can_skb_priv), GFP_ATOMIC); + skb = alloc_skb(so->ll.mtu, GFP_ATOMIC); if (!skb) { dev_put(dev); return; @@ -793,7 +791,6 @@ static void isotp_send_cframe(struct isotp_sock *so) return; } - can_skb_reserve(skb); csx->can_iif = dev->ifindex; cf = (struct canfd_frame *)skb->data; @@ -1015,8 +1012,8 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) goto err_out_drop; } - skb = sock_alloc_send_skb(sk, so->ll.mtu + sizeof(struct can_skb_priv), - msg->msg_flags & MSG_DONTWAIT, &err); + skb = sock_alloc_send_skb(sk, so->ll.mtu, msg->msg_flags & MSG_DONTWAIT, + &err); if (!skb) { dev_put(dev); goto err_out_drop; @@ -1030,7 +1027,6 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) goto err_out_drop; } - can_skb_reserve(skb); csx->can_iif = dev->ifindex; so->tx.len = size; diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c index cc698a6dc363..0502b030d238 100644 --- a/net/can/j1939/socket.c +++ b/net/can/j1939/socket.c @@ -891,8 +891,7 @@ static struct sk_buff *j1939_sk_alloc_skb(struct net_device *ndev, skb = sock_alloc_send_skb(sk, size + sizeof(struct can_frame) - - sizeof(((struct can_frame *)NULL)->data) + - sizeof(struct can_skb_priv), + sizeof(((struct can_frame *)NULL)->data), msg->msg_flags & MSG_DONTWAIT, &ret); if (!skb) goto failure; @@ -904,7 +903,6 @@ static struct sk_buff *j1939_sk_alloc_skb(struct net_device *ndev, goto failure; } - can_skb_reserve(skb); csx->can_iif = ndev->ifindex; skb_reserve(skb, offsetof(struct can_frame, data)); diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c index 3456ef481799..2cbe94fc487a 100644 --- a/net/can/j1939/transport.c +++ b/net/can/j1939/transport.c @@ -595,8 +595,7 @@ sk_buff *j1939_tp_tx_dat_new(struct j1939_priv *priv, struct can_skb_ext *csx; struct j1939_sk_buff_cb *skcb; - skb = alloc_skb(sizeof(struct can_frame) + sizeof(struct can_skb_priv), - GFP_ATOMIC); + skb = alloc_skb(sizeof(struct can_frame), GFP_ATOMIC); if (unlikely(!skb)) return ERR_PTR(-ENOMEM); @@ -607,7 +606,6 @@ sk_buff *j1939_tp_tx_dat_new(struct j1939_priv *priv, } skb->dev = priv->ndev; - can_skb_reserve(skb); csx->can_iif = priv->ndev->ifindex; /* reserve CAN header */ skb_reserve(skb, offsetof(struct can_frame, data)); @@ -1548,7 +1546,7 @@ j1939_session *j1939_session_fresh_new(struct j1939_priv *priv, struct j1939_sk_buff_cb *skcb; struct j1939_session *session; - skb = alloc_skb(size + sizeof(struct can_skb_priv), GFP_ATOMIC); + skb = alloc_skb(size, GFP_ATOMIC); if (unlikely(!skb)) return NULL; @@ -1559,7 +1557,6 @@ j1939_session *j1939_session_fresh_new(struct j1939_priv *priv, } skb->dev = priv->ndev; - can_skb_reserve(skb); csx->can_iif = priv->ndev->ifindex; skcb = j1939_skb_to_cb(skb); memcpy(skcb, rel_skcb, sizeof(*skcb)); diff --git a/net/can/raw.c b/net/can/raw.c index 022154b0f6cc..eee244ffc31e 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -953,8 +953,8 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) goto put_dev; } - skb = sock_alloc_send_skb(sk, size + sizeof(struct can_skb_priv), - msg->msg_flags & MSG_DONTWAIT, &err); + skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, + &err); if (!skb) goto put_dev; @@ -965,7 +965,6 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) goto put_dev; } - can_skb_reserve(skb); csx->can_iif = dev->ifindex; /* fill the skb before testing for valid CAN frames */ -- cgit v1.2.3