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'.
7 Has been used with the card plugged in during all up time.
8 no cards removals/insertions yet.
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.
14 BUGS: check endian, alignment and mem/io issues;
15 receive watchdog interrupts.
16 TODO: automatic power management;
21 #include "../port/lib.h"
26 #include "../port/error.h"
27 #include "../port/netif.h"
28 #include "../port/etherif.h"
34 MSperTick= 50, /* ms between ticks of kproc */
38 * When we're using a PCI device and memory-mapped I/O,
39 * the registers are spaced out as though each takes 32 bits,
40 * even though they are only 16-bit registers. Thus,
41 * ctlr->mmb[reg] is the right way to access register reg,
42 * even though a priori you'd expect to use ctlr->mmb[reg/2].
45 csr_outs(Ctlr *ctlr, int reg, ushort arg)
50 outs(ctlr->iob+reg, arg);
54 csr_ins(Ctlr *ctlr, int reg)
57 return ctlr->mmb[reg];
59 return ins(ctlr->iob+reg);
63 csr_ack(Ctlr *ctlr, int ev)
65 csr_outs(ctlr, WR_EvAck, ev);
69 csr_inss(Ctlr *ctlr, int reg, void *dat, int ndat)
79 inss(ctlr->iob+reg, dat, ndat);
83 csr_outss(Ctlr *ctlr, int reg, void *dat, int ndat)
93 outss(ctlr->iob+reg, dat, ndat);
96 // w_... routines do not ilock the Ctlr and should
102 csr_outs(ctlr, WR_IntEna, 0);
103 csr_ack(ctlr, 0xffff);
109 csr_outs(ctlr, WR_IntEna, WEvs);
113 w_cmd(Ctlr *ctlr, ushort cmd, ushort arg)
117 for(i=0; i<WTmOut; i++)
118 if((csr_ins(ctlr, WR_Cmd)&WCmdBusy) == 0)
121 print("#l%d: issuing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_Cmd));
125 csr_outs(ctlr, WR_Parm0, arg);
126 csr_outs(ctlr, WR_Cmd, cmd);
128 for(i=0; i<WTmOut; i++)
129 if(csr_ins(ctlr, WR_EvSts)&WCmdEv)
133 * WCmdIni can take a really long time.
135 enum { IniTmOut = 2000 };
136 for(i=0; i<IniTmOut; i++){
137 if(csr_ins(ctlr, WR_EvSts)&WCmdEv)
142 if(0) print("#l%d: long cmd %.4ux %d\n", ctlr->ctlrno, cmd, i);
144 print("#l%d: execing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_EvSts));
148 rc = csr_ins(ctlr, WR_Sts);
149 csr_ack(ctlr, WCmdEv);
151 if((rc&WCmdMsk) != (cmd&WCmdMsk)){
152 print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc);
157 * Don't print; this happens on every WCmdAccWr for some reason.
159 if(0) print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc);
166 w_seek(Ctlr* ctlr, ushort id, ushort offset, int chan)
169 static ushort sel[] = { WR_Sel0, WR_Sel1 };
170 static ushort off[] = { WR_Off0, WR_Off1 };
172 if(chan != 0 && chan != 1)
173 panic("wavelan: bad chan");
174 csr_outs(ctlr, sel[chan], id);
175 csr_outs(ctlr, off[chan], offset);
176 for (i=0; i<WTmOut; i++){
177 rc = csr_ins(ctlr, off[chan]);
178 if((rc & (WBusyOff|WErrOff)) == 0)
185 w_inltv(Ctlr* ctlr, Wltv* ltv)
190 if(w_cmd(ctlr, WCmdAccRd, ltv->type)){
191 DEBUG("wavelan: access read failed\n");
194 if(w_seek(ctlr,ltv->type,0,1)){
195 DEBUG("wavelan: seek failed\n");
198 len = csr_ins(ctlr, WR_Data1);
202 if((code=csr_ins(ctlr, WR_Data1)) != ltv->type){
204 DEBUG("wavelan: type %x != code %x\n",ltv->type,code);
208 csr_inss(ctlr, WR_Data1, <v->val, ltv->len-1);
214 w_outltv(Ctlr* ctlr, Wltv* ltv)
216 if(w_seek(ctlr,ltv->type, 0, 1))
218 csr_outss(ctlr, WR_Data1, ltv, ltv->len+1);
219 w_cmd(ctlr, WCmdAccWr, ltv->type);
223 ltv_outs(Ctlr* ctlr, int type, ushort val)
230 w_outltv(ctlr, <v);
234 ltv_ins(Ctlr* ctlr, int type)
241 if(w_inltv(ctlr, <v))
247 ltv_outstr(Ctlr* ctlr, int type, char* val)
253 if(len > sizeof(ltv.s))
255 memset(<v, 0, sizeof(ltv));
256 ltv.len = (sizeof(ltv.type)+sizeof(ltv.slen)+sizeof(ltv.s))/2;
259 // This should be ltv.slen = len; according to Axel Belinfante
262 strncpy(ltv.s, val, len);
263 w_outltv(ctlr, <v);
266 static char Unkname[] = "who knows";
267 static char Nilname[] = "card does not tell";
270 ltv_inname(Ctlr* ctlr, int type)
275 memset(<v,0,sizeof(ltv));
276 ltv.len = WNameLen/2+2;
278 if(w_inltv(ctlr, <v))
281 if(len == 0 || ltv.s[0] == 0)
283 if(len >= sizeof ltv.s)
284 len = sizeof ltv.s - 1;
290 w_read(Ctlr* ctlr, int type, int off, void* buf, ulong len)
292 if(w_seek(ctlr, type, off, 1)){
293 DEBUG("wavelan: w_read: seek failed");
296 csr_inss(ctlr, WR_Data1, buf, len/2);
302 w_write(Ctlr* ctlr, int type, int off, void* buf, ulong len)
304 if(w_seek(ctlr, type, off, 0)){
305 DEBUG("wavelan: w_write: seek failed\n");
309 csr_outss(ctlr, WR_Data0, buf, len/2);
310 csr_outs(ctlr, WR_Data0, 0xdead);
311 csr_outs(ctlr, WR_Data0, 0xbeef);
312 if(w_seek(ctlr, type, off + len, 0)){
313 DEBUG("wavelan: write seek failed\n");
316 if(csr_ins(ctlr, WR_Data0) == 0xdead && csr_ins(ctlr, WR_Data0) == 0xbeef)
319 DEBUG("wavelan: Hermes bug byte.\n");
324 w_alloc(Ctlr* ctlr, int len)
329 if(w_cmd(ctlr, WCmdMalloc, len)==0)
330 for (i = 0; i<WTmOut; i++)
331 if(csr_ins(ctlr, WR_EvSts) & WAllocEv){
332 csr_ack(ctlr, WAllocEv);
333 rc=csr_ins(ctlr, WR_Alloc);
334 if(w_seek(ctlr, rc, 0, 0))
337 for (j=0; j<len; j++)
338 csr_outs(ctlr, WR_Data0, 0);
345 w_enable(Ether* ether)
348 Ctlr* ctlr = (Ctlr*) ether->ctlr;
354 w_cmd(ctlr, WCmdDis, 0);
356 if(w_cmd(ctlr, WCmdIni, 0))
360 ltv_outs(ctlr, WTyp_Tick, 8);
361 ltv_outs(ctlr, WTyp_MaxLen, ctlr->maxlen);
362 ltv_outs(ctlr, WTyp_Ptype, ctlr->ptype);
363 ltv_outs(ctlr, WTyp_CreateIBSS, ctlr->createibss);
364 ltv_outs(ctlr, WTyp_RtsThres, ctlr->rtsthres);
365 ltv_outs(ctlr, WTyp_TxRate, ctlr->txrate);
366 ltv_outs(ctlr, WTyp_ApDens, ctlr->apdensity);
367 ltv_outs(ctlr, WTyp_PMWait, ctlr->pmwait);
368 ltv_outs(ctlr, WTyp_PM, ctlr->pmena);
370 ltv_outstr(ctlr, WTyp_NetName, ctlr->netname);
372 ltv_outstr(ctlr, WTyp_WantName, ctlr->wantname);
373 ltv_outs(ctlr, WTyp_Chan, ctlr->chan);
375 ltv_outstr(ctlr, WTyp_NodeName, ctlr->nodename);
378 memmove(ltv.addr, ether->ea, Eaddrlen);
379 w_outltv(ctlr, <v);
381 ltv_outs(ctlr, WTyp_Prom, (ether->prom?1:0));
383 if(ctlr->hascrypt && ctlr->crypt){
384 ltv_outs(ctlr, WTyp_Crypt, ctlr->crypt);
385 ltv_outs(ctlr, WTyp_TxKey, ctlr->txkey);
386 w_outltv(ctlr, &ctlr->keys);
387 ltv_outs(ctlr, WTyp_XClear, ctlr->xclear);
390 // BUG: set multicast addresses
392 if(w_cmd(ctlr, WCmdEna, 0)){
393 DEBUG("wavelan: Enable failed");
396 ctlr->txdid = w_alloc(ctlr, 1518 + sizeof(WFrame) + 8);
397 ctlr->txmid = w_alloc(ctlr, 1518 + sizeof(WFrame) + 8);
398 if(ctlr->txdid == -1 || ctlr->txmid == -1)
399 DEBUG("wavelan: alloc failed");
406 w_rxdone(Ether* ether)
408 Ctlr* ctlr = (Ctlr*) ether->ctlr;
414 sp = csr_ins(ctlr, WR_RXId);
415 len = w_read(ctlr, sp, 0, &f, sizeof(f));
417 DEBUG("wavelan: read frame error\n");
427 len = f.dlen + WSnapHdrLen;
428 bp = iallocb(ETHERHDRSIZE + len + 2);
431 ep = (Etherpkt*) bp->wp;
432 memmove(ep->d, f.addr1, Eaddrlen);
433 memmove(ep->s, f.addr2, Eaddrlen);
434 memmove(ep->type,&f.type,2);
435 bp->wp += ETHERHDRSIZE;
436 if(w_read(ctlr, sp, WF_802_11_Off, bp->wp, len+2) == 0){
437 DEBUG("wavelan: read 802.11 error\n");
440 bp->wp = bp->rp+(ETHERHDRSIZE+f.dlen);
443 len = ETHERHDRSIZE + f.dlen + 2;
447 if(w_read(ctlr, sp, WF_802_3_Off, bp->wp, len) == 0){
448 DEBUG("wavelan: read 800.3 error\n");
456 ctlr->signal = ((ctlr->signal*15)+((f.qinfo>>8) & 0xFF))/16;
457 ctlr->noise = ((ctlr->noise*15)+(f.qinfo & 0xFF))/16;
466 w_txstart(Ether* ether)
473 if((ctlr = ether->ctlr) == nil || (ctlr->state & (Attached|Power)) != (Attached|Power) || ctlr->txbusy)
476 if((bp = qget(ether->oq)) == nil)
478 pkt = (Etherpkt*)bp->rp;
481 // If the packet header type field is > 1500 it is an IP or
482 // ARP datagram, otherwise it is an 802.3 packet. See RFC1042.
484 memset(&ctlr->txf, 0, sizeof(ctlr->txf));
485 if(((pkt->type[0]<<8)|pkt->type[1]) > 1500){
486 ctlr->txf.framectl = WF_Data;
487 memmove(ctlr->txf.addr1, pkt->d, Eaddrlen);
488 memmove(ctlr->txf.addr2, pkt->s, Eaddrlen);
489 memmove(ctlr->txf.dstaddr, pkt->d, Eaddrlen);
490 memmove(ctlr->txf.srcaddr, pkt->s, Eaddrlen);
491 memmove(&ctlr->txf.type, pkt->type, 2);
492 bp->rp += ETHERHDRSIZE;
495 ctlr->txf.dlen = len+ETHERHDRSIZE-WSnapHdrLen;
496 hnputs((uchar*)&ctlr->txf.dat[0], WSnap0);
497 hnputs((uchar*)&ctlr->txf.dat[1], WSnap1);
498 hnputs((uchar*)&ctlr->txf.len, len+ETHERHDRSIZE-WSnapHdrLen);
503 ctlr->txf.dlen = len;
505 w_write(ctlr, ctlr->txdid, 0, &ctlr->txf, sizeof(ctlr->txf));
506 w_write(ctlr, ctlr->txdid, off, bp->rp, len+2);
508 if(w_cmd(ctlr, WCmdReclaim|WCmdTx, ctlr->txdid)){
509 DEBUG("wavelan: transmit failed\n");
520 w_txdone(Ctlr* ctlr, int sts)
530 /* save the stats info in the ctlr struct */
532 w_stats(Ctlr* ctlr, int len)
535 ulong* p = (ulong*)&ctlr->WStats;
536 ulong* pend = (ulong*)&ctlr->end;
538 for (i = 0; i < len && p < pend; i++){
539 rc = csr_ins(ctlr, WR_Data1);
546 /* send the base station scan info to any readers */
548 w_scaninfo(Ether* ether, Ctlr *ctlr, int len)
551 Netfile **ep, *f, **fp;
556 scanbuf = malloc(len*2);
560 for (i = 0; i < len ; i++)
561 scanbuf[i] = csr_ins(ctlr, WR_Data1);
563 /* calculate number of samples */
569 ep = ðer->f[Ntypes];
570 for(fp = ether->f; fp < ep && i > 0; fp++){
572 if(f == nil || f->scan == 0)
575 bp = iallocb(100*len);
578 for(j = 0; j < len; j++){
579 wsp = (WScan*)(&scanbuf[j*25]);
580 if(wsp->ssid_len > 32)
582 bp->wp = (uchar*)seprint((char*)bp->wp, (char*)bp->lim,
583 "ssid=%.*s;bssid=%E;signal=%d;noise=%d;chan=%d%s\n",
584 wsp->ssid_len, wsp->ssid, wsp->bssid, wsp->signal,
585 wsp->noise, wsp->chan, (wsp->capinfo&(1<<4))?";wep":"");
595 w_info(Ether *ether, Ctlr* ctlr)
600 sp = csr_ins(ctlr, WR_InfoId);
601 ltv.len = ltv.type = 0;
602 w_read(ctlr, sp, 0, <v, 4);
606 w_stats(ctlr, ltv.len);
609 w_scaninfo(ether, ctlr, ltv.len);
615 /* set scanning interval */
617 w_scanbs(void *a, uint secs)
620 Ctlr* ctlr = (Ctlr*) ether->ctlr;
622 ctlr->scanticks = secs*(1000/MSperTick);
629 Ctlr* ctlr = (Ctlr*) ether->ctlr;
631 if((ctlr->state & Power) == 0)
634 if((ctlr->state & Attached) == 0){
635 csr_ack(ctlr, 0xffff);
636 csr_outs(ctlr, WR_IntEna, 0);
640 rc = csr_ins(ctlr, WR_EvSts);
641 csr_ack(ctlr, ~WEvs); // Not interested in them
644 csr_ack(ctlr, WRXEv);
648 csr_ack(ctlr, WTXEv);
652 txid = csr_ins(ctlr, WR_Alloc);
653 csr_ack(ctlr, WAllocEv);
654 if(txid == ctlr->txdid){
655 if((rc & WTXEv) == 0)
662 csr_ack(ctlr, WInfoEv);
666 csr_ack(ctlr, WTxErrEv);
670 csr_ack(ctlr, WIDropEv);
675 // Watcher to ensure that the card still works properly and
676 // to request WStats updates once a minute.
677 // BUG: it runs much more often, see the comment below.
682 Ether* ether = (Ether*) arg;
683 Ctlr* ctlr = (Ctlr*)ether->ctlr;
685 ctlr->timerproc = up;
689 tsleep(&up->sleep, return0, 0, MSperTick);
690 ctlr = (Ctlr*)ether->ctlr;
693 if((ctlr->state & (Attached|Power)) != (Attached|Power))
699 // Seems that the card gets frames BUT does
700 // not send the interrupt; this is a problem because
701 // I suspect it runs out of receive buffers and
702 // stops receiving until a transmit watchdog
703 // reenables the card.
704 // The problem is serious because it leads to
706 // This can be seen clearly by commenting out
707 // the next if and doing a ping: it will stop
708 // receiving (although the icmp replies are being
709 // issued from the remote) after a few seconds.
710 // Of course this `bug' could be because I'm reading
711 // the card frames in the wrong way; due to the
712 // lack of documentation I cannot know.
714 if(csr_ins(ctlr, WR_EvSts)&WEvs){
719 if((ctlr->ticks % 10) == 0) {
720 if(ctlr->txtmout && --ctlr->txtmout == 0){
722 w_txdone(ctlr, WTxErrEv);
724 DEBUG("wavelan: wdog enable failed\n");
728 if((ctlr->ticks % 120) == 0)
729 if(ctlr->txbusy == 0)
730 w_cmd(ctlr, WCmdEnquire, WTyp_Stats);
731 if(ctlr->scanticks > 0)
732 if((ctlr->ticks % ctlr->scanticks) == 0)
733 if(ctlr->txbusy == 0)
734 w_cmd(ctlr, WCmdEnquire, WTyp_Scan);
738 pexit("terminated", 1);
742 w_multicast(void *ether, uchar*, int add)
744 /* BUG: use controller's multicast filter */
746 w_promiscuous(ether, 1);
750 w_attach(Ether* ether)
759 snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
760 ctlr = (Ctlr*) ether->ctlr;
761 if((ctlr->state & Attached) == 0){
763 rc = w_enable(ether);
766 ctlr->state |= Attached;
767 kproc(name, w_timer, ether);
769 print("#l%d: enable failed\n",ether->ctlrno);
774 w_detach(Ether* ether)
779 if(ether->ctlr == nil)
782 snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
783 ctlr = (Ctlr*) ether->ctlr;
784 if(ctlr->state & Attached){
788 if(!postnote(ctlr->timerproc, 1, "kill", NExit))
789 print("timerproc note not posted\n");
790 print("w_detach, killing 0x%p\n", ctlr->timerproc);
792 ctlr->state &= ~Attached;
799 w_power(Ether* ether, int on)
803 ctlr = (Ctlr*) ether->ctlr;
805 iprint("w_power %d\n", on);
807 if((ctlr->state & Power) == 0){
808 if (wavelanreset(ether, ctlr) < 0){
809 iprint("w_power: reset failed\n");
815 if(ctlr->state & Attached)
817 ctlr->state |= Power;
820 if(ctlr->state & Power){
821 if(ctlr->state & Attached)
823 ctlr->state &= ~Power;
829 #define PRINTSTAT(fmt,val) l += snprint(p+l, READSTR-l, (fmt), (val))
830 #define PRINTSTR(fmt) l += snprint(p+l, READSTR-l, (fmt))
833 w_ifstat(Ether* ether, void* a, long n, ulong offset)
835 Ctlr *ctlr = (Ctlr*) ether->ctlr;
839 ether->oerrs = ctlr->ntxerr;
840 ether->crcs = ctlr->nrxfcserr;
842 ether->buffs = ctlr->nrxdropnobuf;
843 ether->overflows = 0;
846 // Offset must be zero or there's a possibility the
847 // new data won't match the previous read.
849 if(n == 0 || offset != 0)
852 p = smalloc(READSTR);
855 PRINTSTAT("Signal: %d\n", ctlr->signal-149);
856 PRINTSTAT("Noise: %d\n", ctlr->noise-149);
857 PRINTSTAT("SNR: %ud\n", ctlr->signal-ctlr->noise);
858 PRINTSTAT("Interrupts: %lud\n", ctlr->nints);
859 PRINTSTAT("Double Interrupts: %lud\n", ctlr->ndoubleint);
860 PRINTSTAT("TxPackets: %lud\n", ctlr->ntx);
861 PRINTSTAT("RxPackets: %lud\n", ctlr->nrx);
862 PRINTSTAT("TxErrors: %lud\n", ctlr->ntxerr);
863 PRINTSTAT("RxErrors: %lud\n", ctlr->nrxerr);
864 PRINTSTAT("TxRequests: %lud\n", ctlr->ntxrq);
865 PRINTSTAT("AllocEvs: %lud\n", ctlr->nalloc);
866 PRINTSTAT("InfoEvs: %lud\n", ctlr->ninfo);
867 PRINTSTAT("InfoDrop: %lud\n", ctlr->nidrop);
868 PRINTSTAT("WatchDogs: %lud\n", ctlr->nwatchdogs);
869 PRINTSTAT("Ticks: %ud\n", ctlr->ticks);
870 PRINTSTAT("TickIntr: %ud\n", ctlr->tickintr);
871 k = ((ctlr->state & Attached) ? "attached" : "not attached");
872 PRINTSTAT("Card %s", k);
873 k = ((ctlr->state & Power) ? "on" : "off");
874 PRINTSTAT(", power %s", k);
875 k = ((ctlr->txbusy)? ", txbusy" : "");
876 PRINTSTAT("%s\n", k);
880 for (i = 0; i < WNKeys; i++){
881 if(ctlr->keys.keys[i].len == 0)
883 else if(SEEKEYS == 0)
886 PRINTSTAT("%s ", ctlr->keys.keys[i].dat);
893 PRINTSTR("\nCard stats: \n");
894 PRINTSTAT("Status: %ux\n", csr_ins(ctlr, WR_Sts));
895 PRINTSTAT("Event status: %ux\n", csr_ins(ctlr, WR_EvSts));
896 i = ltv_ins(ctlr, WTyp_Ptype);
897 PRINTSTAT("Port type: %d\n", i);
898 PRINTSTAT("Transmit rate: %d\n", ltv_ins(ctlr, WTyp_TxRate));
899 PRINTSTAT("Current Transmit rate: %d\n",
900 ltv_ins(ctlr, WTyp_CurTxRate));
901 PRINTSTAT("Channel: %d\n", ltv_ins(ctlr, WTyp_Chan));
902 PRINTSTAT("AP density: %d\n", ltv_ins(ctlr, WTyp_ApDens));
903 PRINTSTAT("Promiscuous mode: %d\n", ltv_ins(ctlr, WTyp_Prom));
905 PRINTSTAT("SSID name: %s\n", ltv_inname(ctlr, WTyp_NetName));
908 PRINTSTAT("Current name: %s\n", ltv_inname(ctlr, WTyp_CurName));
909 ltv.type = WTyp_BaseID;
911 if(w_inltv(ctlr, <v))
912 print("#l%d: unable to read base station mac addr\n", ether->ctlrno);
913 l += snprint(p+l, READSTR-l, "Base station: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
914 ltv.addr[0], ltv.addr[1], ltv.addr[2], ltv.addr[3], ltv.addr[4], ltv.addr[5]);
916 PRINTSTAT("Net name: %s\n", ltv_inname(ctlr, WTyp_WantName));
917 PRINTSTAT("Node name: %s\n", ltv_inname(ctlr, WTyp_NodeName));
918 if(ltv_ins(ctlr, WTyp_HasCrypt) == 0)
919 PRINTSTR("WEP: not supported\n");
921 if(ltv_ins(ctlr, WTyp_Crypt) == 0)
922 PRINTSTR("WEP: disabled\n");
924 PRINTSTR("WEP: enabled\n");
925 k = ((ctlr->xclear)? "excluded": "included");
926 PRINTSTAT("Clear packets: %s\n", k);
927 txid = ltv_ins(ctlr, WTyp_TxKey);
928 PRINTSTAT("Transmit key id: %d\n", txid);
933 PRINTSTAT("ntxuframes: %lud\n", ctlr->ntxuframes);
934 PRINTSTAT("ntxmframes: %lud\n", ctlr->ntxmframes);
935 PRINTSTAT("ntxfrags: %lud\n", ctlr->ntxfrags);
936 PRINTSTAT("ntxubytes: %lud\n", ctlr->ntxubytes);
937 PRINTSTAT("ntxmbytes: %lud\n", ctlr->ntxmbytes);
938 PRINTSTAT("ntxdeferred: %lud\n", ctlr->ntxdeferred);
939 PRINTSTAT("ntxsretries: %lud\n", ctlr->ntxsretries);
940 PRINTSTAT("ntxmultiretries: %lud\n", ctlr->ntxmultiretries);
941 PRINTSTAT("ntxretrylimit: %lud\n", ctlr->ntxretrylimit);
942 PRINTSTAT("ntxdiscards: %lud\n", ctlr->ntxdiscards);
943 PRINTSTAT("nrxuframes: %lud\n", ctlr->nrxuframes);
944 PRINTSTAT("nrxmframes: %lud\n", ctlr->nrxmframes);
945 PRINTSTAT("nrxfrags: %lud\n", ctlr->nrxfrags);
946 PRINTSTAT("nrxubytes: %lud\n", ctlr->nrxubytes);
947 PRINTSTAT("nrxmbytes: %lud\n", ctlr->nrxmbytes);
948 PRINTSTAT("nrxfcserr: %lud\n", ctlr->nrxfcserr);
949 PRINTSTAT("nrxdropnobuf: %lud\n", ctlr->nrxdropnobuf);
950 PRINTSTAT("nrxdropnosa: %lud\n", ctlr->nrxdropnosa);
951 PRINTSTAT("nrxcantdecrypt: %lud\n", ctlr->nrxcantdecrypt);
952 PRINTSTAT("nrxmsgfrag: %lud\n", ctlr->nrxmsgfrag);
953 PRINTSTAT("nrxmsgbadfrag: %lud\n", ctlr->nrxmsgbadfrag);
955 n = readstr(offset, a, n, p);
963 parsekey(WKey* key, char* a)
966 char buf[WMaxKeyLen];
969 if(len == WMinKeyLen || len == WMaxKeyLen){
970 memset(key->dat, 0, sizeof(key->dat));
971 memmove(key->dat, a, len);
976 else if(len == WMinKeyLen*2 || len == WMaxKeyLen*2){
978 for(i = 0; i < len; i++){
979 if(*a >= '0' && *a <= '9')
981 else if(*a >= 'a' && *a <= 'f')
983 else if(*a >= 'A' && *a <= 'F')
996 memset(key->dat, 0, sizeof(key->dat));
997 memmove(key->dat, buf, k);
1007 w_option(Ctlr* ctlr, char* buf, long n)
1015 cb = parsecmd(buf, n);
1018 else if(cistrcmp(cb->f[0], "essid") == 0){
1019 if(cistrcmp(cb->f[1],"default") == 0)
1023 if(ctlr->ptype == WPTypeAdHoc){
1024 memset(ctlr->netname, 0, sizeof(ctlr->netname));
1025 strncpy(ctlr->netname, p, WNameLen-1);
1028 memset(ctlr->wantname, 0, sizeof(ctlr->wantname));
1029 strncpy(ctlr->wantname, p, WNameLen-1);
1032 else if(cistrcmp(cb->f[0], "station") == 0){
1033 memset(ctlr->nodename, 0, sizeof(ctlr->nodename));
1034 strncpy(ctlr->nodename, cb->f[1], WNameLen-1);
1036 else if(cistrcmp(cb->f[0], "channel") == 0){
1037 if((i = atoi(cb->f[1])) >= 1 && i <= 16)
1042 else if(cistrcmp(cb->f[0], "mode") == 0){
1043 if(cistrcmp(cb->f[1], "managed") == 0)
1044 ctlr->ptype = WPTypeManaged;
1045 else if(cistrcmp(cb->f[1], "wds") == 0)
1046 ctlr->ptype = WPTypeWDS;
1047 else if(cistrcmp(cb->f[1], "adhoc") == 0)
1048 ctlr->ptype = WPTypeAdHoc;
1049 else if((i = atoi(cb->f[1])) >= 0 && i <= 3)
1054 else if(cistrcmp(cb->f[0], "ibss") == 0){
1055 if(cistrcmp(cb->f[1], "on") == 0)
1056 ctlr->createibss = 1;
1058 ctlr->createibss = 0;
1060 else if(cistrcmp(cb->f[0], "crypt") == 0){
1061 if(cistrcmp(cb->f[1], "off") == 0)
1063 else if(cistrcmp(cb->f[1], "on") == 0 && ctlr->hascrypt)
1068 else if(cistrcmp(cb->f[0], "clear") == 0){
1069 if(cistrcmp(cb->f[1], "on") == 0)
1071 else if(cistrcmp(cb->f[1], "off") == 0 && ctlr->hascrypt)
1076 else if(cistrncmp(cb->f[0], "key", 3) == 0){
1077 if((i = atoi(cb->f[0]+3)) >= 1 && i <= WNKeys){
1079 if(parsekey(&ctlr->keys.keys[ctlr->txkey], cb->f[1]))
1085 else if(cistrcmp(cb->f[0], "txkey") == 0){
1086 if((i = atoi(cb->f[1])) >= 1 && i <= WNKeys)
1091 else if(cistrcmp(cb->f[0], "pm") == 0){
1092 if(cistrcmp(cb->f[1], "off") == 0)
1094 else if(cistrcmp(cb->f[1], "on") == 0){
1098 // check range here? what are the units?
1113 w_ctl(Ether* ether, void* buf, long n)
1117 if((ctlr = ether->ctlr) == nil)
1119 if((ctlr->state & Attached) == 0)
1123 if(w_option(ctlr, buf, n)){
1128 w_txdone(ctlr, WTxErrEv);
1137 w_transmit(Ether* ether)
1139 Ctlr* ctlr = ether->ctlr;
1151 w_promiscuous(void* arg, int on)
1153 Ether* ether = (Ether*)arg;
1154 Ctlr* ctlr = ether->ctlr;
1157 error("card not found");
1158 if((ctlr->state & Attached) == 0)
1159 error("card not attached");
1161 ltv_outs(ctlr, WTyp_Prom, (on?1:0));
1166 w_interrupt(Ureg* ,void* arg)
1168 Ether* ether = (Ether*) arg;
1169 Ctlr* ctlr = (Ctlr*) ether->ctlr;
1180 wavelanreset(Ether* ether, Ctlr *ctlr)
1184 iprint("wavelanreset, iob 0x%ux\n", ctlr->iob);
1186 if(w_cmd(ctlr,WCmdIni,0)){
1187 iprint("#l%d: init failed\n", ether->ctlrno);
1191 ltv_outs(ctlr, WTyp_Tick, 8);
1194 ctlr->ptype = WDfltPType;
1196 ctlr->createibss = 0;
1197 ctlr->keys.len = sizeof(WKey)*WNKeys/2 + 1;
1198 ctlr->keys.type = WTyp_Keys;
1199 if(ctlr->hascrypt = ltv_ins(ctlr, WTyp_HasCrypt))
1201 *ctlr->netname = *ctlr->wantname = 0;
1202 strcpy(ctlr->nodename, "Plan 9 STA");
1204 ctlr->netname[WNameLen-1] = 0;
1205 ctlr->wantname[WNameLen-1] = 0;
1206 ctlr->nodename[WNameLen-1] =0;
1208 ltv.type = WTyp_Mac;
1210 if(w_inltv(ctlr, <v)){
1211 iprint("#l%d: unable to read mac addr\n",
1215 memmove(ether->ea, ltv.addr, Eaddrlen);
1218 ctlr->chan = ltv_ins(ctlr, WTyp_Chan);
1219 ctlr->apdensity = WDfltApDens;
1220 ctlr->rtsthres = WDfltRtsThres;
1221 ctlr->txrate = WDfltTxRate;
1222 ctlr->maxlen = WMaxLen;
1227 ctlr->state |= Power;
1229 // free old Ctlr struct if resetting after suspend
1230 if(ether->ctlr && ether->ctlr != ctlr)
1236 ether->attach = w_attach;
1237 ether->transmit = w_transmit;
1238 ether->ifstat = w_ifstat;
1240 ether->power = w_power;
1241 ether->promiscuous = w_promiscuous;
1242 ether->multicast = w_multicast;
1243 ether->scanbs = w_scanbs;
1246 intrenable(ether->irq, w_interrupt, ether, ether->tbdf, ether->name);
1248 DEBUG("#l%d: irq %d port %lx type %s",
1249 ether->ctlrno, ether->irq, ether->port, ether->type);
1250 DEBUG(" %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux\n",
1251 ether->ea[0], ether->ea[1], ether->ea[2],
1252 ether->ea[3], ether->ea[4], ether->ea[5]);
1257 char* wavenames[] = {
1260 "Instant Wireless ; Network PC CARD",
1261 "Instant Wireless Network PC Card",
1262 "Avaya Wireless PC Card",
1264 "INTERSIL;HFA384x/IEEE;Version 01.02;",