mac80211: stop toggling IEEE80211_HT_CAP_SUP_WIDTH_20_40
For VHT, many more bandwidth changes are possible. As a first step, stop toggling the IEEE80211_HT_CAP_SUP_WIDTH_20_40 flag in the HT capabilities and instead introduce a bandwidth field indicating the currently usable bandwidth to transmit to the station. Of course, make all drivers use it. To achieve this, make ieee80211_ht_cap_ie_to_sta_ht_cap() get the station as an argument, rather than the new capabilities, so it can set up the new bandwidth field. If the station is a VHT station and VHT bandwidth is in use, also set the bandwidth accordingly. Doing this allows us to get rid of the supports_40mhz flag as the HT capabilities now reflect the true capability instead of the current setting. While at it, also fix ieee80211_ht_cap_ie_to_sta_ht_cap() to not ignore HT cap overrides when MCS TX isn't supported (not that it really happens...) Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
		
					parent
					
						
							
								4a34215ef7
							
						
					
				
			
			
				commit
				
					
						e1a0c6b3a4
					
				
			
		
					 27 changed files with 184 additions and 158 deletions
				
			
		| 
						 | 
					@ -1204,7 +1204,7 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta)
 | 
				
			||||||
			caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG;
 | 
								caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG;
 | 
				
			||||||
		else if (sta->ht_cap.mcs.rx_mask[1])
 | 
							else if (sta->ht_cap.mcs.rx_mask[1])
 | 
				
			||||||
			caps |= WLAN_RC_DS_FLAG;
 | 
								caps |= WLAN_RC_DS_FLAG;
 | 
				
			||||||
		if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
 | 
							if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) {
 | 
				
			||||||
			caps |= WLAN_RC_40_FLAG;
 | 
								caps |= WLAN_RC_40_FLAG;
 | 
				
			||||||
			if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
 | 
								if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
 | 
				
			||||||
				caps |= WLAN_RC_SGI_FLAG;
 | 
									caps |= WLAN_RC_SGI_FLAG;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -338,7 +338,7 @@ int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
 | 
					bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
 | 
				
			||||||
			    struct iwl_rxon_context *ctx,
 | 
								    struct iwl_rxon_context *ctx,
 | 
				
			||||||
			    struct ieee80211_sta_ht_cap *ht_cap);
 | 
								    struct ieee80211_sta *sta);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int iwl_sta_id(struct ieee80211_sta *sta)
 | 
					static inline int iwl_sta_id(struct ieee80211_sta *sta)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1305,7 +1305,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
 | 
				
			||||||
	tbl->max_search = IWL_MAX_SEARCH;
 | 
						tbl->max_search = IWL_MAX_SEARCH;
 | 
				
			||||||
	rate_mask = lq_sta->active_mimo2_rate;
 | 
						rate_mask = lq_sta->active_mimo2_rate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
 | 
						if (iwl_is_ht40_tx_allowed(priv, ctx, sta))
 | 
				
			||||||
		tbl->is_ht40 = 1;
 | 
							tbl->is_ht40 = 1;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		tbl->is_ht40 = 0;
 | 
							tbl->is_ht40 = 0;
 | 
				
			||||||
| 
						 | 
					@ -1361,7 +1361,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
 | 
				
			||||||
	tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
 | 
						tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
 | 
				
			||||||
	rate_mask = lq_sta->active_mimo3_rate;
 | 
						rate_mask = lq_sta->active_mimo3_rate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
 | 
						if (iwl_is_ht40_tx_allowed(priv, ctx, sta))
 | 
				
			||||||
		tbl->is_ht40 = 1;
 | 
							tbl->is_ht40 = 1;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		tbl->is_ht40 = 0;
 | 
							tbl->is_ht40 = 0;
 | 
				
			||||||
| 
						 | 
					@ -1410,7 +1410,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
 | 
				
			||||||
	tbl->max_search = IWL_MAX_SEARCH;
 | 
						tbl->max_search = IWL_MAX_SEARCH;
 | 
				
			||||||
	rate_mask = lq_sta->active_siso_rate;
 | 
						rate_mask = lq_sta->active_siso_rate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
 | 
						if (iwl_is_ht40_tx_allowed(priv, ctx, sta))
 | 
				
			||||||
		tbl->is_ht40 = 1;
 | 
							tbl->is_ht40 = 1;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		tbl->is_ht40 = 0;
 | 
							tbl->is_ht40 = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -173,7 +173,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
 | 
					bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
 | 
				
			||||||
			    struct iwl_rxon_context *ctx,
 | 
								    struct iwl_rxon_context *ctx,
 | 
				
			||||||
			    struct ieee80211_sta_ht_cap *ht_cap)
 | 
								    struct ieee80211_sta *sta)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
 | 
						if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
| 
						 | 
					@ -183,20 +183,11 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/* special case for RXON */
 | 
				
			||||||
	 * Remainder of this function checks ht_cap, but if it's
 | 
						if (!sta)
 | 
				
			||||||
	 * NULL then we can do HT40 (special case for RXON)
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (!ht_cap)
 | 
					 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!ht_cap->ht_supported)
 | 
						return sta->bandwidth >= IEEE80211_STA_RX_BW_40;
 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
 | 
					static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
 | 
				
			||||||
