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