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
csr_outs(Ctlr * ctlr,int reg,ushort arg)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
csr_ins(Ctlr * ctlr,int reg)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
csr_ack(Ctlr * ctlr,int ev)62 csr_ack(Ctlr *ctlr, int ev)
63 {
64 csr_outs(ctlr, WR_EvAck, ev);
65 }
66
67 static void
csr_inss(Ctlr * ctlr,int reg,void * dat,int ndat)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
csr_outss(Ctlr * ctlr,int reg,void * dat,int ndat)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
w_intdis(Ctlr * ctlr)99 w_intdis(Ctlr* ctlr)
100 {
101 csr_outs(ctlr, WR_IntEna, 0);
102 csr_ack(ctlr, 0xffff);
103 }
104
105 static void
w_intena(Ctlr * ctlr)106 w_intena(Ctlr* ctlr)
107 {
108 csr_outs(ctlr, WR_IntEna, WEvs);
109 }
110
111 int
w_cmd(Ctlr * ctlr,ushort cmd,ushort arg)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
w_seek(Ctlr * ctlr,ushort id,ushort offset,int chan)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\n");
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
w_inltv(Ctlr * ctlr,Wltv * ltv)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, <v->val, ltv->len-1);
208
209 return 0;
210 }
211
212 static void
w_outltv(Ctlr * ctlr,Wltv * ltv)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
ltv_outs(Ctlr * ctlr,int type,ushort val)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, <v);
230 }
231
232 int
ltv_ins(Ctlr * ctlr,int type)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, <v))
241 return -1;
242 return ltv.val;
243 }
244
245 static void
ltv_outstr(Ctlr * ctlr,int type,char * val)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(<v, 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, <v);
263 }
264
265 static char Unkname[] = "who knows";
266 static char Nilname[] = "card does not tell";
267
268 static char*
ltv_inname(Ctlr * ctlr,int type)269 ltv_inname(Ctlr* ctlr, int type)
270 {
271 static Wltv ltv;
272 int len;
273
274 memset(<v,0,sizeof(ltv));
275 ltv.len = WNameLen/2+2;
276 ltv.type = type;
277 if(w_inltv(ctlr, <v))
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
w_read(Ctlr * ctlr,int type,int off,void * buf,ulong len)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
w_write(Ctlr * ctlr,int type,int off,void * buf,ulong len)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
w_alloc(Ctlr * ctlr,int len)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
w_enable(Ether * ether)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, <v);
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
w_rxdone(Ether * ether)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
w_txstart(Ether * ether)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
w_txdone(Ctlr * ctlr,int sts)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
w_stats(Ctlr * ctlr,int len)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
w_scaninfo(Ether * ether,Ctlr * ctlr,int len)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 = ðer->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
w_info(Ether * ether,Ctlr * ctlr)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, <v, 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
w_scanbs(void * a,uint secs)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
w_intr(Ether * ether)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
w_timer(void * arg)679 w_timer(void* arg)
680 {
681 Ether* ether = (Ether*) arg;
682 Ctlr* ctlr = (Ctlr*)ether->ctlr;
683
684 ctlr->timerproc = up;
685 for(;;){
686 tsleep(&up->sleep, return0, 0, MSperTick);
687 ctlr = (Ctlr*)ether->ctlr;
688 if(ctlr == 0)
689 break;
690 if((ctlr->state & (Attached|Power)) != (Attached|Power))
691 continue;
692 ctlr->ticks++;
693
694 ilock(ctlr);
695
696 // Seems that the card gets frames BUT does
697 // not send the interrupt; this is a problem because
698 // I suspect it runs out of receive buffers and
699 // stops receiving until a transmit watchdog
700 // reenables the card.
701 // The problem is serious because it leads to
702 // poor rtts.
703 // This can be seen clearly by commenting out
704 // the next if and doing a ping: it will stop
705 // receiving (although the icmp replies are being
706 // issued from the remote) after a few seconds.
707 // Of course this `bug' could be because I'm reading
708 // the card frames in the wrong way; due to the
709 // lack of documentation I cannot know.
710
711 if(csr_ins(ctlr, WR_EvSts)&WEvs){
712 ctlr->tickintr++;
713 w_intr(ether);
714 }
715
716 if((ctlr->ticks % 10) == 0) {
717 if(ctlr->txtmout && --ctlr->txtmout == 0){
718 ctlr->nwatchdogs++;
719 w_txdone(ctlr, WTxErrEv);
720 if(w_enable(ether)){
721 DEBUG("wavelan: wdog enable failed\n");
722 }
723 w_txstart(ether);
724 }
725 if((ctlr->ticks % 120) == 0)
726 if(ctlr->txbusy == 0)
727 w_cmd(ctlr, WCmdEnquire, WTyp_Stats);
728 if(ctlr->scanticks > 0)
729 if((ctlr->ticks % ctlr->scanticks) == 0)
730 if(ctlr->txbusy == 0)
731 w_cmd(ctlr, WCmdEnquire, WTyp_Scan);
732 }
733 iunlock(ctlr);
734 }
735 pexit("terminated", 0);
736 }
737
738 void
w_multicast(void * ether,uchar *,int add)739 w_multicast(void *ether, uchar*, int add)
740 {
741 /* BUG: use controller's multicast filter */
742 if (add)
743 w_promiscuous(ether, 1);
744 }
745
746 void
w_attach(Ether * ether)747 w_attach(Ether* ether)
748 {
749 Ctlr* ctlr;
750 char name[64];
751 int rc;
752
753 if(ether->ctlr == 0)
754 return;
755
756 snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
757 ctlr = (Ctlr*) ether->ctlr;
758 if((ctlr->state & Attached) == 0){
759 ilock(ctlr);
760 rc = w_enable(ether);
761 iunlock(ctlr);
762 if(rc == 0){
763 ctlr->state |= Attached;
764 kproc(name, w_timer, ether);
765 } else
766 print("#l%d: enable failed\n",ether->ctlrno);
767 }
768 }
769
770 void
w_detach(Ether * ether)771 w_detach(Ether* ether)
772 {
773 Ctlr* ctlr;
774 char name[64];
775
776 if(ether->ctlr == nil)
777 return;
778
779 snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
780 ctlr = (Ctlr*) ether->ctlr;
781 if(ctlr->state & Attached){
782 ilock(ctlr);
783 w_intdis(ctlr);
784 if(ctlr->timerproc){
785 if(!postnote(ctlr->timerproc, 1, "kill", NExit))
786 print("timerproc note not posted\n");
787 print("w_detach, killing 0x%p\n", ctlr->timerproc);
788 }
789 ctlr->state &= ~Attached;
790 iunlock(ctlr);
791 }
792 ether->ctlr = nil;
793 }
794
795 void
w_power(Ether * ether,int on)796 w_power(Ether* ether, int on)
797 {
798 Ctlr *ctlr;
799
800 ctlr = (Ctlr*) ether->ctlr;
801 ilock(ctlr);
802 iprint("w_power %d\n", on);
803 if(on){
804 if((ctlr->state & Power) == 0){
805 if (wavelanreset(ether, ctlr) < 0){
806 iprint("w_power: reset failed\n");
807 iunlock(ctlr);
808 w_detach(ether);
809 free(ctlr);
810 return;
811 }
812 if(ctlr->state & Attached)
813 w_enable(ether);
814 ctlr->state |= Power;
815 }
816 }else{
817 if(ctlr->state & Power){
818 if(ctlr->state & Attached)
819 w_intdis(ctlr);
820 ctlr->state &= ~Power;
821 }
822 }
823 iunlock(ctlr);
824 }
825
826 #define PRINTSTAT(fmt,val) l += snprint(p+l, READSTR-l, (fmt), (val))
827 #define PRINTSTR(fmt) l += snprint(p+l, READSTR-l, (fmt))
828
829 long
w_ifstat(Ether * ether,void * a,long n,ulong offset)830 w_ifstat(Ether* ether, void* a, long n, ulong offset)
831 {
832 Ctlr *ctlr = (Ctlr*) ether->ctlr;
833 char *k, *p;
834 int i, l, txid;
835
836 ether->oerrs = ctlr->ntxerr;
837 ether->crcs = ctlr->nrxfcserr;
838 ether->frames = 0;
839 ether->buffs = ctlr->nrxdropnobuf;
840 ether->overflows = 0;
841
842 //
843 // Offset must be zero or there's a possibility the
844 // new data won't match the previous read.
845 //
846 if(n == 0 || offset != 0)
847 return 0;
848
849 p = malloc(READSTR);
850 if(p == nil)
851 error(Enomem);
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, <v))
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
parsekey(WKey * key,char * a)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
w_option(Ctlr * ctlr,char * buf,long n)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);
1025 }
1026 else{
1027 memset(ctlr->wantname, 0, sizeof(ctlr->wantname));
1028 strncpy(ctlr->wantname, p, WNameLen);
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);
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
w_ctl(Ether * ether,void * buf,long n)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
w_transmit(Ether * ether)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
w_promiscuous(void * arg,int on)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
w_interrupt(Ureg *,void * arg)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 static void
w_shutdown(Ether * ether)1179 w_shutdown(Ether* ether)
1180 {
1181 Ctlr *ctlr;
1182
1183 ctlr = ether->ctlr;
1184 w_intdis(ctlr);
1185 if(w_cmd(ctlr,WCmdIni,0))
1186 iprint("#l%d: init failed\n", ether->ctlrno);
1187 w_intdis(ctlr);
1188 }
1189
1190 int
wavelanreset(Ether * ether,Ctlr * ctlr)1191 wavelanreset(Ether* ether, Ctlr *ctlr)
1192 {
1193 Wltv ltv;
1194
1195 iprint("wavelanreset, iob 0x%ux\n", ctlr->iob);
1196 w_intdis(ctlr);
1197 if(w_cmd(ctlr,WCmdIni,0)){
1198 iprint("#l%d: init failed\n", ether->ctlrno);
1199 return -1;
1200 }
1201 w_intdis(ctlr);
1202 ltv_outs(ctlr, WTyp_Tick, 8);
1203
1204 ctlr->chan = 0;
1205 ctlr->ptype = WDfltPType;
1206 ctlr->txkey = 0;
1207 ctlr->createibss = 0;
1208 ctlr->keys.len = sizeof(WKey)*WNKeys/2 + 1;
1209 ctlr->keys.type = WTyp_Keys;
1210 if(ctlr->hascrypt = ltv_ins(ctlr, WTyp_HasCrypt))
1211 ctlr->crypt = 1;
1212 *ctlr->netname = *ctlr->wantname = 0;
1213 strcpy(ctlr->nodename, "Plan 9 STA");
1214
1215 ctlr->netname[WNameLen-1] = 0;
1216 ctlr->wantname[WNameLen-1] = 0;
1217 ctlr->nodename[WNameLen-1] =0;
1218
1219 ltv.type = WTyp_Mac;
1220 ltv.len = 4;
1221 if(w_inltv(ctlr, <v)){
1222 iprint("#l%d: unable to read mac addr\n",
1223 ether->ctlrno);
1224 return -1;
1225 }
1226 memmove(ether->ea, ltv.addr, Eaddrlen);
1227
1228 if(ctlr->chan == 0)
1229 ctlr->chan = ltv_ins(ctlr, WTyp_Chan);
1230 ctlr->apdensity = WDfltApDens;
1231 ctlr->rtsthres = WDfltRtsThres;
1232 ctlr->txrate = WDfltTxRate;
1233 ctlr->maxlen = WMaxLen;
1234 ctlr->pmena = 0;
1235 ctlr->pmwait = 100;
1236 ctlr->signal = 1;
1237 ctlr->noise = 1;
1238 ctlr->state |= Power;
1239
1240 // free old Ctlr struct if resetting after suspend
1241 if(ether->ctlr && ether->ctlr != ctlr)
1242 free(ether->ctlr);
1243
1244 // link to ether
1245 ether->ctlr = ctlr;
1246 ether->mbps = 10;
1247 ether->attach = w_attach;
1248 ether->detach = w_detach;
1249 ether->interrupt = w_interrupt;
1250 ether->transmit = w_transmit;
1251 ether->ifstat = w_ifstat;
1252 ether->ctl = w_ctl;
1253 ether->power = w_power;
1254 ether->promiscuous = w_promiscuous;
1255 ether->multicast = w_multicast;
1256 ether->shutdown = w_shutdown;
1257 ether->scanbs = w_scanbs;
1258 ether->arg = ether;
1259
1260 DEBUG("#l%d: irq %d port %lx type %s",
1261 ether->ctlrno, ether->irq, ether->port, ether->type);
1262 DEBUG(" %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux\n",
1263 ether->ea[0], ether->ea[1], ether->ea[2],
1264 ether->ea[3], ether->ea[4], ether->ea[5]);
1265
1266 return 0;
1267 }
1268
1269 char* wavenames[] = {
1270 "WaveLAN/IEEE",
1271 "TrueMobile 1150",
1272 "Instant Wireless ; Network PC CARD",
1273 "Instant Wireless Network PC Card",
1274 "Avaya Wireless PC Card",
1275 "AirLancer MC-11",
1276 "INTERSIL;HFA384x/IEEE;Version 01.02;",
1277 nil,
1278 };
1279