blob: 9b0714cea75e6eeec52db8876e17918c9f52d924 [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 {
Al Viro4293ea32007-12-19 19:21:51 -0500504 __le16 len;
505 __le16 kindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 u8 mac[ETH_ALEN];
Al Viro4293ea32007-12-19 19:21:51 -0500507 __le16 klen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 u8 key[16];
509} WepKeyRid;
510
511/* These structures are from the Aironet's PC4500 Developers Manual */
512typedef struct {
Al Viro0dd22122007-12-17 16:11:57 -0500513 __le16 len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 u8 ssid[32];
515} Ssid;
516
517typedef struct {
Al Viro0dd22122007-12-17 16:11:57 -0500518 __le16 len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 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 {
Al Viroa23ace52007-12-19 22:24:16 -0500709 __le16 len;
710 __le16 spacer;
711 __le32 vals[100];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712} 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 {
Al Viro17e70492007-12-19 18:56:37 -0500752 __le16 unknown[4];
Dan Williams3c304952006-04-15 12:26:18 -0400753 u8 fixed[12]; /* WLAN management frame */
754 u8 iep[624];
755} BSSListRidExtra;
756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757typedef struct {
Al Viro17e70492007-12-19 18:56:37 -0500758 __le16 len;
759 __le16 index; /* First is 0 and 0xffff means end of list */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760#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) */
Al Viro17e70492007-12-19 18:56:37 -0500763 __le16 radioType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 u8 bssid[ETH_ALEN]; /* Mac address of the BSS */
765 u8 zero;
766 u8 ssidLen;
767 u8 ssid[32];
Al Viro17e70492007-12-19 18:56:37 -0500768 __le16 dBm;
769#define CAP_ESS cpu_to_le16(1<<0)
770#define CAP_IBSS cpu_to_le16(1<<1)
771#define CAP_PRIVACY cpu_to_le16(1<<4)
772#define CAP_SHORTHDR cpu_to_le16(1<<5)
773 __le16 cap;
774 __le16 beaconInterval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 u8 rates[8]; /* Same as rates for config rid */
776 struct { /* For frequency hopping only */
Al Viro17e70492007-12-19 18:56:37 -0500777 __le16 dwell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 u8 hopSet;
779 u8 hopPattern;
780 u8 hopIndex;
781 u8 fill;
782 } fh;
Al Viro17e70492007-12-19 18:56:37 -0500783 __le16 dsChannel;
784 __le16 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);
Al Virob8c06bc2007-12-19 17:55:43 -05001104static int aux_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 int whichbap);
Al Virob8c06bc2007-12-19 17:55:43 -05001106static int fast_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 int whichbap);
Al Virob8c06bc2007-12-19 17:55:43 -05001108static int bap_write(struct airo_info*, const __le16 *pu16Src, int bytelen,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 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;
Al Virob8c06bc2007-12-19 17:55:43 -05001191 int (*bap_read)(struct airo_info*, __le16 *pu16Dst, int bytelen,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 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
Al Virob8c06bc2007-12-19 17:55:43 -05001239static inline int bap_read(struct airo_info *ai, __le16 *pu16Dst, int bytelen,
1240 int whichbap)
1241{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 return ai->bap_read(ai, pu16Dst, bytelen, whichbap);
1243}
1244
1245static int setup_proc_entry( struct net_device *dev,
1246 struct airo_info *apriv );
1247static int takedown_proc_entry( struct net_device *dev,
1248 struct airo_info *apriv );
1249
Jouni Malinenff1d2762005-05-12 22:54:16 -04001250static int cmdreset(struct airo_info *ai);
1251static int setflashmode (struct airo_info *ai);
1252static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime);
1253static int flashputbuf(struct airo_info *ai);
1254static int flashrestart(struct airo_info *ai,struct net_device *dev);
1255
Dan Williams934d8bf2006-03-16 13:46:23 -05001256#define airo_print(type, name, fmt, args...) \
Michal Schmidt1138c372007-06-29 15:33:41 +02001257 printk(type DRV_NAME "(%s): " fmt "\n", name, ##args)
Dan Williams934d8bf2006-03-16 13:46:23 -05001258
1259#define airo_print_info(name, fmt, args...) \
1260 airo_print(KERN_INFO, name, fmt, ##args)
1261
1262#define airo_print_dbg(name, fmt, args...) \
1263 airo_print(KERN_DEBUG, name, fmt, ##args)
1264
1265#define airo_print_warn(name, fmt, args...) \
1266 airo_print(KERN_WARNING, name, fmt, ##args)
1267
1268#define airo_print_err(name, fmt, args...) \
1269 airo_print(KERN_ERR, name, fmt, ##args)
1270
1271
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272/***********************************************************************
1273 * MIC ROUTINES *
1274 ***********************************************************************
1275 */
1276
1277static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq);
1278static void MoveWindow(miccntx *context, u32 micSeq);
Herbert Xuf12cc202006-08-22 20:36:13 +10001279static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
1280 struct crypto_cipher *tfm);
Jouni Malinenff1d2762005-05-12 22:54:16 -04001281static void emmh32_init(emmh32_context *context);
1282static void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
1283static void emmh32_final(emmh32_context *context, u8 digest[4]);
1284static int flashpchar(struct airo_info *ai,int byte,int dwelltime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285
1286/* micinit - Initialize mic seed */
1287
1288static void micinit(struct airo_info *ai)
1289{
1290 MICRid mic_rid;
1291
Dan Williams3c304952006-04-15 12:26:18 -04001292 clear_bit(JOB_MIC, &ai->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
1294 up(&ai->sem);
1295
1296 ai->micstats.enabled = (mic_rid.state & 0x00FF) ? 1 : 0;
1297
1298 if (ai->micstats.enabled) {
1299 /* Key must be valid and different */
1300 if (mic_rid.multicastValid && (!ai->mod[0].mCtx.valid ||
1301 (memcmp (ai->mod[0].mCtx.key, mic_rid.multicast,
1302 sizeof(ai->mod[0].mCtx.key)) != 0))) {
1303 /* Age current mic Context */
1304 memcpy(&ai->mod[1].mCtx,&ai->mod[0].mCtx,sizeof(miccntx));
1305 /* Initialize new context */
1306 memcpy(&ai->mod[0].mCtx.key,mic_rid.multicast,sizeof(mic_rid.multicast));
1307 ai->mod[0].mCtx.window = 33; //Window always points to the middle
1308 ai->mod[0].mCtx.rx = 0; //Rx Sequence numbers
1309 ai->mod[0].mCtx.tx = 0; //Tx sequence numbers
1310 ai->mod[0].mCtx.valid = 1; //Key is now valid
1311
1312 /* Give key to mic seed */
1313 emmh32_setseed(&ai->mod[0].mCtx.seed,mic_rid.multicast,sizeof(mic_rid.multicast), ai->tfm);
1314 }
1315
1316 /* Key must be valid and different */
1317 if (mic_rid.unicastValid && (!ai->mod[0].uCtx.valid ||
1318 (memcmp(ai->mod[0].uCtx.key, mic_rid.unicast,
1319 sizeof(ai->mod[0].uCtx.key)) != 0))) {
1320 /* Age current mic Context */
1321 memcpy(&ai->mod[1].uCtx,&ai->mod[0].uCtx,sizeof(miccntx));
1322 /* Initialize new context */
1323 memcpy(&ai->mod[0].uCtx.key,mic_rid.unicast,sizeof(mic_rid.unicast));
1324
1325 ai->mod[0].uCtx.window = 33; //Window always points to the middle
1326 ai->mod[0].uCtx.rx = 0; //Rx Sequence numbers
1327 ai->mod[0].uCtx.tx = 0; //Tx sequence numbers
1328 ai->mod[0].uCtx.valid = 1; //Key is now valid
1329
1330 //Give key to mic seed
1331 emmh32_setseed(&ai->mod[0].uCtx.seed, mic_rid.unicast, sizeof(mic_rid.unicast), ai->tfm);
1332 }
1333 } else {
1334 /* So next time we have a valid key and mic is enabled, we will update
1335 * the sequence number if the key is the same as before.
1336 */
1337 ai->mod[0].uCtx.valid = 0;
1338 ai->mod[0].mCtx.valid = 0;
1339 }
1340}
1341
1342/* micsetup - Get ready for business */
1343
1344static int micsetup(struct airo_info *ai) {
1345 int i;
1346
1347 if (ai->tfm == NULL)
Herbert Xuf12cc202006-08-22 20:36:13 +10001348 ai->tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
Herbert Xuf12cc202006-08-22 20:36:13 +10001350 if (IS_ERR(ai->tfm)) {
Dan Williams934d8bf2006-03-16 13:46:23 -05001351 airo_print_err(ai->dev->name, "failed to load transform for AES");
Herbert Xuf12cc202006-08-22 20:36:13 +10001352 ai->tfm = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 return ERROR;
1354 }
1355
1356 for (i=0; i < NUM_MODULES; i++) {
1357 memset(&ai->mod[i].mCtx,0,sizeof(miccntx));
1358 memset(&ai->mod[i].uCtx,0,sizeof(miccntx));
1359 }
1360 return SUCCESS;
1361}
1362
Jouni Malinenff1d2762005-05-12 22:54:16 -04001363static char micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364
1365/*===========================================================================
1366 * Description: Mic a packet
1367 *
1368 * Inputs: etherHead * pointer to an 802.3 frame
1369 *
1370 * Returns: BOOLEAN if successful, otherwise false.
1371 * PacketTxLen will be updated with the mic'd packets size.
1372 *
1373 * Caveats: It is assumed that the frame buffer will already
1374 * be big enough to hold the largets mic message possible.
1375 * (No memory allocation is done here).
1376 *
1377 * Author: sbraneky (10/15/01)
1378 * Merciless hacks by rwilcher (1/14/02)
1379 */
1380
1381static int encapsulate(struct airo_info *ai ,etherHead *frame, MICBuffer *mic, int payLen)
1382{
1383 miccntx *context;
1384
1385 // Determine correct context
1386 // If not adhoc, always use unicast key
1387
1388 if (test_bit(FLAG_ADHOC, &ai->flags) && (frame->da[0] & 0x1))
1389 context = &ai->mod[0].mCtx;
1390 else
1391 context = &ai->mod[0].uCtx;
1392
1393 if (!context->valid)
1394 return ERROR;
1395
1396 mic->typelen = htons(payLen + 16); //Length of Mic'd packet
1397
1398 memcpy(&mic->u.snap, micsnap, sizeof(micsnap)); // Add Snap
1399
1400 // Add Tx sequence
1401 mic->seq = htonl(context->tx);
1402 context->tx += 2;
1403
1404 emmh32_init(&context->seed); // Mic the packet
1405 emmh32_update(&context->seed,frame->da,ETH_ALEN * 2); // DA,SA
1406 emmh32_update(&context->seed,(u8*)&mic->typelen,10); // Type/Length and Snap
1407 emmh32_update(&context->seed,(u8*)&mic->seq,sizeof(mic->seq)); //SEQ
1408 emmh32_update(&context->seed,frame->da + ETH_ALEN * 2,payLen); //payload
1409 emmh32_final(&context->seed, (u8*)&mic->mic);
1410
1411 /* New Type/length ?????????? */
1412 mic->typelen = 0; //Let NIC know it could be an oversized packet
1413 return SUCCESS;
1414}
1415
1416typedef enum {
1417 NONE,
1418 NOMIC,
1419 NOMICPLUMMED,
1420 SEQUENCE,
1421 INCORRECTMIC,
1422} mic_error;
1423
1424/*===========================================================================
1425 * Description: Decapsulates a MIC'd packet and returns the 802.3 packet
1426 * (removes the MIC stuff) if packet is a valid packet.
1427 *
1428 * Inputs: etherHead pointer to the 802.3 packet
1429 *
1430 * Returns: BOOLEAN - TRUE if packet should be dropped otherwise FALSE
1431 *
1432 * Author: sbraneky (10/15/01)
1433 * Merciless hacks by rwilcher (1/14/02)
1434 *---------------------------------------------------------------------------
1435 */
1436
1437static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *eth, u16 payLen)
1438{
1439 int i;
1440 u32 micSEQ;
1441 miccntx *context;
1442 u8 digest[4];
1443 mic_error micError = NONE;
1444
1445 // Check if the packet is a Mic'd packet
1446
1447 if (!ai->micstats.enabled) {
1448 //No Mic set or Mic OFF but we received a MIC'd packet.
1449 if (memcmp ((u8*)eth + 14, micsnap, sizeof(micsnap)) == 0) {
1450 ai->micstats.rxMICPlummed++;
1451 return ERROR;
1452 }
1453 return SUCCESS;
1454 }
1455
1456 if (ntohs(mic->typelen) == 0x888E)
1457 return SUCCESS;
1458
1459 if (memcmp (mic->u.snap, micsnap, sizeof(micsnap)) != 0) {
1460 // Mic enabled but packet isn't Mic'd
1461 ai->micstats.rxMICPlummed++;
1462 return ERROR;
1463 }
1464
1465 micSEQ = ntohl(mic->seq); //store SEQ as CPU order
1466
1467 //At this point we a have a mic'd packet and mic is enabled
1468 //Now do the mic error checking.
1469
1470 //Receive seq must be odd
1471 if ( (micSEQ & 1) == 0 ) {
1472 ai->micstats.rxWrongSequence++;
1473 return ERROR;
1474 }
1475
1476 for (i = 0; i < NUM_MODULES; i++) {
1477 int mcast = eth->da[0] & 1;
1478 //Determine proper context
1479 context = mcast ? &ai->mod[i].mCtx : &ai->mod[i].uCtx;
1480
1481 //Make sure context is valid
1482 if (!context->valid) {
1483 if (i == 0)
1484 micError = NOMICPLUMMED;
1485 continue;
1486 }
1487 //DeMic it
1488
1489 if (!mic->typelen)
1490 mic->typelen = htons(payLen + sizeof(MICBuffer) - 2);
1491
1492 emmh32_init(&context->seed);
1493 emmh32_update(&context->seed, eth->da, ETH_ALEN*2);
1494 emmh32_update(&context->seed, (u8 *)&mic->typelen, sizeof(mic->typelen)+sizeof(mic->u.snap));
1495 emmh32_update(&context->seed, (u8 *)&mic->seq,sizeof(mic->seq));
1496 emmh32_update(&context->seed, eth->da + ETH_ALEN*2,payLen);
1497 //Calculate MIC
1498 emmh32_final(&context->seed, digest);
1499
1500 if (memcmp(digest, &mic->mic, 4)) { //Make sure the mics match
1501 //Invalid Mic
1502 if (i == 0)
1503 micError = INCORRECTMIC;
1504 continue;
1505 }
1506
1507 //Check Sequence number if mics pass
1508 if (RxSeqValid(ai, context, mcast, micSEQ) == SUCCESS) {
1509 ai->micstats.rxSuccess++;
1510 return SUCCESS;
1511 }
1512 if (i == 0)
1513 micError = SEQUENCE;
1514 }
1515
1516 // Update statistics
1517 switch (micError) {
1518 case NOMICPLUMMED: ai->micstats.rxMICPlummed++; break;
1519 case SEQUENCE: ai->micstats.rxWrongSequence++; break;
1520 case INCORRECTMIC: ai->micstats.rxIncorrectMIC++; break;
1521 case NONE: break;
1522 case NOMIC: break;
1523 }
1524 return ERROR;
1525}
1526
1527/*===========================================================================
1528 * Description: Checks the Rx Seq number to make sure it is valid
1529 * and hasn't already been received
1530 *
1531 * Inputs: miccntx - mic context to check seq against
1532 * micSeq - the Mic seq number
1533 *
1534 * Returns: TRUE if valid otherwise FALSE.
1535 *
1536 * Author: sbraneky (10/15/01)
1537 * Merciless hacks by rwilcher (1/14/02)
1538 *---------------------------------------------------------------------------
1539 */
1540
1541static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq)
1542{
1543 u32 seq,index;
1544
1545 //Allow for the ap being rebooted - if it is then use the next
1546 //sequence number of the current sequence number - might go backwards
1547
1548 if (mcast) {
1549 if (test_bit(FLAG_UPDATE_MULTI, &ai->flags)) {
1550 clear_bit (FLAG_UPDATE_MULTI, &ai->flags);
1551 context->window = (micSeq > 33) ? micSeq : 33;
1552 context->rx = 0; // Reset rx
1553 }
1554 } else if (test_bit(FLAG_UPDATE_UNI, &ai->flags)) {
1555 clear_bit (FLAG_UPDATE_UNI, &ai->flags);
1556 context->window = (micSeq > 33) ? micSeq : 33; // Move window
1557 context->rx = 0; // Reset rx
1558 }
1559
1560 //Make sequence number relative to START of window
1561 seq = micSeq - (context->window - 33);
1562
1563 //Too old of a SEQ number to check.
1564 if ((s32)seq < 0)
1565 return ERROR;
1566
1567 if ( seq > 64 ) {
1568 //Window is infinite forward
1569 MoveWindow(context,micSeq);
1570 return SUCCESS;
1571 }
1572
1573 // We are in the window. Now check the context rx bit to see if it was already sent
1574 seq >>= 1; //divide by 2 because we only have odd numbers
1575 index = 1 << seq; //Get an index number
1576
1577 if (!(context->rx & index)) {
1578 //micSEQ falls inside the window.
1579 //Add seqence number to the list of received numbers.
1580 context->rx |= index;
1581
1582 MoveWindow(context,micSeq);
1583
1584 return SUCCESS;
1585 }
1586 return ERROR;
1587}
1588
1589static void MoveWindow(miccntx *context, u32 micSeq)
1590{
1591 u32 shift;
1592
1593 //Move window if seq greater than the middle of the window
1594 if (micSeq > context->window) {
1595 shift = (micSeq - context->window) >> 1;
1596
1597 //Shift out old
1598 if (shift < 32)
1599 context->rx >>= shift;
1600 else
1601 context->rx = 0;
1602
1603 context->window = micSeq; //Move window
1604 }
1605}
1606
1607/*==============================================*/
1608/*========== EMMH ROUTINES ====================*/
1609/*==============================================*/
1610
1611/* mic accumulate */
1612#define MIC_ACCUM(val) \
1613 context->accum += (u64)(val) * context->coeff[coeff_position++];
1614
1615static unsigned char aes_counter[16];
1616
1617/* expand the key to fill the MMH coefficient array */
Herbert Xuf12cc202006-08-22 20:36:13 +10001618static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
1619 struct crypto_cipher *tfm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620{
1621 /* take the keying material, expand if necessary, truncate at 16-bytes */
1622 /* run through AES counter mode to generate context->coeff[] */
1623
1624 int i,j;
1625 u32 counter;
1626 u8 *cipher, plain[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627
1628 crypto_cipher_setkey(tfm, pkey, 16);
1629 counter = 0;
Ahmed S. Darwishe7c04fd2007-02-05 18:58:29 +02001630 for (i = 0; i < ARRAY_SIZE(context->coeff); ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 aes_counter[15] = (u8)(counter >> 0);
1632 aes_counter[14] = (u8)(counter >> 8);
1633 aes_counter[13] = (u8)(counter >> 16);
1634 aes_counter[12] = (u8)(counter >> 24);
1635 counter++;
1636 memcpy (plain, aes_counter, 16);
Herbert Xuf12cc202006-08-22 20:36:13 +10001637 crypto_cipher_encrypt_one(tfm, plain, plain);
1638 cipher = plain;
Ahmed S. Darwishe7c04fd2007-02-05 18:58:29 +02001639 for (j = 0; (j < 16) && (i < ARRAY_SIZE(context->coeff)); ) {
Al Viro593c2b92007-12-17 15:09:34 -05001640 context->coeff[i++] = ntohl(*(__be32 *)&cipher[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 j += 4;
1642 }
1643 }
1644}
1645
1646/* prepare for calculation of a new mic */
Jouni Malinenff1d2762005-05-12 22:54:16 -04001647static void emmh32_init(emmh32_context *context)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648{
1649 /* prepare for new mic calculation */
1650 context->accum = 0;
1651 context->position = 0;
1652}
1653
1654/* add some bytes to the mic calculation */
Jouni Malinenff1d2762005-05-12 22:54:16 -04001655static void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656{
1657 int coeff_position, byte_position;
1658
1659 if (len == 0) return;
1660
1661 coeff_position = context->position >> 2;
1662
1663 /* deal with partial 32-bit word left over from last update */
1664 byte_position = context->position & 3;
1665 if (byte_position) {
1666 /* have a partial word in part to deal with */
1667 do {
1668 if (len == 0) return;
1669 context->part.d8[byte_position++] = *pOctets++;
1670 context->position++;
1671 len--;
1672 } while (byte_position < 4);
Al Viro593c2b92007-12-17 15:09:34 -05001673 MIC_ACCUM(ntohl(context->part.d32));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 }
1675
1676 /* deal with full 32-bit words */
1677 while (len >= 4) {
Al Viro593c2b92007-12-17 15:09:34 -05001678 MIC_ACCUM(ntohl(*(__be32 *)pOctets));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 context->position += 4;
1680 pOctets += 4;
1681 len -= 4;
1682 }
1683
1684 /* deal with partial 32-bit word that will be left over from this update */
1685 byte_position = 0;
1686 while (len > 0) {
1687 context->part.d8[byte_position++] = *pOctets++;
1688 context->position++;
1689 len--;
1690 }
1691}
1692
1693/* mask used to zero empty bytes for final partial word */
1694static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L };
1695
1696/* calculate the mic */
Jouni Malinenff1d2762005-05-12 22:54:16 -04001697static void emmh32_final(emmh32_context *context, u8 digest[4])
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698{
1699 int coeff_position, byte_position;
1700 u32 val;
1701
1702 u64 sum, utmp;
1703 s64 stmp;
1704
1705 coeff_position = context->position >> 2;
1706
1707 /* deal with partial 32-bit word left over from last update */
1708 byte_position = context->position & 3;
1709 if (byte_position) {
1710 /* have a partial word in part to deal with */
Al Viro593c2b92007-12-17 15:09:34 -05001711 val = ntohl(context->part.d32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 MIC_ACCUM(val & mask32[byte_position]); /* zero empty bytes */
1713 }
1714
1715 /* reduce the accumulated u64 to a 32-bit MIC */
1716 sum = context->accum;
1717 stmp = (sum & 0xffffffffLL) - ((sum >> 32) * 15);
1718 utmp = (stmp & 0xffffffffLL) - ((stmp >> 32) * 15);
1719 sum = utmp & 0xffffffffLL;
1720 if (utmp > 0x10000000fLL)
1721 sum -= 15;
1722
1723 val = (u32)sum;
1724 digest[0] = (val>>24) & 0xFF;
1725 digest[1] = (val>>16) & 0xFF;
1726 digest[2] = (val>>8) & 0xFF;
1727 digest[3] = val & 0xFF;
1728}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
1730static int readBSSListRid(struct airo_info *ai, int first,
Al Viro17e70492007-12-19 18:56:37 -05001731 BSSListRid *list)
1732{
Dan Williams3c304952006-04-15 12:26:18 -04001733 Cmd cmd;
1734 Resp rsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735
1736 if (first == 1) {
Dan Williams3c304952006-04-15 12:26:18 -04001737 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
1738 memset(&cmd, 0, sizeof(cmd));
1739 cmd.cmd=CMD_LISTBSS;
1740 if (down_interruptible(&ai->sem))
1741 return -ERESTARTSYS;
Sukadev Bhattiprolu3b4c7d642006-08-14 23:12:03 -07001742 ai->list_bss_task = current;
Dan Williams3c304952006-04-15 12:26:18 -04001743 issuecommand(ai, &cmd, &rsp);
1744 up(&ai->sem);
1745 /* Let the command take effect */
Sukadev Bhattiprolu3b4c7d642006-08-14 23:12:03 -07001746 schedule_timeout_uninterruptible(3 * HZ);
1747 ai->list_bss_task = NULL;
Dan Williams3c304952006-04-15 12:26:18 -04001748 }
Al Viro17e70492007-12-19 18:56:37 -05001749 return PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
Dan Williams3c304952006-04-15 12:26:18 -04001750 list, ai->bssListRidLen, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751}
1752
Al Viro4293ea32007-12-19 19:21:51 -05001753static int readWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int temp, int lock)
1754{
1755 return PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 wkr, sizeof(*wkr), lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758
Al Viro4293ea32007-12-19 19:21:51 -05001759static int writeWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int perm, int lock)
1760{
1761 int rc;
1762 rc = PC4500_writerid(ai, RID_WEP_TEMP, wkr, sizeof(*wkr), lock);
1763 if (rc!=SUCCESS)
1764 airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 if (perm) {
Al Viro4293ea32007-12-19 19:21:51 -05001766 rc = PC4500_writerid(ai, RID_WEP_PERM, wkr, sizeof(*wkr), lock);
1767 if (rc!=SUCCESS)
Dan Williams934d8bf2006-03-16 13:46:23 -05001768 airo_print_err(ai->dev->name, "WEP_PERM set %x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 }
1770 return rc;
1771}
1772
Al Viro0dd22122007-12-17 16:11:57 -05001773static int readSsidRid(struct airo_info*ai, SsidRid *ssidr)
1774{
1775 return PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
Al Viro0dd22122007-12-17 16:11:57 -05001778static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock)
1779{
1780 return PC4500_writerid(ai, RID_SSID, pssidr, sizeof(*pssidr), lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781}
Al Viro0dd22122007-12-17 16:11:57 -05001782
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783static int readConfigRid(struct airo_info*ai, int lock) {
1784 int rc;
1785 u16 *s;
1786 ConfigRid cfg;
1787
1788 if (ai->config.len)
1789 return SUCCESS;
1790
1791 rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock);
1792 if (rc != SUCCESS)
1793 return rc;
1794
1795 for(s = &cfg.len; s <= &cfg.rtsThres; s++) *s = le16_to_cpu(*s);
1796
1797 for(s = &cfg.shortRetryLimit; s <= &cfg.radioType; s++)
1798 *s = le16_to_cpu(*s);
1799
1800 for(s = &cfg.txPower; s <= &cfg.radioSpecific; s++)
1801 *s = le16_to_cpu(*s);
1802
1803 for(s = &cfg.arlThreshold; s <= &cfg._reserved4[0]; s++)
1804 *s = cpu_to_le16(*s);
1805
1806 for(s = &cfg.autoWake; s <= &cfg.autoWake; s++)
1807 *s = cpu_to_le16(*s);
1808
1809 ai->config = cfg;
1810 return SUCCESS;
1811}
1812static inline void checkThrottle(struct airo_info *ai) {
1813 int i;
1814/* Old hardware had a limit on encryption speed */
1815 if (ai->config.authType != AUTH_OPEN && maxencrypt) {
1816 for(i=0; i<8; i++) {
1817 if (ai->config.rates[i] > maxencrypt) {
1818 ai->config.rates[i] = 0;
1819 }
1820 }
1821 }
1822}
1823static int writeConfigRid(struct airo_info*ai, int lock) {
1824 u16 *s;
1825 ConfigRid cfgr;
1826
1827 if (!test_bit (FLAG_COMMIT, &ai->flags))
1828 return SUCCESS;
1829
1830 clear_bit (FLAG_COMMIT, &ai->flags);
1831 clear_bit (FLAG_RESET, &ai->flags);
1832 checkThrottle(ai);
1833 cfgr = ai->config;
1834
1835 if ((cfgr.opmode & 0xFF) == MODE_STA_IBSS)
1836 set_bit(FLAG_ADHOC, &ai->flags);
1837 else
1838 clear_bit(FLAG_ADHOC, &ai->flags);
1839
1840 for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s);
1841
1842 for(s = &cfgr.shortRetryLimit; s <= &cfgr.radioType; s++)
1843 *s = cpu_to_le16(*s);
1844
1845 for(s = &cfgr.txPower; s <= &cfgr.radioSpecific; s++)
1846 *s = cpu_to_le16(*s);
1847
1848 for(s = &cfgr.arlThreshold; s <= &cfgr._reserved4[0]; s++)
1849 *s = cpu_to_le16(*s);
1850
1851 for(s = &cfgr.autoWake; s <= &cfgr.autoWake; s++)
1852 *s = cpu_to_le16(*s);
1853
1854 return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock);
1855}
1856static int readStatusRid(struct airo_info*ai, StatusRid *statr, int lock) {
1857 int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock);
1858 u16 *s;
1859
1860 statr->len = le16_to_cpu(statr->len);
1861 for(s = &statr->mode; s <= &statr->SSIDlen; s++) *s = le16_to_cpu(*s);
1862
1863 for(s = &statr->beaconPeriod; s <= &statr->shortPreamble; s++)
1864 *s = le16_to_cpu(*s);
1865 statr->load = le16_to_cpu(statr->load);
1866 statr->assocStatus = le16_to_cpu(statr->assocStatus);
1867 return rc;
1868}
1869static int readAPListRid(struct airo_info*ai, APListRid *aplr) {
1870 int rc = PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr), 1);
1871 aplr->len = le16_to_cpu(aplr->len);
1872 return rc;
1873}
1874static int writeAPListRid(struct airo_info*ai, APListRid *aplr, int lock) {
1875 int rc;
1876 aplr->len = cpu_to_le16(aplr->len);
1877 rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock);
1878 return rc;
1879}
1880static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr, int lock) {
1881 int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock);
1882 u16 *s;
1883
1884 capr->len = le16_to_cpu(capr->len);
1885 capr->prodNum = le16_to_cpu(capr->prodNum);
1886 capr->radioType = le16_to_cpu(capr->radioType);
1887 capr->country = le16_to_cpu(capr->country);
1888 for(s = &capr->txPowerLevels[0]; s <= &capr->requiredHard; s++)
1889 *s = le16_to_cpu(*s);
1890 return rc;
1891}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892
Al Viroa23ace52007-12-19 22:24:16 -05001893static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock)
1894{
1895 return PC4500_readrid(ai, rid, sr, sizeof(*sr), lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896}
1897
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001898static void try_auto_wep(struct airo_info *ai)
1899{
1900 if (auto_wep && !(ai->flags & FLAG_RADIO_DOWN)) {
1901 ai->expires = RUN_AT(3*HZ);
1902 wake_up_interruptible(&ai->thr_wait);
1903 }
1904}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001906static int airo_open(struct net_device *dev) {
1907 struct airo_info *ai = dev->priv;
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001908 int rc = 0;
1909
1910 if (test_bit(FLAG_FLASHING, &ai->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 return -EIO;
1912
1913 /* Make sure the card is configured.
1914 * Wireless Extensions may postpone config changes until the card
1915 * is open (to pipeline changes and speed-up card setup). If
1916 * those changes are not yet commited, do it now - Jean II */
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001917 if (test_bit(FLAG_COMMIT, &ai->flags)) {
1918 disable_MAC(ai, 1);
1919 writeConfigRid(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 }
1921
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001922 if (ai->wifidev != dev) {
1923 clear_bit(JOB_DIE, &ai->jobs);
1924 ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name);
1925 if (IS_ERR(ai->airo_thread_task))
1926 return (int)PTR_ERR(ai->airo_thread_task);
1927
1928 rc = request_irq(dev->irq, airo_interrupt, IRQF_SHARED,
1929 dev->name, dev);
1930 if (rc) {
1931 airo_print_err(dev->name,
1932 "register interrupt %d failed, rc %d",
1933 dev->irq, rc);
1934 set_bit(JOB_DIE, &ai->jobs);
1935 kthread_stop(ai->airo_thread_task);
1936 return rc;
1937 }
1938
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 /* Power on the MAC controller (which may have been disabled) */
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001940 clear_bit(FLAG_RADIO_DOWN, &ai->flags);
1941 enable_interrupts(ai);
1942
1943 try_auto_wep(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 }
Michal Schmidt175ec1a2007-06-29 15:33:47 +02001945 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946
1947 netif_start_queue(dev);
1948 return 0;
1949}
1950
1951static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
1952 int npacks, pending;
1953 unsigned long flags;
1954 struct airo_info *ai = dev->priv;
1955
1956 if (!skb) {
Dan Williams934d8bf2006-03-16 13:46:23 -05001957 airo_print_err(dev->name, "%s: skb == NULL!",__FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 return 0;
1959 }
1960 npacks = skb_queue_len (&ai->txq);
1961
1962 if (npacks >= MAXTXQ - 1) {
1963 netif_stop_queue (dev);
1964 if (npacks > MAXTXQ) {
1965 ai->stats.tx_fifo_errors++;
1966 return 1;
1967 }
1968 skb_queue_tail (&ai->txq, skb);
1969 return 0;
1970 }
1971
1972 spin_lock_irqsave(&ai->aux_lock, flags);
1973 skb_queue_tail (&ai->txq, skb);
1974 pending = test_bit(FLAG_PENDING_XMIT, &ai->flags);
1975 spin_unlock_irqrestore(&ai->aux_lock,flags);
1976 netif_wake_queue (dev);
1977
1978 if (pending == 0) {
1979 set_bit(FLAG_PENDING_XMIT, &ai->flags);
1980 mpi_send_packet (dev);
1981 }
1982 return 0;
1983}
1984
1985/*
1986 * @mpi_send_packet
1987 *
1988 * Attempt to transmit a packet. Can be called from interrupt
1989 * or transmit . return number of packets we tried to send
1990 */
1991
1992static int mpi_send_packet (struct net_device *dev)
1993{
1994 struct sk_buff *skb;
1995 unsigned char *buffer;
Al Viro593c2b92007-12-17 15:09:34 -05001996 s16 len;
1997 __le16 *payloadLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 struct airo_info *ai = dev->priv;
1999 u8 *sendbuf;
2000
2001 /* get a packet to send */
2002
Al Viro79ea13c2008-01-24 02:06:46 -08002003 if ((skb = skb_dequeue(&ai->txq)) == NULL) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002004 airo_print_err(dev->name,
2005 "%s: Dequeue'd zero in send_packet()",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 __FUNCTION__);
2007 return 0;
2008 }
2009
2010 /* check min length*/
2011 len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
2012 buffer = skb->data;
2013
2014 ai->txfids[0].tx_desc.offset = 0;
2015 ai->txfids[0].tx_desc.valid = 1;
2016 ai->txfids[0].tx_desc.eoc = 1;
2017 ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr);
2018
2019/*
2020 * Magic, the cards firmware needs a length count (2 bytes) in the host buffer
2021 * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen
2022 * is immediatly after it. ------------------------------------------------
2023 * |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA|
2024 * ------------------------------------------------
2025 */
2026
2027 memcpy((char *)ai->txfids[0].virtual_host_addr,
2028 (char *)&wifictlhdr8023, sizeof(wifictlhdr8023));
2029
Al Viro593c2b92007-12-17 15:09:34 -05002030 payloadLen = (__le16 *)(ai->txfids[0].virtual_host_addr +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 sizeof(wifictlhdr8023));
2032 sendbuf = ai->txfids[0].virtual_host_addr +
2033 sizeof(wifictlhdr8023) + 2 ;
2034
2035 /*
2036 * Firmware automaticly puts 802 header on so
2037 * we don't need to account for it in the length
2038 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
Al Viro593c2b92007-12-17 15:09:34 -05002040 (ntohs(((__be16 *)buffer)[6]) != 0x888E)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 MICBuffer pMic;
2042
2043 if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS)
2044 return ERROR;
2045
2046 *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic));
2047 ai->txfids[0].tx_desc.len += sizeof(pMic);
2048 /* copy data into airo dma buffer */
2049 memcpy (sendbuf, buffer, sizeof(etherHead));
2050 buffer += sizeof(etherHead);
2051 sendbuf += sizeof(etherHead);
2052 memcpy (sendbuf, &pMic, sizeof(pMic));
2053 sendbuf += sizeof(pMic);
2054 memcpy (sendbuf, buffer, len - sizeof(etherHead));
Adrian Bunka39d3e72006-01-21 01:35:15 +01002055 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 *payloadLen = cpu_to_le16(len - sizeof(etherHead));
2057
2058 dev->trans_start = jiffies;
2059
2060 /* copy data into airo dma buffer */
2061 memcpy(sendbuf, buffer, len);
2062 }
2063
2064 memcpy_toio(ai->txfids[0].card_ram_off,
2065 &ai->txfids[0].tx_desc, sizeof(TxFid));
2066
2067 OUT4500(ai, EVACK, 8);
2068
2069 dev_kfree_skb_any(skb);
2070 return 1;
2071}
2072
Gabriel A. Devenyi29b09fc2005-11-03 19:30:47 -05002073static void get_tx_error(struct airo_info *ai, s32 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074{
Al Viro593c2b92007-12-17 15:09:34 -05002075 __le16 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076
2077 if (fid < 0)
2078 status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status;
2079 else {
2080 if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) != SUCCESS)
2081 return;
2082 bap_read(ai, &status, 2, BAP0);
2083 }
2084 if (le16_to_cpu(status) & 2) /* Too many retries */
2085 ai->stats.tx_aborted_errors++;
2086 if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */
2087 ai->stats.tx_heartbeat_errors++;
2088 if (le16_to_cpu(status) & 8) /* Aid fail */
2089 { }
2090 if (le16_to_cpu(status) & 0x10) /* MAC disabled */
2091 ai->stats.tx_carrier_errors++;
2092 if (le16_to_cpu(status) & 0x20) /* Association lost */
2093 { }
2094 /* We produce a TXDROP event only for retry or lifetime
2095 * exceeded, because that's the only status that really mean
2096 * that this particular node went away.
2097 * Other errors means that *we* screwed up. - Jean II */
2098 if ((le16_to_cpu(status) & 2) ||
2099 (le16_to_cpu(status) & 4)) {
2100 union iwreq_data wrqu;
2101 char junk[0x18];
2102
2103 /* Faster to skip over useless data than to do
2104 * another bap_setup(). We are at offset 0x6 and
2105 * need to go to 0x18 and read 6 bytes - Jean II */
Al Virob8c06bc2007-12-19 17:55:43 -05002106 bap_read(ai, (__le16 *) junk, 0x18, BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107
2108 /* Copy 802.11 dest address.
2109 * We use the 802.11 header because the frame may
2110 * not be 802.3 or may be mangled...
2111 * In Ad-Hoc mode, it will be the node address.
2112 * In managed mode, it will be most likely the AP addr
2113 * User space will figure out how to convert it to
2114 * whatever it needs (IP address or else).
2115 * - Jean II */
2116 memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN);
2117 wrqu.addr.sa_family = ARPHRD_ETHER;
2118
2119 /* Send event to user space */
2120 wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL);
2121 }
2122}
2123
2124static void airo_end_xmit(struct net_device *dev) {
2125 u16 status;
2126 int i;
2127 struct airo_info *priv = dev->priv;
2128 struct sk_buff *skb = priv->xmit.skb;
2129 int fid = priv->xmit.fid;
2130 u32 *fids = priv->fids;
2131
Dan Williams3c304952006-04-15 12:26:18 -04002132 clear_bit(JOB_XMIT, &priv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 clear_bit(FLAG_PENDING_XMIT, &priv->flags);
2134 status = transmit_802_3_packet (priv, fids[fid], skb->data);
2135 up(&priv->sem);
2136
2137 i = 0;
2138 if ( status == SUCCESS ) {
2139 dev->trans_start = jiffies;
2140 for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++);
2141 } else {
2142 priv->fids[fid] &= 0xffff;
2143 priv->stats.tx_window_errors++;
2144 }
2145 if (i < MAX_FIDS / 2)
2146 netif_wake_queue(dev);
2147 dev_kfree_skb(skb);
2148}
2149
2150static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
2151 s16 len;
2152 int i, j;
2153 struct airo_info *priv = dev->priv;
2154 u32 *fids = priv->fids;
2155
2156 if ( skb == NULL ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002157 airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 return 0;
2159 }
2160
2161 /* Find a vacant FID */
2162 for( i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++ );
2163 for( j = i + 1; j < MAX_FIDS / 2 && (fids[j] & 0xffff0000); j++ );
2164
2165 if ( j >= MAX_FIDS / 2 ) {
2166 netif_stop_queue(dev);
2167
2168 if (i == MAX_FIDS / 2) {
2169 priv->stats.tx_fifo_errors++;
2170 return 1;
2171 }
2172 }
2173 /* check min length*/
2174 len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
2175 /* Mark fid as used & save length for later */
2176 fids[i] |= (len << 16);
2177 priv->xmit.skb = skb;
2178 priv->xmit.fid = i;
2179 if (down_trylock(&priv->sem) != 0) {
2180 set_bit(FLAG_PENDING_XMIT, &priv->flags);
2181 netif_stop_queue(dev);
Dan Williams3c304952006-04-15 12:26:18 -04002182 set_bit(JOB_XMIT, &priv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 wake_up_interruptible(&priv->thr_wait);
2184 } else
2185 airo_end_xmit(dev);
2186 return 0;
2187}
2188
2189static void airo_end_xmit11(struct net_device *dev) {
2190 u16 status;
2191 int i;
2192 struct airo_info *priv = dev->priv;
2193 struct sk_buff *skb = priv->xmit11.skb;
2194 int fid = priv->xmit11.fid;
2195 u32 *fids = priv->fids;
2196
Dan Williams3c304952006-04-15 12:26:18 -04002197 clear_bit(JOB_XMIT11, &priv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 clear_bit(FLAG_PENDING_XMIT11, &priv->flags);
2199 status = transmit_802_11_packet (priv, fids[fid], skb->data);
2200 up(&priv->sem);
2201
2202 i = MAX_FIDS / 2;
2203 if ( status == SUCCESS ) {
2204 dev->trans_start = jiffies;
2205 for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++);
2206 } else {
2207 priv->fids[fid] &= 0xffff;
2208 priv->stats.tx_window_errors++;
2209 }
2210 if (i < MAX_FIDS)
2211 netif_wake_queue(dev);
2212 dev_kfree_skb(skb);
2213}
2214
2215static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
2216 s16 len;
2217 int i, j;
2218 struct airo_info *priv = dev->priv;
2219 u32 *fids = priv->fids;
2220
2221 if (test_bit(FLAG_MPI, &priv->flags)) {
2222 /* Not implemented yet for MPI350 */
2223 netif_stop_queue(dev);
2224 return -ENETDOWN;
2225 }
2226
2227 if ( skb == NULL ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002228 airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 return 0;
2230 }
2231
2232 /* Find a vacant FID */
2233 for( i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++ );
2234 for( j = i + 1; j < MAX_FIDS && (fids[j] & 0xffff0000); j++ );
2235
2236 if ( j >= MAX_FIDS ) {
2237 netif_stop_queue(dev);
2238
2239 if (i == MAX_FIDS) {
2240 priv->stats.tx_fifo_errors++;
2241 return 1;
2242 }
2243 }
2244 /* check min length*/
2245 len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
2246 /* Mark fid as used & save length for later */
2247 fids[i] |= (len << 16);
2248 priv->xmit11.skb = skb;
2249 priv->xmit11.fid = i;
2250 if (down_trylock(&priv->sem) != 0) {
2251 set_bit(FLAG_PENDING_XMIT11, &priv->flags);
2252 netif_stop_queue(dev);
Dan Williams3c304952006-04-15 12:26:18 -04002253 set_bit(JOB_XMIT11, &priv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 wake_up_interruptible(&priv->thr_wait);
2255 } else
2256 airo_end_xmit11(dev);
2257 return 0;
2258}
2259
Al Viroa23ace52007-12-19 22:24:16 -05002260static void airo_read_stats(struct airo_info *ai)
2261{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 StatsRid stats_rid;
Al Viroa23ace52007-12-19 22:24:16 -05002263 __le32 *vals = stats_rid.vals;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264
Dan Williams3c304952006-04-15 12:26:18 -04002265 clear_bit(JOB_STATS, &ai->jobs);
Pavel Machekca078ba2005-09-03 15:56:57 -07002266 if (ai->power.event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 up(&ai->sem);
2268 return;
2269 }
2270 readStatsRid(ai, &stats_rid, RID_STATS, 0);
2271 up(&ai->sem);
2272
Al Viroa23ace52007-12-19 22:24:16 -05002273 ai->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) +
2274 le32_to_cpu(vals[45]);
2275 ai->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) +
2276 le32_to_cpu(vals[41]);
2277 ai->stats.rx_bytes = le32_to_cpu(vals[92]);
2278 ai->stats.tx_bytes = le32_to_cpu(vals[91]);
2279 ai->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) +
2280 le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]);
2281 ai->stats.tx_errors = le32_to_cpu(vals[42]) + ai->stats.tx_fifo_errors;
2282 ai->stats.multicast = le32_to_cpu(vals[43]);
2283 ai->stats.collisions = le32_to_cpu(vals[89]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284
2285 /* detailed rx_errors: */
Al Viroa23ace52007-12-19 22:24:16 -05002286 ai->stats.rx_length_errors = le32_to_cpu(vals[3]);
2287 ai->stats.rx_crc_errors = le32_to_cpu(vals[4]);
2288 ai->stats.rx_frame_errors = le32_to_cpu(vals[2]);
2289 ai->stats.rx_fifo_errors = le32_to_cpu(vals[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290}
2291
Jouni Malinenff1d2762005-05-12 22:54:16 -04002292static struct net_device_stats *airo_get_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293{
2294 struct airo_info *local = dev->priv;
2295
Dan Williams3c304952006-04-15 12:26:18 -04002296 if (!test_bit(JOB_STATS, &local->jobs)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 /* Get stats out of the card if available */
2298 if (down_trylock(&local->sem) != 0) {
Dan Williams3c304952006-04-15 12:26:18 -04002299 set_bit(JOB_STATS, &local->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 wake_up_interruptible(&local->thr_wait);
2301 } else
2302 airo_read_stats(local);
2303 }
2304
2305 return &local->stats;
2306}
2307
2308static void airo_set_promisc(struct airo_info *ai) {
2309 Cmd cmd;
2310 Resp rsp;
2311
2312 memset(&cmd, 0, sizeof(cmd));
2313 cmd.cmd=CMD_SETMODE;
Dan Williams3c304952006-04-15 12:26:18 -04002314 clear_bit(JOB_PROMISC, &ai->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
2316 issuecommand(ai, &cmd, &rsp);
2317 up(&ai->sem);
2318}
2319
2320static void airo_set_multicast_list(struct net_device *dev) {
2321 struct airo_info *ai = dev->priv;
2322
2323 if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
2324 change_bit(FLAG_PROMISC, &ai->flags);
2325 if (down_trylock(&ai->sem) != 0) {
Dan Williams3c304952006-04-15 12:26:18 -04002326 set_bit(JOB_PROMISC, &ai->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 wake_up_interruptible(&ai->thr_wait);
2328 } else
2329 airo_set_promisc(ai);
2330 }
2331
2332 if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) {
2333 /* Turn on multicast. (Should be already setup...) */
2334 }
2335}
2336
2337static int airo_set_mac_address(struct net_device *dev, void *p)
2338{
2339 struct airo_info *ai = dev->priv;
2340 struct sockaddr *addr = p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341
2342 readConfigRid(ai, 1);
2343 memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
2344 set_bit (FLAG_COMMIT, &ai->flags);
2345 disable_MAC(ai, 1);
2346 writeConfigRid (ai, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02002347 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 memcpy (ai->dev->dev_addr, addr->sa_data, dev->addr_len);
2349 if (ai->wifidev)
2350 memcpy (ai->wifidev->dev_addr, addr->sa_data, dev->addr_len);
2351 return 0;
2352}
2353
2354static int airo_change_mtu(struct net_device *dev, int new_mtu)
2355{
2356 if ((new_mtu < 68) || (new_mtu > 2400))
2357 return -EINVAL;
2358 dev->mtu = new_mtu;
2359 return 0;
2360}
2361
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01002362static LIST_HEAD(airo_devices);
2363
2364static void add_airo_dev(struct airo_info *ai)
2365{
2366 /* Upper layers already keep track of PCI devices,
2367 * so we only need to remember our non-PCI cards. */
2368 if (!ai->pci)
2369 list_add_tail(&ai->dev_list, &airo_devices);
2370}
2371
2372static void del_airo_dev(struct airo_info *ai)
2373{
2374 if (!ai->pci)
2375 list_del(&ai->dev_list);
2376}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377
2378static int airo_close(struct net_device *dev) {
2379 struct airo_info *ai = dev->priv;
2380
2381 netif_stop_queue(dev);
2382
2383 if (ai->wifidev != dev) {
2384#ifdef POWER_ON_DOWN
2385 /* Shut power to the card. The idea is that the user can save
2386 * power when he doesn't need the card with "ifconfig down".
2387 * That's the method that is most friendly towards the network
2388 * stack (i.e. the network stack won't try to broadcast
2389 * anything on the interface and routes are gone. Jean II */
2390 set_bit(FLAG_RADIO_DOWN, &ai->flags);
2391 disable_MAC(ai, 1);
2392#endif
2393 disable_interrupts( ai );
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02002394
2395 free_irq(dev->irq, dev);
2396
2397 set_bit(JOB_DIE, &ai->jobs);
2398 kthread_stop(ai->airo_thread_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 }
2400 return 0;
2401}
2402
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403void stop_airo_card( struct net_device *dev, int freeres )
2404{
2405 struct airo_info *ai = dev->priv;
2406
2407 set_bit(FLAG_RADIO_DOWN, &ai->flags);
2408 disable_MAC(ai, 1);
2409 disable_interrupts(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 takedown_proc_entry( dev, ai );
2411 if (test_bit(FLAG_REGISTERED, &ai->flags)) {
2412 unregister_netdev( dev );
2413 if (ai->wifidev) {
2414 unregister_netdev(ai->wifidev);
2415 free_netdev(ai->wifidev);
2416 ai->wifidev = NULL;
2417 }
2418 clear_bit(FLAG_REGISTERED, &ai->flags);
2419 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 /*
2421 * Clean out tx queue
2422 */
David S. Millerb03efcf2005-07-08 14:57:23 -07002423 if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 struct sk_buff *skb = NULL;
2425 for (;(skb = skb_dequeue(&ai->txq));)
2426 dev_kfree_skb(skb);
2427 }
2428
Dan Williams9e75af32006-03-16 13:46:29 -05002429 airo_networks_free (ai);
2430
Jesper Juhlb4558ea2005-10-28 16:53:13 -04002431 kfree(ai->flash);
2432 kfree(ai->rssi);
2433 kfree(ai->APList);
2434 kfree(ai->SSID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 if (freeres) {
2436 /* PCMCIA frees this stuff, so only for PCI and ISA */
2437 release_region( dev->base_addr, 64 );
2438 if (test_bit(FLAG_MPI, &ai->flags)) {
2439 if (ai->pci)
2440 mpi_unmap_card(ai->pci);
2441 if (ai->pcimem)
2442 iounmap(ai->pcimem);
2443 if (ai->pciaux)
2444 iounmap(ai->pciaux);
2445 pci_free_consistent(ai->pci, PCI_SHARED_LEN,
2446 ai->shared, ai->shared_dma);
2447 }
2448 }
Herbert Xuf12cc202006-08-22 20:36:13 +10002449 crypto_free_cipher(ai->tfm);
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01002450 del_airo_dev(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 free_netdev( dev );
2452}
2453
2454EXPORT_SYMBOL(stop_airo_card);
2455
Stephen Hemmingerb95cce32007-09-26 22:13:38 -07002456static int wll_header_parse(const struct sk_buff *skb, unsigned char *haddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457{
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -07002458 memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 return ETH_ALEN;
2460}
2461
2462static void mpi_unmap_card(struct pci_dev *pci)
2463{
2464 unsigned long mem_start = pci_resource_start(pci, 1);
2465 unsigned long mem_len = pci_resource_len(pci, 1);
2466 unsigned long aux_start = pci_resource_start(pci, 2);
2467 unsigned long aux_len = AUXMEMSIZE;
2468
2469 release_mem_region(aux_start, aux_len);
2470 release_mem_region(mem_start, mem_len);
2471}
2472
2473/*************************************************************
2474 * This routine assumes that descriptors have been setup .
2475 * Run at insmod time or after reset when the decriptors
2476 * have been initialized . Returns 0 if all is well nz
2477 * otherwise . Does not allocate memory but sets up card
2478 * using previously allocated descriptors.
2479 */
2480static int mpi_init_descriptors (struct airo_info *ai)
2481{
2482 Cmd cmd;
2483 Resp rsp;
2484 int i;
2485 int rc = SUCCESS;
2486
2487 /* Alloc card RX descriptors */
2488 netif_stop_queue(ai->dev);
2489
2490 memset(&rsp,0,sizeof(rsp));
2491 memset(&cmd,0,sizeof(cmd));
2492
2493 cmd.cmd = CMD_ALLOCATEAUX;
2494 cmd.parm0 = FID_RX;
2495 cmd.parm1 = (ai->rxfids[0].card_ram_off - ai->pciaux);
2496 cmd.parm2 = MPI_MAX_FIDS;
2497 rc=issuecommand(ai, &cmd, &rsp);
2498 if (rc != SUCCESS) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002499 airo_print_err(ai->dev->name, "Couldn't allocate RX FID");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 return rc;
2501 }
2502
2503 for (i=0; i<MPI_MAX_FIDS; i++) {
2504 memcpy_toio(ai->rxfids[i].card_ram_off,
2505 &ai->rxfids[i].rx_desc, sizeof(RxFid));
2506 }
2507
2508 /* Alloc card TX descriptors */
2509
2510 memset(&rsp,0,sizeof(rsp));
2511 memset(&cmd,0,sizeof(cmd));
2512
2513 cmd.cmd = CMD_ALLOCATEAUX;
2514 cmd.parm0 = FID_TX;
2515 cmd.parm1 = (ai->txfids[0].card_ram_off - ai->pciaux);
2516 cmd.parm2 = MPI_MAX_FIDS;
2517
2518 for (i=0; i<MPI_MAX_FIDS; i++) {
2519 ai->txfids[i].tx_desc.valid = 1;
2520 memcpy_toio(ai->txfids[i].card_ram_off,
2521 &ai->txfids[i].tx_desc, sizeof(TxFid));
2522 }
2523 ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
2524
2525 rc=issuecommand(ai, &cmd, &rsp);
2526 if (rc != SUCCESS) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002527 airo_print_err(ai->dev->name, "Couldn't allocate TX FID");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 return rc;
2529 }
2530
2531 /* Alloc card Rid descriptor */
2532 memset(&rsp,0,sizeof(rsp));
2533 memset(&cmd,0,sizeof(cmd));
2534
2535 cmd.cmd = CMD_ALLOCATEAUX;
2536 cmd.parm0 = RID_RW;
2537 cmd.parm1 = (ai->config_desc.card_ram_off - ai->pciaux);
2538 cmd.parm2 = 1; /* Magic number... */
2539 rc=issuecommand(ai, &cmd, &rsp);
2540 if (rc != SUCCESS) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002541 airo_print_err(ai->dev->name, "Couldn't allocate RID");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 return rc;
2543 }
2544
2545 memcpy_toio(ai->config_desc.card_ram_off,
2546 &ai->config_desc.rid_desc, sizeof(Rid));
2547
2548 return rc;
2549}
2550
2551/*
2552 * We are setting up three things here:
2553 * 1) Map AUX memory for descriptors: Rid, TxFid, or RxFid.
2554 * 2) Map PCI memory for issueing commands.
2555 * 3) Allocate memory (shared) to send and receive ethernet frames.
2556 */
Michal Schmidt1138c372007-06-29 15:33:41 +02002557static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558{
2559 unsigned long mem_start, mem_len, aux_start, aux_len;
2560 int rc = -1;
2561 int i;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002562 dma_addr_t busaddroff;
2563 unsigned char *vpackoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 unsigned char __iomem *pciaddroff;
2565
2566 mem_start = pci_resource_start(pci, 1);
2567 mem_len = pci_resource_len(pci, 1);
2568 aux_start = pci_resource_start(pci, 2);
2569 aux_len = AUXMEMSIZE;
2570
Michal Schmidt1138c372007-06-29 15:33:41 +02002571 if (!request_mem_region(mem_start, mem_len, DRV_NAME)) {
2572 airo_print_err("", "Couldn't get region %x[%x]",
2573 (int)mem_start, (int)mem_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 goto out;
2575 }
Michal Schmidt1138c372007-06-29 15:33:41 +02002576 if (!request_mem_region(aux_start, aux_len, DRV_NAME)) {
2577 airo_print_err("", "Couldn't get region %x[%x]",
2578 (int)aux_start, (int)aux_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 goto free_region1;
2580 }
2581
2582 ai->pcimem = ioremap(mem_start, mem_len);
2583 if (!ai->pcimem) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002584 airo_print_err("", "Couldn't map region %x[%x]",
2585 (int)mem_start, (int)mem_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 goto free_region2;
2587 }
2588 ai->pciaux = ioremap(aux_start, aux_len);
2589 if (!ai->pciaux) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002590 airo_print_err("", "Couldn't map region %x[%x]",
2591 (int)aux_start, (int)aux_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 goto free_memmap;
2593 }
2594
2595 /* Reserve PKTSIZE for each fid and 2K for the Rids */
2596 ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma);
2597 if (!ai->shared) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002598 airo_print_err("", "Couldn't alloc_consistent %d",
2599 PCI_SHARED_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 goto free_auxmap;
2601 }
2602
2603 /*
2604 * Setup descriptor RX, TX, CONFIG
2605 */
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002606 busaddroff = ai->shared_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 pciaddroff = ai->pciaux + AUX_OFFSET;
2608 vpackoff = ai->shared;
2609
2610 /* RX descriptor setup */
2611 for(i = 0; i < MPI_MAX_FIDS; i++) {
2612 ai->rxfids[i].pending = 0;
2613 ai->rxfids[i].card_ram_off = pciaddroff;
2614 ai->rxfids[i].virtual_host_addr = vpackoff;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002615 ai->rxfids[i].rx_desc.host_addr = busaddroff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 ai->rxfids[i].rx_desc.valid = 1;
2617 ai->rxfids[i].rx_desc.len = PKTSIZE;
2618 ai->rxfids[i].rx_desc.rdy = 0;
2619
2620 pciaddroff += sizeof(RxFid);
2621 busaddroff += PKTSIZE;
2622 vpackoff += PKTSIZE;
2623 }
2624
2625 /* TX descriptor setup */
2626 for(i = 0; i < MPI_MAX_FIDS; i++) {
2627 ai->txfids[i].card_ram_off = pciaddroff;
2628 ai->txfids[i].virtual_host_addr = vpackoff;
2629 ai->txfids[i].tx_desc.valid = 1;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002630 ai->txfids[i].tx_desc.host_addr = busaddroff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 memcpy(ai->txfids[i].virtual_host_addr,
2632 &wifictlhdr8023, sizeof(wifictlhdr8023));
2633
2634 pciaddroff += sizeof(TxFid);
2635 busaddroff += PKTSIZE;
2636 vpackoff += PKTSIZE;
2637 }
2638 ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
2639
2640 /* Rid descriptor setup */
2641 ai->config_desc.card_ram_off = pciaddroff;
2642 ai->config_desc.virtual_host_addr = vpackoff;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002643 ai->config_desc.rid_desc.host_addr = busaddroff;
2644 ai->ridbus = busaddroff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 ai->config_desc.rid_desc.rid = 0;
2646 ai->config_desc.rid_desc.len = RIDSIZE;
2647 ai->config_desc.rid_desc.valid = 1;
2648 pciaddroff += sizeof(Rid);
2649 busaddroff += RIDSIZE;
2650 vpackoff += RIDSIZE;
2651
2652 /* Tell card about descriptors */
2653 if (mpi_init_descriptors (ai) != SUCCESS)
2654 goto free_shared;
2655
2656 return 0;
2657 free_shared:
2658 pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
2659 free_auxmap:
2660 iounmap(ai->pciaux);
2661 free_memmap:
2662 iounmap(ai->pcimem);
2663 free_region2:
2664 release_mem_region(aux_start, aux_len);
2665 free_region1:
2666 release_mem_region(mem_start, mem_len);
2667 out:
2668 return rc;
2669}
2670
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07002671static const struct header_ops airo_header_ops = {
2672 .parse = wll_header_parse,
2673};
2674
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675static void wifi_setup(struct net_device *dev)
2676{
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07002677 dev->header_ops = &airo_header_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 dev->hard_start_xmit = &airo_start_xmit11;
2679 dev->get_stats = &airo_get_stats;
2680 dev->set_mac_address = &airo_set_mac_address;
2681 dev->do_ioctl = &airo_ioctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 dev->wireless_handlers = &airo_handler_def;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 dev->change_mtu = &airo_change_mtu;
2684 dev->open = &airo_open;
2685 dev->stop = &airo_close;
2686
2687 dev->type = ARPHRD_IEEE80211;
2688 dev->hard_header_len = ETH_HLEN;
Dan Williams15db2762006-03-16 13:46:27 -05002689 dev->mtu = AIRO_DEF_MTU;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 dev->addr_len = ETH_ALEN;
2691 dev->tx_queue_len = 100;
2692
2693 memset(dev->broadcast,0xFF, ETH_ALEN);
2694
2695 dev->flags = IFF_BROADCAST|IFF_MULTICAST;
2696}
2697
2698static struct net_device *init_wifidev(struct airo_info *ai,
2699 struct net_device *ethdev)
2700{
2701 int err;
2702 struct net_device *dev = alloc_netdev(0, "wifi%d", wifi_setup);
2703 if (!dev)
2704 return NULL;
2705 dev->priv = ethdev->priv;
2706 dev->irq = ethdev->irq;
2707 dev->base_addr = ethdev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 dev->wireless_data = ethdev->wireless_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len);
2710 err = register_netdev(dev);
2711 if (err<0) {
2712 free_netdev(dev);
2713 return NULL;
2714 }
2715 return dev;
2716}
2717
Jouni Malinenff1d2762005-05-12 22:54:16 -04002718static int reset_card( struct net_device *dev , int lock) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 struct airo_info *ai = dev->priv;
2720
2721 if (lock && down_interruptible(&ai->sem))
2722 return -1;
2723 waitbusy (ai);
2724 OUT4500(ai,COMMAND,CMD_SOFTRESET);
2725 msleep(200);
2726 waitbusy (ai);
2727 msleep(200);
2728 if (lock)
2729 up(&ai->sem);
2730 return 0;
2731}
2732
Dan Williams3c304952006-04-15 12:26:18 -04002733#define AIRO_MAX_NETWORK_COUNT 64
Dan Williams9e75af32006-03-16 13:46:29 -05002734static int airo_networks_allocate(struct airo_info *ai)
2735{
2736 if (ai->networks)
2737 return 0;
2738
2739 ai->networks =
Dan Williams3c304952006-04-15 12:26:18 -04002740 kzalloc(AIRO_MAX_NETWORK_COUNT * sizeof(BSSListElement),
Dan Williams9e75af32006-03-16 13:46:29 -05002741 GFP_KERNEL);
2742 if (!ai->networks) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002743 airo_print_warn("", "Out of memory allocating beacons");
Dan Williams9e75af32006-03-16 13:46:29 -05002744 return -ENOMEM;
2745 }
2746
2747 return 0;
2748}
2749
2750static void airo_networks_free(struct airo_info *ai)
2751{
Dan Williams9e75af32006-03-16 13:46:29 -05002752 kfree(ai->networks);
2753 ai->networks = NULL;
2754}
2755
2756static void airo_networks_initialize(struct airo_info *ai)
2757{
2758 int i;
2759
2760 INIT_LIST_HEAD(&ai->network_free_list);
2761 INIT_LIST_HEAD(&ai->network_list);
Dan Williams3c304952006-04-15 12:26:18 -04002762 for (i = 0; i < AIRO_MAX_NETWORK_COUNT; i++)
Dan Williams9e75af32006-03-16 13:46:29 -05002763 list_add_tail(&ai->networks[i].list,
2764 &ai->network_free_list);
2765}
2766
Dan Williams3c304952006-04-15 12:26:18 -04002767static int airo_test_wpa_capable(struct airo_info *ai)
2768{
2769 int status;
2770 CapabilityRid cap_rid;
Dan Williams3c304952006-04-15 12:26:18 -04002771
2772 status = readCapabilityRid(ai, &cap_rid, 1);
2773 if (status != SUCCESS) return 0;
2774
2775 /* Only firmware versions 5.30.17 or better can do WPA */
2776 if ((cap_rid.softVer > 0x530)
Michal Schmidt0c6157a2006-05-02 23:29:55 +02002777 || ((cap_rid.softVer == 0x530) && (cap_rid.softSubVer >= 17))) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002778 airo_print_info("", "WPA is supported.");
Dan Williams3c304952006-04-15 12:26:18 -04002779 return 1;
2780 }
2781
2782 /* No WPA support */
Michal Schmidt1138c372007-06-29 15:33:41 +02002783 airo_print_info("", "WPA unsupported (only firmware versions 5.30.17"
Dan Williams3c304952006-04-15 12:26:18 -04002784 " and greater support WPA. Detected %s)", cap_rid.prodVer);
2785 return 0;
2786}
2787
Jouni Malinenff1d2762005-05-12 22:54:16 -04002788static struct net_device *_init_airo_card( unsigned short irq, int port,
2789 int is_pcmcia, struct pci_dev *pci,
2790 struct device *dmdev )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791{
2792 struct net_device *dev;
2793 struct airo_info *ai;
2794 int i, rc;
Joe Perches0795af52007-10-03 17:59:30 -07002795 DECLARE_MAC_BUF(mac);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796
2797 /* Create the network device object. */
Michal Schmidt1138c372007-06-29 15:33:41 +02002798 dev = alloc_netdev(sizeof(*ai), "", ether_setup);
2799 if (!dev) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002800 airo_print_err("", "Couldn't alloc_etherdev");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 }
2803
2804 ai = dev->priv;
2805 ai->wifidev = NULL;
Michal Schmidtfb038c22007-06-29 15:33:52 +02002806 ai->flags = 1 << FLAG_RADIO_DOWN;
Dan Williams3c304952006-04-15 12:26:18 -04002807 ai->jobs = 0;
Dan Williams934d8bf2006-03-16 13:46:23 -05002808 ai->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002810 airo_print_dbg("", "Found an MPI350 card");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 set_bit(FLAG_MPI, &ai->flags);
2812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 spin_lock_init(&ai->aux_lock);
2814 sema_init(&ai->sem, 1);
2815 ai->config.len = 0;
2816 ai->pci = pci;
2817 init_waitqueue_head (&ai->thr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 ai->tfm = NULL;
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01002819 add_airo_dev(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820
Dan Williams9e75af32006-03-16 13:46:29 -05002821 if (airo_networks_allocate (ai))
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02002822 goto err_out_free;
Dan Williams9e75af32006-03-16 13:46:29 -05002823 airo_networks_initialize (ai);
2824
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 /* The Airo-specific entries in the device structure. */
2826 if (test_bit(FLAG_MPI,&ai->flags)) {
2827 skb_queue_head_init (&ai->txq);
2828 dev->hard_start_xmit = &mpi_start_xmit;
2829 } else
2830 dev->hard_start_xmit = &airo_start_xmit;
2831 dev->get_stats = &airo_get_stats;
2832 dev->set_multicast_list = &airo_set_multicast_list;
2833 dev->set_mac_address = &airo_set_mac_address;
2834 dev->do_ioctl = &airo_ioctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 dev->wireless_handlers = &airo_handler_def;
2836 ai->wireless_data.spy_data = &ai->spy_data;
2837 dev->wireless_data = &ai->wireless_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 dev->change_mtu = &airo_change_mtu;
2839 dev->open = &airo_open;
2840 dev->stop = &airo_close;
2841 dev->irq = irq;
2842 dev->base_addr = port;
2843
2844 SET_NETDEV_DEV(dev, dmdev);
2845
Matthieu CASTET1d97f382005-12-01 02:35:26 -05002846 reset_card (dev, 1);
2847 msleep(400);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 if (!is_pcmcia) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002850 if (!request_region(dev->base_addr, 64, DRV_NAME)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 rc = -EBUSY;
Dan Williams934d8bf2006-03-16 13:46:23 -05002852 airo_print_err(dev->name, "Couldn't request region");
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02002853 goto err_out_nets;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 }
2855 }
2856
2857 if (test_bit(FLAG_MPI,&ai->flags)) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002858 if (mpi_map_card(ai, pci)) {
2859 airo_print_err("", "Could not map memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 goto err_out_res;
2861 }
2862 }
2863
2864 if (probe) {
2865 if ( setup_card( ai, dev->dev_addr, 1 ) != SUCCESS ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002866 airo_print_err(dev->name, "MAC could not be enabled" );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 rc = -EIO;
2868 goto err_out_map;
2869 }
2870 } else if (!test_bit(FLAG_MPI,&ai->flags)) {
2871 ai->bap_read = fast_bap_read;
2872 set_bit(FLAG_FLASHING, &ai->flags);
2873 }
2874
Dan Williams3c304952006-04-15 12:26:18 -04002875 /* Test for WPA support */
2876 if (airo_test_wpa_capable(ai)) {
2877 set_bit(FLAG_WPA_CAPABLE, &ai->flags);
2878 ai->bssListFirst = RID_WPA_BSSLISTFIRST;
2879 ai->bssListNext = RID_WPA_BSSLISTNEXT;
2880 ai->bssListRidLen = sizeof(BSSListRid);
2881 } else {
2882 ai->bssListFirst = RID_BSSLISTFIRST;
2883 ai->bssListNext = RID_BSSLISTNEXT;
2884 ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra);
2885 }
2886
Michal Schmidt1138c372007-06-29 15:33:41 +02002887 strcpy(dev->name, "eth%d");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 rc = register_netdev(dev);
2889 if (rc) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002890 airo_print_err(dev->name, "Couldn't register_netdev");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 goto err_out_map;
2892 }
2893 ai->wifidev = init_wifidev(ai, dev);
Florin Malita431aca52006-10-10 16:46:30 -04002894 if (!ai->wifidev)
2895 goto err_out_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896
2897 set_bit(FLAG_REGISTERED,&ai->flags);
Joe Perches0795af52007-10-03 17:59:30 -07002898 airo_print_info(dev->name, "MAC enabled %s",
2899 print_mac(mac, dev->dev_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900
2901 /* Allocate the transmit buffers */
2902 if (probe && !test_bit(FLAG_MPI,&ai->flags))
2903 for( i = 0; i < MAX_FIDS; i++ )
Dan Williams15db2762006-03-16 13:46:27 -05002904 ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905
Florin Malita431aca52006-10-10 16:46:30 -04002906 if (setup_proc_entry(dev, dev->priv) < 0)
2907 goto err_out_wifi;
2908
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 return dev;
2910
Florin Malita431aca52006-10-10 16:46:30 -04002911err_out_wifi:
2912 unregister_netdev(ai->wifidev);
2913 free_netdev(ai->wifidev);
2914err_out_reg:
2915 unregister_netdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916err_out_map:
2917 if (test_bit(FLAG_MPI,&ai->flags) && pci) {
2918 pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
2919 iounmap(ai->pciaux);
2920 iounmap(ai->pcimem);
2921 mpi_unmap_card(ai->pci);
2922 }
2923err_out_res:
2924 if (!is_pcmcia)
2925 release_region( dev->base_addr, 64 );
Michal Schmidt4d881902007-03-16 12:42:59 +01002926err_out_nets:
2927 airo_networks_free(ai);
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01002928 del_airo_dev(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929err_out_free:
2930 free_netdev(dev);
2931 return NULL;
2932}
2933
2934struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia,
2935 struct device *dmdev)
2936{
2937 return _init_airo_card ( irq, port, is_pcmcia, NULL, dmdev);
2938}
2939
2940EXPORT_SYMBOL(init_airo_card);
2941
2942static int waitbusy (struct airo_info *ai) {
2943 int delay = 0;
2944 while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) & (delay < 10000)) {
2945 udelay (10);
2946 if ((++delay % 20) == 0)
2947 OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
2948 }
2949 return delay < 10000;
2950}
2951
2952int reset_airo_card( struct net_device *dev )
2953{
2954 int i;
2955 struct airo_info *ai = dev->priv;
Joe Perches0795af52007-10-03 17:59:30 -07002956 DECLARE_MAC_BUF(mac);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957
2958 if (reset_card (dev, 1))
2959 return -1;
2960
2961 if ( setup_card(ai, dev->dev_addr, 1 ) != SUCCESS ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002962 airo_print_err(dev->name, "MAC could not be enabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 return -1;
2964 }
Joe Perches0795af52007-10-03 17:59:30 -07002965 airo_print_info(dev->name, "MAC enabled %s",
2966 print_mac(mac, dev->dev_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 /* Allocate the transmit buffers if needed */
2968 if (!test_bit(FLAG_MPI,&ai->flags))
2969 for( i = 0; i < MAX_FIDS; i++ )
Dan Williams15db2762006-03-16 13:46:27 -05002970 ai->fids[i] = transmit_allocate (ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971
2972 enable_interrupts( ai );
2973 netif_wake_queue(dev);
2974 return 0;
2975}
2976
2977EXPORT_SYMBOL(reset_airo_card);
2978
2979static void airo_send_event(struct net_device *dev) {
2980 struct airo_info *ai = dev->priv;
2981 union iwreq_data wrqu;
2982 StatusRid status_rid;
2983
Dan Williams3c304952006-04-15 12:26:18 -04002984 clear_bit(JOB_EVENT, &ai->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
2986 up(&ai->sem);
2987 wrqu.data.length = 0;
2988 wrqu.data.flags = 0;
2989 memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN);
2990 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
2991
2992 /* Send event to user space */
2993 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
2994}
2995
Dan Williams9e75af32006-03-16 13:46:29 -05002996static void airo_process_scan_results (struct airo_info *ai) {
2997 union iwreq_data wrqu;
Dan Williams3c304952006-04-15 12:26:18 -04002998 BSSListRid bss;
Dan Williams9e75af32006-03-16 13:46:29 -05002999 int rc;
3000 BSSListElement * loop_net;
3001 BSSListElement * tmp_net;
3002
3003 /* Blow away current list of scan results */
3004 list_for_each_entry_safe (loop_net, tmp_net, &ai->network_list, list) {
3005 list_move_tail (&loop_net->list, &ai->network_free_list);
3006 /* Don't blow away ->list, just BSS data */
3007 memset (loop_net, 0, sizeof (loop_net->bss));
3008 }
3009
3010 /* Try to read the first entry of the scan result */
Dan Williams3c304952006-04-15 12:26:18 -04003011 rc = PC4500_readrid(ai, ai->bssListFirst, &bss, ai->bssListRidLen, 0);
Al Viro17e70492007-12-19 18:56:37 -05003012 if((rc) || (bss.index == cpu_to_le16(0xffff))) {
Dan Williams9e75af32006-03-16 13:46:29 -05003013 /* No scan results */
3014 goto out;
3015 }
3016
3017 /* Read and parse all entries */
3018 tmp_net = NULL;
Al Viro17e70492007-12-19 18:56:37 -05003019 while((!rc) && (bss.index != cpu_to_le16(0xffff))) {
Dan Williams9e75af32006-03-16 13:46:29 -05003020 /* Grab a network off the free list */
3021 if (!list_empty(&ai->network_free_list)) {
3022 tmp_net = list_entry(ai->network_free_list.next,
3023 BSSListElement, list);
3024 list_del(ai->network_free_list.next);
3025 }
3026
3027 if (tmp_net != NULL) {
Dan Williams3c304952006-04-15 12:26:18 -04003028 memcpy(tmp_net, &bss, sizeof(tmp_net->bss));
Dan Williams9e75af32006-03-16 13:46:29 -05003029 list_add_tail(&tmp_net->list, &ai->network_list);
3030 tmp_net = NULL;
3031 }
3032
3033 /* Read next entry */
Dan Williams3c304952006-04-15 12:26:18 -04003034 rc = PC4500_readrid(ai, ai->bssListNext,
3035 &bss, ai->bssListRidLen, 0);
Dan Williams9e75af32006-03-16 13:46:29 -05003036 }
3037
3038out:
3039 ai->scan_timeout = 0;
Dan Williams3c304952006-04-15 12:26:18 -04003040 clear_bit(JOB_SCAN_RESULTS, &ai->jobs);
Dan Williams9e75af32006-03-16 13:46:29 -05003041 up(&ai->sem);
3042
3043 /* Send an empty event to user space.
3044 * We don't send the received data on
3045 * the event because it would require
3046 * us to do complex transcoding, and
3047 * we want to minimise the work done in
3048 * the irq handler. Use a request to
3049 * extract the data - Jean II */
3050 wrqu.data.length = 0;
3051 wrqu.data.flags = 0;
3052 wireless_send_event(ai->dev, SIOCGIWSCAN, &wrqu, NULL);
3053}
3054
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055static int airo_thread(void *data) {
3056 struct net_device *dev = data;
3057 struct airo_info *ai = dev->priv;
3058 int locked;
Rafael J. Wysocki83144182007-07-17 04:03:35 -07003059
3060 set_freezable();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 while(1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 /* make swsusp happy with our thread */
Christoph Lameter3e1d1d22005-06-24 23:13:50 -07003063 try_to_freeze();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064
Dan Williams3c304952006-04-15 12:26:18 -04003065 if (test_bit(JOB_DIE, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 break;
3067
Dan Williams3c304952006-04-15 12:26:18 -04003068 if (ai->jobs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 locked = down_interruptible(&ai->sem);
3070 } else {
3071 wait_queue_t wait;
3072
3073 init_waitqueue_entry(&wait, current);
3074 add_wait_queue(&ai->thr_wait, &wait);
3075 for (;;) {
3076 set_current_state(TASK_INTERRUPTIBLE);
Dan Williams3c304952006-04-15 12:26:18 -04003077 if (ai->jobs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 break;
Dan Williams9e75af32006-03-16 13:46:29 -05003079 if (ai->expires || ai->scan_timeout) {
3080 if (ai->scan_timeout &&
3081 time_after_eq(jiffies,ai->scan_timeout)){
Dan Williams3c304952006-04-15 12:26:18 -04003082 set_bit(JOB_SCAN_RESULTS, &ai->jobs);
Dan Williams9e75af32006-03-16 13:46:29 -05003083 break;
3084 } else if (ai->expires &&
3085 time_after_eq(jiffies,ai->expires)){
Dan Williams3c304952006-04-15 12:26:18 -04003086 set_bit(JOB_AUTOWEP, &ai->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 break;
3088 }
Dave Kleikamp5bb85f12006-10-10 14:45:46 -07003089 if (!kthread_should_stop() &&
3090 !freezing(current)) {
Dan Williams9e75af32006-03-16 13:46:29 -05003091 unsigned long wake_at;
3092 if (!ai->expires || !ai->scan_timeout) {
3093 wake_at = max(ai->expires,
3094 ai->scan_timeout);
3095 } else {
3096 wake_at = min(ai->expires,
3097 ai->scan_timeout);
3098 }
3099 schedule_timeout(wake_at - jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 continue;
3101 }
Dave Kleikamp5bb85f12006-10-10 14:45:46 -07003102 } else if (!kthread_should_stop() &&
3103 !freezing(current)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 schedule();
3105 continue;
3106 }
3107 break;
3108 }
3109 current->state = TASK_RUNNING;
3110 remove_wait_queue(&ai->thr_wait, &wait);
3111 locked = 1;
3112 }
3113
3114 if (locked)
3115 continue;
3116
Dan Williams3c304952006-04-15 12:26:18 -04003117 if (test_bit(JOB_DIE, &ai->jobs)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 up(&ai->sem);
3119 break;
3120 }
3121
Pavel Machekca078ba2005-09-03 15:56:57 -07003122 if (ai->power.event || test_bit(FLAG_FLASHING, &ai->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 up(&ai->sem);
3124 continue;
3125 }
3126
Dan Williams3c304952006-04-15 12:26:18 -04003127 if (test_bit(JOB_XMIT, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 airo_end_xmit(dev);
Dan Williams3c304952006-04-15 12:26:18 -04003129 else if (test_bit(JOB_XMIT11, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 airo_end_xmit11(dev);
Dan Williams3c304952006-04-15 12:26:18 -04003131 else if (test_bit(JOB_STATS, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 airo_read_stats(ai);
Dan Williams3c304952006-04-15 12:26:18 -04003133 else if (test_bit(JOB_WSTATS, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 airo_read_wireless_stats(ai);
Dan Williams3c304952006-04-15 12:26:18 -04003135 else if (test_bit(JOB_PROMISC, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 airo_set_promisc(ai);
Dan Williams3c304952006-04-15 12:26:18 -04003137 else if (test_bit(JOB_MIC, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 micinit(ai);
Dan Williams3c304952006-04-15 12:26:18 -04003139 else if (test_bit(JOB_EVENT, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 airo_send_event(dev);
Dan Williams3c304952006-04-15 12:26:18 -04003141 else if (test_bit(JOB_AUTOWEP, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 timer_func(dev);
Dan Williams3c304952006-04-15 12:26:18 -04003143 else if (test_bit(JOB_SCAN_RESULTS, &ai->jobs))
Dan Williams9e75af32006-03-16 13:46:29 -05003144 airo_process_scan_results(ai);
3145 else /* Shouldn't get here, but we make sure to unlock */
3146 up(&ai->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 }
Sukadev Bhattiprolu3b4c7d642006-08-14 23:12:03 -07003148
3149 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150}
3151
Al Viro0300b332007-12-19 22:38:33 -05003152static int header_len(__le16 ctl)
3153{
3154 u16 fc = le16_to_cpu(ctl);
3155 switch (fc & 0xc) {
3156 case 4:
3157 if ((fc & 0xe0) == 0xc0)
3158 return 10; /* one-address control packet */
3159 return 16; /* two-address control packet */
3160 case 8:
3161 if ((fc & 0x300) == 0x300)
3162 return 30; /* WDS packet */
3163 }
3164 return 24;
3165}
3166
Jeff Garzik28fc1f52007-10-29 05:46:16 -04003167static irqreturn_t airo_interrupt(int irq, void *dev_id)
3168{
3169 struct net_device *dev = dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 u16 status;
3171 u16 fid;
3172 struct airo_info *apriv = dev->priv;
3173 u16 savedInterrupts = 0;
3174 int handled = 0;
3175
3176 if (!netif_device_present(dev))
3177 return IRQ_NONE;
3178
3179 for (;;) {
3180 status = IN4500( apriv, EVSTAT );
3181 if ( !(status & STATUS_INTS) || status == 0xffff ) break;
3182
3183 handled = 1;
3184
3185 if ( status & EV_AWAKE ) {
3186 OUT4500( apriv, EVACK, EV_AWAKE );
3187 OUT4500( apriv, EVACK, EV_AWAKE );
3188 }
3189
3190 if (!savedInterrupts) {
3191 savedInterrupts = IN4500( apriv, EVINTEN );
3192 OUT4500( apriv, EVINTEN, 0 );
3193 }
3194
3195 if ( status & EV_MIC ) {
3196 OUT4500( apriv, EVACK, EV_MIC );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) {
Dan Williams3c304952006-04-15 12:26:18 -04003198 set_bit(JOB_MIC, &apriv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 wake_up_interruptible(&apriv->thr_wait);
3200 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 }
3202 if ( status & EV_LINK ) {
3203 union iwreq_data wrqu;
Dan Williams6fcdf562006-03-31 15:08:46 -05003204 int scan_forceloss = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 /* The link status has changed, if you want to put a
3206 monitor hook in, do it here. (Remember that
3207 interrupts are still disabled!)
3208 */
3209 u16 newStatus = IN4500(apriv, LINKSTAT);
3210 OUT4500( apriv, EVACK, EV_LINK);
3211 /* Here is what newStatus means: */
3212#define NOBEACON 0x8000 /* Loss of sync - missed beacons */
3213#define MAXRETRIES 0x8001 /* Loss of sync - max retries */
3214#define MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/
3215#define FORCELOSS 0x8003 /* Loss of sync - host request */
3216#define TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */
3217#define DEAUTH 0x8100 /* Deauthentication (low byte is reason code) */
3218#define DISASS 0x8200 /* Disassociation (low byte is reason code) */
3219#define ASSFAIL 0x8400 /* Association failure (low byte is reason
3220 code) */
3221#define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason
3222 code) */
Dan Williams6fcdf562006-03-31 15:08:46 -05003223#define ASSOCIATED 0x0400 /* Associated */
3224#define REASSOCIATED 0x0600 /* Reassociated? Only on firmware >= 5.30.17 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225#define RC_RESERVED 0 /* Reserved return code */
3226#define RC_NOREASON 1 /* Unspecified reason */
3227#define RC_AUTHINV 2 /* Previous authentication invalid */
3228#define RC_DEAUTH 3 /* Deauthenticated because sending station is
3229 leaving */
3230#define RC_NOACT 4 /* Disassociated due to inactivity */
3231#define RC_MAXLOAD 5 /* Disassociated because AP is unable to handle
3232 all currently associated stations */
3233#define RC_BADCLASS2 6 /* Class 2 frame received from
3234 non-Authenticated station */
3235#define RC_BADCLASS3 7 /* Class 3 frame received from
3236 non-Associated station */
3237#define RC_STATLEAVE 8 /* Disassociated because sending station is
3238 leaving BSS */
3239#define RC_NOAUTH 9 /* Station requesting (Re)Association is not
3240 Authenticated with the responding station */
Dan Williams6fcdf562006-03-31 15:08:46 -05003241 if (newStatus == FORCELOSS && apriv->scan_timeout > 0)
3242 scan_forceloss = 1;
3243 if(newStatus == ASSOCIATED || newStatus == REASSOCIATED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 if (auto_wep)
3245 apriv->expires = 0;
Sukadev Bhattiprolu3b4c7d642006-08-14 23:12:03 -07003246 if (apriv->list_bss_task)
3247 wake_up_process(apriv->list_bss_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 set_bit(FLAG_UPDATE_UNI, &apriv->flags);
3249 set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
Dan Williams6fcdf562006-03-31 15:08:46 -05003250
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251 if (down_trylock(&apriv->sem) != 0) {
Dan Williams3c304952006-04-15 12:26:18 -04003252 set_bit(JOB_EVENT, &apriv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 wake_up_interruptible(&apriv->thr_wait);
3254 } else
3255 airo_send_event(dev);
Dan Williams6fcdf562006-03-31 15:08:46 -05003256 } else if (!scan_forceloss) {
3257 if (auto_wep && !apriv->expires) {
3258 apriv->expires = RUN_AT(3*HZ);
3259 wake_up_interruptible(&apriv->thr_wait);
3260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261
3262 /* Send event to user space */
Dan Williams6fcdf562006-03-31 15:08:46 -05003263 memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN);
3264 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL);
3266 }
3267 }
3268
3269 /* Check to see if there is something to receive */
3270 if ( status & EV_RX ) {
3271 struct sk_buff *skb = NULL;
Al Virob8c06bc2007-12-19 17:55:43 -05003272 __le16 fc, v;
3273 u16 len, hdrlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274#pragma pack(1)
3275 struct {
Al Viro593c2b92007-12-17 15:09:34 -05003276 __le16 status, len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 u8 rssi[2];
3278 u8 rate;
3279 u8 freq;
Al Viro593c2b92007-12-17 15:09:34 -05003280 __le16 tmp[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 } hdr;
3282#pragma pack()
3283 u16 gap;
Al Virob8c06bc2007-12-19 17:55:43 -05003284 __le16 tmpbuf[4];
3285 __le16 *buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286
3287 if (test_bit(FLAG_MPI,&apriv->flags)) {
3288 if (test_bit(FLAG_802_11, &apriv->flags))
3289 mpi_receive_802_11(apriv);
3290 else
3291 mpi_receive_802_3(apriv);
3292 OUT4500(apriv, EVACK, EV_RX);
3293 goto exitrx;
3294 }
3295
3296 fid = IN4500( apriv, RXFID );
3297
3298 /* Get the packet length */
3299 if (test_bit(FLAG_802_11, &apriv->flags)) {
3300 bap_setup (apriv, fid, 4, BAP0);
Al Virob8c06bc2007-12-19 17:55:43 -05003301 bap_read (apriv, (__le16*)&hdr, sizeof(hdr), BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 /* Bad CRC. Ignore packet */
3303 if (le16_to_cpu(hdr.status) & 2)
3304 hdr.len = 0;
3305 if (apriv->wifidev == NULL)
3306 hdr.len = 0;
3307 } else {
3308 bap_setup (apriv, fid, 0x36, BAP0);
Al Virob8c06bc2007-12-19 17:55:43 -05003309 bap_read (apriv, &hdr.len, 2, BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 }
3311 len = le16_to_cpu(hdr.len);
3312
Dan Williams15db2762006-03-16 13:46:27 -05003313 if (len > AIRO_DEF_MTU) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003314 airo_print_err(apriv->dev->name, "Bad size %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 goto badrx;
3316 }
3317 if (len == 0)
3318 goto badrx;
3319
3320 if (test_bit(FLAG_802_11, &apriv->flags)) {
Al Viro0300b332007-12-19 22:38:33 -05003321 bap_read (apriv, &fc, sizeof(fc), BAP0);
3322 hdrlen = header_len(fc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 } else
3324 hdrlen = ETH_ALEN * 2;
3325
3326 skb = dev_alloc_skb( len + hdrlen + 2 + 2 );
3327 if ( !skb ) {
3328 apriv->stats.rx_dropped++;
3329 goto badrx;
3330 }
3331 skb_reserve(skb, 2); /* This way the IP header is aligned */
Al Virob8c06bc2007-12-19 17:55:43 -05003332 buffer = (__le16*)skb_put (skb, len + hdrlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 if (test_bit(FLAG_802_11, &apriv->flags)) {
3334 buffer[0] = fc;
3335 bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
3336 if (hdrlen == 24)
3337 bap_read (apriv, tmpbuf, 6, BAP0);
3338
Al Virob8c06bc2007-12-19 17:55:43 -05003339 bap_read (apriv, &v, sizeof(v), BAP0);
3340 gap = le16_to_cpu(v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 if (gap) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003342 if (gap <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 bap_read (apriv, tmpbuf, gap, BAP0);
Dan Williams934d8bf2006-03-16 13:46:23 -05003344 } else {
3345 airo_print_err(apriv->dev->name, "gaplen too "
3346 "big. Problems will follow...");
3347 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 }
3349 bap_read (apriv, buffer + hdrlen/2, len, BAP0);
3350 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 MICBuffer micbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 if (apriv->micstats.enabled) {
Al Virob8c06bc2007-12-19 17:55:43 -05003354 bap_read (apriv,(__le16*)&micbuf,sizeof(micbuf),BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 if (ntohs(micbuf.typelen) > 0x05DC)
3356 bap_setup (apriv, fid, 0x44, BAP0);
3357 else {
3358 if (len <= sizeof(micbuf))
3359 goto badmic;
3360
3361 len -= sizeof(micbuf);
3362 skb_trim (skb, len + hdrlen);
3363 }
3364 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 bap_read(apriv,buffer+ETH_ALEN,len,BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
3367badmic:
3368 dev_kfree_skb_irq (skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369badrx:
3370 OUT4500( apriv, EVACK, EV_RX);
3371 goto exitrx;
3372 }
3373 }
3374#ifdef WIRELESS_SPY
3375 if (apriv->spy_data.spy_number > 0) {
3376 char *sa;
3377 struct iw_quality wstats;
3378 /* Prepare spy data : addr + qual */
3379 if (!test_bit(FLAG_802_11, &apriv->flags)) {
3380 sa = (char*)buffer + 6;
3381 bap_setup (apriv, fid, 8, BAP0);
Al Virob8c06bc2007-12-19 17:55:43 -05003382 bap_read (apriv, (__le16*)hdr.rssi, 2, BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 } else
3384 sa = (char*)buffer + 10;
3385 wstats.qual = hdr.rssi[0];
3386 if (apriv->rssi)
3387 wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
3388 else
3389 wstats.level = (hdr.rssi[1] + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04003390 wstats.noise = apriv->wstats.qual.noise;
3391 wstats.updated = IW_QUAL_LEVEL_UPDATED
3392 | IW_QUAL_QUAL_UPDATED
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07003393 | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 /* Update spy records */
3395 wireless_spy_update(dev, sa, &wstats);
3396 }
3397#endif /* WIRELESS_SPY */
3398 OUT4500( apriv, EVACK, EV_RX);
3399
3400 if (test_bit(FLAG_802_11, &apriv->flags)) {
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07003401 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 skb->pkt_type = PACKET_OTHERHOST;
3403 skb->dev = apriv->wifidev;
3404 skb->protocol = htons(ETH_P_802_2);
Arnaldo Carvalho de Melo4c13eb62007-04-25 17:40:23 -07003405 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 skb->protocol = eth_type_trans(skb,dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 skb->dev->last_rx = jiffies;
3408 skb->ip_summed = CHECKSUM_NONE;
3409
3410 netif_rx( skb );
3411 }
3412exitrx:
3413
3414 /* Check to see if a packet has been transmitted */
3415 if ( status & ( EV_TX|EV_TXCPY|EV_TXEXC ) ) {
3416 int i;
3417 int len = 0;
3418 int index = -1;
3419
3420 if (test_bit(FLAG_MPI,&apriv->flags)) {
3421 unsigned long flags;
3422
3423 if (status & EV_TXEXC)
3424 get_tx_error(apriv, -1);
3425 spin_lock_irqsave(&apriv->aux_lock, flags);
David S. Millerb03efcf2005-07-08 14:57:23 -07003426 if (!skb_queue_empty(&apriv->txq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 spin_unlock_irqrestore(&apriv->aux_lock,flags);
3428 mpi_send_packet (dev);
3429 } else {
3430 clear_bit(FLAG_PENDING_XMIT, &apriv->flags);
3431 spin_unlock_irqrestore(&apriv->aux_lock,flags);
3432 netif_wake_queue (dev);
3433 }
3434 OUT4500( apriv, EVACK,
3435 status & (EV_TX|EV_TXCPY|EV_TXEXC));
3436 goto exittx;
3437 }
3438
3439 fid = IN4500(apriv, TXCOMPLFID);
3440
3441 for( i = 0; i < MAX_FIDS; i++ ) {
3442 if ( ( apriv->fids[i] & 0xffff ) == fid ) {
3443 len = apriv->fids[i] >> 16;
3444 index = i;
3445 }
3446 }
3447 if (index != -1) {
3448 if (status & EV_TXEXC)
3449 get_tx_error(apriv, index);
3450 OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC));
3451 /* Set up to be used again */
3452 apriv->fids[index] &= 0xffff;
3453 if (index < MAX_FIDS / 2) {
3454 if (!test_bit(FLAG_PENDING_XMIT, &apriv->flags))
3455 netif_wake_queue(dev);
3456 } else {
3457 if (!test_bit(FLAG_PENDING_XMIT11, &apriv->flags))
3458 netif_wake_queue(apriv->wifidev);
3459 }
3460 } else {
3461 OUT4500( apriv, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC));
Dan Williams934d8bf2006-03-16 13:46:23 -05003462 airo_print_err(apriv->dev->name, "Unallocated FID was "
3463 "used to xmit" );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 }
3465 }
3466exittx:
3467 if ( status & ~STATUS_INTS & ~IGNORE_INTS )
Dan Williams934d8bf2006-03-16 13:46:23 -05003468 airo_print_warn(apriv->dev->name, "Got weird status %x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 status & ~STATUS_INTS & ~IGNORE_INTS );
3470 }
3471
3472 if (savedInterrupts)
3473 OUT4500( apriv, EVINTEN, savedInterrupts );
3474
3475 /* done.. */
3476 return IRQ_RETVAL(handled);
3477}
3478
3479/*
3480 * Routines to talk to the card
3481 */
3482
3483/*
3484 * This was originally written for the 4500, hence the name
3485 * NOTE: If use with 8bit mode and SMP bad things will happen!
3486 * Why would some one do 8 bit IO in an SMP machine?!?
3487 */
3488static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) {
3489 if (test_bit(FLAG_MPI,&ai->flags))
3490 reg <<= 1;
3491 if ( !do8bitIO )
3492 outw( val, ai->dev->base_addr + reg );
3493 else {
3494 outb( val & 0xff, ai->dev->base_addr + reg );
3495 outb( val >> 8, ai->dev->base_addr + reg + 1 );
3496 }
3497}
3498
3499static u16 IN4500( struct airo_info *ai, u16 reg ) {
3500 unsigned short rc;
3501
3502 if (test_bit(FLAG_MPI,&ai->flags))
3503 reg <<= 1;
3504 if ( !do8bitIO )
3505 rc = inw( ai->dev->base_addr + reg );
3506 else {
3507 rc = inb( ai->dev->base_addr + reg );
3508 rc += ((int)inb( ai->dev->base_addr + reg + 1 )) << 8;
3509 }
3510 return rc;
3511}
3512
Michal Schmidt175ec1a2007-06-29 15:33:47 +02003513static int enable_MAC(struct airo_info *ai, int lock)
3514{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 int rc;
Michal Schmidt175ec1a2007-06-29 15:33:47 +02003516 Cmd cmd;
3517 Resp rsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518
3519 /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions
3520 * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down"
3521 * Note : we could try to use !netif_running(dev) in enable_MAC()
3522 * instead of this flag, but I don't trust it *within* the
3523 * open/close functions, and testing both flags together is
3524 * "cheaper" - Jean II */
3525 if (ai->flags & FLAG_RADIO_MASK) return SUCCESS;
3526
3527 if (lock && down_interruptible(&ai->sem))
3528 return -ERESTARTSYS;
3529
3530 if (!test_bit(FLAG_ENABLED, &ai->flags)) {
3531 memset(&cmd, 0, sizeof(cmd));
3532 cmd.cmd = MAC_ENABLE;
Michal Schmidt175ec1a2007-06-29 15:33:47 +02003533 rc = issuecommand(ai, &cmd, &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 if (rc == SUCCESS)
3535 set_bit(FLAG_ENABLED, &ai->flags);
3536 } else
3537 rc = SUCCESS;
3538
3539 if (lock)
3540 up(&ai->sem);
3541
3542 if (rc)
Michal Schmidt175ec1a2007-06-29 15:33:47 +02003543 airo_print_err(ai->dev->name, "Cannot enable MAC");
3544 else if ((rsp.status & 0xFF00) != 0) {
3545 airo_print_err(ai->dev->name, "Bad MAC enable reason=%x, "
3546 "rid=%x, offset=%d", rsp.rsp0, rsp.rsp1, rsp.rsp2);
3547 rc = ERROR;
3548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 return rc;
3550}
3551
3552static void disable_MAC( struct airo_info *ai, int lock ) {
3553 Cmd cmd;
3554 Resp rsp;
3555
3556 if (lock && down_interruptible(&ai->sem))
3557 return;
3558
3559 if (test_bit(FLAG_ENABLED, &ai->flags)) {
3560 memset(&cmd, 0, sizeof(cmd));
3561 cmd.cmd = MAC_DISABLE; // disable in case already enabled
3562 issuecommand(ai, &cmd, &rsp);
3563 clear_bit(FLAG_ENABLED, &ai->flags);
3564 }
3565 if (lock)
3566 up(&ai->sem);
3567}
3568
3569static void enable_interrupts( struct airo_info *ai ) {
3570 /* Enable the interrupts */
3571 OUT4500( ai, EVINTEN, STATUS_INTS );
3572}
3573
3574static void disable_interrupts( struct airo_info *ai ) {
3575 OUT4500( ai, EVINTEN, 0 );
3576}
3577
3578static void mpi_receive_802_3(struct airo_info *ai)
3579{
3580 RxFid rxd;
3581 int len = 0;
3582 struct sk_buff *skb;
3583 char *buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 int off = 0;
3585 MICBuffer micbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586
3587 memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
3588 /* Make sure we got something */
3589 if (rxd.rdy && rxd.valid == 0) {
3590 len = rxd.len + 12;
3591 if (len < 12 || len > 2048)
3592 goto badrx;
3593
3594 skb = dev_alloc_skb(len);
3595 if (!skb) {
3596 ai->stats.rx_dropped++;
3597 goto badrx;
3598 }
3599 buffer = skb_put(skb,len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2);
3601 if (ai->micstats.enabled) {
3602 memcpy(&micbuf,
3603 ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2,
3604 sizeof(micbuf));
3605 if (ntohs(micbuf.typelen) <= 0x05DC) {
3606 if (len <= sizeof(micbuf) + ETH_ALEN * 2)
3607 goto badmic;
3608
3609 off = sizeof(micbuf);
3610 skb_trim (skb, len - off);
3611 }
3612 }
3613 memcpy(buffer + ETH_ALEN * 2,
3614 ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off,
3615 len - ETH_ALEN * 2 - off);
3616 if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) {
3617badmic:
3618 dev_kfree_skb_irq (skb);
3619 goto badrx;
3620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621#ifdef WIRELESS_SPY
3622 if (ai->spy_data.spy_number > 0) {
3623 char *sa;
3624 struct iw_quality wstats;
3625 /* Prepare spy data : addr + qual */
3626 sa = buffer + ETH_ALEN;
3627 wstats.qual = 0; /* XXX Where do I get that info from ??? */
3628 wstats.level = 0;
3629 wstats.updated = 0;
3630 /* Update spy records */
3631 wireless_spy_update(ai->dev, sa, &wstats);
3632 }
3633#endif /* WIRELESS_SPY */
3634
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 skb->ip_summed = CHECKSUM_NONE;
3636 skb->protocol = eth_type_trans(skb, ai->dev);
3637 skb->dev->last_rx = jiffies;
3638 netif_rx(skb);
3639 }
3640badrx:
3641 if (rxd.valid == 0) {
3642 rxd.valid = 1;
3643 rxd.rdy = 0;
3644 rxd.len = PKTSIZE;
3645 memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd));
3646 }
3647}
3648
3649void mpi_receive_802_11 (struct airo_info *ai)
3650{
3651 RxFid rxd;
3652 struct sk_buff *skb = NULL;
Al Viro0300b332007-12-19 22:38:33 -05003653 u16 len, hdrlen = 0;
3654 __le16 fc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655#pragma pack(1)
3656 struct {
Al Viro593c2b92007-12-17 15:09:34 -05003657 __le16 status, len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 u8 rssi[2];
3659 u8 rate;
3660 u8 freq;
Al Viro593c2b92007-12-17 15:09:34 -05003661 __le16 tmp[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 } hdr;
3663#pragma pack()
3664 u16 gap;
3665 u16 *buffer;
3666 char *ptr = ai->rxfids[0].virtual_host_addr+4;
3667
3668 memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
3669 memcpy ((char *)&hdr, ptr, sizeof(hdr));
3670 ptr += sizeof(hdr);
3671 /* Bad CRC. Ignore packet */
3672 if (le16_to_cpu(hdr.status) & 2)
3673 hdr.len = 0;
3674 if (ai->wifidev == NULL)
3675 hdr.len = 0;
3676 len = le16_to_cpu(hdr.len);
Dan Williams15db2762006-03-16 13:46:27 -05003677 if (len > AIRO_DEF_MTU) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003678 airo_print_err(ai->dev->name, "Bad size %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 goto badrx;
3680 }
3681 if (len == 0)
3682 goto badrx;
3683
Al Viro0300b332007-12-19 22:38:33 -05003684 fc = get_unaligned((__le16 *)ptr);
3685 hdrlen = header_len(fc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686
3687 skb = dev_alloc_skb( len + hdrlen + 2 );
3688 if ( !skb ) {
3689 ai->stats.rx_dropped++;
3690 goto badrx;
3691 }
3692 buffer = (u16*)skb_put (skb, len + hdrlen);
3693 memcpy ((char *)buffer, ptr, hdrlen);
3694 ptr += hdrlen;
3695 if (hdrlen == 24)
3696 ptr += 6;
Al Viro593c2b92007-12-17 15:09:34 -05003697 gap = le16_to_cpu(get_unaligned((__le16 *)ptr));
3698 ptr += sizeof(__le16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 if (gap) {
3700 if (gap <= 8)
3701 ptr += gap;
3702 else
Dan Williams934d8bf2006-03-16 13:46:23 -05003703 airo_print_err(ai->dev->name,
3704 "gaplen too big. Problems will follow...");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 }
3706 memcpy ((char *)buffer + hdrlen, ptr, len);
3707 ptr += len;
3708#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
3709 if (ai->spy_data.spy_number > 0) {
3710 char *sa;
3711 struct iw_quality wstats;
3712 /* Prepare spy data : addr + qual */
3713 sa = (char*)buffer + 10;
3714 wstats.qual = hdr.rssi[0];
3715 if (ai->rssi)
3716 wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm;
3717 else
3718 wstats.level = (hdr.rssi[1] + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04003719 wstats.noise = ai->wstats.qual.noise;
3720 wstats.updated = IW_QUAL_QUAL_UPDATED
3721 | IW_QUAL_LEVEL_UPDATED
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07003722 | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 /* Update spy records */
3724 wireless_spy_update(ai->dev, sa, &wstats);
3725 }
3726#endif /* IW_WIRELESS_SPY */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07003727 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 skb->pkt_type = PACKET_OTHERHOST;
3729 skb->dev = ai->wifidev;
3730 skb->protocol = htons(ETH_P_802_2);
3731 skb->dev->last_rx = jiffies;
3732 skb->ip_summed = CHECKSUM_NONE;
3733 netif_rx( skb );
3734badrx:
3735 if (rxd.valid == 0) {
3736 rxd.valid = 1;
3737 rxd.rdy = 0;
3738 rxd.len = PKTSIZE;
3739 memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd));
3740 }
3741}
3742
3743static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
3744{
3745 Cmd cmd;
3746 Resp rsp;
3747 int status;
3748 int i;
3749 SsidRid mySsid;
Al Viro4293ea32007-12-19 19:21:51 -05003750 __le16 lastindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 WepKeyRid wkr;
3752 int rc;
3753
3754 memset( &mySsid, 0, sizeof( mySsid ) );
Jesper Juhlb4558ea2005-10-28 16:53:13 -04003755 kfree (ai->flash);
3756 ai->flash = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757
3758 /* The NOP is the first step in getting the card going */
3759 cmd.cmd = NOP;
3760 cmd.parm0 = cmd.parm1 = cmd.parm2 = 0;
3761 if (lock && down_interruptible(&ai->sem))
3762 return ERROR;
3763 if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
3764 if (lock)
3765 up(&ai->sem);
3766 return ERROR;
3767 }
3768 disable_MAC( ai, 0);
3769
3770 // Let's figure out if we need to use the AUX port
3771 if (!test_bit(FLAG_MPI,&ai->flags)) {
3772 cmd.cmd = CMD_ENABLEAUX;
3773 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
3774 if (lock)
3775 up(&ai->sem);
Dan Williams934d8bf2006-03-16 13:46:23 -05003776 airo_print_err(ai->dev->name, "Error checking for AUX port");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 return ERROR;
3778 }
3779 if (!aux_bap || rsp.status & 0xff00) {
3780 ai->bap_read = fast_bap_read;
Dan Williams934d8bf2006-03-16 13:46:23 -05003781 airo_print_dbg(ai->dev->name, "Doing fast bap_reads");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 } else {
3783 ai->bap_read = aux_bap_read;
Dan Williams934d8bf2006-03-16 13:46:23 -05003784 airo_print_dbg(ai->dev->name, "Doing AUX bap_reads");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 }
3786 }
3787 if (lock)
3788 up(&ai->sem);
3789 if (ai->config.len == 0) {
3790 tdsRssiRid rssi_rid;
3791 CapabilityRid cap_rid;
3792
Jesper Juhlb4558ea2005-10-28 16:53:13 -04003793 kfree(ai->APList);
3794 ai->APList = NULL;
3795 kfree(ai->SSID);
3796 ai->SSID = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 // general configuration (read/modify/write)
3798 status = readConfigRid(ai, lock);
3799 if ( status != SUCCESS ) return ERROR;
3800
3801 status = readCapabilityRid(ai, &cap_rid, lock);
3802 if ( status != SUCCESS ) return ERROR;
3803
3804 status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),lock);
3805 if ( status == SUCCESS ) {
3806 if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
Dan Williams41480af2005-05-10 09:45:51 -04003807 memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 }
3809 else {
Jesper Juhlb4558ea2005-10-28 16:53:13 -04003810 kfree(ai->rssi);
3811 ai->rssi = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 if (cap_rid.softCap & 8)
3813 ai->config.rmode |= RXMODE_NORMALIZED_RSSI;
3814 else
Dan Williams934d8bf2006-03-16 13:46:23 -05003815 airo_print_warn(ai->dev->name, "unknown received signal "
3816 "level scale");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 }
3818 ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
3819 ai->config.authType = AUTH_OPEN;
3820 ai->config.modulation = MOD_CCK;
3821
Al Viro15617852007-12-20 17:21:36 -05003822 if ((cap_rid.len>=sizeof(cap_rid)) &&
3823 (cap_rid.extSoftCap & cpu_to_le16(1)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 (micsetup(ai) == SUCCESS)) {
3825 ai->config.opmode |= MODE_MIC;
3826 set_bit(FLAG_MIC_CAPABLE, &ai->flags);
3827 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828
3829 /* Save off the MAC */
3830 for( i = 0; i < ETH_ALEN; i++ ) {
3831 mac[i] = ai->config.macAddr[i];
3832 }
3833
3834 /* Check to see if there are any insmod configured
3835 rates to add */
3836 if ( rates[0] ) {
3837 int i = 0;
3838 memset(ai->config.rates,0,sizeof(ai->config.rates));
3839 for( i = 0; i < 8 && rates[i]; i++ ) {
3840 ai->config.rates[i] = rates[i];
3841 }
3842 }
3843 if ( basic_rate > 0 ) {
3844 int i;
3845 for( i = 0; i < 8; i++ ) {
3846 if ( ai->config.rates[i] == basic_rate ||
3847 !ai->config.rates ) {
3848 ai->config.rates[i] = basic_rate | 0x80;
3849 break;
3850 }
3851 }
3852 }
3853 set_bit (FLAG_COMMIT, &ai->flags);
3854 }
3855
3856 /* Setup the SSIDs if present */
3857 if ( ssids[0] ) {
3858 int i;
3859 for( i = 0; i < 3 && ssids[i]; i++ ) {
Al Viro0dd22122007-12-17 16:11:57 -05003860 size_t len = strlen(ssids[i]);
3861 if (len > 32)
3862 len = 32;
3863 mySsid.ssids[i].len = cpu_to_le16(len);
3864 memcpy(mySsid.ssids[i].ssid, ssids[i], len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 }
Al Viro0dd22122007-12-17 16:11:57 -05003866 mySsid.len = cpu_to_le16(sizeof(mySsid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 }
3868
3869 status = writeConfigRid(ai, lock);
3870 if ( status != SUCCESS ) return ERROR;
3871
3872 /* Set up the SSID list */
3873 if ( ssids[0] ) {
3874 status = writeSsidRid(ai, &mySsid, lock);
3875 if ( status != SUCCESS ) return ERROR;
3876 }
3877
Michal Schmidt175ec1a2007-06-29 15:33:47 +02003878 status = enable_MAC(ai, lock);
3879 if (status != SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 return ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881
3882 /* Grab the initial wep key, we gotta save it for auto_wep */
3883 rc = readWepKeyRid(ai, &wkr, 1, lock);
3884 if (rc == SUCCESS) do {
3885 lastindex = wkr.kindex;
Al Viro4293ea32007-12-19 19:21:51 -05003886 if (wkr.kindex == cpu_to_le16(0xffff)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 ai->defindex = wkr.mac[0];
3888 }
3889 rc = readWepKeyRid(ai, &wkr, 0, lock);
3890 } while(lastindex != wkr.kindex);
3891
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02003892 try_auto_wep(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893
3894 return SUCCESS;
3895}
3896
3897static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
3898 // Im really paranoid about letting it run forever!
3899 int max_tries = 600000;
3900
3901 if (IN4500(ai, EVSTAT) & EV_CMD)
3902 OUT4500(ai, EVACK, EV_CMD);
3903
3904 OUT4500(ai, PARAM0, pCmd->parm0);
3905 OUT4500(ai, PARAM1, pCmd->parm1);
3906 OUT4500(ai, PARAM2, pCmd->parm2);
3907 OUT4500(ai, COMMAND, pCmd->cmd);
3908
3909 while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) {
3910 if ((IN4500(ai, COMMAND)) == pCmd->cmd)
3911 // PC4500 didn't notice command, try again
3912 OUT4500(ai, COMMAND, pCmd->cmd);
3913 if (!in_atomic() && (max_tries & 255) == 0)
3914 schedule();
3915 }
3916
3917 if ( max_tries == -1 ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003918 airo_print_err(ai->dev->name,
3919 "Max tries exceeded when issueing command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 if (IN4500(ai, COMMAND) & COMMAND_BUSY)
3921 OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
3922 return ERROR;
3923 }
3924
3925 // command completed
3926 pRsp->status = IN4500(ai, STATUS);
3927 pRsp->rsp0 = IN4500(ai, RESP0);
3928 pRsp->rsp1 = IN4500(ai, RESP1);
3929 pRsp->rsp2 = IN4500(ai, RESP2);
Robert Schulze13dca9b2006-07-10 18:37:44 +02003930 if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET)
3931 airo_print_err(ai->dev->name,
3932 "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x",
3933 pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1,
3934 pRsp->rsp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935
3936 // clear stuck command busy if necessary
3937 if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
3938 OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
3939 }
3940 // acknowledge processing the status/response
3941 OUT4500(ai, EVACK, EV_CMD);
3942
3943 return SUCCESS;
3944}
3945
3946/* Sets up the bap to start exchange data. whichbap should
3947 * be one of the BAP0 or BAP1 defines. Locks should be held before
3948 * calling! */
3949static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap )
3950{
3951 int timeout = 50;
3952 int max_tries = 3;
3953
3954 OUT4500(ai, SELECT0+whichbap, rid);
3955 OUT4500(ai, OFFSET0+whichbap, offset);
3956 while (1) {
3957 int status = IN4500(ai, OFFSET0+whichbap);
3958 if (status & BAP_BUSY) {
3959 /* This isn't really a timeout, but its kinda
3960 close */
3961 if (timeout--) {
3962 continue;
3963 }
3964 } else if ( status & BAP_ERR ) {
3965 /* invalid rid or offset */
Dan Williams934d8bf2006-03-16 13:46:23 -05003966 airo_print_err(ai->dev->name, "BAP error %x %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 status, whichbap );
3968 return ERROR;
3969 } else if (status & BAP_DONE) { // success
3970 return SUCCESS;
3971 }
3972 if ( !(max_tries--) ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003973 airo_print_err(ai->dev->name,
Michal Schmidt1138c372007-06-29 15:33:41 +02003974 "BAP setup error too many retries\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 return ERROR;
3976 }
3977 // -- PC4500 missed it, try again
3978 OUT4500(ai, SELECT0+whichbap, rid);
3979 OUT4500(ai, OFFSET0+whichbap, offset);
3980 timeout = 50;
3981 }
3982}
3983
3984/* should only be called by aux_bap_read. This aux function and the
3985 following use concepts not documented in the developers guide. I
3986 got them from a patch given to my by Aironet */
3987static u16 aux_setup(struct airo_info *ai, u16 page,
3988 u16 offset, u16 *len)
3989{
3990 u16 next;
3991
3992 OUT4500(ai, AUXPAGE, page);
3993 OUT4500(ai, AUXOFF, 0);
3994 next = IN4500(ai, AUXDATA);
3995 *len = IN4500(ai, AUXDATA)&0xff;
3996 if (offset != 4) OUT4500(ai, AUXOFF, offset);
3997 return next;
3998}
3999
4000/* requires call to bap_setup() first */
Al Virob8c06bc2007-12-19 17:55:43 -05004001static int aux_bap_read(struct airo_info *ai, __le16 *pu16Dst,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 int bytelen, int whichbap)
4003{
4004 u16 len;
4005 u16 page;
4006 u16 offset;
4007 u16 next;
4008 int words;
4009 int i;
4010 unsigned long flags;
4011
4012 spin_lock_irqsave(&ai->aux_lock, flags);
4013 page = IN4500(ai, SWS0+whichbap);
4014 offset = IN4500(ai, SWS2+whichbap);
4015 next = aux_setup(ai, page, offset, &len);
4016 words = (bytelen+1)>>1;
4017
4018 for (i=0; i<words;) {
4019 int count;
4020 count = (len>>1) < (words-i) ? (len>>1) : (words-i);
4021 if ( !do8bitIO )
4022 insw( ai->dev->base_addr+DATA0+whichbap,
4023 pu16Dst+i,count );
4024 else
4025 insb( ai->dev->base_addr+DATA0+whichbap,
4026 pu16Dst+i, count << 1 );
4027 i += count;
4028 if (i<words) {
4029 next = aux_setup(ai, next, 4, &len);
4030 }
4031 }
4032 spin_unlock_irqrestore(&ai->aux_lock, flags);
4033 return SUCCESS;
4034}
4035
4036
4037/* requires call to bap_setup() first */
Al Virob8c06bc2007-12-19 17:55:43 -05004038static int fast_bap_read(struct airo_info *ai, __le16 *pu16Dst,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 int bytelen, int whichbap)
4040{
4041 bytelen = (bytelen + 1) & (~1); // round up to even value
4042 if ( !do8bitIO )
4043 insw( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1 );
4044 else
4045 insb( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen );
4046 return SUCCESS;
4047}
4048
4049/* requires call to bap_setup() first */
Al Virob8c06bc2007-12-19 17:55:43 -05004050static int bap_write(struct airo_info *ai, const __le16 *pu16Src,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 int bytelen, int whichbap)
4052{
4053 bytelen = (bytelen + 1) & (~1); // round up to even value
4054 if ( !do8bitIO )
4055 outsw( ai->dev->base_addr+DATA0+whichbap,
4056 pu16Src, bytelen>>1 );
4057 else
4058 outsb( ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen );
4059 return SUCCESS;
4060}
4061
4062static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd)
4063{
4064 Cmd cmd; /* for issuing commands */
4065 Resp rsp; /* response from commands */
4066 u16 status;
4067
4068 memset(&cmd, 0, sizeof(cmd));
4069 cmd.cmd = accmd;
4070 cmd.parm0 = rid;
4071 status = issuecommand(ai, &cmd, &rsp);
4072 if (status != 0) return status;
4073 if ( (rsp.status & 0x7F00) != 0) {
4074 return (accmd << 8) + (rsp.rsp0 & 0xFF);
4075 }
4076 return 0;
4077}
4078
4079/* Note, that we are using BAP1 which is also used by transmit, so
4080 * we must get a lock. */
4081static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, int lock)
4082{
4083 u16 status;
4084 int rc = SUCCESS;
4085
4086 if (lock) {
4087 if (down_interruptible(&ai->sem))
4088 return ERROR;
4089 }
4090 if (test_bit(FLAG_MPI,&ai->flags)) {
4091 Cmd cmd;
4092 Resp rsp;
4093
4094 memset(&cmd, 0, sizeof(cmd));
4095 memset(&rsp, 0, sizeof(rsp));
4096 ai->config_desc.rid_desc.valid = 1;
4097 ai->config_desc.rid_desc.len = RIDSIZE;
4098 ai->config_desc.rid_desc.rid = 0;
4099 ai->config_desc.rid_desc.host_addr = ai->ridbus;
4100
4101 cmd.cmd = CMD_ACCESS;
4102 cmd.parm0 = rid;
4103
4104 memcpy_toio(ai->config_desc.card_ram_off,
4105 &ai->config_desc.rid_desc, sizeof(Rid));
4106
4107 rc = issuecommand(ai, &cmd, &rsp);
4108
4109 if (rsp.status & 0x7f00)
4110 rc = rsp.rsp0;
4111 if (!rc)
4112 memcpy(pBuf, ai->config_desc.virtual_host_addr, len);
4113 goto done;
4114 } else {
4115 if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS))!=SUCCESS) {
4116 rc = status;
4117 goto done;
4118 }
4119 if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
4120 rc = ERROR;
4121 goto done;
4122 }
4123 // read the rid length field
4124 bap_read(ai, pBuf, 2, BAP1);
4125 // length for remaining part of rid
Al Viro593c2b92007-12-17 15:09:34 -05004126 len = min(len, (int)le16_to_cpu(*(__le16*)pBuf)) - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127
4128 if ( len <= 2 ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004129 airo_print_err(ai->dev->name,
4130 "Rid %x has a length of %d which is too short",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131 (int)rid, (int)len );
4132 rc = ERROR;
4133 goto done;
4134 }
4135 // read remainder of the rid
Al Virob8c06bc2007-12-19 17:55:43 -05004136 rc = bap_read(ai, ((__le16*)pBuf)+1, len, BAP1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 }
4138done:
4139 if (lock)
4140 up(&ai->sem);
4141 return rc;
4142}
4143
4144/* Note, that we are using BAP1 which is also used by transmit, so
4145 * make sure this isnt called when a transmit is happening */
4146static int PC4500_writerid(struct airo_info *ai, u16 rid,
4147 const void *pBuf, int len, int lock)
4148{
4149 u16 status;
4150 int rc = SUCCESS;
4151
Al Viro593c2b92007-12-17 15:09:34 -05004152 *(__le16*)pBuf = cpu_to_le16((u16)len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153
4154 if (lock) {
4155 if (down_interruptible(&ai->sem))
4156 return ERROR;
4157 }
4158 if (test_bit(FLAG_MPI,&ai->flags)) {
4159 Cmd cmd;
4160 Resp rsp;
4161
Dan Streetmanf89b2322005-11-11 11:41:42 -05004162 if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid))
Dan Williams934d8bf2006-03-16 13:46:23 -05004163 airo_print_err(ai->dev->name,
4164 "%s: MAC should be disabled (rid=%04x)",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 __FUNCTION__, rid);
4166 memset(&cmd, 0, sizeof(cmd));
4167 memset(&rsp, 0, sizeof(rsp));
4168
4169 ai->config_desc.rid_desc.valid = 1;
4170 ai->config_desc.rid_desc.len = *((u16 *)pBuf);
4171 ai->config_desc.rid_desc.rid = 0;
4172
4173 cmd.cmd = CMD_WRITERID;
4174 cmd.parm0 = rid;
4175
4176 memcpy_toio(ai->config_desc.card_ram_off,
4177 &ai->config_desc.rid_desc, sizeof(Rid));
4178
4179 if (len < 4 || len > 2047) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004180 airo_print_err(ai->dev->name, "%s: len=%d", __FUNCTION__, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 rc = -1;
4182 } else {
4183 memcpy((char *)ai->config_desc.virtual_host_addr,
4184 pBuf, len);
4185
4186 rc = issuecommand(ai, &cmd, &rsp);
4187 if ((rc & 0xff00) != 0) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004188 airo_print_err(ai->dev->name, "%s: Write rid Error %d",
4189 __FUNCTION__, rc);
4190 airo_print_err(ai->dev->name, "%s: Cmd=%04x",
4191 __FUNCTION__, cmd.cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 }
4193
4194 if ((rsp.status & 0x7f00))
4195 rc = rsp.rsp0;
4196 }
4197 } else {
4198 // --- first access so that we can write the rid data
4199 if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
4200 rc = status;
4201 goto done;
4202 }
4203 // --- now write the rid data
4204 if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
4205 rc = ERROR;
4206 goto done;
4207 }
4208 bap_write(ai, pBuf, len, BAP1);
4209 // ---now commit the rid data
4210 rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
4211 }
4212done:
4213 if (lock)
4214 up(&ai->sem);
4215 return rc;
4216}
4217
4218/* Allocates a FID to be used for transmitting packets. We only use
4219 one for now. */
4220static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw)
4221{
4222 unsigned int loop = 3000;
4223 Cmd cmd;
4224 Resp rsp;
4225 u16 txFid;
Al Viro593c2b92007-12-17 15:09:34 -05004226 __le16 txControl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227
4228 cmd.cmd = CMD_ALLOCATETX;
4229 cmd.parm0 = lenPayload;
4230 if (down_interruptible(&ai->sem))
4231 return ERROR;
4232 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
4233 txFid = ERROR;
4234 goto done;
4235 }
4236 if ( (rsp.status & 0xFF00) != 0) {
4237 txFid = ERROR;
4238 goto done;
4239 }
4240 /* wait for the allocate event/indication
4241 * It makes me kind of nervous that this can just sit here and spin,
4242 * but in practice it only loops like four times. */
4243 while (((IN4500(ai, EVSTAT) & EV_ALLOC) == 0) && --loop);
4244 if (!loop) {
4245 txFid = ERROR;
4246 goto done;
4247 }
4248
4249 // get the allocated fid and acknowledge
4250 txFid = IN4500(ai, TXALLOCFID);
4251 OUT4500(ai, EVACK, EV_ALLOC);
4252
4253 /* The CARD is pretty cool since it converts the ethernet packet
4254 * into 802.11. Also note that we don't release the FID since we
4255 * will be using the same one over and over again. */
4256 /* We only have to setup the control once since we are not
4257 * releasing the fid. */
4258 if (raw)
4259 txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_11
4260 | TXCTL_ETHERNET | TXCTL_NORELEASE);
4261 else
4262 txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3
4263 | TXCTL_ETHERNET | TXCTL_NORELEASE);
4264 if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS)
4265 txFid = ERROR;
4266 else
4267 bap_write(ai, &txControl, sizeof(txControl), BAP1);
4268
4269done:
4270 up(&ai->sem);
4271
4272 return txFid;
4273}
4274
4275/* In general BAP1 is dedicated to transmiting packets. However,
4276 since we need a BAP when accessing RIDs, we also use BAP1 for that.
4277 Make sure the BAP1 spinlock is held when this is called. */
4278static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
4279{
Al Viro593c2b92007-12-17 15:09:34 -05004280 __le16 payloadLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 Cmd cmd;
4282 Resp rsp;
4283 int miclen = 0;
4284 u16 txFid = len;
4285 MICBuffer pMic;
4286
4287 len >>= 16;
4288
4289 if (len <= ETH_ALEN * 2) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004290 airo_print_warn(ai->dev->name, "Short packet %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291 return ERROR;
4292 }
4293 len -= ETH_ALEN * 2;
4294
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295 if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
Al Viro593c2b92007-12-17 15:09:34 -05004296 (ntohs(((__be16 *)pPacket)[6]) != 0x888E)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS)
4298 return ERROR;
4299 miclen = sizeof(pMic);
4300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 // packet is destination[6], source[6], payload[len-12]
4302 // write the payload length and dst/src/payload
4303 if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR;
4304 /* The hardware addresses aren't counted as part of the payload, so
4305 * we have to subtract the 12 bytes for the addresses off */
4306 payloadLen = cpu_to_le16(len + miclen);
4307 bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
Al Virob8c06bc2007-12-19 17:55:43 -05004308 bap_write(ai, (__le16*)pPacket, sizeof(etherHead), BAP1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 if (miclen)
Al Virob8c06bc2007-12-19 17:55:43 -05004310 bap_write(ai, (__le16*)&pMic, miclen, BAP1);
4311 bap_write(ai, (__le16*)(pPacket + sizeof(etherHead)), len, BAP1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 // issue the transmit command
4313 memset( &cmd, 0, sizeof( cmd ) );
4314 cmd.cmd = CMD_TRANSMIT;
4315 cmd.parm0 = txFid;
4316 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
4317 if ( (rsp.status & 0xFF00) != 0) return ERROR;
4318 return SUCCESS;
4319}
4320
4321static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
4322{
Al Viro593c2b92007-12-17 15:09:34 -05004323 __le16 fc, payloadLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 Cmd cmd;
4325 Resp rsp;
4326 int hdrlen;
Al Viro977b1432007-12-19 16:45:29 -05004327 static u8 tail[(30-10) + 2 + 6] = {[30-10] = 6};
4328 /* padding of header to full size + le16 gaplen (6) + gaplen bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 u16 txFid = len;
4330 len >>= 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331
Al Viro0300b332007-12-19 22:38:33 -05004332 fc = *(__le16*)pPacket;
4333 hdrlen = header_len(fc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
4335 if (len < hdrlen) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004336 airo_print_warn(ai->dev->name, "Short packet %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 return ERROR;
4338 }
4339
4340 /* packet is 802.11 header + payload
4341 * write the payload length and dst/src/payload */
4342 if (bap_setup(ai, txFid, 6, BAP1) != SUCCESS) return ERROR;
4343 /* The 802.11 header aren't counted as part of the payload, so
4344 * we have to subtract the header bytes off */
4345 payloadLen = cpu_to_le16(len-hdrlen);
4346 bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
4347 if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR;
Al Virob8c06bc2007-12-19 17:55:43 -05004348 bap_write(ai, (__le16 *)pPacket, hdrlen, BAP1);
4349 bap_write(ai, (__le16 *)(tail + (hdrlen - 10)), 38 - hdrlen, BAP1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350
Al Virob8c06bc2007-12-19 17:55:43 -05004351 bap_write(ai, (__le16 *)(pPacket + hdrlen), len - hdrlen, BAP1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 // issue the transmit command
4353 memset( &cmd, 0, sizeof( cmd ) );
4354 cmd.cmd = CMD_TRANSMIT;
4355 cmd.parm0 = txFid;
4356 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
4357 if ( (rsp.status & 0xFF00) != 0) return ERROR;
4358 return SUCCESS;
4359}
4360
4361/*
4362 * This is the proc_fs routines. It is a bit messier than I would
4363 * like! Feel free to clean it up!
4364 */
4365
4366static ssize_t proc_read( struct file *file,
4367 char __user *buffer,
4368 size_t len,
4369 loff_t *offset);
4370
4371static ssize_t proc_write( struct file *file,
4372 const char __user *buffer,
4373 size_t len,
4374 loff_t *offset );
4375static int proc_close( struct inode *inode, struct file *file );
4376
4377static int proc_stats_open( struct inode *inode, struct file *file );
4378static int proc_statsdelta_open( struct inode *inode, struct file *file );
4379static int proc_status_open( struct inode *inode, struct file *file );
4380static int proc_SSID_open( struct inode *inode, struct file *file );
4381static int proc_APList_open( struct inode *inode, struct file *file );
4382static int proc_BSSList_open( struct inode *inode, struct file *file );
4383static int proc_config_open( struct inode *inode, struct file *file );
4384static int proc_wepkey_open( struct inode *inode, struct file *file );
4385
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004386static const struct file_operations proc_statsdelta_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 .read = proc_read,
4388 .open = proc_statsdelta_open,
4389 .release = proc_close
4390};
4391
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004392static const struct file_operations proc_stats_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393 .read = proc_read,
4394 .open = proc_stats_open,
4395 .release = proc_close
4396};
4397
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004398static const struct file_operations proc_status_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004399 .read = proc_read,
4400 .open = proc_status_open,
4401 .release = proc_close
4402};
4403
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004404static const struct file_operations proc_SSID_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 .read = proc_read,
4406 .write = proc_write,
4407 .open = proc_SSID_open,
4408 .release = proc_close
4409};
4410
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004411static const struct file_operations proc_BSSList_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 .read = proc_read,
4413 .write = proc_write,
4414 .open = proc_BSSList_open,
4415 .release = proc_close
4416};
4417
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004418static const struct file_operations proc_APList_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 .read = proc_read,
4420 .write = proc_write,
4421 .open = proc_APList_open,
4422 .release = proc_close
4423};
4424
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004425static const struct file_operations proc_config_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 .read = proc_read,
4427 .write = proc_write,
4428 .open = proc_config_open,
4429 .release = proc_close
4430};
4431
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004432static const struct file_operations proc_wepkey_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 .read = proc_read,
4434 .write = proc_write,
4435 .open = proc_wepkey_open,
4436 .release = proc_close
4437};
4438
4439static struct proc_dir_entry *airo_entry;
4440
4441struct proc_data {
4442 int release_buffer;
4443 int readlen;
4444 char *rbuffer;
4445 int writelen;
4446 int maxwritelen;
4447 char *wbuffer;
4448 void (*on_close) (struct inode *, struct file *);
4449};
4450
4451#ifndef SETPROC_OPS
4452#define SETPROC_OPS(entry, ops) (entry)->proc_fops = &(ops)
4453#endif
4454
4455static int setup_proc_entry( struct net_device *dev,
4456 struct airo_info *apriv ) {
4457 struct proc_dir_entry *entry;
4458 /* First setup the device directory */
4459 strcpy(apriv->proc_name,dev->name);
4460 apriv->proc_entry = create_proc_entry(apriv->proc_name,
4461 S_IFDIR|airo_perm,
4462 airo_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004463 if (!apriv->proc_entry)
4464 goto fail;
4465 apriv->proc_entry->uid = proc_uid;
4466 apriv->proc_entry->gid = proc_gid;
4467 apriv->proc_entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468
4469 /* Setup the StatsDelta */
4470 entry = create_proc_entry("StatsDelta",
4471 S_IFREG | (S_IRUGO&proc_perm),
4472 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004473 if (!entry)
4474 goto fail_stats_delta;
4475 entry->uid = proc_uid;
4476 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004478 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 SETPROC_OPS(entry, proc_statsdelta_ops);
4480
4481 /* Setup the Stats */
4482 entry = create_proc_entry("Stats",
4483 S_IFREG | (S_IRUGO&proc_perm),
4484 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004485 if (!entry)
4486 goto fail_stats;
4487 entry->uid = proc_uid;
4488 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004490 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 SETPROC_OPS(entry, proc_stats_ops);
4492
4493 /* Setup the Status */
4494 entry = create_proc_entry("Status",
4495 S_IFREG | (S_IRUGO&proc_perm),
4496 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004497 if (!entry)
4498 goto fail_status;
4499 entry->uid = proc_uid;
4500 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004502 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 SETPROC_OPS(entry, proc_status_ops);
4504
4505 /* Setup the Config */
4506 entry = create_proc_entry("Config",
4507 S_IFREG | proc_perm,
4508 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004509 if (!entry)
4510 goto fail_config;
4511 entry->uid = proc_uid;
4512 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004514 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 SETPROC_OPS(entry, proc_config_ops);
4516
4517 /* Setup the SSID */
4518 entry = create_proc_entry("SSID",
4519 S_IFREG | proc_perm,
4520 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004521 if (!entry)
4522 goto fail_ssid;
4523 entry->uid = proc_uid;
4524 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004526 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 SETPROC_OPS(entry, proc_SSID_ops);
4528
4529 /* Setup the APList */
4530 entry = create_proc_entry("APList",
4531 S_IFREG | proc_perm,
4532 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004533 if (!entry)
4534 goto fail_aplist;
4535 entry->uid = proc_uid;
4536 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004538 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 SETPROC_OPS(entry, proc_APList_ops);
4540
4541 /* Setup the BSSList */
4542 entry = create_proc_entry("BSSList",
4543 S_IFREG | proc_perm,
4544 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004545 if (!entry)
4546 goto fail_bsslist;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547 entry->uid = proc_uid;
4548 entry->gid = proc_gid;
4549 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004550 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 SETPROC_OPS(entry, proc_BSSList_ops);
4552
4553 /* Setup the WepKey */
4554 entry = create_proc_entry("WepKey",
4555 S_IFREG | proc_perm,
4556 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004557 if (!entry)
4558 goto fail_wepkey;
4559 entry->uid = proc_uid;
4560 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004562 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 SETPROC_OPS(entry, proc_wepkey_ops);
4564
4565 return 0;
Florin Malita431aca52006-10-10 16:46:30 -04004566
4567fail_wepkey:
4568 remove_proc_entry("BSSList", apriv->proc_entry);
4569fail_bsslist:
4570 remove_proc_entry("APList", apriv->proc_entry);
4571fail_aplist:
4572 remove_proc_entry("SSID", apriv->proc_entry);
4573fail_ssid:
4574 remove_proc_entry("Config", apriv->proc_entry);
4575fail_config:
4576 remove_proc_entry("Status", apriv->proc_entry);
4577fail_status:
4578 remove_proc_entry("Stats", apriv->proc_entry);
4579fail_stats:
4580 remove_proc_entry("StatsDelta", apriv->proc_entry);
4581fail_stats_delta:
4582 remove_proc_entry(apriv->proc_name, airo_entry);
4583fail:
4584 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585}
4586
4587static int takedown_proc_entry( struct net_device *dev,
4588 struct airo_info *apriv ) {
4589 if ( !apriv->proc_entry->namelen ) return 0;
4590 remove_proc_entry("Stats",apriv->proc_entry);
4591 remove_proc_entry("StatsDelta",apriv->proc_entry);
4592 remove_proc_entry("Status",apriv->proc_entry);
4593 remove_proc_entry("Config",apriv->proc_entry);
4594 remove_proc_entry("SSID",apriv->proc_entry);
4595 remove_proc_entry("APList",apriv->proc_entry);
4596 remove_proc_entry("BSSList",apriv->proc_entry);
4597 remove_proc_entry("WepKey",apriv->proc_entry);
4598 remove_proc_entry(apriv->proc_name,airo_entry);
4599 return 0;
4600}
4601
4602/*
4603 * What we want from the proc_fs is to be able to efficiently read
4604 * and write the configuration. To do this, we want to read the
4605 * configuration when the file is opened and write it when the file is
4606 * closed. So basically we allocate a read buffer at open and fill it
4607 * with data, and allocate a write buffer and read it at close.
4608 */
4609
4610/*
4611 * The read routine is generic, it relies on the preallocated rbuffer
4612 * to supply the data.
4613 */
4614static ssize_t proc_read( struct file *file,
4615 char __user *buffer,
4616 size_t len,
4617 loff_t *offset )
4618{
4619 loff_t pos = *offset;
4620 struct proc_data *priv = (struct proc_data*)file->private_data;
4621
4622 if (!priv->rbuffer)
4623 return -EINVAL;
4624
4625 if (pos < 0)
4626 return -EINVAL;
4627 if (pos >= priv->readlen)
4628 return 0;
4629 if (len > priv->readlen - pos)
4630 len = priv->readlen - pos;
4631 if (copy_to_user(buffer, priv->rbuffer + pos, len))
4632 return -EFAULT;
4633 *offset = pos + len;
4634 return len;
4635}
4636
4637/*
4638 * The write routine is generic, it fills in a preallocated rbuffer
4639 * to supply the data.
4640 */
4641static ssize_t proc_write( struct file *file,
4642 const char __user *buffer,
4643 size_t len,
4644 loff_t *offset )
4645{
4646 loff_t pos = *offset;
4647 struct proc_data *priv = (struct proc_data*)file->private_data;
4648
4649 if (!priv->wbuffer)
4650 return -EINVAL;
4651
4652 if (pos < 0)
4653 return -EINVAL;
4654 if (pos >= priv->maxwritelen)
4655 return 0;
4656 if (len > priv->maxwritelen - pos)
4657 len = priv->maxwritelen - pos;
4658 if (copy_from_user(priv->wbuffer + pos, buffer, len))
4659 return -EFAULT;
4660 if ( pos + len > priv->writelen )
4661 priv->writelen = len + file->f_pos;
4662 *offset = pos + len;
4663 return len;
4664}
4665
4666static int proc_status_open( struct inode *inode, struct file *file ) {
4667 struct proc_data *data;
4668 struct proc_dir_entry *dp = PDE(inode);
4669 struct net_device *dev = dp->data;
4670 struct airo_info *apriv = dev->priv;
4671 CapabilityRid cap_rid;
4672 StatusRid status_rid;
4673 int i;
4674
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01004675 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 data = (struct proc_data *)file->private_data;
4678 if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
4679 kfree (file->private_data);
4680 return -ENOMEM;
4681 }
4682
4683 readStatusRid(apriv, &status_rid, 1);
4684 readCapabilityRid(apriv, &cap_rid, 1);
4685
4686 i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n",
4687 status_rid.mode & 1 ? "CFG ": "",
4688 status_rid.mode & 2 ? "ACT ": "",
4689 status_rid.mode & 0x10 ? "SYN ": "",
4690 status_rid.mode & 0x20 ? "LNK ": "",
4691 status_rid.mode & 0x40 ? "LEAP ": "",
4692 status_rid.mode & 0x80 ? "PRIV ": "",
4693 status_rid.mode & 0x100 ? "KEY ": "",
4694 status_rid.mode & 0x200 ? "WEP ": "",
4695 status_rid.mode & 0x8000 ? "ERR ": "");
4696 sprintf( data->rbuffer+i, "Mode: %x\n"
4697 "Signal Strength: %d\n"
4698 "Signal Quality: %d\n"
4699 "SSID: %-.*s\n"
4700 "AP: %-.16s\n"
4701 "Freq: %d\n"
4702 "BitRate: %dmbs\n"
4703 "Driver Version: %s\n"
4704 "Device: %s\nManufacturer: %s\nFirmware Version: %s\n"
4705 "Radio type: %x\nCountry: %x\nHardware Version: %x\n"
4706 "Software Version: %x\nSoftware Subversion: %x\n"
4707 "Boot block version: %x\n",
4708 (int)status_rid.mode,
4709 (int)status_rid.normalizedSignalStrength,
4710 (int)status_rid.signalQuality,
4711 (int)status_rid.SSIDlen,
4712 status_rid.SSID,
4713 status_rid.apName,
4714 (int)status_rid.channel,
4715 (int)status_rid.currentXmitRate/2,
4716 version,
4717 cap_rid.prodName,
4718 cap_rid.manName,
4719 cap_rid.prodVer,
4720 cap_rid.radioType,
4721 cap_rid.country,
4722 cap_rid.hardVer,
4723 (int)cap_rid.softVer,
4724 (int)cap_rid.softSubVer,
4725 (int)cap_rid.bootBlockVer );
4726 data->readlen = strlen( data->rbuffer );
4727 return 0;
4728}
4729
4730static int proc_stats_rid_open(struct inode*, struct file*, u16);
4731static int proc_statsdelta_open( struct inode *inode,
4732 struct file *file ) {
4733 if (file->f_mode&FMODE_WRITE) {
4734 return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR);
4735 }
4736 return proc_stats_rid_open(inode, file, RID_STATSDELTA);
4737}
4738
4739static int proc_stats_open( struct inode *inode, struct file *file ) {
4740 return proc_stats_rid_open(inode, file, RID_STATS);
4741}
4742
4743static int proc_stats_rid_open( struct inode *inode,
4744 struct file *file,
Al Viroa23ace52007-12-19 22:24:16 -05004745 u16 rid )
4746{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 struct proc_data *data;
4748 struct proc_dir_entry *dp = PDE(inode);
4749 struct net_device *dev = dp->data;
4750 struct airo_info *apriv = dev->priv;
4751 StatsRid stats;
4752 int i, j;
Al Viroa23ace52007-12-19 22:24:16 -05004753 __le32 *vals = stats.vals;
4754 int len = le16_to_cpu(stats.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01004756 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 data = (struct proc_data *)file->private_data;
4759 if ((data->rbuffer = kmalloc( 4096, GFP_KERNEL )) == NULL) {
4760 kfree (file->private_data);
4761 return -ENOMEM;
4762 }
4763
4764 readStatsRid(apriv, &stats, rid, 1);
4765
4766 j = 0;
Al Viroa23ace52007-12-19 22:24:16 -05004767 for(i=0; statsLabels[i]!=(char *)-1 && i*4<len; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 if (!statsLabels[i]) continue;
4769 if (j+strlen(statsLabels[i])+16>4096) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004770 airo_print_warn(apriv->dev->name,
4771 "Potentially disasterous buffer overflow averted!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 break;
4773 }
Al Viroa23ace52007-12-19 22:24:16 -05004774 j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i],
4775 le32_to_cpu(vals[i]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 }
Al Viroa23ace52007-12-19 22:24:16 -05004777 if (i*4 >= len) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004778 airo_print_warn(apriv->dev->name, "Got a short rid");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 }
4780 data->readlen = j;
4781 return 0;
4782}
4783
4784static int get_dec_u16( char *buffer, int *start, int limit ) {
4785 u16 value;
4786 int valid = 0;
4787 for( value = 0; buffer[*start] >= '0' &&
4788 buffer[*start] <= '9' &&
4789 *start < limit; (*start)++ ) {
4790 valid = 1;
4791 value *= 10;
4792 value += buffer[*start] - '0';
4793 }
4794 if ( !valid ) return -1;
4795 return value;
4796}
4797
4798static int airo_config_commit(struct net_device *dev,
4799 struct iw_request_info *info, void *zwrq,
4800 char *extra);
4801
4802static void proc_config_on_close( struct inode *inode, struct file *file ) {
4803 struct proc_data *data = file->private_data;
4804 struct proc_dir_entry *dp = PDE(inode);
4805 struct net_device *dev = dp->data;
4806 struct airo_info *ai = dev->priv;
4807 char *line;
4808
4809 if ( !data->writelen ) return;
4810
4811 readConfigRid(ai, 1);
4812 set_bit (FLAG_COMMIT, &ai->flags);
4813
4814 line = data->wbuffer;
4815 while( line[0] ) {
4816/*** Mode processing */
4817 if ( !strncmp( line, "Mode: ", 6 ) ) {
4818 line += 6;
4819 if ((ai->config.rmode & 0xff) >= RXMODE_RFMON)
4820 set_bit (FLAG_RESET, &ai->flags);
4821 ai->config.rmode &= 0xfe00;
4822 clear_bit (FLAG_802_11, &ai->flags);
4823 ai->config.opmode &= 0xFF00;
4824 ai->config.scanMode = SCANMODE_ACTIVE;
4825 if ( line[0] == 'a' ) {
4826 ai->config.opmode |= 0;
4827 } else {
4828 ai->config.opmode |= 1;
4829 if ( line[0] == 'r' ) {
4830 ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
4831 ai->config.scanMode = SCANMODE_PASSIVE;
4832 set_bit (FLAG_802_11, &ai->flags);
4833 } else if ( line[0] == 'y' ) {
4834 ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER;
4835 ai->config.scanMode = SCANMODE_PASSIVE;
4836 set_bit (FLAG_802_11, &ai->flags);
4837 } else if ( line[0] == 'l' )
4838 ai->config.rmode |= RXMODE_LANMON;
4839 }
4840 set_bit (FLAG_COMMIT, &ai->flags);
4841 }
4842
4843/*** Radio status */
4844 else if (!strncmp(line,"Radio: ", 7)) {
4845 line += 7;
4846 if (!strncmp(line,"off",3)) {
4847 set_bit (FLAG_RADIO_OFF, &ai->flags);
4848 } else {
4849 clear_bit (FLAG_RADIO_OFF, &ai->flags);
4850 }
4851 }
4852/*** NodeName processing */
4853 else if ( !strncmp( line, "NodeName: ", 10 ) ) {
4854 int j;
4855
4856 line += 10;
4857 memset( ai->config.nodeName, 0, 16 );
4858/* Do the name, assume a space between the mode and node name */
4859 for( j = 0; j < 16 && line[j] != '\n'; j++ ) {
4860 ai->config.nodeName[j] = line[j];
4861 }
4862 set_bit (FLAG_COMMIT, &ai->flags);
4863 }
4864
4865/*** PowerMode processing */
4866 else if ( !strncmp( line, "PowerMode: ", 11 ) ) {
4867 line += 11;
4868 if ( !strncmp( line, "PSPCAM", 6 ) ) {
4869 ai->config.powerSaveMode = POWERSAVE_PSPCAM;
4870 set_bit (FLAG_COMMIT, &ai->flags);
4871 } else if ( !strncmp( line, "PSP", 3 ) ) {
4872 ai->config.powerSaveMode = POWERSAVE_PSP;
4873 set_bit (FLAG_COMMIT, &ai->flags);
4874 } else {
4875 ai->config.powerSaveMode = POWERSAVE_CAM;
4876 set_bit (FLAG_COMMIT, &ai->flags);
4877 }
4878 } else if ( !strncmp( line, "DataRates: ", 11 ) ) {
4879 int v, i = 0, k = 0; /* i is index into line,
4880 k is index to rates */
4881
4882 line += 11;
4883 while((v = get_dec_u16(line, &i, 3))!=-1) {
4884 ai->config.rates[k++] = (u8)v;
4885 line += i + 1;
4886 i = 0;
4887 }
4888 set_bit (FLAG_COMMIT, &ai->flags);
4889 } else if ( !strncmp( line, "Channel: ", 9 ) ) {
4890 int v, i = 0;
4891 line += 9;
4892 v = get_dec_u16(line, &i, i+3);
4893 if ( v != -1 ) {
4894 ai->config.channelSet = (u16)v;
4895 set_bit (FLAG_COMMIT, &ai->flags);
4896 }
4897 } else if ( !strncmp( line, "XmitPower: ", 11 ) ) {
4898 int v, i = 0;
4899 line += 11;
4900 v = get_dec_u16(line, &i, i+3);
4901 if ( v != -1 ) {
4902 ai->config.txPower = (u16)v;
4903 set_bit (FLAG_COMMIT, &ai->flags);
4904 }
4905 } else if ( !strncmp( line, "WEP: ", 5 ) ) {
4906 line += 5;
4907 switch( line[0] ) {
4908 case 's':
4909 ai->config.authType = (u16)AUTH_SHAREDKEY;
4910 break;
4911 case 'e':
4912 ai->config.authType = (u16)AUTH_ENCRYPT;
4913 break;
4914 default:
4915 ai->config.authType = (u16)AUTH_OPEN;
4916 break;
4917 }
4918 set_bit (FLAG_COMMIT, &ai->flags);
4919 } else if ( !strncmp( line, "LongRetryLimit: ", 16 ) ) {
4920 int v, i = 0;
4921
4922 line += 16;
4923 v = get_dec_u16(line, &i, 3);
4924 v = (v<0) ? 0 : ((v>255) ? 255 : v);
4925 ai->config.longRetryLimit = (u16)v;
4926 set_bit (FLAG_COMMIT, &ai->flags);
4927 } else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) {
4928 int v, i = 0;
4929
4930 line += 17;
4931 v = get_dec_u16(line, &i, 3);
4932 v = (v<0) ? 0 : ((v>255) ? 255 : v);
4933 ai->config.shortRetryLimit = (u16)v;
4934 set_bit (FLAG_COMMIT, &ai->flags);
4935 } else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) {
4936 int v, i = 0;
4937
4938 line += 14;
4939 v = get_dec_u16(line, &i, 4);
Dan Williams15db2762006-03-16 13:46:27 -05004940 v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941 ai->config.rtsThres = (u16)v;
4942 set_bit (FLAG_COMMIT, &ai->flags);
4943 } else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) {
4944 int v, i = 0;
4945
4946 line += 16;
4947 v = get_dec_u16(line, &i, 5);
4948 v = (v<0) ? 0 : v;
4949 ai->config.txLifetime = (u16)v;
4950 set_bit (FLAG_COMMIT, &ai->flags);
4951 } else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) {
4952 int v, i = 0;
4953
4954 line += 16;
4955 v = get_dec_u16(line, &i, 5);
4956 v = (v<0) ? 0 : v;
4957 ai->config.rxLifetime = (u16)v;
4958 set_bit (FLAG_COMMIT, &ai->flags);
4959 } else if ( !strncmp( line, "TXDiversity: ", 13 ) ) {
4960 ai->config.txDiversity =
4961 (line[13]=='l') ? 1 :
4962 ((line[13]=='r')? 2: 3);
4963 set_bit (FLAG_COMMIT, &ai->flags);
4964 } else if ( !strncmp( line, "RXDiversity: ", 13 ) ) {
4965 ai->config.rxDiversity =
4966 (line[13]=='l') ? 1 :
4967 ((line[13]=='r')? 2: 3);
4968 set_bit (FLAG_COMMIT, &ai->flags);
4969 } else if ( !strncmp( line, "FragThreshold: ", 15 ) ) {
4970 int v, i = 0;
4971
4972 line += 15;
4973 v = get_dec_u16(line, &i, 4);
Dan Williams15db2762006-03-16 13:46:27 -05004974 v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 v = v & 0xfffe; /* Make sure its even */
4976 ai->config.fragThresh = (u16)v;
4977 set_bit (FLAG_COMMIT, &ai->flags);
4978 } else if (!strncmp(line, "Modulation: ", 12)) {
4979 line += 12;
4980 switch(*line) {
4981 case 'd': ai->config.modulation=MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break;
4982 case 'c': ai->config.modulation=MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break;
4983 case 'm': ai->config.modulation=MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break;
Dan Williams934d8bf2006-03-16 13:46:23 -05004984 default: airo_print_warn(ai->dev->name, "Unknown modulation");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 }
4986 } else if (!strncmp(line, "Preamble: ", 10)) {
4987 line += 10;
4988 switch(*line) {
4989 case 'a': ai->config.preamble=PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break;
4990 case 'l': ai->config.preamble=PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break;
4991 case 's': ai->config.preamble=PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break;
Dan Williams934d8bf2006-03-16 13:46:23 -05004992 default: airo_print_warn(ai->dev->name, "Unknown preamble");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 }
4994 } else {
Dan Williams934d8bf2006-03-16 13:46:23 -05004995 airo_print_warn(ai->dev->name, "Couldn't figure out %s", line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 }
4997 while( line[0] && line[0] != '\n' ) line++;
4998 if ( line[0] ) line++;
4999 }
5000 airo_config_commit(dev, NULL, NULL, NULL);
5001}
5002
5003static char *get_rmode(u16 mode) {
5004 switch(mode&0xff) {
5005 case RXMODE_RFMON: return "rfmon";
5006 case RXMODE_RFMON_ANYBSS: return "yna (any) bss rfmon";
5007 case RXMODE_LANMON: return "lanmon";
5008 }
5009 return "ESS";
5010}
5011
5012static int proc_config_open( struct inode *inode, struct file *file ) {
5013 struct proc_data *data;
5014 struct proc_dir_entry *dp = PDE(inode);
5015 struct net_device *dev = dp->data;
5016 struct airo_info *ai = dev->priv;
5017 int i;
5018
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005019 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005021 data = (struct proc_data *)file->private_data;
5022 if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
5023 kfree (file->private_data);
5024 return -ENOMEM;
5025 }
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005026 if ((data->wbuffer = kzalloc( 2048, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027 kfree (data->rbuffer);
5028 kfree (file->private_data);
5029 return -ENOMEM;
5030 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 data->maxwritelen = 2048;
5032 data->on_close = proc_config_on_close;
5033
5034 readConfigRid(ai, 1);
5035
5036 i = sprintf( data->rbuffer,
5037 "Mode: %s\n"
5038 "Radio: %s\n"
5039 "NodeName: %-16s\n"
5040 "PowerMode: %s\n"
5041 "DataRates: %d %d %d %d %d %d %d %d\n"
5042 "Channel: %d\n"
5043 "XmitPower: %d\n",
5044 (ai->config.opmode & 0xFF) == 0 ? "adhoc" :
5045 (ai->config.opmode & 0xFF) == 1 ? get_rmode(ai->config.rmode):
5046 (ai->config.opmode & 0xFF) == 2 ? "AP" :
5047 (ai->config.opmode & 0xFF) == 3 ? "AP RPTR" : "Error",
5048 test_bit(FLAG_RADIO_OFF, &ai->flags) ? "off" : "on",
5049 ai->config.nodeName,
5050 ai->config.powerSaveMode == 0 ? "CAM" :
5051 ai->config.powerSaveMode == 1 ? "PSP" :
5052 ai->config.powerSaveMode == 2 ? "PSPCAM" : "Error",
5053 (int)ai->config.rates[0],
5054 (int)ai->config.rates[1],
5055 (int)ai->config.rates[2],
5056 (int)ai->config.rates[3],
5057 (int)ai->config.rates[4],
5058 (int)ai->config.rates[5],
5059 (int)ai->config.rates[6],
5060 (int)ai->config.rates[7],
5061 (int)ai->config.channelSet,
5062 (int)ai->config.txPower
5063 );
5064 sprintf( data->rbuffer + i,
5065 "LongRetryLimit: %d\n"
5066 "ShortRetryLimit: %d\n"
5067 "RTSThreshold: %d\n"
5068 "TXMSDULifetime: %d\n"
5069 "RXMSDULifetime: %d\n"
5070 "TXDiversity: %s\n"
5071 "RXDiversity: %s\n"
5072 "FragThreshold: %d\n"
5073 "WEP: %s\n"
5074 "Modulation: %s\n"
5075 "Preamble: %s\n",
5076 (int)ai->config.longRetryLimit,
5077 (int)ai->config.shortRetryLimit,
5078 (int)ai->config.rtsThres,
5079 (int)ai->config.txLifetime,
5080 (int)ai->config.rxLifetime,
5081 ai->config.txDiversity == 1 ? "left" :
5082 ai->config.txDiversity == 2 ? "right" : "both",
5083 ai->config.rxDiversity == 1 ? "left" :
5084 ai->config.rxDiversity == 2 ? "right" : "both",
5085 (int)ai->config.fragThresh,
5086 ai->config.authType == AUTH_ENCRYPT ? "encrypt" :
5087 ai->config.authType == AUTH_SHAREDKEY ? "shared" : "open",
5088 ai->config.modulation == 0 ? "default" :
5089 ai->config.modulation == MOD_CCK ? "cck" :
5090 ai->config.modulation == MOD_MOK ? "mok" : "error",
5091 ai->config.preamble == PREAMBLE_AUTO ? "auto" :
5092 ai->config.preamble == PREAMBLE_LONG ? "long" :
5093 ai->config.preamble == PREAMBLE_SHORT ? "short" : "error"
5094 );
5095 data->readlen = strlen( data->rbuffer );
5096 return 0;
5097}
5098
Al Viro0dd22122007-12-17 16:11:57 -05005099static void proc_SSID_on_close(struct inode *inode, struct file *file)
5100{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101 struct proc_data *data = (struct proc_data *)file->private_data;
5102 struct proc_dir_entry *dp = PDE(inode);
5103 struct net_device *dev = dp->data;
5104 struct airo_info *ai = dev->priv;
5105 SsidRid SSID_rid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 int i;
Al Viro0dd22122007-12-17 16:11:57 -05005107 char *p = data->wbuffer;
5108 char *end = p + data->writelen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109
Al Viro0dd22122007-12-17 16:11:57 -05005110 if (!data->writelen)
5111 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112
Al Viro0dd22122007-12-17 16:11:57 -05005113 *end = '\n'; /* sentinel; we have space for it */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114
Al Viro0dd22122007-12-17 16:11:57 -05005115 memset(&SSID_rid, 0, sizeof(SSID_rid));
5116
5117 for (i = 0; i < 3 && p < end; i++) {
5118 int j = 0;
5119 /* copy up to 32 characters from this line */
5120 while (*p != '\n' && j < 32)
5121 SSID_rid.ssids[i].ssid[j++] = *p++;
5122 if (j == 0)
5123 break;
5124 SSID_rid.ssids[i].len = cpu_to_le16(j);
5125 /* skip to the beginning of the next line */
5126 while (*p++ != '\n')
5127 ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 }
5129 if (i)
Al Viro0dd22122007-12-17 16:11:57 -05005130 SSID_rid.len = cpu_to_le16(sizeof(SSID_rid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131 disable_MAC(ai, 1);
5132 writeSsidRid(ai, &SSID_rid, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005133 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005134}
5135
Jesper Juhl77933d72005-07-27 11:46:09 -07005136static inline u8 hexVal(char c) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137 if (c>='0' && c<='9') return c -= '0';
5138 if (c>='a' && c<='f') return c -= 'a'-10;
5139 if (c>='A' && c<='F') return c -= 'A'-10;
5140 return 0;
5141}
5142
5143static void proc_APList_on_close( struct inode *inode, struct file *file ) {
5144 struct proc_data *data = (struct proc_data *)file->private_data;
5145 struct proc_dir_entry *dp = PDE(inode);
5146 struct net_device *dev = dp->data;
5147 struct airo_info *ai = dev->priv;
5148 APListRid APList_rid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 int i;
5150
5151 if ( !data->writelen ) return;
5152
5153 memset( &APList_rid, 0, sizeof(APList_rid) );
5154 APList_rid.len = sizeof(APList_rid);
5155
5156 for( i = 0; i < 4 && data->writelen >= (i+1)*6*3; i++ ) {
5157 int j;
5158 for( j = 0; j < 6*3 && data->wbuffer[j+i*6*3]; j++ ) {
5159 switch(j%3) {
5160 case 0:
5161 APList_rid.ap[i][j/3]=
5162 hexVal(data->wbuffer[j+i*6*3])<<4;
5163 break;
5164 case 1:
5165 APList_rid.ap[i][j/3]|=
5166 hexVal(data->wbuffer[j+i*6*3]);
5167 break;
5168 }
5169 }
5170 }
5171 disable_MAC(ai, 1);
5172 writeAPListRid(ai, &APList_rid, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005173 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174}
5175
5176/* This function wraps PC4500_writerid with a MAC disable */
5177static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data,
5178 int len, int dummy ) {
5179 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180
5181 disable_MAC(ai, 1);
5182 rc = PC4500_writerid(ai, rid, rid_data, len, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005183 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 return rc;
5185}
5186
5187/* Returns the length of the key at the index. If index == 0xffff
5188 * the index of the transmit key is returned. If the key doesn't exist,
5189 * -1 will be returned.
5190 */
5191static int get_wep_key(struct airo_info *ai, u16 index) {
5192 WepKeyRid wkr;
5193 int rc;
Al Viro4293ea32007-12-19 19:21:51 -05005194 __le16 lastindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195
5196 rc = readWepKeyRid(ai, &wkr, 1, 1);
5197 if (rc == SUCCESS) do {
5198 lastindex = wkr.kindex;
Al Viro4293ea32007-12-19 19:21:51 -05005199 if (wkr.kindex == cpu_to_le16(index)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 if (index == 0xffff) {
5201 return wkr.mac[0];
5202 }
Al Viro4293ea32007-12-19 19:21:51 -05005203 return le16_to_cpu(wkr.klen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204 }
5205 readWepKeyRid(ai, &wkr, 0, 1);
Al Viro4293ea32007-12-19 19:21:51 -05005206 } while (lastindex != wkr.kindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 return -1;
5208}
5209
5210static int set_wep_key(struct airo_info *ai, u16 index,
Al Viro4293ea32007-12-19 19:21:51 -05005211 const char *key, u16 keylen, int perm, int lock )
5212{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
5214 WepKeyRid wkr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215
5216 memset(&wkr, 0, sizeof(wkr));
5217 if (keylen == 0) {
5218// We are selecting which key to use
Al Viro4293ea32007-12-19 19:21:51 -05005219 wkr.len = cpu_to_le16(sizeof(wkr));
5220 wkr.kindex = cpu_to_le16(0xffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 wkr.mac[0] = (char)index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222 if (perm) ai->defindex = (char)index;
5223 } else {
5224// We are actually setting the key
Al Viro4293ea32007-12-19 19:21:51 -05005225 wkr.len = cpu_to_le16(sizeof(wkr));
5226 wkr.kindex = cpu_to_le16(index);
5227 wkr.klen = cpu_to_le16(keylen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 memcpy( wkr.key, key, keylen );
5229 memcpy( wkr.mac, macaddr, ETH_ALEN );
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 }
5231
Dan Streetmanf89b2322005-11-11 11:41:42 -05005232 if (perm) disable_MAC(ai, lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 writeWepKeyRid(ai, &wkr, perm, lock);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005234 if (perm) enable_MAC(ai, lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 return 0;
5236}
5237
5238static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
5239 struct proc_data *data;
5240 struct proc_dir_entry *dp = PDE(inode);
5241 struct net_device *dev = dp->data;
5242 struct airo_info *ai = dev->priv;
5243 int i;
5244 char key[16];
5245 u16 index = 0;
5246 int j = 0;
5247
5248 memset(key, 0, sizeof(key));
5249
5250 data = (struct proc_data *)file->private_data;
5251 if ( !data->writelen ) return;
5252
5253 if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' &&
5254 (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) {
5255 index = data->wbuffer[0] - '0';
5256 if (data->wbuffer[1] == '\n') {
5257 set_wep_key(ai, index, NULL, 0, 1, 1);
5258 return;
5259 }
5260 j = 2;
5261 } else {
Dan Williams934d8bf2006-03-16 13:46:23 -05005262 airo_print_err(ai->dev->name, "WepKey passed invalid key index");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 return;
5264 }
5265
5266 for( i = 0; i < 16*3 && data->wbuffer[i+j]; i++ ) {
5267 switch(i%3) {
5268 case 0:
5269 key[i/3] = hexVal(data->wbuffer[i+j])<<4;
5270 break;
5271 case 1:
5272 key[i/3] |= hexVal(data->wbuffer[i+j]);
5273 break;
5274 }
5275 }
5276 set_wep_key(ai, index, key, i/3, 1, 1);
5277}
5278
Al Viro4293ea32007-12-19 19:21:51 -05005279static int proc_wepkey_open( struct inode *inode, struct file *file )
5280{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281 struct proc_data *data;
5282 struct proc_dir_entry *dp = PDE(inode);
5283 struct net_device *dev = dp->data;
5284 struct airo_info *ai = dev->priv;
5285 char *ptr;
5286 WepKeyRid wkr;
Al Viro4293ea32007-12-19 19:21:51 -05005287 __le16 lastindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288 int j=0;
5289 int rc;
5290
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005291 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293 memset(&wkr, 0, sizeof(wkr));
5294 data = (struct proc_data *)file->private_data;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005295 if ((data->rbuffer = kzalloc( 180, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 kfree (file->private_data);
5297 return -ENOMEM;
5298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299 data->writelen = 0;
5300 data->maxwritelen = 80;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005301 if ((data->wbuffer = kzalloc( 80, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302 kfree (data->rbuffer);
5303 kfree (file->private_data);
5304 return -ENOMEM;
5305 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306 data->on_close = proc_wepkey_on_close;
5307
5308 ptr = data->rbuffer;
5309 strcpy(ptr, "No wep keys\n");
5310 rc = readWepKeyRid(ai, &wkr, 1, 1);
5311 if (rc == SUCCESS) do {
5312 lastindex = wkr.kindex;
Al Viro4293ea32007-12-19 19:21:51 -05005313 if (wkr.kindex == cpu_to_le16(0xffff)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314 j += sprintf(ptr+j, "Tx key = %d\n",
5315 (int)wkr.mac[0]);
5316 } else {
5317 j += sprintf(ptr+j, "Key %d set with length = %d\n",
Al Viro4293ea32007-12-19 19:21:51 -05005318 le16_to_cpu(wkr.kindex),
5319 le16_to_cpu(wkr.klen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005320 }
5321 readWepKeyRid(ai, &wkr, 0, 1);
5322 } while((lastindex != wkr.kindex) && (j < 180-30));
5323
5324 data->readlen = strlen( data->rbuffer );
5325 return 0;
5326}
5327
Al Viro0dd22122007-12-17 16:11:57 -05005328static int proc_SSID_open(struct inode *inode, struct file *file)
5329{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330 struct proc_data *data;
5331 struct proc_dir_entry *dp = PDE(inode);
5332 struct net_device *dev = dp->data;
5333 struct airo_info *ai = dev->priv;
5334 int i;
5335 char *ptr;
5336 SsidRid SSID_rid;
5337
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005338 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005339 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340 data = (struct proc_data *)file->private_data;
5341 if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
5342 kfree (file->private_data);
5343 return -ENOMEM;
5344 }
5345 data->writelen = 0;
5346 data->maxwritelen = 33*3;
Al Viro0dd22122007-12-17 16:11:57 -05005347 /* allocate maxwritelen + 1; we'll want a sentinel */
5348 if ((data->wbuffer = kzalloc(33*3 + 1, GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005349 kfree (data->rbuffer);
5350 kfree (file->private_data);
5351 return -ENOMEM;
5352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353 data->on_close = proc_SSID_on_close;
5354
5355 readSsidRid(ai, &SSID_rid);
5356 ptr = data->rbuffer;
Al Viro0dd22122007-12-17 16:11:57 -05005357 for (i = 0; i < 3; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358 int j;
Al Viro0dd22122007-12-17 16:11:57 -05005359 size_t len = le16_to_cpu(SSID_rid.ssids[i].len);
5360 if (!len)
5361 break;
5362 if (len > 32)
5363 len = 32;
5364 for (j = 0; j < len && SSID_rid.ssids[i].ssid[j]; j++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 *ptr++ = SSID_rid.ssids[i].ssid[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366 *ptr++ = '\n';
5367 }
5368 *ptr = '\0';
5369 data->readlen = strlen( data->rbuffer );
5370 return 0;
5371}
5372
5373static int proc_APList_open( struct inode *inode, struct file *file ) {
5374 struct proc_data *data;
5375 struct proc_dir_entry *dp = PDE(inode);
5376 struct net_device *dev = dp->data;
5377 struct airo_info *ai = dev->priv;
5378 int i;
5379 char *ptr;
5380 APListRid APList_rid;
Joe Perches0795af52007-10-03 17:59:30 -07005381 DECLARE_MAC_BUF(mac);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005383 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 data = (struct proc_data *)file->private_data;
5386 if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
5387 kfree (file->private_data);
5388 return -ENOMEM;
5389 }
5390 data->writelen = 0;
5391 data->maxwritelen = 4*6*3;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005392 if ((data->wbuffer = kzalloc( data->maxwritelen, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393 kfree (data->rbuffer);
5394 kfree (file->private_data);
5395 return -ENOMEM;
5396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 data->on_close = proc_APList_on_close;
5398
5399 readAPListRid(ai, &APList_rid);
5400 ptr = data->rbuffer;
5401 for( i = 0; i < 4; i++ ) {
5402// We end when we find a zero MAC
5403 if ( !*(int*)APList_rid.ap[i] &&
5404 !*(int*)&APList_rid.ap[i][2]) break;
Joe Perches0795af52007-10-03 17:59:30 -07005405 ptr += sprintf(ptr, "%s\n",
5406 print_mac(mac, APList_rid.ap[i]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 }
5408 if (i==0) ptr += sprintf(ptr, "Not using specific APs\n");
5409
5410 *ptr = '\0';
5411 data->readlen = strlen( data->rbuffer );
5412 return 0;
5413}
5414
5415static int proc_BSSList_open( struct inode *inode, struct file *file ) {
5416 struct proc_data *data;
5417 struct proc_dir_entry *dp = PDE(inode);
5418 struct net_device *dev = dp->data;
5419 struct airo_info *ai = dev->priv;
5420 char *ptr;
5421 BSSListRid BSSList_rid;
5422 int rc;
5423 /* If doLoseSync is not 1, we won't do a Lose Sync */
5424 int doLoseSync = -1;
Joe Perches0795af52007-10-03 17:59:30 -07005425 DECLARE_MAC_BUF(mac);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005427 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 data = (struct proc_data *)file->private_data;
5430 if ((data->rbuffer = kmalloc( 1024, GFP_KERNEL )) == NULL) {
5431 kfree (file->private_data);
5432 return -ENOMEM;
5433 }
5434 data->writelen = 0;
5435 data->maxwritelen = 0;
5436 data->wbuffer = NULL;
5437 data->on_close = NULL;
5438
5439 if (file->f_mode & FMODE_WRITE) {
5440 if (!(file->f_mode & FMODE_READ)) {
5441 Cmd cmd;
5442 Resp rsp;
5443
5444 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
5445 memset(&cmd, 0, sizeof(cmd));
5446 cmd.cmd=CMD_LISTBSS;
5447 if (down_interruptible(&ai->sem))
5448 return -ERESTARTSYS;
5449 issuecommand(ai, &cmd, &rsp);
5450 up(&ai->sem);
5451 data->readlen = 0;
5452 return 0;
5453 }
5454 doLoseSync = 1;
5455 }
5456 ptr = data->rbuffer;
5457 /* There is a race condition here if there are concurrent opens.
5458 Since it is a rare condition, we'll just live with it, otherwise
5459 we have to add a spin lock... */
5460 rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
Al Viro17e70492007-12-19 18:56:37 -05005461 while(rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) {
Joe Perches0795af52007-10-03 17:59:30 -07005462 ptr += sprintf(ptr, "%s %*s rssi = %d",
5463 print_mac(mac, BSSList_rid.bssid),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464 (int)BSSList_rid.ssidLen,
5465 BSSList_rid.ssid,
Al Viro17e70492007-12-19 18:56:37 -05005466 le16_to_cpu(BSSList_rid.dBm));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 ptr += sprintf(ptr, " channel = %d %s %s %s %s\n",
Al Viro17e70492007-12-19 18:56:37 -05005468 le16_to_cpu(BSSList_rid.dsChannel),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469 BSSList_rid.cap & CAP_ESS ? "ESS" : "",
5470 BSSList_rid.cap & CAP_IBSS ? "adhoc" : "",
5471 BSSList_rid.cap & CAP_PRIVACY ? "wep" : "",
5472 BSSList_rid.cap & CAP_SHORTHDR ? "shorthdr" : "");
5473 rc = readBSSListRid(ai, 0, &BSSList_rid);
5474 }
5475 *ptr = '\0';
5476 data->readlen = strlen( data->rbuffer );
5477 return 0;
5478}
5479
5480static int proc_close( struct inode *inode, struct file *file )
5481{
Jesper Juhlb4558ea2005-10-28 16:53:13 -04005482 struct proc_data *data = file->private_data;
5483
5484 if (data->on_close != NULL)
5485 data->on_close(inode, file);
5486 kfree(data->rbuffer);
5487 kfree(data->wbuffer);
5488 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 return 0;
5490}
5491
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492/* Since the card doesn't automatically switch to the right WEP mode,
5493 we will make it do it. If the card isn't associated, every secs we
5494 will switch WEP modes to see if that will help. If the card is
5495 associated we will check every minute to see if anything has
5496 changed. */
5497static void timer_func( struct net_device *dev ) {
5498 struct airo_info *apriv = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499
5500/* We don't have a link so try changing the authtype */
5501 readConfigRid(apriv, 0);
5502 disable_MAC(apriv, 0);
5503 switch(apriv->config.authType) {
5504 case AUTH_ENCRYPT:
5505/* So drop to OPEN */
5506 apriv->config.authType = AUTH_OPEN;
5507 break;
5508 case AUTH_SHAREDKEY:
5509 if (apriv->keyindex < auto_wep) {
5510 set_wep_key(apriv, apriv->keyindex, NULL, 0, 0, 0);
5511 apriv->config.authType = AUTH_SHAREDKEY;
5512 apriv->keyindex++;
5513 } else {
5514 /* Drop to ENCRYPT */
5515 apriv->keyindex = 0;
5516 set_wep_key(apriv, apriv->defindex, NULL, 0, 0, 0);
5517 apriv->config.authType = AUTH_ENCRYPT;
5518 }
5519 break;
5520 default: /* We'll escalate to SHAREDKEY */
5521 apriv->config.authType = AUTH_SHAREDKEY;
5522 }
5523 set_bit (FLAG_COMMIT, &apriv->flags);
5524 writeConfigRid(apriv, 0);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005525 enable_MAC(apriv, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 up(&apriv->sem);
5527
5528/* Schedule check to see if the change worked */
Dan Williams3c304952006-04-15 12:26:18 -04005529 clear_bit(JOB_AUTOWEP, &apriv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530 apriv->expires = RUN_AT(HZ*3);
5531}
5532
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533#ifdef CONFIG_PCI
5534static int __devinit airo_pci_probe(struct pci_dev *pdev,
5535 const struct pci_device_id *pent)
5536{
5537 struct net_device *dev;
5538
5539 if (pci_enable_device(pdev))
5540 return -ENODEV;
5541 pci_set_master(pdev);
5542
5543 if (pdev->device == 0x5000 || pdev->device == 0xa504)
5544 dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev);
5545 else
5546 dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev);
Michal Schmidt777ec5e2007-06-29 15:33:30 +02005547 if (!dev) {
5548 pci_disable_device(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 return -ENODEV;
Michal Schmidt777ec5e2007-06-29 15:33:30 +02005550 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551
5552 pci_set_drvdata(pdev, dev);
5553 return 0;
5554}
5555
5556static void __devexit airo_pci_remove(struct pci_dev *pdev)
5557{
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01005558 struct net_device *dev = pci_get_drvdata(pdev);
5559
5560 airo_print_info(dev->name, "Unregistering...");
5561 stop_airo_card(dev, 1);
Michal Schmidt777ec5e2007-06-29 15:33:30 +02005562 pci_disable_device(pdev);
5563 pci_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564}
5565
Pavel Machek05adc3b2005-04-16 15:25:25 -07005566static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567{
5568 struct net_device *dev = pci_get_drvdata(pdev);
5569 struct airo_info *ai = dev->priv;
5570 Cmd cmd;
5571 Resp rsp;
5572
5573 if ((ai->APList == NULL) &&
5574 (ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL)) == NULL)
5575 return -ENOMEM;
5576 if ((ai->SSID == NULL) &&
5577 (ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL)) == NULL)
5578 return -ENOMEM;
5579 readAPListRid(ai, ai->APList);
5580 readSsidRid(ai, ai->SSID);
5581 memset(&cmd, 0, sizeof(cmd));
5582 /* the lock will be released at the end of the resume callback */
5583 if (down_interruptible(&ai->sem))
5584 return -EAGAIN;
5585 disable_MAC(ai, 0);
5586 netif_device_detach(dev);
5587 ai->power = state;
5588 cmd.cmd=HOSTSLEEP;
5589 issuecommand(ai, &cmd, &rsp);
5590
Pavel Machek1cc68ae2005-06-20 15:33:04 -07005591 pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 pci_save_state(pdev);
Pavel Machek1cc68ae2005-06-20 15:33:04 -07005593 return pci_set_power_state(pdev, pci_choose_state(pdev, state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594}
5595
5596static int airo_pci_resume(struct pci_dev *pdev)
5597{
5598 struct net_device *dev = pci_get_drvdata(pdev);
5599 struct airo_info *ai = dev->priv;
Michal Schmidt53232802005-10-04 07:46:21 -04005600 pci_power_t prev_state = pdev->current_state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601
Michal Schmidt53232802005-10-04 07:46:21 -04005602 pci_set_power_state(pdev, PCI_D0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603 pci_restore_state(pdev);
Michal Schmidt53232802005-10-04 07:46:21 -04005604 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605
Michal Schmidt53232802005-10-04 07:46:21 -04005606 if (prev_state != PCI_D1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 reset_card(dev, 0);
5608 mpi_init_descriptors(ai);
5609 setup_card(ai, dev->dev_addr, 0);
5610 clear_bit(FLAG_RADIO_OFF, &ai->flags);
5611 clear_bit(FLAG_PENDING_XMIT, &ai->flags);
5612 } else {
5613 OUT4500(ai, EVACK, EV_AWAKEN);
5614 OUT4500(ai, EVACK, EV_AWAKEN);
5615 msleep(100);
5616 }
5617
5618 set_bit (FLAG_COMMIT, &ai->flags);
5619 disable_MAC(ai, 0);
5620 msleep(200);
5621 if (ai->SSID) {
5622 writeSsidRid(ai, ai->SSID, 0);
5623 kfree(ai->SSID);
5624 ai->SSID = NULL;
5625 }
5626 if (ai->APList) {
5627 writeAPListRid(ai, ai->APList, 0);
5628 kfree(ai->APList);
5629 ai->APList = NULL;
5630 }
5631 writeConfigRid(ai, 0);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005632 enable_MAC(ai, 0);
Pavel Machek1cc68ae2005-06-20 15:33:04 -07005633 ai->power = PMSG_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634 netif_device_attach(dev);
5635 netif_wake_queue(dev);
5636 enable_interrupts(ai);
5637 up(&ai->sem);
5638 return 0;
5639}
5640#endif
5641
5642static int __init airo_init_module( void )
5643{
Jeff Garzikde897882006-10-01 07:31:09 -04005644 int i;
5645#if 0
5646 int have_isa_dev = 0;
5647#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648
5649 airo_entry = create_proc_entry("aironet",
5650 S_IFDIR | airo_perm,
5651 proc_root_driver);
Jeff Garzikde897882006-10-01 07:31:09 -04005652
5653 if (airo_entry) {
5654 airo_entry->uid = proc_uid;
5655 airo_entry->gid = proc_gid;
5656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657
5658 for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05005659 airo_print_info("", "Trying to configure ISA adapter at irq=%d "
5660 "io=0x%x", irq[i], io[i] );
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661 if (init_airo_card( irq[i], io[i], 0, NULL ))
Jeff Garzikde897882006-10-01 07:31:09 -04005662#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663 have_isa_dev = 1;
Jeff Garzikde897882006-10-01 07:31:09 -04005664#else
5665 /* do nothing */ ;
5666#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667 }
5668
5669#ifdef CONFIG_PCI
Dan Williams934d8bf2006-03-16 13:46:23 -05005670 airo_print_info("", "Probing for PCI adapters");
Jeff Garzikde897882006-10-01 07:31:09 -04005671 i = pci_register_driver(&airo_driver);
Dan Williams934d8bf2006-03-16 13:46:23 -05005672 airo_print_info("", "Finished probing for PCI adapters");
Jeff Garzikde897882006-10-01 07:31:09 -04005673
5674 if (i) {
5675 remove_proc_entry("aironet", proc_root_driver);
5676 return i;
5677 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678#endif
5679
5680 /* Always exit with success, as we are a library module
5681 * as well as a driver module
5682 */
5683 return 0;
5684}
5685
5686static void __exit airo_cleanup_module( void )
5687{
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01005688 struct airo_info *ai;
5689 while(!list_empty(&airo_devices)) {
5690 ai = list_entry(airo_devices.next, struct airo_info, dev_list);
5691 airo_print_info(ai->dev->name, "Unregistering...");
5692 stop_airo_card(ai->dev, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693 }
5694#ifdef CONFIG_PCI
5695 pci_unregister_driver(&airo_driver);
5696#endif
5697 remove_proc_entry("aironet", proc_root_driver);
5698}
5699
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700/*
5701 * Initial Wireless Extension code for Aironet driver by :
5702 * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 17 November 00
5703 * Conversion to new driver API by :
5704 * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 26 March 02
5705 * Javier also did a good amount of work here, adding some new extensions
5706 * and fixing my code. Let's just say that without him this code just
5707 * would not work at all... - Jean II
5708 */
5709
Dan Williams41480af2005-05-10 09:45:51 -04005710static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi)
5711{
5712 if( !rssi_rid )
5713 return 0;
5714
5715 return (0x100 - rssi_rid[rssi].rssidBm);
5716}
5717
5718static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
5719{
5720 int i;
5721
5722 if( !rssi_rid )
5723 return 0;
5724
5725 for( i = 0; i < 256; i++ )
5726 if (rssi_rid[i].rssidBm == dbm)
5727 return rssi_rid[i].rssipct;
5728
5729 return 0;
5730}
5731
5732
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid)
5734{
5735 int quality = 0;
5736
5737 if ((status_rid->mode & 0x3f) == 0x3f && (cap_rid->hardCap & 8)) {
5738 if (memcmp(cap_rid->prodName, "350", 3))
5739 if (status_rid->signalQuality > 0x20)
5740 quality = 0;
5741 else
5742 quality = 0x20 - status_rid->signalQuality;
5743 else
5744 if (status_rid->signalQuality > 0xb0)
5745 quality = 0;
5746 else if (status_rid->signalQuality < 0x10)
5747 quality = 0xa0;
5748 else
5749 quality = 0xb0 - status_rid->signalQuality;
5750 }
5751 return quality;
5752}
5753
5754#define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0)
5755#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50);
5756
5757/*------------------------------------------------------------------*/
5758/*
5759 * Wireless Handler : get protocol name
5760 */
5761static int airo_get_name(struct net_device *dev,
5762 struct iw_request_info *info,
5763 char *cwrq,
5764 char *extra)
5765{
5766 strcpy(cwrq, "IEEE 802.11-DS");
5767 return 0;
5768}
5769
5770/*------------------------------------------------------------------*/
5771/*
5772 * Wireless Handler : set frequency
5773 */
5774static int airo_set_freq(struct net_device *dev,
5775 struct iw_request_info *info,
5776 struct iw_freq *fwrq,
5777 char *extra)
5778{
5779 struct airo_info *local = dev->priv;
5780 int rc = -EINPROGRESS; /* Call commit handler */
5781
5782 /* If setting by frequency, convert to a channel */
5783 if((fwrq->e == 1) &&
5784 (fwrq->m >= (int) 2.412e8) &&
5785 (fwrq->m <= (int) 2.487e8)) {
5786 int f = fwrq->m / 100000;
5787 int c = 0;
5788 while((c < 14) && (f != frequency_list[c]))
5789 c++;
5790 /* Hack to fall through... */
5791 fwrq->e = 0;
5792 fwrq->m = c + 1;
5793 }
5794 /* Setting by channel number */
5795 if((fwrq->m > 1000) || (fwrq->e > 0))
5796 rc = -EOPNOTSUPP;
5797 else {
5798 int channel = fwrq->m;
5799 /* We should do a better check than that,
5800 * based on the card capability !!! */
Javier Achirica2610c732006-01-17 08:01:01 -05005801 if((channel < 1) || (channel > 14)) {
Dan Williams934d8bf2006-03-16 13:46:23 -05005802 airo_print_dbg(dev->name, "New channel value of %d is invalid!",
5803 fwrq->m);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804 rc = -EINVAL;
5805 } else {
5806 readConfigRid(local, 1);
5807 /* Yes ! We can set it !!! */
Javier Achirica2610c732006-01-17 08:01:01 -05005808 local->config.channelSet = (u16) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809 set_bit (FLAG_COMMIT, &local->flags);
5810 }
5811 }
5812 return rc;
5813}
5814
5815/*------------------------------------------------------------------*/
5816/*
5817 * Wireless Handler : get frequency
5818 */
5819static int airo_get_freq(struct net_device *dev,
5820 struct iw_request_info *info,
5821 struct iw_freq *fwrq,
5822 char *extra)
5823{
5824 struct airo_info *local = dev->priv;
5825 StatusRid status_rid; /* Card status info */
Javier Achirica2610c732006-01-17 08:01:01 -05005826 int ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827
5828 readConfigRid(local, 1);
5829 if ((local->config.opmode & 0xFF) == MODE_STA_ESS)
5830 status_rid.channel = local->config.channelSet;
5831 else
5832 readStatusRid(local, &status_rid, 1);
5833
Javier Achirica2610c732006-01-17 08:01:01 -05005834 ch = (int)status_rid.channel;
5835 if((ch > 0) && (ch < 15)) {
5836 fwrq->m = frequency_list[ch - 1] * 100000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837 fwrq->e = 1;
Javier Achirica2610c732006-01-17 08:01:01 -05005838 } else {
5839 fwrq->m = ch;
5840 fwrq->e = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842
5843 return 0;
5844}
5845
5846/*------------------------------------------------------------------*/
5847/*
5848 * Wireless Handler : set ESSID
5849 */
5850static int airo_set_essid(struct net_device *dev,
5851 struct iw_request_info *info,
5852 struct iw_point *dwrq,
5853 char *extra)
5854{
5855 struct airo_info *local = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856 SsidRid SSID_rid; /* SSIDs */
5857
5858 /* Reload the list of current SSID */
5859 readSsidRid(local, &SSID_rid);
5860
5861 /* Check if we asked for `any' */
5862 if(dwrq->flags == 0) {
5863 /* Just send an empty SSID list */
5864 memset(&SSID_rid, 0, sizeof(SSID_rid));
5865 } else {
5866 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
5867
5868 /* Check the size of the string */
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07005869 if(dwrq->length > IW_ESSID_MAX_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870 return -E2BIG ;
5871 }
5872 /* Check if index is valid */
5873 if((index < 0) || (index >= 4)) {
5874 return -EINVAL;
5875 }
5876
5877 /* Set the SSID */
5878 memset(SSID_rid.ssids[index].ssid, 0,
5879 sizeof(SSID_rid.ssids[index].ssid));
5880 memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
Al Viro0dd22122007-12-17 16:11:57 -05005881 SSID_rid.ssids[index].len = cpu_to_le16(dwrq->length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882 }
Al Viro0dd22122007-12-17 16:11:57 -05005883 SSID_rid.len = cpu_to_le16(sizeof(SSID_rid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884 /* Write it to the card */
5885 disable_MAC(local, 1);
5886 writeSsidRid(local, &SSID_rid, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005887 enable_MAC(local, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888
5889 return 0;
5890}
5891
5892/*------------------------------------------------------------------*/
5893/*
5894 * Wireless Handler : get ESSID
5895 */
5896static int airo_get_essid(struct net_device *dev,
5897 struct iw_request_info *info,
5898 struct iw_point *dwrq,
5899 char *extra)
5900{
5901 struct airo_info *local = dev->priv;
5902 StatusRid status_rid; /* Card status info */
5903
5904 readStatusRid(local, &status_rid, 1);
5905
5906 /* Note : if dwrq->flags != 0, we should
5907 * get the relevant SSID from the SSID list... */
5908
5909 /* Get the current SSID */
5910 memcpy(extra, status_rid.SSID, status_rid.SSIDlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911 /* If none, we may want to get the one that was set */
5912
5913 /* Push it out ! */
Dan Williamsd6a13a22006-01-12 15:00:58 -05005914 dwrq->length = status_rid.SSIDlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915 dwrq->flags = 1; /* active */
5916
5917 return 0;
5918}
5919
5920/*------------------------------------------------------------------*/
5921/*
5922 * Wireless Handler : set AP address
5923 */
5924static int airo_set_wap(struct net_device *dev,
5925 struct iw_request_info *info,
5926 struct sockaddr *awrq,
5927 char *extra)
5928{
5929 struct airo_info *local = dev->priv;
5930 Cmd cmd;
5931 Resp rsp;
5932 APListRid APList_rid;
Dan Williams4be757d2006-01-30 11:58:00 -05005933 static const u8 any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
5934 static const u8 off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935
5936 if (awrq->sa_family != ARPHRD_ETHER)
5937 return -EINVAL;
Dan Williams4be757d2006-01-30 11:58:00 -05005938 else if (!memcmp(any, awrq->sa_data, ETH_ALEN) ||
5939 !memcmp(off, awrq->sa_data, ETH_ALEN)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005940 memset(&cmd, 0, sizeof(cmd));
5941 cmd.cmd=CMD_LOSE_SYNC;
5942 if (down_interruptible(&local->sem))
5943 return -ERESTARTSYS;
5944 issuecommand(local, &cmd, &rsp);
5945 up(&local->sem);
5946 } else {
5947 memset(&APList_rid, 0, sizeof(APList_rid));
5948 APList_rid.len = sizeof(APList_rid);
5949 memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN);
5950 disable_MAC(local, 1);
5951 writeAPListRid(local, &APList_rid, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005952 enable_MAC(local, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 }
5954 return 0;
5955}
5956
5957/*------------------------------------------------------------------*/
5958/*
5959 * Wireless Handler : get AP address
5960 */
5961static int airo_get_wap(struct net_device *dev,
5962 struct iw_request_info *info,
5963 struct sockaddr *awrq,
5964 char *extra)
5965{
5966 struct airo_info *local = dev->priv;
5967 StatusRid status_rid; /* Card status info */
5968
5969 readStatusRid(local, &status_rid, 1);
5970
5971 /* Tentative. This seems to work, wow, I'm lucky !!! */
5972 memcpy(awrq->sa_data, status_rid.bssid[0], ETH_ALEN);
5973 awrq->sa_family = ARPHRD_ETHER;
5974
5975 return 0;
5976}
5977
5978/*------------------------------------------------------------------*/
5979/*
5980 * Wireless Handler : set Nickname
5981 */
5982static int airo_set_nick(struct net_device *dev,
5983 struct iw_request_info *info,
5984 struct iw_point *dwrq,
5985 char *extra)
5986{
5987 struct airo_info *local = dev->priv;
5988
5989 /* Check the size of the string */
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07005990 if(dwrq->length > 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991 return -E2BIG;
5992 }
5993 readConfigRid(local, 1);
5994 memset(local->config.nodeName, 0, sizeof(local->config.nodeName));
5995 memcpy(local->config.nodeName, extra, dwrq->length);
5996 set_bit (FLAG_COMMIT, &local->flags);
5997
5998 return -EINPROGRESS; /* Call commit handler */
5999}
6000
6001/*------------------------------------------------------------------*/
6002/*
6003 * Wireless Handler : get Nickname
6004 */
6005static int airo_get_nick(struct net_device *dev,
6006 struct iw_request_info *info,
6007 struct iw_point *dwrq,
6008 char *extra)
6009{
6010 struct airo_info *local = dev->priv;
6011
6012 readConfigRid(local, 1);
6013 strncpy(extra, local->config.nodeName, 16);
6014 extra[16] = '\0';
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006015 dwrq->length = strlen(extra);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016
6017 return 0;
6018}
6019
6020/*------------------------------------------------------------------*/
6021/*
6022 * Wireless Handler : set Bit-Rate
6023 */
6024static int airo_set_rate(struct net_device *dev,
6025 struct iw_request_info *info,
6026 struct iw_param *vwrq,
6027 char *extra)
6028{
6029 struct airo_info *local = dev->priv;
6030 CapabilityRid cap_rid; /* Card capability info */
6031 u8 brate = 0;
6032 int i;
6033
6034 /* First : get a valid bit rate value */
6035 readCapabilityRid(local, &cap_rid, 1);
6036
6037 /* Which type of value ? */
6038 if((vwrq->value < 8) && (vwrq->value >= 0)) {
6039 /* Setting by rate index */
6040 /* Find value in the magic rate table */
6041 brate = cap_rid.supportedRates[vwrq->value];
6042 } else {
6043 /* Setting by frequency value */
6044 u8 normvalue = (u8) (vwrq->value/500000);
6045
6046 /* Check if rate is valid */
6047 for(i = 0 ; i < 8 ; i++) {
6048 if(normvalue == cap_rid.supportedRates[i]) {
6049 brate = normvalue;
6050 break;
6051 }
6052 }
6053 }
6054 /* -1 designed the max rate (mostly auto mode) */
6055 if(vwrq->value == -1) {
6056 /* Get the highest available rate */
6057 for(i = 0 ; i < 8 ; i++) {
6058 if(cap_rid.supportedRates[i] == 0)
6059 break;
6060 }
6061 if(i != 0)
6062 brate = cap_rid.supportedRates[i - 1];
6063 }
6064 /* Check that it is valid */
6065 if(brate == 0) {
6066 return -EINVAL;
6067 }
6068
6069 readConfigRid(local, 1);
6070 /* Now, check if we want a fixed or auto value */
6071 if(vwrq->fixed == 0) {
6072 /* Fill all the rates up to this max rate */
6073 memset(local->config.rates, 0, 8);
6074 for(i = 0 ; i < 8 ; i++) {
6075 local->config.rates[i] = cap_rid.supportedRates[i];
6076 if(local->config.rates[i] == brate)
6077 break;
6078 }
6079 } else {
6080 /* Fixed mode */
6081 /* One rate, fixed */
6082 memset(local->config.rates, 0, 8);
6083 local->config.rates[0] = brate;
6084 }
6085 set_bit (FLAG_COMMIT, &local->flags);
6086
6087 return -EINPROGRESS; /* Call commit handler */
6088}
6089
6090/*------------------------------------------------------------------*/
6091/*
6092 * Wireless Handler : get Bit-Rate
6093 */
6094static int airo_get_rate(struct net_device *dev,
6095 struct iw_request_info *info,
6096 struct iw_param *vwrq,
6097 char *extra)
6098{
6099 struct airo_info *local = dev->priv;
6100 StatusRid status_rid; /* Card status info */
6101
6102 readStatusRid(local, &status_rid, 1);
6103
6104 vwrq->value = status_rid.currentXmitRate * 500000;
6105 /* If more than one rate, set auto */
6106 readConfigRid(local, 1);
6107 vwrq->fixed = (local->config.rates[1] == 0);
6108
6109 return 0;
6110}
6111
6112/*------------------------------------------------------------------*/
6113/*
6114 * Wireless Handler : set RTS threshold
6115 */
6116static int airo_set_rts(struct net_device *dev,
6117 struct iw_request_info *info,
6118 struct iw_param *vwrq,
6119 char *extra)
6120{
6121 struct airo_info *local = dev->priv;
6122 int rthr = vwrq->value;
6123
6124 if(vwrq->disabled)
Dan Williams15db2762006-03-16 13:46:27 -05006125 rthr = AIRO_DEF_MTU;
6126 if((rthr < 0) || (rthr > AIRO_DEF_MTU)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127 return -EINVAL;
6128 }
6129 readConfigRid(local, 1);
6130 local->config.rtsThres = rthr;
6131 set_bit (FLAG_COMMIT, &local->flags);
6132
6133 return -EINPROGRESS; /* Call commit handler */
6134}
6135
6136/*------------------------------------------------------------------*/
6137/*
6138 * Wireless Handler : get RTS threshold
6139 */
6140static int airo_get_rts(struct net_device *dev,
6141 struct iw_request_info *info,
6142 struct iw_param *vwrq,
6143 char *extra)
6144{
6145 struct airo_info *local = dev->priv;
6146
6147 readConfigRid(local, 1);
6148 vwrq->value = local->config.rtsThres;
Dan Williams15db2762006-03-16 13:46:27 -05006149 vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006150 vwrq->fixed = 1;
6151
6152 return 0;
6153}
6154
6155/*------------------------------------------------------------------*/
6156/*
6157 * Wireless Handler : set Fragmentation threshold
6158 */
6159static int airo_set_frag(struct net_device *dev,
6160 struct iw_request_info *info,
6161 struct iw_param *vwrq,
6162 char *extra)
6163{
6164 struct airo_info *local = dev->priv;
6165 int fthr = vwrq->value;
6166
6167 if(vwrq->disabled)
Dan Williams15db2762006-03-16 13:46:27 -05006168 fthr = AIRO_DEF_MTU;
6169 if((fthr < 256) || (fthr > AIRO_DEF_MTU)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006170 return -EINVAL;
6171 }
6172 fthr &= ~0x1; /* Get an even value - is it really needed ??? */
6173 readConfigRid(local, 1);
6174 local->config.fragThresh = (u16)fthr;
6175 set_bit (FLAG_COMMIT, &local->flags);
6176
6177 return -EINPROGRESS; /* Call commit handler */
6178}
6179
6180/*------------------------------------------------------------------*/
6181/*
6182 * Wireless Handler : get Fragmentation threshold
6183 */
6184static int airo_get_frag(struct net_device *dev,
6185 struct iw_request_info *info,
6186 struct iw_param *vwrq,
6187 char *extra)
6188{
6189 struct airo_info *local = dev->priv;
6190
6191 readConfigRid(local, 1);
6192 vwrq->value = local->config.fragThresh;
Dan Williams15db2762006-03-16 13:46:27 -05006193 vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006194 vwrq->fixed = 1;
6195
6196 return 0;
6197}
6198
6199/*------------------------------------------------------------------*/
6200/*
6201 * Wireless Handler : set Mode of Operation
6202 */
6203static int airo_set_mode(struct net_device *dev,
6204 struct iw_request_info *info,
6205 __u32 *uwrq,
6206 char *extra)
6207{
6208 struct airo_info *local = dev->priv;
6209 int reset = 0;
6210
6211 readConfigRid(local, 1);
6212 if ((local->config.rmode & 0xff) >= RXMODE_RFMON)
6213 reset = 1;
6214
6215 switch(*uwrq) {
6216 case IW_MODE_ADHOC:
6217 local->config.opmode &= 0xFF00;
6218 local->config.opmode |= MODE_STA_IBSS;
6219 local->config.rmode &= 0xfe00;
6220 local->config.scanMode = SCANMODE_ACTIVE;
6221 clear_bit (FLAG_802_11, &local->flags);
6222 break;
6223 case IW_MODE_INFRA:
6224 local->config.opmode &= 0xFF00;
6225 local->config.opmode |= MODE_STA_ESS;
6226 local->config.rmode &= 0xfe00;
6227 local->config.scanMode = SCANMODE_ACTIVE;
6228 clear_bit (FLAG_802_11, &local->flags);
6229 break;
6230 case IW_MODE_MASTER:
6231 local->config.opmode &= 0xFF00;
6232 local->config.opmode |= MODE_AP;
6233 local->config.rmode &= 0xfe00;
6234 local->config.scanMode = SCANMODE_ACTIVE;
6235 clear_bit (FLAG_802_11, &local->flags);
6236 break;
6237 case IW_MODE_REPEAT:
6238 local->config.opmode &= 0xFF00;
6239 local->config.opmode |= MODE_AP_RPTR;
6240 local->config.rmode &= 0xfe00;
6241 local->config.scanMode = SCANMODE_ACTIVE;
6242 clear_bit (FLAG_802_11, &local->flags);
6243 break;
6244 case IW_MODE_MONITOR:
6245 local->config.opmode &= 0xFF00;
6246 local->config.opmode |= MODE_STA_ESS;
6247 local->config.rmode &= 0xfe00;
6248 local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
6249 local->config.scanMode = SCANMODE_PASSIVE;
6250 set_bit (FLAG_802_11, &local->flags);
6251 break;
6252 default:
6253 return -EINVAL;
6254 }
6255 if (reset)
6256 set_bit (FLAG_RESET, &local->flags);
6257 set_bit (FLAG_COMMIT, &local->flags);
6258
6259 return -EINPROGRESS; /* Call commit handler */
6260}
6261
6262/*------------------------------------------------------------------*/
6263/*
6264 * Wireless Handler : get Mode of Operation
6265 */
6266static int airo_get_mode(struct net_device *dev,
6267 struct iw_request_info *info,
6268 __u32 *uwrq,
6269 char *extra)
6270{
6271 struct airo_info *local = dev->priv;
6272
6273 readConfigRid(local, 1);
6274 /* If not managed, assume it's ad-hoc */
6275 switch (local->config.opmode & 0xFF) {
6276 case MODE_STA_ESS:
6277 *uwrq = IW_MODE_INFRA;
6278 break;
6279 case MODE_AP:
6280 *uwrq = IW_MODE_MASTER;
6281 break;
6282 case MODE_AP_RPTR:
6283 *uwrq = IW_MODE_REPEAT;
6284 break;
6285 default:
6286 *uwrq = IW_MODE_ADHOC;
6287 }
6288
6289 return 0;
6290}
6291
6292/*------------------------------------------------------------------*/
6293/*
6294 * Wireless Handler : set Encryption Key
6295 */
6296static int airo_set_encode(struct net_device *dev,
6297 struct iw_request_info *info,
6298 struct iw_point *dwrq,
6299 char *extra)
6300{
6301 struct airo_info *local = dev->priv;
6302 CapabilityRid cap_rid; /* Card capability info */
Dan Streetmanf89b2322005-11-11 11:41:42 -05006303 int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 );
6304 u16 currentAuthType = local->config.authType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305
6306 /* Is WEP supported ? */
6307 readCapabilityRid(local, &cap_rid, 1);
6308 /* Older firmware doesn't support this...
6309 if(!(cap_rid.softCap & 2)) {
6310 return -EOPNOTSUPP;
6311 } */
6312 readConfigRid(local, 1);
6313
6314 /* Basic checking: do we have a key to set ?
6315 * Note : with the new API, it's impossible to get a NULL pointer.
6316 * Therefore, we need to check a key size == 0 instead.
6317 * New version of iwconfig properly set the IW_ENCODE_NOKEY flag
6318 * when no key is present (only change flags), but older versions
6319 * don't do it. - Jean II */
6320 if (dwrq->length > 0) {
6321 wep_key_t key;
6322 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
6323 int current_index = get_wep_key(local, 0xffff);
6324 /* Check the size of the key */
6325 if (dwrq->length > MAX_KEY_SIZE) {
6326 return -EINVAL;
6327 }
6328 /* Check the index (none -> use current) */
6329 if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4:1)))
6330 index = current_index;
6331 /* Set the length */
6332 if (dwrq->length > MIN_KEY_SIZE)
6333 key.len = MAX_KEY_SIZE;
6334 else
6335 if (dwrq->length > 0)
6336 key.len = MIN_KEY_SIZE;
6337 else
6338 /* Disable the key */
6339 key.len = 0;
6340 /* Check if the key is not marked as invalid */
6341 if(!(dwrq->flags & IW_ENCODE_NOKEY)) {
6342 /* Cleanup */
6343 memset(key.key, 0, MAX_KEY_SIZE);
6344 /* Copy the key in the driver */
6345 memcpy(key.key, extra, dwrq->length);
6346 /* Send the key to the card */
Dan Streetmanf89b2322005-11-11 11:41:42 -05006347 set_wep_key(local, index, key.key, key.len, perm, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348 }
6349 /* WE specify that if a valid key is set, encryption
6350 * should be enabled (user may turn it off later)
6351 * This is also how "iwconfig ethX key on" works */
6352 if((index == current_index) && (key.len > 0) &&
6353 (local->config.authType == AUTH_OPEN)) {
6354 local->config.authType = AUTH_ENCRYPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355 }
6356 } else {
6357 /* Do we want to just set the transmit key index ? */
6358 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
6359 if ((index >= 0) && (index < ((cap_rid.softCap & 0x80)?4:1))) {
Dan Streetmanf89b2322005-11-11 11:41:42 -05006360 set_wep_key(local, index, NULL, 0, perm, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006361 } else
6362 /* Don't complain if only change the mode */
Jeff Garzik93a3b602007-11-23 21:50:20 -05006363 if (!(dwrq->flags & IW_ENCODE_MODE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006365 }
6366 /* Read the flags */
6367 if(dwrq->flags & IW_ENCODE_DISABLED)
6368 local->config.authType = AUTH_OPEN; // disable encryption
6369 if(dwrq->flags & IW_ENCODE_RESTRICTED)
6370 local->config.authType = AUTH_SHAREDKEY; // Only Both
6371 if(dwrq->flags & IW_ENCODE_OPEN)
6372 local->config.authType = AUTH_ENCRYPT; // Only Wep
6373 /* Commit the changes to flags if needed */
Dan Streetmanf89b2322005-11-11 11:41:42 -05006374 if (local->config.authType != currentAuthType)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006375 set_bit (FLAG_COMMIT, &local->flags);
6376 return -EINPROGRESS; /* Call commit handler */
6377}
6378
6379/*------------------------------------------------------------------*/
6380/*
6381 * Wireless Handler : get Encryption Key
6382 */
6383static int airo_get_encode(struct net_device *dev,
6384 struct iw_request_info *info,
6385 struct iw_point *dwrq,
6386 char *extra)
6387{
6388 struct airo_info *local = dev->priv;
6389 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
6390 CapabilityRid cap_rid; /* Card capability info */
6391
6392 /* Is it supported ? */
6393 readCapabilityRid(local, &cap_rid, 1);
6394 if(!(cap_rid.softCap & 2)) {
6395 return -EOPNOTSUPP;
6396 }
6397 readConfigRid(local, 1);
6398 /* Check encryption mode */
6399 switch(local->config.authType) {
6400 case AUTH_ENCRYPT:
6401 dwrq->flags = IW_ENCODE_OPEN;
6402 break;
6403 case AUTH_SHAREDKEY:
6404 dwrq->flags = IW_ENCODE_RESTRICTED;
6405 break;
6406 default:
6407 case AUTH_OPEN:
6408 dwrq->flags = IW_ENCODE_DISABLED;
6409 break;
6410 }
6411 /* We can't return the key, so set the proper flag and return zero */
6412 dwrq->flags |= IW_ENCODE_NOKEY;
6413 memset(extra, 0, 16);
6414
6415 /* Which key do we want ? -1 -> tx index */
6416 if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4 : 1)))
6417 index = get_wep_key(local, 0xffff);
6418 dwrq->flags |= index + 1;
6419 /* Copy the key to the user buffer */
6420 dwrq->length = get_wep_key(local, index);
6421 if (dwrq->length > 16) {
6422 dwrq->length=0;
6423 }
6424 return 0;
6425}
6426
6427/*------------------------------------------------------------------*/
6428/*
Dan Williams4be757d2006-01-30 11:58:00 -05006429 * Wireless Handler : set extended Encryption parameters
6430 */
6431static int airo_set_encodeext(struct net_device *dev,
6432 struct iw_request_info *info,
6433 union iwreq_data *wrqu,
6434 char *extra)
6435{
6436 struct airo_info *local = dev->priv;
6437 struct iw_point *encoding = &wrqu->encoding;
6438 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
6439 CapabilityRid cap_rid; /* Card capability info */
6440 int perm = ( encoding->flags & IW_ENCODE_TEMP ? 0 : 1 );
6441 u16 currentAuthType = local->config.authType;
Dan Williams22d88462006-02-05 18:00:30 -05006442 int idx, key_len, alg = ext->alg, set_key = 1;
Dan Williams4be757d2006-01-30 11:58:00 -05006443 wep_key_t key;
6444
6445 /* Is WEP supported ? */
6446 readCapabilityRid(local, &cap_rid, 1);
6447 /* Older firmware doesn't support this...
6448 if(!(cap_rid.softCap & 2)) {
6449 return -EOPNOTSUPP;
6450 } */
6451 readConfigRid(local, 1);
6452
6453 /* Determine and validate the key index */
6454 idx = encoding->flags & IW_ENCODE_INDEX;
6455 if (idx) {
6456 if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1))
6457 return -EINVAL;
6458 idx--;
6459 } else
6460 idx = get_wep_key(local, 0xffff);
6461
6462 if (encoding->flags & IW_ENCODE_DISABLED)
6463 alg = IW_ENCODE_ALG_NONE;
6464
Dan Williams4be757d2006-01-30 11:58:00 -05006465 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
Dan Williams22d88462006-02-05 18:00:30 -05006466 /* Only set transmit key index here, actual
6467 * key is set below if needed.
6468 */
Dan Williams4be757d2006-01-30 11:58:00 -05006469 set_wep_key(local, idx, NULL, 0, perm, 1);
Dan Williams22d88462006-02-05 18:00:30 -05006470 set_key = ext->key_len > 0 ? 1 : 0;
6471 }
6472
6473 if (set_key) {
Dan Williams4be757d2006-01-30 11:58:00 -05006474 /* Set the requested key first */
6475 memset(key.key, 0, MAX_KEY_SIZE);
6476 switch (alg) {
6477 case IW_ENCODE_ALG_NONE:
6478 key.len = 0;
6479 break;
6480 case IW_ENCODE_ALG_WEP:
6481 if (ext->key_len > MIN_KEY_SIZE) {
6482 key.len = MAX_KEY_SIZE;
6483 } else if (ext->key_len > 0) {
6484 key.len = MIN_KEY_SIZE;
6485 } else {
6486 return -EINVAL;
6487 }
6488 key_len = min (ext->key_len, key.len);
6489 memcpy(key.key, ext->key, key_len);
6490 break;
6491 default:
6492 return -EINVAL;
6493 }
6494 /* Send the key to the card */
6495 set_wep_key(local, idx, key.key, key.len, perm, 1);
6496 }
6497
6498 /* Read the flags */
6499 if(encoding->flags & IW_ENCODE_DISABLED)
6500 local->config.authType = AUTH_OPEN; // disable encryption
6501 if(encoding->flags & IW_ENCODE_RESTRICTED)
6502 local->config.authType = AUTH_SHAREDKEY; // Only Both
6503 if(encoding->flags & IW_ENCODE_OPEN)
6504 local->config.authType = AUTH_ENCRYPT; // Only Wep
6505 /* Commit the changes to flags if needed */
6506 if (local->config.authType != currentAuthType)
6507 set_bit (FLAG_COMMIT, &local->flags);
6508
6509 return -EINPROGRESS;
6510}
6511
6512
6513/*------------------------------------------------------------------*/
6514/*
6515 * Wireless Handler : get extended Encryption parameters
6516 */
6517static int airo_get_encodeext(struct net_device *dev,
6518 struct iw_request_info *info,
6519 union iwreq_data *wrqu,
6520 char *extra)
6521{
6522 struct airo_info *local = dev->priv;
6523 struct iw_point *encoding = &wrqu->encoding;
6524 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
6525 CapabilityRid cap_rid; /* Card capability info */
6526 int idx, max_key_len;
6527
6528 /* Is it supported ? */
6529 readCapabilityRid(local, &cap_rid, 1);
6530 if(!(cap_rid.softCap & 2)) {
6531 return -EOPNOTSUPP;
6532 }
6533 readConfigRid(local, 1);
6534
6535 max_key_len = encoding->length - sizeof(*ext);
6536 if (max_key_len < 0)
6537 return -EINVAL;
6538
6539 idx = encoding->flags & IW_ENCODE_INDEX;
6540 if (idx) {
6541 if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1))
6542 return -EINVAL;
6543 idx--;
6544 } else
6545 idx = get_wep_key(local, 0xffff);
6546
6547 encoding->flags = idx + 1;
6548 memset(ext, 0, sizeof(*ext));
6549
6550 /* Check encryption mode */
6551 switch(local->config.authType) {
6552 case AUTH_ENCRYPT:
6553 encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
6554 break;
6555 case AUTH_SHAREDKEY:
6556 encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
6557 break;
6558 default:
6559 case AUTH_OPEN:
6560 encoding->flags = IW_ENCODE_ALG_NONE | IW_ENCODE_DISABLED;
6561 break;
6562 }
6563 /* We can't return the key, so set the proper flag and return zero */
6564 encoding->flags |= IW_ENCODE_NOKEY;
6565 memset(extra, 0, 16);
6566
6567 /* Copy the key to the user buffer */
6568 ext->key_len = get_wep_key(local, idx);
6569 if (ext->key_len > 16) {
6570 ext->key_len=0;
6571 }
6572
6573 return 0;
6574}
6575
6576
6577/*------------------------------------------------------------------*/
6578/*
6579 * Wireless Handler : set extended authentication parameters
6580 */
6581static int airo_set_auth(struct net_device *dev,
6582 struct iw_request_info *info,
6583 union iwreq_data *wrqu, char *extra)
6584{
6585 struct airo_info *local = dev->priv;
6586 struct iw_param *param = &wrqu->param;
6587 u16 currentAuthType = local->config.authType;
6588
6589 switch (param->flags & IW_AUTH_INDEX) {
6590 case IW_AUTH_WPA_VERSION:
6591 case IW_AUTH_CIPHER_PAIRWISE:
6592 case IW_AUTH_CIPHER_GROUP:
6593 case IW_AUTH_KEY_MGMT:
6594 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
6595 case IW_AUTH_PRIVACY_INVOKED:
6596 /*
6597 * airo does not use these parameters
6598 */
6599 break;
6600
6601 case IW_AUTH_DROP_UNENCRYPTED:
6602 if (param->value) {
6603 /* Only change auth type if unencrypted */
6604 if (currentAuthType == AUTH_OPEN)
6605 local->config.authType = AUTH_ENCRYPT;
6606 } else {
6607 local->config.authType = AUTH_OPEN;
6608 }
6609
6610 /* Commit the changes to flags if needed */
6611 if (local->config.authType != currentAuthType)
6612 set_bit (FLAG_COMMIT, &local->flags);
6613 break;
6614
6615 case IW_AUTH_80211_AUTH_ALG: {
6616 /* FIXME: What about AUTH_OPEN? This API seems to
6617 * disallow setting our auth to AUTH_OPEN.
6618 */
6619 if (param->value & IW_AUTH_ALG_SHARED_KEY) {
6620 local->config.authType = AUTH_SHAREDKEY;
6621 } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
6622 local->config.authType = AUTH_ENCRYPT;
6623 } else
6624 return -EINVAL;
6625 break;
6626
6627 /* Commit the changes to flags if needed */
6628 if (local->config.authType != currentAuthType)
6629 set_bit (FLAG_COMMIT, &local->flags);
6630 }
6631
6632 case IW_AUTH_WPA_ENABLED:
6633 /* Silently accept disable of WPA */
6634 if (param->value > 0)
6635 return -EOPNOTSUPP;
6636 break;
6637
6638 default:
6639 return -EOPNOTSUPP;
6640 }
6641 return -EINPROGRESS;
6642}
6643
6644
6645/*------------------------------------------------------------------*/
6646/*
6647 * Wireless Handler : get extended authentication parameters
6648 */
6649static int airo_get_auth(struct net_device *dev,
6650 struct iw_request_info *info,
6651 union iwreq_data *wrqu, char *extra)
6652{
6653 struct airo_info *local = dev->priv;
6654 struct iw_param *param = &wrqu->param;
6655 u16 currentAuthType = local->config.authType;
6656
6657 switch (param->flags & IW_AUTH_INDEX) {
6658 case IW_AUTH_DROP_UNENCRYPTED:
6659 switch (currentAuthType) {
6660 case AUTH_SHAREDKEY:
6661 case AUTH_ENCRYPT:
6662 param->value = 1;
6663 break;
6664 default:
6665 param->value = 0;
6666 break;
6667 }
6668 break;
6669
6670 case IW_AUTH_80211_AUTH_ALG:
6671 switch (currentAuthType) {
6672 case AUTH_SHAREDKEY:
6673 param->value = IW_AUTH_ALG_SHARED_KEY;
6674 break;
6675 case AUTH_ENCRYPT:
6676 default:
6677 param->value = IW_AUTH_ALG_OPEN_SYSTEM;
6678 break;
6679 }
6680 break;
6681
6682 case IW_AUTH_WPA_ENABLED:
6683 param->value = 0;
6684 break;
6685
6686 default:
6687 return -EOPNOTSUPP;
6688 }
6689 return 0;
6690}
6691
6692
6693/*------------------------------------------------------------------*/
6694/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006695 * Wireless Handler : set Tx-Power
6696 */
6697static int airo_set_txpow(struct net_device *dev,
6698 struct iw_request_info *info,
6699 struct iw_param *vwrq,
6700 char *extra)
6701{
6702 struct airo_info *local = dev->priv;
6703 CapabilityRid cap_rid; /* Card capability info */
6704 int i;
6705 int rc = -EINVAL;
6706
6707 readCapabilityRid(local, &cap_rid, 1);
6708
6709 if (vwrq->disabled) {
6710 set_bit (FLAG_RADIO_OFF, &local->flags);
6711 set_bit (FLAG_COMMIT, &local->flags);
6712 return -EINPROGRESS; /* Call commit handler */
6713 }
6714 if (vwrq->flags != IW_TXPOW_MWATT) {
6715 return -EINVAL;
6716 }
6717 clear_bit (FLAG_RADIO_OFF, &local->flags);
6718 for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
6719 if ((vwrq->value==cap_rid.txPowerLevels[i])) {
6720 readConfigRid(local, 1);
6721 local->config.txPower = vwrq->value;
6722 set_bit (FLAG_COMMIT, &local->flags);
6723 rc = -EINPROGRESS; /* Call commit handler */
6724 break;
6725 }
6726 return rc;
6727}
6728
6729/*------------------------------------------------------------------*/
6730/*
6731 * Wireless Handler : get Tx-Power
6732 */
6733static int airo_get_txpow(struct net_device *dev,
6734 struct iw_request_info *info,
6735 struct iw_param *vwrq,
6736 char *extra)
6737{
6738 struct airo_info *local = dev->priv;
6739
6740 readConfigRid(local, 1);
6741 vwrq->value = local->config.txPower;
6742 vwrq->fixed = 1; /* No power control */
6743 vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags);
6744 vwrq->flags = IW_TXPOW_MWATT;
6745
6746 return 0;
6747}
6748
6749/*------------------------------------------------------------------*/
6750/*
6751 * Wireless Handler : set Retry limits
6752 */
6753static int airo_set_retry(struct net_device *dev,
6754 struct iw_request_info *info,
6755 struct iw_param *vwrq,
6756 char *extra)
6757{
6758 struct airo_info *local = dev->priv;
6759 int rc = -EINVAL;
6760
6761 if(vwrq->disabled) {
6762 return -EINVAL;
6763 }
6764 readConfigRid(local, 1);
6765 if(vwrq->flags & IW_RETRY_LIMIT) {
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006766 if(vwrq->flags & IW_RETRY_LONG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006767 local->config.longRetryLimit = vwrq->value;
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006768 else if (vwrq->flags & IW_RETRY_SHORT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006769 local->config.shortRetryLimit = vwrq->value;
6770 else {
6771 /* No modifier : set both */
6772 local->config.longRetryLimit = vwrq->value;
6773 local->config.shortRetryLimit = vwrq->value;
6774 }
6775 set_bit (FLAG_COMMIT, &local->flags);
6776 rc = -EINPROGRESS; /* Call commit handler */
6777 }
6778 if(vwrq->flags & IW_RETRY_LIFETIME) {
6779 local->config.txLifetime = vwrq->value / 1024;
6780 set_bit (FLAG_COMMIT, &local->flags);
6781 rc = -EINPROGRESS; /* Call commit handler */
6782 }
6783 return rc;
6784}
6785
6786/*------------------------------------------------------------------*/
6787/*
6788 * Wireless Handler : get Retry limits
6789 */
6790static int airo_get_retry(struct net_device *dev,
6791 struct iw_request_info *info,
6792 struct iw_param *vwrq,
6793 char *extra)
6794{
6795 struct airo_info *local = dev->priv;
6796
6797 vwrq->disabled = 0; /* Can't be disabled */
6798
6799 readConfigRid(local, 1);
6800 /* Note : by default, display the min retry number */
6801 if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
6802 vwrq->flags = IW_RETRY_LIFETIME;
6803 vwrq->value = (int)local->config.txLifetime * 1024;
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006804 } else if((vwrq->flags & IW_RETRY_LONG)) {
6805 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006806 vwrq->value = (int)local->config.longRetryLimit;
6807 } else {
6808 vwrq->flags = IW_RETRY_LIMIT;
6809 vwrq->value = (int)local->config.shortRetryLimit;
6810 if((int)local->config.shortRetryLimit != (int)local->config.longRetryLimit)
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006811 vwrq->flags |= IW_RETRY_SHORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006812 }
6813
6814 return 0;
6815}
6816
6817/*------------------------------------------------------------------*/
6818/*
6819 * Wireless Handler : get range info
6820 */
6821static int airo_get_range(struct net_device *dev,
6822 struct iw_request_info *info,
6823 struct iw_point *dwrq,
6824 char *extra)
6825{
6826 struct airo_info *local = dev->priv;
6827 struct iw_range *range = (struct iw_range *) extra;
6828 CapabilityRid cap_rid; /* Card capability info */
6829 int i;
6830 int k;
6831
6832 readCapabilityRid(local, &cap_rid, 1);
6833
6834 dwrq->length = sizeof(struct iw_range);
6835 memset(range, 0, sizeof(*range));
6836 range->min_nwid = 0x0000;
6837 range->max_nwid = 0x0000;
6838 range->num_channels = 14;
6839 /* Should be based on cap_rid.country to give only
6840 * what the current card support */
6841 k = 0;
6842 for(i = 0; i < 14; i++) {
6843 range->freq[k].i = i + 1; /* List index */
6844 range->freq[k].m = frequency_list[i] * 100000;
6845 range->freq[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */
6846 }
6847 range->num_frequency = k;
6848
Linus Torvalds1da177e2005-04-16 15:20:36 -07006849 range->sensitivity = 65535;
6850
Dan Williams41480af2005-05-10 09:45:51 -04006851 /* Hum... Should put the right values there */
6852 if (local->rssi)
6853 range->max_qual.qual = 100; /* % */
6854 else
6855 range->max_qual.qual = airo_get_max_quality(&cap_rid);
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006856 range->max_qual.level = 0x100 - 120; /* -120 dBm */
6857 range->max_qual.noise = 0x100 - 120; /* -120 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006858
6859 /* Experimental measurements - boundary 11/5.5 Mb/s */
6860 /* Note : with or without the (local->rssi), results
6861 * are somewhat different. - Jean II */
6862 if (local->rssi) {
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006863 range->avg_qual.qual = 50; /* % */
6864 range->avg_qual.level = 0x100 - 70; /* -70 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006865 } else {
6866 range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006867 range->avg_qual.level = 0x100 - 80; /* -80 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006868 }
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006869 range->avg_qual.noise = 0x100 - 85; /* -85 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006870
Linus Torvalds1da177e2005-04-16 15:20:36 -07006871 for(i = 0 ; i < 8 ; i++) {
6872 range->bitrate[i] = cap_rid.supportedRates[i] * 500000;
6873 if(range->bitrate[i] == 0)
6874 break;
6875 }
6876 range->num_bitrates = i;
6877
6878 /* Set an indication of the max TCP throughput
6879 * in bit/s that we can expect using this interface.
6880 * May be use for QoS stuff... Jean II */
6881 if(i > 2)
6882 range->throughput = 5000 * 1000;
6883 else
6884 range->throughput = 1500 * 1000;
6885
6886 range->min_rts = 0;
Dan Williams15db2762006-03-16 13:46:27 -05006887 range->max_rts = AIRO_DEF_MTU;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006888 range->min_frag = 256;
Dan Williams15db2762006-03-16 13:46:27 -05006889 range->max_frag = AIRO_DEF_MTU;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006890
6891 if(cap_rid.softCap & 2) {
6892 // WEP: RC4 40 bits
6893 range->encoding_size[0] = 5;
6894 // RC4 ~128 bits
6895 if (cap_rid.softCap & 0x100) {
6896 range->encoding_size[1] = 13;
6897 range->num_encoding_sizes = 2;
6898 } else
6899 range->num_encoding_sizes = 1;
6900 range->max_encoding_tokens = (cap_rid.softCap & 0x80) ? 4 : 1;
6901 } else {
6902 range->num_encoding_sizes = 0;
6903 range->max_encoding_tokens = 0;
6904 }
6905 range->min_pmp = 0;
6906 range->max_pmp = 5000000; /* 5 secs */
6907 range->min_pmt = 0;
6908 range->max_pmt = 65535 * 1024; /* ??? */
6909 range->pmp_flags = IW_POWER_PERIOD;
6910 range->pmt_flags = IW_POWER_TIMEOUT;
6911 range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
6912
6913 /* Transmit Power - values are in mW */
6914 for(i = 0 ; i < 8 ; i++) {
6915 range->txpower[i] = cap_rid.txPowerLevels[i];
6916 if(range->txpower[i] == 0)
6917 break;
6918 }
6919 range->num_txpower = i;
6920 range->txpower_capa = IW_TXPOW_MWATT;
Dan Williams3c304952006-04-15 12:26:18 -04006921 range->we_version_source = 19;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006922 range->we_version_compiled = WIRELESS_EXT;
6923 range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
6924 range->retry_flags = IW_RETRY_LIMIT;
6925 range->r_time_flags = IW_RETRY_LIFETIME;
6926 range->min_retry = 1;
6927 range->max_retry = 65535;
6928 range->min_r_time = 1024;
6929 range->max_r_time = 65535 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006930
6931 /* Event capability (kernel + driver) */
6932 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
6933 IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
6934 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
6935 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
6936 range->event_capa[1] = IW_EVENT_CAPA_K_1;
6937 range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVTXDROP);
6938 return 0;
6939}
6940
6941/*------------------------------------------------------------------*/
6942/*
6943 * Wireless Handler : set Power Management
6944 */
6945static int airo_set_power(struct net_device *dev,
6946 struct iw_request_info *info,
6947 struct iw_param *vwrq,
6948 char *extra)
6949{
6950 struct airo_info *local = dev->priv;
6951
6952 readConfigRid(local, 1);
6953 if (vwrq->disabled) {
6954 if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
6955 return -EINVAL;
6956 }
6957 local->config.powerSaveMode = POWERSAVE_CAM;
6958 local->config.rmode &= 0xFF00;
6959 local->config.rmode |= RXMODE_BC_MC_ADDR;
6960 set_bit (FLAG_COMMIT, &local->flags);
6961 return -EINPROGRESS; /* Call commit handler */
6962 }
6963 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
6964 local->config.fastListenDelay = (vwrq->value + 500) / 1024;
6965 local->config.powerSaveMode = POWERSAVE_PSPCAM;
6966 set_bit (FLAG_COMMIT, &local->flags);
6967 } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
6968 local->config.fastListenInterval = local->config.listenInterval = (vwrq->value + 500) / 1024;
6969 local->config.powerSaveMode = POWERSAVE_PSPCAM;
6970 set_bit (FLAG_COMMIT, &local->flags);
6971 }
6972 switch (vwrq->flags & IW_POWER_MODE) {
6973 case IW_POWER_UNICAST_R:
6974 if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
6975 return -EINVAL;
6976 }
6977 local->config.rmode &= 0xFF00;
6978 local->config.rmode |= RXMODE_ADDR;
6979 set_bit (FLAG_COMMIT, &local->flags);
6980 break;
6981 case IW_POWER_ALL_R:
6982 if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
6983 return -EINVAL;
6984 }
6985 local->config.rmode &= 0xFF00;
6986 local->config.rmode |= RXMODE_BC_MC_ADDR;
6987 set_bit (FLAG_COMMIT, &local->flags);
6988 case IW_POWER_ON:
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006989 /* This is broken, fixme ;-) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006990 break;
6991 default:
6992 return -EINVAL;
6993 }
6994 // Note : we may want to factor local->need_commit here
6995 // Note2 : may also want to factor RXMODE_RFMON test
6996 return -EINPROGRESS; /* Call commit handler */
6997}
6998
6999/*------------------------------------------------------------------*/
7000/*
7001 * Wireless Handler : get Power Management
7002 */
7003static int airo_get_power(struct net_device *dev,
7004 struct iw_request_info *info,
7005 struct iw_param *vwrq,
7006 char *extra)
7007{
7008 struct airo_info *local = dev->priv;
7009 int mode;
7010
7011 readConfigRid(local, 1);
7012 mode = local->config.powerSaveMode;
7013 if ((vwrq->disabled = (mode == POWERSAVE_CAM)))
7014 return 0;
7015 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
7016 vwrq->value = (int)local->config.fastListenDelay * 1024;
7017 vwrq->flags = IW_POWER_TIMEOUT;
7018 } else {
7019 vwrq->value = (int)local->config.fastListenInterval * 1024;
7020 vwrq->flags = IW_POWER_PERIOD;
7021 }
7022 if ((local->config.rmode & 0xFF) == RXMODE_ADDR)
7023 vwrq->flags |= IW_POWER_UNICAST_R;
7024 else
7025 vwrq->flags |= IW_POWER_ALL_R;
7026
7027 return 0;
7028}
7029
7030/*------------------------------------------------------------------*/
7031/*
7032 * Wireless Handler : set Sensitivity
7033 */
7034static int airo_set_sens(struct net_device *dev,
7035 struct iw_request_info *info,
7036 struct iw_param *vwrq,
7037 char *extra)
7038{
7039 struct airo_info *local = dev->priv;
7040
7041 readConfigRid(local, 1);
7042 local->config.rssiThreshold = vwrq->disabled ? RSSI_DEFAULT : vwrq->value;
7043 set_bit (FLAG_COMMIT, &local->flags);
7044
7045 return -EINPROGRESS; /* Call commit handler */
7046}
7047
7048/*------------------------------------------------------------------*/
7049/*
7050 * Wireless Handler : get Sensitivity
7051 */
7052static int airo_get_sens(struct net_device *dev,
7053 struct iw_request_info *info,
7054 struct iw_param *vwrq,
7055 char *extra)
7056{
7057 struct airo_info *local = dev->priv;
7058
7059 readConfigRid(local, 1);
7060 vwrq->value = local->config.rssiThreshold;
7061 vwrq->disabled = (vwrq->value == 0);
7062 vwrq->fixed = 1;
7063
7064 return 0;
7065}
7066
7067/*------------------------------------------------------------------*/
7068/*
7069 * Wireless Handler : get AP List
7070 * Note : this is deprecated in favor of IWSCAN
7071 */
7072static int airo_get_aplist(struct net_device *dev,
7073 struct iw_request_info *info,
7074 struct iw_point *dwrq,
7075 char *extra)
7076{
7077 struct airo_info *local = dev->priv;
7078 struct sockaddr *address = (struct sockaddr *) extra;
7079 struct iw_quality qual[IW_MAX_AP];
7080 BSSListRid BSSList;
7081 int i;
7082 int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
7083
7084 for (i = 0; i < IW_MAX_AP; i++) {
Al Viro17e70492007-12-19 18:56:37 -05007085 u16 dBm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007086 if (readBSSListRid(local, loseSync, &BSSList))
7087 break;
7088 loseSync = 0;
7089 memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN);
7090 address[i].sa_family = ARPHRD_ETHER;
Al Viro17e70492007-12-19 18:56:37 -05007091 dBm = le16_to_cpu(BSSList.dBm);
Dan Williams41480af2005-05-10 09:45:51 -04007092 if (local->rssi) {
Al Viro17e70492007-12-19 18:56:37 -05007093 qual[i].level = 0x100 - dBm;
7094 qual[i].qual = airo_dbm_to_pct(local->rssi, dBm);
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007095 qual[i].updated = IW_QUAL_QUAL_UPDATED
7096 | IW_QUAL_LEVEL_UPDATED
7097 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04007098 } else {
Al Viro17e70492007-12-19 18:56:37 -05007099 qual[i].level = (dBm + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04007100 qual[i].qual = 0;
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007101 qual[i].updated = IW_QUAL_QUAL_INVALID
7102 | IW_QUAL_LEVEL_UPDATED
7103 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04007104 }
7105 qual[i].noise = local->wstats.qual.noise;
Al Viro17e70492007-12-19 18:56:37 -05007106 if (BSSList.index == cpu_to_le16(0xffff))
Linus Torvalds1da177e2005-04-16 15:20:36 -07007107 break;
7108 }
7109 if (!i) {
7110 StatusRid status_rid; /* Card status info */
7111 readStatusRid(local, &status_rid, 1);
7112 for (i = 0;
7113 i < min(IW_MAX_AP, 4) &&
7114 (status_rid.bssid[i][0]
7115 & status_rid.bssid[i][1]
7116 & status_rid.bssid[i][2]
7117 & status_rid.bssid[i][3]
7118 & status_rid.bssid[i][4]
7119 & status_rid.bssid[i][5])!=0xff &&
7120 (status_rid.bssid[i][0]
7121 | status_rid.bssid[i][1]
7122 | status_rid.bssid[i][2]
7123 | status_rid.bssid[i][3]
7124 | status_rid.bssid[i][4]
7125 | status_rid.bssid[i][5]);
7126 i++) {
7127 memcpy(address[i].sa_data,
7128 status_rid.bssid[i], ETH_ALEN);
7129 address[i].sa_family = ARPHRD_ETHER;
7130 }
7131 } else {
7132 dwrq->flags = 1; /* Should be define'd */
7133 memcpy(extra + sizeof(struct sockaddr)*i,
7134 &qual, sizeof(struct iw_quality)*i);
7135 }
7136 dwrq->length = i;
7137
7138 return 0;
7139}
7140
7141/*------------------------------------------------------------------*/
7142/*
7143 * Wireless Handler : Initiate Scan
7144 */
7145static int airo_set_scan(struct net_device *dev,
7146 struct iw_request_info *info,
7147 struct iw_param *vwrq,
7148 char *extra)
7149{
7150 struct airo_info *ai = dev->priv;
7151 Cmd cmd;
7152 Resp rsp;
Dan Williams9e75af32006-03-16 13:46:29 -05007153 int wake = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007154
7155 /* Note : you may have realised that, as this is a SET operation,
7156 * this is privileged and therefore a normal user can't
7157 * perform scanning.
7158 * This is not an error, while the device perform scanning,
7159 * traffic doesn't flow, so it's a perfect DoS...
7160 * Jean II */
7161 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
7162
Dan Williams9e75af32006-03-16 13:46:29 -05007163 if (down_interruptible(&ai->sem))
7164 return -ERESTARTSYS;
7165
7166 /* If there's already a scan in progress, don't
7167 * trigger another one. */
7168 if (ai->scan_timeout > 0)
7169 goto out;
7170
Linus Torvalds1da177e2005-04-16 15:20:36 -07007171 /* Initiate a scan command */
Dan Williams6fcdf562006-03-31 15:08:46 -05007172 ai->scan_timeout = RUN_AT(3*HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007173 memset(&cmd, 0, sizeof(cmd));
7174 cmd.cmd=CMD_LISTBSS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007175 issuecommand(ai, &cmd, &rsp);
Dan Williams9e75af32006-03-16 13:46:29 -05007176 wake = 1;
7177
7178out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07007179 up(&ai->sem);
Dan Williams9e75af32006-03-16 13:46:29 -05007180 if (wake)
7181 wake_up_interruptible(&ai->thr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007182 return 0;
7183}
7184
7185/*------------------------------------------------------------------*/
7186/*
7187 * Translate scan data returned from the card to a card independent
7188 * format that the Wireless Tools will understand - Jean II
7189 */
7190static inline char *airo_translate_scan(struct net_device *dev,
7191 char *current_ev,
7192 char *end_buf,
Dan Williams41480af2005-05-10 09:45:51 -04007193 BSSListRid *bss)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007194{
7195 struct airo_info *ai = dev->priv;
7196 struct iw_event iwe; /* Temporary buffer */
Al Viro17e70492007-12-19 18:56:37 -05007197 __le16 capabilities;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007198 char * current_val; /* For rates */
7199 int i;
Dan Williams3c304952006-04-15 12:26:18 -04007200 char * buf;
Al Viro851b3e52007-12-19 19:20:12 -05007201 u16 dBm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007202
7203 /* First entry *MUST* be the AP MAC address */
7204 iwe.cmd = SIOCGIWAP;
7205 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
Dan Williams41480af2005-05-10 09:45:51 -04007206 memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007207 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
7208
7209 /* Other entries will be displayed in the order we give them */
7210
7211 /* Add the ESSID */
Dan Williams41480af2005-05-10 09:45:51 -04007212 iwe.u.data.length = bss->ssidLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007213 if(iwe.u.data.length > 32)
7214 iwe.u.data.length = 32;
7215 iwe.cmd = SIOCGIWESSID;
7216 iwe.u.data.flags = 1;
Dan Williams41480af2005-05-10 09:45:51 -04007217 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007218
7219 /* Add mode */
7220 iwe.cmd = SIOCGIWMODE;
Al Viro17e70492007-12-19 18:56:37 -05007221 capabilities = bss->cap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007222 if(capabilities & (CAP_ESS | CAP_IBSS)) {
7223 if(capabilities & CAP_ESS)
7224 iwe.u.mode = IW_MODE_MASTER;
7225 else
7226 iwe.u.mode = IW_MODE_ADHOC;
7227 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
7228 }
7229
7230 /* Add frequency */
7231 iwe.cmd = SIOCGIWFREQ;
Dan Williams41480af2005-05-10 09:45:51 -04007232 iwe.u.freq.m = le16_to_cpu(bss->dsChannel);
matthieu castet11414552005-09-12 23:31:39 +02007233 /* iwe.u.freq.m containt the channel (starting 1), our
7234 * frequency_list array start at index 0...
7235 */
7236 iwe.u.freq.m = frequency_list[iwe.u.freq.m - 1] * 100000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007237 iwe.u.freq.e = 1;
7238 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
7239
Al Viro851b3e52007-12-19 19:20:12 -05007240 dBm = le16_to_cpu(bss->dBm);
7241
Linus Torvalds1da177e2005-04-16 15:20:36 -07007242 /* Add quality statistics */
7243 iwe.cmd = IWEVQUAL;
Dan Williams41480af2005-05-10 09:45:51 -04007244 if (ai->rssi) {
Al Viro851b3e52007-12-19 19:20:12 -05007245 iwe.u.qual.level = 0x100 - dBm;
7246 iwe.u.qual.qual = airo_dbm_to_pct(ai->rssi, dBm);
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007247 iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
7248 | IW_QUAL_LEVEL_UPDATED
7249 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04007250 } else {
Al Viro851b3e52007-12-19 19:20:12 -05007251 iwe.u.qual.level = (dBm + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04007252 iwe.u.qual.qual = 0;
Jeff Garzikbbeec902005-09-07 00:27:54 -04007253 iwe.u.qual.updated = IW_QUAL_QUAL_INVALID
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007254 | IW_QUAL_LEVEL_UPDATED
7255 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04007256 }
7257 iwe.u.qual.noise = ai->wstats.qual.noise;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007258 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
7259
7260 /* Add encryption capability */
7261 iwe.cmd = SIOCGIWENCODE;
7262 if(capabilities & CAP_PRIVACY)
7263 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
7264 else
7265 iwe.u.data.flags = IW_ENCODE_DISABLED;
7266 iwe.u.data.length = 0;
Dan Williams41480af2005-05-10 09:45:51 -04007267 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007268
7269 /* Rate : stuffing multiple values in a single event require a bit
7270 * more of magic - Jean II */
7271 current_val = current_ev + IW_EV_LCP_LEN;
7272
7273 iwe.cmd = SIOCGIWRATE;
7274 /* Those two flags are ignored... */
7275 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
7276 /* Max 8 values */
7277 for(i = 0 ; i < 8 ; i++) {
7278 /* NULL terminated */
Dan Williams41480af2005-05-10 09:45:51 -04007279 if(bss->rates[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007280 break;
7281 /* Bit rate given in 500 kb/s units (+ 0x80) */
Dan Williams41480af2005-05-10 09:45:51 -04007282 iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007283 /* Add new value to event */
7284 current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
7285 }
7286 /* Check if we added any event */
7287 if((current_val - current_ev) > IW_EV_LCP_LEN)
7288 current_ev = current_val;
7289
Dan Williams3c304952006-04-15 12:26:18 -04007290 /* Beacon interval */
7291 buf = kmalloc(30, GFP_KERNEL);
7292 if (buf) {
7293 iwe.cmd = IWEVCUSTOM;
7294 sprintf(buf, "bcn_int=%d", bss->beaconInterval);
7295 iwe.u.data.length = strlen(buf);
7296 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
7297 kfree(buf);
7298 }
7299
7300 /* Put WPA/RSN Information Elements into the event stream */
7301 if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) {
7302 unsigned int num_null_ies = 0;
7303 u16 length = sizeof (bss->extra.iep);
7304 struct ieee80211_info_element *info_element =
7305 (struct ieee80211_info_element *) &bss->extra.iep;
7306
7307 while ((length >= sizeof(*info_element)) && (num_null_ies < 2)) {
7308 if (sizeof(*info_element) + info_element->len > length) {
7309 /* Invalid element, don't continue parsing IE */
7310 break;
7311 }
7312
7313 switch (info_element->id) {
7314 case MFIE_TYPE_SSID:
7315 /* Two zero-length SSID elements
7316 * mean we're done parsing elements */
7317 if (!info_element->len)
7318 num_null_ies++;
7319 break;
7320
7321 case MFIE_TYPE_GENERIC:
7322 if (info_element->len >= 4 &&
7323 info_element->data[0] == 0x00 &&
7324 info_element->data[1] == 0x50 &&
7325 info_element->data[2] == 0xf2 &&
7326 info_element->data[3] == 0x01) {
7327 iwe.cmd = IWEVGENIE;
7328 iwe.u.data.length = min(info_element->len + 2,
7329 MAX_WPA_IE_LEN);
7330 current_ev = iwe_stream_add_point(current_ev, end_buf,
7331 &iwe, (char *) info_element);
7332 }
7333 break;
7334
7335 case MFIE_TYPE_RSN:
7336 iwe.cmd = IWEVGENIE;
7337 iwe.u.data.length = min(info_element->len + 2,
7338 MAX_WPA_IE_LEN);
7339 current_ev = iwe_stream_add_point(current_ev, end_buf,
7340 &iwe, (char *) info_element);
7341 break;
7342
7343 default:
7344 break;
7345 }
7346
7347 length -= sizeof(*info_element) + info_element->len;
7348 info_element =
7349 (struct ieee80211_info_element *)&info_element->
7350 data[info_element->len];
7351 }
7352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007353 return current_ev;
7354}
7355
7356/*------------------------------------------------------------------*/
7357/*
7358 * Wireless Handler : Read Scan Results
7359 */
7360static int airo_get_scan(struct net_device *dev,
7361 struct iw_request_info *info,
7362 struct iw_point *dwrq,
7363 char *extra)
7364{
7365 struct airo_info *ai = dev->priv;
Dan Williams9e75af32006-03-16 13:46:29 -05007366 BSSListElement *net;
7367 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007368 char *current_ev = extra;
7369
Dan Williams9e75af32006-03-16 13:46:29 -05007370 /* If a scan is in-progress, return -EAGAIN */
7371 if (ai->scan_timeout > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007372 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007373
Dan Williams9e75af32006-03-16 13:46:29 -05007374 if (down_interruptible(&ai->sem))
7375 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007376
Dan Williams9e75af32006-03-16 13:46:29 -05007377 list_for_each_entry (net, &ai->network_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007378 /* Translate to WE format this entry */
7379 current_ev = airo_translate_scan(dev, current_ev,
7380 extra + dwrq->length,
Dan Williams9e75af32006-03-16 13:46:29 -05007381 &net->bss);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007382
7383 /* Check if there is space for one more entry */
7384 if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
7385 /* Ask user space to try again with a bigger buffer */
Dan Williams9e75af32006-03-16 13:46:29 -05007386 err = -E2BIG;
7387 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007389 }
Dan Williams9e75af32006-03-16 13:46:29 -05007390
Linus Torvalds1da177e2005-04-16 15:20:36 -07007391 /* Length of data */
7392 dwrq->length = (current_ev - extra);
7393 dwrq->flags = 0; /* todo */
7394
Dan Williams9e75af32006-03-16 13:46:29 -05007395out:
7396 up(&ai->sem);
7397 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007398}
7399
7400/*------------------------------------------------------------------*/
7401/*
7402 * Commit handler : called after a bunch of SET operations
7403 */
7404static int airo_config_commit(struct net_device *dev,
7405 struct iw_request_info *info, /* NULL */
7406 void *zwrq, /* NULL */
7407 char *extra) /* NULL */
7408{
7409 struct airo_info *local = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007410
7411 if (!test_bit (FLAG_COMMIT, &local->flags))
7412 return 0;
7413
7414 /* Some of the "SET" function may have modified some of the
7415 * parameters. It's now time to commit them in the card */
7416 disable_MAC(local, 1);
7417 if (test_bit (FLAG_RESET, &local->flags)) {
7418 APListRid APList_rid;
7419 SsidRid SSID_rid;
7420
7421 readAPListRid(local, &APList_rid);
7422 readSsidRid(local, &SSID_rid);
7423 if (test_bit(FLAG_MPI,&local->flags))
7424 setup_card(local, dev->dev_addr, 1 );
7425 else
7426 reset_airo_card(dev);
7427 disable_MAC(local, 1);
7428 writeSsidRid(local, &SSID_rid, 1);
7429 writeAPListRid(local, &APList_rid, 1);
7430 }
7431 if (down_interruptible(&local->sem))
7432 return -ERESTARTSYS;
7433 writeConfigRid(local, 0);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02007434 enable_MAC(local, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007435 if (test_bit (FLAG_RESET, &local->flags))
7436 airo_set_promisc(local);
7437 else
7438 up(&local->sem);
7439
7440 return 0;
7441}
7442
7443/*------------------------------------------------------------------*/
7444/*
7445 * Structures to export the Wireless Handlers
7446 */
7447
7448static const struct iw_priv_args airo_private_args[] = {
7449/*{ cmd, set_args, get_args, name } */
7450 { AIROIOCTL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
7451 IW_PRIV_TYPE_BYTE | 2047, "airoioctl" },
7452 { AIROIDIFC, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
7453 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" },
7454};
7455
7456static const iw_handler airo_handler[] =
7457{
7458 (iw_handler) airo_config_commit, /* SIOCSIWCOMMIT */
7459 (iw_handler) airo_get_name, /* SIOCGIWNAME */
7460 (iw_handler) NULL, /* SIOCSIWNWID */
7461 (iw_handler) NULL, /* SIOCGIWNWID */
7462 (iw_handler) airo_set_freq, /* SIOCSIWFREQ */
7463 (iw_handler) airo_get_freq, /* SIOCGIWFREQ */
7464 (iw_handler) airo_set_mode, /* SIOCSIWMODE */
7465 (iw_handler) airo_get_mode, /* SIOCGIWMODE */
7466 (iw_handler) airo_set_sens, /* SIOCSIWSENS */
7467 (iw_handler) airo_get_sens, /* SIOCGIWSENS */
7468 (iw_handler) NULL, /* SIOCSIWRANGE */
7469 (iw_handler) airo_get_range, /* SIOCGIWRANGE */
7470 (iw_handler) NULL, /* SIOCSIWPRIV */
7471 (iw_handler) NULL, /* SIOCGIWPRIV */
7472 (iw_handler) NULL, /* SIOCSIWSTATS */
7473 (iw_handler) NULL, /* SIOCGIWSTATS */
7474 iw_handler_set_spy, /* SIOCSIWSPY */
7475 iw_handler_get_spy, /* SIOCGIWSPY */
7476 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
7477 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
7478 (iw_handler) airo_set_wap, /* SIOCSIWAP */
7479 (iw_handler) airo_get_wap, /* SIOCGIWAP */
7480 (iw_handler) NULL, /* -- hole -- */
7481 (iw_handler) airo_get_aplist, /* SIOCGIWAPLIST */
7482 (iw_handler) airo_set_scan, /* SIOCSIWSCAN */
7483 (iw_handler) airo_get_scan, /* SIOCGIWSCAN */
7484 (iw_handler) airo_set_essid, /* SIOCSIWESSID */
7485 (iw_handler) airo_get_essid, /* SIOCGIWESSID */
7486 (iw_handler) airo_set_nick, /* SIOCSIWNICKN */
7487 (iw_handler) airo_get_nick, /* SIOCGIWNICKN */
7488 (iw_handler) NULL, /* -- hole -- */
7489 (iw_handler) NULL, /* -- hole -- */
7490 (iw_handler) airo_set_rate, /* SIOCSIWRATE */
7491 (iw_handler) airo_get_rate, /* SIOCGIWRATE */
7492 (iw_handler) airo_set_rts, /* SIOCSIWRTS */
7493 (iw_handler) airo_get_rts, /* SIOCGIWRTS */
7494 (iw_handler) airo_set_frag, /* SIOCSIWFRAG */
7495 (iw_handler) airo_get_frag, /* SIOCGIWFRAG */
7496 (iw_handler) airo_set_txpow, /* SIOCSIWTXPOW */
7497 (iw_handler) airo_get_txpow, /* SIOCGIWTXPOW */
7498 (iw_handler) airo_set_retry, /* SIOCSIWRETRY */
7499 (iw_handler) airo_get_retry, /* SIOCGIWRETRY */
7500 (iw_handler) airo_set_encode, /* SIOCSIWENCODE */
7501 (iw_handler) airo_get_encode, /* SIOCGIWENCODE */
7502 (iw_handler) airo_set_power, /* SIOCSIWPOWER */
7503 (iw_handler) airo_get_power, /* SIOCGIWPOWER */
Dan Williams4be757d2006-01-30 11:58:00 -05007504 (iw_handler) NULL, /* -- hole -- */
7505 (iw_handler) NULL, /* -- hole -- */
7506 (iw_handler) NULL, /* SIOCSIWGENIE */
7507 (iw_handler) NULL, /* SIOCGIWGENIE */
7508 (iw_handler) airo_set_auth, /* SIOCSIWAUTH */
7509 (iw_handler) airo_get_auth, /* SIOCGIWAUTH */
7510 (iw_handler) airo_set_encodeext, /* SIOCSIWENCODEEXT */
7511 (iw_handler) airo_get_encodeext, /* SIOCGIWENCODEEXT */
7512 (iw_handler) NULL, /* SIOCSIWPMKSA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007513};
7514
7515/* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here.
7516 * We want to force the use of the ioctl code, because those can't be
7517 * won't work the iw_handler code (because they simultaneously read
7518 * and write data and iw_handler can't do that).
7519 * Note that it's perfectly legal to read/write on a single ioctl command,
7520 * you just can't use iwpriv and need to force it via the ioctl handler.
7521 * Jean II */
7522static const iw_handler airo_private_handler[] =
7523{
7524 NULL, /* SIOCIWFIRSTPRIV */
7525};
7526
7527static const struct iw_handler_def airo_handler_def =
7528{
Denis Chengff8ac602007-09-02 18:30:18 +08007529 .num_standard = ARRAY_SIZE(airo_handler),
7530 .num_private = ARRAY_SIZE(airo_private_handler),
7531 .num_private_args = ARRAY_SIZE(airo_private_args),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007532 .standard = airo_handler,
7533 .private = airo_private_handler,
7534 .private_args = airo_private_args,
7535 .get_wireless_stats = airo_get_wireless_stats,
7536};
7537
Linus Torvalds1da177e2005-04-16 15:20:36 -07007538/*
7539 * This defines the configuration part of the Wireless Extensions
7540 * Note : irq and spinlock protection will occur in the subroutines
7541 *
7542 * TODO :
7543 * o Check input value more carefully and fill correct values in range
7544 * o Test and shakeout the bugs (if any)
7545 *
7546 * Jean II
7547 *
7548 * Javier Achirica did a great job of merging code from the unnamed CISCO
7549 * developer that added support for flashing the card.
7550 */
7551static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
7552{
7553 int rc = 0;
7554 struct airo_info *ai = (struct airo_info *)dev->priv;
7555
Pavel Machekca078ba2005-09-03 15:56:57 -07007556 if (ai->power.event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007557 return 0;
7558
7559 switch (cmd) {
7560#ifdef CISCO_EXT
7561 case AIROIDIFC:
7562#ifdef AIROOLDIDIFC
7563 case AIROOLDIDIFC:
7564#endif
7565 {
7566 int val = AIROMAGIC;
7567 aironet_ioctl com;
7568 if (copy_from_user(&com,rq->ifr_data,sizeof(com)))
7569 rc = -EFAULT;
7570 else if (copy_to_user(com.data,(char *)&val,sizeof(val)))
7571 rc = -EFAULT;
7572 }
7573 break;
7574
7575 case AIROIOCTL:
7576#ifdef AIROOLDIOCTL
7577 case AIROOLDIOCTL:
7578#endif
7579 /* Get the command struct and hand it off for evaluation by
7580 * the proper subfunction
7581 */
7582 {
7583 aironet_ioctl com;
7584 if (copy_from_user(&com,rq->ifr_data,sizeof(com))) {
7585 rc = -EFAULT;
7586 break;
7587 }
7588
7589 /* Separate R/W functions bracket legality here
7590 */
7591 if ( com.command == AIRORSWVERSION ) {
7592 if (copy_to_user(com.data, swversion, sizeof(swversion)))
7593 rc = -EFAULT;
7594 else
7595 rc = 0;
7596 }
7597 else if ( com.command <= AIRORRID)
7598 rc = readrids(dev,&com);
7599 else if ( com.command >= AIROPCAP && com.command <= (AIROPLEAPUSR+2) )
7600 rc = writerids(dev,&com);
7601 else if ( com.command >= AIROFLSHRST && com.command <= AIRORESTART )
7602 rc = flashcard(dev,&com);
7603 else
7604 rc = -EINVAL; /* Bad command in ioctl */
7605 }
7606 break;
7607#endif /* CISCO_EXT */
7608
7609 // All other calls are currently unsupported
7610 default:
7611 rc = -EOPNOTSUPP;
7612 }
7613 return rc;
7614}
7615
Linus Torvalds1da177e2005-04-16 15:20:36 -07007616/*
7617 * Get the Wireless stats out of the driver
7618 * Note : irq and spinlock protection will occur in the subroutines
7619 *
7620 * TODO :
7621 * o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs)
7622 *
7623 * Jean
7624 */
7625static void airo_read_wireless_stats(struct airo_info *local)
7626{
7627 StatusRid status_rid;
7628 StatsRid stats_rid;
7629 CapabilityRid cap_rid;
Al Viroa23ace52007-12-19 22:24:16 -05007630 __le32 *vals = stats_rid.vals;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007631
7632 /* Get stats out of the card */
Dan Williams3c304952006-04-15 12:26:18 -04007633 clear_bit(JOB_WSTATS, &local->jobs);
Pavel Machekca078ba2005-09-03 15:56:57 -07007634 if (local->power.event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007635 up(&local->sem);
7636 return;
7637 }
7638 readCapabilityRid(local, &cap_rid, 0);
7639 readStatusRid(local, &status_rid, 0);
7640 readStatsRid(local, &stats_rid, RID_STATS, 0);
7641 up(&local->sem);
7642
7643 /* The status */
7644 local->wstats.status = status_rid.mode;
7645
Dan Williams41480af2005-05-10 09:45:51 -04007646 /* Signal quality and co */
7647 if (local->rssi) {
7648 local->wstats.qual.level = airo_rssi_to_dbm( local->rssi, status_rid.sigQuality );
7649 /* normalizedSignalStrength appears to be a percentage */
7650 local->wstats.qual.qual = status_rid.normalizedSignalStrength;
7651 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007652 local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04007653 local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
7654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007655 if (status_rid.len >= 124) {
Dan Williams41480af2005-05-10 09:45:51 -04007656 local->wstats.qual.noise = 0x100 - status_rid.noisedBm;
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007657 local->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007658 } else {
7659 local->wstats.qual.noise = 0;
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007660 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 -07007661 }
7662
7663 /* Packets discarded in the wireless adapter due to wireless
7664 * specific problems */
Al Viroa23ace52007-12-19 22:24:16 -05007665 local->wstats.discard.nwid = le32_to_cpu(vals[56]) +
7666 le32_to_cpu(vals[57]) +
7667 le32_to_cpu(vals[58]); /* SSID Mismatch */
7668 local->wstats.discard.code = le32_to_cpu(vals[6]);/* RxWepErr */
7669 local->wstats.discard.fragment = le32_to_cpu(vals[30]);
7670 local->wstats.discard.retries = le32_to_cpu(vals[10]);
7671 local->wstats.discard.misc = le32_to_cpu(vals[1]) +
7672 le32_to_cpu(vals[32]);
7673 local->wstats.miss.beacon = le32_to_cpu(vals[34]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007674}
7675
Jouni Malinenff1d2762005-05-12 22:54:16 -04007676static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007677{
7678 struct airo_info *local = dev->priv;
7679
Dan Williams3c304952006-04-15 12:26:18 -04007680 if (!test_bit(JOB_WSTATS, &local->jobs)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007681 /* Get stats out of the card if available */
7682 if (down_trylock(&local->sem) != 0) {
Dan Williams3c304952006-04-15 12:26:18 -04007683 set_bit(JOB_WSTATS, &local->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007684 wake_up_interruptible(&local->thr_wait);
7685 } else
7686 airo_read_wireless_stats(local);
7687 }
7688
7689 return &local->wstats;
7690}
Linus Torvalds1da177e2005-04-16 15:20:36 -07007691
7692#ifdef CISCO_EXT
7693/*
7694 * This just translates from driver IOCTL codes to the command codes to
7695 * feed to the radio's host interface. Things can be added/deleted
7696 * as needed. This represents the READ side of control I/O to
7697 * the card
7698 */
7699static int readrids(struct net_device *dev, aironet_ioctl *comp) {
7700 unsigned short ridcode;
7701 unsigned char *iobuf;
7702 int len;
7703 struct airo_info *ai = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007704
7705 if (test_bit(FLAG_FLASHING, &ai->flags))
7706 return -EIO;
7707
7708 switch(comp->command)
7709 {
7710 case AIROGCAP: ridcode = RID_CAPABILITIES; break;
7711 case AIROGCFG: ridcode = RID_CONFIG;
7712 if (test_bit(FLAG_COMMIT, &ai->flags)) {
7713 disable_MAC (ai, 1);
7714 writeConfigRid (ai, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02007715 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007716 }
7717 break;
7718 case AIROGSLIST: ridcode = RID_SSID; break;
7719 case AIROGVLIST: ridcode = RID_APLIST; break;
7720 case AIROGDRVNAM: ridcode = RID_DRVNAME; break;
7721 case AIROGEHTENC: ridcode = RID_ETHERENCAP; break;
7722 case AIROGWEPKTMP: ridcode = RID_WEP_TEMP;
7723 /* Only super-user can read WEP keys */
7724 if (!capable(CAP_NET_ADMIN))
7725 return -EPERM;
7726 break;
7727 case AIROGWEPKNV: ridcode = RID_WEP_PERM;
7728 /* Only super-user can read WEP keys */
7729 if (!capable(CAP_NET_ADMIN))
7730 return -EPERM;
7731 break;
7732 case AIROGSTAT: ridcode = RID_STATUS; break;
7733 case AIROGSTATSD32: ridcode = RID_STATSDELTA; break;
7734 case AIROGSTATSC32: ridcode = RID_STATS; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007735 case AIROGMICSTATS:
7736 if (copy_to_user(comp->data, &ai->micstats,
7737 min((int)comp->len,(int)sizeof(ai->micstats))))
7738 return -EFAULT;
7739 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007740 case AIRORRID: ridcode = comp->ridnum; break;
7741 default:
7742 return -EINVAL;
7743 break;
7744 }
7745
7746 if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
7747 return -ENOMEM;
7748
7749 PC4500_readrid(ai,ridcode,iobuf,RIDSIZE, 1);
7750 /* get the count of bytes in the rid docs say 1st 2 bytes is it.
7751 * then return it to the user
7752 * 9/22/2000 Honor user given length
7753 */
7754 len = comp->len;
7755
7756 if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) {
7757 kfree (iobuf);
7758 return -EFAULT;
7759 }
7760 kfree (iobuf);
7761 return 0;
7762}
7763
7764/*
7765 * Danger Will Robinson write the rids here
7766 */
7767
7768static int writerids(struct net_device *dev, aironet_ioctl *comp) {
7769 struct airo_info *ai = dev->priv;
7770 int ridcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007771 int enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007772 static int (* writer)(struct airo_info *, u16 rid, const void *, int, int);
7773 unsigned char *iobuf;
7774
7775 /* Only super-user can write RIDs */
7776 if (!capable(CAP_NET_ADMIN))
7777 return -EPERM;
7778
7779 if (test_bit(FLAG_FLASHING, &ai->flags))
7780 return -EIO;
7781
7782 ridcode = 0;
7783 writer = do_writerid;
7784
7785 switch(comp->command)
7786 {
7787 case AIROPSIDS: ridcode = RID_SSID; break;
7788 case AIROPCAP: ridcode = RID_CAPABILITIES; break;
7789 case AIROPAPLIST: ridcode = RID_APLIST; break;
7790 case AIROPCFG: ai->config.len = 0;
7791 clear_bit(FLAG_COMMIT, &ai->flags);
7792 ridcode = RID_CONFIG; break;
7793 case AIROPWEPKEYNV: ridcode = RID_WEP_PERM; break;
7794 case AIROPLEAPUSR: ridcode = RID_LEAPUSERNAME; break;
7795 case AIROPLEAPPWD: ridcode = RID_LEAPPASSWORD; break;
7796 case AIROPWEPKEY: ridcode = RID_WEP_TEMP; writer = PC4500_writerid;
7797 break;
7798 case AIROPLEAPUSR+1: ridcode = 0xFF2A; break;
7799 case AIROPLEAPUSR+2: ridcode = 0xFF2B; break;
7800
7801 /* this is not really a rid but a command given to the card
7802 * same with MAC off
7803 */
7804 case AIROPMACON:
Michal Schmidt175ec1a2007-06-29 15:33:47 +02007805 if (enable_MAC(ai, 1) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007806 return -EIO;
7807 return 0;
7808
7809 /*
7810 * Evidently this code in the airo driver does not get a symbol
7811 * as disable_MAC. it's probably so short the compiler does not gen one.
7812 */
7813 case AIROPMACOFF:
7814 disable_MAC(ai, 1);
7815 return 0;
7816
7817 /* This command merely clears the counts does not actually store any data
7818 * only reads rid. But as it changes the cards state, I put it in the
7819 * writerid routines.
7820 */
7821 case AIROPSTCLR:
7822 if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
7823 return -ENOMEM;
7824
7825 PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDSIZE, 1);
7826
Linus Torvalds1da177e2005-04-16 15:20:36 -07007827 enabled = ai->micstats.enabled;
7828 memset(&ai->micstats,0,sizeof(ai->micstats));
7829 ai->micstats.enabled = enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007830
7831 if (copy_to_user(comp->data, iobuf,
7832 min((int)comp->len, (int)RIDSIZE))) {
7833 kfree (iobuf);
7834 return -EFAULT;
7835 }
7836 kfree (iobuf);
7837 return 0;
7838
7839 default:
7840 return -EOPNOTSUPP; /* Blarg! */
7841 }
7842 if(comp->len > RIDSIZE)
7843 return -EINVAL;
7844
7845 if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
7846 return -ENOMEM;
7847
7848 if (copy_from_user(iobuf,comp->data,comp->len)) {
7849 kfree (iobuf);
7850 return -EFAULT;
7851 }
7852
7853 if (comp->command == AIROPCFG) {
7854 ConfigRid *cfg = (ConfigRid *)iobuf;
7855
7856 if (test_bit(FLAG_MIC_CAPABLE, &ai->flags))
Al Viro2ab1f512007-12-20 23:04:35 -05007857 cfg->opmode |= cpu_to_le16(MODE_MIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007858
Al Viro2ab1f512007-12-20 23:04:35 -05007859 if ((le16_to_cpu(cfg->opmode) & 0xFF) == MODE_STA_IBSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007860 set_bit (FLAG_ADHOC, &ai->flags);
7861 else
7862 clear_bit (FLAG_ADHOC, &ai->flags);
7863 }
7864
7865 if((*writer)(ai, ridcode, iobuf,comp->len,1)) {
7866 kfree (iobuf);
7867 return -EIO;
7868 }
7869 kfree (iobuf);
7870 return 0;
7871}
7872
7873/*****************************************************************************
7874 * Ancillary flash / mod functions much black magic lurkes here *
7875 *****************************************************************************
7876 */
7877
7878/*
7879 * Flash command switch table
7880 */
7881
Jouni Malinenff1d2762005-05-12 22:54:16 -04007882static int flashcard(struct net_device *dev, aironet_ioctl *comp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007883 int z;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007884
7885 /* Only super-user can modify flash */
7886 if (!capable(CAP_NET_ADMIN))
7887 return -EPERM;
7888
7889 switch(comp->command)
7890 {
7891 case AIROFLSHRST:
7892 return cmdreset((struct airo_info *)dev->priv);
7893
7894 case AIROFLSHSTFL:
7895 if (!((struct airo_info *)dev->priv)->flash &&
7896 (((struct airo_info *)dev->priv)->flash = kmalloc (FLASHSIZE, GFP_KERNEL)) == NULL)
7897 return -ENOMEM;
7898 return setflashmode((struct airo_info *)dev->priv);
7899
7900 case AIROFLSHGCHR: /* Get char from aux */
7901 if(comp->len != sizeof(int))
7902 return -EINVAL;
7903 if (copy_from_user(&z,comp->data,comp->len))
7904 return -EFAULT;
7905 return flashgchar((struct airo_info *)dev->priv,z,8000);
7906
7907 case AIROFLSHPCHR: /* Send char to card. */
7908 if(comp->len != sizeof(int))
7909 return -EINVAL;
7910 if (copy_from_user(&z,comp->data,comp->len))
7911 return -EFAULT;
7912 return flashpchar((struct airo_info *)dev->priv,z,8000);
7913
7914 case AIROFLPUTBUF: /* Send 32k to card */
7915 if (!((struct airo_info *)dev->priv)->flash)
7916 return -ENOMEM;
7917 if(comp->len > FLASHSIZE)
7918 return -EINVAL;
7919 if(copy_from_user(((struct airo_info *)dev->priv)->flash,comp->data,comp->len))
7920 return -EFAULT;
7921
7922 flashputbuf((struct airo_info *)dev->priv);
7923 return 0;
7924
7925 case AIRORESTART:
7926 if(flashrestart((struct airo_info *)dev->priv,dev))
7927 return -EIO;
7928 return 0;
7929 }
7930 return -EINVAL;
7931}
7932
7933#define FLASH_COMMAND 0x7e7e
7934
7935/*
7936 * STEP 1)
7937 * Disable MAC and do soft reset on
7938 * card.
7939 */
7940
Jouni Malinenff1d2762005-05-12 22:54:16 -04007941static int cmdreset(struct airo_info *ai) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007942 disable_MAC(ai, 1);
7943
7944 if(!waitbusy (ai)){
Dan Williams934d8bf2006-03-16 13:46:23 -05007945 airo_print_info(ai->dev->name, "Waitbusy hang before RESET");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007946 return -EBUSY;
7947 }
7948
7949 OUT4500(ai,COMMAND,CMD_SOFTRESET);
7950
7951 ssleep(1); /* WAS 600 12/7/00 */
7952
7953 if(!waitbusy (ai)){
Dan Williams934d8bf2006-03-16 13:46:23 -05007954 airo_print_info(ai->dev->name, "Waitbusy hang AFTER RESET");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007955 return -EBUSY;
7956 }
7957 return 0;
7958}
7959
7960/* STEP 2)
7961 * Put the card in legendary flash
7962 * mode
7963 */
7964
Jouni Malinenff1d2762005-05-12 22:54:16 -04007965static int setflashmode (struct airo_info *ai) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007966 set_bit (FLAG_FLASHING, &ai->flags);
7967
7968 OUT4500(ai, SWS0, FLASH_COMMAND);
7969 OUT4500(ai, SWS1, FLASH_COMMAND);
7970 if (probe) {
7971 OUT4500(ai, SWS0, FLASH_COMMAND);
7972 OUT4500(ai, COMMAND,0x10);
7973 } else {
7974 OUT4500(ai, SWS2, FLASH_COMMAND);
7975 OUT4500(ai, SWS3, FLASH_COMMAND);
7976 OUT4500(ai, COMMAND,0);
7977 }
7978 msleep(500); /* 500ms delay */
7979
7980 if(!waitbusy(ai)) {
7981 clear_bit (FLAG_FLASHING, &ai->flags);
Dan Williams934d8bf2006-03-16 13:46:23 -05007982 airo_print_info(ai->dev->name, "Waitbusy hang after setflash mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007983 return -EIO;
7984 }
7985 return 0;
7986}
7987
7988/* Put character to SWS0 wait for dwelltime
7989 * x 50us for echo .
7990 */
7991
Jouni Malinenff1d2762005-05-12 22:54:16 -04007992static int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007993 int echo;
7994 int waittime;
7995
7996 byte |= 0x8000;
7997
7998 if(dwelltime == 0 )
7999 dwelltime = 200;
8000
8001 waittime=dwelltime;
8002
8003 /* Wait for busy bit d15 to go false indicating buffer empty */
8004 while ((IN4500 (ai, SWS0) & 0x8000) && waittime > 0) {
8005 udelay (50);
8006 waittime -= 50;
8007 }
8008
8009 /* timeout for busy clear wait */
8010 if(waittime <= 0 ){
Dan Williams934d8bf2006-03-16 13:46:23 -05008011 airo_print_info(ai->dev->name, "flash putchar busywait timeout!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07008012 return -EBUSY;
8013 }
8014
8015 /* Port is clear now write byte and wait for it to echo back */
8016 do {
8017 OUT4500(ai,SWS0,byte);
8018 udelay(50);
8019 dwelltime -= 50;
8020 echo = IN4500(ai,SWS1);
8021 } while (dwelltime >= 0 && echo != byte);
8022
8023 OUT4500(ai,SWS1,0);
8024
8025 return (echo == byte) ? 0 : -EIO;
8026}
8027
8028/*
8029 * Get a character from the card matching matchbyte
8030 * Step 3)
8031 */
Jouni Malinenff1d2762005-05-12 22:54:16 -04008032static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
Linus Torvalds1da177e2005-04-16 15:20:36 -07008033 int rchar;
8034 unsigned char rbyte=0;
8035
8036 do {
8037 rchar = IN4500(ai,SWS1);
8038
8039 if(dwelltime && !(0x8000 & rchar)){
8040 dwelltime -= 10;
8041 mdelay(10);
8042 continue;
8043 }
8044 rbyte = 0xff & rchar;
8045
8046 if( (rbyte == matchbyte) && (0x8000 & rchar) ){
8047 OUT4500(ai,SWS1,0);
8048 return 0;
8049 }
8050 if( rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar)
8051 break;
8052 OUT4500(ai,SWS1,0);
8053
8054 }while(dwelltime > 0);
8055 return -EIO;
8056}
8057
8058/*
8059 * Transfer 32k of firmware data from user buffer to our buffer and
8060 * send to the card
8061 */
8062
Jouni Malinenff1d2762005-05-12 22:54:16 -04008063static int flashputbuf(struct airo_info *ai){
Linus Torvalds1da177e2005-04-16 15:20:36 -07008064 int nwords;
8065
8066 /* Write stuff */
8067 if (test_bit(FLAG_MPI,&ai->flags))
8068 memcpy_toio(ai->pciaux + 0x8000, ai->flash, FLASHSIZE);
8069 else {
8070 OUT4500(ai,AUXPAGE,0x100);
8071 OUT4500(ai,AUXOFF,0);
8072
8073 for(nwords=0;nwords != FLASHSIZE / 2;nwords++){
8074 OUT4500(ai,AUXDATA,ai->flash[nwords] & 0xffff);
8075 }
8076 }
8077 OUT4500(ai,SWS0,0x8000);
8078
8079 return 0;
8080}
8081
8082/*
8083 *
8084 */
Jouni Malinenff1d2762005-05-12 22:54:16 -04008085static int flashrestart(struct airo_info *ai,struct net_device *dev){
Linus Torvalds1da177e2005-04-16 15:20:36 -07008086 int i,status;
8087
8088 ssleep(1); /* Added 12/7/00 */
8089 clear_bit (FLAG_FLASHING, &ai->flags);
8090 if (test_bit(FLAG_MPI, &ai->flags)) {
8091 status = mpi_init_descriptors(ai);
8092 if (status != SUCCESS)
8093 return status;
8094 }
8095 status = setup_card(ai, dev->dev_addr, 1);
8096
8097 if (!test_bit(FLAG_MPI,&ai->flags))
8098 for( i = 0; i < MAX_FIDS; i++ ) {
8099 ai->fids[i] = transmit_allocate
Dan Williams15db2762006-03-16 13:46:27 -05008100 ( ai, AIRO_DEF_MTU, i >= MAX_FIDS / 2 );
Linus Torvalds1da177e2005-04-16 15:20:36 -07008101 }
8102
8103 ssleep(1); /* Added 12/7/00 */
8104 return status;
8105}
8106#endif /* CISCO_EXT */
8107
8108/*
8109 This program is free software; you can redistribute it and/or
8110 modify it under the terms of the GNU General Public License
8111 as published by the Free Software Foundation; either version 2
8112 of the License, or (at your option) any later version.
8113
8114 This program is distributed in the hope that it will be useful,
8115 but WITHOUT ANY WARRANTY; without even the implied warranty of
8116 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8117 GNU General Public License for more details.
8118
8119 In addition:
8120
8121 Redistribution and use in source and binary forms, with or without
8122 modification, are permitted provided that the following conditions
8123 are met:
8124
8125 1. Redistributions of source code must retain the above copyright
8126 notice, this list of conditions and the following disclaimer.
8127 2. Redistributions in binary form must reproduce the above copyright
8128 notice, this list of conditions and the following disclaimer in the
8129 documentation and/or other materials provided with the distribution.
8130 3. The name of the author may not be used to endorse or promote
8131 products derived from this software without specific prior written
8132 permission.
8133
8134 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
8135 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8136 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8137 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
8138 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
8139 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
8140 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8141 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
8142 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
8143 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
8144 POSSIBILITY OF SUCH DAMAGE.
8145*/
8146
8147module_init(airo_init_module);
8148module_exit(airo_cleanup_module);