mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-05-24 10:39:52 +00:00
wifi: mac80211: mlme: handle EHT channel puncturing
Handle the Puncturing info received from the AP in the EHT Operation element in beacons. If the info is invalid: - during association: disable EHT connection for the AP - after association: disconnect This commit includes many (internal) bugfixes and spec updates various people. Co-developed-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://lore.kernel.org/r/20230127123930.4fbc74582331.I3547481d49f958389f59dfeba3fcc75e72b0aa6e@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
8bb588d975
commit
aa87cd8b35
5 changed files with 228 additions and 7 deletions
|
@ -340,7 +340,7 @@ struct ieee80211_vif_chanctx_switch {
|
||||||
* @BSS_CHANGED_FILS_DISCOVERY: FILS discovery status changed.
|
* @BSS_CHANGED_FILS_DISCOVERY: FILS discovery status changed.
|
||||||
* @BSS_CHANGED_UNSOL_BCAST_PROBE_RESP: Unsolicited broadcast probe response
|
* @BSS_CHANGED_UNSOL_BCAST_PROBE_RESP: Unsolicited broadcast probe response
|
||||||
* status changed.
|
* status changed.
|
||||||
*
|
* @BSS_CHANGED_EHT_PUNCTURING: The channel puncturing bitmap changed.
|
||||||
*/
|
*/
|
||||||
enum ieee80211_bss_change {
|
enum ieee80211_bss_change {
|
||||||
BSS_CHANGED_ASSOC = 1<<0,
|
BSS_CHANGED_ASSOC = 1<<0,
|
||||||
|
@ -375,6 +375,7 @@ enum ieee80211_bss_change {
|
||||||
BSS_CHANGED_HE_BSS_COLOR = 1<<29,
|
BSS_CHANGED_HE_BSS_COLOR = 1<<29,
|
||||||
BSS_CHANGED_FILS_DISCOVERY = 1<<30,
|
BSS_CHANGED_FILS_DISCOVERY = 1<<30,
|
||||||
BSS_CHANGED_UNSOL_BCAST_PROBE_RESP = 1<<31,
|
BSS_CHANGED_UNSOL_BCAST_PROBE_RESP = 1<<31,
|
||||||
|
BSS_CHANGED_EHT_PUNCTURING = BIT_ULL(32),
|
||||||
|
|
||||||
/* when adding here, make sure to change ieee80211_reconfig */
|
/* when adding here, make sure to change ieee80211_reconfig */
|
||||||
};
|
};
|
||||||
|
@ -640,6 +641,7 @@ struct ieee80211_fils_discovery {
|
||||||
* @tx_pwr_env_num: number of @tx_pwr_env.
|
* @tx_pwr_env_num: number of @tx_pwr_env.
|
||||||
* @pwr_reduction: power constraint of BSS.
|
* @pwr_reduction: power constraint of BSS.
|
||||||
* @eht_support: does this BSS support EHT
|
* @eht_support: does this BSS support EHT
|
||||||
|
* @eht_puncturing: bitmap to indicate which channels are punctured in this BSS
|
||||||
* @csa_active: marks whether a channel switch is going on. Internally it is
|
* @csa_active: marks whether a channel switch is going on. Internally it is
|
||||||
* write-protected by sdata_lock and local->mtx so holding either is fine
|
* write-protected by sdata_lock and local->mtx so holding either is fine
|
||||||
* for read access.
|
* for read access.
|
||||||
|
@ -736,6 +738,7 @@ struct ieee80211_bss_conf {
|
||||||
u8 tx_pwr_env_num;
|
u8 tx_pwr_env_num;
|
||||||
u8 pwr_reduction;
|
u8 pwr_reduction;
|
||||||
bool eht_support;
|
bool eht_support;
|
||||||
|
u16 eht_puncturing;
|
||||||
|
|
||||||
bool csa_active;
|
bool csa_active;
|
||||||
bool mu_mimo_owner;
|
bool mu_mimo_owner;
|
||||||
|
|
|
@ -4171,7 +4171,7 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy,
|
||||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||||
struct ieee80211_link_data *link;
|
struct ieee80211_link_data *link;
|
||||||
int ret;
|
int ret;
|
||||||
u32 changed = 0;
|
u64 changed = 0;
|
||||||
|
|
||||||
link = sdata_dereference(sdata->link[link_id], sdata);
|
link = sdata_dereference(sdata->link[link_id], sdata);
|
||||||
|
|
||||||
|
|
|
@ -1916,7 +1916,7 @@ int ieee80211_link_use_reserved_context(struct ieee80211_link_data *link)
|
||||||
|
|
||||||
int ieee80211_link_change_bandwidth(struct ieee80211_link_data *link,
|
int ieee80211_link_change_bandwidth(struct ieee80211_link_data *link,
|
||||||
const struct cfg80211_chan_def *chandef,
|
const struct cfg80211_chan_def *chandef,
|
||||||
u32 *changed)
|
u64 *changed)
|
||||||
{
|
{
|
||||||
struct ieee80211_sub_if_data *sdata = link->sdata;
|
struct ieee80211_sub_if_data *sdata = link->sdata;
|
||||||
struct ieee80211_bss_conf *link_conf = link->conf;
|
struct ieee80211_bss_conf *link_conf = link->conf;
|
||||||
|
|
|
@ -2481,7 +2481,7 @@ int ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link);
|
||||||
int __must_check
|
int __must_check
|
||||||
ieee80211_link_change_bandwidth(struct ieee80211_link_data *link,
|
ieee80211_link_change_bandwidth(struct ieee80211_link_data *link,
|
||||||
const struct cfg80211_chan_def *chandef,
|
const struct cfg80211_chan_def *chandef,
|
||||||
u32 *changed);
|
u64 *changed);
|
||||||
void ieee80211_link_release_channel(struct ieee80211_link_data *link);
|
void ieee80211_link_release_channel(struct ieee80211_link_data *link);
|
||||||
void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link);
|
void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link);
|
||||||
void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
|
void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||||
* Copyright (C) 2015 - 2017 Intel Deutschland GmbH
|
* Copyright (C) 2015 - 2017 Intel Deutschland GmbH
|
||||||
* Copyright (C) 2018 - 2022 Intel Corporation
|
* Copyright (C) 2018 - 2023 Intel Corporation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
@ -88,6 +88,141 @@ MODULE_PARM_DESC(probe_wait_ms,
|
||||||
*/
|
*/
|
||||||
#define IEEE80211_SIGNAL_AVE_MIN_COUNT 4
|
#define IEEE80211_SIGNAL_AVE_MIN_COUNT 4
|
||||||
|
|
||||||
|
struct ieee80211_per_bw_puncturing_values {
|
||||||
|
u8 len;
|
||||||
|
const u16 *valid_values;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u16 puncturing_values_80mhz[] = {
|
||||||
|
0x8, 0x4, 0x2, 0x1
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u16 puncturing_values_160mhz[] = {
|
||||||
|
0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1, 0xc0, 0x30, 0xc, 0x3
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u16 puncturing_values_320mhz[] = {
|
||||||
|
0xc000, 0x3000, 0xc00, 0x300, 0xc0, 0x30, 0xc, 0x3, 0xf000, 0xf00,
|
||||||
|
0xf0, 0xf, 0xfc00, 0xf300, 0xf0c0, 0xf030, 0xf00c, 0xf003, 0xc00f,
|
||||||
|
0x300f, 0xc0f, 0x30f, 0xcf, 0x3f
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IEEE80211_PER_BW_VALID_PUNCTURING_VALUES(_bw) \
|
||||||
|
{ \
|
||||||
|
.len = ARRAY_SIZE(puncturing_values_ ## _bw ## mhz), \
|
||||||
|
.valid_values = puncturing_values_ ## _bw ## mhz \
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct ieee80211_per_bw_puncturing_values per_bw_puncturing[] = {
|
||||||
|
IEEE80211_PER_BW_VALID_PUNCTURING_VALUES(80),
|
||||||
|
IEEE80211_PER_BW_VALID_PUNCTURING_VALUES(160),
|
||||||
|
IEEE80211_PER_BW_VALID_PUNCTURING_VALUES(320)
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool ieee80211_valid_disable_subchannel_bitmap(u16 *bitmap,
|
||||||
|
enum nl80211_chan_width bw)
|
||||||
|
{
|
||||||
|
u32 idx, i;
|
||||||
|
|
||||||
|
switch (bw) {
|
||||||
|
case NL80211_CHAN_WIDTH_80:
|
||||||
|
idx = 0;
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_WIDTH_160:
|
||||||
|
idx = 1;
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_WIDTH_320:
|
||||||
|
idx = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*bitmap = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*bitmap)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (i = 0; i < per_bw_puncturing[idx].len; i++)
|
||||||
|
if (per_bw_puncturing[idx].valid_values[i] == *bitmap)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract from the given disabled subchannel bitmap (raw format
|
||||||
|
* from the EHT Operation Element) the bits for the subchannel
|
||||||
|
* we're using right now.
|
||||||
|
*/
|
||||||
|
static u16
|
||||||
|
ieee80211_extract_dis_subch_bmap(const struct ieee80211_eht_operation *eht_oper,
|
||||||
|
struct cfg80211_chan_def *chandef, u16 bitmap)
|
||||||
|
{
|
||||||
|
struct ieee80211_eht_operation_info *info = (void *)eht_oper->optional;
|
||||||
|
struct cfg80211_chan_def ap_chandef = *chandef;
|
||||||
|
u32 ap_center_freq, local_center_freq;
|
||||||
|
u32 ap_bw, local_bw;
|
||||||
|
int ap_start_freq, local_start_freq;
|
||||||
|
u16 shift, mask;
|
||||||
|
|
||||||
|
if (!(eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT) ||
|
||||||
|
!(eht_oper->params &
|
||||||
|
IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* set 160/320 supported to get the full AP definition */
|
||||||
|
ieee80211_chandef_eht_oper(eht_oper, true, true, &ap_chandef);
|
||||||
|
ap_center_freq = ap_chandef.center_freq1;
|
||||||
|
ap_bw = 20 * BIT(u8_get_bits(info->control,
|
||||||
|
IEEE80211_EHT_OPER_CHAN_WIDTH));
|
||||||
|
ap_start_freq = ap_center_freq - ap_bw / 2;
|
||||||
|
local_center_freq = chandef->center_freq1;
|
||||||
|
local_bw = 20 * BIT(ieee80211_chan_width_to_rx_bw(chandef->width));
|
||||||
|
local_start_freq = local_center_freq - local_bw / 2;
|
||||||
|
shift = (local_start_freq - ap_start_freq) / 20;
|
||||||
|
mask = BIT(local_bw / 20) - 1;
|
||||||
|
|
||||||
|
return (bitmap >> shift) & mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle the puncturing bitmap, possibly downgrading bandwidth to get a
|
||||||
|
* valid bitmap.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ieee80211_handle_puncturing_bitmap(struct ieee80211_link_data *link,
|
||||||
|
const struct ieee80211_eht_operation *eht_oper,
|
||||||
|
u16 bitmap, u64 *changed)
|
||||||
|
{
|
||||||
|
struct cfg80211_chan_def *chandef = &link->conf->chandef;
|
||||||
|
u16 extracted;
|
||||||
|
u64 _changed = 0;
|
||||||
|
|
||||||
|
if (!changed)
|
||||||
|
changed = &_changed;
|
||||||
|
|
||||||
|
while (chandef->width > NL80211_CHAN_WIDTH_40) {
|
||||||
|
extracted =
|
||||||
|
ieee80211_extract_dis_subch_bmap(eht_oper, chandef,
|
||||||
|
bitmap);
|
||||||
|
|
||||||
|
if (ieee80211_valid_disable_subchannel_bitmap(&bitmap,
|
||||||
|
chandef->width))
|
||||||
|
break;
|
||||||
|
link->u.mgd.conn_flags |=
|
||||||
|
ieee80211_chandef_downgrade(chandef);
|
||||||
|
*changed |= BSS_CHANGED_BANDWIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chandef->width <= NL80211_CHAN_WIDTH_40)
|
||||||
|
extracted = 0;
|
||||||
|
|
||||||
|
if (link->conf->eht_puncturing != extracted) {
|
||||||
|
link->conf->eht_puncturing = extracted;
|
||||||
|
*changed |= BSS_CHANGED_EHT_PUNCTURING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can have multiple work items (and connection probing)
|
* We can have multiple work items (and connection probing)
|
||||||
* scheduling this timer, but we need to take care to only
|
* scheduling this timer, but we need to take care to only
|
||||||
|
@ -413,7 +548,7 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link,
|
||||||
const struct ieee80211_he_operation *he_oper,
|
const struct ieee80211_he_operation *he_oper,
|
||||||
const struct ieee80211_eht_operation *eht_oper,
|
const struct ieee80211_eht_operation *eht_oper,
|
||||||
const struct ieee80211_s1g_oper_ie *s1g_oper,
|
const struct ieee80211_s1g_oper_ie *s1g_oper,
|
||||||
const u8 *bssid, u32 *changed)
|
const u8 *bssid, u64 *changed)
|
||||||
{
|
{
|
||||||
struct ieee80211_sub_if_data *sdata = link->sdata;
|
struct ieee80211_sub_if_data *sdata = link->sdata;
|
||||||
struct ieee80211_local *local = sdata->local;
|
struct ieee80211_local *local = sdata->local;
|
||||||
|
@ -4145,6 +4280,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
|
||||||
link_sta);
|
link_sta);
|
||||||
|
|
||||||
bss_conf->eht_support = link_sta->pub->eht_cap.has_eht;
|
bss_conf->eht_support = link_sta->pub->eht_cap.has_eht;
|
||||||
|
*changed |= BSS_CHANGED_EHT_PUNCTURING;
|
||||||
} else {
|
} else {
|
||||||
bss_conf->eht_support = false;
|
bss_conf->eht_support = false;
|
||||||
}
|
}
|
||||||
|
@ -5477,6 +5613,45 @@ static bool ieee80211_rx_our_beacon(const u8 *tx_bssid,
|
||||||
return ether_addr_equal(tx_bssid, bss->transmitted_bss->bssid);
|
return ether_addr_equal(tx_bssid, bss->transmitted_bss->bssid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ieee80211_config_puncturing(struct ieee80211_link_data *link,
|
||||||
|
const struct ieee80211_eht_operation *eht_oper,
|
||||||
|
u64 *changed)
|
||||||
|
{
|
||||||
|
u16 bitmap = 0, extracted;
|
||||||
|
|
||||||
|
if ((eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT) &&
|
||||||
|
(eht_oper->params &
|
||||||
|
IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)) {
|
||||||
|
const struct ieee80211_eht_operation_info *info =
|
||||||
|
(void *)eht_oper->optional;
|
||||||
|
const u8 *disable_subchannel_bitmap = info->optional;
|
||||||
|
|
||||||
|
bitmap = get_unaligned_le16(disable_subchannel_bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
extracted = ieee80211_extract_dis_subch_bmap(eht_oper,
|
||||||
|
&link->conf->chandef,
|
||||||
|
bitmap);
|
||||||
|
|
||||||
|
/* accept if there are no changes */
|
||||||
|
if (!(*changed & BSS_CHANGED_BANDWIDTH) &&
|
||||||
|
extracted == link->conf->eht_puncturing)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!ieee80211_valid_disable_subchannel_bitmap(&bitmap,
|
||||||
|
link->conf->chandef.width)) {
|
||||||
|
link_info(link,
|
||||||
|
"Got an invalid disable subchannel bitmap from AP %pM: bitmap = 0x%x, bw = 0x%x. disconnect\n",
|
||||||
|
link->u.mgd.bssid,
|
||||||
|
bitmap,
|
||||||
|
link->conf->chandef.width);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ieee80211_handle_puncturing_bitmap(link, eht_oper, bitmap, changed);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
|
static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
|
||||||
struct ieee80211_hdr *hdr, size_t len,
|
struct ieee80211_hdr *hdr, size_t len,
|
||||||
struct ieee80211_rx_status *rx_status)
|
struct ieee80211_rx_status *rx_status)
|
||||||
|
@ -5494,7 +5669,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
|
||||||
struct ieee80211_channel *chan;
|
struct ieee80211_channel *chan;
|
||||||
struct link_sta_info *link_sta;
|
struct link_sta_info *link_sta;
|
||||||
struct sta_info *sta;
|
struct sta_info *sta;
|
||||||
u32 changed = 0;
|
u64 changed = 0;
|
||||||
bool erp_valid;
|
bool erp_valid;
|
||||||
u8 erp_value = 0;
|
u8 erp_value = 0;
|
||||||
u32 ncrc = 0;
|
u32 ncrc = 0;
|
||||||
|
@ -5791,6 +5966,21 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
|
||||||
elems->pwr_constr_elem,
|
elems->pwr_constr_elem,
|
||||||
elems->cisco_dtpc_elem);
|
elems->cisco_dtpc_elem);
|
||||||
|
|
||||||
|
if (elems->eht_operation &&
|
||||||
|
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT)) {
|
||||||
|
if (!ieee80211_config_puncturing(link, elems->eht_operation,
|
||||||
|
&changed)) {
|
||||||
|
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
|
||||||
|
WLAN_REASON_DEAUTH_LEAVING,
|
||||||
|
true, deauth_buf);
|
||||||
|
ieee80211_report_disconnect(sdata, deauth_buf,
|
||||||
|
sizeof(deauth_buf), true,
|
||||||
|
WLAN_REASON_DEAUTH_LEAVING,
|
||||||
|
false);
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ieee80211_link_info_change_notify(sdata, link, changed);
|
ieee80211_link_info_change_notify(sdata, link, changed);
|
||||||
free:
|
free:
|
||||||
kfree(elems);
|
kfree(elems);
|
||||||
|
@ -6892,9 +7082,12 @@ ieee80211_setup_assoc_link(struct ieee80211_sub_if_data *sdata,
|
||||||
ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
|
ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
link->conf->eht_puncturing = 0;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
beacon_ies = rcu_dereference(cbss->beacon_ies);
|
beacon_ies = rcu_dereference(cbss->beacon_ies);
|
||||||
if (beacon_ies) {
|
if (beacon_ies) {
|
||||||
|
const struct ieee80211_eht_operation *eht_oper;
|
||||||
const struct element *elem;
|
const struct element *elem;
|
||||||
u8 dtim_count = 0;
|
u8 dtim_count = 0;
|
||||||
|
|
||||||
|
@ -6923,6 +7116,31 @@ ieee80211_setup_assoc_link(struct ieee80211_sub_if_data *sdata,
|
||||||
link->conf->ema_ap = true;
|
link->conf->ema_ap = true;
|
||||||
else
|
else
|
||||||
link->conf->ema_ap = false;
|
link->conf->ema_ap = false;
|
||||||
|
|
||||||
|
elem = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_OPERATION,
|
||||||
|
beacon_ies->data, beacon_ies->len);
|
||||||
|
eht_oper = (const void *)(elem->data + 1);
|
||||||
|
|
||||||
|
if (elem &&
|
||||||
|
ieee80211_eht_oper_size_ok((const void *)(elem->data + 1),
|
||||||
|
elem->datalen - 1) &&
|
||||||
|
(eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT) &&
|
||||||
|
(eht_oper->params & IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)) {
|
||||||
|
const struct ieee80211_eht_operation_info *info =
|
||||||
|
(void *)eht_oper->optional;
|
||||||
|
const u8 *disable_subchannel_bitmap = info->optional;
|
||||||
|
u16 bitmap;
|
||||||
|
|
||||||
|
bitmap = get_unaligned_le16(disable_subchannel_bitmap);
|
||||||
|
if (ieee80211_valid_disable_subchannel_bitmap(&bitmap,
|
||||||
|
link->conf->chandef.width))
|
||||||
|
ieee80211_handle_puncturing_bitmap(link,
|
||||||
|
eht_oper,
|
||||||
|
bitmap,
|
||||||
|
NULL);
|
||||||
|
else
|
||||||
|
conn_flags |= IEEE80211_CONN_DISABLE_EHT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue