On 2026 Mar 24 (Tue) at 18:52:14 +0100 (+0100), Kirill A. Korinsky wrote:
: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:
:

Looking at the IEEE standard, this is a simplistic but sensible implementation.

One nit, OK either way.


: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)
                            ^^^^^^^^  this can be simplified to ifp->if_flags


:+                              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
:

-- 
All theoretical chemistry is really physics;
and all theoretical chemists know it.
                -- Richard P. Feynman

Reply via email to