aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r--net/mac80211/tx.c189
1 files changed, 138 insertions, 51 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 19d36d4117e0..5214686d9fd1 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2328,7 +2328,8 @@ void ieee80211_tx_pending(unsigned long data)
2328/* functions for drivers to get certain frames */ 2328/* functions for drivers to get certain frames */
2329 2329
2330static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, 2330static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
2331 struct ps_data *ps, struct sk_buff *skb) 2331 struct ps_data *ps, struct sk_buff *skb,
2332 bool is_template)
2332{ 2333{
2333 u8 *pos, *tim; 2334 u8 *pos, *tim;
2334 int aid0 = 0; 2335 int aid0 = 0;
@@ -2341,11 +2342,12 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
2341 * checking byte-for-byte */ 2342 * checking byte-for-byte */
2342 have_bits = !bitmap_empty((unsigned long *)ps->tim, 2343 have_bits = !bitmap_empty((unsigned long *)ps->tim,
2343 IEEE80211_MAX_AID+1); 2344 IEEE80211_MAX_AID+1);
2344 2345 if (!is_template) {
2345 if (ps->dtim_count == 0) 2346 if (ps->dtim_count == 0)
2346 ps->dtim_count = sdata->vif.bss_conf.dtim_period - 1; 2347 ps->dtim_count = sdata->vif.bss_conf.dtim_period - 1;
2347 else 2348 else
2348 ps->dtim_count--; 2349 ps->dtim_count--;
2350 }
2349 2351
2350 tim = pos = (u8 *) skb_put(skb, 6); 2352 tim = pos = (u8 *) skb_put(skb, 6);
2351 *pos++ = WLAN_EID_TIM; 2353 *pos++ = WLAN_EID_TIM;
@@ -2391,7 +2393,8 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
2391} 2393}
2392 2394
2393static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, 2395static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
2394 struct ps_data *ps, struct sk_buff *skb) 2396 struct ps_data *ps, struct sk_buff *skb,
2397 bool is_template)
2395{ 2398{
2396 struct ieee80211_local *local = sdata->local; 2399 struct ieee80211_local *local = sdata->local;
2397 2400
@@ -2403,24 +2406,24 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
2403 * of the tim bitmap in mac80211 and the driver. 2406 * of the tim bitmap in mac80211 and the driver.
2404 */ 2407 */
2405 if (local->tim_in_locked_section) { 2408 if (local->tim_in_locked_section) {
2406 __ieee80211_beacon_add_tim(sdata, ps, skb); 2409 __ieee80211_beacon_add_tim(sdata, ps, skb, is_template);
2407 } else { 2410 } else {
2408 spin_lock_bh(&local->tim_lock); 2411 spin_lock_bh(&local->tim_lock);
2409 __ieee80211_beacon_add_tim(sdata, ps, skb); 2412 __ieee80211_beacon_add_tim(sdata, ps, skb, is_template);
2410 spin_unlock_bh(&local->tim_lock); 2413 spin_unlock_bh(&local->tim_lock);
2411 } 2414 }
2412 2415
2413 return 0; 2416 return 0;
2414} 2417}
2415 2418
2416static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata, 2419static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata,
2417 struct beacon_data *beacon) 2420 struct beacon_data *beacon)
2418{ 2421{
2419 struct probe_resp *resp; 2422 struct probe_resp *resp;
2420 int counter_offset_beacon = sdata->csa_counter_offset_beacon;
2421 int counter_offset_presp = sdata->csa_counter_offset_presp;
2422 u8 *beacon_data; 2423 u8 *beacon_data;
2423 size_t beacon_data_len; 2424 size_t beacon_data_len;
2425 int i;
2426 u8 count = sdata->csa_current_counter;
2424 2427
2425 switch (sdata->vif.type) { 2428 switch (sdata->vif.type) {
2426 case NL80211_IFTYPE_AP: 2429 case NL80211_IFTYPE_AP:
@@ -2438,40 +2441,57 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
2438 default: 2441 default:
2439 return; 2442 return;
2440 } 2443 }
2441 if (WARN_ON(counter_offset_beacon >= beacon_data_len))
2442 return;
2443 2444
2444 /* Warn if the driver did not check for/react to csa 2445 for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) {
2445 * completeness. A beacon with CSA counter set to 0 should 2446 u16 counter_offset_beacon =
2446 * never occur, because a counter of 1 means switch just 2447 sdata->csa_counter_offset_beacon[i];
2447 * before the next beacon. 2448 u16 counter_offset_presp = sdata->csa_counter_offset_presp[i];
2448 */
2449 if (WARN_ON(beacon_data[counter_offset_beacon] == 1))
2450 return;
2451 2449
2452 beacon_data[counter_offset_beacon]--; 2450 if (counter_offset_beacon) {
2451 if (WARN_ON(counter_offset_beacon >= beacon_data_len))
2452 return;
2453 2453
2454 if (sdata->vif.type == NL80211_IFTYPE_AP && counter_offset_presp) { 2454 beacon_data[counter_offset_beacon] = count;
2455 rcu_read_lock(); 2455 }
2456 resp = rcu_dereference(sdata->u.ap.probe_resp); 2456
2457 if (sdata->vif.type == NL80211_IFTYPE_AP &&
2458 counter_offset_presp) {
2459 rcu_read_lock();
2460 resp = rcu_dereference(sdata->u.ap.probe_resp);
2457 2461
2458 /* if nl80211 accepted the offset, this should not happen. */ 2462 /* If nl80211 accepted the offset, this should
2459 if (WARN_ON(!resp)) { 2463 * not happen.
2464 */
2465 if (WARN_ON(!resp)) {
2466 rcu_read_unlock();
2467 return;
2468 }
2469 resp->data[counter_offset_presp] = count;
2460 rcu_read_unlock(); 2470 rcu_read_unlock();
2461 return;
2462 } 2471 }
2463 resp->data[counter_offset_presp]--;
2464 rcu_read_unlock();
2465 } 2472 }
2466} 2473}
2467 2474
2475u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif)
2476{
2477 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
2478
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;
2485}
2486EXPORT_SYMBOL(ieee80211_csa_update_counter);
2487
2468bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) 2488bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
2469{ 2489{
2470 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 2490 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
2471 struct beacon_data *beacon = NULL; 2491 struct beacon_data *beacon = NULL;
2472 u8 *beacon_data; 2492 u8 *beacon_data;
2473 size_t beacon_data_len; 2493 size_t beacon_data_len;
2474 int counter_beacon = sdata->csa_counter_offset_beacon; 2494 int counter_beacon = sdata->csa_counter_offset_beacon[0];
2475 int ret = false; 2495 int ret = false;
2476 2496
2477 if (!ieee80211_sdata_running(sdata)) 2497 if (!ieee80211_sdata_running(sdata))
@@ -2521,9 +2541,11 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
2521} 2541}
2522EXPORT_SYMBOL(ieee80211_csa_is_complete); 2542EXPORT_SYMBOL(ieee80211_csa_is_complete);
2523 2543
2524struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, 2544static struct sk_buff *
2525 struct ieee80211_vif *vif, 2545__ieee80211_beacon_get(struct ieee80211_hw *hw,
2526 u16 *tim_offset, u16 *tim_length) 2546 struct ieee80211_vif *vif,
2547 struct ieee80211_mutable_offsets *offs,
2548 bool is_template)
2527{ 2549{
2528 struct ieee80211_local *local = hw_to_local(hw); 2550 struct ieee80211_local *local = hw_to_local(hw);
2529 struct sk_buff *skb = NULL; 2551 struct sk_buff *skb = NULL;
@@ -2532,6 +2554,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2532 enum ieee80211_band band; 2554 enum ieee80211_band band;
2533 struct ieee80211_tx_rate_control txrc; 2555 struct ieee80211_tx_rate_control txrc;
2534 struct ieee80211_chanctx_conf *chanctx_conf; 2556 struct ieee80211_chanctx_conf *chanctx_conf;
2557 int csa_off_base = 0;
2535 2558
2536 rcu_read_lock(); 2559 rcu_read_lock();
2537 2560
@@ -2541,18 +2564,20 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2541 if (!ieee80211_sdata_running(sdata) || !chanctx_conf) 2564 if (!ieee80211_sdata_running(sdata) || !chanctx_conf)
2542 goto out; 2565 goto out;
2543 2566
2544 if (tim_offset) 2567 if (offs)
2545 *tim_offset = 0; 2568 memset(offs, 0, sizeof(*offs));
2546 if (tim_length)
2547 *tim_length = 0;
2548 2569
2549 if (sdata->vif.type == NL80211_IFTYPE_AP) { 2570 if (sdata->vif.type == NL80211_IFTYPE_AP) {
2550 struct ieee80211_if_ap *ap = &sdata->u.ap; 2571 struct ieee80211_if_ap *ap = &sdata->u.ap;
2551 struct beacon_data *beacon = rcu_dereference(ap->beacon); 2572 struct beacon_data *beacon = rcu_dereference(ap->beacon);
2552 2573
2553 if (beacon) { 2574 if (beacon) {
2554 if (sdata->vif.csa_active) 2575 if (sdata->vif.csa_active) {
2555 ieee80211_update_csa(sdata, beacon); 2576 if (!is_template)
2577 ieee80211_csa_update_counter(vif);
2578
2579 ieee80211_set_csa(sdata, beacon);
2580 }
2556 2581
2557 /* 2582 /*
2558 * headroom, head length, 2583 * headroom, head length,
@@ -2569,12 +2594,16 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2569 memcpy(skb_put(skb, beacon->head_len), beacon->head, 2594 memcpy(skb_put(skb, beacon->head_len), beacon->head,
2570 beacon->head_len); 2595 beacon->head_len);
2571 2596
2572 ieee80211_beacon_add_tim(sdata, &ap->ps, skb); 2597 ieee80211_beacon_add_tim(sdata, &ap->ps, skb,
2598 is_template);
2573 2599
2574 if (tim_offset) 2600 if (offs) {
2575 *tim_offset = beacon->head_len; 2601 offs->tim_offset = beacon->head_len;
2576 if (tim_length) 2602 offs->tim_length = skb->len - beacon->head_len;
2577 *tim_length = skb->len - beacon->head_len; 2603
2604 /* for AP the csa offsets are from tail */
2605 csa_off_base = skb->len;
2606 }
2578 2607
2579 if (beacon->tail) 2608 if (beacon->tail)
2580 memcpy(skb_put(skb, beacon->tail_len), 2609 memcpy(skb_put(skb, beacon->tail_len),
@@ -2589,9 +2618,12 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2589 if (!presp) 2618 if (!presp)
2590 goto out; 2619 goto out;
2591 2620
2592 if (sdata->vif.csa_active) 2621 if (sdata->vif.csa_active) {
2593 ieee80211_update_csa(sdata, presp); 2622 if (!is_template)
2623 ieee80211_csa_update_counter(vif);
2594 2624
2625 ieee80211_set_csa(sdata, presp);
2626 }
2595 2627
2596 skb = dev_alloc_skb(local->tx_headroom + presp->head_len + 2628 skb = dev_alloc_skb(local->tx_headroom + presp->head_len +
2597 local->hw.extra_beacon_tailroom); 2629 local->hw.extra_beacon_tailroom);
@@ -2611,8 +2643,17 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2611 if (!bcn) 2643 if (!bcn)
2612 goto out; 2644 goto out;
2613 2645
2614 if (sdata->vif.csa_active) 2646 if (sdata->vif.csa_active) {
2615 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 }
2616 2657
2617 if (ifmsh->sync_ops) 2658 if (ifmsh->sync_ops)
2618 ifmsh->sync_ops->adjust_tbtt(sdata, bcn); 2659 ifmsh->sync_ops->adjust_tbtt(sdata, bcn);
@@ -2626,13 +2667,33 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2626 goto out; 2667 goto out;
2627 skb_reserve(skb, local->tx_headroom); 2668 skb_reserve(skb, local->tx_headroom);
2628 memcpy(skb_put(skb, bcn->head_len), bcn->head, bcn->head_len); 2669 memcpy(skb_put(skb, bcn->head_len), bcn->head, bcn->head_len);
2629 ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb); 2670 ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template);
2671
2672 if (offs) {
2673 offs->tim_offset = bcn->head_len;
2674 offs->tim_length = skb->len - bcn->head_len;
2675 }
2676
2630 memcpy(skb_put(skb, bcn->tail_len), bcn->tail, bcn->tail_len); 2677 memcpy(skb_put(skb, bcn->tail_len), bcn->tail, bcn->tail_len);
2631 } else { 2678 } else {
2632 WARN_ON(1); 2679 WARN_ON(1);
2633 goto out; 2680 goto out;
2634 } 2681 }
2635 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
2636 band = chanctx_conf->def.chan->band; 2697 band = chanctx_conf->def.chan->band;
2637 2698
2638 info = IEEE80211_SKB_CB(skb); 2699 info = IEEE80211_SKB_CB(skb);
@@ -2663,6 +2724,32 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2663 out: 2724 out:
2664 rcu_read_unlock(); 2725 rcu_read_unlock();
2665 return skb; 2726 return skb;
2727
2728}
2729
2730struct sk_buff *
2731ieee80211_beacon_get_template(struct ieee80211_hw *hw,
2732 struct ieee80211_vif *vif,
2733 struct ieee80211_mutable_offsets *offs)
2734{
2735 return __ieee80211_beacon_get(hw, vif, offs, true);
2736}
2737EXPORT_SYMBOL(ieee80211_beacon_get_template);
2738
2739struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2740 struct ieee80211_vif *vif,
2741 u16 *tim_offset, u16 *tim_length)
2742{
2743 struct ieee80211_mutable_offsets offs = {};
2744 struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false);
2745
2746 if (tim_offset)
2747 *tim_offset = offs.tim_offset;
2748
2749 if (tim_length)
2750 *tim_length = offs.tim_length;
2751
2752 return bcn;
2666} 2753}
2667EXPORT_SYMBOL(ieee80211_beacon_get_tim); 2754EXPORT_SYMBOL(ieee80211_beacon_get_tim);
2668 2755