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:
parent
b94c766fef
commit
3b87d6114d
3 changed files with 99 additions and 27 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue