diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 59 |
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 | ||
236 | static const struct nla_policy | ||
237 | nl80211_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 */ |
236 | static int nl80211_get_ifidx(struct netlink_callback *cb) | 243 | static 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, |