aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/nl80211.h43
-rw-r--r--include/net/cfg80211.h20
-rw-r--r--net/wireless/nl80211.c59
3 files changed, 121 insertions, 1 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 387e6e22050..8aa7badc196 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -769,6 +769,8 @@ enum nl80211_commands {
769 * that can be added to a scan request 769 * that can be added to a scan request
770 * @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information 770 * @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information
771 * elements that can be added to a scheduled scan request 771 * elements that can be added to a scheduled scan request
772 * @NL80211_ATTR_MAX_MATCH_SETS: maximum number of sets that can be
773 * used with @NL80211_ATTR_SCHED_SCAN_MATCH, a wiphy attribute.
772 * 774 *
773 * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz) 775 * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
774 * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive 776 * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
@@ -1011,6 +1013,24 @@ enum nl80211_commands {
1011 1013
1012 * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan 1014 * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan
1013 * cycles, in msecs. 1015 * cycles, in msecs.
1016
1017 * @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more
1018 * sets of attributes to match during scheduled scans. Only BSSs
1019 * that match any of the sets will be reported. These are
1020 * pass-thru filter rules.
1021 * For a match to succeed, the BSS must match all attributes of a
1022 * set. Since not every hardware supports matching all types of
1023 * attributes, there is no guarantee that the reported BSSs are
1024 * fully complying with the match sets and userspace needs to be
1025 * able to ignore them by itself.
1026 * Thus, the implementation is somewhat hardware-dependent, but
1027 * this is only an optimization and the userspace application
1028 * needs to handle all the non-filtered results anyway.
1029 * If the match attributes don't make sense when combined with
1030 * the values passed in @NL80211_ATTR_SCAN_SSIDS (eg. if an SSID
1031 * is included in the probe request, but the match attributes
1032 * will never let it go through), -EINVAL may be returned.
1033 * If ommited, no filtering is done.
1014 * 1034 *
1015 * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported 1035 * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported
1016 * interface combinations. In each nested item, it contains attributes 1036 * interface combinations. In each nested item, it contains attributes
@@ -1265,6 +1285,9 @@ enum nl80211_attrs {
1265 1285
1266 NL80211_ATTR_ROAM_SUPPORT, 1286 NL80211_ATTR_ROAM_SUPPORT,
1267 1287
1288 NL80211_ATTR_SCHED_SCAN_MATCH,
1289 NL80211_ATTR_MAX_MATCH_SETS,
1290
1268 /* add attributes here, update the policy in nl80211.c */ 1291 /* add attributes here, update the policy in nl80211.c */
1269 1292
1270 __NL80211_ATTR_AFTER_LAST, 1293 __NL80211_ATTR_AFTER_LAST,
@@ -1724,6 +1747,26 @@ enum nl80211_reg_rule_attr {
1724}; 1747};
1725 1748
1726/** 1749/**
1750 * enum nl80211_sched_scan_match_attr - scheduled scan match attributes
1751 * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
1752 * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
1753 * only report BSS with matching SSID.
1754 * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
1755 * attribute number currently defined
1756 * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
1757 */
1758enum nl80211_sched_scan_match_attr {
1759 __NL80211_SCHED_SCAN_MATCH_ATTR_INVALID,
1760
1761 NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
1762
1763 /* keep last */
1764 __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
1765 NL80211_SCHED_SCAN_MATCH_ATTR_MAX =
1766 __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1
1767};
1768
1769/**
1727 * enum nl80211_reg_rule_flags - regulatory rule flags 1770 * enum nl80211_reg_rule_flags - regulatory rule flags
1728 * 1771 *
1729 * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed 1772 * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 01c6bde99a4..09024ab617f 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -876,6 +876,15 @@ struct cfg80211_scan_request {
876}; 876};
877 877
878/** 878/**
879 * struct cfg80211_match_set - sets of attributes to match
880 *
881 * @ssid: SSID to be matched
882 */
883struct cfg80211_match_set {
884 struct cfg80211_ssid ssid;
885};
886
887/**
879 * struct cfg80211_sched_scan_request - scheduled scan request description 888 * struct cfg80211_sched_scan_request - scheduled scan request description
880 * 889 *
881 * @ssids: SSIDs to scan for (passed in the probe_reqs in active scans) 890 * @ssids: SSIDs to scan for (passed in the probe_reqs in active scans)
@@ -884,6 +893,11 @@ struct cfg80211_scan_request {
884 * @interval: interval between each scheduled scan cycle 893 * @interval: interval between each scheduled scan cycle
885 * @ie: optional information element(s) to add into Probe Request or %NULL 894 * @ie: optional information element(s) to add into Probe Request or %NULL
886 * @ie_len: length of ie in octets 895 * @ie_len: length of ie in octets
896 * @match_sets: sets of parameters to be matched for a scan result
897 * entry to be considered valid and to be passed to the host
898 * (others are filtered out).
899 * If ommited, all results are passed.
900 * @n_match_sets: number of match sets
887 * @wiphy: the wiphy this was for 901 * @wiphy: the wiphy this was for
888 * @dev: the interface 902 * @dev: the interface
889 * @channels: channels to scan 903 * @channels: channels to scan
@@ -895,6 +909,8 @@ struct cfg80211_sched_scan_request {
895 u32 interval; 909 u32 interval;
896 const u8 *ie; 910 const u8 *ie;
897 size_t ie_len; 911 size_t ie_len;
912 struct cfg80211_match_set *match_sets;
913 int n_match_sets;
898 914
899 /* internal */ 915 /* internal */
900 struct wiphy *wiphy; 916 struct wiphy *wiphy;
@@ -1814,6 +1830,9 @@ struct wiphy_wowlan_support {
1814 * any given scan 1830 * any given scan
1815 * @max_sched_scan_ssids: maximum number of SSIDs the device can scan 1831 * @max_sched_scan_ssids: maximum number of SSIDs the device can scan
1816 * for in any given scheduled scan 1832 * for in any given scheduled scan
1833 * @max_match_sets: maximum number of match sets the device can handle
1834 * when performing a scheduled scan, 0 if filtering is not
1835 * supported.
1817 * @max_scan_ie_len: maximum length of user-controlled IEs device can 1836 * @max_scan_ie_len: maximum length of user-controlled IEs device can
1818 * add to probe request frames transmitted during a scan, must not 1837 * add to probe request frames transmitted during a scan, must not
1819 * include fixed IEs like supported rates 1838 * include fixed IEs like supported rates
@@ -1871,6 +1890,7 @@ struct wiphy {
1871 int bss_priv_size; 1890 int bss_priv_size;
1872 u8 max_scan_ssids; 1891 u8 max_scan_ssids;
1873 u8 max_sched_scan_ssids; 1892 u8 max_sched_scan_ssids;
1893 u8 max_match_sets;
1874 u16 max_scan_ie_len; 1894 u16 max_scan_ie_len;
1875 u16 max_sched_scan_ie_len; 1895 u16 max_sched_scan_ie_len;
1876 1896
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,