802.11: clean up/fix HT support
This patch cleans up a number of things:
 * the unusable definition of the HT capabilities/HT information
   information elements
 * variable names that are hard to understand
 * mac80211: move ieee80211_handle_ht to ht.c and remove the unused
             enable_ht parameter
 * mac80211: fix bug with MCS rate 32 in ieee80211_handle_ht
 * mac80211: fix bug with casting the result of ieee80211_bss_get_ie
             to an information element _contents_ rather than the
             whole element, add size checking (another out-of-bounds
             access bug fixed!)
 * mac80211: remove some unused return values in favour of BUG_ON
             checking
 * a few minor other things
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
			
			
This commit is contained in:
		
							parent
							
								
									40333e4fb4
								
							
						
					
					
						commit
						d9fe60dea7
					
				| @ -61,24 +61,24 @@ static u32 ath_get_extchanmode(struct ath_softc *sc, | ||||
| 
 | ||||
| 	switch (chan->band) { | ||||
| 	case IEEE80211_BAND_2GHZ: | ||||
| 		if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) && | ||||
| 		if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) && | ||||
| 		    (tx_chan_width == ATH9K_HT_MACMODE_20)) | ||||
| 			chanmode = CHANNEL_G_HT20; | ||||
| 		if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) && | ||||
| 		if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) && | ||||
| 		    (tx_chan_width == ATH9K_HT_MACMODE_2040)) | ||||
| 			chanmode = CHANNEL_G_HT40PLUS; | ||||
| 		if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) && | ||||
| 		if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) && | ||||
| 		    (tx_chan_width == ATH9K_HT_MACMODE_2040)) | ||||
| 			chanmode = CHANNEL_G_HT40MINUS; | ||||
| 		break; | ||||
| 	case IEEE80211_BAND_5GHZ: | ||||
| 		if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) && | ||||
| 		if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) && | ||||
| 		    (tx_chan_width == ATH9K_HT_MACMODE_20)) | ||||
| 			chanmode = CHANNEL_A_HT20; | ||||
| 		if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) && | ||||
| 		if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) && | ||||
| 		    (tx_chan_width == ATH9K_HT_MACMODE_2040)) | ||||
| 			chanmode = CHANNEL_A_HT40PLUS; | ||||
| 		if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) && | ||||
| 		if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) && | ||||
| 		    (tx_chan_width == ATH9K_HT_MACMODE_2040)) | ||||
| 			chanmode = CHANNEL_A_HT40MINUS; | ||||
| 		break; | ||||
| @ -215,24 +215,24 @@ static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) | ||||
| 	ath_key_reset(sc, key->keyidx, freeslot); | ||||
| } | ||||
| 
 | ||||
| static void setup_ht_cap(struct ieee80211_ht_info *ht_info) | ||||
| static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info) | ||||
| { | ||||
| #define	ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3	/* 2 ^ 16 */ | ||||
| #define	ATH9K_HT_CAP_MPDUDENSITY_8 0x6		/* 8 usec */ | ||||
| 
 | ||||
| 	ht_info->ht_supported = 1; | ||||
| 	ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH | ||||
| 			|(u16)IEEE80211_HT_CAP_SM_PS | ||||
| 			|(u16)IEEE80211_HT_CAP_SGI_40 | ||||
| 			|(u16)IEEE80211_HT_CAP_DSSSCCK40; | ||||
| 	ht_info->ht_supported = true; | ||||
| 	ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | ||||
| 		       IEEE80211_HT_CAP_SM_PS | | ||||
| 		       IEEE80211_HT_CAP_SGI_40 | | ||||
| 		       IEEE80211_HT_CAP_DSSSCCK40; | ||||
| 
 | ||||
| 	ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; | ||||
| 	ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; | ||||
| 	/* setup supported mcs set */ | ||||
| 	memset(ht_info->supp_mcs_set, 0, 16); | ||||
| 	ht_info->supp_mcs_set[0] = 0xff; | ||||
| 	ht_info->supp_mcs_set[1] = 0xff; | ||||
| 	ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED; | ||||
| 	/* set up supported mcs set */ | ||||
| 	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); | ||||
| 	ht_info->mcs.rx_mask[0] = 0xff; | ||||
| 	ht_info->mcs.rx_mask[1] = 0xff; | ||||
| 	ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | ||||
| } | ||||
| 
 | ||||
| static int ath_rate2idx(struct ath_softc *sc, int rate) | ||||
| @ -328,31 +328,28 @@ static u8 parse_mpdudensity(u8 mpdudensity) | ||||
| static void ath9k_ht_conf(struct ath_softc *sc, | ||||
| 			  struct ieee80211_bss_conf *bss_conf) | ||||
| { | ||||
| #define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14) | ||||
| 	struct ath_ht_info *ht_info = &sc->sc_ht_info; | ||||
| 
 | ||||
| 	if (bss_conf->assoc_ht) { | ||||
| 		ht_info->ext_chan_offset = | ||||
| 			bss_conf->ht_bss_conf->bss_cap & | ||||
| 				IEEE80211_HT_IE_CHA_SEC_OFFSET; | ||||
| 				IEEE80211_HT_PARAM_CHA_SEC_OFFSET; | ||||
| 
 | ||||
| 		if (!(bss_conf->ht_conf->cap & | ||||
| 		if (!(bss_conf->ht_cap->cap & | ||||
| 			IEEE80211_HT_CAP_40MHZ_INTOLERANT) && | ||||
| 			    (bss_conf->ht_bss_conf->bss_cap & | ||||
| 				IEEE80211_HT_IE_CHA_WIDTH)) | ||||
| 				IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) | ||||
| 			ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040; | ||||
| 		else | ||||
| 			ht_info->tx_chan_width = ATH9K_HT_MACMODE_20; | ||||
| 
 | ||||
| 		ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width); | ||||
| 		ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + | ||||
| 					bss_conf->ht_conf->ampdu_factor); | ||||
| 					bss_conf->ht_cap->ampdu_factor); | ||||
| 		ht_info->mpdudensity = | ||||
| 			parse_mpdudensity(bss_conf->ht_conf->ampdu_density); | ||||
| 			parse_mpdudensity(bss_conf->ht_cap->ampdu_density); | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| #undef IEEE80211_HT_CAP_40MHZ_INTOLERANT | ||||
| } | ||||
| 
 | ||||
| static void ath9k_bss_assoc_info(struct ath_softc *sc, | ||||
| @ -411,7 +408,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		if (hw->conf.ht_conf.ht_supported) | ||||
| 		if (hw->conf.ht_cap.ht_supported) | ||||
| 			sc->sc_ah->ah_channels[pos].chanmode = | ||||
| 				ath_get_extchanmode(sc, curchan); | ||||
| 		else | ||||
| @ -534,7 +531,7 @@ int _ath_rx_indicate(struct ath_softc *sc, | ||||
| 
 | ||||
| 	if (an) { | ||||
| 		ath_rx_input(sc, an, | ||||
| 			     hw->conf.ht_conf.ht_supported, | ||||
| 			     hw->conf.ht_cap.ht_supported, | ||||
| 			     skb, status, &st); | ||||
| 	} | ||||
| 	if (!an || (st != ATH_RX_CONSUMED)) | ||||
| @ -943,7 +940,7 @@ static int ath_attach(u16 devid, | ||||
| 
 | ||||
| 	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) | ||||
| 		/* Setup HT capabilities for 2.4Ghz*/ | ||||
| 		setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_info); | ||||
| 		setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); | ||||
| 
 | ||||
| 	hw->wiphy->bands[IEEE80211_BAND_2GHZ] = | ||||
| 		&sc->sbands[IEEE80211_BAND_2GHZ]; | ||||
| @ -958,7 +955,7 @@ static int ath_attach(u16 devid, | ||||
| 
 | ||||
| 		if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) | ||||
| 			/* Setup HT capabilities for 5Ghz*/ | ||||
| 			setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_info); | ||||
| 			setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); | ||||
| 
 | ||||
| 		hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | ||||
| 			&sc->sbands[IEEE80211_BAND_5GHZ]; | ||||
| @ -1254,7 +1251,7 @@ static int ath9k_config(struct ieee80211_hw *hw, | ||||
| 		(curchan->band == IEEE80211_BAND_2GHZ) ? | ||||
| 		CHANNEL_G : CHANNEL_A; | ||||
| 
 | ||||
| 	if (sc->sc_curaid && hw->conf.ht_conf.ht_supported) | ||||
| 	if (sc->sc_curaid && hw->conf.ht_cap.ht_supported) | ||||
| 		sc->sc_ah->ah_channels[pos].chanmode = | ||||
| 			ath_get_extchanmode(sc, curchan); | ||||
| 
 | ||||
|  | ||||
| @ -1838,7 +1838,7 @@ void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv) | ||||
| 	struct ath_softc *sc = hw->priv; | ||||
| 	u32 capflag = 0; | ||||
| 
 | ||||
