From afe2e7dfd7922aa8f73cbfb092ccac18d3055200 Mon Sep 17 00:00:00 2001 From: stsp Date: Sun, 25 Feb 2018 12:40:06 +0000 Subject: [PATCH] My previous commit to iwn(4) broke the scan loop. The problem happened if we didn't find an AP to connect to after one scan iteration. The net80211 stack then performs a SCAN -> SCAN transition to kick off another scan, but the driver treated this transition as a no-op and remained in SCAN state doing nothing. To fix this, introduce a flag which keeps track of whether a firmware scan command is in progress, and start another scan during a SCAN->SCAN transition if no scan is in progress. Matches what iwm(4) does. Note that previously (i.e. in 6.2), iwn(4) would always try to start a new scan regardless of what the firmware was currently doing. Problem noticed by myself and also by deraadt@ test & ok tb@ --- sys/dev/pci/if_iwn.c | 25 +++++++++++++++++-------- sys/dev/pci/if_iwnvar.h | 3 ++- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/sys/dev/pci/if_iwn.c b/sys/dev/pci/if_iwn.c index 65969746188..d26fb6a5e64 100644 --- a/sys/dev/pci/if_iwn.c +++ b/sys/dev/pci/if_iwn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwn.c,v 1.200 2018/02/01 11:21:34 stsp Exp $ */ +/* $OpenBSD: if_iwn.c,v 1.201 2018/02/25 12:40:06 stsp Exp $ */ /*- * Copyright (c) 2007-2010 Damien Bergamini @@ -1773,8 +1773,11 @@ iwn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) } if (ic->ic_state == IEEE80211_S_SCAN) { - if (nstate == IEEE80211_S_SCAN) - return 0; + if (nstate == IEEE80211_S_SCAN) { + if (sc->sc_flags & IWN_FLAG_SCANNING) + return 0; + } else + sc->sc_flags &= ~IWN_FLAG_SCANNING; /* Turn LED off when leaving scan state. */ iwn_set_led(sc, IWN_LED_LINK, 1, 0); } @@ -2653,8 +2656,9 @@ iwn_notif_intr(struct iwn_softc *sc) if (error == 0) break; } - ieee80211_end_scan(ifp); + sc->sc_flags &= ~IWN_FLAG_SCANNING; sc->sc_flags &= ~IWN_FLAG_BGSCAN; + ieee80211_end_scan(ifp); break; } case IWN5000_CALIBRATION_RESULT: @@ -4922,11 +4926,12 @@ iwn_scan(struct iwn_softc *sc, uint16_t flags, int bgscan) hdr->len = htole16(buflen); DPRINTF(("sending scan command nchan=%d\n", hdr->nchan)); - if (bgscan) - sc->sc_flags |= IWN_FLAG_BGSCAN; error = iwn_cmd(sc, IWN_CMD_SCAN, buf, buflen, 1); - if (bgscan && error) - sc->sc_flags &= ~IWN_FLAG_BGSCAN; + if (error == 0) { + sc->sc_flags |= IWN_FLAG_SCANNING; + if (bgscan) + sc->sc_flags |= IWN_FLAG_BGSCAN; + } free(buf, M_DEVBUF, IWN_SCAN_MAXSZ); return error; } @@ -4939,6 +4944,7 @@ iwn_scan_abort(struct iwn_softc *sc) /* XXX Cannot wait for status response in interrupt context. */ DELAY(100); + sc->sc_flags &= ~IWN_FLAG_SCANNING; sc->sc_flags &= ~IWN_FLAG_BGSCAN; } @@ -4948,6 +4954,9 @@ iwn_bgscan(struct ieee80211com *ic) struct iwn_softc *sc = ic->ic_softc; int error; + if (sc->sc_flags & IWN_FLAG_SCANNING) + return 0; + error = iwn_scan(sc, IEEE80211_CHAN_2GHZ, 1); if (error) printf("%s: could not initiate background scan\n", diff --git a/sys/dev/pci/if_iwnvar.h b/sys/dev/pci/if_iwnvar.h index 82a3693439d..fd9616f0258 100644 --- a/sys/dev/pci/if_iwnvar.h +++ b/sys/dev/pci/if_iwnvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwnvar.h,v 1.33 2017/12/14 14:21:11 stsp Exp $ */ +/* $OpenBSD: if_iwnvar.h,v 1.34 2018/02/25 12:40:06 stsp Exp $ */ /*- * Copyright (c) 2007, 2008 @@ -203,6 +203,7 @@ struct iwn_softc { #define IWN_FLAG_ENH_SENS (1 << 7) #define IWN_FLAG_ADV_BT_COEX (1 << 8) #define IWN_FLAG_BGSCAN (1 << 9) +#define IWN_FLAG_SCANNING (1 << 10) uint8_t hw_type; -- 2.20.1