diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 71 |
1 files changed, 56 insertions, 15 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index bc6f87edc624..bd581a80e4b7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -289,6 +289,8 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
289 | } else { | 289 | } else { |
290 | /* 40 MHz (and 80 MHz) must be supported for VHT */ | 290 | /* 40 MHz (and 80 MHz) must be supported for VHT */ |
291 | ret = IEEE80211_STA_DISABLE_VHT; | 291 | ret = IEEE80211_STA_DISABLE_VHT; |
292 | /* also mark 40 MHz disabled */ | ||
293 | ret |= IEEE80211_STA_DISABLE_40MHZ; | ||
292 | goto out; | 294 | goto out; |
293 | } | 295 | } |
294 | 296 | ||
@@ -964,16 +966,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
964 | if (!ifmgd->associated) | 966 | if (!ifmgd->associated) |
965 | goto out; | 967 | goto out; |
966 | 968 | ||
967 | /* | 969 | local->_oper_chandef = local->csa_chandef; |
968 | * FIXME: Here we are downgrading to NL80211_CHAN_WIDTH_20_NOHT | ||
969 | * and don't adjust our ht/vht settings | ||
970 | * This is wrong - we should behave according to the CSA params | ||
971 | */ | ||
972 | local->_oper_chandef.chan = local->csa_channel; | ||
973 | local->_oper_chandef.width = NL80211_CHAN_WIDTH_20_NOHT; | ||
974 | local->_oper_chandef.center_freq1 = | ||
975 | local->_oper_chandef.chan->center_freq; | ||
976 | local->_oper_chandef.center_freq2 = 0; | ||
977 | 970 | ||
978 | if (!local->ops->channel_switch) { | 971 | if (!local->ops->channel_switch) { |
979 | /* call "hw_config" only if doing sw channel switch */ | 972 | /* call "hw_config" only if doing sw channel switch */ |
@@ -1028,13 +1021,14 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1028 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1021 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1029 | struct cfg80211_bss *cbss = ifmgd->associated; | 1022 | struct cfg80211_bss *cbss = ifmgd->associated; |
1030 | struct ieee80211_bss *bss; | 1023 | struct ieee80211_bss *bss; |
1031 | struct ieee80211_channel *new_ch; | ||
1032 | struct ieee80211_chanctx *chanctx; | 1024 | struct ieee80211_chanctx *chanctx; |
1033 | enum ieee80211_band new_band; | 1025 | enum ieee80211_band new_band; |
1034 | int new_freq; | 1026 | int new_freq; |
1035 | u8 new_chan_no; | 1027 | u8 new_chan_no; |
1036 | u8 count; | 1028 | u8 count; |
1037 | u8 mode; | 1029 | u8 mode; |
1030 | struct cfg80211_chan_def new_chandef = {}; | ||
1031 | int secondary_channel_offset = -1; | ||
1038 | 1032 | ||
1039 | ASSERT_MGD_MTX(ifmgd); | 1033 | ASSERT_MGD_MTX(ifmgd); |
1040 | 1034 | ||
@@ -1048,6 +1042,19 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1048 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) | 1042 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) |
1049 | return; | 1043 | return; |
1050 | 1044 | ||
1045 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | ||
1046 | /* if HT is enabled and the IE not present, it's still HT */ | ||
1047 | secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
1048 | if (elems->sec_chan_offs) | ||
1049 | secondary_channel_offset = | ||
1050 | elems->sec_chan_offs->sec_chan_offs; | ||
1051 | } | ||
1052 | |||
1053 | if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ && | ||
1054 | (secondary_channel_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE || | ||
1055 | secondary_channel_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)) | ||
1056 | secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
1057 | |||
1051 | if (elems->ext_chansw_ie) { | 1058 | if (elems->ext_chansw_ie) { |
1052 | if (!ieee80211_operating_class_to_band( | 1059 | if (!ieee80211_operating_class_to_band( |
1053 | elems->ext_chansw_ie->new_operating_class, | 1060 | elems->ext_chansw_ie->new_operating_class, |
@@ -1074,8 +1081,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1074 | bss = (void *)cbss->priv; | 1081 | bss = (void *)cbss->priv; |
1075 | 1082 | ||
1076 | new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band); | 1083 | new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band); |
1077 | new_ch = ieee80211_get_channel(local->hw.wiphy, new_freq); | 1084 | new_chandef.chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); |
1078 | if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) { | 1085 | if (!new_chandef.chan || |
1086 | new_chandef.chan->flags & IEEE80211_CHAN_DISABLED) { | ||
1079 | sdata_info(sdata, | 1087 | sdata_info(sdata, |
1080 | "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", | 1088 | "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", |
1081 | ifmgd->associated->bssid, new_freq); | 1089 | ifmgd->associated->bssid, new_freq); |
@@ -1084,6 +1092,39 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1084 | return; | 1092 | return; |
1085 | } | 1093 | } |
1086 | 1094 | ||
1095 | switch (secondary_channel_offset) { | ||
1096 | default: | ||
1097 | /* secondary_channel_offset was present but is invalid */ | ||
1098 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | ||
1099 | cfg80211_chandef_create(&new_chandef, new_chandef.chan, | ||
1100 | NL80211_CHAN_HT20); | ||
1101 | break; | ||
1102 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
1103 | cfg80211_chandef_create(&new_chandef, new_chandef.chan, | ||
1104 | NL80211_CHAN_HT40PLUS); | ||
1105 | break; | ||
1106 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
1107 | cfg80211_chandef_create(&new_chandef, new_chandef.chan, | ||
1108 | NL80211_CHAN_HT40MINUS); | ||
1109 | break; | ||
1110 | case -1: | ||
1111 | cfg80211_chandef_create(&new_chandef, new_chandef.chan, | ||
1112 | NL80211_CHAN_NO_HT); | ||
1113 | break; | ||
1114 | } | ||
1115 | |||
1116 | if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef, | ||
1117 | IEEE80211_CHAN_DISABLED)) { | ||
1118 | sdata_info(sdata, | ||
1119 | "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", | ||
1120 | ifmgd->associated->bssid, new_freq, | ||
1121 | new_chandef.width, new_chandef.center_freq1, | ||
1122 | new_chandef.center_freq2); | ||
1123 | ieee80211_queue_work(&local->hw, | ||
1124 | &ifmgd->csa_connection_drop_work); | ||
1125 | return; | ||
1126 | } | ||
1127 | |||
1087 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | 1128 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; |
1088 | 1129 | ||
1089 | if (local->use_chanctx) { | 1130 | if (local->use_chanctx) { |
@@ -1111,7 +1152,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1111 | } | 1152 | } |
1112 | mutex_unlock(&local->chanctx_mtx); | 1153 | mutex_unlock(&local->chanctx_mtx); |
1113 | 1154 | ||
1114 | local->csa_channel = new_ch; | 1155 | local->csa_chandef = new_chandef; |
1115 | 1156 | ||
1116 | if (mode) | 1157 | if (mode) |
1117 | ieee80211_stop_queues_by_reason(&local->hw, | 1158 | ieee80211_stop_queues_by_reason(&local->hw, |
@@ -1123,7 +1164,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1123 | struct ieee80211_channel_switch ch_switch = { | 1164 | struct ieee80211_channel_switch ch_switch = { |
1124 | .timestamp = timestamp, | 1165 | .timestamp = timestamp, |
1125 | .block_tx = mode, | 1166 | .block_tx = mode, |
1126 | .channel = new_ch, | 1167 | .chandef = new_chandef, |
1127 | .count = count, | 1168 | .count = count, |
1128 | }; | 1169 | }; |
1129 | 1170 | ||