xref: /plan9-contrib/sys/src/cmd/usb/ether/ether.c (revision 401314a3b4602c168a19b28ed47ba5cbefe42fe0)
1 /*
2  * usb/ether - usb ethernet adapter.
3  * BUG: This should use /dev/etherfile to
4  * use the kernel ether device code.
5  */
6 #include <u.h>
7 #include <libc.h>
8 #include <fcall.h>
9 #include <thread.h>
10 #include "usb.h"
11 #include "usbfs.h"
12 #include "ether.h"
13 
14 typedef struct Dirtab Dirtab;
15 
16 enum
17 {
18 	/* Qids. Maintain order (relative to dirtabs structs) */
19 	Qroot	= 0,
20 	Qclone,
21 	Qaddr,
22 	Qifstats,
23 	Qstats,
24 	Qndir,
25 	Qndata,
26 	Qnctl,
27 	Qnifstats,
28 	Qnstats,
29 	Qntype,
30 	Qmax,
31 };
32 
33 struct Dirtab
34 {
35 	char	*name;
36 	int	qid;
37 	int	mode;
38 };
39 
40 typedef int (*Resetf)(Ether*);
41 
42 /*
43  * Controllers by vid/vid. Used to locate
44  * specific adapters that do not implement cdc ethernet
45  * Keep null terminated.
46  */
47 Cinfo cinfo[] =
48 {
49 	/* Asix controllers.
50 	 * Only A88178 and A88772 are implemented.
51 	 * Others are easy to add by borrowing code
52 	 * from other systems.
53 	 */
54 	{0x0411, 0x003d, A8817x},	/* buffalo */
55 	{0x0411, 0x006e, A88178},
56 	{0x04f1, 0x3008, A8817x},
57 	{0x050d, 0x5055, A88178},
58 	{0x0557, 0x2009, A8817x},
59 	{0x05ac, 0x1402, A88772},	/* Apple */
60 	{0x077b, 0x2226, A8817x},
61 	{0x07aa, 0x0017, A8817x},
62 	{0x07d1, 0x3c05, A88772},
63 	{0x0b95, 0x1720, A8817x},	/* asix */
64 	{0x0b95, 0x1780, A88178},	/* Geoff */
65 	{0x0b95, 0x7720, A88772},
66 	{0x0b95, 0x772a, A88772},
67 	{0x0db0, 0xa877, A88772},
68 	{0x1189, 0x0893, A8817x},
69 	{0x13b1, 0x0018, A88772},
70 	{0x14ea, 0xab11, A88178},
71 	{0x1557, 0x7720, A88772},
72 	{0x1631, 0x6200, A8817x},
73 	{0x1737, 0x0039, A88178},
74 	{0x2001, 0x3c05, A88772},
75 	{0x6189, 0x182d, A8817x},
76 	{0, 0, 0},
77 };
78 
79 /*
80  * Each etherU%d is the root of our file system,
81  * which is added to the usb root directory. We only
82  * have to concern ourselfs with each /etherU%d subtree.
83  *
84  * NB: Maintain order in dirtabs, relative to the Qids enum.
85  */
86 
87 static Dirtab rootdirtab[] =
88 {
89 	"/",		Qroot,		DMDIR|0555,	/* etherU%d */
90 	"clone",	Qclone,		0666,
91 	"addr",		Qaddr,		0444,
92 	"ifstats",	Qifstats,	0444,
93 	"stats",	Qstats,		0444,
94 	/* one dir per connection here */
95 	nil, 0, 0,
96 };
97 
98 static Dirtab conndirtab[] =
99 {
100 	"%d",		Qndir,		DMDIR|0555,
101 	"data",		Qndata,		0666,
102 	"ctl",		Qnctl,		0666,
103 	"ifstats",	Qnifstats,	0444,
104 	"stats",	Qnstats,	0444,
105 	"type",		Qntype,		0444,
106 	nil, 0,
107 };
108 
109 int etherdebug;
110 
111 Resetf ethers[] =
112 {
113 	asixreset,
114 	cdcreset,	/* keep last */
115 };
116 
117 static int
118 qtype(vlong q)
119 {
120 	return q&0xFF;
121 }
122 
123 static int
124 qnum(vlong q)
125 {
126 	return (q >> 8) & 0xFFFFFF;
127 }
128 
129 static uvlong
130 mkqid(int n, int t)
131 {
132 	uvlong q;
133 
134 	q = (n&0xFFFFFF) << 8 | t&0xFF;
135 	return q;
136 }
137 
138 static void
139 freebuf(Ether *e, Buf *bp)
140 {
141 	if(0)deprint(2, "%s: freebuf %#p\n", argv0, bp);
142 	if(bp != nil){
143 		qlock(e);
144 		e->nbufs--;
145 		qunlock(e);
146 		sendp(e->bc, bp);
147 	}
148 }
149 
150 static Buf*
151 allocbuf(Ether *e)
152 {
153 	Buf *bp;
154 
155 	bp = nbrecvp(e->bc);
156 	if(bp == nil){
157 		qlock(e);
158 		if(e->nabufs < Nconns){
159 			bp = emallocz(sizeof(Buf), 1);
160 			e->nabufs++;
161 			setmalloctag(bp, getcallerpc(&e));
162 			deprint(2, "%s: %d buffers\n", argv0, e->nabufs);
163 		}
164 		qunlock(e);
165 	}
166 	if(bp == nil)
167 		bp = recvp(e->bc);
168 	bp->rp = bp->data + Hdrsize;
169 	bp->ndata = 0;
170 	if(0)deprint(2, "%s: allocbuf %#p\n", argv0, bp);
171 	qlock(e);
172 	e->nbufs++;
173 	qunlock(e);
174 	return bp;
175 }
176 
177 static Conn*
178 newconn(Ether *e)
179 {
180 	int i;
181 	Conn *c;
182 
183 	qlock(e);
184 	for(i = 0; i < nelem(e->conns); i++){
185 		c = e->conns[i];
186 		if(c == nil || c->ref == 0){
187 			if(c == nil){
188 				c = emallocz(sizeof(Conn), 1);
189 				c->rc = chancreate(sizeof(Buf*), 2);
190 				c->nb = i;
191 			}
192 			c->ref = 1;
193 			if(i == e->nconns)
194 				e->nconns++;
195 			e->conns[i] = c;
196 			deprint(2, "%s: newconn %d\n", argv0, i);
197 			qunlock(e);
198 			return c;
199 		}
200 	}
201 	qunlock(e);
202 	return nil;
203 }
204 
205 static char*
206 seprintaddr(char *s, char *se, uchar *addr)
207 {
208 	int i;
209 
210 	for(i = 0; i < Eaddrlen; i++)
211 		s = seprint(s, se, "%02x", addr[i]);
212 	return s;
213 }
214 
215 void
216 dumpframe(char *tag, void *p, int n)
217 {
218 	Etherpkt *ep;
219 	char buf[128];
220 	char *s, *se;
221 	int i;
222 
223 	ep = p;
224 	if(n < Eaddrlen * 2 + 2){
225 		fprint(2, "short packet (%d bytes)\n", n);
226 		return;
227 	}
228 	se = buf+sizeof(buf);
229 	s = seprint(buf, se, "%s [%d]: ", tag, n);
230 	s = seprintaddr(s, se, ep->s);
231 	s = seprint(s, se, " -> ");
232 	s = seprintaddr(s, se, ep->d);
233 	s = seprint(s, se, " type 0x%02ux%02ux ", ep->type[0], ep->type[1]);
234 	n -= Eaddrlen * 2 + 2;
235 	for(i = 0; i < n && i < 16; i++)
236 		s = seprint(s, se, "%02x", ep->data[i]);
237 	if(n >= 16)
238 		fprint(2, "%s...\n", buf);
239 	else
240 		fprint(2, "%s\n", buf);
241 }
242 
243 static char*
244 seprintstats(char *s, char *se, Ether *e)
245 {
246 	qlock(e);
247 	s = seprint(s, se, "in: %ld\n", e->nin);
248 	s = seprint(s, se, "out: %ld\n", e->nout);
249 	s = seprint(s, se, "input errs: %ld\n", e->nierrs);
250 	s = seprint(s, se, "output errs: %ld\n", e->noerrs);
251 	s = seprint(s, se, "mbps: %d\n", e->mbps);
252 	s = seprint(s, se, "prom: %ld\n", e->prom.ref);
253 	s = seprint(s, se, "addr: ");
254 	s = seprintaddr(s, se, e->addr);
255 	s = seprint(s, se, "\n");
256 	qunlock(e);
257 	return s;
258 }
259 
260 static char*
261 seprintifstats(char *s, char *se, Ether *e)
262 {
263 	int i;
264 	Conn *c;
265 
266 	qlock(e);
267 	s = seprint(s, se, "ctlr id: %#x\n", e->cid);
268 	s = seprint(s, se, "phy: %#x\n", e->phy);
269 	s = seprint(s, se, "exiting: %s\n", e->exiting ? "y" : "n");
270 	s = seprint(s, se, "conns: %d\n", e->nconns);
271 	s = seprint(s, se, "allocated bufs: %d\n", e->nabufs);
272 	s = seprint(s, se, "used bufs: %d\n", e->nbufs);
273 	for(i = 0; i < nelem(e->conns); i++){
274 		c = e->conns[i];
275 		if(c == nil)
276 			continue;
277 		if(c->ref == 0)
278 			s = seprint(s, se, "c[%d]: free\n", i);
279 		else{
280 			s = seprint(s, se, "c[%d]: refs %ld t %#x h %d p %d\n",
281 				c->nb, c->ref, c->type, c->headersonly, c->prom);
282 		}
283 	}
284 	qunlock(e);
285 	return s;
286 }
287 
288 static void
289 etherdump(Ether *e)
290 {
291 	char buf[256];
292 
293 	if(etherdebug == 0)
294 		return;
295 	seprintifstats(buf, buf+sizeof(buf), e);
296 	fprint(2, "%s: ether %#p:\n%s\n", argv0, e, buf);
297 }
298 
299 static Conn*
300 getconn(Ether *e, int i, int idleok)
301 {
302 	Conn *c;
303 
304 	qlock(e);
305 	if(i < 0 || i >= e->nconns)
306 		c = nil;
307 	else{
308 		c = e->conns[i];
309 		if(idleok == 0 && c != nil && c->ref == 0)
310 			c = nil;
311 	}
312 	qunlock(e);
313 	return c;
314 }
315 
316 static void
317 filldir(Usbfs *fs, Dir *d, Dirtab *tab, int cn)
318 {
319 	d->qid.path = mkqid(cn, tab->qid);
320 	d->qid.path |= fs->qid;
321 	d->mode = tab->mode;
322 	if((d->mode & DMDIR) != 0)
323 		d->qid.type = QTDIR;
324 	else
325 		d->qid.type = QTFILE;
326 	if(tab->qid == Qndir)
327 		snprint(d->name, Namesz, "%d", cn);
328 	else
329 		d->name = tab->name;
330 }
331 
332 static int
333 rootdirgen(Usbfs *fs, Qid, int i, Dir *d, void *)
334 {
335 	Ether *e;
336 	Dirtab *tab;
337 	int cn;
338 
339 	e = fs->aux;
340 	i++;				/* skip root */
341 	cn = 0;
342 	if(i < nelem(rootdirtab) - 1)	/* null terminated */
343 		tab = &rootdirtab[i];
344 	else{
345 		cn = i - nelem(rootdirtab) + 1;
346 		if(cn < e->nconns)
347 			tab = &conndirtab[0];
348 		else
349 			return -1;
350 	}
351 	filldir(fs, d, tab, cn);
352 	return 0;
353 }
354 
355 static int
356 conndirgen(Usbfs *fs, Qid q, int i, Dir *d, void *)
357 {
358 	Dirtab *tab;
359 
360 	i++;				/* skip root */
361 	if(i < nelem(conndirtab) - 1)	/* null terminated */
362 		tab = &conndirtab[i];
363 	else
364 		return -1;
365 	filldir(fs, d, tab, qnum(q.path));
366 	return 0;
367 }
368 
369 static int
370 fswalk(Usbfs *fs, Fid *fid, char *name)
371 {
372 	int cn, i;
373 	char *es;
374 	Dirtab *tab;
375 	Ether *e;
376 	Qid qid;
377 
378 	e = fs->aux;
379 	qid = fid->qid;
380 	qid.path &= ~fs->qid;
381 	if((qid.type & QTDIR) == 0){
382 		werrstr("walk in non-directory");
383 		return -1;
384 	}
385 
386 	if(strcmp(name, "..") == 0){
387 		/* must be /etherU%d; i.e. our root dir. */
388 		fid->qid.path = mkqid(0, Qroot) | fs->qid;
389 		fid->qid.vers = 0;
390 		fid->qid.type = QTDIR;
391 		return 0;
392 	}
393 	switch(qtype(qid.path)){
394 	case Qroot:
395 		if(name[0] >= '0' && name[0] <= '9'){
396 			es = name;
397 			cn = strtoul(name, &es, 10);
398 			if(cn >= e->nconns || *es != 0){
399 				werrstr(Enotfound);
400 				return -1;
401 			}
402 			fid->qid.path = mkqid(cn, Qndir) | fs->qid;
403 			fid->qid.vers = 0;
404 			return 0;
405 		}
406 		/* fall */
407 	case Qndir:
408 		if(qtype(qid.path) == Qroot)
409 			tab = rootdirtab;
410 		else
411 			tab = conndirtab;
412 		cn = qnum(qid.path);
413 		for(i = 0; tab[i].name != nil; tab++)
414 			if(strcmp(tab[i].name, name) == 0){
415 				fid->qid.path = mkqid(cn, tab[i].qid)|fs->qid;
416 				fid->qid.vers = 0;
417 				if((tab[i].mode & DMDIR) != 0)
418 					fid->qid.type = QTDIR;
419 				else
420 					fid->qid.type = QTFILE;
421 				return 0;
422 			}
423 		break;
424 	default:
425 		sysfatal("usb: ether: fswalk bug");
426 	}
427 	return -1;
428 }
429 
430 static Dirtab*
431 qdirtab(vlong q)
432 {
433 	int i, qt;
434 	Dirtab *tab;
435 
436 	qt = qtype(q);
437 	if(qt < nelem(rootdirtab) - 1){	/* null terminated */
438 		tab = rootdirtab;
439 		i = qt;
440 	}else{
441 		tab = conndirtab;
442 		i = qt - (nelem(rootdirtab) - 1);
443 		assert(i < nelem(conndirtab) - 1);
444 	}
445 	return &tab[i];
446 }
447 
448 static int
449 fsstat(Usbfs *fs, Qid qid, Dir *d)
450 {
451 	filldir(fs, d, qdirtab(qid.path), qnum(qid.path));
452 	return 0;
453 }
454 
455 static int
456 fsopen(Usbfs *fs, Fid *fid, int omode)
457 {
458 	int qt;
459 	vlong qid;
460 	Conn *c;
461 	Dirtab *tab;
462 	Ether *e;
463 
464 	qid = fid->qid.path & ~fs->qid;
465 	e = fs->aux;
466 	qt = qtype(qid);
467 	tab = qdirtab(qid);
468 	omode &= 3;
469 	if(omode != OREAD && (tab->mode&0222) == 0){
470 		werrstr(Eperm);
471 		return -1;
472 	}
473 	switch(qt){
474 	case Qclone:
475 		c = newconn(e);
476 		if(c == nil){
477 			werrstr("no more connections");
478 			return -1;
479 		}
480 		fid->qid.type = QTFILE;
481 		fid->qid.path = mkqid(c->nb, Qnctl)|fs->qid;
482 		fid->qid.vers = 0;
483 		break;
484 	case Qndata:
485 	case Qnctl:
486 	case Qnifstats:
487 	case Qnstats:
488 	case Qntype:
489 		c = getconn(e, qnum(qid), 1);
490 		if(c == nil)
491 			sysfatal("usb: ether: fsopen bug");
492 		incref(c);
493 		break;
494 	}
495 	etherdump(e);
496 	return 0;
497 }
498 
499 static int
500 prom(Ether *e, int set)
501 {
502 	if(e->promiscuous != nil)
503 		return e->promiscuous(e, set);
504 	return 0;
505 }
506 
507 static void
508 fsclunk(Usbfs *fs, Fid *fid)
509 {
510 	int qt;
511 	vlong qid;
512 	Buf *bp;
513 	Conn *c;
514 	Ether *e;
515 
516 	e = fs->aux;
517 	qid = fid->qid.path & ~fs->qid;
518 	qt = qtype(qid);
519 	switch(qt){
520 	case Qndata:
521 	case Qnctl:
522 	case Qnifstats:
523 	case Qnstats:
524 	case Qntype:
525 		if(fid->omode != ONONE){
526 			c = getconn(e, qnum(qid), 0);
527 			if(c == nil)
528 				sysfatal("usb: ether: fsopen bug");
529 			if(decref(c) == 0){
530 				while((bp = nbrecvp(c->rc)) != nil)
531 					freebuf(e, bp);
532 				qlock(e);
533 				if(c->prom != 0)
534 					if(decref(&e->prom) == 0)
535 						prom(e, 0);
536 				c->prom = c->type = 0;
537 				qunlock(e);
538 			}
539 		}
540 		break;
541 	}
542 	etherdump(e);
543 }
544 
545 int
546 parseaddr(uchar *m, char *s)
547 {
548 	int i, n;
549 	uchar v;
550 
551 	if(strlen(s) < 12)
552 		return -1;
553 	if(strlen(s) > 12 && strlen(s) < 17)
554 		return -1;
555 	for(i = n = 0; i < strlen(s); i++){
556 		if(s[i] == ':')
557 			continue;
558 		if(s[i] >= 'A' && s[i] <= 'F')
559 			v = 10 + s[i] - 'A';
560 		else if(s[i] >= 'a' && s[i] <= 'f')
561 			v = 10 + s[i] - 'a';
562 		else if(s[i] >= '0' && s[i] <= '9')
563 			v = s[i] - '0';
564 		else
565 			return -1;
566 		if(n&1)
567 			m[n/2] |= v;
568 		else
569 			m[n/2] = v<<4;
570 		n++;
571 	}
572 	return 0;
573 }
574 
575 static long
576 fsread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
577 {
578 	int cn, qt;
579 	char *s, *se;
580 	char buf[2048];		/* keep this large for ifstats */
581 	Buf *bp;
582 	Conn *c;
583 	Ether *e;
584 	Qid q;
585 
586 	q = fid->qid;
587 	q.path &= ~fs->qid;
588 	e = fs->aux;
589 	s = buf;
590 	se = buf+sizeof(buf);
591 	qt = qtype(q.path);
592 	cn = qnum(q.path);
593 	switch(qt){
594 	case Qroot:
595 		count = usbdirread(fs, q, data, count, offset, rootdirgen, nil);
596 		break;
597 	case Qaddr:
598 		s = seprintaddr(s, se, e->addr);
599 		count = usbreadbuf(data, count, offset, buf, s - buf);
600 		break;
601 	case Qnifstats:
602 		/* BUG */
603 	case Qifstats:
604 		s = seprintifstats(s, se, e);
605 		if(e->seprintstats != nil)
606 			s = e->seprintstats(s, se, e);
607 		count = usbreadbuf(data, count, offset, buf, s - buf);
608 		break;
609 	case Qnstats:
610 		/* BUG */
611 	case Qstats:
612 		s = seprintstats(s, se, e);
613 		count = usbreadbuf(data, count, offset, buf, s - buf);
614 		break;
615 
616 	case Qndir:
617 		count = usbdirread(fs, q, data, count, offset, conndirgen, nil);
618 		break;
619 	case Qndata:
620 		c = getconn(e, cn, 0);
621 		if(c == nil){
622 			werrstr(Eio);
623 			return -1;
624 		}
625 		bp = recvp(c->rc);
626 		if(bp == nil)
627 			return -1;
628 		if(etherdebug > 1)
629 			dumpframe("etherin", bp->rp, bp->ndata);
630 		count = usbreadbuf(data, count, 0LL, bp->rp, bp->ndata);
631 		freebuf(e, bp);
632 		break;
633 	case Qnctl:
634 		s = seprint(s, se, "%11d ", cn);
635 		count = usbreadbuf(data, count, offset, buf, s - buf);
636 		break;
637 	case Qntype:
638 		c = getconn(e, cn, 0);
639 		if(c == nil)
640 			s = seprint(s, se, "%11d ", 0);
641 		else
642 			s = seprint(s, se, "%11d ", c->type);
643 		count = usbreadbuf(data, count, offset, buf, s - buf);
644 		break;
645 	default:
646 		sysfatal("usb: ether: fsread bug");
647 	}
648 	return count;
649 }
650 
651 static int
652 typeinuse(Ether *e, int t)
653 {
654 	int i;
655 
656 	for(i = 0; i < e->nconns; i++)
657 		if(e->conns[i]->ref > 0 && e->conns[i]->type == t)
658 			return 1;
659 	return 0;
660 }
661 
662 static int
663 isloopback(Ether *e, Buf *)
664 {
665 	return e->prom.ref > 0; /* BUG: also loopbacks and broadcasts */
666 }
667 
668 static int
669 etherctl(Ether *e, Conn *c, char *buf)
670 {
671 	uchar addr[Eaddrlen];
672 	int t;
673 
674 	deprint(2, "%s: etherctl: %s\n", argv0, buf);
675 	if(strncmp(buf, "connect ", 8) == 0){
676 		t = atoi(buf+8);
677 		qlock(e);
678 		if(typeinuse(e, t)){
679 			werrstr("type already in use");
680 			qunlock(e);
681 			return -1;
682 		}
683 		c->type = atoi(buf+8);
684 		qunlock(e);
685 		return 0;
686 	}
687 	if(strncmp(buf, "nonblocking", 11) == 0){
688 		if(buf[11] == '\n' || buf[11] == 0)
689 			e->nblock = 1;
690 		else
691 			e->nblock = atoi(buf + 12);
692 		deprint(2, "%s: nblock %d\n", argv0, e->nblock);
693 		return 0;
694 	}
695 	if(strncmp(buf, "promiscuous", 11) == 0){
696 		if(c->prom == 0)
697 			incref(&e->prom);
698 		c->prom = 1;
699 		return prom(e, 1);
700 	}
701 	if(strncmp(buf, "headersonly", 11) == 0){
702 		c->headersonly = 1;
703 		return 0;
704 	}
705 	if(strncmp(buf, "addmulti ", 9) == 0 || strncmp(buf, "remmulti ", 9) == 0){
706 		if(parseaddr(addr, buf+9) < 0){
707 			werrstr("bad address");
708 			return -1;
709 		}
710 		if(e->multicast == nil)
711 			return 0;
712 		if(strncmp(buf, "add", 3) == 0){
713 			e->nmcasts++;
714 			return e->multicast(e, addr, 1);
715 		}else{
716 			e->nmcasts--;
717 			return e->multicast(e, addr, 0);
718 		}
719 	}
720 
721 	if(e->ctl != nil)
722 		return e->ctl(e, buf);
723 	werrstr(Ebadctl);
724 	return -1;
725 }
726 
727 static long
728 etherbread(Ether *e, Buf *bp)
729 {
730 	deprint(2, "%s: etherbread\n", argv0);
731 	bp->rp = bp->data + Hdrsize;
732 	bp->ndata = -1;
733 	bp->ndata = read(e->epin->dfd, bp->rp, sizeof(bp->data)-Hdrsize);
734 	if(bp->ndata < 0){
735 		deprint(2, "%s: etherbread: %r\n", argv0);	/* keep { and }  */
736 	}else
737 		deprint(2, "%s: etherbread: got %d bytes\n", argv0, bp->ndata);
738 	return bp->ndata;
739 }
740 
741 static long
742 etherbwrite(Ether *e, Buf *bp)
743 {
744 	long n;
745 
746 	deprint(2, "%s: etherbwrite %d bytes\n", argv0, bp->ndata);
747 	n = write(e->epout->dfd, bp->rp, bp->ndata);
748 	if(n < 0){
749 		deprint(2, "%s: etherbwrite: %r\n", argv0);	/* keep { and }  */
750 	}else
751 		deprint(2, "%s: etherbwrite wrote %ld bytes\n", argv0, n);
752 	if(n <= 0)
753 		return n;
754 	if((bp->ndata % e->epout->maxpkt) == 0){
755 		deprint(2, "%s: short pkt write\n", argv0);
756 		write(e->epout->dfd, "", 1);
757 	}
758 	return n;
759 }
760 
761 static long
762 fswrite(Usbfs *fs, Fid *fid, void *data, long count, vlong)
763 {
764 	int cn, qt;
765 	char buf[128];
766 	Buf *bp;
767 	Conn *c;
768 	Ether *e;
769 	Qid q;
770 
771 	q = fid->qid;
772 	q.path &= ~fs->qid;
773 	e = fs->aux;
774 	qt = qtype(q.path);
775 	cn = qnum(q.path);
776 	switch(qt){
777 	case Qndata:
778 		c = getconn(e, cn, 0);
779 		if(c == nil){
780 			werrstr(Eio);
781 			return -1;
782 		}
783 		bp = allocbuf(e);
784 		if(count > sizeof(bp->data)-Hdrsize)
785 			count = sizeof(bp->data)-Hdrsize;
786 		memmove(bp->rp, data, count);
787 		bp->ndata = count;
788 		if(etherdebug > 1)
789 			dumpframe("etherout", bp->rp, bp->ndata);
790 		if(e->nblock == 0)
791 			sendp(e->wc, bp);
792 		else if(nbsendp(e->wc, bp) == 0){
793 			deprint(2, "%s: (out) packet lost\n", argv0);
794 			freebuf(e, bp);
795 		}
796 		break;
797 	case Qnctl:
798 		c = getconn(e, cn, 0);
799 		if(c == nil){
800 			werrstr(Eio);
801 			return -1;
802 		}
803 		if(count > sizeof(buf) - 1)
804 			count = sizeof(buf) - 1;
805 		memmove(buf, data, count);
806 		buf[count] = 0;
807 		if(etherctl(e, c, buf) < 0)
808 			return -1;
809 		break;
810 	default:
811 		sysfatal("usb: ether: fsread bug");
812 	}
813 	return count;
814 }
815 
816 static int
817 openeps(Ether *e, int epin, int epout)
818 {
819 	e->epin = openep(e->dev, epin);
820 	if(e->epin == nil){
821 		fprint(2, "ether: in: openep %d: %r\n", epin);
822 		return -1;
823 	}
824 	if(epout == epin){
825 		incref(e->epin);
826 		e->epout = e->epin;
827 	}else
828 		e->epout = openep(e->dev, epout);
829 	if(e->epout == nil){
830 		fprint(2, "ether: out: openep %d: %r\n", epout);
831 		closedev(e->epin);
832 		return -1;
833 	}
834 	if(e->epin == e->epout)
835 		opendevdata(e->epin, ORDWR);
836 	else{
837 		opendevdata(e->epin, OREAD);
838 		opendevdata(e->epout, OWRITE);
839 	}
840 	if(e->epin->dfd < 0 || e->epout->dfd < 0){
841 		fprint(2, "ether: open i/o ep data: %r\n");
842 		closedev(e->epin);
843 		closedev(e->epout);
844 		return -1;
845 	}
846 	dprint(2, "ether: ep in %s maxpkt %d; ep out %s maxpkt %d\n",
847 		e->epin->dir, e->epin->maxpkt, e->epout->dir, e->epout->maxpkt);
848 
849 	/* time outs are not activated for I/O endpoints */
850 
851 	if(usbdebug > 2 || etherdebug > 2){
852 		devctl(e->epin, "debug 1");
853 		devctl(e->epout, "debug 1");
854 		devctl(e->dev, "debug 1");
855 	}
856 
857 	return 0;
858 }
859 
860 static int
861 usage(void)
862 {
863 	werrstr("usage: usb/ether [-d] [-N nb]");
864 	return -1;
865 }
866 
867 static Usbfs etherfs = {
868 	.walk = fswalk,
869 	.open =	 fsopen,
870 	.read =	 fsread,
871 	.write = fswrite,
872 	.stat =	 fsstat,
873 	.clunk = fsclunk,
874 };
875 
876 static void
877 shutdownchan(Channel *c)
878 {
879 	Buf *bp;
880 
881 	while((bp=nbrecvp(c)) != nil)
882 		free(bp);
883 	chanfree(c);
884 }
885 
886 static void
887 etherfree(Ether *e)
888 {
889 	int i;
890 	Buf *bp;
891 
892 	if(e->free != nil)
893 		e->free(e);
894 	closedev(e->epin);
895 	closedev(e->epout);
896 	if(e->rc == nil){	/* not really started */
897 		free(e);
898 		return;
899 	}
900 	for(i = 0; i < e->nconns; i++)
901 		if(e->conns[i] != nil){
902 			while((bp = nbrecvp(e->conns[i]->rc)) != nil)
903 				free(bp);
904 			chanfree(e->conns[i]->rc);
905 			free(e->conns[i]);
906 		}
907 	shutdownchan(e->bc);
908 	shutdownchan(e->rc);
909 	shutdownchan(e->wc);
910 	e->epin = e->epout = nil;
911 	devctl(e->dev, "detach");
912 	free(e);
913 }
914 
915 static void
916 etherdevfree(void *a)
917 {
918 	Ether *e = a;
919 
920 	if(e != nil)
921 		etherfree(e);
922 }
923 
924 /* must return 1 if c wants bp; 0 if not */
925 static int
926 cwantsbp(Conn *c, Buf *bp)
927 {
928 	if(c->ref != 0 && (c->prom != 0 || c->type < 0 || c->type == bp->type))
929 		return 1;
930 	return 0;
931 }
932 
933 static void
934 etherwriteproc(void *a)
935 {
936 	Ether *e = a;
937 	Buf *bp;
938 	Channel *wc;
939 
940 	wc = e->wc;
941 	while(e->exiting == 0){
942 		bp = recvp(wc);
943 		if(bp == nil || e->exiting != 0){
944 			free(bp);
945 			break;
946 		}
947 		e->nout++;
948 		if(e->bwrite(e, bp) < 0)
949 			e->noerrs++;
950 		if(isloopback(e, bp) && e->exiting == 0)
951 			sendp(e->rc, bp); /* send to input queue */
952 		else
953 			freebuf(e, bp);
954 	}
955 	deprint(2, "%s: writeproc exiting\n", argv0);
956 	closedev(e->dev);
957 }
958 
959 static void
960 setbuftype(Buf *bp)
961 {
962 	uchar *p;
963 
964 	bp->type = 0;
965 	if(bp->ndata >= Ehdrsize){
966 		p = bp->rp + Eaddrlen*2;
967 		bp->type = p[0]<<8 | p[1];
968 	}
969 }
970 
971 static void
972 etherexiting(Ether *e)
973 {
974 	devctl(e->dev, "detach");
975 	e->exiting = 1;
976 	close(e->epin->dfd);
977 	e->epin->dfd = -1;
978 	close(e->epout->dfd);
979 	e->epout->dfd = -1;
980 	nbsend(e->wc, nil);
981 }
982 
983 static void
984 etherreadproc(void *a)
985 {
986 	int i, n, nwants;
987 	Buf *bp, *dbp;
988 	Ether *e = a;
989 
990 	while(e->exiting == 0){
991 		bp = nbrecvp(e->rc);
992 		if(bp == nil){
993 			bp = allocbuf(e);	/* leak() may think we leak */
994 			if(e->bread(e, bp) < 0){
995 				freebuf(e, bp);
996 				break;
997 			}
998 			if(bp->ndata == 0){
999 				/* may be a short packet; continue */
1000 				if(0)dprint(2, "%s: read: short\n", argv0);
1001 				freebuf(e, bp);
1002 				continue;
1003 			}else
1004 				setbuftype(bp);
1005 		}
1006 		e->nin++;
1007 		nwants = 0;
1008 		for(i = 0; i < e->nconns; i++)
1009 			nwants += cwantsbp(e->conns[i], bp);
1010 		for(i = 0; nwants > 0 && i < e->nconns; i++)
1011 			if(cwantsbp(e->conns[i], bp)){
1012 				n = bp->ndata;
1013 				if(e->conns[i]->type == -2 && n > 64)
1014 					n = 64;
1015 				if(nwants-- == 1){
1016 					bp->ndata = n;
1017 					dbp = bp;
1018 					bp = nil;
1019 				}else{
1020 					dbp = allocbuf(e);
1021 					memmove(dbp->rp, bp->rp, n);
1022 					dbp->ndata = n;
1023 					dbp->type = bp->type;
1024 				}
1025 				if(nbsendp(e->conns[i]->rc, dbp) == 0){
1026 					e->nierrs++;
1027 					freebuf(e, dbp);
1028 				}
1029 			}
1030 		freebuf(e, bp);
1031 	}
1032 	deprint(2, "%s: writeproc exiting\n", argv0);
1033 	etherexiting(e);
1034 	closedev(e->dev);
1035 	usbfsdel(&e->fs);
1036 }
1037 
1038 static void
1039 setalt(Dev *d, int ifcid, int altid)
1040 {
1041 	if(usbcmd(d, Rh2d|Rstd|Riface, Rsetiface, altid, ifcid, nil, 0) < 0)
1042 		dprint(2, "%s: setalt ifc %d alt %d: %r\n", argv0, ifcid, altid);
1043 }
1044 
1045 static int
1046 ifaceinit(Ether *e, Iface *ifc, int *ei, int *eo)
1047 {
1048 	Ep *ep;
1049 	int epin, epout, i;
1050 
1051 	if(ifc == nil)
1052 		return -1;
1053 
1054 	epin = epout = -1;
1055 	for(i = 0; (epin < 0 || epout < 0) && i < nelem(ifc->ep); i++)
1056 		if((ep = ifc->ep[i]) != nil && ep->type == Ebulk){
1057 			if(ep->dir == Eboth || ep->dir == Ein)
1058 				if(epin == -1)
1059 					epin =  ep->id;
1060 			if(ep->dir == Eboth || ep->dir == Eout)
1061 				if(epout == -1)
1062 					epout = ep->id;
1063 		}
1064 	if(epin == -1 || epout == -1)
1065 		return -1;
1066 
1067 	dprint(2, "ether: ep ids: in %d out %d\n", epin, epout);
1068 	for(i = 0; i < nelem(ifc->altc); i++)
1069 		if(ifc->altc[i] != nil)
1070 			setalt(e->dev, ifc->id, i);
1071 
1072 	*ei = epin;
1073 	*eo = epout;
1074 	return 0;
1075 }
1076 
1077 static int
1078 etherinit(Ether *e, int *ei, int *eo)
1079 {
1080 	int ctlid, datid, i, j;
1081 	Conf *c;
1082 	Desc *desc;
1083 	Iface *ctlif, *datif;
1084 	Usbdev *ud;
1085 
1086 	*ei = *eo = -1;
1087 	ud = e->dev->usb;
1088 
1089 	/* look for union descriptor with ethernet ctrl interface */
1090 	for(i = 0; i < nelem(ud->ddesc); i++){
1091 		if((desc = ud->ddesc[i]) == nil)
1092 			continue;
1093 		if(desc->data.bLength < 5 || desc->data.bbytes[0] != Cdcunion)
1094 			continue;
1095 
1096 		ctlid = desc->data.bbytes[1];
1097 		datid = desc->data.bbytes[2];
1098 
1099 		if((c = desc->conf) == nil)
1100 			continue;
1101 
1102 		ctlif = datif = nil;
1103 		for(j = 0; j < nelem(c->iface); j++){
1104 			if(c->iface[j] == nil)
1105 				continue;
1106 			if(c->iface[j]->id == ctlid)
1107 				ctlif = c->iface[j];
1108 			if(c->iface[j]->id == datid)
1109 				datif = c->iface[j];
1110 
1111 			if(datif != nil && ctlif != nil){
1112 				if(Subclass(ctlif->csp) == Scether &&
1113 				    ifaceinit(e, datif, ei, eo) != -1)
1114 					return 0;
1115 				break;
1116 			}
1117 		}
1118 	}
1119 	/* try any other one that seems to be ok */
1120 	for(i = 0; i < nelem(ud->conf); i++)
1121 		if((c = ud->conf[i]) != nil)
1122 			for(j = 0; j < nelem(c->iface); j++)
1123 				if(ifaceinit(e, c->iface[j], ei, eo) != -1)
1124 					return 0;
1125 	dprint(2, "%s: no valid endpoints", argv0);
1126 	return -1;
1127 }
1128 
1129 int
1130 ethermain(Dev *dev, int argc, char **argv)
1131 {
1132 	int epin, epout, i, devid;
1133 	Ether *e;
1134 
1135 	devid = dev->id;
1136 	ARGBEGIN{
1137 	case 'd':
1138 		if(etherdebug == 0)
1139 			fprint(2, "ether debug on\n");
1140 		etherdebug++;
1141 		break;
1142 	case 'N':
1143 		devid = atoi(EARGF(usage()));
1144 		break;
1145 	default:
1146 		return usage();
1147 	}ARGEND
1148 	if(argc != 0) {
1149 		return usage();
1150 	}
1151 	e = dev->aux = emallocz(sizeof(Ether), 1);
1152 	e->dev = dev;
1153 	dev->free = etherdevfree;
1154 
1155 	for(i = 0; i < nelem(ethers); i++)
1156 		if(ethers[i](e) == 0)
1157 			break;
1158 	if(i == nelem(ethers))
1159 		return -1;
1160 	if(e->init == nil)
1161 		e->init = etherinit;
1162 	if(e->init(e, &epin, &epout) < 0)
1163 		return -1;
1164 	if(e->bwrite == nil)
1165 		e->bwrite = etherbwrite;
1166 	if(e->bread == nil)
1167 		e->bread = etherbread;
1168 
1169 	if(openeps(e, epin, epout) < 0)
1170 		return -1;
1171 	e->fs = etherfs;
1172 	snprint(e->fs.name, sizeof(e->fs.name), "etherU%d", devid);
1173 	e->fs.dev = dev;
1174 	e->fs.aux = e;
1175 	e->bc = chancreate(sizeof(Buf*), Nconns);
1176 	e->rc = chancreate(sizeof(Buf*), Nconns/2);
1177 	e->wc = chancreate(sizeof(Buf*), Nconns*2);
1178 	incref(e->dev);
1179 	proccreate(etherwriteproc, e, 16*1024);
1180 	incref(e->dev);
1181 	proccreate(etherreadproc, e, 16*1024);
1182 	deprint(2, "%s: dev ref %ld\n", argv0, dev->ref);
1183 	incref(e->dev);
1184 	usbfsadd(&e->fs);
1185 	return 0;
1186 }
1187