plan 9 kernel history: overview | file list | diff list

2000/0401/alphapc/devether.c (diff list | history)

1999/0415/sys/src/9/alphapc/devether.c:356,3621999/0515/sys/src/9/alphapc/devether.c:356,362 (short | long)
1999/0415    
				ether->irq = 9; 
			intrenable(VectorPCI+ether->irq, ether->interrupt, ether, ether->tbdf); 
 
			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d", 
1999/0515    
			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %ld", 
1999/0415    
				ctlrno, ether->type, ether->mbps, ether->port, ether->irq); 
			if(ether->mem) 
				i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem)); 
1999/0515/sys/src/9/alphapc/devether.c:130,1402000/0401/sys/src/9/alphapc/devether.c:130,140 (short | long)
1999/0415    
} 
 
Block* 
etheriq(Ether* ether, Block* bp, int freebp) 
2000/0401    
etheriq(Ether* ether, Block* bp, int fromwire) 
1999/0415    
{ 
	Etherpkt *pkt; 
	ushort type; 
	int len; 
2000/0401    
	int len, multi, tome, fromme; 
1999/0415    
	Netfile **ep, *f, **fp, *fx; 
	Block *xbp; 
 
1999/0515/sys/src/9/alphapc/devether.c:146,1552000/0401/sys/src/9/alphapc/devether.c:146,156
1999/0415    
	fx = 0; 
	ep = ðer->f[Ntypes]; 
 
2000/0401    
	multi = pkt->d[0] & 1; 
1999/0415    
	/* check for valid multcast addresses */ 
	if((pkt->d[0] & 1) && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){ 
2000/0401    
	if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){ 
1999/0415    
		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){ 
			if(freebp){ 
2000/0401    
			if(fromwire){ 
1999/0415    
				freeb(bp); 
				bp = 0; 
			} 
1999/0515/sys/src/9/alphapc/devether.c:157,1722000/0401/sys/src/9/alphapc/devether.c:158,182
1999/0415    
		} 
	} 
 
2000/0401    
	/* is it for me? */ 
	tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0; 
	fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0; 
 
1999/0415    
	/* 
	 * Multiplex the packet to all the connections which want it. 
	 * If the packet is not to be used subsequently (freebp != 0), 
2000/0401    
	 * If the packet is not to be used subsequently (fromwire != 0), 
1999/0415    
	 * attempt to simply pass it into one of the connections, thereby 
	 * saving a copy of the data (usual case hopefully). 
	 */ 
	for(fp = ether->f; fp < ep; fp++){ 
		if((f = *fp) && (f->type == type || f->type < 0)){ 
			if(f->type > -2){ 
				if(freebp && fx == 0) 
2000/0401    
		if(f = *fp) 
		if(f->type == type || f->type < 0) 
		if(tome || multi || f->prom){ 
			/* Don't want to hear bridged packets */ 
			if(f->bridge && !fromwire && !fromme) 
				continue; 
			if(!f->headersonly){ 
				if(fromwire && fx == 0) 
1999/0415    
					fx = f; 
				else if(xbp = iallocb(len)){ 
					memmove(xbp->wp, pkt, len); 
1999/0515/sys/src/9/alphapc/devether.c:182,1912000/0401/sys/src/9/alphapc/devether.c:192,202
1999/0415    
	} 
 
	if(fx){ 
		qpass(fx->in, bp); 
2000/0401    
		if(qpass(fx->in, bp) < 0) 
			ether->soverflows++; 
1999/0415    
		return 0; 
	} 
	if(freebp){ 
2000/0401    
	if(fromwire){ 
1999/0415    
		freeb(bp); 
		return 0; 
	} 
1999/0515/sys/src/9/alphapc/devether.c:207,2192000/0401/sys/src/9/alphapc/devether.c:218,232
1999/0415    
	 * in promiscuous mode. 
	 * If it's a loopback packet indicate to etheriq that the data isn't 
	 * needed and return, etheriq will pass-on or free the block. 
2000/0401    
	 * To enable bridging to work, only packets that were originated 
	 * by this interface are fed back. 
1999/0415    
	 */ 
	pkt = (Etherpkt*)bp->rp; 
	len = BLEN(bp); 
	loopback = (memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0); 
2000/0401    
	loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0; 
1999/0415    
	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){ 
		s = splhi(); 
		etheriq(ether, bp, loopback); 
2000/0401    
		etheriq(ether, bp, 0); 
1999/0415    
		splx(s); 
	} 
 
1999/0515/sys/src/9/alphapc/devether.c:220,2262000/0401/sys/src/9/alphapc/devether.c:233,240
1999/0415    
	if(!loopback){ 
		qbwrite(ether->oq, bp); 
		ether->transmit(ether); 
	} 
2000/0401    
	} else 
		freeb(bp); 
1999/0415    
 
	return len; 
} 
1999/0515/sys/src/9/alphapc/devether.c:354,3622000/0401/sys/src/9/alphapc/devether.c:368,377
1999/0415    
			 */ 
			if(ether->irq == 2) 
				ether->irq = 9; 
			intrenable(VectorPCI+ether->irq, ether->interrupt, ether, ether->tbdf); 
2000/0401    
			snprint(name, sizeof(name), "ether%d", ctlrno); 
			intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name); 
1999/0415    
 
1999/0515    
			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %ld", 
2000/0401    
			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %lud", 
1999/0415    
				ctlrno, ether->type, ether->mbps, ether->port, ether->irq); 
			if(ether->mem) 
				i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem)); 
