git: 9front

Download patch

ref: e50d910806e298b5bf25fb7033095fd05faf574b
parent: 206862fbf11c8163d90dea86f3dcf79f19831a0e
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Sat Jun 15 15:02:17 EDT 2013

wpa: automatically pick cipher suits from beacon rsne

--- a/sys/src/9/pc/wifi.c
+++ b/sys/src/9/pc/wifi.c
@@ -280,6 +280,7 @@
 static void
 recvbeacon(Wifi *, Wnode *wn, uchar *d, int len)
 {
+	static uchar wpa1oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
 	uchar *e, *x;
 	uchar t, m[256/8];
 
@@ -304,7 +305,7 @@
 		m[t/8] |= 1<<(t%8);
 
 		switch(t){
-		case 0:	/* SSID */
+		case 0x00:	/* SSID */
 			len = 0;
 			while(len < Essidlen && d+len < x && d[len] != 0)
 				len++;
@@ -315,10 +316,20 @@
 				wn->ssid[len] = 0;
 			}
 			break;
-		case 3:	/* DSPARAMS */
+		case 0x03:	/* DSPARAMS */
 			if(d != x)
 				wn->channel = d[0];
 			break;
+		case 0xdd:	/* vendor specific */
+			len = x - d;
+			if(len < sizeof(wpa1oui) || memcmp(d, wpa1oui, sizeof(wpa1oui)) != 0)
+				break;
+			/* no break */
+		case 0x30:	/* RSN information */
+			len = x - &d[-2];
+			memmove(wn->brsne, &d[-2], len);
+			wn->brsnelen = len;
+			break;
 		}
 	}
 }
@@ -655,8 +666,20 @@
 
 	p = seprint(p, e, "status: %s\n", wifi->status);
 	p = seprint(p, e, "essid: %s\n", wifi->essid);
+
 	wn = wifi->bss;
-	p = seprint(p, e, "bssid: %E\n", wn != nil ? wn->bssid : zeros);
+	if(wn != nil){
+		p = seprint(p, e, "bssid: %E\n", wn->bssid);
+		if(wn->brsnelen > 0){
+			int i;
+
+			p = seprint(p, e, "brsne: ");
+			for(i=0; i<wn->brsnelen; i++)
+				p = seprint(p, e, "%.2X", wn->brsne[i]);
+			p = seprint(p, e, "\n");
+		}
+		p = seprint(p, e, "channel: %.2d\n", wn->channel);
+	}
 
 	now = MACHP(0)->ticks;
 	for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
--- a/sys/src/9/pc/wifi.h
+++ b/sys/src/9/pc/wifi.h
@@ -27,15 +27,18 @@
 	char	ssid[Essidlen+2];
 
 	int	rsnelen;
-	uchar	rsne[256];
+	uchar	rsne[258];
 	Wkey	txkey[1];
 	Wkey	rxkey[5];
 
+	/* stuff from beacon */
 	int	ival;
 	int	cap;
 	int	aid;
 	int	channel;
 	long	lastseen;
+	int	brsnelen;
+	uchar	brsne[258];
 };
 
 struct Wifi
--- a/sys/src/cmd/aux/wpa.c
+++ b/sys/src/cmd/aux/wpa.c
@@ -66,6 +66,10 @@
 char	essid[32+1];
 uvlong	lastrepc;
 
+uchar rsntkipoui[4] = {0x00, 0x0F, 0xAC, 0x02};
+uchar rsnccmpoui[4] = {0x00, 0x0F, 0xAC, 0x04};
+uchar rsnapskoui[4] = {0x00, 0x0F, 0xAC, 0x02};
+
 uchar	rsnie[] = {
 	0x30,			/* RSN */
 	0x14,			/* length */
@@ -78,6 +82,10 @@
 	0x00, 0x00,		/* capabilities */
 };
 
