Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: Add initial support for EHT and 320 MHz channels

Add initial support for EHT and 320 MHz bandwidth in mac80211.

As a new IEEE80211_STA_RX_BW_320 is added to
enum ieee80211_sta_rx_bandwidth, update the drivers to avoid
compilation warnings.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Link: https://lore.kernel.org/r/20220214173004.0f144cc0bba6.Iad18111264da87eed5fd7b017f0cc6e58c604e07@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Ilan Peer and committed by
Johannes Berg
5dca295d f0e6bea8

+215 -61
+1
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
··· 87 87 } 88 88 89 89 switch (sta->bandwidth) { 90 + case IEEE80211_STA_RX_BW_320: 90 91 case IEEE80211_STA_RX_BW_160: 91 92 add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_160MHZ); 92 93 fallthrough;
+1
drivers/net/wireless/mac80211_hwsim.c
··· 2195 2195 C(40); 2196 2196 C(80); 2197 2197 C(160); 2198 + C(320); 2198 2199 #undef C 2199 2200 } 2200 2201
+2
include/net/mac80211.h
··· 2005 2005 * @IEEE80211_STA_RX_BW_80: station can receive up to 80 MHz 2006 2006 * @IEEE80211_STA_RX_BW_160: station can receive up to 160 MHz 2007 2007 * (including 80+80 MHz) 2008 + * @IEEE80211_STA_RX_BW_320: station can receive up to 320 MHz 2008 2009 * 2009 2010 * Implementation note: 20 must be zero to be initialized 2010 2011 * correctly, the values must be sorted. ··· 2015 2014 IEEE80211_STA_RX_BW_40, 2016 2015 IEEE80211_STA_RX_BW_80, 2017 2016 IEEE80211_STA_RX_BW_160, 2017 + IEEE80211_STA_RX_BW_320, 2018 2018 }; 2019 2019 2020 2020 /**
+4 -1
net/mac80211/chan.c
··· 218 218 * might be smaller than the configured bw (160). 219 219 */ 220 220 return NL80211_CHAN_WIDTH_160; 221 + case IEEE80211_STA_RX_BW_320: 222 + return NL80211_CHAN_WIDTH_320; 221 223 default: 222 224 WARN_ON(1); 223 225 return NL80211_CHAN_WIDTH_20; ··· 419 417 { 420 418 u32 changed; 421 419 422 - /* expected to handle only 20/40/80/160 channel widths */ 420 + /* expected to handle only 20/40/80/160/320 channel widths */ 423 421 switch (chandef->width) { 424 422 case NL80211_CHAN_WIDTH_20_NOHT: 425 423 case NL80211_CHAN_WIDTH_20: ··· 427 425 case NL80211_CHAN_WIDTH_80: 428 426 case NL80211_CHAN_WIDTH_80P80: 429 427 case NL80211_CHAN_WIDTH_160: 428 + case NL80211_CHAN_WIDTH_320: 430 429 break; 431 430 default: 432 431 WARN_ON(1);
+3
net/mac80211/ieee80211_i.h
··· 366 366 IEEE80211_STA_DISABLE_WMM = BIT(14), 367 367 IEEE80211_STA_ENABLE_RRM = BIT(15), 368 368 IEEE80211_STA_DISABLE_HE = BIT(16), 369 + IEEE80211_STA_DISABLE_EHT = BIT(17), 370 + IEEE80211_STA_DISABLE_320MHZ = BIT(18), 369 371 }; 370 372 371 373 struct ieee80211_mgd_auth_data { ··· 2416 2414 struct cfg80211_chan_def *chandef); 2417 2415 bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata, 2418 2416 const struct ieee80211_he_operation *he_oper, 2417 + const struct ieee80211_eht_operation *eht_oper, 2419 2418 struct cfg80211_chan_def *chandef); 2420 2419 bool ieee80211_chandef_s1g_oper(const struct ieee80211_s1g_oper_ie *oper, 2421 2420 struct cfg80211_chan_def *chandef);
+3 -2
net/mac80211/mesh.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 /* 3 3 * Copyright (c) 2008, 2009 open80211s Ltd. 4 - * Copyright (C) 2018 - 2020 Intel Corporation 4 + * Copyright (C) 2018 - 2021 Intel Corporation 5 5 * Authors: Luis Carlos Cobo <luisca@cozybit.com> 6 6 * Javier Cardona <javier@cozybit.com> 7 7 */ ··· 104 104 ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info, 105 105 ie->vht_operation, ie->ht_operation, 106 106 &sta_chan_def); 107 - ieee80211_chandef_he_6ghz_oper(sdata, ie->he_operation, &sta_chan_def); 107 + ieee80211_chandef_he_6ghz_oper(sdata, ie->he_operation, NULL, 108 + &sta_chan_def); 108 109 109 110 if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef, 110 111 &sta_chan_def))
+86 -23
net/mac80211/mlme.c
··· 149 149 const struct ieee80211_ht_operation *ht_oper, 150 150 const struct ieee80211_vht_operation *vht_oper, 151 151 const struct ieee80211_he_operation *he_oper, 152 + const struct ieee80211_eht_operation *eht_oper, 152 153 const struct ieee80211_s1g_oper_ie *s1g_oper, 153 154 struct cfg80211_chan_def *chandef, bool tracking) 154 155 { ··· 165 164 chandef->freq1_offset = channel->freq_offset; 166 165 167 166 if (channel->band == NL80211_BAND_6GHZ) { 168 - if (!ieee80211_chandef_he_6ghz_oper(sdata, he_oper, chandef)) { 167 + if (!ieee80211_chandef_he_6ghz_oper(sdata, he_oper, eht_oper, 168 + chandef)) { 169 169 mlme_dbg(sdata, 170 - "bad 6 GHz operation, disabling HT/VHT/HE\n"); 170 + "bad 6 GHz operation, disabling HT/VHT/HE/EHT\n"); 171 171 ret = IEEE80211_STA_DISABLE_HT | 172 172 IEEE80211_STA_DISABLE_VHT | 173 - IEEE80211_STA_DISABLE_HE; 173 + IEEE80211_STA_DISABLE_HE | 174 + IEEE80211_STA_DISABLE_EHT; 174 175 } else { 175 176 ret = 0; 176 177 } ··· 199 196 mlme_dbg(sdata, "HT operation missing / HT not supported\n"); 200 197 ret = IEEE80211_STA_DISABLE_HT | 201 198 IEEE80211_STA_DISABLE_VHT | 202 - IEEE80211_STA_DISABLE_HE; 199 + IEEE80211_STA_DISABLE_HE | 200 + IEEE80211_STA_DISABLE_EHT; 203 201 goto out; 204 202 } 205 203 ··· 223 219 ht_oper->primary_chan, channel->band); 224 220 ret = IEEE80211_STA_DISABLE_HT | 225 221 IEEE80211_STA_DISABLE_VHT | 226 - IEEE80211_STA_DISABLE_HE; 222 + IEEE80211_STA_DISABLE_HE | 223 + IEEE80211_STA_DISABLE_EHT; 227 224 goto out; 228 225 } 229 226 ··· 265 260 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) 266 261 sdata_info(sdata, 267 262 "HE AP VHT information is invalid, disabling HE\n"); 268 - ret = IEEE80211_STA_DISABLE_HE; 263 + ret = IEEE80211_STA_DISABLE_HE | IEEE80211_STA_DISABLE_EHT; 269 264 goto out; 270 265 } 271 266 } else if (!ieee80211_chandef_vht_oper(&sdata->local->hw, ··· 345 340 if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { 346 341 ret = IEEE80211_STA_DISABLE_HT | 347 342 IEEE80211_STA_DISABLE_VHT | 348 - IEEE80211_STA_DISABLE_HE; 343 + IEEE80211_STA_DISABLE_HE | 344 + IEEE80211_STA_DISABLE_EHT; 349 345 break; 350 346 } 351 347 ··· 355 349 356 350 if (!he_oper || !cfg80211_chandef_usable(sdata->wdev.wiphy, chandef, 357 351 IEEE80211_CHAN_NO_HE)) 358 - ret |= IEEE80211_STA_DISABLE_HE; 352 + ret |= IEEE80211_STA_DISABLE_HE | IEEE80211_STA_DISABLE_EHT; 353 + 354 + if (!eht_oper || !cfg80211_chandef_usable(sdata->wdev.wiphy, chandef, 355 + IEEE80211_CHAN_NO_EHT)) 356 + ret |= IEEE80211_STA_DISABLE_EHT; 359 357 360 358 if (chandef->width != vht_chandef.width && !tracking) 361 359 sdata_info(sdata, ··· 376 366 const struct ieee80211_ht_operation *ht_oper, 377 367 const struct ieee80211_vht_operation *vht_oper, 378 368 const struct ieee80211_he_operation *he_oper, 369 + const struct ieee80211_eht_operation *eht_oper, 379 370 const struct ieee80211_s1g_oper_ie *s1g_oper, 380 371 const u8 *bssid, u32 *changed) 381 372 { ··· 402 391 /* don't check HE if we associated as non-HE station */ 403 392 if (ifmgd->flags & IEEE80211_STA_DISABLE_HE || 404 393 !ieee80211_get_he_iftype_cap(sband, 405 - ieee80211_vif_type_p2p(&sdata->vif))) 406 - 394 + ieee80211_vif_type_p2p(&sdata->vif))) { 407 395 he_oper = NULL; 396 + eht_oper = NULL; 397 + } 398 + 399 + /* don't check EHT if we associated as non-EHT station */ 400 + if (ifmgd->flags & IEEE80211_STA_DISABLE_EHT || 401 + !ieee80211_get_eht_iftype_cap(sband, 402 + ieee80211_vif_type_p2p(&sdata->vif))) 403 + eht_oper = NULL; 408 404 409 405 if (WARN_ON_ONCE(!sta)) 410 406 return -EINVAL; ··· 431 413 432 414 /* calculate new channel (type) based on HT/VHT/HE operation IEs */ 433 415 flags = ieee80211_determine_chantype(sdata, sband, chan, vht_cap_info, 434 - ht_oper, vht_oper, he_oper, 416 + ht_oper, vht_oper, 417 + he_oper, eht_oper, 435 418 s1g_oper, &chandef, true); 436 419 437 420 /* ··· 466 447 if (flags != (ifmgd->flags & (IEEE80211_STA_DISABLE_HT | 467 448 IEEE80211_STA_DISABLE_VHT | 468 449 IEEE80211_STA_DISABLE_HE | 450 + IEEE80211_STA_DISABLE_EHT | 469 451 IEEE80211_STA_DISABLE_40MHZ | 470 452 IEEE80211_STA_DISABLE_80P80MHZ | 471 - IEEE80211_STA_DISABLE_160MHZ)) || 453 + IEEE80211_STA_DISABLE_160MHZ | 454 + IEEE80211_STA_DISABLE_320MHZ)) || 472 455 !cfg80211_chandef_valid(&chandef)) { 473 456 sdata_info(sdata, 474 457 "AP %pM changed caps/bw in a way we can't support (0x%x/0x%x) - disconnect\n", ··· 1011 990 &assoc_data->ap_vht_cap); 1012 991 1013 992 /* 1014 - * If AP doesn't support HT, mark HE as disabled. 993 + * If AP doesn't support HT, mark HE and EHT as disabled. 1015 994 * If on the 5GHz band, make sure it supports VHT. 1016 995 */ 1017 996 if (ifmgd->flags & IEEE80211_STA_DISABLE_HT || 1018 997 (sband->band == NL80211_BAND_5GHZ && 1019 998 ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) 1020 - ifmgd->flags |= IEEE80211_STA_DISABLE_HE; 999 + ifmgd->flags |= IEEE80211_STA_DISABLE_HE | 1000 + IEEE80211_STA_DISABLE_EHT; 1021 1001 1022 1002 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) 1023 1003 ieee80211_add_he_ie(sdata, skb, sband); ··· 4280 4258 if (ieee80211_config_bw(sdata, sta, elems->ht_cap_elem, 4281 4259 elems->vht_cap_elem, elems->ht_operation, 4282 4260 elems->vht_operation, elems->he_operation, 4261 + elems->eht_operation, 4283 4262 elems->s1g_oper, bssid, &changed)) { 4284 4263 mutex_unlock(&local->sta_mtx); 4285 4264 sdata_info(sdata, ··· 5208 5185 const struct ieee80211_ht_operation *ht_oper = NULL; 5209 5186 const struct ieee80211_vht_operation *vht_oper = NULL; 5210 5187 const struct ieee80211_he_operation *he_oper = NULL; 5188 + const struct ieee80211_eht_operation *eht_oper = NULL; 5211 5189 const struct ieee80211_s1g_oper_ie *s1g_oper = NULL; 5212 5190 struct ieee80211_supported_band *sband; 5213 5191 struct cfg80211_chan_def chandef; ··· 5239 5215 5240 5216 /* disable HT/VHT/HE if we don't support them */ 5241 5217 if (!sband->ht_cap.ht_supported && !is_6ghz) { 5242 - mlme_dbg(sdata, "HT not supported, disabling HT/VHT/HE\n"); 5218 + mlme_dbg(sdata, "HT not supported, disabling HT/VHT/HE/EHT\n"); 5243 5219 ifmgd->flags |= IEEE80211_STA_DISABLE_HT; 5244 5220 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; 5245 5221 ifmgd->flags |= IEEE80211_STA_DISABLE_HE; 5222 + ifmgd->flags |= IEEE80211_STA_DISABLE_EHT; 5246 5223 } 5247 5224 5248 5225 if (!sband->vht_cap.vht_supported && is_5ghz) { 5249 - mlme_dbg(sdata, "VHT not supported, disabling VHT/HE\n"); 5226 + mlme_dbg(sdata, "VHT not supported, disabling VHT/HE/EHT\n"); 5250 5227 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; 5251 5228 ifmgd->flags |= IEEE80211_STA_DISABLE_HE; 5229 + ifmgd->flags |= IEEE80211_STA_DISABLE_EHT; 5252 5230 } 5253 5231 5254 5232 if (!ieee80211_get_he_iftype_cap(sband, 5255 5233 ieee80211_vif_type_p2p(&sdata->vif))) { 5256 - mlme_dbg(sdata, "HE not supported, disabling it\n"); 5234 + mlme_dbg(sdata, "HE not supported, disabling HE and EHT\n"); 5257 5235 ifmgd->flags |= IEEE80211_STA_DISABLE_HE; 5236 + ifmgd->flags |= IEEE80211_STA_DISABLE_EHT; 5237 + } 5238 + 5239 + if (!ieee80211_get_eht_iftype_cap(sband, 5240 + ieee80211_vif_type_p2p(&sdata->vif))) { 5241 + mlme_dbg(sdata, "EHT not supported, disabling EHT\n"); 5242 + ifmgd->flags |= IEEE80211_STA_DISABLE_EHT; 5258 5243 } 5259 5244 5260 5245 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && !is_6ghz) { ··· 5285 5252 ifmgd->flags |= IEEE80211_STA_DISABLE_HT; 5286 5253 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; 5287 5254 ifmgd->flags |= IEEE80211_STA_DISABLE_HE; 5255 + ifmgd->flags |= IEEE80211_STA_DISABLE_EHT; 5288 5256 } 5289 5257 5290 5258 if (!elems->vht_cap_elem) { ··· 5325 5291 5326 5292 if (!ieee80211_verify_peer_he_mcs_support(sdata, ies, he_oper) || 5327 5293 !ieee80211_verify_sta_he_mcs_support(sdata, sband, he_oper)) 5328 - ifmgd->flags |= IEEE80211_STA_DISABLE_HE; 5294 + ifmgd->flags |= IEEE80211_STA_DISABLE_HE | 5295 + IEEE80211_STA_DISABLE_EHT; 5296 + } 5297 + 5298 + /* 5299 + * EHT requires HE to be supported as well. Specifically for 6 GHz 5300 + * channels, the operation channel information can only be deduced from 5301 + * both the 6 GHz operation information (from the HE operation IE) and 5302 + * EHT operation. 5303 + */ 5304 + if (!(ifmgd->flags & (IEEE80211_STA_DISABLE_HE | 5305 + IEEE80211_STA_DISABLE_EHT)) && he_oper) { 5306 + const struct cfg80211_bss_ies *ies; 5307 + const u8 *eht_oper_ie; 5308 + 5309 + ies = rcu_dereference(cbss->ies); 5310 + eht_oper_ie = cfg80211_find_ext_ie(WLAN_EID_EXT_EHT_OPERATION, 5311 + ies->data, ies->len); 5312 + if (eht_oper_ie && eht_oper_ie[1] >= 5313 + 1 + sizeof(struct ieee80211_eht_operation)) 5314 + eht_oper = (void *)(eht_oper_ie + 3); 5315 + else 5316 + eht_oper = NULL; 5329 5317 } 5330 5318 5331 5319 /* Allow VHT if at least one channel on the sband supports 80 MHz */ ··· 5376 5320 ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, 5377 5321 cbss->channel, 5378 5322 bss->vht_cap_info, 5379 - ht_oper, vht_oper, he_oper, 5323 + ht_oper, vht_oper, 5324 + he_oper, eht_oper, 5380 5325 s1g_oper, 5381 5326 &chandef, false); 5382 5327 ··· 5868 5811 ifmgd->flags |= IEEE80211_STA_DISABLE_HT; 5869 5812 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; 5870 5813 ifmgd->flags |= IEEE80211_STA_DISABLE_HE; 5814 + ifmgd->flags |= IEEE80211_STA_DISABLE_EHT; 5871 5815 netdev_info(sdata->dev, 5872 5816 "disabling HT/VHT/HE due to WEP/TKIP use\n"); 5873 5817 } ··· 5876 5818 5877 5819 sband = local->hw.wiphy->bands[req->bss->channel->band]; 5878 5820 5879 - /* also disable HT/VHT/HE if the AP doesn't use WMM */ 5821 + /* also disable HT/VHT/HE/EHT if the AP doesn't use WMM */ 5880 5822 if (!bss->wmm_used) { 5881 5823 ifmgd->flags |= IEEE80211_STA_DISABLE_HT; 5882 5824 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; 5883 5825 ifmgd->flags |= IEEE80211_STA_DISABLE_HE; 5826 + ifmgd->flags |= IEEE80211_STA_DISABLE_EHT; 5884 5827 netdev_info(sdata->dev, 5885 5828 "disabling HT/VHT/HE as WMM/QoS is not supported by the AP\n"); 5886 5829 } ··· 5935 5876 memcpy(&assoc_data->ap_vht_cap, vht_elem->data, 5936 5877 sizeof(struct ieee80211_vht_cap)); 5937 5878 } else if (is_5ghz) { 5938 - sdata_info(sdata, "VHT capa missing/short, disabling VHT/HE\n"); 5879 + sdata_info(sdata, 5880 + "VHT capa missing/short, disabling VHT/HE/EHT\n"); 5939 5881 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT | 5940 - IEEE80211_STA_DISABLE_HE; 5882 + IEEE80211_STA_DISABLE_HE | 5883 + IEEE80211_STA_DISABLE_EHT; 5941 5884 } 5942 5885 rcu_read_unlock(); 5943 5886 ··· 6018 5957 ifmgd->flags |= IEEE80211_STA_DISABLE_HT; 6019 5958 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; 6020 5959 ifmgd->flags |= IEEE80211_STA_DISABLE_HE; 5960 + ifmgd->flags |= IEEE80211_STA_DISABLE_EHT; 6021 5961 } 6022 5962 6023 5963 if (req->flags & ASSOC_REQ_DISABLE_VHT) { ··· 6027 5965 } 6028 5966 6029 5967 if (req->flags & ASSOC_REQ_DISABLE_HE) { 6030 - mlme_dbg(sdata, "HE disabled by flag, disabling VHT\n"); 5968 + mlme_dbg(sdata, "HE disabled by flag, disabling HE/EHT\n"); 6031 5969 ifmgd->flags |= IEEE80211_STA_DISABLE_HE; 5970 + ifmgd->flags |= IEEE80211_STA_DISABLE_EHT; 6032 5971 } 6033 5972 6034 5973 err = ieee80211_prep_connection(sdata, req->bss, true, override);
+112 -34
net/mac80211/util.c
··· 3086 3086 else 3087 3087 ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW; 3088 3088 break; 3089 + case NL80211_CHAN_WIDTH_320: 3090 + /* HT information element should not be included on 6GHz */ 3091 + WARN_ON(1); 3092 + return pos; 3089 3093 default: 3090 3094 ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; 3091 3095 break; ··· 3129 3125 case NL80211_CHAN_WIDTH_80P80: 3130 3126 *pos++ = IEEE80211_VHT_CHANWIDTH_80P80MHZ; 3131 3127 break; 3128 + case NL80211_CHAN_WIDTH_320: 3129 + /* The behavior is not defined for 320 MHz channels */ 3130 + WARN_ON(1); 3131 + fallthrough; 3132 3132 default: 3133 3133 *pos++ = IEEE80211_VHT_CHANWIDTH_USE_HT; 3134 3134 } ··· 3185 3177 case NL80211_CHAN_WIDTH_80: 3186 3178 vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ; 3187 3179 break; 3180 + case NL80211_CHAN_WIDTH_320: 3181 + /* VHT information element should not be included on 6GHz */ 3182 + WARN_ON(1); 3183 + return pos; 3188 3184 default: 3189 3185 vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT; 3190 3186 break; ··· 3249 3237 he_6ghz_op->ccfs1 = 0; 3250 3238 3251 3239 switch (chandef->width) { 3240 + case NL80211_CHAN_WIDTH_320: 3241 + /* 3242 + * TODO: mesh operation is not defined over 6GHz 320 MHz 3243 + * channels. 3244 + */ 3245 + WARN_ON(1); 3246 + break; 3252 3247 case NL80211_CHAN_WIDTH_160: 3253 3248 /* Convert 160 MHz channel width to new style as interop 3254 3249 * workaround. ··· 3444 3425 3445 3426 bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata, 3446 3427 const struct ieee80211_he_operation *he_oper, 3428 + const struct ieee80211_eht_operation *eht_oper, 3447 3429 struct cfg80211_chan_def *chandef) 3448 3430 { 3449 3431 struct ieee80211_local *local = sdata->local; 3450 3432 struct ieee80211_supported_band *sband; 3451 3433 enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif); 3452 3434 const struct ieee80211_sta_he_cap *he_cap; 3435 + const struct ieee80211_sta_eht_cap *eht_cap; 3453 3436 struct cfg80211_chan_def he_chandef = *chandef; 3454 3437 const struct ieee80211_he_6ghz_oper *he_6ghz_oper; 3455 3438 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; 3456 - bool support_80_80, support_160; 3457 - u8 he_phy_cap; 3439 + bool support_80_80, support_160, support_320; 3440 + u8 he_phy_cap, eht_phy_cap; 3458 3441 u32 freq; 3459 3442 3460 3443 if (chandef->chan->band != NL80211_BAND_6GHZ) ··· 3485 3464 return false; 3486 3465 } 3487 3466 3467 + eht_cap = ieee80211_get_eht_iftype_cap(sband, iftype); 3468 + if (!eht_cap) { 3469 + sdata_info(sdata, "Missing iftype sband data/EHT cap"); 3470 + eht_oper = NULL; 3471 + } 3472 + 3488 3473 he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper); 3489 3474 3490 3475 if (!he_6ghz_oper) { ··· 3500 3473 return false; 3501 3474 } 3502 3475 3476 + /* 3477 + * The EHT operation IE does not contain the primary channel so the 3478 + * primary channel frequency should be taken from the 6 GHz operation 3479 + * information. 3480 + */ 3503 3481 freq = ieee80211_channel_to_frequency(he_6ghz_oper->primary, 3504 3482 NL80211_BAND_6GHZ); 3505 3483 he_chandef.chan = ieee80211_get_channel(sdata->local->hw.wiphy, freq); ··· 3522 3490 break; 3523 3491 } 3524 3492 3525 - switch (u8_get_bits(he_6ghz_oper->control, 3526 - IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH)) { 3527 - case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ: 3528 - he_chandef.width = NL80211_CHAN_WIDTH_20; 3529 - break; 3530 - case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_40MHZ: 3531 - he_chandef.width = NL80211_CHAN_WIDTH_40; 3532 - break; 3533 - case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ: 3534 - he_chandef.width = NL80211_CHAN_WIDTH_80; 3535 - break; 3536 - case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ: 3537 - he_chandef.width = NL80211_CHAN_WIDTH_80; 3538 - if (!he_6ghz_oper->ccfs1) 3493 + if (!eht_oper) { 3494 + switch (u8_get_bits(he_6ghz_oper->control, 3495 + IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH)) { 3496 + case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ: 3497 + he_chandef.width = NL80211_CHAN_WIDTH_20; 3539 3498 break; 3540 - if (abs(he_6ghz_oper->ccfs1 - he_6ghz_oper->ccfs0) == 8) { 3541 - if (support_160) 3542 - he_chandef.width = NL80211_CHAN_WIDTH_160; 3543 - } else { 3544 - if (support_80_80) 3545 - he_chandef.width = NL80211_CHAN_WIDTH_80P80; 3499 + case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_40MHZ: 3500 + he_chandef.width = NL80211_CHAN_WIDTH_40; 3501 + break; 3502 + case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ: 3503 + he_chandef.width = NL80211_CHAN_WIDTH_80; 3504 + break; 3505 + case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ: 3506 + he_chandef.width = NL80211_CHAN_WIDTH_80; 3507 + if (!he_6ghz_oper->ccfs1) 3508 + break; 3509 + if (abs(he_6ghz_oper->ccfs1 - he_6ghz_oper->ccfs0) == 8) { 3510 + if (support_160) 3511 + he_chandef.width = NL80211_CHAN_WIDTH_160; 3512 + } else { 3513 + if (support_80_80) 3514 + he_chandef.width = NL80211_CHAN_WIDTH_80P80; 3515 + } 3516 + break; 3546 3517 } 3547 - break; 3548 - } 3549 3518 3550 - if (he_chandef.width == NL80211_CHAN_WIDTH_160) { 3551 - he_chandef.center_freq1 = 3552 - ieee80211_channel_to_frequency(he_6ghz_oper->ccfs1, 3553 - NL80211_BAND_6GHZ); 3554 - } else { 3555 - he_chandef.center_freq1 = 3556 - ieee80211_channel_to_frequency(he_6ghz_oper->ccfs0, 3557 - NL80211_BAND_6GHZ); 3558 - if (support_80_80 || support_160) 3559 - he_chandef.center_freq2 = 3519 + if (he_chandef.width == NL80211_CHAN_WIDTH_160) { 3520 + he_chandef.center_freq1 = 3560 3521 ieee80211_channel_to_frequency(he_6ghz_oper->ccfs1, 3561 3522 NL80211_BAND_6GHZ); 3523 + } else { 3524 + he_chandef.center_freq1 = 3525 + ieee80211_channel_to_frequency(he_6ghz_oper->ccfs0, 3526 + NL80211_BAND_6GHZ); 3527 + if (support_80_80 || support_160) 3528 + he_chandef.center_freq2 = 3529 + ieee80211_channel_to_frequency(he_6ghz_oper->ccfs1, 3530 + NL80211_BAND_6GHZ); 3531 + } 3532 + } else { 3533 + eht_phy_cap = eht_cap->eht_cap_elem.phy_cap_info[0]; 3534 + support_320 = 3535 + eht_phy_cap & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; 3536 + 3537 + switch (u8_get_bits(eht_oper->chan_width, 3538 + IEEE80211_EHT_OPER_CHAN_WIDTH)) { 3539 + case IEEE80211_EHT_OPER_CHAN_WIDTH_20MHZ: 3540 + he_chandef.width = NL80211_CHAN_WIDTH_20; 3541 + break; 3542 + case IEEE80211_EHT_OPER_CHAN_WIDTH_40MHZ: 3543 + he_chandef.width = NL80211_CHAN_WIDTH_40; 3544 + break; 3545 + case IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ: 3546 + he_chandef.width = NL80211_CHAN_WIDTH_80; 3547 + break; 3548 + case IEEE80211_EHT_OPER_CHAN_WIDTH_160MHZ: 3549 + if (support_160) 3550 + he_chandef.width = NL80211_CHAN_WIDTH_160; 3551 + else 3552 + he_chandef.width = NL80211_CHAN_WIDTH_80; 3553 + break; 3554 + case IEEE80211_EHT_OPER_CHAN_WIDTH_320MHZ: 3555 + if (support_320) 3556 + he_chandef.width = NL80211_CHAN_WIDTH_320; 3557 + else if (support_160) 3558 + he_chandef.width = NL80211_CHAN_WIDTH_160; 3559 + else 3560 + he_chandef.width = NL80211_CHAN_WIDTH_80; 3561 + break; 3562 + } 3563 + 3564 + he_chandef.center_freq1 = 3565 + ieee80211_channel_to_frequency(eht_oper->ccfs, 3566 + NL80211_BAND_6GHZ); 3562 3567 } 3563 3568 3564 3569 if (!cfg80211_chandef_valid(&he_chandef)) { ··· 4066 3997 c->width = NL80211_CHAN_WIDTH_80; 4067 3998 ret = IEEE80211_STA_DISABLE_80P80MHZ | 4068 3999 IEEE80211_STA_DISABLE_160MHZ; 4000 + break; 4001 + case NL80211_CHAN_WIDTH_320: 4002 + /* n_P20 */ 4003 + tmp = (150 + c->chan->center_freq - c->center_freq1) / 20; 4004 + /* n_P160 */ 4005 + tmp /= 80; 4006 + c->center_freq1 = c->center_freq1 - 80 + 160 * tmp; 4007 + c->width = NL80211_CHAN_WIDTH_160; 4008 + ret = IEEE80211_STA_DISABLE_320MHZ; 4069 4009 break; 4070 4010 default: 4071 4011 case NL80211_CHAN_WIDTH_20_NOHT:
+3 -1
net/mac80211/vht.c
··· 4 4 * 5 5 * Portions of this file 6 6 * Copyright(c) 2015 - 2016 Intel Deutschland GmbH 7 - * Copyright (C) 2018 - 2020 Intel Corporation 7 + * Copyright (C) 2018 - 2021 Intel Corporation 8 8 */ 9 9 10 10 #include <linux/ieee80211.h> ··· 445 445 case NL80211_CHAN_WIDTH_160: 446 446 case NL80211_CHAN_WIDTH_80P80: 447 447 return IEEE80211_STA_RX_BW_160; 448 + case NL80211_CHAN_WIDTH_320: 449 + return IEEE80211_STA_RX_BW_320; 448 450 default: 449 451 WARN_ON_ONCE(1); 450 452 return IEEE80211_STA_RX_BW_20;