1999/0515/sys/src/9/alphapc/devether.c:368,3742000/0401/sys/src/9/alphapc/devether.c:383,388
1999/0415    
			sprint(buf+i, "\n"); 
			print(buf); 
 
			snprint(name, sizeof(name), "ether%d", ctlrno); 
			if(ether->mbps == 100){ 
				netifinit(ether, name, Ntypes, 256*1024); 
				if(ether->oq == 0) 
2000/0401/sys/src/9/alphapc/devether.c:110,1212000/0713/sys/src/9/alphapc/devether.c:110,121 (short | long)
1999/0415    
 
	if(qwindow(f->in) <= 0) 
		return; 
	if(len > 64) 
		n = 64; 
2000/0713    
	if(len > 58) 
		n = 58; 
1999/0415    
	else 
		n = len; 
	bp = iallocb(n); 
	if(bp == 0) 
2000/0713    
	bp = iallocb(64); 
	if(bp == nil) 
1999/0415    
		return; 
	memmove(bp->wp, pkt->d, n); 
	i = TK2MS(MACHP(0)->ticks); 
2000/0713/sys/src/9/alphapc/devether.c:366,3722001/0228/sys/src/9/alphapc/devether.c:366,372 (short | long)
1999/0415    
			 * controllers together. A device set to IRQ2 will appear on 
			 * the second interrupt controller as IRQ9. 
			 */ 
			if(ether->irq == 2) 
2001/0228    
			if(ether->irq == 2 && BUSTYPE(ether->tbdf) != BusPCI) 
1999/0415    
				ether->irq = 9; 
2000/0401    
			snprint(name, sizeof(name), "ether%d", ctlrno); 
			intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name); 
2001/0228/sys/src/9/alphapc/devether.c:35,502001/0727/sys/src/9/alphapc/devether.c:35,50 (short | long)
1999/0415    
	return chan; 
} 
 
static int 
etherwalk(Chan* chan, char* name) 
2001/0727    
static Walkqid* 
etherwalk(Chan* chan, Chan* nchan, char** name, int nname) 
1999/0415    
{ 
	return netifwalk(etherxx[chan->dev], chan, name); 
2001/0727    
	return netifwalk(etherxx[chan->dev], chan, nchan, name, nname); 
1999/0415    
} 
 
static void 
etherstat(Chan* chan, char* dp) 
2001/0727    
static int 
etherstat(Chan* chan, uchar* dp, int n) 
1999/0415    
{ 
	netifstat(etherxx[chan->dev], chan, dp); 
2001/0727    
	return netifstat(etherxx[chan->dev], chan, dp, n); 
1999/0415    
} 
 
