These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / wireless / nl80211.c
index dd78445..75b0d23 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
+ * Copyright 2015      Intel Deutschland GmbH
  */
 
 #include <linux/if.h>
@@ -478,6 +479,12 @@ nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
        [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
 };
 
+static const struct nla_policy
+nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = {
+       [NL80211_SCHED_SCAN_PLAN_INTERVAL] = { .type = NLA_U32 },
+       [NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 },
+};
+
 static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
                                     struct netlink_callback *cb,
                                     struct cfg80211_registered_device **rdev,
@@ -639,8 +646,8 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
                if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) &&
                    nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY))
                        goto nla_put_failure;
-               if ((chan->flags & IEEE80211_CHAN_GO_CONCURRENT) &&
-                   nla_put_flag(msg, NL80211_FREQUENCY_ATTR_GO_CONCURRENT))
+               if ((chan->flags & IEEE80211_CHAN_IR_CONCURRENT) &&
+                   nla_put_flag(msg, NL80211_FREQUENCY_ATTR_IR_CONCURRENT))
                        goto nla_put_failure;
                if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
                    nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
@@ -1303,7 +1310,13 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                    nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
                                rdev->wiphy.max_sched_scan_ie_len) ||
                    nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
-                              rdev->wiphy.max_match_sets))
+                              rdev->wiphy.max_match_sets) ||
+                   nla_put_u32(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
+                               rdev->wiphy.max_sched_scan_plans) ||
+                   nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
+                               rdev->wiphy.max_sched_scan_plan_interval) ||
+                   nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
+                               rdev->wiphy.max_sched_scan_plan_iterations))
                        goto nla_put_failure;
 
                if ((rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
@@ -2003,7 +2016,8 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
        switch (iftype) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_P2P_GO:
-               if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) {
+               if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
+                                                  iftype)) {
                        result = -EINVAL;
                        break;
                }
@@ -2320,6 +2334,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                        rdev->wiphy.frag_threshold = old_frag_threshold;
                        rdev->wiphy.rts_threshold = old_rts_threshold;
                        rdev->wiphy.coverage_class = old_coverage_class;
+                       return result;
                }
        }
        return 0;
@@ -2401,6 +2416,16 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
                }
        }
 
+       if (rdev->ops->get_tx_power) {
+               int dbm, ret;
+
+               ret = rdev_get_tx_power(rdev, wdev, &dbm);
+               if (ret == 0 &&
+                   nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
+                               DBM_TO_MBM(dbm)))
+                       goto nla_put_failure;
+       }
+
        if (wdev->ssid_len) {
                if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
                        goto nla_put_failure;
@@ -3403,16 +3428,10 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        } else if (!nl80211_get_ap_channel(rdev, &params))
                return -EINVAL;
 
-       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
-                                    wdev->iftype))
+       if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
+                                          wdev->iftype))
                return -EINVAL;
 
-       if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
-               params.acl = parse_acl_data(&rdev->wiphy, info);
-               if (IS_ERR(params.acl))
-                       return PTR_ERR(params.acl);
-       }
-
        if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
                params.smps_mode =
                        nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
@@ -3436,6 +3455,12 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
                params.smps_mode = NL80211_SMPS_OFF;
        }
 
+       if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
+               params.acl = parse_acl_data(&rdev->wiphy, info);
+               if (IS_ERR(params.acl))
+                       return PTR_ERR(params.acl);
+       }
+
        wdev_lock(wdev);
        err = rdev_start_ap(rdev, dev, &params);
        if (!err) {
@@ -3943,10 +3968,13 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
                                  struct station_parameters *params,
                                  enum cfg80211_station_type statype)
 {
-       if (params->listen_interval != -1)
+       if (params->listen_interval != -1 &&
+           statype != CFG80211_STA_AP_CLIENT_UNASSOC)
                return -EINVAL;
+
        if (params->aid &&
-           !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
+           !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
+           statype != CFG80211_STA_AP_CLIENT_UNASSOC)
                return -EINVAL;
 
        /* When you run into this, adjust the code below for the new flag */
@@ -3996,7 +4024,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
                params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
        }
 
-       if (statype != CFG80211_STA_TDLS_PEER_SETUP) {
+       if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
+           statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
                /* reject other things that can't change */
                if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
                        return -EINVAL;
@@ -4008,7 +4037,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
                        return -EINVAL;
        }
 
