xref: /plan9-contrib/sys/src/9/kw/devether.c (revision 7ae8f4532bb599d9c475208824b53a0495a01a84)
1154abd99SDavid du Colombier #include "u.h"
2154abd99SDavid du Colombier #include "../port/lib.h"
3154abd99SDavid du Colombier #include "mem.h"
4154abd99SDavid du Colombier #include "dat.h"
5154abd99SDavid du Colombier #include "fns.h"
6154abd99SDavid du Colombier #include "io.h"
7154abd99SDavid du Colombier #include "../port/error.h"
8154abd99SDavid du Colombier 
9154abd99SDavid du Colombier #include "../port/netif.h"
10154abd99SDavid du Colombier #include "etherif.h"
11154abd99SDavid du Colombier 
12c6569576SDavid du Colombier extern int archether(unsigned ctlno, Ether *ether);
13154abd99SDavid du Colombier 
14154abd99SDavid du Colombier static Ether *etherxx[MaxEther];
15154abd99SDavid du Colombier 
16154abd99SDavid du Colombier Chan*
etherattach(char * spec)17154abd99SDavid du Colombier etherattach(char* spec)
18154abd99SDavid du Colombier {
19154abd99SDavid du Colombier 	int ctlrno;
20154abd99SDavid du Colombier 	char *p;
21154abd99SDavid du Colombier 	Chan *chan;
22154abd99SDavid du Colombier 
23154abd99SDavid du Colombier 	ctlrno = 0;
24154abd99SDavid du Colombier 	if(spec && *spec){
25154abd99SDavid du Colombier 		ctlrno = strtoul(spec, &p, 0);
26154abd99SDavid du Colombier 		if((ctlrno == 0 && p == spec) || *p != 0)
27154abd99SDavid du Colombier 			error(Ebadarg);
28154abd99SDavid du Colombier 		if(ctlrno < 0 || ctlrno >= MaxEther)
29154abd99SDavid du Colombier 			error(Ebadarg);
30154abd99SDavid du Colombier 	}
31154abd99SDavid du Colombier 	if(etherxx[ctlrno] == 0)
32154abd99SDavid du Colombier 		error(Enodev);
33154abd99SDavid du Colombier 
34154abd99SDavid du Colombier 	chan = devattach('l', spec);
35154abd99SDavid du Colombier 	if(waserror()){
36154abd99SDavid du Colombier 		chanfree(chan);
37154abd99SDavid du Colombier 		nexterror();
38154abd99SDavid du Colombier 	}
390d0cdc9eSDavid du Colombier 	chan->dev = ctlrno;
40154abd99SDavid du Colombier 	if(etherxx[ctlrno]->attach)
41154abd99SDavid du Colombier 		etherxx[ctlrno]->attach(etherxx[ctlrno]);
42154abd99SDavid du Colombier 	poperror();
43154abd99SDavid du Colombier 	return chan;
44154abd99SDavid du Colombier }
45154abd99SDavid du Colombier 
46154abd99SDavid du Colombier static Walkqid*
etherwalk(Chan * chan,Chan * nchan,char ** name,int nname)47154abd99SDavid du Colombier etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
48154abd99SDavid du Colombier {
490d0cdc9eSDavid du Colombier 	return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
50154abd99SDavid du Colombier }
51154abd99SDavid du Colombier 
52154abd99SDavid du Colombier static int
etherstat(Chan * chan,uchar * dp,int n)53154abd99SDavid du Colombier etherstat(Chan* chan, uchar* dp, int n)
54154abd99SDavid du Colombier {
550d0cdc9eSDavid du Colombier 	return netifstat(etherxx[chan->dev], chan, dp, n);
56154abd99SDavid du Colombier }
57154abd99SDavid du Colombier 
58154abd99SDavid du Colombier static Chan*
etheropen(Chan * chan,int omode)59154abd99SDavid du Colombier etheropen(Chan* chan, int omode)
60154abd99SDavid du Colombier {
610d0cdc9eSDavid du Colombier 	return netifopen(etherxx[chan->dev], chan, omode);
62154abd99SDavid du Colombier }
63154abd99SDavid du Colombier 
64154abd99SDavid du Colombier static void
ethercreate(Chan *,char *,int,ulong)65154abd99SDavid du Colombier ethercreate(Chan*, char*, int, ulong)
66154abd99SDavid du Colombier {
67154abd99SDavid du Colombier }
68154abd99SDavid du Colombier 
69154abd99SDavid du Colombier static void
etherclose(Chan * chan)70154abd99SDavid du Colombier etherclose(Chan* chan)
71154abd99SDavid du Colombier {
720d0cdc9eSDavid du Colombier 	netifclose(etherxx[chan->dev], chan);
73154abd99SDavid du Colombier }
74154abd99SDavid du Colombier 
75154abd99SDavid du Colombier static long
etherread(Chan * chan,void * buf,long n,vlong off)76154abd99SDavid du Colombier etherread(Chan* chan, void* buf, long n, vlong off)
77154abd99SDavid du Colombier {
78154abd99SDavid du Colombier 	Ether *ether;
79154abd99SDavid du Colombier 	ulong offset = off;
80154abd99SDavid du Colombier 
810d0cdc9eSDavid du Colombier 	ether = etherxx[chan->dev];
82154abd99SDavid du Colombier 	if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
83154abd99SDavid du Colombier 		/*
84154abd99SDavid du Colombier 		 * With some controllers it is necessary to reach
85154abd99SDavid du Colombier 		 * into the chip to extract statistics.
86154abd99SDavid du Colombier 		 */
87154abd99SDavid du Colombier 		if(NETTYPE(chan->qid.path) == Nifstatqid)
88154abd99SDavid du Colombier 			return ether->ifstat(ether, buf, n, offset);
89154abd99SDavid du Colombier 		else if(NETTYPE(chan->qid.path) == Nstatqid)
90154abd99SDavid du Colombier 			ether->ifstat(ether, buf, 0, offset);
91154abd99SDavid du Colombier 	}
92154abd99SDavid du Colombier 
93154abd99SDavid du Colombier 	return netifread(ether, chan, buf, n, offset);
94154abd99SDavid du Colombier }
95154abd99SDavid du Colombier 
96154abd99SDavid du Colombier static Block*
etherbread(Chan * chan,long n,ulong offset)97154abd99SDavid du Colombier etherbread(Chan* chan, long n, ulong offset)
98154abd99SDavid du Colombier {
990d0cdc9eSDavid du Colombier 	return netifbread(etherxx[chan->dev], chan, n, offset);
100154abd99SDavid du Colombier }
101154abd99SDavid du Colombier 
102154abd99SDavid du Colombier static int
etherwstat(Chan * chan,uchar * dp,int n)103154abd99SDavid du Colombier etherwstat(Chan* chan, uchar* dp, int n)
104154abd99SDavid du Colombier {
1050d0cdc9eSDavid du Colombier 	return netifwstat(etherxx[chan->dev], chan, dp, n);
106154abd99SDavid du Colombier }
107154abd99SDavid du Colombier 
108154abd99SDavid du Colombier static void
etherrtrace(Netfile * f,Etherpkt * pkt,int len)109154abd99SDavid du Colombier etherrtrace(Netfile* f, Etherpkt* pkt, int len)
110154abd99SDavid du Colombier {
111154abd99SDavid du Colombier 	int i, n;
112154abd99SDavid du Colombier 	Block *bp;
113154abd99SDavid du Colombier 
1140d0cdc9eSDavid du Colombier 	if(qwindow(f->in) <= 0)
115154abd99SDavid du Colombier 		return;
116154abd99SDavid du Colombier 	if(len > 58)
117154abd99SDavid du Colombier 		n = 58;
118154abd99SDavid du Colombier 	else
119154abd99SDavid du Colombier 		n = len;
120154abd99SDavid du Colombier 	bp = iallocb(64);
121154abd99SDavid du Colombier 	if(bp == nil)
122154abd99SDavid du Colombier 		return;
123154abd99SDavid du Colombier 	memmove(bp->wp, pkt->d, n);
124154abd99SDavid du Colombier 	i = TK2MS(MACHP(0)->ticks);
125154abd99SDavid du Colombier 	bp->wp[58] = len>>8;
126154abd99SDavid du Colombier 	bp->wp[59] = len;
127154abd99SDavid du Colombier 	bp->wp[60] = i>>24;
128154abd99SDavid du Colombier 	bp->wp[61] = i>>16;
129154abd99SDavid du Colombier 	bp->wp[62] = i>>8;
130154abd99SDavid du Colombier 	bp->wp[63] = i;
131154abd99SDavid du Colombier 	bp->wp += 64;
1320d0cdc9eSDavid du Colombier 	qpass(f->in, bp);
133154abd99SDavid du Colombier }
134154abd99SDavid du Colombier 
135154abd99SDavid du Colombier Block*
etheriq(Ether * ether,Block * bp,int fromwire)136154abd99SDavid du Colombier etheriq(Ether* ether, Block* bp, int fromwire)
137154abd99SDavid du Colombier {
138154abd99SDavid du Colombier 	Etherpkt *pkt;
139154abd99SDavid du Colombier 	ushort type;
140154abd99SDavid du Colombier 	int len, multi, tome, fromme;
141154abd99SDavid du Colombier 	Netfile **ep, *f, **fp, *fx;
142154abd99SDavid du Colombier 	Block *xbp;
143154abd99SDavid du Colombier 
144154abd99SDavid du Colombier 	ether->inpackets++;
145154abd99SDavid du Colombier 
146154abd99SDavid du Colombier 	pkt = (Etherpkt*)bp->rp;
147154abd99SDavid du Colombier 	len = BLEN(bp);
148154abd99SDavid du Colombier 	type = (pkt->type[0]<<8)|pkt->type[1];
149154abd99SDavid du Colombier 	fx = 0;
150154abd99SDavid du Colombier 	ep = &ether->f[Ntypes];
151154abd99SDavid du Colombier 
152154abd99SDavid du Colombier 	multi = pkt->d[0] & 1;
153154abd99SDavid du Colombier 	/* check for valid multicast addresses */
154154abd99SDavid du Colombier 	if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
155154abd99SDavid du Colombier 		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
156154abd99SDavid du Colombier 			if(fromwire){
157154abd99SDavid du Colombier 				freeb(bp);
158154abd99SDavid du Colombier 				bp = 0;
159154abd99SDavid du Colombier 			}
160154abd99SDavid du Colombier 			return bp;
161154abd99SDavid du Colombier 		}
162154abd99SDavid du Colombier 	}
163154abd99SDavid du Colombier 
164154abd99SDavid du Colombier 	/* is it for me? */
165154abd99SDavid du Colombier 	tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
166154abd99SDavid du Colombier 	fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
167154abd99SDavid du Colombier 
168154abd99SDavid du Colombier 	/*
169154abd99SDavid du Colombier 	 * Multiplex the packet to all the connections which want it.
170154abd99SDavid du Colombier 	 * If the packet is not to be used subsequently (fromwire != 0),
171154abd99SDavid du Colombier 	 * attempt to simply pass it into one of the connections, thereby
172154abd99SDavid du Colombier 	 * saving a copy of the data (usual case hopefully).
173154abd99SDavid du Colombier 	 */
174154abd99SDavid du Colombier 	for(fp = ether->f; fp < ep; fp++){
175154abd99SDavid du Colombier 		if(f = *fp)
176154abd99SDavid du Colombier 		if(f->type == type || f->type < 0)
177154abd99SDavid du Colombier 		if(tome || multi || f->prom){
178154abd99SDavid du Colombier 			/* Don't want to hear bridged packets */
179154abd99SDavid du Colombier 			if(f->bridge && !fromwire && !fromme)
180154abd99SDavid du Colombier 				continue;
181154abd99SDavid du Colombier 			if(!f->headersonly){
182154abd99SDavid du Colombier 				if(fromwire && fx == 0)
183154abd99SDavid du Colombier 					fx = f;
184154abd99SDavid du Colombier 				else if(xbp = iallocb(len)){
185154abd99SDavid du Colombier 					memmove(xbp->wp, pkt, len);
186154abd99SDavid du Colombier 					xbp->wp += len;
1870d0cdc9eSDavid du Colombier 					if(qpass(f->in, xbp) < 0)
188154abd99SDavid du Colombier 						ether->soverflows++;
189154abd99SDavid du Colombier 				}
190154abd99SDavid du Colombier 				else
191154abd99SDavid du Colombier 					ether->soverflows++;
192154abd99SDavid du Colombier 			}
193154abd99SDavid du Colombier 			else
194154abd99SDavid du Colombier 				etherrtrace(f, pkt, len);
195154abd99SDavid du Colombier 		}
196154abd99SDavid du Colombier 	}
197154abd99SDavid du Colombier 
198154abd99SDavid du Colombier 	if(fx){
1990d0cdc9eSDavid du Colombier 		if(qpass(fx->in, bp) < 0)
200154abd99SDavid du Colombier 			ether->soverflows++;
201154abd99SDavid du Colombier 		return 0;
202154abd99SDavid du Colombier 	}
203154abd99SDavid du Colombier 	if(fromwire){
204154abd99SDavid du Colombier 		freeb(bp);
205154abd99SDavid du Colombier 		return 0;
206154abd99SDavid du Colombier 	}
207154abd99SDavid du Colombier 
208154abd99SDavid du Colombier 	return bp;
209154abd99SDavid du Colombier }
210154abd99SDavid du Colombier 
211154abd99SDavid du Colombier static int
etheroq(Ether * ether,Block * bp)212154abd99SDavid du Colombier etheroq(Ether* ether, Block* bp)
213154abd99SDavid du Colombier {
214154abd99SDavid du Colombier 	int len, loopback, s;
215154abd99SDavid du Colombier 	Etherpkt *pkt;
216154abd99SDavid du Colombier 
217154abd99SDavid du Colombier 	ether->outpackets++;
218154abd99SDavid du Colombier 
219154abd99SDavid du Colombier 	/*
220154abd99SDavid du Colombier 	 * Check if the packet has to be placed back onto the input queue,
221154abd99SDavid du Colombier 	 * i.e. if it's a loopback or broadcast packet or the interface is
222154abd99SDavid du Colombier 	 * in promiscuous mode.
223154abd99SDavid du Colombier 	 * If it's a loopback packet indicate to etheriq that the data isn't
224154abd99SDavid du Colombier 	 * needed and return, etheriq will pass-on or free the block.
225154abd99SDavid du Colombier 	 * To enable bridging to work, only packets that were originated
226154abd99SDavid du Colombier 	 * by this interface are fed back.
227154abd99SDavid du Colombier 	 */
228154abd99SDavid du Colombier 	pkt = (Etherpkt*)bp->rp;
229154abd99SDavid du Colombier 	len = BLEN(bp);
230154abd99SDavid du Colombier 	loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
231154abd99SDavid du Colombier 	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
232154abd99SDavid du Colombier 		s = splhi();
233154abd99SDavid du Colombier 		etheriq(ether, bp, 0);
234154abd99SDavid du Colombier 		splx(s);
235154abd99SDavid du Colombier 	}
236154abd99SDavid du Colombier 
237154abd99SDavid du Colombier 	if(!loopback){
238154abd99SDavid du Colombier 		qbwrite(ether->oq, bp);
239154abd99SDavid du Colombier 		if(ether->transmit != nil)
240154abd99SDavid du Colombier 			ether->transmit(ether);
241154abd99SDavid du Colombier 	} else
242154abd99SDavid du Colombier 		freeb(bp);
243154abd99SDavid du Colombier 
244154abd99SDavid du Colombier 	return len;
245154abd99SDavid du Colombier }
246154abd99SDavid du Colombier 
247154abd99SDavid du Colombier static long
etherwrite(Chan * chan,void * buf,long n,vlong)248154abd99SDavid du Colombier etherwrite(Chan* chan, void* buf, long n, vlong)
249154abd99SDavid du Colombier {
250154abd99SDavid du Colombier 	Ether *ether;
251154abd99SDavid du Colombier 	Block *bp;
252154abd99SDavid du Colombier 	int nn, onoff;
253154abd99SDavid du Colombier 	Cmdbuf *cb;
254154abd99SDavid du Colombier 
2550d0cdc9eSDavid du Colombier 	ether = etherxx[chan->dev];
256154abd99SDavid du Colombier 	if(NETTYPE(chan->qid.path) != Ndataqid) {
257154abd99SDavid du Colombier 		nn = netifwrite(ether, chan, buf, n);
258154abd99SDavid du Colombier 		if(nn >= 0)
259154abd99SDavid du Colombier 			return nn;
260154abd99SDavid du Colombier 		cb = parsecmd(buf, n);
261154abd99SDavid du Colombier 		if(strcmp(cb->f[0], "nonblocking") == 0){
262154abd99SDavid du Colombier 			if(cb->nf <= 1)
263154abd99SDavid du Colombier 				onoff = 1;
264154abd99SDavid du Colombier 			else
265154abd99SDavid du Colombier 				onoff = atoi(cb->f[1]);
266154abd99SDavid du Colombier 			qnoblock(ether->oq, onoff);
267154abd99SDavid du Colombier 			free(cb);
268154abd99SDavid du Colombier 			return n;
269154abd99SDavid du Colombier 		}
270154abd99SDavid du Colombier 		free(cb);
271154abd99SDavid du Colombier 		if(ether->ctl!=nil)
272154abd99SDavid du Colombier 			return ether->ctl(ether,buf,n);
273154abd99SDavid du Colombier 
274154abd99SDavid du Colombier 		error(Ebadctl);
275154abd99SDavid du Colombier 	}
276154abd99SDavid du Colombier 
277154abd99SDavid du Colombier 	if(n > ether->maxmtu)
278154abd99SDavid du Colombier 		error(Etoobig);
279154abd99SDavid du Colombier 	if(n < ether->minmtu)
280154abd99SDavid du Colombier 		error(Etoosmall);
281154abd99SDavid du Colombier 
282154abd99SDavid du Colombier 	bp = allocb(n);
283154abd99SDavid du Colombier 	if(waserror()){
284154abd99SDavid du Colombier 		freeb(bp);
285154abd99SDavid du Colombier 		nexterror();
286154abd99SDavid du Colombier 	}
287154abd99SDavid du Colombier 	memmove(bp->rp, buf, n);
288154abd99SDavid du Colombier 	memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
289154abd99SDavid du Colombier 	poperror();
290154abd99SDavid du Colombier 	bp->wp += n;
291154abd99SDavid du Colombier 
292154abd99SDavid du Colombier 	return etheroq(ether, bp);
293154abd99SDavid du Colombier }
294154abd99SDavid du Colombier 
295154abd99SDavid du Colombier static long
etherbwrite(Chan * chan,Block * bp,ulong)296154abd99SDavid du Colombier etherbwrite(Chan* chan, Block* bp, ulong)
297154abd99SDavid du Colombier {
298154abd99SDavid du Colombier 	Ether *ether;
299154abd99SDavid du Colombier 	long n;
300154abd99SDavid du Colombier 
301154abd99SDavid du Colombier 	n = BLEN(bp);
302154abd99SDavid du Colombier 	if(NETTYPE(chan->qid.path) != Ndataqid){
303154abd99SDavid du Colombier 		if(waserror()) {
304154abd99SDavid du Colombier 			freeb(bp);
305154abd99SDavid du Colombier 			nexterror();
306154abd99SDavid du Colombier 		}
307154abd99SDavid du Colombier 		n = etherwrite(chan, bp->rp, n, 0);
308154abd99SDavid du Colombier 		poperror();
309154abd99SDavid du Colombier 		freeb(bp);
310154abd99SDavid du Colombier 		return n;
311154abd99SDavid du Colombier 	}
3120d0cdc9eSDavid du Colombier 	ether = etherxx[chan->dev];
313154abd99SDavid du Colombier 
314154abd99SDavid du Colombier 	if(n > ether->maxmtu){
315154abd99SDavid du Colombier 		freeb(bp);
316154abd99SDavid du Colombier 		error(Etoobig);
317154abd99SDavid du Colombier 	}
318154abd99SDavid du Colombier 	if(n < ether->minmtu){
319154abd99SDavid du Colombier 		freeb(bp);
320154abd99SDavid du Colombier 		error(Etoosmall);
321154abd99SDavid du Colombier 	}
322154abd99SDavid du Colombier 
323154abd99SDavid du Colombier 	return etheroq(ether, bp);
324154abd99SDavid du Colombier }
325154abd99SDavid du Colombier 
326154abd99SDavid du Colombier static struct {
327154abd99SDavid du Colombier 	char*	type;
328154abd99SDavid du Colombier 	int	(*reset)(Ether*);
329154abd99SDavid du Colombier } cards[MaxEther+1];
330154abd99SDavid du Colombier 
331154abd99SDavid du Colombier void
addethercard(char * t,int (* r)(Ether *))332154abd99SDavid du Colombier addethercard(char* t, int (*r)(Ether*))
333154abd99SDavid du Colombier {
334154abd99SDavid du Colombier 	static int ncard;
335154abd99SDavid du Colombier 
336154abd99SDavid du Colombier 	if(ncard == MaxEther)
337154abd99SDavid du Colombier 		panic("too many ether cards");
338154abd99SDavid du Colombier 	cards[ncard].type = t;
339154abd99SDavid du Colombier 	cards[ncard].reset = r;
340154abd99SDavid du Colombier 	ncard++;
341154abd99SDavid du Colombier }
342154abd99SDavid du Colombier 
343154abd99SDavid du Colombier int
parseether(uchar * to,char * from)344154abd99SDavid du Colombier parseether(uchar *to, char *from)
345154abd99SDavid du Colombier {
346154abd99SDavid du Colombier 	char nip[4];
347154abd99SDavid du Colombier 	char *p;
348154abd99SDavid du Colombier 	int i;
349154abd99SDavid du Colombier 
350154abd99SDavid du Colombier 	p = from;
351154abd99SDavid du Colombier 	for(i = 0; i < Eaddrlen; i++){
352154abd99SDavid du Colombier 		if(*p == 0)
353154abd99SDavid du Colombier 			return -1;
354154abd99SDavid du Colombier 		nip[0] = *p++;
355154abd99SDavid du Colombier 		if(*p == 0)
356154abd99SDavid du Colombier 			return -1;
357154abd99SDavid du Colombier 		nip[1] = *p++;
358154abd99SDavid du Colombier 		nip[2] = 0;
359154abd99SDavid du Colombier 		to[i] = strtoul(nip, 0, 16);
360154abd99SDavid du Colombier 		if(*p == ':')
361154abd99SDavid du Colombier 			p++;
362154abd99SDavid du Colombier 	}
363154abd99SDavid du Colombier 	return 0;
364154abd99SDavid du Colombier }
365154abd99SDavid du Colombier 
366154abd99SDavid du Colombier static void
etherreset(void)367154abd99SDavid du Colombier etherreset(void)
368154abd99SDavid du Colombier {
369154abd99SDavid du Colombier 	Ether *ether;
370154abd99SDavid du Colombier 	int i, n, ctlrno;
371154abd99SDavid du Colombier 	char name[KNAMELEN], buf[128];
372154abd99SDavid du Colombier 
373154abd99SDavid du Colombier 	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
374154abd99SDavid du Colombier 		if(ether == 0)
375154abd99SDavid du Colombier 			ether = malloc(sizeof(Ether));
376*7ae8f453SDavid du Colombier 		if(ether == 0)
377*7ae8f453SDavid du Colombier 			panic("etherreset: no memory");
378154abd99SDavid du Colombier 		memset(ether, 0, sizeof(Ether));
379154abd99SDavid du Colombier 		ether->ctlrno = ctlrno;
380154abd99SDavid du Colombier 		ether->mbps = 10;
381154abd99SDavid du Colombier 		ether->minmtu = ETHERMINTU;
382154abd99SDavid du Colombier 		ether->maxmtu = ETHERMAXTU;
383154abd99SDavid du Colombier 
384154abd99SDavid du Colombier 		if(archether(ctlrno, ether) <= 0)
385154abd99SDavid du Colombier 			continue;
386154abd99SDavid du Colombier 
387154abd99SDavid du Colombier 		for(n = 0; cards[n].type; n++){
388154abd99SDavid du Colombier 			if(cistrcmp(cards[n].type, ether->type))
389154abd99SDavid du Colombier 				continue;
390154abd99SDavid du Colombier 			for(i = 0; i < ether->nopt; i++){
391154abd99SDavid du Colombier 				if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
392154abd99SDavid du Colombier 					if(parseether(ether->ea, &ether->opt[i][3]) == -1)
393154abd99SDavid du Colombier 						memset(ether->ea, 0, Eaddrlen);
394154abd99SDavid du Colombier 				}else if(cistrcmp(ether->opt[i], "fullduplex") == 0 ||
395154abd99SDavid du Colombier 					cistrcmp(ether->opt[i], "10BASE-TFD") == 0)
396154abd99SDavid du Colombier 					ether->fullduplex = 1;
397154abd99SDavid du Colombier 				else if(cistrcmp(ether->opt[i], "100BASE-TXFD") == 0)
398154abd99SDavid du Colombier 					ether->mbps = 100;
399154abd99SDavid du Colombier 			}
400154abd99SDavid du Colombier 			if(cards[n].reset(ether))
401154abd99SDavid du Colombier 				break;
402154abd99SDavid du Colombier 			snprint(name, sizeof(name), "ether%d", ctlrno);
403154abd99SDavid du Colombier 
404154abd99SDavid du Colombier 			if(ether->interrupt != nil)
405154abd99SDavid du Colombier 				intrenable(Irqlo, ether->irq, ether->interrupt,
406154abd99SDavid du Colombier 					ether, name);
407154abd99SDavid du Colombier 
408ab6ce076SDavid du Colombier 			i = snprint(buf, sizeof buf,
409ab6ce076SDavid du Colombier 				"#l%d: %s: %dMbps port %#lux irq %d",
410154abd99SDavid du Colombier 				ctlrno, ether->type, ether->mbps, ether->port,
411154abd99SDavid du Colombier 				ether->irq);
412154abd99SDavid du Colombier 			if(ether->mem)
413ab6ce076SDavid du Colombier 				i += snprint(buf+i, sizeof buf - i,
414ab6ce076SDavid du Colombier 					" addr %#lux", PADDR(ether->mem));
415154abd99SDavid du Colombier 			if(ether->size)
416ab6ce076SDavid du Colombier 				i += snprint(buf+i, sizeof buf - i,
4179f2e9820SDavid du Colombier 					" size %#luX", ether->size);
418ab6ce076SDavid du Colombier 			i += snprint(buf+i, sizeof buf - i,
419ab6ce076SDavid du Colombier 				": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
420154abd99SDavid du Colombier 				ether->ea[0], ether->ea[1], ether->ea[2],
421154abd99SDavid du Colombier 				ether->ea[3], ether->ea[4], ether->ea[5]);
422ab6ce076SDavid du Colombier 			snprint(buf+i, sizeof buf - i, "\n");
423154abd99SDavid du Colombier 			print("%s", buf);
424154abd99SDavid du Colombier 
425154abd99SDavid du Colombier 			if(ether->mbps >= 1000)
426154abd99SDavid du Colombier 				netifinit(ether, name, Ntypes, 4*1024*1024);
427154abd99SDavid du Colombier 			else if(ether->mbps >= 100)
428154abd99SDavid du Colombier 				netifinit(ether, name, Ntypes, 1024*1024);
429154abd99SDavid du Colombier 			else
430154abd99SDavid du Colombier 				netifinit(ether, name, Ntypes, 65*1024);
431154abd99SDavid du Colombier 			if(ether->oq == 0)
432154abd99SDavid du Colombier 				ether->oq = qopen(ether->limit, Qmsg, 0, 0);
433154abd99SDavid du Colombier 			if(ether->oq == 0)
434154abd99SDavid du Colombier 				panic("etherreset %s", name);
435154abd99SDavid du Colombier 			ether->alen = Eaddrlen;
436154abd99SDavid du Colombier 			memmove(ether->addr, ether->ea, Eaddrlen);
437154abd99SDavid du Colombier 			memset(ether->bcast, 0xFF, Eaddrlen);
438154abd99SDavid du Colombier 
439154abd99SDavid du Colombier 			etherxx[ctlrno] = ether;
440154abd99SDavid du Colombier 			ether = 0;
441154abd99SDavid du Colombier 			break;
442154abd99SDavid du Colombier 		}
443154abd99SDavid du Colombier 	}
444154abd99SDavid du Colombier 	if(ether)
445154abd99SDavid du Colombier 		free(ether);
446154abd99SDavid du Colombier }
447154abd99SDavid du Colombier 
448154abd99SDavid du Colombier static void
ethershutdown(void)449154abd99SDavid du Colombier ethershutdown(void)
450154abd99SDavid du Colombier {
451154abd99SDavid du Colombier 	Ether *ether;
452154abd99SDavid du Colombier 	int i;
453154abd99SDavid du Colombier 
454154abd99SDavid du Colombier 	for(i = 0; i < MaxEther; i++){
455154abd99SDavid du Colombier 		ether = etherxx[i];
456154abd99SDavid du Colombier 		if(ether == nil)
457154abd99SDavid du Colombier 			continue;
458154abd99SDavid du Colombier 		if(ether->shutdown == nil) {
459154abd99SDavid du Colombier 			print("#l%d: no shutdown function\n", i);
460154abd99SDavid du Colombier 			continue;
461154abd99SDavid du Colombier 		}
462154abd99SDavid du Colombier 		(*ether->shutdown)(ether);
463154abd99SDavid du Colombier 	}
464154abd99SDavid du Colombier }
465154abd99SDavid du Colombier 
466154abd99SDavid du Colombier #define POLY 0xedb88320
467154abd99SDavid du Colombier 
468154abd99SDavid du Colombier /* really slow 32 bit crc for ethers */
469154abd99SDavid du Colombier ulong
ethercrc(uchar * p,int len)470154abd99SDavid du Colombier ethercrc(uchar *p, int len)
471154abd99SDavid du Colombier {
472154abd99SDavid du Colombier 	int i, j;
473154abd99SDavid du Colombier 	ulong crc, b;
474154abd99SDavid du Colombier 
475154abd99SDavid du Colombier 	crc = 0xffffffff;
476154abd99SDavid du Colombier 	for(i = 0; i < len; i++){
477154abd99SDavid du Colombier 		b = *p++;
478154abd99SDavid du Colombier 		for(j = 0; j < 8; j++){
479154abd99SDavid du Colombier 			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
480154abd99SDavid du Colombier 			b >>= 1;
481154abd99SDavid du Colombier 		}
482154abd99SDavid du Colombier 	}
483154abd99SDavid du Colombier 	return crc;
484154abd99SDavid du Colombier }
485154abd99SDavid du Colombier 
486154abd99SDavid du Colombier void
dumpoq(Queue * oq)487154abd99SDavid du Colombier dumpoq(Queue *oq)
488154abd99SDavid du Colombier {
489154abd99SDavid du Colombier 	if (oq == nil)
490154abd99SDavid du Colombier 		print("no outq! ");
491154abd99SDavid du Colombier 	else if (qisclosed(oq))
492154abd99SDavid du Colombier 		print("outq closed ");
493154abd99SDavid du Colombier 	else if (qfull(oq))
494154abd99SDavid du Colombier 		print("outq full ");
495154abd99SDavid du Colombier 	else
496154abd99SDavid du Colombier 		print("outq %d ", qlen(oq));
497154abd99SDavid du Colombier }
498154abd99SDavid du Colombier 
499154abd99SDavid du Colombier void
dumpnetif(Netif * netif)500154abd99SDavid du Colombier dumpnetif(Netif *netif)
501154abd99SDavid du Colombier {
502154abd99SDavid du Colombier 	print("netif %s ", netif->name);
503154abd99SDavid du Colombier 	print("limit %d mbps %d link %d ",
504154abd99SDavid du Colombier 		netif->limit, netif->mbps, netif->link);
505154abd99SDavid du Colombier 	print("inpkts %lld outpkts %lld errs %d\n",
506154abd99SDavid du Colombier 		netif->inpackets, netif->outpackets,
507154abd99SDavid du Colombier 		netif->crcs + netif->oerrs + netif->frames + netif->overflows +
508154abd99SDavid du Colombier 		netif->buffs + netif->soverflows);
509154abd99SDavid du Colombier }
510154abd99SDavid du Colombier 
511154abd99SDavid du Colombier Dev etherdevtab = {
512154abd99SDavid du Colombier 	'l',
513154abd99SDavid du Colombier 	"ether",
514154abd99SDavid du Colombier 
515154abd99SDavid du Colombier 	etherreset,
516154abd99SDavid du Colombier 	devinit,
517154abd99SDavid du Colombier 	ethershutdown,
518154abd99SDavid du Colombier 	etherattach,
519154abd99SDavid du Colombier 	etherwalk,
520154abd99SDavid du Colombier 	etherstat,
521154abd99SDavid du Colombier 	etheropen,
522154abd99SDavid du Colombier 	ethercreate,
523154abd99SDavid du Colombier 	etherclose,
524154abd99SDavid du Colombier 	etherread,
525154abd99SDavid du Colombier 	etherbread,
526154abd99SDavid du Colombier 	etherwrite,
527154abd99SDavid du Colombier 	etherbwrite,
528154abd99SDavid du Colombier 	devremove,
529154abd99SDavid du Colombier 	etherwstat,
530154abd99SDavid du Colombier };
531