aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/linux/ieee80211.h4
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/mlme.c20
-rw-r--r--net/mac80211/util.c4
4 files changed, 27 insertions, 3 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 9fe1948d28d..7800e20f197 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -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,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 212c732fbba..9112c5247c3 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -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(
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 42c5f981c71..82c598a8368 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -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);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 5cd430333f0..963e0473205 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -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;
}