cfg80211: add support for parsing OBBS_PD attributes
authorJohn Crispin <john@phrozen.org>
Tue, 30 Jul 2019 16:37:00 +0000 (18:37 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 31 Jul 2019 09:00:52 +0000 (11:00 +0200)
Add the data structure, policy and parsing code allowing userland to send
the OBSS PD information into the kernel.

Signed-off-by: John Crispin <john@phrozen.org>
Link: https://lore.kernel.org/r/20190730163701.18836-2-john@phrozen.org
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/cfg80211.h
include/uapi/linux/nl80211.h
net/wireless/nl80211.c

index 45850a8..35ec1f0 100644 (file)
@@ -247,6 +247,19 @@ struct ieee80211_rate {
 };
 
 /**
+ * struct ieee80211_he_obss_pd - AP settings for spatial reuse
+ *
+ * @enable: is the feature enabled.
+ * @min_offset: minimal tx power offset an associated station shall use
+ * @max_offset: maximum tx power offset an associated station shall use
+ */
+struct ieee80211_he_obss_pd {
+       bool enable;
+       u8 min_offset;
+       u8 max_offset;
+};
+
+/**
  * struct ieee80211_sta_ht_cap - STA's HT capabilities
  *
  * This structure describes most essential parameters needed
@@ -896,6 +909,7 @@ enum cfg80211_ap_settings_flags {
  * @vht_required: stations must support VHT
  * @twt_responder: Enable Target Wait Time
  * @flags: flags, as defined in enum cfg80211_ap_settings_flags
+ * @he_obss_pd: OBSS Packet Detection settings
  */
 struct cfg80211_ap_settings {
        struct cfg80211_chan_def chandef;
@@ -923,6 +937,7 @@ struct cfg80211_ap_settings {
        bool ht_required, vht_required;
        bool twt_responder;
        u32 flags;
+       struct ieee80211_he_obss_pd he_obss_pd;
 };
 
 /**
index c45587c..822851d 100644 (file)
@@ -2358,6 +2358,9 @@ enum nl80211_commands {
  *
  * @NL80211_ATTR_TWT_RESPONDER: Enable target wait time responder support.
  *
+ * @NL80211_ATTR_HE_OBSS_PD: nested attribute for OBSS Packet Detection
+ *     functionality.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2815,6 +2818,8 @@ enum nl80211_attrs {
 
        NL80211_ATTR_TWT_RESPONDER,
 
+       NL80211_ATTR_HE_OBSS_PD,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -6490,4 +6495,26 @@ enum nl80211_peer_measurement_ftm_resp {
        NL80211_PMSR_FTM_RESP_ATTR_MAX = NUM_NL80211_PMSR_FTM_RESP_ATTR - 1
 };
 
+/**
+ * enum nl80211_obss_pd_attributes - OBSS packet detection attributes
+ * @__NL80211_HE_OBSS_PD_ATTR_INVALID: Invalid
+ *
+ * @NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET: the OBSS PD minimum tx power offset.
+ * @NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET: the OBSS PD maximum tx power offset.
+ *
+ * @__NL80211_HE_OBSS_PD_ATTR_LAST: Internal
+ * @NL80211_HE_OBSS_PD_ATTR_MAX: highest OBSS PD attribute.
+ */
+enum nl80211_obss_pd_attributes {
+       __NL80211_HE_OBSS_PD_ATTR_INVALID,
+
+       NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
+       NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
+
+       /* keep last */
+       __NL80211_HE_OBSS_PD_ATTR_LAST,
+       NL80211_HE_OBSS_PD_ATTR_MAX = __NL80211_HE_OBSS_PD_ATTR_LAST - 1,
+};
+
+
 #endif /* __LINUX_NL80211_H */
index 1e78ed4..3006cfc 100644 (file)
@@ -281,6 +281,14 @@ nl80211_pmsr_attr_policy[NL80211_PMSR_ATTR_MAX + 1] = {
                NLA_POLICY_NESTED_ARRAY(nl80211_psmr_peer_attr_policy),
 };
 
+static const struct nla_policy
+he_obss_pd_policy[NL80211_HE_OBSS_PD_ATTR_MAX + 1] = {
+       [NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET] =
+               NLA_POLICY_RANGE(NLA_U8, 1, 20),
+       [NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET] =
+               NLA_POLICY_RANGE(NLA_U8, 1, 20),
+};
+
 const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
        [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
        [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
@@ -574,6 +582,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
        [NL80211_ATTR_SAE_PASSWORD] = { .type = NLA_BINARY,
                                        .len = SAE_PASSWORD_MAX_LEN },
        [NL80211_ATTR_TWT_RESPONDER] = { .type = NLA_FLAG },
+       [NL80211_ATTR_HE_OBSS_PD] = NLA_POLICY_NESTED(he_obss_pd_policy),
 };
 
 /* policy for the key attributes */
@@ -4405,6 +4414,34 @@ static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
        return 0;
 }
 
+static int nl80211_parse_he_obss_pd(struct nlattr *attrs,
+                                   struct ieee80211_he_obss_pd *he_obss_pd)
+{
+       struct nlattr *tb[NL80211_HE_OBSS_PD_ATTR_MAX + 1];
+       int err;
+
+       err = nla_parse_nested(tb, NL80211_HE_OBSS_PD_ATTR_MAX, attrs,
+                              he_obss_pd_policy, NULL);
+       if (err)
+               return err;
+
+       if (!tb[NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET] ||
+           !tb[NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET])
+               return -EINVAL;
+
+       he_obss_pd->min_offset =
+               nla_get_u32(tb[NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET]);
+       he_obss_pd->max_offset =
+               nla_get_u32(tb[NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET]);
+
+       if (he_obss_pd->min_offset >= he_obss_pd->max_offset)
+               return -EINVAL;
+
+       he_obss_pd->enable = true;
+
+       return 0;
+}
+
 static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
                                            const u8 *rates)
 {
@@ -4689,6 +4726,14 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        params.twt_responder =
                    nla_get_flag(info->attrs[NL80211_ATTR_TWT_RESPONDER]);
 
+       if (info->attrs[NL80211_ATTR_HE_OBSS_PD]) {
+               err = nl80211_parse_he_obss_pd(
+                                       info->attrs[NL80211_ATTR_HE_OBSS_PD],
+                                       &params.he_obss_pd);
+               if (err)
+                       return err;
+       }
+
        nl80211_calculate_ap_params(&params);
 
        if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])