aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
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);