Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac802...
[linux-drm-fsl-dcu.git] / net / wireless / nl80211.c
index a1eb21073176115a587f9eb1edf5d36dba582484..efaa23e562b4501045d314bcda149ece0e352a07 100644 (file)
@@ -564,12 +564,12 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
        if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
            nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
                goto nla_put_failure;
-       if ((chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
-           nla_put_flag(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN))
-               goto nla_put_failure;
-       if ((chan->flags & IEEE80211_CHAN_NO_IBSS) &&
-           nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS))
-               goto nla_put_failure;
+       if (chan->flags & IEEE80211_CHAN_NO_IR) {
+               if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR))
+                       goto nla_put_failure;
+               if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS))
+                       goto nla_put_failure;
+       }
        if (chan->flags & IEEE80211_CHAN_RADAR) {
                if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
                        goto nla_put_failure;
@@ -1247,10 +1247,6 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
                    nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
                        goto nla_put_failure;
-               if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
-                   nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ))
-                       goto nla_put_failure;
-
                state->split_start++;
                if (state->split)
                        break;
@@ -1579,6 +1575,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                if (nl80211_send_coalesce(msg, dev))
                        goto nla_put_failure;
 
+               if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
+                   (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
+                    nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
+                       goto nla_put_failure;
+
                /* done */
                state->split_start = 0;
                break;
@@ -2187,7 +2188,7 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
 }
 
 static int nl80211_send_chandef(struct sk_buff *msg,
-                                struct cfg80211_chan_def *chandef)
+                               const struct cfg80211_chan_def *chandef)
 {
        WARN_ON(!cfg80211_chandef_valid(chandef));
 
@@ -3236,6 +3237,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
                        return PTR_ERR(params.acl);
        }
 
+       wdev_lock(wdev);
        err = rdev_start_ap(rdev, dev, &params);
        if (!err) {
                wdev->preset_chandef = params.chandef;
@@ -3244,6 +3246,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
                wdev->ssid_len = params.ssid_len;
                memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
        }
+       wdev_unlock(wdev);
 
        kfree(params.acl);
 
@@ -3272,7 +3275,11 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
        if (err)
                return err;
 
-       return rdev_change_beacon(rdev, dev, &params);
+       wdev_lock(wdev);
+       err = rdev_change_beacon(rdev, dev, &params);
+       wdev_unlock(wdev);
+
+       return err;
 }
 
 static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
@@ -4478,7 +4485,9 @@ static int nl80211_set_bss(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];
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct bss_parameters params;
+       int err;
 
        memset(&params, 0, sizeof(params));
        /* default to not changing parameters */
@@ -4544,7 +4553,11 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
                return -EOPNOTSUPP;
 
-       return rdev_change_bss(rdev, dev, &params);
+       wdev_lock(wdev);
+       err = rdev_change_bss(rdev, dev, &params);
+       wdev_unlock(wdev);
+
+       return err;
 }
 
 static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
@@ -5098,7 +5111,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
        char *alpha2 = NULL;
        int rem_reg_rules = 0, r = 0;
        u32 num_rules = 0, rule_idx = 0, size_of_regd;
-       u8 dfs_region = 0;
+       enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
        struct ieee80211_regdomain *rd = NULL;
 
        if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
@@ -5119,6 +5132,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
                        return -EINVAL;
        }
 
+       if (!reg_is_valid_request(alpha2))
+               return -EINVAL;
+
        size_of_regd = sizeof(struct ieee80211_regdomain) +
                       num_rules * sizeof(struct ieee80211_reg_rule);
 
@@ -5361,10 +5377,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
                request->flags = nla_get_u32(
                        info->attrs[NL80211_ATTR_SCAN_FLAGS]);
-               if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
-                    !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
-                   ((request->flags & NL80211_SCAN_FLAG_FLUSH) &&
-                    !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) {
+               if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
+                   !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
                        err = -EOPNOTSUPP;
                        goto out_free;
                }
@@ -5604,10 +5618,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
        if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
                request->flags = nla_get_u32(
                        info->attrs[NL80211_ATTR_SCAN_FLAGS]);
