diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2014-06-05 08:21:36 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2014-06-23 08:22:06 -0400 |
commit | af296bdb8da4d0a4284de10fc4a61497272ddf11 (patch) | |
tree | 5387b60fbc8d858402068f2ee69d57104f961e5f /net/mac80211 | |
parent | b49328361bab10d786e321aeae79b4429fdff38c (diff) |
mac80211: move csa counters from sdata to beacon/presp
Having csa counters part of beacon and probe_resp
structures makes it easier to get rid of possible
races between setting a beacon and updating
counters on SMP systems by guaranteeing counters
are always consistent against given beacon struct.
While at it relax WARN_ON into WARN_ON_ONCE to
prevent spamming logs and racing.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
[remove pointless array check]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 67 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 16 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 2 | ||||
-rw-r--r-- | net/mac80211/tx.c | 103 |
5 files changed, 115 insertions, 75 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b6d73c14e1ae..af3eac482acd 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -554,7 +554,8 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, | |||
554 | } | 554 | } |
555 | 555 | ||
556 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | 556 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, |
557 | const u8 *resp, size_t resp_len) | 557 | const u8 *resp, size_t resp_len, |
558 | const struct ieee80211_csa_settings *csa) | ||
558 | { | 559 | { |
559 | struct probe_resp *new, *old; | 560 | struct probe_resp *new, *old; |
560 | 561 | ||
@@ -570,6 +571,11 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
570 | new->len = resp_len; | 571 | new->len = resp_len; |
571 | memcpy(new->data, resp, resp_len); | 572 | memcpy(new->data, resp, resp_len); |
572 | 573 | ||
574 | if (csa) | ||
575 | memcpy(new->csa_counter_offsets, csa->counter_offsets_presp, | ||
576 | csa->n_counter_offsets_presp * | ||
577 | sizeof(new->csa_counter_offsets[0])); | ||
578 | |||
573 | rcu_assign_pointer(sdata->u.ap.probe_resp, new); | 579 | rcu_assign_pointer(sdata->u.ap.probe_resp, new); |
574 | if (old) | 580 | if (old) |
575 | kfree_rcu(old, rcu_head); | 581 | kfree_rcu(old, rcu_head); |
@@ -578,7 +584,8 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
578 | } | 584 | } |
579 | 585 | ||
580 | static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | 586 | static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, |
581 | struct cfg80211_beacon_data *params) | 587 | struct cfg80211_beacon_data *params, |
588 | const struct ieee80211_csa_settings *csa) | ||
582 | { | 589 | { |
583 | struct beacon_data *new, *old; | 590 | struct beacon_data *new, *old; |
584 | int new_head_len, new_tail_len; | 591 | int new_head_len, new_tail_len; |
@@ -622,6 +629,13 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | |||
622 | new->head_len = new_head_len; | 629 | new->head_len = new_head_len; |
623 | new->tail_len = new_tail_len; | 630 | new->tail_len = new_tail_len; |
624 | 631 | ||
632 | if (csa) { | ||
633 | new->csa_current_counter = csa->count; | ||
634 | memcpy(new->csa_counter_offsets, csa->counter_offsets_beacon, | ||
635 | csa->n_counter_offsets_beacon * | ||
636 | sizeof(new->csa_counter_offsets[0])); | ||
637 | } | ||
638 | |||
625 | /* copy in head */ | 639 | /* copy in head */ |
626 | if (params->head) | 640 | if (params->head) |
627 | memcpy(new->head, params->head, new_head_len); | 641 | memcpy(new->head, params->head, new_head_len); |
@@ -636,7 +650,7 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | |||
636 | memcpy(new->tail, old->tail, new_tail_len); | 650 | memcpy(new->tail, old->tail, new_tail_len); |
637 | 651 | ||
638 | err = ieee80211_set_probe_resp(sdata, params->probe_resp, | 652 | err = ieee80211_set_probe_resp(sdata, params->probe_resp, |
639 | params->probe_resp_len); | 653 | params->probe_resp_len, csa); |
640 | if (err < 0) | 654 | if (err < 0) |
641 | return err; | 655 | return err; |
642 | if (err == 0) | 656 | if (err == 0) |
@@ -721,7 +735,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
721 | sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |= | 735 | sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |= |
722 | IEEE80211_P2P_OPPPS_ENABLE_BIT; | 736 | IEEE80211_P2P_OPPPS_ENABLE_BIT; |
723 | 737 | ||
724 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon); | 738 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon, NULL); |
725 | if (err < 0) { | 739 | if (err < 0) { |
726 | ieee80211_vif_release_channel(sdata); | 740 | ieee80211_vif_release_channel(sdata); |
727 | return err; | 741 | return err; |
@@ -769,7 +783,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
769 | if (!old) | 783 | if (!old) |
770 | return -ENOENT; | 784 | return -ENOENT; |
771 | 785 | ||
772 | err = ieee80211_assign_beacon(sdata, params); | 786 | err = ieee80211_assign_beacon(sdata, params, NULL); |
773 | if (err < 0) | 787 | if (err < 0) |
774 | return err; | 788 | return err; |
775 | ieee80211_bss_info_change_notify(sdata, err); | 789 | ieee80211_bss_info_change_notify(sdata, err); |
@@ -2752,7 +2766,8 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
2752 | 2766 | ||
2753 | switch (sdata->vif.type) { | 2767 | switch (sdata->vif.type) { |
2754 | case NL80211_IFTYPE_AP: | 2768 | case NL80211_IFTYPE_AP: |
2755 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); | 2769 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, |
2770 | NULL); | ||
2756 | kfree(sdata->u.ap.next_beacon); | 2771 | kfree(sdata->u.ap.next_beacon); |
2757 | sdata->u.ap.next_beacon = NULL; | 2772 | sdata->u.ap.next_beacon = NULL; |
2758 | 2773 | ||
@@ -2855,6 +2870,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
2855 | struct cfg80211_csa_settings *params, | 2870 | struct cfg80211_csa_settings *params, |
2856 | u32 *changed) | 2871 | u32 *changed) |
2857 | { | 2872 | { |
2873 | struct ieee80211_csa_settings csa = {}; | ||
2858 | int err; | 2874 | int err; |
2859 | 2875 | ||
2860 | switch (sdata->vif.type) { | 2876 | switch (sdata->vif.type) { |
@@ -2889,20 +2905,13 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
2889 | IEEE80211_MAX_CSA_COUNTERS_NUM)) | 2905 | IEEE80211_MAX_CSA_COUNTERS_NUM)) |
2890 | return -EINVAL; | 2906 | return -EINVAL; |
2891 | 2907 | ||
2892 | /* make sure we don't have garbage in other counters */ | 2908 | csa.counter_offsets_beacon = params->counter_offsets_beacon; |
2893 | memset(sdata->csa_counter_offset_beacon, 0, | 2909 | csa.counter_offsets_presp = params->counter_offsets_presp; |
2894 | sizeof(sdata->csa_counter_offset_beacon)); | 2910 | csa.n_counter_offsets_beacon = params->n_counter_offsets_beacon; |
2895 | memset(sdata->csa_counter_offset_presp, 0, | 2911 | csa.n_counter_offsets_presp = params->n_counter_offsets_presp; |
2896 | sizeof(sdata->csa_counter_offset_presp)); | 2912 | csa.count = params->count; |
2897 | |||
2898 | memcpy(sdata->csa_counter_offset_beacon, | ||
2899 | params->counter_offsets_beacon, | ||
2900 | params->n_counter_offsets_beacon * sizeof(u16)); | ||
2901 | memcpy(sdata->csa_counter_offset_presp, | ||
2902 | params->counter_offsets_presp, | ||
2903 | params->n_counter_offsets_presp * sizeof(u16)); | ||
2904 | 2913 | ||
2905 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); | 2914 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa); |
2906 | if (err < 0) { | 2915 | if (err < 0) { |
2907 | kfree(sdata->u.ap.next_beacon); | 2916 | kfree(sdata->u.ap.next_beacon); |
2908 | return err; | 2917 | return err; |
@@ -3046,7 +3055,6 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3046 | sdata->csa_radar_required = params->radar_required; | 3055 | sdata->csa_radar_required = params->radar_required; |
3047 | sdata->csa_chandef = params->chandef; | 3056 | sdata->csa_chandef = params->chandef; |
3048 | sdata->csa_block_tx = params->block_tx; | 3057 | sdata->csa_block_tx = params->block_tx; |
3049 | sdata->csa_current_counter = params->count; | ||
3050 | sdata->vif.csa_active = true; | 3058 | sdata->vif.csa_active = true; |
3051 | 3059 | ||
3052 | if (sdata->csa_block_tx) | 3060 | if (sdata->csa_block_tx) |
@@ -3194,10 +3202,23 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
3194 | sdata->vif.type == NL80211_IFTYPE_ADHOC) && | 3202 | sdata->vif.type == NL80211_IFTYPE_ADHOC) && |
3195 | params->n_csa_offsets) { | 3203 | params->n_csa_offsets) { |
3196 | int i; | 3204 | int i; |
3197 | u8 c = sdata->csa_current_counter; | 3205 | struct beacon_data *beacon = NULL; |
3198 | 3206 | ||
3199 | for (i = 0; i < params->n_csa_offsets; i++) | 3207 | rcu_read_lock(); |
3200 | data[params->csa_offsets[i]] = c; | 3208 | |
3209 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
3210 | beacon = rcu_dereference(sdata->u.ap.beacon); | ||
3211 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
3212 | beacon = rcu_dereference(sdata->u.ibss.presp); | ||
3213 | else if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
3214 | beacon = rcu_dereference(sdata->u.mesh.beacon); | ||
3215 | |||
3216 | if (beacon) | ||
3217 | for (i = 0; i < params->n_csa_offsets; i++) | ||
3218 | data[params->csa_offsets[i]] = | ||
3219 | beacon->csa_current_counter; | ||
3220 | |||
3221 | rcu_read_unlock(); | ||
3201 | } | 3222 | } |
3202 | 3223 | ||
3203 | IEEE80211_SKB_CB(skb)->flags = flags; | 3224 | IEEE80211_SKB_CB(skb)->flags = flags; |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 18ee0a256b1e..713485f9effc 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -143,7 +143,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, | |||
143 | *pos++ = csa_settings->block_tx ? 1 : 0; | 143 | *pos++ = csa_settings->block_tx ? 1 : 0; |
144 | *pos++ = ieee80211_frequency_to_channel( | 144 | *pos++ = ieee80211_frequency_to_channel( |
145 | csa_settings->chandef.chan->center_freq); | 145 | csa_settings->chandef.chan->center_freq); |
146 | sdata->csa_counter_offset_beacon[0] = (pos - presp->head); | 146 | presp->csa_counter_offsets[0] = (pos - presp->head); |
147 | *pos++ = csa_settings->count; | 147 | *pos++ = csa_settings->count; |
148 | } | 148 | } |
149 | 149 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4372d48b718f..d9af7ef3c11a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -229,16 +229,29 @@ struct ieee80211_rx_data { | |||
229 | u16 tkip_iv16; | 229 | u16 tkip_iv16; |
230 | }; | 230 | }; |
231 | 231 | ||
232 | struct ieee80211_csa_settings { | ||
233 | const u16 *counter_offsets_beacon; | ||
234 | const u16 *counter_offsets_presp; | ||
235 | |||
236 | int n_counter_offsets_beacon; | ||
237 | int n_counter_offsets_presp; | ||
238 | |||
239 | u8 count; | ||
240 | }; | ||
241 | |||
232 | struct beacon_data { | 242 | struct beacon_data { |
233 | u8 *head, *tail; | 243 | u8 *head, *tail; |
234 | int head_len, tail_len; | 244 | int head_len, tail_len; |
235 | struct ieee80211_meshconf_ie *meshconf; | 245 | struct ieee80211_meshconf_ie *meshconf; |
246 | u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM]; | ||
247 | u8 csa_current_counter; | ||
236 | struct rcu_head rcu_head; | 248 | struct rcu_head rcu_head; |
237 | }; | 249 | }; |
238 | 250 | ||
239 | struct probe_resp { | 251 | struct probe_resp { |
240 | struct rcu_head rcu_head; | 252 | struct rcu_head rcu_head; |
241 | int len; | 253 | int len; |
254 | u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM]; | ||
242 | u8 data[0]; | 255 | u8 data[0]; |
243 | }; | 256 | }; |
244 | 257 | ||
@@ -754,8 +767,6 @@ struct ieee80211_sub_if_data { | |||
754 | struct mac80211_qos_map __rcu *qos_map; | 767 | struct mac80211_qos_map __rcu *qos_map; |
755 | 768 | ||
756 | struct work_struct csa_finalize_work; | 769 | struct work_struct csa_finalize_work; |
757 | u16 csa_counter_offset_beacon[IEEE80211_MAX_CSA_COUNTERS_NUM]; | ||
758 | u16 csa_counter_offset_presp[IEEE80211_MAX_CSA_COUNTERS_NUM]; | ||
759 | bool csa_radar_required; | 770 | bool csa_radar_required; |
760 | bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ | 771 | bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ |
761 | struct cfg80211_chan_def csa_chandef; | 772 | struct cfg80211_chan_def csa_chandef; |
@@ -767,7 +778,6 @@ struct ieee80211_sub_if_data { | |||
767 | struct ieee80211_chanctx *reserved_chanctx; | 778 | struct ieee80211_chanctx *reserved_chanctx; |
768 | struct cfg80211_chan_def reserved_chandef; | 779 | struct cfg80211_chan_def reserved_chandef; |
769 | bool reserved_radar_required; | 780 | bool reserved_radar_required; |
770 | u8 csa_current_counter; | ||
771 | 781 | ||
772 | /* used to reconfigure hardware SM PS */ | 782 | /* used to reconfigure hardware SM PS */ |
773 | struct work_struct recalc_smps; | 783 | struct work_struct recalc_smps; |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index da164685b524..e9f99c1e3fad 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -679,7 +679,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
679 | *pos++ = 0x0; | 679 | *pos++ = 0x0; |
680 | *pos++ = ieee80211_frequency_to_channel( | 680 | *pos++ = ieee80211_frequency_to_channel( |
681 | csa->settings.chandef.chan->center_freq); | 681 | csa->settings.chandef.chan->center_freq); |
682 | sdata->csa_counter_offset_beacon[0] = hdr_len + 6; | 682 | bcn->csa_counter_offsets[0] = hdr_len + 6; |
683 | *pos++ = csa->settings.count; | 683 | *pos++ = csa->settings.count; |
684 | *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; | 684 | *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; |
685 | *pos++ = 6; | 685 | *pos++ = 6; |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3c80bf29b050..ed56f0091663 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -2426,7 +2426,7 @@ static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata, | |||
2426 | u8 *beacon_data; | 2426 | u8 *beacon_data; |
2427 | size_t beacon_data_len; | 2427 | size_t beacon_data_len; |
2428 | int i; | 2428 | int i; |
2429 | u8 count = sdata->csa_current_counter; | 2429 | u8 count = beacon->csa_current_counter; |
2430 | 2430 | ||
2431 | switch (sdata->vif.type) { | 2431 | switch (sdata->vif.type) { |
2432 | case NL80211_IFTYPE_AP: | 2432 | case NL80211_IFTYPE_AP: |
@@ -2445,46 +2445,53 @@ static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata, | |||
2445 | return; | 2445 | return; |
2446 | } | 2446 | } |
2447 | 2447 | ||
2448 | rcu_read_lock(); | ||
2448 | for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) { | 2449 | for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) { |
2449 | u16 counter_offset_beacon = | 2450 | resp = rcu_dereference(sdata->u.ap.probe_resp); |
2450 | sdata->csa_counter_offset_beacon[i]; | ||
2451 | u16 counter_offset_presp = sdata->csa_counter_offset_presp[i]; | ||
2452 | |||
2453 | if (counter_offset_beacon) { | ||
2454 | if (WARN_ON(counter_offset_beacon >= beacon_data_len)) | ||
2455 | return; | ||
2456 | |||
2457 | beacon_data[counter_offset_beacon] = count; | ||
2458 | } | ||
2459 | |||
2460 | if (sdata->vif.type == NL80211_IFTYPE_AP && | ||
2461 | counter_offset_presp) { | ||
2462 | rcu_read_lock(); | ||
2463 | resp = rcu_dereference(sdata->u.ap.probe_resp); | ||
2464 | 2451 | ||
2465 | /* If nl80211 accepted the offset, this should | 2452 | if (beacon->csa_counter_offsets[i]) { |
2466 | * not happen. | 2453 | if (WARN_ON_ONCE(beacon->csa_counter_offsets[i] >= |
2467 | */ | 2454 | beacon_data_len)) { |
2468 | if (WARN_ON(!resp)) { | ||
2469 | rcu_read_unlock(); | 2455 | rcu_read_unlock(); |
2470 | return; | 2456 | return; |
2471 | } | 2457 | } |
2472 | resp->data[counter_offset_presp] = count; | 2458 | |
2473 | rcu_read_unlock(); | 2459 | beacon_data[beacon->csa_counter_offsets[i]] = count; |
2474 | } | 2460 | } |
2461 | |||
2462 | if (sdata->vif.type == NL80211_IFTYPE_AP && resp) | ||
2463 | resp->data[resp->csa_counter_offsets[i]] = count; | ||
2475 | } | 2464 | } |
2465 | rcu_read_unlock(); | ||
2476 | } | 2466 | } |
2477 | 2467 | ||
2478 | u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif) | 2468 | u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif) |
2479 | { | 2469 | { |
2480 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 2470 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
2471 | struct beacon_data *beacon = NULL; | ||
2472 | u8 count = 0; | ||
2481 | 2473 | ||
2482 | sdata->csa_current_counter--; | 2474 | rcu_read_lock(); |
2475 | |||
2476 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
2477 | beacon = rcu_dereference(sdata->u.ap.beacon); | ||
2478 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
2479 | beacon = rcu_dereference(sdata->u.ibss.presp); | ||
2480 | else if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
2481 | beacon = rcu_dereference(sdata->u.mesh.beacon); | ||
2482 | |||
2483 | if (!beacon) | ||
2484 | goto unlock; | ||
2485 | |||
2486 | beacon->csa_current_counter--; | ||
2483 | 2487 | ||
2484 | /* the counter should never reach 0 */ | 2488 | /* the counter should never reach 0 */ |
2485 | WARN_ON(!sdata->csa_current_counter); | 2489 | WARN_ON_ONCE(!beacon->csa_current_counter); |
2490 | count = beacon->csa_current_counter; | ||
2486 | 2491 | ||
2487 | return sdata->csa_current_counter; | 2492 | unlock: |
2493 | rcu_read_unlock(); | ||
2494 | return count; | ||
2488 | } | 2495 | } |
2489 | EXPORT_SYMBOL(ieee80211_csa_update_counter); | 2496 | EXPORT_SYMBOL(ieee80211_csa_update_counter); |
2490 | 2497 | ||
@@ -2494,7 +2501,6 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) | |||
2494 | struct beacon_data *beacon = NULL; | 2501 | struct beacon_data *beacon = NULL; |
2495 | u8 *beacon_data; | 2502 | u8 *beacon_data; |
2496 | size_t beacon_data_len; | 2503 | size_t beacon_data_len; |
2497 | int counter_beacon = sdata->csa_counter_offset_beacon[0]; | ||
2498 | int ret = false; | 2504 | int ret = false; |
2499 | 2505 | ||
2500 | if (!ieee80211_sdata_running(sdata)) | 2506 | if (!ieee80211_sdata_running(sdata)) |
@@ -2532,10 +2538,10 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) | |||
2532 | goto out; | 2538 | goto out; |
2533 | } | 2539 | } |
2534 | 2540 | ||
2535 | if (WARN_ON(counter_beacon > beacon_data_len)) | 2541 | if (WARN_ON_ONCE(beacon->csa_counter_offsets[0] > beacon_data_len)) |
2536 | goto out; | 2542 | goto out; |
2537 | 2543 | ||
2538 | if (beacon_data[counter_beacon] == 1) | 2544 | if (beacon_data[beacon->csa_counter_offsets[0]] == 1) |
2539 | ret = true; | 2545 | ret = true; |
2540 | out: | 2546 | out: |
2541 | rcu_read_unlock(); | 2547 | rcu_read_unlock(); |
@@ -2551,6 +2557,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
2551 | bool is_template) | 2557 | bool is_template) |
2552 | { | 2558 | { |
2553 | struct ieee80211_local *local = hw_to_local(hw); | 2559 | struct ieee80211_local *local = hw_to_local(hw); |
2560 | struct beacon_data *beacon = NULL; | ||
2554 | struct sk_buff *skb = NULL; | 2561 | struct sk_buff *skb = NULL; |
2555 | struct ieee80211_tx_info *info; | 2562 | struct ieee80211_tx_info *info; |
2556 | struct ieee80211_sub_if_data *sdata = NULL; | 2563 | struct ieee80211_sub_if_data *sdata = NULL; |
@@ -2572,8 +2579,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
2572 | 2579 | ||
2573 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 2580 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
2574 | struct ieee80211_if_ap *ap = &sdata->u.ap; | 2581 | struct ieee80211_if_ap *ap = &sdata->u.ap; |
2575 | struct beacon_data *beacon = rcu_dereference(ap->beacon); | ||
2576 | 2582 | ||
2583 | beacon = rcu_dereference(ap->beacon); | ||
2577 | if (beacon) { | 2584 | if (beacon) { |
2578 | if (sdata->vif.csa_active) { | 2585 | if (sdata->vif.csa_active) { |
2579 | if (!is_template) | 2586 | if (!is_template) |
@@ -2616,34 +2623,34 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
2616 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 2623 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
2617 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 2624 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
2618 | struct ieee80211_hdr *hdr; | 2625 | struct ieee80211_hdr *hdr; |
2619 | struct beacon_data *presp = rcu_dereference(ifibss->presp); | ||
2620 | 2626 | ||
2621 | if (!presp) | 2627 | beacon = rcu_dereference(ifibss->presp); |
2628 | if (!beacon) | ||
2622 | goto out; | 2629 | goto out; |
2623 | 2630 | ||
2624 | if (sdata->vif.csa_active) { | 2631 | if (sdata->vif.csa_active) { |
2625 | if (!is_template) | 2632 | if (!is_template) |
2626 | ieee80211_csa_update_counter(vif); | 2633 | ieee80211_csa_update_counter(vif); |
2627 | 2634 | ||
2628 | ieee80211_set_csa(sdata, presp); | 2635 | ieee80211_set_csa(sdata, beacon); |
2629 | } | 2636 | } |
2630 | 2637 | ||
2631 | skb = dev_alloc_skb(local->tx_headroom + presp->head_len + | 2638 | skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + |
2632 | local->hw.extra_beacon_tailroom); | 2639 | local->hw.extra_beacon_tailroom); |
2633 | if (!skb) | 2640 | if (!skb) |
2634 | goto out; | 2641 | goto out; |
2635 | skb_reserve(skb, local->tx_headroom); | 2642 | skb_reserve(skb, local->tx_headroom); |
2636 | memcpy(skb_put(skb, presp->head_len), presp->head, | 2643 | memcpy(skb_put(skb, beacon->head_len), beacon->head, |
2637 | presp->head_len); | 2644 | beacon->head_len); |
2638 | 2645 | ||
2639 | hdr = (struct ieee80211_hdr *) skb->data; | 2646 | hdr = (struct ieee80211_hdr *) skb->data; |
2640 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 2647 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
2641 | IEEE80211_STYPE_BEACON); | 2648 | IEEE80211_STYPE_BEACON); |
2642 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 2649 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
2643 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 2650 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
2644 | struct beacon_data *bcn = rcu_dereference(ifmsh->beacon); | ||
2645 | 2651 | ||
2646 | if (!bcn) | 2652 | beacon = rcu_dereference(ifmsh->beacon); |
2653 | if (!beacon) | ||
2647 | goto out; | 2654 | goto out; |
2648 | 2655 | ||
2649 | if (sdata->vif.csa_active) { | 2656 | if (sdata->vif.csa_active) { |
@@ -2655,40 +2662,42 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
2655 | */ | 2662 | */ |
2656 | ieee80211_csa_update_counter(vif); | 2663 | ieee80211_csa_update_counter(vif); |
2657 | 2664 | ||
2658 | ieee80211_set_csa(sdata, bcn); | 2665 | ieee80211_set_csa(sdata, beacon); |
2659 | } | 2666 | } |
2660 | 2667 | ||
2661 | if (ifmsh->sync_ops) | 2668 | if (ifmsh->sync_ops) |
2662 | ifmsh->sync_ops->adjust_tbtt(sdata, bcn); | 2669 | ifmsh->sync_ops->adjust_tbtt(sdata, beacon); |
2663 | 2670 | ||
2664 | skb = dev_alloc_skb(local->tx_headroom + | 2671 | skb = dev_alloc_skb(local->tx_headroom + |
2665 | bcn->head_len + | 2672 | beacon->head_len + |
2666 | 256 + /* TIM IE */ | 2673 | 256 + /* TIM IE */ |
2667 | bcn->tail_len + | 2674 | beacon->tail_len + |
2668 | local->hw.extra_beacon_tailroom); | 2675 | local->hw.extra_beacon_tailroom); |
2669 | if (!skb) | 2676 | if (!skb) |
2670 | goto out; | 2677 | goto out; |
2671 | skb_reserve(skb, local->tx_headroom); | 2678 | skb_reserve(skb, local->tx_headroom); |
2672 | memcpy(skb_put(skb, bcn->head_len), bcn->head, bcn->head_len); | 2679 | memcpy(skb_put(skb, beacon->head_len), beacon->head, |
2680 | beacon->head_len); | ||
2673 | ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template); | 2681 | ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template); |
2674 | 2682 | ||
2675 | if (offs) { | 2683 | if (offs) { |
2676 | offs->tim_offset = bcn->head_len; | 2684 | offs->tim_offset = beacon->head_len; |
2677 | offs->tim_length = skb->len - bcn->head_len; | 2685 | offs->tim_length = skb->len - beacon->head_len; |
2678 | } | 2686 | } |
2679 | 2687 | ||
2680 | memcpy(skb_put(skb, bcn->tail_len), bcn->tail, bcn->tail_len); | 2688 | memcpy(skb_put(skb, beacon->tail_len), beacon->tail, |
2689 | beacon->tail_len); | ||
2681 | } else { | 2690 | } else { |
2682 | WARN_ON(1); | 2691 | WARN_ON(1); |
2683 | goto out; | 2692 | goto out; |
2684 | } | 2693 | } |
2685 | 2694 | ||
2686 | /* CSA offsets */ | 2695 | /* CSA offsets */ |
2687 | if (offs) { | 2696 | if (offs && beacon) { |
2688 | int i; | 2697 | int i; |
2689 | 2698 | ||
2690 | for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; i++) { | 2699 | for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; i++) { |
2691 | u16 csa_off = sdata->csa_counter_offset_beacon[i]; | 2700 | u16 csa_off = beacon->csa_counter_offsets[i]; |
2692 | 2701 | ||
2693 | if (!csa_off) | 2702 | if (!csa_off) |
2694 | continue; | 2703 | continue; |