xref: /plan9/sys/src/cmd/usb/ether/ether.c (revision 14093dc2f1c686bec1bc44cefce44368c26be35a)
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 
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[128];
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);
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);
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]");
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 	free(e);
912 
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 			break;
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