Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a107eec6 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "cfg80211: Define macro to indicate support for random mac address for scan"

parents 972d2102 d767e45e
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ struct wiphy;
#define CFG80211_DISCONNECTED_V2 1
#define CFG80211_CONNECT_TIMEOUT 1
#define CFG80211_INFORM_BSS_FRAME_DATA 1
#define CFG80211_SCAN_RANDOM_MAC_ADDR 1

/*
 * wireless hardware capability structures
@@ -1512,6 +1513,10 @@ struct cfg80211_ssid {
 * @aborted: (internal) scan request was notified as aborted
 * @notified: (internal) scan request was notified as done or aborted
 * @no_cck: used to send probe requests at non CCK rate in 2GHz band
 * @mac_addr: MAC address used with randomisation
 * @mac_addr_mask: MAC address mask used with randomisation, bits that
 *	are 0 in the mask should be randomised, bits that are 1 should
 *	be taken from the @mac_addr
 * @bssid: BSSID to scan for (most commonly, the wildcard BSSID)
 */
struct cfg80211_scan_request {
@@ -1529,6 +1534,9 @@ struct cfg80211_scan_request {

	u8 bssid[ETH_ALEN] __aligned(2);

	u8 mac_addr[ETH_ALEN] __aligned(2);
	u8 mac_addr_mask[ETH_ALEN] __aligned(2);

	/* internal */
	struct wiphy *wiphy;
	unsigned long scan_start;
@@ -1539,6 +1547,17 @@ struct cfg80211_scan_request {
	struct ieee80211_channel *channels[0];
};

static inline void get_random_mask_addr(u8 *buf, const u8 *addr, const u8 *mask)
{
	int i;

	get_random_bytes(buf, ETH_ALEN);
	for (i = 0; i < ETH_ALEN; i++) {
		buf[i] &= ~mask[i];
		buf[i] |= addr[i] & mask[i];
	}
}

/**
 * struct cfg80211_match_set - sets of attributes to match
 *
@@ -1572,6 +1591,10 @@ struct cfg80211_match_set {
 * @channels: channels to scan
 * @min_rssi_thold: for drivers only supporting a single threshold, this
 *	contains the minimum over all matchsets
 * @mac_addr: MAC address used with randomisation
 * @mac_addr_mask: MAC address mask used with randomisation, bits that
 *	are 0 in the mask should be randomised, bits that are 1 should
 *	be taken from the @mac_addr
 * @owner_nlportid: netlink portid of owner (if this should is a request
 *	owned by a particular socket)
 */
@@ -1588,6 +1611,9 @@ struct cfg80211_sched_scan_request {
	int n_match_sets;
	s32 min_rssi_thold;

	u8 mac_addr[ETH_ALEN] __aligned(2);
	u8 mac_addr_mask[ETH_ALEN] __aligned(2);

	/* internal */
	struct wiphy *wiphy;
	struct net_device *dev;
+25 −0
Original line number Diff line number Diff line
@@ -4212,6 +4212,18 @@ enum nl80211_ap_sme_features {
 *	multiplexing powersave, ie. can turn off all but one chain
 *	and then wake the rest up as required after, for example,
 *	rts/cts handshake.
 * @NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR: This device/driver supports using a
 *	random MAC address during scan (if the device is unassociated); the
 *	%NL80211_SCAN_FLAG_RANDOM_ADDR flag may be set for scans and the MAC
 *	address mask/value will be used.
 * @NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR: This device/driver supports
 *	using a random MAC address for every scan iteration during scheduled
 *	scan (while not associated), the %NL80211_SCAN_FLAG_RANDOM_ADDR may
 *	be set for scheduled scan and the MAC address mask/value will be used.
 * @NL80211_FEATURE_ND_RANDOM_MAC_ADDR: This device/driver supports using a
 *	random MAC address for every scan iteration during "net detect", i.e.
 *	scan in unassociated WoWLAN, the %NL80211_SCAN_FLAG_RANDOM_ADDR may
 *	be set for scheduled scan and the MAC address mask/value will be used.
 */
enum nl80211_feature_flags {
	NL80211_FEATURE_SK_TX_STATUS			= 1 << 0,
@@ -4240,6 +4252,9 @@ enum nl80211_feature_flags {
	NL80211_FEATURE_ACKTO_ESTIMATION		= 1 << 23,
	NL80211_FEATURE_STATIC_SMPS			= 1 << 24,
	NL80211_FEATURE_DYNAMIC_SMPS			= 1 << 25,
	NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR		= 1 << 29,
	NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR	= 1 << 30,
	NL80211_FEATURE_ND_RANDOM_MAC_ADDR		= 1 << 31,
};

/**
@@ -4288,11 +4303,21 @@ enum nl80211_connect_failed_reason {
 *	dangerous because will destroy stations performance as a lot of frames
 *	will be lost while scanning off-channel, therefore it must be used only
 *	when really needed
 * @NL80211_SCAN_FLAG_RANDOM_ADDR: use a random MAC address for this scan (or
 *	for scheduled scan: a different one for every scan iteration). When the
 *	flag is set, depending on device capabilities the @NL80211_ATTR_MAC and
 *	@NL80211_ATTR_MAC_MASK attributes may also be given in which case only
 *	the masked bits will be preserved from the MAC address and the remainder
 *	randomised. If the attributes are not given full randomisation (46 bits,
 *	locally administered 1, multicast 0) is assumed.
 *	This flag must not be requested when the feature isn't supported, check
 *	the nl80211 feature flags for the device.
 */
enum nl80211_scan_flags {
	NL80211_SCAN_FLAG_LOW_PRIORITY			= 1<<0,
	NL80211_SCAN_FLAG_FLUSH				= 1<<1,
	NL80211_SCAN_FLAG_AP				= 1<<2,
	NL80211_SCAN_FLAG_RANDOM_ADDR			= 1<<3,
};

/**
+155 −61
Original line number Diff line number Diff line
@@ -395,6 +395,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
	[NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 },
	[NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
	[NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
	[NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN },
	[NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
};

@@ -5724,6 +5725,43 @@ static int validate_scan_freqs(struct nlattr *freqs)
	return n_channels;
}

static int nl80211_parse_random_mac(struct nlattr **attrs,
				    u8 *mac_addr, u8 *mac_addr_mask)
{
	int i;

	if (!attrs[NL80211_ATTR_MAC] && !attrs[NL80211_ATTR_MAC_MASK]) {
		memset(mac_addr, 0, ETH_ALEN);
		memset(mac_addr_mask, 0, ETH_ALEN);
		mac_addr[0] = 0x2;
		mac_addr_mask[0] = 0x3;

		return 0;
	}

	/* need both or none */
	if (!attrs[NL80211_ATTR_MAC] || !attrs[NL80211_ATTR_MAC_MASK])
		return -EINVAL;

	memcpy(mac_addr, nla_data(attrs[NL80211_ATTR_MAC]), ETH_ALEN);
	memcpy(mac_addr_mask, nla_data(attrs[NL80211_ATTR_MAC_MASK]), ETH_ALEN);

	/* don't allow or configure an mcast address */
	if (!is_multicast_ether_addr(mac_addr_mask) ||
	    is_multicast_ether_addr(mac_addr))
		return -EINVAL;

	/*
	 * allow users to pass a MAC address that has bits set outside
	 * of the mask, but don't bother drivers with having to deal
	 * with such bits
	 */
	for (i = 0; i < ETH_ALEN; i++)
		mac_addr[i] &= mac_addr_mask[i];

	return 0;
}

static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -5901,6 +5939,25 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
			err = -EOPNOTSUPP;
			goto out_free;
		}

		if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
			if (!(wiphy->features &
					NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR)) {
				err = -EOPNOTSUPP;
				goto out_free;
			}

			if (wdev->current_bss) {
				err = -EOPNOTSUPP;
				goto out_free;
			}

			err = nl80211_parse_random_mac(info->attrs,
						       request->mac_addr,
						       request->mac_addr_mask);
			if (err)
				goto out_free;
		}
	}

	request->no_cck =
@@ -5951,14 +6008,12 @@ static int nl80211_abort_scan(struct sk_buff *skb, struct genl_info *info)
	return 0;
}

static int nl80211_start_sched_scan(struct sk_buff *skb,
				    struct genl_info *info)
static struct cfg80211_sched_scan_request *
nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
			 struct nlattr **attrs)
{
	struct cfg80211_sched_scan_request *request;
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	struct nlattr *attr;
	struct wiphy *wiphy;
	int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i;
	u32 interval;
	enum ieee80211_band band;
@@ -5966,38 +6021,32 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
	struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
	s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;

	if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
	    !rdev->ops->sched_scan_start)
		return -EOPNOTSUPP;

	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
		return -EINVAL;
	if (!is_valid_ie_attr(attrs[NL80211_ATTR_IE]))
		return ERR_PTR(-EINVAL);

	if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
		return -EINVAL;
	if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
		return ERR_PTR(-EINVAL);

	interval = nla_get_u32(info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
	interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
	if (interval == 0)
		return -EINVAL;

	wiphy = &rdev->wiphy;
		return ERR_PTR(-EINVAL);

	if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
	if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
		n_channels = validate_scan_freqs(
				info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
				attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
		if (!n_channels)
			return -EINVAL;
			return ERR_PTR(-EINVAL);
	} else {
		n_channels = ieee80211_get_num_supported_channels(wiphy);
	}

	if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
		nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS],
	if (attrs[NL80211_ATTR_SCAN_SSIDS])
		nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
				    tmp)
			n_ssids++;

	if (n_ssids > wiphy->max_sched_scan_ssids)
		return -EINVAL;
		return ERR_PTR(-EINVAL);

	/*
	 * First, count the number of 'real' matchsets. Due to an issue with
@@ -6008,9 +6057,9 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
	 * older userspace that treated a matchset with only the RSSI as the
	 * global RSSI for all other matchsets - if there are other matchsets.
	 */
	if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
	if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
		nla_for_each_nested(attr,
				    info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
				    attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
				    tmp) {
			struct nlattr *rssi;

@@ -6018,7 +6067,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
					nla_data(attr), nla_len(attr),
					nl80211_match_policy);
			if (err)
				return err;
				return ERR_PTR(err);
			/* add other standalone attributes here */
			if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) {
				n_match_sets++;
@@ -6035,30 +6084,23 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
		n_match_sets = 1;

	if (n_match_sets > wiphy->max_match_sets)
		return -EINVAL;
		return ERR_PTR(-EINVAL);

	if (info->attrs[NL80211_ATTR_IE])
		ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
	if (attrs[NL80211_ATTR_IE])
		ie_len = nla_len(attrs[NL80211_ATTR_IE]);
	else
		ie_len = 0;

	if (ie_len > wiphy->max_sched_scan_ie_len)
		return -EINVAL;

	if (rdev->sched_scan_req) {
		err = -EINPROGRESS;
		goto out;
	}
		return ERR_PTR(-EINVAL);

	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) {
		err = -ENOMEM;
		goto out;
	}
	if (!request)
		return ERR_PTR(-ENOMEM);

	if (n_ssids)
		request->ssids = (void *)&request->channels[n_channels];
