aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/tx.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/tx.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/tx.c')
-rw-r--r--net/mac80211/tx.c103
1 files changed, 56 insertions, 47 deletions
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
2478u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif) 2468u8 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; 2492unlock:
2493 rcu_read_unlock();
2494 return count;
2488} 2495}
2489EXPORT_SYMBOL(ieee80211_csa_update_counter); 2496EXPORT_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;