blob: b735fef9ee4b9590af241fd76960e1032ed67812 [file] [log] [blame]
Johannes Berg2295c662010-10-23 09:15:41 -07001/******************************************************************************
2 *
3 * GPL LICENSE SUMMARY
4 *
5 * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
19 * USA
20 *
21 * The full GNU General Public License is included in this distribution
22 * in the file called LICENSE.GPL.
23 *
24 * Contact Information:
25 * Intel Linux Wireless <ilw@linux.intel.com>
26 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
27 *****************************************************************************/
28
29#include <linux/kernel.h>
30#include <net/mac80211.h>
31
32#include "iwl-dev.h"
33#include "iwl-core.h"
34#include "iwl-legacy.h"
35
36/**
37 * iwl_legacy_mac_config - mac80211 config callback
38 */
39int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed)
40{
41 struct iwl_priv *priv = hw->priv;
42 const struct iwl_channel_info *ch_info;
43 struct ieee80211_conf *conf = &hw->conf;
44 struct ieee80211_channel *channel = conf->channel;
45 struct iwl_ht_config *ht_conf = &priv->current_ht_config;
46 struct iwl_rxon_context *ctx;
47 unsigned long flags = 0;
48 int ret = 0;
49 u16 ch;
50 int scan_active = 0;
51
52 if (WARN_ON(!priv->cfg->ops->legacy))
53 return -EOPNOTSUPP;
54
55 mutex_lock(&priv->mutex);
56
57 IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n",
58 channel->hw_value, changed);
59
60 if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
61 test_bit(STATUS_SCANNING, &priv->status))) {
62 scan_active = 1;
63 IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
64 }
65
66 if (changed & (IEEE80211_CONF_CHANGE_SMPS |
67 IEEE80211_CONF_CHANGE_CHANNEL)) {
68 /* mac80211 uses static for non-HT which is what we want */
69 priv->current_ht_config.smps = conf->smps_mode;
70
71 /*
72 * Recalculate chain counts.
73 *
74 * If monitor mode is enabled then mac80211 will
75 * set up the SM PS mode to OFF if an HT channel is
76 * configured.
77 */
78 if (priv->cfg->ops->hcmd->set_rxon_chain)
79 for_each_context(priv, ctx)
80 priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
81 }
82
83 /* during scanning mac80211 will delay channel setting until
84 * scan finish with changed = 0
85 */
86 if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
87 if (scan_active)
88 goto set_ch_out;
89
90 ch = channel->hw_value;
91 ch_info = iwl_get_channel_info(priv, channel->band, ch);
92 if (!is_channel_valid(ch_info)) {
93 IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
94 ret = -EINVAL;
95 goto set_ch_out;
96 }
97
98 spin_lock_irqsave(&priv->lock, flags);
99
100 for_each_context(priv, ctx) {
101 /* Configure HT40 channels */
102 ctx->ht.enabled = conf_is_ht(conf);
103 if (ctx->ht.enabled) {
104 if (conf_is_ht40_minus(conf)) {
105 ctx->ht.extension_chan_offset =
106 IEEE80211_HT_PARAM_CHA_SEC_BELOW;
107 ctx->ht.is_40mhz = true;
108 } else if (conf_is_ht40_plus(conf)) {
109 ctx->ht.extension_chan_offset =
110 IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
111 ctx->ht.is_40mhz = true;
112 } else {
113 ctx->ht.extension_chan_offset =
114 IEEE80211_HT_PARAM_CHA_SEC_NONE;
115 ctx->ht.is_40mhz = false;
116 }
117 } else
118 ctx->ht.is_40mhz = false;
119
120 /*
121 * Default to no protection. Protection mode will
122 * later be set from BSS config in iwl_ht_conf
123 */
124 ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
125
126 /* if we are switching from ht to 2.4 clear flags
127 * from any ht related info since 2.4 does not
128 * support ht */
129 if ((le16_to_cpu(ctx->staging.channel) != ch))
130 ctx->staging.flags = 0;
131
132 iwl_set_rxon_channel(priv, channel, ctx);
133 iwl_set_rxon_ht(priv, ht_conf);
134
135 iwl_set_flags_for_band(priv, ctx, channel->band,
136 ctx->vif);
137 }
138
139 spin_unlock_irqrestore(&priv->lock, flags);
140
141 if (priv->cfg->ops->legacy->update_bcast_stations)
142 ret = priv->cfg->ops->legacy->update_bcast_stations(priv);
143
144 set_ch_out:
145 /* The list of supported rates and rate mask can be different
146 * for each band; since the band may have changed, reset
147 * the rate mask to what mac80211 lists */
148 iwl_set_rate(priv);
149 }
150
151 if (changed & (IEEE80211_CONF_CHANGE_PS |
152 IEEE80211_CONF_CHANGE_IDLE)) {
153 ret = iwl_power_update_mode(priv, false);
154 if (ret)
155 IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n");
156 }
157
158 if (changed & IEEE80211_CONF_CHANGE_POWER) {
159 IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n",
160 priv->tx_power_user_lmt, conf->power_level);
161
162 iwl_set_tx_power(priv, conf->power_level, false);
163 }
164
165 if (!iwl_is_ready(priv)) {
166 IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
167 goto out;
168 }
169
170 if (scan_active)
171 goto out;
172
173 for_each_context(priv, ctx) {
174 if (memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)))
175 iwlcore_commit_rxon(priv, ctx);
176 else
177 IWL_DEBUG_INFO(priv,
178 "Not re-sending same RXON configuration.\n");
179 }
180
181out:
182 IWL_DEBUG_MAC80211(priv, "leave\n");
183 mutex_unlock(&priv->mutex);
184 return ret;
185}
186EXPORT_SYMBOL(iwl_legacy_mac_config);
187
188void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw)
189{
190 struct iwl_priv *priv = hw->priv;
191 unsigned long flags;
192 /* IBSS can only be the IWL_RXON_CTX_BSS context */
193 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
194
195 if (WARN_ON(!priv->cfg->ops->legacy))
196 return;
197
198 mutex_lock(&priv->mutex);
199 IWL_DEBUG_MAC80211(priv, "enter\n");
200
201 spin_lock_irqsave(&priv->lock, flags);
202 memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config));
203 spin_unlock_irqrestore(&priv->lock, flags);
204
205 spin_lock_irqsave(&priv->lock, flags);
206
207 /* new association get rid of ibss beacon skb */
208 if (priv->beacon_skb)
209 dev_kfree_skb(priv->beacon_skb);
210
211 priv->beacon_skb = NULL;
212
213 priv->timestamp = 0;
214
215 spin_unlock_irqrestore(&priv->lock, flags);
216
217 iwl_scan_cancel_timeout(priv, 100);
218 if (!iwl_is_ready_rf(priv)) {
219 IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
220 mutex_unlock(&priv->mutex);
221 return;
222 }
223
224 /* we are restarting association process
225 * clear RXON_FILTER_ASSOC_MSK bit
226 */
227 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
228 iwlcore_commit_rxon(priv, ctx);
229
230 iwl_set_rate(priv);
231
232 mutex_unlock(&priv->mutex);
233
234 IWL_DEBUG_MAC80211(priv, "leave\n");
235}
236EXPORT_SYMBOL(iwl_legacy_mac_reset_tsf);
237
238static void iwl_ht_conf(struct iwl_priv *priv,
239 struct ieee80211_vif *vif)
240{
241 struct iwl_ht_config *ht_conf = &priv->current_ht_config;
242 struct ieee80211_sta *sta;
243 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
244 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
245
246 IWL_DEBUG_ASSOC(priv, "enter:\n");
247
248 if (!ctx->ht.enabled)
249 return;
250
251 ctx->ht.protection =
252 bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
253 ctx->ht.non_gf_sta_present =
254 !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
255
256 ht_conf->single_chain_sufficient = false;
257
258 switch (vif->type) {
259 case NL80211_IFTYPE_STATION:
260 rcu_read_lock();
261 sta = ieee80211_find_sta(vif, bss_conf->bssid);
262 if (sta) {
263 struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
264 int maxstreams;
265
266 maxstreams = (ht_cap->mcs.tx_params &
267 IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
268 >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
269 maxstreams += 1;
270
271 if ((ht_cap->mcs.rx_mask[1] == 0) &&
272 (ht_cap->mcs.rx_mask[2] == 0))
273 ht_conf->single_chain_sufficient = true;
274 if (maxstreams <= 1)
275 ht_conf->single_chain_sufficient = true;
276 } else {
277 /*
278 * If at all, this can only happen through a race
279 * when the AP disconnects us while we're still
280 * setting up the connection, in that case mac80211
281 * will soon tell us about that.
282 */
283 ht_conf->single_chain_sufficient = true;
284 }
285 rcu_read_unlock();
286 break;
287 case NL80211_IFTYPE_ADHOC:
288 ht_conf->single_chain_sufficient = true;
289 break;
290 default:
291 break;
292 }
293
294 IWL_DEBUG_ASSOC(priv, "leave\n");
295}
296
297static void iwl_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
298{
299 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
300 return;
301
302 if (!ctx->is_active)
303 return;
304
305 ctx->qos_data.def_qos_parm.qos_flags = 0;
306
307 if (ctx->qos_data.qos_active)
308 ctx->qos_data.def_qos_parm.qos_flags |=
309 QOS_PARAM_FLG_UPDATE_EDCA_MSK;
310
311 if (ctx->ht.enabled)
312 ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
313
314 IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
315 ctx->qos_data.qos_active,
316 ctx->qos_data.def_qos_parm.qos_flags);
317
318 iwl_send_cmd_pdu_async(priv, ctx->qos_cmd,
319 sizeof(struct iwl_qosparam_cmd),
320 &ctx->qos_data.def_qos_parm, NULL);
321}
322
323static inline void iwl_set_no_assoc(struct iwl_priv *priv,
324 struct ieee80211_vif *vif)
325{
326 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
327
328 iwl_led_disassociate(priv);
329 /*
330 * inform the ucode that there is no longer an
331 * association and that no more packets should be
332 * sent
333 */
334 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
335 ctx->staging.assoc_id = 0;
336 iwlcore_commit_rxon(priv, ctx);
337}
338
339static void iwlcore_beacon_update(struct ieee80211_hw *hw,
340 struct ieee80211_vif *vif)
341{
342 struct iwl_priv *priv = hw->priv;
343 unsigned long flags;
344 __le64 timestamp;
345 struct sk_buff *skb = ieee80211_beacon_get(hw, vif);
346
347 if (!skb)
348 return;
349
350 IWL_DEBUG_MAC80211(priv, "enter\n");
351
352 lockdep_assert_held(&priv->mutex);
353
354 if (!priv->beacon_ctx) {
355 IWL_ERR(priv, "update beacon but no beacon context!\n");
356 dev_kfree_skb(skb);
357 return;
358 }
359
360 spin_lock_irqsave(&priv->lock, flags);
361
362 if (priv->beacon_skb)
363 dev_kfree_skb(priv->beacon_skb);
364
365 priv->beacon_skb = skb;
366
367 timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
368 priv->timestamp = le64_to_cpu(timestamp);
369
370 IWL_DEBUG_MAC80211(priv, "leave\n");
371 spin_unlock_irqrestore(&priv->lock, flags);
372
373 if (!iwl_is_ready_rf(priv)) {
374 IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
375 return;
376 }
377
378 priv->cfg->ops->legacy->post_associate(priv);
379}
380
381void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw,
382 struct ieee80211_vif *vif,
383 struct ieee80211_bss_conf *bss_conf,
384 u32 changes)
385{
386 struct iwl_priv *priv = hw->priv;
387 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
388 int ret;
389
390 if (WARN_ON(!priv->cfg->ops->legacy))
391 return;
392
393 IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes);
394
395 if (!iwl_is_alive(priv))
396 return;
397
398 mutex_lock(&priv->mutex);
399
400 if (changes & BSS_CHANGED_QOS) {
401 unsigned long flags;
402
403 spin_lock_irqsave(&priv->lock, flags);
404 ctx->qos_data.qos_active = bss_conf->qos;
405 iwl_update_qos(priv, ctx);
406 spin_unlock_irqrestore(&priv->lock, flags);
407 }
408
409 if (changes & BSS_CHANGED_BEACON_ENABLED) {
410 /*
411 * the add_interface code must make sure we only ever
412 * have a single interface that could be beaconing at
413 * any time.
414 */
415 if (vif->bss_conf.enable_beacon)
416 priv->beacon_ctx = ctx;
417 else
418 priv->beacon_ctx = NULL;
419 }
420
421 if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) {
422 dev_kfree_skb(priv->beacon_skb);
423 priv->beacon_skb = ieee80211_beacon_get(hw, vif);
424 }
425
426 if (changes & BSS_CHANGED_BEACON_INT && vif->type == NL80211_IFTYPE_AP)
427 iwl_send_rxon_timing(priv, ctx);
428
429 if (changes & BSS_CHANGED_BSSID) {
430 IWL_DEBUG_MAC80211(priv, "BSSID %pM\n", bss_conf->bssid);
431
432 /*
433 * If there is currently a HW scan going on in the
434 * background then we need to cancel it else the RXON
435 * below/in post_associate will fail.
436 */
437 if (iwl_scan_cancel_timeout(priv, 100)) {
438 IWL_WARN(priv, "Aborted scan still in progress after 100ms\n");
439 IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n");
440 mutex_unlock(&priv->mutex);
441 return;
442 }
443
444 /* mac80211 only sets assoc when in STATION mode */
445 if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) {
446 memcpy(ctx->staging.bssid_addr,
447 bss_conf->bssid, ETH_ALEN);
448
449 /* currently needed in a few places */
450 memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
451 } else {
452 ctx->staging.filter_flags &=
453 ~RXON_FILTER_ASSOC_MSK;
454 }
455
456 }
457
458 /*
459 * This needs to be after setting the BSSID in case
460 * mac80211 decides to do both changes at once because
461 * it will invoke post_associate.
462 */
463 if (vif->type == NL80211_IFTYPE_ADHOC && changes & BSS_CHANGED_BEACON)
464 iwlcore_beacon_update(hw, vif);
465
466 if (changes & BSS_CHANGED_ERP_PREAMBLE) {
467 IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n",
468 bss_conf->use_short_preamble);
469 if (bss_conf->use_short_preamble)
470 ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
471 else
472 ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
473 }
474
475 if (changes & BSS_CHANGED_ERP_CTS_PROT) {
476 IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot);
477 if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
478 ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
479 else
480 ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
481 if (bss_conf->use_cts_prot)
482 ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
483 else
484 ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
485 }
486
487 if (changes & BSS_CHANGED_BASIC_RATES) {
488 /* XXX use this information
489 *
490 * To do that, remove code from iwl_set_rate() and put something
491 * like this here:
492 *
493 if (A-band)
494 ctx->staging.ofdm_basic_rates =
495 bss_conf->basic_rates;
496 else
497 ctx->staging.ofdm_basic_rates =
498 bss_conf->basic_rates >> 4;
499 ctx->staging.cck_basic_rates =
500 bss_conf->basic_rates & 0xF;
501 */
502 }
503
504 if (changes & BSS_CHANGED_HT) {
505 iwl_ht_conf(priv, vif);
506
507 if (priv->cfg->ops->hcmd->set_rxon_chain)
508 priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
509 }
510
511 if (changes & BSS_CHANGED_ASSOC) {
512 IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc);
513 if (bss_conf->assoc) {
514 priv->timestamp = bss_conf->timestamp;
515
516 iwl_led_associate(priv);
517
518 if (!iwl_is_rfkill(priv))
519 priv->cfg->ops->legacy->post_associate(priv);
520 } else
521 iwl_set_no_assoc(priv, vif);
522 }
523
524 if (changes && iwl_is_associated_ctx(ctx) && bss_conf->aid) {
525 IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n",
526 changes);
527 ret = iwl_send_rxon_assoc(priv, ctx);
528 if (!ret) {
529 /* Sync active_rxon with latest change. */
530 memcpy((void *)&ctx->active,
531 &ctx->staging,
532 sizeof(struct iwl_rxon_cmd));
533 }
534 }
535
536 if (changes & BSS_CHANGED_BEACON_ENABLED) {
537 if (vif->bss_conf.enable_beacon) {
538 memcpy(ctx->staging.bssid_addr,
539 bss_conf->bssid, ETH_ALEN);
540 memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
541 iwl_led_associate(priv);
542 priv->cfg->ops->legacy->config_ap(priv);
543 } else
544 iwl_set_no_assoc(priv, vif);
545 }
546
547 if (changes & BSS_CHANGED_IBSS) {
548 ret = priv->cfg->ops->legacy->manage_ibss_station(priv, vif,
549 bss_conf->ibss_joined);
550 if (ret)
551 IWL_ERR(priv, "failed to %s IBSS station %pM\n",
552 bss_conf->ibss_joined ? "add" : "remove",
553 bss_conf->bssid);
554 }
555
556 mutex_unlock(&priv->mutex);
557
558 IWL_DEBUG_MAC80211(priv, "leave\n");
559}
560EXPORT_SYMBOL(iwl_legacy_mac_bss_info_changed);