An AP which never responds to auth/assoc requests can remain in the
joinlist and keep being selected. This results in an endless loop
between SCAN and AUTH (and sometimes ASSOC) states:

iwm0: SCAN -> AUTH
iwm0: sending auth to 00:1a:dd:da:e3:f1 on channel 64 mode 11a
iwm0: AUTH -> SCAN

Another AP added to the joinlist may never be selected if it has a
lower score than this "bad" AP in the list (e.g. if the "bad" AP is
using WPA and the alternative AP which was added uses no encryption).

In this example, the AP which does not respond has the SSID "OpenBSD",
and I added the unencrypted "univbuc_free" network to the joinlist
during SCAN:

iwm0: end passive scan
iwm0: AP 10:bd:18:3d:c1:11 "univbuc_free" score 43
iwm0: AP 10:bd:18:3d:c1:1e "univbuc_free" score 43
iwm0: AP 10:bd:18:4d:9f:f1 "univbuc_free" score 43
iwm0: AP 10:bd:18:4d:9f:fe "univbuc_free" score 43
iwm0: AP f4:ea:67:5c:f9:61 "univbuc_free" score 43
iwm0: AP f4:ea:67:5c:f9:6e "univbuc_free" score 45
iwm0: AP f4:ea:67:5d:01:51 "univbuc_free" score 43
iwm0: AP f4:ea:67:5d:01:5e "univbuc_free" score 43
iwm0: AP f4:ea:67:bf:aa:11 "univbuc_free" score 43
iwm0: AP f4:ea:67:c0:f8:71 "univbuc_free" score 43
iwm0: AP f4:ea:67:c0:f8:7e "univbuc_free" score 43
iwm0: best AP 00:1a:dd:da:e3:e1 "OpenBSD" score 52
iwm0: switching to network "OpenBSD"

With this diff we deselect an AP which fails to auth/assoc, and give
higher priority to APs which have had no auth/assoc failures yet.

This looks like:

iwm0: end active scan
iwm0: AP 10:bd:18:3c:d4:81 "univbuc_free" score 54
iwm0: AP 10:bd:18:3c:d4:8e "univbuc_free" score 54
iwm0: AP 10:bd:18:4d:98:81 "univbuc_free" score 54
iwm0: AP 10:bd:18:4d:98:8e "univbuc_free" score 53
iwm0: AP 10:bd:18:4d:9f:7e "univbuc_free" score 53
iwm0: AP 10:bd:18:4d:9f:fe "univbuc_free" score 53
iwm0: AP 10:bd:18:4d:cf:41 "univbuc_free" score 53
iwm0: AP 10:bd:18:4d:cf:4e "univbuc_free" score 53
iwm0: AP 10:bd:18:6c:aa:51 "univbuc_free" score 53
iwm0: AP 10:bd:18:6c:aa:5e "univbuc_free" score 53
iwm0: AP f4:ea:67:5c:f9:61 "univbuc_free" score 33
iwm0: AP f4:ea:67:5c:f9:6e "univbuc_free" score 53
iwm0: AP f4:ea:67:5d:01:51 "univbuc_free" score 53
iwm0: AP f4:ea:67:5d:01:5e "univbuc_free" score 53
iwm0: AP f4:ea:67:c0:f8:71 "univbuc_free" score 54
iwm0: AP f4:ea:67:c0:f8:7e "univbuc_free" score 54
iwm0: best AP 00:1a:dd:da:e3:f1 "OpenBSD" score 73
iwm0: switching to network "OpenBSD"

(long scan result list omitted)

