| 1 | // SPDX-License-Identifier: GPL-2.0 | 
|---|
| 2 | /* | 
|---|
| 3 | * Wireless utility functions | 
|---|
| 4 | * | 
|---|
| 5 | * Copyright 2007-2009	Johannes Berg <johannes@sipsolutions.net> | 
|---|
| 6 | * Copyright 2013-2014  Intel Mobile Communications GmbH | 
|---|
| 7 | * Copyright 2017	Intel Deutschland GmbH | 
|---|
| 8 | * Copyright (C) 2018-2023, 2025 Intel Corporation | 
|---|
| 9 | */ | 
|---|
| 10 | #include <linux/export.h> | 
|---|
| 11 | #include <linux/bitops.h> | 
|---|
| 12 | #include <linux/etherdevice.h> | 
|---|
| 13 | #include <linux/slab.h> | 
|---|
| 14 | #include <linux/ieee80211.h> | 
|---|
| 15 | #include <net/cfg80211.h> | 
|---|
| 16 | #include <net/ip.h> | 
|---|
| 17 | #include <net/dsfield.h> | 
|---|
| 18 | #include <linux/if_vlan.h> | 
|---|
| 19 | #include <linux/mpls.h> | 
|---|
| 20 | #include <linux/gcd.h> | 
|---|
| 21 | #include <linux/bitfield.h> | 
|---|
| 22 | #include <linux/nospec.h> | 
|---|
| 23 | #include "core.h" | 
|---|
| 24 | #include "rdev-ops.h" | 
|---|
| 25 |  | 
|---|
| 26 |  | 
|---|
| 27 | const struct ieee80211_rate * | 
|---|
| 28 | ieee80211_get_response_rate(struct ieee80211_supported_band *sband, | 
|---|
| 29 | u32 basic_rates, int bitrate) | 
|---|
| 30 | { | 
|---|
| 31 | struct ieee80211_rate *result = &sband->bitrates[0]; | 
|---|
| 32 | int i; | 
|---|
| 33 |  | 
|---|
| 34 | for (i = 0; i < sband->n_bitrates; i++) { | 
|---|
| 35 | if (!(basic_rates & BIT(i))) | 
|---|
| 36 | continue; | 
|---|
| 37 | if (sband->bitrates[i].bitrate > bitrate) | 
|---|
| 38 | continue; | 
|---|
| 39 | result = &sband->bitrates[i]; | 
|---|
| 40 | } | 
|---|
| 41 |  | 
|---|
| 42 | return result; | 
|---|
| 43 | } | 
|---|
| 44 | EXPORT_SYMBOL(ieee80211_get_response_rate); | 
|---|
| 45 |  | 
|---|
| 46 | u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband) | 
|---|
| 47 | { | 
|---|
| 48 | struct ieee80211_rate *bitrates; | 
|---|
| 49 | u32 mandatory_rates = 0; | 
|---|
| 50 | enum ieee80211_rate_flags mandatory_flag; | 
|---|
| 51 | int i; | 
|---|
| 52 |  | 
|---|
| 53 | if (WARN_ON(!sband)) | 
|---|
| 54 | return 1; | 
|---|
| 55 |  | 
|---|
| 56 | if (sband->band == NL80211_BAND_2GHZ) | 
|---|
| 57 | mandatory_flag = IEEE80211_RATE_MANDATORY_B; | 
|---|
| 58 | else | 
|---|
| 59 | mandatory_flag = IEEE80211_RATE_MANDATORY_A; | 
|---|
| 60 |  | 
|---|
| 61 | bitrates = sband->bitrates; | 
|---|
| 62 | for (i = 0; i < sband->n_bitrates; i++) | 
|---|
| 63 | if (bitrates[i].flags & mandatory_flag) | 
|---|
| 64 | mandatory_rates |= BIT(i); | 
|---|
| 65 | return mandatory_rates; | 
|---|
| 66 | } | 
|---|
| 67 | EXPORT_SYMBOL(ieee80211_mandatory_rates); | 
|---|
| 68 |  | 
|---|
| 69 | u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band) | 
|---|
| 70 | { | 
|---|
| 71 | /* see 802.11 17.3.8.3.2 and Annex J | 
|---|
| 72 | * there are overlapping channel numbers in 5GHz and 2GHz bands */ | 
|---|
| 73 | if (chan <= 0) | 
|---|
| 74 | return 0; /* not supported */ | 
|---|
| 75 | switch (band) { | 
|---|
| 76 | case NL80211_BAND_2GHZ: | 
|---|
| 77 | case NL80211_BAND_LC: | 
|---|
| 78 | if (chan == 14) | 
|---|
| 79 | return MHZ_TO_KHZ(2484); | 
|---|
| 80 | else if (chan < 14) | 
|---|
| 81 | return MHZ_TO_KHZ(2407 + chan * 5); | 
|---|
| 82 | break; | 
|---|
| 83 | case NL80211_BAND_5GHZ: | 
|---|
| 84 | if (chan >= 182 && chan <= 196) | 
|---|
| 85 | return MHZ_TO_KHZ(4000 + chan * 5); | 
|---|
| 86 | else | 
|---|
| 87 | return MHZ_TO_KHZ(5000 + chan * 5); | 
|---|
| 88 | break; | 
|---|
| 89 | case NL80211_BAND_6GHZ: | 
|---|
| 90 | /* see 802.11ax D6.1 27.3.23.2 */ | 
|---|
| 91 | if (chan == 2) | 
|---|
| 92 | return MHZ_TO_KHZ(5935); | 
|---|
| 93 | if (chan <= 233) | 
|---|
| 94 | return MHZ_TO_KHZ(5950 + chan * 5); | 
|---|
| 95 | break; | 
|---|
| 96 | case NL80211_BAND_60GHZ: | 
|---|
| 97 | if (chan < 7) | 
|---|
| 98 | return MHZ_TO_KHZ(56160 + chan * 2160); | 
|---|
| 99 | break; | 
|---|
| 100 | case NL80211_BAND_S1GHZ: | 
|---|
| 101 | return 902000 + chan * 500; | 
|---|
| 102 | default: | 
|---|
| 103 | ; | 
|---|
| 104 | } | 
|---|
| 105 | return 0; /* not supported */ | 
|---|
| 106 | } | 
|---|
| 107 | EXPORT_SYMBOL(ieee80211_channel_to_freq_khz); | 
|---|
| 108 |  | 
|---|
| 109 | int ieee80211_freq_khz_to_channel(u32 freq) | 
|---|
| 110 | { | 
|---|
| 111 | /* TODO: just handle MHz for now */ | 
|---|
| 112 | freq = KHZ_TO_MHZ(freq); | 
|---|
| 113 |  | 
|---|
| 114 | /* see 802.11 17.3.8.3.2 and Annex J */ | 
|---|
| 115 | if (freq == 2484) | 
|---|
| 116 | return 14; | 
|---|
| 117 | else if (freq < 2484) | 
|---|
| 118 | return (freq - 2407) / 5; | 
|---|
| 119 | else if (freq >= 4910 && freq <= 4980) | 
|---|
| 120 | return (freq - 4000) / 5; | 
|---|
| 121 | else if (freq < 5925) | 
|---|
| 122 | return (freq - 5000) / 5; | 
|---|
| 123 | else if (freq == 5935) | 
|---|
| 124 | return 2; | 
|---|
| 125 | else if (freq <= 45000) /* DMG band lower limit */ | 
|---|
| 126 | /* see 802.11ax D6.1 27.3.22.2 */ | 
|---|
| 127 | return (freq - 5950) / 5; | 
|---|
| 128 | else if (freq >= 58320 && freq <= 70200) | 
|---|
| 129 | return (freq - 56160) / 2160; | 
|---|
| 130 | else | 
|---|
| 131 | return 0; | 
|---|
| 132 | } | 
|---|
| 133 | EXPORT_SYMBOL(ieee80211_freq_khz_to_channel); | 
|---|
| 134 |  | 
|---|
| 135 | struct ieee80211_channel *ieee80211_get_channel_khz(struct wiphy *wiphy, | 
|---|
| 136 | u32 freq) | 
|---|
| 137 | { | 
|---|
| 138 | enum nl80211_band band; | 
|---|
| 139 | struct ieee80211_supported_band *sband; | 
|---|
| 140 | int i; | 
|---|
| 141 |  | 
|---|
| 142 | for (band = 0; band < NUM_NL80211_BANDS; band++) { | 
|---|
| 143 | sband = wiphy->bands[band]; | 
|---|
| 144 |  | 
|---|
| 145 | if (!sband) | 
|---|
| 146 | continue; | 
|---|
| 147 |  | 
|---|
| 148 | for (i = 0; i < sband->n_channels; i++) { | 
|---|
| 149 | struct ieee80211_channel *chan = &sband->channels[i]; | 
|---|
| 150 |  | 
|---|
| 151 | if (ieee80211_channel_to_khz(chan) == freq) | 
|---|
| 152 | return chan; | 
|---|
| 153 | } | 
|---|
| 154 | } | 
|---|
| 155 |  | 
|---|
| 156 | return NULL; | 
|---|
| 157 | } | 
|---|
| 158 | EXPORT_SYMBOL(ieee80211_get_channel_khz); | 
|---|
| 159 |  | 
|---|
| 160 | static void set_mandatory_flags_band(struct ieee80211_supported_band *sband) | 
|---|
| 161 | { | 
|---|
| 162 | int i, want; | 
|---|
| 163 |  | 
|---|
| 164 | switch (sband->band) { | 
|---|
| 165 | case NL80211_BAND_5GHZ: | 
|---|
| 166 | case NL80211_BAND_6GHZ: | 
|---|
| 167 | want = 3; | 
|---|
| 168 | for (i = 0; i < sband->n_bitrates; i++) { | 
|---|
| 169 | if (sband->bitrates[i].bitrate == 60 || | 
|---|
| 170 | sband->bitrates[i].bitrate == 120 || | 
|---|
| 171 | sband->bitrates[i].bitrate == 240) { | 
|---|
| 172 | sband->bitrates[i].flags |= | 
|---|
| 173 | IEEE80211_RATE_MANDATORY_A; | 
|---|
| 174 | want--; | 
|---|
| 175 | } | 
|---|
| 176 | } | 
|---|
| 177 | WARN_ON(want); | 
|---|
| 178 | break; | 
|---|
| 179 | case NL80211_BAND_2GHZ: | 
|---|
| 180 | case NL80211_BAND_LC: | 
|---|
| 181 | want = 7; | 
|---|
| 182 | for (i = 0; i < sband->n_bitrates; i++) { | 
|---|
| 183 | switch (sband->bitrates[i].bitrate) { | 
|---|
| 184 | case 10: | 
|---|
| 185 | case 20: | 
|---|
| 186 | case 55: | 
|---|
| 187 | case 110: | 
|---|
| 188 | sband->bitrates[i].flags |= | 
|---|
| 189 | IEEE80211_RATE_MANDATORY_B | | 
|---|
| 190 | IEEE80211_RATE_MANDATORY_G; | 
|---|
| 191 | want--; | 
|---|
| 192 | break; | 
|---|
| 193 | case 60: | 
|---|
| 194 | case 120: | 
|---|
| 195 | case 240: | 
|---|
| 196 | sband->bitrates[i].flags |= | 
|---|
| 197 | IEEE80211_RATE_MANDATORY_G; | 
|---|
| 198 | want--; | 
|---|
| 199 | fallthrough; | 
|---|
| 200 | default: | 
|---|
| 201 | sband->bitrates[i].flags |= | 
|---|
| 202 | IEEE80211_RATE_ERP_G; | 
|---|
| 203 | break; | 
|---|
| 204 | } | 
|---|
| 205 | } | 
|---|
| 206 | WARN_ON(want != 0 && want != 3); | 
|---|
| 207 | break; | 
|---|
| 208 | case NL80211_BAND_60GHZ: | 
|---|
| 209 | /* check for mandatory HT MCS 1..4 */ | 
|---|
| 210 | WARN_ON(!sband->ht_cap.ht_supported); | 
|---|
| 211 | WARN_ON((sband->ht_cap.mcs.rx_mask[0] & 0x1e) != 0x1e); | 
|---|
| 212 | break; | 
|---|
| 213 | case NL80211_BAND_S1GHZ: | 
|---|
| 214 | /* Figure 9-589bd: 3 means unsupported, so != 3 means at least | 
|---|
| 215 | * mandatory is ok. | 
|---|
| 216 | */ | 
|---|
| 217 | WARN_ON((sband->s1g_cap.nss_mcs[0] & 0x3) == 0x3); | 
|---|
| 218 | break; | 
|---|
| 219 | case NUM_NL80211_BANDS: | 
|---|
| 220 | default: | 
|---|
| 221 | WARN_ON(1); | 
|---|
| 222 | break; | 
|---|
| 223 | } | 
|---|
| 224 | } | 
|---|
| 225 |  | 
|---|
| 226 | void ieee80211_set_bitrate_flags(struct wiphy *wiphy) | 
|---|
| 227 | { | 
|---|
| 228 | enum nl80211_band band; | 
|---|
| 229 |  | 
|---|
| 230 | for (band = 0; band < NUM_NL80211_BANDS; band++) | 
|---|
| 231 | if (wiphy->bands[band]) | 
|---|
| 232 | set_mandatory_flags_band(wiphy->bands[band]); | 
|---|
| 233 | } | 
|---|
| 234 |  | 
|---|
| 235 | bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher) | 
|---|
| 236 | { | 
|---|
| 237 | int i; | 
|---|
| 238 | for (i = 0; i < wiphy->n_cipher_suites; i++) | 
|---|
| 239 | if (cipher == wiphy->cipher_suites[i]) | 
|---|
| 240 | return true; | 
|---|
| 241 | return false; | 
|---|
| 242 | } | 
|---|
| 243 |  | 
|---|
| 244 | static bool | 
|---|
| 245 | cfg80211_igtk_cipher_supported(struct cfg80211_registered_device *rdev) | 
|---|
| 246 | { | 
|---|
| 247 | struct wiphy *wiphy = &rdev->wiphy; | 
|---|
| 248 | int i; | 
|---|
| 249 |  | 
|---|
| 250 | for (i = 0; i < wiphy->n_cipher_suites; i++) { | 
|---|
| 251 | switch (wiphy->cipher_suites[i]) { | 
|---|
| 252 | case WLAN_CIPHER_SUITE_AES_CMAC: | 
|---|
| 253 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | 
|---|
| 254 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | 
|---|
| 255 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | 
|---|
| 256 | return true; | 
|---|
| 257 | } | 
|---|
| 258 | } | 
|---|
| 259 |  | 
|---|
| 260 | return false; | 
|---|
| 261 | } | 
|---|
| 262 |  | 
|---|
| 263 | bool cfg80211_valid_key_idx(struct cfg80211_registered_device *rdev, | 
|---|
| 264 | int key_idx, bool pairwise) | 
|---|
| 265 | { | 
|---|
| 266 | int max_key_idx; | 
|---|
| 267 |  | 
|---|
| 268 | if (pairwise) | 
|---|
| 269 | max_key_idx = 3; | 
|---|
| 270 | else if (wiphy_ext_feature_isset(wiphy: &rdev->wiphy, | 
|---|
| 271 | ftidx: NL80211_EXT_FEATURE_BEACON_PROTECTION) || | 
|---|
| 272 | wiphy_ext_feature_isset(wiphy: &rdev->wiphy, | 
|---|
| 273 | ftidx: NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT)) | 
|---|
| 274 | max_key_idx = 7; | 
|---|
| 275 | else if (cfg80211_igtk_cipher_supported(rdev)) | 
|---|
| 276 | max_key_idx = 5; | 
|---|
| 277 | else | 
|---|
| 278 | max_key_idx = 3; | 
|---|
| 279 |  | 
|---|
| 280 | if (key_idx < 0 || key_idx > max_key_idx) | 
|---|
| 281 | return false; | 
|---|
| 282 |  | 
|---|
| 283 | return true; | 
|---|
| 284 | } | 
|---|
| 285 |  | 
|---|
| 286 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 
|---|
| 287 | struct key_params *params, int key_idx, | 
|---|
| 288 | bool pairwise, const u8 *mac_addr) | 
|---|
| 289 | { | 
|---|
| 290 | if (!cfg80211_valid_key_idx(rdev, key_idx, pairwise)) | 
|---|
| 291 | return -EINVAL; | 
|---|
| 292 |  | 
|---|
| 293 | if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | 
|---|
| 294 | return -EINVAL; | 
|---|
| 295 |  | 
|---|
| 296 | if (pairwise && !mac_addr) | 
|---|
| 297 | return -EINVAL; | 
|---|
| 298 |  | 
|---|
| 299 | switch (params->cipher) { | 
|---|
| 300 | case WLAN_CIPHER_SUITE_TKIP: | 
|---|
| 301 | /* Extended Key ID can only be used with CCMP/GCMP ciphers */ | 
|---|
| 302 | if ((pairwise && key_idx) || | 
|---|
| 303 | params->mode != NL80211_KEY_RX_TX) | 
|---|
| 304 | return -EINVAL; | 
|---|
| 305 | break; | 
|---|
| 306 | case WLAN_CIPHER_SUITE_CCMP: | 
|---|
| 307 | case WLAN_CIPHER_SUITE_CCMP_256: | 
|---|
| 308 | case WLAN_CIPHER_SUITE_GCMP: | 
|---|
| 309 | case WLAN_CIPHER_SUITE_GCMP_256: | 
|---|
| 310 | /* IEEE802.11-2016 allows only 0 and - when supporting | 
|---|
| 311 | * Extended Key ID - 1 as index for pairwise keys. | 
|---|
| 312 | * @NL80211_KEY_NO_TX is only allowed for pairwise keys when | 
|---|
| 313 | * the driver supports Extended Key ID. | 
|---|
| 314 | * @NL80211_KEY_SET_TX can't be set when installing and | 
|---|
| 315 | * validating a key. | 
|---|
| 316 | */ | 
|---|
| 317 | if ((params->mode == NL80211_KEY_NO_TX && !pairwise) || | 
|---|
| 318 | params->mode == NL80211_KEY_SET_TX) | 
|---|
| 319 | return -EINVAL; | 
|---|
| 320 | if (wiphy_ext_feature_isset(wiphy: &rdev->wiphy, | 
|---|
| 321 | ftidx: NL80211_EXT_FEATURE_EXT_KEY_ID)) { | 
|---|
| 322 | if (pairwise && (key_idx < 0 || key_idx > 1)) | 
|---|
| 323 | return -EINVAL; | 
|---|
| 324 | } else if (pairwise && key_idx) { | 
|---|
| 325 | return -EINVAL; | 
|---|
| 326 | } | 
|---|
| 327 | break; | 
|---|
| 328 | case WLAN_CIPHER_SUITE_AES_CMAC: | 
|---|
| 329 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | 
|---|
| 330 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | 
|---|
| 331 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | 
|---|
| 332 | /* Disallow BIP (group-only) cipher as pairwise cipher */ | 
|---|
| 333 | if (pairwise) | 
|---|
| 334 | return -EINVAL; | 
|---|
| 335 | if (key_idx < 4) | 
|---|
| 336 | return -EINVAL; | 
|---|
| 337 | break; | 
|---|
| 338 | case WLAN_CIPHER_SUITE_WEP40: | 
|---|
| 339 | case WLAN_CIPHER_SUITE_WEP104: | 
|---|
| 340 | if (key_idx > 3) | 
|---|
| 341 | return -EINVAL; | 
|---|
| 342 | break; | 
|---|
| 343 | default: | 
|---|
| 344 | break; | 
|---|
| 345 | } | 
|---|
| 346 |  | 
|---|
| 347 | switch (params->cipher) { | 
|---|
| 348 | case WLAN_CIPHER_SUITE_WEP40: | 
|---|
| 349 | if (params->key_len != WLAN_KEY_LEN_WEP40) | 
|---|
| 350 | return -EINVAL; | 
|---|
| 351 | break; | 
|---|
| 352 | case WLAN_CIPHER_SUITE_TKIP: | 
|---|
| 353 | if (params->key_len != WLAN_KEY_LEN_TKIP) | 
|---|
| 354 | return -EINVAL; | 
|---|
| 355 | break; | 
|---|
| 356 | case WLAN_CIPHER_SUITE_CCMP: | 
|---|
| 357 | if (params->key_len != WLAN_KEY_LEN_CCMP) | 
|---|
| 358 | return -EINVAL; | 
|---|
| 359 | break; | 
|---|
| 360 | case WLAN_CIPHER_SUITE_CCMP_256: | 
|---|
| 361 | if (params->key_len != WLAN_KEY_LEN_CCMP_256) | 
|---|
| 362 | return -EINVAL; | 
|---|
| 363 | break; | 
|---|
| 364 | case WLAN_CIPHER_SUITE_GCMP: | 
|---|
| 365 | if (params->key_len != WLAN_KEY_LEN_GCMP) | 
|---|
| 366 | return -EINVAL; | 
|---|
| 367 | break; | 
|---|
| 368 | case WLAN_CIPHER_SUITE_GCMP_256: | 
|---|
| 369 | if (params->key_len != WLAN_KEY_LEN_GCMP_256) | 
|---|
| 370 | return -EINVAL; | 
|---|
| 371 | break; | 
|---|
| 372 | case WLAN_CIPHER_SUITE_WEP104: | 
|---|
| 373 | if (params->key_len != WLAN_KEY_LEN_WEP104) | 
|---|
| 374 | return -EINVAL; | 
|---|
| 375 | break; | 
|---|
| 376 | case WLAN_CIPHER_SUITE_AES_CMAC: | 
|---|
| 377 | if (params->key_len != WLAN_KEY_LEN_AES_CMAC) | 
|---|
| 378 | return -EINVAL; | 
|---|
| 379 | break; | 
|---|
| 380 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | 
|---|
| 381 | if (params->key_len != WLAN_KEY_LEN_BIP_CMAC_256) | 
|---|
| 382 | return -EINVAL; | 
|---|
| 383 | break; | 
|---|
| 384 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | 
|---|
| 385 | if (params->key_len != WLAN_KEY_LEN_BIP_GMAC_128) | 
|---|
| 386 | return -EINVAL; | 
|---|
| 387 | break; | 
|---|
| 388 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | 
|---|
| 389 | if (params->key_len != WLAN_KEY_LEN_BIP_GMAC_256) | 
|---|
| 390 | return -EINVAL; | 
|---|
| 391 | break; | 
|---|
| 392 | default: | 
|---|
| 393 | /* | 
|---|
| 394 | * We don't know anything about this algorithm, | 
|---|
| 395 | * allow using it -- but the driver must check | 
|---|
| 396 | * all parameters! We still check below whether | 
|---|
| 397 | * or not the driver supports this algorithm, | 
|---|
| 398 | * of course. | 
|---|
| 399 | */ | 
|---|
| 400 | break; | 
|---|
| 401 | } | 
|---|
| 402 |  | 
|---|
| 403 | if (params->seq) { | 
|---|
| 404 | switch (params->cipher) { | 
|---|
| 405 | case WLAN_CIPHER_SUITE_WEP40: | 
|---|
| 406 | case WLAN_CIPHER_SUITE_WEP104: | 
|---|
| 407 | /* These ciphers do not use key sequence */ | 
|---|
| 408 | return -EINVAL; | 
|---|
| 409 | case WLAN_CIPHER_SUITE_TKIP: | 
|---|
| 410 | case WLAN_CIPHER_SUITE_CCMP: | 
|---|
| 411 | case WLAN_CIPHER_SUITE_CCMP_256: | 
|---|
| 412 | case WLAN_CIPHER_SUITE_GCMP: | 
|---|
| 413 | case WLAN_CIPHER_SUITE_GCMP_256: | 
|---|
| 414 | case WLAN_CIPHER_SUITE_AES_CMAC: | 
|---|
| 415 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | 
|---|
| 416 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | 
|---|
| 417 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | 
|---|
| 418 | if (params->seq_len != 6) | 
|---|
| 419 | return -EINVAL; | 
|---|
| 420 | break; | 
|---|
| 421 | } | 
|---|
| 422 | } | 
|---|
| 423 |  | 
|---|
| 424 | if (!cfg80211_supported_cipher_suite(wiphy: &rdev->wiphy, cipher: params->cipher)) | 
|---|
| 425 | return -EINVAL; | 
|---|
| 426 |  | 
|---|
| 427 | return 0; | 
|---|
| 428 | } | 
|---|
| 429 |  | 
|---|
| 430 | unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc) | 
|---|
| 431 | { | 
|---|
| 432 | unsigned int hdrlen = 24; | 
|---|
| 433 |  | 
|---|
| 434 | if (ieee80211_is_ext(fc)) { | 
|---|
| 435 | hdrlen = 4; | 
|---|
| 436 | goto out; | 
|---|
| 437 | } | 
|---|
| 438 |  | 
|---|
| 439 | if (ieee80211_is_data(fc)) { | 
|---|
| 440 | if (ieee80211_has_a4(fc)) | 
|---|
| 441 | hdrlen = 30; | 
|---|
| 442 | if (ieee80211_is_data_qos(fc)) { | 
|---|
| 443 | hdrlen += IEEE80211_QOS_CTL_LEN; | 
|---|
| 444 | if (ieee80211_has_order(fc)) | 
|---|
| 445 | hdrlen += IEEE80211_HT_CTL_LEN; | 
|---|
| 446 | } | 
|---|
| 447 | goto out; | 
|---|
| 448 | } | 
|---|
| 449 |  | 
|---|
| 450 | if (ieee80211_is_mgmt(fc)) { | 
|---|
| 451 | if (ieee80211_has_order(fc)) | 
|---|
| 452 | hdrlen += IEEE80211_HT_CTL_LEN; | 
|---|
| 453 | goto out; | 
|---|
| 454 | } | 
|---|
| 455 |  | 
|---|
| 456 | if (ieee80211_is_ctl(fc)) { | 
|---|
| 457 | /* | 
|---|
| 458 | * ACK and CTS are 10 bytes, all others 16. To see how | 
|---|
| 459 | * to get this condition consider | 
|---|
| 460 | *   subtype mask:   0b0000000011110000 (0x00F0) | 
|---|
| 461 | *   ACK subtype:    0b0000000011010000 (0x00D0) | 
|---|
| 462 | *   CTS subtype:    0b0000000011000000 (0x00C0) | 
|---|
| 463 | *   bits that matter:         ^^^      (0x00E0) | 
|---|
| 464 | *   value of those: 0b0000000011000000 (0x00C0) | 
|---|
| 465 | */ | 
|---|
| 466 | if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) | 
|---|
| 467 | hdrlen = 10; | 
|---|
| 468 | else | 
|---|
| 469 | hdrlen = 16; | 
|---|
| 470 | } | 
|---|
| 471 | out: | 
|---|
| 472 | return hdrlen; | 
|---|
| 473 | } | 
|---|
| 474 | EXPORT_SYMBOL(ieee80211_hdrlen); | 
|---|
| 475 |  | 
|---|
| 476 | unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) | 
|---|
| 477 | { | 
|---|
| 478 | const struct ieee80211_hdr *hdr = | 
|---|
| 479 | (const struct ieee80211_hdr *)skb->data; | 
|---|
| 480 | unsigned int hdrlen; | 
|---|
| 481 |  | 
|---|
| 482 | if (unlikely(skb->len < 10)) | 
|---|
| 483 | return 0; | 
|---|
| 484 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 
|---|
| 485 | if (unlikely(hdrlen > skb->len)) | 
|---|
| 486 | return 0; | 
|---|
| 487 | return hdrlen; | 
|---|
| 488 | } | 
|---|
| 489 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); | 
|---|
| 490 |  | 
|---|
| 491 | static unsigned int __ieee80211_get_mesh_hdrlen(u8 flags) | 
|---|
| 492 | { | 
|---|
| 493 | int ae = flags & MESH_FLAGS_AE; | 
|---|
| 494 | /* 802.11-2012, 8.2.4.7.3 */ | 
|---|
| 495 | switch (ae) { | 
|---|
| 496 | default: | 
|---|
| 497 | case 0: | 
|---|
| 498 | return 6; | 
|---|
| 499 | case MESH_FLAGS_AE_A4: | 
|---|
| 500 | return 12; | 
|---|
| 501 | case MESH_FLAGS_AE_A5_A6: | 
|---|
| 502 | return 18; | 
|---|
| 503 | } | 
|---|
| 504 | } | 
|---|
| 505 |  | 
|---|
| 506 | unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | 
|---|
| 507 | { | 
|---|
| 508 | return __ieee80211_get_mesh_hdrlen(flags: meshhdr->flags); | 
|---|
| 509 | } | 
|---|
| 510 | EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen); | 
|---|
| 511 |  | 
|---|
| 512 | bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto) | 
|---|
| 513 | { | 
|---|
| 514 | const __be16 *hdr_proto = hdr + ETH_ALEN; | 
|---|
| 515 |  | 
|---|
| 516 | if (!(ether_addr_equal(addr1: hdr, addr2: rfc1042_header) && | 
|---|
| 517 | *hdr_proto != htons(ETH_P_AARP) && | 
|---|
| 518 | *hdr_proto != htons(ETH_P_IPX)) && | 
|---|
| 519 | !ether_addr_equal(addr1: hdr, addr2: bridge_tunnel_header)) | 
|---|
| 520 | return false; | 
|---|
| 521 |  | 
|---|
| 522 | *proto = *hdr_proto; | 
|---|
| 523 |  | 
|---|
| 524 | return true; | 
|---|
| 525 | } | 
|---|
| 526 | EXPORT_SYMBOL(ieee80211_get_8023_tunnel_proto); | 
|---|
| 527 |  | 
|---|
| 528 | int ieee80211_strip_8023_mesh_hdr(struct sk_buff *skb) | 
|---|
| 529 | { | 
|---|
| 530 | const void *mesh_addr; | 
|---|
| 531 | struct { | 
|---|
| 532 | struct ethhdr eth; | 
|---|
| 533 | u8 flags; | 
|---|
| 534 | } payload; | 
|---|
| 535 | int hdrlen; | 
|---|
| 536 | int ret; | 
|---|
| 537 |  | 
|---|
| 538 | ret = skb_copy_bits(skb, offset: 0, to: &payload, len: sizeof(payload)); | 
|---|
| 539 | if (ret) | 
|---|
| 540 | return ret; | 
|---|
| 541 |  | 
|---|
| 542 | hdrlen = sizeof(payload.eth) + __ieee80211_get_mesh_hdrlen(flags: payload.flags); | 
|---|
| 543 |  | 
|---|
| 544 | if (likely(pskb_may_pull(skb, hdrlen + 8) && | 
|---|
| 545 | ieee80211_get_8023_tunnel_proto(skb->data + hdrlen, | 
|---|
| 546 | &payload.eth.h_proto))) | 
|---|
| 547 | hdrlen += ETH_ALEN + 2; | 
|---|
| 548 | else if (!pskb_may_pull(skb, len: hdrlen)) | 
|---|
| 549 | return -EINVAL; | 
|---|
| 550 | else | 
|---|
| 551 | payload.eth.h_proto = htons(skb->len - hdrlen); | 
|---|
| 552 |  | 
|---|
| 553 | mesh_addr = skb->data + sizeof(payload.eth) + ETH_ALEN; | 
|---|
| 554 | switch (payload.flags & MESH_FLAGS_AE) { | 
|---|
| 555 | case MESH_FLAGS_AE_A4: | 
|---|
| 556 | memcpy(to: &payload.eth.h_source, from: mesh_addr, ETH_ALEN); | 
|---|
| 557 | break; | 
|---|
| 558 | case MESH_FLAGS_AE_A5_A6: | 
|---|
| 559 | memcpy(to: &payload.eth, from: mesh_addr, len: 2 * ETH_ALEN); | 
|---|
| 560 | break; | 
|---|
| 561 | default: | 
|---|
| 562 | break; | 
|---|
| 563 | } | 
|---|
| 564 |  | 
|---|
| 565 | pskb_pull(skb, len: hdrlen - sizeof(payload.eth)); | 
|---|
| 566 | memcpy(to: skb->data, from: &payload.eth, len: sizeof(payload.eth)); | 
|---|
| 567 |  | 
|---|
| 568 | return 0; | 
|---|
| 569 | } | 
|---|
| 570 | EXPORT_SYMBOL(ieee80211_strip_8023_mesh_hdr); | 
|---|
| 571 |  | 
|---|
| 572 | int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr, | 
|---|
| 573 | const u8 *addr, enum nl80211_iftype iftype, | 
|---|
| 574 | u8 data_offset, bool is_amsdu) | 
|---|
| 575 | { | 
|---|
| 576 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 
|---|
| 577 | struct { | 
|---|
| 578 | u8 hdr[ETH_ALEN] __aligned(2); | 
|---|
| 579 | __be16 proto; | 
|---|
| 580 | } payload; | 
|---|
| 581 | struct ethhdr tmp; | 
|---|
| 582 | u16 hdrlen; | 
|---|
| 583 |  | 
|---|
| 584 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) | 
|---|
| 585 | return -1; | 
|---|
| 586 |  | 
|---|
| 587 | hdrlen = ieee80211_hdrlen(hdr->frame_control) + data_offset; | 
|---|
| 588 | if (skb->len < hdrlen) | 
|---|
| 589 | return -1; | 
|---|
| 590 |  | 
|---|
| 591 | /* convert IEEE 802.11 header + possible LLC headers into Ethernet | 
|---|
| 592 | * header | 
|---|
| 593 | * IEEE 802.11 address fields: | 
|---|
| 594 | * ToDS FromDS Addr1 Addr2 Addr3 Addr4 | 
|---|
| 595 | *   0     0   DA    SA    BSSID n/a | 
|---|
| 596 | *   0     1   DA    BSSID SA    n/a | 
|---|
| 597 | *   1     0   BSSID SA    DA    n/a | 
|---|
| 598 | *   1     1   RA    TA    DA    SA | 
|---|
| 599 | */ | 
|---|
| 600 | memcpy(to: tmp.h_dest, from: ieee80211_get_DA(hdr), ETH_ALEN); | 
|---|
| 601 | memcpy(to: tmp.h_source, from: ieee80211_get_SA(hdr), ETH_ALEN); | 
|---|
| 602 |  | 
|---|
| 603 | switch (hdr->frame_control & | 
|---|
| 604 | cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { | 
|---|
| 605 | case cpu_to_le16(IEEE80211_FCTL_TODS): | 
|---|
| 606 | if (unlikely(iftype != NL80211_IFTYPE_AP && | 
|---|
| 607 | iftype != NL80211_IFTYPE_AP_VLAN && | 
|---|
| 608 | iftype != NL80211_IFTYPE_P2P_GO)) | 
|---|
| 609 | return -1; | 
|---|
| 610 | break; | 
|---|
| 611 | case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): | 
|---|
| 612 | if (unlikely(iftype != NL80211_IFTYPE_MESH_POINT && | 
|---|
| 613 | iftype != NL80211_IFTYPE_AP_VLAN && | 
|---|
| 614 | iftype != NL80211_IFTYPE_STATION)) | 
|---|
| 615 | return -1; | 
|---|
| 616 | break; | 
|---|
| 617 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): | 
|---|
| 618 | if ((iftype != NL80211_IFTYPE_STATION && | 
|---|
| 619 | iftype != NL80211_IFTYPE_P2P_CLIENT && | 
|---|
| 620 | iftype != NL80211_IFTYPE_MESH_POINT) || | 
|---|
| 621 | (is_multicast_ether_addr(addr: tmp.h_dest) && | 
|---|
| 622 | ether_addr_equal(addr1: tmp.h_source, addr2: addr))) | 
|---|
| 623 | return -1; | 
|---|
| 624 | break; | 
|---|
| 625 | case cpu_to_le16(0): | 
|---|
| 626 | if (iftype != NL80211_IFTYPE_ADHOC && | 
|---|
| 627 | iftype != NL80211_IFTYPE_STATION && | 
|---|
| 628 | iftype != NL80211_IFTYPE_OCB) | 
|---|
| 629 | return -1; | 
|---|
| 630 | break; | 
|---|
| 631 | } | 
|---|
| 632 |  | 
|---|
| 633 | if (likely(!is_amsdu && iftype != NL80211_IFTYPE_MESH_POINT && | 
|---|
| 634 | skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 && | 
|---|
| 635 | ieee80211_get_8023_tunnel_proto(&payload, &tmp.h_proto))) { | 
|---|
| 636 | /* remove RFC1042 or Bridge-Tunnel encapsulation */ | 
|---|
| 637 | hdrlen += ETH_ALEN + 2; | 
|---|
| 638 | skb_postpull_rcsum(skb, start: &payload, ETH_ALEN + 2); | 
|---|
| 639 | } else { | 
|---|
| 640 | tmp.h_proto = htons(skb->len - hdrlen); | 
|---|
| 641 | } | 
|---|
| 642 |  | 
|---|
| 643 | pskb_pull(skb, len: hdrlen); | 
|---|
| 644 |  | 
|---|
| 645 | if (!ehdr) | 
|---|
| 646 | ehdr = skb_push(skb, len: sizeof(struct ethhdr)); | 
|---|
| 647 | memcpy(to: ehdr, from: &tmp, len: sizeof(tmp)); | 
|---|
| 648 |  | 
|---|
| 649 | return 0; | 
|---|
| 650 | } | 
|---|
| 651 | EXPORT_SYMBOL(ieee80211_data_to_8023_exthdr); | 
|---|
| 652 |  | 
|---|
| 653 | static void | 
|---|
| 654 | __frame_add_frag(struct sk_buff *skb, struct page *page, | 
|---|
| 655 | void *ptr, int len, int size) | 
|---|
| 656 | { | 
|---|
| 657 | struct skb_shared_info *sh = skb_shinfo(skb); | 
|---|
| 658 | int page_offset; | 
|---|
| 659 |  | 
|---|
| 660 | get_page(page); | 
|---|
| 661 | page_offset = ptr - page_address(page); | 
|---|
| 662 | skb_add_rx_frag(skb, i: sh->nr_frags, page, off: page_offset, size: len, truesize: size); | 
|---|
| 663 | } | 
|---|
| 664 |  | 
|---|
| 665 | static void | 
|---|
| 666 | __ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame, | 
|---|
| 667 | int offset, int len) | 
|---|
| 668 | { | 
|---|
| 669 | struct skb_shared_info *sh = skb_shinfo(skb); | 
|---|
| 670 | const skb_frag_t *frag = &sh->frags[0]; | 
|---|
| 671 | struct page *frag_page; | 
|---|
| 672 | void *frag_ptr; | 
|---|
| 673 | int frag_len, frag_size; | 
|---|
| 674 | int head_size = skb->len - skb->data_len; | 
|---|
| 675 | int cur_len; | 
|---|
| 676 |  | 
|---|
| 677 | frag_page = virt_to_head_page(x: skb->head); | 
|---|
| 678 | frag_ptr = skb->data; | 
|---|
| 679 | frag_size = head_size; | 
|---|
| 680 |  | 
|---|
| 681 | while (offset >= frag_size) { | 
|---|
| 682 | offset -= frag_size; | 
|---|
| 683 | frag_page = skb_frag_page(frag); | 
|---|
| 684 | frag_ptr = skb_frag_address(frag); | 
|---|
| 685 | frag_size = skb_frag_size(frag); | 
|---|
| 686 | frag++; | 
|---|
| 687 | } | 
|---|
| 688 |  | 
|---|
| 689 | frag_ptr += offset; | 
|---|
| 690 | frag_len = frag_size - offset; | 
|---|
| 691 |  | 
|---|
| 692 | cur_len = min(len, frag_len); | 
|---|
| 693 |  | 
|---|
| 694 | __frame_add_frag(skb: frame, page: frag_page, ptr: frag_ptr, len: cur_len, size: frag_size); | 
|---|
| 695 | len -= cur_len; | 
|---|
| 696 |  | 
|---|
| 697 | while (len > 0) { | 
|---|
| 698 | frag_len = skb_frag_size(frag); | 
|---|
| 699 | cur_len = min(len, frag_len); | 
|---|
| 700 | __frame_add_frag(skb: frame, page: skb_frag_page(frag), | 
|---|
| 701 | ptr: skb_frag_address(frag), len: cur_len, size: frag_len); | 
|---|
| 702 | len -= cur_len; | 
|---|
| 703 | frag++; | 
|---|
| 704 | } | 
|---|
| 705 | } | 
|---|
| 706 |  | 
|---|
| 707 | static struct sk_buff * | 
|---|
| 708 | __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen, | 
|---|
| 709 | int offset, int len, bool reuse_frag, | 
|---|
| 710 | int min_len) | 
|---|
| 711 | { | 
|---|
| 712 | struct sk_buff *frame; | 
|---|
| 713 | int cur_len = len; | 
|---|
| 714 |  | 
|---|
| 715 | if (skb->len - offset < len) | 
|---|
| 716 | return NULL; | 
|---|
| 717 |  | 
|---|
| 718 | /* | 
|---|
| 719 | * When reusing fragments, copy some data to the head to simplify | 
|---|
| 720 | * ethernet header handling and speed up protocol header processing | 
|---|
| 721 | * in the stack later. | 
|---|
| 722 | */ | 
|---|
| 723 | if (reuse_frag) | 
|---|
| 724 | cur_len = min_t(int, len, min_len); | 
|---|
| 725 |  | 
|---|
| 726 | /* | 
|---|
| 727 | * Allocate and reserve two bytes more for payload | 
|---|
| 728 | * alignment since sizeof(struct ethhdr) is 14. | 
|---|
| 729 | */ | 
|---|
| 730 | frame = dev_alloc_skb(length: hlen + sizeof(struct ethhdr) + 2 + cur_len); | 
|---|
| 731 | if (!frame) | 
|---|
| 732 | return NULL; | 
|---|
| 733 |  | 
|---|
| 734 | frame->priority = skb->priority; | 
|---|
| 735 | skb_reserve(skb: frame, len: hlen + sizeof(struct ethhdr) + 2); | 
|---|
| 736 | skb_copy_bits(skb, offset, to: skb_put(skb: frame, len: cur_len), len: cur_len); | 
|---|
| 737 |  | 
|---|
| 738 | len -= cur_len; | 
|---|
| 739 | if (!len) | 
|---|
| 740 | return frame; | 
|---|
| 741 |  | 
|---|
| 742 | offset += cur_len; | 
|---|
| 743 | __ieee80211_amsdu_copy_frag(skb, frame, offset, len); | 
|---|
| 744 |  | 
|---|
| 745 | return frame; | 
|---|
| 746 | } | 
|---|
| 747 |  | 
|---|
| 748 | static u16 | 
|---|
| 749 | ieee80211_amsdu_subframe_length(void *field, u8 mesh_flags, u8 hdr_type) | 
|---|
| 750 | { | 
|---|
| 751 | __le16 *field_le = field; | 
|---|
| 752 | __be16 *field_be = field; | 
|---|
| 753 | u16 len; | 
|---|
| 754 |  | 
|---|
| 755 | if (hdr_type >= 2) | 
|---|
| 756 | len = le16_to_cpu(*field_le); | 
|---|
| 757 | else | 
|---|
| 758 | len = be16_to_cpu(*field_be); | 
|---|
| 759 | if (hdr_type) | 
|---|
| 760 | len += __ieee80211_get_mesh_hdrlen(flags: mesh_flags); | 
|---|
| 761 |  | 
|---|
| 762 | return len; | 
|---|
| 763 | } | 
|---|
| 764 |  | 
|---|
| 765 | bool ieee80211_is_valid_amsdu(struct sk_buff *skb, u8 mesh_hdr) | 
|---|
| 766 | { | 
|---|
| 767 | int offset = 0, subframe_len, padding; | 
|---|
| 768 |  | 
|---|
| 769 | for (offset = 0; offset < skb->len; offset += subframe_len + padding) { | 
|---|
| 770 | int remaining = skb->len - offset; | 
|---|
| 771 | struct { | 
|---|
| 772 | __be16 len; | 
|---|
| 773 | u8 mesh_flags; | 
|---|
| 774 | } hdr; | 
|---|
| 775 | u16 len; | 
|---|
| 776 |  | 
|---|
| 777 | if (sizeof(hdr) > remaining) | 
|---|
| 778 | return false; | 
|---|
| 779 |  | 
|---|
| 780 | if (skb_copy_bits(skb, offset: offset + 2 * ETH_ALEN, to: &hdr, len: sizeof(hdr)) < 0) | 
|---|
| 781 | return false; | 
|---|
| 782 |  | 
|---|
| 783 | len = ieee80211_amsdu_subframe_length(field: &hdr.len, mesh_flags: hdr.mesh_flags, | 
|---|
| 784 | hdr_type: mesh_hdr); | 
|---|
| 785 | subframe_len = sizeof(struct ethhdr) + len; | 
|---|
| 786 | padding = (4 - subframe_len) & 0x3; | 
|---|
| 787 |  | 
|---|
| 788 | if (subframe_len > remaining) | 
|---|
| 789 | return false; | 
|---|
| 790 | } | 
|---|
| 791 |  | 
|---|
| 792 | return true; | 
|---|
| 793 | } | 
|---|
| 794 | EXPORT_SYMBOL(ieee80211_is_valid_amsdu); | 
|---|
| 795 |  | 
|---|
| 796 |  | 
|---|
| 797 | /* | 
|---|
| 798 | * Detects if an MSDU frame was maliciously converted into an A-MSDU | 
|---|
| 799 | * frame by an adversary. This is done by parsing the received frame | 
|---|
| 800 | * as if it were a regular MSDU, even though the A-MSDU flag is set. | 
|---|
| 801 | * | 
|---|
| 802 | * For non-mesh interfaces, detection involves checking whether the | 
|---|
| 803 | * payload, when interpreted as an MSDU, begins with a valid RFC1042 | 
|---|
| 804 | * header. This is done by comparing the A-MSDU subheader's destination | 
|---|
| 805 | * address to the start of the RFC1042 header. | 
|---|
| 806 | * | 
|---|
| 807 | * For mesh interfaces, the MSDU includes a 6-byte Mesh Control field | 
|---|
| 808 | * and an optional variable-length Mesh Address Extension field before | 
|---|
| 809 | * the RFC1042 header. The position of the RFC1042 header must therefore | 
|---|
| 810 | * be calculated based on the mesh header length. | 
|---|
| 811 | * | 
|---|
| 812 | * Since this function intentionally parses an A-MSDU frame as an MSDU, | 
|---|
| 813 | * it only assumes that the A-MSDU subframe header is present, and | 
|---|
| 814 | * beyond this it performs its own bounds checks under the assumption | 
|---|
| 815 | * that the frame is instead parsed as a non-aggregated MSDU. | 
|---|
| 816 | */ | 
|---|
| 817 | static bool | 
|---|
| 818 | is_amsdu_aggregation_attack(struct ethhdr *eth, struct sk_buff *skb, | 
|---|
| 819 | enum nl80211_iftype iftype) | 
|---|
| 820 | { | 
|---|
| 821 | int offset; | 
|---|
| 822 |  | 
|---|
| 823 | /* Non-mesh case can be directly compared */ | 
|---|
| 824 | if (iftype != NL80211_IFTYPE_MESH_POINT) | 
|---|
| 825 | return ether_addr_equal(addr1: eth->h_dest, addr2: rfc1042_header); | 
|---|
| 826 |  | 
|---|
| 827 | offset = __ieee80211_get_mesh_hdrlen(flags: eth->h_dest[0]); | 
|---|
| 828 | if (offset == 6) { | 
|---|
| 829 | /* Mesh case with empty address extension field */ | 
|---|
| 830 | return ether_addr_equal(addr1: eth->h_source, addr2: rfc1042_header); | 
|---|
| 831 | } else if (offset + ETH_ALEN <= skb->len) { | 
|---|
| 832 | /* Mesh case with non-empty address extension field */ | 
|---|
| 833 | u8 temp[ETH_ALEN]; | 
|---|
| 834 |  | 
|---|
| 835 | skb_copy_bits(skb, offset, to: temp, ETH_ALEN); | 
|---|
| 836 | return ether_addr_equal(addr1: temp, addr2: rfc1042_header); | 
|---|
| 837 | } | 
|---|
| 838 |  | 
|---|
| 839 | return false; | 
|---|
| 840 | } | 
|---|
| 841 |  | 
|---|
| 842 | void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, | 
|---|
| 843 | const u8 *addr, enum nl80211_iftype iftype, | 
|---|
| 844 | const unsigned int , | 
|---|
| 845 | const u8 *check_da, const u8 *check_sa, | 
|---|
| 846 | u8 mesh_control) | 
|---|
| 847 | { | 
|---|
| 848 | unsigned int hlen = ALIGN(extra_headroom, 4); | 
|---|
| 849 | struct sk_buff *frame = NULL; | 
|---|
| 850 | int offset = 0; | 
|---|
| 851 | struct { | 
|---|
| 852 | struct ethhdr eth; | 
|---|
| 853 | uint8_t flags; | 
|---|
| 854 | } hdr; | 
|---|
| 855 | bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb); | 
|---|
| 856 | bool reuse_skb = false; | 
|---|
| 857 | bool last = false; | 
|---|
| 858 | int copy_len = sizeof(hdr.eth); | 
|---|
| 859 |  | 
|---|
| 860 | if (iftype == NL80211_IFTYPE_MESH_POINT) | 
|---|
| 861 | copy_len = sizeof(hdr); | 
|---|
| 862 |  | 
|---|
| 863 | while (!last) { | 
|---|
| 864 | int remaining = skb->len - offset; | 
|---|
| 865 | unsigned int subframe_len; | 
|---|
| 866 | int len, mesh_len = 0; | 
|---|
| 867 | u8 padding; | 
|---|
| 868 |  | 
|---|
| 869 | if (copy_len > remaining) | 
|---|
| 870 | goto purge; | 
|---|
| 871 |  | 
|---|
| 872 | skb_copy_bits(skb, offset, to: &hdr, len: copy_len); | 
|---|
| 873 | if (iftype == NL80211_IFTYPE_MESH_POINT) | 
|---|
| 874 | mesh_len = __ieee80211_get_mesh_hdrlen(flags: hdr.flags); | 
|---|
| 875 | len = ieee80211_amsdu_subframe_length(field: &hdr.eth.h_proto, mesh_flags: hdr.flags, | 
|---|
| 876 | hdr_type: mesh_control); | 
|---|
| 877 | subframe_len = sizeof(struct ethhdr) + len; | 
|---|
| 878 | padding = (4 - subframe_len) & 0x3; | 
|---|
| 879 |  | 
|---|
| 880 | /* the last MSDU has no padding */ | 
|---|
| 881 | if (subframe_len > remaining) | 
|---|
| 882 | goto purge; | 
|---|
| 883 | /* mitigate A-MSDU aggregation injection attacks, to be | 
|---|
| 884 | * checked when processing first subframe (offset == 0). | 
|---|
| 885 | */ | 
|---|
| 886 | if (offset == 0 && is_amsdu_aggregation_attack(eth: &hdr.eth, skb, iftype)) | 
|---|
| 887 | goto purge; | 
|---|
| 888 |  | 
|---|
| 889 | offset += sizeof(struct ethhdr); | 
|---|
| 890 | last = remaining <= subframe_len + padding; | 
|---|
| 891 |  | 
|---|
| 892 | /* FIXME: should we really accept multicast DA? */ | 
|---|
| 893 | if ((check_da && !is_multicast_ether_addr(addr: hdr.eth.h_dest) && | 
|---|
| 894 | !ether_addr_equal(addr1: check_da, addr2: hdr.eth.h_dest)) || | 
|---|
| 895 | (check_sa && !ether_addr_equal(addr1: check_sa, addr2: hdr.eth.h_source))) { | 
|---|
| 896 | offset += len + padding; | 
|---|
| 897 | continue; | 
|---|
| 898 | } | 
|---|
| 899 |  | 
|---|
| 900 | /* reuse skb for the last subframe */ | 
|---|
| 901 | if (!skb_is_nonlinear(skb) && !reuse_frag && last) { | 
|---|
| 902 | skb_pull(skb, len: offset); | 
|---|
| 903 | frame = skb; | 
|---|
| 904 | reuse_skb = true; | 
|---|
| 905 | } else { | 
|---|
| 906 | frame = __ieee80211_amsdu_copy(skb, hlen, offset, len, | 
|---|
| 907 | reuse_frag, min_len: 32 + mesh_len); | 
|---|
| 908 | if (!frame) | 
|---|
| 909 | goto purge; | 
|---|
| 910 |  | 
|---|
| 911 | offset += len + padding; | 
|---|
| 912 | } | 
|---|
| 913 |  | 
|---|
| 914 | skb_reset_network_header(skb: frame); | 
|---|
| 915 | frame->dev = skb->dev; | 
|---|
| 916 | frame->priority = skb->priority; | 
|---|
| 917 |  | 
|---|
| 918 | if (likely(iftype != NL80211_IFTYPE_MESH_POINT && | 
|---|
| 919 | ieee80211_get_8023_tunnel_proto(frame->data, &hdr.eth.h_proto))) | 
|---|
| 920 | skb_pull(skb: frame, ETH_ALEN + 2); | 
|---|
| 921 |  | 
|---|
| 922 | memcpy(to: skb_push(skb: frame, len: sizeof(hdr.eth)), from: &hdr.eth, len: sizeof(hdr.eth)); | 
|---|
| 923 | __skb_queue_tail(list, newsk: frame); | 
|---|
| 924 | } | 
|---|
| 925 |  | 
|---|
| 926 | if (!reuse_skb) | 
|---|
| 927 | dev_kfree_skb(skb); | 
|---|
| 928 |  | 
|---|
| 929 | return; | 
|---|
| 930 |  | 
|---|
| 931 | purge: | 
|---|
| 932 | __skb_queue_purge(list); | 
|---|
| 933 | dev_kfree_skb(skb); | 
|---|
| 934 | } | 
|---|
| 935 | EXPORT_SYMBOL(ieee80211_amsdu_to_8023s); | 
|---|
| 936 |  | 
|---|
| 937 | /* Given a data frame determine the 802.1p/1d tag to use. */ | 
|---|
| 938 | unsigned int cfg80211_classify8021d(struct sk_buff *skb, | 
|---|
| 939 | struct cfg80211_qos_map *qos_map) | 
|---|
| 940 | { | 
|---|
| 941 | unsigned int dscp; | 
|---|
| 942 | unsigned char vlan_priority; | 
|---|
| 943 | unsigned int ret; | 
|---|
| 944 |  | 
|---|
| 945 | /* skb->priority values from 256->263 are magic values to | 
|---|
| 946 | * directly indicate a specific 802.1d priority.  This is used | 
|---|
| 947 | * to allow 802.1d priority to be passed directly in from VLAN | 
|---|
| 948 | * tags, etc. | 
|---|
| 949 | */ | 
|---|
| 950 | if (skb->priority >= 256 && skb->priority <= 263) { | 
|---|
| 951 | ret = skb->priority - 256; | 
|---|
| 952 | goto out; | 
|---|
| 953 | } | 
|---|
| 954 |  | 
|---|
| 955 | if (skb_vlan_tag_present(skb)) { | 
|---|
| 956 | vlan_priority = (skb_vlan_tag_get(skb) & VLAN_PRIO_MASK) | 
|---|
| 957 | >> VLAN_PRIO_SHIFT; | 
|---|
| 958 | if (vlan_priority > 0) { | 
|---|
| 959 | ret = vlan_priority; | 
|---|
| 960 | goto out; | 
|---|
| 961 | } | 
|---|
| 962 | } | 
|---|
| 963 |  | 
|---|
| 964 | switch (skb->protocol) { | 
|---|
| 965 | case htons(ETH_P_IP): | 
|---|
| 966 | dscp = ipv4_get_dsfield(iph: ip_hdr(skb)) & 0xfc; | 
|---|
| 967 | break; | 
|---|
| 968 | case htons(ETH_P_IPV6): | 
|---|
| 969 | dscp = ipv6_get_dsfield(ipv6h: ipv6_hdr(skb)) & 0xfc; | 
|---|
| 970 | break; | 
|---|
| 971 | case htons(ETH_P_MPLS_UC): | 
|---|
| 972 | case htons(ETH_P_MPLS_MC): { | 
|---|
| 973 | struct mpls_label mpls_tmp, *mpls; | 
|---|
| 974 |  | 
|---|
| 975 | mpls = skb_header_pointer(skb, offset: sizeof(struct ethhdr), | 
|---|
| 976 | len: sizeof(*mpls), buffer: &mpls_tmp); | 
|---|
| 977 | if (!mpls) | 
|---|
| 978 | return 0; | 
|---|
| 979 |  | 
|---|
| 980 | ret = (ntohl(mpls->entry) & MPLS_LS_TC_MASK) | 
|---|
| 981 | >> MPLS_LS_TC_SHIFT; | 
|---|
| 982 | goto out; | 
|---|
| 983 | } | 
|---|
| 984 | case htons(ETH_P_80221): | 
|---|
| 985 | /* 802.21 is always network control traffic */ | 
|---|
| 986 | return 7; | 
|---|
| 987 | default: | 
|---|
| 988 | return 0; | 
|---|
| 989 | } | 
|---|
| 990 |  | 
|---|
| 991 | if (qos_map) { | 
|---|
| 992 | unsigned int i, tmp_dscp = dscp >> 2; | 
|---|
| 993 |  | 
|---|
| 994 | for (i = 0; i < qos_map->num_des; i++) { | 
|---|
| 995 | if (tmp_dscp == qos_map->dscp_exception[i].dscp) { | 
|---|
| 996 | ret = qos_map->dscp_exception[i].up; | 
|---|
| 997 | goto out; | 
|---|
| 998 | } | 
|---|
| 999 | } | 
|---|
| 1000 |  | 
|---|
| 1001 | for (i = 0; i < 8; i++) { | 
|---|
| 1002 | if (tmp_dscp >= qos_map->up[i].low && | 
|---|
| 1003 | tmp_dscp <= qos_map->up[i].high) { | 
|---|
| 1004 | ret = i; | 
|---|
| 1005 | goto out; | 
|---|
| 1006 | } | 
|---|
| 1007 | } | 
|---|
| 1008 | } | 
|---|
| 1009 |  | 
|---|
| 1010 | /* The default mapping as defined Section 2.3 in RFC8325: The three | 
|---|
| 1011 | * Most Significant Bits (MSBs) of the DSCP are used as the | 
|---|
| 1012 | * corresponding L2 markings. | 
|---|
| 1013 | */ | 
|---|
| 1014 | ret = dscp >> 5; | 
|---|
| 1015 |  | 
|---|
| 1016 | /* Handle specific DSCP values for which the default mapping (as | 
|---|
| 1017 | * described above) doesn't adhere to the intended usage of the DSCP | 
|---|
| 1018 | * value. See section 4 in RFC8325. Specifically, for the following | 
|---|
| 1019 | * Diffserv Service Classes no update is needed: | 
|---|
| 1020 | * - Standard: DF | 
|---|
| 1021 | * - Low Priority Data: CS1 | 
|---|
| 1022 | * - Multimedia Conferencing: AF41, AF42, AF43 | 
|---|
| 1023 | * - Network Control Traffic: CS7 | 
|---|
| 1024 | * - Real-Time Interactive: CS4 | 
|---|
| 1025 | * - Signaling: CS5 | 
|---|
| 1026 | */ | 
|---|
| 1027 | switch (dscp >> 2) { | 
|---|
| 1028 | case 10: | 
|---|
| 1029 | case 12: | 
|---|
| 1030 | case 14: | 
|---|
| 1031 | /* High throughput data: AF11, AF12, AF13 */ | 
|---|
| 1032 | ret = 0; | 
|---|
| 1033 | break; | 
|---|
| 1034 | case 16: | 
|---|
| 1035 | /* Operations, Administration, and Maintenance and Provisioning: | 
|---|
| 1036 | * CS2 | 
|---|
| 1037 | */ | 
|---|
| 1038 | ret = 0; | 
|---|
| 1039 | break; | 
|---|
| 1040 | case 18: | 
|---|
| 1041 | case 20: | 
|---|
| 1042 | case 22: | 
|---|
| 1043 | /* Low latency data: AF21, AF22, AF23 */ | 
|---|
| 1044 | ret = 3; | 
|---|
| 1045 | break; | 
|---|
| 1046 | case 24: | 
|---|
| 1047 | /* Broadcasting video: CS3 */ | 
|---|
| 1048 | ret = 4; | 
|---|
| 1049 | break; | 
|---|
| 1050 | case 26: | 
|---|
| 1051 | case 28: | 
|---|
| 1052 | case 30: | 
|---|
| 1053 | /* Multimedia Streaming: AF31, AF32, AF33 */ | 
|---|
| 1054 | ret = 4; | 
|---|
| 1055 | break; | 
|---|
| 1056 | case 44: | 
|---|
| 1057 | /* Voice Admit: VA */ | 
|---|
| 1058 | ret = 6; | 
|---|
| 1059 | break; | 
|---|
| 1060 | case 46: | 
|---|
| 1061 | /* Telephony traffic: EF */ | 
|---|
| 1062 | ret = 6; | 
|---|
| 1063 | break; | 
|---|
| 1064 | case 48: | 
|---|
| 1065 | /* Network Control Traffic: CS6 */ | 
|---|
| 1066 | ret = 7; | 
|---|
| 1067 | break; | 
|---|
| 1068 | } | 
|---|
| 1069 | out: | 
|---|
| 1070 | return array_index_nospec(ret, IEEE80211_NUM_TIDS); | 
|---|
| 1071 | } | 
|---|
| 1072 | EXPORT_SYMBOL(cfg80211_classify8021d); | 
|---|
| 1073 |  | 
|---|
| 1074 | const struct element *ieee80211_bss_get_elem(struct cfg80211_bss *bss, u8 id) | 
|---|
| 1075 | { | 
|---|
| 1076 | const struct cfg80211_bss_ies *ies; | 
|---|
| 1077 |  | 
|---|
| 1078 | ies = rcu_dereference(bss->ies); | 
|---|
| 1079 | if (!ies) | 
|---|
| 1080 | return NULL; | 
|---|
| 1081 |  | 
|---|
| 1082 | return cfg80211_find_elem(eid: id, ies: ies->data, len: ies->len); | 
|---|
| 1083 | } | 
|---|
| 1084 | EXPORT_SYMBOL(ieee80211_bss_get_elem); | 
|---|
| 1085 |  | 
|---|
| 1086 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev) | 
|---|
| 1087 | { | 
|---|
| 1088 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy: wdev->wiphy); | 
|---|
| 1089 | struct net_device *dev = wdev->netdev; | 
|---|
| 1090 | int i; | 
|---|
| 1091 |  | 
|---|
| 1092 | if (!wdev->connect_keys) | 
|---|
| 1093 | return; | 
|---|
| 1094 |  | 
|---|
| 1095 | for (i = 0; i < 4; i++) { | 
|---|
| 1096 | if (!wdev->connect_keys->params[i].cipher) | 
|---|
| 1097 | continue; | 
|---|
| 1098 | if (rdev_add_key(rdev, netdev: dev, link_id: -1, key_index: i, pairwise: false, NULL, | 
|---|
| 1099 | params: &wdev->connect_keys->params[i])) { | 
|---|
| 1100 | netdev_err(dev, format: "failed to set key %d\n", i); | 
|---|
| 1101 | continue; | 
|---|
| 1102 | } | 
|---|
| 1103 | if (wdev->connect_keys->def == i && | 
|---|
| 1104 | rdev_set_default_key(rdev, netdev: dev, link_id: -1, key_index: i, unicast: true, multicast: true)) { | 
|---|
| 1105 | netdev_err(dev, format: "failed to set defkey %d\n", i); | 
|---|
| 1106 | continue; | 
|---|
| 1107 | } | 
|---|
| 1108 | } | 
|---|
| 1109 |  | 
|---|
| 1110 | kfree_sensitive(objp: wdev->connect_keys); | 
|---|
| 1111 | wdev->connect_keys = NULL; | 
|---|
| 1112 | } | 
|---|
| 1113 |  | 
|---|
| 1114 | void cfg80211_process_wdev_events(struct wireless_dev *wdev) | 
|---|
| 1115 | { | 
|---|
| 1116 | struct cfg80211_event *ev; | 
|---|
| 1117 | unsigned long flags; | 
|---|
| 1118 |  | 
|---|
| 1119 | spin_lock_irqsave(&wdev->event_lock, flags); | 
|---|
| 1120 | while (!list_empty(head: &wdev->event_list)) { | 
|---|
| 1121 | ev = list_first_entry(&wdev->event_list, | 
|---|
| 1122 | struct cfg80211_event, list); | 
|---|
| 1123 | list_del(entry: &ev->list); | 
|---|
| 1124 | spin_unlock_irqrestore(lock: &wdev->event_lock, flags); | 
|---|
| 1125 |  | 
|---|
| 1126 | switch (ev->type) { | 
|---|
| 1127 | case EVENT_CONNECT_RESULT: | 
|---|
| 1128 | __cfg80211_connect_result( | 
|---|
| 1129 | dev: wdev->netdev, | 
|---|
| 1130 | params: &ev->cr, | 
|---|
| 1131 | wextev: ev->cr.status == WLAN_STATUS_SUCCESS); | 
|---|
| 1132 | break; | 
|---|
| 1133 | case EVENT_ROAMED: | 
|---|
| 1134 | __cfg80211_roamed(wdev, info: &ev->rm); | 
|---|
| 1135 | break; | 
|---|
| 1136 | case EVENT_DISCONNECTED: | 
|---|
| 1137 | __cfg80211_disconnected(dev: wdev->netdev, | 
|---|
| 1138 | ie: ev->dc.ie, ie_len: ev->dc.ie_len, | 
|---|
| 1139 | reason: ev->dc.reason, | 
|---|
| 1140 | from_ap: !ev->dc.locally_generated); | 
|---|
| 1141 | break; | 
|---|
| 1142 | case EVENT_IBSS_JOINED: | 
|---|
| 1143 | __cfg80211_ibss_joined(dev: wdev->netdev, bssid: ev->ij.bssid, | 
|---|
| 1144 | channel: ev->ij.channel); | 
|---|
| 1145 | break; | 
|---|
| 1146 | case EVENT_STOPPED: | 
|---|
| 1147 | cfg80211_leave(rdev: wiphy_to_rdev(wiphy: wdev->wiphy), wdev); | 
|---|
| 1148 | break; | 
|---|
| 1149 | case EVENT_PORT_AUTHORIZED: | 
|---|
| 1150 | __cfg80211_port_authorized(wdev, peer_addr: ev->pa.peer_addr, | 
|---|
| 1151 | td_bitmap: ev->pa.td_bitmap, | 
|---|
| 1152 | td_bitmap_len: ev->pa.td_bitmap_len); | 
|---|
| 1153 | break; | 
|---|
| 1154 | } | 
|---|
| 1155 |  | 
|---|
| 1156 | kfree(objp: ev); | 
|---|
| 1157 |  | 
|---|
| 1158 | spin_lock_irqsave(&wdev->event_lock, flags); | 
|---|
| 1159 | } | 
|---|
| 1160 | spin_unlock_irqrestore(lock: &wdev->event_lock, flags); | 
|---|
| 1161 | } | 
|---|
| 1162 |  | 
|---|
| 1163 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) | 
|---|
| 1164 | { | 
|---|
| 1165 | struct wireless_dev *wdev; | 
|---|
| 1166 |  | 
|---|
| 1167 | lockdep_assert_held(&rdev->wiphy.mtx); | 
|---|
| 1168 |  | 
|---|
| 1169 | list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) | 
|---|
| 1170 | cfg80211_process_wdev_events(wdev); | 
|---|
| 1171 | } | 
|---|
| 1172 |  | 
|---|
| 1173 | int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | 
|---|
| 1174 | struct net_device *dev, enum nl80211_iftype ntype, | 
|---|
| 1175 | struct vif_params *params) | 
|---|
| 1176 | { | 
|---|
| 1177 | int err; | 
|---|
| 1178 | enum nl80211_iftype otype = dev->ieee80211_ptr->iftype; | 
|---|
| 1179 |  | 
|---|
| 1180 | lockdep_assert_held(&rdev->wiphy.mtx); | 
|---|
| 1181 |  | 
|---|
| 1182 | /* don't support changing VLANs, you just re-create them */ | 
|---|
| 1183 | if (otype == NL80211_IFTYPE_AP_VLAN) | 
|---|
| 1184 | return -EOPNOTSUPP; | 
|---|
| 1185 |  | 
|---|
| 1186 | /* cannot change into P2P device or NAN */ | 
|---|
| 1187 | if (ntype == NL80211_IFTYPE_P2P_DEVICE || | 
|---|
| 1188 | ntype == NL80211_IFTYPE_NAN) | 
|---|
| 1189 | return -EOPNOTSUPP; | 
|---|
| 1190 |  | 
|---|
| 1191 | if (!rdev->ops->change_virtual_intf || | 
|---|
| 1192 | !(rdev->wiphy.interface_modes & (1 << ntype))) | 
|---|
| 1193 | return -EOPNOTSUPP; | 
|---|
| 1194 |  | 
|---|
| 1195 | if (ntype != otype) { | 
|---|
| 1196 | /* if it's part of a bridge, reject changing type to station/ibss */ | 
|---|
| 1197 | if (netif_is_bridge_port(dev) && | 
|---|
| 1198 | (ntype == NL80211_IFTYPE_ADHOC || | 
|---|
| 1199 | ntype == NL80211_IFTYPE_STATION || | 
|---|
| 1200 | ntype == NL80211_IFTYPE_P2P_CLIENT)) | 
|---|
| 1201 | return -EBUSY; | 
|---|
| 1202 |  | 
|---|
| 1203 | dev->ieee80211_ptr->use_4addr = false; | 
|---|
| 1204 | rdev_set_qos_map(rdev, dev, NULL); | 
|---|
| 1205 |  | 
|---|
| 1206 | switch (otype) { | 
|---|
| 1207 | case NL80211_IFTYPE_AP: | 
|---|
| 1208 | case NL80211_IFTYPE_P2P_GO: | 
|---|
| 1209 | cfg80211_stop_ap(rdev, dev, link: -1, notify: true); | 
|---|
| 1210 | break; | 
|---|
| 1211 | case NL80211_IFTYPE_ADHOC: | 
|---|
| 1212 | cfg80211_leave_ibss(rdev, dev, nowext: false); | 
|---|
| 1213 | break; | 
|---|
| 1214 | case NL80211_IFTYPE_STATION: | 
|---|
| 1215 | case NL80211_IFTYPE_P2P_CLIENT: | 
|---|
| 1216 | cfg80211_disconnect(rdev, dev, | 
|---|
| 1217 | reason: WLAN_REASON_DEAUTH_LEAVING, wextev: true); | 
|---|
| 1218 | break; | 
|---|
| 1219 | case NL80211_IFTYPE_MESH_POINT: | 
|---|
| 1220 | /* mesh should be handled? */ | 
|---|
| 1221 | break; | 
|---|
| 1222 | case NL80211_IFTYPE_OCB: | 
|---|
| 1223 | cfg80211_leave_ocb(rdev, dev); | 
|---|
| 1224 | break; | 
|---|
| 1225 | default: | 
|---|
| 1226 | break; | 
|---|
| 1227 | } | 
|---|
| 1228 |  | 
|---|
| 1229 | cfg80211_process_rdev_events(rdev); | 
|---|
| 1230 | cfg80211_mlme_purge_registrations(wdev: dev->ieee80211_ptr); | 
|---|
| 1231 |  | 
|---|
| 1232 | memset(s: &dev->ieee80211_ptr->u, c: 0, | 
|---|
| 1233 | n: sizeof(dev->ieee80211_ptr->u)); | 
|---|
| 1234 | memset(s: &dev->ieee80211_ptr->links, c: 0, | 
|---|
| 1235 | n: sizeof(dev->ieee80211_ptr->links)); | 
|---|
| 1236 | } | 
|---|
| 1237 |  | 
|---|
| 1238 | err = rdev_change_virtual_intf(rdev, dev, type: ntype, params); | 
|---|
| 1239 |  | 
|---|
| 1240 | WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); | 
|---|
| 1241 |  | 
|---|
| 1242 | if (!err && params && params->use_4addr != -1) | 
|---|
| 1243 | dev->ieee80211_ptr->use_4addr = params->use_4addr; | 
|---|
| 1244 |  | 
|---|
| 1245 | if (!err) { | 
|---|
| 1246 | dev->priv_flags &= ~IFF_DONT_BRIDGE; | 
|---|
| 1247 | switch (ntype) { | 
|---|
| 1248 | case NL80211_IFTYPE_STATION: | 
|---|
| 1249 | if (dev->ieee80211_ptr->use_4addr) | 
|---|
| 1250 | break; | 
|---|
| 1251 | fallthrough; | 
|---|
| 1252 | case NL80211_IFTYPE_OCB: | 
|---|
| 1253 | case NL80211_IFTYPE_P2P_CLIENT: | 
|---|
| 1254 | case NL80211_IFTYPE_ADHOC: | 
|---|
| 1255 | dev->priv_flags |= IFF_DONT_BRIDGE; | 
|---|
| 1256 | break; | 
|---|
| 1257 | case NL80211_IFTYPE_P2P_GO: | 
|---|
| 1258 | case NL80211_IFTYPE_AP: | 
|---|
| 1259 | case NL80211_IFTYPE_AP_VLAN: | 
|---|
| 1260 | case NL80211_IFTYPE_MESH_POINT: | 
|---|
| 1261 | /* bridging OK */ | 
|---|
| 1262 | break; | 
|---|
| 1263 | case NL80211_IFTYPE_MONITOR: | 
|---|
| 1264 | /* monitor can't bridge anyway */ | 
|---|
| 1265 | break; | 
|---|
| 1266 | case NL80211_IFTYPE_UNSPECIFIED: | 
|---|
| 1267 | case NUM_NL80211_IFTYPES: | 
|---|
| 1268 | /* not happening */ | 
|---|
| 1269 | break; | 
|---|
| 1270 | case NL80211_IFTYPE_P2P_DEVICE: | 
|---|
| 1271 | case NL80211_IFTYPE_WDS: | 
|---|
| 1272 | case NL80211_IFTYPE_NAN: | 
|---|
| 1273 | WARN_ON(1); | 
|---|
| 1274 | break; | 
|---|
| 1275 | } | 
|---|
| 1276 | } | 
|---|
| 1277 |  | 
|---|
| 1278 | if (!err && ntype != otype && netif_running(dev)) { | 
|---|
| 1279 | cfg80211_update_iface_num(rdev, iftype: ntype, num: 1); | 
|---|
| 1280 | cfg80211_update_iface_num(rdev, iftype: otype, num: -1); | 
|---|
| 1281 | } | 
|---|
| 1282 |  | 
|---|
| 1283 | return err; | 
|---|
| 1284 | } | 
|---|
| 1285 |  | 
|---|
| 1286 | static u32 cfg80211_calculate_bitrate_ht(struct rate_info *rate) | 
|---|
| 1287 | { | 
|---|
| 1288 | int modulation, streams, bitrate; | 
|---|
| 1289 |  | 
|---|
| 1290 | /* the formula below does only work for MCS values smaller than 32 */ | 
|---|
| 1291 | if (WARN_ON_ONCE(rate->mcs >= 32)) | 
|---|
| 1292 | return 0; | 
|---|
| 1293 |  | 
|---|
| 1294 | modulation = rate->mcs & 7; | 
|---|
| 1295 | streams = (rate->mcs >> 3) + 1; | 
|---|
| 1296 |  | 
|---|
| 1297 | bitrate = (rate->bw == RATE_INFO_BW_40) ? 13500000 : 6500000; | 
|---|
| 1298 |  | 
|---|
| 1299 | if (modulation < 4) | 
|---|
| 1300 | bitrate *= (modulation + 1); | 
|---|
| 1301 | else if (modulation == 4) | 
|---|
| 1302 | bitrate *= (modulation + 2); | 
|---|
| 1303 | else | 
|---|
| 1304 | bitrate *= (modulation + 3); | 
|---|
| 1305 |  | 
|---|
| 1306 | bitrate *= streams; | 
|---|
| 1307 |  | 
|---|
| 1308 | if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) | 
|---|
| 1309 | bitrate = (bitrate / 9) * 10; | 
|---|
| 1310 |  | 
|---|
| 1311 | /* do NOT round down here */ | 
|---|
| 1312 | return (bitrate + 50000) / 100000; | 
|---|
| 1313 | } | 
|---|
| 1314 |  | 
|---|
| 1315 | static u32 cfg80211_calculate_bitrate_dmg(struct rate_info *rate) | 
|---|
| 1316 | { | 
|---|
| 1317 | static const u32 __mcs2bitrate[] = { | 
|---|
| 1318 | /* control PHY */ | 
|---|
| 1319 | [0] =   275, | 
|---|
| 1320 | /* SC PHY */ | 
|---|
| 1321 | [1] =  3850, | 
|---|
| 1322 | [2] =  7700, | 
|---|
| 1323 | [3] =  9625, | 
|---|
| 1324 | [4] = 11550, | 
|---|
| 1325 | [5] = 12512, /* 1251.25 mbps */ | 
|---|
| 1326 | [6] = 15400, | 
|---|
| 1327 | [7] = 19250, | 
|---|
| 1328 | [8] = 23100, | 
|---|
| 1329 | [9] = 25025, | 
|---|
| 1330 | [10] = 30800, | 
|---|
| 1331 | [11] = 38500, | 
|---|
| 1332 | [12] = 46200, | 
|---|
| 1333 | /* OFDM PHY */ | 
|---|
| 1334 | [13] =  6930, | 
|---|
| 1335 | [14] =  8662, /* 866.25 mbps */ | 
|---|
| 1336 | [15] = 13860, | 
|---|
| 1337 | [16] = 17325, | 
|---|
| 1338 | [17] = 20790, | 
|---|
| 1339 | [18] = 27720, | 
|---|
| 1340 | [19] = 34650, | 
|---|
| 1341 | [20] = 41580, | 
|---|
| 1342 | [21] = 45045, | 
|---|
| 1343 | [22] = 51975, | 
|---|
| 1344 | [23] = 62370, | 
|---|
| 1345 | [24] = 67568, /* 6756.75 mbps */ | 
|---|
| 1346 | /* LP-SC PHY */ | 
|---|
| 1347 | [25] =  6260, | 
|---|
| 1348 | [26] =  8340, | 
|---|
| 1349 | [27] = 11120, | 
|---|
| 1350 | [28] = 12510, | 
|---|
| 1351 | [29] = 16680, | 
|---|
| 1352 | [30] = 22240, | 
|---|
| 1353 | [31] = 25030, | 
|---|
| 1354 | }; | 
|---|
| 1355 |  | 
|---|
| 1356 | if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate))) | 
|---|
| 1357 | return 0; | 
|---|
| 1358 |  | 
|---|
| 1359 | return __mcs2bitrate[rate->mcs]; | 
|---|
| 1360 | } | 
|---|
| 1361 |  | 
|---|
| 1362 | static u32 cfg80211_calculate_bitrate_extended_sc_dmg(struct rate_info *rate) | 
|---|
| 1363 | { | 
|---|
| 1364 | static const u32 __mcs2bitrate[] = { | 
|---|
| 1365 | [6 - 6] = 26950, /* MCS 9.1 : 2695.0 mbps */ | 
|---|
| 1366 | [7 - 6] = 50050, /* MCS 12.1 */ | 
|---|
| 1367 | [8 - 6] = 53900, | 
|---|
| 1368 | [9 - 6] = 57750, | 
|---|
| 1369 | [10 - 6] = 63900, | 
|---|
| 1370 | [11 - 6] = 75075, | 
|---|
| 1371 | [12 - 6] = 80850, | 
|---|
| 1372 | }; | 
|---|
| 1373 |  | 
|---|
| 1374 | /* Extended SC MCS not defined for base MCS below 6 or above 12 */ | 
|---|
| 1375 | if (WARN_ON_ONCE(rate->mcs < 6 || rate->mcs > 12)) | 
|---|
| 1376 | return 0; | 
|---|
| 1377 |  | 
|---|
| 1378 | return __mcs2bitrate[rate->mcs - 6]; | 
|---|
| 1379 | } | 
|---|
| 1380 |  | 
|---|
| 1381 | static u32 cfg80211_calculate_bitrate_edmg(struct rate_info *rate) | 
|---|
| 1382 | { | 
|---|
| 1383 | static const u32 __mcs2bitrate[] = { | 
|---|
| 1384 | /* control PHY */ | 
|---|
| 1385 | [0] =   275, | 
|---|
| 1386 | /* SC PHY */ | 
|---|
| 1387 | [1] =  3850, | 
|---|
| 1388 | [2] =  7700, | 
|---|
| 1389 | [3] =  9625, | 
|---|
| 1390 | [4] = 11550, | 
|---|
| 1391 | [5] = 12512, /* 1251.25 mbps */ | 
|---|
| 1392 | [6] = 13475, | 
|---|
| 1393 | [7] = 15400, | 
|---|
| 1394 | [8] = 19250, | 
|---|
| 1395 | [9] = 23100, | 
|---|
| 1396 | [10] = 25025, | 
|---|
| 1397 | [11] = 26950, | 
|---|
| 1398 | [12] = 30800, | 
|---|
| 1399 | [13] = 38500, | 
|---|
| 1400 | [14] = 46200, | 
|---|
| 1401 | [15] = 50050, | 
|---|
| 1402 | [16] = 53900, | 
|---|
| 1403 | [17] = 57750, | 
|---|
| 1404 | [18] = 69300, | 
|---|
| 1405 | [19] = 75075, | 
|---|
| 1406 | [20] = 80850, | 
|---|
| 1407 | }; | 
|---|
| 1408 |  | 
|---|
| 1409 | if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate))) | 
|---|
| 1410 | return 0; | 
|---|
| 1411 |  | 
|---|
| 1412 | return __mcs2bitrate[rate->mcs] * rate->n_bonded_ch; | 
|---|
| 1413 | } | 
|---|
| 1414 |  | 
|---|
| 1415 | static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate) | 
|---|
| 1416 | { | 
|---|
| 1417 | static const u32 base[4][12] = { | 
|---|
| 1418 | {   6500000, | 
|---|
| 1419 | 13000000, | 
|---|
| 1420 | 19500000, | 
|---|
| 1421 | 26000000, | 
|---|
| 1422 | 39000000, | 
|---|
| 1423 | 52000000, | 
|---|
| 1424 | 58500000, | 
|---|
| 1425 | 65000000, | 
|---|
| 1426 | 78000000, | 
|---|
| 1427 | /* not in the spec, but some devices use this: */ | 
|---|
| 1428 | 86700000, | 
|---|
| 1429 | 97500000, | 
|---|
| 1430 | 108300000, | 
|---|
| 1431 | }, | 
|---|
| 1432 | {  13500000, | 
|---|
| 1433 | 27000000, | 
|---|
| 1434 | 40500000, | 
|---|
| 1435 | 54000000, | 
|---|
| 1436 | 81000000, | 
|---|
| 1437 | 108000000, | 
|---|
| 1438 | 121500000, | 
|---|
| 1439 | 135000000, | 
|---|
| 1440 | 162000000, | 
|---|
| 1441 | 180000000, | 
|---|
| 1442 | 202500000, | 
|---|
| 1443 | 225000000, | 
|---|
| 1444 | }, | 
|---|
| 1445 | {  29300000, | 
|---|
| 1446 | 58500000, | 
|---|
| 1447 | 87800000, | 
|---|
| 1448 | 117000000, | 
|---|
| 1449 | 175500000, | 
|---|
| 1450 | 234000000, | 
|---|
| 1451 | 263300000, | 
|---|
| 1452 | 292500000, | 
|---|
| 1453 | 351000000, | 
|---|
| 1454 | 390000000, | 
|---|
| 1455 | 438800000, | 
|---|
| 1456 | 487500000, | 
|---|
| 1457 | }, | 
|---|
| 1458 | {  58500000, | 
|---|
| 1459 | 117000000, | 
|---|
| 1460 | 175500000, | 
|---|
| 1461 | 234000000, | 
|---|
| 1462 | 351000000, | 
|---|
| 1463 | 468000000, | 
|---|
| 1464 | 526500000, | 
|---|
| 1465 | 585000000, | 
|---|
| 1466 | 702000000, | 
|---|
| 1467 | 780000000, | 
|---|
| 1468 | 877500000, | 
|---|
| 1469 | 975000000, | 
|---|
| 1470 | }, | 
|---|
| 1471 | }; | 
|---|
| 1472 | u32 bitrate; | 
|---|
| 1473 | int idx; | 
|---|
| 1474 |  | 
|---|
| 1475 | if (rate->mcs > 11) | 
|---|
| 1476 | goto warn; | 
|---|
| 1477 |  | 
|---|
| 1478 | switch (rate->bw) { | 
|---|
| 1479 | case RATE_INFO_BW_160: | 
|---|
| 1480 | idx = 3; | 
|---|
| 1481 | break; | 
|---|
| 1482 | case RATE_INFO_BW_80: | 
|---|
| 1483 | idx = 2; | 
|---|
| 1484 | break; | 
|---|
| 1485 | case RATE_INFO_BW_40: | 
|---|
| 1486 | idx = 1; | 
|---|
| 1487 | break; | 
|---|
| 1488 | case RATE_INFO_BW_5: | 
|---|
| 1489 | case RATE_INFO_BW_10: | 
|---|
| 1490 | default: | 
|---|
| 1491 | goto warn; | 
|---|
| 1492 | case RATE_INFO_BW_20: | 
|---|
| 1493 | idx = 0; | 
|---|
| 1494 | } | 
|---|
| 1495 |  | 
|---|
| 1496 | bitrate = base[idx][rate->mcs]; | 
|---|
| 1497 | bitrate *= rate->nss; | 
|---|
| 1498 |  | 
|---|
| 1499 | if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) | 
|---|
| 1500 | bitrate = (bitrate / 9) * 10; | 
|---|
| 1501 |  | 
|---|
| 1502 | /* do NOT round down here */ | 
|---|
| 1503 | return (bitrate + 50000) / 100000; | 
|---|
| 1504 | warn: | 
|---|
| 1505 | WARN_ONCE(1, "invalid rate bw=%d, mcs=%d, nss=%d\n", | 
|---|
| 1506 | rate->bw, rate->mcs, rate->nss); | 
|---|
| 1507 | return 0; | 
|---|
| 1508 | } | 
|---|
| 1509 |  | 
|---|
| 1510 | static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate) | 
|---|
| 1511 | { | 
|---|
| 1512 | #define SCALE 6144 | 
|---|
| 1513 | u32 mcs_divisors[14] = { | 
|---|
| 1514 | 102399, /* 16.666666... */ | 
|---|
| 1515 | 51201, /*  8.333333... */ | 
|---|
| 1516 | 34134, /*  5.555555... */ | 
|---|
| 1517 | 25599, /*  4.166666... */ | 
|---|
| 1518 | 17067, /*  2.777777... */ | 
|---|
| 1519 | 12801, /*  2.083333... */ | 
|---|
| 1520 | 11377, /*  1.851725... */ | 
|---|
| 1521 | 10239, /*  1.666666... */ | 
|---|
| 1522 | 8532, /*  1.388888... */ | 
|---|
| 1523 | 7680, /*  1.250000... */ | 
|---|
| 1524 | 6828, /*  1.111111... */ | 
|---|
| 1525 | 6144, /*  1.000000... */ | 
|---|
| 1526 | 5690, /*  0.926106... */ | 
|---|
| 1527 | 5120, /*  0.833333... */ | 
|---|
| 1528 | }; | 
|---|
| 1529 | u32 rates_160M[3] = { 960777777, 907400000, 816666666 }; | 
|---|
| 1530 | u32 rates_996[3] =  { 480388888, 453700000, 408333333 }; | 
|---|
| 1531 | u32 rates_484[3] =  { 229411111, 216666666, 195000000 }; | 
|---|
| 1532 | u32 rates_242[3] =  { 114711111, 108333333,  97500000 }; | 
|---|
| 1533 | u32 rates_106[3] =  {  40000000,  37777777,  34000000 }; | 
|---|
| 1534 | u32 rates_52[3]  =  {  18820000,  17777777,  16000000 }; | 
|---|
| 1535 | u32 rates_26[3]  =  {   9411111,   8888888,   8000000 }; | 
|---|
| 1536 | u64 tmp; | 
|---|
| 1537 | u32 result; | 
|---|
| 1538 |  | 
|---|
| 1539 | if (WARN_ON_ONCE(rate->mcs > 13)) | 
|---|
| 1540 | return 0; | 
|---|
| 1541 |  | 
|---|
| 1542 | if (WARN_ON_ONCE(rate->he_gi > NL80211_RATE_INFO_HE_GI_3_2)) | 
|---|
| 1543 | return 0; | 
|---|
| 1544 | if (WARN_ON_ONCE(rate->he_ru_alloc > | 
|---|
| 1545 | NL80211_RATE_INFO_HE_RU_ALLOC_2x996)) | 
|---|
| 1546 | return 0; | 
|---|
| 1547 | if (WARN_ON_ONCE(rate->nss < 1 || rate->nss > 8)) | 
|---|
| 1548 | return 0; | 
|---|
| 1549 |  | 
|---|
| 1550 | if (rate->bw == RATE_INFO_BW_160 || | 
|---|
| 1551 | (rate->bw == RATE_INFO_BW_HE_RU && | 
|---|
| 1552 | rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_2x996)) | 
|---|
| 1553 | result = rates_160M[rate->he_gi]; | 
|---|
| 1554 | else if (rate->bw == RATE_INFO_BW_80 || | 
|---|
| 1555 | (rate->bw == RATE_INFO_BW_HE_RU && | 
|---|
| 1556 | rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_996)) | 
|---|
| 1557 | result = rates_996[rate->he_gi]; | 
|---|
| 1558 | else if (rate->bw == RATE_INFO_BW_40 || | 
|---|
| 1559 | (rate->bw == RATE_INFO_BW_HE_RU && | 
|---|
| 1560 | rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_484)) | 
|---|
| 1561 | result = rates_484[rate->he_gi]; | 
|---|
| 1562 | else if (rate->bw == RATE_INFO_BW_20 || | 
|---|
| 1563 | (rate->bw == RATE_INFO_BW_HE_RU && | 
|---|
| 1564 | rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_242)) | 
|---|
| 1565 | result = rates_242[rate->he_gi]; | 
|---|
| 1566 | else if (rate->bw == RATE_INFO_BW_HE_RU && | 
|---|
| 1567 | rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_106) | 
|---|
| 1568 | result = rates_106[rate->he_gi]; | 
|---|
| 1569 | else if (rate->bw == RATE_INFO_BW_HE_RU && | 
|---|
| 1570 | rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_52) | 
|---|
| 1571 | result = rates_52[rate->he_gi]; | 
|---|
| 1572 | else if (rate->bw == RATE_INFO_BW_HE_RU && | 
|---|
| 1573 | rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_26) | 
|---|
| 1574 | result = rates_26[rate->he_gi]; | 
|---|
| 1575 | else { | 
|---|
| 1576 | WARN(1, "invalid HE MCS: bw:%d, ru:%d\n", | 
|---|
| 1577 | rate->bw, rate->he_ru_alloc); | 
|---|
| 1578 | return 0; | 
|---|
| 1579 | } | 
|---|
| 1580 |  | 
|---|
| 1581 | /* now scale to the appropriate MCS */ | 
|---|
| 1582 | tmp = result; | 
|---|
| 1583 | tmp *= SCALE; | 
|---|
| 1584 | do_div(tmp, mcs_divisors[rate->mcs]); | 
|---|
| 1585 | result = tmp; | 
|---|
| 1586 |  | 
|---|
| 1587 | /* and take NSS, DCM into account */ | 
|---|
| 1588 | result = (result * rate->nss) / 8; | 
|---|
| 1589 | if (rate->he_dcm) | 
|---|
| 1590 | result /= 2; | 
|---|
| 1591 |  | 
|---|
| 1592 | return result / 10000; | 
|---|
| 1593 | } | 
|---|
| 1594 |  | 
|---|
| 1595 | static u32 cfg80211_calculate_bitrate_eht(struct rate_info *rate) | 
|---|
| 1596 | { | 
|---|
| 1597 | #define SCALE 6144 | 
|---|
| 1598 | static const u32 mcs_divisors[16] = { | 
|---|
| 1599 | 102399, /* 16.666666... */ | 
|---|
| 1600 | 51201, /*  8.333333... */ | 
|---|
| 1601 | 34134, /*  5.555555... */ | 
|---|
| 1602 | 25599, /*  4.166666... */ | 
|---|
| 1603 | 17067, /*  2.777777... */ | 
|---|
| 1604 | 12801, /*  2.083333... */ | 
|---|
| 1605 | 11377, /*  1.851725... */ | 
|---|
| 1606 | 10239, /*  1.666666... */ | 
|---|
| 1607 | 8532, /*  1.388888... */ | 
|---|
| 1608 | 7680, /*  1.250000... */ | 
|---|
| 1609 | 6828, /*  1.111111... */ | 
|---|
| 1610 | 6144, /*  1.000000... */ | 
|---|
| 1611 | 5690, /*  0.926106... */ | 
|---|
| 1612 | 5120, /*  0.833333... */ | 
|---|
| 1613 | 409600, /* 66.666666... */ | 
|---|
| 1614 | 204800, /* 33.333333... */ | 
|---|
| 1615 | }; | 
|---|
| 1616 | static const u32 rates_996[3] =  { 480388888, 453700000, 408333333 }; | 
|---|
| 1617 | static const u32 rates_484[3] =  { 229411111, 216666666, 195000000 }; | 
|---|
| 1618 | static const u32 rates_242[3] =  { 114711111, 108333333,  97500000 }; | 
|---|
| 1619 | static const u32 rates_106[3] =  {  40000000,  37777777,  34000000 }; | 
|---|
| 1620 | static const u32 rates_52[3]  =  {  18820000,  17777777,  16000000 }; | 
|---|
| 1621 | static const u32 rates_26[3]  =  {   9411111,   8888888,   8000000 }; | 
|---|
| 1622 | u64 tmp; | 
|---|
| 1623 | u32 result; | 
|---|
| 1624 |  | 
|---|
| 1625 | if (WARN_ON_ONCE(rate->mcs > 15)) | 
|---|
| 1626 | return 0; | 
|---|
| 1627 | if (WARN_ON_ONCE(rate->eht_gi > NL80211_RATE_INFO_EHT_GI_3_2)) | 
|---|
| 1628 | return 0; | 
|---|
| 1629 | if (WARN_ON_ONCE(rate->eht_ru_alloc > | 
|---|
| 1630 | NL80211_RATE_INFO_EHT_RU_ALLOC_4x996)) | 
|---|
| 1631 | return 0; | 
|---|
| 1632 | if (WARN_ON_ONCE(rate->nss < 1 || rate->nss > 8)) | 
|---|
| 1633 | return 0; | 
|---|
| 1634 |  | 
|---|
| 1635 | /* Bandwidth checks for MCS 14 */ | 
|---|
| 1636 | if (rate->mcs == 14) { | 
|---|
| 1637 | if ((rate->bw != RATE_INFO_BW_EHT_RU && | 
|---|
| 1638 | rate->bw != RATE_INFO_BW_80 && | 
|---|
| 1639 | rate->bw != RATE_INFO_BW_160 && | 
|---|
| 1640 | rate->bw != RATE_INFO_BW_320) || | 
|---|
| 1641 | (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1642 | rate->eht_ru_alloc != NL80211_RATE_INFO_EHT_RU_ALLOC_996 && | 
|---|
| 1643 | rate->eht_ru_alloc != NL80211_RATE_INFO_EHT_RU_ALLOC_2x996 && | 
|---|
| 1644 | rate->eht_ru_alloc != NL80211_RATE_INFO_EHT_RU_ALLOC_4x996)) { | 
|---|
| 1645 | WARN(1, "invalid EHT BW for MCS 14: bw:%d, ru:%d\n", | 
|---|
| 1646 | rate->bw, rate->eht_ru_alloc); | 
|---|
| 1647 | return 0; | 
|---|
| 1648 | } | 
|---|
| 1649 | } | 
|---|
| 1650 |  | 
|---|
| 1651 | if (rate->bw == RATE_INFO_BW_320 || | 
|---|
| 1652 | (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1653 | rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_4x996)) | 
|---|
| 1654 | result = 4 * rates_996[rate->eht_gi]; | 
|---|
| 1655 | else if (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1656 | rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484) | 
|---|
| 1657 | result = 3 * rates_996[rate->eht_gi] + rates_484[rate->eht_gi]; | 
|---|
| 1658 | else if (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1659 | rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_3x996) | 
|---|
| 1660 | result = 3 * rates_996[rate->eht_gi]; | 
|---|
| 1661 | else if (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1662 | rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484) | 
|---|
| 1663 | result = 2 * rates_996[rate->eht_gi] + rates_484[rate->eht_gi]; | 
|---|
| 1664 | else if (rate->bw == RATE_INFO_BW_160 || | 
|---|
| 1665 | (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1666 | rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_2x996)) | 
|---|
| 1667 | result = 2 * rates_996[rate->eht_gi]; | 
|---|
| 1668 | else if (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1669 | rate->eht_ru_alloc == | 
|---|
| 1670 | NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242) | 
|---|
| 1671 | result = rates_996[rate->eht_gi] + rates_484[rate->eht_gi] | 
|---|
| 1672 | + rates_242[rate->eht_gi]; | 
|---|
| 1673 | else if (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1674 | rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_996P484) | 
|---|
| 1675 | result = rates_996[rate->eht_gi] + rates_484[rate->eht_gi]; | 
|---|
| 1676 | else if (rate->bw == RATE_INFO_BW_80 || | 
|---|
| 1677 | (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1678 | rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_996)) | 
|---|
| 1679 | result = rates_996[rate->eht_gi]; | 
|---|
| 1680 | else if (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1681 | rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_484P242) | 
|---|
| 1682 | result = rates_484[rate->eht_gi] + rates_242[rate->eht_gi]; | 
|---|
| 1683 | else if (rate->bw == RATE_INFO_BW_40 || | 
|---|
| 1684 | (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1685 | rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_484)) | 
|---|
| 1686 | result = rates_484[rate->eht_gi]; | 
|---|
| 1687 | else if (rate->bw == RATE_INFO_BW_20 || | 
|---|
| 1688 | (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1689 | rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_242)) | 
|---|
| 1690 | result = rates_242[rate->eht_gi]; | 
|---|
| 1691 | else if (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1692 | rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_106P26) | 
|---|
| 1693 | result = rates_106[rate->eht_gi] + rates_26[rate->eht_gi]; | 
|---|
| 1694 | else if (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1695 | rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_106) | 
|---|
| 1696 | result = rates_106[rate->eht_gi]; | 
|---|
| 1697 | else if (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1698 | rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_52P26) | 
|---|
| 1699 | result = rates_52[rate->eht_gi] + rates_26[rate->eht_gi]; | 
|---|
| 1700 | else if (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1701 | rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_52) | 
|---|
| 1702 | result = rates_52[rate->eht_gi]; | 
|---|
| 1703 | else if (rate->bw == RATE_INFO_BW_EHT_RU && | 
|---|
| 1704 | rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_26) | 
|---|
| 1705 | result = rates_26[rate->eht_gi]; | 
|---|
| 1706 | else { | 
|---|
| 1707 | WARN(1, "invalid EHT MCS: bw:%d, ru:%d\n", | 
|---|
| 1708 | rate->bw, rate->eht_ru_alloc); | 
|---|
| 1709 | return 0; | 
|---|
| 1710 | } | 
|---|
| 1711 |  | 
|---|
| 1712 | /* now scale to the appropriate MCS */ | 
|---|
| 1713 | tmp = result; | 
|---|
| 1714 | tmp *= SCALE; | 
|---|
| 1715 | do_div(tmp, mcs_divisors[rate->mcs]); | 
|---|
| 1716 |  | 
|---|
| 1717 | /* and take NSS */ | 
|---|
| 1718 | tmp *= rate->nss; | 
|---|
| 1719 | do_div(tmp, 8); | 
|---|
| 1720 |  | 
|---|
| 1721 | result = tmp; | 
|---|
| 1722 |  | 
|---|
| 1723 | return result / 10000; | 
|---|
| 1724 | } | 
|---|
| 1725 |  | 
|---|
| 1726 | static u32 cfg80211_calculate_bitrate_s1g(struct rate_info *rate) | 
|---|
| 1727 | { | 
|---|
| 1728 | /* For 1, 2, 4, 8 and 16 MHz channels */ | 
|---|
| 1729 | static const u32 base[5][11] = { | 
|---|
| 1730 | {  300000, | 
|---|
| 1731 | 600000, | 
|---|
| 1732 | 900000, | 
|---|
| 1733 | 1200000, | 
|---|
| 1734 | 1800000, | 
|---|
| 1735 | 2400000, | 
|---|
| 1736 | 2700000, | 
|---|
| 1737 | 3000000, | 
|---|
| 1738 | 3600000, | 
|---|
| 1739 | 4000000, | 
|---|
| 1740 | /* MCS 10 supported in 1 MHz only */ | 
|---|
| 1741 | 150000, | 
|---|
| 1742 | }, | 
|---|
| 1743 | {  650000, | 
|---|
| 1744 | 1300000, | 
|---|
| 1745 | 1950000, | 
|---|
| 1746 | 2600000, | 
|---|
| 1747 | 3900000, | 
|---|
| 1748 | 5200000, | 
|---|
| 1749 | 5850000, | 
|---|
| 1750 | 6500000, | 
|---|
| 1751 | 7800000, | 
|---|
| 1752 | /* MCS 9 not valid */ | 
|---|
| 1753 | }, | 
|---|
| 1754 | {  1350000, | 
|---|
| 1755 | 2700000, | 
|---|
| 1756 | 4050000, | 
|---|
| 1757 | 5400000, | 
|---|
| 1758 | 8100000, | 
|---|
| 1759 | 10800000, | 
|---|
| 1760 | 12150000, | 
|---|
| 1761 | 13500000, | 
|---|
| 1762 | 16200000, | 
|---|
| 1763 | 18000000, | 
|---|
| 1764 | }, | 
|---|
| 1765 | {  2925000, | 
|---|
| 1766 | 5850000, | 
|---|
| 1767 | 8775000, | 
|---|
| 1768 | 11700000, | 
|---|
| 1769 | 17550000, | 
|---|
| 1770 | 23400000, | 
|---|
| 1771 | 26325000, | 
|---|
| 1772 | 29250000, | 
|---|
| 1773 | 35100000, | 
|---|
| 1774 | 39000000, | 
|---|
| 1775 | }, | 
|---|
| 1776 | {  8580000, | 
|---|
| 1777 | 11700000, | 
|---|
| 1778 | 17550000, | 
|---|
| 1779 | 23400000, | 
|---|
| 1780 | 35100000, | 
|---|
| 1781 | 46800000, | 
|---|
| 1782 | 52650000, | 
|---|
| 1783 | 58500000, | 
|---|
| 1784 | 70200000, | 
|---|
| 1785 | 78000000, | 
|---|
| 1786 | }, | 
|---|
| 1787 | }; | 
|---|
| 1788 | u32 bitrate; | 
|---|
| 1789 | /* default is 1 MHz index */ | 
|---|
| 1790 | int idx = 0; | 
|---|
| 1791 |  | 
|---|
| 1792 | if (rate->mcs >= 11) | 
|---|
| 1793 | goto warn; | 
|---|
| 1794 |  | 
|---|
| 1795 | switch (rate->bw) { | 
|---|
| 1796 | case RATE_INFO_BW_16: | 
|---|
| 1797 | idx = 4; | 
|---|
| 1798 | break; | 
|---|
| 1799 | case RATE_INFO_BW_8: | 
|---|
| 1800 | idx = 3; | 
|---|
| 1801 | break; | 
|---|
| 1802 | case RATE_INFO_BW_4: | 
|---|
| 1803 | idx = 2; | 
|---|
| 1804 | break; | 
|---|
| 1805 | case RATE_INFO_BW_2: | 
|---|
| 1806 | idx = 1; | 
|---|
| 1807 | break; | 
|---|
| 1808 | case RATE_INFO_BW_1: | 
|---|
| 1809 | idx = 0; | 
|---|
| 1810 | break; | 
|---|
| 1811 | case RATE_INFO_BW_5: | 
|---|
| 1812 | case RATE_INFO_BW_10: | 
|---|
| 1813 | case RATE_INFO_BW_20: | 
|---|
| 1814 | case RATE_INFO_BW_40: | 
|---|
| 1815 | case RATE_INFO_BW_80: | 
|---|
| 1816 | case RATE_INFO_BW_160: | 
|---|
| 1817 | default: | 
|---|
| 1818 | goto warn; | 
|---|
| 1819 | } | 
|---|
| 1820 |  | 
|---|
| 1821 | bitrate = base[idx][rate->mcs]; | 
|---|
| 1822 | bitrate *= rate->nss; | 
|---|
| 1823 |  | 
|---|
| 1824 | if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) | 
|---|
| 1825 | bitrate = (bitrate / 9) * 10; | 
|---|
| 1826 | /* do NOT round down here */ | 
|---|
| 1827 | return (bitrate + 50000) / 100000; | 
|---|
| 1828 | warn: | 
|---|
| 1829 | WARN_ONCE(1, "invalid rate bw=%d, mcs=%d, nss=%d\n", | 
|---|
| 1830 | rate->bw, rate->mcs, rate->nss); | 
|---|
| 1831 | return 0; | 
|---|
| 1832 | } | 
|---|
| 1833 |  | 
|---|
| 1834 | u32 cfg80211_calculate_bitrate(struct rate_info *rate) | 
|---|
| 1835 | { | 
|---|
| 1836 | if (rate->flags & RATE_INFO_FLAGS_MCS) | 
|---|
| 1837 | return cfg80211_calculate_bitrate_ht(rate); | 
|---|
| 1838 | if (rate->flags & RATE_INFO_FLAGS_DMG) | 
|---|
| 1839 | return cfg80211_calculate_bitrate_dmg(rate); | 
|---|
| 1840 | if (rate->flags & RATE_INFO_FLAGS_EXTENDED_SC_DMG) | 
|---|
| 1841 | return cfg80211_calculate_bitrate_extended_sc_dmg(rate); | 
|---|
| 1842 | if (rate->flags & RATE_INFO_FLAGS_EDMG) | 
|---|
| 1843 | return cfg80211_calculate_bitrate_edmg(rate); | 
|---|
| 1844 | if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) | 
|---|
| 1845 | return cfg80211_calculate_bitrate_vht(rate); | 
|---|
| 1846 | if (rate->flags & RATE_INFO_FLAGS_HE_MCS) | 
|---|
| 1847 | return cfg80211_calculate_bitrate_he(rate); | 
|---|
| 1848 | if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) | 
|---|
| 1849 | return cfg80211_calculate_bitrate_eht(rate); | 
|---|
| 1850 | if (rate->flags & RATE_INFO_FLAGS_S1G_MCS) | 
|---|
| 1851 | return cfg80211_calculate_bitrate_s1g(rate); | 
|---|
| 1852 |  | 
|---|
| 1853 | return rate->legacy; | 
|---|
| 1854 | } | 
|---|
| 1855 | EXPORT_SYMBOL(cfg80211_calculate_bitrate); | 
|---|
| 1856 |  | 
|---|
| 1857 | int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, | 
|---|
| 1858 | enum ieee80211_p2p_attr_id attr, | 
|---|
| 1859 | u8 *buf, unsigned int bufsize) | 
|---|
| 1860 | { | 
|---|
| 1861 | u8 *out = buf; | 
|---|
| 1862 | u16 attr_remaining = 0; | 
|---|
| 1863 | bool desired_attr = false; | 
|---|
| 1864 | u16 desired_len = 0; | 
|---|
| 1865 |  | 
|---|
| 1866 | while (len > 0) { | 
|---|
| 1867 | unsigned int iedatalen; | 
|---|
| 1868 | unsigned int copy; | 
|---|
| 1869 | const u8 *iedata; | 
|---|
| 1870 |  | 
|---|
| 1871 | if (len < 2) | 
|---|
| 1872 | return -EILSEQ; | 
|---|
| 1873 | iedatalen = ies[1]; | 
|---|
| 1874 | if (iedatalen + 2 > len) | 
|---|
| 1875 | return -EILSEQ; | 
|---|
| 1876 |  | 
|---|
| 1877 | if (ies[0] != WLAN_EID_VENDOR_SPECIFIC) | 
|---|
| 1878 | goto cont; | 
|---|
| 1879 |  | 
|---|
| 1880 | if (iedatalen < 4) | 
|---|
| 1881 | goto cont; | 
|---|
| 1882 |  | 
|---|
| 1883 | iedata = ies + 2; | 
|---|
| 1884 |  | 
|---|
| 1885 | /* check WFA OUI, P2P subtype */ | 
|---|
| 1886 | if (iedata[0] != 0x50 || iedata[1] != 0x6f || | 
|---|
| 1887 | iedata[2] != 0x9a || iedata[3] != 0x09) | 
|---|
| 1888 | goto cont; | 
|---|
| 1889 |  | 
|---|
| 1890 | iedatalen -= 4; | 
|---|
| 1891 | iedata += 4; | 
|---|
| 1892 |  | 
|---|
| 1893 | /* check attribute continuation into this IE */ | 
|---|
| 1894 | copy = min_t(unsigned int, attr_remaining, iedatalen); | 
|---|
| 1895 | if (copy && desired_attr) { | 
|---|
| 1896 | desired_len += copy; | 
|---|
| 1897 | if (out) { | 
|---|
| 1898 | memcpy(to: out, from: iedata, min(bufsize, copy)); | 
|---|
| 1899 | out += min(bufsize, copy); | 
|---|
| 1900 | bufsize -= min(bufsize, copy); | 
|---|
| 1901 | } | 
|---|
| 1902 |  | 
|---|
| 1903 |  | 
|---|
| 1904 | if (copy == attr_remaining) | 
|---|
| 1905 | return desired_len; | 
|---|
| 1906 | } | 
|---|
| 1907 |  | 
|---|
| 1908 | attr_remaining -= copy; | 
|---|
| 1909 | if (attr_remaining) | 
|---|
| 1910 | goto cont; | 
|---|
| 1911 |  | 
|---|
| 1912 | iedatalen -= copy; | 
|---|
| 1913 | iedata += copy; | 
|---|
| 1914 |  | 
|---|
| 1915 | while (iedatalen > 0) { | 
|---|
| 1916 | u16 attr_len; | 
|---|
| 1917 |  | 
|---|
| 1918 | /* P2P attribute ID & size must fit */ | 
|---|
| 1919 | if (iedatalen < 3) | 
|---|
| 1920 | return -EILSEQ; | 
|---|
| 1921 | desired_attr = iedata[0] == attr; | 
|---|
| 1922 | attr_len = get_unaligned_le16(p: iedata + 1); | 
|---|
| 1923 | iedatalen -= 3; | 
|---|
| 1924 | iedata += 3; | 
|---|
| 1925 |  | 
|---|
| 1926 | copy = min_t(unsigned int, attr_len, iedatalen); | 
|---|
| 1927 |  | 
|---|
| 1928 | if (desired_attr) { | 
|---|
| 1929 | desired_len += copy; | 
|---|
| 1930 | if (out) { | 
|---|
| 1931 | memcpy(to: out, from: iedata, min(bufsize, copy)); | 
|---|
| 1932 | out += min(bufsize, copy); | 
|---|
| 1933 | bufsize -= min(bufsize, copy); | 
|---|
| 1934 | } | 
|---|
| 1935 |  | 
|---|
| 1936 | if (copy == attr_len) | 
|---|
| 1937 | return desired_len; | 
|---|
| 1938 | } | 
|---|
| 1939 |  | 
|---|
| 1940 | iedata += copy; | 
|---|
| 1941 | iedatalen -= copy; | 
|---|
| 1942 | attr_remaining = attr_len - copy; | 
|---|
| 1943 | } | 
|---|
| 1944 |  | 
|---|
| 1945 | cont: | 
|---|
| 1946 | len -= ies[1] + 2; | 
|---|
| 1947 | ies += ies[1] + 2; | 
|---|
| 1948 | } | 
|---|
| 1949 |  | 
|---|
| 1950 | if (attr_remaining && desired_attr) | 
|---|
| 1951 | return -EILSEQ; | 
|---|
| 1952 |  | 
|---|
| 1953 | return -ENOENT; | 
|---|
| 1954 | } | 
|---|
| 1955 | EXPORT_SYMBOL(cfg80211_get_p2p_attr); | 
|---|
| 1956 |  | 
|---|
| 1957 | static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id, bool id_ext) | 
|---|
| 1958 | { | 
|---|
| 1959 | int i; | 
|---|
| 1960 |  | 
|---|
| 1961 | /* Make sure array values are legal */ | 
|---|
| 1962 | if (WARN_ON(ids[n_ids - 1] == WLAN_EID_EXTENSION)) | 
|---|
| 1963 | return false; | 
|---|
| 1964 |  | 
|---|
| 1965 | i = 0; | 
|---|
| 1966 | while (i < n_ids) { | 
|---|
| 1967 | if (ids[i] == WLAN_EID_EXTENSION) { | 
|---|
| 1968 | if (id_ext && (ids[i + 1] == id)) | 
|---|
| 1969 | return true; | 
|---|
| 1970 |  | 
|---|
| 1971 | i += 2; | 
|---|
| 1972 | continue; | 
|---|
| 1973 | } | 
|---|
| 1974 |  | 
|---|
| 1975 | if (ids[i] == id && !id_ext) | 
|---|
| 1976 | return true; | 
|---|
| 1977 |  | 
|---|
| 1978 | i++; | 
|---|
| 1979 | } | 
|---|
| 1980 | return false; | 
|---|
| 1981 | } | 
|---|
| 1982 |  | 
|---|
| 1983 | static size_t skip_ie(const u8 *ies, size_t ielen, size_t pos) | 
|---|
| 1984 | { | 
|---|
| 1985 | /* we assume a validly formed IEs buffer */ | 
|---|
| 1986 | u8 len = ies[pos + 1]; | 
|---|
| 1987 |  | 
|---|
| 1988 | pos += 2 + len; | 
|---|
| 1989 |  | 
|---|
| 1990 | /* the IE itself must have 255 bytes for fragments to follow */ | 
|---|
| 1991 | if (len < 255) | 
|---|
| 1992 | return pos; | 
|---|
| 1993 |  | 
|---|
| 1994 | while (pos < ielen && ies[pos] == WLAN_EID_FRAGMENT) { | 
|---|
| 1995 | len = ies[pos + 1]; | 
|---|
| 1996 | pos += 2 + len; | 
|---|
| 1997 | } | 
|---|
| 1998 |  | 
|---|
| 1999 | return pos; | 
|---|
| 2000 | } | 
|---|
| 2001 |  | 
|---|
| 2002 | size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen, | 
|---|
| 2003 | const u8 *ids, int n_ids, | 
|---|
| 2004 | const u8 *after_ric, int n_after_ric, | 
|---|
| 2005 | size_t offset) | 
|---|
| 2006 | { | 
|---|
| 2007 | size_t pos = offset; | 
|---|
| 2008 |  | 
|---|
| 2009 | while (pos < ielen) { | 
|---|
| 2010 | u8 ext = 0; | 
|---|
| 2011 |  | 
|---|
| 2012 | if (ies[pos] == WLAN_EID_EXTENSION) | 
|---|
| 2013 | ext = 2; | 
|---|
| 2014 | if ((pos + ext) >= ielen) | 
|---|
| 2015 | break; | 
|---|
| 2016 |  | 
|---|
| 2017 | if (!ieee80211_id_in_list(ids, n_ids, id: ies[pos + ext], | 
|---|
| 2018 | id_ext: ies[pos] == WLAN_EID_EXTENSION)) | 
|---|
| 2019 | break; | 
|---|
| 2020 |  | 
|---|
| 2021 | if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) { | 
|---|
| 2022 | pos = skip_ie(ies, ielen, pos); | 
|---|
| 2023 |  | 
|---|
| 2024 | while (pos < ielen) { | 
|---|
| 2025 | if (ies[pos] == WLAN_EID_EXTENSION) | 
|---|
| 2026 | ext = 2; | 
|---|
| 2027 | else | 
|---|
| 2028 | ext = 0; | 
|---|
| 2029 |  | 
|---|
| 2030 | if ((pos + ext) >= ielen) | 
|---|
| 2031 | break; | 
|---|
| 2032 |  | 
|---|
| 2033 | if (!ieee80211_id_in_list(ids: after_ric, | 
|---|
| 2034 | n_ids: n_after_ric, | 
|---|
| 2035 | id: ies[pos + ext], | 
|---|
| 2036 | id_ext: ext == 2)) | 
|---|
| 2037 | pos = skip_ie(ies, ielen, pos); | 
|---|
| 2038 | else | 
|---|
| 2039 | break; | 
|---|
| 2040 | } | 
|---|
| 2041 | } else { | 
|---|
| 2042 | pos = skip_ie(ies, ielen, pos); | 
|---|
| 2043 | } | 
|---|
| 2044 | } | 
|---|
| 2045 |  | 
|---|
| 2046 | return pos; | 
|---|
| 2047 | } | 
|---|
| 2048 | EXPORT_SYMBOL(ieee80211_ie_split_ric); | 
|---|
| 2049 |  | 
|---|
| 2050 | void ieee80211_fragment_element(struct sk_buff *skb, u8 *len_pos, u8 frag_id) | 
|---|
| 2051 | { | 
|---|
| 2052 | unsigned int elem_len; | 
|---|
| 2053 |  | 
|---|
| 2054 | if (!len_pos) | 
|---|
| 2055 | return; | 
|---|
| 2056 |  | 
|---|
| 2057 | elem_len = skb->data + skb->len - len_pos - 1; | 
|---|
| 2058 |  | 
|---|
| 2059 | while (elem_len > 255) { | 
|---|
| 2060 | /* this one is 255 */ | 
|---|
| 2061 | *len_pos = 255; | 
|---|
| 2062 | /* remaining data gets smaller */ | 
|---|
| 2063 | elem_len -= 255; | 
|---|
| 2064 | /* make space for the fragment ID/len in SKB */ | 
|---|
| 2065 | skb_put(skb, len: 2); | 
|---|
| 2066 | /* shift back the remaining data to place fragment ID/len */ | 
|---|
| 2067 | memmove(dest: len_pos + 255 + 3, src: len_pos + 255 + 1, count: elem_len); | 
|---|
| 2068 | /* place the fragment ID */ | 
|---|
| 2069 | len_pos += 255 + 1; | 
|---|
| 2070 | *len_pos = frag_id; | 
|---|
| 2071 | /* and point to fragment length to update later */ | 
|---|
| 2072 | len_pos++; | 
|---|
| 2073 | } | 
|---|
| 2074 |  | 
|---|
| 2075 | *len_pos = elem_len; | 
|---|
| 2076 | } | 
|---|
| 2077 | EXPORT_SYMBOL(ieee80211_fragment_element); | 
|---|
| 2078 |  | 
|---|
| 2079 | bool ieee80211_operating_class_to_band(u8 operating_class, | 
|---|
| 2080 | enum nl80211_band *band) | 
|---|
| 2081 | { | 
|---|
| 2082 | switch (operating_class) { | 
|---|
| 2083 | case 112: | 
|---|
| 2084 | case 115 ... 127: | 
|---|
| 2085 | case 128 ... 130: | 
|---|
| 2086 | *band = NL80211_BAND_5GHZ; | 
|---|
| 2087 | return true; | 
|---|
| 2088 | case 131 ... 135: | 
|---|
| 2089 | case 137: | 
|---|
| 2090 | *band = NL80211_BAND_6GHZ; | 
|---|
| 2091 | return true; | 
|---|
| 2092 | case 81: | 
|---|
| 2093 | case 82: | 
|---|
| 2094 | case 83: | 
|---|
| 2095 | case 84: | 
|---|
| 2096 | *band = NL80211_BAND_2GHZ; | 
|---|
| 2097 | return true; | 
|---|
| 2098 | case 180: | 
|---|
| 2099 | *band = NL80211_BAND_60GHZ; | 
|---|
| 2100 | return true; | 
|---|
| 2101 | } | 
|---|
| 2102 |  | 
|---|
| 2103 | return false; | 
|---|
| 2104 | } | 
|---|
| 2105 | EXPORT_SYMBOL(ieee80211_operating_class_to_band); | 
|---|
| 2106 |  | 
|---|
| 2107 | bool ieee80211_operating_class_to_chandef(u8 operating_class, | 
|---|
| 2108 | struct ieee80211_channel *chan, | 
|---|
| 2109 | struct cfg80211_chan_def *chandef) | 
|---|
| 2110 | { | 
|---|
| 2111 | u32 control_freq, offset = 0; | 
|---|
| 2112 | enum nl80211_band band; | 
|---|
| 2113 |  | 
|---|
| 2114 | if (!ieee80211_operating_class_to_band(operating_class, &band) || | 
|---|
| 2115 | !chan || band != chan->band) | 
|---|
| 2116 | return false; | 
|---|
| 2117 |  | 
|---|
| 2118 | control_freq = chan->center_freq; | 
|---|
| 2119 | chandef->chan = chan; | 
|---|
| 2120 |  | 
|---|
| 2121 | if (control_freq >= 5955) | 
|---|
| 2122 | offset = control_freq - 5955; | 
|---|
| 2123 | else if (control_freq >= 5745) | 
|---|
| 2124 | offset = control_freq - 5745; | 
|---|
| 2125 | else if (control_freq >= 5180) | 
|---|
| 2126 | offset = control_freq - 5180; | 
|---|
| 2127 | offset /= 20; | 
|---|
| 2128 |  | 
|---|
| 2129 | switch (operating_class) { | 
|---|
| 2130 | case 81:  /* 2 GHz band; 20 MHz; channels 1..13 */ | 
|---|
| 2131 | case 82:  /* 2 GHz band; 20 MHz; channel 14 */ | 
|---|
| 2132 | case 115: /* 5 GHz band; 20 MHz; channels 36,40,44,48 */ | 
|---|
| 2133 | case 118: /* 5 GHz band; 20 MHz; channels 52,56,60,64 */ | 
|---|
| 2134 | case 121: /* 5 GHz band; 20 MHz; channels 100..144 */ | 
|---|
| 2135 | case 124: /* 5 GHz band; 20 MHz; channels 149,153,157,161 */ | 
|---|
| 2136 | case 125: /* 5 GHz band; 20 MHz; channels 149..177 */ | 
|---|
| 2137 | case 131: /* 6 GHz band; 20 MHz; channels 1..233*/ | 
|---|
| 2138 | case 136: /* 6 GHz band; 20 MHz; channel 2 */ | 
|---|
| 2139 | chandef->center_freq1 = control_freq; | 
|---|
| 2140 | chandef->width = NL80211_CHAN_WIDTH_20; | 
|---|
| 2141 | return true; | 
|---|
| 2142 | case 83:  /* 2 GHz band; 40 MHz; channels 1..9 */ | 
|---|
| 2143 | case 116: /* 5 GHz band; 40 MHz; channels 36,44 */ | 
|---|
| 2144 | case 119: /* 5 GHz band; 40 MHz; channels 52,60 */ | 
|---|
| 2145 | case 122: /* 5 GHz band; 40 MHz; channels 100,108,116,124,132,140 */ | 
|---|
| 2146 | case 126: /* 5 GHz band; 40 MHz; channels 149,157,165,173 */ | 
|---|
| 2147 | chandef->center_freq1 = control_freq + 10; | 
|---|
| 2148 | chandef->width = NL80211_CHAN_WIDTH_40; | 
|---|
| 2149 | return true; | 
|---|
| 2150 | case 84:  /* 2 GHz band; 40 MHz; channels 5..13 */ | 
|---|
| 2151 | case 117: /* 5 GHz band; 40 MHz; channels 40,48 */ | 
|---|
| 2152 | case 120: /* 5 GHz band; 40 MHz; channels 56,64 */ | 
|---|
| 2153 | case 123: /* 5 GHz band; 40 MHz; channels 104,112,120,128,136,144 */ | 
|---|
| 2154 | case 127: /* 5 GHz band; 40 MHz; channels 153,161,169,177 */ | 
|---|
| 2155 | chandef->center_freq1 = control_freq - 10; | 
|---|
| 2156 | chandef->width = NL80211_CHAN_WIDTH_40; | 
|---|
| 2157 | return true; | 
|---|
| 2158 | case 132: /* 6 GHz band; 40 MHz; channels 1,5,..,229*/ | 
|---|
| 2159 | chandef->center_freq1 = control_freq + 10 - (offset & 1) * 20; | 
|---|
| 2160 | chandef->width = NL80211_CHAN_WIDTH_40; | 
|---|
| 2161 | return true; | 
|---|
| 2162 | case 128: /* 5 GHz band; 80 MHz; channels 36..64,100..144,149..177 */ | 
|---|
| 2163 | case 133: /* 6 GHz band; 80 MHz; channels 1,5,..,229 */ | 
|---|
| 2164 | chandef->center_freq1 = control_freq + 30 - (offset & 3) * 20; | 
|---|
| 2165 | chandef->width = NL80211_CHAN_WIDTH_80; | 
|---|
| 2166 | return true; | 
|---|
| 2167 | case 129: /* 5 GHz band; 160 MHz; channels 36..64,100..144,149..177 */ | 
|---|
| 2168 | case 134: /* 6 GHz band; 160 MHz; channels 1,5,..,229 */ | 
|---|
| 2169 | chandef->center_freq1 = control_freq + 70 - (offset & 7) * 20; | 
|---|
| 2170 | chandef->width = NL80211_CHAN_WIDTH_160; | 
|---|
| 2171 | return true; | 
|---|
| 2172 | case 130: /* 5 GHz band; 80+80 MHz; channels 36..64,100..144,149..177 */ | 
|---|
| 2173 | case 135: /* 6 GHz band; 80+80 MHz; channels 1,5,..,229 */ | 
|---|
| 2174 | /* The center_freq2 of 80+80 MHz is unknown */ | 
|---|
| 2175 | case 137: /* 6 GHz band; 320 MHz; channels 1,5,..,229 */ | 
|---|
| 2176 | /* 320-1 or 320-2 channelization is unknown */ | 
|---|
| 2177 | default: | 
|---|
| 2178 | return false; | 
|---|
| 2179 | } | 
|---|
| 2180 | } | 
|---|
| 2181 | EXPORT_SYMBOL(ieee80211_operating_class_to_chandef); | 
|---|
| 2182 |  | 
|---|
| 2183 | bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef, | 
|---|
| 2184 | u8 *op_class) | 
|---|
| 2185 | { | 
|---|
| 2186 | u8 vht_opclass; | 
|---|
| 2187 | u32 freq = chandef->center_freq1; | 
|---|
| 2188 |  | 
|---|
| 2189 | if (freq >= 2412 && freq <= 2472) { | 
|---|
| 2190 | if (chandef->width > NL80211_CHAN_WIDTH_40) | 
|---|
| 2191 | return false; | 
|---|
| 2192 |  | 
|---|
| 2193 | /* 2.407 GHz, channels 1..13 */ | 
|---|
| 2194 | if (chandef->width == NL80211_CHAN_WIDTH_40) { | 
|---|
| 2195 | if (freq > chandef->chan->center_freq) | 
|---|
| 2196 | *op_class = 83; /* HT40+ */ | 
|---|
| 2197 | else | 
|---|
| 2198 | *op_class = 84; /* HT40- */ | 
|---|
| 2199 | } else { | 
|---|
| 2200 | *op_class = 81; | 
|---|
| 2201 | } | 
|---|
| 2202 |  | 
|---|
| 2203 | return true; | 
|---|
| 2204 | } | 
|---|
| 2205 |  | 
|---|
| 2206 | if (freq == 2484) { | 
|---|
| 2207 | /* channel 14 is only for IEEE 802.11b */ | 
|---|
| 2208 | if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT) | 
|---|
| 2209 | return false; | 
|---|
| 2210 |  | 
|---|
| 2211 | *op_class = 82; /* channel 14 */ | 
|---|
| 2212 | return true; | 
|---|
| 2213 | } | 
|---|
| 2214 |  | 
|---|
| 2215 | switch (chandef->width) { | 
|---|
| 2216 | case NL80211_CHAN_WIDTH_80: | 
|---|
| 2217 | vht_opclass = 128; | 
|---|
| 2218 | break; | 
|---|
| 2219 | case NL80211_CHAN_WIDTH_160: | 
|---|
| 2220 | vht_opclass = 129; | 
|---|
| 2221 | break; | 
|---|
| 2222 | case NL80211_CHAN_WIDTH_80P80: | 
|---|
| 2223 | vht_opclass = 130; | 
|---|
| 2224 | break; | 
|---|
| 2225 | case NL80211_CHAN_WIDTH_10: | 
|---|
| 2226 | case NL80211_CHAN_WIDTH_5: | 
|---|
| 2227 | return false; /* unsupported for now */ | 
|---|
| 2228 | default: | 
|---|
| 2229 | vht_opclass = 0; | 
|---|
| 2230 | break; | 
|---|
| 2231 | } | 
|---|
| 2232 |  | 
|---|
| 2233 | /* 5 GHz, channels 36..48 */ | 
|---|
| 2234 | if (freq >= 5180 && freq <= 5240) { | 
|---|
| 2235 | if (vht_opclass) { | 
|---|
| 2236 | *op_class = vht_opclass; | 
|---|
| 2237 | } else if (chandef->width == NL80211_CHAN_WIDTH_40) { | 
|---|
| 2238 | if (freq > chandef->chan->center_freq) | 
|---|
| 2239 | *op_class = 116; | 
|---|
| 2240 | else | 
|---|
| 2241 | *op_class = 117; | 
|---|
| 2242 | } else { | 
|---|
| 2243 | *op_class = 115; | 
|---|
| 2244 | } | 
|---|
| 2245 |  | 
|---|
| 2246 | return true; | 
|---|
| 2247 | } | 
|---|
| 2248 |  | 
|---|
| 2249 | /* 5 GHz, channels 52..64 */ | 
|---|
| 2250 | if (freq >= 5260 && freq <= 5320) { | 
|---|
| 2251 | if (vht_opclass) { | 
|---|
| 2252 | *op_class = vht_opclass; | 
|---|
| 2253 | } else if (chandef->width == NL80211_CHAN_WIDTH_40) { | 
|---|
| 2254 | if (freq > chandef->chan->center_freq) | 
|---|
| 2255 | *op_class = 119; | 
|---|
| 2256 | else | 
|---|
| 2257 | *op_class = 120; | 
|---|
| 2258 | } else { | 
|---|
| 2259 | *op_class = 118; | 
|---|
| 2260 | } | 
|---|
| 2261 |  | 
|---|
| 2262 | return true; | 
|---|
| 2263 | } | 
|---|
| 2264 |  | 
|---|
| 2265 | /* 5 GHz, channels 100..144 */ | 
|---|
| 2266 | if (freq >= 5500 && freq <= 5720) { | 
|---|
| 2267 | if (vht_opclass) { | 
|---|
| 2268 | *op_class = vht_opclass; | 
|---|
| 2269 | } else if (chandef->width == NL80211_CHAN_WIDTH_40) { | 
|---|
| 2270 | if (freq > chandef->chan->center_freq) | 
|---|
| 2271 | *op_class = 122; | 
|---|
| 2272 | else | 
|---|
| 2273 | *op_class = 123; | 
|---|
| 2274 | } else { | 
|---|
| 2275 | *op_class = 121; | 
|---|
| 2276 | } | 
|---|
| 2277 |  | 
|---|
| 2278 | return true; | 
|---|
| 2279 | } | 
|---|
| 2280 |  | 
|---|
| 2281 | /* 5 GHz, channels 149..169 */ | 
|---|
| 2282 | if (freq >= 5745 && freq <= 5845) { | 
|---|
| 2283 | if (vht_opclass) { | 
|---|
| 2284 | *op_class = vht_opclass; | 
|---|
| 2285 | } else if (chandef->width == NL80211_CHAN_WIDTH_40) { | 
|---|
| 2286 | if (freq > chandef->chan->center_freq) | 
|---|
| 2287 | *op_class = 126; | 
|---|
| 2288 | else | 
|---|
| 2289 | *op_class = 127; | 
|---|
| 2290 | } else if (freq <= 5805) { | 
|---|
| 2291 | *op_class = 124; | 
|---|
| 2292 | } else { | 
|---|
| 2293 | *op_class = 125; | 
|---|
| 2294 | } | 
|---|
| 2295 |  | 
|---|
| 2296 | return true; | 
|---|
| 2297 | } | 
|---|
| 2298 |  | 
|---|
| 2299 | /* 56.16 GHz, channel 1..4 */ | 
|---|
| 2300 | if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) { | 
|---|
| 2301 | if (chandef->width >= NL80211_CHAN_WIDTH_40) | 
|---|
| 2302 | return false; | 
|---|
| 2303 |  | 
|---|
| 2304 | *op_class = 180; | 
|---|
| 2305 | return true; | 
|---|
| 2306 | } | 
|---|
| 2307 |  | 
|---|
| 2308 | /* not supported yet */ | 
|---|
| 2309 | return false; | 
|---|
| 2310 | } | 
|---|
| 2311 | EXPORT_SYMBOL(ieee80211_chandef_to_operating_class); | 
|---|
| 2312 |  | 
|---|
| 2313 | static int cfg80211_wdev_bi(struct wireless_dev *wdev) | 
|---|
| 2314 | { | 
|---|
| 2315 | switch (wdev->iftype) { | 
|---|
| 2316 | case NL80211_IFTYPE_AP: | 
|---|
| 2317 | case NL80211_IFTYPE_P2P_GO: | 
|---|
| 2318 | WARN_ON(wdev->valid_links); | 
|---|
| 2319 | return wdev->links[0].ap.beacon_interval; | 
|---|
| 2320 | case NL80211_IFTYPE_MESH_POINT: | 
|---|
| 2321 | return wdev->u.mesh.beacon_interval; | 
|---|
| 2322 | case NL80211_IFTYPE_ADHOC: | 
|---|
| 2323 | return wdev->u.ibss.beacon_interval; | 
|---|
| 2324 | default: | 
|---|
| 2325 | break; | 
|---|
| 2326 | } | 
|---|
| 2327 |  | 
|---|
| 2328 | return 0; | 
|---|
| 2329 | } | 
|---|
| 2330 |  | 
|---|
| 2331 | static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int, | 
|---|
| 2332 | u32 *beacon_int_gcd, | 
|---|
| 2333 | bool *beacon_int_different, | 
|---|
| 2334 | int radio_idx) | 
|---|
| 2335 | { | 
|---|
| 2336 | struct cfg80211_registered_device *rdev; | 
|---|
| 2337 | struct wireless_dev *wdev; | 
|---|
| 2338 |  | 
|---|
| 2339 | *beacon_int_gcd = 0; | 
|---|
| 2340 | *beacon_int_different = false; | 
|---|
| 2341 |  | 
|---|
| 2342 | rdev = wiphy_to_rdev(wiphy); | 
|---|
| 2343 | list_for_each_entry(wdev, &wiphy->wdev_list, list) { | 
|---|
| 2344 | int wdev_bi; | 
|---|
| 2345 |  | 
|---|
| 2346 | /* this feature isn't supported with MLO */ | 
|---|
| 2347 | if (wdev->valid_links) | 
|---|
| 2348 | continue; | 
|---|
| 2349 |  | 
|---|
| 2350 | /* skip wdevs not active on the given wiphy radio */ | 
|---|
| 2351 | if (radio_idx >= 0 && | 
|---|
| 2352 | !(rdev_get_radio_mask(rdev, dev: wdev->netdev) & BIT(radio_idx))) | 
|---|
| 2353 | continue; | 
|---|
| 2354 |  | 
|---|
| 2355 | wdev_bi = cfg80211_wdev_bi(wdev); | 
|---|
| 2356 |  | 
|---|
| 2357 | if (!wdev_bi) | 
|---|
| 2358 | continue; | 
|---|
| 2359 |  | 
|---|
| 2360 | if (!*beacon_int_gcd) { | 
|---|
| 2361 | *beacon_int_gcd = wdev_bi; | 
|---|
| 2362 | continue; | 
|---|
| 2363 | } | 
|---|
| 2364 |  | 
|---|
| 2365 | if (wdev_bi == *beacon_int_gcd) | 
|---|
| 2366 | continue; | 
|---|
| 2367 |  | 
|---|
| 2368 | *beacon_int_different = true; | 
|---|
| 2369 | *beacon_int_gcd = gcd(a: *beacon_int_gcd, b: wdev_bi); | 
|---|
| 2370 | } | 
|---|
| 2371 |  | 
|---|
| 2372 | if (new_beacon_int && *beacon_int_gcd != new_beacon_int) { | 
|---|
| 2373 | if (*beacon_int_gcd) | 
|---|
| 2374 | *beacon_int_different = true; | 
|---|
| 2375 | *beacon_int_gcd = gcd(a: *beacon_int_gcd, b: new_beacon_int); | 
|---|
| 2376 | } | 
|---|
| 2377 | } | 
|---|
| 2378 |  | 
|---|
| 2379 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 
|---|
| 2380 | enum nl80211_iftype iftype, u32 beacon_int) | 
|---|
| 2381 | { | 
|---|
| 2382 | /* | 
|---|
| 2383 | * This is just a basic pre-condition check; if interface combinations | 
|---|
| 2384 | * are possible the driver must already be checking those with a call | 
|---|
| 2385 | * to cfg80211_check_combinations(), in which case we'll validate more | 
|---|
| 2386 | * through the cfg80211_calculate_bi_data() call and code in | 
|---|
| 2387 | * cfg80211_iter_combinations(). | 
|---|
| 2388 | */ | 
|---|
| 2389 |  | 
|---|
| 2390 | if (beacon_int < 10 || beacon_int > 10000) | 
|---|
| 2391 | return -EINVAL; | 
|---|
| 2392 |  | 
|---|
| 2393 | return 0; | 
|---|
| 2394 | } | 
|---|
| 2395 |  | 
|---|
| 2396 | int cfg80211_iter_combinations(struct wiphy *wiphy, | 
|---|
| 2397 | struct iface_combination_params *params, | 
|---|
| 2398 | void (*iter)(const struct ieee80211_iface_combination *c, | 
|---|
| 2399 | void *data), | 
|---|
| 2400 | void *data) | 
|---|
| 2401 | { | 
|---|
| 2402 | const struct wiphy_radio *radio = NULL; | 
|---|
| 2403 | const struct ieee80211_iface_combination *c, *cs; | 
|---|
| 2404 | const struct ieee80211_regdomain *regdom; | 
|---|
| 2405 | enum nl80211_dfs_regions region = 0; | 
|---|
| 2406 | int i, j, n, iftype; | 
|---|
| 2407 | int num_interfaces = 0; | 
|---|
| 2408 | u32 used_iftypes = 0; | 
|---|
| 2409 | u32 beacon_int_gcd; | 
|---|
| 2410 | bool beacon_int_different; | 
|---|
| 2411 |  | 
|---|
| 2412 | if (params->radio_idx >= 0) | 
|---|
| 2413 | radio = &wiphy->radio[params->radio_idx]; | 
|---|
| 2414 |  | 
|---|
| 2415 | /* | 
|---|
| 2416 | * This is a bit strange, since the iteration used to rely only on | 
|---|
| 2417 | * the data given by the driver, but here it now relies on context, | 
|---|
| 2418 | * in form of the currently operating interfaces. | 
|---|
| 2419 | * This is OK for all current users, and saves us from having to | 
|---|
| 2420 | * push the GCD calculations into all the drivers. | 
|---|
| 2421 | * In the future, this should probably rely more on data that's in | 
|---|
| 2422 | * cfg80211 already - the only thing not would appear to be any new | 
|---|
| 2423 | * interfaces (while being brought up) and channel/radar data. | 
|---|
| 2424 | */ | 
|---|
| 2425 | cfg80211_calculate_bi_data(wiphy, new_beacon_int: params->new_beacon_int, | 
|---|
| 2426 | beacon_int_gcd: &beacon_int_gcd, beacon_int_different: &beacon_int_different, | 
|---|
| 2427 | radio_idx: params->radio_idx); | 
|---|
| 2428 |  | 
|---|
| 2429 | if (params->radar_detect) { | 
|---|
| 2430 | rcu_read_lock(); | 
|---|
| 2431 | regdom = rcu_dereference(cfg80211_regdomain); | 
|---|
| 2432 | if (regdom) | 
|---|
| 2433 | region = regdom->dfs_region; | 
|---|
| 2434 | rcu_read_unlock(); | 
|---|
| 2435 | } | 
|---|
| 2436 |  | 
|---|
| 2437 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { | 
|---|
| 2438 | num_interfaces += params->iftype_num[iftype]; | 
|---|
| 2439 | if (params->iftype_num[iftype] > 0 && | 
|---|
| 2440 | !cfg80211_iftype_allowed(wiphy, iftype, is_4addr: 0, check_swif: 1)) | 
|---|
| 2441 | used_iftypes |= BIT(iftype); | 
|---|
| 2442 | } | 
|---|
| 2443 |  | 
|---|
| 2444 | if (radio) { | 
|---|
| 2445 | cs = radio->iface_combinations; | 
|---|
| 2446 | n = radio->n_iface_combinations; | 
|---|
| 2447 | } else { | 
|---|
| 2448 | cs = wiphy->iface_combinations; | 
|---|
| 2449 | n = wiphy->n_iface_combinations; | 
|---|
| 2450 | } | 
|---|
| 2451 | for (i = 0; i < n; i++) { | 
|---|
| 2452 | struct ieee80211_iface_limit *limits; | 
|---|
| 2453 | u32 all_iftypes = 0; | 
|---|
| 2454 |  | 
|---|
| 2455 | c = &cs[i]; | 
|---|
| 2456 | if (num_interfaces > c->max_interfaces) | 
|---|
| 2457 | continue; | 
|---|
| 2458 | if (params->num_different_channels > c->num_different_channels) | 
|---|
| 2459 | continue; | 
|---|
| 2460 |  | 
|---|
| 2461 | limits = kmemdup_array(src: c->limits, count: c->n_limits, element_size: sizeof(*limits), | 
|---|
| 2462 | GFP_KERNEL); | 
|---|
| 2463 | if (!limits) | 
|---|
| 2464 | return -ENOMEM; | 
|---|
| 2465 |  | 
|---|
| 2466 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { | 
|---|
| 2467 | if (cfg80211_iftype_allowed(wiphy, iftype, is_4addr: 0, check_swif: 1)) | 
|---|
| 2468 | continue; | 
|---|
| 2469 | for (j = 0; j < c->n_limits; j++) { | 
|---|
| 2470 | all_iftypes |= limits[j].types; | 
|---|
| 2471 | if (!(limits[j].types & BIT(iftype))) | 
|---|
| 2472 | continue; | 
|---|
| 2473 | if (limits[j].max < params->iftype_num[iftype]) | 
|---|
| 2474 | goto cont; | 
|---|
| 2475 | limits[j].max -= params->iftype_num[iftype]; | 
|---|
| 2476 | } | 
|---|
| 2477 | } | 
|---|
| 2478 |  | 
|---|
| 2479 | if (params->radar_detect != | 
|---|
| 2480 | (c->radar_detect_widths & params->radar_detect)) | 
|---|
| 2481 | goto cont; | 
|---|
| 2482 |  | 
|---|
| 2483 | if (params->radar_detect && c->radar_detect_regions && | 
|---|
| 2484 | !(c->radar_detect_regions & BIT(region))) | 
|---|
| 2485 | goto cont; | 
|---|
| 2486 |  | 
|---|
| 2487 | /* Finally check that all iftypes that we're currently | 
|---|
| 2488 | * using are actually part of this combination. If they | 
|---|
| 2489 | * aren't then we can't use this combination and have | 
|---|
| 2490 | * to continue to the next. | 
|---|
| 2491 | */ | 
|---|
| 2492 | if ((all_iftypes & used_iftypes) != used_iftypes) | 
|---|
| 2493 | goto cont; | 
|---|
| 2494 |  | 
|---|
| 2495 | if (beacon_int_gcd) { | 
|---|
| 2496 | if (c->beacon_int_min_gcd && | 
|---|
| 2497 | beacon_int_gcd < c->beacon_int_min_gcd) | 
|---|
| 2498 | goto cont; | 
|---|
| 2499 | if (!c->beacon_int_min_gcd && beacon_int_different) | 
|---|
| 2500 | goto cont; | 
|---|
| 2501 | } | 
|---|
| 2502 |  | 
|---|
| 2503 | /* This combination covered all interface types and | 
|---|
| 2504 | * supported the requested numbers, so we're good. | 
|---|
| 2505 | */ | 
|---|
| 2506 |  | 
|---|
| 2507 | (*iter)(c, data); | 
|---|
| 2508 | cont: | 
|---|
| 2509 | kfree(objp: limits); | 
|---|
| 2510 | } | 
|---|
| 2511 |  | 
|---|
| 2512 | return 0; | 
|---|
| 2513 | } | 
|---|
| 2514 | EXPORT_SYMBOL(cfg80211_iter_combinations); | 
|---|
| 2515 |  | 
|---|
| 2516 | static void | 
|---|
| 2517 | cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c, | 
|---|
| 2518 | void *data) | 
|---|
| 2519 | { | 
|---|
| 2520 | int *num = data; | 
|---|
| 2521 | (*num)++; | 
|---|
| 2522 | } | 
|---|
| 2523 |  | 
|---|
| 2524 | int cfg80211_check_combinations(struct wiphy *wiphy, | 
|---|
| 2525 | struct iface_combination_params *params) | 
|---|
| 2526 | { | 
|---|
| 2527 | int err, num = 0; | 
|---|
| 2528 |  | 
|---|
| 2529 | err = cfg80211_iter_combinations(wiphy, params, | 
|---|
| 2530 | cfg80211_iter_sum_ifcombs, &num); | 
|---|
| 2531 | if (err) | 
|---|
| 2532 | return err; | 
|---|
| 2533 | if (num == 0) | 
|---|
| 2534 | return -EBUSY; | 
|---|
| 2535 |  | 
|---|
| 2536 | return 0; | 
|---|
| 2537 | } | 
|---|
| 2538 | EXPORT_SYMBOL(cfg80211_check_combinations); | 
|---|
| 2539 |  | 
|---|
| 2540 | int cfg80211_get_radio_idx_by_chan(struct wiphy *wiphy, | 
|---|
| 2541 | const struct ieee80211_channel *chan) | 
|---|
| 2542 | { | 
|---|
| 2543 | const struct wiphy_radio *radio; | 
|---|
| 2544 | int i, j; | 
|---|
| 2545 | u32 freq; | 
|---|
| 2546 |  | 
|---|
| 2547 | if (!chan) | 
|---|
| 2548 | return -EINVAL; | 
|---|
| 2549 |  | 
|---|
| 2550 | freq = ieee80211_channel_to_khz(chan); | 
|---|
| 2551 | for (i = 0; i < wiphy->n_radio; i++) { | 
|---|
| 2552 | radio = &wiphy->radio[i]; | 
|---|
| 2553 | for (j = 0; j < radio->n_freq_range; j++) { | 
|---|
| 2554 | if (freq >= radio->freq_range[j].start_freq && | 
|---|
| 2555 | freq < radio->freq_range[j].end_freq) | 
|---|
| 2556 | return i; | 
|---|
| 2557 | } | 
|---|
| 2558 | } | 
|---|
| 2559 |  | 
|---|
| 2560 | return -EINVAL; | 
|---|
| 2561 | } | 
|---|
| 2562 | EXPORT_SYMBOL(cfg80211_get_radio_idx_by_chan); | 
|---|
| 2563 |  | 
|---|
| 2564 | int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | 
|---|
| 2565 | const u8 *rates, unsigned int n_rates, | 
|---|
| 2566 | u32 *mask) | 
|---|
| 2567 | { | 
|---|
| 2568 | int i, j; | 
|---|
| 2569 |  | 
|---|
| 2570 | if (!sband) | 
|---|
| 2571 | return -EINVAL; | 
|---|
| 2572 |  | 
|---|
| 2573 | if (n_rates == 0 || n_rates > NL80211_MAX_SUPP_RATES) | 
|---|
| 2574 | return -EINVAL; | 
|---|
| 2575 |  | 
|---|
| 2576 | *mask = 0; | 
|---|
| 2577 |  | 
|---|
| 2578 | for (i = 0; i < n_rates; i++) { | 
|---|
| 2579 | int rate = (rates[i] & 0x7f) * 5; | 
|---|
| 2580 | bool found = false; | 
|---|
| 2581 |  | 
|---|
| 2582 | for (j = 0; j < sband->n_bitrates; j++) { | 
|---|
| 2583 | if (sband->bitrates[j].bitrate == rate) { | 
|---|
| 2584 | found = true; | 
|---|
| 2585 | *mask |= BIT(j); | 
|---|
| 2586 | break; | 
|---|
| 2587 | } | 
|---|
| 2588 | } | 
|---|
| 2589 | if (!found) | 
|---|
| 2590 | return -EINVAL; | 
|---|
| 2591 | } | 
|---|
| 2592 |  | 
|---|
| 2593 | /* | 
|---|
| 2594 | * mask must have at least one bit set here since we | 
|---|
| 2595 | * didn't accept a 0-length rates array nor allowed | 
|---|
| 2596 | * entries in the array that didn't exist | 
|---|
| 2597 | */ | 
|---|
| 2598 |  | 
|---|
| 2599 | return 0; | 
|---|
| 2600 | } | 
|---|
| 2601 |  | 
|---|
| 2602 | unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy) | 
|---|
| 2603 | { | 
|---|
| 2604 | enum nl80211_band band; | 
|---|
| 2605 | unsigned int n_channels = 0; | 
|---|
| 2606 |  | 
|---|
| 2607 | for (band = 0; band < NUM_NL80211_BANDS; band++) | 
|---|
| 2608 | if (wiphy->bands[band]) | 
|---|
| 2609 | n_channels += wiphy->bands[band]->n_channels; | 
|---|
| 2610 |  | 
|---|
| 2611 | return n_channels; | 
|---|
| 2612 | } | 
|---|
| 2613 | EXPORT_SYMBOL(ieee80211_get_num_supported_channels); | 
|---|
| 2614 |  | 
|---|
| 2615 | int cfg80211_get_station(struct net_device *dev, const u8 *mac_addr, | 
|---|
| 2616 | struct station_info *sinfo) | 
|---|
| 2617 | { | 
|---|
| 2618 | struct cfg80211_registered_device *rdev; | 
|---|
| 2619 | struct wireless_dev *wdev; | 
|---|
| 2620 |  | 
|---|
| 2621 | wdev = dev->ieee80211_ptr; | 
|---|
| 2622 | if (!wdev) | 
|---|
| 2623 | return -EOPNOTSUPP; | 
|---|
| 2624 |  | 
|---|
| 2625 | rdev = wiphy_to_rdev(wiphy: wdev->wiphy); | 
|---|
| 2626 | if (!rdev->ops->get_station) | 
|---|
| 2627 | return -EOPNOTSUPP; | 
|---|
| 2628 |  | 
|---|
| 2629 | memset(s: sinfo, c: 0, n: sizeof(*sinfo)); | 
|---|
| 2630 |  | 
|---|
| 2631 | guard(wiphy)(T: &rdev->wiphy); | 
|---|
| 2632 |  | 
|---|
| 2633 | return rdev_get_station(rdev, dev, mac: mac_addr, sinfo); | 
|---|
| 2634 | } | 
|---|
| 2635 | EXPORT_SYMBOL(cfg80211_get_station); | 
|---|
| 2636 |  | 
|---|
| 2637 | void cfg80211_free_nan_func(struct cfg80211_nan_func *f) | 
|---|
| 2638 | { | 
|---|
| 2639 | int i; | 
|---|
| 2640 |  | 
|---|
| 2641 | if (!f) | 
|---|
| 2642 | return; | 
|---|
| 2643 |  | 
|---|
| 2644 | kfree(objp: f->serv_spec_info); | 
|---|
| 2645 | kfree(objp: f->srf_bf); | 
|---|
| 2646 | kfree(objp: f->srf_macs); | 
|---|
| 2647 | for (i = 0; i < f->num_rx_filters; i++) | 
|---|
| 2648 | kfree(objp: f->rx_filters[i].filter); | 
|---|
| 2649 |  | 
|---|
| 2650 | for (i = 0; i < f->num_tx_filters; i++) | 
|---|
| 2651 | kfree(objp: f->tx_filters[i].filter); | 
|---|
| 2652 |  | 
|---|
| 2653 | kfree(objp: f->rx_filters); | 
|---|
| 2654 | kfree(objp: f->tx_filters); | 
|---|
| 2655 | kfree(objp: f); | 
|---|
| 2656 | } | 
|---|
| 2657 | EXPORT_SYMBOL(cfg80211_free_nan_func); | 
|---|
| 2658 |  | 
|---|
| 2659 | bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range, | 
|---|
| 2660 | u32 center_freq_khz, u32 bw_khz) | 
|---|
| 2661 | { | 
|---|
| 2662 | u32 start_freq_khz, end_freq_khz; | 
|---|
| 2663 |  | 
|---|
| 2664 | start_freq_khz = center_freq_khz - (bw_khz / 2); | 
|---|
| 2665 | end_freq_khz = center_freq_khz + (bw_khz / 2); | 
|---|
| 2666 |  | 
|---|
| 2667 | if (start_freq_khz >= freq_range->start_freq_khz && | 
|---|
| 2668 | end_freq_khz <= freq_range->end_freq_khz) | 
|---|
| 2669 | return true; | 
|---|
| 2670 |  | 
|---|
| 2671 | return false; | 
|---|
| 2672 | } | 
|---|
| 2673 |  | 
|---|
| 2674 | int cfg80211_link_sinfo_alloc_tid_stats(struct link_station_info *link_sinfo, | 
|---|
| 2675 | gfp_t gfp) | 
|---|
| 2676 | { | 
|---|
| 2677 | link_sinfo->pertid = kcalloc(IEEE80211_NUM_TIDS + 1, | 
|---|
| 2678 | sizeof(*link_sinfo->pertid), gfp); | 
|---|
| 2679 | if (!link_sinfo->pertid) | 
|---|
| 2680 | return -ENOMEM; | 
|---|
| 2681 |  | 
|---|
| 2682 | return 0; | 
|---|
| 2683 | } | 
|---|
| 2684 | EXPORT_SYMBOL(cfg80211_link_sinfo_alloc_tid_stats); | 
|---|
| 2685 |  | 
|---|
| 2686 | int cfg80211_sinfo_alloc_tid_stats(struct station_info *sinfo, gfp_t gfp) | 
|---|
| 2687 | { | 
|---|
| 2688 | sinfo->pertid = kcalloc(IEEE80211_NUM_TIDS + 1, | 
|---|
| 2689 | sizeof(*(sinfo->pertid)), | 
|---|
| 2690 | gfp); | 
|---|
| 2691 | if (!sinfo->pertid) | 
|---|
| 2692 | return -ENOMEM; | 
|---|
| 2693 |  | 
|---|
| 2694 | return 0; | 
|---|
| 2695 | } | 
|---|
| 2696 | EXPORT_SYMBOL(cfg80211_sinfo_alloc_tid_stats); | 
|---|
| 2697 |  | 
|---|
| 2698 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | 
|---|
| 2699 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | 
|---|
| 2700 | const unsigned char [] __aligned(2) = | 
|---|
| 2701 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | 
|---|
| 2702 | EXPORT_SYMBOL(rfc1042_header); | 
|---|
| 2703 |  | 
|---|
| 2704 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ | 
|---|
| 2705 | const unsigned char [] __aligned(2) = | 
|---|
| 2706 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | 
|---|
| 2707 | EXPORT_SYMBOL(bridge_tunnel_header); | 
|---|
| 2708 |  | 
|---|
| 2709 | /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ | 
|---|
| 2710 | struct iapp_layer2_update { | 
|---|
| 2711 | u8 da[ETH_ALEN];	/* broadcast */ | 
|---|
| 2712 | u8 sa[ETH_ALEN];	/* STA addr */ | 
|---|
| 2713 | __be16 len;		/* 6 */ | 
|---|
| 2714 | u8 dsap;		/* 0 */ | 
|---|
| 2715 | u8 ssap;		/* 0 */ | 
|---|
| 2716 | u8 control; | 
|---|
| 2717 | u8 xid_info[3]; | 
|---|
| 2718 | } __packed; | 
|---|
| 2719 |  | 
|---|
| 2720 | void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr) | 
|---|
| 2721 | { | 
|---|
| 2722 | struct iapp_layer2_update *msg; | 
|---|
| 2723 | struct sk_buff *skb; | 
|---|
| 2724 |  | 
|---|
| 2725 | /* Send Level 2 Update Frame to update forwarding tables in layer 2 | 
|---|
| 2726 | * bridge devices */ | 
|---|
| 2727 |  | 
|---|
| 2728 | skb = dev_alloc_skb(length: sizeof(*msg)); | 
|---|
| 2729 | if (!skb) | 
|---|
| 2730 | return; | 
|---|
| 2731 | msg = skb_put(skb, len: sizeof(*msg)); | 
|---|
| 2732 |  | 
|---|
| 2733 | /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) | 
|---|
| 2734 | * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ | 
|---|
| 2735 |  | 
|---|
| 2736 | eth_broadcast_addr(addr: msg->da); | 
|---|
| 2737 | ether_addr_copy(dst: msg->sa, src: addr); | 
|---|
| 2738 | msg->len = htons(6); | 
|---|
| 2739 | msg->dsap = 0; | 
|---|
| 2740 | msg->ssap = 0x01;	/* NULL LSAP, CR Bit: Response */ | 
|---|
| 2741 | msg->control = 0xaf;	/* XID response lsb.1111F101. | 
|---|
| 2742 | * F=0 (no poll command; unsolicited frame) */ | 
|---|
| 2743 | msg->xid_info[0] = 0x81;	/* XID format identifier */ | 
|---|
| 2744 | msg->xid_info[1] = 1;	/* LLC types/classes: Type 1 LLC */ | 
|---|
| 2745 | msg->xid_info[2] = 0;	/* XID sender's receive window size (RW) */ | 
|---|
| 2746 |  | 
|---|
| 2747 | skb->dev = dev; | 
|---|
| 2748 | skb->protocol = eth_type_trans(skb, dev); | 
|---|
| 2749 | memset(s: skb->cb, c: 0, n: sizeof(skb->cb)); | 
|---|
| 2750 | netif_rx(skb); | 
|---|
| 2751 | } | 
|---|
| 2752 | EXPORT_SYMBOL(cfg80211_send_layer2_update); | 
|---|
| 2753 |  | 
|---|
| 2754 | int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap, | 
|---|
| 2755 | enum ieee80211_vht_chanwidth bw, | 
|---|
| 2756 | int mcs, bool ext_nss_bw_capable, | 
|---|
| 2757 | unsigned int max_vht_nss) | 
|---|
| 2758 | { | 
|---|
| 2759 | u16 map = le16_to_cpu(cap->supp_mcs.rx_mcs_map); | 
|---|
| 2760 | int ext_nss_bw; | 
|---|
| 2761 | int supp_width; | 
|---|
| 2762 | int i, mcs_encoding; | 
|---|
| 2763 |  | 
|---|
| 2764 | if (map == 0xffff) | 
|---|
| 2765 | return 0; | 
|---|
| 2766 |  | 
|---|
| 2767 | if (WARN_ON(mcs > 9 || max_vht_nss > 8)) | 
|---|
| 2768 | return 0; | 
|---|
| 2769 | if (mcs <= 7) | 
|---|
| 2770 | mcs_encoding = 0; | 
|---|
| 2771 | else if (mcs == 8) | 
|---|
| 2772 | mcs_encoding = 1; | 
|---|
| 2773 | else | 
|---|
| 2774 | mcs_encoding = 2; | 
|---|
| 2775 |  | 
|---|
| 2776 | if (!max_vht_nss) { | 
|---|
| 2777 | /* find max_vht_nss for the given MCS */ | 
|---|
| 2778 | for (i = 7; i >= 0; i--) { | 
|---|
| 2779 | int supp = (map >> (2 * i)) & 3; | 
|---|
| 2780 |  | 
|---|
| 2781 | if (supp == 3) | 
|---|
| 2782 | continue; | 
|---|
| 2783 |  | 
|---|
| 2784 | if (supp >= mcs_encoding) { | 
|---|
| 2785 | max_vht_nss = i + 1; | 
|---|
| 2786 | break; | 
|---|
| 2787 | } | 
|---|
| 2788 | } | 
|---|
| 2789 | } | 
|---|
| 2790 |  | 
|---|
| 2791 | if (!(cap->supp_mcs.tx_mcs_map & | 
|---|
| 2792 | cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE))) | 
|---|
| 2793 | return max_vht_nss; | 
|---|
| 2794 |  | 
|---|
| 2795 | ext_nss_bw = le32_get_bits(v: cap->vht_cap_info, | 
|---|
| 2796 | IEEE80211_VHT_CAP_EXT_NSS_BW_MASK); | 
|---|
| 2797 | supp_width = le32_get_bits(v: cap->vht_cap_info, | 
|---|
| 2798 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK); | 
|---|
| 2799 |  | 
|---|
| 2800 | /* if not capable, treat ext_nss_bw as 0 */ | 
|---|
| 2801 | if (!ext_nss_bw_capable) | 
|---|
| 2802 | ext_nss_bw = 0; | 
|---|
| 2803 |  | 
|---|
| 2804 | /* This is invalid */ | 
|---|
| 2805 | if (supp_width == 3) | 
|---|
| 2806 | return 0; | 
|---|
| 2807 |  | 
|---|
| 2808 | /* This is an invalid combination so pretend nothing is supported */ | 
|---|
| 2809 | if (supp_width == 2 && (ext_nss_bw == 1 || ext_nss_bw == 2)) | 
|---|
| 2810 | return 0; | 
|---|
| 2811 |  | 
|---|
| 2812 | /* | 
|---|
| 2813 | * Cover all the special cases according to IEEE 802.11-2016 | 
|---|
| 2814 | * Table 9-250. All other cases are either factor of 1 or not | 
|---|
| 2815 | * valid/supported. | 
|---|
| 2816 | */ | 
|---|
| 2817 | switch (bw) { | 
|---|
| 2818 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | 
|---|
| 2819 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | 
|---|
| 2820 | if ((supp_width == 1 || supp_width == 2) && | 
|---|
| 2821 | ext_nss_bw == 3) | 
|---|
| 2822 | return 2 * max_vht_nss; | 
|---|
| 2823 | break; | 
|---|
| 2824 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | 
|---|
| 2825 | if (supp_width == 0 && | 
|---|
| 2826 | (ext_nss_bw == 1 || ext_nss_bw == 2)) | 
|---|
| 2827 | return max_vht_nss / 2; | 
|---|
| 2828 | if (supp_width == 0 && | 
|---|
| 2829 | ext_nss_bw == 3) | 
|---|
| 2830 | return (3 * max_vht_nss) / 4; | 
|---|
| 2831 | if (supp_width == 1 && | 
|---|
| 2832 | ext_nss_bw == 3) | 
|---|
| 2833 | return 2 * max_vht_nss; | 
|---|
| 2834 | break; | 
|---|
| 2835 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | 
|---|
| 2836 | if (supp_width == 0 && ext_nss_bw == 1) | 
|---|
| 2837 | return 0; /* not possible */ | 
|---|
| 2838 | if (supp_width == 0 && | 
|---|
| 2839 | ext_nss_bw == 2) | 
|---|
| 2840 | return max_vht_nss / 2; | 
|---|
| 2841 | if (supp_width == 0 && | 
|---|
| 2842 | ext_nss_bw == 3) | 
|---|
| 2843 | return (3 * max_vht_nss) / 4; | 
|---|
| 2844 | if (supp_width == 1 && | 
|---|
| 2845 | ext_nss_bw == 0) | 
|---|
| 2846 | return 0; /* not possible */ | 
|---|
| 2847 | if (supp_width == 1 && | 
|---|
| 2848 | ext_nss_bw == 1) | 
|---|
| 2849 | return max_vht_nss / 2; | 
|---|
| 2850 | if (supp_width == 1 && | 
|---|
| 2851 | ext_nss_bw == 2) | 
|---|
| 2852 | return (3 * max_vht_nss) / 4; | 
|---|
| 2853 | break; | 
|---|
| 2854 | } | 
|---|
| 2855 |  | 
|---|
| 2856 | /* not covered or invalid combination received */ | 
|---|
| 2857 | return max_vht_nss; | 
|---|
| 2858 | } | 
|---|
| 2859 | EXPORT_SYMBOL(ieee80211_get_vht_max_nss); | 
|---|
| 2860 |  | 
|---|
| 2861 | bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype, | 
|---|
| 2862 | bool is_4addr, u8 check_swif) | 
|---|
| 2863 |  | 
|---|
| 2864 | { | 
|---|
| 2865 | bool is_vlan = iftype == NL80211_IFTYPE_AP_VLAN; | 
|---|
| 2866 |  | 
|---|
| 2867 | switch (check_swif) { | 
|---|
| 2868 | case 0: | 
|---|
| 2869 | if (is_vlan && is_4addr) | 
|---|
| 2870 | return wiphy->flags & WIPHY_FLAG_4ADDR_AP; | 
|---|
| 2871 | return wiphy->interface_modes & BIT(iftype); | 
|---|
| 2872 | case 1: | 
|---|
| 2873 | if (!(wiphy->software_iftypes & BIT(iftype)) && is_vlan) | 
|---|
| 2874 | return wiphy->flags & WIPHY_FLAG_4ADDR_AP; | 
|---|
| 2875 | return wiphy->software_iftypes & BIT(iftype); | 
|---|
| 2876 | default: | 
|---|
| 2877 | break; | 
|---|
| 2878 | } | 
|---|
| 2879 |  | 
|---|
| 2880 | return false; | 
|---|
| 2881 | } | 
|---|
| 2882 | EXPORT_SYMBOL(cfg80211_iftype_allowed); | 
|---|
| 2883 |  | 
|---|
| 2884 | void cfg80211_remove_link(struct wireless_dev *wdev, unsigned int link_id) | 
|---|
| 2885 | { | 
|---|
| 2886 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy: wdev->wiphy); | 
|---|
| 2887 |  | 
|---|
| 2888 | lockdep_assert_wiphy(wdev->wiphy); | 
|---|
| 2889 |  | 
|---|
| 2890 | switch (wdev->iftype) { | 
|---|
| 2891 | case NL80211_IFTYPE_AP: | 
|---|
| 2892 | case NL80211_IFTYPE_P2P_GO: | 
|---|
| 2893 | cfg80211_stop_ap(rdev, dev: wdev->netdev, link: link_id, notify: true); | 
|---|
| 2894 | break; | 
|---|
| 2895 | default: | 
|---|
| 2896 | /* per-link not relevant */ | 
|---|
| 2897 | break; | 
|---|
| 2898 | } | 
|---|
| 2899 |  | 
|---|
| 2900 | rdev_del_intf_link(rdev, wdev, link_id); | 
|---|
| 2901 |  | 
|---|
| 2902 | wdev->valid_links &= ~BIT(link_id); | 
|---|
| 2903 | eth_zero_addr(addr: wdev->links[link_id].addr); | 
|---|
| 2904 | } | 
|---|
| 2905 |  | 
|---|
| 2906 | void cfg80211_remove_links(struct wireless_dev *wdev) | 
|---|
| 2907 | { | 
|---|
| 2908 | unsigned int link_id; | 
|---|
| 2909 |  | 
|---|
| 2910 | /* | 
|---|
| 2911 | * links are controlled by upper layers (userspace/cfg) | 
|---|
| 2912 | * only for AP mode, so only remove them here for AP | 
|---|
| 2913 | */ | 
|---|
| 2914 | if (wdev->iftype != NL80211_IFTYPE_AP) | 
|---|
| 2915 | return; | 
|---|
| 2916 |  | 
|---|
| 2917 | if (wdev->valid_links) { | 
|---|
| 2918 | for_each_valid_link(wdev, link_id) | 
|---|
| 2919 | cfg80211_remove_link(wdev, link_id); | 
|---|
| 2920 | } | 
|---|
| 2921 | } | 
|---|
| 2922 |  | 
|---|
| 2923 | int cfg80211_remove_virtual_intf(struct cfg80211_registered_device *rdev, | 
|---|
| 2924 | struct wireless_dev *wdev) | 
|---|
| 2925 | { | 
|---|
| 2926 | cfg80211_remove_links(wdev); | 
|---|
| 2927 |  | 
|---|
| 2928 | return rdev_del_virtual_intf(rdev, wdev); | 
|---|
| 2929 | } | 
|---|
| 2930 |  | 
|---|
| 2931 | const struct wiphy_iftype_ext_capab * | 
|---|
| 2932 | cfg80211_get_iftype_ext_capa(struct wiphy *wiphy, enum nl80211_iftype type) | 
|---|
| 2933 | { | 
|---|
| 2934 | int i; | 
|---|
| 2935 |  | 
|---|
| 2936 | for (i = 0; i < wiphy->num_iftype_ext_capab; i++) { | 
|---|
| 2937 | if (wiphy->iftype_ext_capab[i].iftype == type) | 
|---|
| 2938 | return &wiphy->iftype_ext_capab[i]; | 
|---|
| 2939 | } | 
|---|
| 2940 |  | 
|---|
| 2941 | return NULL; | 
|---|
| 2942 | } | 
|---|
| 2943 | EXPORT_SYMBOL(cfg80211_get_iftype_ext_capa); | 
|---|
| 2944 |  | 
|---|
| 2945 | static bool | 
|---|
| 2946 | ieee80211_radio_freq_range_valid(const struct wiphy_radio *radio, | 
|---|
| 2947 | u32 freq, u32 width) | 
|---|
| 2948 | { | 
|---|
| 2949 | const struct wiphy_radio_freq_range *r; | 
|---|
| 2950 | int i; | 
|---|
| 2951 |  | 
|---|
| 2952 | for (i = 0; i < radio->n_freq_range; i++) { | 
|---|
| 2953 | r = &radio->freq_range[i]; | 
|---|
| 2954 | if (freq - width / 2 >= r->start_freq && | 
|---|
| 2955 | freq + width / 2 <= r->end_freq) | 
|---|
| 2956 | return true; | 
|---|
| 2957 | } | 
|---|
| 2958 |  | 
|---|
| 2959 | return false; | 
|---|
| 2960 | } | 
|---|
| 2961 |  | 
|---|
| 2962 | bool cfg80211_radio_chandef_valid(const struct wiphy_radio *radio, | 
|---|
| 2963 | const struct cfg80211_chan_def *chandef) | 
|---|
| 2964 | { | 
|---|
| 2965 | u32 freq, width; | 
|---|
| 2966 |  | 
|---|
| 2967 | freq = ieee80211_chandef_to_khz(chandef); | 
|---|
| 2968 | width = MHZ_TO_KHZ(cfg80211_chandef_get_width(chandef)); | 
|---|
| 2969 | if (!ieee80211_radio_freq_range_valid(radio, freq, width)) | 
|---|
| 2970 | return false; | 
|---|
| 2971 |  | 
|---|
| 2972 | freq = MHZ_TO_KHZ(chandef->center_freq2); | 
|---|
| 2973 | if (freq && !ieee80211_radio_freq_range_valid(radio, freq, width)) | 
|---|
| 2974 | return false; | 
|---|
| 2975 |  | 
|---|
| 2976 | return true; | 
|---|
| 2977 | } | 
|---|
| 2978 | EXPORT_SYMBOL(cfg80211_radio_chandef_valid); | 
|---|
| 2979 |  | 
|---|
| 2980 | bool cfg80211_wdev_channel_allowed(struct wireless_dev *wdev, | 
|---|
| 2981 | struct ieee80211_channel *chan) | 
|---|
| 2982 | { | 
|---|
| 2983 | struct wiphy *wiphy = wdev->wiphy; | 
|---|
| 2984 | const struct wiphy_radio *radio; | 
|---|
| 2985 | struct cfg80211_chan_def chandef; | 
|---|
| 2986 | u32 radio_mask; | 
|---|
| 2987 | int i; | 
|---|
| 2988 |  | 
|---|
| 2989 | radio_mask = wdev->radio_mask; | 
|---|
| 2990 | if (!wiphy->n_radio || radio_mask == BIT(wiphy->n_radio) - 1) | 
|---|
| 2991 | return true; | 
|---|
| 2992 |  | 
|---|
| 2993 | cfg80211_chandef_create(chandef: &chandef, channel: chan, chantype: NL80211_CHAN_HT20); | 
|---|
| 2994 | for (i = 0; i < wiphy->n_radio; i++) { | 
|---|
| 2995 | if (!(radio_mask & BIT(i))) | 
|---|
| 2996 | continue; | 
|---|
| 2997 |  | 
|---|
| 2998 | radio = &wiphy->radio[i]; | 
|---|
| 2999 | if (!cfg80211_radio_chandef_valid(radio, &chandef)) | 
|---|
| 3000 | continue; | 
|---|
| 3001 |  | 
|---|
| 3002 | return true; | 
|---|
| 3003 | } | 
|---|
| 3004 |  | 
|---|
| 3005 | return false; | 
|---|
| 3006 | } | 
|---|
| 3007 | EXPORT_SYMBOL(cfg80211_wdev_channel_allowed); | 
|---|
| 3008 |  | 
|---|