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;
16 receive watchdog interrupts.
17 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\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)
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*, uchar*, int)
745 w_attach(Ether* ether)
754 snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
755 ctlr = (Ctlr*) ether->ctlr;
756 if((ctlr->state & Attached) == 0){
758 rc = w_enable(ether);
761 ctlr->state |= Attached;
762 kproc(name, w_timer, ether);
764 print("#l%d: enable failed\n",ether->ctlrno);
769 w_detach(Ether* ether)
774 if(ether->ctlr == nil)
777 snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
778 ctlr = (Ctlr*) ether->ctlr;
779 if(ctlr->state & Attached){
783 if(!postnote(ctlr->timerproc, 1, "kill", NExit))
784 print("timerproc note not posted\n");
785 print("w_detach, killing 0x%p\n", ctlr->timerproc);
787 ctlr->state &= ~Attached;
794 w_power(Ether* ether, int on)
798 ctlr = (Ctlr*) ether->ctlr;
800 iprint("w_power %d\n", on);
802 if((ctlr->state & Power) == 0){
803 if (wavelanreset(ether, ctlr) < 0){
804 iprint("w_power: reset failed\n");
810 if(ctlr->state & Attached)
812 ctlr->state |= Power;
815 if(ctlr->state & Power){
816 if(ctlr->state & Attached)
818 ctlr->state &= ~Power;
824 #define PRINTSTAT(fmt,val) l += snprint(p+l, READSTR-l, (fmt), (val))
825 #define PRINTSTR(fmt) l += snprint(p+l, READSTR-l, (fmt))
828 w_ifstat(Ether* ether, void* a, long n, ulong offset)
830 Ctlr *ctlr = (Ctlr*) ether->ctlr;
834 ether->oerrs = ctlr->ntxerr;
835 ether->crcs = ctlr->nrxfcserr;
837 ether->buffs = ctlr->nrxdropnobuf;
838 ether->overflows = 0;
841 // Offset must be zero or there's a possibility the
842 // new data won't match the previous read.
844 if(n == 0 || offset != 0)
850 PRINTSTAT("Signal: %d\n", ctlr->signal-149);
851 PRINTSTAT("Noise: %d\n", ctlr->noise-149);
852 PRINTSTAT("SNR: %ud\n", ctlr->signal-ctlr->noise);
853 PRINTSTAT("Interrupts: %lud\n", ctlr->nints);
854 PRINTSTAT("Double Interrupts: %lud\n", ctlr->ndoubleint);
855 PRINTSTAT("TxPackets: %lud\n", ctlr->ntx);
856 PRINTSTAT("RxPackets: %lud\n", ctlr->nrx);
857 PRINTSTAT("TxErrors: %lud\n", ctlr->ntxerr);
858 PRINTSTAT("RxErrors: %lud\n", ctlr->nrxerr);
859 PRINTSTAT("TxRequests: %lud\n", ctlr->ntxrq);
860 PRINTSTAT("AllocEvs: %lud\n", ctlr->nalloc);
861 PRINTSTAT("InfoEvs: %lud\n", ctlr->ninfo);
862 PRINTSTAT("InfoDrop: %lud\n", ctlr->nidrop);
863 PRINTSTAT("WatchDogs: %lud\n", ctlr->nwatchdogs);
864 PRINTSTAT("Ticks: %ud\n", ctlr->ticks);
865 PRINTSTAT("TickIntr: %ud\n", ctlr->tickintr);
866 k = ((ctlr->state & Attached) ? "attached" : "not attached");
867 PRINTSTAT("Card %s", k);
868 k = ((ctlr->state & Power) ? "on" : "off");
869 PRINTSTAT(", power %s", k);
870 k = ((ctlr->txbusy)? ", txbusy" : "");
871 PRINTSTAT("%s\n", k);
875 for (i = 0; i < WNKeys; i++){
876 if(ctlr->keys.keys[i].len == 0)
878 else if(SEEKEYS == 0)
881 PRINTSTAT("%s ", ctlr->keys.keys[i].dat);
888 PRINTSTR("\nCard stats: \n");
889 PRINTSTAT("Status: %ux\n", csr_ins(ctlr, WR_Sts));
890 PRINTSTAT("Event status: %ux\n", csr_ins(ctlr, WR_EvSts));
891 i = ltv_ins(ctlr, WTyp_Ptype);
892 PRINTSTAT("Port type: %d\n", i);
893 PRINTSTAT("Transmit rate: %d\n", ltv_ins(ctlr, WTyp_TxRate));
894 PRINTSTAT("Current Transmit rate: %d\n",
895 ltv_ins(ctlr, WTyp_CurTxRate));
896 PRINTSTAT("Channel: %d\n", ltv_ins(ctlr, WTyp_Chan));
897 PRINTSTAT("AP density: %d\n", ltv_ins(ctlr, WTyp_ApDens));
898 PRINTSTAT("Promiscuous mode: %d\n", ltv_ins(ctlr, WTyp_Prom));
900 PRINTSTAT("SSID name: %s\n", ltv_inname(ctlr, WTyp_NetName));
903 PRINTSTAT("Current name: %s\n", ltv_inname(ctlr, WTyp_CurName));
904 ltv.type = WTyp_BaseID;
906 if(w_inltv(ctlr, <v))
907 print("#l%d: unable to read base station mac addr\n", ether->ctlrno);
908 l += snprint(p+l, READSTR-l, "Base station: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
909 ltv.addr[0], ltv.addr[1], ltv.addr[2], ltv.addr[3], ltv.addr[4], ltv.addr[5]);
911 PRINTSTAT("Net name: %s\n", ltv_inname(ctlr, WTyp_WantName));
912 PRINTSTAT("Node name: %s\n", ltv_inname(ctlr, WTyp_NodeName));
913 if(ltv_ins(ctlr, WTyp_HasCrypt) == 0)
914 PRINTSTR("WEP: not supported\n");
916 if(ltv_ins(ctlr, WTyp_Crypt) == 0)
917 PRINTSTR("WEP: disabled\n");
919 PRINTSTR("WEP: enabled\n");
920 k = ((ctlr->xclear)? "excluded": "included");
921 PRINTSTAT("Clear packets: %s\n", k);
922 txid = ltv_ins(ctlr, WTyp_TxKey);
923 PRINTSTAT("Transmit key id: %d\n", txid);
928 PRINTSTAT("ntxuframes: %lud\n", ctlr->ntxuframes);
929 PRINTSTAT("ntxmframes: %lud\n", ctlr->ntxmframes);
930 PRINTSTAT("ntxfrags: %lud\n", ctlr->ntxfrags);
931 PRINTSTAT("ntxubytes: %lud\n", ctlr->ntxubytes);
932 PRINTSTAT("ntxmbytes: %lud\n", ctlr->ntxmbytes);
933 PRINTSTAT("ntxdeferred: %lud\n", ctlr->ntxdeferred);
934 PRINTSTAT("ntxsretries: %lud\n", ctlr->ntxsretries);
935 PRINTSTAT("ntxmultiretries: %lud\n", ctlr->ntxmultiretries);
936 PRINTSTAT("ntxretrylimit: %lud\n", ctlr->ntxretrylimit);
937 PRINTSTAT("ntxdiscards: %lud\n", ctlr->ntxdiscards);
938 PRINTSTAT("nrxuframes: %lud\n", ctlr->nrxuframes);
939 PRINTSTAT("nrxmframes: %lud\n", ctlr->nrxmframes);
940 PRINTSTAT("nrxfrags: %lud\n", ctlr->nrxfrags);
941 PRINTSTAT("nrxubytes: %lud\n", ctlr->nrxubytes);
942 PRINTSTAT("nrxmbytes: %lud\n", ctlr->nrxmbytes);
943 PRINTSTAT("nrxfcserr: %lud\n", ctlr->nrxfcserr);
944 PRINTSTAT("nrxdropnobuf: %lud\n", ctlr->nrxdropnobuf);
945 PRINTSTAT("nrxdropnosa: %lud\n", ctlr->nrxdropnosa);
946 PRINTSTAT("nrxcantdecrypt: %lud\n", ctlr->nrxcantdecrypt);
947 PRINTSTAT("nrxmsgfrag: %lud\n", ctlr->nrxmsgfrag);
948 PRINTSTAT("nrxmsgbadfrag: %lud\n", ctlr->nrxmsgbadfrag);
950 n = readstr(offset, a, n, p);
958 w_option(Ctlr* ctlr, char* buf, long n)
967 cb = parsecmd(buf, n);
970 else if(cistrcmp(cb->f[0], "essid") == 0){
971 if(cistrcmp(cb->f[1],"default") == 0)
975 if(ctlr->ptype == WPTypeAdHoc){
976 memset(ctlr->netname, 0, sizeof(ctlr->netname));
977 strncpy(ctlr->netname, p, WNameLen);
980 memset(ctlr->wantname, 0, sizeof(ctlr->wantname));
981 strncpy(ctlr->wantname, p, WNameLen);
984 else if(cistrcmp(cb->f[0], "station") == 0){
985 memset(ctlr->nodename, 0, sizeof(ctlr->nodename));
986 strncpy(ctlr->nodename, cb->f[1], WNameLen);
988 else if(cistrcmp(cb->f[0], "channel") == 0){
989 if((i = atoi(cb->f[1])) >= 1 && i <= 16)
994 else if(cistrcmp(cb->f[0], "mode") == 0){
995 if(cistrcmp(cb->f[1], "managed") == 0)
996 ctlr->ptype = WPTypeManaged;
997 else if(cistrcmp(cb->f[1], "wds") == 0)
998 ctlr->ptype = WPTypeWDS;
999 else if(cistrcmp(cb->f[1], "adhoc") == 0)
1000 ctlr->ptype = WPTypeAdHoc;
1001 else if((i = atoi(cb->f[1])) >= 1 && i <= 3)
1006 else if(cistrcmp(cb->f[0], "ibss") == 0){
1007 if(cistrcmp(cb->f[1], "on") == 0)
1008 ctlr->createibss = 1;
1010 ctlr->createibss = 0;
1012 else if(cistrcmp(cb->f[0], "crypt") == 0){
1013 if(cistrcmp(cb->f[1], "off") == 0)
1015 else if(cistrcmp(cb->f[1], "on") == 0 && ctlr->hascrypt)
1020 else if(cistrcmp(cb->f[0], "clear") == 0){
1021 if(cistrcmp(cb->f[1], "on") == 0)
1023 else if(cistrcmp(cb->f[1], "off") == 0 && ctlr->hascrypt)
1028 else if(cistrncmp(cb->f[0], "key", 3) == 0){
1029 if((i = atoi(cb->f[0]+3)) >= 1 && i <= WNKeys){
1031 key = &ctlr->keys.keys[ctlr->txkey];
1032 key->len = strlen(cb->f[1]);
1033 if(key->len > WKeyLen)
1035 memset(key->dat, 0, sizeof(key->dat));
1036 memmove(key->dat, cb->f[1], key->len);
1041 else if(cistrcmp(cb->f[0], "txkey") == 0){
1042 if((i = atoi(cb->f[1])) >= 1 && i <= WNKeys)
1047 else if(cistrcmp(cb->f[0], "pm") == 0){
1048 if(cistrcmp(cb->f[1], "off") == 0)
1050 else if(cistrcmp(cb->f[1], "on") == 0){
1054 // check range here? what are the units?
1069 w_ctl(Ether* ether, void* buf, long n)
1073 if((ctlr = ether->ctlr) == nil)
1075 if((ctlr->state & Attached) == 0)
1079 if(w_option(ctlr, buf, n)){
1084 w_txdone(ctlr, WTxErrEv);
1093 w_transmit(Ether* ether)
1095 Ctlr* ctlr = ether->ctlr;
1107 w_promiscuous(void* arg, int on)
1109 Ether* ether = (Ether*)arg;
1110 Ctlr* ctlr = ether->ctlr;
1113 error("card not found");
1114 if((ctlr->state & Attached) == 0)
1115 error("card not attached");
1117 ltv_outs(ctlr, WTyp_Prom, (on?1:0));
1122 w_interrupt(Ureg* ,void* arg)
1124 Ether* ether = (Ether*) arg;
1125 Ctlr* ctlr = (Ctlr*) ether->ctlr;
1136 wavelanreset(Ether* ether, Ctlr *ctlr)
1140 iprint("wavelanreset, iob 0x%ux\n", ctlr->iob);
1142 if(w_cmd(ctlr,WCmdIni,0)){
1143 iprint("#l%d: init failed\n", ether->ctlrno);
1147 ltv_outs(ctlr, WTyp_Tick, 8);
1150 ctlr->ptype = WDfltPType;
1152 ctlr->createibss = 0;
1153 ctlr->keys.len = sizeof(WKey)*WNKeys/2 + 1;
1154 ctlr->keys.type = WTyp_Keys;
1155 if(ctlr->hascrypt = ltv_ins(ctlr, WTyp_HasCrypt))
1157 *ctlr->netname = *ctlr->wantname = 0;
1158 strcpy(ctlr->nodename, "Plan 9 STA");
1160 ctlr->netname[WNameLen-1] = 0;
1161 ctlr->wantname[WNameLen-1] = 0;
1162 ctlr->nodename[WNameLen-1] =0;
1164 ltv.type = WTyp_Mac;
1166 if(w_inltv(ctlr, <v)){
1167 iprint("#l%d: unable to read mac addr\n",
1171 memmove(ether->ea, ltv.addr, Eaddrlen);
1174 ctlr->chan = ltv_ins(ctlr, WTyp_Chan);
1175 ctlr->apdensity = WDfltApDens;
1176 ctlr->rtsthres = WDfltRtsThres;
1177 ctlr->txrate = WDfltTxRate;
1178 ctlr->maxlen = WMaxLen;
1183 ctlr->state |= Power;
1185 // free old Ctlr struct if resetting after suspend
1186 if(ether->ctlr && ether->ctlr != ctlr)
1192 ether->attach = w_attach;
1193 ether->detach = w_detach;
1194 ether->interrupt = w_interrupt;
1195 ether->transmit = w_transmit;
1196 ether->ifstat = w_ifstat;
1198 ether->power = w_power;
1199 ether->promiscuous = w_promiscuous;
1200 ether->multicast = w_multicast;
1201 ether->scanbs = w_scanbs;
1204 DEBUG("#l%d: irq %lud port %lx type %s",
1205 ether->ctlrno, ether->intnum, ether->ports[0].port, ether->type);
1206 DEBUG(" %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux\n",
1207 ether->ea[0], ether->ea[1], ether->ea[2],
1208 ether->ea[3], ether->ea[4], ether->ea[5]);
1213 char* wavenames[] = {
1216 "Instant Wireless ; Network PC CARD",
1217 "Instant Wireless Network PC Card",
1218 "Avaya Wireless PC Card",