xref: /plan9/sys/src/9/omap/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 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 &&
155 	    ether->prom == 0){
156 		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
157 			if(fromwire){
158 				freeb(bp);
159 				bp = 0;
160 			}
161 			return bp;
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) != nil && (f->type == type || f->type < 0) &&
176 		    (tome || multi || f->prom)){
177 			/* Don't want to hear bridged packets */
178 			if(f->bridge && !fromwire && !fromme)
179 				continue;
180 			if(!f->headersonly){
181 				if(fromwire && fx == 0)
182 					fx = f;
183 				else if(xbp = iallocb(len)){
184 					memmove(xbp->wp, pkt, len);
185 					xbp->wp += len;
186 					if(qpass(f->in, xbp) < 0)
187 						ether->soverflows++;
188 				}
189 				else
190 					ether->soverflows++;
191 			}
192 			else
193 				etherrtrace(f, pkt, len);
194 		}
195 	}
196 
197 	if(fx){
198 		if(qpass(fx->in, bp) < 0)
199 			ether->soverflows++;
200 		return 0;
201 	}
202 	if(fromwire){
203 		freeb(bp);
204 		return 0;
205 	}
206 	return bp;
207 }
208 
209 static int
etheroq(Ether * ether,Block * bp)210 etheroq(Ether* ether, Block* bp)
211 {
212 	int len, loopback, s;
213 	Etherpkt *pkt;
214 
215 	ether->outpackets++;
216 
217 	/*
218 	 * Check if the packet has to be placed back onto the input queue,
219 	 * i.e. if it's a loopback or broadcast packet or the interface is
220 	 * in promiscuous mode.
221 	 * If it's a loopback packet indicate to etheriq that the data isn't
222 	 * needed and return, etheriq will pass-on or free the block.
223 	 * To enable bridging to work, only packets that were originated
224 	 * by this interface are fed back.
225 	 */
226 	pkt = (Etherpkt*)bp->rp;
227 	len = BLEN(bp);
228 	loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
229 	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
230 		s = splhi();
231 		etheriq(ether, bp, 0);
232 		splx(s);
233 	}
234 
235 	if(!loopback){
236 		qbwrite(ether->oq, bp);
237 		if(ether->transmit != nil)
238 			ether->transmit(ether);
239 	} else
240 		freeb(bp);
241 
242 	return len;
243 }
244 
245 static long
etherwrite(Chan * chan,void * buf,long n,vlong)246 etherwrite(Chan* chan, void* buf, long n, vlong)
247 {
248 	Ether *ether;
249 	Block *bp;
250 	int nn, onoff;
251 	Cmdbuf *cb;
252 
253 	ether = etherxx[chan->dev];
254 	if(NETTYPE(chan->qid.path) != Ndataqid) {
255 		nn = netifwrite(ether, chan, buf, n);
256 		if(nn >= 0)
257 			return nn;
258 		cb = parsecmd(buf, n);
259 		if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
260 			if(cb->nf <= 1)
261 				onoff = 1;
262 			else
263 				onoff = atoi(cb->f[1]);
264 			qnoblock(ether->oq, onoff);
265 			free(cb);
266 			return n;
267 		}
268 		free(cb);
269 		if(ether->ctl!=nil)
270 			return ether->ctl(ether,buf,n);
271 
272 		error(Ebadctl);
273 	}
274 
275 	if(n > ether->maxmtu)
276 		error(Etoobig);
277 	if(n < ether->minmtu)
278 		error(Etoosmall);
279 
280 	bp = allocb(n);
281 	if(waserror()){
282 		freeb(bp);
283 		nexterror();
284 	}
285 	memmove(bp->rp, buf, n);
286 	memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
287 	poperror();
288 	bp->wp += n;
289 
290 	return etheroq(ether, bp);
291 }
292 
293 static long
etherbwrite(Chan * chan,Block * bp,ulong)294 etherbwrite(Chan* chan, Block* bp, ulong)
295 {
296 	Ether *ether;
297 	long n;
298 
299 	n = BLEN(bp);
300 	if(NETTYPE(chan->qid.path) != Ndataqid){
301 		if(waserror()) {
302 			freeb(bp);
303 			nexterror();
304 		}
305 		n = etherwrite(chan, bp->rp, n, 0);
306 		poperror();
307 		freeb(bp);
308 		return n;
309 	}
310 	ether = etherxx[chan->dev];
311 
312 	if(n > ether->maxmtu){
313 		freeb(bp);
314 		error(Etoobig);
315 	}
316 	if(n < ether->minmtu){
317 		freeb(bp);
318 		error(Etoosmall);
319 	}
320 
321 	return etheroq(ether, bp);
322 }
323 
324 static struct {
325 	char*	type;
326 	int	(*reset)(Ether*);
327 } cards[MaxEther+1];
328 
329 void
addethercard(char * t,int (* r)(Ether *))330 addethercard(char* t, int (*r)(Ether*))
331 {
332 	static int ncard;
333 
334 	if(ncard == MaxEther)
335 		panic("too many ether cards");
336 	cards[ncard].type = t;
337 	cards[ncard].reset = r;
338 	ncard++;
339 }
340 
341 int
parseether(uchar * to,char * from)342 parseether(uchar *to, char *from)
343 {
344 	char nip[4];
345 	char *p;
346 	int i;
347 
348 	p = from;
349 	for(i = 0; i < Eaddrlen; i++){
350 		if(*p == 0)
351 			return -1;
352 		nip[0] = *p++;
353 		if(*p == 0)
354 			return -1;
355 		nip[1] = *p++;
356 		nip[2] = 0;
357 		to[i] = strtoul(nip, 0, 16);
358 		if(*p == ':')
359 			p++;
360 	}
361 	return 0;
362 }
363 
364 static void
etherreset(void)365 etherreset(void)
366 {
367 	Ether *ether;
368 	int i, n, ctlrno;
369 	char name[KNAMELEN], buf[128];
370 
371 	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
372 		if(ether == 0)
373 			ether = malloc(sizeof(Ether));
374 		memset(ether, 0, sizeof(Ether));
375 		ether->ctlrno = ctlrno;
376 		ether->mbps = 10;
377 		ether->minmtu = ETHERMINTU;
378 		ether->maxmtu = ETHERMAXTU;
379 
380 		if(archether(ctlrno, ether) <= 0)
381 			continue;
382 
383 		if(isaconfig("ether", ctlrno, ether) == 0){
384 //			free(ether);
385 //			return nil;
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,
394 					    &ether->opt[i][3]) == -1)
395 						memset(ether->ea, 0, Eaddrlen);
396 				} else if(cistrcmp(ether->opt[i],
397 				    "100BASE-TXFD") == 0)
398 					ether->mbps = 100;
399 			if(cards[n].reset(ether))
400 				break;
401 			snprint(name, sizeof(name), "ether%d", ctlrno);
402 
403 			if(ether->interrupt != nil && ether->irq >= 0)
404 				intrenable(ether->irq, ether->interrupt,
405 					ether, 0, name);
406 
407 			i = snprint(buf, sizeof buf,
408 				"#l%d: %s: %dMbps port %#lux irq %d",
409 				ctlrno, ether->type, ether->mbps, ether->port,
410 				ether->irq);
411 			if(ether->mem)
412 				i += snprint(buf+i, sizeof buf - i,
413 					" addr %#lux", PADDR(ether->mem));
414 			if(ether->size)
415 				i += snprint(buf+i, sizeof buf - i,
416 					" size %#luX", ether->size);
417 			i += snprint(buf+i, sizeof buf - i,
418 				": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
419 				ether->ea[0], ether->ea[1], ether->ea[2],
420 				ether->ea[3], ether->ea[4], ether->ea[5]);
421 			snprint(buf+i, sizeof buf - i, "\n");
422 			iprint("%s", buf);  /* it may be too early for print */
423 
424 			if(ether->mbps >= 1000)
425 				netifinit(ether, name, Ntypes, 4*1024*1024);
426 			else if(ether->mbps >= 100)
427 				netifinit(ether, name, Ntypes, 1024*1024);
428 			else
429 				netifinit(ether, name, Ntypes, 65*1024);
430 			if(ether->oq == 0)
431 				ether->oq = qopen(ether->limit, Qmsg, 0, 0);
432 			if(ether->oq == 0)
433 				panic("etherreset %s", name);
434 			ether->alen = Eaddrlen;
435 			memmove(ether->addr, ether->ea, Eaddrlen);
436 			memset(ether->bcast, 0xFF, Eaddrlen);
437 
438 			etherxx[ctlrno] = ether;
439 			ether = 0;
440 			break;
441 		}
442 	}
443 	if(ether)
444 		free(ether);
445 }
446 
447 static void
ethershutdown(void)448 ethershutdown(void)
449 {
450 	Ether *ether;
451 	int i;
452 
453 	for(i = 0; i < MaxEther; i++){
454 		ether = etherxx[i];
455 		if(ether == nil)
456 			continue;
457 		if(ether->shutdown == nil) {
458 			print("#l%d: no shutdown function\n", i);
459 			continue;
460 		}
461 		(*ether->shutdown)(ether);
462 	}
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