blob: 10d9c420287508dc10b6f5a0212590aa62996ddb [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"
Wey-Yi Guy81baf6e2010-11-10 09:56:39 -080034#include "iwl-helpers.h"
Johannes Berg2295c662010-10-23 09:15:41 -070035#include "iwl-legacy.h"
36
37/**
38 * iwl_legacy_mac_config - mac80211 config callback
39 */
40int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed)
41{
42 struct iwl_priv *priv = hw->priv;
43 const struct iwl_channel_info *ch_info;
44 struct ieee80211_conf *conf = &hw->conf;
45 struct ieee80211_channel *channel = conf->channel;
46 struct iwl_ht_config *ht_conf = &priv->current_ht_config;
47 struct iwl_rxon_context *ctx;
48 unsigned long flags = 0;
49 int ret = 0;
50 u16 ch;
51 int scan_active = 0;
52
53 if (WARN_ON(!priv->cfg->ops->legacy))
54 return -EOPNOTSUPP;
55
56 mutex_lock(&priv->mutex);
57
58 IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n",
59 channel->hw_value, changed);
60
61 if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
62 test_bit(STATUS_SCANNING, &priv->status))) {
63 scan_active = 1;
64 IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
65 }
66
67 if (changed & (IEEE80211_CONF_CHANGE_SMPS |
68 IEEE80211_CONF_CHANGE_CHANNEL)) {
69 /* mac80211 uses static for non-HT which is what we want */
70 priv->current_ht_config.smps = conf->smps_mode;
71
72 /*
73 * Recalculate chain counts.
74 *
75 * If monitor mode is enabled then mac80211 will
76 * set up the SM PS mode to OFF if an HT channel is
77 * configured.
78 */
79 if (priv->cfg->ops->hcmd->set_rxon_chain)
80 for_each_context(priv, ctx)
81 priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
82 }
83
84 /* during scanning mac80211 will delay channel setting until
85 * scan finish with changed = 0
86 */
87 if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
88 if (scan_active)
89 goto set_ch_out;
90
91 ch = channel->hw_value;
92 ch_info = iwl_get_channel_info(priv, channel->band, ch);
93 if (!is_channel_valid(ch_info)) {
94 IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
95 ret = -EINVAL;
96 goto set_ch_out;
97 }
98
99 spin_lock_irqsave(&priv->lock, flags);
100
101 for_each_context(priv, ctx) {
102 /* Configure HT40 channels */
103 ctx->ht.enabled = conf_is_ht(conf);
104 if (ctx->ht.enabled) {
105 if (conf_is_ht40_minus(conf)) {
106 ctx->ht.extension_chan_offset =
107 IEEE80211_HT_PARAM_CHA_SEC_BELOW;
108 ctx->ht.is_40mhz = true;
109 } else if (conf_is_ht40_plus(conf)) {
110 ctx->ht.extension_chan_offset =
111 IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
112 ctx->ht.is_40mhz = true;
113 } else {
114 ctx->ht.extension_chan_offset =
115 IEEE80211_HT_PARAM_CHA_SEC_NONE;
116 ctx->ht.is_40mhz = false;
117 }
118 } else
119 ctx->ht.is_40mhz = false;
120
121 /*
122 * Default to no protection. Protection mode will
123 * later be set from BSS config in iwl_ht_conf
124 */
125 ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
126
127 /* if we are switching from ht to 2.4 clear flags
128 * from any ht related info since 2.4 does not
129 * support ht */
130 if ((le16_to_cpu(ctx->staging.channel) != ch))
131 ctx->staging.flags = 0;
132
133 iwl_set_rxon_channel(priv, channel, ctx);
134 iwl_set_rxon_ht(priv, ht_conf);
135
136 iwl_set_flags_for_band(priv, ctx, channel->band,
137 ctx->vif);
138 }
139
140 spin_unlock_irqrestore(&priv->lock, flags);
141
142 if (priv->cfg->ops->legacy->update_bcast_stations)
143 ret = priv->cfg->ops->legacy->update_bcast_stations(priv);
144
145 set_ch_out:
146 /* The list of supported rates and rate mask can be different
147 * for each band; since the band may have changed, reset
148 * the rate mask to what mac80211 lists */
149 iwl_set_rate(priv);
150 }
151
152 if (changed & (IEEE80211_CONF_CHANGE_PS |
153 IEEE80211_CONF_CHANGE_IDLE)) {
154 ret = iwl_power_update_mode(priv, false);
155 if (ret)
156 IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n");
157 }
158
159 if (changed & IEEE80211_CONF_CHANGE_POWER) {
160 IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n",
161 priv->tx_power_user_lmt, conf->power_level);
162
163 iwl_set_tx_power(priv, conf->power_level, false);
164 }
165
166 if (!iwl_is_ready(priv)) {
167 IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
168 goto out;
169 }
170
171 if (scan_active)
172 goto out;
173
174 for_each_context(priv, ctx) {
175 if (memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)))
176 iwlcore_commit_rxon(priv, ctx);
177 else
178 IWL_DEBUG_INFO(priv,
179 "Not re-sending same RXON configuration.\n");
180 }
181
182out:
183 IWL_DEBUG_MAC80211(priv, "leave\n");
184 mutex_unlock(&priv->mutex);
185 return ret;
186}
187EXPORT_SYMBOL(iwl_legacy_mac_config);
188
189void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw)
190{
191 struct iwl_priv *priv = hw->priv;
192 unsigned long flags;
193 /* IBSS can only be the IWL_RXON_CTX_BSS context */
194 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
195
196 if (WARN_ON(!priv->cfg->ops->legacy))
197 return;
198
199 mutex_lock(&priv->mutex);
200 IWL_DEBUG_MAC80211(priv, "enter\n");
201
202 spin_lock_irqsave(&priv->lock, flags);
203 memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config));
204 spin_unlock_irqrestore(&priv->lock, flags);
205
206 spin_lock_irqsave(&priv->lock, flags);
207
208 /* new association get rid of ibss beacon skb */
209 if (priv->beacon_skb)
210 dev_kfree_skb(priv->beacon_skb);
211
212 priv->beacon_skb = NULL;
213
214 priv->timestamp = 0;
215
216 spin_unlock_irqrestore(&priv->lock, flags);
217
218 iwl_scan_cancel_timeout(priv, 100);
219 if (!iwl_is_ready_rf(priv)) {
220 IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
221 mutex_unlock(&priv->mutex);
222 return;
223 }
224
225 /* we are restarting association process
226 * clear RXON_FILTER_ASSOC_MSK bit
227 */
228 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
229 iwlcore_commit_rxon(priv, ctx);
230
231 iwl_set_rate(priv);
232
233 mutex_unlock(&priv->mutex);
234
235 IWL_DEBUG_MAC80211(priv, "leave\n");
236}
237EXPORT_SYMBOL(iwl_legacy_mac_reset_tsf);
238
239static void iwl_ht_conf(struct iwl_priv *priv,
240 struct ieee80211_vif *vif)
241{
242 struct iwl_ht_config *ht_conf = &priv->current_ht_config;
243 struct ieee80211_sta *sta;
244 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
245 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
246
247 IWL_DEBUG_ASSOC(priv, "enter:\n");
248
249 if (!ctx->ht.enabled)
250 return;
251
252 ctx->ht.protection =
253 bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
254 ctx->ht.non_gf_sta_present =
255 !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
256
257 ht_conf->single_chain_sufficient = false;
258
259 switch (vif->type) {
260 case NL80211_IFTYPE_STATION:
261 rcu_read_lock();
262 sta = ieee80211_find_sta(vif, bss_conf->bssid);
263 if (sta) {
264 struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
265 int maxstreams;
266
267 maxstreams = (ht_cap->mcs.tx_params &
268 IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
269 >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
270 maxstreams += 1;
271
272 if ((ht_cap->mcs.rx_mask[1] == 0) &&
273 (ht_cap->mcs.rx_mask[2] == 0))
274 ht_conf->single_chain_sufficient = true;
275 if (maxstreams <= 1)
276 ht_conf->single_chain_sufficient = true;
277 } else {
278 /*
279 * If at all, this can only happen through a race
280 * when the AP disconnects us while we're still
281 * setting up the connection, in that case mac80211
282 * will soon tell us about that.
283 */
284 ht_conf->single_chain_sufficient = true;
285 }
286 rcu_read_unlock();
287 break;
288 case NL80211_IFTYPE_ADHOC:
289 ht_conf->single_chain_sufficient = true;
290 break;
291 default:
292 break;
293 }
294
295 IWL_DEBUG_ASSOC(priv, "leave\n");
296}
297
298static void iwl_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
299{
300 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
301 return;
302
303 if (!ctx->is_active)
304 return;
305
306 ctx->qos_data.def_qos_parm.qos_flags = 0;
307
308 if (ctx->qos_data.qos_active)
309 ctx->qos_data.def_qos_parm.qos_flags |=
310 QOS_PARAM_FLG_UPDATE_EDCA_MSK;
311
312 if (ctx->ht.enabled)
313 ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
314
315 IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
316 ctx->qos_data.qos_active,
317 ctx->qos_data.def_qos_parm.qos_flags);
318
319 iwl_send_cmd_pdu_async(priv, ctx->qos_cmd,
320 sizeof(struct iwl_qosparam_cmd),
321 &ctx->qos_data.def_qos_parm, NULL);
322}
323
324static inline void iwl_set_no_assoc(struct iwl_priv *priv,
325 struct ieee80211_vif *vif)
326{
327 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
328
329 iwl_led_disassociate(priv);
330 /*
331 * inform the ucode that there is no longer an
332 * association and that no more packets should be
333 * sent
334 */
335 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
336 ctx->staging.assoc_id = 0;
337 iwlcore_commit_rxon(priv, ctx);
338}
339
340static void iwlcore_beacon_update(struct ieee80211_hw *hw,
341 struct ieee80211_vif *vif)
342{
343 struct iwl_priv *priv = hw->priv;
344 unsigned long flags;
345 __le64 timestamp;
346 struct sk_buff *skb = ieee80211_beacon_get(hw, vif);
347
348 if (!skb)
349 return;
350
351 IWL_DEBUG_MAC80211(priv, "enter\n");
352
353 lockdep_assert_held(&priv->mutex);
354
355 if (!priv->beacon_ctx) {
356 IWL_ERR(priv, "update beacon but no beacon context!\n");
357 dev_kfree_skb(skb);
358 return;
359 }
360
361 spin_lock_irqsave(&priv->lock, flags);
362
363 if (priv->beacon_skb)
364 dev_kfree_skb(priv->beacon_skb);
365
366 priv->beacon_skb = skb;
367
368 timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
369 priv->timestamp = le64_to_cpu(timestamp);
370
371 IWL_DEBUG_MAC80211(priv, "leave\n");
372 spin_unlock_irqrestore(&priv->lock, flags);
373
374 if (!iwl_is_ready_rf(priv)) {
375 IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
376 return;
377 }
378
379 priv->cfg->ops->legacy->post_associate(priv);
380}
381
382void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw,
383 struct ieee80211_vif *vif,
384 struct ieee80211_bss_conf *bss_conf,
385 u32 changes)
386{
387 struct iwl_priv *priv = hw->priv;
388 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
389 int ret;
390
391 if (WARN_ON(!priv->cfg->ops->legacy))
392 return;
393
394 IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes);
395
396 if (!iwl_is_alive(priv))
397 return;
398
399 mutex_lock(&priv->mutex);
400
401 if (changes & BSS_CHANGED_QOS) {
402 unsigned long flags;
403
404 spin_lock_irqsave(&priv->lock, flags);
405 ctx->qos_data.qos_active = bss_conf->qos;
406 iwl_update_qos(priv, ctx);
407 spin_unlock_irqrestore(&priv->lock, flags);
408 }
409
410 if (changes & BSS_CHANGED_BEACON_ENABLED) {
411 /*
412 * the add_interface code must make sure we only ever
413 * have a single interface that could be beaconing at
414 * any time.
415 */
416 if (vif->bss_conf.enable_beacon)
417 priv->beacon_ctx = ctx;
418 else
419 priv->beacon_ctx = NULL;
420 }
421
422 if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) {
423 dev_kfree_skb(priv->beacon_skb);
424 priv->beacon_skb = ieee80211_beacon_get(hw, vif);
425 }
426
427 if (changes & BSS_CHANGED_BEACON_INT && vif->type == NL80211_IFTYPE_AP)
428 iwl_send_rxon_timing(priv, ctx);
429
430 if (changes & BSS_CHANGED_BSSID) {
431 IWL_DEBUG_MAC80211(priv, "BSSID %pM\n", bss_conf->bssid);
432
433 /*
434 * If there is currently a HW scan going on in the
435 * background then we need to cancel it else the RXON
436 * below/in post_associate will fail.
437 */
438 if (iwl_scan_cancel_timeout(priv, 100)) {
439 IWL_WARN(priv, "Aborted scan still in progress after 100ms\n");
440 IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n");
441 mutex_unlock(&priv->mutex);
442 return;
443 }
444
445 /* mac80211 only sets assoc when in STATION mode */
446 if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) {
447 memcpy(ctx->staging.bssid_addr,
448 bss_conf->bssid, ETH_ALEN);
449
450 /* currently needed in a few places */
451 memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
452 } else {
453 ctx->staging.filter_flags &=
454 ~RXON_FILTER_ASSOC_MSK;
455 }
456
457 }
458
459 /*
460 * This needs to be after setting the BSSID in case
461 * mac80211 decides to do both changes at once because
462 * it will invoke post_associate.
463 */
464 if (vif->type == NL80211_IFTYPE_ADHOC && changes & BSS_CHANGED_BEACON)
465 iwlcore_beacon_update(hw, vif);
466
467 if (changes & BSS_CHANGED_ERP_PREAMBLE) {
468 IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n",
469 bss_conf->use_short_preamble);
470 if (bss_conf->use_short_preamble)
471 ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
472 else
473 ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
474 }
475
476 if (changes & BSS_CHANGED_ERP_CTS_PROT) {
477 IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot);
478 if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
479 ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
480 else
481 ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
482 if (bss_conf->use_cts_prot)
483 ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
484 else
485 ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
486 }
487
488 if (changes & BSS_CHANGED_BASIC_RATES) {
489 /* XXX use this information
490 *
491 * To do that, remove code from iwl_set_rate() and put something
492 * like this here:
493 *
494 if (A-band)
495 ctx->staging.ofdm_basic_rates =
496 bss_conf->basic_rates;
497 else
498 ctx->staging.ofdm_basic_rates =
499 bss_conf->basic_rates >> 4;
500 ctx->staging.cck_basic_rates =
501 bss_conf->basic_rates & 0xF;
502 */
503 }
504
505 if (changes & BSS_CHANGED_HT) {
506 iwl_ht_conf(priv, vif);
507
508 if (priv->cfg->ops->hcmd->set_rxon_chain)
509 priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
510 }
511
512 if (changes & BSS_CHANGED_ASSOC) {
513 IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc);
514 if (bss_conf->assoc) {
515 priv->timestamp = bss_conf->timestamp;
516
517 iwl_led_associate(priv);
518
519 if (!iwl_is_rfkill(priv))
520 priv->cfg->ops->legacy->post_associate(priv);
521 } else
522 iwl_set_no_assoc(priv, vif);
523 }
524
525 if (changes && iwl_is_associated_ctx(ctx) && bss_conf->aid) {
526 IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n",
527 changes);
528 ret = iwl_send_rxon_assoc(priv, ctx);
529 if (!ret) {
530 /* Sync active_rxon with latest change. */
531 memcpy((void *)&ctx->active,
532 &ctx->staging,
533 sizeof(struct iwl_rxon_cmd));
534 }
535 }
536
537 if (changes & BSS_CHANGED_BEACON_ENABLED) {
538 if (vif->bss_conf.enable_beacon) {
539 memcpy(ctx->staging.bssid_addr,
540 bss_conf->bssid, ETH_ALEN);
541 memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
542 iwl_led_associate(priv);
543 priv->cfg->ops->legacy->config_ap(priv);
544 } else
545 iwl_set_no_assoc(priv, vif);
546 }
547
548 if (changes & BSS_CHANGED_IBSS) {
549 ret = priv->cfg->ops->legacy->manage_ibss_station(priv, vif,
550 bss_conf->ibss_joined);
551 if (ret)
552 IWL_ERR(priv, "failed to %s IBSS station %pM\n",
553 bss_conf->ibss_joined ? "add" : "remove",
554 bss_conf->bssid);
555 }
556
557 mutex_unlock(&priv->mutex);
558
559 IWL_DEBUG_MAC80211(priv, "leave\n");
560}
561EXPORT_SYMBOL(iwl_legacy_mac_bss_info_changed);
Wey-Yi Guy81baf6e2010-11-10 09:56:39 -0800562
563irqreturn_t iwl_isr_legacy(int irq, void *data)
564{
565 struct iwl_priv *priv = data;
566 u32 inta, inta_mask;
567 u32 inta_fh;
568 unsigned long flags;
569 if (!priv)
570 return IRQ_NONE;
571
572 spin_lock_irqsave(&priv->lock, flags);
573
574 /* Disable (but don't clear!) interrupts here to avoid
575 * back-to-back ISRs and sporadic interrupts from our NIC.
576 * If we have something to service, the tasklet will re-enable ints.
577 * If we *don't* have something, we'll re-enable before leaving here. */
578 inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
579 iwl_write32(priv, CSR_INT_MASK, 0x00000000);
580
581 /* Discover which interrupts are active/pending */
582 inta = iwl_read32(priv, CSR_INT);
583 inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
584
585 /* Ignore interrupt if there's nothing in NIC to service.
586 * This may be due to IRQ shared with another device,
587 * or due to sporadic interrupts thrown from our NIC. */
588 if (!inta && !inta_fh) {
589 IWL_DEBUG_ISR(priv,
590 "Ignore interrupt, inta == 0, inta_fh == 0\n");
591 goto none;
592 }
593
594 if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
595 /* Hardware disappeared. It might have already raised
596 * an interrupt */
597 IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
598 goto unplugged;
599 }
600
601 IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
602 inta, inta_mask, inta_fh);
603
604 inta &= ~CSR_INT_BIT_SCD;
605
606 /* iwl_irq_tasklet() will service interrupts and re-enable them */
607 if (likely(inta || inta_fh))
608 tasklet_schedule(&priv->irq_tasklet);
609
610unplugged:
611 spin_unlock_irqrestore(&priv->lock, flags);
612 return IRQ_HANDLED;
613
614none:
615 /* re-enable interrupts here since we don't have anything to service. */
616 /* only Re-enable if diabled by irq */
617 if (test_bit(STATUS_INT_ENABLED, &priv->status))
618 iwl_enable_interrupts(priv);
619 spin_unlock_irqrestore(&priv->lock, flags);
620 return IRQ_NONE;
621}
622EXPORT_SYMBOL(iwl_isr_legacy);
Wey-Yi Guy708068d2010-11-10 09:56:41 -0800623
624/*
625 * iwl_legacy_tx_cmd_protection: Set rts/cts. 3945 and 4965 only share this
626 * function.
627 */
628void iwl_legacy_tx_cmd_protection(struct iwl_priv *priv,
629 struct ieee80211_tx_info *info,
630 __le16 fc, __le32 *tx_flags)
631{
632 if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
633 *tx_flags |= TX_CMD_FLG_RTS_MSK;
634 *tx_flags &= ~TX_CMD_FLG_CTS_MSK;
635 *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
636
637 if (!ieee80211_is_mgmt(fc))
638 return;
639
640 switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
641 case cpu_to_le16(IEEE80211_STYPE_AUTH):
642 case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
643 case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
644 case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
645 *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
646 *tx_flags |= TX_CMD_FLG_CTS_MSK;
647 break;
648 }
649 } else if (info->control.rates[0].flags &
650 IEEE80211_TX_RC_USE_CTS_PROTECT) {
651 *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
652 *tx_flags |= TX_CMD_FLG_CTS_MSK;
653 *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
654 }
655}
656EXPORT_SYMBOL(iwl_legacy_tx_cmd_protection);