| 
						 | 
					@ -246,7 +237,7 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
 | 
				
			||||||
	*flags |= cpu_to_le32(
 | 
						*flags |= cpu_to_le32(
 | 
				
			||||||
		(u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
 | 
							(u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
 | 
						if (iwl_is_ht40_tx_allowed(priv, ctx, sta))
 | 
				
			||||||
		*flags |= STA_FLG_HT40_EN_MSK;
 | 
							*flags |= STA_FLG_HT40_EN_MSK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1209,23 +1209,9 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
 | 
				
			||||||
	return new_rate;
 | 
						return new_rate;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool iwl_is_ht40_tx_allowed(struct iwl_mvm *mvm,
 | 
					static bool iwl_is_ht40_tx_allowed(struct ieee80211_sta *sta)
 | 
				
			||||||
			    struct ieee80211_sta_ht_cap *ht_cap)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/*
 | 
						return sta->bandwidth >= IEEE80211_STA_RX_BW_40;
 | 
				
			||||||
	 * Remainder of this function checks ht_cap, but if it's
 | 
					 | 
				
			||||||
	 * NULL then we can do HT40 (special case for RXON)
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (!ht_cap)
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!ht_cap->ht_supported)
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -1258,7 +1244,7 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm,
 | 
				
			||||||
	tbl->max_search = IWL_MAX_SEARCH;
 | 
						tbl->max_search = IWL_MAX_SEARCH;
 | 
				
			||||||
	rate_mask = lq_sta->active_mimo2_rate;
 | 
						rate_mask = lq_sta->active_mimo2_rate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap))
 | 
						if (iwl_is_ht40_tx_allowed(sta))
 | 
				
			||||||
		tbl->is_ht40 = 1;
 | 
							tbl->is_ht40 = 1;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		tbl->is_ht40 = 0;
 | 
							tbl->is_ht40 = 0;
 | 
				
			||||||
| 
						 | 
					@ -1311,7 +1297,7 @@ static int rs_switch_to_mimo3(struct iwl_mvm *mvm,
 | 
				
			||||||
	tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
 | 
						tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
 | 
				
			||||||
	rate_mask = lq_sta->active_mimo3_rate;
 | 
						rate_mask = lq_sta->active_mimo3_rate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap))
 | 
						if (iwl_is_ht40_tx_allowed(sta))
 | 
				
			||||||
		tbl->is_ht40 = 1;
 | 
							tbl->is_ht40 = 1;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		tbl->is_ht40 = 0;
 | 
							tbl->is_ht40 = 0;
 | 
				
			||||||
| 
						 | 
					@ -1356,7 +1342,7 @@ static int rs_switch_to_siso(struct iwl_mvm *mvm,
 | 
				
			||||||
	tbl->max_search = IWL_MAX_SEARCH;
 | 
						tbl->max_search = IWL_MAX_SEARCH;
 | 
				
			||||||
	rate_mask = lq_sta->active_siso_rate;
 | 
						rate_mask = lq_sta->active_siso_rate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap))
 | 
						if (iwl_is_ht40_tx_allowed(sta))
 | 
				
			||||||
		tbl->is_ht40 = 1;
 | 
							tbl->is_ht40 = 1;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		tbl->is_ht40 = 0;
 | 
							tbl->is_ht40 = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -523,8 +523,8 @@ static void _rtl_query_shortgi(struct ieee80211_hw *hw,
 | 
				
			||||||
	if (mac->opmode == NL80211_IFTYPE_STATION)
 | 
						if (mac->opmode == NL80211_IFTYPE_STATION)
 | 
				
			||||||
		bw_40 = mac->bw_40;
 | 
							bw_40 = mac->bw_40;
 | 
				
			||||||
	else if (mac->opmode == NL80211_IFTYPE_AP ||
 | 
						else if (mac->opmode == NL80211_IFTYPE_AP ||
 | 
				
			||||||
		mac->opmode == NL80211_IFTYPE_ADHOC)
 | 
							 mac->opmode == NL80211_IFTYPE_ADHOC)
 | 
				
			||||||
		bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
							bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (bw_40 && sgi_40)
 | 
						if (bw_40 && sgi_40)
 | 
				
			||||||
		tcb_desc->use_shortgi = true;
 | 
							tcb_desc->use_shortgi = true;
 | 
				
			||||||
| 
						 | 
					@ -634,8 +634,7 @@ static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	if (mac->opmode == NL80211_IFTYPE_AP ||
 | 
						if (mac->opmode == NL80211_IFTYPE_AP ||
 | 
				
			||||||
	    mac->opmode == NL80211_IFTYPE_ADHOC) {
 | 
						    mac->opmode == NL80211_IFTYPE_ADHOC) {
 | 
				
			||||||
		if (!(sta->ht_cap.ht_supported) ||
 | 
							if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
 | 
				
			||||||
		    !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
 | 
					 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
	} else if (mac->opmode == NL80211_IFTYPE_STATION) {
 | 
						} else if (mac->opmode == NL80211_IFTYPE_STATION) {
 | 
				
			||||||
		if (!mac->bw_40 || !(sta->ht_cap.ht_supported))
 | 
							if (!mac->bw_40 || !(sta->ht_cap.ht_supported))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,9 +116,8 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv,
 | 
				
			||||||
		if (txrc->short_preamble)
 | 
							if (txrc->short_preamble)
 | 
				
			||||||
			rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
 | 
								rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
 | 
				
			||||||
		if (mac->opmode == NL80211_IFTYPE_AP ||
 | 
							if (mac->opmode == NL80211_IFTYPE_AP ||
 | 
				
			||||||
			mac->opmode == NL80211_IFTYPE_ADHOC) {
 | 
							    mac->opmode == NL80211_IFTYPE_ADHOC) {
 | 
				
			||||||
			if (sta && (sta->ht_cap.cap &
 | 
								if (sta && (sta->bandwidth >= IEEE80211_STA_RX_BW_40))
 | 
				
			||||||
			    IEEE80211_HT_CAP_SUP_WIDTH_20_40))
 | 
					 | 
				
			||||||
				rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
 | 
									rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			if (mac->bw_40)
 | 
								if (mac->bw_40)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1846,9 +1846,9 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw,
 | 
				
			||||||
	struct rtl_sta_info *sta_entry = NULL;
 | 
						struct rtl_sta_info *sta_entry = NULL;
 | 
				
			||||||
	u32 ratr_bitmap;
 | 
						u32 ratr_bitmap;
 | 
				
			||||||
	u8 ratr_index;
 | 
						u8 ratr_index;
 | 
				
			||||||
	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
 | 
						u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0;
 | 
				
			||||||
				? 1 : 0;
 | 
						u8 curshortgi_40mhz = curtxbw_40mhz &&
 | 
				
			||||||
	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
 | 
								      (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
 | 
				
			||||||
				1 : 0;
 | 
									1 : 0;
 | 
				
			||||||
	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
 | 
						u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
 | 
				
			||||||
				1 : 0;
 | 
									1 : 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -626,8 +626,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
 | 
				
			||||||
	} else if (mac->opmode == NL80211_IFTYPE_AP ||
 | 
						} else if (mac->opmode == NL80211_IFTYPE_AP ||
 | 
				
			||||||
		mac->opmode == NL80211_IFTYPE_ADHOC) {
 | 
							mac->opmode == NL80211_IFTYPE_ADHOC) {
 | 
				
			||||||
		if (sta)
 | 
							if (sta)
 | 
				
			||||||
			bw_40 = sta->ht_cap.cap &
 | 
								bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
 | 
				
			||||||
				IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
 | 
						seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1970,8 +1970,7 @@ static void rtl92de_update_hal_rate_mask(struct ieee80211_hw *hw,
 | 
				
			||||||
	struct rtl_sta_info *sta_entry = NULL;
 | 
						struct rtl_sta_info *sta_entry = NULL;
 | 
				
			||||||
	u32 ratr_bitmap;
 | 
						u32 ratr_bitmap;
 | 
				
			||||||
	u8 ratr_index;
 | 
						u8 ratr_index;
 | 
				
			||||||
	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
 | 
						u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0;
 | 
				
			||||||
							? 1 : 0;
 | 
					 | 
				
			||||||
	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
 | 
						u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
 | 
				
			||||||
							1 : 0;
 | 
												1 : 0;
 | 
				
			||||||
	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
 | 
						u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -574,8 +574,7 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
 | 
				
			||||||
	} else if (mac->opmode == NL80211_IFTYPE_AP ||
 | 
						} else if (mac->opmode == NL80211_IFTYPE_AP ||
 | 
				
			||||||
		mac->opmode == NL80211_IFTYPE_ADHOC) {
 | 
							mac->opmode == NL80211_IFTYPE_ADHOC) {
 | 
				
			||||||
		if (sta)
 | 
							if (sta)
 | 
				
			||||||
			bw_40 = sta->ht_cap.cap &
 | 
								bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
 | 
				
			||||||
				IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
 | 
						seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
 | 
				
			||||||
	rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc);
 | 
						rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2085,8 +2085,7 @@ static void rtl92se_update_hal_rate_mask(struct ieee80211_hw *hw,
 | 
				
			||||||
	struct rtl_sta_info *sta_entry = NULL;
 | 
						struct rtl_sta_info *sta_entry = NULL;
 | 
				
			||||||
	u32 ratr_bitmap;
 | 
						u32 ratr_bitmap;
 | 
				
			||||||
	u8 ratr_index = 0;
 | 
						u8 ratr_index = 0;
 | 
				
			||||||
	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
 | 
						u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0;
 | 
				
			||||||
				? 1 : 0;
 | 
					 | 
				
			||||||
	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
 | 
						u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
 | 
				
			||||||
				1 : 0;
 | 
									1 : 0;
 | 
				
			||||||
	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
 | 
						u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -621,8 +621,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
 | 
				
			||||||
	} else if (mac->opmode == NL80211_IFTYPE_AP ||
 | 
						} else if (mac->opmode == NL80211_IFTYPE_AP ||
 | 
				
			||||||
		mac->opmode == NL80211_IFTYPE_ADHOC) {
 | 
							mac->opmode == NL80211_IFTYPE_ADHOC) {
 | 
				
			||||||
		if (sta)
 | 
							if (sta)
 | 
				
			||||||
			bw_40 = sta->ht_cap.cap &
 | 
								bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
 | 
				
			||||||
				    IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
 | 
						seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1866,8 +1866,7 @@ static void rtl8723ae_update_hal_rate_mask(struct ieee80211_hw *hw,
 | 
				
			||||||
	struct rtl_sta_info *sta_entry = NULL;
 | 
						struct rtl_sta_info *sta_entry = NULL;
 | 
				
			||||||
	u32 ratr_bitmap;
 | 
						u32 ratr_bitmap;
 | 
				
			||||||
	u8 ratr_index;
 | 
						u8 ratr_index;
 | 
				
			||||||
	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
 | 
						u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0;
 | 
				
			||||||
				? 1 : 0;
 | 
					 | 
				
			||||||
	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
 | 
						u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
 | 
				
			||||||
				1 : 0;
 | 
									1 : 0;
 | 
				
			||||||
	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
 | 
						u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -395,8 +395,7 @@ void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw,
 | 
				
			||||||
	} else if (mac->opmode == NL80211_IFTYPE_AP ||
 | 
						} else if (mac->opmode == NL80211_IFTYPE_AP ||
 | 
				
			||||||
		mac->opmode == NL80211_IFTYPE_ADHOC) {
 | 
							mac->opmode == NL80211_IFTYPE_ADHOC) {
 | 
				
			||||||
		if (sta)
 | 
							if (sta)
 | 
				
			||||||
			bw_40 = sta->ht_cap.cap &
 | 
								bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
 | 
				
			||||||
				IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
 | 
						seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1374,7 +1374,7 @@ static void wl18xx_sta_rc_update(struct wl1271 *wl,
 | 
				
			||||||
				 struct ieee80211_sta *sta,
 | 
									 struct ieee80211_sta *sta,
 | 
				
			||||||
				 u32 changed)
 | 
									 u32 changed)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	bool wide = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
						bool wide = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide);
 | 
						wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1196,6 +1196,24 @@ enum ieee80211_sta_state {
 | 
				
			||||||
	IEEE80211_STA_AUTHORIZED,
 | 
						IEEE80211_STA_AUTHORIZED,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * enum ieee80211_sta_rx_bandwidth - station RX bandwidth
 | 
				
			||||||
 | 
					 * @IEEE80211_STA_RX_BW_20: station can only receive 20 MHz
 | 
				
			||||||
 | 
					 * @IEEE80211_STA_RX_BW_40: station can receive up to 40 MHz
 | 
				
			||||||
 | 
					 * @IEEE80211_STA_RX_BW_80: station can receive up to 80 MHz
 | 
				
			||||||
 | 
					 * @IEEE80211_STA_RX_BW_160: station can receive up to 160 MHz
 | 
				
			||||||
 | 
					 *	(including 80+80 MHz)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Implementation note: 20 must be zero to be initialized
 | 
				
			||||||
 | 
					 *	correctly, the values must be sorted.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum ieee80211_sta_rx_bandwidth {
 | 
				
			||||||
 | 
						IEEE80211_STA_RX_BW_20 = 0,
 | 
				
			||||||
 | 
						IEEE80211_STA_RX_BW_40,
 | 
				
			||||||
 | 
						IEEE80211_STA_RX_BW_80,
 | 
				
			||||||
 | 
						IEEE80211_STA_RX_BW_160,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * struct ieee80211_sta - station table entry
 | 
					 * struct ieee80211_sta - station table entry
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -1218,6 +1236,7 @@ enum ieee80211_sta_state {
 | 
				
			||||||
 * @uapsd_queues: bitmap of queues configured for uapsd. Only valid
 | 
					 * @uapsd_queues: bitmap of queues configured for uapsd. Only valid
 | 
				
			||||||
 *	if wme is supported.
 | 
					 *	if wme is supported.
 | 
				
			||||||
 * @max_sp: max Service Period. Only valid if wme is supported.
 | 
					 * @max_sp: max Service Period. Only valid if wme is supported.
 | 
				
			||||||
 | 
					 * @bandwidth: current bandwidth the station can receive with
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct ieee80211_sta {
 | 
					struct ieee80211_sta {
 | 
				
			||||||
	u32 supp_rates[IEEE80211_NUM_BANDS];
 | 
						u32 supp_rates[IEEE80211_NUM_BANDS];
 | 
				
			||||||
| 
						 | 
					@ -1228,6 +1247,7 @@ struct ieee80211_sta {
 | 
				
			||||||
	bool wme;
 | 
						bool wme;
 | 
				
			||||||
	u8 uapsd_queues;
 | 
						u8 uapsd_queues;
 | 
				
			||||||
	u8 max_sp;
 | 
						u8 max_sp;
 | 
				
			||||||
 | 
						enum ieee80211_sta_rx_bandwidth bandwidth;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* must be last */
 | 
						/* must be last */
 | 
				
			||||||
	u8 drv_priv[0] __aligned(sizeof(void *));
 | 
						u8 drv_priv[0] __aligned(sizeof(void *));
 | 
				
			||||||
| 
						 | 
					@ -2086,7 +2106,9 @@ enum ieee80211_frame_release_type {
 | 
				
			||||||
 * enum ieee80211_rate_control_changed - flags to indicate what changed
 | 
					 * enum ieee80211_rate_control_changed - flags to indicate what changed
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @IEEE80211_RC_BW_CHANGED: The bandwidth that can be used to transmit
 | 
					 * @IEEE80211_RC_BW_CHANGED: The bandwidth that can be used to transmit
 | 
				
			||||||
 *	to this station changed.
 | 
					 *	to this station changed. The actual bandwidth is in the station
 | 
				
			||||||
 | 
					 *	information -- for HT20/40 the IEEE80211_HT_CAP_SUP_WIDTH_20_40
 | 
				
			||||||
 | 
					 *	flag changes, for HT and VHT the bandwidth field changes.
 | 
				
			||||||
 * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed.
 | 
					 * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed.
 | 
				
			||||||
 * @IEEE80211_RC_SUPP_RATES_CHANGED: The supported rate set of this peer
 | 
					 * @IEEE80211_RC_SUPP_RATES_CHANGED: The supported rate set of this peer
 | 
				
			||||||
 *	changed (in IBSS mode) due to discovering more information about
 | 
					 *	changed (in IBSS mode) due to discovering more information about
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1252,8 +1252,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (params->ht_capa)
 | 
						if (params->ht_capa)
 | 
				
			||||||
		ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
 | 
							ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
 | 
				
			||||||
						  params->ht_capa,
 | 
											  params->ht_capa, sta);
 | 
				
			||||||
						  &sta->sta.ht_cap);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (params->vht_capa)
 | 
						if (params->vht_capa)
 | 
				
			||||||
		ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
 | 
							ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,6 +37,9 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
	u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask);
 | 
						u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask);
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ht_cap->ht_supported)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sdata->vif.type != NL80211_IFTYPE_STATION) {
 | 
						if (sdata->vif.type != NL80211_IFTYPE_STATION) {
 | 
				
			||||||
		/* AP interfaces call this code when adding new stations,
 | 
							/* AP interfaces call this code when adding new stations,
 | 
				
			||||||
		 * so just silently ignore non station interfaces.
 | 
							 * so just silently ignore non station interfaces.
 | 
				
			||||||
| 
						 | 
					@ -89,22 +92,23 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
 | 
					bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
				       struct ieee80211_supported_band *sband,
 | 
									       struct ieee80211_supported_band *sband,
 | 
				
			||||||
				       struct ieee80211_ht_cap *ht_cap_ie,
 | 
									       struct ieee80211_ht_cap *ht_cap_ie,
 | 
				
			||||||
				       struct ieee80211_sta_ht_cap *ht_cap)
 | 
									       struct sta_info *sta)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct ieee80211_sta_ht_cap ht_cap;
 | 
				
			||||||
	u8 ampdu_info, tx_mcs_set_cap;
 | 
						u8 ampdu_info, tx_mcs_set_cap;
 | 
				
			||||||
	int i, max_tx_streams;
 | 
						int i, max_tx_streams;
 | 
				
			||||||
 | 
						bool changed;
 | 
				
			||||||
 | 
						enum ieee80211_sta_rx_bandwidth bw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BUG_ON(!ht_cap);
 | 
						memset(&ht_cap, 0, sizeof(ht_cap));
 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(ht_cap, 0, sizeof(*ht_cap));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!ht_cap_ie || !sband->ht_cap.ht_supported)
 | 
						if (!ht_cap_ie || !sband->ht_cap.ht_supported)
 | 
				
			||||||
		return;
 | 
							goto apply;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ht_cap->ht_supported = true;
 | 
						ht_cap.ht_supported = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The bits listed in this expression should be
 | 
						 * The bits listed in this expression should be
 | 
				
			||||||
| 
						 | 
					@ -112,7 +116,7 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
	 * advertises more then we can't use those thus
 | 
						 * advertises more then we can't use those thus
 | 
				
			||||||
	 * we mask them out.
 | 
						 * we mask them out.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) &
 | 
						ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) &
 | 
				
			||||||
		(sband->ht_cap.cap |
 | 
							(sband->ht_cap.cap |
 | 
				
			||||||
		 ~(IEEE80211_HT_CAP_LDPC_CODING |
 | 
							 ~(IEEE80211_HT_CAP_LDPC_CODING |
 | 
				
			||||||
		   IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
 | 
							   IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
 | 
				
			||||||
| 
						 | 
					@ -121,44 +125,30 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
		   IEEE80211_HT_CAP_SGI_40 |
 | 
							   IEEE80211_HT_CAP_SGI_40 |
 | 
				
			||||||
		   IEEE80211_HT_CAP_DSSSCCK40));
 | 
							   IEEE80211_HT_CAP_DSSSCCK40));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Unset 40 MHz if we're not using a 40 MHz channel */
 | 
					 | 
				
			||||||
	switch (sdata->vif.bss_conf.chandef.width) {
 | 
					 | 
				
			||||||
	case NL80211_CHAN_WIDTH_20_NOHT:
 | 
					 | 
				
			||||||
	case NL80211_CHAN_WIDTH_20:
 | 
					 | 
				
			||||||
		ht_cap->cap &= ~IEEE80211_HT_CAP_SGI_40;
 | 
					 | 
				
			||||||
		ht_cap->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case NL80211_CHAN_WIDTH_40:
 | 
					 | 
				
			||||||
	case NL80211_CHAN_WIDTH_80:
 | 
					 | 
				
			||||||
	case NL80211_CHAN_WIDTH_80P80:
 | 
					 | 
				
			||||||
	case NL80211_CHAN_WIDTH_160:
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The STBC bits are asymmetric -- if we don't have
 | 
						 * The STBC bits are asymmetric -- if we don't have
 | 
				
			||||||
	 * TX then mask out the peer's RX and vice versa.
 | 
						 * TX then mask out the peer's RX and vice versa.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC))
 | 
						if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC))
 | 
				
			||||||
		ht_cap->cap &= ~IEEE80211_HT_CAP_RX_STBC;
 | 
							ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC;
 | 
				
			||||||
	if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC))
 | 
						if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC))
 | 
				
			||||||
		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
 | 
							ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ampdu_info = ht_cap_ie->ampdu_params_info;
 | 
						ampdu_info = ht_cap_ie->ampdu_params_info;
 | 
				
			||||||
	ht_cap->ampdu_factor =
 | 
						ht_cap.ampdu_factor =
 | 
				
			||||||
		ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
 | 
							ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
 | 
				
			||||||
	ht_cap->ampdu_density =
 | 
						ht_cap.ampdu_density =
 | 
				
			||||||
		(ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
 | 
							(ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* own MCS TX capabilities */
 | 
						/* own MCS TX capabilities */
 | 
				
			||||||
	tx_mcs_set_cap = sband->ht_cap.mcs.tx_params;
 | 
						tx_mcs_set_cap = sband->ht_cap.mcs.tx_params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Copy peer MCS TX capabilities, the driver might need them. */
 | 
						/* Copy peer MCS TX capabilities, the driver might need them. */
 | 
				
			||||||
	ht_cap->mcs.tx_params = ht_cap_ie->mcs.tx_params;
 | 
						ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* can we TX with MCS rates? */
 | 
						/* can we TX with MCS rates? */
 | 
				
			||||||
	if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED))
 | 
						if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED))
 | 
				
			||||||
		return;
 | 
							goto apply;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Counting from 0, therefore +1 */
 | 
						/* Counting from 0, therefore +1 */
 | 
				
			||||||
	if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF)
 | 
						if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF)
 | 
				
			||||||
