ref: 3b87d6114dceccd0a5cee998ab6d6cc393de1ef2
parent: b94c766fef2c0ad8334f9e63ad3acc4bc25aa031
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Apr 20 23:43:51 EDT 2014
wifi: first attempt on negotiating data rates driver sets wifi->rates array to tell wifi layer what rates it supports. when we receive beacon, we determine the minimum and maximum data rates and set wn->minrate and wn->maxrate to point to the entries in wifi->rates. it is the responsibility of the driver to use this information on transmit.
--- a/sys/src/9/pc/etheriwl.c
+++ b/sys/src/9/pc/etheriwl.c
@@ -1813,6 +1813,24 @@
{ 120, 0x3, 0 }
};
+static uchar iwlrates[] = {
+ 0x80 | 2,
+ 0x80 | 4,
+ 0x80 | 11,
+ 0x80 | 22,
+ 12,
+ 18,
+ 24,
+ 36,
+ 48,
+ 72,
+ 96,
+ 108,
+ 120,
+
+ 0
+};
+
enum {
TFlagNeedProtection = 1<<0,
TFlagNeedRTS = 1<<1,
@@ -1858,9 +1876,9 @@
return;
}
- rate = 0;
flags = 0;
nodeid = ctlr->bcastnodeid;
+ p = wn->minrate;
w = (Wifipkt*)b->rp;
if((w->a1[0] & 1) == 0){
flags |= TFlagNeedACK;
@@ -1870,7 +1888,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)){
@@ -1883,6 +1901,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);
@@ -2048,8 +2070,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]);
@@ -2359,7 +2383,7 @@
edev->shutdown = iwlshutdown;
edev->promiscuous = iwlpromiscuous;
edev->multicast = nil;
- edev->mbps = 10;
+ edev->mbps = 54;
if(iwlinit(edev) < 0){
edev->ctlr = nil;
--- a/sys/src/9/pc/wifi.c
+++ b/sys/src/9/pc/wifi.c
@@ -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++ = n;
+ memmove(p, bss->ssid, 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);
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;
@@ -672,6 +712,8 @@
}
wifi->ether = ether;
wifi->transmit = transmit;
+
+ wifi->rates = basicrates;
wifi->essid[0] = 0;
memmove(wifi->bssid, ether->bcast, Eaddrlen);
--- a/sys/src/9/pc/wifi.h
+++ b/sys/src/9/pc/wifi.h
@@ -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;