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