On Wed, Aug 28, 2019 at 07:12:58PM +0200, Stefan Sperling wrote:
> Another (hopefully final) update:

Turns out the previous diffs break the ramdisk kernel build.

Fixed version:

diff refs/heads/master refs/heads/assocfail
blob - 543e09f0d6e6b4e75456a21d4218468729b61a5e
blob + 42ad3819f5688690ebee46d01274f54907066e67
--- sbin/ifconfig/ifconfig.c
+++ sbin/ifconfig/ifconfig.c
@@ -2348,10 +2348,25 @@ print_cipherset(u_int32_t cipherset)
 }
 
 void
+print_assoc_failures(uint32_t assoc_fail)
+{
+       /* Filter out the most obvious failure cases. */
+       assoc_fail &= ~IEEE80211_NODEREQ_ASSOCFAIL_ESSID;
+       if (assoc_fail & IEEE80211_NODEREQ_ASSOCFAIL_PRIVACY)
+               assoc_fail &= ~IEEE80211_NODEREQ_ASSOCFAIL_WPA_PROTO;
+       assoc_fail &= ~IEEE80211_NODEREQ_ASSOCFAIL_PRIVACY;
+
+       if (assoc_fail == 0)
+               return;
+
+       printb_status(assoc_fail, IEEE80211_NODEREQ_ASSOCFAIL_BITS);
+}
+
+void
 ieee80211_status(void)
 {
        int len, inwid, ijoin, inwkey, ipsk, ichan, ipwr;
-       int ibssid, iwpa;
+       int ibssid, iwpa, assocfail = 0;
        struct ieee80211_nwid nwid;
        struct ieee80211_join join;
        struct ieee80211_nwkey nwkey;
@@ -2431,11 +2446,15 @@ ieee80211_status(void)
                bzero(&nr, sizeof(nr));
                bcopy(bssid.i_bssid, &nr.nr_macaddr, sizeof(nr.nr_macaddr));
                strlcpy(nr.nr_ifname, name, sizeof(nr.nr_ifname));
-               if (ioctl(s, SIOCG80211NODE, &nr) == 0 && nr.nr_rssi) {
-                       if (nr.nr_max_rssi)
-                               printf(" %u%%", IEEE80211_NODEREQ_RSSI(&nr));
-                       else
-                               printf(" %ddBm", nr.nr_rssi);
+               if (ioctl(s, SIOCG80211NODE, &nr) == 0) {
+                       if (nr.nr_rssi) {
+                               if (nr.nr_max_rssi)
+                                       printf(" %u%%",
+                                           IEEE80211_NODEREQ_RSSI(&nr));
+                               else
+                                       printf(" %ddBm", nr.nr_rssi);
+                       }
+                       assocfail = nr.nr_assoc_fail;
                }
        }
 
@@ -2478,6 +2497,11 @@ ieee80211_status(void)
                putchar(' ');
                printb_status(ifr.ifr_flags, IEEE80211_F_USERBITS);
        }
+
+       if (assocfail) {
+               putchar(' ');
+               print_assoc_failures(assocfail);
+       }
        putchar('\n');
        if (show_join)
                join_status();
@@ -2751,6 +2775,8 @@ ieee80211_printnode(struct ieee80211_nodereq *nr)
        if ((nr->nr_flags & IEEE80211_NODEREQ_AP) == 0)
                printb_status(IEEE80211_NODEREQ_STATE(nr->nr_state),
                    IEEE80211_NODEREQ_STATE_BITS);
+       else if (nr->nr_assoc_fail)
+               print_assoc_failures(nr->nr_assoc_fail);
 }
 
 void
