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