In iwm(4) and iwx(4), prevent attemps to transition towards the same state
authorstsp <stsp@openbsd.org>
Thu, 30 Sep 2021 09:27:47 +0000 (09:27 +0000)
committerstsp <stsp@openbsd.org>
Thu, 30 Sep 2021 09:27:47 +0000 (09:27 +0000)
in cases where this would result in a redundant or illegal state transition.

jmc@ observed ASSOC -> ASSOC transitions which would result in a hang.
Such transitions are invalid and never intentionally triggered by net80211.
They imply a race between the Rx interrupt handler and the newstate task.

Tested by jmc@ on AX200 for a week and several known issues seem to be fixed.

sys/dev/pci/if_iwm.c
sys/dev/pci/if_iwx.c

index cb75fbf..c8229ae 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_iwm.c,v 1.368 2021/09/24 19:02:16 stsp Exp $       */
+/*     $OpenBSD: if_iwm.c,v 1.369 2021/09/30 09:27:47 stsp Exp $       */
 
 /*
  * Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -9004,6 +9004,14 @@ iwm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
        struct iwm_softc *sc = ifp->if_softc;
        int i;
 
+       /*
+        * Prevent attemps to transition towards the same state, unless
+        * we are scanning in which case a SCAN -> SCAN transition
+        * triggers another scan iteration.
+        */
+       if (sc->ns_nstate == nstate && nstate != IEEE80211_S_SCAN)
+               return 0;
+
        if (ic->ic_state == IEEE80211_S_RUN) {
                timeout_del(&sc->sc_calib_to);
                iwm_del_task(sc, systq, &sc->ba_task);
index f9c68a2..0535076 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_iwx.c,v 1.111 2021/09/23 16:27:58 stsp Exp $       */
+/*     $OpenBSD: if_iwx.c,v 1.112 2021/09/30 09:27:47 stsp Exp $       */
 
 /*
  * Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -7921,6 +7921,14 @@ iwx_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
        struct iwx_softc *sc = ifp->if_softc;
        int i;
 
+       /*
+        * Prevent attemps to transition towards the same state, unless
+        * we are scanning in which case a SCAN -> SCAN transition
+        * triggers another scan iteration.
+        */
+       if (sc->ns_nstate == nstate && nstate != IEEE80211_S_SCAN)
+               return 0;
+
        if (ic->ic_state == IEEE80211_S_RUN) {
                iwx_del_task(sc, systq, &sc->ba_task);
                iwx_del_task(sc, systq, &sc->setkey_task);