diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 130 |
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 | ||
5684 | static int nl80211_start_sched_scan(struct sk_buff *skb, | 5684 | static struct cfg80211_sched_scan_request * |
5685 | struct genl_info *info) | 5685 | nl80211_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 | ||
5964 | out_free: | 5941 | out_free: |
5965 | kfree(request); | 5942 | kfree(request); |
5966 | out: | 5943 | return ERR_PTR(err); |
5944 | } | ||
5945 | |||
5946 | static 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 | |||
5977 | out_free: | ||
5978 | kfree(rdev->sched_scan_req); | ||
5979 | out_err: | ||
5980 | rdev->sched_scan_req = NULL; | ||
5967 | return err; | 5981 | return err; |
5968 | } | 5982 | } |
5969 | 5983 | ||