diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/ibss.c | 22 | ||||
-rw-r--r-- | net/mac80211/main.c | 28 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 4 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 70 | ||||
-rw-r--r-- | net/mac80211/rx.c | 1 | ||||
-rw-r--r-- | net/mac80211/tx.c | 54 | ||||
-rw-r--r-- | net/mac80211/util.c | 11 |
7 files changed, 141 insertions, 49 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 6449a1c2283b..f0f5fedb8caa 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -947,8 +947,8 @@ static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, | |||
947 | if (len < IEEE80211_DEAUTH_FRAME_LEN) | 947 | if (len < IEEE80211_DEAUTH_FRAME_LEN) |
948 | return; | 948 | return; |
949 | 949 | ||
950 | ibss_dbg(sdata, "RX DeAuth SA=%pM DA=%pM BSSID=%pM (reason: %d)\n", | 950 | ibss_dbg(sdata, "RX DeAuth SA=%pM DA=%pM\n", mgmt->sa, mgmt->da); |
951 | mgmt->sa, mgmt->da, mgmt->bssid, reason); | 951 | ibss_dbg(sdata, "\tBSSID=%pM (reason: %d)\n", mgmt->bssid, reason); |
952 | sta_info_destroy_addr(sdata, mgmt->sa); | 952 | sta_info_destroy_addr(sdata, mgmt->sa); |
953 | } | 953 | } |
954 | 954 | ||
@@ -966,9 +966,9 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
966 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | 966 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); |
967 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | 967 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); |
968 | 968 | ||
969 | ibss_dbg(sdata, | 969 | ibss_dbg(sdata, "RX Auth SA=%pM DA=%pM\n", mgmt->sa, mgmt->da); |
970 | "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", | 970 | ibss_dbg(sdata, "\tBSSID=%pM (auth_transaction=%d)\n", |
971 | mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); | 971 | mgmt->bssid, auth_transaction); |
972 | 972 | ||
973 | if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) | 973 | if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) |
974 | return; | 974 | return; |
@@ -1175,10 +1175,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1175 | rx_timestamp = drv_get_tsf(local, sdata); | 1175 | rx_timestamp = drv_get_tsf(local, sdata); |
1176 | } | 1176 | } |
1177 | 1177 | ||
1178 | ibss_dbg(sdata, | 1178 | ibss_dbg(sdata, "RX beacon SA=%pM BSSID=%pM TSF=0x%llx\n", |
1179 | "RX beacon SA=%pM BSSID=%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", | ||
1180 | mgmt->sa, mgmt->bssid, | 1179 | mgmt->sa, mgmt->bssid, |
1181 | (unsigned long long)rx_timestamp, | 1180 | (unsigned long long)rx_timestamp); |
1181 | ibss_dbg(sdata, "\tBCN=0x%llx diff=%lld @%lu\n", | ||
1182 | (unsigned long long)beacon_timestamp, | 1182 | (unsigned long long)beacon_timestamp, |
1183 | (unsigned long long)(rx_timestamp - beacon_timestamp), | 1183 | (unsigned long long)(rx_timestamp - beacon_timestamp), |
1184 | jiffies); | 1184 | jiffies); |
@@ -1537,9 +1537,9 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1537 | 1537 | ||
1538 | tx_last_beacon = drv_tx_last_beacon(local); | 1538 | tx_last_beacon = drv_tx_last_beacon(local); |
1539 | 1539 | ||
1540 | ibss_dbg(sdata, | 1540 | ibss_dbg(sdata, "RX ProbeReq SA=%pM DA=%pM\n", mgmt->sa, mgmt->da); |
1541 | "RX ProbeReq SA=%pM DA=%pM BSSID=%pM (tx_last_beacon=%d)\n", | 1541 | ibss_dbg(sdata, "\tBSSID=%pM (tx_last_beacon=%d)\n", |
1542 | mgmt->sa, mgmt->da, mgmt->bssid, tx_last_beacon); | 1542 | mgmt->bssid, tx_last_beacon); |
1543 | 1543 | ||
1544 | if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da)) | 1544 | if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da)) |
1545 | return; | 1545 | return; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 4fb2709cb527..513627896204 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -256,8 +256,27 @@ static void ieee80211_restart_work(struct work_struct *work) | |||
256 | 256 | ||
257 | flush_work(&local->radar_detected_work); | 257 | flush_work(&local->radar_detected_work); |
258 | rtnl_lock(); | 258 | rtnl_lock(); |
259 | list_for_each_entry(sdata, &local->interfaces, list) | 259 | list_for_each_entry(sdata, &local->interfaces, list) { |
260 | /* | ||
261 | * XXX: there may be more work for other vif types and even | ||
262 | * for station mode: a good thing would be to run most of | ||
263 | * the iface type's dependent _stop (ieee80211_mg_stop, | ||
264 | * ieee80211_ibss_stop) etc... | ||
265 | * For now, fix only the specific bug that was seen: race | ||
266 | * between csa_connection_drop_work and us. | ||
267 | */ | ||
268 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
269 | /* | ||
270 | * This worker is scheduled from the iface worker that | ||
271 | * runs on mac80211's workqueue, so we can't be | ||
272 | * scheduling this worker after the cancel right here. | ||
273 | * The exception is ieee80211_chswitch_done. | ||
274 | * Then we can have a race... | ||
275 | */ | ||
276 | cancel_work_sync(&sdata->u.mgd.csa_connection_drop_work); | ||
277 | } | ||
260 | flush_delayed_work(&sdata->dec_tailroom_needed_wk); | 278 | flush_delayed_work(&sdata->dec_tailroom_needed_wk); |
279 | } | ||
261 | ieee80211_scan_cancel(local); | 280 | ieee80211_scan_cancel(local); |
262 | 281 | ||
263 | /* make sure any new ROC will consider local->in_reconfig */ | 282 | /* make sure any new ROC will consider local->in_reconfig */ |
@@ -471,10 +490,7 @@ static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = { | |||
471 | cpu_to_le32(IEEE80211_VHT_CAP_RXLDPC | | 490 | cpu_to_le32(IEEE80211_VHT_CAP_RXLDPC | |
472 | IEEE80211_VHT_CAP_SHORT_GI_80 | | 491 | IEEE80211_VHT_CAP_SHORT_GI_80 | |
473 | IEEE80211_VHT_CAP_SHORT_GI_160 | | 492 | IEEE80211_VHT_CAP_SHORT_GI_160 | |
474 | IEEE80211_VHT_CAP_RXSTBC_1 | | 493 | IEEE80211_VHT_CAP_RXSTBC_MASK | |
475 | IEEE80211_VHT_CAP_RXSTBC_2 | | ||
476 | IEEE80211_VHT_CAP_RXSTBC_3 | | ||
477 | IEEE80211_VHT_CAP_RXSTBC_4 | | ||
478 | IEEE80211_VHT_CAP_TXSTBC | | 494 | IEEE80211_VHT_CAP_TXSTBC | |
479 | IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | | 495 | IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | |
480 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | | 496 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | |
@@ -1208,6 +1224,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
1208 | #if IS_ENABLED(CONFIG_IPV6) | 1224 | #if IS_ENABLED(CONFIG_IPV6) |
1209 | unregister_inet6addr_notifier(&local->ifa6_notifier); | 1225 | unregister_inet6addr_notifier(&local->ifa6_notifier); |
1210 | #endif | 1226 | #endif |
1227 | ieee80211_txq_teardown_flows(local); | ||
1211 | 1228 | ||
1212 | rtnl_lock(); | 1229 | rtnl_lock(); |
1213 | 1230 | ||
@@ -1236,7 +1253,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
1236 | skb_queue_purge(&local->skb_queue); | 1253 | skb_queue_purge(&local->skb_queue); |
1237 | skb_queue_purge(&local->skb_queue_unreliable); | 1254 | skb_queue_purge(&local->skb_queue_unreliable); |
1238 | skb_queue_purge(&local->skb_queue_tdls_chsw); | 1255 | skb_queue_purge(&local->skb_queue_tdls_chsw); |
1239 | ieee80211_txq_teardown_flows(local); | ||
1240 | 1256 | ||
1241 | destroy_workqueue(local->workqueue); | 1257 | destroy_workqueue(local->workqueue); |
1242 | wiphy_unregister(local->hw.wiphy); | 1258 | wiphy_unregister(local->hw.wiphy); |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 35ad3983ae4b..daf9db3c8f24 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -572,6 +572,10 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
572 | forward = false; | 572 | forward = false; |
573 | reply = true; | 573 | reply = true; |
574 | target_metric = 0; | 574 | target_metric = 0; |
575 | |||
576 | if (SN_GT(target_sn, ifmsh->sn)) | ||
577 | ifmsh->sn = target_sn; | ||
578 | |||
575 | if (time_after(jiffies, ifmsh->last_sn_update + | 579 | if (time_after(jiffies, ifmsh->last_sn_update + |
576 | net_traversal_jiffies(sdata)) || | 580 | net_traversal_jiffies(sdata)) || |
577 | time_before(jiffies, ifmsh->last_sn_update)) { | 581 | time_before(jiffies, ifmsh->last_sn_update)) { |
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); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 64742f2765c4..96611d5dfadb 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1728,6 +1728,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1728 | */ | 1728 | */ |
1729 | if (!ieee80211_hw_check(&sta->local->hw, AP_LINK_PS) && | 1729 | if (!ieee80211_hw_check(&sta->local->hw, AP_LINK_PS) && |
1730 | !ieee80211_has_morefrags(hdr->frame_control) && | 1730 | !ieee80211_has_morefrags(hdr->frame_control) && |
1731 | !is_multicast_ether_addr(hdr->addr1) && | ||
1731 | (ieee80211_is_mgmt(hdr->frame_control) || | 1732 | (ieee80211_is_mgmt(hdr->frame_control) || |
1732 | ieee80211_is_data(hdr->frame_control)) && | 1733 | ieee80211_is_data(hdr->frame_control)) && |
1733 | !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && | 1734 | !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index cd332e3e1134..f353d9db54bc 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -3078,27 +3078,18 @@ void ieee80211_clear_fast_xmit(struct sta_info *sta) | |||
3078 | } | 3078 | } |
3079 | 3079 | ||
3080 | static bool ieee80211_amsdu_realloc_pad(struct ieee80211_local *local, | 3080 | static bool ieee80211_amsdu_realloc_pad(struct ieee80211_local *local, |
3081 | struct sk_buff *skb, int headroom, | 3081 | struct sk_buff *skb, int headroom) |
3082 | int *subframe_len) | ||
3083 | { | 3082 | { |
3084 | int amsdu_len = *subframe_len + sizeof(struct ethhdr); | 3083 | if (skb_headroom(skb) < headroom) { |
3085 | int padding = (4 - amsdu_len) & 3; | ||
3086 | |||
3087 | if (skb_headroom(skb) < headroom || skb_tailroom(skb) < padding) { | ||
3088 | I802_DEBUG_INC(local->tx_expand_skb_head); | 3084 | I802_DEBUG_INC(local->tx_expand_skb_head); |
3089 | 3085 | ||
3090 | if (pskb_expand_head(skb, headroom, padding, GFP_ATOMIC)) { | 3086 | if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { |
3091 | wiphy_debug(local->hw.wiphy, | 3087 | wiphy_debug(local->hw.wiphy, |
3092 | "failed to reallocate TX buffer\n"); | 3088 | "failed to reallocate TX buffer\n"); |
3093 | return false; | 3089 | return false; |
3094 | } | 3090 | } |
3095 | } | 3091 | } |
3096 | 3092 | ||
3097 | if (padding) { | ||
3098 | *subframe_len += padding; | ||
3099 | skb_put_zero(skb, padding); | ||
3100 | } | ||
3101 | |||
3102 | return true; | 3093 | return true; |
3103 | } | 3094 | } |
3104 | 3095 | ||
@@ -3122,8 +3113,7 @@ static bool ieee80211_amsdu_prepare_head(struct ieee80211_sub_if_data *sdata, | |||
3122 | if (info->control.flags & IEEE80211_TX_CTRL_AMSDU) | 3113 | if (info->control.flags & IEEE80211_TX_CTRL_AMSDU) |
3123 | return true; | 3114 | return true; |
3124 | 3115 | ||
3125 | if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(*amsdu_hdr), | 3116 | if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(*amsdu_hdr))) |
3126 | &subframe_len)) | ||
3127 | return false; | 3117 | return false; |
3128 | 3118 | ||
3129 | data = skb_push(skb, sizeof(*amsdu_hdr)); | 3119 | data = skb_push(skb, sizeof(*amsdu_hdr)); |
@@ -3189,7 +3179,8 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata, | |||
3189 | void *data; | 3179 | void *data; |
3190 | bool ret = false; | 3180 | bool ret = false; |
3191 | unsigned int orig_len; | 3181 | unsigned int orig_len; |
3192 | int n = 1, nfrags; | 3182 | int n = 2, nfrags, pad = 0; |
3183 | u16 hdrlen; | ||
3193 | 3184 | ||
3194 | if (!ieee80211_hw_check(&local->hw, TX_AMSDU)) | 3185 | if (!ieee80211_hw_check(&local->hw, TX_AMSDU)) |
3195 | return false; | 3186 | return false; |
@@ -3222,9 +3213,6 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata, | |||
3222 | if (skb->len + head->len > max_amsdu_len) | 3213 | if (skb->len + head->len > max_amsdu_len) |
3223 | goto out; | 3214 | goto out; |
3224 | 3215 | ||
3225 | if (!ieee80211_amsdu_prepare_head(sdata, fast_tx, head)) | ||
3226 | goto out; | ||
3227 | |||
3228 | nfrags = 1 + skb_shinfo(skb)->nr_frags; | 3216 | nfrags = 1 + skb_shinfo(skb)->nr_frags; |
3229 | nfrags += 1 + skb_shinfo(head)->nr_frags; | 3217 | nfrags += 1 + skb_shinfo(head)->nr_frags; |
3230 | frag_tail = &skb_shinfo(head)->frag_list; | 3218 | frag_tail = &skb_shinfo(head)->frag_list; |
@@ -3240,10 +3228,24 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata, | |||
3240 | if (max_frags && nfrags > max_frags) | 3228 | if (max_frags && nfrags > max_frags) |
3241 | goto out; | 3229 | goto out; |
3242 | 3230 | ||
3243 | if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) + 2, | 3231 | if (!ieee80211_amsdu_prepare_head(sdata, fast_tx, head)) |
3244 | &subframe_len)) | ||
3245 | goto out; | 3232 | goto out; |
3246 | 3233 | ||
3234 | /* | ||
3235 | * Pad out the previous subframe to a multiple of 4 by adding the | ||
3236 | * padding to the next one, that's being added. Note that head->len | ||
3237 | * is the length of the full A-MSDU, but that works since each time | ||
3238 | * we add a new subframe we pad out the previous one to a multiple | ||
3239 | * of 4 and thus it no longer matters in the next round. | ||
3240 | */ | ||
3241 | hdrlen = fast_tx->hdr_len - sizeof(rfc1042_header); | ||
3242 | if ((head->len - hdrlen) & 3) | ||
3243 | pad = 4 - ((head->len - hdrlen) & 3); | ||
3244 | |||
3245 | if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) + | ||
3246 | 2 + pad)) | ||
3247 | goto out_recalc; | ||
3248 | |||
3247 | ret = true; | 3249 | ret = true; |
3248 | data = skb_push(skb, ETH_ALEN + 2); | 3250 | data = skb_push(skb, ETH_ALEN + 2); |
3249 | memmove(data, data + ETH_ALEN + 2, 2 * ETH_ALEN); | 3251 | memmove(data, data + ETH_ALEN + 2, 2 * ETH_ALEN); |
@@ -3253,15 +3255,19 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata, | |||
3253 | memcpy(data, &len, 2); | 3255 | memcpy(data, &len, 2); |
3254 | memcpy(data + 2, rfc1042_header, sizeof(rfc1042_header)); | 3256 | memcpy(data + 2, rfc1042_header, sizeof(rfc1042_header)); |
3255 | 3257 | ||
3258 | memset(skb_push(skb, pad), 0, pad); | ||
3259 | |||
3256 | head->len += skb->len; | 3260 | head->len += skb->len; |
3257 | head->data_len += skb->len; | 3261 | head->data_len += skb->len; |
3258 | *frag_tail = skb; | 3262 | *frag_tail = skb; |
3259 | 3263 | ||
3260 | flow->backlog += head->len - orig_len; | 3264 | out_recalc: |
3261 | tin->backlog_bytes += head->len - orig_len; | 3265 | if (head->len != orig_len) { |
3262 | 3266 | flow->backlog += head->len - orig_len; | |
3263 | fq_recalc_backlog(fq, tin, flow); | 3267 | tin->backlog_bytes += head->len - orig_len; |
3264 | 3268 | ||
3269 | fq_recalc_backlog(fq, tin, flow); | ||
3270 | } | ||
3265 | out: | 3271 | out: |
3266 | spin_unlock_bh(&fq->lock); | 3272 | spin_unlock_bh(&fq->lock); |
3267 | 3273 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 88efda7c9f8a..716cd6442d86 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1135,7 +1135,7 @@ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata, | |||
1135 | { | 1135 | { |
1136 | struct ieee80211_chanctx_conf *chanctx_conf; | 1136 | struct ieee80211_chanctx_conf *chanctx_conf; |
1137 | const struct ieee80211_reg_rule *rrule; | 1137 | const struct ieee80211_reg_rule *rrule; |
1138 | struct ieee80211_wmm_ac *wmm_ac; | 1138 | const struct ieee80211_wmm_ac *wmm_ac; |
1139 | u16 center_freq = 0; | 1139 | u16 center_freq = 0; |
1140 | 1140 | ||
1141 | if (sdata->vif.type != NL80211_IFTYPE_AP && | 1141 | if (sdata->vif.type != NL80211_IFTYPE_AP && |
@@ -1154,20 +1154,19 @@ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata, | |||
1154 | 1154 | ||
1155 | rrule = freq_reg_info(sdata->wdev.wiphy, MHZ_TO_KHZ(center_freq)); | 1155 | rrule = freq_reg_info(sdata->wdev.wiphy, MHZ_TO_KHZ(center_freq)); |
1156 | 1156 | ||
1157 | if (IS_ERR_OR_NULL(rrule) || !rrule->wmm_rule) { | 1157 | if (IS_ERR_OR_NULL(rrule) || !rrule->has_wmm) { |
1158 | rcu_read_unlock(); | 1158 | rcu_read_unlock(); |
1159 | return; | 1159 | return; |
1160 | } | 1160 | } |
1161 | 1161 | ||
1162 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 1162 | if (sdata->vif.type == NL80211_IFTYPE_AP) |
1163 | wmm_ac = &rrule->wmm_rule->ap[ac]; | 1163 | wmm_ac = &rrule->wmm_rule.ap[ac]; |
1164 | else | 1164 | else |
1165 | wmm_ac = &rrule->wmm_rule->client[ac]; | 1165 | wmm_ac = &rrule->wmm_rule.client[ac]; |
1166 | qparam->cw_min = max_t(u16, qparam->cw_min, wmm_ac->cw_min); | 1166 | qparam->cw_min = max_t(u16, qparam->cw_min, wmm_ac->cw_min); |
1167 | qparam->cw_max = max_t(u16, qparam->cw_max, wmm_ac->cw_max); | 1167 | qparam->cw_max = max_t(u16, qparam->cw_max, wmm_ac->cw_max); |
1168 | qparam->aifs = max_t(u8, qparam->aifs, wmm_ac->aifsn); | 1168 | qparam->aifs = max_t(u8, qparam->aifs, wmm_ac->aifsn); |
1169 | qparam->txop = !qparam->txop ? wmm_ac->cot / 32 : | 1169 | qparam->txop = min_t(u16, qparam->txop, wmm_ac->cot / 32); |
1170 | min_t(u16, qparam->txop, wmm_ac->cot / 32); | ||
1171 | rcu_read_unlock(); | 1170 | rcu_read_unlock(); |
1172 | } | 1171 | } |
1173 | 1172 | ||