nl80211/cfg80211: add match filtering for sched_scan
Introduce filtering for scheduled scans to reduce the number of unnecessary results (which cause useless wake-ups). Add a new nested attribute where sets of parameters to be matched can be passed when starting a scheduled scan. Only scan results that match any of the sets will be returned. At this point, the set consists of a single parameter, an SSID. This can be easily extended in the future to support more complex matches. Signed-off-by: Luciano Coelho <coelho@ti.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
committed by
John W. Linville
parent
cedb5412ba
commit
a1f1c21c18
@@ -769,6 +769,8 @@ enum nl80211_commands {
|
|||||||
* that can be added to a scan request
|
* that can be added to a scan request
|
||||||
* @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information
|
* @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information
|
||||||
* elements that can be added to a scheduled scan request
|
* elements that can be added to a scheduled scan request
|
||||||
|
* @NL80211_ATTR_MAX_MATCH_SETS: maximum number of sets that can be
|
||||||
|
* used with @NL80211_ATTR_SCHED_SCAN_MATCH, a wiphy attribute.
|
||||||
*
|
*
|
||||||
* @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
|
* @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
|
||||||
* @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
|
* @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
|
||||||
@@ -1011,6 +1013,24 @@ enum nl80211_commands {
|
|||||||
|
|
||||||
* @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan
|
* @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan
|
||||||
* cycles, in msecs.
|
* cycles, in msecs.
|
||||||
|
|
||||||
|
* @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more
|
||||||
|
* sets of attributes to match during scheduled scans. Only BSSs
|
||||||
|
* that match any of the sets will be reported. These are
|
||||||
|
* pass-thru filter rules.
|
||||||
|
* For a match to succeed, the BSS must match all attributes of a
|
||||||
|
* set. Since not every hardware supports matching all types of
|
||||||
|
* attributes, there is no guarantee that the reported BSSs are
|
||||||
|
* fully complying with the match sets and userspace needs to be
|
||||||
|
* able to ignore them by itself.
|
||||||
|
* Thus, the implementation is somewhat hardware-dependent, but
|
||||||
|
* this is only an optimization and the userspace application
|
||||||
|
* needs to handle all the non-filtered results anyway.
|
||||||
|
* If the match attributes don't make sense when combined with
|
||||||
|
* the values passed in @NL80211_ATTR_SCAN_SSIDS (eg. if an SSID
|
||||||
|
* is included in the probe request, but the match attributes
|
||||||
|
* will never let it go through), -EINVAL may be returned.
|
||||||
|
* If ommited, no filtering is done.
|
||||||
*
|
*
|
||||||
* @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported
|
* @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported
|
||||||
* interface combinations. In each nested item, it contains attributes
|
* interface combinations. In each nested item, it contains attributes
|
||||||
@@ -1265,6 +1285,9 @@ enum nl80211_attrs {
|
|||||||
|
|
||||||
NL80211_ATTR_ROAM_SUPPORT,
|
NL80211_ATTR_ROAM_SUPPORT,
|
||||||
|
|
||||||
|
NL80211_ATTR_SCHED_SCAN_MATCH,
|
||||||
|
NL80211_ATTR_MAX_MATCH_SETS,
|
||||||
|
|
||||||
/* add attributes here, update the policy in nl80211.c */
|
/* add attributes here, update the policy in nl80211.c */
|
||||||
|
|
||||||
__NL80211_ATTR_AFTER_LAST,
|
__NL80211_ATTR_AFTER_LAST,
|
||||||
@@ -1723,6 +1746,26 @@ enum nl80211_reg_rule_attr {
|
|||||||
NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
|
NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum nl80211_sched_scan_match_attr - scheduled scan match attributes
|
||||||
|
* @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
|
||||||
|
* @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
|
||||||
|
* only report BSS with matching SSID.
|
||||||
|
* @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
|
||||||
|
* attribute number currently defined
|
||||||
|
* @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
|
||||||
|
*/
|
||||||
|
enum nl80211_sched_scan_match_attr {
|
||||||
|
__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID,
|
||||||
|
|
||||||
|
NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
|
||||||
|
|
||||||
|
/* keep last */
|
||||||
|
__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
|
||||||
|
NL80211_SCHED_SCAN_MATCH_ATTR_MAX =
|
||||||
|
__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum nl80211_reg_rule_flags - regulatory rule flags
|
* enum nl80211_reg_rule_flags - regulatory rule flags
|
||||||
*
|
*
|
||||||
|
@@ -875,6 +875,15 @@ struct cfg80211_scan_request {
|
|||||||
struct ieee80211_channel *channels[0];
|
struct ieee80211_channel *channels[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct cfg80211_match_set - sets of attributes to match
|
||||||
|
*
|
||||||
|
* @ssid: SSID to be matched
|
||||||
|
*/
|
||||||
|
struct cfg80211_match_set {
|
||||||
|
struct cfg80211_ssid ssid;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct cfg80211_sched_scan_request - scheduled scan request description
|
* struct cfg80211_sched_scan_request - scheduled scan request description
|
||||||
*
|
*
|
||||||
@@ -884,6 +893,11 @@ struct cfg80211_scan_request {
|
|||||||
* @interval: interval between each scheduled scan cycle
|
* @interval: interval between each scheduled scan cycle
|
||||||
* @ie: optional information element(s) to add into Probe Request or %NULL
|
* @ie: optional information element(s) to add into Probe Request or %NULL
|
||||||
* @ie_len: length of ie in octets
|
* @ie_len: length of ie in octets
|
||||||
|
* @match_sets: sets of parameters to be matched for a scan result
|
||||||
|
* entry to be considered valid and to be passed to the host
|
||||||
|
* (others are filtered out).
|
||||||
|
* If ommited, all results are passed.
|
||||||
|
* @n_match_sets: number of match sets
|
||||||
* @wiphy: the wiphy this was for
|
* @wiphy: the wiphy this was for
|
||||||
* @dev: the interface
|
* @dev: the interface
|
||||||
* @channels: channels to scan
|
* @channels: channels to scan
|
||||||
@@ -895,6 +909,8 @@ struct cfg80211_sched_scan_request {
|
|||||||
u32 interval;
|
u32 interval;
|
||||||
const u8 *ie;
|
const u8 *ie;
|
||||||
size_t ie_len;
|
size_t ie_len;
|
||||||
|
struct cfg80211_match_set *match_sets;
|
||||||
|
int n_match_sets;
|
||||||
|
|
||||||
/* internal */
|
/* internal */
|
||||||
struct wiphy *wiphy;
|
struct wiphy *wiphy;
|
||||||
@@ -1814,6 +1830,9 @@ struct wiphy_wowlan_support {
|
|||||||
* any given scan
|
* any given scan
|
||||||
* @max_sched_scan_ssids: maximum number of SSIDs the device can scan
|
* @max_sched_scan_ssids: maximum number of SSIDs the device can scan
|
||||||
* for in any given scheduled scan
|
* for in any given scheduled scan
|
||||||
|
* @max_match_sets: maximum number of match sets the device can handle
|
||||||
|
* when performing a scheduled scan, 0 if filtering is not
|
||||||
|
* supported.
|
||||||
* @max_scan_ie_len: maximum length of user-controlled IEs device can
|
* @max_scan_ie_len: maximum length of user-controlled IEs device can
|
||||||
* add to probe request frames transmitted during a scan, must not
|
* add to probe request frames transmitted during a scan, must not
|
||||||
* include fixed IEs like supported rates
|
* include fixed IEs like supported rates
|
||||||
@@ -1871,6 +1890,7 @@ struct wiphy {
|
|||||||
int bss_priv_size;
|
int bss_priv_size;
|
||||||
u8 max_scan_ssids;
|
u8 max_scan_ssids;
|
||||||
u8 max_sched_scan_ssids;
|
u8 max_sched_scan_ssids;
|
||||||
|
u8 max_match_sets;
|
||||||
u16 max_scan_ie_len;
|
u16 max_scan_ie_len;
|
||||||
u16 max_sched_scan_ie_len;
|
u16 max_sched_scan_ie_len;
|
||||||
|
|
||||||
|
@@ -190,6 +190,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
|
|||||||
[NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY,
|
[NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY,
|
||||||
.len = IEEE80211_MAX_DATA_LEN },
|
.len = IEEE80211_MAX_DATA_LEN },
|
||||||
[NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
|
[NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
|
||||||
|
[NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* policy for the key attributes */
|
/* policy for the key attributes */
|
||||||
@@ -232,6 +233,12 @@ nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
|
|||||||
[NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
|
[NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct nla_policy
|
||||||
|
nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
|
||||||
|
[NL80211_ATTR_SCHED_SCAN_MATCH_SSID] = { .type = NLA_BINARY,
|
||||||
|
.len = IEEE80211_MAX_SSID_LEN },
|
||||||
|
};
|
||||||
|
|
||||||
/* ifidx get helper */
|
/* ifidx get helper */
|
||||||
static int nl80211_get_ifidx(struct netlink_callback *cb)
|
static int nl80211_get_ifidx(struct netlink_callback *cb)
|
||||||
{
|
{
|
||||||
@@ -715,6 +722,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
|||||||
dev->wiphy.max_scan_ie_len);
|
dev->wiphy.max_scan_ie_len);
|
||||||
NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
|
NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
|
||||||
dev->wiphy.max_sched_scan_ie_len);
|
dev->wiphy.max_sched_scan_ie_len);
|
||||||
|
NLA_PUT_U8(msg, NL80211_ATTR_MAX_MATCH_SETS,
|
||||||
|
dev->wiphy.max_match_sets);
|
||||||
|
|
||||||
if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)
|
if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)
|
||||||
NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN);
|
NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN);
|
||||||
@@ -3632,10 +3641,11 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
|
|||||||
struct net_device *dev = info->user_ptr[1];
|
struct net_device *dev = info->user_ptr[1];
|
||||||
struct nlattr *attr;
|
struct nlattr *attr;
|
||||||
struct wiphy *wiphy;
|
struct wiphy *wiphy;
|
||||||
int err, tmp, n_ssids = 0, n_channels, i;
|
int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i;
|
||||||
u32 interval;
|
u32 interval;
|
||||||
enum ieee80211_band band;
|
enum ieee80211_band band;
|
||||||
size_t ie_len;
|
size_t ie_len;
|
||||||
|
struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
|
||||||
|
|
||||||
if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
|
if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
|
||||||
!rdev->ops->sched_scan_start)
|
!rdev->ops->sched_scan_start)
|
||||||
@@ -3674,6 +3684,15 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
|
|||||||
if (n_ssids > wiphy->max_sched_scan_ssids)
|
if (n_ssids > wiphy->max_sched_scan_ssids)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH])
|
||||||
|
nla_for_each_nested(attr,
|
||||||
|
info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
|
||||||
|
tmp)
|
||||||
|
n_match_sets++;
|
||||||
|
|
||||||
|
if (n_match_sets > wiphy->max_match_sets)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (info->attrs[NL80211_ATTR_IE])
|
if (info->attrs[NL80211_ATTR_IE])
|
||||||
ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
|
ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
|
||||||
else
|
else
|
||||||
@@ -3691,6 +3710,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
|
|||||||
|
|
||||||
request = kzalloc(sizeof(*request)
|
request = kzalloc(sizeof(*request)
|
||||||
+ sizeof(*request->ssids) * n_ssids
|
+ sizeof(*request->ssids) * n_ssids
|
||||||
|
+ sizeof(*request->match_sets) * n_match_sets
|
||||||
+ sizeof(*request->channels) * n_channels
|
+ sizeof(*request->channels) * n_channels
|
||||||
+ ie_len, GFP_KERNEL);
|
+ ie_len, GFP_KERNEL);
|
||||||
if (!request) {
|
if (!request) {
|
||||||
@@ -3708,6 +3728,18 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
|
|||||||
request->ie = (void *)(request->channels + n_channels);
|
request->ie = (void *)(request->channels + n_channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (n_match_sets) {
|
||||||
|
if (request->ie)
|
||||||
|
request->match_sets = (void *)(request->ie + ie_len);
|
||||||
|
else if (request->ssids)
|
||||||
|
request->match_sets =
|
||||||
|
(void *)(request->ssids + n_ssids);
|
||||||
|
else
|
||||||
|
request->match_sets =
|
||||||
|
(void *)(request->channels + n_channels);
|
||||||
|
}
|
||||||
|
request->n_match_sets = n_match_sets;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
|
if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
|
||||||
/* user specified, bail out if channel not found */
|
/* user specified, bail out if channel not found */
|
||||||
@@ -3772,6 +3804,31 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
|
||||||
|
nla_for_each_nested(attr,
|
||||||
|
info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
|
||||||
|
tmp) {
|
||||||
|
struct nlattr *ssid;
|
||||||
|
|
||||||
|
nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
|
||||||
|
nla_data(attr), nla_len(attr),
|
||||||
|
nl80211_match_policy);
|
||||||
|
ssid = tb[NL80211_ATTR_SCHED_SCAN_MATCH_SSID];
|
||||||
|
if (ssid) {
|
||||||
|
if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
memcpy(request->match_sets[i].ssid.ssid,
|
||||||
|
nla_data(ssid), nla_len(ssid));
|
||||||
|
request->match_sets[i].ssid.ssid_len =
|
||||||
|
nla_len(ssid);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (info->attrs[NL80211_ATTR_IE]) {
|
if (info->attrs[NL80211_ATTR_IE]) {
|
||||||
request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
|
request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
|
||||||
memcpy((void *)request->ie,
|
memcpy((void *)request->ie,
|
||||||
|
Reference in New Issue
Block a user