diff options
Diffstat (limited to 'net/mac80211/util.c')
| -rw-r--r-- | net/mac80211/util.c | 99 | 
1 files changed, 98 insertions, 1 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 1a28fe5cb614..1527d6aafc14 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -314,6 +314,8 @@ void ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw,  	struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif);  	struct ieee80211_txq *queue; +	spin_lock(&local->handle_wake_tx_queue_lock); +  	/* Use ieee80211_next_txq() for airtime fairness accounting */  	ieee80211_txq_schedule_start(hw, txq->ac);  	while ((queue = ieee80211_next_txq(hw, txq->ac))) { @@ -321,6 +323,7 @@ void ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw,  		ieee80211_return_txq(hw, queue, false);  	}  	ieee80211_txq_schedule_end(hw, txq->ac); +	spin_unlock(&local->handle_wake_tx_queue_lock);  }  EXPORT_SYMBOL(ieee80211_handle_wake_tx_queue); @@ -1959,6 +1962,14 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata,  	rate_flags = ieee80211_chandef_rate_flags(chandef);  	shift = ieee80211_chandef_get_shift(chandef); +	/* For direct scan add S1G IE and consider its override bits */ +	if (band == NL80211_BAND_S1GHZ) { +		if (end - pos < 2 + sizeof(struct ieee80211_s1g_cap)) +			goto out_err; +		pos = ieee80211_ie_build_s1g_cap(pos, &sband->s1g_cap); +		goto done; +	} +  	num_rates = 0;  	for (i = 0; i < sband->n_bitrates; i++) {  		if ((BIT(i) & rate_mask) == 0) @@ -3020,6 +3031,21 @@ size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)  	return pos;  } +u8 *ieee80211_ie_build_s1g_cap(u8 *pos, struct ieee80211_sta_s1g_cap *s1g_cap) +{ +	*pos++ = WLAN_EID_S1G_CAPABILITIES; +	*pos++ = sizeof(struct ieee80211_s1g_cap); +	memset(pos, 0, sizeof(struct ieee80211_s1g_cap)); + +	memcpy(pos, &s1g_cap->cap, sizeof(s1g_cap->cap)); +	pos += sizeof(s1g_cap->cap); + +	memcpy(pos, &s1g_cap->nss_mcs, sizeof(s1g_cap->nss_mcs)); +	pos += sizeof(s1g_cap->nss_mcs); + +	return pos; +} +  u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,  			      u16 cap)  { @@ -3459,6 +3485,77 @@ out:  	return pos;  } +u8 *ieee80211_ie_build_eht_oper(u8 *pos, struct cfg80211_chan_def *chandef, +				const struct ieee80211_sta_eht_cap *eht_cap) + +{ +	const struct ieee80211_eht_mcs_nss_supp_20mhz_only *eht_mcs_nss = +					&eht_cap->eht_mcs_nss_supp.only_20mhz; +	struct ieee80211_eht_operation *eht_oper; +	struct ieee80211_eht_operation_info *eht_oper_info; +	u8 eht_oper_len = offsetof(struct ieee80211_eht_operation, optional); +	u8 eht_oper_info_len = +		offsetof(struct ieee80211_eht_operation_info, optional); +	u8 chan_width = 0; + +	*pos++ = WLAN_EID_EXTENSION; +	*pos++ = 1 + eht_oper_len + eht_oper_info_len; +	*pos++ = WLAN_EID_EXT_EHT_OPERATION; + +	eht_oper = (struct ieee80211_eht_operation *)pos; + +	memcpy(&eht_oper->basic_mcs_nss, eht_mcs_nss, sizeof(*eht_mcs_nss)); +	eht_oper->params |= IEEE80211_EHT_OPER_INFO_PRESENT; +	pos += eht_oper_len; + +	eht_oper_info = +		(struct ieee80211_eht_operation_info *)eht_oper->optional; + +	eht_oper_info->ccfs0 = +		ieee80211_frequency_to_channel(chandef->center_freq1); +	if (chandef->center_freq2) +		eht_oper_info->ccfs1 = +			ieee80211_frequency_to_channel(chandef->center_freq2); +	else +		eht_oper_info->ccfs1 = 0; + +	switch (chandef->width) { +	case NL80211_CHAN_WIDTH_320: +		chan_width = IEEE80211_EHT_OPER_CHAN_WIDTH_320MHZ; +		eht_oper_info->ccfs1 = eht_oper_info->ccfs0; +		if (chandef->chan->center_freq < chandef->center_freq1) +			eht_oper_info->ccfs0 -= 16; +		else +			eht_oper_info->ccfs0 += 16; +		break; +	case NL80211_CHAN_WIDTH_160: +		eht_oper_info->ccfs1 = eht_oper_info->ccfs0; +		if (chandef->chan->center_freq < chandef->center_freq1) +			eht_oper_info->ccfs0 -= 8; +		else +			eht_oper_info->ccfs0 += 8; +		fallthrough; +	case NL80211_CHAN_WIDTH_80P80: +		chan_width = IEEE80211_EHT_OPER_CHAN_WIDTH_160MHZ; +		break; +	case NL80211_CHAN_WIDTH_80: +		chan_width = IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ; +		break; +	case NL80211_CHAN_WIDTH_40: +		chan_width = IEEE80211_EHT_OPER_CHAN_WIDTH_40MHZ; +		break; +	default: +		chan_width = IEEE80211_EHT_OPER_CHAN_WIDTH_20MHZ; +		break; +	} +	eht_oper_info->control = chan_width; +	pos += eht_oper_info_len; + +	/* TODO: eht_oper_info->optional */ + +	return pos; +} +  bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,  			       struct cfg80211_chan_def *chandef)  { @@ -4903,7 +5000,7 @@ u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata, u8 iftype)  				       &eht_cap->eht_cap_elem,  				       is_ap);  	return 2 + 1 + -	       sizeof(he_cap->he_cap_elem) + n + +	       sizeof(eht_cap->eht_cap_elem) + n +  	       ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0],  				      eht_cap->eht_cap_elem.phy_cap_info);  	return 0;  |