| 	if (hw->conf.ht_conf.ht_supported) { | ||||
| 	if (hw->conf.ht_cap.ht_supported) { | ||||
| 		capflag |= ATH_RC_HT_FLAG | ATH_RC_DS_FLAG; | ||||
| 		if (sc->sc_ht_info.tx_chan_width == ATH9K_HT_MACMODE_2040) | ||||
| 			capflag |= ATH_RC_CW40_FLAG; | ||||
| @ -1910,7 +1910,7 @@ static void ath_tx_aggr_resp(struct ath_softc *sc, | ||||
| 	 */ | ||||
| 	si = container_of(sta, struct sta_info, sta); | ||||
| 	buffersize = IEEE80211_MIN_AMPDU_BUF << | ||||
| 		sband->ht_info.ampdu_factor; /* FIXME */ | ||||
| 		sband->ht_cap.ampdu_factor; /* FIXME */ | ||||
| 	state = si->ampdu_mlme.tid_state_tx[tidno]; | ||||
| 
 | ||||
| 	if (state & HT_ADDBA_RECEIVED_MSK) { | ||||
| @ -1979,7 +1979,7 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, | ||||
| 
 | ||||
| 	/* Check if aggregation has to be enabled for this tid */ | ||||
| 
 | ||||
| 	if (hw->conf.ht_conf.ht_supported) { | ||||
| 	if (hw->conf.ht_cap.ht_supported) { | ||||
| 		if (ieee80211_is_data_qos(fc)) { | ||||
| 			qc = ieee80211_get_qos_ctl(hdr); | ||||
| 			tid = qc[0] & 0xf; | ||||
| @ -2027,8 +2027,8 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, | ||||
| 
 | ||||
| 	ath_setup_rates(sc, sband, sta, ath_rc_priv); | ||||
| 	if (sc->hw->conf.flags & IEEE80211_CONF_SUPPORT_HT_MODE) { | ||||
| 		for (i = 0; i < MCS_SET_SIZE; i++) { | ||||
| 			if (sc->hw->conf.ht_conf.supp_mcs_set[i/8] & (1<<(i%8))) | ||||
| 		for (i = 0; i < 77; i++) { | ||||
| 			if (sc->hw->conf.ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) | ||||
| 				ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; | ||||
| 			if (j == ATH_RATE_MAX) | ||||
| 				break; | ||||
|  | ||||
| @ -59,7 +59,6 @@ struct ath_softc; | ||||
| #define FALSE 0 | ||||
| 
 | ||||
| #define ATH_RATE_MAX	30 | ||||
| #define MCS_SET_SIZE	128 | ||||
| 
 | ||||
| enum ieee80211_fixed_rate_mode { | ||||
| 	IEEE80211_FIXED_RATE_NONE  = 0, | ||||
|  | ||||
| @ -1119,7 +1119,7 @@ int ath_rx_aggr_start(struct ath_softc *sc, | ||||
| 
 | ||||
| 	sband = hw->wiphy->bands[hw->conf.channel->band]; | ||||
| 	buffersize = IEEE80211_MIN_AMPDU_BUF << | ||||
| 		sband->ht_info.ampdu_factor; /* FIXME */ | ||||
| 		sband->ht_cap.ampdu_factor; /* FIXME */ | ||||
| 
 | ||||
| 	rxtid = &an->an_aggr.rx.tid[tid]; | ||||
| 
 | ||||
|  | ||||
| @ -300,7 +300,7 @@ static int ath_tx_prepare(struct ath_softc *sc, | ||||
| 	if (ieee80211_is_data(fc) && !txctl->use_minrate) { | ||||
| 
 | ||||
| 		/* Enable HT only for DATA frames and not for EAPOL */ | ||||
| 		txctl->ht = (hw->conf.ht_conf.ht_supported && | ||||
| 		txctl->ht = (hw->conf.ht_cap.ht_supported && | ||||
| 			    (tx_info->flags & IEEE80211_TX_CTL_AMPDU)); | ||||
| 
 | ||||
| 		if (is_multicast_ether_addr(hdr->addr1)) { | ||||
|  | ||||
| @ -1134,10 +1134,10 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, | ||||
| 	s8 is_green = lq_sta->is_green; | ||||
| 
 | ||||
| 	if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || | ||||
| 	    !sta->ht_info.ht_supported) | ||||
| 	    !sta->ht_cap.ht_supported) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	if (((sta->ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | ||||
| 	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | ||||
| 						== WLAN_HT_CAP_SM_PS_STATIC) | ||||
| 		return -1; | ||||
| 
 | ||||
| @ -1202,7 +1202,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, | ||||
| 	s32 rate; | ||||
| 
 | ||||
| 	if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || | ||||
| 	    !sta->ht_info.ht_supported) | ||||
| 	    !sta->ht_cap.ht_supported) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	IWL_DEBUG_RATE("LQ: try to switch to SISO\n"); | ||||
| @ -2238,19 +2238,19 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, | ||||
| 	 * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), | ||||
| 	 * supp_rates[] does not; shift to convert format, force 9 MBits off. | ||||
| 	 */ | ||||
| 	lq_sta->active_siso_rate = conf->ht_conf.supp_mcs_set[0] << 1; | ||||
| 	lq_sta->active_siso_rate |= conf->ht_conf.supp_mcs_set[0] & 0x1; | ||||
| 	lq_sta->active_siso_rate = conf->ht_cap.mcs.rx_mask[0] << 1; | ||||
| 	lq_sta->active_siso_rate |= conf->ht_cap.mcs.rx_mask[0] & 0x1; | ||||
| 	lq_sta->active_siso_rate &= ~((u16)0x2); | ||||
| 	lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; | ||||
| 
 | ||||
| 	/* Same here */ | ||||
| 	lq_sta->active_mimo2_rate = conf->ht_conf.supp_mcs_set[1] << 1; | ||||
| 	lq_sta->active_mimo2_rate |= conf->ht_conf.supp_mcs_set[1] & 0x1; | ||||
| 	lq_sta->active_mimo2_rate = conf->ht_cap.mcs.rx_mask[1] << 1; | ||||
| 	lq_sta->active_mimo2_rate |= conf->ht_cap.mcs.rx_mask[1] & 0x1; | ||||
| 	lq_sta->active_mimo2_rate &= ~((u16)0x2); | ||||
| 	lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; | ||||
| 
 | ||||
| 	lq_sta->active_mimo3_rate = conf->ht_conf.supp_mcs_set[2] << 1; | ||||
| 	lq_sta->active_mimo3_rate |= conf->ht_conf.supp_mcs_set[2] & 0x1; | ||||
| 	lq_sta->active_mimo3_rate = conf->ht_cap.mcs.rx_mask[2] << 1; | ||||
| 	lq_sta->active_mimo3_rate |= conf->ht_cap.mcs.rx_mask[2] & 0x1; | ||||
| 	lq_sta->active_mimo3_rate &= ~((u16)0x2); | ||||
| 	lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; | ||||
| 
 | ||||
|  | ||||
| @ -552,7 +552,7 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) | ||||
| static void iwl4965_ht_conf(struct iwl_priv *priv, | ||||
| 			    struct ieee80211_bss_conf *bss_conf) | ||||
| { | ||||
| 	struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf; | ||||
| 	struct ieee80211_sta_ht_cap *ht_conf = bss_conf->ht_cap; | ||||
| 	struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf; | ||||
| 	struct iwl_ht_info *iwl_conf = &priv->current_ht_config; | ||||
| 
 | ||||
| @ -573,27 +573,27 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, | ||||
| 		!!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); | ||||
| 
 | ||||
| 	iwl_conf->supported_chan_width = | ||||
| 		!!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH); | ||||
| 		!!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); | ||||
| 	iwl_conf->extension_chan_offset = | ||||
| 		ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET; | ||||
| 		ht_bss_conf->bss_cap & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; | ||||
| 	/* If no above or below channel supplied disable FAT channel */ | ||||
| 	if (iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_ABOVE && | ||||
| 	    iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_BELOW) { | ||||
| 		iwl_conf->extension_chan_offset = IEEE80211_HT_IE_CHA_SEC_NONE; | ||||
| 	if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && | ||||
| 	    iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) { | ||||
| 		iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||||
| 		iwl_conf->supported_chan_width = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); | ||||
| 
 | ||||
| 	memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); | ||||
| 	memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); | ||||
| 
 | ||||
| 	iwl_conf->control_channel = ht_bss_conf->primary_channel; | ||||
| 	iwl_conf->tx_chan_width = | ||||
| 		!!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH); | ||||
| 		!!(ht_bss_conf->bss_cap & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY); | ||||
| 	iwl_conf->ht_protection = | ||||
| 		ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION; | ||||
| 		ht_bss_conf->bss_op_mode & IEEE80211_HT_OP_MODE_PROTECTION; | ||||
| 	iwl_conf->non_GF_STA_present = | ||||
| 		!!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT); | ||||
| 		!!(ht_bss_conf->bss_op_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); | ||||
| 
 | ||||
| 	IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel); | ||||
| 	IWL_DEBUG_MAC80211("leave\n"); | ||||
|  | ||||
| @ -382,10 +382,10 @@ void iwl_reset_qos(struct iwl_priv *priv) | ||||
| } | ||||
| EXPORT_SYMBOL(iwl_reset_qos); | ||||
| 
 | ||||
| #define MAX_BIT_RATE_40_MHZ 0x96 /* 150 Mbps */ | ||||
| #define MAX_BIT_RATE_20_MHZ 0x48 /* 72 Mbps */ | ||||
| #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ | ||||
| #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ | ||||
| static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, | ||||
| 			      struct ieee80211_ht_info *ht_info, | ||||
| 			      struct ieee80211_sta_ht_cap *ht_info, | ||||
| 			      enum ieee80211_band band) | ||||
| { | ||||
| 	u16 max_bit_rate = 0; | ||||
| @ -393,45 +393,46 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, | ||||
| 	u8 tx_chains_num = priv->hw_params.tx_chains_num; | ||||
| 
 | ||||
| 	ht_info->cap = 0; | ||||
| 	memset(ht_info->supp_mcs_set, 0, 16); | ||||
| 	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); | ||||
| 
 | ||||
| 	ht_info->ht_supported = 1; | ||||
| 	ht_info->ht_supported = true; | ||||
| 
 | ||||
| 	ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; | ||||
| 	ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; | ||||
| 	ht_info->cap |= (u16)(IEEE80211_HT_CAP_SM_PS & | ||||
| 	ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; | ||||
| 	ht_info->cap |= IEEE80211_HT_CAP_SGI_20; | ||||
| 	ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & | ||||
| 			     (WLAN_HT_CAP_SM_PS_DISABLED << 2)); | ||||
| 
 | ||||
| 	max_bit_rate = MAX_BIT_RATE_20_MHZ; | ||||
| 	if (priv->hw_params.fat_channel & BIT(band)) { | ||||
| 		ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH; | ||||
| 		ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40; | ||||
| 		ht_info->supp_mcs_set[4] = 0x01; | ||||
| 		ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||||
| 		ht_info->cap |= IEEE80211_HT_CAP_SGI_40; | ||||
| 		ht_info->mcs.rx_mask[4] = 0x01; | ||||
| 		max_bit_rate = MAX_BIT_RATE_40_MHZ; | ||||
| 	} | ||||
| 
 | ||||
| 	if (priv->cfg->mod_params->amsdu_size_8K) | ||||
| 		ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU; | ||||
| 		ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; | ||||
| 
 | ||||
| 	ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; | ||||
| 	ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; | ||||
| 
 | ||||
| 	ht_info->supp_mcs_set[0] = 0xFF; | ||||
| 	ht_info->mcs.rx_mask[0] = 0xFF; | ||||
| 	if (rx_chains_num >= 2) | ||||
| 		ht_info->supp_mcs_set[1] = 0xFF; | ||||
| 		ht_info->mcs.rx_mask[1] = 0xFF; | ||||
| 	if (rx_chains_num >= 3) | ||||
| 		ht_info->supp_mcs_set[2] = 0xFF; | ||||
| 		ht_info->mcs.rx_mask[2] = 0xFF; | ||||
| 
 | ||||
| 	/* Highest supported Rx data rate */ | ||||
| 	max_bit_rate *= rx_chains_num; | ||||
| 	ht_info->supp_mcs_set[10] = (u8)(max_bit_rate & 0x00FF); | ||||
| 	ht_info->supp_mcs_set[11] = (u8)((max_bit_rate & 0xFF00) >> 8); | ||||
| 	WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK); | ||||
| 	ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate); | ||||
| 
 | ||||
| 	/* Tx MCS capabilities */ | ||||
| 	ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED; | ||||
| 	ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | ||||
| 	if (tx_chains_num != rx_chains_num) { | ||||
| 		ht_info->supp_mcs_set[12] |= IEEE80211_HT_CAP_MCS_TX_RX_DIFF; | ||||
| 		ht_info->supp_mcs_set[12] |= ((tx_chains_num - 1) << 2); | ||||
| 		ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; | ||||
| 		ht_info->mcs.tx_params |= ((tx_chains_num - 1) << | ||||
| 				IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -495,7 +496,7 @@ static int iwlcore_init_geos(struct iwl_priv *priv) | ||||
| 	sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; | ||||
| 
 | ||||
| 	if (priv->cfg->sku & IWL_SKU_N) | ||||
| 		iwlcore_init_ht_hw_capab(priv, &sband->ht_info, | ||||
| 		iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, | ||||
| 					 IEEE80211_BAND_5GHZ); | ||||
| 
 | ||||
| 	sband = &priv->bands[IEEE80211_BAND_2GHZ]; | ||||
| @ -505,7 +506,7 @@ static int iwlcore_init_geos(struct iwl_priv *priv) | ||||
| 	sband->n_bitrates = IWL_RATE_COUNT; | ||||
| 
 | ||||
| 	if (priv->cfg->sku & IWL_SKU_N) | ||||
| 		iwlcore_init_ht_hw_capab(priv, &sband->ht_info, | ||||
| 		iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, | ||||
| 					 IEEE80211_BAND_2GHZ); | ||||
| 
 | ||||
| 	priv->ieee_channels = channels; | ||||
| @ -595,8 +596,8 @@ static void iwlcore_free_geos(struct iwl_priv *priv) | ||||
| static bool is_single_rx_stream(struct iwl_priv *priv) | ||||
| { | ||||
| 	return !priv->current_ht_config.is_ht || | ||||
| 	       ((priv->current_ht_config.supp_mcs_set[1] == 0) && | ||||
| 		(priv->current_ht_config.supp_mcs_set[2] == 0)); | ||||
| 	       ((priv->current_ht_config.mcs.rx_mask[1] == 0) && | ||||
| 		(priv->current_ht_config.mcs.rx_mask[2] == 0)); | ||||
| } | ||||
| 
 | ||||
| static u8 iwl_is_channel_extension(struct iwl_priv *priv, | ||||
| @ -609,10 +610,10 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, | ||||
| 	if (!is_channel_valid(ch_info)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) | ||||
| 	if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) | ||||
| 		return !(ch_info->fat_extension_channel & | ||||
| 					IEEE80211_CHAN_NO_FAT_ABOVE); | ||||
| 	else if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) | ||||
| 	else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) | ||||
| 		return !(ch_info->fat_extension_channel & | ||||
| 					IEEE80211_CHAN_NO_FAT_BELOW); | ||||
| 
 | ||||
| @ -620,18 +621,18 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, | ||||
| } | ||||
| 
 | ||||
