xref: /plan9/sys/src/9/teg2/devether.c (revision a1216cc64119db675aa140f55fbd73eb2414b763)
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 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->dev = 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->dev], chan, nchan, name, nname);
48 }
49 
50 static int
etherstat(Chan * chan,uchar * dp,int n)51 etherstat(Chan* chan, uchar* dp, int n)
52 {
53 	return netifstat(etherxx[chan->dev], 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->dev], chan, omode);
60 }
61 
62 static void
ethercreate(Chan *,char *,int,ulong)63 ethercreate(Chan*, char*, int, ulong)
64 {
65 }
66 
67 static void
etherclose(Chan * chan)68 etherclose(Chan* chan)
69 {
70 	netifclose(etherxx[chan->dev], 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->dev];
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,ulong offset)95 etherbread(Chan* chan, long n, ulong offset)
96 {
97 	return netifbread(etherxx[chan->dev], chan, n, offset);
98 }
99 
100 static int
etherwstat(Chan * chan,uchar * dp,int n)101 etherwstat(Chan* chan, uchar* dp, int n)
102 {
103 	return netifwstat(etherxx[chan->dev], 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->in) <= 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(MACHP(0)->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->in, 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 &&
153 	    ether->prom == 0){
154 		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
155 			if(fromwire){
156 				freeb(bp);
157 				bp = 0;
158 			}
159 			return bp;
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) != nil && (f->type == type || f->type < 0) &&
174 		    (tome || multi || f->prom)){
175 			/* Don't want to hear bridged packets */
176 			if(f->bridge && !fromwire && !fromme)
177 				continue;
178 			if(!f->headersonly){
179 				if(fromwire && fx == 0)
180 					fx = f;
181 				else if(xbp = iallocb(len)){
182 					memmove(xbp->wp, pkt, len);
183 					xbp->wp += len;
184 					if(qpass(f->in, xbp) < 0)
185 						ether->soverflows++;
186 				}
187 				else
188 					ether->soverflows++;
189 			}
190 			else
191 				etherrtrace(f, pkt, len);
192 		}
193 	}
194 
195 	if(fx){
196 		if(qpass(fx->in, bp) < 0)
197 			ether->soverflows++;
198 		return 0;
199 	}
200 	if(fromwire){
201 		freeb(bp);
202 		return 0;
203 	}
204 	return bp;
205 }
206 
207 static int
etheroq(Ether * ether,Block * bp)208 etheroq(Ether* ether, Block* bp)
209 {
210 	int len, loopback, s;
211 	Etherpkt *pkt;
212 
213 	ether->outpackets++;
214 
215 	/*
216 	 * Check if the packet has to be placed back onto the input queue,
217 	 * i.e. if it's a loopback or broadcast packet or the interface is
218 	 * in promiscuous mode.
219 	 * If it's a loopback packet indicate to etheriq that the data isn't
220 	 * needed and return, etheriq will pass-on or free the block.
221 	 * To enable bridging to work, only packets that were originated
222 	 * by this interface are fed back.
223 	 */
224 	pkt = (Etherpkt*)bp->rp;
225 	len = BLEN(bp);
226 	loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
227 	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
228 		s = splhi();
229 		etheriq(ether, bp, 0);
230 		splx(s);
231 	}
232 
233 	if(!loopback){
234 		qbwrite(ether->oq, bp);
235 		if(ether->transmit != nil)
236 			ether->transmit(ether);
237 	} else
238 		freeb(bp);
239 
240 	return len;
241 }
242 
243 static long
etherwrite(Chan * chan,void * buf,long n,vlong)244 etherwrite(Chan* chan, void* buf, long n, vlong)
245 {
246 	Ether *ether;
247 	Block *bp;
248 	int nn, onoff;
249 	Cmdbuf *cb;
250 
251 	ether = etherxx[chan->dev];
252 	if(NETTYPE(chan->qid.path) != Ndataqid) {
253 		nn = netifwrite(ether, chan, buf, n);
254 		if(nn >= 0)
255 			return nn;
256 		cb = parsecmd(buf, n);
257 		if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
258 			if(cb->nf <= 1)
259 				onoff = 1;
260 			else
261 				onoff = atoi(cb->f[1]);
262 			qnoblock(ether->oq, onoff);
263 			free(cb);
264 			return n;
265 		}
266 		free(cb);
267 		if(ether->ctl!=nil)
268 			return ether->ctl(ether,buf,n);
269 
270 		error(Ebadctl);
271 	}
272 
273 	if(n > ether->maxmtu)
274 		error(Etoobig);
275 	if(n < ether->minmtu)
276 		error(Etoosmall);
277 
278 	bp = allocb(n);
279 	if(waserror()){
280 		freeb(bp);
281 		nexterror();
282 	}
283 	memmove(bp->rp, buf, n);
284 	memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
285 	poperror();
286 	bp->wp += n;
287 
288 	return etheroq(ether, bp);
289 }
290 
291 static long
etherbwrite(Chan * chan,Block * bp,ulong)292 etherbwrite(Chan* chan, Block* bp, ulong)
293 {
294 	Ether *ether;
295 	long n;
296 
297 	n = BLEN(bp);
298 	if(NETTYPE(chan->qid.path) != Ndataqid){
299 		if(waserror()) {
300 			freeb(bp);
301 			nexterror();
302 		}
303 		n = etherwrite(chan, bp->rp, n, 0);
304 		poperror();
305 		freeb(bp);
306 		return n;
307 	}
308 	ether = etherxx[chan->dev];
309 
310 	if(n > ether->maxmtu){
311 		freeb(bp);
312 		error(Etoobig);
313 	}
314 	if(n < ether->minmtu){
315 		freeb(bp);
316 		error(Etoosmall);
317 	}
318 
319 	return etheroq(ether, bp);
320 }
321 
322 static struct {
323 	char*	type;
324 	int	(*reset)(Ether*);
325 } cards[MaxEther+1];
326 
327 void
addethercard(char * t,int (* r)(Ether *))328 addethercard(char* t, int (*r)(Ether*))
329 {
330 	static int ncard;
331 
332 	if(ncard == MaxEther)
333 		panic("too many ether cards");
334 	cards[ncard].type = t;
335 	cards[ncard].reset = r;
336 	ncard++;
337 }
338 
339 int
parseether(uchar * to,char * from)340 parseether(uchar *to, char *from)
341 {
342 	char nip[4];
343 	char *p;
344 	int i;
345 
346 	p = from;
347 	for(i = 0; i < Eaddrlen; i++){
348 		if(*p == 0)
349 			return -1;
350 		nip[0] = *p++;
351 		if(*p == 0)
352 			return -1;
353 		nip[1] = *p++;
354 		nip[2] = 0;
355 		to[i] = strtoul(nip, 0, 16);
356 		if(*p == ':')
357 			p++;
358 	}
359 	return 0;
360 }
361 
362 static void
etherreset(void)363 etherreset(void)
364 {
365 	Ether *ether;
366 	int i, n, ctlrno;
367 	char name[KNAMELEN], buf[128];
368 
369 	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
370 		if(ether == 0)
371 			ether = malloc(sizeof(Ether));
372 		memset(ether, 0, sizeof(Ether));
373 		ether->ctlrno = ctlrno;
374 		ether->mbps = 10;
375 		ether->minmtu = ETHERMINTU;
376 		ether->maxmtu = ETHERMAXTU;
377 
378 		if(archether(ctlrno, ether) <= 0)
379 			continue;
380 
381 		if(isaconfig("ether", ctlrno, ether) == 0){
382 //			free(ether);
383 //			return nil;
384 			continue;
385 		}
386 		for(n = 0; cards[n].type; n++){
387 			if(cistrcmp(cards[n].type, ether->type))
388 				continue;
389 			for(i = 0; i < ether->nopt; i++)
390 				if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
391 					if(parseether(ether->ea,
392 					    &ether->opt[i][3]) == -1)
393 						memset(ether->ea, 0, Eaddrlen);
394 				} else if(cistrcmp(ether->opt[i],
395 				    "100BASE-TXFD") == 0)
396 					ether->mbps = 100;
397 			if(cards[n].reset(ether))
398 				break;
399 			snprint(name, sizeof(name), "ether%d", ctlrno);
400 
401 			if(ether->interrupt != nil && ether->irq >= 0)
402 				intrenable(ether->irq, ether->interrupt,
403 					ether, 0, name);
404 
405 			i = snprint(buf, sizeof buf,
406 				"#l%d: %s: %dMbps port %#lux irq %d",
407 				ctlrno, ether->type, ether->mbps, ether->port,
408 				ether->irq);
409 			if(ether->mem)
410 				i += snprint(buf+i, sizeof buf - i,
411 					" addr %#lux", PADDR(ether->mem));
412 			if(ether->size)
413 				i += snprint(buf+i, sizeof buf - i,
414 					" size %#luX", ether->size);
415 			i += snprint(buf+i, sizeof buf - i,
416 				": %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 			snprint(buf+i, sizeof buf - i, "\n");
420 			iprint("%s", buf);  /* it may be too early for print */
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
ethershutdown(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 #define POLY 0xedb88320
465 
466 /* really slow 32 bit crc for ethers */
467 ulong
ethercrc(uchar * p,int len)468 ethercrc(uchar *p, int len)
469 {
470 	int i, j;
471 	ulong crc, b;
472 
473 	crc = 0xffffffff;
474 	for(i = 0; i < len; i++){
475 		b = *p++;
476 		for(j = 0; j < 8; j++){
477 			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
478 			b >>= 1;
479 		}
480 	}
481 	return crc;
482 }
483 
484 void
dumpoq(Queue * oq)485 dumpoq(Queue *oq)
486 {
487 	if (oq == nil)
488 		print("no outq! ");
489 	else if (qisclosed(oq))
490 		print("outq closed ");
491 	else if (qfull(oq))
492 		print("outq full ");
493 	else
494 		print("outq %d ", qlen(oq));
495 }
496 
497 void
dumpnetif(Netif * netif)498 dumpnetif(Netif *netif)
499 {
500 	print("netif %s ", netif->name);
501 	print("limit %d mbps %d link %d ",
502 		netif->limit, netif->mbps, netif->link);
503 	print("inpkts %lld outpkts %lld errs %d\n",
504 		netif->inpackets, netif->outpackets,
505 		netif->crcs + netif->oerrs + netif->frames + netif->overflows +
506 		netif->buffs + netif->soverflows);
507 }
508 
509 Dev etherdevtab = {
510 	'l',
511 	"ether",
512 
513 	etherreset,
514 	devinit,
515 	ethershutdown,
516 	etherattach,
517 	etherwalk,
518 	etherstat,
519 	etheropen,
520 	ethercreate,
521 	etherclose,
522 	etherread,
523 	etherbread,
524 	etherwrite,
525 	etherbwrite,
526 	devremove,
527 	etherwstat,
528 };
529