18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Wireless utility functions 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net> 68c2ecf20Sopenharmony_ci * Copyright 2013-2014 Intel Mobile Communications GmbH 78c2ecf20Sopenharmony_ci * Copyright 2017 Intel Deutschland GmbH 88c2ecf20Sopenharmony_ci * Copyright (C) 2018-2020 Intel Corporation 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/export.h> 118c2ecf20Sopenharmony_ci#include <linux/bitops.h> 128c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/ieee80211.h> 158c2ecf20Sopenharmony_ci#include <net/cfg80211.h> 168c2ecf20Sopenharmony_ci#include <net/ip.h> 178c2ecf20Sopenharmony_ci#include <net/dsfield.h> 188c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 198c2ecf20Sopenharmony_ci#include <linux/mpls.h> 208c2ecf20Sopenharmony_ci#include <linux/gcd.h> 218c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 228c2ecf20Sopenharmony_ci#include <linux/nospec.h> 238c2ecf20Sopenharmony_ci#include "core.h" 248c2ecf20Sopenharmony_ci#include "rdev-ops.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct ieee80211_rate * 288c2ecf20Sopenharmony_ciieee80211_get_response_rate(struct ieee80211_supported_band *sband, 298c2ecf20Sopenharmony_ci u32 basic_rates, int bitrate) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci struct ieee80211_rate *result = &sband->bitrates[0]; 328c2ecf20Sopenharmony_ci int i; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci for (i = 0; i < sband->n_bitrates; i++) { 358c2ecf20Sopenharmony_ci if (!(basic_rates & BIT(i))) 368c2ecf20Sopenharmony_ci continue; 378c2ecf20Sopenharmony_ci if (sband->bitrates[i].bitrate > bitrate) 388c2ecf20Sopenharmony_ci continue; 398c2ecf20Sopenharmony_ci result = &sband->bitrates[i]; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci return result; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_get_response_rate); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ciu32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband, 478c2ecf20Sopenharmony_ci enum nl80211_bss_scan_width scan_width) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct ieee80211_rate *bitrates; 508c2ecf20Sopenharmony_ci u32 mandatory_rates = 0; 518c2ecf20Sopenharmony_ci enum ieee80211_rate_flags mandatory_flag; 528c2ecf20Sopenharmony_ci int i; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (WARN_ON(!sband)) 558c2ecf20Sopenharmony_ci return 1; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (sband->band == NL80211_BAND_2GHZ) { 588c2ecf20Sopenharmony_ci if (scan_width == NL80211_BSS_CHAN_WIDTH_5 || 598c2ecf20Sopenharmony_ci scan_width == NL80211_BSS_CHAN_WIDTH_10) 608c2ecf20Sopenharmony_ci mandatory_flag = IEEE80211_RATE_MANDATORY_G; 618c2ecf20Sopenharmony_ci else 628c2ecf20Sopenharmony_ci mandatory_flag = IEEE80211_RATE_MANDATORY_B; 638c2ecf20Sopenharmony_ci } else { 648c2ecf20Sopenharmony_ci mandatory_flag = IEEE80211_RATE_MANDATORY_A; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci bitrates = sband->bitrates; 688c2ecf20Sopenharmony_ci for (i = 0; i < sband->n_bitrates; i++) 698c2ecf20Sopenharmony_ci if (bitrates[i].flags & mandatory_flag) 708c2ecf20Sopenharmony_ci mandatory_rates |= BIT(i); 718c2ecf20Sopenharmony_ci return mandatory_rates; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_mandatory_rates); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ciu32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci /* see 802.11 17.3.8.3.2 and Annex J 788c2ecf20Sopenharmony_ci * there are overlapping channel numbers in 5GHz and 2GHz bands */ 798c2ecf20Sopenharmony_ci if (chan <= 0) 808c2ecf20Sopenharmony_ci return 0; /* not supported */ 818c2ecf20Sopenharmony_ci switch (band) { 828c2ecf20Sopenharmony_ci case NL80211_BAND_2GHZ: 838c2ecf20Sopenharmony_ci if (chan == 14) 848c2ecf20Sopenharmony_ci return MHZ_TO_KHZ(2484); 858c2ecf20Sopenharmony_ci else if (chan < 14) 868c2ecf20Sopenharmony_ci return MHZ_TO_KHZ(2407 + chan * 5); 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci case NL80211_BAND_5GHZ: 898c2ecf20Sopenharmony_ci if (chan >= 182 && chan <= 196) 908c2ecf20Sopenharmony_ci return MHZ_TO_KHZ(4000 + chan * 5); 918c2ecf20Sopenharmony_ci else 928c2ecf20Sopenharmony_ci return MHZ_TO_KHZ(5000 + chan * 5); 938c2ecf20Sopenharmony_ci break; 948c2ecf20Sopenharmony_ci case NL80211_BAND_6GHZ: 958c2ecf20Sopenharmony_ci /* see 802.11ax D6.1 27.3.23.2 */ 968c2ecf20Sopenharmony_ci if (chan == 2) 978c2ecf20Sopenharmony_ci return MHZ_TO_KHZ(5935); 988c2ecf20Sopenharmony_ci if (chan <= 233) 998c2ecf20Sopenharmony_ci return MHZ_TO_KHZ(5950 + chan * 5); 1008c2ecf20Sopenharmony_ci break; 1018c2ecf20Sopenharmony_ci case NL80211_BAND_60GHZ: 1028c2ecf20Sopenharmony_ci if (chan < 7) 1038c2ecf20Sopenharmony_ci return MHZ_TO_KHZ(56160 + chan * 2160); 1048c2ecf20Sopenharmony_ci break; 1058c2ecf20Sopenharmony_ci case NL80211_BAND_S1GHZ: 1068c2ecf20Sopenharmony_ci return 902000 + chan * 500; 1078c2ecf20Sopenharmony_ci default: 1088c2ecf20Sopenharmony_ci ; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci return 0; /* not supported */ 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_channel_to_freq_khz); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cienum nl80211_chan_width 1158c2ecf20Sopenharmony_ciieee80211_s1g_channel_width(const struct ieee80211_channel *chan) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci if (WARN_ON(!chan || chan->band != NL80211_BAND_S1GHZ)) 1188c2ecf20Sopenharmony_ci return NL80211_CHAN_WIDTH_20_NOHT; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /*S1G defines a single allowed channel width per channel. 1218c2ecf20Sopenharmony_ci * Extract that width here. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci if (chan->flags & IEEE80211_CHAN_1MHZ) 1248c2ecf20Sopenharmony_ci return NL80211_CHAN_WIDTH_1; 1258c2ecf20Sopenharmony_ci else if (chan->flags & IEEE80211_CHAN_2MHZ) 1268c2ecf20Sopenharmony_ci return NL80211_CHAN_WIDTH_2; 1278c2ecf20Sopenharmony_ci else if (chan->flags & IEEE80211_CHAN_4MHZ) 1288c2ecf20Sopenharmony_ci return NL80211_CHAN_WIDTH_4; 1298c2ecf20Sopenharmony_ci else if (chan->flags & IEEE80211_CHAN_8MHZ) 1308c2ecf20Sopenharmony_ci return NL80211_CHAN_WIDTH_8; 1318c2ecf20Sopenharmony_ci else if (chan->flags & IEEE80211_CHAN_16MHZ) 1328c2ecf20Sopenharmony_ci return NL80211_CHAN_WIDTH_16; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci pr_err("unknown channel width for channel at %dKHz?\n", 1358c2ecf20Sopenharmony_ci ieee80211_channel_to_khz(chan)); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return NL80211_CHAN_WIDTH_1; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_s1g_channel_width); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ciint ieee80211_freq_khz_to_channel(u32 freq) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci /* TODO: just handle MHz for now */ 1448c2ecf20Sopenharmony_ci freq = KHZ_TO_MHZ(freq); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* see 802.11 17.3.8.3.2 and Annex J */ 1478c2ecf20Sopenharmony_ci if (freq == 2484) 1488c2ecf20Sopenharmony_ci return 14; 1498c2ecf20Sopenharmony_ci else if (freq < 2484) 1508c2ecf20Sopenharmony_ci return (freq - 2407) / 5; 1518c2ecf20Sopenharmony_ci else if (freq >= 4910 && freq <= 4980) 1528c2ecf20Sopenharmony_ci return (freq - 4000) / 5; 1538c2ecf20Sopenharmony_ci else if (freq < 5925) 1548c2ecf20Sopenharmony_ci return (freq - 5000) / 5; 1558c2ecf20Sopenharmony_ci else if (freq == 5935) 1568c2ecf20Sopenharmony_ci return 2; 1578c2ecf20Sopenharmony_ci else if (freq <= 45000) /* DMG band lower limit */ 1588c2ecf20Sopenharmony_ci /* see 802.11ax D6.1 27.3.22.2 */ 1598c2ecf20Sopenharmony_ci return (freq - 5950) / 5; 1608c2ecf20Sopenharmony_ci else if (freq >= 58320 && freq <= 70200) 1618c2ecf20Sopenharmony_ci return (freq - 56160) / 2160; 1628c2ecf20Sopenharmony_ci else 1638c2ecf20Sopenharmony_ci return 0; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_freq_khz_to_channel); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistruct ieee80211_channel *ieee80211_get_channel_khz(struct wiphy *wiphy, 1688c2ecf20Sopenharmony_ci u32 freq) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci enum nl80211_band band; 1718c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 1728c2ecf20Sopenharmony_ci int i; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) { 1758c2ecf20Sopenharmony_ci sband = wiphy->bands[band]; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (!sband) 1788c2ecf20Sopenharmony_ci continue; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci for (i = 0; i < sband->n_channels; i++) { 1818c2ecf20Sopenharmony_ci struct ieee80211_channel *chan = &sband->channels[i]; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (ieee80211_channel_to_khz(chan) == freq) 1848c2ecf20Sopenharmony_ci return chan; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return NULL; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_get_channel_khz); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic void set_mandatory_flags_band(struct ieee80211_supported_band *sband) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci int i, want; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci switch (sband->band) { 1978c2ecf20Sopenharmony_ci case NL80211_BAND_5GHZ: 1988c2ecf20Sopenharmony_ci case NL80211_BAND_6GHZ: 1998c2ecf20Sopenharmony_ci want = 3; 2008c2ecf20Sopenharmony_ci for (i = 0; i < sband->n_bitrates; i++) { 2018c2ecf20Sopenharmony_ci if (sband->bitrates[i].bitrate == 60 || 2028c2ecf20Sopenharmony_ci sband->bitrates[i].bitrate == 120 || 2038c2ecf20Sopenharmony_ci sband->bitrates[i].bitrate == 240) { 2048c2ecf20Sopenharmony_ci sband->bitrates[i].flags |= 2058c2ecf20Sopenharmony_ci IEEE80211_RATE_MANDATORY_A; 2068c2ecf20Sopenharmony_ci want--; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci WARN_ON(want); 2108c2ecf20Sopenharmony_ci break; 2118c2ecf20Sopenharmony_ci case NL80211_BAND_2GHZ: 2128c2ecf20Sopenharmony_ci want = 7; 2138c2ecf20Sopenharmony_ci for (i = 0; i < sband->n_bitrates; i++) { 2148c2ecf20Sopenharmony_ci switch (sband->bitrates[i].bitrate) { 2158c2ecf20Sopenharmony_ci case 10: 2168c2ecf20Sopenharmony_ci case 20: 2178c2ecf20Sopenharmony_ci case 55: 2188c2ecf20Sopenharmony_ci case 110: 2198c2ecf20Sopenharmony_ci sband->bitrates[i].flags |= 2208c2ecf20Sopenharmony_ci IEEE80211_RATE_MANDATORY_B | 2218c2ecf20Sopenharmony_ci IEEE80211_RATE_MANDATORY_G; 2228c2ecf20Sopenharmony_ci want--; 2238c2ecf20Sopenharmony_ci break; 2248c2ecf20Sopenharmony_ci case 60: 2258c2ecf20Sopenharmony_ci case 120: 2268c2ecf20Sopenharmony_ci case 240: 2278c2ecf20Sopenharmony_ci sband->bitrates[i].flags |= 2288c2ecf20Sopenharmony_ci IEEE80211_RATE_MANDATORY_G; 2298c2ecf20Sopenharmony_ci want--; 2308c2ecf20Sopenharmony_ci fallthrough; 2318c2ecf20Sopenharmony_ci default: 2328c2ecf20Sopenharmony_ci sband->bitrates[i].flags |= 2338c2ecf20Sopenharmony_ci IEEE80211_RATE_ERP_G; 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci WARN_ON(want != 0 && want != 3); 2388c2ecf20Sopenharmony_ci break; 2398c2ecf20Sopenharmony_ci case NL80211_BAND_60GHZ: 2408c2ecf20Sopenharmony_ci /* check for mandatory HT MCS 1..4 */ 2418c2ecf20Sopenharmony_ci WARN_ON(!sband->ht_cap.ht_supported); 2428c2ecf20Sopenharmony_ci WARN_ON((sband->ht_cap.mcs.rx_mask[0] & 0x1e) != 0x1e); 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci case NL80211_BAND_S1GHZ: 2458c2ecf20Sopenharmony_ci /* Figure 9-589bd: 3 means unsupported, so != 3 means at least 2468c2ecf20Sopenharmony_ci * mandatory is ok. 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_ci WARN_ON((sband->s1g_cap.nss_mcs[0] & 0x3) == 0x3); 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci case NUM_NL80211_BANDS: 2518c2ecf20Sopenharmony_ci default: 2528c2ecf20Sopenharmony_ci WARN_ON(1); 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_civoid ieee80211_set_bitrate_flags(struct wiphy *wiphy) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci enum nl80211_band band; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) 2628c2ecf20Sopenharmony_ci if (wiphy->bands[band]) 2638c2ecf20Sopenharmony_ci set_mandatory_flags_band(wiphy->bands[band]); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cibool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci int i; 2698c2ecf20Sopenharmony_ci for (i = 0; i < wiphy->n_cipher_suites; i++) 2708c2ecf20Sopenharmony_ci if (cipher == wiphy->cipher_suites[i]) 2718c2ecf20Sopenharmony_ci return true; 2728c2ecf20Sopenharmony_ci return false; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic bool 2768c2ecf20Sopenharmony_cicfg80211_igtk_cipher_supported(struct cfg80211_registered_device *rdev) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct wiphy *wiphy = &rdev->wiphy; 2798c2ecf20Sopenharmony_ci int i; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci for (i = 0; i < wiphy->n_cipher_suites; i++) { 2828c2ecf20Sopenharmony_ci switch (wiphy->cipher_suites[i]) { 2838c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_AES_CMAC: 2848c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_CMAC_256: 2858c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_GMAC_128: 2868c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_GMAC_256: 2878c2ecf20Sopenharmony_ci return true; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return false; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cibool cfg80211_valid_key_idx(struct cfg80211_registered_device *rdev, 2958c2ecf20Sopenharmony_ci int key_idx, bool pairwise) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci int max_key_idx; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (pairwise) 3008c2ecf20Sopenharmony_ci max_key_idx = 3; 3018c2ecf20Sopenharmony_ci else if (wiphy_ext_feature_isset(&rdev->wiphy, 3028c2ecf20Sopenharmony_ci NL80211_EXT_FEATURE_BEACON_PROTECTION) || 3038c2ecf20Sopenharmony_ci wiphy_ext_feature_isset(&rdev->wiphy, 3048c2ecf20Sopenharmony_ci NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT)) 3058c2ecf20Sopenharmony_ci max_key_idx = 7; 3068c2ecf20Sopenharmony_ci else if (cfg80211_igtk_cipher_supported(rdev)) 3078c2ecf20Sopenharmony_ci max_key_idx = 5; 3088c2ecf20Sopenharmony_ci else 3098c2ecf20Sopenharmony_ci max_key_idx = 3; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (key_idx < 0 || key_idx > max_key_idx) 3128c2ecf20Sopenharmony_ci return false; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci return true; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ciint cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, 3188c2ecf20Sopenharmony_ci struct key_params *params, int key_idx, 3198c2ecf20Sopenharmony_ci bool pairwise, const u8 *mac_addr) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci if (!cfg80211_valid_key_idx(rdev, key_idx, pairwise)) 3228c2ecf20Sopenharmony_ci return -EINVAL; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) 3258c2ecf20Sopenharmony_ci return -EINVAL; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (pairwise && !mac_addr) 3288c2ecf20Sopenharmony_ci return -EINVAL; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci switch (params->cipher) { 3318c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 3328c2ecf20Sopenharmony_ci /* Extended Key ID can only be used with CCMP/GCMP ciphers */ 3338c2ecf20Sopenharmony_ci if ((pairwise && key_idx) || 3348c2ecf20Sopenharmony_ci params->mode != NL80211_KEY_RX_TX) 3358c2ecf20Sopenharmony_ci return -EINVAL; 3368c2ecf20Sopenharmony_ci break; 3378c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 3388c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP_256: 3398c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP: 3408c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP_256: 3418c2ecf20Sopenharmony_ci /* IEEE802.11-2016 allows only 0 and - when supporting 3428c2ecf20Sopenharmony_ci * Extended Key ID - 1 as index for pairwise keys. 3438c2ecf20Sopenharmony_ci * @NL80211_KEY_NO_TX is only allowed for pairwise keys when 3448c2ecf20Sopenharmony_ci * the driver supports Extended Key ID. 3458c2ecf20Sopenharmony_ci * @NL80211_KEY_SET_TX can't be set when installing and 3468c2ecf20Sopenharmony_ci * validating a key. 3478c2ecf20Sopenharmony_ci */ 3488c2ecf20Sopenharmony_ci if ((params->mode == NL80211_KEY_NO_TX && !pairwise) || 3498c2ecf20Sopenharmony_ci params->mode == NL80211_KEY_SET_TX) 3508c2ecf20Sopenharmony_ci return -EINVAL; 3518c2ecf20Sopenharmony_ci if (wiphy_ext_feature_isset(&rdev->wiphy, 3528c2ecf20Sopenharmony_ci NL80211_EXT_FEATURE_EXT_KEY_ID)) { 3538c2ecf20Sopenharmony_ci if (pairwise && (key_idx < 0 || key_idx > 1)) 3548c2ecf20Sopenharmony_ci return -EINVAL; 3558c2ecf20Sopenharmony_ci } else if (pairwise && key_idx) { 3568c2ecf20Sopenharmony_ci return -EINVAL; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_AES_CMAC: 3608c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_CMAC_256: 3618c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_GMAC_128: 3628c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_GMAC_256: 3638c2ecf20Sopenharmony_ci /* Disallow BIP (group-only) cipher as pairwise cipher */ 3648c2ecf20Sopenharmony_ci if (pairwise) 3658c2ecf20Sopenharmony_ci return -EINVAL; 3668c2ecf20Sopenharmony_ci if (key_idx < 4) 3678c2ecf20Sopenharmony_ci return -EINVAL; 3688c2ecf20Sopenharmony_ci break; 3698c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 3708c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 3718c2ecf20Sopenharmony_ci if (key_idx > 3) 3728c2ecf20Sopenharmony_ci return -EINVAL; 3738c2ecf20Sopenharmony_ci default: 3748c2ecf20Sopenharmony_ci break; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci switch (params->cipher) { 3788c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 3798c2ecf20Sopenharmony_ci if (params->key_len != WLAN_KEY_LEN_WEP40) 3808c2ecf20Sopenharmony_ci return -EINVAL; 3818c2ecf20Sopenharmony_ci break; 3828c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 3838c2ecf20Sopenharmony_ci if (params->key_len != WLAN_KEY_LEN_TKIP) 3848c2ecf20Sopenharmony_ci return -EINVAL; 3858c2ecf20Sopenharmony_ci break; 3868c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 3878c2ecf20Sopenharmony_ci if (params->key_len != WLAN_KEY_LEN_CCMP) 3888c2ecf20Sopenharmony_ci return -EINVAL; 3898c2ecf20Sopenharmony_ci break; 3908c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP_256: 3918c2ecf20Sopenharmony_ci if (params->key_len != WLAN_KEY_LEN_CCMP_256) 3928c2ecf20Sopenharmony_ci return -EINVAL; 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP: 3958c2ecf20Sopenharmony_ci if (params->key_len != WLAN_KEY_LEN_GCMP) 3968c2ecf20Sopenharmony_ci return -EINVAL; 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP_256: 3998c2ecf20Sopenharmony_ci if (params->key_len != WLAN_KEY_LEN_GCMP_256) 4008c2ecf20Sopenharmony_ci return -EINVAL; 4018c2ecf20Sopenharmony_ci break; 4028c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 4038c2ecf20Sopenharmony_ci if (params->key_len != WLAN_KEY_LEN_WEP104) 4048c2ecf20Sopenharmony_ci return -EINVAL; 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_AES_CMAC: 4078c2ecf20Sopenharmony_ci if (params->key_len != WLAN_KEY_LEN_AES_CMAC) 4088c2ecf20Sopenharmony_ci return -EINVAL; 4098c2ecf20Sopenharmony_ci break; 4108c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_CMAC_256: 4118c2ecf20Sopenharmony_ci if (params->key_len != WLAN_KEY_LEN_BIP_CMAC_256) 4128c2ecf20Sopenharmony_ci return -EINVAL; 4138c2ecf20Sopenharmony_ci break; 4148c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_GMAC_128: 4158c2ecf20Sopenharmony_ci if (params->key_len != WLAN_KEY_LEN_BIP_GMAC_128) 4168c2ecf20Sopenharmony_ci return -EINVAL; 4178c2ecf20Sopenharmony_ci break; 4188c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_GMAC_256: 4198c2ecf20Sopenharmony_ci if (params->key_len != WLAN_KEY_LEN_BIP_GMAC_256) 4208c2ecf20Sopenharmony_ci return -EINVAL; 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci default: 4238c2ecf20Sopenharmony_ci /* 4248c2ecf20Sopenharmony_ci * We don't know anything about this algorithm, 4258c2ecf20Sopenharmony_ci * allow using it -- but the driver must check 4268c2ecf20Sopenharmony_ci * all parameters! We still check below whether 4278c2ecf20Sopenharmony_ci * or not the driver supports this algorithm, 4288c2ecf20Sopenharmony_ci * of course. 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_ci break; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (params->seq) { 4348c2ecf20Sopenharmony_ci switch (params->cipher) { 4358c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 4368c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 4378c2ecf20Sopenharmony_ci /* These ciphers do not use key sequence */ 4388c2ecf20Sopenharmony_ci return -EINVAL; 4398c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 4408c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 4418c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP_256: 4428c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP: 4438c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP_256: 4448c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_AES_CMAC: 4458c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_CMAC_256: 4468c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_GMAC_128: 4478c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_GMAC_256: 4488c2ecf20Sopenharmony_ci if (params->seq_len != 6) 4498c2ecf20Sopenharmony_ci return -EINVAL; 4508c2ecf20Sopenharmony_ci break; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (!cfg80211_supported_cipher_suite(&rdev->wiphy, params->cipher)) 4558c2ecf20Sopenharmony_ci return -EINVAL; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci return 0; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ciunsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci unsigned int hdrlen = 24; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (ieee80211_is_ext(fc)) { 4658c2ecf20Sopenharmony_ci hdrlen = 4; 4668c2ecf20Sopenharmony_ci goto out; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (ieee80211_is_data(fc)) { 4708c2ecf20Sopenharmony_ci if (ieee80211_has_a4(fc)) 4718c2ecf20Sopenharmony_ci hdrlen = 30; 4728c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(fc)) { 4738c2ecf20Sopenharmony_ci hdrlen += IEEE80211_QOS_CTL_LEN; 4748c2ecf20Sopenharmony_ci if (ieee80211_has_order(fc)) 4758c2ecf20Sopenharmony_ci hdrlen += IEEE80211_HT_CTL_LEN; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci goto out; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (ieee80211_is_mgmt(fc)) { 4818c2ecf20Sopenharmony_ci if (ieee80211_has_order(fc)) 4828c2ecf20Sopenharmony_ci hdrlen += IEEE80211_HT_CTL_LEN; 4838c2ecf20Sopenharmony_ci goto out; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (ieee80211_is_ctl(fc)) { 4878c2ecf20Sopenharmony_ci /* 4888c2ecf20Sopenharmony_ci * ACK and CTS are 10 bytes, all others 16. To see how 4898c2ecf20Sopenharmony_ci * to get this condition consider 4908c2ecf20Sopenharmony_ci * subtype mask: 0b0000000011110000 (0x00F0) 4918c2ecf20Sopenharmony_ci * ACK subtype: 0b0000000011010000 (0x00D0) 4928c2ecf20Sopenharmony_ci * CTS subtype: 0b0000000011000000 (0x00C0) 4938c2ecf20Sopenharmony_ci * bits that matter: ^^^ (0x00E0) 4948c2ecf20Sopenharmony_ci * value of those: 0b0000000011000000 (0x00C0) 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_ci if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) 4978c2ecf20Sopenharmony_ci hdrlen = 10; 4988c2ecf20Sopenharmony_ci else 4998c2ecf20Sopenharmony_ci hdrlen = 16; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ciout: 5028c2ecf20Sopenharmony_ci return hdrlen; 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_hdrlen); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ciunsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci const struct ieee80211_hdr *hdr = 5098c2ecf20Sopenharmony_ci (const struct ieee80211_hdr *)skb->data; 5108c2ecf20Sopenharmony_ci unsigned int hdrlen; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (unlikely(skb->len < 10)) 5138c2ecf20Sopenharmony_ci return 0; 5148c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 5158c2ecf20Sopenharmony_ci if (unlikely(hdrlen > skb->len)) 5168c2ecf20Sopenharmony_ci return 0; 5178c2ecf20Sopenharmony_ci return hdrlen; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic unsigned int __ieee80211_get_mesh_hdrlen(u8 flags) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci int ae = flags & MESH_FLAGS_AE; 5248c2ecf20Sopenharmony_ci /* 802.11-2012, 8.2.4.7.3 */ 5258c2ecf20Sopenharmony_ci switch (ae) { 5268c2ecf20Sopenharmony_ci default: 5278c2ecf20Sopenharmony_ci case 0: 5288c2ecf20Sopenharmony_ci return 6; 5298c2ecf20Sopenharmony_ci case MESH_FLAGS_AE_A4: 5308c2ecf20Sopenharmony_ci return 12; 5318c2ecf20Sopenharmony_ci case MESH_FLAGS_AE_A5_A6: 5328c2ecf20Sopenharmony_ci return 18; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ciunsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci return __ieee80211_get_mesh_hdrlen(meshhdr->flags); 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_get_mesh_hdrlen); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ciint ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr, 5438c2ecf20Sopenharmony_ci const u8 *addr, enum nl80211_iftype iftype, 5448c2ecf20Sopenharmony_ci u8 data_offset, bool is_amsdu) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 5478c2ecf20Sopenharmony_ci struct { 5488c2ecf20Sopenharmony_ci u8 hdr[ETH_ALEN] __aligned(2); 5498c2ecf20Sopenharmony_ci __be16 proto; 5508c2ecf20Sopenharmony_ci } payload; 5518c2ecf20Sopenharmony_ci struct ethhdr tmp; 5528c2ecf20Sopenharmony_ci u16 hdrlen; 5538c2ecf20Sopenharmony_ci u8 mesh_flags = 0; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) 5568c2ecf20Sopenharmony_ci return -1; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control) + data_offset; 5598c2ecf20Sopenharmony_ci if (skb->len < hdrlen + 8) 5608c2ecf20Sopenharmony_ci return -1; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* convert IEEE 802.11 header + possible LLC headers into Ethernet 5638c2ecf20Sopenharmony_ci * header 5648c2ecf20Sopenharmony_ci * IEEE 802.11 address fields: 5658c2ecf20Sopenharmony_ci * ToDS FromDS Addr1 Addr2 Addr3 Addr4 5668c2ecf20Sopenharmony_ci * 0 0 DA SA BSSID n/a 5678c2ecf20Sopenharmony_ci * 0 1 DA BSSID SA n/a 5688c2ecf20Sopenharmony_ci * 1 0 BSSID SA DA n/a 5698c2ecf20Sopenharmony_ci * 1 1 RA TA DA SA 5708c2ecf20Sopenharmony_ci */ 5718c2ecf20Sopenharmony_ci memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN); 5728c2ecf20Sopenharmony_ci memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (iftype == NL80211_IFTYPE_MESH_POINT) 5758c2ecf20Sopenharmony_ci skb_copy_bits(skb, hdrlen, &mesh_flags, 1); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci mesh_flags &= MESH_FLAGS_AE; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci switch (hdr->frame_control & 5808c2ecf20Sopenharmony_ci cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { 5818c2ecf20Sopenharmony_ci case cpu_to_le16(IEEE80211_FCTL_TODS): 5828c2ecf20Sopenharmony_ci if (unlikely(iftype != NL80211_IFTYPE_AP && 5838c2ecf20Sopenharmony_ci iftype != NL80211_IFTYPE_AP_VLAN && 5848c2ecf20Sopenharmony_ci iftype != NL80211_IFTYPE_P2P_GO)) 5858c2ecf20Sopenharmony_ci return -1; 5868c2ecf20Sopenharmony_ci break; 5878c2ecf20Sopenharmony_ci case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): 5888c2ecf20Sopenharmony_ci if (unlikely(iftype != NL80211_IFTYPE_WDS && 5898c2ecf20Sopenharmony_ci iftype != NL80211_IFTYPE_MESH_POINT && 5908c2ecf20Sopenharmony_ci iftype != NL80211_IFTYPE_AP_VLAN && 5918c2ecf20Sopenharmony_ci iftype != NL80211_IFTYPE_STATION)) 5928c2ecf20Sopenharmony_ci return -1; 5938c2ecf20Sopenharmony_ci if (iftype == NL80211_IFTYPE_MESH_POINT) { 5948c2ecf20Sopenharmony_ci if (mesh_flags == MESH_FLAGS_AE_A4) 5958c2ecf20Sopenharmony_ci return -1; 5968c2ecf20Sopenharmony_ci if (mesh_flags == MESH_FLAGS_AE_A5_A6) { 5978c2ecf20Sopenharmony_ci skb_copy_bits(skb, hdrlen + 5988c2ecf20Sopenharmony_ci offsetof(struct ieee80211s_hdr, eaddr1), 5998c2ecf20Sopenharmony_ci tmp.h_dest, 2 * ETH_ALEN); 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags); 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci break; 6048c2ecf20Sopenharmony_ci case cpu_to_le16(IEEE80211_FCTL_FROMDS): 6058c2ecf20Sopenharmony_ci if ((iftype != NL80211_IFTYPE_STATION && 6068c2ecf20Sopenharmony_ci iftype != NL80211_IFTYPE_P2P_CLIENT && 6078c2ecf20Sopenharmony_ci iftype != NL80211_IFTYPE_MESH_POINT) || 6088c2ecf20Sopenharmony_ci (is_multicast_ether_addr(tmp.h_dest) && 6098c2ecf20Sopenharmony_ci ether_addr_equal(tmp.h_source, addr))) 6108c2ecf20Sopenharmony_ci return -1; 6118c2ecf20Sopenharmony_ci if (iftype == NL80211_IFTYPE_MESH_POINT) { 6128c2ecf20Sopenharmony_ci if (mesh_flags == MESH_FLAGS_AE_A5_A6) 6138c2ecf20Sopenharmony_ci return -1; 6148c2ecf20Sopenharmony_ci if (mesh_flags == MESH_FLAGS_AE_A4) 6158c2ecf20Sopenharmony_ci skb_copy_bits(skb, hdrlen + 6168c2ecf20Sopenharmony_ci offsetof(struct ieee80211s_hdr, eaddr1), 6178c2ecf20Sopenharmony_ci tmp.h_source, ETH_ALEN); 6188c2ecf20Sopenharmony_ci hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags); 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci break; 6218c2ecf20Sopenharmony_ci case cpu_to_le16(0): 6228c2ecf20Sopenharmony_ci if (iftype != NL80211_IFTYPE_ADHOC && 6238c2ecf20Sopenharmony_ci iftype != NL80211_IFTYPE_STATION && 6248c2ecf20Sopenharmony_ci iftype != NL80211_IFTYPE_OCB) 6258c2ecf20Sopenharmony_ci return -1; 6268c2ecf20Sopenharmony_ci break; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)); 6308c2ecf20Sopenharmony_ci tmp.h_proto = payload.proto; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (likely((!is_amsdu && ether_addr_equal(payload.hdr, rfc1042_header) && 6338c2ecf20Sopenharmony_ci tmp.h_proto != htons(ETH_P_AARP) && 6348c2ecf20Sopenharmony_ci tmp.h_proto != htons(ETH_P_IPX)) || 6358c2ecf20Sopenharmony_ci ether_addr_equal(payload.hdr, bridge_tunnel_header))) 6368c2ecf20Sopenharmony_ci /* remove RFC1042 or Bridge-Tunnel encapsulation and 6378c2ecf20Sopenharmony_ci * replace EtherType */ 6388c2ecf20Sopenharmony_ci hdrlen += ETH_ALEN + 2; 6398c2ecf20Sopenharmony_ci else 6408c2ecf20Sopenharmony_ci tmp.h_proto = htons(skb->len - hdrlen); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci pskb_pull(skb, hdrlen); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (!ehdr) 6458c2ecf20Sopenharmony_ci ehdr = skb_push(skb, sizeof(struct ethhdr)); 6468c2ecf20Sopenharmony_ci memcpy(ehdr, &tmp, sizeof(tmp)); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci return 0; 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_data_to_8023_exthdr); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cistatic void 6538c2ecf20Sopenharmony_ci__frame_add_frag(struct sk_buff *skb, struct page *page, 6548c2ecf20Sopenharmony_ci void *ptr, int len, int size) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci struct skb_shared_info *sh = skb_shinfo(skb); 6578c2ecf20Sopenharmony_ci int page_offset; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci get_page(page); 6608c2ecf20Sopenharmony_ci page_offset = ptr - page_address(page); 6618c2ecf20Sopenharmony_ci skb_add_rx_frag(skb, sh->nr_frags, page, page_offset, len, size); 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic void 6658c2ecf20Sopenharmony_ci__ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame, 6668c2ecf20Sopenharmony_ci int offset, int len) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci struct skb_shared_info *sh = skb_shinfo(skb); 6698c2ecf20Sopenharmony_ci const skb_frag_t *frag = &sh->frags[0]; 6708c2ecf20Sopenharmony_ci struct page *frag_page; 6718c2ecf20Sopenharmony_ci void *frag_ptr; 6728c2ecf20Sopenharmony_ci int frag_len, frag_size; 6738c2ecf20Sopenharmony_ci int head_size = skb->len - skb->data_len; 6748c2ecf20Sopenharmony_ci int cur_len; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci frag_page = virt_to_head_page(skb->head); 6778c2ecf20Sopenharmony_ci frag_ptr = skb->data; 6788c2ecf20Sopenharmony_ci frag_size = head_size; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci while (offset >= frag_size) { 6818c2ecf20Sopenharmony_ci offset -= frag_size; 6828c2ecf20Sopenharmony_ci frag_page = skb_frag_page(frag); 6838c2ecf20Sopenharmony_ci frag_ptr = skb_frag_address(frag); 6848c2ecf20Sopenharmony_ci frag_size = skb_frag_size(frag); 6858c2ecf20Sopenharmony_ci frag++; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci frag_ptr += offset; 6898c2ecf20Sopenharmony_ci frag_len = frag_size - offset; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci cur_len = min(len, frag_len); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci __frame_add_frag(frame, frag_page, frag_ptr, cur_len, frag_size); 6948c2ecf20Sopenharmony_ci len -= cur_len; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci while (len > 0) { 6978c2ecf20Sopenharmony_ci frag_len = skb_frag_size(frag); 6988c2ecf20Sopenharmony_ci cur_len = min(len, frag_len); 6998c2ecf20Sopenharmony_ci __frame_add_frag(frame, skb_frag_page(frag), 7008c2ecf20Sopenharmony_ci skb_frag_address(frag), cur_len, frag_len); 7018c2ecf20Sopenharmony_ci len -= cur_len; 7028c2ecf20Sopenharmony_ci frag++; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic struct sk_buff * 7078c2ecf20Sopenharmony_ci__ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen, 7088c2ecf20Sopenharmony_ci int offset, int len, bool reuse_frag) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct sk_buff *frame; 7118c2ecf20Sopenharmony_ci int cur_len = len; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (skb->len - offset < len) 7148c2ecf20Sopenharmony_ci return NULL; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* 7178c2ecf20Sopenharmony_ci * When reusing framents, copy some data to the head to simplify 7188c2ecf20Sopenharmony_ci * ethernet header handling and speed up protocol header processing 7198c2ecf20Sopenharmony_ci * in the stack later. 7208c2ecf20Sopenharmony_ci */ 7218c2ecf20Sopenharmony_ci if (reuse_frag) 7228c2ecf20Sopenharmony_ci cur_len = min_t(int, len, 32); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* 7258c2ecf20Sopenharmony_ci * Allocate and reserve two bytes more for payload 7268c2ecf20Sopenharmony_ci * alignment since sizeof(struct ethhdr) is 14. 7278c2ecf20Sopenharmony_ci */ 7288c2ecf20Sopenharmony_ci frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len); 7298c2ecf20Sopenharmony_ci if (!frame) 7308c2ecf20Sopenharmony_ci return NULL; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); 7338c2ecf20Sopenharmony_ci skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci len -= cur_len; 7368c2ecf20Sopenharmony_ci if (!len) 7378c2ecf20Sopenharmony_ci return frame; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci offset += cur_len; 7408c2ecf20Sopenharmony_ci __ieee80211_amsdu_copy_frag(skb, frame, offset, len); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci return frame; 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_civoid ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, 7468c2ecf20Sopenharmony_ci const u8 *addr, enum nl80211_iftype iftype, 7478c2ecf20Sopenharmony_ci const unsigned int extra_headroom, 7488c2ecf20Sopenharmony_ci const u8 *check_da, const u8 *check_sa) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci unsigned int hlen = ALIGN(extra_headroom, 4); 7518c2ecf20Sopenharmony_ci struct sk_buff *frame = NULL; 7528c2ecf20Sopenharmony_ci u16 ethertype; 7538c2ecf20Sopenharmony_ci u8 *payload; 7548c2ecf20Sopenharmony_ci int offset = 0, remaining; 7558c2ecf20Sopenharmony_ci struct ethhdr eth; 7568c2ecf20Sopenharmony_ci bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb); 7578c2ecf20Sopenharmony_ci bool reuse_skb = false; 7588c2ecf20Sopenharmony_ci bool last = false; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci while (!last) { 7618c2ecf20Sopenharmony_ci unsigned int subframe_len; 7628c2ecf20Sopenharmony_ci int len; 7638c2ecf20Sopenharmony_ci u8 padding; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci skb_copy_bits(skb, offset, ð, sizeof(eth)); 7668c2ecf20Sopenharmony_ci len = ntohs(eth.h_proto); 7678c2ecf20Sopenharmony_ci subframe_len = sizeof(struct ethhdr) + len; 7688c2ecf20Sopenharmony_ci padding = (4 - subframe_len) & 0x3; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci /* the last MSDU has no padding */ 7718c2ecf20Sopenharmony_ci remaining = skb->len - offset; 7728c2ecf20Sopenharmony_ci if (subframe_len > remaining) 7738c2ecf20Sopenharmony_ci goto purge; 7748c2ecf20Sopenharmony_ci /* mitigate A-MSDU aggregation injection attacks */ 7758c2ecf20Sopenharmony_ci if (ether_addr_equal(eth.h_dest, rfc1042_header)) 7768c2ecf20Sopenharmony_ci goto purge; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci offset += sizeof(struct ethhdr); 7798c2ecf20Sopenharmony_ci last = remaining <= subframe_len + padding; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci /* FIXME: should we really accept multicast DA? */ 7828c2ecf20Sopenharmony_ci if ((check_da && !is_multicast_ether_addr(eth.h_dest) && 7838c2ecf20Sopenharmony_ci !ether_addr_equal(check_da, eth.h_dest)) || 7848c2ecf20Sopenharmony_ci (check_sa && !ether_addr_equal(check_sa, eth.h_source))) { 7858c2ecf20Sopenharmony_ci offset += len + padding; 7868c2ecf20Sopenharmony_ci continue; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci /* reuse skb for the last subframe */ 7908c2ecf20Sopenharmony_ci if (!skb_is_nonlinear(skb) && !reuse_frag && last) { 7918c2ecf20Sopenharmony_ci skb_pull(skb, offset); 7928c2ecf20Sopenharmony_ci frame = skb; 7938c2ecf20Sopenharmony_ci reuse_skb = true; 7948c2ecf20Sopenharmony_ci } else { 7958c2ecf20Sopenharmony_ci frame = __ieee80211_amsdu_copy(skb, hlen, offset, len, 7968c2ecf20Sopenharmony_ci reuse_frag); 7978c2ecf20Sopenharmony_ci if (!frame) 7988c2ecf20Sopenharmony_ci goto purge; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci offset += len + padding; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci skb_reset_network_header(frame); 8048c2ecf20Sopenharmony_ci frame->dev = skb->dev; 8058c2ecf20Sopenharmony_ci frame->priority = skb->priority; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci payload = frame->data; 8088c2ecf20Sopenharmony_ci ethertype = (payload[6] << 8) | payload[7]; 8098c2ecf20Sopenharmony_ci if (likely((ether_addr_equal(payload, rfc1042_header) && 8108c2ecf20Sopenharmony_ci ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || 8118c2ecf20Sopenharmony_ci ether_addr_equal(payload, bridge_tunnel_header))) { 8128c2ecf20Sopenharmony_ci eth.h_proto = htons(ethertype); 8138c2ecf20Sopenharmony_ci skb_pull(frame, ETH_ALEN + 2); 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci memcpy(skb_push(frame, sizeof(eth)), ð, sizeof(eth)); 8178c2ecf20Sopenharmony_ci __skb_queue_tail(list, frame); 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (!reuse_skb) 8218c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci return; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci purge: 8268c2ecf20Sopenharmony_ci __skb_queue_purge(list); 8278c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_amsdu_to_8023s); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci/* Given a data frame determine the 802.1p/1d tag to use. */ 8328c2ecf20Sopenharmony_ciunsigned int cfg80211_classify8021d(struct sk_buff *skb, 8338c2ecf20Sopenharmony_ci struct cfg80211_qos_map *qos_map) 8348c2ecf20Sopenharmony_ci{ 8358c2ecf20Sopenharmony_ci unsigned int dscp; 8368c2ecf20Sopenharmony_ci unsigned char vlan_priority; 8378c2ecf20Sopenharmony_ci unsigned int ret; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci /* skb->priority values from 256->263 are magic values to 8408c2ecf20Sopenharmony_ci * directly indicate a specific 802.1d priority. This is used 8418c2ecf20Sopenharmony_ci * to allow 802.1d priority to be passed directly in from VLAN 8428c2ecf20Sopenharmony_ci * tags, etc. 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_ci if (skb->priority >= 256 && skb->priority <= 263) { 8458c2ecf20Sopenharmony_ci ret = skb->priority - 256; 8468c2ecf20Sopenharmony_ci goto out; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 8508c2ecf20Sopenharmony_ci vlan_priority = (skb_vlan_tag_get(skb) & VLAN_PRIO_MASK) 8518c2ecf20Sopenharmony_ci >> VLAN_PRIO_SHIFT; 8528c2ecf20Sopenharmony_ci if (vlan_priority > 0) { 8538c2ecf20Sopenharmony_ci ret = vlan_priority; 8548c2ecf20Sopenharmony_ci goto out; 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci switch (skb->protocol) { 8598c2ecf20Sopenharmony_ci case htons(ETH_P_IP): 8608c2ecf20Sopenharmony_ci dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc; 8618c2ecf20Sopenharmony_ci break; 8628c2ecf20Sopenharmony_ci case htons(ETH_P_IPV6): 8638c2ecf20Sopenharmony_ci dscp = ipv6_get_dsfield(ipv6_hdr(skb)) & 0xfc; 8648c2ecf20Sopenharmony_ci break; 8658c2ecf20Sopenharmony_ci case htons(ETH_P_MPLS_UC): 8668c2ecf20Sopenharmony_ci case htons(ETH_P_MPLS_MC): { 8678c2ecf20Sopenharmony_ci struct mpls_label mpls_tmp, *mpls; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci mpls = skb_header_pointer(skb, sizeof(struct ethhdr), 8708c2ecf20Sopenharmony_ci sizeof(*mpls), &mpls_tmp); 8718c2ecf20Sopenharmony_ci if (!mpls) 8728c2ecf20Sopenharmony_ci return 0; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci ret = (ntohl(mpls->entry) & MPLS_LS_TC_MASK) 8758c2ecf20Sopenharmony_ci >> MPLS_LS_TC_SHIFT; 8768c2ecf20Sopenharmony_ci goto out; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci case htons(ETH_P_80221): 8798c2ecf20Sopenharmony_ci /* 802.21 is always network control traffic */ 8808c2ecf20Sopenharmony_ci return 7; 8818c2ecf20Sopenharmony_ci default: 8828c2ecf20Sopenharmony_ci return 0; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (qos_map) { 8868c2ecf20Sopenharmony_ci unsigned int i, tmp_dscp = dscp >> 2; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci for (i = 0; i < qos_map->num_des; i++) { 8898c2ecf20Sopenharmony_ci if (tmp_dscp == qos_map->dscp_exception[i].dscp) { 8908c2ecf20Sopenharmony_ci ret = qos_map->dscp_exception[i].up; 8918c2ecf20Sopenharmony_ci goto out; 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 8968c2ecf20Sopenharmony_ci if (tmp_dscp >= qos_map->up[i].low && 8978c2ecf20Sopenharmony_ci tmp_dscp <= qos_map->up[i].high) { 8988c2ecf20Sopenharmony_ci ret = i; 8998c2ecf20Sopenharmony_ci goto out; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci ret = dscp >> 5; 9058c2ecf20Sopenharmony_ciout: 9068c2ecf20Sopenharmony_ci return array_index_nospec(ret, IEEE80211_NUM_TIDS); 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfg80211_classify8021d); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ciconst struct element *ieee80211_bss_get_elem(struct cfg80211_bss *bss, u8 id) 9118c2ecf20Sopenharmony_ci{ 9128c2ecf20Sopenharmony_ci const struct cfg80211_bss_ies *ies; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci ies = rcu_dereference(bss->ies); 9158c2ecf20Sopenharmony_ci if (!ies) 9168c2ecf20Sopenharmony_ci return NULL; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci return cfg80211_find_elem(id, ies->data, ies->len); 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_bss_get_elem); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_civoid cfg80211_upload_connect_keys(struct wireless_dev *wdev) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 9258c2ecf20Sopenharmony_ci struct net_device *dev = wdev->netdev; 9268c2ecf20Sopenharmony_ci int i; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (!wdev->connect_keys) 9298c2ecf20Sopenharmony_ci return; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++) { 9328c2ecf20Sopenharmony_ci if (!wdev->connect_keys->params[i].cipher) 9338c2ecf20Sopenharmony_ci continue; 9348c2ecf20Sopenharmony_ci if (rdev_add_key(rdev, dev, i, false, NULL, 9358c2ecf20Sopenharmony_ci &wdev->connect_keys->params[i])) { 9368c2ecf20Sopenharmony_ci netdev_err(dev, "failed to set key %d\n", i); 9378c2ecf20Sopenharmony_ci continue; 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci if (wdev->connect_keys->def == i && 9408c2ecf20Sopenharmony_ci rdev_set_default_key(rdev, dev, i, true, true)) { 9418c2ecf20Sopenharmony_ci netdev_err(dev, "failed to set defkey %d\n", i); 9428c2ecf20Sopenharmony_ci continue; 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci kfree_sensitive(wdev->connect_keys); 9478c2ecf20Sopenharmony_ci wdev->connect_keys = NULL; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_civoid cfg80211_process_wdev_events(struct wireless_dev *wdev) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct cfg80211_event *ev; 9538c2ecf20Sopenharmony_ci unsigned long flags; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdev->event_lock, flags); 9568c2ecf20Sopenharmony_ci while (!list_empty(&wdev->event_list)) { 9578c2ecf20Sopenharmony_ci ev = list_first_entry(&wdev->event_list, 9588c2ecf20Sopenharmony_ci struct cfg80211_event, list); 9598c2ecf20Sopenharmony_ci list_del(&ev->list); 9608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdev->event_lock, flags); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci wdev_lock(wdev); 9638c2ecf20Sopenharmony_ci switch (ev->type) { 9648c2ecf20Sopenharmony_ci case EVENT_CONNECT_RESULT: 9658c2ecf20Sopenharmony_ci __cfg80211_connect_result( 9668c2ecf20Sopenharmony_ci wdev->netdev, 9678c2ecf20Sopenharmony_ci &ev->cr, 9688c2ecf20Sopenharmony_ci ev->cr.status == WLAN_STATUS_SUCCESS); 9698c2ecf20Sopenharmony_ci break; 9708c2ecf20Sopenharmony_ci case EVENT_ROAMED: 9718c2ecf20Sopenharmony_ci __cfg80211_roamed(wdev, &ev->rm); 9728c2ecf20Sopenharmony_ci break; 9738c2ecf20Sopenharmony_ci case EVENT_DISCONNECTED: 9748c2ecf20Sopenharmony_ci __cfg80211_disconnected(wdev->netdev, 9758c2ecf20Sopenharmony_ci ev->dc.ie, ev->dc.ie_len, 9768c2ecf20Sopenharmony_ci ev->dc.reason, 9778c2ecf20Sopenharmony_ci !ev->dc.locally_generated); 9788c2ecf20Sopenharmony_ci break; 9798c2ecf20Sopenharmony_ci case EVENT_IBSS_JOINED: 9808c2ecf20Sopenharmony_ci __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid, 9818c2ecf20Sopenharmony_ci ev->ij.channel); 9828c2ecf20Sopenharmony_ci break; 9838c2ecf20Sopenharmony_ci case EVENT_STOPPED: 9848c2ecf20Sopenharmony_ci __cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev); 9858c2ecf20Sopenharmony_ci break; 9868c2ecf20Sopenharmony_ci case EVENT_PORT_AUTHORIZED: 9878c2ecf20Sopenharmony_ci __cfg80211_port_authorized(wdev, ev->pa.bssid); 9888c2ecf20Sopenharmony_ci break; 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci wdev_unlock(wdev); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci kfree(ev); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdev->event_lock, flags); 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdev->event_lock, flags); 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_civoid cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci struct wireless_dev *wdev; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci ASSERT_RTNL(); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) 10068c2ecf20Sopenharmony_ci cfg80211_process_wdev_events(wdev); 10078c2ecf20Sopenharmony_ci} 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ciint cfg80211_change_iface(struct cfg80211_registered_device *rdev, 10108c2ecf20Sopenharmony_ci struct net_device *dev, enum nl80211_iftype ntype, 10118c2ecf20Sopenharmony_ci struct vif_params *params) 10128c2ecf20Sopenharmony_ci{ 10138c2ecf20Sopenharmony_ci int err; 10148c2ecf20Sopenharmony_ci enum nl80211_iftype otype = dev->ieee80211_ptr->iftype; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci ASSERT_RTNL(); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci /* don't support changing VLANs, you just re-create them */ 10198c2ecf20Sopenharmony_ci if (otype == NL80211_IFTYPE_AP_VLAN) 10208c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci /* cannot change into P2P device or NAN */ 10238c2ecf20Sopenharmony_ci if (ntype == NL80211_IFTYPE_P2P_DEVICE || 10248c2ecf20Sopenharmony_ci ntype == NL80211_IFTYPE_NAN) 10258c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci if (!rdev->ops->change_virtual_intf || 10288c2ecf20Sopenharmony_ci !(rdev->wiphy.interface_modes & (1 << ntype))) 10298c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (ntype != otype) { 10328c2ecf20Sopenharmony_ci /* if it's part of a bridge, reject changing type to station/ibss */ 10338c2ecf20Sopenharmony_ci if (netif_is_bridge_port(dev) && 10348c2ecf20Sopenharmony_ci (ntype == NL80211_IFTYPE_ADHOC || 10358c2ecf20Sopenharmony_ci ntype == NL80211_IFTYPE_STATION || 10368c2ecf20Sopenharmony_ci ntype == NL80211_IFTYPE_P2P_CLIENT)) 10378c2ecf20Sopenharmony_ci return -EBUSY; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci dev->ieee80211_ptr->use_4addr = false; 10408c2ecf20Sopenharmony_ci dev->ieee80211_ptr->mesh_id_up_len = 0; 10418c2ecf20Sopenharmony_ci wdev_lock(dev->ieee80211_ptr); 10428c2ecf20Sopenharmony_ci rdev_set_qos_map(rdev, dev, NULL); 10438c2ecf20Sopenharmony_ci wdev_unlock(dev->ieee80211_ptr); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci switch (otype) { 10468c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 10478c2ecf20Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 10488c2ecf20Sopenharmony_ci cfg80211_stop_ap(rdev, dev, true); 10498c2ecf20Sopenharmony_ci break; 10508c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 10518c2ecf20Sopenharmony_ci cfg80211_leave_ibss(rdev, dev, false); 10528c2ecf20Sopenharmony_ci break; 10538c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 10548c2ecf20Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 10558c2ecf20Sopenharmony_ci wdev_lock(dev->ieee80211_ptr); 10568c2ecf20Sopenharmony_ci cfg80211_disconnect(rdev, dev, 10578c2ecf20Sopenharmony_ci WLAN_REASON_DEAUTH_LEAVING, true); 10588c2ecf20Sopenharmony_ci wdev_unlock(dev->ieee80211_ptr); 10598c2ecf20Sopenharmony_ci break; 10608c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 10618c2ecf20Sopenharmony_ci /* mesh should be handled? */ 10628c2ecf20Sopenharmony_ci break; 10638c2ecf20Sopenharmony_ci case NL80211_IFTYPE_OCB: 10648c2ecf20Sopenharmony_ci cfg80211_leave_ocb(rdev, dev); 10658c2ecf20Sopenharmony_ci break; 10668c2ecf20Sopenharmony_ci default: 10678c2ecf20Sopenharmony_ci break; 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci cfg80211_process_rdev_events(rdev); 10718c2ecf20Sopenharmony_ci cfg80211_mlme_purge_registrations(dev->ieee80211_ptr); 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci err = rdev_change_virtual_intf(rdev, dev, ntype, params); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if (!err && params && params->use_4addr != -1) 10798c2ecf20Sopenharmony_ci dev->ieee80211_ptr->use_4addr = params->use_4addr; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci if (!err) { 10828c2ecf20Sopenharmony_ci dev->priv_flags &= ~IFF_DONT_BRIDGE; 10838c2ecf20Sopenharmony_ci switch (ntype) { 10848c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 10858c2ecf20Sopenharmony_ci if (dev->ieee80211_ptr->use_4addr) 10868c2ecf20Sopenharmony_ci break; 10878c2ecf20Sopenharmony_ci fallthrough; 10888c2ecf20Sopenharmony_ci case NL80211_IFTYPE_OCB: 10898c2ecf20Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 10908c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 10918c2ecf20Sopenharmony_ci dev->priv_flags |= IFF_DONT_BRIDGE; 10928c2ecf20Sopenharmony_ci break; 10938c2ecf20Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 10948c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 10958c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP_VLAN: 10968c2ecf20Sopenharmony_ci case NL80211_IFTYPE_WDS: 10978c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 10988c2ecf20Sopenharmony_ci /* bridging OK */ 10998c2ecf20Sopenharmony_ci break; 11008c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MONITOR: 11018c2ecf20Sopenharmony_ci /* monitor can't bridge anyway */ 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci case NL80211_IFTYPE_UNSPECIFIED: 11048c2ecf20Sopenharmony_ci case NUM_NL80211_IFTYPES: 11058c2ecf20Sopenharmony_ci /* not happening */ 11068c2ecf20Sopenharmony_ci break; 11078c2ecf20Sopenharmony_ci case NL80211_IFTYPE_P2P_DEVICE: 11088c2ecf20Sopenharmony_ci case NL80211_IFTYPE_NAN: 11098c2ecf20Sopenharmony_ci WARN_ON(1); 11108c2ecf20Sopenharmony_ci break; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci if (!err && ntype != otype && netif_running(dev)) { 11158c2ecf20Sopenharmony_ci cfg80211_update_iface_num(rdev, ntype, 1); 11168c2ecf20Sopenharmony_ci cfg80211_update_iface_num(rdev, otype, -1); 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci return err; 11208c2ecf20Sopenharmony_ci} 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_cistatic u32 cfg80211_calculate_bitrate_ht(struct rate_info *rate) 11238c2ecf20Sopenharmony_ci{ 11248c2ecf20Sopenharmony_ci int modulation, streams, bitrate; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci /* the formula below does only work for MCS values smaller than 32 */ 11278c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(rate->mcs >= 32)) 11288c2ecf20Sopenharmony_ci return 0; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci modulation = rate->mcs & 7; 11318c2ecf20Sopenharmony_ci streams = (rate->mcs >> 3) + 1; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci bitrate = (rate->bw == RATE_INFO_BW_40) ? 13500000 : 6500000; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci if (modulation < 4) 11368c2ecf20Sopenharmony_ci bitrate *= (modulation + 1); 11378c2ecf20Sopenharmony_ci else if (modulation == 4) 11388c2ecf20Sopenharmony_ci bitrate *= (modulation + 2); 11398c2ecf20Sopenharmony_ci else 11408c2ecf20Sopenharmony_ci bitrate *= (modulation + 3); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci bitrate *= streams; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) 11458c2ecf20Sopenharmony_ci bitrate = (bitrate / 9) * 10; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci /* do NOT round down here */ 11488c2ecf20Sopenharmony_ci return (bitrate + 50000) / 100000; 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_cistatic u32 cfg80211_calculate_bitrate_dmg(struct rate_info *rate) 11528c2ecf20Sopenharmony_ci{ 11538c2ecf20Sopenharmony_ci static const u32 __mcs2bitrate[] = { 11548c2ecf20Sopenharmony_ci /* control PHY */ 11558c2ecf20Sopenharmony_ci [0] = 275, 11568c2ecf20Sopenharmony_ci /* SC PHY */ 11578c2ecf20Sopenharmony_ci [1] = 3850, 11588c2ecf20Sopenharmony_ci [2] = 7700, 11598c2ecf20Sopenharmony_ci [3] = 9625, 11608c2ecf20Sopenharmony_ci [4] = 11550, 11618c2ecf20Sopenharmony_ci [5] = 12512, /* 1251.25 mbps */ 11628c2ecf20Sopenharmony_ci [6] = 15400, 11638c2ecf20Sopenharmony_ci [7] = 19250, 11648c2ecf20Sopenharmony_ci [8] = 23100, 11658c2ecf20Sopenharmony_ci [9] = 25025, 11668c2ecf20Sopenharmony_ci [10] = 30800, 11678c2ecf20Sopenharmony_ci [11] = 38500, 11688c2ecf20Sopenharmony_ci [12] = 46200, 11698c2ecf20Sopenharmony_ci /* OFDM PHY */ 11708c2ecf20Sopenharmony_ci [13] = 6930, 11718c2ecf20Sopenharmony_ci [14] = 8662, /* 866.25 mbps */ 11728c2ecf20Sopenharmony_ci [15] = 13860, 11738c2ecf20Sopenharmony_ci [16] = 17325, 11748c2ecf20Sopenharmony_ci [17] = 20790, 11758c2ecf20Sopenharmony_ci [18] = 27720, 11768c2ecf20Sopenharmony_ci [19] = 34650, 11778c2ecf20Sopenharmony_ci [20] = 41580, 11788c2ecf20Sopenharmony_ci [21] = 45045, 11798c2ecf20Sopenharmony_ci [22] = 51975, 11808c2ecf20Sopenharmony_ci [23] = 62370, 11818c2ecf20Sopenharmony_ci [24] = 67568, /* 6756.75 mbps */ 11828c2ecf20Sopenharmony_ci /* LP-SC PHY */ 11838c2ecf20Sopenharmony_ci [25] = 6260, 11848c2ecf20Sopenharmony_ci [26] = 8340, 11858c2ecf20Sopenharmony_ci [27] = 11120, 11868c2ecf20Sopenharmony_ci [28] = 12510, 11878c2ecf20Sopenharmony_ci [29] = 16680, 11888c2ecf20Sopenharmony_ci [30] = 22240, 11898c2ecf20Sopenharmony_ci [31] = 25030, 11908c2ecf20Sopenharmony_ci }; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate))) 11938c2ecf20Sopenharmony_ci return 0; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci return __mcs2bitrate[rate->mcs]; 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic u32 cfg80211_calculate_bitrate_edmg(struct rate_info *rate) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci static const u32 __mcs2bitrate[] = { 12018c2ecf20Sopenharmony_ci /* control PHY */ 12028c2ecf20Sopenharmony_ci [0] = 275, 12038c2ecf20Sopenharmony_ci /* SC PHY */ 12048c2ecf20Sopenharmony_ci [1] = 3850, 12058c2ecf20Sopenharmony_ci [2] = 7700, 12068c2ecf20Sopenharmony_ci [3] = 9625, 12078c2ecf20Sopenharmony_ci [4] = 11550, 12088c2ecf20Sopenharmony_ci [5] = 12512, /* 1251.25 mbps */ 12098c2ecf20Sopenharmony_ci [6] = 13475, 12108c2ecf20Sopenharmony_ci [7] = 15400, 12118c2ecf20Sopenharmony_ci [8] = 19250, 12128c2ecf20Sopenharmony_ci [9] = 23100, 12138c2ecf20Sopenharmony_ci [10] = 25025, 12148c2ecf20Sopenharmony_ci [11] = 26950, 12158c2ecf20Sopenharmony_ci [12] = 30800, 12168c2ecf20Sopenharmony_ci [13] = 38500, 12178c2ecf20Sopenharmony_ci [14] = 46200, 12188c2ecf20Sopenharmony_ci [15] = 50050, 12198c2ecf20Sopenharmony_ci [16] = 53900, 12208c2ecf20Sopenharmony_ci [17] = 57750, 12218c2ecf20Sopenharmony_ci [18] = 69300, 12228c2ecf20Sopenharmony_ci [19] = 75075, 12238c2ecf20Sopenharmony_ci [20] = 80850, 12248c2ecf20Sopenharmony_ci }; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate))) 12278c2ecf20Sopenharmony_ci return 0; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci return __mcs2bitrate[rate->mcs] * rate->n_bonded_ch; 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_cistatic u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate) 12338c2ecf20Sopenharmony_ci{ 12348c2ecf20Sopenharmony_ci static const u32 base[4][10] = { 12358c2ecf20Sopenharmony_ci { 6500000, 12368c2ecf20Sopenharmony_ci 13000000, 12378c2ecf20Sopenharmony_ci 19500000, 12388c2ecf20Sopenharmony_ci 26000000, 12398c2ecf20Sopenharmony_ci 39000000, 12408c2ecf20Sopenharmony_ci 52000000, 12418c2ecf20Sopenharmony_ci 58500000, 12428c2ecf20Sopenharmony_ci 65000000, 12438c2ecf20Sopenharmony_ci 78000000, 12448c2ecf20Sopenharmony_ci /* not in the spec, but some devices use this: */ 12458c2ecf20Sopenharmony_ci 86500000, 12468c2ecf20Sopenharmony_ci }, 12478c2ecf20Sopenharmony_ci { 13500000, 12488c2ecf20Sopenharmony_ci 27000000, 12498c2ecf20Sopenharmony_ci 40500000, 12508c2ecf20Sopenharmony_ci 54000000, 12518c2ecf20Sopenharmony_ci 81000000, 12528c2ecf20Sopenharmony_ci 108000000, 12538c2ecf20Sopenharmony_ci 121500000, 12548c2ecf20Sopenharmony_ci 135000000, 12558c2ecf20Sopenharmony_ci 162000000, 12568c2ecf20Sopenharmony_ci 180000000, 12578c2ecf20Sopenharmony_ci }, 12588c2ecf20Sopenharmony_ci { 29300000, 12598c2ecf20Sopenharmony_ci 58500000, 12608c2ecf20Sopenharmony_ci 87800000, 12618c2ecf20Sopenharmony_ci 117000000, 12628c2ecf20Sopenharmony_ci 175500000, 12638c2ecf20Sopenharmony_ci 234000000, 12648c2ecf20Sopenharmony_ci 263300000, 12658c2ecf20Sopenharmony_ci 292500000, 12668c2ecf20Sopenharmony_ci 351000000, 12678c2ecf20Sopenharmony_ci 390000000, 12688c2ecf20Sopenharmony_ci }, 12698c2ecf20Sopenharmony_ci { 58500000, 12708c2ecf20Sopenharmony_ci 117000000, 12718c2ecf20Sopenharmony_ci 175500000, 12728c2ecf20Sopenharmony_ci 234000000, 12738c2ecf20Sopenharmony_ci 351000000, 12748c2ecf20Sopenharmony_ci 468000000, 12758c2ecf20Sopenharmony_ci 526500000, 12768c2ecf20Sopenharmony_ci 585000000, 12778c2ecf20Sopenharmony_ci 702000000, 12788c2ecf20Sopenharmony_ci 780000000, 12798c2ecf20Sopenharmony_ci }, 12808c2ecf20Sopenharmony_ci }; 12818c2ecf20Sopenharmony_ci u32 bitrate; 12828c2ecf20Sopenharmony_ci int idx; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci if (rate->mcs > 9) 12858c2ecf20Sopenharmony_ci goto warn; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci switch (rate->bw) { 12888c2ecf20Sopenharmony_ci case RATE_INFO_BW_160: 12898c2ecf20Sopenharmony_ci idx = 3; 12908c2ecf20Sopenharmony_ci break; 12918c2ecf20Sopenharmony_ci case RATE_INFO_BW_80: 12928c2ecf20Sopenharmony_ci idx = 2; 12938c2ecf20Sopenharmony_ci break; 12948c2ecf20Sopenharmony_ci case RATE_INFO_BW_40: 12958c2ecf20Sopenharmony_ci idx = 1; 12968c2ecf20Sopenharmony_ci break; 12978c2ecf20Sopenharmony_ci case RATE_INFO_BW_5: 12988c2ecf20Sopenharmony_ci case RATE_INFO_BW_10: 12998c2ecf20Sopenharmony_ci default: 13008c2ecf20Sopenharmony_ci goto warn; 13018c2ecf20Sopenharmony_ci case RATE_INFO_BW_20: 13028c2ecf20Sopenharmony_ci idx = 0; 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci bitrate = base[idx][rate->mcs]; 13068c2ecf20Sopenharmony_ci bitrate *= rate->nss; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) 13098c2ecf20Sopenharmony_ci bitrate = (bitrate / 9) * 10; 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci /* do NOT round down here */ 13128c2ecf20Sopenharmony_ci return (bitrate + 50000) / 100000; 13138c2ecf20Sopenharmony_ci warn: 13148c2ecf20Sopenharmony_ci WARN_ONCE(1, "invalid rate bw=%d, mcs=%d, nss=%d\n", 13158c2ecf20Sopenharmony_ci rate->bw, rate->mcs, rate->nss); 13168c2ecf20Sopenharmony_ci return 0; 13178c2ecf20Sopenharmony_ci} 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_cistatic u32 cfg80211_calculate_bitrate_he(struct rate_info *rate) 13208c2ecf20Sopenharmony_ci{ 13218c2ecf20Sopenharmony_ci#define SCALE 2048 13228c2ecf20Sopenharmony_ci u16 mcs_divisors[12] = { 13238c2ecf20Sopenharmony_ci 34133, /* 16.666666... */ 13248c2ecf20Sopenharmony_ci 17067, /* 8.333333... */ 13258c2ecf20Sopenharmony_ci 11378, /* 5.555555... */ 13268c2ecf20Sopenharmony_ci 8533, /* 4.166666... */ 13278c2ecf20Sopenharmony_ci 5689, /* 2.777777... */ 13288c2ecf20Sopenharmony_ci 4267, /* 2.083333... */ 13298c2ecf20Sopenharmony_ci 3923, /* 1.851851... */ 13308c2ecf20Sopenharmony_ci 3413, /* 1.666666... */ 13318c2ecf20Sopenharmony_ci 2844, /* 1.388888... */ 13328c2ecf20Sopenharmony_ci 2560, /* 1.250000... */ 13338c2ecf20Sopenharmony_ci 2276, /* 1.111111... */ 13348c2ecf20Sopenharmony_ci 2048, /* 1.000000... */ 13358c2ecf20Sopenharmony_ci }; 13368c2ecf20Sopenharmony_ci u32 rates_160M[3] = { 960777777, 907400000, 816666666 }; 13378c2ecf20Sopenharmony_ci u32 rates_969[3] = { 480388888, 453700000, 408333333 }; 13388c2ecf20Sopenharmony_ci u32 rates_484[3] = { 229411111, 216666666, 195000000 }; 13398c2ecf20Sopenharmony_ci u32 rates_242[3] = { 114711111, 108333333, 97500000 }; 13408c2ecf20Sopenharmony_ci u32 rates_106[3] = { 40000000, 37777777, 34000000 }; 13418c2ecf20Sopenharmony_ci u32 rates_52[3] = { 18820000, 17777777, 16000000 }; 13428c2ecf20Sopenharmony_ci u32 rates_26[3] = { 9411111, 8888888, 8000000 }; 13438c2ecf20Sopenharmony_ci u64 tmp; 13448c2ecf20Sopenharmony_ci u32 result; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(rate->mcs > 11)) 13478c2ecf20Sopenharmony_ci return 0; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(rate->he_gi > NL80211_RATE_INFO_HE_GI_3_2)) 13508c2ecf20Sopenharmony_ci return 0; 13518c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(rate->he_ru_alloc > 13528c2ecf20Sopenharmony_ci NL80211_RATE_INFO_HE_RU_ALLOC_2x996)) 13538c2ecf20Sopenharmony_ci return 0; 13548c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(rate->nss < 1 || rate->nss > 8)) 13558c2ecf20Sopenharmony_ci return 0; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci if (rate->bw == RATE_INFO_BW_160 || 13588c2ecf20Sopenharmony_ci (rate->bw == RATE_INFO_BW_HE_RU && 13598c2ecf20Sopenharmony_ci rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_2x996)) 13608c2ecf20Sopenharmony_ci result = rates_160M[rate->he_gi]; 13618c2ecf20Sopenharmony_ci else if (rate->bw == RATE_INFO_BW_80 || 13628c2ecf20Sopenharmony_ci (rate->bw == RATE_INFO_BW_HE_RU && 13638c2ecf20Sopenharmony_ci rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_996)) 13648c2ecf20Sopenharmony_ci result = rates_969[rate->he_gi]; 13658c2ecf20Sopenharmony_ci else if (rate->bw == RATE_INFO_BW_40 || 13668c2ecf20Sopenharmony_ci (rate->bw == RATE_INFO_BW_HE_RU && 13678c2ecf20Sopenharmony_ci rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_484)) 13688c2ecf20Sopenharmony_ci result = rates_484[rate->he_gi]; 13698c2ecf20Sopenharmony_ci else if (rate->bw == RATE_INFO_BW_20 || 13708c2ecf20Sopenharmony_ci (rate->bw == RATE_INFO_BW_HE_RU && 13718c2ecf20Sopenharmony_ci rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_242)) 13728c2ecf20Sopenharmony_ci result = rates_242[rate->he_gi]; 13738c2ecf20Sopenharmony_ci else if (rate->bw == RATE_INFO_BW_HE_RU && 13748c2ecf20Sopenharmony_ci rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_106) 13758c2ecf20Sopenharmony_ci result = rates_106[rate->he_gi]; 13768c2ecf20Sopenharmony_ci else if (rate->bw == RATE_INFO_BW_HE_RU && 13778c2ecf20Sopenharmony_ci rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_52) 13788c2ecf20Sopenharmony_ci result = rates_52[rate->he_gi]; 13798c2ecf20Sopenharmony_ci else if (rate->bw == RATE_INFO_BW_HE_RU && 13808c2ecf20Sopenharmony_ci rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_26) 13818c2ecf20Sopenharmony_ci result = rates_26[rate->he_gi]; 13828c2ecf20Sopenharmony_ci else { 13838c2ecf20Sopenharmony_ci WARN(1, "invalid HE MCS: bw:%d, ru:%d\n", 13848c2ecf20Sopenharmony_ci rate->bw, rate->he_ru_alloc); 13858c2ecf20Sopenharmony_ci return 0; 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci /* now scale to the appropriate MCS */ 13898c2ecf20Sopenharmony_ci tmp = result; 13908c2ecf20Sopenharmony_ci tmp *= SCALE; 13918c2ecf20Sopenharmony_ci do_div(tmp, mcs_divisors[rate->mcs]); 13928c2ecf20Sopenharmony_ci result = tmp; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci /* and take NSS, DCM into account */ 13958c2ecf20Sopenharmony_ci result = (result * rate->nss) / 8; 13968c2ecf20Sopenharmony_ci if (rate->he_dcm) 13978c2ecf20Sopenharmony_ci result /= 2; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci return result / 10000; 14008c2ecf20Sopenharmony_ci} 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ciu32 cfg80211_calculate_bitrate(struct rate_info *rate) 14038c2ecf20Sopenharmony_ci{ 14048c2ecf20Sopenharmony_ci if (rate->flags & RATE_INFO_FLAGS_MCS) 14058c2ecf20Sopenharmony_ci return cfg80211_calculate_bitrate_ht(rate); 14068c2ecf20Sopenharmony_ci if (rate->flags & RATE_INFO_FLAGS_DMG) 14078c2ecf20Sopenharmony_ci return cfg80211_calculate_bitrate_dmg(rate); 14088c2ecf20Sopenharmony_ci if (rate->flags & RATE_INFO_FLAGS_EDMG) 14098c2ecf20Sopenharmony_ci return cfg80211_calculate_bitrate_edmg(rate); 14108c2ecf20Sopenharmony_ci if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) 14118c2ecf20Sopenharmony_ci return cfg80211_calculate_bitrate_vht(rate); 14128c2ecf20Sopenharmony_ci if (rate->flags & RATE_INFO_FLAGS_HE_MCS) 14138c2ecf20Sopenharmony_ci return cfg80211_calculate_bitrate_he(rate); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci return rate->legacy; 14168c2ecf20Sopenharmony_ci} 14178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfg80211_calculate_bitrate); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ciint cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, 14208c2ecf20Sopenharmony_ci enum ieee80211_p2p_attr_id attr, 14218c2ecf20Sopenharmony_ci u8 *buf, unsigned int bufsize) 14228c2ecf20Sopenharmony_ci{ 14238c2ecf20Sopenharmony_ci u8 *out = buf; 14248c2ecf20Sopenharmony_ci u16 attr_remaining = 0; 14258c2ecf20Sopenharmony_ci bool desired_attr = false; 14268c2ecf20Sopenharmony_ci u16 desired_len = 0; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci while (len > 0) { 14298c2ecf20Sopenharmony_ci unsigned int iedatalen; 14308c2ecf20Sopenharmony_ci unsigned int copy; 14318c2ecf20Sopenharmony_ci const u8 *iedata; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci if (len < 2) 14348c2ecf20Sopenharmony_ci return -EILSEQ; 14358c2ecf20Sopenharmony_ci iedatalen = ies[1]; 14368c2ecf20Sopenharmony_ci if (iedatalen + 2 > len) 14378c2ecf20Sopenharmony_ci return -EILSEQ; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci if (ies[0] != WLAN_EID_VENDOR_SPECIFIC) 14408c2ecf20Sopenharmony_ci goto cont; 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci if (iedatalen < 4) 14438c2ecf20Sopenharmony_ci goto cont; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci iedata = ies + 2; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci /* check WFA OUI, P2P subtype */ 14488c2ecf20Sopenharmony_ci if (iedata[0] != 0x50 || iedata[1] != 0x6f || 14498c2ecf20Sopenharmony_ci iedata[2] != 0x9a || iedata[3] != 0x09) 14508c2ecf20Sopenharmony_ci goto cont; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci iedatalen -= 4; 14538c2ecf20Sopenharmony_ci iedata += 4; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci /* check attribute continuation into this IE */ 14568c2ecf20Sopenharmony_ci copy = min_t(unsigned int, attr_remaining, iedatalen); 14578c2ecf20Sopenharmony_ci if (copy && desired_attr) { 14588c2ecf20Sopenharmony_ci desired_len += copy; 14598c2ecf20Sopenharmony_ci if (out) { 14608c2ecf20Sopenharmony_ci memcpy(out, iedata, min(bufsize, copy)); 14618c2ecf20Sopenharmony_ci out += min(bufsize, copy); 14628c2ecf20Sopenharmony_ci bufsize -= min(bufsize, copy); 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci if (copy == attr_remaining) 14678c2ecf20Sopenharmony_ci return desired_len; 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci attr_remaining -= copy; 14718c2ecf20Sopenharmony_ci if (attr_remaining) 14728c2ecf20Sopenharmony_ci goto cont; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci iedatalen -= copy; 14758c2ecf20Sopenharmony_ci iedata += copy; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci while (iedatalen > 0) { 14788c2ecf20Sopenharmony_ci u16 attr_len; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci /* P2P attribute ID & size must fit */ 14818c2ecf20Sopenharmony_ci if (iedatalen < 3) 14828c2ecf20Sopenharmony_ci return -EILSEQ; 14838c2ecf20Sopenharmony_ci desired_attr = iedata[0] == attr; 14848c2ecf20Sopenharmony_ci attr_len = get_unaligned_le16(iedata + 1); 14858c2ecf20Sopenharmony_ci iedatalen -= 3; 14868c2ecf20Sopenharmony_ci iedata += 3; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci copy = min_t(unsigned int, attr_len, iedatalen); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci if (desired_attr) { 14918c2ecf20Sopenharmony_ci desired_len += copy; 14928c2ecf20Sopenharmony_ci if (out) { 14938c2ecf20Sopenharmony_ci memcpy(out, iedata, min(bufsize, copy)); 14948c2ecf20Sopenharmony_ci out += min(bufsize, copy); 14958c2ecf20Sopenharmony_ci bufsize -= min(bufsize, copy); 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci if (copy == attr_len) 14998c2ecf20Sopenharmony_ci return desired_len; 15008c2ecf20Sopenharmony_ci } 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci iedata += copy; 15038c2ecf20Sopenharmony_ci iedatalen -= copy; 15048c2ecf20Sopenharmony_ci attr_remaining = attr_len - copy; 15058c2ecf20Sopenharmony_ci } 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci cont: 15088c2ecf20Sopenharmony_ci len -= ies[1] + 2; 15098c2ecf20Sopenharmony_ci ies += ies[1] + 2; 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci if (attr_remaining && desired_attr) 15138c2ecf20Sopenharmony_ci return -EILSEQ; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci return -ENOENT; 15168c2ecf20Sopenharmony_ci} 15178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfg80211_get_p2p_attr); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_cistatic bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id, bool id_ext) 15208c2ecf20Sopenharmony_ci{ 15218c2ecf20Sopenharmony_ci int i; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci /* Make sure array values are legal */ 15248c2ecf20Sopenharmony_ci if (WARN_ON(ids[n_ids - 1] == WLAN_EID_EXTENSION)) 15258c2ecf20Sopenharmony_ci return false; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci i = 0; 15288c2ecf20Sopenharmony_ci while (i < n_ids) { 15298c2ecf20Sopenharmony_ci if (ids[i] == WLAN_EID_EXTENSION) { 15308c2ecf20Sopenharmony_ci if (id_ext && (ids[i + 1] == id)) 15318c2ecf20Sopenharmony_ci return true; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci i += 2; 15348c2ecf20Sopenharmony_ci continue; 15358c2ecf20Sopenharmony_ci } 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci if (ids[i] == id && !id_ext) 15388c2ecf20Sopenharmony_ci return true; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci i++; 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci return false; 15438c2ecf20Sopenharmony_ci} 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_cistatic size_t skip_ie(const u8 *ies, size_t ielen, size_t pos) 15468c2ecf20Sopenharmony_ci{ 15478c2ecf20Sopenharmony_ci /* we assume a validly formed IEs buffer */ 15488c2ecf20Sopenharmony_ci u8 len = ies[pos + 1]; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci pos += 2 + len; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci /* the IE itself must have 255 bytes for fragments to follow */ 15538c2ecf20Sopenharmony_ci if (len < 255) 15548c2ecf20Sopenharmony_ci return pos; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci while (pos < ielen && ies[pos] == WLAN_EID_FRAGMENT) { 15578c2ecf20Sopenharmony_ci len = ies[pos + 1]; 15588c2ecf20Sopenharmony_ci pos += 2 + len; 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci return pos; 15628c2ecf20Sopenharmony_ci} 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_cisize_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen, 15658c2ecf20Sopenharmony_ci const u8 *ids, int n_ids, 15668c2ecf20Sopenharmony_ci const u8 *after_ric, int n_after_ric, 15678c2ecf20Sopenharmony_ci size_t offset) 15688c2ecf20Sopenharmony_ci{ 15698c2ecf20Sopenharmony_ci size_t pos = offset; 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci while (pos < ielen) { 15728c2ecf20Sopenharmony_ci u8 ext = 0; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci if (ies[pos] == WLAN_EID_EXTENSION) 15758c2ecf20Sopenharmony_ci ext = 2; 15768c2ecf20Sopenharmony_ci if ((pos + ext) >= ielen) 15778c2ecf20Sopenharmony_ci break; 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci if (!ieee80211_id_in_list(ids, n_ids, ies[pos + ext], 15808c2ecf20Sopenharmony_ci ies[pos] == WLAN_EID_EXTENSION)) 15818c2ecf20Sopenharmony_ci break; 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) { 15848c2ecf20Sopenharmony_ci pos = skip_ie(ies, ielen, pos); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci while (pos < ielen) { 15878c2ecf20Sopenharmony_ci if (ies[pos] == WLAN_EID_EXTENSION) 15888c2ecf20Sopenharmony_ci ext = 2; 15898c2ecf20Sopenharmony_ci else 15908c2ecf20Sopenharmony_ci ext = 0; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci if ((pos + ext) >= ielen) 15938c2ecf20Sopenharmony_ci break; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci if (!ieee80211_id_in_list(after_ric, 15968c2ecf20Sopenharmony_ci n_after_ric, 15978c2ecf20Sopenharmony_ci ies[pos + ext], 15988c2ecf20Sopenharmony_ci ext == 2)) 15998c2ecf20Sopenharmony_ci pos = skip_ie(ies, ielen, pos); 16008c2ecf20Sopenharmony_ci else 16018c2ecf20Sopenharmony_ci break; 16028c2ecf20Sopenharmony_ci } 16038c2ecf20Sopenharmony_ci } else { 16048c2ecf20Sopenharmony_ci pos = skip_ie(ies, ielen, pos); 16058c2ecf20Sopenharmony_ci } 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci return pos; 16098c2ecf20Sopenharmony_ci} 16108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_ie_split_ric); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_cibool ieee80211_operating_class_to_band(u8 operating_class, 16138c2ecf20Sopenharmony_ci enum nl80211_band *band) 16148c2ecf20Sopenharmony_ci{ 16158c2ecf20Sopenharmony_ci switch (operating_class) { 16168c2ecf20Sopenharmony_ci case 112: 16178c2ecf20Sopenharmony_ci case 115 ... 127: 16188c2ecf20Sopenharmony_ci case 128 ... 130: 16198c2ecf20Sopenharmony_ci *band = NL80211_BAND_5GHZ; 16208c2ecf20Sopenharmony_ci return true; 16218c2ecf20Sopenharmony_ci case 131 ... 135: 16228c2ecf20Sopenharmony_ci *band = NL80211_BAND_6GHZ; 16238c2ecf20Sopenharmony_ci return true; 16248c2ecf20Sopenharmony_ci case 81: 16258c2ecf20Sopenharmony_ci case 82: 16268c2ecf20Sopenharmony_ci case 83: 16278c2ecf20Sopenharmony_ci case 84: 16288c2ecf20Sopenharmony_ci *band = NL80211_BAND_2GHZ; 16298c2ecf20Sopenharmony_ci return true; 16308c2ecf20Sopenharmony_ci case 180: 16318c2ecf20Sopenharmony_ci *band = NL80211_BAND_60GHZ; 16328c2ecf20Sopenharmony_ci return true; 16338c2ecf20Sopenharmony_ci } 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci return false; 16368c2ecf20Sopenharmony_ci} 16378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_operating_class_to_band); 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_cibool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef, 16408c2ecf20Sopenharmony_ci u8 *op_class) 16418c2ecf20Sopenharmony_ci{ 16428c2ecf20Sopenharmony_ci u8 vht_opclass; 16438c2ecf20Sopenharmony_ci u32 freq = chandef->center_freq1; 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci if (freq >= 2412 && freq <= 2472) { 16468c2ecf20Sopenharmony_ci if (chandef->width > NL80211_CHAN_WIDTH_40) 16478c2ecf20Sopenharmony_ci return false; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci /* 2.407 GHz, channels 1..13 */ 16508c2ecf20Sopenharmony_ci if (chandef->width == NL80211_CHAN_WIDTH_40) { 16518c2ecf20Sopenharmony_ci if (freq > chandef->chan->center_freq) 16528c2ecf20Sopenharmony_ci *op_class = 83; /* HT40+ */ 16538c2ecf20Sopenharmony_ci else 16548c2ecf20Sopenharmony_ci *op_class = 84; /* HT40- */ 16558c2ecf20Sopenharmony_ci } else { 16568c2ecf20Sopenharmony_ci *op_class = 81; 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci return true; 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci if (freq == 2484) { 16638c2ecf20Sopenharmony_ci /* channel 14 is only for IEEE 802.11b */ 16648c2ecf20Sopenharmony_ci if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT) 16658c2ecf20Sopenharmony_ci return false; 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci *op_class = 82; /* channel 14 */ 16688c2ecf20Sopenharmony_ci return true; 16698c2ecf20Sopenharmony_ci } 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci switch (chandef->width) { 16728c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_80: 16738c2ecf20Sopenharmony_ci vht_opclass = 128; 16748c2ecf20Sopenharmony_ci break; 16758c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_160: 16768c2ecf20Sopenharmony_ci vht_opclass = 129; 16778c2ecf20Sopenharmony_ci break; 16788c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_80P80: 16798c2ecf20Sopenharmony_ci vht_opclass = 130; 16808c2ecf20Sopenharmony_ci break; 16818c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_10: 16828c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_5: 16838c2ecf20Sopenharmony_ci return false; /* unsupported for now */ 16848c2ecf20Sopenharmony_ci default: 16858c2ecf20Sopenharmony_ci vht_opclass = 0; 16868c2ecf20Sopenharmony_ci break; 16878c2ecf20Sopenharmony_ci } 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci /* 5 GHz, channels 36..48 */ 16908c2ecf20Sopenharmony_ci if (freq >= 5180 && freq <= 5240) { 16918c2ecf20Sopenharmony_ci if (vht_opclass) { 16928c2ecf20Sopenharmony_ci *op_class = vht_opclass; 16938c2ecf20Sopenharmony_ci } else if (chandef->width == NL80211_CHAN_WIDTH_40) { 16948c2ecf20Sopenharmony_ci if (freq > chandef->chan->center_freq) 16958c2ecf20Sopenharmony_ci *op_class = 116; 16968c2ecf20Sopenharmony_ci else 16978c2ecf20Sopenharmony_ci *op_class = 117; 16988c2ecf20Sopenharmony_ci } else { 16998c2ecf20Sopenharmony_ci *op_class = 115; 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci return true; 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci /* 5 GHz, channels 52..64 */ 17068c2ecf20Sopenharmony_ci if (freq >= 5260 && freq <= 5320) { 17078c2ecf20Sopenharmony_ci if (vht_opclass) { 17088c2ecf20Sopenharmony_ci *op_class = vht_opclass; 17098c2ecf20Sopenharmony_ci } else if (chandef->width == NL80211_CHAN_WIDTH_40) { 17108c2ecf20Sopenharmony_ci if (freq > chandef->chan->center_freq) 17118c2ecf20Sopenharmony_ci *op_class = 119; 17128c2ecf20Sopenharmony_ci else 17138c2ecf20Sopenharmony_ci *op_class = 120; 17148c2ecf20Sopenharmony_ci } else { 17158c2ecf20Sopenharmony_ci *op_class = 118; 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci return true; 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci /* 5 GHz, channels 100..144 */ 17228c2ecf20Sopenharmony_ci if (freq >= 5500 && freq <= 5720) { 17238c2ecf20Sopenharmony_ci if (vht_opclass) { 17248c2ecf20Sopenharmony_ci *op_class = vht_opclass; 17258c2ecf20Sopenharmony_ci } else if (chandef->width == NL80211_CHAN_WIDTH_40) { 17268c2ecf20Sopenharmony_ci if (freq > chandef->chan->center_freq) 17278c2ecf20Sopenharmony_ci *op_class = 122; 17288c2ecf20Sopenharmony_ci else 17298c2ecf20Sopenharmony_ci *op_class = 123; 17308c2ecf20Sopenharmony_ci } else { 17318c2ecf20Sopenharmony_ci *op_class = 121; 17328c2ecf20Sopenharmony_ci } 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci return true; 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci /* 5 GHz, channels 149..169 */ 17388c2ecf20Sopenharmony_ci if (freq >= 5745 && freq <= 5845) { 17398c2ecf20Sopenharmony_ci if (vht_opclass) { 17408c2ecf20Sopenharmony_ci *op_class = vht_opclass; 17418c2ecf20Sopenharmony_ci } else if (chandef->width == NL80211_CHAN_WIDTH_40) { 17428c2ecf20Sopenharmony_ci if (freq > chandef->chan->center_freq) 17438c2ecf20Sopenharmony_ci *op_class = 126; 17448c2ecf20Sopenharmony_ci else 17458c2ecf20Sopenharmony_ci *op_class = 127; 17468c2ecf20Sopenharmony_ci } else if (freq <= 5805) { 17478c2ecf20Sopenharmony_ci *op_class = 124; 17488c2ecf20Sopenharmony_ci } else { 17498c2ecf20Sopenharmony_ci *op_class = 125; 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci return true; 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci /* 56.16 GHz, channel 1..4 */ 17568c2ecf20Sopenharmony_ci if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) { 17578c2ecf20Sopenharmony_ci if (chandef->width >= NL80211_CHAN_WIDTH_40) 17588c2ecf20Sopenharmony_ci return false; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci *op_class = 180; 17618c2ecf20Sopenharmony_ci return true; 17628c2ecf20Sopenharmony_ci } 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci /* not supported yet */ 17658c2ecf20Sopenharmony_ci return false; 17668c2ecf20Sopenharmony_ci} 17678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_chandef_to_operating_class); 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_cistatic void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int, 17708c2ecf20Sopenharmony_ci u32 *beacon_int_gcd, 17718c2ecf20Sopenharmony_ci bool *beacon_int_different) 17728c2ecf20Sopenharmony_ci{ 17738c2ecf20Sopenharmony_ci struct wireless_dev *wdev; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci *beacon_int_gcd = 0; 17768c2ecf20Sopenharmony_ci *beacon_int_different = false; 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci list_for_each_entry(wdev, &wiphy->wdev_list, list) { 17798c2ecf20Sopenharmony_ci if (!wdev->beacon_interval) 17808c2ecf20Sopenharmony_ci continue; 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci if (!*beacon_int_gcd) { 17838c2ecf20Sopenharmony_ci *beacon_int_gcd = wdev->beacon_interval; 17848c2ecf20Sopenharmony_ci continue; 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci if (wdev->beacon_interval == *beacon_int_gcd) 17888c2ecf20Sopenharmony_ci continue; 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci *beacon_int_different = true; 17918c2ecf20Sopenharmony_ci *beacon_int_gcd = gcd(*beacon_int_gcd, wdev->beacon_interval); 17928c2ecf20Sopenharmony_ci } 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci if (new_beacon_int && *beacon_int_gcd != new_beacon_int) { 17958c2ecf20Sopenharmony_ci if (*beacon_int_gcd) 17968c2ecf20Sopenharmony_ci *beacon_int_different = true; 17978c2ecf20Sopenharmony_ci *beacon_int_gcd = gcd(*beacon_int_gcd, new_beacon_int); 17988c2ecf20Sopenharmony_ci } 17998c2ecf20Sopenharmony_ci} 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ciint cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, 18028c2ecf20Sopenharmony_ci enum nl80211_iftype iftype, u32 beacon_int) 18038c2ecf20Sopenharmony_ci{ 18048c2ecf20Sopenharmony_ci /* 18058c2ecf20Sopenharmony_ci * This is just a basic pre-condition check; if interface combinations 18068c2ecf20Sopenharmony_ci * are possible the driver must already be checking those with a call 18078c2ecf20Sopenharmony_ci * to cfg80211_check_combinations(), in which case we'll validate more 18088c2ecf20Sopenharmony_ci * through the cfg80211_calculate_bi_data() call and code in 18098c2ecf20Sopenharmony_ci * cfg80211_iter_combinations(). 18108c2ecf20Sopenharmony_ci */ 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci if (beacon_int < 10 || beacon_int > 10000) 18138c2ecf20Sopenharmony_ci return -EINVAL; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci return 0; 18168c2ecf20Sopenharmony_ci} 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ciint cfg80211_iter_combinations(struct wiphy *wiphy, 18198c2ecf20Sopenharmony_ci struct iface_combination_params *params, 18208c2ecf20Sopenharmony_ci void (*iter)(const struct ieee80211_iface_combination *c, 18218c2ecf20Sopenharmony_ci void *data), 18228c2ecf20Sopenharmony_ci void *data) 18238c2ecf20Sopenharmony_ci{ 18248c2ecf20Sopenharmony_ci const struct ieee80211_regdomain *regdom; 18258c2ecf20Sopenharmony_ci enum nl80211_dfs_regions region = 0; 18268c2ecf20Sopenharmony_ci int i, j, iftype; 18278c2ecf20Sopenharmony_ci int num_interfaces = 0; 18288c2ecf20Sopenharmony_ci u32 used_iftypes = 0; 18298c2ecf20Sopenharmony_ci u32 beacon_int_gcd; 18308c2ecf20Sopenharmony_ci bool beacon_int_different; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci /* 18338c2ecf20Sopenharmony_ci * This is a bit strange, since the iteration used to rely only on 18348c2ecf20Sopenharmony_ci * the data given by the driver, but here it now relies on context, 18358c2ecf20Sopenharmony_ci * in form of the currently operating interfaces. 18368c2ecf20Sopenharmony_ci * This is OK for all current users, and saves us from having to 18378c2ecf20Sopenharmony_ci * push the GCD calculations into all the drivers. 18388c2ecf20Sopenharmony_ci * In the future, this should probably rely more on data that's in 18398c2ecf20Sopenharmony_ci * cfg80211 already - the only thing not would appear to be any new 18408c2ecf20Sopenharmony_ci * interfaces (while being brought up) and channel/radar data. 18418c2ecf20Sopenharmony_ci */ 18428c2ecf20Sopenharmony_ci cfg80211_calculate_bi_data(wiphy, params->new_beacon_int, 18438c2ecf20Sopenharmony_ci &beacon_int_gcd, &beacon_int_different); 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci if (params->radar_detect) { 18468c2ecf20Sopenharmony_ci rcu_read_lock(); 18478c2ecf20Sopenharmony_ci regdom = rcu_dereference(cfg80211_regdomain); 18488c2ecf20Sopenharmony_ci if (regdom) 18498c2ecf20Sopenharmony_ci region = regdom->dfs_region; 18508c2ecf20Sopenharmony_ci rcu_read_unlock(); 18518c2ecf20Sopenharmony_ci } 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { 18548c2ecf20Sopenharmony_ci num_interfaces += params->iftype_num[iftype]; 18558c2ecf20Sopenharmony_ci if (params->iftype_num[iftype] > 0 && 18568c2ecf20Sopenharmony_ci !cfg80211_iftype_allowed(wiphy, iftype, 0, 1)) 18578c2ecf20Sopenharmony_ci used_iftypes |= BIT(iftype); 18588c2ecf20Sopenharmony_ci } 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci for (i = 0; i < wiphy->n_iface_combinations; i++) { 18618c2ecf20Sopenharmony_ci const struct ieee80211_iface_combination *c; 18628c2ecf20Sopenharmony_ci struct ieee80211_iface_limit *limits; 18638c2ecf20Sopenharmony_ci u32 all_iftypes = 0; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci c = &wiphy->iface_combinations[i]; 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci if (num_interfaces > c->max_interfaces) 18688c2ecf20Sopenharmony_ci continue; 18698c2ecf20Sopenharmony_ci if (params->num_different_channels > c->num_different_channels) 18708c2ecf20Sopenharmony_ci continue; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, 18738c2ecf20Sopenharmony_ci GFP_KERNEL); 18748c2ecf20Sopenharmony_ci if (!limits) 18758c2ecf20Sopenharmony_ci return -ENOMEM; 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { 18788c2ecf20Sopenharmony_ci if (cfg80211_iftype_allowed(wiphy, iftype, 0, 1)) 18798c2ecf20Sopenharmony_ci continue; 18808c2ecf20Sopenharmony_ci for (j = 0; j < c->n_limits; j++) { 18818c2ecf20Sopenharmony_ci all_iftypes |= limits[j].types; 18828c2ecf20Sopenharmony_ci if (!(limits[j].types & BIT(iftype))) 18838c2ecf20Sopenharmony_ci continue; 18848c2ecf20Sopenharmony_ci if (limits[j].max < params->iftype_num[iftype]) 18858c2ecf20Sopenharmony_ci goto cont; 18868c2ecf20Sopenharmony_ci limits[j].max -= params->iftype_num[iftype]; 18878c2ecf20Sopenharmony_ci } 18888c2ecf20Sopenharmony_ci } 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci if (params->radar_detect != 18918c2ecf20Sopenharmony_ci (c->radar_detect_widths & params->radar_detect)) 18928c2ecf20Sopenharmony_ci goto cont; 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci if (params->radar_detect && c->radar_detect_regions && 18958c2ecf20Sopenharmony_ci !(c->radar_detect_regions & BIT(region))) 18968c2ecf20Sopenharmony_ci goto cont; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci /* Finally check that all iftypes that we're currently 18998c2ecf20Sopenharmony_ci * using are actually part of this combination. If they 19008c2ecf20Sopenharmony_ci * aren't then we can't use this combination and have 19018c2ecf20Sopenharmony_ci * to continue to the next. 19028c2ecf20Sopenharmony_ci */ 19038c2ecf20Sopenharmony_ci if ((all_iftypes & used_iftypes) != used_iftypes) 19048c2ecf20Sopenharmony_ci goto cont; 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci if (beacon_int_gcd) { 19078c2ecf20Sopenharmony_ci if (c->beacon_int_min_gcd && 19088c2ecf20Sopenharmony_ci beacon_int_gcd < c->beacon_int_min_gcd) 19098c2ecf20Sopenharmony_ci goto cont; 19108c2ecf20Sopenharmony_ci if (!c->beacon_int_min_gcd && beacon_int_different) 19118c2ecf20Sopenharmony_ci goto cont; 19128c2ecf20Sopenharmony_ci } 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci /* This combination covered all interface types and 19158c2ecf20Sopenharmony_ci * supported the requested numbers, so we're good. 19168c2ecf20Sopenharmony_ci */ 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci (*iter)(c, data); 19198c2ecf20Sopenharmony_ci cont: 19208c2ecf20Sopenharmony_ci kfree(limits); 19218c2ecf20Sopenharmony_ci } 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci return 0; 19248c2ecf20Sopenharmony_ci} 19258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfg80211_iter_combinations); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_cistatic void 19288c2ecf20Sopenharmony_cicfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c, 19298c2ecf20Sopenharmony_ci void *data) 19308c2ecf20Sopenharmony_ci{ 19318c2ecf20Sopenharmony_ci int *num = data; 19328c2ecf20Sopenharmony_ci (*num)++; 19338c2ecf20Sopenharmony_ci} 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ciint cfg80211_check_combinations(struct wiphy *wiphy, 19368c2ecf20Sopenharmony_ci struct iface_combination_params *params) 19378c2ecf20Sopenharmony_ci{ 19388c2ecf20Sopenharmony_ci int err, num = 0; 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci err = cfg80211_iter_combinations(wiphy, params, 19418c2ecf20Sopenharmony_ci cfg80211_iter_sum_ifcombs, &num); 19428c2ecf20Sopenharmony_ci if (err) 19438c2ecf20Sopenharmony_ci return err; 19448c2ecf20Sopenharmony_ci if (num == 0) 19458c2ecf20Sopenharmony_ci return -EBUSY; 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci return 0; 19488c2ecf20Sopenharmony_ci} 19498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfg80211_check_combinations); 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ciint ieee80211_get_ratemask(struct ieee80211_supported_band *sband, 19528c2ecf20Sopenharmony_ci const u8 *rates, unsigned int n_rates, 19538c2ecf20Sopenharmony_ci u32 *mask) 19548c2ecf20Sopenharmony_ci{ 19558c2ecf20Sopenharmony_ci int i, j; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci if (!sband) 19588c2ecf20Sopenharmony_ci return -EINVAL; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci if (n_rates == 0 || n_rates > NL80211_MAX_SUPP_RATES) 19618c2ecf20Sopenharmony_ci return -EINVAL; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci *mask = 0; 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci for (i = 0; i < n_rates; i++) { 19668c2ecf20Sopenharmony_ci int rate = (rates[i] & 0x7f) * 5; 19678c2ecf20Sopenharmony_ci bool found = false; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci for (j = 0; j < sband->n_bitrates; j++) { 19708c2ecf20Sopenharmony_ci if (sband->bitrates[j].bitrate == rate) { 19718c2ecf20Sopenharmony_ci found = true; 19728c2ecf20Sopenharmony_ci *mask |= BIT(j); 19738c2ecf20Sopenharmony_ci break; 19748c2ecf20Sopenharmony_ci } 19758c2ecf20Sopenharmony_ci } 19768c2ecf20Sopenharmony_ci if (!found) 19778c2ecf20Sopenharmony_ci return -EINVAL; 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci /* 19818c2ecf20Sopenharmony_ci * mask must have at least one bit set here since we 19828c2ecf20Sopenharmony_ci * didn't accept a 0-length rates array nor allowed 19838c2ecf20Sopenharmony_ci * entries in the array that didn't exist 19848c2ecf20Sopenharmony_ci */ 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci return 0; 19878c2ecf20Sopenharmony_ci} 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ciunsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy) 19908c2ecf20Sopenharmony_ci{ 19918c2ecf20Sopenharmony_ci enum nl80211_band band; 19928c2ecf20Sopenharmony_ci unsigned int n_channels = 0; 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) 19958c2ecf20Sopenharmony_ci if (wiphy->bands[band]) 19968c2ecf20Sopenharmony_ci n_channels += wiphy->bands[band]->n_channels; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci return n_channels; 19998c2ecf20Sopenharmony_ci} 20008c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_get_num_supported_channels); 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ciint cfg80211_get_station(struct net_device *dev, const u8 *mac_addr, 20038c2ecf20Sopenharmony_ci struct station_info *sinfo) 20048c2ecf20Sopenharmony_ci{ 20058c2ecf20Sopenharmony_ci struct cfg80211_registered_device *rdev; 20068c2ecf20Sopenharmony_ci struct wireless_dev *wdev; 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci wdev = dev->ieee80211_ptr; 20098c2ecf20Sopenharmony_ci if (!wdev) 20108c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci rdev = wiphy_to_rdev(wdev->wiphy); 20138c2ecf20Sopenharmony_ci if (!rdev->ops->get_station) 20148c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci memset(sinfo, 0, sizeof(*sinfo)); 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci return rdev_get_station(rdev, dev, mac_addr, sinfo); 20198c2ecf20Sopenharmony_ci} 20208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfg80211_get_station); 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_civoid cfg80211_free_nan_func(struct cfg80211_nan_func *f) 20238c2ecf20Sopenharmony_ci{ 20248c2ecf20Sopenharmony_ci int i; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci if (!f) 20278c2ecf20Sopenharmony_ci return; 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci kfree(f->serv_spec_info); 20308c2ecf20Sopenharmony_ci kfree(f->srf_bf); 20318c2ecf20Sopenharmony_ci kfree(f->srf_macs); 20328c2ecf20Sopenharmony_ci for (i = 0; i < f->num_rx_filters; i++) 20338c2ecf20Sopenharmony_ci kfree(f->rx_filters[i].filter); 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci for (i = 0; i < f->num_tx_filters; i++) 20368c2ecf20Sopenharmony_ci kfree(f->tx_filters[i].filter); 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci kfree(f->rx_filters); 20398c2ecf20Sopenharmony_ci kfree(f->tx_filters); 20408c2ecf20Sopenharmony_ci kfree(f); 20418c2ecf20Sopenharmony_ci} 20428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfg80211_free_nan_func); 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_cibool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range, 20458c2ecf20Sopenharmony_ci u32 center_freq_khz, u32 bw_khz) 20468c2ecf20Sopenharmony_ci{ 20478c2ecf20Sopenharmony_ci u32 start_freq_khz, end_freq_khz; 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci start_freq_khz = center_freq_khz - (bw_khz / 2); 20508c2ecf20Sopenharmony_ci end_freq_khz = center_freq_khz + (bw_khz / 2); 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci if (start_freq_khz >= freq_range->start_freq_khz && 20538c2ecf20Sopenharmony_ci end_freq_khz <= freq_range->end_freq_khz) 20548c2ecf20Sopenharmony_ci return true; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci return false; 20578c2ecf20Sopenharmony_ci} 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ciint cfg80211_sinfo_alloc_tid_stats(struct station_info *sinfo, gfp_t gfp) 20608c2ecf20Sopenharmony_ci{ 20618c2ecf20Sopenharmony_ci sinfo->pertid = kcalloc(IEEE80211_NUM_TIDS + 1, 20628c2ecf20Sopenharmony_ci sizeof(*(sinfo->pertid)), 20638c2ecf20Sopenharmony_ci gfp); 20648c2ecf20Sopenharmony_ci if (!sinfo->pertid) 20658c2ecf20Sopenharmony_ci return -ENOMEM; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci return 0; 20688c2ecf20Sopenharmony_ci} 20698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfg80211_sinfo_alloc_tid_stats); 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ 20728c2ecf20Sopenharmony_ci/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ 20738c2ecf20Sopenharmony_ciconst unsigned char rfc1042_header[] __aligned(2) = 20748c2ecf20Sopenharmony_ci { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; 20758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rfc1042_header); 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ 20788c2ecf20Sopenharmony_ciconst unsigned char bridge_tunnel_header[] __aligned(2) = 20798c2ecf20Sopenharmony_ci { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; 20808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bridge_tunnel_header); 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ 20838c2ecf20Sopenharmony_cistruct iapp_layer2_update { 20848c2ecf20Sopenharmony_ci u8 da[ETH_ALEN]; /* broadcast */ 20858c2ecf20Sopenharmony_ci u8 sa[ETH_ALEN]; /* STA addr */ 20868c2ecf20Sopenharmony_ci __be16 len; /* 6 */ 20878c2ecf20Sopenharmony_ci u8 dsap; /* 0 */ 20888c2ecf20Sopenharmony_ci u8 ssap; /* 0 */ 20898c2ecf20Sopenharmony_ci u8 control; 20908c2ecf20Sopenharmony_ci u8 xid_info[3]; 20918c2ecf20Sopenharmony_ci} __packed; 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_civoid cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr) 20948c2ecf20Sopenharmony_ci{ 20958c2ecf20Sopenharmony_ci struct iapp_layer2_update *msg; 20968c2ecf20Sopenharmony_ci struct sk_buff *skb; 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci /* Send Level 2 Update Frame to update forwarding tables in layer 2 20998c2ecf20Sopenharmony_ci * bridge devices */ 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci skb = dev_alloc_skb(sizeof(*msg)); 21028c2ecf20Sopenharmony_ci if (!skb) 21038c2ecf20Sopenharmony_ci return; 21048c2ecf20Sopenharmony_ci msg = skb_put(skb, sizeof(*msg)); 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) 21078c2ecf20Sopenharmony_ci * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci eth_broadcast_addr(msg->da); 21108c2ecf20Sopenharmony_ci ether_addr_copy(msg->sa, addr); 21118c2ecf20Sopenharmony_ci msg->len = htons(6); 21128c2ecf20Sopenharmony_ci msg->dsap = 0; 21138c2ecf20Sopenharmony_ci msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */ 21148c2ecf20Sopenharmony_ci msg->control = 0xaf; /* XID response lsb.1111F101. 21158c2ecf20Sopenharmony_ci * F=0 (no poll command; unsolicited frame) */ 21168c2ecf20Sopenharmony_ci msg->xid_info[0] = 0x81; /* XID format identifier */ 21178c2ecf20Sopenharmony_ci msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ 21188c2ecf20Sopenharmony_ci msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci skb->dev = dev; 21218c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 21228c2ecf20Sopenharmony_ci memset(skb->cb, 0, sizeof(skb->cb)); 21238c2ecf20Sopenharmony_ci netif_rx_ni(skb); 21248c2ecf20Sopenharmony_ci} 21258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfg80211_send_layer2_update); 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ciint ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap, 21288c2ecf20Sopenharmony_ci enum ieee80211_vht_chanwidth bw, 21298c2ecf20Sopenharmony_ci int mcs, bool ext_nss_bw_capable, 21308c2ecf20Sopenharmony_ci unsigned int max_vht_nss) 21318c2ecf20Sopenharmony_ci{ 21328c2ecf20Sopenharmony_ci u16 map = le16_to_cpu(cap->supp_mcs.rx_mcs_map); 21338c2ecf20Sopenharmony_ci int ext_nss_bw; 21348c2ecf20Sopenharmony_ci int supp_width; 21358c2ecf20Sopenharmony_ci int i, mcs_encoding; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci if (map == 0xffff) 21388c2ecf20Sopenharmony_ci return 0; 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci if (WARN_ON(mcs > 9 || max_vht_nss > 8)) 21418c2ecf20Sopenharmony_ci return 0; 21428c2ecf20Sopenharmony_ci if (mcs <= 7) 21438c2ecf20Sopenharmony_ci mcs_encoding = 0; 21448c2ecf20Sopenharmony_ci else if (mcs == 8) 21458c2ecf20Sopenharmony_ci mcs_encoding = 1; 21468c2ecf20Sopenharmony_ci else 21478c2ecf20Sopenharmony_ci mcs_encoding = 2; 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci if (!max_vht_nss) { 21508c2ecf20Sopenharmony_ci /* find max_vht_nss for the given MCS */ 21518c2ecf20Sopenharmony_ci for (i = 7; i >= 0; i--) { 21528c2ecf20Sopenharmony_ci int supp = (map >> (2 * i)) & 3; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci if (supp == 3) 21558c2ecf20Sopenharmony_ci continue; 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci if (supp >= mcs_encoding) { 21588c2ecf20Sopenharmony_ci max_vht_nss = i + 1; 21598c2ecf20Sopenharmony_ci break; 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci } 21628c2ecf20Sopenharmony_ci } 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci if (!(cap->supp_mcs.tx_mcs_map & 21658c2ecf20Sopenharmony_ci cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE))) 21668c2ecf20Sopenharmony_ci return max_vht_nss; 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci ext_nss_bw = le32_get_bits(cap->vht_cap_info, 21698c2ecf20Sopenharmony_ci IEEE80211_VHT_CAP_EXT_NSS_BW_MASK); 21708c2ecf20Sopenharmony_ci supp_width = le32_get_bits(cap->vht_cap_info, 21718c2ecf20Sopenharmony_ci IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK); 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci /* if not capable, treat ext_nss_bw as 0 */ 21748c2ecf20Sopenharmony_ci if (!ext_nss_bw_capable) 21758c2ecf20Sopenharmony_ci ext_nss_bw = 0; 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci /* This is invalid */ 21788c2ecf20Sopenharmony_ci if (supp_width == 3) 21798c2ecf20Sopenharmony_ci return 0; 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci /* This is an invalid combination so pretend nothing is supported */ 21828c2ecf20Sopenharmony_ci if (supp_width == 2 && (ext_nss_bw == 1 || ext_nss_bw == 2)) 21838c2ecf20Sopenharmony_ci return 0; 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci /* 21868c2ecf20Sopenharmony_ci * Cover all the special cases according to IEEE 802.11-2016 21878c2ecf20Sopenharmony_ci * Table 9-250. All other cases are either factor of 1 or not 21888c2ecf20Sopenharmony_ci * valid/supported. 21898c2ecf20Sopenharmony_ci */ 21908c2ecf20Sopenharmony_ci switch (bw) { 21918c2ecf20Sopenharmony_ci case IEEE80211_VHT_CHANWIDTH_USE_HT: 21928c2ecf20Sopenharmony_ci case IEEE80211_VHT_CHANWIDTH_80MHZ: 21938c2ecf20Sopenharmony_ci if ((supp_width == 1 || supp_width == 2) && 21948c2ecf20Sopenharmony_ci ext_nss_bw == 3) 21958c2ecf20Sopenharmony_ci return 2 * max_vht_nss; 21968c2ecf20Sopenharmony_ci break; 21978c2ecf20Sopenharmony_ci case IEEE80211_VHT_CHANWIDTH_160MHZ: 21988c2ecf20Sopenharmony_ci if (supp_width == 0 && 21998c2ecf20Sopenharmony_ci (ext_nss_bw == 1 || ext_nss_bw == 2)) 22008c2ecf20Sopenharmony_ci return max_vht_nss / 2; 22018c2ecf20Sopenharmony_ci if (supp_width == 0 && 22028c2ecf20Sopenharmony_ci ext_nss_bw == 3) 22038c2ecf20Sopenharmony_ci return (3 * max_vht_nss) / 4; 22048c2ecf20Sopenharmony_ci if (supp_width == 1 && 22058c2ecf20Sopenharmony_ci ext_nss_bw == 3) 22068c2ecf20Sopenharmony_ci return 2 * max_vht_nss; 22078c2ecf20Sopenharmony_ci break; 22088c2ecf20Sopenharmony_ci case IEEE80211_VHT_CHANWIDTH_80P80MHZ: 22098c2ecf20Sopenharmony_ci if (supp_width == 0 && ext_nss_bw == 1) 22108c2ecf20Sopenharmony_ci return 0; /* not possible */ 22118c2ecf20Sopenharmony_ci if (supp_width == 0 && 22128c2ecf20Sopenharmony_ci ext_nss_bw == 2) 22138c2ecf20Sopenharmony_ci return max_vht_nss / 2; 22148c2ecf20Sopenharmony_ci if (supp_width == 0 && 22158c2ecf20Sopenharmony_ci ext_nss_bw == 3) 22168c2ecf20Sopenharmony_ci return (3 * max_vht_nss) / 4; 22178c2ecf20Sopenharmony_ci if (supp_width == 1 && 22188c2ecf20Sopenharmony_ci ext_nss_bw == 0) 22198c2ecf20Sopenharmony_ci return 0; /* not possible */ 22208c2ecf20Sopenharmony_ci if (supp_width == 1 && 22218c2ecf20Sopenharmony_ci ext_nss_bw == 1) 22228c2ecf20Sopenharmony_ci return max_vht_nss / 2; 22238c2ecf20Sopenharmony_ci if (supp_width == 1 && 22248c2ecf20Sopenharmony_ci ext_nss_bw == 2) 22258c2ecf20Sopenharmony_ci return (3 * max_vht_nss) / 4; 22268c2ecf20Sopenharmony_ci break; 22278c2ecf20Sopenharmony_ci } 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci /* not covered or invalid combination received */ 22308c2ecf20Sopenharmony_ci return max_vht_nss; 22318c2ecf20Sopenharmony_ci} 22328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_get_vht_max_nss); 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_cibool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype, 22358c2ecf20Sopenharmony_ci bool is_4addr, u8 check_swif) 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci{ 22388c2ecf20Sopenharmony_ci bool is_vlan = iftype == NL80211_IFTYPE_AP_VLAN; 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci switch (check_swif) { 22418c2ecf20Sopenharmony_ci case 0: 22428c2ecf20Sopenharmony_ci if (is_vlan && is_4addr) 22438c2ecf20Sopenharmony_ci return wiphy->flags & WIPHY_FLAG_4ADDR_AP; 22448c2ecf20Sopenharmony_ci return wiphy->interface_modes & BIT(iftype); 22458c2ecf20Sopenharmony_ci case 1: 22468c2ecf20Sopenharmony_ci if (!(wiphy->software_iftypes & BIT(iftype)) && is_vlan) 22478c2ecf20Sopenharmony_ci return wiphy->flags & WIPHY_FLAG_4ADDR_AP; 22488c2ecf20Sopenharmony_ci return wiphy->software_iftypes & BIT(iftype); 22498c2ecf20Sopenharmony_ci default: 22508c2ecf20Sopenharmony_ci break; 22518c2ecf20Sopenharmony_ci } 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ci return false; 22548c2ecf20Sopenharmony_ci} 22558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfg80211_iftype_allowed); 2256