diff options
-rw-r--r-- | net/mac80211/mlme.c | 28 |
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 | ||
1016 | static void | 1016 | static void |
1017 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 1017 | ieee80211_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 | } |