xref: /plan9/sys/src/9/teg2/devether.c (revision a1216cc64119db675aa140f55fbd73eb2414b763)
13de6a9c0SDavid du Colombier #include "u.h"
23de6a9c0SDavid du Colombier #include "../port/lib.h"
33de6a9c0SDavid du Colombier #include "mem.h"
43de6a9c0SDavid du Colombier #include "dat.h"
53de6a9c0SDavid du Colombier #include "fns.h"
63de6a9c0SDavid du Colombier #include "io.h"
73de6a9c0SDavid du Colombier #include "../port/error.h"
83de6a9c0SDavid du Colombier 
93de6a9c0SDavid du Colombier #include "../port/netif.h"
103de6a9c0SDavid du Colombier #include "etherif.h"
113de6a9c0SDavid du Colombier 
123de6a9c0SDavid du Colombier static Ether *etherxx[MaxEther];
133de6a9c0SDavid du Colombier 
143de6a9c0SDavid du Colombier Chan*
etherattach(char * spec)153de6a9c0SDavid du Colombier etherattach(char* spec)
163de6a9c0SDavid du Colombier {
173de6a9c0SDavid du Colombier 	int ctlrno;
183de6a9c0SDavid du Colombier 	char *p;
193de6a9c0SDavid du Colombier 	Chan *chan;
203de6a9c0SDavid du Colombier 
213de6a9c0SDavid du Colombier 	ctlrno = 0;
223de6a9c0SDavid du Colombier 	if(spec && *spec){
233de6a9c0SDavid du Colombier 		ctlrno = strtoul(spec, &p, 0);
243de6a9c0SDavid du Colombier 		if((ctlrno == 0 && p == spec) || *p != 0)
253de6a9c0SDavid du Colombier 			error(Ebadarg);
263de6a9c0SDavid du Colombier 		if(ctlrno < 0 || ctlrno >= MaxEther)
273de6a9c0SDavid du Colombier 			error(Ebadarg);
283de6a9c0SDavid du Colombier 	}
293de6a9c0SDavid du Colombier 	if(etherxx[ctlrno] == 0)
303de6a9c0SDavid du Colombier 		error(Enodev);
313de6a9c0SDavid du Colombier 
323de6a9c0SDavid du Colombier 	chan = devattach('l', spec);
333de6a9c0SDavid du Colombier 	if(waserror()){
343de6a9c0SDavid du Colombier 		chanfree(chan);
353de6a9c0SDavid du Colombier 		nexterror();
363de6a9c0SDavid du Colombier 	}
373de6a9c0SDavid du Colombier 	chan->dev = ctlrno;
383de6a9c0SDavid du Colombier 	if(etherxx[ctlrno]->attach)
393de6a9c0SDavid du Colombier 		etherxx[ctlrno]->attach(etherxx[ctlrno]);
403de6a9c0SDavid du Colombier 	poperror();
413de6a9c0SDavid du Colombier 	return chan;
423de6a9c0SDavid du Colombier }
433de6a9c0SDavid du Colombier 
443de6a9c0SDavid du Colombier static Walkqid*
etherwalk(Chan * chan,Chan * nchan,char ** name,int nname)453de6a9c0SDavid du Colombier etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
463de6a9c0SDavid du Colombier {
473de6a9c0SDavid du Colombier 	return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
483de6a9c0SDavid du Colombier }
493de6a9c0SDavid du Colombier 
503de6a9c0SDavid du Colombier static int
etherstat(Chan * chan,uchar * dp,int n)513de6a9c0SDavid du Colombier etherstat(Chan* chan, uchar* dp, int n)
523de6a9c0SDavid du Colombier {
533de6a9c0SDavid du Colombier 	return netifstat(etherxx[chan->dev], chan, dp, n);
543de6a9c0SDavid du Colombier }
553de6a9c0SDavid du Colombier 
563de6a9c0SDavid du Colombier static Chan*
etheropen(Chan * chan,int omode)573de6a9c0SDavid du Colombier etheropen(Chan* chan, int omode)
583de6a9c0SDavid du Colombier {
593de6a9c0SDavid du Colombier 	return netifopen(etherxx[chan->dev], chan, omode);
603de6a9c0SDavid du Colombier }
613de6a9c0SDavid du Colombier 
623de6a9c0SDavid du Colombier static void
ethercreate(Chan *,char *,int,ulong)633de6a9c0SDavid du Colombier ethercreate(Chan*, char*, int, ulong)
643de6a9c0SDavid du Colombier {
653de6a9c0SDavid du Colombier }
663de6a9c0SDavid du Colombier 
673de6a9c0SDavid du Colombier static void
etherclose(Chan * chan)683de6a9c0SDavid du Colombier etherclose(Chan* chan)
693de6a9c0SDavid du Colombier {
703de6a9c0SDavid du Colombier 	netifclose(etherxx[chan->dev], chan);
713de6a9c0SDavid du Colombier }
723de6a9c0SDavid du Colombier 
733de6a9c0SDavid du Colombier static long
etherread(Chan * chan,void * buf,long n,vlong off)743de6a9c0SDavid du Colombier etherread(Chan* chan, void* buf, long n, vlong off)
753de6a9c0SDavid du Colombier {
763de6a9c0SDavid du Colombier 	Ether *ether;
773de6a9c0SDavid du Colombier 	ulong offset = off;
783de6a9c0SDavid du Colombier 
793de6a9c0SDavid du Colombier 	ether = etherxx[chan->dev];
803de6a9c0SDavid du Colombier 	if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
813de6a9c0SDavid du Colombier 		/*
823de6a9c0SDavid du Colombier 		 * With some controllers it is necessary to reach
833de6a9c0SDavid du Colombier 		 * into the chip to extract statistics.
843de6a9c0SDavid du Colombier 		 */
853de6a9c0SDavid du Colombier 		if(NETTYPE(chan->qid.path) == Nifstatqid)
863de6a9c0SDavid du Colombier 			return ether->ifstat(ether, buf, n, offset);
873de6a9c0SDavid du Colombier 		else if(NETTYPE(chan->qid.path) == Nstatqid)
883de6a9c0SDavid du Colombier 			ether->ifstat(ether, buf, 0, offset);
893de6a9c0SDavid du Colombier 	}
903de6a9c0SDavid du Colombier 
913de6a9c0SDavid du Colombier 	return netifread(ether, chan, buf, n, offset);
923de6a9c0SDavid du Colombier }
933de6a9c0SDavid du Colombier 
943de6a9c0SDavid du Colombier static Block*
etherbread(Chan * chan,long n,ulong offset)953de6a9c0SDavid du Colombier etherbread(Chan* chan, long n, ulong offset)
963de6a9c0SDavid du Colombier {
973de6a9c0SDavid du Colombier 	return netifbread(etherxx[chan->dev], chan, n, offset);
983de6a9c0SDavid du Colombier }
993de6a9c0SDavid du Colombier 
1003de6a9c0SDavid du Colombier static int
etherwstat(Chan * chan,uchar * dp,int n)1013de6a9c0SDavid du Colombier etherwstat(Chan* chan, uchar* dp, int n)
1023de6a9c0SDavid du Colombier {
1033de6a9c0SDavid du Colombier 	return netifwstat(etherxx[chan->dev], chan, dp, n);
1043de6a9c0SDavid du Colombier }
1053de6a9c0SDavid du Colombier 
1063de6a9c0SDavid du Colombier static void
etherrtrace(Netfile * f,Etherpkt * pkt,int len)1073de6a9c0SDavid du Colombier etherrtrace(Netfile* f, Etherpkt* pkt, int len)
1083de6a9c0SDavid du Colombier {
1093de6a9c0SDavid du Colombier 	int i, n;
1103de6a9c0SDavid du Colombier 	Block *bp;
1113de6a9c0SDavid du Colombier 
1123de6a9c0SDavid du Colombier 	if(qwindow(f->in) <= 0)
1133de6a9c0SDavid du Colombier 		return;
1143de6a9c0SDavid du Colombier 	if(len > 58)
1153de6a9c0SDavid du Colombier 		n = 58;
1163de6a9c0SDavid du Colombier 	else
1173de6a9c0SDavid du Colombier 		n = len;
1183de6a9c0SDavid du Colombier 	bp = iallocb(64);
1193de6a9c0SDavid du Colombier 	if(bp == nil)
1203de6a9c0SDavid du Colombier 		return;
1213de6a9c0SDavid du Colombier 	memmove(bp->wp, pkt->d, n);
1223de6a9c0SDavid du Colombier 	i = TK2MS(MACHP(0)->ticks);
1233de6a9c0SDavid du Colombier 	bp->wp[58] = len>>8;
1243de6a9c0SDavid du Colombier 	bp->wp[59] = len;
1253de6a9c0SDavid du Colombier 	bp->wp[60] = i>>24;
1263de6a9c0SDavid du Colombier 	bp->wp[61] = i>>16;
1273de6a9c0SDavid du Colombier 	bp->wp[62] = i>>8;
1283de6a9c0SDavid du Colombier 	bp->wp[63] = i;
1293de6a9c0SDavid du Colombier 	bp->wp += 64;
1303de6a9c0SDavid du Colombier 	qpass(f->in, bp);
1313de6a9c0SDavid du Colombier }
1323de6a9c0SDavid du Colombier 
1333de6a9c0SDavid du Colombier Block*
etheriq(Ether * ether,Block * bp,int fromwire)1343de6a9c0SDavid du Colombier etheriq(Ether* ether, Block* bp, int fromwire)
1353de6a9c0SDavid du Colombier {
1363de6a9c0SDavid du Colombier 	Etherpkt *pkt;
1373de6a9c0SDavid du Colombier 	ushort type;
1383de6a9c0SDavid du Colombier 	int len, multi, tome, fromme;
1393de6a9c0SDavid du Colombier 	Netfile **ep, *f, **fp, *fx;
1403de6a9c0SDavid du Colombier 	Block *xbp;
1413de6a9c0SDavid du Colombier 
1423de6a9c0SDavid du Colombier 	ether->inpackets++;
1433de6a9c0SDavid du Colombier 
1443de6a9c0SDavid du Colombier 	pkt = (Etherpkt*)bp->rp;
1453de6a9c0SDavid du Colombier 	len = BLEN(bp);
1463de6a9c0SDavid du Colombier 	type = (pkt->type[0]<<8)|pkt->type[1];
1473de6a9c0SDavid du Colombier 	fx = 0;
1483de6a9c0SDavid du Colombier 	ep = &ether->f[Ntypes];
1493de6a9c0SDavid du Colombier 
1503de6a9c0SDavid du Colombier 	multi = pkt->d[0] & 1;
1513de6a9c0SDavid du Colombier 	/* check for valid multicast addresses */
1523de6a9c0SDavid du Colombier 	if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 &&
1533de6a9c0SDavid du Colombier 	    ether->prom == 0){
1543de6a9c0SDavid du Colombier 		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
1553de6a9c0SDavid du Colombier 			if(fromwire){
1563de6a9c0SDavid du Colombier 				freeb(bp);
1573de6a9c0SDavid du Colombier 				bp = 0;
1583de6a9c0SDavid du Colombier 			}
1593de6a9c0SDavid du Colombier 			return bp;
1603de6a9c0SDavid du Colombier 		}
1613de6a9c0SDavid du Colombier 	}
1623de6a9c0SDavid du Colombier 	/* is it for me? */
1633de6a9c0SDavid du Colombier 	tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
1643de6a9c0SDavid du Colombier 	fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
1653de6a9c0SDavid du Colombier 
1663de6a9c0SDavid du Colombier 	/*
1673de6a9c0SDavid du Colombier 	 * Multiplex the packet to all the connections which want it.
1683de6a9c0SDavid du Colombier 	 * If the packet is not to be used subsequently (fromwire != 0),
1693de6a9c0SDavid du Colombier 	 * attempt to simply pass it into one of the connections, thereby
1703de6a9c0SDavid du Colombier 	 * saving a copy of the data (usual case hopefully).
1713de6a9c0SDavid du Colombier 	 */
1723de6a9c0SDavid du Colombier 	for(fp = ether->f; fp < ep; fp++){
1733de6a9c0SDavid du Colombier 		if((f = *fp) != nil && (f->type == type || f->type < 0) &&
1743de6a9c0SDavid du Colombier 		    (tome || multi || f->prom)){
1753de6a9c0SDavid du Colombier 			/* Don't want to hear bridged packets */
1763de6a9c0SDavid du Colombier 			if(f->bridge && !fromwire && !fromme)
1773de6a9c0SDavid du Colombier 				continue;
1783de6a9c0SDavid du Colombier 			if(!f->headersonly){
1793de6a9c0SDavid du Colombier 				if(fromwire && fx == 0)
1803de6a9c0SDavid du Colombier 					fx = f;
1813de6a9c0SDavid du Colombier 				else if(xbp = iallocb(len)){
1823de6a9c0SDavid du Colombier 					memmove(xbp->wp, pkt, len);
1833de6a9c0SDavid du Colombier 					xbp->wp += len;
1843de6a9c0SDavid du Colombier 					if(qpass(f->in, xbp) < 0)
1853de6a9c0SDavid du Colombier 						ether->soverflows++;
1863de6a9c0SDavid du Colombier 				}
1873de6a9c0SDavid du Colombier 				else
1883de6a9c0SDavid du Colombier 					ether->soverflows++;
1893de6a9c0SDavid du Colombier 			}
1903de6a9c0SDavid du Colombier 			else
1913de6a9c0SDavid du Colombier 				etherrtrace(f, pkt, len);
1923de6a9c0SDavid du Colombier 		}
1933de6a9c0SDavid du Colombier 	}
1943de6a9c0SDavid du Colombier 
1953de6a9c0SDavid du Colombier 	if(fx){
1963de6a9c0SDavid du Colombier 		if(qpass(fx->in, bp) < 0)
1973de6a9c0SDavid du Colombier 			ether->soverflows++;
1983de6a9c0SDavid du Colombier 		return 0;
1993de6a9c0SDavid du Colombier 	}
2003de6a9c0SDavid du Colombier 	if(fromwire){
2013de6a9c0SDavid du Colombier 		freeb(bp);
2023de6a9c0SDavid du Colombier 		return 0;
2033de6a9c0SDavid du Colombier 	}
2043de6a9c0SDavid du Colombier 	return bp;
2053de6a9c0SDavid du Colombier }
2063de6a9c0SDavid du Colombier 
2073de6a9c0SDavid du Colombier static int
etheroq(Ether * ether,Block * bp)2083de6a9c0SDavid du Colombier etheroq(Ether* ether, Block* bp)
2093de6a9c0SDavid du Colombier {
2103de6a9c0SDavid du Colombier 	int len, loopback, s;
2113de6a9c0SDavid du Colombier 	Etherpkt *pkt;
2123de6a9c0SDavid du Colombier 
2133de6a9c0SDavid du Colombier 	ether->outpackets++;
2143de6a9c0SDavid du Colombier 
2153de6a9c0SDavid du Colombier 	/*
2163de6a9c0SDavid du Colombier 	 * Check if the packet has to be placed back onto the input queue,
2173de6a9c0SDavid du Colombier 	 * i.e. if it's a loopback or broadcast packet or the interface is
2183de6a9c0SDavid du Colombier 	 * in promiscuous mode.
2193de6a9c0SDavid du Colombier 	 * If it's a loopback packet indicate to etheriq that the data isn't
2203de6a9c0SDavid du Colombier 	 * needed and return, etheriq will pass-on or free the block.
2213de6a9c0SDavid du Colombier 	 * To enable bridging to work, only packets that were originated
2223de6a9c0SDavid du Colombier 	 * by this interface are fed back.
2233de6a9c0SDavid du Colombier 	 */
2243de6a9c0SDavid du Colombier 	pkt = (Etherpkt*)bp->rp;
2253de6a9c0SDavid du Colombier 	len = BLEN(bp);
2263de6a9c0SDavid du Colombier 	loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
2273de6a9c0SDavid du Colombier 	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
2283de6a9c0SDavid du Colombier 		s = splhi();
2293de6a9c0SDavid du Colombier 		etheriq(ether, bp, 0);
2303de6a9c0SDavid du Colombier 		splx(s);
2313de6a9c0SDavid du Colombier 	}
2323de6a9c0SDavid du Colombier 
2333de6a9c0SDavid du Colombier 	if(!loopback){
2343de6a9c0SDavid du Colombier 		qbwrite(ether->oq, bp);
2353de6a9c0SDavid du Colombier 		if(ether->transmit != nil)
2363de6a9c0SDavid du Colombier 			ether->transmit(ether);
2373de6a9c0SDavid du Colombier 	} else
2383de6a9c0SDavid du Colombier 		freeb(bp);
2393de6a9c0SDavid du Colombier 
2403de6a9c0SDavid du Colombier 	return len;
2413de6a9c0SDavid du Colombier }
2423de6a9c0SDavid du Colombier 
2433de6a9c0SDavid du Colombier static long
etherwrite(Chan * chan,void * buf,long n,vlong)2443de6a9c0SDavid du Colombier etherwrite(Chan* chan, void* buf, long n, vlong)
2453de6a9c0SDavid du Colombier {
2463de6a9c0SDavid du Colombier 	Ether *ether;
2473de6a9c0SDavid du Colombier 	Block *bp;
2483de6a9c0SDavid du Colombier 	int nn, onoff;
2493de6a9c0SDavid du Colombier 	Cmdbuf *cb;
2503de6a9c0SDavid du Colombier 
2513de6a9c0SDavid du Colombier 	ether = etherxx[chan->dev];
2523de6a9c0SDavid du Colombier 	if(NETTYPE(chan->qid.path) != Ndataqid) {
2533de6a9c0SDavid du Colombier 		nn = netifwrite(ether, chan, buf, n);
2543de6a9c0SDavid du Colombier 		if(nn >= 0)
2553de6a9c0SDavid du Colombier 			return nn;
2563de6a9c0SDavid du Colombier 		cb = parsecmd(buf, n);
2573de6a9c0SDavid du Colombier 		if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
2583de6a9c0SDavid du Colombier 			if(cb->nf <= 1)
2593de6a9c0SDavid du Colombier 				onoff = 1;
2603de6a9c0SDavid du Colombier 			else
2613de6a9c0SDavid du Colombier 				onoff = atoi(cb->f[1]);
2623de6a9c0SDavid du Colombier 			qnoblock(ether->oq, onoff);
2633de6a9c0SDavid du Colombier 			free(cb);
2643de6a9c0SDavid du Colombier 			return n;
2653de6a9c0SDavid du Colombier 		}
2663de6a9c0SDavid du Colombier 		free(cb);
2673de6a9c0SDavid du Colombier 		if(ether->ctl!=nil)
2683de6a9c0SDavid du Colombier 			return ether->ctl(ether,buf,n);
2693de6a9c0SDavid du Colombier 
2703de6a9c0SDavid du Colombier 		error(Ebadctl);
2713de6a9c0SDavid du Colombier 	}
2723de6a9c0SDavid du Colombier 
2733de6a9c0SDavid du Colombier 	if(n > ether->maxmtu)
2743de6a9c0SDavid du Colombier 		error(Etoobig);
2753de6a9c0SDavid du Colombier 	if(n < ether->minmtu)
2763de6a9c0SDavid du Colombier 		error(Etoosmall);
2773de6a9c0SDavid du Colombier 
2783de6a9c0SDavid du Colombier 	bp = allocb(n);
2793de6a9c0SDavid du Colombier 	if(waserror()){
2803de6a9c0SDavid du Colombier 		freeb(bp);
2813de6a9c0SDavid du Colombier 		nexterror();
2823de6a9c0SDavid du Colombier 	}
2833de6a9c0SDavid du Colombier 	memmove(bp->rp, buf, n);
2843de6a9c0SDavid du Colombier 	memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
2853de6a9c0SDavid du Colombier 	poperror();
2863de6a9c0SDavid du Colombier 	bp->wp += n;
2873de6a9c0SDavid du Colombier 
2883de6a9c0SDavid du Colombier 	return etheroq(ether, bp);
2893de6a9c0SDavid du Colombier }
2903de6a9c0SDavid du Colombier 
2913de6a9c0SDavid du Colombier static long
etherbwrite(Chan * chan,Block * bp,ulong)2923de6a9c0SDavid du Colombier etherbwrite(Chan* chan, Block* bp, ulong)
2933de6a9c0SDavid du Colombier {
2943de6a9c0SDavid du Colombier 	Ether *ether;
2953de6a9c0SDavid du Colombier 	long n;
2963de6a9c0SDavid du Colombier 
2973de6a9c0SDavid du Colombier 	n = BLEN(bp);
2983de6a9c0SDavid du Colombier 	if(NETTYPE(chan->qid.path) != Ndataqid){
2993de6a9c0SDavid du Colombier 		if(waserror()) {
3003de6a9c0SDavid du Colombier 			freeb(bp);
3013de6a9c0SDavid du Colombier 			nexterror();
3023de6a9c0SDavid du Colombier 		}
3033de6a9c0SDavid du Colombier 		n = etherwrite(chan, bp->rp, n, 0);
3043de6a9c0SDavid du Colombier 		poperror();
3053de6a9c0SDavid du Colombier 		freeb(bp);
3063de6a9c0SDavid du Colombier 		return n;
3073de6a9c0SDavid du Colombier 	}
3083de6a9c0SDavid du Colombier 	ether = etherxx[chan->dev];
3093de6a9c0SDavid du Colombier 
3103de6a9c0SDavid du Colombier 	if(n > ether->maxmtu){
3113de6a9c0SDavid du Colombier 		freeb(bp);
3123de6a9c0SDavid du Colombier 		error(Etoobig);
3133de6a9c0SDavid du Colombier 	}
3143de6a9c0SDavid du Colombier 	if(n < ether->minmtu){
3153de6a9c0SDavid du Colombier 		freeb(bp);
3163de6a9c0SDavid du Colombier 		error(Etoosmall);
3173de6a9c0SDavid du Colombier 	}
3183de6a9c0SDavid du Colombier 
3193de6a9c0SDavid du Colombier 	return etheroq(ether, bp);
3203de6a9c0SDavid du Colombier }
3213de6a9c0SDavid du Colombier 
3223de6a9c0SDavid du Colombier static struct {
3233de6a9c0SDavid du Colombier 	char*	type;
3243de6a9c0SDavid du Colombier 	int	(*reset)(Ether*);
3253de6a9c0SDavid du Colombier } cards[MaxEther+1];
3263de6a9c0SDavid du Colombier 
3273de6a9c0SDavid du Colombier void
addethercard(char * t,int (* r)(Ether *))3283de6a9c0SDavid du Colombier addethercard(char* t, int (*r)(Ether*))
3293de6a9c0SDavid du Colombier {
3303de6a9c0SDavid du Colombier 	static int ncard;
3313de6a9c0SDavid du Colombier 
3323de6a9c0SDavid du Colombier 	if(ncard == MaxEther)
3333de6a9c0SDavid du Colombier 		panic("too many ether cards");
3343de6a9c0SDavid du Colombier 	cards[ncard].type = t;
3353de6a9c0SDavid du Colombier 	cards[ncard].reset = r;
3363de6a9c0SDavid du Colombier 	ncard++;
3373de6a9c0SDavid du Colombier }
3383de6a9c0SDavid du Colombier 
3393de6a9c0SDavid du Colombier int
parseether(uchar * to,char * from)3403de6a9c0SDavid du Colombier parseether(uchar *to, char *from)
3413de6a9c0SDavid du Colombier {
3423de6a9c0SDavid du Colombier 	char nip[4];
3433de6a9c0SDavid du Colombier 	char *p;
3443de6a9c0SDavid du Colombier 	int i;
3453de6a9c0SDavid du Colombier 
3463de6a9c0SDavid du Colombier 	p = from;
3473de6a9c0SDavid du Colombier 	for(i = 0; i < Eaddrlen; i++){
3483de6a9c0SDavid du Colombier 		if(*p == 0)
3493de6a9c0SDavid du Colombier 			return -1;
3503de6a9c0SDavid du Colombier 		nip[0] = *p++;
3513de6a9c0SDavid du Colombier 		if(*p == 0)
3523de6a9c0SDavid du Colombier 			return -1;
3533de6a9c0SDavid du Colombier 		nip[1] = *p++;
3543de6a9c0SDavid du Colombier 		nip[2] = 0;
3553de6a9c0SDavid du Colombier 		to[i] = strtoul(nip, 0, 16);
3563de6a9c0SDavid du Colombier 		if(*p == ':')
3573de6a9c0SDavid du Colombier 			p++;
3583de6a9c0SDavid du Colombier 	}
3593de6a9c0SDavid du Colombier 	return 0;
3603de6a9c0SDavid du Colombier }
3613de6a9c0SDavid du Colombier 
3623de6a9c0SDavid du Colombier static void
etherreset(void)3633de6a9c0SDavid du Colombier etherreset(void)
3643de6a9c0SDavid du Colombier {
3653de6a9c0SDavid du Colombier 	Ether *ether;
3663de6a9c0SDavid du Colombier 	int i, n, ctlrno;
3673de6a9c0SDavid du Colombier 	char name[KNAMELEN], buf[128];
3683de6a9c0SDavid du Colombier 
3693de6a9c0SDavid du Colombier 	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
3703de6a9c0SDavid du Colombier 		if(ether == 0)
3713de6a9c0SDavid du Colombier 			ether = malloc(sizeof(Ether));
3723de6a9c0SDavid du Colombier 		memset(ether, 0, sizeof(Ether));
3733de6a9c0SDavid du Colombier 		ether->ctlrno = ctlrno;
3743de6a9c0SDavid du Colombier 		ether->mbps = 10;
3753de6a9c0SDavid du Colombier 		ether->minmtu = ETHERMINTU;
3763de6a9c0SDavid du Colombier 		ether->maxmtu = ETHERMAXTU;
3773de6a9c0SDavid du Colombier 
3783de6a9c0SDavid du Colombier 		if(archether(ctlrno, ether) <= 0)
3793de6a9c0SDavid du Colombier 			continue;
3803de6a9c0SDavid du Colombier 
3813de6a9c0SDavid du Colombier 		if(isaconfig("ether", ctlrno, ether) == 0){
382*a1216cc6SDavid du Colombier //			free(ether);
3833de6a9c0SDavid du Colombier //			return nil;
3843de6a9c0SDavid du Colombier 			continue;
3853de6a9c0SDavid du Colombier 		}
3863de6a9c0SDavid du Colombier 		for(n = 0; cards[n].type; n++){
3873de6a9c0SDavid du Colombier 			if(cistrcmp(cards[n].type, ether->type))
3883de6a9c0SDavid du Colombier 				continue;
3893de6a9c0SDavid du Colombier 			for(i = 0; i < ether->nopt; i++)
3903de6a9c0SDavid du Colombier 				if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
3913de6a9c0SDavid du Colombier 					if(parseether(ether->ea,
3923de6a9c0SDavid du Colombier 					    &ether->opt[i][3]) == -1)
3933de6a9c0SDavid du Colombier 						memset(ether->ea, 0, Eaddrlen);
3943de6a9c0SDavid du Colombier 				} else if(cistrcmp(ether->opt[i],
3953de6a9c0SDavid du Colombier 				    "100BASE-TXFD") == 0)
3963de6a9c0SDavid du Colombier 					ether->mbps = 100;
3973de6a9c0SDavid du Colombier 			if(cards[n].reset(ether))
3983de6a9c0SDavid du Colombier 				break;
3993de6a9c0SDavid du Colombier 			snprint(name, sizeof(name), "ether%d", ctlrno);
4003de6a9c0SDavid du Colombier 
4013de6a9c0SDavid du Colombier 			if(ether->interrupt != nil && ether->irq >= 0)
4023de6a9c0SDavid du Colombier 				intrenable(ether->irq, ether->interrupt,
4033de6a9c0SDavid du Colombier 					ether, 0, name);
4043de6a9c0SDavid du Colombier 
4053de6a9c0SDavid du Colombier 			i = snprint(buf, sizeof buf,
4063de6a9c0SDavid du Colombier 				"#l%d: %s: %dMbps port %#lux irq %d",
4073de6a9c0SDavid du Colombier 				ctlrno, ether->type, ether->mbps, ether->port,
4083de6a9c0SDavid du Colombier 				ether->irq);
4093de6a9c0SDavid du Colombier 			if(ether->mem)
4103de6a9c0SDavid du Colombier 				i += snprint(buf+i, sizeof buf - i,
4113de6a9c0SDavid du Colombier 					" addr %#lux", PADDR(ether->mem));
4123de6a9c0SDavid du Colombier 			if(ether->size)
4133de6a9c0SDavid du Colombier 				i += snprint(buf+i, sizeof buf - i,
4143de6a9c0SDavid du Colombier 					" size %#luX", ether->size);
4153de6a9c0SDavid du Colombier 			i += snprint(buf+i, sizeof buf - i,
4163de6a9c0SDavid du Colombier 				": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
4173de6a9c0SDavid du Colombier 				ether->ea[0], ether->ea[1], ether->ea[2],
4183de6a9c0SDavid du Colombier 				ether->ea[3], ether->ea[4], ether->ea[5]);
4193de6a9c0SDavid du Colombier 			snprint(buf+i, sizeof buf - i, "\n");
4203de6a9c0SDavid du Colombier 			iprint("%s", buf);  /* it may be too early for print */
4213de6a9c0SDavid du Colombier 
4223de6a9c0SDavid du Colombier 			if(ether->mbps >= 1000)
4233de6a9c0SDavid du Colombier 				netifinit(ether, name, Ntypes, 4*1024*1024);
4243de6a9c0SDavid du Colombier 			else if(ether->mbps >= 100)
4253de6a9c0SDavid du Colombier 				netifinit(ether, name, Ntypes, 1024*1024);
4263de6a9c0SDavid du Colombier 			else
4273de6a9c0SDavid du Colombier 				netifinit(ether, name, Ntypes, 65*1024);
4283de6a9c0SDavid du Colombier 			if(ether->oq == 0)
4293de6a9c0SDavid du Colombier 				ether->oq = qopen(ether->limit, Qmsg, 0, 0);
4303de6a9c0SDavid du Colombier 			if(ether->oq == 0)
4313de6a9c0SDavid du Colombier 				panic("etherreset %s", name);
4323de6a9c0SDavid du Colombier 			ether->alen = Eaddrlen;
4333de6a9c0SDavid du Colombier 			memmove(ether->addr, ether->ea, Eaddrlen);
4343de6a9c0SDavid du Colombier 			memset(ether->bcast, 0xFF, Eaddrlen);
4353de6a9c0SDavid du Colombier 
4363de6a9c0SDavid du Colombier 			etherxx[ctlrno] = ether;
4373de6a9c0SDavid du Colombier 			ether = 0;
4383de6a9c0SDavid du Colombier 			break;
4393de6a9c0SDavid du Colombier 		}
4403de6a9c0SDavid du Colombier 	}
4413de6a9c0SDavid du Colombier 	if(ether)
4423de6a9c0SDavid du Colombier 		free(ether);
4433de6a9c0SDavid du Colombier }
4443de6a9c0SDavid du Colombier 
4453de6a9c0SDavid du Colombier static void
ethershutdown(void)4463de6a9c0SDavid du Colombier ethershutdown(void)
4473de6a9c0SDavid du Colombier {
4483de6a9c0SDavid du Colombier 	Ether *ether;
4493de6a9c0SDavid du Colombier 	int i;
4503de6a9c0SDavid du Colombier 
4513de6a9c0SDavid du Colombier 	for(i = 0; i < MaxEther; i++){
4523de6a9c0SDavid du Colombier 		ether = etherxx[i];
4533de6a9c0SDavid du Colombier 		if(ether == nil)
4543de6a9c0SDavid du Colombier 			continue;
4553de6a9c0SDavid du Colombier 		if(ether->shutdown == nil) {
4563de6a9c0SDavid du Colombier 			print("#l%d: no shutdown function\n", i);
4573de6a9c0SDavid du Colombier 			continue;
4583de6a9c0SDavid du Colombier 		}
4593de6a9c0SDavid du Colombier 		(*ether->shutdown)(ether);
4603de6a9c0SDavid du Colombier 	}
4613de6a9c0SDavid du Colombier }
4623de6a9c0SDavid du Colombier 
4633de6a9c0SDavid du Colombier 
4643de6a9c0SDavid du Colombier #define POLY 0xedb88320
4653de6a9c0SDavid du Colombier 
4663de6a9c0SDavid du Colombier /* really slow 32 bit crc for ethers */
4673de6a9c0SDavid du Colombier ulong
ethercrc(uchar * p,int len)4683de6a9c0SDavid du Colombier ethercrc(uchar *p, int len)
4693de6a9c0SDavid du Colombier {
4703de6a9c0SDavid du Colombier 	int i, j;
4713de6a9c0SDavid du Colombier 	ulong crc, b;
4723de6a9c0SDavid du Colombier 
4733de6a9c0SDavid du Colombier 	crc = 0xffffffff;
4743de6a9c0SDavid du Colombier 	for(i = 0; i < len; i++){
4753de6a9c0SDavid du Colombier 		b = *p++;
4763de6a9c0SDavid du Colombier 		for(j = 0; j < 8; j++){
4773de6a9c0SDavid du Colombier 			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
4783de6a9c0SDavid du Colombier 			b >>= 1;
4793de6a9c0SDavid du Colombier 		}
4803de6a9c0SDavid du Colombier 	}
4813de6a9c0SDavid du Colombier 	return crc;
4823de6a9c0SDavid du Colombier }
4833de6a9c0SDavid du Colombier 
4843de6a9c0SDavid du Colombier void
dumpoq(Queue * oq)4853de6a9c0SDavid du Colombier dumpoq(Queue *oq)
4863de6a9c0SDavid du Colombier {
4873de6a9c0SDavid du Colombier 	if (oq == nil)
4883de6a9c0SDavid du Colombier 		print("no outq! ");
4893de6a9c0SDavid du Colombier 	else if (qisclosed(oq))
4903de6a9c0SDavid du Colombier 		print("outq closed ");
4913de6a9c0SDavid du Colombier 	else if (qfull(oq))
4923de6a9c0SDavid du Colombier 		print("outq full ");
4933de6a9c0SDavid du Colombier 	else
4943de6a9c0SDavid du Colombier 		print("outq %d ", qlen(oq));
4953de6a9c0SDavid du Colombier }
4963de6a9c0SDavid du Colombier 
4973de6a9c0SDavid du Colombier void
dumpnetif(Netif * netif)4983de6a9c0SDavid du Colombier dumpnetif(Netif *netif)
4993de6a9c0SDavid du Colombier {
5003de6a9c0SDavid du Colombier 	print("netif %s ", netif->name);
5013de6a9c0SDavid du Colombier 	print("limit %d mbps %d link %d ",
5023de6a9c0SDavid du Colombier 		netif->limit, netif->mbps, netif->link);
5033de6a9c0SDavid du Colombier 	print("inpkts %lld outpkts %lld errs %d\n",
5043de6a9c0SDavid du Colombier 		netif->inpackets, netif->outpackets,
5053de6a9c0SDavid du Colombier 		netif->crcs + netif->oerrs + netif->frames + netif->overflows +
5063de6a9c0SDavid du Colombier 		netif->buffs + netif->soverflows);
5073de6a9c0SDavid du Colombier }
5083de6a9c0SDavid du Colombier 
5093de6a9c0SDavid du Colombier Dev etherdevtab = {
5103de6a9c0SDavid du Colombier 	'l',
5113de6a9c0SDavid du Colombier 	"ether",
5123de6a9c0SDavid du Colombier 
5133de6a9c0SDavid du Colombier 	etherreset,
5143de6a9c0SDavid du Colombier 	devinit,
5153de6a9c0SDavid du Colombier 	ethershutdown,
5163de6a9c0SDavid du Colombier 	etherattach,
5173de6a9c0SDavid du Colombier 	etherwalk,
5183de6a9c0SDavid du Colombier 	etherstat,
5193de6a9c0SDavid du Colombier 	etheropen,
5203de6a9c0SDavid du Colombier 	ethercreate,
5213de6a9c0SDavid du Colombier 	etherclose,
5223de6a9c0SDavid du Colombier 	etherread,
5233de6a9c0SDavid du Colombier 	etherbread,
5243de6a9c0SDavid du Colombier 	etherwrite,
5253de6a9c0SDavid du Colombier 	etherbwrite,
5263de6a9c0SDavid du Colombier 	devremove,
5273de6a9c0SDavid du Colombier 	etherwstat,
5283de6a9c0SDavid du Colombier };
529