| u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, | ||||
| 			     struct ieee80211_ht_info *sta_ht_inf) | ||||
| 			 struct ieee80211_sta_ht_cap *sta_ht_inf) | ||||
| { | ||||
| 	struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; | ||||
| 
 | ||||
| 	if ((!iwl_ht_conf->is_ht) || | ||||
| 	   (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) || | ||||
| 	   (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE)) | ||||
| 	   (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (sta_ht_inf) { | ||||
| 		if ((!sta_ht_inf->ht_supported) || | ||||
| 		   (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH))) | ||||
| 		   (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))) | ||||
| 			return 0; | ||||
| 	} | ||||
| 
 | ||||
| @ -671,13 +672,13 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) | ||||
| 
 | ||||
| 	/* Note: control channel is opposite of extension channel */ | ||||
| 	switch (ht_info->extension_chan_offset) { | ||||
| 	case IEEE80211_HT_IE_CHA_SEC_ABOVE: | ||||
| 	case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||||
| 		rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); | ||||
| 		break; | ||||
| 	case IEEE80211_HT_IE_CHA_SEC_BELOW: | ||||
| 	case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||||
| 		rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; | ||||
| 		break; | ||||
| 	case IEEE80211_HT_IE_CHA_SEC_NONE: | ||||
| 	case IEEE80211_HT_PARAM_CHA_SEC_NONE: | ||||
| 	default: | ||||
| 		rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; | ||||
| 		break; | ||||
| @ -693,9 +694,9 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) | ||||
| 			"rxon flags 0x%X operation mode :0x%X " | ||||
| 			"extension channel offset 0x%x " | ||||
| 			"control chan %d\n", | ||||
| 			ht_info->supp_mcs_set[0], | ||||
| 			ht_info->supp_mcs_set[1], | ||||
| 			ht_info->supp_mcs_set[2], | ||||
| 			ht_info->mcs.rx_mask[0], | ||||
| 			ht_info->mcs.rx_mask[1], | ||||
| 			ht_info->mcs.rx_mask[2], | ||||
| 			le32_to_cpu(rxon->flags), ht_info->ht_protection, | ||||
| 			ht_info->extension_chan_offset, | ||||
| 			ht_info->control_channel); | ||||
|  | ||||
| @ -190,7 +190,7 @@ void iwl_set_rxon_chain(struct iwl_priv *priv); | ||||
| int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); | ||||
| void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); | ||||
| u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, | ||||
| 			 struct ieee80211_ht_info *sta_ht_inf); | ||||
| 			 struct ieee80211_sta_ht_cap *sta_ht_inf); | ||||
| int iwl_hw_nic_init(struct iwl_priv *priv); | ||||
| int iwl_setup_mac(struct iwl_priv *priv); | ||||
| int iwl_set_hw_params(struct iwl_priv *priv); | ||||
|  | ||||
| @ -411,7 +411,7 @@ struct iwl_ht_info { | ||||
| 	u8 max_amsdu_size; | ||||
| 	u8 ampdu_factor; | ||||
| 	u8 mpdu_density; | ||||
| 	u8 supp_mcs_set[16]; | ||||
| 	struct ieee80211_mcs_info mcs; | ||||
| 	/* BSS related data */ | ||||
| 	u8 control_channel; | ||||
| 	u8 extension_chan_offset; | ||||
| @ -585,7 +585,7 @@ struct iwl_addsta_cmd; | ||||
| extern int iwl_send_add_sta(struct iwl_priv *priv, | ||||
| 			    struct iwl_addsta_cmd *sta, u8 flags); | ||||
| extern u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, | ||||
| 			int is_ap, u8 flags, struct ieee80211_ht_info *ht_info); | ||||
| 			int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); | ||||
| extern void iwl4965_update_chain_flags(struct iwl_priv *priv); | ||||
| extern int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); | ||||
| extern const u8 iwl_bcast_addr[ETH_ALEN]; | ||||
|  | ||||
| @ -550,7 +550,7 @@ static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, | ||||
| { | ||||
| 	struct ieee80211_ht_cap *ht_cap; | ||||
| 
 | ||||
| 	if (!sband || !sband->ht_info.ht_supported) | ||||
| 	if (!sband || !sband->ht_cap.ht_supported) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (*left < sizeof(struct ieee80211_ht_cap)) | ||||
| @ -559,12 +559,12 @@ static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, | ||||
| 	*pos++ = sizeof(struct ieee80211_ht_cap); | ||||
| 	ht_cap = (struct ieee80211_ht_cap *) pos; | ||||
| 
 | ||||
| 	ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap); | ||||
| 	memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16); | ||||
| 	ht_cap->cap_info = cpu_to_le16(sband->ht_cap.cap); | ||||
| 	memcpy(&ht_cap->mcs, &sband->ht_cap.mcs, 16); | ||||
| 	ht_cap->ampdu_params_info = | ||||
| 		(sband->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) | | ||||
| 		((sband->ht_info.ampdu_density << 2) & | ||||
| 			IEEE80211_HT_CAP_AMPDU_DENSITY); | ||||
| 		(sband->ht_cap.ampdu_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) | | ||||
| 		((sband->ht_cap.ampdu_density << 2) & | ||||
| 			IEEE80211_HT_AMPDU_PARM_DENSITY); | ||||
| 	*left -= sizeof(struct ieee80211_ht_cap); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -181,7 +181,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, | ||||
| EXPORT_SYMBOL(iwl_send_add_sta); | ||||
| 
 | ||||
