diff options
Diffstat (limited to 'net/wireless/scan.c')
| -rw-r--r-- | net/wireless/scan.c | 121 | 
1 files changed, 78 insertions, 43 deletions
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 22e92be61938..b888522f133b 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -406,22 +406,20 @@ static int  cfg80211_add_nontrans_list(struct cfg80211_bss *trans_bss,  			   struct cfg80211_bss *nontrans_bss)  { -	const u8 *ssid; -	size_t ssid_len; +	const struct element *ssid_elem;  	struct cfg80211_bss *bss = NULL;  	rcu_read_lock(); -	ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID); -	if (!ssid) { +	ssid_elem = ieee80211_bss_get_elem(nontrans_bss, WLAN_EID_SSID); +	if (!ssid_elem) {  		rcu_read_unlock();  		return -EINVAL;  	} -	ssid_len = ssid[1]; -	ssid = ssid + 2;  	/* check if nontrans_bss is in the list */  	list_for_each_entry(bss, &trans_bss->nontrans_list, nontrans_list) { -		if (is_bss(bss, nontrans_bss->bssid, ssid, ssid_len)) { +		if (is_bss(bss, nontrans_bss->bssid, ssid_elem->data, +			   ssid_elem->datalen)) {  			rcu_read_unlock();  			return 0;  		} @@ -1795,33 +1793,52 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,  }  int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen, -				    enum nl80211_band band) +				    enum nl80211_band band, +				    enum cfg80211_bss_frame_type ftype)  { -	const u8 *tmp; -	int channel_number = -1; +	const struct element *tmp; + +	if (band == NL80211_BAND_6GHZ) { +		struct ieee80211_he_operation *he_oper; -	if (band == NL80211_BAND_S1GHZ) { -		tmp = cfg80211_find_ie(WLAN_EID_S1G_OPERATION, ie, ielen); -		if (tmp && tmp[1] >= sizeof(struct ieee80211_s1g_oper_ie)) { -			struct ieee80211_s1g_oper_ie *s1gop = (void *)(tmp + 2); +		tmp = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ie, +					     ielen); +		if (tmp && tmp->datalen >= sizeof(*he_oper) && +		    tmp->datalen >= ieee80211_he_oper_size(&tmp->data[1])) { +			const struct ieee80211_he_6ghz_oper *he_6ghz_oper; + +			he_oper = (void *)&tmp->data[1]; + +			he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper); +			if (!he_6ghz_oper) +				return -1; -			channel_number = s1gop->primary_ch; +			if (ftype != CFG80211_BSS_FTYPE_BEACON || +			    he_6ghz_oper->control & IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON) +				return he_6ghz_oper->primary; +		} +	} else if (band == NL80211_BAND_S1GHZ) { +		tmp = cfg80211_find_elem(WLAN_EID_S1G_OPERATION, ie, ielen); +		if (tmp && tmp->datalen >= sizeof(struct ieee80211_s1g_oper_ie)) { +			struct ieee80211_s1g_oper_ie *s1gop = (void *)tmp->data; + +			return s1gop->primary_ch;  		}  	} else { -		tmp = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ie, ielen); -		if (tmp && tmp[1] == 1) { -			channel_number = tmp[2]; -		} else { -			tmp = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie, ielen); -			if (tmp && tmp[1] >= sizeof(struct ieee80211_ht_operation)) { -				struct ieee80211_ht_operation *htop = (void *)(tmp + 2); +		tmp = cfg80211_find_elem(WLAN_EID_DS_PARAMS, ie, ielen); +		if (tmp && tmp->datalen == 1) +			return tmp->data[0]; -				channel_number = htop->primary_chan; -			} +		tmp = cfg80211_find_elem(WLAN_EID_HT_OPERATION, ie, ielen); +		if (tmp && +		    tmp->datalen >= sizeof(struct ieee80211_ht_operation)) { +			struct ieee80211_ht_operation *htop = (void *)tmp->data; + +			return htop->primary_chan;  		}  	} -	return channel_number; +	return -1;  }  EXPORT_SYMBOL(cfg80211_get_ies_channel_number); @@ -1831,18 +1848,20 @@ EXPORT_SYMBOL(cfg80211_get_ies_channel_number);   * from neighboring channels and the Beacon frames use the DSSS Parameter Set   * element to indicate the current (transmitting) channel, but this might also   * be needed on other bands if RX frequency does not match with the actual - * operating channel of a BSS. + * operating channel of a BSS, or if the AP reports a different primary channel.   */  static struct ieee80211_channel *  cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,  			 struct ieee80211_channel *channel, -			 enum nl80211_bss_scan_width scan_width) +			 enum nl80211_bss_scan_width scan_width, +			 enum cfg80211_bss_frame_type ftype)  {  	u32 freq;  	int channel_number;  	struct ieee80211_channel *alt_channel; -	channel_number = cfg80211_get_ies_channel_number(ie, ielen, channel->band); +	channel_number = cfg80211_get_ies_channel_number(ie, ielen, +							 channel->band, ftype);  	if (channel_number < 0) {  		/* No channel information in frame payload */ @@ -1850,6 +1869,16 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,  	}  	freq = ieee80211_channel_to_freq_khz(channel_number, channel->band); + +	/* +	 * In 6GHz, duplicated beacon indication is relevant for +	 * beacons only. +	 */ +	if (channel->band == NL80211_BAND_6GHZ && +	    (freq == channel->center_freq || +	     abs(freq - channel->center_freq) > 80)) +		return channel; +  	alt_channel = ieee80211_get_channel_khz(wiphy, freq);  	if (!alt_channel) {  		if (channel->band == NL80211_BAND_2GHZ) { @@ -1911,7 +1940,7 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,  		return NULL;  	channel = cfg80211_get_bss_channel(wiphy, ie, ielen, data->chan, -					   data->scan_width); +					   data->scan_width, ftype);  	if (!channel)  		return NULL; @@ -2234,7 +2263,8 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,  				   struct ieee80211_mgmt *mgmt, size_t len)  {  	u8 *ie, *new_ie, *pos; -	const u8 *nontrans_ssid, *trans_ssid, *mbssid; +	const struct element *nontrans_ssid; +	const u8 *trans_ssid, *mbssid;  	size_t ielen = len - offsetof(struct ieee80211_mgmt,  				      u.probe_resp.variable);  	size_t new_ie_len; @@ -2261,11 +2291,11 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,  		return;  	new_ie_len -= mbssid[1]; -	nontrans_ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID); +	nontrans_ssid = ieee80211_bss_get_elem(nontrans_bss, WLAN_EID_SSID);  	if (!nontrans_ssid)  		return; -	new_ie_len += nontrans_ssid[1]; +	new_ie_len += nontrans_ssid->datalen;  	/* generate new ie for nontrans BSS  	 * 1. replace SSID with nontrans BSS' SSID @@ -2282,7 +2312,7 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,  	pos = new_ie;  	/* copy the nontransmitted SSID */ -	cpy_len = nontrans_ssid[1] + 2; +	cpy_len = nontrans_ssid->datalen + 2;  	memcpy(pos, nontrans_ssid, cpy_len);  	pos += cpy_len;  	/* copy the IEs between SSID and MBSSID */ @@ -2333,6 +2363,7 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,  	size_t ielen, min_hdr_len = offsetof(struct ieee80211_mgmt,  					     u.probe_resp.variable);  	int bss_type; +	enum cfg80211_bss_frame_type ftype;  	BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=  			offsetof(struct ieee80211_mgmt, u.beacon.variable)); @@ -2369,8 +2400,16 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,  			variable = ext->u.s1g_beacon.variable;  	} +	if (ieee80211_is_beacon(mgmt->frame_control)) +		ftype = CFG80211_BSS_FTYPE_BEACON; +	else if (ieee80211_is_probe_resp(mgmt->frame_control)) +		ftype = CFG80211_BSS_FTYPE_PRESP; +	else +		ftype = CFG80211_BSS_FTYPE_UNKNOWN; +  	channel = cfg80211_get_bss_channel(wiphy, variable, -					   ielen, data->chan, data->scan_width); +					   ielen, data->chan, data->scan_width, +					   ftype);  	if (!channel)  		return NULL; @@ -2687,7 +2726,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,  	struct cfg80211_registered_device *rdev;  	struct wiphy *wiphy;  	struct iw_scan_req *wreq = NULL; -	struct cfg80211_scan_request *creq = NULL; +	struct cfg80211_scan_request *creq;  	int i, err, n_channels = 0;  	enum nl80211_band band; @@ -2702,10 +2741,8 @@ int cfg80211_wext_siwscan(struct net_device *dev,  	if (IS_ERR(rdev))  		return PTR_ERR(rdev); -	if (rdev->scan_req || rdev->scan_msg) { -		err = -EBUSY; -		goto out; -	} +	if (rdev->scan_req || rdev->scan_msg) +		return -EBUSY;  	wiphy = &rdev->wiphy; @@ -2718,10 +2755,8 @@ int cfg80211_wext_siwscan(struct net_device *dev,  	creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +  		       n_channels * sizeof(void *),  		       GFP_ATOMIC); -	if (!creq) { -		err = -ENOMEM; -		goto out; -	} +	if (!creq) +		return -ENOMEM;  	creq->wiphy = wiphy;  	creq->wdev = dev->ieee80211_ptr;  |