diff options
author | Felix Fietkau <nbd@openwrt.org> | 2013-12-16 15:49:14 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-12-19 07:37:46 -0500 |
commit | a7022e65c68ad89d6eb64f21aa4831c3822403d4 (patch) | |
tree | 7f00a23cf59d36eac93e99435d78adf486a0d242 /net/mac80211/util.c | |
parent | 34a3740d6b392896b71e36cd5cd68837a8f94a5c (diff) |
mac80211: add helper functions for tracking P2P NoA state
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ed93504d24b8..df00f1978a77 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -2594,3 +2594,143 @@ int ieee80211_cs_headroom(struct ieee80211_local *local, | |||
2594 | 2594 | ||
2595 | return headroom; | 2595 | return headroom; |
2596 | } | 2596 | } |
2597 | |||
2598 | static bool | ||
2599 | ieee80211_extend_noa_desc(struct ieee80211_noa_data *data, u32 tsf, int i) | ||
2600 | { | ||
2601 | s32 end = data->desc[i].start + data->desc[i].duration - (tsf + 1); | ||
2602 | int skip; | ||
2603 | |||
2604 | if (end > 0) | ||
2605 | return false; | ||
2606 | |||
2607 | /* End time is in the past, check for repetitions */ | ||
2608 | skip = DIV_ROUND_UP(-end, data->desc[i].interval); | ||
2609 | if (data->count[i] < 255) { | ||
2610 | if (data->count[i] <= skip) { | ||
2611 | data->count[i] = 0; | ||
2612 | return false; | ||
2613 | } | ||
2614 | |||
2615 | data->count[i] -= skip; | ||
2616 | } | ||
2617 | |||
2618 | data->desc[i].start += skip * data->desc[i].interval; | ||
2619 | |||
2620 | return true; | ||
2621 | } | ||
2622 | |||
2623 | static bool | ||
2624 | ieee80211_extend_absent_time(struct ieee80211_noa_data *data, u32 tsf, | ||
2625 | s32 *offset) | ||
2626 | { | ||
2627 | bool ret = false; | ||
2628 | int i; | ||
2629 | |||
2630 | for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) { | ||
2631 | s32 cur; | ||
2632 | |||
2633 | if (!data->count[i]) | ||
2634 | continue; | ||
2635 | |||
2636 | if (ieee80211_extend_noa_desc(data, tsf + *offset, i)) | ||
2637 | ret = true; | ||
2638 | |||
2639 | cur = data->desc[i].start - tsf; | ||
2640 | if (cur > *offset) | ||
2641 | continue; | ||
2642 | |||
2643 | cur = data->desc[i].start + data->desc[i].duration - tsf; | ||
2644 | if (cur > *offset) | ||
2645 | *offset = cur; | ||
2646 | } | ||
2647 | |||
2648 | return ret; | ||
2649 | } | ||
2650 | |||
2651 | static u32 | ||
2652 | ieee80211_get_noa_absent_time(struct ieee80211_noa_data *data, u32 tsf) | ||
2653 | { | ||
2654 | s32 offset = 0; | ||
2655 | int tries = 0; | ||
2656 | /* | ||
2657 | * arbitrary limit, used to avoid infinite loops when combined NoA | ||
2658 | * descriptors cover the full time period. | ||
2659 | */ | ||
2660 | int max_tries = 5; | ||
2661 | |||
2662 | ieee80211_extend_absent_time(data, tsf, &offset); | ||
2663 | do { | ||
2664 | if (!ieee80211_extend_absent_time(data, tsf, &offset)) | ||
2665 | break; | ||
2666 | |||
2667 | tries++; | ||
2668 | } while (tries < max_tries); | ||
2669 | |||
2670 | return offset; | ||
2671 | } | ||
2672 | |||
2673 | void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf) | ||
2674 | { | ||
2675 | u32 next_offset = BIT(31) - 1; | ||
2676 | int i; | ||
2677 | |||
2678 | data->absent = 0; | ||
2679 | data->has_next_tsf = false; | ||
2680 | for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) { | ||
2681 | s32 start; | ||
2682 | |||
2683 | if (!data->count[i]) | ||
2684 | continue; | ||
2685 | |||
2686 | ieee80211_extend_noa_desc(data, tsf, i); | ||
2687 | start = data->desc[i].start - tsf; | ||
2688 | if (start <= 0) | ||
2689 | data->absent |= BIT(i); | ||
2690 | |||
2691 | if (next_offset > start) | ||
2692 | next_offset = start; | ||
2693 | |||
2694 | data->has_next_tsf = true; | ||
2695 | } | ||
2696 | |||
2697 | if (data->absent) | ||
2698 | next_offset = ieee80211_get_noa_absent_time(data, tsf); | ||
2699 | |||
2700 | data->next_tsf = tsf + next_offset; | ||
2701 | } | ||
2702 | EXPORT_SYMBOL(ieee80211_update_p2p_noa); | ||
2703 | |||
2704 | int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr, | ||
2705 | struct ieee80211_noa_data *data, u32 tsf) | ||
2706 | { | ||
2707 | int ret = 0; | ||
2708 | int i; | ||
2709 | |||
2710 | memset(data, 0, sizeof(*data)); | ||
2711 | |||
2712 | for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) { | ||
2713 | const struct ieee80211_p2p_noa_desc *desc = &attr->desc[i]; | ||
2714 | |||
2715 | if (!desc->count || !desc->duration) | ||
2716 | continue; | ||
2717 | |||
2718 | data->count[i] = desc->count; | ||
2719 | data->desc[i].start = le32_to_cpu(desc->start_time); | ||
2720 | data->desc[i].duration = le32_to_cpu(desc->duration); | ||
2721 | data->desc[i].interval = le32_to_cpu(desc->interval); | ||
2722 | |||
2723 | if (data->count[i] > 1 && | ||
2724 | data->desc[i].interval < data->desc[i].duration) | ||
2725 | continue; | ||
2726 | |||
2727 | ieee80211_extend_noa_desc(data, tsf, i); | ||
2728 | ret++; | ||
2729 | } | ||
2730 | |||
2731 | if (ret) | ||
2732 | ieee80211_update_p2p_noa(data, tsf); | ||
2733 | |||
2734 | return ret; | ||
2735 | } | ||
2736 | EXPORT_SYMBOL(ieee80211_parse_p2p_noa); | ||