The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/pc/wavelan.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    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'.
    6 
    7         Has been used with the card plugged in during all up time.
    8         no cards removals/insertions yet.
    9 
   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.
   13 
   14         BUGS: check endian, alignment and mem/io issues;
   15               receive watchdog interrupts.
   16         TODO: automatic power management;
   17               multicast filtering;
   18               improve locking.
   19  */
   20 #include "u.h"
   21 #include "../port/lib.h"
   22 #include "mem.h"
   23 #include "dat.h"
   24 #include "fns.h"
   25 #include "io.h"
   26 #include "../port/error.h"
   27 #include "../port/netif.h"
   28 #include "etherif.h"
   29 #include "wavelan.h"
   30 
   31 enum
   32 {
   33         MSperTick=      50,     /* ms between ticks of kproc */
   34 };
   35 
   36 /*
   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].
   42  */
   43 void
   44 csr_outs(Ctlr *ctlr, int reg, ushort arg)
   45 {
   46         if(ctlr->mmb)
   47                 ctlr->mmb[reg] = arg;
   48         else
   49                 outs(ctlr->iob+reg, arg);
   50 }
   51 
   52 ushort
   53 csr_ins(Ctlr *ctlr, int reg)
   54 {
   55         if(ctlr->mmb)
   56                 return ctlr->mmb[reg];
   57         else
   58                 return ins(ctlr->iob+reg);
   59 }
   60 
   61 static void
   62 csr_ack(Ctlr *ctlr, int ev)
   63 {
   64         csr_outs(ctlr, WR_EvAck, ev);
   65 }
   66 
   67 static void
   68 csr_inss(Ctlr *ctlr, int reg, void *dat, int ndat)
   69 {
   70         ushort *rp, *wp;
   71 
   72         if(ctlr->mmb){
   73                 rp = &ctlr->mmb[reg];
   74                 wp = dat;
   75                 while(ndat-- > 0)
   76                         *wp++ = *rp;
   77         }else
   78                 inss(ctlr->iob+reg, dat, ndat);
   79 }
   80 
   81 static void
   82 csr_outss(Ctlr *ctlr, int reg, void *dat, int ndat)
   83 {
   84         ushort *rp, *wp;
   85 
   86         if(ctlr->mmb){
   87                 rp = dat;
   88                 wp = &ctlr->mmb[reg];
   89                 while(ndat-- > 0)
   90                         *wp = *rp++;
   91         }else
   92                 outss(ctlr->iob+reg, dat, ndat);
   93 }
   94 
   95 // w_... routines do not ilock the Ctlr and should
   96 // be called locked.
   97 
   98 void
   99 w_intdis(Ctlr* ctlr)
  100 {
  101         csr_outs(ctlr, WR_IntEna, 0);
  102         csr_ack(ctlr, 0xffff);
  103 }
  104 
  105 static void
  106 w_intena(Ctlr* ctlr)
  107 {
  108         csr_outs(ctlr, WR_IntEna, WEvs);
  109 }
  110 
  111 int
  112 w_cmd(Ctlr *ctlr, ushort cmd, ushort arg)
  113 {
  114         int i, rc;
  115 
  116         for(i=0; i<WTmOut; i++)
  117                 if((csr_ins(ctlr, WR_Cmd)&WCmdBusy) == 0)
  118                         break;
  119         if(i==WTmOut){
  120                 print("#l%d: issuing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_Cmd));
  121                 return -1;
  122         }
  123 
  124         csr_outs(ctlr, WR_Parm0, arg);
  125         csr_outs(ctlr, WR_Cmd, cmd);
  126 
  127         for(i=0; i<WTmOut; i++)
  128                 if(csr_ins(ctlr, WR_EvSts)&WCmdEv)
  129                         break;
  130         if(i==WTmOut){
  131                 /*
  132                  * WCmdIni can take a really long time.
  133                  */
  134                 enum { IniTmOut = 2000 };
  135                 for(i=0; i<IniTmOut; i++){
  136                         if(csr_ins(ctlr, WR_EvSts)&WCmdEv)
  137                                 break;
  138                         microdelay(100);
  139                 }
  140                 if(i < IniTmOut)
  141                         if(0) print("#l%d: long cmd %.4ux %d\n", ctlr->ctlrno, cmd, i);
  142                 if(i == IniTmOut){
  143                         print("#l%d: execing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_EvSts));
  144                         return -1;
  145                 }
  146         }
  147         rc = csr_ins(ctlr, WR_Sts);
  148         csr_ack(ctlr, WCmdEv);
  149 
  150         if((rc&WCmdMsk) != (cmd&WCmdMsk)){
  151                 print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc);
  152                 return -1;
  153         }
  154         if(rc&WResSts){
  155                 /*
  156                  * Don't print; this happens on every WCmdAccWr for some reason.
  157                  */
  158                 if(0) print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc);
  159                 return -1;
  160         }
  161         return 0;
  162 }
  163 
  164 static int
  165 w_seek(Ctlr* ctlr, ushort id, ushort offset, int chan)
  166 {
  167         int i, rc;
  168         static ushort sel[] = { WR_Sel0, WR_Sel1 };
  169         static ushort off[] = { WR_Off0, WR_Off1 };
  170 
  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)
  178                         return 0;
  179         }
  180         return -1;
  181 }
  182 
  183 int
  184 w_inltv(Ctlr* ctlr, Wltv* ltv)
  185 {
  186         int len;
  187         ushort code;
  188 
  189         if(w_cmd(ctlr, WCmdAccRd, ltv->type)){
  190                 DEBUG("wavelan: access read failed\n");
  191                 return -1;
  192         }
  193         if(w_seek(ctlr,ltv->type,0,1)){
  194                 DEBUG("wavelan: seek failed\n");
  195                 return -1;
  196         }
  197         len = csr_ins(ctlr, WR_Data1);
  198         if(len > ltv->len)
  199                 return -1;
  200         ltv->len = len;
  201         if((code=csr_ins(ctlr, WR_Data1)) != ltv->type){
  202                 USED(code);
  203                 DEBUG("wavelan: type %x != code %x\n",ltv->type,code);
  204                 return -1;
  205         }
  206         if(ltv->len > 0)
  207                 csr_inss(ctlr, WR_Data1, &ltv->val, ltv->len-1);
  208 
  209         return 0;
  210 }
  211 
  212 static void
  213 w_outltv(Ctlr* ctlr, Wltv* ltv)
  214 {
  215         if(w_seek(ctlr,ltv->type, 0, 1))
  216                 return;
  217         csr_outss(ctlr, WR_Data1, ltv, ltv->len+1);
  218         w_cmd(ctlr, WCmdAccWr, ltv->type);
  219 }
  220 
  221 void
  222 ltv_outs(Ctlr* ctlr, int type, ushort val)
  223 {
  224         Wltv ltv;
  225 
  226         ltv.len = 2;
  227         ltv.type = type;
  228         ltv.val = val;
  229         w_outltv(ctlr, &ltv);
  230 }
  231 
  232 int
  233 ltv_ins(Ctlr* ctlr, int type)
  234 {
  235         Wltv ltv;
  236 
  237         ltv.len = 2;
  238         ltv.type = type;
  239         ltv.val = 0;
  240         if(w_inltv(ctlr, &ltv))
  241                 return -1;
  242         return ltv.val;
  243 }
  244 
  245 static void
  246 ltv_outstr(Ctlr* ctlr, int type, char* val)
  247 {
  248         Wltv ltv;
  249         int len;
  250 
  251         len = strlen(val);
  252         if(len > sizeof(ltv.s))
  253                 len = sizeof(ltv.s);
  254         memset(&ltv, 0, sizeof(ltv));
  255         ltv.len = (sizeof(ltv.type)+sizeof(ltv.slen)+sizeof(ltv.s))/2;
  256         ltv.type = type;
  257 
  258 //      This should be ltv.slen = len; according to Axel Belinfante
  259         ltv.slen = len; 
  260 
  261         strncpy(ltv.s, val, len);
  262         w_outltv(ctlr, &ltv);
  263 }
  264 
  265 static char Unkname[] = "who knows";
  266 static char Nilname[] = "card does not tell";
  267 
  268 static char*
  269 ltv_inname(Ctlr* ctlr, int type)
  270 {
  271         static Wltv ltv;
  272         int len;
  273 
  274         memset(&ltv,0,sizeof(ltv));
  275         ltv.len = WNameLen/2+2;
  276         ltv.type = type;
  277         if(w_inltv(ctlr, &ltv))
  278                 return Unkname;
  279         len = ltv.slen;
  280         if(len == 0 || ltv.s[0] == 0)
  281                 return Nilname;
  282         if(len >= sizeof ltv.s)
  283                 len = sizeof ltv.s - 1;
  284         ltv.s[len] = '\0';
  285         return ltv.s;
  286 }
  287 
  288 static int
  289 w_read(Ctlr* ctlr, int type, int off, void* buf, ulong len)
  290 {
  291         if(w_seek(ctlr, type, off, 1)){
  292                 DEBUG("wavelan: w_read: seek failed");
  293                 return 0;
  294         }
  295         csr_inss(ctlr, WR_Data1, buf, len/2);
  296 
  297         return len;
  298 }
  299 
  300 static int
  301 w_write(Ctlr* ctlr, int type, int off, void* buf, ulong len)
  302 {
  303         if(w_seek(ctlr, type, off, 0)){
  304                 DEBUG("wavelan: w_write: seek failed\n");
  305                 return 0;
  306         }
  307 
  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");
  313                 return 0;
  314         }
  315         if(csr_ins(ctlr, WR_Data0) == 0xdead && csr_ins(ctlr, WR_Data0) == 0xbeef)
  316                 return len;
  317 
  318         DEBUG("wavelan: Hermes bug byte.\n");
  319         return 0;
  320 }
  321 
  322 static int
  323 w_alloc(Ctlr* ctlr, int len)
  324 {
  325         int rc;
  326         int i,j;
  327 
  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))
  334                                         return -1;
  335                                 len = len/2;
  336                                 for (j=0; j<len; j++)
  337                                         csr_outs(ctlr, WR_Data0, 0);
  338                                 return rc;
  339                         }
  340         return -1;
  341 }
  342 
  343 static int
  344 w_enable(Ether* ether)
  345 {
  346         Wltv ltv;
  347         Ctlr* ctlr = (Ctlr*) ether->ctlr;
  348 
  349         if(!ctlr)
  350                 return -1;
  351 
  352         w_intdis(ctlr);
  353         w_cmd(ctlr, WCmdDis, 0);
  354         w_intdis(ctlr);
  355         if(w_cmd(ctlr, WCmdIni, 0))
  356                 return -1;
  357         w_intdis(ctlr);
  358 
  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);
  368         if(*ctlr->netname)
  369                 ltv_outstr(ctlr, WTyp_NetName, ctlr->netname);
  370         if(*ctlr->wantname)
  371                 ltv_outstr(ctlr, WTyp_WantName, ctlr->wantname);
  372         ltv_outs(ctlr, WTyp_Chan, ctlr->chan);
  373         if(*ctlr->nodename)
  374                 ltv_outstr(ctlr, WTyp_NodeName, ctlr->nodename);
  375         ltv.len = 4;
  376         ltv.type = WTyp_Mac;
  377         memmove(ltv.addr, ether->ea, Eaddrlen);
  378         w_outltv(ctlr, &ltv);
  379 
  380         ltv_outs(ctlr, WTyp_Prom, (ether->prom?1:0));
  381 
  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);
  387         }
  388 
  389         // BUG: set multicast addresses
  390 
  391         if(w_cmd(ctlr, WCmdEna, 0)){
  392                 DEBUG("wavelan: Enable failed");
  393                 return -1;
  394         }
  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");
  399         ctlr->txbusy = 0;
  400         w_intena(ctlr);
  401         return 0;
  402 }
  403 
  404 static void
  405 w_rxdone(Ether* ether)
  406 {
  407         Ctlr* ctlr = (Ctlr*) ether->ctlr;
  408         int len, sp;
  409         WFrame f;
  410         Block* bp=0;
  411         Etherpkt* ep;
  412 
  413         sp = csr_ins(ctlr, WR_RXId);
  414         len = w_read(ctlr, sp, 0, &f, sizeof(f));
  415         if(len == 0){
  416                 DEBUG("wavelan: read frame error\n");
  417                 goto rxerror;
  418         }
  419         if(f.sts&WF_Err){
  420                 goto rxerror;
  421         }
  422         switch(f.sts){
  423         case WF_1042:
  424         case WF_Tunnel:
  425         case WF_WMP:
  426                 len = f.dlen + WSnapHdrLen;
  427                 bp = iallocb(ETHERHDRSIZE + len + 2);
  428                 if(!bp)
  429                         goto rxerror;
  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");
  437                         goto rxerror;
  438                 }
  439                 bp->wp = bp->rp+(ETHERHDRSIZE+f.dlen);
  440                 break;
  441         default:
  442                 len = ETHERHDRSIZE + f.dlen + 2;
  443                 bp = iallocb(len);
  444                 if(!bp)
  445                         goto rxerror;
  446                 if(w_read(ctlr, sp, WF_802_3_Off, bp->wp, len) == 0){
  447                         DEBUG("wavelan: read 800.3 error\n");
  448                         goto rxerror;
  449                 }
  450                 bp->wp += len;
  451         }
  452 
  453         ctlr->nrx++;
  454         etheriq(ether,bp,1);
  455         ctlr->signal = ((ctlr->signal*15)+((f.qinfo>>8) & 0xFF))/16;
  456         ctlr->noise = ((ctlr->noise*15)+(f.qinfo & 0xFF))/16;
  457         return;
  458 
  459 rxerror:
  460         freeb(bp);
  461         ctlr->nrxerr++;
  462 }
  463 
  464 static void
  465 w_txstart(Ether* ether)
  466 {
  467         Etherpkt *pkt;
  468         Ctlr *ctlr;
  469         Block *bp;
  470         int len, off;
  471 
  472         if((ctlr = ether->ctlr) == nil || (ctlr->state & (Attached|Power)) != (Attached|Power) || ctlr->txbusy)
  473                 return;
  474 
  475         if((bp = qget(ether->oq)) == nil)
  476                 return;
  477         pkt = (Etherpkt*)bp->rp;
  478 
  479         //
  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.
  482         //
  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;
  492                 len = BLEN(bp);
  493                 off = WF_802_11_Off;
  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);
  498         }
  499         else{
  500                 len = BLEN(bp);
  501                 off = WF_802_3_Off;
  502                 ctlr->txf.dlen = len;
  503         }
  504         w_write(ctlr, ctlr->txdid, 0, &ctlr->txf, sizeof(ctlr->txf));
  505         w_write(ctlr, ctlr->txdid, off, bp->rp, len+2);
  506 
  507         if(w_cmd(ctlr, WCmdReclaim|WCmdTx, ctlr->txdid)){
  508                 DEBUG("wavelan: transmit failed\n");
  509                 ctlr->ntxerr++;
  510         }
  511         else{
  512                 ctlr->txbusy = 1;
  513                 ctlr->txtmout = 2;
  514         }
  515         freeb(bp);
  516 }
  517 
  518 static void
  519 w_txdone(Ctlr* ctlr, int sts)
  520 {
  521         ctlr->txbusy = 0;
  522         ctlr->txtmout = 0;
  523         if(sts & WTxErrEv)
  524                 ctlr->ntxerr++;
  525         else
  526                 ctlr->ntx++;
  527 }
  528 
  529 /* save the stats info in the ctlr struct */
  530 static void
  531 w_stats(Ctlr* ctlr, int len)
  532 {
  533         int i, rc;
  534         ulong* p = (ulong*)&ctlr->WStats;
  535         ulong* pend = (ulong*)&ctlr->end;
  536 
  537         for (i = 0; i < len && p < pend; i++){
  538                 rc = csr_ins(ctlr, WR_Data1);
  539                 if(rc > 0xf000)
  540                         rc = ~rc & 0xffff;
  541                 p[i] += rc;
  542         }
  543 }
  544 
  545 /* send the base station scan info to any readers */
  546 static void
  547 w_scaninfo(Ether* ether, Ctlr *ctlr, int len)
  548 {
  549         int i, j;
  550         Netfile **ep, *f, **fp;
  551         Block *bp;
  552         WScan *wsp;
  553         ushort *scanbuf;
  554 
  555         scanbuf = malloc(len*2);
  556         if(scanbuf == nil)
  557                 return;
  558         
  559         for (i = 0; i < len ; i++)
  560                 scanbuf[i] = csr_ins(ctlr, WR_Data1);
  561 
  562         /* calculate number of samples */
  563         len /= 25;
  564         if(len == 0)
  565                 goto out;
  566 
  567         i = ether->scan;
  568         ep = &ether->f[Ntypes];
  569         for(fp = ether->f; fp < ep && i > 0; fp++){
  570                 f = *fp;
  571                 if(f == nil || f->scan == 0)
  572                         continue;
  573 
  574                 bp = iallocb(100*len);
  575                 if(bp == nil)
  576                         break;
  577                 for(j = 0; j < len; j++){
  578                         wsp = (WScan*)(&scanbuf[j*25]);
  579                         if(wsp->ssid_len > 32)
  580                                 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":"");
  585                 }
  586                 qpass(f->in, bp);
  587                 i--;
  588         }
  589 out:
  590         free(scanbuf);
  591 }
  592 
  593 static int
  594 w_info(Ether *ether, Ctlr* ctlr)
  595 {
  596         int sp;
  597         Wltv ltv;
  598 
  599         sp = csr_ins(ctlr, WR_InfoId);
  600         ltv.len = ltv.type = 0;
  601         w_read(ctlr, sp, 0, &ltv, 4);
  602         ltv.len--;
  603         switch(ltv.type){
  604         case WTyp_Stats:
  605                 w_stats(ctlr, ltv.len);
  606                 return 0;
  607         case WTyp_Scan:
  608                 w_scaninfo(ether, ctlr, ltv.len);
  609                 return 0;
  610         }
  611         return -1;
  612 }
  613 
  614 /* set scanning interval */
  615 static void
  616 w_scanbs(void *a, uint secs)
  617 {
  618         Ether *ether = a;
  619         Ctlr* ctlr = (Ctlr*) ether->ctlr;
  620 
  621         ctlr->scanticks = secs*(1000/MSperTick);
  622 }
  623 
  624 static void
  625 w_intr(Ether *ether)
  626 {
  627         int rc, txid;
  628         Ctlr* ctlr = (Ctlr*) ether->ctlr;
  629 
  630         if((ctlr->state & Power) == 0)
  631                 return;
  632 
  633         if((ctlr->state & Attached) == 0){
  634                 csr_ack(ctlr, 0xffff);
  635                 csr_outs(ctlr, WR_IntEna, 0);
  636                 return;
  637         }
  638 
  639         rc = csr_ins(ctlr, WR_EvSts);
  640         csr_ack(ctlr, ~WEvs);   // Not interested in them
  641         if(rc & WRXEv){
  642                 w_rxdone(ether);
  643                 csr_ack(ctlr, WRXEv);
  644         }
  645         if(rc & WTXEv){
  646                 w_txdone(ctlr, rc);
  647                 csr_ack(ctlr, WTXEv);
  648         }
  649         if(rc & WAllocEv){
  650                 ctlr->nalloc++;
  651                 txid = csr_ins(ctlr, WR_Alloc);
  652                 csr_ack(ctlr, WAllocEv);
  653                 if(txid == ctlr->txdid){
  654                         if((rc & WTXEv) == 0)
  655                                 w_txdone(ctlr, rc);
  656                 }
  657         }
  658         if(rc & WInfoEv){
  659                 ctlr->ninfo++;
  660                 w_info(ether, ctlr);
  661                 csr_ack(ctlr, WInfoEv);
  662         }
  663         if(rc & WTxErrEv){
  664                 w_txdone(ctlr, rc);
  665                 csr_ack(ctlr, WTxErrEv);
  666         }
  667         if(rc & WIDropEv){
  668                 ctlr->nidrop++;
  669                 csr_ack(ctlr, WIDropEv);
  670         }
  671         w_txstart(ether);
  672 }
  673 
  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.
  677 
  678 static void
  679 w_timer(void* arg)
  680 {
  681         Ether* ether = (Ether*) arg;
  682         Ctlr* ctlr = (Ctlr*)ether->ctlr;
  683 
  684         ctlr->timerproc = up;
  685         for(;;){
  686                 tsleep(&up->sleep, return0, 0, MSperTick);
  687                 ctlr = (Ctlr*)ether->ctlr;
  688                 if(ctlr == 0)
  689                         break;
  690                 if((ctlr->state & (Attached|Power)) != (Attached|Power))
  691                         continue;
  692                 ctlr->ticks++;
  693 
  694                 ilock(ctlr);
  695 
  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
  702                 // poor rtts.
  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.
  710 
  711                 if(csr_ins(ctlr, WR_EvSts)&WEvs){
  712                         ctlr->tickintr++;
  713                         w_intr(ether);
  714                 }
  715 
  716                 if((ctlr->ticks % 10) == 0) {
  717                         if(ctlr->txtmout && --ctlr->txtmout == 0){
  718                                 ctlr->nwatchdogs++;
  719                                 w_txdone(ctlr, WTxErrEv);
  720                                 if(w_enable(ether)){
  721                                         DEBUG("wavelan: wdog enable failed\n");
  722                                 }
  723                                 w_txstart(ether);
  724                         }
  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);
  732                 }
  733                 iunlock(ctlr);
  734         }
  735         pexit("terminated", 0);
  736 }
  737 
  738 void
  739 w_multicast(void *ether, uchar*, int add)
  740 {
  741         /* BUG: use controller's multicast filter */
  742         if (add)
  743                 w_promiscuous(ether, 1);
  744 }
  745 
  746 void
  747 w_attach(Ether* ether)
  748 {
  749         Ctlr* ctlr;
  750         char name[64];
  751         int rc;
  752 
  753         if(ether->ctlr == 0)
  754                 return;
  755 
  756         snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
  757         ctlr = (Ctlr*) ether->ctlr;
  758         if((ctlr->state & Attached) == 0){
  759                 ilock(ctlr);
  760                 rc = w_enable(ether);
  761                 iunlock(ctlr);
  762                 if(rc == 0){
  763                         ctlr->state |= Attached;
  764                         kproc(name, w_timer, ether);
  765                 } else
  766                         print("#l%d: enable failed\n",ether->ctlrno);
  767         }
  768 }
  769 
  770 void
  771 w_detach(Ether* ether)
  772 {
  773         Ctlr* ctlr;
  774         char name[64];
  775 
  776         if(ether->ctlr == nil)
  777                 return;
  778 
  779         snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
  780         ctlr = (Ctlr*) ether->ctlr;
  781         if(ctlr->state & Attached){
  782                 ilock(ctlr);
  783                 w_intdis(ctlr);
  784                 if(ctlr->timerproc){
  785                         if(!postnote(ctlr->timerproc, 1, "kill", NExit))
  786                                 print("timerproc note not posted\n");
  787                         print("w_detach, killing 0x%p\n", ctlr->timerproc);
  788                 }
  789                 ctlr->state &= ~Attached;
  790                 iunlock(ctlr);
  791         }
  792         ether->ctlr = nil;
  793 }
  794 
  795 void
  796 w_power(Ether* ether, int on)
  797 {
  798         Ctlr *ctlr;
  799 
  800         ctlr = (Ctlr*) ether->ctlr;
  801         ilock(ctlr);
  802 iprint("w_power %d\n", on);
  803         if(on){
  804                 if((ctlr->state & Power) == 0){
  805                         if (wavelanreset(ether, ctlr) < 0){
  806                                 iprint("w_power: reset failed\n");
  807                                 iunlock(ctlr);
  808                                 w_detach(ether);
  809                                 free(ctlr);
  810                                 return;
  811                         }
  812                         if(ctlr->state & Attached)
  813                                 w_enable(ether);
  814                         ctlr->state |= Power;
  815                 }
  816         }else{
  817                 if(ctlr->state & Power){
  818                         if(ctlr->state & Attached)
  819                                 w_intdis(ctlr);
  820                         ctlr->state &= ~Power;
  821                 }
  822         }
  823         iunlock(ctlr);
  824 }
  825 
  826 #define PRINTSTAT(fmt,val)      l += snprint(p+l, READSTR-l, (fmt), (val))
  827 #define PRINTSTR(fmt)           l += snprint(p+l, READSTR-l, (fmt))
  828 
  829 long
  830 w_ifstat(Ether* ether, void* a, long n, ulong offset)
  831 {
  832         Ctlr *ctlr = (Ctlr*) ether->ctlr;
  833         char *k, *p;
  834         int i, l, txid;
  835 
  836         ether->oerrs = ctlr->ntxerr;
  837         ether->crcs = ctlr->nrxfcserr;
  838         ether->frames = 0;
  839         ether->buffs = ctlr->nrxdropnobuf;
  840         ether->overflows = 0;
  841 
  842         //
  843         // Offset must be zero or there's a possibility the
  844         // new data won't match the previous read.
  845         //
  846         if(n == 0 || offset != 0)
  847                 return 0;
  848 
  849         p = malloc(READSTR);
  850         l = 0;
  851 
  852         PRINTSTAT("Signal: %d\n", ctlr->signal-149);
  853         PRINTSTAT("Noise: %d\n", ctlr->noise-149);
  854         PRINTSTAT("SNR: %ud\n", ctlr->signal-ctlr->noise);
  855         PRINTSTAT("Interrupts: %lud\n", ctlr->nints);
  856         PRINTSTAT("Double Interrupts: %lud\n", ctlr->ndoubleint);
  857         PRINTSTAT("TxPackets: %lud\n", ctlr->ntx);
  858         PRINTSTAT("RxPackets: %lud\n", ctlr->nrx);
  859         PRINTSTAT("TxErrors: %lud\n", ctlr->ntxerr);
  860         PRINTSTAT("RxErrors: %lud\n", ctlr->nrxerr);
  861         PRINTSTAT("TxRequests: %lud\n", ctlr->ntxrq);
  862         PRINTSTAT("AllocEvs: %lud\n", ctlr->nalloc);
  863         PRINTSTAT("InfoEvs: %lud\n", ctlr->ninfo);
  864         PRINTSTAT("InfoDrop: %lud\n", ctlr->nidrop);
  865         PRINTSTAT("WatchDogs: %lud\n", ctlr->nwatchdogs);
  866         PRINTSTAT("Ticks: %ud\n", ctlr->ticks);
  867         PRINTSTAT("TickIntr: %ud\n", ctlr->tickintr);
  868         k = ((ctlr->state & Attached) ? "attached" : "not attached");
  869         PRINTSTAT("Card %s", k);
  870         k = ((ctlr->state & Power) ? "on" : "off");
  871         PRINTSTAT(", power %s", k);
  872         k = ((ctlr->txbusy)? ", txbusy" : "");
  873         PRINTSTAT("%s\n", k);
  874 
  875         if(ctlr->hascrypt){
  876                 PRINTSTR("Keys: ");
  877                 for (i = 0; i < WNKeys; i++){
  878                         if(ctlr->keys.keys[i].len == 0)
  879                                 PRINTSTR("none ");
  880                         else if(SEEKEYS == 0)
  881                                 PRINTSTR("set ");
  882                         else
  883                                 PRINTSTAT("%s ", ctlr->keys.keys[i].dat);
  884                 }
  885                 PRINTSTR("\n");
  886         }
  887 
  888         // real card stats
  889         ilock(ctlr);
  890         PRINTSTR("\nCard stats: \n");
  891         PRINTSTAT("Status: %ux\n", csr_ins(ctlr, WR_Sts));
  892         PRINTSTAT("Event status: %ux\n", csr_ins(ctlr, WR_EvSts));
  893         i = ltv_ins(ctlr, WTyp_Ptype);
  894         PRINTSTAT("Port type: %d\n", i);
  895         PRINTSTAT("Transmit rate: %d\n", ltv_ins(ctlr, WTyp_TxRate));
  896         PRINTSTAT("Current Transmit rate: %d\n",
  897                 ltv_ins(ctlr, WTyp_CurTxRate));
  898         PRINTSTAT("Channel: %d\n", ltv_ins(ctlr, WTyp_Chan));
  899         PRINTSTAT("AP density: %d\n", ltv_ins(ctlr, WTyp_ApDens));
  900         PRINTSTAT("Promiscuous mode: %d\n", ltv_ins(ctlr, WTyp_Prom));
  901         if(i == WPTypeAdHoc)
  902                 PRINTSTAT("SSID name: %s\n", ltv_inname(ctlr, WTyp_NetName));
  903         else {
  904                 Wltv ltv;
  905                 PRINTSTAT("Current name: %s\n", ltv_inname(ctlr, WTyp_CurName));
  906                 ltv.type = WTyp_BaseID;
  907                 ltv.len = 4;
  908                 if(w_inltv(ctlr, &ltv))
  909                         print("#l%d: unable to read base station mac addr\n", ether->ctlrno);
  910                 l += snprint(p+l, READSTR-l, "Base station: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
  911                         ltv.addr[0], ltv.addr[1], ltv.addr[2], ltv.addr[3], ltv.addr[4], ltv.addr[5]);
  912         }
  913         PRINTSTAT("Net name: %s\n", ltv_inname(ctlr, WTyp_WantName));
  914         PRINTSTAT("Node name: %s\n", ltv_inname(ctlr, WTyp_NodeName));
  915         if(ltv_ins(ctlr, WTyp_HasCrypt) == 0)
  916                 PRINTSTR("WEP: not supported\n");
  917         else {
  918                 if(ltv_ins(ctlr, WTyp_Crypt) == 0)
  919                         PRINTSTR("WEP: disabled\n");
  920                 else{
  921                         PRINTSTR("WEP: enabled\n");
  922                         k = ((ctlr->xclear)? "excluded": "included");
  923                         PRINTSTAT("Clear packets: %s\n", k);
  924                         txid = ltv_ins(ctlr, WTyp_TxKey);
  925                         PRINTSTAT("Transmit key id: %d\n", txid);
  926                 }
  927         }
  928         iunlock(ctlr);
  929 
  930         PRINTSTAT("ntxuframes: %lud\n", ctlr->ntxuframes);
  931         PRINTSTAT("ntxmframes: %lud\n", ctlr->ntxmframes);
  932         PRINTSTAT("ntxfrags: %lud\n", ctlr->ntxfrags);
  933         PRINTSTAT("ntxubytes: %lud\n", ctlr->ntxubytes);
  934         PRINTSTAT("ntxmbytes: %lud\n", ctlr->ntxmbytes);
  935         PRINTSTAT("ntxdeferred: %lud\n", ctlr->ntxdeferred);
  936         PRINTSTAT("ntxsretries: %lud\n", ctlr->ntxsretries);
  937         PRINTSTAT("ntxmultiretries: %lud\n", ctlr->ntxmultiretries);
  938         PRINTSTAT("ntxretrylimit: %lud\n", ctlr->ntxretrylimit);
  939         PRINTSTAT("ntxdiscards: %lud\n", ctlr->ntxdiscards);
  940         PRINTSTAT("nrxuframes: %lud\n", ctlr->nrxuframes);
  941         PRINTSTAT("nrxmframes: %lud\n", ctlr->nrxmframes);
  942         PRINTSTAT("nrxfrags: %lud\n", ctlr->nrxfrags);
  943         PRINTSTAT("nrxubytes: %lud\n", ctlr->nrxubytes);
  944         PRINTSTAT("nrxmbytes: %lud\n", ctlr->nrxmbytes);
  945         PRINTSTAT("nrxfcserr: %lud\n", ctlr->nrxfcserr);
  946         PRINTSTAT("nrxdropnobuf: %lud\n", ctlr->nrxdropnobuf);
  947         PRINTSTAT("nrxdropnosa: %lud\n", ctlr->nrxdropnosa);
  948         PRINTSTAT("nrxcantdecrypt: %lud\n", ctlr->nrxcantdecrypt);
  949         PRINTSTAT("nrxmsgfrag: %lud\n", ctlr->nrxmsgfrag);
  950         PRINTSTAT("nrxmsgbadfrag: %lud\n", ctlr->nrxmsgbadfrag);
  951         USED(l);
  952         n = readstr(offset, a, n, p);
  953         free(p);
  954         return n;
  955 }
  956 #undef PRINTSTR
  957 #undef PRINTSTAT
  958 
  959 static int
  960 parsekey(WKey* key, char* a) 
  961 {
  962         int i, k, len, n;
  963         char buf[WMaxKeyLen];
  964 
  965         len = strlen(a);
  966         if(len == WMinKeyLen || len == WMaxKeyLen){
  967                 memset(key->dat, 0, sizeof(key->dat));
  968                 memmove(key->dat, a, len);
  969                 key->len = len;
  970 
  971                 return 0;
  972         }
  973         else if(len == WMinKeyLen*2 || len == WMaxKeyLen*2){
  974                 k = 0;
  975                 for(i = 0; i < len; i++){
  976                         if(*a >= '' && *a <= '9')
  977                                 n = *a++ - '';
  978                         else if(*a >= 'a' && *a <= 'f')
  979                                 n = *a++ - 'a' + 10;
  980                         else if(*a >= 'A' && *a <= 'F')
  981                                 n = *a++ - 'A' + 10;
  982                         else
  983                                 return -1;
  984         
  985                         if(i & 1){
  986                                 buf[k] |= n;
  987                                 k++;
  988                         }
  989                         else
  990                                 buf[k] = n<<4;
  991                 }
  992 
  993                 memset(key->dat, 0, sizeof(key->dat));
  994                 memmove(key->dat, buf, k);
  995                 key->len = k;
  996 
  997                 return 0;
  998         }
  999 
 1000         return -1;
 1001 }
 1002 
 1003 int
 1004 w_option(Ctlr* ctlr, char* buf, long n)
 1005 {
 1006         char *p;
 1007         int i, r;
 1008         Cmdbuf *cb;
 1009 
 1010         r = 0;
 1011 
 1012         cb = parsecmd(buf, n);
 1013         if(cb->nf < 2)
 1014                 r = -1;
 1015         else if(cistrcmp(cb->f[0], "essid") == 0){
 1016                 if(cistrcmp(cb->f[1],"default") == 0)
 1017                         p = "";
 1018                 else
 1019                         p = cb->f[1];
 1020                 if(ctlr->ptype == WPTypeAdHoc){
 1021                         memset(ctlr->netname, 0, sizeof(ctlr->netname));
 1022                         strncpy(ctlr->netname, p, WNameLen);
 1023                 }
 1024                 else{
 1025                         memset(ctlr->wantname, 0, sizeof(ctlr->wantname));
 1026                         strncpy(ctlr->wantname, p, WNameLen);
 1027                 }
 1028         }
 1029         else if(cistrcmp(cb->f[0], "station") == 0){
 1030                 memset(ctlr->nodename, 0, sizeof(ctlr->nodename));
 1031                 strncpy(ctlr->nodename, cb->f[1], WNameLen);
 1032         }
 1033         else if(cistrcmp(cb->f[0], "channel") == 0){
 1034                 if((i = atoi(cb->f[1])) >= 1 && i <= 16)
 1035                         ctlr->chan = i;
 1036                 else
 1037                         r = -1;
 1038         }
 1039         else if(cistrcmp(cb->f[0], "mode") == 0){
 1040                 if(cistrcmp(cb->f[1], "managed") == 0)
 1041                         ctlr->ptype = WPTypeManaged;
 1042                 else if(cistrcmp(cb->f[1], "wds") == 0)
 1043                         ctlr->ptype = WPTypeWDS;
 1044                 else if(cistrcmp(cb->f[1], "adhoc") == 0)
 1045                         ctlr->ptype = WPTypeAdHoc;
 1046                 else if((i = atoi(cb->f[1])) >= 0 && i <= 3)
 1047                         ctlr->ptype = i;
 1048                 else
 1049                         r = -1;
 1050         }
 1051         else if(cistrcmp(cb->f[0], "ibss") == 0){
 1052                 if(cistrcmp(cb->f[1], "on") == 0)
 1053                         ctlr->createibss = 1;
 1054                 else
 1055                         ctlr->createibss = 0;
 1056         }
 1057         else if(cistrcmp(cb->f[0], "crypt") == 0){
 1058                 if(cistrcmp(cb->f[1], "off") == 0)
 1059                         ctlr->crypt = 0;
 1060                 else if(cistrcmp(cb->f[1], "on") == 0 && ctlr->hascrypt)
 1061                         ctlr->crypt = 1;
 1062                 else
 1063                         r = -1;
 1064         }
 1065         else if(cistrcmp(cb->f[0], "clear") == 0){
 1066                 if(cistrcmp(cb->f[1], "on") == 0)
 1067                         ctlr->xclear = 0;
 1068                 else if(cistrcmp(cb->f[1], "off") == 0 && ctlr->hascrypt)
 1069                         ctlr->xclear = 1;
 1070                 else
 1071                         r = -1;
 1072         }
 1073         else if(cistrncmp(cb->f[0], "key", 3) == 0){
 1074                 if((i = atoi(cb->f[0]+3)) >= 1 && i <= WNKeys){
 1075                         ctlr->txkey = i-1;
 1076                         if(parsekey(&ctlr->keys.keys[ctlr->txkey], cb->f[1]))
 1077                                 r = -1;
 1078                 }
 1079                 else
 1080                         r = -1;
 1081         }
 1082         else if(cistrcmp(cb->f[0], "txkey") == 0){
 1083                 if((i = atoi(cb->f[1])) >= 1 && i <= WNKeys)
 1084                         ctlr->txkey = i-1;
 1085                 else
 1086                         r = -1;
 1087         }
 1088         else if(cistrcmp(cb->f[0], "pm") == 0){
 1089                 if(cistrcmp(cb->f[1], "off") == 0)
 1090                         ctlr->pmena = 0;
 1091                 else if(cistrcmp(cb->f[1], "on") == 0){
 1092                         ctlr->pmena = 1;
 1093                         if(cb->nf == 3){
 1094                                 i = atoi(cb->f[2]);
 1095                                 // check range here? what are the units?
 1096                                 ctlr->pmwait = i;
 1097                         }
 1098                 }
 1099                 else
 1100                         r = -1;
 1101         }
 1102         else
 1103                 r = -2;
 1104         free(cb);
 1105 
 1106         return r;
 1107 }
 1108 
 1109 long
 1110 w_ctl(Ether* ether, void* buf, long n)
 1111 {
 1112         Ctlr *ctlr;
 1113 
 1114         if((ctlr = ether->ctlr) == nil)
 1115                 error(Enonexist);
 1116         if((ctlr->state & Attached) == 0)
 1117                 error(Eshutdown);
 1118 
 1119         ilock(ctlr);
 1120         if(w_option(ctlr, buf, n)){
 1121                 iunlock(ctlr);
 1122                 error(Ebadctl);
 1123         }
 1124         if(ctlr->txbusy)
 1125                 w_txdone(ctlr, WTxErrEv);
 1126         w_enable(ether);
 1127         w_txstart(ether);
 1128         iunlock(ctlr);
 1129 
 1130         return n;
 1131 }
 1132 
 1133 void
 1134 w_transmit(Ether* ether)
 1135 {
 1136         Ctlr* ctlr = ether->ctlr;
 1137 
 1138         if(ctlr == 0)
 1139                 return;
 1140 
 1141         ilock(ctlr);
 1142         ctlr->ntxrq++;
 1143         w_txstart(ether);
 1144         iunlock(ctlr);
 1145 }
 1146 
 1147 void
 1148 w_promiscuous(void* arg, int on)
 1149 {
 1150         Ether* ether = (Ether*)arg;
 1151         Ctlr* ctlr = ether->ctlr;
 1152 
 1153         if(ctlr == nil)
 1154                 error("card not found");
 1155         if((ctlr->state & Attached) == 0)
 1156                 error("card not attached");
 1157         ilock(ctlr);
 1158         ltv_outs(ctlr, WTyp_Prom, (on?1:0));
 1159         iunlock(ctlr);
 1160 }
 1161 
 1162 void
 1163 w_interrupt(Ureg* ,void* arg)
 1164 {
 1165         Ether* ether = (Ether*) arg;
 1166         Ctlr* ctlr = (Ctlr*) ether->ctlr;
 1167 
 1168         if(ctlr == 0)
 1169                 return;
 1170         ilock(ctlr);
 1171         ctlr->nints++;
 1172         w_intr(ether);
 1173         iunlock(ctlr);
 1174 }
 1175 
 1176 int
 1177 wavelanreset(Ether* ether, Ctlr *ctlr)
 1178 {
 1179         Wltv ltv;
 1180 
 1181         iprint("wavelanreset, iob 0x%ux\n", ctlr->iob);
 1182         w_intdis(ctlr);
 1183         if(w_cmd(ctlr,WCmdIni,0)){
 1184                 iprint("#l%d: init failed\n", ether->ctlrno);
 1185                 return -1;
 1186         }
 1187         w_intdis(ctlr);
 1188         ltv_outs(ctlr, WTyp_Tick, 8);
 1189 
 1190         ctlr->chan = 0;
 1191         ctlr->ptype = WDfltPType;
 1192         ctlr->txkey = 0;
 1193         ctlr->createibss = 0;
 1194         ctlr->keys.len = sizeof(WKey)*WNKeys/2 + 1;
 1195         ctlr->keys.type = WTyp_Keys;
 1196         if(ctlr->hascrypt = ltv_ins(ctlr, WTyp_HasCrypt))
 1197                 ctlr->crypt = 1;
 1198         *ctlr->netname = *ctlr->wantname = 0;
 1199         strcpy(ctlr->nodename, "Plan 9 STA");
 1200 
 1201         ctlr->netname[WNameLen-1] = 0;
 1202         ctlr->wantname[WNameLen-1] = 0;
 1203         ctlr->nodename[WNameLen-1] =0;
 1204 
 1205         ltv.type = WTyp_Mac;
 1206         ltv.len = 4;
 1207         if(w_inltv(ctlr, &ltv)){
 1208                 iprint("#l%d: unable to read mac addr\n",
 1209                         ether->ctlrno);
 1210                 return -1;
 1211         }
 1212         memmove(ether->ea, ltv.addr, Eaddrlen);
 1213 
 1214         if(ctlr->chan == 0)
 1215                 ctlr->chan = ltv_ins(ctlr, WTyp_Chan);
 1216         ctlr->apdensity = WDfltApDens;
 1217         ctlr->rtsthres = WDfltRtsThres;
 1218         ctlr->txrate = WDfltTxRate;
 1219         ctlr->maxlen = WMaxLen;
 1220         ctlr->pmena = 0;
 1221         ctlr->pmwait = 100;
 1222         ctlr->signal = 1;
 1223         ctlr->noise = 1;
 1224         ctlr->state |= Power;
 1225 
 1226         // free old Ctlr struct if resetting after suspend
 1227         if(ether->ctlr && ether->ctlr != ctlr)
 1228                 free(ether->ctlr);
 1229 
 1230         // link to ether
 1231         ether->ctlr = ctlr;
 1232         ether->mbps = 10;
 1233         ether->attach = w_attach;
 1234         ether->detach = w_detach;
 1235         ether->interrupt = w_interrupt;
 1236         ether->transmit = w_transmit;
 1237         ether->ifstat = w_ifstat;
 1238         ether->ctl = w_ctl;
 1239         ether->power = w_power;
 1240         ether->promiscuous = w_promiscuous;
 1241         ether->multicast = w_multicast;
 1242         ether->scanbs = w_scanbs;
 1243         ether->arg = ether;
 1244 
 1245         DEBUG("#l%d: irq %d port %lx type %s",
 1246                 ether->ctlrno, ether->irq, ether->port, ether->type);
 1247         DEBUG(" %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux\n",
 1248                 ether->ea[0], ether->ea[1], ether->ea[2],
 1249                 ether->ea[3], ether->ea[4], ether->ea[5]);
 1250 
 1251         return 0;
 1252 }
 1253 
 1254 char* wavenames[] = {
 1255         "WaveLAN/IEEE",
 1256         "TrueMobile 1150",
 1257         "Instant Wireless ; Network PC CARD",
 1258         "Instant Wireless Network PC Card",
 1259         "Avaya Wireless PC Card",
 1260         "AirLancer MC-11",
 1261         "INTERSIL;HFA384x/IEEE;Version 01.02;",
 1262         nil,
 1263 };

Cache object: 2fa1e20f5d258a26471df762a9603cbe


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.