123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278 |
- /*
- 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;
- receive watchdog interrupts.
- TODO: automatic power management;
- multicast filtering;
- improve locking.
- */
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "io.h"
- #include "../port/error.h"
- #include "../port/netif.h"
- #include "etherif.h"
- #include "wavelan.h"
- enum
- {
- MSperTick= 50, /* ms between ticks of kproc */
- };
- /*
- * 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);
- }
- ushort
- csr_ins(Ctlr *ctlr, int reg)
- {
- if(ctlr->mmb)
- return ctlr->mmb[reg];
- else
- return ins(ctlr->iob+reg);
- }
- static void
- csr_ack(Ctlr *ctlr, int ev)
- {
- csr_outs(ctlr, WR_EvAck, ev);
- }
- static void
- csr_inss(Ctlr *ctlr, int reg, void *dat, int ndat)
- {
- ushort *rp, *wp;
- if(ctlr->mmb){
- rp = &ctlr->mmb[reg];
- wp = dat;
- while(ndat-- > 0)
- *wp++ = *rp;
- }else
- inss(ctlr->iob+reg, dat, ndat);
- }
- static void
- csr_outss(Ctlr *ctlr, int reg, void *dat, int ndat)
- {
- ushort *rp, *wp;
- 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; 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_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; i<WTmOut; i++){
- rc = csr_ins(ctlr, off[chan]);
- if((rc & (WBusyOff|WErrOff)) == 0)
- return 0;
- }
- return -1;
- }
- 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 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)
- {
- 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 && csr_ins(ctlr, WR_Data0) == 0xbeef)
- return len;
- DEBUG("wavelan: Hermes bug byte.\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; 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;
- }
- static int
- w_enable(Ether* ether)
- {
- Wltv ltv;
- Ctlr* ctlr = (Ctlr*) ether->ctlr;
- 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 && ctlr->crypt){
- 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->state & (Attached|Power)) != (Attached|Power) || 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++;
- }
- /* 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_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;
- }
- /* set scanning interval */
- static void
- w_scanbs(void *a, uint secs)
- {
- Ether *ether = a;
- Ctlr* ctlr = (Ctlr*) ether->ctlr;
- ctlr->scanticks = secs*(1000/MSperTick);
- }
- 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);
- }
- // 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;
- 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);
- }
- void
- w_multicast(void *ether, uchar*, int add)
- {
- /* BUG: use controller's multicast filter */
- if (add)
- w_promiscuous(ether, 1);
- }
- 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->state & Attached) == 0){
- ilock(ctlr);
- rc = w_enable(ether);
- iunlock(ctlr);
- if(rc == 0){
- ctlr->state |= Attached;
- kproc(name, w_timer, ether);
- } else
- print("#l%d: enable failed\n",ether->ctlrno);
- }
- }
- void
- w_detach(Ether* ether)
- {
- Ctlr* ctlr;
- char name[64];
- if(ether->ctlr == nil)
- return;
- snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
- ctlr = (Ctlr*) ether->ctlr;
- if(ctlr->state & 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->state &= ~Attached;
- iunlock(ctlr);
- }
- ether->ctlr = nil;
- }
- void
- w_power(Ether* ether, int on)
- {
- Ctlr *ctlr;
- ctlr = (Ctlr*) ether->ctlr;
- ilock(ctlr);
- iprint("w_power %d\n", on);
- if(on){
- if((ctlr->state & Power) == 0){
- if (wavelanreset(ether, ctlr) < 0){
- iprint("w_power: reset failed\n");
- iunlock(ctlr);
- w_detach(ether);
- free(ctlr);
- return;
- }
- 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);
- }
- #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);
- if(p == nil)
- error(Enomem);
- 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;
- }
- #undef PRINTSTR
- #undef PRINTSTAT
- static int
- parsekey(WKey* key, char* a)
- {
- int i, k, len, n;
- char buf[WMaxKeyLen];
- len = strlen(a);
- if(len == WMinKeyLen || len == WMaxKeyLen){
- memset(key->dat, 0, sizeof(key->dat));
- memmove(key->dat, a, len);
- key->len = len;
- return 0;
- }
- else if(len == WMinKeyLen*2 || len == WMaxKeyLen*2){
- k = 0;
- for(i = 0; i < len; i++){
- if(*a >= '0' && *a <= '9')
- n = *a++ - '0';
- else if(*a >= 'a' && *a <= 'f')
- n = *a++ - 'a' + 10;
- else if(*a >= 'A' && *a <= 'F')
- n = *a++ - 'A' + 10;
- else
- return -1;
-
- if(i & 1){
- buf[k] |= n;
- k++;
- }
- else
- buf[k] = n<<4;
- }
- memset(key->dat, 0, sizeof(key->dat));
- memmove(key->dat, buf, k);
- key->len = k;
- return 0;
- }
- return -1;
- }
- int
- w_option(Ctlr* ctlr, char* buf, long n)
- {
- char *p;
- int i, r;
- 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 == WPTypeAdHoc){
- 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])) >= 0 && 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;
- if(parsekey(&ctlr->keys.keys[ctlr->txkey], cb->f[1]))
- r = -1;
- }
- 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->state & 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->state & 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);
- }
- static void
- w_shutdown(Ether* ether)
- {
- Ctlr *ctlr;
- ctlr = ether->ctlr;
- w_intdis(ctlr);
- if(w_cmd(ctlr,WCmdIni,0))
- iprint("#l%d: init failed\n", ether->ctlrno);
- w_intdis(ctlr);
- }
- int
- wavelanreset(Ether* ether, Ctlr *ctlr)
- {
- Wltv ltv;
- iprint("wavelanreset, iob 0x%ux\n", ctlr->iob);
- w_intdis(ctlr);
- if(w_cmd(ctlr,WCmdIni,0)){
- iprint("#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)){
- iprint("#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;
- ctlr->state |= Power;
- // free old Ctlr struct if resetting after suspend
- if(ether->ctlr && ether->ctlr != ctlr)
- free(ether->ctlr);
- // link to ether
- ether->ctlr = ctlr;
- ether->mbps = 10;
- ether->attach = w_attach;
- ether->detach = w_detach;
- ether->interrupt = w_interrupt;
- ether->transmit = w_transmit;
- ether->ifstat = w_ifstat;
- ether->ctl = w_ctl;
- ether->power = w_power;
- ether->promiscuous = w_promiscuous;
- ether->multicast = w_multicast;
- ether->shutdown = w_shutdown;
- ether->scanbs = w_scanbs;
- ether->arg = ether;
- DEBUG("#l%d: irq %d 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",
- "Instant Wireless Network PC Card",
- "Avaya Wireless PC Card",
- "AirLancer MC-11",
- "INTERSIL;HFA384x/IEEE;Version 01.02;",
- nil,
- };
|