diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 70 |
1 files changed, 68 insertions, 2 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7fb9957359a3..3dbecae4be73 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1073,6 +1073,10 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
1073 | */ | 1073 | */ |
1074 | 1074 | ||
1075 | if (sdata->reserved_chanctx) { | 1075 | if (sdata->reserved_chanctx) { |
1076 | struct ieee80211_supported_band *sband = NULL; | ||
1077 | struct sta_info *mgd_sta = NULL; | ||
1078 | enum ieee80211_sta_rx_bandwidth bw = IEEE80211_STA_RX_BW_20; | ||
1079 | |||
1076 | /* | 1080 | /* |
1077 | * with multi-vif csa driver may call ieee80211_csa_finish() | 1081 | * with multi-vif csa driver may call ieee80211_csa_finish() |
1078 | * many times while waiting for other interfaces to use their | 1082 | * many times while waiting for other interfaces to use their |
@@ -1081,6 +1085,48 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
1081 | if (sdata->reserved_ready) | 1085 | if (sdata->reserved_ready) |
1082 | goto out; | 1086 | goto out; |
1083 | 1087 | ||
1088 | if (sdata->vif.bss_conf.chandef.width != | ||
1089 | sdata->csa_chandef.width) { | ||
1090 | /* | ||
1091 | * For managed interface, we need to also update the AP | ||
1092 | * station bandwidth and align the rate scale algorithm | ||
1093 | * on the bandwidth change. Here we only consider the | ||
1094 | * bandwidth of the new channel definition (as channel | ||
1095 | * switch flow does not have the full HT/VHT/HE | ||
1096 | * information), assuming that if additional changes are | ||
1097 | * required they would be done as part of the processing | ||
1098 | * of the next beacon from the AP. | ||
1099 | */ | ||
1100 | switch (sdata->csa_chandef.width) { | ||
1101 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
1102 | case NL80211_CHAN_WIDTH_20: | ||
1103 | default: | ||
1104 | bw = IEEE80211_STA_RX_BW_20; | ||
1105 | break; | ||
1106 | case NL80211_CHAN_WIDTH_40: | ||
1107 | bw = IEEE80211_STA_RX_BW_40; | ||
1108 | break; | ||
1109 | case NL80211_CHAN_WIDTH_80: | ||
1110 | bw = IEEE80211_STA_RX_BW_80; | ||
1111 | break; | ||
1112 | case NL80211_CHAN_WIDTH_80P80: | ||
1113 | case NL80211_CHAN_WIDTH_160: | ||
1114 | bw = IEEE80211_STA_RX_BW_160; | ||
1115 | break; | ||
1116 | } | ||
1117 | |||
1118 | mgd_sta = sta_info_get(sdata, ifmgd->bssid); | ||
1119 | sband = | ||
1120 | local->hw.wiphy->bands[sdata->csa_chandef.chan->band]; | ||
1121 | } | ||
1122 | |||
1123 | if (sdata->vif.bss_conf.chandef.width > | ||
1124 | sdata->csa_chandef.width) { | ||
1125 | mgd_sta->sta.bandwidth = bw; | ||
1126 | rate_control_rate_update(local, sband, mgd_sta, | ||
1127 | IEEE80211_RC_BW_CHANGED); | ||
1128 | } | ||
1129 | |||
1084 | ret = ieee80211_vif_use_reserved_context(sdata); | 1130 | ret = ieee80211_vif_use_reserved_context(sdata); |
1085 | if (ret) { | 1131 | if (ret) { |
1086 | sdata_info(sdata, | 1132 | sdata_info(sdata, |
@@ -1091,6 +1137,13 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
1091 | goto out; | 1137 | goto out; |
1092 | } | 1138 | } |
1093 | 1139 | ||
1140 | if (sdata->vif.bss_conf.chandef.width < | ||
1141 | sdata->csa_chandef.width) { | ||
1142 | mgd_sta->sta.bandwidth = bw; | ||
1143 | rate_control_rate_update(local, sband, mgd_sta, | ||
1144 | IEEE80211_RC_BW_CHANGED); | ||
1145 | } | ||
1146 | |||
1094 | goto out; | 1147 | goto out; |
1095 | } | 1148 | } |
1096 | 1149 | ||
@@ -1312,6 +1365,16 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1312 | cbss->beacon_interval)); | 1365 | cbss->beacon_interval)); |
1313 | return; | 1366 | return; |
1314 | drop_connection: | 1367 | drop_connection: |
1368 | /* | ||
1369 | * This is just so that the disconnect flow will know that | ||
1370 | * we were trying to switch channel and failed. In case the | ||
1371 | * mode is 1 (we are not allowed to Tx), we will know not to | ||
1372 | * send a deauthentication frame. Those two fields will be | ||
1373 | * reset when the disconnection worker runs. | ||
1374 | */ | ||
1375 | sdata->vif.csa_active = true; | ||
1376 | sdata->csa_block_tx = csa_ie.mode; | ||
1377 | |||
1315 | ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work); | 1378 | ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work); |
1316 | mutex_unlock(&local->chanctx_mtx); | 1379 | mutex_unlock(&local->chanctx_mtx); |
1317 | mutex_unlock(&local->mtx); | 1380 | mutex_unlock(&local->mtx); |
@@ -2522,6 +2585,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2522 | struct ieee80211_local *local = sdata->local; | 2585 | struct ieee80211_local *local = sdata->local; |
2523 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2586 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2524 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 2587 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
2588 | bool tx; | ||
2525 | 2589 | ||
2526 | sdata_lock(sdata); | 2590 | sdata_lock(sdata); |
2527 | if (!ifmgd->associated) { | 2591 | if (!ifmgd->associated) { |
@@ -2529,6 +2593,8 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2529 | return; | 2593 | return; |
2530 | } | 2594 | } |
2531 | 2595 | ||
2596 | tx = !sdata->csa_block_tx; | ||
2597 | |||
2532 | /* AP is probably out of range (or not reachable for another reason) so | 2598 | /* AP is probably out of range (or not reachable for another reason) so |
2533 | * remove the bss struct for that AP. | 2599 | * remove the bss struct for that AP. |
2534 | */ | 2600 | */ |
@@ -2536,7 +2602,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2536 | 2602 | ||
2537 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 2603 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
2538 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 2604 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
2539 | true, frame_buf); | 2605 | tx, frame_buf); |
2540 | mutex_lock(&local->mtx); | 2606 | mutex_lock(&local->mtx); |
2541 | sdata->vif.csa_active = false; | 2607 | sdata->vif.csa_active = false; |
2542 | ifmgd->csa_waiting_bcn = false; | 2608 | ifmgd->csa_waiting_bcn = false; |
@@ -2547,7 +2613,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2547 | } | 2613 | } |
2548 | mutex_unlock(&local->mtx); | 2614 | mutex_unlock(&local->mtx); |
2549 | 2615 | ||
2550 | ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, | 2616 | ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), tx, |
2551 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); | 2617 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); |
2552 | 2618 | ||
2553 | sdata_unlock(sdata); | 2619 | sdata_unlock(sdata); |