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