cfg80211: remove enum ieee80211_band
[cascardo/linux.git] / net / wireless / nl80211.c
index 98c9242..13ef553 100644 (file)
@@ -402,6 +402,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
        [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
        [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
        [NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
+       [NL80211_ATTR_BSS_SELECT] = { .type = NLA_NESTED },
+       [NL80211_ATTR_STA_SUPPORT_P2P_PS] = { .type = NLA_U8 },
 };
 
 /* policy for the key attributes */
@@ -486,6 +488,15 @@ nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = {
        [NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 },
 };
 
+static const struct nla_policy
+nl80211_bss_select_policy[NL80211_BSS_SELECT_ATTR_MAX + 1] = {
+       [NL80211_BSS_SELECT_ATTR_RSSI] = { .type = NLA_FLAG },
+       [NL80211_BSS_SELECT_ATTR_BAND_PREF] = { .type = NLA_U32 },
+       [NL80211_BSS_SELECT_ATTR_RSSI_ADJUST] = {
+               .len = sizeof(struct nl80211_bss_select_rssi_adjust)
+       },
+};
+
 static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
                                     struct netlink_callback *cb,
                                     struct cfg80211_registered_device **rdev,
@@ -1266,7 +1277,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
        struct nlattr *nl_bands, *nl_band;
        struct nlattr *nl_freqs, *nl_freq;
        struct nlattr *nl_cmds;
-       enum ieee80211_band band;
+       enum nl80211_band band;
        struct ieee80211_channel *chan;
        int i;
        const struct ieee80211_txrx_stypes *mgmt_stypes =
@@ -1399,7 +1410,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                        goto nla_put_failure;
 
                for (band = state->band_start;
-                    band < IEEE80211_NUM_BANDS; band++) {
+                    band < NUM_NL80211_BANDS; band++) {
                        struct ieee80211_supported_band *sband;
 
                        sband = rdev->wiphy.bands[band];
@@ -1461,7 +1472,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                }
                nla_nest_end(msg, nl_bands);
 
-               if (band < IEEE80211_NUM_BANDS)
+               if (band < NUM_NL80211_BANDS)
                        state->band_start = band + 1;
                else
                        state->band_start = 0;
@@ -1731,6 +1742,25 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                            rdev->wiphy.ext_features))
                        goto nla_put_failure;
 
+               if (rdev->wiphy.bss_select_support) {
+                       struct nlattr *nested;
+                       u32 bss_select_support = rdev->wiphy.bss_select_support;
+
+                       nested = nla_nest_start(msg, NL80211_ATTR_BSS_SELECT);
+                       if (!nested)
+                               goto nla_put_failure;
+
+                       i = 0;
+                       while (bss_select_support) {
+                               if ((bss_select_support & 1) &&
+                                   nla_put_flag(msg, i))
+                                       goto nla_put_failure;
+                               i++;
+                               bss_select_support >>= 1;
+                       }
+                       nla_nest_end(msg, nested);
+               }
+
                /* done */
                state->split_start = 0;
                break;
@@ -3463,7 +3493,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        }
 
        params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
-       if (params.pbss && !rdev->wiphy.bands[IEEE80211_BAND_60GHZ])
+       if (params.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ])
                return -EOPNOTSUPP;
 
        wdev_lock(wdev);
@@ -3977,6 +4007,10 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
            statype != CFG80211_STA_AP_CLIENT_UNASSOC)
                return -EINVAL;
 
+       if (params->support_p2p_ps != -1 &&
+           statype != CFG80211_STA_AP_CLIENT_UNASSOC)
+               return -EINVAL;
+
        if (params->aid &&
            !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
            statype != CFG80211_STA_AP_CLIENT_UNASSOC)
@@ -4270,6 +4304,18 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
        else
                params.listen_interval = -1;
 
+       if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
+               u8 tmp;
+
+               tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
+               if (tmp >= NUM_NL80211_P2P_PS_STATUS)
+                       return -EINVAL;
+
+               params.support_p2p_ps = tmp;
+       } else {
+               params.support_p2p_ps = -1;
+       }
+
        if (!info->attrs[NL80211_ATTR_MAC])
                return -EINVAL;
 
@@ -4393,6 +4439,23 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
        params.listen_interval =
                nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
 
