From nobody Mon Feb 9 09:23:05 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D7D462C08A2; Sat, 31 Jan 2026 13:25:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769865914; cv=none; b=q5KH2zw+iBvQVPMMPJTGAyScS88UJZK2AN1/5Swnwlp3NHDV2AUHt4rmVLPZJuSIn7Y1CG2AXa7TgLY9bt+8HZAWjCJBKtRAJzA55vVVoXyZLAVsd9sWqz+UyzV+PsehMl87eqOvpa072lbsYxDPu8Dg4/P2boA2LR1fYsuIboQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769865914; c=relaxed/simple; bh=JBFIByEVATCHIEF3t0UYW6l3zge4t/kRXZbMpYmFA+c=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=GHvTY5+cGQs27UuquLK5ilfxYfZ1F/bw/dSXriTocJCGYPeNq+uFw15TFCTGNkL94hz3CLGhsoV9xhYRec79MmDNOwCKxi12TEbpAqgsyJol2FNmQYCf1yMphiiaM1U75JoTnV3DvfX7z3CFhep46Sp4CUHplBAQmrD/qsTyq4o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Aa5GApEO; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Aa5GApEO" Received: by smtp.kernel.org (Postfix) with ESMTPS id A7253C19422; Sat, 31 Jan 2026 13:25:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1769865914; bh=JBFIByEVATCHIEF3t0UYW6l3zge4t/kRXZbMpYmFA+c=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Aa5GApEONe4TwYearyLmtBDnXFUAIRbYkmTxA4Dm6cvXE00r8YA3r35i4ja7CpQPm nkhOe8U1dMbDRzHcCCAbTOGDc4NR6rYD2ju0ydYjXYniE/GUsJWtJdYIfj2b3ftXTQ sOMn2rgdTtN1LC1KM3Y5WcdmuVO7XuoCigLmz/ALTMyFs1kBpDGzwbhRhx1YoxMDMy WfThRGsVDz8S8Lt2wWB/C0R5xbQfQb9+03jrK5GAidQtPGAKxISugGP1D3Rl2IkHPR vhciGkB0hUdCwDRr1Ul8rcetAPaHfxcTZufwVEbghY/SmmR1VSVlj6vwS009sviMyx Qjgsd7qO7wcYQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 966EED79768; Sat, 31 Jan 2026 13:25:14 +0000 (UTC) From: Oliver Hartkopp via B4 Relay Date: Sat, 31 Jan 2026 14:25:06 +0100 Subject: [PATCH net-next v7 1/6] can: use skb hash instead of private variable in headroom Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260131-can_skb_ext-v7-1-dd0f8f84a83d@hartkopp.net> References: <20260131-can_skb_ext-v7-0-dd0f8f84a83d@hartkopp.net> In-Reply-To: <20260131-can_skb_ext-v7-0-dd0f8f84a83d@hartkopp.net> To: Marc Kleine-Budde , Vincent Mailhol , Oliver Hartkopp , Robin van der Gracht , Oleksij Rempel , kernel@pengutronix.de, "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman Cc: linux-can@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org X-Mailer: b4 0.15-dev-47773 X-Developer-Signature: v=1; a=ed25519-sha256; t=1769865912; l=9579; i=socketcan@hartkopp.net; s=20260128; h=from:subject:message-id; bh=zxcFoiKJF2100rOz6zKnSRW+KicEl2DYfMk7Y/gmvbI=; b=tK4aoNPj/tHvEntrs9XW92XjPUlxd5ahjpKrlBEXuP4ddg2MD2oqZWIObXI/BbfcAdsWjK/9/ Jig6snYi6xJA0gDqYHIRSr08JDNNl3A34e1wSjl+bZ1Mh0Yfmgps0t3 X-Developer-Key: i=socketcan@hartkopp.net; a=ed25519; pk=/gU/7/wBqak3kTsTeFbCCqUi9dnh+1i6ITEkfPj/BvU= X-Endpoint-Received: by B4 Relay for socketcan@hartkopp.net/20260128 with auth_id=620 X-Original-From: Oliver Hartkopp Reply-To: socketcan@hartkopp.net From: Oliver Hartkopp 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 --- drivers/net/can/dev/skb.c | 2 -- include/linux/can/core.h | 1 + include/linux/can/skb.h | 2 -- net/can/af_can.c | 14 +++++++++++--- net/can/bcm.c | 2 -- net/can/isotp.c | 3 --- net/can/j1939/socket.c | 1 - net/can/j1939/transport.c | 2 -- net/can/raw.c | 7 +++---- 9 files changed, 15 insertions(+), 19 deletions(-) diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c index 3ebd4f779b9b..0da615afa04d 100644 --- a/drivers/net/can/dev/skb.c +++ b/drivers/net/can/dev/skb.c @@ -200,11 +200,10 @@ static void init_can_skb_reserve(struct sk_buff *skb) skb_reset_mac_header(skb); skb_reset_network_header(skb); skb_reset_transport_header(skb); =20 can_skb_reserve(skb); - can_skb_prv(skb)->skbcnt =3D 0; } =20 struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **c= f) { struct sk_buff *skb; @@ -310,11 +309,10 @@ static bool can_skb_headroom_valid(struct net_device = *dev, struct sk_buff *skb) =20 /* af_packet does not apply CAN skb specific settings */ if (skb->ip_summed =3D=3D CHECKSUM_NONE) { /* init headroom */ can_skb_prv(skb)->ifindex =3D dev->ifindex; - can_skb_prv(skb)->skbcnt =3D 0; =20 skb->ip_summed =3D CHECKSUM_UNNECESSARY; =20 /* perform proper loopback on capable devices */ if (dev->flags & IFF_ECHO) 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 @@ -56,8 +56,9 @@ extern void can_rx_unregister(struct net *net, struct net= _device *dev, canid_t can_id, canid_t mask, void (*func)(struct sk_buff *, void *), void *data); =20 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); =20 #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 @@ -47,17 +47,15 @@ bool can_dropped_invalid_skb(struct net_device *dev, st= ruct sk_buff *skb); */ =20 /** * 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[]; }; =20 static inline struct can_skb_priv *can_skb_prv(struct sk_buff *skb) diff --git a/net/can/af_can.c b/net/can/af_can.c index 770173d8db42..70659987ef4d 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -639,10 +639,20 @@ static int can_rcv_filter(struct can_dev_rcv_lists *d= ev_rcv_lists, struct sk_buf } =20 return matches; } =20 +void can_set_skb_uid(struct sk_buff *skb) +{ + /* create non-zero unique skb identifier together with *skb */ + while (!(skb->hash)) + skb->hash =3D atomic_inc_return(&skbcounter); + + skb->sw_hash =3D 1; +} +EXPORT_SYMBOL(can_set_skb_uid); + static void can_receive(struct sk_buff *skb, struct net_device *dev) { struct can_dev_rcv_lists *dev_rcv_lists; struct net *net =3D dev_net(dev); struct can_pkg_stats *pkg_stats =3D net->can.pkg_stats; @@ -650,13 +660,11 @@ static void can_receive(struct sk_buff *skb, struct n= et_device *dev) =20 /* update statistics */ atomic_long_inc(&pkg_stats->rx_frames); atomic_long_inc(&pkg_stats->rx_frames_delta); =20 - /* create non-zero unique skb identifier together with *skb */ - while (!(can_skb_prv(skb)->skbcnt)) - can_skb_prv(skb)->skbcnt =3D atomic_inc_return(&skbcounter); + can_set_skb_uid(skb); =20 rcu_read_lock(); =20 /* deliver the packet to sockets listening on all devices */ matches =3D can_rcv_filter(net->can.rx_alldev_list, skb); diff --git a/net/can/bcm.c b/net/can/bcm.c index 7eba8ae01a5b..8ed60f18c2ea 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -314,11 +314,10 @@ static void bcm_can_tx(struct bcm_op *op) if (!skb) goto out; =20 can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D dev->ifindex; - can_skb_prv(skb)->skbcnt =3D 0; =20 skb_put_data(skb, cf, op->cfsiz); =20 /* send with loopback */ skb->dev =3D dev; @@ -1342,11 +1341,10 @@ static int bcm_tx_send(struct msghdr *msg, int ifin= dex, struct sock *sk, kfree_skb(skb); return -ENODEV; } =20 can_skb_prv(skb)->ifindex =3D dev->ifindex; - can_skb_prv(skb)->skbcnt =3D 0; skb->dev =3D dev; can_skb_set_owner(skb, sk); err =3D can_send(skb, 1); /* send with loopback */ dev_put(dev); =20 diff --git a/net/can/isotp.c b/net/can/isotp.c index ce588b85665a..4bb60b8f9b96 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -228,11 +228,10 @@ static int isotp_send_fc(struct sock *sk, int ae, u8 = flowstatus) return 1; } =20 can_skb_reserve(nskb); can_skb_prv(nskb)->ifindex =3D dev->ifindex; - can_skb_prv(nskb)->skbcnt =3D 0; =20 nskb->dev =3D dev; can_skb_set_owner(nskb, sk); ncf =3D (struct canfd_frame *)nskb->data; skb_put_zero(nskb, so->ll.mtu); @@ -778,11 +777,10 @@ static void isotp_send_cframe(struct isotp_sock *so) return; } =20 can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D dev->ifindex; - can_skb_prv(skb)->skbcnt =3D 0; =20 cf =3D (struct canfd_frame *)skb->data; skb_put_zero(skb, so->ll.mtu); =20 /* create consecutive frame */ @@ -1007,11 +1005,10 @@ static int isotp_sendmsg(struct socket *sock, struc= t msghdr *msg, size_t size) goto err_out_drop; } =20 can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D dev->ifindex; - can_skb_prv(skb)->skbcnt =3D 0; =20 so->tx.len =3D size; so->tx.idx =3D 0; =20 cf =3D (struct canfd_frame *)skb->data; diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c index ff9c4fd7b433..1589e8ca634e 100644 --- a/net/can/j1939/socket.c +++ b/net/can/j1939/socket.c @@ -895,11 +895,10 @@ static struct sk_buff *j1939_sk_alloc_skb(struct net_= device *ndev, if (!skb) goto failure; =20 can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D ndev->ifindex; - can_skb_prv(skb)->skbcnt =3D 0; skb_reserve(skb, offsetof(struct can_frame, data)); =20 ret =3D memcpy_from_msg(skb_put(skb, size), msg, size); if (ret < 0) goto free_skb; diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c index 8656ab388c83..d5d3e5320f7a 100644 --- a/net/can/j1939/transport.c +++ b/net/can/j1939/transport.c @@ -599,11 +599,10 @@ sk_buff *j1939_tp_tx_dat_new(struct j1939_priv *priv, return ERR_PTR(-ENOMEM); =20 skb->dev =3D priv->ndev; can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D priv->ndev->ifindex; - can_skb_prv(skb)->skbcnt =3D 0; /* reserve CAN header */ skb_reserve(skb, offsetof(struct can_frame, data)); =20 /* skb->cb must be large enough to hold a j1939_sk_buff_cb structure */ BUILD_BUG_ON(sizeof(skb->cb) < sizeof(*re_skcb)); @@ -1534,11 +1533,10 @@ j1939_session *j1939_session_fresh_new(struct j1939= _priv *priv, return NULL; =20 skb->dev =3D priv->ndev; can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D priv->ndev->ifindex; - can_skb_prv(skb)->skbcnt =3D 0; skcb =3D j1939_skb_to_cb(skb); memcpy(skcb, rel_skcb, sizeof(*skcb)); =20 session =3D j1939_session_new(priv, skb, size); if (!session) { diff --git a/net/can/raw.c b/net/can/raw.c index 12293363413c..fb4f9c854df0 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -74,11 +74,11 @@ MODULE_ALIAS("can-proto-1"); * storing the single filter in dfilter, to avoid using dynamic memory. */ =20 struct uniqframe { const struct sk_buff *skb; - int skbcnt; + u32 hash; unsigned int join_rx_count; }; =20 struct raw_sock { struct sock sk; @@ -162,21 +162,21 @@ static void raw_rcv(struct sk_buff *oskb, void *data) } } =20 /* eliminate multiple filter matches for the same skb */ if (this_cpu_ptr(ro->uniq)->skb =3D=3D oskb && - this_cpu_ptr(ro->uniq)->skbcnt =3D=3D can_skb_prv(oskb)->skbcnt) { + this_cpu_ptr(ro->uniq)->hash =3D=3D oskb->hash) { if (!ro->join_filters) return; =20 this_cpu_inc(ro->uniq->join_rx_count); /* drop frame until all enabled filters matched */ if (this_cpu_ptr(ro->uniq)->join_rx_count < ro->count) return; } else { this_cpu_ptr(ro->uniq)->skb =3D oskb; - this_cpu_ptr(ro->uniq)->skbcnt =3D can_skb_prv(oskb)->skbcnt; + this_cpu_ptr(ro->uniq)->hash =3D oskb->hash; this_cpu_ptr(ro->uniq)->join_rx_count =3D 1; /* drop first frame to check all enabled filters? */ if (ro->join_filters && ro->count > 1) return; } @@ -956,11 +956,10 @@ static int raw_sendmsg(struct socket *sock, struct ms= ghdr *msg, size_t size) if (!skb) goto put_dev; =20 can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D dev->ifindex; - can_skb_prv(skb)->skbcnt =3D 0; =20 /* fill the skb before testing for valid CAN frames */ err =3D memcpy_from_msg(skb_put(skb, size), msg, size); if (err < 0) goto free_skb; --=20 2.51.0 From nobody Mon Feb 9 09:23:05 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ED122352946; Sat, 31 Jan 2026 13:25:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769865915; cv=none; b=NjYf235UFUCqH1pjSYcEcZBQidIdBOrLg1Qi1U1FRNPoQur/d6hr6QJiCgq36FveeBkHc8kBxpt9bID3QSVjsshY9+GKjEPHWVZe4W43SOWyLzAdhgvg1P6czD1jH+3qY1mhDdRWzAbEFTD4obAZRJRbr0Tza8I7qTsEEIgK4y0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769865915; c=relaxed/simple; bh=PsBNbtV0anz4gJVrJ3+/Gm1XjZ2Adh8XCGdNB5tzPyI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=AbLj1WWyOFzyBKYZFDYLpcEKdCV/nMIDp7CQhrLWyrTljmGWEZMfOF/LUihMbjit253B2e0gC9i23uxSQOSJgWgmM6yo8vjMPE5IyRm5xTSrHy1/gqs1+EXSKFr7OagSWrubBFqxXlHJ9CTAHxMI56DjeV45gdvGsFePto/nx28= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Z/ZssJoo; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Z/ZssJoo" Received: by smtp.kernel.org (Postfix) with ESMTPS id B6819C2BC86; Sat, 31 Jan 2026 13:25:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1769865914; bh=PsBNbtV0anz4gJVrJ3+/Gm1XjZ2Adh8XCGdNB5tzPyI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Z/ZssJooadduB/+cSDMmc3Dtd+qTR8lnyn+4DdiBcn8Ka3l3WSApQ1HzBuOzdY//w sVJgpVCDNS+ms7ST803Qkobw66G+U43kpZ/ec7fL2E2cOWdyf5wTVMTJILdJb9JfYe 7k6T4s+vvkUHHeGvuQSycc1TAo/Crd6l8/fDJI7RNh2ffWN2m+nmUAF+pTzBAtOIEV dEWto56WqqaoAWE8SnlC7Y+nMu43+fiTVlhyVfnWO+1lIYq459523lJ4pwzspEJ4PY f1sf/esPgFy/5Ja87zWowps8f5vxOxrn/4CrbQoEZmw9allYgnic/31Y5awwIqLbhc twkTOI/QhZXyw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id A703BD79769; Sat, 31 Jan 2026 13:25:14 +0000 (UTC) From: Oliver Hartkopp via B4 Relay Date: Sat, 31 Jan 2026 14:25:07 +0100 Subject: [PATCH net-next v7 2/6] can: add CAN skb extension infrastructure Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260131-can_skb_ext-v7-2-dd0f8f84a83d@hartkopp.net> References: <20260131-can_skb_ext-v7-0-dd0f8f84a83d@hartkopp.net> In-Reply-To: <20260131-can_skb_ext-v7-0-dd0f8f84a83d@hartkopp.net> To: Marc Kleine-Budde , Vincent Mailhol , Oliver Hartkopp , Robin van der Gracht , Oleksij Rempel , kernel@pengutronix.de, "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman Cc: linux-can@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org X-Mailer: b4 0.15-dev-47773 X-Developer-Signature: v=1; a=ed25519-sha256; t=1769865912; l=26471; i=socketcan@hartkopp.net; s=20260128; h=from:subject:message-id; bh=2oA0C35sU+xq4mW5Fv23zTu6yCBGqaQ8Kytx/tbEU/Q=; b=UO1a2f4ryq7ZigJc9ZfkokpPtNYGGyNLYtlfaXcfA2ba7/BqHCn4qdClXCJqBPNuJFw1NG3om l3W6zBvMQuLDGXibx6On9ldgsRcDFypI8E65HdmJqgg/YzducAlvtg4 X-Developer-Key: i=socketcan@hartkopp.net; a=ed25519; pk=/gU/7/wBqak3kTsTeFbCCqUi9dnh+1i6ITEkfPj/BvU= X-Endpoint-Received: by B4 Relay for socketcan@hartkopp.net/20260128 with auth_id=620 X-Original-From: Oliver Hartkopp Reply-To: socketcan@hartkopp.net From: Oliver Hartkopp 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 Signed-off-by: Marc Kleine-Budde Signed-off-by: Oliver Hartkopp --- MAINTAINERS | 1 + drivers/net/can/dev/skb.c | 56 +++++++++++++++++++++++++++++++++++++------= ---- drivers/net/can/vxcan.c | 14 ++++++++++++ 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 | 24 ++++++++++++++++++++ net/can/j1939/socket.c | 8 +++++++ net/can/j1939/transport.c | 28 +++++++++++++++++++++++- net/can/raw.c | 8 +++++++ net/core/skbuff.c | 4 ++++ 15 files changed, 218 insertions(+), 15 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index c3df85fd5acd..97f276375219 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5632,10 +5632,11 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/gi= t/mkl/linux-can-next.git F: Documentation/networking/can.rst 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 F: include/uapi/linux/can/gw.h F: include/uapi/linux/can/isotp.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 @@ -4,10 +4,11 @@ * Copyright (C) 2008-2009 Wolfgang Grandegger */ =20 #include #include +#include =20 #define MOD_DESC "CAN device driver interface" =20 MODULE_DESCRIPTION(MOD_DESC); MODULE_LICENSE("GPL v2"); @@ -205,40 +206,53 @@ static void init_can_skb_reserve(struct sk_buff *skb) } =20 struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **c= f) { struct sk_buff *skb; + struct can_skb_ext *csx; =20 skb =3D netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + sizeof(struct can_frame)); - if (unlikely(!skb)) { - *cf =3D NULL; + if (unlikely(!skb)) + goto out_error_cc; =20 - return NULL; + csx =3D can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + goto out_error_cc; } =20 skb->protocol =3D htons(ETH_P_CAN); init_can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D dev->ifindex; =20 *cf =3D skb_put_zero(skb, sizeof(struct can_frame)); =20 return skb; + +out_error_cc: + *cf =3D NULL; + + return NULL; } EXPORT_SYMBOL_GPL(alloc_can_skb); =20 struct sk_buff *alloc_canfd_skb(struct net_device *dev, struct canfd_frame **cfd) { struct sk_buff *skb; + struct can_skb_ext *csx; =20 skb =3D netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + sizeof(struct canfd_frame)); - if (unlikely(!skb)) { - *cfd =3D NULL; + if (unlikely(!skb)) + goto out_error_fd; =20 - return NULL; + csx =3D can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + goto out_error_fd; } =20 skb->protocol =3D htons(ETH_P_CANFD); init_can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D dev->ifindex; @@ -247,26 +261,38 @@ struct sk_buff *alloc_canfd_skb(struct net_device *de= v, =20 /* set CAN FD flag by default */ (*cfd)->flags =3D CANFD_FDF; =20 return skb; + +out_error_fd: + *cfd =3D NULL; + + return NULL; } EXPORT_SYMBOL_GPL(alloc_canfd_skb); =20 struct sk_buff *alloc_canxl_skb(struct net_device *dev, struct canxl_frame **cxl, unsigned int data_len) { struct sk_buff *skb; + struct can_skb_ext *csx; =20 if (data_len < CANXL_MIN_DLEN || data_len > CANXL_MAX_DLEN) - goto out_error; + goto out_error_xl; =20 skb =3D 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 =3D can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + goto out_error_xl; + } =20 skb->protocol =3D htons(ETH_P_CANXL); init_can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D dev->ifindex; =20 @@ -276,11 +302,11 @@ struct sk_buff *alloc_canxl_skb(struct net_device *de= v, (*cxl)->flags =3D CANXL_XLF; (*cxl)->len =3D data_len; =20 return skb; =20 -out_error: +out_error_xl: *cxl =3D NULL; =20 return NULL; } EXPORT_SYMBOL_GPL(alloc_canxl_skb); @@ -301,17 +327,25 @@ struct sk_buff *alloc_can_err_skb(struct net_device *= dev, struct can_frame **cf) EXPORT_SYMBOL_GPL(alloc_can_err_skb); =20 /* 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 =3D 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; =20 /* af_packet does not apply CAN skb specific settings */ - if (skb->ip_summed =3D=3D CHECKSUM_NONE) { - /* init headroom */ + if (skb->ip_summed =3D=3D CHECKSUM_NONE || !csx) { + /* init CAN skb content */ + if (!csx) { + csx =3D can_skb_ext_add(skb); + if (!csx) + return false; + } + can_skb_prv(skb)->ifindex =3D dev->ifindex; =20 skb->ip_summed =3D CHECKSUM_UNNECESSARY; =20 /* perform proper loopback on capable devices */ diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index f14c6f02b662..53d7d9046f85 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -19,10 +19,11 @@ #include #include #include #include #include +#include #include =20 #define DRV_NAME "vxcan" =20 MODULE_DESCRIPTION("Virtual CAN Tunnel"); @@ -37,10 +38,11 @@ struct vxcan_priv { static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, struct net_device *dev) { struct vxcan_priv *priv =3D netdev_priv(dev); struct net_device *peer; struct net_device_stats *peerstats, *srcstats =3D &dev->stats; + struct can_skb_ext *csx; struct sk_buff *skb; unsigned int len; =20 if (can_dropped_invalid_skb(dev, oskb)) return NETDEV_TX_OK; @@ -61,10 +63,22 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, str= uct net_device *dev) } else { kfree_skb(oskb); goto out_unlock; } =20 + /* the cloned skb points to the skb extension of the original 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 =3D skb_ext_add(skb, SKB_EXT_CAN); + if (!csx) { + kfree_skb(skb); + kfree_skb(oskb); + goto out_unlock; + } + /* reset CAN GW hop counter */ skb->csum_start =3D 0; skb->pkt_type =3D PACKET_BROADCAST; skb->dev =3D peer; skb->ip_summed =3D CHECKSUM_UNNECESSARY; 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 @@ -12,10 +12,11 @@ #define _CAN_SKB_H =20 #include #include #include +#include #include =20 void can_flush_echo_skb(struct net_device *dev); int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, unsigned int idx, unsigned int frame_len); @@ -66,10 +67,26 @@ static inline struct can_skb_priv *can_skb_prv(struct s= k_buff *skb) static inline void can_skb_reserve(struct sk_buff *skb) { skb_reserve(skb, sizeof(struct can_skb_priv)); } =20 +static inline struct can_skb_ext *can_skb_ext_add(struct sk_buff *skb) +{ + struct can_skb_ext *csx =3D skb_ext_add(skb, SKB_EXT_CAN); + + /* skb_ext_add() returns uninitialized space */ + if (csx) + csx->can_gw_hops =3D 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 * refcount may already be 0 (and the socket will be freed * after the last TX skb has been freed). So only increase diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index e6bfe5d0c525..b5beb28e5730 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -4986,10 +4986,13 @@ enum skb_ext_id { #if IS_ENABLED(CONFIG_MCTP_FLOWS) SKB_EXT_MCTP, #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 */ }; =20 /** 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 @@ -3,10 +3,11 @@ # Controller Area Network (CAN) network layer core configuration # =20 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 1983 at Robert Bosch GmbH, and the protocol was officially released in 1986. The CAN bus was originally mainly for automotive, 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 @@ -685,11 +685,12 @@ static void can_receive(struct sk_buff *skb, struct n= et_device *dev) } =20 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 !=3D ARPHRD_CAN || !can_get_ml_priv(dev) || !can_i= s_can_skb(skb))) { + if (unlikely(dev->type !=3D 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); =20 kfree_skb_reason(skb, SKB_DROP_REASON_CAN_RX_INVALID_FRAME); return NET_RX_DROP; @@ -700,11 +701,12 @@ static int can_rcv(struct sk_buff *skb, struct net_de= vice *dev, } =20 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 !=3D ARPHRD_CAN || !can_get_ml_priv(dev) || !can_i= s_canfd_skb(skb))) { + if (unlikely(dev->type !=3D 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, le= n %d\n", dev->type, skb->len); =20 kfree_skb_reason(skb, SKB_DROP_REASON_CANFD_RX_INVALID_FRAME); return NET_RX_DROP; @@ -715,11 +717,12 @@ static int canfd_rcv(struct sk_buff *skb, struct net_= device *dev, } =20 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 !=3D ARPHRD_CAN || !can_get_ml_priv(dev) || !can_i= s_canxl_skb(skb))) { + if (unlikely(dev->type !=3D 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, le= n %d\n", dev->type, skb->len); =20 kfree_skb_reason(skb, SKB_DROP_REASON_CANXL_RX_INVALID_FRAME); return NET_RX_DROP; 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 @@ -57,10 +57,11 @@ #include #include #include #include #include +#include #include #include =20 /* * To send multiple CAN frame content within TX_SETUP or to filter @@ -289,10 +290,11 @@ static int bcm_proc_show(struct seq_file *m, void *v) * of the given bcm tx op */ 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; =20 /* no target device? =3D> exit */ @@ -312,10 +314,16 @@ static void bcm_can_tx(struct bcm_op *op) =20 skb =3D alloc_skb(op->cfsiz + sizeof(struct can_skb_priv), gfp_any()); if (!skb) goto out; =20 + csx =3D can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + goto out; + } + can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D dev->ifindex; =20 skb_put_data(skb, cf, op->cfsiz); =20 @@ -1315,10 +1323,11 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_he= ad, struct msghdr *msg, */ 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; =20 /* we need a real device to send frames */ if (!ifindex) @@ -1326,10 +1335,16 @@ static int bcm_tx_send(struct msghdr *msg, int ifin= dex, struct sock *sk, =20 skb =3D alloc_skb(cfsiz + sizeof(struct can_skb_priv), GFP_KERNEL); if (!skb) return -ENOMEM; =20 + csx =3D can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + return -ENOMEM; + } + can_skb_reserve(skb); =20 err =3D memcpy_from_msg(skb_put(skb, cfsiz), msg, cfsiz); if (err < 0) { kfree_skb(skb); 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 @@ -53,10 +53,11 @@ #include #include #include #include #include +#include #include #include #include =20 #define CAN_GW_NAME "can-gw" @@ -457,10 +458,11 @@ static void cgw_csum_crc8_neg(struct canfd_frame *cf, static void can_can_gw_rcv(struct sk_buff *skb, void *data) { struct cgw_job *gwj =3D (struct cgw_job *)data; struct canfd_frame *cf; struct sk_buff *nskb; + struct can_skb_ext *csx, *ncsx; struct cf_mod *mod; int modidx =3D 0; =20 /* process strictly Classic CAN or CAN FD frames */ if (gwj->flags & CGW_FLAGS_CAN_FD) { @@ -469,10 +471,14 @@ static void can_can_gw_rcv(struct sk_buff *skb, void = *data) } else { if (!can_is_can_skb(skb)) return; } =20 + csx =3D 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). * * The Controller Area Network controllers only accept CAN frames with @@ -516,10 +522,21 @@ static void can_can_gw_rcv(struct sk_buff *skb, void = *data) if (!nskb) { gwj->dropped_frames++; return; } =20 + /* 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 =3D 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) =3D cgw_hops(skb) + 1; =20 /* first processing of this CAN frame -> adjust to private hop limit */ if (gwj->limit_hops && cgw_hops(nskb) =3D=3D 1) diff --git a/net/can/isotp.c b/net/can/isotp.c index 4bb60b8f9b96..94103fe654ff 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -67,10 +67,11 @@ #include #include #include #include #include +#include #include #include =20 MODULE_DESCRIPTION("PF_CAN ISO 15765-2 transport protocol"); MODULE_LICENSE("Dual BSD/GPL"); @@ -212,18 +213,25 @@ static enum hrtimer_restart isotp_rx_timer_handler(st= ruct hrtimer *hrtimer) =20 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 =3D isotp_sk(sk); int can_send_ret; =20 nskb =3D alloc_skb(so->ll.mtu + sizeof(struct can_skb_priv), gfp_any()); if (!nskb) return 1; =20 + csx =3D can_skb_ext_add(nskb); + if (!csx) { + kfree_skb(nskb); + return 1; + } + dev =3D dev_get_by_index(sock_net(sk), so->ifindex); if (!dev) { kfree_skb(nskb); return 1; } @@ -760,10 +768,11 @@ static void isotp_fill_dataframe(struct canfd_frame *= cf, struct isotp_sock *so, =20 static void isotp_send_cframe(struct isotp_sock *so) { struct sock *sk =3D &so->sk; struct sk_buff *skb; + struct can_skb_ext *csx; struct net_device *dev; struct canfd_frame *cf; int can_send_ret; int ae =3D (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0; =20 @@ -775,10 +784,17 @@ static void isotp_send_cframe(struct isotp_sock *so) if (!skb) { dev_put(dev); return; } =20 + csx =3D can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + netdev_put(dev, NULL); + return; + } + can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D dev->ifindex; =20 cf =3D (struct canfd_frame *)skb->data; skb_put_zero(skb, so->ll.mtu); @@ -936,10 +952,11 @@ static enum hrtimer_restart isotp_txfr_timer_handler(= struct hrtimer *hrtimer) static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t s= ize) { struct sock *sk =3D sock->sk; struct isotp_sock *so =3D isotp_sk(sk); struct sk_buff *skb; + struct can_skb_ext *csx; struct net_device *dev; struct canfd_frame *cf; int ae =3D (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0; int wait_tx_done =3D (so->opt.flags & CAN_ISOTP_WAIT_TX_DONE) ? 1 : 0; s64 hrtimer_sec =3D ISOTP_ECHO_TIMEOUT; @@ -1003,10 +1020,17 @@ static int isotp_sendmsg(struct socket *sock, struc= t msghdr *msg, size_t size) if (!skb) { dev_put(dev); goto err_out_drop; } =20 + csx =3D can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + netdev_put(dev, NULL); + goto err_out_drop; + } + can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D dev->ifindex; =20 so->tx.len =3D size; so->tx.idx =3D 0; diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c index 1589e8ca634e..fc28a7677369 100644 --- a/net/can/j1939/socket.c +++ b/net/can/j1939/socket.c @@ -15,10 +15,11 @@ #include #include #include #include #include +#include =20 #include "j1939-priv.h" =20 #define J1939_MIN_NAMELEN CAN_REQUIRED_SIZE(struct sockaddr_can, can_addr.= j1939) =20 @@ -882,10 +883,11 @@ static struct sk_buff *j1939_sk_alloc_skb(struct net_= device *ndev, int *errcode) { struct j1939_sock *jsk =3D j1939_sk(sk); struct j1939_sk_buff_cb *skcb; struct sk_buff *skb; + struct can_skb_ext *csx; int ret; =20 skb =3D sock_alloc_send_skb(sk, size + sizeof(struct can_frame) - @@ -893,10 +895,16 @@ static struct sk_buff *j1939_sk_alloc_skb(struct net_= device *ndev, sizeof(struct can_skb_priv), msg->msg_flags & MSG_DONTWAIT, &ret); if (!skb) goto failure; =20 + csx =3D can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + goto failure; + } + can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D ndev->ifindex; skb_reserve(skb, offsetof(struct can_frame, data)); =20 ret =3D memcpy_from_msg(skb_put(skb, size), msg, size); diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c index d5d3e5320f7a..16b4ea5e31ff 100644 --- a/net/can/j1939/transport.c +++ b/net/can/j1939/transport.c @@ -7,10 +7,11 @@ // Marc Kleine-Budde // Copyright (c) 2017-2019 Pengutronix, // Oleksij Rempel =20 #include +#include =20 #include "j1939-priv.h" =20 #define J1939_XTP_TX_RETRY_LIMIT 100 =20 @@ -589,17 +590,24 @@ sk_buff *j1939_tp_tx_dat_new(struct j1939_priv *priv, const struct j1939_sk_buff_cb *re_skcb, bool ctl, bool swap_src_dst) { struct sk_buff *skb; + struct can_skb_ext *csx; struct j1939_sk_buff_cb *skcb; =20 skb =3D alloc_skb(sizeof(struct can_frame) + sizeof(struct can_skb_priv), GFP_ATOMIC); if (unlikely(!skb)) return ERR_PTR(-ENOMEM); =20 + csx =3D can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + return ERR_PTR(-ENOMEM); + } + skb->dev =3D priv->ndev; can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D priv->ndev->ifindex; /* reserve CAN header */ skb_reserve(skb, offsetof(struct can_frame, data)); @@ -1049,11 +1057,22 @@ static int j1939_simple_txnext(struct j1939_session= *session) if (!skb) { ret =3D -ENOMEM; goto out_free; } =20 - can_skb_set_owner(skb, se_skb->sk); + /* 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 =3D -ENOMEM; + goto out_free; + } + + can_skb_set_owner(skb, se_skb->sk); =20 j1939_tp_set_rxtimeout(session, J1939_SIMPLE_ECHO_TIMEOUT_MS); =20 ret =3D j1939_send_one(priv, skb); if (ret) @@ -1523,17 +1542,24 @@ static struct j1939_session *j1939_session_fresh_new(struct j1939_priv *priv, int size, 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; =20 skb =3D alloc_skb(size + sizeof(struct can_skb_priv), GFP_ATOMIC); if (unlikely(!skb)) return NULL; =20 + csx =3D can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + return NULL; + } + skb->dev =3D priv->ndev; can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D priv->ndev->ifindex; skcb =3D j1939_skb_to_cb(skb); memcpy(skcb, rel_skcb, sizeof(*skcb)); diff --git a/net/can/raw.c b/net/can/raw.c index fb4f9c854df0..03438e9bc535 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -51,10 +51,11 @@ #include #include #include #include #include +#include #include #include =20 MODULE_DESCRIPTION("PF_CAN raw protocol"); MODULE_LICENSE("Dual BSD/GPL"); @@ -916,10 +917,11 @@ static int raw_sendmsg(struct socket *sock, struct ms= ghdr *msg, size_t size) { struct sock *sk =3D sock->sk; struct raw_sock *ro =3D 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; int err =3D -EINVAL; =20 @@ -954,10 +956,16 @@ static int raw_sendmsg(struct socket *sock, struct ms= ghdr *msg, size_t size) skb =3D sock_alloc_send_skb(sk, size + sizeof(struct can_skb_priv), msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) goto put_dev; =20 + csx =3D can_skb_ext_add(skb); + if (!csx) { + kfree_skb(skb); + goto put_dev; + } + can_skb_reserve(skb); can_skb_prv(skb)->ifindex =3D dev->ifindex; =20 /* fill the skb before testing for valid CAN frames */ err =3D memcpy_from_msg(skb_put(skb, size), msg, size); 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 @@ -76,10 +76,11 @@ #include #include #include #include #include +#include #include #include #include #include =20 @@ -5137,10 +5138,13 @@ static const u8 skb_ext_type_len[] =3D { [SKB_EXT_MCTP] =3D SKB_EXT_CHUNKSIZEOF(struct mctp_flow), #endif #if IS_ENABLED(CONFIG_INET_PSP) [SKB_EXT_PSP] =3D SKB_EXT_CHUNKSIZEOF(struct psp_skb_ext), #endif +#if IS_ENABLED(CONFIG_CAN) + [SKB_EXT_CAN] =3D SKB_EXT_CHUNKSIZEOF(struct can_skb_ext), +#endif }; =20 static __always_inline unsigned int skb_ext_total_length(void) { unsigned int l =3D SKB_EXT_CHUNKSIZEOF(struct skb_ext); --=20 2.51.0 From nobody Mon Feb 9 09:23:05 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F285A35294E; Sat, 31 Jan 2026 13:25:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769865915; cv=none; b=gA099fzJDlPba95BPCMmDXKITYkywuAXDke95bjm2oHfuwot9EwfeMy5p/YNcQ/xO0y8eb2b7/J6ip6NXqW58bpEydkiDFvbiauPr8itIzQ1OB0yuRHw+Xnt+pJJFUcamQO79DVATQUQuielIfRzm/0S6Kq4/MbHpo1zOVI+wCg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769865915; c=relaxed/simple; bh=UHSJbd0qY7BE8fwJbao5Yn+bKzFnj5ZCjpST0YvegHU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jXzYVJgOAhBh3HDGUKp01jXHWtssKbz41Eob0xbN8zzXbSeF8pDI0cNgn5RSZi4bpY28ywNzF5qd5wqILp98ibqRzjCzMfTnT+3sGbprHpQ+zBQoQ5lI9Scsbc+ebBxl5aiwPpjl6KbFbAUojEol/eEIT3/E6C8P192cj3eLpzw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=J8QPMfLK; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="J8QPMfLK" Received: by smtp.kernel.org (Postfix) with ESMTPS id C0B2EC2BC87; Sat, 31 Jan 2026 13:25:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1769865914; bh=UHSJbd0qY7BE8fwJbao5Yn+bKzFnj5ZCjpST0YvegHU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=J8QPMfLK7rxfT+kHtWjKzDpPyHjQYqkokxk5qqnIigjBltuBbARB7mOPHSHJHDgfJ 1sduXuO15xLM4fNIFKPykNiCRRaqW7aJZPa9OmtfrVu5sofVeNeM9YpFH3+IbyHSGI tbxL3qLXTZfz8h3MrQ+2IOVgX3tF1mnvCqSIFXuHm2/l55hX5x8cgJAeG2hc0zCYvw obQRV8v2kMUqjrkogedbYMmsHbyKSWg0GfMKdZ+ljPc2lLByA0TT8xoTlz5kIeLtbr DCv+2IPnJX4Ydp49YNXiQ4AGoJ1/uRCNEMXEMHVa5HC4mj2ex6P/gw3N4jTfoso5ZL cO5CQA5eZCU/w== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id B773ED79770; Sat, 31 Jan 2026 13:25:14 +0000 (UTC) From: Oliver Hartkopp via B4 Relay Date: Sat, 31 Jan 2026 14:25:08 +0100 Subject: [PATCH net-next v7 3/6] can: move ifindex to CAN skb extensions Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260131-can_skb_ext-v7-3-dd0f8f84a83d@hartkopp.net> References: <20260131-can_skb_ext-v7-0-dd0f8f84a83d@hartkopp.net> In-Reply-To: <20260131-can_skb_ext-v7-0-dd0f8f84a83d@hartkopp.net> To: Marc Kleine-Budde , Vincent Mailhol , Oliver Hartkopp , Robin van der Gracht , Oleksij Rempel , kernel@pengutronix.de, "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman Cc: linux-can@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org X-Mailer: b4 0.15-dev-47773 X-Developer-Signature: v=1; a=ed25519-sha256; t=1769865912; l=7268; i=socketcan@hartkopp.net; s=20260128; h=from:subject:message-id; bh=wMw9byBhQyOCKPJ0md/sAo7e7Aa5o2G/FpRbTmJ6S/o=; b=HUB9mSYjXW5ntHM+E98OzOSd57qcBRDv/OYwMIcCah95dYfHWaXZc55mZvwK1sETg+sVJPtAg 9GbofOdRmTyAxKYp1jw5Mmcq6rIAJcqIL/TMxKo023UsvLYFXJb0NKr X-Developer-Key: i=socketcan@hartkopp.net; a=ed25519; pk=/gU/7/wBqak3kTsTeFbCCqUi9dnh+1i6ITEkfPj/BvU= X-Endpoint-Received: by B4 Relay for socketcan@hartkopp.net/20260128 with auth_id=620 X-Original-From: Oliver Hartkopp Reply-To: socketcan@hartkopp.net From: Oliver Hartkopp When routing CAN frames over different CAN interfaces the interface index skb->iif is overwritten with every single hop. To prevent sending a CAN frame back to its originating (first) incoming CAN interface another ifindex variable is needed, which was stored in can_skb_priv::ifindex. Move the can_skb_priv::ifindex content to can_skb_ext::can_iif. Signed-off-by: Marc Kleine-Budde Signed-off-by: Oliver Hartkopp --- drivers/net/can/dev/skb.c | 9 ++++----- net/can/bcm.c | 4 ++-- net/can/gw.c | 2 +- net/can/isotp.c | 6 +++--- net/can/j1939/socket.c | 2 +- net/can/j1939/transport.c | 4 ++-- net/can/raw.c | 2 +- 7 files changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c index c572745565f6..470255fe7367 100644 --- a/drivers/net/can/dev/skb.c +++ b/drivers/net/can/dev/skb.c @@ -221,11 +221,11 @@ struct sk_buff *alloc_can_skb(struct net_device *dev,= struct can_frame **cf) goto out_error_cc; } =20 skb->protocol =3D htons(ETH_P_CAN); init_can_skb_reserve(skb); - can_skb_prv(skb)->ifindex =3D dev->ifindex; + csx->can_iif =3D dev->ifindex; =20 *cf =3D skb_put_zero(skb, sizeof(struct can_frame)); =20 return skb; =20 @@ -253,11 +253,11 @@ struct sk_buff *alloc_canfd_skb(struct net_device *de= v, goto out_error_fd; } =20 skb->protocol =3D htons(ETH_P_CANFD); init_can_skb_reserve(skb); - can_skb_prv(skb)->ifindex =3D dev->ifindex; + csx->can_iif =3D dev->ifindex; =20 *cfd =3D skb_put_zero(skb, sizeof(struct canfd_frame)); =20 /* set CAN FD flag by default */ (*cfd)->flags =3D CANFD_FDF; @@ -292,11 +292,11 @@ struct sk_buff *alloc_canxl_skb(struct net_device *de= v, goto out_error_xl; } =20 skb->protocol =3D htons(ETH_P_CANXL); init_can_skb_reserve(skb); - can_skb_prv(skb)->ifindex =3D dev->ifindex; + csx->can_iif =3D dev->ifindex; =20 *cxl =3D skb_put_zero(skb, CANXL_HDR_SIZE + data_len); =20 /* set CAN XL flag and length information by default */ (*cxl)->flags =3D CANXL_XLF; @@ -342,12 +342,11 @@ static bool can_skb_headroom_valid(struct net_device = *dev, struct sk_buff *skb) csx =3D can_skb_ext_add(skb); if (!csx) return false; } =20 - can_skb_prv(skb)->ifindex =3D dev->ifindex; - + csx->can_iif =3D dev->ifindex; skb->ip_summed =3D CHECKSUM_UNNECESSARY; =20 /* perform proper loopback on capable devices */ if (dev->flags & IFF_ECHO) skb->pkt_type =3D PACKET_LOOPBACK; diff --git a/net/can/bcm.c b/net/can/bcm.c index 38452069dea8..f102d17e8619 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -321,11 +321,11 @@ static void bcm_can_tx(struct bcm_op *op) kfree_skb(skb); goto out; } =20 can_skb_reserve(skb); - can_skb_prv(skb)->ifindex =3D dev->ifindex; + csx->can_iif =3D dev->ifindex; =20 skb_put_data(skb, cf, op->cfsiz); =20 /* send with loopback */ skb->dev =3D dev; @@ -1355,11 +1355,11 @@ static int bcm_tx_send(struct msghdr *msg, int ifin= dex, struct sock *sk, if (!dev) { kfree_skb(skb); return -ENODEV; } =20 - can_skb_prv(skb)->ifindex =3D dev->ifindex; + csx->can_iif =3D dev->ifindex; skb->dev =3D dev; can_skb_set_owner(skb, sk); err =3D can_send(skb, 1); /* send with loopback */ dev_put(dev); =20 diff --git a/net/can/gw.c b/net/can/gw.c index 191afe3b673c..816154a978c1 100644 --- a/net/can/gw.c +++ b/net/can/gw.c @@ -503,11 +503,11 @@ static void can_can_gw_rcv(struct sk_buff *skb, void = *data) return; } =20 /* is sending the skb back to the incoming interface not allowed? */ if (!(gwj->flags & CGW_FLAGS_CAN_IIF_TX_OK) && - can_skb_prv(skb)->ifindex =3D=3D gwj->dst.dev->ifindex) + csx->can_iif =3D=3D gwj->dst.dev->ifindex) return; =20 /* clone the given skb, which has not been done in can_rcv() * * When there is at least one modification function activated, diff --git a/net/can/isotp.c b/net/can/isotp.c index 94103fe654ff..4a6ce6836b24 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -235,11 +235,11 @@ static int isotp_send_fc(struct sock *sk, int ae, u8 = flowstatus) kfree_skb(nskb); return 1; } =20 can_skb_reserve(nskb); - can_skb_prv(nskb)->ifindex =3D dev->ifindex; + csx->can_iif =3D dev->ifindex; =20 nskb->dev =3D dev; can_skb_set_owner(nskb, sk); ncf =3D (struct canfd_frame *)nskb->data; skb_put_zero(nskb, so->ll.mtu); @@ -792,11 +792,11 @@ static void isotp_send_cframe(struct isotp_sock *so) netdev_put(dev, NULL); return; } =20 can_skb_reserve(skb); - can_skb_prv(skb)->ifindex =3D dev->ifindex; + csx->can_iif =3D dev->ifindex; =20 cf =3D (struct canfd_frame *)skb->data; skb_put_zero(skb, so->ll.mtu); =20 /* create consecutive frame */ @@ -1028,11 +1028,11 @@ static int isotp_sendmsg(struct socket *sock, struc= t msghdr *msg, size_t size) netdev_put(dev, NULL); goto err_out_drop; } =20 can_skb_reserve(skb); - can_skb_prv(skb)->ifindex =3D dev->ifindex; + csx->can_iif =3D dev->ifindex; =20 so->tx.len =3D size; so->tx.idx =3D 0; =20 cf =3D (struct canfd_frame *)skb->data; diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c index fc28a7677369..f03bae79354e 100644 --- a/net/can/j1939/socket.c +++ b/net/can/j1939/socket.c @@ -902,11 +902,11 @@ static struct sk_buff *j1939_sk_alloc_skb(struct net_= device *ndev, kfree_skb(skb); goto failure; } =20 can_skb_reserve(skb); - can_skb_prv(skb)->ifindex =3D ndev->ifindex; + csx->can_iif =3D ndev->ifindex; skb_reserve(skb, offsetof(struct can_frame, data)); =20 ret =3D memcpy_from_msg(skb_put(skb, size), msg, size); if (ret < 0) goto free_skb; diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c index 16b4ea5e31ff..88f99a6f5c8e 100644 --- a/net/can/j1939/transport.c +++ b/net/can/j1939/transport.c @@ -606,11 +606,11 @@ sk_buff *j1939_tp_tx_dat_new(struct j1939_priv *priv, return ERR_PTR(-ENOMEM); } =20 skb->dev =3D priv->ndev; can_skb_reserve(skb); - can_skb_prv(skb)->ifindex =3D priv->ndev->ifindex; + csx->can_iif =3D priv->ndev->ifindex; /* reserve CAN header */ skb_reserve(skb, offsetof(struct can_frame, data)); =20 /* skb->cb must be large enough to hold a j1939_sk_buff_cb structure */ BUILD_BUG_ON(sizeof(skb->cb) < sizeof(*re_skcb)); @@ -1558,11 +1558,11 @@ j1939_session *j1939_session_fresh_new(struct j1939= _priv *priv, return NULL; } =20 skb->dev =3D priv->ndev; can_skb_reserve(skb); - can_skb_prv(skb)->ifindex =3D priv->ndev->ifindex; + csx->can_iif =3D priv->ndev->ifindex; skcb =3D j1939_skb_to_cb(skb); memcpy(skcb, rel_skcb, sizeof(*skcb)); =20 session =3D j1939_session_new(priv, skb, size); if (!session) { diff --git a/net/can/raw.c b/net/can/raw.c index 03438e9bc535..7c89962ec913 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -963,11 +963,11 @@ static int raw_sendmsg(struct socket *sock, struct ms= ghdr *msg, size_t size) kfree_skb(skb); goto put_dev; } =20 can_skb_reserve(skb); - can_skb_prv(skb)->ifindex =3D dev->ifindex; + csx->can_iif =3D dev->ifindex; =20 /* fill the skb before testing for valid CAN frames */ err =3D memcpy_from_msg(skb_put(skb, size), msg, size); if (err < 0) goto free_skb; --=20 2.51.0 From nobody Mon Feb 9 09:23:05 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0A6D2352C22; Sat, 31 Jan 2026 13:25:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769865915; cv=none; b=U+/7R145Vpp+uQfCWjKot3siURYtx3yGwuhUlhJnTrbpkNbus32tWuR5Izy+7W06Tz/I+qpLFeFBISN9OI4VpbjGgcYwxVKNjZxO6ufOP2ihjYGegYIuHBg0F6j6M2ICefwYFgv4OsSG92iLioLOMyoFNiY8bo2LB9sQJhEKA2U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769865915; c=relaxed/simple; bh=SBs/C150pguj/vCEZlWhOTRKiUV8IQgb9NQzwVbQ8vI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=otH5EUa4pPV8Pl/KhYF1HkgVbQb3IdsDOcMUP2UxH6YvRlsld0Y3V+r2xOwTqF7PHm+H8evQJnyVYbbbOU9+nCcmyNvhDIC/FvJSqPbKI/5Lp0Esan7y1eAGB1JbHiM9/8IofUUmrD2vgOna0jUES9mnemFkPrgBDmFyKOhAY68= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=QVqEiJtg; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QVqEiJtg" Received: by smtp.kernel.org (Postfix) with ESMTPS id CE126C2BCB0; Sat, 31 Jan 2026 13:25:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1769865914; bh=SBs/C150pguj/vCEZlWhOTRKiUV8IQgb9NQzwVbQ8vI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=QVqEiJtga9ljWDru0ompsCQCyvwzw2RHek5JEc722qg1ROtQmUIXld6xRNksk1a5Q psa5wAQYz6YFVExDiyIt0j3KNGgzcRZQn4VZroeXOMvwcVo8VjGmOdPqF1l0c3wOau IcSXLjpdYK5cR6HNaGtFV+iiTJpb8+8nRpyR7jqqPxdN8figEqJT/3NZSTf9JoZ1Ky L0WJN0nygVjBM3O5e4aLl8gw3F1vb9uvnmXW6vtElrdXCA5ozWBi64dRRknVL1zz1c eNMMvS7MkdiESSFXvDEWvNMnp9EvyfRccT/r/TcYykLevOeCiJ7D+2rPtNLXI4HCAL gVptXIituChHw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id C5AE0D7976C; Sat, 31 Jan 2026 13:25:14 +0000 (UTC) From: Oliver Hartkopp via B4 Relay Date: Sat, 31 Jan 2026 14:25:09 +0100 Subject: [PATCH net-next v7 4/6] can: move frame_len to CAN skb extensions Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260131-can_skb_ext-v7-4-dd0f8f84a83d@hartkopp.net> References: <20260131-can_skb_ext-v7-0-dd0f8f84a83d@hartkopp.net> In-Reply-To: <20260131-can_skb_ext-v7-0-dd0f8f84a83d@hartkopp.net> To: Marc Kleine-Budde , Vincent Mailhol , Oliver Hartkopp , Robin van der Gracht , Oleksij Rempel , kernel@pengutronix.de, "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman Cc: linux-can@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org X-Mailer: b4 0.15-dev-47773 X-Developer-Signature: v=1; a=ed25519-sha256; t=1769865912; l=3158; i=socketcan@hartkopp.net; s=20260128; h=from:subject:message-id; bh=ArF50dGFLTJeKrJinhCvEu9UmJPwPrODNYHzRcVUyg0=; b=1iGtLytz9m3gTW5Xu6mkQ8oZM8PBA4Ni5zGBLjOXtRVJKmZxtzUxZbRXZVCjvTp3tZoKAkIzs D0GQTSDChIeCfbplx0MgEuvmMXJO6ELFuQYuegbDYaU/HQ8+YFVWVkF X-Developer-Key: i=socketcan@hartkopp.net; a=ed25519; pk=/gU/7/wBqak3kTsTeFbCCqUi9dnh+1i6ITEkfPj/BvU= X-Endpoint-Received: by B4 Relay for socketcan@hartkopp.net/20260128 with auth_id=620 X-Original-From: Oliver Hartkopp Reply-To: socketcan@hartkopp.net From: Oliver Hartkopp The can_skb_priv::frame_len variable is used to cache a previous calculated CAN frame length to be passed to BQL queueing disciplines. Move the can_skb_priv::frame_len content to can_skb_ext::can_framelen. Signed-off-by: Marc Kleine-Budde Signed-off-by: Oliver Hartkopp --- drivers/net/can/dev/skb.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c index 470255fe7367..408ee49abce1 100644 --- a/drivers/net/can/dev/skb.c +++ b/drivers/net/can/dev/skb.c @@ -47,10 +47,11 @@ void can_flush_echo_skb(struct net_device *dev) */ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, unsigned int idx, unsigned int frame_len) { struct can_priv *priv =3D netdev_priv(dev); + struct can_skb_ext *csx; =20 if (idx >=3D priv->echo_skb_max) { netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bou= nds (%u/max %u)\n", __func__, idx, priv->echo_skb_max); return -EINVAL; @@ -73,11 +74,13 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_de= vice *dev, /* make settings for echo to reduce code in irq context */ skb->ip_summed =3D CHECKSUM_UNNECESSARY; skb->dev =3D dev; =20 /* save frame_len to reuse it when transmission is completed */ - can_skb_prv(skb)->frame_len =3D frame_len; + csx =3D can_skb_ext_find(skb); + if (csx) + csx->can_framelen =3D frame_len; =20 if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) skb_shinfo(skb)->tx_flags |=3D SKBTX_IN_PROGRESS; =20 skb_tx_timestamp(skb); @@ -110,20 +113,25 @@ __can_get_echo_skb(struct net_device *dev, unsigned i= nt idx, if (priv->echo_skb[idx]) { /* Using "struct canfd_frame::len" for the frame * length is supported on both CAN and CANFD frames. */ struct sk_buff *skb =3D priv->echo_skb[idx]; - struct can_skb_priv *can_skb_priv =3D can_skb_prv(skb); + struct can_skb_ext *csx; =20 if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) skb_tstamp_tx(skb, skb_hwtstamps(skb)); =20 /* get the real payload length for netdev statistics */ *len_ptr =3D can_skb_get_data_len(skb); =20 - if (frame_len_ptr) - *frame_len_ptr =3D can_skb_priv->frame_len; + if (frame_len_ptr) { + csx =3D can_skb_ext_find(skb); + if (csx) + *frame_len_ptr =3D csx->can_framelen; + else + *frame_len_ptr =3D 0; + } =20 priv->echo_skb[idx] =3D NULL; =20 if (skb->pkt_type =3D=3D PACKET_LOOPBACK) { skb->pkt_type =3D PACKET_BROADCAST; @@ -179,14 +187,19 @@ void can_free_echo_skb(struct net_device *dev, unsign= ed int idx, return; } =20 if (priv->echo_skb[idx]) { struct sk_buff *skb =3D priv->echo_skb[idx]; - struct can_skb_priv *can_skb_priv =3D can_skb_prv(skb); - - if (frame_len_ptr) - *frame_len_ptr =3D can_skb_priv->frame_len; + struct can_skb_ext *csx; + + if (frame_len_ptr) { + csx =3D can_skb_ext_find(skb); + if (csx) + *frame_len_ptr =3D csx->can_framelen; + else + *frame_len_ptr =3D 0; + } =20 dev_kfree_skb_any(skb); priv->echo_skb[idx] =3D NULL; } } --=20 2.51.0 From nobody Mon Feb 9 09:23:05 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 38B53352F85; Sat, 31 Jan 2026 13:25:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769865915; cv=none; b=Q7W1ltzY/NN/iam1dBa80fkasxArXaPHwEm8e7CSen5xWkjoAF/lFnhi6ipzwPE0AzFbZsA3GDJB8EGsuRW3LlcwwL00gMGgHXCRt5AhvRE0ptFszlJXNcqvSlHguEJqu0GHOlW4tTGOSMiKXMwfBNzjFjTwFBrgGKGJk/XI3hc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769865915; c=relaxed/simple; bh=Ld8o/SdkGkzz6kr9ajSZzyVd/FyfOAfNxY6og7fma/o=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fHL2kk6A5uWGRIhNSnvGJi+ZL5FLkTiIZNYKwPRl+uwN90LkOqSuk8LWESvQ1FJaHgui2m77IfF+BPyIMEpTH/941dE5V/MFssn4MQCL40BbcFFOx0leakFFBAdtcWKVxRxyuR/OQsqPVT4eJJpcPXoAjr/nvyaT+InWKfqAT7c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=leyH+hvK; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="leyH+hvK" Received: by smtp.kernel.org (Postfix) with ESMTPS id DFE8DC2BCB3; Sat, 31 Jan 2026 13:25:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1769865914; bh=Ld8o/SdkGkzz6kr9ajSZzyVd/FyfOAfNxY6og7fma/o=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=leyH+hvKIniE3Ifv0eBnnWT1VeiUEUfgSEwGb7csI0hyzElgOo787mZxUf4RDMjVT 5A5YzRw0Qyz7wFAk+Zn9JPj2YDBIY4bDXYaYuN0Pj1nD8/lk+x28AuH7lBq4dtSQ38 GsNvijmhOLuuIbYymxsxCkV9j7n+QZSgo46jTvb/dezxitPuHooAHBDjZyFlvTabnd OfvqUsOS1ktBKOdYLNwhnPhdjSZmdXP5v/+vXybuUIzSRUz8BW/JEhdOLPm/lkavZC Vc9dNwsnqqN2UIxi4OIeOWGMYd8/H4nJcTWizFUJeCIvzoJ8t6fOpcAv1ylULjVRyz B92g+igY+EcEw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id D5737D7976B; Sat, 31 Jan 2026 13:25:14 +0000 (UTC) From: Oliver Hartkopp via B4 Relay Date: Sat, 31 Jan 2026 14:25:10 +0100 Subject: [PATCH net-next v7 5/6] can: remove private CAN skb headroom infrastructure Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260131-can_skb_ext-v7-5-dd0f8f84a83d@hartkopp.net> References: <20260131-can_skb_ext-v7-0-dd0f8f84a83d@hartkopp.net> In-Reply-To: <20260131-can_skb_ext-v7-0-dd0f8f84a83d@hartkopp.net> To: Marc Kleine-Budde , Vincent Mailhol , Oliver Hartkopp , Robin van der Gracht , Oleksij Rempel , kernel@pengutronix.de, "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman Cc: linux-can@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org X-Mailer: b4 0.15-dev-47773 X-Developer-Signature: v=1; a=ed25519-sha256; t=1769865912; l=12880; i=socketcan@hartkopp.net; s=20260128; h=from:subject:message-id; bh=xjnmdOvLg1CEoRCY/T6zFChUGn03hpwp6E50Yl02b1Q=; b=slIx63lAIbq4xiyoIJQYBvtHny/snn8lZ/W5gWUuZBH2Xtq10yVpgxKK72SfyFAAXjLGWzp8k Op7tXtUiOxPBa1eFpkwGVff+nRHHhqvCP1JcaW/cikXO0AJO8SdFPbt X-Developer-Key: i=socketcan@hartkopp.net; a=ed25519; pk=/gU/7/wBqak3kTsTeFbCCqUi9dnh+1i6ITEkfPj/BvU= X-Endpoint-Received: by B4 Relay for socketcan@hartkopp.net/20260128 with auth_id=620 X-Original-From: Oliver Hartkopp Reply-To: socketcan@hartkopp.net From: Oliver Hartkopp 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 --- 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(-) 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 @@ -204,40 +204,33 @@ void can_free_echo_skb(struct net_device *dev, unsign= ed int idx, } } EXPORT_SYMBOL_GPL(can_free_echo_skb); =20 /* 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 =3D PACKET_BROADCAST; skb->ip_summed =3D CHECKSUM_UNNECESSARY; - - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - skb_reset_transport_header(skb); - - can_skb_reserve(skb); } =20 struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **c= f) { struct sk_buff *skb; struct can_skb_ext *csx; =20 - skb =3D netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + - sizeof(struct can_frame)); + skb =3D netdev_alloc_skb(dev, sizeof(struct can_frame)); if (unlikely(!skb)) goto out_error_cc; =20 csx =3D can_skb_ext_add(skb); if (!csx) { kfree_skb(skb); goto out_error_cc; } =20 skb->protocol =3D htons(ETH_P_CAN); - init_can_skb_reserve(skb); + init_can_skb(skb); csx->can_iif =3D dev->ifindex; =20 *cf =3D skb_put_zero(skb, sizeof(struct can_frame)); =20 return skb; @@ -253,23 +246,22 @@ struct sk_buff *alloc_canfd_skb(struct net_device *de= v, struct canfd_frame **cfd) { struct sk_buff *skb; struct can_skb_ext *csx; =20 - skb =3D netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + - sizeof(struct canfd_frame)); + skb =3D netdev_alloc_skb(dev, sizeof(struct canfd_frame)); if (unlikely(!skb)) goto out_error_fd; =20 csx =3D can_skb_ext_add(skb); if (!csx) { kfree_skb(skb); goto out_error_fd; } =20 skb->protocol =3D htons(ETH_P_CANFD); - init_can_skb_reserve(skb); + init_can_skb(skb); csx->can_iif =3D dev->ifindex; =20 *cfd =3D skb_put_zero(skb, sizeof(struct canfd_frame)); =20 /* set CAN FD flag by default */ @@ -292,23 +284,22 @@ struct sk_buff *alloc_canxl_skb(struct net_device *de= v, struct can_skb_ext *csx; =20 if (data_len < CANXL_MIN_DLEN || data_len > CANXL_MAX_DLEN) goto out_error_xl; =20 - skb =3D netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + - CANXL_HDR_SIZE + data_len); + skb =3D netdev_alloc_skb(dev, CANXL_HDR_SIZE + data_len); if (unlikely(!skb)) goto out_error_xl; =20 csx =3D can_skb_ext_add(skb); if (!csx) { kfree_skb(skb); goto out_error_xl; } =20 skb->protocol =3D htons(ETH_P_CANXL); - init_can_skb_reserve(skb); + init_can_skb(skb); csx->can_iif =3D dev->ifindex; =20 *cxl =3D skb_put_zero(skb, CANXL_HDR_SIZE + data_len); =20 /* set CAN XL flag and length information by default */ @@ -338,18 +329,14 @@ struct sk_buff *alloc_can_err_skb(struct net_device *= dev, struct can_frame **cf) return skb; } EXPORT_SYMBOL_GPL(alloc_can_err_skb); =20 /* 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 =3D can_skb_ext_find(skb); =20 - /* 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 =3D=3D CHECKSUM_NONE || !csx) { /* init CAN skb content */ if (!csx) { csx =3D can_skb_ext_add(skb); @@ -403,11 +390,11 @@ bool can_dropped_invalid_skb(struct net_device *dev, = struct sk_buff *skb) =20 default: goto inval_skb; } =20 - if (!can_skb_headroom_valid(dev, skb)) + if (!can_skb_init_valid(dev, skb)) goto inval_skb; =20 return false; =20 inval_skb: 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 @@ -36,41 +36,10 @@ struct sk_buff *alloc_canxl_skb(struct net_device *dev, unsigned int data_len); 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); =20 -/* - * The struct can_skb_priv is used to transport additional information alo= ng - * with the stored struct can(fd)_frame that can not be contained in exist= ing - * 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 =3D skb_ext_add(skb, SKB_EXT_CAN); =20 /* skb_ext_add() returns uninitialized space */ 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 @@ -310,21 +310,20 @@ static void bcm_can_tx(struct bcm_op *op) if (!dev) { /* RFC: should this bcm_op remove itself here? */ return; } =20 - skb =3D alloc_skb(op->cfsiz + sizeof(struct can_skb_priv), gfp_any()); + skb =3D alloc_skb(op->cfsiz, gfp_any()); if (!skb) goto out; =20 csx =3D can_skb_ext_add(skb); if (!csx) { kfree_skb(skb); goto out; } =20 - can_skb_reserve(skb); csx->can_iif =3D dev->ifindex; =20 skb_put_data(skb, cf, op->cfsiz); =20 /* send with loopback */ @@ -1331,22 +1330,20 @@ static int bcm_tx_send(struct msghdr *msg, int ifin= dex, struct sock *sk, =20 /* we need a real device to send frames */ if (!ifindex) return -ENODEV; =20 - skb =3D alloc_skb(cfsiz + sizeof(struct can_skb_priv), GFP_KERNEL); + skb =3D alloc_skb(cfsiz, GFP_KERNEL); if (!skb) return -ENOMEM; =20 csx =3D can_skb_ext_add(skb); if (!csx) { kfree_skb(skb); return -ENOMEM; } =20 - can_skb_reserve(skb); - err =3D memcpy_from_msg(skb_put(skb, cfsiz), msg, cfsiz); if (err < 0) { kfree_skb(skb); return err; } diff --git a/net/can/isotp.c b/net/can/isotp.c index 4a6ce6836b24..736078357b5c 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -218,11 +218,11 @@ static int isotp_send_fc(struct sock *sk, int ae, u8 = flowstatus) struct can_skb_ext *csx; struct canfd_frame *ncf; struct isotp_sock *so =3D isotp_sk(sk); int can_send_ret; =20 - nskb =3D alloc_skb(so->ll.mtu + sizeof(struct can_skb_priv), gfp_any()); + nskb =3D alloc_skb(so->ll.mtu, gfp_any()); if (!nskb) return 1; =20 csx =3D can_skb_ext_add(nskb); if (!csx) { @@ -234,13 +234,11 @@ static int isotp_send_fc(struct sock *sk, int ae, u8 = flowstatus) if (!dev) { kfree_skb(nskb); return 1; } =20 - can_skb_reserve(nskb); csx->can_iif =3D dev->ifindex; - nskb->dev =3D dev; can_skb_set_owner(nskb, sk); ncf =3D (struct canfd_frame *)nskb->data; skb_put_zero(nskb, so->ll.mtu); =20 @@ -778,11 +776,11 @@ static void isotp_send_cframe(struct isotp_sock *so) =20 dev =3D dev_get_by_index(sock_net(sk), so->ifindex); if (!dev) return; =20 - skb =3D alloc_skb(so->ll.mtu + sizeof(struct can_skb_priv), GFP_ATOMIC); + skb =3D alloc_skb(so->ll.mtu, GFP_ATOMIC); if (!skb) { dev_put(dev); return; } =20 @@ -791,11 +789,10 @@ static void isotp_send_cframe(struct isotp_sock *so) kfree_skb(skb); netdev_put(dev, NULL); return; } =20 - can_skb_reserve(skb); csx->can_iif =3D dev->ifindex; =20 cf =3D (struct canfd_frame *)skb->data; skb_put_zero(skb, so->ll.mtu); =20 @@ -1013,12 +1010,12 @@ static int isotp_sendmsg(struct socket *sock, struc= t msghdr *msg, size_t size) if (!dev) { err =3D -ENXIO; goto err_out_drop; } =20 - skb =3D sock_alloc_send_skb(sk, so->ll.mtu + sizeof(struct can_skb_priv), - msg->msg_flags & MSG_DONTWAIT, &err); + skb =3D sock_alloc_send_skb(sk, so->ll.mtu, msg->msg_flags & MSG_DONTWAIT, + &err); if (!skb) { dev_put(dev); goto err_out_drop; } =20 @@ -1027,11 +1024,10 @@ static int isotp_sendmsg(struct socket *sock, struc= t msghdr *msg, size_t size) kfree_skb(skb); netdev_put(dev, NULL); goto err_out_drop; } =20 - can_skb_reserve(skb); csx->can_iif =3D dev->ifindex; =20 so->tx.len =3D size; so->tx.idx =3D 0; =20 diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c index f03bae79354e..10014d95c319 100644 --- a/net/can/j1939/socket.c +++ b/net/can/j1939/socket.c @@ -889,23 +889,21 @@ static struct sk_buff *j1939_sk_alloc_skb(struct net_= device *ndev, int ret; =20 skb =3D 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; =20 csx =3D can_skb_ext_add(skb); if (!csx) { kfree_skb(skb); goto failure; } =20 - can_skb_reserve(skb); csx->can_iif =3D ndev->ifindex; skb_reserve(skb, offsetof(struct can_frame, data)); =20 ret =3D memcpy_from_msg(skb_put(skb, size), msg, size); if (ret < 0) diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c index 88f99a6f5c8e..271922ff3a23 100644 --- a/net/can/j1939/transport.c +++ b/net/can/j1939/transport.c @@ -593,23 +593,21 @@ sk_buff *j1939_tp_tx_dat_new(struct j1939_priv *priv, { struct sk_buff *skb; struct can_skb_ext *csx; struct j1939_sk_buff_cb *skcb; =20 - skb =3D alloc_skb(sizeof(struct can_frame) + sizeof(struct can_skb_priv), - GFP_ATOMIC); + skb =3D alloc_skb(sizeof(struct can_frame), GFP_ATOMIC); if (unlikely(!skb)) return ERR_PTR(-ENOMEM); =20 csx =3D can_skb_ext_add(skb); if (!csx) { kfree_skb(skb); return ERR_PTR(-ENOMEM); } =20 skb->dev =3D priv->ndev; - can_skb_reserve(skb); csx->can_iif =3D priv->ndev->ifindex; /* reserve CAN header */ skb_reserve(skb, offsetof(struct can_frame, data)); =20 /* skb->cb must be large enough to hold a j1939_sk_buff_cb structure */ @@ -1546,22 +1544,21 @@ j1939_session *j1939_session_fresh_new(struct j1939= _priv *priv, struct sk_buff *skb; struct can_skb_ext *csx; struct j1939_sk_buff_cb *skcb; struct j1939_session *session; =20 - skb =3D alloc_skb(size + sizeof(struct can_skb_priv), GFP_ATOMIC); + skb =3D alloc_skb(size, GFP_ATOMIC); if (unlikely(!skb)) return NULL; =20 csx =3D can_skb_ext_add(skb); if (!csx) { kfree_skb(skb); return NULL; } =20 skb->dev =3D priv->ndev; - can_skb_reserve(skb); csx->can_iif =3D priv->ndev->ifindex; skcb =3D j1939_skb_to_cb(skb); memcpy(skcb, rel_skcb, sizeof(*skcb)); =20 session =3D j1939_session_new(priv, skb, size); diff --git a/net/can/raw.c b/net/can/raw.c index 7c89962ec913..d33ce436018f 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -951,22 +951,21 @@ static int raw_sendmsg(struct socket *sock, struct ms= ghdr *msg, size_t size) if (can_cap_enabled(dev, CAN_CAP_RO)) { err =3D -EACCES; goto put_dev; } =20 - skb =3D sock_alloc_send_skb(sk, size + sizeof(struct can_skb_priv), - msg->msg_flags & MSG_DONTWAIT, &err); + skb =3D sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, + &err); if (!skb) goto put_dev; =20 csx =3D can_skb_ext_add(skb); if (!csx) { kfree_skb(skb); goto put_dev; } =20 - can_skb_reserve(skb); csx->can_iif =3D dev->ifindex; =20 /* fill the skb before testing for valid CAN frames */ err =3D memcpy_from_msg(skb_put(skb, size), msg, size); if (err < 0) --=20 2.51.0 From nobody Mon Feb 9 09:23:05 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1C475352C2E; Sat, 31 Jan 2026 13:25:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769865915; cv=none; b=f5NIhicSZNjVM0kfHtmJDSt5ESKWuYL/89wPLt/wZipdPJD07TQuXfWpl42IefFD4WJtmhrWliHOBRUE9uHpQXRwK0cF2yplErGl2Sz3UaC1Yj/OI3EArZqECxwVOgI0mHBzRelAmZMKYD2qX6toCPTDFaV19IJStntGxULaUQ8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769865915; c=relaxed/simple; bh=zf3WXPVkSFDzLsDWT4dV9ZRA9kjiomjTQb6KZWd1ANQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=lsbz63kKH53JOOu7K2rXLg6gloDYEWgWs43AcH0PxQ5z6LcX4w9X7tguvIaGqvlKEi3uEPEwy6ytRjXNQgmDHmd4w5mAy9V+XQJItaWCx2gUCQfy+Qxof/t6Z65jMZb1ITIt9/R0KCURaxEM6omrgjJUHhNU0nc5RUbVHOTUI2Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=uo7mAC7r; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="uo7mAC7r" Received: by smtp.kernel.org (Postfix) with ESMTPS id EBF41C2BCB7; Sat, 31 Jan 2026 13:25:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1769865915; bh=zf3WXPVkSFDzLsDWT4dV9ZRA9kjiomjTQb6KZWd1ANQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=uo7mAC7rKB9ndz3MUF197/lQHeInV1b0l1JIzFjQavkHqtTd8sjYSn1qAJvnmCnVQ l9OQWVmTplvRPDnA/UavpWUbmnC/tJcfhf+GO7QgEZRlI+IkK/sMeXWpblH8mTeMz4 Idg4y1N8lb1oFncgYdwvGLklqSPstUGOdaFt2Lsh0Uo2EFBLn2yDpeVWSU4W39UnQe Wau+ALYHom5zXqfxyKQEUzmq7skYxEWtmW2EUssNSrHyZ5bFtZ7l218TmGhTReYbsv KxKN8ParUc4XRcdDx848Xt7PwGH1RDgemvA3gM5OUEkkMI9JecOoikB1HsXTyZwOYx nq9fREd8NXTiw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id E45D8D79771; Sat, 31 Jan 2026 13:25:14 +0000 (UTC) From: Oliver Hartkopp via B4 Relay Date: Sat, 31 Jan 2026 14:25:11 +0100 Subject: [PATCH net-next v7 6/6] can: gw: use can_gw_hops instead of sk_buff::csum_start Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260131-can_skb_ext-v7-6-dd0f8f84a83d@hartkopp.net> References: <20260131-can_skb_ext-v7-0-dd0f8f84a83d@hartkopp.net> In-Reply-To: <20260131-can_skb_ext-v7-0-dd0f8f84a83d@hartkopp.net> To: Marc Kleine-Budde , Vincent Mailhol , Oliver Hartkopp , Robin van der Gracht , Oleksij Rempel , kernel@pengutronix.de, "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman Cc: linux-can@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org X-Mailer: b4 0.15-dev-47773 X-Developer-Signature: v=1; a=ed25519-sha256; t=1769865912; l=3632; i=socketcan@hartkopp.net; s=20260128; h=from:subject:message-id; bh=ov/1Nd5fmtdN4DViiwCnK/2y+He9qcgNw2oZkmdY3H8=; b=qCf8F5KQ+Ulb1P9YvkvH+SJ+7YVcT+z3gd+i0t9ZNQP2anpAKs7qNUyG1aQPujgkg0+ViP6cd NssymmS2ga0Bq43rJeoVo6OtG11jJsf5N23iqvTsD8yZt+lc9LHJCXS X-Developer-Key: i=socketcan@hartkopp.net; a=ed25519; pk=/gU/7/wBqak3kTsTeFbCCqUi9dnh+1i6ITEkfPj/BvU= X-Endpoint-Received: by B4 Relay for socketcan@hartkopp.net/20260128 with auth_id=620 X-Original-From: Oliver Hartkopp Reply-To: socketcan@hartkopp.net From: Oliver Hartkopp As CAN skbs don't use IP checksums the skb->csum_start variable was used to store the can-gw CAN frame time-to-live counter together with skb->ip_summed set to CHECKSUM_UNNECESSARY. Remove the 'hack' using the skb->csum_start variable and move the content to can_skb_ext::can_gw_hops of the CAN skb extensions. The module parameter 'max_hops' has been reduced to a single byte to fit can_skb_ext::can_gw_hops as the maximum value to be stored is 6. Signed-off-by: Marc Kleine-Budde Signed-off-by: Oliver Hartkopp --- drivers/net/can/vxcan.c | 2 +- net/can/gw.c | 23 ++++++----------------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index 53d7d9046f85..60e5dad0694d 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -76,11 +76,11 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, str= uct net_device *dev) kfree_skb(oskb); goto out_unlock; } =20 /* reset CAN GW hop counter */ - skb->csum_start =3D 0; + csx->can_gw_hops =3D 0; skb->pkt_type =3D PACKET_BROADCAST; skb->dev =3D peer; skb->ip_summed =3D CHECKSUM_UNNECESSARY; =20 len =3D can_skb_get_data_len(skb); diff --git a/net/can/gw.c b/net/can/gw.c index 816154a978c1..61a1e6b1b83f 100644 --- a/net/can/gw.c +++ b/net/can/gw.c @@ -69,12 +69,12 @@ MODULE_ALIAS(CAN_GW_NAME); =20 #define CGW_MIN_HOPS 1 #define CGW_MAX_HOPS 6 #define CGW_DEFAULT_HOPS 1 =20 -static unsigned int max_hops __read_mostly =3D CGW_DEFAULT_HOPS; -module_param(max_hops, uint, 0444); +static unsigned char max_hops __read_mostly =3D CGW_DEFAULT_HOPS; +module_param(max_hops, byte, 0444); MODULE_PARM_DESC(max_hops, "maximum " CAN_GW_NAME " routing hops for CAN frames " "(valid values: " __stringify(CGW_MIN_HOPS) "-" __stringify(CGW_MAX_HOPS) " hops, " "default: " __stringify(CGW_DEFAULT_HOPS) ")"); @@ -478,23 +478,12 @@ static void can_can_gw_rcv(struct sk_buff *skb, void = *data) return; =20 /* 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). - * - * The Controller Area Network controllers only accept CAN frames with - * correct CRCs - which are not visible in the controller registers. - * According to skbuff.h documentation the csum_start element for IP - * checksums is undefined/unused when ip_summed =3D=3D CHECKSUM_UNNECESSA= RY. - * Only CAN skbs can be processed here which already have this property. */ - -#define cgw_hops(skb) ((skb)->csum_start) - - BUG_ON(skb->ip_summed !=3D CHECKSUM_UNNECESSARY); - - if (cgw_hops(skb) >=3D max_hops) { + if (csx->can_gw_hops >=3D max_hops) { /* indicate deleted frames due to misconfiguration */ gwj->deleted_frames++; return; } =20 @@ -534,15 +523,15 @@ static void can_can_gw_rcv(struct sk_buff *skb, void = *data) gwj->dropped_frames++; return; } =20 /* put the incremented hop counter in the cloned skb */ - cgw_hops(nskb) =3D cgw_hops(skb) + 1; + ncsx->can_gw_hops =3D csx->can_gw_hops + 1; =20 /* first processing of this CAN frame -> adjust to private hop limit */ - if (gwj->limit_hops && cgw_hops(nskb) =3D=3D 1) - cgw_hops(nskb) =3D max_hops - gwj->limit_hops + 1; + if (gwj->limit_hops && ncsx->can_gw_hops =3D=3D 1) + ncsx->can_gw_hops =3D max_hops - gwj->limit_hops + 1; =20 nskb->dev =3D gwj->dst.dev; =20 /* pointer to modifiable CAN frame */ cf =3D (struct canfd_frame *)nskb->data; --=20 2.51.0