|
@@ -190,6 +190,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
|
|
|
[NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY,
|
|
|
.len = IEEE80211_MAX_DATA_LEN },
|
|
|
[NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
|
|
|
+ [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
|
|
|
};
|
|
|
|
|
|
/* 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 },
|
|
|
};
|
|
|
|
|
|
+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 */
|
|
|
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);
|
|
|
NLA_PUT_U16(msg, NL80211_ATTR_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)
|
|
|
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 nlattr *attr;
|
|
|
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;
|
|
|
enum ieee80211_band band;
|
|
|
size_t ie_len;
|
|
|
+ struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
|
|
|
|
|
|
if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
|
|
|
!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)
|
|
|
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])
|
|
|
ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
|
|
|
else
|
|
@@ -3691,6 +3710,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
|
|
|
|
|
|
request = kzalloc(sizeof(*request)
|
|
|
+ sizeof(*request->ssids) * n_ssids
|
|
|
+ + sizeof(*request->match_sets) * n_match_sets
|
|
|
+ sizeof(*request->channels) * n_channels
|
|
|
+ ie_len, GFP_KERNEL);
|
|
|
if (!request) {
|
|
@@ -3708,6 +3728,18 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
|
|
|
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;
|
|
|
if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
|
|
|
/* 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]) {
|
|
|
request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
|
|
|
memcpy((void *)request->ie,
|