aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/util.c
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2013-12-16 15:49:14 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-12-19 07:37:46 -0500
commita7022e65c68ad89d6eb64f21aa4831c3822403d4 (patch)
tree7f00a23cf59d36eac93e99435d78adf486a0d242 /net/mac80211/util.c
parent34a3740d6b392896b71e36cd5cd68837a8f94a5c (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.c140
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
2598static bool
2599ieee80211_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
2623static bool
2624ieee80211_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
2651static u32
2652ieee80211_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
2673void 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}
2702EXPORT_SYMBOL(ieee80211_update_p2p_noa);
2703
2704int 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}
2736EXPORT_SYMBOL(ieee80211_parse_p2p_noa);