static Chan* 
2001/0228/sys/src/9/alphapc/devether.c:71,772001/0727/sys/src/9/alphapc/devether.c:71,77
1999/0415    
	ulong offset = off; 
 
	ether = etherxx[chan->dev]; 
	if((chan->qid.path & CHDIR) == 0 && ether->ifstat){ 
2001/0727    
	if((chan->qid.type & QTDIR) == 0 && ether->ifstat){ 
1999/0415    
		/* 
		 * With some controllers it is necessary to reach 
		 * into the chip to extract statistics. 
2001/0228/sys/src/9/alphapc/devether.c:96,1052001/0727/sys/src/9/alphapc/devether.c:96,105
1999/0415    
{ 
} 
 
static void 
etherwstat(Chan* chan, char* dp) 
2001/0727    
static int 
etherwstat(Chan* chan, uchar* dp, int n) 
1999/0415    
{ 
	netifwstat(etherxx[chan->dev], chan, dp); 
2001/0727    
	return netifwstat(etherxx[chan->dev], chan, dp, n); 
1999/0415    
} 
 
static void 
2001/0228/sys/src/9/alphapc/devether.c:338,3442001/0727/sys/src/9/alphapc/devether.c:338,344
1999/0415    
{ 
	Ether *ether; 
	int i, n, ctlrno; 
	char name[NAMELEN], buf[128]; 
2001/0727    
	char name[32], buf[128]; 
1999/0415    
 
	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){ 
		if(ether == 0) 
2001/0228/sys/src/9/alphapc/devether.c:347,3522001/0727/sys/src/9/alphapc/devether.c:347,354
1999/0415    
		ether->ctlrno = ctlrno; 
		ether->tbdf = BUSUNKNOWN; 
		ether->mbps = 10; 
2001/0727    
		ether->minmtu = ETHERMINTU; 
		ether->maxmtu = ETHERMAXTU; 
1999/0415    
		if(isaconfig("ether", ctlrno, ether) == 0) 
			continue; 
		for(n = 0; cards[n].type; n++){ 
2001/0228/sys/src/9/alphapc/devether.c:435,4412001/0727/sys/src/9/alphapc/devether.c:437,442
1999/0415    
	etherreset, 
	devinit, 
	etherattach, 
	devclone, 
	etherwalk, 
	etherstat, 
	etheropen, 
2001/0727/sys/src/9/alphapc/devether.c:91,1012001/1204/sys/src/9/alphapc/devether.c:91,96 (short | long)
1999/0415    
	return netifbread(etherxx[chan->dev], chan, n, offset); 
} 
 
static void 
etherremove(Chan*) 
{ 
} 
                 
2001/0727    
static int 
etherwstat(Chan* chan, uchar* dp, int n) 
1999/0415    
{ 
2001/0727/sys/src/9/alphapc/devether.c:446,4512001/1204/sys/src/9/alphapc/devether.c:441,446
1999/0415    
	etherbread, 
	etherwrite, 
	etherbwrite, 
	etherremove, 
2001/1204    
	devremove, 
1999/0415    
	etherwstat, 
}; 
2001/1204/sys/src/9/alphapc/devether.c:431,4362002/0109/sys/src/9/alphapc/devether.c:431,437 (short | long)
1999/0415    
 
	etherreset, 
	devinit, 
2002/0109    
	devshutdown, 
1999/0415    
	etherattach, 
	etherwalk, 
	etherstat, 
2002/0109/sys/src/9/alphapc/devether.c:383,3942002/0711/sys/src/9/alphapc/devether.c:383,394 (short | long)
1999/0415    
			if(ether->mbps == 100){ 
				netifinit(ether, name, Ntypes, 256*1024); 
				if(ether->oq == 0) 
					ether->oq = qopen(256*1024, 1, 0, 0); 
2002/0711    
					ether->oq = qopen(256*1024, Qmsg, 0, 0); 
1999/0415    
			} 
			else{ 
				netifinit(ether, name, Ntypes, 65*1024); 
				if(ether->oq == 0) 
					ether->oq = qopen(65*1024, 1, 0, 0); 
2002/0711    
					ether->oq = qopen(65*1024, Qmsg, 0, 0); 
1999/0415    
			} 
			if(ether->oq == 0) 
				panic("etherreset %s", name); 
2002/0711/sys/src/9/alphapc/devether.c:241,2482002/0712/sys/src/9/alphapc/devether.c:241,255 (short | long)
1999/0415    
	Block *bp; 
 
	ether = etherxx[chan->dev]; 
	if(NETTYPE(chan->qid.path) != Ndataqid) 
2002/0712    
	if(NETTYPE(chan->qid.path) != Ndataqid){ 
 
		if(n == sizeof("nonblocking")-1 && strncmp((char*)buf, "nonblocking", n) == 0){ 
			qnoblock(ether->oq, 1); 
			return n; 
		} 
 
1999/0415    
		return netifwrite(ether, chan, buf, n); 
2002/0712    
	} 
1999/0415    
 
	if(n > ETHERMAXTU) 
		error(Etoobig); 
2002/0712/sys/src/9/alphapc/devether.c:10,162002/1130/sys/src/9/alphapc/devether.c:10,16 (short | long)
1999/0415    
 
#include "etherif.h" 
 
static Ether *etherxx[MaxEther]; 
2002/1130    
static volatile Ether *etherxx[MaxEther]; 
1999/0415    
 
Chan* 
etherattach(char* spec) 
2002/0712/sys/src/9/alphapc/devether.c:176,1822002/1130/sys/src/9/alphapc/devether.c:176,183
1999/0415    
				else if(xbp = iallocb(len)){ 
					memmove(xbp->wp, pkt, len); 
					xbp->wp += len; 
					qpass(f->in, xbp); 
2002/1130    
					if(qpass(f->in, xbp) < 0) 
						ether->soverflows++; 
1999/0415    
				} 
				else 
					ether->soverflows++; 
2002/0712/sys/src/9/alphapc/devether.c:239,2592002/1130/sys/src/9/alphapc/devether.c:240,265
1999/0415    
{ 
	Ether *ether; 
	Block *bp; 
2002/1130    
	int nn; 
1999/0415    
 
	ether = etherxx[chan->dev]; 
2002/0712    
	if(NETTYPE(chan->qid.path) != Ndataqid){ 
                 
2002/1130    
	if(NETTYPE(chan->qid.path) != Ndataqid) { 
		nn = netifwrite(ether, chan, buf, n); 
		if(nn >= 0) 
			return nn; 
2002/0712    
		if(n == sizeof("nonblocking")-1 && strncmp((char*)buf, "nonblocking", n) == 0){ 
			qnoblock(ether->oq, 1); 
			return n; 
		} 
2002/1130    
		if(ether->ctl!=nil) 
			return ether->ctl(ether,buf,n); 
2002/0712    
 
1999/0415    
		return netifwrite(ether, chan, buf, n); 
2002/1130    
		error(Ebadctl); 
2002/0712    
	} 
1999/0415    
 
	if(n > ETHERMAXTU) 
2002/1130    
	if(n > ether->maxmtu) 
1999/0415    
		error(Etoobig); 
	if(n < ETHERMINTU) 
2002/1130    
	if(n < ether->minmtu) 
1999/0415    
		error(Etoosmall); 
 
	bp = allocb(n); 
2002/0712/sys/src/9/alphapc/devether.c:276,2932002/1130/sys/src/9/alphapc/devether.c:282,304
1999/0415    
	long n; 
 
	n = BLEN(bp); 
	ether = etherxx[chan->dev]; 
	if(NETTYPE(chan->qid.path) != Ndataqid){ 
		n = netifwrite(ether, chan, bp->rp, n); 
2002/1130    
		if(waserror()) { 
			freeb(bp); 
			nexterror(); 
		} 
		n = etherwrite(chan, bp->rp, n, 0); 
		poperror(); 
1999/0415    
		freeb(bp); 
		return n; 
	} 
2002/1130    
	ether = etherxx[chan->dev]; 
1999/0415    
 
	if(n > ETHERMAXTU){ 
2002/1130    
	if(n > ether->maxmtu){ 
1999/0415    
		freeb(bp); 
		error(Ebadarg); 
2002/1130    
		error(Etoobig); 
1999/0415    
	} 
	if(n < ETHERMINTU){ 
2002/1130    
	if(n < ether->minmtu){ 
1999/0415    
		freeb(bp); 
		error(Etoosmall); 
	} 
2002/0712/sys/src/9/alphapc/devether.c:320,3262002/1130/sys/src/9/alphapc/devether.c:331,337
1999/0415    
	int i; 
 
	p = from; 
	for(i = 0; i < 6; i++){ 
2002/1130    
	for(i = 0; i < Eaddrlen; i++){ 
1999/0415    
		if(*p == 0) 
			return -1; 
		nip[0] = *p++; 
2002/0712/sys/src/9/alphapc/devether.c:340,3462002/1130/sys/src/9/alphapc/devether.c:351,357
1999/0415    
{ 
	Ether *ether; 
	int i, n, ctlrno; 
2001/0727    
	char name[32], buf[128]; 
2002/1130    
	char name[32], buf[256]; 
1999/0415    
 
	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){ 
		if(ether == 0) 
2002/0712/sys/src/9/alphapc/devether.c:359,3672002/1130/sys/src/9/alphapc/devether.c:370,378
1999/0415    
			for(i = 0; i < ether->nopt; i++){ 
				if(strncmp(ether->opt[i], "ea=", 3)) 
					continue; 
				if(parseether(ether->ea, ðer->opt[i][3]) == -1) 
2002/1130    
				if(parseether(ether->ea, ðer->opt[i][3])) 
1999/0415    
					memset(ether->ea, 0, Eaddrlen); 
			}	 
2002/1130    
			} 
1999/0415    
			if(cards[n].reset(ether)) 
				break; 
 
2002/0712/sys/src/9/alphapc/devether.c:373,3822002/1130/sys/src/9/alphapc/devether.c:384,400
2001/0228    
			if(ether->irq == 2 && BUSTYPE(ether->tbdf) != BusPCI) 
1999/0415    
				ether->irq = 9; 
2000/0401    
			snprint(name, sizeof(name), "ether%d", ctlrno); 
			intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name); 
2002/1130    
			/* 
			 * If ether->irq is 0, it is a hack to indicate no 
			 * interrupt used by ethersink. 
			 */ 
			if(ether->irq > 0) 
				intrenable(ether->irq, ether->interrupt, 
					ether, ether->tbdf, name); 
1999/0415    
 
2000/0401    
			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %lud", 
1999/0415    
				ctlrno, ether->type, ether->mbps, ether->port, ether->irq); 
2002/1130    
			i = sprint(buf, "#l%d (%s): %s: %dMbps port 0x%luX irq %lud", 
				ctlrno, name, ether->type, ether->mbps, 
				ether->port, ether->irq); 
1999/0415    
			if(ether->mem) 
				i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem)); 
			if(ether->size) 
