wifi: cfg80211: add regulatory flag to allow VLP AP operation
Add a regulatory flag to allow VLP AP operation even on channels otherwise marked NO_IR, which may be possible in some regulatory domains/countries. Note that this requires checking also when the beacon is changed, since that may change the regulatory power type. Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Link: https://msgid.link/20240523120945.63792ce19790.Ie2a02750d283b78fbf3c686b10565fb0388889e2@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
9fd171a71b
commit
c1d8bd8d77
@ -125,6 +125,8 @@ struct wiphy;
|
||||
* @IEEE80211_CHAN_CAN_MONITOR: This channel can be used for monitor
|
||||
* mode even in the presence of other (regulatory) restrictions,
|
||||
* even if it is otherwise disabled.
|
||||
* @IEEE80211_CHAN_ALLOW_6GHZ_VLP_AP: Allow using this channel for AP operation
|
||||
* with very low power (VLP), even if otherwise set to NO_IR.
|
||||
*/
|
||||
enum ieee80211_channel_flags {
|
||||
IEEE80211_CHAN_DISABLED = BIT(0),
|
||||
@ -152,6 +154,7 @@ enum ieee80211_channel_flags {
|
||||
IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT = BIT(22),
|
||||
IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT = BIT(23),
|
||||
IEEE80211_CHAN_CAN_MONITOR = BIT(24),
|
||||
IEEE80211_CHAN_ALLOW_6GHZ_VLP_AP = BIT(25),
|
||||
};
|
||||
|
||||
#define IEEE80211_CHAN_NO_HT40 \
|
||||
@ -8806,9 +8809,12 @@ static inline void cfg80211_report_obss_beacon(struct wiphy *wiphy,
|
||||
* @relax: allow IR-relaxation conditions to apply (e.g. another
|
||||
* interface connected already on the same channel)
|
||||
* NOTE: If this is set, wiphy mutex must be held.
|
||||
* @reg_power: &enum ieee80211_ap_reg_power value indicating the
|
||||
* advertised/used 6 GHz regulatory power setting
|
||||
*/
|
||||
struct cfg80211_beaconing_check_config {
|
||||
enum nl80211_iftype iftype;
|
||||
enum ieee80211_ap_reg_power reg_power;
|
||||
bool relax;
|
||||
};
|
||||
|
||||
|
@ -4277,6 +4277,8 @@ enum nl80211_wmm_rule {
|
||||
* @NL80211_FREQUENCY_ATTR_CAN_MONITOR: This channel can be used in monitor
|
||||
* mode despite other (regulatory) restrictions, even if the channel is
|
||||
* otherwise completely disabled.
|
||||
* @NL80211_FREQUENCY_ATTR_ALLOW_6GHZ_VLP_AP: This channel can be used for a
|
||||
* very low power (VLP) AP, despite being NO_IR.
|
||||
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
|
||||
* currently defined
|
||||
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
|
||||
@ -4320,6 +4322,7 @@ enum nl80211_frequency_attr {
|
||||
NL80211_FREQUENCY_ATTR_NO_6GHZ_VLP_CLIENT,
|
||||
NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT,
|
||||
NL80211_FREQUENCY_ATTR_CAN_MONITOR,
|
||||
NL80211_FREQUENCY_ATTR_ALLOW_6GHZ_VLP_AP,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
|
||||
@ -4529,6 +4532,8 @@ enum nl80211_sched_scan_match_attr {
|
||||
* Should be used together with %NL80211_RRF_DFS only.
|
||||
* @NL80211_RRF_NO_6GHZ_VLP_CLIENT: Client connection to VLP AP not allowed
|
||||
* @NL80211_RRF_NO_6GHZ_AFC_CLIENT: Client connection to AFC AP not allowed
|
||||
* @NL80211_RRF_ALLOW_6GHZ_VLP_AP: Very low power (VLP) AP can be permitted
|
||||
* despite NO_IR configuration.
|
||||
*/
|
||||
enum nl80211_reg_rule_flags {
|
||||
NL80211_RRF_NO_OFDM = 1<<0,
|
||||
@ -4553,6 +4558,7 @@ enum nl80211_reg_rule_flags {
|
||||
NL80211_RRF_DFS_CONCURRENT = 1<<21,
|
||||
NL80211_RRF_NO_6GHZ_VLP_CLIENT = 1<<22,
|
||||
NL80211_RRF_NO_6GHZ_AFC_CLIENT = 1<<23,
|
||||
NL80211_RRF_ALLOW_6GHZ_VLP_AP = 1<<24,
|
||||
};
|
||||
|
||||
#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
|
||||
|
@ -1523,28 +1523,38 @@ 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, 0);
|
||||
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;
|
||||
@ -1555,6 +1565,7 @@ bool cfg80211_reg_check_beaconing(struct wiphy *wiphy,
|
||||
struct cfg80211_beaconing_check_config *cfg)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
u32 permitting_flags = 0;
|
||||
bool check_no_ir = true;
|
||||
|
||||
/*
|
||||
@ -1569,8 +1580,12 @@ bool cfg80211_reg_check_beaconing(struct wiphy *wiphy,
|
||||
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, cfg->iftype,
|
||||
check_no_ir);
|
||||
check_no_ir ? IEEE80211_CHAN_NO_IR : 0,
|
||||
permitting_flags);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_reg_check_beaconing);
|
||||
|
||||
|
@ -1207,6 +1207,9 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
|
||||
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,
|
||||
@ -5954,6 +5957,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;
|
||||
@ -6103,8 +6107,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;
|
||||
}
|
||||
@ -6261,6 +6270,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;
|
||||
@ -6287,6 +6297,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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user