blob - 425ee5f5a726e3fe0445c82debb0469d4878407f
blob + 6b3b8a5834db39d5b2f2dc7693f42d0b5adbcfbb
--- sys/net80211/ieee80211_ioctl.c
+++ sys/net80211/ieee80211_ioctl.c
@@ -104,6 +104,7 @@ ieee80211_node2req(struct ieee80211com *ic, const stru
        nr->nr_txseq = ni->ni_txseq;
        nr->nr_rxseq = ni->ni_rxseq;
        nr->nr_fails = ni->ni_fails;
+       nr->nr_assoc_fail = ni->ni_assoc_fail; /* flag values are the same */
        nr->nr_inact = ni->ni_inact;
        nr->nr_txrate = ni->ni_txrate;
        nr->nr_state = ni->ni_state;
@@ -821,7 +822,11 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t
                break;
        case SIOCG80211NODE:
                nr = (struct ieee80211_nodereq *)data;
-               ni = ieee80211_find_node(ic, nr->nr_macaddr);
+               if (ic->ic_bss &&
+                   IEEE80211_ADDR_EQ(nr->nr_macaddr, ic->ic_bss->ni_macaddr))
+                       ni = ic->ic_bss;
+               else
+                       ni = ieee80211_find_node(ic, nr->nr_macaddr);
                if (ni == NULL) {
                        error = ENOENT;
                        break;
blob - 575a573d2e21e9863bdab5276471f32fd189cc57
blob + 6a53566afc4594afeecf9834055f31af3d021b9f
--- sys/net80211/ieee80211_ioctl.h
+++ sys/net80211/ieee80211_ioctl.h
@@ -359,6 +359,8 @@ struct ieee80211_nodereq {
 
        /* VHT */
        uint8_t                 nr_vht_ss;
+
+       u_int32_t       nr_assoc_fail;  /* association failure reasons */
 };
 
 #define IEEE80211_NODEREQ_STATE(_s)    (1 << _s)
@@ -378,6 +380,18 @@ struct ieee80211_nodereq {
 #define SIOCG80211NODE         _IOWR('i', 211, struct ieee80211_nodereq)
 #define SIOCS80211NODE          _IOW('i', 212, struct ieee80211_nodereq)
 #define SIOCS80211DELNODE       _IOW('i', 213, struct ieee80211_nodereq)
+
+#define IEEE80211_NODEREQ_ASSOCFAIL_CHAN       0x01
+#define IEEE80211_NODEREQ_ASSOCFAIL_IBSS       0x02
+#define IEEE80211_NODEREQ_ASSOCFAIL_PRIVACY    0x04
+#define IEEE80211_NODEREQ_ASSOCFAIL_BASIC_RATE 0x08
+#define IEEE80211_NODEREQ_ASSOCFAIL_ESSID      0x10
+#define IEEE80211_NODEREQ_ASSOCFAIL_BSSID      0x20
+#define IEEE80211_NODEREQ_ASSOCFAIL_WPA_PROTO  0x40
+#define IEEE80211_NODEREQ_ASSOCFAIL_WPA_KEY    0x80
+#define IEEE80211_NODEREQ_ASSOCFAIL_BITS       \
+       "\20\1!CHAN\2!IBSS\3!PRIVACY\4!BASICRATE\5!ESSID\6!BSSID\7!WPAPROTO" \
+       "\10!WPAKEY"
 
 /* get the entire node cache */
 struct ieee80211_nodereq_all {
blob - 99b17a709fec1326d108be8e39ae8596f5b7f0f6
blob + 93238443fea9ca5f17d7f739617b295da5d1d3f7
--- sys/net80211/ieee80211_node.c
+++ sys/net80211/ieee80211_node.c
@@ -523,28 +523,40 @@ ieee80211_match_ess(struct ieee80211_ess *ess, struct 
 {
        if (ess->esslen != 0 &&
            (ess->esslen != ni->ni_esslen ||
-           memcmp(ess->essid, ni->ni_essid, ess->esslen) != 0))
+           memcmp(ess->essid, ni->ni_essid, ess->esslen) != 0)) {
+               ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_ESSID;
                return 0;
+       }
 
        if (ess->flags & (IEEE80211_F_PSK | IEEE80211_F_RSNON)) {
                /* Ensure same WPA version. */
                if ((ni->ni_rsnprotos & IEEE80211_PROTO_RSN) &&
-                   (ess->rsnprotos & IEEE80211_PROTO_RSN) == 0)
+                   (ess->rsnprotos & IEEE80211_PROTO_RSN) == 0) {
+                       ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
                        return 0;
+               }
                if ((ni->ni_rsnprotos & IEEE80211_PROTO_WPA) &&
-                   (ess->rsnprotos & IEEE80211_PROTO_WPA) == 0)
+                   (ess->rsnprotos & IEEE80211_PROTO_WPA) == 0) {
+                       ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
                        return 0;
+               }
        } else if (ess->flags & IEEE80211_F_WEPON) {
-               if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
+               if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) {
+                       ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_PRIVACY;
                        return 0;
+               }
        } else {
-               if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) != 0)
+               if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) != 0) {
+                       ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_PRIVACY;
                        return 0;
+               }
        }
 
        if (ess->esslen == 0 &&
-           (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) != 0)
+           (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) != 0) {
+               ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_PRIVACY;
                return 0;
+       }
 
        return 1;
 }
