## diffname pc/wavelan.c 1999/0623 ## diff -e /dev/null /n/emeliedump/1999/0623/sys/src/brazil/pc/wavelan.c 0a #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" extern Dev rootdevtab; extern Dev consdevtab; extern Dev envdevtab; extern Dev pipedevtab; extern Dev procdevtab; extern Dev mntdevtab; extern Dev srvdevtab; extern Dev dupdevtab; extern Dev rtcdevtab; extern Dev ssldevtab; extern Dev mntstatsdevtab; extern Dev etherdevtab; extern Dev ipdevtab; extern Dev drawdevtab; extern Dev mousedevtab; extern Dev vgadevtab; extern Dev scsidevtab; extern Dev cddevtab; extern Dev sddevtab; extern Dev atadevtab; extern Dev floppydevtab; extern Dev audiodevtab; extern Dev i82365devtab; extern Dev lptdevtab; extern Dev ns16552devtab; extern Dev lmldevtab; Dev* devtab[]={ &rootdevtab, &consdevtab, &envdevtab, &pipedevtab, &procdevtab, &mntdevtab, &srvdevtab, &dupdevtab, &rtcdevtab, &ssldevtab, &mntstatsdevtab, ðerdevtab, &ipdevtab, &drawdevtab, &mousedevtab, &vgadevtab, &scsidevtab, &cddevtab, &sddevtab, &atadevtab, &floppydevtab, &audiodevtab, &i82365devtab, &lptdevtab, &ns16552devtab, &lmldevtab, nil, }; extern void ether2000link(void); extern void ether2114xlink(void); extern void ether589link(void); extern void ether79c970link(void); extern void ether8003link(void); extern void ether82557link(void); extern void etherelnk3link(void); extern void etherwavelanlink(void); extern void ethermediumlink(void); void links(void){ ether2000link(); ether2114xlink(); ether589link(); ether79c970link(); ether8003link(); ether82557link(); etherelnk3link(); etherwavelanlink(); ethermediumlink(); } extern PCArch archgeneric; extern PCArch archmp; PCArch* knownarch[] = { &archgeneric, &archmp, nil, }; extern SCSIdev scsibuslogicdev; SCSIdev* scsidev[] = { &scsibuslogicdev, nil, }; #define Image IMAGE #include #include #include #include "screen.h" extern VGAdev vgaark2000pvdev; extern VGAdev vgaclgd542xdev; extern VGAdev vgact65545dev; extern VGAdev vgamach64xxdev; extern VGAdev vgamga2164wdev; extern VGAdev vgas3dev; VGAdev* vgadev[] = { &vgaark2000pvdev, &vgaclgd542xdev, &vgact65545dev, &vgamach64xxdev, &vgamga2164wdev, &vgas3dev, nil, }; extern VGAcur vgaark2000pvcur; extern VGAcur vgabt485cur; extern VGAcur vgaclgd542xcur; extern VGAcur vgact65545cur; extern VGAcur vgamach64xxcur; extern VGAcur vgamga2164wcur; extern VGAcur vgargb524cur; extern VGAcur vgas3cur; extern VGAcur vgatvp3020cur; extern VGAcur vgatvp3026cur; VGAcur* vgacur[] = { &vgaark2000pvcur, &vgabt485cur, &vgaclgd542xcur, &vgact65545cur, &vgamach64xxcur, &vgamga2164wcur, &vgargb524cur, &vgas3cur, &vgatvp3020cur, &vgatvp3026cur, nil, }; #include "../ip/ip.h" extern void ilinit(Fs*); extern void tcpinit(Fs*); extern void udpinit(Fs*); extern void rudpinit(Fs*); extern void ipifcinit(Fs*); extern void icmpinit(Fs*); extern void greinit(Fs*); extern void ipmuxinit(Fs*); void (*ipprotoinit[])(Fs*) = { ilinit, tcpinit, udpinit, rudpinit, ipifcinit, icmpinit, greinit, ipmuxinit, nil, }; int cpuserver = 0; char* conffile = "wavelan"; ulong kerndate = KERNDATE; . ## diffname pc/wavelan.c 2002/0606 ## diff -e /n/emeliedump/1999/0623/sys/src/brazil/pc/wavelan.c /n/emeliedump/2002/0606/sys/src/9/pc/wavelan.c 166,168d 145,162c if(ctlr->mmb){ rp = dat; wp = &ctlr->mmb[reg]; while(ndat-- > 0) *wp = *rp++; }else outss(ctlr->iob+reg, dat, ndat); } // w_... routines do not ilock the Ctlr and should // be called locked. void w_intdis(Ctlr* ctlr) { csr_outs(ctlr, WR_IntEna, 0); csr_ack(ctlr, 0xffff); } static void w_intena(Ctlr* ctlr) { csr_outs(ctlr, WR_IntEna, WEvs); } int w_cmd(Ctlr *ctlr, ushort cmd, ushort arg) { int i, rc; for(i=0; ictlrno, cmd, csr_ins(ctlr, WR_Cmd)); return -1; } csr_outs(ctlr, WR_Parm0, arg); csr_outs(ctlr, WR_Cmd, cmd); for(i=0; ictlrno, cmd, i); if(i == IniTmOut){ print("#l%d: execing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_EvSts)); return -1; } } rc = csr_ins(ctlr, WR_Sts); csr_ack(ctlr, WCmdEv); if((rc&WCmdMsk) != (cmd&WCmdMsk)){ print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc); return -1; } if(rc&WResSts){ /* * Don't print; this happens on every WCmdAccWr for some reason. */ if(0) print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc); return -1; } return 0; } static int w_seek(Ctlr* ctlr, ushort id, ushort offset, int chan) { int i, rc; static ushort sel[] = { WR_Sel0, WR_Sel1 }; static ushort off[] = { WR_Off0, WR_Off1 }; if (chan != 0 && chan != 1) panic("wavelan: bad chan\n"); csr_outs(ctlr, sel[chan], id); csr_outs(ctlr, off[chan], offset); for (i=0; itype)){ DEBUG("wavelan: access read failed\n"); return -1; } if (w_seek(ctlr,ltv->type,0,1)){ DEBUG("wavelan: seek failed\n"); return -1; } len = csr_ins(ctlr, WR_Data1); if (len > ltv->len) return -1; ltv->len = len; if ((code=csr_ins(ctlr, WR_Data1)) != ltv->type){ USED(code); DEBUG("wavelan: type %x != code %x\n",ltv->type,code); return -1; } if(ltv->len > 0) csr_inss(ctlr, WR_Data1, <v->val, ltv->len-1); return 0; } static void w_outltv(Ctlr* ctlr, Wltv* ltv) { if(w_seek(ctlr,ltv->type, 0, 1)) return; csr_outss(ctlr, WR_Data1, ltv, ltv->len+1); w_cmd(ctlr, WCmdAccWr, ltv->type); } void ltv_outs(Ctlr* ctlr, int type, ushort val) { Wltv ltv; ltv.len = 2; ltv.type = type; ltv.val = val; w_outltv(ctlr, <v); } int ltv_ins(Ctlr* ctlr, int type) { Wltv ltv; ltv.len = 2; ltv.type = type; ltv.val = 0; if(w_inltv(ctlr, <v)) return -1; return ltv.val; } static void ltv_outstr(Ctlr* ctlr, int type, char* val) { Wltv ltv; int len; len = strlen(val); if(len > sizeof(ltv.s)) len = sizeof(ltv.s); memset(<v, 0, sizeof(ltv)); ltv.len = (sizeof(ltv.type)+sizeof(ltv.slen)+sizeof(ltv.s))/2; ltv.type = type; // This should be ltv.slen = len; according to Axel Belinfante ltv.slen = len; strncpy(ltv.s, val, len); w_outltv(ctlr, <v); } static char Unkname[] = "who knows"; static char Nilname[] = "card does not tell"; static char* ltv_inname(Ctlr* ctlr, int type) { static Wltv ltv; int len; memset(<v,0,sizeof(ltv)); ltv.len = WNameLen/2+2; ltv.type = type; if (w_inltv(ctlr, <v)) return Unkname; len = ltv.slen; if(len == 0 || ltv.s[0] == 0) return Nilname; if(len >= sizeof ltv.s) len = sizeof ltv.s - 1; ltv.s[len] = '\0'; return ltv.s; } static int w_read(Ctlr* ctlr, int type, int off, void* buf, ulong len) { if (w_seek(ctlr, type, off, 1)){ DEBUG("wavelan: w_read: seek failed"); return 0; } csr_inss(ctlr, WR_Data1, buf, len/2); return len; } static int w_write(Ctlr* ctlr, int type, int off, void* buf, ulong len) { int tries; for (tries=0; tries < WTmOut; tries++){ if (w_seek(ctlr, type, off, 0)){ DEBUG("wavelan: w_write: seek failed\n"); return 0; } csr_outss(ctlr, WR_Data0, buf, len/2); csr_outs(ctlr, WR_Data0, 0xdead); csr_outs(ctlr, WR_Data0, 0xbeef); if (w_seek(ctlr, type, off + len, 0)){ DEBUG("wavelan: write seek failed\n"); return 0; } if (csr_ins(ctlr, WR_Data0) == 0xdead) if (csr_ins(ctlr, WR_Data0) == 0xbeef) return len; DEBUG("wavelan: Hermes bug byte.\n"); return 0; } DEBUG("wavelan: tx timeout\n"); return 0; } static int w_alloc(Ctlr* ctlr, int len) { int rc; int i,j; if (w_cmd(ctlr, WCmdMalloc, len)==0) for (i = 0; ictlr; if (!ctlr) return -1; w_intdis(ctlr); w_cmd(ctlr, WCmdDis, 0); w_intdis(ctlr); if(w_cmd(ctlr, WCmdIni, 0)) return -1; w_intdis(ctlr); ltv_outs(ctlr, WTyp_Tick, 8); ltv_outs(ctlr, WTyp_MaxLen, ctlr->maxlen); ltv_outs(ctlr, WTyp_Ptype, ctlr->ptype); ltv_outs(ctlr, WTyp_CreateIBSS, ctlr->createibss); ltv_outs(ctlr, WTyp_RtsThres, ctlr->rtsthres); ltv_outs(ctlr, WTyp_TxRate, ctlr->txrate); ltv_outs(ctlr, WTyp_ApDens, ctlr->apdensity); ltv_outs(ctlr, WTyp_PMWait, ctlr->pmwait); ltv_outs(ctlr, WTyp_PM, ctlr->pmena); if (*ctlr->netname) ltv_outstr(ctlr, WTyp_NetName, ctlr->netname); if (*ctlr->wantname) ltv_outstr(ctlr, WTyp_WantName, ctlr->wantname); ltv_outs(ctlr, WTyp_Chan, ctlr->chan); if (*ctlr->nodename) ltv_outstr(ctlr, WTyp_NodeName, ctlr->nodename); ltv.len = 4; ltv.type = WTyp_Mac; memmove(ltv.addr, ether->ea, Eaddrlen); w_outltv(ctlr, <v); ltv_outs(ctlr, WTyp_Prom, (ether->prom?1:0)); if (ctlr->hascrypt){ ltv_outs(ctlr, WTyp_Crypt, ctlr->crypt); ltv_outs(ctlr, WTyp_TxKey, ctlr->txkey); w_outltv(ctlr, &ctlr->keys); ltv_outs(ctlr, WTyp_XClear, ctlr->xclear); } // BUG: set multicast addresses if (w_cmd(ctlr, WCmdEna, 0)){ DEBUG("wavelan: Enable failed"); return -1; } ctlr->txdid = w_alloc(ctlr, 1518 + sizeof(WFrame) + 8); ctlr->txmid = w_alloc(ctlr, 1518 + sizeof(WFrame) + 8); if (ctlr->txdid == -1 || ctlr->txmid == -1) DEBUG("wavelan: alloc failed"); ctlr->txbusy = 0; w_intena(ctlr); return 0; } static void w_rxdone(Ether* ether) { Ctlr* ctlr = (Ctlr*) ether->ctlr; int len, sp; WFrame f; Block* bp=0; Etherpkt* ep; sp = csr_ins(ctlr, WR_RXId); len = w_read(ctlr, sp, 0, &f, sizeof(f)); if (len == 0){ DEBUG("wavelan: read frame error\n"); goto rxerror; } if (f.sts&WF_Err){ goto rxerror; } switch(f.sts){ case WF_1042: case WF_Tunnel: case WF_WMP: len = f.dlen + WSnapHdrLen; bp = iallocb(ETHERHDRSIZE + len + 2); if (!bp) goto rxerror; ep = (Etherpkt*) bp->wp; memmove(ep->d, f.addr1, Eaddrlen); memmove(ep->s, f.addr2, Eaddrlen); memmove(ep->type,&f.type,2); bp->wp += ETHERHDRSIZE; if (w_read(ctlr, sp, WF_802_11_Off, bp->wp, len+2) == 0){ DEBUG("wavelan: read 802.11 error\n"); goto rxerror; } bp->wp = bp->rp+(ETHERHDRSIZE+f.dlen); break; default: len = ETHERHDRSIZE + f.dlen + 2; bp = iallocb(len); if (!bp) goto rxerror; if (w_read(ctlr, sp, WF_802_3_Off, bp->wp, len) == 0){ DEBUG("wavelan: read 800.3 error\n"); goto rxerror; } bp->wp += len; } ctlr->nrx++; etheriq(ether,bp,1); ctlr->signal = ((ctlr->signal*15)+((f.qinfo>>8) & 0xFF))/16; ctlr->noise = ((ctlr->noise*15)+(f.qinfo & 0xFF))/16; return; rxerror: freeb(bp); ctlr->nrxerr++; } static void w_txstart(Ether* ether) { Etherpkt *pkt; Ctlr *ctlr; Block *bp; int len, off; if((ctlr = ether->ctlr) == nil || ctlr->attached == 0 || ctlr->txbusy) return; if((bp = qget(ether->oq)) == nil) return; pkt = (Etherpkt*)bp->rp; // // If the packet header type field is > 1500 it is an IP or // ARP datagram, otherwise it is an 802.3 packet. See RFC1042. // memset(&ctlr->txf, 0, sizeof(ctlr->txf)); if(((pkt->type[0]<<8)|pkt->type[1]) > 1500){ ctlr->txf.framectl = WF_Data; memmove(ctlr->txf.addr1, pkt->d, Eaddrlen); memmove(ctlr->txf.addr2, pkt->s, Eaddrlen); memmove(ctlr->txf.dstaddr, pkt->d, Eaddrlen); memmove(ctlr->txf.srcaddr, pkt->s, Eaddrlen); memmove(&ctlr->txf.type, pkt->type, 2); bp->rp += ETHERHDRSIZE; len = BLEN(bp); off = WF_802_11_Off; ctlr->txf.dlen = len+ETHERHDRSIZE-WSnapHdrLen; hnputs((uchar*)&ctlr->txf.dat[0], WSnap0); hnputs((uchar*)&ctlr->txf.dat[1], WSnap1); hnputs((uchar*)&ctlr->txf.len, len+ETHERHDRSIZE-WSnapHdrLen); } else{ len = BLEN(bp); off = WF_802_3_Off; ctlr->txf.dlen = len; } w_write(ctlr, ctlr->txdid, 0, &ctlr->txf, sizeof(ctlr->txf)); w_write(ctlr, ctlr->txdid, off, bp->rp, len+2); if(w_cmd(ctlr, WCmdReclaim|WCmdTx, ctlr->txdid)){ DEBUG("wavelan: transmit failed\n"); ctlr->ntxerr++; } else{ ctlr->txbusy = 1; ctlr->txtmout = 2; } freeb(bp); } static void w_txdone(Ctlr* ctlr, int sts) { ctlr->txbusy = 0; ctlr->txtmout = 0; if (sts & WTxErrEv) ctlr->ntxerr++; else ctlr->ntx++; } static int w_stats(Ctlr* ctlr) { int i, rc, sp; Wltv ltv; ulong* p = (ulong*)&ctlr->WStats; ulong* pend = (ulong*)&ctlr->end; sp = csr_ins(ctlr, WR_InfoId); ltv.len = ltv.type = 0; w_read(ctlr, sp, 0, <v, 4); if (ltv.type == WTyp_Stats){ ltv.len--; for (i = 0; i < ltv.len && p < pend; i++){ rc = csr_ins(ctlr, WR_Data1); if (rc > 0xf000) rc = ~rc & 0xffff; p[i] += rc; } return 0; } return -1; } static void w_intr(Ether *ether) { int rc, txid; Ctlr* ctlr = (Ctlr*) ether->ctlr; if (ctlr->attached == 0){ csr_ack(ctlr, 0xffff); csr_outs(ctlr, WR_IntEna, 0); return; } rc = csr_ins(ctlr, WR_EvSts); csr_ack(ctlr, ~WEvs); // Not interested in them if (rc & WRXEv){ w_rxdone(ether); csr_ack(ctlr, WRXEv); } if (rc & WTXEv){ w_txdone(ctlr, rc); csr_ack(ctlr, WTXEv); } if (rc & WAllocEv){ ctlr->nalloc++; txid = csr_ins(ctlr, WR_Alloc); csr_ack(ctlr, WAllocEv); if (txid == ctlr->txdid){ if ((rc & WTXEv) == 0) w_txdone(ctlr, rc); } } if (rc & WInfoEv){ ctlr->ninfo++; w_stats(ctlr); csr_ack(ctlr, WInfoEv); } if (rc & WTxErrEv){ w_txdone(ctlr, rc); csr_ack(ctlr, WTxErrEv); } if (rc & WIDropEv){ ctlr->nidrop++; csr_ack(ctlr, WIDropEv); } w_txstart(ether); } // Watcher to ensure that the card still works properly and // to request WStats updates once a minute. // BUG: it runs much more often, see the comment below. static void w_timer(void* arg) { Ether* ether = (Ether*) arg; Ctlr* ctlr = (Ctlr*)ether->ctlr; for(;;){ tsleep(&ctlr->timer, return0, 0, 50); ctlr = (Ctlr*)ether->ctlr; if (ctlr == 0) break; if (ctlr->attached == 0) continue; ctlr->ticks++; ilock(ctlr); // Seems that the card gets frames BUT does // not send the interrupt; this is a problem because // I suspect it runs out of receive buffers and // stops receiving until a transmit watchdog // reenables the card. // The problem is serious because it leads to // poor rtts. // This can be seen clearly by commenting out // the next if and doing a ping: it will stop // receiving (although the icmp replies are being // issued from the remote) after a few seconds. // Of course this `bug' could be because I'm reading // the card frames in the wrong way; due to the // lack of documentation I cannot know. if (csr_ins(ctlr, WR_EvSts)&WEvs){ ctlr->tickintr++; w_intr(ether); } if ((ctlr->ticks % 10) == 0) { if (ctlr->txtmout && --ctlr->txtmout == 0){ ctlr->nwatchdogs++; w_txdone(ctlr, WTxErrEv); if (w_enable(ether)){ DEBUG("wavelan: wdog enable failed\n"); } w_txstart(ether); } if ((ctlr->ticks % 120) == 0) if (ctlr->txbusy == 0) w_cmd(ctlr, WCmdAskStats, WTyp_Stats); } iunlock(ctlr); } pexit("terminated",0); } void w_multicast(void*, uchar*, int) { // BUG: to be added. } void w_attach(Ether* ether) { Ctlr* ctlr; char name[64]; int rc; if (ether->ctlr == 0) return; snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno); ctlr = (Ctlr*) ether->ctlr; if (ctlr->attached == 0){ ilock(ctlr); rc = w_enable(ether); iunlock(ctlr); if(rc == 0){ ctlr->attached = 1; kproc(name, w_timer, ether); } else print("#l%d: enable failed\n",ether->ctlrno); } } #define PRINTSTAT(fmt,val) l += snprint(p+l, READSTR-l, (fmt), (val)) #define PRINTSTR(fmt) l += snprint(p+l, READSTR-l, (fmt)) long w_ifstat(Ether* ether, void* a, long n, ulong offset) { Ctlr *ctlr = (Ctlr*) ether->ctlr; char *k, *p; int i, l, txid; ether->oerrs = ctlr->ntxerr; ether->crcs = ctlr->nrxfcserr; ether->frames = 0; ether->buffs = ctlr->nrxdropnobuf; ether->overflows = 0; // // Offset must be zero or there's a possibility the // new data won't match the previous read. // if(n == 0 || offset != 0) return 0; p = malloc(READSTR); l = 0; PRINTSTAT("Signal: %d\n", ctlr->signal-149); PRINTSTAT("Noise: %d\n", ctlr->noise-149); PRINTSTAT("SNR: %ud\n", ctlr->signal-ctlr->noise); PRINTSTAT("Interrupts: %lud\n", ctlr->nints); PRINTSTAT("Double Interrupts: %lud\n", ctlr->ndoubleint); PRINTSTAT("TxPackets: %lud\n", ctlr->ntx); PRINTSTAT("RxPackets: %lud\n", ctlr->nrx); PRINTSTAT("TxErrors: %lud\n", ctlr->ntxerr); PRINTSTAT("RxErrors: %lud\n", ctlr->nrxerr); PRINTSTAT("TxRequests: %lud\n", ctlr->ntxrq); PRINTSTAT("AllocEvs: %lud\n", ctlr->nalloc); PRINTSTAT("InfoEvs: %lud\n", ctlr->ninfo); PRINTSTAT("InfoDrop: %lud\n", ctlr->nidrop); PRINTSTAT("WatchDogs: %lud\n", ctlr->nwatchdogs); PRINTSTAT("Ticks: %ud\n", ctlr->ticks); PRINTSTAT("TickIntr: %ud\n", ctlr->tickintr); k = ((ctlr->attached) ? "attached" : "not attached"); PRINTSTAT("Card %s", k); k = ((ctlr->txbusy)? ", txbusy" : ""); PRINTSTAT("%s\n", k); if (ctlr->hascrypt){ PRINTSTR("Keys: "); for (i = 0; i < WNKeys; i++){ if (ctlr->keys.keys[i].len == 0) PRINTSTR("none "); else if (SEEKEYS == 0) PRINTSTR("set "); else PRINTSTAT("%s ", ctlr->keys.keys[i].dat); } PRINTSTR("\n"); } // real card stats ilock(ctlr); PRINTSTR("\nCard stats: \n"); PRINTSTAT("Status: %ux\n", csr_ins(ctlr, WR_Sts)); PRINTSTAT("Event status: %ux\n", csr_ins(ctlr, WR_EvSts)); i = ltv_ins(ctlr, WTyp_Ptype); PRINTSTAT("Port type: %d\n", i); PRINTSTAT("Transmit rate: %d\n", ltv_ins(ctlr, WTyp_TxRate)); PRINTSTAT("Current Transmit rate: %d\n", ltv_ins(ctlr, WTyp_CurTxRate)); PRINTSTAT("Channel: %d\n", ltv_ins(ctlr, WTyp_Chan)); PRINTSTAT("AP density: %d\n", ltv_ins(ctlr, WTyp_ApDens)); PRINTSTAT("Promiscuous mode: %d\n", ltv_ins(ctlr, WTyp_Prom)); if(i == 3) PRINTSTAT("SSID name: %s\n", ltv_inname(ctlr, WTyp_NetName)); else { Wltv ltv; PRINTSTAT("Current name: %s\n", ltv_inname(ctlr, WTyp_CurName)); ltv.type = WTyp_BaseID; ltv.len = 4; if (w_inltv(ctlr, <v)) print("#l%d: unable to read base station mac addr\n", ether->ctlrno); l += snprint(p+l, READSTR-l, "Base station: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", ltv.addr[0], ltv.addr[1], ltv.addr[2], ltv.addr[3], ltv.addr[4], ltv.addr[5]); } PRINTSTAT("Net name: %s\n", ltv_inname(ctlr, WTyp_WantName)); PRINTSTAT("Node name: %s\n", ltv_inname(ctlr, WTyp_NodeName)); if (ltv_ins(ctlr, WTyp_HasCrypt) == 0) PRINTSTR("WEP: not supported\n"); else { if (ltv_ins(ctlr, WTyp_Crypt) == 0) PRINTSTR("WEP: disabled\n"); else{ PRINTSTR("WEP: enabled\n"); k = ((ctlr->xclear)? "excluded": "included"); PRINTSTAT("Clear packets: %s\n", k); txid = ltv_ins(ctlr, WTyp_TxKey); PRINTSTAT("Transmit key id: %d\n", txid); } } iunlock(ctlr); PRINTSTAT("ntxuframes: %lud\n", ctlr->ntxuframes); PRINTSTAT("ntxmframes: %lud\n", ctlr->ntxmframes); PRINTSTAT("ntxfrags: %lud\n", ctlr->ntxfrags); PRINTSTAT("ntxubytes: %lud\n", ctlr->ntxubytes); PRINTSTAT("ntxmbytes: %lud\n", ctlr->ntxmbytes); PRINTSTAT("ntxdeferred: %lud\n", ctlr->ntxdeferred); PRINTSTAT("ntxsretries: %lud\n", ctlr->ntxsretries); PRINTSTAT("ntxmultiretries: %lud\n", ctlr->ntxmultiretries); PRINTSTAT("ntxretrylimit: %lud\n", ctlr->ntxretrylimit); PRINTSTAT("ntxdiscards: %lud\n", ctlr->ntxdiscards); PRINTSTAT("nrxuframes: %lud\n", ctlr->nrxuframes); PRINTSTAT("nrxmframes: %lud\n", ctlr->nrxmframes); PRINTSTAT("nrxfrags: %lud\n", ctlr->nrxfrags); PRINTSTAT("nrxubytes: %lud\n", ctlr->nrxubytes); PRINTSTAT("nrxmbytes: %lud\n", ctlr->nrxmbytes); PRINTSTAT("nrxfcserr: %lud\n", ctlr->nrxfcserr); PRINTSTAT("nrxdropnobuf: %lud\n", ctlr->nrxdropnobuf); PRINTSTAT("nrxdropnosa: %lud\n", ctlr->nrxdropnosa); PRINTSTAT("nrxcantdecrypt: %lud\n", ctlr->nrxcantdecrypt); PRINTSTAT("nrxmsgfrag: %lud\n", ctlr->nrxmsgfrag); PRINTSTAT("nrxmsgbadfrag: %lud\n", ctlr->nrxmsgbadfrag); USED(l); n = readstr(offset, a, n, p); free(p); return n; } #undef PRINTSTR #undef PRINTSTAT int w_option(Ctlr* ctlr, char* buf, long n) { char *p; int i, r; WKey *key; Cmdbuf *cb; r = 0; cb = parsecmd(buf, n); if(cb->nf < 2) r = -1; else if(cistrcmp(cb->f[0], "essid") == 0){ if (cistrcmp(cb->f[1],"default") == 0) p = ""; else p = cb->f[1]; if(ctlr->ptype == 3){ memset(ctlr->netname, 0, sizeof(ctlr->netname)); strncpy(ctlr->netname, p, WNameLen); } else{ memset(ctlr->wantname, 0, sizeof(ctlr->wantname)); strncpy(ctlr->wantname, p, WNameLen); } } else if(cistrcmp(cb->f[0], "station") == 0){ memset(ctlr->nodename, 0, sizeof(ctlr->nodename)); strncpy(ctlr->nodename, cb->f[1], WNameLen); } else if(cistrcmp(cb->f[0], "channel") == 0){ if((i = atoi(cb->f[1])) >= 1 && i <= 16) ctlr->chan = i; else r = -1; } else if(cistrcmp(cb->f[0], "mode") == 0){ if(cistrcmp(cb->f[1], "managed") == 0) ctlr->ptype = WPTypeManaged; else if(cistrcmp(cb->f[1], "wds") == 0) ctlr->ptype = WPTypeWDS; else if(cistrcmp(cb->f[1], "adhoc") == 0) ctlr->ptype = WPTypeAdHoc; else if((i = atoi(cb->f[1])) >= 1 && i <= 3) ctlr->ptype = i; else r = -1; } else if(cistrcmp(cb->f[0], "ibss") == 0){ if(cistrcmp(cb->f[1], "on") == 0) ctlr->createibss = 1; else ctlr->createibss = 0; } else if(cistrcmp(cb->f[0], "crypt") == 0){ if(cistrcmp(cb->f[1], "off") == 0) ctlr->crypt = 0; else if(cistrcmp(cb->f[1], "on") == 0 && ctlr->hascrypt) ctlr->crypt = 1; else r = -1; } else if(cistrcmp(cb->f[0], "clear") == 0){ if(cistrcmp(cb->f[1], "on") == 0) ctlr->xclear = 0; else if(cistrcmp(cb->f[1], "off") == 0 && ctlr->hascrypt) ctlr->xclear = 1; else r = -1; } else if(cistrncmp(cb->f[0], "key", 3) == 0){ if((i = atoi(cb->f[0]+3)) >= 1 && i <= WNKeys){ ctlr->txkey = i-1; key = &ctlr->keys.keys[ctlr->txkey]; key->len = strlen(cb->f[1]); if (key->len > WKeyLen) key->len = WKeyLen; memset(key->dat, 0, sizeof(key->dat)); memmove(key->dat, cb->f[1], key->len); } else r = -1; } else if(cistrcmp(cb->f[0], "txkey") == 0){ if((i = atoi(cb->f[1])) >= 1 && i <= WNKeys) ctlr->txkey = i-1; else r = -1; } else if(cistrcmp(cb->f[0], "pm") == 0){ if(cistrcmp(cb->f[1], "off") == 0) ctlr->pmena = 0; else if(cistrcmp(cb->f[1], "on") == 0){ ctlr->pmena = 1; if(cb->nf == 3){ i = atoi(cb->f[2]); // check range here? what are the units? ctlr->pmwait = i; } } else r = -1; } else r = -2; free(cb); return r; } long w_ctl(Ether* ether, void* buf, long n) { Ctlr *ctlr; if((ctlr = ether->ctlr) == nil) error(Enonexist); if(ctlr->attached == 0) error(Eshutdown); ilock(ctlr); if(w_option(ctlr, buf, n)){ iunlock(ctlr); error(Ebadctl); } if(ctlr->txbusy) w_txdone(ctlr, WTxErrEv); w_enable(ether); w_txstart(ether); iunlock(ctlr); return n; } void w_transmit(Ether* ether) { Ctlr* ctlr = ether->ctlr; if (ctlr == 0) return; ilock(ctlr); ctlr->ntxrq++; w_txstart(ether); iunlock(ctlr); } void w_promiscuous(void* arg, int on) { Ether* ether = (Ether*)arg; Ctlr* ctlr = ether->ctlr; if (ctlr == nil) error("card not found"); if (ctlr->attached == 0) error("card not attached"); ilock(ctlr); ltv_outs(ctlr, WTyp_Prom, (on?1:0)); iunlock(ctlr); } void w_interrupt(Ureg* ,void* arg) { Ether* ether = (Ether*) arg; Ctlr* ctlr = (Ctlr*) ether->ctlr; if (ctlr == 0) return; ilock(ctlr); ctlr->nints++; w_intr(ether); iunlock(ctlr); } int wavelanreset(Ether* ether, Ctlr *ctlr) { Wltv ltv; w_intdis(ctlr); if (w_cmd(ctlr,WCmdIni,0)){ print("#l%d: init failed\n", ether->ctlrno); return -1; } w_intdis(ctlr); ltv_outs(ctlr, WTyp_Tick, 8); ctlr->chan = 0; ctlr->ptype = WDfltPType; ctlr->txkey = 0; ctlr->createibss = 0; ctlr->keys.len = sizeof(WKey)*WNKeys/2 + 1; ctlr->keys.type = WTyp_Keys; if(ctlr->hascrypt = ltv_ins(ctlr, WTyp_HasCrypt)) ctlr->crypt = 1; *ctlr->netname = *ctlr->wantname = 0; strcpy(ctlr->nodename, "Plan 9 STA"); ctlr->netname[WNameLen-1] = 0; ctlr->wantname[WNameLen-1] = 0; ctlr->nodename[WNameLen-1] =0; ltv.type = WTyp_Mac; ltv.len = 4; if (w_inltv(ctlr, <v)){ print("#l%d: unable to read mac addr\n", ether->ctlrno); return -1; } memmove(ether->ea, ltv.addr, Eaddrlen); if (ctlr->chan == 0) ctlr->chan = ltv_ins(ctlr, WTyp_Chan); ctlr->apdensity = WDfltApDens; ctlr->rtsthres = WDfltRtsThres; ctlr->txrate = WDfltTxRate; ctlr->maxlen = WMaxLen; ctlr->pmena = 0; ctlr->pmwait = 100; ctlr->signal = 1; ctlr->noise = 1; // link to ether ether->ctlr = ctlr; ether->mbps = 10; ether->attach = w_attach; ether->interrupt = w_interrupt; ether->transmit = w_transmit; ether->ifstat = w_ifstat; ether->ctl = w_ctl; ether->promiscuous = w_promiscuous; ether->multicast = w_multicast; ether->arg = ether; // DEBUG("#l%d: irq %ld port %lx type %s", // ether->ctlrno, ether->irq, ether->port, ether->type); // DEBUG(" %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX\n", // ether->ea[0], ether->ea[1], ether->ea[2], // ether->ea[3], ether->ea[4], ether->ea[5]); return 0; } char* wavenames[] = { "WaveLAN/IEEE", "TrueMobile 1150", "Instant Wireless ; Network PC CARD", . 121,143c static void csr_outss(Ctlr *ctlr, int reg, void *dat, int ndat) { ushort *rp, *wp; . 100,119c if(ctlr->mmb){ rp = &ctlr->mmb[reg]; wp = dat; while(ndat-- > 0) *wp++ = *rp; }else inss(ctlr->iob+reg, dat, ndat); } . 94,98c static void csr_inss(Ctlr *ctlr, int reg, void *dat, int ndat) { ushort *rp, *wp; . 86,92c static void csr_ack(Ctlr *ctlr, int ev) { csr_outs(ctlr, WR_EvAck, ev); } . 65,83c ushort csr_ins(Ctlr *ctlr, int reg) { if(ctlr->mmb) return ctlr->mmb[reg]; else return ins(ctlr->iob+reg); . 9,63c /* * When we're using a PCI device and memory-mapped I/O, * the registers are spaced out as though each takes 32 bits, * even though they are only 16-bit registers. Thus, * ctlr->mmb[reg] is the right way to access register reg, * even though a priori you'd expect to use ctlr->mmb[reg/2]. */ void csr_outs(Ctlr *ctlr, int reg, ushort arg) { if(ctlr->mmb) ctlr->mmb[reg] = arg; else outs(ctlr->iob+reg, arg); } . 7a #include "../port/netif.h" #include "etherif.h" #include "wavelan.h" . 0a /* Lucent Wavelan IEEE 802.11 pcmcia. There is almost no documentation for the card. the driver is done using both the FreeBSD, Linux and original Plan 9 drivers as `documentation'. Has been used with the card plugged in during all up time. no cards removals/insertions yet. For known BUGS see the comments below. Besides, the driver keeps interrupts disabled for just too long. When it gets robust, locks should be revisited. BUGS: check endian, alignment and mem/io issues; multicast; receive watchdog interrupts. TODO: automatic power management; improve locking. */ . ## diffname pc/wavelan.c 2002/0615 ## diff -e /n/emeliedump/2002/0606/sys/src/9/pc/wavelan.c /n/emeliedump/2002/0615/sys/src/9/pc/wavelan.c 1051a ether->detach = w_detach; . 690a void w_detach(Ether* ether) { Ctlr* ctlr; char name[64]; if (ether->ctlr == 0) return; snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno); ctlr = (Ctlr*) ether->ctlr; if (ctlr->attached){ ilock(ctlr); w_intdis(ctlr); if (ctlr->timerproc){ if (!postnote(ctlr->timerproc, 1, "kill", NExit)) print("timerproc note not posted\n"); print("w_detach, killing 0x%p\n", ctlr->timerproc); } ctlr->attached = 0; iunlock(ctlr); } } . 658c poperror(); pexit("terminated", 0); . 611a if (waserror()){ print("timerporc dying\n"); pexit("aaargh!", 0); } ctlr->timerproc = up; . ## diffname pc/wavelan.c 2002/0616 ## diff -e /n/emeliedump/2002/0615/sys/src/9/pc/wavelan.c /n/emeliedump/2002/0616/sys/src/9/pc/wavelan.c 1077a // free old Ctlr struct if resetting after suspend if (ether->ctlr) free(ether->ctlr); . ## diffname pc/wavelan.c 2002/0618 ## diff -e /n/emeliedump/2002/0616/sys/src/9/pc/wavelan.c /n/emeliedump/2002/0618/sys/src/9/pc/wavelan.c 1090a ether->power = w_power; . 1009c if ((ctlr->state & Attached) == 0) . 970c if((ctlr->state & Attached) == 0) . 764a k = ((ctlr->state & Power) ? "on" : "off"); PRINTSTAT("PCardower %s", k); . 763c k = ((ctlr->state & Attached) ? "attached" : "not attached"); . 720a void w_power(Ether* ether, int on) { Ctlr *ctlr; ctlr = (Ctlr*) ether->ctlr; ilock(ctlr); if (on){ if ((ctlr->state & Power) == 0){ if (ctlr->state & Attached) w_enable(ether); ctlr->state |= Power; } }else{ if (ctlr->state & Power){ if (ctlr->state & Attached) w_intdis(ctlr); ctlr->state &= ~Power; } } iunlock(ctlr); } . 716c ctlr->state &= ~Attached; . 708c if (ctlr->state & Attached){ . 690c ctlr->state |= Attached; . 685c if ((ctlr->state & Attached) == 0){ . 663d 622c if ((ctlr->state & Attached) == 0) . 612,615d 561c if ((ctlr->state & Power) == 0) return; if ((ctlr->state & Attached) == 0){ . 474c if((ctlr = ether->ctlr) == nil || (ctlr->state & (Attached|Power)) == 0 || ctlr->txbusy) . ## diffname pc/wavelan.c 2002/0619 ## diff -e /n/emeliedump/2002/0618/sys/src/9/pc/wavelan.c /n/emeliedump/2002/0619/sys/src/9/pc/wavelan.c 1102c if(ether->ctlr) . 1099a ctlr->state |= Power; . 1090c if(ctlr->chan == 0) . 1083c if(w_inltv(ctlr, <v)){ . 1059c if(w_cmd(ctlr,WCmdIni,0)){ . 1045c if(ctlr == 0) . 1032c if((ctlr->state & Attached) == 0) . 1030c if(ctlr == nil) . 1015c if(ctlr == 0) . 951c if(key->len > WKeyLen) . 889c if(cistrcmp(cb->f[1],"default") == 0) . 834c if(ltv_ins(ctlr, WTyp_Crypt) == 0) . 831c if(ltv_ins(ctlr, WTyp_HasCrypt) == 0) . 824c if(w_inltv(ctlr, <v)) . 796c else if(SEEKEYS == 0) . 794c if(ctlr->keys.keys[i].len == 0) . 791c if(ctlr->hascrypt){ . 733,734c if(ctlr->state & Power){ if(ctlr->state & Attached) . 726,728c if(on){ if((ctlr->state & Power) == 0){ if(ctlr->state & Attached) . 709,710c if(ctlr->timerproc){ if(!postnote(ctlr->timerproc, 1, "kill", NExit)) . 706c if(ctlr->state & Attached){ . 701c if(ether->ctlr == 0) . 683c if((ctlr->state & Attached) == 0){ . 678c if(ether->ctlr == 0) . 656,657c if((ctlr->ticks % 120) == 0) if(ctlr->txbusy == 0) . 651c if(w_enable(ether)){ . 647,648c if((ctlr->ticks % 10) == 0) { if(ctlr->txtmout && --ctlr->txtmout == 0){ . 642c if(csr_ins(ctlr, WR_EvSts)&WEvs){ . 621c if((ctlr->state & Attached) == 0) . 619c if(ctlr == 0) . 598c if(rc & WIDropEv){ . 594c if(rc & WTxErrEv){ . 589c if(rc & WInfoEv){ . 584,585c if(txid == ctlr->txdid){ if((rc & WTXEv) == 0) . 580c if(rc & WAllocEv){ . 576c if(rc & WTXEv){ . 572c if(rc & WRXEv){ . 564c if((ctlr->state & Attached) == 0){ . 561c if((ctlr->state & Power) == 0) . 546c if(rc > 0xf000) . 542c if(ltv.type == WTyp_Stats){ . 525c if(sts & WTxErrEv) . 448c if(w_read(ctlr, sp, WF_802_3_Off, bp->wp, len) == 0){ . 446c if(!bp) . 437c if(w_read(ctlr, sp, WF_802_11_Off, bp->wp, len+2) == 0){ . 430c if(!bp) . 421c if(f.sts&WF_Err){ . 417c if(len == 0){ . 399c if(ctlr->txdid == -1 || ctlr->txmid == -1) . 393c if(w_cmd(ctlr, WCmdEna, 0)){ . 384c if(ctlr->hascrypt){ . 375c if(*ctlr->nodename) . 372c if(*ctlr->wantname) . 370c if(*ctlr->netname) . 351c if(!ctlr) . 335c if(w_seek(ctlr, rc, 0, 0)) . 332c if(csr_ins(ctlr, WR_EvSts) & WAllocEv){ . 330c if(w_cmd(ctlr, WCmdMalloc, len)==0) . 314,315c if(csr_ins(ctlr, WR_Data0) == 0xdead) if(csr_ins(ctlr, WR_Data0) == 0xbeef) . 310c if(w_seek(ctlr, type, off + len, 0)){ . 301c if(w_seek(ctlr, type, off, 0)){ . 286c if(w_seek(ctlr, type, off, 1)){ . 272c if(w_inltv(ctlr, <v)) . 196c if((code=csr_ins(ctlr, WR_Data1)) != ltv->type){ . 193c if(len > ltv->len) . 188c if(w_seek(ctlr,ltv->type,0,1)){ . 184c if(w_cmd(ctlr, WCmdAccRd, ltv->type)){ . 172c if((rc & (WBusyOff|WErrOff)) == 0) . 166c if(chan != 0 && chan != 1) . ## diffname pc/wavelan.c 2002/0626 ## diff -e /n/emeliedump/2002/0619/sys/src/9/pc/wavelan.c /n/emeliedump/2002/0626/sys/src/9/pc/wavelan.c 1120,1124c DEBUG("#l%d: intnum %ld port %lx type %s", ether->ctlrno, ether->intnum, ether->port, ether->type); DEBUG(" %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX\n", ether->ea[0], ether->ea[1], ether->ea[2], ether->ea[3], ether->ea[4], ether->ea[5]); . 1103c if(ether->ctlr && ether->ctlr != ctlr) . 1084c iprint("#l%d: unable to read mac addr\n", . 1060c iprint("#l%d: init failed\n", ether->ctlrno); . 1057a iprint("wavelanreset, iob 0x%ux\n", ctlr->iob); . 727a if (wavelanreset(ether, ctlr) < 0){ iprint("w_power: reset failed\n"); iunlock(ctlr); w_detach(ether); free(ctlr); return; } . 725a iprint("w_power %d\n", on); . 716a ether->ctlr = nil; . 701c if(ether->ctlr == nil) . 621c if((ctlr->state & (Attached|Power)) != (Attached|Power)) . 474c if((ctlr = ether->ctlr) == nil || (ctlr->state & (Attached|Power)) != (Attached|Power) || ctlr->txbusy) . ## diffname pc/wavelan.c 2002/0703 ## diff -e /n/emeliedump/2002/0626/sys/src/9/pc/wavelan.c /n/emeliedump/2002/0703/sys/src/9/pc/wavelan.c 1130,1131c DEBUG("#l%d: irq %ld port %lx type %s", ether->ctlrno, ether->irq, ether->port, ether->type); . ## diffname pc/wavelan.c 2002/0919 ## diff -e /n/emeliedump/2002/0703/sys/src/9/pc/wavelan.c /n/emeliedump/2002/0919/sys/src/9/pc/wavelan.c 1142a "Avaya Wireless PC Card", "AirLancer MC-11", . ## diffname pc/wavelan.c 2002/1015 ## diff -e /n/emeliedump/2002/0919/sys/src/9/pc/wavelan.c /n/emeliedump/2002/1015/sys/src/9/pc/wavelan.c 1147d 1142a "Instant Wireless Network PC Card", . ## diffname pc/wavelan.c 2002/1231 ## diff -e /n/emeliedump/2002/1015/sys/src/9/pc/wavelan.c /n/emeliedump/2002/1231/sys/src/9/pc/wavelan.c 796c PRINTSTAT(", power %s", k); . ## diffname pc/wavelan.c 2003/0116 ## diff -e /n/emeliedump/2002/1231/sys/src/9/pc/wavelan.c /n/emeliedump/2003/0116/sys/src/9/pc/wavelan.c 902c if(ctlr->ptype == WPTypeAdHoc){ . 895c if(cistrcmp(cb->f[0], "scan") == 0){ w_cmd(ctlr, WCmdEnquire, WTyp_Scan); } else if(cb->nf < 2) . 852a if(ctlr->nwscan){ for(i = 0; i < ctlr->nwscan; i++) PRINTSTAT("ws: %4.4ux\n", ctlr->wscan[i]); ctlr->nwscan = 0; } . 826c if(i == WPTypeAdHoc) . 774c p = malloc(2*READSTR); . 658c w_cmd(ctlr, WCmdEnquire, WTyp_Stats); . 591c w_info(ctlr); . 551a print("got type %d\n", ltv.len); . 550a case WTyp_Scan: print("calling w_scan %d\n", ltv.len); w_scan(ctlr, ltv.len); return 0; . 542,549c ltv.len--; switch(ltv.type){ case WTyp_Stats: w_stats(ctlr, ltv.len); . 538a for (i = 0; i < len && p < pend; i++){ rc = csr_ins(ctlr, WR_Data1); if(rc > 0xf000) rc = ~rc & 0xffff; p[i] += rc; } } static void w_scan(Ctlr* ctlr, int len) { int i; for (i = 0; i < len && i < nelem(ctlr->wscan); i++) ctlr->wscan[i] = csr_ins(ctlr, WR_Data1); ctlr->nwscan = i; } static int w_info(Ctlr* ctlr) { int sp; Wltv ltv; . 534,535c int i, rc; . 531,532c static void w_stats(Ctlr* ctlr, int len) . ## diffname pc/wavelan.c 2003/0117 ## diff -e /n/emeliedump/2003/0116/sys/src/9/pc/wavelan.c /n/emeliedump/2003/0117/sys/src/9/pc/wavelan.c 1115c ctlr->crypt = 0; . 924,927c if(cb->nf < 2) . 666,669c // if(csr_ins(ctlr, WR_EvSts)&WEvs){ // ctlr->tickintr++; // w_intr(ether); // } . 595a print("intr %ux\n", rc); . 575c print("got type %d\n", ltv.type); . 384c if(ctlr->hascrypt && ctlr->crypt){ . ## diffname pc/wavelan.c 2003/0118 ## diff -e /n/emeliedump/2003/0117/sys/src/9/pc/wavelan.c /n/emeliedump/2003/0118/sys/src/9/pc/wavelan.c 1157a ether->scanbs = w_scanbs; . 1113c ctlr->crypt = 1; . 878,882d 799c p = malloc(READSTR); . 683a if(ctlr->scanticks > 0) if((ctlr->ticks % ctlr->scanticks) == 0) if(ctlr->txbusy == 0) w_cmd(ctlr, WCmdEnquire, WTyp_Scan); . 667,670c if(csr_ins(ctlr, WR_EvSts)&WEvs){ ctlr->tickintr++; w_intr(ether); } . 642c tsleep(&ctlr->timer, return0, 0, MSperTick); . 616c w_info(ether, ctlr); . 596d 579a w_scanbs(void *a, uint secs) { Ether *ether = a; Ctlr* ctlr = (Ctlr*) ether->ctlr; ctlr->scanticks = secs*(1000/MSperTick); } static void . 578a /* set scanning interval */ . 575d 571,572c w_scaninfo(ether, ctlr, ltv.len); . 557c w_info(Ether *ether, Ctlr* ctlr) . 551,553c for (i = 0; i < len ; i++) ctlr->scanbuf[i] = csr_ins(ctlr, WR_Data1); len *= 2; i = ether->scan; ep = ðer->f[Ntypes]; for(fp = ether->f; fp < ep && i > 0; fp++){ f = *fp; if(f == nil || f->scan == 0) continue; bp = iallocb(2048); if(bp == nil) break; for(j = 0; j < len/(2*25); j++){ wsp = (WScan*)(&ctlr->scanbuf[j*25]); if(wsp->ssid_len > 32) wsp->ssid_len = 32; bp->wp += snprint((char*)bp->wp, 2048, "ssid=%.*s;bssid=%E;signal=%d;noise=%d;chan=%d%s\n", wsp->ssid_len, wsp->ssid, wsp->bssid, wsp->signal, wsp->noise, wsp->chan, (wsp->capinfo&(1<<4))?";wep":""); } qpass(f->in, bp); i--; } . 549c int i, j; Netfile **ep, *f, **fp; Block *bp; WScan *wsp; . 547c w_scaninfo(Ether* ether, Ctlr *ctlr, int len) . 545a /* send the base station scan info to any readers */ . 530a /* save the stats info in the ctlr struct */ . 30a enum { MSperTick= 50, /* ms between ticks of kproc */ }; . ## diffname pc/wavelan.c 2003/0301 ## diff -e /n/emeliedump/2003/0118/sys/src/9/pc/wavelan.c /n/emeliedump/2003/0301/sys/src/9/pc/wavelan.c 1200c DEBUG("#l%d: irq %d port %lx type %s", . ## diffname pc/wavelan.c 2003/0302 ## diff -e /n/emeliedump/2003/0301/sys/src/9/pc/wavelan.c /n/emeliedump/2003/0302/sys/src/9/pc/wavelan.c 586a free(scanbuf); . 579c bp->wp = (uchar*)seprint((char*)bp->wp, (char*)bp->lim, . 575,576c for(j = 0; j < len; j++){ wsp = (WScan*)(&scanbuf[j*25]); . 572c bp = iallocb(100*len); . 564c len /= 25; . 562c scanbuf[i] = csr_ins(ctlr, WR_Data1); . 560a scanbuf = malloc(len*2); if(scanbuf == nil) return; . 559a ushort *scanbuf; . ## diffname pc/wavelan.c 2003/0304 ## diff -e /n/emeliedump/2003/0302/sys/src/9/pc/wavelan.c /n/emeliedump/2003/0304/sys/src/9/pc/wavelan.c 591a out: . 569a if(len == 0) goto out; . 568a /* calculate number of samples */ . ## diffname pc/wavelan.c 2003/0407 ## diff -e /n/emeliedump/2003/0304/sys/src/9/pc/wavelan.c /n/emeliedump/2003/0407/sys/src/9/pc/wavelan.c 693c tsleep(&up->sleep, return0, 0, MSperTick); .