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.c328
1 files changed, 317 insertions, 11 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 9f9b9bd3fd44..b8700d417a9c 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)) {
@@ -435,9 +435,8 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
435 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 435 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
436} 436}
437 437
438void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, 438void ieee80211_add_pending_skbs(struct ieee80211_local *local,
439 struct sk_buff_head *skbs, 439 struct sk_buff_head *skbs)
440 void (*fn)(void *data), void *data)
441{ 440{
442 struct ieee80211_hw *hw = &local->hw; 441 struct ieee80211_hw *hw = &local->hw;
443 struct sk_buff *skb; 442 struct sk_buff *skb;
@@ -461,9 +460,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
461 __skb_queue_tail(&local->pending[queue], skb); 460 __skb_queue_tail(&local->pending[queue], skb);
462 } 461 }
463 462
464 if (fn)
465 fn(data);
466
467 for (i = 0; i < hw->queues; i++) 463 for (i = 0; i < hw->queues; i++)
468 __ieee80211_wake_queue(hw, i, 464 __ieee80211_wake_queue(hw, i,
469 IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 465 IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
@@ -642,6 +638,17 @@ void ieee80211_iterate_active_interfaces_rtnl(
642} 638}
643EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); 639EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
644 640
641struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev)
642{
643 struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
644
645 if (!ieee80211_sdata_running(sdata) ||
646 !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
647 return NULL;
648 return &sdata->vif;
649}
650EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif);
651
645/* 652/*
646 * Nothing should have been stuffed into the workqueue during 653 * Nothing should have been stuffed into the workqueue during
647 * the suspend->resume cycle. If this WARN is seen then there 654 * the suspend->resume cycle. If this WARN is seen then there
@@ -1451,6 +1458,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1451 struct sta_info *sta; 1458 struct sta_info *sta;
1452 int res, i; 1459 int res, i;
1453 bool reconfig_due_to_wowlan = false; 1460 bool reconfig_due_to_wowlan = false;
1461 struct ieee80211_sub_if_data *sched_scan_sdata;
1462 bool sched_scan_stopped = false;
1454 1463
1455#ifdef CONFIG_PM 1464#ifdef CONFIG_PM
1456 if (local->suspended) 1465 if (local->suspended)
@@ -1728,6 +1737,26 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1728 IEEE80211_QUEUE_STOP_REASON_SUSPEND); 1737 IEEE80211_QUEUE_STOP_REASON_SUSPEND);
1729 1738
1730 /* 1739 /*
1740 * Reconfigure sched scan if it was interrupted by FW restart or
1741 * suspend.
1742 */
1743 mutex_lock(&local->mtx);
1744 sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
1745 lockdep_is_held(&local->mtx));
1746 if (sched_scan_sdata && local->sched_scan_req)
1747 /*
1748 * Sched scan stopped, but we don't want to report it. Instead,
1749 * we're trying to reschedule.
1750 */
1751 if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
1752 local->sched_scan_req))
1753 sched_scan_stopped = true;
1754 mutex_unlock(&local->mtx);
1755
1756 if (sched_scan_stopped)
1757 cfg80211_sched_scan_stopped(local->hw.wiphy);
1758
1759 /*
1731 * If this is for hw restart things are still running. 1760 * If this is for hw restart things are still running.
1732 * We may want to change that later, however. 1761 * We may want to change that later, however.
1733 */ 1762 */
@@ -1754,6 +1783,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1754#else 1783#else
1755 WARN_ON(1); 1784 WARN_ON(1);
1756#endif 1785#endif
1786
1757 return 0; 1787 return 0;
1758} 1788}
1759 1789
@@ -1804,6 +1834,26 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata)
1804 mutex_unlock(&local->chanctx_mtx); 1834 mutex_unlock(&local->chanctx_mtx);
1805} 1835}
1806 1836
1837void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata)
1838{
1839 struct ieee80211_local *local = sdata->local;
1840 struct ieee80211_chanctx_conf *chanctx_conf;
1841 struct ieee80211_chanctx *chanctx;
1842
1843 mutex_lock(&local->chanctx_mtx);
1844
1845 chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
1846 lockdep_is_held(&local->chanctx_mtx));
1847
1848 if (WARN_ON_ONCE(!chanctx_conf))
1849 goto unlock;
1850
1851 chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
1852 ieee80211_recalc_chanctx_min_def(local, chanctx);
1853 unlock:
1854 mutex_unlock(&local->chanctx_mtx);
1855}
1856
1807static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) 1857static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
1808{ 1858{
1809 int i; 1859 int i;
@@ -2259,19 +2309,28 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
2259void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) 2309void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
2260{ 2310{
2261 struct ieee80211_sub_if_data *sdata; 2311 struct ieee80211_sub_if_data *sdata;
2312 struct cfg80211_chan_def chandef;
2262 2313
2314 mutex_lock(&local->mtx);
2263 mutex_lock(&local->iflist_mtx); 2315 mutex_lock(&local->iflist_mtx);
2264 list_for_each_entry(sdata, &local->interfaces, list) { 2316 list_for_each_entry(sdata, &local->interfaces, list) {
2265 cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); 2317 /* it might be waiting for the local->mtx, but then
2318 * by the time it gets it, sdata->wdev.cac_started
2319 * will no longer be true
2320 */
2321 cancel_delayed_work(&sdata->dfs_cac_timer_work);
2266 2322
2267 if (sdata->wdev.cac_started) { 2323 if (sdata->wdev.cac_started) {
2324 chandef = sdata->vif.bss_conf.chandef;
2268 ieee80211_vif_release_channel(sdata); 2325 ieee80211_vif_release_channel(sdata);
2269 cfg80211_cac_event(sdata->dev, 2326 cfg80211_cac_event(sdata->dev,
2327 &chandef,
2270 NL80211_RADAR_CAC_ABORTED, 2328 NL80211_RADAR_CAC_ABORTED,
2271 GFP_KERNEL); 2329 GFP_KERNEL);
2272 } 2330 }
2273 } 2331 }
2274 mutex_unlock(&local->iflist_mtx); 2332 mutex_unlock(&local->iflist_mtx);
2333 mutex_unlock(&local->mtx);
2275} 2334}
2276 2335
2277void ieee80211_dfs_radar_detected_work(struct work_struct *work) 2336void ieee80211_dfs_radar_detected_work(struct work_struct *work)
@@ -2445,7 +2504,6 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
2445 2504
2446 if (ieee80211_vif_is_mesh(&sdata->vif)) { 2505 if (ieee80211_vif_is_mesh(&sdata->vif)) {
2447 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; 2506 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
2448 __le16 pre_value;
2449 2507
2450 skb_put(skb, 8); 2508 skb_put(skb, 8);
2451 *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; /* EID */ 2509 *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; /* EID */
@@ -2457,11 +2515,259 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
2457 WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00; 2515 WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
2458 put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */ 2516 put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */
2459 pos += 2; 2517 pos += 2;
2460 pre_value = cpu_to_le16(ifmsh->pre_value); 2518 put_unaligned_le16(ifmsh->pre_value, pos);/* Precedence Value */
2461 memcpy(pos, &pre_value, 2); /* Precedence Value */
2462 pos += 2; 2519 pos += 2;
2463 } 2520 }
2464 2521
2465 ieee80211_tx_skb(sdata, skb); 2522 ieee80211_tx_skb(sdata, skb);
2466 return 0; 2523 return 0;
2467} 2524}
2525
2526bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs)
2527{
2528 return !(cs == NULL || cs->cipher == 0 ||
2529 cs->hdr_len < cs->pn_len + cs->pn_off ||
2530 cs->hdr_len <= cs->key_idx_off ||
2531 cs->key_idx_shift > 7 ||
2532 cs->key_idx_mask == 0);
2533}
2534
2535bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n)
2536{
2537 int i;
2538
2539 /* Ensure we have enough iftype bitmap space for all iftype values */
2540 WARN_ON((NUM_NL80211_IFTYPES / 8 + 1) > sizeof(cs[0].iftype));
2541
2542 for (i = 0; i < n; i++)
2543 if (!ieee80211_cs_valid(&cs[i]))
2544 return false;
2545
2546 return true;
2547}
2548
2549const struct ieee80211_cipher_scheme *
2550ieee80211_cs_get(struct ieee80211_local *local, u32 cipher,
2551 enum nl80211_iftype iftype)
2552{
2553 const struct ieee80211_cipher_scheme *l = local->hw.cipher_schemes;
2554 int n = local->hw.n_cipher_schemes;
2555 int i;
2556 const struct ieee80211_cipher_scheme *cs = NULL;
2557
2558 for (i = 0; i < n; i++) {
2559 if (l[i].cipher == cipher) {
2560 cs = &l[i];
2561 break;
2562 }
2563 }
2564
2565 if (!cs || !(cs->iftype & BIT(iftype)))
2566 return NULL;
2567
2568 return cs;
2569}
2570
2571int ieee80211_cs_headroom(struct ieee80211_local *local,
2572 struct cfg80211_crypto_settings *crypto,
2573 enum nl80211_iftype iftype)
2574{
2575 const struct ieee80211_cipher_scheme *cs;
2576 int headroom = IEEE80211_ENCRYPT_HEADROOM;
2577 int i;
2578
2579 for (i = 0; i < crypto->n_ciphers_pairwise; i++) {
2580 cs = ieee80211_cs_get(local, crypto->ciphers_pairwise[i],
2581 iftype);
2582
2583 if (cs && headroom < cs->hdr_len)
2584 headroom = cs->hdr_len;
2585 }
2586
2587 cs = ieee80211_cs_get(local, crypto->cipher_group, iftype);
2588 if (cs && headroom < cs->hdr_len)
2589 headroom = cs->hdr_len;
2590
2591 return headroom;
2592}
2593
2594static bool
2595ieee80211_extend_noa_desc(struct ieee80211_noa_data *data, u32 tsf, int i)
2596{
2597 s32 end = data->desc[i].start + data->desc[i].duration - (tsf + 1);
2598 int skip;
2599
2600 if (end > 0)
2601 return false;
2602
2603 /* End time is in the past, check for repetitions */
2604 skip = DIV_ROUND_UP(-end, data->desc[i].interval);
2605 if (data->count[i] < 255) {
2606 if (data->count[i] <= skip) {
2607 data->count[i] = 0;
2608 return false;
2609 }
2610
2611 data->count[i] -= skip;
2612 }
2613
2614 data->desc[i].start += skip * data->desc[i].interval;
2615
2616 return true;
2617}
2618
2619static bool
2620ieee80211_extend_absent_time(struct ieee80211_noa_data *data, u32 tsf,
2621 s32 *offset)
2622{
2623 bool ret = false;
2624 int i;
2625
2626 for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) {
2627 s32 cur;
2628
2629 if (!data->count[i])
2630 continue;
2631
2632 if (ieee80211_extend_noa_desc(data, tsf + *offset, i))
2633 ret = true;
2634
2635 cur = data->desc[i].start - tsf;
2636 if (cur > *offset)
2637 continue;
2638
2639 cur = data->desc[i].start + data->desc[i].duration - tsf;
2640 if (cur > *offset)
2641 *offset = cur;
2642 }
2643
2644 return ret;
2645}
2646
2647static u32
2648ieee80211_get_noa_absent_time(struct ieee80211_noa_data *data, u32 tsf)
2649{
2650 s32 offset = 0;
2651 int tries = 0;
2652 /*
2653 * arbitrary limit, used to avoid infinite loops when combined NoA
2654 * descriptors cover the full time period.
2655 */
2656 int max_tries = 5;
2657
2658 ieee80211_extend_absent_time(data, tsf, &offset);
2659 do {
2660 if (!ieee80211_extend_absent_time(data, tsf, &offset))
2661 break;
2662
2663 tries++;
2664 } while (tries < max_tries);
2665
2666 return offset;
2667}
2668
2669void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf)
2670{
2671 u32 next_offset = BIT(31) - 1;
2672 int i;
2673
2674 data->absent = 0;
2675 data->has_next_tsf = false;
2676 for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) {
2677 s32 start;
2678
2679 if (!data->count[i])
2680 continue;
2681
2682 ieee80211_extend_noa_desc(data, tsf, i);
2683 start = data->desc[i].start - tsf;
2684 if (start <= 0)
2685 data->absent |= BIT(i);
2686
2687 if (next_offset > start)
2688 next_offset = start;
2689
2690 data->has_next_tsf = true;
2691 }
2692
2693 if (data->absent)
2694 next_offset = ieee80211_get_noa_absent_time(data, tsf);
2695
2696 data->next_tsf = tsf + next_offset;
2697}
2698EXPORT_SYMBOL(ieee80211_update_p2p_noa);
2699
2700int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr,
2701 struct ieee80211_noa_data *data, u32 tsf)
2702{
2703 int ret = 0;
2704 int i;
2705
2706 memset(data, 0, sizeof(*data));
2707
2708 for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) {
2709 const struct ieee80211_p2p_noa_desc *desc = &attr->desc[i];
2710
2711 if (!desc->count || !desc->duration)
2712 continue;
2713
2714 data->count[i] = desc->count;
2715 data->desc[i].start = le32_to_cpu(desc->start_time);
2716 data->desc[i].duration = le32_to_cpu(desc->duration);
2717 data->desc[i].interval = le32_to_cpu(desc->interval);
2718
2719 if (data->count[i] > 1 &&
2720 data->desc[i].interval < data->desc[i].duration)
2721 continue;
2722
2723 ieee80211_extend_noa_desc(data, tsf, i);
2724 ret++;
2725 }
2726
2727 if (ret)
2728 ieee80211_update_p2p_noa(data, tsf);
2729
2730 return ret;
2731}
2732EXPORT_SYMBOL(ieee80211_parse_p2p_noa);
2733
2734void ieee80211_recalc_dtim(struct ieee80211_local *local,
2735 struct ieee80211_sub_if_data *sdata)
2736{
2737 u64 tsf = drv_get_tsf(local, sdata);
2738 u64 dtim_count = 0;
2739 u16 beacon_int = sdata->vif.bss_conf.beacon_int * 1024;
2740 u8 dtim_period = sdata->vif.bss_conf.dtim_period;
2741 struct ps_data *ps;
2742 u8 bcns_from_dtim;
2743
2744 if (tsf == -1ULL || !beacon_int || !dtim_period)
2745 return;
2746
2747 if (sdata->vif.type == NL80211_IFTYPE_AP ||
2748 sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
2749 if (!sdata->bss)
2750 return;
2751
2752 ps = &sdata->bss->ps;
2753 } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
2754 ps = &sdata->u.mesh.ps;
2755 } else {
2756 return;
2757 }
2758
2759 /*
2760 * actually finds last dtim_count, mac80211 will update in
2761 * __beacon_add_tim().
2762 * dtim_count = dtim_period - (tsf / bcn_int) % dtim_period
2763 */
2764 do_div(tsf, beacon_int);
2765 bcns_from_dtim = do_div(tsf, dtim_period);
2766 /* just had a DTIM */
2767 if (!bcns_from_dtim)
2768 dtim_count = 0;
2769 else
2770 dtim_count = dtim_period - bcns_from_dtim;
2771
2772 ps->dtim_count = dtim_count;
2773}