Merge tag 'mac80211-for-davem-2018-09-03' of git://git.kernel.org/pub/scm/linux/kerne...
[linux-block.git] / net / wireless / nl80211.c
index 733ccf8679728d091d0aeacc3aada4abc8318d12..4b8ec659e797ff743267773e315c6220b90993d0 100644 (file)
@@ -428,6 +428,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
        [NL80211_ATTR_TXQ_LIMIT] = { .type = NLA_U32 },
        [NL80211_ATTR_TXQ_MEMORY_LIMIT] = { .type = NLA_U32 },
        [NL80211_ATTR_TXQ_QUANTUM] = { .type = NLA_U32 },
+       [NL80211_ATTR_HE_CAPABILITY] = { .type = NLA_BINARY,
+                                        .len = NL80211_HE_MAX_CAPABILITY_LEN },
 };
 
 /* policy for the key attributes */
@@ -1324,6 +1326,34 @@ static int nl80211_send_coalesce(struct sk_buff *msg,
        return 0;
 }
 
+static int
+nl80211_send_iftype_data(struct sk_buff *msg,
+                        const struct ieee80211_sband_iftype_data *iftdata)
+{
+       const struct ieee80211_sta_he_cap *he_cap = &iftdata->he_cap;
+
+       if (nl80211_put_iftypes(msg, NL80211_BAND_IFTYPE_ATTR_IFTYPES,
+                               iftdata->types_mask))
+               return -ENOBUFS;
+
+       if (he_cap->has_he) {
+               if (nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC,
+                           sizeof(he_cap->he_cap_elem.mac_cap_info),
+                           he_cap->he_cap_elem.mac_cap_info) ||
+                   nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
+                           sizeof(he_cap->he_cap_elem.phy_cap_info),
+                           he_cap->he_cap_elem.phy_cap_info) ||
+                   nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
+                           sizeof(he_cap->he_mcs_nss_supp),
+                           &he_cap->he_mcs_nss_supp) ||
+                   nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
+                           sizeof(he_cap->ppe_thres), he_cap->ppe_thres))
+                       return -ENOBUFS;
+       }
+
+       return 0;
+}
+
 static int nl80211_send_band_rateinfo(struct sk_buff *msg,
                                      struct ieee80211_supported_band *sband)
 {
@@ -1353,6 +1383,32 @@ static int nl80211_send_band_rateinfo(struct sk_buff *msg,
                         sband->vht_cap.cap)))
                return -ENOBUFS;
 
+       if (sband->n_iftype_data) {
+               struct nlattr *nl_iftype_data =
+                       nla_nest_start(msg, NL80211_BAND_ATTR_IFTYPE_DATA);
+               int err;
+
+               if (!nl_iftype_data)
+                       return -ENOBUFS;
+
+               for (i = 0; i < sband->n_iftype_data; i++) {
+                       struct nlattr *iftdata;
+
+                       iftdata = nla_nest_start(msg, i + 1);
+                       if (!iftdata)
+                               return -ENOBUFS;
+
+                       err = nl80211_send_iftype_data(msg,
+                                                      &sband->iftype_data[i]);
+                       if (err)
+                               return err;
+
+                       nla_nest_end(msg, iftdata);
+               }
+
+               nla_nest_end(msg, nl_iftype_data);
+       }
+
        /* add bitrates */
        nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
        if (!nl_rates)
@@ -2757,7 +2813,8 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
            nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address(wdev)) ||
            nla_put_u32(msg, NL80211_ATTR_GENERATION,
                        rdev->devlist_generation ^
-                       (cfg80211_rdev_list_generation << 2)))
+                       (cfg80211_rdev_list_generation << 2)) ||
+           nla_put_u8(msg, NL80211_ATTR_4ADDR, wdev->use_4addr))
                goto nla_put_failure;
 
        if (rdev->ops->get_channel) {
@@ -4472,6 +4529,9 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
        case RATE_INFO_BW_160:
                rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
                break;
+       case RATE_INFO_BW_HE_RU:
+               rate_flg = 0;
+               WARN_ON(!(info->flags & RATE_INFO_FLAGS_HE_MCS));
        }
 
        if (rate_flg && nla_put_flag(msg, rate_flg))
@@ -4491,6 +4551,19 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
                if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
                    nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
                        return false;