@@ -6083,10 +6125,10 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
	request->n_match_sets = n_match_sets;

	i = 0;
	if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
	if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
		/* user specified, bail out if channel not found */
		nla_for_each_nested(attr,
				    info->attrs[NL80211_ATTR_SCAN_FREQUENCIES],
				    attrs[NL80211_ATTR_SCAN_FREQUENCIES],
				    tmp) {
			struct ieee80211_channel *chan;

@@ -6132,8 +6174,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
	request->n_channels = i;

	i = 0;
	if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
		nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS],
	if (attrs[NL80211_ATTR_SCAN_SSIDS]) {
		nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS],
				    tmp) {
			if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
				err = -EINVAL;
@@ -6147,9 +6189,9 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
	}

	i = 0;
	if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
	if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
		nla_for_each_nested(attr,
				    info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
				    attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
				    tmp) {
			struct nlattr *ssid, *rssi;

@@ -6204,39 +6246,91 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
	if (ie_len) {
		request->ie_len = ie_len;
		memcpy((void *)request->ie,
		       nla_data(info->attrs[NL80211_ATTR_IE]),
		       nla_data(attrs[NL80211_ATTR_IE]),
		       request->ie_len);
	}

	if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
	if (attrs[NL80211_ATTR_SCAN_FLAGS]) {
		request->flags = nla_get_u32(
			info->attrs[NL80211_ATTR_SCAN_FLAGS]);
			attrs[NL80211_ATTR_SCAN_FLAGS]);
		if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
		    !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
			err = -EOPNOTSUPP;
			goto out_free;
		}

		if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
			u32 flg = NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;

			if (!wdev) /* must be net-detect */
				flg = NL80211_FEATURE_ND_RANDOM_MAC_ADDR;

			if (!(wiphy->features & flg)) {
				err = -EOPNOTSUPP;
				goto out_free;
			}

			if (wdev && wdev->current_bss) {
				err = -EOPNOTSUPP;
				goto out_free;
			}

			err = nl80211_parse_random_mac(attrs, request->mac_addr,
						       request->mac_addr_mask);
			if (err)
				goto out_free;
		}
	}

	request->dev = dev;
	request->wiphy = &rdev->wiphy;
	request->interval = interval;
	request->scan_start = jiffies;

	err = rdev_sched_scan_start(rdev, dev, request);
	if (!err) {
	return request;

out_free:
	kfree(request);
	return ERR_PTR(err);
}

static int nl80211_start_sched_scan(struct sk_buff *skb,
				    struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	int err;

	if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
	    !rdev->ops->sched_scan_start)
		return -EOPNOTSUPP;

	if (rdev->sched_scan_req)
		return -EINPROGRESS;

	rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
							info->attrs);
	err = PTR_ERR_OR_ZERO(rdev->sched_scan_req);
	if (err)
		goto out_err;

	err = rdev_sched_scan_start(rdev, dev, rdev->sched_scan_req);
	if (err)
		goto out_free;

	rdev->sched_scan_req->dev = dev;
	rdev->sched_scan_req->wiphy = &rdev->wiphy;

	if (info->attrs[NL80211_ATTR_IFACE_SOCKET_OWNER])
			request->owner_nlportid = info->snd_portid;
		rdev->sched_scan_req->owner_nlportid = info->snd_portid;

		rdev->sched_scan_req = request;
	nl80211_send_sched_scan(rdev, dev,
				NL80211_CMD_START_SCHED_SCAN);
		goto out;
	}
	return 0;

out_free:
	kfree(request);
out:
	kfree(rdev->sched_scan_req);
out_err:
	rdev->sched_scan_req = NULL;
	return err;
}