git: 9front

Download patch

ref: a14eb5ac1a8cac780246536b6c398b6d8c0cc1b2
parent: 512973f9c43f1fbd690583e6a5e0e39efe82a04a
parent: 0ebaa881d3ac3f1516ede3c93358287420c2dfb8
author: ppatience0 <ppatience0@gmail.com>
date: Wed Feb 13 02:37:26 EST 2013

merge

--- a/lib/rsc
+++ b/lib/rsc
@@ -71,3 +71,5 @@
 Please don't.
 Test?
 sure
+NOT LGTM sorry
+i lost the ability to use rio a few years ago when they moved wireless configuration into the gnome window manager, making it impossible to have rio and a network connection at the same time.
--- a/lib/troll
+++ b/lib/troll
@@ -114,3 +114,6 @@
 just run linux -- aiju
 I'm fairly new to plan9, and am having trouble ssh'ing to my mac.
 Subject: [golang-dev] not reading code
+Is Trolling Ever Okay?
+I've downloaded the nix bits from http://code.google.com/p/nix-os/ and compiled it under 9vx on OSX, but I'm having some trouble getting the resultant kernel to boot.
+Subject: [nix] servers down
--- a/sys/games/lib/fortunes
+++ b/sys/games/lib/fortunes
@@ -4799,3 +4799,15 @@
 --- you can reply above this line ---
 MIT OpenCourseware >> Electrical Engineering and Computer Science >> Introduction to Electrical Engineering and Computer Science I >> Python Tutorial
 (#plan9) semka → May be I should ask at #cat-v :)
+Monument To Steve Jobs Goes Up In St. Petersburg
+But without moving the directory specifics out of user space code like it was V7 and earlier, it would have been hard to create something as clean as VFS.
+(#cat-v) aiju → what's weird is that uriel loved gay colours
+rcirc on GNU Emacs 24.2.1
+Decade Old KDE Bug Fixed
+Fix the value of TWO
+Fedora 18 Installer: Counterintuitive and Confusing?
+when all you understand is trivial bullshit, trivial bullshit is what's important
+hjfs: ending
+If it’s done right this is not wrong. -- 20h
+Just today I found out that the Chrome JS editor can ‘hot-swap’ your code.
+A programming language, even with its libraries, is not enough, nor is it always the right place to solve all the problems of the network.
--- a/sys/include/mp.h
+++ b/sys/include/mp.h
@@ -45,7 +45,7 @@
 char*	mptoa(mpint*, int, char*, int);
 mpint*	letomp(uchar*, uint, mpint*);	/* byte array, little-endian */
 int	mptole(mpint*, uchar*, uint, uchar**);
-mpint*	betomp(uchar*, uint, mpint*);	/* byte array, little-endian */
+mpint*	betomp(uchar*, uint, mpint*);	/* byte array, big-endian */
 int	mptobe(mpint*, uchar*, uint, uchar**);
 uint	mptoui(mpint*);			/* unsigned int */
 mpint*	uitomp(uint, mpint*);
--- a/sys/lib/rootstub
+++ b/sys/lib/rootstub
@@ -107,6 +107,7 @@
 mkdir -p dist/plan9front
 mkdir -p fd
 mkdir -p lib/audio
+mkdir -p lib/firmware
 mkdir -p lib/ndb
 mkdir -p lib/tftpd
 mkdir -p mail/box
--- a/sys/man/8/plan9.ini
+++ b/sys/man/8/plan9.ini
@@ -381,6 +381,29 @@
 Currently the only tested cards are those based on the
 Intersil Prism 2.5 chipset.
 .
+.TP
+.B iwl
+Intel Wireless WiFi Link mini PCI-Express adapters require
+firmware from
+.B http://firmware.openbsd.org/firmware/iwn-firmware*.tgz
+to be present on attach in
+.B /lib/firmware
+or
+.B /boot.
+To select the access point, the
+.B essid=
+parameter can be specified at boot or set during runtime
+like:
+.EX
+	echo essid left-armpit >/net/ether1/clone
+.EE
+Scan results appear in the
+.B ifstats
+file and can be read out like:
+.EX
+	cat /net/ether1/ifstats
+.EE
+Ad-hoc mode or encryption is currently not supported.
 .SS DISKS, TAPES
 (S)ATA controllers are autodetected.
 .SS \fL*nodma=\fP
--- a/sys/src/9/pc/etheriwl.c
+++ b/sys/src/9/pc/etheriwl.c
@@ -19,7 +19,6 @@
 #include "wifi.h"
 
 enum {
-
 	Ntxlog		= 8,
 	Ntx		= 1<<Ntxlog,
 	Nrxlog		= 8,
@@ -197,16 +196,18 @@
 enum {
 	SchedBase		= 0xa02c00,
 	SchedSramAddr		= SchedBase,
-	SchedDramAddr5000	= SchedBase+0x008,
+
 	SchedDramAddr4965	= SchedBase+0x010,
-	SchedTxFact5000		= SchedBase+0x010,
 	SchedTxFact4965		= SchedBase+0x01c,
 	SchedQueueRdptr4965	= SchedBase+0x064,	// +q*4
-	SchedQueueRdptr5000	= SchedBase+0x068,	// +q*4
 	SchedQChainSel4965	= SchedBase+0x0d0,
 	SchedIntrMask4965	= SchedBase+0x0e4,
-	SchedQChainSel5000	= SchedBase+0x0e8,
 	SchedQueueStatus4965	= SchedBase+0x104,	// +q*4
+
+	SchedDramAddr5000	= SchedBase+0x008,
+	SchedTxFact5000		= SchedBase+0x010,
+	SchedQueueRdptr5000	= SchedBase+0x068,	// +q*4
+	SchedQChainSel5000	= SchedBase+0x0e8,
 	SchedIntrMask5000	= SchedBase+0x108,
 	SchedQueueStatus5000	= SchedBase+0x10c,	// +q*4
 	SchedAggrSel5000	= SchedBase+0x248,
@@ -215,13 +216,33 @@
 enum {
 	SchedCtxOff4965		= 0x380,
 	SchedCtxLen4965		= 416,
-	SchedTransTblOff4965	= 0x500,
 
 	SchedCtxOff5000		= 0x600,
 	SchedCtxLen5000		= 512,
-	SchedTransTblOff5000	= 0x7e0,
 };
 
+enum {
+	FilterPromisc		= 1<<0,
+	FilterCtl		= 1<<1,
+	FilterMulticast		= 1<<2,
+	FilterNoDecrypt		= 1<<3,
+	FilterBSS		= 1<<5,
+	FilterBeacon		= 1<<6,
+};
+
+enum {
+	RFlag24Ghz		= 1<<0,
+	RFlagCCK		= 1<<1,
+	RFlagAuto		= 1<<2,
+	RFlagShSlot		= 1<<4,
+	RFlagShPreamble		= 1<<5,
+	RFlagNoDiversity	= 1<<7,
+	RFlagAntennaA		= 1<<8,
+	RFlagAntennaB		= 1<<9,
+	RFlagTSF		= 1<<15,
+	RFlagCTSToSelf		= 1<<30,
+};
+
 typedef struct FWInfo FWInfo;
 typedef struct FWImage FWImage;
 typedef struct FWSect FWSect;
@@ -231,8 +252,6 @@
 
 typedef struct Ctlr Ctlr;
 
-typedef struct Ctlrtype Ctlrtype;
-
 struct FWSect
 {
 	uchar	*data;
@@ -303,7 +322,15 @@
 	u32int *nic;
 	uchar *kwpage;
 
+	/* assigned node ids in hardware node table or -1 if unassigned */
+	int bcastnodeid;
+	int bssnodeid;
+
+	/* current receiver settings */
+	uchar bssid[Eaddrlen];
 	int channel;
+	int prom;
+	int aid;
 
 	RXQ rx;
 	TXQ tx[20];
@@ -349,41 +376,18 @@
 	Type6005	= 11,
 };
 
-struct Ctlrtype
-{
-	char	*fwname;
+static char *fwname[16] = {
+	[Type4965] "iwn-4965",
+	[Type5300] "iwn-5000",
+	[Type5350] "iwn-5000",
+	[Type5150] "iwn-5150",
+	[Type5100] "iwn-5000",
+	[Type1000] "iwn-1000",
+	[Type6000] "iwn-6000",
+	[Type6050] "iwn-6050",
+	[Type6005] "iwn-6005",
 };
 
-static Ctlrtype ctlrtype[16] = {
-	[Type4965] {
-		.fwname = "iwn-4965",
-	},
-	[Type5300] {
-		.fwname = "iwn-5000",
-	},
-	[Type5350] {
-		.fwname = "iwn-5000",
-	},
-	[Type5150] {
-		.fwname = "iwn-5150",
-	},
-	[Type5100] {
-		.fwname = "iwn-5000",
-	},
-	[Type1000] {
-		.fwname = "iwn-1000",
-	},
-	[Type6000] {
-		.fwname = "iwn-6000",
-	},
-	[Type6050] {
-		.fwname = "iwn-6050",
-	},
-	[Type6005] {
-		.fwname = "iwn-6005",
-	},
-};
-
 #define csr32r(c, r)	(*((c)->nic+((r)/4)))
 #define csr32w(c, r, v)	(*((c)->nic+((r)/4)) = (v))
 
@@ -725,7 +729,7 @@
 			return "bad firmware signature";
 		p += 4;
 		strncpy(i->descr, (char*)p, 64);
-		i->descr[sizeof(i->descr)-1] = 0;
+		i->descr[64] = 0;
 		p += 64;
 		i->rev = get32(p); p += 4;
 		i->build = get32(p); p += 4;
@@ -747,7 +751,7 @@
 			default:s = &dummy;
 			}
 			p += 2;
-			if(get16(p) != alt)
+			if(get16(p) != 0 && get16(p) != alt)
 				s = &dummy;
 			p += 2;
 			s->size = get32(p); p += 4;
@@ -913,6 +917,7 @@
 			return err;
 		if((err = loadfirmware1(ctlr, 0x00800000, fw->main.data.data, fw->main.data.size)) != nil)
 			return err;
+		csr32w(ctlr, Reset, 0);
 		goto bootmain;
 	}
 
@@ -937,6 +942,12 @@
 	prphwrite(ctlr, BsmDramTextAddr, PCIWADDR(p) >> 4);
 	prphwrite(ctlr, BsmDramTextSize, fw->init.text.size);
 
+	nicunlock(ctlr);
+	if((err = niclock(ctlr)) != nil){
+		free(dma);
+		return err;
+	}
+
 	p = fw->boot.text.data;
 	n = fw->boot.text.size/4;
 	for(i=0; i<n; i++, p += 4)
@@ -990,7 +1001,6 @@
 	nicunlock(ctlr);
 
 bootmain:
-	csr32w(ctlr, Reset, 0);
 	if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive){
 		free(dma);
 		return "main firmware boot failed";
@@ -1019,12 +1029,11 @@
 	q = &ctlr->tx[qid];
 	while(q->n >= Ntx){
 		iunlock(ctlr);
-		eqlock(q);
-		if(waserror()){
-			qunlock(q);
-			nexterror();
+		qlock(q);
+		if(!waserror()){
+			tsleep(q, txqready, q, 10);
+			poperror();
 		}
-		tsleep(q, txqready, q, 10);
 		qunlock(q);
 		ilock(ctlr);
 	}
@@ -1067,12 +1076,43 @@
 	iunlock(ctlr);
 }
 
+static int
+txqempty(void *arg)
+{
+	TXQ *q = arg;
+	return q->n == 0;
+}
+
 static void
+flushq(Ctlr *ctlr, uint qid)
+{
+	TXQ *q;
+
+	q = &ctlr->tx[qid];
+	while(q->n > 0){
+		qlock(q);
+		if(!waserror()){
+			tsleep(q, txqempty, q, 10);
+			poperror();
+		}
+		qunlock(q);
+	}
+}
+
+
+static void
+flushcmd(Ctlr *ctlr)
+{
+	flushq(ctlr, 4);
+}
+
+static void
 cmd(Ctlr *ctlr, uint code, uchar *data, int size)
 {
 	qcmd(ctlr, 4, code, data, size, nil);
 }
 
+
 static void
 setled(Ctlr *ctlr, int which, int on, int off)
 {
@@ -1099,9 +1139,6 @@
 	char *err;
 	int i, q;
 
-	/* main led turn on! (verify that firmware processes commands) */
-	setled(ctlr, 2, 0, 1);
-
 	if((err = niclock(ctlr)) != nil)
 		error(err);
 
@@ -1118,8 +1155,8 @@
 	}
 
 	ctlr->sched.base = prphread(ctlr, SchedSramAddr);
-	for(i=0; i < ctxlen/4; i++)
-		memwrite(ctlr, ctlr->sched.base + ctxoff + i*4, 0);
+	for(i=0; i < ctxlen; i += 4)
+		memwrite(ctlr, ctlr->sched.base + ctxoff + i, 0);
 
 	prphwrite(ctlr, dramaddr, PCIWADDR(ctlr->sched.s)>>10);
 
@@ -1130,7 +1167,7 @@
 		prphwrite(ctlr, SchedQChainSel5000, 0xfffef);
 		prphwrite(ctlr, SchedAggrSel5000, 0);
 
-		for(q=0; q<nelem(ctlr->tx); q++){
+		for(q=0; q<20; q++){
 			prphwrite(ctlr, SchedQueueRdptr5000 + q*4, 0);
 			csr32w(ctlr, HbusTargWptr, q << 8);
 
@@ -1162,25 +1199,26 @@
 
 	/* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */
 	for(q=0; q<7; q++){
-		static uchar qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
-		if(ctlr->type != Type4965)
+		if(ctlr->type != Type4965){
+			static uchar qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
 			prphwrite(ctlr, SchedQueueStatus5000 + q*4, 0x00ff0018 | qid2fifo[q]);
-		else
-			prphwrite(ctlr, SchedQueueStatus4965 + q*4, 0x0007fc01 | qid2fifo[q]);
+		} else {
+			static uchar qid2fifo[] = { 3, 2, 1, 0, 4, 5, 6 };
+			prphwrite(ctlr, SchedQueueStatus4965 + q*4, 0x0007fc01 | qid2fifo[q]<<1);
+		}
 	}
 	nicunlock(ctlr);
 
-	if(ctlr->type != Type5150){
-		memset(c, 0, sizeof(c));
-		c[0] = 15;	/* code */
-		c[1] = 0;	/* grup */
-		c[2] = 1;	/* ngroup */
-		c[3] = 1;	/* isvalid */
-		put16(c+4, ctlr->eeprom.crystal);
-		cmd(ctlr, 176, c, 8);
-	}
-
 	if(ctlr->type != Type4965){
+		if(ctlr->type != Type5150){
+			memset(c, 0, sizeof(c));
+			c[0] = 15;	/* code */
+			c[1] = 0;	/* grup */
+			c[2] = 1;	/* ngroup */
+			c[3] = 1;	/* isvalid */
+			put16(c+4, ctlr->eeprom.crystal);
+			cmd(ctlr, 176, c, 8);
+		}
 		put32(c, ctlr->rfcfg.txantmask & 7);
 		cmd(ctlr, 152, c, 4);
 	}
@@ -1211,15 +1249,15 @@
 		p += 8;		/* tcs */
 		p += 8;		/* rxmic */
 		p += 8;		/* txmic */
-		p += 4;		/* htflags */
-		p += 4;		/* mask */
-		p += 2;		/* disable tid */
-		p += 2;		/* reserved */
-		p++;		/* add ba tid */
-		p++;		/* del ba tid */
-		p += 2;		/* add ba ssn */
-		p += 4;		/* reserved */
 	}
+	p += 4;		/* htflags */
+	p += 4;		/* mask */
+	p += 2;		/* disable tid */
+	p += 2;		/* reserved */
+	p++;		/* add ba tid */
+	p++;		/* del ba tid */
+	p += 2;		/* add ba ssn */
+	p += 4;		/* reserved */
 	cmd(ctlr, 24, c, p - c);
 }
 
@@ -1227,13 +1265,39 @@
 rxon(Ether *edev, Wnode *bss)
 {
 	uchar c[Tcmdsize], *p;
+	int filter, flags;
 	Ctlr *ctlr;
 
 	ctlr = edev->ctlr;
+	filter = FilterMulticast | FilterBeacon;
+	if(ctlr->prom){
+		filter |= FilterPromisc;
+		bss = nil;
+	}
+	if(bss != nil){
+		ctlr->channel = bss->channel;
+		memmove(ctlr->bssid, bss->bssid, Eaddrlen);
+		ctlr->aid = bss->aid;
+		if(ctlr->aid != 0){
+			filter |= FilterBSS;
+			filter &= ~FilterBeacon;
+			ctlr->bssnodeid = -1;
+		} else
+			ctlr->bcastnodeid = -1;
+	} else {
+		memmove(ctlr->bssid, edev->bcast, Eaddrlen);
+		ctlr->aid = 0;
+		ctlr->bcastnodeid = -1;
+		ctlr->bssnodeid = -1;
+	}
+	flags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
+
+	if(0) print("rxon: bssid %E, aid %x, channel %d, filter %x, flags %x\n",
+		ctlr->bssid, ctlr->aid, ctlr->channel, filter, flags);
+
 	memset(p = c, 0, sizeof(c));
 	memmove(p, edev->ea, 6); p += 8;	/* myaddr */
-	memmove(p, (bss != nil) ? bss->bssid : edev->bcast, 6);
-	p += 8;					/* bssid */
+	memmove(p, ctlr->bssid, 6); p += 8;	/* bssid */
 	memmove(p, edev->ea, 6); p += 8;	/* wlap */
 	*p++ = 3;				/* mode (STA) */
 	*p++ = 0;				/* air (?) */
@@ -1242,14 +1306,13 @@
 	p += 2;
 	*p++ = 0xff;				/* ofdm mask (not yet negotiated) */
 	*p++ = 0x0f;				/* cck mask (not yet negotiated) */
-	if(bss != nil)
-		put16(p, bss->aid & ~0xc000);
+	put16(p, ctlr->aid & 0x3fff);
 	p += 2;					/* aid */
-	put32(p, (1<<15)|(1<<30)|(1<<0));	/* flags (TSF | CTS_TO_SELF | 24GHZ) */
+	put32(p, flags);
 	p += 4;
-	put32(p, 8|4|1);			/* filter (NODECRYPT|MULTICAST|PROMISC) */
+	put32(p, filter);
 	p += 4;
-	*p++ = bss != nil ? bss->channel : ctlr->channel;
+	*p++ = ctlr->channel;
 	p++;					/* reserved */
 	*p++ = 0xff;				/* ht single mask */
 	*p++ = 0xff;				/* ht dual mask */
@@ -1261,9 +1324,15 @@
 	}
 	cmd(ctlr, 16, c, p - c);
 
-	addnode(ctlr, (ctlr->type != Type4965) ? 15 : 31, edev->bcast);
-	if(bss != nil)
-		addnode(ctlr, 0, bss->bssid);
+	if(ctlr->bcastnodeid == -1){
+		ctlr->bcastnodeid = (ctlr->type != Type4965) ? 15 : 31;
+		addnode(ctlr, ctlr->bcastnodeid, edev->bcast);
+	}
+	if(ctlr->bssnodeid == -1 && bss != nil && ctlr->aid != 0){
+		ctlr->bssnodeid = 0;
+		addnode(ctlr, ctlr->bssnodeid, bss->bssid);
+	}
+	flushcmd(ctlr);
 }
 
 static struct ratetab {
@@ -1271,10 +1340,10 @@
 	uchar	plcp;
 	uchar	flags;
 } ratetab[] = {
-	{   2,  10, 1<<1 },
-	{   4,  20, 1<<1 },
-	{  11,  55, 1<<1 },
-	{  22, 110, 1<<1 },
+	{   2,  10, RFlagCCK },
+	{   4,  20, RFlagCCK },
+	{  11,  55, RFlagCCK },
+	{  22, 110, RFlagCCK },
 	{  12, 0xd, 0 },
 	{  18, 0xf, 0 },
 	{  24, 0x5, 0 },
@@ -1286,32 +1355,80 @@
 	{ 120, 0x3, 0 }
 };
 
+enum {
+	TFlagNeedProtection	= 1<<0,
+	TFlagNeedRTS		= 1<<1,
+	TFlagNeedCTS		= 1<<2,
+	TFlagNeedACK		= 1<<3,
+	TFlagLinkq		= 1<<4,
+	TFlagImmBa		= 1<<6,
+	TFlagFullTxOp		= 1<<7,
+	TFlagBtDis		= 1<<12,
+	TFlagAutoSeq		= 1<<13,
+	TFlagMoreFrag		= 1<<14,
+	TFlagInsertTs		= 1<<16,
+	TFlagNeedPadding	= 1<<20,
+};
+
 static void
-transmit(Wifi *wifi, Wnode *, Block *b)
+transmit(Wifi *wifi, Wnode *wn, Block *b)
 {
 	uchar c[Tcmdsize], *p;
+	Ether *edev;
 	Ctlr *ctlr;
+	Wifipkt *w;
+	int flags, nodeid, rate;
 
-	ctlr = wifi->ether->ctlr;
+	w = (Wifipkt*)b->rp;
+	edev = wifi->ether;
+	ctlr = edev->ctlr;
 
+	qlock(ctlr);
+
+	if(ctlr->prom == 0)
+	if(wn->aid != ctlr->aid
+	|| wn->channel != ctlr->channel
+	|| memcmp(wn->bssid, ctlr->bssid, Eaddrlen) != 0)
+		rxon(edev, wn);
+
+	rate = 0;
+	flags = 0;
+	nodeid = ctlr->bcastnodeid;
+	if((w->a1[0] & 1) == 0){
+		flags |= TFlagNeedACK;
+
+		if(BLEN(b) > 512-4)
+			flags |= TFlagNeedRTS;
+
+		if((w->fc[0] & 0x0c) == 0x08 &&	ctlr->bssnodeid != -1){
+			nodeid = ctlr->bssnodeid;
+			rate = 2; /* BUG: hardcode 11Mbit */
+		}
+
+		if(flags & (TFlagNeedRTS|TFlagNeedCTS)){
+			if(ctlr->type != Type4965){
+				flags &= ~(TFlagNeedRTS|TFlagNeedCTS);
+				flags |= TFlagNeedProtection;
+			} else
+				flags |= TFlagFullTxOp;
+		}
+	}
+	qunlock(ctlr);
+
 	memset(p = c, 0, sizeof(c));
 	put16(p, BLEN(b));
 	p += 2;
 	p += 2;		/* lnext */
-	put32(p, 0);	/* flags */
+	put32(p, flags);
 	p += 4;
 	put32(p, 0);
 	p += 4;		/* scratch */
 
-	/* BUG: hardcode 11Mbit */
-	*p++ = ratetab[2].plcp;			/* plcp */
-	*p++ = ratetab[2].flags | (1<<6);	/* rflags */
+	*p++ = ratetab[rate].plcp;
+	*p++ = ratetab[rate].flags | (1<<6);
 
 	p += 2;		/* xflags */
-
-	/* BUG: we always use broadcast node! */
-	*p++ = (ctlr->type != Type4965) ? 15 : 31;
-
+	*p++ = nodeid;
 	*p++ = 0;	/* security */
 	*p++ = 0;	/* linkq */
 	p++;		/* reserved */
@@ -1379,11 +1496,7 @@
 	int i;
 
 	ctlr = edev->ctlr;
-	ctlr->channel = 3;
 	for(i = 0; i < edev->nopt; i++){
-		if(strncmp(edev->opt[i], "channel=", 8) == 0)
-			ctlr->channel = atoi(edev->opt[i]+8);
-		else
 		if(strncmp(edev->opt[i], "essid=", 6) == 0){
 			snprint(buf, sizeof(buf), "essid %s", edev->opt[i]+6);
 			if(!waserror()){
@@ -1395,8 +1508,74 @@
 }
 
 static void
+iwlpromiscuous(void *arg, int on)
+{
+	Ether *edev;
+	Ctlr *ctlr;
+
+	edev = arg;
+	ctlr = edev->ctlr;
+	qlock(ctlr);
+	ctlr->prom = on;
+	rxon(edev, ctlr->wifi->bss);
+	qunlock(ctlr);
+}
+
+static void
+iwlproc(void *arg)
+{
+	Ether *edev;
+	Ctlr *ctlr;
+	Wifi *wifi;
+	Wnode *bss;
+
+	edev = arg;
+	ctlr = edev->ctlr;
+	wifi = ctlr->wifi;
+
+	for(;;){
+		/* hop channels for catching beacons */
+		setled(ctlr, 2, 5, 5);
+		while(wifi->bss == nil){
+			qlock(ctlr);
+			if(wifi->bss != nil){
+				qunlock(ctlr);
+				break;
+			}
+			ctlr->channel = 1 + ctlr->channel % 11;
+			ctlr->aid = 0;
+			rxon(edev, nil);
+			qunlock(ctlr);
+			tsleep(&up->sleep, return0, 0, 1000);
+		}
+
+		/* wait for association */
+		setled(ctlr, 2, 10, 10);
+		while((bss = wifi->bss) != nil){
+			if(bss->aid != 0)
+				break;
+			tsleep(&up->sleep, return0, 0, 1000);
+		}
+
+		if(bss == nil)
+			continue;
+
+		/* wait for disassociation */
+		edev->link = 1;
+		setled(ctlr, 2, 0, 1);
+		while((bss = wifi->bss) != nil){
+			if(bss->aid == 0)
+				break;
+			tsleep(&up->sleep, return0, 0, 1000);
+		}
+		edev->link = 0;
+	}
+}
+
+static void
 iwlattach(Ether *edev)
 {
+	char name[32];
 	FWImage *fw;
 	Ctlr *ctlr;
 	char *err;
@@ -1420,10 +1599,10 @@
 			ctlr->wifi = wifiattach(edev, transmit);
 
 		if(ctlr->fw == nil){
-			fw = readfirmware(ctlrtype[ctlr->type].fwname);
+			fw = readfirmware(fwname[ctlr->type]);
 			print("#l%d: firmware: %s, rev %ux, build %ud, size %ux+%ux+%ux+%ux+%ux\n",
 				edev->ctlrno,
-				ctlrtype[ctlr->type].fwname,
+				fwname[ctlr->type],
 				fw->rev, fw->build,
 				fw->main.text.size, fw->main.data.size,
 				fw->init.text.size, fw->init.data.size,
@@ -1502,18 +1681,20 @@
 		if((err = niclock(ctlr)) != nil)
 			error(err);
 
-		prphwrite(ctlr, SchedTxFact5000, 0);
+		if(ctlr->type != Type4965)
+			prphwrite(ctlr, SchedTxFact5000, 0);
+		else
+			prphwrite(ctlr, SchedTxFact4965, 0);
 
 		csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
 
-		for(q=0; q<nelem(ctlr->tx); q++)
-			if(q < 15 || ctlr->type != Type4965)
-				csr32w(ctlr, FhCbbcQueue + q*4, PCIWADDR(ctlr->tx[q].d) >> 8);
+		for(q = (ctlr->type != Type4965) ? 19 : 15; q >= 0; q--)
+			csr32w(ctlr, FhCbbcQueue + q*4, PCIWADDR(ctlr->tx[q].d) >> 8);
+
 		nicunlock(ctlr);
 
-		for(i=0; i<8; i++)
-			if(i < 7 || ctlr->type != Type4965)
-				csr32w(ctlr, FhTxConfig + i*32, FhTxConfigDmaEna | FhTxConfigDmaCreditEna);
+		for(i = (ctlr->type != Type4965) ? 7 : 6; i >= 0; i--)
+			csr32w(ctlr, FhTxConfig + i*32, FhTxConfigDmaEna | FhTxConfigDmaCreditEna);
 
 		csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
 		csr32w(ctlr, UcodeGp1Clr, UcodeGp1CmdBlocked);
@@ -1528,12 +1709,16 @@
 		bootfirmware(ctlr);
 		postboot(ctlr);
 
+		ctlr->bcastnodeid = -1;
+		ctlr->bssnodeid = -1;
+		ctlr->channel = 1;
+		ctlr->aid = 0;
+
 		setoptions(edev);
 
-		rxon(edev, nil);
+		snprint(name, sizeof(name), "#l%diwl", edev->ctlrno);
+		kproc(name, iwlproc, edev);
 
-		edev->prom = 1;
-		edev->link = 1;
 		ctlr->attached = 1;
 	}
 	qunlock(ctlr);
@@ -1619,9 +1804,10 @@
 		case 192:	/* rx phy */
 			break;
 		case 195:	/* rx done */
-			if(d + 60 > b->lim)
+			if(d + 2 > b->lim)
 				break;
-			d += 60;
+			d += d[1];
+			d += 56;
 		case 193:	/* mpdu rx done */
 			if(d + 4 > b->lim)
 				break;
@@ -1705,6 +1891,8 @@
 		switch(pdev->did){
 		default:
 			continue;
+		case 0x4229:	/* WiFi Link 4965 */
+		case 0x4230:	/* WiFi Link 4965 */
 		case 0x4236:	/* WiFi Link 5300 AGN */
 		case 0x4237:	/* Wifi Link 5100 AGN */
 			break;
@@ -1739,7 +1927,7 @@
 		ctlr->pdev = pdev;
 		ctlr->type = (csr32r(ctlr, Rev) >> 4) & 0xF;
 
-		if(ctlrtype[ctlr->type].fwname == nil){
+		if(fwname[ctlr->type] == nil){
 			print("iwl: unsupported controller type %d\n", ctlr->type);
 			vunmap(mem, pdev->mem[0].size);
 			free(ctlr);
@@ -1783,7 +1971,7 @@
 	edev->attach = iwlattach;
 	edev->ifstat = iwlifstat;
 	edev->ctl = iwlctl;
-	edev->promiscuous = nil;
+	edev->promiscuous = iwlpromiscuous;
 	edev->multicast = nil;
 	edev->mbps = 10;
 
--- a/sys/src/9/pc/mkfile
+++ b/sys/src/9/pc/mkfile
@@ -121,6 +121,7 @@
 uartaxp.$O:			uartaxp.i
 etherm10g.$O:			etherm10g2k.i etherm10g4k.i
 etheriwl.$O:			wifi.h
+wifi.$O:			wifi.h
 
 init.h:D:		../port/initcode.c init9.c
 	$CC ../port/initcode.c
--- a/sys/src/9/pc/pci.c
+++ b/sys/src/9/pc/pci.c
@@ -681,6 +681,7 @@
 	{ 0x8086, 0x3b06, pIIxget, pIIxset },	/* Intel 82801? ibex peak */
 	{ 0x8086, 0x3b14, pIIxget, pIIxset },	/* Intel 82801? 3420 */
 	{ 0x8086, 0x1c49, pIIxget, pIIxset },	/* Intel 82hm65 cougar point pch */
+	{ 0x8086, 0x1c4f, pIIxget, pIIxset },	/* Intel 82qm67 cougar point pch */
 	{ 0x8086, 0x1c52, pIIxget, pIIxset },	/* Intel 82q65 cougar point pch */
 	{ 0x8086, 0x1c54, pIIxget, pIIxset },	/* Intel 82q67 cougar point pch */
 	{ 0x1106, 0x0586, viaget, viaset },	/* Viatech 82C586 */
--- a/sys/src/9/pc/wifi.c
+++ b/sys/src/9/pc/wifi.c
@@ -63,9 +63,13 @@
 		default:
 			goto drop;
 		}
-		if(BLEN(b) < SNAPHDRSIZE || b->rp[0] != 0xAA || b->rp[1] != 0xAA || b->rp[2] != 0x03)
+		if(BLEN(b) < SNAPHDRSIZE)
 			break;
 		memmove(&s, b->rp, SNAPHDRSIZE);
+		if(s.dsap != 0xAA || s.ssap != 0xAA || s.control != 3)
+			break;
+		if(s.orgcode[0] != 0 || s.orgcode[1] != 0 || s.orgcode[2] != 0)
+			break;
 		b->rp += SNAPHDRSIZE-ETHERHDRSIZE;
 		e = (Etherpkt*)b->rp;
 		switch(w.fc[1] & 0x03){
@@ -93,12 +97,12 @@
 }
 
 static void
-wifitx(Wifi *wifi, Block *b)
+wifitx(Wifi *wifi, Wnode *wn, Block *b)
 {
 	Wifipkt *w;
 	uint seq;
 
-	seq = wifi->txseq++;
+	seq = incref(&wifi->txseq);
 	seq <<= 4;
 
 	w = (Wifipkt*)b->rp;
@@ -107,7 +111,7 @@
 	w->seq[0] = seq;
 	w->seq[1] = seq>>8;
 
-	(*wifi->transmit)(wifi, wifi->bss, b);
+	(*wifi->transmit)(wifi, wn, b);
 }
 
 
@@ -118,17 +122,32 @@
 
 	if(memcmp(bssid, wifi->ether->bcast, Eaddrlen) == 0)
 		return nil;
-	for(wn = nn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
+	if((wn = wifi->bss) != nil){
 		if(memcmp(wn->bssid, bssid, Eaddrlen) == 0){
 			wn->lastseen = MACHP(0)->ticks;
 			return wn;
 		}
-		if(wn != wifi->bss && wn->lastseen < nn->lastseen)
+	}
+	if((nn = wifi->node) == wn)
+		nn++;
+	for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
+		if(wn == wifi->bss)
+			continue;
+		if(memcmp(wn->bssid, bssid, Eaddrlen) == 0){
+			wn->lastseen = MACHP(0)->ticks;
+			return wn;
+		}
+		if(wn->lastseen < nn->lastseen)
 			nn = wn;
 	}
 	if(!new)
 		return nil;
 	memmove(nn->bssid, bssid, Eaddrlen);
+	nn->ssid[0] = 0;
+	nn->ival = 0;
+	nn->cap = 0;
+	nn->aid = 0;
+	nn->channel = 0;
 	nn->lastseen = MACHP(0)->ticks;
 	return nn;
 }
@@ -156,7 +175,7 @@
 	*p++ = 0;	/* status */
 	*p++ = 0;
 	b->wp = p;
-	wifitx(wifi, b);
+	wifitx(wifi, bss, b);
 }
 
 static void
@@ -190,7 +209,7 @@
 	*p++ = 0x8b;
 	*p++ = 0x96;
 	b->wp = p;
-	wifitx(wifi, b);
+	wifitx(wifi, bss, b);
 }
 
 static void
@@ -210,6 +229,7 @@
 		wifi->status = Sassoc;
 		break;
 	default:
+		wn->aid = 0;
 		wifi->status = Sunassoc;
 		return;
 	}
@@ -216,7 +236,7 @@
 }
 
 static void
-recvbeacon(Wifi *wifi, Wnode *wn, uchar *d, int len)
+recvbeacon(Wifi *, Wnode *wn, uchar *d, int len)
 {
 	uchar *e, *x;
 	uchar t, m[256/8];
@@ -251,11 +271,6 @@
 			if(len != strlen(wn->ssid) || strncmp(wn->ssid, (char*)d, len) != 0){
 				strncpy(wn->ssid, (char*)d, len);
 				wn->ssid[len] = 0;
-				if(wifi->bss == nil && strcmp(wifi->essid, wn->ssid) == 0){
-					wifi->bss = wn;
-					wifi->status = Sconn;
-					sendauth(wifi, wn);
-				}
 			}
 			break;
 		case 3:	/* DSPARAMS */
@@ -289,8 +304,15 @@
 				continue;
 			b->rp += WIFIHDRSIZE;
 			recvbeacon(wifi, wn, b->rp, BLEN(b));
+			if(wifi->bss == nil && wifi->essid[0] != 0 && strcmp(wifi->essid, wn->ssid) == 0){
+				wifi->bss = wn;
+				wifi->status = Sconn;
+				sendauth(wifi, wn);
+			}
 			continue;
 		}
+		if(memcmp(w->a1, wifi->ether->ea, Eaddrlen))
+			continue;
 		if((wn = nodelookup(wifi, w->a3, 0)) == nil)
 			continue;
 		if(wn != wifi->bss)
@@ -306,7 +328,9 @@
 			sendassoc(wifi, wn);
 			break;
 		case 0xc0:	/* deauth */
+			wn->aid = 0;
 			wifi->status = Sunauth;
+			sendauth(wifi, wn);
 			break;
 		}
 	}
@@ -318,9 +342,11 @@
 {
 	Etherpkt e;
 	Wifipkt *w;
+	Wnode *bss;
 	SNAP *s;
 
-	if(BLEN(b) < ETHERHDRSIZE){
+	bss = wifi->bss;
+	if(bss == nil || BLEN(b) < ETHERHDRSIZE){
 		freeb(b);
 		return;
 	}
@@ -332,7 +358,7 @@
 	w = (Wifipkt*)b->rp;
 	w->fc[0] = 0x08;	/* data */
 	w->fc[1] = 0x01;	/* STA->AP */
-	memmove(w->a1, wifi->bss ? wifi->bss->bssid : wifi->ether->bcast, Eaddrlen);
+	memmove(w->a1, bss->bssid, Eaddrlen);
 	memmove(w->a2, e.s, Eaddrlen);
 	memmove(w->a3, e.d, Eaddrlen);
 
@@ -344,7 +370,7 @@
 	s->orgcode[2] = 0;
 	memmove(s->type, e.type, 2);
 
-	wifitx(wifi, b);
+	wifitx(wifi, bss, b);
 }
 
 static void
@@ -364,6 +390,7 @@
 Wifi*
 wifiattach(Ether *ether, void (*transmit)(Wifi*, Wnode*, Block*))
 {
+	char name[32];
 	Wifi *wifi;
 
 	wifi = malloc(sizeof(Wifi));
@@ -372,8 +399,10 @@
 	wifi->transmit = transmit;
 	wifi->status = Snone;
 
-	kproc("wifi", wifiproc, wifi);
-	kproc("wifo", wifoproc, wifi);
+	snprint(name, sizeof(name), "#l%dwifi", ether->ctlrno);
+	kproc(name, wifiproc, wifi);
+	snprint(name, sizeof(name), "#l%dwifo", ether->ctlrno);
+	kproc(name, wifoproc, wifi);
 
 	return wifi;
 }
@@ -392,13 +421,13 @@
 	cb = parsecmd(buf, n);
 	if(cb->f[0] && strcmp(cb->f[0], "essid") == 0){
 		if(cb->f[1] == nil){
-			/* TODO senddeauth(wifi); */
 			wifi->essid[0] = 0;
 			wifi->bss = nil;
+			wifi->status = Snone;
 		} else {
 			strncpy(wifi->essid, cb->f[1], 32);
 			wifi->essid[32] = 0;
-			for(wn=wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++)
+			for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++)
 				if(strcmp(wifi->essid, wn->ssid) == 0){
 					wifi->bss = wn;
 					wifi->status = Sconn;
@@ -425,10 +454,11 @@
 
 	p = seprint(p, e, "status: %s\n", wifi->status);
 	p = seprint(p, e, "essid: %s\n", wifi->essid);
-	p = seprint(p, e, "bssid: %E\n", wifi->bss ? wifi->bss->bssid : zeros);
+	wn = wifi->bss;
+	p = seprint(p, e, "bssid: %E\n", wn != nil ? wn->bssid : zeros);
 
 	now = MACHP(0)->ticks;
-	for(wn=wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
+	for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
 		if(wn->lastseen == 0)
 			continue;
 		p = seprint(p, e, "node: %E %.4x %d %ld %d %s\n",
--- a/sys/src/9/pc/wifi.h
+++ b/sys/src/9/pc/wifi.h
@@ -34,13 +34,13 @@
 
 	Queue	*iq;
 	char	*status;
+	Ref	txseq;
 	void	(*transmit)(Wifi*, Wnode*, Block*);
 
-	Wnode	node[16];
+	char	essid[32+2];
 	Wnode	*bss;
 
-	uint	txseq;
-	char	essid[32+2];
+	Wnode	node[32];
 };
 
 Wifi *wifiattach(Ether *ether, void (*transmit)(Wifi*, Wnode*, Block*));
--- a/sys/src/cmd/nusb/disk/disk.c
+++ b/sys/src/cmd/nusb/disk/disk.c
@@ -812,7 +812,7 @@
 		}
 		switch(lun->phase){
 		case Pcmd:
-			if(count != 6 && count != 10){
+			if(count != 6 && count != 10 && count != 12 && count != 16){
 				respond(req, "bad command length");
 				break;
 			}
--- a/sys/src/cmd/nusb/disk/ums.h
+++ b/sys/src/cmd/nusb/disk/ums.h
@@ -79,7 +79,7 @@
 	/* partitions */
 	Part part[Maxparts];
 
-	uchar 	rawcmd[10];
+	uchar 	rawcmd[16];
 	uchar	phase;
 	char	*inq;
 	Ums	*ums;
--