@@ -780,7 +792,7 @@ ieee80211_reset_scan(struct ifnet *ifp)
 }
 
 /*
- * Increase a node's inactitivy counter.
+ * Increase a node's inactivity counter.
  * This counter get reset to zero if a frame is received.
  * This function is intended for station mode only.
  * See ieee80211_node_cache_timeout() for hostap mode.
@@ -993,48 +1005,49 @@ ieee80211_create_ibss(struct ieee80211com* ic, struct 
 #endif /* IEEE80211_STA_ONLY */
 
 int
-ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni)
+ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni,
+    int bgscan)
 {
        u_int8_t rate;
        int fail;
 
        fail = 0;
        if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
-               fail |= 0x01;
+               fail |= IEEE80211_NODE_ASSOCFAIL_CHAN;
        if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
            ni->ni_chan != ic->ic_des_chan)
-               fail |= 0x01;
+               fail |= IEEE80211_NODE_ASSOCFAIL_CHAN;
 #ifndef IEEE80211_STA_ONLY
        if (ic->ic_opmode == IEEE80211_M_IBSS) {
                if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
-                       fail |= 0x02;
+                       fail |= IEEE80211_NODE_ASSOCFAIL_IBSS;
        } else
 #endif
        {
                if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
-                       fail |= 0x02;
+                       fail |= IEEE80211_NODE_ASSOCFAIL_IBSS;
        }
        if (ic->ic_flags & (IEEE80211_F_WEPON | IEEE80211_F_RSNON)) {
                if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
-                       fail |= 0x04;
+                       fail |= IEEE80211_NODE_ASSOCFAIL_PRIVACY;
        } else {
                if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
-                       fail |= 0x04;
+                       fail |= IEEE80211_NODE_ASSOCFAIL_PRIVACY;
        }
 
        rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DONEGO);
        if (rate & IEEE80211_RATE_BASIC)
-               fail |= 0x08;
+               fail |= IEEE80211_NODE_ASSOCFAIL_BASIC_RATE;
        if (ISSET(ic->ic_flags, IEEE80211_F_AUTO_JOIN) &&
            ic->ic_des_esslen == 0)
-               fail |= 0x10;
+               fail |= IEEE80211_NODE_ASSOCFAIL_ESSID;
        if (ic->ic_des_esslen != 0 &&
            (ni->ni_esslen != ic->ic_des_esslen ||
             memcmp(ni->ni_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0))
-               fail |= 0x10;
+               fail |= IEEE80211_NODE_ASSOCFAIL_ESSID;
        if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
            !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid))
-               fail |= 0x20;
+               fail |= IEEE80211_NODE_ASSOCFAIL_BSSID;
 
        if (ic->ic_flags & IEEE80211_F_RSNON) {
                /*
@@ -1043,66 +1056,76 @@ ieee80211_match_bss(struct ieee80211com *ic, struct ie
                 * decline to associate with that AP.
                 */
                if ((ni->ni_rsnprotos & ic->ic_rsnprotos) == 0)
-                       fail |= 0x40;
+                       fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
                if ((ni->ni_rsnakms & ic->ic_rsnakms) == 0)
-                       fail |= 0x40;
+                       fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
                if ((ni->ni_rsnakms & ic->ic_rsnakms &
                     ~(IEEE80211_AKM_PSK | IEEE80211_AKM_SHA256_PSK)) == 0) {
                        /* AP only supports PSK AKMPs */
                        if (!(ic->ic_flags & IEEE80211_F_PSK))
-                               fail |= 0x40;
+                               fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
                }
                if (ni->ni_rsngroupcipher != IEEE80211_CIPHER_WEP40 &&
                    ni->ni_rsngroupcipher != IEEE80211_CIPHER_TKIP &&
                    ni->ni_rsngroupcipher != IEEE80211_CIPHER_CCMP &&
                    ni->ni_rsngroupcipher != IEEE80211_CIPHER_WEP104)
-                       fail |= 0x40;
+                       fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
                if ((ni->ni_rsnciphers & ic->ic_rsnciphers) == 0)
-                       fail |= 0x40;
+                       fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
 
                /* we only support BIP as the IGTK cipher */
                if ((ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC) &&
                    ni->ni_rsngroupmgmtcipher != IEEE80211_CIPHER_BIP)
-                       fail |= 0x40;
+                       fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
 
                /* we do not support MFP but AP requires it */
                if (!(ic->ic_caps & IEEE80211_C_MFP) &&
                    (ni->ni_rsncaps & IEEE80211_RSNCAP_MFPR))
-                       fail |= 0x40;
+                       fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
 
                /* we require MFP but AP does not support it */
                if ((ic->ic_caps & IEEE80211_C_MFP) &&
                    (ic->ic_flags & IEEE80211_F_MFPR) &&
                    !(ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC))
-                       fail |= 0x40;
+                       fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO;
        }
 
        if (ic->ic_if.if_flags & IFF_DEBUG) {
                printf("%s: %c %s%c", ic->ic_if.if_xname, fail ? '-' : '+',
                    ether_sprintf(ni->ni_bssid),
-                   fail & 0x20 ? '!' : ' ');
+                   fail & IEEE80211_NODE_ASSOCFAIL_BSSID ? '!' : ' ');
                printf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan),
-                       fail & 0x01 ? '!' : ' ');
+                       fail & IEEE80211_NODE_ASSOCFAIL_CHAN ? '!' : ' ');
                printf(" %+4d", ni->ni_rssi);
                printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2,
-                   fail & 0x08 ? '!' : ' ');
+                   fail & IEEE80211_NODE_ASSOCFAIL_BASIC_RATE ? '!' : ' ');
                printf(" %4s%c",
                    (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
                    (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
                    "????",
-                   fail & 0x02 ? '!' : ' ');
+                   fail & IEEE80211_NODE_ASSOCFAIL_IBSS ? '!' : ' ');
                printf(" %7s%c ",
                    (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ?
                    "privacy" : "no",
-                   fail & 0x04 ? '!' : ' ');
+                   fail & IEEE80211_NODE_ASSOCFAIL_PRIVACY ? '!' : ' ');
                printf(" %3s%c ",
                    (ic->ic_flags & IEEE80211_F_RSNON) ?
                    "rsn" : "no",
-                   fail & 0x40 ? '!' : ' ');
+                   fail & IEEE80211_NODE_ASSOCFAIL_WPA_PROTO ? '!' : ' ');
                ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
-               printf("%s\n", fail & 0x10 ? "!" : "");
+               printf("%s\n",
+                   fail & IEEE80211_NODE_ASSOCFAIL_ESSID ? "!" : "");
        }
 
+       /* We don't care about unrelated networks during background scans. */
+       if (bgscan) {
+               if ((fail & IEEE80211_NODE_ASSOCFAIL_ESSID) == 0)
+                       ni->ni_assoc_fail = fail;
+       } else
+               ni->ni_assoc_fail = fail;
+       if ((fail & IEEE80211_NODE_ASSOCFAIL_ESSID) == 0)
+               ic->ic_bss->ni_assoc_fail = ni->ni_assoc_fail;
+
        return fail;
 }
 
