aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-03-25 13:29:27 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-04-16 09:29:44 -0400
commit85220d71bf3ca1ba9129e0744247ae5f61bec559 (patch)
tree5bdabc71bc5da27ee71fb1272b86809ac2f95b0d /net/mac80211/mlme.c
parentb4f286a1c0ad0b84c2d502b354d4d98d5a86c64b (diff)
mac80211: support secondary channel offset in CSA
Add support for the secondary channel offset IE in channel switch announcements. This is necessary for proper handling of CSA on HT access points. For this to work it is also necessary to convert everything here to use chandef structs instead of just channels. The driver updates aren't really correct though. In particular, the TI wl18xx driver update can't possibly be right since it just ignores the new channel width for lack of firmware API. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c71
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