]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - net/wireless/nl80211.c
nl80211: Add support for EDMG channels
[linux.git] / net / wireless / nl80211.c
index 1e78ed45a759ac126c172f7b084f1b9f32cdc622..4565d7385884fdcdc10c8e29c43e7917cb684603 100644 (file)
@@ -281,7 +281,16 @@ 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] = {
+       [0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
        [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
        [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
                                      .len = 20-1 },
@@ -289,6 +298,13 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
 
        [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
        [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
+       [NL80211_ATTR_WIPHY_EDMG_CHANNELS] = NLA_POLICY_RANGE(NLA_U8,
+                                               NL80211_EDMG_CHANNELS_MIN,
+                                               NL80211_EDMG_CHANNELS_MAX),
+       [NL80211_ATTR_WIPHY_EDMG_BW_CONFIG] = NLA_POLICY_RANGE(NLA_U8,
+                                               NL80211_EDMG_BW_CONFIG_MIN,
+                                               NL80211_EDMG_BW_CONFIG_MAX),
+
        [NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
        [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
        [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },
@@ -574,6 +590,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 */
@@ -667,6 +684,7 @@ static const struct nla_policy
 nl80211_match_band_rssi_policy[NUM_NL80211_BANDS] = {
        [NL80211_BAND_2GHZ] = { .type = NLA_S32 },
        [NL80211_BAND_5GHZ] = { .type = NLA_S32 },
+       [NL80211_BAND_6GHZ] = { .type = NLA_S32 },
        [NL80211_BAND_60GHZ] = { .type = NLA_S32 },
 };
 
@@ -1563,6 +1581,15 @@ static int nl80211_send_band_rateinfo(struct sk_buff *msg,
                nla_nest_end(msg, nl_iftype_data);
        }
 
+       /* add EDMG info */
+       if (sband->edmg_cap.channels &&
+           (nla_put_u8(msg, NL80211_BAND_ATTR_EDMG_CHANNELS,
+                      sband->edmg_cap.channels) ||
+           nla_put_u8(msg, NL80211_BAND_ATTR_EDMG_BW_CONFIG,
+                      sband->edmg_cap.bw_config)))
+
+               return -ENOBUFS;
+
        /* add bitrates */
        nl_rates = nla_nest_start_noflag(msg, NL80211_BAND_ATTR_RATES);
        if (!nl_rates)
@@ -2666,6 +2693,18 @@ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
                                nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2]);
        }
 
+       if (info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]) {
+               chandef->edmg.channels =
+                     nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]);
+
+               if (info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG])
+                       chandef->edmg.bw_config =
+                    nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG]);
+       } else {
+               chandef->edmg.bw_config = 0;
+               chandef->edmg.channels = 0;
+       }
+
        if (!cfg80211_chandef_valid(chandef)) {
                NL_SET_ERR_MSG(extack, "invalid channel definition");
                return -EINVAL;
@@ -3528,9 +3567,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
                        return err;
        }
 
-       if (!(rdev->wiphy.interface_modes & (1 << type)) &&
-           !(type == NL80211_IFTYPE_AP_VLAN && params.use_4addr &&
-             rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP))
+       if (!cfg80211_iftype_allowed(&rdev->wiphy, type, params.use_4addr, 0))
                return -EOPNOTSUPP;
 
        err = nl80211_parse_mon_options(rdev, type, info, &params);
@@ -4405,6 +4442,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 +4754,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])
@@ -4987,6 +5060,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
 
        PUT_SINFO(CONNECTED_TIME, connected_time, u32);
        PUT_SINFO(INACTIVE_TIME, inactive_time, u32);
+       PUT_SINFO_U64(ASSOC_AT_BOOTTIME, assoc_at);
 
        if (sinfo->filled & (BIT_ULL(NL80211_STA_INFO_RX_BYTES) |
                             BIT_ULL(NL80211_STA_INFO_RX_BYTES64)) &&
@@ -9848,6 +9922,15 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
                        return -EINVAL;
        }
 
+       if (info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]) {
+               connect.edmg.channels =
+                     nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]);
+
+               if (info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG])
+                       connect.edmg.bw_config =
+                               nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG]);
+       }
+
        if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
                connkeys = nl80211_parse_connkeys(rdev, info, NULL);
                if (IS_ERR(connkeys))