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