-       if (statype != CFG80211_STA_AP_CLIENT) {
+       if (statype != CFG80211_STA_AP_CLIENT &&
+           statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
                if (params->vlan)
                        return -EINVAL;
        }
@@ -4020,6 +4050,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
                        return -EOPNOTSUPP;
                break;
        case CFG80211_STA_AP_CLIENT:
+       case CFG80211_STA_AP_CLIENT_UNASSOC:
                /* accept only the listed bits */
                if (params->sta_flags_mask &
                                ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
@@ -4061,7 +4092,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
                        return -EINVAL;
                break;
        case CFG80211_STA_MESH_PEER_USER:
-               if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
+               if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION &&
+                   params->plink_action != NL80211_PLINK_ACTION_BLOCK)
                        return -EINVAL;
                break;
        }
@@ -4216,13 +4248,22 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
 
        memset(&params, 0, sizeof(params));
 
-       params.listen_interval = -1;
-
        if (!rdev->ops->change_station)
                return -EOPNOTSUPP;
 
-       if (info->attrs[NL80211_ATTR_STA_AID])
-               return -EINVAL;
+       /*
+        * AID and listen_interval properties can be set only for unassociated
+        * station. Include these parameters here and will check them in
+        * cfg80211_check_station_change().
+        */
+       if (info->attrs[NL80211_ATTR_PEER_AID])
+               params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
+
+       if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
+               params.listen_interval =
+                    nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
+       else
+               params.listen_interval = -1;
 
        if (!info->attrs[NL80211_ATTR_MAC])
                return -EINVAL;
@@ -4249,9 +4290,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
                        nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
        }
 
-       if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
-               return -EINVAL;
-
        if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
                return -EINVAL;
 
@@ -4915,56 +4953,6 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
        return err;
 }
 
-static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
-       [NL80211_ATTR_REG_RULE_FLAGS]           = { .type = NLA_U32 },
-       [NL80211_ATTR_FREQ_RANGE_START]         = { .type = NLA_U32 },
-       [NL80211_ATTR_FREQ_RANGE_END]           = { .type = NLA_U32 },
-       [NL80211_ATTR_FREQ_RANGE_MAX_BW]        = { .type = NLA_U32 },
-       [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]  = { .type = NLA_U32 },
-       [NL80211_ATTR_POWER_RULE_MAX_EIRP]      = { .type = NLA_U32 },
-       [NL80211_ATTR_DFS_CAC_TIME]             = { .type = NLA_U32 },
-};
-
-static int parse_reg_rule(struct nlattr *tb[],
-       struct ieee80211_reg_rule *reg_rule)
-{
-       struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
-       struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
-
-       if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
-               return -EINVAL;
-       if (!tb[NL80211_ATTR_FREQ_RANGE_START])
-               return -EINVAL;
-       if (!tb[NL80211_ATTR_FREQ_RANGE_END])
-               return -EINVAL;
-       if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
-               return -EINVAL;
-       if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
-               return -EINVAL;
-
-       reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
-
-       freq_range->start_freq_khz =
-               nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
-       freq_range->end_freq_khz =
-               nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
-       freq_range->max_bandwidth_khz =
-               nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
-
-       power_rule->max_eirp =
-               nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
-
-       if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
-               power_rule->max_antenna_gain =
-                       nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
-
-       if (tb[NL80211_ATTR_DFS_CAC_TIME])
-               reg_rule->dfs_cac_ms =
-                       nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
-
-       return 0;
-}
-
 static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
 {
        char *data = NULL;
@@ -5596,6 +5584,57 @@ out_err:
        return err;
 }
 
+#ifdef CONFIG_CFG80211_CRDA_SUPPORT
+static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
+       [NL80211_ATTR_REG_RULE_FLAGS]           = { .type = NLA_U32 },
+       [NL80211_ATTR_FREQ_RANGE_START]         = { .type = NLA_U32 },
+       [NL80211_ATTR_FREQ_RANGE_END]           = { .type = NLA_U32 },
+       [NL80211_ATTR_FREQ_RANGE_MAX_BW]        = { .type = NLA_U32 },
+       [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]  = { .type = NLA_U32 },
+       [NL80211_ATTR_POWER_RULE_MAX_EIRP]      = { .type = NLA_U32 },
+       [NL80211_ATTR_DFS_CAC_TIME]             = { .type = NLA_U32 },
+};
+
+static int parse_reg_rule(struct nlattr *tb[],
+       struct ieee80211_reg_rule *reg_rule)
+{
+       struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
+       struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
+
+       if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
+               return -EINVAL;
+       if (!tb[NL80211_ATTR_FREQ_RANGE_START])
+               return -EINVAL;
+       if (!tb[NL80211_ATTR_FREQ_RANGE_END])
+               return -EINVAL;
+       if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
+               return -EINVAL;
+       if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
+               return -EINVAL;
+
+       reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
+
+       freq_range->start_freq_khz =
+               nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
+       freq_range->end_freq_khz =
+               nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
+       freq_range->max_bandwidth_khz =
+               nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
+
+       power_rule->max_eirp =
+               nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
+
+       if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
+               power_rule->max_antenna_gain =
+                       nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
+
+       if (tb[NL80211_ATTR_DFS_CAC_TIME])
+               reg_rule->dfs_cac_ms =
+                       nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
+
+       return 0;
+}
+
 static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
@@ -5672,6 +5711,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
        kfree(rd);
        return r;
 }
+#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
 
 static int validate_scan_freqs(struct nlattr *freqs)
 {
@@ -5957,14 +5997,100 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        return err;
 }
 
+static int
+nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
+                              struct cfg80211_sched_scan_request *request,
+                              struct nlattr **attrs)
+{
+       int tmp, err, i = 0;
+       struct nlattr *attr;
+
+       if (!attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
+               u32 interval;
+
+               /*
+                * If scan plans are not specified,
+                * %NL80211_ATTR_SCHED_SCAN_INTERVAL must be specified. In this
+                * case one scan plan will be set with the specified scan
+                * interval and infinite number of iterations.
+                */
+               if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
+                       return -EINVAL;
+
+               interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
+               if (!interval)
+                       return -EINVAL;
+
+               request->scan_plans[0].interval =
+                       DIV_ROUND_UP(interval, MSEC_PER_SEC);
+               if (!request->scan_plans[0].interval)
+                       return -EINVAL;
+
+               if (request->scan_plans[0].interval >
+                   wiphy->max_sched_scan_plan_interval)
+                       request->scan_plans[0].interval =
+                               wiphy->max_sched_scan_plan_interval;
+
+               return 0;
+       }
+
+       nla_for_each_nested(attr, attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp) {
+               struct nlattr *plan[NL80211_SCHED_SCAN_PLAN_MAX + 1];
+
+               if (WARN_ON(i >= n_plans))
+                       return -EINVAL;
+
+               err = nla_parse(plan, NL80211_SCHED_SCAN_PLAN_MAX,
+                               nla_data(attr), nla_len(attr),
+                               nl80211_plan_policy);
+               if (err)
+                       return err;
+
+               if (!plan[NL80211_SCHED_SCAN_PLAN_INTERVAL])
+                       return -EINVAL;
+
+               request->scan_plans[i].interval =
+                       nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_INTERVAL]);
+               if (!request->scan_plans[i].interval ||
+                   request->scan_plans[i].interval >
+                   wiphy->max_sched_scan_plan_interval)
+                       return -EINVAL;
+
+               if (plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]) {
+                       request->scan_plans[i].iterations =
+                               nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]);
+                       if (!request->scan_plans[i].iterations ||
+                           (request->scan_plans[i].iterations >
+                            wiphy->max_sched_scan_plan_iterations))
+                               return -EINVAL;
+               } else if (i < n_plans - 1) {
+                       /*
+                        * All scan plans but the last one must specify
+                        * a finite number of iterations
+                        */
+                       return -EINVAL;
+               }
+
+               i++;
+       }
+
+       /*
+        * The last scan plan must not specify the number of
+        * iterations, it is supposed to run infinitely
+        */
+       if (request->scan_plans[n_plans - 1].iterations)
+               return  -EINVAL;
+
+       return 0;
+}
+
 static struct cfg80211_sched_scan_request *
 nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
                         struct nlattr **attrs)
 {
        struct cfg80211_sched_scan_request *request;
        struct nlattr *attr;
-       int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i;
-       u32 interval;
+       int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i, n_plans = 0;
        enum ieee80211_band band;
        size_t ie_len;
        struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
@@ -5973,13 +6099,6 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
        if (!is_valid_ie_attr(attrs[NL80211_ATTR_IE]))
                return ERR_PTR(-EINVAL);
 
-       if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
-               return ERR_PTR(-EINVAL);
-
-       interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
-       if (interval == 0)
-               return ERR_PTR(-EINVAL);
-
        if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
                n_channels = validate_scan_freqs(
                                attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
@@ -6043,9 +6162,37 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
        if (ie_len > wiphy->max_sched_scan_ie_len)
                return ERR_PTR(-EINVAL);
 
+       if (attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
+               /*
+                * NL80211_ATTR_SCHED_SCAN_INTERVAL must not be specified since
+                * each scan plan already specifies its own interval
+                */
+               if (attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
+                       return ERR_PTR(-EINVAL);
+
+               nla_for_each_nested(attr,
+                                   attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp)
+                       n_plans++;
+       } else {
+               /*
+                * The scan interval attribute is kept for backward
+                * compatibility. If no scan plans are specified and sched scan
+                * interval is specified, one scan plan will be set with this
+                * scan interval and infinite number of iterations.
+                */
+               if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
+                       return ERR_PTR(-EINVAL);
+
+               n_plans = 1;
+       }
+
+       if (!n_plans || n_plans > wiphy->max_sched_scan_plans)
+               return ERR_PTR(-EINVAL);
+
        request = kzalloc(sizeof(*request)
                        + sizeof(*request->ssids) * n_ssids
                        + sizeof(*request->match_sets) * n_match_sets
+                       + sizeof(*request->scan_plans) * n_plans
                        + sizeof(*request->channels) * n_channels
                        + ie_len, GFP_KERNEL);
        if (!request)
@@ -6073,6 +6220,18 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
        }
        request->n_match_sets = n_match_sets;
 
+       if (n_match_sets)
+               request->scan_plans = (void *)(request->match_sets +
+                                              n_match_sets);
+       else if (request->ie)
+               request->scan_plans = (void *)(request->ie + ie_len);
+       else if (n_ssids)
+               request->scan_plans = (void *)(request->ssids + n_ssids);
+       else
+               request->scan_plans = (void *)(request->channels + n_channels);
+
+       request->n_scan_plans = n_plans;
+
        i = 0;
        if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
                /* user specified, bail out if channel not found */
@@ -6235,7 +6394,10 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
                request->delay =
                        nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]);
 
