aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2014-06-12 15:39:05 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-11-19 12:45:52 -0500
commitad2b26abc157460ca6fac1a53a2bfeade283adfa (patch)
tree81f73219cf0132dca99028fe1a8f4a26805d5247 /net/wireless/nl80211.c
parentff5db4392c75e005882dd93641b2caa436437dd6 (diff)
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. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c86
1 files changed, 83 insertions, 3 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 3ec7dc557960..dd5a827f9cb0 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -395,6 +395,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
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)
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)
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)
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,
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,
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,
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,
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;