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
1437 * @aborted: (internal) scan request was notified as aborted1437 * @aborted: (internal) scan request was notified as aborted
1438 * @notified: (internal) scan request was notified as done or aborted1438 * @notified: (internal) scan request was notified as done or aborted
1439 * @no_cck: used to send probe requests at non CCK rate in 2GHz band1439 * @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
1440 */1444 */
1441struct cfg80211_scan_request {1445struct cfg80211_scan_request {
1442 struct cfg80211_ssid *ssids;1446 struct cfg80211_ssid *ssids;
@@ -1451,6 +1455,9 @@ struct cfg80211_scan_request { · 8 unmodified lines
1451 1455
1452 struct wireless_dev *wdev;1456 struct wireless_dev *wdev;
1453 1457
1458 u8 mac_addr[ETH_ALEN] __aligned(2);
1459 u8 mac_addr_mask[ETH_ALEN] __aligned(2);
1460
1454 /* internal */1461 /* internal */
1455 struct wiphy *wiphy;1462 struct wiphy *wiphy;
1456 unsigned long scan_start;1463 unsigned long scan_start;
@@ -1461,6 +1468,17 @@ struct cfg80211_scan_request { · 4 unmodified lines
1461 struct ieee80211_channel *channels[0];1468 struct ieee80211_channel *channels[0];
1462};1469};
1463 1470
1471static 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
1464/**1482/**
1465 * struct cfg80211_match_set - sets of attributes to match1483 * struct cfg80211_match_set - sets of attributes to match
1466 *1484 *
@@ -1494,6 +1512,10 @@ struct cfg80211_match_set { · 27 unmodified lines
1494 * @channels: channels to scan1512 * @channels: channels to scan
1495 * @min_rssi_thold: for drivers only supporting a single threshold, this1513 * @min_rssi_thold: for drivers only supporting a single threshold, this
1496 * contains the minimum over all matchsets1514 * 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
1497 */1519 */
1498struct cfg80211_sched_scan_request {1520struct cfg80211_sched_scan_request {
1499 struct cfg80211_ssid *ssids;1521 struct cfg80211_ssid *ssids;
@@ -1508,6 +1530,9 @@ struct cfg80211_sched_scan_request { · 8 unmodified lines
1508 int n_match_sets;1530 int n_match_sets;
1509 s32 min_rssi_thold;1531 s32 min_rssi_thold;
1510 1532
1533 u8 mac_addr[ETH_ALEN] __aligned(2);
1534 u8 mac_addr_mask[ETH_ALEN] __aligned(2);
1535
1511 /* internal */1536 /* internal */
1512 struct wiphy *wiphy;1537 struct wiphy *wiphy;
1513 struct net_device *dev;1538 struct net_device *dev;
include/uapi/linux/nl80211.h+29−0
@@ -1686,6 +1686,8 @@ enum nl80211_commands { · 1685 unmodified lines
1686 *1686 *
1687 * @NL80211_ATTR_OPER_CLASS: operating class1687 * @NL80211_ATTR_OPER_CLASS: operating class
1688 *1688 *
1689 * @NL80211_ATTR_MAC_MASK: MAC address mask
1690 *
1689 * @NUM_NL80211_ATTR: total number of nl80211_attrs available1691 * @NUM_NL80211_ATTR: total number of nl80211_attrs available
1690 * @NL80211_ATTR_MAX: highest attribute number currently defined1692 * @NL80211_ATTR_MAX: highest attribute number currently defined
1691 * @__NL80211_ATTR_AFTER_LAST: internal use1693 * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2041,6 +2043,8 @@ enum nl80211_attrs { · 349 unmodified lines
2041 2043
2042 NL80211_ATTR_OPER_CLASS,2044 NL80211_ATTR_OPER_CLASS,
2043 2045
2046 NL80211_ATTR_MAC_MASK,
2047
2044 /* add attributes here, update the policy in nl80211.c */2048 /* add attributes here, update the policy in nl80211.c */
2045 2049
2046 __NL80211_ATTR_AFTER_LAST,2050 __NL80211_ATTR_AFTER_LAST,
@@ -4139,6 +4143,18 @@ enum nl80211_ap_sme_features { · 2092 unmodified lines
4139 * See 'macaddr' field in the vif_params (cfg80211.h).4143 * See 'macaddr' field in the vif_params (cfg80211.h).
4140 * @NL80211_FEATURE_TDLS_CHANNEL_SWITCH: Driver supports channel switching when4144 * @NL80211_FEATURE_TDLS_CHANNEL_SWITCH: Driver supports channel switching when
4141 * operating as a TDLS peer.4145 * 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.
4142 */4158 */
4143enum nl80211_feature_flags {4159enum nl80211_feature_flags {
4144 NL80211_FEATURE_SK_TX_STATUS = 1 << 0,4160 NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
@@ -4170,6 +4186,9 @@ enum nl80211_feature_flags { · 25 unmodified lines
4170 NL80211_FEATURE_SUPPORTS_WMM_ADMISSION = 1 << 26,4186 NL80211_FEATURE_SUPPORTS_WMM_ADMISSION = 1 << 26,
4171 NL80211_FEATURE_MAC_ON_CREATE = 1 << 27,4187 NL80211_FEATURE_MAC_ON_CREATE = 1 << 27,
4172 NL80211_FEATURE_TDLS_CHANNEL_SWITCH = 1 << 28,4188 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,
4173};4192};
4174 4193
4175/**4194/**
@@ -4218,11 +4237,21 @@ enum nl80211_connect_failed_reason { · 42 unmodified lines
4218 * dangerous because will destroy stations performance as a lot of frames4237 * dangerous because will destroy stations performance as a lot of frames
4219 * will be lost while scanning off-channel, therefore it must be used only4238 * will be lost while scanning off-channel, therefore it must be used only
4220 * when really needed4239 * 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.
4221 */4249 */
4222enum nl80211_scan_flags {4250enum nl80211_scan_flags {
4223 NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,4251 NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
4224 NL80211_SCAN_FLAG_FLUSH = 1<<1,4252 NL80211_SCAN_FLAG_FLUSH = 1<<1,
4225 NL80211_SCAN_FLAG_AP = 1<<2,4253 NL80211_SCAN_FLAG_AP = 1<<2,
4254 NL80211_SCAN_FLAG_RANDOM_ADDR = 1<<3,
4226};4255};
4227 4256
4228/**4257/**
net/wireless/nl80211.c+83−3
@@ -395,6 +395,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { · 394 unmodified lines
395 [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 },395 [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 },
396 [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },396 [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
397 [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },397 [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
398 [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN },
398};399};
399 400
400/* policy for the key attributes */401/* policy for the key attributes */
@@ -5481,6 +5482,43 @@ static int validate_scan_freqs(struct nlattr *freqs) · 5080 unmodified lines
5481 return n_channels;5482 return n_channels;
5482}5483}
5483 5484
5485static 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
5484static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)5522static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
5485{5523{
5486 struct cfg80211_registered_device *rdev = info->user_ptr[0];5524 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
5658 err = -EOPNOTSUPP;5696 err = -EOPNOTSUPP;
5659 goto out_free;5697 goto out_free;
5660 }5698 }
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 }
5661 }5718 }
5662 5719
5663 request->no_cck =5720 request->no_cck =
@@ -5685,7 +5742,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) · 21 unmodified lines
5685}5742}
5686 5743
5687static struct cfg80211_sched_scan_request *5744static struct cfg80211_sched_scan_request *
5688nl80211_parse_sched_scan(struct wiphy *wiphy,5745nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
5689 struct nlattr **attrs)5746 struct nlattr **attrs)
5690{5747{
5691 struct cfg80211_sched_scan_request *request;5748 struct cfg80211_sched_scan_request *request;
@@ -5934,6 +5991,28 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, · 242 unmodified lines
5934 err = -EOPNOTSUPP;5991 err = -EOPNOTSUPP;
5935 goto out_free;5992 goto out_free;
5936 }5993 }
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 }
5937 }6016 }
5938 6017
5939 request->interval = interval;6018 request->interval = interval;
@@ -5951,6 +6030,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, · 11 unmodified lines
5951{6030{
5952 struct cfg80211_registered_device *rdev = info->user_ptr[0];6031 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5953 struct net_device *dev = info->user_ptr[1];6032 struct net_device *dev = info->user_ptr[1];
6033 struct wireless_dev *wdev = dev->ieee80211_ptr;
5954 int err;6034 int err;
5955 6035
5956 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||6036 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
5960 if (rdev->sched_scan_req)6040 if (rdev->sched_scan_req)
5961 return -EINPROGRESS;6041 return -EINPROGRESS;
5962 6042
5963 rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy,6043 rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
5964 info->attrs);6044 info->attrs);
5965 err = PTR_ERR_OR_ZERO(rdev->sched_scan_req);6045 err = PTR_ERR_OR_ZERO(rdev->sched_scan_req);
5966 if (err)6046 if (err)
@@ -8721,7 +8801,7 @@ static int nl80211_parse_wowlan_nd(struct cfg80211_registered_device *rdev, · 2754 unmodified lines
8721 if (err)8801 if (err)
8722 goto out;8802 goto out;
8723 8803
8724 trig->nd_config = nl80211_parse_sched_scan(&rdev->wiphy, tb);8804 trig->nd_config = nl80211_parse_sched_scan(&rdev->wiphy, NULL, tb);
8725 err = PTR_ERR_OR_ZERO(trig->nd_config);8805 err = PTR_ERR_OR_ZERO(trig->nd_config);
8726 if (err)8806 if (err)
8727 trig->nd_config = NULL;8807 trig->nd_config = NULL;