| static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, | ||||
| 				   struct ieee80211_ht_info *sta_ht_inf) | ||||
| 				   struct ieee80211_sta_ht_cap *sta_ht_inf) | ||||
| { | ||||
| 	__le32 sta_flags; | ||||
| 	u8 mimo_ps_mode; | ||||
| @ -229,7 +229,7 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, | ||||
|  * iwl_add_station_flags - Add station to tables in driver and device | ||||
|  */ | ||||
| u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, | ||||
| 			 u8 flags, struct ieee80211_ht_info *ht_info) | ||||
| 			 u8 flags, struct ieee80211_sta_ht_cap *ht_info) | ||||
| { | ||||
| 	int i; | ||||
| 	int sta_id = IWL_INVALID_STATION; | ||||
| @ -894,7 +894,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) | ||||
| 
 | ||||
| 	/* Add station to device's station table */ | ||||
| 	struct ieee80211_conf *conf = &priv->hw->conf; | ||||
| 	struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf; | ||||
| 	struct ieee80211_sta_ht_cap *cur_ht_config = &conf->ht_cap; | ||||
| 
 | ||||
| 	if ((is_ap) && | ||||
| 	    (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && | ||||
|  | ||||
| @ -563,19 +563,18 @@ static int __init init_mac80211_hwsim(void) | ||||
| 		data->band.n_channels = ARRAY_SIZE(hwsim_channels); | ||||
| 		data->band.bitrates = data->rates; | ||||
| 		data->band.n_bitrates = ARRAY_SIZE(hwsim_rates); | ||||
| 		data->band.ht_info.ht_supported = 1; | ||||
| 		data->band.ht_info.cap = IEEE80211_HT_CAP_SUP_WIDTH | | ||||
| 		data->band.ht_cap.ht_supported = true; | ||||
| 		data->band.ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | ||||
| 			IEEE80211_HT_CAP_GRN_FLD | | ||||
| 			IEEE80211_HT_CAP_SGI_40 | | ||||
| 			IEEE80211_HT_CAP_DSSSCCK40; | ||||
| 		data->band.ht_info.ampdu_factor = 0x3; | ||||
| 		data->band.ht_info.ampdu_density = 0x6; | ||||
| 		memset(data->band.ht_info.supp_mcs_set, 0, | ||||
| 		       sizeof(data->band.ht_info.supp_mcs_set)); | ||||
| 		data->band.ht_info.supp_mcs_set[0] = 0xff; | ||||
| 		data->band.ht_info.supp_mcs_set[1] = 0xff; | ||||
| 		data->band.ht_info.supp_mcs_set[12] = | ||||
| 			IEEE80211_HT_CAP_MCS_TX_DEFINED; | ||||
| 		data->band.ht_cap.ampdu_factor = 0x3; | ||||
| 		data->band.ht_cap.ampdu_density = 0x6; | ||||
| 		memset(&data->band.ht_cap.mcs, 0, | ||||
| 		       sizeof(data->band.ht_cap.mcs)); | ||||
| 		data->band.ht_cap.mcs.rx_mask[0] = 0xff; | ||||
| 		data->band.ht_cap.mcs.rx_mask[1] = 0xff; | ||||
| 		data->band.ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | ||||
| 		hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band; | ||||
| 
 | ||||
| 		err = ieee80211_register_hw(hw); | ||||
|  | ||||
| @ -685,28 +685,88 @@ struct ieee80211_bar { | ||||
| #define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL     0x0000 | ||||
| #define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA  0x0004 | ||||
| 
 | ||||
| 
 | ||||
| #define IEEE80211_HT_MCS_MASK_LEN		10 | ||||
| 
 | ||||
| /**
 | ||||
|  * struct ieee80211_mcs_info - MCS information | ||||
|  * @rx_mask: RX mask | ||||
|  * @rx_highest: highest supported RX rate | ||||
|  * @tx_params: TX parameters | ||||
|  */ | ||||
| struct ieee80211_mcs_info { | ||||
| 	u8 rx_mask[IEEE80211_HT_MCS_MASK_LEN]; | ||||
| 	__le16 rx_highest; | ||||
| 	u8 tx_params; | ||||
| 	u8 reserved[3]; | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| /* 802.11n HT capability MSC set */ | ||||
| #define IEEE80211_HT_MCS_RX_HIGHEST_MASK	0x3ff | ||||
| #define IEEE80211_HT_MCS_TX_DEFINED		0x01 | ||||
| #define IEEE80211_HT_MCS_TX_RX_DIFF		0x02 | ||||
| /* value 0 == 1 stream etc */ | ||||
| #define IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK	0x0C | ||||
| #define IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT	2 | ||||
| #define		IEEE80211_HT_MCS_TX_MAX_STREAMS	4 | ||||
| #define IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION	0x10 | ||||
| 
 | ||||
| /*
 | ||||
|  * 802.11n D5.0 20.3.5 / 20.6 says: | ||||
|  * - indices 0 to 7 and 32 are single spatial stream | ||||
|  * - 8 to 31 are multiple spatial streams using equal modulation | ||||
|  *   [8..15 for two streams, 16..23 for three and 24..31 for four] | ||||
|  * - remainder are multiple spatial streams using unequal modulation | ||||
|  */ | ||||
| #define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START 33 | ||||
| #define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE \ | ||||
| 	(IEEE80211_HT_MCS_UNEQUAL_MODULATION_START / 8) | ||||
| 
 | ||||
| /**
 | ||||
|  * struct ieee80211_ht_cap - HT capabilities | ||||
|  * | ||||
|  * This structure refers to "HT capabilities element" as | ||||
|  * described in 802.11n draft section 7.3.2.52 | ||||
|  * This structure is the "HT capabilities element" as | ||||
|  * described in 802.11n D5.0 7.3.2.57 | ||||
|  */ | ||||
| struct ieee80211_ht_cap { | ||||
| 	__le16 cap_info; | ||||
| 	u8 ampdu_params_info; | ||||
| 	u8 supp_mcs_set[16]; | ||||
| 
 | ||||
| 	/* 16 bytes MCS information */ | ||||
| 	struct ieee80211_mcs_info mcs; | ||||
| 
 | ||||
| 	__le16 extended_ht_cap_info; | ||||
| 	__le32 tx_BF_cap_info; | ||||
| 	u8 antenna_selection_info; | ||||
| } __attribute__ ((packed)); | ||||
| 
 | ||||
| /* 802.11n HT capabilities masks (for cap_info) */ | ||||
| #define IEEE80211_HT_CAP_LDPC_CODING		0x0001 | ||||
| #define IEEE80211_HT_CAP_SUP_WIDTH_20_40	0x0002 | ||||
| #define IEEE80211_HT_CAP_SM_PS			0x000C | ||||
| #define IEEE80211_HT_CAP_GRN_FLD		0x0010 | ||||
| #define IEEE80211_HT_CAP_SGI_20			0x0020 | ||||
| #define IEEE80211_HT_CAP_SGI_40			0x0040 | ||||
| #define IEEE80211_HT_CAP_TX_STBC		0x0080 | ||||
| #define IEEE80211_HT_CAP_RX_STBC		0x0300 | ||||
| #define IEEE80211_HT_CAP_DELAY_BA		0x0400 | ||||
| #define IEEE80211_HT_CAP_MAX_AMSDU		0x0800 | ||||
| #define IEEE80211_HT_CAP_DSSSCCK40		0x1000 | ||||
| #define IEEE80211_HT_CAP_PSMP_SUPPORT		0x2000 | ||||
| #define IEEE80211_HT_CAP_40MHZ_INTOLERANT	0x4000 | ||||
| #define IEEE80211_HT_CAP_LSIG_TXOP_PROT		0x8000 | ||||
| 
 | ||||
| /* 802.11n HT capability AMPDU settings (for ampdu_params_info) */ | ||||
| #define IEEE80211_HT_AMPDU_PARM_FACTOR		0x03 | ||||
| #define IEEE80211_HT_AMPDU_PARM_DENSITY		0x1C | ||||
| 
 | ||||
| /**
 | ||||
|  * struct ieee80211_ht_cap - HT additional information | ||||
|  * struct ieee80211_ht_info - HT information | ||||
|  * | ||||
|  * This structure refers to "HT information element" as | ||||
|  * described in 802.11n draft section 7.3.2.53 | ||||
|  * This structure is the "HT information element" as | ||||
|  * described in 802.11n D5.0 7.3.2.58 | ||||
|  */ | ||||
| struct ieee80211_ht_addt_info { | ||||
| struct ieee80211_ht_info { | ||||
| 	u8 control_chan; | ||||
| 	u8 ht_param; | ||||
| 	__le16 operation_mode; | ||||
| @ -714,36 +774,33 @@ struct ieee80211_ht_addt_info { | ||||
| 	u8 basic_set[16]; | ||||
| } __attribute__ ((packed)); | ||||
| 
 | ||||
| /* 802.11n HT capabilities masks */ | ||||
| #define IEEE80211_HT_CAP_SUP_WIDTH		0x0002 | ||||
| #define IEEE80211_HT_CAP_SM_PS			0x000C | ||||
| #define IEEE80211_HT_CAP_GRN_FLD		0x0010 | ||||
| #define IEEE80211_HT_CAP_SGI_20			0x0020 | ||||
| #define IEEE80211_HT_CAP_SGI_40			0x0040 | ||||
| #define IEEE80211_HT_CAP_DELAY_BA		0x0400 | ||||
| #define IEEE80211_HT_CAP_MAX_AMSDU		0x0800 | ||||
| #define IEEE80211_HT_CAP_DSSSCCK40		0x1000 | ||||
| /* 802.11n HT capability AMPDU settings */ | ||||
| #define IEEE80211_HT_CAP_AMPDU_FACTOR		0x03 | ||||
| #define IEEE80211_HT_CAP_AMPDU_DENSITY		0x1C | ||||
| /* 802.11n HT capability MSC set */ | ||||
| #define IEEE80211_SUPP_MCS_SET_UEQM		4 | ||||
| #define IEEE80211_HT_CAP_MAX_STREAMS		4 | ||||
| #define IEEE80211_SUPP_MCS_SET_LEN		10 | ||||
| /* maximum streams the spec allows */ | ||||
| #define IEEE80211_HT_CAP_MCS_TX_DEFINED		0x01 | ||||
| #define IEEE80211_HT_CAP_MCS_TX_RX_DIFF		0x02 | ||||
| #define IEEE80211_HT_CAP_MCS_TX_STREAMS		0x0C | ||||
| #define IEEE80211_HT_CAP_MCS_TX_UEQM		0x10 | ||||
| /* 802.11n HT IE masks */ | ||||
| #define IEEE80211_HT_IE_CHA_SEC_OFFSET		0x03 | ||||
| #define IEEE80211_HT_IE_CHA_SEC_NONE	 	0x00 | ||||
| #define IEEE80211_HT_IE_CHA_SEC_ABOVE 		0x01 | ||||
| #define IEEE80211_HT_IE_CHA_SEC_BELOW 		0x03 | ||||
| #define IEEE80211_HT_IE_CHA_WIDTH		0x04 | ||||
| #define IEEE80211_HT_IE_HT_PROTECTION		0x0003 | ||||
| #define IEEE80211_HT_IE_NON_GF_STA_PRSNT	0x0004 | ||||
| #define IEEE80211_HT_IE_NON_HT_STA_PRSNT	0x0010 | ||||
| /* for ht_param */ | ||||
| #define IEEE80211_HT_PARAM_CHA_SEC_OFFSET		0x03 | ||||
| #define		IEEE80211_HT_PARAM_CHA_SEC_NONE		0x00 | ||||
| #define		IEEE80211_HT_PARAM_CHA_SEC_ABOVE	0x01 | ||||
| #define		IEEE80211_HT_PARAM_CHA_SEC_BELOW	0x03 | ||||
| #define IEEE80211_HT_PARAM_CHAN_WIDTH_ANY		0x04 | ||||
| #define IEEE80211_HT_PARAM_RIFS_MODE			0x08 | ||||
| #define IEEE80211_HT_PARAM_SPSMP_SUPPORT		0x10 | ||||
| #define IEEE80211_HT_PARAM_SERV_INTERVAL_GRAN		0xE0 | ||||
| 
 | ||||
| /* for operation_mode */ | ||||
| #define IEEE80211_HT_OP_MODE_PROTECTION			0x0003 | ||||
| #define		IEEE80211_HT_OP_MODE_PROTECTION_NONE		0 | ||||
| #define		IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER	1 | ||||
| #define		IEEE80211_HT_OP_MODE_PROTECTION_20MHZ		2 | ||||
| #define		IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED	3 | ||||
| #define IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT		0x0004 | ||||
| #define IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT		0x0010 | ||||
| 
 | ||||
| /* for stbc_param */ | ||||
| #define IEEE80211_HT_STBC_PARAM_DUAL_BEACON		0x0040 | ||||
| #define IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT		0x0080 | ||||
| #define IEEE80211_HT_STBC_PARAM_STBC_BEACON		0x0100 | ||||
| #define IEEE80211_HT_STBC_PARAM_LSIG_TXOP_FULLPROT	0x0200 | ||||
| #define IEEE80211_HT_STBC_PARAM_PCO_ACTIVE		0x0400 | ||||
| #define IEEE80211_HT_STBC_PARAM_PCO_PHASE		0x0800 | ||||
| 
 | ||||
| 
 | ||||
| /* block-ack parameters */ | ||||
| #define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002 | ||||
| @ -949,7 +1006,7 @@ enum ieee80211_eid { | ||||
| 	WLAN_EID_EXT_SUPP_RATES = 50, | ||||
| 	/* 802.11n */ | ||||
| 	WLAN_EID_HT_CAPABILITY = 45, | ||||
| 	WLAN_EID_HT_EXTRA_INFO = 61, | ||||
| 	WLAN_EID_HT_INFORMATION = 61, | ||||
| 	/* 802.11i */ | ||||
| 	WLAN_EID_RSN = 48, | ||||
| 	WLAN_EID_WPA = 221, | ||||
|  | ||||
| @ -191,7 +191,7 @@ enum ieee80211_bss_change { | ||||
|  * @beacon_int: beacon interval | ||||
|  * @assoc_capability: capabilities taken from assoc resp | ||||
|  * @assoc_ht: association in HT mode | ||||
|  * @ht_conf: ht capabilities | ||||
|  * @ht_cap: ht capabilities | ||||
|  * @ht_bss_conf: ht extended capabilities | ||||
|  * @basic_rates: bitmap of basic rates, each bit stands for an | ||||
|  *	index into the rate table configured by the driver in | ||||
| @ -212,7 +212,7 @@ struct ieee80211_bss_conf { | ||||
| 	u64 basic_rates; | ||||
| 	/* ht related data */ | ||||
| 	bool assoc_ht; | ||||
| 	struct ieee80211_ht_info *ht_conf; | ||||
| 	struct ieee80211_sta_ht_cap *ht_cap; | ||||
| 	struct ieee80211_ht_bss_info *ht_bss_conf; | ||||
| }; | ||||
| 
 | ||||
| @ -477,7 +477,7 @@ static inline int __deprecated __IEEE80211_CONF_SHORT_SLOT_TIME(void) | ||||
|  * @antenna_sel_tx: transmit antenna selection, 0: default/diversity, | ||||
|  *	1/2: antenna 0/1 | ||||
|  * @antenna_sel_rx: receive antenna selection, like @antenna_sel_tx | ||||
|  * @ht_conf: describes current self configuration of 802.11n HT capabilies | ||||
|  * @ht_cap: describes current self configuration of 802.11n HT capabilities | ||||
|  * @ht_bss_conf: describes current BSS configuration of 802.11n HT parameters | ||||
|  * @channel: the channel to tune to | ||||
|  */ | ||||
| @ -493,7 +493,7 @@ struct ieee80211_conf { | ||||
| 
 | ||||
| 	struct ieee80211_channel *channel; | ||||
| 
 | ||||
| 	struct ieee80211_ht_info ht_conf; | ||||
| 	struct ieee80211_sta_ht_cap ht_cap; | ||||
| 	struct ieee80211_ht_bss_info ht_bss_conf; | ||||
| }; | ||||
| 
 | ||||
| @ -687,7 +687,7 @@ enum set_key_cmd { | ||||
|  * @addr: MAC address | ||||
|  * @aid: AID we assigned to the station if we're an AP | ||||
|  * @supp_rates: Bitmap of supported rates (per band) | ||||
|  * @ht_info: HT capabilities of this STA | ||||
|  * @ht_cap: HT capabilities of this STA | ||||
|  * @drv_priv: data area for driver use, will always be aligned to | ||||
|  *	sizeof(void *), size is determined in hw information. | ||||
|  */ | ||||
| @ -695,7 +695,7 @@ struct ieee80211_sta { | ||||
| 	u64 supp_rates[IEEE80211_NUM_BANDS]; | ||||
| 	u8 addr[ETH_ALEN]; | ||||
| 	u16 aid; | ||||
| 	struct ieee80211_ht_info ht_info; | ||||
| 	struct ieee80211_sta_ht_cap ht_cap; | ||||
| 
 | ||||
| 	/* must be last */ | ||||
| 	u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); | ||||
|  | ||||
| @ -10,6 +10,7 @@ | ||||
| #include <linux/netdevice.h> | ||||
| #include <linux/debugfs.h> | ||||
| #include <linux/list.h> | ||||
| #include <linux/ieee80211.h> | ||||
| #include <net/cfg80211.h> | ||||
| 
 | ||||
| /**
 | ||||
| @ -133,23 +134,23 @@ struct ieee80211_rate { | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * struct ieee80211_ht_info - describing STA's HT capabilities | ||||
|  * struct ieee80211_sta_ht_cap - STA's HT capabilities | ||||
|  * | ||||
|  * This structure describes most essential parameters needed | ||||
|  * to describe 802.11n HT capabilities for an STA. | ||||
|  * | ||||
|  * @ht_supported: is HT supported by STA, 0: no, 1: yes | ||||
|  * @ht_supported: is HT supported by the STA | ||||
|  * @cap: HT capabilities map as described in 802.11n spec | ||||
|  * @ampdu_factor: Maximum A-MPDU length factor | ||||
|  * @ampdu_density: Minimum A-MPDU spacing | ||||
|  * @supp_mcs_set: Supported MCS set as described in 802.11n spec | ||||
|  * @mcs: Supported MCS rates | ||||
|  */ | ||||
| struct ieee80211_ht_info { | ||||
| struct ieee80211_sta_ht_cap { | ||||
| 	u16 cap; /* use IEEE80211_HT_CAP_ */ | ||||
| 	u8 ht_supported; | ||||
| 	bool ht_supported; | ||||
| 	u8 ampdu_factor; | ||||
| 	u8 ampdu_density; | ||||
| 	u8 supp_mcs_set[16]; | ||||
| 	struct ieee80211_mcs_info mcs; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| @ -173,7 +174,7 @@ struct ieee80211_supported_band { | ||||
| 	enum ieee80211_band band; | ||||
| 	int n_channels; | ||||
| 	int n_bitrates; | ||||
| 	struct ieee80211_ht_info ht_info; | ||||
| 	struct ieee80211_sta_ht_cap ht_cap; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  | ||||
| @ -633,10 +633,9 @@ static void sta_apply_parameters(struct ieee80211_local *local, | ||||
| 		sta->sta.supp_rates[local->oper_channel->band] = rates; | ||||
| 	} | ||||
| 
 | ||||
| 	if (params->ht_capa) { | ||||
| 		ieee80211_ht_cap_ie_to_ht_info(params->ht_capa, | ||||
| 					       &sta->sta.ht_info); | ||||
| 	} | ||||
| 	if (params->ht_capa) | ||||
| 		ieee80211_ht_cap_ie_to_sta_ht_cap(params->ht_capa, | ||||
| 						  &sta->sta.ht_cap); | ||||
| 
 | ||||
| 	if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { | ||||
| 		switch (params->plink_action) { | ||||
|  | ||||
| @ -20,37 +20,33 @@ | ||||
| #include "sta_info.h" | ||||
| #include "wme.h" | ||||
| 
 | ||||
| int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, | ||||
| 				   struct ieee80211_ht_info *ht_info) | ||||
| void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_ht_cap *ht_cap_ie, | ||||
| 				       struct ieee80211_sta_ht_cap *ht_cap) | ||||
| { | ||||
| 
 | ||||
| 	if (ht_info == NULL) | ||||
| 		return -EINVAL; | ||||
| 	BUG_ON(!ht_cap); | ||||
| 
 | ||||
| 	memset(ht_info, 0, sizeof(*ht_info)); | ||||
| 	memset(ht_cap, 0, sizeof(*ht_cap)); | ||||
| 
 | ||||
| 	if (ht_cap_ie) { | ||||
| 		u8 ampdu_info = ht_cap_ie->ampdu_params_info; | ||||
| 
 | ||||
| 		ht_info->ht_supported = 1; | ||||
| 		ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info); | ||||
| 		ht_info->ampdu_factor = | ||||
| 			ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR; | ||||
| 		ht_info->ampdu_density = | ||||
| 			(ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2; | ||||
| 		memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16); | ||||
| 		ht_cap->ht_supported = true; | ||||
| 		ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info); | ||||
| 		ht_cap->ampdu_factor = | ||||
| 			ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR; | ||||
| 		ht_cap->ampdu_density = | ||||
| 			(ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; | ||||
| 		memcpy(&ht_cap->mcs, &ht_cap_ie->mcs, sizeof(ht_cap->mcs)); | ||||
| 	} else | ||||
| 		ht_info->ht_supported = 0; | ||||
| 
 | ||||
| 	return 0; | ||||
| 		ht_cap->ht_supported = false; | ||||
| } | ||||
| 
 | ||||
| int ieee80211_ht_addt_info_ie_to_ht_bss_info( | ||||
| 			struct ieee80211_ht_addt_info *ht_add_info_ie, | ||||
| void ieee80211_ht_info_ie_to_ht_bss_info( | ||||
| 			struct ieee80211_ht_info *ht_add_info_ie, | ||||
| 			struct ieee80211_ht_bss_info *bss_info) | ||||
| { | ||||
| 	if (bss_info == NULL) | ||||
| 		return -EINVAL; | ||||
| 	BUG_ON(!bss_info); | ||||
| 
 | ||||
| 	memset(bss_info, 0, sizeof(*bss_info)); | ||||
| 
 | ||||
| @ -62,8 +58,119 @@ int ieee80211_ht_addt_info_ie_to_ht_bss_info( | ||||
| 		bss_info->bss_cap = ht_add_info_ie->ht_param; | ||||
| 		bss_info->bss_op_mode = (u8)(op_mode & 0xff); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 	return 0; | ||||
| /*
 | ||||
|  * ieee80211_handle_ht should be called only after the operating band | ||||
|  * has been determined as ht configuration depends on the hw's | ||||
|  * HT abilities for a specific band. | ||||
|  */ | ||||
| u32 ieee80211_handle_ht(struct ieee80211_local *local, | ||||
| 			struct ieee80211_sta_ht_cap *req_ht_cap, | ||||
| 			struct ieee80211_ht_bss_info *req_bss_cap) | ||||
| { | ||||
| 	struct ieee80211_conf *conf = &local->hw.conf; | ||||
| 	struct ieee80211_supported_band *sband; | ||||
| 	struct ieee80211_sta_ht_cap ht_cap; | ||||
| 	struct ieee80211_ht_bss_info ht_bss_conf; | ||||
| 	u32 changed = 0; | ||||
| 	int i; | ||||
| 	u8 max_tx_streams; | ||||
| 	u8 tx_mcs_set_cap; | ||||
| 	bool enable_ht = true; | ||||
| 
 | ||||
| 	sband = local->hw.wiphy->bands[conf->channel->band]; | ||||
| 
 | ||||
| 	memset(&ht_cap, 0, sizeof(ht_cap)); | ||||
| 	memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info)); | ||||
| 
 | ||||
| 	/* HT is not supported */ | ||||
| 	if (!sband->ht_cap.ht_supported) | ||||
| 		enable_ht = false; | ||||
| 
 | ||||
| 	/* disable HT */ | ||||
| 	if (!enable_ht) { | ||||
| 		if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) | ||||
| 			changed |= BSS_CHANGED_HT; | ||||
| 		conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; | ||||
| 		conf->ht_cap.ht_supported = false; | ||||
| 		return changed; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) | ||||
| 		changed |= BSS_CHANGED_HT; | ||||
| 
 | ||||
| 	conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; | ||||
| 	ht_cap.ht_supported = true; | ||||
| 
 | ||||
| 	ht_cap.cap = req_ht_cap->cap & sband->ht_cap.cap; | ||||
| 	ht_cap.cap &= ~IEEE80211_HT_CAP_SM_PS; | ||||
| 	ht_cap.cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS; | ||||
| 
 | ||||
| 	ht_bss_conf.primary_channel = req_bss_cap->primary_channel; | ||||
| 	ht_bss_conf.bss_cap = req_bss_cap->bss_cap; | ||||
| 	ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; | ||||
| 
 | ||||
| 	ht_cap.ampdu_factor = req_ht_cap->ampdu_factor; | ||||
| 	ht_cap.ampdu_density = req_ht_cap->ampdu_density; | ||||
| 
 | ||||
| 	/* own MCS TX capabilities */ | ||||
| 	tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * configure supported Tx MCS according to requested MCS | ||||
| 	 * (based in most cases on Rx capabilities of peer) and self | ||||
| 	 * Tx MCS capabilities (as defined by low level driver HW | ||||
| 	 * Tx capabilities) | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* can we TX with MCS rates? */ | ||||
| 	if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) | ||||
| 		goto check_changed; | ||||
| 
 | ||||
| 	/* Counting from 0, therefore +1 */ | ||||
| 	if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF) | ||||
| 		max_tx_streams = | ||||
| 			((tx_mcs_set_cap & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) | ||||
| 				>> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1; | ||||
| 	else | ||||
| 		max_tx_streams = IEEE80211_HT_MCS_TX_MAX_STREAMS; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * 802.11n D5.0 20.3.5 / 20.6 says: | ||||
| 	 * - indices 0 to 7 and 32 are single spatial stream | ||||
| 	 * - 8 to 31 are multiple spatial streams using equal modulation | ||||
| 	 *   [8..15 for two streams, 16..23 for three and 24..31 for four] | ||||
| 	 * - remainder are multiple spatial streams using unequal modulation | ||||
| 	 */ | ||||
| 	for (i = 0; i < max_tx_streams; i++) | ||||
| 		ht_cap.mcs.rx_mask[i] = | ||||
| 			sband->ht_cap.mcs.rx_mask[i] & | ||||
| 					req_ht_cap->mcs.rx_mask[i]; | ||||
| 
 | ||||
| 	if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) | ||||
| 		for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; | ||||
| 		     i < IEEE80211_HT_MCS_MASK_LEN; i++) | ||||
| 			ht_cap.mcs.rx_mask[i] = | ||||
| 				sband->ht_cap.mcs.rx_mask[i] & | ||||
| 					req_ht_cap->mcs.rx_mask[i]; | ||||
| 
 | ||||
| 	/* handle MCS rate 32 too */ | ||||
| 	if (sband->ht_cap.mcs.rx_mask[32/8] & | ||||
| 	    req_ht_cap->mcs.rx_mask[32/8] & 1) | ||||
| 		ht_cap.mcs.rx_mask[32/8] |= 1; | ||||
| 
 | ||||
|  check_changed: | ||||
| 	/* if bss configuration changed store the new one */ | ||||
| 	if (memcmp(&conf->ht_cap, &ht_cap, sizeof(ht_cap)) || | ||||
| 	    memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) { | ||||
| 		changed |= BSS_CHANGED_HT; | ||||
| 		memcpy(&conf->ht_cap, &ht_cap, sizeof(ht_cap)); | ||||
| 		memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf)); | ||||
| 	} | ||||
| 
 | ||||
| 	return changed; | ||||
| } | ||||
| 
 | ||||
| static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, | ||||
| @ -794,7 +901,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | ||||
| 	 * check if configuration can support the BA policy | ||||
| 	 * and if buffer size does not exceeds max value */ | ||||
| 	if (((ba_policy != 1) | ||||
| 		&& (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA))) | ||||
| 		&& (!(conf->ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) | ||||
| 		|| (buf_size > IEEE80211_MAX_AMPDU_BUF)) { | ||||
| 		status = WLAN_STATUS_INVALID_QOS_PARAM; | ||||
| #ifdef CONFIG_MAC80211_HT_DEBUG | ||||
| @ -812,7 +919,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | ||||
| 
 | ||||
| 		sband = local->hw.wiphy->bands[conf->channel->band]; | ||||
| 		buf_size = IEEE80211_MIN_AMPDU_BUF; | ||||
| 		buf_size = buf_size << sband->ht_info.ampdu_factor; | ||||
| 		buf_size = buf_size << sband->ht_cap.ampdu_factor; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -817,7 +817,7 @@ struct ieee802_11_elems { | ||||
| 	u8 *wmm_info; | ||||
| 	u8 *wmm_param; | ||||
| 	struct ieee80211_ht_cap *ht_cap_elem; | ||||
| 	struct ieee80211_ht_addt_info *ht_info_elem; | ||||
| 	struct ieee80211_ht_info *ht_info_elem; | ||||
| 	u8 *mesh_config; | ||||
| 	u8 *mesh_id; | ||||
| 	u8 *peer_link; | ||||
| @ -880,9 +880,6 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) | ||||
| int ieee80211_hw_config(struct ieee80211_local *local); | ||||
| int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed); | ||||
| void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); | ||||
| u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, | ||||
| 			struct ieee80211_ht_info *req_ht_cap, | ||||
| 			struct ieee80211_ht_bss_info *req_bss_cap); | ||||
| void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | ||||
| 				      u32 changed); | ||||
| void ieee80211_configure_filter(struct ieee80211_local *local); | ||||
| @ -963,11 +960,14 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||||
| int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||||
| 
 | ||||
| /* HT */ | ||||
| int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, | ||||
| 				   struct ieee80211_ht_info *ht_info); | ||||
| int ieee80211_ht_addt_info_ie_to_ht_bss_info( | ||||
| 			struct ieee80211_ht_addt_info *ht_add_info_ie, | ||||
| void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_ht_cap *ht_cap_ie, | ||||
| 				       struct ieee80211_sta_ht_cap *ht_cap); | ||||
| void ieee80211_ht_info_ie_to_ht_bss_info( | ||||
| 			struct ieee80211_ht_info *ht_add_info_ie, | ||||
| 			struct ieee80211_ht_bss_info *bss_info); | ||||
| u32 ieee80211_handle_ht(struct ieee80211_local *local, | ||||
| 			struct ieee80211_sta_ht_cap *req_ht_cap, | ||||
| 			struct ieee80211_ht_bss_info *req_bss_cap); | ||||
| void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn); | ||||
| 
 | ||||
| void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da, | ||||
|  | ||||
| @ -232,100 +232,6 @@ int ieee80211_hw_config(struct ieee80211_local *local) | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * ieee80211_handle_ht should be used only after legacy configuration | ||||
|  * has been determined namely band, as ht configuration depends upon | ||||
|  * the hardware's HT abilities for a _specific_ band. | ||||
|  */ | ||||
| u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, | ||||
| 			   struct ieee80211_ht_info *req_ht_cap, | ||||
| 			   struct ieee80211_ht_bss_info *req_bss_cap) | ||||
| { | ||||
| 	struct ieee80211_conf *conf = &local->hw.conf; | ||||
| 	struct ieee80211_supported_band *sband; | ||||
| 	struct ieee80211_ht_info ht_conf; | ||||
| 	struct ieee80211_ht_bss_info ht_bss_conf; | ||||
| 	u32 changed = 0; | ||||
| 	int i; | ||||
| 	u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS; | ||||
| 	u8 tx_mcs_set_cap; | ||||
| 
 | ||||
| 	sband = local->hw.wiphy->bands[conf->channel->band]; | ||||
| 
 | ||||
| 	memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info)); | ||||
| 	memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info)); | ||||
| 
 | ||||
| 	/* HT is not supported */ | ||||
| 	if (!sband->ht_info.ht_supported) { | ||||
| 		conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	/* disable HT */ | ||||
| 	if (!enable_ht) { | ||||
| 		if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) | ||||
| 			changed |= BSS_CHANGED_HT; | ||||
| 		conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; | ||||
| 		conf->ht_conf.ht_supported = 0; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) | ||||
| 		changed |= BSS_CHANGED_HT; | ||||
| 
 | ||||
| 	conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; | ||||
| 	ht_conf.ht_supported = 1; | ||||
| 
 | ||||
| 	ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; | ||||
| 	ht_conf.cap &= ~(IEEE80211_HT_CAP_SM_PS); | ||||
| 	ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_SM_PS; | ||||
| 	ht_bss_conf.primary_channel = req_bss_cap->primary_channel; | ||||
| 	ht_bss_conf.bss_cap = req_bss_cap->bss_cap; | ||||
| 	ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; | ||||
| 
 | ||||
| 	ht_conf.ampdu_factor = req_ht_cap->ampdu_factor; | ||||
| 	ht_conf.ampdu_density = req_ht_cap->ampdu_density; | ||||
| 
 | ||||
| 	/* Bits 96-100 */ | ||||
| 	tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12]; | ||||
| 
 | ||||
