iwl3945-base.c 136 KB
Newer Older
1
2
/******************************************************************************
 *
3
 * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * Portions of this file are derived from the ipw3945 project, as well
 * as portions of the ieee80211 subsystem header files.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
 *
 * The full GNU General Public License is included in this distribution in the
 * file called LICENSE.
 *
 * Contact Information:
25
 *  Intel Linux Wireless <ilw@linux.intel.com>
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *
 *****************************************************************************/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <linux/firmware.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>

#include <net/ieee80211_radiotap.h>
44
#include <net/lib80211.h>
45
46
47
48
#include <net/mac80211.h>

#include <asm/div64.h>

49
50
#define DRV_NAME	"iwl3945"

Winkler, Tomas's avatar
Winkler, Tomas committed
51
52
#include "iwl-fh.h"
#include "iwl-3945-fh.h"
53
#include "iwl-commands.h"
54
#include "iwl-sta.h"
55
56
#include "iwl-3945.h"
#include "iwl-helpers.h"
57
#include "iwl-core.h"
58
#include "iwl-dev.h"
59
60
61
62
63
64
65
66

/*
 * module name, copyright, version, etc.
 */

#define DRV_DESCRIPTION	\
"Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux"

Samuel Ortiz's avatar
Samuel Ortiz committed
67
#ifdef CONFIG_IWLWIFI_DEBUG
68
69
70
71
72
#define VD "d"
#else
#define VD
#endif

73
#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
74
75
76
77
78
#define VS "s"
#else
#define VS
#endif

79
#define IWL39_VERSION "1.2.26k" VD VS
80
#define DRV_COPYRIGHT	"Copyright(c) 2003-2009 Intel Corporation"
81
#define DRV_AUTHOR     "<ilw@linux.intel.com>"
82
#define DRV_VERSION     IWL39_VERSION
83
84
85
86


MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
87
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
88
89
MODULE_LICENSE("GPL");

90
91
92
 /* module parameters */
struct iwl_mod_params iwl3945_mod_params = {
	.num_of_queues = IWL39_MAX_NUM_QUEUES,
93
	.sw_crypto = 1,
94
	.restart_fw = 1,
95
96
97
	/* the rest are 0 by default */
};

98
/*************** STATION TABLE MANAGEMENT ****
99
 * mac80211 should be examined to determine if sta_info is duplicating
100
101
102
103
 * the functionality provided here
 */

/**************************************************************/
104
#if 0 /* temporary disable till we add real remove station */
105
106
107
108
109
/**
 * iwl3945_remove_station - Remove driver's knowledge of station.
 *
 * NOTE:  This does not remove station from device's station table.
 */
110
static u8 iwl3945_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
111
112
113
114
115
116
117
118
119
120
{
	int index = IWL_INVALID_STATION;
	int i;
	unsigned long flags;

	spin_lock_irqsave(&priv->sta_lock, flags);

	if (is_ap)
		index = IWL_AP_ID;
	else if (is_broadcast_ether_addr(addr))
121
		index = priv->hw_params.bcast_sta_id;
122
	else
123
		for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
124
125
			if (priv->stations_39[i].used &&
			    !compare_ether_addr(priv->stations_39[i].sta.sta.addr,
126
127
128
129
130
131
132
133
						addr)) {
				index = i;
				break;
			}

	if (unlikely(index == IWL_INVALID_STATION))
		goto out;

134
135
	if (priv->stations_39[index].used) {
		priv->stations_39[index].used = 0;
136
137
138
139
140
141
142
143
144
		priv->num_stations--;
	}

	BUG_ON(priv->num_stations < 0);

out:
	spin_unlock_irqrestore(&priv->sta_lock, flags);
	return 0;
}
145
#endif
146
147
148
149
150
151

/**
 * iwl3945_clear_stations_table - Clear the driver's station table
 *
 * NOTE:  This does not clear or otherwise alter the device's station table.
 */
152
void iwl3945_clear_stations_table(struct iwl_priv *priv)
153
154
155
156
157
158
{
	unsigned long flags;

	spin_lock_irqsave(&priv->sta_lock, flags);

	priv->num_stations = 0;
159
	memset(priv->stations_39, 0, sizeof(priv->stations_39));
160
161
162
163

	spin_unlock_irqrestore(&priv->sta_lock, flags);
}

164
165
166
/**
 * iwl3945_add_station - Add station to station tables in driver and device
 */
