xref: /plan9/sys/src/9/kw/devether.c (revision 7ae8f4532bb599d9c475208824b53a0495a01a84)
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 extern int archether(unsigned ctlno, Ether *ether);
13 
14 static Ether *etherxx[MaxEther];
15 
16 Chan*
etherattach(char * spec)17 etherattach(char* spec)
18 {
19 	int 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 != 0)
27 			error(Ebadarg);
28 		if(ctlrno < 0 || ctlrno >= MaxEther)
29 			error(Ebadarg);
30 	}
31 	if(etherxx[ctlrno] == 0)
32 		error(Enodev);
33 
34 	chan = devattach('l', spec);
35 	if(waserror()){
36 		chanfree(chan);
37 		nexterror();
38 	}
39 	chan->dev = ctlrno;
40 	if(etherxx[ctlrno]->attach)
41 		etherxx[ctlrno]->attach(etherxx[ctlrno]);
42 	poperror();
43 	return chan;
44 }
45 
46 static Walkqid*
etherwalk(Chan * chan,Chan * nchan,char ** name,int nname)47 etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
48 {
49 	return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
50 }
51 
52 static int
etherstat(Chan * chan,uchar * dp,int n)53 etherstat(Chan* chan, uchar* dp, int n)
54 {
55 	return netifstat(etherxx[chan->dev], chan, dp, n);
56 }
57 
58 static Chan*
etheropen(Chan * chan,int omode)59 etheropen(Chan* chan, int omode)
60 {
61 	return netifopen(etherxx[chan->dev], chan, omode);
62 }
63 
64 static void
ethercreate(Chan *,char *,int,ulong)65 ethercreate(Chan*, char*, int, ulong)
66 {
67 }
68 
69 static void
etherclose(Chan * chan)70 etherclose(Chan* chan)
71 {
72 	netifclose(etherxx[chan->dev], chan);
73 }
74 
75 static long
etherread(Chan * chan,void * buf,long n,vlong off)76 etherread(Chan* chan, void* buf, long n, vlong off)
77 {
78 	Ether *ether;
79 	ulong offset = off;
80 
81 	ether = etherxx[chan->dev];
82 	if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
83 		/*
84 		 * With some controllers it is necessary to reach
85 		 * into the chip to extract statistics.
86 		 */
87 		if(NETTYPE(chan->qid.path) == Nifstatqid)
88 			return ether->ifstat(ether, buf, n, offset);
89 		else if(NETTYPE(chan->qid.path) == Nstatqid)
90 			ether->ifstat(ether, buf, 0, offset);
91 	}
92 
93 	return netifread(ether, chan, buf, n, offset);
94 }
95 
96 static Block*
etherbread(Chan * chan,long n,ulong offset)97 etherbread(Chan* chan, long n, ulong offset)
98 {
99 	return netifbread(etherxx[chan->dev], chan, n, offset);
100 }
101 
102 static int
etherwstat(Chan * chan,uchar * dp,int n)103 etherwstat(Chan* chan, uchar* dp, int n)
104 {
105 	return netifwstat(etherxx[chan->dev], chan, dp, n);
106 }
107 
108 static void
etherrtrace(Netfile * f,Etherpkt * pkt,int len)109 etherrtrace(Netfile* f, Etherpkt* pkt, int len)
110 {
111 	int i, n;
112 	Block *bp;
113 
114 	if(qwindow(f->in) <= 0)
115 		return;
116 	if(len > 58)
117 		n = 58;
118 	else
119 		n = len;
120 	bp = iallocb(64);
121 	if(bp == nil)
122 		return;
123 	memmove(bp->wp, pkt->d, n);
124 	i = TK2MS(MACHP(0)->ticks);
125 	bp->wp[58] = len>>8;
126 	bp->wp[59] = len;
127 	bp->wp[60] = i>>24;
128 	bp->wp[61] = i>>16;
129 	bp->wp[62] = i>>8;
130 	bp->wp[63] = i;
131 	bp->wp += 64;
132 	qpass(f->in, bp);
133 }
134 
135 Block*
etheriq(Ether * ether,Block * bp,int fromwire)136 etheriq(Ether* ether, Block* bp, int fromwire)
137 {
138 	Etherpkt *pkt;
139 	ushort type;
140 	int len, multi, tome, fromme;
141 	Netfile **ep, *f, **fp, *fx;
142 	Block *xbp;
143 
144 	ether->inpackets++;
145 
146 	pkt = (Etherpkt*)bp->rp;
147 	len = BLEN(bp);
148 	type = (pkt->type[0]<<8)|pkt->type[1];
149 	fx = 0;
150 	ep = &ether->f[Ntypes];
151 
152 	multi = pkt->d[0] & 1;
153 	/* check for valid multicast addresses */
154 	if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
155 		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
156 			if(fromwire){
157 				freeb(bp);
158 				bp = 0;
159 			}
160 			return bp;
161 		}
162 	}
163 
164 	/* is it for me? */
165 	tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
166 	fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
167 
168 	/*
169 	 * Multiplex the packet to all the connections which want it.
170 	 * If the packet is not to be used subsequently (fromwire != 0),
171 	 * attempt to simply pass it into one of the connections, thereby
172 	 * saving a copy of the data (usual case hopefully).
173 	 */
174 	for(fp = ether->f; fp < ep; fp++){
175 		if(f = *fp)
176 		if(f->type == type || f->type < 0)
177 		if(tome || multi || f->prom){
178 			/* Don't want to hear bridged packets */
179 			if(f->bridge && !fromwire && !fromme)
180 				continue;
181 			if(!f->headersonly){
182 				if(fromwire && fx == 0)
183 					fx = f;
184 				else if(xbp = iallocb(len)){
185 					memmove(xbp->wp, pkt, len);
186 					xbp->wp += len;
187 					if(qpass(f->in, xbp) < 0)
188 						ether->soverflows++;
189 				}
190 				else
191 					ether->soverflows++;
192 			}
193 			else
194 				etherrtrace(f, pkt, len);
195 		}
196 	}
197 
198 	if(fx){
199 		if(qpass(fx->in, bp) < 0)
200 			ether->soverflows++;
201 		return 0;
202 	}
203 	if(fromwire){
204 		freeb(bp);
205 		return 0;
206 	}
207 
208 	return bp;
209 }
210 
211 static int
etheroq(Ether * ether,Block * bp)212 etheroq(Ether* ether, Block* bp)
213 {
214 	int len, loopback, s;
215 	Etherpkt *pkt;
216 
217 	ether->outpackets++;
218 
219 	/*
220 	 * Check if the packet has to be placed back onto the input queue,
221 	 * i.e. if it's a loopback or broadcast packet or the interface is
222 	 * in promiscuous mode.
223 	 * If it's a loopback packet indicate to etheriq that the data isn't
224 	 * needed and return, etheriq will pass-on or free the block.
225 	 * To enable bridging to work, only packets that were originated
226 	 * by this interface are fed back.
227 	 */
228 	pkt = (Etherpkt*)bp->rp;
229 	len = BLEN(bp);
230 	loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
231 	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
232 		s = splhi();
233 		etheriq(ether, bp, 0);
234 		splx(s);
235 	}
236 
237 	if(!loopback){
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->dev];
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(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->maxmtu)
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,ulong)296 etherbwrite(Chan* chan, Block* bp, ulong)
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->dev];
313 
314 	if(n > ether->maxmtu){
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 void
etherreset(void)367 etherreset(void)
368 {
369 	Ether *ether;
370 	int i, n, ctlrno;
371 	char name[KNAMELEN], buf[128];
372 
373 	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
374 		if(ether == 0)
375 			ether = malloc(sizeof(Ether));
376 		if(ether == 0)
377 			panic("etherreset: no memory");
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(Irqlo, ether->irq, ether->interrupt,
406 					ether, name);
407 
408 			i = snprint(buf, sizeof buf,
409 				"#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 += snprint(buf+i, sizeof buf - i,
414 					" addr %#lux", PADDR(ether->mem));
415 			if(ether->size)
416 				i += snprint(buf+i, sizeof buf - i,
417 					" size %#luX", ether->size);
418 			i += snprint(buf+i, sizeof buf - i,
419 				": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
420 				ether->ea[0], ether->ea[1], ether->ea[2],
421 				ether->ea[3], ether->ea[4], ether->ea[5]);
422 			snprint(buf+i, sizeof buf - i, "\n");
423 			print("%s", buf);
424 
425 			if(ether->mbps >= 1000)
426 				netifinit(ether, name, Ntypes, 4*1024*1024);
427 			else if(ether->mbps >= 100)
428 				netifinit(ether, name, Ntypes, 1024*1024);
429 			else
430 				netifinit(ether, name, Ntypes, 65*1024);
431 			if(ether->oq == 0)
432 				ether->oq = qopen(ether->limit, Qmsg, 0, 0);
433 			if(ether->oq == 0)
434 				panic("etherreset %s", name);
435 			ether->alen = Eaddrlen;
436 			memmove(ether->addr, ether->ea, Eaddrlen);
437 			memset(ether->bcast, 0xFF, Eaddrlen);
438 
439 			etherxx[ctlrno] = ether;
440 			ether = 0;
441 			break;
442 		}
443 	}
444 	if(ether)
445 		free(ether);
446 }
447 
448 static void
ethershutdown(void)449 ethershutdown(void)
450 {
451 	Ether *ether;
452 	int i;
453 
454 	for(i = 0; i < MaxEther; i++){
455 		ether = etherxx[i];
456 		if(ether == nil)
457 			continue;
458 		if(ether->shutdown == nil) {
459 			print("#l%d: no shutdown function\n", i);
460 			continue;
461 		}
462 		(*ether->shutdown)(ether);
463 	}
464 }
465 
466 #define POLY 0xedb88320
467 
468 /* really slow 32 bit crc for ethers */
469 ulong
ethercrc(uchar * p,int len)470 ethercrc(uchar *p, int len)
471 {
472 	int i, j;
473 	ulong crc, b;
474 
475 	crc = 0xffffffff;
476 	for(i = 0; i < len; i++){
477 		b = *p++;
478 		for(j = 0; j < 8; j++){
479 			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
480 			b >>= 1;
481 		}
482 	}
483 	return crc;
484 }
485 
486 void
dumpoq(Queue * oq)487 dumpoq(Queue *oq)
488 {
489 	if (oq == nil)
490 		print("no outq! ");
491 	else if (qisclosed(oq))
492 		print("outq closed ");
493 	else if (qfull(oq))
494 		print("outq full ");
495 	else
496 		print("outq %d ", qlen(oq));
497 }
498 
499 void
dumpnetif(Netif * netif)500 dumpnetif(Netif *netif)
501 {
502 	print("netif %s ", netif->name);
503 	print("limit %d mbps %d link %d ",
504 		netif->limit, netif->mbps, netif->link);
505 	print("inpkts %lld outpkts %lld errs %d\n",
506 		netif->inpackets, netif->outpackets,
507 		netif->crcs + netif->oerrs + netif->frames + netif->overflows +
508 		netif->buffs + netif->soverflows);
509 }
510 
511 Dev etherdevtab = {
512 	'l',
513 	"ether",
514 
515 	etherreset,
516 	devinit,
517 	ethershutdown,
518 	etherattach,
519 	etherwalk,
520 	etherstat,
521 	etheropen,
522 	ethercreate,
523 	etherclose,
524 	etherread,
525 	etherbread,
526 	etherwrite,
527 	etherbwrite,
528 	devremove,
529 	etherwstat,
530 };
531