diff options
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r-- | net/mac80211/tx.c | 189 |
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 | ||
2330 | static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, | 2330 | static 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 | ||
2393 | static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, | 2395 | static 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 | ||
2416 | static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata, | 2419 | static 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 | ||
2475 | u8 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 | } | ||
2486 | EXPORT_SYMBOL(ieee80211_csa_update_counter); | ||
2487 | |||
2468 | bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) | 2488 | bool 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 | } |
2522 | EXPORT_SYMBOL(ieee80211_csa_is_complete); | 2542 | EXPORT_SYMBOL(ieee80211_csa_is_complete); |
2523 | 2543 | ||
2524 | struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | 2544 | static 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 | |||
2730 | struct sk_buff * | ||
2731 | ieee80211_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 | } | ||
2737 | EXPORT_SYMBOL(ieee80211_beacon_get_template); | ||
2738 | |||
2739 | struct 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 | } |
2667 | EXPORT_SYMBOL(ieee80211_beacon_get_tim); | 2754 | EXPORT_SYMBOL(ieee80211_beacon_get_tim); |
2668 | 2755 | ||