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