From: Jeremy Kerr <jk@codeconstruct.com.au>
To: Matt Johnston <matt@codeconstruct.com.au>,
Andrew Lunn <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>,
Paolo Abeni <pabeni@redhat.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: netdev@vger.kernel.org, linux-usb@vger.kernel.org
Subject: [PATCH net-next 08/12] net: mctp: usblib: Implement receive-side packet spanning
Date: Tue, 30 Jun 2026 11:21:29 +0800 [thread overview]
Message-ID: <20260630-dev-mctp-usb-1-1-v1-8-86a311fc67b7@codeconstruct.com.au> (raw)
In-Reply-To: <20260630-dev-mctp-usb-1-1-v1-0-86a311fc67b7@codeconstruct.com.au>
Using the existing prepare/complete API, we can persist the rx skb
across receives to implement v1.1 packet spanning.
Alter the packet-extraction loop to allow truncated packets, returning
early with the skb persisted for the next IN urb completion. When we see
we have a complete packet, netif_rx() that. If the packet boundary
aligns with the urb completion, we can netif_rx() the whole thing.
We still need to handle non-spanning mode, so error out on
truncated-packet cases there.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
---
drivers/net/mctp/mctp-usb.c | 2 +-
drivers/net/mctp/mctp-usblib.c | 135 ++++++++++++++++++++++++++---------------
include/linux/usb/mctp-usb.h | 5 +-
3 files changed, 91 insertions(+), 51 deletions(-)
diff --git a/drivers/net/mctp/mctp-usb.c b/drivers/net/mctp/mctp-usb.c
index b31599dfaa7e..c89588741855 100644
--- a/drivers/net/mctp/mctp-usb.c
+++ b/drivers/net/mctp/mctp-usb.c
@@ -275,7 +275,7 @@ static int mctp_usb_probe(struct usb_interface *intf,
spin_lock_init(&dev->tx_lock);
usb_set_intfdata(intf, dev);
- mctp_usblib_rx_init(&dev->rx);
+ mctp_usblib_rx_init(&dev->rx, false);
mctp_usblib_tx_init(&dev->tx, &tx_ops, dev);
init_usb_anchor(&dev->tx_anchor);
diff --git a/drivers/net/mctp/mctp-usblib.c b/drivers/net/mctp/mctp-usblib.c
index acfae6d32390..a1649f24d937 100644
--- a/drivers/net/mctp/mctp-usblib.c
+++ b/drivers/net/mctp/mctp-usblib.c
@@ -3,7 +3,7 @@
* mctp-usblib.c - MCTP-over-USB (DMTF DSP0283) transport helper library
*
* DSP0283 is available at:
- * https://www.dmtf.org/sites/default/files/standards/documents/DSP0283_1.0.1.pdf
+ * https://www.dmtf.org/sites/default/files/standards/documents/DSP0283_1.1.0.pdf
*
* Copyright (C) 2024-2026 Code Construct Pty Ltd
*/
@@ -13,9 +13,10 @@
#include <linux/usb/mctp-usb.h>
#include <net/mctp.h>
-void mctp_usblib_rx_init(struct mctp_usblib_rx *rx)
+void mctp_usblib_rx_init(struct mctp_usblib_rx *rx, bool span)
{
memset(rx, 0, sizeof(*rx));
+ rx->span = span;
}
EXPORT_SYMBOL_GPL(mctp_usblib_rx_init);
@@ -33,12 +34,30 @@ int mctp_usblib_rx_prepare(struct net_device *netdev,
struct mctp_usblib_rx *rx,
void **bufp, size_t *lenp, gfp_t gfp)
{
- const unsigned int len = MCTP_USB_1_0_XFER_SIZE;
- struct sk_buff *skb;
+ struct sk_buff *skb = rx->skb;
+ unsigned int len = 0;
- skb = __netdev_alloc_skb(netdev, len, gfp);
- if (!skb)
- return -ENOMEM;
+ if (skb && skb->len >= MCTP_USB_1_1_PKTLEN_MAX) {
+ /* something must have gone terribly wrong. clear and restart */
+ mctp_usblib_rx_cancel(rx);
+ skb = NULL;
+ }
+
+ len = rx->span ? MCTP_USB_1_1_PKTLEN_MAX : MCTP_USB_1_0_XFER_SIZE;
+
+ if (skb) {
+ struct sk_buff *skb2;
+
+ skb2 = skb_copy_expand(skb, 0, len, gfp);
+ if (!skb2)
+ return -ENOMEM;
+ dev_kfree_skb_any(skb);
+ skb = skb2;
+ } else {
+ skb = __netdev_alloc_skb(netdev, len, gfp);
+ if (!skb)
+ return -ENOMEM;
+ }
rx->skb = skb;
@@ -60,10 +79,11 @@ static void mctp_usblib_rx(struct net_device *netdev, struct sk_buff *skb)
*/
flags = u64_stats_update_begin_irqsave(&dstats->syncp);
u64_stats_inc(&dstats->rx_packets);
- u64_stats_add(&dstats->rx_bytes, skb->len + sizeof(struct mctp_usb_hdr));
+ u64_stats_add(&dstats->rx_bytes, skb->len);
u64_stats_update_end_irqrestore(&dstats->syncp, flags);
skb_reset_mac_header(skb);
+ skb_pull(skb, sizeof(struct mctp_usb_hdr));
skb->protocol = htons(ETH_P_MCTP);
skb_reset_network_header(skb);
cb = __mctp_cb(skb);
@@ -86,70 +106,87 @@ int mctp_usblib_rx_complete(struct net_device *netdev,
__skb_put(skb, len);
- while (skb) {
- struct sk_buff *skb2 = NULL;
+ for (;;) {
struct mctp_usb_hdr *hdr;
- u16 hdr_len;
- /* length of MCTP packet, no USB header */
- u8 pkt_len;
-
- skb_reset_mac_header(skb);
- hdr = skb_pull_data(skb, sizeof(*hdr));
- if (!hdr) {
- rc = -ENOMSG;
+ struct sk_buff *skb2;
+ /* length of MCTP packet, including USB header */
+ u16 pkt_len;
+
+ /* no header yet, resubmit for the rest of the packet */
+ if (skb->len < sizeof(*hdr)) {
+ if (!rx->span) {
+ netdev_dbg(netdev,
+ "rx: tiny xfer (%d) in non-span mode",
+ skb->len);
+ rc = -ENOMSG;
+ goto err_reset;
+ }
break;
}
+ hdr = (struct mctp_usb_hdr *)skb->data;
+
if (be16_to_cpu(hdr->id) != MCTP_USB_DMTF_ID) {
+ /* By resetting here, will start the next IN transfer
+ * at the beginning of the new skb. This will mean
+ * we re-sync when we next see a spanned packet aligned
+ * with the start of a transfer.
+ *
+ * In non-spanning mode, this just means we'll drop
+ * the current transfer only
+ */
netdev_dbg(netdev, "rx: invalid id %04x\n",
be16_to_cpu(hdr->id));
rc = -EPROTO;
- break;
+ goto err_reset;
}
- hdr_len = be16_to_cpu(hdr->len) & MCTP_USB_1_0_PKTLEN_MAX;
-
- if (hdr_len <
- sizeof(struct mctp_hdr) + sizeof(struct mctp_usb_hdr)) {
- netdev_dbg(netdev, "rx: short packet (hdr) %d\n",
- hdr->len);
+ pkt_len = be16_to_cpu(hdr->len);
+ /* v1.1, with span enabled, has a 13-bit length */
+ pkt_len &= rx->span ?
+ MCTP_USB_1_1_PKTLEN_MAX : MCTP_USB_1_0_PKTLEN_MAX;
+ if (pkt_len < sizeof(*hdr)) {
+ netdev_dbg(netdev, "rx: invalid len %d\n", pkt_len);
rc = -EPROTO;
- break;
+ goto err_reset;
}
- /* we know we have at least sizeof(struct mctp_usb_hdr) here */
- pkt_len = hdr_len - sizeof(struct mctp_usb_hdr);
+ /* span continues to the next transfer, resubmit */
if (pkt_len > skb->len) {
- rc = -EPROTO;
- netdev_dbg(netdev,
- "rx: short packet (xfer) %d, actual %d\n",
- hdr_len, skb->len);
+ if (!rx->span) {
+ netdev_dbg(netdev,
+ "rx: short xfer (%d vs %d) in non-span mode",
+ pkt_len, skb->len);
+ rc = -ENOMSG;
+ goto err_reset;
+ }
break;
}
- if (pkt_len < skb->len) {
- /* more packets may follow - clone to a new
- * skb to use on the next iteration
- */
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2) {
- if (!skb_pull(skb2, pkt_len)) {
- dev_kfree_skb_any(skb2);
- skb2 = NULL;
- }
- }
- skb_trim(skb, pkt_len);
+ /* we have (exactly) a complete packet, RX it directly */
+ if (pkt_len == skb->len) {
+ mctp_usblib_rx(netdev, skb);
+ rx->skb = NULL;
+ break;
}
- mctp_usblib_rx(netdev, skb);
- skb = skb2;
+ /* more packets follow - RX a clone so that we can continue
+ * processing the current SKB, which may be the start of a
+ * span.
+ */
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2) {
+ skb_trim(skb2, pkt_len);
+ mctp_usblib_rx(netdev, skb2);
+ }
+ skb_pull(skb, pkt_len);
}
- if (skb)
- dev_kfree_skb_any(skb);
+ return 0;
+err_reset:
+ dev_kfree_skb_any(rx->skb);
rx->skb = NULL;
-
return rc;
}
EXPORT_SYMBOL_GPL(mctp_usblib_rx_complete);
diff --git a/include/linux/usb/mctp-usb.h b/include/linux/usb/mctp-usb.h
index 47561f2471e5..00c538a8e211 100644
--- a/include/linux/usb/mctp-usb.h
+++ b/include/linux/usb/mctp-usb.h
@@ -34,6 +34,8 @@ struct mctp_usb_hdr {
#define MCTP_USB_MTU_MIN MCTP_USB_BTU
#define MCTP_USB_1_0_PKTLEN_MAX U8_MAX
#define MCTP_USB_1_0_MTU_MAX (MCTP_USB_1_0_PKTLEN_MAX - sizeof(struct mctp_usb_hdr))
+#define MCTP_USB_1_1_PKTLEN_MAX GENMASK(12, 0)
+#define MCTP_USB_1_1_MTU_MAX (MCTP_USB_1_1_PKTLEN_MAX - sizeof(struct mctp_usb_hdr))
#define MCTP_USB_DMTF_ID 0x1ab4
/* mctp-usblib */
@@ -46,9 +48,10 @@ struct mctp_usb_hdr {
*/
struct mctp_usblib_rx {
struct sk_buff *skb;
+ bool span;
};
-void mctp_usblib_rx_init(struct mctp_usblib_rx *rx);
+void mctp_usblib_rx_init(struct mctp_usblib_rx *rx, bool span);
void mctp_usblib_rx_fini(struct mctp_usblib_rx *rx);
int mctp_usblib_rx_prepare(struct net_device *netdev,
--
2.47.3
next prev parent reply other threads:[~2026-06-30 3:22 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-30 3:21 [PATCH net-next 00/12] net: mctp: usb: Add support for MCTP-over-USB v1.1 Jeremy Kerr
2026-06-30 3:21 ` [PATCH net-next 01/12] net: mctp: usb: Include version indicator in max packet size defines Jeremy Kerr
2026-06-30 3:21 ` [PATCH net-next 02/12] net: mctp: usb: Use packet-length max for maximum packet-size check Jeremy Kerr
2026-06-30 3:21 ` [PATCH net-next 03/12] net: mctp: usblib: Move RX transfer processing to a new mctp-usblib Jeremy Kerr
2026-07-02 10:09 ` Paolo Abeni
2026-06-30 3:21 ` [PATCH net-next 04/12] net: mctp: usblib: Move TX transfer processing to mctp-usblib Jeremy Kerr
2026-07-02 10:10 ` Paolo Abeni
2026-06-30 3:21 ` [PATCH net-next 05/12] net: mctp: usb: Allow for multiple urb submissions from a packet tx Jeremy Kerr
2026-06-30 3:21 ` [PATCH net-next 06/12] net: mctp: usblib: Add support for multi-packet transmit Jeremy Kerr
2026-06-30 3:21 ` [PATCH net-next 07/12] net: mctp: usb: Accommodate DSP0283 v1.1 header format Jeremy Kerr
2026-06-30 3:21 ` Jeremy Kerr [this message]
2026-06-30 3:21 ` [PATCH net-next 09/12] net: mctp: usblib: Implement transmit-side packet spanning Jeremy Kerr
2026-06-30 3:21 ` [PATCH net-next 10/12] net: mctp: usblib: Add initial kunit tests Jeremy Kerr
2026-07-02 10:10 ` Paolo Abeni
2026-06-30 3:21 ` [PATCH net-next 11/12] net: mctp: usb: enable v1.1 packet spanning Jeremy Kerr
2026-06-30 3:21 ` [PATCH net-next 12/12] net: mctp: usb: Allow multiple urbs in flight Jeremy Kerr
2026-07-02 10:09 ` Paolo Abeni
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260630-dev-mctp-usb-1-1-v1-8-86a311fc67b7@codeconstruct.com.au \
--to=jk@codeconstruct.com.au \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=gregkh@linuxfoundation.org \
--cc=kuba@kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=matt@codeconstruct.com.au \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox