Merge tag 'mac80211-next-for-davem-2017-01-13' of git://git.kernel.org/pub/scm/linux...
[sfrench/cifs-2.6.git] / net / wireless / nl80211.c
index ef5eff93a8b817dda5fa41bebf4fe4963663a9d6..bed816cfd7543bde13540d3a96de1ad68683941c 100644 (file)
@@ -405,6 +405,11 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
        [NL80211_ATTR_FILS_NONCES] = { .len = 2 * FILS_NONCE_LEN },
        [NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
        [NL80211_ATTR_BSSID] = { .len = ETH_ALEN },
+       [NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 },
+       [NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
+               .len = sizeof(struct nl80211_bss_select_rssi_adjust)
+       },
+       [NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
 };
 
 /* policy for the key attributes */
@@ -6775,13 +6780,10 @@ nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
 
                /*
                 * If scan plans are not specified,
-                * %NL80211_ATTR_SCHED_SCAN_INTERVAL must be specified. In this
+                * %NL80211_ATTR_SCHED_SCAN_INTERVAL will 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;
@@ -6953,6 +6955,12 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
        if (!n_plans || n_plans > wiphy->max_sched_scan_plans)
                return ERR_PTR(-EINVAL);
 
+       if (!wiphy_ext_feature_isset(
+                   wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI) &&
+           (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] ||
+            attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]))
+               return ERR_PTR(-EINVAL);
+
        request = kzalloc(sizeof(*request)
                        + sizeof(*request->ssids) * n_ssids
                        + sizeof(*request->match_sets) * n_match_sets
@@ -7159,6 +7167,26 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
                request->delay =
                        nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]);
 
+       if (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]) {
+               request->relative_rssi = nla_get_s8(
+                       attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]);
+               request->relative_rssi_set = true;
+       }
+
+       if (request->relative_rssi_set &&
+           attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]) {
+               struct nl80211_bss_select_rssi_adjust *rssi_adjust;
+
+               rssi_adjust = nla_data(
+                       attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]);
+               request->rssi_adjust.band = rssi_adjust->band;
+               request->rssi_adjust.delta = rssi_adjust->delta;
+               if (!is_band_valid(wiphy, request->rssi_adjust.band)) {
+                       err = -EINVAL;
+                       goto out_free;
+               }
+       }
+
        err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs);
        if (err)
                goto out_free;
@@ -8053,8 +8081,17 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
        err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
        if (!err) {
                wdev_lock(dev->ieee80211_ptr);
+
                err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
                                          ssid, ssid_len, &req);
+
+               if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
+                       dev->ieee80211_ptr->conn_owner_nlportid =
+                               info->snd_portid;
+                       memcpy(dev->ieee80211_ptr->disconnect_bssid,
+                              bssid, ETH_ALEN);
+               }
+
                wdev_unlock(dev->ieee80211_ptr);
        }
 
@@ -8773,11 +8810,24 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
        }
 
        wdev_lock(dev->ieee80211_ptr);
+
        err = cfg80211_connect(rdev, dev, &connect, connkeys,
                               connect.prev_bssid);
-       wdev_unlock(dev->ieee80211_ptr);
        if (err)
                kzfree(connkeys);
+
+       if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
+               dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
+               if (connect.bssid)
+                       memcpy(dev->ieee80211_ptr->disconnect_bssid,
+                              connect.bssid, ETH_ALEN);
+               else
+                       memset(dev->ieee80211_ptr->disconnect_bssid,
+                              0, ETH_ALEN);
+       }
+
+       wdev_unlock(dev->ieee80211_ptr);
+
        return err;
 }
 
@@ -9673,6 +9723,20 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg,
        if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
                return -ENOBUFS;
 
+       if (req->relative_rssi_set) {
+               struct nl80211_bss_select_rssi_adjust rssi_adjust;
+
+               if (nla_put_s8(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
+                              req->relative_rssi))
+                       return -ENOBUFS;
+
+               rssi_adjust.band = req->rssi_adjust.band;
+               rssi_adjust.delta = req->rssi_adjust.delta;
+               if (nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
+                           sizeof(rssi_adjust), &rssi_adjust))
+                       return -ENOBUFS;
+       }
+
        freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
        if (!freqs)
                return -ENOBUFS;
@@ -11807,9 +11871,6 @@ static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
        const struct nlattr *nla;
        bool enabled;
 
-       if (netif_running(dev))
-               return -EBUSY;
-
        if (!rdev->ops->set_multicast_to_unicast)
                return -EOPNOTSUPP;
 
@@ -12810,7 +12871,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
        return -ENOBUFS;
 }
 
-static int nl80211_send_scan_msg(struct sk_buff *msg,
+static int nl80211_prep_scan_msg(struct sk_buff *msg,
                                 struct cfg80211_registered_device *rdev,
                                 struct wireless_dev *wdev,
                                 u32 portid, u32 seq, int flags,
@@ -12841,7 +12902,7 @@ static int nl80211_send_scan_msg(struct sk_buff *msg,
 }
 
 static int
-nl80211_send_sched_scan_msg(struct sk_buff *msg,
+nl80211_prep_sched_scan_msg(struct sk_buff *msg,
                            struct cfg80211_registered_device *rdev,
                            struct net_device *netdev,
                            u32 portid, u32 seq, int flags, u32 cmd)
@@ -12873,7 +12934,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
        if (!msg)
                return;
 
-       if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
+       if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
                                  NL80211_CMD_TRIGGER_SCAN) < 0) {
                nlmsg_free(msg);
                return;
@@ -12892,7 +12953,7 @@ struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
        if (!msg)
                return NULL;
 
-       if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
+       if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
                                  aborted ? NL80211_CMD_SCAN_ABORTED :
                                            NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
                nlmsg_free(msg);
@@ -12902,31 +12963,13 @@ struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
        return msg;
 }
 
-void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
-                             struct sk_buff *msg)
-{
-       if (!msg)
-               return;
-
-       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-                               NL80211_MCGRP_SCAN, GFP_KERNEL);
-}
-
-void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
-                                    struct net_device *netdev)
+/* send message created by nl80211_build_scan_msg() */
+void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
+                          struct sk_buff *msg)
 {
-       struct sk_buff *msg;
-
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
                return;
 
-       if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0,
-                                       NL80211_CMD_SCHED_SCAN_RESULTS) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
-
        genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
                                NL80211_MCGRP_SCAN, GFP_KERNEL);
 }
