FreeBSD/Linux Kernel Cross Reference
sys/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\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 *ether, uchar*, int add)
740 {
741 /* BUG: use controller's multicast filter */
742 if (add)
743 w_promiscuous(ether, 1);
744 }
745
746 void
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
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
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
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 l = 0;
851
852 PRINTSTAT("Signal: %d\n", ctlr->signal-149);
853 PRINTSTAT("Noise: %d\n", ctlr->noise-149);
854 PRINTSTAT("SNR: %ud\n", ctlr->signal-ctlr->noise);
855 PRINTSTAT("Interrupts: %lud\n", ctlr->nints);
856 PRINTSTAT("Double Interrupts: %lud\n", ctlr->ndoubleint);
857 PRINTSTAT("TxPackets: %lud\n", ctlr->ntx);
858 PRINTSTAT("RxPackets: %lud\n", ctlr->nrx);
859 PRINTSTAT("TxErrors: %lud\n", ctlr->ntxerr);
860 PRINTSTAT("RxErrors: %lud\n", ctlr->nrxerr);
861 PRINTSTAT("TxRequests: %lud\n", ctlr->ntxrq);
862 PRINTSTAT("AllocEvs: %lud\n", ctlr->nalloc);
863 PRINTSTAT("InfoEvs: %lud\n", ctlr->ninfo);
864 PRINTSTAT("InfoDrop: %lud\n", ctlr->nidrop);
865 PRINTSTAT("WatchDogs: %lud\n", ctlr->nwatchdogs);
866 PRINTSTAT("Ticks: %ud\n", ctlr->ticks);
867 PRINTSTAT("TickIntr: %ud\n", ctlr->tickintr);
868 k = ((ctlr->state & Attached) ? "attached" : "not attached");
869 PRINTSTAT("Card %s", k);
870 k = ((ctlr->state & Power) ? "on" : "off");
871 PRINTSTAT(", power %s", k);
872 k = ((ctlr->txbusy)? ", txbusy" : "");
873 PRINTSTAT("%s\n", k);
874
875 if(ctlr->hascrypt){
876 PRINTSTR("Keys: ");
877 for (i = 0; i < WNKeys; i++){
878 if(ctlr->keys.keys[i].len == 0)
879 PRINTSTR("none ");
880 else if(SEEKEYS == 0)
881 PRINTSTR("set ");
882 else
883 PRINTSTAT("%s ", ctlr->keys.keys[i].dat);
884 }
885 PRINTSTR("\n");
886 }
887
888 // real card stats
889 ilock(ctlr);
890 PRINTSTR("\nCard stats: \n");
891 PRINTSTAT("Status: %ux\n", csr_ins(ctlr, WR_Sts));
892 PRINTSTAT("Event status: %ux\n", csr_ins(ctlr, WR_EvSts));
893 i = ltv_ins(ctlr, WTyp_Ptype);
894 PRINTSTAT("Port type: %d\n", i);
895 PRINTSTAT("Transmit rate: %d\n", ltv_ins(ctlr, WTyp_TxRate));
896 PRINTSTAT("Current Transmit rate: %d\n",
897 ltv_ins(ctlr, WTyp_CurTxRate));
898 PRINTSTAT("Channel: %d\n", ltv_ins(ctlr, WTyp_Chan));
899 PRINTSTAT("AP density: %d\n", ltv_ins(ctlr, WTyp_ApDens));
900 PRINTSTAT("Promiscuous mode: %d\n", ltv_ins(ctlr, WTyp_Prom));
901 if(i == WPTypeAdHoc)
902 PRINTSTAT("SSID name: %s\n", ltv_inname(ctlr, WTyp_NetName));
903 else {
904 Wltv ltv;
905 PRINTSTAT("Current name: %s\n", ltv_inname(ctlr, WTyp_CurName));
906 ltv.type = WTyp_BaseID;
907 ltv.len = 4;
908 if(w_inltv(ctlr, <v))
909 print("#l%d: unable to read base station mac addr\n", ether->ctlrno);
910 l += snprint(p+l, READSTR-l, "Base station: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
911 ltv.addr[0], ltv.addr[1], ltv.addr[2], ltv.addr[3], ltv.addr[4], ltv.addr[5]);
912 }
913 PRINTSTAT("Net name: %s\n", ltv_inname(ctlr, WTyp_WantName));
914 PRINTSTAT("Node name: %s\n", ltv_inname(ctlr, WTyp_NodeName));
915 if(ltv_ins(ctlr, WTyp_HasCrypt) == 0)
916 PRINTSTR("WEP: not supported\n");
917 else {
918 if(ltv_ins(ctlr, WTyp_Crypt) == 0)
919 PRINTSTR("WEP: disabled\n");
920 else{
921 PRINTSTR("WEP: enabled\n");
922 k = ((ctlr->xclear)? "excluded": "included");
923 PRINTSTAT("Clear packets: %s\n", k);
924 txid = ltv_ins(ctlr, WTyp_TxKey);
925 PRINTSTAT("Transmit key id: %d\n", txid);
926 }
927 }
928 iunlock(ctlr);
929
930 PRINTSTAT("ntxuframes: %lud\n", ctlr->ntxuframes);
931 PRINTSTAT("ntxmframes: %lud\n", ctlr->ntxmframes);
932 PRINTSTAT("ntxfrags: %lud\n", ctlr->ntxfrags);
933 PRINTSTAT("ntxubytes: %lud\n", ctlr->ntxubytes);
934 PRINTSTAT("ntxmbytes: %lud\n", ctlr->ntxmbytes);
935 PRINTSTAT("ntxdeferred: %lud\n", ctlr->ntxdeferred);
936 PRINTSTAT("ntxsretries: %lud\n", ctlr->ntxsretries);
937 PRINTSTAT("ntxmultiretries: %lud\n", ctlr->ntxmultiretries);
938 PRINTSTAT("ntxretrylimit: %lud\n", ctlr->ntxretrylimit);
939 PRINTSTAT("ntxdiscards: %lud\n", ctlr->ntxdiscards);
940 PRINTSTAT("nrxuframes: %lud\n", ctlr->nrxuframes);
941 PRINTSTAT("nrxmframes: %lud\n", ctlr->nrxmframes);
942 PRINTSTAT("nrxfrags: %lud\n", ctlr->nrxfrags);
943 PRINTSTAT("nrxubytes: %lud\n", ctlr->nrxubytes);
944 PRINTSTAT("nrxmbytes: %lud\n", ctlr->nrxmbytes);
945 PRINTSTAT("nrxfcserr: %lud\n", ctlr->nrxfcserr);
946 PRINTSTAT("nrxdropnobuf: %lud\n", ctlr->nrxdropnobuf);
947 PRINTSTAT("nrxdropnosa: %lud\n", ctlr->nrxdropnosa);
948 PRINTSTAT("nrxcantdecrypt: %lud\n", ctlr->nrxcantdecrypt);
949 PRINTSTAT("nrxmsgfrag: %lud\n", ctlr->nrxmsgfrag);
950 PRINTSTAT("nrxmsgbadfrag: %lud\n", ctlr->nrxmsgbadfrag);
951 USED(l);
952 n = readstr(offset, a, n, p);
953 free(p);
954 return n;
955 }
956 #undef PRINTSTR
957 #undef PRINTSTAT
958
959 static int
960 parsekey(WKey* key, char* a)
961 {
962 int i, k, len, n;
963 char buf[WMaxKeyLen];
964
965 len = strlen(a);
966 if(len == WMinKeyLen || len == WMaxKeyLen){
967 memset(key->dat, 0, sizeof(key->dat));
968 memmove(key->dat, a, len);
969 key->len = len;
970
971 return 0;
972 }
973 else if(len == WMinKeyLen*2 || len == WMaxKeyLen*2){
974 k = 0;
975 for(i = 0; i < len; i++){
976 if(*a >= '' && *a <= '9')
977 n = *a++ - '';
978 else if(*a >= 'a' && *a <= 'f')
979 n = *a++ - 'a' + 10;
980 else if(*a >= 'A' && *a <= 'F')
981 n = *a++ - 'A' + 10;
982 else
983 return -1;
984
985 if(i & 1){
986 buf[k] |= n;
987 k++;
988 }
989 else
990 buf[k] = n<<4;
991 }
992
993 memset(key->dat, 0, sizeof(key->dat));
994 memmove(key->dat, buf, k);
995 key->len = k;
996
997 return 0;
998 }
999
1000 return -1;
1001 }
1002
1003 int
1004 w_option(Ctlr* ctlr, char* buf, long n)
1005 {
1006 char *p;
1007 int i, r;
1008 Cmdbuf *cb;
1009
1010 r = 0;
1011
1012 cb = parsecmd(buf, n);
1013 if(cb->nf < 2)
1014 r = -1;
1015 else if(cistrcmp(cb->f[0], "essid") == 0){
1016 if(cistrcmp(cb->f[1],"default") == 0)
1017 p = "";
1018 else
1019 p = cb->f[1];
1020 if(ctlr->ptype == WPTypeAdHoc){
1021 memset(ctlr->netname, 0, sizeof(ctlr->netname));
1022 strncpy(ctlr->netname, p, WNameLen);
1023 }
1024 else{
1025 memset(ctlr->wantname, 0, sizeof(ctlr->wantname));
1026 strncpy(ctlr->wantname, p, WNameLen);
1027 }
1028 }
1029 else if(cistrcmp(cb->f[0], "station") == 0){
1030 memset(ctlr->nodename, 0, sizeof(ctlr->nodename));
1031 strncpy(ctlr->nodename, cb->f[1], WNameLen);
1032 }
1033 else if(cistrcmp(cb->f[0], "channel") == 0){
1034 if((i = atoi(cb->f[1])) >= 1 && i <= 16)
1035 ctlr->chan = i;
1036 else
1037 r = -1;
1038 }
1039 else if(cistrcmp(cb->f[0], "mode") == 0){
1040 if(cistrcmp(cb->f[1], "managed") == 0)
1041 ctlr->ptype = WPTypeManaged;
1042 else if(cistrcmp(cb->f[1], "wds") == 0)
1043 ctlr->ptype = WPTypeWDS;
1044 else if(cistrcmp(cb->f[1], "adhoc") == 0)
1045 ctlr->ptype = WPTypeAdHoc;
1046 else if((i = atoi(cb->f[1])) >= 0 && i <= 3)
1047 ctlr->ptype = i;
1048 else
1049 r = -1;
1050 }
1051 else if(cistrcmp(cb->f[0], "ibss") == 0){
1052 if(cistrcmp(cb->f[1], "on") == 0)
1053 ctlr->createibss = 1;
1054 else
1055 ctlr->createibss = 0;
1056 }
1057 else if(cistrcmp(cb->f[0], "crypt") == 0){
1058 if(cistrcmp(cb->f[1], "off") == 0)
1059 ctlr->crypt = 0;
1060 else if(cistrcmp(cb->f[1], "on") == 0 && ctlr->hascrypt)
1061 ctlr->crypt = 1;
1062 else
1063 r = -1;
1064 }
1065 else if(cistrcmp(cb->f[0], "clear") == 0){
1066 if(cistrcmp(cb->f[1], "on") == 0)
1067 ctlr->xclear = 0;
1068 else if(cistrcmp(cb->f[1], "off") == 0 && ctlr->hascrypt)
1069 ctlr->xclear = 1;
1070 else
1071 r = -1;
1072 }
1073 else if(cistrncmp(cb->f[0], "key", 3) == 0){
1074 if((i = atoi(cb->f[0]+3)) >= 1 && i <= WNKeys){
1075 ctlr->txkey = i-1;
1076 if(parsekey(&ctlr->keys.keys[ctlr->txkey], cb->f[1]))
1077 r = -1;
1078 }
1079 else
1080 r = -1;
1081 }
1082 else if(cistrcmp(cb->f[0], "txkey") == 0){
1083 if((i = atoi(cb->f[1])) >= 1 && i <= WNKeys)
1084 ctlr->txkey = i-1;
1085 else
1086 r = -1;
1087 }
1088 else if(cistrcmp(cb->f[0], "pm") == 0){
1089 if(cistrcmp(cb->f[1], "off") == 0)
1090 ctlr->pmena = 0;
1091 else if(cistrcmp(cb->f[1], "on") == 0){
1092 ctlr->pmena = 1;
1093 if(cb->nf == 3){
1094 i = atoi(cb->f[2]);
1095 // check range here? what are the units?
1096 ctlr->pmwait = i;
1097 }
1098 }
1099 else
1100 r = -1;
1101 }
1102 else
1103 r = -2;
1104 free(cb);
1105
1106 return r;
1107 }
1108
1109 long
1110 w_ctl(Ether* ether, void* buf, long n)
1111 {
1112 Ctlr *ctlr;
1113
1114 if((ctlr = ether->ctlr) == nil)
1115 error(Enonexist);
1116 if((ctlr->state & Attached) == 0)
1117 error(Eshutdown);
1118
1119 ilock(ctlr);
1120 if(w_option(ctlr, buf, n)){
1121 iunlock(ctlr);
1122 error(Ebadctl);
1123 }
1124 if(ctlr->txbusy)
1125 w_txdone(ctlr, WTxErrEv);
1126 w_enable(ether);
1127 w_txstart(ether);
1128 iunlock(ctlr);
1129
1130 return n;
1131 }
1132
1133 void
1134 w_transmit(Ether* ether)
1135 {
1136 Ctlr* ctlr = ether->ctlr;
1137
1138 if(ctlr == 0)
1139 return;
1140
1141 ilock(ctlr);
1142 ctlr->ntxrq++;
1143 w_txstart(ether);
1144 iunlock(ctlr);
1145 }
1146
1147 void
1148 w_promiscuous(void* arg, int on)
1149 {
1150 Ether* ether = (Ether*)arg;
1151 Ctlr* ctlr = ether->ctlr;
1152
1153 if(ctlr == nil)
1154 error("card not found");
1155 if((ctlr->state & Attached) == 0)
1156 error("card not attached");
1157 ilock(ctlr);
1158 ltv_outs(ctlr, WTyp_Prom, (on?1:0));
1159 iunlock(ctlr);
1160 }
1161
1162 void
1163 w_interrupt(Ureg* ,void* arg)
1164 {
1165 Ether* ether = (Ether*) arg;
1166 Ctlr* ctlr = (Ctlr*) ether->ctlr;
1167
1168 if(ctlr == 0)
1169 return;
1170 ilock(ctlr);
1171 ctlr->nints++;
1172 w_intr(ether);
1173 iunlock(ctlr);
1174 }
1175
1176 int
1177 wavelanreset(Ether* ether, Ctlr *ctlr)
1178 {
1179 Wltv ltv;
1180
1181 iprint("wavelanreset, iob 0x%ux\n", ctlr->iob);
1182 w_intdis(ctlr);
1183 if(w_cmd(ctlr,WCmdIni,0)){
1184 iprint("#l%d: init failed\n", ether->ctlrno);
1185 return -1;
1186 }
1187 w_intdis(ctlr);
1188 ltv_outs(ctlr, WTyp_Tick, 8);
1189
1190 ctlr->chan = 0;
1191 ctlr->ptype = WDfltPType;
1192 ctlr->txkey = 0;
1193 ctlr->createibss = 0;
1194 ctlr->keys.len = sizeof(WKey)*WNKeys/2 + 1;
1195 ctlr->keys.type = WTyp_Keys;
1196 if(ctlr->hascrypt = ltv_ins(ctlr, WTyp_HasCrypt))
1197 ctlr->crypt = 1;
1198 *ctlr->netname = *ctlr->wantname = 0;
1199 strcpy(ctlr->nodename, "Plan 9 STA");
1200
1201 ctlr->netname[WNameLen-1] = 0;
1202 ctlr->wantname[WNameLen-1] = 0;
1203 ctlr->nodename[WNameLen-1] =0;
1204
1205 ltv.type = WTyp_Mac;
1206 ltv.len = 4;
1207 if(w_inltv(ctlr, <v)){
1208 iprint("#l%d: unable to read mac addr\n",
1209 ether->ctlrno);
1210 return -1;
1211 }
1212 memmove(ether->ea, ltv.addr, Eaddrlen);
1213
1214 if(ctlr->chan == 0)
1215 ctlr->chan = ltv_ins(ctlr, WTyp_Chan);
1216 ctlr->apdensity = WDfltApDens;
1217 ctlr->rtsthres = WDfltRtsThres;
1218 ctlr->txrate = WDfltTxRate;
1219 ctlr->maxlen = WMaxLen;
1220 ctlr->pmena = 0;
1221 ctlr->pmwait = 100;
1222 ctlr->signal = 1;
1223 ctlr->noise = 1;
1224 ctlr->state |= Power;
1225
1226 // free old Ctlr struct if resetting after suspend
1227 if(ether->ctlr && ether->ctlr != ctlr)
1228 free(ether->ctlr);
1229
1230 // link to ether
1231 ether->ctlr = ctlr;
1232 ether->mbps = 10;
1233 ether->attach = w_attach;
1234 ether->detach = w_detach;
1235 ether->interrupt = w_interrupt;
1236 ether->transmit = w_transmit;
1237 ether->ifstat = w_ifstat;
1238 ether->ctl = w_ctl;
1239 ether->power = w_power;
1240 ether->promiscuous = w_promiscuous;
1241 ether->multicast = w_multicast;
1242 ether->scanbs = w_scanbs;
1243 ether->arg = ether;
1244
1245 DEBUG("#l%d: irq %d port %lx type %s",
1246 ether->ctlrno, ether->irq, ether->port, ether->type);
1247 DEBUG(" %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux\n",
1248 ether->ea[0], ether->ea[1], ether->ea[2],
1249 ether->ea[3], ether->ea[4], ether->ea[5]);
1250
1251 return 0;
1252 }
1253
1254 char* wavenames[] = {
1255 "WaveLAN/IEEE",
1256 "TrueMobile 1150",
1257 "Instant Wireless ; Network PC CARD",
1258 "Instant Wireless Network PC Card",
1259 "Avaya Wireless PC Card",
1260 "AirLancer MC-11",
1261 "INTERSIL;HFA384x/IEEE;Version 01.02;",
1262 nil,
1263 };
Cache object: 2fa1e20f5d258a26471df762a9603cbe
|