]> www.infradead.org Git - users/hch/configfs.git/commitdiff
wifi: cfg80211: add regulatory flag to allow VLP AP operation
authorJohannes Berg <johannes.berg@intel.com>
Thu, 23 May 2024 10:09:49 +0000 (12:09 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 12 Jun 2024 11:04:25 +0000 (13:04 +0200)
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>
include/net/cfg80211.h
include/uapi/linux/nl80211.h
net/wireless/chan.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/trace.h

index 45ffeb110d36275ad51d14a2addf82b8612d1870..6f992aff74aeff45614af52cf88dab8d746191ed 100644 (file)
@@ -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;
 };
 
index f917bc6c9b6ff4f9d5149fdd00f85308b4929404..6ae3997061b64cd6a4aecb3f313d6b5a6b7fe7f8 100644 (file)
@@ -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
index 8b1796130b283d7c2f0349381958e0a1e60956d4..bf2fdcd420191b0149752feae13f8676c57924ee 100644 (file)
@@ -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);
 
index 4628280abf1daaecea93083fa933d1281cd0e624..a94e73c133f76f8434731a0da1bffc66239e76c5 100644 (file)
@@ -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, &params->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, &params->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,
index 3cef0021a3db923c3e410d54760d5ea68df065db..4a27f3823e25970c6f4ceaade0040d98efb680ff 100644 (file)
@@ -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;
 }
 
index 6ef9294747e3dc244ad22cc67101b0ff78b7491f..5c26f065bd688c600d3ced5e222a2f4c84cd509a 100644 (file)
@@ -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,