diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-02-08 08:52:32 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-02-15 03:41:37 -0500 |
commit | 6565ec9b58483a9706fbe888364aeceb359aeced (patch) | |
tree | 42838a53f6dd307909e87c57e27950dd6d4fd976 /net/mac80211 | |
parent | 2c9b735982ee8a2d34e7eeb3e26b683f81872fdb (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')
-rw-r--r-- | net/mac80211/mlme.c | 390 |
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 | ||
177 | static 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 | |||
231 | static u32 | ||
232 | ieee80211_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 | |||
352 | out: | ||
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 | |||
177 | static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata, | 372 | static 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 | ||
3324 | static 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 | |||
3378 | static u32 | ||
3379 | ieee80211_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 | |||
3499 | out: | ||
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 | |||
3519 | static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, | 3519 | static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, |
3520 | struct cfg80211_bss *cbss) | 3520 | struct cfg80211_bss *cbss) |
3521 | { | 3521 | { |