I find myself regularly asking people to run 'ifconfig iwm0 debug' to
figure out reasons behind association failures from dmesg output.

I would like to make this information more accessible. Making it part
of regular ifconfig output seems like a reasonable thing to do. This
becomes possible now that node information is cached across scans.

The current net80211 code is already computing failure reason codes which
are visible in 'ifconfig debug' output. So far such codes were magic numbers.
We can simply create macros for them and expose them in ieee80211_ioctl.h,
and add another code to represent the "wrong-WPA-key" situation.

To avoid changing the existing ifconfig output too much, the following
association failure reasons are not displayed:

 - wrong SSID
 - open vs. encrypted network

(They remain available at the ioctl layer which could be useful for
third-party wifi tools in the ports tree.)

I have never heard from people having problems figuring out the above
two failure cases so I don't think it's worth adding them to virtually
every line of 'ifconfig scan' output.

However, the following cases are causing regular cries for help:

- wrong WPA protocol version (number 1 reason for cries for help)
- wrong WPA key
- user forgets about previously hard-coded channel
- user forgets about previously hard-coded BSSID

And, of course, any of these problems can occur in combination.

With the diff below, ifconfig output in such situations looks as follows:

# ifconfig iwm0 nwid stsp.name wpakey wrong-key

Now ifconfig iwm0 scan indicates wrong WPA key after a failed WPA handshake:

  nwid stsp.name chan 52 bssid 28:af:44:01:4f:38 71% HT-MCS15 
privacy,short_slottime,wpa2 !(wpakey)

(Configure AP to run WPA1 only.)
# ifconfig iwm0 nwid stsp.name wpakey correct-key

ifconfig iwm0 scan indicates wrong WPA protocol version:

  nwid stsp.name chan 52 bssid 28:af:44:01:4f:38 52% HT-MCS15 
privacy,short_slottime,wpa1 !(wpaproto)

(user hard-codes the channel)
# ifconfig iwm0 chan 36

Now ifconfig iwm0 scan indicates WPA1-only AP on wrong channel:

  nwid stsp.name chan 52 bssid 28:af:44:01:4f:38 79% HT-MCS15 
privacy,short_slottime,wpa1 !(chan,wpaproto)

(user hard-codes BSSID)
WPA1-only AP on wrong channel with wrong BSSID:
# ifconfig iwm0 bssid 00:1c:c2:08:c6:65

now ifconfig iwm0 scan indicates WPA1-only AP, wrong channel, and wrong BSSID:

  nwid stsp.name chan 52 bssid 28:af:44:01:4f:38 56% HT-MCS15 
privacy,short_slottime,wpa1 !(chan,bssid,wpaproto)


Is this going in the right direction?

There are no man page changes yet but the various reason failure codes
would have to be properly documented, of course.

To test the diff below, recompile the patched kernel, install the patched
ieee80211_ioctl.h header (e.g. via 'make includes'), and recompile ifconfig.
If ifconfig displays garbage with this patch applied, your kernel and
ifconfig binary are out of sync.

diff refs/heads/master refs/heads/assocfail
blob - 543e09f0d6e6b4e75456a21d4218468729b61a5e
blob + 03e4818ef5fa11d7e5dbf8307affb9f0ea5522a0
--- sbin/ifconfig/ifconfig.c
+++ sbin/ifconfig/ifconfig.c
@@ -2348,10 +2348,27 @@ print_cipherset(u_int32_t cipherset)
 }
 
 void
+print_assoc_failures(uint32_t assoc_fail, const char *intro, const char *outro)
+{
+       /* 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;
+
+       printf("%s", intro);
+       printb_status(assoc_fail, IEEE80211_NODEREQ_ASSOCFAIL_BITS);
+       printf("%s", outro);
+}
+
+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 +2448,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 +2499,10 @@ ieee80211_status(void)
                putchar(' ');
                printb_status(ifr.ifr_flags, IEEE80211_F_USERBITS);
        }
+
+       if (assocfail)
+               print_assoc_failures(assocfail, " !(", ")");
+
        putchar('\n');
        if (show_join)
                join_status();
@@ -2751,6 +2776,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 + 4b5b8cb5d273de964469fcffb03532c349ecca84
--- 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,17 @@ 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\1CHAN\2IBSS\3PRIVACY\4BASICRATE\5ESSID\6BSSID\7WPAPROTO\10WPAKEY"
 
 /* get the entire node cache */
 struct ieee80211_nodereq_all {
blob - 99b17a709fec1326d108be8e39ae8596f5b7f0f6
blob + ac031edda4662154bf384a3bd6d722c72547f136
--- 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.
@@ -1000,41 +1012,41 @@ ieee80211_match_bss(struct ieee80211com *ic, struct ie
 
        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 +1055,71 @@ 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 ? "!" : "");
        }
 
+       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,14 +1177,24 @@ 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)
blob - b2b80656a4b4aa907b4d729ecaecb81827739c52
blob + ddd746729a48b15fa3c21d85390682263d2934d9
--- 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;
blob - ba8c1872a2df596a0667ecb7c306f7e7f9dd0ffc
blob + daf43cd6457134728ce5dd485229036ea4822445
--- 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:
blob - 30c784c7b2f404dcdb35d37a8b1b29928f628184
blob + 5ab07bfe2215a99449a86e073bc474ed238ae6b3
--- sys/net80211/ieee80211_proto.c
+++ sys/net80211/ieee80211_proto.c
@@ -939,6 +939,30 @@ 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 &&
+           ic->ic_opmode != IEEE80211_M_IBSS)
+               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 +1061,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 +1122,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 +1245,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