aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r--net/mac80211/util.c80
1 files changed, 65 insertions, 15 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 9919892575f4..32f7a3b3d43c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -572,24 +572,40 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
size_t left = len;
u8 *pos = start;
bool calc_crc = filter != 0;
+ DECLARE_BITMAP(seen_elems, 256);
+ bitmap_zero(seen_elems, 256);
memset(elems, 0, sizeof(*elems));
elems->ie_start = start;
elems->total_len = len;
while (left >= 2) {
u8 id, elen;
+ bool elem_parse_failed;
id = *pos++;
elen = *pos++;
left -= 2;
- if (elen > left)
+ if (elen > left) {
+ elems->parse_error = true;
break;
+ }
+
+ if (id != WLAN_EID_VENDOR_SPECIFIC &&
+ id != WLAN_EID_QUIET &&
+ test_bit(id, seen_elems)) {
+ elems->parse_error = true;
+ left -= elen;
+ pos += elen;
+ continue;
+ }
if (calc_crc && id < 64 && (filter & (1ULL << id)))
crc = crc32_be(crc, pos - 2, elen + 2);
+ elem_parse_failed = false;
+
switch (id) {
case WLAN_EID_SSID:
elems->ssid = pos;
@@ -615,7 +631,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
if (elen >= sizeof(struct ieee80211_tim_ie)) {
elems->tim = (void *)pos;
elems->tim_len = elen;
- }
+ } else
+ elem_parse_failed = true;
break;
case WLAN_EID_IBSS_PARAMS:
elems->ibss_params = pos;
@@ -664,10 +681,14 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
case WLAN_EID_HT_CAPABILITY:
if (elen >= sizeof(struct ieee80211_ht_cap))
elems->ht_cap_elem = (void *)pos;
+ else
+ elem_parse_failed = true;
break;
case WLAN_EID_HT_INFORMATION:
if (elen >= sizeof(struct ieee80211_ht_info))
elems->ht_info_elem = (void *)pos;
+ else
+ elem_parse_failed = true;
break;
case WLAN_EID_MESH_ID:
elems->mesh_id = pos;
@@ -676,6 +697,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
case WLAN_EID_MESH_CONFIG:
if (elen >= sizeof(struct ieee80211_meshconf_ie))
elems->mesh_config = (void *)pos;
+ else
+ elem_parse_failed = true;
break;
case WLAN_EID_PEER_MGMT:
elems->peering = pos;
@@ -696,6 +719,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
case WLAN_EID_RANN:
if (elen >= sizeof(struct ieee80211_rann_ie))
elems->rann = (void *)pos;
+ else
+ elem_parse_failed = true;
break;
case WLAN_EID_CHANNEL_SWITCH:
elems->ch_switch_elem = pos;
@@ -724,10 +749,18 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
break;
}
+ if (elem_parse_failed)
+ elems->parse_error = true;
+ else
+ set_bit(id, seen_elems);
+
left -= elen;
pos += elen;
}
+ if (left != 0)
+ elems->parse_error = true;
+
return crc;
}
@@ -737,7 +770,8 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
ieee802_11_parse_elems_crc(start, len, elems, 0, 0);
}
-void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
+void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
+ bool bss_notify)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_queue_params qparam;
@@ -753,7 +787,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
!(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
- for (queue = 0; queue < local_to_hw(local)->queues; queue++) {
+ for (queue = 0; queue < local->hw.queues; queue++) {
/* Set defaults according to 802.11-2007 Table 7-37 */
aCWmax = 1023;
if (use_11b)
@@ -807,7 +841,9 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
sdata->vif.bss_conf.qos =
sdata->vif.type != NL80211_IFTYPE_STATION;
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
+ if (bss_notify)
+ ieee80211_bss_info_change_notify(sdata,
+ BSS_CHANGED_QOS);
}
}
@@ -829,7 +865,7 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
else
sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
- ieee80211_set_wmm_default(sdata);
+ ieee80211_set_wmm_default(sdata, true);
}
u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
@@ -862,8 +898,8 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg,
- u8 *extra, size_t extra_len, const u8 *bssid,
- const u8 *key, u8 key_len, u8 key_idx)
+ u8 *extra, size_t extra_len, const u8 *da,
+ const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx)
{
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
@@ -881,7 +917,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
memset(mgmt, 0, 24 + 6);
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_AUTH);
- memcpy(mgmt->da, bssid, ETH_ALEN);
+ memcpy(mgmt->da, da, ETH_ALEN);
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
memcpy(mgmt->bssid, bssid, ETH_ALEN);
mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);
@@ -1185,13 +1221,12 @@ int ieee80211_reconfig(struct ieee80211_local *local)
mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list) {
if (sta->uploaded) {
- sdata = sta->sdata;
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- sdata = container_of(sdata->bss,
- struct ieee80211_sub_if_data,
- u.ap);
+ enum ieee80211_sta_state state;
- WARN_ON(drv_sta_add(local, sdata, &sta->sta));
+ for (state = IEEE80211_STA_NOTEXIST;
+ state < sta->sta_state - 1; state++)
+ WARN_ON(drv_sta_state(local, sta->sdata, sta,
+ state, state + 1));
}
}
mutex_unlock(&local->sta_mtx);
@@ -1272,6 +1307,21 @@ int ieee80211_reconfig(struct ieee80211_local *local)
ieee80211_recalc_ps(local, -1);
/*
+ * The sta might be in psm against the ap (e.g. because
+ * this was the state before a hw restart), so we
+ * explicitly send a null packet in order to make sure
+ * it'll sync against the ap (and get out of psm).
+ */
+ if (!(local->hw.conf.flags & IEEE80211_CONF_PS)) {
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ continue;
+
+ ieee80211_send_nullfunc(local, sdata, 0);
+ }
+ }
+
+ /*
* Clear the WLAN_STA_BLOCK_BA flag so new aggregation
* sessions can be established after a resume.
*