1 /*
2 * Broadcom bcm4330 wifi (sdio interface)
3 */
4
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "io.h"
11 #include "../port/error.h"
12 #include "../port/netif.h"
13 #include "../port/sd.h"
14
15 extern int sdiocardintr(int);
16
17 #include "etherif.h"
18 #define CACHELINESZ 64 /* temp */
19
20 enum{
21 SDIODEBUG = 0,
22 SBDEBUG = 0,
23 EVENTDEBUG = 0,
24 VARDEBUG = 0,
25 FWDEBUG = 0,
26
27 Corescansz = 512,
28 Uploadsz = 2048,
29
30 Wifichan = 0, /* default channel */
31 Firmwarecmp = 1,
32
33 ARMcm3 = 0x82A,
34 ARM7tdmi = 0x825,
35 ARMcr4 = 0x83E,
36
37 Fn0 = 0,
38 Fn1 = 1,
39 Fn2 = 2,
40 Fbr1 = 0x100,
41 Fbr2 = 0x200,
42
43 /* CCCR */
44 Ioenable = 0x02,
45 Ioready = 0x03,
46 Intenable = 0x04,
47 Intpend = 0x05,
48 Ioabort = 0x06,
49 Busifc = 0x07,
50 Capability = 0x08,
51 Blksize = 0x10,
52 Highspeed = 0x13,
53
54 /* SDIOCommands */
55 GO_IDLE_STATE = 0,
56 SEND_RELATIVE_ADDR = 3,
57 IO_SEND_OP_COND = 5,
58 SELECT_CARD = 7,
59 VOLTAGE_SWITCH = 11,
60 IO_RW_DIRECT = 52,
61 IO_RW_EXTENDED = 53,
62
63 /* SELECT_CARD args */
64 Rcashift = 16,
65
66 /* SEND_OP_COND args */
67 Hcs = 1<<30, /* host supports SDHC & SDXC */
68 V3_3 = 3<<20, /* 3.2-3.4 volts */
69 V2_8 = 3<<15, /* 2.7-2.9 volts */
70 V2_0 = 1<<8, /* 2.0-2.1 volts */
71 S18R = 1<<24, /* switch to 1.8V request */
72
73 /* Sonics Silicon Backplane (access to cores on chip) */
74 Sbwsize = 0x8000,
75 Sb32bit = 0x8000,
76 Sbaddr = 0x1000a,
77 Enumbase = 0x18000000,
78 Framectl= 0x1000d,
79 Rfhalt = 0x01,
80 Wfhalt = 0x02,
81 Clkcsr = 0x1000e,
82 ForceALP = 0x01, /* active low-power clock */
83 ForceHT = 0x02, /* high throughput clock */
84 ForceILP = 0x04, /* idle low-power clock */
85 ReqALP = 0x08,
86 ReqHT = 0x10,
87 Nohwreq = 0x20,
88 ALPavail = 0x40,
89 HTavail = 0x80,
90 Pullups = 0x1000f,
91 Wfrmcnt = 0x10019,
92 Rfrmcnt = 0x1001b,
93
94 /* core control regs */
95 Ioctrl = 0x408,
96 Resetctrl = 0x800,
97
98 /* socram regs */
99 Coreinfo = 0x00,
100 Bankidx = 0x10,
101 Bankinfo = 0x40,
102 Bankpda = 0x44,
103
104 /* armcr4 regs */
105 Cr4Cap = 0x04,
106 Cr4Bankidx = 0x40,
107 Cr4Bankinfo = 0x44,
108 Cr4Cpuhalt = 0x20,
109
110 /* chipcommon regs */
111 Gpiopullup = 0x58,
112 Gpiopulldown = 0x5c,
113 Chipctladdr = 0x650,
114 Chipctldata = 0x654,
115
116 /* sdio core regs */
117 Intstatus = 0x20,
118 Fcstate = 1<<4,
119 Fcchange = 1<<5,
120 FrameInt = 1<<6,
121 MailboxInt = 1<<7,
122 Intmask = 0x24,
123 Sbmbox = 0x40,
124 Sbmboxdata = 0x48,
125 Hostmboxdata= 0x4c,
126 Fwready = 0x80,
127
128 /* wifi control commands */
129 GetVar = 262,
130 SetVar = 263,
131
132 /* status */
133 Disconnected= 0,
134 Connecting,
135 Connected,
136 };
137
138 typedef struct Ctlr Ctlr;
139
140 enum{
141 Wpa = 1,
142 Wep = 2,
143 Wpa2 = 3,
144 WNameLen = 32,
145 WNKeys = 4,
146 WKeyLen = 32,
147 WMinKeyLen = 5,
148 WMaxKeyLen = 13,
149 };
150
151 typedef struct WKey WKey;
152 struct WKey
153 {
154 ushort len;
155 char dat[WKeyLen];
156 };
157
158 struct Ctlr {
159 Ether* edev;
160 QLock cmdlock;
161 QLock pktlock;
162 QLock tlock;
163 QLock alock;
164 Lock txwinlock;
165 Rendez cmdr;
166 Rendez joinr;
167 int joinstatus;
168 int cryptotype;
169 int chanid;
170 char essid[WNameLen + 1];
171 WKey keys[WNKeys];
172 Block *rsp;
173 Block *scanb;
174 int scansecs;
175 int status;
176 int chipid;
177 int chiprev;
178 int armcore;
179 char *regufile;
180 union {
181 u32int i;
182 uchar c[4];
183 } resetvec;
184 ulong chipcommon;
185 ulong armctl;
186 ulong armregs;
187 ulong d11ctl;
188 ulong socramregs;
189 ulong socramctl;
190 ulong sdregs;
191 int sdiorev;
192 int socramrev;
193 ulong socramsize;
194 ulong rambase;
195 short reqid;
196 uchar fcmask;
197 uchar txwindow;
198 uchar txseq;
199 uchar rxseq;
200 };
201
202 enum{
203 CMauth,
204 CMchannel,
205 CMcrypt,
206 CMessid,
207 CMkey1,
208 CMkey2,
209 CMkey3,
210 CMkey4,
211 CMrxkey,
212 CMrxkey0,
213 CMrxkey1,
214 CMrxkey2,
215 CMrxkey3,
216 CMtxkey,
217 CMdebug,
218 CMjoin,
219 };
220
221 static Cmdtab cmds[] = {
222 {CMauth, "auth", 2},
223 {CMchannel, "channel", 2},
224 {CMcrypt, "crypt", 2},
225 {CMessid, "essid", 2},
226 {CMkey1, "key1", 2},
227 {CMkey2, "key1", 2},
228 {CMkey3, "key1", 2},
229 {CMkey4, "key1", 2},
230 {CMrxkey, "rxkey", 3},
231 {CMrxkey0, "rxkey0", 3},
232 {CMrxkey1, "rxkey1", 3},
233 {CMrxkey2, "rxkey2", 3},
234 {CMrxkey3, "rxkey3", 3},
235 {CMtxkey, "txkey", 3},
236 {CMdebug, "debug", 2},
237 {CMjoin, "join", 5},
238 };
239
240 typedef struct Sdpcm Sdpcm;
241 typedef struct Cmd Cmd;
242 struct Sdpcm {
243 uchar len[2];
244 uchar lenck[2];
245 uchar seq;
246 uchar chanflg;
247 uchar nextlen;
248 uchar doffset;
249 uchar fcmask;
250 uchar window;
251 uchar version;
252 uchar pad;
253 };
254
255 struct Cmd {
256 uchar cmd[4];
257 uchar len[4];
258 uchar flags[2];
259 uchar id[2];
260 uchar status[4];
261 };
262
263 static char config40181[] = "bcmdhd.cal.40181";
264 static char config40183[] = "bcmdhd.cal.40183.26MHz";
265
266 struct {
267 int chipid;
268 int chiprev;
269 char *fwfile;
270 char *cfgfile;
271 char *regufile;
272 } firmware[] = {
273 { 0x4330, 3, "fw_bcm40183b1.bin", config40183, 0 },
274 { 0x4330, 4, "fw_bcm40183b2.bin", config40183, 0 },
275 { 43362, 0, "fw_bcm40181a0.bin", config40181, 0 },
276 { 43362, 1, "fw_bcm40181a2.bin", config40181, 0 },
277 { 43430, 1, "brcmfmac43430-sdio.bin", "brcmfmac43430-sdio.txt", 0 },
278 { 43430, 2, "brcmfmac43436-sdio.bin", "brcmfmac43436-sdio.txt", "brcmfmac43436-sdio.clm_blob" },
279 { 0x4345, 6, "brcmfmac43455-sdio.bin", "brcmfmac43455-sdio.txt", "brcmfmac43455-sdio.clm_blob" },
280 };
281
282 static QLock sdiolock;
283 static int iodebug;
284
285 static void etherbcmintr(void *);
286 static void bcmevent(Ctlr*, uchar*, int);
287 static void wlscanresult(Ether*, uchar*, int);
288 static void wlsetvar(Ctlr*, char*, void*, int);
289
290 static uchar*
put2(uchar * p,short v)291 put2(uchar *p, short v)
292 {
293 p[0] = v;
294 p[1] = v >> 8;
295 return p + 2;
296 }
297
298 static uchar*
put4(uchar * p,long v)299 put4(uchar *p, long v)
300 {
301 p[0] = v;
302 p[1] = v >> 8;
303 p[2] = v >> 16;
304 p[3] = v >> 24;
305 return p + 4;
306 }
307
308 static ushort
get2(uchar * p)309 get2(uchar *p)
310 {
311 return p[0] | p[1]<<8;
312 }
313
314 static ulong
get4(uchar * p)315 get4(uchar *p)
316 {
317 return p[0] | p[1]<<8 | p[2]<<16 | p[3]<<24;
318 }
319
320 static void
dump(char * s,void * a,int n)321 dump(char *s, void *a, int n)
322 {
323 int i;
324 uchar *p;
325
326 p = a;
327 print("%s:", s);
328 for(i = 0; i < n; i++)
329 print("%c%2.2x", i&15? ' ' : '\n', *p++);
330 print("\n");
331 }
332
333 /*
334 * SDIO communication with dongle
335 */
336 static ulong
sdiocmd_locked(int cmd,ulong arg)337 sdiocmd_locked(int cmd, ulong arg)
338 {
339 u32int resp[4];
340
341 sdio.cmd(cmd, arg, resp);
342 return resp[0];
343 }
344
345 static ulong
sdiocmd(int cmd,ulong arg)346 sdiocmd(int cmd, ulong arg)
347 {
348 ulong r;
349
350 qlock(&sdiolock);
351 if(waserror()){
352 if(SDIODEBUG) print("sdiocmd error: cmd %d arg %lux\n", cmd, arg);
353 qunlock(&sdiolock);
354 nexterror();
355 }
356 r = sdiocmd_locked(cmd, arg);
357 qunlock(&sdiolock);
358 poperror();
359 return r;
360
361 }
362
363 static ulong
trysdiocmd(int cmd,ulong arg)364 trysdiocmd(int cmd, ulong arg)
365 {
366 ulong r;
367
368 if(waserror())
369 return 0;
370 r = sdiocmd(cmd, arg);
371 poperror();
372 return r;
373 }
374
375 static int
sdiord(int fn,int addr)376 sdiord(int fn, int addr)
377 {
378 int r;
379
380 r = sdiocmd(IO_RW_DIRECT, (0<<31)|((fn&7)<<28)|((addr&0x1FFFF)<<9));
381 if(r & 0xCF00){
382 print("ether4330: sdiord(%x, %x) fail: %2.2ux %2.2ux\n", fn, addr, (r>>8)&0xFF, r&0xFF);
383 error(Eio);
384 }
385 return r & 0xFF;
386 }
387
388 static void
sdiowr(int fn,int addr,int data)389 sdiowr(int fn, int addr, int data)
390 {
391 int r;
392 int retry;
393
394 r = 0;
395 for(retry = 0; retry < 10; retry++){
396 r = sdiocmd(IO_RW_DIRECT, (1<<31)|((fn&7)<<28)|((addr&0x1FFFF)<<9)|(data&0xFF));
397 if((r & 0xCF00) == 0)
398 return;
399 }
400 print("ether4330: sdiowr(%x, %x, %x) fail: %2.2ux %2.2ux\n", fn, addr, data, (r>>8)&0xFF, r&0xFF);
401 error(Eio);
402 }
403
404 static void
sdiorwext(int fn,int write,void * a,int len,int addr,int incr)405 sdiorwext(int fn, int write, void *a, int len, int addr, int incr)
406 {
407 int bsize, blk, bcount, m;
408
409 bsize = fn == Fn2? 512 : 64;
410 while(len > 0){
411 if(len >= 511*bsize){
412 blk = 1;
413 bcount = 511;
414 m = bcount*bsize;
415 }else if(len > bsize){
416 blk = 1;
417 bcount = len/bsize;
418 m = bcount*bsize;
419 }else{
420 blk = 0;
421 bcount = len;
422 m = bcount;
423 }
424 qlock(&sdiolock);
425 if(waserror()){
426 print("ether4330: sdiorwext fail: %s\n", up->errstr);
427 qunlock(&sdiolock);
428 nexterror();
429 }
430 if(blk)
431 sdio.iosetup(write, a, bsize, bcount);
432 else
433 sdio.iosetup(write, a, bcount, 1);
434 sdiocmd_locked(IO_RW_EXTENDED,
435 write<<31 | (fn&7)<<28 | blk<<27 | incr<<26 | (addr&0x1FFFF)<<9 | (bcount&0x1FF));
436 sdio.io(write, a, m);
437 qunlock(&sdiolock);
438 poperror();
439 len -= m;
440 a = (char*)a + m;
441 if(incr)
442 addr += m;
443 }
444 }
445
446 static void
sdioset(int fn,int addr,int bits)447 sdioset(int fn, int addr, int bits)
448 {
449 sdiowr(fn, addr, sdiord(fn, addr) | bits);
450 }
451
452 static void
sdioinit(void)453 sdioinit(void)
454 {
455 ulong ocr, rca;
456 int i;
457
458 /* disconnect emmc from SD card (connect sdhost instead) */
459 for(i = 48; i <= 53; i++)
460 gpiosel(i, Alt0);
461 /* connect emmc to wifi */
462 for(i = 34; i <= 39; i++){
463 gpiosel(i, Alt3);
464 if(i == 34)
465 gpiopulloff(i);
466 else
467 gpiopullup(i);
468 }
469 sdio.init();
470 sdio.enable();
471 sdiocmd(GO_IDLE_STATE, 0);
472 ocr = trysdiocmd(IO_SEND_OP_COND, 0);
473 i = 0;
474 while((ocr & (1<<31)) == 0){
475 if(++i > 5){
476 print("ether4330: no response to sdio access: ocr = %lux\n", ocr);
477 error(Eio);
478 }
479 ocr = trysdiocmd(IO_SEND_OP_COND, V3_3);
480 tsleep(&up->sleep, return0, nil, 100);
481 }
482 rca = sdiocmd(SEND_RELATIVE_ADDR, 0) >> Rcashift;
483 sdiocmd(SELECT_CARD, rca << Rcashift);
484 sdioset(Fn0, Highspeed, 2);
485 sdioset(Fn0, Busifc, 2); /* bus width 4 */
486 sdiowr(Fn0, Fbr1+Blksize, 64);
487 sdiowr(Fn0, Fbr1+Blksize+1, 64>>8);
488 sdiowr(Fn0, Fbr2+Blksize, 512);
489 sdiowr(Fn0, Fbr2+Blksize+1, 512>>8);
490 sdioset(Fn0, Ioenable, 1<<Fn1);
491 sdiowr(Fn0, Intenable, 0);
492 for(i = 0; !(sdiord(Fn0, Ioready) & 1<<Fn1); i++){
493 if(i == 10){
494 print("ether4330: can't enable SDIO function\n");
495 error(Eio);
496 }
497 tsleep(&up->sleep, return0, nil, 100);
498 }
499 }
500
501 static void
sdioreset(void)502 sdioreset(void)
503 {
504 sdiowr(Fn0, Ioabort, 1<<3); /* reset */
505 }
506
507 static void
sdioabort(int fn)508 sdioabort(int fn)
509 {
510 sdiowr(Fn0, Ioabort, fn);
511 }
512
513 /*
514 * Chip register and memory access via SDIO
515 */
516
517 static void
cfgw(ulong off,int val)518 cfgw(ulong off, int val)
519 {
520 sdiowr(Fn1, off, val);
521 }
522
523 static int
cfgr(ulong off)524 cfgr(ulong off)
525 {
526 return sdiord(Fn1, off);
527 }
528
529 static ulong
cfgreadl(int fn,ulong off)530 cfgreadl(int fn, ulong off)
531 {
532 uchar cbuf[2*CACHELINESZ];
533 uchar *p;
534
535 p = (uchar*)ROUND((uintptr)cbuf, CACHELINESZ);
536 memset(p, 0, 4);
537 sdiorwext(fn, 0, p, 4, off|Sb32bit, 1);
538 if(SDIODEBUG) print("cfgreadl %lux: %2.2x %2.2x %2.2x %2.2x\n", off, p[0], p[1], p[2], p[3]);
539 return p[0] | p[1]<<8 | p[2]<<16 | p[3]<<24;
540 }
541
542 static void
cfgwritel(int fn,ulong off,u32int data)543 cfgwritel(int fn, ulong off, u32int data)
544 {
545 uchar cbuf[2*CACHELINESZ];
546 uchar *p;
547 int retry;
548
549 p = (uchar*)ROUND((uintptr)cbuf, CACHELINESZ);
550 put4(p, data);
551 if(SDIODEBUG) print("cfgwritel %lux: %2.2x %2.2x %2.2x %2.2x\n", off, p[0], p[1], p[2], p[3]);
552 retry = 0;
553 while(waserror()){
554 print("ether4330: cfgwritel retry %lux %ux\n", off, data);
555 sdioabort(fn);
556 if(++retry == 3)
557 nexterror();
558 }
559 sdiorwext(fn, 1, p, 4, off|Sb32bit, 1);
560 poperror();
561 }
562
563 static void
sbwindow(ulong addr)564 sbwindow(ulong addr)
565 {
566 addr &= ~(Sbwsize-1);
567 cfgw(Sbaddr, addr>>8);
568 cfgw(Sbaddr+1, addr>>16);
569 cfgw(Sbaddr+2, addr>>24);
570 }
571
572 static void
sbrw(int fn,int write,uchar * buf,int len,ulong off)573 sbrw(int fn, int write, uchar *buf, int len, ulong off)
574 {
575 int n;
576 USED(fn);
577
578 if(waserror()){
579 print("ether4330: sbrw err off %lux len %ud\n", off, len);
580 nexterror();
581 }
582 if(write){
583 if(len >= 4){
584 n = len;
585 n &= ~3;
586 sdiorwext(Fn1, write, buf, n, off|Sb32bit, 1);
587 off += n;
588 buf += n;
589 len -= n;
590 }
591 while(len > 0){
592 sdiowr(Fn1, off|Sb32bit, *buf);
593 off++;
594 buf++;
595 len--;
596 }
597 }else{
598 if(len >= 4){
599 n = len;
600 n &= ~3;
601 sdiorwext(Fn1, write, buf, n, off|Sb32bit, 1);
602 off += n;
603 buf += n;
604 len -= n;
605 }
606 while(len > 0){
607 *buf = sdiord(Fn1, off|Sb32bit);
608 off++;
609 buf++;
610 len--;
611 }
612 }
613 poperror();
614 }
615
616 static void
sbmem(int write,uchar * buf,int len,ulong off)617 sbmem(int write, uchar *buf, int len, ulong off)
618 {
619 ulong n;
620
621 n = ROUNDUP(off, Sbwsize) - off;
622 if(n == 0)
623 n = Sbwsize;
624 while(len > 0){
625 if(n > len)
626 n = len;
627 sbwindow(off);
628 sbrw(Fn1, write, buf, n, off & (Sbwsize-1));
629 off += n;
630 buf += n;
631 len -= n;
632 n = Sbwsize;
633 }
634 }
635
636 static void
packetrw(int write,uchar * buf,int len)637 packetrw(int write, uchar *buf, int len)
638 {
639 int n;
640 int retry;
641
642 n = 2048;
643 while(len > 0){
644 if(n > len)
645 n = ROUND(len, 4);
646 retry = 0;
647 while(waserror()){
648 sdioabort(Fn2);
649 if(++retry == 3)
650 nexterror();
651 }
652 sdiorwext(Fn2, write, buf, n, Enumbase, 0);
653 poperror();
654 buf += n;
655 len -= n;
656 }
657 }
658
659 /*
660 * Configuration and control of chip cores via Silicon Backplane
661 */
662
663 static void
sbdisable(ulong regs,int pre,int ioctl)664 sbdisable(ulong regs, int pre, int ioctl)
665 {
666 sbwindow(regs);
667 if((cfgreadl(Fn1, regs + Resetctrl) & 1) != 0){
668 cfgwritel(Fn1, regs + Ioctrl, 3|ioctl);
669 cfgreadl(Fn1, regs + Ioctrl);
670 return;
671 }
672 cfgwritel(Fn1, regs + Ioctrl, 3|pre);
673 cfgreadl(Fn1, regs + Ioctrl);
674 cfgwritel(Fn1, regs + Resetctrl, 1);
675 microdelay(10);
676 while((cfgreadl(Fn1, regs + Resetctrl) & 1) == 0)
677 ;
678 cfgwritel(Fn1, regs + Ioctrl, 3|ioctl);
679 cfgreadl(Fn1, regs + Ioctrl);
680 }
681
682 static void
sbreset(ulong regs,int pre,int ioctl)683 sbreset(ulong regs, int pre, int ioctl)
684 {
685 sbdisable(regs, pre, ioctl);
686 sbwindow(regs);
687 if(SBDEBUG) print("sbreset %#p %#lux %#lux ->", regs,
688 cfgreadl(Fn1, regs+Ioctrl), cfgreadl(Fn1, regs+Resetctrl));
689 while((cfgreadl(Fn1, regs + Resetctrl) & 1) != 0){
690 cfgwritel(Fn1, regs + Resetctrl, 0);
691 microdelay(40);
692 }
693 cfgwritel(Fn1, regs + Ioctrl, 1|ioctl);
694 cfgreadl(Fn1, regs + Ioctrl);
695 if(SBDEBUG) print("%#lux %#lux\n",
696 cfgreadl(Fn1, regs+Ioctrl), cfgreadl(Fn1, regs+Resetctrl));
697 }
698
699 static void
corescan(Ctlr * ctl,ulong r)700 corescan(Ctlr *ctl, ulong r)
701 {
702 uchar *buf;
703 int i, coreid, corerev;
704 ulong addr;
705
706 buf = sdmalloc(Corescansz);
707 if(buf == nil)
708 error(Enomem);
709 sbmem(0, buf, Corescansz, r);
710 coreid = 0;
711 corerev = 0;
712 for(i = 0; i < Corescansz; i += 4){
713 switch(buf[i]&0xF){
714 case 0xF: /* end */
715 sdfree(buf);
716 return;
717 case 0x1: /* core info */
718 if((buf[i+4]&0xF) != 0x1)
719 break;
720 coreid = (buf[i+1] | buf[i+2]<<8) & 0xFFF;
721 i += 4;
722 corerev = buf[i+3];
723 break;
724 case 0x05: /* address */
725 addr = buf[i+1]<<8 | buf[i+2]<<16 | buf[i+3]<<24;
726 addr &= ~0xFFF;
727 if(SBDEBUG) print("core %x %s %#p\n", coreid, buf[i]&0xC0? "ctl" : "mem", addr);
728 switch(coreid){
729 case 0x800:
730 if((buf[i] & 0xC0) == 0)
731 ctl->chipcommon = addr;
732 break;
733 case ARMcm3:
734 case ARM7tdmi:
735 case ARMcr4:
736 ctl->armcore = coreid;
737 if(buf[i] & 0xC0){
738 if(ctl->armctl == 0)
739 ctl->armctl = addr;
740 }else{
741 if(ctl->armregs == 0)
742 ctl->armregs = addr;
743 }
744 break;
745 case 0x80E:
746 if(buf[i] & 0xC0)
747 ctl->socramctl = addr;
748 else if(ctl->socramregs == 0)
749 ctl->socramregs = addr;
750 ctl->socramrev = corerev;
751 break;
752 case 0x829:
753 if((buf[i] & 0xC0) == 0)
754 ctl->sdregs = addr;
755 ctl->sdiorev = corerev;
756 break;
757 case 0x812:
758 if(buf[i] & 0xC0)
759 ctl->d11ctl = addr;
760 break;
761 }
762 }
763 }
764 sdfree(buf);
765 }
766
767 static void
ramscan(Ctlr * ctl)768 ramscan(Ctlr *ctl)
769 {
770 ulong r, n, size;
771 int banks, i;
772
773 if(ctl->armcore == ARMcr4){
774 r = ctl->armregs;
775 sbwindow(r);
776 n = cfgreadl(Fn1, r + Cr4Cap);
777 if(SBDEBUG) print("cr4 banks %lux\n", n);
778 banks = ((n>>4) & 0xF) + (n & 0xF);
779 size = 0;
780 for(i = 0; i < banks; i++){
781 cfgwritel(Fn1, r + Cr4Bankidx, i);
782 n = cfgreadl(Fn1, r + Cr4Bankinfo);
783 if(SBDEBUG) print("bank %d reg %lux size %lud\n", i, n, 8192 * ((n & 0x3F) + 1));
784 size += 8192 * ((n & 0x3F) + 1);
785 }
786 ctl->socramsize = size;
787 ctl->rambase = 0x198000;
788 return;
789 }
790 if(ctl->socramrev <= 7 || ctl->socramrev == 12){
791 print("ether4330: SOCRAM rev %d not supported\n", ctl->socramrev);
792 error(Eio);
793 }
794 sbreset(ctl->socramctl, 0, 0);
795 r = ctl->socramregs;
796 sbwindow(r);
797 n = cfgreadl(Fn1, r + Coreinfo);
798 if(SBDEBUG) print("socramrev %d coreinfo %lux\n", ctl->socramrev, n);
799 banks = (n>>4) & 0xF;
800 size = 0;
801 for(i = 0; i < banks; i++){
802 cfgwritel(Fn1, r + Bankidx, i);
803 n = cfgreadl(Fn1, r + Bankinfo);
804 if(SBDEBUG) print("bank %d reg %lux size %lud\n", i, n, 8192 * ((n & 0x3F) + 1));
805 size += 8192 * ((n & 0x3F) + 1);
806 }
807 ctl->socramsize = size;
808 ctl->rambase = 0;
809 if(ctl->chipid == 43430){
810 cfgwritel(Fn1, r + Bankidx, 3);
811 cfgwritel(Fn1, r + Bankpda, 0);
812 }
813 }
814
815 static void
sbinit(Ctlr * ctl)816 sbinit(Ctlr *ctl)
817 {
818 ulong r;
819 int chipid;
820 char buf[16];
821
822 sbwindow(Enumbase);
823 r = cfgreadl(Fn1, Enumbase);
824 chipid = r & 0xFFFF;
825 sprint(buf, chipid > 43000 ? "%d" : "%#x", chipid);
826 print("ether4330: chip %s rev %ld type %ld\n", buf, (r>>16)&0xF, (r>>28)&0xF);
827 switch(chipid){
828 case 0x4330:
829 case 43362:
830 case 43430:
831 case 0x4345:
832 ctl->chipid = chipid;
833 ctl->chiprev = (r>>16)&0xF;
834 break;
835 default:
836 print("ether4330: chipid %#x (%d) not supported\n", chipid, chipid);
837 error(Eio);
838 }
839 r = cfgreadl(Fn1, Enumbase + 63*4);
840 corescan(ctl, r);
841 if(ctl->armctl == 0 || ctl->d11ctl == 0 ||
842 (ctl->armcore == ARMcm3 && (ctl->socramctl == 0 || ctl->socramregs == 0)))
843 error("corescan didn't find essential cores\n");
844 if(ctl->armcore == ARMcr4)
845 sbreset(ctl->armctl, Cr4Cpuhalt, Cr4Cpuhalt);
846 else
847 sbdisable(ctl->armctl, 0, 0);
848 sbreset(ctl->d11ctl, 8|4, 4);
849 ramscan(ctl);
850 if(SBDEBUG) print("ARM %#p D11 %#p SOCRAM %#p,%#p %lud bytes @ %#p\n",
851 ctl->armctl, ctl->d11ctl, ctl->socramctl, ctl->socramregs, ctl->socramsize, ctl->rambase);
852 cfgw(Clkcsr, 0);
853 microdelay(10);
854 if(SBDEBUG) print("chipclk: %x\n", cfgr(Clkcsr));
855 cfgw(Clkcsr, Nohwreq | ReqALP);
856 while((cfgr(Clkcsr) & (HTavail|ALPavail)) == 0)
857 microdelay(10);
858 cfgw(Clkcsr, Nohwreq | ForceALP);
859 microdelay(65);
860 if(SBDEBUG) print("chipclk: %x\n", cfgr(Clkcsr));
861 cfgw(Pullups, 0);
862 sbwindow(ctl->chipcommon);
863 cfgwritel(Fn1, ctl->chipcommon + Gpiopullup, 0);
864 cfgwritel(Fn1, ctl->chipcommon + Gpiopulldown, 0);
865 if(ctl->chipid != 0x4330 && ctl->chipid != 43362)
866 return;
867 cfgwritel(Fn1, ctl->chipcommon + Chipctladdr, 1);
868 if(cfgreadl(Fn1, ctl->chipcommon + Chipctladdr) != 1)
869 print("ether4330: can't set Chipctladdr\n");
870 else{
871 r = cfgreadl(Fn1, ctl->chipcommon + Chipctldata);
872 if(SBDEBUG) print("chipcommon PMU (%lux) %lux", cfgreadl(Fn1, ctl->chipcommon + Chipctladdr), r);
873 /* set SDIO drive strength >= 6mA */
874 r &= ~0x3800;
875 if(ctl->chipid == 0x4330)
876 r |= 3<<11;
877 else
878 r |= 7<<11;
879 cfgwritel(Fn1, ctl->chipcommon + Chipctldata, r);
880 if(SBDEBUG) print("-> %lux (= %lux)\n", r, cfgreadl(Fn1, ctl->chipcommon + Chipctldata));
881 }
882 }
883
884 static void
sbenable(Ctlr * ctl)885 sbenable(Ctlr *ctl)
886 {
887 int i;
888
889 if(SBDEBUG) print("enabling HT clock...");
890 cfgw(Clkcsr, 0);
891 delay(1);
892 cfgw(Clkcsr, ReqHT);
893 for(i = 0; (cfgr(Clkcsr) & HTavail) == 0; i++){
894 if(i == 50){
895 print("ether4330: can't enable HT clock: csr %x\n", cfgr(Clkcsr));
896 error(Eio);
897 }
898 tsleep(&up->sleep, return0, nil, 100);
899 }
900 cfgw(Clkcsr, cfgr(Clkcsr) | ForceHT);
901 delay(10);
902 if(SBDEBUG) print("chipclk: %x\n", cfgr(Clkcsr));
903 sbwindow(ctl->sdregs);
904 cfgwritel(Fn1, ctl->sdregs + Sbmboxdata, 4 << 16); /* protocol version */
905 cfgwritel(Fn1, ctl->sdregs + Intmask, FrameInt | MailboxInt | Fcchange);
906 sdioset(Fn0, Ioenable, 1<<Fn2);
907 for(i = 0; !(sdiord(Fn0, Ioready) & 1<<Fn2); i++){
908 if(i == 10){
909 print("ether4330: can't enable SDIO function 2 - ioready %x\n", sdiord(Fn0, Ioready));
910 error(Eio);
911 }
912 tsleep(&up->sleep, return0, nil, 100);
913 }
914 sdiowr(Fn0, Intenable, (1<<Fn1) | (1<<Fn2) | 1);
915 }
916
917
918 /*
919 * Firmware and config file uploading
920 */
921
922 /*
923 * Condense config file contents (in buffer buf with length n)
924 * to 'var=value\0' list for firmware:
925 * - remove comments (starting with '#') and blank lines
926 * - remove carriage returns
927 * - convert newlines to nulls
928 * - mark end with two nulls
929 * - pad with nulls to multiple of 4 bytes total length
930 */
931 static int
condense(uchar * buf,int n)932 condense(uchar *buf, int n)
933 {
934 uchar *p, *ep, *lp, *op;
935 int c, skipping;
936
937 skipping = 0; /* true if in a comment */
938 ep = buf + n; /* end of input */
939 op = buf; /* end of output */
940 lp = buf; /* start of current output line */
941 for(p = buf; p < ep; p++){
942 switch(c = *p){
943 case '#':
944 skipping = 1;
945 break;
946 case '\0':
947 case '\n':
948 skipping = 0;
949 if(op != lp){
950 *op++ = '\0';
951 lp = op;
952 }
953 break;
954 case '\r':
955 break;
956 default:
957 if(!skipping)
958 *op++ = c;
959 break;
960 }
961 }
962 if(!skipping && op != lp)
963 *op++ = '\0';
964 *op++ = '\0';
965 for(n = op - buf; n & 03; n++)
966 *op++ = '\0';
967 return n;
968 }
969
970 /*
971 * Try to find firmware file in /boot or in /sys/lib/firmware.
972 * Throw an error if not found.
973 */
974 static Chan*
findfirmware(char * file)975 findfirmware(char *file)
976 {
977 char nbuf[64];
978 Chan *c;
979
980 if(!waserror()){
981 snprint(nbuf, sizeof nbuf, "/boot/%s", file);
982 c = namec(nbuf, Aopen, OREAD, 0);
983 poperror();
984 }else if(!waserror()){
985 snprint(nbuf, sizeof nbuf, "/sys/lib/firmware/%s", file);
986 c = namec(nbuf, Aopen, OREAD, 0);
987 poperror();
988 }else{
989 c = nil;
990 snprint(up->genbuf, sizeof up->genbuf, "can't find %s in /boot or /sys/lib/firmware", file);
991 error(up->genbuf);
992 }
993 return c;
994 }
995
996 static int
upload(Ctlr * ctl,char * file,int isconfig)997 upload(Ctlr *ctl, char *file, int isconfig)
998 {
999 Chan *c;
1000 uchar *buf;
1001 uchar *cbuf;
1002 int off, n;
1003
1004 buf = cbuf = nil;
1005 c = findfirmware(file);
1006 if(waserror()){
1007 cclose(c);
1008 sdfree(buf);
1009 sdfree(cbuf);
1010 nexterror();
1011 }
1012 buf = sdmalloc(Uploadsz);
1013 if(buf == nil)
1014 error(Enomem);
1015 if(Firmwarecmp){
1016 cbuf = sdmalloc(Uploadsz);
1017 if(cbuf == nil)
1018 error(Enomem);
1019 }
1020 off = 0;
1021 for(;;){
1022 n = devtab[c->type]->read(c, buf, Uploadsz, off);
1023 if(n <= 0)
1024 break;
1025 if(isconfig){
1026 n = condense(buf, n);
1027 off = ctl->socramsize - n - 4;
1028 }else if(off == 0)
1029 memmove(ctl->resetvec.c, buf, sizeof(ctl->resetvec.c));
1030 while(n&3)
1031 buf[n++] = 0;
1032 sbmem(1, buf, n, ctl->rambase + off);
1033 if(isconfig)
1034 break;
1035 off += n;
1036 }
1037 if(Firmwarecmp){
1038 if(FWDEBUG) print("compare...");
1039 if(!isconfig)
1040 off = 0;
1041 for(;;){
1042 if(!isconfig){
1043 n = devtab[c->type]->read(c, buf, Uploadsz, off);
1044 if(n <= 0)
1045 break;
1046 while(n&3)
1047 buf[n++] = 0;
1048 }
1049 sbmem(0, cbuf, n, ctl->rambase + off);
1050 if(memcmp(buf, cbuf, n) != 0){
1051 print("ether4330: firmware load failed offset %d\n", off);
1052 error(Eio);
1053 }
1054 if(isconfig)
1055 break;
1056 off += n;
1057 }
1058 }
1059 if(FWDEBUG) print("\n");
1060 poperror();
1061 cclose(c);
1062 sdfree(buf);
1063 sdfree(cbuf);
1064 return n;
1065 }
1066
1067 /*
1068 * Upload regulatory file (.clm) to firmware.
1069 * Packet format is
1070 * [2]flag [2]type [4]len [4]crc [len]data
1071 */
1072 static void
reguload(Ctlr * ctl,char * file)1073 reguload(Ctlr *ctl, char *file)
1074 {
1075 Chan *c;
1076 uchar *buf;
1077 int off, n, flag;
1078 enum {
1079 Reguhdr = 2+2+4+4,
1080 Regusz = 1400,
1081 Regutyp = 2,
1082 Flagclm = 1<<12,
1083 Firstpkt= 1<<1,
1084 Lastpkt = 1<<2,
1085 };
1086
1087 buf = nil;
1088 c = findfirmware(file);
1089 if(waserror()){
1090 cclose(c);
1091 free(buf);
1092 nexterror();
1093 }
1094 buf = malloc(Reguhdr+Regusz+1);
1095 if(buf == nil)
1096 error(Enomem);
1097 put2(buf+2, Regutyp);
1098 put2(buf+8, 0);
1099 off = 0;
1100 flag = Flagclm | Firstpkt;
1101 while((flag&Lastpkt) == 0){
1102 n = devtab[c->type]->read(c, buf+Reguhdr, Regusz+1, off);
1103 if(n <= 0)
1104 break;
1105 if(n == Regusz+1)
1106 --n;
1107 else{
1108 while(n&7)
1109 buf[Reguhdr+n++] = 0;
1110 flag |= Lastpkt;
1111 }
1112 put2(buf+0, flag);
1113 put4(buf+4, n);
1114 wlsetvar(ctl, "clmload", buf, Reguhdr + n);
1115 off += n;
1116 flag &= ~Firstpkt;
1117 }
1118 poperror();
1119 cclose(c);
1120 free(buf);
1121 }
1122
1123 static void
fwload(Ctlr * ctl)1124 fwload(Ctlr *ctl)
1125 {
1126 uchar buf[4];
1127 uint i, n;
1128
1129 i = 0;
1130 while(firmware[i].chipid != ctl->chipid ||
1131 firmware[i].chiprev != ctl->chiprev){
1132 if(++i == nelem(firmware)){
1133 print("ether4330: no firmware for chipid %x (%d) chiprev %d\n",
1134 ctl->chipid, ctl->chipid, ctl->chiprev);
1135 error("no firmware");
1136 }
1137 }
1138 ctl->regufile = firmware[i].regufile;
1139 cfgw(Clkcsr, ReqALP);
1140 while((cfgr(Clkcsr) & ALPavail) == 0)
1141 microdelay(10);
1142 memset(buf, 0, 4);
1143 sbmem(1, buf, 4, ctl->rambase + ctl->socramsize - 4);
1144 if(FWDEBUG) print("firmware load...");
1145 upload(ctl, firmware[i].fwfile, 0);
1146 if(FWDEBUG) print("config load...");
1147 n = upload(ctl, firmware[i].cfgfile, 1);
1148 n /= 4;
1149 n = (n & 0xFFFF) | (~n << 16);
1150 put4(buf, n);
1151 sbmem(1, buf, 4, ctl->rambase + ctl->socramsize - 4);
1152 if(ctl->armcore == ARMcr4){
1153 sbwindow(ctl->sdregs);
1154 cfgwritel(Fn1, ctl->sdregs + Intstatus, ~0);
1155 if(ctl->resetvec.i != 0){
1156 if(SBDEBUG) print("%ux\n", ctl->resetvec.i);
1157 sbmem(1, ctl->resetvec.c, sizeof(ctl->resetvec.c), 0);
1158 }
1159 sbreset(ctl->armctl, Cr4Cpuhalt, 0);
1160 }else
1161 sbreset(ctl->armctl, 0, 0);
1162 }
1163
1164 /*
1165 * Communication of data and control packets
1166 */
1167
1168 void
intwait(Ctlr * ctlr,int wait)1169 intwait(Ctlr *ctlr, int wait)
1170 {
1171 ulong ints, mbox;
1172 int i;
1173
1174 if(waserror())
1175 return;
1176 for(;;){
1177 sdiocardintr(wait);
1178 sbwindow(ctlr->sdregs);
1179 i = sdiord(Fn0, Intpend);
1180 if(i == 0){
1181 tsleep(&up->sleep, return0, 0, 10);
1182 continue;
1183 }
1184 ints = cfgreadl(Fn1, ctlr->sdregs + Intstatus);
1185 cfgwritel(Fn1, ctlr->sdregs + Intstatus, ints);
1186 if(0) print("INTS: (%x) %lux -> %lux\n", i, ints, cfgreadl(Fn1, ctlr->sdregs + Intstatus));
1187 if(ints & MailboxInt){
1188 mbox = cfgreadl(Fn1, ctlr->sdregs + Hostmboxdata);
1189 cfgwritel(Fn1, ctlr->sdregs + Sbmbox, 2); /* ack */
1190 if(mbox & 0x8)
1191 print("ether4330: firmware ready\n");
1192 }
1193 if(ints & FrameInt)
1194 break;
1195 }
1196 poperror();
1197 }
1198
1199 static Block*
wlreadpkt(Ctlr * ctl)1200 wlreadpkt(Ctlr *ctl)
1201 {
1202 Block *b;
1203 Sdpcm *p;
1204 int len, lenck;
1205
1206 b = allocb(2048);
1207 p = (Sdpcm*)b->wp;
1208 qlock(&ctl->pktlock);
1209 for(;;){
1210 packetrw(0, b->wp, sizeof(*p));
1211 len = p->len[0] | p->len[1]<<8;
1212 if(len == 0){
1213 freeb(b);
1214 b = nil;
1215 break;
1216 }
1217 lenck = p->lenck[0] | p->lenck[1]<<8;
1218 if(lenck != (len ^ 0xFFFF) ||
1219 len < sizeof(*p) || len > 2048){
1220 print("ether4330: wlreadpkt error len %.4x lenck %.4x\n", len, lenck);
1221 cfgw(Framectl, Rfhalt);
1222 while(cfgr(Rfrmcnt+1))
1223 ;
1224 while(cfgr(Rfrmcnt))
1225 ;
1226 continue;
1227 }
1228 if(len > sizeof(*p))
1229 packetrw(0, b->wp + sizeof(*p), len - sizeof(*p));
1230 b->wp += len;
1231 break;
1232 }
1233 qunlock(&ctl->pktlock);
1234 return b;
1235 }
1236
1237 static void
txstart(Ether * edev)1238 txstart(Ether *edev)
1239 {
1240 Ctlr *ctl;
1241 Sdpcm *p;
1242 Block *b;
1243 int len, off;
1244
1245 ctl = edev->ctlr;
1246 if(!canqlock(&ctl->tlock))
1247 return;
1248 if(waserror()){
1249 qunlock(&ctl->tlock);
1250 return;
1251 }
1252 for(;;){
1253 lock(&ctl->txwinlock);
1254 if(ctl->txseq == ctl->txwindow){
1255 //print("f");
1256 unlock(&ctl->txwinlock);
1257 break;
1258 }
1259 if(ctl->fcmask & 1<<2){
1260 //print("x");
1261 unlock(&ctl->txwinlock);
1262 break;
1263 }
1264 unlock(&ctl->txwinlock);
1265 b = qget(edev->oq);
1266 if(b == nil)
1267 break;
1268 off = ((uintptr)b->rp & 3) + sizeof(Sdpcm);
1269 b = padblock(b, off + 4);
1270 len = BLEN(b);
1271 p = (Sdpcm*)b->rp;
1272 memset(p, 0, off); /* TODO: refactor dup code */
1273 put2(p->len, len);
1274 put2(p->lenck, ~len);
1275 p->chanflg = 2;
1276 p->seq = ctl->txseq;
1277 p->doffset = off;
1278 put4(b->rp + off, 0x20); /* BDC header */
1279 if(iodebug) dump("send", b->rp, len);
1280 qlock(&ctl->pktlock);
1281 if(waserror()){
1282 if(iodebug) print("halt frame %x %x\n", cfgr(Wfrmcnt+1), cfgr(Wfrmcnt+1));
1283 cfgw(Framectl, Wfhalt);
1284 while(cfgr(Wfrmcnt+1))
1285 ;
1286 while(cfgr(Wfrmcnt))
1287 ;
1288 qunlock(&ctl->pktlock);
1289 nexterror();
1290 }
1291 packetrw(1, b->rp, len);
1292 ctl->txseq++;
1293 poperror();
1294 qunlock(&ctl->pktlock);
1295 freeb(b);
1296 }
1297 poperror();
1298 qunlock(&ctl->tlock);
1299 }
1300
1301 static void
rproc(void * a)1302 rproc(void *a)
1303 {
1304 Ether *edev;
1305 Ctlr *ctl;
1306 Block *b;
1307 Sdpcm *p;
1308 Cmd *q;
1309 int flowstart;
1310 int bdc;
1311
1312 edev = a;
1313 ctl = edev->ctlr;
1314 flowstart = 0;
1315 for(;;){
1316 if(flowstart){
1317 //print("F");
1318 flowstart = 0;
1319 txstart(edev);
1320 }
1321 b = wlreadpkt(ctl);
1322 if(b == nil){
1323 intwait(ctl, 1);
1324 continue;
1325 }
1326 p = (Sdpcm*)b->rp;
1327 if(p->window != ctl->txwindow || p->fcmask != ctl->fcmask){
1328 lock(&ctl->txwinlock);
1329 if(p->window != ctl->txwindow){
1330 if(ctl->txseq == ctl->txwindow)
1331 flowstart = 1;
1332 ctl->txwindow = p->window;
1333 }
1334 if(p->fcmask != ctl->fcmask){
1335 if((p->fcmask & 1<<2) == 0)
1336 flowstart = 1;
1337 ctl->fcmask = p->fcmask;
1338 }
1339 unlock(&ctl->txwinlock);
1340 }
1341 switch(p->chanflg & 0xF){
1342 case 0:
1343 if(iodebug) dump("rsp", b->rp, BLEN(b));
1344 if(BLEN(b) < sizeof(Sdpcm) + sizeof(Cmd))
1345 break;
1346 q = (Cmd*)(b->rp + sizeof(*p));
1347 if((q->id[0] | q->id[1]<<8) != ctl->reqid)
1348 break;
1349 ctl->rsp = b;
1350 wakeup(&ctl->cmdr);
1351 continue;
1352 case 1:
1353 if(iodebug) dump("event", b->rp, BLEN(b));
1354 if(BLEN(b) > p->doffset + 4){
1355 bdc = 4 + (b->rp[p->doffset + 3] << 2);
1356 if(BLEN(b) > p->doffset + bdc){
1357 b->rp += p->doffset + bdc; /* skip BDC header */
1358 bcmevent(ctl, b->rp, BLEN(b));
1359 break;
1360 }
1361 }
1362 if(iodebug && BLEN(b) != p->doffset)
1363 print("short event %ld %d\n", BLEN(b), p->doffset);
1364 break;
1365 case 2:
1366 if(iodebug) dump("packet", b->rp, BLEN(b));
1367 if(BLEN(b) > p->doffset + 4){
1368 bdc = 4 + (b->rp[p->doffset + 3] << 2);
1369 if(BLEN(b) >= p->doffset + bdc + ETHERHDRSIZE){
1370 b->rp += p->doffset + bdc; /* skip BDC header */
1371 etheriq(edev, b, 1);
1372 continue;
1373 }
1374 }
1375 break;
1376 default:
1377 dump("ether4330: bad packet", b->rp, BLEN(b));
1378 break;
1379 }
1380 freeb(b);
1381 }
1382 }
1383
1384 static void
linkdown(Ctlr * ctl)1385 linkdown(Ctlr *ctl)
1386 {
1387 Ether *edev;
1388 Netfile *f;
1389 int i;
1390
1391 edev = ctl->edev;
1392 if(edev == nil || ctl->status != Connected)
1393 return;
1394 ctl->status = Disconnected;
1395 /* send eof to aux/wpa */
1396 for(i = 0; i < edev->nfile; i++){
1397 f = edev->f[i];
1398 if(f == nil || f->in == nil || f->inuse == 0 || f->type != 0x888e)
1399 continue;
1400 qwrite(f->in, 0, 0);
1401 }
1402 }
1403
1404 /*
1405 * Command interface between host and firmware
1406 */
1407
1408 static char *eventnames[] = {
1409 [0] = "set ssid",
1410 [1] = "join",
1411 [2] = "start",
1412 [3] = "auth",
1413 [4] = "auth ind",
1414 [5] = "deauth",
1415 [6] = "deauth ind",
1416 [7] = "assoc",
1417 [8] = "assoc ind",
1418 [9] = "reassoc",
1419 [10] = "reassoc ind",
1420 [11] = "disassoc",
1421 [12] = "disassoc ind",
1422 [13] = "quiet start",
1423 [14] = "quiet end",
1424 [15] = "beacon rx",
1425 [16] = "link",
1426 [17] = "mic error",
1427 [18] = "ndis link",
1428 [19] = "roam",
1429 [20] = "txfail",
1430 [21] = "pmkid cache",
1431 [22] = "retrograde tsf",
1432 [23] = "prune",
1433 [24] = "autoauth",
1434 [25] = "eapol msg",
1435 [26] = "scan complete",
1436 [27] = "addts ind",
1437 [28] = "delts ind",
1438 [29] = "bcnsent ind",
1439 [30] = "bcnrx msg",
1440 [31] = "bcnlost msg",
1441 [32] = "roam prep",
1442 [33] = "pfn net found",
1443 [34] = "pfn net lost",
1444 [35] = "reset complete",
1445 [36] = "join start",
1446 [37] = "roam start",
1447 [38] = "assoc start",
1448 [39] = "ibss assoc",
1449 [40] = "radio",
1450 [41] = "psm watchdog",
1451 [44] = "probreq msg",
1452 [45] = "scan confirm ind",
1453 [46] = "psk sup",
1454 [47] = "country code changed",
1455 [48] = "exceeded medium time",
1456 [49] = "icv error",
1457 [50] = "unicast decode error",
1458 [51] = "multicast decode error",
1459 [52] = "trace",
1460 [53] = "bta hci event",
1461 [54] = "if",
1462 [55] = "p2p disc listen complete",
1463 [56] = "rssi",
1464 [57] = "pfn scan complete",
1465 [58] = "extlog msg",
1466 [59] = "action frame",
1467 [60] = "action frame complete",
1468 [61] = "pre assoc ind",
1469 [62] = "pre reassoc ind",
1470 [63] = "channel adopted",
1471 [64] = "ap started",
1472 [65] = "dfs ap stop",
1473 [66] = "dfs ap resume",
1474 [67] = "wai sta event",
1475 [68] = "wai msg",
1476 [69] = "escan result",
1477 [70] = "action frame off chan complete",
1478 [71] = "probresp msg",
1479 [72] = "p2p probreq msg",
1480 [73] = "dcs request",
1481 [74] = "fifo credit map",
1482 [75] = "action frame rx",
1483 [76] = "wake event",
1484 [77] = "rm complete",
1485 [78] = "htsfsync",
1486 [79] = "overlay req",
1487 [80] = "csa complete ind",
1488 [81] = "excess pm wake event",
1489 [82] = "pfn scan none",
1490 [83] = "pfn scan allgone",
1491 [84] = "gtk plumbed",
1492 [85] = "assoc ind ndis",
1493 [86] = "reassoc ind ndis",
1494 [87] = "assoc req ie",
1495 [88] = "assoc resp ie",
1496 [89] = "assoc recreated",
1497 [90] = "action frame rx ndis",
1498 [91] = "auth req",
1499 [92] = "tdls peer event",
1500 [127] = "bcmc credit support"
1501 };
1502
1503 static char*
evstring(uint event)1504 evstring(uint event)
1505 {
1506 static char buf[12];
1507
1508 if(event >= nelem(eventnames) || eventnames[event] == 0){
1509 /* not reentrant but only called from one kproc */
1510 snprint(buf, sizeof buf, "%d", event);
1511 return buf;
1512 }
1513 return eventnames[event];
1514 }
1515
1516 static void
bcmevent(Ctlr * ctl,uchar * p,int len)1517 bcmevent(Ctlr *ctl, uchar *p, int len)
1518 {
1519 int flags;
1520 long event, status, reason;
1521
1522 if(len < ETHERHDRSIZE + 10 + 46)
1523 return;
1524 p += ETHERHDRSIZE + 10; /* skip bcm_ether header */
1525 len -= ETHERHDRSIZE + 10;
1526 flags = nhgets(p + 2);
1527 event = nhgets(p + 6);
1528 status = nhgetl(p + 8);
1529 reason = nhgetl(p + 12);
1530 if(EVENTDEBUG)
1531 print("ether4330: [%s] status %ld flags %#x reason %ld\n",
1532 evstring(event), status, flags, reason);
1533 switch(event){
1534 case 19: /* E_ROAM */
1535 if(status == 0)
1536 break;
1537 /* fall through */
1538 case 0: /* E_SET_SSID */
1539 ctl->joinstatus = 1 + status;
1540 wakeup(&ctl->joinr);
1541 break;
1542 case 16: /* E_LINK */
1543 if(flags&1) /* link up */
1544 break;
1545 /* fall through */
1546 case 5: /* E_DEAUTH */
1547 case 6: /* E_DEAUTH_IND */
1548 case 12: /* E_DISASSOC_IND */
1549 linkdown(ctl);
1550 break;
1551 case 26: /* E_SCAN_COMPLETE */
1552 break;
1553 case 69: /* E_ESCAN_RESULT */
1554 wlscanresult(ctl->edev, p + 48, len - 48);
1555 break;
1556 default:
1557 if(status){
1558 if(!EVENTDEBUG)
1559 print("ether4330: [%s] error status %ld flags %#x reason %ld\n",
1560 evstring(event), status, flags, reason);
1561 dump("event", p, len);
1562 }
1563 }
1564 }
1565
1566 static int
joindone(void * a)1567 joindone(void *a)
1568 {
1569 return ((Ctlr*)a)->joinstatus;
1570 }
1571
1572 static int
waitjoin(Ctlr * ctl)1573 waitjoin(Ctlr *ctl)
1574 {
1575 int n;
1576
1577 sleep(&ctl->joinr, joindone, ctl);
1578 n = ctl->joinstatus;
1579 ctl->joinstatus = 0;
1580 return n - 1;
1581 }
1582
1583 static int
cmddone(void * a)1584 cmddone(void *a)
1585 {
1586 return ((Ctlr*)a)->rsp != nil;
1587 }
1588
1589 static void
wlcmd(Ctlr * ctl,int write,int op,void * data,int dlen,void * res,int rlen)1590 wlcmd(Ctlr *ctl, int write, int op, void *data, int dlen, void *res, int rlen)
1591 {
1592 Block *b;
1593 Sdpcm *p;
1594 Cmd *q;
1595 int len, tlen;
1596
1597 if(write)
1598 tlen = dlen + rlen;
1599 else
1600 tlen = MAX(dlen, rlen);
1601 len = sizeof(Sdpcm) + sizeof(Cmd) + tlen;
1602 b = allocb(len);
1603 qlock(&ctl->cmdlock);
1604 if(waserror()){
1605 freeb(b);
1606 qunlock(&ctl->cmdlock);
1607 nexterror();
1608 }
1609 memset(b->wp, 0, len);
1610 qlock(&ctl->pktlock);
1611 p = (Sdpcm*)b->wp;
1612 put2(p->len, len);
1613 put2(p->lenck, ~len);
1614 p->seq = ctl->txseq;
1615 p->doffset = sizeof(Sdpcm);
1616 b->wp += sizeof(*p);
1617
1618 q = (Cmd*)b->wp;
1619 put4(q->cmd, op);
1620 put4(q->len, tlen);
1621 put2(q->flags, write? 2 : 0);
1622 put2(q->id, ++ctl->reqid);
1623 put4(q->status, 0);
1624 b->wp += sizeof(*q);
1625
1626 if(dlen > 0)
1627 memmove(b->wp, data, dlen);
1628 if(write)
1629 memmove(b->wp + dlen, res, rlen);
1630 b->wp += tlen;
1631
1632 if(iodebug) dump("cmd", b->rp, len);
1633 packetrw(1, b->rp, len);
1634 ctl->txseq++;
1635 qunlock(&ctl->pktlock);
1636 freeb(b);
1637 b = nil;
1638 USED(b);
1639 sleep(&ctl->cmdr, cmddone, ctl);
1640 b = ctl->rsp;
1641 ctl->rsp = nil;
1642 assert(b != nil);
1643 p = (Sdpcm*)b->rp;
1644 q = (Cmd*)(b->rp + p->doffset);
1645 if(q->status[0] | q->status[1] | q->status[2] | q->status[3]){
1646 print("ether4330: cmd %d error status %ld\n", op, get4(q->status));
1647 dump("ether4330: cmd error", b->rp, BLEN(b));
1648 error("wlcmd error");
1649 }
1650 if(!write)
1651 memmove(res, q + 1, rlen);
1652 freeb(b);
1653 qunlock(&ctl->cmdlock);
1654 poperror();
1655 }
1656
1657 static void
wlcmdint(Ctlr * ctl,int op,int val)1658 wlcmdint(Ctlr *ctl, int op, int val)
1659 {
1660 uchar buf[4];
1661
1662 put4(buf, val);
1663 wlcmd(ctl, 1, op, buf, 4, nil, 0);
1664 }
1665
1666 static void
wlgetvar(Ctlr * ctl,char * name,void * val,int len)1667 wlgetvar(Ctlr *ctl, char *name, void *val, int len)
1668 {
1669 wlcmd(ctl, 0, GetVar, name, strlen(name) + 1, val, len);
1670 }
1671
1672 static void
wlsetvar(Ctlr * ctl,char * name,void * val,int len)1673 wlsetvar(Ctlr *ctl, char *name, void *val, int len)
1674 {
1675 if(VARDEBUG){
1676 char buf[32];
1677 snprint(buf, sizeof buf, "wlsetvar %s:", name);
1678 dump(buf, val, len);
1679 }
1680 wlcmd(ctl, 1, SetVar, name, strlen(name) + 1, val, len);
1681 }
1682
1683 static void
wlsetint(Ctlr * ctl,char * name,int val)1684 wlsetint(Ctlr *ctl, char *name, int val)
1685 {
1686 uchar buf[4];
1687
1688 put4(buf, val);
1689 wlsetvar(ctl, name, buf, 4);
1690 }
1691
1692 static void
wlwepkey(Ctlr * ctl,int i)1693 wlwepkey(Ctlr *ctl, int i)
1694 {
1695 uchar params[164];
1696 uchar *p;
1697
1698 memset(params, 0, sizeof params);
1699 p = params;
1700 p = put4(p, i); /* index */
1701 p = put4(p, ctl->keys[i].len);
1702 memmove(p, ctl->keys[i].dat, ctl->keys[i].len);
1703 p += 32 + 18*4; /* keydata, pad */
1704 if(ctl->keys[i].len == WMinKeyLen)
1705 p = put4(p, 1); /* algo = WEP1 */
1706 else
1707 p = put4(p, 3); /* algo = WEP128 */
1708 put4(p, 2); /* flags = Primarykey */
1709
1710 wlsetvar(ctl, "wsec_key", params, sizeof params);
1711 }
1712
1713 static void
memreverse(char * dst,char * src,int len)1714 memreverse(char *dst, char *src, int len)
1715 {
1716 src += len;
1717 while(len-- > 0)
1718 *dst++ = *--src;
1719 }
1720
1721 static void
wlwpakey(Ctlr * ctl,int id,uvlong iv,uchar * ea)1722 wlwpakey(Ctlr *ctl, int id, uvlong iv, uchar *ea)
1723 {
1724 uchar params[164];
1725 uchar *p;
1726 int pairwise;
1727
1728 if(id == CMrxkey)
1729 return;
1730 pairwise = (id == CMrxkey || id == CMtxkey);
1731 memset(params, 0, sizeof params);
1732 p = params;
1733 if(pairwise)
1734 p = put4(p, 0);
1735 else
1736 p = put4(p, id - CMrxkey0); /* group key id */
1737 p = put4(p, ctl->keys[0].len);
1738 memmove((char*)p, ctl->keys[0].dat, ctl->keys[0].len);
1739 p += 32 + 18*4; /* keydata, pad */
1740 if(ctl->cryptotype == Wpa)
1741 p = put4(p, 2); /* algo = TKIP */
1742 else
1743 p = put4(p, 4); /* algo = AES_CCM */
1744 if(pairwise)
1745 p = put4(p, 0);
1746 else
1747 p = put4(p, 2); /* flags = Primarykey */
1748 p += 3*4;
1749 p = put4(p, 0); //pairwise); /* iv initialised */
1750 p += 4;
1751 p = put4(p, iv>>16); /* iv high */
1752 p = put2(p, iv&0xFFFF); /* iv low */
1753 p += 2 + 2*4; /* align, pad */
1754 if(pairwise)
1755 memmove(p, ea, Eaddrlen);
1756
1757 wlsetvar(ctl, "wsec_key", params, sizeof params);
1758 }
1759
1760 static void
wljoin(Ctlr * ctl,char * ssid,int chan)1761 wljoin(Ctlr *ctl, char *ssid, int chan)
1762 {
1763 uchar params[72];
1764 uchar *p;
1765 int n;
1766
1767 if(chan != 0)
1768 chan |= 0x2b00; /* 20Mhz channel width */
1769 p = params;
1770 n = strlen(ssid);
1771 n = MIN(n, 32);
1772 p = put4(p, n);
1773 memmove(p, ssid, n);
1774 memset(p + n, 0, 32 - n);
1775 p += 32;
1776 p = put4(p, 0xff); /* scan type */
1777 if(chan != 0){
1778 p = put4(p, 2); /* num probes */
1779 p = put4(p, 120); /* active time */
1780 p = put4(p, 390); /* passive time */
1781 }else{
1782 p = put4(p, -1); /* num probes */
1783 p = put4(p, -1); /* active time */
1784 p = put4(p, -1); /* passive time */
1785 }
1786 p = put4(p, -1); /* home time */
1787 memset(p, 0xFF, Eaddrlen); /* bssid */
1788 p += Eaddrlen;
1789 p = put2(p, 0); /* pad */
1790 if(chan != 0){
1791 p = put4(p, 1); /* num chans */
1792 p = put2(p, chan); /* chan spec */
1793 p = put2(p, 0); /* pad */
1794 assert(p == params + sizeof(params));
1795 }else{
1796 p = put4(p, 0); /* num chans */
1797 assert(p == params + sizeof(params) - 4);
1798 }
1799
1800 wlsetvar(ctl, "join", params, chan? sizeof params : sizeof params - 4);
1801 ctl->status = Connecting;
1802 switch(waitjoin(ctl)){
1803 case 0:
1804 ctl->status = Connected;
1805 break;
1806 case 3:
1807 ctl->status = Disconnected;
1808 error("wifi join: network not found");
1809 case 1:
1810 ctl->status = Disconnected;
1811 error("wifi join: failed");
1812 default:
1813 ctl->status = Disconnected;
1814 error("wifi join: error");
1815 }
1816 }
1817
1818 static void
wlscanstart(Ctlr * ctl)1819 wlscanstart(Ctlr *ctl)
1820 {
1821 /* version[4] action[2] sync_id[2] ssidlen[4] ssid[32] bssid[6] bss_type[1]
1822 scan_type[1] nprobes[4] active_time[4] passive_time[4] home_time[4]
1823 nchans[2] nssids[2] chans[nchans][2] ssids[nssids][32] */
1824 /* hack - this is only correct on a little-endian cpu */
1825 static uchar params[4+2+2+4+32+6+1+1+4*4+2+2+14*2+32+4] = {
1826 1,0,0,0,
1827 1,0,
1828 0x34,0x12,
1829 0,0,0,0,
1830 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1831 0xff,0xff,0xff,0xff,0xff,0xff,
1832 2,
1833 0,
1834 0xff,0xff,0xff,0xff,
1835 0xff,0xff,0xff,0xff,
1836 0xff,0xff,0xff,0xff,
1837 0xff,0xff,0xff,0xff,
1838 14,0,
1839 1,0,
1840 0x01,0x2b,0x02,0x2b,0x03,0x2b,0x04,0x2b,0x05,0x2e,0x06,0x2e,0x07,0x2e,
1841 0x08,0x2b,0x09,0x2b,0x0a,0x2b,0x0b,0x2b,0x0c,0x2b,0x0d,0x2b,0x0e,0x2b,
1842 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1843 };
1844
1845 wlcmdint(ctl, 49, 0); /* PASSIVE_SCAN */
1846 wlsetvar(ctl, "escan", params, sizeof params);
1847 }
1848
1849 static uchar*
gettlv(uchar * p,uchar * ep,int tag)1850 gettlv(uchar *p, uchar *ep, int tag)
1851 {
1852 int len;
1853
1854 while(p + 1 < ep){
1855 len = p[1];
1856 if(p + 2 + len > ep)
1857 return nil;
1858 if(p[0] == tag)
1859 return p;
1860 p += 2 + len;
1861 }
1862 return nil;
1863 }
1864
1865 static void
addscan(Block * bp,uchar * p,int len)1866 addscan(Block *bp, uchar *p, int len)
1867 {
1868 char bssid[24];
1869 char *auth, *auth2;
1870 uchar *t, *et;
1871 int ielen;
1872 static uchar wpaie1[4] = { 0x00, 0x50, 0xf2, 0x01 };
1873
1874 snprint(bssid, sizeof bssid, ";bssid=%E", p + 8);
1875 if(strstr((char*)bp->rp, bssid) != nil)
1876 return;
1877 bp->wp = (uchar*)seprint((char*)bp->wp, (char*)bp->lim,
1878 "ssid=%.*s%s;signal=%d;noise=%d;chan=%d",
1879 p[18], (char*)p+19, bssid,
1880 (short)get2(p+78), (signed char)p[80],
1881 get2(p+72) & 0xF);
1882 auth = auth2 = "";
1883 if(get2(p + 16) & 0x10)
1884 auth = ";wep";
1885 ielen = get4(p + 0x78);
1886 if(ielen > 0){
1887 t = p + get4(p + 0x74);
1888 et = t + ielen;
1889 if(et > p + len)
1890 return;
1891 if(gettlv(t, et, 0x30) != nil){
1892 auth = "";
1893 auth2 = ";wpa2";
1894 }
1895 while((t = gettlv(t, et, 0xdd)) != nil){
1896 if(t[1] > 4 && memcmp(t+2, wpaie1, 4) == 0){
1897 auth = ";wpa";
1898 break;
1899 }
1900 t += 2 + t[1];
1901 }
1902 }
1903 bp->wp = (uchar*)seprint((char*)bp->wp, (char*)bp->lim,
1904 "%s%s\n", auth, auth2);
1905 }
1906
1907
1908 static void
wlscanresult(Ether * edev,uchar * p,int len)1909 wlscanresult(Ether *edev, uchar *p, int len)
1910 {
1911 Ctlr *ctlr;
1912 Netfile **ep, *f, **fp;
1913 Block *bp;
1914 int nbss, i;
1915
1916 ctlr = edev->ctlr;
1917 if(get4(p) > len)
1918 return;
1919 /* TODO: more syntax checking */
1920 bp = ctlr->scanb;
1921 if(bp == nil)
1922 ctlr->scanb = bp = allocb(8192);
1923 nbss = get2(p+10);
1924 p += 12;
1925 len -= 12;
1926 if(0) dump("SCAN", p, len);
1927 if(nbss){
1928 addscan(bp, p, len);
1929 return;
1930 }
1931 i = edev->scan;
1932 ep = &edev->f[Ntypes];
1933 for(fp = edev->f; fp < ep && i > 0; fp++){
1934 f = *fp;
1935 if(f == nil || f->scan == 0)
1936 continue;
1937 if(i == 1)
1938 qpass(f->in, bp);
1939 else
1940 qpass(f->in, copyblock(bp, BLEN(bp)));
1941 i--;
1942 }
1943 if(i)
1944 freeb(bp);
1945 ctlr->scanb = nil;
1946 }
1947
1948 static void
lproc(void * a)1949 lproc(void *a)
1950 {
1951 Ether *edev;
1952 Ctlr *ctlr;
1953 int secs;
1954
1955 edev = a;
1956 ctlr = edev->ctlr;
1957 secs = 0;
1958 for(;;){
1959 tsleep(&up->sleep, return0, 0, 1000);
1960 if(ctlr->scansecs){
1961 if(secs == 0){
1962 if(waserror())
1963 ctlr->scansecs = 0;
1964 else{
1965 wlscanstart(ctlr);
1966 poperror();
1967 }
1968 secs = ctlr->scansecs;
1969 }
1970 --secs;
1971 }else
1972 secs = 0;
1973 }
1974 }
1975
1976 static void
wlinit(Ether * edev,Ctlr * ctlr)1977 wlinit(Ether *edev, Ctlr *ctlr)
1978 {
1979 uchar ea[Eaddrlen];
1980 uchar eventmask[16];
1981 char version[128];
1982 char *p;
1983 static uchar keepalive[12] = {1, 0, 11, 0, 0xd8, 0xd6, 0, 0, 0, 0, 0, 0};
1984
1985 wlgetvar(ctlr, "cur_etheraddr", ea, Eaddrlen);
1986 memmove(edev->ea, ea, Eaddrlen);
1987 memmove(edev->addr, ea, Eaddrlen);
1988 print("ether4330: addr %E\n", edev->ea);
1989 wlsetint(ctlr, "assoc_listen", 10);
1990 if(ctlr->chipid == 43430 || ctlr->chipid == 0x4345)
1991 wlcmdint(ctlr, 0x56, 0); /* powersave off */
1992 else
1993 wlcmdint(ctlr, 0x56, 2); /* powersave FAST */
1994 wlsetint(ctlr, "bus:txglom", 0);
1995 wlsetint(ctlr, "bcn_timeout", 10);
1996 wlsetint(ctlr, "assoc_retry_max", 3);
1997 if(ctlr->chipid == 0x4330){
1998 wlsetint(ctlr, "btc_wire", 4);
1999 wlsetint(ctlr, "btc_mode", 1);
2000 wlsetvar(ctlr, "mkeep_alive", keepalive, 11);
2001 }
2002 memset(eventmask, 0xFF, sizeof eventmask);
2003 #define ENABLE(n) eventmask[n/8] |= 1<<(n%8)
2004 #define DISABLE(n) eventmask[n/8] &= ~(1<<(n%8))
2005 DISABLE(40); /* E_RADIO */
2006 DISABLE(44); /* E_PROBREQ_MSG */
2007 DISABLE(54); /* E_IF */
2008 DISABLE(71); /* E_PROBRESP_MSG */
2009 DISABLE(20); /* E_TXFAIL */
2010 DISABLE(124); /* ? */
2011 wlsetvar(ctlr, "event_msgs", eventmask, sizeof eventmask);
2012 wlcmdint(ctlr, 0xb9, 0x28); /* SET_SCAN_CHANNEL_TIME */
2013 wlcmdint(ctlr, 0xbb, 0x28); /* SET_SCAN_UNASSOC_TIME */
2014 wlcmdint(ctlr, 0x102, 0x82); /* SET_SCAN_PASSIVE_TIME */
2015 wlcmdint(ctlr, 2, 0); /* UP */
2016 memset(version, 0, sizeof version);
2017 wlgetvar(ctlr, "ver", version, sizeof version - 1);
2018 if((p = strchr(version, '\n')) != nil)
2019 *p = '\0';
2020 if(0) print("ether4330: %s\n", version);
2021 wlsetint(ctlr, "roam_off", 1);
2022 wlcmdint(ctlr, 0x14, 1); /* SET_INFRA 1 */
2023 wlcmdint(ctlr, 10, 0); /* SET_PROMISC */
2024 //wlcmdint(ctlr, 0x8e, 0); /* SET_BAND 0 */
2025 //wlsetint(ctlr, "wsec", 1);
2026 wlcmdint(ctlr, 2, 1); /* UP */
2027 ctlr->keys[0].len = WMinKeyLen;
2028 //wlwepkey(ctlr, 0);
2029 }
2030
2031 /*
2032 * Plan 9 driver interface
2033 */
2034
2035 static long
etherbcmifstat(Ether * edev,void * a,long n,ulong offset)2036 etherbcmifstat(Ether* edev, void* a, long n, ulong offset)
2037 {
2038 Ctlr *ctlr;
2039 char *p;
2040 int l;
2041 static char *cryptoname[4] = {
2042 [0] "off",
2043 [Wep] "wep",
2044 [Wpa] "wpa",
2045 [Wpa2] "wpa2",
2046 };
2047 /* these strings are known by aux/wpa */
2048 static char* connectstate[] = {
2049 [Disconnected] = "unassociated",
2050 [Connecting] = "connecting",
2051 [Connected] = "associated",
2052 };
2053
2054 ctlr = edev->ctlr;
2055 if(ctlr == nil)
2056 return 0;
2057 p = malloc(READSTR);
2058 l = 0;
2059
2060 l += snprint(p+l, READSTR-l, "channel: %d\n", ctlr->chanid);
2061 l += snprint(p+l, READSTR-l, "essid: %s\n", ctlr->essid);
2062 l += snprint(p+l, READSTR-l, "crypt: %s\n", cryptoname[ctlr->cryptotype]);
2063 l += snprint(p+l, READSTR-l, "oq: %d\n", qlen(edev->oq));
2064 l += snprint(p+l, READSTR-l, "txwin: %d\n", ctlr->txwindow);
2065 l += snprint(p+l, READSTR-l, "txseq: %d\n", ctlr->txseq);
2066 l += snprint(p+l, READSTR-l, "status: %s\n", connectstate[ctlr->status]);
2067 USED(l);
2068 n = readstr(offset, a, n, p);
2069 free(p);
2070 return n;
2071 }
2072
2073 static void
etherbcmtransmit(Ether * edev)2074 etherbcmtransmit(Ether *edev)
2075 {
2076 Ctlr *ctlr;
2077
2078 ctlr = edev->ctlr;
2079 if(ctlr == nil)
2080 return;
2081 txstart(edev);
2082 }
2083
2084 static int
parsehex(char * buf,int buflen,char * a)2085 parsehex(char *buf, int buflen, char *a)
2086 {
2087 int i, k, n;
2088
2089 k = 0;
2090 for(i = 0;k < buflen && *a; i++){
2091 if(*a >= '0' && *a <= '9')
2092 n = *a++ - '0';
2093 else if(*a >= 'a' && *a <= 'f')
2094 n = *a++ - 'a' + 10;
2095 else if(*a >= 'A' && *a <= 'F')
2096 n = *a++ - 'A' + 10;
2097 else
2098 break;
2099
2100 if(i & 1){
2101 buf[k] |= n;
2102 k++;
2103 }
2104 else
2105 buf[k] = n<<4;
2106 }
2107 if(i & 1)
2108 return -1;
2109 return k;
2110 }
2111
2112 static int
wepparsekey(WKey * key,char * a)2113 wepparsekey(WKey* key, char* a)
2114 {
2115 int i, k, len, n;
2116 char buf[WMaxKeyLen];
2117
2118 len = strlen(a);
2119 if(len == WMinKeyLen || len == WMaxKeyLen){
2120 memset(key->dat, 0, sizeof(key->dat));
2121 memmove(key->dat, a, len);
2122 key->len = len;
2123
2124 return 0;
2125 }
2126 else if(len == WMinKeyLen*2 || len == WMaxKeyLen*2){
2127 k = 0;
2128 for(i = 0; i < len; i++){
2129 if(*a >= '0' && *a <= '9')
2130 n = *a++ - '0';
2131 else if(*a >= 'a' && *a <= 'f')
2132 n = *a++ - 'a' + 10;
2133 else if(*a >= 'A' && *a <= 'F')
2134 n = *a++ - 'A' + 10;
2135 else
2136 return -1;
2137
2138 if(i & 1){
2139 buf[k] |= n;
2140 k++;
2141 }
2142 else
2143 buf[k] = n<<4;
2144 }
2145
2146 memset(key->dat, 0, sizeof(key->dat));
2147 memmove(key->dat, buf, k);
2148 key->len = k;
2149
2150 return 0;
2151 }
2152
2153 return -1;
2154 }
2155
2156 static int
wpaparsekey(WKey * key,uvlong * ivp,char * a)2157 wpaparsekey(WKey *key, uvlong *ivp, char *a)
2158 {
2159 int len;
2160 char *e;
2161
2162 if(cistrncmp(a, "tkip:", 5) == 0 || cistrncmp(a, "ccmp:", 5) == 0)
2163 a += 5;
2164 else
2165 return 1;
2166 len = parsehex(key->dat, sizeof(key->dat), a);
2167 if(len <= 0)
2168 return 1;
2169 key->len = len;
2170 a += 2*len;
2171 if(*a++ != '@')
2172 return 1;
2173 *ivp = strtoull(a, &e, 16);
2174 if(e == a)
2175 return -1;
2176 return 0;
2177 }
2178
2179 static void
setauth(Ctlr * ctlr,Cmdbuf * cb,char * a)2180 setauth(Ctlr *ctlr, Cmdbuf *cb, char *a)
2181 {
2182 uchar wpaie[32];
2183 int i;
2184
2185 i = parsehex((char*)wpaie, sizeof wpaie, a);
2186 if(i < 2 || i != wpaie[1] + 2)
2187 cmderror(cb, "bad wpa ie syntax");
2188 if(wpaie[0] == 0xdd)
2189 ctlr->cryptotype = Wpa;
2190 else if(wpaie[0] == 0x30)
2191 ctlr->cryptotype = Wpa2;
2192 else
2193 cmderror(cb, "bad wpa ie");
2194 wlsetvar(ctlr, "wpaie", wpaie, i);
2195 if(ctlr->cryptotype == Wpa){
2196 wlsetint(ctlr, "wpa_auth", 4|2); /* auth_psk | auth_unspecified */
2197 wlsetint(ctlr, "auth", 0);
2198 wlsetint(ctlr, "wsec", 2); /* tkip */
2199 wlsetint(ctlr, "wpa_auth", 4); /* auth_psk */
2200 }else{
2201 wlsetint(ctlr, "wpa_auth", 0x80|0x40); /* auth_psk | auth_unspecified */
2202 wlsetint(ctlr, "auth", 0);
2203 wlsetint(ctlr, "wsec", 4); /* aes */
2204 wlsetint(ctlr, "wpa_auth", 0x80); /* auth_psk */
2205 }
2206 }
2207
2208 static int
setcrypt(Ctlr * ctlr,Cmdbuf *,char * a)2209 setcrypt(Ctlr *ctlr, Cmdbuf*, char *a)
2210 {
2211 if(cistrcmp(a, "wep") == 0 || cistrcmp(a, "on") == 0)
2212 ctlr->cryptotype = Wep;
2213 else if(cistrcmp(a, "off") == 0 || cistrcmp(a, "none") == 0)
2214 ctlr->cryptotype = 0;
2215 else
2216 return 0;
2217 wlsetint(ctlr, "auth", ctlr->cryptotype);
2218 return 1;
2219 }
2220
2221 static long
etherbcmctl(Ether * edev,void * buf,long n)2222 etherbcmctl(Ether* edev, void* buf, long n)
2223 {
2224 Ctlr *ctlr;
2225 Cmdbuf *cb;
2226 Cmdtab *ct;
2227 uchar ea[Eaddrlen];
2228 uvlong iv;
2229 int i;
2230
2231 if((ctlr = edev->ctlr) == nil)
2232 error(Enonexist);
2233 USED(ctlr);
2234
2235 cb = parsecmd(buf, n);
2236 if(waserror()){
2237 free(cb);
2238 nexterror();
2239 }
2240 ct = lookupcmd(cb, cmds, nelem(cmds));
2241 switch(ct->index){
2242 case CMauth:
2243 setauth(ctlr, cb, cb->f[1]);
2244 if(ctlr->essid[0])
2245 wljoin(ctlr, ctlr->essid, ctlr->chanid);
2246 break;
2247 case CMchannel:
2248 if((i = atoi(cb->f[1])) < 0 || i > 16)
2249 cmderror(cb, "bad channel number");
2250 //wlcmdint(ctlr, 30, i); /* SET_CHANNEL */
2251 ctlr->chanid = i;
2252 break;
2253 case CMcrypt:
2254 if(setcrypt(ctlr, cb, cb->f[1])){
2255 if(ctlr->essid[0])
2256 wljoin(ctlr, ctlr->essid, ctlr->chanid);
2257 }else
2258 cmderror(cb, "bad crypt type");
2259 break;
2260 case CMessid:
2261 if(cistrcmp(cb->f[1], "default") == 0)
2262 memset(ctlr->essid, 0, sizeof(ctlr->essid));
2263 else{
2264 strncpy(ctlr->essid, cb->f[1], sizeof(ctlr->essid) - 1);
2265 ctlr->essid[sizeof(ctlr->essid) - 1] = '\0';
2266 }
2267 if(!waserror()){
2268 wljoin(ctlr, ctlr->essid, ctlr->chanid);
2269 poperror();
2270 }
2271 break;
2272 case CMjoin: /* join essid channel wep|on|off|wpakey */
2273 if(strcmp(cb->f[1], "") != 0){ /* empty string for no change */
2274 if(cistrcmp(cb->f[1], "default") != 0){
2275 strncpy(ctlr->essid, cb->f[1], sizeof(ctlr->essid)-1);
2276 ctlr->essid[sizeof(ctlr->essid)-1] = 0;
2277 }else
2278 memset(ctlr->essid, 0, sizeof(ctlr->essid));
2279 }else if(ctlr->essid[0] == 0)
2280 cmderror(cb, "essid not set");
2281 if((i = atoi(cb->f[2])) >= 0 && i <= 16)
2282 ctlr->chanid = i;
2283 else
2284 cmderror(cb, "bad channel number");
2285 if(!setcrypt(ctlr, cb, cb->f[3]))
2286 setauth(ctlr, cb, cb->f[3]);
2287 if(ctlr->essid[0])
2288 wljoin(ctlr, ctlr->essid, ctlr->chanid);
2289 break;
2290 case CMkey1:
2291 case CMkey2:
2292 case CMkey3:
2293 case CMkey4:
2294 i = ct->index - CMkey1;
2295 if(wepparsekey(&ctlr->keys[i], cb->f[1]))
2296 cmderror(cb, "bad WEP key syntax");
2297 wlsetint(ctlr, "wsec", 1); /* wep enabled */
2298 wlwepkey(ctlr, i);
2299 break;
2300 case CMrxkey:
2301 case CMrxkey0:
2302 case CMrxkey1:
2303 case CMrxkey2:
2304 case CMrxkey3:
2305 case CMtxkey:
2306 if(parseether(ea, cb->f[1]) < 0)
2307 cmderror(cb, "bad ether addr");
2308 if(wpaparsekey(&ctlr->keys[0], &iv, cb->f[2]))
2309 cmderror(cb, "bad wpa key");
2310 wlwpakey(ctlr, ct->index, iv, ea);
2311 break;
2312 case CMdebug:
2313 iodebug = atoi(cb->f[1]);
2314 break;
2315 }
2316 poperror();
2317 free(cb);
2318 return n;
2319 }
2320
2321 static void
etherbcmscan(void * a,uint secs)2322 etherbcmscan(void *a, uint secs)
2323 {
2324 Ether* edev;
2325 Ctlr* ctlr;
2326
2327 edev = a;
2328 ctlr = edev->ctlr;
2329 ctlr->scansecs = secs;
2330 }
2331
2332 static void
etherbcmattach(Ether * edev)2333 etherbcmattach(Ether* edev)
2334 {
2335 Ctlr *ctlr;
2336
2337 ctlr = edev->ctlr;
2338 qlock(&ctlr->alock);
2339 if(waserror()){
2340 //print("ether4330: attach failed: %s\n", up->errstr);
2341 qunlock(&ctlr->alock);
2342 nexterror();
2343 }
2344 if(ctlr->edev == nil){
2345 if(ctlr->chipid == 0){
2346 sdioinit();
2347 sbinit(ctlr);
2348 }
2349 fwload(ctlr);
2350 sbenable(ctlr);
2351 kproc("wifireader", rproc, edev);
2352 kproc("wifitimer", lproc, edev);
2353 if(ctlr->regufile)
2354 reguload(ctlr, ctlr->regufile);
2355 wlinit(edev, ctlr);
2356 ctlr->edev = edev;
2357 }
2358 qunlock(&ctlr->alock);
2359 poperror();
2360 }
2361
2362 static void
etherbcmshutdown(Ether *)2363 etherbcmshutdown(Ether*)
2364 {
2365 sdioreset();
2366 }
2367
2368
2369 static int
etherbcmpnp(Ether * edev)2370 etherbcmpnp(Ether* edev)
2371 {
2372 Ctlr *ctlr;
2373
2374 ctlr = malloc(sizeof(Ctlr));
2375 ctlr->chanid = Wifichan;
2376 edev->ctlr = ctlr;
2377 edev->attach = etherbcmattach;
2378 edev->transmit = etherbcmtransmit;
2379 edev->ifstat = etherbcmifstat;
2380 edev->ctl = etherbcmctl;
2381 edev->scanbs = etherbcmscan;
2382 edev->shutdown = etherbcmshutdown;
2383 edev->arg = edev;
2384
2385 return 0;
2386 }
2387
2388 void
ether4330link(void)2389 ether4330link(void)
2390 {
2391 addethercard("4330", etherbcmpnp);
2392 }
2393