]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/wireless/nl80211.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[karo-tx-linux.git] / net / wireless / nl80211.c
index 2d3541c5e05851739db352b3e2d7a6902aa2181e..3b508eaf2d072e094f8aee5dd433ab013bed3439 100644 (file)
@@ -71,46 +71,52 @@ static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs,
 }
 
 static struct cfg80211_registered_device *
-__cfg80211_rdev_from_info(struct genl_info *info)
+__cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
 {
-       int ifindex;
-       struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL;
-       struct net_device *dev;
-       int err = -EINVAL;
+       struct cfg80211_registered_device *rdev = NULL, *tmp;
+       struct net_device *netdev;
 
        assert_cfg80211_lock();
 
-       if (info->attrs[NL80211_ATTR_WIPHY]) {
-               bywiphyidx = cfg80211_rdev_by_wiphy_idx(
-                               nla_get_u32(info->attrs[NL80211_ATTR_WIPHY]));
-               err = -ENODEV;
-       }
+       if (!attrs[NL80211_ATTR_WIPHY] &&
+           !attrs[NL80211_ATTR_IFINDEX])
+               return ERR_PTR(-EINVAL);
 
-       if (info->attrs[NL80211_ATTR_IFINDEX]) {
-               ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
-               dev = dev_get_by_index(genl_info_net(info), ifindex);
-               if (dev) {
-                       if (dev->ieee80211_ptr)
-                               byifidx =
-                                       wiphy_to_dev(dev->ieee80211_ptr->wiphy);
-                       dev_put(dev);
+       if (attrs[NL80211_ATTR_WIPHY])
+               rdev = cfg80211_rdev_by_wiphy_idx(
+                               nla_get_u32(attrs[NL80211_ATTR_WIPHY]));
+
+       if (attrs[NL80211_ATTR_IFINDEX]) {
+               int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
+               netdev = dev_get_by_index(netns, ifindex);
+               if (netdev) {
+                       if (netdev->ieee80211_ptr)
+                               tmp = wiphy_to_dev(
+                                               netdev->ieee80211_ptr->wiphy);
+                       else
+                               tmp = NULL;
+
+                       dev_put(netdev);
+
+                       /* not wireless device -- return error */
+                       if (!tmp)
+                               return ERR_PTR(-EINVAL);
+
+                       /* mismatch -- return error */
+                       if (rdev && tmp != rdev)
+                               return ERR_PTR(-EINVAL);
+
+                       rdev = tmp;
                }
-               err = -ENODEV;
        }
 
-       if (bywiphyidx && byifidx) {
-               if (bywiphyidx != byifidx)
-                       return ERR_PTR(-EINVAL);
-               else
-                       return bywiphyidx; /* == byifidx */
-       }
-       if (bywiphyidx)
-               return bywiphyidx;
+       if (!rdev)
+               return ERR_PTR(-ENODEV);
 
-       if (byifidx)
-               return byifidx;
+       if (netns != wiphy_net(&rdev->wiphy))
+               return ERR_PTR(-ENODEV);
 
-       return ERR_PTR(err);
+       return rdev;
 }
 
 /*
@@ -134,12 +140,12 @@ __cfg80211_rdev_from_info(struct genl_info *info)
  * be checked with IS_ERR() for errors.
  */
 static struct cfg80211_registered_device *
-cfg80211_get_dev_from_info(struct genl_info *info)
+cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev;
 
        mutex_lock(&cfg80211_mutex);
-       rdev = __cfg80211_rdev_from_info(info);
+       rdev = __cfg80211_rdev_from_attrs(netns, info->attrs);
 
        /* if it is not an error we grab the lock on
         * it to assure it won't be going away while
@@ -334,6 +340,7 @@ static const struct nla_policy
 nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
        [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
                                                 .len = IEEE80211_MAX_SSID_LEN },
+       [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
 };
 
 /* ifidx get helper */
@@ -1416,7 +1423,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
        }
 
        if (!netdev) {
-               rdev = __cfg80211_rdev_from_info(info);
+               rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
+                                                 info->attrs);
                if (IS_ERR(rdev)) {
                        mutex_unlock(&cfg80211_mutex);
                        return PTR_ERR(rdev);
@@ -2328,6 +2336,33 @@ static int nl80211_parse_beacon(struct genl_info *info,
        return 0;
 }
 
+static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
+                                  struct cfg80211_ap_settings *params)
+{
+       struct wireless_dev *wdev;
+       bool ret = false;
+
+       mutex_lock(&rdev->devlist_mtx);
+
+       list_for_each_entry(wdev, &rdev->netdev_list, list) {
+               if (wdev->iftype != NL80211_IFTYPE_AP &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO)
+                       continue;
+
+               if (!wdev->preset_chan)
+                       continue;
+
+               params->channel = wdev->preset_chan;
+               params->channel_type = wdev->preset_chantype;
+               ret = true;
+               break;
+       }
+
+       mutex_unlock(&rdev->devlist_mtx);
+
+       return ret;
+}
+
 static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -2430,7 +2465,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        } else if (wdev->preset_chan) {
                params.channel = wdev->preset_chan;
                params.channel_type = wdev->preset_chantype;
-       } else
+       } else if (!nl80211_get_ap_channel(rdev, &params))
                return -EINVAL;
 
        if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel,
