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;
686 tsleep(&up->sleep, return0, 0, MSperTick);
687 ctlr = (Ctlr*)ether->ctlr;
690 if((ctlr->state & (Attached|Power)) != (Attached|Power))
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
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.
711 if(csr_ins(ctlr, WR_EvSts)&WEvs){
716 if((ctlr->ticks % 10) == 0) {
717 if(ctlr->txtmout && --ctlr->txtmout == 0){
719 w_txdone(ctlr, WTxErrEv);
721 DEBUG("wavelan: wdog enable failed\n");
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);
735 pexit("terminated", 0);
739 w_multicast(void *ether, uchar*, int add)
741 /* BUG: use controller's multicast filter */
743 w_promiscuous(ether, 1);
747 w_attach(Ether* ether)
756 snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
757 ctlr = (Ctlr*) ether->ctlr;
758 if((ctlr->state & Attached) == 0){
760 rc = w_enable(ether);
763 ctlr->state |= Attached;
764 kproc(name, w_timer, ether);
766 print("#l%d: enable failed\n",ether->ctlrno);
771 w_detach(Ether* ether)
776 if(ether->ctlr == nil)
779 snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
780 ctlr = (Ctlr*) ether->ctlr;
781 if(ctlr->state & Attached){
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);
789 ctlr->state &= ~Attached;
796 w_power(Ether* ether, int on)
800 ctlr = (Ctlr*) ether->ctlr;
802 iprint("w_power %d\n", on);
804 if((ctlr->state & Power) == 0){
805 if (wavelanreset(ether, ctlr) < 0){
806 iprint("w_power: reset failed\n");
812 if(ctlr->state & Attached)
814 ctlr->state |= Power;
817 if(ctlr->state & Power){
818 if(ctlr->state & Attached)
820 ctlr->state &= ~Power;
826 #define PRINTSTAT(fmt,val) l += snprint(p+l, READSTR-l, (fmt), (val))
827 #define PRINTSTR(fmt) l += snprint(p+l, READSTR-l, (fmt))
830 w_ifstat(Ether* ether, void* a, long n, ulong offset)
832 Ctlr *ctlr = (Ctlr*) ether->ctlr;
836 ether->oerrs = ctlr->ntxerr;
837 ether->crcs = ctlr->nrxfcserr;
839 ether->buffs = ctlr->nrxdropnobuf;
840 ether->overflows = 0;
843 // Offset must be zero or there's a possibility the
844 // new data won't match the previous read.
846 if(n == 0 || offset != 0)
849 p = smalloc(READSTR);
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);
877 for (i = 0; i < WNKeys; i++){
878 if(ctlr->keys.keys[i].len == 0)
880 else if(SEEKEYS == 0)
883 PRINTSTAT("%s ", ctlr->keys.keys[i].dat);
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));
902 PRINTSTAT("SSID name: %s\n", ltv_inname(ctlr, WTyp_NetName));
905 PRINTSTAT("Current name: %s\n", ltv_inname(ctlr, WTyp_CurName));
906 ltv.type = WTyp_BaseID;
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]);
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");
918 if(ltv_ins(ctlr, WTyp_Crypt) == 0)
919 PRINTSTR("WEP: disabled\n");
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);
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);
952 n = readstr(offset, a, n, p);
960 parsekey(WKey* key, char* a)
963 char buf[WMaxKeyLen];
966 if(len == WMinKeyLen || len == WMaxKeyLen){
967 memset(key->dat, 0, sizeof(key->dat));
968 memmove(key->dat, a, len);
973 else if(len == WMinKeyLen*2 || len == WMaxKeyLen*2){
975 for(i = 0; i < len; i++){
976 if(*a >= '0' && *a <= '9')
978 else if(*a >= 'a' && *a <= 'f')
980 else if(*a >= 'A' && *a <= 'F')
993 memset(key->dat, 0, sizeof(key->dat));
994 memmove(key->dat, buf, k);
1004 w_option(Ctlr* ctlr, char* buf, long n)
1012 cb = parsecmd(buf, n);
1015 else if(cistrcmp(cb->f[0], "essid") == 0){
1016 if(cistrcmp(cb->f[1],"default") == 0)
1020 if(ctlr->ptype == WPTypeAdHoc){
1021 memset(ctlr->netname, 0, sizeof(ctlr->netname));
1022 strncpy(ctlr->netname, p, WNameLen);
1025 memset(ctlr->wantname, 0, sizeof(ctlr->wantname));
1026 strncpy(ctlr->wantname, p, WNameLen);
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);
1033 else if(cistrcmp(cb->f[0], "channel") == 0){
1034 if((i = atoi(cb->f[1])) >= 1 && i <= 16)
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)
1051 else if(cistrcmp(cb->f[0], "ibss") == 0){
1052 if(cistrcmp(cb->f[1], "on") == 0)
1053 ctlr->createibss = 1;
1055 ctlr->createibss = 0;
1057 else if(cistrcmp(cb->f[0], "crypt") == 0){
1058 if(cistrcmp(cb->f[1], "off") == 0)
1060 else if(cistrcmp(cb->f[1], "on") == 0 && ctlr->hascrypt)
1065 else if(cistrcmp(cb->f[0], "clear") == 0){
1066 if(cistrcmp(cb->f[1], "on") == 0)
1068 else if(cistrcmp(cb->f[1], "off") == 0 && ctlr->hascrypt)
1073 else if(cistrncmp(cb->f[0], "key", 3) == 0){
1074 if((i = atoi(cb->f[0]+3)) >= 1 && i <= WNKeys){
1076 if(parsekey(&ctlr->keys.keys[ctlr->txkey], cb->f[1]))
1082 else if(cistrcmp(cb->f[0], "txkey") == 0){
1083 if((i = atoi(cb->f[1])) >= 1 && i <= WNKeys)
1088 else if(cistrcmp(cb->f[0], "pm") == 0){
1089 if(cistrcmp(cb->f[1], "off") == 0)
1091 else if(cistrcmp(cb->f[1], "on") == 0){
1095 // check range here? what are the units?
1110 w_ctl(Ether* ether, void* buf, long n)
1114 if((ctlr = ether->ctlr) == nil)
1116 if((ctlr->state & Attached) == 0)
1120 if(w_option(ctlr, buf, n)){
1125 w_txdone(ctlr, WTxErrEv);
1134 w_transmit(Ether* ether)
1136 Ctlr* ctlr = ether->ctlr;
1148 w_promiscuous(void* arg, int on)
1150 Ether* ether = (Ether*)arg;
1151 Ctlr* ctlr = ether->ctlr;
1154 error("card not found");
1155 if((ctlr->state & Attached) == 0)
1156 error("card not attached");
1158 ltv_outs(ctlr, WTyp_Prom, (on?1:0));
1163 w_interrupt(Ureg* ,void* arg)
1165 Ether* ether = (Ether*) arg;
1166 Ctlr* ctlr = (Ctlr*) ether->ctlr;
1177 wavelanreset(Ether* ether, Ctlr *ctlr)
1181 iprint("wavelanreset, iob 0x%ux\n", ctlr->iob);
1183 if(w_cmd(ctlr,WCmdIni,0)){
1184 iprint("#l%d: init failed\n", ether->ctlrno);
1188 ltv_outs(ctlr, WTyp_Tick, 8);
1191 ctlr->ptype = WDfltPType;
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))
1198 *ctlr->netname = *ctlr->wantname = 0;
1199 strcpy(ctlr->nodename, "Plan 9 STA");
1201 ctlr->netname[WNameLen-1] = 0;
1202 ctlr->wantname[WNameLen-1] = 0;
1203 ctlr->nodename[WNameLen-1] =0;
1205 ltv.type = WTyp_Mac;
1207 if(w_inltv(ctlr, <v)){
1208 iprint("#l%d: unable to read mac addr\n",
1212 memmove(ether->ea, ltv.addr, Eaddrlen);
1215 ctlr->chan = ltv_ins(ctlr, WTyp_Chan);
1216 ctlr->apdensity = WDfltApDens;
1217 ctlr->rtsthres = WDfltRtsThres;
1218 ctlr->txrate = WDfltTxRate;
1219 ctlr->maxlen = WMaxLen;
1224 ctlr->state |= Power;
1226 // free old Ctlr struct if resetting after suspend
1227 if(ether->ctlr && ether->ctlr != ctlr)
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;
1239 ether->power = w_power;
1240 ether->promiscuous = w_promiscuous;
1241 ether->multicast = w_multicast;
1242 ether->scanbs = w_scanbs;
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]);
1254 char* wavenames[] = {
1257 "Instant Wireless ; Network PC CARD",
1258 "Instant Wireless Network PC Card",
1259 "Avaya Wireless PC Card",
1261 "INTERSIL;HFA384x/IEEE;Version 01.02;",