diff options
Diffstat (limited to 'net/mac80211/ht.c')
| -rw-r--r-- | net/mac80211/ht.c | 92 | 
1 files changed, 89 insertions, 3 deletions
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index f0fb737efa8..f25fff7607d 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -19,7 +19,84 @@  #include "ieee80211_i.h"  #include "rate.h" -void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, +bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata) +{ +	const __le16 flg = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40); +	if ((sdata->u.mgd.ht_capa_mask.cap_info & flg) && +	    !(sdata->u.mgd.ht_capa.cap_info & flg)) +		return true; +	return false; +} + +static void __check_htcap_disable(struct ieee80211_sub_if_data *sdata, +				  struct ieee80211_sta_ht_cap *ht_cap, +				  u16 flag) +{ +	__le16 le_flag = cpu_to_le16(flag); +	if (sdata->u.mgd.ht_capa_mask.cap_info & le_flag) { +		if (!(sdata->u.mgd.ht_capa.cap_info & le_flag)) +			ht_cap->cap &= ~flag; +	} +} + +void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, +				     struct ieee80211_sta_ht_cap *ht_cap) +{ +	u8 *scaps = (u8 *)(&sdata->u.mgd.ht_capa.mcs.rx_mask); +	u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask); +	int i; + +	if (sdata->vif.type != NL80211_IFTYPE_STATION) { +		/* AP interfaces call this code when adding new stations, +		 * so just silently ignore non station interfaces. +		 */ +		return; +	} + +	/* NOTE:  If you add more over-rides here, update register_hw +	 * ht_capa_mod_msk logic in main.c as well. +	 * And, if this method can ever change ht_cap.ht_supported, fix +	 * the check in ieee80211_add_ht_ie. +	 */ + +	/* check for HT over-rides, MCS rates first. */ +	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) { +		u8 m = smask[i]; +		ht_cap->mcs.rx_mask[i] &= ~m; /* turn off all masked bits */ +		/* Add back rates that are supported */ +		ht_cap->mcs.rx_mask[i] |= (m & scaps[i]); +	} + +	/* Force removal of HT-40 capabilities? */ +	__check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SUP_WIDTH_20_40); +	__check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SGI_40); + +	/* Allow user to disable the max-AMSDU bit. */ +	__check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_MAX_AMSDU); + +	/* Allow user to decrease AMPDU factor */ +	if (sdata->u.mgd.ht_capa_mask.ampdu_params_info & +	    IEEE80211_HT_AMPDU_PARM_FACTOR) { +		u8 n = sdata->u.mgd.ht_capa.ampdu_params_info +			& IEEE80211_HT_AMPDU_PARM_FACTOR; +		if (n < ht_cap->ampdu_factor) +			ht_cap->ampdu_factor = n; +	} + +	/* Allow the user to increase AMPDU density. */ +	if (sdata->u.mgd.ht_capa_mask.ampdu_params_info & +	    IEEE80211_HT_AMPDU_PARM_DENSITY) { +		u8 n = (sdata->u.mgd.ht_capa.ampdu_params_info & +			IEEE80211_HT_AMPDU_PARM_DENSITY) +			>> IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT; +		if (n > ht_cap->ampdu_density) +			ht_cap->ampdu_density = n; +	} +} + + +void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, +				       struct ieee80211_supported_band *sband,  				       struct ieee80211_ht_cap *ht_cap_ie,  				       struct ieee80211_sta_ht_cap *ht_cap)  { @@ -103,6 +180,12 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,  	/* handle MCS rate 32 too */  	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; + +	/* +	 * If user has specified capability over-rides, take care +	 * of that here. +	 */ +	ieee80211_apply_htcap_overrides(sdata, ht_cap);  }  void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx) @@ -196,10 +279,13 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,  	memcpy(mgmt->da, da, ETH_ALEN);  	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);  	if (sdata->vif.type == NL80211_IFTYPE_AP || -	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN) +	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN || +	    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)  		memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);  	else if (sdata->vif.type == NL80211_IFTYPE_STATION)  		memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); +	else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) +		memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);  	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |  					  IEEE80211_STYPE_ACTION); @@ -214,7 +300,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,  	mgmt->u.action.u.delba.params = cpu_to_le16(params);  	mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); -	ieee80211_tx_skb(sdata, skb); +	ieee80211_tx_skb_tid(sdata, skb, tid);  }  void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,  |