@@ -2438,8 +2473,11 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
                return -EINVAL;
 
        err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
-       if (!err)
+       if (!err) {
+               wdev->preset_chan = params.channel;
+               wdev->preset_chantype = params.channel_type;
                wdev->beacon_interval = params.beacon_interval;
+       }
        return err;
 }
 
@@ -4350,7 +4388,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
                nla_for_each_nested(attr,
                                    info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
                                    tmp) {
-                       struct nlattr *ssid;
+                       struct nlattr *ssid, *rssi;
 
                        nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
                                  nla_data(attr), nla_len(attr),
@@ -4366,6 +4404,12 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
                                request->match_sets[i].ssid.ssid_len =
                                        nla_len(ssid);
                        }
+                       rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
+                       if (rssi)
+                               request->rssi_thold = nla_get_u32(rssi);
+                       else
+                               request->rssi_thold =
+                                                  NL80211_SCAN_RSSI_THOLD_OFF;
                        i++;
                }
        }
@@ -5223,21 +5267,18 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
                                  nl80211_policy);
                if (err)
                        return err;
-               if (nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]) {
-                       phy_idx = nla_get_u32(
-                               nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]);
-               } else {
-                       struct net_device *netdev;
 
-                       err = get_rdev_dev_by_ifindex(sock_net(skb->sk),
-                                                     nl80211_fam.attrbuf,
-                                                     &rdev, &netdev);
-                       if (err)
-                               return err;
-                       dev_put(netdev);
-                       phy_idx = rdev->wiphy_idx;
-                       cfg80211_unlock_rdev(rdev);
+               mutex_lock(&cfg80211_mutex);
+               rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk),
+                                                 nl80211_fam.attrbuf);
+               if (IS_ERR(rdev)) {
+                       mutex_unlock(&cfg80211_mutex);
+                       return PTR_ERR(rdev);
                }
+               phy_idx = rdev->wiphy_idx;
+               rdev = NULL;
+               mutex_unlock(&cfg80211_mutex);
+
                if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA])
                        cb->args[1] =
                                (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA];
@@ -6620,7 +6661,7 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
                rtnl_lock();
 
        if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
-               rdev = cfg80211_get_dev_from_info(info);
+               rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
                if (IS_ERR(rdev)) {
                        if (rtnl)
                                rtnl_unlock();
@@ -7319,7 +7360,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
 {
        struct sk_buff *msg;
 
-       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
                return;
 
@@ -7395,7 +7436,7 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
 {
        struct sk_buff *msg;
 
-       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
                return;
 
@@ -7611,7 +7652,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
 
@@ -7651,7 +7692,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
 
@@ -7689,7 +7730,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
                return;
 
@@ -7951,7 +7992,7 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
 {
        struct sk_buff *msg;
 
-       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
 
@@ -7972,7 +8013,7 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
 
@@ -8135,7 +8176,7 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
        struct nlattr *pinfoattr;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
 
@@ -8178,7 +8219,7 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
        struct nlattr *rekey_attr;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
 
@@ -8222,7 +8263,7 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
        struct nlattr *attr;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
 
@@ -8266,7 +8307,7 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
 
@@ -8301,7 +8342,7 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
        struct nlattr *pinfoattr;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
 
@@ -8345,7 +8386,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
        void *hdr;
        int err;
 
-       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;