-               if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
-                    !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
-                   ((request->flags & NL80211_SCAN_FLAG_FLUSH) &&
-                    !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) {
+               if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
+                   !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
                        err = -EOPNOTSUPP;
                        goto out_free;
                }
@@ -5670,7 +5682,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
        if (err == 0)
                return -EINVAL;
 
-       if (chandef.chan->dfs_state != NL80211_DFS_USABLE)
+       if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef))
                return -EINVAL;
 
        if (!rdev->ops->start_radar_detection)
@@ -5810,7 +5822,11 @@ skip_beacons:
        if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
                params.block_tx = true;
 
-       return rdev_channel_switch(rdev, dev, &params);
+       wdev_lock(wdev);
+       err = rdev_channel_switch(rdev, dev, &params);
+       wdev_unlock(wdev);
+
+       return err;
 }
 
 static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
@@ -7443,10 +7459,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        void *hdr = NULL;
        u64 cookie;
        struct sk_buff *msg = NULL;
-       unsigned int wait = 0;
-       bool offchan, no_cck, dont_wait_for_ack;
-
-       dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK];
+       struct cfg80211_mgmt_tx_params params = {
+               .dont_wait_for_ack =
+                       info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK],
+       };
 
        if (!info->attrs[NL80211_ATTR_FRAME])
                return -EINVAL;
@@ -7473,24 +7489,24 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_DURATION]) {
                if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
                        return -EINVAL;
-               wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
+               params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
 
                /*
                 * We should wait on the channel for at least a minimum amount
                 * of time (10ms) but no longer than the driver supports.
                 */
-               if (wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
-                   wait > rdev->wiphy.max_remain_on_channel_duration)
+               if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
+                   params.wait > rdev->wiphy.max_remain_on_channel_duration)
                        return -EINVAL;
 
        }
 
-       offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
+       params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
 
-       if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
+       if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
                return -EINVAL;
 
-       no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
+       params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
 
        /* get the channel if any has been specified, otherwise pass NULL to
         * the driver. The latter will use the current one
@@ -7502,10 +7518,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
                        return err;
        }
 
-       if (!chandef.chan && offchan)
+       if (!chandef.chan && params.offchan)
                return -EINVAL;
 
-       if (!dont_wait_for_ack) {
+       if (!params.dont_wait_for_ack) {
                msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
                if (!msg)
                        return -ENOMEM;
@@ -7518,10 +7534,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
-       err = cfg80211_mlme_mgmt_tx(rdev, wdev, chandef.chan, offchan, wait,
-                                   nla_data(info->attrs[NL80211_ATTR_FRAME]),
-                                   nla_len(info->attrs[NL80211_ATTR_FRAME]),
-                                   no_cck, dont_wait_for_ack, &cookie);
+       params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
+       params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
+       params.chan = chandef.chan;
+       err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie);
        if (err)
                goto free_msg;
 
@@ -10805,21 +10821,18 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
-       trace_cfg80211_ch_switch_notify(dev, chandef);
+       ASSERT_WDEV_LOCK(wdev);
 
-       wdev_lock(wdev);
+       trace_cfg80211_ch_switch_notify(dev, chandef);
 
        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
                    wdev->iftype != NL80211_IFTYPE_P2P_GO &&
                    wdev->iftype != NL80211_IFTYPE_ADHOC &&
                    wdev->iftype != NL80211_IFTYPE_MESH_POINT))
-               goto out;
+               return;
 
        wdev->channel = chandef->chan;
        nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
-out:
-       wdev_unlock(wdev);
-       return;
 }
 EXPORT_SYMBOL(cfg80211_ch_switch_notify);
 
@@ -10878,7 +10891,7 @@ EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
 
 void
 nl80211_radar_notify(struct cfg80211_registered_device *rdev,
-                    struct cfg80211_chan_def *chandef,
+                    const struct cfg80211_chan_def *chandef,
                     enum nl80211_radar_event event,
                     struct net_device *netdev, gfp_t gfp)
 {