2002/0712/sys/src/9/alphapc/devether.c:411,4162002/1130/sys/src/9/alphapc/devether.c:429,454
1999/0415    
	if(ether) 
		free(ether); 
} 
2002/1130    
 
/* imported from ../pc; not ready for use yet */ 
static void 
ethershutdown(void) 
{ 
	Ether *ether; 
	int i; 
 
	for(i = 0; i < MaxEther; i++){ 
		ether = etherxx[i]; 
		if(ether == nil) 
			continue; 
		if(ether->shutdown == nil) { 
			print("#l%d: no shutdown fuction\n", i); 
			continue; 
		} 
		(*ether->shutdown)(ether); 
	} 
} 
 
1999/0415    
 
#define POLY 0xedb88320 
 
2002/1130/sys/src/9/alphapc/devether.c:1,4922003/0301/sys/src/9/alphapc/devether.c:1 (short | long)
1999/0415    
#include "u.h" 
#include "../port/lib.h" 
#include "mem.h" 
#include "dat.h" 
#include "fns.h" 
#include "io.h" 
#include "ureg.h" 
#include "../port/error.h" 
#include "../port/netif.h" 
                 
#include "etherif.h" 
                 
2002/1130    
static volatile Ether *etherxx[MaxEther]; 
1999/0415    
                 