| 	/* configure suppoerted Tx MCS according to requested MCS
 | ||||
| 	 * (based in most cases on Rx capabilities of peer) and self | ||||
| 	 * Tx MCS capabilities (as defined by low level driver HW | ||||
| 	 * Tx capabilities) */ | ||||
| 	if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED)) | ||||
| 		goto check_changed; | ||||
| 
 | ||||
| 	/* Counting from 0 therfore + 1 */ | ||||
| 	if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF) | ||||
| 		max_tx_streams = ((tx_mcs_set_cap & | ||||
| 				IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1; | ||||
| 
 | ||||
| 	for (i = 0; i < max_tx_streams; i++) | ||||
| 		ht_conf.supp_mcs_set[i] = | ||||
| 			sband->ht_info.supp_mcs_set[i] & | ||||
| 					req_ht_cap->supp_mcs_set[i]; | ||||
| 
 | ||||
| 	if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM) | ||||
| 		for (i = IEEE80211_SUPP_MCS_SET_UEQM; | ||||
| 		     i < IEEE80211_SUPP_MCS_SET_LEN; i++) | ||||
| 			ht_conf.supp_mcs_set[i] = | ||||
| 				sband->ht_info.supp_mcs_set[i] & | ||||
| 					req_ht_cap->supp_mcs_set[i]; | ||||
| 
 | ||||
| check_changed: | ||||
| 	/* if bss configuration changed store the new one */ | ||||
| 	if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) || | ||||
| 	    memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) { | ||||
| 		changed |= BSS_CHANGED_HT; | ||||
| 		memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf)); | ||||
| 		memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf)); | ||||
| 	} | ||||
| out: | ||||
| 	return changed; | ||||
| } | ||||
| 
 | ||||