+       } else if (info->flags & RATE_INFO_FLAGS_HE_MCS) {
+               if (nla_put_u8(msg, NL80211_RATE_INFO_HE_MCS, info->mcs))
+                       return false;
+               if (nla_put_u8(msg, NL80211_RATE_INFO_HE_NSS, info->nss))
+                       return false;
+               if (nla_put_u8(msg, NL80211_RATE_INFO_HE_GI, info->he_gi))
+                       return false;
+               if (nla_put_u8(msg, NL80211_RATE_INFO_HE_DCM, info->he_dcm))
+                       return false;
+               if (info->bw == RATE_INFO_BW_HE_RU &&
+                   nla_put_u8(msg, NL80211_RATE_INFO_HE_RU_ALLOC,
+                              info->he_ru_alloc))
+                       return false;
        }
 
        nla_nest_end(msg, rate);
@@ -4547,13 +4620,13 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
 
 #define PUT_SINFO(attr, memb, type) do {                               \
        BUILD_BUG_ON(sizeof(type) == sizeof(u64));                      \
-       if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) &&      \
+       if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_ ## attr) &&       \
            nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr,            \
                             sinfo->memb))                              \
                goto nla_put_failure;                                   \
        } while (0)
 #define PUT_SINFO_U64(attr, memb) do {                                 \
-       if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) &&      \
+       if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_ ## attr) &&       \
            nla_put_u64_64bit(msg, NL80211_STA_INFO_ ## attr,           \
                              sinfo->memb, NL80211_STA_INFO_PAD))       \
                goto nla_put_failure;                                   \
@@ -4562,14 +4635,14 @@ 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);
 
-       if (sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES) |
-                            BIT(NL80211_STA_INFO_RX_BYTES64)) &&
+       if (sinfo->filled & (BIT_ULL(NL80211_STA_INFO_RX_BYTES) |
+                            BIT_ULL(NL80211_STA_INFO_RX_BYTES64)) &&
            nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
                        (u32)sinfo->rx_bytes))
                goto nla_put_failure;
 
-       if (sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES) |
-                            BIT(NL80211_STA_INFO_TX_BYTES64)) &&
+       if (sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES) |
+                            BIT_ULL(NL80211_STA_INFO_TX_BYTES64)) &&
            nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
                        (u32)sinfo->tx_bytes))
                goto nla_put_failure;
@@ -4589,24 +4662,24 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
        default:
                break;
        }
-       if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL)) {
+       if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) {
                if (!nl80211_put_signal(msg, sinfo->chains,
                                        sinfo->chain_signal,
                                        NL80211_STA_INFO_CHAIN_SIGNAL))
                        goto nla_put_failure;
        }
-       if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
+       if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
                if (!nl80211_put_signal(msg, sinfo->chains,
                                        sinfo->chain_signal_avg,
                                        NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
                        goto nla_put_failure;
        }
-       if (sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
+       if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)) {
                if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
                                          NL80211_STA_INFO_TX_BITRATE))
                        goto nla_put_failure;
        }
-       if (sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE)) {
+       if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) {
                if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
                                          NL80211_STA_INFO_RX_BITRATE))
                        goto nla_put_failure;
@@ -4622,7 +4695,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
        PUT_SINFO(PEER_PM, peer_pm, u32);
        PUT_SINFO(NONPEER_PM, nonpeer_pm, u32);
 
-       if (sinfo->filled & BIT(NL80211_STA_INFO_BSS_PARAM)) {
+       if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_BSS_PARAM)) {
                bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
                if (!bss_param)
                        goto nla_put_failure;
@@ -4641,7 +4714,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
 
                nla_nest_end(msg, bss_param);
        }
-       if ((sinfo->filled & BIT(NL80211_STA_INFO_STA_FLAGS)) &&
+       if ((sinfo->filled & BIT_ULL(NL80211_STA_INFO_STA_FLAGS)) &&
            nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
                    sizeof(struct nl80211_sta_flag_update),
                    &sinfo->sta_flags))
@@ -4887,7 +4960,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
                        return -EINVAL;
                if (params->supported_rates)
                        return -EINVAL;
-               if (params->ext_capab || params->ht_capa || params->vht_capa)
+               if (params->ext_capab || params->ht_capa || params->vht_capa ||
+                   params->he_capa)
                        return -EINVAL;
        }
 
@@ -5093,6 +5167,15 @@ static int nl80211_set_station_tdls(struct genl_info *info,
        if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
                params->vht_capa =
                        nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
+       if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) {
+               params->he_capa =
+                       nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
+               params->he_capa_len =
+                       nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
+
+               if (params->he_capa_len < NL80211_HE_MIN_CAPABILITY_LEN)
+                       return -EINVAL;
+       }
 
        err = nl80211_parse_sta_channel_info(info, params);
        if (err)
