shithub: riscv

Download patch

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;