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.
This commit is contained in:
cinap_lenrek 2014-04-21 03:43:51 +02:00
parent b94c766fef
commit 3b87d6114d
3 changed files with 99 additions and 27 deletions

View file

@ -1813,6 +1813,24 @@ static struct ratetab {
{ 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 @@ transmit(Wifi *wifi, Wnode *wn, Block *b)
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 @@ transmit(Wifi *wifi, Wnode *wn, Block *b)
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 @@ transmit(Wifi *wifi, Wnode *wn, Block *b)
}
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 @@ iwlattach(Ether *edev)
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 @@ again:
edev->shutdown = iwlshutdown;
edev->promiscuous = iwlpromiscuous;
edev->multicast = nil;
edev->mbps = 10;
edev->mbps = 54;
if(iwlinit(edev) < 0){
edev->ctlr = nil;

View file

@ -37,6 +37,15 @@ static char Sassoc[] = "associated";
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 @@ nodelookup(Wifi *wifi, uchar *bssid, int new)
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 @@ wifiprobe(Wifi *wifi, Wnode *wn)
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 @@ sendassoc(Wifi *wifi, Wnode *bss)
*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 @@ recvassoc(Wifi *wifi, Wnode *wn, uchar *d, int len)
}
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 @@ recvbeacon(Wifi *, Wnode *wn, uchar *d, int len)
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 @@ recvbeacon(Wifi *, Wnode *wn, uchar *d, int len)
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;
@ -673,6 +713,8 @@ wifiattach(Ether *ether, void (*transmit)(Wifi*, Wnode*, Block*))
wifi->ether = ether;
wifi->transmit = transmit;
wifi->rates = basicrates;
wifi->essid[0] = 0;
memmove(wifi->bssid, ether->bcast, Eaddrlen);

View file

@ -37,6 +37,9 @@ struct Wnode
ulong lastsend;
ulong lastseen;
uchar *minrate; /* pointers into wifi->rates */
uchar *maxrate;
/* stuff from beacon */
int ival;
int cap;
@ -60,6 +63,9 @@ struct Wifi
uchar bssid[Eaddrlen];
char essid[Essidlen+2];
/* supported data rates by hardware */
uchar *rates;
/* effective base station */
Wnode *bss;