FreeBSD/Linux Kernel Cross Reference
sys/bitsy/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 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 #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\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
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
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, <v);
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, <v))
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(<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*
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
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, <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
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 = ð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
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
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 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
739 w_multicast(void*, uchar*, int)
740 {
741 // BUG: to be added.
742 }
743
744 void
745 w_attach(Ether* ether)
746 {
747 Ctlr* ctlr;
748 char name[64];
749 int rc;
750
751 if(ether->ctlr == 0)
752 return;
753
754 snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
755 ctlr = (Ctlr*) ether->ctlr;
756 if((ctlr->state & Attached) == 0){
757 ilock(ctlr);
758 rc = w_enable(ether);
759 iunlock(ctlr);
760 if(rc == 0){
761 ctlr->state |= Attached;
762 kproc(name, w_timer, ether);
763 } else
764 print("#l%d: enable failed\n",ether->ctlrno);
765 }
766 }
767
768 void
769 w_detach(Ether* ether)
770 {
771 Ctlr* ctlr;
772 char name[64];
773
774 if(ether->ctlr == nil)
775 return;
776
777 snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
778 ctlr = (Ctlr*) ether->ctlr;
779 if(ctlr->state & Attached){
780 ilock(ctlr);
781 w_intdis(ctlr);
782 if(ctlr->timerproc){
783 if(!postnote(ctlr->timerproc, 1, "kill", NExit))
784 print("timerproc note not posted\n");
785 print("w_detach, killing 0x%p\n", ctlr->timerproc);
786 }
787 ctlr->state &= ~Attached;
788 iunlock(ctlr);
789 }
790 ether->ctlr = nil;
791 }
792
793 void
794 w_power(Ether* ether, int on)
795 {
796 Ctlr *ctlr;
797
798 ctlr = (Ctlr*) ether->ctlr;
799 ilock(ctlr);
800 iprint("w_power %d\n", on);
801 if(on){
802 if((ctlr->state & Power) == 0){
803 if (wavelanreset(ether, ctlr) < 0){
804 iprint("w_power: reset failed\n");
805 iunlock(ctlr);
806 w_detach(ether);
807 free(ctlr);
808 return;
809 }
810 if(ctlr->state & Attached)
811 w_enable(ether);
812 ctlr->state |= Power;
813 }
814 }else{
815 if(ctlr->state & Power){
816 if(ctlr->state & Attached)
817 w_intdis(ctlr);
818 ctlr->state &= ~Power;
819 }
820 }
821 iunlock(ctlr);
822 }
823
824 #define PRINTSTAT(fmt,val) l += snprint(p+l, READSTR-l, (fmt), (val))
825 #define PRINTSTR(fmt) l += snprint(p+l, READSTR-l, (fmt))
826
827 long
828 w_ifstat(Ether* ether, void* a, long n, ulong offset)
829 {
830 Ctlr *ctlr = (Ctlr*) ether->ctlr;
831 char *k, *p;
832 int i, l, txid;
833
834 ether->oerrs = ctlr->ntxerr;
835 ether->crcs = ctlr->nrxfcserr;
836 ether->frames = 0;
837 ether->buffs = ctlr->nrxdropnobuf;
838 ether->overflows = 0;
839
840 //
841 // Offset must be zero or there's a possibility the
842 // new data won't match the previous read.
843 //
844 if(n == 0 || offset != 0)
845 return 0;
846
847 p = malloc(READSTR);
848 l = 0;
849
850 PRINTSTAT("Signal: %d\n", ctlr->signal-149);
851 PRINTSTAT("Noise: %d\n", ctlr->noise-149);
852 PRINTSTAT("SNR: %ud\n", ctlr->signal-ctlr->noise);
853 PRINTSTAT("Interrupts: %lud\n", ctlr->nints);
854 PRINTSTAT("Double Interrupts: %lud\n", ctlr->ndoubleint);
855 PRINTSTAT("TxPackets: %lud\n", ctlr->ntx);
856 PRINTSTAT("RxPackets: %lud\n", ctlr->nrx);
857 PRINTSTAT("TxErrors: %lud\n", ctlr->ntxerr);
858 PRINTSTAT("RxErrors: %lud\n", ctlr->nrxerr);
859 PRINTSTAT("TxRequests: %lud\n", ctlr->ntxrq);
860 PRINTSTAT("AllocEvs: %lud\n", ctlr->nalloc);
861 PRINTSTAT("InfoEvs: %lud\n", ctlr->ninfo);
862 PRINTSTAT("InfoDrop: %lud\n", ctlr->nidrop);
863 PRINTSTAT("WatchDogs: %lud\n", ctlr->nwatchdogs);
864 PRINTSTAT("Ticks: %ud\n", ctlr->ticks);
865 PRINTSTAT("TickIntr: %ud\n", ctlr->tickintr);
866 k = ((ctlr->state & Attached) ? "attached" : "not attached");
867 PRINTSTAT("Card %s", k);
868 k = ((ctlr->state & Power) ? "on" : "off");
869 PRINTSTAT(", power %s", k);
870 k = ((ctlr->txbusy)? ", txbusy" : "");
871 PRINTSTAT("%s\n", k);
872
873 if(ctlr->hascrypt){
874 PRINTSTR("Keys: ");
875 for (i = 0; i < WNKeys; i++){
876 if(ctlr->keys.keys[i].len == 0)
877 PRINTSTR("none ");
878 else if(SEEKEYS == 0)
879 PRINTSTR("set ");
880 else
881 PRINTSTAT("%s ", ctlr->keys.keys[i].dat);
882 }
883 PRINTSTR("\n");
884 }
885
886 // real card stats
887 ilock(ctlr);
888 PRINTSTR("\nCard stats: \n");
889 PRINTSTAT("Status: %ux\n", csr_ins(ctlr, WR_Sts));
890 PRINTSTAT("Event status: %ux\n", csr_ins(ctlr, WR_EvSts));
891 i = ltv_ins(ctlr, WTyp_Ptype);
892 PRINTSTAT("Port type: %d\n", i);
893 PRINTSTAT("Transmit rate: %d\n", ltv_ins(ctlr, WTyp_TxRate));
894 PRINTSTAT("Current Transmit rate: %d\n",
895 ltv_ins(ctlr, WTyp_CurTxRate));
896 PRINTSTAT("Channel: %d\n", ltv_ins(ctlr, WTyp_Chan));
897 PRINTSTAT("AP density: %d\n", ltv_ins(ctlr, WTyp_ApDens));
898 PRINTSTAT("Promiscuous mode: %d\n", ltv_ins(ctlr, WTyp_Prom));
899 if(i == WPTypeAdHoc)
900 PRINTSTAT("SSID name: %s\n", ltv_inname(ctlr, WTyp_NetName));
901 else {
902 Wltv ltv;
903 PRINTSTAT("Current name: %s\n", ltv_inname(ctlr, WTyp_CurName));
904 ltv.type = WTyp_BaseID;
905 ltv.len = 4;
906 if(w_inltv(ctlr, <v))
907 print("#l%d: unable to read base station mac addr\n", ether->ctlrno);
908 l += snprint(p+l, READSTR-l, "Base station: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
909 ltv.addr[0], ltv.addr[1], ltv.addr[2], ltv.addr[3], ltv.addr[4], ltv.addr[5]);
910 }
911 PRINTSTAT("Net name: %s\n", ltv_inname(ctlr, WTyp_WantName));
912 PRINTSTAT("Node name: %s\n", ltv_inname(ctlr, WTyp_NodeName));
913 if(ltv_ins(ctlr, WTyp_HasCrypt) == 0)
914 PRINTSTR("WEP: not supported\n");
915 else {
916 if(ltv_ins(ctlr, WTyp_Crypt) == 0)
917 PRINTSTR("WEP: disabled\n");
918 else{
919 PRINTSTR("WEP: enabled\n");
920 k = ((ctlr->xclear)? "excluded": "included");
921 PRINTSTAT("Clear packets: %s\n", k);
922 txid = ltv_ins(ctlr, WTyp_TxKey);
923 PRINTSTAT("Transmit key id: %d\n", txid);
924 }
925 }
926 iunlock(ctlr);
927
928 PRINTSTAT("ntxuframes: %lud\n", ctlr->ntxuframes);
929 PRINTSTAT("ntxmframes: %lud\n", ctlr->ntxmframes);
930 PRINTSTAT("ntxfrags: %lud\n", ctlr->ntxfrags);
931 PRINTSTAT("ntxubytes: %lud\n", ctlr->ntxubytes);
932 PRINTSTAT("ntxmbytes: %lud\n", ctlr->ntxmbytes);
933 PRINTSTAT("ntxdeferred: %lud\n", ctlr->ntxdeferred);
934 PRINTSTAT("ntxsretries: %lud\n", ctlr->ntxsretries);
935 PRINTSTAT("ntxmultiretries: %lud\n", ctlr->ntxmultiretries);
936 PRINTSTAT("ntxretrylimit: %lud\n", ctlr->ntxretrylimit);
937 PRINTSTAT("ntxdiscards: %lud\n", ctlr->ntxdiscards);
938 PRINTSTAT("nrxuframes: %lud\n", ctlr->nrxuframes);
939 PRINTSTAT("nrxmframes: %lud\n", ctlr->nrxmframes);
940 PRINTSTAT("nrxfrags: %lud\n", ctlr->nrxfrags);
941 PRINTSTAT("nrxubytes: %lud\n", ctlr->nrxubytes);
942 PRINTSTAT("nrxmbytes: %lud\n", ctlr->nrxmbytes);
943 PRINTSTAT("nrxfcserr: %lud\n", ctlr->nrxfcserr);
944 PRINTSTAT("nrxdropnobuf: %lud\n", ctlr->nrxdropnobuf);
945 PRINTSTAT("nrxdropnosa: %lud\n", ctlr->nrxdropnosa);
946 PRINTSTAT("nrxcantdecrypt: %lud\n", ctlr->nrxcantdecrypt);
947 PRINTSTAT("nrxmsgfrag: %lud\n", ctlr->nrxmsgfrag);
948 PRINTSTAT("nrxmsgbadfrag: %lud\n", ctlr->nrxmsgbadfrag);
949 USED(l);
950 n = readstr(offset, a, n, p);
951 free(p);
952 return n;
953 }
954 #undef PRINTSTR
955 #undef PRINTSTAT
956
957 int
958 w_option(Ctlr* ctlr, char* buf, long n)
959 {
960 char *p;
961 int i, r;
962 WKey *key;
963 Cmdbuf *cb;
964
965 r = 0;
966
967 cb = parsecmd(buf, n);
968 if(cb->nf < 2)
969 r = -1;
970 else if(cistrcmp(cb->f[0], "essid") == 0){
971 if(cistrcmp(cb->f[1],"default") == 0)
972 p = "";
973 else
974 p = cb->f[1];
975 if(ctlr->ptype == WPTypeAdHoc){
976 memset(ctlr->netname, 0, sizeof(ctlr->netname));
977 strncpy(ctlr->netname, p, WNameLen);
978 }
979 else{
980 memset(ctlr->wantname, 0, sizeof(ctlr->wantname));
981 strncpy(ctlr->wantname, p, WNameLen);
982 }
983 }
984 else if(cistrcmp(cb->f[0], "station") == 0){
985 memset(ctlr->nodename, 0, sizeof(ctlr->nodename));
986 strncpy(ctlr->nodename, cb->f[1], WNameLen);
987 }
988 else if(cistrcmp(cb->f[0], "channel") == 0){
989 if((i = atoi(cb->f[1])) >= 1 && i <= 16)
990 ctlr->chan = i;
991 else
992 r = -1;
993 }
994 else if(cistrcmp(cb->f[0], "mode") == 0){
995 if(cistrcmp(cb->f[1], "managed") == 0)
996 ctlr->ptype = WPTypeManaged;
997 else if(cistrcmp(cb->f[1], "wds") == 0)
998 ctlr->ptype = WPTypeWDS;
999 else if(cistrcmp(cb->f[1], "adhoc") == 0)
1000 ctlr->ptype = WPTypeAdHoc;
1001 else if((i = atoi(cb->f[1])) >= 1 && i <= 3)
1002 ctlr->ptype = i;
1003 else
1004 r = -1;
1005 }
1006 else if(cistrcmp(cb->f[0], "ibss") == 0){
1007 if(cistrcmp(cb->f[1], "on") == 0)
1008 ctlr->createibss = 1;
1009 else
1010 ctlr->createibss = 0;
1011 }
1012 else if(cistrcmp(cb->f[0], "crypt") == 0){
1013 if(cistrcmp(cb->f[1], "off") == 0)
1014 ctlr->crypt = 0;
1015 else if(cistrcmp(cb->f[1], "on") == 0 && ctlr->hascrypt)
1016 ctlr->crypt = 1;
1017 else
1018 r = -1;
1019 }
1020 else if(cistrcmp(cb->f[0], "clear") == 0){
1021 if(cistrcmp(cb->f[1], "on") == 0)
1022 ctlr->xclear = 0;
1023 else if(cistrcmp(cb->f[1], "off") == 0 && ctlr->hascrypt)
1024 ctlr->xclear = 1;
1025 else
1026 r = -1;
1027 }
1028 else if(cistrncmp(cb->f[0], "key", 3) == 0){
1029 if((i = atoi(cb->f[0]+3)) >= 1 && i <= WNKeys){
1030 ctlr->txkey = i-1;
1031 key = &ctlr->keys.keys[ctlr->txkey];
1032 key->len = strlen(cb->f[1]);
1033 if(key->len > WKeyLen)
1034 key->len = WKeyLen;
1035 memset(key->dat, 0, sizeof(key->dat));
1036 memmove(key->dat, cb->f[1], key->len);
1037 }
1038 else
1039 r = -1;
1040 }
1041 else if(cistrcmp(cb->f[0], "txkey") == 0){
1042 if((i = atoi(cb->f[1])) >= 1 && i <= WNKeys)
1043 ctlr->txkey = i-1;
1044 else
1045 r = -1;
1046 }
1047 else if(cistrcmp(cb->f[0], "pm") == 0){
1048 if(cistrcmp(cb->f[1], "off") == 0)
1049 ctlr->pmena = 0;
1050 else if(cistrcmp(cb->f[1], "on") == 0){
1051 ctlr->pmena = 1;
1052 if(cb->nf == 3){
1053 i = atoi(cb->f[2]);
1054 // check range here? what are the units?
1055 ctlr->pmwait = i;
1056 }
1057 }
1058 else
1059 r = -1;
1060 }
1061 else
1062 r = -2;
1063 free(cb);
1064
1065 return r;
1066 }
1067
1068 long
1069 w_ctl(Ether* ether, void* buf, long n)
1070 {
1071 Ctlr *ctlr;
1072
1073 if((ctlr = ether->ctlr) == nil)
1074 error(Enonexist);
1075 if((ctlr->state & Attached) == 0)
1076 error(Eshutdown);
1077
1078 ilock(ctlr);
1079 if(w_option(ctlr, buf, n)){
1080 iunlock(ctlr);
1081 error(Ebadctl);
1082 }
1083 if(ctlr->txbusy)
1084 w_txdone(ctlr, WTxErrEv);
1085 w_enable(ether);
1086 w_txstart(ether);
1087 iunlock(ctlr);
1088
1089 return n;
1090 }
1091
1092 void
1093 w_transmit(Ether* ether)
1094 {
1095 Ctlr* ctlr = ether->ctlr;
1096
1097 if(ctlr == 0)
1098 return;
1099
1100 ilock(ctlr);
1101 ctlr->ntxrq++;
1102 w_txstart(ether);
1103 iunlock(ctlr);
1104 }
1105
1106 void
1107 w_promiscuous(void* arg, int on)
1108 {
1109 Ether* ether = (Ether*)arg;
1110 Ctlr* ctlr = ether->ctlr;
1111
1112 if(ctlr == nil)
1113 error("card not found");
1114 if((ctlr->state & Attached) == 0)
1115 error("card not attached");
1116 ilock(ctlr);
1117 ltv_outs(ctlr, WTyp_Prom, (on?1:0));
1118 iunlock(ctlr);
1119 }
1120
1121 void
1122 w_interrupt(Ureg* ,void* arg)
1123 {
1124 Ether* ether = (Ether*) arg;
1125 Ctlr* ctlr = (Ctlr*) ether->ctlr;
1126
1127 if(ctlr == 0)
1128 return;
1129 ilock(ctlr);
1130 ctlr->nints++;
1131 w_intr(ether);
1132 iunlock(ctlr);
1133 }
1134
1135 int
1136 wavelanreset(Ether* ether, Ctlr *ctlr)
1137 {
1138 Wltv ltv;
1139
1140 iprint("wavelanreset, iob 0x%ux\n", ctlr->iob);
1141 w_intdis(ctlr);
1142 if(w_cmd(ctlr,WCmdIni,0)){
1143 iprint("#l%d: init failed\n", ether->ctlrno);
1144 return -1;
1145 }
1146 w_intdis(ctlr);
1147 ltv_outs(ctlr, WTyp_Tick, 8);
1148
1149 ctlr->chan = 0;
1150 ctlr->ptype = WDfltPType;
1151 ctlr->txkey = 0;
1152 ctlr->createibss = 0;
1153 ctlr->keys.len = sizeof(WKey)*WNKeys/2 + 1;
1154 ctlr->keys.type = WTyp_Keys;
1155 if(ctlr->hascrypt = ltv_ins(ctlr, WTyp_HasCrypt))
1156 ctlr->crypt = 1;
1157 *ctlr->netname = *ctlr->wantname = 0;
1158 strcpy(ctlr->nodename, "Plan 9 STA");
1159
1160 ctlr->netname[WNameLen-1] = 0;
1161 ctlr->wantname[WNameLen-1] = 0;
1162 ctlr->nodename[WNameLen-1] =0;
1163
1164 ltv.type = WTyp_Mac;
1165 ltv.len = 4;
1166 if(w_inltv(ctlr, <v)){
1167 iprint("#l%d: unable to read mac addr\n",
1168 ether->ctlrno);
1169 return -1;
1170 }
1171 memmove(ether->ea, ltv.addr, Eaddrlen);
1172
1173 if(ctlr->chan == 0)
1174 ctlr->chan = ltv_ins(ctlr, WTyp_Chan);
1175 ctlr->apdensity = WDfltApDens;
1176 ctlr->rtsthres = WDfltRtsThres;
1177 ctlr->txrate = WDfltTxRate;
1178 ctlr->maxlen = WMaxLen;
1179 ctlr->pmena = 0;
1180 ctlr->pmwait = 100;
1181 ctlr->signal = 1;
1182 ctlr->noise = 1;
1183 ctlr->state |= Power;
1184
1185 // free old Ctlr struct if resetting after suspend
1186 if(ether->ctlr && ether->ctlr != ctlr)
1187 free(ether->ctlr);
1188
1189 // link to ether
1190 ether->ctlr = ctlr;
1191 ether->mbps = 10;
1192 ether->attach = w_attach;
1193 ether->detach = w_detach;
1194 ether->interrupt = w_interrupt;
1195 ether->transmit = w_transmit;
1196 ether->ifstat = w_ifstat;
1197 ether->ctl = w_ctl;
1198 ether->power = w_power;
1199 ether->promiscuous = w_promiscuous;
1200 ether->multicast = w_multicast;
1201 ether->scanbs = w_scanbs;
1202 ether->arg = ether;
1203
1204 DEBUG("#l%d: irq %lud port %lx type %s",
1205 ether->ctlrno, ether->intnum, ether->ports[0].port, ether->type);
1206 DEBUG(" %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux\n",
1207 ether->ea[0], ether->ea[1], ether->ea[2],
1208 ether->ea[3], ether->ea[4], ether->ea[5]);
1209
1210 return 0;
1211 }
1212
1213 char* wavenames[] = {
1214 "WaveLAN/IEEE",
1215 "TrueMobile 1150",
1216 "Instant Wireless ; Network PC CARD",
1217 "Instant Wireless Network PC Card",
1218 "Avaya Wireless PC Card",
1219 "AirLancer MC-11",
1220 nil,
1221 };
Cache object: c9ed002a447c151a7e2128840ddd29b0
|