aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/cfg.c
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2014-06-05 08:21:36 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-06-23 08:22:06 -0400
commitaf296bdb8da4d0a4284de10fc4a61497272ddf11 (patch)
tree5387b60fbc8d858402068f2ee69d57104f961e5f /net/mac80211/cfg.c
parentb49328361bab10d786e321aeae79b4429fdff38c (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.c67
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
556static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, 556static 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
580static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, 586static 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, &params->beacon); 738 err = ieee80211_assign_beacon(sdata, &params->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, &params->beacon_csa); 2914 err = ieee80211_assign_beacon(sdata, &params->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;