aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r--net/mac80211/util.c320
1 files changed, 315 insertions, 5 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 9f9b9bd3fd44..676dc0967f37 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -76,7 +76,7 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
76 } 76 }
77 77
78 if (ieee80211_is_ctl(fc)) { 78 if (ieee80211_is_ctl(fc)) {
79 if(ieee80211_is_pspoll(fc)) 79 if (ieee80211_is_pspoll(fc))
80 return hdr->addr1; 80 return hdr->addr1;
81 81
82 if (ieee80211_is_back_req(fc)) { 82 if (ieee80211_is_back_req(fc)) {
@@ -642,6 +642,17 @@ void ieee80211_iterate_active_interfaces_rtnl(
642} 642}
643EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); 643EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
644 644
645struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev)
646{
647 struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
648
649 if (!ieee80211_sdata_running(sdata) ||
650 !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
651 return NULL;
652 return &sdata->vif;
653}
654EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif);
655
645/* 656/*
646 * Nothing should have been stuffed into the workqueue during 657 * Nothing should have been stuffed into the workqueue during
647 * the suspend->resume cycle. If this WARN is seen then there 658 * the suspend->resume cycle. If this WARN is seen then there
@@ -1451,6 +1462,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1451 struct sta_info *sta; 1462 struct sta_info *sta;
1452 int res, i; 1463 int res, i;
1453 bool reconfig_due_to_wowlan = false; 1464 bool reconfig_due_to_wowlan = false;
1465 struct ieee80211_sub_if_data *sched_scan_sdata;
1466 bool sched_scan_stopped = false;
1454 1467
1455#ifdef CONFIG_PM 1468#ifdef CONFIG_PM
1456 if (local->suspended) 1469 if (local->suspended)
@@ -1754,6 +1767,27 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1754#else 1767#else
1755 WARN_ON(1); 1768 WARN_ON(1);
1756#endif 1769#endif
1770
1771 /*
1772 * Reconfigure sched scan if it was interrupted by FW restart or
1773 * suspend.
1774 */
1775 mutex_lock(&local->mtx);
1776 sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
1777 lockdep_is_held(&local->mtx));
1778 if (sched_scan_sdata && local->sched_scan_req)
1779 /*
1780 * Sched scan stopped, but we don't want to report it. Instead,
1781 * we're trying to reschedule.
1782 */
1783 if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
1784 local->sched_scan_req))
1785 sched_scan_stopped = true;
1786 mutex_unlock(&local->mtx);
1787
1788 if (sched_scan_stopped)
1789 cfg80211_sched_scan_stopped(local->hw.wiphy);
1790
1757 return 0; 1791 return 0;
1758} 1792}
1759 1793
@@ -1804,6 +1838,26 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata)
1804 mutex_unlock(&local->chanctx_mtx); 1838 mutex_unlock(&local->chanctx_mtx);
1805} 1839}
1806 1840
1841void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata)
1842{
1843 struct ieee80211_local *local = sdata->local;
1844 struct ieee80211_chanctx_conf *chanctx_conf;
1845 struct ieee80211_chanctx *chanctx;
1846
1847 mutex_lock(&local->chanctx_mtx);
1848
1849 chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
1850 lockdep_is_held(&local->chanctx_mtx));
1851
1852 if (WARN_ON_ONCE(!chanctx_conf))
1853 goto unlock;
1854
1855 chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
1856 ieee80211_recalc_chanctx_min_def(local, chanctx);
1857 unlock:
1858 mutex_unlock(&local->chanctx_mtx);
1859}
1860
1807static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) 1861static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
1808{ 1862{
1809 int i; 1863 int i;
@@ -2259,19 +2313,28 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
2259void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) 2313void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
2260{ 2314{
2261 struct ieee80211_sub_if_data *sdata; 2315 struct ieee80211_sub_if_data *sdata;
2316 struct cfg80211_chan_def chandef;
2262 2317
2318 mutex_lock(&local->mtx);
2263 mutex_lock(&local->iflist_mtx); 2319 mutex_lock(&local->iflist_mtx);
2264 list_for_each_entry(sdata, &local->interfaces, list) { 2320 list_for_each_entry(sdata, &local->interfaces, list) {
2265 cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); 2321 /* it might be waiting for the local->mtx, but then
2322 * by the time it gets it, sdata->wdev.cac_started
2323 * will no longer be true
2324 */
2325 cancel_delayed_work(&sdata->dfs_cac_timer_work);
2266 2326
2267 if (sdata->wdev.cac_started) { 2327 if (sdata->wdev.cac_started) {
2328 chandef = sdata->vif.bss_conf.chandef;
2268 ieee80211_vif_release_channel(sdata); 2329 ieee80211_vif_release_channel(sdata);
2269 cfg80211_cac_event(sdata->dev, 2330 cfg80211_cac_event(sdata->dev,
2331 &chandef,
2270 NL80211_RADAR_CAC_ABORTED, 2332 NL80211_RADAR_CAC_ABORTED,
2271 GFP_KERNEL); 2333 GFP_KERNEL);
2272 } 2334 }
2273 } 2335 }
2274 mutex_unlock(&local->iflist_mtx); 2336 mutex_unlock(&local->iflist_mtx);
2337 mutex_unlock(&local->mtx);
2275} 2338}
2276 2339
2277void ieee80211_dfs_radar_detected_work(struct work_struct *work) 2340void ieee80211_dfs_radar_detected_work(struct work_struct *work)
@@ -2445,7 +2508,6 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
2445 2508
2446 if (ieee80211_vif_is_mesh(&sdata->vif)) { 2509 if (ieee80211_vif_is_mesh(&sdata->vif)) {
2447 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; 2510 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
2448 __le16 pre_value;
2449 2511
2450 skb_put(skb, 8); 2512 skb_put(skb, 8);
2451 *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; /* EID */ 2513 *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; /* EID */
@@ -2457,11 +2519,259 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
2457 WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00; 2519 WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
2458 put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */ 2520 put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */
2459 pos += 2; 2521 pos += 2;
2460 pre_value = cpu_to_le16(ifmsh->pre_value); 2522 put_unaligned_le16(ifmsh->pre_value, pos);/* Precedence Value */
2461 memcpy(pos, &pre_value, 2); /* Precedence Value */
2462 pos += 2; 2523 pos += 2;
2463 } 2524 }
2464 2525
2465 ieee80211_tx_skb(sdata, skb); 2526 ieee80211_tx_skb(sdata, skb);
2466 return 0; 2527 return 0;
2467} 2528}
2529
2530bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs)
2531{
2532 return !(cs == NULL || cs->cipher == 0 ||
2533 cs->hdr_len < cs->pn_len + cs->pn_off ||
2534 cs->hdr_len <= cs->key_idx_off ||
2535 cs->key_idx_shift > 7 ||
2536 cs->key_idx_mask == 0);
2537}
2538
2539bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n)
2540{
2541 int i;
2542
2543 /* Ensure we have enough iftype bitmap space for all iftype values */
2544 WARN_ON((NUM_NL80211_IFTYPES / 8 + 1) > sizeof(cs[0].iftype));
2545
2546 for (i = 0; i < n; i++)
2547 if (!ieee80211_cs_valid(&cs[i]))
2548 return false;
2549
2550 return true;
2551}
2552
2553const struct ieee80211_cipher_scheme *
2554ieee80211_cs_get(struct ieee80211_local *local, u32 cipher,
2555 enum nl80211_iftype iftype)
2556{
2557 const struct ieee80211_cipher_scheme *l = local->hw.cipher_schemes;
2558 int n = local->hw.n_cipher_schemes;
2559 int i;
2560 const struct ieee80211_cipher_scheme *cs = NULL;
2561
2562 for (i = 0; i < n; i++) {
2563 if (l[i].cipher == cipher) {
2564 cs = &l[i];
2565 break;
2566 }
2567 }
2568
2569 if (!cs || !(cs->iftype & BIT(iftype)))
2570 return NULL;
2571
2572 return cs;
2573}
2574
2575int ieee80211_cs_headroom(struct ieee80211_local *local,
2576 struct cfg80211_crypto_settings *crypto,
2577 enum nl80211_iftype iftype)
2578{
2579 const struct ieee80211_cipher_scheme *cs;
2580 int headroom = IEEE80211_ENCRYPT_HEADROOM;
2581 int i;
2582
2583 for (i = 0; i < crypto->n_ciphers_pairwise; i++) {
2584 cs = ieee80211_cs_get(local, crypto->ciphers_pairwise[i],
2585 iftype);
2586
2587 if (cs && headroom < cs->hdr_len)
2588 headroom = cs->hdr_len;
2589 }
2590
2591 cs = ieee80211_cs_get(local, crypto->cipher_group, iftype);
2592 if (cs && headroom < cs->hdr_len)
2593 headroom = cs->hdr_len;
2594
2595 return headroom;
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);
2737
2738void ieee80211_recalc_dtim(struct ieee80211_local *local,
2739 struct ieee80211_sub_if_data *sdata)
2740{
2741 u64 tsf = drv_get_tsf(local, sdata);
2742 u64 dtim_count = 0;
2743 u16 beacon_int = sdata->vif.bss_conf.beacon_int * 1024;
2744 u8 dtim_period = sdata->vif.bss_conf.dtim_period;
2745 struct ps_data *ps;
2746 u8 bcns_from_dtim;
2747
2748 if (tsf == -1ULL || !beacon_int || !dtim_period)
2749 return;
2750
2751 if (sdata->vif.type == NL80211_IFTYPE_AP ||
2752 sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
2753 if (!sdata->bss)
2754 return;
2755
2756 ps = &sdata->bss->ps;
2757 } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
2758 ps = &sdata->u.mesh.ps;
2759 } else {
2760 return;
2761 }
2762
2763 /*
2764 * actually finds last dtim_count, mac80211 will update in
2765 * __beacon_add_tim().
2766 * dtim_count = dtim_period - (tsf / bcn_int) % dtim_period
2767 */
2768 do_div(tsf, beacon_int);
2769 bcns_from_dtim = do_div(tsf, dtim_period);
2770 /* just had a DTIM */
2771 if (!bcns_from_dtim)
2772 dtim_count = 0;
2773 else
2774 dtim_count = dtim_period - bcns_from_dtim;
2775
2776 ps->dtim_count = dtim_count;
2777}