blob: 99e96508b1dcde18885c71190b27e7b33d7f018f [file] [log] [blame]
Johannes Berg2295c662010-10-23 09:15:41 -07001/******************************************************************************
2 *
3 * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
4 *
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"
29#include "iwl-sta.h"
30#include "iwl-core.h"
31#include "iwl-agn-calib.h"
32
33static int iwlagn_disable_bss(struct iwl_priv *priv,
34 struct iwl_rxon_context *ctx,
35 struct iwl_rxon_cmd *send)
36{
37 __le32 old_filter = send->filter_flags;
38 int ret;
39
40 send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
41 ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send);
42
43 send->filter_flags = old_filter;
44
45 if (ret)
46 IWL_ERR(priv, "Error clearing ASSOC_MSK on BSS (%d)\n", ret);
47
48 return ret;
49}
50
51static int iwlagn_disable_pan(struct iwl_priv *priv,
52 struct iwl_rxon_context *ctx,
53 struct iwl_rxon_cmd *send)
54{
Johannes Berg311dce72011-01-04 16:22:01 -080055 struct iwl_notification_wait disable_wait;
Johannes Berg2295c662010-10-23 09:15:41 -070056 __le32 old_filter = send->filter_flags;
57 u8 old_dev_type = send->dev_type;
58 int ret;
59
Johannes Berg311dce72011-01-04 16:22:01 -080060 iwlagn_init_notification_wait(priv, &disable_wait, NULL,
61 REPLY_WIPAN_DEACTIVATION_COMPLETE);
62
Johannes Berg2295c662010-10-23 09:15:41 -070063 send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
64 send->dev_type = RXON_DEV_TYPE_P2P;
65 ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send);
66
67 send->filter_flags = old_filter;
68 send->dev_type = old_dev_type;
69
Johannes Berg311dce72011-01-04 16:22:01 -080070 if (ret) {
Johannes Berg2295c662010-10-23 09:15:41 -070071 IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
Johannes Berg311dce72011-01-04 16:22:01 -080072 iwlagn_remove_notification(priv, &disable_wait);
73 } else {
74 signed long wait_res;
Johannes Berg2295c662010-10-23 09:15:41 -070075
Johannes Berg311dce72011-01-04 16:22:01 -080076 wait_res = iwlagn_wait_notification(priv, &disable_wait, HZ);
77 if (wait_res == 0)
78 IWL_ERR(priv, "Timed out waiting for PAN disable\n");
79 }
Johannes Berg2295c662010-10-23 09:15:41 -070080
81 return ret;
82}
83
Shanyu Zhaof4115d42010-11-10 18:25:58 -080084static void iwlagn_update_qos(struct iwl_priv *priv,
85 struct iwl_rxon_context *ctx)
86{
87 int ret;
88
89 if (!ctx->is_active)
90 return;
91
92 ctx->qos_data.def_qos_parm.qos_flags = 0;
93
94 if (ctx->qos_data.qos_active)
95 ctx->qos_data.def_qos_parm.qos_flags |=
96 QOS_PARAM_FLG_UPDATE_EDCA_MSK;
97
98 if (ctx->ht.enabled)
99 ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
100
101 IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
102 ctx->qos_data.qos_active,
103 ctx->qos_data.def_qos_parm.qos_flags);
104
105 ret = iwl_send_cmd_pdu(priv, ctx->qos_cmd,
106 sizeof(struct iwl_qosparam_cmd),
107 &ctx->qos_data.def_qos_parm);
108 if (ret)
109 IWL_ERR(priv, "Failed to update QoS\n");
110}
111
Johannes Bergbd50a8a2010-10-23 09:15:42 -0700112static int iwlagn_update_beacon(struct iwl_priv *priv,
113 struct ieee80211_vif *vif)
114{
115 lockdep_assert_held(&priv->mutex);
116
117 dev_kfree_skb(priv->beacon_skb);
118 priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif);
119 if (!priv->beacon_skb)
120 return -ENOMEM;
121 return iwlagn_send_beacon_cmd(priv);
122}
123
Johannes Berg2295c662010-10-23 09:15:41 -0700124/**
125 * iwlagn_commit_rxon - commit staging_rxon to hardware
126 *
127 * The RXON command in staging_rxon is committed to the hardware and
128 * the active_rxon structure is updated with the new data. This
129 * function correctly transitions out of the RXON_ASSOC_MSK state if
130 * a HW tune is required based on the RXON structure changes.
131 */
132int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
133{
134 /* cast away the const for active_rxon in this function */
135 struct iwl_rxon_cmd *active = (void *)&ctx->active;
Johannes Berg2295c662010-10-23 09:15:41 -0700136 bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
Johannes Berg2b5f7a62010-11-10 18:25:48 -0800137 bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK);
Johannes Berg2295c662010-10-23 09:15:41 -0700138 int ret;
139
140 lockdep_assert_held(&priv->mutex);
141
Wey-Yi Guyadb90a02010-11-26 11:09:42 -0800142 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
143 return -EINVAL;
144
Johannes Berg2295c662010-10-23 09:15:41 -0700145 if (!iwl_is_alive(priv))
146 return -EBUSY;
147
148 /* This function hardcodes a bunch of dual-mode assumptions */
149 BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
150
151 if (!ctx->is_active)
152 return 0;
153
154 /* always get timestamp with Rx frame */
155 ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
156
157 if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) ||
158 !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK))
159 ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
160 else
161 ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
162
163 ret = iwl_check_rxon_cmd(priv, ctx);
164 if (ret) {
165 IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
166 return -EINVAL;
167 }
168
169 /*
170 * receive commit_rxon request
171 * abort any previous channel switch if still in process
172 */
173 if (priv->switch_rxon.switch_in_progress &&
174 (priv->switch_rxon.channel != ctx->staging.channel)) {
175 IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
176 le16_to_cpu(priv->switch_rxon.channel));
177 iwl_chswitch_done(priv, false);
178 }
179
180 /*
181 * If we don't need to send a full RXON, we can use
182 * iwl_rxon_assoc_cmd which is used to reconfigure filter
183 * and other flags for the current radio configuration.
184 */
185 if (!iwl_full_rxon_required(priv, ctx)) {
186 ret = iwl_send_rxon_assoc(priv, ctx);
187 if (ret) {
188 IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
189 return ret;
190 }
191
192 memcpy(active, &ctx->staging, sizeof(*active));
193 iwl_print_rx_config_cmd(priv, ctx);
194 return 0;
195 }
196
197 if (priv->cfg->ops->hcmd->set_pan_params) {
198 ret = priv->cfg->ops->hcmd->set_pan_params(priv);
199 if (ret)
200 return ret;
201 }
202
203 iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto);
204
205 IWL_DEBUG_INFO(priv,
206 "Going to commit RXON\n"
207 " * with%s RXON_FILTER_ASSOC_MSK\n"
208 " * channel = %d\n"
209 " * bssid = %pM\n",
210 (new_assoc ? "" : "out"),
211 le16_to_cpu(ctx->staging.channel),
212 ctx->staging.bssid_addr);
213
214 /*
Johannes Berg52d980c2010-11-10 09:56:45 -0800215 * Always clear associated first, but with the correct config.
216 * This is required as for example station addition for the
217 * AP station must be done after the BSSID is set to correctly
218 * set up filters in the device.
Johannes Berg2295c662010-10-23 09:15:41 -0700219 */
Johannes Berg2b5f7a62010-11-10 18:25:48 -0800220 if ((old_assoc && new_assoc) || !new_assoc) {
221 if (ctx->ctxid == IWL_RXON_CTX_BSS)
222 ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
223 else
224 ret = iwlagn_disable_pan(priv, ctx, &ctx->staging);
225 if (ret)
226 return ret;
Johannes Berg2295c662010-10-23 09:15:41 -0700227
Johannes Berg2b5f7a62010-11-10 18:25:48 -0800228 memcpy(active, &ctx->staging, sizeof(*active));
Johannes Berg2295c662010-10-23 09:15:41 -0700229
Johannes Berg2b5f7a62010-11-10 18:25:48 -0800230 /*
231 * Un-assoc RXON clears the station table and WEP
232 * keys, so we have to restore those afterwards.
233 */
234 iwl_clear_ucode_stations(priv, ctx);
235 iwl_restore_stations(priv, ctx);
236 ret = iwl_restore_default_wep_keys(priv, ctx);
237 if (ret) {
238 IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
239 return ret;
240 }
Johannes Berg2295c662010-10-23 09:15:41 -0700241 }
242
243 /* RXON timing must be before associated RXON */
244 ret = iwl_send_rxon_timing(priv, ctx);
245 if (ret) {
246 IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
247 return ret;
248 }
249
250 if (new_assoc) {
Shanyu Zhaof4115d42010-11-10 18:25:58 -0800251 /* QoS info may be cleared by previous un-assoc RXON */
252 iwlagn_update_qos(priv, ctx);
253
Johannes Bergbd50a8a2010-10-23 09:15:42 -0700254 /*
255 * We'll run into this code path when beaconing is
256 * enabled, but then we also need to send the beacon
257 * to the device.
258 */
259 if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) {
260 ret = iwlagn_update_beacon(priv, ctx->vif);
261 if (ret) {
262 IWL_ERR(priv,
263 "Error sending required beacon (%d)!\n",
264 ret);
265 return ret;
266 }
Johannes Berg2295c662010-10-23 09:15:41 -0700267 }
268
269 priv->start_calib = 0;
270 /*
271 * Apply the new configuration.
272 *
273 * Associated RXON doesn't clear the station table in uCode,
274 * so we don't need to restore stations etc. after this.
275 */
276 ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
277 sizeof(struct iwl_rxon_cmd), &ctx->staging);
278 if (ret) {
279 IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
280 return ret;
281 }
282 memcpy(active, &ctx->staging, sizeof(*active));
Johannes Bergbd50a8a2010-10-23 09:15:42 -0700283
Johannes Berg2b5f7a62010-11-10 18:25:48 -0800284 iwl_reprogram_ap_sta(priv, ctx);
285
Johannes Bergbd50a8a2010-10-23 09:15:42 -0700286 /* IBSS beacon needs to be sent after setting assoc */
287 if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC))
288 if (iwlagn_update_beacon(priv, ctx->vif))
289 IWL_ERR(priv, "Error sending IBSS beacon\n");
Johannes Berg2295c662010-10-23 09:15:41 -0700290 }
291
292 iwl_print_rx_config_cmd(priv, ctx);
293
294 iwl_init_sensitivity(priv);
295
296 /*
297 * If we issue a new RXON command which required a tune then we must
298 * send a new TXPOWER command or we won't be able to Tx any frames.
299 *
300 * FIXME: which RXON requires a tune? Can we optimise this out in
301 * some cases?
302 */
303 ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
304 if (ret) {
305 IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
306 return ret;
307 }
308
309 return 0;
310}
311
312int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
313{
314 struct iwl_priv *priv = hw->priv;
315 struct iwl_rxon_context *ctx;
316 struct ieee80211_conf *conf = &hw->conf;
317 struct ieee80211_channel *channel = conf->channel;
318 const struct iwl_channel_info *ch_info;
319 int ret = 0;
Wey-Yi Guy35a6eb32010-11-10 09:56:43 -0800320 bool ht_changed[NUM_IWL_RXON_CTX] = {};
Johannes Berg2295c662010-10-23 09:15:41 -0700321
322 IWL_DEBUG_MAC80211(priv, "changed %#x", changed);
323
324 mutex_lock(&priv->mutex);
325
326 if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
327 IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
328 goto out;
329 }
330
331 if (!iwl_is_ready(priv)) {
332 IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
333 goto out;
334 }
335
336 if (changed & (IEEE80211_CONF_CHANGE_SMPS |
337 IEEE80211_CONF_CHANGE_CHANNEL)) {
338 /* mac80211 uses static for non-HT which is what we want */
339 priv->current_ht_config.smps = conf->smps_mode;
340
341 /*
342 * Recalculate chain counts.
343 *
344 * If monitor mode is enabled then mac80211 will
345 * set up the SM PS mode to OFF if an HT channel is
346 * configured.
347 */
348 if (priv->cfg->ops->hcmd->set_rxon_chain)
349 for_each_context(priv, ctx)
350 priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
351 }
352
353 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
354 unsigned long flags;
355
356 ch_info = iwl_get_channel_info(priv, channel->band,
357 channel->hw_value);
358 if (!is_channel_valid(ch_info)) {
359 IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
360 ret = -EINVAL;
361 goto out;
362 }
363
364 spin_lock_irqsave(&priv->lock, flags);
365
366 for_each_context(priv, ctx) {
367 /* Configure HT40 channels */
Wey-Yi Guy35a6eb32010-11-10 09:56:43 -0800368 if (ctx->ht.enabled != conf_is_ht(conf)) {
369 ctx->ht.enabled = conf_is_ht(conf);
370 ht_changed[ctx->ctxid] = true;
371 }
372
Johannes Berg2295c662010-10-23 09:15:41 -0700373 if (ctx->ht.enabled) {
374 if (conf_is_ht40_minus(conf)) {
375 ctx->ht.extension_chan_offset =
376 IEEE80211_HT_PARAM_CHA_SEC_BELOW;
377 ctx->ht.is_40mhz = true;
378 } else if (conf_is_ht40_plus(conf)) {
379 ctx->ht.extension_chan_offset =
380 IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
381 ctx->ht.is_40mhz = true;
382 } else {
383 ctx->ht.extension_chan_offset =
384 IEEE80211_HT_PARAM_CHA_SEC_NONE;
385 ctx->ht.is_40mhz = false;
386 }
387 } else
388 ctx->ht.is_40mhz = false;
389
390 /*
391 * Default to no protection. Protection mode will
392 * later be set from BSS config in iwl_ht_conf
393 */
394 ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
395
396 /* if we are switching from ht to 2.4 clear flags
397 * from any ht related info since 2.4 does not
398 * support ht */
399 if (le16_to_cpu(ctx->staging.channel) !=
400 channel->hw_value)
401 ctx->staging.flags = 0;
402
403 iwl_set_rxon_channel(priv, channel, ctx);
404 iwl_set_rxon_ht(priv, &priv->current_ht_config);
405
406 iwl_set_flags_for_band(priv, ctx, channel->band,
407 ctx->vif);
408 }
409
410 spin_unlock_irqrestore(&priv->lock, flags);
411
412 iwl_update_bcast_stations(priv);
413
414 /*
415 * The list of supported rates and rate mask can be different
416 * for each band; since the band may have changed, reset
417 * the rate mask to what mac80211 lists.
418 */
419 iwl_set_rate(priv);
420 }
421
422 if (changed & (IEEE80211_CONF_CHANGE_PS |
423 IEEE80211_CONF_CHANGE_IDLE)) {
424 ret = iwl_power_update_mode(priv, false);
425 if (ret)
426 IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n");
427 }
428
429 if (changed & IEEE80211_CONF_CHANGE_POWER) {
430 IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n",
431 priv->tx_power_user_lmt, conf->power_level);
432
433 iwl_set_tx_power(priv, conf->power_level, false);
434 }
435
436 for_each_context(priv, ctx) {
437 if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
438 continue;
439 iwlagn_commit_rxon(priv, ctx);
Wey-Yi Guy35a6eb32010-11-10 09:56:43 -0800440 if (ht_changed[ctx->ctxid])
441 iwlagn_update_qos(priv, ctx);
Johannes Berg2295c662010-10-23 09:15:41 -0700442 }
443 out:
444 mutex_unlock(&priv->mutex);
445 return ret;
446}
447
Johannes Berg2295c662010-10-23 09:15:41 -0700448static void iwlagn_check_needed_chains(struct iwl_priv *priv,
449 struct iwl_rxon_context *ctx,
450 struct ieee80211_bss_conf *bss_conf)
451{
452 struct ieee80211_vif *vif = ctx->vif;
453 struct iwl_rxon_context *tmp;
454 struct ieee80211_sta *sta;
455 struct iwl_ht_config *ht_conf = &priv->current_ht_config;
456 bool need_multiple;
457
458 lockdep_assert_held(&priv->mutex);
459
460 switch (vif->type) {
461 case NL80211_IFTYPE_STATION:
462 rcu_read_lock();
463 sta = ieee80211_find_sta(vif, bss_conf->bssid);
464 if (sta) {
465 struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
466 int maxstreams;
467
468 maxstreams = (ht_cap->mcs.tx_params &
469 IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
470 >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
471 maxstreams += 1;
472
Johannes Berg2e1fea42010-11-10 09:56:44 -0800473 need_multiple = true;
474
Johannes Berg2295c662010-10-23 09:15:41 -0700475 if ((ht_cap->mcs.rx_mask[1] == 0) &&
476 (ht_cap->mcs.rx_mask[2] == 0))
477 need_multiple = false;
478 if (maxstreams <= 1)
Johannes Berg2e1fea42010-11-10 09:56:44 -0800479 need_multiple = false;
Johannes Berg2295c662010-10-23 09:15:41 -0700480 } else {
481 /*
482 * If at all, this can only happen through a race
483 * when the AP disconnects us while we're still
484 * setting up the connection, in that case mac80211
485 * will soon tell us about that.
486 */
487 need_multiple = false;
488 }
489 rcu_read_unlock();
490 break;
491 case NL80211_IFTYPE_ADHOC:
492 /* currently */
493 need_multiple = false;
494 break;
495 default:
496 /* only AP really */
497 need_multiple = true;
498 break;
499 }
500
501 ctx->ht_need_multiple_chains = need_multiple;
502
503 if (!need_multiple) {
504 /* check all contexts */
505 for_each_context(priv, tmp) {
506 if (!tmp->vif)
507 continue;
508 if (tmp->ht_need_multiple_chains) {
509 need_multiple = true;
510 break;
511 }
512 }
513 }
514
515 ht_conf->single_chain_sufficient = !need_multiple;
516}
517
518void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
519 struct ieee80211_vif *vif,
520 struct ieee80211_bss_conf *bss_conf,
521 u32 changes)
522{
523 struct iwl_priv *priv = hw->priv;
524 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
525 int ret;
526 bool force = false;
527
528 mutex_lock(&priv->mutex);
529
Shanyu Zhaoae0b6932010-12-02 11:02:28 -0800530 if (unlikely(!iwl_is_ready(priv))) {
Wey-Yi Guy14a085e2010-12-14 07:38:58 -0800531 IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
532 mutex_unlock(&priv->mutex);
Shanyu Zhaoae0b6932010-12-02 11:02:28 -0800533 return;
534 }
535
536 if (unlikely(!ctx->vif)) {
537 IWL_DEBUG_MAC80211(priv, "leave - vif is NULL\n");
Johannes Berg893654d2010-11-10 18:25:47 -0800538 mutex_unlock(&priv->mutex);
539 return;
540 }
541
Johannes Berg2295c662010-10-23 09:15:41 -0700542 if (changes & BSS_CHANGED_BEACON_INT)
543 force = true;
544
545 if (changes & BSS_CHANGED_QOS) {
546 ctx->qos_data.qos_active = bss_conf->qos;
547 iwlagn_update_qos(priv, ctx);
548 }
549
550 ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
551 if (vif->bss_conf.use_short_preamble)
552 ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
553 else
554 ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
555
556 if (changes & BSS_CHANGED_ASSOC) {
557 if (bss_conf->assoc) {
558 iwl_led_associate(priv);
559 priv->timestamp = bss_conf->timestamp;
560 ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
561 } else {
562 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
563 iwl_led_disassociate(priv);
564 }
565 }
566
567 if (ctx->ht.enabled) {
568 ctx->ht.protection = bss_conf->ht_operation_mode &
569 IEEE80211_HT_OP_MODE_PROTECTION;
570 ctx->ht.non_gf_sta_present = !!(bss_conf->ht_operation_mode &
571 IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
572 iwlagn_check_needed_chains(priv, ctx, bss_conf);
Johannes Bergb2769b82010-11-10 09:56:47 -0800573 iwl_set_rxon_ht(priv, &priv->current_ht_config);
Johannes Berg2295c662010-10-23 09:15:41 -0700574 }
575
576 if (priv->cfg->ops->hcmd->set_rxon_chain)
577 priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
578
579 if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
580 ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
581 else
582 ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
583
584 if (bss_conf->use_cts_prot)
585 ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
586 else
587 ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
588
589 memcpy(ctx->staging.bssid_addr, bss_conf->bssid, ETH_ALEN);
590
591 if (vif->type == NL80211_IFTYPE_AP ||
592 vif->type == NL80211_IFTYPE_ADHOC) {
593 if (vif->bss_conf.enable_beacon) {
594 ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
595 priv->beacon_ctx = ctx;
596 } else {
597 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
598 priv->beacon_ctx = NULL;
599 }
600 }
601
602 if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
603 iwlagn_commit_rxon(priv, ctx);
604
Johannes Berg8da8e622010-11-10 09:56:46 -0800605 if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) {
606 /*
607 * The chain noise calibration will enable PM upon
608 * completion. If calibration has already been run
609 * then we need to enable power management here.
610 */
611 if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
612 iwl_power_update_mode(priv, false);
613
614 /* Enable RX differential gain and sensitivity calibrations */
615 iwl_chain_noise_reset(priv);
616 priv->start_calib = 1;
617 }
618
Johannes Berg2295c662010-10-23 09:15:41 -0700619 if (changes & BSS_CHANGED_IBSS) {
620 ret = iwlagn_manage_ibss_station(priv, vif,
621 bss_conf->ibss_joined);
622 if (ret)
623 IWL_ERR(priv, "failed to %s IBSS station %pM\n",
624 bss_conf->ibss_joined ? "add" : "remove",
625 bss_conf->bssid);
626 }
627
Johannes Bergbd50a8a2010-10-23 09:15:42 -0700628 if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_ADHOC &&
629 priv->beacon_ctx) {
630 if (iwlagn_update_beacon(priv, vif))
631 IWL_ERR(priv, "Error sending IBSS beacon\n");
632 }
633
Johannes Berg2295c662010-10-23 09:15:41 -0700634 mutex_unlock(&priv->mutex);
635}
Johannes Bergae79d232010-11-10 09:56:38 -0800636
637void iwlagn_post_scan(struct iwl_priv *priv)
638{
639 struct iwl_rxon_context *ctx;
640
641 /*
642 * Since setting the RXON may have been deferred while
643 * performing the scan, fire one off if needed
644 */
645 for_each_context(priv, ctx)
646 if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
647 iwlagn_commit_rxon(priv, ctx);
648
649 if (priv->cfg->ops->hcmd->set_pan_params)
650 priv->cfg->ops->hcmd->set_pan_params(priv);
651}