blob: 76cd1036e2d264cddcc8a121ad8739044a0c4671 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*======================================================================
2
3 Aironet driver for 4500 and 4800 series cards
4
5 This code is released under both the GPL version 2 and BSD licenses.
6 Either license may be used. The respective licenses are found at
7 the end of this file.
8
9 This code was developed by Benjamin Reed <breed@users.sourceforge.net>
10 including portions of which come from the Aironet PC4500
11 Developer's Reference Manual and used with permission. Copyright
12 (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use
13 code in the Developer's manual was granted for this driver by
14 Aironet. Major code contributions were received from Javier Achirica
15 <achirica@users.sourceforge.net> and Jean Tourrilhes <jt@hpl.hp.com>.
16 Code was also integrated from the Cisco Aironet driver for Linux.
17 Support for MPI350 cards was added by Fabrice Bellet
18 <fabrice@bellet.info>.
19
20======================================================================*/
21
Herbert Xuf12cc202006-08-22 20:36:13 +100022#include <linux/err.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/init.h>
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
29#include <linux/sched.h>
30#include <linux/ptrace.h>
31#include <linux/slab.h>
32#include <linux/string.h>
33#include <linux/timer.h>
34#include <linux/interrupt.h>
35#include <linux/in.h>
36#include <linux/bitops.h>
David Hardeman378f0582005-09-17 17:55:31 +100037#include <linux/scatterlist.h>
Adrian Bunka39d3e72006-01-21 01:35:15 +010038#include <linux/crypto.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <asm/io.h>
40#include <asm/system.h>
Al Viro593c2b92007-12-17 15:09:34 -050041#include <asm/unaligned.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43#include <linux/netdevice.h>
44#include <linux/etherdevice.h>
45#include <linux/skbuff.h>
46#include <linux/if_arp.h>
47#include <linux/ioport.h>
48#include <linux/pci.h>
49#include <asm/uaccess.h>
Dan Williams3c304952006-04-15 12:26:18 -040050#include <net/ieee80211.h>
Sukadev Bhattiprolu3b4c7d642006-08-14 23:12:03 -070051#include <linux/kthread.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080052#include <linux/freezer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Adrian Bunkd3808762005-11-05 17:42:27 +010054#include "airo.h"
55
Michal Schmidt1138c372007-06-29 15:33:41 +020056#define DRV_NAME "airo"
57
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#ifdef CONFIG_PCI
59static struct pci_device_id card_ids[] = {
60 { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, },
61 { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID },
62 { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, },
63 { 0x14b9, 0x0340, PCI_ANY_ID, PCI_ANY_ID, },
64 { 0x14b9, 0x0350, PCI_ANY_ID, PCI_ANY_ID, },
65 { 0x14b9, 0x5000, PCI_ANY_ID, PCI_ANY_ID, },
66 { 0x14b9, 0xa504, PCI_ANY_ID, PCI_ANY_ID, },
67 { 0, }
68};
69MODULE_DEVICE_TABLE(pci, card_ids);
70
71static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *);
72static void airo_pci_remove(struct pci_dev *);
Pavel Machek05adc3b2005-04-16 15:25:25 -070073static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074static int airo_pci_resume(struct pci_dev *pdev);
75
76static struct pci_driver airo_driver = {
Michal Schmidt1138c372007-06-29 15:33:41 +020077 .name = DRV_NAME,
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 .id_table = card_ids,
79 .probe = airo_pci_probe,
80 .remove = __devexit_p(airo_pci_remove),
81 .suspend = airo_pci_suspend,
82 .resume = airo_pci_resume,
83};
84#endif /* CONFIG_PCI */
85
86/* Include Wireless Extension definition and check version - Jean II */
87#include <linux/wireless.h>
88#define WIRELESS_SPY // enable iwspy support
89#include <net/iw_handler.h> // New driver API
90
91#define CISCO_EXT // enable Cisco extensions
92#ifdef CISCO_EXT
93#include <linux/delay.h>
94#endif
95
Linus Torvalds1da177e2005-04-16 15:20:36 -070096/* Hack to do some power saving */
97#define POWER_ON_DOWN
98
99/* As you can see this list is HUGH!
100 I really don't know what a lot of these counts are about, but they
101 are all here for completeness. If the IGNLABEL macro is put in
102 infront of the label, that statistic will not be included in the list
103 of statistics in the /proc filesystem */
104
105#define IGNLABEL(comment) NULL
106static char *statsLabels[] = {
107 "RxOverrun",
108 IGNLABEL("RxPlcpCrcErr"),
109 IGNLABEL("RxPlcpFormatErr"),
110 IGNLABEL("RxPlcpLengthErr"),
111 "RxMacCrcErr",
112 "RxMacCrcOk",
113 "RxWepErr",
114 "RxWepOk",
115 "RetryLong",
116 "RetryShort",
117 "MaxRetries",
118 "NoAck",
119 "NoCts",
120 "RxAck",
121 "RxCts",
122 "TxAck",
123 "TxRts",
124 "TxCts",
125 "TxMc",
126 "TxBc",
127 "TxUcFrags",
128 "TxUcPackets",
129 "TxBeacon",
130 "RxBeacon",
131 "TxSinColl",
132 "TxMulColl",
133 "DefersNo",
134 "DefersProt",
135 "DefersEngy",
136 "DupFram",
137 "RxFragDisc",
138 "TxAged",
139 "RxAged",
140 "LostSync-MaxRetry",
141 "LostSync-MissedBeacons",
142 "LostSync-ArlExceeded",
143 "LostSync-Deauth",
144 "LostSync-Disassoced",
145 "LostSync-TsfTiming",
146 "HostTxMc",
147 "HostTxBc",
148 "HostTxUc",
149 "HostTxFail",
150 "HostRxMc",
151 "HostRxBc",
152 "HostRxUc",
153 "HostRxDiscard",
154 IGNLABEL("HmacTxMc"),
155 IGNLABEL("HmacTxBc"),
156 IGNLABEL("HmacTxUc"),
157 IGNLABEL("HmacTxFail"),
158 IGNLABEL("HmacRxMc"),
159 IGNLABEL("HmacRxBc"),
160 IGNLABEL("HmacRxUc"),
161 IGNLABEL("HmacRxDiscard"),
162 IGNLABEL("HmacRxAccepted"),
163 "SsidMismatch",
164 "ApMismatch",
165 "RatesMismatch",
166 "AuthReject",
167 "AuthTimeout",
168 "AssocReject",
169 "AssocTimeout",
170 IGNLABEL("ReasonOutsideTable"),
171 IGNLABEL("ReasonStatus1"),
172 IGNLABEL("ReasonStatus2"),
173 IGNLABEL("ReasonStatus3"),
174 IGNLABEL("ReasonStatus4"),
175 IGNLABEL("ReasonStatus5"),
176 IGNLABEL("ReasonStatus6"),
177 IGNLABEL("ReasonStatus7"),
178 IGNLABEL("ReasonStatus8"),
179 IGNLABEL("ReasonStatus9"),
180 IGNLABEL("ReasonStatus10"),
181 IGNLABEL("ReasonStatus11"),
182 IGNLABEL("ReasonStatus12"),
183 IGNLABEL("ReasonStatus13"),
184 IGNLABEL("ReasonStatus14"),
185 IGNLABEL("ReasonStatus15"),
186 IGNLABEL("ReasonStatus16"),
187 IGNLABEL("ReasonStatus17"),
188 IGNLABEL("ReasonStatus18"),
189 IGNLABEL("ReasonStatus19"),
190 "RxMan",
191 "TxMan",
192 "RxRefresh",
193 "TxRefresh",
194 "RxPoll",
195 "TxPoll",
196 "HostRetries",
197 "LostSync-HostReq",
198 "HostTxBytes",
199 "HostRxBytes",
200 "ElapsedUsec",
201 "ElapsedSec",
202 "LostSyncBetterAP",
203 "PrivacyMismatch",
204 "Jammed",
205 "DiscRxNotWepped",
206 "PhyEleMismatch",
207 (char*)-1 };
208#ifndef RUN_AT
209#define RUN_AT(x) (jiffies+(x))
210#endif
211
212
213/* These variables are for insmod, since it seems that the rates
214 can only be set in setup_card. Rates should be a comma separated
215 (no spaces) list of rates (up to 8). */
216
217static int rates[8];
218static int basic_rate;
219static char *ssids[3];
220
221static int io[4];
222static int irq[4];
223
224static
225int maxencrypt /* = 0 */; /* The highest rate that the card can encrypt at.
226 0 means no limit. For old cards this was 4 */
227
228static int auto_wep /* = 0 */; /* If set, it tries to figure out the wep mode */
229static int aux_bap /* = 0 */; /* Checks to see if the aux ports are needed to read
230 the bap, needed on some older cards and buses. */
231static int adhoc;
232
233static int probe = 1;
234
235static int proc_uid /* = 0 */;
236
237static int proc_gid /* = 0 */;
238
239static int airo_perm = 0555;
240
241static int proc_perm = 0644;
242
243MODULE_AUTHOR("Benjamin Reed");
244MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \
Bill Nottinghamd73ae552007-07-27 19:43:17 -0400245cards. Direct support for ISA/PCI/MPI cards and support \
246for PCMCIA when used with airo_cs.");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247MODULE_LICENSE("Dual BSD/GPL");
248MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350");
249module_param_array(io, int, NULL, 0);
250module_param_array(irq, int, NULL, 0);
251module_param(basic_rate, int, 0);
252module_param_array(rates, int, NULL, 0);
253module_param_array(ssids, charp, NULL, 0);
254module_param(auto_wep, int, 0);
255MODULE_PARM_DESC(auto_wep, "If non-zero, the driver will keep looping through \
256the authentication options until an association is made. The value of \
257auto_wep is number of the wep keys to check. A value of 2 will try using \
258the key at index 0 and index 1.");
259module_param(aux_bap, int, 0);
260MODULE_PARM_DESC(aux_bap, "If non-zero, the driver will switch into a mode \
261than seems to work better for older cards with some older buses. Before \
262switching it checks that the switch is needed.");
263module_param(maxencrypt, int, 0);
264MODULE_PARM_DESC(maxencrypt, "The maximum speed that the card can do \
265encryption. Units are in 512kbs. Zero (default) means there is no limit. \
266Older cards used to be limited to 2mbs (4).");
267module_param(adhoc, int, 0);
268MODULE_PARM_DESC(adhoc, "If non-zero, the card will start in adhoc mode.");
269module_param(probe, int, 0);
270MODULE_PARM_DESC(probe, "If zero, the driver won't start the card.");
271
272module_param(proc_uid, int, 0);
273MODULE_PARM_DESC(proc_uid, "The uid that the /proc files will belong to.");
274module_param(proc_gid, int, 0);
275MODULE_PARM_DESC(proc_gid, "The gid that the /proc files will belong to.");
276module_param(airo_perm, int, 0);
277MODULE_PARM_DESC(airo_perm, "The permission bits of /proc/[driver/]aironet.");
278module_param(proc_perm, int, 0);
279MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc");
280
281/* This is a kind of sloppy hack to get this information to OUT4500 and
282 IN4500. I would be extremely interested in the situation where this
283 doesn't work though!!! */
284static int do8bitIO = 0;
285
286/* Return codes */
287#define SUCCESS 0
288#define ERROR -1
289#define NO_PACKET -2
290
291/* Commands */
292#define NOP2 0x0000
293#define MAC_ENABLE 0x0001
294#define MAC_DISABLE 0x0002
295#define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */
296#define CMD_SOFTRESET 0x0004
297#define HOSTSLEEP 0x0005
298#define CMD_MAGIC_PKT 0x0006
299#define CMD_SETWAKEMASK 0x0007
300#define CMD_READCFG 0x0008
301#define CMD_SETMODE 0x0009
302#define CMD_ALLOCATETX 0x000a
303#define CMD_TRANSMIT 0x000b
304#define CMD_DEALLOCATETX 0x000c
305#define NOP 0x0010
306#define CMD_WORKAROUND 0x0011
307#define CMD_ALLOCATEAUX 0x0020
308#define CMD_ACCESS 0x0021
309#define CMD_PCIBAP 0x0022
310#define CMD_PCIAUX 0x0023
311#define CMD_ALLOCBUF 0x0028
312#define CMD_GETTLV 0x0029
313#define CMD_PUTTLV 0x002a
314#define CMD_DELTLV 0x002b
315#define CMD_FINDNEXTTLV 0x002c
316#define CMD_PSPNODES 0x0030
317#define CMD_SETCW 0x0031
318#define CMD_SETPCF 0x0032
319#define CMD_SETPHYREG 0x003e
320#define CMD_TXTEST 0x003f
321#define MAC_ENABLETX 0x0101
322#define CMD_LISTBSS 0x0103
323#define CMD_SAVECFG 0x0108
324#define CMD_ENABLEAUX 0x0111
325#define CMD_WRITERID 0x0121
326#define CMD_USEPSPNODES 0x0130
327#define MAC_ENABLERX 0x0201
328
329/* Command errors */
330#define ERROR_QUALIF 0x00
331#define ERROR_ILLCMD 0x01
332#define ERROR_ILLFMT 0x02
333#define ERROR_INVFID 0x03
334#define ERROR_INVRID 0x04
335#define ERROR_LARGE 0x05
336#define ERROR_NDISABL 0x06
337#define ERROR_ALLOCBSY 0x07
338#define ERROR_NORD 0x0B
339#define ERROR_NOWR 0x0C
340#define ERROR_INVFIDTX 0x0D
341#define ERROR_TESTACT 0x0E
342#define ERROR_TAGNFND 0x12
343#define ERROR_DECODE 0x20
344#define ERROR_DESCUNAV 0x21
345#define ERROR_BADLEN 0x22
346#define ERROR_MODE 0x80
347#define ERROR_HOP 0x81
348#define ERROR_BINTER 0x82
349#define ERROR_RXMODE 0x83
350#define ERROR_MACADDR 0x84
351#define ERROR_RATES 0x85
352#define ERROR_ORDER 0x86
353#define ERROR_SCAN 0x87
354#define ERROR_AUTH 0x88
355#define ERROR_PSMODE 0x89
356#define ERROR_RTYPE 0x8A
357#define ERROR_DIVER 0x8B
358#define ERROR_SSID 0x8C
359#define ERROR_APLIST 0x8D
360#define ERROR_AUTOWAKE 0x8E
361#define ERROR_LEAP 0x8F
362
363/* Registers */
364#define COMMAND 0x00
365#define PARAM0 0x02
366#define PARAM1 0x04
367#define PARAM2 0x06
368#define STATUS 0x08
369#define RESP0 0x0a
370#define RESP1 0x0c
371#define RESP2 0x0e
372#define LINKSTAT 0x10
373#define SELECT0 0x18
374#define OFFSET0 0x1c
375#define RXFID 0x20
376#define TXALLOCFID 0x22
377#define TXCOMPLFID 0x24
378#define DATA0 0x36
379#define EVSTAT 0x30
380#define EVINTEN 0x32
381#define EVACK 0x34
382#define SWS0 0x28
383#define SWS1 0x2a
384#define SWS2 0x2c
385#define SWS3 0x2e
386#define AUXPAGE 0x3A
387#define AUXOFF 0x3C
388#define AUXDATA 0x3E
389
390#define FID_TX 1
391#define FID_RX 2
392/* Offset into aux memory for descriptors */
393#define AUX_OFFSET 0x800
394/* Size of allocated packets */
395#define PKTSIZE 1840
396#define RIDSIZE 2048
397/* Size of the transmit queue */
398#define MAXTXQ 64
399
400/* BAP selectors */
401#define BAP0 0 // Used for receiving packets
402#define BAP1 2 // Used for xmiting packets and working with RIDS
403
404/* Flags */
405#define COMMAND_BUSY 0x8000
406
407#define BAP_BUSY 0x8000
408#define BAP_ERR 0x4000
409#define BAP_DONE 0x2000
410
411#define PROMISC 0xffff
412#define NOPROMISC 0x0000
413
414#define EV_CMD 0x10
415#define EV_CLEARCOMMANDBUSY 0x4000
416#define EV_RX 0x01
417#define EV_TX 0x02
418#define EV_TXEXC 0x04
419#define EV_ALLOC 0x08
420#define EV_LINK 0x80
421#define EV_AWAKE 0x100
422#define EV_TXCPY 0x400
423#define EV_UNKNOWN 0x800
424#define EV_MIC 0x1000 /* Message Integrity Check Interrupt */
425#define EV_AWAKEN 0x2000
426#define STATUS_INTS (EV_AWAKE|EV_LINK|EV_TXEXC|EV_TX|EV_TXCPY|EV_RX|EV_MIC)
427
428#ifdef CHECK_UNKNOWN_INTS
429#define IGNORE_INTS ( EV_CMD | EV_UNKNOWN)
430#else
431#define IGNORE_INTS (~STATUS_INTS)
432#endif
433
434/* RID TYPES */
435#define RID_RW 0x20
436
437/* The RIDs */
438#define RID_CAPABILITIES 0xFF00
439#define RID_APINFO 0xFF01
440#define RID_RADIOINFO 0xFF02
441#define RID_UNKNOWN3 0xFF03
442#define RID_RSSI 0xFF04
443#define RID_CONFIG 0xFF10
444#define RID_SSID 0xFF11
445#define RID_APLIST 0xFF12
446#define RID_DRVNAME 0xFF13
447#define RID_ETHERENCAP 0xFF14
448#define RID_WEP_TEMP 0xFF15
449#define RID_WEP_PERM 0xFF16
450#define RID_MODULATION 0xFF17
451#define RID_OPTIONS 0xFF18
452#define RID_ACTUALCONFIG 0xFF20 /*readonly*/
453#define RID_FACTORYCONFIG 0xFF21
454#define RID_UNKNOWN22 0xFF22
455#define RID_LEAPUSERNAME 0xFF23
456#define RID_LEAPPASSWORD 0xFF24
457#define RID_STATUS 0xFF50
458#define RID_BEACON_HST 0xFF51
459#define RID_BUSY_HST 0xFF52
460#define RID_RETRIES_HST 0xFF53
461#define RID_UNKNOWN54 0xFF54
462#define RID_UNKNOWN55 0xFF55
463#define RID_UNKNOWN56 0xFF56
464#define RID_MIC 0xFF57
465#define RID_STATS16 0xFF60
466#define RID_STATS16DELTA 0xFF61
467#define RID_STATS16DELTACLEAR 0xFF62
468#define RID_STATS 0xFF68
469#define RID_STATSDELTA 0xFF69
470#define RID_STATSDELTACLEAR 0xFF6A
471#define RID_ECHOTEST_RID 0xFF70
472#define RID_ECHOTEST_RESULTS 0xFF71
473#define RID_BSSLISTFIRST 0xFF72
474#define RID_BSSLISTNEXT 0xFF73
Dan Williams3c304952006-04-15 12:26:18 -0400475#define RID_WPA_BSSLISTFIRST 0xFF74
476#define RID_WPA_BSSLISTNEXT 0xFF75
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477
478typedef struct {
479 u16 cmd;
480 u16 parm0;
481 u16 parm1;
482 u16 parm2;
483} Cmd;
484
485typedef struct {
486 u16 status;
487 u16 rsp0;
488 u16 rsp1;
489 u16 rsp2;
490} Resp;
491
492/*
493 * Rids and endian-ness: The Rids will always be in cpu endian, since
494 * this all the patches from the big-endian guys end up doing that.
495 * so all rid access should use the read/writeXXXRid routines.
496 */
497
498/* This is redundant for x86 archs, but it seems necessary for ARM */
499#pragma pack(1)
500
501/* This structure came from an email sent to me from an engineer at
502 aironet for inclusion into this driver */
503typedef struct {
504 u16 len;
505 u16 kindex;
506 u8 mac[ETH_ALEN];
507 u16 klen;
508 u8 key[16];
509} WepKeyRid;
510
511/* These structures are from the Aironet's PC4500 Developers Manual */
512typedef struct {
513 u16 len;
514 u8 ssid[32];
515} Ssid;
516
517typedef struct {
518 u16 len;
519 Ssid ssids[3];
520} SsidRid;
521
522typedef struct {
523 u16 len;
524 u16 modulation;
525#define MOD_DEFAULT 0
526#define MOD_CCK 1
527#define MOD_MOK 2
528} ModulationRid;
529
530typedef struct {
531 u16 len; /* sizeof(ConfigRid) */
532 u16 opmode; /* operating mode */
533#define MODE_STA_IBSS 0
534#define MODE_STA_ESS 1
535#define MODE_AP 2
536#define MODE_AP_RPTR 3
537#define MODE_ETHERNET_HOST (0<<8) /* rx payloads converted */
538#define MODE_LLC_HOST (1<<8) /* rx payloads left as is */
539#define MODE_AIRONET_EXTEND (1<<9) /* enable Aironet extenstions */
540#define MODE_AP_INTERFACE (1<<10) /* enable ap interface extensions */
541#define MODE_ANTENNA_ALIGN (1<<11) /* enable antenna alignment */
542#define MODE_ETHER_LLC (1<<12) /* enable ethernet LLC */
543#define MODE_LEAF_NODE (1<<13) /* enable leaf node bridge */
544#define MODE_CF_POLLABLE (1<<14) /* enable CF pollable */
545#define MODE_MIC (1<<15) /* enable MIC */
546 u16 rmode; /* receive mode */
547#define RXMODE_BC_MC_ADDR 0
548#define RXMODE_BC_ADDR 1 /* ignore multicasts */
549#define RXMODE_ADDR 2 /* ignore multicast and broadcast */
550#define RXMODE_RFMON 3 /* wireless monitor mode */
551#define RXMODE_RFMON_ANYBSS 4
552#define RXMODE_LANMON 5 /* lan style monitor -- data packets only */
553#define RXMODE_DISABLE_802_3_HEADER (1<<8) /* disables 802.3 header on rx */
554#define RXMODE_NORMALIZED_RSSI (1<<9) /* return normalized RSSI */
555 u16 fragThresh;
556 u16 rtsThres;
557 u8 macAddr[ETH_ALEN];
558 u8 rates[8];
559 u16 shortRetryLimit;
560 u16 longRetryLimit;
561 u16 txLifetime; /* in kusec */
562 u16 rxLifetime; /* in kusec */
563 u16 stationary;
564 u16 ordering;
565 u16 u16deviceType; /* for overriding device type */
566 u16 cfpRate;
567 u16 cfpDuration;
568 u16 _reserved1[3];
569 /*---------- Scanning/Associating ----------*/
570 u16 scanMode;
571#define SCANMODE_ACTIVE 0
572#define SCANMODE_PASSIVE 1
573#define SCANMODE_AIROSCAN 2
574 u16 probeDelay; /* in kusec */
575 u16 probeEnergyTimeout; /* in kusec */
576 u16 probeResponseTimeout;
577 u16 beaconListenTimeout;
578 u16 joinNetTimeout;
579 u16 authTimeout;
580 u16 authType;
581#define AUTH_OPEN 0x1
582#define AUTH_ENCRYPT 0x101
583#define AUTH_SHAREDKEY 0x102
584#define AUTH_ALLOW_UNENCRYPTED 0x200
585 u16 associationTimeout;
586 u16 specifiedApTimeout;
587 u16 offlineScanInterval;
588 u16 offlineScanDuration;
589 u16 linkLossDelay;
590 u16 maxBeaconLostTime;
591 u16 refreshInterval;
592#define DISABLE_REFRESH 0xFFFF
593 u16 _reserved1a[1];
594 /*---------- Power save operation ----------*/
595 u16 powerSaveMode;
596#define POWERSAVE_CAM 0
597#define POWERSAVE_PSP 1
598#define POWERSAVE_PSPCAM 2
599 u16 sleepForDtims;
600 u16 listenInterval;
601 u16 fastListenInterval;
602 u16 listenDecay;
603 u16 fastListenDelay;
604 u16 _reserved2[2];
605 /*---------- Ap/Ibss config items ----------*/
606 u16 beaconPeriod;
607 u16 atimDuration;
608 u16 hopPeriod;
609 u16 channelSet;
610 u16 channel;
611 u16 dtimPeriod;
612 u16 bridgeDistance;
613 u16 radioID;
614 /*---------- Radio configuration ----------*/
615 u16 radioType;
616#define RADIOTYPE_DEFAULT 0
617#define RADIOTYPE_802_11 1
618#define RADIOTYPE_LEGACY 2
619 u8 rxDiversity;
620 u8 txDiversity;
621 u16 txPower;
622#define TXPOWER_DEFAULT 0
623 u16 rssiThreshold;
624#define RSSI_DEFAULT 0
625 u16 modulation;
626#define PREAMBLE_AUTO 0
627#define PREAMBLE_LONG 1
628#define PREAMBLE_SHORT 2
629 u16 preamble;
630 u16 homeProduct;
631 u16 radioSpecific;
632 /*---------- Aironet Extensions ----------*/
633 u8 nodeName[16];
634 u16 arlThreshold;
635 u16 arlDecay;
636 u16 arlDelay;
637 u16 _reserved4[1];
638 /*---------- Aironet Extensions ----------*/
639 u8 magicAction;
640#define MAGIC_ACTION_STSCHG 1
641#define MAGIC_ACTION_RESUME 2
642#define MAGIC_IGNORE_MCAST (1<<8)
643#define MAGIC_IGNORE_BCAST (1<<9)
644#define MAGIC_SWITCH_TO_PSP (0<<10)
645#define MAGIC_STAY_IN_CAM (1<<10)
646 u8 magicControl;
647 u16 autoWake;
648} ConfigRid;
649
650typedef struct {
651 u16 len;
652 u8 mac[ETH_ALEN];
653 u16 mode;
654 u16 errorCode;
655 u16 sigQuality;
656 u16 SSIDlen;
657 char SSID[32];
658 char apName[16];
659 u8 bssid[4][ETH_ALEN];
660 u16 beaconPeriod;
661 u16 dimPeriod;
662 u16 atimDuration;
663 u16 hopPeriod;
664 u16 channelSet;
665 u16 channel;
666 u16 hopsToBackbone;
667 u16 apTotalLoad;
668 u16 generatedLoad;
669 u16 accumulatedArl;
670 u16 signalQuality;
671 u16 currentXmitRate;
672 u16 apDevExtensions;
673 u16 normalizedSignalStrength;
674 u16 shortPreamble;
675 u8 apIP[4];
676 u8 noisePercent; /* Noise percent in last second */
677 u8 noisedBm; /* Noise dBm in last second */
678 u8 noiseAvePercent; /* Noise percent in last minute */
679 u8 noiseAvedBm; /* Noise dBm in last minute */
680 u8 noiseMaxPercent; /* Highest noise percent in last minute */
681 u8 noiseMaxdBm; /* Highest noise dbm in last minute */
682 u16 load;
683 u8 carrier[4];
684 u16 assocStatus;
685#define STAT_NOPACKETS 0
686#define STAT_NOCARRIERSET 10
687#define STAT_GOTCARRIERSET 11
688#define STAT_WRONGSSID 20
689#define STAT_BADCHANNEL 25
690#define STAT_BADBITRATES 30
691#define STAT_BADPRIVACY 35
692#define STAT_APFOUND 40
693#define STAT_APREJECTED 50
694#define STAT_AUTHENTICATING 60
695#define STAT_DEAUTHENTICATED 61
696#define STAT_AUTHTIMEOUT 62
697#define STAT_ASSOCIATING 70
698#define STAT_DEASSOCIATED 71
699#define STAT_ASSOCTIMEOUT 72
700#define STAT_NOTAIROAP 73
701#define STAT_ASSOCIATED 80
702#define STAT_LEAPING 90
703#define STAT_LEAPFAILED 91
704#define STAT_LEAPTIMEDOUT 92
705#define STAT_LEAPCOMPLETE 93
706} StatusRid;
707
708typedef struct {
709 u16 len;
710 u16 spacer;
711 u32 vals[100];
712} StatsRid;
713
714
715typedef struct {
716 u16 len;
717 u8 ap[4][ETH_ALEN];
718} APListRid;
719
720typedef struct {
721 u16 len;
722 char oui[3];
723 char zero;
724 u16 prodNum;
725 char manName[32];
726 char prodName[16];
727 char prodVer[8];
728 char factoryAddr[ETH_ALEN];
729 char aironetAddr[ETH_ALEN];
730 u16 radioType;
731 u16 country;
732 char callid[ETH_ALEN];
733 char supportedRates[8];
734 char rxDiversity;
735 char txDiversity;
736 u16 txPowerLevels[8];
737 u16 hardVer;
738 u16 hardCap;
739 u16 tempRange;
740 u16 softVer;
741 u16 softSubVer;
742 u16 interfaceVer;
743 u16 softCap;
744 u16 bootBlockVer;
745 u16 requiredHard;
746 u16 extSoftCap;
747} CapabilityRid;
748
Dan Williams3c304952006-04-15 12:26:18 -0400749
750/* Only present on firmware >= 5.30.17 */
751typedef struct {
752 u16 unknown[4];
753 u8 fixed[12]; /* WLAN management frame */
754 u8 iep[624];
755} BSSListRidExtra;
756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757typedef struct {
758 u16 len;
759 u16 index; /* First is 0 and 0xffff means end of list */
760#define RADIO_FH 1 /* Frequency hopping radio type */
761#define RADIO_DS 2 /* Direct sequence radio type */
762#define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */
763 u16 radioType;
764 u8 bssid[ETH_ALEN]; /* Mac address of the BSS */
765 u8 zero;
766 u8 ssidLen;
767 u8 ssid[32];
Dan Williams41480af2005-05-10 09:45:51 -0400768 u16 dBm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769#define CAP_ESS (1<<0)
770#define CAP_IBSS (1<<1)
771#define CAP_PRIVACY (1<<4)
772#define CAP_SHORTHDR (1<<5)
773 u16 cap;
774 u16 beaconInterval;
775 u8 rates[8]; /* Same as rates for config rid */
776 struct { /* For frequency hopping only */
777 u16 dwell;
778 u8 hopSet;
779 u8 hopPattern;
780 u8 hopIndex;
781 u8 fill;
782 } fh;
783 u16 dsChannel;
784 u16 atimWindow;
Dan Williams3c304952006-04-15 12:26:18 -0400785
786 /* Only present on firmware >= 5.30.17 */
787 BSSListRidExtra extra;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788} BSSListRid;
789
790typedef struct {
Dan Williams9e75af32006-03-16 13:46:29 -0500791 BSSListRid bss;
792 struct list_head list;
793} BSSListElement;
794
795typedef struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 u8 rssipct;
797 u8 rssidBm;
798} tdsRssiEntry;
799
800typedef struct {
801 u16 len;
802 tdsRssiEntry x[256];
803} tdsRssiRid;
804
805typedef struct {
806 u16 len;
807 u16 state;
808 u16 multicastValid;
809 u8 multicast[16];
810 u16 unicastValid;
811 u8 unicast[16];
812} MICRid;
813
814typedef struct {
Al Viro593c2b92007-12-17 15:09:34 -0500815 __be16 typelen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817 union {
818 u8 snap[8];
819 struct {
820 u8 dsap;
821 u8 ssap;
822 u8 control;
823 u8 orgcode[3];
824 u8 fieldtype[2];
825 } llc;
826 } u;
Al Viro593c2b92007-12-17 15:09:34 -0500827 __be32 mic;
828 __be32 seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829} MICBuffer;
830
831typedef struct {
832 u8 da[ETH_ALEN];
833 u8 sa[ETH_ALEN];
834} etherHead;
835
836#pragma pack()
837
838#define TXCTL_TXOK (1<<1) /* report if tx is ok */
839#define TXCTL_TXEX (1<<2) /* report if tx fails */
840#define TXCTL_802_3 (0<<3) /* 802.3 packet */
841#define TXCTL_802_11 (1<<3) /* 802.11 mac packet */
842#define TXCTL_ETHERNET (0<<4) /* payload has ethertype */
843#define TXCTL_LLC (1<<4) /* payload is llc */
844#define TXCTL_RELEASE (0<<5) /* release after completion */
845#define TXCTL_NORELEASE (1<<5) /* on completion returns to host */
846
847#define BUSY_FID 0x10000
848
849#ifdef CISCO_EXT
850#define AIROMAGIC 0xa55a
851/* Warning : SIOCDEVPRIVATE may disapear during 2.5.X - Jean II */
852#ifdef SIOCIWFIRSTPRIV
853#ifdef SIOCDEVPRIVATE
854#define AIROOLDIOCTL SIOCDEVPRIVATE
855#define AIROOLDIDIFC AIROOLDIOCTL + 1
856#endif /* SIOCDEVPRIVATE */
857#else /* SIOCIWFIRSTPRIV */
858#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
859#endif /* SIOCIWFIRSTPRIV */
860/* This may be wrong. When using the new SIOCIWFIRSTPRIV range, we probably
861 * should use only "GET" ioctls (last bit set to 1). "SET" ioctls are root
862 * only and don't return the modified struct ifreq to the application which
863 * is usually a problem. - Jean II */
864#define AIROIOCTL SIOCIWFIRSTPRIV
865#define AIROIDIFC AIROIOCTL + 1
866
867/* Ioctl constants to be used in airo_ioctl.command */
868
869#define AIROGCAP 0 // Capability rid
870#define AIROGCFG 1 // USED A LOT
871#define AIROGSLIST 2 // System ID list
872#define AIROGVLIST 3 // List of specified AP's
873#define AIROGDRVNAM 4 // NOTUSED
874#define AIROGEHTENC 5 // NOTUSED
875#define AIROGWEPKTMP 6
876#define AIROGWEPKNV 7
877#define AIROGSTAT 8
878#define AIROGSTATSC32 9
879#define AIROGSTATSD32 10
880#define AIROGMICRID 11
881#define AIROGMICSTATS 12
882#define AIROGFLAGS 13
883#define AIROGID 14
884#define AIRORRID 15
885#define AIRORSWVERSION 17
886
887/* Leave gap of 40 commands after AIROGSTATSD32 for future */
888
889#define AIROPCAP AIROGSTATSD32 + 40
890#define AIROPVLIST AIROPCAP + 1
891#define AIROPSLIST AIROPVLIST + 1
892#define AIROPCFG AIROPSLIST + 1
893#define AIROPSIDS AIROPCFG + 1
894#define AIROPAPLIST AIROPSIDS + 1
895#define AIROPMACON AIROPAPLIST + 1 /* Enable mac */
896#define AIROPMACOFF AIROPMACON + 1 /* Disable mac */
897#define AIROPSTCLR AIROPMACOFF + 1
898#define AIROPWEPKEY AIROPSTCLR + 1
899#define AIROPWEPKEYNV AIROPWEPKEY + 1
900#define AIROPLEAPPWD AIROPWEPKEYNV + 1
901#define AIROPLEAPUSR AIROPLEAPPWD + 1
902
903/* Flash codes */
904
905#define AIROFLSHRST AIROPWEPKEYNV + 40
906#define AIROFLSHGCHR AIROFLSHRST + 1
907#define AIROFLSHSTFL AIROFLSHGCHR + 1
908#define AIROFLSHPCHR AIROFLSHSTFL + 1
909#define AIROFLPUTBUF AIROFLSHPCHR + 1
910#define AIRORESTART AIROFLPUTBUF + 1
911
912#define FLASHSIZE 32768
913#define AUXMEMSIZE (256 * 1024)
914
915typedef struct aironet_ioctl {
916 unsigned short command; // What to do
917 unsigned short len; // Len of data
918 unsigned short ridnum; // rid number
919 unsigned char __user *data; // d-data
920} aironet_ioctl;
921
Domen Puncer62595eb2005-06-20 23:54:37 +0200922static char swversion[] = "2.1";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923#endif /* CISCO_EXT */
924
925#define NUM_MODULES 2
926#define MIC_MSGLEN_MAX 2400
927#define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX
Dan Williams15db2762006-03-16 13:46:27 -0500928#define AIRO_DEF_MTU 2312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
930typedef struct {
931 u32 size; // size
932 u8 enabled; // MIC enabled or not
933 u32 rxSuccess; // successful packets received
934 u32 rxIncorrectMIC; // pkts dropped due to incorrect MIC comparison
935 u32 rxNotMICed; // pkts dropped due to not being MIC'd
936 u32 rxMICPlummed; // pkts dropped due to not having a MIC plummed
937 u32 rxWrongSequence; // pkts dropped due to sequence number violation
938 u32 reserve[32];
939} mic_statistics;
940
941typedef struct {
942 u32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2];
943 u64 accum; // accumulated mic, reduced to u32 in final()
944 int position; // current position (byte offset) in message
945 union {
946 u8 d8[4];
Al Viro593c2b92007-12-17 15:09:34 -0500947 __be32 d32;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 } part; // saves partial message word across update() calls
949} emmh32_context;
950
951typedef struct {
952 emmh32_context seed; // Context - the seed
953 u32 rx; // Received sequence number
954 u32 tx; // Tx sequence number
955 u32 window; // Start of window
956 u8 valid; // Flag to say if context is valid or not
957 u8 key[16];
958} miccntx;
959
960typedef struct {
961 miccntx mCtx; // Multicast context
962 miccntx uCtx; // Unicast context
963} mic_module;
964
965typedef struct {
966 unsigned int rid: 16;
967 unsigned int len: 15;
968 unsigned int valid: 1;
969 dma_addr_t host_addr;
970} Rid;
971
972typedef struct {
973 unsigned int offset: 15;
974 unsigned int eoc: 1;
975 unsigned int len: 15;
976 unsigned int valid: 1;
977 dma_addr_t host_addr;
978} TxFid;
979
980typedef struct {
981 unsigned int ctl: 15;
982 unsigned int rdy: 1;
983 unsigned int len: 15;
984 unsigned int valid: 1;
985 dma_addr_t host_addr;
986} RxFid;
987
988/*
989 * Host receive descriptor
990 */
991typedef struct {
992 unsigned char __iomem *card_ram_off; /* offset into card memory of the
993 desc */
994 RxFid rx_desc; /* card receive descriptor */
995 char *virtual_host_addr; /* virtual address of host receive
996 buffer */
997 int pending;
998} HostRxDesc;
999
1000/*
1001 * Host transmit descriptor
1002 */
1003typedef struct {
1004 unsigned char __iomem *card_ram_off; /* offset into card memory of the
1005 desc */
1006 TxFid tx_desc; /* card transmit descriptor */
1007 char *virtual_host_addr; /* virtual address of host receive
1008 buffer */
1009 int pending;
1010} HostTxDesc;
1011
1012/*
1013 * Host RID descriptor
1014 */
1015typedef struct {
1016 unsigned char __iomem *card_ram_off; /* offset into card memory of the
1017 descriptor */
1018 Rid rid_desc; /* card RID descriptor */
1019 char *virtual_host_addr; /* virtual address of host receive
1020 buffer */
1021} HostRidDesc;
1022
1023typedef struct {
1024 u16 sw0;
1025 u16 sw1;
1026 u16 status;
1027 u16 len;
1028#define HOST_SET (1 << 0)
1029#define HOST_INT_TX (1 << 1) /* Interrupt on successful TX */
1030#define HOST_INT_TXERR (1 << 2) /* Interrupt on unseccessful TX */
1031#define HOST_LCC_PAYLOAD (1 << 4) /* LLC payload, 0 = Ethertype */
1032#define HOST_DONT_RLSE (1 << 5) /* Don't release buffer when done */
1033#define HOST_DONT_RETRY (1 << 6) /* Don't retry trasmit */
1034#define HOST_CLR_AID (1 << 7) /* clear AID failure */
1035#define HOST_RTS (1 << 9) /* Force RTS use */
1036#define HOST_SHORT (1 << 10) /* Do short preamble */
1037 u16 ctl;
1038 u16 aid;
1039 u16 retries;
1040 u16 fill;
1041} TxCtlHdr;
1042
1043typedef struct {
1044 u16 ctl;
1045 u16 duration;
1046 char addr1[6];
1047 char addr2[6];
1048 char addr3[6];
1049 u16 seq;
1050 char addr4[6];
1051} WifiHdr;
1052
1053
1054typedef struct {
1055 TxCtlHdr ctlhdr;
1056 u16 fill1;
1057 u16 fill2;
1058 WifiHdr wifihdr;
1059 u16 gaplen;
1060 u16 status;
1061} WifiCtlHdr;
1062
Jouni Malinenff1d2762005-05-12 22:54:16 -04001063static WifiCtlHdr wifictlhdr8023 = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 .ctlhdr = {
1065 .ctl = HOST_DONT_RLSE,
1066 }
1067};
1068
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069// Frequency list (map channels to frequencies)
1070static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
1071 2447, 2452, 2457, 2462, 2467, 2472, 2484 };
1072
1073// A few details needed for WEP (Wireless Equivalent Privacy)
1074#define MAX_KEY_SIZE 13 // 128 (?) bits
1075#define MIN_KEY_SIZE 5 // 40 bits RC4 - WEP
1076typedef struct wep_key_t {
1077 u16 len;
1078 u8 key[16]; /* 40-bit and 104-bit keys */
1079} wep_key_t;
1080
1081/* Backward compatibility */
1082#ifndef IW_ENCODE_NOKEY
1083#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */
1084#define IW_ENCODE_MODE (IW_ENCODE_DISABLED | IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)
1085#endif /* IW_ENCODE_NOKEY */
1086
1087/* List of Wireless Handlers (new API) */
1088static const struct iw_handler_def airo_handler_def;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
1090static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)";
1091
1092struct airo_info;
1093
1094static int get_dec_u16( char *buffer, int *start, int limit );
1095static void OUT4500( struct airo_info *, u16 register, u16 value );
1096static unsigned short IN4500( struct airo_info *, u16 register );
1097static u16 setup_card(struct airo_info*, u8 *mac, int lock);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02001098static int enable_MAC(struct airo_info *ai, int lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099static void disable_MAC(struct airo_info *ai, int lock);
1100static void enable_interrupts(struct airo_info*);
1101static void disable_interrupts(struct airo_info*);
1102static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
1103static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
1104static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
1105 int whichbap);
1106static int fast_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
1107 int whichbap);
1108static int bap_write(struct airo_info*, const u16 *pu16Src, int bytelen,
1109 int whichbap);
1110static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd);
1111static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock);
1112static int PC4500_writerid(struct airo_info*, u16 rid, const void
1113 *pBuf, int len, int lock);
1114static int do_writerid( struct airo_info*, u16 rid, const void *rid_data,
1115 int len, int dummy );
1116static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw);
1117static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket);
1118static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket);
1119
1120static int mpi_send_packet (struct net_device *dev);
1121static void mpi_unmap_card(struct pci_dev *pci);
1122static void mpi_receive_802_3(struct airo_info *ai);
1123static void mpi_receive_802_11(struct airo_info *ai);
1124static int waitbusy (struct airo_info *ai);
1125
David Howells7d12e782006-10-05 14:55:46 +01001126static irqreturn_t airo_interrupt( int irq, void* dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127static int airo_thread(void *data);
1128static void timer_func( struct net_device *dev );
1129static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
Jouni Malinenff1d2762005-05-12 22:54:16 -04001130static struct iw_statistics *airo_get_wireless_stats (struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131static void airo_read_wireless_stats (struct airo_info *local);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132#ifdef CISCO_EXT
1133static int readrids(struct net_device *dev, aironet_ioctl *comp);
1134static int writerids(struct net_device *dev, aironet_ioctl *comp);
Jouni Malinenff1d2762005-05-12 22:54:16 -04001135static int flashcard(struct net_device *dev, aironet_ioctl *comp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136#endif /* CISCO_EXT */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137static void micinit(struct airo_info *ai);
1138static int micsetup(struct airo_info *ai);
1139static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len);
1140static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen);
1141
Dan Williams41480af2005-05-10 09:45:51 -04001142static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi);
1143static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm);
1144
Dan Williams9e75af32006-03-16 13:46:29 -05001145static void airo_networks_free(struct airo_info *ai);
1146
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147struct airo_info {
1148 struct net_device_stats stats;
1149 struct net_device *dev;
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01001150 struct list_head dev_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we
1152 use the high bit to mark whether it is in use. */
1153#define MAX_FIDS 6
1154#define MPI_MAX_FIDS 1
1155 int fids[MAX_FIDS];
1156 ConfigRid config;
1157 char keyindex; // Used with auto wep
1158 char defindex; // Used with auto wep
1159 struct proc_dir_entry *proc_entry;
1160 spinlock_t aux_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161#define FLAG_RADIO_OFF 0 /* User disabling of MAC */
1162#define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */
1163#define FLAG_RADIO_MASK 0x03
1164#define FLAG_ENABLED 2
1165#define FLAG_ADHOC 3 /* Needed by MIC */
1166#define FLAG_MIC_CAPABLE 4
1167#define FLAG_UPDATE_MULTI 5
1168#define FLAG_UPDATE_UNI 6
1169#define FLAG_802_11 7
Dan Williams3c304952006-04-15 12:26:18 -04001170#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171#define FLAG_PENDING_XMIT 9
1172#define FLAG_PENDING_XMIT11 10
1173#define FLAG_MPI 11
1174#define FLAG_REGISTERED 12
1175#define FLAG_COMMIT 13
1176#define FLAG_RESET 14
1177#define FLAG_FLASHING 15
Dan Williams3c304952006-04-15 12:26:18 -04001178#define FLAG_WPA_CAPABLE 16
1179 unsigned long flags;
1180#define JOB_DIE 0
1181#define JOB_XMIT 1
1182#define JOB_XMIT11 2
1183#define JOB_STATS 3
1184#define JOB_PROMISC 4
1185#define JOB_MIC 5
1186#define JOB_EVENT 6
1187#define JOB_AUTOWEP 7
1188#define JOB_WSTATS 8
1189#define JOB_SCAN_RESULTS 9
1190 unsigned long jobs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
1192 int whichbap);
1193 unsigned short *flash;
1194 tdsRssiEntry *rssi;
Sukadev Bhattiprolu3b4c7d642006-08-14 23:12:03 -07001195 struct task_struct *list_bss_task;
1196 struct task_struct *airo_thread_task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 struct semaphore sem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 wait_queue_head_t thr_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 unsigned long expires;
1200 struct {
1201 struct sk_buff *skb;
1202 int fid;
1203 } xmit, xmit11;
1204 struct net_device *wifidev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 struct iw_statistics wstats; // wireless stats
Dan Williams9e75af32006-03-16 13:46:29 -05001206 unsigned long scan_timeout; /* Time scan should be read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 struct iw_spy_data spy_data;
1208 struct iw_public_data wireless_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 /* MIC stuff */
Herbert Xuf12cc202006-08-22 20:36:13 +10001210 struct crypto_cipher *tfm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 mic_module mod[2];
1212 mic_statistics micstats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors
1214 HostTxDesc txfids[MPI_MAX_FIDS];
1215 HostRidDesc config_desc;
1216 unsigned long ridbus; // phys addr of config_desc
1217 struct sk_buff_head txq;// tx queue used by mpi350 code
1218 struct pci_dev *pci;
1219 unsigned char __iomem *pcimem;
1220 unsigned char __iomem *pciaux;
1221 unsigned char *shared;
1222 dma_addr_t shared_dma;
Pavel Machek1cc68ae2005-06-20 15:33:04 -07001223 pm_message_t power;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 SsidRid *SSID;
1225 APListRid *APList;
1226#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
1227 char proc_name[IFNAMSIZ];
Dan Williams9e75af32006-03-16 13:46:29 -05001228
Dan Williams3c304952006-04-15 12:26:18 -04001229 /* WPA-related stuff */
1230 unsigned int bssListFirst;
1231 unsigned int bssListNext;
1232 unsigned int bssListRidLen;
1233
Dan Williams9e75af32006-03-16 13:46:29 -05001234 struct list_head network_list;
1235 struct list_head network_free_list;
1236 BSSListElement *networks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237};
1238
1239static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
1240 int whichbap) {
1241 return ai->bap_read(ai, pu16Dst, bytelen, whichbap);
1242}
1243
1244static int setup_proc_entry( struct net_device *dev,
1245 struct airo_info *apriv );
1246static int takedown_proc_entry( struct net_device *dev,
1247 struct airo_info *apriv );
1248
Jouni Malinenff1d2762005-05-12 22:54:16 -04001249static int cmdreset(struct airo_info *ai);
1250static int setflashmode (struct airo_info *ai);
1251static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime);
1252static int flashputbuf(struct airo_info *ai);
1253static int flashrestart(struct airo_info *ai,struct net_device *dev);
1254
Dan Williams934d8bf2006-03-16 13:46:23 -05001255#define airo_print(type, name, fmt, args...) \
Michal Schmidt1138c372007-06-29 15:33:41 +02001256 printk(type DRV_NAME "(%s): " fmt "\n", name, ##args)
Dan Williams934d8bf2006-03-16 13:46:23 -05001257
1258#define airo_print_info(name, fmt, args...) \
1259 airo_print(KERN_INFO, name, fmt, ##args)
1260
1261#define airo_print_dbg(name, fmt, args...) \
1262 airo_print(KERN_DEBUG, name, fmt, ##args)
1263
1264#define airo_print_warn(name, fmt, args...) \
1265 airo_print(KERN_WARNING, name, fmt, ##args)
1266
1267#define airo_print_err(name, fmt, args...) \
1268 airo_print(KERN_ERR, name, fmt, ##args)
1269
1270
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271/***********************************************************************
1272 * MIC ROUTINES *
1273 ***********************************************************************
1274 */
1275
1276static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq);
1277static void MoveWindow(miccntx *context, u32 micSeq);
Herbert Xuf12cc202006-08-22 20:36:13 +10001278static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
1279 struct crypto_cipher *tfm);
Jouni Malinenff1d2762005-05-12 22:54:16 -04001280static void emmh32_init(emmh32_context *context);
1281static void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
1282static void emmh32_final(emmh32_context *context, u8 digest[4]);
1283static int flashpchar(struct airo_info *ai,int byte,int dwelltime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
1285/* micinit - Initialize mic seed */
1286
1287static void micinit(struct airo_info *ai)
1288{
1289 MICRid mic_rid;
1290
Dan Williams3c304952006-04-15 12:26:18 -04001291 clear_bit(JOB_MIC, &ai->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
1293 up(&ai->sem);
1294
1295 ai->micstats.enabled = (mic_rid.state & 0x00FF) ? 1 : 0;
1296
1297 if (ai->micstats.enabled) {
1298 /* Key must be valid and different */
1299 if (mic_rid.multicastValid && (!ai->mod[0].mCtx.valid ||
1300 (memcmp (ai->mod[0].mCtx.key, mic_rid.multicast,
1301 sizeof(ai->mod[0].mCtx.key)) != 0))) {
1302 /* Age current mic Context */
1303 memcpy(&ai->mod[1].mCtx,&ai->mod[0].mCtx,sizeof(miccntx));
1304 /* Initialize new context */
1305 memcpy(&ai->mod[0].mCtx.key,mic_rid.multicast,sizeof(mic_rid.multicast));
1306 ai->mod[0].mCtx.window = 33; //Window always points to the middle
1307 ai->mod[0].mCtx.rx = 0; //Rx Sequence numbers
1308 ai->mod[0].mCtx.tx = 0; //Tx sequence numbers
1309 ai->mod[0].mCtx.valid = 1; //Key is now valid
1310
1311 /* Give key to mic seed */
1312 emmh32_setseed(&ai->mod[0].mCtx.seed,mic_rid.multicast,sizeof(mic_rid.multicast), ai->tfm);
1313 }
1314
1315 /* Key must be valid and different */
1316 if (mic_rid.unicastValid && (!ai->mod[0].uCtx.valid ||
1317 (memcmp(ai->mod[0].uCtx.key, mic_rid.unicast,
1318 sizeof(ai->mod[0].uCtx.key)) != 0))) {
1319 /* Age current mic Context */
1320 memcpy(&ai->mod[1].uCtx,&ai->mod[0].uCtx,sizeof(miccntx));
1321 /* Initialize new context */
1322 memcpy(&ai->mod[0].uCtx.key,mic_rid.unicast,sizeof(mic_rid.unicast));
1323
1324 ai->mod[0].uCtx.window = 33; //Window always points to the middle
1325 ai->mod[0].uCtx.rx = 0; //Rx Sequence numbers
1326 ai->mod[0].uCtx.tx = 0; //Tx sequence numbers
1327 ai->mod[0].uCtx.valid = 1; //Key is now valid
1328
1329 //Give key to mic seed
1330 emmh32_setseed(&ai->mod[0].uCtx.seed, mic_rid.unicast, sizeof(mic_rid.unicast), ai->tfm);
1331 }
1332 } else {
1333 /* So next time we have a valid key and mic is enabled, we will update
1334 * the sequence number if the key is the same as before.
1335 */
1336 ai->mod[0].uCtx.valid = 0;
1337 ai->mod[0].mCtx.valid = 0;
1338 }
1339}
1340
1341/* micsetup - Get ready for business */
1342
1343static int micsetup(struct airo_info *ai) {
1344 int i;
1345
1346 if (ai->tfm == NULL)
Herbert Xuf12cc202006-08-22 20:36:13 +10001347 ai->tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348
Herbert Xuf12cc202006-08-22 20:36:13 +10001349 if (IS_ERR(ai->tfm)) {
Dan Williams934d8bf2006-03-16 13:46:23 -05001350 airo_print_err(ai->dev->name, "failed to load transform for AES");
Herbert Xuf12cc202006-08-22 20:36:13 +10001351 ai->tfm = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 return ERROR;
1353 }
1354
1355 for (i=0; i < NUM_MODULES; i++) {
1356 memset(&ai->mod[i].mCtx,0,sizeof(miccntx));
1357 memset(&ai->mod[i].uCtx,0,sizeof(miccntx));
1358 }
1359 return SUCCESS;
1360}
1361
Jouni Malinenff1d2762005-05-12 22:54:16 -04001362static char micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
1364/*===========================================================================
1365 * Description: Mic a packet
1366 *
1367 * Inputs: etherHead * pointer to an 802.3 frame
1368 *
1369 * Returns: BOOLEAN if successful, otherwise false.
1370 * PacketTxLen will be updated with the mic'd packets size.
1371 *
1372 * Caveats: It is assumed that the frame buffer will already
1373 * be big enough to hold the largets mic message possible.
1374 * (No memory allocation is done here).
1375 *
1376 * Author: sbraneky (10/15/01)
1377 * Merciless hacks by rwilcher (1/14/02)
1378 */
1379
1380static int encapsulate(struct airo_info *ai ,etherHead *frame, MICBuffer *mic, int payLen)
1381{
1382 miccntx *context;
1383
1384 // Determine correct context
1385 // If not adhoc, always use unicast key
1386
1387 if (test_bit(FLAG_ADHOC, &ai->flags) && (frame->da[0] & 0x1))
1388 context = &ai->mod[0].mCtx;
1389 else
1390 context = &ai->mod[0].uCtx;
1391
1392 if (!context->valid)
1393 return ERROR;
1394
1395 mic->typelen = htons(payLen + 16); //Length of Mic'd packet
1396
1397 memcpy(&mic->u.snap, micsnap, sizeof(micsnap)); // Add Snap
1398
1399 // Add Tx sequence
1400 mic->seq = htonl(context->tx);
1401 context->tx += 2;
1402
1403 emmh32_init(&context->seed); // Mic the packet
1404 emmh32_update(&context->seed,frame->da,ETH_ALEN * 2); // DA,SA
1405 emmh32_update(&context->seed,(u8*)&mic->typelen,10); // Type/Length and Snap
1406 emmh32_update(&context->seed,(u8*)&mic->seq,sizeof(mic->seq)); //SEQ
1407 emmh32_update(&context->seed,frame->da + ETH_ALEN * 2,payLen); //payload
1408 emmh32_final(&context->seed, (u8*)&mic->mic);
1409
1410 /* New Type/length ?????????? */
1411 mic->typelen = 0; //Let NIC know it could be an oversized packet
1412 return SUCCESS;
1413}
1414
1415typedef enum {
1416 NONE,
1417 NOMIC,
1418 NOMICPLUMMED,
1419 SEQUENCE,
1420 INCORRECTMIC,
1421} mic_error;
1422
1423/*===========================================================================
1424 * Description: Decapsulates a MIC'd packet and returns the 802.3 packet
1425 * (removes the MIC stuff) if packet is a valid packet.
1426 *
1427 * Inputs: etherHead pointer to the 802.3 packet
1428 *
1429 * Returns: BOOLEAN - TRUE if packet should be dropped otherwise FALSE
1430 *
1431 * Author: sbraneky (10/15/01)
1432 * Merciless hacks by rwilcher (1/14/02)
1433 *---------------------------------------------------------------------------
1434 */
1435
1436static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *eth, u16 payLen)
1437{
1438 int i;
1439 u32 micSEQ;
1440 miccntx *context;
1441 u8 digest[4];
1442 mic_error micError = NONE;
1443
1444 // Check if the packet is a Mic'd packet
1445
1446 if (!ai->micstats.enabled) {
1447 //No Mic set or Mic OFF but we received a MIC'd packet.
1448 if (memcmp ((u8*)eth + 14, micsnap, sizeof(micsnap)) == 0) {
1449 ai->micstats.rxMICPlummed++;
1450 return ERROR;
1451 }
1452 return SUCCESS;
1453 }
1454
1455 if (ntohs(mic->typelen) == 0x888E)
1456 return SUCCESS;
1457
1458 if (memcmp (mic->u.snap, micsnap, sizeof(micsnap)) != 0) {
1459 // Mic enabled but packet isn't Mic'd
1460 ai->micstats.rxMICPlummed++;
1461 return ERROR;
1462 }
1463
1464 micSEQ = ntohl(mic->seq); //store SEQ as CPU order
1465
1466 //At this point we a have a mic'd packet and mic is enabled
1467 //Now do the mic error checking.
1468
1469 //Receive seq must be odd
1470 if ( (micSEQ & 1) == 0 ) {
1471 ai->micstats.rxWrongSequence++;
1472 return ERROR;
1473 }
1474
1475 for (i = 0; i < NUM_MODULES; i++) {
1476 int mcast = eth->da[0] & 1;
1477 //Determine proper context
1478 context = mcast ? &ai->mod[i].mCtx : &ai->mod[i].uCtx;
1479
1480 //Make sure context is valid
1481 if (!context->valid) {
1482 if (i == 0)
1483 micError = NOMICPLUMMED;
1484 continue;
1485 }
1486 //DeMic it
1487
1488 if (!mic->typelen)
1489 mic->typelen = htons(payLen + sizeof(MICBuffer) - 2);
1490
1491 emmh32_init(&context->seed);
1492 emmh32_update(&context->seed, eth->da, ETH_ALEN*2);
1493 emmh32_update(&context->seed, (u8 *)&mic->typelen, sizeof(mic->typelen)+sizeof(mic->u.snap));
1494 emmh32_update(&context->seed, (u8 *)&mic->seq,sizeof(mic->seq));
1495 emmh32_update(&context->seed, eth->da + ETH_ALEN*2,payLen);
1496 //Calculate MIC
1497 emmh32_final(&context->seed, digest);
1498
1499 if (memcmp(digest, &mic->mic, 4)) { //Make sure the mics match
1500 //Invalid Mic
1501 if (i == 0)
1502 micError = INCORRECTMIC;
1503 continue;
1504 }
1505
1506 //Check Sequence number if mics pass
1507 if (RxSeqValid(ai, context, mcast, micSEQ) == SUCCESS) {
1508 ai->micstats.rxSuccess++;
1509 return SUCCESS;
1510 }
1511 if (i == 0)
1512 micError = SEQUENCE;
1513 }
1514
1515 // Update statistics
1516 switch (micError) {
1517 case NOMICPLUMMED: ai->micstats.rxMICPlummed++; break;
1518 case SEQUENCE: ai->micstats.rxWrongSequence++; break;
1519 case INCORRECTMIC: ai->micstats.rxIncorrectMIC++; break;
1520 case NONE: break;
1521 case NOMIC: break;
1522 }
1523 return ERROR;
1524}
1525
1526/*===========================================================================
1527 * Description: Checks the Rx Seq number to make sure it is valid
1528 * and hasn't already been received
1529 *
1530 * Inputs: miccntx - mic context to check seq against
1531 * micSeq - the Mic seq number
1532 *
1533 * Returns: TRUE if valid otherwise FALSE.
1534 *
1535 * Author: sbraneky (10/15/01)
1536 * Merciless hacks by rwilcher (1/14/02)
1537 *---------------------------------------------------------------------------
1538 */
1539
1540static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq)
1541{
1542 u32 seq,index;
1543
1544 //Allow for the ap being rebooted - if it is then use the next
1545 //sequence number of the current sequence number - might go backwards
1546
1547 if (mcast) {
1548 if (test_bit(FLAG_UPDATE_MULTI, &ai->flags)) {
1549 clear_bit (FLAG_UPDATE_MULTI, &ai->flags);
1550 context->window = (micSeq > 33) ? micSeq : 33;
1551 context->rx = 0; // Reset rx
1552 }
1553 } else if (test_bit(FLAG_UPDATE_UNI, &ai->flags)) {
1554 clear_bit (FLAG_UPDATE_UNI, &ai->flags);
1555 context->window = (micSeq > 33) ? micSeq : 33; // Move window
1556 context->rx = 0; // Reset rx
1557 }
1558
1559 //Make sequence number relative to START of window
1560 seq = micSeq - (context->window - 33);
1561
1562 //Too old of a SEQ number to check.
1563 if ((s32)seq < 0)
1564 return ERROR;
1565
1566 if ( seq > 64 ) {
1567 //Window is infinite forward
1568 MoveWindow(context,micSeq);
1569 return SUCCESS;
1570 }
1571
1572 // We are in the window. Now check the context rx bit to see if it was already sent
1573 seq >>= 1; //divide by 2 because we only have odd numbers
1574 index = 1 << seq; //Get an index number
1575
1576 if (!(context->rx & index)) {
1577 //micSEQ falls inside the window.
1578 //Add seqence number to the list of received numbers.
1579 context->rx |= index;
1580
1581 MoveWindow(context,micSeq);
1582
1583 return SUCCESS;
1584 }
1585 return ERROR;
1586}
1587
1588static void MoveWindow(miccntx *context, u32 micSeq)
1589{
1590 u32 shift;
1591
1592 //Move window if seq greater than the middle of the window
1593 if (micSeq > context->window) {
1594 shift = (micSeq - context->window) >> 1;
1595
1596 //Shift out old
1597 if (shift < 32)
1598 context->rx >>= shift;
1599 else
1600 context->rx = 0;
1601
1602 context->window = micSeq; //Move window
1603 }
1604}
1605
1606/*==============================================*/
1607/*========== EMMH ROUTINES ====================*/
1608/*==============================================*/
1609
1610/* mic accumulate */
1611#define MIC_ACCUM(val) \
1612 context->accum += (u64)(val) * context->coeff[coeff_position++];
1613
1614static unsigned char aes_counter[16];
1615
1616/* expand the key to fill the MMH coefficient array */
Herbert Xuf12cc202006-08-22 20:36:13 +10001617static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
1618 struct crypto_cipher *tfm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619{
1620 /* take the keying material, expand if necessary, truncate at 16-bytes */
1621 /* run through AES counter mode to generate context->coeff[] */
1622
1623 int i,j;
1624 u32 counter;
1625 u8 *cipher, plain[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
1627 crypto_cipher_setkey(tfm, pkey, 16);
1628 counter = 0;
Ahmed S. Darwishe7c04fd2007-02-05 18:58:29 +02001629 for (i = 0; i < ARRAY_SIZE(context->coeff); ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 aes_counter[15] = (u8)(counter >> 0);
1631 aes_counter[14] = (u8)(counter >> 8);
1632 aes_counter[13] = (u8)(counter >> 16);
1633 aes_counter[12] = (u8)(counter >> 24);
1634 counter++;
1635 memcpy (plain, aes_counter, 16);
Herbert Xuf12cc202006-08-22 20:36:13 +10001636 crypto_cipher_encrypt_one(tfm, plain, plain);
1637 cipher = plain;
Ahmed S. Darwishe7c04fd2007-02-05 18:58:29 +02001638 for (j = 0; (j < 16) && (i < ARRAY_SIZE(context->coeff)); ) {
Al Viro593c2b92007-12-17 15:09:34 -05001639 context->coeff[i++] = ntohl(*(__be32 *)&cipher[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 j += 4;
1641 }
1642 }
1643}
1644
1645/* prepare for calculation of a new mic */
Jouni Malinenff1d2762005-05-12 22:54:16 -04001646static void emmh32_init(emmh32_context *context)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647{
1648 /* prepare for new mic calculation */
1649 context->accum = 0;
1650 context->position = 0;
1651}
1652
1653/* add some bytes to the mic calculation */
Jouni Malinenff1d2762005-05-12 22:54:16 -04001654static void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655{
1656 int coeff_position, byte_position;
1657
1658 if (len == 0) return;
1659
1660 coeff_position = context->position >> 2;
1661
1662 /* deal with partial 32-bit word left over from last update */
1663 byte_position = context->position & 3;
1664 if (byte_position) {
1665 /* have a partial word in part to deal with */
1666 do {
1667 if (len == 0) return;
1668 context->part.d8[byte_position++] = *pOctets++;
1669 context->position++;
1670 len--;
1671 } while (byte_position < 4);
Al Viro593c2b92007-12-17 15:09:34 -05001672 MIC_ACCUM(ntohl(context->part.d32));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 }
1674
1675 /* deal with full 32-bit words */
1676 while (len >= 4) {
Al Viro593c2b92007-12-17 15:09:34 -05001677 MIC_ACCUM(ntohl(*(__be32 *)pOctets));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 context->position += 4;
1679 pOctets += 4;
1680 len -= 4;
1681 }
1682
1683 /* deal with partial 32-bit word that will be left over from this update */
1684 byte_position = 0;
1685 while (len > 0) {
1686 context->part.d8[byte_position++] = *pOctets++;
1687 context->position++;
1688 len--;
1689 }
1690}
1691
1692/* mask used to zero empty bytes for final partial word */
1693static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L };
1694
1695/* calculate the mic */
Jouni Malinenff1d2762005-05-12 22:54:16 -04001696static void emmh32_final(emmh32_context *context, u8 digest[4])
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697{
1698 int coeff_position, byte_position;
1699 u32 val;
1700
1701 u64 sum, utmp;
1702 s64 stmp;
1703
1704 coeff_position = context->position >> 2;
1705
1706 /* deal with partial 32-bit word left over from last update */
1707 byte_position = context->position & 3;
1708 if (byte_position) {
1709 /* have a partial word in part to deal with */
Al Viro593c2b92007-12-17 15:09:34 -05001710 val = ntohl(context->part.d32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 MIC_ACCUM(val & mask32[byte_position]); /* zero empty bytes */
1712 }
1713
1714 /* reduce the accumulated u64 to a 32-bit MIC */
1715 sum = context->accum;
1716 stmp = (sum & 0xffffffffLL) - ((sum >> 32) * 15);
1717 utmp = (stmp & 0xffffffffLL) - ((stmp >> 32) * 15);
1718 sum = utmp & 0xffffffffLL;
1719 if (utmp > 0x10000000fLL)
1720 sum -= 15;
1721
1722 val = (u32)sum;
1723 digest[0] = (val>>24) & 0xFF;
1724 digest[1] = (val>>16) & 0xFF;
1725 digest[2] = (val>>8) & 0xFF;
1726 digest[3] = val & 0xFF;
1727}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728
1729static int readBSSListRid(struct airo_info *ai, int first,
1730 BSSListRid *list) {
1731 int rc;
Dan Williams3c304952006-04-15 12:26:18 -04001732 Cmd cmd;
1733 Resp rsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734
1735 if (first == 1) {
Dan Williams3c304952006-04-15 12:26:18 -04001736 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
1737 memset(&cmd, 0, sizeof(cmd));
1738 cmd.cmd=CMD_LISTBSS;
1739 if (down_interruptible(&ai->sem))
1740 return -ERESTARTSYS;
Sukadev Bhattiprolu3b4c7d642006-08-14 23:12:03 -07001741 ai->list_bss_task = current;
Dan Williams3c304952006-04-15 12:26:18 -04001742 issuecommand(ai, &cmd, &rsp);
1743 up(&ai->sem);
1744 /* Let the command take effect */
Sukadev Bhattiprolu3b4c7d642006-08-14 23:12:03 -07001745 schedule_timeout_uninterruptible(3 * HZ);
1746 ai->list_bss_task = NULL;
Dan Williams3c304952006-04-15 12:26:18 -04001747 }
1748 rc = PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
1749 list, ai->bssListRidLen, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750
1751 list->len = le16_to_cpu(list->len);
1752 list->index = le16_to_cpu(list->index);
1753 list->radioType = le16_to_cpu(list->radioType);
1754 list->cap = le16_to_cpu(list->cap);
1755 list->beaconInterval = le16_to_cpu(list->beaconInterval);
1756 list->fh.dwell = le16_to_cpu(list->fh.dwell);
1757 list->dsChannel = le16_to_cpu(list->dsChannel);
1758 list->atimWindow = le16_to_cpu(list->atimWindow);
Dan Williams41480af2005-05-10 09:45:51 -04001759 list->dBm = le16_to_cpu(list->dBm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 return rc;
1761}
1762
1763static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp, int lock) {
1764 int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM,
1765 wkr, sizeof(*wkr), lock);
1766
1767 wkr->len = le16_to_cpu(wkr->len);
1768 wkr->kindex = le16_to_cpu(wkr->kindex);
1769 wkr->klen = le16_to_cpu(wkr->klen);
1770 return rc;
1771}
1772/* In the writeXXXRid routines we copy the rids so that we don't screwup
1773 * the originals when we endian them... */
1774static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm, int lock) {
1775 int rc;
1776 WepKeyRid wkr = *pwkr;
1777
1778 wkr.len = cpu_to_le16(wkr.len);
1779 wkr.kindex = cpu_to_le16(wkr.kindex);
1780 wkr.klen = cpu_to_le16(wkr.klen);
1781 rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr), lock);
Dan Williams934d8bf2006-03-16 13:46:23 -05001782 if (rc!=SUCCESS) airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 if (perm) {
1784 rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr), lock);
1785 if (rc!=SUCCESS) {
Dan Williams934d8bf2006-03-16 13:46:23 -05001786 airo_print_err(ai->dev->name, "WEP_PERM set %x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 }
1788 }
1789 return rc;
1790}
1791
1792static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) {
1793 int i;
1794 int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1);
1795
1796 ssidr->len = le16_to_cpu(ssidr->len);
1797 for(i = 0; i < 3; i++) {
1798 ssidr->ssids[i].len = le16_to_cpu(ssidr->ssids[i].len);
1799 }
1800 return rc;
1801}
1802static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock) {
1803 int rc;
1804 int i;
1805 SsidRid ssidr = *pssidr;
1806
1807 ssidr.len = cpu_to_le16(ssidr.len);
1808 for(i = 0; i < 3; i++) {
1809 ssidr.ssids[i].len = cpu_to_le16(ssidr.ssids[i].len);
1810 }
1811 rc = PC4500_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr), lock);
1812 return rc;
1813}
1814static int readConfigRid(struct airo_info*ai, int lock) {
1815 int rc;
1816 u16 *s;
1817 ConfigRid cfg;
1818
1819 if (ai->config.len)
1820 return SUCCESS;
1821
1822 rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock);
1823 if (rc != SUCCESS)
1824 return rc;
1825
1826 for(s = &cfg.len; s <= &cfg.rtsThres; s++) *s = le16_to_cpu(*s);
1827
1828 for(s = &cfg.shortRetryLimit; s <= &cfg.radioType; s++)
1829 *s = le16_to_cpu(*s);
1830
1831 for(s = &cfg.txPower; s <= &cfg.radioSpecific; s++)
1832 *s = le16_to_cpu(*s);
1833
1834 for(s = &cfg.arlThreshold; s <= &cfg._reserved4[0]; s++)
1835 *s = cpu_to_le16(*s);
1836
1837 for(s = &cfg.autoWake; s <= &cfg.autoWake; s++)
1838 *s = cpu_to_le16(*s);
1839
1840 ai->config = cfg;
1841 return SUCCESS;
1842}
1843static inline void checkThrottle(struct airo_info *ai) {
1844 int i;
1845/* Old hardware had a limit on encryption speed */
1846 if (ai->config.authType != AUTH_OPEN && maxencrypt) {
1847 for(i=0; i<8; i++) {
1848 if (ai->config.rates[i] > maxencrypt) {
1849 ai->config.rates[i] = 0;
1850 }
1851 }
1852 }
1853}
1854static int writeConfigRid(struct airo_info*ai, int lock) {
1855 u16 *s;
1856 ConfigRid cfgr;
1857
1858 if (!test_bit (FLAG_COMMIT, &ai->flags))
1859 return SUCCESS;
1860
1861 clear_bit (FLAG_COMMIT, &ai->flags);
1862 clear_bit (FLAG_RESET, &ai->flags);
1863 checkThrottle(ai);
1864 cfgr = ai->config;
1865
1866 if ((cfgr.opmode & 0xFF) == MODE_STA_IBSS)
1867 set_bit(FLAG_ADHOC, &ai->flags);
1868 else
1869 clear_bit(FLAG_ADHOC, &ai->flags);
1870
1871 for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s);
1872
1873 for(s = &cfgr.shortRetryLimit; s <= &cfgr.radioType; s++)
1874 *s = cpu_to_le16(*s);
1875
1876 for(s = &cfgr.txPower; s <= &cfgr.radioSpecific; s++)
1877 *s = cpu_to_le16(*s);
1878
1879 for(s = &cfgr.arlThreshold; s <= &cfgr._reserved4[0]; s++)
1880 *s = cpu_to_le16(*s);
1881
1882 for(s = &cfgr.autoWake; s <= &cfgr.autoWake; s++)
1883 *s = cpu_to_le16(*s);
1884
1885 return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock);
1886}
1887static int readStatusRid(struct airo_info*ai, StatusRid *statr, int lock) {
1888 int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock);
1889 u16 *s;
1890
1891 statr->len = le16_to_cpu(statr->len);
1892 for(s = &statr->mode; s <= &statr->SSIDlen; s++) *s = le16_to_cpu(*s);
1893
1894 for(s = &statr->beaconPeriod; s <= &statr->shortPreamble; s++)
1895 *s = le16_to_cpu(*s);
1896 statr->load = le16_to_cpu(statr->load);
1897 statr->assocStatus = le16_to_cpu(statr->assocStatus);
1898 return rc;
1899}
1900static int readAPListRid(struct airo_info*ai, APListRid *aplr) {
1901 int rc = PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr), 1);
1902 aplr->len = le16_to_cpu(aplr->len);
1903 return rc;
1904}
1905static int writeAPListRid(struct airo_info*ai, APListRid *aplr, int lock) {
1906 int rc;
1907 aplr->len = cpu_to_le16(aplr->len);
1908 rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock);
1909 return rc;
1910}
1911static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr, int lock) {
1912 int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock);
1913 u16 *s;
1914
1915 capr->len = le16_to_cpu(capr->len);
1916 capr->prodNum = le16_to_cpu(capr->prodNum);
1917 capr->radioType = le16_to_cpu(capr->radioType);
1918 capr->country = le16_to_cpu(capr->country);
1919 for(s = &capr->txPowerLevels[0]; s <= &capr->requiredHard; s++)
1920 *s = le16_to_cpu(*s);
1921 return rc;
1922}
1923static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) {
1924 int rc = PC4500_readrid(ai, rid, sr, sizeof(*sr), lock);
1925 u32 *i;
1926
1927 sr->len = le16_to_cpu(sr->len);
1928 for(i = &sr->vals[0]; i <= &sr->vals[99]; i++) *i = le32_to_cpu(*i);
1929 return rc;
1930}
1931
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001932static void try_auto_wep(struct airo_info *ai)
1933{
1934 if (auto_wep && !(ai->flags & FLAG_RADIO_DOWN)) {
1935 ai->expires = RUN_AT(3*HZ);
1936 wake_up_interruptible(&ai->thr_wait);
1937 }
1938}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001940static int airo_open(struct net_device *dev) {
1941 struct airo_info *ai = dev->priv;
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001942 int rc = 0;
1943
1944 if (test_bit(FLAG_FLASHING, &ai->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 return -EIO;
1946
1947 /* Make sure the card is configured.
1948 * Wireless Extensions may postpone config changes until the card
1949 * is open (to pipeline changes and speed-up card setup). If
1950 * those changes are not yet commited, do it now - Jean II */
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001951 if (test_bit(FLAG_COMMIT, &ai->flags)) {
1952 disable_MAC(ai, 1);
1953 writeConfigRid(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 }
1955
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001956 if (ai->wifidev != dev) {
1957 clear_bit(JOB_DIE, &ai->jobs);
1958 ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name);
1959 if (IS_ERR(ai->airo_thread_task))
1960 return (int)PTR_ERR(ai->airo_thread_task);
1961
1962 rc = request_irq(dev->irq, airo_interrupt, IRQF_SHARED,
1963 dev->name, dev);
1964 if (rc) {
1965 airo_print_err(dev->name,
1966 "register interrupt %d failed, rc %d",
1967 dev->irq, rc);
1968 set_bit(JOB_DIE, &ai->jobs);
1969 kthread_stop(ai->airo_thread_task);
1970 return rc;
1971 }
1972
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 /* Power on the MAC controller (which may have been disabled) */
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001974 clear_bit(FLAG_RADIO_DOWN, &ai->flags);
1975 enable_interrupts(ai);
1976
1977 try_auto_wep(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 }
Michal Schmidt175ec1a2007-06-29 15:33:47 +02001979 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
1981 netif_start_queue(dev);
1982 return 0;
1983}
1984
1985static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
1986 int npacks, pending;
1987 unsigned long flags;
1988 struct airo_info *ai = dev->priv;
1989
1990 if (!skb) {
Dan Williams934d8bf2006-03-16 13:46:23 -05001991 airo_print_err(dev->name, "%s: skb == NULL!",__FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 return 0;
1993 }
1994 npacks = skb_queue_len (&ai->txq);
1995
1996 if (npacks >= MAXTXQ - 1) {
1997 netif_stop_queue (dev);
1998 if (npacks > MAXTXQ) {
1999 ai->stats.tx_fifo_errors++;
2000 return 1;
2001 }
2002 skb_queue_tail (&ai->txq, skb);
2003 return 0;
2004 }
2005
2006 spin_lock_irqsave(&ai->aux_lock, flags);
2007 skb_queue_tail (&ai->txq, skb);
2008 pending = test_bit(FLAG_PENDING_XMIT, &ai->flags);
2009 spin_unlock_irqrestore(&ai->aux_lock,flags);
2010 netif_wake_queue (dev);
2011
2012 if (pending == 0) {
2013 set_bit(FLAG_PENDING_XMIT, &ai->flags);
2014 mpi_send_packet (dev);
2015 }
2016 return 0;
2017}
2018
2019/*
2020 * @mpi_send_packet
2021 *
2022 * Attempt to transmit a packet. Can be called from interrupt
2023 * or transmit . return number of packets we tried to send
2024 */
2025
2026static int mpi_send_packet (struct net_device *dev)
2027{
2028 struct sk_buff *skb;
2029 unsigned char *buffer;
Al Viro593c2b92007-12-17 15:09:34 -05002030 s16 len;
2031 __le16 *payloadLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 struct airo_info *ai = dev->priv;
2033 u8 *sendbuf;
2034
2035 /* get a packet to send */
2036
Al Viro79ea13c2008-01-24 02:06:46 -08002037 if ((skb = skb_dequeue(&ai->txq)) == NULL) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002038 airo_print_err(dev->name,
2039 "%s: Dequeue'd zero in send_packet()",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 __FUNCTION__);
2041 return 0;
2042 }
2043
2044 /* check min length*/
2045 len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
2046 buffer = skb->data;
2047
2048 ai->txfids[0].tx_desc.offset = 0;
2049 ai->txfids[0].tx_desc.valid = 1;
2050 ai->txfids[0].tx_desc.eoc = 1;
2051 ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr);
2052
2053/*
2054 * Magic, the cards firmware needs a length count (2 bytes) in the host buffer
2055 * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen
2056 * is immediatly after it. ------------------------------------------------
2057 * |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA|
2058 * ------------------------------------------------
2059 */
2060
2061 memcpy((char *)ai->txfids[0].virtual_host_addr,
2062 (char *)&wifictlhdr8023, sizeof(wifictlhdr8023));
2063
Al Viro593c2b92007-12-17 15:09:34 -05002064 payloadLen = (__le16 *)(ai->txfids[0].virtual_host_addr +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 sizeof(wifictlhdr8023));
2066 sendbuf = ai->txfids[0].virtual_host_addr +
2067 sizeof(wifictlhdr8023) + 2 ;
2068
2069 /*
2070 * Firmware automaticly puts 802 header on so
2071 * we don't need to account for it in the length
2072 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
Al Viro593c2b92007-12-17 15:09:34 -05002074 (ntohs(((__be16 *)buffer)[6]) != 0x888E)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 MICBuffer pMic;
2076
2077 if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS)
2078 return ERROR;
2079
2080 *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic));
2081 ai->txfids[0].tx_desc.len += sizeof(pMic);
2082 /* copy data into airo dma buffer */
2083 memcpy (sendbuf, buffer, sizeof(etherHead));
2084 buffer += sizeof(etherHead);
2085 sendbuf += sizeof(etherHead);
2086 memcpy (sendbuf, &pMic, sizeof(pMic));
2087 sendbuf += sizeof(pMic);
2088 memcpy (sendbuf, buffer, len - sizeof(etherHead));
Adrian Bunka39d3e72006-01-21 01:35:15 +01002089 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 *payloadLen = cpu_to_le16(len - sizeof(etherHead));
2091
2092 dev->trans_start = jiffies;
2093
2094 /* copy data into airo dma buffer */
2095 memcpy(sendbuf, buffer, len);
2096 }
2097
2098 memcpy_toio(ai->txfids[0].card_ram_off,
2099 &ai->txfids[0].tx_desc, sizeof(TxFid));
2100
2101 OUT4500(ai, EVACK, 8);
2102
2103 dev_kfree_skb_any(skb);
2104 return 1;
2105}
2106
Gabriel A. Devenyi29b09fc2005-11-03 19:30:47 -05002107static void get_tx_error(struct airo_info *ai, s32 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108{
Al Viro593c2b92007-12-17 15:09:34 -05002109 __le16 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
2111 if (fid < 0)
2112 status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status;
2113 else {
2114 if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) != SUCCESS)
2115 return;
2116 bap_read(ai, &status, 2, BAP0);
2117 }
2118 if (le16_to_cpu(status) & 2) /* Too many retries */
2119 ai->stats.tx_aborted_errors++;
2120 if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */
2121 ai->stats.tx_heartbeat_errors++;
2122 if (le16_to_cpu(status) & 8) /* Aid fail */
2123 { }
2124 if (le16_to_cpu(status) & 0x10) /* MAC disabled */
2125 ai->stats.tx_carrier_errors++;
2126 if (le16_to_cpu(status) & 0x20) /* Association lost */
2127 { }
2128 /* We produce a TXDROP event only for retry or lifetime
2129 * exceeded, because that's the only status that really mean
2130 * that this particular node went away.
2131 * Other errors means that *we* screwed up. - Jean II */
2132 if ((le16_to_cpu(status) & 2) ||
2133 (le16_to_cpu(status) & 4)) {
2134 union iwreq_data wrqu;
2135 char junk[0x18];
2136
2137 /* Faster to skip over useless data than to do
2138 * another bap_setup(). We are at offset 0x6 and
2139 * need to go to 0x18 and read 6 bytes - Jean II */
2140 bap_read(ai, (u16 *) junk, 0x18, BAP0);
2141
2142 /* Copy 802.11 dest address.
2143 * We use the 802.11 header because the frame may
2144 * not be 802.3 or may be mangled...
2145 * In Ad-Hoc mode, it will be the node address.
2146 * In managed mode, it will be most likely the AP addr
2147 * User space will figure out how to convert it to
2148 * whatever it needs (IP address or else).
2149 * - Jean II */
2150 memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN);
2151 wrqu.addr.sa_family = ARPHRD_ETHER;
2152
2153 /* Send event to user space */
2154 wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL);
2155 }
2156}
2157
2158static void airo_end_xmit(struct net_device *dev) {
2159 u16 status;
2160 int i;
2161 struct airo_info *priv = dev->priv;
2162 struct sk_buff *skb = priv->xmit.skb;
2163 int fid = priv->xmit.fid;
2164 u32 *fids = priv->fids;
2165
Dan Williams3c304952006-04-15 12:26:18 -04002166 clear_bit(JOB_XMIT, &priv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 clear_bit(FLAG_PENDING_XMIT, &priv->flags);
2168 status = transmit_802_3_packet (priv, fids[fid], skb->data);
2169 up(&priv->sem);
2170
2171 i = 0;
2172 if ( status == SUCCESS ) {
2173 dev->trans_start = jiffies;
2174 for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++);
2175 } else {
2176 priv->fids[fid] &= 0xffff;
2177 priv->stats.tx_window_errors++;
2178 }
2179 if (i < MAX_FIDS / 2)
2180 netif_wake_queue(dev);
2181 dev_kfree_skb(skb);
2182}
2183
2184static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
2185 s16 len;
2186 int i, j;
2187 struct airo_info *priv = dev->priv;
2188 u32 *fids = priv->fids;
2189
2190 if ( skb == NULL ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002191 airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 return 0;
2193 }
2194
2195 /* Find a vacant FID */
2196 for( i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++ );
2197 for( j = i + 1; j < MAX_FIDS / 2 && (fids[j] & 0xffff0000); j++ );
2198
2199 if ( j >= MAX_FIDS / 2 ) {
2200 netif_stop_queue(dev);
2201
2202 if (i == MAX_FIDS / 2) {
2203 priv->stats.tx_fifo_errors++;
2204 return 1;
2205 }
2206 }
2207 /* check min length*/
2208 len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
2209 /* Mark fid as used & save length for later */
2210 fids[i] |= (len << 16);
2211 priv->xmit.skb = skb;
2212 priv->xmit.fid = i;
2213 if (down_trylock(&priv->sem) != 0) {
2214 set_bit(FLAG_PENDING_XMIT, &priv->flags);
2215 netif_stop_queue(dev);
Dan Williams3c304952006-04-15 12:26:18 -04002216 set_bit(JOB_XMIT, &priv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 wake_up_interruptible(&priv->thr_wait);
2218 } else
2219 airo_end_xmit(dev);
2220 return 0;
2221}
2222
2223static void airo_end_xmit11(struct net_device *dev) {
2224 u16 status;
2225 int i;
2226 struct airo_info *priv = dev->priv;
2227 struct sk_buff *skb = priv->xmit11.skb;
2228 int fid = priv->xmit11.fid;
2229 u32 *fids = priv->fids;
2230
Dan Williams3c304952006-04-15 12:26:18 -04002231 clear_bit(JOB_XMIT11, &priv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 clear_bit(FLAG_PENDING_XMIT11, &priv->flags);
2233 status = transmit_802_11_packet (priv, fids[fid], skb->data);
2234 up(&priv->sem);
2235
2236 i = MAX_FIDS / 2;
2237 if ( status == SUCCESS ) {
2238 dev->trans_start = jiffies;
2239 for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++);
2240 } else {
2241 priv->fids[fid] &= 0xffff;
2242 priv->stats.tx_window_errors++;
2243 }
2244 if (i < MAX_FIDS)
2245 netif_wake_queue(dev);
2246 dev_kfree_skb(skb);
2247}
2248
2249static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
2250 s16 len;
2251 int i, j;
2252 struct airo_info *priv = dev->priv;
2253 u32 *fids = priv->fids;
2254
2255 if (test_bit(FLAG_MPI, &priv->flags)) {
2256 /* Not implemented yet for MPI350 */
2257 netif_stop_queue(dev);
2258 return -ENETDOWN;
2259 }
2260
2261 if ( skb == NULL ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002262 airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 return 0;
2264 }
2265
2266 /* Find a vacant FID */
2267 for( i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++ );
2268 for( j = i + 1; j < MAX_FIDS && (fids[j] & 0xffff0000); j++ );
2269
2270 if ( j >= MAX_FIDS ) {
2271 netif_stop_queue(dev);
2272
2273 if (i == MAX_FIDS) {
2274 priv->stats.tx_fifo_errors++;
2275 return 1;
2276 }
2277 }
2278 /* check min length*/
2279 len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
2280 /* Mark fid as used & save length for later */
2281 fids[i] |= (len << 16);
2282 priv->xmit11.skb = skb;
2283 priv->xmit11.fid = i;
2284 if (down_trylock(&priv->sem) != 0) {
2285 set_bit(FLAG_PENDING_XMIT11, &priv->flags);
2286 netif_stop_queue(dev);
Dan Williams3c304952006-04-15 12:26:18 -04002287 set_bit(JOB_XMIT11, &priv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 wake_up_interruptible(&priv->thr_wait);
2289 } else
2290 airo_end_xmit11(dev);
2291 return 0;
2292}
2293
2294static void airo_read_stats(struct airo_info *ai) {
2295 StatsRid stats_rid;
2296 u32 *vals = stats_rid.vals;
2297
Dan Williams3c304952006-04-15 12:26:18 -04002298 clear_bit(JOB_STATS, &ai->jobs);
Pavel Machekca078ba2005-09-03 15:56:57 -07002299 if (ai->power.event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 up(&ai->sem);
2301 return;
2302 }
2303 readStatsRid(ai, &stats_rid, RID_STATS, 0);
2304 up(&ai->sem);
2305
2306 ai->stats.rx_packets = vals[43] + vals[44] + vals[45];
2307 ai->stats.tx_packets = vals[39] + vals[40] + vals[41];
2308 ai->stats.rx_bytes = vals[92];
2309 ai->stats.tx_bytes = vals[91];
2310 ai->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4];
2311 ai->stats.tx_errors = vals[42] + ai->stats.tx_fifo_errors;
2312 ai->stats.multicast = vals[43];
2313 ai->stats.collisions = vals[89];
2314
2315 /* detailed rx_errors: */
2316 ai->stats.rx_length_errors = vals[3];
2317 ai->stats.rx_crc_errors = vals[4];
2318 ai->stats.rx_frame_errors = vals[2];
2319 ai->stats.rx_fifo_errors = vals[0];
2320}
2321
Jouni Malinenff1d2762005-05-12 22:54:16 -04002322static struct net_device_stats *airo_get_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323{
2324 struct airo_info *local = dev->priv;
2325
Dan Williams3c304952006-04-15 12:26:18 -04002326 if (!test_bit(JOB_STATS, &local->jobs)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 /* Get stats out of the card if available */
2328 if (down_trylock(&local->sem) != 0) {
Dan Williams3c304952006-04-15 12:26:18 -04002329 set_bit(JOB_STATS, &local->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 wake_up_interruptible(&local->thr_wait);
2331 } else
2332 airo_read_stats(local);
2333 }
2334
2335 return &local->stats;
2336}
2337
2338static void airo_set_promisc(struct airo_info *ai) {
2339 Cmd cmd;
2340 Resp rsp;
2341
2342 memset(&cmd, 0, sizeof(cmd));
2343 cmd.cmd=CMD_SETMODE;
Dan Williams3c304952006-04-15 12:26:18 -04002344 clear_bit(JOB_PROMISC, &ai->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
2346 issuecommand(ai, &cmd, &rsp);
2347 up(&ai->sem);
2348}
2349
2350static void airo_set_multicast_list(struct net_device *dev) {
2351 struct airo_info *ai = dev->priv;
2352
2353 if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
2354 change_bit(FLAG_PROMISC, &ai->flags);
2355 if (down_trylock(&ai->sem) != 0) {
Dan Williams3c304952006-04-15 12:26:18 -04002356 set_bit(JOB_PROMISC, &ai->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 wake_up_interruptible(&ai->thr_wait);
2358 } else
2359 airo_set_promisc(ai);
2360 }
2361
2362 if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) {
2363 /* Turn on multicast. (Should be already setup...) */
2364 }
2365}
2366
2367static int airo_set_mac_address(struct net_device *dev, void *p)
2368{
2369 struct airo_info *ai = dev->priv;
2370 struct sockaddr *addr = p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
2372 readConfigRid(ai, 1);
2373 memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
2374 set_bit (FLAG_COMMIT, &ai->flags);
2375 disable_MAC(ai, 1);
2376 writeConfigRid (ai, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02002377 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 memcpy (ai->dev->dev_addr, addr->sa_data, dev->addr_len);
2379 if (ai->wifidev)
2380 memcpy (ai->wifidev->dev_addr, addr->sa_data, dev->addr_len);
2381 return 0;
2382}
2383
2384static int airo_change_mtu(struct net_device *dev, int new_mtu)
2385{
2386 if ((new_mtu < 68) || (new_mtu > 2400))
2387 return -EINVAL;
2388 dev->mtu = new_mtu;
2389 return 0;
2390}
2391
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01002392static LIST_HEAD(airo_devices);
2393
2394static void add_airo_dev(struct airo_info *ai)
2395{
2396 /* Upper layers already keep track of PCI devices,
2397 * so we only need to remember our non-PCI cards. */
2398 if (!ai->pci)
2399 list_add_tail(&ai->dev_list, &airo_devices);
2400}
2401
2402static void del_airo_dev(struct airo_info *ai)
2403{
2404 if (!ai->pci)
2405 list_del(&ai->dev_list);
2406}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
2408static int airo_close(struct net_device *dev) {
2409 struct airo_info *ai = dev->priv;
2410
2411 netif_stop_queue(dev);
2412
2413 if (ai->wifidev != dev) {
2414#ifdef POWER_ON_DOWN
2415 /* Shut power to the card. The idea is that the user can save
2416 * power when he doesn't need the card with "ifconfig down".
2417 * That's the method that is most friendly towards the network
2418 * stack (i.e. the network stack won't try to broadcast
2419 * anything on the interface and routes are gone. Jean II */
2420 set_bit(FLAG_RADIO_DOWN, &ai->flags);
2421 disable_MAC(ai, 1);
2422#endif
2423 disable_interrupts( ai );
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02002424
2425 free_irq(dev->irq, dev);
2426
2427 set_bit(JOB_DIE, &ai->jobs);
2428 kthread_stop(ai->airo_thread_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 }
2430 return 0;
2431}
2432
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433void stop_airo_card( struct net_device *dev, int freeres )
2434{
2435 struct airo_info *ai = dev->priv;
2436
2437 set_bit(FLAG_RADIO_DOWN, &ai->flags);
2438 disable_MAC(ai, 1);
2439 disable_interrupts(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 takedown_proc_entry( dev, ai );
2441 if (test_bit(FLAG_REGISTERED, &ai->flags)) {
2442 unregister_netdev( dev );
2443 if (ai->wifidev) {
2444 unregister_netdev(ai->wifidev);
2445 free_netdev(ai->wifidev);
2446 ai->wifidev = NULL;
2447 }
2448 clear_bit(FLAG_REGISTERED, &ai->flags);
2449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 /*
2451 * Clean out tx queue
2452 */
David S. Millerb03efcf2005-07-08 14:57:23 -07002453 if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 struct sk_buff *skb = NULL;
2455 for (;(skb = skb_dequeue(&ai->txq));)
2456 dev_kfree_skb(skb);
2457 }
2458
Dan Williams9e75af32006-03-16 13:46:29 -05002459 airo_networks_free (ai);
2460
Jesper Juhlb4558ea2005-10-28 16:53:13 -04002461 kfree(ai->flash);
2462 kfree(ai->rssi);
2463 kfree(ai->APList);
2464 kfree(ai->SSID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 if (freeres) {
2466 /* PCMCIA frees this stuff, so only for PCI and ISA */
2467 release_region( dev->base_addr, 64 );
2468 if (test_bit(FLAG_MPI, &ai->flags)) {
2469 if (ai->pci)
2470 mpi_unmap_card(ai->pci);
2471 if (ai->pcimem)
2472 iounmap(ai->pcimem);
2473 if (ai->pciaux)
2474 iounmap(ai->pciaux);
2475 pci_free_consistent(ai->pci, PCI_SHARED_LEN,
2476 ai->shared, ai->shared_dma);
2477 }
2478 }
Herbert Xuf12cc202006-08-22 20:36:13 +10002479 crypto_free_cipher(ai->tfm);
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01002480 del_airo_dev(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 free_netdev( dev );
2482}
2483
2484EXPORT_SYMBOL(stop_airo_card);
2485
Stephen Hemmingerb95cce32007-09-26 22:13:38 -07002486static int wll_header_parse(const struct sk_buff *skb, unsigned char *haddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487{
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -07002488 memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 return ETH_ALEN;
2490}
2491
2492static void mpi_unmap_card(struct pci_dev *pci)
2493{
2494 unsigned long mem_start = pci_resource_start(pci, 1);
2495 unsigned long mem_len = pci_resource_len(pci, 1);
2496 unsigned long aux_start = pci_resource_start(pci, 2);
2497 unsigned long aux_len = AUXMEMSIZE;
2498
2499 release_mem_region(aux_start, aux_len);
2500 release_mem_region(mem_start, mem_len);
2501}
2502
2503/*************************************************************
2504 * This routine assumes that descriptors have been setup .
2505 * Run at insmod time or after reset when the decriptors
2506 * have been initialized . Returns 0 if all is well nz
2507 * otherwise . Does not allocate memory but sets up card
2508 * using previously allocated descriptors.
2509 */
2510static int mpi_init_descriptors (struct airo_info *ai)
2511{
2512 Cmd cmd;
2513 Resp rsp;
2514 int i;
2515 int rc = SUCCESS;
2516
2517 /* Alloc card RX descriptors */
2518 netif_stop_queue(ai->dev);
2519
2520 memset(&rsp,0,sizeof(rsp));
2521 memset(&cmd,0,sizeof(cmd));
2522
2523 cmd.cmd = CMD_ALLOCATEAUX;
2524 cmd.parm0 = FID_RX;
2525 cmd.parm1 = (ai->rxfids[0].card_ram_off - ai->pciaux);
2526 cmd.parm2 = MPI_MAX_FIDS;
2527 rc=issuecommand(ai, &cmd, &rsp);
2528 if (rc != SUCCESS) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002529 airo_print_err(ai->dev->name, "Couldn't allocate RX FID");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 return rc;
2531 }
2532
2533 for (i=0; i<MPI_MAX_FIDS; i++) {
2534 memcpy_toio(ai->rxfids[i].card_ram_off,
2535 &ai->rxfids[i].rx_desc, sizeof(RxFid));
2536 }
2537
2538 /* Alloc card TX descriptors */
2539
2540 memset(&rsp,0,sizeof(rsp));
2541 memset(&cmd,0,sizeof(cmd));
2542
2543 cmd.cmd = CMD_ALLOCATEAUX;
2544 cmd.parm0 = FID_TX;
2545 cmd.parm1 = (ai->txfids[0].card_ram_off - ai->pciaux);
2546 cmd.parm2 = MPI_MAX_FIDS;
2547
2548 for (i=0; i<MPI_MAX_FIDS; i++) {
2549 ai->txfids[i].tx_desc.valid = 1;
2550 memcpy_toio(ai->txfids[i].card_ram_off,
2551 &ai->txfids[i].tx_desc, sizeof(TxFid));
2552 }
2553 ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
2554
2555 rc=issuecommand(ai, &cmd, &rsp);
2556 if (rc != SUCCESS) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002557 airo_print_err(ai->dev->name, "Couldn't allocate TX FID");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 return rc;
2559 }
2560
2561 /* Alloc card Rid descriptor */
2562 memset(&rsp,0,sizeof(rsp));
2563 memset(&cmd,0,sizeof(cmd));
2564
2565 cmd.cmd = CMD_ALLOCATEAUX;
2566 cmd.parm0 = RID_RW;
2567 cmd.parm1 = (ai->config_desc.card_ram_off - ai->pciaux);
2568 cmd.parm2 = 1; /* Magic number... */
2569 rc=issuecommand(ai, &cmd, &rsp);
2570 if (rc != SUCCESS) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002571 airo_print_err(ai->dev->name, "Couldn't allocate RID");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 return rc;
2573 }
2574
2575 memcpy_toio(ai->config_desc.card_ram_off,
2576 &ai->config_desc.rid_desc, sizeof(Rid));
2577
2578 return rc;
2579}
2580
2581/*
2582 * We are setting up three things here:
2583 * 1) Map AUX memory for descriptors: Rid, TxFid, or RxFid.
2584 * 2) Map PCI memory for issueing commands.
2585 * 3) Allocate memory (shared) to send and receive ethernet frames.
2586 */
Michal Schmidt1138c372007-06-29 15:33:41 +02002587static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588{
2589 unsigned long mem_start, mem_len, aux_start, aux_len;
2590 int rc = -1;
2591 int i;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002592 dma_addr_t busaddroff;
2593 unsigned char *vpackoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 unsigned char __iomem *pciaddroff;
2595
2596 mem_start = pci_resource_start(pci, 1);
2597 mem_len = pci_resource_len(pci, 1);
2598 aux_start = pci_resource_start(pci, 2);
2599 aux_len = AUXMEMSIZE;
2600
Michal Schmidt1138c372007-06-29 15:33:41 +02002601 if (!request_mem_region(mem_start, mem_len, DRV_NAME)) {
2602 airo_print_err("", "Couldn't get region %x[%x]",
2603 (int)mem_start, (int)mem_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 goto out;
2605 }
Michal Schmidt1138c372007-06-29 15:33:41 +02002606 if (!request_mem_region(aux_start, aux_len, DRV_NAME)) {
2607 airo_print_err("", "Couldn't get region %x[%x]",
2608 (int)aux_start, (int)aux_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 goto free_region1;
2610 }
2611
2612 ai->pcimem = ioremap(mem_start, mem_len);
2613 if (!ai->pcimem) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002614 airo_print_err("", "Couldn't map region %x[%x]",
2615 (int)mem_start, (int)mem_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 goto free_region2;
2617 }
2618 ai->pciaux = ioremap(aux_start, aux_len);
2619 if (!ai->pciaux) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002620 airo_print_err("", "Couldn't map region %x[%x]",
2621 (int)aux_start, (int)aux_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 goto free_memmap;
2623 }
2624
2625 /* Reserve PKTSIZE for each fid and 2K for the Rids */
2626 ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma);
2627 if (!ai->shared) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002628 airo_print_err("", "Couldn't alloc_consistent %d",
2629 PCI_SHARED_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 goto free_auxmap;
2631 }
2632
2633 /*
2634 * Setup descriptor RX, TX, CONFIG
2635 */
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002636 busaddroff = ai->shared_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 pciaddroff = ai->pciaux + AUX_OFFSET;
2638 vpackoff = ai->shared;
2639
2640 /* RX descriptor setup */
2641 for(i = 0; i < MPI_MAX_FIDS; i++) {
2642 ai->rxfids[i].pending = 0;
2643 ai->rxfids[i].card_ram_off = pciaddroff;
2644 ai->rxfids[i].virtual_host_addr = vpackoff;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002645 ai->rxfids[i].rx_desc.host_addr = busaddroff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 ai->rxfids[i].rx_desc.valid = 1;
2647 ai->rxfids[i].rx_desc.len = PKTSIZE;
2648 ai->rxfids[i].rx_desc.rdy = 0;
2649
2650 pciaddroff += sizeof(RxFid);
2651 busaddroff += PKTSIZE;
2652 vpackoff += PKTSIZE;
2653 }
2654
2655 /* TX descriptor setup */
2656 for(i = 0; i < MPI_MAX_FIDS; i++) {
2657 ai->txfids[i].card_ram_off = pciaddroff;
2658 ai->txfids[i].virtual_host_addr = vpackoff;
2659 ai->txfids[i].tx_desc.valid = 1;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002660 ai->txfids[i].tx_desc.host_addr = busaddroff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 memcpy(ai->txfids[i].virtual_host_addr,
2662 &wifictlhdr8023, sizeof(wifictlhdr8023));
2663
2664 pciaddroff += sizeof(TxFid);
2665 busaddroff += PKTSIZE;
2666 vpackoff += PKTSIZE;
2667 }
2668 ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
2669
2670 /* Rid descriptor setup */
2671 ai->config_desc.card_ram_off = pciaddroff;
2672 ai->config_desc.virtual_host_addr = vpackoff;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002673 ai->config_desc.rid_desc.host_addr = busaddroff;
2674 ai->ridbus = busaddroff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 ai->config_desc.rid_desc.rid = 0;
2676 ai->config_desc.rid_desc.len = RIDSIZE;
2677 ai->config_desc.rid_desc.valid = 1;
2678 pciaddroff += sizeof(Rid);
2679 busaddroff += RIDSIZE;
2680 vpackoff += RIDSIZE;
2681
2682 /* Tell card about descriptors */
2683 if (mpi_init_descriptors (ai) != SUCCESS)
2684 goto free_shared;
2685
2686 return 0;
2687 free_shared:
2688 pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
2689 free_auxmap:
2690 iounmap(ai->pciaux);
2691 free_memmap:
2692 iounmap(ai->pcimem);
2693 free_region2:
2694 release_mem_region(aux_start, aux_len);
2695 free_region1:
2696 release_mem_region(mem_start, mem_len);
2697 out:
2698 return rc;
2699}
2700
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07002701static const struct header_ops airo_header_ops = {
2702 .parse = wll_header_parse,
2703};
2704
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705static void wifi_setup(struct net_device *dev)
2706{
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07002707 dev->header_ops = &airo_header_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 dev->hard_start_xmit = &airo_start_xmit11;
2709 dev->get_stats = &airo_get_stats;
2710 dev->set_mac_address = &airo_set_mac_address;
2711 dev->do_ioctl = &airo_ioctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 dev->wireless_handlers = &airo_handler_def;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 dev->change_mtu = &airo_change_mtu;
2714 dev->open = &airo_open;
2715 dev->stop = &airo_close;
2716
2717 dev->type = ARPHRD_IEEE80211;
2718 dev->hard_header_len = ETH_HLEN;
Dan Williams15db2762006-03-16 13:46:27 -05002719 dev->mtu = AIRO_DEF_MTU;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 dev->addr_len = ETH_ALEN;
2721 dev->tx_queue_len = 100;
2722
2723 memset(dev->broadcast,0xFF, ETH_ALEN);
2724
2725 dev->flags = IFF_BROADCAST|IFF_MULTICAST;
2726}
2727
2728static struct net_device *init_wifidev(struct airo_info *ai,
2729 struct net_device *ethdev)
2730{
2731 int err;
2732 struct net_device *dev = alloc_netdev(0, "wifi%d", wifi_setup);
2733 if (!dev)
2734 return NULL;
2735 dev->priv = ethdev->priv;
2736 dev->irq = ethdev->irq;
2737 dev->base_addr = ethdev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 dev->wireless_data = ethdev->wireless_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len);
2740 err = register_netdev(dev);
2741 if (err<0) {
2742 free_netdev(dev);
2743 return NULL;
2744 }
2745 return dev;
2746}
2747
Jouni Malinenff1d2762005-05-12 22:54:16 -04002748static int reset_card( struct net_device *dev , int lock) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 struct airo_info *ai = dev->priv;
2750
2751 if (lock && down_interruptible(&ai->sem))
2752 return -1;
2753 waitbusy (ai);
2754 OUT4500(ai,COMMAND,CMD_SOFTRESET);
2755 msleep(200);
2756 waitbusy (ai);
2757 msleep(200);
2758 if (lock)
2759 up(&ai->sem);
2760 return 0;
2761}
2762
Dan Williams3c304952006-04-15 12:26:18 -04002763#define AIRO_MAX_NETWORK_COUNT 64
Dan Williams9e75af32006-03-16 13:46:29 -05002764static int airo_networks_allocate(struct airo_info *ai)
2765{
2766 if (ai->networks)
2767 return 0;
2768
2769 ai->networks =
Dan Williams3c304952006-04-15 12:26:18 -04002770 kzalloc(AIRO_MAX_NETWORK_COUNT * sizeof(BSSListElement),
Dan Williams9e75af32006-03-16 13:46:29 -05002771 GFP_KERNEL);
2772 if (!ai->networks) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002773 airo_print_warn("", "Out of memory allocating beacons");
Dan Williams9e75af32006-03-16 13:46:29 -05002774 return -ENOMEM;
2775 }
2776
2777 return 0;
2778}
2779
2780static void airo_networks_free(struct airo_info *ai)
2781{
Dan Williams9e75af32006-03-16 13:46:29 -05002782 kfree(ai->networks);
2783 ai->networks = NULL;
2784}
2785
2786static void airo_networks_initialize(struct airo_info *ai)
2787{
2788 int i;
2789
2790 INIT_LIST_HEAD(&ai->network_free_list);
2791 INIT_LIST_HEAD(&ai->network_list);
Dan Williams3c304952006-04-15 12:26:18 -04002792 for (i = 0; i < AIRO_MAX_NETWORK_COUNT; i++)
Dan Williams9e75af32006-03-16 13:46:29 -05002793 list_add_tail(&ai->networks[i].list,
2794 &ai->network_free_list);
2795}
2796
Dan Williams3c304952006-04-15 12:26:18 -04002797static int airo_test_wpa_capable(struct airo_info *ai)
2798{
2799 int status;
2800 CapabilityRid cap_rid;
Dan Williams3c304952006-04-15 12:26:18 -04002801
2802 status = readCapabilityRid(ai, &cap_rid, 1);
2803 if (status != SUCCESS) return 0;
2804
2805 /* Only firmware versions 5.30.17 or better can do WPA */
2806 if ((cap_rid.softVer > 0x530)
Michal Schmidt0c6157a2006-05-02 23:29:55 +02002807 || ((cap_rid.softVer == 0x530) && (cap_rid.softSubVer >= 17))) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002808 airo_print_info("", "WPA is supported.");
Dan Williams3c304952006-04-15 12:26:18 -04002809 return 1;
2810 }
2811
2812 /* No WPA support */
Michal Schmidt1138c372007-06-29 15:33:41 +02002813 airo_print_info("", "WPA unsupported (only firmware versions 5.30.17"
Dan Williams3c304952006-04-15 12:26:18 -04002814 " and greater support WPA. Detected %s)", cap_rid.prodVer);
2815 return 0;
2816}
2817
Jouni Malinenff1d2762005-05-12 22:54:16 -04002818static struct net_device *_init_airo_card( unsigned short irq, int port,
2819 int is_pcmcia, struct pci_dev *pci,
2820 struct device *dmdev )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821{
2822 struct net_device *dev;
2823 struct airo_info *ai;
2824 int i, rc;
Joe Perches0795af52007-10-03 17:59:30 -07002825 DECLARE_MAC_BUF(mac);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826
2827 /* Create the network device object. */
Michal Schmidt1138c372007-06-29 15:33:41 +02002828 dev = alloc_netdev(sizeof(*ai), "", ether_setup);
2829 if (!dev) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002830 airo_print_err("", "Couldn't alloc_etherdev");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 }
2833
2834 ai = dev->priv;
2835 ai->wifidev = NULL;
Michal Schmidtfb038c22007-06-29 15:33:52 +02002836 ai->flags = 1 << FLAG_RADIO_DOWN;
Dan Williams3c304952006-04-15 12:26:18 -04002837 ai->jobs = 0;
Dan Williams934d8bf2006-03-16 13:46:23 -05002838 ai->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002840 airo_print_dbg("", "Found an MPI350 card");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 set_bit(FLAG_MPI, &ai->flags);
2842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 spin_lock_init(&ai->aux_lock);
2844 sema_init(&ai->sem, 1);
2845 ai->config.len = 0;
2846 ai->pci = pci;
2847 init_waitqueue_head (&ai->thr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 ai->tfm = NULL;
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01002849 add_airo_dev(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850
Dan Williams9e75af32006-03-16 13:46:29 -05002851 if (airo_networks_allocate (ai))
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02002852 goto err_out_free;
Dan Williams9e75af32006-03-16 13:46:29 -05002853 airo_networks_initialize (ai);
2854
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 /* The Airo-specific entries in the device structure. */
2856 if (test_bit(FLAG_MPI,&ai->flags)) {
2857 skb_queue_head_init (&ai->txq);
2858 dev->hard_start_xmit = &mpi_start_xmit;
2859 } else
2860 dev->hard_start_xmit = &airo_start_xmit;
2861 dev->get_stats = &airo_get_stats;
2862 dev->set_multicast_list = &airo_set_multicast_list;
2863 dev->set_mac_address = &airo_set_mac_address;
2864 dev->do_ioctl = &airo_ioctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 dev->wireless_handlers = &airo_handler_def;
2866 ai->wireless_data.spy_data = &ai->spy_data;
2867 dev->wireless_data = &ai->wireless_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 dev->change_mtu = &airo_change_mtu;
2869 dev->open = &airo_open;
2870 dev->stop = &airo_close;
2871 dev->irq = irq;
2872 dev->base_addr = port;
2873
2874 SET_NETDEV_DEV(dev, dmdev);
2875
Matthieu CASTET1d97f382005-12-01 02:35:26 -05002876 reset_card (dev, 1);
2877 msleep(400);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 if (!is_pcmcia) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002880 if (!request_region(dev->base_addr, 64, DRV_NAME)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 rc = -EBUSY;
Dan Williams934d8bf2006-03-16 13:46:23 -05002882 airo_print_err(dev->name, "Couldn't request region");
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02002883 goto err_out_nets;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 }
2885 }
2886
2887 if (test_bit(FLAG_MPI,&ai->flags)) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002888 if (mpi_map_card(ai, pci)) {
2889 airo_print_err("", "Could not map memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 goto err_out_res;
2891 }
2892 }
2893
2894 if (probe) {
2895 if ( setup_card( ai, dev->dev_addr, 1 ) != SUCCESS ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002896 airo_print_err(dev->name, "MAC could not be enabled" );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 rc = -EIO;
2898 goto err_out_map;
2899 }
2900 } else if (!test_bit(FLAG_MPI,&ai->flags)) {
2901 ai->bap_read = fast_bap_read;
2902 set_bit(FLAG_FLASHING, &ai->flags);
2903 }
2904
Dan Williams3c304952006-04-15 12:26:18 -04002905 /* Test for WPA support */
2906 if (airo_test_wpa_capable(ai)) {
2907 set_bit(FLAG_WPA_CAPABLE, &ai->flags);
2908 ai->bssListFirst = RID_WPA_BSSLISTFIRST;
2909 ai->bssListNext = RID_WPA_BSSLISTNEXT;
2910 ai->bssListRidLen = sizeof(BSSListRid);
2911 } else {
2912 ai->bssListFirst = RID_BSSLISTFIRST;
2913 ai->bssListNext = RID_BSSLISTNEXT;
2914 ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra);
2915 }
2916
Michal Schmidt1138c372007-06-29 15:33:41 +02002917 strcpy(dev->name, "eth%d");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 rc = register_netdev(dev);
2919 if (rc) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002920 airo_print_err(dev->name, "Couldn't register_netdev");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 goto err_out_map;
2922 }
2923 ai->wifidev = init_wifidev(ai, dev);
Florin Malita431aca52006-10-10 16:46:30 -04002924 if (!ai->wifidev)
2925 goto err_out_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926
2927 set_bit(FLAG_REGISTERED,&ai->flags);
Joe Perches0795af52007-10-03 17:59:30 -07002928 airo_print_info(dev->name, "MAC enabled %s",
2929 print_mac(mac, dev->dev_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930
2931 /* Allocate the transmit buffers */
2932 if (probe && !test_bit(FLAG_MPI,&ai->flags))
2933 for( i = 0; i < MAX_FIDS; i++ )
Dan Williams15db2762006-03-16 13:46:27 -05002934 ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935
Florin Malita431aca52006-10-10 16:46:30 -04002936 if (setup_proc_entry(dev, dev->priv) < 0)
2937 goto err_out_wifi;
2938
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 return dev;
2940
Florin Malita431aca52006-10-10 16:46:30 -04002941err_out_wifi:
2942 unregister_netdev(ai->wifidev);
2943 free_netdev(ai->wifidev);
2944err_out_reg:
2945 unregister_netdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946err_out_map:
2947 if (test_bit(FLAG_MPI,&ai->flags) && pci) {
2948 pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
2949 iounmap(ai->pciaux);
2950 iounmap(ai->pcimem);
2951 mpi_unmap_card(ai->pci);
2952 }
2953err_out_res:
2954 if (!is_pcmcia)
2955 release_region( dev->base_addr, 64 );
Michal Schmidt4d881902007-03-16 12:42:59 +01002956err_out_nets:
2957 airo_networks_free(ai);
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01002958 del_airo_dev(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959err_out_free:
2960 free_netdev(dev);
2961 return NULL;
2962}
2963
2964struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia,
2965 struct device *dmdev)
2966{
2967 return _init_airo_card ( irq, port, is_pcmcia, NULL, dmdev);
2968}
2969
2970EXPORT_SYMBOL(init_airo_card);
2971
2972static int waitbusy (struct airo_info *ai) {
2973 int delay = 0;
2974 while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) & (delay < 10000)) {
2975 udelay (10);
2976 if ((++delay % 20) == 0)
2977 OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
2978 }
2979 return delay < 10000;
2980}
2981
2982int reset_airo_card( struct net_device *dev )
2983{
2984 int i;
2985 struct airo_info *ai = dev->priv;
Joe Perches0795af52007-10-03 17:59:30 -07002986 DECLARE_MAC_BUF(mac);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987
2988 if (reset_card (dev, 1))
2989 return -1;
2990
2991 if ( setup_card(ai, dev->dev_addr, 1 ) != SUCCESS ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002992 airo_print_err(dev->name, "MAC could not be enabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 return -1;
2994 }
Joe Perches0795af52007-10-03 17:59:30 -07002995 airo_print_info(dev->name, "MAC enabled %s",
2996 print_mac(mac, dev->dev_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 /* Allocate the transmit buffers if needed */
2998 if (!test_bit(FLAG_MPI,&ai->flags))
2999 for( i = 0; i < MAX_FIDS; i++ )
Dan Williams15db2762006-03-16 13:46:27 -05003000 ai->fids[i] = transmit_allocate (ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001
3002 enable_interrupts( ai );
3003 netif_wake_queue(dev);
3004 return 0;
3005}
3006
3007EXPORT_SYMBOL(reset_airo_card);
3008
3009static void airo_send_event(struct net_device *dev) {
3010 struct airo_info *ai = dev->priv;
3011 union iwreq_data wrqu;
3012 StatusRid status_rid;
3013
Dan Williams3c304952006-04-15 12:26:18 -04003014 clear_bit(JOB_EVENT, &ai->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
3016 up(&ai->sem);
3017 wrqu.data.length = 0;
3018 wrqu.data.flags = 0;
3019 memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN);
3020 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
3021
3022 /* Send event to user space */
3023 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
3024}
3025
Dan Williams9e75af32006-03-16 13:46:29 -05003026static void airo_process_scan_results (struct airo_info *ai) {
3027 union iwreq_data wrqu;
Dan Williams3c304952006-04-15 12:26:18 -04003028 BSSListRid bss;
Dan Williams9e75af32006-03-16 13:46:29 -05003029 int rc;
3030 BSSListElement * loop_net;
3031 BSSListElement * tmp_net;
3032
3033 /* Blow away current list of scan results */
3034 list_for_each_entry_safe (loop_net, tmp_net, &ai->network_list, list) {
3035 list_move_tail (&loop_net->list, &ai->network_free_list);
3036 /* Don't blow away ->list, just BSS data */
3037 memset (loop_net, 0, sizeof (loop_net->bss));
3038 }
3039
3040 /* Try to read the first entry of the scan result */
Dan Williams3c304952006-04-15 12:26:18 -04003041 rc = PC4500_readrid(ai, ai->bssListFirst, &bss, ai->bssListRidLen, 0);
3042 if((rc) || (bss.index == 0xffff)) {
Dan Williams9e75af32006-03-16 13:46:29 -05003043 /* No scan results */
3044 goto out;
3045 }
3046
3047 /* Read and parse all entries */
3048 tmp_net = NULL;
Dan Williams3c304952006-04-15 12:26:18 -04003049 while((!rc) && (bss.index != 0xffff)) {
Dan Williams9e75af32006-03-16 13:46:29 -05003050 /* Grab a network off the free list */
3051 if (!list_empty(&ai->network_free_list)) {
3052 tmp_net = list_entry(ai->network_free_list.next,
3053 BSSListElement, list);
3054 list_del(ai->network_free_list.next);
3055 }
3056
3057 if (tmp_net != NULL) {
Dan Williams3c304952006-04-15 12:26:18 -04003058 memcpy(tmp_net, &bss, sizeof(tmp_net->bss));
Dan Williams9e75af32006-03-16 13:46:29 -05003059 list_add_tail(&tmp_net->list, &ai->network_list);
3060 tmp_net = NULL;
3061 }
3062
3063 /* Read next entry */
Dan Williams3c304952006-04-15 12:26:18 -04003064 rc = PC4500_readrid(ai, ai->bssListNext,
3065 &bss, ai->bssListRidLen, 0);
Dan Williams9e75af32006-03-16 13:46:29 -05003066 }
3067
3068out:
3069 ai->scan_timeout = 0;
Dan Williams3c304952006-04-15 12:26:18 -04003070 clear_bit(JOB_SCAN_RESULTS, &ai->jobs);
Dan Williams9e75af32006-03-16 13:46:29 -05003071 up(&ai->sem);
3072
3073 /* Send an empty event to user space.
3074 * We don't send the received data on
3075 * the event because it would require
3076 * us to do complex transcoding, and
3077 * we want to minimise the work done in
3078 * the irq handler. Use a request to
3079 * extract the data - Jean II */
3080 wrqu.data.length = 0;
3081 wrqu.data.flags = 0;
3082 wireless_send_event(ai->dev, SIOCGIWSCAN, &wrqu, NULL);
3083}
3084
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085static int airo_thread(void *data) {
3086 struct net_device *dev = data;
3087 struct airo_info *ai = dev->priv;
3088 int locked;
Rafael J. Wysocki83144182007-07-17 04:03:35 -07003089
3090 set_freezable();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 while(1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 /* make swsusp happy with our thread */
Christoph Lameter3e1d1d22005-06-24 23:13:50 -07003093 try_to_freeze();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094
Dan Williams3c304952006-04-15 12:26:18 -04003095 if (test_bit(JOB_DIE, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 break;
3097
Dan Williams3c304952006-04-15 12:26:18 -04003098 if (ai->jobs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 locked = down_interruptible(&ai->sem);
3100 } else {
3101 wait_queue_t wait;
3102
3103 init_waitqueue_entry(&wait, current);
3104 add_wait_queue(&ai->thr_wait, &wait);
3105 for (;;) {
3106 set_current_state(TASK_INTERRUPTIBLE);
Dan Williams3c304952006-04-15 12:26:18 -04003107 if (ai->jobs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 break;
Dan Williams9e75af32006-03-16 13:46:29 -05003109 if (ai->expires || ai->scan_timeout) {
3110 if (ai->scan_timeout &&
3111 time_after_eq(jiffies,ai->scan_timeout)){
Dan Williams3c304952006-04-15 12:26:18 -04003112 set_bit(JOB_SCAN_RESULTS, &ai->jobs);
Dan Williams9e75af32006-03-16 13:46:29 -05003113 break;
3114 } else if (ai->expires &&
3115 time_after_eq(jiffies,ai->expires)){
Dan Williams3c304952006-04-15 12:26:18 -04003116 set_bit(JOB_AUTOWEP, &ai->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 break;
3118 }
Dave Kleikamp5bb85f12006-10-10 14:45:46 -07003119 if (!kthread_should_stop() &&
3120 !freezing(current)) {
Dan Williams9e75af32006-03-16 13:46:29 -05003121 unsigned long wake_at;
3122 if (!ai->expires || !ai->scan_timeout) {
3123 wake_at = max(ai->expires,
3124 ai->scan_timeout);
3125 } else {
3126 wake_at = min(ai->expires,
3127 ai->scan_timeout);
3128 }
3129 schedule_timeout(wake_at - jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 continue;
3131 }
Dave Kleikamp5bb85f12006-10-10 14:45:46 -07003132 } else if (!kthread_should_stop() &&
3133 !freezing(current)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 schedule();
3135 continue;
3136 }
3137 break;
3138 }
3139 current->state = TASK_RUNNING;
3140 remove_wait_queue(&ai->thr_wait, &wait);
3141 locked = 1;
3142 }
3143
3144 if (locked)
3145 continue;
3146
Dan Williams3c304952006-04-15 12:26:18 -04003147 if (test_bit(JOB_DIE, &ai->jobs)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 up(&ai->sem);
3149 break;
3150 }
3151
Pavel Machekca078ba2005-09-03 15:56:57 -07003152 if (ai->power.event || test_bit(FLAG_FLASHING, &ai->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 up(&ai->sem);
3154 continue;
3155 }
3156
Dan Williams3c304952006-04-15 12:26:18 -04003157 if (test_bit(JOB_XMIT, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 airo_end_xmit(dev);
Dan Williams3c304952006-04-15 12:26:18 -04003159 else if (test_bit(JOB_XMIT11, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 airo_end_xmit11(dev);
Dan Williams3c304952006-04-15 12:26:18 -04003161 else if (test_bit(JOB_STATS, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 airo_read_stats(ai);
Dan Williams3c304952006-04-15 12:26:18 -04003163 else if (test_bit(JOB_WSTATS, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 airo_read_wireless_stats(ai);
Dan Williams3c304952006-04-15 12:26:18 -04003165 else if (test_bit(JOB_PROMISC, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 airo_set_promisc(ai);
Dan Williams3c304952006-04-15 12:26:18 -04003167 else if (test_bit(JOB_MIC, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 micinit(ai);
Dan Williams3c304952006-04-15 12:26:18 -04003169 else if (test_bit(JOB_EVENT, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 airo_send_event(dev);
Dan Williams3c304952006-04-15 12:26:18 -04003171 else if (test_bit(JOB_AUTOWEP, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 timer_func(dev);
Dan Williams3c304952006-04-15 12:26:18 -04003173 else if (test_bit(JOB_SCAN_RESULTS, &ai->jobs))
Dan Williams9e75af32006-03-16 13:46:29 -05003174 airo_process_scan_results(ai);
3175 else /* Shouldn't get here, but we make sure to unlock */
3176 up(&ai->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 }
Sukadev Bhattiprolu3b4c7d642006-08-14 23:12:03 -07003178
3179 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180}
3181
Al Viro0300b332007-12-19 22:38:33 -05003182static int header_len(__le16 ctl)
3183{
3184 u16 fc = le16_to_cpu(ctl);
3185 switch (fc & 0xc) {
3186 case 4:
3187 if ((fc & 0xe0) == 0xc0)
3188 return 10; /* one-address control packet */
3189 return 16; /* two-address control packet */
3190 case 8:
3191 if ((fc & 0x300) == 0x300)
3192 return 30; /* WDS packet */
3193 }
3194 return 24;
3195}
3196
Jeff Garzik28fc1f52007-10-29 05:46:16 -04003197static irqreturn_t airo_interrupt(int irq, void *dev_id)
3198{
3199 struct net_device *dev = dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 u16 status;
3201 u16 fid;
3202 struct airo_info *apriv = dev->priv;
3203 u16 savedInterrupts = 0;
3204 int handled = 0;
3205
3206 if (!netif_device_present(dev))
3207 return IRQ_NONE;
3208
3209 for (;;) {
3210 status = IN4500( apriv, EVSTAT );
3211 if ( !(status & STATUS_INTS) || status == 0xffff ) break;
3212
3213 handled = 1;
3214
3215 if ( status & EV_AWAKE ) {
3216 OUT4500( apriv, EVACK, EV_AWAKE );
3217 OUT4500( apriv, EVACK, EV_AWAKE );
3218 }
3219
3220 if (!savedInterrupts) {
3221 savedInterrupts = IN4500( apriv, EVINTEN );
3222 OUT4500( apriv, EVINTEN, 0 );
3223 }
3224
3225 if ( status & EV_MIC ) {
3226 OUT4500( apriv, EVACK, EV_MIC );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) {
Dan Williams3c304952006-04-15 12:26:18 -04003228 set_bit(JOB_MIC, &apriv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 wake_up_interruptible(&apriv->thr_wait);
3230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231 }
3232 if ( status & EV_LINK ) {
3233 union iwreq_data wrqu;
Dan Williams6fcdf562006-03-31 15:08:46 -05003234 int scan_forceloss = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 /* The link status has changed, if you want to put a
3236 monitor hook in, do it here. (Remember that
3237 interrupts are still disabled!)
3238 */
3239 u16 newStatus = IN4500(apriv, LINKSTAT);
3240 OUT4500( apriv, EVACK, EV_LINK);
3241 /* Here is what newStatus means: */
3242#define NOBEACON 0x8000 /* Loss of sync - missed beacons */
3243#define MAXRETRIES 0x8001 /* Loss of sync - max retries */
3244#define MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/
3245#define FORCELOSS 0x8003 /* Loss of sync - host request */
3246#define TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */
3247#define DEAUTH 0x8100 /* Deauthentication (low byte is reason code) */
3248#define DISASS 0x8200 /* Disassociation (low byte is reason code) */
3249#define ASSFAIL 0x8400 /* Association failure (low byte is reason
3250 code) */
3251#define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason
3252 code) */
Dan Williams6fcdf562006-03-31 15:08:46 -05003253#define ASSOCIATED 0x0400 /* Associated */
3254#define REASSOCIATED 0x0600 /* Reassociated? Only on firmware >= 5.30.17 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255#define RC_RESERVED 0 /* Reserved return code */
3256#define RC_NOREASON 1 /* Unspecified reason */
3257#define RC_AUTHINV 2 /* Previous authentication invalid */
3258#define RC_DEAUTH 3 /* Deauthenticated because sending station is
3259 leaving */
3260#define RC_NOACT 4 /* Disassociated due to inactivity */
3261#define RC_MAXLOAD 5 /* Disassociated because AP is unable to handle
3262 all currently associated stations */
3263#define RC_BADCLASS2 6 /* Class 2 frame received from
3264 non-Authenticated station */
3265#define RC_BADCLASS3 7 /* Class 3 frame received from
3266 non-Associated station */
3267#define RC_STATLEAVE 8 /* Disassociated because sending station is
3268 leaving BSS */
3269#define RC_NOAUTH 9 /* Station requesting (Re)Association is not
3270 Authenticated with the responding station */
Dan Williams6fcdf562006-03-31 15:08:46 -05003271 if (newStatus == FORCELOSS && apriv->scan_timeout > 0)
3272 scan_forceloss = 1;
3273 if(newStatus == ASSOCIATED || newStatus == REASSOCIATED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 if (auto_wep)
3275 apriv->expires = 0;
Sukadev Bhattiprolu3b4c7d642006-08-14 23:12:03 -07003276 if (apriv->list_bss_task)
3277 wake_up_process(apriv->list_bss_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 set_bit(FLAG_UPDATE_UNI, &apriv->flags);
3279 set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
Dan Williams6fcdf562006-03-31 15:08:46 -05003280
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 if (down_trylock(&apriv->sem) != 0) {
Dan Williams3c304952006-04-15 12:26:18 -04003282 set_bit(JOB_EVENT, &apriv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 wake_up_interruptible(&apriv->thr_wait);
3284 } else
3285 airo_send_event(dev);
Dan Williams6fcdf562006-03-31 15:08:46 -05003286 } else if (!scan_forceloss) {
3287 if (auto_wep && !apriv->expires) {
3288 apriv->expires = RUN_AT(3*HZ);
3289 wake_up_interruptible(&apriv->thr_wait);
3290 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291
3292 /* Send event to user space */
Dan Williams6fcdf562006-03-31 15:08:46 -05003293 memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN);
3294 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL);
3296 }
3297 }
3298
3299 /* Check to see if there is something to receive */
3300 if ( status & EV_RX ) {
3301 struct sk_buff *skb = NULL;
3302 u16 fc, len, hdrlen = 0;
3303#pragma pack(1)
3304 struct {
Al Viro593c2b92007-12-17 15:09:34 -05003305 __le16 status, len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 u8 rssi[2];
3307 u8 rate;
3308 u8 freq;
Al Viro593c2b92007-12-17 15:09:34 -05003309 __le16 tmp[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 } hdr;
3311#pragma pack()
3312 u16 gap;
3313 u16 tmpbuf[4];
3314 u16 *buffer;
3315
3316 if (test_bit(FLAG_MPI,&apriv->flags)) {
3317 if (test_bit(FLAG_802_11, &apriv->flags))
3318 mpi_receive_802_11(apriv);
3319 else
3320 mpi_receive_802_3(apriv);
3321 OUT4500(apriv, EVACK, EV_RX);
3322 goto exitrx;
3323 }
3324
3325 fid = IN4500( apriv, RXFID );
3326
3327 /* Get the packet length */
3328 if (test_bit(FLAG_802_11, &apriv->flags)) {
3329 bap_setup (apriv, fid, 4, BAP0);
3330 bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0);
3331 /* Bad CRC. Ignore packet */
3332 if (le16_to_cpu(hdr.status) & 2)
3333 hdr.len = 0;
3334 if (apriv->wifidev == NULL)
3335 hdr.len = 0;
3336 } else {
3337 bap_setup (apriv, fid, 0x36, BAP0);
3338 bap_read (apriv, (u16*)&hdr.len, 2, BAP0);
3339 }
3340 len = le16_to_cpu(hdr.len);
3341
Dan Williams15db2762006-03-16 13:46:27 -05003342 if (len > AIRO_DEF_MTU) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003343 airo_print_err(apriv->dev->name, "Bad size %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 goto badrx;
3345 }
3346 if (len == 0)
3347 goto badrx;
3348
3349 if (test_bit(FLAG_802_11, &apriv->flags)) {
Al Viro0300b332007-12-19 22:38:33 -05003350 bap_read (apriv, &fc, sizeof(fc), BAP0);
3351 hdrlen = header_len(fc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 } else
3353 hdrlen = ETH_ALEN * 2;
3354
3355 skb = dev_alloc_skb( len + hdrlen + 2 + 2 );
3356 if ( !skb ) {
3357 apriv->stats.rx_dropped++;
3358 goto badrx;
3359 }
3360 skb_reserve(skb, 2); /* This way the IP header is aligned */
3361 buffer = (u16*)skb_put (skb, len + hdrlen);
3362 if (test_bit(FLAG_802_11, &apriv->flags)) {
3363 buffer[0] = fc;
3364 bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
3365 if (hdrlen == 24)
3366 bap_read (apriv, tmpbuf, 6, BAP0);
3367
3368 bap_read (apriv, &gap, sizeof(gap), BAP0);
3369 gap = le16_to_cpu(gap);
3370 if (gap) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003371 if (gap <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 bap_read (apriv, tmpbuf, gap, BAP0);
Dan Williams934d8bf2006-03-16 13:46:23 -05003373 } else {
3374 airo_print_err(apriv->dev->name, "gaplen too "
3375 "big. Problems will follow...");
3376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 }
3378 bap_read (apriv, buffer + hdrlen/2, len, BAP0);
3379 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 MICBuffer micbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 if (apriv->micstats.enabled) {
3383 bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0);
3384 if (ntohs(micbuf.typelen) > 0x05DC)
3385 bap_setup (apriv, fid, 0x44, BAP0);
3386 else {
3387 if (len <= sizeof(micbuf))
3388 goto badmic;
3389
3390 len -= sizeof(micbuf);
3391 skb_trim (skb, len + hdrlen);
3392 }
3393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 bap_read(apriv,buffer+ETH_ALEN,len,BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
3396badmic:
3397 dev_kfree_skb_irq (skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398badrx:
3399 OUT4500( apriv, EVACK, EV_RX);
3400 goto exitrx;
3401 }
3402 }
3403#ifdef WIRELESS_SPY
3404 if (apriv->spy_data.spy_number > 0) {
3405 char *sa;
3406 struct iw_quality wstats;
3407 /* Prepare spy data : addr + qual */
3408 if (!test_bit(FLAG_802_11, &apriv->flags)) {
3409 sa = (char*)buffer + 6;
3410 bap_setup (apriv, fid, 8, BAP0);
3411 bap_read (apriv, (u16*)hdr.rssi, 2, BAP0);
3412 } else
3413 sa = (char*)buffer + 10;
3414 wstats.qual = hdr.rssi[0];
3415 if (apriv->rssi)
3416 wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
3417 else
3418 wstats.level = (hdr.rssi[1] + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04003419 wstats.noise = apriv->wstats.qual.noise;
3420 wstats.updated = IW_QUAL_LEVEL_UPDATED
3421 | IW_QUAL_QUAL_UPDATED
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07003422 | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 /* Update spy records */
3424 wireless_spy_update(dev, sa, &wstats);
3425 }
3426#endif /* WIRELESS_SPY */
3427 OUT4500( apriv, EVACK, EV_RX);
3428
3429 if (test_bit(FLAG_802_11, &apriv->flags)) {
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07003430 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 skb->pkt_type = PACKET_OTHERHOST;
3432 skb->dev = apriv->wifidev;
3433 skb->protocol = htons(ETH_P_802_2);
Arnaldo Carvalho de Melo4c13eb62007-04-25 17:40:23 -07003434 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 skb->protocol = eth_type_trans(skb,dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 skb->dev->last_rx = jiffies;
3437 skb->ip_summed = CHECKSUM_NONE;
3438
3439 netif_rx( skb );
3440 }
3441exitrx:
3442
3443 /* Check to see if a packet has been transmitted */
3444 if ( status & ( EV_TX|EV_TXCPY|EV_TXEXC ) ) {
3445 int i;
3446 int len = 0;
3447 int index = -1;
3448
3449 if (test_bit(FLAG_MPI,&apriv->flags)) {
3450 unsigned long flags;
3451
3452 if (status & EV_TXEXC)
3453 get_tx_error(apriv, -1);
3454 spin_lock_irqsave(&apriv->aux_lock, flags);
David S. Millerb03efcf2005-07-08 14:57:23 -07003455 if (!skb_queue_empty(&apriv->txq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 spin_unlock_irqrestore(&apriv->aux_lock,flags);
3457 mpi_send_packet (dev);
3458 } else {
3459 clear_bit(FLAG_PENDING_XMIT, &apriv->flags);
3460 spin_unlock_irqrestore(&apriv->aux_lock,flags);
3461 netif_wake_queue (dev);
3462 }
3463 OUT4500( apriv, EVACK,
3464 status & (EV_TX|EV_TXCPY|EV_TXEXC));
3465 goto exittx;
3466 }
3467
3468 fid = IN4500(apriv, TXCOMPLFID);
3469
3470 for( i = 0; i < MAX_FIDS; i++ ) {
3471 if ( ( apriv->fids[i] & 0xffff ) == fid ) {
3472 len = apriv->fids[i] >> 16;
3473 index = i;
3474 }
3475 }
3476 if (index != -1) {
3477 if (status & EV_TXEXC)
3478 get_tx_error(apriv, index);
3479 OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC));
3480 /* Set up to be used again */
3481 apriv->fids[index] &= 0xffff;
3482 if (index < MAX_FIDS / 2) {
3483 if (!test_bit(FLAG_PENDING_XMIT, &apriv->flags))
3484 netif_wake_queue(dev);
3485 } else {
3486 if (!test_bit(FLAG_PENDING_XMIT11, &apriv->flags))
3487 netif_wake_queue(apriv->wifidev);
3488 }
3489 } else {
3490 OUT4500( apriv, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC));
Dan Williams934d8bf2006-03-16 13:46:23 -05003491 airo_print_err(apriv->dev->name, "Unallocated FID was "
3492 "used to xmit" );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 }
3494 }
3495exittx:
3496 if ( status & ~STATUS_INTS & ~IGNORE_INTS )
Dan Williams934d8bf2006-03-16 13:46:23 -05003497 airo_print_warn(apriv->dev->name, "Got weird status %x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 status & ~STATUS_INTS & ~IGNORE_INTS );
3499 }
3500
3501 if (savedInterrupts)
3502 OUT4500( apriv, EVINTEN, savedInterrupts );
3503
3504 /* done.. */
3505 return IRQ_RETVAL(handled);
3506}
3507
3508/*
3509 * Routines to talk to the card
3510 */
3511
3512/*
3513 * This was originally written for the 4500, hence the name
3514 * NOTE: If use with 8bit mode and SMP bad things will happen!
3515 * Why would some one do 8 bit IO in an SMP machine?!?
3516 */
3517static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) {
3518 if (test_bit(FLAG_MPI,&ai->flags))
3519 reg <<= 1;
3520 if ( !do8bitIO )
3521 outw( val, ai->dev->base_addr + reg );
3522 else {
3523 outb( val & 0xff, ai->dev->base_addr + reg );
3524 outb( val >> 8, ai->dev->base_addr + reg + 1 );
3525 }
3526}
3527
3528static u16 IN4500( struct airo_info *ai, u16 reg ) {
3529 unsigned short rc;
3530
3531 if (test_bit(FLAG_MPI,&ai->flags))
3532 reg <<= 1;
3533 if ( !do8bitIO )
3534 rc = inw( ai->dev->base_addr + reg );
3535 else {
3536 rc = inb( ai->dev->base_addr + reg );
3537 rc += ((int)inb( ai->dev->base_addr + reg + 1 )) << 8;
3538 }
3539 return rc;
3540}
3541
Michal Schmidt175ec1a2007-06-29 15:33:47 +02003542static int enable_MAC(struct airo_info *ai, int lock)
3543{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 int rc;
Michal Schmidt175ec1a2007-06-29 15:33:47 +02003545 Cmd cmd;
3546 Resp rsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547
3548 /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions
3549 * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down"
3550 * Note : we could try to use !netif_running(dev) in enable_MAC()
3551 * instead of this flag, but I don't trust it *within* the
3552 * open/close functions, and testing both flags together is
3553 * "cheaper" - Jean II */
3554 if (ai->flags & FLAG_RADIO_MASK) return SUCCESS;
3555
3556 if (lock && down_interruptible(&ai->sem))
3557 return -ERESTARTSYS;
3558
3559 if (!test_bit(FLAG_ENABLED, &ai->flags)) {
3560 memset(&cmd, 0, sizeof(cmd));
3561 cmd.cmd = MAC_ENABLE;
Michal Schmidt175ec1a2007-06-29 15:33:47 +02003562 rc = issuecommand(ai, &cmd, &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 if (rc == SUCCESS)
3564 set_bit(FLAG_ENABLED, &ai->flags);
3565 } else
3566 rc = SUCCESS;
3567
3568 if (lock)
3569 up(&ai->sem);
3570
3571 if (rc)
Michal Schmidt175ec1a2007-06-29 15:33:47 +02003572 airo_print_err(ai->dev->name, "Cannot enable MAC");
3573 else if ((rsp.status & 0xFF00) != 0) {
3574 airo_print_err(ai->dev->name, "Bad MAC enable reason=%x, "
3575 "rid=%x, offset=%d", rsp.rsp0, rsp.rsp1, rsp.rsp2);
3576 rc = ERROR;
3577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 return rc;
3579}
3580
3581static void disable_MAC( struct airo_info *ai, int lock ) {
3582 Cmd cmd;
3583 Resp rsp;
3584
3585 if (lock && down_interruptible(&ai->sem))
3586 return;
3587
3588 if (test_bit(FLAG_ENABLED, &ai->flags)) {
3589 memset(&cmd, 0, sizeof(cmd));
3590 cmd.cmd = MAC_DISABLE; // disable in case already enabled
3591 issuecommand(ai, &cmd, &rsp);
3592 clear_bit(FLAG_ENABLED, &ai->flags);
3593 }
3594 if (lock)
3595 up(&ai->sem);
3596}
3597
3598static void enable_interrupts( struct airo_info *ai ) {
3599 /* Enable the interrupts */
3600 OUT4500( ai, EVINTEN, STATUS_INTS );
3601}
3602
3603static void disable_interrupts( struct airo_info *ai ) {
3604 OUT4500( ai, EVINTEN, 0 );
3605}
3606
3607static void mpi_receive_802_3(struct airo_info *ai)
3608{
3609 RxFid rxd;
3610 int len = 0;
3611 struct sk_buff *skb;
3612 char *buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 int off = 0;
3614 MICBuffer micbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615
3616 memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
3617 /* Make sure we got something */
3618 if (rxd.rdy && rxd.valid == 0) {
3619 len = rxd.len + 12;
3620 if (len < 12 || len > 2048)
3621 goto badrx;
3622
3623 skb = dev_alloc_skb(len);
3624 if (!skb) {
3625 ai->stats.rx_dropped++;
3626 goto badrx;
3627 }
3628 buffer = skb_put(skb,len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2);
3630 if (ai->micstats.enabled) {
3631 memcpy(&micbuf,
3632 ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2,
3633 sizeof(micbuf));
3634 if (ntohs(micbuf.typelen) <= 0x05DC) {
3635 if (len <= sizeof(micbuf) + ETH_ALEN * 2)
3636 goto badmic;
3637
3638 off = sizeof(micbuf);
3639 skb_trim (skb, len - off);
3640 }
3641 }
3642 memcpy(buffer + ETH_ALEN * 2,
3643 ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off,
3644 len - ETH_ALEN * 2 - off);
3645 if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) {
3646badmic:
3647 dev_kfree_skb_irq (skb);
3648 goto badrx;
3649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650#ifdef WIRELESS_SPY
3651 if (ai->spy_data.spy_number > 0) {
3652 char *sa;
3653 struct iw_quality wstats;
3654 /* Prepare spy data : addr + qual */
3655 sa = buffer + ETH_ALEN;
3656 wstats.qual = 0; /* XXX Where do I get that info from ??? */
3657 wstats.level = 0;
3658 wstats.updated = 0;
3659 /* Update spy records */
3660 wireless_spy_update(ai->dev, sa, &wstats);
3661 }
3662#endif /* WIRELESS_SPY */
3663
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 skb->ip_summed = CHECKSUM_NONE;
3665 skb->protocol = eth_type_trans(skb, ai->dev);
3666 skb->dev->last_rx = jiffies;
3667 netif_rx(skb);
3668 }
3669badrx:
3670 if (rxd.valid == 0) {
3671 rxd.valid = 1;
3672 rxd.rdy = 0;
3673 rxd.len = PKTSIZE;
3674 memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd));
3675 }
3676}
3677
3678void mpi_receive_802_11 (struct airo_info *ai)
3679{
3680 RxFid rxd;
3681 struct sk_buff *skb = NULL;
Al Viro0300b332007-12-19 22:38:33 -05003682 u16 len, hdrlen = 0;
3683 __le16 fc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684#pragma pack(1)
3685 struct {
Al Viro593c2b92007-12-17 15:09:34 -05003686 __le16 status, len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 u8 rssi[2];
3688 u8 rate;
3689 u8 freq;
Al Viro593c2b92007-12-17 15:09:34 -05003690 __le16 tmp[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 } hdr;
3692#pragma pack()
3693 u16 gap;
3694 u16 *buffer;
3695 char *ptr = ai->rxfids[0].virtual_host_addr+4;
3696
3697 memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
3698 memcpy ((char *)&hdr, ptr, sizeof(hdr));
3699 ptr += sizeof(hdr);
3700 /* Bad CRC. Ignore packet */
3701 if (le16_to_cpu(hdr.status) & 2)
3702 hdr.len = 0;
3703 if (ai->wifidev == NULL)
3704 hdr.len = 0;
3705 len = le16_to_cpu(hdr.len);
Dan Williams15db2762006-03-16 13:46:27 -05003706 if (len > AIRO_DEF_MTU) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003707 airo_print_err(ai->dev->name, "Bad size %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 goto badrx;
3709 }
3710 if (len == 0)
3711 goto badrx;
3712
Al Viro0300b332007-12-19 22:38:33 -05003713 fc = get_unaligned((__le16 *)ptr);
3714 hdrlen = header_len(fc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715
3716 skb = dev_alloc_skb( len + hdrlen + 2 );
3717 if ( !skb ) {
3718 ai->stats.rx_dropped++;
3719 goto badrx;
3720 }
3721 buffer = (u16*)skb_put (skb, len + hdrlen);
3722 memcpy ((char *)buffer, ptr, hdrlen);
3723 ptr += hdrlen;
3724 if (hdrlen == 24)
3725 ptr += 6;
Al Viro593c2b92007-12-17 15:09:34 -05003726 gap = le16_to_cpu(get_unaligned((__le16 *)ptr));
3727 ptr += sizeof(__le16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 if (gap) {
3729 if (gap <= 8)
3730 ptr += gap;
3731 else
Dan Williams934d8bf2006-03-16 13:46:23 -05003732 airo_print_err(ai->dev->name,
3733 "gaplen too big. Problems will follow...");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 }
3735 memcpy ((char *)buffer + hdrlen, ptr, len);
3736 ptr += len;
3737#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
3738 if (ai->spy_data.spy_number > 0) {
3739 char *sa;
3740 struct iw_quality wstats;
3741 /* Prepare spy data : addr + qual */
3742 sa = (char*)buffer + 10;
3743 wstats.qual = hdr.rssi[0];
3744 if (ai->rssi)
3745 wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm;
3746 else
3747 wstats.level = (hdr.rssi[1] + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04003748 wstats.noise = ai->wstats.qual.noise;
3749 wstats.updated = IW_QUAL_QUAL_UPDATED
3750 | IW_QUAL_LEVEL_UPDATED
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07003751 | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 /* Update spy records */
3753 wireless_spy_update(ai->dev, sa, &wstats);
3754 }
3755#endif /* IW_WIRELESS_SPY */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07003756 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 skb->pkt_type = PACKET_OTHERHOST;
3758 skb->dev = ai->wifidev;
3759 skb->protocol = htons(ETH_P_802_2);
3760 skb->dev->last_rx = jiffies;
3761 skb->ip_summed = CHECKSUM_NONE;
3762 netif_rx( skb );
3763badrx:
3764 if (rxd.valid == 0) {
3765 rxd.valid = 1;
3766 rxd.rdy = 0;
3767 rxd.len = PKTSIZE;
3768 memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd));
3769 }
3770}
3771
3772static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
3773{
3774 Cmd cmd;
3775 Resp rsp;
3776 int status;
3777 int i;
3778 SsidRid mySsid;
3779 u16 lastindex;
3780 WepKeyRid wkr;
3781 int rc;
3782
3783 memset( &mySsid, 0, sizeof( mySsid ) );
Jesper Juhlb4558ea2005-10-28 16:53:13 -04003784 kfree (ai->flash);
3785 ai->flash = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786
3787 /* The NOP is the first step in getting the card going */
3788 cmd.cmd = NOP;
3789 cmd.parm0 = cmd.parm1 = cmd.parm2 = 0;
3790 if (lock && down_interruptible(&ai->sem))
3791 return ERROR;
3792 if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
3793 if (lock)
3794 up(&ai->sem);
3795 return ERROR;
3796 }
3797 disable_MAC( ai, 0);
3798
3799 // Let's figure out if we need to use the AUX port
3800 if (!test_bit(FLAG_MPI,&ai->flags)) {
3801 cmd.cmd = CMD_ENABLEAUX;
3802 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
3803 if (lock)
3804 up(&ai->sem);
Dan Williams934d8bf2006-03-16 13:46:23 -05003805 airo_print_err(ai->dev->name, "Error checking for AUX port");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 return ERROR;
3807 }
3808 if (!aux_bap || rsp.status & 0xff00) {
3809 ai->bap_read = fast_bap_read;
Dan Williams934d8bf2006-03-16 13:46:23 -05003810 airo_print_dbg(ai->dev->name, "Doing fast bap_reads");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 } else {
3812 ai->bap_read = aux_bap_read;
Dan Williams934d8bf2006-03-16 13:46:23 -05003813 airo_print_dbg(ai->dev->name, "Doing AUX bap_reads");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 }
3815 }
3816 if (lock)
3817 up(&ai->sem);
3818 if (ai->config.len == 0) {
3819 tdsRssiRid rssi_rid;
3820 CapabilityRid cap_rid;
3821
Jesper Juhlb4558ea2005-10-28 16:53:13 -04003822 kfree(ai->APList);
3823 ai->APList = NULL;
3824 kfree(ai->SSID);
3825 ai->SSID = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 // general configuration (read/modify/write)
3827 status = readConfigRid(ai, lock);
3828 if ( status != SUCCESS ) return ERROR;
3829
3830 status = readCapabilityRid(ai, &cap_rid, lock);
3831 if ( status != SUCCESS ) return ERROR;
3832
3833 status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),lock);
3834 if ( status == SUCCESS ) {
3835 if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
Dan Williams41480af2005-05-10 09:45:51 -04003836 memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 }
3838 else {
Jesper Juhlb4558ea2005-10-28 16:53:13 -04003839 kfree(ai->rssi);
3840 ai->rssi = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 if (cap_rid.softCap & 8)
3842 ai->config.rmode |= RXMODE_NORMALIZED_RSSI;
3843 else
Dan Williams934d8bf2006-03-16 13:46:23 -05003844 airo_print_warn(ai->dev->name, "unknown received signal "
3845 "level scale");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 }
3847 ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
3848 ai->config.authType = AUTH_OPEN;
3849 ai->config.modulation = MOD_CCK;
3850
Al Viro15617852007-12-20 17:21:36 -05003851 if ((cap_rid.len>=sizeof(cap_rid)) &&
3852 (cap_rid.extSoftCap & cpu_to_le16(1)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853 (micsetup(ai) == SUCCESS)) {
3854 ai->config.opmode |= MODE_MIC;
3855 set_bit(FLAG_MIC_CAPABLE, &ai->flags);
3856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857
3858 /* Save off the MAC */
3859 for( i = 0; i < ETH_ALEN; i++ ) {
3860 mac[i] = ai->config.macAddr[i];
3861 }
3862
3863 /* Check to see if there are any insmod configured
3864 rates to add */
3865 if ( rates[0] ) {
3866 int i = 0;
3867 memset(ai->config.rates,0,sizeof(ai->config.rates));
3868 for( i = 0; i < 8 && rates[i]; i++ ) {
3869 ai->config.rates[i] = rates[i];
3870 }
3871 }
3872 if ( basic_rate > 0 ) {
3873 int i;
3874 for( i = 0; i < 8; i++ ) {
3875 if ( ai->config.rates[i] == basic_rate ||
3876 !ai->config.rates ) {
3877 ai->config.rates[i] = basic_rate | 0x80;
3878 break;
3879 }
3880 }
3881 }
3882 set_bit (FLAG_COMMIT, &ai->flags);
3883 }
3884
3885 /* Setup the SSIDs if present */
3886 if ( ssids[0] ) {
3887 int i;
3888 for( i = 0; i < 3 && ssids[i]; i++ ) {
3889 mySsid.ssids[i].len = strlen(ssids[i]);
3890 if ( mySsid.ssids[i].len > 32 )
3891 mySsid.ssids[i].len = 32;
3892 memcpy(mySsid.ssids[i].ssid, ssids[i],
3893 mySsid.ssids[i].len);
3894 }
3895 mySsid.len = sizeof(mySsid);
3896 }
3897
3898 status = writeConfigRid(ai, lock);
3899 if ( status != SUCCESS ) return ERROR;
3900
3901 /* Set up the SSID list */
3902 if ( ssids[0] ) {
3903 status = writeSsidRid(ai, &mySsid, lock);
3904 if ( status != SUCCESS ) return ERROR;
3905 }
3906
Michal Schmidt175ec1a2007-06-29 15:33:47 +02003907 status = enable_MAC(ai, lock);
3908 if (status != SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 return ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910
3911 /* Grab the initial wep key, we gotta save it for auto_wep */
3912 rc = readWepKeyRid(ai, &wkr, 1, lock);
3913 if (rc == SUCCESS) do {
3914 lastindex = wkr.kindex;
3915 if (wkr.kindex == 0xffff) {
3916 ai->defindex = wkr.mac[0];
3917 }
3918 rc = readWepKeyRid(ai, &wkr, 0, lock);
3919 } while(lastindex != wkr.kindex);
3920
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02003921 try_auto_wep(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922
3923 return SUCCESS;
3924}
3925
3926static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
3927 // Im really paranoid about letting it run forever!
3928 int max_tries = 600000;
3929
3930 if (IN4500(ai, EVSTAT) & EV_CMD)
3931 OUT4500(ai, EVACK, EV_CMD);
3932
3933 OUT4500(ai, PARAM0, pCmd->parm0);
3934 OUT4500(ai, PARAM1, pCmd->parm1);
3935 OUT4500(ai, PARAM2, pCmd->parm2);
3936 OUT4500(ai, COMMAND, pCmd->cmd);
3937
3938 while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) {
3939 if ((IN4500(ai, COMMAND)) == pCmd->cmd)
3940 // PC4500 didn't notice command, try again
3941 OUT4500(ai, COMMAND, pCmd->cmd);
3942 if (!in_atomic() && (max_tries & 255) == 0)
3943 schedule();
3944 }
3945
3946 if ( max_tries == -1 ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003947 airo_print_err(ai->dev->name,
3948 "Max tries exceeded when issueing command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 if (IN4500(ai, COMMAND) & COMMAND_BUSY)
3950 OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
3951 return ERROR;
3952 }
3953
3954 // command completed
3955 pRsp->status = IN4500(ai, STATUS);
3956 pRsp->rsp0 = IN4500(ai, RESP0);
3957 pRsp->rsp1 = IN4500(ai, RESP1);
3958 pRsp->rsp2 = IN4500(ai, RESP2);
Robert Schulze13dca9b2006-07-10 18:37:44 +02003959 if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET)
3960 airo_print_err(ai->dev->name,
3961 "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x",
3962 pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1,
3963 pRsp->rsp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964
3965 // clear stuck command busy if necessary
3966 if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
3967 OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
3968 }
3969 // acknowledge processing the status/response
3970 OUT4500(ai, EVACK, EV_CMD);
3971
3972 return SUCCESS;
3973}
3974
3975/* Sets up the bap to start exchange data. whichbap should
3976 * be one of the BAP0 or BAP1 defines. Locks should be held before
3977 * calling! */
3978static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap )
3979{
3980 int timeout = 50;
3981 int max_tries = 3;
3982
3983 OUT4500(ai, SELECT0+whichbap, rid);
3984 OUT4500(ai, OFFSET0+whichbap, offset);
3985 while (1) {
3986 int status = IN4500(ai, OFFSET0+whichbap);
3987 if (status & BAP_BUSY) {
3988 /* This isn't really a timeout, but its kinda
3989 close */
3990 if (timeout--) {
3991 continue;
3992 }
3993 } else if ( status & BAP_ERR ) {
3994 /* invalid rid or offset */
Dan Williams934d8bf2006-03-16 13:46:23 -05003995 airo_print_err(ai->dev->name, "BAP error %x %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 status, whichbap );
3997 return ERROR;
3998 } else if (status & BAP_DONE) { // success
3999 return SUCCESS;
4000 }
4001 if ( !(max_tries--) ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004002 airo_print_err(ai->dev->name,
Michal Schmidt1138c372007-06-29 15:33:41 +02004003 "BAP setup error too many retries\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 return ERROR;
4005 }
4006 // -- PC4500 missed it, try again
4007 OUT4500(ai, SELECT0+whichbap, rid);
4008 OUT4500(ai, OFFSET0+whichbap, offset);
4009 timeout = 50;
4010 }
4011}
4012
4013/* should only be called by aux_bap_read. This aux function and the
4014 following use concepts not documented in the developers guide. I
4015 got them from a patch given to my by Aironet */
4016static u16 aux_setup(struct airo_info *ai, u16 page,
4017 u16 offset, u16 *len)
4018{
4019 u16 next;
4020
4021 OUT4500(ai, AUXPAGE, page);
4022 OUT4500(ai, AUXOFF, 0);
4023 next = IN4500(ai, AUXDATA);
4024 *len = IN4500(ai, AUXDATA)&0xff;
4025 if (offset != 4) OUT4500(ai, AUXOFF, offset);
4026 return next;
4027}
4028
4029/* requires call to bap_setup() first */
4030static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst,
4031 int bytelen, int whichbap)
4032{
4033 u16 len;
4034 u16 page;
4035 u16 offset;
4036 u16 next;
4037 int words;
4038 int i;
4039 unsigned long flags;
4040
4041 spin_lock_irqsave(&ai->aux_lock, flags);
4042 page = IN4500(ai, SWS0+whichbap);
4043 offset = IN4500(ai, SWS2+whichbap);
4044 next = aux_setup(ai, page, offset, &len);
4045 words = (bytelen+1)>>1;
4046
4047 for (i=0; i<words;) {
4048 int count;
4049 count = (len>>1) < (words-i) ? (len>>1) : (words-i);
4050 if ( !do8bitIO )
4051 insw( ai->dev->base_addr+DATA0+whichbap,
4052 pu16Dst+i,count );
4053 else
4054 insb( ai->dev->base_addr+DATA0+whichbap,
4055 pu16Dst+i, count << 1 );
4056 i += count;
4057 if (i<words) {
4058 next = aux_setup(ai, next, 4, &len);
4059 }
4060 }
4061 spin_unlock_irqrestore(&ai->aux_lock, flags);
4062 return SUCCESS;
4063}
4064
4065
4066/* requires call to bap_setup() first */
4067static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst,
4068 int bytelen, int whichbap)
4069{
4070 bytelen = (bytelen + 1) & (~1); // round up to even value
4071 if ( !do8bitIO )
4072 insw( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1 );
4073 else
4074 insb( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen );
4075 return SUCCESS;
4076}
4077
4078/* requires call to bap_setup() first */
4079static int bap_write(struct airo_info *ai, const u16 *pu16Src,
4080 int bytelen, int whichbap)
4081{
4082 bytelen = (bytelen + 1) & (~1); // round up to even value
4083 if ( !do8bitIO )
4084 outsw( ai->dev->base_addr+DATA0+whichbap,
4085 pu16Src, bytelen>>1 );
4086 else
4087 outsb( ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen );
4088 return SUCCESS;
4089}
4090
4091static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd)
4092{
4093 Cmd cmd; /* for issuing commands */
4094 Resp rsp; /* response from commands */
4095 u16 status;
4096
4097 memset(&cmd, 0, sizeof(cmd));
4098 cmd.cmd = accmd;
4099 cmd.parm0 = rid;
4100 status = issuecommand(ai, &cmd, &rsp);
4101 if (status != 0) return status;
4102 if ( (rsp.status & 0x7F00) != 0) {
4103 return (accmd << 8) + (rsp.rsp0 & 0xFF);
4104 }
4105 return 0;
4106}
4107
4108/* Note, that we are using BAP1 which is also used by transmit, so
4109 * we must get a lock. */
4110static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, int lock)
4111{
4112 u16 status;
4113 int rc = SUCCESS;
4114
4115 if (lock) {
4116 if (down_interruptible(&ai->sem))
4117 return ERROR;
4118 }
4119 if (test_bit(FLAG_MPI,&ai->flags)) {
4120 Cmd cmd;
4121 Resp rsp;
4122
4123 memset(&cmd, 0, sizeof(cmd));
4124 memset(&rsp, 0, sizeof(rsp));
4125 ai->config_desc.rid_desc.valid = 1;
4126 ai->config_desc.rid_desc.len = RIDSIZE;
4127 ai->config_desc.rid_desc.rid = 0;
4128 ai->config_desc.rid_desc.host_addr = ai->ridbus;
4129
4130 cmd.cmd = CMD_ACCESS;
4131 cmd.parm0 = rid;
4132
4133 memcpy_toio(ai->config_desc.card_ram_off,
4134 &ai->config_desc.rid_desc, sizeof(Rid));
4135
4136 rc = issuecommand(ai, &cmd, &rsp);
4137
4138 if (rsp.status & 0x7f00)
4139 rc = rsp.rsp0;
4140 if (!rc)
4141 memcpy(pBuf, ai->config_desc.virtual_host_addr, len);
4142 goto done;
4143 } else {
4144 if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS))!=SUCCESS) {
4145 rc = status;
4146 goto done;
4147 }
4148 if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
4149 rc = ERROR;
4150 goto done;
4151 }
4152 // read the rid length field
4153 bap_read(ai, pBuf, 2, BAP1);
4154 // length for remaining part of rid
Al Viro593c2b92007-12-17 15:09:34 -05004155 len = min(len, (int)le16_to_cpu(*(__le16*)pBuf)) - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156
4157 if ( len <= 2 ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004158 airo_print_err(ai->dev->name,
4159 "Rid %x has a length of %d which is too short",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 (int)rid, (int)len );
4161 rc = ERROR;
4162 goto done;
4163 }
4164 // read remainder of the rid
4165 rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
4166 }
4167done:
4168 if (lock)
4169 up(&ai->sem);
4170 return rc;
4171}
4172
4173/* Note, that we are using BAP1 which is also used by transmit, so
4174 * make sure this isnt called when a transmit is happening */
4175static int PC4500_writerid(struct airo_info *ai, u16 rid,
4176 const void *pBuf, int len, int lock)
4177{
4178 u16 status;
4179 int rc = SUCCESS;
4180
Al Viro593c2b92007-12-17 15:09:34 -05004181 *(__le16*)pBuf = cpu_to_le16((u16)len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182
4183 if (lock) {
4184 if (down_interruptible(&ai->sem))
4185 return ERROR;
4186 }
4187 if (test_bit(FLAG_MPI,&ai->flags)) {
4188 Cmd cmd;
4189 Resp rsp;
4190
Dan Streetmanf89b2322005-11-11 11:41:42 -05004191 if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid))
Dan Williams934d8bf2006-03-16 13:46:23 -05004192 airo_print_err(ai->dev->name,
4193 "%s: MAC should be disabled (rid=%04x)",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 __FUNCTION__, rid);
4195 memset(&cmd, 0, sizeof(cmd));
4196 memset(&rsp, 0, sizeof(rsp));
4197
4198 ai->config_desc.rid_desc.valid = 1;
4199 ai->config_desc.rid_desc.len = *((u16 *)pBuf);
4200 ai->config_desc.rid_desc.rid = 0;
4201
4202 cmd.cmd = CMD_WRITERID;
4203 cmd.parm0 = rid;
4204
4205 memcpy_toio(ai->config_desc.card_ram_off,
4206 &ai->config_desc.rid_desc, sizeof(Rid));
4207
4208 if (len < 4 || len > 2047) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004209 airo_print_err(ai->dev->name, "%s: len=%d", __FUNCTION__, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 rc = -1;
4211 } else {
4212 memcpy((char *)ai->config_desc.virtual_host_addr,
4213 pBuf, len);
4214
4215 rc = issuecommand(ai, &cmd, &rsp);
4216 if ((rc & 0xff00) != 0) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004217 airo_print_err(ai->dev->name, "%s: Write rid Error %d",
4218 __FUNCTION__, rc);
4219 airo_print_err(ai->dev->name, "%s: Cmd=%04x",
4220 __FUNCTION__, cmd.cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221 }
4222
4223 if ((rsp.status & 0x7f00))
4224 rc = rsp.rsp0;
4225 }
4226 } else {
4227 // --- first access so that we can write the rid data
4228 if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
4229 rc = status;
4230 goto done;
4231 }
4232 // --- now write the rid data
4233 if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
4234 rc = ERROR;
4235 goto done;
4236 }
4237 bap_write(ai, pBuf, len, BAP1);
4238 // ---now commit the rid data
4239 rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
4240 }
4241done:
4242 if (lock)
4243 up(&ai->sem);
4244 return rc;
4245}
4246
4247/* Allocates a FID to be used for transmitting packets. We only use
4248 one for now. */
4249static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw)
4250{
4251 unsigned int loop = 3000;
4252 Cmd cmd;
4253 Resp rsp;
4254 u16 txFid;
Al Viro593c2b92007-12-17 15:09:34 -05004255 __le16 txControl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256
4257 cmd.cmd = CMD_ALLOCATETX;
4258 cmd.parm0 = lenPayload;
4259 if (down_interruptible(&ai->sem))
4260 return ERROR;
4261 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
4262 txFid = ERROR;
4263 goto done;
4264 }
4265 if ( (rsp.status & 0xFF00) != 0) {
4266 txFid = ERROR;
4267 goto done;
4268 }
4269 /* wait for the allocate event/indication
4270 * It makes me kind of nervous that this can just sit here and spin,
4271 * but in practice it only loops like four times. */
4272 while (((IN4500(ai, EVSTAT) & EV_ALLOC) == 0) && --loop);
4273 if (!loop) {
4274 txFid = ERROR;
4275 goto done;
4276 }
4277
4278 // get the allocated fid and acknowledge
4279 txFid = IN4500(ai, TXALLOCFID);
4280 OUT4500(ai, EVACK, EV_ALLOC);
4281
4282 /* The CARD is pretty cool since it converts the ethernet packet
4283 * into 802.11. Also note that we don't release the FID since we
4284 * will be using the same one over and over again. */
4285 /* We only have to setup the control once since we are not
4286 * releasing the fid. */
4287 if (raw)
4288 txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_11
4289 | TXCTL_ETHERNET | TXCTL_NORELEASE);
4290 else
4291 txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3
4292 | TXCTL_ETHERNET | TXCTL_NORELEASE);
4293 if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS)
4294 txFid = ERROR;
4295 else
4296 bap_write(ai, &txControl, sizeof(txControl), BAP1);
4297
4298done:
4299 up(&ai->sem);
4300
4301 return txFid;
4302}
4303
4304/* In general BAP1 is dedicated to transmiting packets. However,
4305 since we need a BAP when accessing RIDs, we also use BAP1 for that.
4306 Make sure the BAP1 spinlock is held when this is called. */
4307static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
4308{
Al Viro593c2b92007-12-17 15:09:34 -05004309 __le16 payloadLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 Cmd cmd;
4311 Resp rsp;
4312 int miclen = 0;
4313 u16 txFid = len;
4314 MICBuffer pMic;
4315
4316 len >>= 16;
4317
4318 if (len <= ETH_ALEN * 2) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004319 airo_print_warn(ai->dev->name, "Short packet %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 return ERROR;
4321 }
4322 len -= ETH_ALEN * 2;
4323
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
Al Viro593c2b92007-12-17 15:09:34 -05004325 (ntohs(((__be16 *)pPacket)[6]) != 0x888E)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS)
4327 return ERROR;
4328 miclen = sizeof(pMic);
4329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 // packet is destination[6], source[6], payload[len-12]
4331 // write the payload length and dst/src/payload
4332 if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR;
4333 /* The hardware addresses aren't counted as part of the payload, so
4334 * we have to subtract the 12 bytes for the addresses off */
4335 payloadLen = cpu_to_le16(len + miclen);
4336 bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
4337 bap_write(ai, (const u16*)pPacket, sizeof(etherHead), BAP1);
4338 if (miclen)
4339 bap_write(ai, (const u16*)&pMic, miclen, BAP1);
4340 bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len, BAP1);
4341 // issue the transmit command
4342 memset( &cmd, 0, sizeof( cmd ) );
4343 cmd.cmd = CMD_TRANSMIT;
4344 cmd.parm0 = txFid;
4345 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
4346 if ( (rsp.status & 0xFF00) != 0) return ERROR;
4347 return SUCCESS;
4348}
4349
4350static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
4351{
Al Viro593c2b92007-12-17 15:09:34 -05004352 __le16 fc, payloadLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 Cmd cmd;
4354 Resp rsp;
4355 int hdrlen;
Al Viro977b1432007-12-19 16:45:29 -05004356 static u8 tail[(30-10) + 2 + 6] = {[30-10] = 6};
4357 /* padding of header to full size + le16 gaplen (6) + gaplen bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 u16 txFid = len;
4359 len >>= 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360
Al Viro0300b332007-12-19 22:38:33 -05004361 fc = *(__le16*)pPacket;
4362 hdrlen = header_len(fc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363
4364 if (len < hdrlen) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004365 airo_print_warn(ai->dev->name, "Short packet %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 return ERROR;
4367 }
4368
4369 /* packet is 802.11 header + payload
4370 * write the payload length and dst/src/payload */
4371 if (bap_setup(ai, txFid, 6, BAP1) != SUCCESS) return ERROR;
4372 /* The 802.11 header aren't counted as part of the payload, so
4373 * we have to subtract the header bytes off */
4374 payloadLen = cpu_to_le16(len-hdrlen);
4375 bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
4376 if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR;
4377 bap_write(ai, (const u16*)pPacket, hdrlen, BAP1);
Al Viro977b1432007-12-19 16:45:29 -05004378 bap_write(ai, (u16 *)(tail + (hdrlen - 10)), 38 - hdrlen, BAP1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379
4380 bap_write(ai, (const u16*)(pPacket + hdrlen), len - hdrlen, BAP1);
4381 // issue the transmit command
4382 memset( &cmd, 0, sizeof( cmd ) );
4383 cmd.cmd = CMD_TRANSMIT;
4384 cmd.parm0 = txFid;
4385 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
4386 if ( (rsp.status & 0xFF00) != 0) return ERROR;
4387 return SUCCESS;
4388}
4389
4390/*
4391 * This is the proc_fs routines. It is a bit messier than I would
4392 * like! Feel free to clean it up!
4393 */
4394
4395static ssize_t proc_read( struct file *file,
4396 char __user *buffer,
4397 size_t len,
4398 loff_t *offset);
4399
4400static ssize_t proc_write( struct file *file,
4401 const char __user *buffer,
4402 size_t len,
4403 loff_t *offset );
4404static int proc_close( struct inode *inode, struct file *file );
4405
4406static int proc_stats_open( struct inode *inode, struct file *file );
4407static int proc_statsdelta_open( struct inode *inode, struct file *file );
4408static int proc_status_open( struct inode *inode, struct file *file );
4409static int proc_SSID_open( struct inode *inode, struct file *file );
4410static int proc_APList_open( struct inode *inode, struct file *file );
4411static int proc_BSSList_open( struct inode *inode, struct file *file );
4412static int proc_config_open( struct inode *inode, struct file *file );
4413static int proc_wepkey_open( struct inode *inode, struct file *file );
4414
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004415static const struct file_operations proc_statsdelta_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 .read = proc_read,
4417 .open = proc_statsdelta_open,
4418 .release = proc_close
4419};
4420
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004421static const struct file_operations proc_stats_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 .read = proc_read,
4423 .open = proc_stats_open,
4424 .release = proc_close
4425};
4426
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004427static const struct file_operations proc_status_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428 .read = proc_read,
4429 .open = proc_status_open,
4430 .release = proc_close
4431};
4432
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004433static const struct file_operations proc_SSID_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 .read = proc_read,
4435 .write = proc_write,
4436 .open = proc_SSID_open,
4437 .release = proc_close
4438};
4439
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004440static const struct file_operations proc_BSSList_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 .read = proc_read,
4442 .write = proc_write,
4443 .open = proc_BSSList_open,
4444 .release = proc_close
4445};
4446
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004447static const struct file_operations proc_APList_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 .read = proc_read,
4449 .write = proc_write,
4450 .open = proc_APList_open,
4451 .release = proc_close
4452};
4453
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004454static const struct file_operations proc_config_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 .read = proc_read,
4456 .write = proc_write,
4457 .open = proc_config_open,
4458 .release = proc_close
4459};
4460
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004461static const struct file_operations proc_wepkey_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 .read = proc_read,
4463 .write = proc_write,
4464 .open = proc_wepkey_open,
4465 .release = proc_close
4466};
4467
4468static struct proc_dir_entry *airo_entry;
4469
4470struct proc_data {
4471 int release_buffer;
4472 int readlen;
4473 char *rbuffer;
4474 int writelen;
4475 int maxwritelen;
4476 char *wbuffer;
4477 void (*on_close) (struct inode *, struct file *);
4478};
4479
4480#ifndef SETPROC_OPS
4481#define SETPROC_OPS(entry, ops) (entry)->proc_fops = &(ops)
4482#endif
4483
4484static int setup_proc_entry( struct net_device *dev,
4485 struct airo_info *apriv ) {
4486 struct proc_dir_entry *entry;
4487 /* First setup the device directory */
4488 strcpy(apriv->proc_name,dev->name);
4489 apriv->proc_entry = create_proc_entry(apriv->proc_name,
4490 S_IFDIR|airo_perm,
4491 airo_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004492 if (!apriv->proc_entry)
4493 goto fail;
4494 apriv->proc_entry->uid = proc_uid;
4495 apriv->proc_entry->gid = proc_gid;
4496 apriv->proc_entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497
4498 /* Setup the StatsDelta */
4499 entry = create_proc_entry("StatsDelta",
4500 S_IFREG | (S_IRUGO&proc_perm),
4501 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004502 if (!entry)
4503 goto fail_stats_delta;
4504 entry->uid = proc_uid;
4505 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004507 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 SETPROC_OPS(entry, proc_statsdelta_ops);
4509
4510 /* Setup the Stats */
4511 entry = create_proc_entry("Stats",
4512 S_IFREG | (S_IRUGO&proc_perm),
4513 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004514 if (!entry)
4515 goto fail_stats;
4516 entry->uid = proc_uid;
4517 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004519 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 SETPROC_OPS(entry, proc_stats_ops);
4521
4522 /* Setup the Status */
4523 entry = create_proc_entry("Status",
4524 S_IFREG | (S_IRUGO&proc_perm),
4525 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004526 if (!entry)
4527 goto fail_status;
4528 entry->uid = proc_uid;
4529 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004531 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 SETPROC_OPS(entry, proc_status_ops);
4533
4534 /* Setup the Config */
4535 entry = create_proc_entry("Config",
4536 S_IFREG | proc_perm,
4537 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004538 if (!entry)
4539 goto fail_config;
4540 entry->uid = proc_uid;
4541 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004543 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544 SETPROC_OPS(entry, proc_config_ops);
4545
4546 /* Setup the SSID */
4547 entry = create_proc_entry("SSID",
4548 S_IFREG | proc_perm,
4549 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004550 if (!entry)
4551 goto fail_ssid;
4552 entry->uid = proc_uid;
4553 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004555 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556 SETPROC_OPS(entry, proc_SSID_ops);
4557
4558 /* Setup the APList */
4559 entry = create_proc_entry("APList",
4560 S_IFREG | proc_perm,
4561 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004562 if (!entry)
4563 goto fail_aplist;
4564 entry->uid = proc_uid;
4565 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004567 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 SETPROC_OPS(entry, proc_APList_ops);
4569
4570 /* Setup the BSSList */
4571 entry = create_proc_entry("BSSList",
4572 S_IFREG | proc_perm,
4573 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004574 if (!entry)
4575 goto fail_bsslist;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 entry->uid = proc_uid;
4577 entry->gid = proc_gid;
4578 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004579 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 SETPROC_OPS(entry, proc_BSSList_ops);
4581
4582 /* Setup the WepKey */
4583 entry = create_proc_entry("WepKey",
4584 S_IFREG | proc_perm,
4585 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004586 if (!entry)
4587 goto fail_wepkey;
4588 entry->uid = proc_uid;
4589 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004591 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 SETPROC_OPS(entry, proc_wepkey_ops);
4593
4594 return 0;
Florin Malita431aca52006-10-10 16:46:30 -04004595
4596fail_wepkey:
4597 remove_proc_entry("BSSList", apriv->proc_entry);
4598fail_bsslist:
4599 remove_proc_entry("APList", apriv->proc_entry);
4600fail_aplist:
4601 remove_proc_entry("SSID", apriv->proc_entry);
4602fail_ssid:
4603 remove_proc_entry("Config", apriv->proc_entry);
4604fail_config:
4605 remove_proc_entry("Status", apriv->proc_entry);
4606fail_status:
4607 remove_proc_entry("Stats", apriv->proc_entry);
4608fail_stats:
4609 remove_proc_entry("StatsDelta", apriv->proc_entry);
4610fail_stats_delta:
4611 remove_proc_entry(apriv->proc_name, airo_entry);
4612fail:
4613 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614}
4615
4616static int takedown_proc_entry( struct net_device *dev,
4617 struct airo_info *apriv ) {
4618 if ( !apriv->proc_entry->namelen ) return 0;
4619 remove_proc_entry("Stats",apriv->proc_entry);
4620 remove_proc_entry("StatsDelta",apriv->proc_entry);
4621 remove_proc_entry("Status",apriv->proc_entry);
4622 remove_proc_entry("Config",apriv->proc_entry);
4623 remove_proc_entry("SSID",apriv->proc_entry);
4624 remove_proc_entry("APList",apriv->proc_entry);
4625 remove_proc_entry("BSSList",apriv->proc_entry);
4626 remove_proc_entry("WepKey",apriv->proc_entry);
4627 remove_proc_entry(apriv->proc_name,airo_entry);
4628 return 0;
4629}
4630
4631/*
4632 * What we want from the proc_fs is to be able to efficiently read
4633 * and write the configuration. To do this, we want to read the
4634 * configuration when the file is opened and write it when the file is
4635 * closed. So basically we allocate a read buffer at open and fill it
4636 * with data, and allocate a write buffer and read it at close.
4637 */
4638
4639/*
4640 * The read routine is generic, it relies on the preallocated rbuffer
4641 * to supply the data.
4642 */
4643static ssize_t proc_read( struct file *file,
4644 char __user *buffer,
4645 size_t len,
4646 loff_t *offset )
4647{
4648 loff_t pos = *offset;
4649 struct proc_data *priv = (struct proc_data*)file->private_data;
4650
4651 if (!priv->rbuffer)
4652 return -EINVAL;
4653
4654 if (pos < 0)
4655 return -EINVAL;
4656 if (pos >= priv->readlen)
4657 return 0;
4658 if (len > priv->readlen - pos)
4659 len = priv->readlen - pos;
4660 if (copy_to_user(buffer, priv->rbuffer + pos, len))
4661 return -EFAULT;
4662 *offset = pos + len;
4663 return len;
4664}
4665
4666/*
4667 * The write routine is generic, it fills in a preallocated rbuffer
4668 * to supply the data.
4669 */
4670static ssize_t proc_write( struct file *file,
4671 const char __user *buffer,
4672 size_t len,
4673 loff_t *offset )
4674{
4675 loff_t pos = *offset;
4676 struct proc_data *priv = (struct proc_data*)file->private_data;
4677
4678 if (!priv->wbuffer)
4679 return -EINVAL;
4680
4681 if (pos < 0)
4682 return -EINVAL;
4683 if (pos >= priv->maxwritelen)
4684 return 0;
4685 if (len > priv->maxwritelen - pos)
4686 len = priv->maxwritelen - pos;
4687 if (copy_from_user(priv->wbuffer + pos, buffer, len))
4688 return -EFAULT;
4689 if ( pos + len > priv->writelen )
4690 priv->writelen = len + file->f_pos;
4691 *offset = pos + len;
4692 return len;
4693}
4694
4695static int proc_status_open( struct inode *inode, struct file *file ) {
4696 struct proc_data *data;
4697 struct proc_dir_entry *dp = PDE(inode);
4698 struct net_device *dev = dp->data;
4699 struct airo_info *apriv = dev->priv;
4700 CapabilityRid cap_rid;
4701 StatusRid status_rid;
4702 int i;
4703
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01004704 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 data = (struct proc_data *)file->private_data;
4707 if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
4708 kfree (file->private_data);
4709 return -ENOMEM;
4710 }
4711
4712 readStatusRid(apriv, &status_rid, 1);
4713 readCapabilityRid(apriv, &cap_rid, 1);
4714
4715 i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n",
4716 status_rid.mode & 1 ? "CFG ": "",
4717 status_rid.mode & 2 ? "ACT ": "",
4718 status_rid.mode & 0x10 ? "SYN ": "",
4719 status_rid.mode & 0x20 ? "LNK ": "",
4720 status_rid.mode & 0x40 ? "LEAP ": "",
4721 status_rid.mode & 0x80 ? "PRIV ": "",
4722 status_rid.mode & 0x100 ? "KEY ": "",
4723 status_rid.mode & 0x200 ? "WEP ": "",
4724 status_rid.mode & 0x8000 ? "ERR ": "");
4725 sprintf( data->rbuffer+i, "Mode: %x\n"
4726 "Signal Strength: %d\n"
4727 "Signal Quality: %d\n"
4728 "SSID: %-.*s\n"
4729 "AP: %-.16s\n"
4730 "Freq: %d\n"
4731 "BitRate: %dmbs\n"
4732 "Driver Version: %s\n"
4733 "Device: %s\nManufacturer: %s\nFirmware Version: %s\n"
4734 "Radio type: %x\nCountry: %x\nHardware Version: %x\n"
4735 "Software Version: %x\nSoftware Subversion: %x\n"
4736 "Boot block version: %x\n",
4737 (int)status_rid.mode,
4738 (int)status_rid.normalizedSignalStrength,
4739 (int)status_rid.signalQuality,
4740 (int)status_rid.SSIDlen,
4741 status_rid.SSID,
4742 status_rid.apName,
4743 (int)status_rid.channel,
4744 (int)status_rid.currentXmitRate/2,
4745 version,
4746 cap_rid.prodName,
4747 cap_rid.manName,
4748 cap_rid.prodVer,
4749 cap_rid.radioType,
4750 cap_rid.country,
4751 cap_rid.hardVer,
4752 (int)cap_rid.softVer,
4753 (int)cap_rid.softSubVer,
4754 (int)cap_rid.bootBlockVer );
4755 data->readlen = strlen( data->rbuffer );
4756 return 0;
4757}
4758
4759static int proc_stats_rid_open(struct inode*, struct file*, u16);
4760static int proc_statsdelta_open( struct inode *inode,
4761 struct file *file ) {
4762 if (file->f_mode&FMODE_WRITE) {
4763 return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR);
4764 }
4765 return proc_stats_rid_open(inode, file, RID_STATSDELTA);
4766}
4767
4768static int proc_stats_open( struct inode *inode, struct file *file ) {
4769 return proc_stats_rid_open(inode, file, RID_STATS);
4770}
4771
4772static int proc_stats_rid_open( struct inode *inode,
4773 struct file *file,
4774 u16 rid ) {
4775 struct proc_data *data;
4776 struct proc_dir_entry *dp = PDE(inode);
4777 struct net_device *dev = dp->data;
4778 struct airo_info *apriv = dev->priv;
4779 StatsRid stats;
4780 int i, j;
4781 u32 *vals = stats.vals;
4782
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01004783 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 data = (struct proc_data *)file->private_data;
4786 if ((data->rbuffer = kmalloc( 4096, GFP_KERNEL )) == NULL) {
4787 kfree (file->private_data);
4788 return -ENOMEM;
4789 }
4790
4791 readStatsRid(apriv, &stats, rid, 1);
4792
4793 j = 0;
4794 for(i=0; statsLabels[i]!=(char *)-1 &&
4795 i*4<stats.len; i++){
4796 if (!statsLabels[i]) continue;
4797 if (j+strlen(statsLabels[i])+16>4096) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004798 airo_print_warn(apriv->dev->name,
4799 "Potentially disasterous buffer overflow averted!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 break;
4801 }
4802 j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], vals[i]);
4803 }
4804 if (i*4>=stats.len){
Dan Williams934d8bf2006-03-16 13:46:23 -05004805 airo_print_warn(apriv->dev->name, "Got a short rid");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 }
4807 data->readlen = j;
4808 return 0;
4809}
4810
4811static int get_dec_u16( char *buffer, int *start, int limit ) {
4812 u16 value;
4813 int valid = 0;
4814 for( value = 0; buffer[*start] >= '0' &&
4815 buffer[*start] <= '9' &&
4816 *start < limit; (*start)++ ) {
4817 valid = 1;
4818 value *= 10;
4819 value += buffer[*start] - '0';
4820 }
4821 if ( !valid ) return -1;
4822 return value;
4823}
4824
4825static int airo_config_commit(struct net_device *dev,
4826 struct iw_request_info *info, void *zwrq,
4827 char *extra);
4828
4829static void proc_config_on_close( struct inode *inode, struct file *file ) {
4830 struct proc_data *data = file->private_data;
4831 struct proc_dir_entry *dp = PDE(inode);
4832 struct net_device *dev = dp->data;
4833 struct airo_info *ai = dev->priv;
4834 char *line;
4835
4836 if ( !data->writelen ) return;
4837
4838 readConfigRid(ai, 1);
4839 set_bit (FLAG_COMMIT, &ai->flags);
4840
4841 line = data->wbuffer;
4842 while( line[0] ) {
4843/*** Mode processing */
4844 if ( !strncmp( line, "Mode: ", 6 ) ) {
4845 line += 6;
4846 if ((ai->config.rmode & 0xff) >= RXMODE_RFMON)
4847 set_bit (FLAG_RESET, &ai->flags);
4848 ai->config.rmode &= 0xfe00;
4849 clear_bit (FLAG_802_11, &ai->flags);
4850 ai->config.opmode &= 0xFF00;
4851 ai->config.scanMode = SCANMODE_ACTIVE;
4852 if ( line[0] == 'a' ) {
4853 ai->config.opmode |= 0;
4854 } else {
4855 ai->config.opmode |= 1;
4856 if ( line[0] == 'r' ) {
4857 ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
4858 ai->config.scanMode = SCANMODE_PASSIVE;
4859 set_bit (FLAG_802_11, &ai->flags);
4860 } else if ( line[0] == 'y' ) {
4861 ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER;
4862 ai->config.scanMode = SCANMODE_PASSIVE;
4863 set_bit (FLAG_802_11, &ai->flags);
4864 } else if ( line[0] == 'l' )
4865 ai->config.rmode |= RXMODE_LANMON;
4866 }
4867 set_bit (FLAG_COMMIT, &ai->flags);
4868 }
4869
4870/*** Radio status */
4871 else if (!strncmp(line,"Radio: ", 7)) {
4872 line += 7;
4873 if (!strncmp(line,"off",3)) {
4874 set_bit (FLAG_RADIO_OFF, &ai->flags);
4875 } else {
4876 clear_bit (FLAG_RADIO_OFF, &ai->flags);
4877 }
4878 }
4879/*** NodeName processing */
4880 else if ( !strncmp( line, "NodeName: ", 10 ) ) {
4881 int j;
4882
4883 line += 10;
4884 memset( ai->config.nodeName, 0, 16 );
4885/* Do the name, assume a space between the mode and node name */
4886 for( j = 0; j < 16 && line[j] != '\n'; j++ ) {
4887 ai->config.nodeName[j] = line[j];
4888 }
4889 set_bit (FLAG_COMMIT, &ai->flags);
4890 }
4891
4892/*** PowerMode processing */
4893 else if ( !strncmp( line, "PowerMode: ", 11 ) ) {
4894 line += 11;
4895 if ( !strncmp( line, "PSPCAM", 6 ) ) {
4896 ai->config.powerSaveMode = POWERSAVE_PSPCAM;
4897 set_bit (FLAG_COMMIT, &ai->flags);
4898 } else if ( !strncmp( line, "PSP", 3 ) ) {
4899 ai->config.powerSaveMode = POWERSAVE_PSP;
4900 set_bit (FLAG_COMMIT, &ai->flags);
4901 } else {
4902 ai->config.powerSaveMode = POWERSAVE_CAM;
4903 set_bit (FLAG_COMMIT, &ai->flags);
4904 }
4905 } else if ( !strncmp( line, "DataRates: ", 11 ) ) {
4906 int v, i = 0, k = 0; /* i is index into line,
4907 k is index to rates */
4908
4909 line += 11;
4910 while((v = get_dec_u16(line, &i, 3))!=-1) {
4911 ai->config.rates[k++] = (u8)v;
4912 line += i + 1;
4913 i = 0;
4914 }
4915 set_bit (FLAG_COMMIT, &ai->flags);
4916 } else if ( !strncmp( line, "Channel: ", 9 ) ) {
4917 int v, i = 0;
4918 line += 9;
4919 v = get_dec_u16(line, &i, i+3);
4920 if ( v != -1 ) {
4921 ai->config.channelSet = (u16)v;
4922 set_bit (FLAG_COMMIT, &ai->flags);
4923 }
4924 } else if ( !strncmp( line, "XmitPower: ", 11 ) ) {
4925 int v, i = 0;
4926 line += 11;
4927 v = get_dec_u16(line, &i, i+3);
4928 if ( v != -1 ) {
4929 ai->config.txPower = (u16)v;
4930 set_bit (FLAG_COMMIT, &ai->flags);
4931 }
4932 } else if ( !strncmp( line, "WEP: ", 5 ) ) {
4933 line += 5;
4934 switch( line[0] ) {
4935 case 's':
4936 ai->config.authType = (u16)AUTH_SHAREDKEY;
4937 break;
4938 case 'e':
4939 ai->config.authType = (u16)AUTH_ENCRYPT;
4940 break;
4941 default:
4942 ai->config.authType = (u16)AUTH_OPEN;
4943 break;
4944 }
4945 set_bit (FLAG_COMMIT, &ai->flags);
4946 } else if ( !strncmp( line, "LongRetryLimit: ", 16 ) ) {
4947 int v, i = 0;
4948
4949 line += 16;
4950 v = get_dec_u16(line, &i, 3);
4951 v = (v<0) ? 0 : ((v>255) ? 255 : v);
4952 ai->config.longRetryLimit = (u16)v;
4953 set_bit (FLAG_COMMIT, &ai->flags);
4954 } else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) {
4955 int v, i = 0;
4956
4957 line += 17;
4958 v = get_dec_u16(line, &i, 3);
4959 v = (v<0) ? 0 : ((v>255) ? 255 : v);
4960 ai->config.shortRetryLimit = (u16)v;
4961 set_bit (FLAG_COMMIT, &ai->flags);
4962 } else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) {
4963 int v, i = 0;
4964
4965 line += 14;
4966 v = get_dec_u16(line, &i, 4);
Dan Williams15db2762006-03-16 13:46:27 -05004967 v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968 ai->config.rtsThres = (u16)v;
4969 set_bit (FLAG_COMMIT, &ai->flags);
4970 } else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) {
4971 int v, i = 0;
4972
4973 line += 16;
4974 v = get_dec_u16(line, &i, 5);
4975 v = (v<0) ? 0 : v;
4976 ai->config.txLifetime = (u16)v;
4977 set_bit (FLAG_COMMIT, &ai->flags);
4978 } else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) {
4979 int v, i = 0;
4980
4981 line += 16;
4982 v = get_dec_u16(line, &i, 5);
4983 v = (v<0) ? 0 : v;
4984 ai->config.rxLifetime = (u16)v;
4985 set_bit (FLAG_COMMIT, &ai->flags);
4986 } else if ( !strncmp( line, "TXDiversity: ", 13 ) ) {
4987 ai->config.txDiversity =
4988 (line[13]=='l') ? 1 :
4989 ((line[13]=='r')? 2: 3);
4990 set_bit (FLAG_COMMIT, &ai->flags);
4991 } else if ( !strncmp( line, "RXDiversity: ", 13 ) ) {
4992 ai->config.rxDiversity =
4993 (line[13]=='l') ? 1 :
4994 ((line[13]=='r')? 2: 3);
4995 set_bit (FLAG_COMMIT, &ai->flags);
4996 } else if ( !strncmp( line, "FragThreshold: ", 15 ) ) {
4997 int v, i = 0;
4998
4999 line += 15;
5000 v = get_dec_u16(line, &i, 4);
Dan Williams15db2762006-03-16 13:46:27 -05005001 v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002 v = v & 0xfffe; /* Make sure its even */
5003 ai->config.fragThresh = (u16)v;
5004 set_bit (FLAG_COMMIT, &ai->flags);
5005 } else if (!strncmp(line, "Modulation: ", 12)) {
5006 line += 12;
5007 switch(*line) {
5008 case 'd': ai->config.modulation=MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break;
5009 case 'c': ai->config.modulation=MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break;
5010 case 'm': ai->config.modulation=MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break;
Dan Williams934d8bf2006-03-16 13:46:23 -05005011 default: airo_print_warn(ai->dev->name, "Unknown modulation");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012 }
5013 } else if (!strncmp(line, "Preamble: ", 10)) {
5014 line += 10;
5015 switch(*line) {
5016 case 'a': ai->config.preamble=PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break;
5017 case 'l': ai->config.preamble=PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break;
5018 case 's': ai->config.preamble=PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break;
Dan Williams934d8bf2006-03-16 13:46:23 -05005019 default: airo_print_warn(ai->dev->name, "Unknown preamble");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 }
5021 } else {
Dan Williams934d8bf2006-03-16 13:46:23 -05005022 airo_print_warn(ai->dev->name, "Couldn't figure out %s", line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023 }
5024 while( line[0] && line[0] != '\n' ) line++;
5025 if ( line[0] ) line++;
5026 }
5027 airo_config_commit(dev, NULL, NULL, NULL);
5028}
5029
5030static char *get_rmode(u16 mode) {
5031 switch(mode&0xff) {
5032 case RXMODE_RFMON: return "rfmon";
5033 case RXMODE_RFMON_ANYBSS: return "yna (any) bss rfmon";
5034 case RXMODE_LANMON: return "lanmon";
5035 }
5036 return "ESS";
5037}
5038
5039static int proc_config_open( struct inode *inode, struct file *file ) {
5040 struct proc_data *data;
5041 struct proc_dir_entry *dp = PDE(inode);
5042 struct net_device *dev = dp->data;
5043 struct airo_info *ai = dev->priv;
5044 int i;
5045
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005046 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048 data = (struct proc_data *)file->private_data;
5049 if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
5050 kfree (file->private_data);
5051 return -ENOMEM;
5052 }
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005053 if ((data->wbuffer = kzalloc( 2048, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 kfree (data->rbuffer);
5055 kfree (file->private_data);
5056 return -ENOMEM;
5057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 data->maxwritelen = 2048;
5059 data->on_close = proc_config_on_close;
5060
5061 readConfigRid(ai, 1);
5062
5063 i = sprintf( data->rbuffer,
5064 "Mode: %s\n"
5065 "Radio: %s\n"
5066 "NodeName: %-16s\n"
5067 "PowerMode: %s\n"
5068 "DataRates: %d %d %d %d %d %d %d %d\n"
5069 "Channel: %d\n"
5070 "XmitPower: %d\n",
5071 (ai->config.opmode & 0xFF) == 0 ? "adhoc" :
5072 (ai->config.opmode & 0xFF) == 1 ? get_rmode(ai->config.rmode):
5073 (ai->config.opmode & 0xFF) == 2 ? "AP" :
5074 (ai->config.opmode & 0xFF) == 3 ? "AP RPTR" : "Error",
5075 test_bit(FLAG_RADIO_OFF, &ai->flags) ? "off" : "on",
5076 ai->config.nodeName,
5077 ai->config.powerSaveMode == 0 ? "CAM" :
5078 ai->config.powerSaveMode == 1 ? "PSP" :
5079 ai->config.powerSaveMode == 2 ? "PSPCAM" : "Error",
5080 (int)ai->config.rates[0],
5081 (int)ai->config.rates[1],
5082 (int)ai->config.rates[2],
5083 (int)ai->config.rates[3],
5084 (int)ai->config.rates[4],
5085 (int)ai->config.rates[5],
5086 (int)ai->config.rates[6],
5087 (int)ai->config.rates[7],
5088 (int)ai->config.channelSet,
5089 (int)ai->config.txPower
5090 );
5091 sprintf( data->rbuffer + i,
5092 "LongRetryLimit: %d\n"
5093 "ShortRetryLimit: %d\n"
5094 "RTSThreshold: %d\n"
5095 "TXMSDULifetime: %d\n"
5096 "RXMSDULifetime: %d\n"
5097 "TXDiversity: %s\n"
5098 "RXDiversity: %s\n"
5099 "FragThreshold: %d\n"
5100 "WEP: %s\n"
5101 "Modulation: %s\n"
5102 "Preamble: %s\n",
5103 (int)ai->config.longRetryLimit,
5104 (int)ai->config.shortRetryLimit,
5105 (int)ai->config.rtsThres,
5106 (int)ai->config.txLifetime,
5107 (int)ai->config.rxLifetime,
5108 ai->config.txDiversity == 1 ? "left" :
5109 ai->config.txDiversity == 2 ? "right" : "both",
5110 ai->config.rxDiversity == 1 ? "left" :
5111 ai->config.rxDiversity == 2 ? "right" : "both",
5112 (int)ai->config.fragThresh,
5113 ai->config.authType == AUTH_ENCRYPT ? "encrypt" :
5114 ai->config.authType == AUTH_SHAREDKEY ? "shared" : "open",
5115 ai->config.modulation == 0 ? "default" :
5116 ai->config.modulation == MOD_CCK ? "cck" :
5117 ai->config.modulation == MOD_MOK ? "mok" : "error",
5118 ai->config.preamble == PREAMBLE_AUTO ? "auto" :
5119 ai->config.preamble == PREAMBLE_LONG ? "long" :
5120 ai->config.preamble == PREAMBLE_SHORT ? "short" : "error"
5121 );
5122 data->readlen = strlen( data->rbuffer );
5123 return 0;
5124}
5125
5126static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
5127 struct proc_data *data = (struct proc_data *)file->private_data;
5128 struct proc_dir_entry *dp = PDE(inode);
5129 struct net_device *dev = dp->data;
5130 struct airo_info *ai = dev->priv;
5131 SsidRid SSID_rid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132 int i;
5133 int offset = 0;
5134
5135 if ( !data->writelen ) return;
5136
5137 memset( &SSID_rid, 0, sizeof( SSID_rid ) );
5138
5139 for( i = 0; i < 3; i++ ) {
5140 int j;
5141 for( j = 0; j+offset < data->writelen && j < 32 &&
5142 data->wbuffer[offset+j] != '\n'; j++ ) {
5143 SSID_rid.ssids[i].ssid[j] = data->wbuffer[offset+j];
5144 }
5145 if ( j == 0 ) break;
5146 SSID_rid.ssids[i].len = j;
5147 offset += j;
5148 while( data->wbuffer[offset] != '\n' &&
5149 offset < data->writelen ) offset++;
5150 offset++;
5151 }
5152 if (i)
5153 SSID_rid.len = sizeof(SSID_rid);
5154 disable_MAC(ai, 1);
5155 writeSsidRid(ai, &SSID_rid, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005156 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157}
5158
Jesper Juhl77933d72005-07-27 11:46:09 -07005159static inline u8 hexVal(char c) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 if (c>='0' && c<='9') return c -= '0';
5161 if (c>='a' && c<='f') return c -= 'a'-10;
5162 if (c>='A' && c<='F') return c -= 'A'-10;
5163 return 0;
5164}
5165
5166static void proc_APList_on_close( struct inode *inode, struct file *file ) {
5167 struct proc_data *data = (struct proc_data *)file->private_data;
5168 struct proc_dir_entry *dp = PDE(inode);
5169 struct net_device *dev = dp->data;
5170 struct airo_info *ai = dev->priv;
5171 APListRid APList_rid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 int i;
5173
5174 if ( !data->writelen ) return;
5175
5176 memset( &APList_rid, 0, sizeof(APList_rid) );
5177 APList_rid.len = sizeof(APList_rid);
5178
5179 for( i = 0; i < 4 && data->writelen >= (i+1)*6*3; i++ ) {
5180 int j;
5181 for( j = 0; j < 6*3 && data->wbuffer[j+i*6*3]; j++ ) {
5182 switch(j%3) {
5183 case 0:
5184 APList_rid.ap[i][j/3]=
5185 hexVal(data->wbuffer[j+i*6*3])<<4;
5186 break;
5187 case 1:
5188 APList_rid.ap[i][j/3]|=
5189 hexVal(data->wbuffer[j+i*6*3]);
5190 break;
5191 }
5192 }
5193 }
5194 disable_MAC(ai, 1);
5195 writeAPListRid(ai, &APList_rid, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005196 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197}
5198
5199/* This function wraps PC4500_writerid with a MAC disable */
5200static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data,
5201 int len, int dummy ) {
5202 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203
5204 disable_MAC(ai, 1);
5205 rc = PC4500_writerid(ai, rid, rid_data, len, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005206 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 return rc;
5208}
5209
5210/* Returns the length of the key at the index. If index == 0xffff
5211 * the index of the transmit key is returned. If the key doesn't exist,
5212 * -1 will be returned.
5213 */
5214static int get_wep_key(struct airo_info *ai, u16 index) {
5215 WepKeyRid wkr;
5216 int rc;
5217 u16 lastindex;
5218
5219 rc = readWepKeyRid(ai, &wkr, 1, 1);
5220 if (rc == SUCCESS) do {
5221 lastindex = wkr.kindex;
5222 if (wkr.kindex == index) {
5223 if (index == 0xffff) {
5224 return wkr.mac[0];
5225 }
5226 return wkr.klen;
5227 }
5228 readWepKeyRid(ai, &wkr, 0, 1);
5229 } while(lastindex != wkr.kindex);
5230 return -1;
5231}
5232
5233static int set_wep_key(struct airo_info *ai, u16 index,
5234 const char *key, u16 keylen, int perm, int lock ) {
5235 static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
5236 WepKeyRid wkr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237
5238 memset(&wkr, 0, sizeof(wkr));
5239 if (keylen == 0) {
5240// We are selecting which key to use
5241 wkr.len = sizeof(wkr);
5242 wkr.kindex = 0xffff;
5243 wkr.mac[0] = (char)index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244 if (perm) ai->defindex = (char)index;
5245 } else {
5246// We are actually setting the key
5247 wkr.len = sizeof(wkr);
5248 wkr.kindex = index;
5249 wkr.klen = keylen;
5250 memcpy( wkr.key, key, keylen );
5251 memcpy( wkr.mac, macaddr, ETH_ALEN );
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 }
5253
Dan Streetmanf89b2322005-11-11 11:41:42 -05005254 if (perm) disable_MAC(ai, lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255 writeWepKeyRid(ai, &wkr, perm, lock);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005256 if (perm) enable_MAC(ai, lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257 return 0;
5258}
5259
5260static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
5261 struct proc_data *data;
5262 struct proc_dir_entry *dp = PDE(inode);
5263 struct net_device *dev = dp->data;
5264 struct airo_info *ai = dev->priv;
5265 int i;
5266 char key[16];
5267 u16 index = 0;
5268 int j = 0;
5269
5270 memset(key, 0, sizeof(key));
5271
5272 data = (struct proc_data *)file->private_data;
5273 if ( !data->writelen ) return;
5274
5275 if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' &&
5276 (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) {
5277 index = data->wbuffer[0] - '0';
5278 if (data->wbuffer[1] == '\n') {
5279 set_wep_key(ai, index, NULL, 0, 1, 1);
5280 return;
5281 }
5282 j = 2;
5283 } else {
Dan Williams934d8bf2006-03-16 13:46:23 -05005284 airo_print_err(ai->dev->name, "WepKey passed invalid key index");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285 return;
5286 }
5287
5288 for( i = 0; i < 16*3 && data->wbuffer[i+j]; i++ ) {
5289 switch(i%3) {
5290 case 0:
5291 key[i/3] = hexVal(data->wbuffer[i+j])<<4;
5292 break;
5293 case 1:
5294 key[i/3] |= hexVal(data->wbuffer[i+j]);
5295 break;
5296 }
5297 }
5298 set_wep_key(ai, index, key, i/3, 1, 1);
5299}
5300
5301static int proc_wepkey_open( struct inode *inode, struct file *file ) {
5302 struct proc_data *data;
5303 struct proc_dir_entry *dp = PDE(inode);
5304 struct net_device *dev = dp->data;
5305 struct airo_info *ai = dev->priv;
5306 char *ptr;
5307 WepKeyRid wkr;
5308 u16 lastindex;
5309 int j=0;
5310 int rc;
5311
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005312 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314 memset(&wkr, 0, sizeof(wkr));
5315 data = (struct proc_data *)file->private_data;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005316 if ((data->rbuffer = kzalloc( 180, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317 kfree (file->private_data);
5318 return -ENOMEM;
5319 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005320 data->writelen = 0;
5321 data->maxwritelen = 80;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005322 if ((data->wbuffer = kzalloc( 80, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323 kfree (data->rbuffer);
5324 kfree (file->private_data);
5325 return -ENOMEM;
5326 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327 data->on_close = proc_wepkey_on_close;
5328
5329 ptr = data->rbuffer;
5330 strcpy(ptr, "No wep keys\n");
5331 rc = readWepKeyRid(ai, &wkr, 1, 1);
5332 if (rc == SUCCESS) do {
5333 lastindex = wkr.kindex;
5334 if (wkr.kindex == 0xffff) {
5335 j += sprintf(ptr+j, "Tx key = %d\n",
5336 (int)wkr.mac[0]);
5337 } else {
5338 j += sprintf(ptr+j, "Key %d set with length = %d\n",
5339 (int)wkr.kindex, (int)wkr.klen);
5340 }
5341 readWepKeyRid(ai, &wkr, 0, 1);
5342 } while((lastindex != wkr.kindex) && (j < 180-30));
5343
5344 data->readlen = strlen( data->rbuffer );
5345 return 0;
5346}
5347
5348static int proc_SSID_open( struct inode *inode, struct file *file ) {
5349 struct proc_data *data;
5350 struct proc_dir_entry *dp = PDE(inode);
5351 struct net_device *dev = dp->data;
5352 struct airo_info *ai = dev->priv;
5353 int i;
5354 char *ptr;
5355 SsidRid SSID_rid;
5356
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005357 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359 data = (struct proc_data *)file->private_data;
5360 if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
5361 kfree (file->private_data);
5362 return -ENOMEM;
5363 }
5364 data->writelen = 0;
5365 data->maxwritelen = 33*3;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005366 if ((data->wbuffer = kzalloc( 33*3, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367 kfree (data->rbuffer);
5368 kfree (file->private_data);
5369 return -ENOMEM;
5370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 data->on_close = proc_SSID_on_close;
5372
5373 readSsidRid(ai, &SSID_rid);
5374 ptr = data->rbuffer;
5375 for( i = 0; i < 3; i++ ) {
5376 int j;
5377 if ( !SSID_rid.ssids[i].len ) break;
5378 for( j = 0; j < 32 &&
5379 j < SSID_rid.ssids[i].len &&
5380 SSID_rid.ssids[i].ssid[j]; j++ ) {
5381 *ptr++ = SSID_rid.ssids[i].ssid[j];
5382 }
5383 *ptr++ = '\n';
5384 }
5385 *ptr = '\0';
5386 data->readlen = strlen( data->rbuffer );
5387 return 0;
5388}
5389
5390static int proc_APList_open( struct inode *inode, struct file *file ) {
5391 struct proc_data *data;
5392 struct proc_dir_entry *dp = PDE(inode);
5393 struct net_device *dev = dp->data;
5394 struct airo_info *ai = dev->priv;
5395 int i;
5396 char *ptr;
5397 APListRid APList_rid;
Joe Perches0795af52007-10-03 17:59:30 -07005398 DECLARE_MAC_BUF(mac);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005400 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 data = (struct proc_data *)file->private_data;
5403 if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
5404 kfree (file->private_data);
5405 return -ENOMEM;
5406 }
5407 data->writelen = 0;
5408 data->maxwritelen = 4*6*3;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005409 if ((data->wbuffer = kzalloc( data->maxwritelen, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410 kfree (data->rbuffer);
5411 kfree (file->private_data);
5412 return -ENOMEM;
5413 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414 data->on_close = proc_APList_on_close;
5415
5416 readAPListRid(ai, &APList_rid);
5417 ptr = data->rbuffer;
5418 for( i = 0; i < 4; i++ ) {
5419// We end when we find a zero MAC
5420 if ( !*(int*)APList_rid.ap[i] &&
5421 !*(int*)&APList_rid.ap[i][2]) break;
Joe Perches0795af52007-10-03 17:59:30 -07005422 ptr += sprintf(ptr, "%s\n",
5423 print_mac(mac, APList_rid.ap[i]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 }
5425 if (i==0) ptr += sprintf(ptr, "Not using specific APs\n");
5426
5427 *ptr = '\0';
5428 data->readlen = strlen( data->rbuffer );
5429 return 0;
5430}
5431
5432static int proc_BSSList_open( struct inode *inode, struct file *file ) {
5433 struct proc_data *data;
5434 struct proc_dir_entry *dp = PDE(inode);
5435 struct net_device *dev = dp->data;
5436 struct airo_info *ai = dev->priv;
5437 char *ptr;
5438 BSSListRid BSSList_rid;
5439 int rc;
5440 /* If doLoseSync is not 1, we won't do a Lose Sync */
5441 int doLoseSync = -1;
Joe Perches0795af52007-10-03 17:59:30 -07005442 DECLARE_MAC_BUF(mac);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005444 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 data = (struct proc_data *)file->private_data;
5447 if ((data->rbuffer = kmalloc( 1024, GFP_KERNEL )) == NULL) {
5448 kfree (file->private_data);
5449 return -ENOMEM;
5450 }
5451 data->writelen = 0;
5452 data->maxwritelen = 0;
5453 data->wbuffer = NULL;
5454 data->on_close = NULL;
5455
5456 if (file->f_mode & FMODE_WRITE) {
5457 if (!(file->f_mode & FMODE_READ)) {
5458 Cmd cmd;
5459 Resp rsp;
5460
5461 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
5462 memset(&cmd, 0, sizeof(cmd));
5463 cmd.cmd=CMD_LISTBSS;
5464 if (down_interruptible(&ai->sem))
5465 return -ERESTARTSYS;
5466 issuecommand(ai, &cmd, &rsp);
5467 up(&ai->sem);
5468 data->readlen = 0;
5469 return 0;
5470 }
5471 doLoseSync = 1;
5472 }
5473 ptr = data->rbuffer;
5474 /* There is a race condition here if there are concurrent opens.
5475 Since it is a rare condition, we'll just live with it, otherwise
5476 we have to add a spin lock... */
5477 rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
5478 while(rc == 0 && BSSList_rid.index != 0xffff) {
Joe Perches0795af52007-10-03 17:59:30 -07005479 ptr += sprintf(ptr, "%s %*s rssi = %d",
5480 print_mac(mac, BSSList_rid.bssid),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 (int)BSSList_rid.ssidLen,
5482 BSSList_rid.ssid,
Dan Williams41480af2005-05-10 09:45:51 -04005483 (int)BSSList_rid.dBm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 ptr += sprintf(ptr, " channel = %d %s %s %s %s\n",
5485 (int)BSSList_rid.dsChannel,
5486 BSSList_rid.cap & CAP_ESS ? "ESS" : "",
5487 BSSList_rid.cap & CAP_IBSS ? "adhoc" : "",
5488 BSSList_rid.cap & CAP_PRIVACY ? "wep" : "",
5489 BSSList_rid.cap & CAP_SHORTHDR ? "shorthdr" : "");
5490 rc = readBSSListRid(ai, 0, &BSSList_rid);
5491 }
5492 *ptr = '\0';
5493 data->readlen = strlen( data->rbuffer );
5494 return 0;
5495}
5496
5497static int proc_close( struct inode *inode, struct file *file )
5498{
Jesper Juhlb4558ea2005-10-28 16:53:13 -04005499 struct proc_data *data = file->private_data;
5500
5501 if (data->on_close != NULL)
5502 data->on_close(inode, file);
5503 kfree(data->rbuffer);
5504 kfree(data->wbuffer);
5505 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506 return 0;
5507}
5508
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509/* Since the card doesn't automatically switch to the right WEP mode,
5510 we will make it do it. If the card isn't associated, every secs we
5511 will switch WEP modes to see if that will help. If the card is
5512 associated we will check every minute to see if anything has
5513 changed. */
5514static void timer_func( struct net_device *dev ) {
5515 struct airo_info *apriv = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516
5517/* We don't have a link so try changing the authtype */
5518 readConfigRid(apriv, 0);
5519 disable_MAC(apriv, 0);
5520 switch(apriv->config.authType) {
5521 case AUTH_ENCRYPT:
5522/* So drop to OPEN */
5523 apriv->config.authType = AUTH_OPEN;
5524 break;
5525 case AUTH_SHAREDKEY:
5526 if (apriv->keyindex < auto_wep) {
5527 set_wep_key(apriv, apriv->keyindex, NULL, 0, 0, 0);
5528 apriv->config.authType = AUTH_SHAREDKEY;
5529 apriv->keyindex++;
5530 } else {
5531 /* Drop to ENCRYPT */
5532 apriv->keyindex = 0;
5533 set_wep_key(apriv, apriv->defindex, NULL, 0, 0, 0);
5534 apriv->config.authType = AUTH_ENCRYPT;
5535 }
5536 break;
5537 default: /* We'll escalate to SHAREDKEY */
5538 apriv->config.authType = AUTH_SHAREDKEY;
5539 }
5540 set_bit (FLAG_COMMIT, &apriv->flags);
5541 writeConfigRid(apriv, 0);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005542 enable_MAC(apriv, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 up(&apriv->sem);
5544
5545/* Schedule check to see if the change worked */
Dan Williams3c304952006-04-15 12:26:18 -04005546 clear_bit(JOB_AUTOWEP, &apriv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547 apriv->expires = RUN_AT(HZ*3);
5548}
5549
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550#ifdef CONFIG_PCI
5551static int __devinit airo_pci_probe(struct pci_dev *pdev,
5552 const struct pci_device_id *pent)
5553{
5554 struct net_device *dev;
5555
5556 if (pci_enable_device(pdev))
5557 return -ENODEV;
5558 pci_set_master(pdev);
5559
5560 if (pdev->device == 0x5000 || pdev->device == 0xa504)
5561 dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev);
5562 else
5563 dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev);
Michal Schmidt777ec5e2007-06-29 15:33:30 +02005564 if (!dev) {
5565 pci_disable_device(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 return -ENODEV;
Michal Schmidt777ec5e2007-06-29 15:33:30 +02005567 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568
5569 pci_set_drvdata(pdev, dev);
5570 return 0;
5571}
5572
5573static void __devexit airo_pci_remove(struct pci_dev *pdev)
5574{
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01005575 struct net_device *dev = pci_get_drvdata(pdev);
5576
5577 airo_print_info(dev->name, "Unregistering...");
5578 stop_airo_card(dev, 1);
Michal Schmidt777ec5e2007-06-29 15:33:30 +02005579 pci_disable_device(pdev);
5580 pci_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581}
5582
Pavel Machek05adc3b2005-04-16 15:25:25 -07005583static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584{
5585 struct net_device *dev = pci_get_drvdata(pdev);
5586 struct airo_info *ai = dev->priv;
5587 Cmd cmd;
5588 Resp rsp;
5589
5590 if ((ai->APList == NULL) &&
5591 (ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL)) == NULL)
5592 return -ENOMEM;
5593 if ((ai->SSID == NULL) &&
5594 (ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL)) == NULL)
5595 return -ENOMEM;
5596 readAPListRid(ai, ai->APList);
5597 readSsidRid(ai, ai->SSID);
5598 memset(&cmd, 0, sizeof(cmd));
5599 /* the lock will be released at the end of the resume callback */
5600 if (down_interruptible(&ai->sem))
5601 return -EAGAIN;
5602 disable_MAC(ai, 0);
5603 netif_device_detach(dev);
5604 ai->power = state;
5605 cmd.cmd=HOSTSLEEP;
5606 issuecommand(ai, &cmd, &rsp);
5607
Pavel Machek1cc68ae2005-06-20 15:33:04 -07005608 pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 pci_save_state(pdev);
Pavel Machek1cc68ae2005-06-20 15:33:04 -07005610 return pci_set_power_state(pdev, pci_choose_state(pdev, state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611}
5612
5613static int airo_pci_resume(struct pci_dev *pdev)
5614{
5615 struct net_device *dev = pci_get_drvdata(pdev);
5616 struct airo_info *ai = dev->priv;
Michal Schmidt53232802005-10-04 07:46:21 -04005617 pci_power_t prev_state = pdev->current_state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618
Michal Schmidt53232802005-10-04 07:46:21 -04005619 pci_set_power_state(pdev, PCI_D0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620 pci_restore_state(pdev);
Michal Schmidt53232802005-10-04 07:46:21 -04005621 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622
Michal Schmidt53232802005-10-04 07:46:21 -04005623 if (prev_state != PCI_D1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 reset_card(dev, 0);
5625 mpi_init_descriptors(ai);
5626 setup_card(ai, dev->dev_addr, 0);
5627 clear_bit(FLAG_RADIO_OFF, &ai->flags);
5628 clear_bit(FLAG_PENDING_XMIT, &ai->flags);
5629 } else {
5630 OUT4500(ai, EVACK, EV_AWAKEN);
5631 OUT4500(ai, EVACK, EV_AWAKEN);
5632 msleep(100);
5633 }
5634
5635 set_bit (FLAG_COMMIT, &ai->flags);
5636 disable_MAC(ai, 0);
5637 msleep(200);
5638 if (ai->SSID) {
5639 writeSsidRid(ai, ai->SSID, 0);
5640 kfree(ai->SSID);
5641 ai->SSID = NULL;
5642 }
5643 if (ai->APList) {
5644 writeAPListRid(ai, ai->APList, 0);
5645 kfree(ai->APList);
5646 ai->APList = NULL;
5647 }
5648 writeConfigRid(ai, 0);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005649 enable_MAC(ai, 0);
Pavel Machek1cc68ae2005-06-20 15:33:04 -07005650 ai->power = PMSG_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 netif_device_attach(dev);
5652 netif_wake_queue(dev);
5653 enable_interrupts(ai);
5654 up(&ai->sem);
5655 return 0;
5656}
5657#endif
5658
5659static int __init airo_init_module( void )
5660{
Jeff Garzikde897882006-10-01 07:31:09 -04005661 int i;
5662#if 0
5663 int have_isa_dev = 0;
5664#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665
5666 airo_entry = create_proc_entry("aironet",
5667 S_IFDIR | airo_perm,
5668 proc_root_driver);
Jeff Garzikde897882006-10-01 07:31:09 -04005669
5670 if (airo_entry) {
5671 airo_entry->uid = proc_uid;
5672 airo_entry->gid = proc_gid;
5673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674
5675 for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05005676 airo_print_info("", "Trying to configure ISA adapter at irq=%d "
5677 "io=0x%x", irq[i], io[i] );
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678 if (init_airo_card( irq[i], io[i], 0, NULL ))
Jeff Garzikde897882006-10-01 07:31:09 -04005679#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680 have_isa_dev = 1;
Jeff Garzikde897882006-10-01 07:31:09 -04005681#else
5682 /* do nothing */ ;
5683#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684 }
5685
5686#ifdef CONFIG_PCI
Dan Williams934d8bf2006-03-16 13:46:23 -05005687 airo_print_info("", "Probing for PCI adapters");
Jeff Garzikde897882006-10-01 07:31:09 -04005688 i = pci_register_driver(&airo_driver);
Dan Williams934d8bf2006-03-16 13:46:23 -05005689 airo_print_info("", "Finished probing for PCI adapters");
Jeff Garzikde897882006-10-01 07:31:09 -04005690
5691 if (i) {
5692 remove_proc_entry("aironet", proc_root_driver);
5693 return i;
5694 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005695#endif
5696
5697 /* Always exit with success, as we are a library module
5698 * as well as a driver module
5699 */
5700 return 0;
5701}
5702
5703static void __exit airo_cleanup_module( void )
5704{
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01005705 struct airo_info *ai;
5706 while(!list_empty(&airo_devices)) {
5707 ai = list_entry(airo_devices.next, struct airo_info, dev_list);
5708 airo_print_info(ai->dev->name, "Unregistering...");
5709 stop_airo_card(ai->dev, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005710 }
5711#ifdef CONFIG_PCI
5712 pci_unregister_driver(&airo_driver);
5713#endif
5714 remove_proc_entry("aironet", proc_root_driver);
5715}
5716
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717/*
5718 * Initial Wireless Extension code for Aironet driver by :
5719 * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 17 November 00
5720 * Conversion to new driver API by :
5721 * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 26 March 02
5722 * Javier also did a good amount of work here, adding some new extensions
5723 * and fixing my code. Let's just say that without him this code just
5724 * would not work at all... - Jean II
5725 */
5726
Dan Williams41480af2005-05-10 09:45:51 -04005727static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi)
5728{
5729 if( !rssi_rid )
5730 return 0;
5731
5732 return (0x100 - rssi_rid[rssi].rssidBm);
5733}
5734
5735static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
5736{
5737 int i;
5738
5739 if( !rssi_rid )
5740 return 0;
5741
5742 for( i = 0; i < 256; i++ )
5743 if (rssi_rid[i].rssidBm == dbm)
5744 return rssi_rid[i].rssipct;
5745
5746 return 0;
5747}
5748
5749
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid)
5751{
5752 int quality = 0;
5753
5754 if ((status_rid->mode & 0x3f) == 0x3f && (cap_rid->hardCap & 8)) {
5755 if (memcmp(cap_rid->prodName, "350", 3))
5756 if (status_rid->signalQuality > 0x20)
5757 quality = 0;
5758 else
5759 quality = 0x20 - status_rid->signalQuality;
5760 else
5761 if (status_rid->signalQuality > 0xb0)
5762 quality = 0;
5763 else if (status_rid->signalQuality < 0x10)
5764 quality = 0xa0;
5765 else
5766 quality = 0xb0 - status_rid->signalQuality;
5767 }
5768 return quality;
5769}
5770
5771#define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0)
5772#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50);
5773
5774/*------------------------------------------------------------------*/
5775/*
5776 * Wireless Handler : get protocol name
5777 */
5778static int airo_get_name(struct net_device *dev,
5779 struct iw_request_info *info,
5780 char *cwrq,
5781 char *extra)
5782{
5783 strcpy(cwrq, "IEEE 802.11-DS");
5784 return 0;
5785}
5786
5787/*------------------------------------------------------------------*/
5788/*
5789 * Wireless Handler : set frequency
5790 */
5791static int airo_set_freq(struct net_device *dev,
5792 struct iw_request_info *info,
5793 struct iw_freq *fwrq,
5794 char *extra)
5795{
5796 struct airo_info *local = dev->priv;
5797 int rc = -EINPROGRESS; /* Call commit handler */
5798
5799 /* If setting by frequency, convert to a channel */
5800 if((fwrq->e == 1) &&
5801 (fwrq->m >= (int) 2.412e8) &&
5802 (fwrq->m <= (int) 2.487e8)) {
5803 int f = fwrq->m / 100000;
5804 int c = 0;
5805 while((c < 14) && (f != frequency_list[c]))
5806 c++;
5807 /* Hack to fall through... */
5808 fwrq->e = 0;
5809 fwrq->m = c + 1;
5810 }
5811 /* Setting by channel number */
5812 if((fwrq->m > 1000) || (fwrq->e > 0))
5813 rc = -EOPNOTSUPP;
5814 else {
5815 int channel = fwrq->m;
5816 /* We should do a better check than that,
5817 * based on the card capability !!! */
Javier Achirica2610c732006-01-17 08:01:01 -05005818 if((channel < 1) || (channel > 14)) {
Dan Williams934d8bf2006-03-16 13:46:23 -05005819 airo_print_dbg(dev->name, "New channel value of %d is invalid!",
5820 fwrq->m);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821 rc = -EINVAL;
5822 } else {
5823 readConfigRid(local, 1);
5824 /* Yes ! We can set it !!! */
Javier Achirica2610c732006-01-17 08:01:01 -05005825 local->config.channelSet = (u16) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826 set_bit (FLAG_COMMIT, &local->flags);
5827 }
5828 }
5829 return rc;
5830}
5831
5832/*------------------------------------------------------------------*/
5833/*
5834 * Wireless Handler : get frequency
5835 */
5836static int airo_get_freq(struct net_device *dev,
5837 struct iw_request_info *info,
5838 struct iw_freq *fwrq,
5839 char *extra)
5840{
5841 struct airo_info *local = dev->priv;
5842 StatusRid status_rid; /* Card status info */
Javier Achirica2610c732006-01-17 08:01:01 -05005843 int ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844
5845 readConfigRid(local, 1);
5846 if ((local->config.opmode & 0xFF) == MODE_STA_ESS)
5847 status_rid.channel = local->config.channelSet;
5848 else
5849 readStatusRid(local, &status_rid, 1);
5850
Javier Achirica2610c732006-01-17 08:01:01 -05005851 ch = (int)status_rid.channel;
5852 if((ch > 0) && (ch < 15)) {
5853 fwrq->m = frequency_list[ch - 1] * 100000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854 fwrq->e = 1;
Javier Achirica2610c732006-01-17 08:01:01 -05005855 } else {
5856 fwrq->m = ch;
5857 fwrq->e = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005859
5860 return 0;
5861}
5862
5863/*------------------------------------------------------------------*/
5864/*
5865 * Wireless Handler : set ESSID
5866 */
5867static int airo_set_essid(struct net_device *dev,
5868 struct iw_request_info *info,
5869 struct iw_point *dwrq,
5870 char *extra)
5871{
5872 struct airo_info *local = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873 SsidRid SSID_rid; /* SSIDs */
5874
5875 /* Reload the list of current SSID */
5876 readSsidRid(local, &SSID_rid);
5877
5878 /* Check if we asked for `any' */
5879 if(dwrq->flags == 0) {
5880 /* Just send an empty SSID list */
5881 memset(&SSID_rid, 0, sizeof(SSID_rid));
5882 } else {
5883 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
5884
5885 /* Check the size of the string */
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07005886 if(dwrq->length > IW_ESSID_MAX_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887 return -E2BIG ;
5888 }
5889 /* Check if index is valid */
5890 if((index < 0) || (index >= 4)) {
5891 return -EINVAL;
5892 }
5893
5894 /* Set the SSID */
5895 memset(SSID_rid.ssids[index].ssid, 0,
5896 sizeof(SSID_rid.ssids[index].ssid));
5897 memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07005898 SSID_rid.ssids[index].len = dwrq->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899 }
5900 SSID_rid.len = sizeof(SSID_rid);
5901 /* Write it to the card */
5902 disable_MAC(local, 1);
5903 writeSsidRid(local, &SSID_rid, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005904 enable_MAC(local, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005905
5906 return 0;
5907}
5908
5909/*------------------------------------------------------------------*/
5910/*
5911 * Wireless Handler : get ESSID
5912 */
5913static int airo_get_essid(struct net_device *dev,
5914 struct iw_request_info *info,
5915 struct iw_point *dwrq,
5916 char *extra)
5917{
5918 struct airo_info *local = dev->priv;
5919 StatusRid status_rid; /* Card status info */
5920
5921 readStatusRid(local, &status_rid, 1);
5922
5923 /* Note : if dwrq->flags != 0, we should
5924 * get the relevant SSID from the SSID list... */
5925
5926 /* Get the current SSID */
5927 memcpy(extra, status_rid.SSID, status_rid.SSIDlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928 /* If none, we may want to get the one that was set */
5929
5930 /* Push it out ! */
Dan Williamsd6a13a22006-01-12 15:00:58 -05005931 dwrq->length = status_rid.SSIDlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932 dwrq->flags = 1; /* active */
5933
5934 return 0;
5935}
5936
5937/*------------------------------------------------------------------*/
5938/*
5939 * Wireless Handler : set AP address
5940 */
5941static int airo_set_wap(struct net_device *dev,
5942 struct iw_request_info *info,
5943 struct sockaddr *awrq,
5944 char *extra)
5945{
5946 struct airo_info *local = dev->priv;
5947 Cmd cmd;
5948 Resp rsp;
5949 APListRid APList_rid;
Dan Williams4be757d2006-01-30 11:58:00 -05005950 static const u8 any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
5951 static const u8 off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952
5953 if (awrq->sa_family != ARPHRD_ETHER)
5954 return -EINVAL;
Dan Williams4be757d2006-01-30 11:58:00 -05005955 else if (!memcmp(any, awrq->sa_data, ETH_ALEN) ||
5956 !memcmp(off, awrq->sa_data, ETH_ALEN)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957 memset(&cmd, 0, sizeof(cmd));
5958 cmd.cmd=CMD_LOSE_SYNC;
5959 if (down_interruptible(&local->sem))
5960 return -ERESTARTSYS;
5961 issuecommand(local, &cmd, &rsp);
5962 up(&local->sem);
5963 } else {
5964 memset(&APList_rid, 0, sizeof(APList_rid));
5965 APList_rid.len = sizeof(APList_rid);
5966 memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN);
5967 disable_MAC(local, 1);
5968 writeAPListRid(local, &APList_rid, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005969 enable_MAC(local, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970 }
5971 return 0;
5972}
5973
5974/*------------------------------------------------------------------*/
5975/*
5976 * Wireless Handler : get AP address
5977 */
5978static int airo_get_wap(struct net_device *dev,
5979 struct iw_request_info *info,
5980 struct sockaddr *awrq,
5981 char *extra)
5982{
5983 struct airo_info *local = dev->priv;
5984 StatusRid status_rid; /* Card status info */
5985
5986 readStatusRid(local, &status_rid, 1);
5987
5988 /* Tentative. This seems to work, wow, I'm lucky !!! */
5989 memcpy(awrq->sa_data, status_rid.bssid[0], ETH_ALEN);
5990 awrq->sa_family = ARPHRD_ETHER;
5991
5992 return 0;
5993}
5994
5995/*------------------------------------------------------------------*/
5996/*
5997 * Wireless Handler : set Nickname
5998 */
5999static int airo_set_nick(struct net_device *dev,
6000 struct iw_request_info *info,
6001 struct iw_point *dwrq,
6002 char *extra)
6003{
6004 struct airo_info *local = dev->priv;
6005
6006 /* Check the size of the string */
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006007 if(dwrq->length > 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008 return -E2BIG;
6009 }
6010 readConfigRid(local, 1);
6011 memset(local->config.nodeName, 0, sizeof(local->config.nodeName));
6012 memcpy(local->config.nodeName, extra, dwrq->length);
6013 set_bit (FLAG_COMMIT, &local->flags);
6014
6015 return -EINPROGRESS; /* Call commit handler */
6016}
6017
6018/*------------------------------------------------------------------*/
6019/*
6020 * Wireless Handler : get Nickname
6021 */
6022static int airo_get_nick(struct net_device *dev,
6023 struct iw_request_info *info,
6024 struct iw_point *dwrq,
6025 char *extra)
6026{
6027 struct airo_info *local = dev->priv;
6028
6029 readConfigRid(local, 1);
6030 strncpy(extra, local->config.nodeName, 16);
6031 extra[16] = '\0';
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006032 dwrq->length = strlen(extra);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006033
6034 return 0;
6035}
6036
6037/*------------------------------------------------------------------*/
6038/*
6039 * Wireless Handler : set Bit-Rate
6040 */
6041static int airo_set_rate(struct net_device *dev,
6042 struct iw_request_info *info,
6043 struct iw_param *vwrq,
6044 char *extra)
6045{
6046 struct airo_info *local = dev->priv;
6047 CapabilityRid cap_rid; /* Card capability info */
6048 u8 brate = 0;
6049 int i;
6050
6051 /* First : get a valid bit rate value */
6052 readCapabilityRid(local, &cap_rid, 1);
6053
6054 /* Which type of value ? */
6055 if((vwrq->value < 8) && (vwrq->value >= 0)) {
6056 /* Setting by rate index */
6057 /* Find value in the magic rate table */
6058 brate = cap_rid.supportedRates[vwrq->value];
6059 } else {
6060 /* Setting by frequency value */
6061 u8 normvalue = (u8) (vwrq->value/500000);
6062
6063 /* Check if rate is valid */
6064 for(i = 0 ; i < 8 ; i++) {
6065 if(normvalue == cap_rid.supportedRates[i]) {
6066 brate = normvalue;
6067 break;
6068 }
6069 }
6070 }
6071 /* -1 designed the max rate (mostly auto mode) */
6072 if(vwrq->value == -1) {
6073 /* Get the highest available rate */
6074 for(i = 0 ; i < 8 ; i++) {
6075 if(cap_rid.supportedRates[i] == 0)
6076 break;
6077 }
6078 if(i != 0)
6079 brate = cap_rid.supportedRates[i - 1];
6080 }
6081 /* Check that it is valid */
6082 if(brate == 0) {
6083 return -EINVAL;
6084 }
6085
6086 readConfigRid(local, 1);
6087 /* Now, check if we want a fixed or auto value */
6088 if(vwrq->fixed == 0) {
6089 /* Fill all the rates up to this max rate */
6090 memset(local->config.rates, 0, 8);
6091 for(i = 0 ; i < 8 ; i++) {
6092 local->config.rates[i] = cap_rid.supportedRates[i];
6093 if(local->config.rates[i] == brate)
6094 break;
6095 }
6096 } else {
6097 /* Fixed mode */
6098 /* One rate, fixed */
6099 memset(local->config.rates, 0, 8);
6100 local->config.rates[0] = brate;
6101 }
6102 set_bit (FLAG_COMMIT, &local->flags);
6103
6104 return -EINPROGRESS; /* Call commit handler */
6105}
6106
6107/*------------------------------------------------------------------*/
6108/*
6109 * Wireless Handler : get Bit-Rate
6110 */
6111static int airo_get_rate(struct net_device *dev,
6112 struct iw_request_info *info,
6113 struct iw_param *vwrq,
6114 char *extra)
6115{
6116 struct airo_info *local = dev->priv;
6117 StatusRid status_rid; /* Card status info */
6118
6119 readStatusRid(local, &status_rid, 1);
6120
6121 vwrq->value = status_rid.currentXmitRate * 500000;
6122 /* If more than one rate, set auto */
6123 readConfigRid(local, 1);
6124 vwrq->fixed = (local->config.rates[1] == 0);
6125
6126 return 0;
6127}
6128
6129/*------------------------------------------------------------------*/
6130/*
6131 * Wireless Handler : set RTS threshold
6132 */
6133static int airo_set_rts(struct net_device *dev,
6134 struct iw_request_info *info,
6135 struct iw_param *vwrq,
6136 char *extra)
6137{
6138 struct airo_info *local = dev->priv;
6139 int rthr = vwrq->value;
6140
6141 if(vwrq->disabled)
Dan Williams15db2762006-03-16 13:46:27 -05006142 rthr = AIRO_DEF_MTU;
6143 if((rthr < 0) || (rthr > AIRO_DEF_MTU)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006144 return -EINVAL;
6145 }
6146 readConfigRid(local, 1);
6147 local->config.rtsThres = rthr;
6148 set_bit (FLAG_COMMIT, &local->flags);
6149
6150 return -EINPROGRESS; /* Call commit handler */
6151}
6152
6153/*------------------------------------------------------------------*/
6154/*
6155 * Wireless Handler : get RTS threshold
6156 */
6157static int airo_get_rts(struct net_device *dev,
6158 struct iw_request_info *info,
6159 struct iw_param *vwrq,
6160 char *extra)
6161{
6162 struct airo_info *local = dev->priv;
6163
6164 readConfigRid(local, 1);
6165 vwrq->value = local->config.rtsThres;
Dan Williams15db2762006-03-16 13:46:27 -05006166 vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006167 vwrq->fixed = 1;
6168
6169 return 0;
6170}
6171
6172/*------------------------------------------------------------------*/
6173/*
6174 * Wireless Handler : set Fragmentation threshold
6175 */
6176static int airo_set_frag(struct net_device *dev,
6177 struct iw_request_info *info,
6178 struct iw_param *vwrq,
6179 char *extra)
6180{
6181 struct airo_info *local = dev->priv;
6182 int fthr = vwrq->value;
6183
6184 if(vwrq->disabled)
Dan Williams15db2762006-03-16 13:46:27 -05006185 fthr = AIRO_DEF_MTU;
6186 if((fthr < 256) || (fthr > AIRO_DEF_MTU)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006187 return -EINVAL;
6188 }
6189 fthr &= ~0x1; /* Get an even value - is it really needed ??? */
6190 readConfigRid(local, 1);
6191 local->config.fragThresh = (u16)fthr;
6192 set_bit (FLAG_COMMIT, &local->flags);
6193
6194 return -EINPROGRESS; /* Call commit handler */
6195}
6196
6197/*------------------------------------------------------------------*/
6198/*
6199 * Wireless Handler : get Fragmentation threshold
6200 */
6201static int airo_get_frag(struct net_device *dev,
6202 struct iw_request_info *info,
6203 struct iw_param *vwrq,
6204 char *extra)
6205{
6206 struct airo_info *local = dev->priv;
6207
6208 readConfigRid(local, 1);
6209 vwrq->value = local->config.fragThresh;
Dan Williams15db2762006-03-16 13:46:27 -05006210 vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211 vwrq->fixed = 1;
6212
6213 return 0;
6214}
6215
6216/*------------------------------------------------------------------*/
6217/*
6218 * Wireless Handler : set Mode of Operation
6219 */
6220static int airo_set_mode(struct net_device *dev,
6221 struct iw_request_info *info,
6222 __u32 *uwrq,
6223 char *extra)
6224{
6225 struct airo_info *local = dev->priv;
6226 int reset = 0;
6227
6228 readConfigRid(local, 1);
6229 if ((local->config.rmode & 0xff) >= RXMODE_RFMON)
6230 reset = 1;
6231
6232 switch(*uwrq) {
6233 case IW_MODE_ADHOC:
6234 local->config.opmode &= 0xFF00;
6235 local->config.opmode |= MODE_STA_IBSS;
6236 local->config.rmode &= 0xfe00;
6237 local->config.scanMode = SCANMODE_ACTIVE;
6238 clear_bit (FLAG_802_11, &local->flags);
6239 break;
6240 case IW_MODE_INFRA:
6241 local->config.opmode &= 0xFF00;
6242 local->config.opmode |= MODE_STA_ESS;
6243 local->config.rmode &= 0xfe00;
6244 local->config.scanMode = SCANMODE_ACTIVE;
6245 clear_bit (FLAG_802_11, &local->flags);
6246 break;
6247 case IW_MODE_MASTER:
6248 local->config.opmode &= 0xFF00;
6249 local->config.opmode |= MODE_AP;
6250 local->config.rmode &= 0xfe00;
6251 local->config.scanMode = SCANMODE_ACTIVE;
6252 clear_bit (FLAG_802_11, &local->flags);
6253 break;
6254 case IW_MODE_REPEAT:
6255 local->config.opmode &= 0xFF00;
6256 local->config.opmode |= MODE_AP_RPTR;
6257 local->config.rmode &= 0xfe00;
6258 local->config.scanMode = SCANMODE_ACTIVE;
6259 clear_bit (FLAG_802_11, &local->flags);
6260 break;
6261 case IW_MODE_MONITOR:
6262 local->config.opmode &= 0xFF00;
6263 local->config.opmode |= MODE_STA_ESS;
6264 local->config.rmode &= 0xfe00;
6265 local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
6266 local->config.scanMode = SCANMODE_PASSIVE;
6267 set_bit (FLAG_802_11, &local->flags);
6268 break;
6269 default:
6270 return -EINVAL;
6271 }
6272 if (reset)
6273 set_bit (FLAG_RESET, &local->flags);
6274 set_bit (FLAG_COMMIT, &local->flags);
6275
6276 return -EINPROGRESS; /* Call commit handler */
6277}
6278
6279/*------------------------------------------------------------------*/
6280/*
6281 * Wireless Handler : get Mode of Operation
6282 */
6283static int airo_get_mode(struct net_device *dev,
6284 struct iw_request_info *info,
6285 __u32 *uwrq,
6286 char *extra)
6287{
6288 struct airo_info *local = dev->priv;
6289
6290 readConfigRid(local, 1);
6291 /* If not managed, assume it's ad-hoc */
6292 switch (local->config.opmode & 0xFF) {
6293 case MODE_STA_ESS:
6294 *uwrq = IW_MODE_INFRA;
6295 break;
6296 case MODE_AP:
6297 *uwrq = IW_MODE_MASTER;
6298 break;
6299 case MODE_AP_RPTR:
6300 *uwrq = IW_MODE_REPEAT;
6301 break;
6302 default:
6303 *uwrq = IW_MODE_ADHOC;
6304 }
6305
6306 return 0;
6307}
6308
6309/*------------------------------------------------------------------*/
6310/*
6311 * Wireless Handler : set Encryption Key
6312 */
6313static int airo_set_encode(struct net_device *dev,
6314 struct iw_request_info *info,
6315 struct iw_point *dwrq,
6316 char *extra)
6317{
6318 struct airo_info *local = dev->priv;
6319 CapabilityRid cap_rid; /* Card capability info */
Dan Streetmanf89b2322005-11-11 11:41:42 -05006320 int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 );
6321 u16 currentAuthType = local->config.authType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006322
6323 /* Is WEP supported ? */
6324 readCapabilityRid(local, &cap_rid, 1);
6325 /* Older firmware doesn't support this...
6326 if(!(cap_rid.softCap & 2)) {
6327 return -EOPNOTSUPP;
6328 } */
6329 readConfigRid(local, 1);
6330
6331 /* Basic checking: do we have a key to set ?
6332 * Note : with the new API, it's impossible to get a NULL pointer.
6333 * Therefore, we need to check a key size == 0 instead.
6334 * New version of iwconfig properly set the IW_ENCODE_NOKEY flag
6335 * when no key is present (only change flags), but older versions
6336 * don't do it. - Jean II */
6337 if (dwrq->length > 0) {
6338 wep_key_t key;
6339 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
6340 int current_index = get_wep_key(local, 0xffff);
6341 /* Check the size of the key */
6342 if (dwrq->length > MAX_KEY_SIZE) {
6343 return -EINVAL;
6344 }
6345 /* Check the index (none -> use current) */
6346 if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4:1)))
6347 index = current_index;
6348 /* Set the length */
6349 if (dwrq->length > MIN_KEY_SIZE)
6350 key.len = MAX_KEY_SIZE;
6351 else
6352 if (dwrq->length > 0)
6353 key.len = MIN_KEY_SIZE;
6354 else
6355 /* Disable the key */
6356 key.len = 0;
6357 /* Check if the key is not marked as invalid */
6358 if(!(dwrq->flags & IW_ENCODE_NOKEY)) {
6359 /* Cleanup */
6360 memset(key.key, 0, MAX_KEY_SIZE);
6361 /* Copy the key in the driver */
6362 memcpy(key.key, extra, dwrq->length);
6363 /* Send the key to the card */
Dan Streetmanf89b2322005-11-11 11:41:42 -05006364 set_wep_key(local, index, key.key, key.len, perm, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006365 }
6366 /* WE specify that if a valid key is set, encryption
6367 * should be enabled (user may turn it off later)
6368 * This is also how "iwconfig ethX key on" works */
6369 if((index == current_index) && (key.len > 0) &&
6370 (local->config.authType == AUTH_OPEN)) {
6371 local->config.authType = AUTH_ENCRYPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006372 }
6373 } else {
6374 /* Do we want to just set the transmit key index ? */
6375 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
6376 if ((index >= 0) && (index < ((cap_rid.softCap & 0x80)?4:1))) {
Dan Streetmanf89b2322005-11-11 11:41:42 -05006377 set_wep_key(local, index, NULL, 0, perm, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378 } else
6379 /* Don't complain if only change the mode */
Jeff Garzik93a3b602007-11-23 21:50:20 -05006380 if (!(dwrq->flags & IW_ENCODE_MODE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07006381 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006382 }
6383 /* Read the flags */
6384 if(dwrq->flags & IW_ENCODE_DISABLED)
6385 local->config.authType = AUTH_OPEN; // disable encryption
6386 if(dwrq->flags & IW_ENCODE_RESTRICTED)
6387 local->config.authType = AUTH_SHAREDKEY; // Only Both
6388 if(dwrq->flags & IW_ENCODE_OPEN)
6389 local->config.authType = AUTH_ENCRYPT; // Only Wep
6390 /* Commit the changes to flags if needed */
Dan Streetmanf89b2322005-11-11 11:41:42 -05006391 if (local->config.authType != currentAuthType)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006392 set_bit (FLAG_COMMIT, &local->flags);
6393 return -EINPROGRESS; /* Call commit handler */
6394}
6395
6396/*------------------------------------------------------------------*/
6397/*
6398 * Wireless Handler : get Encryption Key
6399 */
6400static int airo_get_encode(struct net_device *dev,
6401 struct iw_request_info *info,
6402 struct iw_point *dwrq,
6403 char *extra)
6404{
6405 struct airo_info *local = dev->priv;
6406 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
6407 CapabilityRid cap_rid; /* Card capability info */
6408
6409 /* Is it supported ? */
6410 readCapabilityRid(local, &cap_rid, 1);
6411 if(!(cap_rid.softCap & 2)) {
6412 return -EOPNOTSUPP;
6413 }
6414 readConfigRid(local, 1);
6415 /* Check encryption mode */
6416 switch(local->config.authType) {
6417 case AUTH_ENCRYPT:
6418 dwrq->flags = IW_ENCODE_OPEN;
6419 break;
6420 case AUTH_SHAREDKEY:
6421 dwrq->flags = IW_ENCODE_RESTRICTED;
6422 break;
6423 default:
6424 case AUTH_OPEN:
6425 dwrq->flags = IW_ENCODE_DISABLED;
6426 break;
6427 }
6428 /* We can't return the key, so set the proper flag and return zero */
6429 dwrq->flags |= IW_ENCODE_NOKEY;
6430 memset(extra, 0, 16);
6431
6432 /* Which key do we want ? -1 -> tx index */
6433 if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4 : 1)))
6434 index = get_wep_key(local, 0xffff);
6435 dwrq->flags |= index + 1;
6436 /* Copy the key to the user buffer */
6437 dwrq->length = get_wep_key(local, index);
6438 if (dwrq->length > 16) {
6439 dwrq->length=0;
6440 }
6441 return 0;
6442}
6443
6444/*------------------------------------------------------------------*/
6445/*
Dan Williams4be757d2006-01-30 11:58:00 -05006446 * Wireless Handler : set extended Encryption parameters
6447 */
6448static int airo_set_encodeext(struct net_device *dev,
6449 struct iw_request_info *info,
6450 union iwreq_data *wrqu,
6451 char *extra)
6452{
6453 struct airo_info *local = dev->priv;
6454 struct iw_point *encoding = &wrqu->encoding;
6455 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
6456 CapabilityRid cap_rid; /* Card capability info */
6457 int perm = ( encoding->flags & IW_ENCODE_TEMP ? 0 : 1 );
6458 u16 currentAuthType = local->config.authType;
Dan Williams22d88462006-02-05 18:00:30 -05006459 int idx, key_len, alg = ext->alg, set_key = 1;
Dan Williams4be757d2006-01-30 11:58:00 -05006460 wep_key_t key;
6461
6462 /* Is WEP supported ? */
6463 readCapabilityRid(local, &cap_rid, 1);
6464 /* Older firmware doesn't support this...
6465 if(!(cap_rid.softCap & 2)) {
6466 return -EOPNOTSUPP;
6467 } */
6468 readConfigRid(local, 1);
6469
6470 /* Determine and validate the key index */
6471 idx = encoding->flags & IW_ENCODE_INDEX;
6472 if (idx) {
6473 if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1))
6474 return -EINVAL;
6475 idx--;
6476 } else
6477 idx = get_wep_key(local, 0xffff);
6478
6479 if (encoding->flags & IW_ENCODE_DISABLED)
6480 alg = IW_ENCODE_ALG_NONE;
6481
Dan Williams4be757d2006-01-30 11:58:00 -05006482 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
Dan Williams22d88462006-02-05 18:00:30 -05006483 /* Only set transmit key index here, actual
6484 * key is set below if needed.
6485 */
Dan Williams4be757d2006-01-30 11:58:00 -05006486 set_wep_key(local, idx, NULL, 0, perm, 1);
Dan Williams22d88462006-02-05 18:00:30 -05006487 set_key = ext->key_len > 0 ? 1 : 0;
6488 }
6489
6490 if (set_key) {
Dan Williams4be757d2006-01-30 11:58:00 -05006491 /* Set the requested key first */
6492 memset(key.key, 0, MAX_KEY_SIZE);
6493 switch (alg) {
6494 case IW_ENCODE_ALG_NONE:
6495 key.len = 0;
6496 break;
6497 case IW_ENCODE_ALG_WEP:
6498 if (ext->key_len > MIN_KEY_SIZE) {
6499 key.len = MAX_KEY_SIZE;
6500 } else if (ext->key_len > 0) {
6501 key.len = MIN_KEY_SIZE;
6502 } else {
6503 return -EINVAL;
6504 }
6505 key_len = min (ext->key_len, key.len);
6506 memcpy(key.key, ext->key, key_len);
6507 break;
6508 default:
6509 return -EINVAL;
6510 }
6511 /* Send the key to the card */
6512 set_wep_key(local, idx, key.key, key.len, perm, 1);
6513 }
6514
6515 /* Read the flags */
6516 if(encoding->flags & IW_ENCODE_DISABLED)
6517 local->config.authType = AUTH_OPEN; // disable encryption
6518 if(encoding->flags & IW_ENCODE_RESTRICTED)
6519 local->config.authType = AUTH_SHAREDKEY; // Only Both
6520 if(encoding->flags & IW_ENCODE_OPEN)
6521 local->config.authType = AUTH_ENCRYPT; // Only Wep
6522 /* Commit the changes to flags if needed */
6523 if (local->config.authType != currentAuthType)
6524 set_bit (FLAG_COMMIT, &local->flags);
6525
6526 return -EINPROGRESS;
6527}
6528
6529
6530/*------------------------------------------------------------------*/
6531/*
6532 * Wireless Handler : get extended Encryption parameters
6533 */
6534static int airo_get_encodeext(struct net_device *dev,
6535 struct iw_request_info *info,
6536 union iwreq_data *wrqu,
6537 char *extra)
6538{
6539 struct airo_info *local = dev->priv;
6540 struct iw_point *encoding = &wrqu->encoding;
6541 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
6542 CapabilityRid cap_rid; /* Card capability info */
6543 int idx, max_key_len;
6544
6545 /* Is it supported ? */
6546 readCapabilityRid(local, &cap_rid, 1);
6547 if(!(cap_rid.softCap & 2)) {
6548 return -EOPNOTSUPP;
6549 }
6550 readConfigRid(local, 1);
6551
6552 max_key_len = encoding->length - sizeof(*ext);
6553 if (max_key_len < 0)
6554 return -EINVAL;
6555
6556 idx = encoding->flags & IW_ENCODE_INDEX;
6557 if (idx) {
6558 if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1))
6559 return -EINVAL;
6560 idx--;
6561 } else
6562 idx = get_wep_key(local, 0xffff);
6563
6564 encoding->flags = idx + 1;
6565 memset(ext, 0, sizeof(*ext));
6566
6567 /* Check encryption mode */
6568 switch(local->config.authType) {
6569 case AUTH_ENCRYPT:
6570 encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
6571 break;
6572 case AUTH_SHAREDKEY:
6573 encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
6574 break;
6575 default:
6576 case AUTH_OPEN:
6577 encoding->flags = IW_ENCODE_ALG_NONE | IW_ENCODE_DISABLED;
6578 break;
6579 }
6580 /* We can't return the key, so set the proper flag and return zero */
6581 encoding->flags |= IW_ENCODE_NOKEY;
6582 memset(extra, 0, 16);
6583
6584 /* Copy the key to the user buffer */
6585 ext->key_len = get_wep_key(local, idx);
6586 if (ext->key_len > 16) {
6587 ext->key_len=0;
6588 }
6589
6590 return 0;
6591}
6592
6593
6594/*------------------------------------------------------------------*/
6595/*
6596 * Wireless Handler : set extended authentication parameters
6597 */
6598static int airo_set_auth(struct net_device *dev,
6599 struct iw_request_info *info,
6600 union iwreq_data *wrqu, char *extra)
6601{
6602 struct airo_info *local = dev->priv;
6603 struct iw_param *param = &wrqu->param;
6604 u16 currentAuthType = local->config.authType;
6605
6606 switch (param->flags & IW_AUTH_INDEX) {
6607 case IW_AUTH_WPA_VERSION:
6608 case IW_AUTH_CIPHER_PAIRWISE:
6609 case IW_AUTH_CIPHER_GROUP:
6610 case IW_AUTH_KEY_MGMT:
6611 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
6612 case IW_AUTH_PRIVACY_INVOKED:
6613 /*
6614 * airo does not use these parameters
6615 */
6616 break;
6617
6618 case IW_AUTH_DROP_UNENCRYPTED:
6619 if (param->value) {
6620 /* Only change auth type if unencrypted */
6621 if (currentAuthType == AUTH_OPEN)
6622 local->config.authType = AUTH_ENCRYPT;
6623 } else {
6624 local->config.authType = AUTH_OPEN;
6625 }
6626
6627 /* Commit the changes to flags if needed */
6628 if (local->config.authType != currentAuthType)
6629 set_bit (FLAG_COMMIT, &local->flags);
6630 break;
6631
6632 case IW_AUTH_80211_AUTH_ALG: {
6633 /* FIXME: What about AUTH_OPEN? This API seems to
6634 * disallow setting our auth to AUTH_OPEN.
6635 */
6636 if (param->value & IW_AUTH_ALG_SHARED_KEY) {
6637 local->config.authType = AUTH_SHAREDKEY;
6638 } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
6639 local->config.authType = AUTH_ENCRYPT;
6640 } else
6641 return -EINVAL;
6642 break;
6643
6644 /* Commit the changes to flags if needed */
6645 if (local->config.authType != currentAuthType)
6646 set_bit (FLAG_COMMIT, &local->flags);
6647 }
6648
6649 case IW_AUTH_WPA_ENABLED:
6650 /* Silently accept disable of WPA */
6651 if (param->value > 0)
6652 return -EOPNOTSUPP;
6653 break;
6654
6655 default:
6656 return -EOPNOTSUPP;
6657 }
6658 return -EINPROGRESS;
6659}
6660
6661
6662/*------------------------------------------------------------------*/
6663/*
6664 * Wireless Handler : get extended authentication parameters
6665 */
6666static int airo_get_auth(struct net_device *dev,
6667 struct iw_request_info *info,
6668 union iwreq_data *wrqu, char *extra)
6669{
6670 struct airo_info *local = dev->priv;
6671 struct iw_param *param = &wrqu->param;
6672 u16 currentAuthType = local->config.authType;
6673
6674 switch (param->flags & IW_AUTH_INDEX) {
6675 case IW_AUTH_DROP_UNENCRYPTED:
6676 switch (currentAuthType) {
6677 case AUTH_SHAREDKEY:
6678 case AUTH_ENCRYPT:
6679 param->value = 1;
6680 break;
6681 default:
6682 param->value = 0;
6683 break;
6684 }
6685 break;
6686
6687 case IW_AUTH_80211_AUTH_ALG:
6688 switch (currentAuthType) {
6689 case AUTH_SHAREDKEY:
6690 param->value = IW_AUTH_ALG_SHARED_KEY;
6691 break;
6692 case AUTH_ENCRYPT:
6693 default:
6694 param->value = IW_AUTH_ALG_OPEN_SYSTEM;
6695 break;
6696 }
6697 break;
6698
6699 case IW_AUTH_WPA_ENABLED:
6700 param->value = 0;
6701 break;
6702
6703 default:
6704 return -EOPNOTSUPP;
6705 }
6706 return 0;
6707}
6708
6709
6710/*------------------------------------------------------------------*/
6711/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006712 * Wireless Handler : set Tx-Power
6713 */
6714static int airo_set_txpow(struct net_device *dev,
6715 struct iw_request_info *info,
6716 struct iw_param *vwrq,
6717 char *extra)
6718{
6719 struct airo_info *local = dev->priv;
6720 CapabilityRid cap_rid; /* Card capability info */
6721 int i;
6722 int rc = -EINVAL;
6723
6724 readCapabilityRid(local, &cap_rid, 1);
6725
6726 if (vwrq->disabled) {
6727 set_bit (FLAG_RADIO_OFF, &local->flags);
6728 set_bit (FLAG_COMMIT, &local->flags);
6729 return -EINPROGRESS; /* Call commit handler */
6730 }
6731 if (vwrq->flags != IW_TXPOW_MWATT) {
6732 return -EINVAL;
6733 }
6734 clear_bit (FLAG_RADIO_OFF, &local->flags);
6735 for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
6736 if ((vwrq->value==cap_rid.txPowerLevels[i])) {
6737 readConfigRid(local, 1);
6738 local->config.txPower = vwrq->value;
6739 set_bit (FLAG_COMMIT, &local->flags);
6740 rc = -EINPROGRESS; /* Call commit handler */
6741 break;
6742 }
6743 return rc;
6744}
6745
6746/*------------------------------------------------------------------*/
6747/*
6748 * Wireless Handler : get Tx-Power
6749 */
6750static int airo_get_txpow(struct net_device *dev,
6751 struct iw_request_info *info,
6752 struct iw_param *vwrq,
6753 char *extra)
6754{
6755 struct airo_info *local = dev->priv;
6756
6757 readConfigRid(local, 1);
6758 vwrq->value = local->config.txPower;
6759 vwrq->fixed = 1; /* No power control */
6760 vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags);
6761 vwrq->flags = IW_TXPOW_MWATT;
6762
6763 return 0;
6764}
6765
6766/*------------------------------------------------------------------*/
6767/*
6768 * Wireless Handler : set Retry limits
6769 */
6770static int airo_set_retry(struct net_device *dev,
6771 struct iw_request_info *info,
6772 struct iw_param *vwrq,
6773 char *extra)
6774{
6775 struct airo_info *local = dev->priv;
6776 int rc = -EINVAL;
6777
6778 if(vwrq->disabled) {
6779 return -EINVAL;
6780 }
6781 readConfigRid(local, 1);
6782 if(vwrq->flags & IW_RETRY_LIMIT) {
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006783 if(vwrq->flags & IW_RETRY_LONG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006784 local->config.longRetryLimit = vwrq->value;
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006785 else if (vwrq->flags & IW_RETRY_SHORT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006786 local->config.shortRetryLimit = vwrq->value;
6787 else {
6788 /* No modifier : set both */
6789 local->config.longRetryLimit = vwrq->value;
6790 local->config.shortRetryLimit = vwrq->value;
6791 }
6792 set_bit (FLAG_COMMIT, &local->flags);
6793 rc = -EINPROGRESS; /* Call commit handler */
6794 }
6795 if(vwrq->flags & IW_RETRY_LIFETIME) {
6796 local->config.txLifetime = vwrq->value / 1024;
6797 set_bit (FLAG_COMMIT, &local->flags);
6798 rc = -EINPROGRESS; /* Call commit handler */
6799 }
6800 return rc;
6801}
6802
6803/*------------------------------------------------------------------*/
6804/*
6805 * Wireless Handler : get Retry limits
6806 */
6807static int airo_get_retry(struct net_device *dev,
6808 struct iw_request_info *info,
6809 struct iw_param *vwrq,
6810 char *extra)
6811{
6812 struct airo_info *local = dev->priv;
6813
6814 vwrq->disabled = 0; /* Can't be disabled */
6815
6816 readConfigRid(local, 1);
6817 /* Note : by default, display the min retry number */
6818 if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
6819 vwrq->flags = IW_RETRY_LIFETIME;
6820 vwrq->value = (int)local->config.txLifetime * 1024;
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006821 } else if((vwrq->flags & IW_RETRY_LONG)) {
6822 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006823 vwrq->value = (int)local->config.longRetryLimit;
6824 } else {
6825 vwrq->flags = IW_RETRY_LIMIT;
6826 vwrq->value = (int)local->config.shortRetryLimit;
6827 if((int)local->config.shortRetryLimit != (int)local->config.longRetryLimit)
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006828 vwrq->flags |= IW_RETRY_SHORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006829 }
6830
6831 return 0;
6832}
6833
6834/*------------------------------------------------------------------*/
6835/*
6836 * Wireless Handler : get range info
6837 */
6838static int airo_get_range(struct net_device *dev,
6839 struct iw_request_info *info,
6840 struct iw_point *dwrq,
6841 char *extra)
6842{
6843 struct airo_info *local = dev->priv;
6844 struct iw_range *range = (struct iw_range *) extra;
6845 CapabilityRid cap_rid; /* Card capability info */
6846 int i;
6847 int k;
6848
6849 readCapabilityRid(local, &cap_rid, 1);
6850
6851 dwrq->length = sizeof(struct iw_range);
6852 memset(range, 0, sizeof(*range));
6853 range->min_nwid = 0x0000;
6854 range->max_nwid = 0x0000;
6855 range->num_channels = 14;
6856 /* Should be based on cap_rid.country to give only
6857 * what the current card support */
6858 k = 0;
6859 for(i = 0; i < 14; i++) {
6860 range->freq[k].i = i + 1; /* List index */
6861 range->freq[k].m = frequency_list[i] * 100000;
6862 range->freq[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */
6863 }
6864 range->num_frequency = k;
6865
Linus Torvalds1da177e2005-04-16 15:20:36 -07006866 range->sensitivity = 65535;
6867
Dan Williams41480af2005-05-10 09:45:51 -04006868 /* Hum... Should put the right values there */
6869 if (local->rssi)
6870 range->max_qual.qual = 100; /* % */
6871 else
6872 range->max_qual.qual = airo_get_max_quality(&cap_rid);
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006873 range->max_qual.level = 0x100 - 120; /* -120 dBm */
6874 range->max_qual.noise = 0x100 - 120; /* -120 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006875
6876 /* Experimental measurements - boundary 11/5.5 Mb/s */
6877 /* Note : with or without the (local->rssi), results
6878 * are somewhat different. - Jean II */
6879 if (local->rssi) {
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006880 range->avg_qual.qual = 50; /* % */
6881 range->avg_qual.level = 0x100 - 70; /* -70 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006882 } else {
6883 range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006884 range->avg_qual.level = 0x100 - 80; /* -80 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006885 }
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006886 range->avg_qual.noise = 0x100 - 85; /* -85 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006887
Linus Torvalds1da177e2005-04-16 15:20:36 -07006888 for(i = 0 ; i < 8 ; i++) {
6889 range->bitrate[i] = cap_rid.supportedRates[i] * 500000;
6890 if(range->bitrate[i] == 0)
6891 break;
6892 }
6893 range->num_bitrates = i;
6894
6895 /* Set an indication of the max TCP throughput
6896 * in bit/s that we can expect using this interface.
6897 * May be use for QoS stuff... Jean II */
6898 if(i > 2)
6899 range->throughput = 5000 * 1000;
6900 else
6901 range->throughput = 1500 * 1000;
6902
6903 range->min_rts = 0;
Dan Williams15db2762006-03-16 13:46:27 -05006904 range->max_rts = AIRO_DEF_MTU;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006905 range->min_frag = 256;
Dan Williams15db2762006-03-16 13:46:27 -05006906 range->max_frag = AIRO_DEF_MTU;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006907
6908 if(cap_rid.softCap & 2) {
6909 // WEP: RC4 40 bits
6910 range->encoding_size[0] = 5;
6911 // RC4 ~128 bits
6912 if (cap_rid.softCap & 0x100) {
6913 range->encoding_size[1] = 13;
6914 range->num_encoding_sizes = 2;
6915 } else
6916 range->num_encoding_sizes = 1;
6917 range->max_encoding_tokens = (cap_rid.softCap & 0x80) ? 4 : 1;
6918 } else {
6919 range->num_encoding_sizes = 0;
6920 range->max_encoding_tokens = 0;
6921 }
6922 range->min_pmp = 0;
6923 range->max_pmp = 5000000; /* 5 secs */
6924 range->min_pmt = 0;
6925 range->max_pmt = 65535 * 1024; /* ??? */
6926 range->pmp_flags = IW_POWER_PERIOD;
6927 range->pmt_flags = IW_POWER_TIMEOUT;
6928 range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
6929
6930 /* Transmit Power - values are in mW */
6931 for(i = 0 ; i < 8 ; i++) {
6932 range->txpower[i] = cap_rid.txPowerLevels[i];
6933 if(range->txpower[i] == 0)
6934 break;
6935 }
6936 range->num_txpower = i;
6937 range->txpower_capa = IW_TXPOW_MWATT;
Dan Williams3c304952006-04-15 12:26:18 -04006938 range->we_version_source = 19;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006939 range->we_version_compiled = WIRELESS_EXT;
6940 range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
6941 range->retry_flags = IW_RETRY_LIMIT;
6942 range->r_time_flags = IW_RETRY_LIFETIME;
6943 range->min_retry = 1;
6944 range->max_retry = 65535;
6945 range->min_r_time = 1024;
6946 range->max_r_time = 65535 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006947
6948 /* Event capability (kernel + driver) */
6949 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
6950 IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
6951 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
6952 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
6953 range->event_capa[1] = IW_EVENT_CAPA_K_1;
6954 range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVTXDROP);
6955 return 0;
6956}
6957
6958/*------------------------------------------------------------------*/
6959/*
6960 * Wireless Handler : set Power Management
6961 */
6962static int airo_set_power(struct net_device *dev,
6963 struct iw_request_info *info,
6964 struct iw_param *vwrq,
6965 char *extra)
6966{
6967 struct airo_info *local = dev->priv;
6968
6969 readConfigRid(local, 1);
6970 if (vwrq->disabled) {
6971 if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
6972 return -EINVAL;
6973 }
6974 local->config.powerSaveMode = POWERSAVE_CAM;
6975 local->config.rmode &= 0xFF00;
6976 local->config.rmode |= RXMODE_BC_MC_ADDR;
6977 set_bit (FLAG_COMMIT, &local->flags);
6978 return -EINPROGRESS; /* Call commit handler */
6979 }
6980 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
6981 local->config.fastListenDelay = (vwrq->value + 500) / 1024;
6982 local->config.powerSaveMode = POWERSAVE_PSPCAM;
6983 set_bit (FLAG_COMMIT, &local->flags);
6984 } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
6985 local->config.fastListenInterval = local->config.listenInterval = (vwrq->value + 500) / 1024;
6986 local->config.powerSaveMode = POWERSAVE_PSPCAM;
6987 set_bit (FLAG_COMMIT, &local->flags);
6988 }
6989 switch (vwrq->flags & IW_POWER_MODE) {
6990 case IW_POWER_UNICAST_R:
6991 if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
6992 return -EINVAL;
6993 }
6994 local->config.rmode &= 0xFF00;
6995 local->config.rmode |= RXMODE_ADDR;
6996 set_bit (FLAG_COMMIT, &local->flags);
6997 break;
6998 case IW_POWER_ALL_R:
6999 if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
7000 return -EINVAL;
7001 }
7002 local->config.rmode &= 0xFF00;
7003 local->config.rmode |= RXMODE_BC_MC_ADDR;
7004 set_bit (FLAG_COMMIT, &local->flags);
7005 case IW_POWER_ON:
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07007006 /* This is broken, fixme ;-) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007007 break;
7008 default:
7009 return -EINVAL;
7010 }
7011 // Note : we may want to factor local->need_commit here
7012 // Note2 : may also want to factor RXMODE_RFMON test
7013 return -EINPROGRESS; /* Call commit handler */
7014}
7015
7016/*------------------------------------------------------------------*/
7017/*
7018 * Wireless Handler : get Power Management
7019 */
7020static int airo_get_power(struct net_device *dev,
7021 struct iw_request_info *info,
7022 struct iw_param *vwrq,
7023 char *extra)
7024{
7025 struct airo_info *local = dev->priv;
7026 int mode;
7027
7028 readConfigRid(local, 1);
7029 mode = local->config.powerSaveMode;
7030 if ((vwrq->disabled = (mode == POWERSAVE_CAM)))
7031 return 0;
7032 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
7033 vwrq->value = (int)local->config.fastListenDelay * 1024;
7034 vwrq->flags = IW_POWER_TIMEOUT;
7035 } else {
7036 vwrq->value = (int)local->config.fastListenInterval * 1024;
7037 vwrq->flags = IW_POWER_PERIOD;
7038 }
7039 if ((local->config.rmode & 0xFF) == RXMODE_ADDR)
7040 vwrq->flags |= IW_POWER_UNICAST_R;
7041 else
7042 vwrq->flags |= IW_POWER_ALL_R;
7043
7044 return 0;
7045}
7046
7047/*------------------------------------------------------------------*/
7048/*
7049 * Wireless Handler : set Sensitivity
7050 */
7051static int airo_set_sens(struct net_device *dev,
7052 struct iw_request_info *info,
7053 struct iw_param *vwrq,
7054 char *extra)
7055{
7056 struct airo_info *local = dev->priv;
7057
7058 readConfigRid(local, 1);
7059 local->config.rssiThreshold = vwrq->disabled ? RSSI_DEFAULT : vwrq->value;
7060 set_bit (FLAG_COMMIT, &local->flags);
7061
7062 return -EINPROGRESS; /* Call commit handler */
7063}
7064
7065/*------------------------------------------------------------------*/
7066/*
7067 * Wireless Handler : get Sensitivity
7068 */
7069static int airo_get_sens(struct net_device *dev,
7070 struct iw_request_info *info,
7071 struct iw_param *vwrq,
7072 char *extra)
7073{
7074 struct airo_info *local = dev->priv;
7075
7076 readConfigRid(local, 1);
7077 vwrq->value = local->config.rssiThreshold;
7078 vwrq->disabled = (vwrq->value == 0);
7079 vwrq->fixed = 1;
7080
7081 return 0;
7082}
7083
7084/*------------------------------------------------------------------*/
7085/*
7086 * Wireless Handler : get AP List
7087 * Note : this is deprecated in favor of IWSCAN
7088 */
7089static int airo_get_aplist(struct net_device *dev,
7090 struct iw_request_info *info,
7091 struct iw_point *dwrq,
7092 char *extra)
7093{
7094 struct airo_info *local = dev->priv;
7095 struct sockaddr *address = (struct sockaddr *) extra;
7096 struct iw_quality qual[IW_MAX_AP];
7097 BSSListRid BSSList;
7098 int i;
7099 int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
7100
7101 for (i = 0; i < IW_MAX_AP; i++) {
7102 if (readBSSListRid(local, loseSync, &BSSList))
7103 break;
7104 loseSync = 0;
7105 memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN);
7106 address[i].sa_family = ARPHRD_ETHER;
Dan Williams41480af2005-05-10 09:45:51 -04007107 if (local->rssi) {
7108 qual[i].level = 0x100 - BSSList.dBm;
7109 qual[i].qual = airo_dbm_to_pct( local->rssi, BSSList.dBm );
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007110 qual[i].updated = IW_QUAL_QUAL_UPDATED
7111 | IW_QUAL_LEVEL_UPDATED
7112 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04007113 } else {
7114 qual[i].level = (BSSList.dBm + 321) / 2;
7115 qual[i].qual = 0;
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007116 qual[i].updated = IW_QUAL_QUAL_INVALID
7117 | IW_QUAL_LEVEL_UPDATED
7118 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04007119 }
7120 qual[i].noise = local->wstats.qual.noise;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007121 if (BSSList.index == 0xffff)
7122 break;
7123 }
7124 if (!i) {
7125 StatusRid status_rid; /* Card status info */
7126 readStatusRid(local, &status_rid, 1);
7127 for (i = 0;
7128 i < min(IW_MAX_AP, 4) &&
7129 (status_rid.bssid[i][0]
7130 & status_rid.bssid[i][1]
7131 & status_rid.bssid[i][2]
7132 & status_rid.bssid[i][3]
7133 & status_rid.bssid[i][4]
7134 & status_rid.bssid[i][5])!=0xff &&
7135 (status_rid.bssid[i][0]
7136 | status_rid.bssid[i][1]
7137 | status_rid.bssid[i][2]
7138 | status_rid.bssid[i][3]
7139 | status_rid.bssid[i][4]
7140 | status_rid.bssid[i][5]);
7141 i++) {
7142 memcpy(address[i].sa_data,
7143 status_rid.bssid[i], ETH_ALEN);
7144 address[i].sa_family = ARPHRD_ETHER;
7145 }
7146 } else {
7147 dwrq->flags = 1; /* Should be define'd */
7148 memcpy(extra + sizeof(struct sockaddr)*i,
7149 &qual, sizeof(struct iw_quality)*i);
7150 }
7151 dwrq->length = i;
7152
7153 return 0;
7154}
7155
7156/*------------------------------------------------------------------*/
7157/*
7158 * Wireless Handler : Initiate Scan
7159 */
7160static int airo_set_scan(struct net_device *dev,
7161 struct iw_request_info *info,
7162 struct iw_param *vwrq,
7163 char *extra)
7164{
7165 struct airo_info *ai = dev->priv;
7166 Cmd cmd;
7167 Resp rsp;
Dan Williams9e75af32006-03-16 13:46:29 -05007168 int wake = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007169
7170 /* Note : you may have realised that, as this is a SET operation,
7171 * this is privileged and therefore a normal user can't
7172 * perform scanning.
7173 * This is not an error, while the device perform scanning,
7174 * traffic doesn't flow, so it's a perfect DoS...
7175 * Jean II */
7176 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
7177
Dan Williams9e75af32006-03-16 13:46:29 -05007178 if (down_interruptible(&ai->sem))
7179 return -ERESTARTSYS;
7180
7181 /* If there's already a scan in progress, don't
7182 * trigger another one. */
7183 if (ai->scan_timeout > 0)
7184 goto out;
7185
Linus Torvalds1da177e2005-04-16 15:20:36 -07007186 /* Initiate a scan command */
Dan Williams6fcdf562006-03-31 15:08:46 -05007187 ai->scan_timeout = RUN_AT(3*HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007188 memset(&cmd, 0, sizeof(cmd));
7189 cmd.cmd=CMD_LISTBSS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007190 issuecommand(ai, &cmd, &rsp);
Dan Williams9e75af32006-03-16 13:46:29 -05007191 wake = 1;
7192
7193out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07007194 up(&ai->sem);
Dan Williams9e75af32006-03-16 13:46:29 -05007195 if (wake)
7196 wake_up_interruptible(&ai->thr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007197 return 0;
7198}
7199
7200/*------------------------------------------------------------------*/
7201/*
7202 * Translate scan data returned from the card to a card independent
7203 * format that the Wireless Tools will understand - Jean II
7204 */
7205static inline char *airo_translate_scan(struct net_device *dev,
7206 char *current_ev,
7207 char *end_buf,
Dan Williams41480af2005-05-10 09:45:51 -04007208 BSSListRid *bss)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007209{
7210 struct airo_info *ai = dev->priv;
7211 struct iw_event iwe; /* Temporary buffer */
7212 u16 capabilities;
7213 char * current_val; /* For rates */
7214 int i;
Dan Williams3c304952006-04-15 12:26:18 -04007215 char * buf;
Al Viro851b3e52007-12-19 19:20:12 -05007216 u16 dBm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007217
7218 /* First entry *MUST* be the AP MAC address */
7219 iwe.cmd = SIOCGIWAP;
7220 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
Dan Williams41480af2005-05-10 09:45:51 -04007221 memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007222 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
7223
7224 /* Other entries will be displayed in the order we give them */
7225
7226 /* Add the ESSID */
Dan Williams41480af2005-05-10 09:45:51 -04007227 iwe.u.data.length = bss->ssidLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007228 if(iwe.u.data.length > 32)
7229 iwe.u.data.length = 32;
7230 iwe.cmd = SIOCGIWESSID;
7231 iwe.u.data.flags = 1;
Dan Williams41480af2005-05-10 09:45:51 -04007232 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007233
7234 /* Add mode */
7235 iwe.cmd = SIOCGIWMODE;
Dan Williams41480af2005-05-10 09:45:51 -04007236 capabilities = le16_to_cpu(bss->cap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007237 if(capabilities & (CAP_ESS | CAP_IBSS)) {
7238 if(capabilities & CAP_ESS)
7239 iwe.u.mode = IW_MODE_MASTER;
7240 else
7241 iwe.u.mode = IW_MODE_ADHOC;
7242 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
7243 }
7244
7245 /* Add frequency */
7246 iwe.cmd = SIOCGIWFREQ;
Dan Williams41480af2005-05-10 09:45:51 -04007247 iwe.u.freq.m = le16_to_cpu(bss->dsChannel);
matthieu castet11414552005-09-12 23:31:39 +02007248 /* iwe.u.freq.m containt the channel (starting 1), our
7249 * frequency_list array start at index 0...
7250 */
7251 iwe.u.freq.m = frequency_list[iwe.u.freq.m - 1] * 100000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007252 iwe.u.freq.e = 1;
7253 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
7254
Al Viro851b3e52007-12-19 19:20:12 -05007255 dBm = le16_to_cpu(bss->dBm);
7256
Linus Torvalds1da177e2005-04-16 15:20:36 -07007257 /* Add quality statistics */
7258 iwe.cmd = IWEVQUAL;
Dan Williams41480af2005-05-10 09:45:51 -04007259 if (ai->rssi) {
Al Viro851b3e52007-12-19 19:20:12 -05007260 iwe.u.qual.level = 0x100 - dBm;
7261 iwe.u.qual.qual = airo_dbm_to_pct(ai->rssi, dBm);
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007262 iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
7263 | IW_QUAL_LEVEL_UPDATED
7264 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04007265 } else {
Al Viro851b3e52007-12-19 19:20:12 -05007266 iwe.u.qual.level = (dBm + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04007267 iwe.u.qual.qual = 0;
Jeff Garzikbbeec902005-09-07 00:27:54 -04007268 iwe.u.qual.updated = IW_QUAL_QUAL_INVALID
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007269 | IW_QUAL_LEVEL_UPDATED
7270 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04007271 }
7272 iwe.u.qual.noise = ai->wstats.qual.noise;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007273 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
7274
7275 /* Add encryption capability */
7276 iwe.cmd = SIOCGIWENCODE;
7277 if(capabilities & CAP_PRIVACY)
7278 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
7279 else
7280 iwe.u.data.flags = IW_ENCODE_DISABLED;
7281 iwe.u.data.length = 0;
Dan Williams41480af2005-05-10 09:45:51 -04007282 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007283
7284 /* Rate : stuffing multiple values in a single event require a bit
7285 * more of magic - Jean II */
7286 current_val = current_ev + IW_EV_LCP_LEN;
7287
7288 iwe.cmd = SIOCGIWRATE;
7289 /* Those two flags are ignored... */
7290 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
7291 /* Max 8 values */
7292 for(i = 0 ; i < 8 ; i++) {
7293 /* NULL terminated */
Dan Williams41480af2005-05-10 09:45:51 -04007294 if(bss->rates[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007295 break;
7296 /* Bit rate given in 500 kb/s units (+ 0x80) */
Dan Williams41480af2005-05-10 09:45:51 -04007297 iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007298 /* Add new value to event */
7299 current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
7300 }
7301 /* Check if we added any event */
7302 if((current_val - current_ev) > IW_EV_LCP_LEN)
7303 current_ev = current_val;
7304
Dan Williams3c304952006-04-15 12:26:18 -04007305 /* Beacon interval */
7306 buf = kmalloc(30, GFP_KERNEL);
7307 if (buf) {
7308 iwe.cmd = IWEVCUSTOM;
7309 sprintf(buf, "bcn_int=%d", bss->beaconInterval);
7310 iwe.u.data.length = strlen(buf);
7311 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
7312 kfree(buf);
7313 }
7314
7315 /* Put WPA/RSN Information Elements into the event stream */
7316 if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) {
7317 unsigned int num_null_ies = 0;
7318 u16 length = sizeof (bss->extra.iep);
7319 struct ieee80211_info_element *info_element =
7320 (struct ieee80211_info_element *) &bss->extra.iep;
7321
7322 while ((length >= sizeof(*info_element)) && (num_null_ies < 2)) {
7323 if (sizeof(*info_element) + info_element->len > length) {
7324 /* Invalid element, don't continue parsing IE */
7325 break;
7326 }
7327
7328 switch (info_element->id) {
7329 case MFIE_TYPE_SSID:
7330 /* Two zero-length SSID elements
7331 * mean we're done parsing elements */
7332 if (!info_element->len)
7333 num_null_ies++;
7334 break;
7335
7336 case MFIE_TYPE_GENERIC:
7337 if (info_element->len >= 4 &&
7338 info_element->data[0] == 0x00 &&
7339 info_element->data[1] == 0x50 &&
7340 info_element->data[2] == 0xf2 &&
7341 info_element->data[3] == 0x01) {
7342 iwe.cmd = IWEVGENIE;
7343 iwe.u.data.length = min(info_element->len + 2,
7344 MAX_WPA_IE_LEN);
7345 current_ev = iwe_stream_add_point(current_ev, end_buf,
7346 &iwe, (char *) info_element);
7347 }
7348 break;
7349
7350 case MFIE_TYPE_RSN:
7351 iwe.cmd = IWEVGENIE;
7352 iwe.u.data.length = min(info_element->len + 2,
7353 MAX_WPA_IE_LEN);
7354 current_ev = iwe_stream_add_point(current_ev, end_buf,
7355 &iwe, (char *) info_element);
7356 break;
7357
7358 default:
7359 break;
7360 }
7361
7362 length -= sizeof(*info_element) + info_element->len;
7363 info_element =
7364 (struct ieee80211_info_element *)&info_element->
7365 data[info_element->len];
7366 }
7367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007368 return current_ev;
7369}
7370
7371/*------------------------------------------------------------------*/
7372/*
7373 * Wireless Handler : Read Scan Results
7374 */
7375static int airo_get_scan(struct net_device *dev,
7376 struct iw_request_info *info,
7377 struct iw_point *dwrq,
7378 char *extra)
7379{
7380 struct airo_info *ai = dev->priv;
Dan Williams9e75af32006-03-16 13:46:29 -05007381 BSSListElement *net;
7382 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007383 char *current_ev = extra;
7384
Dan Williams9e75af32006-03-16 13:46:29 -05007385 /* If a scan is in-progress, return -EAGAIN */
7386 if (ai->scan_timeout > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007387 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007388
Dan Williams9e75af32006-03-16 13:46:29 -05007389 if (down_interruptible(&ai->sem))
7390 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007391
Dan Williams9e75af32006-03-16 13:46:29 -05007392 list_for_each_entry (net, &ai->network_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007393 /* Translate to WE format this entry */
7394 current_ev = airo_translate_scan(dev, current_ev,
7395 extra + dwrq->length,
Dan Williams9e75af32006-03-16 13:46:29 -05007396 &net->bss);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007397
7398 /* Check if there is space for one more entry */
7399 if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
7400 /* Ask user space to try again with a bigger buffer */
Dan Williams9e75af32006-03-16 13:46:29 -05007401 err = -E2BIG;
7402 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007404 }
Dan Williams9e75af32006-03-16 13:46:29 -05007405
Linus Torvalds1da177e2005-04-16 15:20:36 -07007406 /* Length of data */
7407 dwrq->length = (current_ev - extra);
7408 dwrq->flags = 0; /* todo */
7409
Dan Williams9e75af32006-03-16 13:46:29 -05007410out:
7411 up(&ai->sem);
7412 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007413}
7414
7415/*------------------------------------------------------------------*/
7416/*
7417 * Commit handler : called after a bunch of SET operations
7418 */
7419static int airo_config_commit(struct net_device *dev,
7420 struct iw_request_info *info, /* NULL */
7421 void *zwrq, /* NULL */
7422 char *extra) /* NULL */
7423{
7424 struct airo_info *local = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007425
7426 if (!test_bit (FLAG_COMMIT, &local->flags))
7427 return 0;
7428
7429 /* Some of the "SET" function may have modified some of the
7430 * parameters. It's now time to commit them in the card */
7431 disable_MAC(local, 1);
7432 if (test_bit (FLAG_RESET, &local->flags)) {
7433 APListRid APList_rid;
7434 SsidRid SSID_rid;
7435
7436 readAPListRid(local, &APList_rid);
7437 readSsidRid(local, &SSID_rid);
7438 if (test_bit(FLAG_MPI,&local->flags))
7439 setup_card(local, dev->dev_addr, 1 );
7440 else
7441 reset_airo_card(dev);
7442 disable_MAC(local, 1);
7443 writeSsidRid(local, &SSID_rid, 1);
7444 writeAPListRid(local, &APList_rid, 1);
7445 }
7446 if (down_interruptible(&local->sem))
7447 return -ERESTARTSYS;
7448 writeConfigRid(local, 0);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02007449 enable_MAC(local, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007450 if (test_bit (FLAG_RESET, &local->flags))
7451 airo_set_promisc(local);
7452 else
7453 up(&local->sem);
7454
7455 return 0;
7456}
7457
7458/*------------------------------------------------------------------*/
7459/*
7460 * Structures to export the Wireless Handlers
7461 */
7462
7463static const struct iw_priv_args airo_private_args[] = {
7464/*{ cmd, set_args, get_args, name } */
7465 { AIROIOCTL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
7466 IW_PRIV_TYPE_BYTE | 2047, "airoioctl" },
7467 { AIROIDIFC, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
7468 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" },
7469};
7470
7471static const iw_handler airo_handler[] =
7472{
7473 (iw_handler) airo_config_commit, /* SIOCSIWCOMMIT */
7474 (iw_handler) airo_get_name, /* SIOCGIWNAME */
7475 (iw_handler) NULL, /* SIOCSIWNWID */
7476 (iw_handler) NULL, /* SIOCGIWNWID */
7477 (iw_handler) airo_set_freq, /* SIOCSIWFREQ */
7478 (iw_handler) airo_get_freq, /* SIOCGIWFREQ */
7479 (iw_handler) airo_set_mode, /* SIOCSIWMODE */
7480 (iw_handler) airo_get_mode, /* SIOCGIWMODE */
7481 (iw_handler) airo_set_sens, /* SIOCSIWSENS */
7482 (iw_handler) airo_get_sens, /* SIOCGIWSENS */
7483 (iw_handler) NULL, /* SIOCSIWRANGE */
7484 (iw_handler) airo_get_range, /* SIOCGIWRANGE */
7485 (iw_handler) NULL, /* SIOCSIWPRIV */
7486 (iw_handler) NULL, /* SIOCGIWPRIV */
7487 (iw_handler) NULL, /* SIOCSIWSTATS */
7488 (iw_handler) NULL, /* SIOCGIWSTATS */
7489 iw_handler_set_spy, /* SIOCSIWSPY */
7490 iw_handler_get_spy, /* SIOCGIWSPY */
7491 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
7492 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
7493 (iw_handler) airo_set_wap, /* SIOCSIWAP */
7494 (iw_handler) airo_get_wap, /* SIOCGIWAP */
7495 (iw_handler) NULL, /* -- hole -- */
7496 (iw_handler) airo_get_aplist, /* SIOCGIWAPLIST */
7497 (iw_handler) airo_set_scan, /* SIOCSIWSCAN */
7498 (iw_handler) airo_get_scan, /* SIOCGIWSCAN */
7499 (iw_handler) airo_set_essid, /* SIOCSIWESSID */
7500 (iw_handler) airo_get_essid, /* SIOCGIWESSID */
7501 (iw_handler) airo_set_nick, /* SIOCSIWNICKN */
7502 (iw_handler) airo_get_nick, /* SIOCGIWNICKN */
7503 (iw_handler) NULL, /* -- hole -- */
7504 (iw_handler) NULL, /* -- hole -- */
7505 (iw_handler) airo_set_rate, /* SIOCSIWRATE */
7506 (iw_handler) airo_get_rate, /* SIOCGIWRATE */
7507 (iw_handler) airo_set_rts, /* SIOCSIWRTS */
7508 (iw_handler) airo_get_rts, /* SIOCGIWRTS */
7509 (iw_handler) airo_set_frag, /* SIOCSIWFRAG */
7510 (iw_handler) airo_get_frag, /* SIOCGIWFRAG */
7511 (iw_handler) airo_set_txpow, /* SIOCSIWTXPOW */
7512 (iw_handler) airo_get_txpow, /* SIOCGIWTXPOW */
7513 (iw_handler) airo_set_retry, /* SIOCSIWRETRY */
7514 (iw_handler) airo_get_retry, /* SIOCGIWRETRY */
7515 (iw_handler) airo_set_encode, /* SIOCSIWENCODE */
7516 (iw_handler) airo_get_encode, /* SIOCGIWENCODE */
7517 (iw_handler) airo_set_power, /* SIOCSIWPOWER */
7518 (iw_handler) airo_get_power, /* SIOCGIWPOWER */
Dan Williams4be757d2006-01-30 11:58:00 -05007519 (iw_handler) NULL, /* -- hole -- */
7520 (iw_handler) NULL, /* -- hole -- */
7521 (iw_handler) NULL, /* SIOCSIWGENIE */
7522 (iw_handler) NULL, /* SIOCGIWGENIE */
7523 (iw_handler) airo_set_auth, /* SIOCSIWAUTH */
7524 (iw_handler) airo_get_auth, /* SIOCGIWAUTH */
7525 (iw_handler) airo_set_encodeext, /* SIOCSIWENCODEEXT */
7526 (iw_handler) airo_get_encodeext, /* SIOCGIWENCODEEXT */
7527 (iw_handler) NULL, /* SIOCSIWPMKSA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007528};
7529
7530/* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here.
7531 * We want to force the use of the ioctl code, because those can't be
7532 * won't work the iw_handler code (because they simultaneously read
7533 * and write data and iw_handler can't do that).
7534 * Note that it's perfectly legal to read/write on a single ioctl command,
7535 * you just can't use iwpriv and need to force it via the ioctl handler.
7536 * Jean II */
7537static const iw_handler airo_private_handler[] =
7538{
7539 NULL, /* SIOCIWFIRSTPRIV */
7540};
7541
7542static const struct iw_handler_def airo_handler_def =
7543{
Denis Chengff8ac602007-09-02 18:30:18 +08007544 .num_standard = ARRAY_SIZE(airo_handler),
7545 .num_private = ARRAY_SIZE(airo_private_handler),
7546 .num_private_args = ARRAY_SIZE(airo_private_args),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007547 .standard = airo_handler,
7548 .private = airo_private_handler,
7549 .private_args = airo_private_args,
7550 .get_wireless_stats = airo_get_wireless_stats,
7551};
7552
Linus Torvalds1da177e2005-04-16 15:20:36 -07007553/*
7554 * This defines the configuration part of the Wireless Extensions
7555 * Note : irq and spinlock protection will occur in the subroutines
7556 *
7557 * TODO :
7558 * o Check input value more carefully and fill correct values in range
7559 * o Test and shakeout the bugs (if any)
7560 *
7561 * Jean II
7562 *
7563 * Javier Achirica did a great job of merging code from the unnamed CISCO
7564 * developer that added support for flashing the card.
7565 */
7566static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
7567{
7568 int rc = 0;
7569 struct airo_info *ai = (struct airo_info *)dev->priv;
7570
Pavel Machekca078ba2005-09-03 15:56:57 -07007571 if (ai->power.event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007572 return 0;
7573
7574 switch (cmd) {
7575#ifdef CISCO_EXT
7576 case AIROIDIFC:
7577#ifdef AIROOLDIDIFC
7578 case AIROOLDIDIFC:
7579#endif
7580 {
7581 int val = AIROMAGIC;
7582 aironet_ioctl com;
7583 if (copy_from_user(&com,rq->ifr_data,sizeof(com)))
7584 rc = -EFAULT;
7585 else if (copy_to_user(com.data,(char *)&val,sizeof(val)))
7586 rc = -EFAULT;
7587 }
7588 break;
7589
7590 case AIROIOCTL:
7591#ifdef AIROOLDIOCTL
7592 case AIROOLDIOCTL:
7593#endif
7594 /* Get the command struct and hand it off for evaluation by
7595 * the proper subfunction
7596 */
7597 {
7598 aironet_ioctl com;
7599 if (copy_from_user(&com,rq->ifr_data,sizeof(com))) {
7600 rc = -EFAULT;
7601 break;
7602 }
7603
7604 /* Separate R/W functions bracket legality here
7605 */
7606 if ( com.command == AIRORSWVERSION ) {
7607 if (copy_to_user(com.data, swversion, sizeof(swversion)))
7608 rc = -EFAULT;
7609 else
7610 rc = 0;
7611 }
7612 else if ( com.command <= AIRORRID)
7613 rc = readrids(dev,&com);
7614 else if ( com.command >= AIROPCAP && com.command <= (AIROPLEAPUSR+2) )
7615 rc = writerids(dev,&com);
7616 else if ( com.command >= AIROFLSHRST && com.command <= AIRORESTART )
7617 rc = flashcard(dev,&com);
7618 else
7619 rc = -EINVAL; /* Bad command in ioctl */
7620 }
7621 break;
7622#endif /* CISCO_EXT */
7623
7624 // All other calls are currently unsupported
7625 default:
7626 rc = -EOPNOTSUPP;
7627 }
7628 return rc;
7629}
7630
Linus Torvalds1da177e2005-04-16 15:20:36 -07007631/*
7632 * Get the Wireless stats out of the driver
7633 * Note : irq and spinlock protection will occur in the subroutines
7634 *
7635 * TODO :
7636 * o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs)
7637 *
7638 * Jean
7639 */
7640static void airo_read_wireless_stats(struct airo_info *local)
7641{
7642 StatusRid status_rid;
7643 StatsRid stats_rid;
7644 CapabilityRid cap_rid;
7645 u32 *vals = stats_rid.vals;
7646
7647 /* Get stats out of the card */
Dan Williams3c304952006-04-15 12:26:18 -04007648 clear_bit(JOB_WSTATS, &local->jobs);
Pavel Machekca078ba2005-09-03 15:56:57 -07007649 if (local->power.event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007650 up(&local->sem);
7651 return;
7652 }
7653 readCapabilityRid(local, &cap_rid, 0);
7654 readStatusRid(local, &status_rid, 0);
7655 readStatsRid(local, &stats_rid, RID_STATS, 0);
7656 up(&local->sem);
7657
7658 /* The status */
7659 local->wstats.status = status_rid.mode;
7660
Dan Williams41480af2005-05-10 09:45:51 -04007661 /* Signal quality and co */
7662 if (local->rssi) {
7663 local->wstats.qual.level = airo_rssi_to_dbm( local->rssi, status_rid.sigQuality );
7664 /* normalizedSignalStrength appears to be a percentage */
7665 local->wstats.qual.qual = status_rid.normalizedSignalStrength;
7666 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007667 local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04007668 local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
7669 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007670 if (status_rid.len >= 124) {
Dan Williams41480af2005-05-10 09:45:51 -04007671 local->wstats.qual.noise = 0x100 - status_rid.noisedBm;
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007672 local->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007673 } else {
7674 local->wstats.qual.noise = 0;
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007675 local->wstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007676 }
7677
7678 /* Packets discarded in the wireless adapter due to wireless
7679 * specific problems */
7680 local->wstats.discard.nwid = vals[56] + vals[57] + vals[58];/* SSID Mismatch */
7681 local->wstats.discard.code = vals[6];/* RxWepErr */
7682 local->wstats.discard.fragment = vals[30];
7683 local->wstats.discard.retries = vals[10];
7684 local->wstats.discard.misc = vals[1] + vals[32];
7685 local->wstats.miss.beacon = vals[34];
7686}
7687
Jouni Malinenff1d2762005-05-12 22:54:16 -04007688static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007689{
7690 struct airo_info *local = dev->priv;
7691
Dan Williams3c304952006-04-15 12:26:18 -04007692 if (!test_bit(JOB_WSTATS, &local->jobs)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007693 /* Get stats out of the card if available */
7694 if (down_trylock(&local->sem) != 0) {
Dan Williams3c304952006-04-15 12:26:18 -04007695 set_bit(JOB_WSTATS, &local->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007696 wake_up_interruptible(&local->thr_wait);
7697 } else
7698 airo_read_wireless_stats(local);
7699 }
7700
7701 return &local->wstats;
7702}
Linus Torvalds1da177e2005-04-16 15:20:36 -07007703
7704#ifdef CISCO_EXT
7705/*
7706 * This just translates from driver IOCTL codes to the command codes to
7707 * feed to the radio's host interface. Things can be added/deleted
7708 * as needed. This represents the READ side of control I/O to
7709 * the card
7710 */
7711static int readrids(struct net_device *dev, aironet_ioctl *comp) {
7712 unsigned short ridcode;
7713 unsigned char *iobuf;
7714 int len;
7715 struct airo_info *ai = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007716
7717 if (test_bit(FLAG_FLASHING, &ai->flags))
7718 return -EIO;
7719
7720 switch(comp->command)
7721 {
7722 case AIROGCAP: ridcode = RID_CAPABILITIES; break;
7723 case AIROGCFG: ridcode = RID_CONFIG;
7724 if (test_bit(FLAG_COMMIT, &ai->flags)) {
7725 disable_MAC (ai, 1);
7726 writeConfigRid (ai, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02007727 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007728 }
7729 break;
7730 case AIROGSLIST: ridcode = RID_SSID; break;
7731 case AIROGVLIST: ridcode = RID_APLIST; break;
7732 case AIROGDRVNAM: ridcode = RID_DRVNAME; break;
7733 case AIROGEHTENC: ridcode = RID_ETHERENCAP; break;
7734 case AIROGWEPKTMP: ridcode = RID_WEP_TEMP;
7735 /* Only super-user can read WEP keys */
7736 if (!capable(CAP_NET_ADMIN))
7737 return -EPERM;
7738 break;
7739 case AIROGWEPKNV: ridcode = RID_WEP_PERM;
7740 /* Only super-user can read WEP keys */
7741 if (!capable(CAP_NET_ADMIN))
7742 return -EPERM;
7743 break;
7744 case AIROGSTAT: ridcode = RID_STATUS; break;
7745 case AIROGSTATSD32: ridcode = RID_STATSDELTA; break;
7746 case AIROGSTATSC32: ridcode = RID_STATS; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007747 case AIROGMICSTATS:
7748 if (copy_to_user(comp->data, &ai->micstats,
7749 min((int)comp->len,(int)sizeof(ai->micstats))))
7750 return -EFAULT;
7751 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007752 case AIRORRID: ridcode = comp->ridnum; break;
7753 default:
7754 return -EINVAL;
7755 break;
7756 }
7757
7758 if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
7759 return -ENOMEM;
7760
7761 PC4500_readrid(ai,ridcode,iobuf,RIDSIZE, 1);
7762 /* get the count of bytes in the rid docs say 1st 2 bytes is it.
7763 * then return it to the user
7764 * 9/22/2000 Honor user given length
7765 */
7766 len = comp->len;
7767
7768 if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) {
7769 kfree (iobuf);
7770 return -EFAULT;
7771 }
7772 kfree (iobuf);
7773 return 0;
7774}
7775
7776/*
7777 * Danger Will Robinson write the rids here
7778 */
7779
7780static int writerids(struct net_device *dev, aironet_ioctl *comp) {
7781 struct airo_info *ai = dev->priv;
7782 int ridcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007783 int enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007784 static int (* writer)(struct airo_info *, u16 rid, const void *, int, int);
7785 unsigned char *iobuf;
7786
7787 /* Only super-user can write RIDs */
7788 if (!capable(CAP_NET_ADMIN))
7789 return -EPERM;
7790
7791 if (test_bit(FLAG_FLASHING, &ai->flags))
7792 return -EIO;
7793
7794 ridcode = 0;
7795 writer = do_writerid;
7796
7797 switch(comp->command)
7798 {
7799 case AIROPSIDS: ridcode = RID_SSID; break;
7800 case AIROPCAP: ridcode = RID_CAPABILITIES; break;
7801 case AIROPAPLIST: ridcode = RID_APLIST; break;
7802 case AIROPCFG: ai->config.len = 0;
7803 clear_bit(FLAG_COMMIT, &ai->flags);
7804 ridcode = RID_CONFIG; break;
7805 case AIROPWEPKEYNV: ridcode = RID_WEP_PERM; break;
7806 case AIROPLEAPUSR: ridcode = RID_LEAPUSERNAME; break;
7807 case AIROPLEAPPWD: ridcode = RID_LEAPPASSWORD; break;
7808 case AIROPWEPKEY: ridcode = RID_WEP_TEMP; writer = PC4500_writerid;
7809 break;
7810 case AIROPLEAPUSR+1: ridcode = 0xFF2A; break;
7811 case AIROPLEAPUSR+2: ridcode = 0xFF2B; break;
7812
7813 /* this is not really a rid but a command given to the card
7814 * same with MAC off
7815 */
7816 case AIROPMACON:
Michal Schmidt175ec1a2007-06-29 15:33:47 +02007817 if (enable_MAC(ai, 1) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007818 return -EIO;
7819 return 0;
7820
7821 /*
7822 * Evidently this code in the airo driver does not get a symbol
7823 * as disable_MAC. it's probably so short the compiler does not gen one.
7824 */
7825 case AIROPMACOFF:
7826 disable_MAC(ai, 1);
7827 return 0;
7828
7829 /* This command merely clears the counts does not actually store any data
7830 * only reads rid. But as it changes the cards state, I put it in the
7831 * writerid routines.
7832 */
7833 case AIROPSTCLR:
7834 if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
7835 return -ENOMEM;
7836
7837 PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDSIZE, 1);
7838
Linus Torvalds1da177e2005-04-16 15:20:36 -07007839 enabled = ai->micstats.enabled;
7840 memset(&ai->micstats,0,sizeof(ai->micstats));
7841 ai->micstats.enabled = enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007842
7843 if (copy_to_user(comp->data, iobuf,
7844 min((int)comp->len, (int)RIDSIZE))) {
7845 kfree (iobuf);
7846 return -EFAULT;
7847 }
7848 kfree (iobuf);
7849 return 0;
7850
7851 default:
7852 return -EOPNOTSUPP; /* Blarg! */
7853 }
7854 if(comp->len > RIDSIZE)
7855 return -EINVAL;
7856
7857 if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
7858 return -ENOMEM;
7859
7860 if (copy_from_user(iobuf,comp->data,comp->len)) {
7861 kfree (iobuf);
7862 return -EFAULT;
7863 }
7864
7865 if (comp->command == AIROPCFG) {
7866 ConfigRid *cfg = (ConfigRid *)iobuf;
7867
7868 if (test_bit(FLAG_MIC_CAPABLE, &ai->flags))
Al Viro2ab1f512007-12-20 23:04:35 -05007869 cfg->opmode |= cpu_to_le16(MODE_MIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007870
Al Viro2ab1f512007-12-20 23:04:35 -05007871 if ((le16_to_cpu(cfg->opmode) & 0xFF) == MODE_STA_IBSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007872 set_bit (FLAG_ADHOC, &ai->flags);
7873 else
7874 clear_bit (FLAG_ADHOC, &ai->flags);
7875 }
7876
7877 if((*writer)(ai, ridcode, iobuf,comp->len,1)) {
7878 kfree (iobuf);
7879 return -EIO;
7880 }
7881 kfree (iobuf);
7882 return 0;
7883}
7884
7885/*****************************************************************************
7886 * Ancillary flash / mod functions much black magic lurkes here *
7887 *****************************************************************************
7888 */
7889
7890/*
7891 * Flash command switch table
7892 */
7893
Jouni Malinenff1d2762005-05-12 22:54:16 -04007894static int flashcard(struct net_device *dev, aironet_ioctl *comp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007895 int z;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007896
7897 /* Only super-user can modify flash */
7898 if (!capable(CAP_NET_ADMIN))
7899 return -EPERM;
7900
7901 switch(comp->command)
7902 {
7903 case AIROFLSHRST:
7904 return cmdreset((struct airo_info *)dev->priv);
7905
7906 case AIROFLSHSTFL:
7907 if (!((struct airo_info *)dev->priv)->flash &&
7908 (((struct airo_info *)dev->priv)->flash = kmalloc (FLASHSIZE, GFP_KERNEL)) == NULL)
7909 return -ENOMEM;
7910 return setflashmode((struct airo_info *)dev->priv);
7911
7912 case AIROFLSHGCHR: /* Get char from aux */
7913 if(comp->len != sizeof(int))
7914 return -EINVAL;
7915 if (copy_from_user(&z,comp->data,comp->len))
7916 return -EFAULT;
7917 return flashgchar((struct airo_info *)dev->priv,z,8000);
7918
7919 case AIROFLSHPCHR: /* Send char to card. */
7920 if(comp->len != sizeof(int))
7921 return -EINVAL;
7922 if (copy_from_user(&z,comp->data,comp->len))
7923 return -EFAULT;
7924 return flashpchar((struct airo_info *)dev->priv,z,8000);
7925
7926 case AIROFLPUTBUF: /* Send 32k to card */
7927 if (!((struct airo_info *)dev->priv)->flash)
7928 return -ENOMEM;
7929 if(comp->len > FLASHSIZE)
7930 return -EINVAL;
7931 if(copy_from_user(((struct airo_info *)dev->priv)->flash,comp->data,comp->len))
7932 return -EFAULT;
7933
7934 flashputbuf((struct airo_info *)dev->priv);
7935 return 0;
7936
7937 case AIRORESTART:
7938 if(flashrestart((struct airo_info *)dev->priv,dev))
7939 return -EIO;
7940 return 0;
7941 }
7942 return -EINVAL;
7943}
7944
7945#define FLASH_COMMAND 0x7e7e
7946
7947/*
7948 * STEP 1)
7949 * Disable MAC and do soft reset on
7950 * card.
7951 */
7952
Jouni Malinenff1d2762005-05-12 22:54:16 -04007953static int cmdreset(struct airo_info *ai) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007954 disable_MAC(ai, 1);
7955
7956 if(!waitbusy (ai)){
Dan Williams934d8bf2006-03-16 13:46:23 -05007957 airo_print_info(ai->dev->name, "Waitbusy hang before RESET");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007958 return -EBUSY;
7959 }
7960
7961 OUT4500(ai,COMMAND,CMD_SOFTRESET);
7962
7963 ssleep(1); /* WAS 600 12/7/00 */
7964
7965 if(!waitbusy (ai)){
Dan Williams934d8bf2006-03-16 13:46:23 -05007966 airo_print_info(ai->dev->name, "Waitbusy hang AFTER RESET");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007967 return -EBUSY;
7968 }
7969 return 0;
7970}
7971
7972/* STEP 2)
7973 * Put the card in legendary flash
7974 * mode
7975 */
7976
Jouni Malinenff1d2762005-05-12 22:54:16 -04007977static int setflashmode (struct airo_info *ai) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007978 set_bit (FLAG_FLASHING, &ai->flags);
7979
7980 OUT4500(ai, SWS0, FLASH_COMMAND);
7981 OUT4500(ai, SWS1, FLASH_COMMAND);
7982 if (probe) {
7983 OUT4500(ai, SWS0, FLASH_COMMAND);
7984 OUT4500(ai, COMMAND,0x10);
7985 } else {
7986 OUT4500(ai, SWS2, FLASH_COMMAND);
7987 OUT4500(ai, SWS3, FLASH_COMMAND);
7988 OUT4500(ai, COMMAND,0);
7989 }
7990 msleep(500); /* 500ms delay */
7991
7992 if(!waitbusy(ai)) {
7993 clear_bit (FLAG_FLASHING, &ai->flags);
Dan Williams934d8bf2006-03-16 13:46:23 -05007994 airo_print_info(ai->dev->name, "Waitbusy hang after setflash mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007995 return -EIO;
7996 }
7997 return 0;
7998}
7999
8000/* Put character to SWS0 wait for dwelltime
8001 * x 50us for echo .
8002 */
8003
Jouni Malinenff1d2762005-05-12 22:54:16 -04008004static int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008005 int echo;
8006 int waittime;
8007
8008 byte |= 0x8000;
8009
8010 if(dwelltime == 0 )
8011 dwelltime = 200;
8012
8013 waittime=dwelltime;
8014
8015 /* Wait for busy bit d15 to go false indicating buffer empty */
8016 while ((IN4500 (ai, SWS0) & 0x8000) && waittime > 0) {
8017 udelay (50);
8018 waittime -= 50;
8019 }
8020
8021 /* timeout for busy clear wait */
8022 if(waittime <= 0 ){
Dan Williams934d8bf2006-03-16 13:46:23 -05008023 airo_print_info(ai->dev->name, "flash putchar busywait timeout!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07008024 return -EBUSY;
8025 }
8026
8027 /* Port is clear now write byte and wait for it to echo back */
8028 do {
8029 OUT4500(ai,SWS0,byte);
8030 udelay(50);
8031 dwelltime -= 50;
8032 echo = IN4500(ai,SWS1);
8033 } while (dwelltime >= 0 && echo != byte);
8034
8035 OUT4500(ai,SWS1,0);
8036
8037 return (echo == byte) ? 0 : -EIO;
8038}
8039
8040/*
8041 * Get a character from the card matching matchbyte
8042 * Step 3)
8043 */
Jouni Malinenff1d2762005-05-12 22:54:16 -04008044static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
Linus Torvalds1da177e2005-04-16 15:20:36 -07008045 int rchar;
8046 unsigned char rbyte=0;
8047
8048 do {
8049 rchar = IN4500(ai,SWS1);
8050
8051 if(dwelltime && !(0x8000 & rchar)){
8052 dwelltime -= 10;
8053 mdelay(10);
8054 continue;
8055 }
8056 rbyte = 0xff & rchar;
8057
8058 if( (rbyte == matchbyte) && (0x8000 & rchar) ){
8059 OUT4500(ai,SWS1,0);
8060 return 0;
8061 }
8062 if( rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar)
8063 break;
8064 OUT4500(ai,SWS1,0);
8065
8066 }while(dwelltime > 0);
8067 return -EIO;
8068}
8069
8070/*
8071 * Transfer 32k of firmware data from user buffer to our buffer and
8072 * send to the card
8073 */
8074
Jouni Malinenff1d2762005-05-12 22:54:16 -04008075static int flashputbuf(struct airo_info *ai){
Linus Torvalds1da177e2005-04-16 15:20:36 -07008076 int nwords;
8077
8078 /* Write stuff */
8079 if (test_bit(FLAG_MPI,&ai->flags))
8080 memcpy_toio(ai->pciaux + 0x8000, ai->flash, FLASHSIZE);
8081 else {
8082 OUT4500(ai,AUXPAGE,0x100);
8083 OUT4500(ai,AUXOFF,0);
8084
8085 for(nwords=0;nwords != FLASHSIZE / 2;nwords++){
8086 OUT4500(ai,AUXDATA,ai->flash[nwords] & 0xffff);
8087 }
8088 }
8089 OUT4500(ai,SWS0,0x8000);
8090
8091 return 0;
8092}
8093
8094/*
8095 *
8096 */
Jouni Malinenff1d2762005-05-12 22:54:16 -04008097static int flashrestart(struct airo_info *ai,struct net_device *dev){
Linus Torvalds1da177e2005-04-16 15:20:36 -07008098 int i,status;
8099
8100 ssleep(1); /* Added 12/7/00 */
8101 clear_bit (FLAG_FLASHING, &ai->flags);
8102 if (test_bit(FLAG_MPI, &ai->flags)) {
8103 status = mpi_init_descriptors(ai);
8104 if (status != SUCCESS)
8105 return status;
8106 }
8107 status = setup_card(ai, dev->dev_addr, 1);
8108
8109 if (!test_bit(FLAG_MPI,&ai->flags))
8110 for( i = 0; i < MAX_FIDS; i++ ) {
8111 ai->fids[i] = transmit_allocate
Dan Williams15db2762006-03-16 13:46:27 -05008112 ( ai, AIRO_DEF_MTU, i >= MAX_FIDS / 2 );
Linus Torvalds1da177e2005-04-16 15:20:36 -07008113 }
8114
8115 ssleep(1); /* Added 12/7/00 */
8116 return status;
8117}
8118#endif /* CISCO_EXT */
8119
8120/*
8121 This program is free software; you can redistribute it and/or
8122 modify it under the terms of the GNU General Public License
8123 as published by the Free Software Foundation; either version 2
8124 of the License, or (at your option) any later version.
8125
8126 This program is distributed in the hope that it will be useful,
8127 but WITHOUT ANY WARRANTY; without even the implied warranty of
8128 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8129 GNU General Public License for more details.
8130
8131 In addition:
8132
8133 Redistribution and use in source and binary forms, with or without
8134 modification, are permitted provided that the following conditions
8135 are met:
8136
8137 1. Redistributions of source code must retain the above copyright
8138 notice, this list of conditions and the following disclaimer.
8139 2. Redistributions in binary form must reproduce the above copyright
8140 notice, this list of conditions and the following disclaimer in the
8141 documentation and/or other materials provided with the distribution.
8142 3. The name of the author may not be used to endorse or promote
8143 products derived from this software without specific prior written
8144 permission.
8145
8146 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
8147 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8148 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8149 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
8150 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
8151 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
8152 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8153 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
8154 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
8155 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
8156 POSSIBILITY OF SUCH DAMAGE.
8157*/
8158
8159module_init(airo_init_module);
8160module_exit(airo_cleanup_module);