blob: 306a1d1c1c227804699ba93ac6ed2330a76ff365 [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 {
Al Viroa7497162007-12-20 17:49:41 -0500716 __le16 len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 u8 ap[4][ETH_ALEN];
718} APListRid;
719
720typedef struct {
Al Viro56d81bd2007-12-20 17:18:35 -0500721 __le16 len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 char oui[3];
723 char zero;
Al Viro56d81bd2007-12-20 17:18:35 -0500724 __le16 prodNum;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 char manName[32];
726 char prodName[16];
727 char prodVer[8];
728 char factoryAddr[ETH_ALEN];
729 char aironetAddr[ETH_ALEN];
Al Viro56d81bd2007-12-20 17:18:35 -0500730 __le16 radioType;
731 __le16 country;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 char callid[ETH_ALEN];
733 char supportedRates[8];
734 char rxDiversity;
735 char txDiversity;
Al Viro56d81bd2007-12-20 17:18:35 -0500736 __le16 txPowerLevels[8];
737 __le16 hardVer;
738 __le16 hardCap;
739 __le16 tempRange;
740 __le16 softVer;
741 __le16 softSubVer;
742 __le16 interfaceVer;
743 __le16 softCap;
744 __le16 bootBlockVer;
745 __le16 requiredHard;
746 __le16 extSoftCap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747} 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}
Al Viroa7497162007-12-20 17:49:41 -05001869
1870static int readAPListRid(struct airo_info *ai, APListRid *aplr)
1871{
1872 return PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr), 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873}
Al Viroa7497162007-12-20 17:49:41 -05001874
1875static int writeAPListRid(struct airo_info *ai, APListRid *aplr, int lock)
1876{
1877 return PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
Al Viro56d81bd2007-12-20 17:18:35 -05001880static int readCapabilityRid(struct airo_info *ai, CapabilityRid *capr, int lock)
1881{
1882 return PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884
Al Viroa23ace52007-12-19 22:24:16 -05001885static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock)
1886{
1887 return PC4500_readrid(ai, rid, sr, sizeof(*sr), lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888}
1889
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001890static void try_auto_wep(struct airo_info *ai)
1891{
1892 if (auto_wep && !(ai->flags & FLAG_RADIO_DOWN)) {
1893 ai->expires = RUN_AT(3*HZ);
1894 wake_up_interruptible(&ai->thr_wait);
1895 }
1896}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001898static int airo_open(struct net_device *dev) {
1899 struct airo_info *ai = dev->priv;
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001900 int rc = 0;
1901
1902 if (test_bit(FLAG_FLASHING, &ai->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 return -EIO;
1904
1905 /* Make sure the card is configured.
1906 * Wireless Extensions may postpone config changes until the card
1907 * is open (to pipeline changes and speed-up card setup). If
1908 * those changes are not yet commited, do it now - Jean II */
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001909 if (test_bit(FLAG_COMMIT, &ai->flags)) {
1910 disable_MAC(ai, 1);
1911 writeConfigRid(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 }
1913
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001914 if (ai->wifidev != dev) {
1915 clear_bit(JOB_DIE, &ai->jobs);
1916 ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name);
1917 if (IS_ERR(ai->airo_thread_task))
1918 return (int)PTR_ERR(ai->airo_thread_task);
1919
1920 rc = request_irq(dev->irq, airo_interrupt, IRQF_SHARED,
1921 dev->name, dev);
1922 if (rc) {
1923 airo_print_err(dev->name,
1924 "register interrupt %d failed, rc %d",
1925 dev->irq, rc);
1926 set_bit(JOB_DIE, &ai->jobs);
1927 kthread_stop(ai->airo_thread_task);
1928 return rc;
1929 }
1930
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 /* Power on the MAC controller (which may have been disabled) */
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02001932 clear_bit(FLAG_RADIO_DOWN, &ai->flags);
1933 enable_interrupts(ai);
1934
1935 try_auto_wep(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 }
Michal Schmidt175ec1a2007-06-29 15:33:47 +02001937 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938
1939 netif_start_queue(dev);
1940 return 0;
1941}
1942
1943static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
1944 int npacks, pending;
1945 unsigned long flags;
1946 struct airo_info *ai = dev->priv;
1947
1948 if (!skb) {
Dan Williams934d8bf2006-03-16 13:46:23 -05001949 airo_print_err(dev->name, "%s: skb == NULL!",__FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 return 0;
1951 }
1952 npacks = skb_queue_len (&ai->txq);
1953
1954 if (npacks >= MAXTXQ - 1) {
1955 netif_stop_queue (dev);
1956 if (npacks > MAXTXQ) {
1957 ai->stats.tx_fifo_errors++;
1958 return 1;
1959 }
1960 skb_queue_tail (&ai->txq, skb);
1961 return 0;
1962 }
1963
1964 spin_lock_irqsave(&ai->aux_lock, flags);
1965 skb_queue_tail (&ai->txq, skb);
1966 pending = test_bit(FLAG_PENDING_XMIT, &ai->flags);
1967 spin_unlock_irqrestore(&ai->aux_lock,flags);
1968 netif_wake_queue (dev);
1969
1970 if (pending == 0) {
1971 set_bit(FLAG_PENDING_XMIT, &ai->flags);
1972 mpi_send_packet (dev);
1973 }
1974 return 0;
1975}
1976
1977/*
1978 * @mpi_send_packet
1979 *
1980 * Attempt to transmit a packet. Can be called from interrupt
1981 * or transmit . return number of packets we tried to send
1982 */
1983
1984static int mpi_send_packet (struct net_device *dev)
1985{
1986 struct sk_buff *skb;
1987 unsigned char *buffer;
Al Viro593c2b92007-12-17 15:09:34 -05001988 s16 len;
1989 __le16 *payloadLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 struct airo_info *ai = dev->priv;
1991 u8 *sendbuf;
1992
1993 /* get a packet to send */
1994
Al Viro79ea13c2008-01-24 02:06:46 -08001995 if ((skb = skb_dequeue(&ai->txq)) == NULL) {
Dan Williams934d8bf2006-03-16 13:46:23 -05001996 airo_print_err(dev->name,
1997 "%s: Dequeue'd zero in send_packet()",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 __FUNCTION__);
1999 return 0;
2000 }
2001
2002 /* check min length*/
2003 len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
2004 buffer = skb->data;
2005
2006 ai->txfids[0].tx_desc.offset = 0;
2007 ai->txfids[0].tx_desc.valid = 1;
2008 ai->txfids[0].tx_desc.eoc = 1;
2009 ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr);
2010
2011/*
2012 * Magic, the cards firmware needs a length count (2 bytes) in the host buffer
2013 * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen
2014 * is immediatly after it. ------------------------------------------------
2015 * |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA|
2016 * ------------------------------------------------
2017 */
2018
2019 memcpy((char *)ai->txfids[0].virtual_host_addr,
2020 (char *)&wifictlhdr8023, sizeof(wifictlhdr8023));
2021
Al Viro593c2b92007-12-17 15:09:34 -05002022 payloadLen = (__le16 *)(ai->txfids[0].virtual_host_addr +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 sizeof(wifictlhdr8023));
2024 sendbuf = ai->txfids[0].virtual_host_addr +
2025 sizeof(wifictlhdr8023) + 2 ;
2026
2027 /*
2028 * Firmware automaticly puts 802 header on so
2029 * we don't need to account for it in the length
2030 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
Al Viro593c2b92007-12-17 15:09:34 -05002032 (ntohs(((__be16 *)buffer)[6]) != 0x888E)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 MICBuffer pMic;
2034
2035 if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS)
2036 return ERROR;
2037
2038 *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic));
2039 ai->txfids[0].tx_desc.len += sizeof(pMic);
2040 /* copy data into airo dma buffer */
2041 memcpy (sendbuf, buffer, sizeof(etherHead));
2042 buffer += sizeof(etherHead);
2043 sendbuf += sizeof(etherHead);
2044 memcpy (sendbuf, &pMic, sizeof(pMic));
2045 sendbuf += sizeof(pMic);
2046 memcpy (sendbuf, buffer, len - sizeof(etherHead));
Adrian Bunka39d3e72006-01-21 01:35:15 +01002047 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 *payloadLen = cpu_to_le16(len - sizeof(etherHead));
2049
2050 dev->trans_start = jiffies;
2051
2052 /* copy data into airo dma buffer */
2053 memcpy(sendbuf, buffer, len);
2054 }
2055
2056 memcpy_toio(ai->txfids[0].card_ram_off,
2057 &ai->txfids[0].tx_desc, sizeof(TxFid));
2058
2059 OUT4500(ai, EVACK, 8);
2060
2061 dev_kfree_skb_any(skb);
2062 return 1;
2063}
2064
Gabriel A. Devenyi29b09fc2005-11-03 19:30:47 -05002065static void get_tx_error(struct airo_info *ai, s32 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066{
Al Viro593c2b92007-12-17 15:09:34 -05002067 __le16 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
2069 if (fid < 0)
2070 status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status;
2071 else {
2072 if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) != SUCCESS)
2073 return;
2074 bap_read(ai, &status, 2, BAP0);
2075 }
2076 if (le16_to_cpu(status) & 2) /* Too many retries */
2077 ai->stats.tx_aborted_errors++;
2078 if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */
2079 ai->stats.tx_heartbeat_errors++;
2080 if (le16_to_cpu(status) & 8) /* Aid fail */
2081 { }
2082 if (le16_to_cpu(status) & 0x10) /* MAC disabled */
2083 ai->stats.tx_carrier_errors++;
2084 if (le16_to_cpu(status) & 0x20) /* Association lost */
2085 { }
2086 /* We produce a TXDROP event only for retry or lifetime
2087 * exceeded, because that's the only status that really mean
2088 * that this particular node went away.
2089 * Other errors means that *we* screwed up. - Jean II */
2090 if ((le16_to_cpu(status) & 2) ||
2091 (le16_to_cpu(status) & 4)) {
2092 union iwreq_data wrqu;
2093 char junk[0x18];
2094
2095 /* Faster to skip over useless data than to do
2096 * another bap_setup(). We are at offset 0x6 and
2097 * need to go to 0x18 and read 6 bytes - Jean II */
Al Virob8c06bc2007-12-19 17:55:43 -05002098 bap_read(ai, (__le16 *) junk, 0x18, BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099
2100 /* Copy 802.11 dest address.
2101 * We use the 802.11 header because the frame may
2102 * not be 802.3 or may be mangled...
2103 * In Ad-Hoc mode, it will be the node address.
2104 * In managed mode, it will be most likely the AP addr
2105 * User space will figure out how to convert it to
2106 * whatever it needs (IP address or else).
2107 * - Jean II */
2108 memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN);
2109 wrqu.addr.sa_family = ARPHRD_ETHER;
2110
2111 /* Send event to user space */
2112 wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL);
2113 }
2114}
2115
2116static void airo_end_xmit(struct net_device *dev) {
2117 u16 status;
2118 int i;
2119 struct airo_info *priv = dev->priv;
2120 struct sk_buff *skb = priv->xmit.skb;
2121 int fid = priv->xmit.fid;
2122 u32 *fids = priv->fids;
2123
Dan Williams3c304952006-04-15 12:26:18 -04002124 clear_bit(JOB_XMIT, &priv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 clear_bit(FLAG_PENDING_XMIT, &priv->flags);
2126 status = transmit_802_3_packet (priv, fids[fid], skb->data);
2127 up(&priv->sem);
2128
2129 i = 0;
2130 if ( status == SUCCESS ) {
2131 dev->trans_start = jiffies;
2132 for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++);
2133 } else {
2134 priv->fids[fid] &= 0xffff;
2135 priv->stats.tx_window_errors++;
2136 }
2137 if (i < MAX_FIDS / 2)
2138 netif_wake_queue(dev);
2139 dev_kfree_skb(skb);
2140}
2141
2142static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
2143 s16 len;
2144 int i, j;
2145 struct airo_info *priv = dev->priv;
2146 u32 *fids = priv->fids;
2147
2148 if ( skb == NULL ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002149 airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 return 0;
2151 }
2152
2153 /* Find a vacant FID */
2154 for( i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++ );
2155 for( j = i + 1; j < MAX_FIDS / 2 && (fids[j] & 0xffff0000); j++ );
2156
2157 if ( j >= MAX_FIDS / 2 ) {
2158 netif_stop_queue(dev);
2159
2160 if (i == MAX_FIDS / 2) {
2161 priv->stats.tx_fifo_errors++;
2162 return 1;
2163 }
2164 }
2165 /* check min length*/
2166 len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
2167 /* Mark fid as used & save length for later */
2168 fids[i] |= (len << 16);
2169 priv->xmit.skb = skb;
2170 priv->xmit.fid = i;
2171 if (down_trylock(&priv->sem) != 0) {
2172 set_bit(FLAG_PENDING_XMIT, &priv->flags);
2173 netif_stop_queue(dev);
Dan Williams3c304952006-04-15 12:26:18 -04002174 set_bit(JOB_XMIT, &priv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 wake_up_interruptible(&priv->thr_wait);
2176 } else
2177 airo_end_xmit(dev);
2178 return 0;
2179}
2180
2181static void airo_end_xmit11(struct net_device *dev) {
2182 u16 status;
2183 int i;
2184 struct airo_info *priv = dev->priv;
2185 struct sk_buff *skb = priv->xmit11.skb;
2186 int fid = priv->xmit11.fid;
2187 u32 *fids = priv->fids;
2188
Dan Williams3c304952006-04-15 12:26:18 -04002189 clear_bit(JOB_XMIT11, &priv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 clear_bit(FLAG_PENDING_XMIT11, &priv->flags);
2191 status = transmit_802_11_packet (priv, fids[fid], skb->data);
2192 up(&priv->sem);
2193
2194 i = MAX_FIDS / 2;
2195 if ( status == SUCCESS ) {
2196 dev->trans_start = jiffies;
2197 for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++);
2198 } else {
2199 priv->fids[fid] &= 0xffff;
2200 priv->stats.tx_window_errors++;
2201 }
2202 if (i < MAX_FIDS)
2203 netif_wake_queue(dev);
2204 dev_kfree_skb(skb);
2205}
2206
2207static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
2208 s16 len;
2209 int i, j;
2210 struct airo_info *priv = dev->priv;
2211 u32 *fids = priv->fids;
2212
2213 if (test_bit(FLAG_MPI, &priv->flags)) {
2214 /* Not implemented yet for MPI350 */
2215 netif_stop_queue(dev);
2216 return -ENETDOWN;
2217 }
2218
2219 if ( skb == NULL ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002220 airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 return 0;
2222 }
2223
2224 /* Find a vacant FID */
2225 for( i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++ );
2226 for( j = i + 1; j < MAX_FIDS && (fids[j] & 0xffff0000); j++ );
2227
2228 if ( j >= MAX_FIDS ) {
2229 netif_stop_queue(dev);
2230
2231 if (i == MAX_FIDS) {
2232 priv->stats.tx_fifo_errors++;
2233 return 1;
2234 }
2235 }
2236 /* check min length*/
2237 len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
2238 /* Mark fid as used & save length for later */
2239 fids[i] |= (len << 16);
2240 priv->xmit11.skb = skb;
2241 priv->xmit11.fid = i;
2242 if (down_trylock(&priv->sem) != 0) {
2243 set_bit(FLAG_PENDING_XMIT11, &priv->flags);
2244 netif_stop_queue(dev);
Dan Williams3c304952006-04-15 12:26:18 -04002245 set_bit(JOB_XMIT11, &priv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 wake_up_interruptible(&priv->thr_wait);
2247 } else
2248 airo_end_xmit11(dev);
2249 return 0;
2250}
2251
Al Viroa23ace52007-12-19 22:24:16 -05002252static void airo_read_stats(struct airo_info *ai)
2253{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 StatsRid stats_rid;
Al Viroa23ace52007-12-19 22:24:16 -05002255 __le32 *vals = stats_rid.vals;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256
Dan Williams3c304952006-04-15 12:26:18 -04002257 clear_bit(JOB_STATS, &ai->jobs);
Pavel Machekca078ba2005-09-03 15:56:57 -07002258 if (ai->power.event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 up(&ai->sem);
2260 return;
2261 }
2262 readStatsRid(ai, &stats_rid, RID_STATS, 0);
2263 up(&ai->sem);
2264
Al Viroa23ace52007-12-19 22:24:16 -05002265 ai->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) +
2266 le32_to_cpu(vals[45]);
2267 ai->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) +
2268 le32_to_cpu(vals[41]);
2269 ai->stats.rx_bytes = le32_to_cpu(vals[92]);
2270 ai->stats.tx_bytes = le32_to_cpu(vals[91]);
2271 ai->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) +
2272 le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]);
2273 ai->stats.tx_errors = le32_to_cpu(vals[42]) + ai->stats.tx_fifo_errors;
2274 ai->stats.multicast = le32_to_cpu(vals[43]);
2275 ai->stats.collisions = le32_to_cpu(vals[89]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276
2277 /* detailed rx_errors: */
Al Viroa23ace52007-12-19 22:24:16 -05002278 ai->stats.rx_length_errors = le32_to_cpu(vals[3]);
2279 ai->stats.rx_crc_errors = le32_to_cpu(vals[4]);
2280 ai->stats.rx_frame_errors = le32_to_cpu(vals[2]);
2281 ai->stats.rx_fifo_errors = le32_to_cpu(vals[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282}
2283
Jouni Malinenff1d2762005-05-12 22:54:16 -04002284static struct net_device_stats *airo_get_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285{
2286 struct airo_info *local = dev->priv;
2287
Dan Williams3c304952006-04-15 12:26:18 -04002288 if (!test_bit(JOB_STATS, &local->jobs)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 /* Get stats out of the card if available */
2290 if (down_trylock(&local->sem) != 0) {
Dan Williams3c304952006-04-15 12:26:18 -04002291 set_bit(JOB_STATS, &local->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 wake_up_interruptible(&local->thr_wait);
2293 } else
2294 airo_read_stats(local);
2295 }
2296
2297 return &local->stats;
2298}
2299
2300static void airo_set_promisc(struct airo_info *ai) {
2301 Cmd cmd;
2302 Resp rsp;
2303
2304 memset(&cmd, 0, sizeof(cmd));
2305 cmd.cmd=CMD_SETMODE;
Dan Williams3c304952006-04-15 12:26:18 -04002306 clear_bit(JOB_PROMISC, &ai->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
2308 issuecommand(ai, &cmd, &rsp);
2309 up(&ai->sem);
2310}
2311
2312static void airo_set_multicast_list(struct net_device *dev) {
2313 struct airo_info *ai = dev->priv;
2314
2315 if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
2316 change_bit(FLAG_PROMISC, &ai->flags);
2317 if (down_trylock(&ai->sem) != 0) {
Dan Williams3c304952006-04-15 12:26:18 -04002318 set_bit(JOB_PROMISC, &ai->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 wake_up_interruptible(&ai->thr_wait);
2320 } else
2321 airo_set_promisc(ai);
2322 }
2323
2324 if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) {
2325 /* Turn on multicast. (Should be already setup...) */
2326 }
2327}
2328
2329static int airo_set_mac_address(struct net_device *dev, void *p)
2330{
2331 struct airo_info *ai = dev->priv;
2332 struct sockaddr *addr = p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333
2334 readConfigRid(ai, 1);
2335 memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
2336 set_bit (FLAG_COMMIT, &ai->flags);
2337 disable_MAC(ai, 1);
2338 writeConfigRid (ai, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02002339 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 memcpy (ai->dev->dev_addr, addr->sa_data, dev->addr_len);
2341 if (ai->wifidev)
2342 memcpy (ai->wifidev->dev_addr, addr->sa_data, dev->addr_len);
2343 return 0;
2344}
2345
2346static int airo_change_mtu(struct net_device *dev, int new_mtu)
2347{
2348 if ((new_mtu < 68) || (new_mtu > 2400))
2349 return -EINVAL;
2350 dev->mtu = new_mtu;
2351 return 0;
2352}
2353
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01002354static LIST_HEAD(airo_devices);
2355
2356static void add_airo_dev(struct airo_info *ai)
2357{
2358 /* Upper layers already keep track of PCI devices,
2359 * so we only need to remember our non-PCI cards. */
2360 if (!ai->pci)
2361 list_add_tail(&ai->dev_list, &airo_devices);
2362}
2363
2364static void del_airo_dev(struct airo_info *ai)
2365{
2366 if (!ai->pci)
2367 list_del(&ai->dev_list);
2368}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369
2370static int airo_close(struct net_device *dev) {
2371 struct airo_info *ai = dev->priv;
2372
2373 netif_stop_queue(dev);
2374
2375 if (ai->wifidev != dev) {
2376#ifdef POWER_ON_DOWN
2377 /* Shut power to the card. The idea is that the user can save
2378 * power when he doesn't need the card with "ifconfig down".
2379 * That's the method that is most friendly towards the network
2380 * stack (i.e. the network stack won't try to broadcast
2381 * anything on the interface and routes are gone. Jean II */
2382 set_bit(FLAG_RADIO_DOWN, &ai->flags);
2383 disable_MAC(ai, 1);
2384#endif
2385 disable_interrupts( ai );
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02002386
2387 free_irq(dev->irq, dev);
2388
2389 set_bit(JOB_DIE, &ai->jobs);
2390 kthread_stop(ai->airo_thread_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 }
2392 return 0;
2393}
2394
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395void stop_airo_card( struct net_device *dev, int freeres )
2396{
2397 struct airo_info *ai = dev->priv;
2398
2399 set_bit(FLAG_RADIO_DOWN, &ai->flags);
2400 disable_MAC(ai, 1);
2401 disable_interrupts(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 takedown_proc_entry( dev, ai );
2403 if (test_bit(FLAG_REGISTERED, &ai->flags)) {
2404 unregister_netdev( dev );
2405 if (ai->wifidev) {
2406 unregister_netdev(ai->wifidev);
2407 free_netdev(ai->wifidev);
2408 ai->wifidev = NULL;
2409 }
2410 clear_bit(FLAG_REGISTERED, &ai->flags);
2411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 /*
2413 * Clean out tx queue
2414 */
David S. Millerb03efcf2005-07-08 14:57:23 -07002415 if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 struct sk_buff *skb = NULL;
2417 for (;(skb = skb_dequeue(&ai->txq));)
2418 dev_kfree_skb(skb);
2419 }
2420
Dan Williams9e75af32006-03-16 13:46:29 -05002421 airo_networks_free (ai);
2422
Jesper Juhlb4558ea2005-10-28 16:53:13 -04002423 kfree(ai->flash);
2424 kfree(ai->rssi);
2425 kfree(ai->APList);
2426 kfree(ai->SSID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 if (freeres) {
2428 /* PCMCIA frees this stuff, so only for PCI and ISA */
2429 release_region( dev->base_addr, 64 );
2430 if (test_bit(FLAG_MPI, &ai->flags)) {
2431 if (ai->pci)
2432 mpi_unmap_card(ai->pci);
2433 if (ai->pcimem)
2434 iounmap(ai->pcimem);
2435 if (ai->pciaux)
2436 iounmap(ai->pciaux);
2437 pci_free_consistent(ai->pci, PCI_SHARED_LEN,
2438 ai->shared, ai->shared_dma);
2439 }
2440 }
Herbert Xuf12cc202006-08-22 20:36:13 +10002441 crypto_free_cipher(ai->tfm);
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01002442 del_airo_dev(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 free_netdev( dev );
2444}
2445
2446EXPORT_SYMBOL(stop_airo_card);
2447
Stephen Hemmingerb95cce32007-09-26 22:13:38 -07002448static int wll_header_parse(const struct sk_buff *skb, unsigned char *haddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449{
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -07002450 memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 return ETH_ALEN;
2452}
2453
2454static void mpi_unmap_card(struct pci_dev *pci)
2455{
2456 unsigned long mem_start = pci_resource_start(pci, 1);
2457 unsigned long mem_len = pci_resource_len(pci, 1);
2458 unsigned long aux_start = pci_resource_start(pci, 2);
2459 unsigned long aux_len = AUXMEMSIZE;
2460
2461 release_mem_region(aux_start, aux_len);
2462 release_mem_region(mem_start, mem_len);
2463}
2464
2465/*************************************************************
2466 * This routine assumes that descriptors have been setup .
2467 * Run at insmod time or after reset when the decriptors
2468 * have been initialized . Returns 0 if all is well nz
2469 * otherwise . Does not allocate memory but sets up card
2470 * using previously allocated descriptors.
2471 */
2472static int mpi_init_descriptors (struct airo_info *ai)
2473{
2474 Cmd cmd;
2475 Resp rsp;
2476 int i;
2477 int rc = SUCCESS;
2478
2479 /* Alloc card RX descriptors */
2480 netif_stop_queue(ai->dev);
2481
2482 memset(&rsp,0,sizeof(rsp));
2483 memset(&cmd,0,sizeof(cmd));
2484
2485 cmd.cmd = CMD_ALLOCATEAUX;
2486 cmd.parm0 = FID_RX;
2487 cmd.parm1 = (ai->rxfids[0].card_ram_off - ai->pciaux);
2488 cmd.parm2 = MPI_MAX_FIDS;
2489 rc=issuecommand(ai, &cmd, &rsp);
2490 if (rc != SUCCESS) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002491 airo_print_err(ai->dev->name, "Couldn't allocate RX FID");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 return rc;
2493 }
2494
2495 for (i=0; i<MPI_MAX_FIDS; i++) {
2496 memcpy_toio(ai->rxfids[i].card_ram_off,
2497 &ai->rxfids[i].rx_desc, sizeof(RxFid));
2498 }
2499
2500 /* Alloc card TX descriptors */
2501
2502 memset(&rsp,0,sizeof(rsp));
2503 memset(&cmd,0,sizeof(cmd));
2504
2505 cmd.cmd = CMD_ALLOCATEAUX;
2506 cmd.parm0 = FID_TX;
2507 cmd.parm1 = (ai->txfids[0].card_ram_off - ai->pciaux);
2508 cmd.parm2 = MPI_MAX_FIDS;
2509
2510 for (i=0; i<MPI_MAX_FIDS; i++) {
2511 ai->txfids[i].tx_desc.valid = 1;
2512 memcpy_toio(ai->txfids[i].card_ram_off,
2513 &ai->txfids[i].tx_desc, sizeof(TxFid));
2514 }
2515 ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
2516
2517 rc=issuecommand(ai, &cmd, &rsp);
2518 if (rc != SUCCESS) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002519 airo_print_err(ai->dev->name, "Couldn't allocate TX FID");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 return rc;
2521 }
2522
2523 /* Alloc card Rid descriptor */
2524 memset(&rsp,0,sizeof(rsp));
2525 memset(&cmd,0,sizeof(cmd));
2526
2527 cmd.cmd = CMD_ALLOCATEAUX;
2528 cmd.parm0 = RID_RW;
2529 cmd.parm1 = (ai->config_desc.card_ram_off - ai->pciaux);
2530 cmd.parm2 = 1; /* Magic number... */
2531 rc=issuecommand(ai, &cmd, &rsp);
2532 if (rc != SUCCESS) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002533 airo_print_err(ai->dev->name, "Couldn't allocate RID");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 return rc;
2535 }
2536
2537 memcpy_toio(ai->config_desc.card_ram_off,
2538 &ai->config_desc.rid_desc, sizeof(Rid));
2539
2540 return rc;
2541}
2542
2543/*
2544 * We are setting up three things here:
2545 * 1) Map AUX memory for descriptors: Rid, TxFid, or RxFid.
2546 * 2) Map PCI memory for issueing commands.
2547 * 3) Allocate memory (shared) to send and receive ethernet frames.
2548 */
Michal Schmidt1138c372007-06-29 15:33:41 +02002549static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550{
2551 unsigned long mem_start, mem_len, aux_start, aux_len;
2552 int rc = -1;
2553 int i;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002554 dma_addr_t busaddroff;
2555 unsigned char *vpackoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 unsigned char __iomem *pciaddroff;
2557
2558 mem_start = pci_resource_start(pci, 1);
2559 mem_len = pci_resource_len(pci, 1);
2560 aux_start = pci_resource_start(pci, 2);
2561 aux_len = AUXMEMSIZE;
2562
Michal Schmidt1138c372007-06-29 15:33:41 +02002563 if (!request_mem_region(mem_start, mem_len, DRV_NAME)) {
2564 airo_print_err("", "Couldn't get region %x[%x]",
2565 (int)mem_start, (int)mem_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 goto out;
2567 }
Michal Schmidt1138c372007-06-29 15:33:41 +02002568 if (!request_mem_region(aux_start, aux_len, DRV_NAME)) {
2569 airo_print_err("", "Couldn't get region %x[%x]",
2570 (int)aux_start, (int)aux_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 goto free_region1;
2572 }
2573
2574 ai->pcimem = ioremap(mem_start, mem_len);
2575 if (!ai->pcimem) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002576 airo_print_err("", "Couldn't map region %x[%x]",
2577 (int)mem_start, (int)mem_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 goto free_region2;
2579 }
2580 ai->pciaux = ioremap(aux_start, aux_len);
2581 if (!ai->pciaux) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002582 airo_print_err("", "Couldn't map region %x[%x]",
2583 (int)aux_start, (int)aux_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 goto free_memmap;
2585 }
2586
2587 /* Reserve PKTSIZE for each fid and 2K for the Rids */
2588 ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma);
2589 if (!ai->shared) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002590 airo_print_err("", "Couldn't alloc_consistent %d",
2591 PCI_SHARED_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 goto free_auxmap;
2593 }
2594
2595 /*
2596 * Setup descriptor RX, TX, CONFIG
2597 */
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002598 busaddroff = ai->shared_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 pciaddroff = ai->pciaux + AUX_OFFSET;
2600 vpackoff = ai->shared;
2601
2602 /* RX descriptor setup */
2603 for(i = 0; i < MPI_MAX_FIDS; i++) {
2604 ai->rxfids[i].pending = 0;
2605 ai->rxfids[i].card_ram_off = pciaddroff;
2606 ai->rxfids[i].virtual_host_addr = vpackoff;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002607 ai->rxfids[i].rx_desc.host_addr = busaddroff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 ai->rxfids[i].rx_desc.valid = 1;
2609 ai->rxfids[i].rx_desc.len = PKTSIZE;
2610 ai->rxfids[i].rx_desc.rdy = 0;
2611
2612 pciaddroff += sizeof(RxFid);
2613 busaddroff += PKTSIZE;
2614 vpackoff += PKTSIZE;
2615 }
2616
2617 /* TX descriptor setup */
2618 for(i = 0; i < MPI_MAX_FIDS; i++) {
2619 ai->txfids[i].card_ram_off = pciaddroff;
2620 ai->txfids[i].virtual_host_addr = vpackoff;
2621 ai->txfids[i].tx_desc.valid = 1;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002622 ai->txfids[i].tx_desc.host_addr = busaddroff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 memcpy(ai->txfids[i].virtual_host_addr,
2624 &wifictlhdr8023, sizeof(wifictlhdr8023));
2625
2626 pciaddroff += sizeof(TxFid);
2627 busaddroff += PKTSIZE;
2628 vpackoff += PKTSIZE;
2629 }
2630 ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
2631
2632 /* Rid descriptor setup */
2633 ai->config_desc.card_ram_off = pciaddroff;
2634 ai->config_desc.virtual_host_addr = vpackoff;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002635 ai->config_desc.rid_desc.host_addr = busaddroff;
2636 ai->ridbus = busaddroff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 ai->config_desc.rid_desc.rid = 0;
2638 ai->config_desc.rid_desc.len = RIDSIZE;
2639 ai->config_desc.rid_desc.valid = 1;
2640 pciaddroff += sizeof(Rid);
2641 busaddroff += RIDSIZE;
2642 vpackoff += RIDSIZE;
2643
2644 /* Tell card about descriptors */
2645 if (mpi_init_descriptors (ai) != SUCCESS)
2646 goto free_shared;
2647
2648 return 0;
2649 free_shared:
2650 pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
2651 free_auxmap:
2652 iounmap(ai->pciaux);
2653 free_memmap:
2654 iounmap(ai->pcimem);
2655 free_region2:
2656 release_mem_region(aux_start, aux_len);
2657 free_region1:
2658 release_mem_region(mem_start, mem_len);
2659 out:
2660 return rc;
2661}
2662
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07002663static const struct header_ops airo_header_ops = {
2664 .parse = wll_header_parse,
2665};
2666
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667static void wifi_setup(struct net_device *dev)
2668{
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07002669 dev->header_ops = &airo_header_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 dev->hard_start_xmit = &airo_start_xmit11;
2671 dev->get_stats = &airo_get_stats;
2672 dev->set_mac_address = &airo_set_mac_address;
2673 dev->do_ioctl = &airo_ioctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 dev->wireless_handlers = &airo_handler_def;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 dev->change_mtu = &airo_change_mtu;
2676 dev->open = &airo_open;
2677 dev->stop = &airo_close;
2678
2679 dev->type = ARPHRD_IEEE80211;
2680 dev->hard_header_len = ETH_HLEN;
Dan Williams15db2762006-03-16 13:46:27 -05002681 dev->mtu = AIRO_DEF_MTU;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 dev->addr_len = ETH_ALEN;
2683 dev->tx_queue_len = 100;
2684
2685 memset(dev->broadcast,0xFF, ETH_ALEN);
2686
2687 dev->flags = IFF_BROADCAST|IFF_MULTICAST;
2688}
2689
2690static struct net_device *init_wifidev(struct airo_info *ai,
2691 struct net_device *ethdev)
2692{
2693 int err;
2694 struct net_device *dev = alloc_netdev(0, "wifi%d", wifi_setup);
2695 if (!dev)
2696 return NULL;
2697 dev->priv = ethdev->priv;
2698 dev->irq = ethdev->irq;
2699 dev->base_addr = ethdev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 dev->wireless_data = ethdev->wireless_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len);
2702 err = register_netdev(dev);
2703 if (err<0) {
2704 free_netdev(dev);
2705 return NULL;
2706 }
2707 return dev;
2708}
2709
Jouni Malinenff1d2762005-05-12 22:54:16 -04002710static int reset_card( struct net_device *dev , int lock) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 struct airo_info *ai = dev->priv;
2712
2713 if (lock && down_interruptible(&ai->sem))
2714 return -1;
2715 waitbusy (ai);
2716 OUT4500(ai,COMMAND,CMD_SOFTRESET);
2717 msleep(200);
2718 waitbusy (ai);
2719 msleep(200);
2720 if (lock)
2721 up(&ai->sem);
2722 return 0;
2723}
2724
Dan Williams3c304952006-04-15 12:26:18 -04002725#define AIRO_MAX_NETWORK_COUNT 64
Dan Williams9e75af32006-03-16 13:46:29 -05002726static int airo_networks_allocate(struct airo_info *ai)
2727{
2728 if (ai->networks)
2729 return 0;
2730
2731 ai->networks =
Dan Williams3c304952006-04-15 12:26:18 -04002732 kzalloc(AIRO_MAX_NETWORK_COUNT * sizeof(BSSListElement),
Dan Williams9e75af32006-03-16 13:46:29 -05002733 GFP_KERNEL);
2734 if (!ai->networks) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002735 airo_print_warn("", "Out of memory allocating beacons");
Dan Williams9e75af32006-03-16 13:46:29 -05002736 return -ENOMEM;
2737 }
2738
2739 return 0;
2740}
2741
2742static void airo_networks_free(struct airo_info *ai)
2743{
Dan Williams9e75af32006-03-16 13:46:29 -05002744 kfree(ai->networks);
2745 ai->networks = NULL;
2746}
2747
2748static void airo_networks_initialize(struct airo_info *ai)
2749{
2750 int i;
2751
2752 INIT_LIST_HEAD(&ai->network_free_list);
2753 INIT_LIST_HEAD(&ai->network_list);
Dan Williams3c304952006-04-15 12:26:18 -04002754 for (i = 0; i < AIRO_MAX_NETWORK_COUNT; i++)
Dan Williams9e75af32006-03-16 13:46:29 -05002755 list_add_tail(&ai->networks[i].list,
2756 &ai->network_free_list);
2757}
2758
Dan Williams3c304952006-04-15 12:26:18 -04002759static int airo_test_wpa_capable(struct airo_info *ai)
2760{
2761 int status;
2762 CapabilityRid cap_rid;
Dan Williams3c304952006-04-15 12:26:18 -04002763
2764 status = readCapabilityRid(ai, &cap_rid, 1);
2765 if (status != SUCCESS) return 0;
2766
2767 /* Only firmware versions 5.30.17 or better can do WPA */
Al Viro56d81bd2007-12-20 17:18:35 -05002768 if (le16_to_cpu(cap_rid.softVer) > 0x530
2769 || (le16_to_cpu(cap_rid.softVer) == 0x530
2770 && le16_to_cpu(cap_rid.softSubVer) >= 17)) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002771 airo_print_info("", "WPA is supported.");
Dan Williams3c304952006-04-15 12:26:18 -04002772 return 1;
2773 }
2774
2775 /* No WPA support */
Michal Schmidt1138c372007-06-29 15:33:41 +02002776 airo_print_info("", "WPA unsupported (only firmware versions 5.30.17"
Dan Williams3c304952006-04-15 12:26:18 -04002777 " and greater support WPA. Detected %s)", cap_rid.prodVer);
2778 return 0;
2779}
2780
Jouni Malinenff1d2762005-05-12 22:54:16 -04002781static struct net_device *_init_airo_card( unsigned short irq, int port,
2782 int is_pcmcia, struct pci_dev *pci,
2783 struct device *dmdev )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784{
2785 struct net_device *dev;
2786 struct airo_info *ai;
2787 int i, rc;
Joe Perches0795af52007-10-03 17:59:30 -07002788 DECLARE_MAC_BUF(mac);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789
2790 /* Create the network device object. */
Michal Schmidt1138c372007-06-29 15:33:41 +02002791 dev = alloc_netdev(sizeof(*ai), "", ether_setup);
2792 if (!dev) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002793 airo_print_err("", "Couldn't alloc_etherdev");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 }
2796
2797 ai = dev->priv;
2798 ai->wifidev = NULL;
Michal Schmidtfb038c22007-06-29 15:33:52 +02002799 ai->flags = 1 << FLAG_RADIO_DOWN;
Dan Williams3c304952006-04-15 12:26:18 -04002800 ai->jobs = 0;
Dan Williams934d8bf2006-03-16 13:46:23 -05002801 ai->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002803 airo_print_dbg("", "Found an MPI350 card");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 set_bit(FLAG_MPI, &ai->flags);
2805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 spin_lock_init(&ai->aux_lock);
2807 sema_init(&ai->sem, 1);
2808 ai->config.len = 0;
2809 ai->pci = pci;
2810 init_waitqueue_head (&ai->thr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 ai->tfm = NULL;
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01002812 add_airo_dev(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813
Dan Williams9e75af32006-03-16 13:46:29 -05002814 if (airo_networks_allocate (ai))
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02002815 goto err_out_free;
Dan Williams9e75af32006-03-16 13:46:29 -05002816 airo_networks_initialize (ai);
2817
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 /* The Airo-specific entries in the device structure. */
2819 if (test_bit(FLAG_MPI,&ai->flags)) {
2820 skb_queue_head_init (&ai->txq);
2821 dev->hard_start_xmit = &mpi_start_xmit;
2822 } else
2823 dev->hard_start_xmit = &airo_start_xmit;
2824 dev->get_stats = &airo_get_stats;
2825 dev->set_multicast_list = &airo_set_multicast_list;
2826 dev->set_mac_address = &airo_set_mac_address;
2827 dev->do_ioctl = &airo_ioctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 dev->wireless_handlers = &airo_handler_def;
2829 ai->wireless_data.spy_data = &ai->spy_data;
2830 dev->wireless_data = &ai->wireless_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 dev->change_mtu = &airo_change_mtu;
2832 dev->open = &airo_open;
2833 dev->stop = &airo_close;
2834 dev->irq = irq;
2835 dev->base_addr = port;
2836
2837 SET_NETDEV_DEV(dev, dmdev);
2838
Matthieu CASTET1d97f382005-12-01 02:35:26 -05002839 reset_card (dev, 1);
2840 msleep(400);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 if (!is_pcmcia) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002843 if (!request_region(dev->base_addr, 64, DRV_NAME)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 rc = -EBUSY;
Dan Williams934d8bf2006-03-16 13:46:23 -05002845 airo_print_err(dev->name, "Couldn't request region");
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02002846 goto err_out_nets;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 }
2848 }
2849
2850 if (test_bit(FLAG_MPI,&ai->flags)) {
Michal Schmidt1138c372007-06-29 15:33:41 +02002851 if (mpi_map_card(ai, pci)) {
2852 airo_print_err("", "Could not map memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 goto err_out_res;
2854 }
2855 }
2856
2857 if (probe) {
2858 if ( setup_card( ai, dev->dev_addr, 1 ) != SUCCESS ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002859 airo_print_err(dev->name, "MAC could not be enabled" );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 rc = -EIO;
2861 goto err_out_map;
2862 }
2863 } else if (!test_bit(FLAG_MPI,&ai->flags)) {
2864 ai->bap_read = fast_bap_read;
2865 set_bit(FLAG_FLASHING, &ai->flags);
2866 }
2867
Dan Williams3c304952006-04-15 12:26:18 -04002868 /* Test for WPA support */
2869 if (airo_test_wpa_capable(ai)) {
2870 set_bit(FLAG_WPA_CAPABLE, &ai->flags);
2871 ai->bssListFirst = RID_WPA_BSSLISTFIRST;
2872 ai->bssListNext = RID_WPA_BSSLISTNEXT;
2873 ai->bssListRidLen = sizeof(BSSListRid);
2874 } else {
2875 ai->bssListFirst = RID_BSSLISTFIRST;
2876 ai->bssListNext = RID_BSSLISTNEXT;
2877 ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra);
2878 }
2879
Michal Schmidt1138c372007-06-29 15:33:41 +02002880 strcpy(dev->name, "eth%d");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 rc = register_netdev(dev);
2882 if (rc) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002883 airo_print_err(dev->name, "Couldn't register_netdev");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 goto err_out_map;
2885 }
2886 ai->wifidev = init_wifidev(ai, dev);
Florin Malita431aca52006-10-10 16:46:30 -04002887 if (!ai->wifidev)
2888 goto err_out_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889
2890 set_bit(FLAG_REGISTERED,&ai->flags);
Joe Perches0795af52007-10-03 17:59:30 -07002891 airo_print_info(dev->name, "MAC enabled %s",
2892 print_mac(mac, dev->dev_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893
2894 /* Allocate the transmit buffers */
2895 if (probe && !test_bit(FLAG_MPI,&ai->flags))
2896 for( i = 0; i < MAX_FIDS; i++ )
Dan Williams15db2762006-03-16 13:46:27 -05002897 ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898
Florin Malita431aca52006-10-10 16:46:30 -04002899 if (setup_proc_entry(dev, dev->priv) < 0)
2900 goto err_out_wifi;
2901
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 return dev;
2903
Florin Malita431aca52006-10-10 16:46:30 -04002904err_out_wifi:
2905 unregister_netdev(ai->wifidev);
2906 free_netdev(ai->wifidev);
2907err_out_reg:
2908 unregister_netdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909err_out_map:
2910 if (test_bit(FLAG_MPI,&ai->flags) && pci) {
2911 pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
2912 iounmap(ai->pciaux);
2913 iounmap(ai->pcimem);
2914 mpi_unmap_card(ai->pci);
2915 }
2916err_out_res:
2917 if (!is_pcmcia)
2918 release_region( dev->base_addr, 64 );
Michal Schmidt4d881902007-03-16 12:42:59 +01002919err_out_nets:
2920 airo_networks_free(ai);
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01002921 del_airo_dev(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922err_out_free:
2923 free_netdev(dev);
2924 return NULL;
2925}
2926
2927struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia,
2928 struct device *dmdev)
2929{
2930 return _init_airo_card ( irq, port, is_pcmcia, NULL, dmdev);
2931}
2932
2933EXPORT_SYMBOL(init_airo_card);
2934
2935static int waitbusy (struct airo_info *ai) {
2936 int delay = 0;
2937 while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) & (delay < 10000)) {
2938 udelay (10);
2939 if ((++delay % 20) == 0)
2940 OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
2941 }
2942 return delay < 10000;
2943}
2944
2945int reset_airo_card( struct net_device *dev )
2946{
2947 int i;
2948 struct airo_info *ai = dev->priv;
Joe Perches0795af52007-10-03 17:59:30 -07002949 DECLARE_MAC_BUF(mac);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950
2951 if (reset_card (dev, 1))
2952 return -1;
2953
2954 if ( setup_card(ai, dev->dev_addr, 1 ) != SUCCESS ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002955 airo_print_err(dev->name, "MAC could not be enabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 return -1;
2957 }
Joe Perches0795af52007-10-03 17:59:30 -07002958 airo_print_info(dev->name, "MAC enabled %s",
2959 print_mac(mac, dev->dev_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 /* Allocate the transmit buffers if needed */
2961 if (!test_bit(FLAG_MPI,&ai->flags))
2962 for( i = 0; i < MAX_FIDS; i++ )
Dan Williams15db2762006-03-16 13:46:27 -05002963 ai->fids[i] = transmit_allocate (ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964
2965 enable_interrupts( ai );
2966 netif_wake_queue(dev);
2967 return 0;
2968}
2969
2970EXPORT_SYMBOL(reset_airo_card);
2971
2972static void airo_send_event(struct net_device *dev) {
2973 struct airo_info *ai = dev->priv;
2974 union iwreq_data wrqu;
2975 StatusRid status_rid;
2976
Dan Williams3c304952006-04-15 12:26:18 -04002977 clear_bit(JOB_EVENT, &ai->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
2979 up(&ai->sem);
2980 wrqu.data.length = 0;
2981 wrqu.data.flags = 0;
2982 memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN);
2983 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
2984
2985 /* Send event to user space */
2986 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
2987}
2988
Dan Williams9e75af32006-03-16 13:46:29 -05002989static void airo_process_scan_results (struct airo_info *ai) {
2990 union iwreq_data wrqu;
Dan Williams3c304952006-04-15 12:26:18 -04002991 BSSListRid bss;
Dan Williams9e75af32006-03-16 13:46:29 -05002992 int rc;
2993 BSSListElement * loop_net;
2994 BSSListElement * tmp_net;
2995
2996 /* Blow away current list of scan results */
2997 list_for_each_entry_safe (loop_net, tmp_net, &ai->network_list, list) {
2998 list_move_tail (&loop_net->list, &ai->network_free_list);
2999 /* Don't blow away ->list, just BSS data */
3000 memset (loop_net, 0, sizeof (loop_net->bss));
3001 }
3002
3003 /* Try to read the first entry of the scan result */
Dan Williams3c304952006-04-15 12:26:18 -04003004 rc = PC4500_readrid(ai, ai->bssListFirst, &bss, ai->bssListRidLen, 0);
Al Viro17e70492007-12-19 18:56:37 -05003005 if((rc) || (bss.index == cpu_to_le16(0xffff))) {
Dan Williams9e75af32006-03-16 13:46:29 -05003006 /* No scan results */
3007 goto out;
3008 }
3009
3010 /* Read and parse all entries */
3011 tmp_net = NULL;
Al Viro17e70492007-12-19 18:56:37 -05003012 while((!rc) && (bss.index != cpu_to_le16(0xffff))) {
Dan Williams9e75af32006-03-16 13:46:29 -05003013 /* Grab a network off the free list */
3014 if (!list_empty(&ai->network_free_list)) {
3015 tmp_net = list_entry(ai->network_free_list.next,
3016 BSSListElement, list);
3017 list_del(ai->network_free_list.next);
3018 }
3019
3020 if (tmp_net != NULL) {
Dan Williams3c304952006-04-15 12:26:18 -04003021 memcpy(tmp_net, &bss, sizeof(tmp_net->bss));
Dan Williams9e75af32006-03-16 13:46:29 -05003022 list_add_tail(&tmp_net->list, &ai->network_list);
3023 tmp_net = NULL;
3024 }
3025
3026 /* Read next entry */
Dan Williams3c304952006-04-15 12:26:18 -04003027 rc = PC4500_readrid(ai, ai->bssListNext,
3028 &bss, ai->bssListRidLen, 0);
Dan Williams9e75af32006-03-16 13:46:29 -05003029 }
3030
3031out:
3032 ai->scan_timeout = 0;
Dan Williams3c304952006-04-15 12:26:18 -04003033 clear_bit(JOB_SCAN_RESULTS, &ai->jobs);
Dan Williams9e75af32006-03-16 13:46:29 -05003034 up(&ai->sem);
3035
3036 /* Send an empty event to user space.
3037 * We don't send the received data on
3038 * the event because it would require
3039 * us to do complex transcoding, and
3040 * we want to minimise the work done in
3041 * the irq handler. Use a request to
3042 * extract the data - Jean II */
3043 wrqu.data.length = 0;
3044 wrqu.data.flags = 0;
3045 wireless_send_event(ai->dev, SIOCGIWSCAN, &wrqu, NULL);
3046}
3047
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048static int airo_thread(void *data) {
3049 struct net_device *dev = data;
3050 struct airo_info *ai = dev->priv;
3051 int locked;
Rafael J. Wysocki83144182007-07-17 04:03:35 -07003052
3053 set_freezable();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 while(1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 /* make swsusp happy with our thread */
Christoph Lameter3e1d1d22005-06-24 23:13:50 -07003056 try_to_freeze();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057
Dan Williams3c304952006-04-15 12:26:18 -04003058 if (test_bit(JOB_DIE, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 break;
3060
Dan Williams3c304952006-04-15 12:26:18 -04003061 if (ai->jobs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 locked = down_interruptible(&ai->sem);
3063 } else {
3064 wait_queue_t wait;
3065
3066 init_waitqueue_entry(&wait, current);
3067 add_wait_queue(&ai->thr_wait, &wait);
3068 for (;;) {
3069 set_current_state(TASK_INTERRUPTIBLE);
Dan Williams3c304952006-04-15 12:26:18 -04003070 if (ai->jobs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 break;
Dan Williams9e75af32006-03-16 13:46:29 -05003072 if (ai->expires || ai->scan_timeout) {
3073 if (ai->scan_timeout &&
3074 time_after_eq(jiffies,ai->scan_timeout)){
Dan Williams3c304952006-04-15 12:26:18 -04003075 set_bit(JOB_SCAN_RESULTS, &ai->jobs);
Dan Williams9e75af32006-03-16 13:46:29 -05003076 break;
3077 } else if (ai->expires &&
3078 time_after_eq(jiffies,ai->expires)){
Dan Williams3c304952006-04-15 12:26:18 -04003079 set_bit(JOB_AUTOWEP, &ai->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 break;
3081 }
Dave Kleikamp5bb85f12006-10-10 14:45:46 -07003082 if (!kthread_should_stop() &&
3083 !freezing(current)) {
Dan Williams9e75af32006-03-16 13:46:29 -05003084 unsigned long wake_at;
3085 if (!ai->expires || !ai->scan_timeout) {
3086 wake_at = max(ai->expires,
3087 ai->scan_timeout);
3088 } else {
3089 wake_at = min(ai->expires,
3090 ai->scan_timeout);
3091 }
3092 schedule_timeout(wake_at - jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 continue;
3094 }
Dave Kleikamp5bb85f12006-10-10 14:45:46 -07003095 } else if (!kthread_should_stop() &&
3096 !freezing(current)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 schedule();
3098 continue;
3099 }
3100 break;
3101 }
3102 current->state = TASK_RUNNING;
3103 remove_wait_queue(&ai->thr_wait, &wait);
3104 locked = 1;
3105 }
3106
3107 if (locked)
3108 continue;
3109
Dan Williams3c304952006-04-15 12:26:18 -04003110 if (test_bit(JOB_DIE, &ai->jobs)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 up(&ai->sem);
3112 break;
3113 }
3114
Pavel Machekca078ba2005-09-03 15:56:57 -07003115 if (ai->power.event || test_bit(FLAG_FLASHING, &ai->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 up(&ai->sem);
3117 continue;
3118 }
3119
Dan Williams3c304952006-04-15 12:26:18 -04003120 if (test_bit(JOB_XMIT, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 airo_end_xmit(dev);
Dan Williams3c304952006-04-15 12:26:18 -04003122 else if (test_bit(JOB_XMIT11, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 airo_end_xmit11(dev);
Dan Williams3c304952006-04-15 12:26:18 -04003124 else if (test_bit(JOB_STATS, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 airo_read_stats(ai);
Dan Williams3c304952006-04-15 12:26:18 -04003126 else if (test_bit(JOB_WSTATS, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 airo_read_wireless_stats(ai);
Dan Williams3c304952006-04-15 12:26:18 -04003128 else if (test_bit(JOB_PROMISC, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 airo_set_promisc(ai);
Dan Williams3c304952006-04-15 12:26:18 -04003130 else if (test_bit(JOB_MIC, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 micinit(ai);
Dan Williams3c304952006-04-15 12:26:18 -04003132 else if (test_bit(JOB_EVENT, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 airo_send_event(dev);
Dan Williams3c304952006-04-15 12:26:18 -04003134 else if (test_bit(JOB_AUTOWEP, &ai->jobs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 timer_func(dev);
Dan Williams3c304952006-04-15 12:26:18 -04003136 else if (test_bit(JOB_SCAN_RESULTS, &ai->jobs))
Dan Williams9e75af32006-03-16 13:46:29 -05003137 airo_process_scan_results(ai);
3138 else /* Shouldn't get here, but we make sure to unlock */
3139 up(&ai->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 }
Sukadev Bhattiprolu3b4c7d642006-08-14 23:12:03 -07003141
3142 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143}
3144
Al Viro0300b332007-12-19 22:38:33 -05003145static int header_len(__le16 ctl)
3146{
3147 u16 fc = le16_to_cpu(ctl);
3148 switch (fc & 0xc) {
3149 case 4:
3150 if ((fc & 0xe0) == 0xc0)
3151 return 10; /* one-address control packet */
3152 return 16; /* two-address control packet */
3153 case 8:
3154 if ((fc & 0x300) == 0x300)
3155 return 30; /* WDS packet */
3156 }
3157 return 24;
3158}
3159
Jeff Garzik28fc1f52007-10-29 05:46:16 -04003160static irqreturn_t airo_interrupt(int irq, void *dev_id)
3161{
3162 struct net_device *dev = dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 u16 status;
3164 u16 fid;
3165 struct airo_info *apriv = dev->priv;
3166 u16 savedInterrupts = 0;
3167 int handled = 0;
3168
3169 if (!netif_device_present(dev))
3170 return IRQ_NONE;
3171
3172 for (;;) {
3173 status = IN4500( apriv, EVSTAT );
3174 if ( !(status & STATUS_INTS) || status == 0xffff ) break;
3175
3176 handled = 1;
3177
3178 if ( status & EV_AWAKE ) {
3179 OUT4500( apriv, EVACK, EV_AWAKE );
3180 OUT4500( apriv, EVACK, EV_AWAKE );
3181 }
3182
3183 if (!savedInterrupts) {
3184 savedInterrupts = IN4500( apriv, EVINTEN );
3185 OUT4500( apriv, EVINTEN, 0 );
3186 }
3187
3188 if ( status & EV_MIC ) {
3189 OUT4500( apriv, EVACK, EV_MIC );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) {
Dan Williams3c304952006-04-15 12:26:18 -04003191 set_bit(JOB_MIC, &apriv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 wake_up_interruptible(&apriv->thr_wait);
3193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 }
3195 if ( status & EV_LINK ) {
3196 union iwreq_data wrqu;
Dan Williams6fcdf562006-03-31 15:08:46 -05003197 int scan_forceloss = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 /* The link status has changed, if you want to put a
3199 monitor hook in, do it here. (Remember that
3200 interrupts are still disabled!)
3201 */
3202 u16 newStatus = IN4500(apriv, LINKSTAT);
3203 OUT4500( apriv, EVACK, EV_LINK);
3204 /* Here is what newStatus means: */
3205#define NOBEACON 0x8000 /* Loss of sync - missed beacons */
3206#define MAXRETRIES 0x8001 /* Loss of sync - max retries */
3207#define MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/
3208#define FORCELOSS 0x8003 /* Loss of sync - host request */
3209#define TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */
3210#define DEAUTH 0x8100 /* Deauthentication (low byte is reason code) */
3211#define DISASS 0x8200 /* Disassociation (low byte is reason code) */
3212#define ASSFAIL 0x8400 /* Association failure (low byte is reason
3213 code) */
3214#define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason
3215 code) */
Dan Williams6fcdf562006-03-31 15:08:46 -05003216#define ASSOCIATED 0x0400 /* Associated */
3217#define REASSOCIATED 0x0600 /* Reassociated? Only on firmware >= 5.30.17 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218#define RC_RESERVED 0 /* Reserved return code */
3219#define RC_NOREASON 1 /* Unspecified reason */
3220#define RC_AUTHINV 2 /* Previous authentication invalid */
3221#define RC_DEAUTH 3 /* Deauthenticated because sending station is
3222 leaving */
3223#define RC_NOACT 4 /* Disassociated due to inactivity */
3224#define RC_MAXLOAD 5 /* Disassociated because AP is unable to handle
3225 all currently associated stations */
3226#define RC_BADCLASS2 6 /* Class 2 frame received from
3227 non-Authenticated station */
3228#define RC_BADCLASS3 7 /* Class 3 frame received from
3229 non-Associated station */
3230#define RC_STATLEAVE 8 /* Disassociated because sending station is
3231 leaving BSS */
3232#define RC_NOAUTH 9 /* Station requesting (Re)Association is not
3233 Authenticated with the responding station */
Dan Williams6fcdf562006-03-31 15:08:46 -05003234 if (newStatus == FORCELOSS && apriv->scan_timeout > 0)
3235 scan_forceloss = 1;
3236 if(newStatus == ASSOCIATED || newStatus == REASSOCIATED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 if (auto_wep)
3238 apriv->expires = 0;
Sukadev Bhattiprolu3b4c7d642006-08-14 23:12:03 -07003239 if (apriv->list_bss_task)
3240 wake_up_process(apriv->list_bss_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 set_bit(FLAG_UPDATE_UNI, &apriv->flags);
3242 set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
Dan Williams6fcdf562006-03-31 15:08:46 -05003243
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 if (down_trylock(&apriv->sem) != 0) {
Dan Williams3c304952006-04-15 12:26:18 -04003245 set_bit(JOB_EVENT, &apriv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 wake_up_interruptible(&apriv->thr_wait);
3247 } else
3248 airo_send_event(dev);
Dan Williams6fcdf562006-03-31 15:08:46 -05003249 } else if (!scan_forceloss) {
3250 if (auto_wep && !apriv->expires) {
3251 apriv->expires = RUN_AT(3*HZ);
3252 wake_up_interruptible(&apriv->thr_wait);
3253 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254
3255 /* Send event to user space */
Dan Williams6fcdf562006-03-31 15:08:46 -05003256 memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN);
3257 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL);
3259 }
3260 }
3261
3262 /* Check to see if there is something to receive */
3263 if ( status & EV_RX ) {
3264 struct sk_buff *skb = NULL;
Al Virob8c06bc2007-12-19 17:55:43 -05003265 __le16 fc, v;
3266 u16 len, hdrlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267#pragma pack(1)
3268 struct {
Al Viro593c2b92007-12-17 15:09:34 -05003269 __le16 status, len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 u8 rssi[2];
3271 u8 rate;
3272 u8 freq;
Al Viro593c2b92007-12-17 15:09:34 -05003273 __le16 tmp[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 } hdr;
3275#pragma pack()
3276 u16 gap;
Al Virob8c06bc2007-12-19 17:55:43 -05003277 __le16 tmpbuf[4];
3278 __le16 *buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279
3280 if (test_bit(FLAG_MPI,&apriv->flags)) {
3281 if (test_bit(FLAG_802_11, &apriv->flags))
3282 mpi_receive_802_11(apriv);
3283 else
3284 mpi_receive_802_3(apriv);
3285 OUT4500(apriv, EVACK, EV_RX);
3286 goto exitrx;
3287 }
3288
3289 fid = IN4500( apriv, RXFID );
3290
3291 /* Get the packet length */
3292 if (test_bit(FLAG_802_11, &apriv->flags)) {
3293 bap_setup (apriv, fid, 4, BAP0);
Al Virob8c06bc2007-12-19 17:55:43 -05003294 bap_read (apriv, (__le16*)&hdr, sizeof(hdr), BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 /* Bad CRC. Ignore packet */
3296 if (le16_to_cpu(hdr.status) & 2)
3297 hdr.len = 0;
3298 if (apriv->wifidev == NULL)
3299 hdr.len = 0;
3300 } else {
3301 bap_setup (apriv, fid, 0x36, BAP0);
Al Virob8c06bc2007-12-19 17:55:43 -05003302 bap_read (apriv, &hdr.len, 2, BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 }
3304 len = le16_to_cpu(hdr.len);
3305
Dan Williams15db2762006-03-16 13:46:27 -05003306 if (len > AIRO_DEF_MTU) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003307 airo_print_err(apriv->dev->name, "Bad size %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 goto badrx;
3309 }
3310 if (len == 0)
3311 goto badrx;
3312
3313 if (test_bit(FLAG_802_11, &apriv->flags)) {
Al Viro0300b332007-12-19 22:38:33 -05003314 bap_read (apriv, &fc, sizeof(fc), BAP0);
3315 hdrlen = header_len(fc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 } else
3317 hdrlen = ETH_ALEN * 2;
3318
3319 skb = dev_alloc_skb( len + hdrlen + 2 + 2 );
3320 if ( !skb ) {
3321 apriv->stats.rx_dropped++;
3322 goto badrx;
3323 }
3324 skb_reserve(skb, 2); /* This way the IP header is aligned */
Al Virob8c06bc2007-12-19 17:55:43 -05003325 buffer = (__le16*)skb_put (skb, len + hdrlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 if (test_bit(FLAG_802_11, &apriv->flags)) {
3327 buffer[0] = fc;
3328 bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
3329 if (hdrlen == 24)
3330 bap_read (apriv, tmpbuf, 6, BAP0);
3331
Al Virob8c06bc2007-12-19 17:55:43 -05003332 bap_read (apriv, &v, sizeof(v), BAP0);
3333 gap = le16_to_cpu(v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 if (gap) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003335 if (gap <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 bap_read (apriv, tmpbuf, gap, BAP0);
Dan Williams934d8bf2006-03-16 13:46:23 -05003337 } else {
3338 airo_print_err(apriv->dev->name, "gaplen too "
3339 "big. Problems will follow...");
3340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 }
3342 bap_read (apriv, buffer + hdrlen/2, len, BAP0);
3343 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 MICBuffer micbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 if (apriv->micstats.enabled) {
Al Virob8c06bc2007-12-19 17:55:43 -05003347 bap_read (apriv,(__le16*)&micbuf,sizeof(micbuf),BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 if (ntohs(micbuf.typelen) > 0x05DC)
3349 bap_setup (apriv, fid, 0x44, BAP0);
3350 else {
3351 if (len <= sizeof(micbuf))
3352 goto badmic;
3353
3354 len -= sizeof(micbuf);
3355 skb_trim (skb, len + hdrlen);
3356 }
3357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 bap_read(apriv,buffer+ETH_ALEN,len,BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
3360badmic:
3361 dev_kfree_skb_irq (skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362badrx:
3363 OUT4500( apriv, EVACK, EV_RX);
3364 goto exitrx;
3365 }
3366 }
3367#ifdef WIRELESS_SPY
3368 if (apriv->spy_data.spy_number > 0) {
3369 char *sa;
3370 struct iw_quality wstats;
3371 /* Prepare spy data : addr + qual */
3372 if (!test_bit(FLAG_802_11, &apriv->flags)) {
3373 sa = (char*)buffer + 6;
3374 bap_setup (apriv, fid, 8, BAP0);
Al Virob8c06bc2007-12-19 17:55:43 -05003375 bap_read (apriv, (__le16*)hdr.rssi, 2, BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 } else
3377 sa = (char*)buffer + 10;
3378 wstats.qual = hdr.rssi[0];
3379 if (apriv->rssi)
3380 wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
3381 else
3382 wstats.level = (hdr.rssi[1] + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04003383 wstats.noise = apriv->wstats.qual.noise;
3384 wstats.updated = IW_QUAL_LEVEL_UPDATED
3385 | IW_QUAL_QUAL_UPDATED
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07003386 | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 /* Update spy records */
3388 wireless_spy_update(dev, sa, &wstats);
3389 }
3390#endif /* WIRELESS_SPY */
3391 OUT4500( apriv, EVACK, EV_RX);
3392
3393 if (test_bit(FLAG_802_11, &apriv->flags)) {
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07003394 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 skb->pkt_type = PACKET_OTHERHOST;
3396 skb->dev = apriv->wifidev;
3397 skb->protocol = htons(ETH_P_802_2);
Arnaldo Carvalho de Melo4c13eb62007-04-25 17:40:23 -07003398 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 skb->protocol = eth_type_trans(skb,dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 skb->dev->last_rx = jiffies;
3401 skb->ip_summed = CHECKSUM_NONE;
3402
3403 netif_rx( skb );
3404 }
3405exitrx:
3406
3407 /* Check to see if a packet has been transmitted */
3408 if ( status & ( EV_TX|EV_TXCPY|EV_TXEXC ) ) {
3409 int i;
3410 int len = 0;
3411 int index = -1;
3412
3413 if (test_bit(FLAG_MPI,&apriv->flags)) {
3414 unsigned long flags;
3415
3416 if (status & EV_TXEXC)
3417 get_tx_error(apriv, -1);
3418 spin_lock_irqsave(&apriv->aux_lock, flags);
David S. Millerb03efcf2005-07-08 14:57:23 -07003419 if (!skb_queue_empty(&apriv->txq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 spin_unlock_irqrestore(&apriv->aux_lock,flags);
3421 mpi_send_packet (dev);
3422 } else {
3423 clear_bit(FLAG_PENDING_XMIT, &apriv->flags);
3424 spin_unlock_irqrestore(&apriv->aux_lock,flags);
3425 netif_wake_queue (dev);
3426 }
3427 OUT4500( apriv, EVACK,
3428 status & (EV_TX|EV_TXCPY|EV_TXEXC));
3429 goto exittx;
3430 }
3431
3432 fid = IN4500(apriv, TXCOMPLFID);
3433
3434 for( i = 0; i < MAX_FIDS; i++ ) {
3435 if ( ( apriv->fids[i] & 0xffff ) == fid ) {
3436 len = apriv->fids[i] >> 16;
3437 index = i;
3438 }
3439 }
3440 if (index != -1) {
3441 if (status & EV_TXEXC)
3442 get_tx_error(apriv, index);
3443 OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC));
3444 /* Set up to be used again */
3445 apriv->fids[index] &= 0xffff;
3446 if (index < MAX_FIDS / 2) {
3447 if (!test_bit(FLAG_PENDING_XMIT, &apriv->flags))
3448 netif_wake_queue(dev);
3449 } else {
3450 if (!test_bit(FLAG_PENDING_XMIT11, &apriv->flags))
3451 netif_wake_queue(apriv->wifidev);
3452 }
3453 } else {
3454 OUT4500( apriv, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC));
Dan Williams934d8bf2006-03-16 13:46:23 -05003455 airo_print_err(apriv->dev->name, "Unallocated FID was "
3456 "used to xmit" );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 }
3458 }
3459exittx:
3460 if ( status & ~STATUS_INTS & ~IGNORE_INTS )
Dan Williams934d8bf2006-03-16 13:46:23 -05003461 airo_print_warn(apriv->dev->name, "Got weird status %x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 status & ~STATUS_INTS & ~IGNORE_INTS );
3463 }
3464
3465 if (savedInterrupts)
3466 OUT4500( apriv, EVINTEN, savedInterrupts );
3467
3468 /* done.. */
3469 return IRQ_RETVAL(handled);
3470}
3471
3472/*
3473 * Routines to talk to the card
3474 */
3475
3476/*
3477 * This was originally written for the 4500, hence the name
3478 * NOTE: If use with 8bit mode and SMP bad things will happen!
3479 * Why would some one do 8 bit IO in an SMP machine?!?
3480 */
3481static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) {
3482 if (test_bit(FLAG_MPI,&ai->flags))
3483 reg <<= 1;
3484 if ( !do8bitIO )
3485 outw( val, ai->dev->base_addr + reg );
3486 else {
3487 outb( val & 0xff, ai->dev->base_addr + reg );
3488 outb( val >> 8, ai->dev->base_addr + reg + 1 );
3489 }
3490}
3491
3492static u16 IN4500( struct airo_info *ai, u16 reg ) {
3493 unsigned short rc;
3494
3495 if (test_bit(FLAG_MPI,&ai->flags))
3496 reg <<= 1;
3497 if ( !do8bitIO )
3498 rc = inw( ai->dev->base_addr + reg );
3499 else {
3500 rc = inb( ai->dev->base_addr + reg );
3501 rc += ((int)inb( ai->dev->base_addr + reg + 1 )) << 8;
3502 }
3503 return rc;
3504}
3505
Michal Schmidt175ec1a2007-06-29 15:33:47 +02003506static int enable_MAC(struct airo_info *ai, int lock)
3507{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 int rc;
Michal Schmidt175ec1a2007-06-29 15:33:47 +02003509 Cmd cmd;
3510 Resp rsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511
3512 /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions
3513 * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down"
3514 * Note : we could try to use !netif_running(dev) in enable_MAC()
3515 * instead of this flag, but I don't trust it *within* the
3516 * open/close functions, and testing both flags together is
3517 * "cheaper" - Jean II */
3518 if (ai->flags & FLAG_RADIO_MASK) return SUCCESS;
3519
3520 if (lock && down_interruptible(&ai->sem))
3521 return -ERESTARTSYS;
3522
3523 if (!test_bit(FLAG_ENABLED, &ai->flags)) {
3524 memset(&cmd, 0, sizeof(cmd));
3525 cmd.cmd = MAC_ENABLE;
Michal Schmidt175ec1a2007-06-29 15:33:47 +02003526 rc = issuecommand(ai, &cmd, &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 if (rc == SUCCESS)
3528 set_bit(FLAG_ENABLED, &ai->flags);
3529 } else
3530 rc = SUCCESS;
3531
3532 if (lock)
3533 up(&ai->sem);
3534
3535 if (rc)
Michal Schmidt175ec1a2007-06-29 15:33:47 +02003536 airo_print_err(ai->dev->name, "Cannot enable MAC");
3537 else if ((rsp.status & 0xFF00) != 0) {
3538 airo_print_err(ai->dev->name, "Bad MAC enable reason=%x, "
3539 "rid=%x, offset=%d", rsp.rsp0, rsp.rsp1, rsp.rsp2);
3540 rc = ERROR;
3541 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 return rc;
3543}
3544
3545static void disable_MAC( struct airo_info *ai, int lock ) {
3546 Cmd cmd;
3547 Resp rsp;
3548
3549 if (lock && down_interruptible(&ai->sem))
3550 return;
3551
3552 if (test_bit(FLAG_ENABLED, &ai->flags)) {
3553 memset(&cmd, 0, sizeof(cmd));
3554 cmd.cmd = MAC_DISABLE; // disable in case already enabled
3555 issuecommand(ai, &cmd, &rsp);
3556 clear_bit(FLAG_ENABLED, &ai->flags);
3557 }
3558 if (lock)
3559 up(&ai->sem);
3560}
3561
3562static void enable_interrupts( struct airo_info *ai ) {
3563 /* Enable the interrupts */
3564 OUT4500( ai, EVINTEN, STATUS_INTS );
3565}
3566
3567static void disable_interrupts( struct airo_info *ai ) {
3568 OUT4500( ai, EVINTEN, 0 );
3569}
3570
3571static void mpi_receive_802_3(struct airo_info *ai)
3572{
3573 RxFid rxd;
3574 int len = 0;
3575 struct sk_buff *skb;
3576 char *buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 int off = 0;
3578 MICBuffer micbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579
3580 memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
3581 /* Make sure we got something */
3582 if (rxd.rdy && rxd.valid == 0) {
3583 len = rxd.len + 12;
3584 if (len < 12 || len > 2048)
3585 goto badrx;
3586
3587 skb = dev_alloc_skb(len);
3588 if (!skb) {
3589 ai->stats.rx_dropped++;
3590 goto badrx;
3591 }
3592 buffer = skb_put(skb,len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2);
3594 if (ai->micstats.enabled) {
3595 memcpy(&micbuf,
3596 ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2,
3597 sizeof(micbuf));
3598 if (ntohs(micbuf.typelen) <= 0x05DC) {
3599 if (len <= sizeof(micbuf) + ETH_ALEN * 2)
3600 goto badmic;
3601
3602 off = sizeof(micbuf);
3603 skb_trim (skb, len - off);
3604 }
3605 }
3606 memcpy(buffer + ETH_ALEN * 2,
3607 ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off,
3608 len - ETH_ALEN * 2 - off);
3609 if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) {
3610badmic:
3611 dev_kfree_skb_irq (skb);
3612 goto badrx;
3613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614#ifdef WIRELESS_SPY
3615 if (ai->spy_data.spy_number > 0) {
3616 char *sa;
3617 struct iw_quality wstats;
3618 /* Prepare spy data : addr + qual */
3619 sa = buffer + ETH_ALEN;
3620 wstats.qual = 0; /* XXX Where do I get that info from ??? */
3621 wstats.level = 0;
3622 wstats.updated = 0;
3623 /* Update spy records */
3624 wireless_spy_update(ai->dev, sa, &wstats);
3625 }
3626#endif /* WIRELESS_SPY */
3627
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 skb->ip_summed = CHECKSUM_NONE;
3629 skb->protocol = eth_type_trans(skb, ai->dev);
3630 skb->dev->last_rx = jiffies;
3631 netif_rx(skb);
3632 }
3633badrx:
3634 if (rxd.valid == 0) {
3635 rxd.valid = 1;
3636 rxd.rdy = 0;
3637 rxd.len = PKTSIZE;
3638 memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd));
3639 }
3640}
3641
3642void mpi_receive_802_11 (struct airo_info *ai)
3643{
3644 RxFid rxd;
3645 struct sk_buff *skb = NULL;
Al Viro0300b332007-12-19 22:38:33 -05003646 u16 len, hdrlen = 0;
3647 __le16 fc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648#pragma pack(1)
3649 struct {
Al Viro593c2b92007-12-17 15:09:34 -05003650 __le16 status, len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 u8 rssi[2];
3652 u8 rate;
3653 u8 freq;
Al Viro593c2b92007-12-17 15:09:34 -05003654 __le16 tmp[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 } hdr;
3656#pragma pack()
3657 u16 gap;
3658 u16 *buffer;
3659 char *ptr = ai->rxfids[0].virtual_host_addr+4;
3660
3661 memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
3662 memcpy ((char *)&hdr, ptr, sizeof(hdr));
3663 ptr += sizeof(hdr);
3664 /* Bad CRC. Ignore packet */
3665 if (le16_to_cpu(hdr.status) & 2)
3666 hdr.len = 0;
3667 if (ai->wifidev == NULL)
3668 hdr.len = 0;
3669 len = le16_to_cpu(hdr.len);
Dan Williams15db2762006-03-16 13:46:27 -05003670 if (len > AIRO_DEF_MTU) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003671 airo_print_err(ai->dev->name, "Bad size %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 goto badrx;
3673 }
3674 if (len == 0)
3675 goto badrx;
3676
Al Viro0300b332007-12-19 22:38:33 -05003677 fc = get_unaligned((__le16 *)ptr);
3678 hdrlen = header_len(fc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679
3680 skb = dev_alloc_skb( len + hdrlen + 2 );
3681 if ( !skb ) {
3682 ai->stats.rx_dropped++;
3683 goto badrx;
3684 }
3685 buffer = (u16*)skb_put (skb, len + hdrlen);
3686 memcpy ((char *)buffer, ptr, hdrlen);
3687 ptr += hdrlen;
3688 if (hdrlen == 24)
3689 ptr += 6;
Al Viro593c2b92007-12-17 15:09:34 -05003690 gap = le16_to_cpu(get_unaligned((__le16 *)ptr));
3691 ptr += sizeof(__le16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 if (gap) {
3693 if (gap <= 8)
3694 ptr += gap;
3695 else
Dan Williams934d8bf2006-03-16 13:46:23 -05003696 airo_print_err(ai->dev->name,
3697 "gaplen too big. Problems will follow...");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 }
3699 memcpy ((char *)buffer + hdrlen, ptr, len);
3700 ptr += len;
3701#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
3702 if (ai->spy_data.spy_number > 0) {
3703 char *sa;
3704 struct iw_quality wstats;
3705 /* Prepare spy data : addr + qual */
3706 sa = (char*)buffer + 10;
3707 wstats.qual = hdr.rssi[0];
3708 if (ai->rssi)
3709 wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm;
3710 else
3711 wstats.level = (hdr.rssi[1] + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04003712 wstats.noise = ai->wstats.qual.noise;
3713 wstats.updated = IW_QUAL_QUAL_UPDATED
3714 | IW_QUAL_LEVEL_UPDATED
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07003715 | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 /* Update spy records */
3717 wireless_spy_update(ai->dev, sa, &wstats);
3718 }
3719#endif /* IW_WIRELESS_SPY */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07003720 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 skb->pkt_type = PACKET_OTHERHOST;
3722 skb->dev = ai->wifidev;
3723 skb->protocol = htons(ETH_P_802_2);
3724 skb->dev->last_rx = jiffies;
3725 skb->ip_summed = CHECKSUM_NONE;
3726 netif_rx( skb );
3727badrx:
3728 if (rxd.valid == 0) {
3729 rxd.valid = 1;
3730 rxd.rdy = 0;
3731 rxd.len = PKTSIZE;
3732 memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd));
3733 }
3734}
3735
3736static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
3737{
3738 Cmd cmd;
3739 Resp rsp;
3740 int status;
3741 int i;
3742 SsidRid mySsid;
Al Viro4293ea32007-12-19 19:21:51 -05003743 __le16 lastindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 WepKeyRid wkr;
3745 int rc;
3746
3747 memset( &mySsid, 0, sizeof( mySsid ) );
Jesper Juhlb4558ea2005-10-28 16:53:13 -04003748 kfree (ai->flash);
3749 ai->flash = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750
3751 /* The NOP is the first step in getting the card going */
3752 cmd.cmd = NOP;
3753 cmd.parm0 = cmd.parm1 = cmd.parm2 = 0;
3754 if (lock && down_interruptible(&ai->sem))
3755 return ERROR;
3756 if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
3757 if (lock)
3758 up(&ai->sem);
3759 return ERROR;
3760 }
3761 disable_MAC( ai, 0);
3762
3763 // Let's figure out if we need to use the AUX port
3764 if (!test_bit(FLAG_MPI,&ai->flags)) {
3765 cmd.cmd = CMD_ENABLEAUX;
3766 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
3767 if (lock)
3768 up(&ai->sem);
Dan Williams934d8bf2006-03-16 13:46:23 -05003769 airo_print_err(ai->dev->name, "Error checking for AUX port");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 return ERROR;
3771 }
3772 if (!aux_bap || rsp.status & 0xff00) {
3773 ai->bap_read = fast_bap_read;
Dan Williams934d8bf2006-03-16 13:46:23 -05003774 airo_print_dbg(ai->dev->name, "Doing fast bap_reads");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 } else {
3776 ai->bap_read = aux_bap_read;
Dan Williams934d8bf2006-03-16 13:46:23 -05003777 airo_print_dbg(ai->dev->name, "Doing AUX bap_reads");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 }
3779 }
3780 if (lock)
3781 up(&ai->sem);
3782 if (ai->config.len == 0) {
3783 tdsRssiRid rssi_rid;
3784 CapabilityRid cap_rid;
3785
Jesper Juhlb4558ea2005-10-28 16:53:13 -04003786 kfree(ai->APList);
3787 ai->APList = NULL;
3788 kfree(ai->SSID);
3789 ai->SSID = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 // general configuration (read/modify/write)
3791 status = readConfigRid(ai, lock);
3792 if ( status != SUCCESS ) return ERROR;
3793
3794 status = readCapabilityRid(ai, &cap_rid, lock);
3795 if ( status != SUCCESS ) return ERROR;
3796
3797 status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),lock);
3798 if ( status == SUCCESS ) {
3799 if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
Dan Williams41480af2005-05-10 09:45:51 -04003800 memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 }
3802 else {
Jesper Juhlb4558ea2005-10-28 16:53:13 -04003803 kfree(ai->rssi);
3804 ai->rssi = NULL;
Al Viro56d81bd2007-12-20 17:18:35 -05003805 if (cap_rid.softCap & cpu_to_le16(8))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 ai->config.rmode |= RXMODE_NORMALIZED_RSSI;
3807 else
Dan Williams934d8bf2006-03-16 13:46:23 -05003808 airo_print_warn(ai->dev->name, "unknown received signal "
3809 "level scale");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 }
3811 ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
3812 ai->config.authType = AUTH_OPEN;
3813 ai->config.modulation = MOD_CCK;
3814
Al Viro56d81bd2007-12-20 17:18:35 -05003815 if (le16_to_cpu(cap_rid.len) >= sizeof(cap_rid) &&
Al Viro156178582007-12-20 17:21:36 -05003816 (cap_rid.extSoftCap & cpu_to_le16(1)) &&
Al Viro56d81bd2007-12-20 17:18:35 -05003817 micsetup(ai) == SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 ai->config.opmode |= MODE_MIC;
3819 set_bit(FLAG_MIC_CAPABLE, &ai->flags);
3820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821
3822 /* Save off the MAC */
3823 for( i = 0; i < ETH_ALEN; i++ ) {
3824 mac[i] = ai->config.macAddr[i];
3825 }
3826
3827 /* Check to see if there are any insmod configured
3828 rates to add */
3829 if ( rates[0] ) {
3830 int i = 0;
3831 memset(ai->config.rates,0,sizeof(ai->config.rates));
3832 for( i = 0; i < 8 && rates[i]; i++ ) {
3833 ai->config.rates[i] = rates[i];
3834 }
3835 }
3836 if ( basic_rate > 0 ) {
3837 int i;
3838 for( i = 0; i < 8; i++ ) {
3839 if ( ai->config.rates[i] == basic_rate ||
3840 !ai->config.rates ) {
3841 ai->config.rates[i] = basic_rate | 0x80;
3842 break;
3843 }
3844 }
3845 }
3846 set_bit (FLAG_COMMIT, &ai->flags);
3847 }
3848
3849 /* Setup the SSIDs if present */
3850 if ( ssids[0] ) {
3851 int i;
3852 for( i = 0; i < 3 && ssids[i]; i++ ) {
Al Viro0dd22122007-12-17 16:11:57 -05003853 size_t len = strlen(ssids[i]);
3854 if (len > 32)
3855 len = 32;
3856 mySsid.ssids[i].len = cpu_to_le16(len);
3857 memcpy(mySsid.ssids[i].ssid, ssids[i], len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 }
Al Viro0dd22122007-12-17 16:11:57 -05003859 mySsid.len = cpu_to_le16(sizeof(mySsid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860 }
3861
3862 status = writeConfigRid(ai, lock);
3863 if ( status != SUCCESS ) return ERROR;
3864
3865 /* Set up the SSID list */
3866 if ( ssids[0] ) {
3867 status = writeSsidRid(ai, &mySsid, lock);
3868 if ( status != SUCCESS ) return ERROR;
3869 }
3870
Michal Schmidt175ec1a2007-06-29 15:33:47 +02003871 status = enable_MAC(ai, lock);
3872 if (status != SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 return ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874
3875 /* Grab the initial wep key, we gotta save it for auto_wep */
3876 rc = readWepKeyRid(ai, &wkr, 1, lock);
3877 if (rc == SUCCESS) do {
3878 lastindex = wkr.kindex;
Al Viro4293ea32007-12-19 19:21:51 -05003879 if (wkr.kindex == cpu_to_le16(0xffff)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 ai->defindex = wkr.mac[0];
3881 }
3882 rc = readWepKeyRid(ai, &wkr, 0, lock);
3883 } while(lastindex != wkr.kindex);
3884
Michal Schmidt1c2b7db2007-06-29 15:33:36 +02003885 try_auto_wep(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886
3887 return SUCCESS;
3888}
3889
3890static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
3891 // Im really paranoid about letting it run forever!
3892 int max_tries = 600000;
3893
3894 if (IN4500(ai, EVSTAT) & EV_CMD)
3895 OUT4500(ai, EVACK, EV_CMD);
3896
3897 OUT4500(ai, PARAM0, pCmd->parm0);
3898 OUT4500(ai, PARAM1, pCmd->parm1);
3899 OUT4500(ai, PARAM2, pCmd->parm2);
3900 OUT4500(ai, COMMAND, pCmd->cmd);
3901
3902 while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) {
3903 if ((IN4500(ai, COMMAND)) == pCmd->cmd)
3904 // PC4500 didn't notice command, try again
3905 OUT4500(ai, COMMAND, pCmd->cmd);
3906 if (!in_atomic() && (max_tries & 255) == 0)
3907 schedule();
3908 }
3909
3910 if ( max_tries == -1 ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003911 airo_print_err(ai->dev->name,
3912 "Max tries exceeded when issueing command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 if (IN4500(ai, COMMAND) & COMMAND_BUSY)
3914 OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
3915 return ERROR;
3916 }
3917
3918 // command completed
3919 pRsp->status = IN4500(ai, STATUS);
3920 pRsp->rsp0 = IN4500(ai, RESP0);
3921 pRsp->rsp1 = IN4500(ai, RESP1);
3922 pRsp->rsp2 = IN4500(ai, RESP2);
Robert Schulze13dca9b2006-07-10 18:37:44 +02003923 if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET)
3924 airo_print_err(ai->dev->name,
3925 "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x",
3926 pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1,
3927 pRsp->rsp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928
3929 // clear stuck command busy if necessary
3930 if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
3931 OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
3932 }
3933 // acknowledge processing the status/response
3934 OUT4500(ai, EVACK, EV_CMD);
3935
3936 return SUCCESS;
3937}
3938
3939/* Sets up the bap to start exchange data. whichbap should
3940 * be one of the BAP0 or BAP1 defines. Locks should be held before
3941 * calling! */
3942static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap )
3943{
3944 int timeout = 50;
3945 int max_tries = 3;
3946
3947 OUT4500(ai, SELECT0+whichbap, rid);
3948 OUT4500(ai, OFFSET0+whichbap, offset);
3949 while (1) {
3950 int status = IN4500(ai, OFFSET0+whichbap);
3951 if (status & BAP_BUSY) {
3952 /* This isn't really a timeout, but its kinda
3953 close */
3954 if (timeout--) {
3955 continue;
3956 }
3957 } else if ( status & BAP_ERR ) {
3958 /* invalid rid or offset */
Dan Williams934d8bf2006-03-16 13:46:23 -05003959 airo_print_err(ai->dev->name, "BAP error %x %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 status, whichbap );
3961 return ERROR;
3962 } else if (status & BAP_DONE) { // success
3963 return SUCCESS;
3964 }
3965 if ( !(max_tries--) ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003966 airo_print_err(ai->dev->name,
Michal Schmidt1138c372007-06-29 15:33:41 +02003967 "BAP setup error too many retries\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 return ERROR;
3969 }
3970 // -- PC4500 missed it, try again
3971 OUT4500(ai, SELECT0+whichbap, rid);
3972 OUT4500(ai, OFFSET0+whichbap, offset);
3973 timeout = 50;
3974 }
3975}
3976
3977/* should only be called by aux_bap_read. This aux function and the
3978 following use concepts not documented in the developers guide. I
3979 got them from a patch given to my by Aironet */
3980static u16 aux_setup(struct airo_info *ai, u16 page,
3981 u16 offset, u16 *len)
3982{
3983 u16 next;
3984
3985 OUT4500(ai, AUXPAGE, page);
3986 OUT4500(ai, AUXOFF, 0);
3987 next = IN4500(ai, AUXDATA);
3988 *len = IN4500(ai, AUXDATA)&0xff;
3989 if (offset != 4) OUT4500(ai, AUXOFF, offset);
3990 return next;
3991}
3992
3993/* requires call to bap_setup() first */
Al Virob8c06bc2007-12-19 17:55:43 -05003994static int aux_bap_read(struct airo_info *ai, __le16 *pu16Dst,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 int bytelen, int whichbap)
3996{
3997 u16 len;
3998 u16 page;
3999 u16 offset;
4000 u16 next;
4001 int words;
4002 int i;
4003 unsigned long flags;
4004
4005 spin_lock_irqsave(&ai->aux_lock, flags);
4006 page = IN4500(ai, SWS0+whichbap);
4007 offset = IN4500(ai, SWS2+whichbap);
4008 next = aux_setup(ai, page, offset, &len);
4009 words = (bytelen+1)>>1;
4010
4011 for (i=0; i<words;) {
4012 int count;
4013 count = (len>>1) < (words-i) ? (len>>1) : (words-i);
4014 if ( !do8bitIO )
4015 insw( ai->dev->base_addr+DATA0+whichbap,
4016 pu16Dst+i,count );
4017 else
4018 insb( ai->dev->base_addr+DATA0+whichbap,
4019 pu16Dst+i, count << 1 );
4020 i += count;
4021 if (i<words) {
4022 next = aux_setup(ai, next, 4, &len);
4023 }
4024 }
4025 spin_unlock_irqrestore(&ai->aux_lock, flags);
4026 return SUCCESS;
4027}
4028
4029
4030/* requires call to bap_setup() first */
Al Virob8c06bc2007-12-19 17:55:43 -05004031static int fast_bap_read(struct airo_info *ai, __le16 *pu16Dst,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 int bytelen, int whichbap)
4033{
4034 bytelen = (bytelen + 1) & (~1); // round up to even value
4035 if ( !do8bitIO )
4036 insw( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1 );
4037 else
4038 insb( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen );
4039 return SUCCESS;
4040}
4041
4042/* requires call to bap_setup() first */
Al Virob8c06bc2007-12-19 17:55:43 -05004043static int bap_write(struct airo_info *ai, const __le16 *pu16Src,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 int bytelen, int whichbap)
4045{
4046 bytelen = (bytelen + 1) & (~1); // round up to even value
4047 if ( !do8bitIO )
4048 outsw( ai->dev->base_addr+DATA0+whichbap,
4049 pu16Src, bytelen>>1 );
4050 else
4051 outsb( ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen );
4052 return SUCCESS;
4053}
4054
4055static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd)
4056{
4057 Cmd cmd; /* for issuing commands */
4058 Resp rsp; /* response from commands */
4059 u16 status;
4060
4061 memset(&cmd, 0, sizeof(cmd));
4062 cmd.cmd = accmd;
4063 cmd.parm0 = rid;
4064 status = issuecommand(ai, &cmd, &rsp);
4065 if (status != 0) return status;
4066 if ( (rsp.status & 0x7F00) != 0) {
4067 return (accmd << 8) + (rsp.rsp0 & 0xFF);
4068 }
4069 return 0;
4070}
4071
4072/* Note, that we are using BAP1 which is also used by transmit, so
4073 * we must get a lock. */
4074static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, int lock)
4075{
4076 u16 status;
4077 int rc = SUCCESS;
4078
4079 if (lock) {
4080 if (down_interruptible(&ai->sem))
4081 return ERROR;
4082 }
4083 if (test_bit(FLAG_MPI,&ai->flags)) {
4084 Cmd cmd;
4085 Resp rsp;
4086
4087 memset(&cmd, 0, sizeof(cmd));
4088 memset(&rsp, 0, sizeof(rsp));
4089 ai->config_desc.rid_desc.valid = 1;
4090 ai->config_desc.rid_desc.len = RIDSIZE;
4091 ai->config_desc.rid_desc.rid = 0;
4092 ai->config_desc.rid_desc.host_addr = ai->ridbus;
4093
4094 cmd.cmd = CMD_ACCESS;
4095 cmd.parm0 = rid;
4096
4097 memcpy_toio(ai->config_desc.card_ram_off,
4098 &ai->config_desc.rid_desc, sizeof(Rid));
4099
4100 rc = issuecommand(ai, &cmd, &rsp);
4101
4102 if (rsp.status & 0x7f00)
4103 rc = rsp.rsp0;
4104 if (!rc)
4105 memcpy(pBuf, ai->config_desc.virtual_host_addr, len);
4106 goto done;
4107 } else {
4108 if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS))!=SUCCESS) {
4109 rc = status;
4110 goto done;
4111 }
4112 if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
4113 rc = ERROR;
4114 goto done;
4115 }
4116 // read the rid length field
4117 bap_read(ai, pBuf, 2, BAP1);
4118 // length for remaining part of rid
Al Viro593c2b92007-12-17 15:09:34 -05004119 len = min(len, (int)le16_to_cpu(*(__le16*)pBuf)) - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120
4121 if ( len <= 2 ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004122 airo_print_err(ai->dev->name,
4123 "Rid %x has a length of %d which is too short",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124 (int)rid, (int)len );
4125 rc = ERROR;
4126 goto done;
4127 }
4128 // read remainder of the rid
Al Virob8c06bc2007-12-19 17:55:43 -05004129 rc = bap_read(ai, ((__le16*)pBuf)+1, len, BAP1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 }
4131done:
4132 if (lock)
4133 up(&ai->sem);
4134 return rc;
4135}
4136
4137/* Note, that we are using BAP1 which is also used by transmit, so
4138 * make sure this isnt called when a transmit is happening */
4139static int PC4500_writerid(struct airo_info *ai, u16 rid,
4140 const void *pBuf, int len, int lock)
4141{
4142 u16 status;
4143 int rc = SUCCESS;
4144
Al Viro593c2b92007-12-17 15:09:34 -05004145 *(__le16*)pBuf = cpu_to_le16((u16)len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146
4147 if (lock) {
4148 if (down_interruptible(&ai->sem))
4149 return ERROR;
4150 }
4151 if (test_bit(FLAG_MPI,&ai->flags)) {
4152 Cmd cmd;
4153 Resp rsp;
4154
Dan Streetmanf89b2322005-11-11 11:41:42 -05004155 if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid))
Dan Williams934d8bf2006-03-16 13:46:23 -05004156 airo_print_err(ai->dev->name,
4157 "%s: MAC should be disabled (rid=%04x)",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158 __FUNCTION__, rid);
4159 memset(&cmd, 0, sizeof(cmd));
4160 memset(&rsp, 0, sizeof(rsp));
4161
4162 ai->config_desc.rid_desc.valid = 1;
4163 ai->config_desc.rid_desc.len = *((u16 *)pBuf);
4164 ai->config_desc.rid_desc.rid = 0;
4165
4166 cmd.cmd = CMD_WRITERID;
4167 cmd.parm0 = rid;
4168
4169 memcpy_toio(ai->config_desc.card_ram_off,
4170 &ai->config_desc.rid_desc, sizeof(Rid));
4171
4172 if (len < 4 || len > 2047) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004173 airo_print_err(ai->dev->name, "%s: len=%d", __FUNCTION__, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 rc = -1;
4175 } else {
4176 memcpy((char *)ai->config_desc.virtual_host_addr,
4177 pBuf, len);
4178
4179 rc = issuecommand(ai, &cmd, &rsp);
4180 if ((rc & 0xff00) != 0) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004181 airo_print_err(ai->dev->name, "%s: Write rid Error %d",
4182 __FUNCTION__, rc);
4183 airo_print_err(ai->dev->name, "%s: Cmd=%04x",
4184 __FUNCTION__, cmd.cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 }
4186
4187 if ((rsp.status & 0x7f00))
4188 rc = rsp.rsp0;
4189 }
4190 } else {
4191 // --- first access so that we can write the rid data
4192 if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
4193 rc = status;
4194 goto done;
4195 }
4196 // --- now write the rid data
4197 if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
4198 rc = ERROR;
4199 goto done;
4200 }
4201 bap_write(ai, pBuf, len, BAP1);
4202 // ---now commit the rid data
4203 rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
4204 }
4205done:
4206 if (lock)
4207 up(&ai->sem);
4208 return rc;
4209}
4210
4211/* Allocates a FID to be used for transmitting packets. We only use
4212 one for now. */
4213static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw)
4214{
4215 unsigned int loop = 3000;
4216 Cmd cmd;
4217 Resp rsp;
4218 u16 txFid;
Al Viro593c2b92007-12-17 15:09:34 -05004219 __le16 txControl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220
4221 cmd.cmd = CMD_ALLOCATETX;
4222 cmd.parm0 = lenPayload;
4223 if (down_interruptible(&ai->sem))
4224 return ERROR;
4225 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
4226 txFid = ERROR;
4227 goto done;
4228 }
4229 if ( (rsp.status & 0xFF00) != 0) {
4230 txFid = ERROR;
4231 goto done;
4232 }
4233 /* wait for the allocate event/indication
4234 * It makes me kind of nervous that this can just sit here and spin,
4235 * but in practice it only loops like four times. */
4236 while (((IN4500(ai, EVSTAT) & EV_ALLOC) == 0) && --loop);
4237 if (!loop) {
4238 txFid = ERROR;
4239 goto done;
4240 }
4241
4242 // get the allocated fid and acknowledge
4243 txFid = IN4500(ai, TXALLOCFID);
4244 OUT4500(ai, EVACK, EV_ALLOC);
4245
4246 /* The CARD is pretty cool since it converts the ethernet packet
4247 * into 802.11. Also note that we don't release the FID since we
4248 * will be using the same one over and over again. */
4249 /* We only have to setup the control once since we are not
4250 * releasing the fid. */
4251 if (raw)
4252 txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_11
4253 | TXCTL_ETHERNET | TXCTL_NORELEASE);
4254 else
4255 txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3
4256 | TXCTL_ETHERNET | TXCTL_NORELEASE);
4257 if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS)
4258 txFid = ERROR;
4259 else
4260 bap_write(ai, &txControl, sizeof(txControl), BAP1);
4261
4262done:
4263 up(&ai->sem);
4264
4265 return txFid;
4266}
4267
4268/* In general BAP1 is dedicated to transmiting packets. However,
4269 since we need a BAP when accessing RIDs, we also use BAP1 for that.
4270 Make sure the BAP1 spinlock is held when this is called. */
4271static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
4272{
Al Viro593c2b92007-12-17 15:09:34 -05004273 __le16 payloadLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 Cmd cmd;
4275 Resp rsp;
4276 int miclen = 0;
4277 u16 txFid = len;
4278 MICBuffer pMic;
4279
4280 len >>= 16;
4281
4282 if (len <= ETH_ALEN * 2) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004283 airo_print_warn(ai->dev->name, "Short packet %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 return ERROR;
4285 }
4286 len -= ETH_ALEN * 2;
4287
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
Al Viro593c2b92007-12-17 15:09:34 -05004289 (ntohs(((__be16 *)pPacket)[6]) != 0x888E)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS)
4291 return ERROR;
4292 miclen = sizeof(pMic);
4293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 // packet is destination[6], source[6], payload[len-12]
4295 // write the payload length and dst/src/payload
4296 if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR;
4297 /* The hardware addresses aren't counted as part of the payload, so
4298 * we have to subtract the 12 bytes for the addresses off */
4299 payloadLen = cpu_to_le16(len + miclen);
4300 bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
Al Virob8c06bc2007-12-19 17:55:43 -05004301 bap_write(ai, (__le16*)pPacket, sizeof(etherHead), BAP1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 if (miclen)
Al Virob8c06bc2007-12-19 17:55:43 -05004303 bap_write(ai, (__le16*)&pMic, miclen, BAP1);
4304 bap_write(ai, (__le16*)(pPacket + sizeof(etherHead)), len, BAP1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 // issue the transmit command
4306 memset( &cmd, 0, sizeof( cmd ) );
4307 cmd.cmd = CMD_TRANSMIT;
4308 cmd.parm0 = txFid;
4309 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
4310 if ( (rsp.status & 0xFF00) != 0) return ERROR;
4311 return SUCCESS;
4312}
4313
4314static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
4315{
Al Viro593c2b92007-12-17 15:09:34 -05004316 __le16 fc, payloadLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 Cmd cmd;
4318 Resp rsp;
4319 int hdrlen;
Al Viro977b1432007-12-19 16:45:29 -05004320 static u8 tail[(30-10) + 2 + 6] = {[30-10] = 6};
4321 /* padding of header to full size + le16 gaplen (6) + gaplen bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 u16 txFid = len;
4323 len >>= 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324
Al Viro0300b332007-12-19 22:38:33 -05004325 fc = *(__le16*)pPacket;
4326 hdrlen = header_len(fc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327
4328 if (len < hdrlen) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004329 airo_print_warn(ai->dev->name, "Short packet %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 return ERROR;
4331 }
4332
4333 /* packet is 802.11 header + payload
4334 * write the payload length and dst/src/payload */
4335 if (bap_setup(ai, txFid, 6, BAP1) != SUCCESS) return ERROR;
4336 /* The 802.11 header aren't counted as part of the payload, so
4337 * we have to subtract the header bytes off */
4338 payloadLen = cpu_to_le16(len-hdrlen);
4339 bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
4340 if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR;
Al Virob8c06bc2007-12-19 17:55:43 -05004341 bap_write(ai, (__le16 *)pPacket, hdrlen, BAP1);
4342 bap_write(ai, (__le16 *)(tail + (hdrlen - 10)), 38 - hdrlen, BAP1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343
Al Virob8c06bc2007-12-19 17:55:43 -05004344 bap_write(ai, (__le16 *)(pPacket + hdrlen), len - hdrlen, BAP1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 // issue the transmit command
4346 memset( &cmd, 0, sizeof( cmd ) );
4347 cmd.cmd = CMD_TRANSMIT;
4348 cmd.parm0 = txFid;
4349 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
4350 if ( (rsp.status & 0xFF00) != 0) return ERROR;
4351 return SUCCESS;
4352}
4353
4354/*
4355 * This is the proc_fs routines. It is a bit messier than I would
4356 * like! Feel free to clean it up!
4357 */
4358
4359static ssize_t proc_read( struct file *file,
4360 char __user *buffer,
4361 size_t len,
4362 loff_t *offset);
4363
4364static ssize_t proc_write( struct file *file,
4365 const char __user *buffer,
4366 size_t len,
4367 loff_t *offset );
4368static int proc_close( struct inode *inode, struct file *file );
4369
4370static int proc_stats_open( struct inode *inode, struct file *file );
4371static int proc_statsdelta_open( struct inode *inode, struct file *file );
4372static int proc_status_open( struct inode *inode, struct file *file );
4373static int proc_SSID_open( struct inode *inode, struct file *file );
4374static int proc_APList_open( struct inode *inode, struct file *file );
4375static int proc_BSSList_open( struct inode *inode, struct file *file );
4376static int proc_config_open( struct inode *inode, struct file *file );
4377static int proc_wepkey_open( struct inode *inode, struct file *file );
4378
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004379static const struct file_operations proc_statsdelta_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 .read = proc_read,
4381 .open = proc_statsdelta_open,
4382 .release = proc_close
4383};
4384
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004385static const struct file_operations proc_stats_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 .read = proc_read,
4387 .open = proc_stats_open,
4388 .release = proc_close
4389};
4390
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004391static const struct file_operations proc_status_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 .read = proc_read,
4393 .open = proc_status_open,
4394 .release = proc_close
4395};
4396
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004397static const struct file_operations proc_SSID_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 .read = proc_read,
4399 .write = proc_write,
4400 .open = proc_SSID_open,
4401 .release = proc_close
4402};
4403
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004404static const struct file_operations proc_BSSList_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 .read = proc_read,
4406 .write = proc_write,
4407 .open = proc_BSSList_open,
4408 .release = proc_close
4409};
4410
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004411static const struct file_operations proc_APList_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 .read = proc_read,
4413 .write = proc_write,
4414 .open = proc_APList_open,
4415 .release = proc_close
4416};
4417
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004418static const struct file_operations proc_config_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 .read = proc_read,
4420 .write = proc_write,
4421 .open = proc_config_open,
4422 .release = proc_close
4423};
4424
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08004425static const struct file_operations proc_wepkey_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 .read = proc_read,
4427 .write = proc_write,
4428 .open = proc_wepkey_open,
4429 .release = proc_close
4430};
4431
4432static struct proc_dir_entry *airo_entry;
4433
4434struct proc_data {
4435 int release_buffer;
4436 int readlen;
4437 char *rbuffer;
4438 int writelen;
4439 int maxwritelen;
4440 char *wbuffer;
4441 void (*on_close) (struct inode *, struct file *);
4442};
4443
4444#ifndef SETPROC_OPS
4445#define SETPROC_OPS(entry, ops) (entry)->proc_fops = &(ops)
4446#endif
4447
4448static int setup_proc_entry( struct net_device *dev,
4449 struct airo_info *apriv ) {
4450 struct proc_dir_entry *entry;
4451 /* First setup the device directory */
4452 strcpy(apriv->proc_name,dev->name);
4453 apriv->proc_entry = create_proc_entry(apriv->proc_name,
4454 S_IFDIR|airo_perm,
4455 airo_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004456 if (!apriv->proc_entry)
4457 goto fail;
4458 apriv->proc_entry->uid = proc_uid;
4459 apriv->proc_entry->gid = proc_gid;
4460 apriv->proc_entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461
4462 /* Setup the StatsDelta */
4463 entry = create_proc_entry("StatsDelta",
4464 S_IFREG | (S_IRUGO&proc_perm),
4465 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004466 if (!entry)
4467 goto fail_stats_delta;
4468 entry->uid = proc_uid;
4469 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004471 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 SETPROC_OPS(entry, proc_statsdelta_ops);
4473
4474 /* Setup the Stats */
4475 entry = create_proc_entry("Stats",
4476 S_IFREG | (S_IRUGO&proc_perm),
4477 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004478 if (!entry)
4479 goto fail_stats;
4480 entry->uid = proc_uid;
4481 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004483 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 SETPROC_OPS(entry, proc_stats_ops);
4485
4486 /* Setup the Status */
4487 entry = create_proc_entry("Status",
4488 S_IFREG | (S_IRUGO&proc_perm),
4489 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004490 if (!entry)
4491 goto fail_status;
4492 entry->uid = proc_uid;
4493 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004495 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 SETPROC_OPS(entry, proc_status_ops);
4497
4498 /* Setup the Config */
4499 entry = create_proc_entry("Config",
4500 S_IFREG | proc_perm,
4501 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004502 if (!entry)
4503 goto fail_config;
4504 entry->uid = proc_uid;
4505 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004507 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 SETPROC_OPS(entry, proc_config_ops);
4509
4510 /* Setup the SSID */
4511 entry = create_proc_entry("SSID",
4512 S_IFREG | proc_perm,
4513 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004514 if (!entry)
4515 goto fail_ssid;
4516 entry->uid = proc_uid;
4517 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004519 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 SETPROC_OPS(entry, proc_SSID_ops);
4521
4522 /* Setup the APList */
4523 entry = create_proc_entry("APList",
4524 S_IFREG | proc_perm,
4525 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004526 if (!entry)
4527 goto fail_aplist;
4528 entry->uid = proc_uid;
4529 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004531 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 SETPROC_OPS(entry, proc_APList_ops);
4533
4534 /* Setup the BSSList */
4535 entry = create_proc_entry("BSSList",
4536 S_IFREG | proc_perm,
4537 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004538 if (!entry)
4539 goto fail_bsslist;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540 entry->uid = proc_uid;
4541 entry->gid = proc_gid;
4542 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004543 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544 SETPROC_OPS(entry, proc_BSSList_ops);
4545
4546 /* Setup the WepKey */
4547 entry = create_proc_entry("WepKey",
4548 S_IFREG | proc_perm,
4549 apriv->proc_entry);
Florin Malita431aca52006-10-10 16:46:30 -04004550 if (!entry)
4551 goto fail_wepkey;
4552 entry->uid = proc_uid;
4553 entry->gid = proc_gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 entry->data = dev;
Florin Malita431aca52006-10-10 16:46:30 -04004555 entry->owner = THIS_MODULE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556 SETPROC_OPS(entry, proc_wepkey_ops);
4557
4558 return 0;
Florin Malita431aca52006-10-10 16:46:30 -04004559
4560fail_wepkey:
4561 remove_proc_entry("BSSList", apriv->proc_entry);
4562fail_bsslist:
4563 remove_proc_entry("APList", apriv->proc_entry);
4564fail_aplist:
4565 remove_proc_entry("SSID", apriv->proc_entry);
4566fail_ssid:
4567 remove_proc_entry("Config", apriv->proc_entry);
4568fail_config:
4569 remove_proc_entry("Status", apriv->proc_entry);
4570fail_status:
4571 remove_proc_entry("Stats", apriv->proc_entry);
4572fail_stats:
4573 remove_proc_entry("StatsDelta", apriv->proc_entry);
4574fail_stats_delta:
4575 remove_proc_entry(apriv->proc_name, airo_entry);
4576fail:
4577 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578}
4579
4580static int takedown_proc_entry( struct net_device *dev,
4581 struct airo_info *apriv ) {
4582 if ( !apriv->proc_entry->namelen ) return 0;
4583 remove_proc_entry("Stats",apriv->proc_entry);
4584 remove_proc_entry("StatsDelta",apriv->proc_entry);
4585 remove_proc_entry("Status",apriv->proc_entry);
4586 remove_proc_entry("Config",apriv->proc_entry);
4587 remove_proc_entry("SSID",apriv->proc_entry);
4588 remove_proc_entry("APList",apriv->proc_entry);
4589 remove_proc_entry("BSSList",apriv->proc_entry);
4590 remove_proc_entry("WepKey",apriv->proc_entry);
4591 remove_proc_entry(apriv->proc_name,airo_entry);
4592 return 0;
4593}
4594
4595/*
4596 * What we want from the proc_fs is to be able to efficiently read
4597 * and write the configuration. To do this, we want to read the
4598 * configuration when the file is opened and write it when the file is
4599 * closed. So basically we allocate a read buffer at open and fill it
4600 * with data, and allocate a write buffer and read it at close.
4601 */
4602
4603/*
4604 * The read routine is generic, it relies on the preallocated rbuffer
4605 * to supply the data.
4606 */
4607static ssize_t proc_read( struct file *file,
4608 char __user *buffer,
4609 size_t len,
4610 loff_t *offset )
4611{
4612 loff_t pos = *offset;
4613 struct proc_data *priv = (struct proc_data*)file->private_data;
4614
4615 if (!priv->rbuffer)
4616 return -EINVAL;
4617
4618 if (pos < 0)
4619 return -EINVAL;
4620 if (pos >= priv->readlen)
4621 return 0;
4622 if (len > priv->readlen - pos)
4623 len = priv->readlen - pos;
4624 if (copy_to_user(buffer, priv->rbuffer + pos, len))
4625 return -EFAULT;
4626 *offset = pos + len;
4627 return len;
4628}
4629
4630/*
4631 * The write routine is generic, it fills in a preallocated rbuffer
4632 * to supply the data.
4633 */
4634static ssize_t proc_write( struct file *file,
4635 const char __user *buffer,
4636 size_t len,
4637 loff_t *offset )
4638{
4639 loff_t pos = *offset;
4640 struct proc_data *priv = (struct proc_data*)file->private_data;
4641
4642 if (!priv->wbuffer)
4643 return -EINVAL;
4644
4645 if (pos < 0)
4646 return -EINVAL;
4647 if (pos >= priv->maxwritelen)
4648 return 0;
4649 if (len > priv->maxwritelen - pos)
4650 len = priv->maxwritelen - pos;
4651 if (copy_from_user(priv->wbuffer + pos, buffer, len))
4652 return -EFAULT;
4653 if ( pos + len > priv->writelen )
4654 priv->writelen = len + file->f_pos;
4655 *offset = pos + len;
4656 return len;
4657}
4658
4659static int proc_status_open( struct inode *inode, struct file *file ) {
4660 struct proc_data *data;
4661 struct proc_dir_entry *dp = PDE(inode);
4662 struct net_device *dev = dp->data;
4663 struct airo_info *apriv = dev->priv;
4664 CapabilityRid cap_rid;
4665 StatusRid status_rid;
4666 int i;
4667
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01004668 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 data = (struct proc_data *)file->private_data;
4671 if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
4672 kfree (file->private_data);
4673 return -ENOMEM;
4674 }
4675
4676 readStatusRid(apriv, &status_rid, 1);
4677 readCapabilityRid(apriv, &cap_rid, 1);
4678
4679 i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n",
4680 status_rid.mode & 1 ? "CFG ": "",
4681 status_rid.mode & 2 ? "ACT ": "",
4682 status_rid.mode & 0x10 ? "SYN ": "",
4683 status_rid.mode & 0x20 ? "LNK ": "",
4684 status_rid.mode & 0x40 ? "LEAP ": "",
4685 status_rid.mode & 0x80 ? "PRIV ": "",
4686 status_rid.mode & 0x100 ? "KEY ": "",
4687 status_rid.mode & 0x200 ? "WEP ": "",
4688 status_rid.mode & 0x8000 ? "ERR ": "");
4689 sprintf( data->rbuffer+i, "Mode: %x\n"
4690 "Signal Strength: %d\n"
4691 "Signal Quality: %d\n"
4692 "SSID: %-.*s\n"
4693 "AP: %-.16s\n"
4694 "Freq: %d\n"
4695 "BitRate: %dmbs\n"
4696 "Driver Version: %s\n"
4697 "Device: %s\nManufacturer: %s\nFirmware Version: %s\n"
4698 "Radio type: %x\nCountry: %x\nHardware Version: %x\n"
4699 "Software Version: %x\nSoftware Subversion: %x\n"
4700 "Boot block version: %x\n",
4701 (int)status_rid.mode,
4702 (int)status_rid.normalizedSignalStrength,
4703 (int)status_rid.signalQuality,
4704 (int)status_rid.SSIDlen,
4705 status_rid.SSID,
4706 status_rid.apName,
4707 (int)status_rid.channel,
4708 (int)status_rid.currentXmitRate/2,
4709 version,
4710 cap_rid.prodName,
4711 cap_rid.manName,
4712 cap_rid.prodVer,
Al Viro56d81bd2007-12-20 17:18:35 -05004713 le16_to_cpu(cap_rid.radioType),
4714 le16_to_cpu(cap_rid.country),
4715 le16_to_cpu(cap_rid.hardVer),
4716 le16_to_cpu(cap_rid.softVer),
4717 le16_to_cpu(cap_rid.softSubVer),
4718 le16_to_cpu(cap_rid.bootBlockVer));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 data->readlen = strlen( data->rbuffer );
4720 return 0;
4721}
4722
4723static int proc_stats_rid_open(struct inode*, struct file*, u16);
4724static int proc_statsdelta_open( struct inode *inode,
4725 struct file *file ) {
4726 if (file->f_mode&FMODE_WRITE) {
4727 return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR);
4728 }
4729 return proc_stats_rid_open(inode, file, RID_STATSDELTA);
4730}
4731
4732static int proc_stats_open( struct inode *inode, struct file *file ) {
4733 return proc_stats_rid_open(inode, file, RID_STATS);
4734}
4735
4736static int proc_stats_rid_open( struct inode *inode,
4737 struct file *file,
Al Viroa23ace52007-12-19 22:24:16 -05004738 u16 rid )
4739{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 struct proc_data *data;
4741 struct proc_dir_entry *dp = PDE(inode);
4742 struct net_device *dev = dp->data;
4743 struct airo_info *apriv = dev->priv;
4744 StatsRid stats;
4745 int i, j;
Al Viroa23ace52007-12-19 22:24:16 -05004746 __le32 *vals = stats.vals;
4747 int len = le16_to_cpu(stats.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01004749 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 data = (struct proc_data *)file->private_data;
4752 if ((data->rbuffer = kmalloc( 4096, GFP_KERNEL )) == NULL) {
4753 kfree (file->private_data);
4754 return -ENOMEM;
4755 }
4756
4757 readStatsRid(apriv, &stats, rid, 1);
4758
4759 j = 0;
Al Viroa23ace52007-12-19 22:24:16 -05004760 for(i=0; statsLabels[i]!=(char *)-1 && i*4<len; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 if (!statsLabels[i]) continue;
4762 if (j+strlen(statsLabels[i])+16>4096) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004763 airo_print_warn(apriv->dev->name,
4764 "Potentially disasterous buffer overflow averted!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 break;
4766 }
Al Viroa23ace52007-12-19 22:24:16 -05004767 j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i],
4768 le32_to_cpu(vals[i]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 }
Al Viroa23ace52007-12-19 22:24:16 -05004770 if (i*4 >= len) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004771 airo_print_warn(apriv->dev->name, "Got a short rid");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 }
4773 data->readlen = j;
4774 return 0;
4775}
4776
4777static int get_dec_u16( char *buffer, int *start, int limit ) {
4778 u16 value;
4779 int valid = 0;
4780 for( value = 0; buffer[*start] >= '0' &&
4781 buffer[*start] <= '9' &&
4782 *start < limit; (*start)++ ) {
4783 valid = 1;
4784 value *= 10;
4785 value += buffer[*start] - '0';
4786 }
4787 if ( !valid ) return -1;
4788 return value;
4789}
4790
4791static int airo_config_commit(struct net_device *dev,
4792 struct iw_request_info *info, void *zwrq,
4793 char *extra);
4794
4795static void proc_config_on_close( struct inode *inode, struct file *file ) {
4796 struct proc_data *data = file->private_data;
4797 struct proc_dir_entry *dp = PDE(inode);
4798 struct net_device *dev = dp->data;
4799 struct airo_info *ai = dev->priv;
4800 char *line;
4801
4802 if ( !data->writelen ) return;
4803
4804 readConfigRid(ai, 1);
4805 set_bit (FLAG_COMMIT, &ai->flags);
4806
4807 line = data->wbuffer;
4808 while( line[0] ) {
4809/*** Mode processing */
4810 if ( !strncmp( line, "Mode: ", 6 ) ) {
4811 line += 6;
4812 if ((ai->config.rmode & 0xff) >= RXMODE_RFMON)
4813 set_bit (FLAG_RESET, &ai->flags);
4814 ai->config.rmode &= 0xfe00;
4815 clear_bit (FLAG_802_11, &ai->flags);
4816 ai->config.opmode &= 0xFF00;
4817 ai->config.scanMode = SCANMODE_ACTIVE;
4818 if ( line[0] == 'a' ) {
4819 ai->config.opmode |= 0;
4820 } else {
4821 ai->config.opmode |= 1;
4822 if ( line[0] == 'r' ) {
4823 ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
4824 ai->config.scanMode = SCANMODE_PASSIVE;
4825 set_bit (FLAG_802_11, &ai->flags);
4826 } else if ( line[0] == 'y' ) {
4827 ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER;
4828 ai->config.scanMode = SCANMODE_PASSIVE;
4829 set_bit (FLAG_802_11, &ai->flags);
4830 } else if ( line[0] == 'l' )
4831 ai->config.rmode |= RXMODE_LANMON;
4832 }
4833 set_bit (FLAG_COMMIT, &ai->flags);
4834 }
4835
4836/*** Radio status */
4837 else if (!strncmp(line,"Radio: ", 7)) {
4838 line += 7;
4839 if (!strncmp(line,"off",3)) {
4840 set_bit (FLAG_RADIO_OFF, &ai->flags);
4841 } else {
4842 clear_bit (FLAG_RADIO_OFF, &ai->flags);
4843 }
4844 }
4845/*** NodeName processing */
4846 else if ( !strncmp( line, "NodeName: ", 10 ) ) {
4847 int j;
4848
4849 line += 10;
4850 memset( ai->config.nodeName, 0, 16 );
4851/* Do the name, assume a space between the mode and node name */
4852 for( j = 0; j < 16 && line[j] != '\n'; j++ ) {
4853 ai->config.nodeName[j] = line[j];
4854 }
4855 set_bit (FLAG_COMMIT, &ai->flags);
4856 }
4857
4858/*** PowerMode processing */
4859 else if ( !strncmp( line, "PowerMode: ", 11 ) ) {
4860 line += 11;
4861 if ( !strncmp( line, "PSPCAM", 6 ) ) {
4862 ai->config.powerSaveMode = POWERSAVE_PSPCAM;
4863 set_bit (FLAG_COMMIT, &ai->flags);
4864 } else if ( !strncmp( line, "PSP", 3 ) ) {
4865 ai->config.powerSaveMode = POWERSAVE_PSP;
4866 set_bit (FLAG_COMMIT, &ai->flags);
4867 } else {
4868 ai->config.powerSaveMode = POWERSAVE_CAM;
4869 set_bit (FLAG_COMMIT, &ai->flags);
4870 }
4871 } else if ( !strncmp( line, "DataRates: ", 11 ) ) {
4872 int v, i = 0, k = 0; /* i is index into line,
4873 k is index to rates */
4874
4875 line += 11;
4876 while((v = get_dec_u16(line, &i, 3))!=-1) {
4877 ai->config.rates[k++] = (u8)v;
4878 line += i + 1;
4879 i = 0;
4880 }
4881 set_bit (FLAG_COMMIT, &ai->flags);
4882 } else if ( !strncmp( line, "Channel: ", 9 ) ) {
4883 int v, i = 0;
4884 line += 9;
4885 v = get_dec_u16(line, &i, i+3);
4886 if ( v != -1 ) {
4887 ai->config.channelSet = (u16)v;
4888 set_bit (FLAG_COMMIT, &ai->flags);
4889 }
4890 } else if ( !strncmp( line, "XmitPower: ", 11 ) ) {
4891 int v, i = 0;
4892 line += 11;
4893 v = get_dec_u16(line, &i, i+3);
4894 if ( v != -1 ) {
4895 ai->config.txPower = (u16)v;
4896 set_bit (FLAG_COMMIT, &ai->flags);
4897 }
4898 } else if ( !strncmp( line, "WEP: ", 5 ) ) {
4899 line += 5;
4900 switch( line[0] ) {
4901 case 's':
4902 ai->config.authType = (u16)AUTH_SHAREDKEY;
4903 break;
4904 case 'e':
4905 ai->config.authType = (u16)AUTH_ENCRYPT;
4906 break;
4907 default:
4908 ai->config.authType = (u16)AUTH_OPEN;
4909 break;
4910 }
4911 set_bit (FLAG_COMMIT, &ai->flags);
4912 } else if ( !strncmp( line, "LongRetryLimit: ", 16 ) ) {
4913 int v, i = 0;
4914
4915 line += 16;
4916 v = get_dec_u16(line, &i, 3);
4917 v = (v<0) ? 0 : ((v>255) ? 255 : v);
4918 ai->config.longRetryLimit = (u16)v;
4919 set_bit (FLAG_COMMIT, &ai->flags);
4920 } else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) {
4921 int v, i = 0;
4922
4923 line += 17;
4924 v = get_dec_u16(line, &i, 3);
4925 v = (v<0) ? 0 : ((v>255) ? 255 : v);
4926 ai->config.shortRetryLimit = (u16)v;
4927 set_bit (FLAG_COMMIT, &ai->flags);
4928 } else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) {
4929 int v, i = 0;
4930
4931 line += 14;
4932 v = get_dec_u16(line, &i, 4);
Dan Williams15db2762006-03-16 13:46:27 -05004933 v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934 ai->config.rtsThres = (u16)v;
4935 set_bit (FLAG_COMMIT, &ai->flags);
4936 } else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) {
4937 int v, i = 0;
4938
4939 line += 16;
4940 v = get_dec_u16(line, &i, 5);
4941 v = (v<0) ? 0 : v;
4942 ai->config.txLifetime = (u16)v;
4943 set_bit (FLAG_COMMIT, &ai->flags);
4944 } else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) {
4945 int v, i = 0;
4946
4947 line += 16;
4948 v = get_dec_u16(line, &i, 5);
4949 v = (v<0) ? 0 : v;
4950 ai->config.rxLifetime = (u16)v;
4951 set_bit (FLAG_COMMIT, &ai->flags);
4952 } else if ( !strncmp( line, "TXDiversity: ", 13 ) ) {
4953 ai->config.txDiversity =
4954 (line[13]=='l') ? 1 :
4955 ((line[13]=='r')? 2: 3);
4956 set_bit (FLAG_COMMIT, &ai->flags);
4957 } else if ( !strncmp( line, "RXDiversity: ", 13 ) ) {
4958 ai->config.rxDiversity =
4959 (line[13]=='l') ? 1 :
4960 ((line[13]=='r')? 2: 3);
4961 set_bit (FLAG_COMMIT, &ai->flags);
4962 } else if ( !strncmp( line, "FragThreshold: ", 15 ) ) {
4963 int v, i = 0;
4964
4965 line += 15;
4966 v = get_dec_u16(line, &i, 4);
Dan Williams15db2762006-03-16 13:46:27 -05004967 v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968 v = v & 0xfffe; /* Make sure its even */
4969 ai->config.fragThresh = (u16)v;
4970 set_bit (FLAG_COMMIT, &ai->flags);
4971 } else if (!strncmp(line, "Modulation: ", 12)) {
4972 line += 12;
4973 switch(*line) {
4974 case 'd': ai->config.modulation=MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break;
4975 case 'c': ai->config.modulation=MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break;
4976 case 'm': ai->config.modulation=MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break;
Dan Williams934d8bf2006-03-16 13:46:23 -05004977 default: airo_print_warn(ai->dev->name, "Unknown modulation");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978 }
4979 } else if (!strncmp(line, "Preamble: ", 10)) {
4980 line += 10;
4981 switch(*line) {
4982 case 'a': ai->config.preamble=PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break;
4983 case 'l': ai->config.preamble=PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break;
4984 case 's': ai->config.preamble=PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break;
Dan Williams934d8bf2006-03-16 13:46:23 -05004985 default: airo_print_warn(ai->dev->name, "Unknown preamble");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 }
4987 } else {
Dan Williams934d8bf2006-03-16 13:46:23 -05004988 airo_print_warn(ai->dev->name, "Couldn't figure out %s", line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989 }
4990 while( line[0] && line[0] != '\n' ) line++;
4991 if ( line[0] ) line++;
4992 }
4993 airo_config_commit(dev, NULL, NULL, NULL);
4994}
4995
4996static char *get_rmode(u16 mode) {
4997 switch(mode&0xff) {
4998 case RXMODE_RFMON: return "rfmon";
4999 case RXMODE_RFMON_ANYBSS: return "yna (any) bss rfmon";
5000 case RXMODE_LANMON: return "lanmon";
5001 }
5002 return "ESS";
5003}
5004
5005static int proc_config_open( struct inode *inode, struct file *file ) {
5006 struct proc_data *data;
5007 struct proc_dir_entry *dp = PDE(inode);
5008 struct net_device *dev = dp->data;
5009 struct airo_info *ai = dev->priv;
5010 int i;
5011
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005012 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 data = (struct proc_data *)file->private_data;
5015 if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
5016 kfree (file->private_data);
5017 return -ENOMEM;
5018 }
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005019 if ((data->wbuffer = kzalloc( 2048, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 kfree (data->rbuffer);
5021 kfree (file->private_data);
5022 return -ENOMEM;
5023 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024 data->maxwritelen = 2048;
5025 data->on_close = proc_config_on_close;
5026
5027 readConfigRid(ai, 1);
5028
5029 i = sprintf( data->rbuffer,
5030 "Mode: %s\n"
5031 "Radio: %s\n"
5032 "NodeName: %-16s\n"
5033 "PowerMode: %s\n"
5034 "DataRates: %d %d %d %d %d %d %d %d\n"
5035 "Channel: %d\n"
5036 "XmitPower: %d\n",
5037 (ai->config.opmode & 0xFF) == 0 ? "adhoc" :
5038 (ai->config.opmode & 0xFF) == 1 ? get_rmode(ai->config.rmode):
5039 (ai->config.opmode & 0xFF) == 2 ? "AP" :
5040 (ai->config.opmode & 0xFF) == 3 ? "AP RPTR" : "Error",
5041 test_bit(FLAG_RADIO_OFF, &ai->flags) ? "off" : "on",
5042 ai->config.nodeName,
5043 ai->config.powerSaveMode == 0 ? "CAM" :
5044 ai->config.powerSaveMode == 1 ? "PSP" :
5045 ai->config.powerSaveMode == 2 ? "PSPCAM" : "Error",
5046 (int)ai->config.rates[0],
5047 (int)ai->config.rates[1],
5048 (int)ai->config.rates[2],
5049 (int)ai->config.rates[3],
5050 (int)ai->config.rates[4],
5051 (int)ai->config.rates[5],
5052 (int)ai->config.rates[6],
5053 (int)ai->config.rates[7],
5054 (int)ai->config.channelSet,
5055 (int)ai->config.txPower
5056 );
5057 sprintf( data->rbuffer + i,
5058 "LongRetryLimit: %d\n"
5059 "ShortRetryLimit: %d\n"
5060 "RTSThreshold: %d\n"
5061 "TXMSDULifetime: %d\n"
5062 "RXMSDULifetime: %d\n"
5063 "TXDiversity: %s\n"
5064 "RXDiversity: %s\n"
5065 "FragThreshold: %d\n"
5066 "WEP: %s\n"
5067 "Modulation: %s\n"
5068 "Preamble: %s\n",
5069 (int)ai->config.longRetryLimit,
5070 (int)ai->config.shortRetryLimit,
5071 (int)ai->config.rtsThres,
5072 (int)ai->config.txLifetime,
5073 (int)ai->config.rxLifetime,
5074 ai->config.txDiversity == 1 ? "left" :
5075 ai->config.txDiversity == 2 ? "right" : "both",
5076 ai->config.rxDiversity == 1 ? "left" :
5077 ai->config.rxDiversity == 2 ? "right" : "both",
5078 (int)ai->config.fragThresh,
5079 ai->config.authType == AUTH_ENCRYPT ? "encrypt" :
5080 ai->config.authType == AUTH_SHAREDKEY ? "shared" : "open",
5081 ai->config.modulation == 0 ? "default" :
5082 ai->config.modulation == MOD_CCK ? "cck" :
5083 ai->config.modulation == MOD_MOK ? "mok" : "error",
5084 ai->config.preamble == PREAMBLE_AUTO ? "auto" :
5085 ai->config.preamble == PREAMBLE_LONG ? "long" :
5086 ai->config.preamble == PREAMBLE_SHORT ? "short" : "error"
5087 );
5088 data->readlen = strlen( data->rbuffer );
5089 return 0;
5090}
5091
Al Viro0dd22122007-12-17 16:11:57 -05005092static void proc_SSID_on_close(struct inode *inode, struct file *file)
5093{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 struct proc_data *data = (struct proc_data *)file->private_data;
5095 struct proc_dir_entry *dp = PDE(inode);
5096 struct net_device *dev = dp->data;
5097 struct airo_info *ai = dev->priv;
5098 SsidRid SSID_rid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099 int i;
Al Viro0dd22122007-12-17 16:11:57 -05005100 char *p = data->wbuffer;
5101 char *end = p + data->writelen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102
Al Viro0dd22122007-12-17 16:11:57 -05005103 if (!data->writelen)
5104 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105
Al Viro0dd22122007-12-17 16:11:57 -05005106 *end = '\n'; /* sentinel; we have space for it */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107
Al Viro0dd22122007-12-17 16:11:57 -05005108 memset(&SSID_rid, 0, sizeof(SSID_rid));
5109
5110 for (i = 0; i < 3 && p < end; i++) {
5111 int j = 0;
5112 /* copy up to 32 characters from this line */
5113 while (*p != '\n' && j < 32)
5114 SSID_rid.ssids[i].ssid[j++] = *p++;
5115 if (j == 0)
5116 break;
5117 SSID_rid.ssids[i].len = cpu_to_le16(j);
5118 /* skip to the beginning of the next line */
5119 while (*p++ != '\n')
5120 ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121 }
5122 if (i)
Al Viro0dd22122007-12-17 16:11:57 -05005123 SSID_rid.len = cpu_to_le16(sizeof(SSID_rid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124 disable_MAC(ai, 1);
5125 writeSsidRid(ai, &SSID_rid, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005126 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127}
5128
Jesper Juhl77933d72005-07-27 11:46:09 -07005129static inline u8 hexVal(char c) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130 if (c>='0' && c<='9') return c -= '0';
5131 if (c>='a' && c<='f') return c -= 'a'-10;
5132 if (c>='A' && c<='F') return c -= 'A'-10;
5133 return 0;
5134}
5135
5136static void proc_APList_on_close( struct inode *inode, struct file *file ) {
5137 struct proc_data *data = (struct proc_data *)file->private_data;
5138 struct proc_dir_entry *dp = PDE(inode);
5139 struct net_device *dev = dp->data;
5140 struct airo_info *ai = dev->priv;
5141 APListRid APList_rid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 int i;
5143
5144 if ( !data->writelen ) return;
5145
5146 memset( &APList_rid, 0, sizeof(APList_rid) );
Al Viroa7497162007-12-20 17:49:41 -05005147 APList_rid.len = cpu_to_le16(sizeof(APList_rid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148
5149 for( i = 0; i < 4 && data->writelen >= (i+1)*6*3; i++ ) {
5150 int j;
5151 for( j = 0; j < 6*3 && data->wbuffer[j+i*6*3]; j++ ) {
5152 switch(j%3) {
5153 case 0:
5154 APList_rid.ap[i][j/3]=
5155 hexVal(data->wbuffer[j+i*6*3])<<4;
5156 break;
5157 case 1:
5158 APList_rid.ap[i][j/3]|=
5159 hexVal(data->wbuffer[j+i*6*3]);
5160 break;
5161 }
5162 }
5163 }
5164 disable_MAC(ai, 1);
5165 writeAPListRid(ai, &APList_rid, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005166 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167}
5168
5169/* This function wraps PC4500_writerid with a MAC disable */
5170static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data,
5171 int len, int dummy ) {
5172 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173
5174 disable_MAC(ai, 1);
5175 rc = PC4500_writerid(ai, rid, rid_data, len, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005176 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177 return rc;
5178}
5179
5180/* Returns the length of the key at the index. If index == 0xffff
5181 * the index of the transmit key is returned. If the key doesn't exist,
5182 * -1 will be returned.
5183 */
5184static int get_wep_key(struct airo_info *ai, u16 index) {
5185 WepKeyRid wkr;
5186 int rc;
Al Viro4293ea32007-12-19 19:21:51 -05005187 __le16 lastindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188
5189 rc = readWepKeyRid(ai, &wkr, 1, 1);
5190 if (rc == SUCCESS) do {
5191 lastindex = wkr.kindex;
Al Viro4293ea32007-12-19 19:21:51 -05005192 if (wkr.kindex == cpu_to_le16(index)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193 if (index == 0xffff) {
5194 return wkr.mac[0];
5195 }
Al Viro4293ea32007-12-19 19:21:51 -05005196 return le16_to_cpu(wkr.klen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 }
5198 readWepKeyRid(ai, &wkr, 0, 1);
Al Viro4293ea32007-12-19 19:21:51 -05005199 } while (lastindex != wkr.kindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 return -1;
5201}
5202
5203static int set_wep_key(struct airo_info *ai, u16 index,
Al Viro4293ea32007-12-19 19:21:51 -05005204 const char *key, u16 keylen, int perm, int lock )
5205{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
5207 WepKeyRid wkr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208
5209 memset(&wkr, 0, sizeof(wkr));
5210 if (keylen == 0) {
5211// We are selecting which key to use
Al Viro4293ea32007-12-19 19:21:51 -05005212 wkr.len = cpu_to_le16(sizeof(wkr));
5213 wkr.kindex = cpu_to_le16(0xffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 wkr.mac[0] = (char)index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215 if (perm) ai->defindex = (char)index;
5216 } else {
5217// We are actually setting the key
Al Viro4293ea32007-12-19 19:21:51 -05005218 wkr.len = cpu_to_le16(sizeof(wkr));
5219 wkr.kindex = cpu_to_le16(index);
5220 wkr.klen = cpu_to_le16(keylen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 memcpy( wkr.key, key, keylen );
5222 memcpy( wkr.mac, macaddr, ETH_ALEN );
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223 }
5224
Dan Streetmanf89b2322005-11-11 11:41:42 -05005225 if (perm) disable_MAC(ai, lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 writeWepKeyRid(ai, &wkr, perm, lock);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005227 if (perm) enable_MAC(ai, lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 return 0;
5229}
5230
5231static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
5232 struct proc_data *data;
5233 struct proc_dir_entry *dp = PDE(inode);
5234 struct net_device *dev = dp->data;
5235 struct airo_info *ai = dev->priv;
5236 int i;
5237 char key[16];
5238 u16 index = 0;
5239 int j = 0;
5240
5241 memset(key, 0, sizeof(key));
5242
5243 data = (struct proc_data *)file->private_data;
5244 if ( !data->writelen ) return;
5245
5246 if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' &&
5247 (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) {
5248 index = data->wbuffer[0] - '0';
5249 if (data->wbuffer[1] == '\n') {
5250 set_wep_key(ai, index, NULL, 0, 1, 1);
5251 return;
5252 }
5253 j = 2;
5254 } else {
Dan Williams934d8bf2006-03-16 13:46:23 -05005255 airo_print_err(ai->dev->name, "WepKey passed invalid key index");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 return;
5257 }
5258
5259 for( i = 0; i < 16*3 && data->wbuffer[i+j]; i++ ) {
5260 switch(i%3) {
5261 case 0:
5262 key[i/3] = hexVal(data->wbuffer[i+j])<<4;
5263 break;
5264 case 1:
5265 key[i/3] |= hexVal(data->wbuffer[i+j]);
5266 break;
5267 }
5268 }
5269 set_wep_key(ai, index, key, i/3, 1, 1);
5270}
5271
Al Viro4293ea32007-12-19 19:21:51 -05005272static int proc_wepkey_open( struct inode *inode, struct file *file )
5273{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274 struct proc_data *data;
5275 struct proc_dir_entry *dp = PDE(inode);
5276 struct net_device *dev = dp->data;
5277 struct airo_info *ai = dev->priv;
5278 char *ptr;
5279 WepKeyRid wkr;
Al Viro4293ea32007-12-19 19:21:51 -05005280 __le16 lastindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281 int j=0;
5282 int rc;
5283
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005284 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 memset(&wkr, 0, sizeof(wkr));
5287 data = (struct proc_data *)file->private_data;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005288 if ((data->rbuffer = kzalloc( 180, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 kfree (file->private_data);
5290 return -ENOMEM;
5291 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 data->writelen = 0;
5293 data->maxwritelen = 80;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005294 if ((data->wbuffer = kzalloc( 80, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295 kfree (data->rbuffer);
5296 kfree (file->private_data);
5297 return -ENOMEM;
5298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299 data->on_close = proc_wepkey_on_close;
5300
5301 ptr = data->rbuffer;
5302 strcpy(ptr, "No wep keys\n");
5303 rc = readWepKeyRid(ai, &wkr, 1, 1);
5304 if (rc == SUCCESS) do {
5305 lastindex = wkr.kindex;
Al Viro4293ea32007-12-19 19:21:51 -05005306 if (wkr.kindex == cpu_to_le16(0xffff)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307 j += sprintf(ptr+j, "Tx key = %d\n",
5308 (int)wkr.mac[0]);
5309 } else {
5310 j += sprintf(ptr+j, "Key %d set with length = %d\n",
Al Viro4293ea32007-12-19 19:21:51 -05005311 le16_to_cpu(wkr.kindex),
5312 le16_to_cpu(wkr.klen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 }
5314 readWepKeyRid(ai, &wkr, 0, 1);
5315 } while((lastindex != wkr.kindex) && (j < 180-30));
5316
5317 data->readlen = strlen( data->rbuffer );
5318 return 0;
5319}
5320
Al Viro0dd22122007-12-17 16:11:57 -05005321static int proc_SSID_open(struct inode *inode, struct file *file)
5322{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323 struct proc_data *data;
5324 struct proc_dir_entry *dp = PDE(inode);
5325 struct net_device *dev = dp->data;
5326 struct airo_info *ai = dev->priv;
5327 int i;
5328 char *ptr;
5329 SsidRid SSID_rid;
5330
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005331 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 data = (struct proc_data *)file->private_data;
5334 if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
5335 kfree (file->private_data);
5336 return -ENOMEM;
5337 }
5338 data->writelen = 0;
5339 data->maxwritelen = 33*3;
Al Viro0dd22122007-12-17 16:11:57 -05005340 /* allocate maxwritelen + 1; we'll want a sentinel */
5341 if ((data->wbuffer = kzalloc(33*3 + 1, GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342 kfree (data->rbuffer);
5343 kfree (file->private_data);
5344 return -ENOMEM;
5345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346 data->on_close = proc_SSID_on_close;
5347
5348 readSsidRid(ai, &SSID_rid);
5349 ptr = data->rbuffer;
Al Viro0dd22122007-12-17 16:11:57 -05005350 for (i = 0; i < 3; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 int j;
Al Viro0dd22122007-12-17 16:11:57 -05005352 size_t len = le16_to_cpu(SSID_rid.ssids[i].len);
5353 if (!len)
5354 break;
5355 if (len > 32)
5356 len = 32;
5357 for (j = 0; j < len && SSID_rid.ssids[i].ssid[j]; j++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358 *ptr++ = SSID_rid.ssids[i].ssid[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359 *ptr++ = '\n';
5360 }
5361 *ptr = '\0';
5362 data->readlen = strlen( data->rbuffer );
5363 return 0;
5364}
5365
5366static int proc_APList_open( struct inode *inode, struct file *file ) {
5367 struct proc_data *data;
5368 struct proc_dir_entry *dp = PDE(inode);
5369 struct net_device *dev = dp->data;
5370 struct airo_info *ai = dev->priv;
5371 int i;
5372 char *ptr;
5373 APListRid APList_rid;
Joe Perches0795af52007-10-03 17:59:30 -07005374 DECLARE_MAC_BUF(mac);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005376 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 data = (struct proc_data *)file->private_data;
5379 if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
5380 kfree (file->private_data);
5381 return -ENOMEM;
5382 }
5383 data->writelen = 0;
5384 data->maxwritelen = 4*6*3;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005385 if ((data->wbuffer = kzalloc( data->maxwritelen, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 kfree (data->rbuffer);
5387 kfree (file->private_data);
5388 return -ENOMEM;
5389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390 data->on_close = proc_APList_on_close;
5391
5392 readAPListRid(ai, &APList_rid);
5393 ptr = data->rbuffer;
5394 for( i = 0; i < 4; i++ ) {
5395// We end when we find a zero MAC
5396 if ( !*(int*)APList_rid.ap[i] &&
5397 !*(int*)&APList_rid.ap[i][2]) break;
Joe Perches0795af52007-10-03 17:59:30 -07005398 ptr += sprintf(ptr, "%s\n",
5399 print_mac(mac, APList_rid.ap[i]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400 }
5401 if (i==0) ptr += sprintf(ptr, "Not using specific APs\n");
5402
5403 *ptr = '\0';
5404 data->readlen = strlen( data->rbuffer );
5405 return 0;
5406}
5407
5408static int proc_BSSList_open( struct inode *inode, struct file *file ) {
5409 struct proc_data *data;
5410 struct proc_dir_entry *dp = PDE(inode);
5411 struct net_device *dev = dp->data;
5412 struct airo_info *ai = dev->priv;
5413 char *ptr;
5414 BSSListRid BSSList_rid;
5415 int rc;
5416 /* If doLoseSync is not 1, we won't do a Lose Sync */
5417 int doLoseSync = -1;
Joe Perches0795af52007-10-03 17:59:30 -07005418 DECLARE_MAC_BUF(mac);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005420 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422 data = (struct proc_data *)file->private_data;
5423 if ((data->rbuffer = kmalloc( 1024, GFP_KERNEL )) == NULL) {
5424 kfree (file->private_data);
5425 return -ENOMEM;
5426 }
5427 data->writelen = 0;
5428 data->maxwritelen = 0;
5429 data->wbuffer = NULL;
5430 data->on_close = NULL;
5431
5432 if (file->f_mode & FMODE_WRITE) {
5433 if (!(file->f_mode & FMODE_READ)) {
5434 Cmd cmd;
5435 Resp rsp;
5436
5437 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
5438 memset(&cmd, 0, sizeof(cmd));
5439 cmd.cmd=CMD_LISTBSS;
5440 if (down_interruptible(&ai->sem))
5441 return -ERESTARTSYS;
5442 issuecommand(ai, &cmd, &rsp);
5443 up(&ai->sem);
5444 data->readlen = 0;
5445 return 0;
5446 }
5447 doLoseSync = 1;
5448 }
5449 ptr = data->rbuffer;
5450 /* There is a race condition here if there are concurrent opens.
5451 Since it is a rare condition, we'll just live with it, otherwise
5452 we have to add a spin lock... */
5453 rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
Al Viro17e70492007-12-19 18:56:37 -05005454 while(rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) {
Joe Perches0795af52007-10-03 17:59:30 -07005455 ptr += sprintf(ptr, "%s %*s rssi = %d",
5456 print_mac(mac, BSSList_rid.bssid),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 (int)BSSList_rid.ssidLen,
5458 BSSList_rid.ssid,
Al Viro17e70492007-12-19 18:56:37 -05005459 le16_to_cpu(BSSList_rid.dBm));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460 ptr += sprintf(ptr, " channel = %d %s %s %s %s\n",
Al Viro17e70492007-12-19 18:56:37 -05005461 le16_to_cpu(BSSList_rid.dsChannel),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 BSSList_rid.cap & CAP_ESS ? "ESS" : "",
5463 BSSList_rid.cap & CAP_IBSS ? "adhoc" : "",
5464 BSSList_rid.cap & CAP_PRIVACY ? "wep" : "",
5465 BSSList_rid.cap & CAP_SHORTHDR ? "shorthdr" : "");
5466 rc = readBSSListRid(ai, 0, &BSSList_rid);
5467 }
5468 *ptr = '\0';
5469 data->readlen = strlen( data->rbuffer );
5470 return 0;
5471}
5472
5473static int proc_close( struct inode *inode, struct file *file )
5474{
Jesper Juhlb4558ea2005-10-28 16:53:13 -04005475 struct proc_data *data = file->private_data;
5476
5477 if (data->on_close != NULL)
5478 data->on_close(inode, file);
5479 kfree(data->rbuffer);
5480 kfree(data->wbuffer);
5481 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 return 0;
5483}
5484
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485/* Since the card doesn't automatically switch to the right WEP mode,
5486 we will make it do it. If the card isn't associated, every secs we
5487 will switch WEP modes to see if that will help. If the card is
5488 associated we will check every minute to see if anything has
5489 changed. */
5490static void timer_func( struct net_device *dev ) {
5491 struct airo_info *apriv = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492
5493/* We don't have a link so try changing the authtype */
5494 readConfigRid(apriv, 0);
5495 disable_MAC(apriv, 0);
5496 switch(apriv->config.authType) {
5497 case AUTH_ENCRYPT:
5498/* So drop to OPEN */
5499 apriv->config.authType = AUTH_OPEN;
5500 break;
5501 case AUTH_SHAREDKEY:
5502 if (apriv->keyindex < auto_wep) {
5503 set_wep_key(apriv, apriv->keyindex, NULL, 0, 0, 0);
5504 apriv->config.authType = AUTH_SHAREDKEY;
5505 apriv->keyindex++;
5506 } else {
5507 /* Drop to ENCRYPT */
5508 apriv->keyindex = 0;
5509 set_wep_key(apriv, apriv->defindex, NULL, 0, 0, 0);
5510 apriv->config.authType = AUTH_ENCRYPT;
5511 }
5512 break;
5513 default: /* We'll escalate to SHAREDKEY */
5514 apriv->config.authType = AUTH_SHAREDKEY;
5515 }
5516 set_bit (FLAG_COMMIT, &apriv->flags);
5517 writeConfigRid(apriv, 0);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005518 enable_MAC(apriv, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519 up(&apriv->sem);
5520
5521/* Schedule check to see if the change worked */
Dan Williams3c304952006-04-15 12:26:18 -04005522 clear_bit(JOB_AUTOWEP, &apriv->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 apriv->expires = RUN_AT(HZ*3);
5524}
5525
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526#ifdef CONFIG_PCI
5527static int __devinit airo_pci_probe(struct pci_dev *pdev,
5528 const struct pci_device_id *pent)
5529{
5530 struct net_device *dev;
5531
5532 if (pci_enable_device(pdev))
5533 return -ENODEV;
5534 pci_set_master(pdev);
5535
5536 if (pdev->device == 0x5000 || pdev->device == 0xa504)
5537 dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev);
5538 else
5539 dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev);
Michal Schmidt777ec5e2007-06-29 15:33:30 +02005540 if (!dev) {
5541 pci_disable_device(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 return -ENODEV;
Michal Schmidt777ec5e2007-06-29 15:33:30 +02005543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544
5545 pci_set_drvdata(pdev, dev);
5546 return 0;
5547}
5548
5549static void __devexit airo_pci_remove(struct pci_dev *pdev)
5550{
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01005551 struct net_device *dev = pci_get_drvdata(pdev);
5552
5553 airo_print_info(dev->name, "Unregistering...");
5554 stop_airo_card(dev, 1);
Michal Schmidt777ec5e2007-06-29 15:33:30 +02005555 pci_disable_device(pdev);
5556 pci_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557}
5558
Pavel Machek05adc3b2005-04-16 15:25:25 -07005559static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560{
5561 struct net_device *dev = pci_get_drvdata(pdev);
5562 struct airo_info *ai = dev->priv;
5563 Cmd cmd;
5564 Resp rsp;
5565
5566 if ((ai->APList == NULL) &&
5567 (ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL)) == NULL)
5568 return -ENOMEM;
5569 if ((ai->SSID == NULL) &&
5570 (ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL)) == NULL)
5571 return -ENOMEM;
5572 readAPListRid(ai, ai->APList);
5573 readSsidRid(ai, ai->SSID);
5574 memset(&cmd, 0, sizeof(cmd));
5575 /* the lock will be released at the end of the resume callback */
5576 if (down_interruptible(&ai->sem))
5577 return -EAGAIN;
5578 disable_MAC(ai, 0);
5579 netif_device_detach(dev);
5580 ai->power = state;
5581 cmd.cmd=HOSTSLEEP;
5582 issuecommand(ai, &cmd, &rsp);
5583
Pavel Machek1cc68ae2005-06-20 15:33:04 -07005584 pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 pci_save_state(pdev);
Pavel Machek1cc68ae2005-06-20 15:33:04 -07005586 return pci_set_power_state(pdev, pci_choose_state(pdev, state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587}
5588
5589static int airo_pci_resume(struct pci_dev *pdev)
5590{
5591 struct net_device *dev = pci_get_drvdata(pdev);
5592 struct airo_info *ai = dev->priv;
Michal Schmidt53232802005-10-04 07:46:21 -04005593 pci_power_t prev_state = pdev->current_state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594
Michal Schmidt53232802005-10-04 07:46:21 -04005595 pci_set_power_state(pdev, PCI_D0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596 pci_restore_state(pdev);
Michal Schmidt53232802005-10-04 07:46:21 -04005597 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598
Michal Schmidt53232802005-10-04 07:46:21 -04005599 if (prev_state != PCI_D1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 reset_card(dev, 0);
5601 mpi_init_descriptors(ai);
5602 setup_card(ai, dev->dev_addr, 0);
5603 clear_bit(FLAG_RADIO_OFF, &ai->flags);
5604 clear_bit(FLAG_PENDING_XMIT, &ai->flags);
5605 } else {
5606 OUT4500(ai, EVACK, EV_AWAKEN);
5607 OUT4500(ai, EVACK, EV_AWAKEN);
5608 msleep(100);
5609 }
5610
5611 set_bit (FLAG_COMMIT, &ai->flags);
5612 disable_MAC(ai, 0);
5613 msleep(200);
5614 if (ai->SSID) {
5615 writeSsidRid(ai, ai->SSID, 0);
5616 kfree(ai->SSID);
5617 ai->SSID = NULL;
5618 }
5619 if (ai->APList) {
5620 writeAPListRid(ai, ai->APList, 0);
5621 kfree(ai->APList);
5622 ai->APList = NULL;
5623 }
5624 writeConfigRid(ai, 0);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005625 enable_MAC(ai, 0);
Pavel Machek1cc68ae2005-06-20 15:33:04 -07005626 ai->power = PMSG_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627 netif_device_attach(dev);
5628 netif_wake_queue(dev);
5629 enable_interrupts(ai);
5630 up(&ai->sem);
5631 return 0;
5632}
5633#endif
5634
5635static int __init airo_init_module( void )
5636{
Jeff Garzikde897882006-10-01 07:31:09 -04005637 int i;
5638#if 0
5639 int have_isa_dev = 0;
5640#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641
5642 airo_entry = create_proc_entry("aironet",
5643 S_IFDIR | airo_perm,
5644 proc_root_driver);
Jeff Garzikde897882006-10-01 07:31:09 -04005645
5646 if (airo_entry) {
5647 airo_entry->uid = proc_uid;
5648 airo_entry->gid = proc_gid;
5649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650
5651 for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05005652 airo_print_info("", "Trying to configure ISA adapter at irq=%d "
5653 "io=0x%x", irq[i], io[i] );
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654 if (init_airo_card( irq[i], io[i], 0, NULL ))
Jeff Garzikde897882006-10-01 07:31:09 -04005655#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 have_isa_dev = 1;
Jeff Garzikde897882006-10-01 07:31:09 -04005657#else
5658 /* do nothing */ ;
5659#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 }
5661
5662#ifdef CONFIG_PCI
Dan Williams934d8bf2006-03-16 13:46:23 -05005663 airo_print_info("", "Probing for PCI adapters");
Jeff Garzikde897882006-10-01 07:31:09 -04005664 i = pci_register_driver(&airo_driver);
Dan Williams934d8bf2006-03-16 13:46:23 -05005665 airo_print_info("", "Finished probing for PCI adapters");
Jeff Garzikde897882006-10-01 07:31:09 -04005666
5667 if (i) {
5668 remove_proc_entry("aironet", proc_root_driver);
5669 return i;
5670 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671#endif
5672
5673 /* Always exit with success, as we are a library module
5674 * as well as a driver module
5675 */
5676 return 0;
5677}
5678
5679static void __exit airo_cleanup_module( void )
5680{
Michal Schmidtaf5b5c92007-03-16 12:44:40 +01005681 struct airo_info *ai;
5682 while(!list_empty(&airo_devices)) {
5683 ai = list_entry(airo_devices.next, struct airo_info, dev_list);
5684 airo_print_info(ai->dev->name, "Unregistering...");
5685 stop_airo_card(ai->dev, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686 }
5687#ifdef CONFIG_PCI
5688 pci_unregister_driver(&airo_driver);
5689#endif
5690 remove_proc_entry("aironet", proc_root_driver);
5691}
5692
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693/*
5694 * Initial Wireless Extension code for Aironet driver by :
5695 * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 17 November 00
5696 * Conversion to new driver API by :
5697 * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 26 March 02
5698 * Javier also did a good amount of work here, adding some new extensions
5699 * and fixing my code. Let's just say that without him this code just
5700 * would not work at all... - Jean II
5701 */
5702
Dan Williams41480af2005-05-10 09:45:51 -04005703static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi)
5704{
5705 if( !rssi_rid )
5706 return 0;
5707
5708 return (0x100 - rssi_rid[rssi].rssidBm);
5709}
5710
5711static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
5712{
5713 int i;
5714
5715 if( !rssi_rid )
5716 return 0;
5717
5718 for( i = 0; i < 256; i++ )
5719 if (rssi_rid[i].rssidBm == dbm)
5720 return rssi_rid[i].rssipct;
5721
5722 return 0;
5723}
5724
5725
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid)
5727{
5728 int quality = 0;
5729
Al Viro56d81bd2007-12-20 17:18:35 -05005730 if ((status_rid->mode & 0x3f) != 0x3f)
5731 return 0;
5732
5733 if (!(cap_rid->hardCap & cpu_to_le16(8)))
5734 return 0;
5735
5736 if (memcmp(cap_rid->prodName, "350", 3))
5737 if (status_rid->signalQuality > 0x20)
5738 quality = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739 else
Al Viro56d81bd2007-12-20 17:18:35 -05005740 quality = 0x20 - status_rid->signalQuality;
5741 else
5742 if (status_rid->signalQuality > 0xb0)
5743 quality = 0;
5744 else if (status_rid->signalQuality < 0x10)
5745 quality = 0xa0;
5746 else
5747 quality = 0xb0 - status_rid->signalQuality;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748 return quality;
5749}
5750
5751#define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0)
5752#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50);
5753
5754/*------------------------------------------------------------------*/
5755/*
5756 * Wireless Handler : get protocol name
5757 */
5758static int airo_get_name(struct net_device *dev,
5759 struct iw_request_info *info,
5760 char *cwrq,
5761 char *extra)
5762{
5763 strcpy(cwrq, "IEEE 802.11-DS");
5764 return 0;
5765}
5766
5767/*------------------------------------------------------------------*/
5768/*
5769 * Wireless Handler : set frequency
5770 */
5771static int airo_set_freq(struct net_device *dev,
5772 struct iw_request_info *info,
5773 struct iw_freq *fwrq,
5774 char *extra)
5775{
5776 struct airo_info *local = dev->priv;
5777 int rc = -EINPROGRESS; /* Call commit handler */
5778
5779 /* If setting by frequency, convert to a channel */
5780 if((fwrq->e == 1) &&
5781 (fwrq->m >= (int) 2.412e8) &&
5782 (fwrq->m <= (int) 2.487e8)) {
5783 int f = fwrq->m / 100000;
5784 int c = 0;
5785 while((c < 14) && (f != frequency_list[c]))
5786 c++;
5787 /* Hack to fall through... */
5788 fwrq->e = 0;
5789 fwrq->m = c + 1;
5790 }
5791 /* Setting by channel number */
5792 if((fwrq->m > 1000) || (fwrq->e > 0))
5793 rc = -EOPNOTSUPP;
5794 else {
5795 int channel = fwrq->m;
5796 /* We should do a better check than that,
5797 * based on the card capability !!! */
Javier Achirica2610c732006-01-17 08:01:01 -05005798 if((channel < 1) || (channel > 14)) {
Dan Williams934d8bf2006-03-16 13:46:23 -05005799 airo_print_dbg(dev->name, "New channel value of %d is invalid!",
5800 fwrq->m);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005801 rc = -EINVAL;
5802 } else {
5803 readConfigRid(local, 1);
5804 /* Yes ! We can set it !!! */
Javier Achirica2610c732006-01-17 08:01:01 -05005805 local->config.channelSet = (u16) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806 set_bit (FLAG_COMMIT, &local->flags);
5807 }
5808 }
5809 return rc;
5810}
5811
5812/*------------------------------------------------------------------*/
5813/*
5814 * Wireless Handler : get frequency
5815 */
5816static int airo_get_freq(struct net_device *dev,
5817 struct iw_request_info *info,
5818 struct iw_freq *fwrq,
5819 char *extra)
5820{
5821 struct airo_info *local = dev->priv;
5822 StatusRid status_rid; /* Card status info */
Javier Achirica2610c732006-01-17 08:01:01 -05005823 int ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005824
5825 readConfigRid(local, 1);
5826 if ((local->config.opmode & 0xFF) == MODE_STA_ESS)
5827 status_rid.channel = local->config.channelSet;
5828 else
5829 readStatusRid(local, &status_rid, 1);
5830
Javier Achirica2610c732006-01-17 08:01:01 -05005831 ch = (int)status_rid.channel;
5832 if((ch > 0) && (ch < 15)) {
5833 fwrq->m = frequency_list[ch - 1] * 100000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005834 fwrq->e = 1;
Javier Achirica2610c732006-01-17 08:01:01 -05005835 } else {
5836 fwrq->m = ch;
5837 fwrq->e = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005839
5840 return 0;
5841}
5842
5843/*------------------------------------------------------------------*/
5844/*
5845 * Wireless Handler : set ESSID
5846 */
5847static int airo_set_essid(struct net_device *dev,
5848 struct iw_request_info *info,
5849 struct iw_point *dwrq,
5850 char *extra)
5851{
5852 struct airo_info *local = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005853 SsidRid SSID_rid; /* SSIDs */
5854
5855 /* Reload the list of current SSID */
5856 readSsidRid(local, &SSID_rid);
5857
5858 /* Check if we asked for `any' */
5859 if(dwrq->flags == 0) {
5860 /* Just send an empty SSID list */
5861 memset(&SSID_rid, 0, sizeof(SSID_rid));
5862 } else {
5863 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
5864
5865 /* Check the size of the string */
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07005866 if(dwrq->length > IW_ESSID_MAX_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867 return -E2BIG ;
5868 }
5869 /* Check if index is valid */
5870 if((index < 0) || (index >= 4)) {
5871 return -EINVAL;
5872 }
5873
5874 /* Set the SSID */
5875 memset(SSID_rid.ssids[index].ssid, 0,
5876 sizeof(SSID_rid.ssids[index].ssid));
5877 memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
Al Viro0dd22122007-12-17 16:11:57 -05005878 SSID_rid.ssids[index].len = cpu_to_le16(dwrq->length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005879 }
Al Viro0dd22122007-12-17 16:11:57 -05005880 SSID_rid.len = cpu_to_le16(sizeof(SSID_rid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881 /* Write it to the card */
5882 disable_MAC(local, 1);
5883 writeSsidRid(local, &SSID_rid, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005884 enable_MAC(local, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885
5886 return 0;
5887}
5888
5889/*------------------------------------------------------------------*/
5890/*
5891 * Wireless Handler : get ESSID
5892 */
5893static int airo_get_essid(struct net_device *dev,
5894 struct iw_request_info *info,
5895 struct iw_point *dwrq,
5896 char *extra)
5897{
5898 struct airo_info *local = dev->priv;
5899 StatusRid status_rid; /* Card status info */
5900
5901 readStatusRid(local, &status_rid, 1);
5902
5903 /* Note : if dwrq->flags != 0, we should
5904 * get the relevant SSID from the SSID list... */
5905
5906 /* Get the current SSID */
5907 memcpy(extra, status_rid.SSID, status_rid.SSIDlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908 /* If none, we may want to get the one that was set */
5909
5910 /* Push it out ! */
Dan Williamsd6a13a22006-01-12 15:00:58 -05005911 dwrq->length = status_rid.SSIDlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912 dwrq->flags = 1; /* active */
5913
5914 return 0;
5915}
5916
5917/*------------------------------------------------------------------*/
5918/*
5919 * Wireless Handler : set AP address
5920 */
5921static int airo_set_wap(struct net_device *dev,
5922 struct iw_request_info *info,
5923 struct sockaddr *awrq,
5924 char *extra)
5925{
5926 struct airo_info *local = dev->priv;
5927 Cmd cmd;
5928 Resp rsp;
5929 APListRid APList_rid;
Dan Williams4be757d2006-01-30 11:58:00 -05005930 static const u8 any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
5931 static const u8 off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932
5933 if (awrq->sa_family != ARPHRD_ETHER)
5934 return -EINVAL;
Dan Williams4be757d2006-01-30 11:58:00 -05005935 else if (!memcmp(any, awrq->sa_data, ETH_ALEN) ||
5936 !memcmp(off, awrq->sa_data, ETH_ALEN)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937 memset(&cmd, 0, sizeof(cmd));
5938 cmd.cmd=CMD_LOSE_SYNC;
5939 if (down_interruptible(&local->sem))
5940 return -ERESTARTSYS;
5941 issuecommand(local, &cmd, &rsp);
5942 up(&local->sem);
5943 } else {
5944 memset(&APList_rid, 0, sizeof(APList_rid));
Al Viroa7497162007-12-20 17:49:41 -05005945 APList_rid.len = cpu_to_le16(sizeof(APList_rid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946 memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN);
5947 disable_MAC(local, 1);
5948 writeAPListRid(local, &APList_rid, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02005949 enable_MAC(local, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950 }
5951 return 0;
5952}
5953
5954/*------------------------------------------------------------------*/
5955/*
5956 * Wireless Handler : get AP address
5957 */
5958static int airo_get_wap(struct net_device *dev,
5959 struct iw_request_info *info,
5960 struct sockaddr *awrq,
5961 char *extra)
5962{
5963 struct airo_info *local = dev->priv;
5964 StatusRid status_rid; /* Card status info */
5965
5966 readStatusRid(local, &status_rid, 1);
5967
5968 /* Tentative. This seems to work, wow, I'm lucky !!! */
5969 memcpy(awrq->sa_data, status_rid.bssid[0], ETH_ALEN);
5970 awrq->sa_family = ARPHRD_ETHER;
5971
5972 return 0;
5973}
5974
5975/*------------------------------------------------------------------*/
5976/*
5977 * Wireless Handler : set Nickname
5978 */
5979static int airo_set_nick(struct net_device *dev,
5980 struct iw_request_info *info,
5981 struct iw_point *dwrq,
5982 char *extra)
5983{
5984 struct airo_info *local = dev->priv;
5985
5986 /* Check the size of the string */
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07005987 if(dwrq->length > 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988 return -E2BIG;
5989 }
5990 readConfigRid(local, 1);
5991 memset(local->config.nodeName, 0, sizeof(local->config.nodeName));
5992 memcpy(local->config.nodeName, extra, dwrq->length);
5993 set_bit (FLAG_COMMIT, &local->flags);
5994
5995 return -EINPROGRESS; /* Call commit handler */
5996}
5997
5998/*------------------------------------------------------------------*/
5999/*
6000 * Wireless Handler : get Nickname
6001 */
6002static int airo_get_nick(struct net_device *dev,
6003 struct iw_request_info *info,
6004 struct iw_point *dwrq,
6005 char *extra)
6006{
6007 struct airo_info *local = dev->priv;
6008
6009 readConfigRid(local, 1);
6010 strncpy(extra, local->config.nodeName, 16);
6011 extra[16] = '\0';
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006012 dwrq->length = strlen(extra);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006013
6014 return 0;
6015}
6016
6017/*------------------------------------------------------------------*/
6018/*
6019 * Wireless Handler : set Bit-Rate
6020 */
6021static int airo_set_rate(struct net_device *dev,
6022 struct iw_request_info *info,
6023 struct iw_param *vwrq,
6024 char *extra)
6025{
6026 struct airo_info *local = dev->priv;
6027 CapabilityRid cap_rid; /* Card capability info */
6028 u8 brate = 0;
6029 int i;
6030
6031 /* First : get a valid bit rate value */
6032 readCapabilityRid(local, &cap_rid, 1);
6033
6034 /* Which type of value ? */
6035 if((vwrq->value < 8) && (vwrq->value >= 0)) {
6036 /* Setting by rate index */
6037 /* Find value in the magic rate table */
6038 brate = cap_rid.supportedRates[vwrq->value];
6039 } else {
6040 /* Setting by frequency value */
6041 u8 normvalue = (u8) (vwrq->value/500000);
6042
6043 /* Check if rate is valid */
6044 for(i = 0 ; i < 8 ; i++) {
6045 if(normvalue == cap_rid.supportedRates[i]) {
6046 brate = normvalue;
6047 break;
6048 }
6049 }
6050 }
6051 /* -1 designed the max rate (mostly auto mode) */
6052 if(vwrq->value == -1) {
6053 /* Get the highest available rate */
6054 for(i = 0 ; i < 8 ; i++) {
6055 if(cap_rid.supportedRates[i] == 0)
6056 break;
6057 }
6058 if(i != 0)
6059 brate = cap_rid.supportedRates[i - 1];
6060 }
6061 /* Check that it is valid */
6062 if(brate == 0) {
6063 return -EINVAL;
6064 }
6065
6066 readConfigRid(local, 1);
6067 /* Now, check if we want a fixed or auto value */
6068 if(vwrq->fixed == 0) {
6069 /* Fill all the rates up to this max rate */
6070 memset(local->config.rates, 0, 8);
6071 for(i = 0 ; i < 8 ; i++) {
6072 local->config.rates[i] = cap_rid.supportedRates[i];
6073 if(local->config.rates[i] == brate)
6074 break;
6075 }
6076 } else {
6077 /* Fixed mode */
6078 /* One rate, fixed */
6079 memset(local->config.rates, 0, 8);
6080 local->config.rates[0] = brate;
6081 }
6082 set_bit (FLAG_COMMIT, &local->flags);
6083
6084 return -EINPROGRESS; /* Call commit handler */
6085}
6086
6087/*------------------------------------------------------------------*/
6088/*
6089 * Wireless Handler : get Bit-Rate
6090 */
6091static int airo_get_rate(struct net_device *dev,
6092 struct iw_request_info *info,
6093 struct iw_param *vwrq,
6094 char *extra)
6095{
6096 struct airo_info *local = dev->priv;
6097 StatusRid status_rid; /* Card status info */
6098
6099 readStatusRid(local, &status_rid, 1);
6100
6101 vwrq->value = status_rid.currentXmitRate * 500000;
6102 /* If more than one rate, set auto */
6103 readConfigRid(local, 1);
6104 vwrq->fixed = (local->config.rates[1] == 0);
6105
6106 return 0;
6107}
6108
6109/*------------------------------------------------------------------*/
6110/*
6111 * Wireless Handler : set RTS threshold
6112 */
6113static int airo_set_rts(struct net_device *dev,
6114 struct iw_request_info *info,
6115 struct iw_param *vwrq,
6116 char *extra)
6117{
6118 struct airo_info *local = dev->priv;
6119 int rthr = vwrq->value;
6120
6121 if(vwrq->disabled)
Dan Williams15db2762006-03-16 13:46:27 -05006122 rthr = AIRO_DEF_MTU;
6123 if((rthr < 0) || (rthr > AIRO_DEF_MTU)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006124 return -EINVAL;
6125 }
6126 readConfigRid(local, 1);
6127 local->config.rtsThres = rthr;
6128 set_bit (FLAG_COMMIT, &local->flags);
6129
6130 return -EINPROGRESS; /* Call commit handler */
6131}
6132
6133/*------------------------------------------------------------------*/
6134/*
6135 * Wireless Handler : get RTS threshold
6136 */
6137static int airo_get_rts(struct net_device *dev,
6138 struct iw_request_info *info,
6139 struct iw_param *vwrq,
6140 char *extra)
6141{
6142 struct airo_info *local = dev->priv;
6143
6144 readConfigRid(local, 1);
6145 vwrq->value = local->config.rtsThres;
Dan Williams15db2762006-03-16 13:46:27 -05006146 vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147 vwrq->fixed = 1;
6148
6149 return 0;
6150}
6151
6152/*------------------------------------------------------------------*/
6153/*
6154 * Wireless Handler : set Fragmentation threshold
6155 */
6156static int airo_set_frag(struct net_device *dev,
6157 struct iw_request_info *info,
6158 struct iw_param *vwrq,
6159 char *extra)
6160{
6161 struct airo_info *local = dev->priv;
6162 int fthr = vwrq->value;
6163
6164 if(vwrq->disabled)
Dan Williams15db2762006-03-16 13:46:27 -05006165 fthr = AIRO_DEF_MTU;
6166 if((fthr < 256) || (fthr > AIRO_DEF_MTU)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006167 return -EINVAL;
6168 }
6169 fthr &= ~0x1; /* Get an even value - is it really needed ??? */
6170 readConfigRid(local, 1);
6171 local->config.fragThresh = (u16)fthr;
6172 set_bit (FLAG_COMMIT, &local->flags);
6173
6174 return -EINPROGRESS; /* Call commit handler */
6175}
6176
6177/*------------------------------------------------------------------*/
6178/*
6179 * Wireless Handler : get Fragmentation threshold
6180 */
6181static int airo_get_frag(struct net_device *dev,
6182 struct iw_request_info *info,
6183 struct iw_param *vwrq,
6184 char *extra)
6185{
6186 struct airo_info *local = dev->priv;
6187
6188 readConfigRid(local, 1);
6189 vwrq->value = local->config.fragThresh;
Dan Williams15db2762006-03-16 13:46:27 -05006190 vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006191 vwrq->fixed = 1;
6192
6193 return 0;
6194}
6195
6196/*------------------------------------------------------------------*/
6197/*
6198 * Wireless Handler : set Mode of Operation
6199 */
6200static int airo_set_mode(struct net_device *dev,
6201 struct iw_request_info *info,
6202 __u32 *uwrq,
6203 char *extra)
6204{
6205 struct airo_info *local = dev->priv;
6206 int reset = 0;
6207
6208 readConfigRid(local, 1);
6209 if ((local->config.rmode & 0xff) >= RXMODE_RFMON)
6210 reset = 1;
6211
6212 switch(*uwrq) {
6213 case IW_MODE_ADHOC:
6214 local->config.opmode &= 0xFF00;
6215 local->config.opmode |= MODE_STA_IBSS;
6216 local->config.rmode &= 0xfe00;
6217 local->config.scanMode = SCANMODE_ACTIVE;
6218 clear_bit (FLAG_802_11, &local->flags);
6219 break;
6220 case IW_MODE_INFRA:
6221 local->config.opmode &= 0xFF00;
6222 local->config.opmode |= MODE_STA_ESS;
6223 local->config.rmode &= 0xfe00;
6224 local->config.scanMode = SCANMODE_ACTIVE;
6225 clear_bit (FLAG_802_11, &local->flags);
6226 break;
6227 case IW_MODE_MASTER:
6228 local->config.opmode &= 0xFF00;
6229 local->config.opmode |= MODE_AP;
6230 local->config.rmode &= 0xfe00;
6231 local->config.scanMode = SCANMODE_ACTIVE;
6232 clear_bit (FLAG_802_11, &local->flags);
6233 break;
6234 case IW_MODE_REPEAT:
6235 local->config.opmode &= 0xFF00;
6236 local->config.opmode |= MODE_AP_RPTR;
6237 local->config.rmode &= 0xfe00;
6238 local->config.scanMode = SCANMODE_ACTIVE;
6239 clear_bit (FLAG_802_11, &local->flags);
6240 break;
6241 case IW_MODE_MONITOR:
6242 local->config.opmode &= 0xFF00;
6243 local->config.opmode |= MODE_STA_ESS;
6244 local->config.rmode &= 0xfe00;
6245 local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
6246 local->config.scanMode = SCANMODE_PASSIVE;
6247 set_bit (FLAG_802_11, &local->flags);
6248 break;
6249 default:
6250 return -EINVAL;
6251 }
6252 if (reset)
6253 set_bit (FLAG_RESET, &local->flags);
6254 set_bit (FLAG_COMMIT, &local->flags);
6255
6256 return -EINPROGRESS; /* Call commit handler */
6257}
6258
6259/*------------------------------------------------------------------*/
6260/*
6261 * Wireless Handler : get Mode of Operation
6262 */
6263static int airo_get_mode(struct net_device *dev,
6264 struct iw_request_info *info,
6265 __u32 *uwrq,
6266 char *extra)
6267{
6268 struct airo_info *local = dev->priv;
6269
6270 readConfigRid(local, 1);
6271 /* If not managed, assume it's ad-hoc */
6272 switch (local->config.opmode & 0xFF) {
6273 case MODE_STA_ESS:
6274 *uwrq = IW_MODE_INFRA;
6275 break;
6276 case MODE_AP:
6277 *uwrq = IW_MODE_MASTER;
6278 break;
6279 case MODE_AP_RPTR:
6280 *uwrq = IW_MODE_REPEAT;
6281 break;
6282 default:
6283 *uwrq = IW_MODE_ADHOC;
6284 }
6285
6286 return 0;
6287}
6288
Al Viro56d81bd2007-12-20 17:18:35 -05006289static inline int valid_index(CapabilityRid *p, int index)
6290{
6291 if (index < 0)
6292 return 0;
6293 return index < (p->softCap & cpu_to_le16(0x80) ? 4 : 1);
6294}
6295
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296/*------------------------------------------------------------------*/
6297/*
6298 * Wireless Handler : set Encryption Key
6299 */
6300static int airo_set_encode(struct net_device *dev,
6301 struct iw_request_info *info,
6302 struct iw_point *dwrq,
6303 char *extra)
6304{
6305 struct airo_info *local = dev->priv;
6306 CapabilityRid cap_rid; /* Card capability info */
Dan Streetmanf89b2322005-11-11 11:41:42 -05006307 int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 );
6308 u16 currentAuthType = local->config.authType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006309
6310 /* Is WEP supported ? */
6311 readCapabilityRid(local, &cap_rid, 1);
6312 /* Older firmware doesn't support this...
Al Viro56d81bd2007-12-20 17:18:35 -05006313 if(!(cap_rid.softCap & cpu_to_le16(2))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006314 return -EOPNOTSUPP;
6315 } */
6316 readConfigRid(local, 1);
6317
6318 /* Basic checking: do we have a key to set ?
6319 * Note : with the new API, it's impossible to get a NULL pointer.
6320 * Therefore, we need to check a key size == 0 instead.
6321 * New version of iwconfig properly set the IW_ENCODE_NOKEY flag
6322 * when no key is present (only change flags), but older versions
6323 * don't do it. - Jean II */
6324 if (dwrq->length > 0) {
6325 wep_key_t key;
6326 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
6327 int current_index = get_wep_key(local, 0xffff);
6328 /* Check the size of the key */
6329 if (dwrq->length > MAX_KEY_SIZE) {
6330 return -EINVAL;
6331 }
6332 /* Check the index (none -> use current) */
Al Viro56d81bd2007-12-20 17:18:35 -05006333 if (!valid_index(&cap_rid, index))
Linus Torvalds1da177e2005-04-16 15:20:36 -07006334 index = current_index;
6335 /* Set the length */
6336 if (dwrq->length > MIN_KEY_SIZE)
6337 key.len = MAX_KEY_SIZE;
6338 else
6339 if (dwrq->length > 0)
6340 key.len = MIN_KEY_SIZE;
6341 else
6342 /* Disable the key */
6343 key.len = 0;
6344 /* Check if the key is not marked as invalid */
6345 if(!(dwrq->flags & IW_ENCODE_NOKEY)) {
6346 /* Cleanup */
6347 memset(key.key, 0, MAX_KEY_SIZE);
6348 /* Copy the key in the driver */
6349 memcpy(key.key, extra, dwrq->length);
6350 /* Send the key to the card */
Dan Streetmanf89b2322005-11-11 11:41:42 -05006351 set_wep_key(local, index, key.key, key.len, perm, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006352 }
6353 /* WE specify that if a valid key is set, encryption
6354 * should be enabled (user may turn it off later)
6355 * This is also how "iwconfig ethX key on" works */
6356 if((index == current_index) && (key.len > 0) &&
6357 (local->config.authType == AUTH_OPEN)) {
6358 local->config.authType = AUTH_ENCRYPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006359 }
6360 } else {
6361 /* Do we want to just set the transmit key index ? */
6362 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
Al Viro56d81bd2007-12-20 17:18:35 -05006363 if (valid_index(&cap_rid, index)) {
Dan Streetmanf89b2322005-11-11 11:41:42 -05006364 set_wep_key(local, index, NULL, 0, perm, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006365 } else
6366 /* Don't complain if only change the mode */
Jeff Garzik93a3b602007-11-23 21:50:20 -05006367 if (!(dwrq->flags & IW_ENCODE_MODE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369 }
6370 /* Read the flags */
6371 if(dwrq->flags & IW_ENCODE_DISABLED)
6372 local->config.authType = AUTH_OPEN; // disable encryption
6373 if(dwrq->flags & IW_ENCODE_RESTRICTED)
6374 local->config.authType = AUTH_SHAREDKEY; // Only Both
6375 if(dwrq->flags & IW_ENCODE_OPEN)
6376 local->config.authType = AUTH_ENCRYPT; // Only Wep
6377 /* Commit the changes to flags if needed */
Dan Streetmanf89b2322005-11-11 11:41:42 -05006378 if (local->config.authType != currentAuthType)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006379 set_bit (FLAG_COMMIT, &local->flags);
6380 return -EINPROGRESS; /* Call commit handler */
6381}
6382
6383/*------------------------------------------------------------------*/
6384/*
6385 * Wireless Handler : get Encryption Key
6386 */
6387static int airo_get_encode(struct net_device *dev,
6388 struct iw_request_info *info,
6389 struct iw_point *dwrq,
6390 char *extra)
6391{
6392 struct airo_info *local = dev->priv;
6393 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
6394 CapabilityRid cap_rid; /* Card capability info */
6395
6396 /* Is it supported ? */
6397 readCapabilityRid(local, &cap_rid, 1);
Al Viro56d81bd2007-12-20 17:18:35 -05006398 if(!(cap_rid.softCap & cpu_to_le16(2))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399 return -EOPNOTSUPP;
6400 }
6401 readConfigRid(local, 1);
6402 /* Check encryption mode */
6403 switch(local->config.authType) {
6404 case AUTH_ENCRYPT:
6405 dwrq->flags = IW_ENCODE_OPEN;
6406 break;
6407 case AUTH_SHAREDKEY:
6408 dwrq->flags = IW_ENCODE_RESTRICTED;
6409 break;
6410 default:
6411 case AUTH_OPEN:
6412 dwrq->flags = IW_ENCODE_DISABLED;
6413 break;
6414 }
6415 /* We can't return the key, so set the proper flag and return zero */
6416 dwrq->flags |= IW_ENCODE_NOKEY;
6417 memset(extra, 0, 16);
6418
6419 /* Which key do we want ? -1 -> tx index */
Al Viro56d81bd2007-12-20 17:18:35 -05006420 if (!valid_index(&cap_rid, index))
Linus Torvalds1da177e2005-04-16 15:20:36 -07006421 index = get_wep_key(local, 0xffff);
6422 dwrq->flags |= index + 1;
6423 /* Copy the key to the user buffer */
6424 dwrq->length = get_wep_key(local, index);
6425 if (dwrq->length > 16) {
6426 dwrq->length=0;
6427 }
6428 return 0;
6429}
6430
6431/*------------------------------------------------------------------*/
6432/*
Dan Williams4be757d2006-01-30 11:58:00 -05006433 * Wireless Handler : set extended Encryption parameters
6434 */
6435static int airo_set_encodeext(struct net_device *dev,
6436 struct iw_request_info *info,
6437 union iwreq_data *wrqu,
6438 char *extra)
6439{
6440 struct airo_info *local = dev->priv;
6441 struct iw_point *encoding = &wrqu->encoding;
6442 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
6443 CapabilityRid cap_rid; /* Card capability info */
6444 int perm = ( encoding->flags & IW_ENCODE_TEMP ? 0 : 1 );
6445 u16 currentAuthType = local->config.authType;
Dan Williams22d88462006-02-05 18:00:30 -05006446 int idx, key_len, alg = ext->alg, set_key = 1;
Dan Williams4be757d2006-01-30 11:58:00 -05006447 wep_key_t key;
6448
6449 /* Is WEP supported ? */
6450 readCapabilityRid(local, &cap_rid, 1);
6451 /* Older firmware doesn't support this...
Al Viro56d81bd2007-12-20 17:18:35 -05006452 if(!(cap_rid.softCap & cpu_to_le16(2))) {
Dan Williams4be757d2006-01-30 11:58:00 -05006453 return -EOPNOTSUPP;
6454 } */
6455 readConfigRid(local, 1);
6456
6457 /* Determine and validate the key index */
6458 idx = encoding->flags & IW_ENCODE_INDEX;
6459 if (idx) {
Al Viro56d81bd2007-12-20 17:18:35 -05006460 if (!valid_index(&cap_rid, idx - 1))
Dan Williams4be757d2006-01-30 11:58:00 -05006461 return -EINVAL;
6462 idx--;
6463 } else
6464 idx = get_wep_key(local, 0xffff);
6465
6466 if (encoding->flags & IW_ENCODE_DISABLED)
6467 alg = IW_ENCODE_ALG_NONE;
6468
Dan Williams4be757d2006-01-30 11:58:00 -05006469 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
Dan Williams22d88462006-02-05 18:00:30 -05006470 /* Only set transmit key index here, actual
6471 * key is set below if needed.
6472 */
Dan Williams4be757d2006-01-30 11:58:00 -05006473 set_wep_key(local, idx, NULL, 0, perm, 1);
Dan Williams22d88462006-02-05 18:00:30 -05006474 set_key = ext->key_len > 0 ? 1 : 0;
6475 }
6476
6477 if (set_key) {
Dan Williams4be757d2006-01-30 11:58:00 -05006478 /* Set the requested key first */
6479 memset(key.key, 0, MAX_KEY_SIZE);
6480 switch (alg) {
6481 case IW_ENCODE_ALG_NONE:
6482 key.len = 0;
6483 break;
6484 case IW_ENCODE_ALG_WEP:
6485 if (ext->key_len > MIN_KEY_SIZE) {
6486 key.len = MAX_KEY_SIZE;
6487 } else if (ext->key_len > 0) {
6488 key.len = MIN_KEY_SIZE;
6489 } else {
6490 return -EINVAL;
6491 }
6492 key_len = min (ext->key_len, key.len);
6493 memcpy(key.key, ext->key, key_len);
6494 break;
6495 default:
6496 return -EINVAL;
6497 }
6498 /* Send the key to the card */
6499 set_wep_key(local, idx, key.key, key.len, perm, 1);
6500 }
6501
6502 /* Read the flags */
6503 if(encoding->flags & IW_ENCODE_DISABLED)
6504 local->config.authType = AUTH_OPEN; // disable encryption
6505 if(encoding->flags & IW_ENCODE_RESTRICTED)
6506 local->config.authType = AUTH_SHAREDKEY; // Only Both
6507 if(encoding->flags & IW_ENCODE_OPEN)
6508 local->config.authType = AUTH_ENCRYPT; // Only Wep
6509 /* Commit the changes to flags if needed */
6510 if (local->config.authType != currentAuthType)
6511 set_bit (FLAG_COMMIT, &local->flags);
6512
6513 return -EINPROGRESS;
6514}
6515
6516
6517/*------------------------------------------------------------------*/
6518/*
6519 * Wireless Handler : get extended Encryption parameters
6520 */
6521static int airo_get_encodeext(struct net_device *dev,
6522 struct iw_request_info *info,
6523 union iwreq_data *wrqu,
6524 char *extra)
6525{
6526 struct airo_info *local = dev->priv;
6527 struct iw_point *encoding = &wrqu->encoding;
6528 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
6529 CapabilityRid cap_rid; /* Card capability info */
6530 int idx, max_key_len;
6531
6532 /* Is it supported ? */
6533 readCapabilityRid(local, &cap_rid, 1);
Al Viro56d81bd2007-12-20 17:18:35 -05006534 if(!(cap_rid.softCap & cpu_to_le16(2))) {
Dan Williams4be757d2006-01-30 11:58:00 -05006535 return -EOPNOTSUPP;
6536 }
6537 readConfigRid(local, 1);
6538
6539 max_key_len = encoding->length - sizeof(*ext);
6540 if (max_key_len < 0)
6541 return -EINVAL;
6542
6543 idx = encoding->flags & IW_ENCODE_INDEX;
6544 if (idx) {
Al Viro56d81bd2007-12-20 17:18:35 -05006545 if (!valid_index(&cap_rid, idx - 1))
Dan Williams4be757d2006-01-30 11:58:00 -05006546 return -EINVAL;
6547 idx--;
6548 } else
6549 idx = get_wep_key(local, 0xffff);
6550
6551 encoding->flags = idx + 1;
6552 memset(ext, 0, sizeof(*ext));
6553
6554 /* Check encryption mode */
6555 switch(local->config.authType) {
6556 case AUTH_ENCRYPT:
6557 encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
6558 break;
6559 case AUTH_SHAREDKEY:
6560 encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
6561 break;
6562 default:
6563 case AUTH_OPEN:
6564 encoding->flags = IW_ENCODE_ALG_NONE | IW_ENCODE_DISABLED;
6565 break;
6566 }
6567 /* We can't return the key, so set the proper flag and return zero */
6568 encoding->flags |= IW_ENCODE_NOKEY;
6569 memset(extra, 0, 16);
6570
6571 /* Copy the key to the user buffer */
6572 ext->key_len = get_wep_key(local, idx);
6573 if (ext->key_len > 16) {
6574 ext->key_len=0;
6575 }
6576
6577 return 0;
6578}
6579
6580
6581/*------------------------------------------------------------------*/
6582/*
6583 * Wireless Handler : set extended authentication parameters
6584 */
6585static int airo_set_auth(struct net_device *dev,
6586 struct iw_request_info *info,
6587 union iwreq_data *wrqu, char *extra)
6588{
6589 struct airo_info *local = dev->priv;
6590 struct iw_param *param = &wrqu->param;
6591 u16 currentAuthType = local->config.authType;
6592
6593 switch (param->flags & IW_AUTH_INDEX) {
6594 case IW_AUTH_WPA_VERSION:
6595 case IW_AUTH_CIPHER_PAIRWISE:
6596 case IW_AUTH_CIPHER_GROUP:
6597 case IW_AUTH_KEY_MGMT:
6598 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
6599 case IW_AUTH_PRIVACY_INVOKED:
6600 /*
6601 * airo does not use these parameters
6602 */
6603 break;
6604
6605 case IW_AUTH_DROP_UNENCRYPTED:
6606 if (param->value) {
6607 /* Only change auth type if unencrypted */
6608 if (currentAuthType == AUTH_OPEN)
6609 local->config.authType = AUTH_ENCRYPT;
6610 } else {
6611 local->config.authType = AUTH_OPEN;
6612 }
6613
6614 /* Commit the changes to flags if needed */
6615 if (local->config.authType != currentAuthType)
6616 set_bit (FLAG_COMMIT, &local->flags);
6617 break;
6618
6619 case IW_AUTH_80211_AUTH_ALG: {
6620 /* FIXME: What about AUTH_OPEN? This API seems to
6621 * disallow setting our auth to AUTH_OPEN.
6622 */
6623 if (param->value & IW_AUTH_ALG_SHARED_KEY) {
6624 local->config.authType = AUTH_SHAREDKEY;
6625 } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
6626 local->config.authType = AUTH_ENCRYPT;
6627 } else
6628 return -EINVAL;
6629 break;
6630
6631 /* Commit the changes to flags if needed */
6632 if (local->config.authType != currentAuthType)
6633 set_bit (FLAG_COMMIT, &local->flags);
6634 }
6635
6636 case IW_AUTH_WPA_ENABLED:
6637 /* Silently accept disable of WPA */
6638 if (param->value > 0)
6639 return -EOPNOTSUPP;
6640 break;
6641
6642 default:
6643 return -EOPNOTSUPP;
6644 }
6645 return -EINPROGRESS;
6646}
6647
6648
6649/*------------------------------------------------------------------*/
6650/*
6651 * Wireless Handler : get extended authentication parameters
6652 */
6653static int airo_get_auth(struct net_device *dev,
6654 struct iw_request_info *info,
6655 union iwreq_data *wrqu, char *extra)
6656{
6657 struct airo_info *local = dev->priv;
6658 struct iw_param *param = &wrqu->param;
6659 u16 currentAuthType = local->config.authType;
6660
6661 switch (param->flags & IW_AUTH_INDEX) {
6662 case IW_AUTH_DROP_UNENCRYPTED:
6663 switch (currentAuthType) {
6664 case AUTH_SHAREDKEY:
6665 case AUTH_ENCRYPT:
6666 param->value = 1;
6667 break;
6668 default:
6669 param->value = 0;
6670 break;
6671 }
6672 break;
6673
6674 case IW_AUTH_80211_AUTH_ALG:
6675 switch (currentAuthType) {
6676 case AUTH_SHAREDKEY:
6677 param->value = IW_AUTH_ALG_SHARED_KEY;
6678 break;
6679 case AUTH_ENCRYPT:
6680 default:
6681 param->value = IW_AUTH_ALG_OPEN_SYSTEM;
6682 break;
6683 }
6684 break;
6685
6686 case IW_AUTH_WPA_ENABLED:
6687 param->value = 0;
6688 break;
6689
6690 default:
6691 return -EOPNOTSUPP;
6692 }
6693 return 0;
6694}
6695
6696
6697/*------------------------------------------------------------------*/
6698/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006699 * Wireless Handler : set Tx-Power
6700 */
6701static int airo_set_txpow(struct net_device *dev,
6702 struct iw_request_info *info,
6703 struct iw_param *vwrq,
6704 char *extra)
6705{
6706 struct airo_info *local = dev->priv;
6707 CapabilityRid cap_rid; /* Card capability info */
6708 int i;
6709 int rc = -EINVAL;
6710
6711 readCapabilityRid(local, &cap_rid, 1);
6712
6713 if (vwrq->disabled) {
6714 set_bit (FLAG_RADIO_OFF, &local->flags);
6715 set_bit (FLAG_COMMIT, &local->flags);
6716 return -EINPROGRESS; /* Call commit handler */
6717 }
6718 if (vwrq->flags != IW_TXPOW_MWATT) {
6719 return -EINVAL;
6720 }
6721 clear_bit (FLAG_RADIO_OFF, &local->flags);
6722 for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
Al Viro56d81bd2007-12-20 17:18:35 -05006723 if (vwrq->value == le16_to_cpu(cap_rid.txPowerLevels[i])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006724 readConfigRid(local, 1);
6725 local->config.txPower = vwrq->value;
6726 set_bit (FLAG_COMMIT, &local->flags);
6727 rc = -EINPROGRESS; /* Call commit handler */
6728 break;
6729 }
6730 return rc;
6731}
6732
6733/*------------------------------------------------------------------*/
6734/*
6735 * Wireless Handler : get Tx-Power
6736 */
6737static int airo_get_txpow(struct net_device *dev,
6738 struct iw_request_info *info,
6739 struct iw_param *vwrq,
6740 char *extra)
6741{
6742 struct airo_info *local = dev->priv;
6743
6744 readConfigRid(local, 1);
6745 vwrq->value = local->config.txPower;
6746 vwrq->fixed = 1; /* No power control */
6747 vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags);
6748 vwrq->flags = IW_TXPOW_MWATT;
6749
6750 return 0;
6751}
6752
6753/*------------------------------------------------------------------*/
6754/*
6755 * Wireless Handler : set Retry limits
6756 */
6757static int airo_set_retry(struct net_device *dev,
6758 struct iw_request_info *info,
6759 struct iw_param *vwrq,
6760 char *extra)
6761{
6762 struct airo_info *local = dev->priv;
6763 int rc = -EINVAL;
6764
6765 if(vwrq->disabled) {
6766 return -EINVAL;
6767 }
6768 readConfigRid(local, 1);
6769 if(vwrq->flags & IW_RETRY_LIMIT) {
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006770 if(vwrq->flags & IW_RETRY_LONG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006771 local->config.longRetryLimit = vwrq->value;
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006772 else if (vwrq->flags & IW_RETRY_SHORT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006773 local->config.shortRetryLimit = vwrq->value;
6774 else {
6775 /* No modifier : set both */
6776 local->config.longRetryLimit = vwrq->value;
6777 local->config.shortRetryLimit = vwrq->value;
6778 }
6779 set_bit (FLAG_COMMIT, &local->flags);
6780 rc = -EINPROGRESS; /* Call commit handler */
6781 }
6782 if(vwrq->flags & IW_RETRY_LIFETIME) {
6783 local->config.txLifetime = vwrq->value / 1024;
6784 set_bit (FLAG_COMMIT, &local->flags);
6785 rc = -EINPROGRESS; /* Call commit handler */
6786 }
6787 return rc;
6788}
6789
6790/*------------------------------------------------------------------*/
6791/*
6792 * Wireless Handler : get Retry limits
6793 */
6794static int airo_get_retry(struct net_device *dev,
6795 struct iw_request_info *info,
6796 struct iw_param *vwrq,
6797 char *extra)
6798{
6799 struct airo_info *local = dev->priv;
6800
6801 vwrq->disabled = 0; /* Can't be disabled */
6802
6803 readConfigRid(local, 1);
6804 /* Note : by default, display the min retry number */
6805 if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
6806 vwrq->flags = IW_RETRY_LIFETIME;
6807 vwrq->value = (int)local->config.txLifetime * 1024;
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006808 } else if((vwrq->flags & IW_RETRY_LONG)) {
6809 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006810 vwrq->value = (int)local->config.longRetryLimit;
6811 } else {
6812 vwrq->flags = IW_RETRY_LIMIT;
6813 vwrq->value = (int)local->config.shortRetryLimit;
6814 if((int)local->config.shortRetryLimit != (int)local->config.longRetryLimit)
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006815 vwrq->flags |= IW_RETRY_SHORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006816 }
6817
6818 return 0;
6819}
6820
6821/*------------------------------------------------------------------*/
6822/*
6823 * Wireless Handler : get range info
6824 */
6825static int airo_get_range(struct net_device *dev,
6826 struct iw_request_info *info,
6827 struct iw_point *dwrq,
6828 char *extra)
6829{
6830 struct airo_info *local = dev->priv;
6831 struct iw_range *range = (struct iw_range *) extra;
6832 CapabilityRid cap_rid; /* Card capability info */
6833 int i;
6834 int k;
6835
6836 readCapabilityRid(local, &cap_rid, 1);
6837
6838 dwrq->length = sizeof(struct iw_range);
6839 memset(range, 0, sizeof(*range));
6840 range->min_nwid = 0x0000;
6841 range->max_nwid = 0x0000;
6842 range->num_channels = 14;
6843 /* Should be based on cap_rid.country to give only
6844 * what the current card support */
6845 k = 0;
6846 for(i = 0; i < 14; i++) {
6847 range->freq[k].i = i + 1; /* List index */
6848 range->freq[k].m = frequency_list[i] * 100000;
6849 range->freq[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */
6850 }
6851 range->num_frequency = k;
6852
Linus Torvalds1da177e2005-04-16 15:20:36 -07006853 range->sensitivity = 65535;
6854
Dan Williams41480af2005-05-10 09:45:51 -04006855 /* Hum... Should put the right values there */
6856 if (local->rssi)
6857 range->max_qual.qual = 100; /* % */
6858 else
6859 range->max_qual.qual = airo_get_max_quality(&cap_rid);
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006860 range->max_qual.level = 0x100 - 120; /* -120 dBm */
6861 range->max_qual.noise = 0x100 - 120; /* -120 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006862
6863 /* Experimental measurements - boundary 11/5.5 Mb/s */
6864 /* Note : with or without the (local->rssi), results
6865 * are somewhat different. - Jean II */
6866 if (local->rssi) {
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006867 range->avg_qual.qual = 50; /* % */
6868 range->avg_qual.level = 0x100 - 70; /* -70 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006869 } else {
6870 range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006871 range->avg_qual.level = 0x100 - 80; /* -80 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006872 }
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006873 range->avg_qual.noise = 0x100 - 85; /* -85 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006874
Linus Torvalds1da177e2005-04-16 15:20:36 -07006875 for(i = 0 ; i < 8 ; i++) {
6876 range->bitrate[i] = cap_rid.supportedRates[i] * 500000;
6877 if(range->bitrate[i] == 0)
6878 break;
6879 }
6880 range->num_bitrates = i;
6881
6882 /* Set an indication of the max TCP throughput
6883 * in bit/s that we can expect using this interface.
6884 * May be use for QoS stuff... Jean II */
6885 if(i > 2)
6886 range->throughput = 5000 * 1000;
6887 else
6888 range->throughput = 1500 * 1000;
6889
6890 range->min_rts = 0;
Dan Williams15db2762006-03-16 13:46:27 -05006891 range->max_rts = AIRO_DEF_MTU;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006892 range->min_frag = 256;
Dan Williams15db2762006-03-16 13:46:27 -05006893 range->max_frag = AIRO_DEF_MTU;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006894
Al Viro56d81bd2007-12-20 17:18:35 -05006895 if(cap_rid.softCap & cpu_to_le16(2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006896 // WEP: RC4 40 bits
6897 range->encoding_size[0] = 5;
6898 // RC4 ~128 bits
Al Viro56d81bd2007-12-20 17:18:35 -05006899 if (cap_rid.softCap & cpu_to_le16(0x100)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006900 range->encoding_size[1] = 13;
6901 range->num_encoding_sizes = 2;
6902 } else
6903 range->num_encoding_sizes = 1;
Al Viro56d81bd2007-12-20 17:18:35 -05006904 range->max_encoding_tokens =
6905 cap_rid.softCap & cpu_to_le16(0x80) ? 4 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006906 } else {
6907 range->num_encoding_sizes = 0;
6908 range->max_encoding_tokens = 0;
6909 }
6910 range->min_pmp = 0;
6911 range->max_pmp = 5000000; /* 5 secs */
6912 range->min_pmt = 0;
6913 range->max_pmt = 65535 * 1024; /* ??? */
6914 range->pmp_flags = IW_POWER_PERIOD;
6915 range->pmt_flags = IW_POWER_TIMEOUT;
6916 range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
6917
6918 /* Transmit Power - values are in mW */
6919 for(i = 0 ; i < 8 ; i++) {
Al Viro56d81bd2007-12-20 17:18:35 -05006920 range->txpower[i] = le16_to_cpu(cap_rid.txPowerLevels[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006921 if(range->txpower[i] == 0)
6922 break;
6923 }
6924 range->num_txpower = i;
6925 range->txpower_capa = IW_TXPOW_MWATT;
Dan Williams3c304952006-04-15 12:26:18 -04006926 range->we_version_source = 19;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006927 range->we_version_compiled = WIRELESS_EXT;
6928 range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
6929 range->retry_flags = IW_RETRY_LIMIT;
6930 range->r_time_flags = IW_RETRY_LIFETIME;
6931 range->min_retry = 1;
6932 range->max_retry = 65535;
6933 range->min_r_time = 1024;
6934 range->max_r_time = 65535 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006935
6936 /* Event capability (kernel + driver) */
6937 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
6938 IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
6939 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
6940 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
6941 range->event_capa[1] = IW_EVENT_CAPA_K_1;
6942 range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVTXDROP);
6943 return 0;
6944}
6945
6946/*------------------------------------------------------------------*/
6947/*
6948 * Wireless Handler : set Power Management
6949 */
6950static int airo_set_power(struct net_device *dev,
6951 struct iw_request_info *info,
6952 struct iw_param *vwrq,
6953 char *extra)
6954{
6955 struct airo_info *local = dev->priv;
6956
6957 readConfigRid(local, 1);
6958 if (vwrq->disabled) {
6959 if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
6960 return -EINVAL;
6961 }
6962 local->config.powerSaveMode = POWERSAVE_CAM;
6963 local->config.rmode &= 0xFF00;
6964 local->config.rmode |= RXMODE_BC_MC_ADDR;
6965 set_bit (FLAG_COMMIT, &local->flags);
6966 return -EINPROGRESS; /* Call commit handler */
6967 }
6968 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
6969 local->config.fastListenDelay = (vwrq->value + 500) / 1024;
6970 local->config.powerSaveMode = POWERSAVE_PSPCAM;
6971 set_bit (FLAG_COMMIT, &local->flags);
6972 } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
6973 local->config.fastListenInterval = local->config.listenInterval = (vwrq->value + 500) / 1024;
6974 local->config.powerSaveMode = POWERSAVE_PSPCAM;
6975 set_bit (FLAG_COMMIT, &local->flags);
6976 }
6977 switch (vwrq->flags & IW_POWER_MODE) {
6978 case IW_POWER_UNICAST_R:
6979 if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
6980 return -EINVAL;
6981 }
6982 local->config.rmode &= 0xFF00;
6983 local->config.rmode |= RXMODE_ADDR;
6984 set_bit (FLAG_COMMIT, &local->flags);
6985 break;
6986 case IW_POWER_ALL_R:
6987 if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
6988 return -EINVAL;
6989 }
6990 local->config.rmode &= 0xFF00;
6991 local->config.rmode |= RXMODE_BC_MC_ADDR;
6992 set_bit (FLAG_COMMIT, &local->flags);
6993 case IW_POWER_ON:
Jean Tourrilhes7f8544c2006-08-29 17:58:11 -07006994 /* This is broken, fixme ;-) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006995 break;
6996 default:
6997 return -EINVAL;
6998 }
6999 // Note : we may want to factor local->need_commit here
7000 // Note2 : may also want to factor RXMODE_RFMON test
7001 return -EINPROGRESS; /* Call commit handler */
7002}
7003
7004/*------------------------------------------------------------------*/
7005/*
7006 * Wireless Handler : get Power Management
7007 */
7008static int airo_get_power(struct net_device *dev,
7009 struct iw_request_info *info,
7010 struct iw_param *vwrq,
7011 char *extra)
7012{
7013 struct airo_info *local = dev->priv;
7014 int mode;
7015
7016 readConfigRid(local, 1);
7017 mode = local->config.powerSaveMode;
7018 if ((vwrq->disabled = (mode == POWERSAVE_CAM)))
7019 return 0;
7020 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
7021 vwrq->value = (int)local->config.fastListenDelay * 1024;
7022 vwrq->flags = IW_POWER_TIMEOUT;
7023 } else {
7024 vwrq->value = (int)local->config.fastListenInterval * 1024;
7025 vwrq->flags = IW_POWER_PERIOD;
7026 }
7027 if ((local->config.rmode & 0xFF) == RXMODE_ADDR)
7028 vwrq->flags |= IW_POWER_UNICAST_R;
7029 else
7030 vwrq->flags |= IW_POWER_ALL_R;
7031
7032 return 0;
7033}
7034
7035/*------------------------------------------------------------------*/
7036/*
7037 * Wireless Handler : set Sensitivity
7038 */
7039static int airo_set_sens(struct net_device *dev,
7040 struct iw_request_info *info,
7041 struct iw_param *vwrq,
7042 char *extra)
7043{
7044 struct airo_info *local = dev->priv;
7045
7046 readConfigRid(local, 1);
7047 local->config.rssiThreshold = vwrq->disabled ? RSSI_DEFAULT : vwrq->value;
7048 set_bit (FLAG_COMMIT, &local->flags);
7049
7050 return -EINPROGRESS; /* Call commit handler */
7051}
7052
7053/*------------------------------------------------------------------*/
7054/*
7055 * Wireless Handler : get Sensitivity
7056 */
7057static int airo_get_sens(struct net_device *dev,
7058 struct iw_request_info *info,
7059 struct iw_param *vwrq,
7060 char *extra)
7061{
7062 struct airo_info *local = dev->priv;
7063
7064 readConfigRid(local, 1);
7065 vwrq->value = local->config.rssiThreshold;
7066 vwrq->disabled = (vwrq->value == 0);
7067 vwrq->fixed = 1;
7068
7069 return 0;
7070}
7071
7072/*------------------------------------------------------------------*/
7073/*
7074 * Wireless Handler : get AP List
7075 * Note : this is deprecated in favor of IWSCAN
7076 */
7077static int airo_get_aplist(struct net_device *dev,
7078 struct iw_request_info *info,
7079 struct iw_point *dwrq,
7080 char *extra)
7081{
7082 struct airo_info *local = dev->priv;
7083 struct sockaddr *address = (struct sockaddr *) extra;
7084 struct iw_quality qual[IW_MAX_AP];
7085 BSSListRid BSSList;
7086 int i;
7087 int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
7088
7089 for (i = 0; i < IW_MAX_AP; i++) {
Al Viro17e70492007-12-19 18:56:37 -05007090 u16 dBm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007091 if (readBSSListRid(local, loseSync, &BSSList))
7092 break;
7093 loseSync = 0;
7094 memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN);
7095 address[i].sa_family = ARPHRD_ETHER;
Al Viro17e70492007-12-19 18:56:37 -05007096 dBm = le16_to_cpu(BSSList.dBm);
Dan Williams41480af2005-05-10 09:45:51 -04007097 if (local->rssi) {
Al Viro17e70492007-12-19 18:56:37 -05007098 qual[i].level = 0x100 - dBm;
7099 qual[i].qual = airo_dbm_to_pct(local->rssi, dBm);
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007100 qual[i].updated = IW_QUAL_QUAL_UPDATED
7101 | IW_QUAL_LEVEL_UPDATED
7102 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04007103 } else {
Al Viro17e70492007-12-19 18:56:37 -05007104 qual[i].level = (dBm + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04007105 qual[i].qual = 0;
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007106 qual[i].updated = IW_QUAL_QUAL_INVALID
7107 | IW_QUAL_LEVEL_UPDATED
7108 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04007109 }
7110 qual[i].noise = local->wstats.qual.noise;
Al Viro17e70492007-12-19 18:56:37 -05007111 if (BSSList.index == cpu_to_le16(0xffff))
Linus Torvalds1da177e2005-04-16 15:20:36 -07007112 break;
7113 }
7114 if (!i) {
7115 StatusRid status_rid; /* Card status info */
7116 readStatusRid(local, &status_rid, 1);
7117 for (i = 0;
7118 i < min(IW_MAX_AP, 4) &&
7119 (status_rid.bssid[i][0]
7120 & status_rid.bssid[i][1]
7121 & status_rid.bssid[i][2]
7122 & status_rid.bssid[i][3]
7123 & status_rid.bssid[i][4]
7124 & status_rid.bssid[i][5])!=0xff &&
7125 (status_rid.bssid[i][0]
7126 | status_rid.bssid[i][1]
7127 | status_rid.bssid[i][2]
7128 | status_rid.bssid[i][3]
7129 | status_rid.bssid[i][4]
7130 | status_rid.bssid[i][5]);
7131 i++) {
7132 memcpy(address[i].sa_data,
7133 status_rid.bssid[i], ETH_ALEN);
7134 address[i].sa_family = ARPHRD_ETHER;
7135 }
7136 } else {
7137 dwrq->flags = 1; /* Should be define'd */
7138 memcpy(extra + sizeof(struct sockaddr)*i,
7139 &qual, sizeof(struct iw_quality)*i);
7140 }
7141 dwrq->length = i;
7142
7143 return 0;
7144}
7145
7146/*------------------------------------------------------------------*/
7147/*
7148 * Wireless Handler : Initiate Scan
7149 */
7150static int airo_set_scan(struct net_device *dev,
7151 struct iw_request_info *info,
7152 struct iw_param *vwrq,
7153 char *extra)
7154{
7155 struct airo_info *ai = dev->priv;
7156 Cmd cmd;
7157 Resp rsp;
Dan Williams9e75af32006-03-16 13:46:29 -05007158 int wake = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007159
7160 /* Note : you may have realised that, as this is a SET operation,
7161 * this is privileged and therefore a normal user can't
7162 * perform scanning.
7163 * This is not an error, while the device perform scanning,
7164 * traffic doesn't flow, so it's a perfect DoS...
7165 * Jean II */
7166 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
7167
Dan Williams9e75af32006-03-16 13:46:29 -05007168 if (down_interruptible(&ai->sem))
7169 return -ERESTARTSYS;
7170
7171 /* If there's already a scan in progress, don't
7172 * trigger another one. */
7173 if (ai->scan_timeout > 0)
7174 goto out;
7175
Linus Torvalds1da177e2005-04-16 15:20:36 -07007176 /* Initiate a scan command */
Dan Williams6fcdf562006-03-31 15:08:46 -05007177 ai->scan_timeout = RUN_AT(3*HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007178 memset(&cmd, 0, sizeof(cmd));
7179 cmd.cmd=CMD_LISTBSS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007180 issuecommand(ai, &cmd, &rsp);
Dan Williams9e75af32006-03-16 13:46:29 -05007181 wake = 1;
7182
7183out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07007184 up(&ai->sem);
Dan Williams9e75af32006-03-16 13:46:29 -05007185 if (wake)
7186 wake_up_interruptible(&ai->thr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007187 return 0;
7188}
7189
7190/*------------------------------------------------------------------*/
7191/*
7192 * Translate scan data returned from the card to a card independent
7193 * format that the Wireless Tools will understand - Jean II
7194 */
7195static inline char *airo_translate_scan(struct net_device *dev,
7196 char *current_ev,
7197 char *end_buf,
Dan Williams41480af2005-05-10 09:45:51 -04007198 BSSListRid *bss)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007199{
7200 struct airo_info *ai = dev->priv;
7201 struct iw_event iwe; /* Temporary buffer */
Al Viro17e70492007-12-19 18:56:37 -05007202 __le16 capabilities;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007203 char * current_val; /* For rates */
7204 int i;
Dan Williams3c304952006-04-15 12:26:18 -04007205 char * buf;
Al Viro851b3e52007-12-19 19:20:12 -05007206 u16 dBm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007207
7208 /* First entry *MUST* be the AP MAC address */
7209 iwe.cmd = SIOCGIWAP;
7210 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
Dan Williams41480af2005-05-10 09:45:51 -04007211 memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007212 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
7213
7214 /* Other entries will be displayed in the order we give them */
7215
7216 /* Add the ESSID */
Dan Williams41480af2005-05-10 09:45:51 -04007217 iwe.u.data.length = bss->ssidLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007218 if(iwe.u.data.length > 32)
7219 iwe.u.data.length = 32;
7220 iwe.cmd = SIOCGIWESSID;
7221 iwe.u.data.flags = 1;
Dan Williams41480af2005-05-10 09:45:51 -04007222 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007223
7224 /* Add mode */
7225 iwe.cmd = SIOCGIWMODE;
Al Viro17e70492007-12-19 18:56:37 -05007226 capabilities = bss->cap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007227 if(capabilities & (CAP_ESS | CAP_IBSS)) {
7228 if(capabilities & CAP_ESS)
7229 iwe.u.mode = IW_MODE_MASTER;
7230 else
7231 iwe.u.mode = IW_MODE_ADHOC;
7232 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
7233 }
7234
7235 /* Add frequency */
7236 iwe.cmd = SIOCGIWFREQ;
Dan Williams41480af2005-05-10 09:45:51 -04007237 iwe.u.freq.m = le16_to_cpu(bss->dsChannel);
matthieu castet11414552005-09-12 23:31:39 +02007238 /* iwe.u.freq.m containt the channel (starting 1), our
7239 * frequency_list array start at index 0...
7240 */
7241 iwe.u.freq.m = frequency_list[iwe.u.freq.m - 1] * 100000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007242 iwe.u.freq.e = 1;
7243 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
7244
Al Viro851b3e52007-12-19 19:20:12 -05007245 dBm = le16_to_cpu(bss->dBm);
7246
Linus Torvalds1da177e2005-04-16 15:20:36 -07007247 /* Add quality statistics */
7248 iwe.cmd = IWEVQUAL;
Dan Williams41480af2005-05-10 09:45:51 -04007249 if (ai->rssi) {
Al Viro851b3e52007-12-19 19:20:12 -05007250 iwe.u.qual.level = 0x100 - dBm;
7251 iwe.u.qual.qual = airo_dbm_to_pct(ai->rssi, dBm);
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007252 iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
7253 | IW_QUAL_LEVEL_UPDATED
7254 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04007255 } else {
Al Viro851b3e52007-12-19 19:20:12 -05007256 iwe.u.qual.level = (dBm + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04007257 iwe.u.qual.qual = 0;
Jeff Garzikbbeec902005-09-07 00:27:54 -04007258 iwe.u.qual.updated = IW_QUAL_QUAL_INVALID
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007259 | IW_QUAL_LEVEL_UPDATED
7260 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04007261 }
7262 iwe.u.qual.noise = ai->wstats.qual.noise;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007263 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
7264
7265 /* Add encryption capability */
7266 iwe.cmd = SIOCGIWENCODE;
7267 if(capabilities & CAP_PRIVACY)
7268 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
7269 else
7270 iwe.u.data.flags = IW_ENCODE_DISABLED;
7271 iwe.u.data.length = 0;
Dan Williams41480af2005-05-10 09:45:51 -04007272 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007273
7274 /* Rate : stuffing multiple values in a single event require a bit
7275 * more of magic - Jean II */
7276 current_val = current_ev + IW_EV_LCP_LEN;
7277
7278 iwe.cmd = SIOCGIWRATE;
7279 /* Those two flags are ignored... */
7280 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
7281 /* Max 8 values */
7282 for(i = 0 ; i < 8 ; i++) {
7283 /* NULL terminated */
Dan Williams41480af2005-05-10 09:45:51 -04007284 if(bss->rates[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007285 break;
7286 /* Bit rate given in 500 kb/s units (+ 0x80) */
Dan Williams41480af2005-05-10 09:45:51 -04007287 iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007288 /* Add new value to event */
7289 current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
7290 }
7291 /* Check if we added any event */
7292 if((current_val - current_ev) > IW_EV_LCP_LEN)
7293 current_ev = current_val;
7294
Dan Williams3c304952006-04-15 12:26:18 -04007295 /* Beacon interval */
7296 buf = kmalloc(30, GFP_KERNEL);
7297 if (buf) {
7298 iwe.cmd = IWEVCUSTOM;
7299 sprintf(buf, "bcn_int=%d", bss->beaconInterval);
7300 iwe.u.data.length = strlen(buf);
7301 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
7302 kfree(buf);
7303 }
7304
7305 /* Put WPA/RSN Information Elements into the event stream */
7306 if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) {
7307 unsigned int num_null_ies = 0;
7308 u16 length = sizeof (bss->extra.iep);
7309 struct ieee80211_info_element *info_element =
7310 (struct ieee80211_info_element *) &bss->extra.iep;
7311
7312 while ((length >= sizeof(*info_element)) && (num_null_ies < 2)) {
7313 if (sizeof(*info_element) + info_element->len > length) {
7314 /* Invalid element, don't continue parsing IE */
7315 break;
7316 }
7317
7318 switch (info_element->id) {
7319 case MFIE_TYPE_SSID:
7320 /* Two zero-length SSID elements
7321 * mean we're done parsing elements */
7322 if (!info_element->len)
7323 num_null_ies++;
7324 break;
7325
7326 case MFIE_TYPE_GENERIC:
7327 if (info_element->len >= 4 &&
7328 info_element->data[0] == 0x00 &&
7329 info_element->data[1] == 0x50 &&
7330 info_element->data[2] == 0xf2 &&
7331 info_element->data[3] == 0x01) {
7332 iwe.cmd = IWEVGENIE;
7333 iwe.u.data.length = min(info_element->len + 2,
7334 MAX_WPA_IE_LEN);
7335 current_ev = iwe_stream_add_point(current_ev, end_buf,
7336 &iwe, (char *) info_element);
7337 }
7338 break;
7339
7340 case MFIE_TYPE_RSN:
7341 iwe.cmd = IWEVGENIE;
7342 iwe.u.data.length = min(info_element->len + 2,
7343 MAX_WPA_IE_LEN);
7344 current_ev = iwe_stream_add_point(current_ev, end_buf,
7345 &iwe, (char *) info_element);
7346 break;
7347
7348 default:
7349 break;
7350 }
7351
7352 length -= sizeof(*info_element) + info_element->len;
7353 info_element =
7354 (struct ieee80211_info_element *)&info_element->
7355 data[info_element->len];
7356 }
7357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007358 return current_ev;
7359}
7360
7361/*------------------------------------------------------------------*/
7362/*
7363 * Wireless Handler : Read Scan Results
7364 */
7365static int airo_get_scan(struct net_device *dev,
7366 struct iw_request_info *info,
7367 struct iw_point *dwrq,
7368 char *extra)
7369{
7370 struct airo_info *ai = dev->priv;
Dan Williams9e75af32006-03-16 13:46:29 -05007371 BSSListElement *net;
7372 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007373 char *current_ev = extra;
7374
Dan Williams9e75af32006-03-16 13:46:29 -05007375 /* If a scan is in-progress, return -EAGAIN */
7376 if (ai->scan_timeout > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007377 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007378
Dan Williams9e75af32006-03-16 13:46:29 -05007379 if (down_interruptible(&ai->sem))
7380 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007381
Dan Williams9e75af32006-03-16 13:46:29 -05007382 list_for_each_entry (net, &ai->network_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007383 /* Translate to WE format this entry */
7384 current_ev = airo_translate_scan(dev, current_ev,
7385 extra + dwrq->length,
Dan Williams9e75af32006-03-16 13:46:29 -05007386 &net->bss);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007387
7388 /* Check if there is space for one more entry */
7389 if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
7390 /* Ask user space to try again with a bigger buffer */
Dan Williams9e75af32006-03-16 13:46:29 -05007391 err = -E2BIG;
7392 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007394 }
Dan Williams9e75af32006-03-16 13:46:29 -05007395
Linus Torvalds1da177e2005-04-16 15:20:36 -07007396 /* Length of data */
7397 dwrq->length = (current_ev - extra);
7398 dwrq->flags = 0; /* todo */
7399
Dan Williams9e75af32006-03-16 13:46:29 -05007400out:
7401 up(&ai->sem);
7402 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007403}
7404
7405/*------------------------------------------------------------------*/
7406/*
7407 * Commit handler : called after a bunch of SET operations
7408 */
7409static int airo_config_commit(struct net_device *dev,
7410 struct iw_request_info *info, /* NULL */
7411 void *zwrq, /* NULL */
7412 char *extra) /* NULL */
7413{
7414 struct airo_info *local = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007415
7416 if (!test_bit (FLAG_COMMIT, &local->flags))
7417 return 0;
7418
7419 /* Some of the "SET" function may have modified some of the
7420 * parameters. It's now time to commit them in the card */
7421 disable_MAC(local, 1);
7422 if (test_bit (FLAG_RESET, &local->flags)) {
7423 APListRid APList_rid;
7424 SsidRid SSID_rid;
7425
7426 readAPListRid(local, &APList_rid);
7427 readSsidRid(local, &SSID_rid);
7428 if (test_bit(FLAG_MPI,&local->flags))
7429 setup_card(local, dev->dev_addr, 1 );
7430 else
7431 reset_airo_card(dev);
7432 disable_MAC(local, 1);
7433 writeSsidRid(local, &SSID_rid, 1);
7434 writeAPListRid(local, &APList_rid, 1);
7435 }
7436 if (down_interruptible(&local->sem))
7437 return -ERESTARTSYS;
7438 writeConfigRid(local, 0);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02007439 enable_MAC(local, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007440 if (test_bit (FLAG_RESET, &local->flags))
7441 airo_set_promisc(local);
7442 else
7443 up(&local->sem);
7444
7445 return 0;
7446}
7447
7448/*------------------------------------------------------------------*/
7449/*
7450 * Structures to export the Wireless Handlers
7451 */
7452
7453static const struct iw_priv_args airo_private_args[] = {
7454/*{ cmd, set_args, get_args, name } */
7455 { AIROIOCTL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
7456 IW_PRIV_TYPE_BYTE | 2047, "airoioctl" },
7457 { AIROIDIFC, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
7458 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" },
7459};
7460
7461static const iw_handler airo_handler[] =
7462{
7463 (iw_handler) airo_config_commit, /* SIOCSIWCOMMIT */
7464 (iw_handler) airo_get_name, /* SIOCGIWNAME */
7465 (iw_handler) NULL, /* SIOCSIWNWID */
7466 (iw_handler) NULL, /* SIOCGIWNWID */
7467 (iw_handler) airo_set_freq, /* SIOCSIWFREQ */
7468 (iw_handler) airo_get_freq, /* SIOCGIWFREQ */
7469 (iw_handler) airo_set_mode, /* SIOCSIWMODE */
7470 (iw_handler) airo_get_mode, /* SIOCGIWMODE */
7471 (iw_handler) airo_set_sens, /* SIOCSIWSENS */
7472 (iw_handler) airo_get_sens, /* SIOCGIWSENS */
7473 (iw_handler) NULL, /* SIOCSIWRANGE */
7474 (iw_handler) airo_get_range, /* SIOCGIWRANGE */
7475 (iw_handler) NULL, /* SIOCSIWPRIV */
7476 (iw_handler) NULL, /* SIOCGIWPRIV */
7477 (iw_handler) NULL, /* SIOCSIWSTATS */
7478 (iw_handler) NULL, /* SIOCGIWSTATS */
7479 iw_handler_set_spy, /* SIOCSIWSPY */
7480 iw_handler_get_spy, /* SIOCGIWSPY */
7481 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
7482 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
7483 (iw_handler) airo_set_wap, /* SIOCSIWAP */
7484 (iw_handler) airo_get_wap, /* SIOCGIWAP */
7485 (iw_handler) NULL, /* -- hole -- */
7486 (iw_handler) airo_get_aplist, /* SIOCGIWAPLIST */
7487 (iw_handler) airo_set_scan, /* SIOCSIWSCAN */
7488 (iw_handler) airo_get_scan, /* SIOCGIWSCAN */
7489 (iw_handler) airo_set_essid, /* SIOCSIWESSID */
7490 (iw_handler) airo_get_essid, /* SIOCGIWESSID */
7491 (iw_handler) airo_set_nick, /* SIOCSIWNICKN */
7492 (iw_handler) airo_get_nick, /* SIOCGIWNICKN */
7493 (iw_handler) NULL, /* -- hole -- */
7494 (iw_handler) NULL, /* -- hole -- */
7495 (iw_handler) airo_set_rate, /* SIOCSIWRATE */
7496 (iw_handler) airo_get_rate, /* SIOCGIWRATE */
7497 (iw_handler) airo_set_rts, /* SIOCSIWRTS */
7498 (iw_handler) airo_get_rts, /* SIOCGIWRTS */
7499 (iw_handler) airo_set_frag, /* SIOCSIWFRAG */
7500 (iw_handler) airo_get_frag, /* SIOCGIWFRAG */
7501 (iw_handler) airo_set_txpow, /* SIOCSIWTXPOW */
7502 (iw_handler) airo_get_txpow, /* SIOCGIWTXPOW */
7503 (iw_handler) airo_set_retry, /* SIOCSIWRETRY */
7504 (iw_handler) airo_get_retry, /* SIOCGIWRETRY */
7505 (iw_handler) airo_set_encode, /* SIOCSIWENCODE */
7506 (iw_handler) airo_get_encode, /* SIOCGIWENCODE */
7507 (iw_handler) airo_set_power, /* SIOCSIWPOWER */
7508 (iw_handler) airo_get_power, /* SIOCGIWPOWER */
Dan Williams4be757d2006-01-30 11:58:00 -05007509 (iw_handler) NULL, /* -- hole -- */
7510 (iw_handler) NULL, /* -- hole -- */
7511 (iw_handler) NULL, /* SIOCSIWGENIE */
7512 (iw_handler) NULL, /* SIOCGIWGENIE */
7513 (iw_handler) airo_set_auth, /* SIOCSIWAUTH */
7514 (iw_handler) airo_get_auth, /* SIOCGIWAUTH */
7515 (iw_handler) airo_set_encodeext, /* SIOCSIWENCODEEXT */
7516 (iw_handler) airo_get_encodeext, /* SIOCGIWENCODEEXT */
7517 (iw_handler) NULL, /* SIOCSIWPMKSA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007518};
7519
7520/* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here.
7521 * We want to force the use of the ioctl code, because those can't be
7522 * won't work the iw_handler code (because they simultaneously read
7523 * and write data and iw_handler can't do that).
7524 * Note that it's perfectly legal to read/write on a single ioctl command,
7525 * you just can't use iwpriv and need to force it via the ioctl handler.
7526 * Jean II */
7527static const iw_handler airo_private_handler[] =
7528{
7529 NULL, /* SIOCIWFIRSTPRIV */
7530};
7531
7532static const struct iw_handler_def airo_handler_def =
7533{
Denis Chengff8ac602007-09-02 18:30:18 +08007534 .num_standard = ARRAY_SIZE(airo_handler),
7535 .num_private = ARRAY_SIZE(airo_private_handler),
7536 .num_private_args = ARRAY_SIZE(airo_private_args),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007537 .standard = airo_handler,
7538 .private = airo_private_handler,
7539 .private_args = airo_private_args,
7540 .get_wireless_stats = airo_get_wireless_stats,
7541};
7542
Linus Torvalds1da177e2005-04-16 15:20:36 -07007543/*
7544 * This defines the configuration part of the Wireless Extensions
7545 * Note : irq and spinlock protection will occur in the subroutines
7546 *
7547 * TODO :
7548 * o Check input value more carefully and fill correct values in range
7549 * o Test and shakeout the bugs (if any)
7550 *
7551 * Jean II
7552 *
7553 * Javier Achirica did a great job of merging code from the unnamed CISCO
7554 * developer that added support for flashing the card.
7555 */
7556static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
7557{
7558 int rc = 0;
7559 struct airo_info *ai = (struct airo_info *)dev->priv;
7560
Pavel Machekca078ba2005-09-03 15:56:57 -07007561 if (ai->power.event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007562 return 0;
7563
7564 switch (cmd) {
7565#ifdef CISCO_EXT
7566 case AIROIDIFC:
7567#ifdef AIROOLDIDIFC
7568 case AIROOLDIDIFC:
7569#endif
7570 {
7571 int val = AIROMAGIC;
7572 aironet_ioctl com;
7573 if (copy_from_user(&com,rq->ifr_data,sizeof(com)))
7574 rc = -EFAULT;
7575 else if (copy_to_user(com.data,(char *)&val,sizeof(val)))
7576 rc = -EFAULT;
7577 }
7578 break;
7579
7580 case AIROIOCTL:
7581#ifdef AIROOLDIOCTL
7582 case AIROOLDIOCTL:
7583#endif
7584 /* Get the command struct and hand it off for evaluation by
7585 * the proper subfunction
7586 */
7587 {
7588 aironet_ioctl com;
7589 if (copy_from_user(&com,rq->ifr_data,sizeof(com))) {
7590 rc = -EFAULT;
7591 break;
7592 }
7593
7594 /* Separate R/W functions bracket legality here
7595 */
7596 if ( com.command == AIRORSWVERSION ) {
7597 if (copy_to_user(com.data, swversion, sizeof(swversion)))
7598 rc = -EFAULT;
7599 else
7600 rc = 0;
7601 }
7602 else if ( com.command <= AIRORRID)
7603 rc = readrids(dev,&com);
7604 else if ( com.command >= AIROPCAP && com.command <= (AIROPLEAPUSR+2) )
7605 rc = writerids(dev,&com);
7606 else if ( com.command >= AIROFLSHRST && com.command <= AIRORESTART )
7607 rc = flashcard(dev,&com);
7608 else
7609 rc = -EINVAL; /* Bad command in ioctl */
7610 }
7611 break;
7612#endif /* CISCO_EXT */
7613
7614 // All other calls are currently unsupported
7615 default:
7616 rc = -EOPNOTSUPP;
7617 }
7618 return rc;
7619}
7620
Linus Torvalds1da177e2005-04-16 15:20:36 -07007621/*
7622 * Get the Wireless stats out of the driver
7623 * Note : irq and spinlock protection will occur in the subroutines
7624 *
7625 * TODO :
7626 * o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs)
7627 *
7628 * Jean
7629 */
7630static void airo_read_wireless_stats(struct airo_info *local)
7631{
7632 StatusRid status_rid;
7633 StatsRid stats_rid;
7634 CapabilityRid cap_rid;
Al Viroa23ace52007-12-19 22:24:16 -05007635 __le32 *vals = stats_rid.vals;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007636
7637 /* Get stats out of the card */
Dan Williams3c304952006-04-15 12:26:18 -04007638 clear_bit(JOB_WSTATS, &local->jobs);
Pavel Machekca078ba2005-09-03 15:56:57 -07007639 if (local->power.event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007640 up(&local->sem);
7641 return;
7642 }
7643 readCapabilityRid(local, &cap_rid, 0);
7644 readStatusRid(local, &status_rid, 0);
7645 readStatsRid(local, &stats_rid, RID_STATS, 0);
7646 up(&local->sem);
7647
7648 /* The status */
7649 local->wstats.status = status_rid.mode;
7650
Dan Williams41480af2005-05-10 09:45:51 -04007651 /* Signal quality and co */
7652 if (local->rssi) {
7653 local->wstats.qual.level = airo_rssi_to_dbm( local->rssi, status_rid.sigQuality );
7654 /* normalizedSignalStrength appears to be a percentage */
7655 local->wstats.qual.qual = status_rid.normalizedSignalStrength;
7656 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007657 local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04007658 local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
7659 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007660 if (status_rid.len >= 124) {
Dan Williams41480af2005-05-10 09:45:51 -04007661 local->wstats.qual.noise = 0x100 - status_rid.noisedBm;
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007662 local->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007663 } else {
7664 local->wstats.qual.noise = 0;
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007665 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 -07007666 }
7667
7668 /* Packets discarded in the wireless adapter due to wireless
7669 * specific problems */
Al Viroa23ace52007-12-19 22:24:16 -05007670 local->wstats.discard.nwid = le32_to_cpu(vals[56]) +
7671 le32_to_cpu(vals[57]) +
7672 le32_to_cpu(vals[58]); /* SSID Mismatch */
7673 local->wstats.discard.code = le32_to_cpu(vals[6]);/* RxWepErr */
7674 local->wstats.discard.fragment = le32_to_cpu(vals[30]);
7675 local->wstats.discard.retries = le32_to_cpu(vals[10]);
7676 local->wstats.discard.misc = le32_to_cpu(vals[1]) +
7677 le32_to_cpu(vals[32]);
7678 local->wstats.miss.beacon = le32_to_cpu(vals[34]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007679}
7680
Jouni Malinenff1d2762005-05-12 22:54:16 -04007681static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007682{
7683 struct airo_info *local = dev->priv;
7684
Dan Williams3c304952006-04-15 12:26:18 -04007685 if (!test_bit(JOB_WSTATS, &local->jobs)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007686 /* Get stats out of the card if available */
7687 if (down_trylock(&local->sem) != 0) {
Dan Williams3c304952006-04-15 12:26:18 -04007688 set_bit(JOB_WSTATS, &local->jobs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007689 wake_up_interruptible(&local->thr_wait);
7690 } else
7691 airo_read_wireless_stats(local);
7692 }
7693
7694 return &local->wstats;
7695}
Linus Torvalds1da177e2005-04-16 15:20:36 -07007696
7697#ifdef CISCO_EXT
7698/*
7699 * This just translates from driver IOCTL codes to the command codes to
7700 * feed to the radio's host interface. Things can be added/deleted
7701 * as needed. This represents the READ side of control I/O to
7702 * the card
7703 */
7704static int readrids(struct net_device *dev, aironet_ioctl *comp) {
7705 unsigned short ridcode;
7706 unsigned char *iobuf;
7707 int len;
7708 struct airo_info *ai = dev->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007709
7710 if (test_bit(FLAG_FLASHING, &ai->flags))
7711 return -EIO;
7712
7713 switch(comp->command)
7714 {
7715 case AIROGCAP: ridcode = RID_CAPABILITIES; break;
7716 case AIROGCFG: ridcode = RID_CONFIG;
7717 if (test_bit(FLAG_COMMIT, &ai->flags)) {
7718 disable_MAC (ai, 1);
7719 writeConfigRid (ai, 1);
Michal Schmidt175ec1a2007-06-29 15:33:47 +02007720 enable_MAC(ai, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007721 }
7722 break;
7723 case AIROGSLIST: ridcode = RID_SSID; break;
7724 case AIROGVLIST: ridcode = RID_APLIST; break;
7725 case AIROGDRVNAM: ridcode = RID_DRVNAME; break;
7726 case AIROGEHTENC: ridcode = RID_ETHERENCAP; break;
7727 case AIROGWEPKTMP: ridcode = RID_WEP_TEMP;
7728 /* Only super-user can read WEP keys */
7729 if (!capable(CAP_NET_ADMIN))
7730 return -EPERM;
7731 break;
7732 case AIROGWEPKNV: ridcode = RID_WEP_PERM;
7733 /* Only super-user can read WEP keys */
7734 if (!capable(CAP_NET_ADMIN))
7735 return -EPERM;
7736 break;
7737 case AIROGSTAT: ridcode = RID_STATUS; break;
7738 case AIROGSTATSD32: ridcode = RID_STATSDELTA; break;
7739 case AIROGSTATSC32: ridcode = RID_STATS; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007740 case AIROGMICSTATS:
7741 if (copy_to_user(comp->data, &ai->micstats,
7742 min((int)comp->len,(int)sizeof(ai->micstats))))
7743 return -EFAULT;
7744 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007745 case AIRORRID: ridcode = comp->ridnum; break;
7746 default:
7747 return -EINVAL;
7748 break;
7749 }
7750
7751 if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
7752 return -ENOMEM;
7753
7754 PC4500_readrid(ai,ridcode,iobuf,RIDSIZE, 1);
7755 /* get the count of bytes in the rid docs say 1st 2 bytes is it.
7756 * then return it to the user
7757 * 9/22/2000 Honor user given length
7758 */
7759 len = comp->len;
7760
7761 if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) {
7762 kfree (iobuf);
7763 return -EFAULT;
7764 }
7765 kfree (iobuf);
7766 return 0;
7767}
7768
7769/*
7770 * Danger Will Robinson write the rids here
7771 */
7772
7773static int writerids(struct net_device *dev, aironet_ioctl *comp) {
7774 struct airo_info *ai = dev->priv;
7775 int ridcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007776 int enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007777 static int (* writer)(struct airo_info *, u16 rid, const void *, int, int);
7778 unsigned char *iobuf;
7779
7780 /* Only super-user can write RIDs */
7781 if (!capable(CAP_NET_ADMIN))
7782 return -EPERM;
7783
7784 if (test_bit(FLAG_FLASHING, &ai->flags))
7785 return -EIO;
7786
7787 ridcode = 0;
7788 writer = do_writerid;
7789
7790 switch(comp->command)
7791 {
7792 case AIROPSIDS: ridcode = RID_SSID; break;
7793 case AIROPCAP: ridcode = RID_CAPABILITIES; break;
7794 case AIROPAPLIST: ridcode = RID_APLIST; break;
7795 case AIROPCFG: ai->config.len = 0;
7796 clear_bit(FLAG_COMMIT, &ai->flags);
7797 ridcode = RID_CONFIG; break;
7798 case AIROPWEPKEYNV: ridcode = RID_WEP_PERM; break;
7799 case AIROPLEAPUSR: ridcode = RID_LEAPUSERNAME; break;
7800 case AIROPLEAPPWD: ridcode = RID_LEAPPASSWORD; break;
7801 case AIROPWEPKEY: ridcode = RID_WEP_TEMP; writer = PC4500_writerid;
7802 break;
7803 case AIROPLEAPUSR+1: ridcode = 0xFF2A; break;
7804 case AIROPLEAPUSR+2: ridcode = 0xFF2B; break;
7805
7806 /* this is not really a rid but a command given to the card
7807 * same with MAC off
7808 */
7809 case AIROPMACON:
Michal Schmidt175ec1a2007-06-29 15:33:47 +02007810 if (enable_MAC(ai, 1) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007811 return -EIO;
7812 return 0;
7813
7814 /*
7815 * Evidently this code in the airo driver does not get a symbol
7816 * as disable_MAC. it's probably so short the compiler does not gen one.
7817 */
7818 case AIROPMACOFF:
7819 disable_MAC(ai, 1);
7820 return 0;
7821
7822 /* This command merely clears the counts does not actually store any data
7823 * only reads rid. But as it changes the cards state, I put it in the
7824 * writerid routines.
7825 */
7826 case AIROPSTCLR:
7827 if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
7828 return -ENOMEM;
7829
7830 PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDSIZE, 1);
7831
Linus Torvalds1da177e2005-04-16 15:20:36 -07007832 enabled = ai->micstats.enabled;
7833 memset(&ai->micstats,0,sizeof(ai->micstats));
7834 ai->micstats.enabled = enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007835
7836 if (copy_to_user(comp->data, iobuf,
7837 min((int)comp->len, (int)RIDSIZE))) {
7838 kfree (iobuf);
7839 return -EFAULT;
7840 }
7841 kfree (iobuf);
7842 return 0;
7843
7844 default:
7845 return -EOPNOTSUPP; /* Blarg! */
7846 }
7847 if(comp->len > RIDSIZE)
7848 return -EINVAL;
7849
7850 if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
7851 return -ENOMEM;
7852
7853 if (copy_from_user(iobuf,comp->data,comp->len)) {
7854 kfree (iobuf);
7855 return -EFAULT;
7856 }
7857
7858 if (comp->command == AIROPCFG) {
7859 ConfigRid *cfg = (ConfigRid *)iobuf;
7860
7861 if (test_bit(FLAG_MIC_CAPABLE, &ai->flags))
Al Viro2ab1f512007-12-20 23:04:35 -05007862 cfg->opmode |= cpu_to_le16(MODE_MIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007863
Al Viro2ab1f512007-12-20 23:04:35 -05007864 if ((le16_to_cpu(cfg->opmode) & 0xFF) == MODE_STA_IBSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007865 set_bit (FLAG_ADHOC, &ai->flags);
7866 else
7867 clear_bit (FLAG_ADHOC, &ai->flags);
7868 }
7869
7870 if((*writer)(ai, ridcode, iobuf,comp->len,1)) {
7871 kfree (iobuf);
7872 return -EIO;
7873 }
7874 kfree (iobuf);
7875 return 0;
7876}
7877
7878/*****************************************************************************
7879 * Ancillary flash / mod functions much black magic lurkes here *
7880 *****************************************************************************
7881 */
7882
7883/*
7884 * Flash command switch table
7885 */
7886
Jouni Malinenff1d2762005-05-12 22:54:16 -04007887static int flashcard(struct net_device *dev, aironet_ioctl *comp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007888 int z;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007889
7890 /* Only super-user can modify flash */
7891 if (!capable(CAP_NET_ADMIN))
7892 return -EPERM;
7893
7894 switch(comp->command)
7895 {
7896 case AIROFLSHRST:
7897 return cmdreset((struct airo_info *)dev->priv);
7898
7899 case AIROFLSHSTFL:
7900 if (!((struct airo_info *)dev->priv)->flash &&
7901 (((struct airo_info *)dev->priv)->flash = kmalloc (FLASHSIZE, GFP_KERNEL)) == NULL)
7902 return -ENOMEM;
7903 return setflashmode((struct airo_info *)dev->priv);
7904
7905 case AIROFLSHGCHR: /* Get char from aux */
7906 if(comp->len != sizeof(int))
7907 return -EINVAL;
7908 if (copy_from_user(&z,comp->data,comp->len))
7909 return -EFAULT;
7910 return flashgchar((struct airo_info *)dev->priv,z,8000);
7911
7912 case AIROFLSHPCHR: /* Send char to card. */
7913 if(comp->len != sizeof(int))
7914 return -EINVAL;
7915 if (copy_from_user(&z,comp->data,comp->len))
7916 return -EFAULT;
7917 return flashpchar((struct airo_info *)dev->priv,z,8000);
7918
7919 case AIROFLPUTBUF: /* Send 32k to card */
7920 if (!((struct airo_info *)dev->priv)->flash)
7921 return -ENOMEM;
7922 if(comp->len > FLASHSIZE)
7923 return -EINVAL;
7924 if(copy_from_user(((struct airo_info *)dev->priv)->flash,comp->data,comp->len))
7925 return -EFAULT;
7926
7927 flashputbuf((struct airo_info *)dev->priv);
7928 return 0;
7929
7930 case AIRORESTART:
7931 if(flashrestart((struct airo_info *)dev->priv,dev))
7932 return -EIO;
7933 return 0;
7934 }
7935 return -EINVAL;
7936}
7937
7938#define FLASH_COMMAND 0x7e7e
7939
7940/*
7941 * STEP 1)
7942 * Disable MAC and do soft reset on
7943 * card.
7944 */
7945
Jouni Malinenff1d2762005-05-12 22:54:16 -04007946static int cmdreset(struct airo_info *ai) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007947 disable_MAC(ai, 1);
7948
7949 if(!waitbusy (ai)){
Dan Williams934d8bf2006-03-16 13:46:23 -05007950 airo_print_info(ai->dev->name, "Waitbusy hang before RESET");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007951 return -EBUSY;
7952 }
7953
7954 OUT4500(ai,COMMAND,CMD_SOFTRESET);
7955
7956 ssleep(1); /* WAS 600 12/7/00 */
7957
7958 if(!waitbusy (ai)){
Dan Williams934d8bf2006-03-16 13:46:23 -05007959 airo_print_info(ai->dev->name, "Waitbusy hang AFTER RESET");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007960 return -EBUSY;
7961 }
7962 return 0;
7963}
7964
7965/* STEP 2)
7966 * Put the card in legendary flash
7967 * mode
7968 */
7969
Jouni Malinenff1d2762005-05-12 22:54:16 -04007970static int setflashmode (struct airo_info *ai) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007971 set_bit (FLAG_FLASHING, &ai->flags);
7972
7973 OUT4500(ai, SWS0, FLASH_COMMAND);
7974 OUT4500(ai, SWS1, FLASH_COMMAND);
7975 if (probe) {
7976 OUT4500(ai, SWS0, FLASH_COMMAND);
7977 OUT4500(ai, COMMAND,0x10);
7978 } else {
7979 OUT4500(ai, SWS2, FLASH_COMMAND);
7980 OUT4500(ai, SWS3, FLASH_COMMAND);
7981 OUT4500(ai, COMMAND,0);
7982 }
7983 msleep(500); /* 500ms delay */
7984
7985 if(!waitbusy(ai)) {
7986 clear_bit (FLAG_FLASHING, &ai->flags);
Dan Williams934d8bf2006-03-16 13:46:23 -05007987 airo_print_info(ai->dev->name, "Waitbusy hang after setflash mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007988 return -EIO;
7989 }
7990 return 0;
7991}
7992
7993/* Put character to SWS0 wait for dwelltime
7994 * x 50us for echo .
7995 */
7996
Jouni Malinenff1d2762005-05-12 22:54:16 -04007997static int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007998 int echo;
7999 int waittime;
8000
8001 byte |= 0x8000;
8002
8003 if(dwelltime == 0 )
8004 dwelltime = 200;
8005
8006 waittime=dwelltime;
8007
8008 /* Wait for busy bit d15 to go false indicating buffer empty */
8009 while ((IN4500 (ai, SWS0) & 0x8000) && waittime > 0) {
8010 udelay (50);
8011 waittime -= 50;
8012 }
8013
8014 /* timeout for busy clear wait */
8015 if(waittime <= 0 ){
Dan Williams934d8bf2006-03-16 13:46:23 -05008016 airo_print_info(ai->dev->name, "flash putchar busywait timeout!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07008017 return -EBUSY;
8018 }
8019
8020 /* Port is clear now write byte and wait for it to echo back */
8021 do {
8022 OUT4500(ai,SWS0,byte);
8023 udelay(50);
8024 dwelltime -= 50;
8025 echo = IN4500(ai,SWS1);
8026 } while (dwelltime >= 0 && echo != byte);
8027
8028 OUT4500(ai,SWS1,0);
8029
8030 return (echo == byte) ? 0 : -EIO;
8031}
8032
8033/*
8034 * Get a character from the card matching matchbyte
8035 * Step 3)
8036 */
Jouni Malinenff1d2762005-05-12 22:54:16 -04008037static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
Linus Torvalds1da177e2005-04-16 15:20:36 -07008038 int rchar;
8039 unsigned char rbyte=0;
8040
8041 do {
8042 rchar = IN4500(ai,SWS1);
8043
8044 if(dwelltime && !(0x8000 & rchar)){
8045 dwelltime -= 10;
8046 mdelay(10);
8047 continue;
8048 }
8049 rbyte = 0xff & rchar;
8050
8051 if( (rbyte == matchbyte) && (0x8000 & rchar) ){
8052 OUT4500(ai,SWS1,0);
8053 return 0;
8054 }
8055 if( rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar)
8056 break;
8057 OUT4500(ai,SWS1,0);
8058
8059 }while(dwelltime > 0);
8060 return -EIO;
8061}
8062
8063/*
8064 * Transfer 32k of firmware data from user buffer to our buffer and
8065 * send to the card
8066 */
8067
Jouni Malinenff1d2762005-05-12 22:54:16 -04008068static int flashputbuf(struct airo_info *ai){
Linus Torvalds1da177e2005-04-16 15:20:36 -07008069 int nwords;
8070
8071 /* Write stuff */
8072 if (test_bit(FLAG_MPI,&ai->flags))
8073 memcpy_toio(ai->pciaux + 0x8000, ai->flash, FLASHSIZE);
8074 else {
8075 OUT4500(ai,AUXPAGE,0x100);
8076 OUT4500(ai,AUXOFF,0);
8077
8078 for(nwords=0;nwords != FLASHSIZE / 2;nwords++){
8079 OUT4500(ai,AUXDATA,ai->flash[nwords] & 0xffff);
8080 }
8081 }
8082 OUT4500(ai,SWS0,0x8000);
8083
8084 return 0;
8085}
8086
8087/*
8088 *
8089 */
Jouni Malinenff1d2762005-05-12 22:54:16 -04008090static int flashrestart(struct airo_info *ai,struct net_device *dev){
Linus Torvalds1da177e2005-04-16 15:20:36 -07008091 int i,status;
8092
8093 ssleep(1); /* Added 12/7/00 */
8094 clear_bit (FLAG_FLASHING, &ai->flags);
8095 if (test_bit(FLAG_MPI, &ai->flags)) {
8096 status = mpi_init_descriptors(ai);
8097 if (status != SUCCESS)
8098 return status;
8099 }
8100 status = setup_card(ai, dev->dev_addr, 1);
8101
8102 if (!test_bit(FLAG_MPI,&ai->flags))
8103 for( i = 0; i < MAX_FIDS; i++ ) {
8104 ai->fids[i] = transmit_allocate
Dan Williams15db2762006-03-16 13:46:27 -05008105 ( ai, AIRO_DEF_MTU, i >= MAX_FIDS / 2 );
Linus Torvalds1da177e2005-04-16 15:20:36 -07008106 }
8107
8108 ssleep(1); /* Added 12/7/00 */
8109 return status;
8110}
8111#endif /* CISCO_EXT */
8112
8113/*
8114 This program is free software; you can redistribute it and/or
8115 modify it under the terms of the GNU General Public License
8116 as published by the Free Software Foundation; either version 2
8117 of the License, or (at your option) any later version.
8118
8119 This program is distributed in the hope that it will be useful,
8120 but WITHOUT ANY WARRANTY; without even the implied warranty of
8121 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8122 GNU General Public License for more details.
8123
8124 In addition:
8125
8126 Redistribution and use in source and binary forms, with or without
8127 modification, are permitted provided that the following conditions
8128 are met:
8129
8130 1. Redistributions of source code must retain the above copyright
8131 notice, this list of conditions and the following disclaimer.
8132 2. Redistributions in binary form must reproduce the above copyright
8133 notice, this list of conditions and the following disclaimer in the
8134 documentation and/or other materials provided with the distribution.
8135 3. The name of the author may not be used to endorse or promote
8136 products derived from this software without specific prior written
8137 permission.
8138
8139 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
8140 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8141 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8142 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
8143 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
8144 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
8145 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8146 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
8147 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
8148 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
8149 POSSIBILITY OF SUCH DAMAGE.
8150*/
8151
8152module_init(airo_init_module);
8153module_exit(airo_cleanup_module);