nl80211: add support for BSSIDs in scheduled scan matchsets
authorArend Van Spriel <arend.vanspriel@broadcom.com>
Fri, 21 Apr 2017 12:05:01 +0000 (13:05 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 26 Apr 2017 21:17:39 +0000 (23:17 +0200)
This patch allows for the scheduled scan request to specify matchsets
for specific BSSIDs.

Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
[docs, netlink policy fix]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/cfg80211.h
include/uapi/linux/nl80211.h
net/wireless/nl80211.c

index 43c0f389c27383d25cb9d9078f1259d4bdda7517..4058518e267a61099d580b62266fed7c0bbafd8c 100644 (file)
@@ -1613,11 +1613,15 @@ static inline void get_random_mask_addr(u8 *buf, const u8 *addr, const u8 *mask)
 /**
  * struct cfg80211_match_set - sets of attributes to match
  *
- * @ssid: SSID to be matched; may be zero-length for no match (RSSI only)
+ * @ssid: SSID to be matched; may be zero-length in case of BSSID match
+ *     or no match (RSSI only)
+ * @bssid: BSSID to be matched; may be all-zero BSSID in case of SSID match
+ *     or no match (RSSI only)
  * @rssi_thold: don't report scan results below this threshold (in s32 dBm)
  */
 struct cfg80211_match_set {
        struct cfg80211_ssid ssid;
+       u8 bssid[ETH_ALEN];
        s32 rssi_thold;
 };
 
index f34127d241e58f35253dbc6f8922a06cbe2b3b81..b8c44b98f12d4c42d4f88a73049da962be2678b2 100644 (file)
@@ -3194,6 +3194,7 @@ enum nl80211_reg_rule_attr {
  * @__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.
+ *     (This cannot be used together with BSSID.)
  * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a
  *     BSS in scan results. Filtering is turned off if not specified. Note that
  *     if this attribute is in a match set of its own, then it is treated as
@@ -3209,6 +3210,8 @@ enum nl80211_reg_rule_attr {
  *     BSS-es in the specified band is to be adjusted before doing
  *     RSSI-based BSS selection. The attribute value is a packed structure
  *     value as specified by &struct nl80211_bss_select_rssi_adjust.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_BSSID: BSSID to be used for matching
+ *     (this cannot be used together with SSID).
  * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
  *     attribute number currently defined
  * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@@ -3220,6 +3223,7 @@ enum nl80211_sched_scan_match_attr {
        NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
        NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI,
        NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST,
+       NL80211_SCHED_SCAN_MATCH_ATTR_BSSID,
 
        /* keep last */
        __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
index ac7e2314f9ecfba5a14c193eaeef38c97827d47e..dce69a87d4d04b34b0b83a8a15a87a2e8fd494f5 100644 (file)
@@ -497,6 +497,7 @@ static const struct nla_policy
 nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
        [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
                                                 .len = IEEE80211_MAX_SSID_LEN },
+       [NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = { .len = ETH_ALEN },
        [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
 };
 
@@ -7036,8 +7037,15 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
                                               NULL);
                        if (err)
                                return ERR_PTR(err);
+
+                       /* SSID and BSSID are mutually exclusive */
+                       if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] &&
+                           tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID])
+                               return ERR_PTR(-EINVAL);
+
                        /* add other standalone attributes here */
-                       if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) {
+                       if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] ||
+                           tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID]) {
                                n_match_sets++;
                                continue;
                        }
@@ -7208,7 +7216,7 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
                nla_for_each_nested(attr,
                                    attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
                                    tmp) {
-                       struct nlattr *ssid, *rssi;
+                       struct nlattr *ssid, *bssid, *rssi;
 
                        err = nla_parse_nested(tb,
                                               NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
@@ -7217,7 +7225,8 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
                        if (err)
                                goto out_free;
                        ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
-                       if (ssid) {
+                       bssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID];
+                       if (ssid || bssid) {
                                if (WARN_ON(i >= n_match_sets)) {
                                        /* this indicates a programming error,
                                         * the loop above should have verified
@@ -7227,14 +7236,25 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
                                        goto out_free;
                                }
 
-                               if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
-                                       err = -EINVAL;
-                                       goto out_free;
+                               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);
+                               }
+                               if (bssid) {
+                                       if (nla_len(bssid) != ETH_ALEN) {
+                                               err = -EINVAL;
+                                               goto out_free;
+                                       }
+                                       memcpy(request->match_sets[i].bssid,
+                                              nla_data(bssid), ETH_ALEN);
                                }
-                               memcpy(request->match_sets[i].ssid.ssid,
-                                      nla_data(ssid), nla_len(ssid));
-                               request->match_sets[i].ssid.ssid_len =
-                                       nla_len(ssid);
+
                                /* special attribute - old implementation w/a */
                                request->match_sets[i].rssi_thold =
                                        default_match_rssi;