+       if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) {
+               u8 tmp;
+
+               tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);
+               if (tmp >= NUM_NL80211_P2P_PS_STATUS)
+                       return -EINVAL;
+
+               params.support_p2p_ps = tmp;
+       } else {
+               /*
+                * if not specified, assume it's supported for P2P GO interface,
+                * and is NOT supported for AP interface
+                */
+               params.support_p2p_ps =
+                       dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO;
+       }
+
        if (info->attrs[NL80211_ATTR_PEER_AID])
                params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
        else
@@ -5758,6 +5821,73 @@ static int validate_scan_freqs(struct nlattr *freqs)
        return n_channels;
 }
 
+static bool is_band_valid(struct wiphy *wiphy, enum nl80211_band b)
+{
+       return b < NUM_NL80211_BANDS && wiphy->bands[b];
+}
+
+static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy,
+                           struct cfg80211_bss_selection *bss_select)
+{
+       struct nlattr *attr[NL80211_BSS_SELECT_ATTR_MAX + 1];
+       struct nlattr *nest;
+       int err;
+       bool found = false;
+       int i;
+
+       /* only process one nested attribute */
+       nest = nla_data(nla);
+       if (!nla_ok(nest, nla_len(nest)))
+               return -EINVAL;
+
+       err = nla_parse(attr, NL80211_BSS_SELECT_ATTR_MAX, nla_data(nest),
+                       nla_len(nest), nl80211_bss_select_policy);
+       if (err)
+               return err;
+
+       /* only one attribute may be given */
+       for (i = 0; i <= NL80211_BSS_SELECT_ATTR_MAX; i++) {
+               if (attr[i]) {
+                       if (found)
+                               return -EINVAL;
+                       found = true;
+               }
+       }
+
+       bss_select->behaviour = __NL80211_BSS_SELECT_ATTR_INVALID;
+
+       if (attr[NL80211_BSS_SELECT_ATTR_RSSI])
+               bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI;
+
+       if (attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]) {
+               bss_select->behaviour = NL80211_BSS_SELECT_ATTR_BAND_PREF;
+               bss_select->param.band_pref =
+                       nla_get_u32(attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]);
+               if (!is_band_valid(wiphy, bss_select->param.band_pref))
+                       return -EINVAL;
+       }
+
+       if (attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]) {
+               struct nl80211_bss_select_rssi_adjust *adj_param;
+
+               adj_param = nla_data(attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]);
+               bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI_ADJUST;
+               bss_select->param.adjust.band = adj_param->band;
+               bss_select->param.adjust.delta = adj_param->delta;
+               if (!is_band_valid(wiphy, bss_select->param.adjust.band))
+                       return -EINVAL;
+       }
+
+       /* user-space did not provide behaviour attribute */
+       if (bss_select->behaviour == __NL80211_BSS_SELECT_ATTR_INVALID)
+               return -EINVAL;
+
+       if (!(wiphy->bss_select_support & BIT(bss_select->behaviour)))
+               return -EINVAL;
+
+       return 0;
+}
+
 static int nl80211_parse_random_mac(struct nlattr **attrs,
                                    u8 *mac_addr, u8 *mac_addr_mask)
 {
@@ -5888,10 +6018,10 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                        i++;
                }
        } else {
-               enum ieee80211_band band;
+               enum nl80211_band band;
 
                /* all channels */
-               for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               for (band = 0; band < NUM_NL80211_BANDS; band++) {
                        int j;
                        if (!wiphy->bands[band])
                                continue;
@@ -5936,7 +6066,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                       request->ie_len);
        }
 
-       for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+       for (i = 0; i < NUM_NL80211_BANDS; i++)
                if (wiphy->bands[i])
                        request->rates[i] =
                                (1 << wiphy->bands[i]->n_bitrates) - 1;