@@ -1160,15 +1183,25 @@ ieee80211_node_join_bss(struct ieee80211com *ic, struc
 {
        enum ieee80211_phymode mode;
        struct ieee80211_node *ni;
+       uint32_t assoc_fail = 0;
 
        /* Reinitialize media mode and channels if needed. */
        mode = ieee80211_chan2mode(ic, selbs->ni_chan);
        if (mode != ic->ic_curmode)
                ieee80211_setmode(ic, mode);
 
+       /* Keep recorded association failures for this BSS/ESS intact. */
+       if (IEEE80211_ADDR_EQ(ic->ic_bss->ni_macaddr, selbs->ni_macaddr) ||
+           (ic->ic_des_esslen > 0 && ic->ic_des_esslen == selbs->ni_esslen &&
+           memcmp(ic->ic_des_essid, selbs->ni_essid, selbs->ni_esslen) == 0))
+               assoc_fail = ic->ic_bss->ni_assoc_fail;
+
        (*ic->ic_node_copy)(ic, ic->ic_bss, selbs);
        ni = ic->ic_bss;
+       ni->ni_assoc_fail |= assoc_fail;
 
+       ic->ic_curmode = ieee80211_chan2mode(ic, ni->ni_chan);
+
        /* Make sure we send valid rates in an association request. */
        if (ic->ic_opmode == IEEE80211_M_STA)
                ieee80211_fix_rate(ic, ni,
@@ -1249,7 +1282,7 @@ ieee80211_node_choose_bss(struct ieee80211com *ic, int
                if (curbs && ieee80211_node_cmp(ic->ic_bss, ni) == 0)
                        *curbs = ni;
 
-               if (ieee80211_match_bss(ic, ni) != 0)
+               if (ieee80211_match_bss(ic, ni, bgscan) != 0)
                        continue;
 
                if (ic->ic_caps & IEEE80211_C_SCANALLBAND) {
@@ -2822,7 +2855,7 @@ ieee80211_ibss_merge(struct ieee80211com *ic, struct i
        if (sign < 0)
                return 0;
 
-       if (ieee80211_match_bss(ic, ni) != 0)
+       if (ieee80211_match_bss(ic, ni, 0) != 0)
                return 0;
 
        if (ieee80211_do_slow_print(ic, &did_print)) {
blob - b2b80656a4b4aa907b4d729ecaecb81827739c52
blob + 081e0eee78221d039ff3a9811598333b3a83deff
--- sys/net80211/ieee80211_node.h
+++ sys/net80211/ieee80211_node.h
@@ -353,6 +353,16 @@ struct ieee80211_node {
        u_int16_t               ni_qos_txseqs[IEEE80211_NUM_TID];
        u_int16_t               ni_qos_rxseqs[IEEE80211_NUM_TID];
        int                     ni_fails;       /* failure count to associate */
+       uint32_t                ni_assoc_fail;  /* assoc failure reasons */
+#define IEEE80211_NODE_ASSOCFAIL_CHAN          0x01
+#define IEEE80211_NODE_ASSOCFAIL_IBSS          0x02
+#define IEEE80211_NODE_ASSOCFAIL_PRIVACY       0x04
+#define IEEE80211_NODE_ASSOCFAIL_BASIC_RATE    0x08
+#define IEEE80211_NODE_ASSOCFAIL_ESSID         0x10
+#define IEEE80211_NODE_ASSOCFAIL_BSSID         0x20
+#define IEEE80211_NODE_ASSOCFAIL_WPA_PROTO     0x40
+#define IEEE80211_NODE_ASSOCFAIL_WPA_KEY       0x80
+
        int                     ni_inact;       /* inactivity mark count */
        int                     ni_txrate;      /* index to ni_rates[] */
        int                     ni_state;
@@ -515,8 +525,7 @@ void ieee80211_node_join(struct ieee80211com *,
                struct ieee80211_node *, int);
 void ieee80211_node_leave(struct ieee80211com *,
                struct ieee80211_node *);
-int ieee80211_match_bss(struct ieee80211com *,
-               struct ieee80211_node *);
+int ieee80211_match_bss(struct ieee80211com *, struct ieee80211_node *, int);
 struct ieee80211_node *ieee80211_node_choose_bss(struct ieee80211com *, int,
                struct ieee80211_node **);
 void ieee80211_node_join_bss(struct ieee80211com *, struct ieee80211_node *);
blob - ba8c1872a2df596a0667ecb7c306f7e7f9dd0ffc
blob + 3ab5bacb42d9990898dd11db2e74a29ad3330b53
--- sys/net80211/ieee80211_pae_input.c
+++ sys/net80211/ieee80211_pae_input.c
@@ -650,6 +650,7 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic,
                            ether_sprintf(ni->ni_macaddr)));
                        ni->ni_port_valid = 1;
                        ieee80211_set_link_state(ic, LINK_STATE_UP);
+                       ni->ni_assoc_fail = 0;
                }
        }
  deauth:
@@ -915,6 +916,7 @@ ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic,
                            ether_sprintf(ni->ni_macaddr)));
                        ni->ni_port_valid = 1;
                        ieee80211_set_link_state(ic, LINK_STATE_UP);
+                       ni->ni_assoc_fail = 0;
                }
        }
        /* update the last seen value of the key replay counter field */
@@ -1019,6 +1021,7 @@ ieee80211_recv_wpa_group_msg1(struct ieee80211com *ic,
                            ether_sprintf(ni->ni_macaddr)));
                        ni->ni_port_valid = 1;
                        ieee80211_set_link_state(ic, LINK_STATE_UP);
+                       ni->ni_assoc_fail = 0;
                }
        }
        /* update the last seen value of the key replay counter field */
blob - 30c784c7b2f404dcdb35d37a8b1b29928f628184
blob + e359910007ce2e4429dfe86b78fcd3afdba73a88
--- sys/net80211/ieee80211_proto.c
+++ sys/net80211/ieee80211_proto.c
@@ -939,6 +939,33 @@ ieee80211_stop_ampdu_tx(struct ieee80211com *ic, struc
        }
 }
 
+void
+ieee80211_check_wpa_supplicant_failure(struct ieee80211com *ic,
+    struct ieee80211_node *ni)
+{
+       struct ieee80211_node *ni2;
+
+       if (ic->ic_opmode != IEEE80211_M_STA
+#ifndef IEEE80211_STA_ONLY
+           && ic->ic_opmode != IEEE80211_M_IBSS
+#endif
+           )
+               return;
+
+       if (ni->ni_rsn_supp_state != RSNA_SUPP_PTKNEGOTIATING)
+               return;
+
+       ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_WPA_KEY;
+
+       if (ni != ic->ic_bss)
+               return;
+
+       /* Also update the copy of our AP's node in the node cache. */
+       ni2 = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr);
+       if (ni2)
+               ni2->ni_assoc_fail |= ic->ic_bss->ni_assoc_fail;
+}
+
 int
 ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate,
     int mgt)
@@ -1037,6 +1064,7 @@ justcleanup:
                        break;
                }
                ni->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE;
+               ni->ni_assoc_fail = 0;
                if (ic->ic_flags & IEEE80211_F_RSNON)
                        ieee80211_crypto_clear_groupkeys(ic);
                break;
@@ -1097,6 +1125,8 @@ justcleanup:
                }
                break;
        case IEEE80211_S_AUTH:
+               if (ostate == IEEE80211_S_RUN)
+                       ieee80211_check_wpa_supplicant_failure(ic, ni);
                ni->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE;
                if (ic->ic_flags & IEEE80211_F_RSNON)
                        ieee80211_crypto_clear_groupkeys(ic);
@@ -1218,6 +1248,7 @@ justcleanup:
                                 * the link up until the port is valid.
                                 */
                                ieee80211_set_link_state(ic, LINK_STATE_UP);
+                               ni->ni_assoc_fail = 0;
                        }
                        ic->ic_mgt_timer = 0;
                        ieee80211_set_beacon_miss_threshold(ic);

Reply via email to