aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-02-08 08:52:32 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-02-15 03:41:37 -0500
commit6565ec9b58483a9706fbe888364aeceb359aeced (patch)
tree42838a53f6dd307909e87c57e27950dd6d4fd976 /net/mac80211/mlme.c
parent2c9b735982ee8a2d34e7eeb3e26b683f81872fdb (diff)
mac80211: move ieee80211_determine_chantype function
The next patch will need it further up in the file, so move it unchanged now. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c390
1 files changed, 195 insertions, 195 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 8fdf1e1aee5e..50423c66c239 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -174,6 +174,201 @@ static int ecw2cw(int ecw)
174 return (1 << ecw) - 1; 174 return (1 << ecw) - 1;
175} 175}
176 176
177static u32 chandef_downgrade(struct cfg80211_chan_def *c)
178{
179 u32 ret;
180 int tmp;
181
182 switch (c->width) {
183 case NL80211_CHAN_WIDTH_20:
184 c->width = NL80211_CHAN_WIDTH_20_NOHT;
185 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
186 break;
187 case NL80211_CHAN_WIDTH_40:
188 c->width = NL80211_CHAN_WIDTH_20;
189 c->center_freq1 = c->chan->center_freq;
190 ret = IEEE80211_STA_DISABLE_40MHZ |
191 IEEE80211_STA_DISABLE_VHT;
192 break;
193 case NL80211_CHAN_WIDTH_80:
194 tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
195 /* n_P40 */
196 tmp /= 2;
197 /* freq_P40 */
198 c->center_freq1 = c->center_freq1 - 20 + 40 * tmp;
199 c->width = NL80211_CHAN_WIDTH_40;
200 ret = IEEE80211_STA_DISABLE_VHT;
201 break;
202 case NL80211_CHAN_WIDTH_80P80:
203 c->center_freq2 = 0;
204 c->width = NL80211_CHAN_WIDTH_80;
205 ret = IEEE80211_STA_DISABLE_80P80MHZ |
206 IEEE80211_STA_DISABLE_160MHZ;
207 break;
208 case NL80211_CHAN_WIDTH_160:
209 /* n_P20 */
210 tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
211 /* n_P80 */
212 tmp /= 4;
213 c->center_freq1 = c->center_freq1 - 40 + 80 * tmp;
214 c->width = NL80211_CHAN_WIDTH_80;
215 ret = IEEE80211_STA_DISABLE_80P80MHZ |
216 IEEE80211_STA_DISABLE_160MHZ;
217 break;
218 default:
219 case NL80211_CHAN_WIDTH_20_NOHT:
220 WARN_ON_ONCE(1);
221 c->width = NL80211_CHAN_WIDTH_20_NOHT;
222 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
223 break;
224 }
225
226 WARN_ON_ONCE(!cfg80211_chandef_valid(c));
227
228 return ret;
229}
230
231static u32
232ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
233 struct ieee80211_supported_band *sband,
234 struct ieee80211_channel *channel,
235 const struct ieee80211_ht_operation *ht_oper,
236 const struct ieee80211_vht_operation *vht_oper,
237 struct cfg80211_chan_def *chandef)
238{
239 struct cfg80211_chan_def vht_chandef;
240 u32 ht_cfreq, ret;
241
242 chandef->chan = channel;
243 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
244 chandef->center_freq1 = channel->center_freq;
245 chandef->center_freq2 = 0;
246
247 if (!ht_oper || !sband->ht_cap.ht_supported) {
248 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
249 goto out;
250 }
251
252 chandef->width = NL80211_CHAN_WIDTH_20;
253
254 ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
255 channel->band);
256 /* check that channel matches the right operating channel */
257 if (channel->center_freq != ht_cfreq) {
258 /*
259 * It's possible that some APs are confused here;
260 * Netgear WNDR3700 sometimes reports 4 higher than
261 * the actual channel in association responses, but
262 * since we look at probe response/beacon data here
263 * it should be OK.
264 */
265 sdata_info(sdata,
266 "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
267 channel->center_freq, ht_cfreq,
268 ht_oper->primary_chan, channel->band);
269 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
270 goto out;
271 }
272
273 /* check 40 MHz support, if we have it */
274 if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
275 switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
276 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
277 chandef->width = NL80211_CHAN_WIDTH_40;
278 chandef->center_freq1 += 10;
279 break;
280 case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
281 chandef->width = NL80211_CHAN_WIDTH_40;
282 chandef->center_freq1 -= 10;
283 break;
284 }
285 } else {
286 /* 40 MHz (and 80 MHz) must be supported for VHT */
287 ret = IEEE80211_STA_DISABLE_VHT;
288 goto out;
289 }
290
291 if (!vht_oper || !sband->vht_cap.vht_supported) {
292 ret = IEEE80211_STA_DISABLE_VHT;
293 goto out;
294 }
295
296 vht_chandef.chan = channel;
297 vht_chandef.center_freq1 =
298 ieee80211_channel_to_frequency(vht_oper->center_freq_seg1_idx,
299 channel->band);
300 vht_chandef.center_freq2 = 0;
301
302 if (vht_oper->center_freq_seg2_idx)
303 vht_chandef.center_freq2 =
304 ieee80211_channel_to_frequency(
305 vht_oper->center_freq_seg2_idx,
306 channel->band);
307
308 switch (vht_oper->chan_width) {
309 case IEEE80211_VHT_CHANWIDTH_USE_HT:
310 vht_chandef.width = chandef->width;
311 break;
312 case IEEE80211_VHT_CHANWIDTH_80MHZ:
313 vht_chandef.width = NL80211_CHAN_WIDTH_80;
314 break;
315 case IEEE80211_VHT_CHANWIDTH_160MHZ:
316 vht_chandef.width = NL80211_CHAN_WIDTH_160;
317 break;
318 case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
319 vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
320 break;
321 default:
322 sdata_info(sdata,
323 "AP VHT operation IE has invalid channel width (%d), disable VHT\n",
324 vht_oper->chan_width);
325 ret = IEEE80211_STA_DISABLE_VHT;
326 goto out;
327 }
328
329 if (!cfg80211_chandef_valid(&vht_chandef)) {
330 sdata_info(sdata,
331 "AP VHT information is invalid, disable VHT\n");
332 ret = IEEE80211_STA_DISABLE_VHT;
333 goto out;
334 }
335
336 if (cfg80211_chandef_identical(chandef, &vht_chandef)) {
337 ret = 0;
338 goto out;
339 }
340
341 if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) {
342 sdata_info(sdata,
343 "AP VHT information doesn't match HT, disable VHT\n");
344 ret = IEEE80211_STA_DISABLE_VHT;
345 goto out;
346 }
347
348 *chandef = vht_chandef;
349
350 ret = 0;
351
352out:
353 while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
354 IEEE80211_CHAN_DISABLED)) {
355 if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) {
356 ret = IEEE80211_STA_DISABLE_HT |
357 IEEE80211_STA_DISABLE_VHT;
358 goto out;
359 }
360
361 ret |= chandef_downgrade(chandef);
362 }
363
364 if (chandef->width != vht_chandef.width)
365 sdata_info(sdata,
366 "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n");
367
368 WARN_ON_ONCE(!cfg80211_chandef_valid(chandef));
369 return ret;
370}
371
177static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata, 372static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
178 struct sta_info *sta, 373 struct sta_info *sta,
179 struct ieee80211_ht_operation *ht_oper, 374 struct ieee80211_ht_operation *ht_oper,
@@ -3321,201 +3516,6 @@ int ieee80211_max_network_latency(struct notifier_block *nb,
3321 return 0; 3516 return 0;
3322} 3517}
3323 3518
3324static u32 chandef_downgrade(struct cfg80211_chan_def *c)
3325{
3326 u32 ret;
3327 int tmp;
3328
3329 switch (c->width) {
3330 case NL80211_CHAN_WIDTH_20:
3331 c->width = NL80211_CHAN_WIDTH_20_NOHT;
3332 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
3333 break;
3334 case NL80211_CHAN_WIDTH_40:
3335 c->width = NL80211_CHAN_WIDTH_20;
3336 c->center_freq1 = c->chan->center_freq;
3337 ret = IEEE80211_STA_DISABLE_40MHZ |
3338 IEEE80211_STA_DISABLE_VHT;
3339 break;
3340 case NL80211_CHAN_WIDTH_80:
3341 tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
3342 /* n_P40 */
3343 tmp /= 2;
3344 /* freq_P40 */
3345 c->center_freq1 = c->center_freq1 - 20 + 40 * tmp;
3346 c->width = NL80211_CHAN_WIDTH_40;
3347 ret = IEEE80211_STA_DISABLE_VHT;
3348 break;
3349 case NL80211_CHAN_WIDTH_80P80:
3350 c->center_freq2 = 0;
3351 c->width = NL80211_CHAN_WIDTH_80;
3352 ret = IEEE80211_STA_DISABLE_80P80MHZ |
3353 IEEE80211_STA_DISABLE_160MHZ;
3354 break;
3355 case NL80211_CHAN_WIDTH_160:
3356 /* n_P20 */
3357 tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
3358 /* n_P80 */
3359 tmp /= 4;
3360 c->center_freq1 = c->center_freq1 - 40 + 80 * tmp;
3361 c->width = NL80211_CHAN_WIDTH_80;
3362 ret = IEEE80211_STA_DISABLE_80P80MHZ |
3363 IEEE80211_STA_DISABLE_160MHZ;
3364 break;
3365 default:
3366 case NL80211_CHAN_WIDTH_20_NOHT:
3367 WARN_ON_ONCE(1);
3368 c->width = NL80211_CHAN_WIDTH_20_NOHT;
3369 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
3370 break;
3371 }
3372
3373 WARN_ON_ONCE(!cfg80211_chandef_valid(c));
3374
3375 return ret;
3376}
3377
3378static u32
3379ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
3380 struct ieee80211_supported_band *sband,
3381 struct ieee80211_channel *channel,
3382 const struct ieee80211_ht_operation *ht_oper,
3383 const struct ieee80211_vht_operation *vht_oper,
3384 struct cfg80211_chan_def *chandef)
3385{
3386 struct cfg80211_chan_def vht_chandef;
3387 u32 ht_cfreq, ret;
3388
3389 chandef->chan = channel;
3390 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
3391 chandef->center_freq1 = channel->center_freq;
3392 chandef->center_freq2 = 0;
3393
3394 if (!ht_oper || !sband->ht_cap.ht_supported) {
3395 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
3396 goto out;
3397 }
3398
3399 chandef->width = NL80211_CHAN_WIDTH_20;
3400
3401 ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
3402 channel->band);
3403 /* check that channel matches the right operating channel */
3404 if (channel->center_freq != ht_cfreq) {
3405 /*
3406 * It's possible that some APs are confused here;
3407 * Netgear WNDR3700 sometimes reports 4 higher than
3408 * the actual channel in association responses, but
3409 * since we look at probe response/beacon data here
3410 * it should be OK.
3411 */
3412 sdata_info(sdata,
3413 "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
3414 channel->center_freq, ht_cfreq,
3415 ht_oper->primary_chan, channel->band);
3416 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
3417 goto out;
3418 }
3419
3420 /* check 40 MHz support, if we have it */
3421 if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
3422 switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
3423 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
3424 chandef->width = NL80211_CHAN_WIDTH_40;
3425 chandef->center_freq1 += 10;
3426 break;
3427 case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
3428 chandef->width = NL80211_CHAN_WIDTH_40;
3429 chandef->center_freq1 -= 10;
3430 break;
3431 }
3432 } else {
3433 /* 40 MHz (and 80 MHz) must be supported for VHT */
3434 ret = IEEE80211_STA_DISABLE_VHT;
3435 goto out;
3436 }
3437
3438 if (!vht_oper || !sband->vht_cap.vht_supported) {
3439 ret = IEEE80211_STA_DISABLE_VHT;
3440 goto out;
3441 }
3442
3443 vht_chandef.chan = channel;
3444 vht_chandef.center_freq1 =
3445 ieee80211_channel_to_frequency(vht_oper->center_freq_seg1_idx,
3446 channel->band);
3447 vht_chandef.center_freq2 = 0;
3448
3449 if (vht_oper->center_freq_seg2_idx)
3450 vht_chandef.center_freq2 =
3451 ieee80211_channel_to_frequency(
3452 vht_oper->center_freq_seg2_idx,
3453 channel->band);
3454
3455 switch (vht_oper->chan_width) {
3456 case IEEE80211_VHT_CHANWIDTH_USE_HT:
3457 vht_chandef.width = chandef->width;
3458 break;
3459 case IEEE80211_VHT_CHANWIDTH_80MHZ:
3460 vht_chandef.width = NL80211_CHAN_WIDTH_80;
3461 break;
3462 case IEEE80211_VHT_CHANWIDTH_160MHZ:
3463 vht_chandef.width = NL80211_CHAN_WIDTH_160;
3464 break;
3465 case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
3466 vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
3467 break;
3468 default:
3469 sdata_info(sdata,
3470 "AP VHT operation IE has invalid channel width (%d), disable VHT\n",
3471 vht_oper->chan_width);
3472 ret = IEEE80211_STA_DISABLE_VHT;
3473 goto out;
3474 }
3475
3476 if (!cfg80211_chandef_valid(&vht_chandef)) {
3477 sdata_info(sdata,
3478 "AP VHT information is invalid, disable VHT\n");
3479 ret = IEEE80211_STA_DISABLE_VHT;
3480 goto out;
3481 }
3482
3483 if (cfg80211_chandef_identical(chandef, &vht_chandef)) {
3484 ret = 0;
3485 goto out;
3486 }
3487
3488 if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) {
3489 sdata_info(sdata,
3490 "AP VHT information doesn't match HT, disable VHT\n");
3491 ret = IEEE80211_STA_DISABLE_VHT;
3492 goto out;
3493 }
3494
3495 *chandef = vht_chandef;
3496
3497 ret = 0;
3498
3499out:
3500 while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
3501 IEEE80211_CHAN_DISABLED)) {
3502 if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) {
3503 ret = IEEE80211_STA_DISABLE_HT |
3504 IEEE80211_STA_DISABLE_VHT;
3505 goto out;
3506 }
3507
3508 ret |= chandef_downgrade(chandef);
3509 }
3510
3511 if (chandef->width != vht_chandef.width)
3512 sdata_info(sdata,
3513 "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n");
3514
3515 WARN_ON_ONCE(!cfg80211_chandef_valid(chandef));
3516 return ret;
3517}
3518
3519static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, 3519static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata,
3520 struct cfg80211_bss *cbss) 3520 struct cfg80211_bss *cbss)
3521{ 3521{