Chan* 
etherattach(char* spec) 
{ 
	ulong ctlrno; 
	char *p; 
	Chan *chan; 
                 
	ctlrno = 0; 
	if(spec && *spec){ 
		ctlrno = strtoul(spec, &p, 0); 
		if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther)) 
			error(Ebadarg); 
	} 
	if(etherxx[ctlrno] == 0) 
		error(Enodev); 
                 
	chan = devattach('l', spec); 
	chan->dev = ctlrno; 
	if(etherxx[ctlrno]->attach) 
		etherxx[ctlrno]->attach(etherxx[ctlrno]); 
	return chan; 
} 
                 
2001/0727    
static Walkqid* 
etherwalk(Chan* chan, Chan* nchan, char** name, int nname) 
1999/0415    
{ 
2001/0727    
	return netifwalk(etherxx[chan->dev], chan, nchan, name, nname); 
1999/0415    
} 
                 
2001/0727    
static int 
etherstat(Chan* chan, uchar* dp, int n) 
1999/0415    
{ 
2001/0727    
	return netifstat(etherxx[chan->dev], chan, dp, n); 
1999/0415    
} 
                 
static Chan* 
etheropen(Chan* chan, int omode) 
{ 
	return netifopen(etherxx[chan->dev], chan, omode); 
} 
                 
static void 
ethercreate(Chan*, char*, int, ulong) 
{ 
} 
                 
static void 
etherclose(Chan* chan) 
{ 
	netifclose(etherxx[chan->dev], chan); 
} 
                 
static long 
etherread(Chan* chan, void* buf, long n, vlong off) 
{ 
	Ether *ether; 
	ulong offset = off; 
                 
	ether = etherxx[chan->dev]; 
2001/0727    
	if((chan->qid.type & QTDIR) == 0 && ether->ifstat){ 
1999/0415    
		/* 
		 * With some controllers it is necessary to reach 
		 * into the chip to extract statistics. 
		 */ 
		if(NETTYPE(chan->qid.path) == Nifstatqid) 
			return ether->ifstat(ether, buf, n, offset); 
		else if(NETTYPE(chan->qid.path) == Nstatqid) 
			ether->ifstat(ether, buf, 0, offset); 
	} 
                 
	return netifread(ether, chan, buf, n, offset); 
} 
                 
