On Tue, 24 Mar 2026 12:32:43 +0100,
Stefan Sperling <[email protected]> wrote:
>
> On Tue, Mar 24, 2026 at 09:16:00AM +0100, mwpudrtxoe wrote:
> > >Synopsis: IWX reports errors and eventually hangs with a full send buffer
> > >Category: kernel
> > >Environment:
> > System : OpenBSD 7.8
> > Details : OpenBSD 7.8 (GENERIC.MP) #6: Fri Mar 20 10:18:39 MDT 2026
> >
> > [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
> >
> > Architecture: OpenBSD.amd64
> > Machine : amd64
> > >Description:
> >
> > The IWX driver sporadically reports errors like these:
> >
> > iwx0: unhandled firmware response 0x3ff/0x20000008 rx ring 126[1]
> > iwx0: unhandled firmware response 0x3ff/0x20000008 rx ring 122[229]
> > iwx0: unhandled firmware response 0x3fd/0x2000000c rx ring 81[128]
> > iwx0: unhandled firmware response 0x3ff/0x20000008 rx ring 81[138]
> > iwx0: unhandled firmware response 0x3ff/0x20000008 rx ring 91[4]
> > iwx0: unhandled firmware response 0x3fd/0x2000000c rx ring 104[72]
> > iwx0: unhandled firmware response 0x3fd/0x2000000c rx ring 123[124]
> >
> > ... then after a long while (about one day) runs into a full send buffer.
> >
>
> This is related to channel switch announcements sent by the AP.
> The firmware sends notification 0x3ff to the driver and will no longer
> send frames out. Sending frames on the channel which the AP is switching
> away from is not allowed (I assume this prevents interference with radar,
> which could be the reason why the AP is moving away).
>
> The driver is expected to react to this situation, e.g. by resetting the
> interface and scan for a new AP, or keep the interface associated but move
> it to the AP's new channel. Our driver doesn't do any of that yet.
>
> A fix wouldn't be very hard to write. The interface needs to be put back
> into SCAN state, and net80211 needs to be taught to skip access points which
> are currently announcing a channel switch. Or the driver could be taught to
> send the necessary firmware commands to switch the device to the new channel
> in response to the channel switch annoucenment.
>
> I have too many things on my plate right now to work on this myself.
>
> A workaround is to fix the channel used by the AP, rather than letting
> the AP auto-select one. Preferrably use a channel with does not require DFS.
>
Thanks for detailed explanation, and because I'm in context of iwx driver it
ineed trivial implement. I haven't touched other dirvers, but iwx is tested
and seems works.
Also, I've checked Linux and it treats both CSA and eCSA/XCSA, so I did the
same.
The diff:
Index: sys/dev/pci/if_iwx.c
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/if_iwx.c,v
diff -u -p -r1.223 if_iwx.c
--- sys/dev/pci/if_iwx.c 14 Mar 2026 15:37:44 -0000 1.223
+++ sys/dev/pci/if_iwx.c 24 Mar 2026 17:39:36 -0000
@@ -10994,6 +10994,23 @@ iwx_rx_pkt(struct iwx_softc *sc, struct
break;
}
+ case IWX_WIDE_ID(IWX_MAC_CONF_GROUP,
+ IWX_CHANNEL_SWITCH_START_NOTIF): {
+ if (sc->sc_ic.ic_opmode != IEEE80211_M_STA ||
+ sc->sc_ic.ic_state != IEEE80211_S_RUN)
+ break;
+
+ if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
+ printf("%s: firmware channel switch "
+ "notification 0x%x\n",
+ DEVNAME(sc), code);
+
+ if ((sc->sc_flags & IWX_FLAG_SHUTDOWN) == 0 &&
+ !task_pending(&sc->init_task))
+ task_add(systq, &sc->init_task);
+ break;
+ }
+
case IWX_WIDE_ID(IWX_SYSTEM_GROUP,
IWX_FSEQ_VER_MISMATCH_NOTIFICATION):
break;
Index: sys/dev/pci/if_iwxreg.h
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/if_iwxreg.h,v
diff -u -p -r1.73 if_iwxreg.h
--- sys/dev/pci/if_iwxreg.h 13 Mar 2026 11:11:02 -0000 1.73
+++ sys/dev/pci/if_iwxreg.h 24 Mar 2026 17:37:13 -0000
@@ -2079,6 +2079,7 @@ struct iwx_tx_queue_cfg_rsp {
#define IWX_STA_REMOVE_CMD 0x0c
#define IWX_SESSION_PROTECTION_NOTIF 0xfb
#define IWX_MISSED_BEACONS_NOTIF 0xf6
+#define IWX_CHANNEL_SWITCH_START_NOTIF 0xff
/* DATA_PATH group subcommand IDs */
#define IWX_DQA_ENABLE_CMD 0x00
Index: sys/net80211/ieee80211_input.c
===================================================================
RCS file: /home/cvs/src/sys/net80211/ieee80211_input.c,v
diff -u -p -r1.260 ieee80211_input.c
--- sys/net80211/ieee80211_input.c 19 Mar 2026 16:50:32 -0000 1.260
+++ sys/net80211/ieee80211_input.c 24 Mar 2026 17:40:26 -0000
@@ -1623,7 +1623,7 @@ ieee80211_recv_probe_resp(struct ieee802
{
struct ieee80211_node *ni;
const struct ieee80211_frame *wh;
- const u_int8_t *frm, *efrm;
+ const u_int8_t *frm, *efrm, *csa, *xcsa;
const u_int8_t *tstamp, *ssid, *rates, *xrates, *edcaie, *wmmie, *tim;
const u_int8_t *rsnie, *wpaie, *htcaps, *htop, *vhtcaps, *vhtop,
*hecaps, *heop;
u_int16_t capinfo, bintval;
@@ -1666,7 +1666,7 @@ ieee80211_recv_probe_resp(struct ieee802
capinfo = LE_READ_2(frm); frm += 2;
ssid = rates = xrates = edcaie = wmmie = rsnie = wpaie = tim = NULL;
- htcaps = htop = vhtcaps = vhtop = hecaps = heop = NULL;
+ htcaps = htop = vhtcaps = vhtop = hecaps = heop = csa = xcsa = NULL;
if (rxi->rxi_chan)
bchan = rxi->rxi_chan;
else
@@ -1702,6 +1702,20 @@ ieee80211_recv_probe_resp(struct ieee802
}
erp = frm[2];
break;
+ case IEEE80211_ELEMID_CSA:
+ if (frm[1] < 3) {
+ ic->ic_stats.is_rx_elem_toosmall++;
+ break;
+ }
+ csa = frm;
+ break;
+ case IEEE80211_ELEMID_XCSA:
+ if (frm[1] < 4) {
+ ic->ic_stats.is_rx_elem_toosmall++;
+ break;
+ }
+ xcsa = frm;
+ break;
case IEEE80211_ELEMID_RSN:
rsnie = frm;
break;
@@ -1826,6 +1840,9 @@ ieee80211_recv_probe_resp(struct ieee802
#endif
ni->ni_chan = &ic->ic_channels[chan];
+ ni->ni_flags &= ~IEEE80211_NODE_CSA;
+ if (csa != NULL || xcsa != NULL)
+ ni->ni_flags |= IEEE80211_NODE_CSA;
if (htcaps)
ieee80211_setup_htcaps(ni, htcaps + 2, htcaps[1]);
Index: sys/net80211/ieee80211_node.c
===================================================================
RCS file: /home/cvs/src/sys/net80211/ieee80211_node.c,v
diff -u -p -r1.211 ieee80211_node.c
--- sys/net80211/ieee80211_node.c 19 Mar 2026 16:50:32 -0000 1.211
+++ sys/net80211/ieee80211_node.c 24 Mar 2026 17:30:50 -0000
@@ -1135,6 +1135,8 @@ ieee80211_match_bss(struct ieee80211com
if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
!IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid))
fail |= IEEE80211_NODE_ASSOCFAIL_BSSID;
+ if (ni->ni_flags & IEEE80211_NODE_CSA)
+ fail |= IEEE80211_NODE_ASSOCFAIL_CSA;
if (ic->ic_flags & IEEE80211_F_RSNON) {
/*
Index: sys/net80211/ieee80211_node.h
===================================================================
RCS file: /home/cvs/src/sys/net80211/ieee80211_node.h,v
diff -u -p -r1.99 ieee80211_node.h
--- sys/net80211/ieee80211_node.h 19 Mar 2026 16:50:32 -0000 1.99
+++ sys/net80211/ieee80211_node.h 24 Mar 2026 17:30:50 -0000
@@ -413,6 +413,7 @@ struct ieee80211_node {
#define IEEE80211_NODE_ASSOCFAIL_BSSID 0x20
#define IEEE80211_NODE_ASSOCFAIL_WPA_PROTO 0x40
#define IEEE80211_NODE_ASSOCFAIL_WPA_KEY 0x80
+#define IEEE80211_NODE_ASSOCFAIL_CSA 0x100
int ni_inact; /* inactivity mark count */
int ni_txrate; /* index to ni_rates[] */
@@ -444,6 +445,7 @@ struct ieee80211_node {
#define IEEE80211_NODE_VHT_SGI160 0x100000 /* SGI on 160 MHz negotiated
*/
#define IEEE80211_NODE_HE 0x200000 /* HE negotiated */
#define IEEE80211_NODE_HECAP 0x400000 /* claims to support HE */
+#define IEEE80211_NODE_CSA 0x800000 /* channel switch announced */
/* If not NULL, this function gets called when ni_refcnt hits zero. */
void (*ni_unref_cb)(struct ieee80211com *,
--
wbr, Kirill