2 #include "../port/lib.h"
9 #include "../port/error.h"
10 #include "../port/netif.h"
15 typedef struct SNAP SNAP;
29 static char Snone[] = "new";
30 static char Sconn[] = "connecting";
31 static char Sauth[] = "authenticated";
32 static char Sunauth[] = "unauthentictaed";
33 static char Sassoc[] = "associated";
34 static char Sunassoc[] = "unassociated";
37 wifiiq(Wifi *wifi, Block *b)
43 if(BLEN(b) < WIFIHDRSIZE)
45 memmove(&w, b->rp, WIFIHDRSIZE);
46 switch(w.fc[0] & 0x0c){
47 case 0x00: /* management */
48 if((w.fc[1] & 3) != 0x00) /* STA->STA */
52 case 0x04: /* control */
56 switch(w.fc[0] & 0xf0){
66 if(BLEN(b) < SNAPHDRSIZE)
68 memmove(&s, b->rp, SNAPHDRSIZE);
69 if(s.dsap != 0xAA || s.ssap != 0xAA || s.control != 3)
71 if(s.orgcode[0] != 0 || s.orgcode[1] != 0 || s.orgcode[2] != 0)
73 b->rp += SNAPHDRSIZE-ETHERHDRSIZE;
75 switch(w.fc[1] & 0x03){
76 case 0x00: /* STA->STA */
77 memmove(e->d, w.a1, Eaddrlen);
78 memmove(e->s, w.a2, Eaddrlen);
80 case 0x01: /* STA->AP */
81 memmove(e->d, w.a3, Eaddrlen);
82 memmove(e->s, w.a2, Eaddrlen);
84 case 0x02: /* AP->STA */
85 memmove(e->d, w.a1, Eaddrlen);
86 memmove(e->s, w.a3, Eaddrlen);
88 case 0x03: /* AP->AP */
91 memmove(e->type, s.type, 2);
92 etheriq(wifi->ether, b, 1);
100 wifitx(Wifi *wifi, Wnode *wn, Block *b)
105 seq = incref(&wifi->txseq);
114 (*wifi->transmit)(wifi, wn, b);
119 nodelookup(Wifi *wifi, uchar *bssid, int new)
123 if(memcmp(bssid, wifi->ether->bcast, Eaddrlen) == 0)
125 if((wn = wifi->bss) != nil){
126 if(memcmp(wn->bssid, bssid, Eaddrlen) == 0){
127 wn->lastseen = MACHP(0)->ticks;
131 if((nn = wifi->node) == wn)
133 for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
136 if(memcmp(wn->bssid, bssid, Eaddrlen) == 0){
137 wn->lastseen = MACHP(0)->ticks;
140 if(wn->lastseen < nn->lastseen)
145 memmove(nn->bssid, bssid, Eaddrlen);
151 nn->lastseen = MACHP(0)->ticks;
156 sendauth(Wifi *wifi, Wnode *bss)
162 b = allocb(WIFIHDRSIZE + 3*2);
164 w->fc[0] = 0xB0; /* auth request */
165 w->fc[1] = 0x00; /* STA->STA */
166 memmove(w->a1, bss->bssid, Eaddrlen); /* ??? */
167 memmove(w->a2, wifi->ether->ea, Eaddrlen);
168 memmove(w->a3, bss->bssid, Eaddrlen);
169 b->wp += WIFIHDRSIZE;
175 *p++ = 0; /* status */
178 wifitx(wifi, bss, b);
182 sendassoc(Wifi *wifi, Wnode *bss)
188 b = allocb(WIFIHDRSIZE + 128);
190 w->fc[0] = 0x00; /* assoc request */
191 w->fc[1] = 0x00; /* STA->STA */
192 memmove(w->a1, bss->bssid, Eaddrlen); /* ??? */
193 memmove(w->a2, wifi->ether->ea, Eaddrlen);
194 memmove(w->a3, bss->bssid, Eaddrlen);
195 b->wp += WIFIHDRSIZE;
197 *p++ = 1; /* capinfo */
199 *p++ = 16; /* interval */
202 *p = strlen(bss->ssid);
203 memmove(p+1, bss->ssid, *p);
205 *p++ = 1; /* RATES (BUG: these are all lies!) */
212 wifitx(wifi, bss, b);
216 recvassoc(Wifi *wifi, Wnode *wn, uchar *d, int len)
228 wn->aid = d[0] | d[1]<<8;
229 wifi->status = Sassoc;
233 wifi->status = Sunassoc;
239 recvbeacon(Wifi *, Wnode *wn, uchar *d, int len)
247 d += 8; /* timestamp */
248 wn->ival = d[0] | d[1]<<8;
250 wn->cap = d[0] | d[1]<<8;
253 memset(m, 0, sizeof(m));
254 for(e = d + len; d+2 <= e; d = x){
259 /* skip double entries */
260 if(m[t/8] & 1<<(t%8))
267 while(len < 32 && d+len < x && d[len] != 0)
271 if(len != strlen(wn->ssid) || strncmp(wn->ssid, (char*)d, len) != 0){
272 strncpy(wn->ssid, (char*)d, len);
276 case 3: /* DSPARAMS */
297 if((b = qbread(wifi->iq, 100000)) == nil)
300 switch(w->fc[0] & 0xf0){
301 case 0x50: /* probe response */
302 case 0x80: /* beacon */
303 if((wn = nodelookup(wifi, w->a3, 1)) == nil)
305 b->rp += WIFIHDRSIZE;
306 recvbeacon(wifi, wn, b->rp, BLEN(b));
307 if(wifi->bss == nil && wifi->essid[0] != 0 && strcmp(wifi->essid, wn->ssid) == 0){
309 wifi->status = Sconn;
314 if(memcmp(w->a1, wifi->ether->ea, Eaddrlen))
316 if((wn = nodelookup(wifi, w->a3, 0)) == nil)
320 switch(w->fc[0] & 0xf0){
321 case 0x10: /* assoc response */
322 case 0x30: /* reassoc response */
323 b->rp += WIFIHDRSIZE;
324 recvassoc(wifi, wn, b->rp, BLEN(b));
326 case 0xb0: /* auth */
327 wifi->status = Sauth;
330 case 0xc0: /* deauth */
332 wifi->status = Sunauth;
337 pexit("wifi in queue closed", 0);
341 wifietheroq(Wifi *wifi, Block *b)
349 if(bss == nil || BLEN(b) < ETHERHDRSIZE){
353 memmove(&e, b->rp, ETHERHDRSIZE);
355 b->rp += ETHERHDRSIZE;
356 b = padblock(b, WIFIHDRSIZE + SNAPHDRSIZE);
359 w->fc[0] = 0x08; /* data */
360 w->fc[1] = 0x01; /* STA->AP */
361 memmove(w->a1, bss->bssid, Eaddrlen);
362 memmove(w->a2, e.s, Eaddrlen);
363 memmove(w->a3, e.d, Eaddrlen);
365 s = (SNAP*)(b->rp + WIFIHDRSIZE);
366 s->dsap = s->ssap = 0xAA;
371 memmove(s->type, e.type, 2);
373 wifitx(wifi, bss, b);
385 while((b = qbread(ether->oq, 1000000)) != nil)
386 wifietheroq(wifi, b);
387 pexit("ether out queue closed", 0);
391 wifiattach(Ether *ether, void (*transmit)(Wifi*, Wnode*, Block*))
396 wifi = malloc(sizeof(Wifi));
398 wifi->iq = qopen(8*1024, 0, 0, 0);
399 wifi->transmit = transmit;
400 wifi->status = Snone;
402 snprint(name, sizeof(name), "#l%dwifi", ether->ctlrno);
403 kproc(name, wifiproc, wifi);
404 snprint(name, sizeof(name), "#l%dwifo", ether->ctlrno);
405 kproc(name, wifoproc, wifi);
411 wifictl(Wifi *wifi, void *buf, long n)
421 cb = parsecmd(buf, n);
422 if(cb->f[0] && strcmp(cb->f[0], "essid") == 0){
426 wifi->status = Snone;
428 strncpy(wifi->essid, cb->f[1], 32);
430 for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++)
431 if(strcmp(wifi->essid, wn->ssid) == 0){
433 wifi->status = Sconn;
445 wifistat(Wifi *wifi, void *buf, long n, ulong off)
447 static uchar zeros[Eaddrlen];
452 p = s = smalloc(4096);
455 p = seprint(p, e, "status: %s\n", wifi->status);
456 p = seprint(p, e, "essid: %s\n", wifi->essid);
458 p = seprint(p, e, "bssid: %E\n", wn != nil ? wn->bssid : zeros);
460 now = MACHP(0)->ticks;
461 for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
462 if(wn->lastseen == 0)
464 p = seprint(p, e, "node: %E %.4x %d %ld %d %s\n",
465 wn->bssid, wn->cap, wn->ival, TK2MS(now - wn->lastseen), wn->channel, wn->ssid);
467 n = readstr(off, buf, n, s);