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:
Pagadala Yesu Anjaneyulu 2026-09-21 22:54:54 +03:00 committed by Johannes Berg
parent e5fefa3da5
commit 4b7ad021a9
4 changed files with 38 additions and 11 deletions

View File

@ -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 {

View File

@ -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)

View File

@ -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, &params->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, &params.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, &params.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, &params);
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;

View File

@ -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;