static Block* 
etherbread(Chan* chan, long n, ulong offset) 
{ 
	return netifbread(etherxx[chan->dev], chan, n, offset); 
} 
                 
2001/0727    
static int 
etherwstat(Chan* chan, uchar* dp, int n) 
1999/0415    
{ 
2001/0727    
	return netifwstat(etherxx[chan->dev], chan, dp, n); 
1999/0415    
} 
                 
static void 
etherrtrace(Netfile* f, Etherpkt* pkt, int len) 
{ 
	int i, n; 
	Block *bp; 
                 
	if(qwindow(f->in) <= 0) 
		return; 
2000/0713    
	if(len > 58) 
		n = 58; 
1999/0415    
	else 
		n = len; 
2000/0713    
	bp = iallocb(64); 
	if(bp == nil) 
1999/0415    
		return; 
	memmove(bp->wp, pkt->d, n); 
	i = TK2MS(MACHP(0)->ticks); 
	bp->wp[58] = len>>8; 
	bp->wp[59] = len; 
	bp->wp[60] = i>>24; 
	bp->wp[61] = i>>16; 
	bp->wp[62] = i>>8; 
	bp->wp[63] = i; 
	bp->wp += 64; 
	qpass(f->in, bp); 
} 
                 
Block* 
2000/0401    
etheriq(Ether* ether, Block* bp, int fromwire) 
1999/0415    
{ 
	Etherpkt *pkt; 
	ushort type; 
2000/0401    
	int len, multi, tome, fromme; 
1999/0415    
	Netfile **ep, *f, **fp, *fx; 
	Block *xbp; 
                 
	ether->inpackets++; 
                 
	pkt = (Etherpkt*)bp->rp; 
	len = BLEN(bp); 
	type = (pkt->type[0]<<8)|pkt->type[1]; 
	fx = 0; 
	ep = ðer->f[Ntypes]; 
                 
2000/0401    
	multi = pkt->d[0] & 1; 
1999/0415    
	/* check for valid multcast addresses */ 
2000/0401    
	if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){ 
1999/0415    
		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){ 
2000/0401    
			if(fromwire){ 
1999/0415    
				freeb(bp); 
				bp = 0; 
			} 
			return bp; 
		} 
	} 
                 
2000/0401    
	/* is it for me? */ 
	tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0; 
	fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0; 
                 
1999/0415    
	/* 
	 * Multiplex the packet to all the connections which want it. 
2000/0401    
	 * If the packet is not to be used subsequently (fromwire != 0), 
1999/0415    
	 * attempt to simply pass it into one of the connections, thereby 
	 * saving a copy of the data (usual case hopefully). 
	 */ 
	for(fp = ether->f; fp < ep; fp++){ 
2000/0401    
		if(f = *fp) 
		if(f->type == type || f->type < 0) 
		if(tome || multi || f->prom){ 
			/* Don't want to hear bridged packets */ 
			if(f->bridge && !fromwire && !fromme) 
				continue; 
			if(!f->headersonly){ 
				if(fromwire && fx == 0) 
1999/0415    
					fx = f; 
				else if(xbp = iallocb(len)){ 
					memmove(xbp->wp, pkt, len); 
					xbp->wp += len; 
2002/1130    
					if(qpass(f->in, xbp) < 0) 
						ether->soverflows++; 
1999/0415    
				} 
				else 
					ether->soverflows++; 
			} 
			else 
				etherrtrace(f, pkt, len); 
		} 
	} 
                 
	if(fx){ 
2000/0401    
		if(qpass(fx->in, bp) < 0) 
			ether->soverflows++; 
1999/0415    
		return 0; 
	} 
2000/0401    
	if(fromwire){ 
1999/0415    
		freeb(bp); 
		return 0; 
	} 
                 
	return bp; 
} 
                 
