]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
can: add CAN skb extension infrastructure
authorOliver Hartkopp <socketcan@hartkopp.net>
Sun, 1 Feb 2026 14:33:17 +0000 (15:33 +0100)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 5 Feb 2026 10:58:39 +0000 (11:58 +0100)
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 <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202602010426.PnGrYAk3-lkp@intel.com/
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20260201-can_skb_ext-v8-2-3635d790fe8b@hartkopp.net
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
15 files changed:
MAINTAINERS
drivers/net/can/dev/skb.c
drivers/net/can/vxcan.c
include/linux/can/skb.h
include/linux/skbuff.h
include/net/can.h [new file with mode: 0644]
net/can/Kconfig
net/can/af_can.c
net/can/bcm.c
net/can/gw.c
net/can/isotp.c
net/can/j1939/socket.c
net/can/j1939/transport.c
net/can/raw.c
net/core/skbuff.c

index ac417870c477a2443f78d958b06d8ea16f775163..ce6f49c054c766f69d93b6b5073412ed5775d4e7 100644 (file)
@@ -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
index 0da615afa04de7c3df16c189ef8c7c1664d1a681..c572745565f6d0ff25729039220614ecb117e2b3 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/can/dev.h>
 #include <linux/module.h>
+#include <net/can.h>
 
 #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;
index f14c6f02b662717a3616c84cb8c6077b2e50a755..ac2211f8070c7c96fbba6b638eb47761d2e0034a 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/can/vxcan.h>
 #include <linux/can/can-ml.h>
 #include <linux/slab.h>
+#include <net/can.h>
 #include <net/rtnetlink.h>
 
 #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;
index 869ea574a40a194b27081ae5eeed701f91ec69c4..68c0f24e69149707e38d657e821d6cbe129f7d1d 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/types.h>
 #include <linux/skbuff.h>
 #include <linux/can.h>
+#include <net/can.h>
 #include <net/sock.h>
 
 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
index 8b399ddf1b9bd0dddb37f417ccfa5ea675efafa3..ef56dc6318d311e9a8f79d7d2724bce3ae06f6e7 100644 (file)
@@ -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 (file)
index 0000000..6db9e82
--- /dev/null
@@ -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 <socketcan@hartkopp.net>
+ *
+ */
+
+#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 */
index af64a6f764588cc63862ce285ee47f3245d72d5e..abbb4be7ad2152c66abd2e28dbbd5282ec45d065 100644 (file)
@@ -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
index 70659987ef4d27fc25aaecf01302306d3f7494d0..22c65a014861600c96078f605309419a96b8c6bd 100644 (file)
@@ -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);
 
index 8ed60f18c2eaff7053cb2c76e5e4cf1124dd3ac5..38452069dea883a35b86ba2d085d5c37a11a909d 100644 (file)
@@ -59,6 +59,7 @@
 #include <linux/can/bcm.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <net/can.h>
 #include <net/sock.h>
 #include <net/net_namespace.h>
 
@@ -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);
index 55eccb1c7620c094e04a7525b5d6c2becb96b72c..191afe3b673cf7d1d712c0ae761fd31d5bd529c4 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/can/core.h>
 #include <linux/can/skb.h>
 #include <linux/can/gw.h>
+#include <net/can.h>
 #include <net/rtnetlink.h>
 #include <net/net_namespace.h>
 #include <net/sock.h>
@@ -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;
 
index 4bb60b8f9b96188a328e77be2fdefcb879da1089..1346dac0f382f1037ce0727597624e35764b11a5 100644 (file)
@@ -69,6 +69,7 @@
 #include <linux/can/skb.h>
 #include <linux/can/isotp.h>
 #include <linux/slab.h>
+#include <net/can.h>
 #include <net/sock.h>
 #include <net/net_namespace.h>
 
@@ -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;
 
index 1589e8ca634ecc2b59eb0c2a1e48f546fafccbe0..b7fbc6512f16b2999d7a1344d3ea00488b0a0d70 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/can/skb.h>
 #include <linux/errqueue.h>
 #include <linux/if_arp.h>
+#include <net/can.h>
 
 #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));
index d5d3e5320f7ac5fb247756f6413ab448c75447f6..03fea5bf0f73552f54930a78c006cebcc7e751eb 100644 (file)
@@ -9,6 +9,7 @@
 //                         Oleksij Rempel <kernel@pengutronix.de>
 
 #include <linux/can/skb.h>
+#include <net/can.h>
 
 #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;
index fb4f9c854df04d90ed6bd4601c616ac39bb85ad9..c63af48495b79d6cb48f1553bd5c4c7127fc3479 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/can/core.h>
 #include <linux/can/skb.h>
 #include <linux/can/raw.h>
+#include <net/can.h>
 #include <net/sock.h>
 #include <net/net_namespace.h>
 
@@ -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;
 
index 4d3920e5b141a02117186c3095f15f4f7a35b1df..648c20e190387b8c66e2a6ff8e265795f81974c7 100644 (file)
@@ -78,6 +78,7 @@
 #include <net/mpls.h>
 #include <net/mptcp.h>
 #include <net/mctp.h>
+#include <net/can.h>
 #include <net/page_pool/helpers.h>
 #include <net/psp/types.h>
 #include <net/dropreason.h>
@@ -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)