mac80211: 802.11w - Implement Association Comeback processing
authorJouni Malinen <j@w1.fi>
Thu, 8 Jan 2009 11:32:09 +0000 (13:32 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 29 Jan 2009 21:00:07 +0000 (16:00 -0500)
When MFP is enabled, the AP does not allow a STA to associate if an
existing security association exists without first going through SA
Query process. When this happens, the association request is denied
with a new status code ("temporarily rejected") ans Association
Comeback IE is used to notify when the association may be tried again
(i.e., when the SA Query procedure has timed out).

Use the comeback time to update the mac80211 client MLME timer for
next association attempt to minimize waiting time if association is
temporarily rejected.

Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
include/linux/ieee80211.h
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c
net/mac80211/util.c

index 9fe1948d28d3906b252668a67dc0328740dc0243..7800e20f197f32f847589b69cbba46e011a03bca 100644 (file)
@@ -914,6 +914,9 @@ enum ieee80211_statuscode {
        /* 802.11g */
        WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25,
        WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26,
+       /* 802.11w */
+       WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY = 30,
+       WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION = 31,
        /* 802.11i */
        WLAN_STATUS_INVALID_IE = 40,
        WLAN_STATUS_INVALID_GROUP_CIPHER = 41,
@@ -1034,6 +1037,7 @@ enum ieee80211_eid {
        /* 802.11i */
        WLAN_EID_RSN = 48,
        WLAN_EID_MMIE = 76 /* 802.11w */,
+       WLAN_EID_ASSOC_COMEBACK_TIME = 77,
        WLAN_EID_WPA = 221,
        WLAN_EID_GENERIC = 221,
        WLAN_EID_VENDOR_SPECIFIC = 221,
index 212c732fbba7acd8f5615069552abbabde710514..9112c5247c356477c03d54a683d61ecfb265ddce 100644 (file)
@@ -820,6 +820,7 @@ struct ieee802_11_elems {
        u8 *country_elem;
        u8 *pwr_constr_elem;
        u8 *quiet_elem;         /* first quite element */
+       u8 *assoc_comeback;
 
        /* length of them, respectively */
        u8 ssid_len;
@@ -847,6 +848,7 @@ struct ieee802_11_elems {
        u8 pwr_constr_elem_len;
        u8 quiet_elem_len;
        u8 num_of_quiet_elem;   /* can be more the one */
+       u8 assoc_comeback_len;
 };
 
 static inline struct ieee80211_local *hw_to_local(
index 42c5f981c715f7c28f3196d5849cdb9666ff63ce..82c598a83687cb8f241fbb875dff27294b2a536c 100644 (file)
@@ -1275,6 +1275,23 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
               sdata->dev->name, reassoc ? "Rea" : "A", mgmt->sa,
               capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
 
+       pos = mgmt->u.assoc_resp.variable;
+       ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
+
+       if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
+           elems.assoc_comeback && elems.assoc_comeback_len == 4) {
+               u32 tu, ms;
+               tu = get_unaligned_le32(elems.assoc_comeback);
+               ms = tu * 1024 / 1000;
+               printk(KERN_DEBUG "%s: AP rejected association temporarily; "
+                      "comeback duration %u TU (%u ms)\n",
+                      sdata->dev->name, tu, ms);
+               if (ms > IEEE80211_ASSOC_TIMEOUT)
+                       mod_timer(&ifsta->timer,
+                                 jiffies + msecs_to_jiffies(ms));
+               return;
+       }
+
        if (status_code != WLAN_STATUS_SUCCESS) {
                printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
                       sdata->dev->name, status_code);
@@ -1290,9 +1307,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                       "set\n", sdata->dev->name, aid);
        aid &= ~(BIT(15) | BIT(14));
 
-       pos = mgmt->u.assoc_resp.variable;
-       ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
-
        if (!elems.supp_rates) {
                printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
                       sdata->dev->name);
index 5cd430333f08651920bb411703f3dde0b8ef8d70..963e0473205c21f179241732cb23325191528fbd 100644 (file)
@@ -653,6 +653,10 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
                        elems->pwr_constr_elem = pos;
                        elems->pwr_constr_elem_len = elen;
                        break;
+               case WLAN_EID_ASSOC_COMEBACK_TIME:
+                       elems->assoc_comeback = pos;
+                       elems->assoc_comeback_len = elen;
+                       break;
                default:
                        break;
                }