int w_inltv(Ctlr* ctlr, Wltv* ltv) { int len; ushort code; if(w_cmd(ctlr, WCmdAccRd, ltv->type)){ 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 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 void w_intr(Ether *ether) { int rc, txid; Ctlr* ctlr = (Ctlr*) ether->ctlr; if((ctlr->state & Power) == 0) return; if((ctlr->state & 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_info(ether, 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); }
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_timer(void* arg) { Ether* ether = (Ether*) arg; Ctlr* ctlr = (Ctlr*)ether->ctlr; ctlr->timerproc = up; for(;;) { tsleep(&up->sleep, return0, 0, MSperTick); ctlr = (Ctlr*)ether->ctlr; if(ctlr == 0) break; if((ctlr->state & (Attached|Power)) != (Attached|Power)) 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, WCmdEnquire, WTyp_Stats); if(ctlr->scanticks > 0) if((ctlr->ticks % ctlr->scanticks) == 0) if(ctlr->txbusy == 0) w_cmd(ctlr, WCmdEnquire, WTyp_Scan); } iunlock(ctlr); } pexit("terminated", 0); }
static int w_alloc(Ctlr* ctlr, int len) { int rc; int i,j; if(w_cmd(ctlr, WCmdMalloc, len)==0) for (i = 0; i<WTmOut; i++) if(csr_ins(ctlr, WR_EvSts) & WAllocEv){ csr_ack(ctlr, WAllocEv); rc=csr_ins(ctlr, WR_Alloc); if(w_seek(ctlr, rc, 0, 0)) return -1; len = len/2; for (j=0; j<len; j++) csr_outs(ctlr, WR_Data0, 0); return rc; } return -1; }
/* save the stats info in the ctlr struct */ static void w_stats(Ctlr* ctlr, int len) { int i, rc; ulong* p = (ulong*)&ctlr->WStats; ulong* pend = (ulong*)&ctlr->end; for (i = 0; i < len && p < pend; i++){ rc = csr_ins(ctlr, WR_Data1); if(rc > 0xf000) rc = ~rc & 0xffff; p[i] += rc; } }
/* send the base station scan info to any readers */ static void w_scaninfo(Ether* ether, Ctlr *ctlr, int len) { int i, j; Netfile **ep, *f, **fp; Block *bp; WScan *wsp; ushort *scanbuf; scanbuf = malloc(len*2); if(scanbuf == nil) return; for (i = 0; i < len ; i++) scanbuf[i] = csr_ins(ctlr, WR_Data1); /* calculate number of samples */ len /= 25; if(len == 0) goto out; 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(100*len); if(bp == nil) break; for(j = 0; j < len; j++){ wsp = (WScan*)(&scanbuf[j*25]); if(wsp->ssid_len > 32) wsp->ssid_len = 32; bp->wp = (uchar*)seprint((char*)bp->wp, (char*)bp->lim, "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--; } out: free(scanbuf); }
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"); csr_outs(ctlr, sel[chan], id); csr_outs(ctlr, off[chan], offset); for (i=0; i<WTmOut; i++){ rc = csr_ins(ctlr, off[chan]); if((rc & (WBusyOff|WErrOff)) == 0) return 0; } return -1; }
int w_cmd(Ctlr *ctlr, ushort cmd, ushort arg) { int i, rc; for(i=0; i<WTmOut; i++) if((csr_ins(ctlr, WR_Cmd)&WCmdBusy) == 0) break; if(i==WTmOut){ print("#l%d: issuing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_Cmd)); return -1; } csr_outs(ctlr, WR_Parm0, arg); csr_outs(ctlr, WR_Cmd, cmd); for(i=0; i<WTmOut; i++) if(csr_ins(ctlr, WR_EvSts)&WCmdEv) break; if(i==WTmOut){ /* * WCmdIni can take a really long time. */ enum { IniTmOut = 2000 }; for(i=0; i<IniTmOut; i++){ if(csr_ins(ctlr, WR_EvSts)&WCmdEv) break; microdelay(100); } if(i < IniTmOut) if(0) print("#l%d: long cmd %.4ux %d\n", ctlr->ctlrno, 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_info(Ether *ether, Ctlr* ctlr) { int sp; Wltv ltv; sp = csr_ins(ctlr, WR_InfoId); ltv.len = ltv.type = 0; w_read(ctlr, sp, 0, <v, 4); ltv.len--; switch(ltv.type){ case WTyp_Stats: w_stats(ctlr, ltv.len); return 0; case WTyp_Scan: w_scaninfo(ether, ctlr, ltv.len); return 0; } return -1; }
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 = smalloc(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->state & Attached) ? "attached" : "not attached"); PRINTSTAT("Card %s", k); k = ((ctlr->state & Power) ? "on" : "off"); PRINTSTAT(", power %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 == WPTypeAdHoc) 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; }