167
u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags)
168
169
170
{
	int i;
	int index = IWL_INVALID_STATION;
Christoph Hellwig's avatar
Christoph Hellwig committed
171
	struct iwl3945_station_entry *station;
172
	unsigned long flags_spin;
173
	u8 rate;
174
175
176
177
178

	spin_lock_irqsave(&priv->sta_lock, flags_spin);
	if (is_ap)
		index = IWL_AP_ID;
	else if (is_broadcast_ether_addr(addr))
179
		index = priv->hw_params.bcast_sta_id;
180
	else
181
		for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
182
			if (!compare_ether_addr(priv->stations_39[i].sta.sta.addr,
183
184
185
186
187
						addr)) {
				index = i;
				break;
			}

188
			if (!priv->stations_39[i].used &&
189
190
191
192
			    index == IWL_INVALID_STATION)
				index = i;
		}

193
	/* These two conditions has the same outcome but keep them separate
194
195
196
197
198
199
	  since they have different meaning */
	if (unlikely(index == IWL_INVALID_STATION)) {
		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
		return index;
	}

200
201
	if (priv->stations_39[index].used &&
	   !compare_ether_addr(priv->stations_39[index].sta.sta.addr, addr)) {
202
203
204
205
		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
		return index;
	}

206
	IWL_DEBUG_ASSOC(priv, "Add STA ID %d: %pM\n", index, addr);
207
	station = &priv->stations_39[index];
208
209
210
	station->used = 1;
	priv->num_stations++;

211
	/* Set up the REPLY_ADD_STA command to send to device */
Christoph Hellwig's avatar
Christoph Hellwig committed
212
	memset(&station->sta, 0, sizeof(struct iwl3945_addsta_cmd));
213
214
215
216
217
	memcpy(station->sta.sta.addr, addr, ETH_ALEN);
	station->sta.mode = 0;
	station->sta.sta.sta_id = index;
	station->sta.station_flags = 0;

218
	if (priv->band == IEEE80211_BAND_5GHZ)
219
220
221
		rate = IWL_RATE_6M_PLCP;
	else
		rate =	IWL_RATE_1M_PLCP;
222
223
224

	/* Turn on both antennas for the station... */
	station->sta.rate_n_flags =
Christoph Hellwig's avatar
Christoph Hellwig committed
225
			iwl3945_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK);
226

227
	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
228
229

	/* Add station to device's station table */
230
231
	iwl_send_add_sta(priv,
			 (struct iwl_addsta_cmd *)&station->sta, flags);
232
233
234
235
	return index;

}

236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
/**
 * iwl3945_get_antenna_flags - Get antenna flags for RXON command
 * @priv: eeprom and antenna fields are used to determine antenna flags
 *
 * priv->eeprom39  is used to determine if antenna AUX/MAIN are reversed
 * iwl3945_mod_params.antenna specifies the antenna diversity mode:
 *
 * IWL_ANTENNA_DIVERSITY - NIC selects best antenna by itself
 * IWL_ANTENNA_MAIN      - Force MAIN antenna
 * IWL_ANTENNA_AUX       - Force AUX antenna
 */
__le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv)
{
	struct iwl3945_eeprom *eeprom = (struct iwl3945_eeprom *)priv->eeprom;

	switch (iwl3945_mod_params.antenna) {
	case IWL_ANTENNA_DIVERSITY:
		return 0;

	case IWL_ANTENNA_MAIN:
		if (eeprom->antenna_switch_type)
			return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK;
		return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK;

	case IWL_ANTENNA_AUX:
		if (eeprom->antenna_switch_type)
			return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK;
		return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK;
	}

	/* bad antenna selector value */
	IWL_ERR(priv, "Bad antenna selector value (0x%x)\n",
		iwl3945_mod_params.antenna);

	return 0;		/* "diversity" is default if error */
}

273
static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
274
275
276
277
278
				   struct ieee80211_key_conf *keyconf,
				   u8 sta_id)
{
	unsigned long flags;
	__le16 key_flags = 0;
279
280
281
282
283
284
285
286
287
288
289
	int ret;

	key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
	key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);

	if (sta_id == priv->hw_params.bcast_sta_id)
		key_flags |= STA_KEY_MULTICAST_MSK;

	keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
	keyconf->hw_key_idx = keyconf->keyidx;
	key_flags &= ~STA_KEY_FLG_INVALID;
290
291

	spin_lock_irqsave(&priv->sta_lock, flags);
292
293
294
	priv->stations_39[sta_id].keyinfo.alg = keyconf->alg;
	priv->stations_39[sta_id].keyinfo.keylen = keyconf->keylen;
	memcpy(priv->stations_39[sta_id].keyinfo.key, keyconf->key,
295
296
	       keyconf->keylen);

297
	memcpy(priv->stations_39[sta_id].sta.key.key, keyconf->key,
298
	       keyconf->keylen);
299

300
	if ((priv->stations_39[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
301
			== STA_KEY_FLG_NO_ENC)
302
		priv->stations_39[sta_id].sta.key.key_offset =
303
304
305
306
				 iwl_get_free_ucode_key_index(priv);
	/* else, we are overriding an existing key => no need to allocated room
	* in uCode. */

307
	WARN(priv->stations_39[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
308
309
		"no space for a new key");

310
311
312
	priv->stations_39[sta_id].sta.key.key_flags = key_flags;
	priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
	priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
313

314
315
316
317
318
	IWL_DEBUG_INFO(priv, "hwcrypto: modify ucode station key info\n");

	ret = iwl_send_add_sta(priv,
		(struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, CMD_ASYNC);

319
320
	spin_unlock_irqrestore(&priv->sta_lock, flags);

321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
	return ret;
}

static int iwl3945_set_tkip_dynamic_key_info(struct iwl_priv *priv,
				  struct ieee80211_key_conf *keyconf,
				  u8 sta_id)
{
	return -EOPNOTSUPP;
}

static int iwl3945_set_wep_dynamic_key_info(struct iwl_priv *priv,
				  struct ieee80211_key_conf *keyconf,
				  u8 sta_id)
{
	return -EOPNOTSUPP;
336
337
}

338
static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
339
340
341
342
{
	unsigned long flags;

	spin_lock_irqsave(&priv->sta_lock, flags);
343
344
	memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl3945_hw_key));
	memset(&priv->stations_39[sta_id].sta.key, 0,
345
		sizeof(struct iwl4965_keyinfo));
346
347
348
	priv->stations_39[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
	priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
	priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
349
350
	spin_unlock_irqrestore(&priv->sta_lock, flags);

351
	IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n");
352
353
	iwl_send_add_sta(priv,
		(struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, 0);
354
355
356
	return 0;
}

Abhijeet Kolekar's avatar
Abhijeet Kolekar committed
357
static int iwl3945_set_dynamic_key(struct iwl_priv *priv,
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
			struct ieee80211_key_conf *keyconf, u8 sta_id)
{
	int ret = 0;

	keyconf->hw_key_idx = HW_KEY_DYNAMIC;

	switch (keyconf->alg) {
	case ALG_CCMP:
		ret = iwl3945_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
		break;
	case ALG_TKIP:
		ret = iwl3945_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
		break;
	case ALG_WEP:
		ret = iwl3945_set_wep_dynamic_key_info(priv, keyconf, sta_id);
		break;
	default:
375
		IWL_ERR(priv, "Unknown alg: %s alg = %d\n", __func__, keyconf->alg);
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
		ret = -EINVAL;
	}

	IWL_DEBUG_WEP(priv, "Set dynamic key: alg= %d len=%d idx=%d sta=%d ret=%d\n",
		      keyconf->alg, keyconf->keylen, keyconf->keyidx,
		      sta_id, ret);

	return ret;
}

static int iwl3945_remove_static_key(struct iwl_priv *priv)
{
	int ret = -EOPNOTSUPP;

	return ret;
}

static int iwl3945_set_static_key(struct iwl_priv *priv,
				struct ieee80211_key_conf *key)
{
	if (key->alg == ALG_WEP)
		return -EOPNOTSUPP;

	IWL_ERR(priv, "Static key invalid: alg %d\n", key->alg);
	return -EINVAL;
}

403
static void iwl3945_clear_free_frames(struct iwl_priv *priv)
404
405
406
{
	struct list_head *element;

407
	IWL_DEBUG_INFO(priv, "%d frames on pre-allocated heap on clear.\n",
408
409
410
411
412
		       priv->frames_count);

	while (!list_empty(&priv->free_frames)) {
		element = priv->free_frames.next;
		list_del(element);
Christoph Hellwig's avatar
Christoph Hellwig committed
413
		kfree(list_entry(element, struct iwl3945_frame, list));
414
415
416
417
		priv->frames_count--;
	}

	if (priv->frames_count) {
418
		IWL_WARN(priv, "%d frames still in use.  Did we lose one?\n",
419
420
421
422
423
			    priv->frames_count);
		priv->frames_count = 0;
	}
}

424
static struct iwl3945_frame *iwl3945_get_free_frame(struct iwl_priv *priv)
425
{
Christoph Hellwig's avatar
Christoph Hellwig committed
426
	struct iwl3945_frame *frame;
427
428
429
430
	struct list_head *element;
	if (list_empty(&priv->free_frames)) {
		frame = kzalloc(sizeof(*frame), GFP_KERNEL);
		if (!frame) {
431
			IWL_ERR(priv, "Could not allocate frame!\n");
432
433
434
435
436
437
438
439
440
			return NULL;
		}

		priv->frames_count++;
		return frame;
	}

	element = priv->free_frames.next;
	list_del(element);
Christoph Hellwig's avatar
Christoph Hellwig committed
441
	return list_entry(element, struct iwl3945_frame, list);
442
443
}

444
static void iwl3945_free_frame(struct iwl_priv *priv, struct iwl3945_frame *frame)
445
446
447
448
449
{
	memset(frame, 0, sizeof(*frame));
	list_add(&frame->list, &priv->free_frames);
}

450
unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,
451
				struct ieee80211_hdr *hdr,
452
				int left)
453
454
{

455
	if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
456
457
	    ((priv->iw_mode != NL80211_IFTYPE_ADHOC) &&
	     (priv->iw_mode != NL80211_IFTYPE_AP)))
458
459
460
461
462
463
464
465
466
467
		return 0;

	if (priv->ibss_beacon->len > left)
		return 0;

	memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len);

	return priv->ibss_beacon->len;
}

468
static int iwl3945_send_beacon_cmd(struct iwl_priv *priv)
469
{
Christoph Hellwig's avatar
Christoph Hellwig committed
470
	struct iwl3945_frame *frame;
471
472
473
474
	unsigned int frame_size;
	int rc;
	u8 rate;

Christoph Hellwig's avatar
Christoph Hellwig committed
475
	frame = iwl3945_get_free_frame(priv);
476
477

	if (!frame) {
478
		IWL_ERR(priv, "Could not obtain free frame buffer for beacon "
479
480
481
482
			  "command.\n");
		return -ENOMEM;
	}

483
	rate = iwl_rate_get_lowest_plcp(priv);
484

Christoph Hellwig's avatar
Christoph Hellwig committed
485
	frame_size = iwl3945_hw_get_beacon_cmd(priv, frame, rate);
486

487
	rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
488
489
			      &frame->u.cmd[0]);

Christoph Hellwig's avatar
Christoph Hellwig committed
490
	iwl3945_free_frame(priv, frame);
491
492
493
494

	return rc;
}

495
static void iwl3945_unset_hw_params(struct iwl_priv *priv)
496
{
497
	if (priv->shared_virt)
498
		pci_free_consistent(priv->pci_dev,
Christoph Hellwig's avatar
Christoph Hellwig committed
499
				    sizeof(struct iwl3945_shared),
500
501
				    priv->shared_virt,
				    priv->shared_phys);
502
503
504
}

#define MAX_UCODE_BEACON_INTERVAL	1024
505
#define INTEL_CONN_LISTEN_INTERVAL	cpu_to_le16(0xA)
506

Christoph Hellwig's avatar
Christoph Hellwig committed
507
static __le16 iwl3945_adjust_beacon_interval(u16 beacon_val)
508
509
510
511
512
513
514
515
516
517
518
519
{
	u16 new_val = 0;
	u16 beacon_factor = 0;

	beacon_factor =
	    (beacon_val + MAX_UCODE_BEACON_INTERVAL)
		/ MAX_UCODE_BEACON_INTERVAL;
	new_val = beacon_val / beacon_factor;

	return cpu_to_le16(new_val);
}

520
static void iwl3945_setup_rxon_timing(struct iwl_priv *priv)
521
522
523
524
525
526
527
528
529
530
{
	u64 interval_tm_unit;
	u64 tsf, result;
	unsigned long flags;
	struct ieee80211_conf *conf = NULL;
	u16 beacon_int = 0;

	conf = ieee80211_get_hw_conf(priv->hw);

	spin_lock_irqsave(&priv->lock, flags);
531
	priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
532
533
	priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;

534
	tsf = priv->timestamp;
535
536
537
538

	beacon_int = priv->beacon_int;
	spin_unlock_irqrestore(&priv->lock, flags);

539
	if (priv->iw_mode == NL80211_IFTYPE_STATION) {
540
541
542
543
544
545
546
		if (beacon_int == 0) {
			priv->rxon_timing.beacon_interval = cpu_to_le16(100);
			priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
		} else {
			priv->rxon_timing.beacon_interval =
				cpu_to_le16(beacon_int);
			priv->rxon_timing.beacon_interval =
Christoph Hellwig's avatar
Christoph Hellwig committed
547
			    iwl3945_adjust_beacon_interval(
548
549
550
551
552
553
				le16_to_cpu(priv->rxon_timing.beacon_interval));
		}

		priv->rxon_timing.atim_window = 0;
	} else {
		priv->rxon_timing.beacon_interval =
Christoph Hellwig's avatar
Christoph Hellwig committed
554
			iwl3945_adjust_beacon_interval(conf->beacon_int);
555
556
557
558
559
560
561
562
563
564
565
		/* TODO: we need to get atim_window from upper stack
		 * for now we set to 0 */
		priv->rxon_timing.atim_window = 0;
	}

	interval_tm_unit =
		(le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
	result = do_div(tsf, interval_tm_unit);
	priv->rxon_timing.beacon_init_val =
	    cpu_to_le32((u32) ((u64) interval_tm_unit - result));

566
567
	IWL_DEBUG_ASSOC(priv,
		"beacon interval %d beacon timer %d beacon tim %d\n",
568
569
570
571
572
		le16_to_cpu(priv->rxon_timing.beacon_interval),
		le32_to_cpu(priv->rxon_timing.beacon_init_val),
		le16_to_cpu(priv->rxon_timing.atim_window));
}

573
static int iwl3945_set_mode(struct iwl_priv *priv, int mode)
574
{
575
	if (mode == NL80211_IFTYPE_ADHOC) {
576
		const struct iwl_channel_info *ch_info;
577

578
		ch_info = iwl_get_channel_info(priv,
579
			priv->band,
580
			le16_to_cpu(priv->staging_rxon.channel));
581
582

		if (!ch_info || !is_channel_ibss(ch_info)) {
583
			IWL_ERR(priv, "channel %d not IBSS channel\n",
584
				  le16_to_cpu(priv->staging_rxon.channel));
585
586
587
588
			return -EINVAL;
		}
	}

589
	iwl_connection_init_rx_config(priv, mode);
590

Christoph Hellwig's avatar
Christoph Hellwig committed
591
	iwl3945_clear_stations_table(priv);
592

593
	/* don't commit rxon if rf-kill is on*/
594
	if (!iwl_is_ready_rf(priv))
595
596
597
		return -EAGAIN;

	cancel_delayed_work(&priv->scan_check);
598
	if (iwl_scan_cancel_timeout(priv, 100)) {
599
		IWL_WARN(priv, "Aborted scan still in progress after 100ms\n");
600
		IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n");
601
602
603
		return -EAGAIN;
	}

604
	iwlcore_commit_rxon(priv);
605
606
607
608

	return 0;
}

609
static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
610
				      struct ieee80211_tx_info *info,
611
				      struct iwl_cmd *cmd,
612
				      struct sk_buff *skb_frag,
613
				      int sta_id)
614
{
615
	struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
616
	struct iwl3945_hw_key *keyinfo =
617
	    &priv->stations_39[sta_id].keyinfo;
618
619
620

	switch (keyinfo->alg) {
	case ALG_CCMP:
621
622
		tx->sec_ctl = TX_CMD_SEC_CCM;
		memcpy(tx->key, keyinfo->key, keyinfo->keylen);
623
		IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
624
625
626
627
628
629
		break;

	case ALG_TKIP:
		break;

	case ALG_WEP:
630
		tx->sec_ctl = TX_CMD_SEC_WEP |
631
		    (info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
632
633

		if (keyinfo->keylen == 13)
634
			tx->sec_ctl |= TX_CMD_SEC_KEY128;
635

636
		memcpy(&tx->key[3], keyinfo->key, keyinfo->keylen);
637

638
		IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
639
			     "with key %d\n", info->control.hw_key->hw_key_idx);
640
641
642
		break;

	default:
Tomas Winkler's avatar
Tomas Winkler committed
643
		IWL_ERR(priv, "Unknown encode alg %d\n", keyinfo->alg);
644
645
646
647
648
649
650
		break;
	}
}

/*
 * handle build REPLY_TX command notification.
 */
651
static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
652
				  struct iwl_cmd *cmd,
653
				  struct ieee80211_tx_info *info,
654
				  struct ieee80211_hdr *hdr, u8 std_id)
655
{
656
657
	struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
	__le32 tx_flags = tx->tx_flags;
658
	__le16 fc = hdr->frame_control;
659
	u8 rc_flags = info->control.rates[0].flags;
660

661
	tx->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
662
	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
663
		tx_flags |= TX_CMD_FLG_ACK_MSK;
664
		if (ieee80211_is_mgmt(fc))
665
			tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
666
		if (ieee80211_is_probe_resp(fc) &&
667
668
669
670
671
672
673
		    !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
			tx_flags |= TX_CMD_FLG_TSF_MSK;
	} else {
		tx_flags &= (~TX_CMD_FLG_ACK_MSK);
		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
	}

674
	tx->sta_id = std_id;
675
	if (ieee80211_has_morefrags(fc))
676
677
		tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;

678
679
	if (ieee80211_is_data_qos(fc)) {
		u8 *qc = ieee80211_get_qos_ctl(hdr);
680
		tx->tid_tspec = qc[0] & 0xf;
681
		tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
682
	} else {
683
		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
684
	}
685

686
	if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
687
688
		tx_flags |= TX_CMD_FLG_RTS_MSK;
		tx_flags &= ~TX_CMD_FLG_CTS_MSK;
689
	} else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
690
691
692
693
694
695
696
697
		tx_flags &= ~TX_CMD_FLG_RTS_MSK;
		tx_flags |= TX_CMD_FLG_CTS_MSK;
	}

	if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
		tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;

	tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
698
699
	if (ieee80211_is_mgmt(fc)) {
		if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
700
			tx->timeout.pm_frame_timeout = cpu_to_le16(3);
701
		else
702
			tx->timeout.pm_frame_timeout = cpu_to_le16(2);
Mohamed Abbas's avatar
Mohamed Abbas committed
703
	} else {
704
		tx->timeout.pm_frame_timeout = 0;
705
#ifdef CONFIG_IWLWIFI_LEDS
Mohamed Abbas's avatar
Mohamed Abbas committed
706
707
708
		priv->rxtxpackets += le16_to_cpu(cmd->cmd.tx.len);
#endif
	}
709

710
711
712
	tx->driver_txop = 0;
	tx->tx_flags = tx_flags;
	tx->next_frame_len = 0;
713
714
}

715
716
717
/**
 * iwl3945_get_sta_id - Find station's index within station table
 */
718
static int iwl3945_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
719
720
721
722
{
	int sta_id;
	u16 fc = le16_to_cpu(hdr->frame_control);

723
	/* If this frame is broadcast or management, use broadcast station id */
724
725
	if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
	    is_multicast_ether_addr(hdr->addr1))
726
		return priv->hw_params.bcast_sta_id;
727
728
729

	switch (priv->iw_mode) {

730
731
	/* If we are a client station in a BSS network, use the special
	 * AP station entry (that's the only station we communicate with) */
732
	case NL80211_IFTYPE_STATION:
733
734
735
		return IWL_AP_ID;

	/* If we are an AP, then find the station, or use BCAST */
736
	case NL80211_IFTYPE_AP:
Christoph Hellwig's avatar
Christoph Hellwig committed
737
		sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
738
739
		if (sta_id != IWL_INVALID_STATION)
			return sta_id;
740
		return priv->hw_params.bcast_sta_id;
741

742
743
	/* If this frame is going out to an IBSS network, find the station,
	 * or create a new station table entry */
744
	case NL80211_IFTYPE_ADHOC: {
745
		/* Create new station table entry */
Christoph Hellwig's avatar
Christoph Hellwig committed
746
		sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
747
748
749
		if (sta_id != IWL_INVALID_STATION)
			return sta_id;

Christoph Hellwig's avatar
Christoph Hellwig committed
750
		sta_id = iwl3945_add_station(priv, hdr->addr1, 0, CMD_ASYNC);
751
752
753
754

		if (sta_id != IWL_INVALID_STATION)
			return sta_id;

755
		IWL_DEBUG_DROP(priv, "Station %pM not in station map. "
756
			       "Defaulting to broadcast...\n",
Johannes Berg's avatar
Johannes Berg committed
757
			       hdr->addr1);
758
		iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
759
		return priv->hw_params.bcast_sta_id;
760
	}
761
762
	/* If we are in monitor mode, use BCAST. This is required for
	 * packet injection. */
763
	case NL80211_IFTYPE_MONITOR:
764
		return priv->hw_params.bcast_sta_id;
765

766
	default:
767
768
		IWL_WARN(priv, "Unknown mode of operation: %d\n",
			priv->iw_mode);
769
		return priv->hw_params.bcast_sta_id;
770
771
772
773
774
775
	}
}

/*
 * start REPLY_TX command process
 */
776
static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
777
778
{
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
779
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
780
	struct iwl3945_tx_cmd *tx;
781
	struct iwl_tx_queue *txq = NULL;
782
	struct iwl_queue *q = NULL;
783
	struct iwl_cmd *out_cmd = NULL;
784
785
	dma_addr_t phys_addr;
	dma_addr_t txcmd_phys;
786
	int txq_id = skb_get_queue_mapping(skb);
787
788
789
	u16 len, idx, len_org, hdr_len;
	u8 id;
	u8 unicast;
790
	u8 sta_id;
791
	u8 tid = 0;
792
	u16 seq_number = 0;
793
	__le16 fc;
794
	u8 wait_write_ptr = 0;
795
	u8 *qc = NULL;
796
797
798
799
	unsigned long flags;
	int rc;

	spin_lock_irqsave(&priv->lock, flags);
800
	if (iwl_is_rfkill(priv)) {
801
		IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
802
803
804
		goto drop_unlock;
	}

805
	if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == IWL_INVALID_RATE) {
806
		IWL_ERR(priv, "ERROR: No TX rate available.\n");
807
808
809
810
811
812
		goto drop_unlock;
	}

	unicast = !is_multicast_ether_addr(hdr->addr1);
	id = 0;

813
	fc = hdr->frame_control;
814

Samuel Ortiz's avatar
Samuel Ortiz committed
815
#ifdef CONFIG_IWLWIFI_DEBUG
816
	if (ieee80211_is_auth(fc))
817
		IWL_DEBUG_TX(priv, "Sending AUTH frame\n");
818
	else if (ieee80211_is_assoc_req(fc))
819
		IWL_DEBUG_TX(priv, "Sending ASSOC frame\n");
820
	else if (ieee80211_is_reassoc_req(fc))
821
		IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
822
823
#endif

824
	/* drop all data frame if we are not associated */
825
	if (ieee80211_is_data(fc) &&
826
	    (priv->iw_mode != NL80211_IFTYPE_MONITOR) && /* packet injection */
827
	    (!iwl_is_associated(priv) ||
828
	     ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id))) {
829
		IWL_DEBUG_DROP(priv, "Dropping - !iwl_is_associated\n");
830
831
832
833
834
		goto drop_unlock;
	}

	spin_unlock_irqrestore(&priv->lock, flags);

835
	hdr_len = ieee80211_hdrlen(fc);
836
837

	/* Find (or create) index into station table for destination station */
Christoph Hellwig's avatar
Christoph Hellwig committed
838
	sta_id = iwl3945_get_sta_id(priv, hdr);
839
	if (sta_id == IWL_INVALID_STATION) {
840
		IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
Johannes Berg's avatar
Johannes Berg committed
841
			       hdr->addr1);
842
843
844
		goto drop;
	}

845
	IWL_DEBUG_RATE(priv, "station Id %d\n", sta_id);
846

847
848
	if (ieee80211_is_data_qos(fc)) {
		qc = ieee80211_get_qos_ctl(hdr);
849
		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
850
		seq_number = priv->stations_39[sta_id].tid[tid].seq_number &
851
852
853
				IEEE80211_SCTL_SEQ;
		hdr->seq_ctrl = cpu_to_le16(seq_number) |
			(hdr->seq_ctrl &
854
				cpu_to_le16(IEEE80211_SCTL_FRAG));
855
856
		seq_number += 0x10;
	}
857
858

	/* Descriptor for chosen Tx queue */
859
	txq = &priv->txq[txq_id];
860
861
862
863
	q = &txq->q;

	spin_lock_irqsave(&priv->lock, flags);

864
	idx = get_cmd_index(q, q->write_ptr, 0);
865

866
	/* Set up driver data for this TFD */
Winkler, Tomas's avatar
Winkler, Tomas committed
867
	memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
868
	txq->txb[q->write_ptr].skb[0] = skb;
869
870

	/* Init first empty entry in queue's array of Tx/cmd buffers */
871
	out_cmd = txq->cmd[idx];
872
	tx = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload;
873
	memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
874
	memset(tx, 0, sizeof(*tx));
875
876
877
878
879
880
881

	/*
	 * Set up the Tx-command (not MAC!) header.
	 * Store the chosen Tx queue and TFD index within the sequence field;
	 * after Tx, uCode's Tx response will return this value so driver can
	 * locate the frame within the tx queue and do post-tx processing.
	 */
882
883
	out_cmd->hdr.cmd = REPLY_TX;
	out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
884
				INDEX_TO_SEQ(q->write_ptr)));
885
886

	/* Copy MAC header from skb into command buffer */
887
	memcpy(tx->hdr, hdr, hdr_len);
888

889
890
891
892
893
894
895
896
897
	/*
	 * Use the first empty entry in this queue's command buffer array
	 * to contain the Tx command and MAC header concatenated together
	 * (payload data will be in another buffer).
	 * Size of this varies, due to varying MAC header length.
	 * If end is not dword aligned, we'll have 2 extra bytes at the end
	 * of the MAC header (device reads on dword boundaries).
	 * We'll tell device about this padding later.
	 */
898
	len = sizeof(struct iwl3945_tx_cmd) +
899
			sizeof(struct iwl_cmd_header) + hdr_len;
900
901
902
903
904
905
906
907
908

	len_org = len;
	len = (len + 3) & ~3;

	if (len_org != len)
		len_org = 1;
	else
		len_org = 0;

909
910
	/* Physical address of this Tx command's header (not MAC header!),
	 * within command buffer array. */
911
912
913
914
915
916
917
918
	txcmd_phys = pci_map_single(priv->pci_dev,
				    out_cmd, sizeof(struct iwl_cmd),
				    PCI_DMA_TODEVICE);
	pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys);
	pci_unmap_len_set(&out_cmd->meta, len, sizeof(struct iwl_cmd));
	/* Add buffer containing Tx command and MAC(!) header to TFD's
	 * first entry */
	txcmd_phys += offsetof(struct iwl_cmd, hdr);
919

920
921
	/* Add buffer containing Tx command and MAC(!) header to TFD's
	 * first entry */
922
923
	priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
						   txcmd_phys, len, 1, 0);
924

925
	if (info->control.hw_key)
926
		iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, sta_id);
927

928
929
	/* Set up TFD's 2nd entry to point directly to remainder of skb,
	 * if any (802.11 null frames have no payload). */
930
931
932
933
	len = skb->len - hdr_len;
	if (len) {
		phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
					   len, PCI_DMA_TODEVICE);
934
935
936
		priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
							   phys_addr, len,
							   0, U32_PAD(len));
937
938
	}

939
	/* Total # bytes to be transmitted */
940
	len = (u16)skb->len;
941
	tx->len = cpu_to_le16(len);
942
943

	/* TODO need this for burst mode later on */
944
	iwl3945_build_tx_cmd_basic(priv, out_cmd, info, hdr, sta_id);
945
946

	/* set is_hcca to 0; it probably will never be implemented */
947
	iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, info, hdr, sta_id, 0);
948

949
950
	tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
	tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
951

952
	if (!ieee80211_has_morefrags(hdr->frame_control)) {
953
		txq->need_update = 1;
954
		if (qc)
955
			priv->stations_39[sta_id].tid[tid].seq_number = seq_number;
956
957
958
959
960
	} else {
		wait_write_ptr = 1;
		txq->need_update = 0;
	}

961
	iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx));
962

963
	iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr,
964
			   ieee80211_hdrlen(fc));
965

966
	/* Tell device the write index *just past* this latest filled TFD */
967
	q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
968
	rc = iwl_txq_update_write_ptr(priv, txq);
969
970
971
972
973
	spin_unlock_irqrestore(&priv->lock, flags);

	if (rc)
		return rc;

974
	if ((iwl_queue_space(q) < q->high_mark)
975
976
977
978
	    && priv->mac80211_registered) {
		if (wait_write_ptr) {
			spin_lock_irqsave(&priv->lock, flags);
			txq->need_update = 1;
979
			iwl_txq_update_write_ptr(priv, txq);
980
981
982
			spin_unlock_irqrestore(&priv->lock, flags);
		}

983
		iwl_stop_queue(priv, skb_get_queue_mapping(skb));
984
985
986
987
988
989
990
991
992
993
	}

	return 0;

drop_unlock:
	spin_unlock_irqrestore(&priv->lock, flags);
drop:
	return -1;
}

994
#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
995
996
997
998
999
1000

#include "iwl-spectrum.h"

#define BEACON_TIME_MASK_LOW	0x00FFFFFF
#define BEACON_TIME_MASK_HIGH	0xFF000000
#define TIME_UNIT		1024
For faster browsing, not all history is shown. View entire blame