diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-20 16:43:21 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-20 16:43:21 -0400 |
commit | 06f4e926d256d902dd9a53dcb400fd74974ce087 (patch) | |
tree | 0b438b67f5f0eff6fd617bc497a9dace6164a488 /net/mac80211 | |
parent | 8e7bfcbab3825d1b404d615cb1b54f44ff81f981 (diff) | |
parent | d93515611bbc70c2fe4db232e5feb448ed8e4cc9 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1446 commits)
macvlan: fix panic if lowerdev in a bond
tg3: Add braces around 5906 workaround.
tg3: Fix NETIF_F_LOOPBACK error
macvlan: remove one synchronize_rcu() call
networking: NET_CLS_ROUTE4 depends on INET
irda: Fix error propagation in ircomm_lmp_connect_response()
irda: Kill set but unused variable 'bytes' in irlan_check_command_param()
irda: Kill set but unused variable 'clen' in ircomm_connect_indication()
rxrpc: Fix set but unused variable 'usage' in rxrpc_get_transport()
be2net: Kill set but unused variable 'req' in lancer_fw_download()
irda: Kill set but unused vars 'saddr' and 'daddr' in irlan_provider_connect_indication()
atl1c: atl1c_resume() is only used when CONFIG_PM_SLEEP is defined.
rxrpc: Fix set but unused variable 'usage' in rxrpc_get_peer().
rxrpc: Kill set but unused variable 'local' in rxrpc_UDP_error_handler()
rxrpc: Kill set but unused variable 'sp' in rxrpc_process_connection()
rxrpc: Kill set but unused variable 'sp' in rxrpc_rotate_tx_window()
pkt_sched: Kill set but unused variable 'protocol' in tc_classify()
isdn: capi: Use pr_debug() instead of ifdefs.
tg3: Update version to 3.119
tg3: Apply rx_discards fix to 5719/5720
...
Fix up trivial conflicts in arch/x86/Kconfig and net/mac80211/agg-tx.c
as per Davem.
Diffstat (limited to 'net/mac80211')
39 files changed, 1301 insertions, 690 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 513f85cc2ae1..f5fdfcbf552a 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -2,7 +2,6 @@ config MAC80211 | |||
2 | tristate "Generic IEEE 802.11 Networking Stack (mac80211)" | 2 | tristate "Generic IEEE 802.11 Networking Stack (mac80211)" |
3 | depends on CFG80211 | 3 | depends on CFG80211 |
4 | select CRYPTO | 4 | select CRYPTO |
5 | select CRYPTO_ECB | ||
6 | select CRYPTO_ARC4 | 5 | select CRYPTO_ARC4 |
7 | select CRYPTO_AES | 6 | select CRYPTO_AES |
8 | select CRC32 | 7 | select CRC32 |
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index 4bd6ef0be380..b9b595c08112 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c | |||
@@ -54,13 +54,12 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, | |||
54 | u8 *cdata, u8 *mic) | 54 | u8 *cdata, u8 *mic) |
55 | { | 55 | { |
56 | int i, j, last_len, num_blocks; | 56 | int i, j, last_len, num_blocks; |
57 | u8 *pos, *cpos, *b, *s_0, *e, *b_0, *aad; | 57 | u8 *pos, *cpos, *b, *s_0, *e, *b_0; |
58 | 58 | ||
59 | b = scratch; | 59 | b = scratch; |
60 | s_0 = scratch + AES_BLOCK_LEN; | 60 | s_0 = scratch + AES_BLOCK_LEN; |
61 | e = scratch + 2 * AES_BLOCK_LEN; | 61 | e = scratch + 2 * AES_BLOCK_LEN; |
62 | b_0 = scratch + 3 * AES_BLOCK_LEN; | 62 | b_0 = scratch + 3 * AES_BLOCK_LEN; |
63 | aad = scratch + 4 * AES_BLOCK_LEN; | ||
64 | 63 | ||
65 | num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); | 64 | num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); |
66 | last_len = data_len % AES_BLOCK_LEN; | 65 | last_len = data_len % AES_BLOCK_LEN; |
@@ -94,13 +93,12 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, | |||
94 | u8 *cdata, size_t data_len, u8 *mic, u8 *data) | 93 | u8 *cdata, size_t data_len, u8 *mic, u8 *data) |
95 | { | 94 | { |
96 | int i, j, last_len, num_blocks; | 95 | int i, j, last_len, num_blocks; |
97 | u8 *pos, *cpos, *b, *s_0, *a, *b_0, *aad; | 96 | u8 *pos, *cpos, *b, *s_0, *a, *b_0; |
98 | 97 | ||
99 | b = scratch; | 98 | b = scratch; |
100 | s_0 = scratch + AES_BLOCK_LEN; | 99 | s_0 = scratch + AES_BLOCK_LEN; |
101 | a = scratch + 2 * AES_BLOCK_LEN; | 100 | a = scratch + 2 * AES_BLOCK_LEN; |
102 | b_0 = scratch + 3 * AES_BLOCK_LEN; | 101 | b_0 = scratch + 3 * AES_BLOCK_LEN; |
103 | aad = scratch + 4 * AES_BLOCK_LEN; | ||
104 | 102 | ||
105 | num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); | 103 | num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); |
106 | last_len = data_len % AES_BLOCK_LEN; | 104 | last_len = data_len % AES_BLOCK_LEN; |
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 0c9d0c07eae6..9c0d76cdca92 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -63,7 +63,8 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
63 | 63 | ||
64 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 64 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
65 | 65 | ||
66 | tid_rx = sta->ampdu_mlme.tid_rx[tid]; | 66 | tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid], |
67 | lockdep_is_held(&sta->ampdu_mlme.mtx)); | ||
67 | 68 | ||
68 | if (!tid_rx) | 69 | if (!tid_rx) |
69 | return; | 70 | return; |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 53defafb9aae..c8be8eff70da 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -136,24 +136,35 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 | |||
136 | ieee80211_tx_skb(sdata, skb); | 136 | ieee80211_tx_skb(sdata, skb); |
137 | } | 137 | } |
138 | 138 | ||
139 | void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, | ||
140 | struct tid_ampdu_tx *tid_tx) | ||
141 | { | ||
142 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | ||
143 | lockdep_assert_held(&sta->lock); | ||
144 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); | ||
145 | } | ||
146 | |||
139 | int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | 147 | int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, |
140 | enum ieee80211_back_parties initiator, | 148 | enum ieee80211_back_parties initiator, |
141 | bool tx) | 149 | bool tx) |
142 | { | 150 | { |
143 | struct ieee80211_local *local = sta->local; | 151 | struct ieee80211_local *local = sta->local; |
144 | struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 152 | struct tid_ampdu_tx *tid_tx; |
145 | int ret; | 153 | int ret; |
146 | 154 | ||
147 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 155 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
148 | 156 | ||
149 | if (!tid_tx) | ||
150 | return -ENOENT; | ||
151 | |||
152 | spin_lock_bh(&sta->lock); | 157 | spin_lock_bh(&sta->lock); |
153 | 158 | ||
159 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | ||
160 | if (!tid_tx) { | ||
161 | spin_unlock_bh(&sta->lock); | ||
162 | return -ENOENT; | ||
163 | } | ||
164 | |||
154 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { | 165 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { |
155 | /* not even started yet! */ | 166 | /* not even started yet! */ |
156 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | 167 | ieee80211_assign_tid_tx(sta, tid, NULL); |
157 | spin_unlock_bh(&sta->lock); | 168 | spin_unlock_bh(&sta->lock); |
158 | kfree_rcu(tid_tx, rcu_head); | 169 | kfree_rcu(tid_tx, rcu_head); |
159 | return 0; | 170 | return 0; |
@@ -275,13 +286,13 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid) | |||
275 | 286 | ||
276 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | 287 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) |
277 | { | 288 | { |
278 | struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 289 | struct tid_ampdu_tx *tid_tx; |
279 | struct ieee80211_local *local = sta->local; | 290 | struct ieee80211_local *local = sta->local; |
280 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 291 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
281 | u16 start_seq_num; | 292 | u16 start_seq_num; |
282 | int ret; | 293 | int ret; |
283 | 294 | ||
284 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 295 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
285 | 296 | ||
286 | /* | 297 | /* |
287 | * While we're asking the driver about the aggregation, | 298 | * While we're asking the driver about the aggregation, |
@@ -310,7 +321,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
310 | " tid %d\n", tid); | 321 | " tid %d\n", tid); |
311 | #endif | 322 | #endif |
312 | spin_lock_bh(&sta->lock); | 323 | spin_lock_bh(&sta->lock); |
313 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | 324 | ieee80211_assign_tid_tx(sta, tid, NULL); |
314 | spin_unlock_bh(&sta->lock); | 325 | spin_unlock_bh(&sta->lock); |
315 | 326 | ||
316 | ieee80211_wake_queue_agg(local, tid); | 327 | ieee80211_wake_queue_agg(local, tid); |
@@ -388,9 +399,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
388 | goto err_unlock_sta; | 399 | goto err_unlock_sta; |
389 | } | 400 | } |
390 | 401 | ||
391 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 402 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
392 | /* check if the TID is not in aggregation flow already */ | 403 | /* check if the TID is not in aggregation flow already */ |
393 | if (tid_tx) { | 404 | if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { |
394 | #ifdef CONFIG_MAC80211_HT_DEBUG | 405 | #ifdef CONFIG_MAC80211_HT_DEBUG |
395 | printk(KERN_DEBUG "BA request denied - session is not " | 406 | printk(KERN_DEBUG "BA request denied - session is not " |
396 | "idle on tid %u\n", tid); | 407 | "idle on tid %u\n", tid); |
@@ -425,8 +436,11 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
425 | sta->ampdu_mlme.dialog_token_allocator++; | 436 | sta->ampdu_mlme.dialog_token_allocator++; |
426 | tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator; | 437 | tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator; |
427 | 438 | ||
428 | /* finally, assign it to the array */ | 439 | /* |
429 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); | 440 | * Finally, assign it to the start array; the work item will |
441 | * collect it and move it to the normal array. | ||
442 | */ | ||
443 | sta->ampdu_mlme.tid_start_tx[tid] = tid_tx; | ||
430 | 444 | ||
431 | ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work); | 445 | ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work); |
432 | 446 | ||
@@ -472,16 +486,19 @@ ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid) | |||
472 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | 486 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, |
473 | struct sta_info *sta, u16 tid) | 487 | struct sta_info *sta, u16 tid) |
474 | { | 488 | { |
489 | struct tid_ampdu_tx *tid_tx; | ||
490 | |||
475 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 491 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
476 | 492 | ||
493 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | ||
494 | |||
477 | #ifdef CONFIG_MAC80211_HT_DEBUG | 495 | #ifdef CONFIG_MAC80211_HT_DEBUG |
478 | printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); | 496 | printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); |
479 | #endif | 497 | #endif |
480 | 498 | ||
481 | drv_ampdu_action(local, sta->sdata, | 499 | drv_ampdu_action(local, sta->sdata, |
482 | IEEE80211_AMPDU_TX_OPERATIONAL, | 500 | IEEE80211_AMPDU_TX_OPERATIONAL, |
483 | &sta->sta, tid, NULL, | 501 | &sta->sta, tid, NULL, tid_tx->buf_size); |
484 | sta->ampdu_mlme.tid_tx[tid]->buf_size); | ||
485 | 502 | ||
486 | /* | 503 | /* |
487 | * synchronize with TX path, while splicing the TX path | 504 | * synchronize with TX path, while splicing the TX path |
@@ -489,13 +506,13 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | |||
489 | */ | 506 | */ |
490 | spin_lock_bh(&sta->lock); | 507 | spin_lock_bh(&sta->lock); |
491 | 508 | ||
492 | ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid); | 509 | ieee80211_agg_splice_packets(local, tid_tx, tid); |
493 | /* | 510 | /* |
494 | * Now mark as operational. This will be visible | 511 | * Now mark as operational. This will be visible |
495 | * in the TX path, and lets it go lock-free in | 512 | * in the TX path, and lets it go lock-free in |
496 | * the common case. | 513 | * the common case. |
497 | */ | 514 | */ |
498 | set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state); | 515 | set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); |
499 | ieee80211_agg_splice_finish(local, tid); | 516 | ieee80211_agg_splice_finish(local, tid); |
500 | 517 | ||
501 | spin_unlock_bh(&sta->lock); | 518 | spin_unlock_bh(&sta->lock); |
@@ -529,7 +546,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) | |||
529 | } | 546 | } |
530 | 547 | ||
531 | mutex_lock(&sta->ampdu_mlme.mtx); | 548 | mutex_lock(&sta->ampdu_mlme.mtx); |
532 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 549 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
533 | 550 | ||
534 | if (WARN_ON(!tid_tx)) { | 551 | if (WARN_ON(!tid_tx)) { |
535 | #ifdef CONFIG_MAC80211_HT_DEBUG | 552 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -607,7 +624,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
607 | return -EINVAL; | 624 | return -EINVAL; |
608 | 625 | ||
609 | spin_lock_bh(&sta->lock); | 626 | spin_lock_bh(&sta->lock); |
610 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 627 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
611 | 628 | ||
612 | if (!tid_tx) { | 629 | if (!tid_tx) { |
613 | ret = -ENOENT; | 630 | ret = -ENOENT; |
@@ -663,7 +680,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
663 | 680 | ||
664 | mutex_lock(&sta->ampdu_mlme.mtx); | 681 | mutex_lock(&sta->ampdu_mlme.mtx); |
665 | spin_lock_bh(&sta->lock); | 682 | spin_lock_bh(&sta->lock); |
666 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 683 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
667 | 684 | ||
668 | if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | 685 | if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { |
669 | #ifdef CONFIG_MAC80211_HT_DEBUG | 686 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -689,7 +706,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
689 | ieee80211_agg_splice_packets(local, tid_tx, tid); | 706 | ieee80211_agg_splice_packets(local, tid_tx, tid); |
690 | 707 | ||
691 | /* future packets must not find the tid_tx struct any more */ | 708 | /* future packets must not find the tid_tx struct any more */ |
692 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | 709 | ieee80211_assign_tid_tx(sta, tid, NULL); |
693 | 710 | ||
694 | ieee80211_agg_splice_finish(local, tid); | 711 | ieee80211_agg_splice_finish(local, tid); |
695 | 712 | ||
@@ -744,7 +761,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
744 | 761 | ||
745 | mutex_lock(&sta->ampdu_mlme.mtx); | 762 | mutex_lock(&sta->ampdu_mlme.mtx); |
746 | 763 | ||
747 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 764 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
748 | if (!tid_tx) | 765 | if (!tid_tx) |
749 | goto out; | 766 | goto out; |
750 | 767 | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 44049733c4ea..be70c70d3f5b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -136,7 +136,10 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
136 | mutex_lock(&sdata->local->sta_mtx); | 136 | mutex_lock(&sdata->local->sta_mtx); |
137 | 137 | ||
138 | if (mac_addr) { | 138 | if (mac_addr) { |
139 | sta = sta_info_get_bss(sdata, mac_addr); | 139 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
140 | sta = sta_info_get(sdata, mac_addr); | ||
141 | else | ||
142 | sta = sta_info_get_bss(sdata, mac_addr); | ||
140 | if (!sta) { | 143 | if (!sta) { |
141 | ieee80211_key_free(sdata->local, key); | 144 | ieee80211_key_free(sdata->local, key); |
142 | err = -ENOENT; | 145 | err = -ENOENT; |
@@ -157,13 +160,14 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
157 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | 160 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, |
158 | u8 key_idx, bool pairwise, const u8 *mac_addr) | 161 | u8 key_idx, bool pairwise, const u8 *mac_addr) |
159 | { | 162 | { |
160 | struct ieee80211_sub_if_data *sdata; | 163 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
164 | struct ieee80211_local *local = sdata->local; | ||
161 | struct sta_info *sta; | 165 | struct sta_info *sta; |
166 | struct ieee80211_key *key = NULL; | ||
162 | int ret; | 167 | int ret; |
163 | 168 | ||
164 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 169 | mutex_lock(&local->sta_mtx); |
165 | 170 | mutex_lock(&local->key_mtx); | |
166 | mutex_lock(&sdata->local->sta_mtx); | ||
167 | 171 | ||
168 | if (mac_addr) { | 172 | if (mac_addr) { |
169 | ret = -ENOENT; | 173 | ret = -ENOENT; |
@@ -172,33 +176,24 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
172 | if (!sta) | 176 | if (!sta) |
173 | goto out_unlock; | 177 | goto out_unlock; |
174 | 178 | ||
175 | if (pairwise) { | 179 | if (pairwise) |
176 | if (sta->ptk) { | 180 | key = key_mtx_dereference(local, sta->ptk); |
177 | ieee80211_key_free(sdata->local, sta->ptk); | 181 | else |
178 | ret = 0; | 182 | key = key_mtx_dereference(local, sta->gtk[key_idx]); |
179 | } | 183 | } else |
180 | } else { | 184 | key = key_mtx_dereference(local, sdata->keys[key_idx]); |
181 | if (sta->gtk[key_idx]) { | ||
182 | ieee80211_key_free(sdata->local, | ||
183 | sta->gtk[key_idx]); | ||
184 | ret = 0; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | goto out_unlock; | ||
189 | } | ||
190 | 185 | ||
191 | if (!sdata->keys[key_idx]) { | 186 | if (!key) { |
192 | ret = -ENOENT; | 187 | ret = -ENOENT; |
193 | goto out_unlock; | 188 | goto out_unlock; |
194 | } | 189 | } |
195 | 190 | ||
196 | ieee80211_key_free(sdata->local, sdata->keys[key_idx]); | 191 | __ieee80211_key_free(key); |
197 | WARN_ON(sdata->keys[key_idx]); | ||
198 | 192 | ||
199 | ret = 0; | 193 | ret = 0; |
200 | out_unlock: | 194 | out_unlock: |
201 | mutex_unlock(&sdata->local->sta_mtx); | 195 | mutex_unlock(&local->key_mtx); |
196 | mutex_unlock(&local->sta_mtx); | ||
202 | 197 | ||
203 | return ret; | 198 | return ret; |
204 | } | 199 | } |
@@ -228,11 +223,11 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
228 | goto out; | 223 | goto out; |
229 | 224 | ||
230 | if (pairwise) | 225 | if (pairwise) |
231 | key = sta->ptk; | 226 | key = rcu_dereference(sta->ptk); |
232 | else if (key_idx < NUM_DEFAULT_KEYS) | 227 | else if (key_idx < NUM_DEFAULT_KEYS) |
233 | key = sta->gtk[key_idx]; | 228 | key = rcu_dereference(sta->gtk[key_idx]); |
234 | } else | 229 | } else |
235 | key = sdata->keys[key_idx]; | 230 | key = rcu_dereference(sdata->keys[key_idx]); |
236 | 231 | ||
237 | if (!key) | 232 | if (!key) |
238 | goto out; | 233 | goto out; |
@@ -330,6 +325,7 @@ static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, in | |||
330 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | 325 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) |
331 | { | 326 | { |
332 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 327 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
328 | struct timespec uptime; | ||
333 | 329 | ||
334 | sinfo->generation = sdata->local->sta_generation; | 330 | sinfo->generation = sdata->local->sta_generation; |
335 | 331 | ||
@@ -342,7 +338,12 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
342 | STATION_INFO_TX_FAILED | | 338 | STATION_INFO_TX_FAILED | |
343 | STATION_INFO_TX_BITRATE | | 339 | STATION_INFO_TX_BITRATE | |
344 | STATION_INFO_RX_BITRATE | | 340 | STATION_INFO_RX_BITRATE | |
345 | STATION_INFO_RX_DROP_MISC; | 341 | STATION_INFO_RX_DROP_MISC | |
342 | STATION_INFO_BSS_PARAM | | ||
343 | STATION_INFO_CONNECTED_TIME; | ||
344 | |||
345 | do_posix_clock_monotonic_gettime(&uptime); | ||
346 | sinfo->connected_time = uptime.tv_sec - sta->last_connected; | ||
346 | 347 | ||
347 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 348 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); |
348 | sinfo->rx_bytes = sta->rx_bytes; | 349 | sinfo->rx_bytes = sta->rx_bytes; |
@@ -389,6 +390,16 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
389 | sinfo->plink_state = sta->plink_state; | 390 | sinfo->plink_state = sta->plink_state; |
390 | #endif | 391 | #endif |
391 | } | 392 | } |
393 | |||
394 | sinfo->bss_param.flags = 0; | ||
395 | if (sdata->vif.bss_conf.use_cts_prot) | ||
396 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; | ||
397 | if (sdata->vif.bss_conf.use_short_preamble) | ||
398 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; | ||
399 | if (sdata->vif.bss_conf.use_short_slot) | ||
400 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; | ||
401 | sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period; | ||
402 | sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; | ||
392 | } | 403 | } |
393 | 404 | ||
394 | 405 | ||
@@ -452,7 +463,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
452 | int size; | 463 | int size; |
453 | int err = -EINVAL; | 464 | int err = -EINVAL; |
454 | 465 | ||
455 | old = sdata->u.ap.beacon; | 466 | old = rtnl_dereference(sdata->u.ap.beacon); |
456 | 467 | ||
457 | /* head must not be zero-length */ | 468 | /* head must not be zero-length */ |
458 | if (params->head && !params->head_len) | 469 | if (params->head && !params->head_len) |
@@ -547,8 +558,7 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
547 | 558 | ||
548 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 559 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
549 | 560 | ||
550 | old = sdata->u.ap.beacon; | 561 | old = rtnl_dereference(sdata->u.ap.beacon); |
551 | |||
552 | if (old) | 562 | if (old) |
553 | return -EALREADY; | 563 | return -EALREADY; |
554 | 564 | ||
@@ -563,8 +573,7 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
563 | 573 | ||
564 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 574 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
565 | 575 | ||
566 | old = sdata->u.ap.beacon; | 576 | old = rtnl_dereference(sdata->u.ap.beacon); |
567 | |||
568 | if (!old) | 577 | if (!old) |
569 | return -ENOENT; | 578 | return -ENOENT; |
570 | 579 | ||
@@ -578,8 +587,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) | |||
578 | 587 | ||
579 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 588 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
580 | 589 | ||
581 | old = sdata->u.ap.beacon; | 590 | old = rtnl_dereference(sdata->u.ap.beacon); |
582 | |||
583 | if (!old) | 591 | if (!old) |
584 | return -ENOENT; | 592 | return -ENOENT; |
585 | 593 | ||
@@ -675,6 +683,12 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
675 | if (set & BIT(NL80211_STA_FLAG_MFP)) | 683 | if (set & BIT(NL80211_STA_FLAG_MFP)) |
676 | sta->flags |= WLAN_STA_MFP; | 684 | sta->flags |= WLAN_STA_MFP; |
677 | } | 685 | } |
686 | |||
687 | if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) { | ||
688 | sta->flags &= ~WLAN_STA_AUTH; | ||
689 | if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) | ||
690 | sta->flags |= WLAN_STA_AUTH; | ||
691 | } | ||
678 | spin_unlock_irqrestore(&sta->flaglock, flags); | 692 | spin_unlock_irqrestore(&sta->flaglock, flags); |
679 | 693 | ||
680 | /* | 694 | /* |
@@ -712,15 +726,29 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
712 | params->ht_capa, | 726 | params->ht_capa, |
713 | &sta->sta.ht_cap); | 727 | &sta->sta.ht_cap); |
714 | 728 | ||
715 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { | 729 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
716 | switch (params->plink_action) { | 730 | #ifdef CONFIG_MAC80211_MESH |
717 | case PLINK_ACTION_OPEN: | 731 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) |
718 | mesh_plink_open(sta); | 732 | switch (params->plink_state) { |
719 | break; | 733 | case NL80211_PLINK_LISTEN: |
720 | case PLINK_ACTION_BLOCK: | 734 | case NL80211_PLINK_ESTAB: |
721 | mesh_plink_block(sta); | 735 | case NL80211_PLINK_BLOCKED: |
722 | break; | 736 | sta->plink_state = params->plink_state; |
723 | } | 737 | break; |
738 | default: | ||
739 | /* nothing */ | ||
740 | break; | ||
741 | } | ||
742 | else | ||
743 | switch (params->plink_action) { | ||
744 | case PLINK_ACTION_OPEN: | ||
745 | mesh_plink_open(sta); | ||
746 | break; | ||
747 | case PLINK_ACTION_BLOCK: | ||
748 | mesh_plink_block(sta); | ||
749 | break; | ||
750 | } | ||
751 | #endif | ||
724 | } | 752 | } |
725 | } | 753 | } |
726 | 754 | ||
@@ -921,8 +949,10 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, | |||
921 | static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | 949 | static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, |
922 | struct mpath_info *pinfo) | 950 | struct mpath_info *pinfo) |
923 | { | 951 | { |
924 | if (mpath->next_hop) | 952 | struct sta_info *next_hop_sta = rcu_dereference(mpath->next_hop); |
925 | memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN); | 953 | |
954 | if (next_hop_sta) | ||
955 | memcpy(next_hop, next_hop_sta->sta.addr, ETH_ALEN); | ||
926 | else | 956 | else |
927 | memset(next_hop, 0, ETH_ALEN); | 957 | memset(next_hop, 0, ETH_ALEN); |
928 | 958 | ||
@@ -1023,26 +1053,30 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, | |||
1023 | u8 *new_ie; | 1053 | u8 *new_ie; |
1024 | const u8 *old_ie; | 1054 | const u8 *old_ie; |
1025 | 1055 | ||
1026 | /* first allocate the new vendor information element */ | 1056 | /* allocate information elements */ |
1027 | new_ie = NULL; | 1057 | new_ie = NULL; |
1028 | old_ie = ifmsh->vendor_ie; | 1058 | old_ie = ifmsh->ie; |
1029 | 1059 | ||
1030 | ifmsh->vendor_ie_len = setup->vendor_ie_len; | 1060 | if (setup->ie_len) { |
1031 | if (setup->vendor_ie_len) { | 1061 | new_ie = kmemdup(setup->ie, setup->ie_len, |
1032 | new_ie = kmemdup(setup->vendor_ie, setup->vendor_ie_len, | ||
1033 | GFP_KERNEL); | 1062 | GFP_KERNEL); |
1034 | if (!new_ie) | 1063 | if (!new_ie) |
1035 | return -ENOMEM; | 1064 | return -ENOMEM; |
1036 | } | 1065 | } |
1066 | ifmsh->ie_len = setup->ie_len; | ||
1067 | ifmsh->ie = new_ie; | ||
1068 | kfree(old_ie); | ||
1037 | 1069 | ||
1038 | /* now copy the rest of the setup parameters */ | 1070 | /* now copy the rest of the setup parameters */ |
1039 | ifmsh->mesh_id_len = setup->mesh_id_len; | 1071 | ifmsh->mesh_id_len = setup->mesh_id_len; |
1040 | memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); | 1072 | memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); |
1041 | ifmsh->mesh_pp_id = setup->path_sel_proto; | 1073 | ifmsh->mesh_pp_id = setup->path_sel_proto; |
1042 | ifmsh->mesh_pm_id = setup->path_metric; | 1074 | ifmsh->mesh_pm_id = setup->path_metric; |
1043 | ifmsh->vendor_ie = new_ie; | 1075 | ifmsh->security = IEEE80211_MESH_SEC_NONE; |
1044 | 1076 | if (setup->is_authenticated) | |
1045 | kfree(old_ie); | 1077 | ifmsh->security |= IEEE80211_MESH_SEC_AUTHED; |
1078 | if (setup->is_secure) | ||
1079 | ifmsh->security |= IEEE80211_MESH_SEC_SECURED; | ||
1046 | 1080 | ||
1047 | return 0; | 1081 | return 0; |
1048 | } | 1082 | } |
@@ -1275,9 +1309,10 @@ static int ieee80211_set_channel(struct wiphy *wiphy, | |||
1275 | } | 1309 | } |
1276 | 1310 | ||
1277 | #ifdef CONFIG_PM | 1311 | #ifdef CONFIG_PM |
1278 | static int ieee80211_suspend(struct wiphy *wiphy) | 1312 | static int ieee80211_suspend(struct wiphy *wiphy, |
1313 | struct cfg80211_wowlan *wowlan) | ||
1279 | { | 1314 | { |
1280 | return __ieee80211_suspend(wiphy_priv(wiphy)); | 1315 | return __ieee80211_suspend(wiphy_priv(wiphy), wowlan); |
1281 | } | 1316 | } |
1282 | 1317 | ||
1283 | static int ieee80211_resume(struct wiphy *wiphy) | 1318 | static int ieee80211_resume(struct wiphy *wiphy) |
@@ -1320,6 +1355,30 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
1320 | return ieee80211_request_scan(sdata, req); | 1355 | return ieee80211_request_scan(sdata, req); |
1321 | } | 1356 | } |
1322 | 1357 | ||
1358 | static int | ||
1359 | ieee80211_sched_scan_start(struct wiphy *wiphy, | ||
1360 | struct net_device *dev, | ||
1361 | struct cfg80211_sched_scan_request *req) | ||
1362 | { | ||
1363 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1364 | |||
1365 | if (!sdata->local->ops->sched_scan_start) | ||
1366 | return -EOPNOTSUPP; | ||
1367 | |||
1368 | return ieee80211_request_sched_scan_start(sdata, req); | ||
1369 | } | ||
1370 | |||
1371 | static int | ||
1372 | ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) | ||
1373 | { | ||
1374 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1375 | |||
1376 | if (!sdata->local->ops->sched_scan_stop) | ||
1377 | return -EOPNOTSUPP; | ||
1378 | |||
1379 | return ieee80211_request_sched_scan_stop(sdata); | ||
1380 | } | ||
1381 | |||
1323 | static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, | 1382 | static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, |
1324 | struct cfg80211_auth_request *req) | 1383 | struct cfg80211_auth_request *req) |
1325 | { | 1384 | { |
@@ -1611,16 +1670,13 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
1611 | { | 1670 | { |
1612 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1671 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1613 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1672 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1614 | int i; | 1673 | int i, ret; |
1615 | |||
1616 | /* | ||
1617 | * This _could_ be supported by providing a hook for | ||
1618 | * drivers for this function, but at this point it | ||
1619 | * doesn't seem worth bothering. | ||
1620 | */ | ||
1621 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) | ||
1622 | return -EOPNOTSUPP; | ||
1623 | 1674 | ||
1675 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) { | ||
1676 | ret = drv_set_bitrate_mask(local, sdata, mask); | ||
1677 | if (ret) | ||
1678 | return ret; | ||
1679 | } | ||
1624 | 1680 | ||
1625 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | 1681 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) |
1626 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; | 1682 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; |
@@ -2064,6 +2120,8 @@ struct cfg80211_ops mac80211_config_ops = { | |||
2064 | .suspend = ieee80211_suspend, | 2120 | .suspend = ieee80211_suspend, |
2065 | .resume = ieee80211_resume, | 2121 | .resume = ieee80211_resume, |
2066 | .scan = ieee80211_scan, | 2122 | .scan = ieee80211_scan, |
2123 | .sched_scan_start = ieee80211_sched_scan_start, | ||
2124 | .sched_scan_stop = ieee80211_sched_scan_stop, | ||
2067 | .auth = ieee80211_auth, | 2125 | .auth = ieee80211_auth, |
2068 | .assoc = ieee80211_assoc, | 2126 | .assoc = ieee80211_assoc, |
2069 | .deauth = ieee80211_deauth, | 2127 | .deauth = ieee80211_deauth, |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 51f0d780dafa..186e02f7cc32 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -37,7 +37,7 @@ int mac80211_format_buffer(char __user *userbuf, size_t count, | |||
37 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | 37 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); |
38 | } | 38 | } |
39 | 39 | ||
40 | #define DEBUGFS_READONLY_FILE(name, fmt, value...) \ | 40 | #define DEBUGFS_READONLY_FILE_FN(name, fmt, value...) \ |
41 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ | 41 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ |
42 | size_t count, loff_t *ppos) \ | 42 | size_t count, loff_t *ppos) \ |
43 | { \ | 43 | { \ |
@@ -45,14 +45,19 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \ | |||
45 | \ | 45 | \ |
46 | return mac80211_format_buffer(userbuf, count, ppos, \ | 46 | return mac80211_format_buffer(userbuf, count, ppos, \ |
47 | fmt "\n", ##value); \ | 47 | fmt "\n", ##value); \ |
48 | } \ | 48 | } |
49 | \ | 49 | |
50 | #define DEBUGFS_READONLY_FILE_OPS(name) \ | ||
50 | static const struct file_operations name## _ops = { \ | 51 | static const struct file_operations name## _ops = { \ |
51 | .read = name## _read, \ | 52 | .read = name## _read, \ |
52 | .open = mac80211_open_file_generic, \ | 53 | .open = mac80211_open_file_generic, \ |
53 | .llseek = generic_file_llseek, \ | 54 | .llseek = generic_file_llseek, \ |
54 | }; | 55 | }; |
55 | 56 | ||
57 | #define DEBUGFS_READONLY_FILE(name, fmt, value...) \ | ||
58 | DEBUGFS_READONLY_FILE_FN(name, fmt, value) \ | ||
59 | DEBUGFS_READONLY_FILE_OPS(name) | ||
60 | |||
56 | #define DEBUGFS_ADD(name) \ | 61 | #define DEBUGFS_ADD(name) \ |
57 | debugfs_create_file(#name, 0400, phyd, local, &name## _ops); | 62 | debugfs_create_file(#name, 0400, phyd, local, &name## _ops); |
58 | 63 | ||
@@ -130,7 +135,7 @@ static ssize_t reset_write(struct file *file, const char __user *user_buf, | |||
130 | struct ieee80211_local *local = file->private_data; | 135 | struct ieee80211_local *local = file->private_data; |
131 | 136 | ||
132 | rtnl_lock(); | 137 | rtnl_lock(); |
133 | __ieee80211_suspend(&local->hw); | 138 | __ieee80211_suspend(&local->hw, NULL); |
134 | __ieee80211_resume(&local->hw); | 139 | __ieee80211_resume(&local->hw); |
135 | rtnl_unlock(); | 140 | rtnl_unlock(); |
136 | 141 | ||
@@ -291,11 +296,70 @@ static ssize_t channel_type_read(struct file *file, char __user *user_buf, | |||
291 | return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); | 296 | return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); |
292 | } | 297 | } |
293 | 298 | ||
294 | static const struct file_operations channel_type_ops = { | 299 | static ssize_t hwflags_read(struct file *file, char __user *user_buf, |
295 | .read = channel_type_read, | 300 | size_t count, loff_t *ppos) |
296 | .open = mac80211_open_file_generic, | 301 | { |
297 | .llseek = default_llseek, | 302 | struct ieee80211_local *local = file->private_data; |
298 | }; | 303 | int mxln = 500; |
304 | ssize_t rv; | ||
305 | char *buf = kzalloc(mxln, GFP_KERNEL); | ||
306 | int sf = 0; /* how many written so far */ | ||
307 | |||
308 | sf += snprintf(buf, mxln - sf, "0x%x\n", local->hw.flags); | ||
309 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) | ||
310 | sf += snprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n"); | ||
311 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | ||
312 | sf += snprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n"); | ||
313 | if (local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) | ||
314 | sf += snprintf(buf + sf, mxln - sf, | ||
315 | "HOST_BCAST_PS_BUFFERING\n"); | ||
316 | if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE) | ||
317 | sf += snprintf(buf + sf, mxln - sf, | ||
318 | "2GHZ_SHORT_SLOT_INCAPABLE\n"); | ||
319 | if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE) | ||
320 | sf += snprintf(buf + sf, mxln - sf, | ||
321 | "2GHZ_SHORT_PREAMBLE_INCAPABLE\n"); | ||
322 | if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | ||
323 | sf += snprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n"); | ||
324 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | ||
325 | sf += snprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n"); | ||
326 | if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) | ||
327 | sf += snprintf(buf + sf, mxln - sf, "NEED_DTIM_PERIOD\n"); | ||
328 | if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT) | ||
329 | sf += snprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n"); | ||
330 | if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) | ||
331 | sf += snprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n"); | ||
332 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS) | ||
333 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n"); | ||
334 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | ||
335 | sf += snprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n"); | ||
336 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | ||
337 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n"); | ||
338 | if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE) | ||
339 | sf += snprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n"); | ||
340 | if (local->hw.flags & IEEE80211_HW_BEACON_FILTER) | ||
341 | sf += snprintf(buf + sf, mxln - sf, "BEACON_FILTER\n"); | ||
342 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) | ||
343 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n"); | ||
344 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) | ||
345 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_SMPS\n"); | ||
346 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) | ||
347 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n"); | ||
348 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | ||
349 | sf += snprintf(buf + sf, mxln - sf, "REPORTS_TX_ACK_STATUS\n"); | ||
350 | if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | ||
351 | sf += snprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n"); | ||
352 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) | ||
353 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_CQM_RSSI\n"); | ||
354 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK) | ||
355 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n"); | ||
356 | if (local->hw.flags & IEEE80211_HW_AP_LINK_PS) | ||
357 | sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n"); | ||
358 | |||
359 | rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); | ||
360 | kfree(buf); | ||
361 | return rv; | ||
362 | } | ||
299 | 363 | ||
300 | static ssize_t queues_read(struct file *file, char __user *user_buf, | 364 | static ssize_t queues_read(struct file *file, char __user *user_buf, |
301 | size_t count, loff_t *ppos) | 365 | size_t count, loff_t *ppos) |
@@ -315,11 +379,9 @@ static ssize_t queues_read(struct file *file, char __user *user_buf, | |||
315 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); | 379 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); |
316 | } | 380 | } |
317 | 381 | ||
318 | static const struct file_operations queues_ops = { | 382 | DEBUGFS_READONLY_FILE_OPS(hwflags); |
319 | .read = queues_read, | 383 | DEBUGFS_READONLY_FILE_OPS(channel_type); |
320 | .open = mac80211_open_file_generic, | 384 | DEBUGFS_READONLY_FILE_OPS(queues); |
321 | .llseek = default_llseek, | ||
322 | }; | ||
323 | 385 | ||
324 | /* statistics stuff */ | 386 | /* statistics stuff */ |
325 | 387 | ||
@@ -395,6 +457,7 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
395 | DEBUGFS_ADD(uapsd_queues); | 457 | DEBUGFS_ADD(uapsd_queues); |
396 | DEBUGFS_ADD(uapsd_max_sp_len); | 458 | DEBUGFS_ADD(uapsd_max_sp_len); |
397 | DEBUGFS_ADD(channel_type); | 459 | DEBUGFS_ADD(channel_type); |
460 | DEBUGFS_ADD(hwflags); | ||
398 | DEBUGFS_ADD(user_power); | 461 | DEBUGFS_ADD(user_power); |
399 | DEBUGFS_ADD(power); | 462 | DEBUGFS_ADD(power); |
400 | 463 | ||
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index f7ef3477c24a..33c58b85c911 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -241,16 +241,12 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key) | |||
241 | if (!key->debugfs.dir) | 241 | if (!key->debugfs.dir) |
242 | return; | 242 | return; |
243 | 243 | ||
244 | rcu_read_lock(); | 244 | sta = key->sta; |
245 | sta = rcu_dereference(key->sta); | 245 | if (sta) { |
246 | if (sta) | ||
247 | sprintf(buf, "../../stations/%pM", sta->sta.addr); | 246 | sprintf(buf, "../../stations/%pM", sta->sta.addr); |
248 | rcu_read_unlock(); | ||
249 | |||
250 | /* using sta as a boolean is fine outside RCU lock */ | ||
251 | if (sta) | ||
252 | key->debugfs.stalink = | 247 | key->debugfs.stalink = |
253 | debugfs_create_symlink("station", key->debugfs.dir, buf); | 248 | debugfs_create_symlink("station", key->debugfs.dir, buf); |
249 | } | ||
254 | 250 | ||
255 | DEBUGFS_ADD(keylen); | 251 | DEBUGFS_ADD(keylen); |
256 | DEBUGFS_ADD(flags); | 252 | DEBUGFS_ADD(flags); |
@@ -286,7 +282,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
286 | lockdep_assert_held(&sdata->local->key_mtx); | 282 | lockdep_assert_held(&sdata->local->key_mtx); |
287 | 283 | ||
288 | if (sdata->default_unicast_key) { | 284 | if (sdata->default_unicast_key) { |
289 | key = sdata->default_unicast_key; | 285 | key = key_mtx_dereference(sdata->local, |
286 | sdata->default_unicast_key); | ||
290 | sprintf(buf, "../keys/%d", key->debugfs.cnt); | 287 | sprintf(buf, "../keys/%d", key->debugfs.cnt); |
291 | sdata->debugfs.default_unicast_key = | 288 | sdata->debugfs.default_unicast_key = |
292 | debugfs_create_symlink("default_unicast_key", | 289 | debugfs_create_symlink("default_unicast_key", |
@@ -297,7 +294,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
297 | } | 294 | } |
298 | 295 | ||
299 | if (sdata->default_multicast_key) { | 296 | if (sdata->default_multicast_key) { |
300 | key = sdata->default_multicast_key; | 297 | key = key_mtx_dereference(sdata->local, |
298 | sdata->default_multicast_key); | ||
301 | sprintf(buf, "../keys/%d", key->debugfs.cnt); | 299 | sprintf(buf, "../keys/%d", key->debugfs.cnt); |
302 | sdata->debugfs.default_multicast_key = | 300 | sdata->debugfs.default_multicast_key = |
303 | debugfs_create_symlink("default_multicast_key", | 301 | debugfs_create_symlink("default_multicast_key", |
@@ -316,9 +314,8 @@ void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata) | |||
316 | if (!sdata->debugfs.dir) | 314 | if (!sdata->debugfs.dir) |
317 | return; | 315 | return; |
318 | 316 | ||
319 | /* this is running under the key lock */ | 317 | key = key_mtx_dereference(sdata->local, |
320 | 318 | sdata->default_mgmt_key); | |
321 | key = sdata->default_mgmt_key; | ||
322 | if (key) { | 319 | if (key) { |
323 | sprintf(buf, "../keys/%d", key->debugfs.cnt); | 320 | sprintf(buf, "../keys/%d", key->debugfs.cnt); |
324 | sdata->debugfs.default_mgmt_key = | 321 | sdata->debugfs.default_mgmt_key = |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index c04a1396cf8d..a01d2137fddc 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -92,6 +92,31 @@ static ssize_t sta_inactive_ms_read(struct file *file, char __user *userbuf, | |||
92 | } | 92 | } |
93 | STA_OPS(inactive_ms); | 93 | STA_OPS(inactive_ms); |
94 | 94 | ||
95 | |||
96 | static ssize_t sta_connected_time_read(struct file *file, char __user *userbuf, | ||
97 | size_t count, loff_t *ppos) | ||
98 | { | ||
99 | struct sta_info *sta = file->private_data; | ||
100 | struct timespec uptime; | ||
101 | struct tm result; | ||
102 | long connected_time_secs; | ||
103 | char buf[100]; | ||
104 | int res; | ||
105 | do_posix_clock_monotonic_gettime(&uptime); | ||
106 | connected_time_secs = uptime.tv_sec - sta->last_connected; | ||
107 | time_to_tm(connected_time_secs, 0, &result); | ||
108 | result.tm_year -= 70; | ||
109 | result.tm_mday -= 1; | ||
110 | res = scnprintf(buf, sizeof(buf), | ||
111 | "years - %ld\nmonths - %d\ndays - %d\nclock - %d:%d:%d\n\n", | ||
112 | result.tm_year, result.tm_mon, result.tm_mday, | ||
113 | result.tm_hour, result.tm_min, result.tm_sec); | ||
114 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
115 | } | ||
116 | STA_OPS(connected_time); | ||
117 | |||
118 | |||
119 | |||
95 | static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, | 120 | static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, |
96 | size_t count, loff_t *ppos) | 121 | size_t count, loff_t *ppos) |
97 | { | 122 | { |
@@ -324,6 +349,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) | |||
324 | DEBUGFS_ADD(flags); | 349 | DEBUGFS_ADD(flags); |
325 | DEBUGFS_ADD(num_ps_buf_frames); | 350 | DEBUGFS_ADD(num_ps_buf_frames); |
326 | DEBUGFS_ADD(inactive_ms); | 351 | DEBUGFS_ADD(inactive_ms); |
352 | DEBUGFS_ADD(connected_time); | ||
327 | DEBUGFS_ADD(last_seq_ctrl); | 353 | DEBUGFS_ADD(last_seq_ctrl); |
328 | DEBUGFS_ADD(agg_status); | 354 | DEBUGFS_ADD(agg_status); |
329 | DEBUGFS_ADD(dev); | 355 | DEBUGFS_ADD(dev); |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 9c0d62bb0ea3..eebf7a67daf7 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -41,6 +41,33 @@ static inline void drv_stop(struct ieee80211_local *local) | |||
41 | local->started = false; | 41 | local->started = false; |
42 | } | 42 | } |
43 | 43 | ||
44 | #ifdef CONFIG_PM | ||
45 | static inline int drv_suspend(struct ieee80211_local *local, | ||
46 | struct cfg80211_wowlan *wowlan) | ||
47 | { | ||
48 | int ret; | ||
49 | |||
50 | might_sleep(); | ||
51 | |||
52 | trace_drv_suspend(local); | ||
53 | ret = local->ops->suspend(&local->hw, wowlan); | ||
54 | trace_drv_return_int(local, ret); | ||
55 | return ret; | ||
56 | } | ||
57 | |||
58 | static inline int drv_resume(struct ieee80211_local *local) | ||
59 | { | ||
60 | int ret; | ||
61 | |||
62 | might_sleep(); | ||
63 | |||
64 | trace_drv_resume(local); | ||
65 | ret = local->ops->resume(&local->hw); | ||
66 | trace_drv_return_int(local, ret); | ||
67 | return ret; | ||
68 | } | ||
69 | #endif | ||
70 | |||
44 | static inline int drv_add_interface(struct ieee80211_local *local, | 71 | static inline int drv_add_interface(struct ieee80211_local *local, |
45 | struct ieee80211_vif *vif) | 72 | struct ieee80211_vif *vif) |
46 | { | 73 | { |
@@ -185,12 +212,39 @@ static inline int drv_hw_scan(struct ieee80211_local *local, | |||
185 | 212 | ||
186 | might_sleep(); | 213 | might_sleep(); |
187 | 214 | ||
188 | trace_drv_hw_scan(local, sdata, req); | 215 | trace_drv_hw_scan(local, sdata); |
189 | ret = local->ops->hw_scan(&local->hw, &sdata->vif, req); | 216 | ret = local->ops->hw_scan(&local->hw, &sdata->vif, req); |
190 | trace_drv_return_int(local, ret); | 217 | trace_drv_return_int(local, ret); |
191 | return ret; | 218 | return ret; |
192 | } | 219 | } |
193 | 220 | ||
221 | static inline int | ||
222 | drv_sched_scan_start(struct ieee80211_local *local, | ||
223 | struct ieee80211_sub_if_data *sdata, | ||
224 | struct cfg80211_sched_scan_request *req, | ||
225 | struct ieee80211_sched_scan_ies *ies) | ||
226 | { | ||
227 | int ret; | ||
228 | |||
229 | might_sleep(); | ||
230 | |||
231 | trace_drv_sched_scan_start(local, sdata); | ||
232 | ret = local->ops->sched_scan_start(&local->hw, &sdata->vif, | ||
233 | req, ies); | ||
234 | trace_drv_return_int(local, ret); | ||
235 | return ret; | ||
236 | } | ||
237 | |||
238 | static inline void drv_sched_scan_stop(struct ieee80211_local *local, | ||
239 | struct ieee80211_sub_if_data *sdata) | ||
240 | { | ||
241 | might_sleep(); | ||
242 | |||
243 | trace_drv_sched_scan_stop(local, sdata); | ||
244 | local->ops->sched_scan_stop(&local->hw, &sdata->vif); | ||
245 | trace_drv_return_void(local); | ||
246 | } | ||
247 | |||
194 | static inline void drv_sw_scan_start(struct ieee80211_local *local) | 248 | static inline void drv_sw_scan_start(struct ieee80211_local *local) |
195 | { | 249 | { |
196 | might_sleep(); | 250 | might_sleep(); |
@@ -552,4 +606,35 @@ static inline void drv_get_ringparam(struct ieee80211_local *local, | |||
552 | trace_drv_return_void(local); | 606 | trace_drv_return_void(local); |
553 | } | 607 | } |
554 | 608 | ||
609 | static inline bool drv_tx_frames_pending(struct ieee80211_local *local) | ||
610 | { | ||
611 | bool ret = false; | ||
612 | |||
613 | might_sleep(); | ||
614 | |||
615 | trace_drv_tx_frames_pending(local); | ||
616 | if (local->ops->tx_frames_pending) | ||
617 | ret = local->ops->tx_frames_pending(&local->hw); | ||
618 | trace_drv_return_bool(local, ret); | ||
619 | |||
620 | return ret; | ||
621 | } | ||
622 | |||
623 | static inline int drv_set_bitrate_mask(struct ieee80211_local *local, | ||
624 | struct ieee80211_sub_if_data *sdata, | ||
625 | const struct cfg80211_bitrate_mask *mask) | ||
626 | { | ||
627 | int ret = -EOPNOTSUPP; | ||
628 | |||
629 | might_sleep(); | ||
630 | |||
631 | trace_drv_set_bitrate_mask(local, sdata, mask); | ||
632 | if (local->ops->set_bitrate_mask) | ||
633 | ret = local->ops->set_bitrate_mask(&local->hw, | ||
634 | &sdata->vif, mask); | ||
635 | trace_drv_return_int(local, ret); | ||
636 | |||
637 | return ret; | ||
638 | } | ||
639 | |||
555 | #endif /* __MAC80211_DRIVER_OPS */ | 640 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 45aab80738e2..ed9edcbd9aa5 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -55,6 +55,70 @@ DECLARE_EVENT_CLASS(local_only_evt, | |||
55 | TP_printk(LOCAL_PR_FMT, LOCAL_PR_ARG) | 55 | TP_printk(LOCAL_PR_FMT, LOCAL_PR_ARG) |
56 | ); | 56 | ); |
57 | 57 | ||
58 | DECLARE_EVENT_CLASS(local_sdata_addr_evt, | ||
59 | TP_PROTO(struct ieee80211_local *local, | ||
60 | struct ieee80211_sub_if_data *sdata), | ||
61 | TP_ARGS(local, sdata), | ||
62 | |||
63 | TP_STRUCT__entry( | ||
64 | LOCAL_ENTRY | ||
65 | VIF_ENTRY | ||
66 | __array(char, addr, 6) | ||
67 | ), | ||
68 | |||
69 | TP_fast_assign( | ||
70 | LOCAL_ASSIGN; | ||
71 | VIF_ASSIGN; | ||
72 | memcpy(__entry->addr, sdata->vif.addr, 6); | ||
73 | ), | ||
74 | |||
75 | TP_printk( | ||
76 | LOCAL_PR_FMT VIF_PR_FMT " addr:%pM", | ||
77 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr | ||
78 | ) | ||
79 | ); | ||
80 | |||
81 | DECLARE_EVENT_CLASS(local_u32_evt, | ||
82 | TP_PROTO(struct ieee80211_local *local, u32 value), | ||
83 | TP_ARGS(local, value), | ||
84 | |||
85 | TP_STRUCT__entry( | ||
86 | LOCAL_ENTRY | ||
87 | __field(u32, value) | ||
88 | ), | ||
89 | |||
90 | TP_fast_assign( | ||
91 | LOCAL_ASSIGN; | ||
92 | __entry->value = value; | ||
93 | ), | ||
94 | |||
95 | TP_printk( | ||
96 | LOCAL_PR_FMT " value:%d", | ||
97 | LOCAL_PR_ARG, __entry->value | ||
98 | ) | ||
99 | ); | ||
100 | |||
101 | DECLARE_EVENT_CLASS(local_sdata_evt, | ||
102 | TP_PROTO(struct ieee80211_local *local, | ||
103 | struct ieee80211_sub_if_data *sdata), | ||
104 | TP_ARGS(local, sdata), | ||
105 | |||
106 | TP_STRUCT__entry( | ||
107 | LOCAL_ENTRY | ||
108 | VIF_ENTRY | ||
109 | ), | ||
110 | |||
111 | TP_fast_assign( | ||
112 | LOCAL_ASSIGN; | ||
113 | VIF_ASSIGN; | ||
114 | ), | ||
115 | |||
116 | TP_printk( | ||
117 | LOCAL_PR_FMT VIF_PR_FMT, | ||
118 | LOCAL_PR_ARG, VIF_PR_ARG | ||
119 | ) | ||
120 | ); | ||
121 | |||
58 | DEFINE_EVENT(local_only_evt, drv_return_void, | 122 | DEFINE_EVENT(local_only_evt, drv_return_void, |
59 | TP_PROTO(struct ieee80211_local *local), | 123 | TP_PROTO(struct ieee80211_local *local), |
60 | TP_ARGS(local) | 124 | TP_ARGS(local) |
@@ -74,6 +138,21 @@ TRACE_EVENT(drv_return_int, | |||
74 | TP_printk(LOCAL_PR_FMT " - %d", LOCAL_PR_ARG, __entry->ret) | 138 | TP_printk(LOCAL_PR_FMT " - %d", LOCAL_PR_ARG, __entry->ret) |
75 | ); | 139 | ); |
76 | 140 | ||
141 | TRACE_EVENT(drv_return_bool, | ||
142 | TP_PROTO(struct ieee80211_local *local, bool ret), | ||
143 | TP_ARGS(local, ret), | ||
144 | TP_STRUCT__entry( | ||
145 | LOCAL_ENTRY | ||
146 | __field(bool, ret) | ||
147 | ), | ||
148 | TP_fast_assign( | ||
149 | LOCAL_ASSIGN; | ||
150 | __entry->ret = ret; | ||
151 | ), | ||
152 | TP_printk(LOCAL_PR_FMT " - %s", LOCAL_PR_ARG, (__entry->ret) ? | ||
153 | "true" : "false") | ||
154 | ); | ||
155 | |||
77 | TRACE_EVENT(drv_return_u64, | 156 | TRACE_EVENT(drv_return_u64, |
78 | TP_PROTO(struct ieee80211_local *local, u64 ret), | 157 | TP_PROTO(struct ieee80211_local *local, u64 ret), |
79 | TP_ARGS(local, ret), | 158 | TP_ARGS(local, ret), |
@@ -93,33 +172,25 @@ DEFINE_EVENT(local_only_evt, drv_start, | |||
93 | TP_ARGS(local) | 172 | TP_ARGS(local) |
94 | ); | 173 | ); |
95 | 174 | ||
175 | DEFINE_EVENT(local_only_evt, drv_suspend, | ||
176 | TP_PROTO(struct ieee80211_local *local), | ||
177 | TP_ARGS(local) | ||
178 | ); | ||
179 | |||
180 | DEFINE_EVENT(local_only_evt, drv_resume, | ||
181 | TP_PROTO(struct ieee80211_local *local), | ||
182 | TP_ARGS(local) | ||
183 | ); | ||
184 | |||
96 | DEFINE_EVENT(local_only_evt, drv_stop, | 185 | DEFINE_EVENT(local_only_evt, drv_stop, |
97 | TP_PROTO(struct ieee80211_local *local), | 186 | TP_PROTO(struct ieee80211_local *local), |
98 | TP_ARGS(local) | 187 | TP_ARGS(local) |
99 | ); | 188 | ); |
100 | 189 | ||
101 | TRACE_EVENT(drv_add_interface, | 190 | DEFINE_EVENT(local_sdata_addr_evt, drv_add_interface, |
102 | TP_PROTO(struct ieee80211_local *local, | 191 | TP_PROTO(struct ieee80211_local *local, |
103 | struct ieee80211_sub_if_data *sdata), | 192 | struct ieee80211_sub_if_data *sdata), |
104 | 193 | TP_ARGS(local, sdata) | |
105 | TP_ARGS(local, sdata), | ||
106 | |||
107 | TP_STRUCT__entry( | ||
108 | LOCAL_ENTRY | ||
109 | VIF_ENTRY | ||
110 | __array(char, addr, 6) | ||
111 | ), | ||
112 | |||
113 | TP_fast_assign( | ||
114 | LOCAL_ASSIGN; | ||
115 | VIF_ASSIGN; | ||
116 | memcpy(__entry->addr, sdata->vif.addr, 6); | ||
117 | ), | ||
118 | |||
119 | TP_printk( | ||
120 | LOCAL_PR_FMT VIF_PR_FMT " addr:%pM", | ||
121 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr | ||
122 | ) | ||
123 | ); | 194 | ); |
124 | 195 | ||
125 | TRACE_EVENT(drv_change_interface, | 196 | TRACE_EVENT(drv_change_interface, |
@@ -150,27 +221,10 @@ TRACE_EVENT(drv_change_interface, | |||
150 | ) | 221 | ) |
151 | ); | 222 | ); |
152 | 223 | ||
153 | TRACE_EVENT(drv_remove_interface, | 224 | DEFINE_EVENT(local_sdata_addr_evt, drv_remove_interface, |
154 | TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata), | 225 | TP_PROTO(struct ieee80211_local *local, |
155 | 226 | struct ieee80211_sub_if_data *sdata), | |
156 | TP_ARGS(local, sdata), | 227 | TP_ARGS(local, sdata) |
157 | |||
158 | TP_STRUCT__entry( | ||
159 | LOCAL_ENTRY | ||
160 | VIF_ENTRY | ||
161 | __array(char, addr, 6) | ||
162 | ), | ||
163 | |||
164 | TP_fast_assign( | ||
165 | LOCAL_ASSIGN; | ||
166 | VIF_ASSIGN; | ||
167 | memcpy(__entry->addr, sdata->vif.addr, 6); | ||
168 | ), | ||
169 | |||
170 | TP_printk( | ||
171 | LOCAL_PR_FMT VIF_PR_FMT " addr:%pM", | ||
172 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr | ||
173 | ) | ||
174 | ); | 228 | ); |
175 | 229 | ||
176 | TRACE_EVENT(drv_config, | 230 | TRACE_EVENT(drv_config, |
@@ -400,27 +454,22 @@ TRACE_EVENT(drv_update_tkip_key, | |||
400 | ) | 454 | ) |
401 | ); | 455 | ); |
402 | 456 | ||
403 | TRACE_EVENT(drv_hw_scan, | 457 | DEFINE_EVENT(local_sdata_evt, drv_hw_scan, |
404 | TP_PROTO(struct ieee80211_local *local, | 458 | TP_PROTO(struct ieee80211_local *local, |
405 | struct ieee80211_sub_if_data *sdata, | 459 | struct ieee80211_sub_if_data *sdata), |
406 | struct cfg80211_scan_request *req), | 460 | TP_ARGS(local, sdata) |
407 | 461 | ); | |
408 | TP_ARGS(local, sdata, req), | ||
409 | |||
410 | TP_STRUCT__entry( | ||
411 | LOCAL_ENTRY | ||
412 | VIF_ENTRY | ||
413 | ), | ||
414 | 462 | ||
415 | TP_fast_assign( | 463 | DEFINE_EVENT(local_sdata_evt, drv_sched_scan_start, |
416 | LOCAL_ASSIGN; | 464 | TP_PROTO(struct ieee80211_local *local, |
417 | VIF_ASSIGN; | 465 | struct ieee80211_sub_if_data *sdata), |
418 | ), | 466 | TP_ARGS(local, sdata) |
467 | ); | ||
419 | 468 | ||
420 | TP_printk( | 469 | DEFINE_EVENT(local_sdata_evt, drv_sched_scan_stop, |
421 | LOCAL_PR_FMT VIF_PR_FMT, | 470 | TP_PROTO(struct ieee80211_local *local, |
422 | LOCAL_PR_ARG,VIF_PR_ARG | 471 | struct ieee80211_sub_if_data *sdata), |
423 | ) | 472 | TP_ARGS(local, sdata) |
424 | ); | 473 | ); |
425 | 474 | ||
426 | DEFINE_EVENT(local_only_evt, drv_sw_scan_start, | 475 | DEFINE_EVENT(local_only_evt, drv_sw_scan_start, |
@@ -489,46 +538,14 @@ TRACE_EVENT(drv_get_tkip_seq, | |||
489 | ) | 538 | ) |
490 | ); | 539 | ); |
491 | 540 | ||
492 | TRACE_EVENT(drv_set_frag_threshold, | 541 | DEFINE_EVENT(local_u32_evt, drv_set_frag_threshold, |
493 | TP_PROTO(struct ieee80211_local *local, u32 value), | 542 | TP_PROTO(struct ieee80211_local *local, u32 value), |
494 | 543 | TP_ARGS(local, value) | |
495 | TP_ARGS(local, value), | ||
496 | |||
497 | TP_STRUCT__entry( | ||
498 | LOCAL_ENTRY | ||
499 | __field(u32, value) | ||
500 | ), | ||
501 | |||
502 | TP_fast_assign( | ||
503 | LOCAL_ASSIGN; | ||
504 | __entry->value = value; | ||
505 | ), | ||
506 | |||
507 | TP_printk( | ||
508 | LOCAL_PR_FMT " value:%d", | ||
509 | LOCAL_PR_ARG, __entry->value | ||
510 | ) | ||
511 | ); | 544 | ); |
512 | 545 | ||
513 | TRACE_EVENT(drv_set_rts_threshold, | 546 | DEFINE_EVENT(local_u32_evt, drv_set_rts_threshold, |
514 | TP_PROTO(struct ieee80211_local *local, u32 value), | 547 | TP_PROTO(struct ieee80211_local *local, u32 value), |
515 | 548 | TP_ARGS(local, value) | |
516 | TP_ARGS(local, value), | ||
517 | |||
518 | TP_STRUCT__entry( | ||
519 | LOCAL_ENTRY | ||
520 | __field(u32, value) | ||
521 | ), | ||
522 | |||
523 | TP_fast_assign( | ||
524 | LOCAL_ASSIGN; | ||
525 | __entry->value = value; | ||
526 | ), | ||
527 | |||
528 | TP_printk( | ||
529 | LOCAL_PR_FMT " value:%d", | ||
530 | LOCAL_PR_ARG, __entry->value | ||
531 | ) | ||
532 | ); | 549 | ); |
533 | 550 | ||
534 | TRACE_EVENT(drv_set_coverage_class, | 551 | TRACE_EVENT(drv_set_coverage_class, |
@@ -964,11 +981,43 @@ TRACE_EVENT(drv_get_ringparam, | |||
964 | ) | 981 | ) |
965 | ); | 982 | ); |
966 | 983 | ||
984 | DEFINE_EVENT(local_only_evt, drv_tx_frames_pending, | ||
985 | TP_PROTO(struct ieee80211_local *local), | ||
986 | TP_ARGS(local) | ||
987 | ); | ||
988 | |||
967 | DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait, | 989 | DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait, |
968 | TP_PROTO(struct ieee80211_local *local), | 990 | TP_PROTO(struct ieee80211_local *local), |
969 | TP_ARGS(local) | 991 | TP_ARGS(local) |
970 | ); | 992 | ); |
971 | 993 | ||
994 | TRACE_EVENT(drv_set_bitrate_mask, | ||
995 | TP_PROTO(struct ieee80211_local *local, | ||
996 | struct ieee80211_sub_if_data *sdata, | ||
997 | const struct cfg80211_bitrate_mask *mask), | ||
998 | |||
999 | TP_ARGS(local, sdata, mask), | ||
1000 | |||
1001 | TP_STRUCT__entry( | ||
1002 | LOCAL_ENTRY | ||
1003 | VIF_ENTRY | ||
1004 | __field(u32, legacy_2g) | ||
1005 | __field(u32, legacy_5g) | ||
1006 | ), | ||
1007 | |||
1008 | TP_fast_assign( | ||
1009 | LOCAL_ASSIGN; | ||
1010 | VIF_ASSIGN; | ||
1011 | __entry->legacy_2g = mask->control[IEEE80211_BAND_2GHZ].legacy; | ||
1012 | __entry->legacy_5g = mask->control[IEEE80211_BAND_5GHZ].legacy; | ||
1013 | ), | ||
1014 | |||
1015 | TP_printk( | ||
1016 | LOCAL_PR_FMT VIF_PR_FMT " 2G Mask:0x%x 5G Mask:0x%x", | ||
1017 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->legacy_2g, __entry->legacy_5g | ||
1018 | ) | ||
1019 | ); | ||
1020 | |||
972 | /* | 1021 | /* |
973 | * Tracing for API calls that drivers call. | 1022 | * Tracing for API calls that drivers call. |
974 | */ | 1023 | */ |
@@ -1147,6 +1196,42 @@ TRACE_EVENT(api_scan_completed, | |||
1147 | ) | 1196 | ) |
1148 | ); | 1197 | ); |
1149 | 1198 | ||
1199 | TRACE_EVENT(api_sched_scan_results, | ||
1200 | TP_PROTO(struct ieee80211_local *local), | ||
1201 | |||
1202 | TP_ARGS(local), | ||
1203 | |||
1204 | TP_STRUCT__entry( | ||
1205 | LOCAL_ENTRY | ||
1206 | ), | ||
1207 | |||
1208 | TP_fast_assign( | ||
1209 | LOCAL_ASSIGN; | ||
1210 | ), | ||
1211 | |||
1212 | TP_printk( | ||
1213 | LOCAL_PR_FMT, LOCAL_PR_ARG | ||
1214 | ) | ||
1215 | ); | ||
1216 | |||
1217 | TRACE_EVENT(api_sched_scan_stopped, | ||
1218 | TP_PROTO(struct ieee80211_local *local), | ||
1219 | |||
1220 | TP_ARGS(local), | ||
1221 | |||
1222 | TP_STRUCT__entry( | ||
1223 | LOCAL_ENTRY | ||
1224 | ), | ||
1225 | |||
1226 | TP_fast_assign( | ||
1227 | LOCAL_ASSIGN; | ||
1228 | ), | ||
1229 | |||
1230 | TP_printk( | ||
1231 | LOCAL_PR_FMT, LOCAL_PR_ARG | ||
1232 | ) | ||
1233 | ); | ||
1234 | |||
1150 | TRACE_EVENT(api_sta_block_awake, | 1235 | TRACE_EVENT(api_sta_block_awake, |
1151 | TP_PROTO(struct ieee80211_local *local, | 1236 | TP_PROTO(struct ieee80211_local *local, |
1152 | struct ieee80211_sta *sta, bool block), | 1237 | struct ieee80211_sta *sta, bool block), |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index b9e4b9bd2179..591add22bcc0 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -140,14 +140,29 @@ void ieee80211_ba_session_work(struct work_struct *work) | |||
140 | sta, tid, WLAN_BACK_RECIPIENT, | 140 | sta, tid, WLAN_BACK_RECIPIENT, |
141 | WLAN_REASON_QSTA_TIMEOUT, true); | 141 | WLAN_REASON_QSTA_TIMEOUT, true); |
142 | 142 | ||
143 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 143 | tid_tx = sta->ampdu_mlme.tid_start_tx[tid]; |
144 | if (!tid_tx) | 144 | if (tid_tx) { |
145 | continue; | 145 | /* |
146 | * Assign it over to the normal tid_tx array | ||
147 | * where it "goes live". | ||
148 | */ | ||
149 | spin_lock_bh(&sta->lock); | ||
150 | |||
151 | sta->ampdu_mlme.tid_start_tx[tid] = NULL; | ||
152 | /* could there be a race? */ | ||
153 | if (sta->ampdu_mlme.tid_tx[tid]) | ||
154 | kfree(tid_tx); | ||
155 | else | ||
156 | ieee80211_assign_tid_tx(sta, tid, tid_tx); | ||
157 | spin_unlock_bh(&sta->lock); | ||
146 | 158 | ||
147 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) | ||
148 | ieee80211_tx_ba_session_handle_start(sta, tid); | 159 | ieee80211_tx_ba_session_handle_start(sta, tid); |
149 | else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP, | 160 | continue; |
150 | &tid_tx->state)) | 161 | } |
162 | |||
163 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | ||
164 | if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP, | ||
165 | &tid_tx->state)) | ||
151 | ___ieee80211_stop_tx_ba_session(sta, tid, | 166 | ___ieee80211_stop_tx_ba_session(sta, tid, |
152 | WLAN_BACK_INITIATOR, | 167 | WLAN_BACK_INITIATOR, |
153 | true); | 168 | true); |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 3e81af1fce58..421eaa6b0c2b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -40,7 +40,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
40 | struct ieee80211_mgmt *mgmt, | 40 | struct ieee80211_mgmt *mgmt, |
41 | size_t len) | 41 | size_t len) |
42 | { | 42 | { |
43 | u16 auth_alg, auth_transaction, status_code; | 43 | u16 auth_alg, auth_transaction; |
44 | 44 | ||
45 | lockdep_assert_held(&sdata->u.ibss.mtx); | 45 | lockdep_assert_held(&sdata->u.ibss.mtx); |
46 | 46 | ||
@@ -49,7 +49,6 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
49 | 49 | ||
50 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | 50 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); |
51 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | 51 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); |
52 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | ||
53 | 52 | ||
54 | /* | 53 | /* |
55 | * IEEE 802.11 standard does not require authentication in IBSS | 54 | * IEEE 802.11 standard does not require authentication in IBSS |
@@ -527,8 +526,6 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | |||
527 | static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | 526 | static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) |
528 | { | 527 | { |
529 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 528 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
530 | struct ieee80211_local *local = sdata->local; | ||
531 | struct ieee80211_supported_band *sband; | ||
532 | u8 bssid[ETH_ALEN]; | 529 | u8 bssid[ETH_ALEN]; |
533 | u16 capability; | 530 | u16 capability; |
534 | int i; | 531 | int i; |
@@ -551,8 +548,6 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | |||
551 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", | 548 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", |
552 | sdata->name, bssid); | 549 | sdata->name, bssid); |
553 | 550 | ||
554 | sband = local->hw.wiphy->bands[ifibss->channel->band]; | ||
555 | |||
556 | capability = WLAN_CAPABILITY_IBSS; | 551 | capability = WLAN_CAPABILITY_IBSS; |
557 | 552 | ||
558 | if (ifibss->privacy) | 553 | if (ifibss->privacy) |
@@ -661,19 +656,22 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
661 | static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | 656 | static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, |
662 | struct sk_buff *req) | 657 | struct sk_buff *req) |
663 | { | 658 | { |
664 | struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(req); | ||
665 | struct ieee80211_mgmt *mgmt = (void *)req->data; | 659 | struct ieee80211_mgmt *mgmt = (void *)req->data; |
666 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 660 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
667 | struct ieee80211_local *local = sdata->local; | 661 | struct ieee80211_local *local = sdata->local; |
668 | int tx_last_beacon, len = req->len; | 662 | int tx_last_beacon, len = req->len; |
669 | struct sk_buff *skb; | 663 | struct sk_buff *skb; |
670 | struct ieee80211_mgmt *resp; | 664 | struct ieee80211_mgmt *resp; |
665 | struct sk_buff *presp; | ||
671 | u8 *pos, *end; | 666 | u8 *pos, *end; |
672 | 667 | ||
673 | lockdep_assert_held(&ifibss->mtx); | 668 | lockdep_assert_held(&ifibss->mtx); |
674 | 669 | ||
670 | presp = rcu_dereference_protected(ifibss->presp, | ||
671 | lockdep_is_held(&ifibss->mtx)); | ||
672 | |||
675 | if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || | 673 | if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || |
676 | len < 24 + 2 || !ifibss->presp) | 674 | len < 24 + 2 || !presp) |
677 | return; | 675 | return; |
678 | 676 | ||
679 | tx_last_beacon = drv_tx_last_beacon(local); | 677 | tx_last_beacon = drv_tx_last_beacon(local); |
@@ -685,7 +683,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
685 | mgmt->bssid, tx_last_beacon); | 683 | mgmt->bssid, tx_last_beacon); |
686 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 684 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
687 | 685 | ||
688 | if (!tx_last_beacon && !(rx_status->rx_flags & IEEE80211_RX_RA_MATCH)) | 686 | if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da)) |
689 | return; | 687 | return; |
690 | 688 | ||
691 | if (memcmp(mgmt->bssid, ifibss->bssid, ETH_ALEN) != 0 && | 689 | if (memcmp(mgmt->bssid, ifibss->bssid, ETH_ALEN) != 0 && |
@@ -711,7 +709,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
711 | } | 709 | } |
712 | 710 | ||
713 | /* Reply with ProbeResp */ | 711 | /* Reply with ProbeResp */ |
714 | skb = skb_copy(ifibss->presp, GFP_KERNEL); | 712 | skb = skb_copy(presp, GFP_KERNEL); |
715 | if (!skb) | 713 | if (!skb) |
716 | return; | 714 | return; |
717 | 715 | ||
@@ -991,7 +989,8 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
991 | 989 | ||
992 | /* remove beacon */ | 990 | /* remove beacon */ |
993 | kfree(sdata->u.ibss.ie); | 991 | kfree(sdata->u.ibss.ie); |
994 | skb = sdata->u.ibss.presp; | 992 | skb = rcu_dereference_protected(sdata->u.ibss.presp, |
993 | lockdep_is_held(&sdata->u.ibss.mtx)); | ||
995 | rcu_assign_pointer(sdata->u.ibss.presp, NULL); | 994 | rcu_assign_pointer(sdata->u.ibss.presp, NULL); |
996 | sdata->vif.bss_conf.ibss_joined = false; | 995 | sdata->vif.bss_conf.ibss_joined = false; |
997 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | | 996 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c18396c248d7..2025af52b195 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -214,7 +214,7 @@ struct beacon_data { | |||
214 | }; | 214 | }; |
215 | 215 | ||
216 | struct ieee80211_if_ap { | 216 | struct ieee80211_if_ap { |
217 | struct beacon_data *beacon; | 217 | struct beacon_data __rcu *beacon; |
218 | 218 | ||
219 | struct list_head vlans; | 219 | struct list_head vlans; |
220 | 220 | ||
@@ -237,7 +237,7 @@ struct ieee80211_if_vlan { | |||
237 | struct list_head list; | 237 | struct list_head list; |
238 | 238 | ||
239 | /* used for all tx if the VLAN is configured to 4-addr mode */ | 239 | /* used for all tx if the VLAN is configured to 4-addr mode */ |
240 | struct sta_info *sta; | 240 | struct sta_info __rcu *sta; |
241 | }; | 241 | }; |
242 | 242 | ||
243 | struct mesh_stats { | 243 | struct mesh_stats { |
@@ -442,7 +442,8 @@ struct ieee80211_if_ibss { | |||
442 | 442 | ||
443 | unsigned long ibss_join_req; | 443 | unsigned long ibss_join_req; |
444 | /* probe response/beacon for IBSS */ | 444 | /* probe response/beacon for IBSS */ |
445 | struct sk_buff *presp, *skb; | 445 | struct sk_buff __rcu *presp; |
446 | struct sk_buff *skb; | ||
446 | 447 | ||
447 | enum { | 448 | enum { |
448 | IEEE80211_IBSS_MLME_SEARCH, | 449 | IEEE80211_IBSS_MLME_SEARCH, |
@@ -488,8 +489,13 @@ struct ieee80211_if_mesh { | |||
488 | struct mesh_config mshcfg; | 489 | struct mesh_config mshcfg; |
489 | u32 mesh_seqnum; | 490 | u32 mesh_seqnum; |
490 | bool accepting_plinks; | 491 | bool accepting_plinks; |
491 | const u8 *vendor_ie; | 492 | const u8 *ie; |
492 | u8 vendor_ie_len; | 493 | u8 ie_len; |
494 | enum { | ||
495 | IEEE80211_MESH_SEC_NONE = 0x0, | ||
496 | IEEE80211_MESH_SEC_AUTHED = 0x1, | ||
497 | IEEE80211_MESH_SEC_SECURED = 0x2, | ||
498 | } security; | ||
493 | }; | 499 | }; |
494 | 500 | ||
495 | #ifdef CONFIG_MAC80211_MESH | 501 | #ifdef CONFIG_MAC80211_MESH |
@@ -562,9 +568,10 @@ struct ieee80211_sub_if_data { | |||
562 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; | 568 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; |
563 | unsigned int fragment_next; | 569 | unsigned int fragment_next; |
564 | 570 | ||
565 | struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | 571 | struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
566 | struct ieee80211_key *default_unicast_key, *default_multicast_key; | 572 | struct ieee80211_key __rcu *default_unicast_key; |
567 | struct ieee80211_key *default_mgmt_key; | 573 | struct ieee80211_key __rcu *default_multicast_key; |
574 | struct ieee80211_key __rcu *default_mgmt_key; | ||
568 | 575 | ||
569 | u16 sequence_number; | 576 | u16 sequence_number; |
570 | __be16 control_port_protocol; | 577 | __be16 control_port_protocol; |
@@ -763,8 +770,14 @@ struct ieee80211_local { | |||
763 | /* device is started */ | 770 | /* device is started */ |
764 | bool started; | 771 | bool started; |
765 | 772 | ||
773 | /* wowlan is enabled -- don't reconfig on resume */ | ||
774 | bool wowlan; | ||
775 | |||
766 | int tx_headroom; /* required headroom for hardware/radiotap */ | 776 | int tx_headroom; /* required headroom for hardware/radiotap */ |
767 | 777 | ||
778 | /* count for keys needing tailroom space allocation */ | ||
779 | int crypto_tx_tailroom_needed_cnt; | ||
780 | |||
768 | /* Tasklet and skb queue to process calls from IRQ mode. All frames | 781 | /* Tasklet and skb queue to process calls from IRQ mode. All frames |
769 | * added to skb_queue will be processed, but frames in | 782 | * added to skb_queue will be processed, but frames in |
770 | * skb_queue_unreliable may be dropped if the total length of these | 783 | * skb_queue_unreliable may be dropped if the total length of these |
@@ -794,7 +807,7 @@ struct ieee80211_local { | |||
794 | spinlock_t sta_lock; | 807 | spinlock_t sta_lock; |
795 | unsigned long num_sta; | 808 | unsigned long num_sta; |
796 | struct list_head sta_list, sta_pending_list; | 809 | struct list_head sta_list, sta_pending_list; |
797 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 810 | struct sta_info __rcu *sta_hash[STA_HASH_SIZE]; |
798 | struct timer_list sta_cleanup; | 811 | struct timer_list sta_cleanup; |
799 | struct work_struct sta_finish_work; | 812 | struct work_struct sta_finish_work; |
800 | int sta_generation; | 813 | int sta_generation; |
@@ -809,8 +822,8 @@ struct ieee80211_local { | |||
809 | 822 | ||
810 | struct rate_control_ref *rate_ctrl; | 823 | struct rate_control_ref *rate_ctrl; |
811 | 824 | ||
812 | struct crypto_blkcipher *wep_tx_tfm; | 825 | struct crypto_cipher *wep_tx_tfm; |
813 | struct crypto_blkcipher *wep_rx_tfm; | 826 | struct crypto_cipher *wep_rx_tfm; |
814 | u32 wep_iv; | 827 | u32 wep_iv; |
815 | 828 | ||
816 | /* see iface.c */ | 829 | /* see iface.c */ |
@@ -836,6 +849,10 @@ struct ieee80211_local { | |||
836 | int scan_channel_idx; | 849 | int scan_channel_idx; |
837 | int scan_ies_len; | 850 | int scan_ies_len; |
838 | 851 | ||
852 | bool sched_scanning; | ||
853 | struct ieee80211_sched_scan_ies sched_scan_ies; | ||
854 | struct work_struct sched_scan_stopped_work; | ||
855 | |||
839 | unsigned long leave_oper_channel_time; | 856 | unsigned long leave_oper_channel_time; |
840 | enum mac80211_scan_state next_scan_state; | 857 | enum mac80211_scan_state next_scan_state; |
841 | struct delayed_work scan_work; | 858 | struct delayed_work scan_work; |
@@ -1143,6 +1160,12 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | |||
1143 | void ieee80211_rx_bss_put(struct ieee80211_local *local, | 1160 | void ieee80211_rx_bss_put(struct ieee80211_local *local, |
1144 | struct ieee80211_bss *bss); | 1161 | struct ieee80211_bss *bss); |
1145 | 1162 | ||
1163 | /* scheduled scan handling */ | ||
1164 | int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | ||
1165 | struct cfg80211_sched_scan_request *req); | ||
1166 | int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata); | ||
1167 | void ieee80211_sched_scan_stopped_work(struct work_struct *work); | ||
1168 | |||
1146 | /* off-channel helpers */ | 1169 | /* off-channel helpers */ |
1147 | bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local); | 1170 | bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local); |
1148 | void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local, | 1171 | void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local, |
@@ -1246,7 +1269,8 @@ int ieee80211_reconfig(struct ieee80211_local *local); | |||
1246 | void ieee80211_stop_device(struct ieee80211_local *local); | 1269 | void ieee80211_stop_device(struct ieee80211_local *local); |
1247 | 1270 | ||
1248 | #ifdef CONFIG_PM | 1271 | #ifdef CONFIG_PM |
1249 | int __ieee80211_suspend(struct ieee80211_hw *hw); | 1272 | int __ieee80211_suspend(struct ieee80211_hw *hw, |
1273 | struct cfg80211_wowlan *wowlan); | ||
1250 | 1274 | ||
1251 | static inline int __ieee80211_resume(struct ieee80211_hw *hw) | 1275 | static inline int __ieee80211_resume(struct ieee80211_hw *hw) |
1252 | { | 1276 | { |
@@ -1259,7 +1283,8 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw) | |||
1259 | return ieee80211_reconfig(hw_to_local(hw)); | 1283 | return ieee80211_reconfig(hw_to_local(hw)); |
1260 | } | 1284 | } |
1261 | #else | 1285 | #else |
1262 | static inline int __ieee80211_suspend(struct ieee80211_hw *hw) | 1286 | static inline int __ieee80211_suspend(struct ieee80211_hw *hw, |
1287 | struct cfg80211_wowlan *wowlan) | ||
1263 | { | 1288 | { |
1264 | return 0; | 1289 | return 0; |
1265 | } | 1290 | } |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 4054399be907..7dfbe71dc637 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -449,7 +449,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
449 | /* APs need special treatment */ | 449 | /* APs need special treatment */ |
450 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 450 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
451 | struct ieee80211_sub_if_data *vlan, *tmpsdata; | 451 | struct ieee80211_sub_if_data *vlan, *tmpsdata; |
452 | struct beacon_data *old_beacon = sdata->u.ap.beacon; | 452 | struct beacon_data *old_beacon = |
453 | rtnl_dereference(sdata->u.ap.beacon); | ||
453 | 454 | ||
454 | /* sdata_running will return false, so this will disable */ | 455 | /* sdata_running will return false, so this will disable */ |
455 | ieee80211_bss_info_change_notify(sdata, | 456 | ieee80211_bss_info_change_notify(sdata, |
@@ -1144,10 +1145,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1144 | + IEEE80211_ENCRYPT_HEADROOM; | 1145 | + IEEE80211_ENCRYPT_HEADROOM; |
1145 | ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM; | 1146 | ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM; |
1146 | 1147 | ||
1147 | ret = dev_alloc_name(ndev, ndev->name); | ||
1148 | if (ret < 0) | ||
1149 | goto fail; | ||
1150 | |||
1151 | ieee80211_assign_perm_addr(local, ndev, type); | 1148 | ieee80211_assign_perm_addr(local, ndev, type); |
1152 | memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); | 1149 | memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); |
1153 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); | 1150 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index af3c56482c80..31afd712930d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -101,6 +101,11 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
101 | 101 | ||
102 | if (!ret) { | 102 | if (!ret) { |
103 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; | 103 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; |
104 | |||
105 | if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || | ||
106 | (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))) | ||
107 | key->local->crypto_tx_tailroom_needed_cnt--; | ||
108 | |||
104 | return 0; | 109 | return 0; |
105 | } | 110 | } |
106 | 111 | ||
@@ -156,6 +161,10 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
156 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); | 161 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); |
157 | 162 | ||
158 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | 163 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
164 | |||
165 | if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || | ||
166 | (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))) | ||
167 | key->local->crypto_tx_tailroom_needed_cnt++; | ||
159 | } | 168 | } |
160 | 169 | ||
161 | void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) | 170 | void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) |
@@ -186,7 +195,7 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, | |||
186 | assert_key_lock(sdata->local); | 195 | assert_key_lock(sdata->local); |
187 | 196 | ||
188 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) | 197 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) |
189 | key = sdata->keys[idx]; | 198 | key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
190 | 199 | ||
191 | if (uni) | 200 | if (uni) |
192 | rcu_assign_pointer(sdata->default_unicast_key, key); | 201 | rcu_assign_pointer(sdata->default_unicast_key, key); |
@@ -213,7 +222,7 @@ __ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx) | |||
213 | 222 | ||
214 | if (idx >= NUM_DEFAULT_KEYS && | 223 | if (idx >= NUM_DEFAULT_KEYS && |
215 | idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) | 224 | idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) |
216 | key = sdata->keys[idx]; | 225 | key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
217 | 226 | ||
218 | rcu_assign_pointer(sdata->default_mgmt_key, key); | 227 | rcu_assign_pointer(sdata->default_mgmt_key, key); |
219 | 228 | ||
@@ -257,9 +266,15 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
257 | else | 266 | else |
258 | idx = new->conf.keyidx; | 267 | idx = new->conf.keyidx; |
259 | 268 | ||
260 | defunikey = old && sdata->default_unicast_key == old; | 269 | defunikey = old && |
261 | defmultikey = old && sdata->default_multicast_key == old; | 270 | old == key_mtx_dereference(sdata->local, |
262 | defmgmtkey = old && sdata->default_mgmt_key == old; | 271 | sdata->default_unicast_key); |
272 | defmultikey = old && | ||
273 | old == key_mtx_dereference(sdata->local, | ||
274 | sdata->default_multicast_key); | ||
275 | defmgmtkey = old && | ||
276 | old == key_mtx_dereference(sdata->local, | ||
277 | sdata->default_mgmt_key); | ||
263 | 278 | ||
264 | if (defunikey && !new) | 279 | if (defunikey && !new) |
265 | __ieee80211_set_default_key(sdata, -1, true, false); | 280 | __ieee80211_set_default_key(sdata, -1, true, false); |
@@ -388,8 +403,10 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) | |||
388 | ieee80211_aes_key_free(key->u.ccmp.tfm); | 403 | ieee80211_aes_key_free(key->u.ccmp.tfm); |
389 | if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) | 404 | if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) |
390 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); | 405 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); |
391 | if (key->local) | 406 | if (key->local) { |
392 | ieee80211_debugfs_key_remove(key); | 407 | ieee80211_debugfs_key_remove(key); |
408 | key->local->crypto_tx_tailroom_needed_cnt--; | ||
409 | } | ||
393 | 410 | ||
394 | kfree(key); | 411 | kfree(key); |
395 | } | 412 | } |
@@ -440,17 +457,19 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
440 | mutex_lock(&sdata->local->key_mtx); | 457 | mutex_lock(&sdata->local->key_mtx); |
441 | 458 | ||
442 | if (sta && pairwise) | 459 | if (sta && pairwise) |
443 | old_key = sta->ptk; | 460 | old_key = key_mtx_dereference(sdata->local, sta->ptk); |
444 | else if (sta) | 461 | else if (sta) |
445 | old_key = sta->gtk[idx]; | 462 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); |
446 | else | 463 | else |
447 | old_key = sdata->keys[idx]; | 464 | old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
448 | 465 | ||
449 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); | 466 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); |
450 | __ieee80211_key_destroy(old_key); | 467 | __ieee80211_key_destroy(old_key); |
451 | 468 | ||
452 | ieee80211_debugfs_key_add(key); | 469 | ieee80211_debugfs_key_add(key); |
453 | 470 | ||
471 | key->local->crypto_tx_tailroom_needed_cnt++; | ||
472 | |||
454 | ret = ieee80211_key_enable_hw_accel(key); | 473 | ret = ieee80211_key_enable_hw_accel(key); |
455 | 474 | ||
456 | mutex_unlock(&sdata->local->key_mtx); | 475 | mutex_unlock(&sdata->local->key_mtx); |
@@ -458,8 +477,11 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
458 | return ret; | 477 | return ret; |
459 | } | 478 | } |
460 | 479 | ||
461 | static void __ieee80211_key_free(struct ieee80211_key *key) | 480 | void __ieee80211_key_free(struct ieee80211_key *key) |
462 | { | 481 | { |
482 | if (!key) | ||
483 | return; | ||
484 | |||
463 | /* | 485 | /* |
464 | * Replace key with nothingness if it was ever used. | 486 | * Replace key with nothingness if it was ever used. |
465 | */ | 487 | */ |
@@ -473,9 +495,6 @@ static void __ieee80211_key_free(struct ieee80211_key *key) | |||
473 | void ieee80211_key_free(struct ieee80211_local *local, | 495 | void ieee80211_key_free(struct ieee80211_local *local, |
474 | struct ieee80211_key *key) | 496 | struct ieee80211_key *key) |
475 | { | 497 | { |
476 | if (!key) | ||
477 | return; | ||
478 | |||
479 | mutex_lock(&local->key_mtx); | 498 | mutex_lock(&local->key_mtx); |
480 | __ieee80211_key_free(key); | 499 | __ieee80211_key_free(key); |
481 | mutex_unlock(&local->key_mtx); | 500 | mutex_unlock(&local->key_mtx); |
@@ -492,8 +511,12 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) | |||
492 | 511 | ||
493 | mutex_lock(&sdata->local->key_mtx); | 512 | mutex_lock(&sdata->local->key_mtx); |
494 | 513 | ||
495 | list_for_each_entry(key, &sdata->key_list, list) | 514 | sdata->local->crypto_tx_tailroom_needed_cnt = 0; |
515 | |||
516 | list_for_each_entry(key, &sdata->key_list, list) { | ||
517 | sdata->local->crypto_tx_tailroom_needed_cnt++; | ||
496 | ieee80211_key_enable_hw_accel(key); | 518 | ieee80211_key_enable_hw_accel(key); |
519 | } | ||
497 | 520 | ||
498 | mutex_unlock(&sdata->local->key_mtx); | 521 | mutex_unlock(&sdata->local->key_mtx); |
499 | } | 522 | } |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 4ddbe27eb570..d801d5351336 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -135,6 +135,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
135 | int __must_check ieee80211_key_link(struct ieee80211_key *key, | 135 | int __must_check ieee80211_key_link(struct ieee80211_key *key, |
136 | struct ieee80211_sub_if_data *sdata, | 136 | struct ieee80211_sub_if_data *sdata, |
137 | struct sta_info *sta); | 137 | struct sta_info *sta); |
138 | void __ieee80211_key_free(struct ieee80211_key *key); | ||
138 | void ieee80211_key_free(struct ieee80211_local *local, | 139 | void ieee80211_key_free(struct ieee80211_local *local, |
139 | struct ieee80211_key *key); | 140 | struct ieee80211_key *key); |
140 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, | 141 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, |
@@ -145,4 +146,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); | |||
145 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); | 146 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); |
146 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); | 147 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); |
147 | 148 | ||
149 | #define key_mtx_dereference(local, ref) \ | ||
150 | rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx))) | ||
151 | |||
148 | #endif /* IEEE80211_KEY_H */ | 152 | #endif /* IEEE80211_KEY_H */ |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 562d2984c482..0d7b08db8e56 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -33,12 +33,6 @@ | |||
33 | #include "cfg.h" | 33 | #include "cfg.h" |
34 | #include "debugfs.h" | 34 | #include "debugfs.h" |
35 | 35 | ||
36 | |||
37 | static bool ieee80211_disable_40mhz_24ghz; | ||
38 | module_param(ieee80211_disable_40mhz_24ghz, bool, 0644); | ||
39 | MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz, | ||
40 | "Disable 40MHz support in the 2.4GHz band"); | ||
41 | |||
42 | static struct lock_class_key ieee80211_rx_skb_queue_class; | 36 | static struct lock_class_key ieee80211_rx_skb_queue_class; |
43 | 37 | ||
44 | void ieee80211_configure_filter(struct ieee80211_local *local) | 38 | void ieee80211_configure_filter(struct ieee80211_local *local) |
@@ -364,7 +358,8 @@ static void ieee80211_restart_work(struct work_struct *work) | |||
364 | flush_workqueue(local->workqueue); | 358 | flush_workqueue(local->workqueue); |
365 | 359 | ||
366 | mutex_lock(&local->mtx); | 360 | mutex_lock(&local->mtx); |
367 | WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), | 361 | WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) || |
362 | local->sched_scanning, | ||
368 | "%s called with hardware scan in progress\n", __func__); | 363 | "%s called with hardware scan in progress\n", __func__); |
369 | mutex_unlock(&local->mtx); | 364 | mutex_unlock(&local->mtx); |
370 | 365 | ||
@@ -545,7 +540,9 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { | |||
545 | }, | 540 | }, |
546 | [NL80211_IFTYPE_MESH_POINT] = { | 541 | [NL80211_IFTYPE_MESH_POINT] = { |
547 | .tx = 0xffff, | 542 | .tx = 0xffff, |
548 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4), | 543 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | |
544 | BIT(IEEE80211_STYPE_AUTH >> 4) | | ||
545 | BIT(IEEE80211_STYPE_DEAUTH >> 4), | ||
549 | }, | 546 | }, |
550 | }; | 547 | }; |
551 | 548 | ||
@@ -584,8 +581,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
584 | 581 | ||
585 | wiphy->flags |= WIPHY_FLAG_NETNS_OK | | 582 | wiphy->flags |= WIPHY_FLAG_NETNS_OK | |
586 | WIPHY_FLAG_4ADDR_AP | | 583 | WIPHY_FLAG_4ADDR_AP | |
587 | WIPHY_FLAG_4ADDR_STATION | | 584 | WIPHY_FLAG_4ADDR_STATION; |
588 | WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS; | ||
589 | 585 | ||
590 | if (!ops->set_key) | 586 | if (!ops->set_key) |
591 | wiphy->flags |= WIPHY_FLAG_IBSS_RSN; | 587 | wiphy->flags |= WIPHY_FLAG_IBSS_RSN; |
@@ -656,6 +652,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
656 | setup_timer(&local->dynamic_ps_timer, | 652 | setup_timer(&local->dynamic_ps_timer, |
657 | ieee80211_dynamic_ps_timer, (unsigned long) local); | 653 | ieee80211_dynamic_ps_timer, (unsigned long) local); |
658 | 654 | ||
655 | INIT_WORK(&local->sched_scan_stopped_work, | ||
656 | ieee80211_sched_scan_stopped_work); | ||
657 | |||
659 | sta_info_init(local); | 658 | sta_info_init(local); |
660 | 659 | ||
661 | for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { | 660 | for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { |
@@ -686,7 +685,7 @@ EXPORT_SYMBOL(ieee80211_alloc_hw); | |||
686 | int ieee80211_register_hw(struct ieee80211_hw *hw) | 685 | int ieee80211_register_hw(struct ieee80211_hw *hw) |
687 | { | 686 | { |
688 | struct ieee80211_local *local = hw_to_local(hw); | 687 | struct ieee80211_local *local = hw_to_local(hw); |
689 | int result; | 688 | int result, i; |
690 | enum ieee80211_band band; | 689 | enum ieee80211_band band; |
691 | int channels, max_bitrates; | 690 | int channels, max_bitrates; |
692 | bool supp_ht; | 691 | bool supp_ht; |
@@ -701,6 +700,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
701 | WLAN_CIPHER_SUITE_AES_CMAC | 700 | WLAN_CIPHER_SUITE_AES_CMAC |
702 | }; | 701 | }; |
703 | 702 | ||
703 | if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) | ||
704 | #ifdef CONFIG_PM | ||
705 | && (!local->ops->suspend || !local->ops->resume) | ||
706 | #endif | ||
707 | ) | ||
708 | return -EINVAL; | ||
709 | |||
704 | if (hw->max_report_rates == 0) | 710 | if (hw->max_report_rates == 0) |
705 | hw->max_report_rates = hw->max_rates; | 711 | hw->max_report_rates = hw->max_rates; |
706 | 712 | ||
@@ -726,18 +732,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
726 | } | 732 | } |
727 | channels += sband->n_channels; | 733 | channels += sband->n_channels; |
728 | 734 | ||
729 | /* | ||
730 | * Since ieee80211_disable_40mhz_24ghz is global, we can | ||
731 | * modify the sband's ht data even if the driver uses a | ||
732 | * global structure for that. | ||
733 | */ | ||
734 | if (ieee80211_disable_40mhz_24ghz && | ||
735 | band == IEEE80211_BAND_2GHZ && | ||
736 | sband->ht_cap.ht_supported) { | ||
737 | sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
738 | sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
739 | } | ||
740 | |||
741 | if (max_bitrates < sband->n_bitrates) | 735 | if (max_bitrates < sband->n_bitrates) |
742 | max_bitrates = sband->n_bitrates; | 736 | max_bitrates = sband->n_bitrates; |
743 | supp_ht = supp_ht || sband->ht_cap.ht_supported; | 737 | supp_ht = supp_ht || sband->ht_cap.ht_supported; |
@@ -749,17 +743,30 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
749 | return -ENOMEM; | 743 | return -ENOMEM; |
750 | 744 | ||
751 | /* if low-level driver supports AP, we also support VLAN */ | 745 | /* if low-level driver supports AP, we also support VLAN */ |
752 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) | 746 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { |
753 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); | 747 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); |
748 | hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN); | ||
749 | } | ||
754 | 750 | ||
755 | /* mac80211 always supports monitor */ | 751 | /* mac80211 always supports monitor */ |
756 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); | 752 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); |
753 | hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); | ||
754 | |||
755 | /* mac80211 doesn't support more than 1 channel */ | ||
756 | for (i = 0; i < hw->wiphy->n_iface_combinations; i++) | ||
757 | if (hw->wiphy->iface_combinations[i].num_different_channels > 1) | ||
758 | return -EINVAL; | ||
757 | 759 | ||
758 | #ifndef CONFIG_MAC80211_MESH | 760 | #ifndef CONFIG_MAC80211_MESH |
759 | /* mesh depends on Kconfig, but drivers should set it if they want */ | 761 | /* mesh depends on Kconfig, but drivers should set it if they want */ |
760 | local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT); | 762 | local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT); |
761 | #endif | 763 | #endif |
762 | 764 | ||
765 | /* if the underlying driver supports mesh, mac80211 will (at least) | ||
766 | * provide routing of mesh authentication frames to userspace */ | ||
767 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) | ||
768 | local->hw.wiphy->flags |= WIPHY_FLAG_MESH_AUTH; | ||
769 | |||
763 | /* mac80211 supports control port protocol changing */ | 770 | /* mac80211 supports control port protocol changing */ |
764 | local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL; | 771 | local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL; |
765 | 772 | ||
@@ -838,6 +845,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
838 | if (!local->ops->remain_on_channel) | 845 | if (!local->ops->remain_on_channel) |
839 | local->hw.wiphy->max_remain_on_channel_duration = 5000; | 846 | local->hw.wiphy->max_remain_on_channel_duration = 5000; |
840 | 847 | ||
848 | if (local->ops->sched_scan_start) | ||
849 | local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | ||
850 | |||
841 | result = wiphy_register(local->hw.wiphy); | 851 | result = wiphy_register(local->hw.wiphy); |
842 | if (result < 0) | 852 | if (result < 0) |
843 | goto fail_wiphy_register; | 853 | goto fail_wiphy_register; |
@@ -861,8 +871,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
861 | * and we need some headroom for passing the frame to monitor | 871 | * and we need some headroom for passing the frame to monitor |
862 | * interfaces, but never both at the same time. | 872 | * interfaces, but never both at the same time. |
863 | */ | 873 | */ |
874 | #ifndef __CHECKER__ | ||
864 | BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM != | 875 | BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM != |
865 | sizeof(struct ieee80211_tx_status_rtap_hdr)); | 876 | sizeof(struct ieee80211_tx_status_rtap_hdr)); |
877 | #endif | ||
866 | local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, | 878 | local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, |
867 | sizeof(struct ieee80211_tx_status_rtap_hdr)); | 879 | sizeof(struct ieee80211_tx_status_rtap_hdr)); |
868 | 880 | ||
@@ -879,10 +891,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
879 | 891 | ||
880 | local->dynamic_ps_forced_timeout = -1; | 892 | local->dynamic_ps_forced_timeout = -1; |
881 | 893 | ||
882 | result = sta_info_start(local); | ||
883 | if (result < 0) | ||
884 | goto fail_sta_info; | ||
885 | |||
886 | result = ieee80211_wep_init(local); | 894 | result = ieee80211_wep_init(local); |
887 | if (result < 0) | 895 | if (result < 0) |
888 | wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n", | 896 | wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n", |
@@ -945,7 +953,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
945 | rtnl_unlock(); | 953 | rtnl_unlock(); |
946 | ieee80211_wep_free(local); | 954 | ieee80211_wep_free(local); |
947 | sta_info_stop(local); | 955 | sta_info_stop(local); |
948 | fail_sta_info: | ||
949 | destroy_workqueue(local->workqueue); | 956 | destroy_workqueue(local->workqueue); |
950 | fail_workqueue: | 957 | fail_workqueue: |
951 | wiphy_unregister(local->hw.wiphy); | 958 | wiphy_unregister(local->hw.wiphy); |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 2a57cc02c618..29e9980c8e60 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -279,57 +279,14 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
279 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; | 279 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; |
280 | *pos++ = 0x00; | 280 | *pos++ = 0x00; |
281 | 281 | ||
282 | if (sdata->u.mesh.vendor_ie) { | 282 | if (sdata->u.mesh.ie) { |
283 | int len = sdata->u.mesh.vendor_ie_len; | 283 | int len = sdata->u.mesh.ie_len; |
284 | const u8 *data = sdata->u.mesh.vendor_ie; | 284 | const u8 *data = sdata->u.mesh.ie; |
285 | if (skb_tailroom(skb) > len) | 285 | if (skb_tailroom(skb) > len) |
286 | memcpy(skb_put(skb, len), data, len); | 286 | memcpy(skb_put(skb, len), data, len); |
287 | } | 287 | } |
288 | } | 288 | } |
289 | 289 | ||
290 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl) | ||
291 | { | ||
292 | /* Use last four bytes of hw addr and interface index as hash index */ | ||
293 | return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex, tbl->hash_rnd) | ||
294 | & tbl->hash_mask; | ||
295 | } | ||
296 | |||
297 | struct mesh_table *mesh_table_alloc(int size_order) | ||
298 | { | ||
299 | int i; | ||
300 | struct mesh_table *newtbl; | ||
301 | |||
302 | newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL); | ||
303 | if (!newtbl) | ||
304 | return NULL; | ||
305 | |||
306 | newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) * | ||
307 | (1 << size_order), GFP_KERNEL); | ||
308 | |||
309 | if (!newtbl->hash_buckets) { | ||
310 | kfree(newtbl); | ||
311 | return NULL; | ||
312 | } | ||
313 | |||
314 | newtbl->hashwlock = kmalloc(sizeof(spinlock_t) * | ||
315 | (1 << size_order), GFP_KERNEL); | ||
316 | if (!newtbl->hashwlock) { | ||
317 | kfree(newtbl->hash_buckets); | ||
318 | kfree(newtbl); | ||
319 | return NULL; | ||
320 | } | ||
321 | |||
322 | newtbl->size_order = size_order; | ||
323 | newtbl->hash_mask = (1 << size_order) - 1; | ||
324 | atomic_set(&newtbl->entries, 0); | ||
325 | get_random_bytes(&newtbl->hash_rnd, | ||
326 | sizeof(newtbl->hash_rnd)); | ||
327 | for (i = 0; i <= newtbl->hash_mask; i++) | ||
328 | spin_lock_init(&newtbl->hashwlock[i]); | ||
329 | |||
330 | return newtbl; | ||
331 | } | ||
332 | |||
333 | 290 | ||
334 | static void ieee80211_mesh_path_timer(unsigned long data) | 291 | static void ieee80211_mesh_path_timer(unsigned long data) |
335 | { | 292 | { |
@@ -573,6 +530,10 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
573 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | 530 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, |
574 | &elems); | 531 | &elems); |
575 | 532 | ||
533 | /* ignore beacons from secure mesh peers if our security is off */ | ||
534 | if (elems.rsn_len && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) | ||
535 | return; | ||
536 | |||
576 | if (elems.ds_params && elems.ds_params_len == 1) | 537 | if (elems.ds_params && elems.ds_params_len == 1) |
577 | freq = ieee80211_channel_to_frequency(elems.ds_params[0], band); | 538 | freq = ieee80211_channel_to_frequency(elems.ds_params[0], band); |
578 | else | 539 | else |
@@ -586,9 +547,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
586 | if (elems.mesh_id && elems.mesh_config && | 547 | if (elems.mesh_id && elems.mesh_config && |
587 | mesh_matches_local(&elems, sdata)) { | 548 | mesh_matches_local(&elems, sdata)) { |
588 | supp_rates = ieee80211_sta_get_rates(local, &elems, band); | 549 | supp_rates = ieee80211_sta_get_rates(local, &elems, band); |
589 | 550 | mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems); | |
590 | mesh_neighbour_update(mgmt->sa, supp_rates, sdata, | ||
591 | mesh_peer_accepts_plinks(&elems)); | ||
592 | } | 551 | } |
593 | } | 552 | } |
594 | 553 | ||
@@ -598,7 +557,7 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | |||
598 | struct ieee80211_rx_status *rx_status) | 557 | struct ieee80211_rx_status *rx_status) |
599 | { | 558 | { |
600 | switch (mgmt->u.action.category) { | 559 | switch (mgmt->u.action.category) { |
601 | case WLAN_CATEGORY_MESH_PLINK: | 560 | case WLAN_CATEGORY_MESH_ACTION: |
602 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); | 561 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); |
603 | break; | 562 | break; |
604 | case WLAN_CATEGORY_MESH_PATH_SEL: | 563 | case WLAN_CATEGORY_MESH_PATH_SEL: |
@@ -611,12 +570,9 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
611 | struct sk_buff *skb) | 570 | struct sk_buff *skb) |
612 | { | 571 | { |
613 | struct ieee80211_rx_status *rx_status; | 572 | struct ieee80211_rx_status *rx_status; |
614 | struct ieee80211_if_mesh *ifmsh; | ||
615 | struct ieee80211_mgmt *mgmt; | 573 | struct ieee80211_mgmt *mgmt; |
616 | u16 stype; | 574 | u16 stype; |
617 | 575 | ||
618 | ifmsh = &sdata->u.mesh; | ||
619 | |||
620 | rx_status = IEEE80211_SKB_RXCB(skb); | 576 | rx_status = IEEE80211_SKB_RXCB(skb); |
621 | mgmt = (struct ieee80211_mgmt *) skb->data; | 577 | mgmt = (struct ieee80211_mgmt *) skb->data; |
622 | stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; | 578 | stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index b99e230fe31c..e7c5fddb4804 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -92,7 +92,7 @@ struct mesh_path { | |||
92 | u8 dst[ETH_ALEN]; | 92 | u8 dst[ETH_ALEN]; |
93 | u8 mpp[ETH_ALEN]; /* used for MPP or MAP */ | 93 | u8 mpp[ETH_ALEN]; /* used for MPP or MAP */ |
94 | struct ieee80211_sub_if_data *sdata; | 94 | struct ieee80211_sub_if_data *sdata; |
95 | struct sta_info *next_hop; | 95 | struct sta_info __rcu *next_hop; |
96 | struct timer_list timer; | 96 | struct timer_list timer; |
97 | struct sk_buff_head frame_queue; | 97 | struct sk_buff_head frame_queue; |
98 | struct rcu_head rcu; | 98 | struct rcu_head rcu; |
@@ -226,7 +226,8 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | |||
226 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata); | 226 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata); |
227 | /* Mesh plinks */ | 227 | /* Mesh plinks */ |
228 | void mesh_neighbour_update(u8 *hw_addr, u32 rates, | 228 | void mesh_neighbour_update(u8 *hw_addr, u32 rates, |
229 | struct ieee80211_sub_if_data *sdata, bool add); | 229 | struct ieee80211_sub_if_data *sdata, |
230 | struct ieee802_11_elems *ie); | ||
230 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie); | 231 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie); |
231 | void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); | 232 | void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); |
232 | void mesh_plink_broken(struct sta_info *sta); | 233 | void mesh_plink_broken(struct sta_info *sta); |
@@ -239,12 +240,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
239 | 240 | ||
240 | /* Private interfaces */ | 241 | /* Private interfaces */ |
241 | /* Mesh tables */ | 242 | /* Mesh tables */ |
242 | struct mesh_table *mesh_table_alloc(int size_order); | ||
243 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs); | ||
244 | void mesh_mpath_table_grow(void); | 243 | void mesh_mpath_table_grow(void); |
245 | void mesh_mpp_table_grow(void); | 244 | void mesh_mpp_table_grow(void); |
246 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, | ||
247 | struct mesh_table *tbl); | ||
248 | /* Mesh paths */ | 245 | /* Mesh paths */ |
249 | int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode, | 246 | int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode, |
250 | const u8 *ra, struct ieee80211_sub_if_data *sdata); | 247 | const u8 *ra, struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 5bf64d7112b3..2b18053070c1 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -391,7 +391,6 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
391 | (mpath->flags & MESH_PATH_SN_VALID)) { | 391 | (mpath->flags & MESH_PATH_SN_VALID)) { |
392 | if (SN_GT(mpath->sn, orig_sn) || | 392 | if (SN_GT(mpath->sn, orig_sn) || |
393 | (mpath->sn == orig_sn && | 393 | (mpath->sn == orig_sn && |
394 | action == MPATH_PREQ && | ||
395 | new_metric >= mpath->metric)) { | 394 | new_metric >= mpath->metric)) { |
396 | process = false; | 395 | process = false; |
397 | fresh_info = false; | 396 | fresh_info = false; |
@@ -561,6 +560,14 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
561 | } | 560 | } |
562 | 561 | ||
563 | 562 | ||
563 | static inline struct sta_info * | ||
564 | next_hop_deref_protected(struct mesh_path *mpath) | ||
565 | { | ||
566 | return rcu_dereference_protected(mpath->next_hop, | ||
567 | lockdep_is_held(&mpath->state_lock)); | ||
568 | } | ||
569 | |||
570 | |||
564 | static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | 571 | static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, |
565 | struct ieee80211_mgmt *mgmt, | 572 | struct ieee80211_mgmt *mgmt, |
566 | u8 *prep_elem, u32 metric) | 573 | u8 *prep_elem, u32 metric) |
@@ -600,7 +607,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | |||
600 | spin_unlock_bh(&mpath->state_lock); | 607 | spin_unlock_bh(&mpath->state_lock); |
601 | goto fail; | 608 | goto fail; |
602 | } | 609 | } |
603 | memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN); | 610 | memcpy(next_hop, next_hop_deref_protected(mpath)->sta.addr, ETH_ALEN); |
604 | spin_unlock_bh(&mpath->state_lock); | 611 | spin_unlock_bh(&mpath->state_lock); |
605 | --ttl; | 612 | --ttl; |
606 | flags = PREP_IE_FLAGS(prep_elem); | 613 | flags = PREP_IE_FLAGS(prep_elem); |
@@ -633,7 +640,6 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | |||
633 | struct mesh_path *mpath; | 640 | struct mesh_path *mpath; |
634 | u8 ttl; | 641 | u8 ttl; |
635 | u8 *ta, *target_addr; | 642 | u8 *ta, *target_addr; |
636 | u8 target_flags; | ||
637 | u32 target_sn; | 643 | u32 target_sn; |
638 | u16 target_rcode; | 644 | u16 target_rcode; |
639 | 645 | ||
@@ -644,7 +650,6 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | |||
644 | return; | 650 | return; |
645 | } | 651 | } |
646 | ttl--; | 652 | ttl--; |
647 | target_flags = PERR_IE_TARGET_FLAGS(perr_elem); | ||
648 | target_addr = PERR_IE_TARGET_ADDR(perr_elem); | 653 | target_addr = PERR_IE_TARGET_ADDR(perr_elem); |
649 | target_sn = PERR_IE_TARGET_SN(perr_elem); | 654 | target_sn = PERR_IE_TARGET_SN(perr_elem); |
650 | target_rcode = PERR_IE_TARGET_RCODE(perr_elem); | 655 | target_rcode = PERR_IE_TARGET_RCODE(perr_elem); |
@@ -654,7 +659,8 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | |||
654 | if (mpath) { | 659 | if (mpath) { |
655 | spin_lock_bh(&mpath->state_lock); | 660 | spin_lock_bh(&mpath->state_lock); |
656 | if (mpath->flags & MESH_PATH_ACTIVE && | 661 | if (mpath->flags & MESH_PATH_ACTIVE && |
657 | memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 && | 662 | memcmp(ta, next_hop_deref_protected(mpath)->sta.addr, |
663 | ETH_ALEN) == 0 && | ||
658 | (!(mpath->flags & MESH_PATH_SN_VALID) || | 664 | (!(mpath->flags & MESH_PATH_SN_VALID) || |
659 | SN_GT(target_sn, mpath->sn))) { | 665 | SN_GT(target_sn, mpath->sn))) { |
660 | mpath->flags &= ~MESH_PATH_ACTIVE; | 666 | mpath->flags &= ~MESH_PATH_ACTIVE; |
@@ -675,12 +681,10 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, | |||
675 | { | 681 | { |
676 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 682 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
677 | struct mesh_path *mpath; | 683 | struct mesh_path *mpath; |
678 | u8 *ta; | ||
679 | u8 ttl, flags, hopcount; | 684 | u8 ttl, flags, hopcount; |
680 | u8 *orig_addr; | 685 | u8 *orig_addr; |
681 | u32 orig_sn, metric; | 686 | u32 orig_sn, metric; |
682 | 687 | ||
683 | ta = mgmt->sa; | ||
684 | ttl = rann->rann_ttl; | 688 | ttl = rann->rann_ttl; |
685 | if (ttl <= 1) { | 689 | if (ttl <= 1) { |
686 | ifmsh->mshstats.dropped_frames_ttl++; | 690 | ifmsh->mshstats.dropped_frames_ttl++; |
@@ -918,6 +922,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
918 | { | 922 | { |
919 | struct sk_buff *skb_to_free = NULL; | 923 | struct sk_buff *skb_to_free = NULL; |
920 | struct mesh_path *mpath; | 924 | struct mesh_path *mpath; |
925 | struct sta_info *next_hop; | ||
921 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 926 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
922 | u8 *target_addr = hdr->addr3; | 927 | u8 *target_addr = hdr->addr3; |
923 | int err = 0; | 928 | int err = 0; |
@@ -945,7 +950,11 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
945 | mesh_queue_preq(mpath, | 950 | mesh_queue_preq(mpath, |
946 | PREQ_Q_F_START | PREQ_Q_F_REFRESH); | 951 | PREQ_Q_F_START | PREQ_Q_F_REFRESH); |
947 | } | 952 | } |
948 | memcpy(hdr->addr1, mpath->next_hop->sta.addr, ETH_ALEN); | 953 | next_hop = rcu_dereference(mpath->next_hop); |
954 | if (next_hop) | ||
955 | memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN); | ||
956 | else | ||
957 | err = -ENOENT; | ||
949 | } else { | 958 | } else { |
950 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 959 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
951 | if (!(mpath->flags & MESH_PATH_RESOLVING)) { | 960 | if (!(mpath->flags & MESH_PATH_RESOLVING)) { |
@@ -971,20 +980,11 @@ endlookup: | |||
971 | 980 | ||
972 | void mesh_path_timer(unsigned long data) | 981 | void mesh_path_timer(unsigned long data) |
973 | { | 982 | { |
974 | struct ieee80211_sub_if_data *sdata; | 983 | struct mesh_path *mpath = (void *) data; |
975 | struct mesh_path *mpath; | 984 | struct ieee80211_sub_if_data *sdata = mpath->sdata; |
976 | |||
977 | rcu_read_lock(); | ||
978 | mpath = (struct mesh_path *) data; | ||
979 | mpath = rcu_dereference(mpath); | ||
980 | if (!mpath) | ||
981 | goto endmpathtimer; | ||
982 | sdata = mpath->sdata; | ||
983 | 985 | ||
984 | if (sdata->local->quiescing) { | 986 | if (sdata->local->quiescing) |
985 | rcu_read_unlock(); | ||
986 | return; | 987 | return; |
987 | } | ||
988 | 988 | ||
989 | spin_lock_bh(&mpath->state_lock); | 989 | spin_lock_bh(&mpath->state_lock); |
990 | if (mpath->flags & MESH_PATH_RESOLVED || | 990 | if (mpath->flags & MESH_PATH_RESOLVED || |
@@ -1001,8 +1001,6 @@ void mesh_path_timer(unsigned long data) | |||
1001 | } | 1001 | } |
1002 | 1002 | ||
1003 | spin_unlock_bh(&mpath->state_lock); | 1003 | spin_unlock_bh(&mpath->state_lock); |
1004 | endmpathtimer: | ||
1005 | rcu_read_unlock(); | ||
1006 | } | 1004 | } |
1007 | 1005 | ||
1008 | void | 1006 | void |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 336ca9d0c5c4..83ce48e31913 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -40,6 +40,50 @@ static struct mesh_table *mesh_paths; | |||
40 | static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ | 40 | static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ |
41 | 41 | ||
42 | int mesh_paths_generation; | 42 | int mesh_paths_generation; |
43 | |||
44 | /* This lock will have the grow table function as writer and add / delete nodes | ||
45 | * as readers. When reading the table (i.e. doing lookups) we are well protected | ||
46 | * by RCU | ||
47 | */ | ||
48 | static DEFINE_RWLOCK(pathtbl_resize_lock); | ||
49 | |||
50 | |||
51 | static struct mesh_table *mesh_table_alloc(int size_order) | ||
52 | { | ||
53 | int i; | ||
54 | struct mesh_table *newtbl; | ||
55 | |||
56 | newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL); | ||
57 | if (!newtbl) | ||
58 | return NULL; | ||
59 | |||
60 | newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) * | ||
61 | (1 << size_order), GFP_KERNEL); | ||
62 | |||
63 | if (!newtbl->hash_buckets) { | ||
64 | kfree(newtbl); | ||
65 | return NULL; | ||
66 | } | ||
67 | |||
68 | newtbl->hashwlock = kmalloc(sizeof(spinlock_t) * | ||
69 | (1 << size_order), GFP_KERNEL); | ||
70 | if (!newtbl->hashwlock) { | ||
71 | kfree(newtbl->hash_buckets); | ||
72 | kfree(newtbl); | ||
73 | return NULL; | ||
74 | } | ||
75 | |||
76 | newtbl->size_order = size_order; | ||
77 | newtbl->hash_mask = (1 << size_order) - 1; | ||
78 | atomic_set(&newtbl->entries, 0); | ||
79 | get_random_bytes(&newtbl->hash_rnd, | ||
80 | sizeof(newtbl->hash_rnd)); | ||
81 | for (i = 0; i <= newtbl->hash_mask; i++) | ||
82 | spin_lock_init(&newtbl->hashwlock[i]); | ||
83 | |||
84 | return newtbl; | ||
85 | } | ||
86 | |||
43 | static void __mesh_table_free(struct mesh_table *tbl) | 87 | static void __mesh_table_free(struct mesh_table *tbl) |
44 | { | 88 | { |
45 | kfree(tbl->hash_buckets); | 89 | kfree(tbl->hash_buckets); |
@@ -47,7 +91,7 @@ static void __mesh_table_free(struct mesh_table *tbl) | |||
47 | kfree(tbl); | 91 | kfree(tbl); |
48 | } | 92 | } |
49 | 93 | ||
50 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs) | 94 | static void mesh_table_free(struct mesh_table *tbl, bool free_leafs) |
51 | { | 95 | { |
52 | struct hlist_head *mesh_hash; | 96 | struct hlist_head *mesh_hash; |
53 | struct hlist_node *p, *q; | 97 | struct hlist_node *p, *q; |
@@ -55,60 +99,56 @@ void mesh_table_free(struct mesh_table *tbl, bool free_leafs) | |||
55 | 99 | ||
56 | mesh_hash = tbl->hash_buckets; | 100 | mesh_hash = tbl->hash_buckets; |
57 | for (i = 0; i <= tbl->hash_mask; i++) { | 101 | for (i = 0; i <= tbl->hash_mask; i++) { |
58 | spin_lock(&tbl->hashwlock[i]); | 102 | spin_lock_bh(&tbl->hashwlock[i]); |
59 | hlist_for_each_safe(p, q, &mesh_hash[i]) { | 103 | hlist_for_each_safe(p, q, &mesh_hash[i]) { |
60 | tbl->free_node(p, free_leafs); | 104 | tbl->free_node(p, free_leafs); |
61 | atomic_dec(&tbl->entries); | 105 | atomic_dec(&tbl->entries); |
62 | } | 106 | } |
63 | spin_unlock(&tbl->hashwlock[i]); | 107 | spin_unlock_bh(&tbl->hashwlock[i]); |
64 | } | 108 | } |
65 | __mesh_table_free(tbl); | 109 | __mesh_table_free(tbl); |
66 | } | 110 | } |
67 | 111 | ||
68 | static struct mesh_table *mesh_table_grow(struct mesh_table *tbl) | 112 | static int mesh_table_grow(struct mesh_table *oldtbl, |
113 | struct mesh_table *newtbl) | ||
69 | { | 114 | { |
70 | struct mesh_table *newtbl; | ||
71 | struct hlist_head *oldhash; | 115 | struct hlist_head *oldhash; |
72 | struct hlist_node *p, *q; | 116 | struct hlist_node *p, *q; |
73 | int i; | 117 | int i; |
74 | 118 | ||
75 | if (atomic_read(&tbl->entries) | 119 | if (atomic_read(&oldtbl->entries) |
76 | < tbl->mean_chain_len * (tbl->hash_mask + 1)) | 120 | < oldtbl->mean_chain_len * (oldtbl->hash_mask + 1)) |
77 | goto endgrow; | 121 | return -EAGAIN; |
78 | |||
79 | newtbl = mesh_table_alloc(tbl->size_order + 1); | ||
80 | if (!newtbl) | ||
81 | goto endgrow; | ||
82 | 122 | ||
83 | newtbl->free_node = tbl->free_node; | 123 | newtbl->free_node = oldtbl->free_node; |
84 | newtbl->mean_chain_len = tbl->mean_chain_len; | 124 | newtbl->mean_chain_len = oldtbl->mean_chain_len; |
85 | newtbl->copy_node = tbl->copy_node; | 125 | newtbl->copy_node = oldtbl->copy_node; |
86 | atomic_set(&newtbl->entries, atomic_read(&tbl->entries)); | 126 | atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries)); |
87 | 127 | ||
88 | oldhash = tbl->hash_buckets; | 128 | oldhash = oldtbl->hash_buckets; |
89 | for (i = 0; i <= tbl->hash_mask; i++) | 129 | for (i = 0; i <= oldtbl->hash_mask; i++) |
90 | hlist_for_each(p, &oldhash[i]) | 130 | hlist_for_each(p, &oldhash[i]) |
91 | if (tbl->copy_node(p, newtbl) < 0) | 131 | if (oldtbl->copy_node(p, newtbl) < 0) |
92 | goto errcopy; | 132 | goto errcopy; |
93 | 133 | ||
94 | return newtbl; | 134 | return 0; |
95 | 135 | ||
96 | errcopy: | 136 | errcopy: |
97 | for (i = 0; i <= newtbl->hash_mask; i++) { | 137 | for (i = 0; i <= newtbl->hash_mask; i++) { |
98 | hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) | 138 | hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) |
99 | tbl->free_node(p, 0); | 139 | oldtbl->free_node(p, 0); |
100 | } | 140 | } |
101 | __mesh_table_free(newtbl); | 141 | return -ENOMEM; |
102 | endgrow: | ||
103 | return NULL; | ||
104 | } | 142 | } |
105 | 143 | ||
144 | static u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, | ||
145 | struct mesh_table *tbl) | ||
146 | { | ||
147 | /* Use last four bytes of hw addr and interface index as hash index */ | ||
148 | return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex, tbl->hash_rnd) | ||
149 | & tbl->hash_mask; | ||
150 | } | ||
106 | 151 | ||
107 | /* This lock will have the grow table function as writer and add / delete nodes | ||
108 | * as readers. When reading the table (i.e. doing lookups) we are well protected | ||
109 | * by RCU | ||
110 | */ | ||
111 | static DEFINE_RWLOCK(pathtbl_resize_lock); | ||
112 | 152 | ||
113 | /** | 153 | /** |
114 | * | 154 | * |
@@ -280,7 +320,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
280 | if (!new_node) | 320 | if (!new_node) |
281 | goto err_node_alloc; | 321 | goto err_node_alloc; |
282 | 322 | ||
283 | read_lock(&pathtbl_resize_lock); | 323 | read_lock_bh(&pathtbl_resize_lock); |
284 | memcpy(new_mpath->dst, dst, ETH_ALEN); | 324 | memcpy(new_mpath->dst, dst, ETH_ALEN); |
285 | new_mpath->sdata = sdata; | 325 | new_mpath->sdata = sdata; |
286 | new_mpath->flags = 0; | 326 | new_mpath->flags = 0; |
@@ -295,7 +335,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
295 | hash_idx = mesh_table_hash(dst, sdata, mesh_paths); | 335 | hash_idx = mesh_table_hash(dst, sdata, mesh_paths); |
296 | bucket = &mesh_paths->hash_buckets[hash_idx]; | 336 | bucket = &mesh_paths->hash_buckets[hash_idx]; |
297 | 337 | ||
298 | spin_lock(&mesh_paths->hashwlock[hash_idx]); | 338 | spin_lock_bh(&mesh_paths->hashwlock[hash_idx]); |
299 | 339 | ||
300 | err = -EEXIST; | 340 | err = -EEXIST; |
301 | hlist_for_each_entry(node, n, bucket, list) { | 341 | hlist_for_each_entry(node, n, bucket, list) { |
@@ -311,8 +351,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
311 | 351 | ||
312 | mesh_paths_generation++; | 352 | mesh_paths_generation++; |
313 | 353 | ||
314 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | 354 | spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]); |
315 | read_unlock(&pathtbl_resize_lock); | 355 | read_unlock_bh(&pathtbl_resize_lock); |
316 | if (grow) { | 356 | if (grow) { |
317 | set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags); | 357 | set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags); |
318 | ieee80211_queue_work(&local->hw, &sdata->work); | 358 | ieee80211_queue_work(&local->hw, &sdata->work); |
@@ -320,8 +360,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
320 | return 0; | 360 | return 0; |
321 | 361 | ||
322 | err_exists: | 362 | err_exists: |
323 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | 363 | spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]); |
324 | read_unlock(&pathtbl_resize_lock); | 364 | read_unlock_bh(&pathtbl_resize_lock); |
325 | kfree(new_node); | 365 | kfree(new_node); |
326 | err_node_alloc: | 366 | err_node_alloc: |
327 | kfree(new_mpath); | 367 | kfree(new_mpath); |
@@ -334,15 +374,21 @@ void mesh_mpath_table_grow(void) | |||
334 | { | 374 | { |
335 | struct mesh_table *oldtbl, *newtbl; | 375 | struct mesh_table *oldtbl, *newtbl; |
336 | 376 | ||
337 | write_lock(&pathtbl_resize_lock); | 377 | rcu_read_lock(); |
378 | newtbl = mesh_table_alloc(rcu_dereference(mesh_paths)->size_order + 1); | ||
379 | if (!newtbl) | ||
380 | return; | ||
381 | write_lock_bh(&pathtbl_resize_lock); | ||
338 | oldtbl = mesh_paths; | 382 | oldtbl = mesh_paths; |
339 | newtbl = mesh_table_grow(mesh_paths); | 383 | if (mesh_table_grow(mesh_paths, newtbl) < 0) { |
340 | if (!newtbl) { | 384 | rcu_read_unlock(); |
341 | write_unlock(&pathtbl_resize_lock); | 385 | __mesh_table_free(newtbl); |
386 | write_unlock_bh(&pathtbl_resize_lock); | ||
342 | return; | 387 | return; |
343 | } | 388 | } |
389 | rcu_read_unlock(); | ||
344 | rcu_assign_pointer(mesh_paths, newtbl); | 390 | rcu_assign_pointer(mesh_paths, newtbl); |
345 | write_unlock(&pathtbl_resize_lock); | 391 | write_unlock_bh(&pathtbl_resize_lock); |
346 | 392 | ||
347 | synchronize_rcu(); | 393 | synchronize_rcu(); |
348 | mesh_table_free(oldtbl, false); | 394 | mesh_table_free(oldtbl, false); |
@@ -352,15 +398,21 @@ void mesh_mpp_table_grow(void) | |||
352 | { | 398 | { |
353 | struct mesh_table *oldtbl, *newtbl; | 399 | struct mesh_table *oldtbl, *newtbl; |
354 | 400 | ||
355 | write_lock(&pathtbl_resize_lock); | 401 | rcu_read_lock(); |
402 | newtbl = mesh_table_alloc(rcu_dereference(mpp_paths)->size_order + 1); | ||
403 | if (!newtbl) | ||
404 | return; | ||
405 | write_lock_bh(&pathtbl_resize_lock); | ||
356 | oldtbl = mpp_paths; | 406 | oldtbl = mpp_paths; |
357 | newtbl = mesh_table_grow(mpp_paths); | 407 | if (mesh_table_grow(mpp_paths, newtbl) < 0) { |
358 | if (!newtbl) { | 408 | rcu_read_unlock(); |
359 | write_unlock(&pathtbl_resize_lock); | 409 | __mesh_table_free(newtbl); |
410 | write_unlock_bh(&pathtbl_resize_lock); | ||
360 | return; | 411 | return; |
361 | } | 412 | } |
413 | rcu_read_unlock(); | ||
362 | rcu_assign_pointer(mpp_paths, newtbl); | 414 | rcu_assign_pointer(mpp_paths, newtbl); |
363 | write_unlock(&pathtbl_resize_lock); | 415 | write_unlock_bh(&pathtbl_resize_lock); |
364 | 416 | ||
365 | synchronize_rcu(); | 417 | synchronize_rcu(); |
366 | mesh_table_free(oldtbl, false); | 418 | mesh_table_free(oldtbl, false); |
@@ -394,7 +446,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
394 | if (!new_node) | 446 | if (!new_node) |
395 | goto err_node_alloc; | 447 | goto err_node_alloc; |
396 | 448 | ||
397 | read_lock(&pathtbl_resize_lock); | 449 | read_lock_bh(&pathtbl_resize_lock); |
398 | memcpy(new_mpath->dst, dst, ETH_ALEN); | 450 | memcpy(new_mpath->dst, dst, ETH_ALEN); |
399 | memcpy(new_mpath->mpp, mpp, ETH_ALEN); | 451 | memcpy(new_mpath->mpp, mpp, ETH_ALEN); |
400 | new_mpath->sdata = sdata; | 452 | new_mpath->sdata = sdata; |
@@ -407,7 +459,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
407 | hash_idx = mesh_table_hash(dst, sdata, mpp_paths); | 459 | hash_idx = mesh_table_hash(dst, sdata, mpp_paths); |
408 | bucket = &mpp_paths->hash_buckets[hash_idx]; | 460 | bucket = &mpp_paths->hash_buckets[hash_idx]; |
409 | 461 | ||
410 | spin_lock(&mpp_paths->hashwlock[hash_idx]); | 462 | spin_lock_bh(&mpp_paths->hashwlock[hash_idx]); |
411 | 463 | ||
412 | err = -EEXIST; | 464 | err = -EEXIST; |
413 | hlist_for_each_entry(node, n, bucket, list) { | 465 | hlist_for_each_entry(node, n, bucket, list) { |
@@ -421,8 +473,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
421 | mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1)) | 473 | mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1)) |
422 | grow = 1; | 474 | grow = 1; |
423 | 475 | ||
424 | spin_unlock(&mpp_paths->hashwlock[hash_idx]); | 476 | spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]); |
425 | read_unlock(&pathtbl_resize_lock); | 477 | read_unlock_bh(&pathtbl_resize_lock); |
426 | if (grow) { | 478 | if (grow) { |
427 | set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); | 479 | set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); |
428 | ieee80211_queue_work(&local->hw, &sdata->work); | 480 | ieee80211_queue_work(&local->hw, &sdata->work); |
@@ -430,8 +482,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
430 | return 0; | 482 | return 0; |
431 | 483 | ||
432 | err_exists: | 484 | err_exists: |
433 | spin_unlock(&mpp_paths->hashwlock[hash_idx]); | 485 | spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]); |
434 | read_unlock(&pathtbl_resize_lock); | 486 | read_unlock_bh(&pathtbl_resize_lock); |
435 | kfree(new_node); | 487 | kfree(new_node); |
436 | err_node_alloc: | 488 | err_node_alloc: |
437 | kfree(new_mpath); | 489 | kfree(new_mpath); |
@@ -544,11 +596,11 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) | |||
544 | int hash_idx; | 596 | int hash_idx; |
545 | int err = 0; | 597 | int err = 0; |
546 | 598 | ||
547 | read_lock(&pathtbl_resize_lock); | 599 | read_lock_bh(&pathtbl_resize_lock); |
548 | hash_idx = mesh_table_hash(addr, sdata, mesh_paths); | 600 | hash_idx = mesh_table_hash(addr, sdata, mesh_paths); |
549 | bucket = &mesh_paths->hash_buckets[hash_idx]; | 601 | bucket = &mesh_paths->hash_buckets[hash_idx]; |
550 | 602 | ||
551 | spin_lock(&mesh_paths->hashwlock[hash_idx]); | 603 | spin_lock_bh(&mesh_paths->hashwlock[hash_idx]); |
552 | hlist_for_each_entry(node, n, bucket, list) { | 604 | hlist_for_each_entry(node, n, bucket, list) { |
553 | mpath = node->mpath; | 605 | mpath = node->mpath; |
554 | if (mpath->sdata == sdata && | 606 | if (mpath->sdata == sdata && |
@@ -566,8 +618,8 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) | |||
566 | err = -ENXIO; | 618 | err = -ENXIO; |
567 | enddel: | 619 | enddel: |
568 | mesh_paths_generation++; | 620 | mesh_paths_generation++; |
569 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | 621 | spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]); |
570 | read_unlock(&pathtbl_resize_lock); | 622 | read_unlock_bh(&pathtbl_resize_lock); |
571 | return err; | 623 | return err; |
572 | } | 624 | } |
573 | 625 | ||
@@ -719,7 +771,7 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata) | |||
719 | struct hlist_node *p; | 771 | struct hlist_node *p; |
720 | int i; | 772 | int i; |
721 | 773 | ||
722 | read_lock(&pathtbl_resize_lock); | 774 | read_lock_bh(&pathtbl_resize_lock); |
723 | for_each_mesh_entry(mesh_paths, p, node, i) { | 775 | for_each_mesh_entry(mesh_paths, p, node, i) { |
724 | if (node->mpath->sdata != sdata) | 776 | if (node->mpath->sdata != sdata) |
725 | continue; | 777 | continue; |
@@ -734,7 +786,7 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata) | |||
734 | } else | 786 | } else |
735 | spin_unlock_bh(&mpath->state_lock); | 787 | spin_unlock_bh(&mpath->state_lock); |
736 | } | 788 | } |
737 | read_unlock(&pathtbl_resize_lock); | 789 | read_unlock_bh(&pathtbl_resize_lock); |
738 | } | 790 | } |
739 | 791 | ||
740 | void mesh_pathtbl_unregister(void) | 792 | void mesh_pathtbl_unregister(void) |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 44b53931ba5e..f4adc0917888 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -43,7 +43,7 @@ | |||
43 | #define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks) | 43 | #define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks) |
44 | 44 | ||
45 | enum plink_frame_type { | 45 | enum plink_frame_type { |
46 | PLINK_OPEN = 0, | 46 | PLINK_OPEN = 1, |
47 | PLINK_CONFIRM, | 47 | PLINK_CONFIRM, |
48 | PLINK_CLOSE | 48 | PLINK_CLOSE |
49 | }; | 49 | }; |
@@ -83,7 +83,7 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) | |||
83 | */ | 83 | */ |
84 | static inline void mesh_plink_fsm_restart(struct sta_info *sta) | 84 | static inline void mesh_plink_fsm_restart(struct sta_info *sta) |
85 | { | 85 | { |
86 | sta->plink_state = PLINK_LISTEN; | 86 | sta->plink_state = NL80211_PLINK_LISTEN; |
87 | sta->llid = sta->plid = sta->reason = 0; | 87 | sta->llid = sta->plid = sta->reason = 0; |
88 | sta->plink_retries = 0; | 88 | sta->plink_retries = 0; |
89 | } | 89 | } |
@@ -105,7 +105,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
105 | if (!sta) | 105 | if (!sta) |
106 | return NULL; | 106 | return NULL; |
107 | 107 | ||
108 | sta->flags = WLAN_STA_AUTHORIZED; | 108 | sta->flags = WLAN_STA_AUTHORIZED | WLAN_STA_AUTH; |
109 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; | 109 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; |
110 | rate_control_rate_init(sta); | 110 | rate_control_rate_init(sta); |
111 | 111 | ||
@@ -126,11 +126,11 @@ static bool __mesh_plink_deactivate(struct sta_info *sta) | |||
126 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 126 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
127 | bool deactivated = false; | 127 | bool deactivated = false; |
128 | 128 | ||
129 | if (sta->plink_state == PLINK_ESTAB) { | 129 | if (sta->plink_state == NL80211_PLINK_ESTAB) { |
130 | mesh_plink_dec_estab_count(sdata); | 130 | mesh_plink_dec_estab_count(sdata); |
131 | deactivated = true; | 131 | deactivated = true; |
132 | } | 132 | } |
133 | sta->plink_state = PLINK_BLOCKED; | 133 | sta->plink_state = NL80211_PLINK_BLOCKED; |
134 | mesh_path_flush_by_nexthop(sta); | 134 | mesh_path_flush_by_nexthop(sta); |
135 | 135 | ||
136 | return deactivated; | 136 | return deactivated; |
@@ -161,7 +161,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
161 | __le16 reason) { | 161 | __le16 reason) { |
162 | struct ieee80211_local *local = sdata->local; | 162 | struct ieee80211_local *local = sdata->local; |
163 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 + | 163 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 + |
164 | sdata->u.mesh.vendor_ie_len); | 164 | sdata->u.mesh.ie_len); |
165 | struct ieee80211_mgmt *mgmt; | 165 | struct ieee80211_mgmt *mgmt; |
166 | bool include_plid = false; | 166 | bool include_plid = false; |
167 | static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A }; | 167 | static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A }; |
@@ -181,8 +181,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
181 | IEEE80211_STYPE_ACTION); | 181 | IEEE80211_STYPE_ACTION); |
182 | memcpy(mgmt->da, da, ETH_ALEN); | 182 | memcpy(mgmt->da, da, ETH_ALEN); |
183 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | 183 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
184 | /* BSSID is left zeroed, wildcard value */ | 184 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); |
185 | mgmt->u.action.category = WLAN_CATEGORY_MESH_PLINK; | 185 | mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION; |
186 | mgmt->u.action.u.plink_action.action_code = action; | 186 | mgmt->u.action.u.plink_action.action_code = action; |
187 | 187 | ||
188 | if (action == PLINK_CLOSE) | 188 | if (action == PLINK_CLOSE) |
@@ -237,8 +237,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
237 | return 0; | 237 | return 0; |
238 | } | 238 | } |
239 | 239 | ||
240 | void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data *sdata, | 240 | void mesh_neighbour_update(u8 *hw_addr, u32 rates, |
241 | bool peer_accepting_plinks) | 241 | struct ieee80211_sub_if_data *sdata, |
242 | struct ieee802_11_elems *elems) | ||
242 | { | 243 | { |
243 | struct ieee80211_local *local = sdata->local; | 244 | struct ieee80211_local *local = sdata->local; |
244 | struct sta_info *sta; | 245 | struct sta_info *sta; |
@@ -248,8 +249,14 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data | |||
248 | sta = sta_info_get(sdata, hw_addr); | 249 | sta = sta_info_get(sdata, hw_addr); |
249 | if (!sta) { | 250 | if (!sta) { |
250 | rcu_read_unlock(); | 251 | rcu_read_unlock(); |
251 | 252 | /* Userspace handles peer allocation when security is enabled | |
252 | sta = mesh_plink_alloc(sdata, hw_addr, rates); | 253 | * */ |
254 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) | ||
255 | cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr, | ||
256 | elems->ie_start, elems->total_len, | ||
257 | GFP_KERNEL); | ||
258 | else | ||
259 | sta = mesh_plink_alloc(sdata, hw_addr, rates); | ||
253 | if (!sta) | 260 | if (!sta) |
254 | return; | 261 | return; |
255 | if (sta_info_insert_rcu(sta)) { | 262 | if (sta_info_insert_rcu(sta)) { |
@@ -260,7 +267,8 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data | |||
260 | 267 | ||
261 | sta->last_rx = jiffies; | 268 | sta->last_rx = jiffies; |
262 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; | 269 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; |
263 | if (peer_accepting_plinks && sta->plink_state == PLINK_LISTEN && | 270 | if (mesh_peer_accepts_plinks(elems) && |
271 | sta->plink_state == NL80211_PLINK_LISTEN && | ||
264 | sdata->u.mesh.accepting_plinks && | 272 | sdata->u.mesh.accepting_plinks && |
265 | sdata->u.mesh.mshcfg.auto_open_plinks) | 273 | sdata->u.mesh.mshcfg.auto_open_plinks) |
266 | mesh_plink_open(sta); | 274 | mesh_plink_open(sta); |
@@ -300,8 +308,8 @@ static void mesh_plink_timer(unsigned long data) | |||
300 | sdata = sta->sdata; | 308 | sdata = sta->sdata; |
301 | 309 | ||
302 | switch (sta->plink_state) { | 310 | switch (sta->plink_state) { |
303 | case PLINK_OPN_RCVD: | 311 | case NL80211_PLINK_OPN_RCVD: |
304 | case PLINK_OPN_SNT: | 312 | case NL80211_PLINK_OPN_SNT: |
305 | /* retry timer */ | 313 | /* retry timer */ |
306 | if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { | 314 | if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { |
307 | u32 rand; | 315 | u32 rand; |
@@ -320,17 +328,17 @@ static void mesh_plink_timer(unsigned long data) | |||
320 | } | 328 | } |
321 | reason = cpu_to_le16(MESH_MAX_RETRIES); | 329 | reason = cpu_to_le16(MESH_MAX_RETRIES); |
322 | /* fall through on else */ | 330 | /* fall through on else */ |
323 | case PLINK_CNF_RCVD: | 331 | case NL80211_PLINK_CNF_RCVD: |
324 | /* confirm timer */ | 332 | /* confirm timer */ |
325 | if (!reason) | 333 | if (!reason) |
326 | reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); | 334 | reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); |
327 | sta->plink_state = PLINK_HOLDING; | 335 | sta->plink_state = NL80211_PLINK_HOLDING; |
328 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | 336 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
329 | spin_unlock_bh(&sta->lock); | 337 | spin_unlock_bh(&sta->lock); |
330 | mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid, | 338 | mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid, |
331 | reason); | 339 | reason); |
332 | break; | 340 | break; |
333 | case PLINK_HOLDING: | 341 | case NL80211_PLINK_HOLDING: |
334 | /* holding timer */ | 342 | /* holding timer */ |
335 | del_timer(&sta->plink_timer); | 343 | del_timer(&sta->plink_timer); |
336 | mesh_plink_fsm_restart(sta); | 344 | mesh_plink_fsm_restart(sta); |
@@ -372,14 +380,17 @@ int mesh_plink_open(struct sta_info *sta) | |||
372 | __le16 llid; | 380 | __le16 llid; |
373 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 381 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
374 | 382 | ||
383 | if (!test_sta_flags(sta, WLAN_STA_AUTH)) | ||
384 | return -EPERM; | ||
385 | |||
375 | spin_lock_bh(&sta->lock); | 386 | spin_lock_bh(&sta->lock); |
376 | get_random_bytes(&llid, 2); | 387 | get_random_bytes(&llid, 2); |
377 | sta->llid = llid; | 388 | sta->llid = llid; |
378 | if (sta->plink_state != PLINK_LISTEN) { | 389 | if (sta->plink_state != NL80211_PLINK_LISTEN) { |
379 | spin_unlock_bh(&sta->lock); | 390 | spin_unlock_bh(&sta->lock); |
380 | return -EBUSY; | 391 | return -EBUSY; |
381 | } | 392 | } |
382 | sta->plink_state = PLINK_OPN_SNT; | 393 | sta->plink_state = NL80211_PLINK_OPN_SNT; |
383 | mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); | 394 | mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); |
384 | spin_unlock_bh(&sta->lock); | 395 | spin_unlock_bh(&sta->lock); |
385 | mpl_dbg("Mesh plink: starting establishment with %pM\n", | 396 | mpl_dbg("Mesh plink: starting establishment with %pM\n", |
@@ -396,7 +407,7 @@ void mesh_plink_block(struct sta_info *sta) | |||
396 | 407 | ||
397 | spin_lock_bh(&sta->lock); | 408 | spin_lock_bh(&sta->lock); |
398 | deactivated = __mesh_plink_deactivate(sta); | 409 | deactivated = __mesh_plink_deactivate(sta); |
399 | sta->plink_state = PLINK_BLOCKED; | 410 | sta->plink_state = NL80211_PLINK_BLOCKED; |
400 | spin_unlock_bh(&sta->lock); | 411 | spin_unlock_bh(&sta->lock); |
401 | 412 | ||
402 | if (deactivated) | 413 | if (deactivated) |
@@ -419,13 +430,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
419 | __le16 plid, llid, reason; | 430 | __le16 plid, llid, reason; |
420 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | 431 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG |
421 | static const char *mplstates[] = { | 432 | static const char *mplstates[] = { |
422 | [PLINK_LISTEN] = "LISTEN", | 433 | [NL80211_PLINK_LISTEN] = "LISTEN", |
423 | [PLINK_OPN_SNT] = "OPN-SNT", | 434 | [NL80211_PLINK_OPN_SNT] = "OPN-SNT", |
424 | [PLINK_OPN_RCVD] = "OPN-RCVD", | 435 | [NL80211_PLINK_OPN_RCVD] = "OPN-RCVD", |
425 | [PLINK_CNF_RCVD] = "CNF_RCVD", | 436 | [NL80211_PLINK_CNF_RCVD] = "CNF_RCVD", |
426 | [PLINK_ESTAB] = "ESTAB", | 437 | [NL80211_PLINK_ESTAB] = "ESTAB", |
427 | [PLINK_HOLDING] = "HOLDING", | 438 | [NL80211_PLINK_HOLDING] = "HOLDING", |
428 | [PLINK_BLOCKED] = "BLOCKED" | 439 | [NL80211_PLINK_BLOCKED] = "BLOCKED" |
429 | }; | 440 | }; |
430 | #endif | 441 | #endif |
431 | 442 | ||
@@ -449,6 +460,11 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
449 | mpl_dbg("Mesh plink: missing necessary peer link ie\n"); | 460 | mpl_dbg("Mesh plink: missing necessary peer link ie\n"); |
450 | return; | 461 | return; |
451 | } | 462 | } |
463 | if (elems.rsn_len && | ||
464 | sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { | ||
465 | mpl_dbg("Mesh plink: can't establish link with secure peer\n"); | ||
466 | return; | ||
467 | } | ||
452 | 468 | ||
453 | ftype = mgmt->u.action.u.plink_action.action_code; | 469 | ftype = mgmt->u.action.u.plink_action.action_code; |
454 | ie_len = elems.peer_link_len; | 470 | ie_len = elems.peer_link_len; |
@@ -480,7 +496,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
480 | return; | 496 | return; |
481 | } | 497 | } |
482 | 498 | ||
483 | if (sta && sta->plink_state == PLINK_BLOCKED) { | 499 | if (sta && !test_sta_flags(sta, WLAN_STA_AUTH)) { |
500 | mpl_dbg("Mesh plink: Action frame from non-authed peer\n"); | ||
501 | rcu_read_unlock(); | ||
502 | return; | ||
503 | } | ||
504 | |||
505 | if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) { | ||
484 | rcu_read_unlock(); | 506 | rcu_read_unlock(); |
485 | return; | 507 | return; |
486 | } | 508 | } |
@@ -550,7 +572,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
550 | event = CNF_ACPT; | 572 | event = CNF_ACPT; |
551 | break; | 573 | break; |
552 | case PLINK_CLOSE: | 574 | case PLINK_CLOSE: |
553 | if (sta->plink_state == PLINK_ESTAB) | 575 | if (sta->plink_state == NL80211_PLINK_ESTAB) |
554 | /* Do not check for llid or plid. This does not | 576 | /* Do not check for llid or plid. This does not |
555 | * follow the standard but since multiple plinks | 577 | * follow the standard but since multiple plinks |
556 | * per sta are not supported, it is necessary in | 578 | * per sta are not supported, it is necessary in |
@@ -585,14 +607,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
585 | reason = 0; | 607 | reason = 0; |
586 | switch (sta->plink_state) { | 608 | switch (sta->plink_state) { |
587 | /* spin_unlock as soon as state is updated at each case */ | 609 | /* spin_unlock as soon as state is updated at each case */ |
588 | case PLINK_LISTEN: | 610 | case NL80211_PLINK_LISTEN: |
589 | switch (event) { | 611 | switch (event) { |
590 | case CLS_ACPT: | 612 | case CLS_ACPT: |
591 | mesh_plink_fsm_restart(sta); | 613 | mesh_plink_fsm_restart(sta); |
592 | spin_unlock_bh(&sta->lock); | 614 | spin_unlock_bh(&sta->lock); |
593 | break; | 615 | break; |
594 | case OPN_ACPT: | 616 | case OPN_ACPT: |
595 | sta->plink_state = PLINK_OPN_RCVD; | 617 | sta->plink_state = NL80211_PLINK_OPN_RCVD; |
596 | sta->plid = plid; | 618 | sta->plid = plid; |
597 | get_random_bytes(&llid, 2); | 619 | get_random_bytes(&llid, 2); |
598 | sta->llid = llid; | 620 | sta->llid = llid; |
@@ -609,7 +631,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
609 | } | 631 | } |
610 | break; | 632 | break; |
611 | 633 | ||
612 | case PLINK_OPN_SNT: | 634 | case NL80211_PLINK_OPN_SNT: |
613 | switch (event) { | 635 | switch (event) { |
614 | case OPN_RJCT: | 636 | case OPN_RJCT: |
615 | case CNF_RJCT: | 637 | case CNF_RJCT: |
@@ -618,7 +640,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
618 | if (!reason) | 640 | if (!reason) |
619 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | 641 | reason = cpu_to_le16(MESH_CLOSE_RCVD); |
620 | sta->reason = reason; | 642 | sta->reason = reason; |
621 | sta->plink_state = PLINK_HOLDING; | 643 | sta->plink_state = NL80211_PLINK_HOLDING; |
622 | if (!mod_plink_timer(sta, | 644 | if (!mod_plink_timer(sta, |
623 | dot11MeshHoldingTimeout(sdata))) | 645 | dot11MeshHoldingTimeout(sdata))) |
624 | sta->ignore_plink_timer = true; | 646 | sta->ignore_plink_timer = true; |
@@ -630,7 +652,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
630 | break; | 652 | break; |
631 | case OPN_ACPT: | 653 | case OPN_ACPT: |
632 | /* retry timer is left untouched */ | 654 | /* retry timer is left untouched */ |
633 | sta->plink_state = PLINK_OPN_RCVD; | 655 | sta->plink_state = NL80211_PLINK_OPN_RCVD; |
634 | sta->plid = plid; | 656 | sta->plid = plid; |
635 | llid = sta->llid; | 657 | llid = sta->llid; |
636 | spin_unlock_bh(&sta->lock); | 658 | spin_unlock_bh(&sta->lock); |
@@ -638,7 +660,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
638 | plid, 0); | 660 | plid, 0); |
639 | break; | 661 | break; |
640 | case CNF_ACPT: | 662 | case CNF_ACPT: |
641 | sta->plink_state = PLINK_CNF_RCVD; | 663 | sta->plink_state = NL80211_PLINK_CNF_RCVD; |
642 | if (!mod_plink_timer(sta, | 664 | if (!mod_plink_timer(sta, |
643 | dot11MeshConfirmTimeout(sdata))) | 665 | dot11MeshConfirmTimeout(sdata))) |
644 | sta->ignore_plink_timer = true; | 666 | sta->ignore_plink_timer = true; |
@@ -651,7 +673,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
651 | } | 673 | } |
652 | break; | 674 | break; |
653 | 675 | ||
654 | case PLINK_OPN_RCVD: | 676 | case NL80211_PLINK_OPN_RCVD: |
655 | switch (event) { | 677 | switch (event) { |
656 | case OPN_RJCT: | 678 | case OPN_RJCT: |
657 | case CNF_RJCT: | 679 | case CNF_RJCT: |
@@ -660,7 +682,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
660 | if (!reason) | 682 | if (!reason) |
661 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | 683 | reason = cpu_to_le16(MESH_CLOSE_RCVD); |
662 | sta->reason = reason; | 684 | sta->reason = reason; |
663 | sta->plink_state = PLINK_HOLDING; | 685 | sta->plink_state = NL80211_PLINK_HOLDING; |
664 | if (!mod_plink_timer(sta, | 686 | if (!mod_plink_timer(sta, |
665 | dot11MeshHoldingTimeout(sdata))) | 687 | dot11MeshHoldingTimeout(sdata))) |
666 | sta->ignore_plink_timer = true; | 688 | sta->ignore_plink_timer = true; |
@@ -678,7 +700,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
678 | break; | 700 | break; |
679 | case CNF_ACPT: | 701 | case CNF_ACPT: |
680 | del_timer(&sta->plink_timer); | 702 | del_timer(&sta->plink_timer); |
681 | sta->plink_state = PLINK_ESTAB; | 703 | sta->plink_state = NL80211_PLINK_ESTAB; |
682 | spin_unlock_bh(&sta->lock); | 704 | spin_unlock_bh(&sta->lock); |
683 | mesh_plink_inc_estab_count(sdata); | 705 | mesh_plink_inc_estab_count(sdata); |
684 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 706 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); |
@@ -691,7 +713,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
691 | } | 713 | } |
692 | break; | 714 | break; |
693 | 715 | ||
694 | case PLINK_CNF_RCVD: | 716 | case NL80211_PLINK_CNF_RCVD: |
695 | switch (event) { | 717 | switch (event) { |
696 | case OPN_RJCT: | 718 | case OPN_RJCT: |
697 | case CNF_RJCT: | 719 | case CNF_RJCT: |
@@ -700,7 +722,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
700 | if (!reason) | 722 | if (!reason) |
701 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | 723 | reason = cpu_to_le16(MESH_CLOSE_RCVD); |
702 | sta->reason = reason; | 724 | sta->reason = reason; |
703 | sta->plink_state = PLINK_HOLDING; | 725 | sta->plink_state = NL80211_PLINK_HOLDING; |
704 | if (!mod_plink_timer(sta, | 726 | if (!mod_plink_timer(sta, |
705 | dot11MeshHoldingTimeout(sdata))) | 727 | dot11MeshHoldingTimeout(sdata))) |
706 | sta->ignore_plink_timer = true; | 728 | sta->ignore_plink_timer = true; |
@@ -712,7 +734,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
712 | break; | 734 | break; |
713 | case OPN_ACPT: | 735 | case OPN_ACPT: |
714 | del_timer(&sta->plink_timer); | 736 | del_timer(&sta->plink_timer); |
715 | sta->plink_state = PLINK_ESTAB; | 737 | sta->plink_state = NL80211_PLINK_ESTAB; |
716 | spin_unlock_bh(&sta->lock); | 738 | spin_unlock_bh(&sta->lock); |
717 | mesh_plink_inc_estab_count(sdata); | 739 | mesh_plink_inc_estab_count(sdata); |
718 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 740 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); |
@@ -727,13 +749,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
727 | } | 749 | } |
728 | break; | 750 | break; |
729 | 751 | ||
730 | case PLINK_ESTAB: | 752 | case NL80211_PLINK_ESTAB: |
731 | switch (event) { | 753 | switch (event) { |
732 | case CLS_ACPT: | 754 | case CLS_ACPT: |
733 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | 755 | reason = cpu_to_le16(MESH_CLOSE_RCVD); |
734 | sta->reason = reason; | 756 | sta->reason = reason; |
735 | deactivated = __mesh_plink_deactivate(sta); | 757 | deactivated = __mesh_plink_deactivate(sta); |
736 | sta->plink_state = PLINK_HOLDING; | 758 | sta->plink_state = NL80211_PLINK_HOLDING; |
737 | llid = sta->llid; | 759 | llid = sta->llid; |
738 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | 760 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
739 | spin_unlock_bh(&sta->lock); | 761 | spin_unlock_bh(&sta->lock); |
@@ -753,7 +775,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
753 | break; | 775 | break; |
754 | } | 776 | } |
755 | break; | 777 | break; |
756 | case PLINK_HOLDING: | 778 | case NL80211_PLINK_HOLDING: |
757 | switch (event) { | 779 | switch (event) { |
758 | case CLS_ACPT: | 780 | case CLS_ACPT: |
759 | if (del_timer(&sta->plink_timer)) | 781 | if (del_timer(&sta->plink_timer)) |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 64d92d5a7f40..4f6b2675e41d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -90,20 +90,11 @@ enum rx_mgmt_action { | |||
90 | /* no action required */ | 90 | /* no action required */ |
91 | RX_MGMT_NONE, | 91 | RX_MGMT_NONE, |
92 | 92 | ||
93 | /* caller must call cfg80211_send_rx_auth() */ | ||
94 | RX_MGMT_CFG80211_AUTH, | ||
95 | |||
96 | /* caller must call cfg80211_send_rx_assoc() */ | ||
97 | RX_MGMT_CFG80211_ASSOC, | ||
98 | |||
99 | /* caller must call cfg80211_send_deauth() */ | 93 | /* caller must call cfg80211_send_deauth() */ |
100 | RX_MGMT_CFG80211_DEAUTH, | 94 | RX_MGMT_CFG80211_DEAUTH, |
101 | 95 | ||
102 | /* caller must call cfg80211_send_disassoc() */ | 96 | /* caller must call cfg80211_send_disassoc() */ |
103 | RX_MGMT_CFG80211_DISASSOC, | 97 | RX_MGMT_CFG80211_DISASSOC, |
104 | |||
105 | /* caller must tell cfg80211 about internal error */ | ||
106 | RX_MGMT_CFG80211_ASSOC_ERROR, | ||
107 | }; | 98 | }; |
108 | 99 | ||
109 | /* utils */ | 100 | /* utils */ |
@@ -759,6 +750,8 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
759 | dynamic_ps_enable_work); | 750 | dynamic_ps_enable_work); |
760 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; | 751 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; |
761 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 752 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
753 | unsigned long flags; | ||
754 | int q; | ||
762 | 755 | ||
763 | /* can only happen when PS was just disabled anyway */ | 756 | /* can only happen when PS was just disabled anyway */ |
764 | if (!sdata) | 757 | if (!sdata) |
@@ -767,18 +760,37 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
767 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | 760 | if (local->hw.conf.flags & IEEE80211_CONF_PS) |
768 | return; | 761 | return; |
769 | 762 | ||
763 | /* | ||
764 | * transmission can be stopped by others which leads to | ||
765 | * dynamic_ps_timer expiry. Postpond the ps timer if it | ||
766 | * is not the actual idle state. | ||
767 | */ | ||
768 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
769 | for (q = 0; q < local->hw.queues; q++) { | ||
770 | if (local->queue_stop_reasons[q]) { | ||
771 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, | ||
772 | flags); | ||
773 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
774 | msecs_to_jiffies( | ||
775 | local->hw.conf.dynamic_ps_timeout)); | ||
776 | return; | ||
777 | } | ||
778 | } | ||
779 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
780 | |||
770 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && | 781 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && |
771 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { | 782 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { |
772 | netif_tx_stop_all_queues(sdata->dev); | 783 | netif_tx_stop_all_queues(sdata->dev); |
773 | /* | ||
774 | * Flush all the frames queued in the driver before | ||
775 | * going to power save | ||
776 | */ | ||
777 | drv_flush(local, false); | ||
778 | ieee80211_send_nullfunc(local, sdata, 1); | ||
779 | 784 | ||
780 | /* Flush once again to get the tx status of nullfunc frame */ | 785 | if (drv_tx_frames_pending(local)) |
781 | drv_flush(local, false); | 786 | mod_timer(&local->dynamic_ps_timer, jiffies + |
787 | msecs_to_jiffies( | ||
788 | local->hw.conf.dynamic_ps_timeout)); | ||
789 | else { | ||
790 | ieee80211_send_nullfunc(local, sdata, 1); | ||
791 | /* Flush to get the tx status of nullfunc frame */ | ||
792 | drv_flush(local, false); | ||
793 | } | ||
782 | } | 794 | } |
783 | 795 | ||
784 | if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && | 796 | if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && |
@@ -789,7 +801,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
789 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 801 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
790 | } | 802 | } |
791 | 803 | ||
792 | netif_tx_start_all_queues(sdata->dev); | 804 | netif_tx_wake_all_queues(sdata->dev); |
793 | } | 805 | } |
794 | 806 | ||
795 | void ieee80211_dynamic_ps_timer(unsigned long data) | 807 | void ieee80211_dynamic_ps_timer(unsigned long data) |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index e37355193ed1..730778a2c90c 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -6,7 +6,7 @@ | |||
6 | #include "driver-ops.h" | 6 | #include "driver-ops.h" |
7 | #include "led.h" | 7 | #include "led.h" |
8 | 8 | ||
9 | int __ieee80211_suspend(struct ieee80211_hw *hw) | 9 | int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) |
10 | { | 10 | { |
11 | struct ieee80211_local *local = hw_to_local(hw); | 11 | struct ieee80211_local *local = hw_to_local(hw); |
12 | struct ieee80211_sub_if_data *sdata; | 12 | struct ieee80211_sub_if_data *sdata; |
@@ -14,12 +14,23 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
14 | 14 | ||
15 | ieee80211_scan_cancel(local); | 15 | ieee80211_scan_cancel(local); |
16 | 16 | ||
17 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
18 | mutex_lock(&local->sta_mtx); | ||
19 | list_for_each_entry(sta, &local->sta_list, list) { | ||
20 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); | ||
21 | ieee80211_sta_tear_down_BA_sessions(sta, true); | ||
22 | } | ||
23 | mutex_unlock(&local->sta_mtx); | ||
24 | } | ||
25 | |||
17 | ieee80211_stop_queues_by_reason(hw, | 26 | ieee80211_stop_queues_by_reason(hw, |
18 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 27 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
19 | 28 | ||
20 | /* flush out all packets */ | 29 | /* flush out all packets */ |
21 | synchronize_net(); | 30 | synchronize_net(); |
22 | 31 | ||
32 | drv_flush(local, false); | ||
33 | |||
23 | local->quiescing = true; | 34 | local->quiescing = true; |
24 | /* make quiescing visible to timers everywhere */ | 35 | /* make quiescing visible to timers everywhere */ |
25 | mb(); | 36 | mb(); |
@@ -36,6 +47,16 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
36 | cancel_work_sync(&local->dynamic_ps_enable_work); | 47 | cancel_work_sync(&local->dynamic_ps_enable_work); |
37 | del_timer_sync(&local->dynamic_ps_timer); | 48 | del_timer_sync(&local->dynamic_ps_timer); |
38 | 49 | ||
50 | local->wowlan = wowlan && local->open_count; | ||
51 | if (local->wowlan) { | ||
52 | int err = drv_suspend(local, wowlan); | ||
53 | if (err) { | ||
54 | local->quiescing = false; | ||
55 | return err; | ||
56 | } | ||
57 | goto suspend; | ||
58 | } | ||
59 | |||
39 | /* disable keys */ | 60 | /* disable keys */ |
40 | list_for_each_entry(sdata, &local->interfaces, list) | 61 | list_for_each_entry(sdata, &local->interfaces, list) |
41 | ieee80211_disable_keys(sdata); | 62 | ieee80211_disable_keys(sdata); |
@@ -43,11 +64,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
43 | /* tear down aggregation sessions and remove STAs */ | 64 | /* tear down aggregation sessions and remove STAs */ |
44 | mutex_lock(&local->sta_mtx); | 65 | mutex_lock(&local->sta_mtx); |
45 | list_for_each_entry(sta, &local->sta_list, list) { | 66 | list_for_each_entry(sta, &local->sta_list, list) { |
46 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
47 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); | ||
48 | ieee80211_sta_tear_down_BA_sessions(sta, true); | ||
49 | } | ||
50 | |||
51 | if (sta->uploaded) { | 67 | if (sta->uploaded) { |
52 | sdata = sta->sdata; | 68 | sdata = sta->sdata; |
53 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 69 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
@@ -98,6 +114,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
98 | if (local->open_count) | 114 | if (local->open_count) |
99 | ieee80211_stop_device(local); | 115 | ieee80211_stop_device(local); |
100 | 116 | ||
117 | suspend: | ||
101 | local->suspended = true; | 118 | local->suspended = true; |
102 | /* need suspended to be visible before quiescing is false */ | 119 | /* need suspended to be visible before quiescing is false */ |
103 | barrier(); | 120 | barrier(); |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 778c604d7939..8adac67395f7 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -417,8 +417,8 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, | |||
417 | tx_time_single = mr->ack_time + mr->perfect_tx_time; | 417 | tx_time_single = mr->ack_time + mr->perfect_tx_time; |
418 | 418 | ||
419 | /* contention window */ | 419 | /* contention window */ |
420 | tx_time_single += t_slot + min(cw, mp->cw_max); | 420 | tx_time_single += (t_slot * cw) >> 1; |
421 | cw = (cw << 1) | 1; | 421 | cw = min((cw << 1) | 1, mp->cw_max); |
422 | 422 | ||
423 | tx_time += tx_time_single; | 423 | tx_time += tx_time_single; |
424 | tx_time_cts += tx_time_single + mi->sp_ack_dur; | 424 | tx_time_cts += tx_time_single + mi->sp_ack_dur; |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index c06aa3ac6b9d..333b5118be6d 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -464,6 +464,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
464 | const struct mcs_group *group; | 464 | const struct mcs_group *group; |
465 | unsigned int tx_time, tx_time_rtscts, tx_time_data; | 465 | unsigned int tx_time, tx_time_rtscts, tx_time_data; |
466 | unsigned int cw = mp->cw_min; | 466 | unsigned int cw = mp->cw_min; |
467 | unsigned int ctime = 0; | ||
467 | unsigned int t_slot = 9; /* FIXME */ | 468 | unsigned int t_slot = 9; /* FIXME */ |
468 | unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); | 469 | unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); |
469 | 470 | ||
@@ -480,13 +481,27 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
480 | 481 | ||
481 | group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; | 482 | group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; |
482 | tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len; | 483 | tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len; |
483 | tx_time = 2 * (t_slot + mi->overhead + tx_time_data); | 484 | |
484 | tx_time_rtscts = 2 * (t_slot + mi->overhead_rtscts + tx_time_data); | 485 | /* Contention time for first 2 tries */ |
486 | ctime = (t_slot * cw) >> 1; | ||
487 | cw = min((cw << 1) | 1, mp->cw_max); | ||
488 | ctime += (t_slot * cw) >> 1; | ||
489 | cw = min((cw << 1) | 1, mp->cw_max); | ||
490 | |||
491 | /* Total TX time for data and Contention after first 2 tries */ | ||
492 | tx_time = ctime + 2 * (mi->overhead + tx_time_data); | ||
493 | tx_time_rtscts = ctime + 2 * (mi->overhead_rtscts + tx_time_data); | ||
494 | |||
495 | /* See how many more tries we can fit inside segment size */ | ||
485 | do { | 496 | do { |
486 | cw = (cw << 1) | 1; | 497 | /* Contention time for this try */ |
487 | cw = min(cw, mp->cw_max); | 498 | ctime = (t_slot * cw) >> 1; |
488 | tx_time += cw + t_slot + mi->overhead; | 499 | cw = min((cw << 1) | 1, mp->cw_max); |
489 | tx_time_rtscts += cw + t_slot + mi->overhead_rtscts; | 500 | |
501 | /* Total TX time after this try */ | ||
502 | tx_time += ctime + mi->overhead + tx_time_data; | ||
503 | tx_time_rtscts += ctime + mi->overhead_rtscts + tx_time_data; | ||
504 | |||
490 | if (tx_time_rtscts < mp->segment_size) | 505 | if (tx_time_rtscts < mp->segment_size) |
491 | mr->retry_count_rtscts++; | 506 | mr->retry_count_rtscts++; |
492 | } while ((tx_time < mp->segment_size) && | 507 | } while ((tx_time < mp->segment_size) && |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c5d4530d8284..7fa8c6be7bf0 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -143,7 +143,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
143 | if (status->flag & RX_FLAG_HT) { | 143 | if (status->flag & RX_FLAG_HT) { |
144 | /* | 144 | /* |
145 | * MCS information is a separate field in radiotap, | 145 | * MCS information is a separate field in radiotap, |
146 | * added below. | 146 | * added below. The byte here is needed as padding |
147 | * for the channel though, so initialise it to 0. | ||
147 | */ | 148 | */ |
148 | *pos = 0; | 149 | *pos = 0; |
149 | } else { | 150 | } else { |
@@ -403,11 +404,13 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) | |||
403 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | 404 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
404 | struct sk_buff *skb = rx->skb; | 405 | struct sk_buff *skb = rx->skb; |
405 | 406 | ||
406 | if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN))) | 407 | if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN) && |
408 | !local->sched_scanning)) | ||
407 | return RX_CONTINUE; | 409 | return RX_CONTINUE; |
408 | 410 | ||
409 | if (test_bit(SCAN_HW_SCANNING, &local->scanning) || | 411 | if (test_bit(SCAN_HW_SCANNING, &local->scanning) || |
410 | test_bit(SCAN_SW_SCANNING, &local->scanning)) | 412 | test_bit(SCAN_SW_SCANNING, &local->scanning) || |
413 | local->sched_scanning) | ||
411 | return ieee80211_scan_rx(rx->sdata, skb); | 414 | return ieee80211_scan_rx(rx->sdata, skb); |
412 | 415 | ||
413 | /* scanning finished during invoking of handlers */ | 416 | /* scanning finished during invoking of handlers */ |
@@ -487,22 +490,26 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
487 | * establisment frame, beacon or probe, drop the frame. | 490 | * establisment frame, beacon or probe, drop the frame. |
488 | */ | 491 | */ |
489 | 492 | ||
490 | if (!rx->sta || sta_plink_state(rx->sta) != PLINK_ESTAB) { | 493 | if (!rx->sta || sta_plink_state(rx->sta) != NL80211_PLINK_ESTAB) { |
491 | struct ieee80211_mgmt *mgmt; | 494 | struct ieee80211_mgmt *mgmt; |
492 | 495 | ||
493 | if (!ieee80211_is_mgmt(hdr->frame_control)) | 496 | if (!ieee80211_is_mgmt(hdr->frame_control)) |
494 | return RX_DROP_MONITOR; | 497 | return RX_DROP_MONITOR; |
495 | 498 | ||
496 | if (ieee80211_is_action(hdr->frame_control)) { | 499 | if (ieee80211_is_action(hdr->frame_control)) { |
500 | u8 category; | ||
497 | mgmt = (struct ieee80211_mgmt *)hdr; | 501 | mgmt = (struct ieee80211_mgmt *)hdr; |
498 | if (mgmt->u.action.category != WLAN_CATEGORY_MESH_PLINK) | 502 | category = mgmt->u.action.category; |
503 | if (category != WLAN_CATEGORY_MESH_ACTION && | ||
504 | category != WLAN_CATEGORY_SELF_PROTECTED) | ||
499 | return RX_DROP_MONITOR; | 505 | return RX_DROP_MONITOR; |
500 | return RX_CONTINUE; | 506 | return RX_CONTINUE; |
501 | } | 507 | } |
502 | 508 | ||
503 | if (ieee80211_is_probe_req(hdr->frame_control) || | 509 | if (ieee80211_is_probe_req(hdr->frame_control) || |
504 | ieee80211_is_probe_resp(hdr->frame_control) || | 510 | ieee80211_is_probe_resp(hdr->frame_control) || |
505 | ieee80211_is_beacon(hdr->frame_control)) | 511 | ieee80211_is_beacon(hdr->frame_control) || |
512 | ieee80211_is_auth(hdr->frame_control)) | ||
506 | return RX_CONTINUE; | 513 | return RX_CONTINUE; |
507 | 514 | ||
508 | return RX_DROP_MONITOR; | 515 | return RX_DROP_MONITOR; |
@@ -650,7 +657,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, | |||
650 | set_release_timer: | 657 | set_release_timer: |
651 | 658 | ||
652 | mod_timer(&tid_agg_rx->reorder_timer, | 659 | mod_timer(&tid_agg_rx->reorder_timer, |
653 | tid_agg_rx->reorder_time[j] + | 660 | tid_agg_rx->reorder_time[j] + 1 + |
654 | HT_RX_REORDER_BUF_TIMEOUT); | 661 | HT_RX_REORDER_BUF_TIMEOUT); |
655 | } else { | 662 | } else { |
656 | del_timer(&tid_agg_rx->reorder_timer); | 663 | del_timer(&tid_agg_rx->reorder_timer); |
@@ -707,6 +714,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
707 | /* | 714 | /* |
708 | * If the current MPDU is in the right order and nothing else | 715 | * If the current MPDU is in the right order and nothing else |
709 | * is stored we can process it directly, no need to buffer it. | 716 | * is stored we can process it directly, no need to buffer it. |
717 | * If it is first but there's something stored, we may be able | ||
718 | * to release frames after this one. | ||
710 | */ | 719 | */ |
711 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && | 720 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && |
712 | tid_agg_rx->stored_mpdu_num == 0) { | 721 | tid_agg_rx->stored_mpdu_num == 0) { |
@@ -1583,7 +1592,7 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) | |||
1583 | } | 1592 | } |
1584 | 1593 | ||
1585 | static int | 1594 | static int |
1586 | __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) | 1595 | __ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control) |
1587 | { | 1596 | { |
1588 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 1597 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
1589 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1598 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
@@ -1591,6 +1600,7 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) | |||
1591 | struct ethhdr *ehdr; | 1600 | struct ethhdr *ehdr; |
1592 | int ret; | 1601 | int ret; |
1593 | 1602 | ||
1603 | *port_control = false; | ||
1594 | if (ieee80211_has_a4(hdr->frame_control) && | 1604 | if (ieee80211_has_a4(hdr->frame_control) && |
1595 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta) | 1605 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta) |
1596 | return -1; | 1606 | return -1; |
@@ -1609,11 +1619,13 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) | |||
1609 | return -1; | 1619 | return -1; |
1610 | 1620 | ||
1611 | ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type); | 1621 | ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type); |
1612 | if (ret < 0 || !check_port_control) | 1622 | if (ret < 0) |
1613 | return ret; | 1623 | return ret; |
1614 | 1624 | ||
1615 | ehdr = (struct ethhdr *) rx->skb->data; | 1625 | ehdr = (struct ethhdr *) rx->skb->data; |
1616 | if (ehdr->h_proto != rx->sdata->control_port_protocol) | 1626 | if (ehdr->h_proto == rx->sdata->control_port_protocol) |
1627 | *port_control = true; | ||
1628 | else if (check_port_control) | ||
1617 | return -1; | 1629 | return -1; |
1618 | 1630 | ||
1619 | return 0; | 1631 | return 0; |
@@ -1771,7 +1783,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | |||
1771 | 1783 | ||
1772 | ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, | 1784 | ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, |
1773 | rx->sdata->vif.type, | 1785 | rx->sdata->vif.type, |
1774 | rx->local->hw.extra_tx_headroom); | 1786 | rx->local->hw.extra_tx_headroom, true); |
1775 | 1787 | ||
1776 | while (!skb_queue_empty(&frame_list)) { | 1788 | while (!skb_queue_empty(&frame_list)) { |
1777 | rx->skb = __skb_dequeue(&frame_list); | 1789 | rx->skb = __skb_dequeue(&frame_list); |
@@ -1914,6 +1926,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
1914 | struct net_device *dev = sdata->dev; | 1926 | struct net_device *dev = sdata->dev; |
1915 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1927 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
1916 | __le16 fc = hdr->frame_control; | 1928 | __le16 fc = hdr->frame_control; |
1929 | bool port_control; | ||
1917 | int err; | 1930 | int err; |
1918 | 1931 | ||
1919 | if (unlikely(!ieee80211_is_data(hdr->frame_control))) | 1932 | if (unlikely(!ieee80211_is_data(hdr->frame_control))) |
@@ -1930,13 +1943,21 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
1930 | sdata->vif.type == NL80211_IFTYPE_AP) | 1943 | sdata->vif.type == NL80211_IFTYPE_AP) |
1931 | return RX_DROP_MONITOR; | 1944 | return RX_DROP_MONITOR; |
1932 | 1945 | ||
1933 | err = __ieee80211_data_to_8023(rx); | 1946 | err = __ieee80211_data_to_8023(rx, &port_control); |
1934 | if (unlikely(err)) | 1947 | if (unlikely(err)) |
1935 | return RX_DROP_UNUSABLE; | 1948 | return RX_DROP_UNUSABLE; |
1936 | 1949 | ||
1937 | if (!ieee80211_frame_allowed(rx, fc)) | 1950 | if (!ieee80211_frame_allowed(rx, fc)) |
1938 | return RX_DROP_MONITOR; | 1951 | return RX_DROP_MONITOR; |
1939 | 1952 | ||
1953 | if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | ||
1954 | unlikely(port_control) && sdata->bss) { | ||
1955 | sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, | ||
1956 | u.ap); | ||
1957 | dev = sdata->dev; | ||
1958 | rx->sdata = sdata; | ||
1959 | } | ||
1960 | |||
1940 | rx->skb->dev = dev; | 1961 | rx->skb->dev = dev; |
1941 | 1962 | ||
1942 | dev->stats.rx_packets++; | 1963 | dev->stats.rx_packets++; |
@@ -2189,7 +2210,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2189 | goto handled; | 2210 | goto handled; |
2190 | } | 2211 | } |
2191 | break; | 2212 | break; |
2192 | case WLAN_CATEGORY_MESH_PLINK: | 2213 | case WLAN_CATEGORY_MESH_ACTION: |
2193 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | 2214 | if (!ieee80211_vif_is_mesh(&sdata->vif)) |
2194 | break; | 2215 | break; |
2195 | goto queue; | 2216 | goto queue; |
@@ -2352,47 +2373,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
2352 | return RX_QUEUED; | 2373 | return RX_QUEUED; |
2353 | } | 2374 | } |
2354 | 2375 | ||
2355 | static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr, | ||
2356 | struct ieee80211_rx_data *rx) | ||
2357 | { | ||
2358 | int keyidx; | ||
2359 | unsigned int hdrlen; | ||
2360 | |||
2361 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
2362 | if (rx->skb->len >= hdrlen + 4) | ||
2363 | keyidx = rx->skb->data[hdrlen + 3] >> 6; | ||
2364 | else | ||
2365 | keyidx = -1; | ||
2366 | |||
2367 | if (!rx->sta) { | ||
2368 | /* | ||
2369 | * Some hardware seem to generate incorrect Michael MIC | ||
2370 | * reports; ignore them to avoid triggering countermeasures. | ||
2371 | */ | ||
2372 | return; | ||
2373 | } | ||
2374 | |||
2375 | if (!ieee80211_has_protected(hdr->frame_control)) | ||
2376 | return; | ||
2377 | |||
2378 | if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) { | ||
2379 | /* | ||
2380 | * APs with pairwise keys should never receive Michael MIC | ||
2381 | * errors for non-zero keyidx because these are reserved for | ||
2382 | * group keys and only the AP is sending real multicast | ||
2383 | * frames in the BSS. | ||
2384 | */ | ||
2385 | return; | ||
2386 | } | ||
2387 | |||
2388 | if (!ieee80211_is_data(hdr->frame_control) && | ||
2389 | !ieee80211_is_auth(hdr->frame_control)) | ||
2390 | return; | ||
2391 | |||
2392 | mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL, | ||
2393 | GFP_ATOMIC); | ||
2394 | } | ||
2395 | |||
2396 | /* TODO: use IEEE80211_RX_FRAGMENTED */ | 2376 | /* TODO: use IEEE80211_RX_FRAGMENTED */ |
2397 | static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, | 2377 | static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, |
2398 | struct ieee80211_rate *rate) | 2378 | struct ieee80211_rate *rate) |
@@ -2736,12 +2716,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, | |||
2736 | if (!prepares) | 2716 | if (!prepares) |
2737 | return false; | 2717 | return false; |
2738 | 2718 | ||
2739 | if (status->flag & RX_FLAG_MMIC_ERROR) { | ||
2740 | if (status->rx_flags & IEEE80211_RX_RA_MATCH) | ||
2741 | ieee80211_rx_michael_mic_report(hdr, rx); | ||
2742 | return false; | ||
2743 | } | ||
2744 | |||
2745 | if (!consume) { | 2719 | if (!consume) { |
2746 | skb = skb_copy(skb, GFP_ATOMIC); | 2720 | skb = skb_copy(skb, GFP_ATOMIC); |
2747 | if (!skb) { | 2721 | if (!skb) { |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 489b6ad200d4..d20046b5d8f4 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/if_arp.h> | 15 | #include <linux/if_arp.h> |
16 | #include <linux/rtnetlink.h> | 16 | #include <linux/rtnetlink.h> |
17 | #include <linux/pm_qos_params.h> | 17 | #include <linux/pm_qos_params.h> |
18 | #include <linux/slab.h> | ||
18 | #include <net/sch_generic.h> | 19 | #include <net/sch_generic.h> |
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
20 | #include <net/mac80211.h> | 21 | #include <net/mac80211.h> |
@@ -170,7 +171,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
170 | return RX_CONTINUE; | 171 | return RX_CONTINUE; |
171 | 172 | ||
172 | if (skb->len < 24) | 173 | if (skb->len < 24) |
173 | return RX_DROP_MONITOR; | 174 | return RX_CONTINUE; |
174 | 175 | ||
175 | presp = ieee80211_is_probe_resp(fc); | 176 | presp = ieee80211_is_probe_resp(fc); |
176 | if (presp) { | 177 | if (presp) { |
@@ -850,3 +851,122 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) | |||
850 | } | 851 | } |
851 | mutex_unlock(&local->mtx); | 852 | mutex_unlock(&local->mtx); |
852 | } | 853 | } |
854 | |||
855 | int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | ||
856 | struct cfg80211_sched_scan_request *req) | ||
857 | { | ||
858 | struct ieee80211_local *local = sdata->local; | ||
859 | int ret, i; | ||
860 | |||
861 | mutex_lock(&sdata->local->mtx); | ||
862 | |||
863 | if (local->sched_scanning) { | ||
864 | ret = -EBUSY; | ||
865 | goto out; | ||
866 | } | ||
867 | |||
868 | if (!local->ops->sched_scan_start) { | ||
869 | ret = -ENOTSUPP; | ||
870 | goto out; | ||
871 | } | ||
872 | |||
873 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | ||
874 | local->sched_scan_ies.ie[i] = kzalloc(2 + | ||
875 | IEEE80211_MAX_SSID_LEN + | ||
876 | local->scan_ies_len, | ||
877 | GFP_KERNEL); | ||
878 | if (!local->sched_scan_ies.ie[i]) { | ||
879 | ret = -ENOMEM; | ||
880 | goto out_free; | ||
881 | } | ||
882 | |||
883 | local->sched_scan_ies.len[i] = | ||
884 | ieee80211_build_preq_ies(local, | ||
885 | local->sched_scan_ies.ie[i], | ||
886 | req->ie, req->ie_len, i, | ||
887 | (u32) -1, 0); | ||
888 | } | ||
889 | |||
890 | ret = drv_sched_scan_start(local, sdata, req, | ||
891 | &local->sched_scan_ies); | ||
892 | if (ret == 0) { | ||
893 | local->sched_scanning = true; | ||
894 | goto out; | ||
895 | } | ||
896 | |||
897 | out_free: | ||
898 | while (i > 0) | ||
899 | kfree(local->sched_scan_ies.ie[--i]); | ||
900 | out: | ||
901 | mutex_unlock(&sdata->local->mtx); | ||
902 | return ret; | ||
903 | } | ||
904 | |||
905 | int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) | ||
906 | { | ||
907 | struct ieee80211_local *local = sdata->local; | ||
908 | int ret = 0, i; | ||
909 | |||
910 | mutex_lock(&sdata->local->mtx); | ||
911 | |||
912 | if (!local->ops->sched_scan_stop) { | ||
913 | ret = -ENOTSUPP; | ||
914 | goto out; | ||
915 | } | ||
916 | |||
917 | if (local->sched_scanning) { | ||
918 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
919 | kfree(local->sched_scan_ies.ie[i]); | ||
920 | |||
921 | drv_sched_scan_stop(local, sdata); | ||
922 | local->sched_scanning = false; | ||
923 | } | ||
924 | out: | ||
925 | mutex_unlock(&sdata->local->mtx); | ||
926 | |||
927 | return ret; | ||
928 | } | ||
929 | |||
930 | void ieee80211_sched_scan_results(struct ieee80211_hw *hw) | ||
931 | { | ||
932 | struct ieee80211_local *local = hw_to_local(hw); | ||
933 | |||
934 | trace_api_sched_scan_results(local); | ||
935 | |||
936 | cfg80211_sched_scan_results(hw->wiphy); | ||
937 | } | ||
938 | EXPORT_SYMBOL(ieee80211_sched_scan_results); | ||
939 | |||
940 | void ieee80211_sched_scan_stopped_work(struct work_struct *work) | ||
941 | { | ||
942 | struct ieee80211_local *local = | ||
943 | container_of(work, struct ieee80211_local, | ||
944 | sched_scan_stopped_work); | ||
945 | int i; | ||
946 | |||
947 | mutex_lock(&local->mtx); | ||
948 | |||
949 | if (!local->sched_scanning) { | ||
950 | mutex_unlock(&local->mtx); | ||
951 | return; | ||
952 | } | ||
953 | |||
954 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
955 | kfree(local->sched_scan_ies.ie[i]); | ||
956 | |||
957 | local->sched_scanning = false; | ||
958 | |||
959 | mutex_unlock(&local->mtx); | ||
960 | |||
961 | cfg80211_sched_scan_stopped(local->hw.wiphy); | ||
962 | } | ||
963 | |||
964 | void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw) | ||
965 | { | ||
966 | struct ieee80211_local *local = hw_to_local(hw); | ||
967 | |||
968 | trace_api_sched_scan_stopped(local); | ||
969 | |||
970 | ieee80211_queue_work(&local->hw, &local->sched_scan_stopped_work); | ||
971 | } | ||
972 | EXPORT_SYMBOL(ieee80211_sched_scan_stopped); | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 13e8c30adf01..b83870bf60fa 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -67,7 +67,8 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
67 | { | 67 | { |
68 | struct sta_info *s; | 68 | struct sta_info *s; |
69 | 69 | ||
70 | s = local->sta_hash[STA_HASH(sta->sta.addr)]; | 70 | s = rcu_dereference_protected(local->sta_hash[STA_HASH(sta->sta.addr)], |
71 | lockdep_is_held(&local->sta_lock)); | ||
71 | if (!s) | 72 | if (!s) |
72 | return -ENOENT; | 73 | return -ENOENT; |
73 | if (s == sta) { | 74 | if (s == sta) { |
@@ -76,9 +77,11 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
76 | return 0; | 77 | return 0; |
77 | } | 78 | } |
78 | 79 | ||
79 | while (s->hnext && s->hnext != sta) | 80 | while (rcu_access_pointer(s->hnext) && |
80 | s = s->hnext; | 81 | rcu_access_pointer(s->hnext) != sta) |
81 | if (s->hnext) { | 82 | s = rcu_dereference_protected(s->hnext, |
83 | lockdep_is_held(&local->sta_lock)); | ||
84 | if (rcu_access_pointer(s->hnext)) { | ||
82 | rcu_assign_pointer(s->hnext, sta->hnext); | 85 | rcu_assign_pointer(s->hnext, sta->hnext); |
83 | return 0; | 86 | return 0; |
84 | } | 87 | } |
@@ -228,6 +231,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
228 | { | 231 | { |
229 | struct ieee80211_local *local = sdata->local; | 232 | struct ieee80211_local *local = sdata->local; |
230 | struct sta_info *sta; | 233 | struct sta_info *sta; |
234 | struct timespec uptime; | ||
231 | int i; | 235 | int i; |
232 | 236 | ||
233 | sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); | 237 | sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); |
@@ -245,6 +249,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
245 | sta->sdata = sdata; | 249 | sta->sdata = sdata; |
246 | sta->last_rx = jiffies; | 250 | sta->last_rx = jiffies; |
247 | 251 | ||
252 | do_posix_clock_monotonic_gettime(&uptime); | ||
253 | sta->last_connected = uptime.tv_sec; | ||
248 | ewma_init(&sta->avg_signal, 1024, 8); | 254 | ewma_init(&sta->avg_signal, 1024, 8); |
249 | 255 | ||
250 | if (sta_prepare_rate_control(local, sta, gfp)) { | 256 | if (sta_prepare_rate_control(local, sta, gfp)) { |
@@ -271,7 +277,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
271 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 277 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
272 | 278 | ||
273 | #ifdef CONFIG_MAC80211_MESH | 279 | #ifdef CONFIG_MAC80211_MESH |
274 | sta->plink_state = PLINK_LISTEN; | 280 | sta->plink_state = NL80211_PLINK_LISTEN; |
275 | init_timer(&sta->plink_timer); | 281 | init_timer(&sta->plink_timer); |
276 | #endif | 282 | #endif |
277 | 283 | ||
@@ -584,7 +590,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
584 | { | 590 | { |
585 | unsigned long flags; | 591 | unsigned long flags; |
586 | struct sk_buff *skb; | 592 | struct sk_buff *skb; |
587 | struct ieee80211_sub_if_data *sdata; | ||
588 | 593 | ||
589 | if (skb_queue_empty(&sta->ps_tx_buf)) | 594 | if (skb_queue_empty(&sta->ps_tx_buf)) |
590 | return false; | 595 | return false; |
@@ -601,7 +606,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
601 | if (!skb) | 606 | if (!skb) |
602 | break; | 607 | break; |
603 | 608 | ||
604 | sdata = sta->sdata; | ||
605 | local->total_ps_buffered--; | 609 | local->total_ps_buffered--; |
606 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 610 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
607 | printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n", | 611 | printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n", |
@@ -609,7 +613,8 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
609 | #endif | 613 | #endif |
610 | dev_kfree_skb(skb); | 614 | dev_kfree_skb(skb); |
611 | 615 | ||
612 | if (skb_queue_empty(&sta->ps_tx_buf)) | 616 | if (skb_queue_empty(&sta->ps_tx_buf) && |
617 | !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF)) | ||
613 | sta_info_clear_tim_bit(sta); | 618 | sta_info_clear_tim_bit(sta); |
614 | } | 619 | } |
615 | 620 | ||
@@ -650,10 +655,12 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
650 | if (ret) | 655 | if (ret) |
651 | return ret; | 656 | return ret; |
652 | 657 | ||
658 | mutex_lock(&local->key_mtx); | ||
653 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) | 659 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) |
654 | ieee80211_key_free(local, sta->gtk[i]); | 660 | __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i])); |
655 | if (sta->ptk) | 661 | if (sta->ptk) |
656 | ieee80211_key_free(local, sta->ptk); | 662 | __ieee80211_key_free(key_mtx_dereference(local, sta->ptk)); |
663 | mutex_unlock(&local->key_mtx); | ||
657 | 664 | ||
658 | sta->dead = true; | 665 | sta->dead = true; |
659 | 666 | ||
@@ -698,6 +705,8 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
698 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 705 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
699 | cancel_work_sync(&sta->drv_unblock_wk); | 706 | cancel_work_sync(&sta->drv_unblock_wk); |
700 | 707 | ||
708 | cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); | ||
709 | |||
701 | rate_control_remove_sta_debugfs(sta); | 710 | rate_control_remove_sta_debugfs(sta); |
702 | ieee80211_sta_debugfs_remove(sta); | 711 | ieee80211_sta_debugfs_remove(sta); |
703 | 712 | ||
@@ -766,9 +775,8 @@ static void sta_info_cleanup(unsigned long data) | |||
766 | if (!timer_needed) | 775 | if (!timer_needed) |
767 | return; | 776 | return; |
768 | 777 | ||
769 | local->sta_cleanup.expires = | 778 | mod_timer(&local->sta_cleanup, |
770 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 779 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL)); |
771 | add_timer(&local->sta_cleanup); | ||
772 | } | 780 | } |
773 | 781 | ||
774 | void sta_info_init(struct ieee80211_local *local) | 782 | void sta_info_init(struct ieee80211_local *local) |
@@ -781,14 +789,6 @@ void sta_info_init(struct ieee80211_local *local) | |||
781 | 789 | ||
782 | setup_timer(&local->sta_cleanup, sta_info_cleanup, | 790 | setup_timer(&local->sta_cleanup, sta_info_cleanup, |
783 | (unsigned long)local); | 791 | (unsigned long)local); |
784 | local->sta_cleanup.expires = | ||
785 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | ||
786 | } | ||
787 | |||
788 | int sta_info_start(struct ieee80211_local *local) | ||
789 | { | ||
790 | add_timer(&local->sta_cleanup); | ||
791 | return 0; | ||
792 | } | 792 | } |
793 | 793 | ||
794 | void sta_info_stop(struct ieee80211_local *local) | 794 | void sta_info_stop(struct ieee80211_local *local) |
@@ -900,6 +900,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
900 | struct ieee80211_local *local = sdata->local; | 900 | struct ieee80211_local *local = sdata->local; |
901 | int sent, buffered; | 901 | int sent, buffered; |
902 | 902 | ||
903 | clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF); | ||
903 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) | 904 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) |
904 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); | 905 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); |
905 | 906 | ||
@@ -992,3 +993,12 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | |||
992 | ieee80211_queue_work(hw, &sta->drv_unblock_wk); | 993 | ieee80211_queue_work(hw, &sta->drv_unblock_wk); |
993 | } | 994 | } |
994 | EXPORT_SYMBOL(ieee80211_sta_block_awake); | 995 | EXPORT_SYMBOL(ieee80211_sta_block_awake); |
996 | |||
997 | void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta) | ||
998 | { | ||
999 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
1000 | |||
1001 | set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF); | ||
1002 | sta_info_set_tim_bit(sta); | ||
1003 | } | ||
1004 | EXPORT_SYMBOL(ieee80211_sta_set_tim); | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b2f95966c7f4..c6ae8718bd57 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -43,6 +43,8 @@ | |||
43 | * be in the queues | 43 | * be in the queues |
44 | * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping | 44 | * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping |
45 | * station in power-save mode, reply when the driver unblocks. | 45 | * station in power-save mode, reply when the driver unblocks. |
46 | * @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal | ||
47 | * buffers. Automatically cleared on station wake-up. | ||
46 | */ | 48 | */ |
47 | enum ieee80211_sta_info_flags { | 49 | enum ieee80211_sta_info_flags { |
48 | WLAN_STA_AUTH = 1<<0, | 50 | WLAN_STA_AUTH = 1<<0, |
@@ -58,6 +60,7 @@ enum ieee80211_sta_info_flags { | |||
58 | WLAN_STA_BLOCK_BA = 1<<11, | 60 | WLAN_STA_BLOCK_BA = 1<<11, |
59 | WLAN_STA_PS_DRIVER = 1<<12, | 61 | WLAN_STA_PS_DRIVER = 1<<12, |
60 | WLAN_STA_PSPOLL = 1<<13, | 62 | WLAN_STA_PSPOLL = 1<<13, |
63 | WLAN_STA_PS_DRIVER_BUF = 1<<14, | ||
61 | }; | 64 | }; |
62 | 65 | ||
63 | #define STA_TID_NUM 16 | 66 | #define STA_TID_NUM 16 |
@@ -149,6 +152,7 @@ struct tid_ampdu_rx { | |||
149 | * | 152 | * |
150 | * @tid_rx: aggregation info for Rx per TID -- RCU protected | 153 | * @tid_rx: aggregation info for Rx per TID -- RCU protected |
151 | * @tid_tx: aggregation info for Tx per TID | 154 | * @tid_tx: aggregation info for Tx per TID |
155 | * @tid_start_tx: sessions where start was requested | ||
152 | * @addba_req_num: number of times addBA request has been sent. | 156 | * @addba_req_num: number of times addBA request has been sent. |
153 | * @dialog_token_allocator: dialog token enumerator for each new session; | 157 | * @dialog_token_allocator: dialog token enumerator for each new session; |
154 | * @work: work struct for starting/stopping aggregation | 158 | * @work: work struct for starting/stopping aggregation |
@@ -160,40 +164,18 @@ struct tid_ampdu_rx { | |||
160 | struct sta_ampdu_mlme { | 164 | struct sta_ampdu_mlme { |
161 | struct mutex mtx; | 165 | struct mutex mtx; |
162 | /* rx */ | 166 | /* rx */ |
163 | struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; | 167 | struct tid_ampdu_rx __rcu *tid_rx[STA_TID_NUM]; |
164 | unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)]; | 168 | unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)]; |
165 | /* tx */ | 169 | /* tx */ |
166 | struct work_struct work; | 170 | struct work_struct work; |
167 | struct tid_ampdu_tx *tid_tx[STA_TID_NUM]; | 171 | struct tid_ampdu_tx __rcu *tid_tx[STA_TID_NUM]; |
172 | struct tid_ampdu_tx *tid_start_tx[STA_TID_NUM]; | ||
168 | u8 addba_req_num[STA_TID_NUM]; | 173 | u8 addba_req_num[STA_TID_NUM]; |
169 | u8 dialog_token_allocator; | 174 | u8 dialog_token_allocator; |
170 | }; | 175 | }; |
171 | 176 | ||
172 | 177 | ||
173 | /** | 178 | /** |
174 | * enum plink_state - state of a mesh peer link finite state machine | ||
175 | * | ||
176 | * @PLINK_LISTEN: initial state, considered the implicit state of non existent | ||
177 | * mesh peer links | ||
178 | * @PLINK_OPN_SNT: mesh plink open frame has been sent to this mesh peer | ||
179 | * @PLINK_OPN_RCVD: mesh plink open frame has been received from this mesh peer | ||
180 | * @PLINK_CNF_RCVD: mesh plink confirm frame has been received from this mesh | ||
181 | * peer | ||
182 | * @PLINK_ESTAB: mesh peer link is established | ||
183 | * @PLINK_HOLDING: mesh peer link is being closed or cancelled | ||
184 | * @PLINK_BLOCKED: all frames transmitted from this mesh plink are discarded | ||
185 | */ | ||
186 | enum plink_state { | ||
187 | PLINK_LISTEN, | ||
188 | PLINK_OPN_SNT, | ||
189 | PLINK_OPN_RCVD, | ||
190 | PLINK_CNF_RCVD, | ||
191 | PLINK_ESTAB, | ||
192 | PLINK_HOLDING, | ||
193 | PLINK_BLOCKED | ||
194 | }; | ||
195 | |||
196 | /** | ||
197 | * struct sta_info - STA information | 179 | * struct sta_info - STA information |
198 | * | 180 | * |
199 | * This structure collects information about a station that | 181 | * This structure collects information about a station that |
@@ -226,6 +208,7 @@ enum plink_state { | |||
226 | * @rx_bytes: Number of bytes received from this STA | 208 | * @rx_bytes: Number of bytes received from this STA |
227 | * @wep_weak_iv_count: number of weak WEP IVs received from this station | 209 | * @wep_weak_iv_count: number of weak WEP IVs received from this station |
228 | * @last_rx: time (in jiffies) when last frame was received from this STA | 210 | * @last_rx: time (in jiffies) when last frame was received from this STA |
211 | * @last_connected: time (in seconds) when a station got connected | ||
229 | * @num_duplicates: number of duplicate frames received from this STA | 212 | * @num_duplicates: number of duplicate frames received from this STA |
230 | * @rx_fragments: number of received MPDUs | 213 | * @rx_fragments: number of received MPDUs |
231 | * @rx_dropped: number of dropped MPDUs from this STA | 214 | * @rx_dropped: number of dropped MPDUs from this STA |
@@ -260,11 +243,11 @@ enum plink_state { | |||
260 | struct sta_info { | 243 | struct sta_info { |
261 | /* General information, mostly static */ | 244 | /* General information, mostly static */ |
262 | struct list_head list; | 245 | struct list_head list; |
263 | struct sta_info *hnext; | 246 | struct sta_info __rcu *hnext; |
264 | struct ieee80211_local *local; | 247 | struct ieee80211_local *local; |
265 | struct ieee80211_sub_if_data *sdata; | 248 | struct ieee80211_sub_if_data *sdata; |
266 | struct ieee80211_key *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | 249 | struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
267 | struct ieee80211_key *ptk; | 250 | struct ieee80211_key __rcu *ptk; |
268 | struct rate_control_ref *rate_ctrl; | 251 | struct rate_control_ref *rate_ctrl; |
269 | void *rate_ctrl_priv; | 252 | void *rate_ctrl_priv; |
270 | spinlock_t lock; | 253 | spinlock_t lock; |
@@ -295,6 +278,7 @@ struct sta_info { | |||
295 | unsigned long rx_packets, rx_bytes; | 278 | unsigned long rx_packets, rx_bytes; |
296 | unsigned long wep_weak_iv_count; | 279 | unsigned long wep_weak_iv_count; |
297 | unsigned long last_rx; | 280 | unsigned long last_rx; |
281 | long last_connected; | ||
298 | unsigned long num_duplicates; | 282 | unsigned long num_duplicates; |
299 | unsigned long rx_fragments; | 283 | unsigned long rx_fragments; |
300 | unsigned long rx_dropped; | 284 | unsigned long rx_dropped; |
@@ -334,7 +318,7 @@ struct sta_info { | |||
334 | u8 plink_retries; | 318 | u8 plink_retries; |
335 | bool ignore_plink_timer; | 319 | bool ignore_plink_timer; |
336 | bool plink_timer_was_running; | 320 | bool plink_timer_was_running; |
337 | enum plink_state plink_state; | 321 | enum nl80211_plink_state plink_state; |
338 | u32 plink_timeout; | 322 | u32 plink_timeout; |
339 | struct timer_list plink_timer; | 323 | struct timer_list plink_timer; |
340 | #endif | 324 | #endif |
@@ -352,12 +336,12 @@ struct sta_info { | |||
352 | struct ieee80211_sta sta; | 336 | struct ieee80211_sta sta; |
353 | }; | 337 | }; |
354 | 338 | ||
355 | static inline enum plink_state sta_plink_state(struct sta_info *sta) | 339 | static inline enum nl80211_plink_state sta_plink_state(struct sta_info *sta) |
356 | { | 340 | { |
357 | #ifdef CONFIG_MAC80211_MESH | 341 | #ifdef CONFIG_MAC80211_MESH |
358 | return sta->plink_state; | 342 | return sta->plink_state; |
359 | #endif | 343 | #endif |
360 | return PLINK_LISTEN; | 344 | return NL80211_PLINK_LISTEN; |
361 | } | 345 | } |
362 | 346 | ||
363 | static inline void set_sta_flags(struct sta_info *sta, const u32 flags) | 347 | static inline void set_sta_flags(struct sta_info *sta, const u32 flags) |
@@ -416,7 +400,16 @@ static inline u32 get_sta_flags(struct sta_info *sta) | |||
416 | return ret; | 400 | return ret; |
417 | } | 401 | } |
418 | 402 | ||
403 | void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, | ||
404 | struct tid_ampdu_tx *tid_tx); | ||
419 | 405 | ||
406 | static inline struct tid_ampdu_tx * | ||
407 | rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid) | ||
408 | { | ||
409 | return rcu_dereference_protected(sta->ampdu_mlme.tid_tx[tid], | ||
410 | lockdep_is_held(&sta->lock) || | ||
411 | lockdep_is_held(&sta->ampdu_mlme.mtx)); | ||
412 | } | ||
420 | 413 | ||
421 | #define STA_HASH_SIZE 256 | 414 | #define STA_HASH_SIZE 256 |
422 | #define STA_HASH(sta) (sta[5]) | 415 | #define STA_HASH(sta) (sta[5]) |
@@ -497,7 +490,6 @@ void sta_info_set_tim_bit(struct sta_info *sta); | |||
497 | void sta_info_clear_tim_bit(struct sta_info *sta); | 490 | void sta_info_clear_tim_bit(struct sta_info *sta); |
498 | 491 | ||
499 | void sta_info_init(struct ieee80211_local *local); | 492 | void sta_info_init(struct ieee80211_local *local); |
500 | int sta_info_start(struct ieee80211_local *local); | ||
501 | void sta_info_stop(struct ieee80211_local *local); | 493 | void sta_info_stop(struct ieee80211_local *local); |
502 | int sta_info_flush(struct ieee80211_local *local, | 494 | int sta_info_flush(struct ieee80211_local *local, |
503 | struct ieee80211_sub_if_data *sdata); | 495 | struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index b936dd29e92b..1658efaa2e8e 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -189,16 +189,19 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
189 | bool acked; | 189 | bool acked; |
190 | 190 | ||
191 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 191 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
192 | /* the HW cannot have attempted that rate */ | 192 | if (info->status.rates[i].idx < 0) { |
193 | if (i >= hw->max_report_rates) { | 193 | break; |
194 | } else if (i >= hw->max_report_rates) { | ||
195 | /* the HW cannot have attempted that rate */ | ||
194 | info->status.rates[i].idx = -1; | 196 | info->status.rates[i].idx = -1; |
195 | info->status.rates[i].count = 0; | 197 | info->status.rates[i].count = 0; |
196 | } else if (info->status.rates[i].idx >= 0) { | 198 | break; |
197 | rates_idx = i; | ||
198 | } | 199 | } |
199 | 200 | ||
200 | retry_count += info->status.rates[i].count; | 201 | retry_count += info->status.rates[i].count; |
201 | } | 202 | } |
203 | rates_idx = i - 1; | ||
204 | |||
202 | if (retry_count < 0) | 205 | if (retry_count < 0) |
203 | retry_count = 0; | 206 | retry_count = 0; |
204 | 207 | ||
@@ -443,3 +446,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
443 | dev_kfree_skb(skb); | 446 | dev_kfree_skb(skb); |
444 | } | 447 | } |
445 | EXPORT_SYMBOL(ieee80211_tx_status); | 448 | EXPORT_SYMBOL(ieee80211_tx_status); |
449 | |||
450 | void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets) | ||
451 | { | ||
452 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
453 | cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr, | ||
454 | num_packets, GFP_ATOMIC); | ||
455 | } | ||
456 | EXPORT_SYMBOL(ieee80211_report_low_ack); | ||
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index e840c9cd46db..757e4eb2baf7 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c | |||
@@ -202,7 +202,7 @@ EXPORT_SYMBOL(ieee80211_get_tkip_key); | |||
202 | * @payload_len is the length of payload (_not_ including IV/ICV length). | 202 | * @payload_len is the length of payload (_not_ including IV/ICV length). |
203 | * @ta is the transmitter addresses. | 203 | * @ta is the transmitter addresses. |
204 | */ | 204 | */ |
205 | int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, | 205 | int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, |
206 | struct ieee80211_key *key, | 206 | struct ieee80211_key *key, |
207 | u8 *pos, size_t payload_len, u8 *ta) | 207 | u8 *pos, size_t payload_len, u8 *ta) |
208 | { | 208 | { |
@@ -223,7 +223,7 @@ int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, | |||
223 | * beginning of the buffer containing IEEE 802.11 header payload, i.e., | 223 | * beginning of the buffer containing IEEE 802.11 header payload, i.e., |
224 | * including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the | 224 | * including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the |
225 | * length of payload, including IV, Ext. IV, MIC, ICV. */ | 225 | * length of payload, including IV, Ext. IV, MIC, ICV. */ |
226 | int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, | 226 | int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, |
227 | struct ieee80211_key *key, | 227 | struct ieee80211_key *key, |
228 | u8 *payload, size_t payload_len, u8 *ta, | 228 | u8 *payload, size_t payload_len, u8 *ta, |
229 | u8 *ra, int only_iv, int queue, | 229 | u8 *ra, int only_iv, int queue, |
diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h index 7e83dee976fa..1cab9c86978f 100644 --- a/net/mac80211/tkip.h +++ b/net/mac80211/tkip.h | |||
@@ -15,7 +15,7 @@ | |||
15 | 15 | ||
16 | u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16); | 16 | u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16); |
17 | 17 | ||
18 | int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, | 18 | int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, |
19 | struct ieee80211_key *key, | 19 | struct ieee80211_key *key, |
20 | u8 *pos, size_t payload_len, u8 *ta); | 20 | u8 *pos, size_t payload_len, u8 *ta); |
21 | enum { | 21 | enum { |
@@ -24,7 +24,7 @@ enum { | |||
24 | TKIP_DECRYPT_INVALID_KEYIDX = -2, | 24 | TKIP_DECRYPT_INVALID_KEYIDX = -2, |
25 | TKIP_DECRYPT_REPLAY = -3, | 25 | TKIP_DECRYPT_REPLAY = -3, |
26 | }; | 26 | }; |
27 | int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, | 27 | int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, |
28 | struct ieee80211_key *key, | 28 | struct ieee80211_key *key, |
29 | u8 *payload, size_t payload_len, u8 *ta, | 29 | u8 *payload, size_t payload_len, u8 *ta, |
30 | u8 *ra, int only_iv, int queue, | 30 | u8 *ra, int only_iv, int queue, |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index bd1224fd216a..64e0f7587e6d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1040,14 +1040,11 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
1040 | struct ieee80211_radiotap_iterator iterator; | 1040 | struct ieee80211_radiotap_iterator iterator; |
1041 | struct ieee80211_radiotap_header *rthdr = | 1041 | struct ieee80211_radiotap_header *rthdr = |
1042 | (struct ieee80211_radiotap_header *) skb->data; | 1042 | (struct ieee80211_radiotap_header *) skb->data; |
1043 | struct ieee80211_supported_band *sband; | ||
1044 | bool hw_frag; | 1043 | bool hw_frag; |
1045 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1044 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1046 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, | 1045 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, |
1047 | NULL); | 1046 | NULL); |
1048 | 1047 | ||
1049 | sband = tx->local->hw.wiphy->bands[tx->channel->band]; | ||
1050 | |||
1051 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 1048 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
1052 | tx->flags &= ~IEEE80211_TX_FRAGMENTED; | 1049 | tx->flags &= ~IEEE80211_TX_FRAGMENTED; |
1053 | 1050 | ||
@@ -1154,7 +1151,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx, | |||
1154 | * packet pass through because splicing the frames | 1151 | * packet pass through because splicing the frames |
1155 | * back is already done. | 1152 | * back is already done. |
1156 | */ | 1153 | */ |
1157 | tid_tx = tx->sta->ampdu_mlme.tid_tx[tid]; | 1154 | tid_tx = rcu_dereference_protected_tid_tx(tx->sta, tid); |
1158 | 1155 | ||
1159 | if (!tid_tx) { | 1156 | if (!tid_tx) { |
1160 | /* do nothing, let packet pass through */ | 1157 | /* do nothing, let packet pass through */ |
@@ -1446,11 +1443,8 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
1446 | struct ieee80211_tx_data tx; | 1443 | struct ieee80211_tx_data tx; |
1447 | ieee80211_tx_result res_prepare; | 1444 | ieee80211_tx_result res_prepare; |
1448 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1445 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1449 | u16 queue; | ||
1450 | bool result = true; | 1446 | bool result = true; |
1451 | 1447 | ||
1452 | queue = skb_get_queue_mapping(skb); | ||
1453 | |||
1454 | if (unlikely(skb->len < 10)) { | 1448 | if (unlikely(skb->len < 10)) { |
1455 | dev_kfree_skb(skb); | 1449 | dev_kfree_skb(skb); |
1456 | return true; | 1450 | return true; |
@@ -1486,12 +1480,7 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, | |||
1486 | { | 1480 | { |
1487 | int tail_need = 0; | 1481 | int tail_need = 0; |
1488 | 1482 | ||
1489 | /* | 1483 | if (may_encrypt && local->crypto_tx_tailroom_needed_cnt) { |
1490 | * This could be optimised, devices that do full hardware | ||
1491 | * crypto (including TKIP MMIC) need no tailroom... But we | ||
1492 | * have no drivers for such devices currently. | ||
1493 | */ | ||
1494 | if (may_encrypt) { | ||
1495 | tail_need = IEEE80211_ENCRYPT_TAILROOM; | 1484 | tail_need = IEEE80211_ENCRYPT_TAILROOM; |
1496 | tail_need -= skb_tailroom(skb); | 1485 | tail_need -= skb_tailroom(skb); |
1497 | tail_need = max_t(int, tail_need, 0); | 1486 | tail_need = max_t(int, tail_need, 0); |
@@ -1766,6 +1755,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1766 | ret = NETDEV_TX_OK; | 1755 | ret = NETDEV_TX_OK; |
1767 | goto fail; | 1756 | goto fail; |
1768 | } | 1757 | } |
1758 | rcu_read_lock(); | ||
1769 | if (!is_multicast_ether_addr(skb->data)) | 1759 | if (!is_multicast_ether_addr(skb->data)) |
1770 | mppath = mpp_path_lookup(skb->data, sdata); | 1760 | mppath = mpp_path_lookup(skb->data, sdata); |
1771 | 1761 | ||
@@ -1780,13 +1770,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1780 | !(mppath && compare_ether_addr(mppath->mpp, skb->data))) { | 1770 | !(mppath && compare_ether_addr(mppath->mpp, skb->data))) { |
1781 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, | 1771 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, |
1782 | skb->data, skb->data + ETH_ALEN); | 1772 | skb->data, skb->data + ETH_ALEN); |
1773 | rcu_read_unlock(); | ||
1783 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, | 1774 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, |
1784 | sdata, NULL, NULL); | 1775 | sdata, NULL, NULL); |
1785 | } else { | 1776 | } else { |
1786 | int is_mesh_mcast = 1; | 1777 | int is_mesh_mcast = 1; |
1787 | const u8 *mesh_da; | 1778 | const u8 *mesh_da; |
1788 | 1779 | ||
1789 | rcu_read_lock(); | ||
1790 | if (is_multicast_ether_addr(skb->data)) | 1780 | if (is_multicast_ether_addr(skb->data)) |
1791 | /* DA TA mSA AE:SA */ | 1781 | /* DA TA mSA AE:SA */ |
1792 | mesh_da = skb->data; | 1782 | mesh_da = skb->data; |
@@ -2266,7 +2256,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2266 | 2256 | ||
2267 | /* headroom, head length, tail length and maximum TIM length */ | 2257 | /* headroom, head length, tail length and maximum TIM length */ |
2268 | skb = dev_alloc_skb(local->tx_headroom + 400 + | 2258 | skb = dev_alloc_skb(local->tx_headroom + 400 + |
2269 | sdata->u.mesh.vendor_ie_len); | 2259 | sdata->u.mesh.ie_len); |
2270 | if (!skb) | 2260 | if (!skb) |
2271 | goto out; | 2261 | goto out; |
2272 | 2262 | ||
@@ -2489,7 +2479,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
2489 | { | 2479 | { |
2490 | struct ieee80211_local *local = hw_to_local(hw); | 2480 | struct ieee80211_local *local = hw_to_local(hw); |
2491 | struct sk_buff *skb = NULL; | 2481 | struct sk_buff *skb = NULL; |
2492 | struct sta_info *sta; | ||
2493 | struct ieee80211_tx_data tx; | 2482 | struct ieee80211_tx_data tx; |
2494 | struct ieee80211_sub_if_data *sdata; | 2483 | struct ieee80211_sub_if_data *sdata; |
2495 | struct ieee80211_if_ap *bss = NULL; | 2484 | struct ieee80211_if_ap *bss = NULL; |
@@ -2531,7 +2520,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
2531 | 2520 | ||
2532 | info = IEEE80211_SKB_CB(skb); | 2521 | info = IEEE80211_SKB_CB(skb); |
2533 | 2522 | ||
2534 | sta = tx.sta; | ||
2535 | tx.flags |= IEEE80211_TX_PS_BUFFERED; | 2523 | tx.flags |= IEEE80211_TX_PS_BUFFERED; |
2536 | tx.channel = local->hw.conf.channel; | 2524 | tx.channel = local->hw.conf.channel; |
2537 | info->band = tx.channel->band; | 2525 | info->band = tx.channel->band; |
@@ -2551,8 +2539,9 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
2551 | skb_set_network_header(skb, 0); | 2539 | skb_set_network_header(skb, 0); |
2552 | skb_set_transport_header(skb, 0); | 2540 | skb_set_transport_header(skb, 0); |
2553 | 2541 | ||
2554 | /* send all internal mgmt frames on VO */ | 2542 | /* Send all internal mgmt frames on VO. Accordingly set TID to 7. */ |
2555 | skb_set_queue_mapping(skb, 0); | 2543 | skb_set_queue_mapping(skb, IEEE80211_AC_VO); |
2544 | skb->priority = 7; | ||
2556 | 2545 | ||
2557 | /* | 2546 | /* |
2558 | * The other path calling ieee80211_xmit is from the tasklet, | 2547 | * The other path calling ieee80211_xmit is from the tasklet, |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 556647a910ac..d3fe2d237485 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1125,9 +1125,27 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1125 | struct sta_info *sta; | 1125 | struct sta_info *sta; |
1126 | int res; | 1126 | int res; |
1127 | 1127 | ||
1128 | #ifdef CONFIG_PM | ||
1128 | if (local->suspended) | 1129 | if (local->suspended) |
1129 | local->resuming = true; | 1130 | local->resuming = true; |
1130 | 1131 | ||
1132 | if (local->wowlan) { | ||
1133 | local->wowlan = false; | ||
1134 | res = drv_resume(local); | ||
1135 | if (res < 0) { | ||
1136 | local->resuming = false; | ||
1137 | return res; | ||
1138 | } | ||
1139 | if (res == 0) | ||
1140 | goto wake_up; | ||
1141 | WARN_ON(res > 1); | ||
1142 | /* | ||
1143 | * res is 1, which means the driver requested | ||
1144 | * to go through a regular reset on wakeup. | ||
1145 | */ | ||
1146 | } | ||
1147 | #endif | ||
1148 | |||
1131 | /* restart hardware */ | 1149 | /* restart hardware */ |
1132 | if (local->open_count) { | 1150 | if (local->open_count) { |
1133 | /* | 1151 | /* |
@@ -1258,6 +1276,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1258 | if (ieee80211_sdata_running(sdata)) | 1276 | if (ieee80211_sdata_running(sdata)) |
1259 | ieee80211_enable_keys(sdata); | 1277 | ieee80211_enable_keys(sdata); |
1260 | 1278 | ||
1279 | wake_up: | ||
1261 | ieee80211_wake_queues_by_reason(hw, | 1280 | ieee80211_wake_queues_by_reason(hw, |
1262 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 1281 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
1263 | 1282 | ||
@@ -1290,7 +1309,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1290 | } | 1309 | } |
1291 | } | 1310 | } |
1292 | 1311 | ||
1293 | add_timer(&local->sta_cleanup); | 1312 | mod_timer(&local->sta_cleanup, jiffies + 1); |
1294 | 1313 | ||
1295 | mutex_lock(&local->sta_mtx); | 1314 | mutex_lock(&local->sta_mtx); |
1296 | list_for_each_entry(sta, &local->sta_list, list) | 1315 | list_for_each_entry(sta, &local->sta_list, list) |
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 2ff6d1e3ed21..a1c6bfd55f0f 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
@@ -30,17 +30,15 @@ int ieee80211_wep_init(struct ieee80211_local *local) | |||
30 | /* start WEP IV from a random value */ | 30 | /* start WEP IV from a random value */ |
31 | get_random_bytes(&local->wep_iv, WEP_IV_LEN); | 31 | get_random_bytes(&local->wep_iv, WEP_IV_LEN); |
32 | 32 | ||
33 | local->wep_tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, | 33 | local->wep_tx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC); |
34 | CRYPTO_ALG_ASYNC); | ||
35 | if (IS_ERR(local->wep_tx_tfm)) { | 34 | if (IS_ERR(local->wep_tx_tfm)) { |
36 | local->wep_rx_tfm = ERR_PTR(-EINVAL); | 35 | local->wep_rx_tfm = ERR_PTR(-EINVAL); |
37 | return PTR_ERR(local->wep_tx_tfm); | 36 | return PTR_ERR(local->wep_tx_tfm); |
38 | } | 37 | } |
39 | 38 | ||
40 | local->wep_rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, | 39 | local->wep_rx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC); |
41 | CRYPTO_ALG_ASYNC); | ||
42 | if (IS_ERR(local->wep_rx_tfm)) { | 40 | if (IS_ERR(local->wep_rx_tfm)) { |
43 | crypto_free_blkcipher(local->wep_tx_tfm); | 41 | crypto_free_cipher(local->wep_tx_tfm); |
44 | local->wep_tx_tfm = ERR_PTR(-EINVAL); | 42 | local->wep_tx_tfm = ERR_PTR(-EINVAL); |
45 | return PTR_ERR(local->wep_rx_tfm); | 43 | return PTR_ERR(local->wep_rx_tfm); |
46 | } | 44 | } |
@@ -51,9 +49,9 @@ int ieee80211_wep_init(struct ieee80211_local *local) | |||
51 | void ieee80211_wep_free(struct ieee80211_local *local) | 49 | void ieee80211_wep_free(struct ieee80211_local *local) |
52 | { | 50 | { |
53 | if (!IS_ERR(local->wep_tx_tfm)) | 51 | if (!IS_ERR(local->wep_tx_tfm)) |
54 | crypto_free_blkcipher(local->wep_tx_tfm); | 52 | crypto_free_cipher(local->wep_tx_tfm); |
55 | if (!IS_ERR(local->wep_rx_tfm)) | 53 | if (!IS_ERR(local->wep_rx_tfm)) |
56 | crypto_free_blkcipher(local->wep_rx_tfm); | 54 | crypto_free_cipher(local->wep_rx_tfm); |
57 | } | 55 | } |
58 | 56 | ||
59 | static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen) | 57 | static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen) |
@@ -127,12 +125,11 @@ static void ieee80211_wep_remove_iv(struct ieee80211_local *local, | |||
127 | /* Perform WEP encryption using given key. data buffer must have tailroom | 125 | /* Perform WEP encryption using given key. data buffer must have tailroom |
128 | * for 4-byte ICV. data_len must not include this ICV. Note: this function | 126 | * for 4-byte ICV. data_len must not include this ICV. Note: this function |
129 | * does _not_ add IV. data = RC4(data | CRC32(data)) */ | 127 | * does _not_ add IV. data = RC4(data | CRC32(data)) */ |
130 | int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, | 128 | int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key, |
131 | size_t klen, u8 *data, size_t data_len) | 129 | size_t klen, u8 *data, size_t data_len) |
132 | { | 130 | { |
133 | struct blkcipher_desc desc = { .tfm = tfm }; | ||
134 | struct scatterlist sg; | ||
135 | __le32 icv; | 131 | __le32 icv; |
132 | int i; | ||
136 | 133 | ||
137 | if (IS_ERR(tfm)) | 134 | if (IS_ERR(tfm)) |
138 | return -1; | 135 | return -1; |
@@ -140,9 +137,9 @@ int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, | |||
140 | icv = cpu_to_le32(~crc32_le(~0, data, data_len)); | 137 | icv = cpu_to_le32(~crc32_le(~0, data, data_len)); |
141 | put_unaligned(icv, (__le32 *)(data + data_len)); | 138 | put_unaligned(icv, (__le32 *)(data + data_len)); |
142 | 139 | ||
143 | crypto_blkcipher_setkey(tfm, rc4key, klen); | 140 | crypto_cipher_setkey(tfm, rc4key, klen); |
144 | sg_init_one(&sg, data, data_len + WEP_ICV_LEN); | 141 | for (i = 0; i < data_len + WEP_ICV_LEN; i++) |
145 | crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length); | 142 | crypto_cipher_encrypt_one(tfm, data + i, data + i); |
146 | 143 | ||
147 | return 0; | 144 | return 0; |
148 | } | 145 | } |
@@ -186,19 +183,18 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, | |||
186 | /* Perform WEP decryption using given key. data buffer includes encrypted | 183 | /* Perform WEP decryption using given key. data buffer includes encrypted |
187 | * payload, including 4-byte ICV, but _not_ IV. data_len must not include ICV. | 184 | * payload, including 4-byte ICV, but _not_ IV. data_len must not include ICV. |
188 | * Return 0 on success and -1 on ICV mismatch. */ | 185 | * Return 0 on success and -1 on ICV mismatch. */ |
189 | int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, | 186 | int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key, |
190 | size_t klen, u8 *data, size_t data_len) | 187 | size_t klen, u8 *data, size_t data_len) |
191 | { | 188 | { |
192 | struct blkcipher_desc desc = { .tfm = tfm }; | ||
193 | struct scatterlist sg; | ||
194 | __le32 crc; | 189 | __le32 crc; |
190 | int i; | ||
195 | 191 | ||
196 | if (IS_ERR(tfm)) | 192 | if (IS_ERR(tfm)) |
197 | return -1; | 193 | return -1; |
198 | 194 | ||
199 | crypto_blkcipher_setkey(tfm, rc4key, klen); | 195 | crypto_cipher_setkey(tfm, rc4key, klen); |
200 | sg_init_one(&sg, data, data_len + WEP_ICV_LEN); | 196 | for (i = 0; i < data_len + WEP_ICV_LEN; i++) |
201 | crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length); | 197 | crypto_cipher_decrypt_one(tfm, data + i, data + i); |
202 | 198 | ||
203 | crc = cpu_to_le32(~crc32_le(~0, data, data_len)); | 199 | crc = cpu_to_le32(~crc32_le(~0, data, data_len)); |
204 | if (memcmp(&crc, data + data_len, WEP_ICV_LEN) != 0) | 200 | if (memcmp(&crc, data + data_len, WEP_ICV_LEN) != 0) |
diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index 58654ee33518..01e54840a628 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h | |||
@@ -18,12 +18,12 @@ | |||
18 | 18 | ||
19 | int ieee80211_wep_init(struct ieee80211_local *local); | 19 | int ieee80211_wep_init(struct ieee80211_local *local); |
20 | void ieee80211_wep_free(struct ieee80211_local *local); | 20 | void ieee80211_wep_free(struct ieee80211_local *local); |
21 | int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, | 21 | int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key, |
22 | size_t klen, u8 *data, size_t data_len); | 22 | size_t klen, u8 *data, size_t data_len); |
23 | int ieee80211_wep_encrypt(struct ieee80211_local *local, | 23 | int ieee80211_wep_encrypt(struct ieee80211_local *local, |
24 | struct sk_buff *skb, | 24 | struct sk_buff *skb, |
25 | const u8 *key, int keylen, int keyidx); | 25 | const u8 *key, int keylen, int keyidx); |
26 | int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, | 26 | int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key, |
27 | size_t klen, u8 *data, size_t data_len); | 27 | size_t klen, u8 *data, size_t data_len); |
28 | bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); | 28 | bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); |
29 | 29 | ||
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index ac3549690b8e..d2e7f0e86677 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -190,9 +190,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
190 | struct sk_buff *skb; | 190 | struct sk_buff *skb; |
191 | struct ieee80211_mgmt *mgmt; | 191 | struct ieee80211_mgmt *mgmt; |
192 | u8 *pos, qos_info; | 192 | u8 *pos, qos_info; |
193 | const u8 *ies; | ||
194 | size_t offset = 0, noffset; | 193 | size_t offset = 0, noffset; |
195 | int i, len, count, rates_len, supp_rates_len; | 194 | int i, count, rates_len, supp_rates_len; |
196 | u16 capab; | 195 | u16 capab; |
197 | struct ieee80211_supported_band *sband; | 196 | struct ieee80211_supported_band *sband; |
198 | u32 rates = 0; | 197 | u32 rates = 0; |
@@ -277,7 +276,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
277 | } | 276 | } |
278 | 277 | ||
279 | /* SSID */ | 278 | /* SSID */ |
280 | ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len); | 279 | pos = skb_put(skb, 2 + wk->assoc.ssid_len); |
281 | *pos++ = WLAN_EID_SSID; | 280 | *pos++ = WLAN_EID_SSID; |
282 | *pos++ = wk->assoc.ssid_len; | 281 | *pos++ = wk->assoc.ssid_len; |
283 | memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); | 282 | memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); |
@@ -287,7 +286,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
287 | if (supp_rates_len > 8) | 286 | if (supp_rates_len > 8) |
288 | supp_rates_len = 8; | 287 | supp_rates_len = 8; |
289 | 288 | ||
290 | len = sband->n_bitrates; | ||
291 | pos = skb_put(skb, supp_rates_len + 2); | 289 | pos = skb_put(skb, supp_rates_len + 2); |
292 | *pos++ = WLAN_EID_SUPP_RATES; | 290 | *pos++ = WLAN_EID_SUPP_RATES; |
293 | *pos++ = supp_rates_len; | 291 | *pos++ = supp_rates_len; |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index f1765de2f4bf..9dc3b5f26e80 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -87,42 +87,76 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) | |||
87 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 87 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
88 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 88 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
89 | 89 | ||
90 | /* No way to verify the MIC if the hardware stripped it */ | 90 | /* |
91 | if (status->flag & RX_FLAG_MMIC_STRIPPED) | 91 | * it makes no sense to check for MIC errors on anything other |
92 | * than data frames. | ||
93 | */ | ||
94 | if (!ieee80211_is_data_present(hdr->frame_control)) | ||
95 | return RX_CONTINUE; | ||
96 | |||
97 | /* | ||
98 | * No way to verify the MIC if the hardware stripped it or | ||
99 | * the IV with the key index. In this case we have solely rely | ||
100 | * on the driver to set RX_FLAG_MMIC_ERROR in the event of a | ||
101 | * MIC failure report. | ||
102 | */ | ||
103 | if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) { | ||
104 | if (status->flag & RX_FLAG_MMIC_ERROR) | ||
105 | goto mic_fail; | ||
106 | |||
107 | if (!(status->flag & RX_FLAG_IV_STRIPPED)) | ||
108 | goto update_iv; | ||
109 | |||
92 | return RX_CONTINUE; | 110 | return RX_CONTINUE; |
111 | } | ||
93 | 112 | ||
113 | /* | ||
114 | * Some hardware seems to generate Michael MIC failure reports; even | ||
115 | * though, the frame was not encrypted with TKIP and therefore has no | ||
116 | * MIC. Ignore the flag them to avoid triggering countermeasures. | ||
117 | */ | ||
94 | if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP || | 118 | if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP || |
95 | !ieee80211_has_protected(hdr->frame_control) || | 119 | !(status->flag & RX_FLAG_DECRYPTED)) |
96 | !ieee80211_is_data_present(hdr->frame_control)) | ||
97 | return RX_CONTINUE; | 120 | return RX_CONTINUE; |
98 | 121 | ||
122 | if (rx->sdata->vif.type == NL80211_IFTYPE_AP && rx->key->conf.keyidx) { | ||
123 | /* | ||
124 | * APs with pairwise keys should never receive Michael MIC | ||
125 | * errors for non-zero keyidx because these are reserved for | ||
126 | * group keys and only the AP is sending real multicast | ||
127 | * frames in the BSS. ( | ||
128 | */ | ||
129 | return RX_DROP_UNUSABLE; | ||
130 | } | ||
131 | |||
132 | if (status->flag & RX_FLAG_MMIC_ERROR) | ||
133 | goto mic_fail; | ||
134 | |||
99 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 135 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
100 | if (skb->len < hdrlen + MICHAEL_MIC_LEN) | 136 | if (skb->len < hdrlen + MICHAEL_MIC_LEN) |
101 | return RX_DROP_UNUSABLE; | 137 | return RX_DROP_UNUSABLE; |
102 | 138 | ||
103 | data = skb->data + hdrlen; | 139 | data = skb->data + hdrlen; |
104 | data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; | 140 | data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; |
105 | |||
106 | key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; | 141 | key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; |
107 | michael_mic(key, hdr, data, data_len, mic); | 142 | michael_mic(key, hdr, data, data_len, mic); |
108 | if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) { | 143 | if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) |
109 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) | 144 | goto mic_fail; |
110 | return RX_DROP_UNUSABLE; | ||
111 | |||
112 | mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, | ||
113 | (void *) skb->data, NULL, | ||
114 | GFP_ATOMIC); | ||
115 | return RX_DROP_UNUSABLE; | ||
116 | } | ||
117 | 145 | ||
118 | /* remove Michael MIC from payload */ | 146 | /* remove Michael MIC from payload */ |
119 | skb_trim(skb, skb->len - MICHAEL_MIC_LEN); | 147 | skb_trim(skb, skb->len - MICHAEL_MIC_LEN); |
120 | 148 | ||
149 | update_iv: | ||
121 | /* update IV in key information to be able to detect replays */ | 150 | /* update IV in key information to be able to detect replays */ |
122 | rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32; | 151 | rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32; |
123 | rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16; | 152 | rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16; |
124 | 153 | ||
125 | return RX_CONTINUE; | 154 | return RX_CONTINUE; |
155 | |||
156 | mic_fail: | ||
157 | mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, | ||
158 | (void *) skb->data, NULL, GFP_ATOMIC); | ||
159 | return RX_DROP_UNUSABLE; | ||
126 | } | 160 | } |
127 | 161 | ||
128 | 162 | ||