Message ID | 20220704102341.5692-5-quic_adisi@quicinc.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Johannes Berg |
Headers | show |
Series | cfg80211/mac80211: extend 6 GHz support for all power modes | expand |
On Mon, 2022-07-04 at 15:53 +0530, Aditya Kumar Singh wrote: > > + * @NL80211_ATTR_6GHZ_REG_AP_POWER_MODE: Configure 6 GHz regulatory power mode > + * for access points. Referenced from &enum ieee80211_ap_reg_power. > + * > + * @NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE: Configure 6 GHz regulatory power > + * mode for clients. Referenced from &enum ieee80211_client_reg_power. I don't really see a good reason to have two attributes for this, rather than validating their value based on the iftype? > err = __cfg80211_stop_ap(rdev, dev, link_id, notify); > + > + if (wdev->reg_6ghz_pwr_configured) > + wdev->reg_6ghz_pwr_configured = false; no need to check first > +static int nl80211_set_6ghz_power_mode(struct sk_buff *skb, > + struct genl_info *info) > +{ > + struct net_device *dev = info->user_ptr[1]; > + struct wireless_dev *wdev = NULL; > + enum nl80211_iftype iftype = NL80211_IFTYPE_UNSPECIFIED; > + int ret = -EINVAL; > + > + if (dev) > + wdev = dev->ieee80211_ptr; > + > + if (wdev) > + iftype = wdev->iftype; that's all pretty useless > + if (iftype != NL80211_IFTYPE_AP && > + iftype != NL80211_IFTYPE_STATION) > + return -EOPNOTSUPP; you're going to return here anyway ... Better to just simplify that and return if there's no wdev, and actually you can enforce that anyway through the internal flags?? Not sure why you do all this. Btw, all of that probably also needs to be per *link* rather than per *interface* now, with MLO? > + if (!info->attrs[NL80211_ATTR_6GHZ_REG_AP_POWER_MODE] && > + !info->attrs[NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE]) > + return -EINVAL; > + > + wdev_lock(wdev); > + if (wdev->reg_6ghz_pwr_configured) { > + wdev_unlock(wdev); > + return -EALREADY; > + } > + > + if (iftype == NL80211_IFTYPE_AP && > + info->attrs[NL80211_ATTR_6GHZ_REG_AP_POWER_MODE]) { > + wdev->ap_6ghz_power = > + nla_get_u8(info->attrs[NL80211_ATTR_6GHZ_REG_AP_POWER_MODE]); > + ret = 0; > + } > + > + if (iftype == NL80211_IFTYPE_STATION && > + info->attrs[NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE]) { > + wdev->client_6ghz_power = > + nla_get_u8(info->attrs[NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE]); > + ret = 0; > + } > + > + if (!ret) > + wdev->reg_6ghz_pwr_configured = true; and honestly that logic here with the two attributes is pretty strange... I'd even say you should remove the union in the wdev struct since you only can have one of them at a time anyway > + { > + .cmd = NL80211_CMD_SET_6GHZ_POWER_MODE, > + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, > + .doit = nl80211_set_6ghz_power_mode, > + .flags = GENL_UNS_ADMIN_PERM, > + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV), if you have netdev then you have wdev too, later > > + if (wdev->reg_6ghz_pwr_configured) > + wdev->reg_6ghz_pwr_configured = false; > No need for if johannes
On 9/6/2022 16:35, Johannes Berg wrote: > On Mon, 2022-07-04 at 15:53 +0530, Aditya Kumar Singh wrote: >> >> + * @NL80211_ATTR_6GHZ_REG_AP_POWER_MODE: Configure 6 GHz regulatory power mode >> + * for access points. Referenced from &enum ieee80211_ap_reg_power. >> + * >> + * @NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE: Configure 6 GHz regulatory power >> + * mode for clients. Referenced from &enum ieee80211_client_reg_power. > > I don't really see a good reason to have two attributes for this, rather > than validating their value based on the iftype? > The policy for each varies. For AP power mode, it can vary from 0 to 2 (total 3 power modes currently), and for clients 0 to 1 (total 2 power modes). So, if we have just 1 NL_ATTR, while parsing obviously we can do based on iftype but in NL_ATTR policy validation, for clients it will pass value 2 where actually it should not. Will that be fine? >> err = __cfg80211_stop_ap(rdev, dev, link_id, notify); >> + >> + if (wdev->reg_6ghz_pwr_configured) >> + wdev->reg_6ghz_pwr_configured = false; > > no need to check first Sure, will improvise in next version. > >> ... > > Btw, all of that probably also needs to be per *link* rather than per > *interface* now, with MLO? Yes, it should be per *link*. Im working on the changes, will send next version soon. > >> + if (!info->attrs[NL80211_ATTR_6GHZ_REG_AP_POWER_MODE] && >> + !info->attrs[NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE]) >> + return -EINVAL; >> + >> + wdev_lock(wdev); >> + if (wdev->reg_6ghz_pwr_configured) { >> + wdev_unlock(wdev); >> + return -EALREADY; >> + } >> + >> + if (iftype == NL80211_IFTYPE_AP && >> + info->attrs[NL80211_ATTR_6GHZ_REG_AP_POWER_MODE]) { >> + wdev->ap_6ghz_power = >> + nla_get_u8(info->attrs[NL80211_ATTR_6GHZ_REG_AP_POWER_MODE]); >> + ret = 0; >> + } >> + >> + if (iftype == NL80211_IFTYPE_STATION && >> + info->attrs[NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE]) { >> + wdev->client_6ghz_power = >> + nla_get_u8(info->attrs[NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE]); >> + ret = 0; >> + } >> + >> + if (!ret) >> + wdev->reg_6ghz_pwr_configured = true; > > and honestly that logic here with the two attributes is pretty > strange... > > I'd even say you should remove the union in the wdev struct since you > only can have one of them at a time anyway Sure will do. > >> + { >> + .cmd = NL80211_CMD_SET_6GHZ_POWER_MODE, >> + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, >> + .doit = nl80211_set_6ghz_power_mode, >> + .flags = GENL_UNS_ADMIN_PERM, >> + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV), > > if you have netdev then you have wdev too, later Yes, got it. > >> >> + if (wdev->reg_6ghz_pwr_configured) >> + wdev->reg_6ghz_pwr_configured = false; >> > > No need for if Got it, thanks. Will rectify. > > johannes Aditya
On Wed, 2022-10-19 at 09:54 +0530, Aditya Kumar Singh wrote: > On 9/6/2022 16:35, Johannes Berg wrote: > > On Mon, 2022-07-04 at 15:53 +0530, Aditya Kumar Singh wrote: > > > > > > + * @NL80211_ATTR_6GHZ_REG_AP_POWER_MODE: Configure 6 GHz regulatory power mode > > > + * for access points. Referenced from &enum ieee80211_ap_reg_power. > > > + * > > > + * @NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE: Configure 6 GHz regulatory power > > > + * mode for clients. Referenced from &enum ieee80211_client_reg_power. > > > > I don't really see a good reason to have two attributes for this, rather > > than validating their value based on the iftype? > > > The policy for each varies. For AP power mode, it can vary from 0 to 2 > (total 3 power modes currently), and for clients 0 to 1 (total 2 power > modes). So, if we have just 1 NL_ATTR, while parsing obviously we can do > based on iftype but in NL_ATTR policy validation, for clients it will > pass value 2 where actually it should not. Will that be fine? Yeah, I dunno. That just means we'd have to validate it in the code rather than the policy. Not really sure which is better. johannes
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ed482b23fb9c..1e8852c6149f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5644,6 +5644,9 @@ static inline void wiphy_unlock(struct wiphy *wiphy) * @links: array of %IEEE80211_MLD_MAX_NUM_LINKS elements containing @addr * @ap and @client for each link * @valid_links: bitmap describing what elements of @links are valid + * @ap_6ghz_power: 6 GHz regulatory power mode for Access Points + * @client_6ghz_power: 6 GHz regulatory power mode for Clients + * @reg_6ghz_pwr_configured: true if 6 GHz power mode is configured */ struct wireless_dev { struct wiphy *wiphy; @@ -5758,6 +5761,12 @@ struct wireless_dev { }; } links[IEEE80211_MLD_MAX_NUM_LINKS]; u16 valid_links; + + union { + enum ieee80211_ap_reg_power ap_6ghz_power; + enum ieee80211_client_reg_power client_6ghz_power; + }; + bool reg_6ghz_pwr_configured; }; static inline const u8 *wdev_address(struct wireless_dev *wdev) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 789f73878f50..e62838887802 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1254,6 +1254,11 @@ * without %NL80211_ATTR_MLO_LINK_ID as an easy way to remove all links * in preparation for e.g. roaming to a regular (non-MLO) AP. * + * @NL80211_CMD_SET_6GHZ_POWER_MODE: Set 6 GHz power mode for the interface + * using - + * &NL80211_ATTR_6GHZ_REG_AP_POWER_MODE - for access points + * &NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE - for clients + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1501,6 +1506,8 @@ enum nl80211_commands { NL80211_CMD_ADD_LINK, NL80211_CMD_REMOVE_LINK, + NL80211_CMD_SET_6GHZ_POWER_MODE, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -2701,6 +2708,12 @@ enum nl80211_commands { * suites allowed as %NL80211_MAX_NR_AKM_SUITES which is the legacy maximum * number prior to the introduction of this attribute. * + * @NL80211_ATTR_6GHZ_REG_AP_POWER_MODE: Configure 6 GHz regulatory power mode + * for access points. Referenced from &enum ieee80211_ap_reg_power. + * + * @NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE: Configure 6 GHz regulatory power + * mode for clients. Referenced from &enum ieee80211_client_reg_power. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3223,6 +3236,8 @@ enum nl80211_attrs { NL80211_ATTR_MAX_NUM_AKM_SUITES, + NL80211_ATTR_6GHZ_REG_AP_POWER_MODE, + NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE, /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/ap.c b/net/wireless/ap.c index e68923200018..be4e6177d72a 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c @@ -82,6 +82,10 @@ int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, wdev_lock(wdev); err = __cfg80211_stop_ap(rdev, dev, link_id, notify); + + if (wdev->reg_6ghz_pwr_configured) + wdev->reg_6ghz_pwr_configured = false; + wdev_unlock(wdev); return err; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index afa8cd686e0e..4d5c45f303ec 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -799,6 +799,12 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_MLD_ADDR] = NLA_POLICY_EXACT_LEN(ETH_ALEN), [NL80211_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG }, [NL80211_ATTR_MAX_NUM_AKM_SUITES] = { .type = NLA_REJECT }, + [NL80211_ATTR_6GHZ_REG_AP_POWER_MODE] = + NLA_POLICY_RANGE(NLA_U8, IEEE80211_REG_LPI_AP, + IEEE80211_REG_AP_POWER_MAX), + [NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE] = + NLA_POLICY_RANGE(NLA_U8, IEEE80211_REG_DEFAULT_CLIENT, + IEEE80211_REG_CLIENT_POWER_MAX), }; /* policy for the key attributes */ @@ -15699,6 +15705,55 @@ static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info) return 0; } +static int nl80211_set_6ghz_power_mode(struct sk_buff *skb, + struct genl_info *info) +{ + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = NULL; + enum nl80211_iftype iftype = NL80211_IFTYPE_UNSPECIFIED; + int ret = -EINVAL; + + if (dev) + wdev = dev->ieee80211_ptr; + + if (wdev) + iftype = wdev->iftype; + + if (iftype != NL80211_IFTYPE_AP && + iftype != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_6GHZ_REG_AP_POWER_MODE] && + !info->attrs[NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE]) + return -EINVAL; + + wdev_lock(wdev); + if (wdev->reg_6ghz_pwr_configured) { + wdev_unlock(wdev); + return -EALREADY; + } + + if (iftype == NL80211_IFTYPE_AP && + info->attrs[NL80211_ATTR_6GHZ_REG_AP_POWER_MODE]) { + wdev->ap_6ghz_power = + nla_get_u8(info->attrs[NL80211_ATTR_6GHZ_REG_AP_POWER_MODE]); + ret = 0; + } + + if (iftype == NL80211_IFTYPE_STATION && + info->attrs[NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE]) { + wdev->client_6ghz_power = + nla_get_u8(info->attrs[NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE]); + ret = 0; + } + + if (!ret) + wdev->reg_6ghz_pwr_configured = true; + + wdev_unlock(wdev); + return ret; +} + #define NL80211_FLAG_NEED_WIPHY 0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 @@ -16849,6 +16904,13 @@ static const struct genl_small_ops nl80211_small_ops[] = { .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_MLO_VALID_LINK_ID), }, + { + .cmd = NL80211_CMD_SET_6GHZ_POWER_MODE, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = nl80211_set_6ghz_power_mode, + .flags = GENL_UNS_ADMIN_PERM, + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV), + } }; static struct genl_family nl80211_fam __ro_after_init = { diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 00be498aab2e..8858d396e4f8 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -1500,6 +1500,9 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, if (!wdev->connected) wdev->u.client.ssid_len = 0; + if (wdev->reg_6ghz_pwr_configured) + wdev->reg_6ghz_pwr_configured = false; + return err; }
6 GHz introduces various power modes for access points and for clients. When user configures these power modes, currently cfg80211 does not have support to store the configured power mode. Add support to store the 6 GHz configured power mode in the structure wireless_dev via a new NL command - NL80211_CMD_SET_6GHZ_POWER_MODE. The above command uses two new NL attributes to set power mode for AP and clients - NL80211_ATTR_6GHZ_REG_AP_POWER_MODE and NL80211_ATTR_6GHZ_REG_CLIENT_POWER_MODE respectively. Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com> --- include/net/cfg80211.h | 9 ++++++ include/uapi/linux/nl80211.h | 15 +++++++++ net/wireless/ap.c | 4 +++ net/wireless/nl80211.c | 62 ++++++++++++++++++++++++++++++++++++ net/wireless/sme.c | 3 ++ 5 files changed, 93 insertions(+)