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