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/cfg.c | |
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/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 67 |
1 files changed, 44 insertions, 23 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; |