xref: /plan9-contrib/sys/src/9/loongson/devether.c (revision a81c3ea0c7f009a3088ab7fe55ea9013d9d77a74)
1*a81c3ea0SDavid du Colombier #include "u.h"
2*a81c3ea0SDavid du Colombier #include "../port/lib.h"
3*a81c3ea0SDavid du Colombier #include "mem.h"
4*a81c3ea0SDavid du Colombier #include "dat.h"
5*a81c3ea0SDavid du Colombier #include "fns.h"
6*a81c3ea0SDavid du Colombier #include "io.h"
7*a81c3ea0SDavid du Colombier #include "../port/error.h"
8*a81c3ea0SDavid du Colombier 
9*a81c3ea0SDavid du Colombier #include "../port/netif.h"
10*a81c3ea0SDavid du Colombier #include "etherif.h"
11*a81c3ea0SDavid du Colombier 
12*a81c3ea0SDavid du Colombier extern int archether(unsigned ctlno, Ether *ether);
13*a81c3ea0SDavid du Colombier 
14*a81c3ea0SDavid du Colombier static Ether *etherxx[MaxEther];
15*a81c3ea0SDavid du Colombier 
16*a81c3ea0SDavid du Colombier Chan*
etherattach(char * spec)17*a81c3ea0SDavid du Colombier etherattach(char* spec)
18*a81c3ea0SDavid du Colombier {
19*a81c3ea0SDavid du Colombier 	int ctlrno;
20*a81c3ea0SDavid du Colombier 	char *p;
21*a81c3ea0SDavid du Colombier 	Chan *chan;
22*a81c3ea0SDavid du Colombier 
23*a81c3ea0SDavid du Colombier 	ctlrno = 0;
24*a81c3ea0SDavid du Colombier 	if(spec && *spec){
25*a81c3ea0SDavid du Colombier 		ctlrno = strtoul(spec, &p, 0);
26*a81c3ea0SDavid du Colombier 		if((ctlrno == 0 && p == spec) || *p != 0)
27*a81c3ea0SDavid du Colombier 			error(Ebadarg);
28*a81c3ea0SDavid du Colombier 		if(ctlrno < 0 || ctlrno >= MaxEther)
29*a81c3ea0SDavid du Colombier 			error(Ebadarg);
30*a81c3ea0SDavid du Colombier 	}
31*a81c3ea0SDavid du Colombier 	if(etherxx[ctlrno] == 0)
32*a81c3ea0SDavid du Colombier 		error(Enodev);
33*a81c3ea0SDavid du Colombier 
34*a81c3ea0SDavid du Colombier 	chan = devattach('l', spec);
35*a81c3ea0SDavid du Colombier 	if(waserror()){
36*a81c3ea0SDavid du Colombier 		chanfree(chan);
37*a81c3ea0SDavid du Colombier 		nexterror();
38*a81c3ea0SDavid du Colombier 	}
39*a81c3ea0SDavid du Colombier 	chan->dev = ctlrno;
40*a81c3ea0SDavid du Colombier 	if(etherxx[ctlrno]->attach)
41*a81c3ea0SDavid du Colombier 		etherxx[ctlrno]->attach(etherxx[ctlrno]);
42*a81c3ea0SDavid du Colombier 	poperror();
43*a81c3ea0SDavid du Colombier 	return chan;
44*a81c3ea0SDavid du Colombier }
45*a81c3ea0SDavid du Colombier 
46*a81c3ea0SDavid du Colombier static Walkqid*
etherwalk(Chan * chan,Chan * nchan,char ** name,int nname)47*a81c3ea0SDavid du Colombier etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
48*a81c3ea0SDavid du Colombier {
49*a81c3ea0SDavid du Colombier 	return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
50*a81c3ea0SDavid du Colombier }
51*a81c3ea0SDavid du Colombier 
52*a81c3ea0SDavid du Colombier static int
etherstat(Chan * chan,uchar * dp,int n)53*a81c3ea0SDavid du Colombier etherstat(Chan* chan, uchar* dp, int n)
54*a81c3ea0SDavid du Colombier {
55*a81c3ea0SDavid du Colombier 	return netifstat(etherxx[chan->dev], chan, dp, n);
56*a81c3ea0SDavid du Colombier }
57*a81c3ea0SDavid du Colombier 
58*a81c3ea0SDavid du Colombier static Chan*
etheropen(Chan * chan,int omode)59*a81c3ea0SDavid du Colombier etheropen(Chan* chan, int omode)
60*a81c3ea0SDavid du Colombier {
61*a81c3ea0SDavid du Colombier 	return netifopen(etherxx[chan->dev], chan, omode);
62*a81c3ea0SDavid du Colombier }
63*a81c3ea0SDavid du Colombier 
64*a81c3ea0SDavid du Colombier static void
ethercreate(Chan *,char *,int,ulong)65*a81c3ea0SDavid du Colombier ethercreate(Chan*, char*, int, ulong)
66*a81c3ea0SDavid du Colombier {
67*a81c3ea0SDavid du Colombier }
68*a81c3ea0SDavid du Colombier 
69*a81c3ea0SDavid du Colombier static void
etherclose(Chan * chan)70*a81c3ea0SDavid du Colombier etherclose(Chan* chan)
71*a81c3ea0SDavid du Colombier {
72*a81c3ea0SDavid du Colombier 	netifclose(etherxx[chan->dev], chan);
73*a81c3ea0SDavid du Colombier }
74*a81c3ea0SDavid du Colombier 
75*a81c3ea0SDavid du Colombier static long
etherread(Chan * chan,void * buf,long n,vlong off)76*a81c3ea0SDavid du Colombier etherread(Chan* chan, void* buf, long n, vlong off)
77*a81c3ea0SDavid du Colombier {
78*a81c3ea0SDavid du Colombier 	Ether *ether;
79*a81c3ea0SDavid du Colombier 	ulong offset = off;
80*a81c3ea0SDavid du Colombier 
81*a81c3ea0SDavid du Colombier 	ether = etherxx[chan->dev];
82*a81c3ea0SDavid du Colombier 	if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
83*a81c3ea0SDavid du Colombier 		/*
84*a81c3ea0SDavid du Colombier 		 * With some controllers it is necessary to reach
85*a81c3ea0SDavid du Colombier 		 * into the chip to extract statistics.
86*a81c3ea0SDavid du Colombier 		 */
87*a81c3ea0SDavid du Colombier 		if(NETTYPE(chan->qid.path) == Nifstatqid)
88*a81c3ea0SDavid du Colombier 			return ether->ifstat(ether, buf, n, offset);
89*a81c3ea0SDavid du Colombier 		else if(NETTYPE(chan->qid.path) == Nstatqid)
90*a81c3ea0SDavid du Colombier 			ether->ifstat(ether, buf, 0, offset);
91*a81c3ea0SDavid du Colombier 	}
92*a81c3ea0SDavid du Colombier 
93*a81c3ea0SDavid du Colombier 	return netifread(ether, chan, buf, n, offset);
94*a81c3ea0SDavid du Colombier }
95*a81c3ea0SDavid du Colombier 
96*a81c3ea0SDavid du Colombier static Block*
etherbread(Chan * chan,long n,ulong offset)97*a81c3ea0SDavid du Colombier etherbread(Chan* chan, long n, ulong offset)
98*a81c3ea0SDavid du Colombier {
99*a81c3ea0SDavid du Colombier 	return netifbread(etherxx[chan->dev], chan, n, offset);
100*a81c3ea0SDavid du Colombier }
101*a81c3ea0SDavid du Colombier 
102*a81c3ea0SDavid du Colombier static int
etherwstat(Chan * chan,uchar * dp,int n)103*a81c3ea0SDavid du Colombier etherwstat(Chan* chan, uchar* dp, int n)
104*a81c3ea0SDavid du Colombier {
105*a81c3ea0SDavid du Colombier 	return netifwstat(etherxx[chan->dev], chan, dp, n);
106*a81c3ea0SDavid du Colombier }
107*a81c3ea0SDavid du Colombier 
108*a81c3ea0SDavid du Colombier static void
etherrtrace(Netfile * f,Etherpkt * pkt,int len)109*a81c3ea0SDavid du Colombier etherrtrace(Netfile* f, Etherpkt* pkt, int len)
110*a81c3ea0SDavid du Colombier {
111*a81c3ea0SDavid du Colombier 	int i, n;
112*a81c3ea0SDavid du Colombier 	Block *bp;
113*a81c3ea0SDavid du Colombier 
114*a81c3ea0SDavid du Colombier 	if(qwindow(f->in) <= 0)
115*a81c3ea0SDavid du Colombier 		return;
116*a81c3ea0SDavid du Colombier 	if(len > 58)
117*a81c3ea0SDavid du Colombier 		n = 58;
118*a81c3ea0SDavid du Colombier 	else
119*a81c3ea0SDavid du Colombier 		n = len;
120*a81c3ea0SDavid du Colombier 	bp = iallocb(64);
121*a81c3ea0SDavid du Colombier 	if(bp == nil)
122*a81c3ea0SDavid du Colombier 		return;
123*a81c3ea0SDavid du Colombier 	memmove(bp->wp, pkt->d, n);
124*a81c3ea0SDavid du Colombier 	i = TK2MS(MACHP(0)->ticks);
125*a81c3ea0SDavid du Colombier 	bp->wp[58] = len>>8;
126*a81c3ea0SDavid du Colombier 	bp->wp[59] = len;
127*a81c3ea0SDavid du Colombier 	bp->wp[60] = i>>24;
128*a81c3ea0SDavid du Colombier 	bp->wp[61] = i>>16;
129*a81c3ea0SDavid du Colombier 	bp->wp[62] = i>>8;
130*a81c3ea0SDavid du Colombier 	bp->wp[63] = i;
131*a81c3ea0SDavid du Colombier 	bp->wp += 64;
132*a81c3ea0SDavid du Colombier 	qpass(f->in, bp);
133*a81c3ea0SDavid du Colombier }
134*a81c3ea0SDavid du Colombier 
135*a81c3ea0SDavid du Colombier Block*
etheriq(Ether * ether,Block * bp,int fromwire)136*a81c3ea0SDavid du Colombier etheriq(Ether* ether, Block* bp, int fromwire)
137*a81c3ea0SDavid du Colombier {
138*a81c3ea0SDavid du Colombier 	Etherpkt *pkt;
139*a81c3ea0SDavid du Colombier 	ushort type;
140*a81c3ea0SDavid du Colombier 	int len, multi, tome, fromme;
141*a81c3ea0SDavid du Colombier 	Netfile **ep, *f, **fp, *fx;
142*a81c3ea0SDavid du Colombier 	Block *xbp;
143*a81c3ea0SDavid du Colombier 
144*a81c3ea0SDavid du Colombier 	ether->inpackets++;
145*a81c3ea0SDavid du Colombier 
146*a81c3ea0SDavid du Colombier 	pkt = (Etherpkt*)bp->rp;
147*a81c3ea0SDavid du Colombier 	len = BLEN(bp);
148*a81c3ea0SDavid du Colombier 	type = (pkt->type[0]<<8)|pkt->type[1];
149*a81c3ea0SDavid du Colombier 	fx = 0;
150*a81c3ea0SDavid du Colombier 	ep = &ether->f[Ntypes];
151*a81c3ea0SDavid du Colombier 
152*a81c3ea0SDavid du Colombier 	multi = pkt->d[0] & 1;
153*a81c3ea0SDavid du Colombier 	/* check for valid multicast addresses */
154*a81c3ea0SDavid du Colombier 	if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 &&
155*a81c3ea0SDavid du Colombier 	    ether->prom == 0){
156*a81c3ea0SDavid du Colombier 		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
157*a81c3ea0SDavid du Colombier 			if(fromwire){
158*a81c3ea0SDavid du Colombier 				freeb(bp);
159*a81c3ea0SDavid du Colombier 				bp = 0;
160*a81c3ea0SDavid du Colombier 			}
161*a81c3ea0SDavid du Colombier 			return bp;
162*a81c3ea0SDavid du Colombier 		}
163*a81c3ea0SDavid du Colombier 	}
164*a81c3ea0SDavid du Colombier 	/* is it for me? */
165*a81c3ea0SDavid du Colombier 	tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
166*a81c3ea0SDavid du Colombier 	fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
167*a81c3ea0SDavid du Colombier 
168*a81c3ea0SDavid du Colombier 	/*
169*a81c3ea0SDavid du Colombier 	 * Multiplex the packet to all the connections which want it.
170*a81c3ea0SDavid du Colombier 	 * If the packet is not to be used subsequently (fromwire != 0),
171*a81c3ea0SDavid du Colombier 	 * attempt to simply pass it into one of the connections, thereby
172*a81c3ea0SDavid du Colombier 	 * saving a copy of the data (usual case hopefully).
173*a81c3ea0SDavid du Colombier 	 */
174*a81c3ea0SDavid du Colombier 	for(fp = ether->f; fp < ep; fp++){
175*a81c3ea0SDavid du Colombier 		if((f = *fp) != nil && (f->type == type || f->type < 0) &&
176*a81c3ea0SDavid du Colombier 		    (tome || multi || f->prom)){
177*a81c3ea0SDavid du Colombier 			/* Don't want to hear bridged packets */
178*a81c3ea0SDavid du Colombier 			if(f->bridge && !fromwire && !fromme)
179*a81c3ea0SDavid du Colombier 				continue;
180*a81c3ea0SDavid du Colombier 			if(!f->headersonly){
181*a81c3ea0SDavid du Colombier 				if(fromwire && fx == 0)
182*a81c3ea0SDavid du Colombier 					fx = f;
183*a81c3ea0SDavid du Colombier 				else if(xbp = iallocb(len)){
184*a81c3ea0SDavid du Colombier 					memmove(xbp->wp, pkt, len);
185*a81c3ea0SDavid du Colombier 					xbp->wp += len;
186*a81c3ea0SDavid du Colombier 					if(qpass(f->in, xbp) < 0)
187*a81c3ea0SDavid du Colombier 						ether->soverflows++;
188*a81c3ea0SDavid du Colombier 				}
189*a81c3ea0SDavid du Colombier 				else
190*a81c3ea0SDavid du Colombier 					ether->soverflows++;
191*a81c3ea0SDavid du Colombier 			}
192*a81c3ea0SDavid du Colombier 			else
193*a81c3ea0SDavid du Colombier 				etherrtrace(f, pkt, len);
194*a81c3ea0SDavid du Colombier 		}
195*a81c3ea0SDavid du Colombier 	}
196*a81c3ea0SDavid du Colombier 
197*a81c3ea0SDavid du Colombier 	if(fx){
198*a81c3ea0SDavid du Colombier 		if(qpass(fx->in, bp) < 0)
199*a81c3ea0SDavid du Colombier 			ether->soverflows++;
200*a81c3ea0SDavid du Colombier 		return 0;
201*a81c3ea0SDavid du Colombier 	}
202*a81c3ea0SDavid du Colombier 	if(fromwire){
203*a81c3ea0SDavid du Colombier 		freeb(bp);
204*a81c3ea0SDavid du Colombier 		return 0;
205*a81c3ea0SDavid du Colombier 	}
206*a81c3ea0SDavid du Colombier 	return bp;
207*a81c3ea0SDavid du Colombier }
208*a81c3ea0SDavid du Colombier 
209*a81c3ea0SDavid du Colombier static int
etheroq(Ether * ether,Block * bp)210*a81c3ea0SDavid du Colombier etheroq(Ether* ether, Block* bp)
211*a81c3ea0SDavid du Colombier {
212*a81c3ea0SDavid du Colombier 	int len, loopback, s;
213*a81c3ea0SDavid du Colombier 	Etherpkt *pkt;
214*a81c3ea0SDavid du Colombier 
215*a81c3ea0SDavid du Colombier 	ether->outpackets++;
216*a81c3ea0SDavid du Colombier 
217*a81c3ea0SDavid du Colombier 	/*
218*a81c3ea0SDavid du Colombier 	 * Check if the packet has to be placed back onto the input queue,
219*a81c3ea0SDavid du Colombier 	 * i.e. if it's a loopback or broadcast packet or the interface is
220*a81c3ea0SDavid du Colombier 	 * in promiscuous mode.
221*a81c3ea0SDavid du Colombier 	 * If it's a loopback packet indicate to etheriq that the data isn't
222*a81c3ea0SDavid du Colombier 	 * needed and return, etheriq will pass-on or free the block.
223*a81c3ea0SDavid du Colombier 	 * To enable bridging to work, only packets that were originated
224*a81c3ea0SDavid du Colombier 	 * by this interface are fed back.
225*a81c3ea0SDavid du Colombier 	 */
226*a81c3ea0SDavid du Colombier 	pkt = (Etherpkt*)bp->rp;
227*a81c3ea0SDavid du Colombier 	len = BLEN(bp);
228*a81c3ea0SDavid du Colombier 	loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
229*a81c3ea0SDavid du Colombier 	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
230*a81c3ea0SDavid du Colombier 		s = splhi();
231*a81c3ea0SDavid du Colombier 		etheriq(ether, bp, 0);
232*a81c3ea0SDavid du Colombier 		splx(s);
233*a81c3ea0SDavid du Colombier 	}
234*a81c3ea0SDavid du Colombier 
235*a81c3ea0SDavid du Colombier 	if(!loopback){
236*a81c3ea0SDavid du Colombier 		qbwrite(ether->oq, bp);
237*a81c3ea0SDavid du Colombier 		if(ether->transmit != nil)
238*a81c3ea0SDavid du Colombier 			ether->transmit(ether);
239*a81c3ea0SDavid du Colombier 	} else
240*a81c3ea0SDavid du Colombier 		freeb(bp);
241*a81c3ea0SDavid du Colombier 
242*a81c3ea0SDavid du Colombier 	return len;
243*a81c3ea0SDavid du Colombier }
244*a81c3ea0SDavid du Colombier 
245*a81c3ea0SDavid du Colombier static long
etherwrite(Chan * chan,void * buf,long n,vlong)246*a81c3ea0SDavid du Colombier etherwrite(Chan* chan, void* buf, long n, vlong)
247*a81c3ea0SDavid du Colombier {
248*a81c3ea0SDavid du Colombier 	Ether *ether;
249*a81c3ea0SDavid du Colombier 	Block *bp;
250*a81c3ea0SDavid du Colombier 	int nn, onoff;
251*a81c3ea0SDavid du Colombier 	Cmdbuf *cb;
252*a81c3ea0SDavid du Colombier 
253*a81c3ea0SDavid du Colombier 	ether = etherxx[chan->dev];
254*a81c3ea0SDavid du Colombier 	if(NETTYPE(chan->qid.path) != Ndataqid) {
255*a81c3ea0SDavid du Colombier 		nn = netifwrite(ether, chan, buf, n);
256*a81c3ea0SDavid du Colombier 		if(nn >= 0)
257*a81c3ea0SDavid du Colombier 			return nn;
258*a81c3ea0SDavid du Colombier 		cb = parsecmd(buf, n);
259*a81c3ea0SDavid du Colombier 		if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
260*a81c3ea0SDavid du Colombier 			if(cb->nf <= 1)
261*a81c3ea0SDavid du Colombier 				onoff = 1;
262*a81c3ea0SDavid du Colombier 			else
263*a81c3ea0SDavid du Colombier 				onoff = atoi(cb->f[1]);
264*a81c3ea0SDavid du Colombier 			qnoblock(ether->oq, onoff);
265*a81c3ea0SDavid du Colombier 			free(cb);
266*a81c3ea0SDavid du Colombier 			return n;
267*a81c3ea0SDavid du Colombier 		}
268*a81c3ea0SDavid du Colombier 		free(cb);
269*a81c3ea0SDavid du Colombier 		if(ether->ctl!=nil)
270*a81c3ea0SDavid du Colombier 			return ether->ctl(ether,buf,n);
271*a81c3ea0SDavid du Colombier 
272*a81c3ea0SDavid du Colombier 		error(Ebadctl);
273*a81c3ea0SDavid du Colombier 	}
274*a81c3ea0SDavid du Colombier 
275*a81c3ea0SDavid du Colombier 	if(n > ether->maxmtu)
276*a81c3ea0SDavid du Colombier 		error(Etoobig);
277*a81c3ea0SDavid du Colombier 	if(n < ether->minmtu)
278*a81c3ea0SDavid du Colombier 		error(Etoosmall);
279*a81c3ea0SDavid du Colombier 
280*a81c3ea0SDavid du Colombier 	bp = allocb(n);
281*a81c3ea0SDavid du Colombier 	if(waserror()){
282*a81c3ea0SDavid du Colombier 		freeb(bp);
283*a81c3ea0SDavid du Colombier 		nexterror();
284*a81c3ea0SDavid du Colombier 	}
285*a81c3ea0SDavid du Colombier 	memmove(bp->rp, buf, n);
286*a81c3ea0SDavid du Colombier 	memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
287*a81c3ea0SDavid du Colombier 	poperror();
288*a81c3ea0SDavid du Colombier 	bp->wp += n;
289*a81c3ea0SDavid du Colombier 
290*a81c3ea0SDavid du Colombier 	return etheroq(ether, bp);
291*a81c3ea0SDavid du Colombier }
292*a81c3ea0SDavid du Colombier 
293*a81c3ea0SDavid du Colombier static long
etherbwrite(Chan * chan,Block * bp,ulong)294*a81c3ea0SDavid du Colombier etherbwrite(Chan* chan, Block* bp, ulong)
295*a81c3ea0SDavid du Colombier {
296*a81c3ea0SDavid du Colombier 	Ether *ether;
297*a81c3ea0SDavid du Colombier 	long n;
298*a81c3ea0SDavid du Colombier 
299*a81c3ea0SDavid du Colombier 	n = BLEN(bp);
300*a81c3ea0SDavid du Colombier 	if(NETTYPE(chan->qid.path) != Ndataqid){
301*a81c3ea0SDavid du Colombier 		if(waserror()) {
302*a81c3ea0SDavid du Colombier 			freeb(bp);
303*a81c3ea0SDavid du Colombier 			nexterror();
304*a81c3ea0SDavid du Colombier 		}
305*a81c3ea0SDavid du Colombier 		n = etherwrite(chan, bp->rp, n, 0);
306*a81c3ea0SDavid du Colombier 		poperror();
307*a81c3ea0SDavid du Colombier 		freeb(bp);
308*a81c3ea0SDavid du Colombier 		return n;
309*a81c3ea0SDavid du Colombier 	}
310*a81c3ea0SDavid du Colombier 	ether = etherxx[chan->dev];
311*a81c3ea0SDavid du Colombier 
312*a81c3ea0SDavid du Colombier 	if(n > ether->maxmtu){
313*a81c3ea0SDavid du Colombier 		freeb(bp);
314*a81c3ea0SDavid du Colombier 		error(Etoobig);
315*a81c3ea0SDavid du Colombier 	}
316*a81c3ea0SDavid du Colombier 	if(n < ether->minmtu){
317*a81c3ea0SDavid du Colombier 		freeb(bp);
318*a81c3ea0SDavid du Colombier 		error(Etoosmall);
319*a81c3ea0SDavid du Colombier 	}
320*a81c3ea0SDavid du Colombier 
321*a81c3ea0SDavid du Colombier 	return etheroq(ether, bp);
322*a81c3ea0SDavid du Colombier }
323*a81c3ea0SDavid du Colombier 
324*a81c3ea0SDavid du Colombier static struct {
325*a81c3ea0SDavid du Colombier 	char*	type;
326*a81c3ea0SDavid du Colombier 	int	(*reset)(Ether*);
327*a81c3ea0SDavid du Colombier } cards[MaxEther+1];
328*a81c3ea0SDavid du Colombier 
329*a81c3ea0SDavid du Colombier void
addethercard(char * t,int (* r)(Ether *))330*a81c3ea0SDavid du Colombier addethercard(char* t, int (*r)(Ether*))
331*a81c3ea0SDavid du Colombier {
332*a81c3ea0SDavid du Colombier 	static int ncard;
333*a81c3ea0SDavid du Colombier 
334*a81c3ea0SDavid du Colombier 	if(ncard == MaxEther)
335*a81c3ea0SDavid du Colombier 		panic("too many ether cards");
336*a81c3ea0SDavid du Colombier 	cards[ncard].type = t;
337*a81c3ea0SDavid du Colombier 	cards[ncard].reset = r;
338*a81c3ea0SDavid du Colombier 	ncard++;
339*a81c3ea0SDavid du Colombier }
340*a81c3ea0SDavid du Colombier 
341*a81c3ea0SDavid du Colombier int
parseether(uchar * to,char * from)342*a81c3ea0SDavid du Colombier parseether(uchar *to, char *from)
343*a81c3ea0SDavid du Colombier {
344*a81c3ea0SDavid du Colombier 	char nip[4];
345*a81c3ea0SDavid du Colombier 	char *p;
346*a81c3ea0SDavid du Colombier 	int i;
347*a81c3ea0SDavid du Colombier 
348*a81c3ea0SDavid du Colombier 	p = from;
349*a81c3ea0SDavid du Colombier 	for(i = 0; i < Eaddrlen; i++){
350*a81c3ea0SDavid du Colombier 		if(*p == 0)
351*a81c3ea0SDavid du Colombier 			return -1;
352*a81c3ea0SDavid du Colombier 		nip[0] = *p++;
353*a81c3ea0SDavid du Colombier 		if(*p == 0)
354*a81c3ea0SDavid du Colombier 			return -1;
355*a81c3ea0SDavid du Colombier 		nip[1] = *p++;
356*a81c3ea0SDavid du Colombier 		nip[2] = 0;
357*a81c3ea0SDavid du Colombier 		to[i] = strtoul(nip, 0, 16);
358*a81c3ea0SDavid du Colombier 		if(*p == ':')
359*a81c3ea0SDavid du Colombier 			p++;
360*a81c3ea0SDavid du Colombier 	}
361*a81c3ea0SDavid du Colombier 	return 0;
362*a81c3ea0SDavid du Colombier }
363*a81c3ea0SDavid du Colombier 
364*a81c3ea0SDavid du Colombier static void
etherreset(void)365*a81c3ea0SDavid du Colombier etherreset(void)
366*a81c3ea0SDavid du Colombier {
367*a81c3ea0SDavid du Colombier 	Ether *ether;
368*a81c3ea0SDavid du Colombier 	int i, n, ctlrno, subirq;
369*a81c3ea0SDavid du Colombier 	char name[KNAMELEN], buf[128];
370*a81c3ea0SDavid du Colombier 
371*a81c3ea0SDavid du Colombier 	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
372*a81c3ea0SDavid du Colombier 		if(ether == 0)
373*a81c3ea0SDavid du Colombier 			ether = malloc(sizeof(Ether));
374*a81c3ea0SDavid du Colombier 		memset(ether, 0, sizeof(Ether));
375*a81c3ea0SDavid du Colombier 		ether->ctlrno = ctlrno;
376*a81c3ea0SDavid du Colombier 		ether->mbps = 10;
377*a81c3ea0SDavid du Colombier 		ether->minmtu = ETHERMINTU;
378*a81c3ea0SDavid du Colombier 		ether->maxmtu = ETHERMAXTU;
379*a81c3ea0SDavid du Colombier 
380*a81c3ea0SDavid du Colombier 		if(archether(ctlrno, ether) <= 0)
381*a81c3ea0SDavid du Colombier 			continue;
382*a81c3ea0SDavid du Colombier 
383*a81c3ea0SDavid du Colombier 		for(n = 0; cards[n].type; n++){
384*a81c3ea0SDavid du Colombier 			if(cistrcmp(cards[n].type, ether->type))
385*a81c3ea0SDavid du Colombier 				continue;
386*a81c3ea0SDavid du Colombier 			for(i = 0; i < ether->nopt; i++)
387*a81c3ea0SDavid du Colombier 				if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
388*a81c3ea0SDavid du Colombier 					if(parseether(ether->ea,
389*a81c3ea0SDavid du Colombier 					    &ether->opt[i][3]) == -1)
390*a81c3ea0SDavid du Colombier 						memset(ether->ea, 0, Eaddrlen);
391*a81c3ea0SDavid du Colombier 				} else if(cistrcmp(ether->opt[i],
392*a81c3ea0SDavid du Colombier 				    "100BASE-TXFD") == 0)
393*a81c3ea0SDavid du Colombier 					ether->mbps = 100;
394*a81c3ea0SDavid du Colombier 			if(cards[n].reset(ether))
395*a81c3ea0SDavid du Colombier 				break;
396*a81c3ea0SDavid du Colombier 			snprint(name, sizeof(name), "ether%d", ctlrno);
397*a81c3ea0SDavid du Colombier 
398*a81c3ea0SDavid du Colombier 			subirq = pcisubirq(ether->tbdf);
399*a81c3ea0SDavid du Colombier 			if(ether->interrupt != nil && ether->irq >= 0)
400*a81c3ea0SDavid du Colombier 				intrenable(ether->irq, ether->interrupt, ether, subirq);
401*a81c3ea0SDavid du Colombier 
402*a81c3ea0SDavid du Colombier 			i = snprint(buf, sizeof buf,
403*a81c3ea0SDavid du Colombier 				"#l%d: %s: %dMbps port %#lux irq %d.%d",
404*a81c3ea0SDavid du Colombier 				ctlrno, ether->type, ether->mbps, ether->port,
405*a81c3ea0SDavid du Colombier 				ether->irq, subirq);
406*a81c3ea0SDavid du Colombier 			if(ether->mem)
407*a81c3ea0SDavid du Colombier 				i += snprint(buf+i, sizeof buf - i,
408*a81c3ea0SDavid du Colombier 					" addr %#p", PADDR(ether->mem));
409*a81c3ea0SDavid du Colombier 			if(ether->size)
410*a81c3ea0SDavid du Colombier 				i += snprint(buf+i, sizeof buf - i,
411*a81c3ea0SDavid du Colombier 					" size %#luX", ether->size);
412*a81c3ea0SDavid du Colombier 			i += snprint(buf+i, sizeof buf - i,
413*a81c3ea0SDavid du Colombier 				": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
414*a81c3ea0SDavid du Colombier 				ether->ea[0], ether->ea[1], ether->ea[2],
415*a81c3ea0SDavid du Colombier 				ether->ea[3], ether->ea[4], ether->ea[5]);
416*a81c3ea0SDavid du Colombier 			snprint(buf+i, sizeof buf - i, "\n");
417*a81c3ea0SDavid du Colombier 			iprint("%s", buf);  /* it may be too early for print */
418*a81c3ea0SDavid du Colombier 
419*a81c3ea0SDavid du Colombier 			if(ether->mbps >= 1000)
420*a81c3ea0SDavid du Colombier 				netifinit(ether, name, Ntypes, 4*1024*1024);
421*a81c3ea0SDavid du Colombier 			else if(ether->mbps >= 100)
422*a81c3ea0SDavid du Colombier 				netifinit(ether, name, Ntypes, 1024*1024);
423*a81c3ea0SDavid du Colombier 			else
424*a81c3ea0SDavid du Colombier 				netifinit(ether, name, Ntypes, 65*1024);
425*a81c3ea0SDavid du Colombier 			if(ether->oq == 0)
426*a81c3ea0SDavid du Colombier 				ether->oq = qopen(ether->limit, Qmsg, 0, 0);
427*a81c3ea0SDavid du Colombier 			if(ether->oq == 0)
428*a81c3ea0SDavid du Colombier 				panic("etherreset %s", name);
429*a81c3ea0SDavid du Colombier 			ether->alen = Eaddrlen;
430*a81c3ea0SDavid du Colombier 			memmove(ether->addr, ether->ea, Eaddrlen);
431*a81c3ea0SDavid du Colombier 			memset(ether->bcast, 0xFF, Eaddrlen);
432*a81c3ea0SDavid du Colombier 
433*a81c3ea0SDavid du Colombier 			etherxx[ctlrno] = ether;
434*a81c3ea0SDavid du Colombier 			ether = 0;
435*a81c3ea0SDavid du Colombier 			break;
436*a81c3ea0SDavid du Colombier 		}
437*a81c3ea0SDavid du Colombier 	}
438*a81c3ea0SDavid du Colombier 	if(ether)
439*a81c3ea0SDavid du Colombier 		free(ether);
440*a81c3ea0SDavid du Colombier }
441*a81c3ea0SDavid du Colombier 
442*a81c3ea0SDavid du Colombier static void
ethershutdown(void)443*a81c3ea0SDavid du Colombier ethershutdown(void)
444*a81c3ea0SDavid du Colombier {
445*a81c3ea0SDavid du Colombier 	Ether *ether;
446*a81c3ea0SDavid du Colombier 	int i;
447*a81c3ea0SDavid du Colombier 
448*a81c3ea0SDavid du Colombier 	for(i = 0; i < MaxEther; i++){
449*a81c3ea0SDavid du Colombier 		ether = etherxx[i];
450*a81c3ea0SDavid du Colombier 		if(ether == nil)
451*a81c3ea0SDavid du Colombier 			continue;
452*a81c3ea0SDavid du Colombier 		if(ether->shutdown == nil) {
453*a81c3ea0SDavid du Colombier 			print("#l%d: no shutdown function\n", i);
454*a81c3ea0SDavid du Colombier 			continue;
455*a81c3ea0SDavid du Colombier 		}
456*a81c3ea0SDavid du Colombier 		(*ether->shutdown)(ether);
457*a81c3ea0SDavid du Colombier 	}
458*a81c3ea0SDavid du Colombier }
459*a81c3ea0SDavid du Colombier 
460*a81c3ea0SDavid du Colombier 
461*a81c3ea0SDavid du Colombier #define POLY 0xedb88320
462*a81c3ea0SDavid du Colombier 
463*a81c3ea0SDavid du Colombier /* really slow 32 bit crc for ethers */
464*a81c3ea0SDavid du Colombier ulong
ethercrc(uchar * p,int len)465*a81c3ea0SDavid du Colombier ethercrc(uchar *p, int len)
466*a81c3ea0SDavid du Colombier {
467*a81c3ea0SDavid du Colombier 	int i, j;
468*a81c3ea0SDavid du Colombier 	ulong crc, b;
469*a81c3ea0SDavid du Colombier 
470*a81c3ea0SDavid du Colombier 	crc = 0xffffffff;
471*a81c3ea0SDavid du Colombier 	for(i = 0; i < len; i++){
472*a81c3ea0SDavid du Colombier 		b = *p++;
473*a81c3ea0SDavid du Colombier 		for(j = 0; j < 8; j++){
474*a81c3ea0SDavid du Colombier 			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
475*a81c3ea0SDavid du Colombier 			b >>= 1;
476*a81c3ea0SDavid du Colombier 		}
477*a81c3ea0SDavid du Colombier 	}
478*a81c3ea0SDavid du Colombier 	return crc;
479*a81c3ea0SDavid du Colombier }
480*a81c3ea0SDavid du Colombier 
481*a81c3ea0SDavid du Colombier void
dumpoq(Queue * oq)482*a81c3ea0SDavid du Colombier dumpoq(Queue *oq)
483*a81c3ea0SDavid du Colombier {
484*a81c3ea0SDavid du Colombier 	if (oq == nil)
485*a81c3ea0SDavid du Colombier 		print("no outq! ");
486*a81c3ea0SDavid du Colombier 	else if (qisclosed(oq))
487*a81c3ea0SDavid du Colombier 		print("outq closed ");
488*a81c3ea0SDavid du Colombier 	else if (qfull(oq))
489*a81c3ea0SDavid du Colombier 		print("outq full ");
490*a81c3ea0SDavid du Colombier 	else
491*a81c3ea0SDavid du Colombier 		print("outq %d ", qlen(oq));
492*a81c3ea0SDavid du Colombier }
493*a81c3ea0SDavid du Colombier 
494*a81c3ea0SDavid du Colombier void
dumpnetif(Netif * netif)495*a81c3ea0SDavid du Colombier dumpnetif(Netif *netif)
496*a81c3ea0SDavid du Colombier {
497*a81c3ea0SDavid du Colombier 	print("netif %s ", netif->name);
498*a81c3ea0SDavid du Colombier 	print("limit %d mbps %d link %d ",
499*a81c3ea0SDavid du Colombier 		netif->limit, netif->mbps, netif->link);
500*a81c3ea0SDavid du Colombier 	print("inpkts %lld outpkts %lld errs %d\n",
501*a81c3ea0SDavid du Colombier 		netif->inpackets, netif->outpackets,
502*a81c3ea0SDavid du Colombier 		netif->crcs + netif->oerrs + netif->frames + netif->overflows +
503*a81c3ea0SDavid du Colombier 		netif->buffs + netif->soverflows);
504*a81c3ea0SDavid du Colombier }
505*a81c3ea0SDavid du Colombier 
506*a81c3ea0SDavid du Colombier Dev etherdevtab = {
507*a81c3ea0SDavid du Colombier 	'l',
508*a81c3ea0SDavid du Colombier 	"ether",
509*a81c3ea0SDavid du Colombier 
510*a81c3ea0SDavid du Colombier 	etherreset,
511*a81c3ea0SDavid du Colombier 	devinit,
512*a81c3ea0SDavid du Colombier 	ethershutdown,
513*a81c3ea0SDavid du Colombier 	etherattach,
514*a81c3ea0SDavid du Colombier 	etherwalk,
515*a81c3ea0SDavid du Colombier 	etherstat,
516*a81c3ea0SDavid du Colombier 	etheropen,
517*a81c3ea0SDavid du Colombier 	ethercreate,
518*a81c3ea0SDavid du Colombier 	etherclose,
519*a81c3ea0SDavid du Colombier 	etherread,
520*a81c3ea0SDavid du Colombier 	etherbread,
521*a81c3ea0SDavid du Colombier 	etherwrite,
522*a81c3ea0SDavid du Colombier 	etherbwrite,
523*a81c3ea0SDavid du Colombier 	devremove,
524*a81c3ea0SDavid du Colombier 	etherwstat,
525*a81c3ea0SDavid du Colombier };
526