⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wavelan.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	Lucent Wavelan IEEE 802.11 pcmcia.	There is almost no documentation for the card.	the driver is done using both the FreeBSD, Linux and	original Plan 9 drivers as `documentation'.	Has been used with the card plugged in during all up time.	no cards removals/insertions yet.	For known BUGS see the comments below. Besides,	the driver keeps interrupts disabled for just too	long. When it gets robust, locks should be revisited.	BUGS: check endian, alignment and mem/io issues;	      multicast;	      receive watchdog interrupts.	TODO: automatic power management;	      improve locking. */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h"#include "../port/netif.h"#include "etherif.h"#include "wavelan.h"enum{	MSperTick=	50,	/* ms between ticks of kproc */};/* * When we're using a PCI device and memory-mapped I/O,  * the registers are spaced out as though each takes 32 bits, * even though they are only 16-bit registers.  Thus,  * ctlr->mmb[reg] is the right way to access register reg, * even though a priori you'd expect to use ctlr->mmb[reg/2]. */voidcsr_outs(Ctlr *ctlr, int reg, ushort arg){	if(ctlr->mmb)		ctlr->mmb[reg] = arg;	else		outs(ctlr->iob+reg, arg);}ushortcsr_ins(Ctlr *ctlr, int reg){	if(ctlr->mmb)		return ctlr->mmb[reg];	else		return ins(ctlr->iob+reg);}static voidcsr_ack(Ctlr *ctlr, int ev){	csr_outs(ctlr, WR_EvAck, ev);}static voidcsr_inss(Ctlr *ctlr, int reg, void *dat, int ndat){	ushort *rp, *wp;	if(ctlr->mmb){		rp = &ctlr->mmb[reg];		wp = dat;		while(ndat-- > 0)			*wp++ = *rp;	}else		inss(ctlr->iob+reg, dat, ndat);}static voidcsr_outss(Ctlr *ctlr, int reg, void *dat, int ndat){	ushort *rp, *wp;	if(ctlr->mmb){		rp = dat;		wp = &ctlr->mmb[reg];		while(ndat-- > 0)			*wp = *rp++;	}else		outss(ctlr->iob+reg, dat, ndat);}// w_... routines do not ilock the Ctlr and should// be called locked.voidw_intdis(Ctlr* ctlr){	csr_outs(ctlr, WR_IntEna, 0);	csr_ack(ctlr, 0xffff);}static voidw_intena(Ctlr* ctlr){	csr_outs(ctlr, WR_IntEna, WEvs);}intw_cmd(Ctlr *ctlr, ushort cmd, ushort arg){	int i, rc;	for(i=0; i<WTmOut; i++)		if((csr_ins(ctlr, WR_Cmd)&WCmdBusy) == 0)			break;	if(i==WTmOut){		print("#l%d: issuing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_Cmd));		return -1;	}	csr_outs(ctlr, WR_Parm0, arg);	csr_outs(ctlr, WR_Cmd, cmd);	for(i=0; i<WTmOut; i++)		if(csr_ins(ctlr, WR_EvSts)&WCmdEv)			break;	if(i==WTmOut){		/*		 * WCmdIni can take a really long time.		 */		enum { IniTmOut = 2000 };		for(i=0; i<IniTmOut; i++){			if(csr_ins(ctlr, WR_EvSts)&WCmdEv)				break;			microdelay(100);		}		if(i < IniTmOut)			if(0) print("#l%d: long cmd %.4ux %d\n", ctlr->ctlrno, cmd, i);		if(i == IniTmOut){			print("#l%d: execing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_EvSts));			return -1;		}	}	rc = csr_ins(ctlr, WR_Sts);	csr_ack(ctlr, WCmdEv);	if((rc&WCmdMsk) != (cmd&WCmdMsk)){		print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc);		return -1;	}	if(rc&WResSts){		/*		 * Don't print; this happens on every WCmdAccWr for some reason.		 */		if(0) print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc);		return -1;	}	return 0;}static intw_seek(Ctlr* ctlr, ushort id, ushort offset, int chan){	int i, rc;	static ushort sel[] = { WR_Sel0, WR_Sel1 };	static ushort off[] = { WR_Off0, WR_Off1 };	if(chan != 0 && chan != 1)		panic("wavelan: bad chan\n");	csr_outs(ctlr, sel[chan], id);	csr_outs(ctlr, off[chan], offset);	for (i=0; i<WTmOut; i++){		rc = csr_ins(ctlr, off[chan]);		if((rc & (WBusyOff|WErrOff)) == 0)			return 0;	}	return -1;}intw_inltv(Ctlr* ctlr, Wltv* ltv){	int len;	ushort code;	if(w_cmd(ctlr, WCmdAccRd, ltv->type)){		DEBUG("wavelan: access read failed\n");		return -1;	}	if(w_seek(ctlr,ltv->type,0,1)){		DEBUG("wavelan: seek failed\n");		return -1;	}	len = csr_ins(ctlr, WR_Data1);	if(len > ltv->len)		return -1;	ltv->len = len;	if((code=csr_ins(ctlr, WR_Data1)) != ltv->type){		USED(code);		DEBUG("wavelan: type %x != code %x\n",ltv->type,code);		return -1;	}	if(ltv->len > 0)		csr_inss(ctlr, WR_Data1, &ltv->val, ltv->len-1);	return 0;}static voidw_outltv(Ctlr* ctlr, Wltv* ltv){	if(w_seek(ctlr,ltv->type, 0, 1))		return;	csr_outss(ctlr, WR_Data1, ltv, ltv->len+1);	w_cmd(ctlr, WCmdAccWr, ltv->type);}voidltv_outs(Ctlr* ctlr, int type, ushort val){	Wltv ltv;	ltv.len = 2;	ltv.type = type;	ltv.val = val;	w_outltv(ctlr, &ltv);}intltv_ins(Ctlr* ctlr, int type){	Wltv ltv;	ltv.len = 2;	ltv.type = type;	ltv.val = 0;	if(w_inltv(ctlr, &ltv))		return -1;	return ltv.val;}static voidltv_outstr(Ctlr* ctlr, int type, char* val){	Wltv ltv;	int len;	len = strlen(val);	if(len > sizeof(ltv.s))		len = sizeof(ltv.s);	memset(&ltv, 0, sizeof(ltv));	ltv.len = (sizeof(ltv.type)+sizeof(ltv.slen)+sizeof(ltv.s))/2;	ltv.type = type;//	This should be ltv.slen = len; according to Axel Belinfante	ltv.slen = len;		strncpy(ltv.s, val, len);	w_outltv(ctlr, &ltv);}static char Unkname[] = "who knows";static char Nilname[] = "card does not tell";static char*ltv_inname(Ctlr* ctlr, int type){	static Wltv ltv;	int len;	memset(&ltv,0,sizeof(ltv));	ltv.len = WNameLen/2+2;	ltv.type = type;	if(w_inltv(ctlr, &ltv))		return Unkname;	len = ltv.slen;	if(len == 0 || ltv.s[0] == 0)		return Nilname;	if(len >= sizeof ltv.s)		len = sizeof ltv.s - 1;	ltv.s[len] = '\0';	return ltv.s;}static intw_read(Ctlr* ctlr, int type, int off, void* buf, ulong len){	if(w_seek(ctlr, type, off, 1)){		DEBUG("wavelan: w_read: seek failed");		return 0;	}	csr_inss(ctlr, WR_Data1, buf, len/2);	return len;}static intw_write(Ctlr* ctlr, int type, int off, void* buf, ulong len){	int tries;	for (tries=0; tries < WTmOut; tries++){		if(w_seek(ctlr, type, off, 0)){			DEBUG("wavelan: w_write: seek failed\n");			return 0;		}		csr_outss(ctlr, WR_Data0, buf, len/2);		csr_outs(ctlr, WR_Data0, 0xdead);		csr_outs(ctlr, WR_Data0, 0xbeef);		if(w_seek(ctlr, type, off + len, 0)){			DEBUG("wavelan: write seek failed\n");			return 0;		}		if(csr_ins(ctlr, WR_Data0) == 0xdead)		if(csr_ins(ctlr, WR_Data0) == 0xbeef)			return len;		DEBUG("wavelan: Hermes bug byte.\n");		return 0;	}	DEBUG("wavelan: tx timeout\n");	return 0;}static intw_alloc(Ctlr* ctlr, int len){	int rc;	int i,j;	if(w_cmd(ctlr, WCmdMalloc, len)==0)		for (i = 0; i<WTmOut; i++)			if(csr_ins(ctlr, WR_EvSts) & WAllocEv){				csr_ack(ctlr, WAllocEv);				rc=csr_ins(ctlr, WR_Alloc);				if(w_seek(ctlr, rc, 0, 0))					return -1;				len = len/2;				for (j=0; j<len; j++)					csr_outs(ctlr, WR_Data0, 0);				return rc;			}	return -1;}static intw_enable(Ether* ether){	Wltv ltv;	Ctlr* ctlr = (Ctlr*) ether->ctlr;	if(!ctlr)		return -1;	w_intdis(ctlr);	w_cmd(ctlr, WCmdDis, 0);	w_intdis(ctlr);	if(w_cmd(ctlr, WCmdIni, 0))		return -1;	w_intdis(ctlr);	ltv_outs(ctlr, WTyp_Tick, 8);	ltv_outs(ctlr, WTyp_MaxLen, ctlr->maxlen);	ltv_outs(ctlr, WTyp_Ptype, ctlr->ptype); 	ltv_outs(ctlr, WTyp_CreateIBSS, ctlr->createibss);	ltv_outs(ctlr, WTyp_RtsThres, ctlr->rtsthres);	ltv_outs(ctlr, WTyp_TxRate, ctlr->txrate);	ltv_outs(ctlr, WTyp_ApDens, ctlr->apdensity);	ltv_outs(ctlr, WTyp_PMWait, ctlr->pmwait);	ltv_outs(ctlr, WTyp_PM, ctlr->pmena);	if(*ctlr->netname)		ltv_outstr(ctlr, WTyp_NetName, ctlr->netname);	if(*ctlr->wantname)		ltv_outstr(ctlr, WTyp_WantName, ctlr->wantname);	ltv_outs(ctlr, WTyp_Chan, ctlr->chan);	if(*ctlr->nodename)		ltv_outstr(ctlr, WTyp_NodeName, ctlr->nodename);	ltv.len = 4;	ltv.type = WTyp_Mac;	memmove(ltv.addr, ether->ea, Eaddrlen);	w_outltv(ctlr, &ltv);	ltv_outs(ctlr, WTyp_Prom, (ether->prom?1:0));	if(ctlr->hascrypt && ctlr->crypt){		ltv_outs(ctlr, WTyp_Crypt, ctlr->crypt);		ltv_outs(ctlr, WTyp_TxKey, ctlr->txkey);		w_outltv(ctlr, &ctlr->keys);		ltv_outs(ctlr, WTyp_XClear, ctlr->xclear);	}	// BUG: set multicast addresses	if(w_cmd(ctlr, WCmdEna, 0)){		DEBUG("wavelan: Enable failed");		return -1;	}	ctlr->txdid = w_alloc(ctlr, 1518 + sizeof(WFrame) + 8);	ctlr->txmid = w_alloc(ctlr, 1518 + sizeof(WFrame) + 8);	if(ctlr->txdid == -1 || ctlr->txmid == -1)		DEBUG("wavelan: alloc failed");	ctlr->txbusy = 0;	w_intena(ctlr);	return 0;}static voidw_rxdone(Ether* ether){	Ctlr* ctlr = (Ctlr*) ether->ctlr;	int len, sp;	WFrame f;	Block* bp=0;	Etherpkt* ep;	sp = csr_ins(ctlr, WR_RXId);	len = w_read(ctlr, sp, 0, &f, sizeof(f));	if(len == 0){		DEBUG("wavelan: read frame error\n");		goto rxerror;	}	if(f.sts&WF_Err){		goto rxerror;	}	switch(f.sts){	case WF_1042:	case WF_Tunnel:	case WF_WMP:		len = f.dlen + WSnapHdrLen;		bp = iallocb(ETHERHDRSIZE + len + 2);		if(!bp)			goto rxerror;		ep = (Etherpkt*) bp->wp;		memmove(ep->d, f.addr1, Eaddrlen);		memmove(ep->s, f.addr2, Eaddrlen);		memmove(ep->type,&f.type,2);		bp->wp += ETHERHDRSIZE;		if(w_read(ctlr, sp, WF_802_11_Off, bp->wp, len+2) == 0){			DEBUG("wavelan: read 802.11 error\n");			goto rxerror;		}		bp->wp = bp->rp+(ETHERHDRSIZE+f.dlen);		break;	default:		len = ETHERHDRSIZE + f.dlen + 2;		bp = iallocb(len);		if(!bp)			goto rxerror;		if(w_read(ctlr, sp, WF_802_3_Off, bp->wp, len) == 0){			DEBUG("wavelan: read 800.3 error\n");			goto rxerror;		}		bp->wp += len;	}	ctlr->nrx++;	etheriq(ether,bp,1);	ctlr->signal = ((ctlr->signal*15)+((f.qinfo>>8) & 0xFF))/16;	ctlr->noise = ((ctlr->noise*15)+(f.qinfo & 0xFF))/16;	return;rxerror:	freeb(bp);	ctlr->nrxerr++;}static voidw_txstart(Ether* ether){	Etherpkt *pkt;	Ctlr *ctlr;	Block *bp;	int len, off;	if((ctlr = ether->ctlr) == nil || (ctlr->state & (Attached|Power)) != (Attached|Power) || ctlr->txbusy)		return;	if((bp = qget(ether->oq)) == nil)		return;	pkt = (Etherpkt*)bp->rp;	//	// If the packet header type field is > 1500 it is an IP or	// ARP datagram, otherwise it is an 802.3 packet. See RFC1042.	//	memset(&ctlr->txf, 0, sizeof(ctlr->txf));	if(((pkt->type[0]<<8)|pkt->type[1]) > 1500){		ctlr->txf.framectl = WF_Data;		memmove(ctlr->txf.addr1, pkt->d, Eaddrlen);		memmove(ctlr->txf.addr2, pkt->s, Eaddrlen);		memmove(ctlr->txf.dstaddr, pkt->d, Eaddrlen);		memmove(ctlr->txf.srcaddr, pkt->s, Eaddrlen);		memmove(&ctlr->txf.type, pkt->type, 2);		bp->rp += ETHERHDRSIZE;		len = BLEN(bp);		off = WF_802_11_Off;		ctlr->txf.dlen = len+ETHERHDRSIZE-WSnapHdrLen;		hnputs((uchar*)&ctlr->txf.dat[0], WSnap0);		hnputs((uchar*)&ctlr->txf.dat[1], WSnap1);		hnputs((uchar*)&ctlr->txf.len, len+ETHERHDRSIZE-WSnapHdrLen);	}	else{		len = BLEN(bp);		off = WF_802_3_Off;		ctlr->txf.dlen = len;	}	w_write(ctlr, ctlr->txdid, 0, &ctlr->txf, sizeof(ctlr->txf));	w_write(ctlr, ctlr->txdid, off, bp->rp, len+2);	if(w_cmd(ctlr, WCmdReclaim|WCmdTx, ctlr->txdid)){		DEBUG("wavelan: transmit failed\n");		ctlr->ntxerr++;	}	else{		ctlr->txbusy = 1;		ctlr->txtmout = 2;	}	freeb(bp);}static voidw_txdone(Ctlr* ctlr, int sts){	ctlr->txbusy = 0;	ctlr->txtmout = 0;	if(sts & WTxErrEv)		ctlr->ntxerr++;	else		ctlr->ntx++;}/* save the stats info in the ctlr struct */static voidw_stats(Ctlr* ctlr, int len){	int i, rc;	ulong* p = (ulong*)&ctlr->WStats;	ulong* pend = (ulong*)&ctlr->end;	for (i = 0; i < len && p < pend; i++){		rc = csr_ins(ctlr, WR_Data1);		if(rc > 0xf000)			rc = ~rc & 0xffff;		p[i] += rc;	}}/* send the base station scan info to any readers */static voidw_scaninfo(Ether* ether, Ctlr *ctlr, int len){	int i, j;	Netfile **ep, *f, **fp;	Block *bp;	WScan *wsp;	ushort *scanbuf;	scanbuf = malloc(len*2);	if(scanbuf == nil)		return;		for (i = 0; i < len ; i++)		scanbuf[i] = csr_ins(ctlr, WR_Data1);	/* calculate number of samples */	len /= 25;	if(len == 0)		goto out;	i = ether->scan;	ep = &ether->f[Ntypes];	for(fp = ether->f; fp < ep && i > 0; fp++){		f = *fp;		if(f == nil || f->scan == 0)			continue;		bp = iallocb(100*len);		if(bp == nil)			break;		for(j = 0; j < len; j++){			wsp = (WScan*)(&scanbuf[j*25]);			if(wsp->ssid_len > 32)				wsp->ssid_len = 32;			bp->wp = (uchar*)seprint((char*)bp->wp, (char*)bp->lim,				"ssid=%.*s;bssid=%E;signal=%d;noise=%d;chan=%d%s\n",				wsp->ssid_len, wsp->ssid, wsp->bssid, wsp->signal,				wsp->noise, wsp->chan, (wsp->capinfo&(1<<4))?";wep":"");		}		qpass(f->in, bp);		i--;	}out:	free(scanbuf);}static intw_info(Ether *ether, Ctlr* ctlr){	int sp;	Wltv ltv;	sp = csr_ins(ctlr, WR_InfoId);	ltv.len = ltv.type = 0;	w_read(ctlr, sp, 0, &ltv, 4);	ltv.len--;	switch(ltv.type){	case WTyp_Stats:		w_stats(ctlr, ltv.len);		return 0;	case WTyp_Scan:		w_scaninfo(ether, ctlr, ltv.len);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -