On Thu, Dec 07, 2017 at 02:10:02PM +0100, Stefan Sperling wrote:
> I found a way to reproduce the "hangs" people have been reporting
> during 'ifconfig iwm0 scan'. The problem is actually quite trivial.
> 
> To reproduce:
> 
>   1) configure a network ID that does not exist around you
>   2) put the interface up
>   3) keep running ifconfig iwm0 scan; eventually ifconfig won't
>      show results but just time out; and observe how no frames
>      are received with: tcpdump -i iwm0 -y IEEE802_11_RADIO
> 
> The problem is that iwm_newstate does not restart scans when a SCAN->SCAN
> transition happens and the firmware scan command is no longer busy.

Fixed diff: The previous diff accidentally started a new scan even
while the firmware was still busy scanning.

Index: if_iwm.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v
retrieving revision 1.217
diff -u -p -r1.217 if_iwm.c
--- if_iwm.c    26 Oct 2017 15:00:28 -0000      1.217
+++ if_iwm.c    7 Dec 2017 13:20:57 -0000
@@ -5986,17 +5986,27 @@ iwm_newstate_task(void *psc)
            ieee80211_state_name[ostate],
            ieee80211_state_name[nstate]));
 
-       if (nstate == ostate || (sc->sc_flags & IWM_FLAG_SHUTDOWN)) {
-               /* No-op state change or iwm_stop() is waiting for us. */
+       if (sc->sc_flags & IWM_FLAG_SHUTDOWN) {
+               /* iwm_stop() is waiting for us. */
                refcnt_rele_wake(&sc->task_refs);
                splx(s);
                return;
        }
 
-       if (ostate == IEEE80211_S_SCAN)
-               iwm_led_blink_stop(sc);
+       if (ostate == IEEE80211_S_SCAN) {
+               if (nstate == ostate) {
+                       if (sc->sc_flags & IWM_FLAG_SCANNING) {
+                               refcnt_rele_wake(&sc->task_refs);
+                               splx(s);
+                               return;
+                       }
+                       /* Firmware is no longer scanning. Do another scan. */
+                       goto next_scan;
+               } else
+                       iwm_led_blink_stop(sc);
+       }
 
-       if (nstate < ostate) {
+       if (nstate <= ostate) {
                switch (ostate) {
                case IEEE80211_S_RUN:
                        err = iwm_run_stop(sc);
@@ -6035,6 +6045,7 @@ iwm_newstate_task(void *psc)
                break;
 
        case IEEE80211_S_SCAN:
+next_scan:
                err = iwm_scan(sc);
                if (err)
                        break;

Reply via email to