| void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | ||||
| 				      u32 changed) | ||||
| { | ||||
|  | ||||
| @ -236,7 +236,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 	struct sk_buff *skb; | ||||
| 	struct ieee80211_mgmt *mgmt; | ||||
| 	u8 *pos, *ies, *ht_add_ie; | ||||
| 	u8 *pos, *ies, *ht_ie; | ||||
| 	int i, len, count, rates_len, supp_rates_len; | ||||
| 	u16 capab; | ||||
| 	struct ieee80211_bss *bss; | ||||
| @ -393,24 +393,25 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | ||||
| 
 | ||||
| 	/* wmm support is a must to HT */ | ||||
| 	if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && | ||||
| 	    sband->ht_info.ht_supported && | ||||
| 	    (ht_add_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_EXTRA_INFO))) { | ||||
| 		struct ieee80211_ht_addt_info *ht_add_info = | ||||
| 			(struct ieee80211_ht_addt_info *)ht_add_ie; | ||||
| 		u16 cap = sband->ht_info.cap; | ||||
| 	    sband->ht_cap.ht_supported && | ||||
| 	    (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && | ||||
| 	    ht_ie[1] >= sizeof(struct ieee80211_ht_info)) { | ||||
| 		struct ieee80211_ht_info *ht_info = | ||||
| 			(struct ieee80211_ht_info *)(ht_ie + 2); | ||||
| 		u16 cap = sband->ht_cap.cap; | ||||
| 		__le16 tmp; | ||||
| 		u32 flags = local->hw.conf.channel->flags; | ||||
| 
 | ||||
| 		switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) { | ||||
| 		case IEEE80211_HT_IE_CHA_SEC_ABOVE: | ||||
| 		switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||||
| 		case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||||
| 			if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) { | ||||
| 				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; | ||||
| 				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||||
| 				cap &= ~IEEE80211_HT_CAP_SGI_40; | ||||
| 			} | ||||
| 			break; | ||||
| 		case IEEE80211_HT_IE_CHA_SEC_BELOW: | ||||
| 		case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||||
| 			if (flags & IEEE80211_CHAN_NO_FAT_BELOW) { | ||||
| 				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; | ||||
| 				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||||
| 				cap &= ~IEEE80211_HT_CAP_SGI_40; | ||||
| 			} | ||||
| 			break; | ||||
| @ -424,9 +425,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | ||||
| 		memcpy(pos, &tmp, sizeof(u16)); | ||||
| 		pos += sizeof(u16); | ||||
| 		/* TODO: needs a define here for << 2 */ | ||||
| 		*pos++ = sband->ht_info.ampdu_factor | | ||||
| 			 (sband->ht_info.ampdu_density << 2); | ||||
| 		memcpy(pos, sband->ht_info.supp_mcs_set, 16); | ||||
| 		*pos++ = sband->ht_cap.ampdu_factor | | ||||
| 			 (sband->ht_cap.ampdu_density << 2); | ||||
| 		memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | ||||
| 	} | ||||
| 
 | ||||
