Loading include/net/cfg80211.h +26 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 { Loading @@ -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; Loading @@ -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 * Loading Loading @@ -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) */ Loading @@ -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; Loading include/uapi/linux/nl80211.h +25 −0 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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, }; /** Loading Loading @@ -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, }; /** Loading net/wireless/nl80211.c +155 −61 Original line number Diff line number Diff line Loading @@ -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 }, }; Loading Loading @@ -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]; Loading Loading @@ -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 = Loading Loading @@ -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; Loading @@ -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 Loading @@ -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; Loading @@ -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++; Loading @@ -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]; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; } Loading Loading
include/net/cfg80211.h +26 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 { Loading @@ -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; Loading @@ -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 * Loading Loading @@ -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) */ Loading @@ -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; Loading
include/uapi/linux/nl80211.h +25 −0 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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, }; /** Loading Loading @@ -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, }; /** Loading
net/wireless/nl80211.c +155 −61 Original line number Diff line number Diff line Loading @@ -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 }, }; Loading Loading @@ -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]; Loading Loading @@ -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 = Loading Loading @@ -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; Loading @@ -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 Loading @@ -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; Loading @@ -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++; Loading @@ -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]; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; } Loading