xref: /plan9/sys/src/9/omap/devether.c (revision a1216cc64119db675aa140f55fbd73eb2414b763)
18e32b400SDavid du Colombier #include "u.h"
28e32b400SDavid du Colombier #include "../port/lib.h"
38e32b400SDavid du Colombier #include "mem.h"
48e32b400SDavid du Colombier #include "dat.h"
58e32b400SDavid du Colombier #include "fns.h"
68e32b400SDavid du Colombier #include "io.h"
78e32b400SDavid du Colombier #include "../port/error.h"
88e32b400SDavid du Colombier 
98e32b400SDavid du Colombier #include "../port/netif.h"
108e32b400SDavid du Colombier #include "etherif.h"
118e32b400SDavid du Colombier 
128e32b400SDavid du Colombier extern int archether(unsigned ctlno, Ether *ether);
138e32b400SDavid du Colombier 
148e32b400SDavid du Colombier static Ether *etherxx[MaxEther];
158e32b400SDavid du Colombier 
168e32b400SDavid du Colombier Chan*
etherattach(char * spec)178e32b400SDavid du Colombier etherattach(char* spec)
188e32b400SDavid du Colombier {
198e32b400SDavid du Colombier 	int ctlrno;
208e32b400SDavid du Colombier 	char *p;
218e32b400SDavid du Colombier 	Chan *chan;
228e32b400SDavid du Colombier 
238e32b400SDavid du Colombier 	ctlrno = 0;
248e32b400SDavid du Colombier 	if(spec && *spec){
258e32b400SDavid du Colombier 		ctlrno = strtoul(spec, &p, 0);
268e32b400SDavid du Colombier 		if((ctlrno == 0 && p == spec) || *p != 0)
278e32b400SDavid du Colombier 			error(Ebadarg);
288e32b400SDavid du Colombier 		if(ctlrno < 0 || ctlrno >= MaxEther)
298e32b400SDavid du Colombier 			error(Ebadarg);
308e32b400SDavid du Colombier 	}
318e32b400SDavid du Colombier 	if(etherxx[ctlrno] == 0)
328e32b400SDavid du Colombier 		error(Enodev);
338e32b400SDavid du Colombier 
348e32b400SDavid du Colombier 	chan = devattach('l', spec);
358e32b400SDavid du Colombier 	if(waserror()){
368e32b400SDavid du Colombier 		chanfree(chan);
378e32b400SDavid du Colombier 		nexterror();
388e32b400SDavid du Colombier 	}
398e32b400SDavid du Colombier 	chan->dev = ctlrno;
408e32b400SDavid du Colombier 	if(etherxx[ctlrno]->attach)
418e32b400SDavid du Colombier 		etherxx[ctlrno]->attach(etherxx[ctlrno]);
428e32b400SDavid du Colombier 	poperror();
438e32b400SDavid du Colombier 	return chan;
448e32b400SDavid du Colombier }
458e32b400SDavid du Colombier 
468e32b400SDavid du Colombier static Walkqid*
etherwalk(Chan * chan,Chan * nchan,char ** name,int nname)478e32b400SDavid du Colombier etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
488e32b400SDavid du Colombier {
498e32b400SDavid du Colombier 	return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
508e32b400SDavid du Colombier }
518e32b400SDavid du Colombier 
528e32b400SDavid du Colombier static int
etherstat(Chan * chan,uchar * dp,int n)538e32b400SDavid du Colombier etherstat(Chan* chan, uchar* dp, int n)
548e32b400SDavid du Colombier {
558e32b400SDavid du Colombier 	return netifstat(etherxx[chan->dev], chan, dp, n);
568e32b400SDavid du Colombier }
578e32b400SDavid du Colombier 
588e32b400SDavid du Colombier static Chan*
etheropen(Chan * chan,int omode)598e32b400SDavid du Colombier etheropen(Chan* chan, int omode)
608e32b400SDavid du Colombier {
618e32b400SDavid du Colombier 	return netifopen(etherxx[chan->dev], chan, omode);
628e32b400SDavid du Colombier }
638e32b400SDavid du Colombier 
648e32b400SDavid du Colombier static void
ethercreate(Chan *,char *,int,ulong)658e32b400SDavid du Colombier ethercreate(Chan*, char*, int, ulong)
668e32b400SDavid du Colombier {
678e32b400SDavid du Colombier }
688e32b400SDavid du Colombier 
698e32b400SDavid du Colombier static void
etherclose(Chan * chan)708e32b400SDavid du Colombier etherclose(Chan* chan)
718e32b400SDavid du Colombier {
728e32b400SDavid du Colombier 	netifclose(etherxx[chan->dev], chan);
738e32b400SDavid du Colombier }
748e32b400SDavid du Colombier 
758e32b400SDavid du Colombier static long
etherread(Chan * chan,void * buf,long n,vlong off)768e32b400SDavid du Colombier etherread(Chan* chan, void* buf, long n, vlong off)
778e32b400SDavid du Colombier {
788e32b400SDavid du Colombier 	Ether *ether;
798e32b400SDavid du Colombier 	ulong offset = off;
808e32b400SDavid du Colombier 
818e32b400SDavid du Colombier 	ether = etherxx[chan->dev];
828e32b400SDavid du Colombier 	if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
838e32b400SDavid du Colombier 		/*
848e32b400SDavid du Colombier 		 * With some controllers it is necessary to reach
858e32b400SDavid du Colombier 		 * into the chip to extract statistics.
868e32b400SDavid du Colombier 		 */
878e32b400SDavid du Colombier 		if(NETTYPE(chan->qid.path) == Nifstatqid)
888e32b400SDavid du Colombier 			return ether->ifstat(ether, buf, n, offset);
898e32b400SDavid du Colombier 		else if(NETTYPE(chan->qid.path) == Nstatqid)
908e32b400SDavid du Colombier 			ether->ifstat(ether, buf, 0, offset);
918e32b400SDavid du Colombier 	}
928e32b400SDavid du Colombier 
938e32b400SDavid du Colombier 	return netifread(ether, chan, buf, n, offset);
948e32b400SDavid du Colombier }
958e32b400SDavid du Colombier 
968e32b400SDavid du Colombier static Block*
etherbread(Chan * chan,long n,ulong offset)978e32b400SDavid du Colombier etherbread(Chan* chan, long n, ulong offset)
988e32b400SDavid du Colombier {
998e32b400SDavid du Colombier 	return netifbread(etherxx[chan->dev], chan, n, offset);
1008e32b400SDavid du Colombier }
1018e32b400SDavid du Colombier 
1028e32b400SDavid du Colombier static int
etherwstat(Chan * chan,uchar * dp,int n)1038e32b400SDavid du Colombier etherwstat(Chan* chan, uchar* dp, int n)
1048e32b400SDavid du Colombier {
1058e32b400SDavid du Colombier 	return netifwstat(etherxx[chan->dev], chan, dp, n);
1068e32b400SDavid du Colombier }
1078e32b400SDavid du Colombier 
1088e32b400SDavid du Colombier static void
etherrtrace(Netfile * f,Etherpkt * pkt,int len)1098e32b400SDavid du Colombier etherrtrace(Netfile* f, Etherpkt* pkt, int len)
1108e32b400SDavid du Colombier {
1118e32b400SDavid du Colombier 	int i, n;
1128e32b400SDavid du Colombier 	Block *bp;
1138e32b400SDavid du Colombier 
1148e32b400SDavid du Colombier 	if(qwindow(f->in) <= 0)
1158e32b400SDavid du Colombier 		return;
1168e32b400SDavid du Colombier 	if(len > 58)
1178e32b400SDavid du Colombier 		n = 58;
1188e32b400SDavid du Colombier 	else
1198e32b400SDavid du Colombier 		n = len;
1208e32b400SDavid du Colombier 	bp = iallocb(64);
1218e32b400SDavid du Colombier 	if(bp == nil)
1228e32b400SDavid du Colombier 		return;
1238e32b400SDavid du Colombier 	memmove(bp->wp, pkt->d, n);
1248e32b400SDavid du Colombier 	i = TK2MS(MACHP(0)->ticks);
1258e32b400SDavid du Colombier 	bp->wp[58] = len>>8;
1268e32b400SDavid du Colombier 	bp->wp[59] = len;
1278e32b400SDavid du Colombier 	bp->wp[60] = i>>24;
1288e32b400SDavid du Colombier 	bp->wp[61] = i>>16;
1298e32b400SDavid du Colombier 	bp->wp[62] = i>>8;
1308e32b400SDavid du Colombier 	bp->wp[63] = i;
1318e32b400SDavid du Colombier 	bp->wp += 64;
1328e32b400SDavid du Colombier 	qpass(f->in, bp);
1338e32b400SDavid du Colombier }
1348e32b400SDavid du Colombier 
1358e32b400SDavid du Colombier Block*
etheriq(Ether * ether,Block * bp,int fromwire)1368e32b400SDavid du Colombier etheriq(Ether* ether, Block* bp, int fromwire)
1378e32b400SDavid du Colombier {
1388e32b400SDavid du Colombier 	Etherpkt *pkt;
1398e32b400SDavid du Colombier 	ushort type;
1408e32b400SDavid du Colombier 	int len, multi, tome, fromme;
1418e32b400SDavid du Colombier 	Netfile **ep, *f, **fp, *fx;
1428e32b400SDavid du Colombier 	Block *xbp;
1438e32b400SDavid du Colombier 
1448e32b400SDavid du Colombier 	ether->inpackets++;
1458e32b400SDavid du Colombier 
1468e32b400SDavid du Colombier 	pkt = (Etherpkt*)bp->rp;
1478e32b400SDavid du Colombier 	len = BLEN(bp);
1488e32b400SDavid du Colombier 	type = (pkt->type[0]<<8)|pkt->type[1];
1498e32b400SDavid du Colombier 	fx = 0;
1508e32b400SDavid du Colombier 	ep = &ether->f[Ntypes];
1518e32b400SDavid du Colombier 
1528e32b400SDavid du Colombier 	multi = pkt->d[0] & 1;
1538e32b400SDavid du Colombier 	/* check for valid multicast addresses */
1548e32b400SDavid du Colombier 	if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 &&
1558e32b400SDavid du Colombier 	    ether->prom == 0){
1568e32b400SDavid du Colombier 		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
1578e32b400SDavid du Colombier 			if(fromwire){
1588e32b400SDavid du Colombier 				freeb(bp);
1598e32b400SDavid du Colombier 				bp = 0;
1608e32b400SDavid du Colombier 			}
1618e32b400SDavid du Colombier 			return bp;
1628e32b400SDavid du Colombier 		}
1638e32b400SDavid du Colombier 	}
1648e32b400SDavid du Colombier 	/* is it for me? */
1658e32b400SDavid du Colombier 	tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
1668e32b400SDavid du Colombier 	fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
1678e32b400SDavid du Colombier 
1688e32b400SDavid du Colombier 	/*
1698e32b400SDavid du Colombier 	 * Multiplex the packet to all the connections which want it.
1708e32b400SDavid du Colombier 	 * If the packet is not to be used subsequently (fromwire != 0),
1718e32b400SDavid du Colombier 	 * attempt to simply pass it into one of the connections, thereby
1728e32b400SDavid du Colombier 	 * saving a copy of the data (usual case hopefully).
1738e32b400SDavid du Colombier 	 */
1748e32b400SDavid du Colombier 	for(fp = ether->f; fp < ep; fp++){
1758e32b400SDavid du Colombier 		if((f = *fp) != nil && (f->type == type || f->type < 0) &&
1768e32b400SDavid du Colombier 		    (tome || multi || f->prom)){
1778e32b400SDavid du Colombier 			/* Don't want to hear bridged packets */
1788e32b400SDavid du Colombier 			if(f->bridge && !fromwire && !fromme)
1798e32b400SDavid du Colombier 				continue;
1808e32b400SDavid du Colombier 			if(!f->headersonly){
1818e32b400SDavid du Colombier 				if(fromwire && fx == 0)
1828e32b400SDavid du Colombier 					fx = f;
1838e32b400SDavid du Colombier 				else if(xbp = iallocb(len)){
1848e32b400SDavid du Colombier 					memmove(xbp->wp, pkt, len);
1858e32b400SDavid du Colombier 					xbp->wp += len;
1868e32b400SDavid du Colombier 					if(qpass(f->in, xbp) < 0)
1878e32b400SDavid du Colombier 						ether->soverflows++;
1888e32b400SDavid du Colombier 				}
1898e32b400SDavid du Colombier 				else
1908e32b400SDavid du Colombier 					ether->soverflows++;
1918e32b400SDavid du Colombier 			}
1928e32b400SDavid du Colombier 			else
1938e32b400SDavid du Colombier 				etherrtrace(f, pkt, len);
1948e32b400SDavid du Colombier 		}
1958e32b400SDavid du Colombier 	}
1968e32b400SDavid du Colombier 
1978e32b400SDavid du Colombier 	if(fx){
1988e32b400SDavid du Colombier 		if(qpass(fx->in, bp) < 0)
1998e32b400SDavid du Colombier 			ether->soverflows++;
2008e32b400SDavid du Colombier 		return 0;
2018e32b400SDavid du Colombier 	}
2028e32b400SDavid du Colombier 	if(fromwire){
2038e32b400SDavid du Colombier 		freeb(bp);
2048e32b400SDavid du Colombier 		return 0;
2058e32b400SDavid du Colombier 	}
2068e32b400SDavid du Colombier 	return bp;
2078e32b400SDavid du Colombier }
2088e32b400SDavid du Colombier 
2098e32b400SDavid du Colombier static int
etheroq(Ether * ether,Block * bp)2108e32b400SDavid du Colombier etheroq(Ether* ether, Block* bp)
2118e32b400SDavid du Colombier {
2128e32b400SDavid du Colombier 	int len, loopback, s;
2138e32b400SDavid du Colombier 	Etherpkt *pkt;
2148e32b400SDavid du Colombier 
2158e32b400SDavid du Colombier 	ether->outpackets++;
2168e32b400SDavid du Colombier 
2178e32b400SDavid du Colombier 	/*
2188e32b400SDavid du Colombier 	 * Check if the packet has to be placed back onto the input queue,
2198e32b400SDavid du Colombier 	 * i.e. if it's a loopback or broadcast packet or the interface is
2208e32b400SDavid du Colombier 	 * in promiscuous mode.
2218e32b400SDavid du Colombier 	 * If it's a loopback packet indicate to etheriq that the data isn't
2228e32b400SDavid du Colombier 	 * needed and return, etheriq will pass-on or free the block.
2238e32b400SDavid du Colombier 	 * To enable bridging to work, only packets that were originated
2248e32b400SDavid du Colombier 	 * by this interface are fed back.
2258e32b400SDavid du Colombier 	 */
2268e32b400SDavid du Colombier 	pkt = (Etherpkt*)bp->rp;
2278e32b400SDavid du Colombier 	len = BLEN(bp);
2288e32b400SDavid du Colombier 	loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
2298e32b400SDavid du Colombier 	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
2308e32b400SDavid du Colombier 		s = splhi();
2318e32b400SDavid du Colombier 		etheriq(ether, bp, 0);
2328e32b400SDavid du Colombier 		splx(s);
2338e32b400SDavid du Colombier 	}
2348e32b400SDavid du Colombier 
2358e32b400SDavid du Colombier 	if(!loopback){
2368e32b400SDavid du Colombier 		qbwrite(ether->oq, bp);
2378e32b400SDavid du Colombier 		if(ether->transmit != nil)
2388e32b400SDavid du Colombier 			ether->transmit(ether);
2398e32b400SDavid du Colombier 	} else
2408e32b400SDavid du Colombier 		freeb(bp);
2418e32b400SDavid du Colombier 
2428e32b400SDavid du Colombier 	return len;
2438e32b400SDavid du Colombier }
2448e32b400SDavid du Colombier 
2458e32b400SDavid du Colombier static long
etherwrite(Chan * chan,void * buf,long n,vlong)2468e32b400SDavid du Colombier etherwrite(Chan* chan, void* buf, long n, vlong)
2478e32b400SDavid du Colombier {
2488e32b400SDavid du Colombier 	Ether *ether;
2498e32b400SDavid du Colombier 	Block *bp;
2508e32b400SDavid du Colombier 	int nn, onoff;
2518e32b400SDavid du Colombier 	Cmdbuf *cb;
2528e32b400SDavid du Colombier 
2538e32b400SDavid du Colombier 	ether = etherxx[chan->dev];
2548e32b400SDavid du Colombier 	if(NETTYPE(chan->qid.path) != Ndataqid) {
2558e32b400SDavid du Colombier 		nn = netifwrite(ether, chan, buf, n);
2568e32b400SDavid du Colombier 		if(nn >= 0)
2578e32b400SDavid du Colombier 			return nn;
2588e32b400SDavid du Colombier 		cb = parsecmd(buf, n);
2598e32b400SDavid du Colombier 		if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
2608e32b400SDavid du Colombier 			if(cb->nf <= 1)
2618e32b400SDavid du Colombier 				onoff = 1;
2628e32b400SDavid du Colombier 			else
2638e32b400SDavid du Colombier 				onoff = atoi(cb->f[1]);
2648e32b400SDavid du Colombier 			qnoblock(ether->oq, onoff);
2658e32b400SDavid du Colombier 			free(cb);
2668e32b400SDavid du Colombier 			return n;
2678e32b400SDavid du Colombier 		}
2688e32b400SDavid du Colombier 		free(cb);
2698e32b400SDavid du Colombier 		if(ether->ctl!=nil)
2708e32b400SDavid du Colombier 			return ether->ctl(ether,buf,n);
2718e32b400SDavid du Colombier 
2728e32b400SDavid du Colombier 		error(Ebadctl);
2738e32b400SDavid du Colombier 	}
2748e32b400SDavid du Colombier 
2758e32b400SDavid du Colombier 	if(n > ether->maxmtu)
2768e32b400SDavid du Colombier 		error(Etoobig);
2778e32b400SDavid du Colombier 	if(n < ether->minmtu)
2788e32b400SDavid du Colombier 		error(Etoosmall);
2798e32b400SDavid du Colombier 
2808e32b400SDavid du Colombier 	bp = allocb(n);
2818e32b400SDavid du Colombier 	if(waserror()){
2828e32b400SDavid du Colombier 		freeb(bp);
2838e32b400SDavid du Colombier 		nexterror();
2848e32b400SDavid du Colombier 	}
2858e32b400SDavid du Colombier 	memmove(bp->rp, buf, n);
2868e32b400SDavid du Colombier 	memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
2878e32b400SDavid du Colombier 	poperror();
2888e32b400SDavid du Colombier 	bp->wp += n;
2898e32b400SDavid du Colombier 
2908e32b400SDavid du Colombier 	return etheroq(ether, bp);
2918e32b400SDavid du Colombier }
2928e32b400SDavid du Colombier 
2938e32b400SDavid du Colombier static long
etherbwrite(Chan * chan,Block * bp,ulong)2948e32b400SDavid du Colombier etherbwrite(Chan* chan, Block* bp, ulong)
2958e32b400SDavid du Colombier {
2968e32b400SDavid du Colombier 	Ether *ether;
2978e32b400SDavid du Colombier 	long n;
2988e32b400SDavid du Colombier 
2998e32b400SDavid du Colombier 	n = BLEN(bp);
3008e32b400SDavid du Colombier 	if(NETTYPE(chan->qid.path) != Ndataqid){
3018e32b400SDavid du Colombier 		if(waserror()) {
3028e32b400SDavid du Colombier 			freeb(bp);
3038e32b400SDavid du Colombier 			nexterror();
3048e32b400SDavid du Colombier 		}
3058e32b400SDavid du Colombier 		n = etherwrite(chan, bp->rp, n, 0);
3068e32b400SDavid du Colombier 		poperror();
3078e32b400SDavid du Colombier 		freeb(bp);
3088e32b400SDavid du Colombier 		return n;
3098e32b400SDavid du Colombier 	}
3108e32b400SDavid du Colombier 	ether = etherxx[chan->dev];
3118e32b400SDavid du Colombier 
3128e32b400SDavid du Colombier 	if(n > ether->maxmtu){
3138e32b400SDavid du Colombier 		freeb(bp);
3148e32b400SDavid du Colombier 		error(Etoobig);
3158e32b400SDavid du Colombier 	}
3168e32b400SDavid du Colombier 	if(n < ether->minmtu){
3178e32b400SDavid du Colombier 		freeb(bp);
3188e32b400SDavid du Colombier 		error(Etoosmall);
3198e32b400SDavid du Colombier 	}
3208e32b400SDavid du Colombier 
3218e32b400SDavid du Colombier 	return etheroq(ether, bp);
3228e32b400SDavid du Colombier }
3238e32b400SDavid du Colombier 
3248e32b400SDavid du Colombier static struct {
3258e32b400SDavid du Colombier 	char*	type;
3268e32b400SDavid du Colombier 	int	(*reset)(Ether*);
3278e32b400SDavid du Colombier } cards[MaxEther+1];
3288e32b400SDavid du Colombier 
3298e32b400SDavid du Colombier void
addethercard(char * t,int (* r)(Ether *))3308e32b400SDavid du Colombier addethercard(char* t, int (*r)(Ether*))
3318e32b400SDavid du Colombier {
3328e32b400SDavid du Colombier 	static int ncard;
3338e32b400SDavid du Colombier 
3348e32b400SDavid du Colombier 	if(ncard == MaxEther)
3358e32b400SDavid du Colombier 		panic("too many ether cards");
3368e32b400SDavid du Colombier 	cards[ncard].type = t;
3378e32b400SDavid du Colombier 	cards[ncard].reset = r;
3388e32b400SDavid du Colombier 	ncard++;
3398e32b400SDavid du Colombier }
3408e32b400SDavid du Colombier 
3418e32b400SDavid du Colombier int
parseether(uchar * to,char * from)3428e32b400SDavid du Colombier parseether(uchar *to, char *from)
3438e32b400SDavid du Colombier {
3448e32b400SDavid du Colombier 	char nip[4];
3458e32b400SDavid du Colombier 	char *p;
3468e32b400SDavid du Colombier 	int i;
3478e32b400SDavid du Colombier 
3488e32b400SDavid du Colombier 	p = from;
3498e32b400SDavid du Colombier 	for(i = 0; i < Eaddrlen; i++){
3508e32b400SDavid du Colombier 		if(*p == 0)
3518e32b400SDavid du Colombier 			return -1;
3528e32b400SDavid du Colombier 		nip[0] = *p++;
3538e32b400SDavid du Colombier 		if(*p == 0)
3548e32b400SDavid du Colombier 			return -1;
3558e32b400SDavid du Colombier 		nip[1] = *p++;
3568e32b400SDavid du Colombier 		nip[2] = 0;
3578e32b400SDavid du Colombier 		to[i] = strtoul(nip, 0, 16);
3588e32b400SDavid du Colombier 		if(*p == ':')
3598e32b400SDavid du Colombier 			p++;
3608e32b400SDavid du Colombier 	}
3618e32b400SDavid du Colombier 	return 0;
3628e32b400SDavid du Colombier }
3638e32b400SDavid du Colombier 
3648e32b400SDavid du Colombier static void
etherreset(void)3658e32b400SDavid du Colombier etherreset(void)
3668e32b400SDavid du Colombier {
3678e32b400SDavid du Colombier 	Ether *ether;
3688e32b400SDavid du Colombier 	int i, n, ctlrno;
3698e32b400SDavid du Colombier 	char name[KNAMELEN], buf[128];
3708e32b400SDavid du Colombier 
3718e32b400SDavid du Colombier 	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
3728e32b400SDavid du Colombier 		if(ether == 0)
3738e32b400SDavid du Colombier 			ether = malloc(sizeof(Ether));
3748e32b400SDavid du Colombier 		memset(ether, 0, sizeof(Ether));
3758e32b400SDavid du Colombier 		ether->ctlrno = ctlrno;
3768e32b400SDavid du Colombier 		ether->mbps = 10;
3778e32b400SDavid du Colombier 		ether->minmtu = ETHERMINTU;
3788e32b400SDavid du Colombier 		ether->maxmtu = ETHERMAXTU;
3798e32b400SDavid du Colombier 
3808e32b400SDavid du Colombier 		if(archether(ctlrno, ether) <= 0)
3818e32b400SDavid du Colombier 			continue;
3828e32b400SDavid du Colombier 
3838e32b400SDavid du Colombier 		if(isaconfig("ether", ctlrno, ether) == 0){
384*a1216cc6SDavid du Colombier //			free(ether);
3858e32b400SDavid du Colombier //			return nil;
3868e32b400SDavid du Colombier 			continue;
3878e32b400SDavid du Colombier 		}
3888e32b400SDavid du Colombier 		for(n = 0; cards[n].type; n++){
3898e32b400SDavid du Colombier 			if(cistrcmp(cards[n].type, ether->type))
3908e32b400SDavid du Colombier 				continue;
3918e32b400SDavid du Colombier 			for(i = 0; i < ether->nopt; i++)
3928e32b400SDavid du Colombier 				if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
3938e32b400SDavid du Colombier 					if(parseether(ether->ea,
3948e32b400SDavid du Colombier 					    &ether->opt[i][3]) == -1)
3958e32b400SDavid du Colombier 						memset(ether->ea, 0, Eaddrlen);
3968e32b400SDavid du Colombier 				} else if(cistrcmp(ether->opt[i],
3978e32b400SDavid du Colombier 				    "100BASE-TXFD") == 0)
3988e32b400SDavid du Colombier 					ether->mbps = 100;
3998e32b400SDavid du Colombier 			if(cards[n].reset(ether))
4008e32b400SDavid du Colombier 				break;
4018e32b400SDavid du Colombier 			snprint(name, sizeof(name), "ether%d", ctlrno);
4028e32b400SDavid du Colombier 
4038e32b400SDavid du Colombier 			if(ether->interrupt != nil && ether->irq >= 0)
4048e32b400SDavid du Colombier 				intrenable(ether->irq, ether->interrupt,
4058e32b400SDavid du Colombier 					ether, 0, name);
4068e32b400SDavid du Colombier 
4078e32b400SDavid du Colombier 			i = snprint(buf, sizeof buf,
4088e32b400SDavid du Colombier 				"#l%d: %s: %dMbps port %#lux irq %d",
4098e32b400SDavid du Colombier 				ctlrno, ether->type, ether->mbps, ether->port,
4108e32b400SDavid du Colombier 				ether->irq);
4118e32b400SDavid du Colombier 			if(ether->mem)
4128e32b400SDavid du Colombier 				i += snprint(buf+i, sizeof buf - i,
4138e32b400SDavid du Colombier 					" addr %#lux", PADDR(ether->mem));
4148e32b400SDavid du Colombier 			if(ether->size)
4158e32b400SDavid du Colombier 				i += snprint(buf+i, sizeof buf - i,
416fe25a076SDavid du Colombier 					" size %#luX", ether->size);
4178e32b400SDavid du Colombier 			i += snprint(buf+i, sizeof buf - i,
4188e32b400SDavid du Colombier 				": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
4198e32b400SDavid du Colombier 				ether->ea[0], ether->ea[1], ether->ea[2],
4208e32b400SDavid du Colombier 				ether->ea[3], ether->ea[4], ether->ea[5]);
4218e32b400SDavid du Colombier 			snprint(buf+i, sizeof buf - i, "\n");
4228e32b400SDavid du Colombier 			iprint("%s", buf);  /* it may be too early for print */
4238e32b400SDavid du Colombier 
4248e32b400SDavid du Colombier 			if(ether->mbps >= 1000)
4258e32b400SDavid du Colombier 				netifinit(ether, name, Ntypes, 4*1024*1024);
4268e32b400SDavid du Colombier 			else if(ether->mbps >= 100)
4278e32b400SDavid du Colombier 				netifinit(ether, name, Ntypes, 1024*1024);
4288e32b400SDavid du Colombier 			else
4298e32b400SDavid du Colombier 				netifinit(ether, name, Ntypes, 65*1024);
4308e32b400SDavid du Colombier 			if(ether->oq == 0)
4318e32b400SDavid du Colombier 				ether->oq = qopen(ether->limit, Qmsg, 0, 0);
4328e32b400SDavid du Colombier 			if(ether->oq == 0)
4338e32b400SDavid du Colombier 				panic("etherreset %s", name);
4348e32b400SDavid du Colombier 			ether->alen = Eaddrlen;
4358e32b400SDavid du Colombier 			memmove(ether->addr, ether->ea, Eaddrlen);
4368e32b400SDavid du Colombier 			memset(ether->bcast, 0xFF, Eaddrlen);
4378e32b400SDavid du Colombier 
4388e32b400SDavid du Colombier 			etherxx[ctlrno] = ether;
4398e32b400SDavid du Colombier 			ether = 0;
4408e32b400SDavid du Colombier 			break;
4418e32b400SDavid du Colombier 		}
4428e32b400SDavid du Colombier 	}
4438e32b400SDavid du Colombier 	if(ether)
4448e32b400SDavid du Colombier 		free(ether);
4458e32b400SDavid du Colombier }
4468e32b400SDavid du Colombier 
4478e32b400SDavid du Colombier static void
ethershutdown(void)4488e32b400SDavid du Colombier ethershutdown(void)
4498e32b400SDavid du Colombier {
4508e32b400SDavid du Colombier 	Ether *ether;
4518e32b400SDavid du Colombier 	int i;
4528e32b400SDavid du Colombier 
4538e32b400SDavid du Colombier 	for(i = 0; i < MaxEther; i++){
4548e32b400SDavid du Colombier 		ether = etherxx[i];
4558e32b400SDavid du Colombier 		if(ether == nil)
4568e32b400SDavid du Colombier 			continue;
4578e32b400SDavid du Colombier 		if(ether->shutdown == nil) {
4588e32b400SDavid du Colombier 			print("#l%d: no shutdown function\n", i);
4598e32b400SDavid du Colombier 			continue;
4608e32b400SDavid du Colombier 		}
4618e32b400SDavid du Colombier 		(*ether->shutdown)(ether);
4628e32b400SDavid du Colombier 	}
4638e32b400SDavid du Colombier }
4648e32b400SDavid du Colombier 
4658e32b400SDavid du Colombier 
4668e32b400SDavid du Colombier #define POLY 0xedb88320
4678e32b400SDavid du Colombier 
4688e32b400SDavid du Colombier /* really slow 32 bit crc for ethers */
4698e32b400SDavid du Colombier ulong
ethercrc(uchar * p,int len)4708e32b400SDavid du Colombier ethercrc(uchar *p, int len)
4718e32b400SDavid du Colombier {
4728e32b400SDavid du Colombier 	int i, j;
4738e32b400SDavid du Colombier 	ulong crc, b;
4748e32b400SDavid du Colombier 
4758e32b400SDavid du Colombier 	crc = 0xffffffff;
4768e32b400SDavid du Colombier 	for(i = 0; i < len; i++){
4778e32b400SDavid du Colombier 		b = *p++;
4788e32b400SDavid du Colombier 		for(j = 0; j < 8; j++){
4798e32b400SDavid du Colombier 			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
4808e32b400SDavid du Colombier 			b >>= 1;
4818e32b400SDavid du Colombier 		}
4828e32b400SDavid du Colombier 	}
4838e32b400SDavid du Colombier 	return crc;
4848e32b400SDavid du Colombier }
4858e32b400SDavid du Colombier 
4868e32b400SDavid du Colombier void
dumpoq(Queue * oq)4878e32b400SDavid du Colombier dumpoq(Queue *oq)
4888e32b400SDavid du Colombier {
4898e32b400SDavid du Colombier 	if (oq == nil)
4908e32b400SDavid du Colombier 		print("no outq! ");
4918e32b400SDavid du Colombier 	else if (qisclosed(oq))
4928e32b400SDavid du Colombier 		print("outq closed ");
4938e32b400SDavid du Colombier 	else if (qfull(oq))
4948e32b400SDavid du Colombier 		print("outq full ");
4958e32b400SDavid du Colombier 	else
4968e32b400SDavid du Colombier 		print("outq %d ", qlen(oq));
4978e32b400SDavid du Colombier }
4988e32b400SDavid du Colombier 
4998e32b400SDavid du Colombier void
dumpnetif(Netif * netif)5008e32b400SDavid du Colombier dumpnetif(Netif *netif)
5018e32b400SDavid du Colombier {
5028e32b400SDavid du Colombier 	print("netif %s ", netif->name);
5038e32b400SDavid du Colombier 	print("limit %d mbps %d link %d ",
5048e32b400SDavid du Colombier 		netif->limit, netif->mbps, netif->link);
5058e32b400SDavid du Colombier 	print("inpkts %lld outpkts %lld errs %d\n",
5068e32b400SDavid du Colombier 		netif->inpackets, netif->outpackets,
5078e32b400SDavid du Colombier 		netif->crcs + netif->oerrs + netif->frames + netif->overflows +
5088e32b400SDavid du Colombier 		netif->buffs + netif->soverflows);
5098e32b400SDavid du Colombier }
5108e32b400SDavid du Colombier 
5118e32b400SDavid du Colombier Dev etherdevtab = {
5128e32b400SDavid du Colombier 	'l',
5138e32b400SDavid du Colombier 	"ether",
5148e32b400SDavid du Colombier 
5158e32b400SDavid du Colombier 	etherreset,
5168e32b400SDavid du Colombier 	devinit,
5178e32b400SDavid du Colombier 	ethershutdown,
5188e32b400SDavid du Colombier 	etherattach,
5198e32b400SDavid du Colombier 	etherwalk,
5208e32b400SDavid du Colombier 	etherstat,
5218e32b400SDavid du Colombier 	etheropen,
5228e32b400SDavid du Colombier 	ethercreate,
5238e32b400SDavid du Colombier 	etherclose,
5248e32b400SDavid du Colombier 	etherread,
5258e32b400SDavid du Colombier 	etherbread,
5268e32b400SDavid du Colombier 	etherwrite,
5278e32b400SDavid du Colombier 	etherbwrite,
5288e32b400SDavid du Colombier 	devremove,
5298e32b400SDavid du Colombier 	etherwstat,
5308e32b400SDavid du Colombier };
531