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/tx.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/tx.c')
-rw-r--r-- | net/mac80211/tx.c | 103 |
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 | ||
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; |