@@ -5945,9 +6075,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                nla_for_each_nested(attr,
                                    info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
                                    tmp) {
-                       enum ieee80211_band band = nla_type(attr);
+                       enum nl80211_band band = nla_type(attr);
 
-                       if (band < 0 || band >= IEEE80211_NUM_BANDS) {
+                       if (band < 0 || band >= NUM_NL80211_BANDS) {
                                err = -EINVAL;
                                goto out_free;
                        }
@@ -5996,6 +6126,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        request->no_cck =
                nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
 
+       if (info->attrs[NL80211_ATTR_MAC])
+               memcpy(request->bssid, nla_data(info->attrs[NL80211_ATTR_MAC]),
+                      ETH_ALEN);
+       else
+               eth_broadcast_addr(request->bssid);
+
        request->wdev = wdev;
        request->wiphy = &rdev->wiphy;
        request->scan_start = jiffies;
@@ -6129,7 +6265,7 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
        struct cfg80211_sched_scan_request *request;
        struct nlattr *attr;
        int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i, n_plans = 0;
-       enum ieee80211_band band;
+       enum nl80211_band band;
        size_t ie_len;
        struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
        s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
@@ -6294,7 +6430,7 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
                }
        } else {
                /* all channels */
-               for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               for (band = 0; band < NUM_NL80211_BANDS; band++) {
                        int j;
                        if (!wiphy->bands[band])
                                continue;
@@ -7402,14 +7538,14 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
 
 static bool
 nl80211_parse_mcast_rate(struct cfg80211_registered_device *rdev,
-                        int mcast_rate[IEEE80211_NUM_BANDS],
+                        int mcast_rate[NUM_NL80211_BANDS],
                         int rateval)
 {
        struct wiphy *wiphy = &rdev->wiphy;
        bool found = false;
        int band, i;
 
-       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+       for (band = 0; band < NUM_NL80211_BANDS; band++) {
                struct ieee80211_supported_band *sband;
 
                sband = wiphy->bands[band];
@@ -7589,7 +7725,7 @@ static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net_device *dev = info->user_ptr[1];
-       int mcast_rate[IEEE80211_NUM_BANDS];
+       int mcast_rate[NUM_NL80211_BANDS];
        u32 nla_rate;
        int err;
 
@@ -7922,6 +8058,10 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
                connect.mfp = NL80211_MFP_NO;
        }
 
+       if (info->attrs[NL80211_ATTR_PREV_BSSID])
+               connect.prev_bssid =
+                       nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
+
        if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
                connect.channel = nl80211_get_valid_chan(
                        wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ]);
@@ -7990,13 +8130,29 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
        }
 
        connect.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
-       if (connect.pbss && !rdev->wiphy.bands[IEEE80211_BAND_60GHZ]) {
+       if (connect.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
                kzfree(connkeys);
                return -EOPNOTSUPP;
        }
 
+       if (info->attrs[NL80211_ATTR_BSS_SELECT]) {
+               /* bss selection makes no sense if bssid is set */
+               if (connect.bssid) {
+                       kzfree(connkeys);
+                       return -EINVAL;
+               }
+
+               err = parse_bss_select(info->attrs[NL80211_ATTR_BSS_SELECT],
+                                      wiphy, &connect.bss_select);
+               if (err) {
+                       kzfree(connkeys);
+                       return err;
+               }
+       }
+
        wdev_lock(dev->ieee80211_ptr);
-       err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL);
+       err = cfg80211_connect(rdev, dev, &connect, connkeys,
+                              connect.prev_bssid);
        wdev_unlock(dev->ieee80211_ptr);
        if (err)
                kzfree(connkeys);
@@ -8394,7 +8550,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
 
        memset(&mask, 0, sizeof(mask));
        /* Default to all rates enabled */
-       for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
+       for (i = 0; i < NUM_NL80211_BANDS; i++) {
                sband = rdev->wiphy.bands[i];
 
                if (!sband)
@@ -8418,14 +8574,14 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
 
        /*
         * The nested attribute uses enum nl80211_band as the index. This maps
-        * directly to the enum ieee80211_band values used in cfg80211.
+        * directly to the enum nl80211_band values used in cfg80211.
         */
        BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
        nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
-               enum ieee80211_band band = nla_type(tx_rates);
+               enum nl80211_band band = nla_type(tx_rates);
                int err;
 
-               if (band < 0 || band >= IEEE80211_NUM_BANDS)
+               if (band < 0 || band >= NUM_NL80211_BANDS)
                        return -EINVAL;
                sband = rdev->wiphy.bands[band];
                if (sband == NULL)
@@ -10590,7 +10746,7 @@ static int nl80211_tdls_channel_switch(struct sk_buff *skb,
         * section 10.22.6.2.1. Disallow 5/10Mhz channels as well for now, the
         * specification is not defined for them.
         */
-       if (chandef.chan->band == IEEE80211_BAND_2GHZ &&
+       if (chandef.chan->band == NL80211_BAND_2GHZ &&
            chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
            chandef.width != NL80211_CHAN_WIDTH_20)
                return -EINVAL;