summaryrefslogtreecommitdiff
path: root/drivers/net/can/dev
diff options
context:
space:
mode:
authorOliver Hartkopp <socketcan@hartkopp.net>2026-02-01 15:33:17 +0100
committerPaolo Abeni <pabeni@redhat.com>2026-02-05 11:58:39 +0100
commit96ea3a1e2d317e7ecb6b65dc65c9dd917905a6a8 (patch)
tree2780347dd8e2aea4538e15f43a207e193edf7ab7 /drivers/net/can/dev
parentd4fb6514ff8ed6912a71294e6b66a5d59ee88007 (diff)
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 <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>
Diffstat (limited to 'drivers/net/can/dev')
-rw-r--r--drivers/net/can/dev/skb.c56
1 files changed, 45 insertions, 11 deletions
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 <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;