| 	kfree(ifsta->assocreq_ies); | ||||
| @ -730,7 +731,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | ||||
| 	if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { | ||||
| 		changed |= BSS_CHANGED_HT; | ||||
| 		sdata->bss_conf.assoc_ht = 1; | ||||
| 		sdata->bss_conf.ht_conf = &conf->ht_conf; | ||||
| 		sdata->bss_conf.ht_cap = &conf->ht_cap; | ||||
| 		sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf; | ||||
| 	} | ||||
| 
 | ||||
| @ -850,7 +851,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | ||||
| 		changed |= BSS_CHANGED_HT; | ||||
| 
 | ||||
| 	sdata->bss_conf.assoc_ht = 0; | ||||
| 	sdata->bss_conf.ht_conf = NULL; | ||||
| 	sdata->bss_conf.ht_cap = NULL; | ||||
| 	sdata->bss_conf.ht_bss_conf = NULL; | ||||
| 
 | ||||
| 	ieee80211_led_assoc(local, 0); | ||||
| @ -1335,11 +1336,11 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | ||||
| 	if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && | ||||
| 	    (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { | ||||
| 		struct ieee80211_ht_bss_info bss_info; | ||||
| 		ieee80211_ht_cap_ie_to_ht_info( | ||||
| 				elems.ht_cap_elem, &sta->sta.ht_info); | ||||
| 		ieee80211_ht_addt_info_ie_to_ht_bss_info( | ||||
| 		ieee80211_ht_cap_ie_to_sta_ht_cap( | ||||
| 				elems.ht_cap_elem, &sta->sta.ht_cap); | ||||
| 		ieee80211_ht_info_ie_to_ht_bss_info( | ||||
| 				elems.ht_info_elem, &bss_info); | ||||
| 		ieee80211_handle_ht(local, 1, &sta->sta.ht_info, &bss_info); | ||||
| 		ieee80211_handle_ht(local, &sta->sta.ht_cap, &bss_info); | ||||
| 	} | ||||
| 
 | ||||
| 	rate_control_rate_init(sta); | ||||
| @ -1696,9 +1697,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | ||||
| 	    elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { | ||||
| 		struct ieee80211_ht_bss_info bss_info; | ||||
| 
 | ||||
| 		ieee80211_ht_addt_info_ie_to_ht_bss_info( | ||||
| 		ieee80211_ht_info_ie_to_ht_bss_info( | ||||
| 				elems.ht_info_elem, &bss_info); | ||||
| 		changed |= ieee80211_handle_ht(local, 1, &conf->ht_conf, | ||||
| 		changed |= ieee80211_handle_ht(local, &conf->ht_cap, | ||||
| 					       &bss_info); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -532,8 +532,8 @@ void ieee802_11_parse_elems(u8 *start, size_t len, | ||||
| 			if (elen >= sizeof(struct ieee80211_ht_cap)) | ||||
| 				elems->ht_cap_elem = (void *)pos; | ||||
| 			break; | ||||
| 		case WLAN_EID_HT_EXTRA_INFO: | ||||
| 			if (elen >= sizeof(struct ieee80211_ht_addt_info)) | ||||
| 		case WLAN_EID_HT_INFORMATION: | ||||
| 			if (elen >= sizeof(struct ieee80211_ht_info)) | ||||
| 				elems->ht_info_elem = (void *)pos; | ||||
| 			break; | ||||
| 		case WLAN_EID_MESH_ID: | ||||
|  | ||||
| @ -147,7 +147,7 @@ static int ieee80211_ioctl_giwname(struct net_device *dev, | ||||
| 	sband = local->hw.wiphy->bands[IEEE80211_BAND_5GHZ]; | ||||
| 	if (sband) { | ||||
| 		is_a = 1; | ||||
| 		is_ht |= sband->ht_info.ht_supported; | ||||
| 		is_ht |= sband->ht_cap.ht_supported; | ||||
| 	} | ||||
| 
 | ||||
| 	sband = local->hw.wiphy->bands[IEEE80211_BAND_2GHZ]; | ||||
| @ -160,7 +160,7 @@ static int ieee80211_ioctl_giwname(struct net_device *dev, | ||||
| 			if (sband->bitrates[i].bitrate == 60) | ||||
| 				is_g = 1; | ||||
| 		} | ||||
| 		is_ht |= sband->ht_info.ht_supported; | ||||
| 		is_ht |= sband->ht_cap.ht_supported; | ||||
| 	} | ||||
| 
 | ||||
| 	strcpy(name, "IEEE 802.11"); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user