diff options
Diffstat (limited to 'net/mac80211')
29 files changed, 835 insertions, 422 deletions
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 63d852cb4ca2..cd5125f77cc5 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -136,6 +136,14 @@ 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 | static void kfree_tid_tx(struct rcu_head *rcu_head) | 147 | static void kfree_tid_tx(struct rcu_head *rcu_head) |
140 | { | 148 | { |
141 | struct tid_ampdu_tx *tid_tx = | 149 | struct tid_ampdu_tx *tid_tx = |
@@ -149,19 +157,22 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
149 | bool tx) | 157 | bool tx) |
150 | { | 158 | { |
151 | struct ieee80211_local *local = sta->local; | 159 | struct ieee80211_local *local = sta->local; |
152 | struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 160 | struct tid_ampdu_tx *tid_tx; |
153 | int ret; | 161 | int ret; |
154 | 162 | ||
155 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 163 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
156 | 164 | ||
157 | if (!tid_tx) | ||
158 | return -ENOENT; | ||
159 | |||
160 | spin_lock_bh(&sta->lock); | 165 | spin_lock_bh(&sta->lock); |
161 | 166 | ||
167 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | ||
168 | if (!tid_tx) { | ||
169 | spin_unlock_bh(&sta->lock); | ||
170 | return -ENOENT; | ||
171 | } | ||
172 | |||
162 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { | 173 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { |
163 | /* not even started yet! */ | 174 | /* not even started yet! */ |
164 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | 175 | ieee80211_assign_tid_tx(sta, tid, NULL); |
165 | spin_unlock_bh(&sta->lock); | 176 | spin_unlock_bh(&sta->lock); |
166 | call_rcu(&tid_tx->rcu_head, kfree_tid_tx); | 177 | call_rcu(&tid_tx->rcu_head, kfree_tid_tx); |
167 | return 0; | 178 | return 0; |
@@ -283,13 +294,13 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid) | |||
283 | 294 | ||
284 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | 295 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) |
285 | { | 296 | { |
286 | struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 297 | struct tid_ampdu_tx *tid_tx; |
287 | struct ieee80211_local *local = sta->local; | 298 | struct ieee80211_local *local = sta->local; |
288 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 299 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
289 | u16 start_seq_num; | 300 | u16 start_seq_num; |
290 | int ret; | 301 | int ret; |
291 | 302 | ||
292 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 303 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
293 | 304 | ||
294 | /* | 305 | /* |
295 | * While we're asking the driver about the aggregation, | 306 | * While we're asking the driver about the aggregation, |
@@ -318,7 +329,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
318 | " tid %d\n", tid); | 329 | " tid %d\n", tid); |
319 | #endif | 330 | #endif |
320 | spin_lock_bh(&sta->lock); | 331 | spin_lock_bh(&sta->lock); |
321 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | 332 | ieee80211_assign_tid_tx(sta, tid, NULL); |
322 | spin_unlock_bh(&sta->lock); | 333 | spin_unlock_bh(&sta->lock); |
323 | 334 | ||
324 | ieee80211_wake_queue_agg(local, tid); | 335 | ieee80211_wake_queue_agg(local, tid); |
@@ -396,9 +407,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
396 | goto err_unlock_sta; | 407 | goto err_unlock_sta; |
397 | } | 408 | } |
398 | 409 | ||
399 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 410 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
400 | /* check if the TID is not in aggregation flow already */ | 411 | /* check if the TID is not in aggregation flow already */ |
401 | if (tid_tx) { | 412 | if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { |
402 | #ifdef CONFIG_MAC80211_HT_DEBUG | 413 | #ifdef CONFIG_MAC80211_HT_DEBUG |
403 | printk(KERN_DEBUG "BA request denied - session is not " | 414 | printk(KERN_DEBUG "BA request denied - session is not " |
404 | "idle on tid %u\n", tid); | 415 | "idle on tid %u\n", tid); |
@@ -433,8 +444,11 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
433 | sta->ampdu_mlme.dialog_token_allocator++; | 444 | sta->ampdu_mlme.dialog_token_allocator++; |
434 | tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator; | 445 | tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator; |
435 | 446 | ||
436 | /* finally, assign it to the array */ | 447 | /* |
437 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); | 448 | * Finally, assign it to the start array; the work item will |
449 | * collect it and move it to the normal array. | ||
450 | */ | ||
451 | sta->ampdu_mlme.tid_start_tx[tid] = tid_tx; | ||
438 | 452 | ||
439 | ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work); | 453 | ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work); |
440 | 454 | ||
@@ -480,16 +494,19 @@ ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid) | |||
480 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | 494 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, |
481 | struct sta_info *sta, u16 tid) | 495 | struct sta_info *sta, u16 tid) |
482 | { | 496 | { |
497 | struct tid_ampdu_tx *tid_tx; | ||
498 | |||
483 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 499 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
484 | 500 | ||
501 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | ||
502 | |||
485 | #ifdef CONFIG_MAC80211_HT_DEBUG | 503 | #ifdef CONFIG_MAC80211_HT_DEBUG |
486 | printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); | 504 | printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); |
487 | #endif | 505 | #endif |
488 | 506 | ||
489 | drv_ampdu_action(local, sta->sdata, | 507 | drv_ampdu_action(local, sta->sdata, |
490 | IEEE80211_AMPDU_TX_OPERATIONAL, | 508 | IEEE80211_AMPDU_TX_OPERATIONAL, |
491 | &sta->sta, tid, NULL, | 509 | &sta->sta, tid, NULL, tid_tx->buf_size); |
492 | sta->ampdu_mlme.tid_tx[tid]->buf_size); | ||
493 | 510 | ||
494 | /* | 511 | /* |
495 | * synchronize with TX path, while splicing the TX path | 512 | * synchronize with TX path, while splicing the TX path |
@@ -497,13 +514,13 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | |||
497 | */ | 514 | */ |
498 | spin_lock_bh(&sta->lock); | 515 | spin_lock_bh(&sta->lock); |
499 | 516 | ||
500 | ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid); | 517 | ieee80211_agg_splice_packets(local, tid_tx, tid); |
501 | /* | 518 | /* |
502 | * Now mark as operational. This will be visible | 519 | * Now mark as operational. This will be visible |
503 | * in the TX path, and lets it go lock-free in | 520 | * in the TX path, and lets it go lock-free in |
504 | * the common case. | 521 | * the common case. |
505 | */ | 522 | */ |
506 | set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state); | 523 | set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); |
507 | ieee80211_agg_splice_finish(local, tid); | 524 | ieee80211_agg_splice_finish(local, tid); |
508 | 525 | ||
509 | spin_unlock_bh(&sta->lock); | 526 | spin_unlock_bh(&sta->lock); |
@@ -537,7 +554,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) | |||
537 | } | 554 | } |
538 | 555 | ||
539 | mutex_lock(&sta->ampdu_mlme.mtx); | 556 | mutex_lock(&sta->ampdu_mlme.mtx); |
540 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 557 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
541 | 558 | ||
542 | if (WARN_ON(!tid_tx)) { | 559 | if (WARN_ON(!tid_tx)) { |
543 | #ifdef CONFIG_MAC80211_HT_DEBUG | 560 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -615,7 +632,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
615 | return -EINVAL; | 632 | return -EINVAL; |
616 | 633 | ||
617 | spin_lock_bh(&sta->lock); | 634 | spin_lock_bh(&sta->lock); |
618 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 635 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
619 | 636 | ||
620 | if (!tid_tx) { | 637 | if (!tid_tx) { |
621 | ret = -ENOENT; | 638 | ret = -ENOENT; |
@@ -671,7 +688,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
671 | 688 | ||
672 | mutex_lock(&sta->ampdu_mlme.mtx); | 689 | mutex_lock(&sta->ampdu_mlme.mtx); |
673 | spin_lock_bh(&sta->lock); | 690 | spin_lock_bh(&sta->lock); |
674 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 691 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
675 | 692 | ||
676 | if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | 693 | if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { |
677 | #ifdef CONFIG_MAC80211_HT_DEBUG | 694 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -697,7 +714,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
697 | ieee80211_agg_splice_packets(local, tid_tx, tid); | 714 | ieee80211_agg_splice_packets(local, tid_tx, tid); |
698 | 715 | ||
699 | /* future packets must not find the tid_tx struct any more */ | 716 | /* future packets must not find the tid_tx struct any more */ |
700 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | 717 | ieee80211_assign_tid_tx(sta, tid, NULL); |
701 | 718 | ||
702 | ieee80211_agg_splice_finish(local, tid); | 719 | ieee80211_agg_splice_finish(local, tid); |
703 | 720 | ||
@@ -752,7 +769,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
752 | 769 | ||
753 | mutex_lock(&sta->ampdu_mlme.mtx); | 770 | mutex_lock(&sta->ampdu_mlme.mtx); |
754 | 771 | ||
755 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 772 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
756 | if (!tid_tx) | 773 | if (!tid_tx) |
757 | goto out; | 774 | goto out; |
758 | 775 | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 12d52cec9515..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; |
@@ -468,7 +463,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
468 | int size; | 463 | int size; |
469 | int err = -EINVAL; | 464 | int err = -EINVAL; |
470 | 465 | ||
471 | old = sdata->u.ap.beacon; | 466 | old = rtnl_dereference(sdata->u.ap.beacon); |
472 | 467 | ||
473 | /* head must not be zero-length */ | 468 | /* head must not be zero-length */ |
474 | if (params->head && !params->head_len) | 469 | if (params->head && !params->head_len) |
@@ -563,8 +558,7 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
563 | 558 | ||
564 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 559 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
565 | 560 | ||
566 | old = sdata->u.ap.beacon; | 561 | old = rtnl_dereference(sdata->u.ap.beacon); |
567 | |||
568 | if (old) | 562 | if (old) |
569 | return -EALREADY; | 563 | return -EALREADY; |
570 | 564 | ||
@@ -579,8 +573,7 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
579 | 573 | ||
580 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 574 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
581 | 575 | ||
582 | old = sdata->u.ap.beacon; | 576 | old = rtnl_dereference(sdata->u.ap.beacon); |
583 | |||
584 | if (!old) | 577 | if (!old) |
585 | return -ENOENT; | 578 | return -ENOENT; |
586 | 579 | ||
@@ -594,8 +587,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) | |||
594 | 587 | ||
595 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 588 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
596 | 589 | ||
597 | old = sdata->u.ap.beacon; | 590 | old = rtnl_dereference(sdata->u.ap.beacon); |
598 | |||
599 | if (!old) | 591 | if (!old) |
600 | return -ENOENT; | 592 | return -ENOENT; |
601 | 593 | ||
@@ -734,15 +726,29 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
734 | params->ht_capa, | 726 | params->ht_capa, |
735 | &sta->sta.ht_cap); | 727 | &sta->sta.ht_cap); |
736 | 728 | ||
737 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { | 729 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
738 | switch (params->plink_action) { | 730 | #ifdef CONFIG_MAC80211_MESH |
739 | case PLINK_ACTION_OPEN: | 731 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) |
740 | mesh_plink_open(sta); | 732 | switch (params->plink_state) { |
741 | break; | 733 | case NL80211_PLINK_LISTEN: |
742 | case PLINK_ACTION_BLOCK: | 734 | case NL80211_PLINK_ESTAB: |
743 | mesh_plink_block(sta); | 735 | case NL80211_PLINK_BLOCKED: |
744 | break; | 736 | sta->plink_state = params->plink_state; |
745 | } | 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 | ||
746 | } | 752 | } |
747 | } | 753 | } |
748 | 754 | ||
@@ -943,8 +949,10 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, | |||
943 | 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, |
944 | struct mpath_info *pinfo) | 950 | struct mpath_info *pinfo) |
945 | { | 951 | { |
946 | if (mpath->next_hop) | 952 | struct sta_info *next_hop_sta = rcu_dereference(mpath->next_hop); |
947 | 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); | ||
948 | else | 956 | else |
949 | memset(next_hop, 0, ETH_ALEN); | 957 | memset(next_hop, 0, ETH_ALEN); |
950 | 958 | ||
@@ -1064,7 +1072,11 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, | |||
1064 | memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); | 1072 | memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); |
1065 | ifmsh->mesh_pp_id = setup->path_sel_proto; | 1073 | ifmsh->mesh_pp_id = setup->path_sel_proto; |
1066 | ifmsh->mesh_pm_id = setup->path_metric; | 1074 | ifmsh->mesh_pm_id = setup->path_metric; |
1067 | ifmsh->is_secure = setup->is_secure; | 1075 | ifmsh->security = IEEE80211_MESH_SEC_NONE; |
1076 | if (setup->is_authenticated) | ||
1077 | ifmsh->security |= IEEE80211_MESH_SEC_AUTHED; | ||
1078 | if (setup->is_secure) | ||
1079 | ifmsh->security |= IEEE80211_MESH_SEC_SECURED; | ||
1068 | 1080 | ||
1069 | return 0; | 1081 | return 0; |
1070 | } | 1082 | } |
@@ -1297,9 +1309,10 @@ static int ieee80211_set_channel(struct wiphy *wiphy, | |||
1297 | } | 1309 | } |
1298 | 1310 | ||
1299 | #ifdef CONFIG_PM | 1311 | #ifdef CONFIG_PM |
1300 | static int ieee80211_suspend(struct wiphy *wiphy) | 1312 | static int ieee80211_suspend(struct wiphy *wiphy, |
1313 | struct cfg80211_wowlan *wowlan) | ||
1301 | { | 1314 | { |
1302 | return __ieee80211_suspend(wiphy_priv(wiphy)); | 1315 | return __ieee80211_suspend(wiphy_priv(wiphy), wowlan); |
1303 | } | 1316 | } |
1304 | 1317 | ||
1305 | static int ieee80211_resume(struct wiphy *wiphy) | 1318 | static int ieee80211_resume(struct wiphy *wiphy) |
@@ -1342,6 +1355,30 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
1342 | return ieee80211_request_scan(sdata, req); | 1355 | return ieee80211_request_scan(sdata, req); |
1343 | } | 1356 | } |
1344 | 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 | |||
1345 | static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, | 1382 | static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, |
1346 | struct cfg80211_auth_request *req) | 1383 | struct cfg80211_auth_request *req) |
1347 | { | 1384 | { |
@@ -2083,6 +2120,8 @@ struct cfg80211_ops mac80211_config_ops = { | |||
2083 | .suspend = ieee80211_suspend, | 2120 | .suspend = ieee80211_suspend, |
2084 | .resume = ieee80211_resume, | 2121 | .resume = ieee80211_resume, |
2085 | .scan = ieee80211_scan, | 2122 | .scan = ieee80211_scan, |
2123 | .sched_scan_start = ieee80211_sched_scan_start, | ||
2124 | .sched_scan_stop = ieee80211_sched_scan_stop, | ||
2086 | .auth = ieee80211_auth, | 2125 | .auth = ieee80211_auth, |
2087 | .assoc = ieee80211_assoc, | 2126 | .assoc = ieee80211_assoc, |
2088 | .deauth = ieee80211_deauth, | 2127 | .deauth = ieee80211_deauth, |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 0a602dbfdb2b..186e02f7cc32 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -135,7 +135,7 @@ static ssize_t reset_write(struct file *file, const char __user *user_buf, | |||
135 | struct ieee80211_local *local = file->private_data; | 135 | struct ieee80211_local *local = file->private_data; |
136 | 136 | ||
137 | rtnl_lock(); | 137 | rtnl_lock(); |
138 | __ieee80211_suspend(&local->hw); | 138 | __ieee80211_suspend(&local->hw, NULL); |
139 | __ieee80211_resume(&local->hw); | 139 | __ieee80211_resume(&local->hw); |
140 | rtnl_unlock(); | 140 | rtnl_unlock(); |
141 | 141 | ||
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/driver-ops.h b/net/mac80211/driver-ops.h index 2ddb56e5b51f..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(); |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 191e834ec46b..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) |
@@ -108,33 +172,25 @@ DEFINE_EVENT(local_only_evt, drv_start, | |||
108 | TP_ARGS(local) | 172 | TP_ARGS(local) |
109 | ); | 173 | ); |
110 | 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 | |||
111 | DEFINE_EVENT(local_only_evt, drv_stop, | 185 | DEFINE_EVENT(local_only_evt, drv_stop, |
112 | TP_PROTO(struct ieee80211_local *local), | 186 | TP_PROTO(struct ieee80211_local *local), |
113 | TP_ARGS(local) | 187 | TP_ARGS(local) |
114 | ); | 188 | ); |
115 | 189 | ||
116 | TRACE_EVENT(drv_add_interface, | 190 | DEFINE_EVENT(local_sdata_addr_evt, drv_add_interface, |
117 | TP_PROTO(struct ieee80211_local *local, | 191 | TP_PROTO(struct ieee80211_local *local, |
118 | struct ieee80211_sub_if_data *sdata), | 192 | struct ieee80211_sub_if_data *sdata), |
119 | 193 | TP_ARGS(local, sdata) | |
120 | TP_ARGS(local, sdata), | ||
121 | |||
122 | TP_STRUCT__entry( | ||
123 | LOCAL_ENTRY | ||
124 | VIF_ENTRY | ||
125 | __array(char, addr, 6) | ||
126 | ), | ||
127 | |||
128 | TP_fast_assign( | ||
129 | LOCAL_ASSIGN; | ||
130 | VIF_ASSIGN; | ||
131 | memcpy(__entry->addr, sdata->vif.addr, 6); | ||
132 | ), | ||
133 | |||
134 | TP_printk( | ||
135 | LOCAL_PR_FMT VIF_PR_FMT " addr:%pM", | ||
136 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr | ||
137 | ) | ||
138 | ); | 194 | ); |
139 | 195 | ||
140 | TRACE_EVENT(drv_change_interface, | 196 | TRACE_EVENT(drv_change_interface, |
@@ -165,27 +221,10 @@ TRACE_EVENT(drv_change_interface, | |||
165 | ) | 221 | ) |
166 | ); | 222 | ); |
167 | 223 | ||
168 | TRACE_EVENT(drv_remove_interface, | 224 | DEFINE_EVENT(local_sdata_addr_evt, drv_remove_interface, |
169 | TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata), | 225 | TP_PROTO(struct ieee80211_local *local, |
170 | 226 | struct ieee80211_sub_if_data *sdata), | |
171 | TP_ARGS(local, sdata), | 227 | TP_ARGS(local, sdata) |
172 | |||
173 | TP_STRUCT__entry( | ||
174 | LOCAL_ENTRY | ||
175 | VIF_ENTRY | ||
176 | __array(char, addr, 6) | ||
177 | ), | ||
178 | |||
179 | TP_fast_assign( | ||
180 | LOCAL_ASSIGN; | ||
181 | VIF_ASSIGN; | ||
182 | memcpy(__entry->addr, sdata->vif.addr, 6); | ||
183 | ), | ||
184 | |||
185 | TP_printk( | ||
186 | LOCAL_PR_FMT VIF_PR_FMT " addr:%pM", | ||
187 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr | ||
188 | ) | ||
189 | ); | 228 | ); |
190 | 229 | ||
191 | TRACE_EVENT(drv_config, | 230 | TRACE_EVENT(drv_config, |
@@ -415,27 +454,22 @@ TRACE_EVENT(drv_update_tkip_key, | |||
415 | ) | 454 | ) |
416 | ); | 455 | ); |
417 | 456 | ||
418 | TRACE_EVENT(drv_hw_scan, | 457 | DEFINE_EVENT(local_sdata_evt, drv_hw_scan, |
419 | TP_PROTO(struct ieee80211_local *local, | 458 | TP_PROTO(struct ieee80211_local *local, |
420 | struct ieee80211_sub_if_data *sdata, | 459 | struct ieee80211_sub_if_data *sdata), |
421 | struct cfg80211_scan_request *req), | 460 | TP_ARGS(local, sdata) |
422 | 461 | ); | |
423 | TP_ARGS(local, sdata, req), | ||
424 | |||
425 | TP_STRUCT__entry( | ||
426 | LOCAL_ENTRY | ||
427 | VIF_ENTRY | ||
428 | ), | ||
429 | 462 | ||
430 | TP_fast_assign( | 463 | DEFINE_EVENT(local_sdata_evt, drv_sched_scan_start, |
431 | LOCAL_ASSIGN; | 464 | TP_PROTO(struct ieee80211_local *local, |
432 | VIF_ASSIGN; | 465 | struct ieee80211_sub_if_data *sdata), |
433 | ), | 466 | TP_ARGS(local, sdata) |
467 | ); | ||
434 | 468 | ||
435 | TP_printk( | 469 | DEFINE_EVENT(local_sdata_evt, drv_sched_scan_stop, |
436 | LOCAL_PR_FMT VIF_PR_FMT, | 470 | TP_PROTO(struct ieee80211_local *local, |
437 | LOCAL_PR_ARG,VIF_PR_ARG | 471 | struct ieee80211_sub_if_data *sdata), |
438 | ) | 472 | TP_ARGS(local, sdata) |
439 | ); | 473 | ); |
440 | 474 | ||
441 | DEFINE_EVENT(local_only_evt, drv_sw_scan_start, | 475 | DEFINE_EVENT(local_only_evt, drv_sw_scan_start, |
@@ -504,46 +538,14 @@ TRACE_EVENT(drv_get_tkip_seq, | |||
504 | ) | 538 | ) |
505 | ); | 539 | ); |
506 | 540 | ||
507 | TRACE_EVENT(drv_set_frag_threshold, | 541 | DEFINE_EVENT(local_u32_evt, drv_set_frag_threshold, |
508 | TP_PROTO(struct ieee80211_local *local, u32 value), | 542 | TP_PROTO(struct ieee80211_local *local, u32 value), |
509 | 543 | TP_ARGS(local, value) | |
510 | TP_ARGS(local, value), | ||
511 | |||
512 | TP_STRUCT__entry( | ||
513 | LOCAL_ENTRY | ||
514 | __field(u32, value) | ||
515 | ), | ||
516 | |||
517 | TP_fast_assign( | ||
518 | LOCAL_ASSIGN; | ||
519 | __entry->value = value; | ||
520 | ), | ||
521 | |||
522 | TP_printk( | ||
523 | LOCAL_PR_FMT " value:%d", | ||
524 | LOCAL_PR_ARG, __entry->value | ||
525 | ) | ||
526 | ); | 544 | ); |
527 | 545 | ||
528 | TRACE_EVENT(drv_set_rts_threshold, | 546 | DEFINE_EVENT(local_u32_evt, drv_set_rts_threshold, |
529 | TP_PROTO(struct ieee80211_local *local, u32 value), | 547 | TP_PROTO(struct ieee80211_local *local, u32 value), |
530 | 548 | TP_ARGS(local, value) | |
531 | TP_ARGS(local, value), | ||
532 | |||
533 | TP_STRUCT__entry( | ||
534 | LOCAL_ENTRY | ||
535 | __field(u32, value) | ||
536 | ), | ||
537 | |||
538 | TP_fast_assign( | ||
539 | LOCAL_ASSIGN; | ||
540 | __entry->value = value; | ||
541 | ), | ||
542 | |||
543 | TP_printk( | ||
544 | LOCAL_PR_FMT " value:%d", | ||
545 | LOCAL_PR_ARG, __entry->value | ||
546 | ) | ||
547 | ); | 549 | ); |
548 | 550 | ||
549 | TRACE_EVENT(drv_set_coverage_class, | 551 | TRACE_EVENT(drv_set_coverage_class, |
@@ -1194,6 +1196,42 @@ TRACE_EVENT(api_scan_completed, | |||
1194 | ) | 1196 | ) |
1195 | ); | 1197 | ); |
1196 | 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 | |||
1197 | TRACE_EVENT(api_sta_block_awake, | 1235 | TRACE_EVENT(api_sta_block_awake, |
1198 | TP_PROTO(struct ieee80211_local *local, | 1236 | TP_PROTO(struct ieee80211_local *local, |
1199 | 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 b81860c94698..421eaa6b0c2b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -662,12 +662,16 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
662 | int tx_last_beacon, len = req->len; | 662 | int tx_last_beacon, len = req->len; |
663 | struct sk_buff *skb; | 663 | struct sk_buff *skb; |
664 | struct ieee80211_mgmt *resp; | 664 | struct ieee80211_mgmt *resp; |
665 | struct sk_buff *presp; | ||
665 | u8 *pos, *end; | 666 | u8 *pos, *end; |
666 | 667 | ||
667 | lockdep_assert_held(&ifibss->mtx); | 668 | lockdep_assert_held(&ifibss->mtx); |
668 | 669 | ||
670 | presp = rcu_dereference_protected(ifibss->presp, | ||
671 | lockdep_is_held(&ifibss->mtx)); | ||
672 | |||
669 | if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || | 673 | if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || |
670 | len < 24 + 2 || !ifibss->presp) | 674 | len < 24 + 2 || !presp) |
671 | return; | 675 | return; |
672 | 676 | ||
673 | tx_last_beacon = drv_tx_last_beacon(local); | 677 | tx_last_beacon = drv_tx_last_beacon(local); |
@@ -705,7 +709,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
705 | } | 709 | } |
706 | 710 | ||
707 | /* Reply with ProbeResp */ | 711 | /* Reply with ProbeResp */ |
708 | skb = skb_copy(ifibss->presp, GFP_KERNEL); | 712 | skb = skb_copy(presp, GFP_KERNEL); |
709 | if (!skb) | 713 | if (!skb) |
710 | return; | 714 | return; |
711 | 715 | ||
@@ -985,7 +989,8 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
985 | 989 | ||
986 | /* remove beacon */ | 990 | /* remove beacon */ |
987 | kfree(sdata->u.ibss.ie); | 991 | kfree(sdata->u.ibss.ie); |
988 | skb = sdata->u.ibss.presp; | 992 | skb = rcu_dereference_protected(sdata->u.ibss.presp, |
993 | lockdep_is_held(&sdata->u.ibss.mtx)); | ||
989 | rcu_assign_pointer(sdata->u.ibss.presp, NULL); | 994 | rcu_assign_pointer(sdata->u.ibss.presp, NULL); |
990 | sdata->vif.bss_conf.ibss_joined = false; | 995 | sdata->vif.bss_conf.ibss_joined = false; |
991 | 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 027c0467d7a3..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, |
@@ -490,7 +491,11 @@ struct ieee80211_if_mesh { | |||
490 | bool accepting_plinks; | 491 | bool accepting_plinks; |
491 | const u8 *ie; | 492 | const u8 *ie; |
492 | u8 ie_len; | 493 | u8 ie_len; |
493 | bool is_secure; | 494 | enum { |
495 | IEEE80211_MESH_SEC_NONE = 0x0, | ||
496 | IEEE80211_MESH_SEC_AUTHED = 0x1, | ||
497 | IEEE80211_MESH_SEC_SECURED = 0x2, | ||
498 | } security; | ||
494 | }; | 499 | }; |
495 | 500 | ||
496 | #ifdef CONFIG_MAC80211_MESH | 501 | #ifdef CONFIG_MAC80211_MESH |
@@ -563,9 +568,10 @@ struct ieee80211_sub_if_data { | |||
563 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; | 568 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; |
564 | unsigned int fragment_next; | 569 | unsigned int fragment_next; |
565 | 570 | ||
566 | struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | 571 | struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
567 | struct ieee80211_key *default_unicast_key, *default_multicast_key; | 572 | struct ieee80211_key __rcu *default_unicast_key; |
568 | struct ieee80211_key *default_mgmt_key; | 573 | struct ieee80211_key __rcu *default_multicast_key; |
574 | struct ieee80211_key __rcu *default_mgmt_key; | ||
569 | 575 | ||
570 | u16 sequence_number; | 576 | u16 sequence_number; |
571 | __be16 control_port_protocol; | 577 | __be16 control_port_protocol; |
@@ -764,6 +770,9 @@ struct ieee80211_local { | |||
764 | /* device is started */ | 770 | /* device is started */ |
765 | bool started; | 771 | bool started; |
766 | 772 | ||
773 | /* wowlan is enabled -- don't reconfig on resume */ | ||
774 | bool wowlan; | ||
775 | |||
767 | int tx_headroom; /* required headroom for hardware/radiotap */ | 776 | int tx_headroom; /* required headroom for hardware/radiotap */ |
768 | 777 | ||
769 | /* count for keys needing tailroom space allocation */ | 778 | /* count for keys needing tailroom space allocation */ |
@@ -798,7 +807,7 @@ struct ieee80211_local { | |||
798 | spinlock_t sta_lock; | 807 | spinlock_t sta_lock; |
799 | unsigned long num_sta; | 808 | unsigned long num_sta; |
800 | struct list_head sta_list, sta_pending_list; | 809 | struct list_head sta_list, sta_pending_list; |
801 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 810 | struct sta_info __rcu *sta_hash[STA_HASH_SIZE]; |
802 | struct timer_list sta_cleanup; | 811 | struct timer_list sta_cleanup; |
803 | struct work_struct sta_finish_work; | 812 | struct work_struct sta_finish_work; |
804 | int sta_generation; | 813 | int sta_generation; |
@@ -840,6 +849,10 @@ struct ieee80211_local { | |||
840 | int scan_channel_idx; | 849 | int scan_channel_idx; |
841 | int scan_ies_len; | 850 | int scan_ies_len; |
842 | 851 | ||
852 | bool sched_scanning; | ||
853 | struct ieee80211_sched_scan_ies sched_scan_ies; | ||
854 | struct work_struct sched_scan_stopped_work; | ||
855 | |||
843 | unsigned long leave_oper_channel_time; | 856 | unsigned long leave_oper_channel_time; |
844 | enum mac80211_scan_state next_scan_state; | 857 | enum mac80211_scan_state next_scan_state; |
845 | struct delayed_work scan_work; | 858 | struct delayed_work scan_work; |
@@ -1147,6 +1160,12 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | |||
1147 | void ieee80211_rx_bss_put(struct ieee80211_local *local, | 1160 | void ieee80211_rx_bss_put(struct ieee80211_local *local, |
1148 | struct ieee80211_bss *bss); | 1161 | struct ieee80211_bss *bss); |
1149 | 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 | |||
1150 | /* off-channel helpers */ | 1169 | /* off-channel helpers */ |
1151 | bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local); | 1170 | bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local); |
1152 | void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local, | 1171 | void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local, |
@@ -1250,7 +1269,8 @@ int ieee80211_reconfig(struct ieee80211_local *local); | |||
1250 | void ieee80211_stop_device(struct ieee80211_local *local); | 1269 | void ieee80211_stop_device(struct ieee80211_local *local); |
1251 | 1270 | ||
1252 | #ifdef CONFIG_PM | 1271 | #ifdef CONFIG_PM |
1253 | int __ieee80211_suspend(struct ieee80211_hw *hw); | 1272 | int __ieee80211_suspend(struct ieee80211_hw *hw, |
1273 | struct cfg80211_wowlan *wowlan); | ||
1254 | 1274 | ||
1255 | static inline int __ieee80211_resume(struct ieee80211_hw *hw) | 1275 | static inline int __ieee80211_resume(struct ieee80211_hw *hw) |
1256 | { | 1276 | { |
@@ -1263,7 +1283,8 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw) | |||
1263 | return ieee80211_reconfig(hw_to_local(hw)); | 1283 | return ieee80211_reconfig(hw_to_local(hw)); |
1264 | } | 1284 | } |
1265 | #else | 1285 | #else |
1266 | static inline int __ieee80211_suspend(struct ieee80211_hw *hw) | 1286 | static inline int __ieee80211_suspend(struct ieee80211_hw *hw, |
1287 | struct cfg80211_wowlan *wowlan) | ||
1267 | { | 1288 | { |
1268 | return 0; | 1289 | return 0; |
1269 | } | 1290 | } |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 80c29d626aa4..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, |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index b510721e3b3d..31afd712930d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -195,7 +195,7 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, | |||
195 | assert_key_lock(sdata->local); | 195 | assert_key_lock(sdata->local); |
196 | 196 | ||
197 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) | 197 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) |
198 | key = sdata->keys[idx]; | 198 | key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
199 | 199 | ||
200 | if (uni) | 200 | if (uni) |
201 | rcu_assign_pointer(sdata->default_unicast_key, key); | 201 | rcu_assign_pointer(sdata->default_unicast_key, key); |
@@ -222,7 +222,7 @@ __ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx) | |||
222 | 222 | ||
223 | if (idx >= NUM_DEFAULT_KEYS && | 223 | if (idx >= NUM_DEFAULT_KEYS && |
224 | idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) | 224 | idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) |
225 | key = sdata->keys[idx]; | 225 | key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
226 | 226 | ||
227 | rcu_assign_pointer(sdata->default_mgmt_key, key); | 227 | rcu_assign_pointer(sdata->default_mgmt_key, key); |
228 | 228 | ||
@@ -266,9 +266,15 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
266 | else | 266 | else |
267 | idx = new->conf.keyidx; | 267 | idx = new->conf.keyidx; |
268 | 268 | ||
269 | defunikey = old && sdata->default_unicast_key == old; | 269 | defunikey = old && |
270 | defmultikey = old && sdata->default_multicast_key == old; | 270 | old == key_mtx_dereference(sdata->local, |
271 | 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); | ||
272 | 278 | ||
273 | if (defunikey && !new) | 279 | if (defunikey && !new) |
274 | __ieee80211_set_default_key(sdata, -1, true, false); | 280 | __ieee80211_set_default_key(sdata, -1, true, false); |
@@ -451,11 +457,11 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
451 | mutex_lock(&sdata->local->key_mtx); | 457 | mutex_lock(&sdata->local->key_mtx); |
452 | 458 | ||
453 | if (sta && pairwise) | 459 | if (sta && pairwise) |
454 | old_key = sta->ptk; | 460 | old_key = key_mtx_dereference(sdata->local, sta->ptk); |
455 | else if (sta) | 461 | else if (sta) |
456 | old_key = sta->gtk[idx]; | 462 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); |
457 | else | 463 | else |
458 | old_key = sdata->keys[idx]; | 464 | old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
459 | 465 | ||
460 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); | 466 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); |
461 | __ieee80211_key_destroy(old_key); | 467 | __ieee80211_key_destroy(old_key); |
@@ -471,8 +477,11 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
471 | return ret; | 477 | return ret; |
472 | } | 478 | } |
473 | 479 | ||
474 | static void __ieee80211_key_free(struct ieee80211_key *key) | 480 | void __ieee80211_key_free(struct ieee80211_key *key) |
475 | { | 481 | { |
482 | if (!key) | ||
483 | return; | ||
484 | |||
476 | /* | 485 | /* |
477 | * Replace key with nothingness if it was ever used. | 486 | * Replace key with nothingness if it was ever used. |
478 | */ | 487 | */ |
@@ -486,9 +495,6 @@ static void __ieee80211_key_free(struct ieee80211_key *key) | |||
486 | void ieee80211_key_free(struct ieee80211_local *local, | 495 | void ieee80211_key_free(struct ieee80211_local *local, |
487 | struct ieee80211_key *key) | 496 | struct ieee80211_key *key) |
488 | { | 497 | { |
489 | if (!key) | ||
490 | return; | ||
491 | |||
492 | mutex_lock(&local->key_mtx); | 498 | mutex_lock(&local->key_mtx); |
493 | __ieee80211_key_free(key); | 499 | __ieee80211_key_free(key); |
494 | mutex_unlock(&local->key_mtx); | 500 | mutex_unlock(&local->key_mtx); |
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 61877662e8f8..0d7b08db8e56 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -358,7 +358,8 @@ static void ieee80211_restart_work(struct work_struct *work) | |||
358 | flush_workqueue(local->workqueue); | 358 | flush_workqueue(local->workqueue); |
359 | 359 | ||
360 | mutex_lock(&local->mtx); | 360 | mutex_lock(&local->mtx); |
361 | WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), | 361 | WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) || |
362 | local->sched_scanning, | ||
362 | "%s called with hardware scan in progress\n", __func__); | 363 | "%s called with hardware scan in progress\n", __func__); |
363 | mutex_unlock(&local->mtx); | 364 | mutex_unlock(&local->mtx); |
364 | 365 | ||
@@ -580,8 +581,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
580 | 581 | ||
581 | wiphy->flags |= WIPHY_FLAG_NETNS_OK | | 582 | wiphy->flags |= WIPHY_FLAG_NETNS_OK | |
582 | WIPHY_FLAG_4ADDR_AP | | 583 | WIPHY_FLAG_4ADDR_AP | |
583 | WIPHY_FLAG_4ADDR_STATION | | 584 | WIPHY_FLAG_4ADDR_STATION; |
584 | WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS; | ||
585 | 585 | ||
586 | if (!ops->set_key) | 586 | if (!ops->set_key) |
587 | wiphy->flags |= WIPHY_FLAG_IBSS_RSN; | 587 | wiphy->flags |= WIPHY_FLAG_IBSS_RSN; |
@@ -652,6 +652,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
652 | setup_timer(&local->dynamic_ps_timer, | 652 | setup_timer(&local->dynamic_ps_timer, |
653 | ieee80211_dynamic_ps_timer, (unsigned long) local); | 653 | ieee80211_dynamic_ps_timer, (unsigned long) local); |
654 | 654 | ||
655 | INIT_WORK(&local->sched_scan_stopped_work, | ||
656 | ieee80211_sched_scan_stopped_work); | ||
657 | |||
655 | sta_info_init(local); | 658 | sta_info_init(local); |
656 | 659 | ||
657 | for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { | 660 | for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { |
@@ -682,7 +685,7 @@ EXPORT_SYMBOL(ieee80211_alloc_hw); | |||
682 | int ieee80211_register_hw(struct ieee80211_hw *hw) | 685 | int ieee80211_register_hw(struct ieee80211_hw *hw) |
683 | { | 686 | { |
684 | struct ieee80211_local *local = hw_to_local(hw); | 687 | struct ieee80211_local *local = hw_to_local(hw); |
685 | int result; | 688 | int result, i; |
686 | enum ieee80211_band band; | 689 | enum ieee80211_band band; |
687 | int channels, max_bitrates; | 690 | int channels, max_bitrates; |
688 | bool supp_ht; | 691 | bool supp_ht; |
@@ -697,6 +700,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
697 | WLAN_CIPHER_SUITE_AES_CMAC | 700 | WLAN_CIPHER_SUITE_AES_CMAC |
698 | }; | 701 | }; |
699 | 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 | |||
700 | if (hw->max_report_rates == 0) | 710 | if (hw->max_report_rates == 0) |
701 | hw->max_report_rates = hw->max_rates; | 711 | hw->max_report_rates = hw->max_rates; |
702 | 712 | ||
@@ -733,11 +743,19 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
733 | return -ENOMEM; | 743 | return -ENOMEM; |
734 | 744 | ||
735 | /* if low-level driver supports AP, we also support VLAN */ | 745 | /* if low-level driver supports AP, we also support VLAN */ |
736 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) | 746 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { |
737 | 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 | } | ||
738 | 750 | ||
739 | /* mac80211 always supports monitor */ | 751 | /* mac80211 always supports monitor */ |
740 | 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; | ||
741 | 759 | ||
742 | #ifndef CONFIG_MAC80211_MESH | 760 | #ifndef CONFIG_MAC80211_MESH |
743 | /* 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 */ |
@@ -827,6 +845,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
827 | if (!local->ops->remain_on_channel) | 845 | if (!local->ops->remain_on_channel) |
828 | local->hw.wiphy->max_remain_on_channel_duration = 5000; | 846 | local->hw.wiphy->max_remain_on_channel_duration = 5000; |
829 | 847 | ||
848 | if (local->ops->sched_scan_start) | ||
849 | local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | ||
850 | |||
830 | result = wiphy_register(local->hw.wiphy); | 851 | result = wiphy_register(local->hw.wiphy); |
831 | if (result < 0) | 852 | if (result < 0) |
832 | goto fail_wiphy_register; | 853 | goto fail_wiphy_register; |
@@ -850,8 +871,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
850 | * and we need some headroom for passing the frame to monitor | 871 | * and we need some headroom for passing the frame to monitor |
851 | * interfaces, but never both at the same time. | 872 | * interfaces, but never both at the same time. |
852 | */ | 873 | */ |
874 | #ifndef __CHECKER__ | ||
853 | BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM != | 875 | BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM != |
854 | sizeof(struct ieee80211_tx_status_rtap_hdr)); | 876 | sizeof(struct ieee80211_tx_status_rtap_hdr)); |
877 | #endif | ||
855 | 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, |
856 | sizeof(struct ieee80211_tx_status_rtap_hdr)); | 879 | sizeof(struct ieee80211_tx_status_rtap_hdr)); |
857 | 880 | ||
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index c1299e249541..29e9980c8e60 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -287,49 +287,6 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
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 | { |
@@ -574,7 +531,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
574 | &elems); | 531 | &elems); |
575 | 532 | ||
576 | /* ignore beacons from secure mesh peers if our security is off */ | 533 | /* ignore beacons from secure mesh peers if our security is off */ |
577 | if (elems.rsn_len && !sdata->u.mesh.is_secure) | 534 | if (elems.rsn_len && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) |
578 | return; | 535 | return; |
579 | 536 | ||
580 | if (elems.ds_params && elems.ds_params_len == 1) | 537 | if (elems.ds_params && elems.ds_params_len == 1) |
@@ -600,7 +557,7 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | |||
600 | struct ieee80211_rx_status *rx_status) | 557 | struct ieee80211_rx_status *rx_status) |
601 | { | 558 | { |
602 | switch (mgmt->u.action.category) { | 559 | switch (mgmt->u.action.category) { |
603 | case WLAN_CATEGORY_MESH_PLINK: | 560 | case WLAN_CATEGORY_MESH_ACTION: |
604 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); | 561 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); |
605 | break; | 562 | break; |
606 | case WLAN_CATEGORY_MESH_PATH_SEL: | 563 | case WLAN_CATEGORY_MESH_PATH_SEL: |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 10acf1cc8082..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; |
@@ -240,12 +240,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
240 | 240 | ||
241 | /* Private interfaces */ | 241 | /* Private interfaces */ |
242 | /* Mesh tables */ | 242 | /* Mesh tables */ |
243 | struct mesh_table *mesh_table_alloc(int size_order); | ||
244 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs); | ||
245 | void mesh_mpath_table_grow(void); | 243 | void mesh_mpath_table_grow(void); |
246 | void mesh_mpp_table_grow(void); | 244 | void mesh_mpp_table_grow(void); |
247 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, | ||
248 | struct mesh_table *tbl); | ||
249 | /* Mesh paths */ | 245 | /* Mesh paths */ |
250 | 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, |
251 | 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 e57f2e728cfe..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); |
@@ -652,7 +659,8 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | |||
652 | if (mpath) { | 659 | if (mpath) { |
653 | spin_lock_bh(&mpath->state_lock); | 660 | spin_lock_bh(&mpath->state_lock); |
654 | if (mpath->flags & MESH_PATH_ACTIVE && | 661 | if (mpath->flags & MESH_PATH_ACTIVE && |
655 | memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 && | 662 | memcmp(ta, next_hop_deref_protected(mpath)->sta.addr, |
663 | ETH_ALEN) == 0 && | ||
656 | (!(mpath->flags & MESH_PATH_SN_VALID) || | 664 | (!(mpath->flags & MESH_PATH_SN_VALID) || |
657 | SN_GT(target_sn, mpath->sn))) { | 665 | SN_GT(target_sn, mpath->sn))) { |
658 | mpath->flags &= ~MESH_PATH_ACTIVE; | 666 | mpath->flags &= ~MESH_PATH_ACTIVE; |
@@ -914,6 +922,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
914 | { | 922 | { |
915 | struct sk_buff *skb_to_free = NULL; | 923 | struct sk_buff *skb_to_free = NULL; |
916 | struct mesh_path *mpath; | 924 | struct mesh_path *mpath; |
925 | struct sta_info *next_hop; | ||
917 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 926 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
918 | u8 *target_addr = hdr->addr3; | 927 | u8 *target_addr = hdr->addr3; |
919 | int err = 0; | 928 | int err = 0; |
@@ -941,7 +950,11 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
941 | mesh_queue_preq(mpath, | 950 | mesh_queue_preq(mpath, |
942 | PREQ_Q_F_START | PREQ_Q_F_REFRESH); | 951 | PREQ_Q_F_START | PREQ_Q_F_REFRESH); |
943 | } | 952 | } |
944 | 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; | ||
945 | } else { | 958 | } else { |
946 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 959 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
947 | if (!(mpath->flags & MESH_PATH_RESOLVING)) { | 960 | if (!(mpath->flags & MESH_PATH_RESOLVING)) { |
@@ -967,20 +980,11 @@ endlookup: | |||
967 | 980 | ||
968 | void mesh_path_timer(unsigned long data) | 981 | void mesh_path_timer(unsigned long data) |
969 | { | 982 | { |
970 | struct ieee80211_sub_if_data *sdata; | 983 | struct mesh_path *mpath = (void *) data; |
971 | struct mesh_path *mpath; | 984 | struct ieee80211_sub_if_data *sdata = mpath->sdata; |
972 | |||
973 | rcu_read_lock(); | ||
974 | mpath = (struct mesh_path *) data; | ||
975 | mpath = rcu_dereference(mpath); | ||
976 | if (!mpath) | ||
977 | goto endmpathtimer; | ||
978 | sdata = mpath->sdata; | ||
979 | 985 | ||
980 | if (sdata->local->quiescing) { | 986 | if (sdata->local->quiescing) |
981 | rcu_read_unlock(); | ||
982 | return; | 987 | return; |
983 | } | ||
984 | 988 | ||
985 | spin_lock_bh(&mpath->state_lock); | 989 | spin_lock_bh(&mpath->state_lock); |
986 | if (mpath->flags & MESH_PATH_RESOLVED || | 990 | if (mpath->flags & MESH_PATH_RESOLVED || |
@@ -997,8 +1001,6 @@ void mesh_path_timer(unsigned long data) | |||
997 | } | 1001 | } |
998 | 1002 | ||
999 | spin_unlock_bh(&mpath->state_lock); | 1003 | spin_unlock_bh(&mpath->state_lock); |
1000 | endmpathtimer: | ||
1001 | rcu_read_unlock(); | ||
1002 | } | 1004 | } |
1003 | 1005 | ||
1004 | void | 1006 | void |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 35c715adaae2..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,18 +99,18 @@ 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 int mesh_table_grow(struct mesh_table *oldtbl, | 112 | static int mesh_table_grow(struct mesh_table *oldtbl, |
69 | struct mesh_table *newtbl) | 113 | struct mesh_table *newtbl) |
70 | { | 114 | { |
71 | struct hlist_head *oldhash; | 115 | struct hlist_head *oldhash; |
72 | struct hlist_node *p, *q; | 116 | struct hlist_node *p, *q; |
@@ -76,7 +120,6 @@ static int mesh_table_grow(struct mesh_table *oldtbl, | |||
76 | < oldtbl->mean_chain_len * (oldtbl->hash_mask + 1)) | 120 | < oldtbl->mean_chain_len * (oldtbl->hash_mask + 1)) |
77 | return -EAGAIN; | 121 | return -EAGAIN; |
78 | 122 | ||
79 | |||
80 | newtbl->free_node = oldtbl->free_node; | 123 | newtbl->free_node = oldtbl->free_node; |
81 | newtbl->mean_chain_len = oldtbl->mean_chain_len; | 124 | newtbl->mean_chain_len = oldtbl->mean_chain_len; |
82 | newtbl->copy_node = oldtbl->copy_node; | 125 | newtbl->copy_node = oldtbl->copy_node; |
@@ -98,12 +141,14 @@ errcopy: | |||
98 | return -ENOMEM; | 141 | return -ENOMEM; |
99 | } | 142 | } |
100 | 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 | } | ||
101 | 151 | ||
102 | /* This lock will have the grow table function as writer and add / delete nodes | ||
103 | * as readers. When reading the table (i.e. doing lookups) we are well protected | ||
104 | * by RCU | ||
105 | */ | ||
106 | static DEFINE_RWLOCK(pathtbl_resize_lock); | ||
107 | 152 | ||
108 | /** | 153 | /** |
109 | * | 154 | * |
@@ -275,7 +320,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
275 | if (!new_node) | 320 | if (!new_node) |
276 | goto err_node_alloc; | 321 | goto err_node_alloc; |
277 | 322 | ||
278 | read_lock(&pathtbl_resize_lock); | 323 | read_lock_bh(&pathtbl_resize_lock); |
279 | memcpy(new_mpath->dst, dst, ETH_ALEN); | 324 | memcpy(new_mpath->dst, dst, ETH_ALEN); |
280 | new_mpath->sdata = sdata; | 325 | new_mpath->sdata = sdata; |
281 | new_mpath->flags = 0; | 326 | new_mpath->flags = 0; |
@@ -290,7 +335,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
290 | hash_idx = mesh_table_hash(dst, sdata, mesh_paths); | 335 | hash_idx = mesh_table_hash(dst, sdata, mesh_paths); |
291 | bucket = &mesh_paths->hash_buckets[hash_idx]; | 336 | bucket = &mesh_paths->hash_buckets[hash_idx]; |
292 | 337 | ||
293 | spin_lock(&mesh_paths->hashwlock[hash_idx]); | 338 | spin_lock_bh(&mesh_paths->hashwlock[hash_idx]); |
294 | 339 | ||
295 | err = -EEXIST; | 340 | err = -EEXIST; |
296 | hlist_for_each_entry(node, n, bucket, list) { | 341 | hlist_for_each_entry(node, n, bucket, list) { |
@@ -306,8 +351,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
306 | 351 | ||
307 | mesh_paths_generation++; | 352 | mesh_paths_generation++; |
308 | 353 | ||
309 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | 354 | spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]); |
310 | read_unlock(&pathtbl_resize_lock); | 355 | read_unlock_bh(&pathtbl_resize_lock); |
311 | if (grow) { | 356 | if (grow) { |
312 | set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags); | 357 | set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags); |
313 | ieee80211_queue_work(&local->hw, &sdata->work); | 358 | ieee80211_queue_work(&local->hw, &sdata->work); |
@@ -315,8 +360,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
315 | return 0; | 360 | return 0; |
316 | 361 | ||
317 | err_exists: | 362 | err_exists: |
318 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | 363 | spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]); |
319 | read_unlock(&pathtbl_resize_lock); | 364 | read_unlock_bh(&pathtbl_resize_lock); |
320 | kfree(new_node); | 365 | kfree(new_node); |
321 | err_node_alloc: | 366 | err_node_alloc: |
322 | kfree(new_mpath); | 367 | kfree(new_mpath); |
@@ -329,18 +374,21 @@ void mesh_mpath_table_grow(void) | |||
329 | { | 374 | { |
330 | struct mesh_table *oldtbl, *newtbl; | 375 | struct mesh_table *oldtbl, *newtbl; |
331 | 376 | ||
332 | newtbl = mesh_table_alloc(mesh_paths->size_order + 1); | 377 | rcu_read_lock(); |
378 | newtbl = mesh_table_alloc(rcu_dereference(mesh_paths)->size_order + 1); | ||
333 | if (!newtbl) | 379 | if (!newtbl) |
334 | return; | 380 | return; |
335 | write_lock(&pathtbl_resize_lock); | 381 | write_lock_bh(&pathtbl_resize_lock); |
336 | oldtbl = mesh_paths; | 382 | oldtbl = mesh_paths; |
337 | if (mesh_table_grow(mesh_paths, newtbl) < 0) { | 383 | if (mesh_table_grow(mesh_paths, newtbl) < 0) { |
384 | rcu_read_unlock(); | ||
338 | __mesh_table_free(newtbl); | 385 | __mesh_table_free(newtbl); |
339 | write_unlock(&pathtbl_resize_lock); | 386 | write_unlock_bh(&pathtbl_resize_lock); |
340 | return; | 387 | return; |
341 | } | 388 | } |
389 | rcu_read_unlock(); | ||
342 | rcu_assign_pointer(mesh_paths, newtbl); | 390 | rcu_assign_pointer(mesh_paths, newtbl); |
343 | write_unlock(&pathtbl_resize_lock); | 391 | write_unlock_bh(&pathtbl_resize_lock); |
344 | 392 | ||
345 | synchronize_rcu(); | 393 | synchronize_rcu(); |
346 | mesh_table_free(oldtbl, false); | 394 | mesh_table_free(oldtbl, false); |
@@ -350,18 +398,21 @@ void mesh_mpp_table_grow(void) | |||
350 | { | 398 | { |
351 | struct mesh_table *oldtbl, *newtbl; | 399 | struct mesh_table *oldtbl, *newtbl; |
352 | 400 | ||
353 | newtbl = mesh_table_alloc(mpp_paths->size_order + 1); | 401 | rcu_read_lock(); |
402 | newtbl = mesh_table_alloc(rcu_dereference(mpp_paths)->size_order + 1); | ||
354 | if (!newtbl) | 403 | if (!newtbl) |
355 | return; | 404 | return; |
356 | write_lock(&pathtbl_resize_lock); | 405 | write_lock_bh(&pathtbl_resize_lock); |
357 | oldtbl = mpp_paths; | 406 | oldtbl = mpp_paths; |
358 | if (mesh_table_grow(mpp_paths, newtbl) < 0) { | 407 | if (mesh_table_grow(mpp_paths, newtbl) < 0) { |
408 | rcu_read_unlock(); | ||
359 | __mesh_table_free(newtbl); | 409 | __mesh_table_free(newtbl); |
360 | write_unlock(&pathtbl_resize_lock); | 410 | write_unlock_bh(&pathtbl_resize_lock); |
361 | return; | 411 | return; |
362 | } | 412 | } |
413 | rcu_read_unlock(); | ||
363 | rcu_assign_pointer(mpp_paths, newtbl); | 414 | rcu_assign_pointer(mpp_paths, newtbl); |
364 | write_unlock(&pathtbl_resize_lock); | 415 | write_unlock_bh(&pathtbl_resize_lock); |
365 | 416 | ||
366 | synchronize_rcu(); | 417 | synchronize_rcu(); |
367 | mesh_table_free(oldtbl, false); | 418 | mesh_table_free(oldtbl, false); |
@@ -395,7 +446,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
395 | if (!new_node) | 446 | if (!new_node) |
396 | goto err_node_alloc; | 447 | goto err_node_alloc; |
397 | 448 | ||
398 | read_lock(&pathtbl_resize_lock); | 449 | read_lock_bh(&pathtbl_resize_lock); |
399 | memcpy(new_mpath->dst, dst, ETH_ALEN); | 450 | memcpy(new_mpath->dst, dst, ETH_ALEN); |
400 | memcpy(new_mpath->mpp, mpp, ETH_ALEN); | 451 | memcpy(new_mpath->mpp, mpp, ETH_ALEN); |
401 | new_mpath->sdata = sdata; | 452 | new_mpath->sdata = sdata; |
@@ -408,7 +459,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
408 | hash_idx = mesh_table_hash(dst, sdata, mpp_paths); | 459 | hash_idx = mesh_table_hash(dst, sdata, mpp_paths); |
409 | bucket = &mpp_paths->hash_buckets[hash_idx]; | 460 | bucket = &mpp_paths->hash_buckets[hash_idx]; |
410 | 461 | ||
411 | spin_lock(&mpp_paths->hashwlock[hash_idx]); | 462 | spin_lock_bh(&mpp_paths->hashwlock[hash_idx]); |
412 | 463 | ||
413 | err = -EEXIST; | 464 | err = -EEXIST; |
414 | hlist_for_each_entry(node, n, bucket, list) { | 465 | hlist_for_each_entry(node, n, bucket, list) { |
@@ -422,8 +473,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
422 | mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1)) | 473 | mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1)) |
423 | grow = 1; | 474 | grow = 1; |
424 | 475 | ||
425 | spin_unlock(&mpp_paths->hashwlock[hash_idx]); | 476 | spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]); |
426 | read_unlock(&pathtbl_resize_lock); | 477 | read_unlock_bh(&pathtbl_resize_lock); |
427 | if (grow) { | 478 | if (grow) { |
428 | set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); | 479 | set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); |
429 | ieee80211_queue_work(&local->hw, &sdata->work); | 480 | ieee80211_queue_work(&local->hw, &sdata->work); |
@@ -431,8 +482,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
431 | return 0; | 482 | return 0; |
432 | 483 | ||
433 | err_exists: | 484 | err_exists: |
434 | spin_unlock(&mpp_paths->hashwlock[hash_idx]); | 485 | spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]); |
435 | read_unlock(&pathtbl_resize_lock); | 486 | read_unlock_bh(&pathtbl_resize_lock); |
436 | kfree(new_node); | 487 | kfree(new_node); |
437 | err_node_alloc: | 488 | err_node_alloc: |
438 | kfree(new_mpath); | 489 | kfree(new_mpath); |
@@ -545,11 +596,11 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) | |||
545 | int hash_idx; | 596 | int hash_idx; |
546 | int err = 0; | 597 | int err = 0; |
547 | 598 | ||
548 | read_lock(&pathtbl_resize_lock); | 599 | read_lock_bh(&pathtbl_resize_lock); |
549 | hash_idx = mesh_table_hash(addr, sdata, mesh_paths); | 600 | hash_idx = mesh_table_hash(addr, sdata, mesh_paths); |
550 | bucket = &mesh_paths->hash_buckets[hash_idx]; | 601 | bucket = &mesh_paths->hash_buckets[hash_idx]; |
551 | 602 | ||
552 | spin_lock(&mesh_paths->hashwlock[hash_idx]); | 603 | spin_lock_bh(&mesh_paths->hashwlock[hash_idx]); |
553 | hlist_for_each_entry(node, n, bucket, list) { | 604 | hlist_for_each_entry(node, n, bucket, list) { |
554 | mpath = node->mpath; | 605 | mpath = node->mpath; |
555 | if (mpath->sdata == sdata && | 606 | if (mpath->sdata == sdata && |
@@ -567,8 +618,8 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) | |||
567 | err = -ENXIO; | 618 | err = -ENXIO; |
568 | enddel: | 619 | enddel: |
569 | mesh_paths_generation++; | 620 | mesh_paths_generation++; |
570 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | 621 | spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]); |
571 | read_unlock(&pathtbl_resize_lock); | 622 | read_unlock_bh(&pathtbl_resize_lock); |
572 | return err; | 623 | return err; |
573 | } | 624 | } |
574 | 625 | ||
@@ -720,7 +771,7 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata) | |||
720 | struct hlist_node *p; | 771 | struct hlist_node *p; |
721 | int i; | 772 | int i; |
722 | 773 | ||
723 | read_lock(&pathtbl_resize_lock); | 774 | read_lock_bh(&pathtbl_resize_lock); |
724 | for_each_mesh_entry(mesh_paths, p, node, i) { | 775 | for_each_mesh_entry(mesh_paths, p, node, i) { |
725 | if (node->mpath->sdata != sdata) | 776 | if (node->mpath->sdata != sdata) |
726 | continue; | 777 | continue; |
@@ -735,7 +786,7 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata) | |||
735 | } else | 786 | } else |
736 | spin_unlock_bh(&mpath->state_lock); | 787 | spin_unlock_bh(&mpath->state_lock); |
737 | } | 788 | } |
738 | read_unlock(&pathtbl_resize_lock); | 789 | read_unlock_bh(&pathtbl_resize_lock); |
739 | } | 790 | } |
740 | 791 | ||
741 | 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 84e5b056af02..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 | } |
@@ -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; |
@@ -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) |
@@ -251,7 +251,7 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, | |||
251 | rcu_read_unlock(); | 251 | rcu_read_unlock(); |
252 | /* Userspace handles peer allocation when security is enabled | 252 | /* Userspace handles peer allocation when security is enabled |
253 | * */ | 253 | * */ |
254 | if (sdata->u.mesh.is_secure) | 254 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) |
255 | cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr, | 255 | cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr, |
256 | elems->ie_start, elems->total_len, | 256 | elems->ie_start, elems->total_len, |
257 | GFP_KERNEL); | 257 | GFP_KERNEL); |
@@ -268,7 +268,7 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, | |||
268 | sta->last_rx = jiffies; | 268 | sta->last_rx = jiffies; |
269 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; | 269 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; |
270 | if (mesh_peer_accepts_plinks(elems) && | 270 | if (mesh_peer_accepts_plinks(elems) && |
271 | sta->plink_state == PLINK_LISTEN && | 271 | sta->plink_state == NL80211_PLINK_LISTEN && |
272 | sdata->u.mesh.accepting_plinks && | 272 | sdata->u.mesh.accepting_plinks && |
273 | sdata->u.mesh.mshcfg.auto_open_plinks) | 273 | sdata->u.mesh.mshcfg.auto_open_plinks) |
274 | mesh_plink_open(sta); | 274 | mesh_plink_open(sta); |
@@ -308,8 +308,8 @@ static void mesh_plink_timer(unsigned long data) | |||
308 | sdata = sta->sdata; | 308 | sdata = sta->sdata; |
309 | 309 | ||
310 | switch (sta->plink_state) { | 310 | switch (sta->plink_state) { |
311 | case PLINK_OPN_RCVD: | 311 | case NL80211_PLINK_OPN_RCVD: |
312 | case PLINK_OPN_SNT: | 312 | case NL80211_PLINK_OPN_SNT: |
313 | /* retry timer */ | 313 | /* retry timer */ |
314 | if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { | 314 | if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { |
315 | u32 rand; | 315 | u32 rand; |
@@ -328,17 +328,17 @@ static void mesh_plink_timer(unsigned long data) | |||
328 | } | 328 | } |
329 | reason = cpu_to_le16(MESH_MAX_RETRIES); | 329 | reason = cpu_to_le16(MESH_MAX_RETRIES); |
330 | /* fall through on else */ | 330 | /* fall through on else */ |
331 | case PLINK_CNF_RCVD: | 331 | case NL80211_PLINK_CNF_RCVD: |
332 | /* confirm timer */ | 332 | /* confirm timer */ |
333 | if (!reason) | 333 | if (!reason) |
334 | reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); | 334 | reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); |
335 | sta->plink_state = PLINK_HOLDING; | 335 | sta->plink_state = NL80211_PLINK_HOLDING; |
336 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | 336 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
337 | spin_unlock_bh(&sta->lock); | 337 | spin_unlock_bh(&sta->lock); |
338 | 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, |
339 | reason); | 339 | reason); |
340 | break; | 340 | break; |
341 | case PLINK_HOLDING: | 341 | case NL80211_PLINK_HOLDING: |
342 | /* holding timer */ | 342 | /* holding timer */ |
343 | del_timer(&sta->plink_timer); | 343 | del_timer(&sta->plink_timer); |
344 | mesh_plink_fsm_restart(sta); | 344 | mesh_plink_fsm_restart(sta); |
@@ -386,11 +386,11 @@ int mesh_plink_open(struct sta_info *sta) | |||
386 | spin_lock_bh(&sta->lock); | 386 | spin_lock_bh(&sta->lock); |
387 | get_random_bytes(&llid, 2); | 387 | get_random_bytes(&llid, 2); |
388 | sta->llid = llid; | 388 | sta->llid = llid; |
389 | if (sta->plink_state != PLINK_LISTEN) { | 389 | if (sta->plink_state != NL80211_PLINK_LISTEN) { |
390 | spin_unlock_bh(&sta->lock); | 390 | spin_unlock_bh(&sta->lock); |
391 | return -EBUSY; | 391 | return -EBUSY; |
392 | } | 392 | } |
393 | sta->plink_state = PLINK_OPN_SNT; | 393 | sta->plink_state = NL80211_PLINK_OPN_SNT; |
394 | mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); | 394 | mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); |
395 | spin_unlock_bh(&sta->lock); | 395 | spin_unlock_bh(&sta->lock); |
396 | mpl_dbg("Mesh plink: starting establishment with %pM\n", | 396 | mpl_dbg("Mesh plink: starting establishment with %pM\n", |
@@ -407,7 +407,7 @@ void mesh_plink_block(struct sta_info *sta) | |||
407 | 407 | ||
408 | spin_lock_bh(&sta->lock); | 408 | spin_lock_bh(&sta->lock); |
409 | deactivated = __mesh_plink_deactivate(sta); | 409 | deactivated = __mesh_plink_deactivate(sta); |
410 | sta->plink_state = PLINK_BLOCKED; | 410 | sta->plink_state = NL80211_PLINK_BLOCKED; |
411 | spin_unlock_bh(&sta->lock); | 411 | spin_unlock_bh(&sta->lock); |
412 | 412 | ||
413 | if (deactivated) | 413 | if (deactivated) |
@@ -430,13 +430,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
430 | __le16 plid, llid, reason; | 430 | __le16 plid, llid, reason; |
431 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | 431 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG |
432 | static const char *mplstates[] = { | 432 | static const char *mplstates[] = { |
433 | [PLINK_LISTEN] = "LISTEN", | 433 | [NL80211_PLINK_LISTEN] = "LISTEN", |
434 | [PLINK_OPN_SNT] = "OPN-SNT", | 434 | [NL80211_PLINK_OPN_SNT] = "OPN-SNT", |
435 | [PLINK_OPN_RCVD] = "OPN-RCVD", | 435 | [NL80211_PLINK_OPN_RCVD] = "OPN-RCVD", |
436 | [PLINK_CNF_RCVD] = "CNF_RCVD", | 436 | [NL80211_PLINK_CNF_RCVD] = "CNF_RCVD", |
437 | [PLINK_ESTAB] = "ESTAB", | 437 | [NL80211_PLINK_ESTAB] = "ESTAB", |
438 | [PLINK_HOLDING] = "HOLDING", | 438 | [NL80211_PLINK_HOLDING] = "HOLDING", |
439 | [PLINK_BLOCKED] = "BLOCKED" | 439 | [NL80211_PLINK_BLOCKED] = "BLOCKED" |
440 | }; | 440 | }; |
441 | #endif | 441 | #endif |
442 | 442 | ||
@@ -460,7 +460,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
460 | mpl_dbg("Mesh plink: missing necessary peer link ie\n"); | 460 | mpl_dbg("Mesh plink: missing necessary peer link ie\n"); |
461 | return; | 461 | return; |
462 | } | 462 | } |
463 | if (elems.rsn_len && !sdata->u.mesh.is_secure) { | 463 | if (elems.rsn_len && |
464 | sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { | ||
464 | mpl_dbg("Mesh plink: can't establish link with secure peer\n"); | 465 | mpl_dbg("Mesh plink: can't establish link with secure peer\n"); |
465 | return; | 466 | return; |
466 | } | 467 | } |
@@ -501,7 +502,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
501 | return; | 502 | return; |
502 | } | 503 | } |
503 | 504 | ||
504 | if (sta && sta->plink_state == PLINK_BLOCKED) { | 505 | if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) { |
505 | rcu_read_unlock(); | 506 | rcu_read_unlock(); |
506 | return; | 507 | return; |
507 | } | 508 | } |
@@ -571,7 +572,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
571 | event = CNF_ACPT; | 572 | event = CNF_ACPT; |
572 | break; | 573 | break; |
573 | case PLINK_CLOSE: | 574 | case PLINK_CLOSE: |
574 | if (sta->plink_state == PLINK_ESTAB) | 575 | if (sta->plink_state == NL80211_PLINK_ESTAB) |
575 | /* Do not check for llid or plid. This does not | 576 | /* Do not check for llid or plid. This does not |
576 | * follow the standard but since multiple plinks | 577 | * follow the standard but since multiple plinks |
577 | * per sta are not supported, it is necessary in | 578 | * per sta are not supported, it is necessary in |
@@ -606,14 +607,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
606 | reason = 0; | 607 | reason = 0; |
607 | switch (sta->plink_state) { | 608 | switch (sta->plink_state) { |
608 | /* spin_unlock as soon as state is updated at each case */ | 609 | /* spin_unlock as soon as state is updated at each case */ |
609 | case PLINK_LISTEN: | 610 | case NL80211_PLINK_LISTEN: |
610 | switch (event) { | 611 | switch (event) { |
611 | case CLS_ACPT: | 612 | case CLS_ACPT: |
612 | mesh_plink_fsm_restart(sta); | 613 | mesh_plink_fsm_restart(sta); |
613 | spin_unlock_bh(&sta->lock); | 614 | spin_unlock_bh(&sta->lock); |
614 | break; | 615 | break; |
615 | case OPN_ACPT: | 616 | case OPN_ACPT: |
616 | sta->plink_state = PLINK_OPN_RCVD; | 617 | sta->plink_state = NL80211_PLINK_OPN_RCVD; |
617 | sta->plid = plid; | 618 | sta->plid = plid; |
618 | get_random_bytes(&llid, 2); | 619 | get_random_bytes(&llid, 2); |
619 | sta->llid = llid; | 620 | sta->llid = llid; |
@@ -630,7 +631,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
630 | } | 631 | } |
631 | break; | 632 | break; |
632 | 633 | ||
633 | case PLINK_OPN_SNT: | 634 | case NL80211_PLINK_OPN_SNT: |
634 | switch (event) { | 635 | switch (event) { |
635 | case OPN_RJCT: | 636 | case OPN_RJCT: |
636 | case CNF_RJCT: | 637 | case CNF_RJCT: |
@@ -639,7 +640,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
639 | if (!reason) | 640 | if (!reason) |
640 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | 641 | reason = cpu_to_le16(MESH_CLOSE_RCVD); |
641 | sta->reason = reason; | 642 | sta->reason = reason; |
642 | sta->plink_state = PLINK_HOLDING; | 643 | sta->plink_state = NL80211_PLINK_HOLDING; |
643 | if (!mod_plink_timer(sta, | 644 | if (!mod_plink_timer(sta, |
644 | dot11MeshHoldingTimeout(sdata))) | 645 | dot11MeshHoldingTimeout(sdata))) |
645 | sta->ignore_plink_timer = true; | 646 | sta->ignore_plink_timer = true; |
@@ -651,7 +652,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
651 | break; | 652 | break; |
652 | case OPN_ACPT: | 653 | case OPN_ACPT: |
653 | /* retry timer is left untouched */ | 654 | /* retry timer is left untouched */ |
654 | sta->plink_state = PLINK_OPN_RCVD; | 655 | sta->plink_state = NL80211_PLINK_OPN_RCVD; |
655 | sta->plid = plid; | 656 | sta->plid = plid; |
656 | llid = sta->llid; | 657 | llid = sta->llid; |
657 | spin_unlock_bh(&sta->lock); | 658 | spin_unlock_bh(&sta->lock); |
@@ -659,7 +660,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
659 | plid, 0); | 660 | plid, 0); |
660 | break; | 661 | break; |
661 | case CNF_ACPT: | 662 | case CNF_ACPT: |
662 | sta->plink_state = PLINK_CNF_RCVD; | 663 | sta->plink_state = NL80211_PLINK_CNF_RCVD; |
663 | if (!mod_plink_timer(sta, | 664 | if (!mod_plink_timer(sta, |
664 | dot11MeshConfirmTimeout(sdata))) | 665 | dot11MeshConfirmTimeout(sdata))) |
665 | sta->ignore_plink_timer = true; | 666 | sta->ignore_plink_timer = true; |
@@ -672,7 +673,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
672 | } | 673 | } |
673 | break; | 674 | break; |
674 | 675 | ||
675 | case PLINK_OPN_RCVD: | 676 | case NL80211_PLINK_OPN_RCVD: |
676 | switch (event) { | 677 | switch (event) { |
677 | case OPN_RJCT: | 678 | case OPN_RJCT: |
678 | case CNF_RJCT: | 679 | case CNF_RJCT: |
@@ -681,7 +682,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
681 | if (!reason) | 682 | if (!reason) |
682 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | 683 | reason = cpu_to_le16(MESH_CLOSE_RCVD); |
683 | sta->reason = reason; | 684 | sta->reason = reason; |
684 | sta->plink_state = PLINK_HOLDING; | 685 | sta->plink_state = NL80211_PLINK_HOLDING; |
685 | if (!mod_plink_timer(sta, | 686 | if (!mod_plink_timer(sta, |
686 | dot11MeshHoldingTimeout(sdata))) | 687 | dot11MeshHoldingTimeout(sdata))) |
687 | sta->ignore_plink_timer = true; | 688 | sta->ignore_plink_timer = true; |
@@ -699,7 +700,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
699 | break; | 700 | break; |
700 | case CNF_ACPT: | 701 | case CNF_ACPT: |
701 | del_timer(&sta->plink_timer); | 702 | del_timer(&sta->plink_timer); |
702 | sta->plink_state = PLINK_ESTAB; | 703 | sta->plink_state = NL80211_PLINK_ESTAB; |
703 | spin_unlock_bh(&sta->lock); | 704 | spin_unlock_bh(&sta->lock); |
704 | mesh_plink_inc_estab_count(sdata); | 705 | mesh_plink_inc_estab_count(sdata); |
705 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 706 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); |
@@ -712,7 +713,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
712 | } | 713 | } |
713 | break; | 714 | break; |
714 | 715 | ||
715 | case PLINK_CNF_RCVD: | 716 | case NL80211_PLINK_CNF_RCVD: |
716 | switch (event) { | 717 | switch (event) { |
717 | case OPN_RJCT: | 718 | case OPN_RJCT: |
718 | case CNF_RJCT: | 719 | case CNF_RJCT: |
@@ -721,7 +722,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
721 | if (!reason) | 722 | if (!reason) |
722 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | 723 | reason = cpu_to_le16(MESH_CLOSE_RCVD); |
723 | sta->reason = reason; | 724 | sta->reason = reason; |
724 | sta->plink_state = PLINK_HOLDING; | 725 | sta->plink_state = NL80211_PLINK_HOLDING; |
725 | if (!mod_plink_timer(sta, | 726 | if (!mod_plink_timer(sta, |
726 | dot11MeshHoldingTimeout(sdata))) | 727 | dot11MeshHoldingTimeout(sdata))) |
727 | sta->ignore_plink_timer = true; | 728 | sta->ignore_plink_timer = true; |
@@ -733,7 +734,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
733 | break; | 734 | break; |
734 | case OPN_ACPT: | 735 | case OPN_ACPT: |
735 | del_timer(&sta->plink_timer); | 736 | del_timer(&sta->plink_timer); |
736 | sta->plink_state = PLINK_ESTAB; | 737 | sta->plink_state = NL80211_PLINK_ESTAB; |
737 | spin_unlock_bh(&sta->lock); | 738 | spin_unlock_bh(&sta->lock); |
738 | mesh_plink_inc_estab_count(sdata); | 739 | mesh_plink_inc_estab_count(sdata); |
739 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 740 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); |
@@ -748,13 +749,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
748 | } | 749 | } |
749 | break; | 750 | break; |
750 | 751 | ||
751 | case PLINK_ESTAB: | 752 | case NL80211_PLINK_ESTAB: |
752 | switch (event) { | 753 | switch (event) { |
753 | case CLS_ACPT: | 754 | case CLS_ACPT: |
754 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | 755 | reason = cpu_to_le16(MESH_CLOSE_RCVD); |
755 | sta->reason = reason; | 756 | sta->reason = reason; |
756 | deactivated = __mesh_plink_deactivate(sta); | 757 | deactivated = __mesh_plink_deactivate(sta); |
757 | sta->plink_state = PLINK_HOLDING; | 758 | sta->plink_state = NL80211_PLINK_HOLDING; |
758 | llid = sta->llid; | 759 | llid = sta->llid; |
759 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | 760 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
760 | spin_unlock_bh(&sta->lock); | 761 | spin_unlock_bh(&sta->lock); |
@@ -774,7 +775,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
774 | break; | 775 | break; |
775 | } | 776 | } |
776 | break; | 777 | break; |
777 | case PLINK_HOLDING: | 778 | case NL80211_PLINK_HOLDING: |
778 | switch (event) { | 779 | switch (event) { |
779 | case CLS_ACPT: | 780 | case CLS_ACPT: |
780 | 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 a41f234bd486..4f6b2675e41d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -750,6 +750,8 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
750 | dynamic_ps_enable_work); | 750 | dynamic_ps_enable_work); |
751 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; | 751 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; |
752 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 752 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
753 | unsigned long flags; | ||
754 | int q; | ||
753 | 755 | ||
754 | /* can only happen when PS was just disabled anyway */ | 756 | /* can only happen when PS was just disabled anyway */ |
755 | if (!sdata) | 757 | if (!sdata) |
@@ -758,6 +760,24 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
758 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | 760 | if (local->hw.conf.flags & IEEE80211_CONF_PS) |
759 | return; | 761 | return; |
760 | 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 | |||
761 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && | 781 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && |
762 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { | 782 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { |
763 | netif_tx_stop_all_queues(sdata->dev); | 783 | netif_tx_stop_all_queues(sdata->dev); |
@@ -781,7 +801,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
781 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 801 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
782 | } | 802 | } |
783 | 803 | ||
784 | netif_tx_start_all_queues(sdata->dev); | 804 | netif_tx_wake_all_queues(sdata->dev); |
785 | } | 805 | } |
786 | 806 | ||
787 | 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 042461710880..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; |
@@ -47,6 +47,16 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
47 | cancel_work_sync(&local->dynamic_ps_enable_work); | 47 | cancel_work_sync(&local->dynamic_ps_enable_work); |
48 | del_timer_sync(&local->dynamic_ps_timer); | 48 | del_timer_sync(&local->dynamic_ps_timer); |
49 | 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 | |||
50 | /* disable keys */ | 60 | /* disable keys */ |
51 | list_for_each_entry(sdata, &local->interfaces, list) | 61 | list_for_each_entry(sdata, &local->interfaces, list) |
52 | ieee80211_disable_keys(sdata); | 62 | ieee80211_disable_keys(sdata); |
@@ -104,6 +114,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
104 | if (local->open_count) | 114 | if (local->open_count) |
105 | ieee80211_stop_device(local); | 115 | ieee80211_stop_device(local); |
106 | 116 | ||
117 | suspend: | ||
107 | local->suspended = true; | 118 | local->suspended = true; |
108 | /* need suspended to be visible before quiescing is false */ | 119 | /* need suspended to be visible before quiescing is false */ |
109 | 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 13a6697651ad..7fa8c6be7bf0 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -404,11 +404,13 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) | |||
404 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | 404 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
405 | struct sk_buff *skb = rx->skb; | 405 | struct sk_buff *skb = rx->skb; |
406 | 406 | ||
407 | if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN))) | 407 | if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN) && |
408 | !local->sched_scanning)) | ||
408 | return RX_CONTINUE; | 409 | return RX_CONTINUE; |
409 | 410 | ||
410 | if (test_bit(SCAN_HW_SCANNING, &local->scanning) || | 411 | if (test_bit(SCAN_HW_SCANNING, &local->scanning) || |
411 | test_bit(SCAN_SW_SCANNING, &local->scanning)) | 412 | test_bit(SCAN_SW_SCANNING, &local->scanning) || |
413 | local->sched_scanning) | ||
412 | return ieee80211_scan_rx(rx->sdata, skb); | 414 | return ieee80211_scan_rx(rx->sdata, skb); |
413 | 415 | ||
414 | /* scanning finished during invoking of handlers */ | 416 | /* scanning finished during invoking of handlers */ |
@@ -488,15 +490,18 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
488 | * establisment frame, beacon or probe, drop the frame. | 490 | * establisment frame, beacon or probe, drop the frame. |
489 | */ | 491 | */ |
490 | 492 | ||
491 | if (!rx->sta || sta_plink_state(rx->sta) != PLINK_ESTAB) { | 493 | if (!rx->sta || sta_plink_state(rx->sta) != NL80211_PLINK_ESTAB) { |
492 | struct ieee80211_mgmt *mgmt; | 494 | struct ieee80211_mgmt *mgmt; |
493 | 495 | ||
494 | if (!ieee80211_is_mgmt(hdr->frame_control)) | 496 | if (!ieee80211_is_mgmt(hdr->frame_control)) |
495 | return RX_DROP_MONITOR; | 497 | return RX_DROP_MONITOR; |
496 | 498 | ||
497 | if (ieee80211_is_action(hdr->frame_control)) { | 499 | if (ieee80211_is_action(hdr->frame_control)) { |
500 | u8 category; | ||
498 | mgmt = (struct ieee80211_mgmt *)hdr; | 501 | mgmt = (struct ieee80211_mgmt *)hdr; |
499 | 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) | ||
500 | return RX_DROP_MONITOR; | 505 | return RX_DROP_MONITOR; |
501 | return RX_CONTINUE; | 506 | return RX_CONTINUE; |
502 | } | 507 | } |
@@ -1778,7 +1783,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | |||
1778 | 1783 | ||
1779 | ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, | 1784 | ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, |
1780 | rx->sdata->vif.type, | 1785 | rx->sdata->vif.type, |
1781 | rx->local->hw.extra_tx_headroom); | 1786 | rx->local->hw.extra_tx_headroom, true); |
1782 | 1787 | ||
1783 | while (!skb_queue_empty(&frame_list)) { | 1788 | while (!skb_queue_empty(&frame_list)) { |
1784 | rx->skb = __skb_dequeue(&frame_list); | 1789 | rx->skb = __skb_dequeue(&frame_list); |
@@ -2205,7 +2210,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2205 | goto handled; | 2210 | goto handled; |
2206 | } | 2211 | } |
2207 | break; | 2212 | break; |
2208 | case WLAN_CATEGORY_MESH_PLINK: | 2213 | case WLAN_CATEGORY_MESH_ACTION: |
2209 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | 2214 | if (!ieee80211_vif_is_mesh(&sdata->vif)) |
2210 | break; | 2215 | break; |
2211 | goto queue; | 2216 | goto queue; |
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 d9e6e81ff6b2..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 | } |
@@ -274,7 +277,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
274 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 277 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
275 | 278 | ||
276 | #ifdef CONFIG_MAC80211_MESH | 279 | #ifdef CONFIG_MAC80211_MESH |
277 | sta->plink_state = PLINK_LISTEN; | 280 | sta->plink_state = NL80211_PLINK_LISTEN; |
278 | init_timer(&sta->plink_timer); | 281 | init_timer(&sta->plink_timer); |
279 | #endif | 282 | #endif |
280 | 283 | ||
@@ -652,10 +655,12 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
652 | if (ret) | 655 | if (ret) |
653 | return ret; | 656 | return ret; |
654 | 657 | ||
658 | mutex_lock(&local->key_mtx); | ||
655 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) | 659 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) |
656 | ieee80211_key_free(local, sta->gtk[i]); | 660 | __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i])); |
657 | if (sta->ptk) | 661 | if (sta->ptk) |
658 | ieee80211_key_free(local, sta->ptk); | 662 | __ieee80211_key_free(key_mtx_dereference(local, sta->ptk)); |
663 | mutex_unlock(&local->key_mtx); | ||
659 | 664 | ||
660 | sta->dead = true; | 665 | sta->dead = true; |
661 | 666 | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index aa0adcbf3a93..c6ae8718bd57 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -152,6 +152,7 @@ struct tid_ampdu_rx { | |||
152 | * | 152 | * |
153 | * @tid_rx: aggregation info for Rx per TID -- RCU protected | 153 | * @tid_rx: aggregation info for Rx per TID -- RCU protected |
154 | * @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 | ||
155 | * @addba_req_num: number of times addBA request has been sent. | 156 | * @addba_req_num: number of times addBA request has been sent. |
156 | * @dialog_token_allocator: dialog token enumerator for each new session; | 157 | * @dialog_token_allocator: dialog token enumerator for each new session; |
157 | * @work: work struct for starting/stopping aggregation | 158 | * @work: work struct for starting/stopping aggregation |
@@ -163,40 +164,18 @@ struct tid_ampdu_rx { | |||
163 | struct sta_ampdu_mlme { | 164 | struct sta_ampdu_mlme { |
164 | struct mutex mtx; | 165 | struct mutex mtx; |
165 | /* rx */ | 166 | /* rx */ |
166 | struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; | 167 | struct tid_ampdu_rx __rcu *tid_rx[STA_TID_NUM]; |
167 | 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)]; |
168 | /* tx */ | 169 | /* tx */ |
169 | struct work_struct work; | 170 | struct work_struct work; |
170 | 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]; | ||
171 | u8 addba_req_num[STA_TID_NUM]; | 173 | u8 addba_req_num[STA_TID_NUM]; |
172 | u8 dialog_token_allocator; | 174 | u8 dialog_token_allocator; |
173 | }; | 175 | }; |
174 | 176 | ||
175 | 177 | ||
176 | /** | 178 | /** |
177 | * enum plink_state - state of a mesh peer link finite state machine | ||
178 | * | ||
179 | * @PLINK_LISTEN: initial state, considered the implicit state of non existent | ||
180 | * mesh peer links | ||
181 | * @PLINK_OPN_SNT: mesh plink open frame has been sent to this mesh peer | ||
182 | * @PLINK_OPN_RCVD: mesh plink open frame has been received from this mesh peer | ||
183 | * @PLINK_CNF_RCVD: mesh plink confirm frame has been received from this mesh | ||
184 | * peer | ||
185 | * @PLINK_ESTAB: mesh peer link is established | ||
186 | * @PLINK_HOLDING: mesh peer link is being closed or cancelled | ||
187 | * @PLINK_BLOCKED: all frames transmitted from this mesh plink are discarded | ||
188 | */ | ||
189 | enum plink_state { | ||
190 | PLINK_LISTEN, | ||
191 | PLINK_OPN_SNT, | ||
192 | PLINK_OPN_RCVD, | ||
193 | PLINK_CNF_RCVD, | ||
194 | PLINK_ESTAB, | ||
195 | PLINK_HOLDING, | ||
196 | PLINK_BLOCKED | ||
197 | }; | ||
198 | |||
199 | /** | ||
200 | * struct sta_info - STA information | 179 | * struct sta_info - STA information |
201 | * | 180 | * |
202 | * This structure collects information about a station that | 181 | * This structure collects information about a station that |
@@ -264,11 +243,11 @@ enum plink_state { | |||
264 | struct sta_info { | 243 | struct sta_info { |
265 | /* General information, mostly static */ | 244 | /* General information, mostly static */ |
266 | struct list_head list; | 245 | struct list_head list; |
267 | struct sta_info *hnext; | 246 | struct sta_info __rcu *hnext; |
268 | struct ieee80211_local *local; | 247 | struct ieee80211_local *local; |
269 | struct ieee80211_sub_if_data *sdata; | 248 | struct ieee80211_sub_if_data *sdata; |
270 | struct ieee80211_key *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | 249 | struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
271 | struct ieee80211_key *ptk; | 250 | struct ieee80211_key __rcu *ptk; |
272 | struct rate_control_ref *rate_ctrl; | 251 | struct rate_control_ref *rate_ctrl; |
273 | void *rate_ctrl_priv; | 252 | void *rate_ctrl_priv; |
274 | spinlock_t lock; | 253 | spinlock_t lock; |
@@ -339,7 +318,7 @@ struct sta_info { | |||
339 | u8 plink_retries; | 318 | u8 plink_retries; |
340 | bool ignore_plink_timer; | 319 | bool ignore_plink_timer; |
341 | bool plink_timer_was_running; | 320 | bool plink_timer_was_running; |
342 | enum plink_state plink_state; | 321 | enum nl80211_plink_state plink_state; |
343 | u32 plink_timeout; | 322 | u32 plink_timeout; |
344 | struct timer_list plink_timer; | 323 | struct timer_list plink_timer; |
345 | #endif | 324 | #endif |
@@ -357,12 +336,12 @@ struct sta_info { | |||
357 | struct ieee80211_sta sta; | 336 | struct ieee80211_sta sta; |
358 | }; | 337 | }; |
359 | 338 | ||
360 | 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) |
361 | { | 340 | { |
362 | #ifdef CONFIG_MAC80211_MESH | 341 | #ifdef CONFIG_MAC80211_MESH |
363 | return sta->plink_state; | 342 | return sta->plink_state; |
364 | #endif | 343 | #endif |
365 | return PLINK_LISTEN; | 344 | return NL80211_PLINK_LISTEN; |
366 | } | 345 | } |
367 | 346 | ||
368 | 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) |
@@ -421,7 +400,16 @@ static inline u32 get_sta_flags(struct sta_info *sta) | |||
421 | return ret; | 400 | return ret; |
422 | } | 401 | } |
423 | 402 | ||
403 | void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, | ||
404 | struct tid_ampdu_tx *tid_tx); | ||
424 | 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 | } | ||
425 | 413 | ||
426 | #define STA_HASH_SIZE 256 | 414 | #define STA_HASH_SIZE 256 |
427 | #define STA_HASH(sta) (sta[5]) | 415 | #define STA_HASH(sta) (sta[5]) |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e3e3aa173af0..6eeaaa2bbafe 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1147,7 +1147,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx, | |||
1147 | * packet pass through because splicing the frames | 1147 | * packet pass through because splicing the frames |
1148 | * back is already done. | 1148 | * back is already done. |
1149 | */ | 1149 | */ |
1150 | tid_tx = tx->sta->ampdu_mlme.tid_tx[tid]; | 1150 | tid_tx = rcu_dereference_protected_tid_tx(tx->sta, tid); |
1151 | 1151 | ||
1152 | if (!tid_tx) { | 1152 | if (!tid_tx) { |
1153 | /* do nothing, let packet pass through */ | 1153 | /* do nothing, let packet pass through */ |
@@ -1751,6 +1751,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1751 | ret = NETDEV_TX_OK; | 1751 | ret = NETDEV_TX_OK; |
1752 | goto fail; | 1752 | goto fail; |
1753 | } | 1753 | } |
1754 | rcu_read_lock(); | ||
1754 | if (!is_multicast_ether_addr(skb->data)) | 1755 | if (!is_multicast_ether_addr(skb->data)) |
1755 | mppath = mpp_path_lookup(skb->data, sdata); | 1756 | mppath = mpp_path_lookup(skb->data, sdata); |
1756 | 1757 | ||
@@ -1765,13 +1766,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1765 | !(mppath && compare_ether_addr(mppath->mpp, skb->data))) { | 1766 | !(mppath && compare_ether_addr(mppath->mpp, skb->data))) { |
1766 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, | 1767 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, |
1767 | skb->data, skb->data + ETH_ALEN); | 1768 | skb->data, skb->data + ETH_ALEN); |
1769 | rcu_read_unlock(); | ||
1768 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, | 1770 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, |
1769 | sdata, NULL, NULL); | 1771 | sdata, NULL, NULL); |
1770 | } else { | 1772 | } else { |
1771 | int is_mesh_mcast = 1; | 1773 | int is_mesh_mcast = 1; |
1772 | const u8 *mesh_da; | 1774 | const u8 *mesh_da; |
1773 | 1775 | ||
1774 | rcu_read_lock(); | ||
1775 | if (is_multicast_ether_addr(skb->data)) | 1776 | if (is_multicast_ether_addr(skb->data)) |
1776 | /* DA TA mSA AE:SA */ | 1777 | /* DA TA mSA AE:SA */ |
1777 | mesh_da = skb->data; | 1778 | mesh_da = skb->data; |
@@ -2534,8 +2535,9 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
2534 | skb_set_network_header(skb, 0); | 2535 | skb_set_network_header(skb, 0); |
2535 | skb_set_transport_header(skb, 0); | 2536 | skb_set_transport_header(skb, 0); |
2536 | 2537 | ||
2537 | /* send all internal mgmt frames on VO */ | 2538 | /* Send all internal mgmt frames on VO. Accordingly set TID to 7. */ |
2538 | skb_set_queue_mapping(skb, 0); | 2539 | skb_set_queue_mapping(skb, IEEE80211_AC_VO); |
2540 | skb->priority = 7; | ||
2539 | 2541 | ||
2540 | /* | 2542 | /* |
2541 | * The other path calling ieee80211_xmit is from the tasklet, | 2543 | * The other path calling ieee80211_xmit is from the tasklet, |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ef0560a2346a..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 | ||