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.c59
1 files changed, 58 insertions, 1 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0cda46ab35e..f4cfd3abfbf 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -190,6 +190,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
190 [NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY, 190 [NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY,
191 .len = IEEE80211_MAX_DATA_LEN }, 191 .len = IEEE80211_MAX_DATA_LEN },
192 [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG }, 192 [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
193 [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
193}; 194};
194 195
195/* policy for the key attributes */ 196/* policy for the key attributes */
@@ -232,6 +233,12 @@ nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
232 [NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN }, 233 [NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
233}; 234};
234 235
236static const struct nla_policy
237nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
238 [NL80211_ATTR_SCHED_SCAN_MATCH_SSID] = { .type = NLA_BINARY,
239 .len = IEEE80211_MAX_SSID_LEN },
240};
241
235/* ifidx get helper */ 242/* ifidx get helper */
236static int nl80211_get_ifidx(struct netlink_callback *cb) 243static int nl80211_get_ifidx(struct netlink_callback *cb)
237{ 244{
@@ -715,6 +722,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
715 dev->wiphy.max_scan_ie_len); 722 dev->wiphy.max_scan_ie_len);
716 NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, 723 NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
717 dev->wiphy.max_sched_scan_ie_len); 724 dev->wiphy.max_sched_scan_ie_len);
725 NLA_PUT_U8(msg, NL80211_ATTR_MAX_MATCH_SETS,
726 dev->wiphy.max_match_sets);
718 727
719 if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) 728 if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)
720 NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); 729 NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN);
@@ -3632,10 +3641,11 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
3632 struct net_device *dev = info->user_ptr[1]; 3641 struct net_device *dev = info->user_ptr[1];
3633 struct nlattr *attr; 3642 struct nlattr *attr;
3634 struct wiphy *wiphy; 3643 struct wiphy *wiphy;
3635 int err, tmp, n_ssids = 0, n_channels, i; 3644 int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i;
3636 u32 interval; 3645 u32 interval;
3637 enum ieee80211_band band; 3646 enum ieee80211_band band;
3638 size_t ie_len; 3647 size_t ie_len;
3648 struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
3639 3649
3640 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || 3650 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
3641 !rdev->ops->sched_scan_start) 3651 !rdev->ops->sched_scan_start)
@@ -3674,6 +3684,15 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
3674 if (n_ssids > wiphy->max_sched_scan_ssids) 3684 if (n_ssids > wiphy->max_sched_scan_ssids)
3675 return -EINVAL; 3685 return -EINVAL;
3676 3686
3687 if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH])
3688 nla_for_each_nested(attr,
3689 info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
3690 tmp)
3691 n_match_sets++;
3692
3693 if (n_match_sets > wiphy->max_match_sets)
3694 return -EINVAL;
3695
3677 if (info->attrs[NL80211_ATTR_IE]) 3696 if (info->attrs[NL80211_ATTR_IE])
3678 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3697 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
3679 else 3698 else
@@ -3691,6 +3710,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
3691 3710
3692 request = kzalloc(sizeof(*request) 3711 request = kzalloc(sizeof(*request)
3693 + sizeof(*request->ssids) * n_ssids 3712 + sizeof(*request->ssids) * n_ssids
3713 + sizeof(*request->match_sets) * n_match_sets
3694 + sizeof(*request->channels) * n_channels 3714 + sizeof(*request->channels) * n_channels
3695 + ie_len, GFP_KERNEL); 3715 + ie_len, GFP_KERNEL);
3696 if (!request) { 3716 if (!request) {
@@ -3708,6 +3728,18 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
3708 request->ie = (void *)(request->channels + n_channels); 3728 request->ie = (void *)(request->channels + n_channels);
3709 } 3729 }
3710 3730
3731 if (n_match_sets) {
3732 if (request->ie)
3733 request->match_sets = (void *)(request->ie + ie_len);
3734 else if (request->ssids)
3735 request->match_sets =
3736 (void *)(request->ssids + n_ssids);
3737 else
3738 request->match_sets =
3739 (void *)(request->channels + n_channels);
3740 }
3741 request->n_match_sets = n_match_sets;
3742
3711 i = 0; 3743 i = 0;
3712 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { 3744 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
3713 /* user specified, bail out if channel not found */ 3745 /* user specified, bail out if channel not found */
@@ -3772,6 +3804,31 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
3772 } 3804 }
3773 } 3805 }
3774 3806
3807 i = 0;
3808 if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
3809 nla_for_each_nested(attr,
3810 info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
3811 tmp) {
3812 struct nlattr *ssid;
3813
3814 nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
3815 nla_data(attr), nla_len(attr),
3816 nl80211_match_policy);
3817 ssid = tb[NL80211_ATTR_SCHED_SCAN_MATCH_SSID];
3818 if (ssid) {
3819 if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
3820 err = -EINVAL;
3821 goto out_free;
3822 }
3823 memcpy(request->match_sets[i].ssid.ssid,
3824 nla_data(ssid), nla_len(ssid));
3825 request->match_sets[i].ssid.ssid_len =
3826 nla_len(ssid);
3827 }
3828 i++;
3829 }
3830 }
3831
3775 if (info->attrs[NL80211_ATTR_IE]) { 3832 if (info->attrs[NL80211_ATTR_IE]) {
3776 request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3833 request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
3777 memcpy((void *)request->ie, 3834 memcpy((void *)request->ie,