When starting a background scan, free the nodes table to ensure we
get an up-to-date view of APs around us. In particular, we need to
kick out the AP we are associated to. Otherwise, our current AP might
stay cached if it is turned off while we are scanning, and we could
end up picking a now non-existent but "good looking" AP over and over.
Problem found and diagnosed with phessler.
Note that live data for the asocciated AP lives in ic->ic_bss and
was deep-copied there from the nodes table during association.
The nodes table only contains a cached node for this AP.
Index: dev/ic/pgt.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/pgt.c,v
retrieving revision 1.90
diff -u -p -r1.90 pgt.c
--- dev/ic/pgt.c 26 Oct 2017 15:00:28 -0000 1.90
+++ dev/ic/pgt.c 27 Apr 2018 16:20:53 -0000
@@ -2943,7 +2943,7 @@ pgt_newstate(struct ieee80211com *ic, en
ic->ic_if.if_timer = 0;
ic->ic_mgt_timer = 0;
ic->ic_flags &= ~IEEE80211_F_SIBSS;
- ieee80211_free_allnodes(ic);
+ ieee80211_free_allnodes(ic, 1);
break;
case IEEE80211_S_SCAN:
ic->ic_if.if_timer = 1;
@@ -2951,7 +2951,7 @@ pgt_newstate(struct ieee80211com *ic, en
if (sc->sc_flags & SC_NOFREE_ALLNODES)
sc->sc_flags &= ~SC_NOFREE_ALLNODES;
else
- ieee80211_free_allnodes(ic);
+ ieee80211_free_allnodes(ic, 1);
#ifndef IEEE80211_STA_ONLY
/* Just use any old channel; we override it anyway. */
Index: dev/usb/if_atu.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_atu.c,v
retrieving revision 1.124
diff -u -p -r1.124 if_atu.c
--- dev/usb/if_atu.c 31 Jan 2018 12:36:13 -0000 1.124
+++ dev/usb/if_atu.c 27 Apr 2018 16:20:14 -0000
@@ -1210,7 +1210,7 @@ atu_newstate(struct ieee80211com *ic, en
case IEEE80211_S_SCAN:
memcpy(ic->ic_chan_scan, ic->ic_chan_active,
sizeof(ic->ic_chan_active));
- ieee80211_free_allnodes(ic);
+ ieee80211_free_allnodes(ic, 1);
/* tell the event thread that we want a scan */
sc->sc_cmd = ATU_C_SCAN;
Index: net80211/ieee80211.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211.c,v
retrieving revision 1.67
diff -u -p -r1.67 ieee80211.c
--- net80211/ieee80211.c 26 Apr 2018 12:50:07 -0000 1.67
+++ net80211/ieee80211.c 27 Apr 2018 16:22:00 -0000
@@ -81,6 +81,15 @@ ieee80211_begin_bgscan(struct ifnet *ifp
return;
if (ic->ic_bgscan_start != NULL && ic->ic_bgscan_start(ic) == 0) {
+ /*
+ * Free the nodes table to ensure we get an up-to-date view
+ * of APs around us. In particular, we need to kick out the
+ * AP we are associated to. Otherwise, our current AP might
+ * stay cached if it is turned off while we are scanning, and
+ * we could end up picking a now non-existent AP over and over.
+ */
+ ieee80211_free_allnodes(ic, 0 /* keep ic->ic_bss */);
+
ic->ic_flags |= IEEE80211_F_BGSCAN;
if (ifp->if_flags & IFF_DEBUG)
printf("%s: begin background scan\n", ifp->if_xname);
Index: net80211/ieee80211_node.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_node.c,v
retrieving revision 1.128
diff -u -p -r1.128 ieee80211_node.c
--- net80211/ieee80211_node.c 27 Apr 2018 15:27:10 -0000 1.128
+++ net80211/ieee80211_node.c 27 Apr 2018 16:28:18 -0000
@@ -205,7 +205,7 @@ ieee80211_node_detach(struct ifnet *ifp)
(*ic->ic_node_free)(ic, ic->ic_bss);
ic->ic_bss = NULL;
}
- ieee80211_free_allnodes(ic);
+ ieee80211_free_allnodes(ic, 1);
#ifndef IEEE80211_STA_ONLY
free(ic->ic_aid_bitmap, M_DEVBUF,
howmany(ic->ic_max_aid, 32) * sizeof(u_int32_t));
@@ -271,7 +271,7 @@ ieee80211_begin_scan(struct ifnet *ifp)
* otherwise we'll potentially flush state of stations
* associated with us.
*/
- ieee80211_free_allnodes(ic);
+ ieee80211_free_allnodes(ic, 1);
/*
* Reset the current mode. Setting the current mode will also
@@ -1348,7 +1348,7 @@ ieee80211_release_node(struct ieee80211c
}
void
-ieee80211_free_allnodes(struct ieee80211com *ic)
+ieee80211_free_allnodes(struct ieee80211com *ic, int clear_ic_bss)
{
struct ieee80211_node *ni;
int s;
@@ -1359,7 +1359,7 @@ ieee80211_free_allnodes(struct ieee80211
ieee80211_free_node(ic, ni);
splx(s);
- if (ic->ic_bss != NULL)
+ if (clear_ic_bss && ic->ic_bss != NULL)
ieee80211_node_cleanup(ic, ic->ic_bss); /* for station mode */
}
Index: net80211/ieee80211_node.h
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_node.h,v
retrieving revision 1.73
diff -u -p -r1.73 ieee80211_node.h
--- net80211/ieee80211_node.h 6 Feb 2018 22:17:03 -0000 1.73
+++ net80211/ieee80211_node.h 27 Apr 2018 16:20:02 -0000
@@ -382,7 +382,7 @@ struct ieee80211_node *
const char *, u_int8_t);
void ieee80211_release_node(struct ieee80211com *,
struct ieee80211_node *);
-void ieee80211_free_allnodes(struct ieee80211com *);
+void ieee80211_free_allnodes(struct ieee80211com *, int);
void ieee80211_iterate_nodes(struct ieee80211com *,
ieee80211_iter_func *, void *);
void ieee80211_clean_cached(struct ieee80211com *);
Index: net80211/ieee80211_proto.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_proto.c,v
retrieving revision 1.84
diff -u -p -r1.84 ieee80211_proto.c
--- net80211/ieee80211_proto.c 27 Apr 2018 15:33:49 -0000 1.84
+++ net80211/ieee80211_proto.c 27 Apr 2018 16:28:18 -0000
@@ -944,7 +944,7 @@ justcleanup:
ic->ic_mgt_timer = 0;
mq_purge(&ic->ic_mgtq);
mq_purge(&ic->ic_pwrsaveq);
- ieee80211_free_allnodes(ic);
+ ieee80211_free_allnodes(ic, 1);
break;
}
ni->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE;
@@ -994,7 +994,7 @@ justcleanup:
}
timeout_del(&ic->ic_bgscan_timeout);
ic->ic_bgscan_fail = 0;
- ieee80211_free_allnodes(ic);
+ ieee80211_free_allnodes(ic, 1);
/* FALLTHROUGH */
case IEEE80211_S_AUTH:
case IEEE80211_S_ASSOC: