blob: 6f591abacfdc6292a27a5012ccf05dd10c9d4c1d [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
22#include <linux/config.h>
23#include <linux/init.h>
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/proc_fs.h>
28#include <linux/smp_lock.h>
29
30#include <linux/sched.h>
31#include <linux/ptrace.h>
32#include <linux/slab.h>
33#include <linux/string.h>
34#include <linux/timer.h>
35#include <linux/interrupt.h>
36#include <linux/in.h>
37#include <linux/bitops.h>
David Hardeman378f0582005-09-17 17:55:31 +100038#include <linux/scatterlist.h>
Adrian Bunka39d3e72006-01-21 01:35:15 +010039#include <linux/crypto.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <asm/io.h>
41#include <asm/system.h>
42
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>
50
Adrian Bunkd3808762005-11-05 17:42:27 +010051#include "airo.h"
52
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#ifdef CONFIG_PCI
54static struct pci_device_id card_ids[] = {
55 { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, },
56 { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID },
57 { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, },
58 { 0x14b9, 0x0340, PCI_ANY_ID, PCI_ANY_ID, },
59 { 0x14b9, 0x0350, PCI_ANY_ID, PCI_ANY_ID, },
60 { 0x14b9, 0x5000, PCI_ANY_ID, PCI_ANY_ID, },
61 { 0x14b9, 0xa504, PCI_ANY_ID, PCI_ANY_ID, },
62 { 0, }
63};
64MODULE_DEVICE_TABLE(pci, card_ids);
65
66static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *);
67static void airo_pci_remove(struct pci_dev *);
Pavel Machek05adc3b2005-04-16 15:25:25 -070068static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state);
Linus Torvalds1da177e2005-04-16 15:20:36 -070069static int airo_pci_resume(struct pci_dev *pdev);
70
71static struct pci_driver airo_driver = {
72 .name = "airo",
73 .id_table = card_ids,
74 .probe = airo_pci_probe,
75 .remove = __devexit_p(airo_pci_remove),
76 .suspend = airo_pci_suspend,
77 .resume = airo_pci_resume,
78};
79#endif /* CONFIG_PCI */
80
81/* Include Wireless Extension definition and check version - Jean II */
82#include <linux/wireless.h>
83#define WIRELESS_SPY // enable iwspy support
84#include <net/iw_handler.h> // New driver API
85
86#define CISCO_EXT // enable Cisco extensions
87#ifdef CISCO_EXT
88#include <linux/delay.h>
89#endif
90
Linus Torvalds1da177e2005-04-16 15:20:36 -070091/* Hack to do some power saving */
92#define POWER_ON_DOWN
93
94/* As you can see this list is HUGH!
95 I really don't know what a lot of these counts are about, but they
96 are all here for completeness. If the IGNLABEL macro is put in
97 infront of the label, that statistic will not be included in the list
98 of statistics in the /proc filesystem */
99
100#define IGNLABEL(comment) NULL
101static char *statsLabels[] = {
102 "RxOverrun",
103 IGNLABEL("RxPlcpCrcErr"),
104 IGNLABEL("RxPlcpFormatErr"),
105 IGNLABEL("RxPlcpLengthErr"),
106 "RxMacCrcErr",
107 "RxMacCrcOk",
108 "RxWepErr",
109 "RxWepOk",
110 "RetryLong",
111 "RetryShort",
112 "MaxRetries",
113 "NoAck",
114 "NoCts",
115 "RxAck",
116 "RxCts",
117 "TxAck",
118 "TxRts",
119 "TxCts",
120 "TxMc",
121 "TxBc",
122 "TxUcFrags",
123 "TxUcPackets",
124 "TxBeacon",
125 "RxBeacon",
126 "TxSinColl",
127 "TxMulColl",
128 "DefersNo",
129 "DefersProt",
130 "DefersEngy",
131 "DupFram",
132 "RxFragDisc",
133 "TxAged",
134 "RxAged",
135 "LostSync-MaxRetry",
136 "LostSync-MissedBeacons",
137 "LostSync-ArlExceeded",
138 "LostSync-Deauth",
139 "LostSync-Disassoced",
140 "LostSync-TsfTiming",
141 "HostTxMc",
142 "HostTxBc",
143 "HostTxUc",
144 "HostTxFail",
145 "HostRxMc",
146 "HostRxBc",
147 "HostRxUc",
148 "HostRxDiscard",
149 IGNLABEL("HmacTxMc"),
150 IGNLABEL("HmacTxBc"),
151 IGNLABEL("HmacTxUc"),
152 IGNLABEL("HmacTxFail"),
153 IGNLABEL("HmacRxMc"),
154 IGNLABEL("HmacRxBc"),
155 IGNLABEL("HmacRxUc"),
156 IGNLABEL("HmacRxDiscard"),
157 IGNLABEL("HmacRxAccepted"),
158 "SsidMismatch",
159 "ApMismatch",
160 "RatesMismatch",
161 "AuthReject",
162 "AuthTimeout",
163 "AssocReject",
164 "AssocTimeout",
165 IGNLABEL("ReasonOutsideTable"),
166 IGNLABEL("ReasonStatus1"),
167 IGNLABEL("ReasonStatus2"),
168 IGNLABEL("ReasonStatus3"),
169 IGNLABEL("ReasonStatus4"),
170 IGNLABEL("ReasonStatus5"),
171 IGNLABEL("ReasonStatus6"),
172 IGNLABEL("ReasonStatus7"),
173 IGNLABEL("ReasonStatus8"),
174 IGNLABEL("ReasonStatus9"),
175 IGNLABEL("ReasonStatus10"),
176 IGNLABEL("ReasonStatus11"),
177 IGNLABEL("ReasonStatus12"),
178 IGNLABEL("ReasonStatus13"),
179 IGNLABEL("ReasonStatus14"),
180 IGNLABEL("ReasonStatus15"),
181 IGNLABEL("ReasonStatus16"),
182 IGNLABEL("ReasonStatus17"),
183 IGNLABEL("ReasonStatus18"),
184 IGNLABEL("ReasonStatus19"),
185 "RxMan",
186 "TxMan",
187 "RxRefresh",
188 "TxRefresh",
189 "RxPoll",
190 "TxPoll",
191 "HostRetries",
192 "LostSync-HostReq",
193 "HostTxBytes",
194 "HostRxBytes",
195 "ElapsedUsec",
196 "ElapsedSec",
197 "LostSyncBetterAP",
198 "PrivacyMismatch",
199 "Jammed",
200 "DiscRxNotWepped",
201 "PhyEleMismatch",
202 (char*)-1 };
203#ifndef RUN_AT
204#define RUN_AT(x) (jiffies+(x))
205#endif
206
207
208/* These variables are for insmod, since it seems that the rates
209 can only be set in setup_card. Rates should be a comma separated
210 (no spaces) list of rates (up to 8). */
211
212static int rates[8];
213static int basic_rate;
214static char *ssids[3];
215
216static int io[4];
217static int irq[4];
218
219static
220int maxencrypt /* = 0 */; /* The highest rate that the card can encrypt at.
221 0 means no limit. For old cards this was 4 */
222
223static int auto_wep /* = 0 */; /* If set, it tries to figure out the wep mode */
224static int aux_bap /* = 0 */; /* Checks to see if the aux ports are needed to read
225 the bap, needed on some older cards and buses. */
226static int adhoc;
227
228static int probe = 1;
229
230static int proc_uid /* = 0 */;
231
232static int proc_gid /* = 0 */;
233
234static int airo_perm = 0555;
235
236static int proc_perm = 0644;
237
238MODULE_AUTHOR("Benjamin Reed");
239MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \
240 cards. Direct support for ISA/PCI/MPI cards and support \
241 for PCMCIA when used with airo_cs.");
242MODULE_LICENSE("Dual BSD/GPL");
243MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350");
244module_param_array(io, int, NULL, 0);
245module_param_array(irq, int, NULL, 0);
246module_param(basic_rate, int, 0);
247module_param_array(rates, int, NULL, 0);
248module_param_array(ssids, charp, NULL, 0);
249module_param(auto_wep, int, 0);
250MODULE_PARM_DESC(auto_wep, "If non-zero, the driver will keep looping through \
251the authentication options until an association is made. The value of \
252auto_wep is number of the wep keys to check. A value of 2 will try using \
253the key at index 0 and index 1.");
254module_param(aux_bap, int, 0);
255MODULE_PARM_DESC(aux_bap, "If non-zero, the driver will switch into a mode \
256than seems to work better for older cards with some older buses. Before \
257switching it checks that the switch is needed.");
258module_param(maxencrypt, int, 0);
259MODULE_PARM_DESC(maxencrypt, "The maximum speed that the card can do \
260encryption. Units are in 512kbs. Zero (default) means there is no limit. \
261Older cards used to be limited to 2mbs (4).");
262module_param(adhoc, int, 0);
263MODULE_PARM_DESC(adhoc, "If non-zero, the card will start in adhoc mode.");
264module_param(probe, int, 0);
265MODULE_PARM_DESC(probe, "If zero, the driver won't start the card.");
266
267module_param(proc_uid, int, 0);
268MODULE_PARM_DESC(proc_uid, "The uid that the /proc files will belong to.");
269module_param(proc_gid, int, 0);
270MODULE_PARM_DESC(proc_gid, "The gid that the /proc files will belong to.");
271module_param(airo_perm, int, 0);
272MODULE_PARM_DESC(airo_perm, "The permission bits of /proc/[driver/]aironet.");
273module_param(proc_perm, int, 0);
274MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc");
275
276/* This is a kind of sloppy hack to get this information to OUT4500 and
277 IN4500. I would be extremely interested in the situation where this
278 doesn't work though!!! */
279static int do8bitIO = 0;
280
281/* Return codes */
282#define SUCCESS 0
283#define ERROR -1
284#define NO_PACKET -2
285
286/* Commands */
287#define NOP2 0x0000
288#define MAC_ENABLE 0x0001
289#define MAC_DISABLE 0x0002
290#define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */
291#define CMD_SOFTRESET 0x0004
292#define HOSTSLEEP 0x0005
293#define CMD_MAGIC_PKT 0x0006
294#define CMD_SETWAKEMASK 0x0007
295#define CMD_READCFG 0x0008
296#define CMD_SETMODE 0x0009
297#define CMD_ALLOCATETX 0x000a
298#define CMD_TRANSMIT 0x000b
299#define CMD_DEALLOCATETX 0x000c
300#define NOP 0x0010
301#define CMD_WORKAROUND 0x0011
302#define CMD_ALLOCATEAUX 0x0020
303#define CMD_ACCESS 0x0021
304#define CMD_PCIBAP 0x0022
305#define CMD_PCIAUX 0x0023
306#define CMD_ALLOCBUF 0x0028
307#define CMD_GETTLV 0x0029
308#define CMD_PUTTLV 0x002a
309#define CMD_DELTLV 0x002b
310#define CMD_FINDNEXTTLV 0x002c
311#define CMD_PSPNODES 0x0030
312#define CMD_SETCW 0x0031
313#define CMD_SETPCF 0x0032
314#define CMD_SETPHYREG 0x003e
315#define CMD_TXTEST 0x003f
316#define MAC_ENABLETX 0x0101
317#define CMD_LISTBSS 0x0103
318#define CMD_SAVECFG 0x0108
319#define CMD_ENABLEAUX 0x0111
320#define CMD_WRITERID 0x0121
321#define CMD_USEPSPNODES 0x0130
322#define MAC_ENABLERX 0x0201
323
324/* Command errors */
325#define ERROR_QUALIF 0x00
326#define ERROR_ILLCMD 0x01
327#define ERROR_ILLFMT 0x02
328#define ERROR_INVFID 0x03
329#define ERROR_INVRID 0x04
330#define ERROR_LARGE 0x05
331#define ERROR_NDISABL 0x06
332#define ERROR_ALLOCBSY 0x07
333#define ERROR_NORD 0x0B
334#define ERROR_NOWR 0x0C
335#define ERROR_INVFIDTX 0x0D
336#define ERROR_TESTACT 0x0E
337#define ERROR_TAGNFND 0x12
338#define ERROR_DECODE 0x20
339#define ERROR_DESCUNAV 0x21
340#define ERROR_BADLEN 0x22
341#define ERROR_MODE 0x80
342#define ERROR_HOP 0x81
343#define ERROR_BINTER 0x82
344#define ERROR_RXMODE 0x83
345#define ERROR_MACADDR 0x84
346#define ERROR_RATES 0x85
347#define ERROR_ORDER 0x86
348#define ERROR_SCAN 0x87
349#define ERROR_AUTH 0x88
350#define ERROR_PSMODE 0x89
351#define ERROR_RTYPE 0x8A
352#define ERROR_DIVER 0x8B
353#define ERROR_SSID 0x8C
354#define ERROR_APLIST 0x8D
355#define ERROR_AUTOWAKE 0x8E
356#define ERROR_LEAP 0x8F
357
358/* Registers */
359#define COMMAND 0x00
360#define PARAM0 0x02
361#define PARAM1 0x04
362#define PARAM2 0x06
363#define STATUS 0x08
364#define RESP0 0x0a
365#define RESP1 0x0c
366#define RESP2 0x0e
367#define LINKSTAT 0x10
368#define SELECT0 0x18
369#define OFFSET0 0x1c
370#define RXFID 0x20
371#define TXALLOCFID 0x22
372#define TXCOMPLFID 0x24
373#define DATA0 0x36
374#define EVSTAT 0x30
375#define EVINTEN 0x32
376#define EVACK 0x34
377#define SWS0 0x28
378#define SWS1 0x2a
379#define SWS2 0x2c
380#define SWS3 0x2e
381#define AUXPAGE 0x3A
382#define AUXOFF 0x3C
383#define AUXDATA 0x3E
384
385#define FID_TX 1
386#define FID_RX 2
387/* Offset into aux memory for descriptors */
388#define AUX_OFFSET 0x800
389/* Size of allocated packets */
390#define PKTSIZE 1840
391#define RIDSIZE 2048
392/* Size of the transmit queue */
393#define MAXTXQ 64
394
395/* BAP selectors */
396#define BAP0 0 // Used for receiving packets
397#define BAP1 2 // Used for xmiting packets and working with RIDS
398
399/* Flags */
400#define COMMAND_BUSY 0x8000
401
402#define BAP_BUSY 0x8000
403#define BAP_ERR 0x4000
404#define BAP_DONE 0x2000
405
406#define PROMISC 0xffff
407#define NOPROMISC 0x0000
408
409#define EV_CMD 0x10
410#define EV_CLEARCOMMANDBUSY 0x4000
411#define EV_RX 0x01
412#define EV_TX 0x02
413#define EV_TXEXC 0x04
414#define EV_ALLOC 0x08
415#define EV_LINK 0x80
416#define EV_AWAKE 0x100
417#define EV_TXCPY 0x400
418#define EV_UNKNOWN 0x800
419#define EV_MIC 0x1000 /* Message Integrity Check Interrupt */
420#define EV_AWAKEN 0x2000
421#define STATUS_INTS (EV_AWAKE|EV_LINK|EV_TXEXC|EV_TX|EV_TXCPY|EV_RX|EV_MIC)
422
423#ifdef CHECK_UNKNOWN_INTS
424#define IGNORE_INTS ( EV_CMD | EV_UNKNOWN)
425#else
426#define IGNORE_INTS (~STATUS_INTS)
427#endif
428
429/* RID TYPES */
430#define RID_RW 0x20
431
432/* The RIDs */
433#define RID_CAPABILITIES 0xFF00
434#define RID_APINFO 0xFF01
435#define RID_RADIOINFO 0xFF02
436#define RID_UNKNOWN3 0xFF03
437#define RID_RSSI 0xFF04
438#define RID_CONFIG 0xFF10
439#define RID_SSID 0xFF11
440#define RID_APLIST 0xFF12
441#define RID_DRVNAME 0xFF13
442#define RID_ETHERENCAP 0xFF14
443#define RID_WEP_TEMP 0xFF15
444#define RID_WEP_PERM 0xFF16
445#define RID_MODULATION 0xFF17
446#define RID_OPTIONS 0xFF18
447#define RID_ACTUALCONFIG 0xFF20 /*readonly*/
448#define RID_FACTORYCONFIG 0xFF21
449#define RID_UNKNOWN22 0xFF22
450#define RID_LEAPUSERNAME 0xFF23
451#define RID_LEAPPASSWORD 0xFF24
452#define RID_STATUS 0xFF50
453#define RID_BEACON_HST 0xFF51
454#define RID_BUSY_HST 0xFF52
455#define RID_RETRIES_HST 0xFF53
456#define RID_UNKNOWN54 0xFF54
457#define RID_UNKNOWN55 0xFF55
458#define RID_UNKNOWN56 0xFF56
459#define RID_MIC 0xFF57
460#define RID_STATS16 0xFF60
461#define RID_STATS16DELTA 0xFF61
462#define RID_STATS16DELTACLEAR 0xFF62
463#define RID_STATS 0xFF68
464#define RID_STATSDELTA 0xFF69
465#define RID_STATSDELTACLEAR 0xFF6A
466#define RID_ECHOTEST_RID 0xFF70
467#define RID_ECHOTEST_RESULTS 0xFF71
468#define RID_BSSLISTFIRST 0xFF72
469#define RID_BSSLISTNEXT 0xFF73
470
471typedef struct {
472 u16 cmd;
473 u16 parm0;
474 u16 parm1;
475 u16 parm2;
476} Cmd;
477
478typedef struct {
479 u16 status;
480 u16 rsp0;
481 u16 rsp1;
482 u16 rsp2;
483} Resp;
484
485/*
486 * Rids and endian-ness: The Rids will always be in cpu endian, since
487 * this all the patches from the big-endian guys end up doing that.
488 * so all rid access should use the read/writeXXXRid routines.
489 */
490
491/* This is redundant for x86 archs, but it seems necessary for ARM */
492#pragma pack(1)
493
494/* This structure came from an email sent to me from an engineer at
495 aironet for inclusion into this driver */
496typedef struct {
497 u16 len;
498 u16 kindex;
499 u8 mac[ETH_ALEN];
500 u16 klen;
501 u8 key[16];
502} WepKeyRid;
503
504/* These structures are from the Aironet's PC4500 Developers Manual */
505typedef struct {
506 u16 len;
507 u8 ssid[32];
508} Ssid;
509
510typedef struct {
511 u16 len;
512 Ssid ssids[3];
513} SsidRid;
514
515typedef struct {
516 u16 len;
517 u16 modulation;
518#define MOD_DEFAULT 0
519#define MOD_CCK 1
520#define MOD_MOK 2
521} ModulationRid;
522
523typedef struct {
524 u16 len; /* sizeof(ConfigRid) */
525 u16 opmode; /* operating mode */
526#define MODE_STA_IBSS 0
527#define MODE_STA_ESS 1
528#define MODE_AP 2
529#define MODE_AP_RPTR 3
530#define MODE_ETHERNET_HOST (0<<8) /* rx payloads converted */
531#define MODE_LLC_HOST (1<<8) /* rx payloads left as is */
532#define MODE_AIRONET_EXTEND (1<<9) /* enable Aironet extenstions */
533#define MODE_AP_INTERFACE (1<<10) /* enable ap interface extensions */
534#define MODE_ANTENNA_ALIGN (1<<11) /* enable antenna alignment */
535#define MODE_ETHER_LLC (1<<12) /* enable ethernet LLC */
536#define MODE_LEAF_NODE (1<<13) /* enable leaf node bridge */
537#define MODE_CF_POLLABLE (1<<14) /* enable CF pollable */
538#define MODE_MIC (1<<15) /* enable MIC */
539 u16 rmode; /* receive mode */
540#define RXMODE_BC_MC_ADDR 0
541#define RXMODE_BC_ADDR 1 /* ignore multicasts */
542#define RXMODE_ADDR 2 /* ignore multicast and broadcast */
543#define RXMODE_RFMON 3 /* wireless monitor mode */
544#define RXMODE_RFMON_ANYBSS 4
545#define RXMODE_LANMON 5 /* lan style monitor -- data packets only */
546#define RXMODE_DISABLE_802_3_HEADER (1<<8) /* disables 802.3 header on rx */
547#define RXMODE_NORMALIZED_RSSI (1<<9) /* return normalized RSSI */
548 u16 fragThresh;
549 u16 rtsThres;
550 u8 macAddr[ETH_ALEN];
551 u8 rates[8];
552 u16 shortRetryLimit;
553 u16 longRetryLimit;
554 u16 txLifetime; /* in kusec */
555 u16 rxLifetime; /* in kusec */
556 u16 stationary;
557 u16 ordering;
558 u16 u16deviceType; /* for overriding device type */
559 u16 cfpRate;
560 u16 cfpDuration;
561 u16 _reserved1[3];
562 /*---------- Scanning/Associating ----------*/
563 u16 scanMode;
564#define SCANMODE_ACTIVE 0
565#define SCANMODE_PASSIVE 1
566#define SCANMODE_AIROSCAN 2
567 u16 probeDelay; /* in kusec */
568 u16 probeEnergyTimeout; /* in kusec */
569 u16 probeResponseTimeout;
570 u16 beaconListenTimeout;
571 u16 joinNetTimeout;
572 u16 authTimeout;
573 u16 authType;
574#define AUTH_OPEN 0x1
575#define AUTH_ENCRYPT 0x101
576#define AUTH_SHAREDKEY 0x102
577#define AUTH_ALLOW_UNENCRYPTED 0x200
578 u16 associationTimeout;
579 u16 specifiedApTimeout;
580 u16 offlineScanInterval;
581 u16 offlineScanDuration;
582 u16 linkLossDelay;
583 u16 maxBeaconLostTime;
584 u16 refreshInterval;
585#define DISABLE_REFRESH 0xFFFF
586 u16 _reserved1a[1];
587 /*---------- Power save operation ----------*/
588 u16 powerSaveMode;
589#define POWERSAVE_CAM 0
590#define POWERSAVE_PSP 1
591#define POWERSAVE_PSPCAM 2
592 u16 sleepForDtims;
593 u16 listenInterval;
594 u16 fastListenInterval;
595 u16 listenDecay;
596 u16 fastListenDelay;
597 u16 _reserved2[2];
598 /*---------- Ap/Ibss config items ----------*/
599 u16 beaconPeriod;
600 u16 atimDuration;
601 u16 hopPeriod;
602 u16 channelSet;
603 u16 channel;
604 u16 dtimPeriod;
605 u16 bridgeDistance;
606 u16 radioID;
607 /*---------- Radio configuration ----------*/
608 u16 radioType;
609#define RADIOTYPE_DEFAULT 0
610#define RADIOTYPE_802_11 1
611#define RADIOTYPE_LEGACY 2
612 u8 rxDiversity;
613 u8 txDiversity;
614 u16 txPower;
615#define TXPOWER_DEFAULT 0
616 u16 rssiThreshold;
617#define RSSI_DEFAULT 0
618 u16 modulation;
619#define PREAMBLE_AUTO 0
620#define PREAMBLE_LONG 1
621#define PREAMBLE_SHORT 2
622 u16 preamble;
623 u16 homeProduct;
624 u16 radioSpecific;
625 /*---------- Aironet Extensions ----------*/
626 u8 nodeName[16];
627 u16 arlThreshold;
628 u16 arlDecay;
629 u16 arlDelay;
630 u16 _reserved4[1];
631 /*---------- Aironet Extensions ----------*/
632 u8 magicAction;
633#define MAGIC_ACTION_STSCHG 1
634#define MAGIC_ACTION_RESUME 2
635#define MAGIC_IGNORE_MCAST (1<<8)
636#define MAGIC_IGNORE_BCAST (1<<9)
637#define MAGIC_SWITCH_TO_PSP (0<<10)
638#define MAGIC_STAY_IN_CAM (1<<10)
639 u8 magicControl;
640 u16 autoWake;
641} ConfigRid;
642
643typedef struct {
644 u16 len;
645 u8 mac[ETH_ALEN];
646 u16 mode;
647 u16 errorCode;
648 u16 sigQuality;
649 u16 SSIDlen;
650 char SSID[32];
651 char apName[16];
652 u8 bssid[4][ETH_ALEN];
653 u16 beaconPeriod;
654 u16 dimPeriod;
655 u16 atimDuration;
656 u16 hopPeriod;
657 u16 channelSet;
658 u16 channel;
659 u16 hopsToBackbone;
660 u16 apTotalLoad;
661 u16 generatedLoad;
662 u16 accumulatedArl;
663 u16 signalQuality;
664 u16 currentXmitRate;
665 u16 apDevExtensions;
666 u16 normalizedSignalStrength;
667 u16 shortPreamble;
668 u8 apIP[4];
669 u8 noisePercent; /* Noise percent in last second */
670 u8 noisedBm; /* Noise dBm in last second */
671 u8 noiseAvePercent; /* Noise percent in last minute */
672 u8 noiseAvedBm; /* Noise dBm in last minute */
673 u8 noiseMaxPercent; /* Highest noise percent in last minute */
674 u8 noiseMaxdBm; /* Highest noise dbm in last minute */
675 u16 load;
676 u8 carrier[4];
677 u16 assocStatus;
678#define STAT_NOPACKETS 0
679#define STAT_NOCARRIERSET 10
680#define STAT_GOTCARRIERSET 11
681#define STAT_WRONGSSID 20
682#define STAT_BADCHANNEL 25
683#define STAT_BADBITRATES 30
684#define STAT_BADPRIVACY 35
685#define STAT_APFOUND 40
686#define STAT_APREJECTED 50
687#define STAT_AUTHENTICATING 60
688#define STAT_DEAUTHENTICATED 61
689#define STAT_AUTHTIMEOUT 62
690#define STAT_ASSOCIATING 70
691#define STAT_DEASSOCIATED 71
692#define STAT_ASSOCTIMEOUT 72
693#define STAT_NOTAIROAP 73
694#define STAT_ASSOCIATED 80
695#define STAT_LEAPING 90
696#define STAT_LEAPFAILED 91
697#define STAT_LEAPTIMEDOUT 92
698#define STAT_LEAPCOMPLETE 93
699} StatusRid;
700
701typedef struct {
702 u16 len;
703 u16 spacer;
704 u32 vals[100];
705} StatsRid;
706
707
708typedef struct {
709 u16 len;
710 u8 ap[4][ETH_ALEN];
711} APListRid;
712
713typedef struct {
714 u16 len;
715 char oui[3];
716 char zero;
717 u16 prodNum;
718 char manName[32];
719 char prodName[16];
720 char prodVer[8];
721 char factoryAddr[ETH_ALEN];
722 char aironetAddr[ETH_ALEN];
723 u16 radioType;
724 u16 country;
725 char callid[ETH_ALEN];
726 char supportedRates[8];
727 char rxDiversity;
728 char txDiversity;
729 u16 txPowerLevels[8];
730 u16 hardVer;
731 u16 hardCap;
732 u16 tempRange;
733 u16 softVer;
734 u16 softSubVer;
735 u16 interfaceVer;
736 u16 softCap;
737 u16 bootBlockVer;
738 u16 requiredHard;
739 u16 extSoftCap;
740} CapabilityRid;
741
742typedef struct {
743 u16 len;
744 u16 index; /* First is 0 and 0xffff means end of list */
745#define RADIO_FH 1 /* Frequency hopping radio type */
746#define RADIO_DS 2 /* Direct sequence radio type */
747#define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */
748 u16 radioType;
749 u8 bssid[ETH_ALEN]; /* Mac address of the BSS */
750 u8 zero;
751 u8 ssidLen;
752 u8 ssid[32];
Dan Williams41480af2005-05-10 09:45:51 -0400753 u16 dBm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754#define CAP_ESS (1<<0)
755#define CAP_IBSS (1<<1)
756#define CAP_PRIVACY (1<<4)
757#define CAP_SHORTHDR (1<<5)
758 u16 cap;
759 u16 beaconInterval;
760 u8 rates[8]; /* Same as rates for config rid */
761 struct { /* For frequency hopping only */
762 u16 dwell;
763 u8 hopSet;
764 u8 hopPattern;
765 u8 hopIndex;
766 u8 fill;
767 } fh;
768 u16 dsChannel;
769 u16 atimWindow;
770} BSSListRid;
771
772typedef struct {
773 u8 rssipct;
774 u8 rssidBm;
775} tdsRssiEntry;
776
777typedef struct {
778 u16 len;
779 tdsRssiEntry x[256];
780} tdsRssiRid;
781
782typedef struct {
783 u16 len;
784 u16 state;
785 u16 multicastValid;
786 u8 multicast[16];
787 u16 unicastValid;
788 u8 unicast[16];
789} MICRid;
790
791typedef struct {
792 u16 typelen;
793
794 union {
795 u8 snap[8];
796 struct {
797 u8 dsap;
798 u8 ssap;
799 u8 control;
800 u8 orgcode[3];
801 u8 fieldtype[2];
802 } llc;
803 } u;
804 u32 mic;
805 u32 seq;
806} MICBuffer;
807
808typedef struct {
809 u8 da[ETH_ALEN];
810 u8 sa[ETH_ALEN];
811} etherHead;
812
813#pragma pack()
814
815#define TXCTL_TXOK (1<<1) /* report if tx is ok */
816#define TXCTL_TXEX (1<<2) /* report if tx fails */
817#define TXCTL_802_3 (0<<3) /* 802.3 packet */
818#define TXCTL_802_11 (1<<3) /* 802.11 mac packet */
819#define TXCTL_ETHERNET (0<<4) /* payload has ethertype */
820#define TXCTL_LLC (1<<4) /* payload is llc */
821#define TXCTL_RELEASE (0<<5) /* release after completion */
822#define TXCTL_NORELEASE (1<<5) /* on completion returns to host */
823
824#define BUSY_FID 0x10000
825
826#ifdef CISCO_EXT
827#define AIROMAGIC 0xa55a
828/* Warning : SIOCDEVPRIVATE may disapear during 2.5.X - Jean II */
829#ifdef SIOCIWFIRSTPRIV
830#ifdef SIOCDEVPRIVATE
831#define AIROOLDIOCTL SIOCDEVPRIVATE
832#define AIROOLDIDIFC AIROOLDIOCTL + 1
833#endif /* SIOCDEVPRIVATE */
834#else /* SIOCIWFIRSTPRIV */
835#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
836#endif /* SIOCIWFIRSTPRIV */
837/* This may be wrong. When using the new SIOCIWFIRSTPRIV range, we probably
838 * should use only "GET" ioctls (last bit set to 1). "SET" ioctls are root
839 * only and don't return the modified struct ifreq to the application which
840 * is usually a problem. - Jean II */
841#define AIROIOCTL SIOCIWFIRSTPRIV
842#define AIROIDIFC AIROIOCTL + 1
843
844/* Ioctl constants to be used in airo_ioctl.command */
845
846#define AIROGCAP 0 // Capability rid
847#define AIROGCFG 1 // USED A LOT
848#define AIROGSLIST 2 // System ID list
849#define AIROGVLIST 3 // List of specified AP's
850#define AIROGDRVNAM 4 // NOTUSED
851#define AIROGEHTENC 5 // NOTUSED
852#define AIROGWEPKTMP 6
853#define AIROGWEPKNV 7
854#define AIROGSTAT 8
855#define AIROGSTATSC32 9
856#define AIROGSTATSD32 10
857#define AIROGMICRID 11
858#define AIROGMICSTATS 12
859#define AIROGFLAGS 13
860#define AIROGID 14
861#define AIRORRID 15
862#define AIRORSWVERSION 17
863
864/* Leave gap of 40 commands after AIROGSTATSD32 for future */
865
866#define AIROPCAP AIROGSTATSD32 + 40
867#define AIROPVLIST AIROPCAP + 1
868#define AIROPSLIST AIROPVLIST + 1
869#define AIROPCFG AIROPSLIST + 1
870#define AIROPSIDS AIROPCFG + 1
871#define AIROPAPLIST AIROPSIDS + 1
872#define AIROPMACON AIROPAPLIST + 1 /* Enable mac */
873#define AIROPMACOFF AIROPMACON + 1 /* Disable mac */
874#define AIROPSTCLR AIROPMACOFF + 1
875#define AIROPWEPKEY AIROPSTCLR + 1
876#define AIROPWEPKEYNV AIROPWEPKEY + 1
877#define AIROPLEAPPWD AIROPWEPKEYNV + 1
878#define AIROPLEAPUSR AIROPLEAPPWD + 1
879
880/* Flash codes */
881
882#define AIROFLSHRST AIROPWEPKEYNV + 40
883#define AIROFLSHGCHR AIROFLSHRST + 1
884#define AIROFLSHSTFL AIROFLSHGCHR + 1
885#define AIROFLSHPCHR AIROFLSHSTFL + 1
886#define AIROFLPUTBUF AIROFLSHPCHR + 1
887#define AIRORESTART AIROFLPUTBUF + 1
888
889#define FLASHSIZE 32768
890#define AUXMEMSIZE (256 * 1024)
891
892typedef struct aironet_ioctl {
893 unsigned short command; // What to do
894 unsigned short len; // Len of data
895 unsigned short ridnum; // rid number
896 unsigned char __user *data; // d-data
897} aironet_ioctl;
898
Domen Puncer62595eb2005-06-20 23:54:37 +0200899static char swversion[] = "2.1";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900#endif /* CISCO_EXT */
901
902#define NUM_MODULES 2
903#define MIC_MSGLEN_MAX 2400
904#define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX
Dan Williams15db2762006-03-16 13:46:27 -0500905#define AIRO_DEF_MTU 2312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
907typedef struct {
908 u32 size; // size
909 u8 enabled; // MIC enabled or not
910 u32 rxSuccess; // successful packets received
911 u32 rxIncorrectMIC; // pkts dropped due to incorrect MIC comparison
912 u32 rxNotMICed; // pkts dropped due to not being MIC'd
913 u32 rxMICPlummed; // pkts dropped due to not having a MIC plummed
914 u32 rxWrongSequence; // pkts dropped due to sequence number violation
915 u32 reserve[32];
916} mic_statistics;
917
918typedef struct {
919 u32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2];
920 u64 accum; // accumulated mic, reduced to u32 in final()
921 int position; // current position (byte offset) in message
922 union {
923 u8 d8[4];
924 u32 d32;
925 } part; // saves partial message word across update() calls
926} emmh32_context;
927
928typedef struct {
929 emmh32_context seed; // Context - the seed
930 u32 rx; // Received sequence number
931 u32 tx; // Tx sequence number
932 u32 window; // Start of window
933 u8 valid; // Flag to say if context is valid or not
934 u8 key[16];
935} miccntx;
936
937typedef struct {
938 miccntx mCtx; // Multicast context
939 miccntx uCtx; // Unicast context
940} mic_module;
941
942typedef struct {
943 unsigned int rid: 16;
944 unsigned int len: 15;
945 unsigned int valid: 1;
946 dma_addr_t host_addr;
947} Rid;
948
949typedef struct {
950 unsigned int offset: 15;
951 unsigned int eoc: 1;
952 unsigned int len: 15;
953 unsigned int valid: 1;
954 dma_addr_t host_addr;
955} TxFid;
956
957typedef struct {
958 unsigned int ctl: 15;
959 unsigned int rdy: 1;
960 unsigned int len: 15;
961 unsigned int valid: 1;
962 dma_addr_t host_addr;
963} RxFid;
964
965/*
966 * Host receive descriptor
967 */
968typedef struct {
969 unsigned char __iomem *card_ram_off; /* offset into card memory of the
970 desc */
971 RxFid rx_desc; /* card receive descriptor */
972 char *virtual_host_addr; /* virtual address of host receive
973 buffer */
974 int pending;
975} HostRxDesc;
976
977/*
978 * Host transmit descriptor
979 */
980typedef struct {
981 unsigned char __iomem *card_ram_off; /* offset into card memory of the
982 desc */
983 TxFid tx_desc; /* card transmit descriptor */
984 char *virtual_host_addr; /* virtual address of host receive
985 buffer */
986 int pending;
987} HostTxDesc;
988
989/*
990 * Host RID descriptor
991 */
992typedef struct {
993 unsigned char __iomem *card_ram_off; /* offset into card memory of the
994 descriptor */
995 Rid rid_desc; /* card RID descriptor */
996 char *virtual_host_addr; /* virtual address of host receive
997 buffer */
998} HostRidDesc;
999
1000typedef struct {
1001 u16 sw0;
1002 u16 sw1;
1003 u16 status;
1004 u16 len;
1005#define HOST_SET (1 << 0)
1006#define HOST_INT_TX (1 << 1) /* Interrupt on successful TX */
1007#define HOST_INT_TXERR (1 << 2) /* Interrupt on unseccessful TX */
1008#define HOST_LCC_PAYLOAD (1 << 4) /* LLC payload, 0 = Ethertype */
1009#define HOST_DONT_RLSE (1 << 5) /* Don't release buffer when done */
1010#define HOST_DONT_RETRY (1 << 6) /* Don't retry trasmit */
1011#define HOST_CLR_AID (1 << 7) /* clear AID failure */
1012#define HOST_RTS (1 << 9) /* Force RTS use */
1013#define HOST_SHORT (1 << 10) /* Do short preamble */
1014 u16 ctl;
1015 u16 aid;
1016 u16 retries;
1017 u16 fill;
1018} TxCtlHdr;
1019
1020typedef struct {
1021 u16 ctl;
1022 u16 duration;
1023 char addr1[6];
1024 char addr2[6];
1025 char addr3[6];
1026 u16 seq;
1027 char addr4[6];
1028} WifiHdr;
1029
1030
1031typedef struct {
1032 TxCtlHdr ctlhdr;
1033 u16 fill1;
1034 u16 fill2;
1035 WifiHdr wifihdr;
1036 u16 gaplen;
1037 u16 status;
1038} WifiCtlHdr;
1039
Jouni Malinenff1d2762005-05-12 22:54:16 -04001040static WifiCtlHdr wifictlhdr8023 = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 .ctlhdr = {
1042 .ctl = HOST_DONT_RLSE,
1043 }
1044};
1045
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046// Frequency list (map channels to frequencies)
1047static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
1048 2447, 2452, 2457, 2462, 2467, 2472, 2484 };
1049
1050// A few details needed for WEP (Wireless Equivalent Privacy)
1051#define MAX_KEY_SIZE 13 // 128 (?) bits
1052#define MIN_KEY_SIZE 5 // 40 bits RC4 - WEP
1053typedef struct wep_key_t {
1054 u16 len;
1055 u8 key[16]; /* 40-bit and 104-bit keys */
1056} wep_key_t;
1057
1058/* Backward compatibility */
1059#ifndef IW_ENCODE_NOKEY
1060#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */
1061#define IW_ENCODE_MODE (IW_ENCODE_DISABLED | IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)
1062#endif /* IW_ENCODE_NOKEY */
1063
1064/* List of Wireless Handlers (new API) */
1065static const struct iw_handler_def airo_handler_def;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
1067static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)";
1068
1069struct airo_info;
1070
1071static int get_dec_u16( char *buffer, int *start, int limit );
1072static void OUT4500( struct airo_info *, u16 register, u16 value );
1073static unsigned short IN4500( struct airo_info *, u16 register );
1074static u16 setup_card(struct airo_info*, u8 *mac, int lock);
1075static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock );
1076static void disable_MAC(struct airo_info *ai, int lock);
1077static void enable_interrupts(struct airo_info*);
1078static void disable_interrupts(struct airo_info*);
1079static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
1080static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
1081static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
1082 int whichbap);
1083static int fast_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
1084 int whichbap);
1085static int bap_write(struct airo_info*, const u16 *pu16Src, int bytelen,
1086 int whichbap);
1087static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd);
1088static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock);
1089static int PC4500_writerid(struct airo_info*, u16 rid, const void
1090 *pBuf, int len, int lock);
1091static int do_writerid( struct airo_info*, u16 rid, const void *rid_data,
1092 int len, int dummy );
1093static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw);
1094static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket);
1095static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket);
1096
1097static int mpi_send_packet (struct net_device *dev);
1098static void mpi_unmap_card(struct pci_dev *pci);
1099static void mpi_receive_802_3(struct airo_info *ai);
1100static void mpi_receive_802_11(struct airo_info *ai);
1101static int waitbusy (struct airo_info *ai);
1102
1103static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs
1104 *regs);
1105static int airo_thread(void *data);
1106static void timer_func( struct net_device *dev );
1107static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
Jouni Malinenff1d2762005-05-12 22:54:16 -04001108static struct iw_statistics *airo_get_wireless_stats (struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109static void airo_read_wireless_stats (struct airo_info *local);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110#ifdef CISCO_EXT
1111static int readrids(struct net_device *dev, aironet_ioctl *comp);
1112static int writerids(struct net_device *dev, aironet_ioctl *comp);
Jouni Malinenff1d2762005-05-12 22:54:16 -04001113static int flashcard(struct net_device *dev, aironet_ioctl *comp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114#endif /* CISCO_EXT */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115static void micinit(struct airo_info *ai);
1116static int micsetup(struct airo_info *ai);
1117static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len);
1118static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen);
1119
Dan Williams41480af2005-05-10 09:45:51 -04001120static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi);
1121static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm);
1122
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123struct airo_info {
1124 struct net_device_stats stats;
1125 struct net_device *dev;
1126 /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we
1127 use the high bit to mark whether it is in use. */
1128#define MAX_FIDS 6
1129#define MPI_MAX_FIDS 1
1130 int fids[MAX_FIDS];
1131 ConfigRid config;
1132 char keyindex; // Used with auto wep
1133 char defindex; // Used with auto wep
1134 struct proc_dir_entry *proc_entry;
1135 spinlock_t aux_lock;
1136 unsigned long flags;
1137#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */
1138#define FLAG_RADIO_OFF 0 /* User disabling of MAC */
1139#define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */
1140#define FLAG_RADIO_MASK 0x03
1141#define FLAG_ENABLED 2
1142#define FLAG_ADHOC 3 /* Needed by MIC */
1143#define FLAG_MIC_CAPABLE 4
1144#define FLAG_UPDATE_MULTI 5
1145#define FLAG_UPDATE_UNI 6
1146#define FLAG_802_11 7
1147#define FLAG_PENDING_XMIT 9
1148#define FLAG_PENDING_XMIT11 10
1149#define FLAG_MPI 11
1150#define FLAG_REGISTERED 12
1151#define FLAG_COMMIT 13
1152#define FLAG_RESET 14
1153#define FLAG_FLASHING 15
1154#define JOB_MASK 0x1ff0000
1155#define JOB_DIE 16
1156#define JOB_XMIT 17
1157#define JOB_XMIT11 18
1158#define JOB_STATS 19
1159#define JOB_PROMISC 20
1160#define JOB_MIC 21
1161#define JOB_EVENT 22
1162#define JOB_AUTOWEP 23
1163#define JOB_WSTATS 24
1164 int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
1165 int whichbap);
1166 unsigned short *flash;
1167 tdsRssiEntry *rssi;
1168 struct task_struct *task;
1169 struct semaphore sem;
1170 pid_t thr_pid;
1171 wait_queue_head_t thr_wait;
1172 struct completion thr_exited;
1173 unsigned long expires;
1174 struct {
1175 struct sk_buff *skb;
1176 int fid;
1177 } xmit, xmit11;
1178 struct net_device *wifidev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 struct iw_statistics wstats; // wireless stats
1180 unsigned long scan_timestamp; /* Time started to scan */
1181 struct iw_spy_data spy_data;
1182 struct iw_public_data wireless_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 /* MIC stuff */
1184 struct crypto_tfm *tfm;
1185 mic_module mod[2];
1186 mic_statistics micstats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors
1188 HostTxDesc txfids[MPI_MAX_FIDS];
1189 HostRidDesc config_desc;
1190 unsigned long ridbus; // phys addr of config_desc
1191 struct sk_buff_head txq;// tx queue used by mpi350 code
1192 struct pci_dev *pci;
1193 unsigned char __iomem *pcimem;
1194 unsigned char __iomem *pciaux;
1195 unsigned char *shared;
1196 dma_addr_t shared_dma;
Pavel Machek1cc68ae2005-06-20 15:33:04 -07001197 pm_message_t power;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 SsidRid *SSID;
1199 APListRid *APList;
1200#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
1201 char proc_name[IFNAMSIZ];
1202};
1203
1204static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
1205 int whichbap) {
1206 return ai->bap_read(ai, pu16Dst, bytelen, whichbap);
1207}
1208
1209static int setup_proc_entry( struct net_device *dev,
1210 struct airo_info *apriv );
1211static int takedown_proc_entry( struct net_device *dev,
1212 struct airo_info *apriv );
1213
Jouni Malinenff1d2762005-05-12 22:54:16 -04001214static int cmdreset(struct airo_info *ai);
1215static int setflashmode (struct airo_info *ai);
1216static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime);
1217static int flashputbuf(struct airo_info *ai);
1218static int flashrestart(struct airo_info *ai,struct net_device *dev);
1219
Dan Williams934d8bf2006-03-16 13:46:23 -05001220#define airo_print(type, name, fmt, args...) \
1221 { printk(type "airo(%s): " fmt "\n", name, ##args); }
1222
1223#define airo_print_info(name, fmt, args...) \
1224 airo_print(KERN_INFO, name, fmt, ##args)
1225
1226#define airo_print_dbg(name, fmt, args...) \
1227 airo_print(KERN_DEBUG, name, fmt, ##args)
1228
1229#define airo_print_warn(name, fmt, args...) \
1230 airo_print(KERN_WARNING, name, fmt, ##args)
1231
1232#define airo_print_err(name, fmt, args...) \
1233 airo_print(KERN_ERR, name, fmt, ##args)
1234
1235
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236/***********************************************************************
1237 * MIC ROUTINES *
1238 ***********************************************************************
1239 */
1240
1241static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq);
1242static void MoveWindow(miccntx *context, u32 micSeq);
Jouni Malinenff1d2762005-05-12 22:54:16 -04001243static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *);
1244static void emmh32_init(emmh32_context *context);
1245static void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
1246static void emmh32_final(emmh32_context *context, u8 digest[4]);
1247static int flashpchar(struct airo_info *ai,int byte,int dwelltime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
1249/* micinit - Initialize mic seed */
1250
1251static void micinit(struct airo_info *ai)
1252{
1253 MICRid mic_rid;
1254
1255 clear_bit(JOB_MIC, &ai->flags);
1256 PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
1257 up(&ai->sem);
1258
1259 ai->micstats.enabled = (mic_rid.state & 0x00FF) ? 1 : 0;
1260
1261 if (ai->micstats.enabled) {
1262 /* Key must be valid and different */
1263 if (mic_rid.multicastValid && (!ai->mod[0].mCtx.valid ||
1264 (memcmp (ai->mod[0].mCtx.key, mic_rid.multicast,
1265 sizeof(ai->mod[0].mCtx.key)) != 0))) {
1266 /* Age current mic Context */
1267 memcpy(&ai->mod[1].mCtx,&ai->mod[0].mCtx,sizeof(miccntx));
1268 /* Initialize new context */
1269 memcpy(&ai->mod[0].mCtx.key,mic_rid.multicast,sizeof(mic_rid.multicast));
1270 ai->mod[0].mCtx.window = 33; //Window always points to the middle
1271 ai->mod[0].mCtx.rx = 0; //Rx Sequence numbers
1272 ai->mod[0].mCtx.tx = 0; //Tx sequence numbers
1273 ai->mod[0].mCtx.valid = 1; //Key is now valid
1274
1275 /* Give key to mic seed */
1276 emmh32_setseed(&ai->mod[0].mCtx.seed,mic_rid.multicast,sizeof(mic_rid.multicast), ai->tfm);
1277 }
1278
1279 /* Key must be valid and different */
1280 if (mic_rid.unicastValid && (!ai->mod[0].uCtx.valid ||
1281 (memcmp(ai->mod[0].uCtx.key, mic_rid.unicast,
1282 sizeof(ai->mod[0].uCtx.key)) != 0))) {
1283 /* Age current mic Context */
1284 memcpy(&ai->mod[1].uCtx,&ai->mod[0].uCtx,sizeof(miccntx));
1285 /* Initialize new context */
1286 memcpy(&ai->mod[0].uCtx.key,mic_rid.unicast,sizeof(mic_rid.unicast));
1287
1288 ai->mod[0].uCtx.window = 33; //Window always points to the middle
1289 ai->mod[0].uCtx.rx = 0; //Rx Sequence numbers
1290 ai->mod[0].uCtx.tx = 0; //Tx sequence numbers
1291 ai->mod[0].uCtx.valid = 1; //Key is now valid
1292
1293 //Give key to mic seed
1294 emmh32_setseed(&ai->mod[0].uCtx.seed, mic_rid.unicast, sizeof(mic_rid.unicast), ai->tfm);
1295 }
1296 } else {
1297 /* So next time we have a valid key and mic is enabled, we will update
1298 * the sequence number if the key is the same as before.
1299 */
1300 ai->mod[0].uCtx.valid = 0;
1301 ai->mod[0].mCtx.valid = 0;
1302 }
1303}
1304
1305/* micsetup - Get ready for business */
1306
1307static int micsetup(struct airo_info *ai) {
1308 int i;
1309
1310 if (ai->tfm == NULL)
Herbert Xueb6f1162005-09-01 17:43:25 -07001311 ai->tfm = crypto_alloc_tfm("aes", CRYPTO_TFM_REQ_MAY_SLEEP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312
1313 if (ai->tfm == NULL) {
Dan Williams934d8bf2006-03-16 13:46:23 -05001314 airo_print_err(ai->dev->name, "failed to load transform for AES");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 return ERROR;
1316 }
1317
1318 for (i=0; i < NUM_MODULES; i++) {
1319 memset(&ai->mod[i].mCtx,0,sizeof(miccntx));
1320 memset(&ai->mod[i].uCtx,0,sizeof(miccntx));
1321 }
1322 return SUCCESS;
1323}
1324
Jouni Malinenff1d2762005-05-12 22:54:16 -04001325static char micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
1327/*===========================================================================
1328 * Description: Mic a packet
1329 *
1330 * Inputs: etherHead * pointer to an 802.3 frame
1331 *
1332 * Returns: BOOLEAN if successful, otherwise false.
1333 * PacketTxLen will be updated with the mic'd packets size.
1334 *
1335 * Caveats: It is assumed that the frame buffer will already
1336 * be big enough to hold the largets mic message possible.
1337 * (No memory allocation is done here).
1338 *
1339 * Author: sbraneky (10/15/01)
1340 * Merciless hacks by rwilcher (1/14/02)
1341 */
1342
1343static int encapsulate(struct airo_info *ai ,etherHead *frame, MICBuffer *mic, int payLen)
1344{
1345 miccntx *context;
1346
1347 // Determine correct context
1348 // If not adhoc, always use unicast key
1349
1350 if (test_bit(FLAG_ADHOC, &ai->flags) && (frame->da[0] & 0x1))
1351 context = &ai->mod[0].mCtx;
1352 else
1353 context = &ai->mod[0].uCtx;
1354
1355 if (!context->valid)
1356 return ERROR;
1357
1358 mic->typelen = htons(payLen + 16); //Length of Mic'd packet
1359
1360 memcpy(&mic->u.snap, micsnap, sizeof(micsnap)); // Add Snap
1361
1362 // Add Tx sequence
1363 mic->seq = htonl(context->tx);
1364 context->tx += 2;
1365
1366 emmh32_init(&context->seed); // Mic the packet
1367 emmh32_update(&context->seed,frame->da,ETH_ALEN * 2); // DA,SA
1368 emmh32_update(&context->seed,(u8*)&mic->typelen,10); // Type/Length and Snap
1369 emmh32_update(&context->seed,(u8*)&mic->seq,sizeof(mic->seq)); //SEQ
1370 emmh32_update(&context->seed,frame->da + ETH_ALEN * 2,payLen); //payload
1371 emmh32_final(&context->seed, (u8*)&mic->mic);
1372
1373 /* New Type/length ?????????? */
1374 mic->typelen = 0; //Let NIC know it could be an oversized packet
1375 return SUCCESS;
1376}
1377
1378typedef enum {
1379 NONE,
1380 NOMIC,
1381 NOMICPLUMMED,
1382 SEQUENCE,
1383 INCORRECTMIC,
1384} mic_error;
1385
1386/*===========================================================================
1387 * Description: Decapsulates a MIC'd packet and returns the 802.3 packet
1388 * (removes the MIC stuff) if packet is a valid packet.
1389 *
1390 * Inputs: etherHead pointer to the 802.3 packet
1391 *
1392 * Returns: BOOLEAN - TRUE if packet should be dropped otherwise FALSE
1393 *
1394 * Author: sbraneky (10/15/01)
1395 * Merciless hacks by rwilcher (1/14/02)
1396 *---------------------------------------------------------------------------
1397 */
1398
1399static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *eth, u16 payLen)
1400{
1401 int i;
1402 u32 micSEQ;
1403 miccntx *context;
1404 u8 digest[4];
1405 mic_error micError = NONE;
1406
1407 // Check if the packet is a Mic'd packet
1408
1409 if (!ai->micstats.enabled) {
1410 //No Mic set or Mic OFF but we received a MIC'd packet.
1411 if (memcmp ((u8*)eth + 14, micsnap, sizeof(micsnap)) == 0) {
1412 ai->micstats.rxMICPlummed++;
1413 return ERROR;
1414 }
1415 return SUCCESS;
1416 }
1417
1418 if (ntohs(mic->typelen) == 0x888E)
1419 return SUCCESS;
1420
1421 if (memcmp (mic->u.snap, micsnap, sizeof(micsnap)) != 0) {
1422 // Mic enabled but packet isn't Mic'd
1423 ai->micstats.rxMICPlummed++;
1424 return ERROR;
1425 }
1426
1427 micSEQ = ntohl(mic->seq); //store SEQ as CPU order
1428
1429 //At this point we a have a mic'd packet and mic is enabled
1430 //Now do the mic error checking.
1431
1432 //Receive seq must be odd
1433 if ( (micSEQ & 1) == 0 ) {
1434 ai->micstats.rxWrongSequence++;
1435 return ERROR;
1436 }
1437
1438 for (i = 0; i < NUM_MODULES; i++) {
1439 int mcast = eth->da[0] & 1;
1440 //Determine proper context
1441 context = mcast ? &ai->mod[i].mCtx : &ai->mod[i].uCtx;
1442
1443 //Make sure context is valid
1444 if (!context->valid) {
1445 if (i == 0)
1446 micError = NOMICPLUMMED;
1447 continue;
1448 }
1449 //DeMic it
1450
1451 if (!mic->typelen)
1452 mic->typelen = htons(payLen + sizeof(MICBuffer) - 2);
1453
1454 emmh32_init(&context->seed);
1455 emmh32_update(&context->seed, eth->da, ETH_ALEN*2);
1456 emmh32_update(&context->seed, (u8 *)&mic->typelen, sizeof(mic->typelen)+sizeof(mic->u.snap));
1457 emmh32_update(&context->seed, (u8 *)&mic->seq,sizeof(mic->seq));
1458 emmh32_update(&context->seed, eth->da + ETH_ALEN*2,payLen);
1459 //Calculate MIC
1460 emmh32_final(&context->seed, digest);
1461
1462 if (memcmp(digest, &mic->mic, 4)) { //Make sure the mics match
1463 //Invalid Mic
1464 if (i == 0)
1465 micError = INCORRECTMIC;
1466 continue;
1467 }
1468
1469 //Check Sequence number if mics pass
1470 if (RxSeqValid(ai, context, mcast, micSEQ) == SUCCESS) {
1471 ai->micstats.rxSuccess++;
1472 return SUCCESS;
1473 }
1474 if (i == 0)
1475 micError = SEQUENCE;
1476 }
1477
1478 // Update statistics
1479 switch (micError) {
1480 case NOMICPLUMMED: ai->micstats.rxMICPlummed++; break;
1481 case SEQUENCE: ai->micstats.rxWrongSequence++; break;
1482 case INCORRECTMIC: ai->micstats.rxIncorrectMIC++; break;
1483 case NONE: break;
1484 case NOMIC: break;
1485 }
1486 return ERROR;
1487}
1488
1489/*===========================================================================
1490 * Description: Checks the Rx Seq number to make sure it is valid
1491 * and hasn't already been received
1492 *
1493 * Inputs: miccntx - mic context to check seq against
1494 * micSeq - the Mic seq number
1495 *
1496 * Returns: TRUE if valid otherwise FALSE.
1497 *
1498 * Author: sbraneky (10/15/01)
1499 * Merciless hacks by rwilcher (1/14/02)
1500 *---------------------------------------------------------------------------
1501 */
1502
1503static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq)
1504{
1505 u32 seq,index;
1506
1507 //Allow for the ap being rebooted - if it is then use the next
1508 //sequence number of the current sequence number - might go backwards
1509
1510 if (mcast) {
1511 if (test_bit(FLAG_UPDATE_MULTI, &ai->flags)) {
1512 clear_bit (FLAG_UPDATE_MULTI, &ai->flags);
1513 context->window = (micSeq > 33) ? micSeq : 33;
1514 context->rx = 0; // Reset rx
1515 }
1516 } else if (test_bit(FLAG_UPDATE_UNI, &ai->flags)) {
1517 clear_bit (FLAG_UPDATE_UNI, &ai->flags);
1518 context->window = (micSeq > 33) ? micSeq : 33; // Move window
1519 context->rx = 0; // Reset rx
1520 }
1521
1522 //Make sequence number relative to START of window
1523 seq = micSeq - (context->window - 33);
1524
1525 //Too old of a SEQ number to check.
1526 if ((s32)seq < 0)
1527 return ERROR;
1528
1529 if ( seq > 64 ) {
1530 //Window is infinite forward
1531 MoveWindow(context,micSeq);
1532 return SUCCESS;
1533 }
1534
1535 // We are in the window. Now check the context rx bit to see if it was already sent
1536 seq >>= 1; //divide by 2 because we only have odd numbers
1537 index = 1 << seq; //Get an index number
1538
1539 if (!(context->rx & index)) {
1540 //micSEQ falls inside the window.
1541 //Add seqence number to the list of received numbers.
1542 context->rx |= index;
1543
1544 MoveWindow(context,micSeq);
1545
1546 return SUCCESS;
1547 }
1548 return ERROR;
1549}
1550
1551static void MoveWindow(miccntx *context, u32 micSeq)
1552{
1553 u32 shift;
1554
1555 //Move window if seq greater than the middle of the window
1556 if (micSeq > context->window) {
1557 shift = (micSeq - context->window) >> 1;
1558
1559 //Shift out old
1560 if (shift < 32)
1561 context->rx >>= shift;
1562 else
1563 context->rx = 0;
1564
1565 context->window = micSeq; //Move window
1566 }
1567}
1568
1569/*==============================================*/
1570/*========== EMMH ROUTINES ====================*/
1571/*==============================================*/
1572
1573/* mic accumulate */
1574#define MIC_ACCUM(val) \
1575 context->accum += (u64)(val) * context->coeff[coeff_position++];
1576
1577static unsigned char aes_counter[16];
1578
1579/* expand the key to fill the MMH coefficient array */
Jouni Malinenff1d2762005-05-12 22:54:16 -04001580static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581{
1582 /* take the keying material, expand if necessary, truncate at 16-bytes */
1583 /* run through AES counter mode to generate context->coeff[] */
1584
1585 int i,j;
1586 u32 counter;
1587 u8 *cipher, plain[16];
1588 struct scatterlist sg[1];
1589
1590 crypto_cipher_setkey(tfm, pkey, 16);
1591 counter = 0;
1592 for (i = 0; i < (sizeof(context->coeff)/sizeof(context->coeff[0])); ) {
1593 aes_counter[15] = (u8)(counter >> 0);
1594 aes_counter[14] = (u8)(counter >> 8);
1595 aes_counter[13] = (u8)(counter >> 16);
1596 aes_counter[12] = (u8)(counter >> 24);
1597 counter++;
1598 memcpy (plain, aes_counter, 16);
Herbert Xu6df5b9f2005-09-19 22:30:11 +10001599 sg_set_buf(sg, plain, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 crypto_cipher_encrypt(tfm, sg, sg, 16);
Herbert Xu6df5b9f2005-09-19 22:30:11 +10001601 cipher = kmap(sg->page) + sg->offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 for (j=0; (j<16) && (i< (sizeof(context->coeff)/sizeof(context->coeff[0]))); ) {
1603 context->coeff[i++] = ntohl(*(u32 *)&cipher[j]);
1604 j += 4;
1605 }
1606 }
1607}
1608
1609/* prepare for calculation of a new mic */
Jouni Malinenff1d2762005-05-12 22:54:16 -04001610static void emmh32_init(emmh32_context *context)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611{
1612 /* prepare for new mic calculation */
1613 context->accum = 0;
1614 context->position = 0;
1615}
1616
1617/* add some bytes to the mic calculation */
Jouni Malinenff1d2762005-05-12 22:54:16 -04001618static void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619{
1620 int coeff_position, byte_position;
1621
1622 if (len == 0) return;
1623
1624 coeff_position = context->position >> 2;
1625
1626 /* deal with partial 32-bit word left over from last update */
1627 byte_position = context->position & 3;
1628 if (byte_position) {
1629 /* have a partial word in part to deal with */
1630 do {
1631 if (len == 0) return;
1632 context->part.d8[byte_position++] = *pOctets++;
1633 context->position++;
1634 len--;
1635 } while (byte_position < 4);
1636 MIC_ACCUM(htonl(context->part.d32));
1637 }
1638
1639 /* deal with full 32-bit words */
1640 while (len >= 4) {
1641 MIC_ACCUM(htonl(*(u32 *)pOctets));
1642 context->position += 4;
1643 pOctets += 4;
1644 len -= 4;
1645 }
1646
1647 /* deal with partial 32-bit word that will be left over from this update */
1648 byte_position = 0;
1649 while (len > 0) {
1650 context->part.d8[byte_position++] = *pOctets++;
1651 context->position++;
1652 len--;
1653 }
1654}
1655
1656/* mask used to zero empty bytes for final partial word */
1657static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L };
1658
1659/* calculate the mic */
Jouni Malinenff1d2762005-05-12 22:54:16 -04001660static void emmh32_final(emmh32_context *context, u8 digest[4])
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661{
1662 int coeff_position, byte_position;
1663 u32 val;
1664
1665 u64 sum, utmp;
1666 s64 stmp;
1667
1668 coeff_position = context->position >> 2;
1669
1670 /* deal with partial 32-bit word left over from last update */
1671 byte_position = context->position & 3;
1672 if (byte_position) {
1673 /* have a partial word in part to deal with */
1674 val = htonl(context->part.d32);
1675 MIC_ACCUM(val & mask32[byte_position]); /* zero empty bytes */
1676 }
1677
1678 /* reduce the accumulated u64 to a 32-bit MIC */
1679 sum = context->accum;
1680 stmp = (sum & 0xffffffffLL) - ((sum >> 32) * 15);
1681 utmp = (stmp & 0xffffffffLL) - ((stmp >> 32) * 15);
1682 sum = utmp & 0xffffffffLL;
1683 if (utmp > 0x10000000fLL)
1684 sum -= 15;
1685
1686 val = (u32)sum;
1687 digest[0] = (val>>24) & 0xFF;
1688 digest[1] = (val>>16) & 0xFF;
1689 digest[2] = (val>>8) & 0xFF;
1690 digest[3] = val & 0xFF;
1691}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
1693static int readBSSListRid(struct airo_info *ai, int first,
1694 BSSListRid *list) {
1695 int rc;
1696 Cmd cmd;
1697 Resp rsp;
1698
1699 if (first == 1) {
1700 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
1701 memset(&cmd, 0, sizeof(cmd));
1702 cmd.cmd=CMD_LISTBSS;
1703 if (down_interruptible(&ai->sem))
1704 return -ERESTARTSYS;
1705 issuecommand(ai, &cmd, &rsp);
1706 up(&ai->sem);
1707 /* Let the command take effect */
1708 ai->task = current;
1709 ssleep(3);
1710 ai->task = NULL;
1711 }
1712 rc = PC4500_readrid(ai, first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT,
1713 list, sizeof(*list), 1);
1714
1715 list->len = le16_to_cpu(list->len);
1716 list->index = le16_to_cpu(list->index);
1717 list->radioType = le16_to_cpu(list->radioType);
1718 list->cap = le16_to_cpu(list->cap);
1719 list->beaconInterval = le16_to_cpu(list->beaconInterval);
1720 list->fh.dwell = le16_to_cpu(list->fh.dwell);
1721 list->dsChannel = le16_to_cpu(list->dsChannel);
1722 list->atimWindow = le16_to_cpu(list->atimWindow);
Dan Williams41480af2005-05-10 09:45:51 -04001723 list->dBm = le16_to_cpu(list->dBm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 return rc;
1725}
1726
1727static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp, int lock) {
1728 int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM,
1729 wkr, sizeof(*wkr), lock);
1730
1731 wkr->len = le16_to_cpu(wkr->len);
1732 wkr->kindex = le16_to_cpu(wkr->kindex);
1733 wkr->klen = le16_to_cpu(wkr->klen);
1734 return rc;
1735}
1736/* In the writeXXXRid routines we copy the rids so that we don't screwup
1737 * the originals when we endian them... */
1738static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm, int lock) {
1739 int rc;
1740 WepKeyRid wkr = *pwkr;
1741
1742 wkr.len = cpu_to_le16(wkr.len);
1743 wkr.kindex = cpu_to_le16(wkr.kindex);
1744 wkr.klen = cpu_to_le16(wkr.klen);
1745 rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr), lock);
Dan Williams934d8bf2006-03-16 13:46:23 -05001746 if (rc!=SUCCESS) airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 if (perm) {
1748 rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr), lock);
1749 if (rc!=SUCCESS) {
Dan Williams934d8bf2006-03-16 13:46:23 -05001750 airo_print_err(ai->dev->name, "WEP_PERM set %x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 }
1752 }
1753 return rc;
1754}
1755
1756static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) {
1757 int i;
1758 int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1);
1759
1760 ssidr->len = le16_to_cpu(ssidr->len);
1761 for(i = 0; i < 3; i++) {
1762 ssidr->ssids[i].len = le16_to_cpu(ssidr->ssids[i].len);
1763 }
1764 return rc;
1765}
1766static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock) {
1767 int rc;
1768 int i;
1769 SsidRid ssidr = *pssidr;
1770
1771 ssidr.len = cpu_to_le16(ssidr.len);
1772 for(i = 0; i < 3; i++) {
1773 ssidr.ssids[i].len = cpu_to_le16(ssidr.ssids[i].len);
1774 }
1775 rc = PC4500_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr), lock);
1776 return rc;
1777}
1778static int readConfigRid(struct airo_info*ai, int lock) {
1779 int rc;
1780 u16 *s;
1781 ConfigRid cfg;
1782
1783 if (ai->config.len)
1784 return SUCCESS;
1785
1786 rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock);
1787 if (rc != SUCCESS)
1788 return rc;
1789
1790 for(s = &cfg.len; s <= &cfg.rtsThres; s++) *s = le16_to_cpu(*s);
1791
1792 for(s = &cfg.shortRetryLimit; s <= &cfg.radioType; s++)
1793 *s = le16_to_cpu(*s);
1794
1795 for(s = &cfg.txPower; s <= &cfg.radioSpecific; s++)
1796 *s = le16_to_cpu(*s);
1797
1798 for(s = &cfg.arlThreshold; s <= &cfg._reserved4[0]; s++)
1799 *s = cpu_to_le16(*s);
1800
1801 for(s = &cfg.autoWake; s <= &cfg.autoWake; s++)
1802 *s = cpu_to_le16(*s);
1803
1804 ai->config = cfg;
1805 return SUCCESS;
1806}
1807static inline void checkThrottle(struct airo_info *ai) {
1808 int i;
1809/* Old hardware had a limit on encryption speed */
1810 if (ai->config.authType != AUTH_OPEN && maxencrypt) {
1811 for(i=0; i<8; i++) {
1812 if (ai->config.rates[i] > maxencrypt) {
1813 ai->config.rates[i] = 0;
1814 }
1815 }
1816 }
1817}
1818static int writeConfigRid(struct airo_info*ai, int lock) {
1819 u16 *s;
1820 ConfigRid cfgr;
1821
1822 if (!test_bit (FLAG_COMMIT, &ai->flags))
1823 return SUCCESS;
1824
1825 clear_bit (FLAG_COMMIT, &ai->flags);
1826 clear_bit (FLAG_RESET, &ai->flags);
1827 checkThrottle(ai);
1828 cfgr = ai->config;
1829
1830 if ((cfgr.opmode & 0xFF) == MODE_STA_IBSS)
1831 set_bit(FLAG_ADHOC, &ai->flags);
1832 else
1833 clear_bit(FLAG_ADHOC, &ai->flags);
1834
1835 for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s);
1836
1837 for(s = &cfgr.shortRetryLimit; s <= &cfgr.radioType; s++)
1838 *s = cpu_to_le16(*s);
1839
1840 for(s = &cfgr.txPower; s <= &cfgr.radioSpecific; s++)
1841 *s = cpu_to_le16(*s);
1842
1843 for(s = &cfgr.arlThreshold; s <= &cfgr._reserved4[0]; s++)
1844 *s = cpu_to_le16(*s);
1845
1846 for(s = &cfgr.autoWake; s <= &cfgr.autoWake; s++)
1847 *s = cpu_to_le16(*s);
1848
1849 return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock);
1850}
1851static int readStatusRid(struct airo_info*ai, StatusRid *statr, int lock) {
1852 int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock);
1853 u16 *s;
1854
1855 statr->len = le16_to_cpu(statr->len);
1856 for(s = &statr->mode; s <= &statr->SSIDlen; s++) *s = le16_to_cpu(*s);
1857
1858 for(s = &statr->beaconPeriod; s <= &statr->shortPreamble; s++)
1859 *s = le16_to_cpu(*s);
1860 statr->load = le16_to_cpu(statr->load);
1861 statr->assocStatus = le16_to_cpu(statr->assocStatus);
1862 return rc;
1863}
1864static int readAPListRid(struct airo_info*ai, APListRid *aplr) {
1865 int rc = PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr), 1);
1866 aplr->len = le16_to_cpu(aplr->len);
1867 return rc;
1868}
1869static int writeAPListRid(struct airo_info*ai, APListRid *aplr, int lock) {
1870 int rc;
1871 aplr->len = cpu_to_le16(aplr->len);
1872 rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock);
1873 return rc;
1874}
1875static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr, int lock) {
1876 int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock);
1877 u16 *s;
1878
1879 capr->len = le16_to_cpu(capr->len);
1880 capr->prodNum = le16_to_cpu(capr->prodNum);
1881 capr->radioType = le16_to_cpu(capr->radioType);
1882 capr->country = le16_to_cpu(capr->country);
1883 for(s = &capr->txPowerLevels[0]; s <= &capr->requiredHard; s++)
1884 *s = le16_to_cpu(*s);
1885 return rc;
1886}
1887static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) {
1888 int rc = PC4500_readrid(ai, rid, sr, sizeof(*sr), lock);
1889 u32 *i;
1890
1891 sr->len = le16_to_cpu(sr->len);
1892 for(i = &sr->vals[0]; i <= &sr->vals[99]; i++) *i = le32_to_cpu(*i);
1893 return rc;
1894}
1895
1896static int airo_open(struct net_device *dev) {
1897 struct airo_info *info = dev->priv;
1898 Resp rsp;
1899
1900 if (test_bit(FLAG_FLASHING, &info->flags))
1901 return -EIO;
1902
1903 /* Make sure the card is configured.
1904 * Wireless Extensions may postpone config changes until the card
1905 * is open (to pipeline changes and speed-up card setup). If
1906 * those changes are not yet commited, do it now - Jean II */
1907 if (test_bit (FLAG_COMMIT, &info->flags)) {
1908 disable_MAC(info, 1);
1909 writeConfigRid(info, 1);
1910 }
1911
1912 if (info->wifidev != dev) {
1913 /* Power on the MAC controller (which may have been disabled) */
1914 clear_bit(FLAG_RADIO_DOWN, &info->flags);
1915 enable_interrupts(info);
1916 }
1917 enable_MAC(info, &rsp, 1);
1918
1919 netif_start_queue(dev);
1920 return 0;
1921}
1922
1923static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
1924 int npacks, pending;
1925 unsigned long flags;
1926 struct airo_info *ai = dev->priv;
1927
1928 if (!skb) {
Dan Williams934d8bf2006-03-16 13:46:23 -05001929 airo_print_err(dev->name, "%s: skb == NULL!",__FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 return 0;
1931 }
1932 npacks = skb_queue_len (&ai->txq);
1933
1934 if (npacks >= MAXTXQ - 1) {
1935 netif_stop_queue (dev);
1936 if (npacks > MAXTXQ) {
1937 ai->stats.tx_fifo_errors++;
1938 return 1;
1939 }
1940 skb_queue_tail (&ai->txq, skb);
1941 return 0;
1942 }
1943
1944 spin_lock_irqsave(&ai->aux_lock, flags);
1945 skb_queue_tail (&ai->txq, skb);
1946 pending = test_bit(FLAG_PENDING_XMIT, &ai->flags);
1947 spin_unlock_irqrestore(&ai->aux_lock,flags);
1948 netif_wake_queue (dev);
1949
1950 if (pending == 0) {
1951 set_bit(FLAG_PENDING_XMIT, &ai->flags);
1952 mpi_send_packet (dev);
1953 }
1954 return 0;
1955}
1956
1957/*
1958 * @mpi_send_packet
1959 *
1960 * Attempt to transmit a packet. Can be called from interrupt
1961 * or transmit . return number of packets we tried to send
1962 */
1963
1964static int mpi_send_packet (struct net_device *dev)
1965{
1966 struct sk_buff *skb;
1967 unsigned char *buffer;
1968 s16 len, *payloadLen;
1969 struct airo_info *ai = dev->priv;
1970 u8 *sendbuf;
1971
1972 /* get a packet to send */
1973
1974 if ((skb = skb_dequeue(&ai->txq)) == 0) {
Dan Williams934d8bf2006-03-16 13:46:23 -05001975 airo_print_err(dev->name,
1976 "%s: Dequeue'd zero in send_packet()",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 __FUNCTION__);
1978 return 0;
1979 }
1980
1981 /* check min length*/
1982 len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
1983 buffer = skb->data;
1984
1985 ai->txfids[0].tx_desc.offset = 0;
1986 ai->txfids[0].tx_desc.valid = 1;
1987 ai->txfids[0].tx_desc.eoc = 1;
1988 ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr);
1989
1990/*
1991 * Magic, the cards firmware needs a length count (2 bytes) in the host buffer
1992 * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen
1993 * is immediatly after it. ------------------------------------------------
1994 * |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA|
1995 * ------------------------------------------------
1996 */
1997
1998 memcpy((char *)ai->txfids[0].virtual_host_addr,
1999 (char *)&wifictlhdr8023, sizeof(wifictlhdr8023));
2000
2001 payloadLen = (s16 *)(ai->txfids[0].virtual_host_addr +
2002 sizeof(wifictlhdr8023));
2003 sendbuf = ai->txfids[0].virtual_host_addr +
2004 sizeof(wifictlhdr8023) + 2 ;
2005
2006 /*
2007 * Firmware automaticly puts 802 header on so
2008 * we don't need to account for it in the length
2009 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
2011 (ntohs(((u16 *)buffer)[6]) != 0x888E)) {
2012 MICBuffer pMic;
2013
2014 if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS)
2015 return ERROR;
2016
2017 *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic));
2018 ai->txfids[0].tx_desc.len += sizeof(pMic);
2019 /* copy data into airo dma buffer */
2020 memcpy (sendbuf, buffer, sizeof(etherHead));
2021 buffer += sizeof(etherHead);
2022 sendbuf += sizeof(etherHead);
2023 memcpy (sendbuf, &pMic, sizeof(pMic));
2024 sendbuf += sizeof(pMic);
2025 memcpy (sendbuf, buffer, len - sizeof(etherHead));
Adrian Bunka39d3e72006-01-21 01:35:15 +01002026 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 *payloadLen = cpu_to_le16(len - sizeof(etherHead));
2028
2029 dev->trans_start = jiffies;
2030
2031 /* copy data into airo dma buffer */
2032 memcpy(sendbuf, buffer, len);
2033 }
2034
2035 memcpy_toio(ai->txfids[0].card_ram_off,
2036 &ai->txfids[0].tx_desc, sizeof(TxFid));
2037
2038 OUT4500(ai, EVACK, 8);
2039
2040 dev_kfree_skb_any(skb);
2041 return 1;
2042}
2043
Gabriel A. Devenyi29b09fc2005-11-03 19:30:47 -05002044static void get_tx_error(struct airo_info *ai, s32 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045{
2046 u16 status;
2047
2048 if (fid < 0)
2049 status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status;
2050 else {
2051 if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) != SUCCESS)
2052 return;
2053 bap_read(ai, &status, 2, BAP0);
2054 }
2055 if (le16_to_cpu(status) & 2) /* Too many retries */
2056 ai->stats.tx_aborted_errors++;
2057 if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */
2058 ai->stats.tx_heartbeat_errors++;
2059 if (le16_to_cpu(status) & 8) /* Aid fail */
2060 { }
2061 if (le16_to_cpu(status) & 0x10) /* MAC disabled */
2062 ai->stats.tx_carrier_errors++;
2063 if (le16_to_cpu(status) & 0x20) /* Association lost */
2064 { }
2065 /* We produce a TXDROP event only for retry or lifetime
2066 * exceeded, because that's the only status that really mean
2067 * that this particular node went away.
2068 * Other errors means that *we* screwed up. - Jean II */
2069 if ((le16_to_cpu(status) & 2) ||
2070 (le16_to_cpu(status) & 4)) {
2071 union iwreq_data wrqu;
2072 char junk[0x18];
2073
2074 /* Faster to skip over useless data than to do
2075 * another bap_setup(). We are at offset 0x6 and
2076 * need to go to 0x18 and read 6 bytes - Jean II */
2077 bap_read(ai, (u16 *) junk, 0x18, BAP0);
2078
2079 /* Copy 802.11 dest address.
2080 * We use the 802.11 header because the frame may
2081 * not be 802.3 or may be mangled...
2082 * In Ad-Hoc mode, it will be the node address.
2083 * In managed mode, it will be most likely the AP addr
2084 * User space will figure out how to convert it to
2085 * whatever it needs (IP address or else).
2086 * - Jean II */
2087 memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN);
2088 wrqu.addr.sa_family = ARPHRD_ETHER;
2089
2090 /* Send event to user space */
2091 wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL);
2092 }
2093}
2094
2095static void airo_end_xmit(struct net_device *dev) {
2096 u16 status;
2097 int i;
2098 struct airo_info *priv = dev->priv;
2099 struct sk_buff *skb = priv->xmit.skb;
2100 int fid = priv->xmit.fid;
2101 u32 *fids = priv->fids;
2102
2103 clear_bit(JOB_XMIT, &priv->flags);
2104 clear_bit(FLAG_PENDING_XMIT, &priv->flags);
2105 status = transmit_802_3_packet (priv, fids[fid], skb->data);
2106 up(&priv->sem);
2107
2108 i = 0;
2109 if ( status == SUCCESS ) {
2110 dev->trans_start = jiffies;
2111 for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++);
2112 } else {
2113 priv->fids[fid] &= 0xffff;
2114 priv->stats.tx_window_errors++;
2115 }
2116 if (i < MAX_FIDS / 2)
2117 netif_wake_queue(dev);
2118 dev_kfree_skb(skb);
2119}
2120
2121static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
2122 s16 len;
2123 int i, j;
2124 struct airo_info *priv = dev->priv;
2125 u32 *fids = priv->fids;
2126
2127 if ( skb == NULL ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002128 airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 return 0;
2130 }
2131
2132 /* Find a vacant FID */
2133 for( i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++ );
2134 for( j = i + 1; j < MAX_FIDS / 2 && (fids[j] & 0xffff0000); j++ );
2135
2136 if ( j >= MAX_FIDS / 2 ) {
2137 netif_stop_queue(dev);
2138
2139 if (i == MAX_FIDS / 2) {
2140 priv->stats.tx_fifo_errors++;
2141 return 1;
2142 }
2143 }
2144 /* check min length*/
2145 len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
2146 /* Mark fid as used & save length for later */
2147 fids[i] |= (len << 16);
2148 priv->xmit.skb = skb;
2149 priv->xmit.fid = i;
2150 if (down_trylock(&priv->sem) != 0) {
2151 set_bit(FLAG_PENDING_XMIT, &priv->flags);
2152 netif_stop_queue(dev);
2153 set_bit(JOB_XMIT, &priv->flags);
2154 wake_up_interruptible(&priv->thr_wait);
2155 } else
2156 airo_end_xmit(dev);
2157 return 0;
2158}
2159
2160static void airo_end_xmit11(struct net_device *dev) {
2161 u16 status;
2162 int i;
2163 struct airo_info *priv = dev->priv;
2164 struct sk_buff *skb = priv->xmit11.skb;
2165 int fid = priv->xmit11.fid;
2166 u32 *fids = priv->fids;
2167
2168 clear_bit(JOB_XMIT11, &priv->flags);
2169 clear_bit(FLAG_PENDING_XMIT11, &priv->flags);
2170 status = transmit_802_11_packet (priv, fids[fid], skb->data);
2171 up(&priv->sem);
2172
2173 i = MAX_FIDS / 2;
2174 if ( status == SUCCESS ) {
2175 dev->trans_start = jiffies;
2176 for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++);
2177 } else {
2178 priv->fids[fid] &= 0xffff;
2179 priv->stats.tx_window_errors++;
2180 }
2181 if (i < MAX_FIDS)
2182 netif_wake_queue(dev);
2183 dev_kfree_skb(skb);
2184}
2185
2186static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
2187 s16 len;
2188 int i, j;
2189 struct airo_info *priv = dev->priv;
2190 u32 *fids = priv->fids;
2191
2192 if (test_bit(FLAG_MPI, &priv->flags)) {
2193 /* Not implemented yet for MPI350 */
2194 netif_stop_queue(dev);
2195 return -ENETDOWN;
2196 }
2197
2198 if ( skb == NULL ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002199 airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 return 0;
2201 }
2202
2203 /* Find a vacant FID */
2204 for( i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++ );
2205 for( j = i + 1; j < MAX_FIDS && (fids[j] & 0xffff0000); j++ );
2206
2207 if ( j >= MAX_FIDS ) {
2208 netif_stop_queue(dev);
2209
2210 if (i == MAX_FIDS) {
2211 priv->stats.tx_fifo_errors++;
2212 return 1;
2213 }
2214 }
2215 /* check min length*/
2216 len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
2217 /* Mark fid as used & save length for later */
2218 fids[i] |= (len << 16);
2219 priv->xmit11.skb = skb;
2220 priv->xmit11.fid = i;
2221 if (down_trylock(&priv->sem) != 0) {
2222 set_bit(FLAG_PENDING_XMIT11, &priv->flags);
2223 netif_stop_queue(dev);
2224 set_bit(JOB_XMIT11, &priv->flags);
2225 wake_up_interruptible(&priv->thr_wait);
2226 } else
2227 airo_end_xmit11(dev);
2228 return 0;
2229}
2230
2231static void airo_read_stats(struct airo_info *ai) {
2232 StatsRid stats_rid;
2233 u32 *vals = stats_rid.vals;
2234
2235 clear_bit(JOB_STATS, &ai->flags);
Pavel Machekca078ba2005-09-03 15:56:57 -07002236 if (ai->power.event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 up(&ai->sem);
2238 return;
2239 }
2240 readStatsRid(ai, &stats_rid, RID_STATS, 0);
2241 up(&ai->sem);
2242
2243 ai->stats.rx_packets = vals[43] + vals[44] + vals[45];
2244 ai->stats.tx_packets = vals[39] + vals[40] + vals[41];
2245 ai->stats.rx_bytes = vals[92];
2246 ai->stats.tx_bytes = vals[91];
2247 ai->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4];
2248 ai->stats.tx_errors = vals[42] + ai->stats.tx_fifo_errors;
2249 ai->stats.multicast = vals[43];
2250 ai->stats.collisions = vals[89];
2251
2252 /* detailed rx_errors: */
2253 ai->stats.rx_length_errors = vals[3];
2254 ai->stats.rx_crc_errors = vals[4];
2255 ai->stats.rx_frame_errors = vals[2];
2256 ai->stats.rx_fifo_errors = vals[0];
2257}
2258
Jouni Malinenff1d2762005-05-12 22:54:16 -04002259static struct net_device_stats *airo_get_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260{
2261 struct airo_info *local = dev->priv;
2262
2263 if (!test_bit(JOB_STATS, &local->flags)) {
2264 /* Get stats out of the card if available */
2265 if (down_trylock(&local->sem) != 0) {
2266 set_bit(JOB_STATS, &local->flags);
2267 wake_up_interruptible(&local->thr_wait);
2268 } else
2269 airo_read_stats(local);
2270 }
2271
2272 return &local->stats;
2273}
2274
2275static void airo_set_promisc(struct airo_info *ai) {
2276 Cmd cmd;
2277 Resp rsp;
2278
2279 memset(&cmd, 0, sizeof(cmd));
2280 cmd.cmd=CMD_SETMODE;
2281 clear_bit(JOB_PROMISC, &ai->flags);
2282 cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
2283 issuecommand(ai, &cmd, &rsp);
2284 up(&ai->sem);
2285}
2286
2287static void airo_set_multicast_list(struct net_device *dev) {
2288 struct airo_info *ai = dev->priv;
2289
2290 if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
2291 change_bit(FLAG_PROMISC, &ai->flags);
2292 if (down_trylock(&ai->sem) != 0) {
2293 set_bit(JOB_PROMISC, &ai->flags);
2294 wake_up_interruptible(&ai->thr_wait);
2295 } else
2296 airo_set_promisc(ai);
2297 }
2298
2299 if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) {
2300 /* Turn on multicast. (Should be already setup...) */
2301 }
2302}
2303
2304static int airo_set_mac_address(struct net_device *dev, void *p)
2305{
2306 struct airo_info *ai = dev->priv;
2307 struct sockaddr *addr = p;
2308 Resp rsp;
2309
2310 readConfigRid(ai, 1);
2311 memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
2312 set_bit (FLAG_COMMIT, &ai->flags);
2313 disable_MAC(ai, 1);
2314 writeConfigRid (ai, 1);
2315 enable_MAC(ai, &rsp, 1);
2316 memcpy (ai->dev->dev_addr, addr->sa_data, dev->addr_len);
2317 if (ai->wifidev)
2318 memcpy (ai->wifidev->dev_addr, addr->sa_data, dev->addr_len);
2319 return 0;
2320}
2321
2322static int airo_change_mtu(struct net_device *dev, int new_mtu)
2323{
2324 if ((new_mtu < 68) || (new_mtu > 2400))
2325 return -EINVAL;
2326 dev->mtu = new_mtu;
2327 return 0;
2328}
2329
2330
2331static int airo_close(struct net_device *dev) {
2332 struct airo_info *ai = dev->priv;
2333
2334 netif_stop_queue(dev);
2335
2336 if (ai->wifidev != dev) {
2337#ifdef POWER_ON_DOWN
2338 /* Shut power to the card. The idea is that the user can save
2339 * power when he doesn't need the card with "ifconfig down".
2340 * That's the method that is most friendly towards the network
2341 * stack (i.e. the network stack won't try to broadcast
2342 * anything on the interface and routes are gone. Jean II */
2343 set_bit(FLAG_RADIO_DOWN, &ai->flags);
2344 disable_MAC(ai, 1);
2345#endif
2346 disable_interrupts( ai );
2347 }
2348 return 0;
2349}
2350
2351static void del_airo_dev( struct net_device *dev );
2352
2353void stop_airo_card( struct net_device *dev, int freeres )
2354{
2355 struct airo_info *ai = dev->priv;
2356
2357 set_bit(FLAG_RADIO_DOWN, &ai->flags);
2358 disable_MAC(ai, 1);
2359 disable_interrupts(ai);
2360 free_irq( dev->irq, dev );
2361 takedown_proc_entry( dev, ai );
2362 if (test_bit(FLAG_REGISTERED, &ai->flags)) {
2363 unregister_netdev( dev );
2364 if (ai->wifidev) {
2365 unregister_netdev(ai->wifidev);
2366 free_netdev(ai->wifidev);
2367 ai->wifidev = NULL;
2368 }
2369 clear_bit(FLAG_REGISTERED, &ai->flags);
2370 }
2371 set_bit(JOB_DIE, &ai->flags);
2372 kill_proc(ai->thr_pid, SIGTERM, 1);
2373 wait_for_completion(&ai->thr_exited);
2374
2375 /*
2376 * Clean out tx queue
2377 */
David S. Millerb03efcf2005-07-08 14:57:23 -07002378 if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 struct sk_buff *skb = NULL;
2380 for (;(skb = skb_dequeue(&ai->txq));)
2381 dev_kfree_skb(skb);
2382 }
2383
Jesper Juhlb4558ea2005-10-28 16:53:13 -04002384 kfree(ai->flash);
2385 kfree(ai->rssi);
2386 kfree(ai->APList);
2387 kfree(ai->SSID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 if (freeres) {
2389 /* PCMCIA frees this stuff, so only for PCI and ISA */
2390 release_region( dev->base_addr, 64 );
2391 if (test_bit(FLAG_MPI, &ai->flags)) {
2392 if (ai->pci)
2393 mpi_unmap_card(ai->pci);
2394 if (ai->pcimem)
2395 iounmap(ai->pcimem);
2396 if (ai->pciaux)
2397 iounmap(ai->pciaux);
2398 pci_free_consistent(ai->pci, PCI_SHARED_LEN,
2399 ai->shared, ai->shared_dma);
2400 }
2401 }
Jesper Juhl573dbd92005-09-01 17:44:29 -07002402 crypto_free_tfm(ai->tfm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 del_airo_dev( dev );
2404 free_netdev( dev );
2405}
2406
2407EXPORT_SYMBOL(stop_airo_card);
2408
2409static int add_airo_dev( struct net_device *dev );
2410
Jouni Malinenff1d2762005-05-12 22:54:16 -04002411static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412{
2413 memcpy(haddr, skb->mac.raw + 10, ETH_ALEN);
2414 return ETH_ALEN;
2415}
2416
2417static void mpi_unmap_card(struct pci_dev *pci)
2418{
2419 unsigned long mem_start = pci_resource_start(pci, 1);
2420 unsigned long mem_len = pci_resource_len(pci, 1);
2421 unsigned long aux_start = pci_resource_start(pci, 2);
2422 unsigned long aux_len = AUXMEMSIZE;
2423
2424 release_mem_region(aux_start, aux_len);
2425 release_mem_region(mem_start, mem_len);
2426}
2427
2428/*************************************************************
2429 * This routine assumes that descriptors have been setup .
2430 * Run at insmod time or after reset when the decriptors
2431 * have been initialized . Returns 0 if all is well nz
2432 * otherwise . Does not allocate memory but sets up card
2433 * using previously allocated descriptors.
2434 */
2435static int mpi_init_descriptors (struct airo_info *ai)
2436{
2437 Cmd cmd;
2438 Resp rsp;
2439 int i;
2440 int rc = SUCCESS;
2441
2442 /* Alloc card RX descriptors */
2443 netif_stop_queue(ai->dev);
2444
2445 memset(&rsp,0,sizeof(rsp));
2446 memset(&cmd,0,sizeof(cmd));
2447
2448 cmd.cmd = CMD_ALLOCATEAUX;
2449 cmd.parm0 = FID_RX;
2450 cmd.parm1 = (ai->rxfids[0].card_ram_off - ai->pciaux);
2451 cmd.parm2 = MPI_MAX_FIDS;
2452 rc=issuecommand(ai, &cmd, &rsp);
2453 if (rc != SUCCESS) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002454 airo_print_err(ai->dev->name, "Couldn't allocate RX FID");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 return rc;
2456 }
2457
2458 for (i=0; i<MPI_MAX_FIDS; i++) {
2459 memcpy_toio(ai->rxfids[i].card_ram_off,
2460 &ai->rxfids[i].rx_desc, sizeof(RxFid));
2461 }
2462
2463 /* Alloc card TX descriptors */
2464
2465 memset(&rsp,0,sizeof(rsp));
2466 memset(&cmd,0,sizeof(cmd));
2467
2468 cmd.cmd = CMD_ALLOCATEAUX;
2469 cmd.parm0 = FID_TX;
2470 cmd.parm1 = (ai->txfids[0].card_ram_off - ai->pciaux);
2471 cmd.parm2 = MPI_MAX_FIDS;
2472
2473 for (i=0; i<MPI_MAX_FIDS; i++) {
2474 ai->txfids[i].tx_desc.valid = 1;
2475 memcpy_toio(ai->txfids[i].card_ram_off,
2476 &ai->txfids[i].tx_desc, sizeof(TxFid));
2477 }
2478 ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
2479
2480 rc=issuecommand(ai, &cmd, &rsp);
2481 if (rc != SUCCESS) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002482 airo_print_err(ai->dev->name, "Couldn't allocate TX FID");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 return rc;
2484 }
2485
2486 /* Alloc card Rid descriptor */
2487 memset(&rsp,0,sizeof(rsp));
2488 memset(&cmd,0,sizeof(cmd));
2489
2490 cmd.cmd = CMD_ALLOCATEAUX;
2491 cmd.parm0 = RID_RW;
2492 cmd.parm1 = (ai->config_desc.card_ram_off - ai->pciaux);
2493 cmd.parm2 = 1; /* Magic number... */
2494 rc=issuecommand(ai, &cmd, &rsp);
2495 if (rc != SUCCESS) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002496 airo_print_err(ai->dev->name, "Couldn't allocate RID");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 return rc;
2498 }
2499
2500 memcpy_toio(ai->config_desc.card_ram_off,
2501 &ai->config_desc.rid_desc, sizeof(Rid));
2502
2503 return rc;
2504}
2505
2506/*
2507 * We are setting up three things here:
2508 * 1) Map AUX memory for descriptors: Rid, TxFid, or RxFid.
2509 * 2) Map PCI memory for issueing commands.
2510 * 3) Allocate memory (shared) to send and receive ethernet frames.
2511 */
2512static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
2513 const char *name)
2514{
2515 unsigned long mem_start, mem_len, aux_start, aux_len;
2516 int rc = -1;
2517 int i;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002518 dma_addr_t busaddroff;
2519 unsigned char *vpackoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 unsigned char __iomem *pciaddroff;
2521
2522 mem_start = pci_resource_start(pci, 1);
2523 mem_len = pci_resource_len(pci, 1);
2524 aux_start = pci_resource_start(pci, 2);
2525 aux_len = AUXMEMSIZE;
2526
2527 if (!request_mem_region(mem_start, mem_len, name)) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002528 airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 (int)mem_start, (int)mem_len, name);
2530 goto out;
2531 }
2532 if (!request_mem_region(aux_start, aux_len, name)) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002533 airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 (int)aux_start, (int)aux_len, name);
2535 goto free_region1;
2536 }
2537
2538 ai->pcimem = ioremap(mem_start, mem_len);
2539 if (!ai->pcimem) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002540 airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 (int)mem_start, (int)mem_len, name);
2542 goto free_region2;
2543 }
2544 ai->pciaux = ioremap(aux_start, aux_len);
2545 if (!ai->pciaux) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002546 airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 (int)aux_start, (int)aux_len, name);
2548 goto free_memmap;
2549 }
2550
2551 /* Reserve PKTSIZE for each fid and 2K for the Rids */
2552 ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma);
2553 if (!ai->shared) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002554 airo_print_err(ai->dev->name, "Couldn't alloc_consistent %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 PCI_SHARED_LEN);
2556 goto free_auxmap;
2557 }
2558
2559 /*
2560 * Setup descriptor RX, TX, CONFIG
2561 */
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002562 busaddroff = ai->shared_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 pciaddroff = ai->pciaux + AUX_OFFSET;
2564 vpackoff = ai->shared;
2565
2566 /* RX descriptor setup */
2567 for(i = 0; i < MPI_MAX_FIDS; i++) {
2568 ai->rxfids[i].pending = 0;
2569 ai->rxfids[i].card_ram_off = pciaddroff;
2570 ai->rxfids[i].virtual_host_addr = vpackoff;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002571 ai->rxfids[i].rx_desc.host_addr = busaddroff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 ai->rxfids[i].rx_desc.valid = 1;
2573 ai->rxfids[i].rx_desc.len = PKTSIZE;
2574 ai->rxfids[i].rx_desc.rdy = 0;
2575
2576 pciaddroff += sizeof(RxFid);
2577 busaddroff += PKTSIZE;
2578 vpackoff += PKTSIZE;
2579 }
2580
2581 /* TX descriptor setup */
2582 for(i = 0; i < MPI_MAX_FIDS; i++) {
2583 ai->txfids[i].card_ram_off = pciaddroff;
2584 ai->txfids[i].virtual_host_addr = vpackoff;
2585 ai->txfids[i].tx_desc.valid = 1;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002586 ai->txfids[i].tx_desc.host_addr = busaddroff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 memcpy(ai->txfids[i].virtual_host_addr,
2588 &wifictlhdr8023, sizeof(wifictlhdr8023));
2589
2590 pciaddroff += sizeof(TxFid);
2591 busaddroff += PKTSIZE;
2592 vpackoff += PKTSIZE;
2593 }
2594 ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
2595
2596 /* Rid descriptor setup */
2597 ai->config_desc.card_ram_off = pciaddroff;
2598 ai->config_desc.virtual_host_addr = vpackoff;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002599 ai->config_desc.rid_desc.host_addr = busaddroff;
2600 ai->ridbus = busaddroff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 ai->config_desc.rid_desc.rid = 0;
2602 ai->config_desc.rid_desc.len = RIDSIZE;
2603 ai->config_desc.rid_desc.valid = 1;
2604 pciaddroff += sizeof(Rid);
2605 busaddroff += RIDSIZE;
2606 vpackoff += RIDSIZE;
2607
2608 /* Tell card about descriptors */
2609 if (mpi_init_descriptors (ai) != SUCCESS)
2610 goto free_shared;
2611
2612 return 0;
2613 free_shared:
2614 pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
2615 free_auxmap:
2616 iounmap(ai->pciaux);
2617 free_memmap:
2618 iounmap(ai->pcimem);
2619 free_region2:
2620 release_mem_region(aux_start, aux_len);
2621 free_region1:
2622 release_mem_region(mem_start, mem_len);
2623 out:
2624 return rc;
2625}
2626
2627static void wifi_setup(struct net_device *dev)
2628{
2629 dev->hard_header = NULL;
2630 dev->rebuild_header = NULL;
2631 dev->hard_header_cache = NULL;
2632 dev->header_cache_update= NULL;
2633
2634 dev->hard_header_parse = wll_header_parse;
2635 dev->hard_start_xmit = &airo_start_xmit11;
2636 dev->get_stats = &airo_get_stats;
2637 dev->set_mac_address = &airo_set_mac_address;
2638 dev->do_ioctl = &airo_ioctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 dev->wireless_handlers = &airo_handler_def;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 dev->change_mtu = &airo_change_mtu;
2641 dev->open = &airo_open;
2642 dev->stop = &airo_close;
2643
2644 dev->type = ARPHRD_IEEE80211;
2645 dev->hard_header_len = ETH_HLEN;
Dan Williams15db2762006-03-16 13:46:27 -05002646 dev->mtu = AIRO_DEF_MTU;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 dev->addr_len = ETH_ALEN;
2648 dev->tx_queue_len = 100;
2649
2650 memset(dev->broadcast,0xFF, ETH_ALEN);
2651
2652 dev->flags = IFF_BROADCAST|IFF_MULTICAST;
2653}
2654
2655static struct net_device *init_wifidev(struct airo_info *ai,
2656 struct net_device *ethdev)
2657{
2658 int err;
2659 struct net_device *dev = alloc_netdev(0, "wifi%d", wifi_setup);
2660 if (!dev)
2661 return NULL;
2662 dev->priv = ethdev->priv;
2663 dev->irq = ethdev->irq;
2664 dev->base_addr = ethdev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 dev->wireless_data = ethdev->wireless_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len);
2667 err = register_netdev(dev);
2668 if (err<0) {
2669 free_netdev(dev);
2670 return NULL;
2671 }
2672 return dev;
2673}
2674
Jouni Malinenff1d2762005-05-12 22:54:16 -04002675static int reset_card( struct net_device *dev , int lock) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 struct airo_info *ai = dev->priv;
2677
2678 if (lock && down_interruptible(&ai->sem))
2679 return -1;
2680 waitbusy (ai);
2681 OUT4500(ai,COMMAND,CMD_SOFTRESET);
2682 msleep(200);
2683 waitbusy (ai);
2684 msleep(200);
2685 if (lock)
2686 up(&ai->sem);
2687 return 0;
2688}
2689
Jouni Malinenff1d2762005-05-12 22:54:16 -04002690static struct net_device *_init_airo_card( unsigned short irq, int port,
2691 int is_pcmcia, struct pci_dev *pci,
2692 struct device *dmdev )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693{
2694 struct net_device *dev;
2695 struct airo_info *ai;
2696 int i, rc;
2697
2698 /* Create the network device object. */
2699 dev = alloc_etherdev(sizeof(*ai));
2700 if (!dev) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002701 airo_print_err("", "Couldn't alloc_etherdev");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 return NULL;
2703 }
2704 if (dev_alloc_name(dev, dev->name) < 0) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002705 airo_print_err("", "Couldn't get name!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 goto err_out_free;
2707 }
2708
2709 ai = dev->priv;
2710 ai->wifidev = NULL;
2711 ai->flags = 0;
Dan Williams934d8bf2006-03-16 13:46:23 -05002712 ai->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002714 airo_print_dbg(dev->name, "Found an MPI350 card");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 set_bit(FLAG_MPI, &ai->flags);
2716 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 spin_lock_init(&ai->aux_lock);
2718 sema_init(&ai->sem, 1);
2719 ai->config.len = 0;
2720 ai->pci = pci;
2721 init_waitqueue_head (&ai->thr_wait);
2722 init_completion (&ai->thr_exited);
2723 ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES);
2724 if (ai->thr_pid < 0)
2725 goto err_out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 ai->tfm = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 rc = add_airo_dev( dev );
2728 if (rc)
2729 goto err_out_thr;
2730
2731 /* The Airo-specific entries in the device structure. */
2732 if (test_bit(FLAG_MPI,&ai->flags)) {
2733 skb_queue_head_init (&ai->txq);
2734 dev->hard_start_xmit = &mpi_start_xmit;
2735 } else
2736 dev->hard_start_xmit = &airo_start_xmit;
2737 dev->get_stats = &airo_get_stats;
2738 dev->set_multicast_list = &airo_set_multicast_list;
2739 dev->set_mac_address = &airo_set_mac_address;
2740 dev->do_ioctl = &airo_ioctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 dev->wireless_handlers = &airo_handler_def;
2742 ai->wireless_data.spy_data = &ai->spy_data;
2743 dev->wireless_data = &ai->wireless_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 dev->change_mtu = &airo_change_mtu;
2745 dev->open = &airo_open;
2746 dev->stop = &airo_close;
2747 dev->irq = irq;
2748 dev->base_addr = port;
2749
2750 SET_NETDEV_DEV(dev, dmdev);
2751
2752
Matthieu CASTET1d97f382005-12-01 02:35:26 -05002753 reset_card (dev, 1);
2754 msleep(400);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755
2756 rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev );
2757 if (rc) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002758 airo_print_err(dev->name, "register interrupt %d failed, rc %d",
2759 irq, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 goto err_out_unlink;
2761 }
2762 if (!is_pcmcia) {
2763 if (!request_region( dev->base_addr, 64, dev->name )) {
2764 rc = -EBUSY;
Dan Williams934d8bf2006-03-16 13:46:23 -05002765 airo_print_err(dev->name, "Couldn't request region");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 goto err_out_irq;
2767 }
2768 }
2769
2770 if (test_bit(FLAG_MPI,&ai->flags)) {
2771 if (mpi_map_card(ai, pci, dev->name)) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002772 airo_print_err(dev->name, "Could not map memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 goto err_out_res;
2774 }
2775 }
2776
2777 if (probe) {
2778 if ( setup_card( ai, dev->dev_addr, 1 ) != SUCCESS ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002779 airo_print_err(dev->name, "MAC could not be enabled" );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 rc = -EIO;
2781 goto err_out_map;
2782 }
2783 } else if (!test_bit(FLAG_MPI,&ai->flags)) {
2784 ai->bap_read = fast_bap_read;
2785 set_bit(FLAG_FLASHING, &ai->flags);
2786 }
2787
2788 rc = register_netdev(dev);
2789 if (rc) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002790 airo_print_err(dev->name, "Couldn't register_netdev");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 goto err_out_map;
2792 }
2793 ai->wifidev = init_wifidev(ai, dev);
2794
2795 set_bit(FLAG_REGISTERED,&ai->flags);
Dan Williams934d8bf2006-03-16 13:46:23 -05002796 airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
2798 dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
2799
2800 /* Allocate the transmit buffers */
2801 if (probe && !test_bit(FLAG_MPI,&ai->flags))
2802 for( i = 0; i < MAX_FIDS; i++ )
Dan Williams15db2762006-03-16 13:46:27 -05002803 ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804
2805 setup_proc_entry( dev, dev->priv ); /* XXX check for failure */
2806 netif_start_queue(dev);
2807 SET_MODULE_OWNER(dev);
2808 return dev;
2809
2810err_out_map:
2811 if (test_bit(FLAG_MPI,&ai->flags) && pci) {
2812 pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
2813 iounmap(ai->pciaux);
2814 iounmap(ai->pcimem);
2815 mpi_unmap_card(ai->pci);
2816 }
2817err_out_res:
2818 if (!is_pcmcia)
2819 release_region( dev->base_addr, 64 );
2820err_out_irq:
2821 free_irq(dev->irq, dev);
2822err_out_unlink:
2823 del_airo_dev(dev);
2824err_out_thr:
2825 set_bit(JOB_DIE, &ai->flags);
2826 kill_proc(ai->thr_pid, SIGTERM, 1);
2827 wait_for_completion(&ai->thr_exited);
2828err_out_free:
2829 free_netdev(dev);
2830 return NULL;
2831}
2832
2833struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia,
2834 struct device *dmdev)
2835{
2836 return _init_airo_card ( irq, port, is_pcmcia, NULL, dmdev);
2837}
2838
2839EXPORT_SYMBOL(init_airo_card);
2840
2841static int waitbusy (struct airo_info *ai) {
2842 int delay = 0;
2843 while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) & (delay < 10000)) {
2844 udelay (10);
2845 if ((++delay % 20) == 0)
2846 OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
2847 }
2848 return delay < 10000;
2849}
2850
2851int reset_airo_card( struct net_device *dev )
2852{
2853 int i;
2854 struct airo_info *ai = dev->priv;
2855
2856 if (reset_card (dev, 1))
2857 return -1;
2858
2859 if ( setup_card(ai, dev->dev_addr, 1 ) != SUCCESS ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05002860 airo_print_err(dev->name, "MAC could not be enabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 return -1;
2862 }
Dan Williams934d8bf2006-03-16 13:46:23 -05002863 airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
2865 dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
2866 /* Allocate the transmit buffers if needed */
2867 if (!test_bit(FLAG_MPI,&ai->flags))
2868 for( i = 0; i < MAX_FIDS; i++ )
Dan Williams15db2762006-03-16 13:46:27 -05002869 ai->fids[i] = transmit_allocate (ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870
2871 enable_interrupts( ai );
2872 netif_wake_queue(dev);
2873 return 0;
2874}
2875
2876EXPORT_SYMBOL(reset_airo_card);
2877
2878static void airo_send_event(struct net_device *dev) {
2879 struct airo_info *ai = dev->priv;
2880 union iwreq_data wrqu;
2881 StatusRid status_rid;
2882
2883 clear_bit(JOB_EVENT, &ai->flags);
2884 PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
2885 up(&ai->sem);
2886 wrqu.data.length = 0;
2887 wrqu.data.flags = 0;
2888 memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN);
2889 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
2890
2891 /* Send event to user space */
2892 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
2893}
2894
2895static int airo_thread(void *data) {
2896 struct net_device *dev = data;
2897 struct airo_info *ai = dev->priv;
2898 int locked;
2899
2900 daemonize("%s", dev->name);
2901 allow_signal(SIGTERM);
2902
2903 while(1) {
2904 if (signal_pending(current))
2905 flush_signals(current);
2906
2907 /* make swsusp happy with our thread */
Christoph Lameter3e1d1d22005-06-24 23:13:50 -07002908 try_to_freeze();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909
2910 if (test_bit(JOB_DIE, &ai->flags))
2911 break;
2912
2913 if (ai->flags & JOB_MASK) {
2914 locked = down_interruptible(&ai->sem);
2915 } else {
2916 wait_queue_t wait;
2917
2918 init_waitqueue_entry(&wait, current);
2919 add_wait_queue(&ai->thr_wait, &wait);
2920 for (;;) {
2921 set_current_state(TASK_INTERRUPTIBLE);
2922 if (ai->flags & JOB_MASK)
2923 break;
2924 if (ai->expires) {
2925 if (time_after_eq(jiffies,ai->expires)){
2926 set_bit(JOB_AUTOWEP,&ai->flags);
2927 break;
2928 }
2929 if (!signal_pending(current)) {
2930 schedule_timeout(ai->expires - jiffies);
2931 continue;
2932 }
2933 } else if (!signal_pending(current)) {
2934 schedule();
2935 continue;
2936 }
2937 break;
2938 }
2939 current->state = TASK_RUNNING;
2940 remove_wait_queue(&ai->thr_wait, &wait);
2941 locked = 1;
2942 }
2943
2944 if (locked)
2945 continue;
2946
2947 if (test_bit(JOB_DIE, &ai->flags)) {
2948 up(&ai->sem);
2949 break;
2950 }
2951
Pavel Machekca078ba2005-09-03 15:56:57 -07002952 if (ai->power.event || test_bit(FLAG_FLASHING, &ai->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 up(&ai->sem);
2954 continue;
2955 }
2956
2957 if (test_bit(JOB_XMIT, &ai->flags))
2958 airo_end_xmit(dev);
2959 else if (test_bit(JOB_XMIT11, &ai->flags))
2960 airo_end_xmit11(dev);
2961 else if (test_bit(JOB_STATS, &ai->flags))
2962 airo_read_stats(ai);
2963 else if (test_bit(JOB_WSTATS, &ai->flags))
2964 airo_read_wireless_stats(ai);
2965 else if (test_bit(JOB_PROMISC, &ai->flags))
2966 airo_set_promisc(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 else if (test_bit(JOB_MIC, &ai->flags))
2968 micinit(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 else if (test_bit(JOB_EVENT, &ai->flags))
2970 airo_send_event(dev);
2971 else if (test_bit(JOB_AUTOWEP, &ai->flags))
2972 timer_func(dev);
2973 }
2974 complete_and_exit (&ai->thr_exited, 0);
2975}
2976
2977static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
2978 struct net_device *dev = (struct net_device *)dev_id;
2979 u16 status;
2980 u16 fid;
2981 struct airo_info *apriv = dev->priv;
2982 u16 savedInterrupts = 0;
2983 int handled = 0;
2984
2985 if (!netif_device_present(dev))
2986 return IRQ_NONE;
2987
2988 for (;;) {
2989 status = IN4500( apriv, EVSTAT );
2990 if ( !(status & STATUS_INTS) || status == 0xffff ) break;
2991
2992 handled = 1;
2993
2994 if ( status & EV_AWAKE ) {
2995 OUT4500( apriv, EVACK, EV_AWAKE );
2996 OUT4500( apriv, EVACK, EV_AWAKE );
2997 }
2998
2999 if (!savedInterrupts) {
3000 savedInterrupts = IN4500( apriv, EVINTEN );
3001 OUT4500( apriv, EVINTEN, 0 );
3002 }
3003
3004 if ( status & EV_MIC ) {
3005 OUT4500( apriv, EVACK, EV_MIC );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) {
3007 set_bit(JOB_MIC, &apriv->flags);
3008 wake_up_interruptible(&apriv->thr_wait);
3009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 }
3011 if ( status & EV_LINK ) {
3012 union iwreq_data wrqu;
3013 /* The link status has changed, if you want to put a
3014 monitor hook in, do it here. (Remember that
3015 interrupts are still disabled!)
3016 */
3017 u16 newStatus = IN4500(apriv, LINKSTAT);
3018 OUT4500( apriv, EVACK, EV_LINK);
3019 /* Here is what newStatus means: */
3020#define NOBEACON 0x8000 /* Loss of sync - missed beacons */
3021#define MAXRETRIES 0x8001 /* Loss of sync - max retries */
3022#define MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/
3023#define FORCELOSS 0x8003 /* Loss of sync - host request */
3024#define TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */
3025#define DEAUTH 0x8100 /* Deauthentication (low byte is reason code) */
3026#define DISASS 0x8200 /* Disassociation (low byte is reason code) */
3027#define ASSFAIL 0x8400 /* Association failure (low byte is reason
3028 code) */
3029#define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason
3030 code) */
3031#define ASSOCIATED 0x0400 /* Assocatied */
3032#define RC_RESERVED 0 /* Reserved return code */
3033#define RC_NOREASON 1 /* Unspecified reason */
3034#define RC_AUTHINV 2 /* Previous authentication invalid */
3035#define RC_DEAUTH 3 /* Deauthenticated because sending station is
3036 leaving */
3037#define RC_NOACT 4 /* Disassociated due to inactivity */
3038#define RC_MAXLOAD 5 /* Disassociated because AP is unable to handle
3039 all currently associated stations */
3040#define RC_BADCLASS2 6 /* Class 2 frame received from
3041 non-Authenticated station */
3042#define RC_BADCLASS3 7 /* Class 3 frame received from
3043 non-Associated station */
3044#define RC_STATLEAVE 8 /* Disassociated because sending station is
3045 leaving BSS */
3046#define RC_NOAUTH 9 /* Station requesting (Re)Association is not
3047 Authenticated with the responding station */
3048 if (newStatus != ASSOCIATED) {
3049 if (auto_wep && !apriv->expires) {
3050 apriv->expires = RUN_AT(3*HZ);
3051 wake_up_interruptible(&apriv->thr_wait);
3052 }
3053 } else {
3054 struct task_struct *task = apriv->task;
3055 if (auto_wep)
3056 apriv->expires = 0;
3057 if (task)
3058 wake_up_process (task);
3059 set_bit(FLAG_UPDATE_UNI, &apriv->flags);
3060 set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
3061 }
3062 /* Question : is ASSOCIATED the only status
3063 * that is valid ? We want to catch handover
3064 * and reassociations as valid status
3065 * Jean II */
3066 if(newStatus == ASSOCIATED) {
3067 if (apriv->scan_timestamp) {
3068 /* Send an empty event to user space.
3069 * We don't send the received data on
3070 * the event because it would require
3071 * us to do complex transcoding, and
3072 * we want to minimise the work done in
3073 * the irq handler. Use a request to
3074 * extract the data - Jean II */
3075 wrqu.data.length = 0;
3076 wrqu.data.flags = 0;
3077 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
3078 apriv->scan_timestamp = 0;
3079 }
3080 if (down_trylock(&apriv->sem) != 0) {
3081 set_bit(JOB_EVENT, &apriv->flags);
3082 wake_up_interruptible(&apriv->thr_wait);
3083 } else
3084 airo_send_event(dev);
3085 } else {
3086 memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN);
3087 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
3088
3089 /* Send event to user space */
3090 wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL);
3091 }
3092 }
3093
3094 /* Check to see if there is something to receive */
3095 if ( status & EV_RX ) {
3096 struct sk_buff *skb = NULL;
3097 u16 fc, len, hdrlen = 0;
3098#pragma pack(1)
3099 struct {
3100 u16 status, len;
3101 u8 rssi[2];
3102 u8 rate;
3103 u8 freq;
3104 u16 tmp[4];
3105 } hdr;
3106#pragma pack()
3107 u16 gap;
3108 u16 tmpbuf[4];
3109 u16 *buffer;
3110
3111 if (test_bit(FLAG_MPI,&apriv->flags)) {
3112 if (test_bit(FLAG_802_11, &apriv->flags))
3113 mpi_receive_802_11(apriv);
3114 else
3115 mpi_receive_802_3(apriv);
3116 OUT4500(apriv, EVACK, EV_RX);
3117 goto exitrx;
3118 }
3119
3120 fid = IN4500( apriv, RXFID );
3121
3122 /* Get the packet length */
3123 if (test_bit(FLAG_802_11, &apriv->flags)) {
3124 bap_setup (apriv, fid, 4, BAP0);
3125 bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0);
3126 /* Bad CRC. Ignore packet */
3127 if (le16_to_cpu(hdr.status) & 2)
3128 hdr.len = 0;
3129 if (apriv->wifidev == NULL)
3130 hdr.len = 0;
3131 } else {
3132 bap_setup (apriv, fid, 0x36, BAP0);
3133 bap_read (apriv, (u16*)&hdr.len, 2, BAP0);
3134 }
3135 len = le16_to_cpu(hdr.len);
3136
Dan Williams15db2762006-03-16 13:46:27 -05003137 if (len > AIRO_DEF_MTU) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003138 airo_print_err(apriv->dev->name, "Bad size %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 goto badrx;
3140 }
3141 if (len == 0)
3142 goto badrx;
3143
3144 if (test_bit(FLAG_802_11, &apriv->flags)) {
3145 bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0);
3146 fc = le16_to_cpu(fc);
3147 switch (fc & 0xc) {
3148 case 4:
3149 if ((fc & 0xe0) == 0xc0)
3150 hdrlen = 10;
3151 else
3152 hdrlen = 16;
3153 break;
3154 case 8:
3155 if ((fc&0x300)==0x300){
3156 hdrlen = 30;
3157 break;
3158 }
3159 default:
3160 hdrlen = 24;
3161 }
3162 } else
3163 hdrlen = ETH_ALEN * 2;
3164
3165 skb = dev_alloc_skb( len + hdrlen + 2 + 2 );
3166 if ( !skb ) {
3167 apriv->stats.rx_dropped++;
3168 goto badrx;
3169 }
3170 skb_reserve(skb, 2); /* This way the IP header is aligned */
3171 buffer = (u16*)skb_put (skb, len + hdrlen);
3172 if (test_bit(FLAG_802_11, &apriv->flags)) {
3173 buffer[0] = fc;
3174 bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
3175 if (hdrlen == 24)
3176 bap_read (apriv, tmpbuf, 6, BAP0);
3177
3178 bap_read (apriv, &gap, sizeof(gap), BAP0);
3179 gap = le16_to_cpu(gap);
3180 if (gap) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003181 if (gap <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 bap_read (apriv, tmpbuf, gap, BAP0);
Dan Williams934d8bf2006-03-16 13:46:23 -05003183 } else {
3184 airo_print_err(apriv->dev->name, "gaplen too "
3185 "big. Problems will follow...");
3186 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 }
3188 bap_read (apriv, buffer + hdrlen/2, len, BAP0);
3189 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 MICBuffer micbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 if (apriv->micstats.enabled) {
3193 bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0);
3194 if (ntohs(micbuf.typelen) > 0x05DC)
3195 bap_setup (apriv, fid, 0x44, BAP0);
3196 else {
3197 if (len <= sizeof(micbuf))
3198 goto badmic;
3199
3200 len -= sizeof(micbuf);
3201 skb_trim (skb, len + hdrlen);
3202 }
3203 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 bap_read(apriv,buffer+ETH_ALEN,len,BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
3206badmic:
3207 dev_kfree_skb_irq (skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208badrx:
3209 OUT4500( apriv, EVACK, EV_RX);
3210 goto exitrx;
3211 }
3212 }
3213#ifdef WIRELESS_SPY
3214 if (apriv->spy_data.spy_number > 0) {
3215 char *sa;
3216 struct iw_quality wstats;
3217 /* Prepare spy data : addr + qual */
3218 if (!test_bit(FLAG_802_11, &apriv->flags)) {
3219 sa = (char*)buffer + 6;
3220 bap_setup (apriv, fid, 8, BAP0);
3221 bap_read (apriv, (u16*)hdr.rssi, 2, BAP0);
3222 } else
3223 sa = (char*)buffer + 10;
3224 wstats.qual = hdr.rssi[0];
3225 if (apriv->rssi)
3226 wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
3227 else
3228 wstats.level = (hdr.rssi[1] + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04003229 wstats.noise = apriv->wstats.qual.noise;
3230 wstats.updated = IW_QUAL_LEVEL_UPDATED
3231 | IW_QUAL_QUAL_UPDATED
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07003232 | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 /* Update spy records */
3234 wireless_spy_update(dev, sa, &wstats);
3235 }
3236#endif /* WIRELESS_SPY */
3237 OUT4500( apriv, EVACK, EV_RX);
3238
3239 if (test_bit(FLAG_802_11, &apriv->flags)) {
3240 skb->mac.raw = skb->data;
3241 skb->pkt_type = PACKET_OTHERHOST;
3242 skb->dev = apriv->wifidev;
3243 skb->protocol = htons(ETH_P_802_2);
3244 } else {
3245 skb->dev = dev;
3246 skb->protocol = eth_type_trans(skb,dev);
3247 }
3248 skb->dev->last_rx = jiffies;
3249 skb->ip_summed = CHECKSUM_NONE;
3250
3251 netif_rx( skb );
3252 }
3253exitrx:
3254
3255 /* Check to see if a packet has been transmitted */
3256 if ( status & ( EV_TX|EV_TXCPY|EV_TXEXC ) ) {
3257 int i;
3258 int len = 0;
3259 int index = -1;
3260
3261 if (test_bit(FLAG_MPI,&apriv->flags)) {
3262 unsigned long flags;
3263
3264 if (status & EV_TXEXC)
3265 get_tx_error(apriv, -1);
3266 spin_lock_irqsave(&apriv->aux_lock, flags);
David S. Millerb03efcf2005-07-08 14:57:23 -07003267 if (!skb_queue_empty(&apriv->txq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 spin_unlock_irqrestore(&apriv->aux_lock,flags);
3269 mpi_send_packet (dev);
3270 } else {
3271 clear_bit(FLAG_PENDING_XMIT, &apriv->flags);
3272 spin_unlock_irqrestore(&apriv->aux_lock,flags);
3273 netif_wake_queue (dev);
3274 }
3275 OUT4500( apriv, EVACK,
3276 status & (EV_TX|EV_TXCPY|EV_TXEXC));
3277 goto exittx;
3278 }
3279
3280 fid = IN4500(apriv, TXCOMPLFID);
3281
3282 for( i = 0; i < MAX_FIDS; i++ ) {
3283 if ( ( apriv->fids[i] & 0xffff ) == fid ) {
3284 len = apriv->fids[i] >> 16;
3285 index = i;
3286 }
3287 }
3288 if (index != -1) {
3289 if (status & EV_TXEXC)
3290 get_tx_error(apriv, index);
3291 OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC));
3292 /* Set up to be used again */
3293 apriv->fids[index] &= 0xffff;
3294 if (index < MAX_FIDS / 2) {
3295 if (!test_bit(FLAG_PENDING_XMIT, &apriv->flags))
3296 netif_wake_queue(dev);
3297 } else {
3298 if (!test_bit(FLAG_PENDING_XMIT11, &apriv->flags))
3299 netif_wake_queue(apriv->wifidev);
3300 }
3301 } else {
3302 OUT4500( apriv, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC));
Dan Williams934d8bf2006-03-16 13:46:23 -05003303 airo_print_err(apriv->dev->name, "Unallocated FID was "
3304 "used to xmit" );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 }
3306 }
3307exittx:
3308 if ( status & ~STATUS_INTS & ~IGNORE_INTS )
Dan Williams934d8bf2006-03-16 13:46:23 -05003309 airo_print_warn(apriv->dev->name, "Got weird status %x",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 status & ~STATUS_INTS & ~IGNORE_INTS );
3311 }
3312
3313 if (savedInterrupts)
3314 OUT4500( apriv, EVINTEN, savedInterrupts );
3315
3316 /* done.. */
3317 return IRQ_RETVAL(handled);
3318}
3319
3320/*
3321 * Routines to talk to the card
3322 */
3323
3324/*
3325 * This was originally written for the 4500, hence the name
3326 * NOTE: If use with 8bit mode and SMP bad things will happen!
3327 * Why would some one do 8 bit IO in an SMP machine?!?
3328 */
3329static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) {
3330 if (test_bit(FLAG_MPI,&ai->flags))
3331 reg <<= 1;
3332 if ( !do8bitIO )
3333 outw( val, ai->dev->base_addr + reg );
3334 else {
3335 outb( val & 0xff, ai->dev->base_addr + reg );
3336 outb( val >> 8, ai->dev->base_addr + reg + 1 );
3337 }
3338}
3339
3340static u16 IN4500( struct airo_info *ai, u16 reg ) {
3341 unsigned short rc;
3342
3343 if (test_bit(FLAG_MPI,&ai->flags))
3344 reg <<= 1;
3345 if ( !do8bitIO )
3346 rc = inw( ai->dev->base_addr + reg );
3347 else {
3348 rc = inb( ai->dev->base_addr + reg );
3349 rc += ((int)inb( ai->dev->base_addr + reg + 1 )) << 8;
3350 }
3351 return rc;
3352}
3353
3354static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) {
3355 int rc;
3356 Cmd cmd;
3357
3358 /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions
3359 * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down"
3360 * Note : we could try to use !netif_running(dev) in enable_MAC()
3361 * instead of this flag, but I don't trust it *within* the
3362 * open/close functions, and testing both flags together is
3363 * "cheaper" - Jean II */
3364 if (ai->flags & FLAG_RADIO_MASK) return SUCCESS;
3365
3366 if (lock && down_interruptible(&ai->sem))
3367 return -ERESTARTSYS;
3368
3369 if (!test_bit(FLAG_ENABLED, &ai->flags)) {
3370 memset(&cmd, 0, sizeof(cmd));
3371 cmd.cmd = MAC_ENABLE;
3372 rc = issuecommand(ai, &cmd, rsp);
3373 if (rc == SUCCESS)
3374 set_bit(FLAG_ENABLED, &ai->flags);
3375 } else
3376 rc = SUCCESS;
3377
3378 if (lock)
3379 up(&ai->sem);
3380
3381 if (rc)
Dan Williams934d8bf2006-03-16 13:46:23 -05003382 airo_print_err(ai->dev->name, "%s: Cannot enable MAC, err=%d",
3383 __FUNCTION__, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 return rc;
3385}
3386
3387static void disable_MAC( struct airo_info *ai, int lock ) {
3388 Cmd cmd;
3389 Resp rsp;
3390
3391 if (lock && down_interruptible(&ai->sem))
3392 return;
3393
3394 if (test_bit(FLAG_ENABLED, &ai->flags)) {
3395 memset(&cmd, 0, sizeof(cmd));
3396 cmd.cmd = MAC_DISABLE; // disable in case already enabled
3397 issuecommand(ai, &cmd, &rsp);
3398 clear_bit(FLAG_ENABLED, &ai->flags);
3399 }
3400 if (lock)
3401 up(&ai->sem);
3402}
3403
3404static void enable_interrupts( struct airo_info *ai ) {
3405 /* Enable the interrupts */
3406 OUT4500( ai, EVINTEN, STATUS_INTS );
3407}
3408
3409static void disable_interrupts( struct airo_info *ai ) {
3410 OUT4500( ai, EVINTEN, 0 );
3411}
3412
3413static void mpi_receive_802_3(struct airo_info *ai)
3414{
3415 RxFid rxd;
3416 int len = 0;
3417 struct sk_buff *skb;
3418 char *buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 int off = 0;
3420 MICBuffer micbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421
3422 memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
3423 /* Make sure we got something */
3424 if (rxd.rdy && rxd.valid == 0) {
3425 len = rxd.len + 12;
3426 if (len < 12 || len > 2048)
3427 goto badrx;
3428
3429 skb = dev_alloc_skb(len);
3430 if (!skb) {
3431 ai->stats.rx_dropped++;
3432 goto badrx;
3433 }
3434 buffer = skb_put(skb,len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2);
3436 if (ai->micstats.enabled) {
3437 memcpy(&micbuf,
3438 ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2,
3439 sizeof(micbuf));
3440 if (ntohs(micbuf.typelen) <= 0x05DC) {
3441 if (len <= sizeof(micbuf) + ETH_ALEN * 2)
3442 goto badmic;
3443
3444 off = sizeof(micbuf);
3445 skb_trim (skb, len - off);
3446 }
3447 }
3448 memcpy(buffer + ETH_ALEN * 2,
3449 ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off,
3450 len - ETH_ALEN * 2 - off);
3451 if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) {
3452badmic:
3453 dev_kfree_skb_irq (skb);
3454 goto badrx;
3455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456#ifdef WIRELESS_SPY
3457 if (ai->spy_data.spy_number > 0) {
3458 char *sa;
3459 struct iw_quality wstats;
3460 /* Prepare spy data : addr + qual */
3461 sa = buffer + ETH_ALEN;
3462 wstats.qual = 0; /* XXX Where do I get that info from ??? */
3463 wstats.level = 0;
3464 wstats.updated = 0;
3465 /* Update spy records */
3466 wireless_spy_update(ai->dev, sa, &wstats);
3467 }
3468#endif /* WIRELESS_SPY */
3469
3470 skb->dev = ai->dev;
3471 skb->ip_summed = CHECKSUM_NONE;
3472 skb->protocol = eth_type_trans(skb, ai->dev);
3473 skb->dev->last_rx = jiffies;
3474 netif_rx(skb);
3475 }
3476badrx:
3477 if (rxd.valid == 0) {
3478 rxd.valid = 1;
3479 rxd.rdy = 0;
3480 rxd.len = PKTSIZE;
3481 memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd));
3482 }
3483}
3484
3485void mpi_receive_802_11 (struct airo_info *ai)
3486{
3487 RxFid rxd;
3488 struct sk_buff *skb = NULL;
3489 u16 fc, len, hdrlen = 0;
3490#pragma pack(1)
3491 struct {
3492 u16 status, len;
3493 u8 rssi[2];
3494 u8 rate;
3495 u8 freq;
3496 u16 tmp[4];
3497 } hdr;
3498#pragma pack()
3499 u16 gap;
3500 u16 *buffer;
3501 char *ptr = ai->rxfids[0].virtual_host_addr+4;
3502
3503 memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
3504 memcpy ((char *)&hdr, ptr, sizeof(hdr));
3505 ptr += sizeof(hdr);
3506 /* Bad CRC. Ignore packet */
3507 if (le16_to_cpu(hdr.status) & 2)
3508 hdr.len = 0;
3509 if (ai->wifidev == NULL)
3510 hdr.len = 0;
3511 len = le16_to_cpu(hdr.len);
Dan Williams15db2762006-03-16 13:46:27 -05003512 if (len > AIRO_DEF_MTU) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003513 airo_print_err(ai->dev->name, "Bad size %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 goto badrx;
3515 }
3516 if (len == 0)
3517 goto badrx;
3518
3519 memcpy ((char *)&fc, ptr, sizeof(fc));
3520 fc = le16_to_cpu(fc);
3521 switch (fc & 0xc) {
3522 case 4:
3523 if ((fc & 0xe0) == 0xc0)
3524 hdrlen = 10;
3525 else
3526 hdrlen = 16;
3527 break;
3528 case 8:
3529 if ((fc&0x300)==0x300){
3530 hdrlen = 30;
3531 break;
3532 }
3533 default:
3534 hdrlen = 24;
3535 }
3536
3537 skb = dev_alloc_skb( len + hdrlen + 2 );
3538 if ( !skb ) {
3539 ai->stats.rx_dropped++;
3540 goto badrx;
3541 }
3542 buffer = (u16*)skb_put (skb, len + hdrlen);
3543 memcpy ((char *)buffer, ptr, hdrlen);
3544 ptr += hdrlen;
3545 if (hdrlen == 24)
3546 ptr += 6;
3547 memcpy ((char *)&gap, ptr, sizeof(gap));
3548 ptr += sizeof(gap);
3549 gap = le16_to_cpu(gap);
3550 if (gap) {
3551 if (gap <= 8)
3552 ptr += gap;
3553 else
Dan Williams934d8bf2006-03-16 13:46:23 -05003554 airo_print_err(ai->dev->name,
3555 "gaplen too big. Problems will follow...");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 }
3557 memcpy ((char *)buffer + hdrlen, ptr, len);
3558 ptr += len;
3559#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
3560 if (ai->spy_data.spy_number > 0) {
3561 char *sa;
3562 struct iw_quality wstats;
3563 /* Prepare spy data : addr + qual */
3564 sa = (char*)buffer + 10;
3565 wstats.qual = hdr.rssi[0];
3566 if (ai->rssi)
3567 wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm;
3568 else
3569 wstats.level = (hdr.rssi[1] + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04003570 wstats.noise = ai->wstats.qual.noise;
3571 wstats.updated = IW_QUAL_QUAL_UPDATED
3572 | IW_QUAL_LEVEL_UPDATED
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07003573 | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 /* Update spy records */
3575 wireless_spy_update(ai->dev, sa, &wstats);
3576 }
3577#endif /* IW_WIRELESS_SPY */
3578 skb->mac.raw = skb->data;
3579 skb->pkt_type = PACKET_OTHERHOST;
3580 skb->dev = ai->wifidev;
3581 skb->protocol = htons(ETH_P_802_2);
3582 skb->dev->last_rx = jiffies;
3583 skb->ip_summed = CHECKSUM_NONE;
3584 netif_rx( skb );
3585badrx:
3586 if (rxd.valid == 0) {
3587 rxd.valid = 1;
3588 rxd.rdy = 0;
3589 rxd.len = PKTSIZE;
3590 memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd));
3591 }
3592}
3593
3594static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
3595{
3596 Cmd cmd;
3597 Resp rsp;
3598 int status;
3599 int i;
3600 SsidRid mySsid;
3601 u16 lastindex;
3602 WepKeyRid wkr;
3603 int rc;
3604
3605 memset( &mySsid, 0, sizeof( mySsid ) );
Jesper Juhlb4558ea2005-10-28 16:53:13 -04003606 kfree (ai->flash);
3607 ai->flash = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608
3609 /* The NOP is the first step in getting the card going */
3610 cmd.cmd = NOP;
3611 cmd.parm0 = cmd.parm1 = cmd.parm2 = 0;
3612 if (lock && down_interruptible(&ai->sem))
3613 return ERROR;
3614 if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
3615 if (lock)
3616 up(&ai->sem);
3617 return ERROR;
3618 }
3619 disable_MAC( ai, 0);
3620
3621 // Let's figure out if we need to use the AUX port
3622 if (!test_bit(FLAG_MPI,&ai->flags)) {
3623 cmd.cmd = CMD_ENABLEAUX;
3624 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
3625 if (lock)
3626 up(&ai->sem);
Dan Williams934d8bf2006-03-16 13:46:23 -05003627 airo_print_err(ai->dev->name, "Error checking for AUX port");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 return ERROR;
3629 }
3630 if (!aux_bap || rsp.status & 0xff00) {
3631 ai->bap_read = fast_bap_read;
Dan Williams934d8bf2006-03-16 13:46:23 -05003632 airo_print_dbg(ai->dev->name, "Doing fast bap_reads");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 } else {
3634 ai->bap_read = aux_bap_read;
Dan Williams934d8bf2006-03-16 13:46:23 -05003635 airo_print_dbg(ai->dev->name, "Doing AUX bap_reads");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 }
3637 }
3638 if (lock)
3639 up(&ai->sem);
3640 if (ai->config.len == 0) {
3641 tdsRssiRid rssi_rid;
3642 CapabilityRid cap_rid;
3643
Jesper Juhlb4558ea2005-10-28 16:53:13 -04003644 kfree(ai->APList);
3645 ai->APList = NULL;
3646 kfree(ai->SSID);
3647 ai->SSID = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 // general configuration (read/modify/write)
3649 status = readConfigRid(ai, lock);
3650 if ( status != SUCCESS ) return ERROR;
3651
3652 status = readCapabilityRid(ai, &cap_rid, lock);
3653 if ( status != SUCCESS ) return ERROR;
3654
3655 status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),lock);
3656 if ( status == SUCCESS ) {
3657 if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
Dan Williams41480af2005-05-10 09:45:51 -04003658 memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 }
3660 else {
Jesper Juhlb4558ea2005-10-28 16:53:13 -04003661 kfree(ai->rssi);
3662 ai->rssi = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 if (cap_rid.softCap & 8)
3664 ai->config.rmode |= RXMODE_NORMALIZED_RSSI;
3665 else
Dan Williams934d8bf2006-03-16 13:46:23 -05003666 airo_print_warn(ai->dev->name, "unknown received signal "
3667 "level scale");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 }
3669 ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
3670 ai->config.authType = AUTH_OPEN;
3671 ai->config.modulation = MOD_CCK;
3672
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 if ((cap_rid.len>=sizeof(cap_rid)) && (cap_rid.extSoftCap&1) &&
3674 (micsetup(ai) == SUCCESS)) {
3675 ai->config.opmode |= MODE_MIC;
3676 set_bit(FLAG_MIC_CAPABLE, &ai->flags);
3677 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678
3679 /* Save off the MAC */
3680 for( i = 0; i < ETH_ALEN; i++ ) {
3681 mac[i] = ai->config.macAddr[i];
3682 }
3683
3684 /* Check to see if there are any insmod configured
3685 rates to add */
3686 if ( rates[0] ) {
3687 int i = 0;
3688 memset(ai->config.rates,0,sizeof(ai->config.rates));
3689 for( i = 0; i < 8 && rates[i]; i++ ) {
3690 ai->config.rates[i] = rates[i];
3691 }
3692 }
3693 if ( basic_rate > 0 ) {
3694 int i;
3695 for( i = 0; i < 8; i++ ) {
3696 if ( ai->config.rates[i] == basic_rate ||
3697 !ai->config.rates ) {
3698 ai->config.rates[i] = basic_rate | 0x80;
3699 break;
3700 }
3701 }
3702 }
3703 set_bit (FLAG_COMMIT, &ai->flags);
3704 }
3705
3706 /* Setup the SSIDs if present */
3707 if ( ssids[0] ) {
3708 int i;
3709 for( i = 0; i < 3 && ssids[i]; i++ ) {
3710 mySsid.ssids[i].len = strlen(ssids[i]);
3711 if ( mySsid.ssids[i].len > 32 )
3712 mySsid.ssids[i].len = 32;
3713 memcpy(mySsid.ssids[i].ssid, ssids[i],
3714 mySsid.ssids[i].len);
3715 }
3716 mySsid.len = sizeof(mySsid);
3717 }
3718
3719 status = writeConfigRid(ai, lock);
3720 if ( status != SUCCESS ) return ERROR;
3721
3722 /* Set up the SSID list */
3723 if ( ssids[0] ) {
3724 status = writeSsidRid(ai, &mySsid, lock);
3725 if ( status != SUCCESS ) return ERROR;
3726 }
3727
3728 status = enable_MAC(ai, &rsp, lock);
3729 if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003730 airo_print_err(ai->dev->name, "Bad MAC enable reason = %x, rid = %x,"
3731 " offset = %d", rsp.rsp0, rsp.rsp1, rsp.rsp2 );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 return ERROR;
3733 }
3734
3735 /* Grab the initial wep key, we gotta save it for auto_wep */
3736 rc = readWepKeyRid(ai, &wkr, 1, lock);
3737 if (rc == SUCCESS) do {
3738 lastindex = wkr.kindex;
3739 if (wkr.kindex == 0xffff) {
3740 ai->defindex = wkr.mac[0];
3741 }
3742 rc = readWepKeyRid(ai, &wkr, 0, lock);
3743 } while(lastindex != wkr.kindex);
3744
3745 if (auto_wep) {
3746 ai->expires = RUN_AT(3*HZ);
3747 wake_up_interruptible(&ai->thr_wait);
3748 }
3749
3750 return SUCCESS;
3751}
3752
3753static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
3754 // Im really paranoid about letting it run forever!
3755 int max_tries = 600000;
3756
3757 if (IN4500(ai, EVSTAT) & EV_CMD)
3758 OUT4500(ai, EVACK, EV_CMD);
3759
3760 OUT4500(ai, PARAM0, pCmd->parm0);
3761 OUT4500(ai, PARAM1, pCmd->parm1);
3762 OUT4500(ai, PARAM2, pCmd->parm2);
3763 OUT4500(ai, COMMAND, pCmd->cmd);
3764
3765 while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) {
3766 if ((IN4500(ai, COMMAND)) == pCmd->cmd)
3767 // PC4500 didn't notice command, try again
3768 OUT4500(ai, COMMAND, pCmd->cmd);
3769 if (!in_atomic() && (max_tries & 255) == 0)
3770 schedule();
3771 }
3772
3773 if ( max_tries == -1 ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003774 airo_print_err(ai->dev->name,
3775 "Max tries exceeded when issueing command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776 if (IN4500(ai, COMMAND) & COMMAND_BUSY)
3777 OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
3778 return ERROR;
3779 }
3780
3781 // command completed
3782 pRsp->status = IN4500(ai, STATUS);
3783 pRsp->rsp0 = IN4500(ai, RESP0);
3784 pRsp->rsp1 = IN4500(ai, RESP1);
3785 pRsp->rsp2 = IN4500(ai, RESP2);
3786 if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003787 airo_print_err(ai->dev->name, "cmd= %x\n", pCmd->cmd);
3788 airo_print_err(ai->dev->name, "status= %x\n", pRsp->status);
3789 airo_print_err(ai->dev->name, "Rsp0= %x\n", pRsp->rsp0);
3790 airo_print_err(ai->dev->name, "Rsp1= %x\n", pRsp->rsp1);
3791 airo_print_err(ai->dev->name, "Rsp2= %x\n", pRsp->rsp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 }
3793
3794 // clear stuck command busy if necessary
3795 if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
3796 OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
3797 }
3798 // acknowledge processing the status/response
3799 OUT4500(ai, EVACK, EV_CMD);
3800
3801 return SUCCESS;
3802}
3803
3804/* Sets up the bap to start exchange data. whichbap should
3805 * be one of the BAP0 or BAP1 defines. Locks should be held before
3806 * calling! */
3807static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap )
3808{
3809 int timeout = 50;
3810 int max_tries = 3;
3811
3812 OUT4500(ai, SELECT0+whichbap, rid);
3813 OUT4500(ai, OFFSET0+whichbap, offset);
3814 while (1) {
3815 int status = IN4500(ai, OFFSET0+whichbap);
3816 if (status & BAP_BUSY) {
3817 /* This isn't really a timeout, but its kinda
3818 close */
3819 if (timeout--) {
3820 continue;
3821 }
3822 } else if ( status & BAP_ERR ) {
3823 /* invalid rid or offset */
Dan Williams934d8bf2006-03-16 13:46:23 -05003824 airo_print_err(ai->dev->name, "BAP error %x %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 status, whichbap );
3826 return ERROR;
3827 } else if (status & BAP_DONE) { // success
3828 return SUCCESS;
3829 }
3830 if ( !(max_tries--) ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003831 airo_print_err(ai->dev->name,
3832 "airo: BAP setup error too many retries\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 return ERROR;
3834 }
3835 // -- PC4500 missed it, try again
3836 OUT4500(ai, SELECT0+whichbap, rid);
3837 OUT4500(ai, OFFSET0+whichbap, offset);
3838 timeout = 50;
3839 }
3840}
3841
3842/* should only be called by aux_bap_read. This aux function and the
3843 following use concepts not documented in the developers guide. I
3844 got them from a patch given to my by Aironet */
3845static u16 aux_setup(struct airo_info *ai, u16 page,
3846 u16 offset, u16 *len)
3847{
3848 u16 next;
3849
3850 OUT4500(ai, AUXPAGE, page);
3851 OUT4500(ai, AUXOFF, 0);
3852 next = IN4500(ai, AUXDATA);
3853 *len = IN4500(ai, AUXDATA)&0xff;
3854 if (offset != 4) OUT4500(ai, AUXOFF, offset);
3855 return next;
3856}
3857
3858/* requires call to bap_setup() first */
3859static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst,
3860 int bytelen, int whichbap)
3861{
3862 u16 len;
3863 u16 page;
3864 u16 offset;
3865 u16 next;
3866 int words;
3867 int i;
3868 unsigned long flags;
3869
3870 spin_lock_irqsave(&ai->aux_lock, flags);
3871 page = IN4500(ai, SWS0+whichbap);
3872 offset = IN4500(ai, SWS2+whichbap);
3873 next = aux_setup(ai, page, offset, &len);
3874 words = (bytelen+1)>>1;
3875
3876 for (i=0; i<words;) {
3877 int count;
3878 count = (len>>1) < (words-i) ? (len>>1) : (words-i);
3879 if ( !do8bitIO )
3880 insw( ai->dev->base_addr+DATA0+whichbap,
3881 pu16Dst+i,count );
3882 else
3883 insb( ai->dev->base_addr+DATA0+whichbap,
3884 pu16Dst+i, count << 1 );
3885 i += count;
3886 if (i<words) {
3887 next = aux_setup(ai, next, 4, &len);
3888 }
3889 }
3890 spin_unlock_irqrestore(&ai->aux_lock, flags);
3891 return SUCCESS;
3892}
3893
3894
3895/* requires call to bap_setup() first */
3896static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst,
3897 int bytelen, int whichbap)
3898{
3899 bytelen = (bytelen + 1) & (~1); // round up to even value
3900 if ( !do8bitIO )
3901 insw( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1 );
3902 else
3903 insb( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen );
3904 return SUCCESS;
3905}
3906
3907/* requires call to bap_setup() first */
3908static int bap_write(struct airo_info *ai, const u16 *pu16Src,
3909 int bytelen, int whichbap)
3910{
3911 bytelen = (bytelen + 1) & (~1); // round up to even value
3912 if ( !do8bitIO )
3913 outsw( ai->dev->base_addr+DATA0+whichbap,
3914 pu16Src, bytelen>>1 );
3915 else
3916 outsb( ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen );
3917 return SUCCESS;
3918}
3919
3920static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd)
3921{
3922 Cmd cmd; /* for issuing commands */
3923 Resp rsp; /* response from commands */
3924 u16 status;
3925
3926 memset(&cmd, 0, sizeof(cmd));
3927 cmd.cmd = accmd;
3928 cmd.parm0 = rid;
3929 status = issuecommand(ai, &cmd, &rsp);
3930 if (status != 0) return status;
3931 if ( (rsp.status & 0x7F00) != 0) {
3932 return (accmd << 8) + (rsp.rsp0 & 0xFF);
3933 }
3934 return 0;
3935}
3936
3937/* Note, that we are using BAP1 which is also used by transmit, so
3938 * we must get a lock. */
3939static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, int lock)
3940{
3941 u16 status;
3942 int rc = SUCCESS;
3943
3944 if (lock) {
3945 if (down_interruptible(&ai->sem))
3946 return ERROR;
3947 }
3948 if (test_bit(FLAG_MPI,&ai->flags)) {
3949 Cmd cmd;
3950 Resp rsp;
3951
3952 memset(&cmd, 0, sizeof(cmd));
3953 memset(&rsp, 0, sizeof(rsp));
3954 ai->config_desc.rid_desc.valid = 1;
3955 ai->config_desc.rid_desc.len = RIDSIZE;
3956 ai->config_desc.rid_desc.rid = 0;
3957 ai->config_desc.rid_desc.host_addr = ai->ridbus;
3958
3959 cmd.cmd = CMD_ACCESS;
3960 cmd.parm0 = rid;
3961
3962 memcpy_toio(ai->config_desc.card_ram_off,
3963 &ai->config_desc.rid_desc, sizeof(Rid));
3964
3965 rc = issuecommand(ai, &cmd, &rsp);
3966
3967 if (rsp.status & 0x7f00)
3968 rc = rsp.rsp0;
3969 if (!rc)
3970 memcpy(pBuf, ai->config_desc.virtual_host_addr, len);
3971 goto done;
3972 } else {
3973 if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS))!=SUCCESS) {
3974 rc = status;
3975 goto done;
3976 }
3977 if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
3978 rc = ERROR;
3979 goto done;
3980 }
3981 // read the rid length field
3982 bap_read(ai, pBuf, 2, BAP1);
3983 // length for remaining part of rid
3984 len = min(len, (int)le16_to_cpu(*(u16*)pBuf)) - 2;
3985
3986 if ( len <= 2 ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05003987 airo_print_err(ai->dev->name,
3988 "Rid %x has a length of %d which is too short",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 (int)rid, (int)len );
3990 rc = ERROR;
3991 goto done;
3992 }
3993 // read remainder of the rid
3994 rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
3995 }
3996done:
3997 if (lock)
3998 up(&ai->sem);
3999 return rc;
4000}
4001
4002/* Note, that we are using BAP1 which is also used by transmit, so
4003 * make sure this isnt called when a transmit is happening */
4004static int PC4500_writerid(struct airo_info *ai, u16 rid,
4005 const void *pBuf, int len, int lock)
4006{
4007 u16 status;
4008 int rc = SUCCESS;
4009
4010 *(u16*)pBuf = cpu_to_le16((u16)len);
4011
4012 if (lock) {
4013 if (down_interruptible(&ai->sem))
4014 return ERROR;
4015 }
4016 if (test_bit(FLAG_MPI,&ai->flags)) {
4017 Cmd cmd;
4018 Resp rsp;
4019
Dan Streetmanf89b2322005-11-11 11:41:42 -05004020 if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid))
Dan Williams934d8bf2006-03-16 13:46:23 -05004021 airo_print_err(ai->dev->name,
4022 "%s: MAC should be disabled (rid=%04x)",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 __FUNCTION__, rid);
4024 memset(&cmd, 0, sizeof(cmd));
4025 memset(&rsp, 0, sizeof(rsp));
4026
4027 ai->config_desc.rid_desc.valid = 1;
4028 ai->config_desc.rid_desc.len = *((u16 *)pBuf);
4029 ai->config_desc.rid_desc.rid = 0;
4030
4031 cmd.cmd = CMD_WRITERID;
4032 cmd.parm0 = rid;
4033
4034 memcpy_toio(ai->config_desc.card_ram_off,
4035 &ai->config_desc.rid_desc, sizeof(Rid));
4036
4037 if (len < 4 || len > 2047) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004038 airo_print_err(ai->dev->name, "%s: len=%d", __FUNCTION__, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 rc = -1;
4040 } else {
4041 memcpy((char *)ai->config_desc.virtual_host_addr,
4042 pBuf, len);
4043
4044 rc = issuecommand(ai, &cmd, &rsp);
4045 if ((rc & 0xff00) != 0) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004046 airo_print_err(ai->dev->name, "%s: Write rid Error %d",
4047 __FUNCTION__, rc);
4048 airo_print_err(ai->dev->name, "%s: Cmd=%04x",
4049 __FUNCTION__, cmd.cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 }
4051
4052 if ((rsp.status & 0x7f00))
4053 rc = rsp.rsp0;
4054 }
4055 } else {
4056 // --- first access so that we can write the rid data
4057 if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
4058 rc = status;
4059 goto done;
4060 }
4061 // --- now write the rid data
4062 if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
4063 rc = ERROR;
4064 goto done;
4065 }
4066 bap_write(ai, pBuf, len, BAP1);
4067 // ---now commit the rid data
4068 rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
4069 }
4070done:
4071 if (lock)
4072 up(&ai->sem);
4073 return rc;
4074}
4075
4076/* Allocates a FID to be used for transmitting packets. We only use
4077 one for now. */
4078static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw)
4079{
4080 unsigned int loop = 3000;
4081 Cmd cmd;
4082 Resp rsp;
4083 u16 txFid;
4084 u16 txControl;
4085
4086 cmd.cmd = CMD_ALLOCATETX;
4087 cmd.parm0 = lenPayload;
4088 if (down_interruptible(&ai->sem))
4089 return ERROR;
4090 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
4091 txFid = ERROR;
4092 goto done;
4093 }
4094 if ( (rsp.status & 0xFF00) != 0) {
4095 txFid = ERROR;
4096 goto done;
4097 }
4098 /* wait for the allocate event/indication
4099 * It makes me kind of nervous that this can just sit here and spin,
4100 * but in practice it only loops like four times. */
4101 while (((IN4500(ai, EVSTAT) & EV_ALLOC) == 0) && --loop);
4102 if (!loop) {
4103 txFid = ERROR;
4104 goto done;
4105 }
4106
4107 // get the allocated fid and acknowledge
4108 txFid = IN4500(ai, TXALLOCFID);
4109 OUT4500(ai, EVACK, EV_ALLOC);
4110
4111 /* The CARD is pretty cool since it converts the ethernet packet
4112 * into 802.11. Also note that we don't release the FID since we
4113 * will be using the same one over and over again. */
4114 /* We only have to setup the control once since we are not
4115 * releasing the fid. */
4116 if (raw)
4117 txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_11
4118 | TXCTL_ETHERNET | TXCTL_NORELEASE);
4119 else
4120 txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3
4121 | TXCTL_ETHERNET | TXCTL_NORELEASE);
4122 if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS)
4123 txFid = ERROR;
4124 else
4125 bap_write(ai, &txControl, sizeof(txControl), BAP1);
4126
4127done:
4128 up(&ai->sem);
4129
4130 return txFid;
4131}
4132
4133/* In general BAP1 is dedicated to transmiting packets. However,
4134 since we need a BAP when accessing RIDs, we also use BAP1 for that.
4135 Make sure the BAP1 spinlock is held when this is called. */
4136static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
4137{
4138 u16 payloadLen;
4139 Cmd cmd;
4140 Resp rsp;
4141 int miclen = 0;
4142 u16 txFid = len;
4143 MICBuffer pMic;
4144
4145 len >>= 16;
4146
4147 if (len <= ETH_ALEN * 2) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004148 airo_print_warn(ai->dev->name, "Short packet %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 return ERROR;
4150 }
4151 len -= ETH_ALEN * 2;
4152
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153 if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
4154 (ntohs(((u16 *)pPacket)[6]) != 0x888E)) {
4155 if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS)
4156 return ERROR;
4157 miclen = sizeof(pMic);
4158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 // packet is destination[6], source[6], payload[len-12]
4160 // write the payload length and dst/src/payload
4161 if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR;
4162 /* The hardware addresses aren't counted as part of the payload, so
4163 * we have to subtract the 12 bytes for the addresses off */
4164 payloadLen = cpu_to_le16(len + miclen);
4165 bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
4166 bap_write(ai, (const u16*)pPacket, sizeof(etherHead), BAP1);
4167 if (miclen)
4168 bap_write(ai, (const u16*)&pMic, miclen, BAP1);
4169 bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len, BAP1);
4170 // issue the transmit command
4171 memset( &cmd, 0, sizeof( cmd ) );
4172 cmd.cmd = CMD_TRANSMIT;
4173 cmd.parm0 = txFid;
4174 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
4175 if ( (rsp.status & 0xFF00) != 0) return ERROR;
4176 return SUCCESS;
4177}
4178
4179static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
4180{
4181 u16 fc, payloadLen;
4182 Cmd cmd;
4183 Resp rsp;
4184 int hdrlen;
4185 struct {
4186 u8 addr4[ETH_ALEN];
4187 u16 gaplen;
4188 u8 gap[6];
4189 } gap;
4190 u16 txFid = len;
4191 len >>= 16;
4192 gap.gaplen = 6;
4193
4194 fc = le16_to_cpu(*(const u16*)pPacket);
4195 switch (fc & 0xc) {
4196 case 4:
4197 if ((fc & 0xe0) == 0xc0)
4198 hdrlen = 10;
4199 else
4200 hdrlen = 16;
4201 break;
4202 case 8:
4203 if ((fc&0x300)==0x300){
4204 hdrlen = 30;
4205 break;
4206 }
4207 default:
4208 hdrlen = 24;
4209 }
4210
4211 if (len < hdrlen) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004212 airo_print_warn(ai->dev->name, "Short packet %d", len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 return ERROR;
4214 }
4215
4216 /* packet is 802.11 header + payload
4217 * write the payload length and dst/src/payload */
4218 if (bap_setup(ai, txFid, 6, BAP1) != SUCCESS) return ERROR;
4219 /* The 802.11 header aren't counted as part of the payload, so
4220 * we have to subtract the header bytes off */
4221 payloadLen = cpu_to_le16(len-hdrlen);
4222 bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
4223 if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR;
4224 bap_write(ai, (const u16*)pPacket, hdrlen, BAP1);
4225 bap_write(ai, hdrlen == 30 ?
4226 (const u16*)&gap.gaplen : (const u16*)&gap, 38 - hdrlen, BAP1);
4227
4228 bap_write(ai, (const u16*)(pPacket + hdrlen), len - hdrlen, BAP1);
4229 // issue the transmit command
4230 memset( &cmd, 0, sizeof( cmd ) );
4231 cmd.cmd = CMD_TRANSMIT;
4232 cmd.parm0 = txFid;
4233 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
4234 if ( (rsp.status & 0xFF00) != 0) return ERROR;
4235 return SUCCESS;
4236}
4237
4238/*
4239 * This is the proc_fs routines. It is a bit messier than I would
4240 * like! Feel free to clean it up!
4241 */
4242
4243static ssize_t proc_read( struct file *file,
4244 char __user *buffer,
4245 size_t len,
4246 loff_t *offset);
4247
4248static ssize_t proc_write( struct file *file,
4249 const char __user *buffer,
4250 size_t len,
4251 loff_t *offset );
4252static int proc_close( struct inode *inode, struct file *file );
4253
4254static int proc_stats_open( struct inode *inode, struct file *file );
4255static int proc_statsdelta_open( struct inode *inode, struct file *file );
4256static int proc_status_open( struct inode *inode, struct file *file );
4257static int proc_SSID_open( struct inode *inode, struct file *file );
4258static int proc_APList_open( struct inode *inode, struct file *file );
4259static int proc_BSSList_open( struct inode *inode, struct file *file );
4260static int proc_config_open( struct inode *inode, struct file *file );
4261static int proc_wepkey_open( struct inode *inode, struct file *file );
4262
4263static struct file_operations proc_statsdelta_ops = {
4264 .read = proc_read,
4265 .open = proc_statsdelta_open,
4266 .release = proc_close
4267};
4268
4269static struct file_operations proc_stats_ops = {
4270 .read = proc_read,
4271 .open = proc_stats_open,
4272 .release = proc_close
4273};
4274
4275static struct file_operations proc_status_ops = {
4276 .read = proc_read,
4277 .open = proc_status_open,
4278 .release = proc_close
4279};
4280
4281static struct file_operations proc_SSID_ops = {
4282 .read = proc_read,
4283 .write = proc_write,
4284 .open = proc_SSID_open,
4285 .release = proc_close
4286};
4287
4288static struct file_operations proc_BSSList_ops = {
4289 .read = proc_read,
4290 .write = proc_write,
4291 .open = proc_BSSList_open,
4292 .release = proc_close
4293};
4294
4295static struct file_operations proc_APList_ops = {
4296 .read = proc_read,
4297 .write = proc_write,
4298 .open = proc_APList_open,
4299 .release = proc_close
4300};
4301
4302static struct file_operations proc_config_ops = {
4303 .read = proc_read,
4304 .write = proc_write,
4305 .open = proc_config_open,
4306 .release = proc_close
4307};
4308
4309static struct file_operations proc_wepkey_ops = {
4310 .read = proc_read,
4311 .write = proc_write,
4312 .open = proc_wepkey_open,
4313 .release = proc_close
4314};
4315
4316static struct proc_dir_entry *airo_entry;
4317
4318struct proc_data {
4319 int release_buffer;
4320 int readlen;
4321 char *rbuffer;
4322 int writelen;
4323 int maxwritelen;
4324 char *wbuffer;
4325 void (*on_close) (struct inode *, struct file *);
4326};
4327
4328#ifndef SETPROC_OPS
4329#define SETPROC_OPS(entry, ops) (entry)->proc_fops = &(ops)
4330#endif
4331
4332static int setup_proc_entry( struct net_device *dev,
4333 struct airo_info *apriv ) {
4334 struct proc_dir_entry *entry;
4335 /* First setup the device directory */
4336 strcpy(apriv->proc_name,dev->name);
4337 apriv->proc_entry = create_proc_entry(apriv->proc_name,
4338 S_IFDIR|airo_perm,
4339 airo_entry);
4340 apriv->proc_entry->uid = proc_uid;
4341 apriv->proc_entry->gid = proc_gid;
4342 apriv->proc_entry->owner = THIS_MODULE;
4343
4344 /* Setup the StatsDelta */
4345 entry = create_proc_entry("StatsDelta",
4346 S_IFREG | (S_IRUGO&proc_perm),
4347 apriv->proc_entry);
4348 entry->uid = proc_uid;
4349 entry->gid = proc_gid;
4350 entry->data = dev;
4351 entry->owner = THIS_MODULE;
4352 SETPROC_OPS(entry, proc_statsdelta_ops);
4353
4354 /* Setup the Stats */
4355 entry = create_proc_entry("Stats",
4356 S_IFREG | (S_IRUGO&proc_perm),
4357 apriv->proc_entry);
4358 entry->uid = proc_uid;
4359 entry->gid = proc_gid;
4360 entry->data = dev;
4361 entry->owner = THIS_MODULE;
4362 SETPROC_OPS(entry, proc_stats_ops);
4363
4364 /* Setup the Status */
4365 entry = create_proc_entry("Status",
4366 S_IFREG | (S_IRUGO&proc_perm),
4367 apriv->proc_entry);
4368 entry->uid = proc_uid;
4369 entry->gid = proc_gid;
4370 entry->data = dev;
4371 entry->owner = THIS_MODULE;
4372 SETPROC_OPS(entry, proc_status_ops);
4373
4374 /* Setup the Config */
4375 entry = create_proc_entry("Config",
4376 S_IFREG | proc_perm,
4377 apriv->proc_entry);
4378 entry->uid = proc_uid;
4379 entry->gid = proc_gid;
4380 entry->data = dev;
4381 entry->owner = THIS_MODULE;
4382 SETPROC_OPS(entry, proc_config_ops);
4383
4384 /* Setup the SSID */
4385 entry = create_proc_entry("SSID",
4386 S_IFREG | proc_perm,
4387 apriv->proc_entry);
4388 entry->uid = proc_uid;
4389 entry->gid = proc_gid;
4390 entry->data = dev;
4391 entry->owner = THIS_MODULE;
4392 SETPROC_OPS(entry, proc_SSID_ops);
4393
4394 /* Setup the APList */
4395 entry = create_proc_entry("APList",
4396 S_IFREG | proc_perm,
4397 apriv->proc_entry);
4398 entry->uid = proc_uid;
4399 entry->gid = proc_gid;
4400 entry->data = dev;
4401 entry->owner = THIS_MODULE;
4402 SETPROC_OPS(entry, proc_APList_ops);
4403
4404 /* Setup the BSSList */
4405 entry = create_proc_entry("BSSList",
4406 S_IFREG | proc_perm,
4407 apriv->proc_entry);
4408 entry->uid = proc_uid;
4409 entry->gid = proc_gid;
4410 entry->data = dev;
4411 entry->owner = THIS_MODULE;
4412 SETPROC_OPS(entry, proc_BSSList_ops);
4413
4414 /* Setup the WepKey */
4415 entry = create_proc_entry("WepKey",
4416 S_IFREG | proc_perm,
4417 apriv->proc_entry);
4418 entry->uid = proc_uid;
4419 entry->gid = proc_gid;
4420 entry->data = dev;
4421 entry->owner = THIS_MODULE;
4422 SETPROC_OPS(entry, proc_wepkey_ops);
4423
4424 return 0;
4425}
4426
4427static int takedown_proc_entry( struct net_device *dev,
4428 struct airo_info *apriv ) {
4429 if ( !apriv->proc_entry->namelen ) return 0;
4430 remove_proc_entry("Stats",apriv->proc_entry);
4431 remove_proc_entry("StatsDelta",apriv->proc_entry);
4432 remove_proc_entry("Status",apriv->proc_entry);
4433 remove_proc_entry("Config",apriv->proc_entry);
4434 remove_proc_entry("SSID",apriv->proc_entry);
4435 remove_proc_entry("APList",apriv->proc_entry);
4436 remove_proc_entry("BSSList",apriv->proc_entry);
4437 remove_proc_entry("WepKey",apriv->proc_entry);
4438 remove_proc_entry(apriv->proc_name,airo_entry);
4439 return 0;
4440}
4441
4442/*
4443 * What we want from the proc_fs is to be able to efficiently read
4444 * and write the configuration. To do this, we want to read the
4445 * configuration when the file is opened and write it when the file is
4446 * closed. So basically we allocate a read buffer at open and fill it
4447 * with data, and allocate a write buffer and read it at close.
4448 */
4449
4450/*
4451 * The read routine is generic, it relies on the preallocated rbuffer
4452 * to supply the data.
4453 */
4454static ssize_t proc_read( struct file *file,
4455 char __user *buffer,
4456 size_t len,
4457 loff_t *offset )
4458{
4459 loff_t pos = *offset;
4460 struct proc_data *priv = (struct proc_data*)file->private_data;
4461
4462 if (!priv->rbuffer)
4463 return -EINVAL;
4464
4465 if (pos < 0)
4466 return -EINVAL;
4467 if (pos >= priv->readlen)
4468 return 0;
4469 if (len > priv->readlen - pos)
4470 len = priv->readlen - pos;
4471 if (copy_to_user(buffer, priv->rbuffer + pos, len))
4472 return -EFAULT;
4473 *offset = pos + len;
4474 return len;
4475}
4476
4477/*
4478 * The write routine is generic, it fills in a preallocated rbuffer
4479 * to supply the data.
4480 */
4481static ssize_t proc_write( struct file *file,
4482 const char __user *buffer,
4483 size_t len,
4484 loff_t *offset )
4485{
4486 loff_t pos = *offset;
4487 struct proc_data *priv = (struct proc_data*)file->private_data;
4488
4489 if (!priv->wbuffer)
4490 return -EINVAL;
4491
4492 if (pos < 0)
4493 return -EINVAL;
4494 if (pos >= priv->maxwritelen)
4495 return 0;
4496 if (len > priv->maxwritelen - pos)
4497 len = priv->maxwritelen - pos;
4498 if (copy_from_user(priv->wbuffer + pos, buffer, len))
4499 return -EFAULT;
4500 if ( pos + len > priv->writelen )
4501 priv->writelen = len + file->f_pos;
4502 *offset = pos + len;
4503 return len;
4504}
4505
4506static int proc_status_open( struct inode *inode, struct file *file ) {
4507 struct proc_data *data;
4508 struct proc_dir_entry *dp = PDE(inode);
4509 struct net_device *dev = dp->data;
4510 struct airo_info *apriv = dev->priv;
4511 CapabilityRid cap_rid;
4512 StatusRid status_rid;
4513 int i;
4514
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01004515 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 data = (struct proc_data *)file->private_data;
4518 if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
4519 kfree (file->private_data);
4520 return -ENOMEM;
4521 }
4522
4523 readStatusRid(apriv, &status_rid, 1);
4524 readCapabilityRid(apriv, &cap_rid, 1);
4525
4526 i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n",
4527 status_rid.mode & 1 ? "CFG ": "",
4528 status_rid.mode & 2 ? "ACT ": "",
4529 status_rid.mode & 0x10 ? "SYN ": "",
4530 status_rid.mode & 0x20 ? "LNK ": "",
4531 status_rid.mode & 0x40 ? "LEAP ": "",
4532 status_rid.mode & 0x80 ? "PRIV ": "",
4533 status_rid.mode & 0x100 ? "KEY ": "",
4534 status_rid.mode & 0x200 ? "WEP ": "",
4535 status_rid.mode & 0x8000 ? "ERR ": "");
4536 sprintf( data->rbuffer+i, "Mode: %x\n"
4537 "Signal Strength: %d\n"
4538 "Signal Quality: %d\n"
4539 "SSID: %-.*s\n"
4540 "AP: %-.16s\n"
4541 "Freq: %d\n"
4542 "BitRate: %dmbs\n"
4543 "Driver Version: %s\n"
4544 "Device: %s\nManufacturer: %s\nFirmware Version: %s\n"
4545 "Radio type: %x\nCountry: %x\nHardware Version: %x\n"
4546 "Software Version: %x\nSoftware Subversion: %x\n"
4547 "Boot block version: %x\n",
4548 (int)status_rid.mode,
4549 (int)status_rid.normalizedSignalStrength,
4550 (int)status_rid.signalQuality,
4551 (int)status_rid.SSIDlen,
4552 status_rid.SSID,
4553 status_rid.apName,
4554 (int)status_rid.channel,
4555 (int)status_rid.currentXmitRate/2,
4556 version,
4557 cap_rid.prodName,
4558 cap_rid.manName,
4559 cap_rid.prodVer,
4560 cap_rid.radioType,
4561 cap_rid.country,
4562 cap_rid.hardVer,
4563 (int)cap_rid.softVer,
4564 (int)cap_rid.softSubVer,
4565 (int)cap_rid.bootBlockVer );
4566 data->readlen = strlen( data->rbuffer );
4567 return 0;
4568}
4569
4570static int proc_stats_rid_open(struct inode*, struct file*, u16);
4571static int proc_statsdelta_open( struct inode *inode,
4572 struct file *file ) {
4573 if (file->f_mode&FMODE_WRITE) {
4574 return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR);
4575 }
4576 return proc_stats_rid_open(inode, file, RID_STATSDELTA);
4577}
4578
4579static int proc_stats_open( struct inode *inode, struct file *file ) {
4580 return proc_stats_rid_open(inode, file, RID_STATS);
4581}
4582
4583static int proc_stats_rid_open( struct inode *inode,
4584 struct file *file,
4585 u16 rid ) {
4586 struct proc_data *data;
4587 struct proc_dir_entry *dp = PDE(inode);
4588 struct net_device *dev = dp->data;
4589 struct airo_info *apriv = dev->priv;
4590 StatsRid stats;
4591 int i, j;
4592 u32 *vals = stats.vals;
4593
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01004594 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 data = (struct proc_data *)file->private_data;
4597 if ((data->rbuffer = kmalloc( 4096, GFP_KERNEL )) == NULL) {
4598 kfree (file->private_data);
4599 return -ENOMEM;
4600 }
4601
4602 readStatsRid(apriv, &stats, rid, 1);
4603
4604 j = 0;
4605 for(i=0; statsLabels[i]!=(char *)-1 &&
4606 i*4<stats.len; i++){
4607 if (!statsLabels[i]) continue;
4608 if (j+strlen(statsLabels[i])+16>4096) {
Dan Williams934d8bf2006-03-16 13:46:23 -05004609 airo_print_warn(apriv->dev->name,
4610 "Potentially disasterous buffer overflow averted!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 break;
4612 }
4613 j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], vals[i]);
4614 }
4615 if (i*4>=stats.len){
Dan Williams934d8bf2006-03-16 13:46:23 -05004616 airo_print_warn(apriv->dev->name, "Got a short rid");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 }
4618 data->readlen = j;
4619 return 0;
4620}
4621
4622static int get_dec_u16( char *buffer, int *start, int limit ) {
4623 u16 value;
4624 int valid = 0;
4625 for( value = 0; buffer[*start] >= '0' &&
4626 buffer[*start] <= '9' &&
4627 *start < limit; (*start)++ ) {
4628 valid = 1;
4629 value *= 10;
4630 value += buffer[*start] - '0';
4631 }
4632 if ( !valid ) return -1;
4633 return value;
4634}
4635
4636static int airo_config_commit(struct net_device *dev,
4637 struct iw_request_info *info, void *zwrq,
4638 char *extra);
4639
4640static void proc_config_on_close( struct inode *inode, struct file *file ) {
4641 struct proc_data *data = file->private_data;
4642 struct proc_dir_entry *dp = PDE(inode);
4643 struct net_device *dev = dp->data;
4644 struct airo_info *ai = dev->priv;
4645 char *line;
4646
4647 if ( !data->writelen ) return;
4648
4649 readConfigRid(ai, 1);
4650 set_bit (FLAG_COMMIT, &ai->flags);
4651
4652 line = data->wbuffer;
4653 while( line[0] ) {
4654/*** Mode processing */
4655 if ( !strncmp( line, "Mode: ", 6 ) ) {
4656 line += 6;
4657 if ((ai->config.rmode & 0xff) >= RXMODE_RFMON)
4658 set_bit (FLAG_RESET, &ai->flags);
4659 ai->config.rmode &= 0xfe00;
4660 clear_bit (FLAG_802_11, &ai->flags);
4661 ai->config.opmode &= 0xFF00;
4662 ai->config.scanMode = SCANMODE_ACTIVE;
4663 if ( line[0] == 'a' ) {
4664 ai->config.opmode |= 0;
4665 } else {
4666 ai->config.opmode |= 1;
4667 if ( line[0] == 'r' ) {
4668 ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
4669 ai->config.scanMode = SCANMODE_PASSIVE;
4670 set_bit (FLAG_802_11, &ai->flags);
4671 } else if ( line[0] == 'y' ) {
4672 ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER;
4673 ai->config.scanMode = SCANMODE_PASSIVE;
4674 set_bit (FLAG_802_11, &ai->flags);
4675 } else if ( line[0] == 'l' )
4676 ai->config.rmode |= RXMODE_LANMON;
4677 }
4678 set_bit (FLAG_COMMIT, &ai->flags);
4679 }
4680
4681/*** Radio status */
4682 else if (!strncmp(line,"Radio: ", 7)) {
4683 line += 7;
4684 if (!strncmp(line,"off",3)) {
4685 set_bit (FLAG_RADIO_OFF, &ai->flags);
4686 } else {
4687 clear_bit (FLAG_RADIO_OFF, &ai->flags);
4688 }
4689 }
4690/*** NodeName processing */
4691 else if ( !strncmp( line, "NodeName: ", 10 ) ) {
4692 int j;
4693
4694 line += 10;
4695 memset( ai->config.nodeName, 0, 16 );
4696/* Do the name, assume a space between the mode and node name */
4697 for( j = 0; j < 16 && line[j] != '\n'; j++ ) {
4698 ai->config.nodeName[j] = line[j];
4699 }
4700 set_bit (FLAG_COMMIT, &ai->flags);
4701 }
4702
4703/*** PowerMode processing */
4704 else if ( !strncmp( line, "PowerMode: ", 11 ) ) {
4705 line += 11;
4706 if ( !strncmp( line, "PSPCAM", 6 ) ) {
4707 ai->config.powerSaveMode = POWERSAVE_PSPCAM;
4708 set_bit (FLAG_COMMIT, &ai->flags);
4709 } else if ( !strncmp( line, "PSP", 3 ) ) {
4710 ai->config.powerSaveMode = POWERSAVE_PSP;
4711 set_bit (FLAG_COMMIT, &ai->flags);
4712 } else {
4713 ai->config.powerSaveMode = POWERSAVE_CAM;
4714 set_bit (FLAG_COMMIT, &ai->flags);
4715 }
4716 } else if ( !strncmp( line, "DataRates: ", 11 ) ) {
4717 int v, i = 0, k = 0; /* i is index into line,
4718 k is index to rates */
4719
4720 line += 11;
4721 while((v = get_dec_u16(line, &i, 3))!=-1) {
4722 ai->config.rates[k++] = (u8)v;
4723 line += i + 1;
4724 i = 0;
4725 }
4726 set_bit (FLAG_COMMIT, &ai->flags);
4727 } else if ( !strncmp( line, "Channel: ", 9 ) ) {
4728 int v, i = 0;
4729 line += 9;
4730 v = get_dec_u16(line, &i, i+3);
4731 if ( v != -1 ) {
4732 ai->config.channelSet = (u16)v;
4733 set_bit (FLAG_COMMIT, &ai->flags);
4734 }
4735 } else if ( !strncmp( line, "XmitPower: ", 11 ) ) {
4736 int v, i = 0;
4737 line += 11;
4738 v = get_dec_u16(line, &i, i+3);
4739 if ( v != -1 ) {
4740 ai->config.txPower = (u16)v;
4741 set_bit (FLAG_COMMIT, &ai->flags);
4742 }
4743 } else if ( !strncmp( line, "WEP: ", 5 ) ) {
4744 line += 5;
4745 switch( line[0] ) {
4746 case 's':
4747 ai->config.authType = (u16)AUTH_SHAREDKEY;
4748 break;
4749 case 'e':
4750 ai->config.authType = (u16)AUTH_ENCRYPT;
4751 break;
4752 default:
4753 ai->config.authType = (u16)AUTH_OPEN;
4754 break;
4755 }
4756 set_bit (FLAG_COMMIT, &ai->flags);
4757 } else if ( !strncmp( line, "LongRetryLimit: ", 16 ) ) {
4758 int v, i = 0;
4759
4760 line += 16;
4761 v = get_dec_u16(line, &i, 3);
4762 v = (v<0) ? 0 : ((v>255) ? 255 : v);
4763 ai->config.longRetryLimit = (u16)v;
4764 set_bit (FLAG_COMMIT, &ai->flags);
4765 } else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) {
4766 int v, i = 0;
4767
4768 line += 17;
4769 v = get_dec_u16(line, &i, 3);
4770 v = (v<0) ? 0 : ((v>255) ? 255 : v);
4771 ai->config.shortRetryLimit = (u16)v;
4772 set_bit (FLAG_COMMIT, &ai->flags);
4773 } else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) {
4774 int v, i = 0;
4775
4776 line += 14;
4777 v = get_dec_u16(line, &i, 4);
Dan Williams15db2762006-03-16 13:46:27 -05004778 v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 ai->config.rtsThres = (u16)v;
4780 set_bit (FLAG_COMMIT, &ai->flags);
4781 } else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) {
4782 int v, i = 0;
4783
4784 line += 16;
4785 v = get_dec_u16(line, &i, 5);
4786 v = (v<0) ? 0 : v;
4787 ai->config.txLifetime = (u16)v;
4788 set_bit (FLAG_COMMIT, &ai->flags);
4789 } else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) {
4790 int v, i = 0;
4791
4792 line += 16;
4793 v = get_dec_u16(line, &i, 5);
4794 v = (v<0) ? 0 : v;
4795 ai->config.rxLifetime = (u16)v;
4796 set_bit (FLAG_COMMIT, &ai->flags);
4797 } else if ( !strncmp( line, "TXDiversity: ", 13 ) ) {
4798 ai->config.txDiversity =
4799 (line[13]=='l') ? 1 :
4800 ((line[13]=='r')? 2: 3);
4801 set_bit (FLAG_COMMIT, &ai->flags);
4802 } else if ( !strncmp( line, "RXDiversity: ", 13 ) ) {
4803 ai->config.rxDiversity =
4804 (line[13]=='l') ? 1 :
4805 ((line[13]=='r')? 2: 3);
4806 set_bit (FLAG_COMMIT, &ai->flags);
4807 } else if ( !strncmp( line, "FragThreshold: ", 15 ) ) {
4808 int v, i = 0;
4809
4810 line += 15;
4811 v = get_dec_u16(line, &i, 4);
Dan Williams15db2762006-03-16 13:46:27 -05004812 v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 v = v & 0xfffe; /* Make sure its even */
4814 ai->config.fragThresh = (u16)v;
4815 set_bit (FLAG_COMMIT, &ai->flags);
4816 } else if (!strncmp(line, "Modulation: ", 12)) {
4817 line += 12;
4818 switch(*line) {
4819 case 'd': ai->config.modulation=MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break;
4820 case 'c': ai->config.modulation=MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break;
4821 case 'm': ai->config.modulation=MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break;
Dan Williams934d8bf2006-03-16 13:46:23 -05004822 default: airo_print_warn(ai->dev->name, "Unknown modulation");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 }
4824 } else if (!strncmp(line, "Preamble: ", 10)) {
4825 line += 10;
4826 switch(*line) {
4827 case 'a': ai->config.preamble=PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break;
4828 case 'l': ai->config.preamble=PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break;
4829 case 's': ai->config.preamble=PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break;
Dan Williams934d8bf2006-03-16 13:46:23 -05004830 default: airo_print_warn(ai->dev->name, "Unknown preamble");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 }
4832 } else {
Dan Williams934d8bf2006-03-16 13:46:23 -05004833 airo_print_warn(ai->dev->name, "Couldn't figure out %s", line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 }
4835 while( line[0] && line[0] != '\n' ) line++;
4836 if ( line[0] ) line++;
4837 }
4838 airo_config_commit(dev, NULL, NULL, NULL);
4839}
4840
4841static char *get_rmode(u16 mode) {
4842 switch(mode&0xff) {
4843 case RXMODE_RFMON: return "rfmon";
4844 case RXMODE_RFMON_ANYBSS: return "yna (any) bss rfmon";
4845 case RXMODE_LANMON: return "lanmon";
4846 }
4847 return "ESS";
4848}
4849
4850static int proc_config_open( struct inode *inode, struct file *file ) {
4851 struct proc_data *data;
4852 struct proc_dir_entry *dp = PDE(inode);
4853 struct net_device *dev = dp->data;
4854 struct airo_info *ai = dev->priv;
4855 int i;
4856
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01004857 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 data = (struct proc_data *)file->private_data;
4860 if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
4861 kfree (file->private_data);
4862 return -ENOMEM;
4863 }
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01004864 if ((data->wbuffer = kzalloc( 2048, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 kfree (data->rbuffer);
4866 kfree (file->private_data);
4867 return -ENOMEM;
4868 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 data->maxwritelen = 2048;
4870 data->on_close = proc_config_on_close;
4871
4872 readConfigRid(ai, 1);
4873
4874 i = sprintf( data->rbuffer,
4875 "Mode: %s\n"
4876 "Radio: %s\n"
4877 "NodeName: %-16s\n"
4878 "PowerMode: %s\n"
4879 "DataRates: %d %d %d %d %d %d %d %d\n"
4880 "Channel: %d\n"
4881 "XmitPower: %d\n",
4882 (ai->config.opmode & 0xFF) == 0 ? "adhoc" :
4883 (ai->config.opmode & 0xFF) == 1 ? get_rmode(ai->config.rmode):
4884 (ai->config.opmode & 0xFF) == 2 ? "AP" :
4885 (ai->config.opmode & 0xFF) == 3 ? "AP RPTR" : "Error",
4886 test_bit(FLAG_RADIO_OFF, &ai->flags) ? "off" : "on",
4887 ai->config.nodeName,
4888 ai->config.powerSaveMode == 0 ? "CAM" :
4889 ai->config.powerSaveMode == 1 ? "PSP" :
4890 ai->config.powerSaveMode == 2 ? "PSPCAM" : "Error",
4891 (int)ai->config.rates[0],
4892 (int)ai->config.rates[1],
4893 (int)ai->config.rates[2],
4894 (int)ai->config.rates[3],
4895 (int)ai->config.rates[4],
4896 (int)ai->config.rates[5],
4897 (int)ai->config.rates[6],
4898 (int)ai->config.rates[7],
4899 (int)ai->config.channelSet,
4900 (int)ai->config.txPower
4901 );
4902 sprintf( data->rbuffer + i,
4903 "LongRetryLimit: %d\n"
4904 "ShortRetryLimit: %d\n"
4905 "RTSThreshold: %d\n"
4906 "TXMSDULifetime: %d\n"
4907 "RXMSDULifetime: %d\n"
4908 "TXDiversity: %s\n"
4909 "RXDiversity: %s\n"
4910 "FragThreshold: %d\n"
4911 "WEP: %s\n"
4912 "Modulation: %s\n"
4913 "Preamble: %s\n",
4914 (int)ai->config.longRetryLimit,
4915 (int)ai->config.shortRetryLimit,
4916 (int)ai->config.rtsThres,
4917 (int)ai->config.txLifetime,
4918 (int)ai->config.rxLifetime,
4919 ai->config.txDiversity == 1 ? "left" :
4920 ai->config.txDiversity == 2 ? "right" : "both",
4921 ai->config.rxDiversity == 1 ? "left" :
4922 ai->config.rxDiversity == 2 ? "right" : "both",
4923 (int)ai->config.fragThresh,
4924 ai->config.authType == AUTH_ENCRYPT ? "encrypt" :
4925 ai->config.authType == AUTH_SHAREDKEY ? "shared" : "open",
4926 ai->config.modulation == 0 ? "default" :
4927 ai->config.modulation == MOD_CCK ? "cck" :
4928 ai->config.modulation == MOD_MOK ? "mok" : "error",
4929 ai->config.preamble == PREAMBLE_AUTO ? "auto" :
4930 ai->config.preamble == PREAMBLE_LONG ? "long" :
4931 ai->config.preamble == PREAMBLE_SHORT ? "short" : "error"
4932 );
4933 data->readlen = strlen( data->rbuffer );
4934 return 0;
4935}
4936
4937static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
4938 struct proc_data *data = (struct proc_data *)file->private_data;
4939 struct proc_dir_entry *dp = PDE(inode);
4940 struct net_device *dev = dp->data;
4941 struct airo_info *ai = dev->priv;
4942 SsidRid SSID_rid;
4943 Resp rsp;
4944 int i;
4945 int offset = 0;
4946
4947 if ( !data->writelen ) return;
4948
4949 memset( &SSID_rid, 0, sizeof( SSID_rid ) );
4950
4951 for( i = 0; i < 3; i++ ) {
4952 int j;
4953 for( j = 0; j+offset < data->writelen && j < 32 &&
4954 data->wbuffer[offset+j] != '\n'; j++ ) {
4955 SSID_rid.ssids[i].ssid[j] = data->wbuffer[offset+j];
4956 }
4957 if ( j == 0 ) break;
4958 SSID_rid.ssids[i].len = j;
4959 offset += j;
4960 while( data->wbuffer[offset] != '\n' &&
4961 offset < data->writelen ) offset++;
4962 offset++;
4963 }
4964 if (i)
4965 SSID_rid.len = sizeof(SSID_rid);
4966 disable_MAC(ai, 1);
4967 writeSsidRid(ai, &SSID_rid, 1);
4968 enable_MAC(ai, &rsp, 1);
4969}
4970
Jesper Juhl77933d72005-07-27 11:46:09 -07004971static inline u8 hexVal(char c) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004972 if (c>='0' && c<='9') return c -= '0';
4973 if (c>='a' && c<='f') return c -= 'a'-10;
4974 if (c>='A' && c<='F') return c -= 'A'-10;
4975 return 0;
4976}
4977
4978static void proc_APList_on_close( struct inode *inode, struct file *file ) {
4979 struct proc_data *data = (struct proc_data *)file->private_data;
4980 struct proc_dir_entry *dp = PDE(inode);
4981 struct net_device *dev = dp->data;
4982 struct airo_info *ai = dev->priv;
4983 APListRid APList_rid;
4984 Resp rsp;
4985 int i;
4986
4987 if ( !data->writelen ) return;
4988
4989 memset( &APList_rid, 0, sizeof(APList_rid) );
4990 APList_rid.len = sizeof(APList_rid);
4991
4992 for( i = 0; i < 4 && data->writelen >= (i+1)*6*3; i++ ) {
4993 int j;
4994 for( j = 0; j < 6*3 && data->wbuffer[j+i*6*3]; j++ ) {
4995 switch(j%3) {
4996 case 0:
4997 APList_rid.ap[i][j/3]=
4998 hexVal(data->wbuffer[j+i*6*3])<<4;
4999 break;
5000 case 1:
5001 APList_rid.ap[i][j/3]|=
5002 hexVal(data->wbuffer[j+i*6*3]);
5003 break;
5004 }
5005 }
5006 }
5007 disable_MAC(ai, 1);
5008 writeAPListRid(ai, &APList_rid, 1);
5009 enable_MAC(ai, &rsp, 1);
5010}
5011
5012/* This function wraps PC4500_writerid with a MAC disable */
5013static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data,
5014 int len, int dummy ) {
5015 int rc;
5016 Resp rsp;
5017
5018 disable_MAC(ai, 1);
5019 rc = PC4500_writerid(ai, rid, rid_data, len, 1);
5020 enable_MAC(ai, &rsp, 1);
5021 return rc;
5022}
5023
5024/* Returns the length of the key at the index. If index == 0xffff
5025 * the index of the transmit key is returned. If the key doesn't exist,
5026 * -1 will be returned.
5027 */
5028static int get_wep_key(struct airo_info *ai, u16 index) {
5029 WepKeyRid wkr;
5030 int rc;
5031 u16 lastindex;
5032
5033 rc = readWepKeyRid(ai, &wkr, 1, 1);
5034 if (rc == SUCCESS) do {
5035 lastindex = wkr.kindex;
5036 if (wkr.kindex == index) {
5037 if (index == 0xffff) {
5038 return wkr.mac[0];
5039 }
5040 return wkr.klen;
5041 }
5042 readWepKeyRid(ai, &wkr, 0, 1);
5043 } while(lastindex != wkr.kindex);
5044 return -1;
5045}
5046
5047static int set_wep_key(struct airo_info *ai, u16 index,
5048 const char *key, u16 keylen, int perm, int lock ) {
5049 static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
5050 WepKeyRid wkr;
5051 Resp rsp;
5052
5053 memset(&wkr, 0, sizeof(wkr));
5054 if (keylen == 0) {
5055// We are selecting which key to use
5056 wkr.len = sizeof(wkr);
5057 wkr.kindex = 0xffff;
5058 wkr.mac[0] = (char)index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059 if (perm) ai->defindex = (char)index;
5060 } else {
5061// We are actually setting the key
5062 wkr.len = sizeof(wkr);
5063 wkr.kindex = index;
5064 wkr.klen = keylen;
5065 memcpy( wkr.key, key, keylen );
5066 memcpy( wkr.mac, macaddr, ETH_ALEN );
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067 }
5068
Dan Streetmanf89b2322005-11-11 11:41:42 -05005069 if (perm) disable_MAC(ai, lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 writeWepKeyRid(ai, &wkr, perm, lock);
Dan Streetmanf89b2322005-11-11 11:41:42 -05005071 if (perm) enable_MAC(ai, &rsp, lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 return 0;
5073}
5074
5075static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
5076 struct proc_data *data;
5077 struct proc_dir_entry *dp = PDE(inode);
5078 struct net_device *dev = dp->data;
5079 struct airo_info *ai = dev->priv;
5080 int i;
5081 char key[16];
5082 u16 index = 0;
5083 int j = 0;
5084
5085 memset(key, 0, sizeof(key));
5086
5087 data = (struct proc_data *)file->private_data;
5088 if ( !data->writelen ) return;
5089
5090 if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' &&
5091 (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) {
5092 index = data->wbuffer[0] - '0';
5093 if (data->wbuffer[1] == '\n') {
5094 set_wep_key(ai, index, NULL, 0, 1, 1);
5095 return;
5096 }
5097 j = 2;
5098 } else {
Dan Williams934d8bf2006-03-16 13:46:23 -05005099 airo_print_err(ai->dev->name, "WepKey passed invalid key index");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 return;
5101 }
5102
5103 for( i = 0; i < 16*3 && data->wbuffer[i+j]; i++ ) {
5104 switch(i%3) {
5105 case 0:
5106 key[i/3] = hexVal(data->wbuffer[i+j])<<4;
5107 break;
5108 case 1:
5109 key[i/3] |= hexVal(data->wbuffer[i+j]);
5110 break;
5111 }
5112 }
5113 set_wep_key(ai, index, key, i/3, 1, 1);
5114}
5115
5116static int proc_wepkey_open( struct inode *inode, struct file *file ) {
5117 struct proc_data *data;
5118 struct proc_dir_entry *dp = PDE(inode);
5119 struct net_device *dev = dp->data;
5120 struct airo_info *ai = dev->priv;
5121 char *ptr;
5122 WepKeyRid wkr;
5123 u16 lastindex;
5124 int j=0;
5125 int rc;
5126
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005127 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 memset(&wkr, 0, sizeof(wkr));
5130 data = (struct proc_data *)file->private_data;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005131 if ((data->rbuffer = kzalloc( 180, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132 kfree (file->private_data);
5133 return -ENOMEM;
5134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 data->writelen = 0;
5136 data->maxwritelen = 80;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005137 if ((data->wbuffer = kzalloc( 80, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 kfree (data->rbuffer);
5139 kfree (file->private_data);
5140 return -ENOMEM;
5141 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 data->on_close = proc_wepkey_on_close;
5143
5144 ptr = data->rbuffer;
5145 strcpy(ptr, "No wep keys\n");
5146 rc = readWepKeyRid(ai, &wkr, 1, 1);
5147 if (rc == SUCCESS) do {
5148 lastindex = wkr.kindex;
5149 if (wkr.kindex == 0xffff) {
5150 j += sprintf(ptr+j, "Tx key = %d\n",
5151 (int)wkr.mac[0]);
5152 } else {
5153 j += sprintf(ptr+j, "Key %d set with length = %d\n",
5154 (int)wkr.kindex, (int)wkr.klen);
5155 }
5156 readWepKeyRid(ai, &wkr, 0, 1);
5157 } while((lastindex != wkr.kindex) && (j < 180-30));
5158
5159 data->readlen = strlen( data->rbuffer );
5160 return 0;
5161}
5162
5163static int proc_SSID_open( struct inode *inode, struct file *file ) {
5164 struct proc_data *data;
5165 struct proc_dir_entry *dp = PDE(inode);
5166 struct net_device *dev = dp->data;
5167 struct airo_info *ai = dev->priv;
5168 int i;
5169 char *ptr;
5170 SsidRid SSID_rid;
5171
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005172 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 data = (struct proc_data *)file->private_data;
5175 if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
5176 kfree (file->private_data);
5177 return -ENOMEM;
5178 }
5179 data->writelen = 0;
5180 data->maxwritelen = 33*3;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005181 if ((data->wbuffer = kzalloc( 33*3, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 kfree (data->rbuffer);
5183 kfree (file->private_data);
5184 return -ENOMEM;
5185 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 data->on_close = proc_SSID_on_close;
5187
5188 readSsidRid(ai, &SSID_rid);
5189 ptr = data->rbuffer;
5190 for( i = 0; i < 3; i++ ) {
5191 int j;
5192 if ( !SSID_rid.ssids[i].len ) break;
5193 for( j = 0; j < 32 &&
5194 j < SSID_rid.ssids[i].len &&
5195 SSID_rid.ssids[i].ssid[j]; j++ ) {
5196 *ptr++ = SSID_rid.ssids[i].ssid[j];
5197 }
5198 *ptr++ = '\n';
5199 }
5200 *ptr = '\0';
5201 data->readlen = strlen( data->rbuffer );
5202 return 0;
5203}
5204
5205static int proc_APList_open( struct inode *inode, struct file *file ) {
5206 struct proc_data *data;
5207 struct proc_dir_entry *dp = PDE(inode);
5208 struct net_device *dev = dp->data;
5209 struct airo_info *ai = dev->priv;
5210 int i;
5211 char *ptr;
5212 APListRid APList_rid;
5213
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005214 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 data = (struct proc_data *)file->private_data;
5217 if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
5218 kfree (file->private_data);
5219 return -ENOMEM;
5220 }
5221 data->writelen = 0;
5222 data->maxwritelen = 4*6*3;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005223 if ((data->wbuffer = kzalloc( data->maxwritelen, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 kfree (data->rbuffer);
5225 kfree (file->private_data);
5226 return -ENOMEM;
5227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 data->on_close = proc_APList_on_close;
5229
5230 readAPListRid(ai, &APList_rid);
5231 ptr = data->rbuffer;
5232 for( i = 0; i < 4; i++ ) {
5233// We end when we find a zero MAC
5234 if ( !*(int*)APList_rid.ap[i] &&
5235 !*(int*)&APList_rid.ap[i][2]) break;
5236 ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x\n",
5237 (int)APList_rid.ap[i][0],
5238 (int)APList_rid.ap[i][1],
5239 (int)APList_rid.ap[i][2],
5240 (int)APList_rid.ap[i][3],
5241 (int)APList_rid.ap[i][4],
5242 (int)APList_rid.ap[i][5]);
5243 }
5244 if (i==0) ptr += sprintf(ptr, "Not using specific APs\n");
5245
5246 *ptr = '\0';
5247 data->readlen = strlen( data->rbuffer );
5248 return 0;
5249}
5250
5251static int proc_BSSList_open( struct inode *inode, struct file *file ) {
5252 struct proc_data *data;
5253 struct proc_dir_entry *dp = PDE(inode);
5254 struct net_device *dev = dp->data;
5255 struct airo_info *ai = dev->priv;
5256 char *ptr;
5257 BSSListRid BSSList_rid;
5258 int rc;
5259 /* If doLoseSync is not 1, we won't do a Lose Sync */
5260 int doLoseSync = -1;
5261
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005262 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264 data = (struct proc_data *)file->private_data;
5265 if ((data->rbuffer = kmalloc( 1024, GFP_KERNEL )) == NULL) {
5266 kfree (file->private_data);
5267 return -ENOMEM;
5268 }
5269 data->writelen = 0;
5270 data->maxwritelen = 0;
5271 data->wbuffer = NULL;
5272 data->on_close = NULL;
5273
5274 if (file->f_mode & FMODE_WRITE) {
5275 if (!(file->f_mode & FMODE_READ)) {
5276 Cmd cmd;
5277 Resp rsp;
5278
5279 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
5280 memset(&cmd, 0, sizeof(cmd));
5281 cmd.cmd=CMD_LISTBSS;
5282 if (down_interruptible(&ai->sem))
5283 return -ERESTARTSYS;
5284 issuecommand(ai, &cmd, &rsp);
5285 up(&ai->sem);
5286 data->readlen = 0;
5287 return 0;
5288 }
5289 doLoseSync = 1;
5290 }
5291 ptr = data->rbuffer;
5292 /* There is a race condition here if there are concurrent opens.
5293 Since it is a rare condition, we'll just live with it, otherwise
5294 we have to add a spin lock... */
5295 rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
5296 while(rc == 0 && BSSList_rid.index != 0xffff) {
5297 ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x %*s rssi = %d",
5298 (int)BSSList_rid.bssid[0],
5299 (int)BSSList_rid.bssid[1],
5300 (int)BSSList_rid.bssid[2],
5301 (int)BSSList_rid.bssid[3],
5302 (int)BSSList_rid.bssid[4],
5303 (int)BSSList_rid.bssid[5],
5304 (int)BSSList_rid.ssidLen,
5305 BSSList_rid.ssid,
Dan Williams41480af2005-05-10 09:45:51 -04005306 (int)BSSList_rid.dBm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307 ptr += sprintf(ptr, " channel = %d %s %s %s %s\n",
5308 (int)BSSList_rid.dsChannel,
5309 BSSList_rid.cap & CAP_ESS ? "ESS" : "",
5310 BSSList_rid.cap & CAP_IBSS ? "adhoc" : "",
5311 BSSList_rid.cap & CAP_PRIVACY ? "wep" : "",
5312 BSSList_rid.cap & CAP_SHORTHDR ? "shorthdr" : "");
5313 rc = readBSSListRid(ai, 0, &BSSList_rid);
5314 }
5315 *ptr = '\0';
5316 data->readlen = strlen( data->rbuffer );
5317 return 0;
5318}
5319
5320static int proc_close( struct inode *inode, struct file *file )
5321{
Jesper Juhlb4558ea2005-10-28 16:53:13 -04005322 struct proc_data *data = file->private_data;
5323
5324 if (data->on_close != NULL)
5325 data->on_close(inode, file);
5326 kfree(data->rbuffer);
5327 kfree(data->wbuffer);
5328 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329 return 0;
5330}
5331
5332static struct net_device_list {
5333 struct net_device *dev;
5334 struct net_device_list *next;
5335} *airo_devices;
5336
5337/* Since the card doesn't automatically switch to the right WEP mode,
5338 we will make it do it. If the card isn't associated, every secs we
5339 will switch WEP modes to see if that will help. If the card is
5340 associated we will check every minute to see if anything has
5341 changed. */
5342static void timer_func( struct net_device *dev ) {
5343 struct airo_info *apriv = dev->priv;
5344 Resp rsp;
5345
5346/* We don't have a link so try changing the authtype */
5347 readConfigRid(apriv, 0);
5348 disable_MAC(apriv, 0);
5349 switch(apriv->config.authType) {
5350 case AUTH_ENCRYPT:
5351/* So drop to OPEN */
5352 apriv->config.authType = AUTH_OPEN;
5353 break;
5354 case AUTH_SHAREDKEY:
5355 if (apriv->keyindex < auto_wep) {
5356 set_wep_key(apriv, apriv->keyindex, NULL, 0, 0, 0);
5357 apriv->config.authType = AUTH_SHAREDKEY;
5358 apriv->keyindex++;
5359 } else {
5360 /* Drop to ENCRYPT */
5361 apriv->keyindex = 0;
5362 set_wep_key(apriv, apriv->defindex, NULL, 0, 0, 0);
5363 apriv->config.authType = AUTH_ENCRYPT;
5364 }
5365 break;
5366 default: /* We'll escalate to SHAREDKEY */
5367 apriv->config.authType = AUTH_SHAREDKEY;
5368 }
5369 set_bit (FLAG_COMMIT, &apriv->flags);
5370 writeConfigRid(apriv, 0);
5371 enable_MAC(apriv, &rsp, 0);
5372 up(&apriv->sem);
5373
5374/* Schedule check to see if the change worked */
5375 clear_bit(JOB_AUTOWEP, &apriv->flags);
5376 apriv->expires = RUN_AT(HZ*3);
5377}
5378
5379static int add_airo_dev( struct net_device *dev ) {
5380 struct net_device_list *node = kmalloc( sizeof( *node ), GFP_KERNEL );
5381 if ( !node )
5382 return -ENOMEM;
5383
5384 node->dev = dev;
5385 node->next = airo_devices;
5386 airo_devices = node;
5387
5388 return 0;
5389}
5390
5391static void del_airo_dev( struct net_device *dev ) {
5392 struct net_device_list **p = &airo_devices;
5393 while( *p && ( (*p)->dev != dev ) )
5394 p = &(*p)->next;
5395 if ( *p && (*p)->dev == dev )
5396 *p = (*p)->next;
5397}
5398
5399#ifdef CONFIG_PCI
5400static int __devinit airo_pci_probe(struct pci_dev *pdev,
5401 const struct pci_device_id *pent)
5402{
5403 struct net_device *dev;
5404
5405 if (pci_enable_device(pdev))
5406 return -ENODEV;
5407 pci_set_master(pdev);
5408
5409 if (pdev->device == 0x5000 || pdev->device == 0xa504)
5410 dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev);
5411 else
5412 dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev);
5413 if (!dev)
5414 return -ENODEV;
5415
5416 pci_set_drvdata(pdev, dev);
5417 return 0;
5418}
5419
5420static void __devexit airo_pci_remove(struct pci_dev *pdev)
5421{
5422}
5423
Pavel Machek05adc3b2005-04-16 15:25:25 -07005424static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425{
5426 struct net_device *dev = pci_get_drvdata(pdev);
5427 struct airo_info *ai = dev->priv;
5428 Cmd cmd;
5429 Resp rsp;
5430
5431 if ((ai->APList == NULL) &&
5432 (ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL)) == NULL)
5433 return -ENOMEM;
5434 if ((ai->SSID == NULL) &&
5435 (ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL)) == NULL)
5436 return -ENOMEM;
5437 readAPListRid(ai, ai->APList);
5438 readSsidRid(ai, ai->SSID);
5439 memset(&cmd, 0, sizeof(cmd));
5440 /* the lock will be released at the end of the resume callback */
5441 if (down_interruptible(&ai->sem))
5442 return -EAGAIN;
5443 disable_MAC(ai, 0);
5444 netif_device_detach(dev);
5445 ai->power = state;
5446 cmd.cmd=HOSTSLEEP;
5447 issuecommand(ai, &cmd, &rsp);
5448
Pavel Machek1cc68ae2005-06-20 15:33:04 -07005449 pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 pci_save_state(pdev);
Pavel Machek1cc68ae2005-06-20 15:33:04 -07005451 return pci_set_power_state(pdev, pci_choose_state(pdev, state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452}
5453
5454static int airo_pci_resume(struct pci_dev *pdev)
5455{
5456 struct net_device *dev = pci_get_drvdata(pdev);
5457 struct airo_info *ai = dev->priv;
5458 Resp rsp;
Michal Schmidt53232802005-10-04 07:46:21 -04005459 pci_power_t prev_state = pdev->current_state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460
Michal Schmidt53232802005-10-04 07:46:21 -04005461 pci_set_power_state(pdev, PCI_D0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 pci_restore_state(pdev);
Michal Schmidt53232802005-10-04 07:46:21 -04005463 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464
Michal Schmidt53232802005-10-04 07:46:21 -04005465 if (prev_state != PCI_D1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466 reset_card(dev, 0);
5467 mpi_init_descriptors(ai);
5468 setup_card(ai, dev->dev_addr, 0);
5469 clear_bit(FLAG_RADIO_OFF, &ai->flags);
5470 clear_bit(FLAG_PENDING_XMIT, &ai->flags);
5471 } else {
5472 OUT4500(ai, EVACK, EV_AWAKEN);
5473 OUT4500(ai, EVACK, EV_AWAKEN);
5474 msleep(100);
5475 }
5476
5477 set_bit (FLAG_COMMIT, &ai->flags);
5478 disable_MAC(ai, 0);
5479 msleep(200);
5480 if (ai->SSID) {
5481 writeSsidRid(ai, ai->SSID, 0);
5482 kfree(ai->SSID);
5483 ai->SSID = NULL;
5484 }
5485 if (ai->APList) {
5486 writeAPListRid(ai, ai->APList, 0);
5487 kfree(ai->APList);
5488 ai->APList = NULL;
5489 }
5490 writeConfigRid(ai, 0);
5491 enable_MAC(ai, &rsp, 0);
Pavel Machek1cc68ae2005-06-20 15:33:04 -07005492 ai->power = PMSG_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493 netif_device_attach(dev);
5494 netif_wake_queue(dev);
5495 enable_interrupts(ai);
5496 up(&ai->sem);
5497 return 0;
5498}
5499#endif
5500
5501static int __init airo_init_module( void )
5502{
5503 int i, have_isa_dev = 0;
5504
5505 airo_entry = create_proc_entry("aironet",
5506 S_IFDIR | airo_perm,
5507 proc_root_driver);
5508 airo_entry->uid = proc_uid;
5509 airo_entry->gid = proc_gid;
5510
5511 for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05005512 airo_print_info("", "Trying to configure ISA adapter at irq=%d "
5513 "io=0x%x", irq[i], io[i] );
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 if (init_airo_card( irq[i], io[i], 0, NULL ))
5515 have_isa_dev = 1;
5516 }
5517
5518#ifdef CONFIG_PCI
Dan Williams934d8bf2006-03-16 13:46:23 -05005519 airo_print_info("", "Probing for PCI adapters");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 pci_register_driver(&airo_driver);
Dan Williams934d8bf2006-03-16 13:46:23 -05005521 airo_print_info("", "Finished probing for PCI adapters");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522#endif
5523
5524 /* Always exit with success, as we are a library module
5525 * as well as a driver module
5526 */
5527 return 0;
5528}
5529
5530static void __exit airo_cleanup_module( void )
5531{
5532 while( airo_devices ) {
Dan Williams934d8bf2006-03-16 13:46:23 -05005533 airo_print_info(airo_devices->dev->name, "Unregistering...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 stop_airo_card( airo_devices->dev, 1 );
5535 }
5536#ifdef CONFIG_PCI
5537 pci_unregister_driver(&airo_driver);
5538#endif
5539 remove_proc_entry("aironet", proc_root_driver);
5540}
5541
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542/*
5543 * Initial Wireless Extension code for Aironet driver by :
5544 * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 17 November 00
5545 * Conversion to new driver API by :
5546 * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 26 March 02
5547 * Javier also did a good amount of work here, adding some new extensions
5548 * and fixing my code. Let's just say that without him this code just
5549 * would not work at all... - Jean II
5550 */
5551
Dan Williams41480af2005-05-10 09:45:51 -04005552static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi)
5553{
5554 if( !rssi_rid )
5555 return 0;
5556
5557 return (0x100 - rssi_rid[rssi].rssidBm);
5558}
5559
5560static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
5561{
5562 int i;
5563
5564 if( !rssi_rid )
5565 return 0;
5566
5567 for( i = 0; i < 256; i++ )
5568 if (rssi_rid[i].rssidBm == dbm)
5569 return rssi_rid[i].rssipct;
5570
5571 return 0;
5572}
5573
5574
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid)
5576{
5577 int quality = 0;
5578
5579 if ((status_rid->mode & 0x3f) == 0x3f && (cap_rid->hardCap & 8)) {
5580 if (memcmp(cap_rid->prodName, "350", 3))
5581 if (status_rid->signalQuality > 0x20)
5582 quality = 0;
5583 else
5584 quality = 0x20 - status_rid->signalQuality;
5585 else
5586 if (status_rid->signalQuality > 0xb0)
5587 quality = 0;
5588 else if (status_rid->signalQuality < 0x10)
5589 quality = 0xa0;
5590 else
5591 quality = 0xb0 - status_rid->signalQuality;
5592 }
5593 return quality;
5594}
5595
5596#define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0)
5597#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50);
5598
5599/*------------------------------------------------------------------*/
5600/*
5601 * Wireless Handler : get protocol name
5602 */
5603static int airo_get_name(struct net_device *dev,
5604 struct iw_request_info *info,
5605 char *cwrq,
5606 char *extra)
5607{
5608 strcpy(cwrq, "IEEE 802.11-DS");
5609 return 0;
5610}
5611
5612/*------------------------------------------------------------------*/
5613/*
5614 * Wireless Handler : set frequency
5615 */
5616static int airo_set_freq(struct net_device *dev,
5617 struct iw_request_info *info,
5618 struct iw_freq *fwrq,
5619 char *extra)
5620{
5621 struct airo_info *local = dev->priv;
5622 int rc = -EINPROGRESS; /* Call commit handler */
5623
5624 /* If setting by frequency, convert to a channel */
5625 if((fwrq->e == 1) &&
5626 (fwrq->m >= (int) 2.412e8) &&
5627 (fwrq->m <= (int) 2.487e8)) {
5628 int f = fwrq->m / 100000;
5629 int c = 0;
5630 while((c < 14) && (f != frequency_list[c]))
5631 c++;
5632 /* Hack to fall through... */
5633 fwrq->e = 0;
5634 fwrq->m = c + 1;
5635 }
5636 /* Setting by channel number */
5637 if((fwrq->m > 1000) || (fwrq->e > 0))
5638 rc = -EOPNOTSUPP;
5639 else {
5640 int channel = fwrq->m;
5641 /* We should do a better check than that,
5642 * based on the card capability !!! */
Javier Achirica2610c732006-01-17 08:01:01 -05005643 if((channel < 1) || (channel > 14)) {
Dan Williams934d8bf2006-03-16 13:46:23 -05005644 airo_print_dbg(dev->name, "New channel value of %d is invalid!",
5645 fwrq->m);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646 rc = -EINVAL;
5647 } else {
5648 readConfigRid(local, 1);
5649 /* Yes ! We can set it !!! */
Javier Achirica2610c732006-01-17 08:01:01 -05005650 local->config.channelSet = (u16) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 set_bit (FLAG_COMMIT, &local->flags);
5652 }
5653 }
5654 return rc;
5655}
5656
5657/*------------------------------------------------------------------*/
5658/*
5659 * Wireless Handler : get frequency
5660 */
5661static int airo_get_freq(struct net_device *dev,
5662 struct iw_request_info *info,
5663 struct iw_freq *fwrq,
5664 char *extra)
5665{
5666 struct airo_info *local = dev->priv;
5667 StatusRid status_rid; /* Card status info */
Javier Achirica2610c732006-01-17 08:01:01 -05005668 int ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669
5670 readConfigRid(local, 1);
5671 if ((local->config.opmode & 0xFF) == MODE_STA_ESS)
5672 status_rid.channel = local->config.channelSet;
5673 else
5674 readStatusRid(local, &status_rid, 1);
5675
Javier Achirica2610c732006-01-17 08:01:01 -05005676 ch = (int)status_rid.channel;
5677 if((ch > 0) && (ch < 15)) {
5678 fwrq->m = frequency_list[ch - 1] * 100000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679 fwrq->e = 1;
Javier Achirica2610c732006-01-17 08:01:01 -05005680 } else {
5681 fwrq->m = ch;
5682 fwrq->e = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684
5685 return 0;
5686}
5687
5688/*------------------------------------------------------------------*/
5689/*
5690 * Wireless Handler : set ESSID
5691 */
5692static int airo_set_essid(struct net_device *dev,
5693 struct iw_request_info *info,
5694 struct iw_point *dwrq,
5695 char *extra)
5696{
5697 struct airo_info *local = dev->priv;
5698 Resp rsp;
5699 SsidRid SSID_rid; /* SSIDs */
5700
5701 /* Reload the list of current SSID */
5702 readSsidRid(local, &SSID_rid);
5703
5704 /* Check if we asked for `any' */
5705 if(dwrq->flags == 0) {
5706 /* Just send an empty SSID list */
5707 memset(&SSID_rid, 0, sizeof(SSID_rid));
5708 } else {
5709 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
5710
5711 /* Check the size of the string */
5712 if(dwrq->length > IW_ESSID_MAX_SIZE+1) {
5713 return -E2BIG ;
5714 }
5715 /* Check if index is valid */
5716 if((index < 0) || (index >= 4)) {
5717 return -EINVAL;
5718 }
5719
5720 /* Set the SSID */
5721 memset(SSID_rid.ssids[index].ssid, 0,
5722 sizeof(SSID_rid.ssids[index].ssid));
5723 memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
5724 SSID_rid.ssids[index].len = dwrq->length - 1;
5725 }
5726 SSID_rid.len = sizeof(SSID_rid);
5727 /* Write it to the card */
5728 disable_MAC(local, 1);
5729 writeSsidRid(local, &SSID_rid, 1);
5730 enable_MAC(local, &rsp, 1);
5731
5732 return 0;
5733}
5734
5735/*------------------------------------------------------------------*/
5736/*
5737 * Wireless Handler : get ESSID
5738 */
5739static int airo_get_essid(struct net_device *dev,
5740 struct iw_request_info *info,
5741 struct iw_point *dwrq,
5742 char *extra)
5743{
5744 struct airo_info *local = dev->priv;
5745 StatusRid status_rid; /* Card status info */
5746
5747 readStatusRid(local, &status_rid, 1);
5748
5749 /* Note : if dwrq->flags != 0, we should
5750 * get the relevant SSID from the SSID list... */
5751
5752 /* Get the current SSID */
5753 memcpy(extra, status_rid.SSID, status_rid.SSIDlen);
5754 extra[status_rid.SSIDlen] = '\0';
5755 /* If none, we may want to get the one that was set */
5756
5757 /* Push it out ! */
Dan Williamsd6a13a22006-01-12 15:00:58 -05005758 dwrq->length = status_rid.SSIDlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759 dwrq->flags = 1; /* active */
5760
5761 return 0;
5762}
5763
5764/*------------------------------------------------------------------*/
5765/*
5766 * Wireless Handler : set AP address
5767 */
5768static int airo_set_wap(struct net_device *dev,
5769 struct iw_request_info *info,
5770 struct sockaddr *awrq,
5771 char *extra)
5772{
5773 struct airo_info *local = dev->priv;
5774 Cmd cmd;
5775 Resp rsp;
5776 APListRid APList_rid;
Dan Williams4be757d2006-01-30 11:58:00 -05005777 static const u8 any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
5778 static const u8 off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779
5780 if (awrq->sa_family != ARPHRD_ETHER)
5781 return -EINVAL;
Dan Williams4be757d2006-01-30 11:58:00 -05005782 else if (!memcmp(any, awrq->sa_data, ETH_ALEN) ||
5783 !memcmp(off, awrq->sa_data, ETH_ALEN)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784 memset(&cmd, 0, sizeof(cmd));
5785 cmd.cmd=CMD_LOSE_SYNC;
5786 if (down_interruptible(&local->sem))
5787 return -ERESTARTSYS;
5788 issuecommand(local, &cmd, &rsp);
5789 up(&local->sem);
5790 } else {
5791 memset(&APList_rid, 0, sizeof(APList_rid));
5792 APList_rid.len = sizeof(APList_rid);
5793 memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN);
5794 disable_MAC(local, 1);
5795 writeAPListRid(local, &APList_rid, 1);
5796 enable_MAC(local, &rsp, 1);
5797 }
5798 return 0;
5799}
5800
5801/*------------------------------------------------------------------*/
5802/*
5803 * Wireless Handler : get AP address
5804 */
5805static int airo_get_wap(struct net_device *dev,
5806 struct iw_request_info *info,
5807 struct sockaddr *awrq,
5808 char *extra)
5809{
5810 struct airo_info *local = dev->priv;
5811 StatusRid status_rid; /* Card status info */
5812
5813 readStatusRid(local, &status_rid, 1);
5814
5815 /* Tentative. This seems to work, wow, I'm lucky !!! */
5816 memcpy(awrq->sa_data, status_rid.bssid[0], ETH_ALEN);
5817 awrq->sa_family = ARPHRD_ETHER;
5818
5819 return 0;
5820}
5821
5822/*------------------------------------------------------------------*/
5823/*
5824 * Wireless Handler : set Nickname
5825 */
5826static int airo_set_nick(struct net_device *dev,
5827 struct iw_request_info *info,
5828 struct iw_point *dwrq,
5829 char *extra)
5830{
5831 struct airo_info *local = dev->priv;
5832
5833 /* Check the size of the string */
5834 if(dwrq->length > 16 + 1) {
5835 return -E2BIG;
5836 }
5837 readConfigRid(local, 1);
5838 memset(local->config.nodeName, 0, sizeof(local->config.nodeName));
5839 memcpy(local->config.nodeName, extra, dwrq->length);
5840 set_bit (FLAG_COMMIT, &local->flags);
5841
5842 return -EINPROGRESS; /* Call commit handler */
5843}
5844
5845/*------------------------------------------------------------------*/
5846/*
5847 * Wireless Handler : get Nickname
5848 */
5849static int airo_get_nick(struct net_device *dev,
5850 struct iw_request_info *info,
5851 struct iw_point *dwrq,
5852 char *extra)
5853{
5854 struct airo_info *local = dev->priv;
5855
5856 readConfigRid(local, 1);
5857 strncpy(extra, local->config.nodeName, 16);
5858 extra[16] = '\0';
5859 dwrq->length = strlen(extra) + 1;
5860
5861 return 0;
5862}
5863
5864/*------------------------------------------------------------------*/
5865/*
5866 * Wireless Handler : set Bit-Rate
5867 */
5868static int airo_set_rate(struct net_device *dev,
5869 struct iw_request_info *info,
5870 struct iw_param *vwrq,
5871 char *extra)
5872{
5873 struct airo_info *local = dev->priv;
5874 CapabilityRid cap_rid; /* Card capability info */
5875 u8 brate = 0;
5876 int i;
5877
5878 /* First : get a valid bit rate value */
5879 readCapabilityRid(local, &cap_rid, 1);
5880
5881 /* Which type of value ? */
5882 if((vwrq->value < 8) && (vwrq->value >= 0)) {
5883 /* Setting by rate index */
5884 /* Find value in the magic rate table */
5885 brate = cap_rid.supportedRates[vwrq->value];
5886 } else {
5887 /* Setting by frequency value */
5888 u8 normvalue = (u8) (vwrq->value/500000);
5889
5890 /* Check if rate is valid */
5891 for(i = 0 ; i < 8 ; i++) {
5892 if(normvalue == cap_rid.supportedRates[i]) {
5893 brate = normvalue;
5894 break;
5895 }
5896 }
5897 }
5898 /* -1 designed the max rate (mostly auto mode) */
5899 if(vwrq->value == -1) {
5900 /* Get the highest available rate */
5901 for(i = 0 ; i < 8 ; i++) {
5902 if(cap_rid.supportedRates[i] == 0)
5903 break;
5904 }
5905 if(i != 0)
5906 brate = cap_rid.supportedRates[i - 1];
5907 }
5908 /* Check that it is valid */
5909 if(brate == 0) {
5910 return -EINVAL;
5911 }
5912
5913 readConfigRid(local, 1);
5914 /* Now, check if we want a fixed or auto value */
5915 if(vwrq->fixed == 0) {
5916 /* Fill all the rates up to this max rate */
5917 memset(local->config.rates, 0, 8);
5918 for(i = 0 ; i < 8 ; i++) {
5919 local->config.rates[i] = cap_rid.supportedRates[i];
5920 if(local->config.rates[i] == brate)
5921 break;
5922 }
5923 } else {
5924 /* Fixed mode */
5925 /* One rate, fixed */
5926 memset(local->config.rates, 0, 8);
5927 local->config.rates[0] = brate;
5928 }
5929 set_bit (FLAG_COMMIT, &local->flags);
5930
5931 return -EINPROGRESS; /* Call commit handler */
5932}
5933
5934/*------------------------------------------------------------------*/
5935/*
5936 * Wireless Handler : get Bit-Rate
5937 */
5938static int airo_get_rate(struct net_device *dev,
5939 struct iw_request_info *info,
5940 struct iw_param *vwrq,
5941 char *extra)
5942{
5943 struct airo_info *local = dev->priv;
5944 StatusRid status_rid; /* Card status info */
5945
5946 readStatusRid(local, &status_rid, 1);
5947
5948 vwrq->value = status_rid.currentXmitRate * 500000;
5949 /* If more than one rate, set auto */
5950 readConfigRid(local, 1);
5951 vwrq->fixed = (local->config.rates[1] == 0);
5952
5953 return 0;
5954}
5955
5956/*------------------------------------------------------------------*/
5957/*
5958 * Wireless Handler : set RTS threshold
5959 */
5960static int airo_set_rts(struct net_device *dev,
5961 struct iw_request_info *info,
5962 struct iw_param *vwrq,
5963 char *extra)
5964{
5965 struct airo_info *local = dev->priv;
5966 int rthr = vwrq->value;
5967
5968 if(vwrq->disabled)
Dan Williams15db2762006-03-16 13:46:27 -05005969 rthr = AIRO_DEF_MTU;
5970 if((rthr < 0) || (rthr > AIRO_DEF_MTU)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971 return -EINVAL;
5972 }
5973 readConfigRid(local, 1);
5974 local->config.rtsThres = rthr;
5975 set_bit (FLAG_COMMIT, &local->flags);
5976
5977 return -EINPROGRESS; /* Call commit handler */
5978}
5979
5980/*------------------------------------------------------------------*/
5981/*
5982 * Wireless Handler : get RTS threshold
5983 */
5984static int airo_get_rts(struct net_device *dev,
5985 struct iw_request_info *info,
5986 struct iw_param *vwrq,
5987 char *extra)
5988{
5989 struct airo_info *local = dev->priv;
5990
5991 readConfigRid(local, 1);
5992 vwrq->value = local->config.rtsThres;
Dan Williams15db2762006-03-16 13:46:27 -05005993 vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994 vwrq->fixed = 1;
5995
5996 return 0;
5997}
5998
5999/*------------------------------------------------------------------*/
6000/*
6001 * Wireless Handler : set Fragmentation threshold
6002 */
6003static int airo_set_frag(struct net_device *dev,
6004 struct iw_request_info *info,
6005 struct iw_param *vwrq,
6006 char *extra)
6007{
6008 struct airo_info *local = dev->priv;
6009 int fthr = vwrq->value;
6010
6011 if(vwrq->disabled)
Dan Williams15db2762006-03-16 13:46:27 -05006012 fthr = AIRO_DEF_MTU;
6013 if((fthr < 256) || (fthr > AIRO_DEF_MTU)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014 return -EINVAL;
6015 }
6016 fthr &= ~0x1; /* Get an even value - is it really needed ??? */
6017 readConfigRid(local, 1);
6018 local->config.fragThresh = (u16)fthr;
6019 set_bit (FLAG_COMMIT, &local->flags);
6020
6021 return -EINPROGRESS; /* Call commit handler */
6022}
6023
6024/*------------------------------------------------------------------*/
6025/*
6026 * Wireless Handler : get Fragmentation threshold
6027 */
6028static int airo_get_frag(struct net_device *dev,
6029 struct iw_request_info *info,
6030 struct iw_param *vwrq,
6031 char *extra)
6032{
6033 struct airo_info *local = dev->priv;
6034
6035 readConfigRid(local, 1);
6036 vwrq->value = local->config.fragThresh;
Dan Williams15db2762006-03-16 13:46:27 -05006037 vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006038 vwrq->fixed = 1;
6039
6040 return 0;
6041}
6042
6043/*------------------------------------------------------------------*/
6044/*
6045 * Wireless Handler : set Mode of Operation
6046 */
6047static int airo_set_mode(struct net_device *dev,
6048 struct iw_request_info *info,
6049 __u32 *uwrq,
6050 char *extra)
6051{
6052 struct airo_info *local = dev->priv;
6053 int reset = 0;
6054
6055 readConfigRid(local, 1);
6056 if ((local->config.rmode & 0xff) >= RXMODE_RFMON)
6057 reset = 1;
6058
6059 switch(*uwrq) {
6060 case IW_MODE_ADHOC:
6061 local->config.opmode &= 0xFF00;
6062 local->config.opmode |= MODE_STA_IBSS;
6063 local->config.rmode &= 0xfe00;
6064 local->config.scanMode = SCANMODE_ACTIVE;
6065 clear_bit (FLAG_802_11, &local->flags);
6066 break;
6067 case IW_MODE_INFRA:
6068 local->config.opmode &= 0xFF00;
6069 local->config.opmode |= MODE_STA_ESS;
6070 local->config.rmode &= 0xfe00;
6071 local->config.scanMode = SCANMODE_ACTIVE;
6072 clear_bit (FLAG_802_11, &local->flags);
6073 break;
6074 case IW_MODE_MASTER:
6075 local->config.opmode &= 0xFF00;
6076 local->config.opmode |= MODE_AP;
6077 local->config.rmode &= 0xfe00;
6078 local->config.scanMode = SCANMODE_ACTIVE;
6079 clear_bit (FLAG_802_11, &local->flags);
6080 break;
6081 case IW_MODE_REPEAT:
6082 local->config.opmode &= 0xFF00;
6083 local->config.opmode |= MODE_AP_RPTR;
6084 local->config.rmode &= 0xfe00;
6085 local->config.scanMode = SCANMODE_ACTIVE;
6086 clear_bit (FLAG_802_11, &local->flags);
6087 break;
6088 case IW_MODE_MONITOR:
6089 local->config.opmode &= 0xFF00;
6090 local->config.opmode |= MODE_STA_ESS;
6091 local->config.rmode &= 0xfe00;
6092 local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
6093 local->config.scanMode = SCANMODE_PASSIVE;
6094 set_bit (FLAG_802_11, &local->flags);
6095 break;
6096 default:
6097 return -EINVAL;
6098 }
6099 if (reset)
6100 set_bit (FLAG_RESET, &local->flags);
6101 set_bit (FLAG_COMMIT, &local->flags);
6102
6103 return -EINPROGRESS; /* Call commit handler */
6104}
6105
6106/*------------------------------------------------------------------*/
6107/*
6108 * Wireless Handler : get Mode of Operation
6109 */
6110static int airo_get_mode(struct net_device *dev,
6111 struct iw_request_info *info,
6112 __u32 *uwrq,
6113 char *extra)
6114{
6115 struct airo_info *local = dev->priv;
6116
6117 readConfigRid(local, 1);
6118 /* If not managed, assume it's ad-hoc */
6119 switch (local->config.opmode & 0xFF) {
6120 case MODE_STA_ESS:
6121 *uwrq = IW_MODE_INFRA;
6122 break;
6123 case MODE_AP:
6124 *uwrq = IW_MODE_MASTER;
6125 break;
6126 case MODE_AP_RPTR:
6127 *uwrq = IW_MODE_REPEAT;
6128 break;
6129 default:
6130 *uwrq = IW_MODE_ADHOC;
6131 }
6132
6133 return 0;
6134}
6135
6136/*------------------------------------------------------------------*/
6137/*
6138 * Wireless Handler : set Encryption Key
6139 */
6140static int airo_set_encode(struct net_device *dev,
6141 struct iw_request_info *info,
6142 struct iw_point *dwrq,
6143 char *extra)
6144{
6145 struct airo_info *local = dev->priv;
6146 CapabilityRid cap_rid; /* Card capability info */
Dan Streetmanf89b2322005-11-11 11:41:42 -05006147 int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 );
6148 u16 currentAuthType = local->config.authType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006149
6150 /* Is WEP supported ? */
6151 readCapabilityRid(local, &cap_rid, 1);
6152 /* Older firmware doesn't support this...
6153 if(!(cap_rid.softCap & 2)) {
6154 return -EOPNOTSUPP;
6155 } */
6156 readConfigRid(local, 1);
6157
6158 /* Basic checking: do we have a key to set ?
6159 * Note : with the new API, it's impossible to get a NULL pointer.
6160 * Therefore, we need to check a key size == 0 instead.
6161 * New version of iwconfig properly set the IW_ENCODE_NOKEY flag
6162 * when no key is present (only change flags), but older versions
6163 * don't do it. - Jean II */
6164 if (dwrq->length > 0) {
6165 wep_key_t key;
6166 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
6167 int current_index = get_wep_key(local, 0xffff);
6168 /* Check the size of the key */
6169 if (dwrq->length > MAX_KEY_SIZE) {
6170 return -EINVAL;
6171 }
6172 /* Check the index (none -> use current) */
6173 if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4:1)))
6174 index = current_index;
6175 /* Set the length */
6176 if (dwrq->length > MIN_KEY_SIZE)
6177 key.len = MAX_KEY_SIZE;
6178 else
6179 if (dwrq->length > 0)
6180 key.len = MIN_KEY_SIZE;
6181 else
6182 /* Disable the key */
6183 key.len = 0;
6184 /* Check if the key is not marked as invalid */
6185 if(!(dwrq->flags & IW_ENCODE_NOKEY)) {
6186 /* Cleanup */
6187 memset(key.key, 0, MAX_KEY_SIZE);
6188 /* Copy the key in the driver */
6189 memcpy(key.key, extra, dwrq->length);
6190 /* Send the key to the card */
Dan Streetmanf89b2322005-11-11 11:41:42 -05006191 set_wep_key(local, index, key.key, key.len, perm, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006192 }
6193 /* WE specify that if a valid key is set, encryption
6194 * should be enabled (user may turn it off later)
6195 * This is also how "iwconfig ethX key on" works */
6196 if((index == current_index) && (key.len > 0) &&
6197 (local->config.authType == AUTH_OPEN)) {
6198 local->config.authType = AUTH_ENCRYPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006199 }
6200 } else {
6201 /* Do we want to just set the transmit key index ? */
6202 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
6203 if ((index >= 0) && (index < ((cap_rid.softCap & 0x80)?4:1))) {
Dan Streetmanf89b2322005-11-11 11:41:42 -05006204 set_wep_key(local, index, NULL, 0, perm, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006205 } else
6206 /* Don't complain if only change the mode */
6207 if(!dwrq->flags & IW_ENCODE_MODE) {
6208 return -EINVAL;
6209 }
6210 }
6211 /* Read the flags */
6212 if(dwrq->flags & IW_ENCODE_DISABLED)
6213 local->config.authType = AUTH_OPEN; // disable encryption
6214 if(dwrq->flags & IW_ENCODE_RESTRICTED)
6215 local->config.authType = AUTH_SHAREDKEY; // Only Both
6216 if(dwrq->flags & IW_ENCODE_OPEN)
6217 local->config.authType = AUTH_ENCRYPT; // Only Wep
6218 /* Commit the changes to flags if needed */
Dan Streetmanf89b2322005-11-11 11:41:42 -05006219 if (local->config.authType != currentAuthType)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220 set_bit (FLAG_COMMIT, &local->flags);
6221 return -EINPROGRESS; /* Call commit handler */
6222}
6223
6224/*------------------------------------------------------------------*/
6225/*
6226 * Wireless Handler : get Encryption Key
6227 */
6228static int airo_get_encode(struct net_device *dev,
6229 struct iw_request_info *info,
6230 struct iw_point *dwrq,
6231 char *extra)
6232{
6233 struct airo_info *local = dev->priv;
6234 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
6235 CapabilityRid cap_rid; /* Card capability info */
6236
6237 /* Is it supported ? */
6238 readCapabilityRid(local, &cap_rid, 1);
6239 if(!(cap_rid.softCap & 2)) {
6240 return -EOPNOTSUPP;
6241 }
6242 readConfigRid(local, 1);
6243 /* Check encryption mode */
6244 switch(local->config.authType) {
6245 case AUTH_ENCRYPT:
6246 dwrq->flags = IW_ENCODE_OPEN;
6247 break;
6248 case AUTH_SHAREDKEY:
6249 dwrq->flags = IW_ENCODE_RESTRICTED;
6250 break;
6251 default:
6252 case AUTH_OPEN:
6253 dwrq->flags = IW_ENCODE_DISABLED;
6254 break;
6255 }
6256 /* We can't return the key, so set the proper flag and return zero */
6257 dwrq->flags |= IW_ENCODE_NOKEY;
6258 memset(extra, 0, 16);
6259
6260 /* Which key do we want ? -1 -> tx index */
6261 if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4 : 1)))
6262 index = get_wep_key(local, 0xffff);
6263 dwrq->flags |= index + 1;
6264 /* Copy the key to the user buffer */
6265 dwrq->length = get_wep_key(local, index);
6266 if (dwrq->length > 16) {
6267 dwrq->length=0;
6268 }
6269 return 0;
6270}
6271
6272/*------------------------------------------------------------------*/
6273/*
Dan Williams4be757d2006-01-30 11:58:00 -05006274 * Wireless Handler : set extended Encryption parameters
6275 */
6276static int airo_set_encodeext(struct net_device *dev,
6277 struct iw_request_info *info,
6278 union iwreq_data *wrqu,
6279 char *extra)
6280{
6281 struct airo_info *local = dev->priv;
6282 struct iw_point *encoding = &wrqu->encoding;
6283 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
6284 CapabilityRid cap_rid; /* Card capability info */
6285 int perm = ( encoding->flags & IW_ENCODE_TEMP ? 0 : 1 );
6286 u16 currentAuthType = local->config.authType;
Dan Williams22d88462006-02-05 18:00:30 -05006287 int idx, key_len, alg = ext->alg, set_key = 1;
Dan Williams4be757d2006-01-30 11:58:00 -05006288 wep_key_t key;
6289
6290 /* Is WEP supported ? */
6291 readCapabilityRid(local, &cap_rid, 1);
6292 /* Older firmware doesn't support this...
6293 if(!(cap_rid.softCap & 2)) {
6294 return -EOPNOTSUPP;
6295 } */
6296 readConfigRid(local, 1);
6297
6298 /* Determine and validate the key index */
6299 idx = encoding->flags & IW_ENCODE_INDEX;
6300 if (idx) {
6301 if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1))
6302 return -EINVAL;
6303 idx--;
6304 } else
6305 idx = get_wep_key(local, 0xffff);
6306
6307 if (encoding->flags & IW_ENCODE_DISABLED)
6308 alg = IW_ENCODE_ALG_NONE;
6309
Dan Williams4be757d2006-01-30 11:58:00 -05006310 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
Dan Williams22d88462006-02-05 18:00:30 -05006311 /* Only set transmit key index here, actual
6312 * key is set below if needed.
6313 */
Dan Williams4be757d2006-01-30 11:58:00 -05006314 set_wep_key(local, idx, NULL, 0, perm, 1);
Dan Williams22d88462006-02-05 18:00:30 -05006315 set_key = ext->key_len > 0 ? 1 : 0;
6316 }
6317
6318 if (set_key) {
Dan Williams4be757d2006-01-30 11:58:00 -05006319 /* Set the requested key first */
6320 memset(key.key, 0, MAX_KEY_SIZE);
6321 switch (alg) {
6322 case IW_ENCODE_ALG_NONE:
6323 key.len = 0;
6324 break;
6325 case IW_ENCODE_ALG_WEP:
6326 if (ext->key_len > MIN_KEY_SIZE) {
6327 key.len = MAX_KEY_SIZE;
6328 } else if (ext->key_len > 0) {
6329 key.len = MIN_KEY_SIZE;
6330 } else {
6331 return -EINVAL;
6332 }
6333 key_len = min (ext->key_len, key.len);
6334 memcpy(key.key, ext->key, key_len);
6335 break;
6336 default:
6337 return -EINVAL;
6338 }
6339 /* Send the key to the card */
6340 set_wep_key(local, idx, key.key, key.len, perm, 1);
6341 }
6342
6343 /* Read the flags */
6344 if(encoding->flags & IW_ENCODE_DISABLED)
6345 local->config.authType = AUTH_OPEN; // disable encryption
6346 if(encoding->flags & IW_ENCODE_RESTRICTED)
6347 local->config.authType = AUTH_SHAREDKEY; // Only Both
6348 if(encoding->flags & IW_ENCODE_OPEN)
6349 local->config.authType = AUTH_ENCRYPT; // Only Wep
6350 /* Commit the changes to flags if needed */
6351 if (local->config.authType != currentAuthType)
6352 set_bit (FLAG_COMMIT, &local->flags);
6353
6354 return -EINPROGRESS;
6355}
6356
6357
6358/*------------------------------------------------------------------*/
6359/*
6360 * Wireless Handler : get extended Encryption parameters
6361 */
6362static int airo_get_encodeext(struct net_device *dev,
6363 struct iw_request_info *info,
6364 union iwreq_data *wrqu,
6365 char *extra)
6366{
6367 struct airo_info *local = dev->priv;
6368 struct iw_point *encoding = &wrqu->encoding;
6369 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
6370 CapabilityRid cap_rid; /* Card capability info */
6371 int idx, max_key_len;
6372
6373 /* Is it supported ? */
6374 readCapabilityRid(local, &cap_rid, 1);
6375 if(!(cap_rid.softCap & 2)) {
6376 return -EOPNOTSUPP;
6377 }
6378 readConfigRid(local, 1);
6379
6380 max_key_len = encoding->length - sizeof(*ext);
6381 if (max_key_len < 0)
6382 return -EINVAL;
6383
6384 idx = encoding->flags & IW_ENCODE_INDEX;
6385 if (idx) {
6386 if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1))
6387 return -EINVAL;
6388 idx--;
6389 } else
6390 idx = get_wep_key(local, 0xffff);
6391
6392 encoding->flags = idx + 1;
6393 memset(ext, 0, sizeof(*ext));
6394
6395 /* Check encryption mode */
6396 switch(local->config.authType) {
6397 case AUTH_ENCRYPT:
6398 encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
6399 break;
6400 case AUTH_SHAREDKEY:
6401 encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
6402 break;
6403 default:
6404 case AUTH_OPEN:
6405 encoding->flags = IW_ENCODE_ALG_NONE | IW_ENCODE_DISABLED;
6406 break;
6407 }
6408 /* We can't return the key, so set the proper flag and return zero */
6409 encoding->flags |= IW_ENCODE_NOKEY;
6410 memset(extra, 0, 16);
6411
6412 /* Copy the key to the user buffer */
6413 ext->key_len = get_wep_key(local, idx);
6414 if (ext->key_len > 16) {
6415 ext->key_len=0;
6416 }
6417
6418 return 0;
6419}
6420
6421
6422/*------------------------------------------------------------------*/
6423/*
6424 * Wireless Handler : set extended authentication parameters
6425 */
6426static int airo_set_auth(struct net_device *dev,
6427 struct iw_request_info *info,
6428 union iwreq_data *wrqu, char *extra)
6429{
6430 struct airo_info *local = dev->priv;
6431 struct iw_param *param = &wrqu->param;
6432 u16 currentAuthType = local->config.authType;
6433
6434 switch (param->flags & IW_AUTH_INDEX) {
6435 case IW_AUTH_WPA_VERSION:
6436 case IW_AUTH_CIPHER_PAIRWISE:
6437 case IW_AUTH_CIPHER_GROUP:
6438 case IW_AUTH_KEY_MGMT:
6439 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
6440 case IW_AUTH_PRIVACY_INVOKED:
6441 /*
6442 * airo does not use these parameters
6443 */
6444 break;
6445
6446 case IW_AUTH_DROP_UNENCRYPTED:
6447 if (param->value) {
6448 /* Only change auth type if unencrypted */
6449 if (currentAuthType == AUTH_OPEN)
6450 local->config.authType = AUTH_ENCRYPT;
6451 } else {
6452 local->config.authType = AUTH_OPEN;
6453 }
6454
6455 /* Commit the changes to flags if needed */
6456 if (local->config.authType != currentAuthType)
6457 set_bit (FLAG_COMMIT, &local->flags);
6458 break;
6459
6460 case IW_AUTH_80211_AUTH_ALG: {
6461 /* FIXME: What about AUTH_OPEN? This API seems to
6462 * disallow setting our auth to AUTH_OPEN.
6463 */
6464 if (param->value & IW_AUTH_ALG_SHARED_KEY) {
6465 local->config.authType = AUTH_SHAREDKEY;
6466 } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
6467 local->config.authType = AUTH_ENCRYPT;
6468 } else
6469 return -EINVAL;
6470 break;
6471
6472 /* Commit the changes to flags if needed */
6473 if (local->config.authType != currentAuthType)
6474 set_bit (FLAG_COMMIT, &local->flags);
6475 }
6476
6477 case IW_AUTH_WPA_ENABLED:
6478 /* Silently accept disable of WPA */
6479 if (param->value > 0)
6480 return -EOPNOTSUPP;
6481 break;
6482
6483 default:
6484 return -EOPNOTSUPP;
6485 }
6486 return -EINPROGRESS;
6487}
6488
6489
6490/*------------------------------------------------------------------*/
6491/*
6492 * Wireless Handler : get extended authentication parameters
6493 */
6494static int airo_get_auth(struct net_device *dev,
6495 struct iw_request_info *info,
6496 union iwreq_data *wrqu, char *extra)
6497{
6498 struct airo_info *local = dev->priv;
6499 struct iw_param *param = &wrqu->param;
6500 u16 currentAuthType = local->config.authType;
6501
6502 switch (param->flags & IW_AUTH_INDEX) {
6503 case IW_AUTH_DROP_UNENCRYPTED:
6504 switch (currentAuthType) {
6505 case AUTH_SHAREDKEY:
6506 case AUTH_ENCRYPT:
6507 param->value = 1;
6508 break;
6509 default:
6510 param->value = 0;
6511 break;
6512 }
6513 break;
6514
6515 case IW_AUTH_80211_AUTH_ALG:
6516 switch (currentAuthType) {
6517 case AUTH_SHAREDKEY:
6518 param->value = IW_AUTH_ALG_SHARED_KEY;
6519 break;
6520 case AUTH_ENCRYPT:
6521 default:
6522 param->value = IW_AUTH_ALG_OPEN_SYSTEM;
6523 break;
6524 }
6525 break;
6526
6527 case IW_AUTH_WPA_ENABLED:
6528 param->value = 0;
6529 break;
6530
6531 default:
6532 return -EOPNOTSUPP;
6533 }
6534 return 0;
6535}
6536
6537
6538/*------------------------------------------------------------------*/
6539/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006540 * Wireless Handler : set Tx-Power
6541 */
6542static int airo_set_txpow(struct net_device *dev,
6543 struct iw_request_info *info,
6544 struct iw_param *vwrq,
6545 char *extra)
6546{
6547 struct airo_info *local = dev->priv;
6548 CapabilityRid cap_rid; /* Card capability info */
6549 int i;
6550 int rc = -EINVAL;
6551
6552 readCapabilityRid(local, &cap_rid, 1);
6553
6554 if (vwrq->disabled) {
6555 set_bit (FLAG_RADIO_OFF, &local->flags);
6556 set_bit (FLAG_COMMIT, &local->flags);
6557 return -EINPROGRESS; /* Call commit handler */
6558 }
6559 if (vwrq->flags != IW_TXPOW_MWATT) {
6560 return -EINVAL;
6561 }
6562 clear_bit (FLAG_RADIO_OFF, &local->flags);
6563 for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
6564 if ((vwrq->value==cap_rid.txPowerLevels[i])) {
6565 readConfigRid(local, 1);
6566 local->config.txPower = vwrq->value;
6567 set_bit (FLAG_COMMIT, &local->flags);
6568 rc = -EINPROGRESS; /* Call commit handler */
6569 break;
6570 }
6571 return rc;
6572}
6573
6574/*------------------------------------------------------------------*/
6575/*
6576 * Wireless Handler : get Tx-Power
6577 */
6578static int airo_get_txpow(struct net_device *dev,
6579 struct iw_request_info *info,
6580 struct iw_param *vwrq,
6581 char *extra)
6582{
6583 struct airo_info *local = dev->priv;
6584
6585 readConfigRid(local, 1);
6586 vwrq->value = local->config.txPower;
6587 vwrq->fixed = 1; /* No power control */
6588 vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags);
6589 vwrq->flags = IW_TXPOW_MWATT;
6590
6591 return 0;
6592}
6593
6594/*------------------------------------------------------------------*/
6595/*
6596 * Wireless Handler : set Retry limits
6597 */
6598static int airo_set_retry(struct net_device *dev,
6599 struct iw_request_info *info,
6600 struct iw_param *vwrq,
6601 char *extra)
6602{
6603 struct airo_info *local = dev->priv;
6604 int rc = -EINVAL;
6605
6606 if(vwrq->disabled) {
6607 return -EINVAL;
6608 }
6609 readConfigRid(local, 1);
6610 if(vwrq->flags & IW_RETRY_LIMIT) {
6611 if(vwrq->flags & IW_RETRY_MAX)
6612 local->config.longRetryLimit = vwrq->value;
6613 else if (vwrq->flags & IW_RETRY_MIN)
6614 local->config.shortRetryLimit = vwrq->value;
6615 else {
6616 /* No modifier : set both */
6617 local->config.longRetryLimit = vwrq->value;
6618 local->config.shortRetryLimit = vwrq->value;
6619 }
6620 set_bit (FLAG_COMMIT, &local->flags);
6621 rc = -EINPROGRESS; /* Call commit handler */
6622 }
6623 if(vwrq->flags & IW_RETRY_LIFETIME) {
6624 local->config.txLifetime = vwrq->value / 1024;
6625 set_bit (FLAG_COMMIT, &local->flags);
6626 rc = -EINPROGRESS; /* Call commit handler */
6627 }
6628 return rc;
6629}
6630
6631/*------------------------------------------------------------------*/
6632/*
6633 * Wireless Handler : get Retry limits
6634 */
6635static int airo_get_retry(struct net_device *dev,
6636 struct iw_request_info *info,
6637 struct iw_param *vwrq,
6638 char *extra)
6639{
6640 struct airo_info *local = dev->priv;
6641
6642 vwrq->disabled = 0; /* Can't be disabled */
6643
6644 readConfigRid(local, 1);
6645 /* Note : by default, display the min retry number */
6646 if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
6647 vwrq->flags = IW_RETRY_LIFETIME;
6648 vwrq->value = (int)local->config.txLifetime * 1024;
6649 } else if((vwrq->flags & IW_RETRY_MAX)) {
6650 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
6651 vwrq->value = (int)local->config.longRetryLimit;
6652 } else {
6653 vwrq->flags = IW_RETRY_LIMIT;
6654 vwrq->value = (int)local->config.shortRetryLimit;
6655 if((int)local->config.shortRetryLimit != (int)local->config.longRetryLimit)
6656 vwrq->flags |= IW_RETRY_MIN;
6657 }
6658
6659 return 0;
6660}
6661
6662/*------------------------------------------------------------------*/
6663/*
6664 * Wireless Handler : get range info
6665 */
6666static int airo_get_range(struct net_device *dev,
6667 struct iw_request_info *info,
6668 struct iw_point *dwrq,
6669 char *extra)
6670{
6671 struct airo_info *local = dev->priv;
6672 struct iw_range *range = (struct iw_range *) extra;
6673 CapabilityRid cap_rid; /* Card capability info */
6674 int i;
6675 int k;
6676
6677 readCapabilityRid(local, &cap_rid, 1);
6678
6679 dwrq->length = sizeof(struct iw_range);
6680 memset(range, 0, sizeof(*range));
6681 range->min_nwid = 0x0000;
6682 range->max_nwid = 0x0000;
6683 range->num_channels = 14;
6684 /* Should be based on cap_rid.country to give only
6685 * what the current card support */
6686 k = 0;
6687 for(i = 0; i < 14; i++) {
6688 range->freq[k].i = i + 1; /* List index */
6689 range->freq[k].m = frequency_list[i] * 100000;
6690 range->freq[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */
6691 }
6692 range->num_frequency = k;
6693
Linus Torvalds1da177e2005-04-16 15:20:36 -07006694 range->sensitivity = 65535;
6695
Dan Williams41480af2005-05-10 09:45:51 -04006696 /* Hum... Should put the right values there */
6697 if (local->rssi)
6698 range->max_qual.qual = 100; /* % */
6699 else
6700 range->max_qual.qual = airo_get_max_quality(&cap_rid);
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006701 range->max_qual.level = 0x100 - 120; /* -120 dBm */
6702 range->max_qual.noise = 0x100 - 120; /* -120 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006703
6704 /* Experimental measurements - boundary 11/5.5 Mb/s */
6705 /* Note : with or without the (local->rssi), results
6706 * are somewhat different. - Jean II */
6707 if (local->rssi) {
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006708 range->avg_qual.qual = 50; /* % */
6709 range->avg_qual.level = 0x100 - 70; /* -70 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006710 } else {
6711 range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006712 range->avg_qual.level = 0x100 - 80; /* -80 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006713 }
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006714 range->avg_qual.noise = 0x100 - 85; /* -85 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006715
Linus Torvalds1da177e2005-04-16 15:20:36 -07006716 for(i = 0 ; i < 8 ; i++) {
6717 range->bitrate[i] = cap_rid.supportedRates[i] * 500000;
6718 if(range->bitrate[i] == 0)
6719 break;
6720 }
6721 range->num_bitrates = i;
6722
6723 /* Set an indication of the max TCP throughput
6724 * in bit/s that we can expect using this interface.
6725 * May be use for QoS stuff... Jean II */
6726 if(i > 2)
6727 range->throughput = 5000 * 1000;
6728 else
6729 range->throughput = 1500 * 1000;
6730
6731 range->min_rts = 0;
Dan Williams15db2762006-03-16 13:46:27 -05006732 range->max_rts = AIRO_DEF_MTU;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006733 range->min_frag = 256;
Dan Williams15db2762006-03-16 13:46:27 -05006734 range->max_frag = AIRO_DEF_MTU;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006735
6736 if(cap_rid.softCap & 2) {
6737 // WEP: RC4 40 bits
6738 range->encoding_size[0] = 5;
6739 // RC4 ~128 bits
6740 if (cap_rid.softCap & 0x100) {
6741 range->encoding_size[1] = 13;
6742 range->num_encoding_sizes = 2;
6743 } else
6744 range->num_encoding_sizes = 1;
6745 range->max_encoding_tokens = (cap_rid.softCap & 0x80) ? 4 : 1;
6746 } else {
6747 range->num_encoding_sizes = 0;
6748 range->max_encoding_tokens = 0;
6749 }
6750 range->min_pmp = 0;
6751 range->max_pmp = 5000000; /* 5 secs */
6752 range->min_pmt = 0;
6753 range->max_pmt = 65535 * 1024; /* ??? */
6754 range->pmp_flags = IW_POWER_PERIOD;
6755 range->pmt_flags = IW_POWER_TIMEOUT;
6756 range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
6757
6758 /* Transmit Power - values are in mW */
6759 for(i = 0 ; i < 8 ; i++) {
6760 range->txpower[i] = cap_rid.txPowerLevels[i];
6761 if(range->txpower[i] == 0)
6762 break;
6763 }
6764 range->num_txpower = i;
6765 range->txpower_capa = IW_TXPOW_MWATT;
6766 range->we_version_source = 12;
6767 range->we_version_compiled = WIRELESS_EXT;
6768 range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
6769 range->retry_flags = IW_RETRY_LIMIT;
6770 range->r_time_flags = IW_RETRY_LIFETIME;
6771 range->min_retry = 1;
6772 range->max_retry = 65535;
6773 range->min_r_time = 1024;
6774 range->max_r_time = 65535 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006775
6776 /* Event capability (kernel + driver) */
6777 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
6778 IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
6779 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
6780 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
6781 range->event_capa[1] = IW_EVENT_CAPA_K_1;
6782 range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVTXDROP);
6783 return 0;
6784}
6785
6786/*------------------------------------------------------------------*/
6787/*
6788 * Wireless Handler : set Power Management
6789 */
6790static int airo_set_power(struct net_device *dev,
6791 struct iw_request_info *info,
6792 struct iw_param *vwrq,
6793 char *extra)
6794{
6795 struct airo_info *local = dev->priv;
6796
6797 readConfigRid(local, 1);
6798 if (vwrq->disabled) {
6799 if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
6800 return -EINVAL;
6801 }
6802 local->config.powerSaveMode = POWERSAVE_CAM;
6803 local->config.rmode &= 0xFF00;
6804 local->config.rmode |= RXMODE_BC_MC_ADDR;
6805 set_bit (FLAG_COMMIT, &local->flags);
6806 return -EINPROGRESS; /* Call commit handler */
6807 }
6808 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
6809 local->config.fastListenDelay = (vwrq->value + 500) / 1024;
6810 local->config.powerSaveMode = POWERSAVE_PSPCAM;
6811 set_bit (FLAG_COMMIT, &local->flags);
6812 } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
6813 local->config.fastListenInterval = local->config.listenInterval = (vwrq->value + 500) / 1024;
6814 local->config.powerSaveMode = POWERSAVE_PSPCAM;
6815 set_bit (FLAG_COMMIT, &local->flags);
6816 }
6817 switch (vwrq->flags & IW_POWER_MODE) {
6818 case IW_POWER_UNICAST_R:
6819 if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
6820 return -EINVAL;
6821 }
6822 local->config.rmode &= 0xFF00;
6823 local->config.rmode |= RXMODE_ADDR;
6824 set_bit (FLAG_COMMIT, &local->flags);
6825 break;
6826 case IW_POWER_ALL_R:
6827 if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
6828 return -EINVAL;
6829 }
6830 local->config.rmode &= 0xFF00;
6831 local->config.rmode |= RXMODE_BC_MC_ADDR;
6832 set_bit (FLAG_COMMIT, &local->flags);
6833 case IW_POWER_ON:
6834 break;
6835 default:
6836 return -EINVAL;
6837 }
6838 // Note : we may want to factor local->need_commit here
6839 // Note2 : may also want to factor RXMODE_RFMON test
6840 return -EINPROGRESS; /* Call commit handler */
6841}
6842
6843/*------------------------------------------------------------------*/
6844/*
6845 * Wireless Handler : get Power Management
6846 */
6847static int airo_get_power(struct net_device *dev,
6848 struct iw_request_info *info,
6849 struct iw_param *vwrq,
6850 char *extra)
6851{
6852 struct airo_info *local = dev->priv;
6853 int mode;
6854
6855 readConfigRid(local, 1);
6856 mode = local->config.powerSaveMode;
6857 if ((vwrq->disabled = (mode == POWERSAVE_CAM)))
6858 return 0;
6859 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
6860 vwrq->value = (int)local->config.fastListenDelay * 1024;
6861 vwrq->flags = IW_POWER_TIMEOUT;
6862 } else {
6863 vwrq->value = (int)local->config.fastListenInterval * 1024;
6864 vwrq->flags = IW_POWER_PERIOD;
6865 }
6866 if ((local->config.rmode & 0xFF) == RXMODE_ADDR)
6867 vwrq->flags |= IW_POWER_UNICAST_R;
6868 else
6869 vwrq->flags |= IW_POWER_ALL_R;
6870
6871 return 0;
6872}
6873
6874/*------------------------------------------------------------------*/
6875/*
6876 * Wireless Handler : set Sensitivity
6877 */
6878static int airo_set_sens(struct net_device *dev,
6879 struct iw_request_info *info,
6880 struct iw_param *vwrq,
6881 char *extra)
6882{
6883 struct airo_info *local = dev->priv;
6884
6885 readConfigRid(local, 1);
6886 local->config.rssiThreshold = vwrq->disabled ? RSSI_DEFAULT : vwrq->value;
6887 set_bit (FLAG_COMMIT, &local->flags);
6888
6889 return -EINPROGRESS; /* Call commit handler */
6890}
6891
6892/*------------------------------------------------------------------*/
6893/*
6894 * Wireless Handler : get Sensitivity
6895 */
6896static int airo_get_sens(struct net_device *dev,
6897 struct iw_request_info *info,
6898 struct iw_param *vwrq,
6899 char *extra)
6900{
6901 struct airo_info *local = dev->priv;
6902
6903 readConfigRid(local, 1);
6904 vwrq->value = local->config.rssiThreshold;
6905 vwrq->disabled = (vwrq->value == 0);
6906 vwrq->fixed = 1;
6907
6908 return 0;
6909}
6910
6911/*------------------------------------------------------------------*/
6912/*
6913 * Wireless Handler : get AP List
6914 * Note : this is deprecated in favor of IWSCAN
6915 */
6916static int airo_get_aplist(struct net_device *dev,
6917 struct iw_request_info *info,
6918 struct iw_point *dwrq,
6919 char *extra)
6920{
6921 struct airo_info *local = dev->priv;
6922 struct sockaddr *address = (struct sockaddr *) extra;
6923 struct iw_quality qual[IW_MAX_AP];
6924 BSSListRid BSSList;
6925 int i;
6926 int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
6927
6928 for (i = 0; i < IW_MAX_AP; i++) {
6929 if (readBSSListRid(local, loseSync, &BSSList))
6930 break;
6931 loseSync = 0;
6932 memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN);
6933 address[i].sa_family = ARPHRD_ETHER;
Dan Williams41480af2005-05-10 09:45:51 -04006934 if (local->rssi) {
6935 qual[i].level = 0x100 - BSSList.dBm;
6936 qual[i].qual = airo_dbm_to_pct( local->rssi, BSSList.dBm );
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006937 qual[i].updated = IW_QUAL_QUAL_UPDATED
6938 | IW_QUAL_LEVEL_UPDATED
6939 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04006940 } else {
6941 qual[i].level = (BSSList.dBm + 321) / 2;
6942 qual[i].qual = 0;
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006943 qual[i].updated = IW_QUAL_QUAL_INVALID
6944 | IW_QUAL_LEVEL_UPDATED
6945 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04006946 }
6947 qual[i].noise = local->wstats.qual.noise;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006948 if (BSSList.index == 0xffff)
6949 break;
6950 }
6951 if (!i) {
6952 StatusRid status_rid; /* Card status info */
6953 readStatusRid(local, &status_rid, 1);
6954 for (i = 0;
6955 i < min(IW_MAX_AP, 4) &&
6956 (status_rid.bssid[i][0]
6957 & status_rid.bssid[i][1]
6958 & status_rid.bssid[i][2]
6959 & status_rid.bssid[i][3]
6960 & status_rid.bssid[i][4]
6961 & status_rid.bssid[i][5])!=0xff &&
6962 (status_rid.bssid[i][0]
6963 | status_rid.bssid[i][1]
6964 | status_rid.bssid[i][2]
6965 | status_rid.bssid[i][3]
6966 | status_rid.bssid[i][4]
6967 | status_rid.bssid[i][5]);
6968 i++) {
6969 memcpy(address[i].sa_data,
6970 status_rid.bssid[i], ETH_ALEN);
6971 address[i].sa_family = ARPHRD_ETHER;
6972 }
6973 } else {
6974 dwrq->flags = 1; /* Should be define'd */
6975 memcpy(extra + sizeof(struct sockaddr)*i,
6976 &qual, sizeof(struct iw_quality)*i);
6977 }
6978 dwrq->length = i;
6979
6980 return 0;
6981}
6982
6983/*------------------------------------------------------------------*/
6984/*
6985 * Wireless Handler : Initiate Scan
6986 */
6987static int airo_set_scan(struct net_device *dev,
6988 struct iw_request_info *info,
6989 struct iw_param *vwrq,
6990 char *extra)
6991{
6992 struct airo_info *ai = dev->priv;
6993 Cmd cmd;
6994 Resp rsp;
6995
6996 /* Note : you may have realised that, as this is a SET operation,
6997 * this is privileged and therefore a normal user can't
6998 * perform scanning.
6999 * This is not an error, while the device perform scanning,
7000 * traffic doesn't flow, so it's a perfect DoS...
7001 * Jean II */
7002 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
7003
7004 /* Initiate a scan command */
7005 memset(&cmd, 0, sizeof(cmd));
7006 cmd.cmd=CMD_LISTBSS;
7007 if (down_interruptible(&ai->sem))
7008 return -ERESTARTSYS;
7009 issuecommand(ai, &cmd, &rsp);
7010 ai->scan_timestamp = jiffies;
7011 up(&ai->sem);
7012
7013 /* At this point, just return to the user. */
7014
7015 return 0;
7016}
7017
7018/*------------------------------------------------------------------*/
7019/*
7020 * Translate scan data returned from the card to a card independent
7021 * format that the Wireless Tools will understand - Jean II
7022 */
7023static inline char *airo_translate_scan(struct net_device *dev,
7024 char *current_ev,
7025 char *end_buf,
Dan Williams41480af2005-05-10 09:45:51 -04007026 BSSListRid *bss)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007027{
7028 struct airo_info *ai = dev->priv;
7029 struct iw_event iwe; /* Temporary buffer */
7030 u16 capabilities;
7031 char * current_val; /* For rates */
7032 int i;
7033
7034 /* First entry *MUST* be the AP MAC address */
7035 iwe.cmd = SIOCGIWAP;
7036 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
Dan Williams41480af2005-05-10 09:45:51 -04007037 memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007038 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
7039
7040 /* Other entries will be displayed in the order we give them */
7041
7042 /* Add the ESSID */
Dan Williams41480af2005-05-10 09:45:51 -04007043 iwe.u.data.length = bss->ssidLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007044 if(iwe.u.data.length > 32)
7045 iwe.u.data.length = 32;
7046 iwe.cmd = SIOCGIWESSID;
7047 iwe.u.data.flags = 1;
Dan Williams41480af2005-05-10 09:45:51 -04007048 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007049
7050 /* Add mode */
7051 iwe.cmd = SIOCGIWMODE;
Dan Williams41480af2005-05-10 09:45:51 -04007052 capabilities = le16_to_cpu(bss->cap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007053 if(capabilities & (CAP_ESS | CAP_IBSS)) {
7054 if(capabilities & CAP_ESS)
7055 iwe.u.mode = IW_MODE_MASTER;
7056 else
7057 iwe.u.mode = IW_MODE_ADHOC;
7058 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
7059 }
7060
7061 /* Add frequency */
7062 iwe.cmd = SIOCGIWFREQ;
Dan Williams41480af2005-05-10 09:45:51 -04007063 iwe.u.freq.m = le16_to_cpu(bss->dsChannel);
matthieu castet11414552005-09-12 23:31:39 +02007064 /* iwe.u.freq.m containt the channel (starting 1), our
7065 * frequency_list array start at index 0...
7066 */
7067 iwe.u.freq.m = frequency_list[iwe.u.freq.m - 1] * 100000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007068 iwe.u.freq.e = 1;
7069 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
7070
7071 /* Add quality statistics */
7072 iwe.cmd = IWEVQUAL;
Dan Williams41480af2005-05-10 09:45:51 -04007073 if (ai->rssi) {
7074 iwe.u.qual.level = 0x100 - bss->dBm;
7075 iwe.u.qual.qual = airo_dbm_to_pct( ai->rssi, bss->dBm );
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007076 iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
7077 | IW_QUAL_LEVEL_UPDATED
7078 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04007079 } else {
7080 iwe.u.qual.level = (bss->dBm + 321) / 2;
7081 iwe.u.qual.qual = 0;
Jeff Garzikbbeec902005-09-07 00:27:54 -04007082 iwe.u.qual.updated = IW_QUAL_QUAL_INVALID
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007083 | IW_QUAL_LEVEL_UPDATED
7084 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04007085 }
7086 iwe.u.qual.noise = ai->wstats.qual.noise;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007087 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
7088
7089 /* Add encryption capability */
7090 iwe.cmd = SIOCGIWENCODE;
7091 if(capabilities & CAP_PRIVACY)
7092 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
7093 else
7094 iwe.u.data.flags = IW_ENCODE_DISABLED;
7095 iwe.u.data.length = 0;
Dan Williams41480af2005-05-10 09:45:51 -04007096 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007097
7098 /* Rate : stuffing multiple values in a single event require a bit
7099 * more of magic - Jean II */
7100 current_val = current_ev + IW_EV_LCP_LEN;
7101
7102 iwe.cmd = SIOCGIWRATE;
7103 /* Those two flags are ignored... */
7104 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
7105 /* Max 8 values */
7106 for(i = 0 ; i < 8 ; i++) {
7107 /* NULL terminated */
Dan Williams41480af2005-05-10 09:45:51 -04007108 if(bss->rates[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007109 break;
7110 /* Bit rate given in 500 kb/s units (+ 0x80) */
Dan Williams41480af2005-05-10 09:45:51 -04007111 iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007112 /* Add new value to event */
7113 current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
7114 }
7115 /* Check if we added any event */
7116 if((current_val - current_ev) > IW_EV_LCP_LEN)
7117 current_ev = current_val;
7118
7119 /* The other data in the scan result are not really
7120 * interesting, so for now drop it - Jean II */
7121 return current_ev;
7122}
7123
7124/*------------------------------------------------------------------*/
7125/*
7126 * Wireless Handler : Read Scan Results
7127 */
7128static int airo_get_scan(struct net_device *dev,
7129 struct iw_request_info *info,
7130 struct iw_point *dwrq,
7131 char *extra)
7132{
7133 struct airo_info *ai = dev->priv;
7134 BSSListRid BSSList;
7135 int rc;
7136 char *current_ev = extra;
7137
7138 /* When we are associated again, the scan has surely finished.
7139 * Just in case, let's make sure enough time has elapsed since
7140 * we started the scan. - Javier */
7141 if(ai->scan_timestamp && time_before(jiffies,ai->scan_timestamp+3*HZ)) {
7142 /* Important note : we don't want to block the caller
7143 * until results are ready for various reasons.
7144 * First, managing wait queues is complex and racy
7145 * (there may be multiple simultaneous callers).
7146 * Second, we grab some rtnetlink lock before comming
7147 * here (in dev_ioctl()).
7148 * Third, the caller can wait on the Wireless Event
7149 * - Jean II */
7150 return -EAGAIN;
7151 }
7152 ai->scan_timestamp = 0;
7153
7154 /* There's only a race with proc_BSSList_open(), but its
7155 * consequences are begnign. So I don't bother fixing it - Javier */
7156
7157 /* Try to read the first entry of the scan result */
7158 rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 1);
7159 if((rc) || (BSSList.index == 0xffff)) {
7160 /* Client error, no scan results...
7161 * The caller need to restart the scan. */
7162 return -ENODATA;
7163 }
7164
7165 /* Read and parse all entries */
7166 while((!rc) && (BSSList.index != 0xffff)) {
7167 /* Translate to WE format this entry */
7168 current_ev = airo_translate_scan(dev, current_ev,
7169 extra + dwrq->length,
7170 &BSSList);
7171
7172 /* Check if there is space for one more entry */
7173 if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
7174 /* Ask user space to try again with a bigger buffer */
7175 return -E2BIG;
7176 }
7177
7178 /* Read next entry */
7179 rc = PC4500_readrid(ai, RID_BSSLISTNEXT,
7180 &BSSList, sizeof(BSSList), 1);
7181 }
7182 /* Length of data */
7183 dwrq->length = (current_ev - extra);
7184 dwrq->flags = 0; /* todo */
7185
7186 return 0;
7187}
7188
7189/*------------------------------------------------------------------*/
7190/*
7191 * Commit handler : called after a bunch of SET operations
7192 */
7193static int airo_config_commit(struct net_device *dev,
7194 struct iw_request_info *info, /* NULL */
7195 void *zwrq, /* NULL */
7196 char *extra) /* NULL */
7197{
7198 struct airo_info *local = dev->priv;
7199 Resp rsp;
7200
7201 if (!test_bit (FLAG_COMMIT, &local->flags))
7202 return 0;
7203
7204 /* Some of the "SET" function may have modified some of the
7205 * parameters. It's now time to commit them in the card */
7206 disable_MAC(local, 1);
7207 if (test_bit (FLAG_RESET, &local->flags)) {
7208 APListRid APList_rid;
7209 SsidRid SSID_rid;
7210
7211 readAPListRid(local, &APList_rid);
7212 readSsidRid(local, &SSID_rid);
7213 if (test_bit(FLAG_MPI,&local->flags))
7214 setup_card(local, dev->dev_addr, 1 );
7215 else
7216 reset_airo_card(dev);
7217 disable_MAC(local, 1);
7218 writeSsidRid(local, &SSID_rid, 1);
7219 writeAPListRid(local, &APList_rid, 1);
7220 }
7221 if (down_interruptible(&local->sem))
7222 return -ERESTARTSYS;
7223 writeConfigRid(local, 0);
7224 enable_MAC(local, &rsp, 0);
7225 if (test_bit (FLAG_RESET, &local->flags))
7226 airo_set_promisc(local);
7227 else
7228 up(&local->sem);
7229
7230 return 0;
7231}
7232
7233/*------------------------------------------------------------------*/
7234/*
7235 * Structures to export the Wireless Handlers
7236 */
7237
7238static const struct iw_priv_args airo_private_args[] = {
7239/*{ cmd, set_args, get_args, name } */
7240 { AIROIOCTL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
7241 IW_PRIV_TYPE_BYTE | 2047, "airoioctl" },
7242 { AIROIDIFC, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
7243 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" },
7244};
7245
7246static const iw_handler airo_handler[] =
7247{
7248 (iw_handler) airo_config_commit, /* SIOCSIWCOMMIT */
7249 (iw_handler) airo_get_name, /* SIOCGIWNAME */
7250 (iw_handler) NULL, /* SIOCSIWNWID */
7251 (iw_handler) NULL, /* SIOCGIWNWID */
7252 (iw_handler) airo_set_freq, /* SIOCSIWFREQ */
7253 (iw_handler) airo_get_freq, /* SIOCGIWFREQ */
7254 (iw_handler) airo_set_mode, /* SIOCSIWMODE */
7255 (iw_handler) airo_get_mode, /* SIOCGIWMODE */
7256 (iw_handler) airo_set_sens, /* SIOCSIWSENS */
7257 (iw_handler) airo_get_sens, /* SIOCGIWSENS */
7258 (iw_handler) NULL, /* SIOCSIWRANGE */
7259 (iw_handler) airo_get_range, /* SIOCGIWRANGE */
7260 (iw_handler) NULL, /* SIOCSIWPRIV */
7261 (iw_handler) NULL, /* SIOCGIWPRIV */
7262 (iw_handler) NULL, /* SIOCSIWSTATS */
7263 (iw_handler) NULL, /* SIOCGIWSTATS */
7264 iw_handler_set_spy, /* SIOCSIWSPY */
7265 iw_handler_get_spy, /* SIOCGIWSPY */
7266 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
7267 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
7268 (iw_handler) airo_set_wap, /* SIOCSIWAP */
7269 (iw_handler) airo_get_wap, /* SIOCGIWAP */
7270 (iw_handler) NULL, /* -- hole -- */
7271 (iw_handler) airo_get_aplist, /* SIOCGIWAPLIST */
7272 (iw_handler) airo_set_scan, /* SIOCSIWSCAN */
7273 (iw_handler) airo_get_scan, /* SIOCGIWSCAN */
7274 (iw_handler) airo_set_essid, /* SIOCSIWESSID */
7275 (iw_handler) airo_get_essid, /* SIOCGIWESSID */
7276 (iw_handler) airo_set_nick, /* SIOCSIWNICKN */
7277 (iw_handler) airo_get_nick, /* SIOCGIWNICKN */
7278 (iw_handler) NULL, /* -- hole -- */
7279 (iw_handler) NULL, /* -- hole -- */
7280 (iw_handler) airo_set_rate, /* SIOCSIWRATE */
7281 (iw_handler) airo_get_rate, /* SIOCGIWRATE */
7282 (iw_handler) airo_set_rts, /* SIOCSIWRTS */
7283 (iw_handler) airo_get_rts, /* SIOCGIWRTS */
7284 (iw_handler) airo_set_frag, /* SIOCSIWFRAG */
7285 (iw_handler) airo_get_frag, /* SIOCGIWFRAG */
7286 (iw_handler) airo_set_txpow, /* SIOCSIWTXPOW */
7287 (iw_handler) airo_get_txpow, /* SIOCGIWTXPOW */
7288 (iw_handler) airo_set_retry, /* SIOCSIWRETRY */
7289 (iw_handler) airo_get_retry, /* SIOCGIWRETRY */
7290 (iw_handler) airo_set_encode, /* SIOCSIWENCODE */
7291 (iw_handler) airo_get_encode, /* SIOCGIWENCODE */
7292 (iw_handler) airo_set_power, /* SIOCSIWPOWER */
7293 (iw_handler) airo_get_power, /* SIOCGIWPOWER */
Dan Williams4be757d2006-01-30 11:58:00 -05007294 (iw_handler) NULL, /* -- hole -- */
7295 (iw_handler) NULL, /* -- hole -- */
7296 (iw_handler) NULL, /* SIOCSIWGENIE */
7297 (iw_handler) NULL, /* SIOCGIWGENIE */
7298 (iw_handler) airo_set_auth, /* SIOCSIWAUTH */
7299 (iw_handler) airo_get_auth, /* SIOCGIWAUTH */
7300 (iw_handler) airo_set_encodeext, /* SIOCSIWENCODEEXT */
7301 (iw_handler) airo_get_encodeext, /* SIOCGIWENCODEEXT */
7302 (iw_handler) NULL, /* SIOCSIWPMKSA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007303};
7304
7305/* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here.
7306 * We want to force the use of the ioctl code, because those can't be
7307 * won't work the iw_handler code (because they simultaneously read
7308 * and write data and iw_handler can't do that).
7309 * Note that it's perfectly legal to read/write on a single ioctl command,
7310 * you just can't use iwpriv and need to force it via the ioctl handler.
7311 * Jean II */
7312static const iw_handler airo_private_handler[] =
7313{
7314 NULL, /* SIOCIWFIRSTPRIV */
7315};
7316
7317static const struct iw_handler_def airo_handler_def =
7318{
7319 .num_standard = sizeof(airo_handler)/sizeof(iw_handler),
7320 .num_private = sizeof(airo_private_handler)/sizeof(iw_handler),
7321 .num_private_args = sizeof(airo_private_args)/sizeof(struct iw_priv_args),
7322 .standard = airo_handler,
7323 .private = airo_private_handler,
7324 .private_args = airo_private_args,
7325 .get_wireless_stats = airo_get_wireless_stats,
7326};
7327
Linus Torvalds1da177e2005-04-16 15:20:36 -07007328/*
7329 * This defines the configuration part of the Wireless Extensions
7330 * Note : irq and spinlock protection will occur in the subroutines
7331 *
7332 * TODO :
7333 * o Check input value more carefully and fill correct values in range
7334 * o Test and shakeout the bugs (if any)
7335 *
7336 * Jean II
7337 *
7338 * Javier Achirica did a great job of merging code from the unnamed CISCO
7339 * developer that added support for flashing the card.
7340 */
7341static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
7342{
7343 int rc = 0;
7344 struct airo_info *ai = (struct airo_info *)dev->priv;
7345
Pavel Machekca078ba2005-09-03 15:56:57 -07007346 if (ai->power.event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007347 return 0;
7348
7349 switch (cmd) {
7350#ifdef CISCO_EXT
7351 case AIROIDIFC:
7352#ifdef AIROOLDIDIFC
7353 case AIROOLDIDIFC:
7354#endif
7355 {
7356 int val = AIROMAGIC;
7357 aironet_ioctl com;
7358 if (copy_from_user(&com,rq->ifr_data,sizeof(com)))
7359 rc = -EFAULT;
7360 else if (copy_to_user(com.data,(char *)&val,sizeof(val)))
7361 rc = -EFAULT;
7362 }
7363 break;
7364
7365 case AIROIOCTL:
7366#ifdef AIROOLDIOCTL
7367 case AIROOLDIOCTL:
7368#endif
7369 /* Get the command struct and hand it off for evaluation by
7370 * the proper subfunction
7371 */
7372 {
7373 aironet_ioctl com;
7374 if (copy_from_user(&com,rq->ifr_data,sizeof(com))) {
7375 rc = -EFAULT;
7376 break;
7377 }
7378
7379 /* Separate R/W functions bracket legality here
7380 */
7381 if ( com.command == AIRORSWVERSION ) {
7382 if (copy_to_user(com.data, swversion, sizeof(swversion)))
7383 rc = -EFAULT;
7384 else
7385 rc = 0;
7386 }
7387 else if ( com.command <= AIRORRID)
7388 rc = readrids(dev,&com);
7389 else if ( com.command >= AIROPCAP && com.command <= (AIROPLEAPUSR+2) )
7390 rc = writerids(dev,&com);
7391 else if ( com.command >= AIROFLSHRST && com.command <= AIRORESTART )
7392 rc = flashcard(dev,&com);
7393 else
7394 rc = -EINVAL; /* Bad command in ioctl */
7395 }
7396 break;
7397#endif /* CISCO_EXT */
7398
7399 // All other calls are currently unsupported
7400 default:
7401 rc = -EOPNOTSUPP;
7402 }
7403 return rc;
7404}
7405
Linus Torvalds1da177e2005-04-16 15:20:36 -07007406/*
7407 * Get the Wireless stats out of the driver
7408 * Note : irq and spinlock protection will occur in the subroutines
7409 *
7410 * TODO :
7411 * o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs)
7412 *
7413 * Jean
7414 */
7415static void airo_read_wireless_stats(struct airo_info *local)
7416{
7417 StatusRid status_rid;
7418 StatsRid stats_rid;
7419 CapabilityRid cap_rid;
7420 u32 *vals = stats_rid.vals;
7421
7422 /* Get stats out of the card */
7423 clear_bit(JOB_WSTATS, &local->flags);
Pavel Machekca078ba2005-09-03 15:56:57 -07007424 if (local->power.event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007425 up(&local->sem);
7426 return;
7427 }
7428 readCapabilityRid(local, &cap_rid, 0);
7429 readStatusRid(local, &status_rid, 0);
7430 readStatsRid(local, &stats_rid, RID_STATS, 0);
7431 up(&local->sem);
7432
7433 /* The status */
7434 local->wstats.status = status_rid.mode;
7435
Dan Williams41480af2005-05-10 09:45:51 -04007436 /* Signal quality and co */
7437 if (local->rssi) {
7438 local->wstats.qual.level = airo_rssi_to_dbm( local->rssi, status_rid.sigQuality );
7439 /* normalizedSignalStrength appears to be a percentage */
7440 local->wstats.qual.qual = status_rid.normalizedSignalStrength;
7441 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007442 local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04007443 local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
7444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007445 if (status_rid.len >= 124) {
Dan Williams41480af2005-05-10 09:45:51 -04007446 local->wstats.qual.noise = 0x100 - status_rid.noisedBm;
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007447 local->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007448 } else {
7449 local->wstats.qual.noise = 0;
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007450 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 -07007451 }
7452
7453 /* Packets discarded in the wireless adapter due to wireless
7454 * specific problems */
7455 local->wstats.discard.nwid = vals[56] + vals[57] + vals[58];/* SSID Mismatch */
7456 local->wstats.discard.code = vals[6];/* RxWepErr */
7457 local->wstats.discard.fragment = vals[30];
7458 local->wstats.discard.retries = vals[10];
7459 local->wstats.discard.misc = vals[1] + vals[32];
7460 local->wstats.miss.beacon = vals[34];
7461}
7462
Jouni Malinenff1d2762005-05-12 22:54:16 -04007463static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007464{
7465 struct airo_info *local = dev->priv;
7466
7467 if (!test_bit(JOB_WSTATS, &local->flags)) {
7468 /* Get stats out of the card if available */
7469 if (down_trylock(&local->sem) != 0) {
7470 set_bit(JOB_WSTATS, &local->flags);
7471 wake_up_interruptible(&local->thr_wait);
7472 } else
7473 airo_read_wireless_stats(local);
7474 }
7475
7476 return &local->wstats;
7477}
Linus Torvalds1da177e2005-04-16 15:20:36 -07007478
7479#ifdef CISCO_EXT
7480/*
7481 * This just translates from driver IOCTL codes to the command codes to
7482 * feed to the radio's host interface. Things can be added/deleted
7483 * as needed. This represents the READ side of control I/O to
7484 * the card
7485 */
7486static int readrids(struct net_device *dev, aironet_ioctl *comp) {
7487 unsigned short ridcode;
7488 unsigned char *iobuf;
7489 int len;
7490 struct airo_info *ai = dev->priv;
7491 Resp rsp;
7492
7493 if (test_bit(FLAG_FLASHING, &ai->flags))
7494 return -EIO;
7495
7496 switch(comp->command)
7497 {
7498 case AIROGCAP: ridcode = RID_CAPABILITIES; break;
7499 case AIROGCFG: ridcode = RID_CONFIG;
7500 if (test_bit(FLAG_COMMIT, &ai->flags)) {
7501 disable_MAC (ai, 1);
7502 writeConfigRid (ai, 1);
7503 enable_MAC (ai, &rsp, 1);
7504 }
7505 break;
7506 case AIROGSLIST: ridcode = RID_SSID; break;
7507 case AIROGVLIST: ridcode = RID_APLIST; break;
7508 case AIROGDRVNAM: ridcode = RID_DRVNAME; break;
7509 case AIROGEHTENC: ridcode = RID_ETHERENCAP; break;
7510 case AIROGWEPKTMP: ridcode = RID_WEP_TEMP;
7511 /* Only super-user can read WEP keys */
7512 if (!capable(CAP_NET_ADMIN))
7513 return -EPERM;
7514 break;
7515 case AIROGWEPKNV: ridcode = RID_WEP_PERM;
7516 /* Only super-user can read WEP keys */
7517 if (!capable(CAP_NET_ADMIN))
7518 return -EPERM;
7519 break;
7520 case AIROGSTAT: ridcode = RID_STATUS; break;
7521 case AIROGSTATSD32: ridcode = RID_STATSDELTA; break;
7522 case AIROGSTATSC32: ridcode = RID_STATS; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007523 case AIROGMICSTATS:
7524 if (copy_to_user(comp->data, &ai->micstats,
7525 min((int)comp->len,(int)sizeof(ai->micstats))))
7526 return -EFAULT;
7527 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007528 case AIRORRID: ridcode = comp->ridnum; break;
7529 default:
7530 return -EINVAL;
7531 break;
7532 }
7533
7534 if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
7535 return -ENOMEM;
7536
7537 PC4500_readrid(ai,ridcode,iobuf,RIDSIZE, 1);
7538 /* get the count of bytes in the rid docs say 1st 2 bytes is it.
7539 * then return it to the user
7540 * 9/22/2000 Honor user given length
7541 */
7542 len = comp->len;
7543
7544 if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) {
7545 kfree (iobuf);
7546 return -EFAULT;
7547 }
7548 kfree (iobuf);
7549 return 0;
7550}
7551
7552/*
7553 * Danger Will Robinson write the rids here
7554 */
7555
7556static int writerids(struct net_device *dev, aironet_ioctl *comp) {
7557 struct airo_info *ai = dev->priv;
7558 int ridcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007559 int enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007560 Resp rsp;
7561 static int (* writer)(struct airo_info *, u16 rid, const void *, int, int);
7562 unsigned char *iobuf;
7563
7564 /* Only super-user can write RIDs */
7565 if (!capable(CAP_NET_ADMIN))
7566 return -EPERM;
7567
7568 if (test_bit(FLAG_FLASHING, &ai->flags))
7569 return -EIO;
7570
7571 ridcode = 0;
7572 writer = do_writerid;
7573
7574 switch(comp->command)
7575 {
7576 case AIROPSIDS: ridcode = RID_SSID; break;
7577 case AIROPCAP: ridcode = RID_CAPABILITIES; break;
7578 case AIROPAPLIST: ridcode = RID_APLIST; break;
7579 case AIROPCFG: ai->config.len = 0;
7580 clear_bit(FLAG_COMMIT, &ai->flags);
7581 ridcode = RID_CONFIG; break;
7582 case AIROPWEPKEYNV: ridcode = RID_WEP_PERM; break;
7583 case AIROPLEAPUSR: ridcode = RID_LEAPUSERNAME; break;
7584 case AIROPLEAPPWD: ridcode = RID_LEAPPASSWORD; break;
7585 case AIROPWEPKEY: ridcode = RID_WEP_TEMP; writer = PC4500_writerid;
7586 break;
7587 case AIROPLEAPUSR+1: ridcode = 0xFF2A; break;
7588 case AIROPLEAPUSR+2: ridcode = 0xFF2B; break;
7589
7590 /* this is not really a rid but a command given to the card
7591 * same with MAC off
7592 */
7593 case AIROPMACON:
7594 if (enable_MAC(ai, &rsp, 1) != 0)
7595 return -EIO;
7596 return 0;
7597
7598 /*
7599 * Evidently this code in the airo driver does not get a symbol
7600 * as disable_MAC. it's probably so short the compiler does not gen one.
7601 */
7602 case AIROPMACOFF:
7603 disable_MAC(ai, 1);
7604 return 0;
7605
7606 /* This command merely clears the counts does not actually store any data
7607 * only reads rid. But as it changes the cards state, I put it in the
7608 * writerid routines.
7609 */
7610 case AIROPSTCLR:
7611 if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
7612 return -ENOMEM;
7613
7614 PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDSIZE, 1);
7615
Linus Torvalds1da177e2005-04-16 15:20:36 -07007616 enabled = ai->micstats.enabled;
7617 memset(&ai->micstats,0,sizeof(ai->micstats));
7618 ai->micstats.enabled = enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007619
7620 if (copy_to_user(comp->data, iobuf,
7621 min((int)comp->len, (int)RIDSIZE))) {
7622 kfree (iobuf);
7623 return -EFAULT;
7624 }
7625 kfree (iobuf);
7626 return 0;
7627
7628 default:
7629 return -EOPNOTSUPP; /* Blarg! */
7630 }
7631 if(comp->len > RIDSIZE)
7632 return -EINVAL;
7633
7634 if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
7635 return -ENOMEM;
7636
7637 if (copy_from_user(iobuf,comp->data,comp->len)) {
7638 kfree (iobuf);
7639 return -EFAULT;
7640 }
7641
7642 if (comp->command == AIROPCFG) {
7643 ConfigRid *cfg = (ConfigRid *)iobuf;
7644
7645 if (test_bit(FLAG_MIC_CAPABLE, &ai->flags))
7646 cfg->opmode |= MODE_MIC;
7647
7648 if ((cfg->opmode & 0xFF) == MODE_STA_IBSS)
7649 set_bit (FLAG_ADHOC, &ai->flags);
7650 else
7651 clear_bit (FLAG_ADHOC, &ai->flags);
7652 }
7653
7654 if((*writer)(ai, ridcode, iobuf,comp->len,1)) {
7655 kfree (iobuf);
7656 return -EIO;
7657 }
7658 kfree (iobuf);
7659 return 0;
7660}
7661
7662/*****************************************************************************
7663 * Ancillary flash / mod functions much black magic lurkes here *
7664 *****************************************************************************
7665 */
7666
7667/*
7668 * Flash command switch table
7669 */
7670
Jouni Malinenff1d2762005-05-12 22:54:16 -04007671static int flashcard(struct net_device *dev, aironet_ioctl *comp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007672 int z;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007673
7674 /* Only super-user can modify flash */
7675 if (!capable(CAP_NET_ADMIN))
7676 return -EPERM;
7677
7678 switch(comp->command)
7679 {
7680 case AIROFLSHRST:
7681 return cmdreset((struct airo_info *)dev->priv);
7682
7683 case AIROFLSHSTFL:
7684 if (!((struct airo_info *)dev->priv)->flash &&
7685 (((struct airo_info *)dev->priv)->flash = kmalloc (FLASHSIZE, GFP_KERNEL)) == NULL)
7686 return -ENOMEM;
7687 return setflashmode((struct airo_info *)dev->priv);
7688
7689 case AIROFLSHGCHR: /* Get char from aux */
7690 if(comp->len != sizeof(int))
7691 return -EINVAL;
7692 if (copy_from_user(&z,comp->data,comp->len))
7693 return -EFAULT;
7694 return flashgchar((struct airo_info *)dev->priv,z,8000);
7695
7696 case AIROFLSHPCHR: /* Send char to card. */
7697 if(comp->len != sizeof(int))
7698 return -EINVAL;
7699 if (copy_from_user(&z,comp->data,comp->len))
7700 return -EFAULT;
7701 return flashpchar((struct airo_info *)dev->priv,z,8000);
7702
7703 case AIROFLPUTBUF: /* Send 32k to card */
7704 if (!((struct airo_info *)dev->priv)->flash)
7705 return -ENOMEM;
7706 if(comp->len > FLASHSIZE)
7707 return -EINVAL;
7708 if(copy_from_user(((struct airo_info *)dev->priv)->flash,comp->data,comp->len))
7709 return -EFAULT;
7710
7711 flashputbuf((struct airo_info *)dev->priv);
7712 return 0;
7713
7714 case AIRORESTART:
7715 if(flashrestart((struct airo_info *)dev->priv,dev))
7716 return -EIO;
7717 return 0;
7718 }
7719 return -EINVAL;
7720}
7721
7722#define FLASH_COMMAND 0x7e7e
7723
7724/*
7725 * STEP 1)
7726 * Disable MAC and do soft reset on
7727 * card.
7728 */
7729
Jouni Malinenff1d2762005-05-12 22:54:16 -04007730static int cmdreset(struct airo_info *ai) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007731 disable_MAC(ai, 1);
7732
7733 if(!waitbusy (ai)){
Dan Williams934d8bf2006-03-16 13:46:23 -05007734 airo_print_info(ai->dev->name, "Waitbusy hang before RESET");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007735 return -EBUSY;
7736 }
7737
7738 OUT4500(ai,COMMAND,CMD_SOFTRESET);
7739
7740 ssleep(1); /* WAS 600 12/7/00 */
7741
7742 if(!waitbusy (ai)){
Dan Williams934d8bf2006-03-16 13:46:23 -05007743 airo_print_info(ai->dev->name, "Waitbusy hang AFTER RESET");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007744 return -EBUSY;
7745 }
7746 return 0;
7747}
7748
7749/* STEP 2)
7750 * Put the card in legendary flash
7751 * mode
7752 */
7753
Jouni Malinenff1d2762005-05-12 22:54:16 -04007754static int setflashmode (struct airo_info *ai) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007755 set_bit (FLAG_FLASHING, &ai->flags);
7756
7757 OUT4500(ai, SWS0, FLASH_COMMAND);
7758 OUT4500(ai, SWS1, FLASH_COMMAND);
7759 if (probe) {
7760 OUT4500(ai, SWS0, FLASH_COMMAND);
7761 OUT4500(ai, COMMAND,0x10);
7762 } else {
7763 OUT4500(ai, SWS2, FLASH_COMMAND);
7764 OUT4500(ai, SWS3, FLASH_COMMAND);
7765 OUT4500(ai, COMMAND,0);
7766 }
7767 msleep(500); /* 500ms delay */
7768
7769 if(!waitbusy(ai)) {
7770 clear_bit (FLAG_FLASHING, &ai->flags);
Dan Williams934d8bf2006-03-16 13:46:23 -05007771 airo_print_info(ai->dev->name, "Waitbusy hang after setflash mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007772 return -EIO;
7773 }
7774 return 0;
7775}
7776
7777/* Put character to SWS0 wait for dwelltime
7778 * x 50us for echo .
7779 */
7780
Jouni Malinenff1d2762005-05-12 22:54:16 -04007781static int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007782 int echo;
7783 int waittime;
7784
7785 byte |= 0x8000;
7786
7787 if(dwelltime == 0 )
7788 dwelltime = 200;
7789
7790 waittime=dwelltime;
7791
7792 /* Wait for busy bit d15 to go false indicating buffer empty */
7793 while ((IN4500 (ai, SWS0) & 0x8000) && waittime > 0) {
7794 udelay (50);
7795 waittime -= 50;
7796 }
7797
7798 /* timeout for busy clear wait */
7799 if(waittime <= 0 ){
Dan Williams934d8bf2006-03-16 13:46:23 -05007800 airo_print_info(ai->dev->name, "flash putchar busywait timeout!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007801 return -EBUSY;
7802 }
7803
7804 /* Port is clear now write byte and wait for it to echo back */
7805 do {
7806 OUT4500(ai,SWS0,byte);
7807 udelay(50);
7808 dwelltime -= 50;
7809 echo = IN4500(ai,SWS1);
7810 } while (dwelltime >= 0 && echo != byte);
7811
7812 OUT4500(ai,SWS1,0);
7813
7814 return (echo == byte) ? 0 : -EIO;
7815}
7816
7817/*
7818 * Get a character from the card matching matchbyte
7819 * Step 3)
7820 */
Jouni Malinenff1d2762005-05-12 22:54:16 -04007821static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
Linus Torvalds1da177e2005-04-16 15:20:36 -07007822 int rchar;
7823 unsigned char rbyte=0;
7824
7825 do {
7826 rchar = IN4500(ai,SWS1);
7827
7828 if(dwelltime && !(0x8000 & rchar)){
7829 dwelltime -= 10;
7830 mdelay(10);
7831 continue;
7832 }
7833 rbyte = 0xff & rchar;
7834
7835 if( (rbyte == matchbyte) && (0x8000 & rchar) ){
7836 OUT4500(ai,SWS1,0);
7837 return 0;
7838 }
7839 if( rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar)
7840 break;
7841 OUT4500(ai,SWS1,0);
7842
7843 }while(dwelltime > 0);
7844 return -EIO;
7845}
7846
7847/*
7848 * Transfer 32k of firmware data from user buffer to our buffer and
7849 * send to the card
7850 */
7851
Jouni Malinenff1d2762005-05-12 22:54:16 -04007852static int flashputbuf(struct airo_info *ai){
Linus Torvalds1da177e2005-04-16 15:20:36 -07007853 int nwords;
7854
7855 /* Write stuff */
7856 if (test_bit(FLAG_MPI,&ai->flags))
7857 memcpy_toio(ai->pciaux + 0x8000, ai->flash, FLASHSIZE);
7858 else {
7859 OUT4500(ai,AUXPAGE,0x100);
7860 OUT4500(ai,AUXOFF,0);
7861
7862 for(nwords=0;nwords != FLASHSIZE / 2;nwords++){
7863 OUT4500(ai,AUXDATA,ai->flash[nwords] & 0xffff);
7864 }
7865 }
7866 OUT4500(ai,SWS0,0x8000);
7867
7868 return 0;
7869}
7870
7871/*
7872 *
7873 */
Jouni Malinenff1d2762005-05-12 22:54:16 -04007874static int flashrestart(struct airo_info *ai,struct net_device *dev){
Linus Torvalds1da177e2005-04-16 15:20:36 -07007875 int i,status;
7876
7877 ssleep(1); /* Added 12/7/00 */
7878 clear_bit (FLAG_FLASHING, &ai->flags);
7879 if (test_bit(FLAG_MPI, &ai->flags)) {
7880 status = mpi_init_descriptors(ai);
7881 if (status != SUCCESS)
7882 return status;
7883 }
7884 status = setup_card(ai, dev->dev_addr, 1);
7885
7886 if (!test_bit(FLAG_MPI,&ai->flags))
7887 for( i = 0; i < MAX_FIDS; i++ ) {
7888 ai->fids[i] = transmit_allocate
Dan Williams15db2762006-03-16 13:46:27 -05007889 ( ai, AIRO_DEF_MTU, i >= MAX_FIDS / 2 );
Linus Torvalds1da177e2005-04-16 15:20:36 -07007890 }
7891
7892 ssleep(1); /* Added 12/7/00 */
7893 return status;
7894}
7895#endif /* CISCO_EXT */
7896
7897/*
7898 This program is free software; you can redistribute it and/or
7899 modify it under the terms of the GNU General Public License
7900 as published by the Free Software Foundation; either version 2
7901 of the License, or (at your option) any later version.
7902
7903 This program is distributed in the hope that it will be useful,
7904 but WITHOUT ANY WARRANTY; without even the implied warranty of
7905 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7906 GNU General Public License for more details.
7907
7908 In addition:
7909
7910 Redistribution and use in source and binary forms, with or without
7911 modification, are permitted provided that the following conditions
7912 are met:
7913
7914 1. Redistributions of source code must retain the above copyright
7915 notice, this list of conditions and the following disclaimer.
7916 2. Redistributions in binary form must reproduce the above copyright
7917 notice, this list of conditions and the following disclaimer in the
7918 documentation and/or other materials provided with the distribution.
7919 3. The name of the author may not be used to endorse or promote
7920 products derived from this software without specific prior written
7921 permission.
7922
7923 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
7924 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7925 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7926 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
7927 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
7928 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
7929 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7930 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
7931 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
7932 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
7933 POSSIBILITY OF SUCH DAMAGE.
7934*/
7935
7936module_init(airo_init_module);
7937module_exit(airo_cleanup_module);