| 
						 | 
					@ -176,25 +166,53 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
	 * - remainder are multiple spatial streams using unequal modulation
 | 
						 * - remainder are multiple spatial streams using unequal modulation
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	for (i = 0; i < max_tx_streams; i++)
 | 
						for (i = 0; i < max_tx_streams; i++)
 | 
				
			||||||
		ht_cap->mcs.rx_mask[i] =
 | 
							ht_cap.mcs.rx_mask[i] =
 | 
				
			||||||
			sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
 | 
								sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
 | 
						if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
 | 
				
			||||||
		for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
 | 
							for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
 | 
				
			||||||
		     i < IEEE80211_HT_MCS_MASK_LEN; i++)
 | 
							     i < IEEE80211_HT_MCS_MASK_LEN; i++)
 | 
				
			||||||
			ht_cap->mcs.rx_mask[i] =
 | 
								ht_cap.mcs.rx_mask[i] =
 | 
				
			||||||
				sband->ht_cap.mcs.rx_mask[i] &
 | 
									sband->ht_cap.mcs.rx_mask[i] &
 | 
				
			||||||
					ht_cap_ie->mcs.rx_mask[i];
 | 
										ht_cap_ie->mcs.rx_mask[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* handle MCS rate 32 too */
 | 
						/* handle MCS rate 32 too */
 | 
				
			||||||
	if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
 | 
						if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
 | 
				
			||||||
		ht_cap->mcs.rx_mask[32/8] |= 1;
 | 
							ht_cap.mcs.rx_mask[32/8] |= 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 apply:
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * If user has specified capability over-rides, take care
 | 
						 * If user has specified capability over-rides, take care
 | 
				
			||||||
	 * of that here.
 | 
						 * of that here.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	ieee80211_apply_htcap_overrides(sdata, ht_cap);
 | 
						ieee80211_apply_htcap_overrides(sdata, &ht_cap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (sdata->vif.bss_conf.chandef.width) {
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							WARN_ON_ONCE(1);
 | 
				
			||||||
 | 
							/* fall through */
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_20_NOHT:
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_20:
 | 
				
			||||||
 | 
							bw = IEEE80211_STA_RX_BW_20;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_40:
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_80:
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_80P80:
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_160:
 | 
				
			||||||
 | 
							bw = ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
 | 
				
			||||||
 | 
									IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bw != sta->sta.bandwidth)
 | 
				
			||||||
 | 
							changed = true;
 | 
				
			||||||
 | 
						sta->sta.bandwidth = bw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return changed;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
 | 
					void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -496,33 +496,26 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
		if (sta && elems->ht_operation && elems->ht_cap_elem &&
 | 
							if (sta && elems->ht_operation && elems->ht_cap_elem &&
 | 
				
			||||||
		    sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) {
 | 
							    sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) {
 | 
				
			||||||
			/* we both use HT */
 | 
								/* we both use HT */
 | 
				
			||||||
			struct ieee80211_sta_ht_cap sta_ht_cap_new;
 | 
								struct ieee80211_ht_cap htcap_ie;
 | 
				
			||||||
			struct cfg80211_chan_def chandef;
 | 
								struct cfg80211_chan_def chandef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			ieee80211_ht_oper_to_chandef(channel,
 | 
								ieee80211_ht_oper_to_chandef(channel,
 | 
				
			||||||
						     elems->ht_operation,
 | 
											     elems->ht_operation,
 | 
				
			||||||
						     &chandef);
 | 
											     &chandef);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
 | 
								memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
 | 
				
			||||||
							  elems->ht_cap_elem,
 | 
					 | 
				
			||||||
							  &sta_ht_cap_new);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * fall back to HT20 if we don't use or use
 | 
								 * fall back to HT20 if we don't use or use
 | 
				
			||||||
			 * the other extension channel
 | 
								 * the other extension channel
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			if (chandef.width != NL80211_CHAN_WIDTH_40 ||
 | 
								if (cfg80211_get_chandef_type(&chandef) !=
 | 
				
			||||||
			    cfg80211_get_chandef_type(&chandef) !=
 | 
					 | 
				
			||||||
						sdata->u.ibss.channel_type)
 | 
											sdata->u.ibss.channel_type)
 | 
				
			||||||
				sta_ht_cap_new.cap &=
 | 
									htcap_ie.cap_info &=
 | 
				
			||||||
					~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
										cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (memcmp(&sta->sta.ht_cap, &sta_ht_cap_new,
 | 
								rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(
 | 
				
			||||||
				   sizeof(sta_ht_cap_new))) {
 | 
											sdata, sband, &htcap_ie, sta);
 | 
				
			||||||
				memcpy(&sta->sta.ht_cap, &sta_ht_cap_new,
 | 
					 | 
				
			||||||
				       sizeof(sta_ht_cap_new));
 | 
					 | 
				
			||||||
				rates_updated = true;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (sta && rates_updated) {
 | 
							if (sta && rates_updated) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1384,10 +1384,10 @@ void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
 | 
				
			||||||
/* HT */
 | 
					/* HT */
 | 
				
			||||||
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
 | 
					void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
				     struct ieee80211_sta_ht_cap *ht_cap);
 | 
									     struct ieee80211_sta_ht_cap *ht_cap);
 | 
				
			||||||
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
 | 
					bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
				       struct ieee80211_supported_band *sband,
 | 
									       struct ieee80211_supported_band *sband,
 | 
				
			||||||
				       struct ieee80211_ht_cap *ht_cap_ie,
 | 
									       struct ieee80211_ht_cap *ht_cap_ie,
 | 
				
			||||||
				       struct ieee80211_sta_ht_cap *ht_cap);
 | 
									       struct sta_info *sta);
 | 
				
			||||||
void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
 | 
					void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
			  const u8 *da, u16 tid,
 | 
								  const u8 *da, u16 tid,
 | 
				
			||||||
			  u16 initiator, u16 reason_code);
 | 
								  u16 initiator, u16 reason_code);
 | 
				
			||||||