static int 
etheroq(Ether* ether, Block* bp) 
{ 
	int len, loopback, s; 
	Etherpkt *pkt; 
                 
	ether->outpackets++; 
                 
	/* 
	 * Check if the packet has to be placed back onto the input queue, 
	 * i.e. if it's a loopback or broadcast packet or the interface is 
	 * in promiscuous mode. 
	 * If it's a loopback packet indicate to etheriq that the data isn't 
	 * needed and return, etheriq will pass-on or free the block. 
2000/0401    
	 * To enable bridging to work, only packets that were originated 
	 * by this interface are fed back. 
1999/0415    
	 */ 
	pkt = (Etherpkt*)bp->rp; 
	len = BLEN(bp); 
2000/0401    
	loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0; 
1999/0415    
	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){ 
		s = splhi(); 
2000/0401    
		etheriq(ether, bp, 0); 
1999/0415    
		splx(s); 
	} 
                 
	if(!loopback){ 
		qbwrite(ether->oq, bp); 
		ether->transmit(ether); 
2000/0401    
	} else 
		freeb(bp); 
1999/0415    
                 
	return len; 
} 
                 
static long 
etherwrite(Chan* chan, void* buf, long n, vlong) 
{ 
	Ether *ether; 
	Block *bp; 
2002/1130    
	int nn; 
1999/0415    
                 
	ether = etherxx[chan->dev]; 
2002/1130    
	if(NETTYPE(chan->qid.path) != Ndataqid) { 
		nn = netifwrite(ether, chan, buf, n); 
		if(nn >= 0) 
			return nn; 
2002/0712    
		if(n == sizeof("nonblocking")-1 && strncmp((char*)buf, "nonblocking", n) == 0){ 
			qnoblock(ether->oq, 1); 
			return n; 
		} 
2002/1130    
		if(ether->ctl!=nil) 
			return ether->ctl(ether,buf,n); 
2002/0712    
                 
2002/1130    
		error(Ebadctl); 
2002/0712    
	} 
1999/0415    
                 
2002/1130    
	if(n > ether->maxmtu) 
1999/0415    
		error(Etoobig); 
2002/1130    
	if(n < ether->minmtu) 
1999/0415    
		error(Etoosmall); 
                 
	bp = allocb(n); 
	if(waserror()){ 
		freeb(bp); 
		nexterror(); 
	} 
	memmove(bp->rp, buf, n); 
	memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen); 
	poperror(); 
	bp->wp += n; 
                 
	return etheroq(ether, bp); 
} 
                 
static long 
etherbwrite(Chan* chan, Block* bp, ulong) 
{ 
	Ether *ether; 
	long n; 
                 
	n = BLEN(bp); 
	if(NETTYPE(chan->qid.path) != Ndataqid){ 
2002/1130    
		if(waserror()) { 
			freeb(bp); 
			nexterror(); 
		} 
		n = etherwrite(chan, bp->rp, n, 0); 
		poperror(); 
1999/0415    
		freeb(bp); 
		return n; 
	} 
2002/1130    
	ether = etherxx[chan->dev]; 
1999/0415    
                 
2002/1130    
	if(n > ether->maxmtu){ 
1999/0415    
		freeb(bp); 
2002/1130    
		error(Etoobig); 
1999/0415    
	} 
2002/1130    
	if(n < ether->minmtu){ 
1999/0415    
		freeb(bp); 
		error(Etoosmall); 
	} 
                 
	return etheroq(ether, bp); 
} 
                 
static struct { 
	char*	type; 
	int	(*reset)(Ether*); 
} cards[MaxEther+1]; 
                 
void 
addethercard(char* t, int (*r)(Ether*)) 
{ 
	static int ncard; 
                 
	if(ncard == MaxEther) 
		panic("too many ether cards"); 
	cards[ncard].type = t; 
	cards[ncard].reset = r; 
	ncard++; 
} 
                 
int 
parseether(uchar *to, char *from) 
{ 
	char nip[4]; 
	char *p; 
	int i; 
                 
	p = from; 
2002/1130    
	for(i = 0; i < Eaddrlen; i++){ 
1999/0415    
		if(*p == 0) 
			return -1; 
		nip[0] = *p++; 
		if(*p == 0) 
			return -1; 
		nip[1] = *p++; 
		nip[2] = 0; 
		to[i] = strtoul(nip, 0, 16); 
		if(*p == ':') 
			p++; 
	} 
	return 0; 
} 
                 
