1 /*
2 Lucent Wavelan IEEE 802.11 pcmcia.
3 There is almost no documentation for the card.
4 the driver is done using both the FreeBSD, Linux and
5 original Plan 9 drivers as `documentation'.
6
7 Has been used with the card plugged in during all up time.
8 no cards removals/insertions yet.
9
10 For known BUGS see the comments below. Besides,
11 the driver keeps interrupts disabled for just too
12 long. When it gets robust, locks should be revisited.
13
14 BUGS: check endian, alignment and mem/io issues;
15 multicast;
16 receive watchdog interrupts.
17 TODO: automatic power management;
18 improve locking.
19 */
20 #include "u.h"
21 #include "../port/lib.h"
22 #include "mem.h"
23 #include "dat.h"
24 #include "fns.h"
25 #include "io.h"
26 #include "../port/error.h"
27 #include "../port/netif.h"
28 #include "etherif.h"
29
30 #define print iprint
31 #define DEBUG if(1)iprint
32
33 #define SEEKEYS 1
34
35 typedef struct Ctlr Ctlr;
36 typedef struct Wltv Wltv;
37 typedef struct WFrame WFrame;
38 typedef struct Stats Stats;
39 typedef struct WStats WStats;
40 typedef struct WKey WKey;
41
42 struct WStats
43 {
44 ulong ntxuframes; // unicast frames
45 ulong ntxmframes; // multicast frames
46 ulong ntxfrags; // fragments
47 ulong ntxubytes; // unicast bytes
48 ulong ntxmbytes; // multicast bytes
49 ulong ntxdeferred; // deferred transmits
50 ulong ntxsretries; // single retries
51 ulong ntxmultiretries; // multiple retries
52 ulong ntxretrylimit;
53 ulong ntxdiscards;
54 ulong nrxuframes; // unicast frames
55 ulong nrxmframes; // multicast frames
56 ulong nrxfrags; // fragments
57 ulong nrxubytes; // unicast bytes
58 ulong nrxmbytes; // multicast bytes
59 ulong nrxfcserr;
60 ulong nrxdropnobuf;
61 ulong nrxdropnosa;
62 ulong nrxcantdecrypt;
63 ulong nrxmsgfrag;
64 ulong nrxmsgbadfrag;
65 ulong end;
66 };
67
68 struct WFrame
69 {
70 ushort sts;
71 ushort rsvd0;
72 ushort rsvd1;
73 ushort qinfo;
74 ushort rsvd2;
75 ushort rsvd3;
76 ushort txctl;
77 ushort framectl;
78 ushort id;
79 uchar addr1[Eaddrlen];
80 uchar addr2[Eaddrlen];
81 uchar addr3[Eaddrlen];
82 ushort seqctl;
83 uchar addr4[Eaddrlen];
84 ushort dlen;
85 uchar dstaddr[Eaddrlen];
86 uchar srcaddr[Eaddrlen];
87 ushort len;
88 ushort dat[3];
89 ushort type;
90 };
91
92 // Lucent's Length-Type-Value records to talk to the wavelan.
93 // most operational parameters are read/set using this.
94 enum
95 {
96 WTyp_Stats = 0xf100,
97 WTyp_Ptype = 0xfc00,
98 WTyp_Mac = 0xfc01,
99 WTyp_WantName = 0xfc02,
100 WTyp_Chan = 0xfc03,
101 WTyp_NetName = 0xfc04,
102 WTyp_ApDens = 0xfc06,
103 WTyp_MaxLen = 0xfc07,
104 WTyp_PM = 0xfc09,
105 WTyp_PMWait = 0xfc0c,
106 WTyp_NodeName = 0xfc0e,
107 WTyp_Crypt = 0xfc20,
108 WTyp_XClear = 0xfc22,
109 WTyp_Tick = 0xfce0,
110 WTyp_RtsThres = 0xfc83,
111 WTyp_TxRate = 0xfc84,
112 WTx1Mbps = 0x0,
113 WTx2Mbps = 0x1,
114 WTxAuto = 0x3,
115 WTyp_Prom = 0xfc85,
116 WTyp_Keys = 0xfcb0,
117 WTyp_TxKey = 0xfcb1,
118 WTyp_StationID = 0xfd20,
119 WTyp_CurName = 0xfd41,
120 WTyp_BaseID = 0xfd42, // ID of the currently connected-to base station
121 WTyp_CurTxRate = 0xfd44, // Current TX rate
122 WTyp_HasCrypt = 0xfd4f,
123 };
124
125 // Controller
126 enum
127 {
128 WDfltIRQ = 3, // default irq
129 WDfltIOB = 0x180, // default IO base
130
131 WIOLen = 0x40, // Hermes IO length
132
133 WTmOut = 65536, // Cmd time out
134
135 WPTypePeerToPeer = 0,
136 WPTypeManaged = 1,
137 WPTypeWDS = 2,
138 WPTypeAdHoc = 3,
139 WDfltPType = WPTypeManaged,
140
141 WDfltApDens = 1,
142 WDfltRtsThres = 2347, // == disabled
143 WDfltTxRate = WTxAuto, // 2Mbps
144
145 WMaxLen = 2304,
146 WNameLen = 32,
147
148 WNKeys = 4,
149 WKeyLen = 14,
150 WMinKeyLen = 5,
151
152 // Wavelan hermes registers
153 WR_Cmd = 0x00,
154 WCmdIni = 0x0000,
155 WCmdEna = 0x0001,
156 WCmdDis = 0x0002,
157 WCmdTx = 0x000b,
158 WCmdMalloc = 0x000a,
159 WCmdAskStats = 0x0011,
160 WCmdMsk = 0x003f,
161 WCmdAccRd = 0x0021,
162 WCmdReclaim = 0x0100,
163 WCmdAccWr = 0x0121,
164 WCmdBusy = 0x8000,
165 WR_Parm0 = 0x02,
166 WR_Parm1 = 0x04,
167 WR_Parm2 = 0x06,
168 WR_Sts = 0x08,
169 WR_InfoId = 0x10,
170 WR_Sel0 = 0x18,
171 WR_Sel1 = 0x1a,
172 WR_Off0 = 0x1c,
173 WR_Off1 = 0x1e,
174 WBusyOff = 0x8000,
175 WErrOff = 0x4000,
176 WResSts = 0x7f00,
177 WR_RXId = 0x20,
178 WR_Alloc = 0x22,
179 WR_EvSts = 0x30,
180 WR_IntEna = 0x32,
181 WCmdEv = 0x0010,
182 WRXEv = 0x0001,
183 WTXEv = 0x0002,
184 WTxErrEv = 0x0004,
185 WAllocEv = 0x0008,
186 WInfoEv = 0x0080,
187 WIDropEv = 0x2000,
188 WTickEv = 0x8000,
189 WEvs = WRXEv|WTXEv|WAllocEv|WInfoEv|WIDropEv,
190
191 WR_EvAck = 0x34,
192 WR_Data0 = 0x36,
193 WR_Data1 = 0x38,
194
195 // Frame stuff
196
197 WF_Err = 0x0003,
198 WF_1042 = 0x2000,
199 WF_Tunnel = 0x4000,
200 WF_WMP = 0x6000,
201
202 WF_Data = 0x0008,
203
204 WSnapK1 = 0xaa,
205 WSnapK2 = 0x00,
206 WSnapCtlr = 0x03,
207 WSnap0 = (WSnapK1|(WSnapK1<<8)),
208 WSnap1 = (WSnapK2|(WSnapCtlr<<8)),
209 WSnapHdrLen = 6,
210
211 WF_802_11_Off = 0x44,
212 WF_802_3_Off = 0x2e,
213
214 };
215
216 #define csr_outs(ctlr,r,arg) outs((ctlr)->iob+(r),(arg))
217 #define csr_ins(ctlr,r) ins((ctlr)->iob+(r))
218 #define csr_ack(ctlr,ev) outs((ctlr)->iob+WR_EvAck,(ev))
219
220 struct WKey
221 {
222 ushort len;
223 char dat[WKeyLen];
224 };
225
226 struct Wltv
227 {
228 ushort len;
229 ushort type;
230 union
231 {
232 struct {
233 ushort val;
234 ushort pad;
235 };
236 struct {
237 uchar addr[8];
238 };
239 struct {
240 ushort slen;
241 char s[WNameLen];
242 };
243 struct {
244 char name[WNameLen];
245 };
246 struct {
247 WKey keys[WNKeys];
248 };
249 };
250 };
251
252 // What the driver thinks. Not what the card thinks.
253 struct Stats
254 {
255 ulong nints;
256 ulong nrx;
257 ulong ntx;
258 ulong ntxrq;
259 ulong nrxerr;
260 ulong ntxerr;
261 ulong nalloc; // allocation (reclaim) events
262 ulong ninfo;
263 ulong nidrop;
264 ulong nwatchdogs; // transmit time outs, actually
265 int ticks;
266 int tickintr;
267 int signal;
268 int noise;
269 };
270
271 struct Ctlr
272 {
273 Lock;
274 Rendez timer;
275
276 int attached;
277 int slot;
278 int iob;
279 int ptype;
280 int apdensity;
281 int rtsthres;
282 int txbusy;
283 int txrate;
284 int txdid;
285 int txmid;
286 int txtmout;
287 int maxlen;
288 int chan;
289 int pmena;
290 int pmwait;
291
292 char netname[WNameLen];
293 char wantname[WNameLen];
294 char nodename[WNameLen];
295 WFrame txf;
296 uchar txbuf[1536];
297
298 int hascrypt; // card has encryption
299 int crypt; // encryption off/on
300 int txkey; // transmit key
301 Wltv keys; // default keys
302 int xclear; // exclude clear packets off/on
303
304 Stats;
305 WStats;
306 };
307
308 // w_... routines do not ilock the Ctlr and should
309 // be called locked.
310
311 static void
w_intdis(Ctlr * ctlr)312 w_intdis(Ctlr* ctlr)
313 {
314 csr_outs(ctlr, WR_IntEna, 0);
315 csr_ack(ctlr, 0xffff);
316 }
317
318 static void
w_intena(Ctlr * ctlr)319 w_intena(Ctlr* ctlr)
320 {
321 csr_outs(ctlr, WR_IntEna, WEvs);
322 }
323
324 static int
w_cmd(Ctlr * ctlr,ushort cmd,ushort arg)325 w_cmd(Ctlr *ctlr, ushort cmd, ushort arg)
326 {
327 int i, rc;
328
329 csr_outs(ctlr, WR_Parm0, arg);
330 csr_outs(ctlr, WR_Cmd, cmd);
331 for (i = 0; i<WTmOut; i++){
332 rc = csr_ins(ctlr, WR_EvSts);
333 if ( rc&WCmdEv ){
334 rc = csr_ins(ctlr, WR_Sts);
335 csr_ack(ctlr, WCmdEv);
336 if ((rc&WCmdMsk) != (cmd&WCmdMsk))
337 break;
338 if (rc&WResSts)
339 break;
340 return 0;
341 }
342 }
343
344 return -1;
345 }
346
347 static int
w_seek(Ctlr * ctlr,ushort id,ushort offset,int chan)348 w_seek(Ctlr* ctlr, ushort id, ushort offset, int chan)
349 {
350 int i, rc;
351 static ushort sel[] = { WR_Sel0, WR_Sel1 };
352 static ushort off[] = { WR_Off0, WR_Off1 };
353
354 if (chan != 0 && chan != 1)
355 panic("wavelan: bad chan\n");
356 csr_outs(ctlr, sel[chan], id);
357 csr_outs(ctlr, off[chan], offset);
358 for (i=0; i<WTmOut; i++){
359 rc = csr_ins(ctlr, off[chan]);
360 if ((rc & (WBusyOff|WErrOff)) == 0)
361 return 0;
362 }
363 return -1;
364 }
365
366 static int
w_inltv(Ctlr * ctlr,Wltv * ltv)367 w_inltv(Ctlr* ctlr, Wltv* ltv)
368 {
369 int len;
370 ushort code;
371
372 if (w_cmd(ctlr, WCmdAccRd, ltv->type)){
373 DEBUG("wavelan: access read failed\n");
374 return -1;
375 }
376 if (w_seek(ctlr,ltv->type,0,1)){
377 DEBUG("wavelan: seek failed\n");
378 return -1;
379 }
380 len = csr_ins(ctlr, WR_Data1);
381 if (len > ltv->len)
382 return -1;
383 ltv->len = len;
384 if ((code=csr_ins(ctlr, WR_Data1)) != ltv->type){
385 DEBUG("wavelan: type %x != code %x\n",ltv->type,code);
386 return -1;
387 }
388 if(ltv->len > 0)
389 inss((ctlr)->iob+(WR_Data1), <v->val, ltv->len-1);
390
391 return 0;
392 }
393
394 static void
w_outltv(Ctlr * ctlr,Wltv * ltv)395 w_outltv(Ctlr* ctlr, Wltv* ltv)
396 {
397 if(w_seek(ctlr,ltv->type, 0, 1))
398 return;
399 outss((ctlr)->iob+(WR_Data1), ltv, ltv->len+1);
400 w_cmd(ctlr, WCmdAccWr, ltv->type);
401 }
402
403 static void
ltv_outs(Ctlr * ctlr,int type,ushort val)404 ltv_outs(Ctlr* ctlr, int type, ushort val)
405 {
406 Wltv ltv;
407
408 ltv.len = 2;
409 ltv.type = type;
410 ltv.val = val;
411 w_outltv(ctlr, <v);
412 }
413
414 static int
ltv_ins(Ctlr * ctlr,int type)415 ltv_ins(Ctlr* ctlr, int type)
416 {
417 Wltv ltv;
418
419 ltv.len = 2;
420 ltv.type = type;
421 ltv.val = 0;
422 if(w_inltv(ctlr, <v))
423 return -1;
424 return ltv.val;
425 }
426
427 static void
ltv_outstr(Ctlr * ctlr,int type,char * val)428 ltv_outstr(Ctlr* ctlr, int type, char* val)
429 {
430 Wltv ltv;
431 int len;
432
433 len = strlen(val);
434 if(len > sizeof(ltv.s))
435 len = sizeof(ltv.s);
436 memset(<v, 0, sizeof(ltv));
437 ltv.len = (sizeof(ltv.type)+sizeof(ltv.slen)+sizeof(ltv.s))/2;
438 ltv.type = type;
439
440 // This should be ltv.slen = len; according to Axel Belinfante
441 ltv.slen = len;
442
443 strncpy(ltv.s, val, len);
444 w_outltv(ctlr, <v);
445 }
446
447 static char Unkname[] = "who knows";
448 static char Nilname[] = "card does not tell";
449
450 static char*
ltv_inname(Ctlr * ctlr,int type)451 ltv_inname(Ctlr* ctlr, int type)
452 {
453 static Wltv ltv;
454 int len;
455
456 memset(<v,0,sizeof(ltv));
457 ltv.len = WNameLen/2+2;
458 ltv.type = type;
459 if (w_inltv(ctlr, <v))
460 return Unkname;
461 len = ltv.slen;
462 if(len == 0 || ltv.s[0] == 0)
463 return Nilname;
464 if(len >= sizeof ltv.s)
465 len = sizeof ltv.s - 1;
466 ltv.s[len] = '\0';
467 return ltv.s;
468 }
469
470 static int
w_read(Ctlr * ctlr,int type,int off,void * buf,ulong len)471 w_read(Ctlr* ctlr, int type, int off, void* buf, ulong len)
472 {
473 if (w_seek(ctlr, type, off, 1)){
474 DEBUG("wavelan: w_read: seek failed");
475 return 0;
476 }
477 inss((ctlr)->iob+(WR_Data1), buf, len/2);
478
479 return len;
480 }
481
482 static int
w_write(Ctlr * ctlr,int type,int off,void * buf,ulong len)483 w_write(Ctlr* ctlr, int type, int off, void* buf, ulong len)
484 {
485 int tries;
486
487 for (tries=0; tries < WTmOut; tries++){
488 if (w_seek(ctlr, type, off, 0)){
489 DEBUG("wavelan: w_write: seek failed\n");
490 return 0;
491 }
492
493 outss((ctlr)->iob+(WR_Data0), buf, len/2);
494
495 csr_outs(ctlr, WR_Data0, 0xdead);
496 csr_outs(ctlr, WR_Data0, 0xbeef);
497 if (w_seek(ctlr, type, off + len, 0)){
498 DEBUG("wavelan: write seek failed\n");
499 return 0;
500 }
501 if (csr_ins(ctlr, WR_Data0) == 0xdead)
502 if (csr_ins(ctlr, WR_Data0) == 0xbeef)
503 return len;
504 DEBUG("wavelan: Hermes bug byte.\n");
505 return 0;
506 }
507 DEBUG("wavelan: tx timeout\n");
508 return 0;
509 }
510
511 static int
w_alloc(Ctlr * ctlr,int len)512 w_alloc(Ctlr* ctlr, int len)
513 {
514 int rc;
515 int i,j;
516
517 if (w_cmd(ctlr, WCmdMalloc, len)==0)
518 for (i = 0; i<WTmOut; i++)
519 if (csr_ins(ctlr, WR_EvSts) & WAllocEv){
520 csr_ack(ctlr, WAllocEv);
521 rc=csr_ins(ctlr, WR_Alloc);
522 if (w_seek(ctlr, rc, 0, 0))
523 return -1;
524 len = len/2;
525 for (j=0; j<len; j++)
526 csr_outs(ctlr, WR_Data0, 0);
527 return rc;
528 }
529 return -1;
530 }
531
532 static int
w_enable(Ether * ether)533 w_enable(Ether* ether)
534 {
535 Wltv ltv;
536 Ctlr* ctlr = (Ctlr*) ether->ctlr;
537
538 if (!ctlr)
539 return -1;
540
541 w_intdis(ctlr);
542 w_cmd(ctlr, WCmdDis, 0);
543 w_intdis(ctlr);
544 if(w_cmd(ctlr, WCmdIni, 0))
545 return -1;
546 w_intdis(ctlr);
547
548 ltv_outs(ctlr, WTyp_Tick, 8);
549 ltv_outs(ctlr, WTyp_MaxLen, ctlr->maxlen);
550 ltv_outs(ctlr, WTyp_Ptype, ctlr->ptype);
551 ltv_outs(ctlr, WTyp_RtsThres, ctlr->rtsthres);
552 ltv_outs(ctlr, WTyp_TxRate, ctlr->txrate);
553 ltv_outs(ctlr, WTyp_ApDens, ctlr->apdensity);
554 ltv_outs(ctlr, WTyp_PMWait, ctlr->pmwait);
555 ltv_outs(ctlr, WTyp_PM, ctlr->pmena);
556 if (*ctlr->netname)
557 ltv_outstr(ctlr, WTyp_NetName, ctlr->netname);
558 if (*ctlr->wantname)
559 ltv_outstr(ctlr, WTyp_WantName, ctlr->wantname);
560 ltv_outs(ctlr, WTyp_Chan, ctlr->chan);
561 if (*ctlr->nodename)
562 ltv_outstr(ctlr, WTyp_NodeName, ctlr->nodename);
563 ltv.len = 4;
564 ltv.type = WTyp_Mac;
565 memmove(ltv.addr, ether->ea, Eaddrlen);
566 w_outltv(ctlr, <v);
567
568 ltv_outs(ctlr, WTyp_Prom, (ether->prom?1:0));
569
570 if (ctlr->hascrypt){
571 ltv_outs(ctlr, WTyp_Crypt, ctlr->crypt);
572 ltv_outs(ctlr, WTyp_TxKey, ctlr->txkey);
573 w_outltv(ctlr, &ctlr->keys);
574 ltv_outs(ctlr, WTyp_XClear, ctlr->xclear);
575 }
576
577 // BUG: set multicast addresses
578
579 if (w_cmd(ctlr, WCmdEna, 0)){
580 DEBUG("wavelan: Enable failed");
581 return -1;
582 }
583 ctlr->txdid = w_alloc(ctlr, 1518 + sizeof(WFrame) + 8);
584 ctlr->txmid = w_alloc(ctlr, 1518 + sizeof(WFrame) + 8);
585 if (ctlr->txdid == -1 || ctlr->txmid == -1)
586 DEBUG("wavelan: alloc failed");
587 ctlr->txbusy = 0;
588 w_intena(ctlr);
589 return 0;
590 }
591
592 static void
w_rxdone(Ether * ether)593 w_rxdone(Ether* ether)
594 {
595 Ctlr* ctlr = (Ctlr*) ether->ctlr;
596 int len, sp;
597 WFrame f;
598 Block* bp=0;
599 Etherpkt* ep;
600
601 sp = csr_ins(ctlr, WR_RXId);
602 len = w_read(ctlr, sp, 0, &f, sizeof(f));
603 if (len == 0){
604 DEBUG("wavelan: read frame error\n");
605 goto rxerror;
606 }
607 if (f.sts&WF_Err){
608 goto rxerror;
609 }
610 switch(f.sts){
611 case WF_1042:
612 case WF_Tunnel:
613 case WF_WMP:
614 len = f.dlen + WSnapHdrLen;
615 bp = iallocb(ETHERHDRSIZE + len + 2);
616 if (!bp)
617 goto rxerror;
618 ep = (Etherpkt*) bp->wp;
619 memmove(ep->d, f.addr1, Eaddrlen);
620 memmove(ep->s, f.addr2, Eaddrlen);
621 memmove(ep->type,&f.type,2);
622 bp->wp += ETHERHDRSIZE;
623 if (w_read(ctlr, sp, WF_802_11_Off, bp->wp, len+2) == 0){
624 DEBUG("wavelan: read 802.11 error\n");
625 goto rxerror;
626 }
627 bp->wp = bp->rp+(ETHERHDRSIZE+f.dlen);
628 break;
629 default:
630 len = ETHERHDRSIZE + f.dlen + 2;
631 bp = iallocb(len);
632 if (!bp)
633 goto rxerror;
634 if (w_read(ctlr, sp, WF_802_3_Off, bp->wp, len) == 0){
635 DEBUG("wavelan: read 800.3 error\n");
636 goto rxerror;
637 }
638 bp->wp += len;
639 }
640
641 ctlr->nrx++;
642 etheriq(ether,bp,1);
643 ctlr->signal = ((ctlr->signal*15)+((f.qinfo>>8) & 0xFF))/16;
644 ctlr->noise = ((ctlr->noise*15)+(f.qinfo & 0xFF))/16;
645 return;
646
647 rxerror:
648 freeb(bp);
649 ctlr->nrxerr++;
650 }
651
652 static void
w_txstart(Ether * ether)653 w_txstart(Ether* ether)
654 {
655 Etherpkt *pkt;
656 Ctlr *ctlr;
657 Block *bp;
658 int len, off;
659
660 if((ctlr = ether->ctlr) == nil || ctlr->attached == 0 || ctlr->txbusy)
661 return;
662
663 if((bp = qget(ether->oq)) == nil)
664 return;
665 pkt = (Etherpkt*)bp->rp;
666
667 //
668 // If the packet header type field is > 1500 it is an IP or
669 // ARP datagram, otherwise it is an 802.3 packet. See RFC1042.
670 //
671 memset(&ctlr->txf, 0, sizeof(ctlr->txf));
672 if(((pkt->type[0]<<8)|pkt->type[1]) > 1500){
673 ctlr->txf.framectl = WF_Data;
674 memmove(ctlr->txf.addr1, pkt->d, Eaddrlen);
675 memmove(ctlr->txf.addr2, pkt->s, Eaddrlen);
676 memmove(ctlr->txf.dstaddr, pkt->d, Eaddrlen);
677 memmove(ctlr->txf.srcaddr, pkt->s, Eaddrlen);
678 memmove(&ctlr->txf.type, pkt->type, 2);
679 bp->rp += ETHERHDRSIZE;
680 len = BLEN(bp);
681 off = WF_802_11_Off;
682 ctlr->txf.dlen = len+ETHERHDRSIZE-WSnapHdrLen;
683 hnputs((uchar*)&ctlr->txf.dat[0], WSnap0);
684 hnputs((uchar*)&ctlr->txf.dat[1], WSnap1);
685 hnputs((uchar*)&ctlr->txf.len, len+ETHERHDRSIZE-WSnapHdrLen);
686 }
687 else{
688 len = BLEN(bp);
689 off = WF_802_3_Off;
690 ctlr->txf.dlen = len;
691 }
692 w_write(ctlr, ctlr->txdid, 0, &ctlr->txf, sizeof(ctlr->txf));
693 w_write(ctlr, ctlr->txdid, off, bp->rp, len+2);
694
695 if(w_cmd(ctlr, WCmdReclaim|WCmdTx, ctlr->txdid)){
696 DEBUG("wavelan: transmit failed\n");
697 ctlr->ntxerr++;
698 }
699 else{
700 ctlr->txbusy = 1;
701 ctlr->txtmout = 2;
702 }
703 freeb(bp);
704 }
705
706 static void
w_txdone(Ctlr * ctlr,int sts)707 w_txdone(Ctlr* ctlr, int sts)
708 {
709 ctlr->txbusy = 0;
710 ctlr->txtmout = 0;
711 if (sts & WTxErrEv)
712 ctlr->ntxerr++;
713 else
714 ctlr->ntx++;
715 }
716
717 static int
w_stats(Ctlr * ctlr)718 w_stats(Ctlr* ctlr)
719 {
720 int i, rc, sp;
721 Wltv ltv;
722 ulong* p = (ulong*)&ctlr->WStats;
723 ulong* pend = (ulong*)&ctlr->end;
724
725 sp = csr_ins(ctlr, WR_InfoId);
726 ltv.len = ltv.type = 0;
727 w_read(ctlr, sp, 0, <v, 4);
728 if (ltv.type == WTyp_Stats){
729 ltv.len--;
730 for (i = 0; i < ltv.len && p < pend; i++){
731 rc = csr_ins(ctlr, WR_Data1);
732 if (rc > 0xf000)
733 rc = ~rc & 0xffff;
734 p[i] += rc;
735 }
736 return 0;
737 }
738 return -1;
739 }
740
741 static void
w_intr(Ether * ether)742 w_intr(Ether *ether)
743 {
744 int rc, txid;
745 Ctlr* ctlr = (Ctlr*) ether->ctlr;
746
747 if (ctlr->attached == 0){
748 csr_ack(ctlr, 0xffff);
749 csr_outs(ctlr, WR_IntEna, 0);
750 return;
751 }
752
753 csr_outs(ctlr, WR_IntEna, 0);
754 rc = csr_ins(ctlr, WR_EvSts);
755 csr_ack(ctlr, ~WEvs); // Not interested on them
756
757 if (rc & WRXEv){
758 w_rxdone(ether);
759 csr_ack(ctlr, WRXEv);
760 }
761 if (rc & WTXEv){
762 w_txdone(ctlr, rc);
763 csr_ack(ctlr, WTXEv);
764 }
765 if (rc & WAllocEv){
766 ctlr->nalloc++;
767 txid = csr_ins(ctlr, WR_Alloc);
768 csr_ack(ctlr, WAllocEv);
769 if (txid == ctlr->txdid){
770 if ((rc & WTXEv) == 0)
771 w_txdone(ctlr, rc);
772 }
773 }
774 if (rc & WInfoEv){
775 ctlr->ninfo++;
776 w_stats(ctlr);
777 csr_ack(ctlr, WInfoEv);
778 }
779 if (rc & WTxErrEv){
780 w_txdone(ctlr, rc);
781 csr_ack(ctlr, WTxErrEv);
782 }
783 if (rc & WIDropEv){
784 ctlr->nidrop++;
785 csr_ack(ctlr, WIDropEv);
786 }
787
788 w_intena(ctlr);
789 w_txstart(ether);
790 }
791
792 // Watcher to ensure that the card still works properly and
793 // to request WStats updates once a minute.
794 // BUG: it runs much more often, see the comment below.
795
796 static void
w_timer(void * arg)797 w_timer(void* arg)
798 {
799 Ether* ether = (Ether*) arg;
800 Ctlr* ctlr = (Ctlr*)ether->ctlr;
801
802 for(;;){
803 tsleep(&ctlr->timer, return0, 0, 50);
804 ctlr = (Ctlr*)ether->ctlr;
805 if (ctlr == 0)
806 break;
807 if (ctlr->attached == 0)
808 continue;
809 ctlr->ticks++;
810
811 ilock(ctlr);
812
813 // Seems that the card gets frames BUT does
814 // not send the interrupt; this is a problem because
815 // I suspect it runs out of receive buffers and
816 // stops receiving until a transmit watchdog
817 // reenables the card.
818 // The problem is serious because it leads to
819 // poor rtts.
820 // This can be seen clearly by commenting out
821 // the next if and doing a ping: it will stop
822 // receiving (although the icmp replies are being
823 // issued from the remote) after a few seconds.
824 // Of course this `bug' could be because I'm reading
825 // the card frames in the wrong way; due to the
826 // lack of documentation I cannot know.
827
828 // if (csr_ins(ctlr, WR_EvSts)&WEvs){
829 // ctlr->tickintr++;
830 // w_intr(ether);
831 // }
832
833 if ((ctlr->ticks % 10) == 0) {
834 if (ctlr->txtmout && --ctlr->txtmout == 0){
835 ctlr->nwatchdogs++;
836 w_txdone(ctlr, WTxErrEv);
837 if (w_enable(ether)){
838 DEBUG("wavelan: wdog enable failed\n");
839 }
840 w_txstart(ether);
841 }
842 if ((ctlr->ticks % 120) == 0)
843 if (ctlr->txbusy == 0)
844 w_cmd(ctlr, WCmdAskStats, WTyp_Stats);
845 }
846 iunlock(ctlr);
847 }
848 pexit("terminated",0);
849 }
850
851 static void
multicast(void *,uchar *,int)852 multicast(void*, uchar*, int)
853 {
854 // BUG: to be added.
855 }
856
857 static void
attach(Ether * ether)858 attach(Ether* ether)
859 {
860 Ctlr* ctlr;
861 char name[64];
862 int rc;
863
864 if (ether->ctlr == 0)
865 return;
866
867 snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
868 ctlr = (Ctlr*) ether->ctlr;
869 if (ctlr->attached == 0){
870 ilock(ctlr);
871 rc = w_enable(ether);
872 iunlock(ctlr);
873 if(rc == 0){
874 ctlr->attached = 1;
875 kproc(name, w_timer, ether, 0);
876 } else
877 print("#l%d: enable failed\n",ether->ctlrno);
878 }
879 }
880
881 #define PRINTSTAT(fmt,val) l += snprint(p+l, READSTR-l, (fmt), (val))
882 #define PRINTSTR(fmt) l += snprint(p+l, READSTR-l, (fmt))
883
884 static long
ifstat(Ether * ether,void * a,long n,ulong offset)885 ifstat(Ether* ether, void* a, long n, ulong offset)
886 {
887 Ctlr *ctlr = (Ctlr*) ether->ctlr;
888 char *k, *p;
889 int i, l, txid;
890
891 ether->oerrs = ctlr->ntxerr;
892 ether->crcs = ctlr->nrxfcserr;
893 ether->frames = 0;
894 ether->buffs = ctlr->nrxdropnobuf;
895 ether->overflows = 0;
896
897 //
898 // Offset must be zero or there's a possibility the
899 // new data won't match the previous read.
900 //
901 if(n == 0 || offset != 0)
902 return 0;
903
904 p = malloc(READSTR);
905 l = 0;
906
907 PRINTSTAT("Signal: %d\n", ctlr->signal-149);
908 PRINTSTAT("Noise: %d\n", ctlr->noise-149);
909 PRINTSTAT("SNR: %ud\n", ctlr->signal-ctlr->noise);
910 PRINTSTAT("Interrupts: %lud\n", ctlr->nints);
911 PRINTSTAT("TxPackets: %lud\n", ctlr->ntx);
912 PRINTSTAT("RxPackets: %lud\n", ctlr->nrx);
913 PRINTSTAT("TxErrors: %lud\n", ctlr->ntxerr);
914 PRINTSTAT("RxErrors: %lud\n", ctlr->nrxerr);
915 PRINTSTAT("TxRequests: %lud\n", ctlr->ntxrq);
916 PRINTSTAT("AllocEvs: %lud\n", ctlr->nalloc);
917 PRINTSTAT("InfoEvs: %lud\n", ctlr->ninfo);
918 PRINTSTAT("InfoDrop: %lud\n", ctlr->nidrop);
919 PRINTSTAT("WatchDogs: %lud\n", ctlr->nwatchdogs);
920 PRINTSTAT("Ticks: %ud\n", ctlr->ticks);
921 PRINTSTAT("TickIntr: %ud\n", ctlr->tickintr);
922 k = ((ctlr->attached) ? "attached" : "not attached");
923 PRINTSTAT("Card %s", k);
924 k = ((ctlr->txbusy)? ", txbusy" : "");
925 PRINTSTAT("%s\n", k);
926
927 if (ctlr->hascrypt){
928 PRINTSTR("Keys: ");
929 for (i = 0; i < WNKeys; i++){
930 if (ctlr->keys.keys[i].len == 0)
931 PRINTSTR("none ");
932 else if (SEEKEYS == 0)
933 PRINTSTR("set ");
934 else
935 PRINTSTAT("%s ", ctlr->keys.keys[i].dat);
936 }
937 PRINTSTR("\n");
938 }
939
940 // real card stats
941 ilock(ctlr);
942 PRINTSTR("\nCard stats: \n");
943 PRINTSTAT("Status: %ux\n", csr_ins(ctlr, WR_Sts));
944 PRINTSTAT("Event status: %ux\n", csr_ins(ctlr, WR_EvSts));
945 i = ltv_ins(ctlr, WTyp_Ptype);
946 PRINTSTAT("Port type: %d\n", i);
947 PRINTSTAT("Transmit rate: %d\n", ltv_ins(ctlr, WTyp_TxRate));
948 PRINTSTAT("Current Transmit rate: %d\n",
949 ltv_ins(ctlr, WTyp_CurTxRate));
950 PRINTSTAT("Channel: %d\n", ltv_ins(ctlr, WTyp_Chan));
951 PRINTSTAT("AP density: %d\n", ltv_ins(ctlr, WTyp_ApDens));
952 PRINTSTAT("Promiscuous mode: %d\n", ltv_ins(ctlr, WTyp_Prom));
953 if(i == 3)
954 PRINTSTAT("SSID name: %s\n", ltv_inname(ctlr, WTyp_NetName));
955 else {
956 Wltv ltv;
957 PRINTSTAT("Current name: %s\n", ltv_inname(ctlr, WTyp_CurName));
958 ltv.type = WTyp_BaseID;
959 ltv.len = 4;
960 if (w_inltv(ctlr, <v))
961 print("#l%d: unable to read base station mac addr\n", ether->ctlrno);
962 l += snprint(p+l, READSTR-l, "Base station: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
963 ltv.addr[0], ltv.addr[1], ltv.addr[2], ltv.addr[3], ltv.addr[4], ltv.addr[5]);
964 }
965 PRINTSTAT("Net name: %s\n", ltv_inname(ctlr, WTyp_WantName));
966 PRINTSTAT("Node name: %s\n", ltv_inname(ctlr, WTyp_NodeName));
967 if (ltv_ins(ctlr, WTyp_HasCrypt) == 0)
968 PRINTSTR("WEP: not supported\n");
969 else {
970 if (ltv_ins(ctlr, WTyp_Crypt) == 0)
971 PRINTSTR("WEP: disabled\n");
972 else{
973 PRINTSTR("WEP: enabled\n");
974 k = ((ctlr->xclear)? "excluded": "included");
975 PRINTSTAT("Clear packets: %s\n", k);
976 txid = ltv_ins(ctlr, WTyp_TxKey);
977 PRINTSTAT("Transmit key id: %d\n", txid);
978 }
979 }
980 iunlock(ctlr);
981
982 PRINTSTAT("ntxuframes: %lud\n", ctlr->ntxuframes);
983 PRINTSTAT("ntxmframes: %lud\n", ctlr->ntxmframes);
984 PRINTSTAT("ntxfrags: %lud\n", ctlr->ntxfrags);
985 PRINTSTAT("ntxubytes: %lud\n", ctlr->ntxubytes);
986 PRINTSTAT("ntxmbytes: %lud\n", ctlr->ntxmbytes);
987 PRINTSTAT("ntxdeferred: %lud\n", ctlr->ntxdeferred);
988 PRINTSTAT("ntxsretries: %lud\n", ctlr->ntxsretries);
989 PRINTSTAT("ntxmultiretries: %lud\n", ctlr->ntxmultiretries);
990 PRINTSTAT("ntxretrylimit: %lud\n", ctlr->ntxretrylimit);
991 PRINTSTAT("ntxdiscards: %lud\n", ctlr->ntxdiscards);
992 PRINTSTAT("nrxuframes: %lud\n", ctlr->nrxuframes);
993 PRINTSTAT("nrxmframes: %lud\n", ctlr->nrxmframes);
994 PRINTSTAT("nrxfrags: %lud\n", ctlr->nrxfrags);
995 PRINTSTAT("nrxubytes: %lud\n", ctlr->nrxubytes);
996 PRINTSTAT("nrxmbytes: %lud\n", ctlr->nrxmbytes);
997 PRINTSTAT("nrxfcserr: %lud\n", ctlr->nrxfcserr);
998 PRINTSTAT("nrxdropnobuf: %lud\n", ctlr->nrxdropnobuf);
999 PRINTSTAT("nrxdropnosa: %lud\n", ctlr->nrxdropnosa);
1000 PRINTSTAT("nrxcantdecrypt: %lud\n", ctlr->nrxcantdecrypt);
1001 PRINTSTAT("nrxmsgfrag: %lud\n", ctlr->nrxmsgfrag);
1002 PRINTSTAT("nrxmsgbadfrag: %lud\n", ctlr->nrxmsgbadfrag);
1003 USED(l);
1004 n = readstr(offset, a, n, p);
1005 free(p);
1006 return n;
1007 }
1008 #undef PRINTSTR
1009 #undef PRINTSTAT
1010
1011 static int
w_option(Ctlr * ctlr,char * buf,long n)1012 w_option(Ctlr* ctlr, char* buf, long n)
1013 {
1014 char *p;
1015 int i, r;
1016 WKey *key;
1017 Cmdbuf *cb;
1018
1019 r = 0;
1020
1021 cb = parsecmd(buf, n);
1022 if(cb->nf < 2)
1023 r = -1;
1024 else if(cistrcmp(cb->f[0], "essid") == 0){
1025 if (cistrcmp(cb->f[1],"default") == 0)
1026 p = "";
1027 else
1028 p = cb->f[1];
1029 switch(ctlr->ptype){
1030 case 0:
1031 case 3:
1032 memset(ctlr->netname, 0, sizeof(ctlr->netname));
1033 strncpy(ctlr->netname, p, WNameLen);
1034 if(ctlr->ptype == 3)
1035 break;
1036 /* fall through to set both for peer-to-peer */
1037 default:
1038 memset(ctlr->wantname, 0, sizeof(ctlr->wantname));
1039 strncpy(ctlr->wantname, p, WNameLen);
1040 break;
1041 }
1042 }
1043 else if(cistrcmp(cb->f[0], "station") == 0){
1044 memset(ctlr->nodename, 0, sizeof(ctlr->nodename));
1045 strncpy(ctlr->nodename, cb->f[1], WNameLen);
1046 }
1047 else if(cistrcmp(cb->f[0], "channel") == 0){
1048 if((i = atoi(cb->f[1])) >= 1 && i <= 16)
1049 ctlr->chan = i;
1050 else
1051 r = -1;
1052 }
1053 else if(cistrcmp(cb->f[0], "mode") == 0){
1054 if(cistrcmp(cb->f[1], "managed") == 0)
1055 ctlr->ptype = WPTypeManaged;
1056 else if(cistrcmp(cb->f[1], "wds") == 0)
1057 ctlr->ptype = WPTypeWDS;
1058 else if(cistrcmp(cb->f[1], "adhoc") == 0)
1059 ctlr->ptype = WPTypeAdHoc;
1060 else if(cistrcmp(cb->f[1], "peertopeer") == 0)
1061 ctlr->ptype = WPTypePeerToPeer;
1062 else if((i = atoi(cb->f[1])) >= 0 && i <= 3)
1063 ctlr->ptype = i;
1064 else
1065 r = -1;
1066 }
1067 else if(cistrcmp(cb->f[0], "crypt") == 0){
1068 if(cistrcmp(cb->f[1], "off") == 0)
1069 ctlr->crypt = 0;
1070 else if(cistrcmp(cb->f[1], "on") == 0 && ctlr->hascrypt)
1071 ctlr->crypt = 1;
1072 else
1073 r = -1;
1074 }
1075 else if(cistrcmp(cb->f[0], "clear") == 0){
1076 if(cistrcmp(cb->f[1], "on") == 0)
1077 ctlr->xclear = 0;
1078 else if(cistrcmp(cb->f[1], "off") == 0 && ctlr->hascrypt)
1079 ctlr->xclear = 1;
1080 else
1081 r = -1;
1082 }
1083 else if(strncmp(cb->f[0], "key", 3) == 0){
1084 if((i = atoi(cb->f[0]+3)) >= 1 && i <= WNKeys){
1085 ctlr->txkey = i-1;
1086 key = &ctlr->keys.keys[ctlr->txkey];
1087 key->len = strlen(cb->f[1]);
1088 if (key->len > WKeyLen)
1089 key->len = WKeyLen;
1090 memset(key->dat, 0, sizeof(key->dat));
1091 memmove(key->dat, cb->f[1], key->len);
1092 }
1093 else
1094 r = -1;
1095 }
1096 else if(cistrcmp(cb->f[0], "txkey") == 0){
1097 if((i = atoi(cb->f[1])) >= 1 && i <= WNKeys)
1098 ctlr->txkey = i-1;
1099 else
1100 r = -1;
1101 }
1102 else if(cistrcmp(cb->f[0], "pm") == 0){
1103 if(cistrcmp(cb->f[1], "off") == 0)
1104 ctlr->pmena = 0;
1105 else if(cistrcmp(cb->f[1], "on") == 0){
1106 ctlr->pmena = 1;
1107 if(cb->nf == 3){
1108 i = atoi(cb->f[2]);
1109 // check range here? what are the units?
1110 ctlr->pmwait = i;
1111 }
1112 }
1113 else
1114 r = -1;
1115 }
1116 else
1117 r = -2;
1118 free(cb);
1119
1120 return r;
1121 }
1122
1123 static long
ctl(Ether * ether,void * buf,long n)1124 ctl(Ether* ether, void* buf, long n)
1125 {
1126 Ctlr *ctlr;
1127
1128 if((ctlr = ether->ctlr) == nil)
1129 error(Enonexist);
1130 if(ctlr->attached == 0)
1131 error(Eshutdown);
1132
1133 ilock(ctlr);
1134 if(w_option(ctlr, buf, n)){
1135 iunlock(ctlr);
1136 error(Ebadctl);
1137 }
1138 if(ctlr->txbusy)
1139 w_txdone(ctlr, WTxErrEv);
1140 w_enable(ether);
1141 w_txstart(ether);
1142 iunlock(ctlr);
1143
1144 return n;
1145 }
1146
1147 static void
transmit(Ether * ether)1148 transmit(Ether* ether)
1149 {
1150 Ctlr* ctlr = ether->ctlr;
1151
1152 if (ctlr == 0)
1153 return;
1154
1155 ilock(ctlr);
1156 ctlr->ntxrq++;
1157 w_txstart(ether);
1158 iunlock(ctlr);
1159 }
1160
1161 static void
promiscuous(void * arg,int on)1162 promiscuous(void* arg, int on)
1163 {
1164 Ether* ether = (Ether*)arg;
1165 Ctlr* ctlr = ether->ctlr;
1166
1167 if (ctlr == nil)
1168 error("card not found");
1169 if (ctlr->attached == 0)
1170 error("card not attached");
1171 ilock(ctlr);
1172 ltv_outs(ctlr, WTyp_Prom, (on?1:0));
1173 iunlock(ctlr);
1174 }
1175
1176 static void
interrupt(Ureg *,void * arg)1177 interrupt(Ureg* ,void* arg)
1178 {
1179 Ether* ether = (Ether*) arg;
1180 Ctlr* ctlr = (Ctlr*) ether->ctlr;
1181
1182 if (ctlr == 0)
1183 return;
1184 ilock(ctlr);
1185 ctlr->nints++;
1186 w_intr(ether);
1187 iunlock(ctlr);
1188 }
1189
1190 static int
reset(Ether * ether)1191 reset(Ether* ether)
1192 {
1193 int i;
1194 Wltv ltv;
1195 Ctlr* ctlr;
1196 int slot;
1197 char *p;
1198
1199 if ((slot = pcmspecial("WaveLAN/IEEE", ether))<0){
1200 DEBUG("no wavelan found\n");
1201 return -1;
1202 }
1203
1204 if((ctlr = malloc(sizeof(Ctlr))) == nil)
1205 return -1;
1206
1207 ilock(ctlr);
1208
1209 if (ether->port==0)
1210 ether->port = WDfltIOB;
1211 ctlr->iob = ether->port;
1212 ctlr->slot = slot;
1213
1214 if (ioalloc(ether->port,WIOLen,0,"wavelan")<0){
1215 print("#l%d: port 0x%lx in use\n",
1216 ether->ctlrno, ether->port);
1217 goto abort;
1218 }
1219 DEBUG("#l%d: port=0x%lx irq=%ld\n",
1220 ether->ctlrno, ether->port, ether->irq);
1221
1222 w_intdis(ctlr);
1223 if (w_cmd(ctlr,WCmdIni,0)){
1224 print("#l%d: init failed\n", ether->ctlrno);
1225 goto abort;
1226 }
1227 w_intdis(ctlr);
1228 ltv_outs(ctlr, WTyp_Tick, 8);
1229
1230 ctlr->chan = 0;
1231 ctlr->ptype = WDfltPType;
1232 ctlr->txkey = 0;
1233 ctlr->keys.len = sizeof(WKey)*WNKeys/2 + 1;
1234 ctlr->keys.type = WTyp_Keys;
1235 if(ctlr->hascrypt = ltv_ins(ctlr, WTyp_HasCrypt))
1236 ctlr->crypt = 1;
1237 *ctlr->netname = *ctlr->wantname = 0;
1238 strcpy(ctlr->nodename, "Plan 9 STA");
1239
1240 for(i = 0; i < ether->nopt; i++){
1241 //
1242 // The max. length of an 'opt' is ISAOPTLEN in dat.h.
1243 // It should be > 16 to give reasonable name lengths.
1244 //
1245 if(p = strchr(ether->opt[i], '='))
1246 *p = ' ';
1247 w_option(ctlr, ether->opt[i], strlen(ether->opt[i]));
1248 }
1249
1250 ctlr->netname[WNameLen-1] = 0;
1251 ctlr->wantname[WNameLen-1] = 0;
1252 ctlr->nodename[WNameLen-1] =0;
1253
1254 ltv.type = WTyp_Mac;
1255 ltv.len = 4;
1256 if (w_inltv(ctlr, <v)){
1257 print("#l%d: unable to read mac addr\n",
1258 ether->ctlrno);
1259 goto abort;
1260 }
1261 memmove(ether->ea, ltv.addr, Eaddrlen);
1262
1263 if (ctlr->chan == 0)
1264 ctlr->chan = ltv_ins(ctlr, WTyp_Chan);
1265 ctlr->apdensity = WDfltApDens;
1266 ctlr->rtsthres = WDfltRtsThres;
1267 ctlr->txrate = WDfltTxRate;
1268 ctlr->maxlen = WMaxLen;
1269 ctlr->pmena = 0;
1270 ctlr->pmwait = 100;
1271 ctlr->signal = 1;
1272 ctlr->noise = 1;
1273
1274 // link to ether
1275 ether->ctlr = ctlr;
1276 ether->mbps = 10;
1277 ether->attach = attach;
1278 ether->interrupt = interrupt;
1279 ether->transmit = transmit;
1280 ether->ifstat = ifstat;
1281 ether->ctl = ctl;
1282 ether->promiscuous = promiscuous;
1283 ether->multicast = multicast;
1284 ether->arg = ether;
1285
1286 // DEBUG("#l%d: irq %ld port %lx type %s",
1287 // ether->ctlrno, ether->irq, ether->port, ether->type);
1288 // DEBUG(" %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX\n",
1289 // ether->ea[0], ether->ea[1], ether->ea[2],
1290 // ether->ea[3], ether->ea[4], ether->ea[5]);
1291
1292 iunlock(ctlr);
1293 return 0;
1294
1295 abort:
1296 iunlock(ctlr);
1297 free(ctlr);
1298 ether->ctlr = nil;
1299 iprint("wave reset failed\n");
1300 return -1;
1301 }
1302
1303 void
etherwavelanlink(void)1304 etherwavelanlink(void)
1305 {
1306 addethercard("wavelan", reset);
1307 }
1308