wavelan.c 27 KB

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