mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
wifi: nl80211: defer AP beacon regulatory check to start_ap
Defer the cfg80211_reg_can_beacon_relax() check from __nl80211_set_channel() for AP and P2P-GO. At __nl80211_set_channel() stage AP type is not fully known before start_ap, so this early check incorrectly rejects valid VLP AP bring-up. start_ap has the required AP context and already performs the regulatory validation, so start checking after start_ap. This way, VLP APs can be brought up. Also handle the CSA scenario by running regulatory beaconing validation during channel switch and preserving/updating AP reg_power across CSA completion. Signed-off-by: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com> Reviewed-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://patch.msgid.link/20260921224731.67fbc8a28a2c.I5633284cb4c82ffb4e4e32e6f2dcc9a71fd5b06a@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
e5fefa3da5
commit
4b7ad021a9
|
|
@ -7371,6 +7371,8 @@ struct wireless_dev {
|
|||
union {
|
||||
struct {
|
||||
unsigned int beacon_interval;
|
||||
enum ieee80211_ap_reg_power reg_power;
|
||||
enum ieee80211_ap_reg_power csa_reg_power;
|
||||
struct cfg80211_chan_def chandef;
|
||||
} ap;
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Parts of this file are
|
||||
* Copyright (C) 2022-2023 Intel Corporation
|
||||
* Copyright (C) 2022-2023, 2026 Intel Corporation
|
||||
*/
|
||||
#include <linux/ieee80211.h>
|
||||
#include <linux/export.h>
|
||||
|
|
@ -33,9 +33,8 @@ static int ___cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
|||
err = rdev_stop_ap(rdev, dev, link_id);
|
||||
if (!err) {
|
||||
wdev->conn_owner_nlportid = 0;
|
||||
wdev->links[link_id].ap.beacon_interval = 0;
|
||||
memset(&wdev->links[link_id].ap.chandef, 0,
|
||||
sizeof(wdev->links[link_id].ap.chandef));
|
||||
memset(&wdev->links[link_id].ap, 0,
|
||||
sizeof(wdev->links[link_id].ap));
|
||||
wdev->u.ap.ssid_len = 0;
|
||||
rdev_set_qos_map(rdev, dev, NULL);
|
||||
if (notify)
|
||||
|
|
|
|||
|
|
@ -4156,12 +4156,17 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
|
|||
switch (iftype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
|
||||
iftype))
|
||||
return -EINVAL;
|
||||
if (wdev->links[link_id].ap.beacon_interval) {
|
||||
struct ieee80211_channel *cur_chan;
|
||||
struct cfg80211_beaconing_check_config config = {
|
||||
.iftype = iftype,
|
||||
.reg_power = wdev->links[link_id].ap.reg_power,
|
||||
.relax = true,
|
||||
};
|
||||
|
||||
if (!cfg80211_reg_check_beaconing(&rdev->wiphy,
|
||||
&chandef, &config))
|
||||
return -EINVAL;
|
||||
if (!dev || !rdev->ops->set_ap_chanwidth ||
|
||||
!(rdev->wiphy.features &
|
||||
NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE))
|
||||
|
|
@ -7397,6 +7402,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|||
params->beacon.tail_len, 0);
|
||||
if (!cfg80211_reg_check_beaconing(&rdev->wiphy, ¶ms->chandef,
|
||||
&beacon_check)) {
|
||||
GENL_SET_ERR_MSG(info, "Channel rejected by regulatory");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -7511,6 +7517,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|||
err = rdev_start_ap(rdev, dev, params);
|
||||
if (!err) {
|
||||
wdev->links[link_id].ap.beacon_interval = params->beacon_interval;
|
||||
wdev->links[link_id].ap.reg_power = beacon_check.reg_power;
|
||||
wdev->links[link_id].ap.chandef = params->chandef;
|
||||
wdev->u.ap.ssid_len = params->ssid_len;
|
||||
memcpy(wdev->u.ap.ssid, params->ssid,
|
||||
|
|
@ -7603,6 +7610,8 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
|
|||
}
|
||||
|
||||
err = rdev_change_beacon(rdev, dev, params);
|
||||
if (!err)
|
||||
wdev->links[link_id].ap.reg_power = beacon_check.reg_power;
|
||||
|
||||
out:
|
||||
kfree(params->beacon.mbssid_ies);
|
||||
|
|
@ -12314,6 +12323,7 @@ static int nl80211_parse_counter_offsets(struct cfg80211_registered_device *rdev
|
|||
static int nl80211_channel_switch(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;
|
||||
|
|
@ -12438,8 +12448,13 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
|
|||
goto free;
|
||||
|
||||
skip_beacons:
|
||||
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_after.tail,
|
||||
params.beacon_after.tail_len, 0);
|
||||
if (!cfg80211_reg_check_beaconing(&rdev->wiphy, ¶ms.chandef,
|
||||
&beacon_check)) {
|
||||
err = -EINVAL;
|
||||
goto free;
|
||||
}
|
||||
|
|
@ -12475,6 +12490,10 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
|
|||
params.link_id = link_id;
|
||||
err = rdev_channel_switch(rdev, dev, ¶ms);
|
||||
|
||||
if (!err && (wdev->iftype == NL80211_IFTYPE_AP ||
|
||||
wdev->iftype == NL80211_IFTYPE_P2P_GO))
|
||||
wdev->links[link_id].ap.csa_reg_power = beacon_check.reg_power;
|
||||
|
||||
free:
|
||||
kfree(params.beacon_after.mbssid_ies);
|
||||
kfree(params.beacon_csa.mbssid_ies);
|
||||
|
|
@ -22747,6 +22766,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
|
|||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
wdev->links[link_id].ap.chandef = *chandef;
|
||||
wdev->links[link_id].ap.reg_power =
|
||||
wdev->links[link_id].ap.csa_reg_power;
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
wdev->u.ibss.chandef = *chandef;
|
||||
|
|
|
|||
|
|
@ -2361,6 +2361,10 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
|
|||
}
|
||||
|
||||
for (link = 0; link < ARRAY_SIZE(wdev->links); link++) {
|
||||
struct cfg80211_beaconing_check_config config = {
|
||||
.iftype = iftype,
|
||||
.relax = true,
|
||||
};
|
||||
struct ieee80211_channel *chan;
|
||||
|
||||
if (!wdev->valid_links && link > 0)
|
||||
|
|
@ -2373,6 +2377,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
|
|||
if (!wdev->links[link].ap.beacon_interval)
|
||||
continue;
|
||||
chandef = wdev->links[link].ap.chandef;
|
||||
config.reg_power = wdev->links[link].ap.reg_power;
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
if (!wdev->u.mesh.beacon_interval)
|
||||
|
|
@ -2426,8 +2431,8 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
|
|||
case NL80211_IFTYPE_P2P_GO:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
ret = cfg80211_reg_can_beacon_relax(wiphy, &chandef,
|
||||
iftype);
|
||||
ret = cfg80211_reg_check_beaconing(wiphy, &chandef,
|
||||
&config);
|
||||
if (!ret)
|
||||
return ret;
|
||||
break;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user