aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-02-08 09:12:14 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-02-15 03:41:37 -0500
commit30eb1dc2c43039e0fe278e6f3a288de9f216d70d (patch)
tree6b0e1563c595b8093238cffd20c42c074bc673a5 /net/mac80211/mlme.c
parent6565ec9b58483a9706fbe888364aeceb359aeced (diff)
mac80211: properly track HT/VHT operation changes
A while ago, I made the mac80211 station code never change the channel type after association. This solved a number of issues but is ultimately wrong, we should react if the AP changes the HT operation IE and switches bandwidth. One of the issues is that we associate as HT40 capable, but if the AP ever switches to 40 MHz we won't be able to receive such frames because we never set our channel to 40 MHz. This addresses this and VHT operation changes. If there's a change that is incompatible with our setup, e.g. if the AP decides to change the channel entirely (and for some reason we still hear the beacon) we'll just disconnect. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c236
1 files changed, 168 insertions, 68 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 50423c66c239..05b229e3b226 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -114,6 +114,9 @@ enum rx_mgmt_action {
114 114
115 /* caller must call cfg80211_send_assoc_timeout() */ 115 /* caller must call cfg80211_send_assoc_timeout() */
116 RX_MGMT_CFG80211_ASSOC_TIMEOUT, 116 RX_MGMT_CFG80211_ASSOC_TIMEOUT,
117
118 /* used when a processed beacon causes a deauth */
119 RX_MGMT_CFG80211_TX_DEAUTH,
117}; 120};
118 121
119/* utils */ 122/* utils */
@@ -234,7 +237,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
234 struct ieee80211_channel *channel, 237 struct ieee80211_channel *channel,
235 const struct ieee80211_ht_operation *ht_oper, 238 const struct ieee80211_ht_operation *ht_oper,
236 const struct ieee80211_vht_operation *vht_oper, 239 const struct ieee80211_vht_operation *vht_oper,
237 struct cfg80211_chan_def *chandef) 240 struct cfg80211_chan_def *chandef, bool verbose)
238{ 241{
239 struct cfg80211_chan_def vht_chandef; 242 struct cfg80211_chan_def vht_chandef;
240 u32 ht_cfreq, ret; 243 u32 ht_cfreq, ret;
@@ -262,10 +265,11 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
262 * since we look at probe response/beacon data here 265 * since we look at probe response/beacon data here
263 * it should be OK. 266 * it should be OK.
264 */ 267 */
265 sdata_info(sdata, 268 if (verbose)
266 "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", 269 sdata_info(sdata,
267 channel->center_freq, ht_cfreq, 270 "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
268 ht_oper->primary_chan, channel->band); 271 channel->center_freq, ht_cfreq,
272 ht_oper->primary_chan, channel->band);
269 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; 273 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
270 goto out; 274 goto out;
271 } 275 }
@@ -319,16 +323,18 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
319 vht_chandef.width = NL80211_CHAN_WIDTH_80P80; 323 vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
320 break; 324 break;
321 default: 325 default:
322 sdata_info(sdata, 326 if (verbose)
323 "AP VHT operation IE has invalid channel width (%d), disable VHT\n", 327 sdata_info(sdata,
324 vht_oper->chan_width); 328 "AP VHT operation IE has invalid channel width (%d), disable VHT\n",
329 vht_oper->chan_width);
325 ret = IEEE80211_STA_DISABLE_VHT; 330 ret = IEEE80211_STA_DISABLE_VHT;
326 goto out; 331 goto out;
327 } 332 }
328 333
329 if (!cfg80211_chandef_valid(&vht_chandef)) { 334 if (!cfg80211_chandef_valid(&vht_chandef)) {
330 sdata_info(sdata, 335 if (verbose)
331 "AP VHT information is invalid, disable VHT\n"); 336 sdata_info(sdata,
337 "AP VHT information is invalid, disable VHT\n");
332 ret = IEEE80211_STA_DISABLE_VHT; 338 ret = IEEE80211_STA_DISABLE_VHT;
333 goto out; 339 goto out;
334 } 340 }
@@ -339,8 +345,9 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
339 } 345 }
340 346
341 if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) { 347 if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) {
342 sdata_info(sdata, 348 if (verbose)
343 "AP VHT information doesn't match HT, disable VHT\n"); 349 sdata_info(sdata,
350 "AP VHT information doesn't match HT, disable VHT\n");
344 ret = IEEE80211_STA_DISABLE_VHT; 351 ret = IEEE80211_STA_DISABLE_VHT;
345 goto out; 352 goto out;
346 } 353 }
@@ -361,7 +368,7 @@ out:
361 ret |= chandef_downgrade(chandef); 368 ret |= chandef_downgrade(chandef);
362 } 369 }
363 370
364 if (chandef->width != vht_chandef.width) 371 if (chandef->width != vht_chandef.width && verbose)
365 sdata_info(sdata, 372 sdata_info(sdata,
366 "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n"); 373 "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n");
367 374
@@ -369,66 +376,128 @@ out:
369 return ret; 376 return ret;
370} 377}
371 378
372static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata, 379static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
373 struct sta_info *sta, 380 struct sta_info *sta,
374 struct ieee80211_ht_operation *ht_oper, 381 const struct ieee80211_ht_operation *ht_oper,
375 const u8 *bssid, bool reconfig) 382 const struct ieee80211_vht_operation *vht_oper,
383 const u8 *bssid, u32 *changed)
376{ 384{
377 struct ieee80211_local *local = sdata->local; 385 struct ieee80211_local *local = sdata->local;
386 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
378 struct ieee80211_supported_band *sband; 387 struct ieee80211_supported_band *sband;
379 struct ieee80211_channel *chan; 388 struct ieee80211_channel *chan;
380 u32 changed = 0; 389 struct cfg80211_chan_def chandef;
381 u16 ht_opmode; 390 u16 ht_opmode;
382 bool disable_40 = false; 391 u32 flags;
392 enum ieee80211_sta_rx_bandwidth new_sta_bw;
393 int ret;
383 394
384 if (WARN_ON_ONCE(!sta)) 395 /* if HT was/is disabled, don't track any bandwidth changes */
396 if (ifmgd->flags & IEEE80211_STA_DISABLE_HT || !ht_oper)
385 return 0; 397 return 0;
386 398
399 /* don't check VHT if we associated as non-VHT station */
400 if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
401 vht_oper = NULL;
402
403 if (WARN_ON_ONCE(!sta))
404 return -EINVAL;
405
387 chan = sdata->vif.bss_conf.chandef.chan; 406 chan = sdata->vif.bss_conf.chandef.chan;
388 sband = local->hw.wiphy->bands[chan->band]; 407 sband = local->hw.wiphy->bands[chan->band];
389 408
390 switch (sdata->vif.bss_conf.chandef.width) { 409 /* calculate new channel (type) based on HT/VHT operation IEs */
410 flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper,
411 vht_oper, &chandef, false);
412
413 /*
414 * Downgrade the new channel if we associated with restricted
415 * capabilities. For example, if we associated as a 20 MHz STA
416 * to a 40 MHz AP (due to regulatory, capabilities or config
417 * reasons) then switching to a 40 MHz channel now won't do us
418 * any good -- we couldn't use it with the AP.
419 */
420 if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ &&
421 chandef.width == NL80211_CHAN_WIDTH_80P80)
422 flags |= chandef_downgrade(&chandef);
423 if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ &&
424 chandef.width == NL80211_CHAN_WIDTH_160)
425 flags |= chandef_downgrade(&chandef);
426 if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ &&
427 chandef.width > NL80211_CHAN_WIDTH_20)
428 flags |= chandef_downgrade(&chandef);
429
430 if (cfg80211_chandef_identical(&chandef, &sdata->vif.bss_conf.chandef))
431 return 0;
432
433 sdata_info(sdata,
434 "AP %pM changed bandwidth, new config is %d MHz, width %d (%d/%d MHz)\n",
435 ifmgd->bssid, chandef.chan->center_freq, chandef.width,
436 chandef.center_freq1, chandef.center_freq2);
437
438 if (flags != (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
439 IEEE80211_STA_DISABLE_VHT |
440 IEEE80211_STA_DISABLE_40MHZ |
441 IEEE80211_STA_DISABLE_80P80MHZ |
442 IEEE80211_STA_DISABLE_160MHZ)) ||
443 !cfg80211_chandef_valid(&chandef)) {
444 sdata_info(sdata,
445 "AP %pM changed bandwidth in a way we can't support - disconnect\n",
446 ifmgd->bssid);
447 return -EINVAL;
448 }
449
450 switch (chandef.width) {
451 case NL80211_CHAN_WIDTH_20_NOHT:
452 case NL80211_CHAN_WIDTH_20:
453 new_sta_bw = IEEE80211_STA_RX_BW_20;
454 break;
391 case NL80211_CHAN_WIDTH_40: 455 case NL80211_CHAN_WIDTH_40:
392 if (chan->center_freq > 456 new_sta_bw = IEEE80211_STA_RX_BW_40;
393 sdata->vif.bss_conf.chandef.center_freq1 &&
394 chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
395 disable_40 = true;
396 if (chan->center_freq <
397 sdata->vif.bss_conf.chandef.center_freq1 &&
398 chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
399 disable_40 = true;
400 break; 457 break;
401 default: 458 case NL80211_CHAN_WIDTH_80:
459 new_sta_bw = IEEE80211_STA_RX_BW_80;
402 break; 460 break;
461 case NL80211_CHAN_WIDTH_80P80:
462 case NL80211_CHAN_WIDTH_160:
463 new_sta_bw = IEEE80211_STA_RX_BW_160;
464 break;
465 default:
466 return -EINVAL;
403 } 467 }
404 468
405 /* This can change during the lifetime of the BSS */ 469 if (new_sta_bw > sta->cur_max_bandwidth)
406 if (!(ht_oper->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) 470 new_sta_bw = sta->cur_max_bandwidth;
407 disable_40 = true;
408 471
409 if (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) 472 if (new_sta_bw < sta->sta.bandwidth) {
410 disable_40 = true; 473 sta->sta.bandwidth = new_sta_bw;
474 rate_control_rate_update(local, sband, sta,
475 IEEE80211_RC_BW_CHANGED);
476 }
411 477
412 if (disable_40 != (sta->sta.bandwidth < IEEE80211_STA_RX_BW_40)) { 478 ret = ieee80211_vif_change_bandwidth(sdata, &chandef, changed);
413 if (disable_40) 479 if (ret) {
414 sta->sta.bandwidth = IEEE80211_STA_RX_BW_20; 480 sdata_info(sdata,
415 else 481 "AP %pM changed bandwidth to incompatible one - disconnect\n",
416 sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta); 482 ifmgd->bssid);
483 return ret;
484 }
417 485
418 if (reconfig) 486 if (new_sta_bw > sta->sta.bandwidth) {
419 rate_control_rate_update(local, sband, sta, 487 sta->sta.bandwidth = new_sta_bw;
420 IEEE80211_RC_BW_CHANGED); 488 rate_control_rate_update(local, sband, sta,
489 IEEE80211_RC_BW_CHANGED);
421 } 490 }
422 491
423 ht_opmode = le16_to_cpu(ht_oper->operation_mode); 492 ht_opmode = le16_to_cpu(ht_oper->operation_mode);
424 493
425 /* if bss configuration changed store the new one */ 494 /* if bss configuration changed store the new one */
426 if (!reconfig || (sdata->vif.bss_conf.ht_operation_mode != ht_opmode)) { 495 if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
427 changed |= BSS_CHANGED_HT; 496 *changed |= BSS_CHANGED_HT;
428 sdata->vif.bss_conf.ht_operation_mode = ht_opmode; 497 sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
429 } 498 }
430 499
431 return changed; 500 return 0;
432} 501}
433 502
434/* frame sending functions */ 503/* frame sending functions */
@@ -2377,6 +2446,24 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
2377 2446
2378 ifmgd->aid = aid; 2447 ifmgd->aid = aid;
2379 2448
2449 /*
2450 * We previously checked these in the beacon/probe response, so
2451 * they should be present here. This is just a safety net.
2452 */
2453 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
2454 (!elems.wmm_param || !elems.ht_cap_elem || !elems.ht_operation)) {
2455 sdata_info(sdata,
2456 "HT AP is missing WMM params or HT capability/operation in AssocResp\n");
2457 return false;
2458 }
2459
2460 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
2461 (!elems.vht_cap_elem || !elems.vht_operation)) {
2462 sdata_info(sdata,
2463 "VHT AP is missing VHT capability/operation in AssocResp\n");
2464 return false;
2465 }
2466
2380 mutex_lock(&sdata->local->sta_mtx); 2467 mutex_lock(&sdata->local->sta_mtx);
2381 /* 2468 /*
2382 * station info was already allocated and inserted before 2469 * station info was already allocated and inserted before
@@ -2390,6 +2477,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
2390 2477
2391 sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; 2478 sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)];
2392 2479
2480 /* Set up internal HT/VHT capabilities */
2393 if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) 2481 if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
2394 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, 2482 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
2395 elems.ht_cap_elem, sta); 2483 elems.ht_cap_elem, sta);
@@ -2398,11 +2486,12 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
2398 ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, 2486 ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
2399 elems.vht_cap_elem, sta); 2487 elems.vht_cap_elem, sta);
2400 2488
2401 if (elems.ht_operation && elems.wmm_param && 2489 /*
2402 !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) 2490 * Some APs, e.g. Netgear WNDR3700, report invalid HT operation data
2403 changed |= ieee80211_config_ht_tx(sdata, sta, 2491 * in their association response, so ignore that data for our own
2404 elems.ht_operation, 2492 * configuration. If it changed since the last beacon, we'll get the
2405 cbss->bssid, false); 2493 * next beacon and update then.
2494 */
2406 2495
2407 /* 2496 /*
2408 * If an operating mode notification IE is present, override the 2497 * If an operating mode notification IE is present, override the
@@ -2679,10 +2768,10 @@ static const u64 care_about_ies =
2679 (1ULL << WLAN_EID_HT_CAPABILITY) | 2768 (1ULL << WLAN_EID_HT_CAPABILITY) |
2680 (1ULL << WLAN_EID_HT_OPERATION); 2769 (1ULL << WLAN_EID_HT_OPERATION);
2681 2770
2682static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, 2771static enum rx_mgmt_action
2683 struct ieee80211_mgmt *mgmt, 2772ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2684 size_t len, 2773 struct ieee80211_mgmt *mgmt, size_t len,
2685 struct ieee80211_rx_status *rx_status) 2774 u8 *deauth_buf, struct ieee80211_rx_status *rx_status)
2686{ 2775{
2687 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 2776 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2688 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; 2777 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
@@ -2703,18 +2792,18 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2703 /* Process beacon from the current BSS */ 2792 /* Process beacon from the current BSS */
2704 baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; 2793 baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
2705 if (baselen > len) 2794 if (baselen > len)
2706 return; 2795 return RX_MGMT_NONE;
2707 2796
2708 rcu_read_lock(); 2797 rcu_read_lock();
2709 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); 2798 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
2710 if (!chanctx_conf) { 2799 if (!chanctx_conf) {
2711 rcu_read_unlock(); 2800 rcu_read_unlock();
2712 return; 2801 return RX_MGMT_NONE;
2713 } 2802 }
2714 2803
2715 if (rx_status->freq != chanctx_conf->def.chan->center_freq) { 2804 if (rx_status->freq != chanctx_conf->def.chan->center_freq) {
2716 rcu_read_unlock(); 2805 rcu_read_unlock();
2717 return; 2806 return RX_MGMT_NONE;
2718 } 2807 }
2719 chan = chanctx_conf->def.chan; 2808 chan = chanctx_conf->def.chan;
2720 rcu_read_unlock(); 2809 rcu_read_unlock();
@@ -2742,12 +2831,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2742 ifmgd->assoc_data->timeout = jiffies; 2831 ifmgd->assoc_data->timeout = jiffies;
2743 ifmgd->assoc_data->timeout_started = true; 2832 ifmgd->assoc_data->timeout_started = true;
2744 run_again(ifmgd, ifmgd->assoc_data->timeout); 2833 run_again(ifmgd, ifmgd->assoc_data->timeout);
2745 return; 2834 return RX_MGMT_NONE;
2746 } 2835 }
2747 2836
2748 if (!ifmgd->associated || 2837 if (!ifmgd->associated ||
2749 !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) 2838 !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
2750 return; 2839 return RX_MGMT_NONE;
2751 bssid = ifmgd->associated->bssid; 2840 bssid = ifmgd->associated->bssid;
2752 2841
2753 /* Track average RSSI from the Beacon frames of the current AP */ 2842 /* Track average RSSI from the Beacon frames of the current AP */
@@ -2885,7 +2974,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2885 } 2974 }
2886 2975
2887 if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) 2976 if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
2888 return; 2977 return RX_MGMT_NONE;
2889 ifmgd->beacon_crc = ncrc; 2978 ifmgd->beacon_crc = ncrc;
2890 ifmgd->beacon_crc_valid = true; 2979 ifmgd->beacon_crc_valid = true;
2891 2980
@@ -2934,11 +3023,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2934 mutex_lock(&local->sta_mtx); 3023 mutex_lock(&local->sta_mtx);
2935 sta = sta_info_get(sdata, bssid); 3024 sta = sta_info_get(sdata, bssid);
2936 3025
2937 if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param && 3026 if (ieee80211_config_bw(sdata, sta, elems.ht_operation,
2938 !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) 3027 elems.vht_operation, bssid, &changed)) {
2939 changed |= ieee80211_config_ht_tx(sdata, sta, 3028 mutex_unlock(&local->sta_mtx);
2940 elems.ht_operation, 3029 ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
2941 bssid, true); 3030 WLAN_REASON_DEAUTH_LEAVING,
3031 true, deauth_buf);
3032 return RX_MGMT_CFG80211_TX_DEAUTH;
3033 }
2942 3034
2943 if (sta && elems.opmode_notif) 3035 if (sta && elems.opmode_notif)
2944 ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif, 3036 ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif,
@@ -2954,6 +3046,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2954 elems.pwr_constr_elem); 3046 elems.pwr_constr_elem);
2955 3047
2956 ieee80211_bss_info_change_notify(sdata, changed); 3048 ieee80211_bss_info_change_notify(sdata, changed);
3049
3050 return RX_MGMT_NONE;
2957} 3051}
2958 3052
2959void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, 3053void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
@@ -2964,6 +3058,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
2964 struct ieee80211_mgmt *mgmt; 3058 struct ieee80211_mgmt *mgmt;
2965 struct cfg80211_bss *bss = NULL; 3059 struct cfg80211_bss *bss = NULL;
2966 enum rx_mgmt_action rma = RX_MGMT_NONE; 3060 enum rx_mgmt_action rma = RX_MGMT_NONE;
3061 u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN];
2967 u16 fc; 3062 u16 fc;
2968 3063
2969 rx_status = (struct ieee80211_rx_status *) skb->cb; 3064 rx_status = (struct ieee80211_rx_status *) skb->cb;
@@ -2974,7 +3069,8 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
2974 3069
2975 switch (fc & IEEE80211_FCTL_STYPE) { 3070 switch (fc & IEEE80211_FCTL_STYPE) {
2976 case IEEE80211_STYPE_BEACON: 3071 case IEEE80211_STYPE_BEACON:
2977 ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); 3072 rma = ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
3073 deauth_buf, rx_status);
2978 break; 3074 break;
2979 case IEEE80211_STYPE_PROBE_RESP: 3075 case IEEE80211_STYPE_PROBE_RESP:
2980 ieee80211_rx_mgmt_probe_resp(sdata, skb); 3076 ieee80211_rx_mgmt_probe_resp(sdata, skb);
@@ -3023,6 +3119,10 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
3023 case RX_MGMT_CFG80211_ASSOC_TIMEOUT: 3119 case RX_MGMT_CFG80211_ASSOC_TIMEOUT:
3024 cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid); 3120 cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid);
3025 break; 3121 break;
3122 case RX_MGMT_CFG80211_TX_DEAUTH:
3123 cfg80211_send_deauth(sdata->dev, deauth_buf,
3124 sizeof(deauth_buf));
3125 break;
3026 default: 3126 default:
3027 WARN(1, "unexpected: %d", rma); 3127 WARN(1, "unexpected: %d", rma);
3028 } 3128 }
@@ -3620,7 +3720,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
3620 ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, 3720 ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
3621 cbss->channel, 3721 cbss->channel,
3622 ht_oper, vht_oper, 3722 ht_oper, vht_oper,
3623 &chandef); 3723 &chandef, true);
3624 3724
3625 sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), 3725 sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss),
3626 local->rx_chains); 3726 local->rx_chains);