| 
						 | 
					@ -1431,6 +1431,7 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
					 struct ieee80211_supported_band *sband,
 | 
										 struct ieee80211_supported_band *sband,
 | 
				
			||||||
					 struct ieee80211_vht_cap *vht_cap_ie,
 | 
										 struct ieee80211_vht_cap *vht_cap_ie,
 | 
				
			||||||
					 struct sta_info *sta);
 | 
										 struct sta_info *sta);
 | 
				
			||||||
 | 
					enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Spectrum management */
 | 
					/* Spectrum management */
 | 
				
			||||||
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
 | 
					void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -373,8 +373,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
	if (elems->ht_cap_elem &&
 | 
						if (elems->ht_cap_elem &&
 | 
				
			||||||
	    sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
 | 
						    sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
 | 
				
			||||||
		ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
 | 
							ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
 | 
				
			||||||
						  elems->ht_cap_elem,
 | 
											  elems->ht_cap_elem, sta);
 | 
				
			||||||
						  &sta->sta.ht_cap);
 | 
					 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap));
 | 
							memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -383,8 +382,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!(elems->ht_operation->ht_param &
 | 
							if (!(elems->ht_operation->ht_param &
 | 
				
			||||||
		      IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
 | 
							      IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
 | 
				
			||||||
			sta->sta.ht_cap.cap &=
 | 
								sta->sta.bandwidth = IEEE80211_STA_RX_BW_20;
 | 
				
			||||||
					    ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
					 | 
				
			||||||
		ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
 | 
							ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
 | 
				
			||||||
					     elems->ht_operation, &chandef);
 | 
										     elems->ht_operation, &chandef);
 | 
				
			||||||
		if (sta->ch_width != chandef.width)
 | 
							if (sta->ch_width != chandef.width)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -219,19 +219,20 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
	mutex_lock(&local->sta_mtx);
 | 
						mutex_lock(&local->sta_mtx);
 | 
				
			||||||
	sta = sta_info_get(sdata, bssid);
 | 
						sta = sta_info_get(sdata, bssid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	WARN_ON_ONCE(!sta);
 | 
						if (WARN_ON_ONCE(!sta)) {
 | 
				
			||||||
 | 
							mutex_unlock(&local->sta_mtx);
 | 
				
			||||||
 | 
							return changed;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sta && !sta->supports_40mhz)
 | 
						if (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
 | 
				
			||||||
		disable_40 = true;
 | 
							disable_40 = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sta && (!reconfig ||
 | 
						if (!reconfig ||
 | 
				
			||||||
		    (disable_40 != !(sta->sta.ht_cap.cap &
 | 
						    disable_40 != (sta->sta.bandwidth < IEEE80211_STA_RX_BW_40)) {
 | 
				
			||||||
					IEEE80211_HT_CAP_SUP_WIDTH_20_40)))) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (disable_40)
 | 
							if (disable_40)
 | 
				
			||||||
			sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
								sta->sta.bandwidth = IEEE80211_STA_RX_BW_20;
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			sta->sta.ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
								sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rate_control_rate_update(local, sband, sta,
 | 
							rate_control_rate_update(local, sband, sta,
 | 
				
			||||||
					 IEEE80211_RC_BW_CHANGED);
 | 
										 IEEE80211_RC_BW_CHANGED);
 | 
				
			||||||
| 
						 | 
					@ -2210,10 +2211,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
 | 
						if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
 | 
				
			||||||
		ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
 | 
							ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
 | 
				
			||||||
				elems.ht_cap_elem, &sta->sta.ht_cap);
 | 
											  elems.ht_cap_elem, sta);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	sta->supports_40mhz =
 | 
					 | 
				
			||||||
		sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (elems.vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
 | 
						if (elems.vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
 | 
				
			||||||
		ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
 | 
							ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -848,8 +848,6 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
 | 
				
			||||||
		IEEE80211_HT_CAP_SM_PS_SHIFT;
 | 
							IEEE80211_HT_CAP_SM_PS_SHIFT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(mi->groups); i++) {
 | 
						for (i = 0; i < ARRAY_SIZE(mi->groups); i++) {
 | 
				
			||||||
		u16 req = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		mi->groups[i].supported = 0;
 | 
							mi->groups[i].supported = 0;
 | 
				
			||||||
		if (i == MINSTREL_CCK_GROUP) {
 | 
							if (i == MINSTREL_CCK_GROUP) {
 | 
				
			||||||
			minstrel_ht_update_cck(mp, mi, sband, sta);
 | 
								minstrel_ht_update_cck(mp, mi, sband, sta);
 | 
				
			||||||
| 
						 | 
					@ -857,16 +855,17 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) {
 | 
							if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) {
 | 
				
			||||||
			if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
 | 
								if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
 | 
				
			||||||
				req |= IEEE80211_HT_CAP_SGI_40;
 | 
									if (!(sta_cap & IEEE80211_HT_CAP_SGI_40))
 | 
				
			||||||
			else
 | 
										continue;
 | 
				
			||||||
				req |= IEEE80211_HT_CAP_SGI_20;
 | 
								} else {
 | 
				
			||||||
 | 
									if (!(sta_cap & IEEE80211_HT_CAP_SGI_20))
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
 | 
							if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH &&
 | 
				
			||||||
			req |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
							    sta->bandwidth < IEEE80211_STA_RX_BW_40)
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if ((sta_cap & req) != req)
 | 
					 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Mark MCS > 7 as unsupported if STA is in static SMPS mode */
 | 
							/* Mark MCS > 7 as unsupported if STA is in static SMPS mode */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2410,25 +2410,20 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 | 
				
			||||||
		case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: {
 | 
							case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: {
 | 
				
			||||||
			struct ieee80211_supported_band *sband;
 | 
								struct ieee80211_supported_band *sband;
 | 
				
			||||||
			u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth;
 | 
								u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth;
 | 
				
			||||||
			bool old_40mhz, new_40mhz;
 | 
								enum ieee80211_sta_rx_bandwidth new_bw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* If it doesn't support 40 MHz it can't change ... */
 | 
								/* If it doesn't support 40 MHz it can't change ... */
 | 
				
			||||||
			if (!rx->sta->supports_40mhz)
 | 
								if (!(rx->sta->sta.ht_cap.cap &
 | 
				
			||||||
 | 
										IEEE80211_HT_CAP_SUP_WIDTH_20_40))
 | 
				
			||||||
				goto handled;
 | 
									goto handled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			old_40mhz = rx->sta->sta.ht_cap.cap &
 | 
								if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ)
 | 
				
			||||||
					IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
									new_bw = IEEE80211_STA_RX_BW_20;
 | 
				
			||||||
			new_40mhz = chanwidth == IEEE80211_HT_CHANWIDTH_ANY;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (old_40mhz == new_40mhz)
 | 
					 | 
				
			||||||
				goto handled;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (new_40mhz)
 | 
					 | 
				
			||||||
				rx->sta->sta.ht_cap.cap |=
 | 
					 | 
				
			||||||
					IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
					 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				rx->sta->sta.ht_cap.cap &=
 | 
									new_bw = ieee80211_sta_cur_vht_bw(rx->sta);
 | 
				
			||||||
					~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 | 
					
 | 
				
			||||||
 | 
								if (rx->sta->sta.bandwidth == new_bw)
 | 
				
			||||||
 | 
									goto handled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			sband = rx->local->hw.wiphy->bands[status->band];
 | 
								sband = rx->local->hw.wiphy->bands[status->band];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -296,8 +296,6 @@ struct sta_ampdu_mlme {
 | 
				
			||||||
 * @sta: station information we share with the driver
 | 
					 * @sta: station information we share with the driver
 | 
				
			||||||
 * @sta_state: duplicates information about station state (for debug)
 | 
					 * @sta_state: duplicates information about station state (for debug)
 | 
				
			||||||
 * @beacon_loss_count: number of times beacon loss has triggered
 | 
					 * @beacon_loss_count: number of times beacon loss has triggered
 | 
				
			||||||
 * @supports_40mhz: tracks whether the station advertised 40 MHz support
 | 
					 | 
				
			||||||
 *	as we overwrite its HT parameters with the currently used value
 | 
					 | 
				
			||||||
 * @rcu_head: RCU head used for freeing this station struct
 | 
					 * @rcu_head: RCU head used for freeing this station struct
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sta_info {
 | 
					struct sta_info {
 | 
				
			||||||
| 
						 | 
					@ -403,8 +401,6 @@ struct sta_info {
 | 
				
			||||||
	unsigned int lost_packets;
 | 
						unsigned int lost_packets;
 | 
				
			||||||
	unsigned int beacon_loss_count;
 | 
						unsigned int beacon_loss_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool supports_40mhz;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* keep last! */
 | 
						/* keep last! */
 | 
				
			||||||
	struct ieee80211_sta sta;
 | 
						struct ieee80211_sta sta;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,10 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
	if (!vht_cap_ie || !sband->vht_cap.vht_supported)
 | 
						if (!vht_cap_ie || !sband->vht_cap.vht_supported)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* A VHT STA must support 40 MHz */
 | 
				
			||||||
 | 
						if (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vht_cap->vht_supported = true;
 | 
						vht_cap->vht_supported = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info);
 | 
						vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info);
 | 
				
			||||||
| 
						 | 
					@ -34,4 +38,39 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
	/* Copy peer MCS info, the driver might need them. */
 | 
						/* Copy peer MCS info, the driver might need them. */
 | 
				
			||||||
	memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs,
 | 
						memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs,
 | 
				
			||||||
	       sizeof(struct ieee80211_vht_mcs_info));
 | 
						       sizeof(struct ieee80211_vht_mcs_info));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ieee80211_sub_if_data *sdata = sta->sdata;
 | 
				
			||||||
 | 
						u32 cap = sta->sta.vht_cap.cap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!sta->sta.vht_cap.vht_supported)
 | 
				
			||||||
 | 
							return sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
 | 
				
			||||||
 | 
									IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* TODO: handle VHT opmode notification data */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (sdata->vif.bss_conf.chandef.width) {
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							WARN_ON_ONCE(1);
 | 
				
			||||||
 | 
							/* fall through */
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_20_NOHT:
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_20:
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_40:
 | 
				
			||||||
 | 
							return sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
 | 
				
			||||||
 | 
									IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_160:
 | 
				
			||||||
 | 
							if (cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)
 | 
				
			||||||
 | 
								return IEEE80211_STA_RX_BW_160;
 | 
				
			||||||
 | 
							/* fall through */
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_80P80:
 | 
				
			||||||
 | 
							if (cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
 | 
				
			||||||
 | 
								return IEEE80211_STA_RX_BW_160;
 | 
				
			||||||
 | 
							/* fall through */
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_80:
 | 
				
			||||||
 | 
							return IEEE80211_STA_RX_BW_80;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue