blob: 757443d906b584020541388a8f702f15d9941ff9 [file] [log] [blame]
Johannes Berg2295c662010-10-23 09:15:41 -07001/******************************************************************************
2 *
Wey-Yi Guyfb4961d2012-01-06 13:16:33 -08003 * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
Johannes Berg2295c662010-10-23 09:15:41 -07004 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17 *
18 * The full GNU General Public License is included in this distribution in the
19 * file called LICENSE.
20 *
21 * Contact Information:
22 * Intel Linux Wireless <ilw@linux.intel.com>
23 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24 *
25 *****************************************************************************/
26
27#include "iwl-dev.h"
28#include "iwl-agn.h"
Johannes Berg2295c662010-10-23 09:15:41 -070029#include "iwl-core.h"
30#include "iwl-agn-calib.h"
Emmanuel Grumbachbdfbf092011-07-08 08:46:16 -070031#include "iwl-trans.h"
Emmanuel Grumbach48f20d32011-08-25 23:10:36 -070032#include "iwl-shared.h"
Johannes Berg2295c662010-10-23 09:15:41 -070033
34static int iwlagn_disable_bss(struct iwl_priv *priv,
35 struct iwl_rxon_context *ctx,
36 struct iwl_rxon_cmd *send)
37{
38 __le32 old_filter = send->filter_flags;
39 int ret;
40
41 send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
Johannes Berge10a0532012-03-06 13:30:39 -080042 ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd,
Emmanuel Grumbache419d622011-07-08 08:46:14 -070043 CMD_SYNC, sizeof(*send), send);
Johannes Berg2295c662010-10-23 09:15:41 -070044
45 send->filter_flags = old_filter;
46
47 if (ret)
Todd Previteb36b1102011-11-10 06:55:02 -080048 IWL_DEBUG_QUIET_RFKILL(priv,
49 "Error clearing ASSOC_MSK on BSS (%d)\n", ret);
Johannes Berg2295c662010-10-23 09:15:41 -070050
51 return ret;
52}
53
54static int iwlagn_disable_pan(struct iwl_priv *priv,
55 struct iwl_rxon_context *ctx,
56 struct iwl_rxon_cmd *send)
57{
Johannes Berg311dce72011-01-04 16:22:01 -080058 struct iwl_notification_wait disable_wait;
Johannes Berg2295c662010-10-23 09:15:41 -070059 __le32 old_filter = send->filter_flags;
60 u8 old_dev_type = send->dev_type;
61 int ret;
Johannes Bergdb662d42012-03-15 13:26:44 -070062 static const u8 deactivate_cmd[] = {
63 REPLY_WIPAN_DEACTIVATION_COMPLETE
64 };
Johannes Berg2295c662010-10-23 09:15:41 -070065
Johannes Berg4bd14dd2012-03-06 13:30:58 -080066 iwl_init_notification_wait(&priv->notif_wait, &disable_wait,
Johannes Bergdb662d42012-03-15 13:26:44 -070067 deactivate_cmd, ARRAY_SIZE(deactivate_cmd),
Johannes Berg4bd14dd2012-03-06 13:30:58 -080068 NULL, NULL);
Johannes Berg311dce72011-01-04 16:22:01 -080069
Johannes Berg2295c662010-10-23 09:15:41 -070070 send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
71 send->dev_type = RXON_DEV_TYPE_P2P;
Johannes Berge10a0532012-03-06 13:30:39 -080072 ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd,
Emmanuel Grumbache419d622011-07-08 08:46:14 -070073 CMD_SYNC, sizeof(*send), send);
Johannes Berg2295c662010-10-23 09:15:41 -070074
75 send->filter_flags = old_filter;
76 send->dev_type = old_dev_type;
77
Johannes Berg311dce72011-01-04 16:22:01 -080078 if (ret) {
Johannes Berg2295c662010-10-23 09:15:41 -070079 IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
Johannes Berg4bd14dd2012-03-06 13:30:58 -080080 iwl_remove_notification(&priv->notif_wait, &disable_wait);
Johannes Berg311dce72011-01-04 16:22:01 -080081 } else {
Johannes Berg4bd14dd2012-03-06 13:30:58 -080082 ret = iwl_wait_notification(&priv->notif_wait,
83 &disable_wait, HZ);
Johannes Berga8674a12011-04-13 03:14:48 -070084 if (ret)
Johannes Berg311dce72011-01-04 16:22:01 -080085 IWL_ERR(priv, "Timed out waiting for PAN disable\n");
86 }
Johannes Berg2295c662010-10-23 09:15:41 -070087
88 return ret;
89}
90
Johannes Berg2b9253d2011-05-27 08:40:26 -070091static int iwlagn_disconn_pan(struct iwl_priv *priv,
92 struct iwl_rxon_context *ctx,
93 struct iwl_rxon_cmd *send)
94{
95 __le32 old_filter = send->filter_flags;
96 int ret;
97
98 send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
Johannes Berge10a0532012-03-06 13:30:39 -080099 ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
Emmanuel Grumbache419d622011-07-08 08:46:14 -0700100 sizeof(*send), send);
Johannes Berg2b9253d2011-05-27 08:40:26 -0700101
102 send->filter_flags = old_filter;
103
104 return ret;
105}
106
Shanyu Zhaof4115d42010-11-10 18:25:58 -0800107static void iwlagn_update_qos(struct iwl_priv *priv,
108 struct iwl_rxon_context *ctx)
109{
110 int ret;
111
112 if (!ctx->is_active)
113 return;
114
115 ctx->qos_data.def_qos_parm.qos_flags = 0;
116
117 if (ctx->qos_data.qos_active)
118 ctx->qos_data.def_qos_parm.qos_flags |=
119 QOS_PARAM_FLG_UPDATE_EDCA_MSK;
120
121 if (ctx->ht.enabled)
122 ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
123
Emmanuel Grumbach0dcf50c2011-11-10 06:55:23 -0800124 IWL_DEBUG_INFO(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
Shanyu Zhaof4115d42010-11-10 18:25:58 -0800125 ctx->qos_data.qos_active,
126 ctx->qos_data.def_qos_parm.qos_flags);
127
Johannes Berge10a0532012-03-06 13:30:39 -0800128 ret = iwl_dvm_send_cmd_pdu(priv, ctx->qos_cmd, CMD_SYNC,
Shanyu Zhaof4115d42010-11-10 18:25:58 -0800129 sizeof(struct iwl_qosparam_cmd),
130 &ctx->qos_data.def_qos_parm);
131 if (ret)
Todd Previteb36b1102011-11-10 06:55:02 -0800132 IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n");
Shanyu Zhaof4115d42010-11-10 18:25:58 -0800133}
134
Johannes Bergbd50a8ab2010-10-23 09:15:42 -0700135static int iwlagn_update_beacon(struct iwl_priv *priv,
136 struct ieee80211_vif *vif)
137{
Johannes Bergb1eea292012-03-06 13:30:42 -0800138 lockdep_assert_held(&priv->mutex);
Johannes Bergbd50a8ab2010-10-23 09:15:42 -0700139
140 dev_kfree_skb(priv->beacon_skb);
141 priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif);
142 if (!priv->beacon_skb)
143 return -ENOMEM;
144 return iwlagn_send_beacon_cmd(priv);
145}
146
Wey-Yi Guyc3f6e9c2011-04-19 16:52:57 -0700147static int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
148 struct iwl_rxon_context *ctx)
149{
150 int ret = 0;
Wey-Yi Guy89e746b2011-04-19 16:52:58 -0700151 struct iwl_rxon_assoc_cmd rxon_assoc;
Wey-Yi Guyc3f6e9c2011-04-19 16:52:57 -0700152 const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
153 const struct iwl_rxon_cmd *rxon2 = &ctx->active;
154
155 if ((rxon1->flags == rxon2->flags) &&
156 (rxon1->filter_flags == rxon2->filter_flags) &&
157 (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
158 (rxon1->ofdm_ht_single_stream_basic_rates ==
159 rxon2->ofdm_ht_single_stream_basic_rates) &&
160 (rxon1->ofdm_ht_dual_stream_basic_rates ==
161 rxon2->ofdm_ht_dual_stream_basic_rates) &&
162 (rxon1->ofdm_ht_triple_stream_basic_rates ==
163 rxon2->ofdm_ht_triple_stream_basic_rates) &&
164 (rxon1->acquisition_data == rxon2->acquisition_data) &&
165 (rxon1->rx_chain == rxon2->rx_chain) &&
166 (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
167 IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n");
168 return 0;
169 }
170
171 rxon_assoc.flags = ctx->staging.flags;
172 rxon_assoc.filter_flags = ctx->staging.filter_flags;
173 rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
174 rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
175 rxon_assoc.reserved1 = 0;
176 rxon_assoc.reserved2 = 0;
177 rxon_assoc.reserved3 = 0;
178 rxon_assoc.ofdm_ht_single_stream_basic_rates =
179 ctx->staging.ofdm_ht_single_stream_basic_rates;
180 rxon_assoc.ofdm_ht_dual_stream_basic_rates =
181 ctx->staging.ofdm_ht_dual_stream_basic_rates;
182 rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
183 rxon_assoc.ofdm_ht_triple_stream_basic_rates =
184 ctx->staging.ofdm_ht_triple_stream_basic_rates;
185 rxon_assoc.acquisition_data = ctx->staging.acquisition_data;
186
Johannes Berge10a0532012-03-06 13:30:39 -0800187 ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_assoc_cmd,
Emmanuel Grumbache419d622011-07-08 08:46:14 -0700188 CMD_ASYNC, sizeof(rxon_assoc), &rxon_assoc);
Wey-Yi Guyc3f6e9c2011-04-19 16:52:57 -0700189 return ret;
190}
191
Meenakshi Venkataramandff96c12012-03-15 13:26:59 -0700192static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
193{
194 u16 new_val;
195 u16 beacon_factor;
196
197 /*
198 * If mac80211 hasn't given us a beacon interval, program
199 * the default into the device (not checking this here
200 * would cause the adjustment below to return the maximum
201 * value, which may break PAN.)
202 */
203 if (!beacon_val)
204 return DEFAULT_BEACON_INTERVAL;
205
206 /*
207 * If the beacon interval we obtained from the peer
208 * is too large, we'll have to wake up more often
209 * (and in IBSS case, we'll beacon too much)
210 *
211 * For example, if max_beacon_val is 4096, and the
212 * requested beacon interval is 7000, we'll have to
213 * use 3500 to be able to wake up on the beacons.
214 *
215 * This could badly influence beacon detection stats.
216 */
217
218 beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val;
219 new_val = beacon_val / beacon_factor;
220
221 if (!new_val)
222 new_val = max_beacon_val;
223
224 return new_val;
225}
226
227static int iwl_send_rxon_timing(struct iwl_priv *priv,
228 struct iwl_rxon_context *ctx)
229{
230 u64 tsf;
231 s32 interval_tm, rem;
232 struct ieee80211_conf *conf = NULL;
233 u16 beacon_int;
234 struct ieee80211_vif *vif = ctx->vif;
235
236 conf = &priv->hw->conf;
237
238 lockdep_assert_held(&priv->mutex);
239
240 memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd));
241
242 ctx->timing.timestamp = cpu_to_le64(priv->timestamp);
243 ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval);
244
245 beacon_int = vif ? vif->bss_conf.beacon_int : 0;
246
247 /*
248 * TODO: For IBSS we need to get atim_window from mac80211,
249 * for now just always use 0
250 */
251 ctx->timing.atim_window = 0;
252
253 if (ctx->ctxid == IWL_RXON_CTX_PAN &&
254 (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION) &&
255 iwl_is_associated(priv, IWL_RXON_CTX_BSS) &&
256 priv->contexts[IWL_RXON_CTX_BSS].vif &&
257 priv->contexts[IWL_RXON_CTX_BSS].vif->bss_conf.beacon_int) {
258 ctx->timing.beacon_interval =
259 priv->contexts[IWL_RXON_CTX_BSS].timing.beacon_interval;
260 beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
261 } else if (ctx->ctxid == IWL_RXON_CTX_BSS &&
262 iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
263 priv->contexts[IWL_RXON_CTX_PAN].vif &&
264 priv->contexts[IWL_RXON_CTX_PAN].vif->bss_conf.beacon_int &&
265 (!iwl_is_associated_ctx(ctx) || !ctx->vif ||
266 !ctx->vif->bss_conf.beacon_int)) {
267 ctx->timing.beacon_interval =
268 priv->contexts[IWL_RXON_CTX_PAN].timing.beacon_interval;
269 beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
270 } else {
271 beacon_int = iwl_adjust_beacon_interval(beacon_int,
272 IWL_MAX_UCODE_BEACON_INTERVAL * TIME_UNIT);
273 ctx->timing.beacon_interval = cpu_to_le16(beacon_int);
274 }
275
276 ctx->beacon_int = beacon_int;
277
278 tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
279 interval_tm = beacon_int * TIME_UNIT;
280 rem = do_div(tsf, interval_tm);
281 ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
282
283 ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1;
284
285 IWL_DEBUG_ASSOC(priv,
286 "beacon interval %d beacon timer %d beacon tim %d\n",
287 le16_to_cpu(ctx->timing.beacon_interval),
288 le32_to_cpu(ctx->timing.beacon_init_val),
289 le16_to_cpu(ctx->timing.atim_window));
290
291 return iwl_dvm_send_cmd_pdu(priv, ctx->rxon_timing_cmd,
292 CMD_SYNC, sizeof(ctx->timing), &ctx->timing);
293}
294
Wey-Yi Guyc1821c92011-04-19 16:52:59 -0700295static int iwlagn_rxon_disconn(struct iwl_priv *priv,
296 struct iwl_rxon_context *ctx)
297{
298 int ret;
299 struct iwl_rxon_cmd *active = (void *)&ctx->active;
300
Johannes Berg2b9253d2011-05-27 08:40:26 -0700301 if (ctx->ctxid == IWL_RXON_CTX_BSS) {
Wey-Yi Guyc1821c92011-04-19 16:52:59 -0700302 ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
Johannes Berg2b9253d2011-05-27 08:40:26 -0700303 } else {
Wey-Yi Guyc1821c92011-04-19 16:52:59 -0700304 ret = iwlagn_disable_pan(priv, ctx, &ctx->staging);
Johannes Berg2b9253d2011-05-27 08:40:26 -0700305 if (ret)
306 return ret;
307 if (ctx->vif) {
308 ret = iwl_send_rxon_timing(priv, ctx);
309 if (ret) {
310 IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
311 return ret;
312 }
313 ret = iwlagn_disconn_pan(priv, ctx, &ctx->staging);
314 }
315 }
Wey-Yi Guyc1821c92011-04-19 16:52:59 -0700316 if (ret)
317 return ret;
318
319 /*
320 * Un-assoc RXON clears the station table and WEP
321 * keys, so we have to restore those afterwards.
322 */
323 iwl_clear_ucode_stations(priv, ctx);
Johannes Bergf775aa06d2011-06-22 06:34:09 -0700324 /* update -- might need P2P now */
325 iwl_update_bcast_station(priv, ctx);
Wey-Yi Guyc1821c92011-04-19 16:52:59 -0700326 iwl_restore_stations(priv, ctx);
327 ret = iwl_restore_default_wep_keys(priv, ctx);
328 if (ret) {
329 IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
330 return ret;
331 }
332
333 memcpy(active, &ctx->staging, sizeof(*active));
334 return 0;
335}
336
337static int iwlagn_rxon_connect(struct iwl_priv *priv,
338 struct iwl_rxon_context *ctx)
339{
340 int ret;
341 struct iwl_rxon_cmd *active = (void *)&ctx->active;
342
343 /* RXON timing must be before associated RXON */
Johannes Berg2b9253d2011-05-27 08:40:26 -0700344 if (ctx->ctxid == IWL_RXON_CTX_BSS) {
345 ret = iwl_send_rxon_timing(priv, ctx);
346 if (ret) {
347 IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
348 return ret;
349 }
Wey-Yi Guyc1821c92011-04-19 16:52:59 -0700350 }
351 /* QoS info may be cleared by previous un-assoc RXON */
352 iwlagn_update_qos(priv, ctx);
353
354 /*
355 * We'll run into this code path when beaconing is
356 * enabled, but then we also need to send the beacon
357 * to the device.
358 */
359 if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) {
360 ret = iwlagn_update_beacon(priv, ctx->vif);
361 if (ret) {
362 IWL_ERR(priv,
363 "Error sending required beacon (%d)!\n",
364 ret);
365 return ret;
366 }
367 }
368
369 priv->start_calib = 0;
370 /*
371 * Apply the new configuration.
372 *
373 * Associated RXON doesn't clear the station table in uCode,
374 * so we don't need to restore stations etc. after this.
375 */
Johannes Berge10a0532012-03-06 13:30:39 -0800376 ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
Wey-Yi Guyc1821c92011-04-19 16:52:59 -0700377 sizeof(struct iwl_rxon_cmd), &ctx->staging);
378 if (ret) {
379 IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
380 return ret;
381 }
382 memcpy(active, &ctx->staging, sizeof(*active));
383
Wey-Yi Guyc1821c92011-04-19 16:52:59 -0700384 /* IBSS beacon needs to be sent after setting assoc */
385 if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC))
386 if (iwlagn_update_beacon(priv, ctx->vif))
387 IWL_ERR(priv, "Error sending IBSS beacon\n");
388 iwl_init_sensitivity(priv);
389
390 /*
391 * If we issue a new RXON command which required a tune then
392 * we must send a new TXPOWER command or we won't be able to
393 * Tx any frames.
394 *
395 * It's expected we set power here if channel is changing.
396 */
397 ret = iwl_set_tx_power(priv, priv->tx_power_next, true);
398 if (ret) {
399 IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
400 return ret;
401 }
Wey-Yi Guy15b3f3b2011-06-03 07:54:13 -0700402
Stanislaw Gruszka107ef972011-10-12 10:16:35 +0200403 if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
Don Fry38622412011-12-16 07:07:36 -0800404 cfg(priv)->ht_params && cfg(priv)->ht_params->smps_mode)
Wey-Yi Guy15b3f3b2011-06-03 07:54:13 -0700405 ieee80211_request_smps(ctx->vif,
Don Fry38622412011-12-16 07:07:36 -0800406 cfg(priv)->ht_params->smps_mode);
Wey-Yi Guy15b3f3b2011-06-03 07:54:13 -0700407
Wey-Yi Guyc1821c92011-04-19 16:52:59 -0700408 return 0;
409}
410
Wey-Yi Guye505c432011-07-07 08:27:41 -0700411int iwlagn_set_pan_params(struct iwl_priv *priv)
412{
413 struct iwl_wipan_params_cmd cmd;
414 struct iwl_rxon_context *ctx_bss, *ctx_pan;
415 int slot0 = 300, slot1 = 0;
416 int ret;
417
Johannes Berga18f61b2012-03-15 13:26:53 -0700418 if (priv->valid_contexts == BIT(IWL_RXON_CTX_BSS))
Wey-Yi Guye505c432011-07-07 08:27:41 -0700419 return 0;
420
421 BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
422
Johannes Bergb1eea292012-03-06 13:30:42 -0800423 lockdep_assert_held(&priv->mutex);
Wey-Yi Guye505c432011-07-07 08:27:41 -0700424
425 ctx_bss = &priv->contexts[IWL_RXON_CTX_BSS];
426 ctx_pan = &priv->contexts[IWL_RXON_CTX_PAN];
427
428 /*
429 * If the PAN context is inactive, then we don't need
430 * to update the PAN parameters, the last thing we'll
431 * have done before it goes inactive is making the PAN
432 * parameters be WLAN-only.
433 */
434 if (!ctx_pan->is_active)
435 return 0;
436
437 memset(&cmd, 0, sizeof(cmd));
438
439 /* only 2 slots are currently allowed */
440 cmd.num_slots = 2;
441
442 cmd.slots[0].type = 0; /* BSS */
443 cmd.slots[1].type = 1; /* PAN */
444
Johannes Bergc6baf7f2011-07-23 10:24:47 -0700445 if (priv->hw_roc_setup) {
Wey-Yi Guye505c432011-07-07 08:27:41 -0700446 /* both contexts must be used for this to happen */
Johannes Bergc6baf7f2011-07-23 10:24:47 -0700447 slot1 = IWL_MIN_SLOT_TIME;
448 slot0 = 3000;
Wey-Yi Guye505c432011-07-07 08:27:41 -0700449 } else if (ctx_bss->vif && ctx_pan->vif) {
Johannes Bergbbb05cb2011-07-18 01:59:22 -0700450 int bcnint = ctx_pan->beacon_int;
Wey-Yi Guye505c432011-07-07 08:27:41 -0700451 int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1;
452
453 /* should be set, but seems unused?? */
454 cmd.flags |= cpu_to_le16(IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE);
455
456 if (ctx_pan->vif->type == NL80211_IFTYPE_AP &&
457 bcnint &&
Johannes Bergbbb05cb2011-07-18 01:59:22 -0700458 bcnint != ctx_bss->beacon_int) {
Wey-Yi Guye505c432011-07-07 08:27:41 -0700459 IWL_ERR(priv,
460 "beacon intervals don't match (%d, %d)\n",
Johannes Bergbbb05cb2011-07-18 01:59:22 -0700461 ctx_bss->beacon_int, ctx_pan->beacon_int);
Wey-Yi Guye505c432011-07-07 08:27:41 -0700462 } else
463 bcnint = max_t(int, bcnint,
Johannes Bergbbb05cb2011-07-18 01:59:22 -0700464 ctx_bss->beacon_int);
Wey-Yi Guye505c432011-07-07 08:27:41 -0700465 if (!bcnint)
466 bcnint = DEFAULT_BEACON_INTERVAL;
467 slot0 = bcnint / 2;
468 slot1 = bcnint - slot0;
469
Don Fry83626402012-03-07 09:52:37 -0800470 if (test_bit(STATUS_SCAN_HW, &priv->status) ||
Wey-Yi Guye505c432011-07-07 08:27:41 -0700471 (!ctx_bss->vif->bss_conf.idle &&
472 !ctx_bss->vif->bss_conf.assoc)) {
473 slot0 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
474 slot1 = IWL_MIN_SLOT_TIME;
475 } else if (!ctx_pan->vif->bss_conf.idle &&
476 !ctx_pan->vif->bss_conf.assoc) {
Johannes Berg325a7dd2011-09-22 15:14:55 -0700477 slot1 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
Wey-Yi Guye505c432011-07-07 08:27:41 -0700478 slot0 = IWL_MIN_SLOT_TIME;
479 }
480 } else if (ctx_pan->vif) {
481 slot0 = 0;
482 slot1 = max_t(int, 1, ctx_pan->vif->bss_conf.dtim_period) *
Johannes Bergbbb05cb2011-07-18 01:59:22 -0700483 ctx_pan->beacon_int;
Wey-Yi Guye505c432011-07-07 08:27:41 -0700484 slot1 = max_t(int, DEFAULT_BEACON_INTERVAL, slot1);
485
Don Fry83626402012-03-07 09:52:37 -0800486 if (test_bit(STATUS_SCAN_HW, &priv->status)) {
Wey-Yi Guye505c432011-07-07 08:27:41 -0700487 slot0 = slot1 * 3 - IWL_MIN_SLOT_TIME;
488 slot1 = IWL_MIN_SLOT_TIME;
489 }
490 }
491
492 cmd.slots[0].width = cpu_to_le16(slot0);
493 cmd.slots[1].width = cpu_to_le16(slot1);
494
Johannes Berge10a0532012-03-06 13:30:39 -0800495 ret = iwl_dvm_send_cmd_pdu(priv, REPLY_WIPAN_PARAMS, CMD_SYNC,
Wey-Yi Guye505c432011-07-07 08:27:41 -0700496 sizeof(cmd), &cmd);
497 if (ret)
498 IWL_ERR(priv, "Error setting PAN parameters (%d)\n", ret);
499
500 return ret;
501}
502
Meenakshi Venkataraman354a4532012-03-15 13:27:00 -0700503static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv,
504 struct iwl_rxon_context *ctx, int hw_decrypt)
505{
506 struct iwl_rxon_cmd *rxon = &ctx->staging;
507
508 if (hw_decrypt)
509 rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
510 else
511 rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
512
513}
514
Johannes Berg2295c662010-10-23 09:15:41 -0700515/**
516 * iwlagn_commit_rxon - commit staging_rxon to hardware
517 *
518 * The RXON command in staging_rxon is committed to the hardware and
519 * the active_rxon structure is updated with the new data. This
520 * function correctly transitions out of the RXON_ASSOC_MSK state if
521 * a HW tune is required based on the RXON structure changes.
Wey-Yi Guyc1821c92011-04-19 16:52:59 -0700522 *
523 * The connect/disconnect flow should be as the following:
524 *
525 * 1. make sure send RXON command with association bit unset if not connect
526 * this should include the channel and the band for the candidate
527 * to be connected to
528 * 2. Add Station before RXON association with the AP
529 * 3. RXON_timing has to send before RXON for connection
530 * 4. full RXON command - associated bit set
531 * 5. use RXON_ASSOC command to update any flags changes
Johannes Berg2295c662010-10-23 09:15:41 -0700532 */
533int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
534{
535 /* cast away the const for active_rxon in this function */
536 struct iwl_rxon_cmd *active = (void *)&ctx->active;
Johannes Berg2295c662010-10-23 09:15:41 -0700537 bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
538 int ret;
539
Johannes Bergb1eea292012-03-06 13:30:42 -0800540 lockdep_assert_held(&priv->mutex);
Johannes Berg2295c662010-10-23 09:15:41 -0700541
Don Fry83626402012-03-07 09:52:37 -0800542 if (!iwl_is_alive(priv))
Johannes Berg2295c662010-10-23 09:15:41 -0700543 return -EBUSY;
544
545 /* This function hardcodes a bunch of dual-mode assumptions */
546 BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
547
548 if (!ctx->is_active)
549 return 0;
550
551 /* always get timestamp with Rx frame */
552 ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
553
Stanislaw Gruszka42b70a52011-05-26 17:14:22 +0200554 /*
555 * force CTS-to-self frames protection if RTS-CTS is not preferred
556 * one aggregation protection method
557 */
Johannes Bergb9ad70d2012-03-06 13:30:55 -0800558 if (!hw_params(priv).use_rts_for_aggregation)
Stanislaw Gruszka42b70a52011-05-26 17:14:22 +0200559 ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
560
Johannes Berg2295c662010-10-23 09:15:41 -0700561 if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) ||
562 !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK))
563 ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
564 else
565 ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
566
Emmanuel Grumbach522376d2011-09-06 09:31:19 -0700567 iwl_print_rx_config_cmd(priv, ctx->ctxid);
Johannes Berg2295c662010-10-23 09:15:41 -0700568 ret = iwl_check_rxon_cmd(priv, ctx);
569 if (ret) {
570 IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
571 return -EINVAL;
572 }
573
574 /*
575 * receive commit_rxon request
576 * abort any previous channel switch if still in process
577 */
Don Fry83626402012-03-07 09:52:37 -0800578 if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status) &&
Stanislaw Gruszka6f213ff2011-06-02 18:17:15 +0200579 (priv->switch_channel != ctx->staging.channel)) {
Johannes Berg2295c662010-10-23 09:15:41 -0700580 IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
Stanislaw Gruszka6f213ff2011-06-02 18:17:15 +0200581 le16_to_cpu(priv->switch_channel));
Johannes Berg2295c662010-10-23 09:15:41 -0700582 iwl_chswitch_done(priv, false);
583 }
584
585 /*
586 * If we don't need to send a full RXON, we can use
587 * iwl_rxon_assoc_cmd which is used to reconfigure filter
588 * and other flags for the current radio configuration.
589 */
590 if (!iwl_full_rxon_required(priv, ctx)) {
Wey-Yi Guyc3f6e9c2011-04-19 16:52:57 -0700591 ret = iwlagn_send_rxon_assoc(priv, ctx);
Johannes Berg2295c662010-10-23 09:15:41 -0700592 if (ret) {
593 IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
594 return ret;
595 }
596
597 memcpy(active, &ctx->staging, sizeof(*active));
Wey-Yi Guy891db882011-05-27 08:40:24 -0700598 /*
599 * We do not commit tx power settings while channel changing,
600 * do it now if after settings changed.
601 */
602 iwl_set_tx_power(priv, priv->tx_power_next, false);
Wey-Yi Guy15b3f3b2011-06-03 07:54:13 -0700603
604 /* make sure we are in the right PS state */
605 iwl_power_update_mode(priv, true);
606
Johannes Berg2295c662010-10-23 09:15:41 -0700607 return 0;
608 }
609
Don Fry9d143e92011-04-20 15:23:57 -0700610 iwl_set_rxon_hwcrypto(priv, ctx, !iwlagn_mod_params.sw_crypto);
Johannes Berg2295c662010-10-23 09:15:41 -0700611
612 IWL_DEBUG_INFO(priv,
613 "Going to commit RXON\n"
614 " * with%s RXON_FILTER_ASSOC_MSK\n"
615 " * channel = %d\n"
616 " * bssid = %pM\n",
617 (new_assoc ? "" : "out"),
618 le16_to_cpu(ctx->staging.channel),
619 ctx->staging.bssid_addr);
620
621 /*
Johannes Berg52d980c2010-11-10 09:56:45 -0800622 * Always clear associated first, but with the correct config.
623 * This is required as for example station addition for the
624 * AP station must be done after the BSSID is set to correctly
625 * set up filters in the device.
Johannes Berg2295c662010-10-23 09:15:41 -0700626 */
Wey-Yi Guy3083d032011-05-06 17:06:44 -0700627 ret = iwlagn_rxon_disconn(priv, ctx);
628 if (ret)
629 return ret;
Johannes Berg2295c662010-10-23 09:15:41 -0700630
Wey-Yi Guye3f10ce2011-07-01 07:59:26 -0700631 ret = iwlagn_set_pan_params(priv);
632 if (ret)
633 return ret;
Johannes Berg2b9253d2011-05-27 08:40:26 -0700634
Wey-Yi Guyc1821c92011-04-19 16:52:59 -0700635 if (new_assoc)
636 return iwlagn_rxon_connect(priv, ctx);
Johannes Berg2295c662010-10-23 09:15:41 -0700637
638 return 0;
639}
640
Wey-Yi Guy34a5b4b2011-12-02 08:19:18 -0800641void iwlagn_config_ht40(struct ieee80211_conf *conf,
642 struct iwl_rxon_context *ctx)
643{
644 if (conf_is_ht40_minus(conf)) {
645 ctx->ht.extension_chan_offset =
646 IEEE80211_HT_PARAM_CHA_SEC_BELOW;
647 ctx->ht.is_40mhz = true;
648 } else if (conf_is_ht40_plus(conf)) {
649 ctx->ht.extension_chan_offset =
650 IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
651 ctx->ht.is_40mhz = true;
652 } else {
653 ctx->ht.extension_chan_offset =
654 IEEE80211_HT_PARAM_CHA_SEC_NONE;
655 ctx->ht.is_40mhz = false;
656 }
657}
658
Johannes Berg2295c662010-10-23 09:15:41 -0700659int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
660{
Emmanuel Grumbachd0f76d62012-02-09 16:08:15 +0200661 struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
Johannes Berg2295c662010-10-23 09:15:41 -0700662 struct iwl_rxon_context *ctx;
663 struct ieee80211_conf *conf = &hw->conf;
664 struct ieee80211_channel *channel = conf->channel;
665 const struct iwl_channel_info *ch_info;
666 int ret = 0;
667
Johannes Berg0ca24da2012-03-15 13:26:46 -0700668 IWL_DEBUG_MAC80211(priv, "enter: changed %#x\n", changed);
Johannes Berg2295c662010-10-23 09:15:41 -0700669
Johannes Bergb1eea292012-03-06 13:30:42 -0800670 mutex_lock(&priv->mutex);
Johannes Berg2295c662010-10-23 09:15:41 -0700671
Don Fry83626402012-03-07 09:52:37 -0800672 if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
Johannes Berg2295c662010-10-23 09:15:41 -0700673 IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
674 goto out;
675 }
676
Don Fry83626402012-03-07 09:52:37 -0800677 if (!iwl_is_ready(priv)) {
Johannes Berg2295c662010-10-23 09:15:41 -0700678 IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
679 goto out;
680 }
681
682 if (changed & (IEEE80211_CONF_CHANGE_SMPS |
683 IEEE80211_CONF_CHANGE_CHANNEL)) {
684 /* mac80211 uses static for non-HT which is what we want */
685 priv->current_ht_config.smps = conf->smps_mode;
686
687 /*
688 * Recalculate chain counts.
689 *
690 * If monitor mode is enabled then mac80211 will
691 * set up the SM PS mode to OFF if an HT channel is
692 * configured.
693 */
Wey-Yi Guye3f10ce2011-07-01 07:59:26 -0700694 for_each_context(priv, ctx)
695 iwlagn_set_rxon_chain(priv, ctx);
Johannes Berg2295c662010-10-23 09:15:41 -0700696 }
697
698 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
Johannes Berg2295c662010-10-23 09:15:41 -0700699 ch_info = iwl_get_channel_info(priv, channel->band,
700 channel->hw_value);
701 if (!is_channel_valid(ch_info)) {
702 IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
703 ret = -EINVAL;
704 goto out;
705 }
706
Johannes Berg2295c662010-10-23 09:15:41 -0700707 for_each_context(priv, ctx) {
708 /* Configure HT40 channels */
Daniel Halperin7caa2312011-04-06 12:47:25 -0700709 if (ctx->ht.enabled != conf_is_ht(conf))
Wey-Yi Guy35a6eb32010-11-10 09:56:43 -0800710 ctx->ht.enabled = conf_is_ht(conf);
Wey-Yi Guy35a6eb32010-11-10 09:56:43 -0800711
Johannes Berg2295c662010-10-23 09:15:41 -0700712 if (ctx->ht.enabled) {
Wey-Yi Guy34a5b4b2011-12-02 08:19:18 -0800713 /* if HT40 is used, it should not change
714 * after associated except channel switch */
Wey-Yi Guy78feb352011-12-14 08:22:36 -0800715 if (!ctx->ht.is_40mhz ||
716 !iwl_is_associated_ctx(ctx))
Wey-Yi Guy34a5b4b2011-12-02 08:19:18 -0800717 iwlagn_config_ht40(conf, ctx);
Johannes Berg2295c662010-10-23 09:15:41 -0700718 } else
719 ctx->ht.is_40mhz = false;
720
721 /*
722 * Default to no protection. Protection mode will
723 * later be set from BSS config in iwl_ht_conf
724 */
725 ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
726
727 /* if we are switching from ht to 2.4 clear flags
728 * from any ht related info since 2.4 does not
729 * support ht */
730 if (le16_to_cpu(ctx->staging.channel) !=
731 channel->hw_value)
732 ctx->staging.flags = 0;
733
734 iwl_set_rxon_channel(priv, channel, ctx);
735 iwl_set_rxon_ht(priv, &priv->current_ht_config);
736
737 iwl_set_flags_for_band(priv, ctx, channel->band,
738 ctx->vif);
739 }
740
Johannes Berg2295c662010-10-23 09:15:41 -0700741 iwl_update_bcast_stations(priv);
742
743 /*
744 * The list of supported rates and rate mask can be different
745 * for each band; since the band may have changed, reset
746 * the rate mask to what mac80211 lists.
747 */
748 iwl_set_rate(priv);
749 }
750
751 if (changed & (IEEE80211_CONF_CHANGE_PS |
752 IEEE80211_CONF_CHANGE_IDLE)) {
753 ret = iwl_power_update_mode(priv, false);
754 if (ret)
755 IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n");
756 }
757
758 if (changed & IEEE80211_CONF_CHANGE_POWER) {
759 IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n",
760 priv->tx_power_user_lmt, conf->power_level);
761
762 iwl_set_tx_power(priv, conf->power_level, false);
763 }
764
765 for_each_context(priv, ctx) {
766 if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
767 continue;
768 iwlagn_commit_rxon(priv, ctx);
769 }
770 out:
Johannes Bergb1eea292012-03-06 13:30:42 -0800771 mutex_unlock(&priv->mutex);
Wey-Yi Guy770c72c2011-10-10 07:27:10 -0700772 IWL_DEBUG_MAC80211(priv, "leave\n");
773
Johannes Berg2295c662010-10-23 09:15:41 -0700774 return ret;
775}
776
Johannes Berg2295c662010-10-23 09:15:41 -0700777static void iwlagn_check_needed_chains(struct iwl_priv *priv,
778 struct iwl_rxon_context *ctx,
779 struct ieee80211_bss_conf *bss_conf)
780{
781 struct ieee80211_vif *vif = ctx->vif;
782 struct iwl_rxon_context *tmp;
783 struct ieee80211_sta *sta;
784 struct iwl_ht_config *ht_conf = &priv->current_ht_config;
Johannes Berg850bedc2011-02-25 12:24:11 +0100785 struct ieee80211_sta_ht_cap *ht_cap;
Johannes Berg2295c662010-10-23 09:15:41 -0700786 bool need_multiple;
787
Johannes Bergb1eea292012-03-06 13:30:42 -0800788 lockdep_assert_held(&priv->mutex);
Johannes Berg2295c662010-10-23 09:15:41 -0700789
790 switch (vif->type) {
791 case NL80211_IFTYPE_STATION:
792 rcu_read_lock();
793 sta = ieee80211_find_sta(vif, bss_conf->bssid);
Johannes Berg850bedc2011-02-25 12:24:11 +0100794 if (!sta) {
Johannes Berg2295c662010-10-23 09:15:41 -0700795 /*
796 * If at all, this can only happen through a race
797 * when the AP disconnects us while we're still
798 * setting up the connection, in that case mac80211
799 * will soon tell us about that.
800 */
801 need_multiple = false;
Johannes Berg850bedc2011-02-25 12:24:11 +0100802 rcu_read_unlock();
803 break;
Johannes Berg2295c662010-10-23 09:15:41 -0700804 }
Johannes Berg850bedc2011-02-25 12:24:11 +0100805
806 ht_cap = &sta->ht_cap;
807
808 need_multiple = true;
809
810 /*
811 * If the peer advertises no support for receiving 2 and 3
812 * stream MCS rates, it can't be transmitting them either.
813 */
814 if (ht_cap->mcs.rx_mask[1] == 0 &&
815 ht_cap->mcs.rx_mask[2] == 0) {
816 need_multiple = false;
817 } else if (!(ht_cap->mcs.tx_params &
818 IEEE80211_HT_MCS_TX_DEFINED)) {
819 /* If it can't TX MCS at all ... */
820 need_multiple = false;
821 } else if (ht_cap->mcs.tx_params &
822 IEEE80211_HT_MCS_TX_RX_DIFF) {
823 int maxstreams;
824
825 /*
826 * But if it can receive them, it might still not
827 * be able to transmit them, which is what we need
828 * to check here -- so check the number of streams
829 * it advertises for TX (if different from RX).
830 */
831
832 maxstreams = (ht_cap->mcs.tx_params &
833 IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK);
834 maxstreams >>=
835 IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
836 maxstreams += 1;
837
838 if (maxstreams <= 1)
839 need_multiple = false;
840 }
841
Johannes Berg2295c662010-10-23 09:15:41 -0700842 rcu_read_unlock();
843 break;
844 case NL80211_IFTYPE_ADHOC:
845 /* currently */
846 need_multiple = false;
847 break;
848 default:
849 /* only AP really */
850 need_multiple = true;
851 break;
852 }
853
854 ctx->ht_need_multiple_chains = need_multiple;
855
856 if (!need_multiple) {
857 /* check all contexts */
858 for_each_context(priv, tmp) {
859 if (!tmp->vif)
860 continue;
861 if (tmp->ht_need_multiple_chains) {
862 need_multiple = true;
863 break;
864 }
865 }
866 }
867
868 ht_conf->single_chain_sufficient = !need_multiple;
869}
870
Don Fry5c3d29f2011-07-08 08:46:29 -0700871static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
872{
873 struct iwl_chain_noise_data *data = &priv->chain_noise_data;
874 int ret;
875
876 if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
877 iwl_is_any_associated(priv)) {
878 struct iwl_calib_chain_noise_reset_cmd cmd;
879
880 /* clear data for chain noise calibration algorithm */
881 data->chain_noise_a = 0;
882 data->chain_noise_b = 0;
883 data->chain_noise_c = 0;
884 data->chain_signal_a = 0;
885 data->chain_signal_b = 0;
886 data->chain_signal_c = 0;
887 data->beacon_count = 0;
888
889 memset(&cmd, 0, sizeof(cmd));
890 iwl_set_calib_hdr(&cmd.hdr,
Wey-Yi Guy898ed672011-07-13 08:38:57 -0700891 priv->phy_calib_chain_noise_reset_cmd);
Johannes Berge10a0532012-03-06 13:30:39 -0800892 ret = iwl_dvm_send_cmd_pdu(priv,
Don Fry5c3d29f2011-07-08 08:46:29 -0700893 REPLY_PHY_CALIBRATION_CMD,
894 CMD_SYNC, sizeof(cmd), &cmd);
895 if (ret)
896 IWL_ERR(priv,
897 "Could not send REPLY_PHY_CALIBRATION_CMD\n");
898 data->state = IWL_CHAIN_NOISE_ACCUMULATE;
899 IWL_DEBUG_CALIB(priv, "Run chain_noise_calibrate\n");
900 }
901}
902
Johannes Berg2295c662010-10-23 09:15:41 -0700903void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
904 struct ieee80211_vif *vif,
905 struct ieee80211_bss_conf *bss_conf,
906 u32 changes)
907{
Emmanuel Grumbachd0f76d62012-02-09 16:08:15 +0200908 struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
Johannes Berg2295c662010-10-23 09:15:41 -0700909 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
910 int ret;
911 bool force = false;
912
Johannes Bergb1eea292012-03-06 13:30:42 -0800913 mutex_lock(&priv->mutex);
Johannes Berg2295c662010-10-23 09:15:41 -0700914
Don Fry83626402012-03-07 09:52:37 -0800915 if (unlikely(!iwl_is_ready(priv))) {
Wey-Yi Guy14a085e2010-12-14 07:38:58 -0800916 IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
Johannes Bergb1eea292012-03-06 13:30:42 -0800917 mutex_unlock(&priv->mutex);
Shanyu Zhaoae0b6932010-12-02 11:02:28 -0800918 return;
919 }
920
921 if (unlikely(!ctx->vif)) {
922 IWL_DEBUG_MAC80211(priv, "leave - vif is NULL\n");
Johannes Bergb1eea292012-03-06 13:30:42 -0800923 mutex_unlock(&priv->mutex);
Johannes Berg893654d2010-11-10 18:25:47 -0800924 return;
925 }
926
Johannes Berg2295c662010-10-23 09:15:41 -0700927 if (changes & BSS_CHANGED_BEACON_INT)
928 force = true;
929
930 if (changes & BSS_CHANGED_QOS) {
931 ctx->qos_data.qos_active = bss_conf->qos;
932 iwlagn_update_qos(priv, ctx);
933 }
934
935 ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
936 if (vif->bss_conf.use_short_preamble)
937 ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
938 else
939 ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
940
941 if (changes & BSS_CHANGED_ASSOC) {
942 if (bss_conf->assoc) {
Johannes Berge9ac0742012-03-13 14:29:30 +0100943 priv->timestamp = bss_conf->last_tsf;
Johannes Berg2295c662010-10-23 09:15:41 -0700944 ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
945 } else {
Garen Tamrazian68b99312011-03-30 02:29:32 -0700946 /*
947 * If we disassociate while there are pending
948 * frames, just wake up the queues and let the
949 * frames "escape" ... This shouldn't really
950 * be happening to start with, but we should
951 * not get stuck in this case either since it
952 * can happen if userspace gets confused.
953 */
Johannes Berge755f882012-03-07 09:52:16 -0800954 iwlagn_lift_passive_no_rx(priv);
955
Johannes Berg2295c662010-10-23 09:15:41 -0700956 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
Johannes Bergc8ac61c2011-07-15 13:23:45 -0700957
958 if (ctx->ctxid == IWL_RXON_CTX_BSS)
959 priv->have_rekey_data = false;
Johannes Berg2295c662010-10-23 09:15:41 -0700960 }
Meenakshi Venkataraman207ecc52011-07-08 08:46:23 -0700961
962 iwlagn_bt_coex_rssi_monitor(priv);
Johannes Berg2295c662010-10-23 09:15:41 -0700963 }
964
965 if (ctx->ht.enabled) {
966 ctx->ht.protection = bss_conf->ht_operation_mode &
967 IEEE80211_HT_OP_MODE_PROTECTION;
968 ctx->ht.non_gf_sta_present = !!(bss_conf->ht_operation_mode &
969 IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
970 iwlagn_check_needed_chains(priv, ctx, bss_conf);
Johannes Bergb2769b82010-11-10 09:56:47 -0800971 iwl_set_rxon_ht(priv, &priv->current_ht_config);
Johannes Berg2295c662010-10-23 09:15:41 -0700972 }
973
Wey-Yi Guye3f10ce2011-07-01 07:59:26 -0700974 iwlagn_set_rxon_chain(priv, ctx);
Johannes Berg2295c662010-10-23 09:15:41 -0700975
976 if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
977 ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
978 else
979 ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
980
981 if (bss_conf->use_cts_prot)
982 ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
983 else
984 ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
985
986 memcpy(ctx->staging.bssid_addr, bss_conf->bssid, ETH_ALEN);
987
988 if (vif->type == NL80211_IFTYPE_AP ||
989 vif->type == NL80211_IFTYPE_ADHOC) {
990 if (vif->bss_conf.enable_beacon) {
991 ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
992 priv->beacon_ctx = ctx;
993 } else {
994 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
995 priv->beacon_ctx = NULL;
996 }
997 }
998
Meenakshi Venkataraman758f5552012-02-08 12:04:41 -0800999 /*
1000 * If the ucode decides to do beacon filtering before
1001 * association, it will lose beacons that are needed
1002 * before sending frames out on passive channels. This
1003 * causes association failures on those channels. Enable
1004 * receiving beacons in such cases.
1005 */
1006
1007 if (vif->type == NL80211_IFTYPE_STATION) {
1008 if (!bss_conf->assoc)
1009 ctx->staging.filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
1010 else
1011 ctx->staging.filter_flags &=
1012 ~RXON_FILTER_BCON_AWARE_MSK;
1013 }
1014
Johannes Berg2295c662010-10-23 09:15:41 -07001015 if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
1016 iwlagn_commit_rxon(priv, ctx);
1017
Johannes Berg8da8e622010-11-10 09:56:46 -08001018 if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) {
1019 /*
1020 * The chain noise calibration will enable PM upon
1021 * completion. If calibration has already been run
1022 * then we need to enable power management here.
1023 */
1024 if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
1025 iwl_power_update_mode(priv, false);
1026
1027 /* Enable RX differential gain and sensitivity calibrations */
Don Fry5c3d29f2011-07-08 08:46:29 -07001028 if (!priv->disable_chain_noise_cal)
1029 iwlagn_chain_noise_reset(priv);
Johannes Berg8da8e622010-11-10 09:56:46 -08001030 priv->start_calib = 1;
1031 }
1032
Johannes Berg2295c662010-10-23 09:15:41 -07001033 if (changes & BSS_CHANGED_IBSS) {
1034 ret = iwlagn_manage_ibss_station(priv, vif,
1035 bss_conf->ibss_joined);
1036 if (ret)
1037 IWL_ERR(priv, "failed to %s IBSS station %pM\n",
1038 bss_conf->ibss_joined ? "add" : "remove",
1039 bss_conf->bssid);
1040 }
1041
Johannes Bergbd50a8ab2010-10-23 09:15:42 -07001042 if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_ADHOC &&
1043 priv->beacon_ctx) {
1044 if (iwlagn_update_beacon(priv, vif))
1045 IWL_ERR(priv, "Error sending IBSS beacon\n");
1046 }
1047
Johannes Bergb1eea292012-03-06 13:30:42 -08001048 mutex_unlock(&priv->mutex);
Johannes Berg2295c662010-10-23 09:15:41 -07001049}
Johannes Bergae79d232010-11-10 09:56:38 -08001050
1051void iwlagn_post_scan(struct iwl_priv *priv)
1052{
1053 struct iwl_rxon_context *ctx;
1054
1055 /*
Wey-Yi Guyc2b821d2011-06-03 07:54:14 -07001056 * We do not commit power settings while scan is pending,
1057 * do it now if the settings changed.
1058 */
1059 iwl_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false);
1060 iwl_set_tx_power(priv, priv->tx_power_next, false);
1061
1062 /*
Johannes Bergae79d232010-11-10 09:56:38 -08001063 * Since setting the RXON may have been deferred while
1064 * performing the scan, fire one off if needed
1065 */
1066 for_each_context(priv, ctx)
1067 if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
1068 iwlagn_commit_rxon(priv, ctx);
1069
Wey-Yi Guye3f10ce2011-07-01 07:59:26 -07001070 iwlagn_set_pan_params(priv);
Johannes Bergae79d232010-11-10 09:56:38 -08001071}