aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c130
1 files changed, 72 insertions, 58 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 27666f5e5050..03a302b884fd 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5681,14 +5681,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
5681 return err; 5681 return err;
5682} 5682}
5683 5683
5684static int nl80211_start_sched_scan(struct sk_buff *skb, 5684static struct cfg80211_sched_scan_request *
5685 struct genl_info *info) 5685nl80211_parse_sched_scan(struct wiphy *wiphy,
5686 struct nlattr **attrs)
5686{ 5687{
5687 struct cfg80211_sched_scan_request *request; 5688 struct cfg80211_sched_scan_request *request;
5688 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5689 struct net_device *dev = info->user_ptr[1];
5690 struct nlattr *attr; 5689 struct nlattr *attr;
5691 struct wiphy *wiphy;
5692 int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i; 5690 int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i;
5693 u32 interval; 5691 u32 interval;
5694 enum ieee80211_band band; 5692 enum ieee80211_band band;
@@ -5696,38 +5694,32 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
5696 struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1]; 5694 struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
5697 s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF; 5695 s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
5698 5696
5699 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || 5697 if (!is_valid_ie_attr(attrs[NL80211_ATTR_IE]))
5700 !rdev->ops->sched_scan_start) 5698 return ERR_PTR(-EINVAL);
5701 return -EOPNOTSUPP;
5702
5703 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
5704 return -EINVAL;
5705 5699
5706 if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) 5700 if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
5707 return -EINVAL; 5701 return ERR_PTR(-EINVAL);
5708 5702
5709 interval = nla_get_u32(info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]); 5703 interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
5710 if (interval == 0) 5704 if (interval == 0)
5711 return -EINVAL; 5705 return ERR_PTR(-EINVAL);
5712
5713 wiphy = &rdev->wiphy;
5714 5706
5715 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { 5707 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
5716 n_channels = validate_scan_freqs( 5708 n_channels = validate_scan_freqs(
5717 info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); 5709 attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
5718 if (!n_channels) 5710 if (!n_channels)
5719 return -EINVAL; 5711 return ERR_PTR(-EINVAL);
5720 } else { 5712 } else {
5721 n_channels = ieee80211_get_num_supported_channels(wiphy); 5713 n_channels = ieee80211_get_num_supported_channels(wiphy);
5722 } 5714 }
5723 5715
5724 if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) 5716 if (attrs[NL80211_ATTR_SCAN_SSIDS])
5725 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], 5717 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
5726 tmp) 5718 tmp)
5727 n_ssids++; 5719 n_ssids++;
5728 5720
5729 if (n_ssids > wiphy->max_sched_scan_ssids) 5721 if (n_ssids > wiphy->max_sched_scan_ssids)
5730 return -EINVAL; 5722 return ERR_PTR(-EINVAL);
5731 5723
5732 /* 5724 /*
5733 * First, count the number of 'real' matchsets. Due to an issue with 5725 * First, count the number of 'real' matchsets. Due to an issue with
@@ -5738,9 +5730,9 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
5738 * older userspace that treated a matchset with only the RSSI as the 5730 * older userspace that treated a matchset with only the RSSI as the
5739 * global RSSI for all other matchsets - if there are other matchsets. 5731 * global RSSI for all other matchsets - if there are other matchsets.
5740 */ 5732 */
5741 if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) { 5733 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
5742 nla_for_each_nested(attr, 5734 nla_for_each_nested(attr,
5743 info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], 5735 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
5744 tmp) { 5736 tmp) {
5745 struct nlattr *rssi; 5737 struct nlattr *rssi;
5746 5738
@@ -5748,7 +5740,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
5748 nla_data(attr), nla_len(attr), 5740 nla_data(attr), nla_len(attr),
5749 nl80211_match_policy); 5741 nl80211_match_policy);
5750 if (err) 5742 if (err)
5751 return err; 5743 return ERR_PTR(err);
5752 /* add other standalone attributes here */ 5744 /* add other standalone attributes here */
5753 if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) { 5745 if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) {
5754 n_match_sets++; 5746 n_match_sets++;
@@ -5765,30 +5757,23 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
5765 n_match_sets = 1; 5757 n_match_sets = 1;
5766 5758
5767 if (n_match_sets > wiphy->max_match_sets) 5759 if (n_match_sets > wiphy->max_match_sets)
5768 return -EINVAL; 5760 return ERR_PTR(-EINVAL);
5769 5761
5770 if (info->attrs[NL80211_ATTR_IE]) 5762 if (attrs[NL80211_ATTR_IE])
5771 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 5763 ie_len = nla_len(attrs[NL80211_ATTR_IE]);
5772 else 5764 else
5773 ie_len = 0; 5765 ie_len = 0;
5774 5766
5775 if (ie_len > wiphy->max_sched_scan_ie_len) 5767 if (ie_len > wiphy->max_sched_scan_ie_len)
5776 return -EINVAL; 5768 return ERR_PTR(-EINVAL);
5777
5778 if (rdev->sched_scan_req) {
5779 err = -EINPROGRESS;
5780 goto out;
5781 }
5782 5769
5783 request = kzalloc(sizeof(*request) 5770 request = kzalloc(sizeof(*request)
5784 + sizeof(*request->ssids) * n_ssids 5771 + sizeof(*request->ssids) * n_ssids
5785 + sizeof(*request->match_sets) * n_match_sets 5772 + sizeof(*request->match_sets) * n_match_sets
5786 + sizeof(*request->channels) * n_channels 5773 + sizeof(*request->channels) * n_channels
5787 + ie_len, GFP_KERNEL); 5774 + ie_len, GFP_KERNEL);
5788 if (!request) { 5775 if (!request)
5789 err = -ENOMEM; 5776 return ERR_PTR(-ENOMEM);
5790 goto out;
5791 }
5792 5777
5793 if (n_ssids) 5778 if (n_ssids)
5794 request->ssids = (void *)&request->channels[n_channels]; 5779 request->ssids = (void *)&request->channels[n_channels];
@@ -5813,10 +5798,10 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
5813 request->n_match_sets = n_match_sets; 5798 request->n_match_sets = n_match_sets;
5814 5799
5815 i = 0; 5800 i = 0;
5816 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { 5801 if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
5817 /* user specified, bail out if channel not found */ 5802 /* user specified, bail out if channel not found */
5818 nla_for_each_nested(attr, 5803 nla_for_each_nested(attr,
5819 info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], 5804 attrs[NL80211_ATTR_SCAN_FREQUENCIES],
5820 tmp) { 5805 tmp) {
5821 struct ieee80211_channel *chan; 5806 struct ieee80211_channel *chan;
5822 5807
@@ -5862,8 +5847,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
5862 request->n_channels = i; 5847 request->n_channels = i;
5863 5848
5864 i = 0; 5849 i = 0;
5865 if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { 5850 if (attrs[NL80211_ATTR_SCAN_SSIDS]) {
5866 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], 5851 nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
5867 tmp) { 5852 tmp) {
5868 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) { 5853 if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
5869 err = -EINVAL; 5854 err = -EINVAL;
@@ -5877,9 +5862,9 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
5877 } 5862 }
5878 5863
5879 i = 0; 5864 i = 0;
5880 if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) { 5865 if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
5881 nla_for_each_nested(attr, 5866 nla_for_each_nested(attr,
5882 info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], 5867 attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
5883 tmp) { 5868 tmp) {
5884 struct nlattr *ssid, *rssi; 5869 struct nlattr *ssid, *rssi;
5885 5870
@@ -5934,13 +5919,13 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
5934 if (ie_len) { 5919 if (ie_len) {
5935 request->ie_len = ie_len; 5920 request->ie_len = ie_len;
5936 memcpy((void *)request->ie, 5921 memcpy((void *)request->ie,
5937 nla_data(info->attrs[NL80211_ATTR_IE]), 5922 nla_data(attrs[NL80211_ATTR_IE]),
5938 request->ie_len); 5923 request->ie_len);
5939 } 5924 }
5940 5925
5941 if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { 5926 if (attrs[NL80211_ATTR_SCAN_FLAGS]) {
5942 request->flags = nla_get_u32( 5927 request->flags = nla_get_u32(
5943 info->attrs[NL80211_ATTR_SCAN_FLAGS]); 5928 attrs[NL80211_ATTR_SCAN_FLAGS]);
5944 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && 5929 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
5945 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { 5930 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
5946 err = -EOPNOTSUPP; 5931 err = -EOPNOTSUPP;
@@ -5948,22 +5933,51 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
5948 } 5933 }
5949 } 5934 }
5950 5935
5951 request->dev = dev;
5952 request->wiphy = &rdev->wiphy;
5953 request->interval = interval; 5936 request->interval = interval;
5954 request->scan_start = jiffies; 5937 request->scan_start = jiffies;
5955 5938
5956 err = rdev_sched_scan_start(rdev, dev, request); 5939 return request;
5957 if (!err) {
5958 rdev->sched_scan_req = request;
5959 nl80211_send_sched_scan(rdev, dev,
5960 NL80211_CMD_START_SCHED_SCAN);
5961 goto out;
5962 }
5963 5940
5964out_free: 5941out_free:
5965 kfree(request); 5942 kfree(request);
5966out: 5943 return ERR_PTR(err);
5944}
5945
5946static int nl80211_start_sched_scan(struct sk_buff *skb,
5947 struct genl_info *info)
5948{
5949 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5950 struct net_device *dev = info->user_ptr[1];
5951 int err;
5952
5953 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
5954 !rdev->ops->sched_scan_start)
5955 return -EOPNOTSUPP;
5956
5957 if (rdev->sched_scan_req)
5958 return -EINPROGRESS;
5959
5960 rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy,
5961 info->attrs);
5962 err = PTR_ERR_OR_ZERO(rdev->sched_scan_req);
5963 if (err)
5964 goto out_err;
5965
5966 err = rdev_sched_scan_start(rdev, dev, rdev->sched_scan_req);
5967 if (err)
5968 goto out_free;
5969
5970 rdev->sched_scan_req->dev = dev;
5971 rdev->sched_scan_req->wiphy = &rdev->wiphy;
5972
5973 nl80211_send_sched_scan(rdev, dev,
5974 NL80211_CMD_START_SCHED_SCAN);
5975 return 0;
5976
5977out_free:
5978 kfree(rdev->sched_scan_req);
5979out_err:
5980 rdev->sched_scan_req = NULL;
5967 return err; 5981 return err;
5968} 5982}
5969 5983