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