static void 
etherreset(void) 
{ 
	Ether *ether; 
	int i, n, ctlrno; 
2002/1130    
	char name[32], buf[256]; 
1999/0415    
                 
	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){ 
		if(ether == 0) 
			ether = malloc(sizeof(Ether)); 
		memset(ether, 0, sizeof(Ether)); 
		ether->ctlrno = ctlrno; 
		ether->tbdf = BUSUNKNOWN; 
		ether->mbps = 10; 
2001/0727    
		ether->minmtu = ETHERMINTU; 
		ether->maxmtu = ETHERMAXTU; 
1999/0415    
		if(isaconfig("ether", ctlrno, ether) == 0) 
			continue; 
		for(n = 0; cards[n].type; n++){ 
			if(cistrcmp(cards[n].type, ether->type)) 
				continue; 
			for(i = 0; i < ether->nopt; i++){ 
				if(strncmp(ether->opt[i], "ea=", 3)) 
					continue; 
2002/1130    
				if(parseether(ether->ea, ðer->opt[i][3])) 
1999/0415    
					memset(ether->ea, 0, Eaddrlen); 
2002/1130    
			} 
1999/0415    
			if(cards[n].reset(ether)) 
				break; 
                 
			/* 
			 * IRQ2 doesn't really exist, it's used to gang the interrupt 
			 * controllers together. A device set to IRQ2 will appear on 
			 * the second interrupt controller as IRQ9. 
			 */ 
2001/0228    
			if(ether->irq == 2 && BUSTYPE(ether->tbdf) != BusPCI) 
1999/0415    
				ether->irq = 9; 
2000/0401    
			snprint(name, sizeof(name), "ether%d", ctlrno); 
2002/1130    
			/* 
			 * If ether->irq is 0, it is a hack to indicate no 
			 * interrupt used by ethersink. 
			 */ 
			if(ether->irq > 0) 
				intrenable(ether->irq, ether->interrupt, 
					ether, ether->tbdf, name); 
1999/0415    
                 
2002/1130    
			i = sprint(buf, "#l%d (%s): %s: %dMbps port 0x%luX irq %lud", 
				ctlrno, name, ether->type, ether->mbps, 
				ether->port, ether->irq); 
1999/0415    
			if(ether->mem) 
				i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem)); 
			if(ether->size) 
				i += sprint(buf+i, " size 0x%luX", ether->size); 
			i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX", 
				ether->ea[0], ether->ea[1], ether->ea[2], 
				ether->ea[3], ether->ea[4], ether->ea[5]); 
			sprint(buf+i, "\n"); 
			print(buf); 
                 
			if(ether->mbps == 100){ 
				netifinit(ether, name, Ntypes, 256*1024); 
				if(ether->oq == 0) 
2002/0711    
					ether->oq = qopen(256*1024, Qmsg, 0, 0); 
1999/0415    
			} 
			else{ 
				netifinit(ether, name, Ntypes, 65*1024); 
				if(ether->oq == 0) 
2002/0711    
					ether->oq = qopen(65*1024, Qmsg, 0, 0); 
1999/0415    
			} 
			if(ether->oq == 0) 
				panic("etherreset %s", name); 
			ether->alen = Eaddrlen; 
			memmove(ether->addr, ether->ea, Eaddrlen); 
			memset(ether->bcast, 0xFF, Eaddrlen); 
                 
			etherxx[ctlrno] = ether; 
			ether = 0; 
			break; 
		} 
	} 
	if(ether) 
		free(ether); 
} 
2002/1130    
                 
/* imported from ../pc; not ready for use yet */ 
static void 
ethershutdown(void) 
{ 
	Ether *ether; 
	int i; 
                 
	for(i = 0; i < MaxEther; i++){ 
		ether = etherxx[i]; 
		if(ether == nil) 
			continue; 
		if(ether->shutdown == nil) { 
			print("#l%d: no shutdown fuction\n", i); 
			continue; 
		} 
		(*ether->shutdown)(ether); 
	} 
} 
                 
1999/0415    
                 
#define POLY 0xedb88320 
                 
/* really slow 32 bit crc for ethers */ 
ulong 
ethercrc(uchar *p, int len) 
{ 
	int i, j; 
	ulong crc, b; 
                 
	crc = 0xffffffff; 
	for(i = 0; i < len; i++){ 
		b = *p++; 
		for(j = 0; j < 8; j++){ 
			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0); 
			b >>= 1; 
		} 
	} 
	return crc; 
} 
                 
Dev etherdevtab = { 
	'l', 
	"ether", 
                 
	etherreset, 
	devinit, 
2002/0109    
	devshutdown, 
1999/0415    
	etherattach, 
	etherwalk, 
	etherstat, 
	etheropen, 
	ethercreate, 
	etherclose, 
	etherread, 
	etherbread, 
	etherwrite, 
	etherbwrite, 
2001/1204    
	devremove, 
1999/0415    
	etherwstat, 
}; 
2003/0301    
#include "../pc/devether.c" 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)