@@ -12940,7 +12983,7 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
        if (!msg)
                return;
 
-       if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
+       if (nl80211_prep_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
                nlmsg_free(msg);
                return;
        }
@@ -13042,7 +13085,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+       msg = nlmsg_new(100 + len, gfp);
        if (!msg)
                return;
 
@@ -13189,12 +13232,14 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
                                 struct net_device *netdev, const u8 *bssid,
                                 const u8 *req_ie, size_t req_ie_len,
                                 const u8 *resp_ie, size_t resp_ie_len,
-                                int status, gfp_t gfp)
+                                int status,
+                                enum nl80211_timeout_reason timeout_reason,
+                                gfp_t gfp)
 {
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+       msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
        if (!msg)
                return;
 
@@ -13210,7 +13255,9 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
            nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
                        status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
                        status) ||
-           (status < 0 && nla_put_flag(msg, NL80211_ATTR_TIMED_OUT)) ||
+           (status < 0 &&
+            (nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
+             nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON, timeout_reason))) ||
            (req_ie &&
             nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
            (resp_ie &&
@@ -13236,7 +13283,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+       msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
        if (!msg)
                return;
 
@@ -13273,7 +13320,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       msg = nlmsg_new(100 + ie_len, GFP_KERNEL);
        if (!msg)
                return;
 
@@ -13349,7 +13396,7 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
 
        trace_cfg80211_notify_new_peer_candidate(dev, addr);
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+       msg = nlmsg_new(100 + ie_len, gfp);
        if (!msg)
                return;
 
@@ -13720,7 +13767,7 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+       msg = nlmsg_new(100 + len, gfp);
        if (!msg)
                return -ENOMEM;
 
@@ -13764,7 +13811,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
 
        trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+       msg = nlmsg_new(100 + len, gfp);
        if (!msg)
                return;
 
@@ -14519,6 +14566,8 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
 
                        if (wdev->owner_nlportid == notify->portid)
                                schedule_destroy_work = true;
+                       else if (wdev->conn_owner_nlportid == notify->portid)
+                               schedule_work(&wdev->disconnect_wk);
                }
 
                spin_lock_bh(&rdev->beacon_registrations_lock);
@@ -14573,7 +14622,7 @@ void cfg80211_ft_event(struct net_device *netdev,
        if (!ft_event->target_ap)
                return;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       msg = nlmsg_new(100 + ft_event->ric_ies_len, GFP_KERNEL);
        if (!msg)
                return;