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"
33 MSperTick= 50, /* ms between ticks of kproc */
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].
44 csr_outs(Ctlr *ctlr, int reg, ushort arg)
49 outs(ctlr->iob+reg, arg);
53 csr_ins(Ctlr *ctlr, int reg)
56 return ctlr->mmb[reg];
58 return ins(ctlr->iob+reg);
62 csr_ack(Ctlr *ctlr, int ev)
64 csr_outs(ctlr, WR_EvAck, ev);
68 csr_inss(Ctlr *ctlr, int reg, void *dat, int ndat)
78 inss(ctlr->iob+reg, dat, ndat);
82 csr_outss(Ctlr *ctlr, int reg, void *dat, int ndat)
92 outss(ctlr->iob+reg, dat, ndat);
95 // w_... routines do not ilock the Ctlr and should
101 csr_outs(ctlr, WR_IntEna, 0);
102 csr_ack(ctlr, 0xffff);
108 csr_outs(ctlr, WR_IntEna, WEvs);
112 w_cmd(Ctlr *ctlr, ushort cmd, ushort arg)
116 for(i=0; i<WTmOut; i++)
117 if((csr_ins(ctlr, WR_Cmd)&WCmdBusy) == 0)
120 print("#l%d: issuing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_Cmd));
124 csr_outs(ctlr, WR_Parm0, arg);
125 csr_outs(ctlr, WR_Cmd, cmd);
127 for(i=0; i<WTmOut; i++)
128 if(csr_ins(ctlr, WR_EvSts)&WCmdEv)
132 * WCmdIni can take a really long time.
134 enum { IniTmOut = 2000 };
135 for(i=0; i<IniTmOut; i++){
136 if(csr_ins(ctlr, WR_EvSts)&WCmdEv)
141 if(0) print("#l%d: long cmd %.4ux %d\n", ctlr->ctlrno, cmd, i);
143 print("#l%d: execing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_EvSts));
147 rc = csr_ins(ctlr, WR_Sts);
148 csr_ack(ctlr, WCmdEv);
150 if((rc&WCmdMsk) != (cmd&WCmdMsk)){
151 print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc);
156 * Don't print; this happens on every WCmdAccWr for some reason.
158 if(0) print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc);
165 w_seek(Ctlr* ctlr, ushort id, ushort offset, int chan)
168 static ushort sel[] = { WR_Sel0, WR_Sel1 };
169 static ushort off[] = { WR_Off0, WR_Off1 };
171 if(chan != 0 && chan != 1)
172 panic("wavelan: bad chan");
173 csr_outs(ctlr, sel[chan], id);
174 csr_outs(ctlr, off[chan], offset);
175 for (i=0; i<WTmOut; i++){
176 rc = csr_ins(ctlr, off[chan]);
177 if((rc & (WBusyOff|WErrOff)) == 0)
184 w_inltv(Ctlr* ctlr, Wltv* ltv)
189 if(w_cmd(ctlr, WCmdAccRd, ltv->type)){
190 DEBUG("wavelan: access read failed\n");
193 if(w_seek(ctlr,ltv->type,0,1)){
194 DEBUG("wavelan: seek failed\n");
197 len = csr_ins(ctlr, WR_Data1);
201 if((code=csr_ins(ctlr, WR_Data1)) != ltv->type){
203 DEBUG("wavelan: type %x != code %x\n",ltv->type,code);
207 csr_inss(ctlr, WR_Data1, <v->val, ltv->len-1);
213 w_outltv(Ctlr* ctlr, Wltv* ltv)
215 if(w_seek(ctlr,ltv->type, 0, 1))
217 csr_outss(ctlr, WR_Data1, ltv, ltv->len+1);
218 w_cmd(ctlr, WCmdAccWr, ltv->type);
222 ltv_outs(Ctlr* ctlr, int type, ushort val)
229 w_outltv(ctlr, <v);
233 ltv_ins(Ctlr* ctlr, int type)
240 if(w_inltv(ctlr, <v))
246 ltv_outstr(Ctlr* ctlr, int type, char* val)
252 if(len > sizeof(ltv.s))
254 memset(<v, 0, sizeof(ltv));
255 ltv.len = (sizeof(ltv.type)+sizeof(ltv.slen)+sizeof(ltv.s))/2;
258 // This should be ltv.slen = len; according to Axel Belinfante
261 strncpy(ltv.s, val, len);
262 w_outltv(ctlr, <v);
265 static char Unkname[] = "who knows";
266 static char Nilname[] = "card does not tell";
269 ltv_inname(Ctlr* ctlr, int type)
274 memset(<v,0,sizeof(ltv));
275 ltv.len = WNameLen/2+2;
277 if(w_inltv(ctlr, <v))
280 if(len == 0 || ltv.s[0] == 0)
282 if(len >= sizeof ltv.s)
283 len = sizeof ltv.s - 1;
289 w_read(Ctlr* ctlr, int type, int off, void* buf, ulong len)
291 if(w_seek(ctlr, type, off, 1)){
292 DEBUG("wavelan: w_read: seek failed");
295 csr_inss(ctlr, WR_Data1, buf, len/2);
301 w_write(Ctlr* ctlr, int type, int off, void* buf, ulong len)
303 if(w_seek(ctlr, type, off, 0)){
304 DEBUG("wavelan: w_write: seek failed\n");
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");
315 if(csr_ins(ctlr, WR_Data0) == 0xdead && csr_ins(ctlr, WR_Data0) == 0xbeef)
318 DEBUG("wavelan: Hermes bug byte.\n");
323 w_alloc(Ctlr* ctlr, int len)
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))
336 for (j=0; j<len; j++)
337 csr_outs(ctlr, WR_Data0, 0);
344 w_enable(Ether* ether)
347 Ctlr* ctlr = (Ctlr*) ether->ctlr;
353 w_cmd(ctlr, WCmdDis, 0);
355 if(w_cmd(ctlr, WCmdIni, 0))
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);
369 ltv_outstr(ctlr, WTyp_NetName, ctlr->netname);
371 ltv_outstr(ctlr, WTyp_WantName, ctlr->wantname);
372 ltv_outs(ctlr, WTyp_Chan, ctlr->chan);
374 ltv_outstr(ctlr, WTyp_NodeName, ctlr->nodename);
377 memmove(ltv.addr, ether->ea, Eaddrlen);
378 w_outltv(ctlr, <v);
380 ltv_outs(ctlr, WTyp_Prom, (ether->prom?1:0));
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);
389 // BUG: set multicast addresses
391 if(w_cmd(ctlr, WCmdEna, 0)){
392 DEBUG("wavelan: Enable failed");
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");
405 w_rxdone(Ether* ether)
407 Ctlr* ctlr = (Ctlr*) ether->ctlr;
413 sp = csr_ins(ctlr, WR_RXId);
414 len = w_read(ctlr, sp, 0, &f, sizeof(f));
416 DEBUG("wavelan: read frame error\n");
426 len = f.dlen + WSnapHdrLen;
427 bp = iallocb(ETHERHDRSIZE + len + 2);
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");
439 bp->wp = bp->rp+(ETHERHDRSIZE+f.dlen);
442 len = ETHERHDRSIZE + f.dlen + 2;
446 if(w_read(ctlr, sp, WF_802_3_Off, bp->wp, len) == 0){
447 DEBUG("wavelan: read 800.3 error\n");
455 ctlr->signal = ((ctlr->signal*15)+((f.qinfo>>8) & 0xFF))/16;
456 ctlr->noise = ((ctlr->noise*15)+(f.qinfo & 0xFF))/16;
465 w_txstart(Ether* ether)
472 if((ctlr = ether->ctlr) == nil || (ctlr->state & (Attached|Power)) != (Attached|Power) || ctlr->txbusy)
475 if((bp = qget(ether->oq)) == nil)
477 pkt = (Etherpkt*)bp->rp;
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.
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;
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);
502 ctlr->txf.dlen = len;
504 w_write(ctlr, ctlr->txdid, 0, &ctlr->txf, sizeof(ctlr->txf));
505 w_write(ctlr, ctlr->txdid, off, bp->rp, len+2);
507 if(w_cmd(ctlr, WCmdReclaim|WCmdTx, ctlr->txdid)){
508 DEBUG("wavelan: transmit failed\n");
519 w_txdone(Ctlr* ctlr, int sts)
529 /* save the stats info in the ctlr struct */
531 w_stats(Ctlr* ctlr, int len)
534 ulong* p = (ulong*)&ctlr->WStats;
535 ulong* pend = (ulong*)&ctlr->end;
537 for (i = 0; i < len && p < pend; i++){
538 rc = csr_ins(ctlr, WR_Data1);
545 /* send the base station scan info to any readers */
547 w_scaninfo(Ether* ether, Ctlr *ctlr, int len)
550 Netfile **ep, *f, **fp;
555 scanbuf = malloc(len*2);
559 for (i = 0; i < len ; i++)
560 scanbuf[i] = csr_ins(ctlr, WR_Data1);
562 /* calculate number of samples */
568 ep = ðer->f[Ntypes];
569 for(fp = ether->f; fp < ep && i > 0; fp++){
571 if(f == nil || f->scan == 0)
574 bp = iallocb(100*len);
577 for(j = 0; j < len; j++){
578 wsp = (WScan*)(&scanbuf[j*25]);
579 if(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":"");
594 w_info(Ether *ether, Ctlr* ctlr)
599 sp = csr_ins(ctlr, WR_InfoId);
600 ltv.len = ltv.type = 0;
601 w_read(ctlr, sp, 0, <v, 4);
605 w_stats(ctlr, ltv.len);
608 w_scaninfo(ether, ctlr, ltv.len);
614 /* set scanning interval */
616 w_scanbs(void *a, uint secs)
619 Ctlr* ctlr = (Ctlr*) ether->ctlr;
621 ctlr->scanticks = secs*(1000/MSperTick);
628 Ctlr* ctlr = (Ctlr*) ether->ctlr;
630 if((ctlr->state & Power) == 0)
633 if((ctlr->state & Attached) == 0){
634 csr_ack(ctlr, 0xffff);
635 csr_outs(ctlr, WR_IntEna, 0);
639 rc = csr_ins(ctlr, WR_EvSts);
640 csr_ack(ctlr, ~WEvs); // Not interested in them
643 csr_ack(ctlr, WRXEv);
647 csr_ack(ctlr, WTXEv);
651 txid = csr_ins(ctlr, WR_Alloc);
652 csr_ack(ctlr, WAllocEv);
653 if(txid == ctlr->txdid){
654 if((rc & WTXEv) == 0)
661 csr_ack(ctlr, WInfoEv);
665 csr_ack(ctlr, WTxErrEv);
669 csr_ack(ctlr, WIDropEv);
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.
681 Ether* ether = (Ether*) arg;
682 Ctlr* ctlr = (Ctlr*)ether->ctlr;
684 ctlr->timerproc = up;
688 tsleep(&up->sleep, return0, 0, MSperTick);
689 ctlr = (Ctlr*)ether->ctlr;
692 if((ctlr->state & (Attached|Power)) != (Attached|Power))
698 // Seems that the card gets frames BUT does
699 // not send the interrupt; this is a problem because
700 // I suspect it runs out of receive buffers and
701 // stops receiving until a transmit watchdog
702 // reenables the card.
703 // The problem is serious because it leads to
705 // This can be seen clearly by commenting out
706 // the next if and doing a ping: it will stop
707 // receiving (although the icmp replies are being
708 // issued from the remote) after a few seconds.
709 // Of course this `bug' could be because I'm reading
710 // the card frames in the wrong way; due to the
711 // lack of documentation I cannot know.
713 if(csr_ins(ctlr, WR_EvSts)&WEvs){
718 if((ctlr->ticks % 10) == 0) {
719 if(ctlr->txtmout && --ctlr->txtmout == 0){
721 w_txdone(ctlr, WTxErrEv);
723 DEBUG("wavelan: wdog enable failed\n");
727 if((ctlr->ticks % 120) == 0)
728 if(ctlr->txbusy == 0)
729 w_cmd(ctlr, WCmdEnquire, WTyp_Stats);
730 if(ctlr->scanticks > 0)
731 if((ctlr->ticks % ctlr->scanticks) == 0)
732 if(ctlr->txbusy == 0)
733 w_cmd(ctlr, WCmdEnquire, WTyp_Scan);
737 pexit("terminated", 1);
741 w_multicast(void *ether, uchar*, int add)
743 /* BUG: use controller's multicast filter */
745 w_promiscuous(ether, 1);
749 w_attach(Ether* ether)
758 snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
759 ctlr = (Ctlr*) ether->ctlr;
760 if((ctlr->state & Attached) == 0){
762 rc = w_enable(ether);
765 ctlr->state |= Attached;
766 kproc(name, w_timer, ether);
768 print("#l%d: enable failed\n",ether->ctlrno);
773 w_detach(Ether* ether)
778 if(ether->ctlr == nil)
781 snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
782 ctlr = (Ctlr*) ether->ctlr;
783 if(ctlr->state & Attached){
787 if(!postnote(ctlr->timerproc, 1, "kill", NExit))
788 print("timerproc note not posted\n");
789 print("w_detach, killing 0x%p\n", ctlr->timerproc);
791 ctlr->state &= ~Attached;
798 w_power(Ether* ether, int on)
802 ctlr = (Ctlr*) ether->ctlr;
804 iprint("w_power %d\n", on);
806 if((ctlr->state & Power) == 0){
807 if (wavelanreset(ether, ctlr) < 0){
808 iprint("w_power: reset failed\n");
814 if(ctlr->state & Attached)
816 ctlr->state |= Power;
819 if(ctlr->state & Power){
820 if(ctlr->state & Attached)
822 ctlr->state &= ~Power;
828 #define PRINTSTAT(fmt,val) l += snprint(p+l, READSTR-l, (fmt), (val))
829 #define PRINTSTR(fmt) l += snprint(p+l, READSTR-l, (fmt))
832 w_ifstat(Ether* ether, void* a, long n, ulong offset)
834 Ctlr *ctlr = (Ctlr*) ether->ctlr;
838 ether->oerrs = ctlr->ntxerr;
839 ether->crcs = ctlr->nrxfcserr;
841 ether->buffs = ctlr->nrxdropnobuf;
842 ether->overflows = 0;
845 // Offset must be zero or there's a possibility the
846 // new data won't match the previous read.
848 if(n == 0 || offset != 0)
851 p = smalloc(READSTR);
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);
879 for (i = 0; i < WNKeys; i++){
880 if(ctlr->keys.keys[i].len == 0)
882 else if(SEEKEYS == 0)
885 PRINTSTAT("%s ", ctlr->keys.keys[i].dat);
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));
904 PRINTSTAT("SSID name: %s\n", ltv_inname(ctlr, WTyp_NetName));
907 PRINTSTAT("Current name: %s\n", ltv_inname(ctlr, WTyp_CurName));
908 ltv.type = WTyp_BaseID;
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]);
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");
920 if(ltv_ins(ctlr, WTyp_Crypt) == 0)
921 PRINTSTR("WEP: disabled\n");
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);
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);
954 n = readstr(offset, a, n, p);
962 parsekey(WKey* key, char* a)
965 char buf[WMaxKeyLen];
968 if(len == WMinKeyLen || len == WMaxKeyLen){
969 memset(key->dat, 0, sizeof(key->dat));
970 memmove(key->dat, a, len);
975 else if(len == WMinKeyLen*2 || len == WMaxKeyLen*2){
977 for(i = 0; i < len; i++){
978 if(*a >= '0' && *a <= '9')
980 else if(*a >= 'a' && *a <= 'f')
982 else if(*a >= 'A' && *a <= 'F')
995 memset(key->dat, 0, sizeof(key->dat));
996 memmove(key->dat, buf, k);
1006 w_option(Ctlr* ctlr, char* buf, long n)
1014 cb = parsecmd(buf, n);
1017 else if(cistrcmp(cb->f[0], "essid") == 0){
1018 if(cistrcmp(cb->f[1],"default") == 0)
1022 if(ctlr->ptype == WPTypeAdHoc){
1023 memset(ctlr->netname, 0, sizeof(ctlr->netname));
1024 strncpy(ctlr->netname, p, WNameLen-1);
1027 memset(ctlr->wantname, 0, sizeof(ctlr->wantname));
1028 strncpy(ctlr->wantname, p, WNameLen-1);
1031 else if(cistrcmp(cb->f[0], "station") == 0){
1032 memset(ctlr->nodename, 0, sizeof(ctlr->nodename));
1033 strncpy(ctlr->nodename, cb->f[1], WNameLen-1);
1035 else if(cistrcmp(cb->f[0], "channel") == 0){
1036 if((i = atoi(cb->f[1])) >= 1 && i <= 16)
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)
1053 else if(cistrcmp(cb->f[0], "ibss") == 0){
1054 if(cistrcmp(cb->f[1], "on") == 0)
1055 ctlr->createibss = 1;
1057 ctlr->createibss = 0;
1059 else if(cistrcmp(cb->f[0], "crypt") == 0){
1060 if(cistrcmp(cb->f[1], "off") == 0)
1062 else if(cistrcmp(cb->f[1], "on") == 0 && ctlr->hascrypt)
1067 else if(cistrcmp(cb->f[0], "clear") == 0){
1068 if(cistrcmp(cb->f[1], "on") == 0)
1070 else if(cistrcmp(cb->f[1], "off") == 0 && ctlr->hascrypt)
1075 else if(cistrncmp(cb->f[0], "key", 3) == 0){
1076 if((i = atoi(cb->f[0]+3)) >= 1 && i <= WNKeys){
1078 if(parsekey(&ctlr->keys.keys[ctlr->txkey], cb->f[1]))
1084 else if(cistrcmp(cb->f[0], "txkey") == 0){
1085 if((i = atoi(cb->f[1])) >= 1 && i <= WNKeys)
1090 else if(cistrcmp(cb->f[0], "pm") == 0){
1091 if(cistrcmp(cb->f[1], "off") == 0)
1093 else if(cistrcmp(cb->f[1], "on") == 0){
1097 // check range here? what are the units?
1112 w_ctl(Ether* ether, void* buf, long n)
1116 if((ctlr = ether->ctlr) == nil)
1118 if((ctlr->state & Attached) == 0)
1122 if(w_option(ctlr, buf, n)){
1127 w_txdone(ctlr, WTxErrEv);
1136 w_transmit(Ether* ether)
1138 Ctlr* ctlr = ether->ctlr;
1150 w_promiscuous(void* arg, int on)
1152 Ether* ether = (Ether*)arg;
1153 Ctlr* ctlr = ether->ctlr;
1156 error("card not found");
1157 if((ctlr->state & Attached) == 0)
1158 error("card not attached");
1160 ltv_outs(ctlr, WTyp_Prom, (on?1:0));
1165 w_interrupt(Ureg* ,void* arg)
1167 Ether* ether = (Ether*) arg;
1168 Ctlr* ctlr = (Ctlr*) ether->ctlr;
1179 wavelanreset(Ether* ether, Ctlr *ctlr)
1183 iprint("wavelanreset, iob 0x%ux\n", ctlr->iob);
1185 if(w_cmd(ctlr,WCmdIni,0)){
1186 iprint("#l%d: init failed\n", ether->ctlrno);
1190 ltv_outs(ctlr, WTyp_Tick, 8);
1193 ctlr->ptype = WDfltPType;
1195 ctlr->createibss = 0;
1196 ctlr->keys.len = sizeof(WKey)*WNKeys/2 + 1;
1197 ctlr->keys.type = WTyp_Keys;
1198 if(ctlr->hascrypt = ltv_ins(ctlr, WTyp_HasCrypt))
1200 *ctlr->netname = *ctlr->wantname = 0;
1201 strcpy(ctlr->nodename, "Plan 9 STA");
1203 ctlr->netname[WNameLen-1] = 0;
1204 ctlr->wantname[WNameLen-1] = 0;
1205 ctlr->nodename[WNameLen-1] =0;
1207 ltv.type = WTyp_Mac;
1209 if(w_inltv(ctlr, <v)){
1210 iprint("#l%d: unable to read mac addr\n",
1214 memmove(ether->ea, ltv.addr, Eaddrlen);
1217 ctlr->chan = ltv_ins(ctlr, WTyp_Chan);
1218 ctlr->apdensity = WDfltApDens;
1219 ctlr->rtsthres = WDfltRtsThres;
1220 ctlr->txrate = WDfltTxRate;
1221 ctlr->maxlen = WMaxLen;
1226 ctlr->state |= Power;
1228 // free old Ctlr struct if resetting after suspend
1229 if(ether->ctlr && ether->ctlr != ctlr)
1235 ether->attach = w_attach;
1236 ether->detach = w_detach;
1237 ether->interrupt = w_interrupt;
1238 ether->transmit = w_transmit;
1239 ether->ifstat = w_ifstat;
1241 ether->power = w_power;
1242 ether->promiscuous = w_promiscuous;
1243 ether->multicast = w_multicast;
1244 ether->scanbs = w_scanbs;
1247 DEBUG("#l%d: irq %d port %lx type %s",
1248 ether->ctlrno, ether->irq, ether->port, ether->type);
1249 DEBUG(" %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux\n",
1250 ether->ea[0], ether->ea[1], ether->ea[2],
1251 ether->ea[3], ether->ea[4], ether->ea[5]);
1256 char* wavenames[] = {
1259 "Instant Wireless ; Network PC CARD",
1260 "Instant Wireless Network PC Card",
1261 "Avaya Wireless PC Card",
1263 "INTERSIL;HFA384x/IEEE;Version 01.02;",