aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/mlme.c28
1 files changed, 22 insertions, 6 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 8a948ca55d80..d87d3f1a2f94 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1015,7 +1015,8 @@ static void ieee80211_chswitch_timer(unsigned long data)
1015 1015
1016static void 1016static void
1017ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, 1017ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1018 u64 timestamp, struct ieee802_11_elems *elems) 1018 u64 timestamp, struct ieee802_11_elems *elems,
1019 bool beacon)
1019{ 1020{
1020 struct ieee80211_local *local = sdata->local; 1021 struct ieee80211_local *local = sdata->local;
1021 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 1022 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -1032,6 +1033,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1032 struct cfg80211_chan_def new_vht_chandef = {}; 1033 struct cfg80211_chan_def new_vht_chandef = {};
1033 const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; 1034 const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
1034 const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; 1035 const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
1036 const struct ieee80211_ht_operation *ht_oper;
1035 int secondary_channel_offset = -1; 1037 int secondary_channel_offset = -1;
1036 1038
1037 ASSERT_MGD_MTX(ifmgd); 1039 ASSERT_MGD_MTX(ifmgd);
@@ -1048,11 +1050,14 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1048 1050
1049 sec_chan_offs = elems->sec_chan_offs; 1051 sec_chan_offs = elems->sec_chan_offs;
1050 wide_bw_chansw_ie = elems->wide_bw_chansw_ie; 1052 wide_bw_chansw_ie = elems->wide_bw_chansw_ie;
1053 ht_oper = elems->ht_operation;
1051 1054
1052 if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT | 1055 if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
1053 IEEE80211_STA_DISABLE_40MHZ)) { 1056 IEEE80211_STA_DISABLE_40MHZ)) {
1054 sec_chan_offs = NULL; 1057 sec_chan_offs = NULL;
1055 wide_bw_chansw_ie = NULL; 1058 wide_bw_chansw_ie = NULL;
1059 /* only used for bandwidth here */
1060 ht_oper = NULL;
1056 } 1061 }
1057 1062
1058 if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) 1063 if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
@@ -1094,10 +1099,20 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1094 return; 1099 return;
1095 } 1100 }
1096 1101
1097 if (sec_chan_offs) { 1102 if (!beacon && sec_chan_offs) {
1098 secondary_channel_offset = sec_chan_offs->sec_chan_offs; 1103 secondary_channel_offset = sec_chan_offs->sec_chan_offs;
1104 } else if (beacon && ht_oper) {
1105 secondary_channel_offset =
1106 ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
1099 } else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { 1107 } else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
1100 /* if HT is enabled and the IE not present, it's still HT */ 1108 /*
1109 * If it's not a beacon, HT is enabled and the IE not present,
1110 * it's 20 MHz, 802.11-2012 8.5.2.6:
1111 * This element [the Secondary Channel Offset Element] is
1112 * present when switching to a 40 MHz channel. It may be
1113 * present when switching to a 20 MHz channel (in which
1114 * case the secondary channel offset is set to SCN).
1115 */
1101 secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; 1116 secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
1102 } 1117 }
1103 1118
@@ -2796,7 +2811,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
2796 mutex_unlock(&local->iflist_mtx); 2811 mutex_unlock(&local->iflist_mtx);
2797 } 2812 }
2798 2813
2799 ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, elems); 2814 ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
2815 elems, true);
2800 2816
2801} 2817}
2802 2818
@@ -3210,7 +3226,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
3210 3226
3211 ieee80211_sta_process_chanswitch(sdata, 3227 ieee80211_sta_process_chanswitch(sdata,
3212 rx_status->mactime, 3228 rx_status->mactime,
3213 &elems); 3229 &elems, false);
3214 } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { 3230 } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
3215 ies_len = skb->len - 3231 ies_len = skb->len -
3216 offsetof(struct ieee80211_mgmt, 3232 offsetof(struct ieee80211_mgmt,
@@ -3232,7 +3248,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
3232 3248
3233 ieee80211_sta_process_chanswitch(sdata, 3249 ieee80211_sta_process_chanswitch(sdata,
3234 rx_status->mactime, 3250 rx_status->mactime,
3235 &elems); 3251 &elems, false);
3236 } 3252 }
3237 break; 3253 break;
3238 } 3254 }