diff options
author | John W. Linville <linville@tuxdriver.com> | 2014-07-22 13:49:34 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-07-22 13:49:34 -0400 |
commit | a006827a152c3f4d09324157096c8f89cf7ddca3 (patch) | |
tree | 3590601aa271f8def4ef6fdc701eb0004a05f925 /net | |
parent | 1d9e954e8b522ae37c7c0fdd791b5736321684a0 (diff) | |
parent | 08cf42e843f9a7e253502011c81677f61f7e5c42 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/agg-rx.c | 110 | ||||
-rw-r--r-- | net/mac80211/chan.c | 2 | ||||
-rw-r--r-- | net/mac80211/ht.c | 10 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 13 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 34 | ||||
-rw-r--r-- | net/mac80211/iface.c | 31 | ||||
-rw-r--r-- | net/mac80211/key.c | 3 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 22 | ||||
-rw-r--r-- | net/mac80211/rx.c | 65 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 8 | ||||
-rw-r--r-- | net/mac80211/tdls.c | 459 | ||||
-rw-r--r-- | net/mac80211/util.c | 15 | ||||
-rw-r--r-- | net/mac80211/vht.c | 4 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 2 | ||||
-rw-r--r-- | net/wireless/Kconfig | 6 | ||||
-rw-r--r-- | net/wireless/genregdb.awk | 35 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 3 |
17 files changed, 653 insertions, 169 deletions
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 31bf2586fb84..f0e84bc48038 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -52,7 +52,7 @@ static void ieee80211_free_tid_rx(struct rcu_head *h) | |||
52 | del_timer_sync(&tid_rx->reorder_timer); | 52 | del_timer_sync(&tid_rx->reorder_timer); |
53 | 53 | ||
54 | for (i = 0; i < tid_rx->buf_size; i++) | 54 | for (i = 0; i < tid_rx->buf_size; i++) |
55 | dev_kfree_skb(tid_rx->reorder_buf[i]); | 55 | __skb_queue_purge(&tid_rx->reorder_buf[i]); |
56 | kfree(tid_rx->reorder_buf); | 56 | kfree(tid_rx->reorder_buf); |
57 | kfree(tid_rx->reorder_time); | 57 | kfree(tid_rx->reorder_time); |
58 | kfree(tid_rx); | 58 | kfree(tid_rx); |
@@ -224,28 +224,15 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d | |||
224 | ieee80211_tx_skb(sdata, skb); | 224 | ieee80211_tx_skb(sdata, skb); |
225 | } | 225 | } |
226 | 226 | ||
227 | void ieee80211_process_addba_request(struct ieee80211_local *local, | 227 | void __ieee80211_start_rx_ba_session(struct sta_info *sta, |
228 | struct sta_info *sta, | 228 | u8 dialog_token, u16 timeout, |
229 | struct ieee80211_mgmt *mgmt, | 229 | u16 start_seq_num, u16 ba_policy, u16 tid, |
230 | size_t len) | 230 | u16 buf_size, bool tx) |
231 | { | 231 | { |
232 | struct ieee80211_local *local = sta->sdata->local; | ||
232 | struct tid_ampdu_rx *tid_agg_rx; | 233 | struct tid_ampdu_rx *tid_agg_rx; |
233 | u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; | 234 | int i, ret = -EOPNOTSUPP; |
234 | u8 dialog_token; | 235 | u16 status = WLAN_STATUS_REQUEST_DECLINED; |
235 | int ret = -EOPNOTSUPP; | ||
236 | |||
237 | /* extract session parameters from addba request frame */ | ||
238 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; | ||
239 | timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); | ||
240 | start_seq_num = | ||
241 | le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; | ||
242 | |||
243 | capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); | ||
244 | ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; | ||
245 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | ||
246 | buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; | ||
247 | |||
248 | status = WLAN_STATUS_REQUEST_DECLINED; | ||
249 | 236 | ||
250 | if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { | 237 | if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { |
251 | ht_dbg(sta->sdata, | 238 | ht_dbg(sta->sdata, |
@@ -264,7 +251,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
264 | status = WLAN_STATUS_INVALID_QOS_PARAM; | 251 | status = WLAN_STATUS_INVALID_QOS_PARAM; |
265 | ht_dbg_ratelimited(sta->sdata, | 252 | ht_dbg_ratelimited(sta->sdata, |
266 | "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", | 253 | "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", |
267 | mgmt->sa, tid, ba_policy, buf_size); | 254 | sta->sta.addr, tid, ba_policy, buf_size); |
268 | goto end_no_lock; | 255 | goto end_no_lock; |
269 | } | 256 | } |
270 | /* determine default buffer size */ | 257 | /* determine default buffer size */ |
@@ -281,7 +268,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
281 | if (sta->ampdu_mlme.tid_rx[tid]) { | 268 | if (sta->ampdu_mlme.tid_rx[tid]) { |
282 | ht_dbg_ratelimited(sta->sdata, | 269 | ht_dbg_ratelimited(sta->sdata, |
283 | "unexpected AddBA Req from %pM on tid %u\n", | 270 | "unexpected AddBA Req from %pM on tid %u\n", |
284 | mgmt->sa, tid); | 271 | sta->sta.addr, tid); |
285 | 272 | ||
286 | /* delete existing Rx BA session on the same tid */ | 273 | /* delete existing Rx BA session on the same tid */ |
287 | ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, | 274 | ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, |
@@ -308,7 +295,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
308 | 295 | ||
309 | /* prepare reordering buffer */ | 296 | /* prepare reordering buffer */ |
310 | tid_agg_rx->reorder_buf = | 297 | tid_agg_rx->reorder_buf = |
311 | kcalloc(buf_size, sizeof(struct sk_buff *), GFP_KERNEL); | 298 | kcalloc(buf_size, sizeof(struct sk_buff_head), GFP_KERNEL); |
312 | tid_agg_rx->reorder_time = | 299 | tid_agg_rx->reorder_time = |
313 | kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL); | 300 | kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL); |
314 | if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) { | 301 | if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) { |
@@ -318,6 +305,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
318 | goto end; | 305 | goto end; |
319 | } | 306 | } |
320 | 307 | ||
308 | for (i = 0; i < buf_size; i++) | ||
309 | __skb_queue_head_init(&tid_agg_rx->reorder_buf[i]); | ||
310 | |||
321 | ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, | 311 | ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, |
322 | &sta->sta, tid, &start_seq_num, 0); | 312 | &sta->sta, tid, &start_seq_num, 0); |
323 | ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n", | 313 | ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n", |
@@ -350,6 +340,74 @@ end: | |||
350 | mutex_unlock(&sta->ampdu_mlme.mtx); | 340 | mutex_unlock(&sta->ampdu_mlme.mtx); |
351 | 341 | ||
352 | end_no_lock: | 342 | end_no_lock: |
353 | ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, | 343 | if (tx) |
354 | dialog_token, status, 1, buf_size, timeout); | 344 | ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, |
345 | dialog_token, status, 1, buf_size, | ||
346 | timeout); | ||
347 | } | ||
348 | |||
349 | void ieee80211_process_addba_request(struct ieee80211_local *local, | ||
350 | struct sta_info *sta, | ||
351 | struct ieee80211_mgmt *mgmt, | ||
352 | size_t len) | ||
353 | { | ||
354 | u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num; | ||
355 | u8 dialog_token; | ||
356 | |||
357 | /* extract session parameters from addba request frame */ | ||
358 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; | ||
359 | timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); | ||
360 | start_seq_num = | ||
361 | le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; | ||
362 | |||
363 | capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); | ||
364 | ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; | ||
365 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | ||
366 | buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; | ||
367 | |||
368 | __ieee80211_start_rx_ba_session(sta, dialog_token, timeout, | ||
369 | start_seq_num, ba_policy, tid, | ||
370 | buf_size, true); | ||
371 | } | ||
372 | |||
373 | void ieee80211_start_rx_ba_session_offl(struct ieee80211_vif *vif, | ||
374 | const u8 *addr, u16 tid) | ||
375 | { | ||
376 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
377 | struct ieee80211_local *local = sdata->local; | ||
378 | struct ieee80211_rx_agg *rx_agg; | ||
379 | struct sk_buff *skb = dev_alloc_skb(0); | ||
380 | |||
381 | if (unlikely(!skb)) | ||
382 | return; | ||
383 | |||
384 | rx_agg = (struct ieee80211_rx_agg *) &skb->cb; | ||
385 | memcpy(&rx_agg->addr, addr, ETH_ALEN); | ||
386 | rx_agg->tid = tid; | ||
387 | |||
388 | skb->pkt_type = IEEE80211_SDATA_QUEUE_RX_AGG_START; | ||
389 | skb_queue_tail(&sdata->skb_queue, skb); | ||
390 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
391 | } | ||
392 | EXPORT_SYMBOL(ieee80211_start_rx_ba_session_offl); | ||
393 | |||
394 | void ieee80211_stop_rx_ba_session_offl(struct ieee80211_vif *vif, | ||
395 | const u8 *addr, u16 tid) | ||
396 | { | ||
397 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
398 | struct ieee80211_local *local = sdata->local; | ||
399 | struct ieee80211_rx_agg *rx_agg; | ||
400 | struct sk_buff *skb = dev_alloc_skb(0); | ||
401 | |||
402 | if (unlikely(!skb)) | ||
403 | return; | ||
404 | |||
405 | rx_agg = (struct ieee80211_rx_agg *) &skb->cb; | ||
406 | memcpy(&rx_agg->addr, addr, ETH_ALEN); | ||
407 | rx_agg->tid = tid; | ||
408 | |||
409 | skb->pkt_type = IEEE80211_SDATA_QUEUE_RX_AGG_STOP; | ||
410 | skb_queue_tail(&sdata->skb_queue, skb); | ||
411 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
355 | } | 412 | } |
413 | EXPORT_SYMBOL(ieee80211_stop_rx_ba_session_offl); | ||
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index c3fd4d275bf4..6d537f03c0ba 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -66,7 +66,7 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local) | |||
66 | static struct ieee80211_chanctx * | 66 | static struct ieee80211_chanctx * |
67 | ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata) | 67 | ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata) |
68 | { | 68 | { |
69 | struct ieee80211_local *local = sdata->local; | 69 | struct ieee80211_local *local __maybe_unused = sdata->local; |
70 | struct ieee80211_chanctx_conf *conf; | 70 | struct ieee80211_chanctx_conf *conf; |
71 | 71 | ||
72 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | 72 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 15702ff64a4c..ff630be2ca75 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -150,13 +150,12 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
150 | 150 | ||
151 | /* | 151 | /* |
152 | * If user has specified capability over-rides, take care | 152 | * If user has specified capability over-rides, take care |
153 | * of that if the station we're setting up is the AP that | 153 | * of that if the station we're setting up is the AP or TDLS peer that |
154 | * we advertised a restricted capability set to. Override | 154 | * we advertised a restricted capability set to. Override |
155 | * our own capabilities and then use those below. | 155 | * our own capabilities and then use those below. |
156 | */ | 156 | */ |
157 | if ((sdata->vif.type == NL80211_IFTYPE_STATION || | 157 | if (sdata->vif.type == NL80211_IFTYPE_STATION || |
158 | sdata->vif.type == NL80211_IFTYPE_ADHOC) && | 158 | sdata->vif.type == NL80211_IFTYPE_ADHOC) |
159 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
160 | ieee80211_apply_htcap_overrides(sdata, &own_cap); | 159 | ieee80211_apply_htcap_overrides(sdata, &own_cap); |
161 | 160 | ||
162 | /* | 161 | /* |
@@ -228,6 +227,9 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
228 | if (own_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) | 227 | if (own_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) |
229 | ht_cap.mcs.rx_mask[32/8] |= 1; | 228 | ht_cap.mcs.rx_mask[32/8] |= 1; |
230 | 229 | ||
230 | /* set Rx highest rate */ | ||
231 | ht_cap.mcs.rx_highest = ht_cap_ie->mcs.rx_highest; | ||
232 | |||
231 | apply: | 233 | apply: |
232 | changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); | 234 | changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); |
233 | 235 | ||
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 713485f9effc..9713dc54ea4b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -189,17 +189,8 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, | |||
189 | chandef, 0); | 189 | chandef, 0); |
190 | } | 190 | } |
191 | 191 | ||
192 | if (local->hw.queues >= IEEE80211_NUM_ACS) { | 192 | if (local->hw.queues >= IEEE80211_NUM_ACS) |
193 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | 193 | pos = ieee80211_add_wmm_info_ie(pos, 0); /* U-APSD not in use */ |
194 | *pos++ = 7; /* len */ | ||
195 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
196 | *pos++ = 0x50; | ||
197 | *pos++ = 0xf2; | ||
198 | *pos++ = 2; /* WME */ | ||
199 | *pos++ = 0; /* WME info */ | ||
200 | *pos++ = 1; /* WME ver */ | ||
201 | *pos++ = 0; /* U-APSD no in use */ | ||
202 | } | ||
203 | 194 | ||
204 | presp->head_len = pos - presp->head; | 195 | presp->head_len = pos - presp->head; |
205 | if (WARN_ON(presp->head_len > frame_len)) | 196 | if (WARN_ON(presp->head_len > frame_len)) |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9e025e1184cc..ef7a089ac546 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -345,7 +345,6 @@ enum ieee80211_sta_flags { | |||
345 | IEEE80211_STA_CONNECTION_POLL = BIT(1), | 345 | IEEE80211_STA_CONNECTION_POLL = BIT(1), |
346 | IEEE80211_STA_CONTROL_PORT = BIT(2), | 346 | IEEE80211_STA_CONTROL_PORT = BIT(2), |
347 | IEEE80211_STA_DISABLE_HT = BIT(4), | 347 | IEEE80211_STA_DISABLE_HT = BIT(4), |
348 | IEEE80211_STA_CSA_RECEIVED = BIT(5), | ||
349 | IEEE80211_STA_MFP_ENABLED = BIT(6), | 348 | IEEE80211_STA_MFP_ENABLED = BIT(6), |
350 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), | 349 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), |
351 | IEEE80211_STA_NULLFUNC_ACKED = BIT(8), | 350 | IEEE80211_STA_NULLFUNC_ACKED = BIT(8), |
@@ -503,6 +502,9 @@ struct ieee80211_if_managed { | |||
503 | struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */ | 502 | struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */ |
504 | struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ | 503 | struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ |
505 | struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ | 504 | struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ |
505 | |||
506 | u8 tdls_peer[ETH_ALEN] __aligned(2); | ||
507 | struct delayed_work tdls_peer_del_work; | ||
506 | }; | 508 | }; |
507 | 509 | ||
508 | struct ieee80211_if_ibss { | 510 | struct ieee80211_if_ibss { |
@@ -815,9 +817,6 @@ struct ieee80211_sub_if_data { | |||
815 | bool radar_required; | 817 | bool radar_required; |
816 | struct delayed_work dfs_cac_timer_work; | 818 | struct delayed_work dfs_cac_timer_work; |
817 | 819 | ||
818 | u8 tdls_peer[ETH_ALEN] __aligned(2); | ||
819 | struct delayed_work tdls_peer_del_work; | ||
820 | |||
821 | /* | 820 | /* |
822 | * AP this belongs to: self in AP mode and | 821 | * AP this belongs to: self in AP mode and |
823 | * corresponding AP in VLAN mode, NULL for | 822 | * corresponding AP in VLAN mode, NULL for |
@@ -926,10 +925,17 @@ ieee80211_vif_get_shift(struct ieee80211_vif *vif) | |||
926 | return shift; | 925 | return shift; |
927 | } | 926 | } |
928 | 927 | ||
928 | struct ieee80211_rx_agg { | ||
929 | u8 addr[ETH_ALEN]; | ||
930 | u16 tid; | ||
931 | }; | ||
932 | |||
929 | enum sdata_queue_type { | 933 | enum sdata_queue_type { |
930 | IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, | 934 | IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, |
931 | IEEE80211_SDATA_QUEUE_AGG_START = 1, | 935 | IEEE80211_SDATA_QUEUE_AGG_START = 1, |
932 | IEEE80211_SDATA_QUEUE_AGG_STOP = 2, | 936 | IEEE80211_SDATA_QUEUE_AGG_STOP = 2, |
937 | IEEE80211_SDATA_QUEUE_RX_AGG_START = 3, | ||
938 | IEEE80211_SDATA_QUEUE_RX_AGG_STOP = 4, | ||
933 | }; | 939 | }; |
934 | 940 | ||
935 | enum { | 941 | enum { |
@@ -1578,6 +1584,10 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
1578 | u16 initiator, u16 reason, bool stop); | 1584 | u16 initiator, u16 reason, bool stop); |
1579 | void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | 1585 | void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, |
1580 | u16 initiator, u16 reason, bool stop); | 1586 | u16 initiator, u16 reason, bool stop); |
1587 | void __ieee80211_start_rx_ba_session(struct sta_info *sta, | ||
1588 | u8 dialog_token, u16 timeout, | ||
1589 | u16 start_seq_num, u16 ba_policy, u16 tid, | ||
1590 | u16 buf_size, bool tx); | ||
1581 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, | 1591 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, |
1582 | enum ieee80211_agg_stop_reason reason); | 1592 | enum ieee80211_agg_stop_reason reason); |
1583 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, | 1593 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, |
@@ -1730,6 +1740,21 @@ static inline void ieee802_11_parse_elems(const u8 *start, size_t len, | |||
1730 | ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0); | 1740 | ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0); |
1731 | } | 1741 | } |
1732 | 1742 | ||
1743 | static inline bool ieee80211_rx_reorder_ready(struct sk_buff_head *frames) | ||
1744 | { | ||
1745 | struct sk_buff *tail = skb_peek_tail(frames); | ||
1746 | struct ieee80211_rx_status *status; | ||
1747 | |||
1748 | if (!tail) | ||
1749 | return false; | ||
1750 | |||
1751 | status = IEEE80211_SKB_RXCB(tail); | ||
1752 | if (status->flag & RX_FLAG_AMSDU_MORE) | ||
1753 | return false; | ||
1754 | |||
1755 | return true; | ||
1756 | } | ||
1757 | |||
1733 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); | 1758 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); |
1734 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); | 1759 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); |
1735 | void ieee80211_dynamic_ps_timer(unsigned long data); | 1760 | void ieee80211_dynamic_ps_timer(unsigned long data); |
@@ -1824,6 +1849,7 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | |||
1824 | int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | 1849 | int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, |
1825 | struct sk_buff *skb, bool need_basic, | 1850 | struct sk_buff *skb, bool need_basic, |
1826 | enum ieee80211_band band); | 1851 | enum ieee80211_band band); |
1852 | u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo); | ||
1827 | 1853 | ||
1828 | /* channel management */ | 1854 | /* channel management */ |
1829 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, | 1855 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index bbf51b2f0651..29be8854a027 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -1140,6 +1140,7 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
1140 | struct sk_buff *skb; | 1140 | struct sk_buff *skb; |
1141 | struct sta_info *sta; | 1141 | struct sta_info *sta; |
1142 | struct ieee80211_ra_tid *ra_tid; | 1142 | struct ieee80211_ra_tid *ra_tid; |
1143 | struct ieee80211_rx_agg *rx_agg; | ||
1143 | 1144 | ||
1144 | if (!ieee80211_sdata_running(sdata)) | 1145 | if (!ieee80211_sdata_running(sdata)) |
1145 | return; | 1146 | return; |
@@ -1167,6 +1168,34 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
1167 | ra_tid = (void *)&skb->cb; | 1168 | ra_tid = (void *)&skb->cb; |
1168 | ieee80211_stop_tx_ba_cb(&sdata->vif, ra_tid->ra, | 1169 | ieee80211_stop_tx_ba_cb(&sdata->vif, ra_tid->ra, |
1169 | ra_tid->tid); | 1170 | ra_tid->tid); |
1171 | } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_RX_AGG_START) { | ||
1172 | rx_agg = (void *)&skb->cb; | ||
1173 | mutex_lock(&local->sta_mtx); | ||
1174 | sta = sta_info_get_bss(sdata, rx_agg->addr); | ||
1175 | if (sta) { | ||
1176 | u16 last_seq; | ||
1177 | |||
1178 | last_seq = le16_to_cpu( | ||
1179 | sta->last_seq_ctrl[rx_agg->tid]); | ||
1180 | |||
1181 | __ieee80211_start_rx_ba_session(sta, | ||
1182 | 0, 0, | ||
1183 | ieee80211_sn_inc(last_seq), | ||
1184 | 1, rx_agg->tid, | ||
1185 | IEEE80211_MAX_AMPDU_BUF, | ||
1186 | false); | ||
1187 | } | ||
1188 | mutex_unlock(&local->sta_mtx); | ||
1189 | } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_RX_AGG_STOP) { | ||
1190 | rx_agg = (void *)&skb->cb; | ||
1191 | mutex_lock(&local->sta_mtx); | ||
1192 | sta = sta_info_get_bss(sdata, rx_agg->addr); | ||
1193 | if (sta) | ||
1194 | __ieee80211_stop_rx_ba_session(sta, | ||
1195 | rx_agg->tid, | ||
1196 | WLAN_BACK_RECIPIENT, 0, | ||
1197 | false); | ||
1198 | mutex_unlock(&local->sta_mtx); | ||
1170 | } else if (ieee80211_is_action(mgmt->frame_control) && | 1199 | } else if (ieee80211_is_action(mgmt->frame_control) && |
1171 | mgmt->u.action.category == WLAN_CATEGORY_BACK) { | 1200 | mgmt->u.action.category == WLAN_CATEGORY_BACK) { |
1172 | int len = skb->len; | 1201 | int len = skb->len; |
@@ -1672,8 +1701,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1672 | ieee80211_dfs_cac_timer_work); | 1701 | ieee80211_dfs_cac_timer_work); |
1673 | INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk, | 1702 | INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk, |
1674 | ieee80211_delayed_tailroom_dec); | 1703 | ieee80211_delayed_tailroom_dec); |
1675 | INIT_DELAYED_WORK(&sdata->tdls_peer_del_work, | ||
1676 | ieee80211_tdls_peer_del_work); | ||
1677 | 1704 | ||
1678 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | 1705 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
1679 | struct ieee80211_supported_band *sband; | 1706 | struct ieee80211_supported_band *sband; |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 16d97f044a20..d808cff80153 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -482,9 +482,6 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
482 | int idx, ret; | 482 | int idx, ret; |
483 | bool pairwise; | 483 | bool pairwise; |
484 | 484 | ||
485 | if (WARN_ON(!sdata || !key)) | ||
486 | return -EINVAL; | ||
487 | |||
488 | pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; | 485 | pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; |
489 | idx = key->conf.keyidx; | 486 | idx = key->conf.keyidx; |
490 | key->local = sdata->local; | 487 | key->local = sdata->local; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 931330bbe00c..31a8afaf7332 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -830,16 +830,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
830 | qos_info = 0; | 830 | qos_info = 0; |
831 | } | 831 | } |
832 | 832 | ||
833 | pos = skb_put(skb, 9); | 833 | pos = ieee80211_add_wmm_info_ie(skb_put(skb, 9), qos_info); |
834 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | ||
835 | *pos++ = 7; /* len */ | ||
836 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
837 | *pos++ = 0x50; | ||
838 | *pos++ = 0xf2; | ||
839 | *pos++ = 2; /* WME */ | ||
840 | *pos++ = 0; /* WME info */ | ||
841 | *pos++ = 1; /* WME ver */ | ||
842 | *pos++ = qos_info; | ||
843 | } | 834 | } |
844 | 835 | ||
845 | /* add any remaining custom (i.e. vendor specific here) IEs */ | 836 | /* add any remaining custom (i.e. vendor specific here) IEs */ |
@@ -1005,8 +996,6 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
1005 | sdata->csa_block_tx = false; | 996 | sdata->csa_block_tx = false; |
1006 | } | 997 | } |
1007 | 998 | ||
1008 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
1009 | |||
1010 | ieee80211_sta_reset_beacon_monitor(sdata); | 999 | ieee80211_sta_reset_beacon_monitor(sdata); |
1011 | ieee80211_sta_reset_conn_monitor(sdata); | 1000 | ieee80211_sta_reset_conn_monitor(sdata); |
1012 | 1001 | ||
@@ -1064,7 +1053,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1064 | return; | 1053 | return; |
1065 | 1054 | ||
1066 | /* disregard subsequent announcements if we are already processing */ | 1055 | /* disregard subsequent announcements if we are already processing */ |
1067 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) | 1056 | if (sdata->vif.csa_active) |
1068 | return; | 1057 | return; |
1069 | 1058 | ||
1070 | current_band = cbss->channel->band; | 1059 | current_band = cbss->channel->band; |
@@ -1091,8 +1080,6 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1091 | return; | 1080 | return; |
1092 | } | 1081 | } |
1093 | 1082 | ||
1094 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | ||
1095 | |||
1096 | mutex_lock(&local->mtx); | 1083 | mutex_lock(&local->mtx); |
1097 | mutex_lock(&local->chanctx_mtx); | 1084 | mutex_lock(&local->chanctx_mtx); |
1098 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | 1085 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, |
@@ -2108,8 +2095,6 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2108 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 2095 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
2109 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 2096 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
2110 | true, frame_buf); | 2097 | true, frame_buf); |
2111 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
2112 | |||
2113 | mutex_lock(&local->mtx); | 2098 | mutex_lock(&local->mtx); |
2114 | sdata->vif.csa_active = false; | 2099 | sdata->vif.csa_active = false; |
2115 | if (sdata->csa_block_tx) { | 2100 | if (sdata->csa_block_tx) { |
@@ -3722,6 +3707,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
3722 | INIT_WORK(&ifmgd->csa_connection_drop_work, | 3707 | INIT_WORK(&ifmgd->csa_connection_drop_work, |
3723 | ieee80211_csa_connection_drop_work); | 3708 | ieee80211_csa_connection_drop_work); |
3724 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work); | 3709 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work); |
3710 | INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work, | ||
3711 | ieee80211_tdls_peer_del_work); | ||
3725 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 3712 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
3726 | (unsigned long) sdata); | 3713 | (unsigned long) sdata); |
3727 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, | 3714 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, |
@@ -4585,6 +4572,7 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) | |||
4585 | cancel_work_sync(&ifmgd->request_smps_work); | 4572 | cancel_work_sync(&ifmgd->request_smps_work); |
4586 | cancel_work_sync(&ifmgd->csa_connection_drop_work); | 4573 | cancel_work_sync(&ifmgd->csa_connection_drop_work); |
4587 | cancel_work_sync(&ifmgd->chswitch_work); | 4574 | cancel_work_sync(&ifmgd->chswitch_work); |
4575 | cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work); | ||
4588 | 4576 | ||
4589 | sdata_lock(sdata); | 4577 | sdata_lock(sdata); |
4590 | if (ifmgd->assoc_data) { | 4578 | if (ifmgd->assoc_data) { |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5f572bed1761..bd2c9b22c945 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -688,20 +688,27 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, | |||
688 | int index, | 688 | int index, |
689 | struct sk_buff_head *frames) | 689 | struct sk_buff_head *frames) |
690 | { | 690 | { |
691 | struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; | 691 | struct sk_buff_head *skb_list = &tid_agg_rx->reorder_buf[index]; |
692 | struct sk_buff *skb; | ||
692 | struct ieee80211_rx_status *status; | 693 | struct ieee80211_rx_status *status; |
693 | 694 | ||
694 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | 695 | lockdep_assert_held(&tid_agg_rx->reorder_lock); |
695 | 696 | ||
696 | if (!skb) | 697 | if (skb_queue_empty(skb_list)) |
698 | goto no_frame; | ||
699 | |||
700 | if (!ieee80211_rx_reorder_ready(skb_list)) { | ||
701 | __skb_queue_purge(skb_list); | ||
697 | goto no_frame; | 702 | goto no_frame; |
703 | } | ||
698 | 704 | ||
699 | /* release the frame from the reorder ring buffer */ | 705 | /* release frames from the reorder ring buffer */ |
700 | tid_agg_rx->stored_mpdu_num--; | 706 | tid_agg_rx->stored_mpdu_num--; |
701 | tid_agg_rx->reorder_buf[index] = NULL; | 707 | while ((skb = __skb_dequeue(skb_list))) { |
702 | status = IEEE80211_SKB_RXCB(skb); | 708 | status = IEEE80211_SKB_RXCB(skb); |
703 | status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE; | 709 | status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE; |
704 | __skb_queue_tail(frames, skb); | 710 | __skb_queue_tail(frames, skb); |
711 | } | ||
705 | 712 | ||
706 | no_frame: | 713 | no_frame: |
707 | tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num); | 714 | tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num); |
@@ -738,13 +745,13 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
738 | struct tid_ampdu_rx *tid_agg_rx, | 745 | struct tid_ampdu_rx *tid_agg_rx, |
739 | struct sk_buff_head *frames) | 746 | struct sk_buff_head *frames) |
740 | { | 747 | { |
741 | int index, j; | 748 | int index, i, j; |
742 | 749 | ||
743 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | 750 | lockdep_assert_held(&tid_agg_rx->reorder_lock); |
744 | 751 | ||
745 | /* release the buffer until next missing frame */ | 752 | /* release the buffer until next missing frame */ |
746 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; | 753 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
747 | if (!tid_agg_rx->reorder_buf[index] && | 754 | if (!ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index]) && |
748 | tid_agg_rx->stored_mpdu_num) { | 755 | tid_agg_rx->stored_mpdu_num) { |
749 | /* | 756 | /* |
750 | * No buffers ready to be released, but check whether any | 757 | * No buffers ready to be released, but check whether any |
@@ -753,7 +760,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
753 | int skipped = 1; | 760 | int skipped = 1; |
754 | for (j = (index + 1) % tid_agg_rx->buf_size; j != index; | 761 | for (j = (index + 1) % tid_agg_rx->buf_size; j != index; |
755 | j = (j + 1) % tid_agg_rx->buf_size) { | 762 | j = (j + 1) % tid_agg_rx->buf_size) { |
756 | if (!tid_agg_rx->reorder_buf[j]) { | 763 | if (!ieee80211_rx_reorder_ready( |
764 | &tid_agg_rx->reorder_buf[j])) { | ||
757 | skipped++; | 765 | skipped++; |
758 | continue; | 766 | continue; |
759 | } | 767 | } |
@@ -762,6 +770,11 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
762 | HT_RX_REORDER_BUF_TIMEOUT)) | 770 | HT_RX_REORDER_BUF_TIMEOUT)) |
763 | goto set_release_timer; | 771 | goto set_release_timer; |
764 | 772 | ||
773 | /* don't leave incomplete A-MSDUs around */ | ||
774 | for (i = (index + 1) % tid_agg_rx->buf_size; i != j; | ||
775 | i = (i + 1) % tid_agg_rx->buf_size) | ||
776 | __skb_queue_purge(&tid_agg_rx->reorder_buf[i]); | ||
777 | |||
765 | ht_dbg_ratelimited(sdata, | 778 | ht_dbg_ratelimited(sdata, |
766 | "release an RX reorder frame due to timeout on earlier frames\n"); | 779 | "release an RX reorder frame due to timeout on earlier frames\n"); |
767 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, j, | 780 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, j, |
@@ -775,7 +788,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
775 | skipped) & IEEE80211_SN_MASK; | 788 | skipped) & IEEE80211_SN_MASK; |
776 | skipped = 0; | 789 | skipped = 0; |
777 | } | 790 | } |
778 | } else while (tid_agg_rx->reorder_buf[index]) { | 791 | } else while (ieee80211_rx_reorder_ready( |
792 | &tid_agg_rx->reorder_buf[index])) { | ||
779 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, | 793 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, |
780 | frames); | 794 | frames); |
781 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; | 795 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
@@ -786,7 +800,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
786 | 800 | ||
787 | for (; j != (index - 1) % tid_agg_rx->buf_size; | 801 | for (; j != (index - 1) % tid_agg_rx->buf_size; |
788 | j = (j + 1) % tid_agg_rx->buf_size) { | 802 | j = (j + 1) % tid_agg_rx->buf_size) { |
789 | if (tid_agg_rx->reorder_buf[j]) | 803 | if (ieee80211_rx_reorder_ready( |
804 | &tid_agg_rx->reorder_buf[j])) | ||
790 | break; | 805 | break; |
791 | } | 806 | } |
792 | 807 | ||
@@ -811,6 +826,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
811 | struct sk_buff_head *frames) | 826 | struct sk_buff_head *frames) |
812 | { | 827 | { |
813 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 828 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
829 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
814 | u16 sc = le16_to_cpu(hdr->seq_ctrl); | 830 | u16 sc = le16_to_cpu(hdr->seq_ctrl); |
815 | u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; | 831 | u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; |
816 | u16 head_seq_num, buf_size; | 832 | u16 head_seq_num, buf_size; |
@@ -845,7 +861,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
845 | index = mpdu_seq_num % tid_agg_rx->buf_size; | 861 | index = mpdu_seq_num % tid_agg_rx->buf_size; |
846 | 862 | ||
847 | /* check if we already stored this frame */ | 863 | /* check if we already stored this frame */ |
848 | if (tid_agg_rx->reorder_buf[index]) { | 864 | if (ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index])) { |
849 | dev_kfree_skb(skb); | 865 | dev_kfree_skb(skb); |
850 | goto out; | 866 | goto out; |
851 | } | 867 | } |
@@ -858,17 +874,20 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
858 | */ | 874 | */ |
859 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && | 875 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && |
860 | tid_agg_rx->stored_mpdu_num == 0) { | 876 | tid_agg_rx->stored_mpdu_num == 0) { |
861 | tid_agg_rx->head_seq_num = | 877 | if (!(status->flag & RX_FLAG_AMSDU_MORE)) |
862 | ieee80211_sn_inc(tid_agg_rx->head_seq_num); | 878 | tid_agg_rx->head_seq_num = |
879 | ieee80211_sn_inc(tid_agg_rx->head_seq_num); | ||
863 | ret = false; | 880 | ret = false; |
864 | goto out; | 881 | goto out; |
865 | } | 882 | } |
866 | 883 | ||
867 | /* put the frame in the reordering buffer */ | 884 | /* put the frame in the reordering buffer */ |
868 | tid_agg_rx->reorder_buf[index] = skb; | 885 | __skb_queue_tail(&tid_agg_rx->reorder_buf[index], skb); |
869 | tid_agg_rx->reorder_time[index] = jiffies; | 886 | if (!(status->flag & RX_FLAG_AMSDU_MORE)) { |
870 | tid_agg_rx->stored_mpdu_num++; | 887 | tid_agg_rx->reorder_time[index] = jiffies; |
871 | ieee80211_sta_reorder_release(sdata, tid_agg_rx, frames); | 888 | tid_agg_rx->stored_mpdu_num++; |
889 | ieee80211_sta_reorder_release(sdata, tid_agg_rx, frames); | ||
890 | } | ||
872 | 891 | ||
873 | out: | 892 | out: |
874 | spin_unlock(&tid_agg_rx->reorder_lock); | 893 | spin_unlock(&tid_agg_rx->reorder_lock); |
@@ -3129,6 +3148,14 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
3129 | if (!ieee80211_is_beacon(hdr->frame_control)) | 3148 | if (!ieee80211_is_beacon(hdr->frame_control)) |
3130 | return false; | 3149 | return false; |
3131 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | 3150 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
3151 | } else if (!ieee80211_has_tods(hdr->frame_control)) { | ||
3152 | /* ignore data frames to TDLS-peers */ | ||
3153 | if (ieee80211_is_data(hdr->frame_control)) | ||
3154 | return false; | ||
3155 | /* ignore action frames to TDLS-peers */ | ||
3156 | if (ieee80211_is_action(hdr->frame_control) && | ||
3157 | !ether_addr_equal(bssid, hdr->addr1)) | ||
3158 | return false; | ||
3132 | } | 3159 | } |
3133 | break; | 3160 | break; |
3134 | case NL80211_IFTYPE_WDS: | 3161 | case NL80211_IFTYPE_WDS: |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 2a04361b2162..d411bcc8ef08 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -47,6 +47,8 @@ | |||
47 | * @WLAN_STA_TDLS_PEER: Station is a TDLS peer. | 47 | * @WLAN_STA_TDLS_PEER: Station is a TDLS peer. |
48 | * @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct | 48 | * @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct |
49 | * packets. This means the link is enabled. | 49 | * packets. This means the link is enabled. |
50 | * @WLAN_STA_TDLS_INITIATOR: We are the initiator of the TDLS link with this | ||
51 | * station. | ||
50 | * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was | 52 | * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was |
51 | * keeping station in power-save mode, reply when the driver | 53 | * keeping station in power-save mode, reply when the driver |
52 | * unblocks the station. | 54 | * unblocks the station. |
@@ -76,6 +78,7 @@ enum ieee80211_sta_info_flags { | |||
76 | WLAN_STA_PSPOLL, | 78 | WLAN_STA_PSPOLL, |
77 | WLAN_STA_TDLS_PEER, | 79 | WLAN_STA_TDLS_PEER, |
78 | WLAN_STA_TDLS_PEER_AUTH, | 80 | WLAN_STA_TDLS_PEER_AUTH, |
81 | WLAN_STA_TDLS_INITIATOR, | ||
79 | WLAN_STA_UAPSD, | 82 | WLAN_STA_UAPSD, |
80 | WLAN_STA_SP, | 83 | WLAN_STA_SP, |
81 | WLAN_STA_4ADDR_EVENT, | 84 | WLAN_STA_4ADDR_EVENT, |
@@ -152,7 +155,8 @@ struct tid_ampdu_tx { | |||
152 | /** | 155 | /** |
153 | * struct tid_ampdu_rx - TID aggregation information (Rx). | 156 | * struct tid_ampdu_rx - TID aggregation information (Rx). |
154 | * | 157 | * |
155 | * @reorder_buf: buffer to reorder incoming aggregated MPDUs | 158 | * @reorder_buf: buffer to reorder incoming aggregated MPDUs. An MPDU may be an |
159 | * A-MSDU with individually reported subframes. | ||
156 | * @reorder_time: jiffies when skb was added | 160 | * @reorder_time: jiffies when skb was added |
157 | * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) | 161 | * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) |
158 | * @reorder_timer: releases expired frames from the reorder buffer. | 162 | * @reorder_timer: releases expired frames from the reorder buffer. |
@@ -177,7 +181,7 @@ struct tid_ampdu_tx { | |||
177 | struct tid_ampdu_rx { | 181 | struct tid_ampdu_rx { |
178 | struct rcu_head rcu_head; | 182 | struct rcu_head rcu_head; |
179 | spinlock_t reorder_lock; | 183 | spinlock_t reorder_lock; |
180 | struct sk_buff **reorder_buf; | 184 | struct sk_buff_head *reorder_buf; |
181 | unsigned long *reorder_time; | 185 | unsigned long *reorder_time; |
182 | struct timer_list session_timer; | 186 | struct timer_list session_timer; |
183 | struct timer_list reorder_timer; | 187 | struct timer_list reorder_timer; |
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index f7185338a0fa..1b21050be174 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c | |||
@@ -8,6 +8,7 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/ieee80211.h> | 10 | #include <linux/ieee80211.h> |
11 | #include <linux/log2.h> | ||
11 | #include <net/cfg80211.h> | 12 | #include <net/cfg80211.h> |
12 | #include "ieee80211_i.h" | 13 | #include "ieee80211_i.h" |
13 | #include "driver-ops.h" | 14 | #include "driver-ops.h" |
@@ -21,14 +22,14 @@ void ieee80211_tdls_peer_del_work(struct work_struct *wk) | |||
21 | struct ieee80211_local *local; | 22 | struct ieee80211_local *local; |
22 | 23 | ||
23 | sdata = container_of(wk, struct ieee80211_sub_if_data, | 24 | sdata = container_of(wk, struct ieee80211_sub_if_data, |
24 | tdls_peer_del_work.work); | 25 | u.mgd.tdls_peer_del_work.work); |
25 | local = sdata->local; | 26 | local = sdata->local; |
26 | 27 | ||
27 | mutex_lock(&local->mtx); | 28 | mutex_lock(&local->mtx); |
28 | if (!is_zero_ether_addr(sdata->tdls_peer)) { | 29 | if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer)) { |
29 | tdls_dbg(sdata, "TDLS del peer %pM\n", sdata->tdls_peer); | 30 | tdls_dbg(sdata, "TDLS del peer %pM\n", sdata->u.mgd.tdls_peer); |
30 | sta_info_destroy_addr(sdata, sdata->tdls_peer); | 31 | sta_info_destroy_addr(sdata, sdata->u.mgd.tdls_peer); |
31 | eth_zero_addr(sdata->tdls_peer); | 32 | eth_zero_addr(sdata->u.mgd.tdls_peer); |
32 | } | 33 | } |
33 | mutex_unlock(&local->mtx); | 34 | mutex_unlock(&local->mtx); |
34 | } | 35 | } |
@@ -46,11 +47,16 @@ static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb) | |||
46 | *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; | 47 | *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; |
47 | } | 48 | } |
48 | 49 | ||
49 | static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata) | 50 | static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, |
51 | u16 status_code) | ||
50 | { | 52 | { |
51 | struct ieee80211_local *local = sdata->local; | 53 | struct ieee80211_local *local = sdata->local; |
52 | u16 capab; | 54 | u16 capab; |
53 | 55 | ||
56 | /* The capability will be 0 when sending a failure code */ | ||
57 | if (status_code != 0) | ||
58 | return 0; | ||
59 | |||
54 | capab = 0; | 60 | capab = 0; |
55 | if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ) | 61 | if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ) |
56 | return capab; | 62 | return capab; |
@@ -63,19 +69,332 @@ static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata) | |||
63 | return capab; | 69 | return capab; |
64 | } | 70 | } |
65 | 71 | ||
66 | static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr, | 72 | static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata, |
67 | const u8 *peer, const u8 *bssid) | 73 | struct sk_buff *skb, const u8 *peer, |
74 | bool initiator) | ||
68 | { | 75 | { |
69 | struct ieee80211_tdls_lnkie *lnkid; | 76 | struct ieee80211_tdls_lnkie *lnkid; |
77 | const u8 *init_addr, *rsp_addr; | ||
78 | |||
79 | if (initiator) { | ||
80 | init_addr = sdata->vif.addr; | ||
81 | rsp_addr = peer; | ||
82 | } else { | ||
83 | init_addr = peer; | ||
84 | rsp_addr = sdata->vif.addr; | ||
85 | } | ||
70 | 86 | ||
71 | lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie)); | 87 | lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie)); |
72 | 88 | ||
73 | lnkid->ie_type = WLAN_EID_LINK_ID; | 89 | lnkid->ie_type = WLAN_EID_LINK_ID; |
74 | lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2; | 90 | lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2; |
75 | 91 | ||
76 | memcpy(lnkid->bssid, bssid, ETH_ALEN); | 92 | memcpy(lnkid->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
77 | memcpy(lnkid->init_sta, src_addr, ETH_ALEN); | 93 | memcpy(lnkid->init_sta, init_addr, ETH_ALEN); |
78 | memcpy(lnkid->resp_sta, peer, ETH_ALEN); | 94 | memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN); |
95 | } | ||
96 | |||
97 | /* translate numbering in the WMM parameter IE to the mac80211 notation */ | ||
98 | static enum ieee80211_ac_numbers ieee80211_ac_from_wmm(int ac) | ||
99 | { | ||
100 | switch (ac) { | ||
101 | default: | ||
102 | WARN_ON_ONCE(1); | ||
103 | case 0: | ||
104 | return IEEE80211_AC_BE; | ||
105 | case 1: | ||
106 | return IEEE80211_AC_BK; | ||
107 | case 2: | ||
108 | return IEEE80211_AC_VI; | ||
109 | case 3: | ||
110 | return IEEE80211_AC_VO; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | static u8 ieee80211_wmm_aci_aifsn(int aifsn, bool acm, int aci) | ||
115 | { | ||
116 | u8 ret; | ||
117 | |||
118 | ret = aifsn & 0x0f; | ||
119 | if (acm) | ||
120 | ret |= 0x10; | ||
121 | ret |= (aci << 5) & 0x60; | ||
122 | return ret; | ||
123 | } | ||
124 | |||
125 | static u8 ieee80211_wmm_ecw(u16 cw_min, u16 cw_max) | ||
126 | { | ||
127 | return ((ilog2(cw_min + 1) << 0x0) & 0x0f) | | ||
128 | ((ilog2(cw_max + 1) << 0x4) & 0xf0); | ||
129 | } | ||
130 | |||
131 | static void ieee80211_tdls_add_wmm_param_ie(struct ieee80211_sub_if_data *sdata, | ||
132 | struct sk_buff *skb) | ||
133 | { | ||
134 | struct ieee80211_wmm_param_ie *wmm; | ||
135 | struct ieee80211_tx_queue_params *txq; | ||
136 | int i; | ||
137 | |||
138 | wmm = (void *)skb_put(skb, sizeof(*wmm)); | ||
139 | memset(wmm, 0, sizeof(*wmm)); | ||
140 | |||
141 | wmm->element_id = WLAN_EID_VENDOR_SPECIFIC; | ||
142 | wmm->len = sizeof(*wmm) - 2; | ||
143 | |||
144 | wmm->oui[0] = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
145 | wmm->oui[1] = 0x50; | ||
146 | wmm->oui[2] = 0xf2; | ||
147 | wmm->oui_type = 2; /* WME */ | ||
148 | wmm->oui_subtype = 1; /* WME param */ | ||
149 | wmm->version = 1; /* WME ver */ | ||
150 | wmm->qos_info = 0; /* U-APSD not in use */ | ||
151 | |||
152 | /* | ||
153 | * Use the EDCA parameters defined for the BSS, or default if the AP | ||
154 | * doesn't support it, as mandated by 802.11-2012 section 10.22.4 | ||
155 | */ | ||
156 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { | ||
157 | txq = &sdata->tx_conf[ieee80211_ac_from_wmm(i)]; | ||
158 | wmm->ac[i].aci_aifsn = ieee80211_wmm_aci_aifsn(txq->aifs, | ||
159 | txq->acm, i); | ||
160 | wmm->ac[i].cw = ieee80211_wmm_ecw(txq->cw_min, txq->cw_max); | ||
161 | wmm->ac[i].txop_limit = cpu_to_le16(txq->txop); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | static void | ||
166 | ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | ||
167 | struct sk_buff *skb, const u8 *peer, | ||
168 | u8 action_code, bool initiator, | ||
169 | const u8 *extra_ies, size_t extra_ies_len) | ||
170 | { | ||
171 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | ||
172 | struct ieee80211_local *local = sdata->local; | ||
173 | struct ieee80211_supported_band *sband; | ||
174 | struct ieee80211_sta_ht_cap ht_cap; | ||
175 | struct sta_info *sta = NULL; | ||
176 | size_t offset = 0, noffset; | ||
177 | u8 *pos; | ||
178 | |||
179 | rcu_read_lock(); | ||
180 | |||
181 | /* we should have the peer STA if we're already responding */ | ||
182 | if (action_code == WLAN_TDLS_SETUP_RESPONSE) { | ||
183 | sta = sta_info_get(sdata, peer); | ||
184 | if (WARN_ON_ONCE(!sta)) { | ||
185 | rcu_read_unlock(); | ||
186 | return; | ||
187 | } | ||
188 | } | ||
189 | |||
190 | ieee80211_add_srates_ie(sdata, skb, false, band); | ||
191 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); | ||
192 | |||
193 | /* add any custom IEs that go before Extended Capabilities */ | ||
194 | if (extra_ies_len) { | ||
195 | static const u8 before_ext_cap[] = { | ||
196 | WLAN_EID_SUPP_RATES, | ||
197 | WLAN_EID_COUNTRY, | ||
198 | WLAN_EID_EXT_SUPP_RATES, | ||
199 | WLAN_EID_SUPPORTED_CHANNELS, | ||
200 | WLAN_EID_RSN, | ||
201 | }; | ||
202 | noffset = ieee80211_ie_split(extra_ies, extra_ies_len, | ||
203 | before_ext_cap, | ||
204 | ARRAY_SIZE(before_ext_cap), | ||
205 | offset); | ||
206 | pos = skb_put(skb, noffset - offset); | ||
207 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
208 | offset = noffset; | ||
209 | } | ||
210 | |||
211 | ieee80211_tdls_add_ext_capab(skb); | ||
212 | |||
213 | /* add the QoS element if we support it */ | ||
214 | if (local->hw.queues >= IEEE80211_NUM_ACS && | ||
215 | action_code != WLAN_PUB_ACTION_TDLS_DISCOVER_RES) | ||
216 | ieee80211_add_wmm_info_ie(skb_put(skb, 9), 0); /* no U-APSD */ | ||
217 | |||
218 | /* add any custom IEs that go before HT capabilities */ | ||
219 | if (extra_ies_len) { | ||
220 | static const u8 before_ht_cap[] = { | ||
221 | WLAN_EID_SUPP_RATES, | ||
222 | WLAN_EID_COUNTRY, | ||
223 | WLAN_EID_EXT_SUPP_RATES, | ||
224 | WLAN_EID_SUPPORTED_CHANNELS, | ||
225 | WLAN_EID_RSN, | ||
226 | WLAN_EID_EXT_CAPABILITY, | ||
227 | WLAN_EID_QOS_CAPA, | ||
228 | WLAN_EID_FAST_BSS_TRANSITION, | ||
229 | WLAN_EID_TIMEOUT_INTERVAL, | ||
230 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | ||
231 | }; | ||
232 | noffset = ieee80211_ie_split(extra_ies, extra_ies_len, | ||
233 | before_ht_cap, | ||
234 | ARRAY_SIZE(before_ht_cap), | ||
235 | offset); | ||
236 | pos = skb_put(skb, noffset - offset); | ||
237 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
238 | offset = noffset; | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * with TDLS we can switch channels, and HT-caps are not necessarily | ||
243 | * the same on all bands. The specification limits the setup to a | ||
244 | * single HT-cap, so use the current band for now. | ||
245 | */ | ||
246 | sband = local->hw.wiphy->bands[band]; | ||
247 | memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); | ||
248 | if ((action_code == WLAN_TDLS_SETUP_REQUEST || | ||
249 | action_code == WLAN_TDLS_SETUP_RESPONSE) && | ||
250 | ht_cap.ht_supported && (!sta || sta->sta.ht_cap.ht_supported)) { | ||
251 | if (action_code == WLAN_TDLS_SETUP_REQUEST) { | ||
252 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); | ||
253 | |||
254 | /* disable SMPS in TDLS initiator */ | ||
255 | ht_cap.cap |= (WLAN_HT_CAP_SM_PS_DISABLED | ||
256 | << IEEE80211_HT_CAP_SM_PS_SHIFT); | ||
257 | } else { | ||
258 | /* disable SMPS in TDLS responder */ | ||
259 | sta->sta.ht_cap.cap |= | ||
260 | (WLAN_HT_CAP_SM_PS_DISABLED | ||
261 | << IEEE80211_HT_CAP_SM_PS_SHIFT); | ||
262 | |||
263 | /* the peer caps are already intersected with our own */ | ||
264 | memcpy(&ht_cap, &sta->sta.ht_cap, sizeof(ht_cap)); | ||
265 | } | ||
266 | |||
267 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); | ||
268 | ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap); | ||
269 | } | ||
270 | |||
271 | rcu_read_unlock(); | ||
272 | |||
273 | /* add any remaining IEs */ | ||
274 | if (extra_ies_len) { | ||
275 | noffset = extra_ies_len; | ||
276 | pos = skb_put(skb, noffset - offset); | ||
277 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
278 | } | ||
279 | |||
280 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
281 | } | ||
282 | |||
283 | static void | ||
284 | ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, | ||
285 | struct sk_buff *skb, const u8 *peer, | ||
286 | bool initiator, const u8 *extra_ies, | ||
287 | size_t extra_ies_len) | ||
288 | { | ||
289 | struct ieee80211_local *local = sdata->local; | ||
290 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
291 | size_t offset = 0, noffset; | ||
292 | struct sta_info *sta, *ap_sta; | ||
293 | u8 *pos; | ||
294 | |||
295 | rcu_read_lock(); | ||
296 | |||
297 | sta = sta_info_get(sdata, peer); | ||
298 | ap_sta = sta_info_get(sdata, ifmgd->bssid); | ||
299 | if (WARN_ON_ONCE(!sta || !ap_sta)) { | ||
300 | rcu_read_unlock(); | ||
301 | return; | ||
302 | } | ||
303 | |||
304 | /* add any custom IEs that go before the QoS IE */ | ||
305 | if (extra_ies_len) { | ||
306 | static const u8 before_qos[] = { | ||
307 | WLAN_EID_RSN, | ||
308 | }; | ||
309 | noffset = ieee80211_ie_split(extra_ies, extra_ies_len, | ||
310 | before_qos, | ||
311 | ARRAY_SIZE(before_qos), | ||
312 | offset); | ||
313 | pos = skb_put(skb, noffset - offset); | ||
314 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
315 | offset = noffset; | ||
316 | } | ||
317 | |||
318 | /* add the QoS param IE if both the peer and we support it */ | ||
319 | if (local->hw.queues >= IEEE80211_NUM_ACS && | ||
320 | test_sta_flag(sta, WLAN_STA_WME)) | ||
321 | ieee80211_tdls_add_wmm_param_ie(sdata, skb); | ||
322 | |||
323 | /* add any custom IEs that go before HT operation */ | ||
324 | if (extra_ies_len) { | ||
325 | static const u8 before_ht_op[] = { | ||
326 | WLAN_EID_RSN, | ||
327 | WLAN_EID_QOS_CAPA, | ||
328 | WLAN_EID_FAST_BSS_TRANSITION, | ||
329 | WLAN_EID_TIMEOUT_INTERVAL, | ||
330 | }; | ||
331 | noffset = ieee80211_ie_split(extra_ies, extra_ies_len, | ||
332 | before_ht_op, | ||
333 | ARRAY_SIZE(before_ht_op), | ||
334 | offset); | ||
335 | pos = skb_put(skb, noffset - offset); | ||
336 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
337 | offset = noffset; | ||
338 | } | ||
339 | |||
340 | /* if HT support is only added in TDLS, we need an HT-operation IE */ | ||
341 | if (!ap_sta->sta.ht_cap.ht_supported && sta->sta.ht_cap.ht_supported) { | ||
342 | struct ieee80211_chanctx_conf *chanctx_conf = | ||
343 | rcu_dereference(sdata->vif.chanctx_conf); | ||
344 | if (!WARN_ON(!chanctx_conf)) { | ||
345 | pos = skb_put(skb, 2 + | ||
346 | sizeof(struct ieee80211_ht_operation)); | ||
347 | /* send an empty HT operation IE */ | ||
348 | ieee80211_ie_build_ht_oper(pos, &sta->sta.ht_cap, | ||
349 | &chanctx_conf->def, 0); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | rcu_read_unlock(); | ||
354 | |||
355 | /* add any remaining IEs */ | ||
356 | if (extra_ies_len) { | ||
357 | noffset = extra_ies_len; | ||
358 | pos = skb_put(skb, noffset - offset); | ||
359 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
360 | } | ||
361 | |||
362 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
363 | } | ||
364 | |||
365 | static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, | ||
366 | struct sk_buff *skb, const u8 *peer, | ||
367 | u8 action_code, u16 status_code, | ||
368 | bool initiator, const u8 *extra_ies, | ||
369 | size_t extra_ies_len) | ||
370 | { | ||
371 | switch (action_code) { | ||
372 | case WLAN_TDLS_SETUP_REQUEST: | ||
373 | case WLAN_TDLS_SETUP_RESPONSE: | ||
374 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | ||
375 | if (status_code == 0) | ||
376 | ieee80211_tdls_add_setup_start_ies(sdata, skb, peer, | ||
377 | action_code, | ||
378 | initiator, | ||
379 | extra_ies, | ||
380 | extra_ies_len); | ||
381 | break; | ||
382 | case WLAN_TDLS_SETUP_CONFIRM: | ||
383 | if (status_code == 0) | ||
384 | ieee80211_tdls_add_setup_cfm_ies(sdata, skb, peer, | ||
385 | initiator, extra_ies, | ||
386 | extra_ies_len); | ||
387 | break; | ||
388 | case WLAN_TDLS_TEARDOWN: | ||
389 | case WLAN_TDLS_DISCOVERY_REQUEST: | ||
390 | if (extra_ies_len) | ||
391 | memcpy(skb_put(skb, extra_ies_len), extra_ies, | ||
392 | extra_ies_len); | ||
393 | if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN) | ||
394 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
395 | break; | ||
396 | } | ||
397 | |||
79 | } | 398 | } |
80 | 399 | ||
81 | static int | 400 | static int |
@@ -84,7 +403,6 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
84 | u16 status_code, struct sk_buff *skb) | 403 | u16 status_code, struct sk_buff *skb) |
85 | { | 404 | { |
86 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 405 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
87 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | ||
88 | struct ieee80211_tdls_data *tf; | 406 | struct ieee80211_tdls_data *tf; |
89 | 407 | ||
90 | tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); | 408 | tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); |
@@ -102,11 +420,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
102 | skb_put(skb, sizeof(tf->u.setup_req)); | 420 | skb_put(skb, sizeof(tf->u.setup_req)); |
103 | tf->u.setup_req.dialog_token = dialog_token; | 421 | tf->u.setup_req.dialog_token = dialog_token; |
104 | tf->u.setup_req.capability = | 422 | tf->u.setup_req.capability = |
105 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 423 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, |
106 | 424 | status_code)); | |
107 | ieee80211_add_srates_ie(sdata, skb, false, band); | ||
108 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); | ||
109 | ieee80211_tdls_add_ext_capab(skb); | ||
110 | break; | 425 | break; |
111 | case WLAN_TDLS_SETUP_RESPONSE: | 426 | case WLAN_TDLS_SETUP_RESPONSE: |
112 | tf->category = WLAN_CATEGORY_TDLS; | 427 | tf->category = WLAN_CATEGORY_TDLS; |
@@ -116,11 +431,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
116 | tf->u.setup_resp.status_code = cpu_to_le16(status_code); | 431 | tf->u.setup_resp.status_code = cpu_to_le16(status_code); |
117 | tf->u.setup_resp.dialog_token = dialog_token; | 432 | tf->u.setup_resp.dialog_token = dialog_token; |
118 | tf->u.setup_resp.capability = | 433 | tf->u.setup_resp.capability = |
119 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 434 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, |
120 | 435 | status_code)); | |
121 | ieee80211_add_srates_ie(sdata, skb, false, band); | ||
122 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); | ||
123 | ieee80211_tdls_add_ext_capab(skb); | ||
124 | break; | 436 | break; |
125 | case WLAN_TDLS_SETUP_CONFIRM: | 437 | case WLAN_TDLS_SETUP_CONFIRM: |
126 | tf->category = WLAN_CATEGORY_TDLS; | 438 | tf->category = WLAN_CATEGORY_TDLS; |
@@ -157,7 +469,6 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
157 | u16 status_code, struct sk_buff *skb) | 469 | u16 status_code, struct sk_buff *skb) |
158 | { | 470 | { |
159 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 471 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
160 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | ||
161 | struct ieee80211_mgmt *mgmt; | 472 | struct ieee80211_mgmt *mgmt; |
162 | 473 | ||
163 | mgmt = (void *)skb_put(skb, 24); | 474 | mgmt = (void *)skb_put(skb, 24); |
@@ -178,11 +489,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
178 | mgmt->u.action.u.tdls_discover_resp.dialog_token = | 489 | mgmt->u.action.u.tdls_discover_resp.dialog_token = |
179 | dialog_token; | 490 | dialog_token; |
180 | mgmt->u.action.u.tdls_discover_resp.capability = | 491 | mgmt->u.action.u.tdls_discover_resp.capability = |
181 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 492 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, |
182 | 493 | status_code)); | |
183 | ieee80211_add_srates_ie(sdata, skb, false, band); | ||
184 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); | ||
185 | ieee80211_tdls_add_ext_capab(skb); | ||
186 | break; | 494 | break; |
187 | default: | 495 | default: |
188 | return -EINVAL; | 496 | return -EINVAL; |
@@ -202,7 +510,7 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
202 | struct ieee80211_local *local = sdata->local; | 510 | struct ieee80211_local *local = sdata->local; |
203 | struct sk_buff *skb = NULL; | 511 | struct sk_buff *skb = NULL; |
204 | bool send_direct; | 512 | bool send_direct; |
205 | const u8 *init_addr, *rsp_addr; | 513 | struct sta_info *sta; |
206 | int ret; | 514 | int ret; |
207 | 515 | ||
208 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 516 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
@@ -210,6 +518,9 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
210 | sizeof(struct ieee80211_tdls_data)) + | 518 | sizeof(struct ieee80211_tdls_data)) + |
211 | 50 + /* supported rates */ | 519 | 50 + /* supported rates */ |
212 | 7 + /* ext capab */ | 520 | 7 + /* ext capab */ |
521 | 26 + /* max(WMM-info, WMM-param) */ | ||
522 | 2 + max(sizeof(struct ieee80211_ht_cap), | ||
523 | sizeof(struct ieee80211_ht_operation)) + | ||
213 | extra_ies_len + | 524 | extra_ies_len + |
214 | sizeof(struct ieee80211_tdls_lnkie)); | 525 | sizeof(struct ieee80211_tdls_lnkie)); |
215 | if (!skb) | 526 | if (!skb) |
@@ -242,45 +553,48 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
242 | if (ret < 0) | 553 | if (ret < 0) |
243 | goto fail; | 554 | goto fail; |
244 | 555 | ||
245 | if (extra_ies_len) | 556 | rcu_read_lock(); |
246 | memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); | 557 | sta = sta_info_get(sdata, peer); |
247 | 558 | ||
248 | /* sanity check for initiator */ | 559 | /* infer the initiator if we can, to support old userspace */ |
249 | switch (action_code) { | 560 | switch (action_code) { |
250 | case WLAN_TDLS_SETUP_REQUEST: | 561 | case WLAN_TDLS_SETUP_REQUEST: |
562 | if (sta) | ||
563 | set_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); | ||
564 | /* fall-through */ | ||
251 | case WLAN_TDLS_SETUP_CONFIRM: | 565 | case WLAN_TDLS_SETUP_CONFIRM: |
252 | case WLAN_TDLS_DISCOVERY_REQUEST: | 566 | case WLAN_TDLS_DISCOVERY_REQUEST: |
253 | if (!initiator) { | 567 | initiator = true; |
254 | ret = -EINVAL; | ||
255 | goto fail; | ||
256 | } | ||
257 | break; | 568 | break; |
258 | case WLAN_TDLS_SETUP_RESPONSE: | 569 | case WLAN_TDLS_SETUP_RESPONSE: |
570 | /* | ||
571 | * In some testing scenarios, we send a request and response. | ||
572 | * Make the last packet sent take effect for the initiator | ||
573 | * value. | ||
574 | */ | ||
575 | if (sta) | ||
576 | clear_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); | ||
577 | /* fall-through */ | ||
259 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | 578 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: |
260 | if (initiator) { | 579 | initiator = false; |
261 | ret = -EINVAL; | ||
262 | goto fail; | ||
263 | } | ||
264 | break; | 580 | break; |
265 | case WLAN_TDLS_TEARDOWN: | 581 | case WLAN_TDLS_TEARDOWN: |
266 | /* any value is ok */ | 582 | /* any value is ok */ |
267 | break; | 583 | break; |
268 | default: | 584 | default: |
269 | ret = -ENOTSUPP; | 585 | ret = -ENOTSUPP; |
270 | goto fail; | 586 | break; |
271 | } | 587 | } |
272 | 588 | ||
273 | if (initiator) { | 589 | if (sta && test_sta_flag(sta, WLAN_STA_TDLS_INITIATOR)) |
274 | init_addr = sdata->vif.addr; | 590 | initiator = true; |
275 | rsp_addr = peer; | ||
276 | } else { | ||
277 | init_addr = peer; | ||
278 | rsp_addr = sdata->vif.addr; | ||
279 | } | ||
280 | 591 | ||
281 | ieee80211_tdls_add_link_ie(skb, init_addr, rsp_addr, | 592 | rcu_read_unlock(); |
282 | sdata->u.mgd.bssid); | 593 | if (ret < 0) |
594 | goto fail; | ||
283 | 595 | ||
596 | ieee80211_tdls_add_ies(sdata, skb, peer, action_code, status_code, | ||
597 | initiator, extra_ies, extra_ies_len); | ||
284 | if (send_direct) { | 598 | if (send_direct) { |
285 | ieee80211_tx_skb(sdata, skb); | 599 | ieee80211_tx_skb(sdata, skb); |
286 | return 0; | 600 | return 0; |
@@ -327,8 +641,8 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, | |||
327 | mutex_lock(&local->mtx); | 641 | mutex_lock(&local->mtx); |
328 | 642 | ||
329 | /* we don't support concurrent TDLS peer setups */ | 643 | /* we don't support concurrent TDLS peer setups */ |
330 | if (!is_zero_ether_addr(sdata->tdls_peer) && | 644 | if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer) && |
331 | !ether_addr_equal(sdata->tdls_peer, peer)) { | 645 | !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) { |
332 | ret = -EBUSY; | 646 | ret = -EBUSY; |
333 | goto exit; | 647 | goto exit; |
334 | } | 648 | } |
@@ -336,15 +650,19 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, | |||
336 | /* | 650 | /* |
337 | * make sure we have a STA representing the peer so we drop or buffer | 651 | * make sure we have a STA representing the peer so we drop or buffer |
338 | * non-TDLS-setup frames to the peer. We can't send other packets | 652 | * non-TDLS-setup frames to the peer. We can't send other packets |
339 | * during setup through the AP path | 653 | * during setup through the AP path. |
654 | * Allow error packets to be sent - sometimes we don't even add a STA | ||
655 | * before failing the setup. | ||
340 | */ | 656 | */ |
341 | rcu_read_lock(); | 657 | if (status_code == 0) { |
342 | if (!sta_info_get(sdata, peer)) { | 658 | rcu_read_lock(); |
659 | if (!sta_info_get(sdata, peer)) { | ||
660 | rcu_read_unlock(); | ||
661 | ret = -ENOLINK; | ||
662 | goto exit; | ||
663 | } | ||
343 | rcu_read_unlock(); | 664 | rcu_read_unlock(); |
344 | ret = -ENOLINK; | ||
345 | goto exit; | ||
346 | } | 665 | } |
347 | rcu_read_unlock(); | ||
348 | 666 | ||
349 | ieee80211_flush_queues(local, sdata); | 667 | ieee80211_flush_queues(local, sdata); |
350 | 668 | ||
@@ -355,9 +673,9 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, | |||
355 | if (ret < 0) | 673 | if (ret < 0) |
356 | goto exit; | 674 | goto exit; |
357 | 675 | ||
358 | memcpy(sdata->tdls_peer, peer, ETH_ALEN); | 676 | memcpy(sdata->u.mgd.tdls_peer, peer, ETH_ALEN); |
359 | ieee80211_queue_delayed_work(&sdata->local->hw, | 677 | ieee80211_queue_delayed_work(&sdata->local->hw, |
360 | &sdata->tdls_peer_del_work, | 678 | &sdata->u.mgd.tdls_peer_del_work, |
361 | TDLS_PEER_SETUP_TIMEOUT); | 679 | TDLS_PEER_SETUP_TIMEOUT); |
362 | 680 | ||
363 | exit: | 681 | exit: |
@@ -513,11 +831,22 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | |||
513 | set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); | 831 | set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); |
514 | rcu_read_unlock(); | 832 | rcu_read_unlock(); |
515 | 833 | ||
516 | WARN_ON_ONCE(is_zero_ether_addr(sdata->tdls_peer) || | 834 | WARN_ON_ONCE(is_zero_ether_addr(sdata->u.mgd.tdls_peer) || |
517 | !ether_addr_equal(sdata->tdls_peer, peer)); | 835 | !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)); |
518 | ret = 0; | 836 | ret = 0; |
519 | break; | 837 | break; |
520 | case NL80211_TDLS_DISABLE_LINK: | 838 | case NL80211_TDLS_DISABLE_LINK: |
839 | /* | ||
840 | * The teardown message in ieee80211_tdls_mgmt_teardown() was | ||
841 | * created while the queues were stopped, so it might still be | ||
842 | * pending. Before flushing the queues we need to be sure the | ||
843 | * message is handled by the tasklet handling pending messages, | ||
844 | * otherwise we might start destroying the station before | ||
845 | * sending the teardown packet. | ||
846 | * Note that this only forces the tasklet to flush pendings - | ||
847 | * not to stop the tasklet from rescheduling itself. | ||
848 | */ | ||
849 | tasklet_kill(&local->tx_pending_tasklet); | ||
521 | /* flush a potentially queued teardown packet */ | 850 | /* flush a potentially queued teardown packet */ |
522 | ieee80211_flush_queues(local, sdata); | 851 | ieee80211_flush_queues(local, sdata); |
523 | 852 | ||
@@ -528,9 +857,9 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | |||
528 | break; | 857 | break; |
529 | } | 858 | } |
530 | 859 | ||
531 | if (ret == 0 && ether_addr_equal(sdata->tdls_peer, peer)) { | 860 | if (ret == 0 && ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) { |
532 | cancel_delayed_work(&sdata->tdls_peer_del_work); | 861 | cancel_delayed_work(&sdata->u.mgd.tdls_peer_del_work); |
533 | eth_zero_addr(sdata->tdls_peer); | 862 | eth_zero_addr(sdata->u.mgd.tdls_peer); |
534 | } | 863 | } |
535 | 864 | ||
536 | mutex_unlock(&local->mtx); | 865 | mutex_unlock(&local->mtx); |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index df1bb7e16cfe..725af7a468d2 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -3083,3 +3083,18 @@ int ieee80211_max_num_channels(struct ieee80211_local *local) | |||
3083 | 3083 | ||
3084 | return max_num_different_channels; | 3084 | return max_num_different_channels; |
3085 | } | 3085 | } |
3086 | |||
3087 | u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo) | ||
3088 | { | ||
3089 | *buf++ = WLAN_EID_VENDOR_SPECIFIC; | ||
3090 | *buf++ = 7; /* len */ | ||
3091 | *buf++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
3092 | *buf++ = 0x50; | ||
3093 | *buf++ = 0xf2; | ||
3094 | *buf++ = 2; /* WME */ | ||
3095 | *buf++ = 0; /* WME info */ | ||
3096 | *buf++ = 1; /* WME ver */ | ||
3097 | *buf++ = qosinfo; /* U-APSD no in use */ | ||
3098 | |||
3099 | return buf; | ||
3100 | } | ||
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 9265adfdabfc..671ce0d27a80 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -129,6 +129,10 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
129 | if (!vht_cap_ie || !sband->vht_cap.vht_supported) | 129 | if (!vht_cap_ie || !sband->vht_cap.vht_supported) |
130 | return; | 130 | return; |
131 | 131 | ||
132 | /* don't support VHT for TDLS peers for now */ | ||
133 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
134 | return; | ||
135 | |||
132 | /* | 136 | /* |
133 | * A VHT STA must support 40 MHz, but if we verify that here | 137 | * A VHT STA must support 40 MHz, but if we verify that here |
134 | * then we break a few things - some APs (e.g. Netgear R6300v2 | 138 | * then we break a few things - some APs (e.g. Netgear R6300v2 |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 9b3dcc201145..f7d4ca4c46e0 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -811,7 +811,7 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) | |||
811 | ieee80211_rx_result | 811 | ieee80211_rx_result |
812 | ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx) | 812 | ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx) |
813 | { | 813 | { |
814 | if (rx->sta->cipher_scheme) | 814 | if (rx->sta && rx->sta->cipher_scheme) |
815 | return ieee80211_crypto_cs_decrypt(rx); | 815 | return ieee80211_crypto_cs_decrypt(rx); |
816 | 816 | ||
817 | return RX_DROP_UNUSABLE; | 817 | return RX_DROP_UNUSABLE; |
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 405f3c4cf70c..29c8675f9a11 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig | |||
@@ -162,6 +162,12 @@ config CFG80211_INTERNAL_REGDB | |||
162 | and includes code to query that database. This is an alternative | 162 | and includes code to query that database. This is an alternative |
163 | to using CRDA for defining regulatory rules for the kernel. | 163 | to using CRDA for defining regulatory rules for the kernel. |
164 | 164 | ||
165 | Using this option requires some parsing of the db.txt at build time, | ||
166 | the parser will be upkept with the latest wireless-regdb updates but | ||
167 | older wireless-regdb formats will be ignored. The parser may later | ||
168 | be replaced to avoid issues with conflicts on versions of | ||
169 | wireless-regdb. | ||
170 | |||
165 | For details see: | 171 | For details see: |
166 | 172 | ||
167 | http://wireless.kernel.org/en/developers/Regulatory | 173 | http://wireless.kernel.org/en/developers/Regulatory |
diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index 40c37fc5b67c..baf2426b555a 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk | |||
@@ -51,32 +51,41 @@ function parse_country_head() { | |||
51 | 51 | ||
52 | function parse_reg_rule() | 52 | function parse_reg_rule() |
53 | { | 53 | { |
54 | flag_starts_at = 7 | ||
55 | |||
54 | start = $1 | 56 | start = $1 |
55 | sub(/\(/, "", start) | 57 | sub(/\(/, "", start) |
56 | end = $3 | 58 | end = $3 |
57 | bw = $5 | 59 | bw = $5 |
58 | sub(/\),/, "", bw) | 60 | sub(/\),/, "", bw) |
59 | gain = $6 | 61 | gain = 0 |
60 | sub(/\(/, "", gain) | 62 | power = $6 |
61 | sub(/,/, "", gain) | ||
62 | power = $7 | ||
63 | sub(/\)/, "", power) | ||
64 | sub(/,/, "", power) | ||
65 | # power might be in mW... | 63 | # power might be in mW... |
66 | units = $8 | 64 | units = $7 |
65 | dfs_cac = 0 | ||
66 | |||
67 | sub(/\(/, "", power) | ||
68 | sub(/\),/, "", power) | ||
69 | sub(/\),/, "", units) | ||
67 | sub(/\)/, "", units) | 70 | sub(/\)/, "", units) |
68 | sub(/,/, "", units) | 71 | |
69 | dfs_cac = $9 | ||
70 | if (units == "mW") { | 72 | if (units == "mW") { |
73 | flag_starts_at = 8 | ||
71 | power = 10 * log(power)/log(10) | 74 | power = 10 * log(power)/log(10) |
75 | if ($8 ~ /[[:digit:]]/) { | ||
76 | flag_starts_at = 9 | ||
77 | dfs_cac = $8 | ||
78 | } | ||
72 | } else { | 79 | } else { |
73 | dfs_cac = $8 | 80 | if ($7 ~ /[[:digit:]]/) { |
81 | flag_starts_at = 8 | ||
82 | dfs_cac = $7 | ||
83 | } | ||
74 | } | 84 | } |
75 | sub(/,/, "", dfs_cac) | ||
76 | sub(/\(/, "", dfs_cac) | 85 | sub(/\(/, "", dfs_cac) |
77 | sub(/\)/, "", dfs_cac) | 86 | sub(/\),/, "", dfs_cac) |
78 | flagstr = "" | 87 | flagstr = "" |
79 | for (i=8; i<=NF; i++) | 88 | for (i=flag_starts_at; i<=NF; i++) |
80 | flagstr = flagstr $i | 89 | flagstr = flagstr $i |
81 | split(flagstr, flagarray, ",") | 90 | split(flagstr, flagarray, ",") |
82 | flags = "" | 91 | flags = "" |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 082f5c62b8cf..df7b1332a1ec 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -3814,7 +3814,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy, | |||
3814 | { | 3814 | { |
3815 | if (params->listen_interval != -1) | 3815 | if (params->listen_interval != -1) |
3816 | return -EINVAL; | 3816 | return -EINVAL; |
3817 | if (params->aid) | 3817 | if (params->aid && |
3818 | !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) | ||
3818 | return -EINVAL; | 3819 | return -EINVAL; |
3819 | 3820 | ||
3820 | /* When you run into this, adjust the code below for the new flag */ | 3821 | /* When you run into this, adjust the code below for the new flag */ |