support for multiple rates from cinap Reference: /n/atom/patch/applied/iwlrate Date: Sat May 3 06:27:52 CES 2014 Signed-off-by: quanstro@quanstro.net --- /sys/src/nix/k10/wifi.c Sat May 3 06:27:35 2014 +++ /sys/src/nix/k10/wifi.c Sat May 3 06:27:37 2014 @@ -37,6 +37,15 @@ static char Sunassoc[] = "unassociated"; static char Sblocked[] = "blocked"; /* no keys negotiated. only pass EAPOL frames */ +static uchar basicrates[] = { + 0x80 | 2, /* 1.0 Mb/s */ + 0x80 | 4, /* 2.0 Mb/s */ + 0x80 | 11, /* 5.5 Mb/s */ + 0x80 | 22, /* 11.0 Mb/s */ + + 0 +}; + static Block* wifidecrypt(Wifi *, Wnode *, Block *); static Block* wifiencrypt(Wifi *, Wnode *, Block *); @@ -187,6 +196,29 @@ return nn; } +static uchar* +putrates(uchar *p, uchar *rates) +{ + int n, m; + + n = m = strlen((char*)rates); + if(n > 8) + n = 8; + /* supported rates */ + *p++ = 1; + *p++ = n; + memmove(p, rates, n); + p += n; + if(m > 8){ + /* extended supported rates */ + *p++ = 50; + *p++ = m; + memmove(p, rates, m); + p += m; + } + return p; +} + static void wifiprobe(Wifi *wifi, Wnode *wn) { @@ -212,19 +244,14 @@ b->wp += WIFIHDRSIZE; p = b->wp; - *p++ = 0x00; /* set */ + *p++ = 0; /* set */ *p++ = n; memmove(p, wifi->essid, n); p += n; - *p++ = 1; /* RATES (BUG: these are all lies!) */ - *p++ = 4; - *p++ = 0x82; - *p++ = 0x84; - *p++ = 0x8b; - *p++ = 0x96; + p = putrates(p, wifi->rates); - *p++ = 0x03; /* ds parameter set */ + *p++ = 3; /* ds parameter set */ *p++ = 1; *p++ = wn->channel; @@ -283,17 +310,13 @@ *p++ = 16; /* interval */ *p++ = 16>>8; + n = strlen(bss->ssid); *p++ = 0; /* SSID */ - *p = strlen(bss->ssid); - memmove(p+1, bss->ssid, *p); - p += 1+*p; - - *p++ = 1; /* RATES (BUG: these are all lies!) */ - *p++ = 4; - *p++ = 0x82; - *p++ = 0x84; - *p++ = 0x8b; - *p++ = 0x96; + *p++ = n; + memmove(p, bss->ssid, n); + p += n; + + p = putrates(p, wifi->rates); n = bss->rsnelen; if(n > 0){ @@ -346,10 +369,10 @@ } static void -recvbeacon(Wifi *, Wnode *wn, uchar *d, int len) +recvbeacon(Wifi *wifi, Wnode *wn, uchar *d, int len) { static uchar wpa1oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; - uchar *e, *x; + uchar *e, *x, *p; uchar t, m[256/8]; if(len < 8+2+2) @@ -373,7 +396,7 @@ m[t/8] |= 1<<(t%8); switch(t){ - case 0x00: /* SSID */ + case 0: /* SSID */ len = 0; while(len < Essidlen && d+len < x && d[len] != 0) len++; @@ -384,16 +407,33 @@ wn->ssid[len] = 0; } break; - case 0x03: /* DSPARAMS */ + case 1: /* supported rates */ + case 50: /* extended rates */ + if(wn->minrate != nil || wn->maxrate != nil || wifi->rates == nil) + break; /* already set */ + while(d < x){ + t = *d++ & 0x7f; + for(p = wifi->rates; *p != 0; p++){ + if((*p & 0x7f) == t){ + if(wn->minrate == nil || t < (*wn->minrate & 0x7f)) + wn->minrate = p; + if(wn->maxrate == nil || t > (*wn->maxrate & 0x7f)) + wn->maxrate = p; + break; + } + } + } + break; + case 3: /* DSPARAMS */ if(d != x) wn->channel = d[0]; break; - case 0xdd: /* vendor specific */ + case 221: /* vendor specific */ len = x - d; if(len < sizeof(wpa1oui) || memcmp(d, wpa1oui, sizeof(wpa1oui)) != 0) break; /* no break */ - case 0x30: /* RSN information */ + case 48: /* RSN information */ len = x - &d[-2]; memmove(wn->brsne, &d[-2], len); wn->brsnelen = len; @@ -614,6 +654,7 @@ Wnode wnscan; Wnode *wn; ulong now, tmout; + uchar *rate; wifi = arg; ether = wifi->ether; @@ -637,6 +678,8 @@ tmout = 0; while((wn = wifi->bss) != nil){ ether->link = (wn->status == Sassoc) || (wn->status == Sblocked); + if(ether->link && (rate = wn->maxrate) != nil) + ether->mbps = ((*rate & 0x7f)+1)/2; now = MACHP(0)->ticks; if(wn->status != Sneedauth && TK2SEC(now - wn->lastseen) > 60 || goodbss(wifi, wn) == 0){ wifideauth(wifi, wn); @@ -672,6 +715,8 @@ } wifi->ether = ether; wifi->transmit = transmit; + + wifi->rates = basicrates; wifi->essid[0] = 0; memmove(wifi->bssid, ether->bcast, Eaddrlen); --- /sys/src/nix/k10/wifi.h Sat May 3 06:27:38 2014 +++ /sys/src/nix/k10/wifi.h Sat May 3 06:27:39 2014 @@ -37,6 +37,9 @@ ulong lastsend; ulong lastseen; + uchar *minrate; /* pointers into wifi->rates */ + uchar *maxrate; + /* stuff from beacon */ int ival; int cap; @@ -59,6 +62,9 @@ /* for searching */ uchar bssid[Eaddrlen]; char essid[Essidlen+2]; + + /* supported data rates by hardware */ + uchar *rates; /* effective base station */ Wnode *bss; --- /sys/src/nix/k10/etheriwl.c Sat May 3 06:27:42 2014 +++ /sys/src/nix/k10/etheriwl.c Sat May 3 06:27:44 2014 @@ -892,6 +892,7 @@ break; } + poweroff(ctlr); return 0; Err: print("iwlinit: %s\n", err); @@ -1321,7 +1322,8 @@ c[3] = 1; /* isvalid */ c[4] = ctlr->eeprom.crystal; c[5] = ctlr->eeprom.crystal>>16; - if((err = cmd(ctlr, 176, c, 8)) != nil) + /* for some reason 8086:4238 needs a second try */ + if(cmd(ctlr, 176, c, 8) != nil && (err = cmd(ctlr, 176, c, 8)) != nil) return err; } @@ -1823,6 +1825,24 @@ { 120, 0x3, 0 } }; +static uchar iwlrates[] = { + 0x80 | 2, + 0x80 | 4, + 0x80 | 11, + 0x80 | 22, + 0x80 | 12, + 0x80 | 18, + 0x80 | 24, + 0x80 | 36, + 0x80 | 48, + 0x80 | 72, + 0x80 | 96, + 0x80 | 108, + 0x80 | 120, + + 0 +}; + enum { TFlagNeedProtection = 1<<0, TFlagNeedRTS = 1<<1, @@ -1868,9 +1888,9 @@ return; } - rate = 0; flags = 0; nodeid = ctlr->bcastnodeid; + p = wn->minrate; w = (Wifipkt*)b->rp; if((w->a1[0] & 1) == 0){ flags |= TFlagNeedACK; @@ -1880,7 +1900,7 @@ if((w->fc[0] & 0x0c) == 0x08 && ctlr->bssnodeid != -1){ nodeid = ctlr->bssnodeid; - rate = 2; /* BUG: hardcode 11Mbit */ + p = wn->maxrate; } if(flags & (TFlagNeedRTS|TFlagNeedCTS)){ @@ -1893,6 +1913,10 @@ } qunlock(ctlr); + rate = 0; + if(p >= iwlrates && p < &iwlrates[nelem(ratetab)]) + rate = p - iwlrates; + /* select first available antenna */ ant = ctlr->rfcfg.txantmask & 7; ant |= (ant == 0); @@ -2058,8 +2082,10 @@ if((csr32r(ctlr, Gpc) & RfKill) == 0) error("wifi disabled by switch"); - if(ctlr->wifi == nil) + if(ctlr->wifi == nil){ ctlr->wifi = wifiattach(edev, transmit); + ctlr->wifi->rates = iwlrates; + } if(ctlr->fw == nil){ fw = readfirmware(fwname[ctlr->type]); @@ -2073,7 +2099,6 @@ ctlr->fw = fw; } - if((err = reset(ctlr)) != nil) error(err); if((err = boot(ctlr)) != nil) @@ -2290,8 +2315,10 @@ case 0x4232: /* Wifi Link 5100 */ case 0x4236: /* WiFi Link 5300 AGN */ case 0x4237: /* Wifi Link 5100 AGN */ + case 0x423d: /* Wifi Link 5150 */ case 0x0085: /* Centrino Advanced-N 6205 */ - case 0x422b: /* Centrino Ultimate-N 6300 */ + case 0x422b: /* Centrino Ultimate-N 6300 variant 1 */ + case 0x4238: /* Centrino Ultimate-N 6300 variant 2 */ case 0x08ae: /* Centrino Wireless-N 100 */ break; } @@ -2369,7 +2396,7 @@ edev->shutdown = iwlshutdown; edev->promiscuous = iwlpromiscuous; edev->multicast = nil; - edev->mbps = 10; + edev->mbps = 54; if(iwlinit(edev) < 0){ edev->ctlr = nil;