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.c77
1 files changed, 73 insertions, 4 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 055e000..320c3fe 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -175,6 +175,15 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
[NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 },
[NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
+ [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED },
+ [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED },
+ [NL80211_ATTR_HIDDEN_SSID] = { .type = NLA_U32 },
+ [NL80211_ATTR_IE_PROBE_RESP] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_DATA_LEN },
+ [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 */
@@ -205,6 +214,12 @@ nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = {
[NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED },
};
+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)
{
@@ -682,8 +697,14 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
dev->wiphy.coverage_class);
NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
dev->wiphy.max_scan_ssids);
+ NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
+ dev->wiphy.max_sched_scan_ssids);
NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
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);
@@ -2213,7 +2234,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
}
nla_nest_end(msg, sinfoattr);
- if (sinfo->assoc_req_ies)
+ if (sinfo->filled & STATION_INFO_ASSOC_REQ_IES)
NLA_PUT(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
sinfo->assoc_req_ies);
@@ -3458,10 +3479,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)
@@ -3497,7 +3519,16 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
tmp)
n_ssids++;
- if (n_ssids > wiphy->max_scan_ssids)
+ 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])
@@ -3505,7 +3536,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
else
ie_len = 0;
- if (ie_len > wiphy->max_scan_ie_len)
+ if (ie_len > wiphy->max_sched_scan_ie_len)
return -EINVAL;
mutex_lock(&rdev->sched_scan_mtx);
@@ -3517,6 +3548,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) {
@@ -3534,6 +3566,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 */
@@ -3598,6 +3642,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,