diff options
author | Jakub Kicinski <kuba@kernel.org> | 2024-06-27 13:53:43 -0700 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2024-06-27 13:53:43 -0700 |
commit | 56bf02c26a362a270c7f12f1e36aeced95bc2287 (patch) | |
tree | 1f651324663249a83a033a880884489e698bbe68 /net/wireless | |
parent | 193b9b200224dab4eaec407eb2955303a521f5b6 (diff) | |
parent | f3f942d6e5889ea9d46cecf8fc0b7893b5ba9792 (diff) |
Merge tag 'wireless-next-2024-06-27' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next
Johannes Berg says:
====================
Highlights this time are:
- cfg80211/nl80211:
* improvements for 6 GHz regulatory flexibility
- mac80211:
* use generic netdev stats
* multi-link improvements/fixes
- brcmfmac:
* MFP support (to enable WPA3)
- wilc1000:
* suspend/resume improvements
- iwlwifi:
* remove support for older FW for new devices
* fast resume (keeping the device configured)
- wl18xx:
* support newer firmware versions
* tag 'wireless-next-2024-06-27' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (100 commits)
wifi: brcmfmac: of: Support interrupts-extended
wifi: brcmsmac: advertise MFP_CAPABLE to enable WPA3
net: rfkill: Correct return value in invalid parameter case
wifi: mac80211: fix NULL dereference at band check in starting tx ba session
wifi: iwlwifi: mvm: fix rs.h kernel-doc
wifi: iwlwifi: fw: api: datapath: fix kernel-doc
wifi: iwlwifi: fix remaining mistagged kernel-doc comments
wifi: iwlwifi: fix prototype mismatch kernel-doc warnings
wifi: iwlwifi: fix kernel-doc in iwl-fh.h
wifi: iwlwifi: fix kernel-doc in iwl-trans.h
wifi: iwlwifi: pcie: fix kernel-doc
wifi: iwlwifi: dvm: fix kernel-doc warnings
wifi: iwlwifi: mvm: don't log error for failed UATS table read
wifi: iwlwifi: trans: make bad state warnings
wifi: iwlwifi: fw: api: fix some kernel-doc
wifi: iwlwifi: mvm: remove init_dbg module parameter
wifi: iwlwifi: update the BA notification API
wifi: iwlwifi: mvm: always unblock EMLSR on ROC end
wifi: iwlwifi: mvm: use IWL_FW_CHECK for link ID check
wifi: iwlwifi: mvm: don't flush BSSes on restart with MLD API
...
====================
Link: https://patch.msgid.link/20240627114135.28507-3-johannes@sipsolutions.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/chan.c | 120 | ||||
-rw-r--r-- | net/wireless/core.h | 7 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 35 | ||||
-rw-r--r-- | net/wireless/pmsr.c | 10 | ||||
-rw-r--r-- | net/wireless/rdev-ops.h | 56 | ||||
-rw-r--r-- | net/wireless/reg.c | 2 | ||||
-rw-r--r-- | net/wireless/scan.c | 115 | ||||
-rw-r--r-- | net/wireless/sme.c | 4 | ||||
-rw-r--r-- | net/wireless/tests/chan.c | 22 | ||||
-rw-r--r-- | net/wireless/trace.h | 15 | ||||
-rw-r--r-- | net/wireless/util.c | 8 |
11 files changed, 256 insertions, 138 deletions
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 3414b2c3abcc..e579d7e1425f 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -263,6 +263,37 @@ static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c) return nl80211_chan_width_to_mhz(c->width); } +static bool cfg80211_valid_center_freq(u32 center, + enum nl80211_chan_width width) +{ + int bw; + int step; + + /* We only do strict verification on 6 GHz */ + if (center < 5955 || center > 7115) + return true; + + bw = nl80211_chan_width_to_mhz(width); + if (bw < 0) + return false; + + /* Validate that the channels bw is entirely within the 6 GHz band */ + if (center - bw / 2 < 5945 || center + bw / 2 > 7125) + return false; + + /* With 320 MHz the permitted channels overlap */ + if (bw == 320) + step = 160; + else + step = bw; + + /* + * Valid channels are packed from lowest frequency towards higher ones. + * So test that the lower frequency alignes with one of these steps. + */ + return (center - bw / 2 - 5945) % step == 0; +} + bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) { u32 control_freq, oper_freq; @@ -374,6 +405,13 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) return false; } + if (!cfg80211_valid_center_freq(chandef->center_freq1, chandef->width)) + return false; + + if (chandef->width == NL80211_CHAN_WIDTH_80P80 && + !cfg80211_valid_center_freq(chandef->center_freq2, chandef->width)) + return false; + /* channel 14 is only for IEEE 802.11b */ if (chandef->center_freq1 == 2484 && chandef->width != NL80211_CHAN_WIDTH_20_NOHT) @@ -1145,7 +1183,8 @@ EXPORT_SYMBOL(cfg80211_chandef_dfs_cac_time); static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, u32 center_freq, u32 bandwidth, - u32 prohibited_flags, bool monitor) + u32 prohibited_flags, + u32 permitting_flags) { struct ieee80211_channel *c; u32 freq, start_freq, end_freq; @@ -1157,7 +1196,7 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, c = ieee80211_get_channel_khz(wiphy, freq); if (!c) return false; - if (monitor && c->flags & IEEE80211_CHAN_CAN_MONITOR) + if (c->flags & permitting_flags) continue; if (c->flags & prohibited_flags) return false; @@ -1221,7 +1260,8 @@ static bool cfg80211_edmg_usable(struct wiphy *wiphy, u8 edmg_channels, bool _cfg80211_chandef_usable(struct wiphy *wiphy, const struct cfg80211_chan_def *chandef, - u32 prohibited_flags, bool monitor) + u32 prohibited_flags, + u32 permitting_flags) { struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta_vht_cap *vht_cap; @@ -1383,22 +1423,23 @@ bool _cfg80211_chandef_usable(struct wiphy *wiphy, if (!cfg80211_secondary_chans_ok(wiphy, ieee80211_chandef_to_khz(chandef), - width, prohibited_flags, monitor)) + width, prohibited_flags, + permitting_flags)) return false; if (!chandef->center_freq2) return true; return cfg80211_secondary_chans_ok(wiphy, MHZ_TO_KHZ(chandef->center_freq2), - width, prohibited_flags, monitor); + width, prohibited_flags, + permitting_flags); } bool cfg80211_chandef_usable(struct wiphy *wiphy, const struct cfg80211_chan_def *chandef, u32 prohibited_flags) { - return _cfg80211_chandef_usable(wiphy, chandef, prohibited_flags, - false); + return _cfg80211_chandef_usable(wiphy, chandef, prohibited_flags, 0); } EXPORT_SYMBOL(cfg80211_chandef_usable); @@ -1520,49 +1561,50 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy, static bool _cfg80211_reg_can_beacon(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, enum nl80211_iftype iftype, - bool check_no_ir) + u32 prohibited_flags, + u32 permitting_flags) { - bool res; - u32 prohibited_flags = IEEE80211_CHAN_DISABLED; + bool res, check_radar; int dfs_required; - trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir); + trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, + prohibited_flags, + permitting_flags); - if (check_no_ir) - prohibited_flags |= IEEE80211_CHAN_NO_IR; + if (!_cfg80211_chandef_usable(wiphy, chandef, + IEEE80211_CHAN_DISABLED, 0)) + return false; dfs_required = cfg80211_chandef_dfs_required(wiphy, chandef, iftype); - if (dfs_required != 0) - prohibited_flags |= IEEE80211_CHAN_RADAR; + check_radar = dfs_required != 0; if (dfs_required > 0 && cfg80211_chandef_dfs_available(wiphy, chandef)) { /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */ - prohibited_flags = IEEE80211_CHAN_DISABLED; + prohibited_flags &= ~IEEE80211_CHAN_NO_IR; + check_radar = false; } - res = cfg80211_chandef_usable(wiphy, chandef, prohibited_flags); + if (check_radar && + !_cfg80211_chandef_usable(wiphy, chandef, + IEEE80211_CHAN_RADAR, 0)) + return false; + + res = _cfg80211_chandef_usable(wiphy, chandef, + prohibited_flags, + permitting_flags); trace_cfg80211_return_bool(res); return res; } -bool cfg80211_reg_can_beacon(struct wiphy *wiphy, - struct cfg80211_chan_def *chandef, - enum nl80211_iftype iftype) -{ - return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, true); -} -EXPORT_SYMBOL(cfg80211_reg_can_beacon); - -bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy, - struct cfg80211_chan_def *chandef, - enum nl80211_iftype iftype) +bool cfg80211_reg_check_beaconing(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef, + struct cfg80211_beaconing_check_config *cfg) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - bool check_no_ir; - - lockdep_assert_held(&rdev->wiphy.mtx); + u32 permitting_flags = 0; + bool check_no_ir = true; /* * Under certain conditions suggested by some regulatory bodies a @@ -1570,12 +1612,20 @@ bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy, * only if such relaxations are not enabled and the conditions are not * met. */ - check_no_ir = !cfg80211_ir_permissive_chan(wiphy, iftype, - chandef->chan); + if (cfg->relax) { + lockdep_assert_held(&rdev->wiphy.mtx); + check_no_ir = !cfg80211_ir_permissive_chan(wiphy, cfg->iftype, + chandef->chan); + } + + if (cfg->reg_power == IEEE80211_REG_VLP_AP) + permitting_flags |= IEEE80211_CHAN_ALLOW_6GHZ_VLP_AP; - return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir); + return _cfg80211_reg_can_beacon(wiphy, chandef, cfg->iftype, + check_no_ir ? IEEE80211_CHAN_NO_IR : 0, + permitting_flags); } -EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax); +EXPORT_SYMBOL(cfg80211_reg_check_beaconing); int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, struct cfg80211_chan_def *chandef) diff --git a/net/wireless/core.h b/net/wireless/core.h index 118f2f619828..41c8c0e3ba2e 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -494,7 +494,8 @@ bool cfg80211_wdev_on_sub_chan(struct wireless_dev *wdev, bool primary_only); bool _cfg80211_chandef_usable(struct wiphy *wiphy, const struct cfg80211_chan_def *chandef, - u32 prohibited_flags, bool monitor); + u32 prohibited_flags, + u32 permitting_flags); static inline unsigned int elapsed_jiffies_msecs(unsigned long start) { @@ -532,6 +533,10 @@ struct cfg80211_internal_bss * cfg80211_bss_update(struct cfg80211_registered_device *rdev, struct cfg80211_internal_bss *tmp, bool signal_valid, unsigned long ts); + +enum ieee80211_ap_reg_power +cfg80211_get_6ghz_power_type(const u8 *elems, size_t elems_len); + #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) #else diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b457c2fcee30..19d81200a2a2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -315,8 +315,7 @@ nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = { [NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD] = { .type = NLA_U16 }, [NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION] = NLA_POLICY_MAX(NLA_U8, 15), - [NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST] = - NLA_POLICY_MAX(NLA_U8, 31), + [NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST] = { .type = NLA_U8 }, [NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES] = { .type = NLA_U8 }, [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI] = { .type = NLA_FLAG }, [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC] = { .type = NLA_FLAG }, @@ -1208,6 +1207,12 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy, if ((chan->flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT) && nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT)) goto nla_put_failure; + if ((chan->flags & IEEE80211_CHAN_CAN_MONITOR) && + nla_put_flag(msg, NL80211_FREQUENCY_ATTR_CAN_MONITOR)) + goto nla_put_failure; + if ((chan->flags & IEEE80211_CHAN_ALLOW_6GHZ_VLP_AP) && + nla_put_flag(msg, NL80211_FREQUENCY_ATTR_ALLOW_6GHZ_VLP_AP)) + goto nla_put_failure; } if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, @@ -3348,7 +3353,7 @@ static int _nl80211_parse_chandef(struct cfg80211_registered_device *rdev, if (!_cfg80211_chandef_usable(&rdev->wiphy, chandef, IEEE80211_CHAN_DISABLED, - monitor)) { + monitor ? IEEE80211_CHAN_CAN_MONITOR : 0)) { NL_SET_ERR_MSG(extack, "(extension) channel is disabled"); return -EINVAL; } @@ -5955,6 +5960,7 @@ static int nl80211_validate_ap_phy_operation(struct cfg80211_ap_settings *params static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct cfg80211_beaconing_check_config beacon_check = {}; unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -6104,8 +6110,13 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) goto out; } - if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms->chandef, - wdev->iftype)) { + beacon_check.iftype = wdev->iftype; + beacon_check.relax = true; + beacon_check.reg_power = + cfg80211_get_6ghz_power_type(params->beacon.tail, + params->beacon.tail_len); + if (!cfg80211_reg_check_beaconing(&rdev->wiphy, ¶ms->chandef, + &beacon_check)) { err = -EINVAL; goto out; } @@ -6262,6 +6273,7 @@ out: static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct cfg80211_beaconing_check_config beacon_check = {}; unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -6288,6 +6300,19 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) if (err) goto out; + /* recheck beaconing is permitted with possibly changed power type */ + beacon_check.iftype = wdev->iftype; + beacon_check.relax = true; + beacon_check.reg_power = + cfg80211_get_6ghz_power_type(params->beacon.tail, + params->beacon.tail_len); + if (!cfg80211_reg_check_beaconing(&rdev->wiphy, + &wdev->links[link_id].ap.chandef, + &beacon_check)) { + err = -EINVAL; + goto out; + } + attr = info->attrs[NL80211_ATTR_FILS_DISCOVERY]; if (attr) { err = nl80211_parse_fils_discovery(rdev, attr, diff --git a/net/wireless/pmsr.c b/net/wireless/pmsr.c index c569c37da317..0396fa19bdf1 100644 --- a/net/wireless/pmsr.c +++ b/net/wireless/pmsr.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (C) 2018 - 2021, 2023 Intel Corporation + * Copyright (C) 2018 - 2021, 2023 - 2024 Intel Corporation */ #include <net/cfg80211.h> #include "core.h" @@ -148,6 +148,14 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev, return -EINVAL; } + if (out->ftm.ftms_per_burst > 31 && !out->ftm.non_trigger_based && + !out->ftm.trigger_based) { + NL_SET_ERR_MSG_ATTR(info->extack, + tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST], + "FTM: FTMs per burst must be set lower than 31"); + return -ERANGE; + } + if ((out->ftm.trigger_based || out->ftm.non_trigger_based) && out->ftm.preamble != NL80211_PREAMBLE_HE) { NL_SET_ERR_MSG_ATTR(info->extack, diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 755af47b88b9..8f15658002ee 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -578,13 +578,11 @@ static inline int rdev_leave_ibss(struct cfg80211_registered_device *rdev, static inline int rdev_set_wiphy_params(struct cfg80211_registered_device *rdev, u32 changed) { - int ret; - - if (!rdev->ops->set_wiphy_params) - return -EOPNOTSUPP; + int ret = -EOPNOTSUPP; trace_rdev_set_wiphy_params(&rdev->wiphy, changed); - ret = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); + if (rdev->ops->set_wiphy_params) + ret = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } @@ -1425,13 +1423,11 @@ rdev_set_radar_background(struct cfg80211_registered_device *rdev, struct cfg80211_chan_def *chandef) { struct wiphy *wiphy = &rdev->wiphy; - int ret; - - if (!rdev->ops->set_radar_background) - return -EOPNOTSUPP; + int ret = -EOPNOTSUPP; trace_rdev_set_radar_background(wiphy, chandef); - ret = rdev->ops->set_radar_background(wiphy, chandef); + if (rdev->ops->set_radar_background) + ret = rdev->ops->set_radar_background(wiphy, chandef); trace_rdev_return_int(wiphy, ret); return ret; @@ -1468,13 +1464,11 @@ rdev_add_link_station(struct cfg80211_registered_device *rdev, struct net_device *dev, struct link_station_parameters *params) { - int ret; - - if (!rdev->ops->add_link_station) - return -EOPNOTSUPP; + int ret = -EOPNOTSUPP; trace_rdev_add_link_station(&rdev->wiphy, dev, params); - ret = rdev->ops->add_link_station(&rdev->wiphy, dev, params); + if (rdev->ops->add_link_station) + ret = rdev->ops->add_link_station(&rdev->wiphy, dev, params); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } @@ -1484,13 +1478,11 @@ rdev_mod_link_station(struct cfg80211_registered_device *rdev, struct net_device *dev, struct link_station_parameters *params) { - int ret; - - if (!rdev->ops->mod_link_station) - return -EOPNOTSUPP; + int ret = -EOPNOTSUPP; trace_rdev_mod_link_station(&rdev->wiphy, dev, params); - ret = rdev->ops->mod_link_station(&rdev->wiphy, dev, params); + if (rdev->ops->mod_link_station) + ret = rdev->ops->mod_link_station(&rdev->wiphy, dev, params); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } @@ -1500,13 +1492,11 @@ rdev_del_link_station(struct cfg80211_registered_device *rdev, struct net_device *dev, struct link_station_del_parameters *params) { - int ret; - - if (!rdev->ops->del_link_station) - return -EOPNOTSUPP; + int ret = -EOPNOTSUPP; trace_rdev_del_link_station(&rdev->wiphy, dev, params); - ret = rdev->ops->del_link_station(&rdev->wiphy, dev, params); + if (rdev->ops->del_link_station) + ret = rdev->ops->del_link_station(&rdev->wiphy, dev, params); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } @@ -1517,13 +1507,11 @@ rdev_set_hw_timestamp(struct cfg80211_registered_device *rdev, struct cfg80211_set_hw_timestamp *hwts) { struct wiphy *wiphy = &rdev->wiphy; - int ret; - - if (!rdev->ops->set_hw_timestamp) - return -EOPNOTSUPP; + int ret = -EOPNOTSUPP; trace_rdev_set_hw_timestamp(wiphy, dev, hwts); - ret = rdev->ops->set_hw_timestamp(wiphy, dev, hwts); + if (rdev->ops->set_hw_timestamp) + ret = rdev->ops->set_hw_timestamp(wiphy, dev, hwts); trace_rdev_return_int(wiphy, ret); return ret; @@ -1535,13 +1523,11 @@ rdev_set_ttlm(struct cfg80211_registered_device *rdev, struct cfg80211_ttlm_params *params) { struct wiphy *wiphy = &rdev->wiphy; - int ret; - - if (!rdev->ops->set_ttlm) - return -EOPNOTSUPP; + int ret = -EOPNOTSUPP; trace_rdev_set_ttlm(wiphy, dev, params); - ret = rdev->ops->set_ttlm(wiphy, dev, params); + if (rdev->ops->set_ttlm) + ret = rdev->ops->set_ttlm(wiphy, dev, params); trace_rdev_return_int(wiphy, ret); return ret; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 3cef0021a3db..4a27f3823e25 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1600,6 +1600,8 @@ static u32 map_regdom_flags(u32 rd_flags) channel_flags |= IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT; if (rd_flags & NL80211_RRF_PSD) channel_flags |= IEEE80211_CHAN_PSD; + if (rd_flags & NL80211_RRF_ALLOW_6GHZ_VLP_AP) + channel_flags |= IEEE80211_CHAN_ALLOW_6GHZ_VLP_AP; return channel_flags; } diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0222ede0feb6..d99319d82205 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1604,7 +1604,7 @@ struct cfg80211_bss *__cfg80211_get_bss(struct wiphy *wiphy, } EXPORT_SYMBOL(__cfg80211_get_bss); -static void rb_insert_bss(struct cfg80211_registered_device *rdev, +static bool rb_insert_bss(struct cfg80211_registered_device *rdev, struct cfg80211_internal_bss *bss) { struct rb_node **p = &rdev->bss_tree.rb_node; @@ -1620,7 +1620,7 @@ static void rb_insert_bss(struct cfg80211_registered_device *rdev, if (WARN_ON(!cmp)) { /* will sort of leak this BSS */ - return; + return false; } if (cmp < 0) @@ -1631,6 +1631,7 @@ static void rb_insert_bss(struct cfg80211_registered_device *rdev, rb_link_node(&bss->rbn, parent, p); rb_insert_color(&bss->rbn, &rdev->bss_tree); + return true; } static struct cfg80211_internal_bss * @@ -1657,6 +1658,34 @@ rb_find_bss(struct cfg80211_registered_device *rdev, return NULL; } +static void cfg80211_insert_bss(struct cfg80211_registered_device *rdev, + struct cfg80211_internal_bss *bss) +{ + lockdep_assert_held(&rdev->bss_lock); + + if (!rb_insert_bss(rdev, bss)) + return; + list_add_tail(&bss->list, &rdev->bss_list); + rdev->bss_entries++; +} + +static void cfg80211_rehash_bss(struct cfg80211_registered_device *rdev, + struct cfg80211_internal_bss *bss) +{ + lockdep_assert_held(&rdev->bss_lock); + + rb_erase(&bss->rbn, &rdev->bss_tree); + if (!rb_insert_bss(rdev, bss)) { + list_del(&bss->list); + if (!list_empty(&bss->hidden_list)) + list_del_init(&bss->hidden_list); + if (!list_empty(&bss->pub.nontrans_list)) + list_del_init(&bss->pub.nontrans_list); + rdev->bss_entries--; + } + rdev->bss_generation++; +} + static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev, struct cfg80211_internal_bss *new) { @@ -1969,9 +1998,7 @@ __cfg80211_bss_update(struct cfg80211_registered_device *rdev, bss_ref_get(rdev, bss_from_pub(tmp->pub.transmitted_bss)); } - list_add_tail(&new->list, &rdev->bss_list); - rdev->bss_entries++; - rb_insert_bss(rdev, new); + cfg80211_insert_bss(rdev, new); found = new; } @@ -2136,38 +2163,53 @@ struct cfg80211_inform_single_bss_data { u64 cannot_use_reasons; }; -static bool cfg80211_6ghz_power_type_valid(const u8 *ie, size_t ielen, - const u32 flags) +enum ieee80211_ap_reg_power +cfg80211_get_6ghz_power_type(const u8 *elems, size_t elems_len) { - const struct element *tmp; + const struct ieee80211_he_6ghz_oper *he_6ghz_oper; struct ieee80211_he_operation *he_oper; + const struct element *tmp; - tmp = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ie, ielen); - if (tmp && tmp->datalen >= sizeof(*he_oper) + 1 && - tmp->datalen >= ieee80211_he_oper_size(tmp->data + 1)) { - const struct ieee80211_he_6ghz_oper *he_6ghz_oper; - - he_oper = (void *)&tmp->data[1]; - he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper); - - if (!he_6ghz_oper) - return false; + tmp = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, + elems, elems_len); + if (!tmp || tmp->datalen < sizeof(*he_oper) + 1 || + tmp->datalen < ieee80211_he_oper_size(tmp->data + 1)) + return IEEE80211_REG_UNSET_AP; + + he_oper = (void *)&tmp->data[1]; + he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper); + + if (!he_6ghz_oper) + return IEEE80211_REG_UNSET_AP; + + switch (u8_get_bits(he_6ghz_oper->control, + IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) { + case IEEE80211_6GHZ_CTRL_REG_LPI_AP: + case IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP: + return IEEE80211_REG_LPI_AP; + case IEEE80211_6GHZ_CTRL_REG_SP_AP: + case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP: + return IEEE80211_REG_SP_AP; + case IEEE80211_6GHZ_CTRL_REG_VLP_AP: + return IEEE80211_REG_VLP_AP; + default: + return IEEE80211_REG_UNSET_AP; + } +} - switch (u8_get_bits(he_6ghz_oper->control, - IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) { - case IEEE80211_6GHZ_CTRL_REG_LPI_AP: - case IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP: - return true; - case IEEE80211_6GHZ_CTRL_REG_SP_AP: - case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP: - return !(flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT); - case IEEE80211_6GHZ_CTRL_REG_VLP_AP: - return !(flags & IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT); - default: - return false; - } +static bool cfg80211_6ghz_power_type_valid(const u8 *elems, size_t elems_len, + const u32 flags) +{ + switch (cfg80211_get_6ghz_power_type(elems, elems_len)) { + case IEEE80211_REG_LPI_AP: + return true; + case IEEE80211_REG_SP_AP: + return !(flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT); + case IEEE80211_REG_VLP_AP: + return !(flags & IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT); + default: + return false; } - return false; } /* Returned bss is reference counted and must be cleaned up appropriately. */ @@ -3349,19 +3391,14 @@ void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev, if (!WARN_ON(!__cfg80211_unlink_bss(rdev, new))) rdev->bss_generation++; } - - rb_erase(&cbss->rbn, &rdev->bss_tree); - rb_insert_bss(rdev, cbss); - rdev->bss_generation++; + cfg80211_rehash_bss(rdev, cbss); list_for_each_entry_safe(nontrans_bss, tmp, &cbss->pub.nontrans_list, nontrans_list) { bss = bss_from_pub(nontrans_bss); bss->pub.channel = chan; - rb_erase(&bss->rbn, &rdev->bss_tree); - rb_insert_bss(rdev, bss); - rdev->bss_generation++; + cfg80211_rehash_bss(rdev, bss); } done: diff --git a/net/wireless/sme.c b/net/wireless/sme.c index a8ad55f11133..e419aa8c4a5a 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -5,7 +5,7 @@ * (for nl80211's connect() and wext) * * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> - * Copyright (C) 2009, 2020, 2022-2023 Intel Corporation. All rights reserved. + * Copyright (C) 2009, 2020, 2022-2024 Intel Corporation. All rights reserved. * Copyright 2017 Intel Deutschland GmbH */ @@ -130,7 +130,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) rdev->scan_req = request; - err = rdev_scan(rdev, request); + err = cfg80211_scan(rdev); if (!err) { wdev->conn->state = CFG80211_CONN_SCANNING; nl80211_send_scan_start(rdev, wdev); diff --git a/net/wireless/tests/chan.c b/net/wireless/tests/chan.c index d02258ac2dab..74bbee25085f 100644 --- a/net/wireless/tests/chan.c +++ b/net/wireless/tests/chan.c @@ -113,16 +113,16 @@ static const struct chandef_compat_case { }, }, { - .desc = "different primary 160 MHz", + .desc = "different primary 320 MHz", .c1 = { .width = NL80211_CHAN_WIDTH_320, .chan = &chan_6ghz_105, - .center_freq1 = 6475 + 150, + .center_freq1 = 6475 + 110, }, .c2 = { .width = NL80211_CHAN_WIDTH_320, .chan = &chan_6ghz_105, - .center_freq1 = 6475 - 10, + .center_freq1 = 6475 - 50, }, }, { @@ -131,12 +131,12 @@ static const struct chandef_compat_case { .c1 = { .width = NL80211_CHAN_WIDTH_160, .chan = &chan_6ghz_105, - .center_freq1 = 6475 + 70, + .center_freq1 = 6475 + 30, }, .c2 = { .width = NL80211_CHAN_WIDTH_320, .chan = &chan_6ghz_105, - .center_freq1 = 6475 - 10, + .center_freq1 = 6475 - 50, }, .compat = true, }, @@ -145,12 +145,12 @@ static const struct chandef_compat_case { .c1 = { .width = NL80211_CHAN_WIDTH_160, .chan = &chan_6ghz_105, - .center_freq1 = 6475 + 70, + .center_freq1 = 6475 + 30, }, .c2 = { .width = NL80211_CHAN_WIDTH_320, .chan = &chan_6ghz_105, - .center_freq1 = 6475 - 10, + .center_freq1 = 6475 - 50, .punctured = 0xf, }, .compat = true, @@ -160,13 +160,13 @@ static const struct chandef_compat_case { .c1 = { .width = NL80211_CHAN_WIDTH_160, .chan = &chan_6ghz_105, - .center_freq1 = 6475 + 70, + .center_freq1 = 6475 + 30, .punctured = 0xc0, }, .c2 = { .width = NL80211_CHAN_WIDTH_320, .chan = &chan_6ghz_105, - .center_freq1 = 6475 - 10, + .center_freq1 = 6475 - 50, .punctured = 0xc000, }, .compat = true, @@ -176,13 +176,13 @@ static const struct chandef_compat_case { .c1 = { .width = NL80211_CHAN_WIDTH_160, .chan = &chan_6ghz_105, - .center_freq1 = 6475 + 70, + .center_freq1 = 6475 + 30, .punctured = 0x80, }, .c2 = { .width = NL80211_CHAN_WIDTH_320, .chan = &chan_6ghz_105, - .center_freq1 = 6475 - 10, + .center_freq1 = 6475 - 50, .punctured = 0xc000, }, }, diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 6ef9294747e3..5c26f065bd68 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -3389,23 +3389,26 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify, TRACE_EVENT(cfg80211_reg_can_beacon, TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, - enum nl80211_iftype iftype, bool check_no_ir), - TP_ARGS(wiphy, chandef, iftype, check_no_ir), + enum nl80211_iftype iftype, u32 prohibited_flags, + u32 permitting_flags), + TP_ARGS(wiphy, chandef, iftype, prohibited_flags, permitting_flags), TP_STRUCT__entry( WIPHY_ENTRY CHAN_DEF_ENTRY __field(enum nl80211_iftype, iftype) - __field(bool, check_no_ir) + __field(u32, prohibited_flags) + __field(u32, permitting_flags) ), TP_fast_assign( WIPHY_ASSIGN; CHAN_DEF_ASSIGN(chandef); __entry->iftype = iftype; - __entry->check_no_ir = check_no_ir; + __entry->prohibited_flags = prohibited_flags; + __entry->permitting_flags = permitting_flags; ), - TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d check_no_ir=%s", + TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d prohibited_flags=0x%x permitting_flags=0x%x", WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype, - BOOL_TO_STR(__entry->check_no_ir)) + __entry->prohibited_flags, __entry->permitting_flags) ); TRACE_EVENT(cfg80211_chandef_dfs_required, diff --git a/net/wireless/util.c b/net/wireless/util.c index 082c6f9c5416..af6ec719567f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1504,7 +1504,7 @@ static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate) 5120, /* 0.833333... */ }; u32 rates_160M[3] = { 960777777, 907400000, 816666666 }; - u32 rates_969[3] = { 480388888, 453700000, 408333333 }; + u32 rates_996[3] = { 480388888, 453700000, 408333333 }; u32 rates_484[3] = { 229411111, 216666666, 195000000 }; u32 rates_242[3] = { 114711111, 108333333, 97500000 }; u32 rates_106[3] = { 40000000, 37777777, 34000000 }; @@ -1524,12 +1524,14 @@ static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate) if (WARN_ON_ONCE(rate->nss < 1 || rate->nss > 8)) return 0; - if (rate->bw == RATE_INFO_BW_160) + if (rate->bw == RATE_INFO_BW_160 || + (rate->bw == RATE_INFO_BW_HE_RU && + rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_2x996)) result = rates_160M[rate->he_gi]; else if (rate->bw == RATE_INFO_BW_80 || (rate->bw == RATE_INFO_BW_HE_RU && rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_996)) - result = rates_969[rate->he_gi]; + result = rates_996[rate->he_gi]; else if (rate->bw == RATE_INFO_BW_40 || (rate->bw == RATE_INFO_BW_HE_RU && rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_484)) |