aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrei Otcheretianski <andrei.otcheretianski@intel.com>2014-05-09 07:11:50 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-05-15 09:01:00 -0400
commit1af586c9116cdf6863823a830593c48cd9bcecde (patch)
tree4026e2cc9aa1172aaaadc70025a74fcd083cf8eb
parent6ec8c332a0f93959e615158cc212b3abfd52abe7 (diff)
mac80211: Handle the CSA counters correctly
Make the beacon CSA counters part of ieee80211_mutable_offsets and don't decrement CSA counters when generating a beacon template. This permits the driver to offload the CSA counters handling. Since mac80211 updates the probe responses with the correct counter, the driver should sync the counter's value with mac80211 using ieee80211_csa_update_counter function. Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com> Signed-off-by: Luciano Coelho <luciano.coelho@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/net/mac80211.h23
-rw-r--r--net/mac80211/cfg.c4
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/tx.c76
4 files changed, 80 insertions, 25 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index e6521261a585..982d2cd80166 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3411,14 +3411,20 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
3411 */ 3411 */
3412void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets); 3412void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets);
3413 3413
3414#define IEEE80211_MAX_CSA_COUNTERS_NUM 2
3415
3414/** 3416/**
3415 * struct ieee80211_mutable_offsets - mutable beacon offsets 3417 * struct ieee80211_mutable_offsets - mutable beacon offsets
3416 * @tim_offset: position of TIM element 3418 * @tim_offset: position of TIM element
3417 * @tim_length: size of TIM element 3419 * @tim_length: size of TIM element
3420 * @csa_offs: array of IEEE80211_MAX_CSA_COUNTERS_NUM offsets to CSA counters.
3421 * This array can contain zero values which should be ignored.
3418 */ 3422 */
3419struct ieee80211_mutable_offsets { 3423struct ieee80211_mutable_offsets {
3420 u16 tim_offset; 3424 u16 tim_offset;
3421 u16 tim_length; 3425 u16 tim_length;
3426
3427 u16 csa_counter_offs[IEEE80211_MAX_CSA_COUNTERS_NUM];
3422}; 3428};
3423 3429
3424/** 3430/**
@@ -3433,7 +3439,8 @@ struct ieee80211_mutable_offsets {
3433 * 3439 *
3434 * This function should be used if the beacon frames are generated by the 3440 * This function should be used if the beacon frames are generated by the
3435 * device, and then the driver must use the returned beacon as the template 3441 * device, and then the driver must use the returned beacon as the template
3436 * The driver is responsible to update the DTIM count. 3442 * The driver or the device are responsible to update the DTIM and, when
3443 * applicable, the CSA count.
3437 * 3444 *
3438 * The driver is responsible for freeing the returned skb. 3445 * The driver is responsible for freeing the returned skb.
3439 * 3446 *
@@ -3486,6 +3493,20 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
3486} 3493}
3487 3494
3488/** 3495/**
3496 * ieee80211_csa_update_counter - request mac80211 to decrement the csa counter
3497 * @vif: &struct ieee80211_vif pointer from the add_interface callback.
3498 *
3499 * The csa counter should be updated after each beacon transmission.
3500 * This function is called implicitly when
3501 * ieee80211_beacon_get/ieee80211_beacon_get_tim are called, however if the
3502 * beacon frames are generated by the device, the driver should call this
3503 * function after each beacon transmission to sync mac80211's csa counters.
3504 *
3505 * Return: new csa counter value
3506 */
3507u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif);
3508
3509/**
3489 * ieee80211_csa_finish - notify mac80211 about channel switch 3510 * ieee80211_csa_finish - notify mac80211 about channel switch
3490 * @vif: &struct ieee80211_vif pointer from the add_interface callback. 3511 * @vif: &struct ieee80211_vif pointer from the add_interface callback.
3491 * 3512 *
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index d44dca56b8ff..bfd2534e5a4d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3502,10 +3502,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
3502 sdata->vif.type == NL80211_IFTYPE_ADHOC) && 3502 sdata->vif.type == NL80211_IFTYPE_ADHOC) &&
3503 params->n_csa_offsets) { 3503 params->n_csa_offsets) {
3504 int i; 3504 int i;
3505 u8 c = sdata->csa_current_counter;
3505 3506
3506 for (i = 0; i < params->n_csa_offsets; i++) 3507 for (i = 0; i < params->n_csa_offsets; i++)
3507 data[params->csa_offsets[i]] = 3508 data[params->csa_offsets[i]] = c;
3508 sdata->csa_current_counter;
3509 } 3509 }
3510 3510
3511 IEEE80211_SKB_CB(skb)->flags = flags; 3511 IEEE80211_SKB_CB(skb)->flags = flags;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 05ed592d8bbe..57e0b2682cef 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -70,8 +70,6 @@ struct ieee80211_local;
70 70
71#define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */) 71#define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */)
72 72
73#define IEEE80211_MAX_CSA_COUNTERS_NUM 2
74
75struct ieee80211_fragment_entry { 73struct ieee80211_fragment_entry {
76 unsigned long first_frag_time; 74 unsigned long first_frag_time;
77 unsigned int seq; 75 unsigned int seq;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 509456e5722d..5214686d9fd1 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2416,13 +2416,14 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
2416 return 0; 2416 return 0;
2417} 2417}
2418 2418
2419static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata, 2419static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata,
2420 struct beacon_data *beacon) 2420 struct beacon_data *beacon)
2421{ 2421{
2422 struct probe_resp *resp; 2422 struct probe_resp *resp;
2423 u8 *beacon_data; 2423 u8 *beacon_data;
2424 size_t beacon_data_len; 2424 size_t beacon_data_len;
2425 int i; 2425 int i;
2426 u8 count = sdata->csa_current_counter;
2426 2427
2427 switch (sdata->vif.type) { 2428 switch (sdata->vif.type) {
2428 case NL80211_IFTYPE_AP: 2429 case NL80211_IFTYPE_AP:
@@ -2450,16 +2451,7 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
2450 if (WARN_ON(counter_offset_beacon >= beacon_data_len)) 2451 if (WARN_ON(counter_offset_beacon >= beacon_data_len))
2451 return; 2452 return;
2452 2453
2453 /* Warn if the driver did not check for/react to csa 2454 beacon_data[counter_offset_beacon] = count;
2454 * completeness. A beacon with CSA counter set to 0
2455 * should never occur, because a counter of 1 means
2456 * switch just before the next beacon.
2457 */
2458 if (WARN_ON(beacon_data[counter_offset_beacon] == 1))
2459 return;
2460
2461 beacon_data[counter_offset_beacon] =
2462 sdata->csa_current_counter - 1;
2463 } 2455 }
2464 2456
2465 if (sdata->vif.type == NL80211_IFTYPE_AP && 2457 if (sdata->vif.type == NL80211_IFTYPE_AP &&
@@ -2474,14 +2466,24 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
2474 rcu_read_unlock(); 2466 rcu_read_unlock();
2475 return; 2467 return;
2476 } 2468 }
2477 resp->data[counter_offset_presp] = 2469 resp->data[counter_offset_presp] = count;
2478 sdata->csa_current_counter - 1;
2479 rcu_read_unlock(); 2470 rcu_read_unlock();
2480 } 2471 }
2481 } 2472 }
2473}
2474
2475u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif)
2476{
2477 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
2482 2478
2483 sdata->csa_current_counter--; 2479 sdata->csa_current_counter--;
2480
2481 /* the counter should never reach 0 */
2482 WARN_ON(!sdata->csa_current_counter);
2483
2484 return sdata->csa_current_counter;
2484} 2485}
2486EXPORT_SYMBOL(ieee80211_csa_update_counter);
2485 2487
2486bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) 2488bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
2487{ 2489{
@@ -2552,6 +2554,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
2552 enum ieee80211_band band; 2554 enum ieee80211_band band;
2553 struct ieee80211_tx_rate_control txrc; 2555 struct ieee80211_tx_rate_control txrc;
2554 struct ieee80211_chanctx_conf *chanctx_conf; 2556 struct ieee80211_chanctx_conf *chanctx_conf;
2557 int csa_off_base = 0;
2555 2558
2556 rcu_read_lock(); 2559 rcu_read_lock();
2557 2560
@@ -2569,8 +2572,12 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
2569 struct beacon_data *beacon = rcu_dereference(ap->beacon); 2572 struct beacon_data *beacon = rcu_dereference(ap->beacon);
2570 2573
2571 if (beacon) { 2574 if (beacon) {
2572 if (sdata->vif.csa_active) 2575 if (sdata->vif.csa_active) {
2573 ieee80211_update_csa(sdata, beacon); 2576 if (!is_template)
2577 ieee80211_csa_update_counter(vif);
2578
2579 ieee80211_set_csa(sdata, beacon);
2580 }
2574 2581
2575 /* 2582 /*
2576 * headroom, head length, 2583 * headroom, head length,
@@ -2593,6 +2600,9 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
2593 if (offs) { 2600 if (offs) {
2594 offs->tim_offset = beacon->head_len; 2601 offs->tim_offset = beacon->head_len;
2595 offs->tim_length = skb->len - beacon->head_len; 2602 offs->tim_length = skb->len - beacon->head_len;
2603
2604 /* for AP the csa offsets are from tail */
2605 csa_off_base = skb->len;
2596 } 2606 }
2597 2607
2598 if (beacon->tail) 2608 if (beacon->tail)
@@ -2608,9 +2618,12 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
2608 if (!presp) 2618 if (!presp)
2609 goto out; 2619 goto out;
2610 2620
2611 if (sdata->vif.csa_active) 2621 if (sdata->vif.csa_active) {
2612 ieee80211_update_csa(sdata, presp); 2622 if (!is_template)
2623 ieee80211_csa_update_counter(vif);
2613 2624
2625 ieee80211_set_csa(sdata, presp);
2626 }
2614 2627
2615 skb = dev_alloc_skb(local->tx_headroom + presp->head_len + 2628 skb = dev_alloc_skb(local->tx_headroom + presp->head_len +
2616 local->hw.extra_beacon_tailroom); 2629 local->hw.extra_beacon_tailroom);
@@ -2630,8 +2643,17 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
2630 if (!bcn) 2643 if (!bcn)
2631 goto out; 2644 goto out;
2632 2645
2633 if (sdata->vif.csa_active) 2646 if (sdata->vif.csa_active) {
2634 ieee80211_update_csa(sdata, bcn); 2647 if (!is_template)
2648 /* TODO: For mesh csa_counter is in TU, so
2649 * decrementing it by one isn't correct, but
2650 * for now we leave it consistent with overall
2651 * mac80211's behavior.
2652 */
2653 ieee80211_csa_update_counter(vif);
2654
2655 ieee80211_set_csa(sdata, bcn);
2656 }
2635 2657
2636 if (ifmsh->sync_ops) 2658 if (ifmsh->sync_ops)
2637 ifmsh->sync_ops->adjust_tbtt(sdata, bcn); 2659 ifmsh->sync_ops->adjust_tbtt(sdata, bcn);
@@ -2658,6 +2680,20 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
2658 goto out; 2680 goto out;
2659 } 2681 }
2660 2682
2683 /* CSA offsets */
2684 if (offs) {
2685 int i;
2686
2687 for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; i++) {
2688 u16 csa_off = sdata->csa_counter_offset_beacon[i];
2689
2690 if (!csa_off)
2691 continue;
2692
2693 offs->csa_counter_offs[i] = csa_off_base + csa_off;
2694 }
2695 }
2696
2661 band = chanctx_conf->def.chan->band; 2697 band = chanctx_conf->def.chan->band;
2662 2698
2663 info = IEEE80211_SKB_CB(skb); 2699 info = IEEE80211_SKB_CB(skb);