aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ht.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/ht.c')
-rw-r--r--net/mac80211/ht.c110
1 files changed, 77 insertions, 33 deletions
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 61ac7c48ac0c..0db25d4bb223 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -37,6 +37,9 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
37 u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask); 37 u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask);
38 int i; 38 int i;
39 39
40 if (!ht_cap->ht_supported)
41 return;
42
40 if (sdata->vif.type != NL80211_IFTYPE_STATION) { 43 if (sdata->vif.type != NL80211_IFTYPE_STATION) {
41 /* AP interfaces call this code when adding new stations, 44 /* AP interfaces call this code when adding new stations,
42 * so just silently ignore non station interfaces. 45 * so just silently ignore non station interfaces.
@@ -89,22 +92,24 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
89} 92}
90 93
91 94
92void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, 95bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
93 struct ieee80211_supported_band *sband, 96 struct ieee80211_supported_band *sband,
94 struct ieee80211_ht_cap *ht_cap_ie, 97 const struct ieee80211_ht_cap *ht_cap_ie,
95 struct ieee80211_sta_ht_cap *ht_cap) 98 struct sta_info *sta)
96{ 99{
100 struct ieee80211_sta_ht_cap ht_cap;
97 u8 ampdu_info, tx_mcs_set_cap; 101 u8 ampdu_info, tx_mcs_set_cap;
98 int i, max_tx_streams; 102 int i, max_tx_streams;
103 bool changed;
104 enum ieee80211_sta_rx_bandwidth bw;
105 enum ieee80211_smps_mode smps_mode;
99 106
100 BUG_ON(!ht_cap); 107 memset(&ht_cap, 0, sizeof(ht_cap));
101
102 memset(ht_cap, 0, sizeof(*ht_cap));
103 108
104 if (!ht_cap_ie || !sband->ht_cap.ht_supported) 109 if (!ht_cap_ie || !sband->ht_cap.ht_supported)
105 return; 110 goto apply;
106 111
107 ht_cap->ht_supported = true; 112 ht_cap.ht_supported = true;
108 113
109 /* 114 /*
110 * The bits listed in this expression should be 115 * The bits listed in this expression should be
@@ -112,7 +117,7 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
112 * advertises more then we can't use those thus 117 * advertises more then we can't use those thus
113 * we mask them out. 118 * we mask them out.
114 */ 119 */
115 ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & 120 ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) &
116 (sband->ht_cap.cap | 121 (sband->ht_cap.cap |
117 ~(IEEE80211_HT_CAP_LDPC_CODING | 122 ~(IEEE80211_HT_CAP_LDPC_CODING |
118 IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 123 IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
@@ -121,44 +126,30 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
121 IEEE80211_HT_CAP_SGI_40 | 126 IEEE80211_HT_CAP_SGI_40 |
122 IEEE80211_HT_CAP_DSSSCCK40)); 127 IEEE80211_HT_CAP_DSSSCCK40));
123 128
124 /* Unset 40 MHz if we're not using a 40 MHz channel */
125 switch (sdata->vif.bss_conf.chandef.width) {
126 case NL80211_CHAN_WIDTH_20_NOHT:
127 case NL80211_CHAN_WIDTH_20:
128 ht_cap->cap &= ~IEEE80211_HT_CAP_SGI_40;
129 ht_cap->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
130 break;
131 case NL80211_CHAN_WIDTH_40:
132 case NL80211_CHAN_WIDTH_80:
133 case NL80211_CHAN_WIDTH_80P80:
134 case NL80211_CHAN_WIDTH_160:
135 break;
136 }
137
138 /* 129 /*
139 * The STBC bits are asymmetric -- if we don't have 130 * The STBC bits are asymmetric -- if we don't have
140 * TX then mask out the peer's RX and vice versa. 131 * TX then mask out the peer's RX and vice versa.
141 */ 132 */
142 if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) 133 if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC))
143 ht_cap->cap &= ~IEEE80211_HT_CAP_RX_STBC; 134 ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC;
144 if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)) 135 if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC))
145 ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; 136 ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC;
146 137
147 ampdu_info = ht_cap_ie->ampdu_params_info; 138 ampdu_info = ht_cap_ie->ampdu_params_info;
148 ht_cap->ampdu_factor = 139 ht_cap.ampdu_factor =
149 ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR; 140 ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
150 ht_cap->ampdu_density = 141 ht_cap.ampdu_density =
151 (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; 142 (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
152 143
153 /* own MCS TX capabilities */ 144 /* own MCS TX capabilities */
154 tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; 145 tx_mcs_set_cap = sband->ht_cap.mcs.tx_params;
155 146
156 /* Copy peer MCS TX capabilities, the driver might need them. */ 147 /* Copy peer MCS TX capabilities, the driver might need them. */
157 ht_cap->mcs.tx_params = ht_cap_ie->mcs.tx_params; 148 ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params;
158 149
159 /* can we TX with MCS rates? */ 150 /* can we TX with MCS rates? */
160 if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) 151 if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED))
161 return; 152 goto apply;
162 153
163 /* Counting from 0, therefore +1 */ 154 /* Counting from 0, therefore +1 */
164 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF) 155 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF)
@@ -176,25 +167,75 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
176 * - remainder are multiple spatial streams using unequal modulation 167 * - remainder are multiple spatial streams using unequal modulation
177 */ 168 */
178 for (i = 0; i < max_tx_streams; i++) 169 for (i = 0; i < max_tx_streams; i++)
179 ht_cap->mcs.rx_mask[i] = 170 ht_cap.mcs.rx_mask[i] =
180 sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; 171 sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
181 172
182 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) 173 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
183 for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; 174 for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
184 i < IEEE80211_HT_MCS_MASK_LEN; i++) 175 i < IEEE80211_HT_MCS_MASK_LEN; i++)
185 ht_cap->mcs.rx_mask[i] = 176 ht_cap.mcs.rx_mask[i] =
186 sband->ht_cap.mcs.rx_mask[i] & 177 sband->ht_cap.mcs.rx_mask[i] &
187 ht_cap_ie->mcs.rx_mask[i]; 178 ht_cap_ie->mcs.rx_mask[i];
188 179
189 /* handle MCS rate 32 too */ 180 /* handle MCS rate 32 too */
190 if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) 181 if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
191 ht_cap->mcs.rx_mask[32/8] |= 1; 182 ht_cap.mcs.rx_mask[32/8] |= 1;
192 183
184 apply:
193 /* 185 /*
194 * If user has specified capability over-rides, take care 186 * If user has specified capability over-rides, take care
195 * of that here. 187 * of that here.
196 */ 188 */
197 ieee80211_apply_htcap_overrides(sdata, ht_cap); 189 ieee80211_apply_htcap_overrides(sdata, &ht_cap);
190
191 changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
192
193 memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
194
195 switch (sdata->vif.bss_conf.chandef.width) {
196 default:
197 WARN_ON_ONCE(1);
198 /* fall through */
199 case NL80211_CHAN_WIDTH_20_NOHT:
200 case NL80211_CHAN_WIDTH_20:
201 bw = IEEE80211_STA_RX_BW_20;
202 break;
203 case NL80211_CHAN_WIDTH_40:
204 case NL80211_CHAN_WIDTH_80:
205 case NL80211_CHAN_WIDTH_80P80:
206 case NL80211_CHAN_WIDTH_160:
207 bw = ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
208 IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
209 break;
210 }
211
212 if (bw != sta->sta.bandwidth)
213 changed = true;
214 sta->sta.bandwidth = bw;
215
216 sta->cur_max_bandwidth =
217 ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
218 IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
219
220 switch ((ht_cap.cap & IEEE80211_HT_CAP_SM_PS)
221 >> IEEE80211_HT_CAP_SM_PS_SHIFT) {
222 case WLAN_HT_CAP_SM_PS_INVALID:
223 case WLAN_HT_CAP_SM_PS_STATIC:
224 smps_mode = IEEE80211_SMPS_STATIC;
225 break;
226 case WLAN_HT_CAP_SM_PS_DYNAMIC:
227 smps_mode = IEEE80211_SMPS_DYNAMIC;
228 break;
229 case WLAN_HT_CAP_SM_PS_DISABLED:
230 smps_mode = IEEE80211_SMPS_OFF;
231 break;
232 }
233
234 if (smps_mode != sta->sta.smps_mode)
235 changed = true;
236 sta->sta.smps_mode = smps_mode;
237
238 return changed;
198} 239}
199 240
200void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, 241void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
@@ -406,6 +447,9 @@ void ieee80211_request_smps(struct ieee80211_vif *vif,
406 if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF)) 447 if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF))
407 smps_mode = IEEE80211_SMPS_AUTOMATIC; 448 smps_mode = IEEE80211_SMPS_AUTOMATIC;
408 449
450 if (sdata->u.mgd.driver_smps_mode == smps_mode)
451 return;
452
409 sdata->u.mgd.driver_smps_mode = smps_mode; 453 sdata->u.mgd.driver_smps_mode = smps_mode;
410 454
411 ieee80211_queue_work(&sdata->local->hw, 455 ieee80211_queue_work(&sdata->local->hw,