History

cfg80211: allow drivers to support random MAC addresses for scan

Add the necessary feature flags and a scan flag to support using random MAC addresses for scan while unassociated. The configuration for this supports an arbitrary MAC address value and mask, so that any kind of configuration (e.g. fixed OUI or full 46-bit random) can be requested. Full 46-bit random is the default when no other configuration is passed. Also add a small helper function to use the addr/mask correctly.

Johannes Berg committed 12 years ago

Commit ad2b26a1 parent ff5db433 files · +137 −3Browse files

Unified · Split

3 files
  1. include/net/cfg80211.h +25 −0
  2. include/uapi/linux/nl80211.h +29 −0
  3. net/wireless/nl80211.c +83 −3
include/net/cfg80211.h+25−0
@@ -1437,6 +1437,10 @@ struct cfg80211_ssid { · 1436 unmodified lines
14371437 * @aborted: (internal) scan request was notified as aborted
14381438 * @notified: (internal) scan request was notified as done or aborted
14391439 * @no_cck: used to send probe requests at non CCK rate in 2GHz band
1440+ * @mac_addr: MAC address used with randomisation
1441+ * @mac_addr_mask: MAC address mask used with randomisation, bits that
1442+ * are 0 in the mask should be randomised, bits that are 1 should
1443+ * be taken from the @mac_addr
14401444 */
14411445 struct cfg80211_scan_request {
14421446 struct cfg80211_ssid *ssids;
@@ -1451,6 +1455,9 @@ struct cfg80211_scan_request { · 8 unmodified lines
14511455
14521456 struct wireless_dev *wdev;
14531457
1458+ u8 mac_addr[ETH_ALEN] __aligned(2);
1459+ u8 mac_addr_mask[ETH_ALEN] __aligned(2);
1460+
14541461 /* internal */
14551462 struct wiphy *wiphy;
14561463 unsigned long scan_start;
@@ -1461,6 +1468,17 @@ struct cfg80211_scan_request { · 4 unmodified lines
14611468 struct ieee80211_channel *channels[0];
14621469 };
14631470
1471+static inline void get_random_mask_addr(u8 *buf, const u8 *addr, const u8 *mask)
1472+{
1473+ int i;
1474+
1475+ get_random_bytes(buf, ETH_ALEN);
1476+ for (i = 0; i < ETH_ALEN; i++) {
1477+ buf[i] &= ~mask[i];
1478+ buf[i] |= addr[i] & mask[i];
1479+ }
1480+}
1481+
14641482 /**
14651483 * struct cfg80211_match_set - sets of attributes to match
14661484 *
@@ -1494,6 +1512,10 @@ struct cfg80211_match_set { · 27 unmodified lines
14941512 * @channels: channels to scan
14951513 * @min_rssi_thold: for drivers only supporting a single threshold, this
14961514 * contains the minimum over all matchsets
1515+ * @mac_addr: MAC address used with randomisation
1516+ * @mac_addr_mask: MAC address mask used with randomisation, bits that
1517+ * are 0 in the mask should be randomised, bits that are 1 should
1518+ * be taken from the @mac_addr
14971519 */
14981520 struct cfg80211_sched_scan_request {
14991521 struct cfg80211_ssid *ssids;
@@ -1508,6 +1530,9 @@ struct cfg80211_sched_scan_request { · 8 unmodified lines
15081530 int n_match_sets;
15091531 s32 min_rssi_thold;
15101532
1533+ u8 mac_addr[ETH_ALEN] __aligned(2);
1534+ u8 mac_addr_mask[ETH_ALEN] __aligned(2);
1535+
15111536 /* internal */
15121537 struct wiphy *wiphy;
15131538 struct net_device *dev;
include/uapi/linux/nl80211.h+29−0
@@ -1686,6 +1686,8 @@ enum nl80211_commands { · 1685 unmodified lines
16861686 *
16871687 * @NL80211_ATTR_OPER_CLASS: operating class
16881688 *
1689+ * @NL80211_ATTR_MAC_MASK: MAC address mask
1690+ *
16891691 * @NUM_NL80211_ATTR: total number of nl80211_attrs available
16901692 * @NL80211_ATTR_MAX: highest attribute number currently defined
16911693 * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2041,6 +2043,8 @@ enum nl80211_attrs { · 349 unmodified lines
20412043
20422044 NL80211_ATTR_OPER_CLASS,
20432045
2046+ NL80211_ATTR_MAC_MASK,
2047+
20442048 /* add attributes here, update the policy in nl80211.c */
20452049
20462050 __NL80211_ATTR_AFTER_LAST,
@@ -4139,6 +4143,18 @@ enum nl80211_ap_sme_features { · 2092 unmodified lines
41394143 * See 'macaddr' field in the vif_params (cfg80211.h).
41404144 * @NL80211_FEATURE_TDLS_CHANNEL_SWITCH: Driver supports channel switching when
41414145 * operating as a TDLS peer.
4146+ * @NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR: This device/driver supports using a
4147+ * random MAC address during scan (if the device is unassociated); the
4148+ * %NL80211_SCAN_FLAG_RANDOM_ADDR flag may be set for scans and the MAC
4149+ * address mask/value will be used.
4150+ * @NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR: This device/driver supports
4151+ * using a random MAC address for every scan iteration during scheduled
4152+ * scan (while not associated), the %NL80211_SCAN_FLAG_RANDOM_ADDR may
4153+ * be set for scheduled scan and the MAC address mask/value will be used.
4154+ * @NL80211_FEATURE_ND_RANDOM_MAC_ADDR: This device/driver supports using a
4155+ * random MAC address for every scan iteration during "net detect", i.e.
4156+ * scan in unassociated WoWLAN, the %NL80211_SCAN_FLAG_RANDOM_ADDR may
4157+ * be set for scheduled scan and the MAC address mask/value will be used.
41424158 */
41434159 enum nl80211_feature_flags {
41444160 NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
@@ -4170,6 +4186,9 @@ enum nl80211_feature_flags { · 25 unmodified lines
41704186 NL80211_FEATURE_SUPPORTS_WMM_ADMISSION = 1 << 26,
41714187 NL80211_FEATURE_MAC_ON_CREATE = 1 << 27,
41724188 NL80211_FEATURE_TDLS_CHANNEL_SWITCH = 1 << 28,
4189+ NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR = 1 << 29,
4190+ NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR = 1 << 30,
4191+ NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1 << 31,
41734192 };
41744193
41754194 /**
@@ -4218,11 +4237,21 @@ enum nl80211_connect_failed_reason { · 42 unmodified lines
42184237 * dangerous because will destroy stations performance as a lot of frames
42194238 * will be lost while scanning off-channel, therefore it must be used only
42204239 * when really needed
4240+ * @NL80211_SCAN_FLAG_RANDOM_ADDR: use a random MAC address for this scan (or
4241+ * for scheduled scan: a different one for every scan iteration). When the
4242+ * flag is set, depending on device capabilities the @NL80211_ATTR_MAC and
4243+ * @NL80211_ATTR_MAC_MASK attributes may also be given in which case only
4244+ * the masked bits will be preserved from the MAC address and the remainder
4245+ * randomised. If the attributes are not given full randomisation (46 bits,
4246+ * locally administered 1, multicast 0) is assumed.
4247+ * This flag must not be requested when the feature isn't supported, check
4248+ * the nl80211 feature flags for the device.
42214249 */
42224250 enum nl80211_scan_flags {
42234251 NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
42244252 NL80211_SCAN_FLAG_FLUSH = 1<<1,
42254253 NL80211_SCAN_FLAG_AP = 1<<2,
4254+ NL80211_SCAN_FLAG_RANDOM_ADDR = 1<<3,
42264255 };
42274256
42284257 /**
net/wireless/nl80211.c+83−3
@@ -395,6 +395,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { · 394 unmodified lines
395395 [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 },
396396 [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
397397 [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
398+ [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN },
398399 };
399400
400401 /* policy for the key attributes */
@@ -5481,6 +5482,43 @@ static int validate_scan_freqs(struct nlattr *freqs) · 5080 unmodified lines
54815482 return n_channels;
54825483 }
54835484
5485+static int nl80211_parse_random_mac(struct nlattr **attrs,
5486+ u8 *mac_addr, u8 *mac_addr_mask)
5487+{
5488+ int i;
5489+
5490+ if (!attrs[NL80211_ATTR_MAC] && !attrs[NL80211_ATTR_MAC_MASK]) {
5491+ memset(mac_addr, 0, ETH_ALEN);
5492+ memset(mac_addr_mask, 0, ETH_ALEN);
5493+ mac_addr[0] = 0x2;
5494+ mac_addr_mask[0] = 0x3;
5495+
5496+ return 0;
5497+ }
5498+
5499+ /* need both or none */
5500+ if (!attrs[NL80211_ATTR_MAC] || !attrs[NL80211_ATTR_MAC_MASK])
5501+ return -EINVAL;
5502+
5503+ memcpy(mac_addr, nla_data(attrs[NL80211_ATTR_MAC]), ETH_ALEN);
5504+ memcpy(mac_addr_mask, nla_data(attrs[NL80211_ATTR_MAC_MASK]), ETH_ALEN);
5505+
5506+ /* don't allow or configure an mcast address */
5507+ if (!is_multicast_ether_addr(mac_addr_mask) ||
5508+ is_multicast_ether_addr(mac_addr))
5509+ return -EINVAL;
5510+
5511+ /*
5512+ * allow users to pass a MAC address that has bits set outside
5513+ * of the mask, but don't bother drivers with having to deal
5514+ * with such bits
5515+ */
5516+ for (i = 0; i < ETH_ALEN; i++)
5517+ mac_addr[i] &= mac_addr_mask[i];
5518+
5519+ return 0;
5520+}
5521+
54845522 static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
54855523 {
54865524 struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -5658,6 +5696,25 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) · 171 unmodified lines
56585696 err = -EOPNOTSUPP;
56595697 goto out_free;
56605698 }
5699+
5700+ if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
5701+ if (!(wiphy->features &
5702+ NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR)) {
5703+ err = -EOPNOTSUPP;
5704+ goto out_free;
5705+ }
5706+
5707+ if (wdev->current_bss) {
5708+ err = -EOPNOTSUPP;
5709+ goto out_free;
5710+ }
5711+
5712+ err = nl80211_parse_random_mac(info->attrs,
5713+ request->mac_addr,
5714+ request->mac_addr_mask);
5715+ if (err)
5716+ goto out_free;
5717+ }
56615718 }
56625719
56635720 request->no_cck =
@@ -5685,7 +5742,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) · 21 unmodified lines
56855742 }
56865743
56875744 static struct cfg80211_sched_scan_request *
5688−nl80211_parse_sched_scan(struct wiphy *wiphy,
5745+nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
56895746 struct nlattr **attrs)
56905747 {
56915748 struct cfg80211_sched_scan_request *request;
@@ -5934,6 +5991,28 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, · 242 unmodified lines
59345991 err = -EOPNOTSUPP;
59355992 goto out_free;
59365993 }
5994+
5995+ if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
5996+ u32 flg = NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
5997+
5998+ if (!wdev) /* must be net-detect */
5999+ flg = NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
6000+
6001+ if (!(wiphy->features & flg)) {
6002+ err = -EOPNOTSUPP;
6003+ goto out_free;
6004+ }
6005+
6006+ if (wdev && wdev->current_bss) {
6007+ err = -EOPNOTSUPP;
6008+ goto out_free;
6009+ }
6010+
6011+ err = nl80211_parse_random_mac(attrs, request->mac_addr,
6012+ request->mac_addr_mask);
6013+ if (err)
6014+ goto out_free;
6015+ }
59376016 }
59386017
59396018 request->interval = interval;
@@ -5951,6 +6030,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, · 11 unmodified lines
59516030 {
59526031 struct cfg80211_registered_device *rdev = info->user_ptr[0];
59536032 struct net_device *dev = info->user_ptr[1];
6033+ struct wireless_dev *wdev = dev->ieee80211_ptr;
59546034 int err;
59556035
59566036 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
@@ -5960,7 +6040,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, · 3 unmodified lines
59606040 if (rdev->sched_scan_req)
59616041 return -EINPROGRESS;
59626042
5963− rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy,
6043+ rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
59646044 info->attrs);
59656045 err = PTR_ERR_OR_ZERO(rdev->sched_scan_req);
59666046 if (err)
@@ -8721,7 +8801,7 @@ static int nl80211_parse_wowlan_nd(struct cfg80211_registered_device *rdev, · 2754 unmodified lines
87218801 if (err)
87228802 goto out;
87238803
8724− trig->nd_config = nl80211_parse_sched_scan(&rdev->wiphy, tb);
8804+ trig->nd_config = nl80211_parse_sched_scan(&rdev->wiphy, NULL, tb);
87258805 err = PTR_ERR_OR_ZERO(trig->nd_config);
87268806 if (err)
87278807 trig->nd_config = NULL;