]> git.lizzy.rs Git - plan9front.git/commitdiff
wifi: first attempt on negotiating data rates
authorcinap_lenrek <cinap_lenrek@felloff.net>
Mon, 21 Apr 2014 01:43:51 +0000 (03:43 +0200)
committercinap_lenrek <cinap_lenrek@felloff.net>
Mon, 21 Apr 2014 01:43:51 +0000 (03:43 +0200)
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.

sys/src/9/pc/etheriwl.c
sys/src/9/pc/wifi.c
sys/src/9/pc/wifi.h

index 50c134c85eb13554cf4380f7de188f7f4024a699..ee44aa3f400815d89c375bc6bf4b2880149e8308 100644 (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;
index 2f4c63711f885118a0d29b764bcb1778ae7b5f70..6d7a2536c071cf11bd40f9db3045980435d672e8 100644 (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);
 
index bc451cf3de019d479d61bdc2d6c85565e2746ed8..9b878d192cab6c5bb57bc26c931138d0ba3b2425 100644 (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;