@@ -5320,6 +5403,17 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                params.vht_capa =
                        nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
 
+       if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) {
+               params.he_capa =
+                       nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
+               params.he_capa_len =
+                       nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
+
+               /* max len is validated in nla policy */
+               if (params.he_capa_len < NL80211_HE_MIN_CAPABILITY_LEN)
+                       return -EINVAL;
+       }
+
        if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
                params.opmode_notif_used = true;
                params.opmode_notif =
@@ -5352,6 +5446,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
        if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
                params.ht_capa = NULL;
                params.vht_capa = NULL;
+
+               /* HE requires WME */
+               if (params.he_capa_len)
+                       return -EINVAL;
        }
 
        /* When you run into this, adjust the code below for the new flag */
@@ -6849,6 +6947,16 @@ static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev)
        return regulatory_pre_cac_allowed(wdev->wiphy);
 }
 
+static bool nl80211_check_scan_feat(struct wiphy *wiphy, u32 flags, u32 flag,
+                                   enum nl80211_ext_feature_index feat)
+{
+       if (!(flags & flag))
+               return true;
+       if (wiphy_ext_feature_isset(wiphy, feat))
+               return true;
+       return false;
+}
+
 static int
 nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
                         void *request, struct nlattr **attrs,
@@ -6883,15 +6991,33 @@ nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
 
        if (((*flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
             !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
-           ((*flags & NL80211_SCAN_FLAG_LOW_SPAN) &&
-            !wiphy_ext_feature_isset(wiphy,
-                                     NL80211_EXT_FEATURE_LOW_SPAN_SCAN)) ||
-           ((*flags & NL80211_SCAN_FLAG_LOW_POWER) &&
-            !wiphy_ext_feature_isset(wiphy,
-                                     NL80211_EXT_FEATURE_LOW_POWER_SCAN)) ||
-           ((*flags & NL80211_SCAN_FLAG_HIGH_ACCURACY) &&
-            !wiphy_ext_feature_isset(wiphy,
-                                     NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN)))
+           !nl80211_check_scan_feat(wiphy, *flags,
+                                    NL80211_SCAN_FLAG_LOW_SPAN,
+                                    NL80211_EXT_FEATURE_LOW_SPAN_SCAN) ||
+           !nl80211_check_scan_feat(wiphy, *flags,
+                                    NL80211_SCAN_FLAG_LOW_POWER,
+                                    NL80211_EXT_FEATURE_LOW_POWER_SCAN) ||
+           !nl80211_check_scan_feat(wiphy, *flags,
+                                    NL80211_SCAN_FLAG_HIGH_ACCURACY,
+                                    NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN) ||
+           !nl80211_check_scan_feat(wiphy, *flags,
+                                    NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME,
+                                    NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME) ||
+           !nl80211_check_scan_feat(wiphy, *flags,
+                                    NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP,
+                                    NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP) ||
+           !nl80211_check_scan_feat(wiphy, *flags,
+                                    NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION,
+                                    NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION) ||
+           !nl80211_check_scan_feat(wiphy, *flags,
+                                    NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE,
+                                    NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE) ||
+           !nl80211_check_scan_feat(wiphy, *flags,
+                                    NL80211_SCAN_FLAG_RANDOM_SN,
+                                    NL80211_EXT_FEATURE_SCAN_RANDOM_SN) ||
+           !nl80211_check_scan_feat(wiphy, *flags,
+                                    NL80211_SCAN_FLAG_MIN_PREQ_CONTENT,
+                                    NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT))
                return -EOPNOTSUPP;
 
        if (*flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
@@ -6906,26 +7032,6 @@ nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
                        return err;
        }
 
-       if ((*flags & NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME) &&
-           !wiphy_ext_feature_isset(wiphy,
-                                    NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME))
-               return -EOPNOTSUPP;
-
-       if ((*flags & NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP) &&
-          !wiphy_ext_feature_isset(wiphy,
-                                   NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP))
-               return -EOPNOTSUPP;
-
-       if ((*flags & NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION) &&
-           !wiphy_ext_feature_isset(wiphy,
-                                    NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION))
-               return -EOPNOTSUPP;
-
-       if ((*flags & NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE) &&
-           !wiphy_ext_feature_isset(wiphy,
-                                    NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE))
-               return -EOPNOTSUPP;
-
        return 0;
 }
 
@@ -10148,7 +10254,7 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
                if (err)
                        return err;
 
-               if (sinfo.filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
+               if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
                        wdev->cqm_config->last_rssi_event_value =
                                (s8) sinfo.rx_beacon_signal_avg;
        }