mac80211: limit the A-MSDU Tx based on peer's capabilities
In VHT, the specification allows to limit the number of MSDUs in an A-MSDU in the Extended Capabilities IE. There is also a limitation on the byte size in the VHT IE. In HT, the only limitation is on the byte size. Parse the capabilities from the peer and make them available to the driver. In HT, there is another limitation when a BA agreement is active: the byte size can't be greater than 4095. This is not enforced here. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
committed by
Johannes Berg
parent
a7201a6c5e
commit
506bcfa8ab
@@ -1131,6 +1131,34 @@ static int sta_apply_parameters(struct ieee80211_local *local,
|
||||
sta->sta.max_sp = params->max_sp;
|
||||
}
|
||||
|
||||
/* The sender might not have sent the last bit, consider it to be 0 */
|
||||
if (params->ext_capab_len >= 8) {
|
||||
u8 val = (params->ext_capab[7] &
|
||||
WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB) >> 7;
|
||||
|
||||
/* we did get all the bits, take the MSB as well */
|
||||
if (params->ext_capab_len >= 9) {
|
||||
u8 val_msb = params->ext_capab[8] &
|
||||
WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB;
|
||||
val_msb <<= 1;
|
||||
val |= val_msb;
|
||||
}
|
||||
|
||||
switch (val) {
|
||||
case 1:
|
||||
sta->sta.max_amsdu_subframes = 32;
|
||||
break;
|
||||
case 2:
|
||||
sta->sta.max_amsdu_subframes = 16;
|
||||
break;
|
||||
case 3:
|
||||
sta->sta.max_amsdu_subframes = 8;
|
||||
break;
|
||||
default:
|
||||
sta->sta.max_amsdu_subframes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* cfg80211 validates this (1-2007) and allows setting the AID
|
||||
* only when creating a new station entry
|
||||
@@ -1160,6 +1188,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
|
||||
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
||||
params->ht_capa, sta);
|
||||
|
||||
/* VHT can override some HT caps such as the A-MSDU max length */
|
||||
if (params->vht_capa)
|
||||
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
|
||||
params->vht_capa, sta);
|
||||
|
||||
@@ -230,6 +230,11 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
|
||||
/* set Rx highest rate */
|
||||
ht_cap.mcs.rx_highest = ht_cap_ie->mcs.rx_highest;
|
||||
|
||||
if (ht_cap.cap & IEEE80211_HT_CAP_MAX_AMSDU)
|
||||
sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_7935;
|
||||
else
|
||||
sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_3839;
|
||||
|
||||
apply:
|
||||
changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
|
||||
|
||||
|
||||
@@ -281,6 +281,23 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta);
|
||||
|
||||
/* If HT IE reported 3839 bytes only, stay with that size. */
|
||||
if (sta->sta.max_amsdu_len == IEEE80211_MAX_MPDU_LEN_HT_3839)
|
||||
return;
|
||||
|
||||
switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {
|
||||
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
|
||||
sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454;
|
||||
break;
|
||||
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
|
||||
sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_7991;
|
||||
break;
|
||||
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895:
|
||||
default:
|
||||
sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_3895;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta)
|
||||
|
||||
Reference in New Issue
Block a user