diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-11-22 08:11:39 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-11-27 05:56:07 -0500 |
commit | f2d9d270c15ae0139b54a7e7466d738327e97e03 (patch) | |
tree | f2a758596a1393ad204576e93c8c6c9022156875 /net/mac80211/mlme.c | |
parent | 9f5e8f6efc7c2601136b27d9c7325c245f8fd19a (diff) |
mac80211: support VHT association
Determine the VHT channel from the AP's VHT operation IE
(if present) and configure the hardware to that channel
if it is supported. If channel contexts cause a channel
to not be usable, try a smaller bandwidth.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 368 |
1 files changed, 296 insertions, 72 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d2a4f78b4b0f..35d8cffc973a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -354,6 +354,16 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | |||
354 | /* determine capability flags */ | 354 | /* determine capability flags */ |
355 | cap = vht_cap.cap; | 355 | cap = vht_cap.cap; |
356 | 356 | ||
357 | if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_80P80MHZ) { | ||
358 | cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; | ||
359 | cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; | ||
360 | } | ||
361 | |||
362 | if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_160MHZ) { | ||
363 | cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160; | ||
364 | cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; | ||
365 | } | ||
366 | |||
357 | /* reserve and fill IE */ | 367 | /* reserve and fill IE */ |
358 | pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); | 368 | pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); |
359 | ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); | 369 | ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); |
@@ -543,6 +553,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
543 | offset = noffset; | 553 | offset = noffset; |
544 | } | 554 | } |
545 | 555 | ||
556 | if (WARN_ON_ONCE((ifmgd->flags & IEEE80211_STA_DISABLE_HT) && | ||
557 | !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))) | ||
558 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | ||
559 | |||
546 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) | 560 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) |
547 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, | 561 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, |
548 | sband, chan, sdata->smps_mode); | 562 | sband, chan, sdata->smps_mode); |
@@ -3183,23 +3197,270 @@ int ieee80211_max_network_latency(struct notifier_block *nb, | |||
3183 | return 0; | 3197 | return 0; |
3184 | } | 3198 | } |
3185 | 3199 | ||
3200 | static u32 chandef_downgrade(struct cfg80211_chan_def *c) | ||
3201 | { | ||
3202 | u32 ret; | ||
3203 | int tmp; | ||
3204 | |||
3205 | switch (c->width) { | ||
3206 | case NL80211_CHAN_WIDTH_20: | ||
3207 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
3208 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
3209 | break; | ||
3210 | case NL80211_CHAN_WIDTH_40: | ||
3211 | c->width = NL80211_CHAN_WIDTH_20; | ||
3212 | c->center_freq1 = c->chan->center_freq; | ||
3213 | ret = IEEE80211_STA_DISABLE_40MHZ | | ||
3214 | IEEE80211_STA_DISABLE_VHT; | ||
3215 | break; | ||
3216 | case NL80211_CHAN_WIDTH_80: | ||
3217 | tmp = (30 + c->chan->center_freq - c->center_freq1)/20; | ||
3218 | /* n_P40 */ | ||
3219 | tmp /= 2; | ||
3220 | /* freq_P40 */ | ||
3221 | c->center_freq1 = c->center_freq1 - 20 + 40 * tmp; | ||
3222 | c->width = NL80211_CHAN_WIDTH_40; | ||
3223 | ret = IEEE80211_STA_DISABLE_VHT; | ||
3224 | break; | ||
3225 | case NL80211_CHAN_WIDTH_80P80: | ||
3226 | c->center_freq2 = 0; | ||
3227 | c->width = NL80211_CHAN_WIDTH_80; | ||
3228 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
3229 | IEEE80211_STA_DISABLE_160MHZ; | ||
3230 | break; | ||
3231 | case NL80211_CHAN_WIDTH_160: | ||
3232 | /* n_P20 */ | ||
3233 | tmp = (70 + c->chan->center_freq - c->center_freq1)/20; | ||
3234 | /* n_P80 */ | ||
3235 | tmp /= 4; | ||
3236 | c->center_freq1 = c->center_freq1 - 40 + 80 * tmp; | ||
3237 | c->width = NL80211_CHAN_WIDTH_80; | ||
3238 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
3239 | IEEE80211_STA_DISABLE_160MHZ; | ||
3240 | break; | ||
3241 | default: | ||
3242 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
3243 | WARN_ON_ONCE(1); | ||
3244 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
3245 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
3246 | break; | ||
3247 | } | ||
3248 | |||
3249 | WARN_ON_ONCE(!cfg80211_chandef_valid(c)); | ||
3250 | |||
3251 | return ret; | ||
3252 | } | ||
3253 | |||
3254 | static u32 | ||
3255 | ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | ||
3256 | struct ieee80211_supported_band *sband, | ||
3257 | struct ieee80211_channel *channel, | ||
3258 | const struct ieee80211_ht_operation *ht_oper, | ||
3259 | const struct ieee80211_vht_operation *vht_oper, | ||
3260 | struct cfg80211_chan_def *chandef) | ||
3261 | { | ||
3262 | struct cfg80211_chan_def vht_chandef; | ||
3263 | u32 ht_cfreq, ret; | ||
3264 | |||
3265 | chandef->chan = channel; | ||
3266 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
3267 | chandef->center_freq1 = channel->center_freq; | ||
3268 | chandef->center_freq2 = 0; | ||
3269 | |||
3270 | if (!ht_oper || !sband->ht_cap.ht_supported) { | ||
3271 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
3272 | goto out; | ||
3273 | } | ||
3274 | |||
3275 | chandef->width = NL80211_CHAN_WIDTH_20; | ||
3276 | |||
3277 | ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, | ||
3278 | channel->band); | ||
3279 | /* check that channel matches the right operating channel */ | ||
3280 | if (channel->center_freq != ht_cfreq) { | ||
3281 | /* | ||
3282 | * It's possible that some APs are confused here; | ||
3283 | * Netgear WNDR3700 sometimes reports 4 higher than | ||
3284 | * the actual channel in association responses, but | ||
3285 | * since we look at probe response/beacon data here | ||
3286 | * it should be OK. | ||
3287 | */ | ||
3288 | sdata_info(sdata, | ||
3289 | "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", | ||
3290 | channel->center_freq, ht_cfreq, | ||
3291 | ht_oper->primary_chan, channel->band); | ||
3292 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
3293 | goto out; | ||
3294 | } | ||
3295 | |||
3296 | /* check 40 MHz support, if we have it */ | ||
3297 | if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | ||
3298 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
3299 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
3300 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
3301 | chandef->center_freq1 += 10; | ||
3302 | break; | ||
3303 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
3304 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
3305 | chandef->center_freq1 -= 10; | ||
3306 | break; | ||
3307 | } | ||
3308 | } else { | ||
3309 | /* 40 MHz (and 80 MHz) must be supported for VHT */ | ||
3310 | ret = IEEE80211_STA_DISABLE_VHT; | ||
3311 | goto out; | ||
3312 | } | ||
3313 | |||
3314 | if (!vht_oper || !sband->vht_cap.vht_supported) { | ||
3315 | ret = IEEE80211_STA_DISABLE_VHT; | ||
3316 | goto out; | ||
3317 | } | ||
3318 | |||
3319 | vht_chandef.chan = channel; | ||
3320 | vht_chandef.center_freq1 = | ||
3321 | ieee80211_channel_to_frequency(vht_oper->center_freq_seg1_idx, | ||
3322 | channel->band); | ||
3323 | vht_chandef.center_freq2 = 0; | ||
3324 | |||
3325 | if (vht_oper->center_freq_seg2_idx) | ||
3326 | vht_chandef.center_freq2 = | ||
3327 | ieee80211_channel_to_frequency( | ||
3328 | vht_oper->center_freq_seg2_idx, | ||
3329 | channel->band); | ||
3330 | |||
3331 | switch (vht_oper->chan_width) { | ||
3332 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | ||
3333 | vht_chandef.width = chandef->width; | ||
3334 | break; | ||
3335 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | ||
3336 | vht_chandef.width = NL80211_CHAN_WIDTH_80; | ||
3337 | break; | ||
3338 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | ||
3339 | vht_chandef.width = NL80211_CHAN_WIDTH_160; | ||
3340 | break; | ||
3341 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | ||
3342 | vht_chandef.width = NL80211_CHAN_WIDTH_80P80; | ||
3343 | break; | ||
3344 | default: | ||
3345 | sdata_info(sdata, | ||
3346 | "AP VHT operation IE has invalid channel width (%d), disable VHT\n", | ||
3347 | vht_oper->chan_width); | ||
3348 | ret = IEEE80211_STA_DISABLE_VHT; | ||
3349 | goto out; | ||
3350 | } | ||
3351 | |||
3352 | if (!cfg80211_chandef_valid(&vht_chandef)) { | ||
3353 | sdata_info(sdata, | ||
3354 | "AP VHT information is invalid, disable VHT\n"); | ||
3355 | ret = IEEE80211_STA_DISABLE_VHT; | ||
3356 | goto out; | ||
3357 | } | ||
3358 | |||
3359 | if (cfg80211_chandef_identical(chandef, &vht_chandef)) { | ||
3360 | ret = 0; | ||
3361 | goto out; | ||
3362 | } | ||
3363 | |||
3364 | if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) { | ||
3365 | sdata_info(sdata, | ||
3366 | "AP VHT information doesn't match HT, disable VHT\n"); | ||
3367 | ret = IEEE80211_STA_DISABLE_VHT; | ||
3368 | goto out; | ||
3369 | } | ||
3370 | |||
3371 | *chandef = vht_chandef; | ||
3372 | |||
3373 | ret = 0; | ||
3374 | |||
3375 | while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | ||
3376 | IEEE80211_CHAN_DISABLED)) { | ||
3377 | if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { | ||
3378 | ret = IEEE80211_STA_DISABLE_HT | | ||
3379 | IEEE80211_STA_DISABLE_VHT; | ||
3380 | goto out; | ||
3381 | } | ||
3382 | |||
3383 | ret = chandef_downgrade(chandef); | ||
3384 | } | ||
3385 | |||
3386 | if (chandef->width != vht_chandef.width) | ||
3387 | sdata_info(sdata, | ||
3388 | "local regulatory prevented using AP HT/VHT configuration, downgraded\n"); | ||
3389 | |||
3390 | out: | ||
3391 | WARN_ON_ONCE(!cfg80211_chandef_valid(chandef)); | ||
3392 | return ret; | ||
3393 | } | ||
3394 | |||
3395 | static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, | ||
3396 | struct cfg80211_bss *cbss) | ||
3397 | { | ||
3398 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3399 | const u8 *ht_cap_ie, *vht_cap_ie; | ||
3400 | const struct ieee80211_ht_cap *ht_cap; | ||
3401 | const struct ieee80211_vht_cap *vht_cap; | ||
3402 | u8 chains = 1; | ||
3403 | |||
3404 | if (ifmgd->flags & IEEE80211_STA_DISABLE_HT) | ||
3405 | return chains; | ||
3406 | |||
3407 | ht_cap_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, | ||
3408 | cbss->information_elements, | ||
3409 | cbss->len_information_elements); | ||
3410 | if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap)) { | ||
3411 | ht_cap = (void *)(ht_cap_ie + 2); | ||
3412 | chains = ieee80211_mcs_to_chains(&ht_cap->mcs); | ||
3413 | /* | ||
3414 | * TODO: use "Tx Maximum Number Spatial Streams Supported" and | ||
3415 | * "Tx Unequal Modulation Supported" fields. | ||
3416 | */ | ||
3417 | } | ||
3418 | |||
3419 | if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) | ||
3420 | return chains; | ||
3421 | |||
3422 | vht_cap_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, | ||
3423 | cbss->information_elements, | ||
3424 | cbss->len_information_elements); | ||
3425 | if (vht_cap_ie && vht_cap_ie[1] >= sizeof(*vht_cap)) { | ||
3426 | u8 nss; | ||
3427 | u16 tx_mcs_map; | ||
3428 | |||
3429 | vht_cap = (void *)(vht_cap_ie + 2); | ||
3430 | tx_mcs_map = le16_to_cpu(vht_cap->supp_mcs.tx_mcs_map); | ||
3431 | for (nss = 8; nss > 0; nss--) { | ||
3432 | if (((tx_mcs_map >> (2 * (nss - 1))) & 3) != | ||
3433 | IEEE80211_VHT_MCS_NOT_SUPPORTED) | ||
3434 | break; | ||
3435 | } | ||
3436 | /* TODO: use "Tx Highest Supported Long GI Data Rate" field? */ | ||
3437 | chains = max(chains, nss); | ||
3438 | } | ||
3439 | |||
3440 | return chains; | ||
3441 | } | ||
3442 | |||
3186 | static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | 3443 | static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, |
3187 | struct cfg80211_bss *cbss) | 3444 | struct cfg80211_bss *cbss) |
3188 | { | 3445 | { |
3189 | struct ieee80211_local *local = sdata->local; | 3446 | struct ieee80211_local *local = sdata->local; |
3190 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3447 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3191 | int ht_cfreq; | ||
3192 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
3193 | const u8 *ht_oper_ie; | ||
3194 | const struct ieee80211_ht_operation *ht_oper = NULL; | 3448 | const struct ieee80211_ht_operation *ht_oper = NULL; |
3449 | const struct ieee80211_vht_operation *vht_oper = NULL; | ||
3195 | struct ieee80211_supported_band *sband; | 3450 | struct ieee80211_supported_band *sband; |
3196 | struct cfg80211_chan_def chandef; | 3451 | struct cfg80211_chan_def chandef; |
3452 | int ret; | ||
3197 | 3453 | ||
3198 | sband = local->hw.wiphy->bands[cbss->channel->band]; | 3454 | sband = local->hw.wiphy->bands[cbss->channel->band]; |
3199 | 3455 | ||
3200 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_40MHZ; | 3456 | ifmgd->flags &= ~(IEEE80211_STA_DISABLE_40MHZ | |
3457 | IEEE80211_STA_DISABLE_80P80MHZ | | ||
3458 | IEEE80211_STA_DISABLE_160MHZ); | ||
3459 | |||
3460 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && | ||
3461 | sband->ht_cap.ht_supported) { | ||
3462 | const u8 *ht_oper_ie; | ||
3201 | 3463 | ||
3202 | if (sband->ht_cap.ht_supported) { | ||
3203 | ht_oper_ie = cfg80211_find_ie(WLAN_EID_HT_OPERATION, | 3464 | ht_oper_ie = cfg80211_find_ie(WLAN_EID_HT_OPERATION, |
3204 | cbss->information_elements, | 3465 | cbss->information_elements, |
3205 | cbss->len_information_elements); | 3466 | cbss->len_information_elements); |
@@ -3207,82 +3468,45 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
3207 | ht_oper = (void *)(ht_oper_ie + 2); | 3468 | ht_oper = (void *)(ht_oper_ie + 2); |
3208 | } | 3469 | } |
3209 | 3470 | ||
3210 | if (ht_oper) { | 3471 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && |
3211 | ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, | 3472 | sband->vht_cap.vht_supported) { |
3212 | cbss->channel->band); | 3473 | const u8 *vht_oper_ie; |
3213 | /* check that channel matches the right operating channel */ | 3474 | |
3214 | if (cbss->channel->center_freq != ht_cfreq) { | 3475 | vht_oper_ie = cfg80211_find_ie(WLAN_EID_VHT_OPERATION, |
3215 | /* | 3476 | cbss->information_elements, |
3216 | * It's possible that some APs are confused here; | 3477 | cbss->len_information_elements); |
3217 | * Netgear WNDR3700 sometimes reports 4 higher than | 3478 | if (vht_oper_ie && vht_oper_ie[1] >= sizeof(*vht_oper)) |
3218 | * the actual channel in association responses, but | 3479 | vht_oper = (void *)(vht_oper_ie + 2); |
3219 | * since we look at probe response/beacon data here | 3480 | if (vht_oper && !ht_oper) { |
3220 | * it should be OK. | 3481 | vht_oper = NULL; |
3221 | */ | ||
3222 | sdata_info(sdata, | 3482 | sdata_info(sdata, |
3223 | "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", | 3483 | "AP advertised VHT without HT, disabling both\n"); |
3224 | cbss->channel->center_freq, | 3484 | sdata->flags |= IEEE80211_STA_DISABLE_HT; |
3225 | ht_cfreq, ht_oper->primary_chan, | 3485 | sdata->flags |= IEEE80211_STA_DISABLE_VHT; |
3226 | cbss->channel->band); | ||
3227 | ht_oper = NULL; | ||
3228 | } | 3486 | } |
3229 | } | 3487 | } |
3230 | 3488 | ||
3231 | if (ht_oper) { | 3489 | ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, |
3232 | /* | 3490 | cbss->channel, |
3233 | * cfg80211 already verified that the channel itself can | 3491 | ht_oper, vht_oper, |
3234 | * be used, but it didn't check that we can do the right | 3492 | &chandef); |
3235 | * HT type, so do that here as well. If HT40 isn't allowed | ||
3236 | * on this channel, disable 40 MHz operation. | ||
3237 | */ | ||
3238 | const u8 *ht_cap_ie; | ||
3239 | const struct ieee80211_ht_cap *ht_cap; | ||
3240 | u8 chains = 1; | ||
3241 | |||
3242 | channel_type = NL80211_CHAN_HT20; | ||
3243 | |||
3244 | if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | ||
3245 | switch (ht_oper->ht_param & | ||
3246 | IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
3247 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
3248 | if (cbss->channel->flags & | ||
3249 | IEEE80211_CHAN_NO_HT40PLUS) | ||
3250 | ifmgd->flags |= | ||
3251 | IEEE80211_STA_DISABLE_40MHZ; | ||
3252 | else | ||
3253 | channel_type = NL80211_CHAN_HT40PLUS; | ||
3254 | break; | ||
3255 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
3256 | if (cbss->channel->flags & | ||
3257 | IEEE80211_CHAN_NO_HT40MINUS) | ||
3258 | ifmgd->flags |= | ||
3259 | IEEE80211_STA_DISABLE_40MHZ; | ||
3260 | else | ||
3261 | channel_type = NL80211_CHAN_HT40MINUS; | ||
3262 | break; | ||
3263 | } | ||
3264 | } | ||
3265 | 3493 | ||
3266 | ht_cap_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, | 3494 | sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), |
3267 | cbss->information_elements, | 3495 | local->rx_chains); |
3268 | cbss->len_information_elements); | ||
3269 | if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap)) { | ||
3270 | ht_cap = (void *)(ht_cap_ie + 2); | ||
3271 | chains = ieee80211_mcs_to_chains(&ht_cap->mcs); | ||
3272 | } | ||
3273 | sdata->needed_rx_chains = min(chains, local->rx_chains); | ||
3274 | } else { | ||
3275 | sdata->needed_rx_chains = 1; | ||
3276 | sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_HT; | ||
3277 | } | ||
3278 | 3496 | ||
3279 | /* will change later if needed */ | 3497 | /* will change later if needed */ |
3280 | sdata->smps_mode = IEEE80211_SMPS_OFF; | 3498 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
3281 | 3499 | ||
3282 | ieee80211_vif_release_channel(sdata); | 3500 | /* |
3283 | cfg80211_chandef_create(&chandef, cbss->channel, channel_type); | 3501 | * If this fails (possibly due to channel context sharing |
3284 | return ieee80211_vif_use_channel(sdata, &chandef, | 3502 | * on incompatible channels, e.g. 80+80 and 160 sharing the |
3285 | IEEE80211_CHANCTX_SHARED); | 3503 | * same control channel) try to use a smaller bandwidth. |
3504 | */ | ||
3505 | ret = ieee80211_vif_use_channel(sdata, &chandef, | ||
3506 | IEEE80211_CHANCTX_SHARED); | ||
3507 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) | ||
3508 | ifmgd->flags |= chandef_downgrade(&chandef); | ||
3509 | return ret; | ||
3286 | } | 3510 | } |
3287 | 3511 | ||
3288 | static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | 3512 | static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, |