diff options
author | David S. Miller <davem@davemloft.net> | 2016-03-01 17:02:30 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-03-01 17:03:27 -0500 |
commit | d67703fcede6696667218d29f86b4ee6ae618de6 (patch) | |
tree | a099693d077e646848b8d9a1a5b6feae79045621 /net | |
parent | 4ec620700cda720ac7480ce92e8795d735ff1502 (diff) | |
parent | 50ee738d7271fe825e4024cdfa5c5301a871e2c2 (diff) |
Merge tag 'mac80211-next-for-davem-2016-02-26' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg says:
====================
Here's another round of updates for -next:
* big A-MSDU RX performance improvement (avoid linearize of paged RX)
* rfkill changes: cleanups, documentation, platform properties
* basic PBSS support in cfg80211
* MU-MIMO action frame processing support
* BlockAck reordering & duplicate detection offload support
* various cleanups & little fixes
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
40 files changed, 1096 insertions, 687 deletions
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 10ad4ac1fa0b..1b8a5caa221e 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | 8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> |
9 | * Copyright 2007-2010, Intel Corporation | 9 | * Copyright 2007-2010, Intel Corporation |
10 | * Copyright(c) 2015 Intel Deutschland GmbH | ||
10 | * | 11 | * |
11 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 13 | * it under the terms of the GNU General Public License version 2 as |
@@ -61,16 +62,25 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
61 | { | 62 | { |
62 | struct ieee80211_local *local = sta->local; | 63 | struct ieee80211_local *local = sta->local; |
63 | struct tid_ampdu_rx *tid_rx; | 64 | struct tid_ampdu_rx *tid_rx; |
65 | struct ieee80211_ampdu_params params = { | ||
66 | .sta = &sta->sta, | ||
67 | .action = IEEE80211_AMPDU_RX_STOP, | ||
68 | .tid = tid, | ||
69 | .amsdu = false, | ||
70 | .timeout = 0, | ||
71 | .ssn = 0, | ||
72 | }; | ||
64 | 73 | ||
65 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 74 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
66 | 75 | ||
67 | tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid], | 76 | tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid], |
68 | lockdep_is_held(&sta->ampdu_mlme.mtx)); | 77 | lockdep_is_held(&sta->ampdu_mlme.mtx)); |
69 | 78 | ||
70 | if (!tid_rx) | 79 | if (!test_bit(tid, sta->ampdu_mlme.agg_session_valid)) |
71 | return; | 80 | return; |
72 | 81 | ||
73 | RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL); | 82 | RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL); |
83 | __clear_bit(tid, sta->ampdu_mlme.agg_session_valid); | ||
74 | 84 | ||
75 | ht_dbg(sta->sdata, | 85 | ht_dbg(sta->sdata, |
76 | "Rx BA session stop requested for %pM tid %u %s reason: %d\n", | 86 | "Rx BA session stop requested for %pM tid %u %s reason: %d\n", |
@@ -78,8 +88,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
78 | initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator", | 88 | initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator", |
79 | (int)reason); | 89 | (int)reason); |
80 | 90 | ||
81 | if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP, | 91 | if (drv_ampdu_action(local, sta->sdata, ¶ms)) |
82 | &sta->sta, tid, NULL, 0, false)) | ||
83 | sdata_info(sta->sdata, | 92 | sdata_info(sta->sdata, |
84 | "HW problem - can not stop rx aggregation for %pM tid %d\n", | 93 | "HW problem - can not stop rx aggregation for %pM tid %d\n", |
85 | sta->sta.addr, tid); | 94 | sta->sta.addr, tid); |
@@ -89,6 +98,13 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
89 | ieee80211_send_delba(sta->sdata, sta->sta.addr, | 98 | ieee80211_send_delba(sta->sdata, sta->sta.addr, |
90 | tid, WLAN_BACK_RECIPIENT, reason); | 99 | tid, WLAN_BACK_RECIPIENT, reason); |
91 | 100 | ||
101 | /* | ||
102 | * return here in case tid_rx is not assigned - which will happen if | ||
103 | * IEEE80211_HW_SUPPORTS_REORDERING_BUFFER is set. | ||
104 | */ | ||
105 | if (!tid_rx) | ||
106 | return; | ||
107 | |||
92 | del_timer_sync(&tid_rx->session_timer); | 108 | del_timer_sync(&tid_rx->session_timer); |
93 | 109 | ||
94 | /* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */ | 110 | /* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */ |
@@ -237,6 +253,15 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, | |||
237 | { | 253 | { |
238 | struct ieee80211_local *local = sta->sdata->local; | 254 | struct ieee80211_local *local = sta->sdata->local; |
239 | struct tid_ampdu_rx *tid_agg_rx; | 255 | struct tid_ampdu_rx *tid_agg_rx; |
256 | struct ieee80211_ampdu_params params = { | ||
257 | .sta = &sta->sta, | ||
258 | .action = IEEE80211_AMPDU_RX_START, | ||
259 | .tid = tid, | ||
260 | .amsdu = false, | ||
261 | .timeout = timeout, | ||
262 | .ssn = start_seq_num, | ||
263 | }; | ||
264 | |||
240 | int i, ret = -EOPNOTSUPP; | 265 | int i, ret = -EOPNOTSUPP; |
241 | u16 status = WLAN_STATUS_REQUEST_DECLINED; | 266 | u16 status = WLAN_STATUS_REQUEST_DECLINED; |
242 | 267 | ||
@@ -275,11 +300,12 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, | |||
275 | /* make sure the size doesn't exceed the maximum supported by the hw */ | 300 | /* make sure the size doesn't exceed the maximum supported by the hw */ |
276 | if (buf_size > local->hw.max_rx_aggregation_subframes) | 301 | if (buf_size > local->hw.max_rx_aggregation_subframes) |
277 | buf_size = local->hw.max_rx_aggregation_subframes; | 302 | buf_size = local->hw.max_rx_aggregation_subframes; |
303 | params.buf_size = buf_size; | ||
278 | 304 | ||
279 | /* examine state machine */ | 305 | /* examine state machine */ |
280 | mutex_lock(&sta->ampdu_mlme.mtx); | 306 | mutex_lock(&sta->ampdu_mlme.mtx); |
281 | 307 | ||
282 | if (sta->ampdu_mlme.tid_rx[tid]) { | 308 | if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) { |
283 | ht_dbg_ratelimited(sta->sdata, | 309 | ht_dbg_ratelimited(sta->sdata, |
284 | "unexpected AddBA Req from %pM on tid %u\n", | 310 | "unexpected AddBA Req from %pM on tid %u\n", |
285 | sta->sta.addr, tid); | 311 | sta->sta.addr, tid); |
@@ -290,6 +316,16 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, | |||
290 | false); | 316 | false); |
291 | } | 317 | } |
292 | 318 | ||
319 | if (ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER)) { | ||
320 | ret = drv_ampdu_action(local, sta->sdata, ¶ms); | ||
321 | ht_dbg(sta->sdata, | ||
322 | "Rx A-MPDU request on %pM tid %d result %d\n", | ||
323 | sta->sta.addr, tid, ret); | ||
324 | if (!ret) | ||
325 | status = WLAN_STATUS_SUCCESS; | ||
326 | goto end; | ||
327 | } | ||
328 | |||
293 | /* prepare A-MPDU MLME for Rx aggregation */ | 329 | /* prepare A-MPDU MLME for Rx aggregation */ |
294 | tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL); | 330 | tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL); |
295 | if (!tid_agg_rx) | 331 | if (!tid_agg_rx) |
@@ -322,8 +358,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, | |||
322 | for (i = 0; i < buf_size; i++) | 358 | for (i = 0; i < buf_size; i++) |
323 | __skb_queue_head_init(&tid_agg_rx->reorder_buf[i]); | 359 | __skb_queue_head_init(&tid_agg_rx->reorder_buf[i]); |
324 | 360 | ||
325 | ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, | 361 | ret = drv_ampdu_action(local, sta->sdata, ¶ms); |
326 | &sta->sta, tid, &start_seq_num, 0, false); | ||
327 | ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n", | 362 | ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n", |
328 | sta->sta.addr, tid, ret); | 363 | sta->sta.addr, tid, ret); |
329 | if (ret) { | 364 | if (ret) { |
@@ -341,6 +376,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, | |||
341 | tid_agg_rx->timeout = timeout; | 376 | tid_agg_rx->timeout = timeout; |
342 | tid_agg_rx->stored_mpdu_num = 0; | 377 | tid_agg_rx->stored_mpdu_num = 0; |
343 | tid_agg_rx->auto_seq = auto_seq; | 378 | tid_agg_rx->auto_seq = auto_seq; |
379 | tid_agg_rx->reorder_buf_filtered = 0; | ||
344 | status = WLAN_STATUS_SUCCESS; | 380 | status = WLAN_STATUS_SUCCESS; |
345 | 381 | ||
346 | /* activate it for RX */ | 382 | /* activate it for RX */ |
@@ -352,6 +388,8 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, | |||
352 | } | 388 | } |
353 | 389 | ||
354 | end: | 390 | end: |
391 | if (status == WLAN_STATUS_SUCCESS) | ||
392 | __set_bit(tid, sta->ampdu_mlme.agg_session_valid); | ||
355 | mutex_unlock(&sta->ampdu_mlme.mtx); | 393 | mutex_unlock(&sta->ampdu_mlme.mtx); |
356 | 394 | ||
357 | end_no_lock: | 395 | end_no_lock: |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index ff757181b0a8..4932e9f243a2 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | 8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> |
9 | * Copyright 2007-2010, Intel Corporation | 9 | * Copyright 2007-2010, Intel Corporation |
10 | * Copyright(c) 2015 Intel Deutschland GmbH | ||
10 | * | 11 | * |
11 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 13 | * it under the terms of the GNU General Public License version 2 as |
@@ -295,7 +296,14 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
295 | { | 296 | { |
296 | struct ieee80211_local *local = sta->local; | 297 | struct ieee80211_local *local = sta->local; |
297 | struct tid_ampdu_tx *tid_tx; | 298 | struct tid_ampdu_tx *tid_tx; |
298 | enum ieee80211_ampdu_mlme_action action; | 299 | struct ieee80211_ampdu_params params = { |
300 | .sta = &sta->sta, | ||
301 | .tid = tid, | ||
302 | .buf_size = 0, | ||
303 | .amsdu = false, | ||
304 | .timeout = 0, | ||
305 | .ssn = 0, | ||
306 | }; | ||
299 | int ret; | 307 | int ret; |
300 | 308 | ||
301 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 309 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
@@ -304,10 +312,10 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
304 | case AGG_STOP_DECLINED: | 312 | case AGG_STOP_DECLINED: |
305 | case AGG_STOP_LOCAL_REQUEST: | 313 | case AGG_STOP_LOCAL_REQUEST: |
306 | case AGG_STOP_PEER_REQUEST: | 314 | case AGG_STOP_PEER_REQUEST: |
307 | action = IEEE80211_AMPDU_TX_STOP_CONT; | 315 | params.action = IEEE80211_AMPDU_TX_STOP_CONT; |
308 | break; | 316 | break; |
309 | case AGG_STOP_DESTROY_STA: | 317 | case AGG_STOP_DESTROY_STA: |
310 | action = IEEE80211_AMPDU_TX_STOP_FLUSH; | 318 | params.action = IEEE80211_AMPDU_TX_STOP_FLUSH; |
311 | break; | 319 | break; |
312 | default: | 320 | default: |
313 | WARN_ON_ONCE(1); | 321 | WARN_ON_ONCE(1); |
@@ -330,9 +338,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
330 | spin_unlock_bh(&sta->lock); | 338 | spin_unlock_bh(&sta->lock); |
331 | if (reason != AGG_STOP_DESTROY_STA) | 339 | if (reason != AGG_STOP_DESTROY_STA) |
332 | return -EALREADY; | 340 | return -EALREADY; |
333 | ret = drv_ampdu_action(local, sta->sdata, | 341 | params.action = IEEE80211_AMPDU_TX_STOP_FLUSH_CONT; |
334 | IEEE80211_AMPDU_TX_STOP_FLUSH_CONT, | 342 | ret = drv_ampdu_action(local, sta->sdata, ¶ms); |
335 | &sta->sta, tid, NULL, 0, false); | ||
336 | WARN_ON_ONCE(ret); | 343 | WARN_ON_ONCE(ret); |
337 | return 0; | 344 | return 0; |
338 | } | 345 | } |
@@ -381,8 +388,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
381 | WLAN_BACK_INITIATOR; | 388 | WLAN_BACK_INITIATOR; |
382 | tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST; | 389 | tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST; |
383 | 390 | ||
384 | ret = drv_ampdu_action(local, sta->sdata, action, | 391 | ret = drv_ampdu_action(local, sta->sdata, ¶ms); |
385 | &sta->sta, tid, NULL, 0, false); | ||
386 | 392 | ||
387 | /* HW shall not deny going back to legacy */ | 393 | /* HW shall not deny going back to legacy */ |
388 | if (WARN_ON(ret)) { | 394 | if (WARN_ON(ret)) { |
@@ -445,7 +451,14 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
445 | struct tid_ampdu_tx *tid_tx; | 451 | struct tid_ampdu_tx *tid_tx; |
446 | struct ieee80211_local *local = sta->local; | 452 | struct ieee80211_local *local = sta->local; |
447 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 453 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
448 | u16 start_seq_num; | 454 | struct ieee80211_ampdu_params params = { |
455 | .sta = &sta->sta, | ||
456 | .action = IEEE80211_AMPDU_TX_START, | ||
457 | .tid = tid, | ||
458 | .buf_size = 0, | ||
459 | .amsdu = false, | ||
460 | .timeout = 0, | ||
461 | }; | ||
449 | int ret; | 462 | int ret; |
450 | 463 | ||
451 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | 464 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
@@ -467,10 +480,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
467 | */ | 480 | */ |
468 | synchronize_net(); | 481 | synchronize_net(); |
469 | 482 | ||
470 | start_seq_num = sta->tid_seq[tid] >> 4; | 483 | params.ssn = sta->tid_seq[tid] >> 4; |
471 | 484 | ret = drv_ampdu_action(local, sdata, ¶ms); | |
472 | ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, | ||
473 | &sta->sta, tid, &start_seq_num, 0, false); | ||
474 | if (ret) { | 485 | if (ret) { |
475 | ht_dbg(sdata, | 486 | ht_dbg(sdata, |
476 | "BA request denied - HW unavailable for %pM tid %d\n", | 487 | "BA request denied - HW unavailable for %pM tid %d\n", |
@@ -499,7 +510,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
499 | 510 | ||
500 | /* send AddBA request */ | 511 | /* send AddBA request */ |
501 | ieee80211_send_addba_request(sdata, sta->sta.addr, tid, | 512 | ieee80211_send_addba_request(sdata, sta->sta.addr, tid, |
502 | tid_tx->dialog_token, start_seq_num, | 513 | tid_tx->dialog_token, params.ssn, |
503 | IEEE80211_MAX_AMPDU_BUF, | 514 | IEEE80211_MAX_AMPDU_BUF, |
504 | tid_tx->timeout); | 515 | tid_tx->timeout); |
505 | } | 516 | } |
@@ -684,18 +695,24 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | |||
684 | struct sta_info *sta, u16 tid) | 695 | struct sta_info *sta, u16 tid) |
685 | { | 696 | { |
686 | struct tid_ampdu_tx *tid_tx; | 697 | struct tid_ampdu_tx *tid_tx; |
698 | struct ieee80211_ampdu_params params = { | ||
699 | .sta = &sta->sta, | ||
700 | .action = IEEE80211_AMPDU_TX_OPERATIONAL, | ||
701 | .tid = tid, | ||
702 | .timeout = 0, | ||
703 | .ssn = 0, | ||
704 | }; | ||
687 | 705 | ||
688 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 706 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
689 | 707 | ||
690 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | 708 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
709 | params.buf_size = tid_tx->buf_size; | ||
710 | params.amsdu = tid_tx->amsdu; | ||
691 | 711 | ||
692 | ht_dbg(sta->sdata, "Aggregation is on for %pM tid %d\n", | 712 | ht_dbg(sta->sdata, "Aggregation is on for %pM tid %d\n", |
693 | sta->sta.addr, tid); | 713 | sta->sta.addr, tid); |
694 | 714 | ||
695 | drv_ampdu_action(local, sta->sdata, | 715 | drv_ampdu_action(local, sta->sdata, ¶ms); |
696 | IEEE80211_AMPDU_TX_OPERATIONAL, | ||
697 | &sta->sta, tid, NULL, tid_tx->buf_size, | ||
698 | tid_tx->amsdu); | ||
699 | 716 | ||
700 | /* | 717 | /* |
701 | * synchronize with TX path, while splicing the TX path | 718 | * synchronize with TX path, while splicing the TX path |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 166a29fe6c35..fe1704c4e8fb 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -339,8 +339,9 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
339 | 339 | ||
340 | switch (key->conf.cipher) { | 340 | switch (key->conf.cipher) { |
341 | case WLAN_CIPHER_SUITE_TKIP: | 341 | case WLAN_CIPHER_SUITE_TKIP: |
342 | iv32 = key->u.tkip.tx.iv32; | 342 | pn64 = atomic64_read(&key->conf.tx_pn); |
343 | iv16 = key->u.tkip.tx.iv16; | 343 | iv32 = TKIP_PN_TO_IV32(pn64); |
344 | iv16 = TKIP_PN_TO_IV16(pn64); | ||
344 | 345 | ||
345 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && | 346 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && |
346 | !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { | 347 | !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { |
@@ -1131,6 +1132,34 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1131 | sta->sta.max_sp = params->max_sp; | 1132 | sta->sta.max_sp = params->max_sp; |
1132 | } | 1133 | } |
1133 | 1134 | ||
1135 | /* The sender might not have sent the last bit, consider it to be 0 */ | ||
1136 | if (params->ext_capab_len >= 8) { | ||
1137 | u8 val = (params->ext_capab[7] & | ||
1138 | WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB) >> 7; | ||
1139 | |||
1140 | /* we did get all the bits, take the MSB as well */ | ||
1141 | if (params->ext_capab_len >= 9) { | ||
1142 | u8 val_msb = params->ext_capab[8] & | ||
1143 | WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB; | ||
1144 | val_msb <<= 1; | ||
1145 | val |= val_msb; | ||
1146 | } | ||
1147 | |||
1148 | switch (val) { | ||
1149 | case 1: | ||
1150 | sta->sta.max_amsdu_subframes = 32; | ||
1151 | break; | ||
1152 | case 2: | ||
1153 | sta->sta.max_amsdu_subframes = 16; | ||
1154 | break; | ||
1155 | case 3: | ||
1156 | sta->sta.max_amsdu_subframes = 8; | ||
1157 | break; | ||
1158 | default: | ||
1159 | sta->sta.max_amsdu_subframes = 0; | ||
1160 | } | ||
1161 | } | ||
1162 | |||
1134 | /* | 1163 | /* |
1135 | * cfg80211 validates this (1-2007) and allows setting the AID | 1164 | * cfg80211 validates this (1-2007) and allows setting the AID |
1136 | * only when creating a new station entry | 1165 | * only when creating a new station entry |
@@ -1160,6 +1189,7 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1160 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 1189 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
1161 | params->ht_capa, sta); | 1190 | params->ht_capa, sta); |
1162 | 1191 | ||
1192 | /* VHT can override some HT caps such as the A-MSDU max length */ | ||
1163 | if (params->vht_capa) | 1193 | if (params->vht_capa) |
1164 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | 1194 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
1165 | params->vht_capa, sta); | 1195 | params->vht_capa, sta); |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 1d1b9b7bdefe..283981108ca8 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -231,7 +231,7 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata) | |||
231 | !(sta->sdata->bss && sta->sdata->bss == sdata->bss)) | 231 | !(sta->sdata->bss && sta->sdata->bss == sdata->bss)) |
232 | continue; | 232 | continue; |
233 | 233 | ||
234 | if (!sta->uploaded) | 234 | if (!sta->uploaded || !test_sta_flag(sta, WLAN_STA_ASSOC)) |
235 | continue; | 235 | continue; |
236 | 236 | ||
237 | max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta)); | 237 | max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta)); |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 3e24d0ddb51b..4ab5c522ceee 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -126,6 +126,7 @@ static const char *hw_flag_names[] = { | |||
126 | FLAG(SUPPORTS_AMSDU_IN_AMPDU), | 126 | FLAG(SUPPORTS_AMSDU_IN_AMPDU), |
127 | FLAG(BEACON_TX_STATUS), | 127 | FLAG(BEACON_TX_STATUS), |
128 | FLAG(NEEDS_UNIQUE_STA_ADDR), | 128 | FLAG(NEEDS_UNIQUE_STA_ADDR), |
129 | FLAG(SUPPORTS_REORDERING_BUFFER), | ||
129 | #undef FLAG | 130 | #undef FLAG |
130 | }; | 131 | }; |
131 | 132 | ||
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 7961e7d0b61e..a2ef95f16f11 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -132,9 +132,10 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, | |||
132 | len = scnprintf(buf, sizeof(buf), "\n"); | 132 | len = scnprintf(buf, sizeof(buf), "\n"); |
133 | break; | 133 | break; |
134 | case WLAN_CIPHER_SUITE_TKIP: | 134 | case WLAN_CIPHER_SUITE_TKIP: |
135 | pn = atomic64_read(&key->conf.tx_pn); | ||
135 | len = scnprintf(buf, sizeof(buf), "%08x %04x\n", | 136 | len = scnprintf(buf, sizeof(buf), "%08x %04x\n", |
136 | key->u.tkip.tx.iv32, | 137 | TKIP_PN_TO_IV32(pn), |
137 | key->u.tkip.tx.iv16); | 138 | TKIP_PN_TO_IV16(pn)); |
138 | break; | 139 | break; |
139 | case WLAN_CIPHER_SUITE_CCMP: | 140 | case WLAN_CIPHER_SUITE_CCMP: |
140 | case WLAN_CIPHER_SUITE_CCMP_256: | 141 | case WLAN_CIPHER_SUITE_CCMP_256: |
diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c index ca1fe5576103..c258f1041d33 100644 --- a/net/mac80211/driver-ops.c +++ b/net/mac80211/driver-ops.c | |||
@@ -284,9 +284,7 @@ int drv_switch_vif_chanctx(struct ieee80211_local *local, | |||
284 | 284 | ||
285 | int drv_ampdu_action(struct ieee80211_local *local, | 285 | int drv_ampdu_action(struct ieee80211_local *local, |
286 | struct ieee80211_sub_if_data *sdata, | 286 | struct ieee80211_sub_if_data *sdata, |
287 | enum ieee80211_ampdu_mlme_action action, | 287 | struct ieee80211_ampdu_params *params) |
288 | struct ieee80211_sta *sta, u16 tid, | ||
289 | u16 *ssn, u8 buf_size, bool amsdu) | ||
290 | { | 288 | { |
291 | int ret = -EOPNOTSUPP; | 289 | int ret = -EOPNOTSUPP; |
292 | 290 | ||
@@ -296,12 +294,10 @@ int drv_ampdu_action(struct ieee80211_local *local, | |||
296 | if (!check_sdata_in_driver(sdata)) | 294 | if (!check_sdata_in_driver(sdata)) |
297 | return -EIO; | 295 | return -EIO; |
298 | 296 | ||
299 | trace_drv_ampdu_action(local, sdata, action, sta, tid, | 297 | trace_drv_ampdu_action(local, sdata, params); |
300 | ssn, buf_size, amsdu); | ||
301 | 298 | ||
302 | if (local->ops->ampdu_action) | 299 | if (local->ops->ampdu_action) |
303 | ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action, | 300 | ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params); |
304 | sta, tid, ssn, buf_size, amsdu); | ||
305 | 301 | ||
306 | trace_drv_return_int(local, ret); | 302 | trace_drv_return_int(local, ret); |
307 | 303 | ||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 154ce4b13406..18b0d65baff0 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -585,9 +585,7 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local) | |||
585 | 585 | ||
586 | int drv_ampdu_action(struct ieee80211_local *local, | 586 | int drv_ampdu_action(struct ieee80211_local *local, |
587 | struct ieee80211_sub_if_data *sdata, | 587 | struct ieee80211_sub_if_data *sdata, |
588 | enum ieee80211_ampdu_mlme_action action, | 588 | struct ieee80211_ampdu_params *params); |
589 | struct ieee80211_sta *sta, u16 tid, | ||
590 | u16 *ssn, u8 buf_size, bool amsdu); | ||
591 | 589 | ||
592 | static inline int drv_get_survey(struct ieee80211_local *local, int idx, | 590 | static inline int drv_get_survey(struct ieee80211_local *local, int idx, |
593 | struct survey_info *survey) | 591 | struct survey_info *survey) |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 7a76ce639d58..f4a528773563 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -230,6 +230,11 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
230 | /* set Rx highest rate */ | 230 | /* set Rx highest rate */ |
231 | ht_cap.mcs.rx_highest = ht_cap_ie->mcs.rx_highest; | 231 | ht_cap.mcs.rx_highest = ht_cap_ie->mcs.rx_highest; |
232 | 232 | ||
233 | if (ht_cap.cap & IEEE80211_HT_CAP_MAX_AMSDU) | ||
234 | sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_7935; | ||
235 | else | ||
236 | sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_3839; | ||
237 | |||
233 | apply: | 238 | apply: |
234 | changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); | 239 | changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); |
235 | 240 | ||
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 978d3bc31df7..fc3238376b39 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | 7 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> |
8 | * Copyright 2009, Johannes Berg <johannes@sipsolutions.net> | 8 | * Copyright 2009, Johannes Berg <johannes@sipsolutions.net> |
9 | * Copyright 2013-2014 Intel Mobile Communications GmbH | 9 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
10 | * Copyright(c) 2016 Intel Deutschland GmbH | ||
10 | * | 11 | * |
11 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 13 | * it under the terms of the GNU General Public License version 2 as |
@@ -1050,9 +1051,8 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata, | |||
1050 | struct cfg80211_chan_def chandef; | 1051 | struct cfg80211_chan_def chandef; |
1051 | enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth; | 1052 | enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth; |
1052 | 1053 | ||
1053 | ieee80211_ht_oper_to_chandef(channel, | 1054 | cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT); |
1054 | elems->ht_operation, | 1055 | ieee80211_chandef_ht_oper(elems->ht_operation, &chandef); |
1055 | &chandef); | ||
1056 | 1056 | ||
1057 | memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie)); | 1057 | memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie)); |
1058 | rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 1058 | rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
@@ -1066,9 +1066,8 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata, | |||
1066 | struct ieee80211_vht_cap cap_ie; | 1066 | struct ieee80211_vht_cap cap_ie; |
1067 | struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap; | 1067 | struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap; |
1068 | 1068 | ||
1069 | ieee80211_vht_oper_to_chandef(channel, | 1069 | ieee80211_chandef_vht_oper(elems->vht_operation, |
1070 | elems->vht_operation, | 1070 | &chandef); |
1071 | &chandef); | ||
1072 | memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie)); | 1071 | memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie)); |
1073 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | 1072 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
1074 | &cap_ie, sta); | 1073 | &cap_ie, sta); |
@@ -1485,14 +1484,21 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
1485 | 1484 | ||
1486 | sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); | 1485 | sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); |
1487 | 1486 | ||
1488 | num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy, | ||
1489 | &ifibss->chandef, | ||
1490 | channels, | ||
1491 | ARRAY_SIZE(channels)); | ||
1492 | scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef); | 1487 | scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef); |
1493 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, | 1488 | |
1494 | ifibss->ssid_len, channels, num, | 1489 | if (ifibss->fixed_channel) { |
1495 | scan_width); | 1490 | num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy, |
1491 | &ifibss->chandef, | ||
1492 | channels, | ||
1493 | ARRAY_SIZE(channels)); | ||
1494 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, | ||
1495 | ifibss->ssid_len, channels, | ||
1496 | num, scan_width); | ||
1497 | } else { | ||
1498 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, | ||
1499 | ifibss->ssid_len, NULL, | ||
1500 | 0, scan_width); | ||
1501 | } | ||
1496 | } else { | 1502 | } else { |
1497 | int interval = IEEE80211_SCAN_INTERVAL; | 1503 | int interval = IEEE80211_SCAN_INTERVAL; |
1498 | 1504 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b84f6aa32c08..1630975c89f1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -716,7 +716,6 @@ struct ieee80211_if_mesh { | |||
716 | * back to wireless media and to the local net stack. | 716 | * back to wireless media and to the local net stack. |
717 | * @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume. | 717 | * @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume. |
718 | * @IEEE80211_SDATA_IN_DRIVER: indicates interface was added to driver | 718 | * @IEEE80211_SDATA_IN_DRIVER: indicates interface was added to driver |
719 | * @IEEE80211_SDATA_MU_MIMO_OWNER: indicates interface owns MU-MIMO capability | ||
720 | */ | 719 | */ |
721 | enum ieee80211_sub_if_data_flags { | 720 | enum ieee80211_sub_if_data_flags { |
722 | IEEE80211_SDATA_ALLMULTI = BIT(0), | 721 | IEEE80211_SDATA_ALLMULTI = BIT(0), |
@@ -724,7 +723,6 @@ enum ieee80211_sub_if_data_flags { | |||
724 | IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3), | 723 | IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3), |
725 | IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4), | 724 | IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4), |
726 | IEEE80211_SDATA_IN_DRIVER = BIT(5), | 725 | IEEE80211_SDATA_IN_DRIVER = BIT(5), |
727 | IEEE80211_SDATA_MU_MIMO_OWNER = BIT(6), | ||
728 | }; | 726 | }; |
729 | 727 | ||
730 | /** | 728 | /** |
@@ -804,6 +802,7 @@ enum txq_info_flags { | |||
804 | struct txq_info { | 802 | struct txq_info { |
805 | struct sk_buff_head queue; | 803 | struct sk_buff_head queue; |
806 | unsigned long flags; | 804 | unsigned long flags; |
805 | unsigned long byte_cnt; | ||
807 | 806 | ||
808 | /* keep last! */ | 807 | /* keep last! */ |
809 | struct ieee80211_txq txq; | 808 | struct ieee80211_txq txq; |
@@ -1466,7 +1465,13 @@ ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status) | |||
1466 | { | 1465 | { |
1467 | WARN_ON_ONCE(status->flag & RX_FLAG_MACTIME_START && | 1466 | WARN_ON_ONCE(status->flag & RX_FLAG_MACTIME_START && |
1468 | status->flag & RX_FLAG_MACTIME_END); | 1467 | status->flag & RX_FLAG_MACTIME_END); |
1469 | return status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END); | 1468 | if (status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END)) |
1469 | return true; | ||
1470 | /* can't handle HT/VHT preamble yet */ | ||
1471 | if (status->flag & RX_FLAG_MACTIME_PLCP_START && | ||
1472 | !(status->flag & (RX_FLAG_HT | RX_FLAG_VHT))) | ||
1473 | return true; | ||
1474 | return false; | ||
1470 | } | 1475 | } |
1471 | 1476 | ||
1472 | u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | 1477 | u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, |
@@ -1714,6 +1719,8 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
1714 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta); | 1719 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta); |
1715 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta); | 1720 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta); |
1716 | void ieee80211_sta_set_rx_nss(struct sta_info *sta); | 1721 | void ieee80211_sta_set_rx_nss(struct sta_info *sta); |
1722 | void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata, | ||
1723 | struct ieee80211_mgmt *mgmt); | ||
1717 | u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | 1724 | u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, |
1718 | struct sta_info *sta, u8 opmode, | 1725 | struct sta_info *sta, u8 opmode, |
1719 | enum ieee80211_band band); | 1726 | enum ieee80211_band band); |
@@ -1829,20 +1836,6 @@ static inline void ieee802_11_parse_elems(const u8 *start, size_t len, | |||
1829 | ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0); | 1836 | ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0); |
1830 | } | 1837 | } |
1831 | 1838 | ||
1832 | static inline bool ieee80211_rx_reorder_ready(struct sk_buff_head *frames) | ||
1833 | { | ||
1834 | struct sk_buff *tail = skb_peek_tail(frames); | ||
1835 | struct ieee80211_rx_status *status; | ||
1836 | |||
1837 | if (!tail) | ||
1838 | return false; | ||
1839 | |||
1840 | status = IEEE80211_SKB_RXCB(tail); | ||
1841 | if (status->flag & RX_FLAG_AMSDU_MORE) | ||
1842 | return false; | ||
1843 | |||
1844 | return true; | ||
1845 | } | ||
1846 | 1839 | ||
1847 | extern const int ieee802_1d_to_ac[8]; | 1840 | extern const int ieee802_1d_to_ac[8]; |
1848 | 1841 | ||
@@ -1986,12 +1979,10 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | |||
1986 | u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo); | 1979 | u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo); |
1987 | 1980 | ||
1988 | /* channel management */ | 1981 | /* channel management */ |
1989 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, | 1982 | bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper, |
1990 | const struct ieee80211_ht_operation *ht_oper, | 1983 | struct cfg80211_chan_def *chandef); |
1991 | struct cfg80211_chan_def *chandef); | 1984 | bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper, |
1992 | void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan, | 1985 | struct cfg80211_chan_def *chandef); |
1993 | const struct ieee80211_vht_operation *oper, | ||
1994 | struct cfg80211_chan_def *chandef); | ||
1995 | u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c); | 1986 | u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c); |
1996 | 1987 | ||
1997 | int __must_check | 1988 | int __must_check |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index c9e325d2e120..453b4e741780 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -977,7 +977,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
977 | if (sdata->vif.txq) { | 977 | if (sdata->vif.txq) { |
978 | struct txq_info *txqi = to_txq_info(sdata->vif.txq); | 978 | struct txq_info *txqi = to_txq_info(sdata->vif.txq); |
979 | 979 | ||
980 | spin_lock_bh(&txqi->queue.lock); | ||
980 | ieee80211_purge_tx_queue(&local->hw, &txqi->queue); | 981 | ieee80211_purge_tx_queue(&local->hw, &txqi->queue); |
982 | txqi->byte_cnt = 0; | ||
983 | spin_unlock_bh(&txqi->queue.lock); | ||
984 | |||
981 | atomic_set(&sdata->txqs_len[txqi->txq.ac], 0); | 985 | atomic_set(&sdata->txqs_len[txqi->txq.ac], 0); |
982 | } | 986 | } |
983 | 987 | ||
@@ -1271,6 +1275,16 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
1271 | } | 1275 | } |
1272 | } | 1276 | } |
1273 | mutex_unlock(&local->sta_mtx); | 1277 | mutex_unlock(&local->sta_mtx); |
1278 | } else if (ieee80211_is_action(mgmt->frame_control) && | ||
1279 | mgmt->u.action.category == WLAN_CATEGORY_VHT) { | ||
1280 | switch (mgmt->u.action.u.vht_group_notif.action_code) { | ||
1281 | case WLAN_VHT_ACTION_GROUPID_MGMT: | ||
1282 | ieee80211_process_mu_groups(sdata, mgmt); | ||
1283 | break; | ||
1284 | default: | ||
1285 | WARN_ON(1); | ||
1286 | break; | ||
1287 | } | ||
1274 | } else if (ieee80211_is_data_qos(mgmt->frame_control)) { | 1288 | } else if (ieee80211_is_data_qos(mgmt->frame_control)) { |
1275 | struct ieee80211_hdr *hdr = (void *)mgmt; | 1289 | struct ieee80211_hdr *hdr = (void *)mgmt; |
1276 | /* | 1290 | /* |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 5e5bc599da4c..3df7b0392d30 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -932,50 +932,6 @@ void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid, | |||
932 | } | 932 | } |
933 | EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_notify); | 933 | EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_notify); |
934 | 934 | ||
935 | void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf, | ||
936 | struct ieee80211_key_seq *seq) | ||
937 | { | ||
938 | struct ieee80211_key *key; | ||
939 | u64 pn64; | ||
940 | |||
941 | if (WARN_ON(!(keyconf->flags & IEEE80211_KEY_FLAG_GENERATE_IV))) | ||
942 | return; | ||
943 | |||
944 | key = container_of(keyconf, struct ieee80211_key, conf); | ||
945 | |||
946 | switch (key->conf.cipher) { | ||
947 | case WLAN_CIPHER_SUITE_TKIP: | ||
948 | seq->tkip.iv32 = key->u.tkip.tx.iv32; | ||
949 | seq->tkip.iv16 = key->u.tkip.tx.iv16; | ||
950 | break; | ||
951 | case WLAN_CIPHER_SUITE_CCMP: | ||
952 | case WLAN_CIPHER_SUITE_CCMP_256: | ||
953 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
954 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
955 | BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) != | ||
956 | offsetof(typeof(*seq), aes_cmac)); | ||
957 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
958 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
959 | BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) != | ||
960 | offsetof(typeof(*seq), aes_gmac)); | ||
961 | case WLAN_CIPHER_SUITE_GCMP: | ||
962 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
963 | BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) != | ||
964 | offsetof(typeof(*seq), gcmp)); | ||
965 | pn64 = atomic64_read(&key->conf.tx_pn); | ||
966 | seq->ccmp.pn[5] = pn64; | ||
967 | seq->ccmp.pn[4] = pn64 >> 8; | ||
968 | seq->ccmp.pn[3] = pn64 >> 16; | ||
969 | seq->ccmp.pn[2] = pn64 >> 24; | ||
970 | seq->ccmp.pn[1] = pn64 >> 32; | ||
971 | seq->ccmp.pn[0] = pn64 >> 40; | ||
972 | break; | ||
973 | default: | ||
974 | WARN_ON(1); | ||
975 | } | ||
976 | } | ||
977 | EXPORT_SYMBOL(ieee80211_get_key_tx_seq); | ||
978 | |||
979 | void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, | 935 | void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, |
980 | int tid, struct ieee80211_key_seq *seq) | 936 | int tid, struct ieee80211_key_seq *seq) |
981 | { | 937 | { |
@@ -1029,48 +985,6 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, | |||
1029 | } | 985 | } |
1030 | EXPORT_SYMBOL(ieee80211_get_key_rx_seq); | 986 | EXPORT_SYMBOL(ieee80211_get_key_rx_seq); |
1031 | 987 | ||
1032 | void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf, | ||
1033 | struct ieee80211_key_seq *seq) | ||
1034 | { | ||
1035 | struct ieee80211_key *key; | ||
1036 | u64 pn64; | ||
1037 | |||
1038 | key = container_of(keyconf, struct ieee80211_key, conf); | ||
1039 | |||
1040 | switch (key->conf.cipher) { | ||
1041 | case WLAN_CIPHER_SUITE_TKIP: | ||
1042 | key->u.tkip.tx.iv32 = seq->tkip.iv32; | ||
1043 | key->u.tkip.tx.iv16 = seq->tkip.iv16; | ||
1044 | break; | ||
1045 | case WLAN_CIPHER_SUITE_CCMP: | ||
1046 | case WLAN_CIPHER_SUITE_CCMP_256: | ||
1047 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
1048 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
1049 | BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) != | ||
1050 | offsetof(typeof(*seq), aes_cmac)); | ||
1051 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
1052 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
1053 | BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) != | ||
1054 | offsetof(typeof(*seq), aes_gmac)); | ||
1055 | case WLAN_CIPHER_SUITE_GCMP: | ||
1056 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
1057 | BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) != | ||
1058 | offsetof(typeof(*seq), gcmp)); | ||
1059 | pn64 = (u64)seq->ccmp.pn[5] | | ||
1060 | ((u64)seq->ccmp.pn[4] << 8) | | ||
1061 | ((u64)seq->ccmp.pn[3] << 16) | | ||
1062 | ((u64)seq->ccmp.pn[2] << 24) | | ||
1063 | ((u64)seq->ccmp.pn[1] << 32) | | ||
1064 | ((u64)seq->ccmp.pn[0] << 40); | ||
1065 | atomic64_set(&key->conf.tx_pn, pn64); | ||
1066 | break; | ||
1067 | default: | ||
1068 | WARN_ON(1); | ||
1069 | break; | ||
1070 | } | ||
1071 | } | ||
1072 | EXPORT_SYMBOL_GPL(ieee80211_set_key_tx_seq); | ||
1073 | |||
1074 | void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf, | 988 | void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf, |
1075 | int tid, struct ieee80211_key_seq *seq) | 989 | int tid, struct ieee80211_key_seq *seq) |
1076 | { | 990 | { |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 9951ef06323e..4aa20cef0859 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -44,13 +44,17 @@ enum ieee80211_internal_tkip_state { | |||
44 | }; | 44 | }; |
45 | 45 | ||
46 | struct tkip_ctx { | 46 | struct tkip_ctx { |
47 | u32 iv32; /* current iv32 */ | ||
48 | u16 iv16; /* current iv16 */ | ||
49 | u16 p1k[5]; /* p1k cache */ | 47 | u16 p1k[5]; /* p1k cache */ |
50 | u32 p1k_iv32; /* iv32 for which p1k computed */ | 48 | u32 p1k_iv32; /* iv32 for which p1k computed */ |
51 | enum ieee80211_internal_tkip_state state; | 49 | enum ieee80211_internal_tkip_state state; |
52 | }; | 50 | }; |
53 | 51 | ||
52 | struct tkip_ctx_rx { | ||
53 | struct tkip_ctx ctx; | ||
54 | u32 iv32; /* current iv32 */ | ||
55 | u16 iv16; /* current iv16 */ | ||
56 | }; | ||
57 | |||
54 | struct ieee80211_key { | 58 | struct ieee80211_key { |
55 | struct ieee80211_local *local; | 59 | struct ieee80211_local *local; |
56 | struct ieee80211_sub_if_data *sdata; | 60 | struct ieee80211_sub_if_data *sdata; |
@@ -71,7 +75,7 @@ struct ieee80211_key { | |||
71 | struct tkip_ctx tx; | 75 | struct tkip_ctx tx; |
72 | 76 | ||
73 | /* last received RSC */ | 77 | /* last received RSC */ |
74 | struct tkip_ctx rx[IEEE80211_NUM_TIDS]; | 78 | struct tkip_ctx_rx rx[IEEE80211_NUM_TIDS]; |
75 | 79 | ||
76 | /* number of mic failures */ | 80 | /* number of mic failures */ |
77 | u32 mic_failures; | 81 | u32 mic_failures; |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 6f85b6ab8e51..d32cefcb63b0 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -91,11 +91,10 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, | |||
91 | if (sdata->vif.bss_conf.basic_rates != basic_rates) | 91 | if (sdata->vif.bss_conf.basic_rates != basic_rates) |
92 | return false; | 92 | return false; |
93 | 93 | ||
94 | ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, | 94 | cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chandef.chan, |
95 | ie->ht_operation, &sta_chan_def); | 95 | NL80211_CHAN_NO_HT); |
96 | 96 | ieee80211_chandef_ht_oper(ie->ht_operation, &sta_chan_def); | |
97 | ieee80211_vht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, | 97 | ieee80211_chandef_vht_oper(ie->vht_operation, &sta_chan_def); |
98 | ie->vht_operation, &sta_chan_def); | ||
99 | 98 | ||
100 | if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef, | 99 | if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef, |
101 | &sta_chan_def)) | 100 | &sta_chan_def)) |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 4a8019f79fb2..87c017a3b1ce 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -137,8 +137,6 @@ struct mesh_path { | |||
137 | * @copy_node: function to copy nodes of the table | 137 | * @copy_node: function to copy nodes of the table |
138 | * @size_order: determines size of the table, there will be 2^size_order hash | 138 | * @size_order: determines size of the table, there will be 2^size_order hash |
139 | * buckets | 139 | * buckets |
140 | * @mean_chain_len: maximum average length for the hash buckets' list, if it is | ||
141 | * reached, the table will grow | ||
142 | * @known_gates: list of known mesh gates and their mpaths by the station. The | 140 | * @known_gates: list of known mesh gates and their mpaths by the station. The |
143 | * gate's mpath may or may not be resolved and active. | 141 | * gate's mpath may or may not be resolved and active. |
144 | * | 142 | * |
@@ -154,7 +152,6 @@ struct mesh_table { | |||
154 | void (*free_node) (struct hlist_node *p, bool free_leafs); | 152 | void (*free_node) (struct hlist_node *p, bool free_leafs); |
155 | int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl); | 153 | int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl); |
156 | int size_order; | 154 | int size_order; |
157 | int mean_chain_len; | ||
158 | struct hlist_head *known_gates; | 155 | struct hlist_head *known_gates; |
159 | spinlock_t gates_lock; | 156 | spinlock_t gates_lock; |
160 | 157 | ||
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index dadf8dc6f1cf..2ba7aa56b11c 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -55,16 +55,21 @@ int mpp_paths_generation; | |||
55 | static DEFINE_RWLOCK(pathtbl_resize_lock); | 55 | static DEFINE_RWLOCK(pathtbl_resize_lock); |
56 | 56 | ||
57 | 57 | ||
58 | static inline struct mesh_table *resize_dereference_paths( | ||
59 | struct mesh_table __rcu *table) | ||
60 | { | ||
61 | return rcu_dereference_protected(table, | ||
62 | lockdep_is_held(&pathtbl_resize_lock)); | ||
63 | } | ||
64 | |||
58 | static inline struct mesh_table *resize_dereference_mesh_paths(void) | 65 | static inline struct mesh_table *resize_dereference_mesh_paths(void) |
59 | { | 66 | { |
60 | return rcu_dereference_protected(mesh_paths, | 67 | return resize_dereference_paths(mesh_paths); |
61 | lockdep_is_held(&pathtbl_resize_lock)); | ||
62 | } | 68 | } |
63 | 69 | ||
64 | static inline struct mesh_table *resize_dereference_mpp_paths(void) | 70 | static inline struct mesh_table *resize_dereference_mpp_paths(void) |
65 | { | 71 | { |
66 | return rcu_dereference_protected(mpp_paths, | 72 | return resize_dereference_paths(mpp_paths); |
67 | lockdep_is_held(&pathtbl_resize_lock)); | ||
68 | } | 73 | } |
69 | 74 | ||
70 | /* | 75 | /* |
@@ -160,11 +165,10 @@ static int mesh_table_grow(struct mesh_table *oldtbl, | |||
160 | int i; | 165 | int i; |
161 | 166 | ||
162 | if (atomic_read(&oldtbl->entries) | 167 | if (atomic_read(&oldtbl->entries) |
163 | < oldtbl->mean_chain_len * (oldtbl->hash_mask + 1)) | 168 | < MEAN_CHAIN_LEN * (oldtbl->hash_mask + 1)) |
164 | return -EAGAIN; | 169 | return -EAGAIN; |
165 | 170 | ||
166 | newtbl->free_node = oldtbl->free_node; | 171 | newtbl->free_node = oldtbl->free_node; |
167 | newtbl->mean_chain_len = oldtbl->mean_chain_len; | ||
168 | newtbl->copy_node = oldtbl->copy_node; | 172 | newtbl->copy_node = oldtbl->copy_node; |
169 | newtbl->known_gates = oldtbl->known_gates; | 173 | newtbl->known_gates = oldtbl->known_gates; |
170 | atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries)); | 174 | atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries)); |
@@ -585,7 +589,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata, | |||
585 | 589 | ||
586 | hlist_add_head_rcu(&new_node->list, bucket); | 590 | hlist_add_head_rcu(&new_node->list, bucket); |
587 | if (atomic_inc_return(&tbl->entries) >= | 591 | if (atomic_inc_return(&tbl->entries) >= |
588 | tbl->mean_chain_len * (tbl->hash_mask + 1)) | 592 | MEAN_CHAIN_LEN * (tbl->hash_mask + 1)) |
589 | grow = 1; | 593 | grow = 1; |
590 | 594 | ||
591 | mesh_paths_generation++; | 595 | mesh_paths_generation++; |
@@ -714,7 +718,7 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata, | |||
714 | 718 | ||
715 | hlist_add_head_rcu(&new_node->list, bucket); | 719 | hlist_add_head_rcu(&new_node->list, bucket); |
716 | if (atomic_inc_return(&tbl->entries) >= | 720 | if (atomic_inc_return(&tbl->entries) >= |
717 | tbl->mean_chain_len * (tbl->hash_mask + 1)) | 721 | MEAN_CHAIN_LEN * (tbl->hash_mask + 1)) |
718 | grow = 1; | 722 | grow = 1; |
719 | 723 | ||
720 | spin_unlock(&tbl->hashwlock[hash_idx]); | 724 | spin_unlock(&tbl->hashwlock[hash_idx]); |
@@ -835,6 +839,29 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta) | |||
835 | rcu_read_unlock(); | 839 | rcu_read_unlock(); |
836 | } | 840 | } |
837 | 841 | ||
842 | static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata, | ||
843 | const u8 *proxy) | ||
844 | { | ||
845 | struct mesh_table *tbl; | ||
846 | struct mesh_path *mpp; | ||
847 | struct mpath_node *node; | ||
848 | int i; | ||
849 | |||
850 | rcu_read_lock(); | ||
851 | read_lock_bh(&pathtbl_resize_lock); | ||
852 | tbl = resize_dereference_mpp_paths(); | ||
853 | for_each_mesh_entry(tbl, node, i) { | ||
854 | mpp = node->mpath; | ||
855 | if (ether_addr_equal(mpp->mpp, proxy)) { | ||
856 | spin_lock(&tbl->hashwlock[i]); | ||
857 | __mesh_path_del(tbl, node); | ||
858 | spin_unlock(&tbl->hashwlock[i]); | ||
859 | } | ||
860 | } | ||
861 | read_unlock_bh(&pathtbl_resize_lock); | ||
862 | rcu_read_unlock(); | ||
863 | } | ||
864 | |||
838 | static void table_flush_by_iface(struct mesh_table *tbl, | 865 | static void table_flush_by_iface(struct mesh_table *tbl, |
839 | struct ieee80211_sub_if_data *sdata) | 866 | struct ieee80211_sub_if_data *sdata) |
840 | { | 867 | { |
@@ -876,14 +903,17 @@ void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata) | |||
876 | } | 903 | } |
877 | 904 | ||
878 | /** | 905 | /** |
879 | * mesh_path_del - delete a mesh path from the table | 906 | * table_path_del - delete a path from the mesh or mpp table |
880 | * | 907 | * |
881 | * @addr: dst address (ETH_ALEN length) | 908 | * @tbl: mesh or mpp path table |
882 | * @sdata: local subif | 909 | * @sdata: local subif |
910 | * @addr: dst address (ETH_ALEN length) | ||
883 | * | 911 | * |
884 | * Returns: 0 if successful | 912 | * Returns: 0 if successful |
885 | */ | 913 | */ |
886 | int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) | 914 | static int table_path_del(struct mesh_table __rcu *rcu_tbl, |
915 | struct ieee80211_sub_if_data *sdata, | ||
916 | const u8 *addr) | ||
887 | { | 917 | { |
888 | struct mesh_table *tbl; | 918 | struct mesh_table *tbl; |
889 | struct mesh_path *mpath; | 919 | struct mesh_path *mpath; |
@@ -892,8 +922,7 @@ int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) | |||
892 | int hash_idx; | 922 | int hash_idx; |
893 | int err = 0; | 923 | int err = 0; |
894 | 924 | ||
895 | read_lock_bh(&pathtbl_resize_lock); | 925 | tbl = resize_dereference_paths(rcu_tbl); |
896 | tbl = resize_dereference_mesh_paths(); | ||
897 | hash_idx = mesh_table_hash(addr, sdata, tbl); | 926 | hash_idx = mesh_table_hash(addr, sdata, tbl); |
898 | bucket = &tbl->hash_buckets[hash_idx]; | 927 | bucket = &tbl->hash_buckets[hash_idx]; |
899 | 928 | ||
@@ -909,9 +938,50 @@ int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) | |||
909 | 938 | ||
910 | err = -ENXIO; | 939 | err = -ENXIO; |
911 | enddel: | 940 | enddel: |
912 | mesh_paths_generation++; | ||
913 | spin_unlock(&tbl->hashwlock[hash_idx]); | 941 | spin_unlock(&tbl->hashwlock[hash_idx]); |
942 | return err; | ||
943 | } | ||
944 | |||
945 | /** | ||
946 | * mesh_path_del - delete a mesh path from the table | ||
947 | * | ||
948 | * @addr: dst address (ETH_ALEN length) | ||
949 | * @sdata: local subif | ||
950 | * | ||
951 | * Returns: 0 if successful | ||
952 | */ | ||
953 | int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) | ||
954 | { | ||
955 | int err = 0; | ||
956 | |||
957 | /* flush relevant mpp entries first */ | ||
958 | mpp_flush_by_proxy(sdata, addr); | ||
959 | |||
960 | read_lock_bh(&pathtbl_resize_lock); | ||
961 | err = table_path_del(mesh_paths, sdata, addr); | ||
962 | mesh_paths_generation++; | ||
914 | read_unlock_bh(&pathtbl_resize_lock); | 963 | read_unlock_bh(&pathtbl_resize_lock); |
964 | |||
965 | return err; | ||
966 | } | ||
967 | |||
968 | /** | ||
969 | * mpp_path_del - delete a mesh proxy path from the table | ||
970 | * | ||
971 | * @addr: addr address (ETH_ALEN length) | ||
972 | * @sdata: local subif | ||
973 | * | ||
974 | * Returns: 0 if successful | ||
975 | */ | ||
976 | static int mpp_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) | ||
977 | { | ||
978 | int err = 0; | ||
979 | |||
980 | read_lock_bh(&pathtbl_resize_lock); | ||
981 | err = table_path_del(mpp_paths, sdata, addr); | ||
982 | mpp_paths_generation++; | ||
983 | read_unlock_bh(&pathtbl_resize_lock); | ||
984 | |||
915 | return err; | 985 | return err; |
916 | } | 986 | } |
917 | 987 | ||
@@ -1076,7 +1146,6 @@ int mesh_pathtbl_init(void) | |||
1076 | return -ENOMEM; | 1146 | return -ENOMEM; |
1077 | tbl_path->free_node = &mesh_path_node_free; | 1147 | tbl_path->free_node = &mesh_path_node_free; |
1078 | tbl_path->copy_node = &mesh_path_node_copy; | 1148 | tbl_path->copy_node = &mesh_path_node_copy; |
1079 | tbl_path->mean_chain_len = MEAN_CHAIN_LEN; | ||
1080 | tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC); | 1149 | tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC); |
1081 | if (!tbl_path->known_gates) { | 1150 | if (!tbl_path->known_gates) { |
1082 | ret = -ENOMEM; | 1151 | ret = -ENOMEM; |
@@ -1092,7 +1161,6 @@ int mesh_pathtbl_init(void) | |||
1092 | } | 1161 | } |
1093 | tbl_mpp->free_node = &mesh_path_node_free; | 1162 | tbl_mpp->free_node = &mesh_path_node_free; |
1094 | tbl_mpp->copy_node = &mesh_path_node_copy; | 1163 | tbl_mpp->copy_node = &mesh_path_node_copy; |
1095 | tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN; | ||
1096 | tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC); | 1164 | tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC); |
1097 | if (!tbl_mpp->known_gates) { | 1165 | if (!tbl_mpp->known_gates) { |
1098 | ret = -ENOMEM; | 1166 | ret = -ENOMEM; |
@@ -1131,6 +1199,17 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata) | |||
1131 | time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) | 1199 | time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) |
1132 | mesh_path_del(mpath->sdata, mpath->dst); | 1200 | mesh_path_del(mpath->sdata, mpath->dst); |
1133 | } | 1201 | } |
1202 | |||
1203 | tbl = rcu_dereference(mpp_paths); | ||
1204 | for_each_mesh_entry(tbl, node, i) { | ||
1205 | if (node->mpath->sdata != sdata) | ||
1206 | continue; | ||
1207 | mpath = node->mpath; | ||
1208 | if ((!(mpath->flags & MESH_PATH_FIXED)) && | ||
1209 | time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) | ||
1210 | mpp_path_del(mpath->sdata, mpath->dst); | ||
1211 | } | ||
1212 | |||
1134 | rcu_read_unlock(); | 1213 | rcu_read_unlock(); |
1135 | } | 1214 | } |
1136 | 1215 | ||
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index bd3d55eb21d4..a07e93c21c9e 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -976,6 +976,10 @@ mesh_plink_get_event(struct ieee80211_sub_if_data *sdata, | |||
976 | mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); | 976 | mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); |
977 | goto out; | 977 | goto out; |
978 | } | 978 | } |
979 | |||
980 | /* new matching peer */ | ||
981 | event = OPN_ACPT; | ||
982 | goto out; | ||
979 | } else { | 983 | } else { |
980 | if (!test_sta_flag(sta, WLAN_STA_AUTH)) { | 984 | if (!test_sta_flag(sta, WLAN_STA_AUTH)) { |
981 | mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); | 985 | mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); |
@@ -985,12 +989,6 @@ mesh_plink_get_event(struct ieee80211_sub_if_data *sdata, | |||
985 | goto out; | 989 | goto out; |
986 | } | 990 | } |
987 | 991 | ||
988 | /* new matching peer */ | ||
989 | if (!sta) { | ||
990 | event = OPN_ACPT; | ||
991 | goto out; | ||
992 | } | ||
993 | |||
994 | switch (ftype) { | 992 | switch (ftype) { |
995 | case WLAN_SP_MESH_PEERING_OPEN: | 993 | case WLAN_SP_MESH_PEERING_OPEN: |
996 | if (!matches_local) | 994 | if (!matches_local) |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index bfbb1acafdd1..281b8d6e5109 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 6 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
7 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | 7 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> |
8 | * Copyright 2013-2014 Intel Mobile Communications GmbH | 8 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
9 | * Copyright (C) 2015 Intel Deutschland GmbH | 9 | * Copyright (C) 2015 - 2016 Intel Deutschland GmbH |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -196,16 +196,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
196 | 196 | ||
197 | /* check 40 MHz support, if we have it */ | 197 | /* check 40 MHz support, if we have it */ |
198 | if (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | 198 | if (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { |
199 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 199 | ieee80211_chandef_ht_oper(ht_oper, chandef); |
200 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
201 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
202 | chandef->center_freq1 += 10; | ||
203 | break; | ||
204 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
205 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
206 | chandef->center_freq1 -= 10; | ||
207 | break; | ||
208 | } | ||
209 | } else { | 200 | } else { |
210 | /* 40 MHz (and 80 MHz) must be supported for VHT */ | 201 | /* 40 MHz (and 80 MHz) must be supported for VHT */ |
211 | ret = IEEE80211_STA_DISABLE_VHT; | 202 | ret = IEEE80211_STA_DISABLE_VHT; |
@@ -219,35 +210,11 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
219 | goto out; | 210 | goto out; |
220 | } | 211 | } |
221 | 212 | ||
222 | vht_chandef.chan = channel; | 213 | vht_chandef = *chandef; |
223 | vht_chandef.center_freq1 = | 214 | if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) { |
224 | ieee80211_channel_to_frequency(vht_oper->center_freq_seg1_idx, | ||
225 | channel->band); | ||
226 | vht_chandef.center_freq2 = 0; | ||
227 | |||
228 | switch (vht_oper->chan_width) { | ||
229 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | ||
230 | vht_chandef.width = chandef->width; | ||
231 | vht_chandef.center_freq1 = chandef->center_freq1; | ||
232 | break; | ||
233 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | ||
234 | vht_chandef.width = NL80211_CHAN_WIDTH_80; | ||
235 | break; | ||
236 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | ||
237 | vht_chandef.width = NL80211_CHAN_WIDTH_160; | ||
238 | break; | ||
239 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | ||
240 | vht_chandef.width = NL80211_CHAN_WIDTH_80P80; | ||
241 | vht_chandef.center_freq2 = | ||
242 | ieee80211_channel_to_frequency( | ||
243 | vht_oper->center_freq_seg2_idx, | ||
244 | channel->band); | ||
245 | break; | ||
246 | default: | ||
247 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) | 215 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
248 | sdata_info(sdata, | 216 | sdata_info(sdata, |
249 | "AP VHT operation IE has invalid channel width (%d), disable VHT\n", | 217 | "AP VHT information is invalid, disable VHT\n"); |
250 | vht_oper->chan_width); | ||
251 | ret = IEEE80211_STA_DISABLE_VHT; | 218 | ret = IEEE80211_STA_DISABLE_VHT; |
252 | goto out; | 219 | goto out; |
253 | } | 220 | } |
@@ -592,7 +559,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | |||
592 | struct ieee80211_sub_if_data *other; | 559 | struct ieee80211_sub_if_data *other; |
593 | 560 | ||
594 | list_for_each_entry_rcu(other, &local->interfaces, list) { | 561 | list_for_each_entry_rcu(other, &local->interfaces, list) { |
595 | if (other->flags & IEEE80211_SDATA_MU_MIMO_OWNER) { | 562 | if (other->vif.mu_mimo_owner) { |
596 | disable_mu_mimo = true; | 563 | disable_mu_mimo = true; |
597 | break; | 564 | break; |
598 | } | 565 | } |
@@ -600,7 +567,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | |||
600 | if (disable_mu_mimo) | 567 | if (disable_mu_mimo) |
601 | cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; | 568 | cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; |
602 | else | 569 | else |
603 | sdata->flags |= IEEE80211_SDATA_MU_MIMO_OWNER; | 570 | sdata->vif.mu_mimo_owner = true; |
604 | } | 571 | } |
605 | 572 | ||
606 | mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK; | 573 | mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK; |
@@ -1638,8 +1605,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data) | |||
1638 | 1605 | ||
1639 | void ieee80211_dfs_cac_timer_work(struct work_struct *work) | 1606 | void ieee80211_dfs_cac_timer_work(struct work_struct *work) |
1640 | { | 1607 | { |
1641 | struct delayed_work *delayed_work = | 1608 | struct delayed_work *delayed_work = to_delayed_work(work); |
1642 | container_of(work, struct delayed_work, work); | ||
1643 | struct ieee80211_sub_if_data *sdata = | 1609 | struct ieee80211_sub_if_data *sdata = |
1644 | container_of(delayed_work, struct ieee80211_sub_if_data, | 1610 | container_of(delayed_work, struct ieee80211_sub_if_data, |
1645 | dfs_cac_timer_work); | 1611 | dfs_cac_timer_work); |
@@ -2079,7 +2045,14 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2079 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); | 2045 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); |
2080 | memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa)); | 2046 | memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa)); |
2081 | memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask)); | 2047 | memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask)); |
2082 | sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER; | 2048 | |
2049 | /* reset MU-MIMO ownership and group data */ | ||
2050 | memset(sdata->vif.bss_conf.mu_group.membership, 0, | ||
2051 | sizeof(sdata->vif.bss_conf.mu_group.membership)); | ||
2052 | memset(sdata->vif.bss_conf.mu_group.position, 0, | ||
2053 | sizeof(sdata->vif.bss_conf.mu_group.position)); | ||
2054 | changed |= BSS_CHANGED_MU_GROUPS; | ||
2055 | sdata->vif.mu_mimo_owner = false; | ||
2083 | 2056 | ||
2084 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; | 2057 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; |
2085 | 2058 | ||
@@ -2536,7 +2509,8 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, | |||
2536 | eth_zero_addr(sdata->u.mgd.bssid); | 2509 | eth_zero_addr(sdata->u.mgd.bssid); |
2537 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | 2510 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); |
2538 | sdata->u.mgd.flags = 0; | 2511 | sdata->u.mgd.flags = 0; |
2539 | sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER; | 2512 | sdata->vif.mu_mimo_owner = false; |
2513 | |||
2540 | mutex_lock(&sdata->local->mtx); | 2514 | mutex_lock(&sdata->local->mtx); |
2541 | ieee80211_vif_release_channel(sdata); | 2515 | ieee80211_vif_release_channel(sdata); |
2542 | mutex_unlock(&sdata->local->mtx); | 2516 | mutex_unlock(&sdata->local->mtx); |
@@ -3571,6 +3545,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3571 | elems.ht_cap_elem, elems.ht_operation, | 3545 | elems.ht_cap_elem, elems.ht_operation, |
3572 | elems.vht_operation, bssid, &changed)) { | 3546 | elems.vht_operation, bssid, &changed)) { |
3573 | mutex_unlock(&local->sta_mtx); | 3547 | mutex_unlock(&local->sta_mtx); |
3548 | sdata_info(sdata, | ||
3549 | "failed to follow AP %pM bandwidth change, disconnect\n", | ||
3550 | bssid); | ||
3574 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 3551 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
3575 | WLAN_REASON_DEAUTH_LEAVING, | 3552 | WLAN_REASON_DEAUTH_LEAVING, |
3576 | true, deauth_buf); | 3553 | true, deauth_buf); |
@@ -3946,11 +3923,9 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3946 | * We actually lost the connection ... or did we? | 3923 | * We actually lost the connection ... or did we? |
3947 | * Let's make sure! | 3924 | * Let's make sure! |
3948 | */ | 3925 | */ |
3949 | wiphy_debug(local->hw.wiphy, | 3926 | mlme_dbg(sdata, |
3950 | "%s: No probe response from AP %pM" | 3927 | "No probe response from AP %pM after %dms, disconnecting.\n", |
3951 | " after %dms, disconnecting.\n", | 3928 | bssid, probe_wait_ms); |
3952 | sdata->name, | ||
3953 | bssid, probe_wait_ms); | ||
3954 | 3929 | ||
3955 | ieee80211_sta_connection_lost(sdata, bssid, | 3930 | ieee80211_sta_connection_lost(sdata, bssid, |
3956 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false); | 3931 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false); |
@@ -4536,6 +4511,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
4536 | if (ifmgd->associated) { | 4511 | if (ifmgd->associated) { |
4537 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 4512 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
4538 | 4513 | ||
4514 | sdata_info(sdata, | ||
4515 | "disconnect from AP %pM for new auth to %pM\n", | ||
4516 | ifmgd->associated->bssid, req->bss->bssid); | ||
4539 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 4517 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
4540 | WLAN_REASON_UNSPECIFIED, | 4518 | WLAN_REASON_UNSPECIFIED, |
4541 | false, frame_buf); | 4519 | false, frame_buf); |
@@ -4604,6 +4582,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4604 | if (ifmgd->associated) { | 4582 | if (ifmgd->associated) { |
4605 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 4583 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
4606 | 4584 | ||
4585 | sdata_info(sdata, | ||
4586 | "disconnect from AP %pM for new assoc to %pM\n", | ||
4587 | ifmgd->associated->bssid, req->bss->bssid); | ||
4607 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 4588 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
4608 | WLAN_REASON_UNSPECIFIED, | 4589 | WLAN_REASON_UNSPECIFIED, |
4609 | false, frame_buf); | 4590 | false, frame_buf); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index bc081850ac0e..91279576f4a7 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
5 | * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net> | 5 | * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net> |
6 | * Copyright 2013-2014 Intel Mobile Communications GmbH | 6 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
7 | * Copyright(c) 2015 - 2016 Intel Deutschland GmbH | ||
7 | * | 8 | * |
8 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
@@ -18,6 +19,7 @@ | |||
18 | #include <linux/etherdevice.h> | 19 | #include <linux/etherdevice.h> |
19 | #include <linux/rcupdate.h> | 20 | #include <linux/rcupdate.h> |
20 | #include <linux/export.h> | 21 | #include <linux/export.h> |
22 | #include <linux/bitops.h> | ||
21 | #include <net/mac80211.h> | 23 | #include <net/mac80211.h> |
22 | #include <net/ieee80211_radiotap.h> | 24 | #include <net/ieee80211_radiotap.h> |
23 | #include <asm/unaligned.h> | 25 | #include <asm/unaligned.h> |
@@ -122,7 +124,8 @@ static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len, | |||
122 | hdr = (void *)(skb->data + rtap_vendor_space); | 124 | hdr = (void *)(skb->data + rtap_vendor_space); |
123 | 125 | ||
124 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | | 126 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | |
125 | RX_FLAG_FAILED_PLCP_CRC)) | 127 | RX_FLAG_FAILED_PLCP_CRC | |
128 | RX_FLAG_ONLY_MONITOR)) | ||
126 | return true; | 129 | return true; |
127 | 130 | ||
128 | if (unlikely(skb->len < 16 + present_fcs_len + rtap_vendor_space)) | 131 | if (unlikely(skb->len < 16 + present_fcs_len + rtap_vendor_space)) |
@@ -507,7 +510,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
507 | return NULL; | 510 | return NULL; |
508 | } | 511 | } |
509 | 512 | ||
510 | if (!local->monitors) { | 513 | if (!local->monitors || (status->flag & RX_FLAG_SKIP_MONITOR)) { |
511 | if (should_drop_frame(origskb, present_fcs_len, | 514 | if (should_drop_frame(origskb, present_fcs_len, |
512 | rtap_vendor_space)) { | 515 | rtap_vendor_space)) { |
513 | dev_kfree_skb(origskb); | 516 | dev_kfree_skb(origskb); |
@@ -797,6 +800,26 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
797 | return RX_CONTINUE; | 800 | return RX_CONTINUE; |
798 | } | 801 | } |
799 | 802 | ||
803 | static inline bool ieee80211_rx_reorder_ready(struct tid_ampdu_rx *tid_agg_rx, | ||
804 | int index) | ||
805 | { | ||
806 | struct sk_buff_head *frames = &tid_agg_rx->reorder_buf[index]; | ||
807 | struct sk_buff *tail = skb_peek_tail(frames); | ||
808 | struct ieee80211_rx_status *status; | ||
809 | |||
810 | if (tid_agg_rx->reorder_buf_filtered & BIT_ULL(index)) | ||
811 | return true; | ||
812 | |||
813 | if (!tail) | ||
814 | return false; | ||
815 | |||
816 | status = IEEE80211_SKB_RXCB(tail); | ||
817 | if (status->flag & RX_FLAG_AMSDU_MORE) | ||
818 | return false; | ||
819 | |||
820 | return true; | ||
821 | } | ||
822 | |||
800 | static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, | 823 | static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, |
801 | struct tid_ampdu_rx *tid_agg_rx, | 824 | struct tid_ampdu_rx *tid_agg_rx, |
802 | int index, | 825 | int index, |
@@ -811,7 +834,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, | |||
811 | if (skb_queue_empty(skb_list)) | 834 | if (skb_queue_empty(skb_list)) |
812 | goto no_frame; | 835 | goto no_frame; |
813 | 836 | ||
814 | if (!ieee80211_rx_reorder_ready(skb_list)) { | 837 | if (!ieee80211_rx_reorder_ready(tid_agg_rx, index)) { |
815 | __skb_queue_purge(skb_list); | 838 | __skb_queue_purge(skb_list); |
816 | goto no_frame; | 839 | goto no_frame; |
817 | } | 840 | } |
@@ -825,6 +848,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, | |||
825 | } | 848 | } |
826 | 849 | ||
827 | no_frame: | 850 | no_frame: |
851 | tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index); | ||
828 | tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num); | 852 | tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num); |
829 | } | 853 | } |
830 | 854 | ||
@@ -865,7 +889,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
865 | 889 | ||
866 | /* release the buffer until next missing frame */ | 890 | /* release the buffer until next missing frame */ |
867 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; | 891 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
868 | if (!ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index]) && | 892 | if (!ieee80211_rx_reorder_ready(tid_agg_rx, index) && |
869 | tid_agg_rx->stored_mpdu_num) { | 893 | tid_agg_rx->stored_mpdu_num) { |
870 | /* | 894 | /* |
871 | * No buffers ready to be released, but check whether any | 895 | * No buffers ready to be released, but check whether any |
@@ -874,8 +898,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
874 | int skipped = 1; | 898 | int skipped = 1; |
875 | for (j = (index + 1) % tid_agg_rx->buf_size; j != index; | 899 | for (j = (index + 1) % tid_agg_rx->buf_size; j != index; |
876 | j = (j + 1) % tid_agg_rx->buf_size) { | 900 | j = (j + 1) % tid_agg_rx->buf_size) { |
877 | if (!ieee80211_rx_reorder_ready( | 901 | if (!ieee80211_rx_reorder_ready(tid_agg_rx, j)) { |
878 | &tid_agg_rx->reorder_buf[j])) { | ||
879 | skipped++; | 902 | skipped++; |
880 | continue; | 903 | continue; |
881 | } | 904 | } |
@@ -902,8 +925,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
902 | skipped) & IEEE80211_SN_MASK; | 925 | skipped) & IEEE80211_SN_MASK; |
903 | skipped = 0; | 926 | skipped = 0; |
904 | } | 927 | } |
905 | } else while (ieee80211_rx_reorder_ready( | 928 | } else while (ieee80211_rx_reorder_ready(tid_agg_rx, index)) { |
906 | &tid_agg_rx->reorder_buf[index])) { | ||
907 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, | 929 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, |
908 | frames); | 930 | frames); |
909 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; | 931 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
@@ -914,8 +936,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
914 | 936 | ||
915 | for (; j != (index - 1) % tid_agg_rx->buf_size; | 937 | for (; j != (index - 1) % tid_agg_rx->buf_size; |
916 | j = (j + 1) % tid_agg_rx->buf_size) { | 938 | j = (j + 1) % tid_agg_rx->buf_size) { |
917 | if (ieee80211_rx_reorder_ready( | 939 | if (ieee80211_rx_reorder_ready(tid_agg_rx, j)) |
918 | &tid_agg_rx->reorder_buf[j])) | ||
919 | break; | 940 | break; |
920 | } | 941 | } |
921 | 942 | ||
@@ -986,7 +1007,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
986 | index = mpdu_seq_num % tid_agg_rx->buf_size; | 1007 | index = mpdu_seq_num % tid_agg_rx->buf_size; |
987 | 1008 | ||
988 | /* check if we already stored this frame */ | 1009 | /* check if we already stored this frame */ |
989 | if (ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index])) { | 1010 | if (ieee80211_rx_reorder_ready(tid_agg_rx, index)) { |
990 | dev_kfree_skb(skb); | 1011 | dev_kfree_skb(skb); |
991 | goto out; | 1012 | goto out; |
992 | } | 1013 | } |
@@ -1099,6 +1120,9 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx) | |||
1099 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1120 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
1100 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | 1121 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
1101 | 1122 | ||
1123 | if (status->flag & RX_FLAG_DUP_VALIDATED) | ||
1124 | return RX_CONTINUE; | ||
1125 | |||
1102 | /* | 1126 | /* |
1103 | * Drop duplicate 802.11 retransmissions | 1127 | * Drop duplicate 802.11 retransmissions |
1104 | * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") | 1128 | * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") |
@@ -2199,9 +2223,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | |||
2199 | skb->dev = dev; | 2223 | skb->dev = dev; |
2200 | __skb_queue_head_init(&frame_list); | 2224 | __skb_queue_head_init(&frame_list); |
2201 | 2225 | ||
2202 | if (skb_linearize(skb)) | ||
2203 | return RX_DROP_UNUSABLE; | ||
2204 | |||
2205 | ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, | 2226 | ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, |
2206 | rx->sdata->vif.type, | 2227 | rx->sdata->vif.type, |
2207 | rx->local->hw.extra_tx_headroom, true); | 2228 | rx->local->hw.extra_tx_headroom, true); |
@@ -2231,7 +2252,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
2231 | struct ieee80211_local *local = rx->local; | 2252 | struct ieee80211_local *local = rx->local; |
2232 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 2253 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
2233 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 2254 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
2234 | u16 q, hdrlen; | 2255 | u16 ac, q, hdrlen; |
2235 | 2256 | ||
2236 | hdr = (struct ieee80211_hdr *) skb->data; | 2257 | hdr = (struct ieee80211_hdr *) skb->data; |
2237 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 2258 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
@@ -2290,6 +2311,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
2290 | spin_lock_bh(&mppath->state_lock); | 2311 | spin_lock_bh(&mppath->state_lock); |
2291 | if (!ether_addr_equal(mppath->mpp, mpp_addr)) | 2312 | if (!ether_addr_equal(mppath->mpp, mpp_addr)) |
2292 | memcpy(mppath->mpp, mpp_addr, ETH_ALEN); | 2313 | memcpy(mppath->mpp, mpp_addr, ETH_ALEN); |
2314 | mppath->exp_time = jiffies; | ||
2293 | spin_unlock_bh(&mppath->state_lock); | 2315 | spin_unlock_bh(&mppath->state_lock); |
2294 | } | 2316 | } |
2295 | rcu_read_unlock(); | 2317 | rcu_read_unlock(); |
@@ -2300,7 +2322,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
2300 | ether_addr_equal(sdata->vif.addr, hdr->addr3)) | 2322 | ether_addr_equal(sdata->vif.addr, hdr->addr3)) |
2301 | return RX_CONTINUE; | 2323 | return RX_CONTINUE; |
2302 | 2324 | ||
2303 | q = ieee80211_select_queue_80211(sdata, skb, hdr); | 2325 | ac = ieee80211_select_queue_80211(sdata, skb, hdr); |
2326 | q = sdata->vif.hw_queue[ac]; | ||
2304 | if (ieee80211_queue_stopped(&local->hw, q)) { | 2327 | if (ieee80211_queue_stopped(&local->hw, q)) { |
2305 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion); | 2328 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion); |
2306 | return RX_DROP_MONITOR; | 2329 | return RX_DROP_MONITOR; |
@@ -2738,6 +2761,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2738 | opmode, status->band); | 2761 | opmode, status->band); |
2739 | goto handled; | 2762 | goto handled; |
2740 | } | 2763 | } |
2764 | case WLAN_VHT_ACTION_GROUPID_MGMT: { | ||
2765 | if (len < IEEE80211_MIN_ACTION_SIZE + 25) | ||
2766 | goto invalid; | ||
2767 | goto queue; | ||
2768 | } | ||
2741 | default: | 2769 | default: |
2742 | break; | 2770 | break; |
2743 | } | 2771 | } |
@@ -3275,6 +3303,85 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) | |||
3275 | ieee80211_rx_handlers(&rx, &frames); | 3303 | ieee80211_rx_handlers(&rx, &frames); |
3276 | } | 3304 | } |
3277 | 3305 | ||
3306 | void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid, | ||
3307 | u16 ssn, u64 filtered, | ||
3308 | u16 received_mpdus) | ||
3309 | { | ||
3310 | struct sta_info *sta; | ||
3311 | struct tid_ampdu_rx *tid_agg_rx; | ||
3312 | struct sk_buff_head frames; | ||
3313 | struct ieee80211_rx_data rx = { | ||
3314 | /* This is OK -- must be QoS data frame */ | ||
3315 | .security_idx = tid, | ||
3316 | .seqno_idx = tid, | ||
3317 | }; | ||
3318 | int i, diff; | ||
3319 | |||
3320 | if (WARN_ON(!pubsta || tid >= IEEE80211_NUM_TIDS)) | ||
3321 | return; | ||
3322 | |||
3323 | __skb_queue_head_init(&frames); | ||
3324 | |||
3325 | sta = container_of(pubsta, struct sta_info, sta); | ||
3326 | |||
3327 | rx.sta = sta; | ||
3328 | rx.sdata = sta->sdata; | ||
3329 | rx.local = sta->local; | ||
3330 | |||
3331 | rcu_read_lock(); | ||
3332 | tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); | ||
3333 | if (!tid_agg_rx) | ||
3334 | goto out; | ||
3335 | |||
3336 | spin_lock_bh(&tid_agg_rx->reorder_lock); | ||
3337 | |||
3338 | if (received_mpdus >= IEEE80211_SN_MODULO >> 1) { | ||
3339 | int release; | ||
3340 | |||
3341 | /* release all frames in the reorder buffer */ | ||
3342 | release = (tid_agg_rx->head_seq_num + tid_agg_rx->buf_size) % | ||
3343 | IEEE80211_SN_MODULO; | ||
3344 | ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx, | ||
3345 | release, &frames); | ||
3346 | /* update ssn to match received ssn */ | ||
3347 | tid_agg_rx->head_seq_num = ssn; | ||
3348 | } else { | ||
3349 | ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx, ssn, | ||
3350 | &frames); | ||
3351 | } | ||
3352 | |||
3353 | /* handle the case that received ssn is behind the mac ssn. | ||
3354 | * it can be tid_agg_rx->buf_size behind and still be valid */ | ||
3355 | diff = (tid_agg_rx->head_seq_num - ssn) & IEEE80211_SN_MASK; | ||
3356 | if (diff >= tid_agg_rx->buf_size) { | ||
3357 | tid_agg_rx->reorder_buf_filtered = 0; | ||
3358 | goto release; | ||
3359 | } | ||
3360 | filtered = filtered >> diff; | ||
3361 | ssn += diff; | ||
3362 | |||
3363 | /* update bitmap */ | ||
3364 | for (i = 0; i < tid_agg_rx->buf_size; i++) { | ||
3365 | int index = (ssn + i) % tid_agg_rx->buf_size; | ||
3366 | |||
3367 | tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index); | ||
3368 | if (filtered & BIT_ULL(i)) | ||
3369 | tid_agg_rx->reorder_buf_filtered |= BIT_ULL(index); | ||
3370 | } | ||
3371 | |||
3372 | /* now process also frames that the filter marking released */ | ||
3373 | ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames); | ||
3374 | |||
3375 | release: | ||
3376 | spin_unlock_bh(&tid_agg_rx->reorder_lock); | ||
3377 | |||
3378 | ieee80211_rx_handlers(&rx, &frames); | ||
3379 | |||
3380 | out: | ||
3381 | rcu_read_unlock(); | ||
3382 | } | ||
3383 | EXPORT_SYMBOL(ieee80211_mark_rx_ba_filtered_frames); | ||
3384 | |||
3278 | /* main receive path */ | 3385 | /* main receive path */ |
3279 | 3386 | ||
3280 | static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) | 3387 | static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a4a4f89d3ba0..d20bab5c146c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -116,6 +116,7 @@ static void __cleanup_single_sta(struct sta_info *sta) | |||
116 | 116 | ||
117 | ieee80211_purge_tx_queue(&local->hw, &txqi->queue); | 117 | ieee80211_purge_tx_queue(&local->hw, &txqi->queue); |
118 | atomic_sub(n, &sdata->txqs_len[txqi->txq.ac]); | 118 | atomic_sub(n, &sdata->txqs_len[txqi->txq.ac]); |
119 | txqi->byte_cnt = 0; | ||
119 | } | 120 | } |
120 | } | 121 | } |
121 | 122 | ||
@@ -498,11 +499,17 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) | |||
498 | { | 499 | { |
499 | struct ieee80211_local *local = sta->local; | 500 | struct ieee80211_local *local = sta->local; |
500 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 501 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
501 | struct station_info sinfo; | 502 | struct station_info *sinfo; |
502 | int err = 0; | 503 | int err = 0; |
503 | 504 | ||
504 | lockdep_assert_held(&local->sta_mtx); | 505 | lockdep_assert_held(&local->sta_mtx); |
505 | 506 | ||
507 | sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL); | ||
508 | if (!sinfo) { | ||
509 | err = -ENOMEM; | ||
510 | goto out_err; | ||
511 | } | ||
512 | |||
506 | /* check if STA exists already */ | 513 | /* check if STA exists already */ |
507 | if (sta_info_get_bss(sdata, sta->sta.addr)) { | 514 | if (sta_info_get_bss(sdata, sta->sta.addr)) { |
508 | err = -EEXIST; | 515 | err = -EEXIST; |
@@ -530,14 +537,12 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) | |||
530 | /* accept BA sessions now */ | 537 | /* accept BA sessions now */ |
531 | clear_sta_flag(sta, WLAN_STA_BLOCK_BA); | 538 | clear_sta_flag(sta, WLAN_STA_BLOCK_BA); |
532 | 539 | ||
533 | ieee80211_recalc_min_chandef(sdata); | ||
534 | ieee80211_sta_debugfs_add(sta); | 540 | ieee80211_sta_debugfs_add(sta); |
535 | rate_control_add_sta_debugfs(sta); | 541 | rate_control_add_sta_debugfs(sta); |
536 | 542 | ||
537 | memset(&sinfo, 0, sizeof(sinfo)); | 543 | sinfo->generation = local->sta_generation; |
538 | sinfo.filled = 0; | 544 | cfg80211_new_sta(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL); |
539 | sinfo.generation = local->sta_generation; | 545 | kfree(sinfo); |
540 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); | ||
541 | 546 | ||
542 | sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr); | 547 | sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr); |
543 | 548 | ||
@@ -557,6 +562,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) | |||
557 | __cleanup_single_sta(sta); | 562 | __cleanup_single_sta(sta); |
558 | out_err: | 563 | out_err: |
559 | mutex_unlock(&local->sta_mtx); | 564 | mutex_unlock(&local->sta_mtx); |
565 | kfree(sinfo); | ||
560 | rcu_read_lock(); | 566 | rcu_read_lock(); |
561 | return err; | 567 | return err; |
562 | } | 568 | } |
@@ -898,7 +904,7 @@ static void __sta_info_destroy_part2(struct sta_info *sta) | |||
898 | { | 904 | { |
899 | struct ieee80211_local *local = sta->local; | 905 | struct ieee80211_local *local = sta->local; |
900 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 906 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
901 | struct station_info sinfo = {}; | 907 | struct station_info *sinfo; |
902 | int ret; | 908 | int ret; |
903 | 909 | ||
904 | /* | 910 | /* |
@@ -936,12 +942,14 @@ static void __sta_info_destroy_part2(struct sta_info *sta) | |||
936 | 942 | ||
937 | sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr); | 943 | sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr); |
938 | 944 | ||
939 | sta_set_sinfo(sta, &sinfo); | 945 | sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); |
940 | cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); | 946 | if (sinfo) |
947 | sta_set_sinfo(sta, sinfo); | ||
948 | cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL); | ||
949 | kfree(sinfo); | ||
941 | 950 | ||
942 | rate_control_remove_sta_debugfs(sta); | 951 | rate_control_remove_sta_debugfs(sta); |
943 | ieee80211_sta_debugfs_remove(sta); | 952 | ieee80211_sta_debugfs_remove(sta); |
944 | ieee80211_recalc_min_chandef(sdata); | ||
945 | 953 | ||
946 | cleanup_single_sta(sta); | 954 | cleanup_single_sta(sta); |
947 | } | 955 | } |
@@ -1808,14 +1816,17 @@ int sta_info_move_state(struct sta_info *sta, | |||
1808 | clear_bit(WLAN_STA_AUTH, &sta->_flags); | 1816 | clear_bit(WLAN_STA_AUTH, &sta->_flags); |
1809 | break; | 1817 | break; |
1810 | case IEEE80211_STA_AUTH: | 1818 | case IEEE80211_STA_AUTH: |
1811 | if (sta->sta_state == IEEE80211_STA_NONE) | 1819 | if (sta->sta_state == IEEE80211_STA_NONE) { |
1812 | set_bit(WLAN_STA_AUTH, &sta->_flags); | 1820 | set_bit(WLAN_STA_AUTH, &sta->_flags); |
1813 | else if (sta->sta_state == IEEE80211_STA_ASSOC) | 1821 | } else if (sta->sta_state == IEEE80211_STA_ASSOC) { |
1814 | clear_bit(WLAN_STA_ASSOC, &sta->_flags); | 1822 | clear_bit(WLAN_STA_ASSOC, &sta->_flags); |
1823 | ieee80211_recalc_min_chandef(sta->sdata); | ||
1824 | } | ||
1815 | break; | 1825 | break; |
1816 | case IEEE80211_STA_ASSOC: | 1826 | case IEEE80211_STA_ASSOC: |
1817 | if (sta->sta_state == IEEE80211_STA_AUTH) { | 1827 | if (sta->sta_state == IEEE80211_STA_AUTH) { |
1818 | set_bit(WLAN_STA_ASSOC, &sta->_flags); | 1828 | set_bit(WLAN_STA_ASSOC, &sta->_flags); |
1829 | ieee80211_recalc_min_chandef(sta->sdata); | ||
1819 | } else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) { | 1830 | } else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) { |
1820 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || | 1831 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || |
1821 | (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | 1832 | (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index d6051629ed15..053f5c4fa495 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2002-2005, Devicescape Software, Inc. | 2 | * Copyright 2002-2005, Devicescape Software, Inc. |
3 | * Copyright 2013-2014 Intel Mobile Communications GmbH | 3 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
4 | * Copyright(c) 2015 Intel Deutschland GmbH | ||
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
@@ -167,6 +168,8 @@ struct tid_ampdu_tx { | |||
167 | * | 168 | * |
168 | * @reorder_buf: buffer to reorder incoming aggregated MPDUs. An MPDU may be an | 169 | * @reorder_buf: buffer to reorder incoming aggregated MPDUs. An MPDU may be an |
169 | * A-MSDU with individually reported subframes. | 170 | * A-MSDU with individually reported subframes. |
171 | * @reorder_buf_filtered: bitmap indicating where there are filtered frames in | ||
172 | * the reorder buffer that should be ignored when releasing frames | ||
170 | * @reorder_time: jiffies when skb was added | 173 | * @reorder_time: jiffies when skb was added |
171 | * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) | 174 | * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) |
172 | * @reorder_timer: releases expired frames from the reorder buffer. | 175 | * @reorder_timer: releases expired frames from the reorder buffer. |
@@ -194,6 +197,7 @@ struct tid_ampdu_tx { | |||
194 | struct tid_ampdu_rx { | 197 | struct tid_ampdu_rx { |
195 | struct rcu_head rcu_head; | 198 | struct rcu_head rcu_head; |
196 | spinlock_t reorder_lock; | 199 | spinlock_t reorder_lock; |
200 | u64 reorder_buf_filtered; | ||
197 | struct sk_buff_head *reorder_buf; | 201 | struct sk_buff_head *reorder_buf; |
198 | unsigned long *reorder_time; | 202 | unsigned long *reorder_time; |
199 | struct timer_list session_timer; | 203 | struct timer_list session_timer; |
@@ -212,20 +216,21 @@ struct tid_ampdu_rx { | |||
212 | /** | 216 | /** |
213 | * struct sta_ampdu_mlme - STA aggregation information. | 217 | * struct sta_ampdu_mlme - STA aggregation information. |
214 | * | 218 | * |
219 | * @mtx: mutex to protect all TX data (except non-NULL assignments | ||
220 | * to tid_tx[idx], which are protected by the sta spinlock) | ||
221 | * tid_start_tx is also protected by sta->lock. | ||
215 | * @tid_rx: aggregation info for Rx per TID -- RCU protected | 222 | * @tid_rx: aggregation info for Rx per TID -- RCU protected |
216 | * @tid_tx: aggregation info for Tx per TID | ||
217 | * @tid_start_tx: sessions where start was requested | ||
218 | * @addba_req_num: number of times addBA request has been sent. | ||
219 | * @last_addba_req_time: timestamp of the last addBA request. | ||
220 | * @dialog_token_allocator: dialog token enumerator for each new session; | ||
221 | * @work: work struct for starting/stopping aggregation | ||
222 | * @tid_rx_timer_expired: bitmap indicating on which TIDs the | 223 | * @tid_rx_timer_expired: bitmap indicating on which TIDs the |
223 | * RX timer expired until the work for it runs | 224 | * RX timer expired until the work for it runs |
224 | * @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the | 225 | * @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the |
225 | * driver requested to close until the work for it runs | 226 | * driver requested to close until the work for it runs |
226 | * @mtx: mutex to protect all TX data (except non-NULL assignments | 227 | * @agg_session_valid: bitmap indicating which TID has a rx BA session open on |
227 | * to tid_tx[idx], which are protected by the sta spinlock) | 228 | * @work: work struct for starting/stopping aggregation |
228 | * tid_start_tx is also protected by sta->lock. | 229 | * @tid_tx: aggregation info for Tx per TID |
230 | * @tid_start_tx: sessions where start was requested | ||
231 | * @last_addba_req_time: timestamp of the last addBA request. | ||
232 | * @addba_req_num: number of times addBA request has been sent. | ||
233 | * @dialog_token_allocator: dialog token enumerator for each new session; | ||
229 | */ | 234 | */ |
230 | struct sta_ampdu_mlme { | 235 | struct sta_ampdu_mlme { |
231 | struct mutex mtx; | 236 | struct mutex mtx; |
@@ -233,6 +238,7 @@ struct sta_ampdu_mlme { | |||
233 | struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS]; | 238 | struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS]; |
234 | unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; | 239 | unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; |
235 | unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; | 240 | unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; |
241 | unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; | ||
236 | /* tx */ | 242 | /* tx */ |
237 | struct work_struct work; | 243 | struct work_struct work; |
238 | struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS]; | 244 | struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS]; |
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 0ae207771a58..b3622823bad2 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2002-2004, Instant802 Networks, Inc. | 2 | * Copyright 2002-2004, Instant802 Networks, Inc. |
3 | * Copyright 2005, Devicescape Software, Inc. | 3 | * Copyright 2005, Devicescape Software, Inc. |
4 | * Copyright (C) 2016 Intel Deutschland GmbH | ||
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
@@ -142,15 +143,14 @@ static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx, | |||
142 | /* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets | 143 | /* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets |
143 | * of the IV. Returns pointer to the octet following IVs (i.e., beginning of | 144 | * of the IV. Returns pointer to the octet following IVs (i.e., beginning of |
144 | * the packet payload). */ | 145 | * the packet payload). */ |
145 | u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key) | 146 | u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key_conf *keyconf, u64 pn) |
146 | { | 147 | { |
147 | lockdep_assert_held(&key->u.tkip.txlock); | 148 | pos = write_tkip_iv(pos, TKIP_PN_TO_IV16(pn)); |
148 | 149 | *pos++ = (keyconf->keyidx << 6) | (1 << 5) /* Ext IV */; | |
149 | pos = write_tkip_iv(pos, key->u.tkip.tx.iv16); | 150 | put_unaligned_le32(TKIP_PN_TO_IV32(pn), pos); |
150 | *pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */; | ||
151 | put_unaligned_le32(key->u.tkip.tx.iv32, pos); | ||
152 | return pos + 4; | 151 | return pos + 4; |
153 | } | 152 | } |
153 | EXPORT_SYMBOL_GPL(ieee80211_tkip_add_iv); | ||
154 | 154 | ||
155 | static void ieee80211_compute_tkip_p1k(struct ieee80211_key *key, u32 iv32) | 155 | static void ieee80211_compute_tkip_p1k(struct ieee80211_key *key, u32 iv32) |
156 | { | 156 | { |
@@ -250,6 +250,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, | |||
250 | u8 rc4key[16], keyid, *pos = payload; | 250 | u8 rc4key[16], keyid, *pos = payload; |
251 | int res; | 251 | int res; |
252 | const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; | 252 | const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; |
253 | struct tkip_ctx_rx *rx_ctx = &key->u.tkip.rx[queue]; | ||
253 | 254 | ||
254 | if (payload_len < 12) | 255 | if (payload_len < 12) |
255 | return -1; | 256 | return -1; |
@@ -265,37 +266,36 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, | |||
265 | if ((keyid >> 6) != key->conf.keyidx) | 266 | if ((keyid >> 6) != key->conf.keyidx) |
266 | return TKIP_DECRYPT_INVALID_KEYIDX; | 267 | return TKIP_DECRYPT_INVALID_KEYIDX; |
267 | 268 | ||
268 | if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT && | 269 | if (rx_ctx->ctx.state != TKIP_STATE_NOT_INIT && |
269 | (iv32 < key->u.tkip.rx[queue].iv32 || | 270 | (iv32 < rx_ctx->iv32 || |
270 | (iv32 == key->u.tkip.rx[queue].iv32 && | 271 | (iv32 == rx_ctx->iv32 && iv16 <= rx_ctx->iv16))) |
271 | iv16 <= key->u.tkip.rx[queue].iv16))) | ||
272 | return TKIP_DECRYPT_REPLAY; | 272 | return TKIP_DECRYPT_REPLAY; |
273 | 273 | ||
274 | if (only_iv) { | 274 | if (only_iv) { |
275 | res = TKIP_DECRYPT_OK; | 275 | res = TKIP_DECRYPT_OK; |
276 | key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED; | 276 | rx_ctx->ctx.state = TKIP_STATE_PHASE1_HW_UPLOADED; |
277 | goto done; | 277 | goto done; |
278 | } | 278 | } |
279 | 279 | ||
280 | if (key->u.tkip.rx[queue].state == TKIP_STATE_NOT_INIT || | 280 | if (rx_ctx->ctx.state == TKIP_STATE_NOT_INIT || |
281 | key->u.tkip.rx[queue].iv32 != iv32) { | 281 | rx_ctx->iv32 != iv32) { |
282 | /* IV16 wrapped around - perform TKIP phase 1 */ | 282 | /* IV16 wrapped around - perform TKIP phase 1 */ |
283 | tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32); | 283 | tkip_mixing_phase1(tk, &rx_ctx->ctx, ta, iv32); |
284 | } | 284 | } |
285 | if (key->local->ops->update_tkip_key && | 285 | if (key->local->ops->update_tkip_key && |
286 | key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && | 286 | key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && |
287 | key->u.tkip.rx[queue].state != TKIP_STATE_PHASE1_HW_UPLOADED) { | 287 | rx_ctx->ctx.state != TKIP_STATE_PHASE1_HW_UPLOADED) { |
288 | struct ieee80211_sub_if_data *sdata = key->sdata; | 288 | struct ieee80211_sub_if_data *sdata = key->sdata; |
289 | 289 | ||
290 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 290 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
291 | sdata = container_of(key->sdata->bss, | 291 | sdata = container_of(key->sdata->bss, |
292 | struct ieee80211_sub_if_data, u.ap); | 292 | struct ieee80211_sub_if_data, u.ap); |
293 | drv_update_tkip_key(key->local, sdata, &key->conf, key->sta, | 293 | drv_update_tkip_key(key->local, sdata, &key->conf, key->sta, |
294 | iv32, key->u.tkip.rx[queue].p1k); | 294 | iv32, rx_ctx->ctx.p1k); |
295 | key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED; | 295 | rx_ctx->ctx.state = TKIP_STATE_PHASE1_HW_UPLOADED; |
296 | } | 296 | } |
297 | 297 | ||
298 | tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key); | 298 | tkip_mixing_phase2(tk, &rx_ctx->ctx, iv16, rc4key); |
299 | 299 | ||
300 | res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12); | 300 | res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12); |
301 | done: | 301 | done: |
diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h index e3ecb659b90a..a1bcbfbefe7c 100644 --- a/net/mac80211/tkip.h +++ b/net/mac80211/tkip.h | |||
@@ -13,8 +13,6 @@ | |||
13 | #include <linux/crypto.h> | 13 | #include <linux/crypto.h> |
14 | #include "key.h" | 14 | #include "key.h" |
15 | 15 | ||
16 | u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key); | ||
17 | |||
18 | int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, | 16 | int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, |
19 | struct ieee80211_key *key, | 17 | struct ieee80211_key *key, |
20 | struct sk_buff *skb, | 18 | struct sk_buff *skb, |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index a6b4442776a0..2b0a17ee907a 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -80,7 +80,23 @@ | |||
80 | #define KEY_PR_FMT " cipher:0x%x, flags=%#x, keyidx=%d, hw_key_idx=%d" | 80 | #define KEY_PR_FMT " cipher:0x%x, flags=%#x, keyidx=%d, hw_key_idx=%d" |
81 | #define KEY_PR_ARG __entry->cipher, __entry->flags, __entry->keyidx, __entry->hw_key_idx | 81 | #define KEY_PR_ARG __entry->cipher, __entry->flags, __entry->keyidx, __entry->hw_key_idx |
82 | 82 | ||
83 | 83 | #define AMPDU_ACTION_ENTRY __field(enum ieee80211_ampdu_mlme_action, \ | |
84 | ieee80211_ampdu_mlme_action) \ | ||
85 | STA_ENTRY \ | ||
86 | __field(u16, tid) \ | ||
87 | __field(u16, ssn) \ | ||
88 | __field(u8, buf_size) \ | ||
89 | __field(bool, amsdu) \ | ||
90 | __field(u16, timeout) | ||
91 | #define AMPDU_ACTION_ASSIGN STA_NAMED_ASSIGN(params->sta); \ | ||
92 | __entry->tid = params->tid; \ | ||
93 | __entry->ssn = params->ssn; \ | ||
94 | __entry->buf_size = params->buf_size; \ | ||
95 | __entry->amsdu = params->amsdu; \ | ||
96 | __entry->timeout = params->timeout; | ||
97 | #define AMPDU_ACTION_PR_FMT STA_PR_FMT " tid %d, ssn %d, buf_size %u, amsdu %d, timeout %d" | ||
98 | #define AMPDU_ACTION_PR_ARG STA_PR_ARG, __entry->tid, __entry->ssn, \ | ||
99 | __entry->buf_size, __entry->amsdu, __entry->timeout | ||
84 | 100 | ||
85 | /* | 101 | /* |
86 | * Tracing for driver callbacks. | 102 | * Tracing for driver callbacks. |
@@ -970,38 +986,25 @@ DEFINE_EVENT(local_only_evt, drv_tx_last_beacon, | |||
970 | TRACE_EVENT(drv_ampdu_action, | 986 | TRACE_EVENT(drv_ampdu_action, |
971 | TP_PROTO(struct ieee80211_local *local, | 987 | TP_PROTO(struct ieee80211_local *local, |
972 | struct ieee80211_sub_if_data *sdata, | 988 | struct ieee80211_sub_if_data *sdata, |
973 | enum ieee80211_ampdu_mlme_action action, | 989 | struct ieee80211_ampdu_params *params), |
974 | struct ieee80211_sta *sta, u16 tid, | ||
975 | u16 *ssn, u8 buf_size, bool amsdu), | ||
976 | 990 | ||
977 | TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size, amsdu), | 991 | TP_ARGS(local, sdata, params), |
978 | 992 | ||
979 | TP_STRUCT__entry( | 993 | TP_STRUCT__entry( |
980 | LOCAL_ENTRY | 994 | LOCAL_ENTRY |
981 | STA_ENTRY | ||
982 | __field(u32, action) | ||
983 | __field(u16, tid) | ||
984 | __field(u16, ssn) | ||
985 | __field(u8, buf_size) | ||
986 | __field(bool, amsdu) | ||
987 | VIF_ENTRY | 995 | VIF_ENTRY |
996 | AMPDU_ACTION_ENTRY | ||
988 | ), | 997 | ), |
989 | 998 | ||
990 | TP_fast_assign( | 999 | TP_fast_assign( |
991 | LOCAL_ASSIGN; | 1000 | LOCAL_ASSIGN; |
992 | VIF_ASSIGN; | 1001 | VIF_ASSIGN; |
993 | STA_ASSIGN; | 1002 | AMPDU_ACTION_ASSIGN; |
994 | __entry->action = action; | ||
995 | __entry->tid = tid; | ||
996 | __entry->ssn = ssn ? *ssn : 0; | ||
997 | __entry->buf_size = buf_size; | ||
998 | __entry->amsdu = amsdu; | ||
999 | ), | 1003 | ), |
1000 | 1004 | ||
1001 | TP_printk( | 1005 | TP_printk( |
1002 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d amsdu:%d", | 1006 | LOCAL_PR_FMT VIF_PR_FMT AMPDU_ACTION_PR_FMT, |
1003 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, | 1007 | LOCAL_PR_ARG, VIF_PR_ARG, AMPDU_ACTION_PR_ARG |
1004 | __entry->tid, __entry->buf_size, __entry->amsdu | ||
1005 | ) | 1008 | ) |
1006 | ); | 1009 | ); |
1007 | 1010 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3311ce0f3d6c..3a7475ff1a41 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -710,6 +710,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
710 | 710 | ||
711 | info->control.short_preamble = txrc.short_preamble; | 711 | info->control.short_preamble = txrc.short_preamble; |
712 | 712 | ||
713 | /* don't ask rate control when rate already injected via radiotap */ | ||
714 | if (info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT) | ||
715 | return TX_CONTINUE; | ||
716 | |||
713 | if (tx->sta) | 717 | if (tx->sta) |
714 | assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC); | 718 | assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC); |
715 | 719 | ||
@@ -1266,7 +1270,11 @@ static void ieee80211_drv_tx(struct ieee80211_local *local, | |||
1266 | if (atomic_read(&sdata->txqs_len[ac]) >= local->hw.txq_ac_max_pending) | 1270 | if (atomic_read(&sdata->txqs_len[ac]) >= local->hw.txq_ac_max_pending) |
1267 | netif_stop_subqueue(sdata->dev, ac); | 1271 | netif_stop_subqueue(sdata->dev, ac); |
1268 | 1272 | ||
1269 | skb_queue_tail(&txqi->queue, skb); | 1273 | spin_lock_bh(&txqi->queue.lock); |
1274 | txqi->byte_cnt += skb->len; | ||
1275 | __skb_queue_tail(&txqi->queue, skb); | ||
1276 | spin_unlock_bh(&txqi->queue.lock); | ||
1277 | |||
1270 | drv_wake_tx_queue(local, txqi); | 1278 | drv_wake_tx_queue(local, txqi); |
1271 | 1279 | ||
1272 | return; | 1280 | return; |
@@ -1294,6 +1302,8 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, | |||
1294 | if (!skb) | 1302 | if (!skb) |
1295 | goto out; | 1303 | goto out; |
1296 | 1304 | ||
1305 | txqi->byte_cnt -= skb->len; | ||
1306 | |||
1297 | atomic_dec(&sdata->txqs_len[ac]); | 1307 | atomic_dec(&sdata->txqs_len[ac]); |
1298 | if (__netif_subqueue_stopped(sdata->dev, ac)) | 1308 | if (__netif_subqueue_stopped(sdata->dev, ac)) |
1299 | ieee80211_propagate_queue_wake(local, sdata->vif.hw_queue[ac]); | 1309 | ieee80211_propagate_queue_wake(local, sdata->vif.hw_queue[ac]); |
@@ -1665,15 +1675,24 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
1665 | ieee80211_tx(sdata, sta, skb, false); | 1675 | ieee80211_tx(sdata, sta, skb, false); |
1666 | } | 1676 | } |
1667 | 1677 | ||
1668 | static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) | 1678 | static bool ieee80211_parse_tx_radiotap(struct ieee80211_local *local, |
1679 | struct sk_buff *skb) | ||
1669 | { | 1680 | { |
1670 | struct ieee80211_radiotap_iterator iterator; | 1681 | struct ieee80211_radiotap_iterator iterator; |
1671 | struct ieee80211_radiotap_header *rthdr = | 1682 | struct ieee80211_radiotap_header *rthdr = |
1672 | (struct ieee80211_radiotap_header *) skb->data; | 1683 | (struct ieee80211_radiotap_header *) skb->data; |
1673 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1684 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1685 | struct ieee80211_supported_band *sband = | ||
1686 | local->hw.wiphy->bands[info->band]; | ||
1674 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, | 1687 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, |
1675 | NULL); | 1688 | NULL); |
1676 | u16 txflags; | 1689 | u16 txflags; |
1690 | u16 rate = 0; | ||
1691 | bool rate_found = false; | ||
1692 | u8 rate_retries = 0; | ||
1693 | u16 rate_flags = 0; | ||
1694 | u8 mcs_known, mcs_flags; | ||
1695 | int i; | ||
1677 | 1696 | ||
1678 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | | 1697 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | |
1679 | IEEE80211_TX_CTL_DONTFRAG; | 1698 | IEEE80211_TX_CTL_DONTFRAG; |
@@ -1724,6 +1743,35 @@ static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) | |||
1724 | info->flags |= IEEE80211_TX_CTL_NO_ACK; | 1743 | info->flags |= IEEE80211_TX_CTL_NO_ACK; |
1725 | break; | 1744 | break; |
1726 | 1745 | ||
1746 | case IEEE80211_RADIOTAP_RATE: | ||
1747 | rate = *iterator.this_arg; | ||
1748 | rate_flags = 0; | ||
1749 | rate_found = true; | ||
1750 | break; | ||
1751 | |||
1752 | case IEEE80211_RADIOTAP_DATA_RETRIES: | ||
1753 | rate_retries = *iterator.this_arg; | ||
1754 | break; | ||
1755 | |||
1756 | case IEEE80211_RADIOTAP_MCS: | ||
1757 | mcs_known = iterator.this_arg[0]; | ||
1758 | mcs_flags = iterator.this_arg[1]; | ||
1759 | if (!(mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_MCS)) | ||
1760 | break; | ||
1761 | |||
1762 | rate_found = true; | ||
1763 | rate = iterator.this_arg[2]; | ||
1764 | rate_flags = IEEE80211_TX_RC_MCS; | ||
1765 | |||
1766 | if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_GI && | ||
1767 | mcs_flags & IEEE80211_RADIOTAP_MCS_SGI) | ||
1768 | rate_flags |= IEEE80211_TX_RC_SHORT_GI; | ||
1769 | |||
1770 | if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_BW && | ||
1771 | mcs_flags & IEEE80211_RADIOTAP_MCS_BW_40) | ||
1772 | rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||
1773 | break; | ||
1774 | |||
1727 | /* | 1775 | /* |
1728 | * Please update the file | 1776 | * Please update the file |
1729 | * Documentation/networking/mac80211-injection.txt | 1777 | * Documentation/networking/mac80211-injection.txt |
@@ -1738,6 +1786,32 @@ static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) | |||
1738 | if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ | 1786 | if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ |
1739 | return false; | 1787 | return false; |
1740 | 1788 | ||
1789 | if (rate_found) { | ||
1790 | info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT; | ||
1791 | |||
1792 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | ||
1793 | info->control.rates[i].idx = -1; | ||
1794 | info->control.rates[i].flags = 0; | ||
1795 | info->control.rates[i].count = 0; | ||
1796 | } | ||
1797 | |||
1798 | if (rate_flags & IEEE80211_TX_RC_MCS) { | ||
1799 | info->control.rates[0].idx = rate; | ||
1800 | } else { | ||
1801 | for (i = 0; i < sband->n_bitrates; i++) { | ||
1802 | if (rate * 5 != sband->bitrates[i].bitrate) | ||
1803 | continue; | ||
1804 | |||
1805 | info->control.rates[0].idx = i; | ||
1806 | break; | ||
1807 | } | ||
1808 | } | ||
1809 | |||
1810 | info->control.rates[0].flags = rate_flags; | ||
1811 | info->control.rates[0].count = min_t(u8, rate_retries + 1, | ||
1812 | local->hw.max_rate_tries); | ||
1813 | } | ||
1814 | |||
1741 | /* | 1815 | /* |
1742 | * remove the radiotap header | 1816 | * remove the radiotap header |
1743 | * iterator->_max_length was sanity-checked against | 1817 | * iterator->_max_length was sanity-checked against |
@@ -1818,10 +1892,6 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1818 | info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS | | 1892 | info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS | |
1819 | IEEE80211_TX_CTL_INJECTED; | 1893 | IEEE80211_TX_CTL_INJECTED; |
1820 | 1894 | ||
1821 | /* process and remove the injection radiotap header */ | ||
1822 | if (!ieee80211_parse_tx_radiotap(skb)) | ||
1823 | goto fail; | ||
1824 | |||
1825 | rcu_read_lock(); | 1895 | rcu_read_lock(); |
1826 | 1896 | ||
1827 | /* | 1897 | /* |
@@ -1883,6 +1953,11 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1883 | goto fail_rcu; | 1953 | goto fail_rcu; |
1884 | 1954 | ||
1885 | info->band = chandef->chan->band; | 1955 | info->band = chandef->chan->band; |
1956 | |||
1957 | /* process and remove the injection radiotap header */ | ||
1958 | if (!ieee80211_parse_tx_radiotap(local, skb)) | ||
1959 | goto fail_rcu; | ||
1960 | |||
1886 | ieee80211_xmit(sdata, NULL, skb); | 1961 | ieee80211_xmit(sdata, NULL, skb); |
1887 | rcu_read_unlock(); | 1962 | rcu_read_unlock(); |
1888 | 1963 | ||
@@ -2099,8 +2174,11 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
2099 | mpp_lookup = true; | 2174 | mpp_lookup = true; |
2100 | } | 2175 | } |
2101 | 2176 | ||
2102 | if (mpp_lookup) | 2177 | if (mpp_lookup) { |
2103 | mppath = mpp_path_lookup(sdata, skb->data); | 2178 | mppath = mpp_path_lookup(sdata, skb->data); |
2179 | if (mppath) | ||
2180 | mppath->exp_time = jiffies; | ||
2181 | } | ||
2104 | 2182 | ||
2105 | if (mppath && mpath) | 2183 | if (mppath && mpath) |
2106 | mesh_path_del(mpath->sdata, mpath->dst); | 2184 | mesh_path_del(mpath->sdata, mpath->dst); |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 58f58bd5202f..7390de4946a9 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
5 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | 5 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> |
6 | * Copyright 2013-2014 Intel Mobile Communications GmbH | 6 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
7 | * Copyright (C) 2015 Intel Deutschland GmbH | 7 | * Copyright (C) 2015-2016 Intel Deutschland GmbH |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
@@ -1928,6 +1928,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1928 | BSS_CHANGED_IDLE | | 1928 | BSS_CHANGED_IDLE | |
1929 | BSS_CHANGED_TXPOWER; | 1929 | BSS_CHANGED_TXPOWER; |
1930 | 1930 | ||
1931 | if (sdata->vif.mu_mimo_owner) | ||
1932 | changed |= BSS_CHANGED_MU_GROUPS; | ||
1933 | |||
1931 | switch (sdata->vif.type) { | 1934 | switch (sdata->vif.type) { |
1932 | case NL80211_IFTYPE_STATION: | 1935 | case NL80211_IFTYPE_STATION: |
1933 | changed |= BSS_CHANGED_ASSOC | | 1936 | changed |= BSS_CHANGED_ASSOC | |
@@ -2371,10 +2374,23 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | |||
2371 | 2374 | ||
2372 | switch (chandef->width) { | 2375 | switch (chandef->width) { |
2373 | case NL80211_CHAN_WIDTH_160: | 2376 | case NL80211_CHAN_WIDTH_160: |
2374 | vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ; | 2377 | /* |
2378 | * Convert 160 MHz channel width to new style as interop | ||
2379 | * workaround. | ||
2380 | */ | ||
2381 | vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ; | ||
2382 | vht_oper->center_freq_seg2_idx = vht_oper->center_freq_seg1_idx; | ||
2383 | if (chandef->chan->center_freq < chandef->center_freq1) | ||
2384 | vht_oper->center_freq_seg1_idx -= 8; | ||
2385 | else | ||
2386 | vht_oper->center_freq_seg1_idx += 8; | ||
2375 | break; | 2387 | break; |
2376 | case NL80211_CHAN_WIDTH_80P80: | 2388 | case NL80211_CHAN_WIDTH_80P80: |
2377 | vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ; | 2389 | /* |
2390 | * Convert 80+80 MHz channel width to new style as interop | ||
2391 | * workaround. | ||
2392 | */ | ||
2393 | vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ; | ||
2378 | break; | 2394 | break; |
2379 | case NL80211_CHAN_WIDTH_80: | 2395 | case NL80211_CHAN_WIDTH_80: |
2380 | vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ; | 2396 | vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ; |
@@ -2390,17 +2406,13 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | |||
2390 | return pos + sizeof(struct ieee80211_vht_operation); | 2406 | return pos + sizeof(struct ieee80211_vht_operation); |
2391 | } | 2407 | } |
2392 | 2408 | ||
2393 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, | 2409 | bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper, |
2394 | const struct ieee80211_ht_operation *ht_oper, | 2410 | struct cfg80211_chan_def *chandef) |
2395 | struct cfg80211_chan_def *chandef) | ||
2396 | { | 2411 | { |
2397 | enum nl80211_channel_type channel_type; | 2412 | enum nl80211_channel_type channel_type; |
2398 | 2413 | ||
2399 | if (!ht_oper) { | 2414 | if (!ht_oper) |
2400 | cfg80211_chandef_create(chandef, control_chan, | 2415 | return false; |
2401 | NL80211_CHAN_NO_HT); | ||
2402 | return; | ||
2403 | } | ||
2404 | 2416 | ||
2405 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 2417 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
2406 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | 2418 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: |
@@ -2414,42 +2426,66 @@ void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, | |||
2414 | break; | 2426 | break; |
2415 | default: | 2427 | default: |
2416 | channel_type = NL80211_CHAN_NO_HT; | 2428 | channel_type = NL80211_CHAN_NO_HT; |
2429 | return false; | ||
2417 | } | 2430 | } |
2418 | 2431 | ||
2419 | cfg80211_chandef_create(chandef, control_chan, channel_type); | 2432 | cfg80211_chandef_create(chandef, chandef->chan, channel_type); |
2433 | return true; | ||
2420 | } | 2434 | } |
2421 | 2435 | ||
2422 | void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan, | 2436 | bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper, |
2423 | const struct ieee80211_vht_operation *oper, | 2437 | struct cfg80211_chan_def *chandef) |
2424 | struct cfg80211_chan_def *chandef) | ||
2425 | { | 2438 | { |
2439 | struct cfg80211_chan_def new = *chandef; | ||
2440 | int cf1, cf2; | ||
2441 | |||
2426 | if (!oper) | 2442 | if (!oper) |
2427 | return; | 2443 | return false; |
2428 | 2444 | ||
2429 | chandef->chan = control_chan; | 2445 | cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx, |
2446 | chandef->chan->band); | ||
2447 | cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg2_idx, | ||
2448 | chandef->chan->band); | ||
2430 | 2449 | ||
2431 | switch (oper->chan_width) { | 2450 | switch (oper->chan_width) { |
2432 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | 2451 | case IEEE80211_VHT_CHANWIDTH_USE_HT: |
2433 | break; | 2452 | break; |
2434 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | 2453 | case IEEE80211_VHT_CHANWIDTH_80MHZ: |
2435 | chandef->width = NL80211_CHAN_WIDTH_80; | 2454 | new.width = NL80211_CHAN_WIDTH_80; |
2455 | new.center_freq1 = cf1; | ||
2456 | /* If needed, adjust based on the newer interop workaround. */ | ||
2457 | if (oper->center_freq_seg2_idx) { | ||
2458 | unsigned int diff; | ||
2459 | |||
2460 | diff = abs(oper->center_freq_seg2_idx - | ||
2461 | oper->center_freq_seg1_idx); | ||
2462 | if (diff == 8) { | ||
2463 | new.width = NL80211_CHAN_WIDTH_160; | ||
2464 | new.center_freq1 = cf2; | ||
2465 | } else if (diff > 8) { | ||
2466 | new.width = NL80211_CHAN_WIDTH_80P80; | ||
2467 | new.center_freq2 = cf2; | ||
2468 | } | ||
2469 | } | ||
2436 | break; | 2470 | break; |
2437 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | 2471 | case IEEE80211_VHT_CHANWIDTH_160MHZ: |
2438 | chandef->width = NL80211_CHAN_WIDTH_160; | 2472 | new.width = NL80211_CHAN_WIDTH_160; |
2473 | new.center_freq1 = cf1; | ||
2439 | break; | 2474 | break; |
2440 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | 2475 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: |
2441 | chandef->width = NL80211_CHAN_WIDTH_80P80; | 2476 | new.width = NL80211_CHAN_WIDTH_80P80; |
2477 | new.center_freq1 = cf1; | ||
2478 | new.center_freq2 = cf2; | ||
2442 | break; | 2479 | break; |
2443 | default: | 2480 | default: |
2444 | break; | 2481 | return false; |
2445 | } | 2482 | } |
2446 | 2483 | ||
2447 | chandef->center_freq1 = | 2484 | if (!cfg80211_chandef_valid(&new)) |
2448 | ieee80211_channel_to_frequency(oper->center_freq_seg1_idx, | 2485 | return false; |
2449 | control_chan->band); | 2486 | |
2450 | chandef->center_freq2 = | 2487 | *chandef = new; |
2451 | ieee80211_channel_to_frequency(oper->center_freq_seg2_idx, | 2488 | return true; |
2452 | control_chan->band); | ||
2453 | } | 2489 | } |
2454 | 2490 | ||
2455 | int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef, | 2491 | int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef, |
@@ -2672,6 +2708,18 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | |||
2672 | sband = local->hw.wiphy->bands[status->band]; | 2708 | sband = local->hw.wiphy->bands[status->band]; |
2673 | bitrate = sband->bitrates[status->rate_idx].bitrate; | 2709 | bitrate = sband->bitrates[status->rate_idx].bitrate; |
2674 | ri.legacy = DIV_ROUND_UP(bitrate, (1 << shift)); | 2710 | ri.legacy = DIV_ROUND_UP(bitrate, (1 << shift)); |
2711 | |||
2712 | if (status->flag & RX_FLAG_MACTIME_PLCP_START) { | ||
2713 | /* TODO: handle HT/VHT preambles */ | ||
2714 | if (status->band == IEEE80211_BAND_5GHZ) { | ||
2715 | ts += 20 << shift; | ||
2716 | mpdu_offset += 2; | ||
2717 | } else if (status->flag & RX_FLAG_SHORTPRE) { | ||
2718 | ts += 96; | ||
2719 | } else { | ||
2720 | ts += 192; | ||
2721 | } | ||
2722 | } | ||
2675 | } | 2723 | } |
2676 | 2724 | ||
2677 | rate = cfg80211_calculate_bitrate(&ri); | 2725 | rate = cfg80211_calculate_bitrate(&ri); |
@@ -3357,3 +3405,17 @@ void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata, | |||
3357 | txqi->txq.ac = IEEE80211_AC_BE; | 3405 | txqi->txq.ac = IEEE80211_AC_BE; |
3358 | } | 3406 | } |
3359 | } | 3407 | } |
3408 | |||
3409 | void ieee80211_txq_get_depth(struct ieee80211_txq *txq, | ||
3410 | unsigned long *frame_cnt, | ||
3411 | unsigned long *byte_cnt) | ||
3412 | { | ||
3413 | struct txq_info *txqi = to_txq_info(txq); | ||
3414 | |||
3415 | if (frame_cnt) | ||
3416 | *frame_cnt = txqi->queue.qlen; | ||
3417 | |||
3418 | if (byte_cnt) | ||
3419 | *byte_cnt = txqi->byte_cnt; | ||
3420 | } | ||
3421 | EXPORT_SYMBOL(ieee80211_txq_get_depth); | ||
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index c38b2f07a919..89e04d55aa18 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -1,6 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * VHT handling | 2 | * VHT handling |
3 | * | 3 | * |
4 | * Portions of this file | ||
5 | * Copyright(c) 2015 - 2016 Intel Deutschland GmbH | ||
6 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
6 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
@@ -278,6 +281,23 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
278 | } | 281 | } |
279 | 282 | ||
280 | sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta); | 283 | sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta); |
284 | |||
285 | /* If HT IE reported 3839 bytes only, stay with that size. */ | ||
286 | if (sta->sta.max_amsdu_len == IEEE80211_MAX_MPDU_LEN_HT_3839) | ||
287 | return; | ||
288 | |||
289 | switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) { | ||
290 | case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454: | ||
291 | sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454; | ||
292 | break; | ||
293 | case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991: | ||
294 | sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_7991; | ||
295 | break; | ||
296 | case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895: | ||
297 | default: | ||
298 | sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_3895; | ||
299 | break; | ||
300 | } | ||
281 | } | 301 | } |
282 | 302 | ||
283 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta) | 303 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta) |
@@ -425,6 +445,43 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | |||
425 | return changed; | 445 | return changed; |
426 | } | 446 | } |
427 | 447 | ||
448 | void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata, | ||
449 | struct ieee80211_mgmt *mgmt) | ||
450 | { | ||
451 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | ||
452 | |||
453 | if (!sdata->vif.mu_mimo_owner) | ||
454 | return; | ||
455 | |||
456 | if (!memcmp(mgmt->u.action.u.vht_group_notif.position, | ||
457 | bss_conf->mu_group.position, WLAN_USER_POSITION_LEN) && | ||
458 | !memcmp(mgmt->u.action.u.vht_group_notif.membership, | ||
459 | bss_conf->mu_group.membership, WLAN_MEMBERSHIP_LEN)) | ||
460 | return; | ||
461 | |||
462 | memcpy(bss_conf->mu_group.membership, | ||
463 | mgmt->u.action.u.vht_group_notif.membership, | ||
464 | WLAN_MEMBERSHIP_LEN); | ||
465 | memcpy(bss_conf->mu_group.position, | ||
466 | mgmt->u.action.u.vht_group_notif.position, | ||
467 | WLAN_USER_POSITION_LEN); | ||
468 | |||
469 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MU_GROUPS); | ||
470 | } | ||
471 | |||
472 | void ieee80211_update_mu_groups(struct ieee80211_vif *vif, | ||
473 | const u8 *membership, const u8 *position) | ||
474 | { | ||
475 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
476 | |||
477 | if (WARN_ON_ONCE(!vif->mu_mimo_owner)) | ||
478 | return; | ||
479 | |||
480 | memcpy(bss_conf->mu_group.membership, membership, WLAN_MEMBERSHIP_LEN); | ||
481 | memcpy(bss_conf->mu_group.position, position, WLAN_USER_POSITION_LEN); | ||
482 | } | ||
483 | EXPORT_SYMBOL_GPL(ieee80211_update_mu_groups); | ||
484 | |||
428 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | 485 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, |
429 | struct sta_info *sta, u8 opmode, | 486 | struct sta_info *sta, u8 opmode, |
430 | enum ieee80211_band band) | 487 | enum ieee80211_band band) |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index d824c38971ed..18848258adde 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2002-2004, Instant802 Networks, Inc. | 2 | * Copyright 2002-2004, Instant802 Networks, Inc. |
3 | * Copyright 2008, Jouni Malinen <j@w1.fi> | 3 | * Copyright 2008, Jouni Malinen <j@w1.fi> |
4 | * Copyright (C) 2016 Intel Deutschland GmbH | ||
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
@@ -183,7 +184,6 @@ mic_fail_no_key: | |||
183 | return RX_DROP_UNUSABLE; | 184 | return RX_DROP_UNUSABLE; |
184 | } | 185 | } |
185 | 186 | ||
186 | |||
187 | static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | 187 | static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) |
188 | { | 188 | { |
189 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 189 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
@@ -191,6 +191,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
191 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 191 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
192 | unsigned int hdrlen; | 192 | unsigned int hdrlen; |
193 | int len, tail; | 193 | int len, tail; |
194 | u64 pn; | ||
194 | u8 *pos; | 195 | u8 *pos; |
195 | 196 | ||
196 | if (info->control.hw_key && | 197 | if (info->control.hw_key && |
@@ -222,12 +223,8 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
222 | return 0; | 223 | return 0; |
223 | 224 | ||
224 | /* Increase IV for the frame */ | 225 | /* Increase IV for the frame */ |
225 | spin_lock(&key->u.tkip.txlock); | 226 | pn = atomic64_inc_return(&key->conf.tx_pn); |
226 | key->u.tkip.tx.iv16++; | 227 | pos = ieee80211_tkip_add_iv(pos, &key->conf, pn); |
227 | if (key->u.tkip.tx.iv16 == 0) | ||
228 | key->u.tkip.tx.iv32++; | ||
229 | pos = ieee80211_tkip_add_iv(pos, key); | ||
230 | spin_unlock(&key->u.tkip.txlock); | ||
231 | 228 | ||
232 | /* hwaccel - with software IV */ | 229 | /* hwaccel - with software IV */ |
233 | if (info->control.hw_key) | 230 | if (info->control.hw_key) |
diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig index 598d374f6a35..868f1ad0415a 100644 --- a/net/rfkill/Kconfig +++ b/net/rfkill/Kconfig | |||
@@ -41,5 +41,4 @@ config RFKILL_GPIO | |||
41 | default n | 41 | default n |
42 | help | 42 | help |
43 | If you say yes here you get support of a generic gpio RFKILL | 43 | If you say yes here you get support of a generic gpio RFKILL |
44 | driver. The platform should fill in the appropriate fields in the | 44 | driver. |
45 | rfkill_gpio_platform_data structure and pass that to the driver. | ||
diff --git a/net/rfkill/core.c b/net/rfkill/core.c index cf5b69ab1829..03f26e3a6f48 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c | |||
@@ -57,6 +57,8 @@ struct rfkill { | |||
57 | 57 | ||
58 | bool registered; | 58 | bool registered; |
59 | bool persistent; | 59 | bool persistent; |
60 | bool polling_paused; | ||
61 | bool suspended; | ||
60 | 62 | ||
61 | const struct rfkill_ops *ops; | 63 | const struct rfkill_ops *ops; |
62 | void *data; | 64 | void *data; |
@@ -233,29 +235,6 @@ static void rfkill_event(struct rfkill *rfkill) | |||
233 | rfkill_send_events(rfkill, RFKILL_OP_CHANGE); | 235 | rfkill_send_events(rfkill, RFKILL_OP_CHANGE); |
234 | } | 236 | } |
235 | 237 | ||
236 | static bool __rfkill_set_hw_state(struct rfkill *rfkill, | ||
237 | bool blocked, bool *change) | ||
238 | { | ||
239 | unsigned long flags; | ||
240 | bool prev, any; | ||
241 | |||
242 | BUG_ON(!rfkill); | ||
243 | |||
244 | spin_lock_irqsave(&rfkill->lock, flags); | ||
245 | prev = !!(rfkill->state & RFKILL_BLOCK_HW); | ||
246 | if (blocked) | ||
247 | rfkill->state |= RFKILL_BLOCK_HW; | ||
248 | else | ||
249 | rfkill->state &= ~RFKILL_BLOCK_HW; | ||
250 | *change = prev != blocked; | ||
251 | any = !!(rfkill->state & RFKILL_BLOCK_ANY); | ||
252 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
253 | |||
254 | rfkill_led_trigger_event(rfkill); | ||
255 | |||
256 | return any; | ||
257 | } | ||
258 | |||
259 | /** | 238 | /** |
260 | * rfkill_set_block - wrapper for set_block method | 239 | * rfkill_set_block - wrapper for set_block method |
261 | * | 240 | * |
@@ -285,7 +264,7 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked) | |||
285 | spin_lock_irqsave(&rfkill->lock, flags); | 264 | spin_lock_irqsave(&rfkill->lock, flags); |
286 | prev = rfkill->state & RFKILL_BLOCK_SW; | 265 | prev = rfkill->state & RFKILL_BLOCK_SW; |
287 | 266 | ||
288 | if (rfkill->state & RFKILL_BLOCK_SW) | 267 | if (prev) |
289 | rfkill->state |= RFKILL_BLOCK_SW_PREV; | 268 | rfkill->state |= RFKILL_BLOCK_SW_PREV; |
290 | else | 269 | else |
291 | rfkill->state &= ~RFKILL_BLOCK_SW_PREV; | 270 | rfkill->state &= ~RFKILL_BLOCK_SW_PREV; |
@@ -303,8 +282,8 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked) | |||
303 | spin_lock_irqsave(&rfkill->lock, flags); | 282 | spin_lock_irqsave(&rfkill->lock, flags); |
304 | if (err) { | 283 | if (err) { |
305 | /* | 284 | /* |
306 | * Failed -- reset status to _prev, this may be different | 285 | * Failed -- reset status to _PREV, which may be different |
307 | * from what set set _PREV to earlier in this function | 286 | * from what we have set _PREV to earlier in this function |
308 | * if rfkill_set_sw_state was invoked. | 287 | * if rfkill_set_sw_state was invoked. |
309 | */ | 288 | */ |
310 | if (rfkill->state & RFKILL_BLOCK_SW_PREV) | 289 | if (rfkill->state & RFKILL_BLOCK_SW_PREV) |
@@ -323,6 +302,19 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked) | |||
323 | rfkill_event(rfkill); | 302 | rfkill_event(rfkill); |
324 | } | 303 | } |
325 | 304 | ||
305 | static void rfkill_update_global_state(enum rfkill_type type, bool blocked) | ||
306 | { | ||
307 | int i; | ||
308 | |||
309 | if (type != RFKILL_TYPE_ALL) { | ||
310 | rfkill_global_states[type].cur = blocked; | ||
311 | return; | ||
312 | } | ||
313 | |||
314 | for (i = 0; i < NUM_RFKILL_TYPES; i++) | ||
315 | rfkill_global_states[i].cur = blocked; | ||
316 | } | ||
317 | |||
326 | #ifdef CONFIG_RFKILL_INPUT | 318 | #ifdef CONFIG_RFKILL_INPUT |
327 | static atomic_t rfkill_input_disabled = ATOMIC_INIT(0); | 319 | static atomic_t rfkill_input_disabled = ATOMIC_INIT(0); |
328 | 320 | ||
@@ -332,8 +324,7 @@ static atomic_t rfkill_input_disabled = ATOMIC_INIT(0); | |||
332 | * @blocked: the new state | 324 | * @blocked: the new state |
333 | * | 325 | * |
334 | * This function sets the state of all switches of given type, | 326 | * This function sets the state of all switches of given type, |
335 | * unless a specific switch is claimed by userspace (in which case, | 327 | * unless a specific switch is suspended. |
336 | * that switch is left alone) or suspended. | ||
337 | * | 328 | * |
338 | * Caller must have acquired rfkill_global_mutex. | 329 | * Caller must have acquired rfkill_global_mutex. |
339 | */ | 330 | */ |
@@ -341,15 +332,7 @@ static void __rfkill_switch_all(const enum rfkill_type type, bool blocked) | |||
341 | { | 332 | { |
342 | struct rfkill *rfkill; | 333 | struct rfkill *rfkill; |
343 | 334 | ||
344 | if (type == RFKILL_TYPE_ALL) { | 335 | rfkill_update_global_state(type, blocked); |
345 | int i; | ||
346 | |||
347 | for (i = 0; i < NUM_RFKILL_TYPES; i++) | ||
348 | rfkill_global_states[i].cur = blocked; | ||
349 | } else { | ||
350 | rfkill_global_states[type].cur = blocked; | ||
351 | } | ||
352 | |||
353 | list_for_each_entry(rfkill, &rfkill_list, node) { | 336 | list_for_each_entry(rfkill, &rfkill_list, node) { |
354 | if (rfkill->type != type && type != RFKILL_TYPE_ALL) | 337 | if (rfkill->type != type && type != RFKILL_TYPE_ALL) |
355 | continue; | 338 | continue; |
@@ -477,17 +460,28 @@ bool rfkill_get_global_sw_state(const enum rfkill_type type) | |||
477 | } | 460 | } |
478 | #endif | 461 | #endif |
479 | 462 | ||
480 | |||
481 | bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked) | 463 | bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked) |
482 | { | 464 | { |
483 | bool ret, change; | 465 | unsigned long flags; |
466 | bool ret, prev; | ||
467 | |||
468 | BUG_ON(!rfkill); | ||
484 | 469 | ||
485 | ret = __rfkill_set_hw_state(rfkill, blocked, &change); | 470 | spin_lock_irqsave(&rfkill->lock, flags); |
471 | prev = !!(rfkill->state & RFKILL_BLOCK_HW); | ||
472 | if (blocked) | ||
473 | rfkill->state |= RFKILL_BLOCK_HW; | ||
474 | else | ||
475 | rfkill->state &= ~RFKILL_BLOCK_HW; | ||
476 | ret = !!(rfkill->state & RFKILL_BLOCK_ANY); | ||
477 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
478 | |||
479 | rfkill_led_trigger_event(rfkill); | ||
486 | 480 | ||
487 | if (!rfkill->registered) | 481 | if (!rfkill->registered) |
488 | return ret; | 482 | return ret; |
489 | 483 | ||
490 | if (change) | 484 | if (prev != blocked) |
491 | schedule_work(&rfkill->uevent_work); | 485 | schedule_work(&rfkill->uevent_work); |
492 | 486 | ||
493 | return ret; | 487 | return ret; |
@@ -582,6 +576,34 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) | |||
582 | } | 576 | } |
583 | EXPORT_SYMBOL(rfkill_set_states); | 577 | EXPORT_SYMBOL(rfkill_set_states); |
584 | 578 | ||
579 | static const char * const rfkill_types[] = { | ||
580 | NULL, /* RFKILL_TYPE_ALL */ | ||
581 | "wlan", | ||
582 | "bluetooth", | ||
583 | "ultrawideband", | ||
584 | "wimax", | ||
585 | "wwan", | ||
586 | "gps", | ||
587 | "fm", | ||
588 | "nfc", | ||
589 | }; | ||
590 | |||
591 | enum rfkill_type rfkill_find_type(const char *name) | ||
592 | { | ||
593 | int i; | ||
594 | |||
595 | BUILD_BUG_ON(ARRAY_SIZE(rfkill_types) != NUM_RFKILL_TYPES); | ||
596 | |||
597 | if (!name) | ||
598 | return RFKILL_TYPE_ALL; | ||
599 | |||
600 | for (i = 1; i < NUM_RFKILL_TYPES; i++) | ||
601 | if (!strcmp(name, rfkill_types[i])) | ||
602 | return i; | ||
603 | return RFKILL_TYPE_ALL; | ||
604 | } | ||
605 | EXPORT_SYMBOL(rfkill_find_type); | ||
606 | |||
585 | static ssize_t name_show(struct device *dev, struct device_attribute *attr, | 607 | static ssize_t name_show(struct device *dev, struct device_attribute *attr, |
586 | char *buf) | 608 | char *buf) |
587 | { | 609 | { |
@@ -591,38 +613,12 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr, | |||
591 | } | 613 | } |
592 | static DEVICE_ATTR_RO(name); | 614 | static DEVICE_ATTR_RO(name); |
593 | 615 | ||
594 | static const char *rfkill_get_type_str(enum rfkill_type type) | ||
595 | { | ||
596 | BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_NFC + 1); | ||
597 | |||
598 | switch (type) { | ||
599 | case RFKILL_TYPE_WLAN: | ||
600 | return "wlan"; | ||
601 | case RFKILL_TYPE_BLUETOOTH: | ||
602 | return "bluetooth"; | ||
603 | case RFKILL_TYPE_UWB: | ||
604 | return "ultrawideband"; | ||
605 | case RFKILL_TYPE_WIMAX: | ||
606 | return "wimax"; | ||
607 | case RFKILL_TYPE_WWAN: | ||
608 | return "wwan"; | ||
609 | case RFKILL_TYPE_GPS: | ||
610 | return "gps"; | ||
611 | case RFKILL_TYPE_FM: | ||
612 | return "fm"; | ||
613 | case RFKILL_TYPE_NFC: | ||
614 | return "nfc"; | ||
615 | default: | ||
616 | BUG(); | ||
617 | } | ||
618 | } | ||
619 | |||
620 | static ssize_t type_show(struct device *dev, struct device_attribute *attr, | 616 | static ssize_t type_show(struct device *dev, struct device_attribute *attr, |
621 | char *buf) | 617 | char *buf) |
622 | { | 618 | { |
623 | struct rfkill *rfkill = to_rfkill(dev); | 619 | struct rfkill *rfkill = to_rfkill(dev); |
624 | 620 | ||
625 | return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type)); | 621 | return sprintf(buf, "%s\n", rfkill_types[rfkill->type]); |
626 | } | 622 | } |
627 | static DEVICE_ATTR_RO(type); | 623 | static DEVICE_ATTR_RO(type); |
628 | 624 | ||
@@ -730,20 +726,12 @@ static ssize_t state_store(struct device *dev, struct device_attribute *attr, | |||
730 | } | 726 | } |
731 | static DEVICE_ATTR_RW(state); | 727 | static DEVICE_ATTR_RW(state); |
732 | 728 | ||
733 | static ssize_t claim_show(struct device *dev, struct device_attribute *attr, | ||
734 | char *buf) | ||
735 | { | ||
736 | return sprintf(buf, "%d\n", 0); | ||
737 | } | ||
738 | static DEVICE_ATTR_RO(claim); | ||
739 | |||
740 | static struct attribute *rfkill_dev_attrs[] = { | 729 | static struct attribute *rfkill_dev_attrs[] = { |
741 | &dev_attr_name.attr, | 730 | &dev_attr_name.attr, |
742 | &dev_attr_type.attr, | 731 | &dev_attr_type.attr, |
743 | &dev_attr_index.attr, | 732 | &dev_attr_index.attr, |
744 | &dev_attr_persistent.attr, | 733 | &dev_attr_persistent.attr, |
745 | &dev_attr_state.attr, | 734 | &dev_attr_state.attr, |
746 | &dev_attr_claim.attr, | ||
747 | &dev_attr_soft.attr, | 735 | &dev_attr_soft.attr, |
748 | &dev_attr_hard.attr, | 736 | &dev_attr_hard.attr, |
749 | NULL, | 737 | NULL, |
@@ -768,7 +756,7 @@ static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
768 | if (error) | 756 | if (error) |
769 | return error; | 757 | return error; |
770 | error = add_uevent_var(env, "RFKILL_TYPE=%s", | 758 | error = add_uevent_var(env, "RFKILL_TYPE=%s", |
771 | rfkill_get_type_str(rfkill->type)); | 759 | rfkill_types[rfkill->type]); |
772 | if (error) | 760 | if (error) |
773 | return error; | 761 | return error; |
774 | spin_lock_irqsave(&rfkill->lock, flags); | 762 | spin_lock_irqsave(&rfkill->lock, flags); |
@@ -786,6 +774,7 @@ void rfkill_pause_polling(struct rfkill *rfkill) | |||
786 | if (!rfkill->ops->poll) | 774 | if (!rfkill->ops->poll) |
787 | return; | 775 | return; |
788 | 776 | ||
777 | rfkill->polling_paused = true; | ||
789 | cancel_delayed_work_sync(&rfkill->poll_work); | 778 | cancel_delayed_work_sync(&rfkill->poll_work); |
790 | } | 779 | } |
791 | EXPORT_SYMBOL(rfkill_pause_polling); | 780 | EXPORT_SYMBOL(rfkill_pause_polling); |
@@ -797,6 +786,11 @@ void rfkill_resume_polling(struct rfkill *rfkill) | |||
797 | if (!rfkill->ops->poll) | 786 | if (!rfkill->ops->poll) |
798 | return; | 787 | return; |
799 | 788 | ||
789 | rfkill->polling_paused = false; | ||
790 | |||
791 | if (rfkill->suspended) | ||
792 | return; | ||
793 | |||
800 | queue_delayed_work(system_power_efficient_wq, | 794 | queue_delayed_work(system_power_efficient_wq, |
801 | &rfkill->poll_work, 0); | 795 | &rfkill->poll_work, 0); |
802 | } | 796 | } |
@@ -807,7 +801,8 @@ static int rfkill_suspend(struct device *dev) | |||
807 | { | 801 | { |
808 | struct rfkill *rfkill = to_rfkill(dev); | 802 | struct rfkill *rfkill = to_rfkill(dev); |
809 | 803 | ||
810 | rfkill_pause_polling(rfkill); | 804 | rfkill->suspended = true; |
805 | cancel_delayed_work_sync(&rfkill->poll_work); | ||
811 | 806 | ||
812 | return 0; | 807 | return 0; |
813 | } | 808 | } |
@@ -817,12 +812,16 @@ static int rfkill_resume(struct device *dev) | |||
817 | struct rfkill *rfkill = to_rfkill(dev); | 812 | struct rfkill *rfkill = to_rfkill(dev); |
818 | bool cur; | 813 | bool cur; |
819 | 814 | ||
815 | rfkill->suspended = false; | ||
816 | |||
820 | if (!rfkill->persistent) { | 817 | if (!rfkill->persistent) { |
821 | cur = !!(rfkill->state & RFKILL_BLOCK_SW); | 818 | cur = !!(rfkill->state & RFKILL_BLOCK_SW); |
822 | rfkill_set_block(rfkill, cur); | 819 | rfkill_set_block(rfkill, cur); |
823 | } | 820 | } |
824 | 821 | ||
825 | rfkill_resume_polling(rfkill); | 822 | if (rfkill->ops->poll && !rfkill->polling_paused) |
823 | queue_delayed_work(system_power_efficient_wq, | ||
824 | &rfkill->poll_work, 0); | ||
826 | 825 | ||
827 | return 0; | 826 | return 0; |
828 | } | 827 | } |
@@ -1164,15 +1163,8 @@ static ssize_t rfkill_fop_write(struct file *file, const char __user *buf, | |||
1164 | 1163 | ||
1165 | mutex_lock(&rfkill_global_mutex); | 1164 | mutex_lock(&rfkill_global_mutex); |
1166 | 1165 | ||
1167 | if (ev.op == RFKILL_OP_CHANGE_ALL) { | 1166 | if (ev.op == RFKILL_OP_CHANGE_ALL) |
1168 | if (ev.type == RFKILL_TYPE_ALL) { | 1167 | rfkill_update_global_state(ev.type, ev.soft); |
1169 | enum rfkill_type i; | ||
1170 | for (i = 0; i < NUM_RFKILL_TYPES; i++) | ||
1171 | rfkill_global_states[i].cur = ev.soft; | ||
1172 | } else { | ||
1173 | rfkill_global_states[ev.type].cur = ev.soft; | ||
1174 | } | ||
1175 | } | ||
1176 | 1168 | ||
1177 | list_for_each_entry(rfkill, &rfkill_list, node) { | 1169 | list_for_each_entry(rfkill, &rfkill_list, node) { |
1178 | if (rfkill->idx != ev.idx && ev.op != RFKILL_OP_CHANGE_ALL) | 1170 | if (rfkill->idx != ev.idx && ev.op != RFKILL_OP_CHANGE_ALL) |
@@ -1261,10 +1253,8 @@ static struct miscdevice rfkill_miscdev = { | |||
1261 | static int __init rfkill_init(void) | 1253 | static int __init rfkill_init(void) |
1262 | { | 1254 | { |
1263 | int error; | 1255 | int error; |
1264 | int i; | ||
1265 | 1256 | ||
1266 | for (i = 0; i < NUM_RFKILL_TYPES; i++) | 1257 | rfkill_update_global_state(RFKILL_TYPE_ALL, !rfkill_default_state); |
1267 | rfkill_global_states[i].cur = !rfkill_default_state; | ||
1268 | 1258 | ||
1269 | error = class_register(&rfkill_class); | 1259 | error = class_register(&rfkill_class); |
1270 | if (error) | 1260 | if (error) |
diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c index 4b1e3f35f06c..76c01cbd56e3 100644 --- a/net/rfkill/rfkill-gpio.c +++ b/net/rfkill/rfkill-gpio.c | |||
@@ -27,8 +27,6 @@ | |||
27 | #include <linux/acpi.h> | 27 | #include <linux/acpi.h> |
28 | #include <linux/gpio/consumer.h> | 28 | #include <linux/gpio/consumer.h> |
29 | 29 | ||
30 | #include <linux/rfkill-gpio.h> | ||
31 | |||
32 | struct rfkill_gpio_data { | 30 | struct rfkill_gpio_data { |
33 | const char *name; | 31 | const char *name; |
34 | enum rfkill_type type; | 32 | enum rfkill_type type; |
@@ -81,7 +79,6 @@ static int rfkill_gpio_acpi_probe(struct device *dev, | |||
81 | if (!id) | 79 | if (!id) |
82 | return -ENODEV; | 80 | return -ENODEV; |
83 | 81 | ||
84 | rfkill->name = dev_name(dev); | ||
85 | rfkill->type = (unsigned)id->driver_data; | 82 | rfkill->type = (unsigned)id->driver_data; |
86 | 83 | ||
87 | return acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), | 84 | return acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), |
@@ -90,24 +87,27 @@ static int rfkill_gpio_acpi_probe(struct device *dev, | |||
90 | 87 | ||
91 | static int rfkill_gpio_probe(struct platform_device *pdev) | 88 | static int rfkill_gpio_probe(struct platform_device *pdev) |
92 | { | 89 | { |
93 | struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data; | ||
94 | struct rfkill_gpio_data *rfkill; | 90 | struct rfkill_gpio_data *rfkill; |
95 | struct gpio_desc *gpio; | 91 | struct gpio_desc *gpio; |
92 | const char *type_name; | ||
96 | int ret; | 93 | int ret; |
97 | 94 | ||
98 | rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL); | 95 | rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL); |
99 | if (!rfkill) | 96 | if (!rfkill) |
100 | return -ENOMEM; | 97 | return -ENOMEM; |
101 | 98 | ||
99 | device_property_read_string(&pdev->dev, "name", &rfkill->name); | ||
100 | device_property_read_string(&pdev->dev, "type", &type_name); | ||
101 | |||
102 | if (!rfkill->name) | ||
103 | rfkill->name = dev_name(&pdev->dev); | ||
104 | |||
105 | rfkill->type = rfkill_find_type(type_name); | ||
106 | |||
102 | if (ACPI_HANDLE(&pdev->dev)) { | 107 | if (ACPI_HANDLE(&pdev->dev)) { |
103 | ret = rfkill_gpio_acpi_probe(&pdev->dev, rfkill); | 108 | ret = rfkill_gpio_acpi_probe(&pdev->dev, rfkill); |
104 | if (ret) | 109 | if (ret) |
105 | return ret; | 110 | return ret; |
106 | } else if (pdata) { | ||
107 | rfkill->name = pdata->name; | ||
108 | rfkill->type = pdata->type; | ||
109 | } else { | ||
110 | return -ENODEV; | ||
111 | } | 111 | } |
112 | 112 | ||
113 | rfkill->clk = devm_clk_get(&pdev->dev, NULL); | 113 | rfkill->clk = devm_clk_get(&pdev->dev, NULL); |
@@ -124,10 +124,8 @@ static int rfkill_gpio_probe(struct platform_device *pdev) | |||
124 | 124 | ||
125 | rfkill->shutdown_gpio = gpio; | 125 | rfkill->shutdown_gpio = gpio; |
126 | 126 | ||
127 | /* Make sure at-least one of the GPIO is defined and that | 127 | /* Make sure at-least one GPIO is defined for this instance */ |
128 | * a name is specified for this instance | 128 | if (!rfkill->reset_gpio && !rfkill->shutdown_gpio) { |
129 | */ | ||
130 | if ((!rfkill->reset_gpio && !rfkill->shutdown_gpio) || !rfkill->name) { | ||
131 | dev_err(&pdev->dev, "invalid platform data\n"); | 129 | dev_err(&pdev->dev, "invalid platform data\n"); |
132 | return -EINVAL; | 130 | return -EINVAL; |
133 | } | 131 | } |
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index da72ed32f143..6c606120abfe 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig | |||
@@ -50,8 +50,8 @@ config CFG80211_DEVELOPER_WARNINGS | |||
50 | default n | 50 | default n |
51 | help | 51 | help |
52 | This option enables some additional warnings that help | 52 | This option enables some additional warnings that help |
53 | cfg80211 developers and driver developers, but that can | 53 | cfg80211 developers and driver developers, but beware that |
54 | trigger due to races with userspace. | 54 | they can also trigger due to races with userspace. |
55 | 55 | ||
56 | For example, when a driver reports that it was disconnected | 56 | For example, when a driver reports that it was disconnected |
57 | from the AP, but the user disconnects manually at the same | 57 | from the AP, but the user disconnects manually at the same |
@@ -61,19 +61,6 @@ config CFG80211_DEVELOPER_WARNINGS | |||
61 | on it (or mac80211). | 61 | on it (or mac80211). |
62 | 62 | ||
63 | 63 | ||
64 | config CFG80211_REG_DEBUG | ||
65 | bool "cfg80211 regulatory debugging" | ||
66 | depends on CFG80211 | ||
67 | default n | ||
68 | ---help--- | ||
69 | You can enable this if you want to debug regulatory changes. | ||
70 | For more information on cfg80211 regulatory refer to the wireless | ||
71 | wiki: | ||
72 | |||
73 | http://wireless.kernel.org/en/developers/Regulatory | ||
74 | |||
75 | If unsure, say N. | ||
76 | |||
77 | config CFG80211_CERTIFICATION_ONUS | 64 | config CFG80211_CERTIFICATION_ONUS |
78 | bool "cfg80211 certification onus" | 65 | bool "cfg80211 certification onus" |
79 | depends on CFG80211 && EXPERT | 66 | depends on CFG80211 && EXPERT |
@@ -123,7 +110,7 @@ config CFG80211_REG_RELAX_NO_IR | |||
123 | interface which associated to an AP which userspace assumes or confirms | 110 | interface which associated to an AP which userspace assumes or confirms |
124 | to be an authorized master, i.e., with radar detection support and DFS | 111 | to be an authorized master, i.e., with radar detection support and DFS |
125 | capabilities. However, note that in order to not create daisy chain | 112 | capabilities. However, note that in order to not create daisy chain |
126 | scenarios, this relaxation is not allowed in cases that the BSS client | 113 | scenarios, this relaxation is not allowed in cases where the BSS client |
127 | is associated to P2P GO and in addition the P2P GO instantiated on | 114 | is associated to P2P GO and in addition the P2P GO instantiated on |
128 | a channel due to this relaxation should not allow connection from | 115 | a channel due to this relaxation should not allow connection from |
129 | non P2P clients. | 116 | non P2P clients. |
@@ -148,7 +135,7 @@ config CFG80211_DEBUGFS | |||
148 | depends on CFG80211 | 135 | depends on CFG80211 |
149 | depends on DEBUG_FS | 136 | depends on DEBUG_FS |
150 | ---help--- | 137 | ---help--- |
151 | You can enable this if you want to debugfs entries for cfg80211. | 138 | You can enable this if you want debugfs entries for cfg80211. |
152 | 139 | ||
153 | If unsure, say N. | 140 | If unsure, say N. |
154 | 141 | ||
@@ -159,7 +146,7 @@ config CFG80211_INTERNAL_REGDB | |||
159 | ---help--- | 146 | ---help--- |
160 | This option generates an internal data structure representing | 147 | This option generates an internal data structure representing |
161 | the wireless regulatory rules described in net/wireless/db.txt | 148 | the wireless regulatory rules described in net/wireless/db.txt |
162 | and includes code to query that database. This is an alternative | 149 | and includes code to query that database. This is an alternative |
163 | to using CRDA for defining regulatory rules for the kernel. | 150 | to using CRDA for defining regulatory rules for the kernel. |
164 | 151 | ||
165 | Using this option requires some parsing of the db.txt at build time, | 152 | Using this option requires some parsing of the db.txt at build time, |
@@ -172,7 +159,7 @@ config CFG80211_INTERNAL_REGDB | |||
172 | 159 | ||
173 | http://wireless.kernel.org/en/developers/Regulatory | 160 | http://wireless.kernel.org/en/developers/Regulatory |
174 | 161 | ||
175 | Most distributions have a CRDA package. So if unsure, say N. | 162 | Most distributions have a CRDA package. So if unsure, say N. |
176 | 163 | ||
177 | config CFG80211_CRDA_SUPPORT | 164 | config CFG80211_CRDA_SUPPORT |
178 | bool "support CRDA" if CFG80211_INTERNAL_REGDB | 165 | bool "support CRDA" if CFG80211_INTERNAL_REGDB |
diff --git a/net/wireless/core.c b/net/wireless/core.c index b0915515640e..3a9c41bc849a 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -352,6 +352,16 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, | |||
352 | WARN_ON(ops->add_station && !ops->del_station); | 352 | WARN_ON(ops->add_station && !ops->del_station); |
353 | WARN_ON(ops->add_mpath && !ops->del_mpath); | 353 | WARN_ON(ops->add_mpath && !ops->del_mpath); |
354 | WARN_ON(ops->join_mesh && !ops->leave_mesh); | 354 | WARN_ON(ops->join_mesh && !ops->leave_mesh); |
355 | WARN_ON(ops->start_p2p_device && !ops->stop_p2p_device); | ||
356 | WARN_ON(ops->start_ap && !ops->stop_ap); | ||
357 | WARN_ON(ops->join_ocb && !ops->leave_ocb); | ||
358 | WARN_ON(ops->suspend && !ops->resume); | ||
359 | WARN_ON(ops->sched_scan_start && !ops->sched_scan_stop); | ||
360 | WARN_ON(ops->remain_on_channel && !ops->cancel_remain_on_channel); | ||
361 | WARN_ON(ops->tdls_channel_switch && !ops->tdls_cancel_channel_switch); | ||
362 | WARN_ON(ops->add_tx_ts && !ops->del_tx_ts); | ||
363 | WARN_ON(ops->set_tx_power && !ops->get_tx_power); | ||
364 | WARN_ON(ops->set_antenna && !ops->get_antenna); | ||
355 | 365 | ||
356 | alloc_size = sizeof(*rdev) + sizeof_priv; | 366 | alloc_size = sizeof(*rdev) + sizeof_priv; |
357 | 367 | ||
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index fb44fa3bf4ef..ff328250bc44 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -711,7 +711,7 @@ EXPORT_SYMBOL(cfg80211_rx_mgmt); | |||
711 | 711 | ||
712 | void cfg80211_dfs_channels_update_work(struct work_struct *work) | 712 | void cfg80211_dfs_channels_update_work(struct work_struct *work) |
713 | { | 713 | { |
714 | struct delayed_work *delayed_work; | 714 | struct delayed_work *delayed_work = to_delayed_work(work); |
715 | struct cfg80211_registered_device *rdev; | 715 | struct cfg80211_registered_device *rdev; |
716 | struct cfg80211_chan_def chandef; | 716 | struct cfg80211_chan_def chandef; |
717 | struct ieee80211_supported_band *sband; | 717 | struct ieee80211_supported_band *sband; |
@@ -721,7 +721,6 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work) | |||
721 | unsigned long timeout, next_time = 0; | 721 | unsigned long timeout, next_time = 0; |
722 | int bandid, i; | 722 | int bandid, i; |
723 | 723 | ||
724 | delayed_work = container_of(work, struct delayed_work, work); | ||
725 | rdev = container_of(delayed_work, struct cfg80211_registered_device, | 724 | rdev = container_of(delayed_work, struct cfg80211_registered_device, |
726 | dfs_update_channels_wk); | 725 | dfs_update_channels_wk); |
727 | wiphy = &rdev->wiphy; | 726 | wiphy = &rdev->wiphy; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d4786f2802aa..90890f183c0e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
5 | * Copyright 2013-2014 Intel Mobile Communications GmbH | 5 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
6 | * Copyright 2015 Intel Deutschland GmbH | 6 | * Copyright 2015-2016 Intel Deutschland GmbH |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/if.h> | 9 | #include <linux/if.h> |
@@ -401,6 +401,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { | |||
401 | [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 }, | 401 | [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 }, |
402 | [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 }, | 402 | [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 }, |
403 | [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG }, | 403 | [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG }, |
404 | [NL80211_ATTR_PBSS] = { .type = NLA_FLAG }, | ||
404 | }; | 405 | }; |
405 | 406 | ||
406 | /* policy for the key attributes */ | 407 | /* policy for the key attributes */ |
@@ -3461,6 +3462,10 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
3461 | return PTR_ERR(params.acl); | 3462 | return PTR_ERR(params.acl); |
3462 | } | 3463 | } |
3463 | 3464 | ||
3465 | params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]); | ||
3466 | if (params.pbss && !rdev->wiphy.bands[IEEE80211_BAND_60GHZ]) | ||
3467 | return -EOPNOTSUPP; | ||
3468 | |||
3464 | wdev_lock(wdev); | 3469 | wdev_lock(wdev); |
3465 | err = rdev_start_ap(rdev, dev, ¶ms); | 3470 | err = rdev_start_ap(rdev, dev, ¶ms); |
3466 | if (!err) { | 3471 | if (!err) { |
@@ -7281,9 +7286,11 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
7281 | } | 7286 | } |
7282 | 7287 | ||
7283 | if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) { | 7288 | if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) { |
7284 | if (!(rdev->wiphy.features & | 7289 | if (!((rdev->wiphy.features & |
7285 | NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) || | 7290 | NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) && |
7286 | !(rdev->wiphy.features & NL80211_FEATURE_QUIET)) | 7291 | (rdev->wiphy.features & NL80211_FEATURE_QUIET)) && |
7292 | !wiphy_ext_feature_isset(&rdev->wiphy, | ||
7293 | NL80211_EXT_FEATURE_RRM)) | ||
7287 | return -EINVAL; | 7294 | return -EINVAL; |
7288 | req.flags |= ASSOC_REQ_USE_RRM; | 7295 | req.flags |= ASSOC_REQ_USE_RRM; |
7289 | } | 7296 | } |
@@ -7971,15 +7978,23 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
7971 | } | 7978 | } |
7972 | 7979 | ||
7973 | if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) { | 7980 | if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) { |
7974 | if (!(rdev->wiphy.features & | 7981 | if (!((rdev->wiphy.features & |
7975 | NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) || | 7982 | NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) && |
7976 | !(rdev->wiphy.features & NL80211_FEATURE_QUIET)) { | 7983 | (rdev->wiphy.features & NL80211_FEATURE_QUIET)) && |
7984 | !wiphy_ext_feature_isset(&rdev->wiphy, | ||
7985 | NL80211_EXT_FEATURE_RRM)) { | ||
7977 | kzfree(connkeys); | 7986 | kzfree(connkeys); |
7978 | return -EINVAL; | 7987 | return -EINVAL; |
7979 | } | 7988 | } |
7980 | connect.flags |= ASSOC_REQ_USE_RRM; | 7989 | connect.flags |= ASSOC_REQ_USE_RRM; |
7981 | } | 7990 | } |
7982 | 7991 | ||
7992 | connect.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]); | ||
7993 | if (connect.pbss && !rdev->wiphy.bands[IEEE80211_BAND_60GHZ]) { | ||
7994 | kzfree(connkeys); | ||
7995 | return -EOPNOTSUPP; | ||
7996 | } | ||
7997 | |||
7983 | wdev_lock(dev->ieee80211_ptr); | 7998 | wdev_lock(dev->ieee80211_ptr); |
7984 | err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL); | 7999 | err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL); |
7985 | wdev_unlock(dev->ieee80211_ptr); | 8000 | wdev_unlock(dev->ieee80211_ptr); |
diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c index 722da616438c..6582d155e2fc 100644 --- a/net/wireless/radiotap.c +++ b/net/wireless/radiotap.c | |||
@@ -43,6 +43,7 @@ static const struct radiotap_align_size rtap_namespace_sizes[] = { | |||
43 | [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, }, | 43 | [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, }, |
44 | [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, }, | 44 | [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, }, |
45 | [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, }, | 45 | [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, }, |
46 | [IEEE80211_RADIOTAP_VHT] = { .align = 2, .size = 12, }, | ||
46 | /* | 47 | /* |
47 | * add more here as they are defined in radiotap.h | 48 | * add more here as they are defined in radiotap.h |
48 | */ | 49 | */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 547ceecc0523..c5fb317eee68 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -60,13 +60,6 @@ | |||
60 | #include "regdb.h" | 60 | #include "regdb.h" |
61 | #include "nl80211.h" | 61 | #include "nl80211.h" |
62 | 62 | ||
63 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
64 | #define REG_DBG_PRINT(format, args...) \ | ||
65 | printk(KERN_DEBUG pr_fmt(format), ##args) | ||
66 | #else | ||
67 | #define REG_DBG_PRINT(args...) | ||
68 | #endif | ||
69 | |||
70 | /* | 63 | /* |
71 | * Grace period we give before making sure all current interfaces reside on | 64 | * Grace period we give before making sure all current interfaces reside on |
72 | * channels allowed by the current regulatory domain. | 65 | * channels allowed by the current regulatory domain. |
@@ -178,12 +171,10 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy) | |||
178 | if (wiphy_regd->dfs_region == regd->dfs_region) | 171 | if (wiphy_regd->dfs_region == regd->dfs_region) |
179 | goto out; | 172 | goto out; |
180 | 173 | ||
181 | REG_DBG_PRINT("%s: device specific dfs_region " | 174 | pr_debug("%s: device specific dfs_region (%s) disagrees with cfg80211's central dfs_region (%s)\n", |
182 | "(%s) disagrees with cfg80211's " | 175 | dev_name(&wiphy->dev), |
183 | "central dfs_region (%s)\n", | 176 | reg_dfs_region_str(wiphy_regd->dfs_region), |
184 | dev_name(&wiphy->dev), | 177 | reg_dfs_region_str(regd->dfs_region)); |
185 | reg_dfs_region_str(wiphy_regd->dfs_region), | ||
186 | reg_dfs_region_str(regd->dfs_region)); | ||
187 | 178 | ||
188 | out: | 179 | out: |
189 | return regd->dfs_region; | 180 | return regd->dfs_region; |
@@ -543,7 +534,7 @@ static DECLARE_DELAYED_WORK(crda_timeout, crda_timeout_work); | |||
543 | 534 | ||
544 | static void crda_timeout_work(struct work_struct *work) | 535 | static void crda_timeout_work(struct work_struct *work) |
545 | { | 536 | { |
546 | REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n"); | 537 | pr_debug("Timeout while waiting for CRDA to reply, restoring regulatory settings\n"); |
547 | rtnl_lock(); | 538 | rtnl_lock(); |
548 | reg_crda_timeouts++; | 539 | reg_crda_timeouts++; |
549 | restore_regulatory_settings(true); | 540 | restore_regulatory_settings(true); |
@@ -585,7 +576,7 @@ static int call_crda(const char *alpha2) | |||
585 | 576 | ||
586 | if (!is_world_regdom((char *) alpha2)) | 577 | if (!is_world_regdom((char *) alpha2)) |
587 | pr_debug("Calling CRDA for country: %c%c\n", | 578 | pr_debug("Calling CRDA for country: %c%c\n", |
588 | alpha2[0], alpha2[1]); | 579 | alpha2[0], alpha2[1]); |
589 | else | 580 | else |
590 | pr_debug("Calling CRDA to update world regulatory domain\n"); | 581 | pr_debug("Calling CRDA to update world regulatory domain\n"); |
591 | 582 | ||
@@ -1132,42 +1123,6 @@ const char *reg_initiator_name(enum nl80211_reg_initiator initiator) | |||
1132 | } | 1123 | } |
1133 | EXPORT_SYMBOL(reg_initiator_name); | 1124 | EXPORT_SYMBOL(reg_initiator_name); |
1134 | 1125 | ||
1135 | static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd, | ||
1136 | struct ieee80211_channel *chan, | ||
1137 | const struct ieee80211_reg_rule *reg_rule) | ||
1138 | { | ||
1139 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
1140 | const struct ieee80211_power_rule *power_rule; | ||
1141 | const struct ieee80211_freq_range *freq_range; | ||
1142 | char max_antenna_gain[32], bw[32]; | ||
1143 | |||
1144 | power_rule = ®_rule->power_rule; | ||
1145 | freq_range = ®_rule->freq_range; | ||
1146 | |||
1147 | if (!power_rule->max_antenna_gain) | ||
1148 | snprintf(max_antenna_gain, sizeof(max_antenna_gain), "N/A"); | ||
1149 | else | ||
1150 | snprintf(max_antenna_gain, sizeof(max_antenna_gain), "%d mBi", | ||
1151 | power_rule->max_antenna_gain); | ||
1152 | |||
1153 | if (reg_rule->flags & NL80211_RRF_AUTO_BW) | ||
1154 | snprintf(bw, sizeof(bw), "%d KHz, %d KHz AUTO", | ||
1155 | freq_range->max_bandwidth_khz, | ||
1156 | reg_get_max_bandwidth(regd, reg_rule)); | ||
1157 | else | ||
1158 | snprintf(bw, sizeof(bw), "%d KHz", | ||
1159 | freq_range->max_bandwidth_khz); | ||
1160 | |||
1161 | REG_DBG_PRINT("Updating information on frequency %d MHz with regulatory rule:\n", | ||
1162 | chan->center_freq); | ||
1163 | |||
1164 | REG_DBG_PRINT("(%d KHz - %d KHz @ %s), (%s, %d mBm)\n", | ||
1165 | freq_range->start_freq_khz, freq_range->end_freq_khz, | ||
1166 | bw, max_antenna_gain, | ||
1167 | power_rule->max_eirp); | ||
1168 | #endif | ||
1169 | } | ||
1170 | |||
1171 | static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd, | 1126 | static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd, |
1172 | const struct ieee80211_reg_rule *reg_rule, | 1127 | const struct ieee80211_reg_rule *reg_rule, |
1173 | const struct ieee80211_channel *chan) | 1128 | const struct ieee80211_channel *chan) |
@@ -1242,20 +1197,19 @@ static void handle_channel(struct wiphy *wiphy, | |||
1242 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && | 1197 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && |
1243 | request_wiphy && request_wiphy == wiphy && | 1198 | request_wiphy && request_wiphy == wiphy && |
1244 | request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) { | 1199 | request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) { |
1245 | REG_DBG_PRINT("Disabling freq %d MHz for good\n", | 1200 | pr_debug("Disabling freq %d MHz for good\n", |
1246 | chan->center_freq); | 1201 | chan->center_freq); |
1247 | chan->orig_flags |= IEEE80211_CHAN_DISABLED; | 1202 | chan->orig_flags |= IEEE80211_CHAN_DISABLED; |
1248 | chan->flags = chan->orig_flags; | 1203 | chan->flags = chan->orig_flags; |
1249 | } else { | 1204 | } else { |
1250 | REG_DBG_PRINT("Disabling freq %d MHz\n", | 1205 | pr_debug("Disabling freq %d MHz\n", |
1251 | chan->center_freq); | 1206 | chan->center_freq); |
1252 | chan->flags |= IEEE80211_CHAN_DISABLED; | 1207 | chan->flags |= IEEE80211_CHAN_DISABLED; |
1253 | } | 1208 | } |
1254 | return; | 1209 | return; |
1255 | } | 1210 | } |
1256 | 1211 | ||
1257 | regd = reg_get_regdomain(wiphy); | 1212 | regd = reg_get_regdomain(wiphy); |
1258 | chan_reg_rule_print_dbg(regd, chan, reg_rule); | ||
1259 | 1213 | ||
1260 | power_rule = ®_rule->power_rule; | 1214 | power_rule = ®_rule->power_rule; |
1261 | bw_flags = reg_rule_to_chan_bw_flags(regd, reg_rule, chan); | 1215 | bw_flags = reg_rule_to_chan_bw_flags(regd, reg_rule, chan); |
@@ -1393,18 +1347,15 @@ static bool ignore_reg_update(struct wiphy *wiphy, | |||
1393 | return true; | 1347 | return true; |
1394 | 1348 | ||
1395 | if (!lr) { | 1349 | if (!lr) { |
1396 | REG_DBG_PRINT("Ignoring regulatory request set by %s " | 1350 | pr_debug("Ignoring regulatory request set by %s since last_request is not set\n", |
1397 | "since last_request is not set\n", | 1351 | reg_initiator_name(initiator)); |
1398 | reg_initiator_name(initiator)); | ||
1399 | return true; | 1352 | return true; |
1400 | } | 1353 | } |
1401 | 1354 | ||
1402 | if (initiator == NL80211_REGDOM_SET_BY_CORE && | 1355 | if (initiator == NL80211_REGDOM_SET_BY_CORE && |
1403 | wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) { | 1356 | wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) { |
1404 | REG_DBG_PRINT("Ignoring regulatory request set by %s " | 1357 | pr_debug("Ignoring regulatory request set by %s since the driver uses its own custom regulatory domain\n", |
1405 | "since the driver uses its own custom " | 1358 | reg_initiator_name(initiator)); |
1406 | "regulatory domain\n", | ||
1407 | reg_initiator_name(initiator)); | ||
1408 | return true; | 1359 | return true; |
1409 | } | 1360 | } |
1410 | 1361 | ||
@@ -1415,10 +1366,8 @@ static bool ignore_reg_update(struct wiphy *wiphy, | |||
1415 | if (wiphy_strict_alpha2_regd(wiphy) && !wiphy->regd && | 1366 | if (wiphy_strict_alpha2_regd(wiphy) && !wiphy->regd && |
1416 | initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && | 1367 | initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && |
1417 | !is_world_regdom(lr->alpha2)) { | 1368 | !is_world_regdom(lr->alpha2)) { |
1418 | REG_DBG_PRINT("Ignoring regulatory request set by %s " | 1369 | pr_debug("Ignoring regulatory request set by %s since the driver requires its own regulatory domain to be set first\n", |
1419 | "since the driver requires its own regulatory " | 1370 | reg_initiator_name(initiator)); |
1420 | "domain to be set first\n", | ||
1421 | reg_initiator_name(initiator)); | ||
1422 | return true; | 1371 | return true; |
1423 | } | 1372 | } |
1424 | 1373 | ||
@@ -1699,7 +1648,7 @@ static void reg_check_chans_work(struct work_struct *work) | |||
1699 | { | 1648 | { |
1700 | struct cfg80211_registered_device *rdev; | 1649 | struct cfg80211_registered_device *rdev; |
1701 | 1650 | ||
1702 | REG_DBG_PRINT("Verifying active interfaces after reg change\n"); | 1651 | pr_debug("Verifying active interfaces after reg change\n"); |
1703 | rtnl_lock(); | 1652 | rtnl_lock(); |
1704 | 1653 | ||
1705 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) | 1654 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) |
@@ -1781,8 +1730,8 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1781 | } | 1730 | } |
1782 | 1731 | ||
1783 | if (IS_ERR(reg_rule)) { | 1732 | if (IS_ERR(reg_rule)) { |
1784 | REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n", | 1733 | pr_debug("Disabling freq %d MHz as custom regd has no rule that fits it\n", |
1785 | chan->center_freq); | 1734 | chan->center_freq); |
1786 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) { | 1735 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) { |
1787 | chan->flags |= IEEE80211_CHAN_DISABLED; | 1736 | chan->flags |= IEEE80211_CHAN_DISABLED; |
1788 | } else { | 1737 | } else { |
@@ -1792,8 +1741,6 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1792 | return; | 1741 | return; |
1793 | } | 1742 | } |
1794 | 1743 | ||
1795 | chan_reg_rule_print_dbg(regd, chan, reg_rule); | ||
1796 | |||
1797 | power_rule = ®_rule->power_rule; | 1744 | power_rule = ®_rule->power_rule; |
1798 | bw_flags = reg_rule_to_chan_bw_flags(regd, reg_rule, chan); | 1745 | bw_flags = reg_rule_to_chan_bw_flags(regd, reg_rule, chan); |
1799 | 1746 | ||
@@ -2524,7 +2471,7 @@ static void restore_alpha2(char *alpha2, bool reset_user) | |||
2524 | if (is_user_regdom_saved()) { | 2471 | if (is_user_regdom_saved()) { |
2525 | /* Unless we're asked to ignore it and reset it */ | 2472 | /* Unless we're asked to ignore it and reset it */ |
2526 | if (reset_user) { | 2473 | if (reset_user) { |
2527 | REG_DBG_PRINT("Restoring regulatory settings including user preference\n"); | 2474 | pr_debug("Restoring regulatory settings including user preference\n"); |
2528 | user_alpha2[0] = '9'; | 2475 | user_alpha2[0] = '9'; |
2529 | user_alpha2[1] = '7'; | 2476 | user_alpha2[1] = '7'; |
2530 | 2477 | ||
@@ -2534,24 +2481,24 @@ static void restore_alpha2(char *alpha2, bool reset_user) | |||
2534 | * back as they were for a full restore. | 2481 | * back as they were for a full restore. |
2535 | */ | 2482 | */ |
2536 | if (!is_world_regdom(ieee80211_regdom)) { | 2483 | if (!is_world_regdom(ieee80211_regdom)) { |
2537 | REG_DBG_PRINT("Keeping preference on module parameter ieee80211_regdom: %c%c\n", | 2484 | pr_debug("Keeping preference on module parameter ieee80211_regdom: %c%c\n", |
2538 | ieee80211_regdom[0], ieee80211_regdom[1]); | 2485 | ieee80211_regdom[0], ieee80211_regdom[1]); |
2539 | alpha2[0] = ieee80211_regdom[0]; | 2486 | alpha2[0] = ieee80211_regdom[0]; |
2540 | alpha2[1] = ieee80211_regdom[1]; | 2487 | alpha2[1] = ieee80211_regdom[1]; |
2541 | } | 2488 | } |
2542 | } else { | 2489 | } else { |
2543 | REG_DBG_PRINT("Restoring regulatory settings while preserving user preference for: %c%c\n", | 2490 | pr_debug("Restoring regulatory settings while preserving user preference for: %c%c\n", |
2544 | user_alpha2[0], user_alpha2[1]); | 2491 | user_alpha2[0], user_alpha2[1]); |
2545 | alpha2[0] = user_alpha2[0]; | 2492 | alpha2[0] = user_alpha2[0]; |
2546 | alpha2[1] = user_alpha2[1]; | 2493 | alpha2[1] = user_alpha2[1]; |
2547 | } | 2494 | } |
2548 | } else if (!is_world_regdom(ieee80211_regdom)) { | 2495 | } else if (!is_world_regdom(ieee80211_regdom)) { |
2549 | REG_DBG_PRINT("Keeping preference on module parameter ieee80211_regdom: %c%c\n", | 2496 | pr_debug("Keeping preference on module parameter ieee80211_regdom: %c%c\n", |
2550 | ieee80211_regdom[0], ieee80211_regdom[1]); | 2497 | ieee80211_regdom[0], ieee80211_regdom[1]); |
2551 | alpha2[0] = ieee80211_regdom[0]; | 2498 | alpha2[0] = ieee80211_regdom[0]; |
2552 | alpha2[1] = ieee80211_regdom[1]; | 2499 | alpha2[1] = ieee80211_regdom[1]; |
2553 | } else | 2500 | } else |
2554 | REG_DBG_PRINT("Restoring regulatory settings\n"); | 2501 | pr_debug("Restoring regulatory settings\n"); |
2555 | } | 2502 | } |
2556 | 2503 | ||
2557 | static void restore_custom_reg_settings(struct wiphy *wiphy) | 2504 | static void restore_custom_reg_settings(struct wiphy *wiphy) |
@@ -2663,14 +2610,14 @@ static void restore_regulatory_settings(bool reset_user) | |||
2663 | list_splice_tail_init(&tmp_reg_req_list, ®_requests_list); | 2610 | list_splice_tail_init(&tmp_reg_req_list, ®_requests_list); |
2664 | spin_unlock(®_requests_lock); | 2611 | spin_unlock(®_requests_lock); |
2665 | 2612 | ||
2666 | REG_DBG_PRINT("Kicking the queue\n"); | 2613 | pr_debug("Kicking the queue\n"); |
2667 | 2614 | ||
2668 | schedule_work(®_work); | 2615 | schedule_work(®_work); |
2669 | } | 2616 | } |
2670 | 2617 | ||
2671 | void regulatory_hint_disconnect(void) | 2618 | void regulatory_hint_disconnect(void) |
2672 | { | 2619 | { |
2673 | REG_DBG_PRINT("All devices are disconnected, going to restore regulatory settings\n"); | 2620 | pr_debug("All devices are disconnected, going to restore regulatory settings\n"); |
2674 | restore_regulatory_settings(false); | 2621 | restore_regulatory_settings(false); |
2675 | } | 2622 | } |
2676 | 2623 | ||
@@ -2718,10 +2665,10 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, | |||
2718 | if (!reg_beacon) | 2665 | if (!reg_beacon) |
2719 | return -ENOMEM; | 2666 | return -ENOMEM; |
2720 | 2667 | ||
2721 | REG_DBG_PRINT("Found new beacon on frequency: %d MHz (Ch %d) on %s\n", | 2668 | pr_debug("Found new beacon on frequency: %d MHz (Ch %d) on %s\n", |
2722 | beacon_chan->center_freq, | 2669 | beacon_chan->center_freq, |
2723 | ieee80211_frequency_to_channel(beacon_chan->center_freq), | 2670 | ieee80211_frequency_to_channel(beacon_chan->center_freq), |
2724 | wiphy_name(wiphy)); | 2671 | wiphy_name(wiphy)); |
2725 | 2672 | ||
2726 | memcpy(®_beacon->chan, beacon_chan, | 2673 | memcpy(®_beacon->chan, beacon_chan, |
2727 | sizeof(struct ieee80211_channel)); | 2674 | sizeof(struct ieee80211_channel)); |
@@ -2800,8 +2747,7 @@ bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region) | |||
2800 | case NL80211_DFS_JP: | 2747 | case NL80211_DFS_JP: |
2801 | return true; | 2748 | return true; |
2802 | default: | 2749 | default: |
2803 | REG_DBG_PRINT("Ignoring uknown DFS master region: %d\n", | 2750 | pr_debug("Ignoring uknown DFS master region: %d\n", dfs_region); |
2804 | dfs_region); | ||
2805 | return false; | 2751 | return false; |
2806 | } | 2752 | } |
2807 | } | 2753 | } |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 8020b5b094d4..79bd3a171caa 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -264,7 +264,7 @@ static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev) | |||
264 | wdev->conn->params.bssid, | 264 | wdev->conn->params.bssid, |
265 | wdev->conn->params.ssid, | 265 | wdev->conn->params.ssid, |
266 | wdev->conn->params.ssid_len, | 266 | wdev->conn->params.ssid_len, |
267 | IEEE80211_BSS_TYPE_ESS, | 267 | wdev->conn_bss_type, |
268 | IEEE80211_PRIVACY(wdev->conn->params.privacy)); | 268 | IEEE80211_PRIVACY(wdev->conn->params.privacy)); |
269 | if (!bss) | 269 | if (!bss) |
270 | return NULL; | 270 | return NULL; |
@@ -687,7 +687,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
687 | WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect); | 687 | WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect); |
688 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | 688 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, |
689 | wdev->ssid, wdev->ssid_len, | 689 | wdev->ssid, wdev->ssid_len, |
690 | IEEE80211_BSS_TYPE_ESS, | 690 | wdev->conn_bss_type, |
691 | IEEE80211_PRIVACY_ANY); | 691 | IEEE80211_PRIVACY_ANY); |
692 | if (bss) | 692 | if (bss) |
693 | cfg80211_hold_bss(bss_from_pub(bss)); | 693 | cfg80211_hold_bss(bss_from_pub(bss)); |
@@ -846,7 +846,7 @@ void cfg80211_roamed(struct net_device *dev, | |||
846 | 846 | ||
847 | bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid, | 847 | bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid, |
848 | wdev->ssid_len, | 848 | wdev->ssid_len, |
849 | IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY); | 849 | wdev->conn_bss_type, IEEE80211_PRIVACY_ANY); |
850 | if (WARN_ON(!bss)) | 850 | if (WARN_ON(!bss)) |
851 | return; | 851 | return; |
852 | 852 | ||
@@ -1017,6 +1017,9 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
1017 | memcpy(wdev->ssid, connect->ssid, connect->ssid_len); | 1017 | memcpy(wdev->ssid, connect->ssid, connect->ssid_len); |
1018 | wdev->ssid_len = connect->ssid_len; | 1018 | wdev->ssid_len = connect->ssid_len; |
1019 | 1019 | ||
1020 | wdev->conn_bss_type = connect->pbss ? IEEE80211_BSS_TYPE_PBSS : | ||
1021 | IEEE80211_BSS_TYPE_ESS; | ||
1022 | |||
1020 | if (!rdev->ops->connect) | 1023 | if (!rdev->ops->connect) |
1021 | err = cfg80211_sme_connect(wdev, connect, prev_bssid); | 1024 | err = cfg80211_sme_connect(wdev, connect, prev_bssid); |
1022 | else | 1025 | else |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 92770427b211..c7f6820bb258 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -393,9 +393,9 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) | |||
393 | } | 393 | } |
394 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); | 394 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); |
395 | 395 | ||
396 | unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | 396 | static unsigned int __ieee80211_get_mesh_hdrlen(u8 flags) |
397 | { | 397 | { |
398 | int ae = meshhdr->flags & MESH_FLAGS_AE; | 398 | int ae = flags & MESH_FLAGS_AE; |
399 | /* 802.11-2012, 8.2.4.7.3 */ | 399 | /* 802.11-2012, 8.2.4.7.3 */ |
400 | switch (ae) { | 400 | switch (ae) { |
401 | default: | 401 | default: |
@@ -407,21 +407,31 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | |||
407 | return 18; | 407 | return 18; |
408 | } | 408 | } |
409 | } | 409 | } |
410 | |||
411 | unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | ||
412 | { | ||
413 | return __ieee80211_get_mesh_hdrlen(meshhdr->flags); | ||
414 | } | ||
410 | EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen); | 415 | EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen); |
411 | 416 | ||
412 | int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | 417 | static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr, |
413 | enum nl80211_iftype iftype) | 418 | const u8 *addr, enum nl80211_iftype iftype) |
414 | { | 419 | { |
415 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 420 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
416 | u16 hdrlen, ethertype; | 421 | struct { |
417 | u8 *payload; | 422 | u8 hdr[ETH_ALEN] __aligned(2); |
418 | u8 dst[ETH_ALEN]; | 423 | __be16 proto; |
419 | u8 src[ETH_ALEN] __aligned(2); | 424 | } payload; |
425 | struct ethhdr tmp; | ||
426 | u16 hdrlen; | ||
427 | u8 mesh_flags = 0; | ||
420 | 428 | ||
421 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) | 429 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) |
422 | return -1; | 430 | return -1; |
423 | 431 | ||
424 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 432 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
433 | if (skb->len < hdrlen + 8) | ||
434 | return -1; | ||
425 | 435 | ||
426 | /* convert IEEE 802.11 header + possible LLC headers into Ethernet | 436 | /* convert IEEE 802.11 header + possible LLC headers into Ethernet |
427 | * header | 437 | * header |
@@ -432,8 +442,11 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | |||
432 | * 1 0 BSSID SA DA n/a | 442 | * 1 0 BSSID SA DA n/a |
433 | * 1 1 RA TA DA SA | 443 | * 1 1 RA TA DA SA |
434 | */ | 444 | */ |
435 | memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); | 445 | memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN); |
436 | memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); | 446 | memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN); |
447 | |||
448 | if (iftype == NL80211_IFTYPE_MESH_POINT) | ||
449 | skb_copy_bits(skb, hdrlen, &mesh_flags, 1); | ||
437 | 450 | ||
438 | switch (hdr->frame_control & | 451 | switch (hdr->frame_control & |
439 | cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { | 452 | cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { |
@@ -450,44 +463,31 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | |||
450 | iftype != NL80211_IFTYPE_STATION)) | 463 | iftype != NL80211_IFTYPE_STATION)) |
451 | return -1; | 464 | return -1; |
452 | if (iftype == NL80211_IFTYPE_MESH_POINT) { | 465 | if (iftype == NL80211_IFTYPE_MESH_POINT) { |
453 | struct ieee80211s_hdr *meshdr = | 466 | if (mesh_flags & MESH_FLAGS_AE_A4) |
454 | (struct ieee80211s_hdr *) (skb->data + hdrlen); | ||
455 | /* make sure meshdr->flags is on the linear part */ | ||
456 | if (!pskb_may_pull(skb, hdrlen + 1)) | ||
457 | return -1; | ||
458 | if (meshdr->flags & MESH_FLAGS_AE_A4) | ||
459 | return -1; | 467 | return -1; |
460 | if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { | 468 | if (mesh_flags & MESH_FLAGS_AE_A5_A6) { |
461 | skb_copy_bits(skb, hdrlen + | 469 | skb_copy_bits(skb, hdrlen + |
462 | offsetof(struct ieee80211s_hdr, eaddr1), | 470 | offsetof(struct ieee80211s_hdr, eaddr1), |
463 | dst, ETH_ALEN); | 471 | tmp.h_dest, 2 * ETH_ALEN); |
464 | skb_copy_bits(skb, hdrlen + | ||
465 | offsetof(struct ieee80211s_hdr, eaddr2), | ||
466 | src, ETH_ALEN); | ||
467 | } | 472 | } |
468 | hdrlen += ieee80211_get_mesh_hdrlen(meshdr); | 473 | hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags); |
469 | } | 474 | } |
470 | break; | 475 | break; |
471 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): | 476 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): |
472 | if ((iftype != NL80211_IFTYPE_STATION && | 477 | if ((iftype != NL80211_IFTYPE_STATION && |
473 | iftype != NL80211_IFTYPE_P2P_CLIENT && | 478 | iftype != NL80211_IFTYPE_P2P_CLIENT && |
474 | iftype != NL80211_IFTYPE_MESH_POINT) || | 479 | iftype != NL80211_IFTYPE_MESH_POINT) || |
475 | (is_multicast_ether_addr(dst) && | 480 | (is_multicast_ether_addr(tmp.h_dest) && |
476 | ether_addr_equal(src, addr))) | 481 | ether_addr_equal(tmp.h_source, addr))) |
477 | return -1; | 482 | return -1; |
478 | if (iftype == NL80211_IFTYPE_MESH_POINT) { | 483 | if (iftype == NL80211_IFTYPE_MESH_POINT) { |
479 | struct ieee80211s_hdr *meshdr = | 484 | if (mesh_flags & MESH_FLAGS_AE_A5_A6) |
480 | (struct ieee80211s_hdr *) (skb->data + hdrlen); | ||
481 | /* make sure meshdr->flags is on the linear part */ | ||
482 | if (!pskb_may_pull(skb, hdrlen + 1)) | ||
483 | return -1; | ||
484 | if (meshdr->flags & MESH_FLAGS_AE_A5_A6) | ||
485 | return -1; | 485 | return -1; |
486 | if (meshdr->flags & MESH_FLAGS_AE_A4) | 486 | if (mesh_flags & MESH_FLAGS_AE_A4) |
487 | skb_copy_bits(skb, hdrlen + | 487 | skb_copy_bits(skb, hdrlen + |
488 | offsetof(struct ieee80211s_hdr, eaddr1), | 488 | offsetof(struct ieee80211s_hdr, eaddr1), |
489 | src, ETH_ALEN); | 489 | tmp.h_source, ETH_ALEN); |
490 | hdrlen += ieee80211_get_mesh_hdrlen(meshdr); | 490 | hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags); |
491 | } | 491 | } |
492 | break; | 492 | break; |
493 | case cpu_to_le16(0): | 493 | case cpu_to_le16(0): |
@@ -498,33 +498,33 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | |||
498 | break; | 498 | break; |
499 | } | 499 | } |
500 | 500 | ||
501 | if (!pskb_may_pull(skb, hdrlen + 8)) | 501 | skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)); |
502 | return -1; | 502 | tmp.h_proto = payload.proto; |
503 | |||
504 | payload = skb->data + hdrlen; | ||
505 | ethertype = (payload[6] << 8) | payload[7]; | ||
506 | 503 | ||
507 | if (likely((ether_addr_equal(payload, rfc1042_header) && | 504 | if (likely((ether_addr_equal(payload.hdr, rfc1042_header) && |
508 | ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || | 505 | tmp.h_proto != htons(ETH_P_AARP) && |
509 | ether_addr_equal(payload, bridge_tunnel_header))) { | 506 | tmp.h_proto != htons(ETH_P_IPX)) || |
507 | ether_addr_equal(payload.hdr, bridge_tunnel_header))) | ||
510 | /* remove RFC1042 or Bridge-Tunnel encapsulation and | 508 | /* remove RFC1042 or Bridge-Tunnel encapsulation and |
511 | * replace EtherType */ | 509 | * replace EtherType */ |
512 | skb_pull(skb, hdrlen + 6); | 510 | hdrlen += ETH_ALEN + 2; |
513 | memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); | 511 | else |
514 | memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); | 512 | tmp.h_proto = htons(skb->len); |
515 | } else { | ||
516 | struct ethhdr *ehdr; | ||
517 | __be16 len; | ||
518 | 513 | ||
519 | skb_pull(skb, hdrlen); | 514 | pskb_pull(skb, hdrlen); |
520 | len = htons(skb->len); | 515 | |
516 | if (!ehdr) | ||
521 | ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); | 517 | ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); |
522 | memcpy(ehdr->h_dest, dst, ETH_ALEN); | 518 | memcpy(ehdr, &tmp, sizeof(tmp)); |
523 | memcpy(ehdr->h_source, src, ETH_ALEN); | 519 | |
524 | ehdr->h_proto = len; | ||
525 | } | ||
526 | return 0; | 520 | return 0; |
527 | } | 521 | } |
522 | |||
523 | int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | ||
524 | enum nl80211_iftype iftype) | ||
525 | { | ||
526 | return __ieee80211_data_to_8023(skb, NULL, addr, iftype); | ||
527 | } | ||
528 | EXPORT_SYMBOL(ieee80211_data_to_8023); | 528 | EXPORT_SYMBOL(ieee80211_data_to_8023); |
529 | 529 | ||
530 | int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, | 530 | int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, |
@@ -644,70 +644,147 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, | |||
644 | } | 644 | } |
645 | EXPORT_SYMBOL(ieee80211_data_from_8023); | 645 | EXPORT_SYMBOL(ieee80211_data_from_8023); |
646 | 646 | ||
647 | static void | ||
648 | __frame_add_frag(struct sk_buff *skb, struct page *page, | ||
649 | void *ptr, int len, int size) | ||
650 | { | ||
651 | struct skb_shared_info *sh = skb_shinfo(skb); | ||
652 | int page_offset; | ||
653 | |||
654 | atomic_inc(&page->_count); | ||
655 | page_offset = ptr - page_address(page); | ||
656 | skb_add_rx_frag(skb, sh->nr_frags, page, page_offset, len, size); | ||
657 | } | ||
658 | |||
659 | static void | ||
660 | __ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame, | ||
661 | int offset, int len) | ||
662 | { | ||
663 | struct skb_shared_info *sh = skb_shinfo(skb); | ||
664 | const skb_frag_t *frag = &sh->frags[-1]; | ||
665 | struct page *frag_page; | ||
666 | void *frag_ptr; | ||
667 | int frag_len, frag_size; | ||
668 | int head_size = skb->len - skb->data_len; | ||
669 | int cur_len; | ||
670 | |||
671 | frag_page = virt_to_head_page(skb->head); | ||
672 | frag_ptr = skb->data; | ||
673 | frag_size = head_size; | ||
674 | |||
675 | while (offset >= frag_size) { | ||
676 | offset -= frag_size; | ||
677 | frag++; | ||
678 | frag_page = skb_frag_page(frag); | ||
679 | frag_ptr = skb_frag_address(frag); | ||
680 | frag_size = skb_frag_size(frag); | ||
681 | } | ||
682 | |||
683 | frag_ptr += offset; | ||
684 | frag_len = frag_size - offset; | ||
685 | |||
686 | cur_len = min(len, frag_len); | ||
687 | |||
688 | __frame_add_frag(frame, frag_page, frag_ptr, cur_len, frag_size); | ||
689 | len -= cur_len; | ||
690 | |||
691 | while (len > 0) { | ||
692 | frag++; | ||
693 | frag_len = skb_frag_size(frag); | ||
694 | cur_len = min(len, frag_len); | ||
695 | __frame_add_frag(frame, skb_frag_page(frag), | ||
696 | skb_frag_address(frag), cur_len, frag_len); | ||
697 | len -= cur_len; | ||
698 | } | ||
699 | } | ||
700 | |||
701 | static struct sk_buff * | ||
702 | __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen, | ||
703 | int offset, int len, bool reuse_frag) | ||
704 | { | ||
705 | struct sk_buff *frame; | ||
706 | int cur_len = len; | ||
707 | |||
708 | if (skb->len - offset < len) | ||
709 | return NULL; | ||
710 | |||
711 | /* | ||
712 | * When reusing framents, copy some data to the head to simplify | ||
713 | * ethernet header handling and speed up protocol header processing | ||
714 | * in the stack later. | ||
715 | */ | ||
716 | if (reuse_frag) | ||
717 | cur_len = min_t(int, len, 32); | ||
718 | |||
719 | /* | ||
720 | * Allocate and reserve two bytes more for payload | ||
721 | * alignment since sizeof(struct ethhdr) is 14. | ||
722 | */ | ||
723 | frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len); | ||
724 | |||
725 | skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); | ||
726 | skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len); | ||
727 | |||
728 | len -= cur_len; | ||
729 | if (!len) | ||
730 | return frame; | ||
731 | |||
732 | offset += cur_len; | ||
733 | __ieee80211_amsdu_copy_frag(skb, frame, offset, len); | ||
734 | |||
735 | return frame; | ||
736 | } | ||
647 | 737 | ||
648 | void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, | 738 | void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, |
649 | const u8 *addr, enum nl80211_iftype iftype, | 739 | const u8 *addr, enum nl80211_iftype iftype, |
650 | const unsigned int extra_headroom, | 740 | const unsigned int extra_headroom, |
651 | bool has_80211_header) | 741 | bool has_80211_header) |
652 | { | 742 | { |
743 | unsigned int hlen = ALIGN(extra_headroom, 4); | ||
653 | struct sk_buff *frame = NULL; | 744 | struct sk_buff *frame = NULL; |
654 | u16 ethertype; | 745 | u16 ethertype; |
655 | u8 *payload; | 746 | u8 *payload; |
656 | const struct ethhdr *eth; | 747 | int offset = 0, remaining, err; |
657 | int remaining, err; | 748 | struct ethhdr eth; |
658 | u8 dst[ETH_ALEN], src[ETH_ALEN]; | 749 | bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb); |
750 | bool reuse_skb = false; | ||
751 | bool last = false; | ||
659 | 752 | ||
660 | if (has_80211_header) { | 753 | if (has_80211_header) { |
661 | err = ieee80211_data_to_8023(skb, addr, iftype); | 754 | err = __ieee80211_data_to_8023(skb, ð, addr, iftype); |
662 | if (err) | 755 | if (err) |
663 | goto out; | 756 | goto out; |
664 | |||
665 | /* skip the wrapping header */ | ||
666 | eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); | ||
667 | if (!eth) | ||
668 | goto out; | ||
669 | } else { | ||
670 | eth = (struct ethhdr *) skb->data; | ||
671 | } | 757 | } |
672 | 758 | ||
673 | while (skb != frame) { | 759 | while (!last) { |
760 | unsigned int subframe_len; | ||
761 | int len; | ||
674 | u8 padding; | 762 | u8 padding; |
675 | __be16 len = eth->h_proto; | ||
676 | unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len); | ||
677 | |||
678 | remaining = skb->len; | ||
679 | memcpy(dst, eth->h_dest, ETH_ALEN); | ||
680 | memcpy(src, eth->h_source, ETH_ALEN); | ||
681 | 763 | ||
764 | skb_copy_bits(skb, offset, ð, sizeof(eth)); | ||
765 | len = ntohs(eth.h_proto); | ||
766 | subframe_len = sizeof(struct ethhdr) + len; | ||
682 | padding = (4 - subframe_len) & 0x3; | 767 | padding = (4 - subframe_len) & 0x3; |
768 | |||
683 | /* the last MSDU has no padding */ | 769 | /* the last MSDU has no padding */ |
770 | remaining = skb->len - offset; | ||
684 | if (subframe_len > remaining) | 771 | if (subframe_len > remaining) |
685 | goto purge; | 772 | goto purge; |
686 | 773 | ||
687 | skb_pull(skb, sizeof(struct ethhdr)); | 774 | offset += sizeof(struct ethhdr); |
688 | /* reuse skb for the last subframe */ | 775 | /* reuse skb for the last subframe */ |
689 | if (remaining <= subframe_len + padding) | 776 | last = remaining <= subframe_len + padding; |
777 | if (!skb_is_nonlinear(skb) && !reuse_frag && last) { | ||
778 | skb_pull(skb, offset); | ||
690 | frame = skb; | 779 | frame = skb; |
691 | else { | 780 | reuse_skb = true; |
692 | unsigned int hlen = ALIGN(extra_headroom, 4); | 781 | } else { |
693 | /* | 782 | frame = __ieee80211_amsdu_copy(skb, hlen, offset, len, |
694 | * Allocate and reserve two bytes more for payload | 783 | reuse_frag); |
695 | * alignment since sizeof(struct ethhdr) is 14. | ||
696 | */ | ||
697 | frame = dev_alloc_skb(hlen + subframe_len + 2); | ||
698 | if (!frame) | 784 | if (!frame) |
699 | goto purge; | 785 | goto purge; |
700 | 786 | ||
701 | skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); | 787 | offset += len + padding; |
702 | memcpy(skb_put(frame, ntohs(len)), skb->data, | ||
703 | ntohs(len)); | ||
704 | |||
705 | eth = (struct ethhdr *)skb_pull(skb, ntohs(len) + | ||
706 | padding); | ||
707 | if (!eth) { | ||
708 | dev_kfree_skb(frame); | ||
709 | goto purge; | ||
710 | } | ||
711 | } | 788 | } |
712 | 789 | ||
713 | skb_reset_network_header(frame); | 790 | skb_reset_network_header(frame); |
@@ -716,24 +793,20 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, | |||
716 | 793 | ||
717 | payload = frame->data; | 794 | payload = frame->data; |
718 | ethertype = (payload[6] << 8) | payload[7]; | 795 | ethertype = (payload[6] << 8) | payload[7]; |
719 | |||
720 | if (likely((ether_addr_equal(payload, rfc1042_header) && | 796 | if (likely((ether_addr_equal(payload, rfc1042_header) && |
721 | ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || | 797 | ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || |
722 | ether_addr_equal(payload, bridge_tunnel_header))) { | 798 | ether_addr_equal(payload, bridge_tunnel_header))) { |
723 | /* remove RFC1042 or Bridge-Tunnel | 799 | eth.h_proto = htons(ethertype); |
724 | * encapsulation and replace EtherType */ | 800 | skb_pull(frame, ETH_ALEN + 2); |
725 | skb_pull(frame, 6); | ||
726 | memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); | ||
727 | memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); | ||
728 | } else { | ||
729 | memcpy(skb_push(frame, sizeof(__be16)), &len, | ||
730 | sizeof(__be16)); | ||
731 | memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); | ||
732 | memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); | ||
733 | } | 801 | } |
802 | |||
803 | memcpy(skb_push(frame, sizeof(eth)), ð, sizeof(eth)); | ||
734 | __skb_queue_tail(list, frame); | 804 | __skb_queue_tail(list, frame); |
735 | } | 805 | } |
736 | 806 | ||
807 | if (!reuse_skb) | ||
808 | dev_kfree_skb(skb); | ||
809 | |||
737 | return; | 810 | return; |
738 | 811 | ||
739 | purge: | 812 | purge: |