blob: 9c577f7b6e5836d7cd3cfda226376f11ae02cebc [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
905
906typedef struct {
907 u32 size; // size
908 u8 enabled; // MIC enabled or not
909 u32 rxSuccess; // successful packets received
910 u32 rxIncorrectMIC; // pkts dropped due to incorrect MIC comparison
911 u32 rxNotMICed; // pkts dropped due to not being MIC'd
912 u32 rxMICPlummed; // pkts dropped due to not having a MIC plummed
913 u32 rxWrongSequence; // pkts dropped due to sequence number violation
914 u32 reserve[32];
915} mic_statistics;
916
917typedef struct {
918 u32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2];
919 u64 accum; // accumulated mic, reduced to u32 in final()
920 int position; // current position (byte offset) in message
921 union {
922 u8 d8[4];
923 u32 d32;
924 } part; // saves partial message word across update() calls
925} emmh32_context;
926
927typedef struct {
928 emmh32_context seed; // Context - the seed
929 u32 rx; // Received sequence number
930 u32 tx; // Tx sequence number
931 u32 window; // Start of window
932 u8 valid; // Flag to say if context is valid or not
933 u8 key[16];
934} miccntx;
935
936typedef struct {
937 miccntx mCtx; // Multicast context
938 miccntx uCtx; // Unicast context
939} mic_module;
940
941typedef struct {
942 unsigned int rid: 16;
943 unsigned int len: 15;
944 unsigned int valid: 1;
945 dma_addr_t host_addr;
946} Rid;
947
948typedef struct {
949 unsigned int offset: 15;
950 unsigned int eoc: 1;
951 unsigned int len: 15;
952 unsigned int valid: 1;
953 dma_addr_t host_addr;
954} TxFid;
955
956typedef struct {
957 unsigned int ctl: 15;
958 unsigned int rdy: 1;
959 unsigned int len: 15;
960 unsigned int valid: 1;
961 dma_addr_t host_addr;
962} RxFid;
963
964/*
965 * Host receive descriptor
966 */
967typedef struct {
968 unsigned char __iomem *card_ram_off; /* offset into card memory of the
969 desc */
970 RxFid rx_desc; /* card receive descriptor */
971 char *virtual_host_addr; /* virtual address of host receive
972 buffer */
973 int pending;
974} HostRxDesc;
975
976/*
977 * Host transmit descriptor
978 */
979typedef struct {
980 unsigned char __iomem *card_ram_off; /* offset into card memory of the
981 desc */
982 TxFid tx_desc; /* card transmit descriptor */
983 char *virtual_host_addr; /* virtual address of host receive
984 buffer */
985 int pending;
986} HostTxDesc;
987
988/*
989 * Host RID descriptor
990 */
991typedef struct {
992 unsigned char __iomem *card_ram_off; /* offset into card memory of the
993 descriptor */
994 Rid rid_desc; /* card RID descriptor */
995 char *virtual_host_addr; /* virtual address of host receive
996 buffer */
997} HostRidDesc;
998
999typedef struct {
1000 u16 sw0;
1001 u16 sw1;
1002 u16 status;
1003 u16 len;
1004#define HOST_SET (1 << 0)
1005#define HOST_INT_TX (1 << 1) /* Interrupt on successful TX */
1006#define HOST_INT_TXERR (1 << 2) /* Interrupt on unseccessful TX */
1007#define HOST_LCC_PAYLOAD (1 << 4) /* LLC payload, 0 = Ethertype */
1008#define HOST_DONT_RLSE (1 << 5) /* Don't release buffer when done */
1009#define HOST_DONT_RETRY (1 << 6) /* Don't retry trasmit */
1010#define HOST_CLR_AID (1 << 7) /* clear AID failure */
1011#define HOST_RTS (1 << 9) /* Force RTS use */
1012#define HOST_SHORT (1 << 10) /* Do short preamble */
1013 u16 ctl;
1014 u16 aid;
1015 u16 retries;
1016 u16 fill;
1017} TxCtlHdr;
1018
1019typedef struct {
1020 u16 ctl;
1021 u16 duration;
1022 char addr1[6];
1023 char addr2[6];
1024 char addr3[6];
1025 u16 seq;
1026 char addr4[6];
1027} WifiHdr;
1028
1029
1030typedef struct {
1031 TxCtlHdr ctlhdr;
1032 u16 fill1;
1033 u16 fill2;
1034 WifiHdr wifihdr;
1035 u16 gaplen;
1036 u16 status;
1037} WifiCtlHdr;
1038
Jouni Malinenff1d2762005-05-12 22:54:16 -04001039static WifiCtlHdr wifictlhdr8023 = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 .ctlhdr = {
1041 .ctl = HOST_DONT_RLSE,
1042 }
1043};
1044
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045// Frequency list (map channels to frequencies)
1046static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
1047 2447, 2452, 2457, 2462, 2467, 2472, 2484 };
1048
1049// A few details needed for WEP (Wireless Equivalent Privacy)
1050#define MAX_KEY_SIZE 13 // 128 (?) bits
1051#define MIN_KEY_SIZE 5 // 40 bits RC4 - WEP
1052typedef struct wep_key_t {
1053 u16 len;
1054 u8 key[16]; /* 40-bit and 104-bit keys */
1055} wep_key_t;
1056
1057/* Backward compatibility */
1058#ifndef IW_ENCODE_NOKEY
1059#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */
1060#define IW_ENCODE_MODE (IW_ENCODE_DISABLED | IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)
1061#endif /* IW_ENCODE_NOKEY */
1062
1063/* List of Wireless Handlers (new API) */
1064static const struct iw_handler_def airo_handler_def;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
1066static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)";
1067
1068struct airo_info;
1069
1070static int get_dec_u16( char *buffer, int *start, int limit );
1071static void OUT4500( struct airo_info *, u16 register, u16 value );
1072static unsigned short IN4500( struct airo_info *, u16 register );
1073static u16 setup_card(struct airo_info*, u8 *mac, int lock);
1074static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock );
1075static void disable_MAC(struct airo_info *ai, int lock);
1076static void enable_interrupts(struct airo_info*);
1077static void disable_interrupts(struct airo_info*);
1078static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
1079static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
1080static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
1081 int whichbap);
1082static int fast_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
1083 int whichbap);
1084static int bap_write(struct airo_info*, const u16 *pu16Src, int bytelen,
1085 int whichbap);
1086static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd);
1087static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock);
1088static int PC4500_writerid(struct airo_info*, u16 rid, const void
1089 *pBuf, int len, int lock);
1090static int do_writerid( struct airo_info*, u16 rid, const void *rid_data,
1091 int len, int dummy );
1092static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw);
1093static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket);
1094static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket);
1095
1096static int mpi_send_packet (struct net_device *dev);
1097static void mpi_unmap_card(struct pci_dev *pci);
1098static void mpi_receive_802_3(struct airo_info *ai);
1099static void mpi_receive_802_11(struct airo_info *ai);
1100static int waitbusy (struct airo_info *ai);
1101
1102static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs
1103 *regs);
1104static int airo_thread(void *data);
1105static void timer_func( struct net_device *dev );
1106static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
Jouni Malinenff1d2762005-05-12 22:54:16 -04001107static struct iw_statistics *airo_get_wireless_stats (struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108static void airo_read_wireless_stats (struct airo_info *local);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109#ifdef CISCO_EXT
1110static int readrids(struct net_device *dev, aironet_ioctl *comp);
1111static int writerids(struct net_device *dev, aironet_ioctl *comp);
Jouni Malinenff1d2762005-05-12 22:54:16 -04001112static int flashcard(struct net_device *dev, aironet_ioctl *comp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113#endif /* CISCO_EXT */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114static void micinit(struct airo_info *ai);
1115static int micsetup(struct airo_info *ai);
1116static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len);
1117static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen);
1118
Dan Williams41480af2005-05-10 09:45:51 -04001119static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi);
1120static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm);
1121
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122struct airo_info {
1123 struct net_device_stats stats;
1124 struct net_device *dev;
1125 /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we
1126 use the high bit to mark whether it is in use. */
1127#define MAX_FIDS 6
1128#define MPI_MAX_FIDS 1
1129 int fids[MAX_FIDS];
1130 ConfigRid config;
1131 char keyindex; // Used with auto wep
1132 char defindex; // Used with auto wep
1133 struct proc_dir_entry *proc_entry;
1134 spinlock_t aux_lock;
1135 unsigned long flags;
1136#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */
1137#define FLAG_RADIO_OFF 0 /* User disabling of MAC */
1138#define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */
1139#define FLAG_RADIO_MASK 0x03
1140#define FLAG_ENABLED 2
1141#define FLAG_ADHOC 3 /* Needed by MIC */
1142#define FLAG_MIC_CAPABLE 4
1143#define FLAG_UPDATE_MULTI 5
1144#define FLAG_UPDATE_UNI 6
1145#define FLAG_802_11 7
1146#define FLAG_PENDING_XMIT 9
1147#define FLAG_PENDING_XMIT11 10
1148#define FLAG_MPI 11
1149#define FLAG_REGISTERED 12
1150#define FLAG_COMMIT 13
1151#define FLAG_RESET 14
1152#define FLAG_FLASHING 15
1153#define JOB_MASK 0x1ff0000
1154#define JOB_DIE 16
1155#define JOB_XMIT 17
1156#define JOB_XMIT11 18
1157#define JOB_STATS 19
1158#define JOB_PROMISC 20
1159#define JOB_MIC 21
1160#define JOB_EVENT 22
1161#define JOB_AUTOWEP 23
1162#define JOB_WSTATS 24
1163 int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
1164 int whichbap);
1165 unsigned short *flash;
1166 tdsRssiEntry *rssi;
1167 struct task_struct *task;
1168 struct semaphore sem;
1169 pid_t thr_pid;
1170 wait_queue_head_t thr_wait;
1171 struct completion thr_exited;
1172 unsigned long expires;
1173 struct {
1174 struct sk_buff *skb;
1175 int fid;
1176 } xmit, xmit11;
1177 struct net_device *wifidev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 struct iw_statistics wstats; // wireless stats
1179 unsigned long scan_timestamp; /* Time started to scan */
1180 struct iw_spy_data spy_data;
1181 struct iw_public_data wireless_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 /* MIC stuff */
1183 struct crypto_tfm *tfm;
1184 mic_module mod[2];
1185 mic_statistics micstats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors
1187 HostTxDesc txfids[MPI_MAX_FIDS];
1188 HostRidDesc config_desc;
1189 unsigned long ridbus; // phys addr of config_desc
1190 struct sk_buff_head txq;// tx queue used by mpi350 code
1191 struct pci_dev *pci;
1192 unsigned char __iomem *pcimem;
1193 unsigned char __iomem *pciaux;
1194 unsigned char *shared;
1195 dma_addr_t shared_dma;
Pavel Machek1cc68ae2005-06-20 15:33:04 -07001196 pm_message_t power;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 SsidRid *SSID;
1198 APListRid *APList;
1199#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
1200 char proc_name[IFNAMSIZ];
1201};
1202
1203static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
1204 int whichbap) {
1205 return ai->bap_read(ai, pu16Dst, bytelen, whichbap);
1206}
1207
1208static int setup_proc_entry( struct net_device *dev,
1209 struct airo_info *apriv );
1210static int takedown_proc_entry( struct net_device *dev,
1211 struct airo_info *apriv );
1212
Jouni Malinenff1d2762005-05-12 22:54:16 -04001213static int cmdreset(struct airo_info *ai);
1214static int setflashmode (struct airo_info *ai);
1215static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime);
1216static int flashputbuf(struct airo_info *ai);
1217static int flashrestart(struct airo_info *ai,struct net_device *dev);
1218
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219/***********************************************************************
1220 * MIC ROUTINES *
1221 ***********************************************************************
1222 */
1223
1224static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq);
1225static void MoveWindow(miccntx *context, u32 micSeq);
Jouni Malinenff1d2762005-05-12 22:54:16 -04001226static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *);
1227static void emmh32_init(emmh32_context *context);
1228static void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
1229static void emmh32_final(emmh32_context *context, u8 digest[4]);
1230static int flashpchar(struct airo_info *ai,int byte,int dwelltime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
1232/* micinit - Initialize mic seed */
1233
1234static void micinit(struct airo_info *ai)
1235{
1236 MICRid mic_rid;
1237
1238 clear_bit(JOB_MIC, &ai->flags);
1239 PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
1240 up(&ai->sem);
1241
1242 ai->micstats.enabled = (mic_rid.state & 0x00FF) ? 1 : 0;
1243
1244 if (ai->micstats.enabled) {
1245 /* Key must be valid and different */
1246 if (mic_rid.multicastValid && (!ai->mod[0].mCtx.valid ||
1247 (memcmp (ai->mod[0].mCtx.key, mic_rid.multicast,
1248 sizeof(ai->mod[0].mCtx.key)) != 0))) {
1249 /* Age current mic Context */
1250 memcpy(&ai->mod[1].mCtx,&ai->mod[0].mCtx,sizeof(miccntx));
1251 /* Initialize new context */
1252 memcpy(&ai->mod[0].mCtx.key,mic_rid.multicast,sizeof(mic_rid.multicast));
1253 ai->mod[0].mCtx.window = 33; //Window always points to the middle
1254 ai->mod[0].mCtx.rx = 0; //Rx Sequence numbers
1255 ai->mod[0].mCtx.tx = 0; //Tx sequence numbers
1256 ai->mod[0].mCtx.valid = 1; //Key is now valid
1257
1258 /* Give key to mic seed */
1259 emmh32_setseed(&ai->mod[0].mCtx.seed,mic_rid.multicast,sizeof(mic_rid.multicast), ai->tfm);
1260 }
1261
1262 /* Key must be valid and different */
1263 if (mic_rid.unicastValid && (!ai->mod[0].uCtx.valid ||
1264 (memcmp(ai->mod[0].uCtx.key, mic_rid.unicast,
1265 sizeof(ai->mod[0].uCtx.key)) != 0))) {
1266 /* Age current mic Context */
1267 memcpy(&ai->mod[1].uCtx,&ai->mod[0].uCtx,sizeof(miccntx));
1268 /* Initialize new context */
1269 memcpy(&ai->mod[0].uCtx.key,mic_rid.unicast,sizeof(mic_rid.unicast));
1270
1271 ai->mod[0].uCtx.window = 33; //Window always points to the middle
1272 ai->mod[0].uCtx.rx = 0; //Rx Sequence numbers
1273 ai->mod[0].uCtx.tx = 0; //Tx sequence numbers
1274 ai->mod[0].uCtx.valid = 1; //Key is now valid
1275
1276 //Give key to mic seed
1277 emmh32_setseed(&ai->mod[0].uCtx.seed, mic_rid.unicast, sizeof(mic_rid.unicast), ai->tfm);
1278 }
1279 } else {
1280 /* So next time we have a valid key and mic is enabled, we will update
1281 * the sequence number if the key is the same as before.
1282 */
1283 ai->mod[0].uCtx.valid = 0;
1284 ai->mod[0].mCtx.valid = 0;
1285 }
1286}
1287
1288/* micsetup - Get ready for business */
1289
1290static int micsetup(struct airo_info *ai) {
1291 int i;
1292
1293 if (ai->tfm == NULL)
Herbert Xueb6f1162005-09-01 17:43:25 -07001294 ai->tfm = crypto_alloc_tfm("aes", CRYPTO_TFM_REQ_MAY_SLEEP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295
1296 if (ai->tfm == NULL) {
1297 printk(KERN_ERR "airo: failed to load transform for AES\n");
1298 return ERROR;
1299 }
1300
1301 for (i=0; i < NUM_MODULES; i++) {
1302 memset(&ai->mod[i].mCtx,0,sizeof(miccntx));
1303 memset(&ai->mod[i].uCtx,0,sizeof(miccntx));
1304 }
1305 return SUCCESS;
1306}
1307
Jouni Malinenff1d2762005-05-12 22:54:16 -04001308static char micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309
1310/*===========================================================================
1311 * Description: Mic a packet
1312 *
1313 * Inputs: etherHead * pointer to an 802.3 frame
1314 *
1315 * Returns: BOOLEAN if successful, otherwise false.
1316 * PacketTxLen will be updated with the mic'd packets size.
1317 *
1318 * Caveats: It is assumed that the frame buffer will already
1319 * be big enough to hold the largets mic message possible.
1320 * (No memory allocation is done here).
1321 *
1322 * Author: sbraneky (10/15/01)
1323 * Merciless hacks by rwilcher (1/14/02)
1324 */
1325
1326static int encapsulate(struct airo_info *ai ,etherHead *frame, MICBuffer *mic, int payLen)
1327{
1328 miccntx *context;
1329
1330 // Determine correct context
1331 // If not adhoc, always use unicast key
1332
1333 if (test_bit(FLAG_ADHOC, &ai->flags) && (frame->da[0] & 0x1))
1334 context = &ai->mod[0].mCtx;
1335 else
1336 context = &ai->mod[0].uCtx;
1337
1338 if (!context->valid)
1339 return ERROR;
1340
1341 mic->typelen = htons(payLen + 16); //Length of Mic'd packet
1342
1343 memcpy(&mic->u.snap, micsnap, sizeof(micsnap)); // Add Snap
1344
1345 // Add Tx sequence
1346 mic->seq = htonl(context->tx);
1347 context->tx += 2;
1348
1349 emmh32_init(&context->seed); // Mic the packet
1350 emmh32_update(&context->seed,frame->da,ETH_ALEN * 2); // DA,SA
1351 emmh32_update(&context->seed,(u8*)&mic->typelen,10); // Type/Length and Snap
1352 emmh32_update(&context->seed,(u8*)&mic->seq,sizeof(mic->seq)); //SEQ
1353 emmh32_update(&context->seed,frame->da + ETH_ALEN * 2,payLen); //payload
1354 emmh32_final(&context->seed, (u8*)&mic->mic);
1355
1356 /* New Type/length ?????????? */
1357 mic->typelen = 0; //Let NIC know it could be an oversized packet
1358 return SUCCESS;
1359}
1360
1361typedef enum {
1362 NONE,
1363 NOMIC,
1364 NOMICPLUMMED,
1365 SEQUENCE,
1366 INCORRECTMIC,
1367} mic_error;
1368
1369/*===========================================================================
1370 * Description: Decapsulates a MIC'd packet and returns the 802.3 packet
1371 * (removes the MIC stuff) if packet is a valid packet.
1372 *
1373 * Inputs: etherHead pointer to the 802.3 packet
1374 *
1375 * Returns: BOOLEAN - TRUE if packet should be dropped otherwise FALSE
1376 *
1377 * Author: sbraneky (10/15/01)
1378 * Merciless hacks by rwilcher (1/14/02)
1379 *---------------------------------------------------------------------------
1380 */
1381
1382static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *eth, u16 payLen)
1383{
1384 int i;
1385 u32 micSEQ;
1386 miccntx *context;
1387 u8 digest[4];
1388 mic_error micError = NONE;
1389
1390 // Check if the packet is a Mic'd packet
1391
1392 if (!ai->micstats.enabled) {
1393 //No Mic set or Mic OFF but we received a MIC'd packet.
1394 if (memcmp ((u8*)eth + 14, micsnap, sizeof(micsnap)) == 0) {
1395 ai->micstats.rxMICPlummed++;
1396 return ERROR;
1397 }
1398 return SUCCESS;
1399 }
1400
1401 if (ntohs(mic->typelen) == 0x888E)
1402 return SUCCESS;
1403
1404 if (memcmp (mic->u.snap, micsnap, sizeof(micsnap)) != 0) {
1405 // Mic enabled but packet isn't Mic'd
1406 ai->micstats.rxMICPlummed++;
1407 return ERROR;
1408 }
1409
1410 micSEQ = ntohl(mic->seq); //store SEQ as CPU order
1411
1412 //At this point we a have a mic'd packet and mic is enabled
1413 //Now do the mic error checking.
1414
1415 //Receive seq must be odd
1416 if ( (micSEQ & 1) == 0 ) {
1417 ai->micstats.rxWrongSequence++;
1418 return ERROR;
1419 }
1420
1421 for (i = 0; i < NUM_MODULES; i++) {
1422 int mcast = eth->da[0] & 1;
1423 //Determine proper context
1424 context = mcast ? &ai->mod[i].mCtx : &ai->mod[i].uCtx;
1425
1426 //Make sure context is valid
1427 if (!context->valid) {
1428 if (i == 0)
1429 micError = NOMICPLUMMED;
1430 continue;
1431 }
1432 //DeMic it
1433
1434 if (!mic->typelen)
1435 mic->typelen = htons(payLen + sizeof(MICBuffer) - 2);
1436
1437 emmh32_init(&context->seed);
1438 emmh32_update(&context->seed, eth->da, ETH_ALEN*2);
1439 emmh32_update(&context->seed, (u8 *)&mic->typelen, sizeof(mic->typelen)+sizeof(mic->u.snap));
1440 emmh32_update(&context->seed, (u8 *)&mic->seq,sizeof(mic->seq));
1441 emmh32_update(&context->seed, eth->da + ETH_ALEN*2,payLen);
1442 //Calculate MIC
1443 emmh32_final(&context->seed, digest);
1444
1445 if (memcmp(digest, &mic->mic, 4)) { //Make sure the mics match
1446 //Invalid Mic
1447 if (i == 0)
1448 micError = INCORRECTMIC;
1449 continue;
1450 }
1451
1452 //Check Sequence number if mics pass
1453 if (RxSeqValid(ai, context, mcast, micSEQ) == SUCCESS) {
1454 ai->micstats.rxSuccess++;
1455 return SUCCESS;
1456 }
1457 if (i == 0)
1458 micError = SEQUENCE;
1459 }
1460
1461 // Update statistics
1462 switch (micError) {
1463 case NOMICPLUMMED: ai->micstats.rxMICPlummed++; break;
1464 case SEQUENCE: ai->micstats.rxWrongSequence++; break;
1465 case INCORRECTMIC: ai->micstats.rxIncorrectMIC++; break;
1466 case NONE: break;
1467 case NOMIC: break;
1468 }
1469 return ERROR;
1470}
1471
1472/*===========================================================================
1473 * Description: Checks the Rx Seq number to make sure it is valid
1474 * and hasn't already been received
1475 *
1476 * Inputs: miccntx - mic context to check seq against
1477 * micSeq - the Mic seq number
1478 *
1479 * Returns: TRUE if valid otherwise FALSE.
1480 *
1481 * Author: sbraneky (10/15/01)
1482 * Merciless hacks by rwilcher (1/14/02)
1483 *---------------------------------------------------------------------------
1484 */
1485
1486static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq)
1487{
1488 u32 seq,index;
1489
1490 //Allow for the ap being rebooted - if it is then use the next
1491 //sequence number of the current sequence number - might go backwards
1492
1493 if (mcast) {
1494 if (test_bit(FLAG_UPDATE_MULTI, &ai->flags)) {
1495 clear_bit (FLAG_UPDATE_MULTI, &ai->flags);
1496 context->window = (micSeq > 33) ? micSeq : 33;
1497 context->rx = 0; // Reset rx
1498 }
1499 } else if (test_bit(FLAG_UPDATE_UNI, &ai->flags)) {
1500 clear_bit (FLAG_UPDATE_UNI, &ai->flags);
1501 context->window = (micSeq > 33) ? micSeq : 33; // Move window
1502 context->rx = 0; // Reset rx
1503 }
1504
1505 //Make sequence number relative to START of window
1506 seq = micSeq - (context->window - 33);
1507
1508 //Too old of a SEQ number to check.
1509 if ((s32)seq < 0)
1510 return ERROR;
1511
1512 if ( seq > 64 ) {
1513 //Window is infinite forward
1514 MoveWindow(context,micSeq);
1515 return SUCCESS;
1516 }
1517
1518 // We are in the window. Now check the context rx bit to see if it was already sent
1519 seq >>= 1; //divide by 2 because we only have odd numbers
1520 index = 1 << seq; //Get an index number
1521
1522 if (!(context->rx & index)) {
1523 //micSEQ falls inside the window.
1524 //Add seqence number to the list of received numbers.
1525 context->rx |= index;
1526
1527 MoveWindow(context,micSeq);
1528
1529 return SUCCESS;
1530 }
1531 return ERROR;
1532}
1533
1534static void MoveWindow(miccntx *context, u32 micSeq)
1535{
1536 u32 shift;
1537
1538 //Move window if seq greater than the middle of the window
1539 if (micSeq > context->window) {
1540 shift = (micSeq - context->window) >> 1;
1541
1542 //Shift out old
1543 if (shift < 32)
1544 context->rx >>= shift;
1545 else
1546 context->rx = 0;
1547
1548 context->window = micSeq; //Move window
1549 }
1550}
1551
1552/*==============================================*/
1553/*========== EMMH ROUTINES ====================*/
1554/*==============================================*/
1555
1556/* mic accumulate */
1557#define MIC_ACCUM(val) \
1558 context->accum += (u64)(val) * context->coeff[coeff_position++];
1559
1560static unsigned char aes_counter[16];
1561
1562/* expand the key to fill the MMH coefficient array */
Jouni Malinenff1d2762005-05-12 22:54:16 -04001563static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564{
1565 /* take the keying material, expand if necessary, truncate at 16-bytes */
1566 /* run through AES counter mode to generate context->coeff[] */
1567
1568 int i,j;
1569 u32 counter;
1570 u8 *cipher, plain[16];
1571 struct scatterlist sg[1];
1572
1573 crypto_cipher_setkey(tfm, pkey, 16);
1574 counter = 0;
1575 for (i = 0; i < (sizeof(context->coeff)/sizeof(context->coeff[0])); ) {
1576 aes_counter[15] = (u8)(counter >> 0);
1577 aes_counter[14] = (u8)(counter >> 8);
1578 aes_counter[13] = (u8)(counter >> 16);
1579 aes_counter[12] = (u8)(counter >> 24);
1580 counter++;
1581 memcpy (plain, aes_counter, 16);
Herbert Xu6df5b9f2005-09-19 22:30:11 +10001582 sg_set_buf(sg, plain, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 crypto_cipher_encrypt(tfm, sg, sg, 16);
Herbert Xu6df5b9f2005-09-19 22:30:11 +10001584 cipher = kmap(sg->page) + sg->offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 for (j=0; (j<16) && (i< (sizeof(context->coeff)/sizeof(context->coeff[0]))); ) {
1586 context->coeff[i++] = ntohl(*(u32 *)&cipher[j]);
1587 j += 4;
1588 }
1589 }
1590}
1591
1592/* prepare for calculation of a new mic */
Jouni Malinenff1d2762005-05-12 22:54:16 -04001593static void emmh32_init(emmh32_context *context)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594{
1595 /* prepare for new mic calculation */
1596 context->accum = 0;
1597 context->position = 0;
1598}
1599
1600/* add some bytes to the mic calculation */
Jouni Malinenff1d2762005-05-12 22:54:16 -04001601static void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602{
1603 int coeff_position, byte_position;
1604
1605 if (len == 0) return;
1606
1607 coeff_position = context->position >> 2;
1608
1609 /* deal with partial 32-bit word left over from last update */
1610 byte_position = context->position & 3;
1611 if (byte_position) {
1612 /* have a partial word in part to deal with */
1613 do {
1614 if (len == 0) return;
1615 context->part.d8[byte_position++] = *pOctets++;
1616 context->position++;
1617 len--;
1618 } while (byte_position < 4);
1619 MIC_ACCUM(htonl(context->part.d32));
1620 }
1621
1622 /* deal with full 32-bit words */
1623 while (len >= 4) {
1624 MIC_ACCUM(htonl(*(u32 *)pOctets));
1625 context->position += 4;
1626 pOctets += 4;
1627 len -= 4;
1628 }
1629
1630 /* deal with partial 32-bit word that will be left over from this update */
1631 byte_position = 0;
1632 while (len > 0) {
1633 context->part.d8[byte_position++] = *pOctets++;
1634 context->position++;
1635 len--;
1636 }
1637}
1638
1639/* mask used to zero empty bytes for final partial word */
1640static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L };
1641
1642/* calculate the mic */
Jouni Malinenff1d2762005-05-12 22:54:16 -04001643static void emmh32_final(emmh32_context *context, u8 digest[4])
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644{
1645 int coeff_position, byte_position;
1646 u32 val;
1647
1648 u64 sum, utmp;
1649 s64 stmp;
1650
1651 coeff_position = context->position >> 2;
1652
1653 /* deal with partial 32-bit word left over from last update */
1654 byte_position = context->position & 3;
1655 if (byte_position) {
1656 /* have a partial word in part to deal with */
1657 val = htonl(context->part.d32);
1658 MIC_ACCUM(val & mask32[byte_position]); /* zero empty bytes */
1659 }
1660
1661 /* reduce the accumulated u64 to a 32-bit MIC */
1662 sum = context->accum;
1663 stmp = (sum & 0xffffffffLL) - ((sum >> 32) * 15);
1664 utmp = (stmp & 0xffffffffLL) - ((stmp >> 32) * 15);
1665 sum = utmp & 0xffffffffLL;
1666 if (utmp > 0x10000000fLL)
1667 sum -= 15;
1668
1669 val = (u32)sum;
1670 digest[0] = (val>>24) & 0xFF;
1671 digest[1] = (val>>16) & 0xFF;
1672 digest[2] = (val>>8) & 0xFF;
1673 digest[3] = val & 0xFF;
1674}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675
1676static int readBSSListRid(struct airo_info *ai, int first,
1677 BSSListRid *list) {
1678 int rc;
1679 Cmd cmd;
1680 Resp rsp;
1681
1682 if (first == 1) {
1683 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
1684 memset(&cmd, 0, sizeof(cmd));
1685 cmd.cmd=CMD_LISTBSS;
1686 if (down_interruptible(&ai->sem))
1687 return -ERESTARTSYS;
1688 issuecommand(ai, &cmd, &rsp);
1689 up(&ai->sem);
1690 /* Let the command take effect */
1691 ai->task = current;
1692 ssleep(3);
1693 ai->task = NULL;
1694 }
1695 rc = PC4500_readrid(ai, first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT,
1696 list, sizeof(*list), 1);
1697
1698 list->len = le16_to_cpu(list->len);
1699 list->index = le16_to_cpu(list->index);
1700 list->radioType = le16_to_cpu(list->radioType);
1701 list->cap = le16_to_cpu(list->cap);
1702 list->beaconInterval = le16_to_cpu(list->beaconInterval);
1703 list->fh.dwell = le16_to_cpu(list->fh.dwell);
1704 list->dsChannel = le16_to_cpu(list->dsChannel);
1705 list->atimWindow = le16_to_cpu(list->atimWindow);
Dan Williams41480af2005-05-10 09:45:51 -04001706 list->dBm = le16_to_cpu(list->dBm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 return rc;
1708}
1709
1710static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp, int lock) {
1711 int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM,
1712 wkr, sizeof(*wkr), lock);
1713
1714 wkr->len = le16_to_cpu(wkr->len);
1715 wkr->kindex = le16_to_cpu(wkr->kindex);
1716 wkr->klen = le16_to_cpu(wkr->klen);
1717 return rc;
1718}
1719/* In the writeXXXRid routines we copy the rids so that we don't screwup
1720 * the originals when we endian them... */
1721static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm, int lock) {
1722 int rc;
1723 WepKeyRid wkr = *pwkr;
1724
1725 wkr.len = cpu_to_le16(wkr.len);
1726 wkr.kindex = cpu_to_le16(wkr.kindex);
1727 wkr.klen = cpu_to_le16(wkr.klen);
1728 rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr), lock);
1729 if (rc!=SUCCESS) printk(KERN_ERR "airo: WEP_TEMP set %x\n", rc);
1730 if (perm) {
1731 rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr), lock);
1732 if (rc!=SUCCESS) {
1733 printk(KERN_ERR "airo: WEP_PERM set %x\n", rc);
1734 }
1735 }
1736 return rc;
1737}
1738
1739static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) {
1740 int i;
1741 int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1);
1742
1743 ssidr->len = le16_to_cpu(ssidr->len);
1744 for(i = 0; i < 3; i++) {
1745 ssidr->ssids[i].len = le16_to_cpu(ssidr->ssids[i].len);
1746 }
1747 return rc;
1748}
1749static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock) {
1750 int rc;
1751 int i;
1752 SsidRid ssidr = *pssidr;
1753
1754 ssidr.len = cpu_to_le16(ssidr.len);
1755 for(i = 0; i < 3; i++) {
1756 ssidr.ssids[i].len = cpu_to_le16(ssidr.ssids[i].len);
1757 }
1758 rc = PC4500_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr), lock);
1759 return rc;
1760}
1761static int readConfigRid(struct airo_info*ai, int lock) {
1762 int rc;
1763 u16 *s;
1764 ConfigRid cfg;
1765
1766 if (ai->config.len)
1767 return SUCCESS;
1768
1769 rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock);
1770 if (rc != SUCCESS)
1771 return rc;
1772
1773 for(s = &cfg.len; s <= &cfg.rtsThres; s++) *s = le16_to_cpu(*s);
1774
1775 for(s = &cfg.shortRetryLimit; s <= &cfg.radioType; s++)
1776 *s = le16_to_cpu(*s);
1777
1778 for(s = &cfg.txPower; s <= &cfg.radioSpecific; s++)
1779 *s = le16_to_cpu(*s);
1780
1781 for(s = &cfg.arlThreshold; s <= &cfg._reserved4[0]; s++)
1782 *s = cpu_to_le16(*s);
1783
1784 for(s = &cfg.autoWake; s <= &cfg.autoWake; s++)
1785 *s = cpu_to_le16(*s);
1786
1787 ai->config = cfg;
1788 return SUCCESS;
1789}
1790static inline void checkThrottle(struct airo_info *ai) {
1791 int i;
1792/* Old hardware had a limit on encryption speed */
1793 if (ai->config.authType != AUTH_OPEN && maxencrypt) {
1794 for(i=0; i<8; i++) {
1795 if (ai->config.rates[i] > maxencrypt) {
1796 ai->config.rates[i] = 0;
1797 }
1798 }
1799 }
1800}
1801static int writeConfigRid(struct airo_info*ai, int lock) {
1802 u16 *s;
1803 ConfigRid cfgr;
1804
1805 if (!test_bit (FLAG_COMMIT, &ai->flags))
1806 return SUCCESS;
1807
1808 clear_bit (FLAG_COMMIT, &ai->flags);
1809 clear_bit (FLAG_RESET, &ai->flags);
1810 checkThrottle(ai);
1811 cfgr = ai->config;
1812
1813 if ((cfgr.opmode & 0xFF) == MODE_STA_IBSS)
1814 set_bit(FLAG_ADHOC, &ai->flags);
1815 else
1816 clear_bit(FLAG_ADHOC, &ai->flags);
1817
1818 for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s);
1819
1820 for(s = &cfgr.shortRetryLimit; s <= &cfgr.radioType; s++)
1821 *s = cpu_to_le16(*s);
1822
1823 for(s = &cfgr.txPower; s <= &cfgr.radioSpecific; s++)
1824 *s = cpu_to_le16(*s);
1825
1826 for(s = &cfgr.arlThreshold; s <= &cfgr._reserved4[0]; s++)
1827 *s = cpu_to_le16(*s);
1828
1829 for(s = &cfgr.autoWake; s <= &cfgr.autoWake; s++)
1830 *s = cpu_to_le16(*s);
1831
1832 return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock);
1833}
1834static int readStatusRid(struct airo_info*ai, StatusRid *statr, int lock) {
1835 int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock);
1836 u16 *s;
1837
1838 statr->len = le16_to_cpu(statr->len);
1839 for(s = &statr->mode; s <= &statr->SSIDlen; s++) *s = le16_to_cpu(*s);
1840
1841 for(s = &statr->beaconPeriod; s <= &statr->shortPreamble; s++)
1842 *s = le16_to_cpu(*s);
1843 statr->load = le16_to_cpu(statr->load);
1844 statr->assocStatus = le16_to_cpu(statr->assocStatus);
1845 return rc;
1846}
1847static int readAPListRid(struct airo_info*ai, APListRid *aplr) {
1848 int rc = PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr), 1);
1849 aplr->len = le16_to_cpu(aplr->len);
1850 return rc;
1851}
1852static int writeAPListRid(struct airo_info*ai, APListRid *aplr, int lock) {
1853 int rc;
1854 aplr->len = cpu_to_le16(aplr->len);
1855 rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock);
1856 return rc;
1857}
1858static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr, int lock) {
1859 int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock);
1860 u16 *s;
1861
1862 capr->len = le16_to_cpu(capr->len);
1863 capr->prodNum = le16_to_cpu(capr->prodNum);
1864 capr->radioType = le16_to_cpu(capr->radioType);
1865 capr->country = le16_to_cpu(capr->country);
1866 for(s = &capr->txPowerLevels[0]; s <= &capr->requiredHard; s++)
1867 *s = le16_to_cpu(*s);
1868 return rc;
1869}
1870static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) {
1871 int rc = PC4500_readrid(ai, rid, sr, sizeof(*sr), lock);
1872 u32 *i;
1873
1874 sr->len = le16_to_cpu(sr->len);
1875 for(i = &sr->vals[0]; i <= &sr->vals[99]; i++) *i = le32_to_cpu(*i);
1876 return rc;
1877}
1878
1879static int airo_open(struct net_device *dev) {
1880 struct airo_info *info = dev->priv;
1881 Resp rsp;
1882
1883 if (test_bit(FLAG_FLASHING, &info->flags))
1884 return -EIO;
1885
1886 /* Make sure the card is configured.
1887 * Wireless Extensions may postpone config changes until the card
1888 * is open (to pipeline changes and speed-up card setup). If
1889 * those changes are not yet commited, do it now - Jean II */
1890 if (test_bit (FLAG_COMMIT, &info->flags)) {
1891 disable_MAC(info, 1);
1892 writeConfigRid(info, 1);
1893 }
1894
1895 if (info->wifidev != dev) {
1896 /* Power on the MAC controller (which may have been disabled) */
1897 clear_bit(FLAG_RADIO_DOWN, &info->flags);
1898 enable_interrupts(info);
1899 }
1900 enable_MAC(info, &rsp, 1);
1901
1902 netif_start_queue(dev);
1903 return 0;
1904}
1905
1906static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
1907 int npacks, pending;
1908 unsigned long flags;
1909 struct airo_info *ai = dev->priv;
1910
1911 if (!skb) {
1912 printk(KERN_ERR "airo: %s: skb==NULL\n",__FUNCTION__);
1913 return 0;
1914 }
1915 npacks = skb_queue_len (&ai->txq);
1916
1917 if (npacks >= MAXTXQ - 1) {
1918 netif_stop_queue (dev);
1919 if (npacks > MAXTXQ) {
1920 ai->stats.tx_fifo_errors++;
1921 return 1;
1922 }
1923 skb_queue_tail (&ai->txq, skb);
1924 return 0;
1925 }
1926
1927 spin_lock_irqsave(&ai->aux_lock, flags);
1928 skb_queue_tail (&ai->txq, skb);
1929 pending = test_bit(FLAG_PENDING_XMIT, &ai->flags);
1930 spin_unlock_irqrestore(&ai->aux_lock,flags);
1931 netif_wake_queue (dev);
1932
1933 if (pending == 0) {
1934 set_bit(FLAG_PENDING_XMIT, &ai->flags);
1935 mpi_send_packet (dev);
1936 }
1937 return 0;
1938}
1939
1940/*
1941 * @mpi_send_packet
1942 *
1943 * Attempt to transmit a packet. Can be called from interrupt
1944 * or transmit . return number of packets we tried to send
1945 */
1946
1947static int mpi_send_packet (struct net_device *dev)
1948{
1949 struct sk_buff *skb;
1950 unsigned char *buffer;
1951 s16 len, *payloadLen;
1952 struct airo_info *ai = dev->priv;
1953 u8 *sendbuf;
1954
1955 /* get a packet to send */
1956
1957 if ((skb = skb_dequeue(&ai->txq)) == 0) {
1958 printk (KERN_ERR
1959 "airo: %s: Dequeue'd zero in send_packet()\n",
1960 __FUNCTION__);
1961 return 0;
1962 }
1963
1964 /* check min length*/
1965 len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
1966 buffer = skb->data;
1967
1968 ai->txfids[0].tx_desc.offset = 0;
1969 ai->txfids[0].tx_desc.valid = 1;
1970 ai->txfids[0].tx_desc.eoc = 1;
1971 ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr);
1972
1973/*
1974 * Magic, the cards firmware needs a length count (2 bytes) in the host buffer
1975 * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen
1976 * is immediatly after it. ------------------------------------------------
1977 * |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA|
1978 * ------------------------------------------------
1979 */
1980
1981 memcpy((char *)ai->txfids[0].virtual_host_addr,
1982 (char *)&wifictlhdr8023, sizeof(wifictlhdr8023));
1983
1984 payloadLen = (s16 *)(ai->txfids[0].virtual_host_addr +
1985 sizeof(wifictlhdr8023));
1986 sendbuf = ai->txfids[0].virtual_host_addr +
1987 sizeof(wifictlhdr8023) + 2 ;
1988
1989 /*
1990 * Firmware automaticly puts 802 header on so
1991 * we don't need to account for it in the length
1992 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
1994 (ntohs(((u16 *)buffer)[6]) != 0x888E)) {
1995 MICBuffer pMic;
1996
1997 if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS)
1998 return ERROR;
1999
2000 *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic));
2001 ai->txfids[0].tx_desc.len += sizeof(pMic);
2002 /* copy data into airo dma buffer */
2003 memcpy (sendbuf, buffer, sizeof(etherHead));
2004 buffer += sizeof(etherHead);
2005 sendbuf += sizeof(etherHead);
2006 memcpy (sendbuf, &pMic, sizeof(pMic));
2007 sendbuf += sizeof(pMic);
2008 memcpy (sendbuf, buffer, len - sizeof(etherHead));
Adrian Bunka39d3e72006-01-21 01:35:15 +01002009 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 *payloadLen = cpu_to_le16(len - sizeof(etherHead));
2011
2012 dev->trans_start = jiffies;
2013
2014 /* copy data into airo dma buffer */
2015 memcpy(sendbuf, buffer, len);
2016 }
2017
2018 memcpy_toio(ai->txfids[0].card_ram_off,
2019 &ai->txfids[0].tx_desc, sizeof(TxFid));
2020
2021 OUT4500(ai, EVACK, 8);
2022
2023 dev_kfree_skb_any(skb);
2024 return 1;
2025}
2026
Gabriel A. Devenyi29b09fc2005-11-03 19:30:47 -05002027static void get_tx_error(struct airo_info *ai, s32 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028{
2029 u16 status;
2030
2031 if (fid < 0)
2032 status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status;
2033 else {
2034 if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) != SUCCESS)
2035 return;
2036 bap_read(ai, &status, 2, BAP0);
2037 }
2038 if (le16_to_cpu(status) & 2) /* Too many retries */
2039 ai->stats.tx_aborted_errors++;
2040 if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */
2041 ai->stats.tx_heartbeat_errors++;
2042 if (le16_to_cpu(status) & 8) /* Aid fail */
2043 { }
2044 if (le16_to_cpu(status) & 0x10) /* MAC disabled */
2045 ai->stats.tx_carrier_errors++;
2046 if (le16_to_cpu(status) & 0x20) /* Association lost */
2047 { }
2048 /* We produce a TXDROP event only for retry or lifetime
2049 * exceeded, because that's the only status that really mean
2050 * that this particular node went away.
2051 * Other errors means that *we* screwed up. - Jean II */
2052 if ((le16_to_cpu(status) & 2) ||
2053 (le16_to_cpu(status) & 4)) {
2054 union iwreq_data wrqu;
2055 char junk[0x18];
2056
2057 /* Faster to skip over useless data than to do
2058 * another bap_setup(). We are at offset 0x6 and
2059 * need to go to 0x18 and read 6 bytes - Jean II */
2060 bap_read(ai, (u16 *) junk, 0x18, BAP0);
2061
2062 /* Copy 802.11 dest address.
2063 * We use the 802.11 header because the frame may
2064 * not be 802.3 or may be mangled...
2065 * In Ad-Hoc mode, it will be the node address.
2066 * In managed mode, it will be most likely the AP addr
2067 * User space will figure out how to convert it to
2068 * whatever it needs (IP address or else).
2069 * - Jean II */
2070 memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN);
2071 wrqu.addr.sa_family = ARPHRD_ETHER;
2072
2073 /* Send event to user space */
2074 wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL);
2075 }
2076}
2077
2078static void airo_end_xmit(struct net_device *dev) {
2079 u16 status;
2080 int i;
2081 struct airo_info *priv = dev->priv;
2082 struct sk_buff *skb = priv->xmit.skb;
2083 int fid = priv->xmit.fid;
2084 u32 *fids = priv->fids;
2085
2086 clear_bit(JOB_XMIT, &priv->flags);
2087 clear_bit(FLAG_PENDING_XMIT, &priv->flags);
2088 status = transmit_802_3_packet (priv, fids[fid], skb->data);
2089 up(&priv->sem);
2090
2091 i = 0;
2092 if ( status == SUCCESS ) {
2093 dev->trans_start = jiffies;
2094 for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++);
2095 } else {
2096 priv->fids[fid] &= 0xffff;
2097 priv->stats.tx_window_errors++;
2098 }
2099 if (i < MAX_FIDS / 2)
2100 netif_wake_queue(dev);
2101 dev_kfree_skb(skb);
2102}
2103
2104static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
2105 s16 len;
2106 int i, j;
2107 struct airo_info *priv = dev->priv;
2108 u32 *fids = priv->fids;
2109
2110 if ( skb == NULL ) {
2111 printk( KERN_ERR "airo: skb == NULL!!!\n" );
2112 return 0;
2113 }
2114
2115 /* Find a vacant FID */
2116 for( i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++ );
2117 for( j = i + 1; j < MAX_FIDS / 2 && (fids[j] & 0xffff0000); j++ );
2118
2119 if ( j >= MAX_FIDS / 2 ) {
2120 netif_stop_queue(dev);
2121
2122 if (i == MAX_FIDS / 2) {
2123 priv->stats.tx_fifo_errors++;
2124 return 1;
2125 }
2126 }
2127 /* check min length*/
2128 len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
2129 /* Mark fid as used & save length for later */
2130 fids[i] |= (len << 16);
2131 priv->xmit.skb = skb;
2132 priv->xmit.fid = i;
2133 if (down_trylock(&priv->sem) != 0) {
2134 set_bit(FLAG_PENDING_XMIT, &priv->flags);
2135 netif_stop_queue(dev);
2136 set_bit(JOB_XMIT, &priv->flags);
2137 wake_up_interruptible(&priv->thr_wait);
2138 } else
2139 airo_end_xmit(dev);
2140 return 0;
2141}
2142
2143static void airo_end_xmit11(struct net_device *dev) {
2144 u16 status;
2145 int i;
2146 struct airo_info *priv = dev->priv;
2147 struct sk_buff *skb = priv->xmit11.skb;
2148 int fid = priv->xmit11.fid;
2149 u32 *fids = priv->fids;
2150
2151 clear_bit(JOB_XMIT11, &priv->flags);
2152 clear_bit(FLAG_PENDING_XMIT11, &priv->flags);
2153 status = transmit_802_11_packet (priv, fids[fid], skb->data);
2154 up(&priv->sem);
2155
2156 i = MAX_FIDS / 2;
2157 if ( status == SUCCESS ) {
2158 dev->trans_start = jiffies;
2159 for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++);
2160 } else {
2161 priv->fids[fid] &= 0xffff;
2162 priv->stats.tx_window_errors++;
2163 }
2164 if (i < MAX_FIDS)
2165 netif_wake_queue(dev);
2166 dev_kfree_skb(skb);
2167}
2168
2169static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
2170 s16 len;
2171 int i, j;
2172 struct airo_info *priv = dev->priv;
2173 u32 *fids = priv->fids;
2174
2175 if (test_bit(FLAG_MPI, &priv->flags)) {
2176 /* Not implemented yet for MPI350 */
2177 netif_stop_queue(dev);
2178 return -ENETDOWN;
2179 }
2180
2181 if ( skb == NULL ) {
2182 printk( KERN_ERR "airo: skb == NULL!!!\n" );
2183 return 0;
2184 }
2185
2186 /* Find a vacant FID */
2187 for( i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++ );
2188 for( j = i + 1; j < MAX_FIDS && (fids[j] & 0xffff0000); j++ );
2189
2190 if ( j >= MAX_FIDS ) {
2191 netif_stop_queue(dev);
2192
2193 if (i == MAX_FIDS) {
2194 priv->stats.tx_fifo_errors++;
2195 return 1;
2196 }
2197 }
2198 /* check min length*/
2199 len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
2200 /* Mark fid as used & save length for later */
2201 fids[i] |= (len << 16);
2202 priv->xmit11.skb = skb;
2203 priv->xmit11.fid = i;
2204 if (down_trylock(&priv->sem) != 0) {
2205 set_bit(FLAG_PENDING_XMIT11, &priv->flags);
2206 netif_stop_queue(dev);
2207 set_bit(JOB_XMIT11, &priv->flags);
2208 wake_up_interruptible(&priv->thr_wait);
2209 } else
2210 airo_end_xmit11(dev);
2211 return 0;
2212}
2213
2214static void airo_read_stats(struct airo_info *ai) {
2215 StatsRid stats_rid;
2216 u32 *vals = stats_rid.vals;
2217
2218 clear_bit(JOB_STATS, &ai->flags);
Pavel Machekca078ba2005-09-03 15:56:57 -07002219 if (ai->power.event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 up(&ai->sem);
2221 return;
2222 }
2223 readStatsRid(ai, &stats_rid, RID_STATS, 0);
2224 up(&ai->sem);
2225
2226 ai->stats.rx_packets = vals[43] + vals[44] + vals[45];
2227 ai->stats.tx_packets = vals[39] + vals[40] + vals[41];
2228 ai->stats.rx_bytes = vals[92];
2229 ai->stats.tx_bytes = vals[91];
2230 ai->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4];
2231 ai->stats.tx_errors = vals[42] + ai->stats.tx_fifo_errors;
2232 ai->stats.multicast = vals[43];
2233 ai->stats.collisions = vals[89];
2234
2235 /* detailed rx_errors: */
2236 ai->stats.rx_length_errors = vals[3];
2237 ai->stats.rx_crc_errors = vals[4];
2238 ai->stats.rx_frame_errors = vals[2];
2239 ai->stats.rx_fifo_errors = vals[0];
2240}
2241
Jouni Malinenff1d2762005-05-12 22:54:16 -04002242static struct net_device_stats *airo_get_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243{
2244 struct airo_info *local = dev->priv;
2245
2246 if (!test_bit(JOB_STATS, &local->flags)) {
2247 /* Get stats out of the card if available */
2248 if (down_trylock(&local->sem) != 0) {
2249 set_bit(JOB_STATS, &local->flags);
2250 wake_up_interruptible(&local->thr_wait);
2251 } else
2252 airo_read_stats(local);
2253 }
2254
2255 return &local->stats;
2256}
2257
2258static void airo_set_promisc(struct airo_info *ai) {
2259 Cmd cmd;
2260 Resp rsp;
2261
2262 memset(&cmd, 0, sizeof(cmd));
2263 cmd.cmd=CMD_SETMODE;
2264 clear_bit(JOB_PROMISC, &ai->flags);
2265 cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
2266 issuecommand(ai, &cmd, &rsp);
2267 up(&ai->sem);
2268}
2269
2270static void airo_set_multicast_list(struct net_device *dev) {
2271 struct airo_info *ai = dev->priv;
2272
2273 if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
2274 change_bit(FLAG_PROMISC, &ai->flags);
2275 if (down_trylock(&ai->sem) != 0) {
2276 set_bit(JOB_PROMISC, &ai->flags);
2277 wake_up_interruptible(&ai->thr_wait);
2278 } else
2279 airo_set_promisc(ai);
2280 }
2281
2282 if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) {
2283 /* Turn on multicast. (Should be already setup...) */
2284 }
2285}
2286
2287static int airo_set_mac_address(struct net_device *dev, void *p)
2288{
2289 struct airo_info *ai = dev->priv;
2290 struct sockaddr *addr = p;
2291 Resp rsp;
2292
2293 readConfigRid(ai, 1);
2294 memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
2295 set_bit (FLAG_COMMIT, &ai->flags);
2296 disable_MAC(ai, 1);
2297 writeConfigRid (ai, 1);
2298 enable_MAC(ai, &rsp, 1);
2299 memcpy (ai->dev->dev_addr, addr->sa_data, dev->addr_len);
2300 if (ai->wifidev)
2301 memcpy (ai->wifidev->dev_addr, addr->sa_data, dev->addr_len);
2302 return 0;
2303}
2304
2305static int airo_change_mtu(struct net_device *dev, int new_mtu)
2306{
2307 if ((new_mtu < 68) || (new_mtu > 2400))
2308 return -EINVAL;
2309 dev->mtu = new_mtu;
2310 return 0;
2311}
2312
2313
2314static int airo_close(struct net_device *dev) {
2315 struct airo_info *ai = dev->priv;
2316
2317 netif_stop_queue(dev);
2318
2319 if (ai->wifidev != dev) {
2320#ifdef POWER_ON_DOWN
2321 /* Shut power to the card. The idea is that the user can save
2322 * power when he doesn't need the card with "ifconfig down".
2323 * That's the method that is most friendly towards the network
2324 * stack (i.e. the network stack won't try to broadcast
2325 * anything on the interface and routes are gone. Jean II */
2326 set_bit(FLAG_RADIO_DOWN, &ai->flags);
2327 disable_MAC(ai, 1);
2328#endif
2329 disable_interrupts( ai );
2330 }
2331 return 0;
2332}
2333
2334static void del_airo_dev( struct net_device *dev );
2335
2336void stop_airo_card( struct net_device *dev, int freeres )
2337{
2338 struct airo_info *ai = dev->priv;
2339
2340 set_bit(FLAG_RADIO_DOWN, &ai->flags);
2341 disable_MAC(ai, 1);
2342 disable_interrupts(ai);
2343 free_irq( dev->irq, dev );
2344 takedown_proc_entry( dev, ai );
2345 if (test_bit(FLAG_REGISTERED, &ai->flags)) {
2346 unregister_netdev( dev );
2347 if (ai->wifidev) {
2348 unregister_netdev(ai->wifidev);
2349 free_netdev(ai->wifidev);
2350 ai->wifidev = NULL;
2351 }
2352 clear_bit(FLAG_REGISTERED, &ai->flags);
2353 }
2354 set_bit(JOB_DIE, &ai->flags);
2355 kill_proc(ai->thr_pid, SIGTERM, 1);
2356 wait_for_completion(&ai->thr_exited);
2357
2358 /*
2359 * Clean out tx queue
2360 */
David S. Millerb03efcf2005-07-08 14:57:23 -07002361 if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 struct sk_buff *skb = NULL;
2363 for (;(skb = skb_dequeue(&ai->txq));)
2364 dev_kfree_skb(skb);
2365 }
2366
Jesper Juhlb4558ea2005-10-28 16:53:13 -04002367 kfree(ai->flash);
2368 kfree(ai->rssi);
2369 kfree(ai->APList);
2370 kfree(ai->SSID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 if (freeres) {
2372 /* PCMCIA frees this stuff, so only for PCI and ISA */
2373 release_region( dev->base_addr, 64 );
2374 if (test_bit(FLAG_MPI, &ai->flags)) {
2375 if (ai->pci)
2376 mpi_unmap_card(ai->pci);
2377 if (ai->pcimem)
2378 iounmap(ai->pcimem);
2379 if (ai->pciaux)
2380 iounmap(ai->pciaux);
2381 pci_free_consistent(ai->pci, PCI_SHARED_LEN,
2382 ai->shared, ai->shared_dma);
2383 }
2384 }
Jesper Juhl573dbd92005-09-01 17:44:29 -07002385 crypto_free_tfm(ai->tfm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 del_airo_dev( dev );
2387 free_netdev( dev );
2388}
2389
2390EXPORT_SYMBOL(stop_airo_card);
2391
2392static int add_airo_dev( struct net_device *dev );
2393
Jouni Malinenff1d2762005-05-12 22:54:16 -04002394static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395{
2396 memcpy(haddr, skb->mac.raw + 10, ETH_ALEN);
2397 return ETH_ALEN;
2398}
2399
2400static void mpi_unmap_card(struct pci_dev *pci)
2401{
2402 unsigned long mem_start = pci_resource_start(pci, 1);
2403 unsigned long mem_len = pci_resource_len(pci, 1);
2404 unsigned long aux_start = pci_resource_start(pci, 2);
2405 unsigned long aux_len = AUXMEMSIZE;
2406
2407 release_mem_region(aux_start, aux_len);
2408 release_mem_region(mem_start, mem_len);
2409}
2410
2411/*************************************************************
2412 * This routine assumes that descriptors have been setup .
2413 * Run at insmod time or after reset when the decriptors
2414 * have been initialized . Returns 0 if all is well nz
2415 * otherwise . Does not allocate memory but sets up card
2416 * using previously allocated descriptors.
2417 */
2418static int mpi_init_descriptors (struct airo_info *ai)
2419{
2420 Cmd cmd;
2421 Resp rsp;
2422 int i;
2423 int rc = SUCCESS;
2424
2425 /* Alloc card RX descriptors */
2426 netif_stop_queue(ai->dev);
2427
2428 memset(&rsp,0,sizeof(rsp));
2429 memset(&cmd,0,sizeof(cmd));
2430
2431 cmd.cmd = CMD_ALLOCATEAUX;
2432 cmd.parm0 = FID_RX;
2433 cmd.parm1 = (ai->rxfids[0].card_ram_off - ai->pciaux);
2434 cmd.parm2 = MPI_MAX_FIDS;
2435 rc=issuecommand(ai, &cmd, &rsp);
2436 if (rc != SUCCESS) {
2437 printk(KERN_ERR "airo: Couldn't allocate RX FID\n");
2438 return rc;
2439 }
2440
2441 for (i=0; i<MPI_MAX_FIDS; i++) {
2442 memcpy_toio(ai->rxfids[i].card_ram_off,
2443 &ai->rxfids[i].rx_desc, sizeof(RxFid));
2444 }
2445
2446 /* Alloc card TX descriptors */
2447
2448 memset(&rsp,0,sizeof(rsp));
2449 memset(&cmd,0,sizeof(cmd));
2450
2451 cmd.cmd = CMD_ALLOCATEAUX;
2452 cmd.parm0 = FID_TX;
2453 cmd.parm1 = (ai->txfids[0].card_ram_off - ai->pciaux);
2454 cmd.parm2 = MPI_MAX_FIDS;
2455
2456 for (i=0; i<MPI_MAX_FIDS; i++) {
2457 ai->txfids[i].tx_desc.valid = 1;
2458 memcpy_toio(ai->txfids[i].card_ram_off,
2459 &ai->txfids[i].tx_desc, sizeof(TxFid));
2460 }
2461 ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
2462
2463 rc=issuecommand(ai, &cmd, &rsp);
2464 if (rc != SUCCESS) {
2465 printk(KERN_ERR "airo: Couldn't allocate TX FID\n");
2466 return rc;
2467 }
2468
2469 /* Alloc card Rid descriptor */
2470 memset(&rsp,0,sizeof(rsp));
2471 memset(&cmd,0,sizeof(cmd));
2472
2473 cmd.cmd = CMD_ALLOCATEAUX;
2474 cmd.parm0 = RID_RW;
2475 cmd.parm1 = (ai->config_desc.card_ram_off - ai->pciaux);
2476 cmd.parm2 = 1; /* Magic number... */
2477 rc=issuecommand(ai, &cmd, &rsp);
2478 if (rc != SUCCESS) {
2479 printk(KERN_ERR "airo: Couldn't allocate RID\n");
2480 return rc;
2481 }
2482
2483 memcpy_toio(ai->config_desc.card_ram_off,
2484 &ai->config_desc.rid_desc, sizeof(Rid));
2485
2486 return rc;
2487}
2488
2489/*
2490 * We are setting up three things here:
2491 * 1) Map AUX memory for descriptors: Rid, TxFid, or RxFid.
2492 * 2) Map PCI memory for issueing commands.
2493 * 3) Allocate memory (shared) to send and receive ethernet frames.
2494 */
2495static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
2496 const char *name)
2497{
2498 unsigned long mem_start, mem_len, aux_start, aux_len;
2499 int rc = -1;
2500 int i;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002501 dma_addr_t busaddroff;
2502 unsigned char *vpackoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 unsigned char __iomem *pciaddroff;
2504
2505 mem_start = pci_resource_start(pci, 1);
2506 mem_len = pci_resource_len(pci, 1);
2507 aux_start = pci_resource_start(pci, 2);
2508 aux_len = AUXMEMSIZE;
2509
2510 if (!request_mem_region(mem_start, mem_len, name)) {
2511 printk(KERN_ERR "airo: Couldn't get region %x[%x] for %s\n",
2512 (int)mem_start, (int)mem_len, name);
2513 goto out;
2514 }
2515 if (!request_mem_region(aux_start, aux_len, name)) {
2516 printk(KERN_ERR "airo: Couldn't get region %x[%x] for %s\n",
2517 (int)aux_start, (int)aux_len, name);
2518 goto free_region1;
2519 }
2520
2521 ai->pcimem = ioremap(mem_start, mem_len);
2522 if (!ai->pcimem) {
2523 printk(KERN_ERR "airo: Couldn't map region %x[%x] for %s\n",
2524 (int)mem_start, (int)mem_len, name);
2525 goto free_region2;
2526 }
2527 ai->pciaux = ioremap(aux_start, aux_len);
2528 if (!ai->pciaux) {
2529 printk(KERN_ERR "airo: Couldn't map region %x[%x] for %s\n",
2530 (int)aux_start, (int)aux_len, name);
2531 goto free_memmap;
2532 }
2533
2534 /* Reserve PKTSIZE for each fid and 2K for the Rids */
2535 ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma);
2536 if (!ai->shared) {
2537 printk(KERN_ERR "airo: Couldn't alloc_consistent %d\n",
2538 PCI_SHARED_LEN);
2539 goto free_auxmap;
2540 }
2541
2542 /*
2543 * Setup descriptor RX, TX, CONFIG
2544 */
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002545 busaddroff = ai->shared_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 pciaddroff = ai->pciaux + AUX_OFFSET;
2547 vpackoff = ai->shared;
2548
2549 /* RX descriptor setup */
2550 for(i = 0; i < MPI_MAX_FIDS; i++) {
2551 ai->rxfids[i].pending = 0;
2552 ai->rxfids[i].card_ram_off = pciaddroff;
2553 ai->rxfids[i].virtual_host_addr = vpackoff;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002554 ai->rxfids[i].rx_desc.host_addr = busaddroff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 ai->rxfids[i].rx_desc.valid = 1;
2556 ai->rxfids[i].rx_desc.len = PKTSIZE;
2557 ai->rxfids[i].rx_desc.rdy = 0;
2558
2559 pciaddroff += sizeof(RxFid);
2560 busaddroff += PKTSIZE;
2561 vpackoff += PKTSIZE;
2562 }
2563
2564 /* TX descriptor setup */
2565 for(i = 0; i < MPI_MAX_FIDS; i++) {
2566 ai->txfids[i].card_ram_off = pciaddroff;
2567 ai->txfids[i].virtual_host_addr = vpackoff;
2568 ai->txfids[i].tx_desc.valid = 1;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002569 ai->txfids[i].tx_desc.host_addr = busaddroff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 memcpy(ai->txfids[i].virtual_host_addr,
2571 &wifictlhdr8023, sizeof(wifictlhdr8023));
2572
2573 pciaddroff += sizeof(TxFid);
2574 busaddroff += PKTSIZE;
2575 vpackoff += PKTSIZE;
2576 }
2577 ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
2578
2579 /* Rid descriptor setup */
2580 ai->config_desc.card_ram_off = pciaddroff;
2581 ai->config_desc.virtual_host_addr = vpackoff;
Jeff Garzik2759c8d2005-09-24 04:09:04 -04002582 ai->config_desc.rid_desc.host_addr = busaddroff;
2583 ai->ridbus = busaddroff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 ai->config_desc.rid_desc.rid = 0;
2585 ai->config_desc.rid_desc.len = RIDSIZE;
2586 ai->config_desc.rid_desc.valid = 1;
2587 pciaddroff += sizeof(Rid);
2588 busaddroff += RIDSIZE;
2589 vpackoff += RIDSIZE;
2590
2591 /* Tell card about descriptors */
2592 if (mpi_init_descriptors (ai) != SUCCESS)
2593 goto free_shared;
2594
2595 return 0;
2596 free_shared:
2597 pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
2598 free_auxmap:
2599 iounmap(ai->pciaux);
2600 free_memmap:
2601 iounmap(ai->pcimem);
2602 free_region2:
2603 release_mem_region(aux_start, aux_len);
2604 free_region1:
2605 release_mem_region(mem_start, mem_len);
2606 out:
2607 return rc;
2608}
2609
2610static void wifi_setup(struct net_device *dev)
2611{
2612 dev->hard_header = NULL;
2613 dev->rebuild_header = NULL;
2614 dev->hard_header_cache = NULL;
2615 dev->header_cache_update= NULL;
2616
2617 dev->hard_header_parse = wll_header_parse;
2618 dev->hard_start_xmit = &airo_start_xmit11;
2619 dev->get_stats = &airo_get_stats;
2620 dev->set_mac_address = &airo_set_mac_address;
2621 dev->do_ioctl = &airo_ioctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 dev->wireless_handlers = &airo_handler_def;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 dev->change_mtu = &airo_change_mtu;
2624 dev->open = &airo_open;
2625 dev->stop = &airo_close;
2626
2627 dev->type = ARPHRD_IEEE80211;
2628 dev->hard_header_len = ETH_HLEN;
2629 dev->mtu = 2312;
2630 dev->addr_len = ETH_ALEN;
2631 dev->tx_queue_len = 100;
2632
2633 memset(dev->broadcast,0xFF, ETH_ALEN);
2634
2635 dev->flags = IFF_BROADCAST|IFF_MULTICAST;
2636}
2637
2638static struct net_device *init_wifidev(struct airo_info *ai,
2639 struct net_device *ethdev)
2640{
2641 int err;
2642 struct net_device *dev = alloc_netdev(0, "wifi%d", wifi_setup);
2643 if (!dev)
2644 return NULL;
2645 dev->priv = ethdev->priv;
2646 dev->irq = ethdev->irq;
2647 dev->base_addr = ethdev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 dev->wireless_data = ethdev->wireless_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len);
2650 err = register_netdev(dev);
2651 if (err<0) {
2652 free_netdev(dev);
2653 return NULL;
2654 }
2655 return dev;
2656}
2657
Jouni Malinenff1d2762005-05-12 22:54:16 -04002658static int reset_card( struct net_device *dev , int lock) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 struct airo_info *ai = dev->priv;
2660
2661 if (lock && down_interruptible(&ai->sem))
2662 return -1;
2663 waitbusy (ai);
2664 OUT4500(ai,COMMAND,CMD_SOFTRESET);
2665 msleep(200);
2666 waitbusy (ai);
2667 msleep(200);
2668 if (lock)
2669 up(&ai->sem);
2670 return 0;
2671}
2672
Jouni Malinenff1d2762005-05-12 22:54:16 -04002673static struct net_device *_init_airo_card( unsigned short irq, int port,
2674 int is_pcmcia, struct pci_dev *pci,
2675 struct device *dmdev )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676{
2677 struct net_device *dev;
2678 struct airo_info *ai;
2679 int i, rc;
2680
2681 /* Create the network device object. */
2682 dev = alloc_etherdev(sizeof(*ai));
2683 if (!dev) {
2684 printk(KERN_ERR "airo: Couldn't alloc_etherdev\n");
2685 return NULL;
2686 }
2687 if (dev_alloc_name(dev, dev->name) < 0) {
2688 printk(KERN_ERR "airo: Couldn't get name!\n");
2689 goto err_out_free;
2690 }
2691
2692 ai = dev->priv;
2693 ai->wifidev = NULL;
2694 ai->flags = 0;
2695 if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
2696 printk(KERN_DEBUG "airo: Found an MPI350 card\n");
2697 set_bit(FLAG_MPI, &ai->flags);
2698 }
2699 ai->dev = dev;
2700 spin_lock_init(&ai->aux_lock);
2701 sema_init(&ai->sem, 1);
2702 ai->config.len = 0;
2703 ai->pci = pci;
2704 init_waitqueue_head (&ai->thr_wait);
2705 init_completion (&ai->thr_exited);
2706 ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES);
2707 if (ai->thr_pid < 0)
2708 goto err_out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 ai->tfm = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 rc = add_airo_dev( dev );
2711 if (rc)
2712 goto err_out_thr;
2713
2714 /* The Airo-specific entries in the device structure. */
2715 if (test_bit(FLAG_MPI,&ai->flags)) {
2716 skb_queue_head_init (&ai->txq);
2717 dev->hard_start_xmit = &mpi_start_xmit;
2718 } else
2719 dev->hard_start_xmit = &airo_start_xmit;
2720 dev->get_stats = &airo_get_stats;
2721 dev->set_multicast_list = &airo_set_multicast_list;
2722 dev->set_mac_address = &airo_set_mac_address;
2723 dev->do_ioctl = &airo_ioctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 dev->wireless_handlers = &airo_handler_def;
2725 ai->wireless_data.spy_data = &ai->spy_data;
2726 dev->wireless_data = &ai->wireless_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 dev->change_mtu = &airo_change_mtu;
2728 dev->open = &airo_open;
2729 dev->stop = &airo_close;
2730 dev->irq = irq;
2731 dev->base_addr = port;
2732
2733 SET_NETDEV_DEV(dev, dmdev);
2734
2735
Matthieu CASTET1d97f382005-12-01 02:35:26 -05002736 reset_card (dev, 1);
2737 msleep(400);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738
2739 rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev );
2740 if (rc) {
2741 printk(KERN_ERR "airo: register interrupt %d failed, rc %d\n", irq, rc );
2742 goto err_out_unlink;
2743 }
2744 if (!is_pcmcia) {
2745 if (!request_region( dev->base_addr, 64, dev->name )) {
2746 rc = -EBUSY;
2747 printk(KERN_ERR "airo: Couldn't request region\n");
2748 goto err_out_irq;
2749 }
2750 }
2751
2752 if (test_bit(FLAG_MPI,&ai->flags)) {
2753 if (mpi_map_card(ai, pci, dev->name)) {
2754 printk(KERN_ERR "airo: Could not map memory\n");
2755 goto err_out_res;
2756 }
2757 }
2758
2759 if (probe) {
2760 if ( setup_card( ai, dev->dev_addr, 1 ) != SUCCESS ) {
2761 printk( KERN_ERR "airo: MAC could not be enabled\n" );
2762 rc = -EIO;
2763 goto err_out_map;
2764 }
2765 } else if (!test_bit(FLAG_MPI,&ai->flags)) {
2766 ai->bap_read = fast_bap_read;
2767 set_bit(FLAG_FLASHING, &ai->flags);
2768 }
2769
2770 rc = register_netdev(dev);
2771 if (rc) {
2772 printk(KERN_ERR "airo: Couldn't register_netdev\n");
2773 goto err_out_map;
2774 }
2775 ai->wifidev = init_wifidev(ai, dev);
2776
2777 set_bit(FLAG_REGISTERED,&ai->flags);
2778 printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
2779 dev->name,
2780 dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
2781 dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
2782
2783 /* Allocate the transmit buffers */
2784 if (probe && !test_bit(FLAG_MPI,&ai->flags))
2785 for( i = 0; i < MAX_FIDS; i++ )
2786 ai->fids[i] = transmit_allocate(ai,2312,i>=MAX_FIDS/2);
2787
2788 setup_proc_entry( dev, dev->priv ); /* XXX check for failure */
2789 netif_start_queue(dev);
2790 SET_MODULE_OWNER(dev);
2791 return dev;
2792
2793err_out_map:
2794 if (test_bit(FLAG_MPI,&ai->flags) && pci) {
2795 pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
2796 iounmap(ai->pciaux);
2797 iounmap(ai->pcimem);
2798 mpi_unmap_card(ai->pci);
2799 }
2800err_out_res:
2801 if (!is_pcmcia)
2802 release_region( dev->base_addr, 64 );
2803err_out_irq:
2804 free_irq(dev->irq, dev);
2805err_out_unlink:
2806 del_airo_dev(dev);
2807err_out_thr:
2808 set_bit(JOB_DIE, &ai->flags);
2809 kill_proc(ai->thr_pid, SIGTERM, 1);
2810 wait_for_completion(&ai->thr_exited);
2811err_out_free:
2812 free_netdev(dev);
2813 return NULL;
2814}
2815
2816struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia,
2817 struct device *dmdev)
2818{
2819 return _init_airo_card ( irq, port, is_pcmcia, NULL, dmdev);
2820}
2821
2822EXPORT_SYMBOL(init_airo_card);
2823
2824static int waitbusy (struct airo_info *ai) {
2825 int delay = 0;
2826 while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) & (delay < 10000)) {
2827 udelay (10);
2828 if ((++delay % 20) == 0)
2829 OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
2830 }
2831 return delay < 10000;
2832}
2833
2834int reset_airo_card( struct net_device *dev )
2835{
2836 int i;
2837 struct airo_info *ai = dev->priv;
2838
2839 if (reset_card (dev, 1))
2840 return -1;
2841
2842 if ( setup_card(ai, dev->dev_addr, 1 ) != SUCCESS ) {
2843 printk( KERN_ERR "airo: MAC could not be enabled\n" );
2844 return -1;
2845 }
2846 printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n", dev->name,
2847 dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
2848 dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
2849 /* Allocate the transmit buffers if needed */
2850 if (!test_bit(FLAG_MPI,&ai->flags))
2851 for( i = 0; i < MAX_FIDS; i++ )
2852 ai->fids[i] = transmit_allocate (ai,2312,i>=MAX_FIDS/2);
2853
2854 enable_interrupts( ai );
2855 netif_wake_queue(dev);
2856 return 0;
2857}
2858
2859EXPORT_SYMBOL(reset_airo_card);
2860
2861static void airo_send_event(struct net_device *dev) {
2862 struct airo_info *ai = dev->priv;
2863 union iwreq_data wrqu;
2864 StatusRid status_rid;
2865
2866 clear_bit(JOB_EVENT, &ai->flags);
2867 PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
2868 up(&ai->sem);
2869 wrqu.data.length = 0;
2870 wrqu.data.flags = 0;
2871 memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN);
2872 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
2873
2874 /* Send event to user space */
2875 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
2876}
2877
2878static int airo_thread(void *data) {
2879 struct net_device *dev = data;
2880 struct airo_info *ai = dev->priv;
2881 int locked;
2882
2883 daemonize("%s", dev->name);
2884 allow_signal(SIGTERM);
2885
2886 while(1) {
2887 if (signal_pending(current))
2888 flush_signals(current);
2889
2890 /* make swsusp happy with our thread */
Christoph Lameter3e1d1d22005-06-24 23:13:50 -07002891 try_to_freeze();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892
2893 if (test_bit(JOB_DIE, &ai->flags))
2894 break;
2895
2896 if (ai->flags & JOB_MASK) {
2897 locked = down_interruptible(&ai->sem);
2898 } else {
2899 wait_queue_t wait;
2900
2901 init_waitqueue_entry(&wait, current);
2902 add_wait_queue(&ai->thr_wait, &wait);
2903 for (;;) {
2904 set_current_state(TASK_INTERRUPTIBLE);
2905 if (ai->flags & JOB_MASK)
2906 break;
2907 if (ai->expires) {
2908 if (time_after_eq(jiffies,ai->expires)){
2909 set_bit(JOB_AUTOWEP,&ai->flags);
2910 break;
2911 }
2912 if (!signal_pending(current)) {
2913 schedule_timeout(ai->expires - jiffies);
2914 continue;
2915 }
2916 } else if (!signal_pending(current)) {
2917 schedule();
2918 continue;
2919 }
2920 break;
2921 }
2922 current->state = TASK_RUNNING;
2923 remove_wait_queue(&ai->thr_wait, &wait);
2924 locked = 1;
2925 }
2926
2927 if (locked)
2928 continue;
2929
2930 if (test_bit(JOB_DIE, &ai->flags)) {
2931 up(&ai->sem);
2932 break;
2933 }
2934
Pavel Machekca078ba2005-09-03 15:56:57 -07002935 if (ai->power.event || test_bit(FLAG_FLASHING, &ai->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 up(&ai->sem);
2937 continue;
2938 }
2939
2940 if (test_bit(JOB_XMIT, &ai->flags))
2941 airo_end_xmit(dev);
2942 else if (test_bit(JOB_XMIT11, &ai->flags))
2943 airo_end_xmit11(dev);
2944 else if (test_bit(JOB_STATS, &ai->flags))
2945 airo_read_stats(ai);
2946 else if (test_bit(JOB_WSTATS, &ai->flags))
2947 airo_read_wireless_stats(ai);
2948 else if (test_bit(JOB_PROMISC, &ai->flags))
2949 airo_set_promisc(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 else if (test_bit(JOB_MIC, &ai->flags))
2951 micinit(ai);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 else if (test_bit(JOB_EVENT, &ai->flags))
2953 airo_send_event(dev);
2954 else if (test_bit(JOB_AUTOWEP, &ai->flags))
2955 timer_func(dev);
2956 }
2957 complete_and_exit (&ai->thr_exited, 0);
2958}
2959
2960static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
2961 struct net_device *dev = (struct net_device *)dev_id;
2962 u16 status;
2963 u16 fid;
2964 struct airo_info *apriv = dev->priv;
2965 u16 savedInterrupts = 0;
2966 int handled = 0;
2967
2968 if (!netif_device_present(dev))
2969 return IRQ_NONE;
2970
2971 for (;;) {
2972 status = IN4500( apriv, EVSTAT );
2973 if ( !(status & STATUS_INTS) || status == 0xffff ) break;
2974
2975 handled = 1;
2976
2977 if ( status & EV_AWAKE ) {
2978 OUT4500( apriv, EVACK, EV_AWAKE );
2979 OUT4500( apriv, EVACK, EV_AWAKE );
2980 }
2981
2982 if (!savedInterrupts) {
2983 savedInterrupts = IN4500( apriv, EVINTEN );
2984 OUT4500( apriv, EVINTEN, 0 );
2985 }
2986
2987 if ( status & EV_MIC ) {
2988 OUT4500( apriv, EVACK, EV_MIC );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) {
2990 set_bit(JOB_MIC, &apriv->flags);
2991 wake_up_interruptible(&apriv->thr_wait);
2992 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 }
2994 if ( status & EV_LINK ) {
2995 union iwreq_data wrqu;
2996 /* The link status has changed, if you want to put a
2997 monitor hook in, do it here. (Remember that
2998 interrupts are still disabled!)
2999 */
3000 u16 newStatus = IN4500(apriv, LINKSTAT);
3001 OUT4500( apriv, EVACK, EV_LINK);
3002 /* Here is what newStatus means: */
3003#define NOBEACON 0x8000 /* Loss of sync - missed beacons */
3004#define MAXRETRIES 0x8001 /* Loss of sync - max retries */
3005#define MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/
3006#define FORCELOSS 0x8003 /* Loss of sync - host request */
3007#define TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */
3008#define DEAUTH 0x8100 /* Deauthentication (low byte is reason code) */
3009#define DISASS 0x8200 /* Disassociation (low byte is reason code) */
3010#define ASSFAIL 0x8400 /* Association failure (low byte is reason
3011 code) */
3012#define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason
3013 code) */
3014#define ASSOCIATED 0x0400 /* Assocatied */
3015#define RC_RESERVED 0 /* Reserved return code */
3016#define RC_NOREASON 1 /* Unspecified reason */
3017#define RC_AUTHINV 2 /* Previous authentication invalid */
3018#define RC_DEAUTH 3 /* Deauthenticated because sending station is
3019 leaving */
3020#define RC_NOACT 4 /* Disassociated due to inactivity */
3021#define RC_MAXLOAD 5 /* Disassociated because AP is unable to handle
3022 all currently associated stations */
3023#define RC_BADCLASS2 6 /* Class 2 frame received from
3024 non-Authenticated station */
3025#define RC_BADCLASS3 7 /* Class 3 frame received from
3026 non-Associated station */
3027#define RC_STATLEAVE 8 /* Disassociated because sending station is
3028 leaving BSS */
3029#define RC_NOAUTH 9 /* Station requesting (Re)Association is not
3030 Authenticated with the responding station */
3031 if (newStatus != ASSOCIATED) {
3032 if (auto_wep && !apriv->expires) {
3033 apriv->expires = RUN_AT(3*HZ);
3034 wake_up_interruptible(&apriv->thr_wait);
3035 }
3036 } else {
3037 struct task_struct *task = apriv->task;
3038 if (auto_wep)
3039 apriv->expires = 0;
3040 if (task)
3041 wake_up_process (task);
3042 set_bit(FLAG_UPDATE_UNI, &apriv->flags);
3043 set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
3044 }
3045 /* Question : is ASSOCIATED the only status
3046 * that is valid ? We want to catch handover
3047 * and reassociations as valid status
3048 * Jean II */
3049 if(newStatus == ASSOCIATED) {
3050 if (apriv->scan_timestamp) {
3051 /* Send an empty event to user space.
3052 * We don't send the received data on
3053 * the event because it would require
3054 * us to do complex transcoding, and
3055 * we want to minimise the work done in
3056 * the irq handler. Use a request to
3057 * extract the data - Jean II */
3058 wrqu.data.length = 0;
3059 wrqu.data.flags = 0;
3060 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
3061 apriv->scan_timestamp = 0;
3062 }
3063 if (down_trylock(&apriv->sem) != 0) {
3064 set_bit(JOB_EVENT, &apriv->flags);
3065 wake_up_interruptible(&apriv->thr_wait);
3066 } else
3067 airo_send_event(dev);
3068 } else {
3069 memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN);
3070 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
3071
3072 /* Send event to user space */
3073 wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL);
3074 }
3075 }
3076
3077 /* Check to see if there is something to receive */
3078 if ( status & EV_RX ) {
3079 struct sk_buff *skb = NULL;
3080 u16 fc, len, hdrlen = 0;
3081#pragma pack(1)
3082 struct {
3083 u16 status, len;
3084 u8 rssi[2];
3085 u8 rate;
3086 u8 freq;
3087 u16 tmp[4];
3088 } hdr;
3089#pragma pack()
3090 u16 gap;
3091 u16 tmpbuf[4];
3092 u16 *buffer;
3093
3094 if (test_bit(FLAG_MPI,&apriv->flags)) {
3095 if (test_bit(FLAG_802_11, &apriv->flags))
3096 mpi_receive_802_11(apriv);
3097 else
3098 mpi_receive_802_3(apriv);
3099 OUT4500(apriv, EVACK, EV_RX);
3100 goto exitrx;
3101 }
3102
3103 fid = IN4500( apriv, RXFID );
3104
3105 /* Get the packet length */
3106 if (test_bit(FLAG_802_11, &apriv->flags)) {
3107 bap_setup (apriv, fid, 4, BAP0);
3108 bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0);
3109 /* Bad CRC. Ignore packet */
3110 if (le16_to_cpu(hdr.status) & 2)
3111 hdr.len = 0;
3112 if (apriv->wifidev == NULL)
3113 hdr.len = 0;
3114 } else {
3115 bap_setup (apriv, fid, 0x36, BAP0);
3116 bap_read (apriv, (u16*)&hdr.len, 2, BAP0);
3117 }
3118 len = le16_to_cpu(hdr.len);
3119
3120 if (len > 2312) {
3121 printk( KERN_ERR "airo: Bad size %d\n", len );
3122 goto badrx;
3123 }
3124 if (len == 0)
3125 goto badrx;
3126
3127 if (test_bit(FLAG_802_11, &apriv->flags)) {
3128 bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0);
3129 fc = le16_to_cpu(fc);
3130 switch (fc & 0xc) {
3131 case 4:
3132 if ((fc & 0xe0) == 0xc0)
3133 hdrlen = 10;
3134 else
3135 hdrlen = 16;
3136 break;
3137 case 8:
3138 if ((fc&0x300)==0x300){
3139 hdrlen = 30;
3140 break;
3141 }
3142 default:
3143 hdrlen = 24;
3144 }
3145 } else
3146 hdrlen = ETH_ALEN * 2;
3147
3148 skb = dev_alloc_skb( len + hdrlen + 2 + 2 );
3149 if ( !skb ) {
3150 apriv->stats.rx_dropped++;
3151 goto badrx;
3152 }
3153 skb_reserve(skb, 2); /* This way the IP header is aligned */
3154 buffer = (u16*)skb_put (skb, len + hdrlen);
3155 if (test_bit(FLAG_802_11, &apriv->flags)) {
3156 buffer[0] = fc;
3157 bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
3158 if (hdrlen == 24)
3159 bap_read (apriv, tmpbuf, 6, BAP0);
3160
3161 bap_read (apriv, &gap, sizeof(gap), BAP0);
3162 gap = le16_to_cpu(gap);
3163 if (gap) {
3164 if (gap <= 8)
3165 bap_read (apriv, tmpbuf, gap, BAP0);
3166 else
3167 printk(KERN_ERR "airo: gaplen too big. Problems will follow...\n");
3168 }
3169 bap_read (apriv, buffer + hdrlen/2, len, BAP0);
3170 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 MICBuffer micbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 if (apriv->micstats.enabled) {
3174 bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0);
3175 if (ntohs(micbuf.typelen) > 0x05DC)
3176 bap_setup (apriv, fid, 0x44, BAP0);
3177 else {
3178 if (len <= sizeof(micbuf))
3179 goto badmic;
3180
3181 len -= sizeof(micbuf);
3182 skb_trim (skb, len + hdrlen);
3183 }
3184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 bap_read(apriv,buffer+ETH_ALEN,len,BAP0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
3187badmic:
3188 dev_kfree_skb_irq (skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189badrx:
3190 OUT4500( apriv, EVACK, EV_RX);
3191 goto exitrx;
3192 }
3193 }
3194#ifdef WIRELESS_SPY
3195 if (apriv->spy_data.spy_number > 0) {
3196 char *sa;
3197 struct iw_quality wstats;
3198 /* Prepare spy data : addr + qual */
3199 if (!test_bit(FLAG_802_11, &apriv->flags)) {
3200 sa = (char*)buffer + 6;
3201 bap_setup (apriv, fid, 8, BAP0);
3202 bap_read (apriv, (u16*)hdr.rssi, 2, BAP0);
3203 } else
3204 sa = (char*)buffer + 10;
3205 wstats.qual = hdr.rssi[0];
3206 if (apriv->rssi)
3207 wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
3208 else
3209 wstats.level = (hdr.rssi[1] + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04003210 wstats.noise = apriv->wstats.qual.noise;
3211 wstats.updated = IW_QUAL_LEVEL_UPDATED
3212 | IW_QUAL_QUAL_UPDATED
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07003213 | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 /* Update spy records */
3215 wireless_spy_update(dev, sa, &wstats);
3216 }
3217#endif /* WIRELESS_SPY */
3218 OUT4500( apriv, EVACK, EV_RX);
3219
3220 if (test_bit(FLAG_802_11, &apriv->flags)) {
3221 skb->mac.raw = skb->data;
3222 skb->pkt_type = PACKET_OTHERHOST;
3223 skb->dev = apriv->wifidev;
3224 skb->protocol = htons(ETH_P_802_2);
3225 } else {
3226 skb->dev = dev;
3227 skb->protocol = eth_type_trans(skb,dev);
3228 }
3229 skb->dev->last_rx = jiffies;
3230 skb->ip_summed = CHECKSUM_NONE;
3231
3232 netif_rx( skb );
3233 }
3234exitrx:
3235
3236 /* Check to see if a packet has been transmitted */
3237 if ( status & ( EV_TX|EV_TXCPY|EV_TXEXC ) ) {
3238 int i;
3239 int len = 0;
3240 int index = -1;
3241
3242 if (test_bit(FLAG_MPI,&apriv->flags)) {
3243 unsigned long flags;
3244
3245 if (status & EV_TXEXC)
3246 get_tx_error(apriv, -1);
3247 spin_lock_irqsave(&apriv->aux_lock, flags);
David S. Millerb03efcf2005-07-08 14:57:23 -07003248 if (!skb_queue_empty(&apriv->txq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249 spin_unlock_irqrestore(&apriv->aux_lock,flags);
3250 mpi_send_packet (dev);
3251 } else {
3252 clear_bit(FLAG_PENDING_XMIT, &apriv->flags);
3253 spin_unlock_irqrestore(&apriv->aux_lock,flags);
3254 netif_wake_queue (dev);
3255 }
3256 OUT4500( apriv, EVACK,
3257 status & (EV_TX|EV_TXCPY|EV_TXEXC));
3258 goto exittx;
3259 }
3260
3261 fid = IN4500(apriv, TXCOMPLFID);
3262
3263 for( i = 0; i < MAX_FIDS; i++ ) {
3264 if ( ( apriv->fids[i] & 0xffff ) == fid ) {
3265 len = apriv->fids[i] >> 16;
3266 index = i;
3267 }
3268 }
3269 if (index != -1) {
3270 if (status & EV_TXEXC)
3271 get_tx_error(apriv, index);
3272 OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC));
3273 /* Set up to be used again */
3274 apriv->fids[index] &= 0xffff;
3275 if (index < MAX_FIDS / 2) {
3276 if (!test_bit(FLAG_PENDING_XMIT, &apriv->flags))
3277 netif_wake_queue(dev);
3278 } else {
3279 if (!test_bit(FLAG_PENDING_XMIT11, &apriv->flags))
3280 netif_wake_queue(apriv->wifidev);
3281 }
3282 } else {
3283 OUT4500( apriv, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC));
3284 printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" );
3285 }
3286 }
3287exittx:
3288 if ( status & ~STATUS_INTS & ~IGNORE_INTS )
3289 printk( KERN_WARNING "airo: Got weird status %x\n",
3290 status & ~STATUS_INTS & ~IGNORE_INTS );
3291 }
3292
3293 if (savedInterrupts)
3294 OUT4500( apriv, EVINTEN, savedInterrupts );
3295
3296 /* done.. */
3297 return IRQ_RETVAL(handled);
3298}
3299
3300/*
3301 * Routines to talk to the card
3302 */
3303
3304/*
3305 * This was originally written for the 4500, hence the name
3306 * NOTE: If use with 8bit mode and SMP bad things will happen!
3307 * Why would some one do 8 bit IO in an SMP machine?!?
3308 */
3309static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) {
3310 if (test_bit(FLAG_MPI,&ai->flags))
3311 reg <<= 1;
3312 if ( !do8bitIO )
3313 outw( val, ai->dev->base_addr + reg );
3314 else {
3315 outb( val & 0xff, ai->dev->base_addr + reg );
3316 outb( val >> 8, ai->dev->base_addr + reg + 1 );
3317 }
3318}
3319
3320static u16 IN4500( struct airo_info *ai, u16 reg ) {
3321 unsigned short rc;
3322
3323 if (test_bit(FLAG_MPI,&ai->flags))
3324 reg <<= 1;
3325 if ( !do8bitIO )
3326 rc = inw( ai->dev->base_addr + reg );
3327 else {
3328 rc = inb( ai->dev->base_addr + reg );
3329 rc += ((int)inb( ai->dev->base_addr + reg + 1 )) << 8;
3330 }
3331 return rc;
3332}
3333
3334static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) {
3335 int rc;
3336 Cmd cmd;
3337
3338 /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions
3339 * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down"
3340 * Note : we could try to use !netif_running(dev) in enable_MAC()
3341 * instead of this flag, but I don't trust it *within* the
3342 * open/close functions, and testing both flags together is
3343 * "cheaper" - Jean II */
3344 if (ai->flags & FLAG_RADIO_MASK) return SUCCESS;
3345
3346 if (lock && down_interruptible(&ai->sem))
3347 return -ERESTARTSYS;
3348
3349 if (!test_bit(FLAG_ENABLED, &ai->flags)) {
3350 memset(&cmd, 0, sizeof(cmd));
3351 cmd.cmd = MAC_ENABLE;
3352 rc = issuecommand(ai, &cmd, rsp);
3353 if (rc == SUCCESS)
3354 set_bit(FLAG_ENABLED, &ai->flags);
3355 } else
3356 rc = SUCCESS;
3357
3358 if (lock)
3359 up(&ai->sem);
3360
3361 if (rc)
3362 printk(KERN_ERR "%s: Cannot enable MAC, err=%d\n",
3363 __FUNCTION__,rc);
3364 return rc;
3365}
3366
3367static void disable_MAC( struct airo_info *ai, int lock ) {
3368 Cmd cmd;
3369 Resp rsp;
3370
3371 if (lock && down_interruptible(&ai->sem))
3372 return;
3373
3374 if (test_bit(FLAG_ENABLED, &ai->flags)) {
3375 memset(&cmd, 0, sizeof(cmd));
3376 cmd.cmd = MAC_DISABLE; // disable in case already enabled
3377 issuecommand(ai, &cmd, &rsp);
3378 clear_bit(FLAG_ENABLED, &ai->flags);
3379 }
3380 if (lock)
3381 up(&ai->sem);
3382}
3383
3384static void enable_interrupts( struct airo_info *ai ) {
3385 /* Enable the interrupts */
3386 OUT4500( ai, EVINTEN, STATUS_INTS );
3387}
3388
3389static void disable_interrupts( struct airo_info *ai ) {
3390 OUT4500( ai, EVINTEN, 0 );
3391}
3392
3393static void mpi_receive_802_3(struct airo_info *ai)
3394{
3395 RxFid rxd;
3396 int len = 0;
3397 struct sk_buff *skb;
3398 char *buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 int off = 0;
3400 MICBuffer micbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401
3402 memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
3403 /* Make sure we got something */
3404 if (rxd.rdy && rxd.valid == 0) {
3405 len = rxd.len + 12;
3406 if (len < 12 || len > 2048)
3407 goto badrx;
3408
3409 skb = dev_alloc_skb(len);
3410 if (!skb) {
3411 ai->stats.rx_dropped++;
3412 goto badrx;
3413 }
3414 buffer = skb_put(skb,len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2);
3416 if (ai->micstats.enabled) {
3417 memcpy(&micbuf,
3418 ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2,
3419 sizeof(micbuf));
3420 if (ntohs(micbuf.typelen) <= 0x05DC) {
3421 if (len <= sizeof(micbuf) + ETH_ALEN * 2)
3422 goto badmic;
3423
3424 off = sizeof(micbuf);
3425 skb_trim (skb, len - off);
3426 }
3427 }
3428 memcpy(buffer + ETH_ALEN * 2,
3429 ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off,
3430 len - ETH_ALEN * 2 - off);
3431 if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) {
3432badmic:
3433 dev_kfree_skb_irq (skb);
3434 goto badrx;
3435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436#ifdef WIRELESS_SPY
3437 if (ai->spy_data.spy_number > 0) {
3438 char *sa;
3439 struct iw_quality wstats;
3440 /* Prepare spy data : addr + qual */
3441 sa = buffer + ETH_ALEN;
3442 wstats.qual = 0; /* XXX Where do I get that info from ??? */
3443 wstats.level = 0;
3444 wstats.updated = 0;
3445 /* Update spy records */
3446 wireless_spy_update(ai->dev, sa, &wstats);
3447 }
3448#endif /* WIRELESS_SPY */
3449
3450 skb->dev = ai->dev;
3451 skb->ip_summed = CHECKSUM_NONE;
3452 skb->protocol = eth_type_trans(skb, ai->dev);
3453 skb->dev->last_rx = jiffies;
3454 netif_rx(skb);
3455 }
3456badrx:
3457 if (rxd.valid == 0) {
3458 rxd.valid = 1;
3459 rxd.rdy = 0;
3460 rxd.len = PKTSIZE;
3461 memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd));
3462 }
3463}
3464
3465void mpi_receive_802_11 (struct airo_info *ai)
3466{
3467 RxFid rxd;
3468 struct sk_buff *skb = NULL;
3469 u16 fc, len, hdrlen = 0;
3470#pragma pack(1)
3471 struct {
3472 u16 status, len;
3473 u8 rssi[2];
3474 u8 rate;
3475 u8 freq;
3476 u16 tmp[4];
3477 } hdr;
3478#pragma pack()
3479 u16 gap;
3480 u16 *buffer;
3481 char *ptr = ai->rxfids[0].virtual_host_addr+4;
3482
3483 memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
3484 memcpy ((char *)&hdr, ptr, sizeof(hdr));
3485 ptr += sizeof(hdr);
3486 /* Bad CRC. Ignore packet */
3487 if (le16_to_cpu(hdr.status) & 2)
3488 hdr.len = 0;
3489 if (ai->wifidev == NULL)
3490 hdr.len = 0;
3491 len = le16_to_cpu(hdr.len);
3492 if (len > 2312) {
3493 printk( KERN_ERR "airo: Bad size %d\n", len );
3494 goto badrx;
3495 }
3496 if (len == 0)
3497 goto badrx;
3498
3499 memcpy ((char *)&fc, ptr, sizeof(fc));
3500 fc = le16_to_cpu(fc);
3501 switch (fc & 0xc) {
3502 case 4:
3503 if ((fc & 0xe0) == 0xc0)
3504 hdrlen = 10;
3505 else
3506 hdrlen = 16;
3507 break;
3508 case 8:
3509 if ((fc&0x300)==0x300){
3510 hdrlen = 30;
3511 break;
3512 }
3513 default:
3514 hdrlen = 24;
3515 }
3516
3517 skb = dev_alloc_skb( len + hdrlen + 2 );
3518 if ( !skb ) {
3519 ai->stats.rx_dropped++;
3520 goto badrx;
3521 }
3522 buffer = (u16*)skb_put (skb, len + hdrlen);
3523 memcpy ((char *)buffer, ptr, hdrlen);
3524 ptr += hdrlen;
3525 if (hdrlen == 24)
3526 ptr += 6;
3527 memcpy ((char *)&gap, ptr, sizeof(gap));
3528 ptr += sizeof(gap);
3529 gap = le16_to_cpu(gap);
3530 if (gap) {
3531 if (gap <= 8)
3532 ptr += gap;
3533 else
3534 printk(KERN_ERR
3535 "airo: gaplen too big. Problems will follow...\n");
3536 }
3537 memcpy ((char *)buffer + hdrlen, ptr, len);
3538 ptr += len;
3539#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
3540 if (ai->spy_data.spy_number > 0) {
3541 char *sa;
3542 struct iw_quality wstats;
3543 /* Prepare spy data : addr + qual */
3544 sa = (char*)buffer + 10;
3545 wstats.qual = hdr.rssi[0];
3546 if (ai->rssi)
3547 wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm;
3548 else
3549 wstats.level = (hdr.rssi[1] + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04003550 wstats.noise = ai->wstats.qual.noise;
3551 wstats.updated = IW_QUAL_QUAL_UPDATED
3552 | IW_QUAL_LEVEL_UPDATED
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07003553 | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 /* Update spy records */
3555 wireless_spy_update(ai->dev, sa, &wstats);
3556 }
3557#endif /* IW_WIRELESS_SPY */
3558 skb->mac.raw = skb->data;
3559 skb->pkt_type = PACKET_OTHERHOST;
3560 skb->dev = ai->wifidev;
3561 skb->protocol = htons(ETH_P_802_2);
3562 skb->dev->last_rx = jiffies;
3563 skb->ip_summed = CHECKSUM_NONE;
3564 netif_rx( skb );
3565badrx:
3566 if (rxd.valid == 0) {
3567 rxd.valid = 1;
3568 rxd.rdy = 0;
3569 rxd.len = PKTSIZE;
3570 memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd));
3571 }
3572}
3573
3574static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
3575{
3576 Cmd cmd;
3577 Resp rsp;
3578 int status;
3579 int i;
3580 SsidRid mySsid;
3581 u16 lastindex;
3582 WepKeyRid wkr;
3583 int rc;
3584
3585 memset( &mySsid, 0, sizeof( mySsid ) );
Jesper Juhlb4558ea2005-10-28 16:53:13 -04003586 kfree (ai->flash);
3587 ai->flash = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588
3589 /* The NOP is the first step in getting the card going */
3590 cmd.cmd = NOP;
3591 cmd.parm0 = cmd.parm1 = cmd.parm2 = 0;
3592 if (lock && down_interruptible(&ai->sem))
3593 return ERROR;
3594 if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
3595 if (lock)
3596 up(&ai->sem);
3597 return ERROR;
3598 }
3599 disable_MAC( ai, 0);
3600
3601 // Let's figure out if we need to use the AUX port
3602 if (!test_bit(FLAG_MPI,&ai->flags)) {
3603 cmd.cmd = CMD_ENABLEAUX;
3604 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
3605 if (lock)
3606 up(&ai->sem);
3607 printk(KERN_ERR "airo: Error checking for AUX port\n");
3608 return ERROR;
3609 }
3610 if (!aux_bap || rsp.status & 0xff00) {
3611 ai->bap_read = fast_bap_read;
3612 printk(KERN_DEBUG "airo: Doing fast bap_reads\n");
3613 } else {
3614 ai->bap_read = aux_bap_read;
3615 printk(KERN_DEBUG "airo: Doing AUX bap_reads\n");
3616 }
3617 }
3618 if (lock)
3619 up(&ai->sem);
3620 if (ai->config.len == 0) {
3621 tdsRssiRid rssi_rid;
3622 CapabilityRid cap_rid;
3623
Jesper Juhlb4558ea2005-10-28 16:53:13 -04003624 kfree(ai->APList);
3625 ai->APList = NULL;
3626 kfree(ai->SSID);
3627 ai->SSID = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 // general configuration (read/modify/write)
3629 status = readConfigRid(ai, lock);
3630 if ( status != SUCCESS ) return ERROR;
3631
3632 status = readCapabilityRid(ai, &cap_rid, lock);
3633 if ( status != SUCCESS ) return ERROR;
3634
3635 status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),lock);
3636 if ( status == SUCCESS ) {
3637 if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
Dan Williams41480af2005-05-10 09:45:51 -04003638 memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 }
3640 else {
Jesper Juhlb4558ea2005-10-28 16:53:13 -04003641 kfree(ai->rssi);
3642 ai->rssi = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 if (cap_rid.softCap & 8)
3644 ai->config.rmode |= RXMODE_NORMALIZED_RSSI;
3645 else
3646 printk(KERN_WARNING "airo: unknown received signal level scale\n");
3647 }
3648 ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
3649 ai->config.authType = AUTH_OPEN;
3650 ai->config.modulation = MOD_CCK;
3651
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 if ((cap_rid.len>=sizeof(cap_rid)) && (cap_rid.extSoftCap&1) &&
3653 (micsetup(ai) == SUCCESS)) {
3654 ai->config.opmode |= MODE_MIC;
3655 set_bit(FLAG_MIC_CAPABLE, &ai->flags);
3656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657
3658 /* Save off the MAC */
3659 for( i = 0; i < ETH_ALEN; i++ ) {
3660 mac[i] = ai->config.macAddr[i];
3661 }
3662
3663 /* Check to see if there are any insmod configured
3664 rates to add */
3665 if ( rates[0] ) {
3666 int i = 0;
3667 memset(ai->config.rates,0,sizeof(ai->config.rates));
3668 for( i = 0; i < 8 && rates[i]; i++ ) {
3669 ai->config.rates[i] = rates[i];
3670 }
3671 }
3672 if ( basic_rate > 0 ) {
3673 int i;
3674 for( i = 0; i < 8; i++ ) {
3675 if ( ai->config.rates[i] == basic_rate ||
3676 !ai->config.rates ) {
3677 ai->config.rates[i] = basic_rate | 0x80;
3678 break;
3679 }
3680 }
3681 }
3682 set_bit (FLAG_COMMIT, &ai->flags);
3683 }
3684
3685 /* Setup the SSIDs if present */
3686 if ( ssids[0] ) {
3687 int i;
3688 for( i = 0; i < 3 && ssids[i]; i++ ) {
3689 mySsid.ssids[i].len = strlen(ssids[i]);
3690 if ( mySsid.ssids[i].len > 32 )
3691 mySsid.ssids[i].len = 32;
3692 memcpy(mySsid.ssids[i].ssid, ssids[i],
3693 mySsid.ssids[i].len);
3694 }
3695 mySsid.len = sizeof(mySsid);
3696 }
3697
3698 status = writeConfigRid(ai, lock);
3699 if ( status != SUCCESS ) return ERROR;
3700
3701 /* Set up the SSID list */
3702 if ( ssids[0] ) {
3703 status = writeSsidRid(ai, &mySsid, lock);
3704 if ( status != SUCCESS ) return ERROR;
3705 }
3706
3707 status = enable_MAC(ai, &rsp, lock);
3708 if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) {
3709 printk( KERN_ERR "airo: Bad MAC enable reason = %x, rid = %x, offset = %d\n", rsp.rsp0, rsp.rsp1, rsp.rsp2 );
3710 return ERROR;
3711 }
3712
3713 /* Grab the initial wep key, we gotta save it for auto_wep */
3714 rc = readWepKeyRid(ai, &wkr, 1, lock);
3715 if (rc == SUCCESS) do {
3716 lastindex = wkr.kindex;
3717 if (wkr.kindex == 0xffff) {
3718 ai->defindex = wkr.mac[0];
3719 }
3720 rc = readWepKeyRid(ai, &wkr, 0, lock);
3721 } while(lastindex != wkr.kindex);
3722
3723 if (auto_wep) {
3724 ai->expires = RUN_AT(3*HZ);
3725 wake_up_interruptible(&ai->thr_wait);
3726 }
3727
3728 return SUCCESS;
3729}
3730
3731static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
3732 // Im really paranoid about letting it run forever!
3733 int max_tries = 600000;
3734
3735 if (IN4500(ai, EVSTAT) & EV_CMD)
3736 OUT4500(ai, EVACK, EV_CMD);
3737
3738 OUT4500(ai, PARAM0, pCmd->parm0);
3739 OUT4500(ai, PARAM1, pCmd->parm1);
3740 OUT4500(ai, PARAM2, pCmd->parm2);
3741 OUT4500(ai, COMMAND, pCmd->cmd);
3742
3743 while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) {
3744 if ((IN4500(ai, COMMAND)) == pCmd->cmd)
3745 // PC4500 didn't notice command, try again
3746 OUT4500(ai, COMMAND, pCmd->cmd);
3747 if (!in_atomic() && (max_tries & 255) == 0)
3748 schedule();
3749 }
3750
3751 if ( max_tries == -1 ) {
3752 printk( KERN_ERR
3753 "airo: Max tries exceeded when issueing command\n" );
3754 if (IN4500(ai, COMMAND) & COMMAND_BUSY)
3755 OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
3756 return ERROR;
3757 }
3758
3759 // command completed
3760 pRsp->status = IN4500(ai, STATUS);
3761 pRsp->rsp0 = IN4500(ai, RESP0);
3762 pRsp->rsp1 = IN4500(ai, RESP1);
3763 pRsp->rsp2 = IN4500(ai, RESP2);
3764 if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) {
3765 printk (KERN_ERR "airo: cmd= %x\n", pCmd->cmd);
3766 printk (KERN_ERR "airo: status= %x\n", pRsp->status);
3767 printk (KERN_ERR "airo: Rsp0= %x\n", pRsp->rsp0);
3768 printk (KERN_ERR "airo: Rsp1= %x\n", pRsp->rsp1);
3769 printk (KERN_ERR "airo: Rsp2= %x\n", pRsp->rsp2);
3770 }
3771
3772 // clear stuck command busy if necessary
3773 if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
3774 OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
3775 }
3776 // acknowledge processing the status/response
3777 OUT4500(ai, EVACK, EV_CMD);
3778
3779 return SUCCESS;
3780}
3781
3782/* Sets up the bap to start exchange data. whichbap should
3783 * be one of the BAP0 or BAP1 defines. Locks should be held before
3784 * calling! */
3785static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap )
3786{
3787 int timeout = 50;
3788 int max_tries = 3;
3789
3790 OUT4500(ai, SELECT0+whichbap, rid);
3791 OUT4500(ai, OFFSET0+whichbap, offset);
3792 while (1) {
3793 int status = IN4500(ai, OFFSET0+whichbap);
3794 if (status & BAP_BUSY) {
3795 /* This isn't really a timeout, but its kinda
3796 close */
3797 if (timeout--) {
3798 continue;
3799 }
3800 } else if ( status & BAP_ERR ) {
3801 /* invalid rid or offset */
3802 printk( KERN_ERR "airo: BAP error %x %d\n",
3803 status, whichbap );
3804 return ERROR;
3805 } else if (status & BAP_DONE) { // success
3806 return SUCCESS;
3807 }
3808 if ( !(max_tries--) ) {
3809 printk( KERN_ERR
3810 "airo: BAP setup error too many retries\n" );
3811 return ERROR;
3812 }
3813 // -- PC4500 missed it, try again
3814 OUT4500(ai, SELECT0+whichbap, rid);
3815 OUT4500(ai, OFFSET0+whichbap, offset);
3816 timeout = 50;
3817 }
3818}
3819
3820/* should only be called by aux_bap_read. This aux function and the
3821 following use concepts not documented in the developers guide. I
3822 got them from a patch given to my by Aironet */
3823static u16 aux_setup(struct airo_info *ai, u16 page,
3824 u16 offset, u16 *len)
3825{
3826 u16 next;
3827
3828 OUT4500(ai, AUXPAGE, page);
3829 OUT4500(ai, AUXOFF, 0);
3830 next = IN4500(ai, AUXDATA);
3831 *len = IN4500(ai, AUXDATA)&0xff;
3832 if (offset != 4) OUT4500(ai, AUXOFF, offset);
3833 return next;
3834}
3835
3836/* requires call to bap_setup() first */
3837static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst,
3838 int bytelen, int whichbap)
3839{
3840 u16 len;
3841 u16 page;
3842 u16 offset;
3843 u16 next;
3844 int words;
3845 int i;
3846 unsigned long flags;
3847
3848 spin_lock_irqsave(&ai->aux_lock, flags);
3849 page = IN4500(ai, SWS0+whichbap);
3850 offset = IN4500(ai, SWS2+whichbap);
3851 next = aux_setup(ai, page, offset, &len);
3852 words = (bytelen+1)>>1;
3853
3854 for (i=0; i<words;) {
3855 int count;
3856 count = (len>>1) < (words-i) ? (len>>1) : (words-i);
3857 if ( !do8bitIO )
3858 insw( ai->dev->base_addr+DATA0+whichbap,
3859 pu16Dst+i,count );
3860 else
3861 insb( ai->dev->base_addr+DATA0+whichbap,
3862 pu16Dst+i, count << 1 );
3863 i += count;
3864 if (i<words) {
3865 next = aux_setup(ai, next, 4, &len);
3866 }
3867 }
3868 spin_unlock_irqrestore(&ai->aux_lock, flags);
3869 return SUCCESS;
3870}
3871
3872
3873/* requires call to bap_setup() first */
3874static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst,
3875 int bytelen, int whichbap)
3876{
3877 bytelen = (bytelen + 1) & (~1); // round up to even value
3878 if ( !do8bitIO )
3879 insw( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1 );
3880 else
3881 insb( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen );
3882 return SUCCESS;
3883}
3884
3885/* requires call to bap_setup() first */
3886static int bap_write(struct airo_info *ai, const u16 *pu16Src,
3887 int bytelen, int whichbap)
3888{
3889 bytelen = (bytelen + 1) & (~1); // round up to even value
3890 if ( !do8bitIO )
3891 outsw( ai->dev->base_addr+DATA0+whichbap,
3892 pu16Src, bytelen>>1 );
3893 else
3894 outsb( ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen );
3895 return SUCCESS;
3896}
3897
3898static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd)
3899{
3900 Cmd cmd; /* for issuing commands */
3901 Resp rsp; /* response from commands */
3902 u16 status;
3903
3904 memset(&cmd, 0, sizeof(cmd));
3905 cmd.cmd = accmd;
3906 cmd.parm0 = rid;
3907 status = issuecommand(ai, &cmd, &rsp);
3908 if (status != 0) return status;
3909 if ( (rsp.status & 0x7F00) != 0) {
3910 return (accmd << 8) + (rsp.rsp0 & 0xFF);
3911 }
3912 return 0;
3913}
3914
3915/* Note, that we are using BAP1 which is also used by transmit, so
3916 * we must get a lock. */
3917static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, int lock)
3918{
3919 u16 status;
3920 int rc = SUCCESS;
3921
3922 if (lock) {
3923 if (down_interruptible(&ai->sem))
3924 return ERROR;
3925 }
3926 if (test_bit(FLAG_MPI,&ai->flags)) {
3927 Cmd cmd;
3928 Resp rsp;
3929
3930 memset(&cmd, 0, sizeof(cmd));
3931 memset(&rsp, 0, sizeof(rsp));
3932 ai->config_desc.rid_desc.valid = 1;
3933 ai->config_desc.rid_desc.len = RIDSIZE;
3934 ai->config_desc.rid_desc.rid = 0;
3935 ai->config_desc.rid_desc.host_addr = ai->ridbus;
3936
3937 cmd.cmd = CMD_ACCESS;
3938 cmd.parm0 = rid;
3939
3940 memcpy_toio(ai->config_desc.card_ram_off,
3941 &ai->config_desc.rid_desc, sizeof(Rid));
3942
3943 rc = issuecommand(ai, &cmd, &rsp);
3944
3945 if (rsp.status & 0x7f00)
3946 rc = rsp.rsp0;
3947 if (!rc)
3948 memcpy(pBuf, ai->config_desc.virtual_host_addr, len);
3949 goto done;
3950 } else {
3951 if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS))!=SUCCESS) {
3952 rc = status;
3953 goto done;
3954 }
3955 if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
3956 rc = ERROR;
3957 goto done;
3958 }
3959 // read the rid length field
3960 bap_read(ai, pBuf, 2, BAP1);
3961 // length for remaining part of rid
3962 len = min(len, (int)le16_to_cpu(*(u16*)pBuf)) - 2;
3963
3964 if ( len <= 2 ) {
3965 printk( KERN_ERR
3966 "airo: Rid %x has a length of %d which is too short\n",
3967 (int)rid, (int)len );
3968 rc = ERROR;
3969 goto done;
3970 }
3971 // read remainder of the rid
3972 rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
3973 }
3974done:
3975 if (lock)
3976 up(&ai->sem);
3977 return rc;
3978}
3979
3980/* Note, that we are using BAP1 which is also used by transmit, so
3981 * make sure this isnt called when a transmit is happening */
3982static int PC4500_writerid(struct airo_info *ai, u16 rid,
3983 const void *pBuf, int len, int lock)
3984{
3985 u16 status;
3986 int rc = SUCCESS;
3987
3988 *(u16*)pBuf = cpu_to_le16((u16)len);
3989
3990 if (lock) {
3991 if (down_interruptible(&ai->sem))
3992 return ERROR;
3993 }
3994 if (test_bit(FLAG_MPI,&ai->flags)) {
3995 Cmd cmd;
3996 Resp rsp;
3997
Dan Streetmanf89b2322005-11-11 11:41:42 -05003998 if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 printk(KERN_ERR
4000 "%s: MAC should be disabled (rid=%04x)\n",
4001 __FUNCTION__, rid);
4002 memset(&cmd, 0, sizeof(cmd));
4003 memset(&rsp, 0, sizeof(rsp));
4004
4005 ai->config_desc.rid_desc.valid = 1;
4006 ai->config_desc.rid_desc.len = *((u16 *)pBuf);
4007 ai->config_desc.rid_desc.rid = 0;
4008
4009 cmd.cmd = CMD_WRITERID;
4010 cmd.parm0 = rid;
4011
4012 memcpy_toio(ai->config_desc.card_ram_off,
4013 &ai->config_desc.rid_desc, sizeof(Rid));
4014
4015 if (len < 4 || len > 2047) {
4016 printk(KERN_ERR "%s: len=%d\n",__FUNCTION__,len);
4017 rc = -1;
4018 } else {
4019 memcpy((char *)ai->config_desc.virtual_host_addr,
4020 pBuf, len);
4021
4022 rc = issuecommand(ai, &cmd, &rsp);
4023 if ((rc & 0xff00) != 0) {
4024 printk(KERN_ERR "%s: Write rid Error %d\n",
4025 __FUNCTION__,rc);
4026 printk(KERN_ERR "%s: Cmd=%04x\n",
4027 __FUNCTION__,cmd.cmd);
4028 }
4029
4030 if ((rsp.status & 0x7f00))
4031 rc = rsp.rsp0;
4032 }
4033 } else {
4034 // --- first access so that we can write the rid data
4035 if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
4036 rc = status;
4037 goto done;
4038 }
4039 // --- now write the rid data
4040 if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
4041 rc = ERROR;
4042 goto done;
4043 }
4044 bap_write(ai, pBuf, len, BAP1);
4045 // ---now commit the rid data
4046 rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
4047 }
4048done:
4049 if (lock)
4050 up(&ai->sem);
4051 return rc;
4052}
4053
4054/* Allocates a FID to be used for transmitting packets. We only use
4055 one for now. */
4056static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw)
4057{
4058 unsigned int loop = 3000;
4059 Cmd cmd;
4060 Resp rsp;
4061 u16 txFid;
4062 u16 txControl;
4063
4064 cmd.cmd = CMD_ALLOCATETX;
4065 cmd.parm0 = lenPayload;
4066 if (down_interruptible(&ai->sem))
4067 return ERROR;
4068 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
4069 txFid = ERROR;
4070 goto done;
4071 }
4072 if ( (rsp.status & 0xFF00) != 0) {
4073 txFid = ERROR;
4074 goto done;
4075 }
4076 /* wait for the allocate event/indication
4077 * It makes me kind of nervous that this can just sit here and spin,
4078 * but in practice it only loops like four times. */
4079 while (((IN4500(ai, EVSTAT) & EV_ALLOC) == 0) && --loop);
4080 if (!loop) {
4081 txFid = ERROR;
4082 goto done;
4083 }
4084
4085 // get the allocated fid and acknowledge
4086 txFid = IN4500(ai, TXALLOCFID);
4087 OUT4500(ai, EVACK, EV_ALLOC);
4088
4089 /* The CARD is pretty cool since it converts the ethernet packet
4090 * into 802.11. Also note that we don't release the FID since we
4091 * will be using the same one over and over again. */
4092 /* We only have to setup the control once since we are not
4093 * releasing the fid. */
4094 if (raw)
4095 txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_11
4096 | TXCTL_ETHERNET | TXCTL_NORELEASE);
4097 else
4098 txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3
4099 | TXCTL_ETHERNET | TXCTL_NORELEASE);
4100 if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS)
4101 txFid = ERROR;
4102 else
4103 bap_write(ai, &txControl, sizeof(txControl), BAP1);
4104
4105done:
4106 up(&ai->sem);
4107
4108 return txFid;
4109}
4110
4111/* In general BAP1 is dedicated to transmiting packets. However,
4112 since we need a BAP when accessing RIDs, we also use BAP1 for that.
4113 Make sure the BAP1 spinlock is held when this is called. */
4114static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
4115{
4116 u16 payloadLen;
4117 Cmd cmd;
4118 Resp rsp;
4119 int miclen = 0;
4120 u16 txFid = len;
4121 MICBuffer pMic;
4122
4123 len >>= 16;
4124
4125 if (len <= ETH_ALEN * 2) {
4126 printk( KERN_WARNING "Short packet %d\n", len );
4127 return ERROR;
4128 }
4129 len -= ETH_ALEN * 2;
4130
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131 if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
4132 (ntohs(((u16 *)pPacket)[6]) != 0x888E)) {
4133 if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS)
4134 return ERROR;
4135 miclen = sizeof(pMic);
4136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 // packet is destination[6], source[6], payload[len-12]
4138 // write the payload length and dst/src/payload
4139 if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR;
4140 /* The hardware addresses aren't counted as part of the payload, so
4141 * we have to subtract the 12 bytes for the addresses off */
4142 payloadLen = cpu_to_le16(len + miclen);
4143 bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
4144 bap_write(ai, (const u16*)pPacket, sizeof(etherHead), BAP1);
4145 if (miclen)
4146 bap_write(ai, (const u16*)&pMic, miclen, BAP1);
4147 bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len, BAP1);
4148 // issue the transmit command
4149 memset( &cmd, 0, sizeof( cmd ) );
4150 cmd.cmd = CMD_TRANSMIT;
4151 cmd.parm0 = txFid;
4152 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
4153 if ( (rsp.status & 0xFF00) != 0) return ERROR;
4154 return SUCCESS;
4155}
4156
4157static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
4158{
4159 u16 fc, payloadLen;
4160 Cmd cmd;
4161 Resp rsp;
4162 int hdrlen;
4163 struct {
4164 u8 addr4[ETH_ALEN];
4165 u16 gaplen;
4166 u8 gap[6];
4167 } gap;
4168 u16 txFid = len;
4169 len >>= 16;
4170 gap.gaplen = 6;
4171
4172 fc = le16_to_cpu(*(const u16*)pPacket);
4173 switch (fc & 0xc) {
4174 case 4:
4175 if ((fc & 0xe0) == 0xc0)
4176 hdrlen = 10;
4177 else
4178 hdrlen = 16;
4179 break;
4180 case 8:
4181 if ((fc&0x300)==0x300){
4182 hdrlen = 30;
4183 break;
4184 }
4185 default:
4186 hdrlen = 24;
4187 }
4188
4189 if (len < hdrlen) {
4190 printk( KERN_WARNING "Short packet %d\n", len );
4191 return ERROR;
4192 }
4193
4194 /* packet is 802.11 header + payload
4195 * write the payload length and dst/src/payload */
4196 if (bap_setup(ai, txFid, 6, BAP1) != SUCCESS) return ERROR;
4197 /* The 802.11 header aren't counted as part of the payload, so
4198 * we have to subtract the header bytes off */
4199 payloadLen = cpu_to_le16(len-hdrlen);
4200 bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
4201 if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR;
4202 bap_write(ai, (const u16*)pPacket, hdrlen, BAP1);
4203 bap_write(ai, hdrlen == 30 ?
4204 (const u16*)&gap.gaplen : (const u16*)&gap, 38 - hdrlen, BAP1);
4205
4206 bap_write(ai, (const u16*)(pPacket + hdrlen), len - hdrlen, BAP1);
4207 // issue the transmit command
4208 memset( &cmd, 0, sizeof( cmd ) );
4209 cmd.cmd = CMD_TRANSMIT;
4210 cmd.parm0 = txFid;
4211 if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
4212 if ( (rsp.status & 0xFF00) != 0) return ERROR;
4213 return SUCCESS;
4214}
4215
4216/*
4217 * This is the proc_fs routines. It is a bit messier than I would
4218 * like! Feel free to clean it up!
4219 */
4220
4221static ssize_t proc_read( struct file *file,
4222 char __user *buffer,
4223 size_t len,
4224 loff_t *offset);
4225
4226static ssize_t proc_write( struct file *file,
4227 const char __user *buffer,
4228 size_t len,
4229 loff_t *offset );
4230static int proc_close( struct inode *inode, struct file *file );
4231
4232static int proc_stats_open( struct inode *inode, struct file *file );
4233static int proc_statsdelta_open( struct inode *inode, struct file *file );
4234static int proc_status_open( struct inode *inode, struct file *file );
4235static int proc_SSID_open( struct inode *inode, struct file *file );
4236static int proc_APList_open( struct inode *inode, struct file *file );
4237static int proc_BSSList_open( struct inode *inode, struct file *file );
4238static int proc_config_open( struct inode *inode, struct file *file );
4239static int proc_wepkey_open( struct inode *inode, struct file *file );
4240
4241static struct file_operations proc_statsdelta_ops = {
4242 .read = proc_read,
4243 .open = proc_statsdelta_open,
4244 .release = proc_close
4245};
4246
4247static struct file_operations proc_stats_ops = {
4248 .read = proc_read,
4249 .open = proc_stats_open,
4250 .release = proc_close
4251};
4252
4253static struct file_operations proc_status_ops = {
4254 .read = proc_read,
4255 .open = proc_status_open,
4256 .release = proc_close
4257};
4258
4259static struct file_operations proc_SSID_ops = {
4260 .read = proc_read,
4261 .write = proc_write,
4262 .open = proc_SSID_open,
4263 .release = proc_close
4264};
4265
4266static struct file_operations proc_BSSList_ops = {
4267 .read = proc_read,
4268 .write = proc_write,
4269 .open = proc_BSSList_open,
4270 .release = proc_close
4271};
4272
4273static struct file_operations proc_APList_ops = {
4274 .read = proc_read,
4275 .write = proc_write,
4276 .open = proc_APList_open,
4277 .release = proc_close
4278};
4279
4280static struct file_operations proc_config_ops = {
4281 .read = proc_read,
4282 .write = proc_write,
4283 .open = proc_config_open,
4284 .release = proc_close
4285};
4286
4287static struct file_operations proc_wepkey_ops = {
4288 .read = proc_read,
4289 .write = proc_write,
4290 .open = proc_wepkey_open,
4291 .release = proc_close
4292};
4293
4294static struct proc_dir_entry *airo_entry;
4295
4296struct proc_data {
4297 int release_buffer;
4298 int readlen;
4299 char *rbuffer;
4300 int writelen;
4301 int maxwritelen;
4302 char *wbuffer;
4303 void (*on_close) (struct inode *, struct file *);
4304};
4305
4306#ifndef SETPROC_OPS
4307#define SETPROC_OPS(entry, ops) (entry)->proc_fops = &(ops)
4308#endif
4309
4310static int setup_proc_entry( struct net_device *dev,
4311 struct airo_info *apriv ) {
4312 struct proc_dir_entry *entry;
4313 /* First setup the device directory */
4314 strcpy(apriv->proc_name,dev->name);
4315 apriv->proc_entry = create_proc_entry(apriv->proc_name,
4316 S_IFDIR|airo_perm,
4317 airo_entry);
4318 apriv->proc_entry->uid = proc_uid;
4319 apriv->proc_entry->gid = proc_gid;
4320 apriv->proc_entry->owner = THIS_MODULE;
4321
4322 /* Setup the StatsDelta */
4323 entry = create_proc_entry("StatsDelta",
4324 S_IFREG | (S_IRUGO&proc_perm),
4325 apriv->proc_entry);
4326 entry->uid = proc_uid;
4327 entry->gid = proc_gid;
4328 entry->data = dev;
4329 entry->owner = THIS_MODULE;
4330 SETPROC_OPS(entry, proc_statsdelta_ops);
4331
4332 /* Setup the Stats */
4333 entry = create_proc_entry("Stats",
4334 S_IFREG | (S_IRUGO&proc_perm),
4335 apriv->proc_entry);
4336 entry->uid = proc_uid;
4337 entry->gid = proc_gid;
4338 entry->data = dev;
4339 entry->owner = THIS_MODULE;
4340 SETPROC_OPS(entry, proc_stats_ops);
4341
4342 /* Setup the Status */
4343 entry = create_proc_entry("Status",
4344 S_IFREG | (S_IRUGO&proc_perm),
4345 apriv->proc_entry);
4346 entry->uid = proc_uid;
4347 entry->gid = proc_gid;
4348 entry->data = dev;
4349 entry->owner = THIS_MODULE;
4350 SETPROC_OPS(entry, proc_status_ops);
4351
4352 /* Setup the Config */
4353 entry = create_proc_entry("Config",
4354 S_IFREG | proc_perm,
4355 apriv->proc_entry);
4356 entry->uid = proc_uid;
4357 entry->gid = proc_gid;
4358 entry->data = dev;
4359 entry->owner = THIS_MODULE;
4360 SETPROC_OPS(entry, proc_config_ops);
4361
4362 /* Setup the SSID */
4363 entry = create_proc_entry("SSID",
4364 S_IFREG | proc_perm,
4365 apriv->proc_entry);
4366 entry->uid = proc_uid;
4367 entry->gid = proc_gid;
4368 entry->data = dev;
4369 entry->owner = THIS_MODULE;
4370 SETPROC_OPS(entry, proc_SSID_ops);
4371
4372 /* Setup the APList */
4373 entry = create_proc_entry("APList",
4374 S_IFREG | proc_perm,
4375 apriv->proc_entry);
4376 entry->uid = proc_uid;
4377 entry->gid = proc_gid;
4378 entry->data = dev;
4379 entry->owner = THIS_MODULE;
4380 SETPROC_OPS(entry, proc_APList_ops);
4381
4382 /* Setup the BSSList */
4383 entry = create_proc_entry("BSSList",
4384 S_IFREG | proc_perm,
4385 apriv->proc_entry);
4386 entry->uid = proc_uid;
4387 entry->gid = proc_gid;
4388 entry->data = dev;
4389 entry->owner = THIS_MODULE;
4390 SETPROC_OPS(entry, proc_BSSList_ops);
4391
4392 /* Setup the WepKey */
4393 entry = create_proc_entry("WepKey",
4394 S_IFREG | proc_perm,
4395 apriv->proc_entry);
4396 entry->uid = proc_uid;
4397 entry->gid = proc_gid;
4398 entry->data = dev;
4399 entry->owner = THIS_MODULE;
4400 SETPROC_OPS(entry, proc_wepkey_ops);
4401
4402 return 0;
4403}
4404
4405static int takedown_proc_entry( struct net_device *dev,
4406 struct airo_info *apriv ) {
4407 if ( !apriv->proc_entry->namelen ) return 0;
4408 remove_proc_entry("Stats",apriv->proc_entry);
4409 remove_proc_entry("StatsDelta",apriv->proc_entry);
4410 remove_proc_entry("Status",apriv->proc_entry);
4411 remove_proc_entry("Config",apriv->proc_entry);
4412 remove_proc_entry("SSID",apriv->proc_entry);
4413 remove_proc_entry("APList",apriv->proc_entry);
4414 remove_proc_entry("BSSList",apriv->proc_entry);
4415 remove_proc_entry("WepKey",apriv->proc_entry);
4416 remove_proc_entry(apriv->proc_name,airo_entry);
4417 return 0;
4418}
4419
4420/*
4421 * What we want from the proc_fs is to be able to efficiently read
4422 * and write the configuration. To do this, we want to read the
4423 * configuration when the file is opened and write it when the file is
4424 * closed. So basically we allocate a read buffer at open and fill it
4425 * with data, and allocate a write buffer and read it at close.
4426 */
4427
4428/*
4429 * The read routine is generic, it relies on the preallocated rbuffer
4430 * to supply the data.
4431 */
4432static ssize_t proc_read( struct file *file,
4433 char __user *buffer,
4434 size_t len,
4435 loff_t *offset )
4436{
4437 loff_t pos = *offset;
4438 struct proc_data *priv = (struct proc_data*)file->private_data;
4439
4440 if (!priv->rbuffer)
4441 return -EINVAL;
4442
4443 if (pos < 0)
4444 return -EINVAL;
4445 if (pos >= priv->readlen)
4446 return 0;
4447 if (len > priv->readlen - pos)
4448 len = priv->readlen - pos;
4449 if (copy_to_user(buffer, priv->rbuffer + pos, len))
4450 return -EFAULT;
4451 *offset = pos + len;
4452 return len;
4453}
4454
4455/*
4456 * The write routine is generic, it fills in a preallocated rbuffer
4457 * to supply the data.
4458 */
4459static ssize_t proc_write( struct file *file,
4460 const char __user *buffer,
4461 size_t len,
4462 loff_t *offset )
4463{
4464 loff_t pos = *offset;
4465 struct proc_data *priv = (struct proc_data*)file->private_data;
4466
4467 if (!priv->wbuffer)
4468 return -EINVAL;
4469
4470 if (pos < 0)
4471 return -EINVAL;
4472 if (pos >= priv->maxwritelen)
4473 return 0;
4474 if (len > priv->maxwritelen - pos)
4475 len = priv->maxwritelen - pos;
4476 if (copy_from_user(priv->wbuffer + pos, buffer, len))
4477 return -EFAULT;
4478 if ( pos + len > priv->writelen )
4479 priv->writelen = len + file->f_pos;
4480 *offset = pos + len;
4481 return len;
4482}
4483
4484static int proc_status_open( struct inode *inode, struct file *file ) {
4485 struct proc_data *data;
4486 struct proc_dir_entry *dp = PDE(inode);
4487 struct net_device *dev = dp->data;
4488 struct airo_info *apriv = dev->priv;
4489 CapabilityRid cap_rid;
4490 StatusRid status_rid;
4491 int i;
4492
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01004493 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 data = (struct proc_data *)file->private_data;
4496 if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
4497 kfree (file->private_data);
4498 return -ENOMEM;
4499 }
4500
4501 readStatusRid(apriv, &status_rid, 1);
4502 readCapabilityRid(apriv, &cap_rid, 1);
4503
4504 i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n",
4505 status_rid.mode & 1 ? "CFG ": "",
4506 status_rid.mode & 2 ? "ACT ": "",
4507 status_rid.mode & 0x10 ? "SYN ": "",
4508 status_rid.mode & 0x20 ? "LNK ": "",
4509 status_rid.mode & 0x40 ? "LEAP ": "",
4510 status_rid.mode & 0x80 ? "PRIV ": "",
4511 status_rid.mode & 0x100 ? "KEY ": "",
4512 status_rid.mode & 0x200 ? "WEP ": "",
4513 status_rid.mode & 0x8000 ? "ERR ": "");
4514 sprintf( data->rbuffer+i, "Mode: %x\n"
4515 "Signal Strength: %d\n"
4516 "Signal Quality: %d\n"
4517 "SSID: %-.*s\n"
4518 "AP: %-.16s\n"
4519 "Freq: %d\n"
4520 "BitRate: %dmbs\n"
4521 "Driver Version: %s\n"
4522 "Device: %s\nManufacturer: %s\nFirmware Version: %s\n"
4523 "Radio type: %x\nCountry: %x\nHardware Version: %x\n"
4524 "Software Version: %x\nSoftware Subversion: %x\n"
4525 "Boot block version: %x\n",
4526 (int)status_rid.mode,
4527 (int)status_rid.normalizedSignalStrength,
4528 (int)status_rid.signalQuality,
4529 (int)status_rid.SSIDlen,
4530 status_rid.SSID,
4531 status_rid.apName,
4532 (int)status_rid.channel,
4533 (int)status_rid.currentXmitRate/2,
4534 version,
4535 cap_rid.prodName,
4536 cap_rid.manName,
4537 cap_rid.prodVer,
4538 cap_rid.radioType,
4539 cap_rid.country,
4540 cap_rid.hardVer,
4541 (int)cap_rid.softVer,
4542 (int)cap_rid.softSubVer,
4543 (int)cap_rid.bootBlockVer );
4544 data->readlen = strlen( data->rbuffer );
4545 return 0;
4546}
4547
4548static int proc_stats_rid_open(struct inode*, struct file*, u16);
4549static int proc_statsdelta_open( struct inode *inode,
4550 struct file *file ) {
4551 if (file->f_mode&FMODE_WRITE) {
4552 return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR);
4553 }
4554 return proc_stats_rid_open(inode, file, RID_STATSDELTA);
4555}
4556
4557static int proc_stats_open( struct inode *inode, struct file *file ) {
4558 return proc_stats_rid_open(inode, file, RID_STATS);
4559}
4560
4561static int proc_stats_rid_open( struct inode *inode,
4562 struct file *file,
4563 u16 rid ) {
4564 struct proc_data *data;
4565 struct proc_dir_entry *dp = PDE(inode);
4566 struct net_device *dev = dp->data;
4567 struct airo_info *apriv = dev->priv;
4568 StatsRid stats;
4569 int i, j;
4570 u32 *vals = stats.vals;
4571
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01004572 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 data = (struct proc_data *)file->private_data;
4575 if ((data->rbuffer = kmalloc( 4096, GFP_KERNEL )) == NULL) {
4576 kfree (file->private_data);
4577 return -ENOMEM;
4578 }
4579
4580 readStatsRid(apriv, &stats, rid, 1);
4581
4582 j = 0;
4583 for(i=0; statsLabels[i]!=(char *)-1 &&
4584 i*4<stats.len; i++){
4585 if (!statsLabels[i]) continue;
4586 if (j+strlen(statsLabels[i])+16>4096) {
4587 printk(KERN_WARNING
4588 "airo: Potentially disasterous buffer overflow averted!\n");
4589 break;
4590 }
4591 j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], vals[i]);
4592 }
4593 if (i*4>=stats.len){
4594 printk(KERN_WARNING
4595 "airo: Got a short rid\n");
4596 }
4597 data->readlen = j;
4598 return 0;
4599}
4600
4601static int get_dec_u16( char *buffer, int *start, int limit ) {
4602 u16 value;
4603 int valid = 0;
4604 for( value = 0; buffer[*start] >= '0' &&
4605 buffer[*start] <= '9' &&
4606 *start < limit; (*start)++ ) {
4607 valid = 1;
4608 value *= 10;
4609 value += buffer[*start] - '0';
4610 }
4611 if ( !valid ) return -1;
4612 return value;
4613}
4614
4615static int airo_config_commit(struct net_device *dev,
4616 struct iw_request_info *info, void *zwrq,
4617 char *extra);
4618
4619static void proc_config_on_close( struct inode *inode, struct file *file ) {
4620 struct proc_data *data = file->private_data;
4621 struct proc_dir_entry *dp = PDE(inode);
4622 struct net_device *dev = dp->data;
4623 struct airo_info *ai = dev->priv;
4624 char *line;
4625
4626 if ( !data->writelen ) return;
4627
4628 readConfigRid(ai, 1);
4629 set_bit (FLAG_COMMIT, &ai->flags);
4630
4631 line = data->wbuffer;
4632 while( line[0] ) {
4633/*** Mode processing */
4634 if ( !strncmp( line, "Mode: ", 6 ) ) {
4635 line += 6;
4636 if ((ai->config.rmode & 0xff) >= RXMODE_RFMON)
4637 set_bit (FLAG_RESET, &ai->flags);
4638 ai->config.rmode &= 0xfe00;
4639 clear_bit (FLAG_802_11, &ai->flags);
4640 ai->config.opmode &= 0xFF00;
4641 ai->config.scanMode = SCANMODE_ACTIVE;
4642 if ( line[0] == 'a' ) {
4643 ai->config.opmode |= 0;
4644 } else {
4645 ai->config.opmode |= 1;
4646 if ( line[0] == 'r' ) {
4647 ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
4648 ai->config.scanMode = SCANMODE_PASSIVE;
4649 set_bit (FLAG_802_11, &ai->flags);
4650 } else if ( line[0] == 'y' ) {
4651 ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER;
4652 ai->config.scanMode = SCANMODE_PASSIVE;
4653 set_bit (FLAG_802_11, &ai->flags);
4654 } else if ( line[0] == 'l' )
4655 ai->config.rmode |= RXMODE_LANMON;
4656 }
4657 set_bit (FLAG_COMMIT, &ai->flags);
4658 }
4659
4660/*** Radio status */
4661 else if (!strncmp(line,"Radio: ", 7)) {
4662 line += 7;
4663 if (!strncmp(line,"off",3)) {
4664 set_bit (FLAG_RADIO_OFF, &ai->flags);
4665 } else {
4666 clear_bit (FLAG_RADIO_OFF, &ai->flags);
4667 }
4668 }
4669/*** NodeName processing */
4670 else if ( !strncmp( line, "NodeName: ", 10 ) ) {
4671 int j;
4672
4673 line += 10;
4674 memset( ai->config.nodeName, 0, 16 );
4675/* Do the name, assume a space between the mode and node name */
4676 for( j = 0; j < 16 && line[j] != '\n'; j++ ) {
4677 ai->config.nodeName[j] = line[j];
4678 }
4679 set_bit (FLAG_COMMIT, &ai->flags);
4680 }
4681
4682/*** PowerMode processing */
4683 else if ( !strncmp( line, "PowerMode: ", 11 ) ) {
4684 line += 11;
4685 if ( !strncmp( line, "PSPCAM", 6 ) ) {
4686 ai->config.powerSaveMode = POWERSAVE_PSPCAM;
4687 set_bit (FLAG_COMMIT, &ai->flags);
4688 } else if ( !strncmp( line, "PSP", 3 ) ) {
4689 ai->config.powerSaveMode = POWERSAVE_PSP;
4690 set_bit (FLAG_COMMIT, &ai->flags);
4691 } else {
4692 ai->config.powerSaveMode = POWERSAVE_CAM;
4693 set_bit (FLAG_COMMIT, &ai->flags);
4694 }
4695 } else if ( !strncmp( line, "DataRates: ", 11 ) ) {
4696 int v, i = 0, k = 0; /* i is index into line,
4697 k is index to rates */
4698
4699 line += 11;
4700 while((v = get_dec_u16(line, &i, 3))!=-1) {
4701 ai->config.rates[k++] = (u8)v;
4702 line += i + 1;
4703 i = 0;
4704 }
4705 set_bit (FLAG_COMMIT, &ai->flags);
4706 } else if ( !strncmp( line, "Channel: ", 9 ) ) {
4707 int v, i = 0;
4708 line += 9;
4709 v = get_dec_u16(line, &i, i+3);
4710 if ( v != -1 ) {
4711 ai->config.channelSet = (u16)v;
4712 set_bit (FLAG_COMMIT, &ai->flags);
4713 }
4714 } else if ( !strncmp( line, "XmitPower: ", 11 ) ) {
4715 int v, i = 0;
4716 line += 11;
4717 v = get_dec_u16(line, &i, i+3);
4718 if ( v != -1 ) {
4719 ai->config.txPower = (u16)v;
4720 set_bit (FLAG_COMMIT, &ai->flags);
4721 }
4722 } else if ( !strncmp( line, "WEP: ", 5 ) ) {
4723 line += 5;
4724 switch( line[0] ) {
4725 case 's':
4726 ai->config.authType = (u16)AUTH_SHAREDKEY;
4727 break;
4728 case 'e':
4729 ai->config.authType = (u16)AUTH_ENCRYPT;
4730 break;
4731 default:
4732 ai->config.authType = (u16)AUTH_OPEN;
4733 break;
4734 }
4735 set_bit (FLAG_COMMIT, &ai->flags);
4736 } else if ( !strncmp( line, "LongRetryLimit: ", 16 ) ) {
4737 int v, i = 0;
4738
4739 line += 16;
4740 v = get_dec_u16(line, &i, 3);
4741 v = (v<0) ? 0 : ((v>255) ? 255 : v);
4742 ai->config.longRetryLimit = (u16)v;
4743 set_bit (FLAG_COMMIT, &ai->flags);
4744 } else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) {
4745 int v, i = 0;
4746
4747 line += 17;
4748 v = get_dec_u16(line, &i, 3);
4749 v = (v<0) ? 0 : ((v>255) ? 255 : v);
4750 ai->config.shortRetryLimit = (u16)v;
4751 set_bit (FLAG_COMMIT, &ai->flags);
4752 } else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) {
4753 int v, i = 0;
4754
4755 line += 14;
4756 v = get_dec_u16(line, &i, 4);
4757 v = (v<0) ? 0 : ((v>2312) ? 2312 : v);
4758 ai->config.rtsThres = (u16)v;
4759 set_bit (FLAG_COMMIT, &ai->flags);
4760 } else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) {
4761 int v, i = 0;
4762
4763 line += 16;
4764 v = get_dec_u16(line, &i, 5);
4765 v = (v<0) ? 0 : v;
4766 ai->config.txLifetime = (u16)v;
4767 set_bit (FLAG_COMMIT, &ai->flags);
4768 } else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) {
4769 int v, i = 0;
4770
4771 line += 16;
4772 v = get_dec_u16(line, &i, 5);
4773 v = (v<0) ? 0 : v;
4774 ai->config.rxLifetime = (u16)v;
4775 set_bit (FLAG_COMMIT, &ai->flags);
4776 } else if ( !strncmp( line, "TXDiversity: ", 13 ) ) {
4777 ai->config.txDiversity =
4778 (line[13]=='l') ? 1 :
4779 ((line[13]=='r')? 2: 3);
4780 set_bit (FLAG_COMMIT, &ai->flags);
4781 } else if ( !strncmp( line, "RXDiversity: ", 13 ) ) {
4782 ai->config.rxDiversity =
4783 (line[13]=='l') ? 1 :
4784 ((line[13]=='r')? 2: 3);
4785 set_bit (FLAG_COMMIT, &ai->flags);
4786 } else if ( !strncmp( line, "FragThreshold: ", 15 ) ) {
4787 int v, i = 0;
4788
4789 line += 15;
4790 v = get_dec_u16(line, &i, 4);
4791 v = (v<256) ? 256 : ((v>2312) ? 2312 : v);
4792 v = v & 0xfffe; /* Make sure its even */
4793 ai->config.fragThresh = (u16)v;
4794 set_bit (FLAG_COMMIT, &ai->flags);
4795 } else if (!strncmp(line, "Modulation: ", 12)) {
4796 line += 12;
4797 switch(*line) {
4798 case 'd': ai->config.modulation=MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break;
4799 case 'c': ai->config.modulation=MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break;
4800 case 'm': ai->config.modulation=MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break;
4801 default:
4802 printk( KERN_WARNING "airo: Unknown modulation\n" );
4803 }
4804 } else if (!strncmp(line, "Preamble: ", 10)) {
4805 line += 10;
4806 switch(*line) {
4807 case 'a': ai->config.preamble=PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break;
4808 case 'l': ai->config.preamble=PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break;
4809 case 's': ai->config.preamble=PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break;
4810 default: printk(KERN_WARNING "airo: Unknown preamble\n");
4811 }
4812 } else {
4813 printk( KERN_WARNING "Couldn't figure out %s\n", line );
4814 }
4815 while( line[0] && line[0] != '\n' ) line++;
4816 if ( line[0] ) line++;
4817 }
4818 airo_config_commit(dev, NULL, NULL, NULL);
4819}
4820
4821static char *get_rmode(u16 mode) {
4822 switch(mode&0xff) {
4823 case RXMODE_RFMON: return "rfmon";
4824 case RXMODE_RFMON_ANYBSS: return "yna (any) bss rfmon";
4825 case RXMODE_LANMON: return "lanmon";
4826 }
4827 return "ESS";
4828}
4829
4830static int proc_config_open( struct inode *inode, struct file *file ) {
4831 struct proc_data *data;
4832 struct proc_dir_entry *dp = PDE(inode);
4833 struct net_device *dev = dp->data;
4834 struct airo_info *ai = dev->priv;
4835 int i;
4836
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01004837 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 data = (struct proc_data *)file->private_data;
4840 if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
4841 kfree (file->private_data);
4842 return -ENOMEM;
4843 }
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01004844 if ((data->wbuffer = kzalloc( 2048, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 kfree (data->rbuffer);
4846 kfree (file->private_data);
4847 return -ENOMEM;
4848 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 data->maxwritelen = 2048;
4850 data->on_close = proc_config_on_close;
4851
4852 readConfigRid(ai, 1);
4853
4854 i = sprintf( data->rbuffer,
4855 "Mode: %s\n"
4856 "Radio: %s\n"
4857 "NodeName: %-16s\n"
4858 "PowerMode: %s\n"
4859 "DataRates: %d %d %d %d %d %d %d %d\n"
4860 "Channel: %d\n"
4861 "XmitPower: %d\n",
4862 (ai->config.opmode & 0xFF) == 0 ? "adhoc" :
4863 (ai->config.opmode & 0xFF) == 1 ? get_rmode(ai->config.rmode):
4864 (ai->config.opmode & 0xFF) == 2 ? "AP" :
4865 (ai->config.opmode & 0xFF) == 3 ? "AP RPTR" : "Error",
4866 test_bit(FLAG_RADIO_OFF, &ai->flags) ? "off" : "on",
4867 ai->config.nodeName,
4868 ai->config.powerSaveMode == 0 ? "CAM" :
4869 ai->config.powerSaveMode == 1 ? "PSP" :
4870 ai->config.powerSaveMode == 2 ? "PSPCAM" : "Error",
4871 (int)ai->config.rates[0],
4872 (int)ai->config.rates[1],
4873 (int)ai->config.rates[2],
4874 (int)ai->config.rates[3],
4875 (int)ai->config.rates[4],
4876 (int)ai->config.rates[5],
4877 (int)ai->config.rates[6],
4878 (int)ai->config.rates[7],
4879 (int)ai->config.channelSet,
4880 (int)ai->config.txPower
4881 );
4882 sprintf( data->rbuffer + i,
4883 "LongRetryLimit: %d\n"
4884 "ShortRetryLimit: %d\n"
4885 "RTSThreshold: %d\n"
4886 "TXMSDULifetime: %d\n"
4887 "RXMSDULifetime: %d\n"
4888 "TXDiversity: %s\n"
4889 "RXDiversity: %s\n"
4890 "FragThreshold: %d\n"
4891 "WEP: %s\n"
4892 "Modulation: %s\n"
4893 "Preamble: %s\n",
4894 (int)ai->config.longRetryLimit,
4895 (int)ai->config.shortRetryLimit,
4896 (int)ai->config.rtsThres,
4897 (int)ai->config.txLifetime,
4898 (int)ai->config.rxLifetime,
4899 ai->config.txDiversity == 1 ? "left" :
4900 ai->config.txDiversity == 2 ? "right" : "both",
4901 ai->config.rxDiversity == 1 ? "left" :
4902 ai->config.rxDiversity == 2 ? "right" : "both",
4903 (int)ai->config.fragThresh,
4904 ai->config.authType == AUTH_ENCRYPT ? "encrypt" :
4905 ai->config.authType == AUTH_SHAREDKEY ? "shared" : "open",
4906 ai->config.modulation == 0 ? "default" :
4907 ai->config.modulation == MOD_CCK ? "cck" :
4908 ai->config.modulation == MOD_MOK ? "mok" : "error",
4909 ai->config.preamble == PREAMBLE_AUTO ? "auto" :
4910 ai->config.preamble == PREAMBLE_LONG ? "long" :
4911 ai->config.preamble == PREAMBLE_SHORT ? "short" : "error"
4912 );
4913 data->readlen = strlen( data->rbuffer );
4914 return 0;
4915}
4916
4917static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
4918 struct proc_data *data = (struct proc_data *)file->private_data;
4919 struct proc_dir_entry *dp = PDE(inode);
4920 struct net_device *dev = dp->data;
4921 struct airo_info *ai = dev->priv;
4922 SsidRid SSID_rid;
4923 Resp rsp;
4924 int i;
4925 int offset = 0;
4926
4927 if ( !data->writelen ) return;
4928
4929 memset( &SSID_rid, 0, sizeof( SSID_rid ) );
4930
4931 for( i = 0; i < 3; i++ ) {
4932 int j;
4933 for( j = 0; j+offset < data->writelen && j < 32 &&
4934 data->wbuffer[offset+j] != '\n'; j++ ) {
4935 SSID_rid.ssids[i].ssid[j] = data->wbuffer[offset+j];
4936 }
4937 if ( j == 0 ) break;
4938 SSID_rid.ssids[i].len = j;
4939 offset += j;
4940 while( data->wbuffer[offset] != '\n' &&
4941 offset < data->writelen ) offset++;
4942 offset++;
4943 }
4944 if (i)
4945 SSID_rid.len = sizeof(SSID_rid);
4946 disable_MAC(ai, 1);
4947 writeSsidRid(ai, &SSID_rid, 1);
4948 enable_MAC(ai, &rsp, 1);
4949}
4950
Jesper Juhl77933d72005-07-27 11:46:09 -07004951static inline u8 hexVal(char c) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 if (c>='0' && c<='9') return c -= '0';
4953 if (c>='a' && c<='f') return c -= 'a'-10;
4954 if (c>='A' && c<='F') return c -= 'A'-10;
4955 return 0;
4956}
4957
4958static void proc_APList_on_close( struct inode *inode, struct file *file ) {
4959 struct proc_data *data = (struct proc_data *)file->private_data;
4960 struct proc_dir_entry *dp = PDE(inode);
4961 struct net_device *dev = dp->data;
4962 struct airo_info *ai = dev->priv;
4963 APListRid APList_rid;
4964 Resp rsp;
4965 int i;
4966
4967 if ( !data->writelen ) return;
4968
4969 memset( &APList_rid, 0, sizeof(APList_rid) );
4970 APList_rid.len = sizeof(APList_rid);
4971
4972 for( i = 0; i < 4 && data->writelen >= (i+1)*6*3; i++ ) {
4973 int j;
4974 for( j = 0; j < 6*3 && data->wbuffer[j+i*6*3]; j++ ) {
4975 switch(j%3) {
4976 case 0:
4977 APList_rid.ap[i][j/3]=
4978 hexVal(data->wbuffer[j+i*6*3])<<4;
4979 break;
4980 case 1:
4981 APList_rid.ap[i][j/3]|=
4982 hexVal(data->wbuffer[j+i*6*3]);
4983 break;
4984 }
4985 }
4986 }
4987 disable_MAC(ai, 1);
4988 writeAPListRid(ai, &APList_rid, 1);
4989 enable_MAC(ai, &rsp, 1);
4990}
4991
4992/* This function wraps PC4500_writerid with a MAC disable */
4993static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data,
4994 int len, int dummy ) {
4995 int rc;
4996 Resp rsp;
4997
4998 disable_MAC(ai, 1);
4999 rc = PC4500_writerid(ai, rid, rid_data, len, 1);
5000 enable_MAC(ai, &rsp, 1);
5001 return rc;
5002}
5003
5004/* Returns the length of the key at the index. If index == 0xffff
5005 * the index of the transmit key is returned. If the key doesn't exist,
5006 * -1 will be returned.
5007 */
5008static int get_wep_key(struct airo_info *ai, u16 index) {
5009 WepKeyRid wkr;
5010 int rc;
5011 u16 lastindex;
5012
5013 rc = readWepKeyRid(ai, &wkr, 1, 1);
5014 if (rc == SUCCESS) do {
5015 lastindex = wkr.kindex;
5016 if (wkr.kindex == index) {
5017 if (index == 0xffff) {
5018 return wkr.mac[0];
5019 }
5020 return wkr.klen;
5021 }
5022 readWepKeyRid(ai, &wkr, 0, 1);
5023 } while(lastindex != wkr.kindex);
5024 return -1;
5025}
5026
5027static int set_wep_key(struct airo_info *ai, u16 index,
5028 const char *key, u16 keylen, int perm, int lock ) {
5029 static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
5030 WepKeyRid wkr;
5031 Resp rsp;
5032
5033 memset(&wkr, 0, sizeof(wkr));
5034 if (keylen == 0) {
5035// We are selecting which key to use
5036 wkr.len = sizeof(wkr);
5037 wkr.kindex = 0xffff;
5038 wkr.mac[0] = (char)index;
5039 if (perm) printk(KERN_INFO "Setting transmit key to %d\n", index);
5040 if (perm) ai->defindex = (char)index;
5041 } else {
5042// We are actually setting the key
5043 wkr.len = sizeof(wkr);
5044 wkr.kindex = index;
5045 wkr.klen = keylen;
5046 memcpy( wkr.key, key, keylen );
5047 memcpy( wkr.mac, macaddr, ETH_ALEN );
5048 printk(KERN_INFO "Setting key %d\n", index);
5049 }
5050
Dan Streetmanf89b2322005-11-11 11:41:42 -05005051 if (perm) disable_MAC(ai, lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052 writeWepKeyRid(ai, &wkr, perm, lock);
Dan Streetmanf89b2322005-11-11 11:41:42 -05005053 if (perm) enable_MAC(ai, &rsp, lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 return 0;
5055}
5056
5057static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
5058 struct proc_data *data;
5059 struct proc_dir_entry *dp = PDE(inode);
5060 struct net_device *dev = dp->data;
5061 struct airo_info *ai = dev->priv;
5062 int i;
5063 char key[16];
5064 u16 index = 0;
5065 int j = 0;
5066
5067 memset(key, 0, sizeof(key));
5068
5069 data = (struct proc_data *)file->private_data;
5070 if ( !data->writelen ) return;
5071
5072 if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' &&
5073 (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) {
5074 index = data->wbuffer[0] - '0';
5075 if (data->wbuffer[1] == '\n') {
5076 set_wep_key(ai, index, NULL, 0, 1, 1);
5077 return;
5078 }
5079 j = 2;
5080 } else {
5081 printk(KERN_ERR "airo: WepKey passed invalid key index\n");
5082 return;
5083 }
5084
5085 for( i = 0; i < 16*3 && data->wbuffer[i+j]; i++ ) {
5086 switch(i%3) {
5087 case 0:
5088 key[i/3] = hexVal(data->wbuffer[i+j])<<4;
5089 break;
5090 case 1:
5091 key[i/3] |= hexVal(data->wbuffer[i+j]);
5092 break;
5093 }
5094 }
5095 set_wep_key(ai, index, key, i/3, 1, 1);
5096}
5097
5098static int proc_wepkey_open( struct inode *inode, struct file *file ) {
5099 struct proc_data *data;
5100 struct proc_dir_entry *dp = PDE(inode);
5101 struct net_device *dev = dp->data;
5102 struct airo_info *ai = dev->priv;
5103 char *ptr;
5104 WepKeyRid wkr;
5105 u16 lastindex;
5106 int j=0;
5107 int rc;
5108
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005109 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111 memset(&wkr, 0, sizeof(wkr));
5112 data = (struct proc_data *)file->private_data;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005113 if ((data->rbuffer = kzalloc( 180, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 kfree (file->private_data);
5115 return -ENOMEM;
5116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 data->writelen = 0;
5118 data->maxwritelen = 80;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005119 if ((data->wbuffer = kzalloc( 80, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 kfree (data->rbuffer);
5121 kfree (file->private_data);
5122 return -ENOMEM;
5123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124 data->on_close = proc_wepkey_on_close;
5125
5126 ptr = data->rbuffer;
5127 strcpy(ptr, "No wep keys\n");
5128 rc = readWepKeyRid(ai, &wkr, 1, 1);
5129 if (rc == SUCCESS) do {
5130 lastindex = wkr.kindex;
5131 if (wkr.kindex == 0xffff) {
5132 j += sprintf(ptr+j, "Tx key = %d\n",
5133 (int)wkr.mac[0]);
5134 } else {
5135 j += sprintf(ptr+j, "Key %d set with length = %d\n",
5136 (int)wkr.kindex, (int)wkr.klen);
5137 }
5138 readWepKeyRid(ai, &wkr, 0, 1);
5139 } while((lastindex != wkr.kindex) && (j < 180-30));
5140
5141 data->readlen = strlen( data->rbuffer );
5142 return 0;
5143}
5144
5145static int proc_SSID_open( struct inode *inode, struct file *file ) {
5146 struct proc_data *data;
5147 struct proc_dir_entry *dp = PDE(inode);
5148 struct net_device *dev = dp->data;
5149 struct airo_info *ai = dev->priv;
5150 int i;
5151 char *ptr;
5152 SsidRid SSID_rid;
5153
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005154 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 data = (struct proc_data *)file->private_data;
5157 if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
5158 kfree (file->private_data);
5159 return -ENOMEM;
5160 }
5161 data->writelen = 0;
5162 data->maxwritelen = 33*3;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005163 if ((data->wbuffer = kzalloc( 33*3, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 kfree (data->rbuffer);
5165 kfree (file->private_data);
5166 return -ENOMEM;
5167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 data->on_close = proc_SSID_on_close;
5169
5170 readSsidRid(ai, &SSID_rid);
5171 ptr = data->rbuffer;
5172 for( i = 0; i < 3; i++ ) {
5173 int j;
5174 if ( !SSID_rid.ssids[i].len ) break;
5175 for( j = 0; j < 32 &&
5176 j < SSID_rid.ssids[i].len &&
5177 SSID_rid.ssids[i].ssid[j]; j++ ) {
5178 *ptr++ = SSID_rid.ssids[i].ssid[j];
5179 }
5180 *ptr++ = '\n';
5181 }
5182 *ptr = '\0';
5183 data->readlen = strlen( data->rbuffer );
5184 return 0;
5185}
5186
5187static int proc_APList_open( struct inode *inode, struct file *file ) {
5188 struct proc_data *data;
5189 struct proc_dir_entry *dp = PDE(inode);
5190 struct net_device *dev = dp->data;
5191 struct airo_info *ai = dev->priv;
5192 int i;
5193 char *ptr;
5194 APListRid APList_rid;
5195
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005196 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 data = (struct proc_data *)file->private_data;
5199 if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
5200 kfree (file->private_data);
5201 return -ENOMEM;
5202 }
5203 data->writelen = 0;
5204 data->maxwritelen = 4*6*3;
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005205 if ((data->wbuffer = kzalloc( data->maxwritelen, GFP_KERNEL )) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 kfree (data->rbuffer);
5207 kfree (file->private_data);
5208 return -ENOMEM;
5209 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 data->on_close = proc_APList_on_close;
5211
5212 readAPListRid(ai, &APList_rid);
5213 ptr = data->rbuffer;
5214 for( i = 0; i < 4; i++ ) {
5215// We end when we find a zero MAC
5216 if ( !*(int*)APList_rid.ap[i] &&
5217 !*(int*)&APList_rid.ap[i][2]) break;
5218 ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x\n",
5219 (int)APList_rid.ap[i][0],
5220 (int)APList_rid.ap[i][1],
5221 (int)APList_rid.ap[i][2],
5222 (int)APList_rid.ap[i][3],
5223 (int)APList_rid.ap[i][4],
5224 (int)APList_rid.ap[i][5]);
5225 }
5226 if (i==0) ptr += sprintf(ptr, "Not using specific APs\n");
5227
5228 *ptr = '\0';
5229 data->readlen = strlen( data->rbuffer );
5230 return 0;
5231}
5232
5233static int proc_BSSList_open( struct inode *inode, struct file *file ) {
5234 struct proc_data *data;
5235 struct proc_dir_entry *dp = PDE(inode);
5236 struct net_device *dev = dp->data;
5237 struct airo_info *ai = dev->priv;
5238 char *ptr;
5239 BSSListRid BSSList_rid;
5240 int rc;
5241 /* If doLoseSync is not 1, we won't do a Lose Sync */
5242 int doLoseSync = -1;
5243
Panagiotis Issarisb69a3aa2005-11-08 00:03:15 +01005244 if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246 data = (struct proc_data *)file->private_data;
5247 if ((data->rbuffer = kmalloc( 1024, GFP_KERNEL )) == NULL) {
5248 kfree (file->private_data);
5249 return -ENOMEM;
5250 }
5251 data->writelen = 0;
5252 data->maxwritelen = 0;
5253 data->wbuffer = NULL;
5254 data->on_close = NULL;
5255
5256 if (file->f_mode & FMODE_WRITE) {
5257 if (!(file->f_mode & FMODE_READ)) {
5258 Cmd cmd;
5259 Resp rsp;
5260
5261 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
5262 memset(&cmd, 0, sizeof(cmd));
5263 cmd.cmd=CMD_LISTBSS;
5264 if (down_interruptible(&ai->sem))
5265 return -ERESTARTSYS;
5266 issuecommand(ai, &cmd, &rsp);
5267 up(&ai->sem);
5268 data->readlen = 0;
5269 return 0;
5270 }
5271 doLoseSync = 1;
5272 }
5273 ptr = data->rbuffer;
5274 /* There is a race condition here if there are concurrent opens.
5275 Since it is a rare condition, we'll just live with it, otherwise
5276 we have to add a spin lock... */
5277 rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
5278 while(rc == 0 && BSSList_rid.index != 0xffff) {
5279 ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x %*s rssi = %d",
5280 (int)BSSList_rid.bssid[0],
5281 (int)BSSList_rid.bssid[1],
5282 (int)BSSList_rid.bssid[2],
5283 (int)BSSList_rid.bssid[3],
5284 (int)BSSList_rid.bssid[4],
5285 (int)BSSList_rid.bssid[5],
5286 (int)BSSList_rid.ssidLen,
5287 BSSList_rid.ssid,
Dan Williams41480af2005-05-10 09:45:51 -04005288 (int)BSSList_rid.dBm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 ptr += sprintf(ptr, " channel = %d %s %s %s %s\n",
5290 (int)BSSList_rid.dsChannel,
5291 BSSList_rid.cap & CAP_ESS ? "ESS" : "",
5292 BSSList_rid.cap & CAP_IBSS ? "adhoc" : "",
5293 BSSList_rid.cap & CAP_PRIVACY ? "wep" : "",
5294 BSSList_rid.cap & CAP_SHORTHDR ? "shorthdr" : "");
5295 rc = readBSSListRid(ai, 0, &BSSList_rid);
5296 }
5297 *ptr = '\0';
5298 data->readlen = strlen( data->rbuffer );
5299 return 0;
5300}
5301
5302static int proc_close( struct inode *inode, struct file *file )
5303{
Jesper Juhlb4558ea2005-10-28 16:53:13 -04005304 struct proc_data *data = file->private_data;
5305
5306 if (data->on_close != NULL)
5307 data->on_close(inode, file);
5308 kfree(data->rbuffer);
5309 kfree(data->wbuffer);
5310 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 return 0;
5312}
5313
5314static struct net_device_list {
5315 struct net_device *dev;
5316 struct net_device_list *next;
5317} *airo_devices;
5318
5319/* Since the card doesn't automatically switch to the right WEP mode,
5320 we will make it do it. If the card isn't associated, every secs we
5321 will switch WEP modes to see if that will help. If the card is
5322 associated we will check every minute to see if anything has
5323 changed. */
5324static void timer_func( struct net_device *dev ) {
5325 struct airo_info *apriv = dev->priv;
5326 Resp rsp;
5327
5328/* We don't have a link so try changing the authtype */
5329 readConfigRid(apriv, 0);
5330 disable_MAC(apriv, 0);
5331 switch(apriv->config.authType) {
5332 case AUTH_ENCRYPT:
5333/* So drop to OPEN */
5334 apriv->config.authType = AUTH_OPEN;
5335 break;
5336 case AUTH_SHAREDKEY:
5337 if (apriv->keyindex < auto_wep) {
5338 set_wep_key(apriv, apriv->keyindex, NULL, 0, 0, 0);
5339 apriv->config.authType = AUTH_SHAREDKEY;
5340 apriv->keyindex++;
5341 } else {
5342 /* Drop to ENCRYPT */
5343 apriv->keyindex = 0;
5344 set_wep_key(apriv, apriv->defindex, NULL, 0, 0, 0);
5345 apriv->config.authType = AUTH_ENCRYPT;
5346 }
5347 break;
5348 default: /* We'll escalate to SHAREDKEY */
5349 apriv->config.authType = AUTH_SHAREDKEY;
5350 }
5351 set_bit (FLAG_COMMIT, &apriv->flags);
5352 writeConfigRid(apriv, 0);
5353 enable_MAC(apriv, &rsp, 0);
5354 up(&apriv->sem);
5355
5356/* Schedule check to see if the change worked */
5357 clear_bit(JOB_AUTOWEP, &apriv->flags);
5358 apriv->expires = RUN_AT(HZ*3);
5359}
5360
5361static int add_airo_dev( struct net_device *dev ) {
5362 struct net_device_list *node = kmalloc( sizeof( *node ), GFP_KERNEL );
5363 if ( !node )
5364 return -ENOMEM;
5365
5366 node->dev = dev;
5367 node->next = airo_devices;
5368 airo_devices = node;
5369
5370 return 0;
5371}
5372
5373static void del_airo_dev( struct net_device *dev ) {
5374 struct net_device_list **p = &airo_devices;
5375 while( *p && ( (*p)->dev != dev ) )
5376 p = &(*p)->next;
5377 if ( *p && (*p)->dev == dev )
5378 *p = (*p)->next;
5379}
5380
5381#ifdef CONFIG_PCI
5382static int __devinit airo_pci_probe(struct pci_dev *pdev,
5383 const struct pci_device_id *pent)
5384{
5385 struct net_device *dev;
5386
5387 if (pci_enable_device(pdev))
5388 return -ENODEV;
5389 pci_set_master(pdev);
5390
5391 if (pdev->device == 0x5000 || pdev->device == 0xa504)
5392 dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev);
5393 else
5394 dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev);
5395 if (!dev)
5396 return -ENODEV;
5397
5398 pci_set_drvdata(pdev, dev);
5399 return 0;
5400}
5401
5402static void __devexit airo_pci_remove(struct pci_dev *pdev)
5403{
5404}
5405
Pavel Machek05adc3b2005-04-16 15:25:25 -07005406static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407{
5408 struct net_device *dev = pci_get_drvdata(pdev);
5409 struct airo_info *ai = dev->priv;
5410 Cmd cmd;
5411 Resp rsp;
5412
5413 if ((ai->APList == NULL) &&
5414 (ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL)) == NULL)
5415 return -ENOMEM;
5416 if ((ai->SSID == NULL) &&
5417 (ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL)) == NULL)
5418 return -ENOMEM;
5419 readAPListRid(ai, ai->APList);
5420 readSsidRid(ai, ai->SSID);
5421 memset(&cmd, 0, sizeof(cmd));
5422 /* the lock will be released at the end of the resume callback */
5423 if (down_interruptible(&ai->sem))
5424 return -EAGAIN;
5425 disable_MAC(ai, 0);
5426 netif_device_detach(dev);
5427 ai->power = state;
5428 cmd.cmd=HOSTSLEEP;
5429 issuecommand(ai, &cmd, &rsp);
5430
Pavel Machek1cc68ae2005-06-20 15:33:04 -07005431 pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 pci_save_state(pdev);
Pavel Machek1cc68ae2005-06-20 15:33:04 -07005433 return pci_set_power_state(pdev, pci_choose_state(pdev, state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434}
5435
5436static int airo_pci_resume(struct pci_dev *pdev)
5437{
5438 struct net_device *dev = pci_get_drvdata(pdev);
5439 struct airo_info *ai = dev->priv;
5440 Resp rsp;
Michal Schmidt53232802005-10-04 07:46:21 -04005441 pci_power_t prev_state = pdev->current_state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442
Michal Schmidt53232802005-10-04 07:46:21 -04005443 pci_set_power_state(pdev, PCI_D0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444 pci_restore_state(pdev);
Michal Schmidt53232802005-10-04 07:46:21 -04005445 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446
Michal Schmidt53232802005-10-04 07:46:21 -04005447 if (prev_state != PCI_D1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 reset_card(dev, 0);
5449 mpi_init_descriptors(ai);
5450 setup_card(ai, dev->dev_addr, 0);
5451 clear_bit(FLAG_RADIO_OFF, &ai->flags);
5452 clear_bit(FLAG_PENDING_XMIT, &ai->flags);
5453 } else {
5454 OUT4500(ai, EVACK, EV_AWAKEN);
5455 OUT4500(ai, EVACK, EV_AWAKEN);
5456 msleep(100);
5457 }
5458
5459 set_bit (FLAG_COMMIT, &ai->flags);
5460 disable_MAC(ai, 0);
5461 msleep(200);
5462 if (ai->SSID) {
5463 writeSsidRid(ai, ai->SSID, 0);
5464 kfree(ai->SSID);
5465 ai->SSID = NULL;
5466 }
5467 if (ai->APList) {
5468 writeAPListRid(ai, ai->APList, 0);
5469 kfree(ai->APList);
5470 ai->APList = NULL;
5471 }
5472 writeConfigRid(ai, 0);
5473 enable_MAC(ai, &rsp, 0);
Pavel Machek1cc68ae2005-06-20 15:33:04 -07005474 ai->power = PMSG_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 netif_device_attach(dev);
5476 netif_wake_queue(dev);
5477 enable_interrupts(ai);
5478 up(&ai->sem);
5479 return 0;
5480}
5481#endif
5482
5483static int __init airo_init_module( void )
5484{
5485 int i, have_isa_dev = 0;
5486
5487 airo_entry = create_proc_entry("aironet",
5488 S_IFDIR | airo_perm,
5489 proc_root_driver);
5490 airo_entry->uid = proc_uid;
5491 airo_entry->gid = proc_gid;
5492
5493 for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
5494 printk( KERN_INFO
5495 "airo: Trying to configure ISA adapter at irq=%d io=0x%x\n",
5496 irq[i], io[i] );
5497 if (init_airo_card( irq[i], io[i], 0, NULL ))
5498 have_isa_dev = 1;
5499 }
5500
5501#ifdef CONFIG_PCI
5502 printk( KERN_INFO "airo: Probing for PCI adapters\n" );
5503 pci_register_driver(&airo_driver);
5504 printk( KERN_INFO "airo: Finished probing for PCI adapters\n" );
5505#endif
5506
5507 /* Always exit with success, as we are a library module
5508 * as well as a driver module
5509 */
5510 return 0;
5511}
5512
5513static void __exit airo_cleanup_module( void )
5514{
5515 while( airo_devices ) {
5516 printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name );
5517 stop_airo_card( airo_devices->dev, 1 );
5518 }
5519#ifdef CONFIG_PCI
5520 pci_unregister_driver(&airo_driver);
5521#endif
5522 remove_proc_entry("aironet", proc_root_driver);
5523}
5524
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525/*
5526 * Initial Wireless Extension code for Aironet driver by :
5527 * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 17 November 00
5528 * Conversion to new driver API by :
5529 * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 26 March 02
5530 * Javier also did a good amount of work here, adding some new extensions
5531 * and fixing my code. Let's just say that without him this code just
5532 * would not work at all... - Jean II
5533 */
5534
Dan Williams41480af2005-05-10 09:45:51 -04005535static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi)
5536{
5537 if( !rssi_rid )
5538 return 0;
5539
5540 return (0x100 - rssi_rid[rssi].rssidBm);
5541}
5542
5543static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
5544{
5545 int i;
5546
5547 if( !rssi_rid )
5548 return 0;
5549
5550 for( i = 0; i < 256; i++ )
5551 if (rssi_rid[i].rssidBm == dbm)
5552 return rssi_rid[i].rssipct;
5553
5554 return 0;
5555}
5556
5557
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid)
5559{
5560 int quality = 0;
5561
5562 if ((status_rid->mode & 0x3f) == 0x3f && (cap_rid->hardCap & 8)) {
5563 if (memcmp(cap_rid->prodName, "350", 3))
5564 if (status_rid->signalQuality > 0x20)
5565 quality = 0;
5566 else
5567 quality = 0x20 - status_rid->signalQuality;
5568 else
5569 if (status_rid->signalQuality > 0xb0)
5570 quality = 0;
5571 else if (status_rid->signalQuality < 0x10)
5572 quality = 0xa0;
5573 else
5574 quality = 0xb0 - status_rid->signalQuality;
5575 }
5576 return quality;
5577}
5578
5579#define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0)
5580#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50);
5581
5582/*------------------------------------------------------------------*/
5583/*
5584 * Wireless Handler : get protocol name
5585 */
5586static int airo_get_name(struct net_device *dev,
5587 struct iw_request_info *info,
5588 char *cwrq,
5589 char *extra)
5590{
5591 strcpy(cwrq, "IEEE 802.11-DS");
5592 return 0;
5593}
5594
5595/*------------------------------------------------------------------*/
5596/*
5597 * Wireless Handler : set frequency
5598 */
5599static int airo_set_freq(struct net_device *dev,
5600 struct iw_request_info *info,
5601 struct iw_freq *fwrq,
5602 char *extra)
5603{
5604 struct airo_info *local = dev->priv;
5605 int rc = -EINPROGRESS; /* Call commit handler */
5606
5607 /* If setting by frequency, convert to a channel */
5608 if((fwrq->e == 1) &&
5609 (fwrq->m >= (int) 2.412e8) &&
5610 (fwrq->m <= (int) 2.487e8)) {
5611 int f = fwrq->m / 100000;
5612 int c = 0;
5613 while((c < 14) && (f != frequency_list[c]))
5614 c++;
5615 /* Hack to fall through... */
5616 fwrq->e = 0;
5617 fwrq->m = c + 1;
5618 }
5619 /* Setting by channel number */
5620 if((fwrq->m > 1000) || (fwrq->e > 0))
5621 rc = -EOPNOTSUPP;
5622 else {
5623 int channel = fwrq->m;
5624 /* We should do a better check than that,
5625 * based on the card capability !!! */
Javier Achirica2610c732006-01-17 08:01:01 -05005626 if((channel < 1) || (channel > 14)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627 printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, fwrq->m);
5628 rc = -EINVAL;
5629 } else {
5630 readConfigRid(local, 1);
5631 /* Yes ! We can set it !!! */
Javier Achirica2610c732006-01-17 08:01:01 -05005632 local->config.channelSet = (u16) channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 set_bit (FLAG_COMMIT, &local->flags);
5634 }
5635 }
5636 return rc;
5637}
5638
5639/*------------------------------------------------------------------*/
5640/*
5641 * Wireless Handler : get frequency
5642 */
5643static int airo_get_freq(struct net_device *dev,
5644 struct iw_request_info *info,
5645 struct iw_freq *fwrq,
5646 char *extra)
5647{
5648 struct airo_info *local = dev->priv;
5649 StatusRid status_rid; /* Card status info */
Javier Achirica2610c732006-01-17 08:01:01 -05005650 int ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651
5652 readConfigRid(local, 1);
5653 if ((local->config.opmode & 0xFF) == MODE_STA_ESS)
5654 status_rid.channel = local->config.channelSet;
5655 else
5656 readStatusRid(local, &status_rid, 1);
5657
Javier Achirica2610c732006-01-17 08:01:01 -05005658 ch = (int)status_rid.channel;
5659 if((ch > 0) && (ch < 15)) {
5660 fwrq->m = frequency_list[ch - 1] * 100000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661 fwrq->e = 1;
Javier Achirica2610c732006-01-17 08:01:01 -05005662 } else {
5663 fwrq->m = ch;
5664 fwrq->e = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005666
5667 return 0;
5668}
5669
5670/*------------------------------------------------------------------*/
5671/*
5672 * Wireless Handler : set ESSID
5673 */
5674static int airo_set_essid(struct net_device *dev,
5675 struct iw_request_info *info,
5676 struct iw_point *dwrq,
5677 char *extra)
5678{
5679 struct airo_info *local = dev->priv;
5680 Resp rsp;
5681 SsidRid SSID_rid; /* SSIDs */
5682
5683 /* Reload the list of current SSID */
5684 readSsidRid(local, &SSID_rid);
5685
5686 /* Check if we asked for `any' */
5687 if(dwrq->flags == 0) {
5688 /* Just send an empty SSID list */
5689 memset(&SSID_rid, 0, sizeof(SSID_rid));
5690 } else {
5691 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
5692
5693 /* Check the size of the string */
5694 if(dwrq->length > IW_ESSID_MAX_SIZE+1) {
5695 return -E2BIG ;
5696 }
5697 /* Check if index is valid */
5698 if((index < 0) || (index >= 4)) {
5699 return -EINVAL;
5700 }
5701
5702 /* Set the SSID */
5703 memset(SSID_rid.ssids[index].ssid, 0,
5704 sizeof(SSID_rid.ssids[index].ssid));
5705 memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
5706 SSID_rid.ssids[index].len = dwrq->length - 1;
5707 }
5708 SSID_rid.len = sizeof(SSID_rid);
5709 /* Write it to the card */
5710 disable_MAC(local, 1);
5711 writeSsidRid(local, &SSID_rid, 1);
5712 enable_MAC(local, &rsp, 1);
5713
5714 return 0;
5715}
5716
5717/*------------------------------------------------------------------*/
5718/*
5719 * Wireless Handler : get ESSID
5720 */
5721static int airo_get_essid(struct net_device *dev,
5722 struct iw_request_info *info,
5723 struct iw_point *dwrq,
5724 char *extra)
5725{
5726 struct airo_info *local = dev->priv;
5727 StatusRid status_rid; /* Card status info */
5728
5729 readStatusRid(local, &status_rid, 1);
5730
5731 /* Note : if dwrq->flags != 0, we should
5732 * get the relevant SSID from the SSID list... */
5733
5734 /* Get the current SSID */
5735 memcpy(extra, status_rid.SSID, status_rid.SSIDlen);
5736 extra[status_rid.SSIDlen] = '\0';
5737 /* If none, we may want to get the one that was set */
5738
5739 /* Push it out ! */
Dan Williamsd6a13a22006-01-12 15:00:58 -05005740 dwrq->length = status_rid.SSIDlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005741 dwrq->flags = 1; /* active */
5742
5743 return 0;
5744}
5745
5746/*------------------------------------------------------------------*/
5747/*
5748 * Wireless Handler : set AP address
5749 */
5750static int airo_set_wap(struct net_device *dev,
5751 struct iw_request_info *info,
5752 struct sockaddr *awrq,
5753 char *extra)
5754{
5755 struct airo_info *local = dev->priv;
5756 Cmd cmd;
5757 Resp rsp;
5758 APListRid APList_rid;
5759 static const unsigned char bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 };
5760
5761 if (awrq->sa_family != ARPHRD_ETHER)
5762 return -EINVAL;
5763 else if (!memcmp(bcast, awrq->sa_data, ETH_ALEN)) {
5764 memset(&cmd, 0, sizeof(cmd));
5765 cmd.cmd=CMD_LOSE_SYNC;
5766 if (down_interruptible(&local->sem))
5767 return -ERESTARTSYS;
5768 issuecommand(local, &cmd, &rsp);
5769 up(&local->sem);
5770 } else {
5771 memset(&APList_rid, 0, sizeof(APList_rid));
5772 APList_rid.len = sizeof(APList_rid);
5773 memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN);
5774 disable_MAC(local, 1);
5775 writeAPListRid(local, &APList_rid, 1);
5776 enable_MAC(local, &rsp, 1);
5777 }
5778 return 0;
5779}
5780
5781/*------------------------------------------------------------------*/
5782/*
5783 * Wireless Handler : get AP address
5784 */
5785static int airo_get_wap(struct net_device *dev,
5786 struct iw_request_info *info,
5787 struct sockaddr *awrq,
5788 char *extra)
5789{
5790 struct airo_info *local = dev->priv;
5791 StatusRid status_rid; /* Card status info */
5792
5793 readStatusRid(local, &status_rid, 1);
5794
5795 /* Tentative. This seems to work, wow, I'm lucky !!! */
5796 memcpy(awrq->sa_data, status_rid.bssid[0], ETH_ALEN);
5797 awrq->sa_family = ARPHRD_ETHER;
5798
5799 return 0;
5800}
5801
5802/*------------------------------------------------------------------*/
5803/*
5804 * Wireless Handler : set Nickname
5805 */
5806static int airo_set_nick(struct net_device *dev,
5807 struct iw_request_info *info,
5808 struct iw_point *dwrq,
5809 char *extra)
5810{
5811 struct airo_info *local = dev->priv;
5812
5813 /* Check the size of the string */
5814 if(dwrq->length > 16 + 1) {
5815 return -E2BIG;
5816 }
5817 readConfigRid(local, 1);
5818 memset(local->config.nodeName, 0, sizeof(local->config.nodeName));
5819 memcpy(local->config.nodeName, extra, dwrq->length);
5820 set_bit (FLAG_COMMIT, &local->flags);
5821
5822 return -EINPROGRESS; /* Call commit handler */
5823}
5824
5825/*------------------------------------------------------------------*/
5826/*
5827 * Wireless Handler : get Nickname
5828 */
5829static int airo_get_nick(struct net_device *dev,
5830 struct iw_request_info *info,
5831 struct iw_point *dwrq,
5832 char *extra)
5833{
5834 struct airo_info *local = dev->priv;
5835
5836 readConfigRid(local, 1);
5837 strncpy(extra, local->config.nodeName, 16);
5838 extra[16] = '\0';
5839 dwrq->length = strlen(extra) + 1;
5840
5841 return 0;
5842}
5843
5844/*------------------------------------------------------------------*/
5845/*
5846 * Wireless Handler : set Bit-Rate
5847 */
5848static int airo_set_rate(struct net_device *dev,
5849 struct iw_request_info *info,
5850 struct iw_param *vwrq,
5851 char *extra)
5852{
5853 struct airo_info *local = dev->priv;
5854 CapabilityRid cap_rid; /* Card capability info */
5855 u8 brate = 0;
5856 int i;
5857
5858 /* First : get a valid bit rate value */
5859 readCapabilityRid(local, &cap_rid, 1);
5860
5861 /* Which type of value ? */
5862 if((vwrq->value < 8) && (vwrq->value >= 0)) {
5863 /* Setting by rate index */
5864 /* Find value in the magic rate table */
5865 brate = cap_rid.supportedRates[vwrq->value];
5866 } else {
5867 /* Setting by frequency value */
5868 u8 normvalue = (u8) (vwrq->value/500000);
5869
5870 /* Check if rate is valid */
5871 for(i = 0 ; i < 8 ; i++) {
5872 if(normvalue == cap_rid.supportedRates[i]) {
5873 brate = normvalue;
5874 break;
5875 }
5876 }
5877 }
5878 /* -1 designed the max rate (mostly auto mode) */
5879 if(vwrq->value == -1) {
5880 /* Get the highest available rate */
5881 for(i = 0 ; i < 8 ; i++) {
5882 if(cap_rid.supportedRates[i] == 0)
5883 break;
5884 }
5885 if(i != 0)
5886 brate = cap_rid.supportedRates[i - 1];
5887 }
5888 /* Check that it is valid */
5889 if(brate == 0) {
5890 return -EINVAL;
5891 }
5892
5893 readConfigRid(local, 1);
5894 /* Now, check if we want a fixed or auto value */
5895 if(vwrq->fixed == 0) {
5896 /* Fill all the rates up to this max rate */
5897 memset(local->config.rates, 0, 8);
5898 for(i = 0 ; i < 8 ; i++) {
5899 local->config.rates[i] = cap_rid.supportedRates[i];
5900 if(local->config.rates[i] == brate)
5901 break;
5902 }
5903 } else {
5904 /* Fixed mode */
5905 /* One rate, fixed */
5906 memset(local->config.rates, 0, 8);
5907 local->config.rates[0] = brate;
5908 }
5909 set_bit (FLAG_COMMIT, &local->flags);
5910
5911 return -EINPROGRESS; /* Call commit handler */
5912}
5913
5914/*------------------------------------------------------------------*/
5915/*
5916 * Wireless Handler : get Bit-Rate
5917 */
5918static int airo_get_rate(struct net_device *dev,
5919 struct iw_request_info *info,
5920 struct iw_param *vwrq,
5921 char *extra)
5922{
5923 struct airo_info *local = dev->priv;
5924 StatusRid status_rid; /* Card status info */
5925
5926 readStatusRid(local, &status_rid, 1);
5927
5928 vwrq->value = status_rid.currentXmitRate * 500000;
5929 /* If more than one rate, set auto */
5930 readConfigRid(local, 1);
5931 vwrq->fixed = (local->config.rates[1] == 0);
5932
5933 return 0;
5934}
5935
5936/*------------------------------------------------------------------*/
5937/*
5938 * Wireless Handler : set RTS threshold
5939 */
5940static int airo_set_rts(struct net_device *dev,
5941 struct iw_request_info *info,
5942 struct iw_param *vwrq,
5943 char *extra)
5944{
5945 struct airo_info *local = dev->priv;
5946 int rthr = vwrq->value;
5947
5948 if(vwrq->disabled)
5949 rthr = 2312;
5950 if((rthr < 0) || (rthr > 2312)) {
5951 return -EINVAL;
5952 }
5953 readConfigRid(local, 1);
5954 local->config.rtsThres = rthr;
5955 set_bit (FLAG_COMMIT, &local->flags);
5956
5957 return -EINPROGRESS; /* Call commit handler */
5958}
5959
5960/*------------------------------------------------------------------*/
5961/*
5962 * Wireless Handler : get RTS threshold
5963 */
5964static int airo_get_rts(struct net_device *dev,
5965 struct iw_request_info *info,
5966 struct iw_param *vwrq,
5967 char *extra)
5968{
5969 struct airo_info *local = dev->priv;
5970
5971 readConfigRid(local, 1);
5972 vwrq->value = local->config.rtsThres;
5973 vwrq->disabled = (vwrq->value >= 2312);
5974 vwrq->fixed = 1;
5975
5976 return 0;
5977}
5978
5979/*------------------------------------------------------------------*/
5980/*
5981 * Wireless Handler : set Fragmentation threshold
5982 */
5983static int airo_set_frag(struct net_device *dev,
5984 struct iw_request_info *info,
5985 struct iw_param *vwrq,
5986 char *extra)
5987{
5988 struct airo_info *local = dev->priv;
5989 int fthr = vwrq->value;
5990
5991 if(vwrq->disabled)
5992 fthr = 2312;
5993 if((fthr < 256) || (fthr > 2312)) {
5994 return -EINVAL;
5995 }
5996 fthr &= ~0x1; /* Get an even value - is it really needed ??? */
5997 readConfigRid(local, 1);
5998 local->config.fragThresh = (u16)fthr;
5999 set_bit (FLAG_COMMIT, &local->flags);
6000
6001 return -EINPROGRESS; /* Call commit handler */
6002}
6003
6004/*------------------------------------------------------------------*/
6005/*
6006 * Wireless Handler : get Fragmentation threshold
6007 */
6008static int airo_get_frag(struct net_device *dev,
6009 struct iw_request_info *info,
6010 struct iw_param *vwrq,
6011 char *extra)
6012{
6013 struct airo_info *local = dev->priv;
6014
6015 readConfigRid(local, 1);
6016 vwrq->value = local->config.fragThresh;
6017 vwrq->disabled = (vwrq->value >= 2312);
6018 vwrq->fixed = 1;
6019
6020 return 0;
6021}
6022
6023/*------------------------------------------------------------------*/
6024/*
6025 * Wireless Handler : set Mode of Operation
6026 */
6027static int airo_set_mode(struct net_device *dev,
6028 struct iw_request_info *info,
6029 __u32 *uwrq,
6030 char *extra)
6031{
6032 struct airo_info *local = dev->priv;
6033 int reset = 0;
6034
6035 readConfigRid(local, 1);
6036 if ((local->config.rmode & 0xff) >= RXMODE_RFMON)
6037 reset = 1;
6038
6039 switch(*uwrq) {
6040 case IW_MODE_ADHOC:
6041 local->config.opmode &= 0xFF00;
6042 local->config.opmode |= MODE_STA_IBSS;
6043 local->config.rmode &= 0xfe00;
6044 local->config.scanMode = SCANMODE_ACTIVE;
6045 clear_bit (FLAG_802_11, &local->flags);
6046 break;
6047 case IW_MODE_INFRA:
6048 local->config.opmode &= 0xFF00;
6049 local->config.opmode |= MODE_STA_ESS;
6050 local->config.rmode &= 0xfe00;
6051 local->config.scanMode = SCANMODE_ACTIVE;
6052 clear_bit (FLAG_802_11, &local->flags);
6053 break;
6054 case IW_MODE_MASTER:
6055 local->config.opmode &= 0xFF00;
6056 local->config.opmode |= MODE_AP;
6057 local->config.rmode &= 0xfe00;
6058 local->config.scanMode = SCANMODE_ACTIVE;
6059 clear_bit (FLAG_802_11, &local->flags);
6060 break;
6061 case IW_MODE_REPEAT:
6062 local->config.opmode &= 0xFF00;
6063 local->config.opmode |= MODE_AP_RPTR;
6064 local->config.rmode &= 0xfe00;
6065 local->config.scanMode = SCANMODE_ACTIVE;
6066 clear_bit (FLAG_802_11, &local->flags);
6067 break;
6068 case IW_MODE_MONITOR:
6069 local->config.opmode &= 0xFF00;
6070 local->config.opmode |= MODE_STA_ESS;
6071 local->config.rmode &= 0xfe00;
6072 local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
6073 local->config.scanMode = SCANMODE_PASSIVE;
6074 set_bit (FLAG_802_11, &local->flags);
6075 break;
6076 default:
6077 return -EINVAL;
6078 }
6079 if (reset)
6080 set_bit (FLAG_RESET, &local->flags);
6081 set_bit (FLAG_COMMIT, &local->flags);
6082
6083 return -EINPROGRESS; /* Call commit handler */
6084}
6085
6086/*------------------------------------------------------------------*/
6087/*
6088 * Wireless Handler : get Mode of Operation
6089 */
6090static int airo_get_mode(struct net_device *dev,
6091 struct iw_request_info *info,
6092 __u32 *uwrq,
6093 char *extra)
6094{
6095 struct airo_info *local = dev->priv;
6096
6097 readConfigRid(local, 1);
6098 /* If not managed, assume it's ad-hoc */
6099 switch (local->config.opmode & 0xFF) {
6100 case MODE_STA_ESS:
6101 *uwrq = IW_MODE_INFRA;
6102 break;
6103 case MODE_AP:
6104 *uwrq = IW_MODE_MASTER;
6105 break;
6106 case MODE_AP_RPTR:
6107 *uwrq = IW_MODE_REPEAT;
6108 break;
6109 default:
6110 *uwrq = IW_MODE_ADHOC;
6111 }
6112
6113 return 0;
6114}
6115
6116/*------------------------------------------------------------------*/
6117/*
6118 * Wireless Handler : set Encryption Key
6119 */
6120static int airo_set_encode(struct net_device *dev,
6121 struct iw_request_info *info,
6122 struct iw_point *dwrq,
6123 char *extra)
6124{
6125 struct airo_info *local = dev->priv;
6126 CapabilityRid cap_rid; /* Card capability info */
Dan Streetmanf89b2322005-11-11 11:41:42 -05006127 int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 );
6128 u16 currentAuthType = local->config.authType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006129
6130 /* Is WEP supported ? */
6131 readCapabilityRid(local, &cap_rid, 1);
6132 /* Older firmware doesn't support this...
6133 if(!(cap_rid.softCap & 2)) {
6134 return -EOPNOTSUPP;
6135 } */
6136 readConfigRid(local, 1);
6137
6138 /* Basic checking: do we have a key to set ?
6139 * Note : with the new API, it's impossible to get a NULL pointer.
6140 * Therefore, we need to check a key size == 0 instead.
6141 * New version of iwconfig properly set the IW_ENCODE_NOKEY flag
6142 * when no key is present (only change flags), but older versions
6143 * don't do it. - Jean II */
6144 if (dwrq->length > 0) {
6145 wep_key_t key;
6146 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
6147 int current_index = get_wep_key(local, 0xffff);
6148 /* Check the size of the key */
6149 if (dwrq->length > MAX_KEY_SIZE) {
6150 return -EINVAL;
6151 }
6152 /* Check the index (none -> use current) */
6153 if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4:1)))
6154 index = current_index;
6155 /* Set the length */
6156 if (dwrq->length > MIN_KEY_SIZE)
6157 key.len = MAX_KEY_SIZE;
6158 else
6159 if (dwrq->length > 0)
6160 key.len = MIN_KEY_SIZE;
6161 else
6162 /* Disable the key */
6163 key.len = 0;
6164 /* Check if the key is not marked as invalid */
6165 if(!(dwrq->flags & IW_ENCODE_NOKEY)) {
6166 /* Cleanup */
6167 memset(key.key, 0, MAX_KEY_SIZE);
6168 /* Copy the key in the driver */
6169 memcpy(key.key, extra, dwrq->length);
6170 /* Send the key to the card */
Dan Streetmanf89b2322005-11-11 11:41:42 -05006171 set_wep_key(local, index, key.key, key.len, perm, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006172 }
6173 /* WE specify that if a valid key is set, encryption
6174 * should be enabled (user may turn it off later)
6175 * This is also how "iwconfig ethX key on" works */
6176 if((index == current_index) && (key.len > 0) &&
6177 (local->config.authType == AUTH_OPEN)) {
6178 local->config.authType = AUTH_ENCRYPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006179 }
6180 } else {
6181 /* Do we want to just set the transmit key index ? */
6182 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
6183 if ((index >= 0) && (index < ((cap_rid.softCap & 0x80)?4:1))) {
Dan Streetmanf89b2322005-11-11 11:41:42 -05006184 set_wep_key(local, index, NULL, 0, perm, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185 } else
6186 /* Don't complain if only change the mode */
6187 if(!dwrq->flags & IW_ENCODE_MODE) {
6188 return -EINVAL;
6189 }
6190 }
6191 /* Read the flags */
6192 if(dwrq->flags & IW_ENCODE_DISABLED)
6193 local->config.authType = AUTH_OPEN; // disable encryption
6194 if(dwrq->flags & IW_ENCODE_RESTRICTED)
6195 local->config.authType = AUTH_SHAREDKEY; // Only Both
6196 if(dwrq->flags & IW_ENCODE_OPEN)
6197 local->config.authType = AUTH_ENCRYPT; // Only Wep
6198 /* Commit the changes to flags if needed */
Dan Streetmanf89b2322005-11-11 11:41:42 -05006199 if (local->config.authType != currentAuthType)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200 set_bit (FLAG_COMMIT, &local->flags);
6201 return -EINPROGRESS; /* Call commit handler */
6202}
6203
6204/*------------------------------------------------------------------*/
6205/*
6206 * Wireless Handler : get Encryption Key
6207 */
6208static int airo_get_encode(struct net_device *dev,
6209 struct iw_request_info *info,
6210 struct iw_point *dwrq,
6211 char *extra)
6212{
6213 struct airo_info *local = dev->priv;
6214 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
6215 CapabilityRid cap_rid; /* Card capability info */
6216
6217 /* Is it supported ? */
6218 readCapabilityRid(local, &cap_rid, 1);
6219 if(!(cap_rid.softCap & 2)) {
6220 return -EOPNOTSUPP;
6221 }
6222 readConfigRid(local, 1);
6223 /* Check encryption mode */
6224 switch(local->config.authType) {
6225 case AUTH_ENCRYPT:
6226 dwrq->flags = IW_ENCODE_OPEN;
6227 break;
6228 case AUTH_SHAREDKEY:
6229 dwrq->flags = IW_ENCODE_RESTRICTED;
6230 break;
6231 default:
6232 case AUTH_OPEN:
6233 dwrq->flags = IW_ENCODE_DISABLED;
6234 break;
6235 }
6236 /* We can't return the key, so set the proper flag and return zero */
6237 dwrq->flags |= IW_ENCODE_NOKEY;
6238 memset(extra, 0, 16);
6239
6240 /* Which key do we want ? -1 -> tx index */
6241 if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4 : 1)))
6242 index = get_wep_key(local, 0xffff);
6243 dwrq->flags |= index + 1;
6244 /* Copy the key to the user buffer */
6245 dwrq->length = get_wep_key(local, index);
6246 if (dwrq->length > 16) {
6247 dwrq->length=0;
6248 }
6249 return 0;
6250}
6251
6252/*------------------------------------------------------------------*/
6253/*
6254 * Wireless Handler : set Tx-Power
6255 */
6256static int airo_set_txpow(struct net_device *dev,
6257 struct iw_request_info *info,
6258 struct iw_param *vwrq,
6259 char *extra)
6260{
6261 struct airo_info *local = dev->priv;
6262 CapabilityRid cap_rid; /* Card capability info */
6263 int i;
6264 int rc = -EINVAL;
6265
6266 readCapabilityRid(local, &cap_rid, 1);
6267
6268 if (vwrq->disabled) {
6269 set_bit (FLAG_RADIO_OFF, &local->flags);
6270 set_bit (FLAG_COMMIT, &local->flags);
6271 return -EINPROGRESS; /* Call commit handler */
6272 }
6273 if (vwrq->flags != IW_TXPOW_MWATT) {
6274 return -EINVAL;
6275 }
6276 clear_bit (FLAG_RADIO_OFF, &local->flags);
6277 for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
6278 if ((vwrq->value==cap_rid.txPowerLevels[i])) {
6279 readConfigRid(local, 1);
6280 local->config.txPower = vwrq->value;
6281 set_bit (FLAG_COMMIT, &local->flags);
6282 rc = -EINPROGRESS; /* Call commit handler */
6283 break;
6284 }
6285 return rc;
6286}
6287
6288/*------------------------------------------------------------------*/
6289/*
6290 * Wireless Handler : get Tx-Power
6291 */
6292static int airo_get_txpow(struct net_device *dev,
6293 struct iw_request_info *info,
6294 struct iw_param *vwrq,
6295 char *extra)
6296{
6297 struct airo_info *local = dev->priv;
6298
6299 readConfigRid(local, 1);
6300 vwrq->value = local->config.txPower;
6301 vwrq->fixed = 1; /* No power control */
6302 vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags);
6303 vwrq->flags = IW_TXPOW_MWATT;
6304
6305 return 0;
6306}
6307
6308/*------------------------------------------------------------------*/
6309/*
6310 * Wireless Handler : set Retry limits
6311 */
6312static int airo_set_retry(struct net_device *dev,
6313 struct iw_request_info *info,
6314 struct iw_param *vwrq,
6315 char *extra)
6316{
6317 struct airo_info *local = dev->priv;
6318 int rc = -EINVAL;
6319
6320 if(vwrq->disabled) {
6321 return -EINVAL;
6322 }
6323 readConfigRid(local, 1);
6324 if(vwrq->flags & IW_RETRY_LIMIT) {
6325 if(vwrq->flags & IW_RETRY_MAX)
6326 local->config.longRetryLimit = vwrq->value;
6327 else if (vwrq->flags & IW_RETRY_MIN)
6328 local->config.shortRetryLimit = vwrq->value;
6329 else {
6330 /* No modifier : set both */
6331 local->config.longRetryLimit = vwrq->value;
6332 local->config.shortRetryLimit = vwrq->value;
6333 }
6334 set_bit (FLAG_COMMIT, &local->flags);
6335 rc = -EINPROGRESS; /* Call commit handler */
6336 }
6337 if(vwrq->flags & IW_RETRY_LIFETIME) {
6338 local->config.txLifetime = vwrq->value / 1024;
6339 set_bit (FLAG_COMMIT, &local->flags);
6340 rc = -EINPROGRESS; /* Call commit handler */
6341 }
6342 return rc;
6343}
6344
6345/*------------------------------------------------------------------*/
6346/*
6347 * Wireless Handler : get Retry limits
6348 */
6349static int airo_get_retry(struct net_device *dev,
6350 struct iw_request_info *info,
6351 struct iw_param *vwrq,
6352 char *extra)
6353{
6354 struct airo_info *local = dev->priv;
6355
6356 vwrq->disabled = 0; /* Can't be disabled */
6357
6358 readConfigRid(local, 1);
6359 /* Note : by default, display the min retry number */
6360 if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
6361 vwrq->flags = IW_RETRY_LIFETIME;
6362 vwrq->value = (int)local->config.txLifetime * 1024;
6363 } else if((vwrq->flags & IW_RETRY_MAX)) {
6364 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
6365 vwrq->value = (int)local->config.longRetryLimit;
6366 } else {
6367 vwrq->flags = IW_RETRY_LIMIT;
6368 vwrq->value = (int)local->config.shortRetryLimit;
6369 if((int)local->config.shortRetryLimit != (int)local->config.longRetryLimit)
6370 vwrq->flags |= IW_RETRY_MIN;
6371 }
6372
6373 return 0;
6374}
6375
6376/*------------------------------------------------------------------*/
6377/*
6378 * Wireless Handler : get range info
6379 */
6380static int airo_get_range(struct net_device *dev,
6381 struct iw_request_info *info,
6382 struct iw_point *dwrq,
6383 char *extra)
6384{
6385 struct airo_info *local = dev->priv;
6386 struct iw_range *range = (struct iw_range *) extra;
6387 CapabilityRid cap_rid; /* Card capability info */
6388 int i;
6389 int k;
6390
6391 readCapabilityRid(local, &cap_rid, 1);
6392
6393 dwrq->length = sizeof(struct iw_range);
6394 memset(range, 0, sizeof(*range));
6395 range->min_nwid = 0x0000;
6396 range->max_nwid = 0x0000;
6397 range->num_channels = 14;
6398 /* Should be based on cap_rid.country to give only
6399 * what the current card support */
6400 k = 0;
6401 for(i = 0; i < 14; i++) {
6402 range->freq[k].i = i + 1; /* List index */
6403 range->freq[k].m = frequency_list[i] * 100000;
6404 range->freq[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */
6405 }
6406 range->num_frequency = k;
6407
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408 range->sensitivity = 65535;
6409
Dan Williams41480af2005-05-10 09:45:51 -04006410 /* Hum... Should put the right values there */
6411 if (local->rssi)
6412 range->max_qual.qual = 100; /* % */
6413 else
6414 range->max_qual.qual = airo_get_max_quality(&cap_rid);
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006415 range->max_qual.level = 0x100 - 120; /* -120 dBm */
6416 range->max_qual.noise = 0x100 - 120; /* -120 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006417
6418 /* Experimental measurements - boundary 11/5.5 Mb/s */
6419 /* Note : with or without the (local->rssi), results
6420 * are somewhat different. - Jean II */
6421 if (local->rssi) {
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006422 range->avg_qual.qual = 50; /* % */
6423 range->avg_qual.level = 0x100 - 70; /* -70 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006424 } else {
6425 range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006426 range->avg_qual.level = 0x100 - 80; /* -80 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006427 }
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006428 range->avg_qual.noise = 0x100 - 85; /* -85 dBm */
Dan Williams41480af2005-05-10 09:45:51 -04006429
Linus Torvalds1da177e2005-04-16 15:20:36 -07006430 for(i = 0 ; i < 8 ; i++) {
6431 range->bitrate[i] = cap_rid.supportedRates[i] * 500000;
6432 if(range->bitrate[i] == 0)
6433 break;
6434 }
6435 range->num_bitrates = i;
6436
6437 /* Set an indication of the max TCP throughput
6438 * in bit/s that we can expect using this interface.
6439 * May be use for QoS stuff... Jean II */
6440 if(i > 2)
6441 range->throughput = 5000 * 1000;
6442 else
6443 range->throughput = 1500 * 1000;
6444
6445 range->min_rts = 0;
6446 range->max_rts = 2312;
6447 range->min_frag = 256;
6448 range->max_frag = 2312;
6449
6450 if(cap_rid.softCap & 2) {
6451 // WEP: RC4 40 bits
6452 range->encoding_size[0] = 5;
6453 // RC4 ~128 bits
6454 if (cap_rid.softCap & 0x100) {
6455 range->encoding_size[1] = 13;
6456 range->num_encoding_sizes = 2;
6457 } else
6458 range->num_encoding_sizes = 1;
6459 range->max_encoding_tokens = (cap_rid.softCap & 0x80) ? 4 : 1;
6460 } else {
6461 range->num_encoding_sizes = 0;
6462 range->max_encoding_tokens = 0;
6463 }
6464 range->min_pmp = 0;
6465 range->max_pmp = 5000000; /* 5 secs */
6466 range->min_pmt = 0;
6467 range->max_pmt = 65535 * 1024; /* ??? */
6468 range->pmp_flags = IW_POWER_PERIOD;
6469 range->pmt_flags = IW_POWER_TIMEOUT;
6470 range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
6471
6472 /* Transmit Power - values are in mW */
6473 for(i = 0 ; i < 8 ; i++) {
6474 range->txpower[i] = cap_rid.txPowerLevels[i];
6475 if(range->txpower[i] == 0)
6476 break;
6477 }
6478 range->num_txpower = i;
6479 range->txpower_capa = IW_TXPOW_MWATT;
6480 range->we_version_source = 12;
6481 range->we_version_compiled = WIRELESS_EXT;
6482 range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
6483 range->retry_flags = IW_RETRY_LIMIT;
6484 range->r_time_flags = IW_RETRY_LIFETIME;
6485 range->min_retry = 1;
6486 range->max_retry = 65535;
6487 range->min_r_time = 1024;
6488 range->max_r_time = 65535 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006489
6490 /* Event capability (kernel + driver) */
6491 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
6492 IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
6493 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
6494 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
6495 range->event_capa[1] = IW_EVENT_CAPA_K_1;
6496 range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVTXDROP);
6497 return 0;
6498}
6499
6500/*------------------------------------------------------------------*/
6501/*
6502 * Wireless Handler : set Power Management
6503 */
6504static int airo_set_power(struct net_device *dev,
6505 struct iw_request_info *info,
6506 struct iw_param *vwrq,
6507 char *extra)
6508{
6509 struct airo_info *local = dev->priv;
6510
6511 readConfigRid(local, 1);
6512 if (vwrq->disabled) {
6513 if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
6514 return -EINVAL;
6515 }
6516 local->config.powerSaveMode = POWERSAVE_CAM;
6517 local->config.rmode &= 0xFF00;
6518 local->config.rmode |= RXMODE_BC_MC_ADDR;
6519 set_bit (FLAG_COMMIT, &local->flags);
6520 return -EINPROGRESS; /* Call commit handler */
6521 }
6522 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
6523 local->config.fastListenDelay = (vwrq->value + 500) / 1024;
6524 local->config.powerSaveMode = POWERSAVE_PSPCAM;
6525 set_bit (FLAG_COMMIT, &local->flags);
6526 } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
6527 local->config.fastListenInterval = local->config.listenInterval = (vwrq->value + 500) / 1024;
6528 local->config.powerSaveMode = POWERSAVE_PSPCAM;
6529 set_bit (FLAG_COMMIT, &local->flags);
6530 }
6531 switch (vwrq->flags & IW_POWER_MODE) {
6532 case IW_POWER_UNICAST_R:
6533 if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
6534 return -EINVAL;
6535 }
6536 local->config.rmode &= 0xFF00;
6537 local->config.rmode |= RXMODE_ADDR;
6538 set_bit (FLAG_COMMIT, &local->flags);
6539 break;
6540 case IW_POWER_ALL_R:
6541 if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
6542 return -EINVAL;
6543 }
6544 local->config.rmode &= 0xFF00;
6545 local->config.rmode |= RXMODE_BC_MC_ADDR;
6546 set_bit (FLAG_COMMIT, &local->flags);
6547 case IW_POWER_ON:
6548 break;
6549 default:
6550 return -EINVAL;
6551 }
6552 // Note : we may want to factor local->need_commit here
6553 // Note2 : may also want to factor RXMODE_RFMON test
6554 return -EINPROGRESS; /* Call commit handler */
6555}
6556
6557/*------------------------------------------------------------------*/
6558/*
6559 * Wireless Handler : get Power Management
6560 */
6561static int airo_get_power(struct net_device *dev,
6562 struct iw_request_info *info,
6563 struct iw_param *vwrq,
6564 char *extra)
6565{
6566 struct airo_info *local = dev->priv;
6567 int mode;
6568
6569 readConfigRid(local, 1);
6570 mode = local->config.powerSaveMode;
6571 if ((vwrq->disabled = (mode == POWERSAVE_CAM)))
6572 return 0;
6573 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
6574 vwrq->value = (int)local->config.fastListenDelay * 1024;
6575 vwrq->flags = IW_POWER_TIMEOUT;
6576 } else {
6577 vwrq->value = (int)local->config.fastListenInterval * 1024;
6578 vwrq->flags = IW_POWER_PERIOD;
6579 }
6580 if ((local->config.rmode & 0xFF) == RXMODE_ADDR)
6581 vwrq->flags |= IW_POWER_UNICAST_R;
6582 else
6583 vwrq->flags |= IW_POWER_ALL_R;
6584
6585 return 0;
6586}
6587
6588/*------------------------------------------------------------------*/
6589/*
6590 * Wireless Handler : set Sensitivity
6591 */
6592static int airo_set_sens(struct net_device *dev,
6593 struct iw_request_info *info,
6594 struct iw_param *vwrq,
6595 char *extra)
6596{
6597 struct airo_info *local = dev->priv;
6598
6599 readConfigRid(local, 1);
6600 local->config.rssiThreshold = vwrq->disabled ? RSSI_DEFAULT : vwrq->value;
6601 set_bit (FLAG_COMMIT, &local->flags);
6602
6603 return -EINPROGRESS; /* Call commit handler */
6604}
6605
6606/*------------------------------------------------------------------*/
6607/*
6608 * Wireless Handler : get Sensitivity
6609 */
6610static int airo_get_sens(struct net_device *dev,
6611 struct iw_request_info *info,
6612 struct iw_param *vwrq,
6613 char *extra)
6614{
6615 struct airo_info *local = dev->priv;
6616
6617 readConfigRid(local, 1);
6618 vwrq->value = local->config.rssiThreshold;
6619 vwrq->disabled = (vwrq->value == 0);
6620 vwrq->fixed = 1;
6621
6622 return 0;
6623}
6624
6625/*------------------------------------------------------------------*/
6626/*
6627 * Wireless Handler : get AP List
6628 * Note : this is deprecated in favor of IWSCAN
6629 */
6630static int airo_get_aplist(struct net_device *dev,
6631 struct iw_request_info *info,
6632 struct iw_point *dwrq,
6633 char *extra)
6634{
6635 struct airo_info *local = dev->priv;
6636 struct sockaddr *address = (struct sockaddr *) extra;
6637 struct iw_quality qual[IW_MAX_AP];
6638 BSSListRid BSSList;
6639 int i;
6640 int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
6641
6642 for (i = 0; i < IW_MAX_AP; i++) {
6643 if (readBSSListRid(local, loseSync, &BSSList))
6644 break;
6645 loseSync = 0;
6646 memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN);
6647 address[i].sa_family = ARPHRD_ETHER;
Dan Williams41480af2005-05-10 09:45:51 -04006648 if (local->rssi) {
6649 qual[i].level = 0x100 - BSSList.dBm;
6650 qual[i].qual = airo_dbm_to_pct( local->rssi, BSSList.dBm );
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006651 qual[i].updated = IW_QUAL_QUAL_UPDATED
6652 | IW_QUAL_LEVEL_UPDATED
6653 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04006654 } else {
6655 qual[i].level = (BSSList.dBm + 321) / 2;
6656 qual[i].qual = 0;
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006657 qual[i].updated = IW_QUAL_QUAL_INVALID
6658 | IW_QUAL_LEVEL_UPDATED
6659 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04006660 }
6661 qual[i].noise = local->wstats.qual.noise;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006662 if (BSSList.index == 0xffff)
6663 break;
6664 }
6665 if (!i) {
6666 StatusRid status_rid; /* Card status info */
6667 readStatusRid(local, &status_rid, 1);
6668 for (i = 0;
6669 i < min(IW_MAX_AP, 4) &&
6670 (status_rid.bssid[i][0]
6671 & status_rid.bssid[i][1]
6672 & status_rid.bssid[i][2]
6673 & status_rid.bssid[i][3]
6674 & status_rid.bssid[i][4]
6675 & status_rid.bssid[i][5])!=0xff &&
6676 (status_rid.bssid[i][0]
6677 | status_rid.bssid[i][1]
6678 | status_rid.bssid[i][2]
6679 | status_rid.bssid[i][3]
6680 | status_rid.bssid[i][4]
6681 | status_rid.bssid[i][5]);
6682 i++) {
6683 memcpy(address[i].sa_data,
6684 status_rid.bssid[i], ETH_ALEN);
6685 address[i].sa_family = ARPHRD_ETHER;
6686 }
6687 } else {
6688 dwrq->flags = 1; /* Should be define'd */
6689 memcpy(extra + sizeof(struct sockaddr)*i,
6690 &qual, sizeof(struct iw_quality)*i);
6691 }
6692 dwrq->length = i;
6693
6694 return 0;
6695}
6696
6697/*------------------------------------------------------------------*/
6698/*
6699 * Wireless Handler : Initiate Scan
6700 */
6701static int airo_set_scan(struct net_device *dev,
6702 struct iw_request_info *info,
6703 struct iw_param *vwrq,
6704 char *extra)
6705{
6706 struct airo_info *ai = dev->priv;
6707 Cmd cmd;
6708 Resp rsp;
6709
6710 /* Note : you may have realised that, as this is a SET operation,
6711 * this is privileged and therefore a normal user can't
6712 * perform scanning.
6713 * This is not an error, while the device perform scanning,
6714 * traffic doesn't flow, so it's a perfect DoS...
6715 * Jean II */
6716 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
6717
6718 /* Initiate a scan command */
6719 memset(&cmd, 0, sizeof(cmd));
6720 cmd.cmd=CMD_LISTBSS;
6721 if (down_interruptible(&ai->sem))
6722 return -ERESTARTSYS;
6723 issuecommand(ai, &cmd, &rsp);
6724 ai->scan_timestamp = jiffies;
6725 up(&ai->sem);
6726
6727 /* At this point, just return to the user. */
6728
6729 return 0;
6730}
6731
6732/*------------------------------------------------------------------*/
6733/*
6734 * Translate scan data returned from the card to a card independent
6735 * format that the Wireless Tools will understand - Jean II
6736 */
6737static inline char *airo_translate_scan(struct net_device *dev,
6738 char *current_ev,
6739 char *end_buf,
Dan Williams41480af2005-05-10 09:45:51 -04006740 BSSListRid *bss)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006741{
6742 struct airo_info *ai = dev->priv;
6743 struct iw_event iwe; /* Temporary buffer */
6744 u16 capabilities;
6745 char * current_val; /* For rates */
6746 int i;
6747
6748 /* First entry *MUST* be the AP MAC address */
6749 iwe.cmd = SIOCGIWAP;
6750 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
Dan Williams41480af2005-05-10 09:45:51 -04006751 memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006752 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
6753
6754 /* Other entries will be displayed in the order we give them */
6755
6756 /* Add the ESSID */
Dan Williams41480af2005-05-10 09:45:51 -04006757 iwe.u.data.length = bss->ssidLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006758 if(iwe.u.data.length > 32)
6759 iwe.u.data.length = 32;
6760 iwe.cmd = SIOCGIWESSID;
6761 iwe.u.data.flags = 1;
Dan Williams41480af2005-05-10 09:45:51 -04006762 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006763
6764 /* Add mode */
6765 iwe.cmd = SIOCGIWMODE;
Dan Williams41480af2005-05-10 09:45:51 -04006766 capabilities = le16_to_cpu(bss->cap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006767 if(capabilities & (CAP_ESS | CAP_IBSS)) {
6768 if(capabilities & CAP_ESS)
6769 iwe.u.mode = IW_MODE_MASTER;
6770 else
6771 iwe.u.mode = IW_MODE_ADHOC;
6772 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
6773 }
6774
6775 /* Add frequency */
6776 iwe.cmd = SIOCGIWFREQ;
Dan Williams41480af2005-05-10 09:45:51 -04006777 iwe.u.freq.m = le16_to_cpu(bss->dsChannel);
matthieu castet11414552005-09-12 23:31:39 +02006778 /* iwe.u.freq.m containt the channel (starting 1), our
6779 * frequency_list array start at index 0...
6780 */
6781 iwe.u.freq.m = frequency_list[iwe.u.freq.m - 1] * 100000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006782 iwe.u.freq.e = 1;
6783 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
6784
6785 /* Add quality statistics */
6786 iwe.cmd = IWEVQUAL;
Dan Williams41480af2005-05-10 09:45:51 -04006787 if (ai->rssi) {
6788 iwe.u.qual.level = 0x100 - bss->dBm;
6789 iwe.u.qual.qual = airo_dbm_to_pct( ai->rssi, bss->dBm );
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006790 iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
6791 | IW_QUAL_LEVEL_UPDATED
6792 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04006793 } else {
6794 iwe.u.qual.level = (bss->dBm + 321) / 2;
6795 iwe.u.qual.qual = 0;
Jeff Garzikbbeec902005-09-07 00:27:54 -04006796 iwe.u.qual.updated = IW_QUAL_QUAL_INVALID
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07006797 | IW_QUAL_LEVEL_UPDATED
6798 | IW_QUAL_DBM;
Dan Williams41480af2005-05-10 09:45:51 -04006799 }
6800 iwe.u.qual.noise = ai->wstats.qual.noise;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006801 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
6802
6803 /* Add encryption capability */
6804 iwe.cmd = SIOCGIWENCODE;
6805 if(capabilities & CAP_PRIVACY)
6806 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
6807 else
6808 iwe.u.data.flags = IW_ENCODE_DISABLED;
6809 iwe.u.data.length = 0;
Dan Williams41480af2005-05-10 09:45:51 -04006810 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006811
6812 /* Rate : stuffing multiple values in a single event require a bit
6813 * more of magic - Jean II */
6814 current_val = current_ev + IW_EV_LCP_LEN;
6815
6816 iwe.cmd = SIOCGIWRATE;
6817 /* Those two flags are ignored... */
6818 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
6819 /* Max 8 values */
6820 for(i = 0 ; i < 8 ; i++) {
6821 /* NULL terminated */
Dan Williams41480af2005-05-10 09:45:51 -04006822 if(bss->rates[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006823 break;
6824 /* Bit rate given in 500 kb/s units (+ 0x80) */
Dan Williams41480af2005-05-10 09:45:51 -04006825 iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006826 /* Add new value to event */
6827 current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
6828 }
6829 /* Check if we added any event */
6830 if((current_val - current_ev) > IW_EV_LCP_LEN)
6831 current_ev = current_val;
6832
6833 /* The other data in the scan result are not really
6834 * interesting, so for now drop it - Jean II */
6835 return current_ev;
6836}
6837
6838/*------------------------------------------------------------------*/
6839/*
6840 * Wireless Handler : Read Scan Results
6841 */
6842static int airo_get_scan(struct net_device *dev,
6843 struct iw_request_info *info,
6844 struct iw_point *dwrq,
6845 char *extra)
6846{
6847 struct airo_info *ai = dev->priv;
6848 BSSListRid BSSList;
6849 int rc;
6850 char *current_ev = extra;
6851
6852 /* When we are associated again, the scan has surely finished.
6853 * Just in case, let's make sure enough time has elapsed since
6854 * we started the scan. - Javier */
6855 if(ai->scan_timestamp && time_before(jiffies,ai->scan_timestamp+3*HZ)) {
6856 /* Important note : we don't want to block the caller
6857 * until results are ready for various reasons.
6858 * First, managing wait queues is complex and racy
6859 * (there may be multiple simultaneous callers).
6860 * Second, we grab some rtnetlink lock before comming
6861 * here (in dev_ioctl()).
6862 * Third, the caller can wait on the Wireless Event
6863 * - Jean II */
6864 return -EAGAIN;
6865 }
6866 ai->scan_timestamp = 0;
6867
6868 /* There's only a race with proc_BSSList_open(), but its
6869 * consequences are begnign. So I don't bother fixing it - Javier */
6870
6871 /* Try to read the first entry of the scan result */
6872 rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 1);
6873 if((rc) || (BSSList.index == 0xffff)) {
6874 /* Client error, no scan results...
6875 * The caller need to restart the scan. */
6876 return -ENODATA;
6877 }
6878
6879 /* Read and parse all entries */
6880 while((!rc) && (BSSList.index != 0xffff)) {
6881 /* Translate to WE format this entry */
6882 current_ev = airo_translate_scan(dev, current_ev,
6883 extra + dwrq->length,
6884 &BSSList);
6885
6886 /* Check if there is space for one more entry */
6887 if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
6888 /* Ask user space to try again with a bigger buffer */
6889 return -E2BIG;
6890 }
6891
6892 /* Read next entry */
6893 rc = PC4500_readrid(ai, RID_BSSLISTNEXT,
6894 &BSSList, sizeof(BSSList), 1);
6895 }
6896 /* Length of data */
6897 dwrq->length = (current_ev - extra);
6898 dwrq->flags = 0; /* todo */
6899
6900 return 0;
6901}
6902
6903/*------------------------------------------------------------------*/
6904/*
6905 * Commit handler : called after a bunch of SET operations
6906 */
6907static int airo_config_commit(struct net_device *dev,
6908 struct iw_request_info *info, /* NULL */
6909 void *zwrq, /* NULL */
6910 char *extra) /* NULL */
6911{
6912 struct airo_info *local = dev->priv;
6913 Resp rsp;
6914
6915 if (!test_bit (FLAG_COMMIT, &local->flags))
6916 return 0;
6917
6918 /* Some of the "SET" function may have modified some of the
6919 * parameters. It's now time to commit them in the card */
6920 disable_MAC(local, 1);
6921 if (test_bit (FLAG_RESET, &local->flags)) {
6922 APListRid APList_rid;
6923 SsidRid SSID_rid;
6924
6925 readAPListRid(local, &APList_rid);
6926 readSsidRid(local, &SSID_rid);
6927 if (test_bit(FLAG_MPI,&local->flags))
6928 setup_card(local, dev->dev_addr, 1 );
6929 else
6930 reset_airo_card(dev);
6931 disable_MAC(local, 1);
6932 writeSsidRid(local, &SSID_rid, 1);
6933 writeAPListRid(local, &APList_rid, 1);
6934 }
6935 if (down_interruptible(&local->sem))
6936 return -ERESTARTSYS;
6937 writeConfigRid(local, 0);
6938 enable_MAC(local, &rsp, 0);
6939 if (test_bit (FLAG_RESET, &local->flags))
6940 airo_set_promisc(local);
6941 else
6942 up(&local->sem);
6943
6944 return 0;
6945}
6946
6947/*------------------------------------------------------------------*/
6948/*
6949 * Structures to export the Wireless Handlers
6950 */
6951
6952static const struct iw_priv_args airo_private_args[] = {
6953/*{ cmd, set_args, get_args, name } */
6954 { AIROIOCTL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
6955 IW_PRIV_TYPE_BYTE | 2047, "airoioctl" },
6956 { AIROIDIFC, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
6957 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" },
6958};
6959
6960static const iw_handler airo_handler[] =
6961{
6962 (iw_handler) airo_config_commit, /* SIOCSIWCOMMIT */
6963 (iw_handler) airo_get_name, /* SIOCGIWNAME */
6964 (iw_handler) NULL, /* SIOCSIWNWID */
6965 (iw_handler) NULL, /* SIOCGIWNWID */
6966 (iw_handler) airo_set_freq, /* SIOCSIWFREQ */
6967 (iw_handler) airo_get_freq, /* SIOCGIWFREQ */
6968 (iw_handler) airo_set_mode, /* SIOCSIWMODE */
6969 (iw_handler) airo_get_mode, /* SIOCGIWMODE */
6970 (iw_handler) airo_set_sens, /* SIOCSIWSENS */
6971 (iw_handler) airo_get_sens, /* SIOCGIWSENS */
6972 (iw_handler) NULL, /* SIOCSIWRANGE */
6973 (iw_handler) airo_get_range, /* SIOCGIWRANGE */
6974 (iw_handler) NULL, /* SIOCSIWPRIV */
6975 (iw_handler) NULL, /* SIOCGIWPRIV */
6976 (iw_handler) NULL, /* SIOCSIWSTATS */
6977 (iw_handler) NULL, /* SIOCGIWSTATS */
6978 iw_handler_set_spy, /* SIOCSIWSPY */
6979 iw_handler_get_spy, /* SIOCGIWSPY */
6980 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
6981 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
6982 (iw_handler) airo_set_wap, /* SIOCSIWAP */
6983 (iw_handler) airo_get_wap, /* SIOCGIWAP */
6984 (iw_handler) NULL, /* -- hole -- */
6985 (iw_handler) airo_get_aplist, /* SIOCGIWAPLIST */
6986 (iw_handler) airo_set_scan, /* SIOCSIWSCAN */
6987 (iw_handler) airo_get_scan, /* SIOCGIWSCAN */
6988 (iw_handler) airo_set_essid, /* SIOCSIWESSID */
6989 (iw_handler) airo_get_essid, /* SIOCGIWESSID */
6990 (iw_handler) airo_set_nick, /* SIOCSIWNICKN */
6991 (iw_handler) airo_get_nick, /* SIOCGIWNICKN */
6992 (iw_handler) NULL, /* -- hole -- */
6993 (iw_handler) NULL, /* -- hole -- */
6994 (iw_handler) airo_set_rate, /* SIOCSIWRATE */
6995 (iw_handler) airo_get_rate, /* SIOCGIWRATE */
6996 (iw_handler) airo_set_rts, /* SIOCSIWRTS */
6997 (iw_handler) airo_get_rts, /* SIOCGIWRTS */
6998 (iw_handler) airo_set_frag, /* SIOCSIWFRAG */
6999 (iw_handler) airo_get_frag, /* SIOCGIWFRAG */
7000 (iw_handler) airo_set_txpow, /* SIOCSIWTXPOW */
7001 (iw_handler) airo_get_txpow, /* SIOCGIWTXPOW */
7002 (iw_handler) airo_set_retry, /* SIOCSIWRETRY */
7003 (iw_handler) airo_get_retry, /* SIOCGIWRETRY */
7004 (iw_handler) airo_set_encode, /* SIOCSIWENCODE */
7005 (iw_handler) airo_get_encode, /* SIOCGIWENCODE */
7006 (iw_handler) airo_set_power, /* SIOCSIWPOWER */
7007 (iw_handler) airo_get_power, /* SIOCGIWPOWER */
7008};
7009
7010/* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here.
7011 * We want to force the use of the ioctl code, because those can't be
7012 * won't work the iw_handler code (because they simultaneously read
7013 * and write data and iw_handler can't do that).
7014 * Note that it's perfectly legal to read/write on a single ioctl command,
7015 * you just can't use iwpriv and need to force it via the ioctl handler.
7016 * Jean II */
7017static const iw_handler airo_private_handler[] =
7018{
7019 NULL, /* SIOCIWFIRSTPRIV */
7020};
7021
7022static const struct iw_handler_def airo_handler_def =
7023{
7024 .num_standard = sizeof(airo_handler)/sizeof(iw_handler),
7025 .num_private = sizeof(airo_private_handler)/sizeof(iw_handler),
7026 .num_private_args = sizeof(airo_private_args)/sizeof(struct iw_priv_args),
7027 .standard = airo_handler,
7028 .private = airo_private_handler,
7029 .private_args = airo_private_args,
7030 .get_wireless_stats = airo_get_wireless_stats,
7031};
7032
Linus Torvalds1da177e2005-04-16 15:20:36 -07007033/*
7034 * This defines the configuration part of the Wireless Extensions
7035 * Note : irq and spinlock protection will occur in the subroutines
7036 *
7037 * TODO :
7038 * o Check input value more carefully and fill correct values in range
7039 * o Test and shakeout the bugs (if any)
7040 *
7041 * Jean II
7042 *
7043 * Javier Achirica did a great job of merging code from the unnamed CISCO
7044 * developer that added support for flashing the card.
7045 */
7046static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
7047{
7048 int rc = 0;
7049 struct airo_info *ai = (struct airo_info *)dev->priv;
7050
Pavel Machekca078ba2005-09-03 15:56:57 -07007051 if (ai->power.event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007052 return 0;
7053
7054 switch (cmd) {
7055#ifdef CISCO_EXT
7056 case AIROIDIFC:
7057#ifdef AIROOLDIDIFC
7058 case AIROOLDIDIFC:
7059#endif
7060 {
7061 int val = AIROMAGIC;
7062 aironet_ioctl com;
7063 if (copy_from_user(&com,rq->ifr_data,sizeof(com)))
7064 rc = -EFAULT;
7065 else if (copy_to_user(com.data,(char *)&val,sizeof(val)))
7066 rc = -EFAULT;
7067 }
7068 break;
7069
7070 case AIROIOCTL:
7071#ifdef AIROOLDIOCTL
7072 case AIROOLDIOCTL:
7073#endif
7074 /* Get the command struct and hand it off for evaluation by
7075 * the proper subfunction
7076 */
7077 {
7078 aironet_ioctl com;
7079 if (copy_from_user(&com,rq->ifr_data,sizeof(com))) {
7080 rc = -EFAULT;
7081 break;
7082 }
7083
7084 /* Separate R/W functions bracket legality here
7085 */
7086 if ( com.command == AIRORSWVERSION ) {
7087 if (copy_to_user(com.data, swversion, sizeof(swversion)))
7088 rc = -EFAULT;
7089 else
7090 rc = 0;
7091 }
7092 else if ( com.command <= AIRORRID)
7093 rc = readrids(dev,&com);
7094 else if ( com.command >= AIROPCAP && com.command <= (AIROPLEAPUSR+2) )
7095 rc = writerids(dev,&com);
7096 else if ( com.command >= AIROFLSHRST && com.command <= AIRORESTART )
7097 rc = flashcard(dev,&com);
7098 else
7099 rc = -EINVAL; /* Bad command in ioctl */
7100 }
7101 break;
7102#endif /* CISCO_EXT */
7103
7104 // All other calls are currently unsupported
7105 default:
7106 rc = -EOPNOTSUPP;
7107 }
7108 return rc;
7109}
7110
Linus Torvalds1da177e2005-04-16 15:20:36 -07007111/*
7112 * Get the Wireless stats out of the driver
7113 * Note : irq and spinlock protection will occur in the subroutines
7114 *
7115 * TODO :
7116 * o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs)
7117 *
7118 * Jean
7119 */
7120static void airo_read_wireless_stats(struct airo_info *local)
7121{
7122 StatusRid status_rid;
7123 StatsRid stats_rid;
7124 CapabilityRid cap_rid;
7125 u32 *vals = stats_rid.vals;
7126
7127 /* Get stats out of the card */
7128 clear_bit(JOB_WSTATS, &local->flags);
Pavel Machekca078ba2005-09-03 15:56:57 -07007129 if (local->power.event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007130 up(&local->sem);
7131 return;
7132 }
7133 readCapabilityRid(local, &cap_rid, 0);
7134 readStatusRid(local, &status_rid, 0);
7135 readStatsRid(local, &stats_rid, RID_STATS, 0);
7136 up(&local->sem);
7137
7138 /* The status */
7139 local->wstats.status = status_rid.mode;
7140
Dan Williams41480af2005-05-10 09:45:51 -04007141 /* Signal quality and co */
7142 if (local->rssi) {
7143 local->wstats.qual.level = airo_rssi_to_dbm( local->rssi, status_rid.sigQuality );
7144 /* normalizedSignalStrength appears to be a percentage */
7145 local->wstats.qual.qual = status_rid.normalizedSignalStrength;
7146 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007147 local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2;
Dan Williams41480af2005-05-10 09:45:51 -04007148 local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
7149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007150 if (status_rid.len >= 124) {
Dan Williams41480af2005-05-10 09:45:51 -04007151 local->wstats.qual.noise = 0x100 - status_rid.noisedBm;
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007152 local->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007153 } else {
7154 local->wstats.qual.noise = 0;
Jean Tourrilhesce6623c2005-09-02 11:45:10 -07007155 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 -07007156 }
7157
7158 /* Packets discarded in the wireless adapter due to wireless
7159 * specific problems */
7160 local->wstats.discard.nwid = vals[56] + vals[57] + vals[58];/* SSID Mismatch */
7161 local->wstats.discard.code = vals[6];/* RxWepErr */
7162 local->wstats.discard.fragment = vals[30];
7163 local->wstats.discard.retries = vals[10];
7164 local->wstats.discard.misc = vals[1] + vals[32];
7165 local->wstats.miss.beacon = vals[34];
7166}
7167
Jouni Malinenff1d2762005-05-12 22:54:16 -04007168static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007169{
7170 struct airo_info *local = dev->priv;
7171
7172 if (!test_bit(JOB_WSTATS, &local->flags)) {
7173 /* Get stats out of the card if available */
7174 if (down_trylock(&local->sem) != 0) {
7175 set_bit(JOB_WSTATS, &local->flags);
7176 wake_up_interruptible(&local->thr_wait);
7177 } else
7178 airo_read_wireless_stats(local);
7179 }
7180
7181 return &local->wstats;
7182}
Linus Torvalds1da177e2005-04-16 15:20:36 -07007183
7184#ifdef CISCO_EXT
7185/*
7186 * This just translates from driver IOCTL codes to the command codes to
7187 * feed to the radio's host interface. Things can be added/deleted
7188 * as needed. This represents the READ side of control I/O to
7189 * the card
7190 */
7191static int readrids(struct net_device *dev, aironet_ioctl *comp) {
7192 unsigned short ridcode;
7193 unsigned char *iobuf;
7194 int len;
7195 struct airo_info *ai = dev->priv;
7196 Resp rsp;
7197
7198 if (test_bit(FLAG_FLASHING, &ai->flags))
7199 return -EIO;
7200
7201 switch(comp->command)
7202 {
7203 case AIROGCAP: ridcode = RID_CAPABILITIES; break;
7204 case AIROGCFG: ridcode = RID_CONFIG;
7205 if (test_bit(FLAG_COMMIT, &ai->flags)) {
7206 disable_MAC (ai, 1);
7207 writeConfigRid (ai, 1);
7208 enable_MAC (ai, &rsp, 1);
7209 }
7210 break;
7211 case AIROGSLIST: ridcode = RID_SSID; break;
7212 case AIROGVLIST: ridcode = RID_APLIST; break;
7213 case AIROGDRVNAM: ridcode = RID_DRVNAME; break;
7214 case AIROGEHTENC: ridcode = RID_ETHERENCAP; break;
7215 case AIROGWEPKTMP: ridcode = RID_WEP_TEMP;
7216 /* Only super-user can read WEP keys */
7217 if (!capable(CAP_NET_ADMIN))
7218 return -EPERM;
7219 break;
7220 case AIROGWEPKNV: ridcode = RID_WEP_PERM;
7221 /* Only super-user can read WEP keys */
7222 if (!capable(CAP_NET_ADMIN))
7223 return -EPERM;
7224 break;
7225 case AIROGSTAT: ridcode = RID_STATUS; break;
7226 case AIROGSTATSD32: ridcode = RID_STATSDELTA; break;
7227 case AIROGSTATSC32: ridcode = RID_STATS; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007228 case AIROGMICSTATS:
7229 if (copy_to_user(comp->data, &ai->micstats,
7230 min((int)comp->len,(int)sizeof(ai->micstats))))
7231 return -EFAULT;
7232 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007233 case AIRORRID: ridcode = comp->ridnum; break;
7234 default:
7235 return -EINVAL;
7236 break;
7237 }
7238
7239 if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
7240 return -ENOMEM;
7241
7242 PC4500_readrid(ai,ridcode,iobuf,RIDSIZE, 1);
7243 /* get the count of bytes in the rid docs say 1st 2 bytes is it.
7244 * then return it to the user
7245 * 9/22/2000 Honor user given length
7246 */
7247 len = comp->len;
7248
7249 if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) {
7250 kfree (iobuf);
7251 return -EFAULT;
7252 }
7253 kfree (iobuf);
7254 return 0;
7255}
7256
7257/*
7258 * Danger Will Robinson write the rids here
7259 */
7260
7261static int writerids(struct net_device *dev, aironet_ioctl *comp) {
7262 struct airo_info *ai = dev->priv;
7263 int ridcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007264 int enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007265 Resp rsp;
7266 static int (* writer)(struct airo_info *, u16 rid, const void *, int, int);
7267 unsigned char *iobuf;
7268
7269 /* Only super-user can write RIDs */
7270 if (!capable(CAP_NET_ADMIN))
7271 return -EPERM;
7272
7273 if (test_bit(FLAG_FLASHING, &ai->flags))
7274 return -EIO;
7275
7276 ridcode = 0;
7277 writer = do_writerid;
7278
7279 switch(comp->command)
7280 {
7281 case AIROPSIDS: ridcode = RID_SSID; break;
7282 case AIROPCAP: ridcode = RID_CAPABILITIES; break;
7283 case AIROPAPLIST: ridcode = RID_APLIST; break;
7284 case AIROPCFG: ai->config.len = 0;
7285 clear_bit(FLAG_COMMIT, &ai->flags);
7286 ridcode = RID_CONFIG; break;
7287 case AIROPWEPKEYNV: ridcode = RID_WEP_PERM; break;
7288 case AIROPLEAPUSR: ridcode = RID_LEAPUSERNAME; break;
7289 case AIROPLEAPPWD: ridcode = RID_LEAPPASSWORD; break;
7290 case AIROPWEPKEY: ridcode = RID_WEP_TEMP; writer = PC4500_writerid;
7291 break;
7292 case AIROPLEAPUSR+1: ridcode = 0xFF2A; break;
7293 case AIROPLEAPUSR+2: ridcode = 0xFF2B; break;
7294
7295 /* this is not really a rid but a command given to the card
7296 * same with MAC off
7297 */
7298 case AIROPMACON:
7299 if (enable_MAC(ai, &rsp, 1) != 0)
7300 return -EIO;
7301 return 0;
7302
7303 /*
7304 * Evidently this code in the airo driver does not get a symbol
7305 * as disable_MAC. it's probably so short the compiler does not gen one.
7306 */
7307 case AIROPMACOFF:
7308 disable_MAC(ai, 1);
7309 return 0;
7310
7311 /* This command merely clears the counts does not actually store any data
7312 * only reads rid. But as it changes the cards state, I put it in the
7313 * writerid routines.
7314 */
7315 case AIROPSTCLR:
7316 if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
7317 return -ENOMEM;
7318
7319 PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDSIZE, 1);
7320
Linus Torvalds1da177e2005-04-16 15:20:36 -07007321 enabled = ai->micstats.enabled;
7322 memset(&ai->micstats,0,sizeof(ai->micstats));
7323 ai->micstats.enabled = enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007324
7325 if (copy_to_user(comp->data, iobuf,
7326 min((int)comp->len, (int)RIDSIZE))) {
7327 kfree (iobuf);
7328 return -EFAULT;
7329 }
7330 kfree (iobuf);
7331 return 0;
7332
7333 default:
7334 return -EOPNOTSUPP; /* Blarg! */
7335 }
7336 if(comp->len > RIDSIZE)
7337 return -EINVAL;
7338
7339 if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
7340 return -ENOMEM;
7341
7342 if (copy_from_user(iobuf,comp->data,comp->len)) {
7343 kfree (iobuf);
7344 return -EFAULT;
7345 }
7346
7347 if (comp->command == AIROPCFG) {
7348 ConfigRid *cfg = (ConfigRid *)iobuf;
7349
7350 if (test_bit(FLAG_MIC_CAPABLE, &ai->flags))
7351 cfg->opmode |= MODE_MIC;
7352
7353 if ((cfg->opmode & 0xFF) == MODE_STA_IBSS)
7354 set_bit (FLAG_ADHOC, &ai->flags);
7355 else
7356 clear_bit (FLAG_ADHOC, &ai->flags);
7357 }
7358
7359 if((*writer)(ai, ridcode, iobuf,comp->len,1)) {
7360 kfree (iobuf);
7361 return -EIO;
7362 }
7363 kfree (iobuf);
7364 return 0;
7365}
7366
7367/*****************************************************************************
7368 * Ancillary flash / mod functions much black magic lurkes here *
7369 *****************************************************************************
7370 */
7371
7372/*
7373 * Flash command switch table
7374 */
7375
Jouni Malinenff1d2762005-05-12 22:54:16 -04007376static int flashcard(struct net_device *dev, aironet_ioctl *comp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007377 int z;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007378
7379 /* Only super-user can modify flash */
7380 if (!capable(CAP_NET_ADMIN))
7381 return -EPERM;
7382
7383 switch(comp->command)
7384 {
7385 case AIROFLSHRST:
7386 return cmdreset((struct airo_info *)dev->priv);
7387
7388 case AIROFLSHSTFL:
7389 if (!((struct airo_info *)dev->priv)->flash &&
7390 (((struct airo_info *)dev->priv)->flash = kmalloc (FLASHSIZE, GFP_KERNEL)) == NULL)
7391 return -ENOMEM;
7392 return setflashmode((struct airo_info *)dev->priv);
7393
7394 case AIROFLSHGCHR: /* Get char from aux */
7395 if(comp->len != sizeof(int))
7396 return -EINVAL;
7397 if (copy_from_user(&z,comp->data,comp->len))
7398 return -EFAULT;
7399 return flashgchar((struct airo_info *)dev->priv,z,8000);
7400
7401 case AIROFLSHPCHR: /* Send char to card. */
7402 if(comp->len != sizeof(int))
7403 return -EINVAL;
7404 if (copy_from_user(&z,comp->data,comp->len))
7405 return -EFAULT;
7406 return flashpchar((struct airo_info *)dev->priv,z,8000);
7407
7408 case AIROFLPUTBUF: /* Send 32k to card */
7409 if (!((struct airo_info *)dev->priv)->flash)
7410 return -ENOMEM;
7411 if(comp->len > FLASHSIZE)
7412 return -EINVAL;
7413 if(copy_from_user(((struct airo_info *)dev->priv)->flash,comp->data,comp->len))
7414 return -EFAULT;
7415
7416 flashputbuf((struct airo_info *)dev->priv);
7417 return 0;
7418
7419 case AIRORESTART:
7420 if(flashrestart((struct airo_info *)dev->priv,dev))
7421 return -EIO;
7422 return 0;
7423 }
7424 return -EINVAL;
7425}
7426
7427#define FLASH_COMMAND 0x7e7e
7428
7429/*
7430 * STEP 1)
7431 * Disable MAC and do soft reset on
7432 * card.
7433 */
7434
Jouni Malinenff1d2762005-05-12 22:54:16 -04007435static int cmdreset(struct airo_info *ai) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007436 disable_MAC(ai, 1);
7437
7438 if(!waitbusy (ai)){
7439 printk(KERN_INFO "Waitbusy hang before RESET\n");
7440 return -EBUSY;
7441 }
7442
7443 OUT4500(ai,COMMAND,CMD_SOFTRESET);
7444
7445 ssleep(1); /* WAS 600 12/7/00 */
7446
7447 if(!waitbusy (ai)){
7448 printk(KERN_INFO "Waitbusy hang AFTER RESET\n");
7449 return -EBUSY;
7450 }
7451 return 0;
7452}
7453
7454/* STEP 2)
7455 * Put the card in legendary flash
7456 * mode
7457 */
7458
Jouni Malinenff1d2762005-05-12 22:54:16 -04007459static int setflashmode (struct airo_info *ai) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007460 set_bit (FLAG_FLASHING, &ai->flags);
7461
7462 OUT4500(ai, SWS0, FLASH_COMMAND);
7463 OUT4500(ai, SWS1, FLASH_COMMAND);
7464 if (probe) {
7465 OUT4500(ai, SWS0, FLASH_COMMAND);
7466 OUT4500(ai, COMMAND,0x10);
7467 } else {
7468 OUT4500(ai, SWS2, FLASH_COMMAND);
7469 OUT4500(ai, SWS3, FLASH_COMMAND);
7470 OUT4500(ai, COMMAND,0);
7471 }
7472 msleep(500); /* 500ms delay */
7473
7474 if(!waitbusy(ai)) {
7475 clear_bit (FLAG_FLASHING, &ai->flags);
7476 printk(KERN_INFO "Waitbusy hang after setflash mode\n");
7477 return -EIO;
7478 }
7479 return 0;
7480}
7481
7482/* Put character to SWS0 wait for dwelltime
7483 * x 50us for echo .
7484 */
7485
Jouni Malinenff1d2762005-05-12 22:54:16 -04007486static int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007487 int echo;
7488 int waittime;
7489
7490 byte |= 0x8000;
7491
7492 if(dwelltime == 0 )
7493 dwelltime = 200;
7494
7495 waittime=dwelltime;
7496
7497 /* Wait for busy bit d15 to go false indicating buffer empty */
7498 while ((IN4500 (ai, SWS0) & 0x8000) && waittime > 0) {
7499 udelay (50);
7500 waittime -= 50;
7501 }
7502
7503 /* timeout for busy clear wait */
7504 if(waittime <= 0 ){
7505 printk(KERN_INFO "flash putchar busywait timeout! \n");
7506 return -EBUSY;
7507 }
7508
7509 /* Port is clear now write byte and wait for it to echo back */
7510 do {
7511 OUT4500(ai,SWS0,byte);
7512 udelay(50);
7513 dwelltime -= 50;
7514 echo = IN4500(ai,SWS1);
7515 } while (dwelltime >= 0 && echo != byte);
7516
7517 OUT4500(ai,SWS1,0);
7518
7519 return (echo == byte) ? 0 : -EIO;
7520}
7521
7522/*
7523 * Get a character from the card matching matchbyte
7524 * Step 3)
7525 */
Jouni Malinenff1d2762005-05-12 22:54:16 -04007526static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
Linus Torvalds1da177e2005-04-16 15:20:36 -07007527 int rchar;
7528 unsigned char rbyte=0;
7529
7530 do {
7531 rchar = IN4500(ai,SWS1);
7532
7533 if(dwelltime && !(0x8000 & rchar)){
7534 dwelltime -= 10;
7535 mdelay(10);
7536 continue;
7537 }
7538 rbyte = 0xff & rchar;
7539
7540 if( (rbyte == matchbyte) && (0x8000 & rchar) ){
7541 OUT4500(ai,SWS1,0);
7542 return 0;
7543 }
7544 if( rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar)
7545 break;
7546 OUT4500(ai,SWS1,0);
7547
7548 }while(dwelltime > 0);
7549 return -EIO;
7550}
7551
7552/*
7553 * Transfer 32k of firmware data from user buffer to our buffer and
7554 * send to the card
7555 */
7556
Jouni Malinenff1d2762005-05-12 22:54:16 -04007557static int flashputbuf(struct airo_info *ai){
Linus Torvalds1da177e2005-04-16 15:20:36 -07007558 int nwords;
7559
7560 /* Write stuff */
7561 if (test_bit(FLAG_MPI,&ai->flags))
7562 memcpy_toio(ai->pciaux + 0x8000, ai->flash, FLASHSIZE);
7563 else {
7564 OUT4500(ai,AUXPAGE,0x100);
7565 OUT4500(ai,AUXOFF,0);
7566
7567 for(nwords=0;nwords != FLASHSIZE / 2;nwords++){
7568 OUT4500(ai,AUXDATA,ai->flash[nwords] & 0xffff);
7569 }
7570 }
7571 OUT4500(ai,SWS0,0x8000);
7572
7573 return 0;
7574}
7575
7576/*
7577 *
7578 */
Jouni Malinenff1d2762005-05-12 22:54:16 -04007579static int flashrestart(struct airo_info *ai,struct net_device *dev){
Linus Torvalds1da177e2005-04-16 15:20:36 -07007580 int i,status;
7581
7582 ssleep(1); /* Added 12/7/00 */
7583 clear_bit (FLAG_FLASHING, &ai->flags);
7584 if (test_bit(FLAG_MPI, &ai->flags)) {
7585 status = mpi_init_descriptors(ai);
7586 if (status != SUCCESS)
7587 return status;
7588 }
7589 status = setup_card(ai, dev->dev_addr, 1);
7590
7591 if (!test_bit(FLAG_MPI,&ai->flags))
7592 for( i = 0; i < MAX_FIDS; i++ ) {
7593 ai->fids[i] = transmit_allocate
7594 ( ai, 2312, i >= MAX_FIDS / 2 );
7595 }
7596
7597 ssleep(1); /* Added 12/7/00 */
7598 return status;
7599}
7600#endif /* CISCO_EXT */
7601
7602/*
7603 This program is free software; you can redistribute it and/or
7604 modify it under the terms of the GNU General Public License
7605 as published by the Free Software Foundation; either version 2
7606 of the License, or (at your option) any later version.
7607
7608 This program is distributed in the hope that it will be useful,
7609 but WITHOUT ANY WARRANTY; without even the implied warranty of
7610 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7611 GNU General Public License for more details.
7612
7613 In addition:
7614
7615 Redistribution and use in source and binary forms, with or without
7616 modification, are permitted provided that the following conditions
7617 are met:
7618
7619 1. Redistributions of source code must retain the above copyright
7620 notice, this list of conditions and the following disclaimer.
7621 2. Redistributions in binary form must reproduce the above copyright
7622 notice, this list of conditions and the following disclaimer in the
7623 documentation and/or other materials provided with the distribution.
7624 3. The name of the author may not be used to endorse or promote
7625 products derived from this software without specific prior written
7626 permission.
7627
7628 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
7629 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7630 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7631 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
7632 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
7633 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
7634 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7635 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
7636 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
7637 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
7638 POSSIBILITY OF SUCH DAMAGE.
7639*/
7640
7641module_init(airo_init_module);
7642module_exit(airo_cleanup_module);