diff options
-rw-r--r-- | net/mac80211/agg-rx.c | 3 | ||||
-rw-r--r-- | net/mac80211/agg-tx.c | 36 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 17 | ||||
-rw-r--r-- | net/mac80211/debugfs_key.c | 21 | ||||
-rw-r--r-- | net/mac80211/ht.c | 2 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 11 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 16 | ||||
-rw-r--r-- | net/mac80211/iface.c | 3 | ||||
-rw-r--r-- | net/mac80211/key.c | 22 | ||||
-rw-r--r-- | net/mac80211/key.h | 3 | ||||
-rw-r--r-- | net/mac80211/main.c | 2 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 2 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 20 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 15 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 17 | ||||
-rw-r--r-- | net/mac80211/tx.c | 2 |
16 files changed, 118 insertions, 74 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 f614ee602089..cd5125f77cc5 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -157,16 +157,19 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
157 | bool tx) | 157 | bool tx) |
158 | { | 158 | { |
159 | struct ieee80211_local *local = sta->local; | 159 | struct ieee80211_local *local = sta->local; |
160 | struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 160 | struct tid_ampdu_tx *tid_tx; |
161 | int ret; | 161 | int ret; |
162 | 162 | ||
163 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 163 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
164 | 164 | ||
165 | if (!tid_tx) | ||
166 | return -ENOENT; | ||
167 | |||
168 | spin_lock_bh(&sta->lock); | 165 | spin_lock_bh(&sta->lock); |
169 | 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 | |||
170 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { | 173 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { |
171 | /* not even started yet! */ | 174 | /* not even started yet! */ |
172 | ieee80211_assign_tid_tx(sta, tid, NULL); | 175 | ieee80211_assign_tid_tx(sta, tid, NULL); |
@@ -291,13 +294,13 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid) | |||
291 | 294 | ||
292 | 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) |
293 | { | 296 | { |
294 | struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 297 | struct tid_ampdu_tx *tid_tx; |
295 | struct ieee80211_local *local = sta->local; | 298 | struct ieee80211_local *local = sta->local; |
296 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 299 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
297 | u16 start_seq_num; | 300 | u16 start_seq_num; |
298 | int ret; | 301 | int ret; |
299 | 302 | ||
300 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 303 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
301 | 304 | ||
302 | /* | 305 | /* |
303 | * While we're asking the driver about the aggregation, | 306 | * While we're asking the driver about the aggregation, |
@@ -404,7 +407,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
404 | goto err_unlock_sta; | 407 | goto err_unlock_sta; |
405 | } | 408 | } |
406 | 409 | ||
407 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 410 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
408 | /* check if the TID is not in aggregation flow already */ | 411 | /* check if the TID is not in aggregation flow already */ |
409 | if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { | 412 | if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { |
410 | #ifdef CONFIG_MAC80211_HT_DEBUG | 413 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -491,16 +494,19 @@ ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid) | |||
491 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | 494 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, |
492 | struct sta_info *sta, u16 tid) | 495 | struct sta_info *sta, u16 tid) |
493 | { | 496 | { |
497 | struct tid_ampdu_tx *tid_tx; | ||
498 | |||
494 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 499 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
495 | 500 | ||
501 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | ||
502 | |||
496 | #ifdef CONFIG_MAC80211_HT_DEBUG | 503 | #ifdef CONFIG_MAC80211_HT_DEBUG |
497 | printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); | 504 | printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); |
498 | #endif | 505 | #endif |
499 | 506 | ||
500 | drv_ampdu_action(local, sta->sdata, | 507 | drv_ampdu_action(local, sta->sdata, |
501 | IEEE80211_AMPDU_TX_OPERATIONAL, | 508 | IEEE80211_AMPDU_TX_OPERATIONAL, |
502 | &sta->sta, tid, NULL, | 509 | &sta->sta, tid, NULL, tid_tx->buf_size); |
503 | sta->ampdu_mlme.tid_tx[tid]->buf_size); | ||
504 | 510 | ||
505 | /* | 511 | /* |
506 | * synchronize with TX path, while splicing the TX path | 512 | * synchronize with TX path, while splicing the TX path |
@@ -508,13 +514,13 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | |||
508 | */ | 514 | */ |
509 | spin_lock_bh(&sta->lock); | 515 | spin_lock_bh(&sta->lock); |
510 | 516 | ||
511 | ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid); | 517 | ieee80211_agg_splice_packets(local, tid_tx, tid); |
512 | /* | 518 | /* |
513 | * Now mark as operational. This will be visible | 519 | * Now mark as operational. This will be visible |
514 | * in the TX path, and lets it go lock-free in | 520 | * in the TX path, and lets it go lock-free in |
515 | * the common case. | 521 | * the common case. |
516 | */ | 522 | */ |
517 | set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state); | 523 | set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); |
518 | ieee80211_agg_splice_finish(local, tid); | 524 | ieee80211_agg_splice_finish(local, tid); |
519 | 525 | ||
520 | spin_unlock_bh(&sta->lock); | 526 | spin_unlock_bh(&sta->lock); |
@@ -548,7 +554,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) | |||
548 | } | 554 | } |
549 | 555 | ||
550 | mutex_lock(&sta->ampdu_mlme.mtx); | 556 | mutex_lock(&sta->ampdu_mlme.mtx); |
551 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 557 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
552 | 558 | ||
553 | if (WARN_ON(!tid_tx)) { | 559 | if (WARN_ON(!tid_tx)) { |
554 | #ifdef CONFIG_MAC80211_HT_DEBUG | 560 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -626,7 +632,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
626 | return -EINVAL; | 632 | return -EINVAL; |
627 | 633 | ||
628 | spin_lock_bh(&sta->lock); | 634 | spin_lock_bh(&sta->lock); |
629 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 635 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
630 | 636 | ||
631 | if (!tid_tx) { | 637 | if (!tid_tx) { |
632 | ret = -ENOENT; | 638 | ret = -ENOENT; |
@@ -682,7 +688,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
682 | 688 | ||
683 | mutex_lock(&sta->ampdu_mlme.mtx); | 689 | mutex_lock(&sta->ampdu_mlme.mtx); |
684 | spin_lock_bh(&sta->lock); | 690 | spin_lock_bh(&sta->lock); |
685 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 691 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
686 | 692 | ||
687 | 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)) { |
688 | #ifdef CONFIG_MAC80211_HT_DEBUG | 694 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -763,7 +769,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
763 | 769 | ||
764 | mutex_lock(&sta->ampdu_mlme.mtx); | 770 | mutex_lock(&sta->ampdu_mlme.mtx); |
765 | 771 | ||
766 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 772 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
767 | if (!tid_tx) | 773 | if (!tid_tx) |
768 | goto out; | 774 | goto out; |
769 | 775 | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2d1c1a5f3c51..6ecd5862735d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -177,11 +177,11 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
177 | goto out_unlock; | 177 | goto out_unlock; |
178 | 178 | ||
179 | if (pairwise) | 179 | if (pairwise) |
180 | key = sta->ptk; | 180 | key = key_mtx_dereference(local, sta->ptk); |
181 | else | 181 | else |
182 | key = sta->gtk[key_idx]; | 182 | key = key_mtx_dereference(local, sta->gtk[key_idx]); |
183 | } else | 183 | } else |
184 | key = sdata->keys[key_idx]; | 184 | key = key_mtx_dereference(local, sdata->keys[key_idx]); |
185 | 185 | ||
186 | if (!key) { | 186 | if (!key) { |
187 | ret = -ENOENT; | 187 | ret = -ENOENT; |
@@ -463,7 +463,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
463 | int size; | 463 | int size; |
464 | int err = -EINVAL; | 464 | int err = -EINVAL; |
465 | 465 | ||
466 | old = sdata->u.ap.beacon; | 466 | old = rtnl_dereference(sdata->u.ap.beacon); |
467 | 467 | ||
468 | /* head must not be zero-length */ | 468 | /* head must not be zero-length */ |
469 | if (params->head && !params->head_len) | 469 | if (params->head && !params->head_len) |
@@ -558,8 +558,7 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
558 | 558 | ||
559 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 559 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
560 | 560 | ||
561 | old = sdata->u.ap.beacon; | 561 | old = rtnl_dereference(sdata->u.ap.beacon); |
562 | |||
563 | if (old) | 562 | if (old) |
564 | return -EALREADY; | 563 | return -EALREADY; |
565 | 564 | ||
@@ -574,8 +573,7 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
574 | 573 | ||
575 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 574 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
576 | 575 | ||
577 | old = sdata->u.ap.beacon; | 576 | old = rtnl_dereference(sdata->u.ap.beacon); |
578 | |||
579 | if (!old) | 577 | if (!old) |
580 | return -ENOENT; | 578 | return -ENOENT; |
581 | 579 | ||
@@ -589,8 +587,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) | |||
589 | 587 | ||
590 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 588 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
591 | 589 | ||
592 | old = sdata->u.ap.beacon; | 590 | old = rtnl_dereference(sdata->u.ap.beacon); |
593 | |||
594 | if (!old) | 591 | if (!old) |
595 | return -ENOENT; | 592 | return -ENOENT; |
596 | 593 | ||
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/ht.c b/net/mac80211/ht.c index 9f5842a43111..591add22bcc0 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -160,7 +160,7 @@ void ieee80211_ba_session_work(struct work_struct *work) | |||
160 | continue; | 160 | continue; |
161 | } | 161 | } |
162 | 162 | ||
163 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 163 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
164 | if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP, | 164 | if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP, |
165 | &tid_tx->state)) | 165 | &tid_tx->state)) |
166 | ___ieee80211_stop_tx_ba_session(sta, tid, | 166 | ___ieee80211_stop_tx_ba_session(sta, tid, |
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 82f90ff8bb18..ed755889645d 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, |
@@ -567,9 +568,10 @@ struct ieee80211_sub_if_data { | |||
567 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; | 568 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; |
568 | unsigned int fragment_next; | 569 | unsigned int fragment_next; |
569 | 570 | ||
570 | struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | 571 | struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
571 | struct ieee80211_key *default_unicast_key, *default_multicast_key; | 572 | struct ieee80211_key __rcu *default_unicast_key; |
572 | struct ieee80211_key *default_mgmt_key; | 573 | struct ieee80211_key __rcu *default_multicast_key; |
574 | struct ieee80211_key __rcu *default_mgmt_key; | ||
573 | 575 | ||
574 | u16 sequence_number; | 576 | u16 sequence_number; |
575 | __be16 control_port_protocol; | 577 | __be16 control_port_protocol; |
@@ -805,7 +807,7 @@ struct ieee80211_local { | |||
805 | spinlock_t sta_lock; | 807 | spinlock_t sta_lock; |
806 | unsigned long num_sta; | 808 | unsigned long num_sta; |
807 | struct list_head sta_list, sta_pending_list; | 809 | struct list_head sta_list, sta_pending_list; |
808 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 810 | struct sta_info __rcu *sta_hash[STA_HASH_SIZE]; |
809 | struct timer_list sta_cleanup; | 811 | struct timer_list sta_cleanup; |
810 | struct work_struct sta_finish_work; | 812 | struct work_struct sta_finish_work; |
811 | int sta_generation; | 813 | int sta_generation; |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 4054399be907..0d00ac93d958 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 958832dd4f0a..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); |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index e5432ef8b203..d801d5351336 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -146,4 +146,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); | |||
146 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); | 146 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); |
147 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); | 147 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); |
148 | 148 | ||
149 | #define key_mtx_dereference(local, ref) \ | ||
150 | rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx))) | ||
151 | |||
149 | #endif /* IEEE80211_KEY_H */ | 152 | #endif /* IEEE80211_KEY_H */ |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 79a2281678bf..0d7b08db8e56 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -871,8 +871,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
871 | * and we need some headroom for passing the frame to monitor | 871 | * and we need some headroom for passing the frame to monitor |
872 | * interfaces, but never both at the same time. | 872 | * interfaces, but never both at the same time. |
873 | */ | 873 | */ |
874 | #ifndef __CHECKER__ | ||
874 | BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM != | 875 | BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM != |
875 | sizeof(struct ieee80211_tx_status_rtap_hdr)); | 876 | sizeof(struct ieee80211_tx_status_rtap_hdr)); |
877 | #endif | ||
876 | 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, |
877 | sizeof(struct ieee80211_tx_status_rtap_hdr)); | 879 | sizeof(struct ieee80211_tx_status_rtap_hdr)); |
878 | 880 | ||
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 5c0c20389a1a..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; |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 2aec7c4f357b..2b18053070c1 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -560,6 +560,14 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
560 | } | 560 | } |
561 | 561 | ||
562 | 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 | |||
563 | 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, |
564 | struct ieee80211_mgmt *mgmt, | 572 | struct ieee80211_mgmt *mgmt, |
565 | u8 *prep_elem, u32 metric) | 573 | u8 *prep_elem, u32 metric) |
@@ -599,7 +607,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | |||
599 | spin_unlock_bh(&mpath->state_lock); | 607 | spin_unlock_bh(&mpath->state_lock); |
600 | goto fail; | 608 | goto fail; |
601 | } | 609 | } |
602 | memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN); | 610 | memcpy(next_hop, next_hop_deref_protected(mpath)->sta.addr, ETH_ALEN); |
603 | spin_unlock_bh(&mpath->state_lock); | 611 | spin_unlock_bh(&mpath->state_lock); |
604 | --ttl; | 612 | --ttl; |
605 | flags = PREP_IE_FLAGS(prep_elem); | 613 | flags = PREP_IE_FLAGS(prep_elem); |
@@ -651,7 +659,8 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | |||
651 | if (mpath) { | 659 | if (mpath) { |
652 | spin_lock_bh(&mpath->state_lock); | 660 | spin_lock_bh(&mpath->state_lock); |
653 | if (mpath->flags & MESH_PATH_ACTIVE && | 661 | if (mpath->flags & MESH_PATH_ACTIVE && |
654 | memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 && | 662 | memcmp(ta, next_hop_deref_protected(mpath)->sta.addr, |
663 | ETH_ALEN) == 0 && | ||
655 | (!(mpath->flags & MESH_PATH_SN_VALID) || | 664 | (!(mpath->flags & MESH_PATH_SN_VALID) || |
656 | SN_GT(target_sn, mpath->sn))) { | 665 | SN_GT(target_sn, mpath->sn))) { |
657 | mpath->flags &= ~MESH_PATH_ACTIVE; | 666 | mpath->flags &= ~MESH_PATH_ACTIVE; |
@@ -913,6 +922,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
913 | { | 922 | { |
914 | struct sk_buff *skb_to_free = NULL; | 923 | struct sk_buff *skb_to_free = NULL; |
915 | struct mesh_path *mpath; | 924 | struct mesh_path *mpath; |
925 | struct sta_info *next_hop; | ||
916 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 926 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
917 | u8 *target_addr = hdr->addr3; | 927 | u8 *target_addr = hdr->addr3; |
918 | int err = 0; | 928 | int err = 0; |
@@ -940,7 +950,11 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
940 | mesh_queue_preq(mpath, | 950 | mesh_queue_preq(mpath, |
941 | PREQ_Q_F_START | PREQ_Q_F_REFRESH); | 951 | PREQ_Q_F_START | PREQ_Q_F_REFRESH); |
942 | } | 952 | } |
943 | 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; | ||
944 | } else { | 958 | } else { |
945 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 959 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
946 | if (!(mpath->flags & MESH_PATH_RESOLVING)) { | 960 | if (!(mpath->flags & MESH_PATH_RESOLVING)) { |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index cba8309e9ace..82ab6b4643fc 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 | } |
@@ -654,9 +657,9 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
654 | 657 | ||
655 | mutex_lock(&local->key_mtx); | 658 | mutex_lock(&local->key_mtx); |
656 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) | 659 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) |
657 | __ieee80211_key_free(sta->gtk[i]); | 660 | __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i])); |
658 | if (sta->ptk) | 661 | if (sta->ptk) |
659 | __ieee80211_key_free(sta->ptk); | 662 | __ieee80211_key_free(key_mtx_dereference(local, sta->ptk)); |
660 | mutex_unlock(&local->key_mtx); | 663 | mutex_unlock(&local->key_mtx); |
661 | 664 | ||
662 | sta->dead = true; | 665 | sta->dead = true; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 55c51855ceb7..d6b566076f05 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -164,11 +164,11 @@ struct tid_ampdu_rx { | |||
164 | struct sta_ampdu_mlme { | 164 | struct sta_ampdu_mlme { |
165 | struct mutex mtx; | 165 | struct mutex mtx; |
166 | /* rx */ | 166 | /* rx */ |
167 | struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; | 167 | struct tid_ampdu_rx __rcu *tid_rx[STA_TID_NUM]; |
168 | 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)]; |
169 | /* tx */ | 169 | /* tx */ |
170 | struct work_struct work; | 170 | struct work_struct work; |
171 | 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]; | 172 | struct tid_ampdu_tx *tid_start_tx[STA_TID_NUM]; |
173 | u8 addba_req_num[STA_TID_NUM]; | 173 | u8 addba_req_num[STA_TID_NUM]; |
174 | u8 dialog_token_allocator; | 174 | u8 dialog_token_allocator; |
@@ -243,11 +243,11 @@ struct sta_ampdu_mlme { | |||
243 | struct sta_info { | 243 | struct sta_info { |
244 | /* General information, mostly static */ | 244 | /* General information, mostly static */ |
245 | struct list_head list; | 245 | struct list_head list; |
246 | struct sta_info *hnext; | 246 | struct sta_info __rcu *hnext; |
247 | struct ieee80211_local *local; | 247 | struct ieee80211_local *local; |
248 | struct ieee80211_sub_if_data *sdata; | 248 | struct ieee80211_sub_if_data *sdata; |
249 | struct ieee80211_key *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | 249 | struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
250 | struct ieee80211_key *ptk; | 250 | struct ieee80211_key __rcu *ptk; |
251 | struct rate_control_ref *rate_ctrl; | 251 | struct rate_control_ref *rate_ctrl; |
252 | void *rate_ctrl_priv; | 252 | void *rate_ctrl_priv; |
253 | spinlock_t lock; | 253 | spinlock_t lock; |
@@ -403,6 +403,13 @@ static inline u32 get_sta_flags(struct sta_info *sta) | |||
403 | void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, | 403 | void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, |
404 | struct tid_ampdu_tx *tid_tx); | 404 | struct tid_ampdu_tx *tid_tx); |
405 | 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 | } | ||
406 | 413 | ||
407 | #define STA_HASH_SIZE 256 | 414 | #define STA_HASH_SIZE 256 |
408 | #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 c9f12113ca6a..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 */ |