xref: /plan9/sys/src/cmd/usb/ether/ether.c (revision bfb6eab9346d861b5f68a2b1af55a1768a8fe25b)
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: %s\n", e->exiting ? "y" : "n");
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 static int
355 conndirgen(Usbfs *fs, Qid q, int i, Dir *d, void *)
356 {
357 	Dirtab *tab;
358 
359 	i++;				/* skip root */
360 	if(i < nelem(conndirtab) - 1)	/* null terminated */
361 		tab = &conndirtab[i];
362 	else
363 		return -1;
364 	filldir(fs, d, tab, qnum(q.path));
365 	return 0;
366 }
367 
368 static int
369 fswalk(Usbfs *fs, Fid *fid, char *name)
370 {
371 	int cn, i;
372 	char *es;
373 	Dirtab *tab;
374 	Ether *e;
375 	Qid qid;
376 
377 	e = fs->aux;
378 	qid = fid->qid;
379 	qid.path &= ~fs->qid;
380 	if((qid.type & QTDIR) == 0){
381 		werrstr("walk in non-directory");
382 		return -1;
383 	}
384 
385 	if(strcmp(name, "..") == 0){
386 		/* must be /etherU%d; i.e. our root dir. */
387 		fid->qid.path = mkqid(0, Qroot) | fs->qid;
388 		fid->qid.vers = 0;
389 		fid->qid.type = QTDIR;
390 		return 0;
391 	}
392 	switch(qtype(qid.path)){
393 	case Qroot:
394 		if(name[0] >= '0' && name[0] <= '9'){
395 			es = name;
396 			cn = strtoul(name, &es, 10);
397 			if(cn >= e->nconns || *es != 0){
398 				werrstr(Enotfound);
399 				return -1;
400 			}
401 			fid->qid.path = mkqid(cn, Qndir) | fs->qid;
402 			fid->qid.vers = 0;
403 			return 0;
404 		}
405 		/* fall */
406 	case Qndir:
407 		if(qtype(qid.path) == Qroot)
408 			tab = rootdirtab;
409 		else
410 			tab = conndirtab;
411 		cn = qnum(qid.path);
412 		for(i = 0; tab[i].name != nil; tab++)
413 			if(strcmp(tab[i].name, name) == 0){
414 				fid->qid.path = mkqid(cn, tab[i].qid)|fs->qid;
415 				fid->qid.vers = 0;
416 				if((tab[i].mode & DMDIR) != 0)
417 					fid->qid.type = QTDIR;
418 				else
419 					fid->qid.type = QTFILE;
420 				return 0;
421 			}
422 		break;
423 	default:
424 		sysfatal("usb: ether: fswalk bug");
425 	}
426 	return -1;
427 }
428 
429 static Dirtab*
430 qdirtab(vlong q)
431 {
432 	int i, qt;
433 	Dirtab *tab;
434 
435 	qt = qtype(q);
436 	if(qt < nelem(rootdirtab) - 1){	/* null terminated */
437 		tab = rootdirtab;
438 		i = qt;
439 	}else{
440 		tab = conndirtab;
441 		i = qt - (nelem(rootdirtab) - 1);
442 		assert(i < nelem(conndirtab) - 1);
443 	}
444 	return &tab[i];
445 }
446 
447 static int
448 fsstat(Usbfs *fs, Qid qid, Dir *d)
449 {
450 	filldir(fs, d, qdirtab(qid.path), qnum(qid.path));
451 	return 0;
452 }
453 
454 static int
455 fsopen(Usbfs *fs, Fid *fid, int omode)
456 {
457 	int qt;
458 	vlong qid;
459 	Conn *c;
460 	Dirtab *tab;
461 	Ether *e;
462 
463 	qid = fid->qid.path & ~fs->qid;
464 	e = fs->aux;
465 	qt = qtype(qid);
466 	tab = qdirtab(qid);
467 	omode &= 3;
468 	if(omode != OREAD && (tab->mode&0222) == 0){
469 		werrstr(Eperm);
470 		return -1;
471 	}
472 	switch(qt){
473 	case Qclone:
474 		c = newconn(e);
475 		if(c == nil){
476 			werrstr("no more connections");
477 			return -1;
478 		}
479 		fid->qid.type = QTFILE;
480 		fid->qid.path = mkqid(c->nb, Qnctl)|fs->qid;
481 		fid->qid.vers = 0;
482 		break;
483 	case Qndata:
484 	case Qnctl:
485 	case Qnifstats:
486 	case Qnstats:
487 	case Qntype:
488 		c = getconn(e, qnum(qid), 1);
489 		if(c == nil)
490 			sysfatal("usb: ether: fsopen bug");
491 		incref(c);
492 		break;
493 	}
494 	etherdump(e);
495 	return 0;
496 }
497 
498 static int
499 prom(Ether *e, int set)
500 {
501 	if(e->promiscuous != nil)
502 		return e->promiscuous(e, set);
503 	return 0;
504 }
505 
506 static void
507 fsclunk(Usbfs *fs, Fid *fid)
508 {
509 	int qt;
510 	vlong qid;
511 	Buf *bp;
512 	Conn *c;
513 	Ether *e;
514 
515 	e = fs->aux;
516 	qid = fid->qid.path & ~fs->qid;
517 	qt = qtype(qid);
518 	switch(qt){
519 	case Qndata:
520 	case Qnctl:
521 	case Qnifstats:
522 	case Qnstats:
523 	case Qntype:
524 		if(fid->omode != ONONE){
525 			c = getconn(e, qnum(qid), 0);
526 			if(c == nil)
527 				sysfatal("usb: ether: fsopen bug");
528 			if(decref(c) == 0){
529 				while((bp = nbrecvp(c->rc)) != nil)
530 					freebuf(e, bp);
531 				qlock(e);
532 				if(c->prom != 0)
533 					if(decref(&e->prom) == 0)
534 						prom(e, 0);
535 				c->prom = c->type = 0;
536 				qunlock(e);
537 			}
538 		}
539 		break;
540 	}
541 	etherdump(e);
542 }
543 
544 int
545 parseaddr(uchar *m, char *s)
546 {
547 	int i, n;
548 	uchar v;
549 
550 	if(strlen(s) < 12)
551 		return -1;
552 	if(strlen(s) > 12 && strlen(s) < 17)
553 		return -1;
554 	for(i = n = 0; i < strlen(s); i++){
555 		if(s[i] == ':')
556 			continue;
557 		if(s[i] >= 'A' && s[i] <= 'F')
558 			v = 10 + s[i] - 'A';
559 		else if(s[i] >= 'a' && s[i] <= 'f')
560 			v = 10 + s[i] - 'a';
561 		else if(s[i] >= '0' && s[i] <= '9')
562 			v = s[i] - '0';
563 		else
564 			return -1;
565 		if(n&1)
566 			m[n/2] |= v;
567 		else
568 			m[n/2] = v<<4;
569 		n++;
570 	}
571 	return 0;
572 }
573 
574 static long
575 fsread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
576 {
577 	int cn, qt;
578 	char *s, *se;
579 	char buf[128];
580 	Buf *bp;
581 	Conn *c;
582 	Ether *e;
583 	Qid q;
584 
585 	q = fid->qid;
586 	q.path &= ~fs->qid;
587 	e = fs->aux;
588 	s = buf;
589 	se = buf+sizeof(buf);
590 	qt = qtype(q.path);
591 	cn = qnum(q.path);
592 	switch(qt){
593 	case Qroot:
594 		count = usbdirread(fs, q, data, count, offset, rootdirgen, nil);
595 		break;
596 	case Qaddr:
597 		s = seprintaddr(s, se, e->addr);
598 		count = usbreadbuf(data, count, offset, buf, s - buf);
599 		break;
600 	case Qnifstats:
601 		/* BUG */
602 	case Qifstats:
603 		s = seprintifstats(s, se, e);
604 		if(e->seprintstats != nil)
605 			s = e->seprintstats(s, se, e);
606 		count = usbreadbuf(data, count, offset, buf, s - buf);
607 		break;
608 	case Qnstats:
609 		/* BUG */
610 	case Qstats:
611 		s = seprintstats(s, se, e);
612 		count = usbreadbuf(data, count, offset, buf, s - buf);
613 		break;
614 
615 	case Qndir:
616 		count = usbdirread(fs, q, data, count, offset, conndirgen, nil);
617 		break;
618 	case Qndata:
619 		c = getconn(e, cn, 0);
620 		if(c == nil){
621 			werrstr(Eio);
622 			return -1;
623 		}
624 		bp = recvp(c->rc);
625 		if(bp == nil)
626 			return -1;
627 		if(etherdebug > 1)
628 			dumpframe("etherin", bp->rp, bp->ndata);
629 		count = usbreadbuf(data, count, 0LL, bp->rp, bp->ndata);
630 		freebuf(e, bp);
631 		break;
632 	case Qnctl:
633 		s = seprint(s, se, "%11d ", cn);
634 		count = usbreadbuf(data, count, offset, buf, s - buf);
635 		break;
636 	case Qntype:
637 		c = getconn(e, cn, 0);
638 		if(c == nil)
639 			s = seprint(s, se, "%11d ", 0);
640 		else
641 			s = seprint(s, se, "%11d ", c->type);
642 		count = usbreadbuf(data, count, offset, buf, s - buf);
643 		break;
644 	default:
645 		sysfatal("usb: ether: fsread bug");
646 	}
647 	return count;
648 }
649 
650 static int
651 typeinuse(Ether *e, int t)
652 {
653 	int i;
654 
655 	for(i = 0; i < e->nconns; i++)
656 		if(e->conns[i]->ref > 0 && e->conns[i]->type == t)
657 			return 1;
658 	return 0;
659 }
660 
661 static int
662 isloopback(Ether *e, Buf *)
663 {
664 	return e->prom.ref > 0; /* BUG: also loopbacks and broadcasts */
665 }
666 
667 static int
668 etherctl(Ether *e, Conn *c, char *buf)
669 {
670 	uchar addr[Eaddrlen];
671 	int t;
672 
673 	deprint(2, "%s: etherctl: %s\n", argv0, buf);
674 	if(strncmp(buf, "connect ", 8) == 0){
675 		t = atoi(buf+8);
676 		qlock(e);
677 		if(typeinuse(e, t)){
678 			werrstr("type already in use");
679 			qunlock(e);
680 			return -1;
681 		}
682 		c->type = atoi(buf+8);
683 		qunlock(e);
684 		return 0;
685 	}
686 	if(strncmp(buf, "nonblocking", 11) == 0){
687 		if(buf[11] == '\n' || buf[11] == 0)
688 			e->nblock = 1;
689 		else
690 			e->nblock = atoi(buf + 12);
691 		deprint(2, "%s: nblock %d\n", argv0, e->nblock);
692 		return 0;
693 	}
694 	if(strncmp(buf, "promiscuous", 11) == 0){
695 		if(c->prom == 0)
696 			incref(&e->prom);
697 		c->prom = 1;
698 		return prom(e, 1);
699 	}
700 	if(strncmp(buf, "headersonly", 11) == 0){
701 		c->headersonly = 1;
702 		return 0;
703 	}
704 	if(strncmp(buf, "addmulti ", 9) == 0 || strncmp(buf, "remmulti ", 9) == 0){
705 		if(parseaddr(addr, buf+9) < 0){
706 			werrstr("bad address");
707 			return -1;
708 		}
709 		if(e->multicast == nil)
710 			return 0;
711 		if(strncmp(buf, "add", 3) == 0){
712 			e->nmcasts++;
713 			return e->multicast(e, addr, 1);
714 		}else{
715 			e->nmcasts--;
716 			return e->multicast(e, addr, 0);
717 		}
718 	}
719 
720 	if(e->ctl != nil)
721 		return e->ctl(e, buf);
722 	werrstr(Ebadctl);
723 	return -1;
724 }
725 
726 static long
727 etherbread(Ether *e, Buf *bp)
728 {
729 	deprint(2, "%s: etherbread\n", argv0);
730 	bp->rp = bp->data + Hdrsize;
731 	bp->ndata = -1;
732 	bp->ndata = read(e->epin->dfd, bp->rp, sizeof(bp->data)-Hdrsize);
733 	if(bp->ndata < 0){
734 		deprint(2, "%s: etherbread: %r\n", argv0);	/* keep { and }  */
735 	}else
736 		deprint(2, "%s: etherbread: got %d bytes\n", argv0, bp->ndata);
737 	return bp->ndata;
738 }
739 
740 static long
741 etherbwrite(Ether *e, Buf *bp)
742 {
743 	long n;
744 
745 	deprint(2, "%s: etherbwrite %d bytes\n", argv0, bp->ndata);
746 	n = write(e->epout->dfd, bp->rp, bp->ndata);
747 	if(n < 0){
748 		deprint(2, "%s: etherbwrite: %r\n", argv0);	/* keep { and }  */
749 	}else
750 		deprint(2, "%s: etherbwrite wrote %ld bytes\n", argv0, n);
751 	if(n <= 0)
752 		return n;
753 	if((bp->ndata % e->epout->maxpkt) == 0){
754 		deprint(2, "%s: short pkt write\n", argv0);
755 		write(e->epout->dfd, "", 1);
756 	}
757 	return n;
758 }
759 
760 static long
761 fswrite(Usbfs *fs, Fid *fid, void *data, long count, vlong)
762 {
763 	int cn, qt;
764 	char buf[128];
765 	Buf *bp;
766 	Conn *c;
767 	Ether *e;
768 	Qid q;
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 maxpkt %d; ep out %s maxpkt %d\n",
846 		e->epin->dir, e->epin->maxpkt, e->epout->dir, e->epout->maxpkt);
847 
848 	/* time outs are not activated for I/O endpoints */
849 
850 	if(usbdebug > 2 || etherdebug > 2){
851 		devctl(e->epin, "debug 1");
852 		devctl(e->epout, "debug 1");
853 		devctl(e->dev, "debug 1");
854 	}
855 
856 	return 0;
857 }
858 
859 static int
860 usage(void)
861 {
862 	werrstr("usage: usb/ether [-d]");
863 	return -1;
864 }
865 
866 static Usbfs etherfs = {
867 	.walk = fswalk,
868 	.open =	 fsopen,
869 	.read =	 fsread,
870 	.write = fswrite,
871 	.stat =	 fsstat,
872 	.clunk = fsclunk,
873 };
874 
875 static void
876 shutdownchan(Channel *c)
877 {
878 	Buf *bp;
879 
880 	while((bp=nbrecvp(c)) != nil)
881 		free(bp);
882 	chanfree(c);
883 }
884 
885 static void
886 etherfree(Ether *e)
887 {
888 	int i;
889 	Buf *bp;
890 
891 	if(e->free != nil)
892 		e->free(e);
893 	closedev(e->epin);
894 	closedev(e->epout);
895 	if(e->rc == nil){	/* not really started */
896 		free(e);
897 		return;
898 	}
899 	for(i = 0; i < e->nconns; i++)
900 		if(e->conns[i] != nil){
901 			while((bp = nbrecvp(e->conns[i]->rc)) != nil)
902 				free(bp);
903 			chanfree(e->conns[i]->rc);
904 			free(e->conns[i]);
905 		}
906 	shutdownchan(e->bc);
907 	shutdownchan(e->rc);
908 	shutdownchan(e->wc);
909 	e->epin = e->epout = nil;
910 	free(e);
911 }
912 
913 static void
914 etherdevfree(void *a)
915 {
916 	Ether *e = a;
917 
918 	if(e != nil)
919 		etherfree(e);
920 }
921 
922 /* must return 1 if c wants bp; 0 if not */
923 static int
924 cwantsbp(Conn *c, Buf *bp)
925 {
926 	if(c->ref != 0 && (c->prom != 0 || c->type < 0 || c->type == bp->type))
927 		return 1;
928 	return 0;
929 }
930 
931 static void
932 etherwriteproc(void *a)
933 {
934 	Ether *e = a;
935 	Buf *bp;
936 	Channel *wc;
937 
938 	wc = e->wc;
939 	while(e->exiting == 0){
940 		bp = recvp(wc);
941 		if(bp == nil || e->exiting != 0){
942 			free(bp);
943 			break;
944 		}
945 		e->nout++;
946 		if(e->bwrite(e, bp) < 0)
947 			e->noerrs++;
948 		if(isloopback(e, bp) && e->exiting == 0)
949 			sendp(e->rc, bp); /* send to input queue */
950 		else
951 			freebuf(e, bp);
952 	}
953 	deprint(2, "%s: writeproc exiting\n", argv0);
954 	closedev(e->dev);
955 }
956 
957 static void
958 setbuftype(Buf *bp)
959 {
960 	uchar *p;
961 
962 	bp->type = 0;
963 	if(bp->ndata >= Ehdrsize){
964 		p = bp->rp + Eaddrlen*2;
965 		bp->type = p[0]<<8 | p[1];
966 	}
967 }
968 
969 static void
970 etherexiting(Ether *e)
971 {
972 	devctl(e->dev, "detach");
973 	e->exiting = 1;
974 	close(e->epin->dfd);
975 	e->epin->dfd = -1;
976 	close(e->epout->dfd);
977 	e->epout->dfd = -1;
978 	nbsend(e->wc, nil);
979 }
980 
981 static void
982 etherreadproc(void *a)
983 {
984 	int i, n, nwants;
985 	Buf *bp, *dbp;
986 	Ether *e = a;
987 
988 	while(e->exiting == 0){
989 		bp = nbrecvp(e->rc);
990 		if(bp == nil){
991 			bp = allocbuf(e);	/* leak() may think we leak */
992 			if(e->bread(e, bp) < 0){
993 				freebuf(e, bp);
994 				break;
995 			}
996 			if(bp->ndata == 0){
997 				/* may be a short packet; continue */
998 				if(0)dprint(2, "%s: read: short\n", argv0);
999 				freebuf(e, bp);
1000 				continue;
1001 			}else
1002 				setbuftype(bp);
1003 		}
1004 		e->nin++;
1005 		nwants = 0;
1006 		for(i = 0; i < e->nconns; i++)
1007 			nwants += cwantsbp(e->conns[i], bp);
1008 		for(i = 0; nwants > 0 && i < e->nconns; i++)
1009 			if(cwantsbp(e->conns[i], bp)){
1010 				n = bp->ndata;
1011 				if(e->conns[i]->type == -2 && n > 64)
1012 					n = 64;
1013 				if(nwants-- == 1){
1014 					bp->ndata = n;
1015 					dbp = bp;
1016 					bp = nil;
1017 				}else{
1018 					dbp = allocbuf(e);
1019 					memmove(dbp->rp, bp->rp, n);
1020 					dbp->ndata = n;
1021 					dbp->type = bp->type;
1022 				}
1023 				if(nbsendp(e->conns[i]->rc, dbp) == 0){
1024 					e->nierrs++;
1025 					freebuf(e, dbp);
1026 				}
1027 			}
1028 		freebuf(e, bp);
1029 	}
1030 	deprint(2, "%s: writeproc exiting\n", argv0);
1031 	etherexiting(e);
1032 	closedev(e->dev);
1033 }
1034 
1035 static void
1036 setalt(Dev *d, int ifcid, int altid)
1037 {
1038 	if(usbcmd(d, Rh2d|Rstd|Riface, Rsetiface, altid, ifcid, nil, 0) < 0)
1039 		dprint(2, "%s: setalt ifc %d alt %d: %r\n", argv0, ifcid, altid);
1040 }
1041 
1042 static int
1043 ifaceinit(Ether *e, Iface *ifc, int *ei, int *eo)
1044 {
1045 	Ep *ep;
1046 	int epin, epout, i;
1047 
1048 	if(ifc == nil)
1049 		return -1;
1050 
1051 	epin = epout = -1;
1052 	for(i = 0; (epin < 0 || epout < 0) && i < nelem(ifc->ep); i++)
1053 		if((ep = ifc->ep[i]) != nil && ep->type == Ebulk){
1054 			if(ep->dir == Eboth || ep->dir == Ein)
1055 				if(epin == -1)
1056 					epin =  ep->id;
1057 			if(ep->dir == Eboth || ep->dir == Eout)
1058 				if(epout == -1)
1059 					epout = ep->id;
1060 		}
1061 	if(epin == -1 || epout == -1)
1062 		return -1;
1063 
1064 	dprint(2, "ether: ep ids: in %d out %d\n", epin, epout);
1065 	for(i = 0; i < nelem(ifc->altc); i++)
1066 		if(ifc->altc[i] != nil)
1067 			setalt(e->dev, ifc->id, i);
1068 
1069 	*ei = epin;
1070 	*eo = epout;
1071 	return 0;
1072 }
1073 
1074 static int
1075 etherinit(Ether *e, int *ei, int *eo)
1076 {
1077 	int ctlid, datid, i, j;
1078 	Conf *c;
1079 	Desc *desc;
1080 	Iface *ctlif, *datif;
1081 	Usbdev *ud;
1082 
1083 	*ei = *eo = -1;
1084 	ud = e->dev->usb;
1085 
1086 	/* look for union descriptor with ethernet ctrl interface */
1087 	for(i = 0; i < nelem(ud->ddesc); i++){
1088 		if((desc = ud->ddesc[i]) == nil)
1089 			continue;
1090 		if(desc->data.bLength < 5 || desc->data.bbytes[0] != Cdcunion)
1091 			continue;
1092 
1093 		ctlid = desc->data.bbytes[1];
1094 		datid = desc->data.bbytes[2];
1095 
1096 		if((c = desc->conf) == nil)
1097 			continue;
1098 
1099 		ctlif = datif = nil;
1100 		for(j = 0; j < nelem(c->iface); j++){
1101 			if(c->iface[j] == nil)
1102 				continue;
1103 			if(c->iface[j]->id == ctlid)
1104 				ctlif = c->iface[j];
1105 			if(c->iface[j]->id == datid)
1106 				datif = c->iface[j];
1107 
1108 			if(datif != nil && ctlif != nil){
1109 				if(Subclass(ctlif->csp) == Scether &&
1110 				    ifaceinit(e, datif, ei, eo) != -1)
1111 					return 0;
1112 				break;
1113 			}
1114 		}
1115 	}
1116 	/* try any other one that seems to be ok */
1117 	for(i = 0; i < nelem(ud->conf); i++)
1118 		if((c = ud->conf[i]) != nil)
1119 			for(j = 0; j < nelem(c->iface); j++)
1120 				if(ifaceinit(e, c->iface[j], ei, eo) != -1)
1121 					return 0;
1122 	dprint(2, "%s: no valid endpoints", argv0);
1123 	return -1;
1124 }
1125 
1126 int
1127 ethermain(Dev *dev, int argc, char **argv)
1128 {
1129 	int epin, epout, i;
1130 	Ether *e;
1131 
1132 	ARGBEGIN{
1133 	case 'd':
1134 		if(etherdebug == 0)
1135 			fprint(2, "ether debug on\n");
1136 		etherdebug++;
1137 		break;
1138 	default:
1139 		return usage();
1140 	}ARGEND
1141 	if(argc != 0)
1142 		return usage();
1143 
1144 	e = dev->aux = emallocz(sizeof(Ether), 1);
1145 	e->dev = dev;
1146 	dev->free = etherdevfree;
1147 
1148 	for(i = 0; i < nelem(ethers); i++)
1149 		if(ethers[i](e) == 0)
1150 			break;
1151 	if(i == nelem(ethers))
1152 		return -1;
1153 	if(e->init == nil)
1154 		e->init = etherinit;
1155 	if(e->init(e, &epin, &epout) < 0)
1156 		return -1;
1157 	if(e->bwrite == nil)
1158 		e->bwrite = etherbwrite;
1159 	if(e->bread == nil)
1160 		e->bread = etherbread;
1161 
1162 	if(openeps(e, epin, epout) < 0)
1163 		return -1;
1164 	e->fs = etherfs;
1165 	snprint(e->fs.name, sizeof(e->fs.name), "etherU%d", dev->id);
1166 	e->fs.dev = dev;
1167 	e->fs.aux = e;
1168 	e->bc = chancreate(sizeof(Buf*), Nconns);
1169 	e->rc = chancreate(sizeof(Buf*), Nconns/2);
1170 	e->wc = chancreate(sizeof(Buf*), Nconns*2);
1171 	incref(e->dev);
1172 	proccreate(etherwriteproc, e, 16*1024);
1173 	incref(e->dev);
1174 	proccreate(etherreadproc, e, 16*1024);
1175 	deprint(2, "%s: dev ref %ld\n", argv0, dev->ref);
1176 	usbfsadd(&e->fs);
1177 	return 0;
1178 }
1179