iwm0: SCAN -> AUTH
iwm0: sending auth to 00:1a:dd:da:e3:f1 on channel 64 mode 11a
iwm0: authentication timed out for 00:1a:dd:da:e3:f1
iwm0: AUTH -> SCAN
iwm0: end active scan
iwm0: AP 00:1a:dd:da:e3:f1 "OpenBSD" score 52
iwm0: AP 10:bd:18:4d:9f:71 "univbuc_free" score 53
iwm0: AP 10:bd:18:4d:9f:7e "univbuc_free" score 53
iwm0: AP 10:bd:18:4d:9f:f1 "univbuc_free" score 53
iwm0: AP 10:bd:18:4d:9f:fe "univbuc_free" score 53
iwm0: AP 10:bd:18:4d:cf:41 "univbuc_free" score 53
iwm0: AP 10:bd:18:4d:cf:4e "univbuc_free" score 53
iwm0: AP 10:bd:18:6c:aa:51 "univbuc_free" score 53
iwm0: AP 18:33:9d:6d:9c:61 "univbuc_free" score 53
iwm0: AP 18:33:9d:6d:9c:6e "univbuc_free" score 53
iwm0: AP f4:ea:67:5c:f9:61 "univbuc_free" score 33
iwm0: AP f4:ea:67:5d:01:5e "univbuc_free" score 53
iwm0: AP f4:ea:67:be:74:21 "univbuc_free" score 53
iwm0: AP f4:ea:67:bf:aa:11 "univbuc_free" score 53
iwm0: AP f4:ea:67:c0:f8:71 "univbuc_free" score 53
iwm0: AP f4:ea:67:c0:f8:7e "univbuc_free" score 53
iwm0: best AP f4:ea:67:5d:01:51 "univbuc_free" score 53
iwm0: switching to network "univbuc_free"

ok?

diff refs/heads/master refs/heads/join-deselect
blob - bf2b2858f03d302ded03555bda21450f9c80cf66
blob + d66ca6238ff5d4c8a642805ef45843088bae4289
--- sys/net80211/ieee80211.c
+++ sys/net80211/ieee80211.c
@@ -772,8 +772,25 @@ ieee80211_watchdog(struct ifnet *ifp)
 {
        struct ieee80211com *ic = (void *)ifp;
 
-       if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0)
+       if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0) {
+               if (ic->ic_opmode == IEEE80211_M_STA &&
+                   (ic->ic_state == IEEE80211_S_AUTH ||
+                   ic->ic_state == IEEE80211_S_ASSOC)) {
+                       struct ieee80211_node *ni;
+                       if (ifp->if_flags & IFF_DEBUG)
+                               printf("%s: %s timed out for %s\n",
+                                   ifp->if_xname,
+                                   ic->ic_state == IEEE80211_S_ASSOC ?
+                                   "association" : "authentication",
+                                   ether_sprintf(ic->ic_bss->ni_macaddr));
+                       ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr);
+                       if (ni)
+                               ni->ni_fails++;
+                       if (ISSET(ic->ic_flags, IEEE80211_F_AUTO_JOIN))
+                               ieee80211_deselect_ess(ic);
+               }
                ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+       }
 
        if (ic->ic_mgt_timer != 0)
                ifp->if_timer = 1;
blob - 41530d2a311e1dbc2c0e70f95a14c360e9f981d6 (mode 644)
blob + 78a907b8c5c2e146b4f904fdc2f352430fdf8757 (mode 600)
--- sys/net80211/ieee80211_node.c
+++ sys/net80211/ieee80211_node.c
@@ -476,6 +476,10 @@ ieee80211_ess_calculate_score(struct ieee80211com *ic,
            ni->ni_rssi > min_5ghz_rssi)
                score += 2;
 
+       /* Boost this AP if it had no auth/assoc failures in the past. */
+       if (ni->ni_fails == 0)
+               score += 21;
+
        return score;
 }
 
@@ -669,6 +673,15 @@ ieee80211_set_ess(struct ieee80211com *ic, struct ieee
                ic->ic_def_txkey = ess->def_txkey;
                ic->ic_flags |= IEEE80211_F_WEPON;
        }
+}
+
+void
+ieee80211_deselect_ess(struct ieee80211com *ic)
+{
+       memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
+       ic->ic_des_esslen = 0;
+       ieee80211_disable_wep(ic);
+       ieee80211_disable_rsn(ic);
 }
 
 void
blob - d5560e75f48cd00aa424f22bdb0237e447405420
blob + f1e728c0e72d599aed4165b8d68e412ba3d9413f
--- sys/net80211/ieee80211_var.h
+++ sys/net80211/ieee80211_var.h
@@ -472,6 +472,7 @@ int ieee80211_add_ess(struct ieee80211com *, struct ie
 void   ieee80211_del_ess(struct ieee80211com *, char *, int, int);
 void   ieee80211_set_ess(struct ieee80211com *, struct ieee80211_ess *,
            struct ieee80211_node *);
+void   ieee80211_deselect_ess(struct ieee80211com *);
 struct ieee80211_ess *ieee80211_get_ess(struct ieee80211com *, const char *, 
int);
 
 extern int ieee80211_cache_size;

Reply via email to