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