NetBSD Problem Report #59943
From www@netbsd.org Mon Jan 26 02:56:50 2026
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
client-signature RSA-PSS (2048 bits) client-digest SHA256)
(Client CN "mail.netbsd.org", Issuer "R13" (verified OK))
by mollari.NetBSD.org (Postfix) with ESMTPS id 1A00B1A923D
for <gnats-bugs@gnats.NetBSD.org>; Mon, 26 Jan 2026 02:56:50 +0000 (UTC)
Message-Id: <20260126025648.EC1CC1A923E@mollari.NetBSD.org>
Date: Mon, 26 Jan 2026 02:56:48 +0000 (UTC)
From: campbell+netbsd@mumble.net
Reply-To: campbell+netbsd@mumble.net
To: gnats-bugs@NetBSD.org
Subject: usbnet(9) keeps failed packet in queue to retry indefinitely
X-Send-Pr-Version: www-1.0
X-From4GNATS: "campbell+netbsd@mumble.net via gnats" <gnats-admin@NetBSD.org>
>Number: 59943
>Category: kern
>Synopsis: usbnet(9) keeps failed packet in queue to retry indefinitely
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Jan 26 03:00:00 +0000 2026
>Last-Modified: Sun Feb 01 03:35:04 +0000 2026
>Originator: Taylor R Campbell
>Release: current, 11, 10, 9, ...
>Organization:
ugroundhogday(4)
>Environment:
>Description:
In usbnet_start_locked, whose job is to kick off USB transfers
when there are packets queued for tx on the interface, if
either:
(a) the driver rejects the packet, or
(b) the usbnet chain has no transfer allocated, or
(c) usbd_transfer fails,
the packet is left in the interface's tx queue and we break out
of the loop.
523 while (cd->uncd_tx_cnt < un->un_tx_list_cnt) {
524 IFQ_POLL(&ifp->if_snd, m);
...
533 length = uno_tx_prepare(un, m, c);
534 if (length == 0) {
535 DPRINTF("uno_tx_prepare gave zero length", 0, 0, 0, 0);
536 if_statinc(ifp, if_oerrors);
537 break;
538 }
...
540 if (__predict_false(c->unc_xfer == NULL)) {
541 DPRINTF("unc_xfer is NULL", 0, 0, 0, 0);
542 if_statinc(ifp, if_oerrors);
543 break;
544 }
...
550 usbd_status err = usbd_transfer(c->unc_xfer);
551 if (err != USBD_IN_PROGRESS) {
552 DPRINTF("usbd_transfer on %#jx for %ju bytes: %jd",
553 (uintptr_t)c->unc_buf, length, err, 0);
554 if_statinc(ifp, if_oerrors);
555 break;
556 }
https://nxr.netbsd.org/xref/src/sys/dev/usb/usbnet.c?r=1.121#523
These all strike me as wrong or bonkers.
(a) If the driver rejects the packet, which in all the drivers
I reviewed happens only when the packet does not physically
fit in the buffer, surely it makes no sense to retry the
packet again because it will almost certainly fail again in
the same way.
(b) The usbnet chain _cannot_ fail to have a transfer allocated
because usbnet_start_locked is gated on the success of
usbnet_init_tx_rx, which fails if it can't allocate a
transfer for every usbnet chain.
(c) If the hardware fails to actually transfer the packet,
surely we should drop it rather than keep retrying, no?
That's what we do on usbnet_txeof if the transfer has
failed, for example. The only case in which we should
retry, I think, is temporary memory shortage.
I have seen some USB ethernet interfaces get stuck unable to
transmit packets until I bring them down and back up again.
Haven't investigated in a while but this might explain some of
that.
>How-To-Repeat:
cod inspection
>Fix:
Patch in progress!
>Audit-Trail:
From: Taylor R Campbell <riastradh@NetBSD.org>
To: netbsd-bugs@NetBSD.org, gnats-bugs@NetBSD.org
Cc: mrg@NetBSD.org, skrll@NetBSD.org, jakllsch@NetBSD.org
Subject: Re: kern/59943: usbnet(9) keeps failed packet in queue to retry indefinitely
Date: Mon, 26 Jan 2026 03:53:26 +0000
This is a multi-part message in MIME format.
--=_La7nkjIJilZyzQ04m7iYdJZjSuvrF8DG
The attached (untested) patch tries to address these issues (and some
of those in PR kern/59940: usbnet(9): uno_tx_prepare buffer overrun
audit); details in commit message. Thoughts?
--=_La7nkjIJilZyzQ04m7iYdJZjSuvrF8DG
Content-Type: text/plain; charset="ISO-8859-1"; name="pr59940-pr59943-usbnettxfixes"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="pr59940-pr59943-usbnettxfixes.patch"
# HG changeset patch
# User Taylor R Campbell <riastradh@NetBSD.org>
# Date 1769392552 0
# Mon Jan 26 01:55:52 2026 +0000
# Branch trunk
# Node ID f2a961ab939686586e96a4a42110282d83dcad30
# Parent ce5666ee3bee99fc43a60b487110d6418fb6dd5c
# EXP-Topic riastradh-pr59940-usbnettxlenaudit
usbnet(9): Tighten tx path.
1. Verify, don't just assert, that the packet length is below the
buffer size. Even if all the callers enforce the interface's MTU,
I can't prove that the usbnet(9) tx buffer size is an upper bound
enforced on the interface's MTU.
We can remove the check later if we do enforce that upper bound at
some point, which would probably be worth doing anyway since the
MTU is checked earlier in the tx path.
2. Assert, don't check, that c->unc_xfer is nonnull. We can only
reach the tx path if we cross if_init=3Dusbnet_init_rx_tx, and that
(via usbnet_tx_list_init) is guaranteed to fail and back out
unless all of the usbnet_chain unc_xfers get initialized.
3. If we can't fit the packet into a buffer, drop it -- don't leave
it in the queue to try again when it still won't fit in the
buffer.
4. If the transfer for this packet fails, drop it -- don't leave it
in the queue to try again just in case it might work better the
next time.
PR kern/59940: usbnet(9): uno_tx_prepare buffer overrun audit
PR kern/59943: usbnet(9) keeps failed packet in queue to retry indefinitely
diff -r ce5666ee3bee -r f2a961ab9396 sys/dev/usb/usbnet.c
--- a/sys/dev/usb/usbnet.c Sat Jan 24 23:11:52 2026 +0000
+++ b/sys/dev/usb/usbnet.c Mon Jan 26 01:55:52 2026 +0000
@@ -521,26 +521,29 @@ usbnet_start_locked(struct ifnet *ifp)
idx =3D cd->uncd_tx_prod;
count =3D 0;
while (cd->uncd_tx_cnt < un->un_tx_list_cnt) {
- IFQ_POLL(&ifp->if_snd, m);
+ IFQ_DEQUEUE(&ifp->if_snd, m);
if (m =3D=3D NULL) {
DPRINTF("start called, queue empty", 0, 0, 0, 0);
break;
}
+ if (m->m_pkthdr.len > un->un_tx_bufsz) {
+ DPRINTF("oversize packet, %ju > %ju",
+ m->m_pkthdr.len, un->un_tx_bufsz, 0, 0);
+ if_statinc(ifp, if_oerrors);
+ m_freem(m);
+ continue;
+ }
KASSERT(m->m_pkthdr.len <=3D un->un_tx_bufsz);
=20
struct usbnet_chain *c =3D &cd->uncd_tx_chain[idx];
+ KASSERT(c->unc_xfer !=3D NULL);
=20
length =3D uno_tx_prepare(un, m, c);
if (length =3D=3D 0) {
DPRINTF("uno_tx_prepare gave zero length", 0, 0, 0, 0);
if_statinc(ifp, if_oerrors);
- break;
- }
-
- if (__predict_false(c->unc_xfer =3D=3D NULL)) {
- DPRINTF("unc_xfer is NULL", 0, 0, 0, 0);
- if_statinc(ifp, if_oerrors);
- break;
+ m_freem(m);
+ continue;
}
=20
usbd_setup_xfer(c->unc_xfer, c, c->unc_buf, length,
@@ -552,12 +555,11 @@ usbnet_start_locked(struct ifnet *ifp)
DPRINTF("usbd_transfer on %#jx for %ju bytes: %jd",
(uintptr_t)c->unc_buf, length, err, 0);
if_statinc(ifp, if_oerrors);
- break;
+ m_freem(m);
+ continue;
}
done_transmit =3D true;
=20
- IFQ_DEQUEUE(&ifp->if_snd, m);
-
/*
* If there's a BPF listener, bounce a copy of this frame
* to him.
--=_La7nkjIJilZyzQ04m7iYdJZjSuvrF8DG--
From: Nick Hudson <nick.hudson@gmx.co.uk>
To: Taylor R Campbell <riastradh@NetBSD.org>
Cc: "netbsd-bugs@netbsd.org" <netbsd-bugs@NetBSD.org>,
"gnats-bugs@netbsd.org" <gnats-bugs@NetBSD.org>,
"mrg@netbsd.org" <mrg@NetBSD.org>,
"skrll@netbsd.org" <skrll@NetBSD.org>,
"jakllsch@netbsd.org" <jakllsch@NetBSD.org>
Subject: Re: kern/59943: usbnet(9) keeps failed packet in queue to retry
indefinitely
Date: Mon, 26 Jan 2026 07:12:16 +0000
> On 26 Jan 2026, at 03:53, Taylor R Campbell <riastradh@NetBSD.org> wrote=
:
>=20
> The attached (untested) patch tries to address these issues (and some
> of those in PR kern/59940: usbnet(9): uno_tx_prepare buffer overrun
> audit); details in commit message. Thoughts?
> <pr59940-pr59943-usbnettxfixes.patch>
LGTM
From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/59943 CVS commit: src/sys/dev/usb
Date: Sun, 1 Feb 2026 03:33:19 +0000
Module Name: src
Committed By: riastradh
Date: Sun Feb 1 03:33:19 UTC 2026
Modified Files:
src/sys/dev/usb: usbnet.c
Log Message:
usbnet(9): Tighten tx path.
1. Verify, don't just assert, that the packet length is below the
buffer size. Even if all the callers enforce the interface's MTU,
I can't prove that the usbnet(9) tx buffer size is an upper bound
enforced on the interface's MTU.
We can remove the check later if we do enforce that upper bound at
some point, which would probably be worth doing anyway since the
MTU is checked earlier in the tx path.
2. Assert, don't check, that c->unc_xfer is nonnull. We can only
reach the tx path if we cross if_init=usbnet_init_rx_tx, and that
(via usbnet_tx_list_init) is guaranteed to fail and back out
unless all of the usbnet_chain unc_xfers get initialized.
3. If we can't fit the packet into a buffer, drop it -- don't leave
it in the queue to try again when it still won't fit in the
buffer.
4. If the transfer for this packet fails, drop it -- don't leave it
in the queue to try again just in case it might work better the
next time.
PR kern/59940: usbnet(9): uno_tx_prepare buffer overrun audit
PR kern/59943: usbnet(9) keeps failed packet in queue to retry indefinitely
To generate a diff of this commit:
cvs rdiff -u -r1.121 -r1.122 src/sys/dev/usb/usbnet.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
(Contact us)
$NetBSD: query-full-pr,v 1.51 2026/08/10 02:28:17 riastradh Exp $
$NetBSD: gnats_config.sh,v 1.10 2026/05/13 22:00:09 riastradh Exp $
Copyright © 1994-2026
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.