-       request->interval = interval;
+       err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs);
+       if (err)
+               goto out_free;
+
        request->scan_start = jiffies;
 
        return request;
@@ -6491,8 +6653,8 @@ skip_beacons:
        if (err)
                return err;
 
-       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
-                                    wdev->iftype))
+       if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
+                                          wdev->iftype))
                return -EINVAL;
 
        err = cfg80211_chandef_dfs_required(wdev->wiphy,
@@ -6588,6 +6750,11 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
                        jiffies_to_msecs(jiffies - intbss->ts)))
                goto nla_put_failure;
 
+       if (intbss->ts_boottime &&
+           nla_put_u64(msg, NL80211_BSS_LAST_SEEN_BOOTTIME,
+                       intbss->ts_boottime))
+               goto nla_put_failure;
+
        switch (rdev->wiphy.signal_type) {
        case CFG80211_SIGNAL_TYPE_MBM:
                if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal))
@@ -7388,7 +7555,8 @@ static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
        int err;
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
                return -EOPNOTSUPP;
 
        if (!rdev->ops->set_mcast_rate)
@@ -7773,8 +7941,10 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
        if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
                if (!(rdev->wiphy.features &
                      NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) ||
-                   !(rdev->wiphy.features & NL80211_FEATURE_QUIET))
+                   !(rdev->wiphy.features & NL80211_FEATURE_QUIET)) {
+                       kzfree(connkeys);
                        return -EINVAL;
+               }
                connect.flags |= ASSOC_REQ_USE_RRM;
        }
 
@@ -8827,7 +8997,7 @@ static int nl80211_send_wowlan_tcp(struct sk_buff *msg,
 static int nl80211_send_wowlan_nd(struct sk_buff *msg,
                                  struct cfg80211_sched_scan_request *req)
 {
-       struct nlattr *nd, *freqs, *matches, *match;
+       struct nlattr *nd, *freqs, *matches, *match, *scan_plans, *scan_plan;
        int i;
 
        if (!req)
@@ -8837,7 +9007,9 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg,
        if (!nd)
                return -ENOBUFS;
 
-       if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, req->interval))
+       if (req->n_scan_plans == 1 &&
+           nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL,
+                       req->scan_plans[0].interval * 1000))
                return -ENOBUFS;
 
        if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
@@ -8864,6 +9036,23 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg,
                nla_nest_end(msg, matches);
        }
 
+       scan_plans = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_PLANS);
+       if (!scan_plans)
+               return -ENOBUFS;
+
+       for (i = 0; i < req->n_scan_plans; i++) {
+               scan_plan = nla_nest_start(msg, i + 1);
+               if (!scan_plan ||
+                   nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL,
+                               req->scan_plans[i].interval) ||
+                   (req->scan_plans[i].iterations &&
+                    nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS,
+                                req->scan_plans[i].iterations)))
+                       return -ENOBUFS;
+               nla_nest_end(msg, scan_plan);
+       }
+       nla_nest_end(msg, scan_plans);
+
        nla_nest_end(msg, nd);
 
        return 0;
@@ -9316,6 +9505,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
        if (new_triggers.tcp && new_triggers.tcp->sock)
                sock_release(new_triggers.tcp->sock);
        kfree(new_triggers.tcp);
+       kfree(new_triggers.nd_config);
        return err;
 }
 #endif
@@ -9934,6 +10124,9 @@ static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
                                if (!wdev->netdev && !wdev->p2p_started)
                                        return -ENETDOWN;
                        }
+
+                       if (!vcmd->doit)
+                               return -EOPNOTSUPP;
                } else {
                        wdev = NULL;
                }
@@ -9953,6 +10146,193 @@ static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
        return -EOPNOTSUPP;
 }
 
+static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
+                                      struct netlink_callback *cb,
+                                      struct cfg80211_registered_device **rdev,
+                                      struct wireless_dev **wdev)
+{
+       u32 vid, subcmd;
+       unsigned int i;
+       int vcmd_idx = -1;
+       int err;
+       void *data = NULL;
+       unsigned int data_len = 0;
+
+       rtnl_lock();
+
+       if (cb->args[0]) {
+               /* subtract the 1 again here */
+               struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
+               struct wireless_dev *tmp;
+
+               if (!wiphy) {
+                       err = -ENODEV;
+                       goto out_unlock;
+               }
+               *rdev = wiphy_to_rdev(wiphy);
+               *wdev = NULL;
+
+               if (cb->args[1]) {
+                       list_for_each_entry(tmp, &(*rdev)->wdev_list, list) {
+                               if (tmp->identifier == cb->args[1] - 1) {
+                                       *wdev = tmp;
+                                       break;
+                               }
+                       }
+               }
+
+               /* keep rtnl locked in successful case */
+               return 0;
+       }
+
+       err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
+                         nl80211_fam.attrbuf, nl80211_fam.maxattr,
+                         nl80211_policy);
+       if (err)
+               goto out_unlock;
+
+       if (!nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID] ||
+           !nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
+               err = -EINVAL;
+               goto out_unlock;
+       }
+
+       *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
+                                          nl80211_fam.attrbuf);
+       if (IS_ERR(*wdev))
+               *wdev = NULL;
+
+       *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk),
+                                          nl80211_fam.attrbuf);
+       if (IS_ERR(*rdev)) {
+               err = PTR_ERR(*rdev);
+               goto out_unlock;
+       }
+
+       vid = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID]);
+       subcmd = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
+
+       for (i = 0; i < (*rdev)->wiphy.n_vendor_commands; i++) {
+               const struct wiphy_vendor_command *vcmd;
+
+               vcmd = &(*rdev)->wiphy.vendor_commands[i];
+
+               if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
+                       continue;
+
+               if (!vcmd->dumpit) {
+                       err = -EOPNOTSUPP;
+                       goto out_unlock;
+               }
+
+               vcmd_idx = i;
+               break;
+       }
+
+       if (vcmd_idx < 0) {
+               err = -EOPNOTSUPP;
+               goto out_unlock;
+       }
+
+       if (nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]) {
+               data = nla_data(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]);
+               data_len = nla_len(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]);
+       }
+
+       /* 0 is the first index - add 1 to parse only once */
+       cb->args[0] = (*rdev)->wiphy_idx + 1;
+       /* add 1 to know if it was NULL */
+       cb->args[1] = *wdev ? (*wdev)->identifier + 1 : 0;
+       cb->args[2] = vcmd_idx;
+       cb->args[3] = (unsigned long)data;
+       cb->args[4] = data_len;
+
+       /* keep rtnl locked in successful case */
+       return 0;
+ out_unlock:
+       rtnl_unlock();
+       return err;
+}
+
+static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
+                                  struct netlink_callback *cb)
+{
+       struct cfg80211_registered_device *rdev;
+       struct wireless_dev *wdev;
+       unsigned int vcmd_idx;
+       const struct wiphy_vendor_command *vcmd;
+       void *data;
+       int data_len;
+       int err;
+       struct nlattr *vendor_data;
+
+       err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
+       if (err)
+               return err;
+
+       vcmd_idx = cb->args[2];
+       data = (void *)cb->args[3];
+       data_len = cb->args[4];
+       vcmd = &rdev->wiphy.vendor_commands[vcmd_idx];
+
+       if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
+                          WIPHY_VENDOR_CMD_NEED_NETDEV)) {
+               if (!wdev)
+                       return -EINVAL;
+               if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
+                   !wdev->netdev)
+                       return -EINVAL;
+
+               if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
+                       if (wdev->netdev &&
+                           !netif_running(wdev->netdev))
+                               return -ENETDOWN;
+                       if (!wdev->netdev && !wdev->p2p_started)
+                               return -ENETDOWN;
+               }
+       }
+
+       while (1) {
+               void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
+                                          cb->nlh->nlmsg_seq, NLM_F_MULTI,
+                                          NL80211_CMD_VENDOR);
+               if (!hdr)
+                       break;
+
+               if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+                   (wdev && nla_put_u64(skb, NL80211_ATTR_WDEV,
+                                        wdev_id(wdev)))) {
+                       genlmsg_cancel(skb, hdr);
+                       break;
+               }
+
+               vendor_data = nla_nest_start(skb, NL80211_ATTR_VENDOR_DATA);
+               if (!vendor_data) {
+                       genlmsg_cancel(skb, hdr);
+                       break;
+               }
+
+               err = vcmd->dumpit(&rdev->wiphy, wdev, skb, data, data_len,
+                                  (unsigned long *)&cb->args[5]);
+               nla_nest_end(skb, vendor_data);
+
+               if (err == -ENOBUFS || err == -ENOENT) {
+                       genlmsg_cancel(skb, hdr);
+                       break;
+               } else if (err) {
+                       genlmsg_cancel(skb, hdr);
+                       goto out;
+               }
+
+               genlmsg_end(skb, hdr);
+       }
+
+       err = skb->len;
+ out:
+       rtnl_unlock();
+       return err;
+}
+
 struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
                                           enum nl80211_commands cmd,
                                           enum nl80211_attrs attr,
@@ -10169,7 +10549,8 @@ static int nl80211_tdls_channel_switch(struct sk_buff *skb,
                return -EINVAL;
 
        /* we will be active on the TDLS link */
-       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, wdev->iftype))
+       if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
+                                          wdev->iftype))
                return -EINVAL;
 
        /* don't allow switching to DFS channels */
@@ -10528,6 +10909,7 @@ static const struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_RTNL,
                /* can be retrieved by unprivileged users */
        },
+#ifdef CONFIG_CFG80211_CRDA_SUPPORT
        {
                .cmd = NL80211_CMD_SET_REG,
                .doit = nl80211_set_reg,
@@ -10535,6 +10917,7 @@ static const struct genl_ops nl80211_ops[] = {
                .flags = GENL_ADMIN_PERM,
                .internal_flags = NL80211_FLAG_NEED_RTNL,
        },
+#endif
        {
                .cmd = NL80211_CMD_REQ_SET_REG,
                .doit = nl80211_req_set_reg,
@@ -10989,6 +11372,7 @@ static const struct genl_ops nl80211_ops[] = {
        {
                .cmd = NL80211_CMD_VENDOR,
                .doit = nl80211_vendor_cmd,
+               .dumpit = nl80211_vendor_cmd_dump,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
                .internal_flags = NL80211_FLAG_NEED_WIPHY |