+uchar wpa1oui[4]    = {0x00, 0x50, 0xF2, 0x01};
+uchar wpatkipoui[4] = {0x00, 0x50, 0xF2, 0x02};
+uchar wpaapskoui[4] = {0x00, 0x50, 0xF2, 0x02};
+
 uchar	wpaie[] = {
 	0xdd,			/* vendor specific */
 	0x16,			/* length */
@@ -90,8 +98,31 @@
 	0x00, 0x50, 0xf2, 0x02,	/* authentication suite PSK */
 };
 
+int
+hextob(char *s, char **sp, uchar *b, int n)
+{
+	int r;
+
+	n <<= 1;
+	for(r = 0; r < n && *s; s++){
+		*b <<= 4;
+		if(*s >= '0' && *s <= '9')
+			*b |= (*s - '0');
+		else if(*s >= 'a' && *s <= 'f')
+			*b |= 10+(*s - 'a');
+		else if(*s >= 'A' && *s <= 'F')
+			*b |= 10+(*s - 'A');
+		else break;
+		if((++r & 1) == 0)
+			b++;
+	}
+	if(sp != nil)
+		*sp = s;
+	return r >> 1;
+}
+
 char*
-getessid(void)
+getifstats(char *key, char *val, int nval)
 {
 	char buf[8*1024], *f[2], *p, *e;
 	int fd, n;
@@ -101,22 +132,172 @@
 		return nil;
 	n = read(fd, buf, sizeof(buf)-1);
 	close(fd);
-	if(n > 0){
-		buf[n] = 0;
-		for(p = buf; (e = strchr(p, '\n')) != nil; p = e){
-			*e++ = 0;
-			if(tokenize(p, f, 2) != 2)
-				continue;
-			if(strcmp(f[0], "essid:") != 0)
-				continue;
-			strncpy(essid, f[1], 32);
-			return essid;
-		}
+	if(n <= 0)
+		return nil;
+	buf[n] = 0;
+	for(p = buf; (e = strchr(p, '\n')) != nil; p = e){
+		*e++ = 0;
+		if(tokenize(p, f, 2) != 2)
+			continue;
+		if(strcmp(f[0], key) != 0)
+			continue;
+		strncpy(val, f[1], nval);
+		val[nval-1] = 0;
+		return val;
 	}
 	return nil;
 }
 
+char*
+getessid(void)
+{
+	return getifstats("essid:", essid, sizeof(essid));
+}
+
 int
+buildrsne(uchar rsne[258])
+{
+	char buf[1024];
+	uchar brsne[258];
+	int brsnelen;
+	uchar *p, *w, *e;
+	int i, n;
+
+	if(getifstats("brsne:", buf, sizeof(buf)) == nil)
+		return 0;	/* not an error, might be old kernel */
+
+	brsnelen = hextob(buf, nil, brsne, sizeof(brsne));
+	if(brsnelen <= 4){
+trunc:		sysfatal("invalid or truncated RSNE; brsne: %s", buf);
+		return 0;
+	}
+
+	w = rsne;
+	p = brsne;
+	e = p + brsnelen;
+	if(p[0] == 0x30){
+		p += 2;
+
+		/* RSN */
+		*w++ = 0x30;
+		*w++ = 0;	/* length */
+	} else if(p[0] == 0xDD){
+		p += 2;
+		if((e - p) < 4 || memcmp(p, wpa1oui, 4) != 0){
+			sysfatal("unrecognized WPAIE type; brsne: %s", buf);
+			return 0;
+		}
+
+		/* WPA */
+		*w++ = 0xDD;
+		*w++ = 0;	/* length */
+
+		memmove(w, wpa1oui, 4);
+		w += 4;
+	} else {
+		sysfatal("unrecognized RSNE type; brsne: %s", buf);
+		return 0;
+	}
+
+	if((e - p) < 6)
+		goto trunc;
+
+	*w++ = *p++;		/* version */
+	*w++ = *p++;
+
+	if(rsne[0] == 0x30){
+		if(memcmp(p, rsnccmpoui, 4) == 0)
+			groupcipher = &ccmp;
+		else if(memcmp(p, rsnccmpoui, 4) == 0)
+			groupcipher = &tkip;
+		else {
+			sysfatal("unrecognized RSN group cipher; brsne: %s", buf);
+			return 0;
+		}
+	} else {
+		if(memcmp(p, wpatkipoui, 4) != 0){
+			sysfatal("unrecognized WPA group cipher; brsne: %s", buf);
+			return 0;
+		}
+		groupcipher = &tkip;
+	}
+
+	memmove(w, p, 4);	/* group cipher */
+	w += 4;
+	p += 4;
+
+	if((e - p) < 6)
+		goto trunc;
+
+	*w++ = 0x01;		/* # of peer ciphers */
+	*w++ = 0x00;
+	n = *p++;
+	n |= *p++ << 8;
+
+	if(n <= 0)
+		goto trunc;
+
+	peercipher = &tkip;
+	for(i=0; i<n; i++){
+		if((e - p) < 4)
+			goto trunc;
+
+		if(rsne[0] == 0x30 && memcmp(p, rsnccmpoui, 4) == 0 && peercipher == &tkip)
+			peercipher = &ccmp;
+		p += 4;
+	}
+	if(peercipher == &ccmp)
+		memmove(w, rsnccmpoui, 4);
+	else if(rsne[0] == 0x30)
+		memmove(w, rsntkipoui, 4);
+	else
+		memmove(w, wpatkipoui, 4);
+	w += 4;
+
+	if((e - p) < 6)
+		goto trunc;
+
+	*w++ = 0x01;		/* # of auth suites */
+	*w++ = 0x00;
+	n = *p++;
+	n |= *p++ << 8;
+
+	if(n <= 0)
+		goto trunc;
+
+	for(i=0; i<n; i++){
+		if((e - p) < 4)
+			goto trunc;
+
+		/* look for PSK oui */
+		if(rsne[0] == 0x30){
+			if(memcmp(p, rsnapskoui, 4) == 0)
+				break;
+		} else {
+			if(memcmp(p, wpaapskoui, 4) == 0)
+				break;
+		}
+		p += 4;
+	}
+	if(i >= n){
+		sysfatal("auth suite is not PSK; brsne: %s", buf);
+		return 0;
+	}
+
+	memmove(w, p, 4);
+	w += 4;
+
+	if(rsne[0] == 0x30){
+		/* RSN caps */
+		*w++ = 0x00;
+		*w++ = 0x00;
+	}
+
+	rsne[1] = (w - rsne) - 2;
+	return w - rsne;
+}
+
+int
 getptk(	uchar smac[Eaddrlen], uchar amac[Eaddrlen], 
 	uchar snonce[Noncelen],  uchar anonce[Noncelen], 
 	uchar ptk[PTKlen])
@@ -353,11 +534,10 @@
 	fmtinstall('H', Hfmt);
 	fmtinstall('E', eipfmt);
 
-	/* default is WPA */
-	rsne = wpaie;
-	rsnelen = sizeof(wpaie);
-	peercipher = &tkip;
-	groupcipher = &tkip;
+	rsne = nil;
+	rsnelen = -1;
+	peercipher = nil;
+	groupcipher = nil;
 
 	ARGBEGIN {
 	case 'd':
@@ -414,6 +594,24 @@
 		auth_getkey(s);
 		free(s);
 	}
+
+	if(rsnelen <= 0){
+		static uchar brsne[258];
+
+		rsne = brsne;
+		rsnelen = buildrsne(rsne);
+	}
+
+	if(rsnelen <= 0){
+		/* default is WPA */
+		rsne = wpaie;
+		rsnelen = sizeof(wpaie);
+		peercipher = &tkip;
+		groupcipher = &tkip;
+	}
+
+	if(debug)
+		fprint(2, "rsne: %.*H\n", rsnelen, rsne);
 
 	/*
 	 * we use write() instead of fprint so message gets  written
--