]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/nusb/ether/ether.c
merge
[plan9front.git] / sys / src / cmd / nusb / ether / ether.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4
5 #include "usb.h"
6 #include "dat.h"
7
8 #include <fcall.h>
9 #include <9p.h>
10 #include <ip.h>
11
12 typedef struct Tab Tab;
13 typedef struct Dq Dq;
14 typedef struct Conn Conn;
15 typedef struct Stats Stats;
16
17 enum
18 {
19         Qroot,
20         Qiface,
21         Qclone,
22         Qstats,
23         Qaddr,
24         Qndir,
25         Qctl,
26         Qdata,
27         Qtype,
28         Qmax,
29 };
30
31 struct Tab
32 {
33         char *name;
34         ulong mode;
35 };
36
37 Tab tab[] =
38 {
39         "/",            DMDIR|0555,
40         "etherU",       DMDIR|0555,     /* calling it *ether* makes snoopy(8) happy */
41         "clone",        0666,
42         "stats",        0666,
43         "addr", 0444,
44         "%ud",  DMDIR|0555,
45         "ctl",          0666,
46         "data", 0666,
47         "type", 0444,
48 };
49
50 struct Dq
51 {
52         QLock;
53
54         Dq              *next;
55         Req             *r;
56         Req             **rt;
57         Block           *q;
58         Block           **qt;
59
60         int             size;
61
62         int             nb;
63 };
64
65 struct Conn
66 {
67         QLock;
68
69         int             used;
70         int             type;
71         int             prom;
72         Dq              *dq;
73 };
74
75 struct Stats
76 {
77         int             in;
78         int             out;
79 };
80
81 Stats stats;
82 Conn conn[32];
83 int nconn = 0;
84
85 Dev *epin;
86 Dev *epout;
87
88 ulong time0;
89 static char *uname;
90
91 #define PATH(type, n)           ((type)|((n)<<8))
92 #define TYPE(path)                      (((uint)(path) & 0x000000FF)>>0)
93 #define NUM(path)                       (((uint)(path) & 0xFFFFFF00)>>8)
94 #define NUMCONN(c)              (((uintptr)(c)-(uintptr)&conn[0])/sizeof(conn[0]))
95
96 static void
97 fillstat(Dir *d, uvlong path)
98 {
99         Tab *t;
100
101         memset(d, 0, sizeof(*d));
102         d->uid = estrdup9p(uname);
103         d->gid = estrdup9p(uname);
104         d->qid.path = path;
105         d->atime = d->mtime = time0;
106         t = &tab[TYPE(path)];
107         d->name = smprint(t->name, NUM(path));
108         d->qid.type = t->mode>>24;
109         d->mode = t->mode;
110 }
111
112 static void
113 fsattach(Req *r)
114 {
115         if(r->ifcall.aname && r->ifcall.aname[0]){
116                 respond(r, "invalid attach specifier");
117                 return;
118         }
119         if(uname == nil)
120                 uname = estrdup9p(r->ifcall.uname);
121         r->fid->qid.path = PATH(Qroot, 0);
122         r->fid->qid.type = QTDIR;
123         r->fid->qid.vers = 0;
124         r->ofcall.qid = r->fid->qid;
125         respond(r, nil);
126 }
127
128 static void
129 fsstat(Req *r)
130 {
131         fillstat(&r->d, r->fid->qid.path);
132         respond(r, nil);
133 }
134
135 static int
136 rootgen(int i, Dir *d, void*)
137 {
138         i += Qroot+1;
139         if(i == Qiface){
140                 fillstat(d, i);
141                 return 0;
142         }
143         return -1;
144 }
145
146 static int
147 ifacegen(int i, Dir *d, void*)
148 {
149         i += Qiface+1;
150         if(i < Qndir){
151                 fillstat(d, i);
152                 return 0;
153         }
154         i -= Qndir;
155         if(i < nconn){
156                 fillstat(d, PATH(Qndir, i));
157                 return 0;
158         }
159         return -1;
160 }
161
162 static int
163 ndirgen(int i, Dir *d, void *aux)
164 {
165         i += Qndir+1;
166         if(i < Qmax){
167                 fillstat(d, PATH(i, NUMCONN(aux)));
168                 return 0;
169         }
170         return -1;
171 }
172
173 static char*
174 fswalk1(Fid *fid, char *name, Qid *qid)
175 {
176         int i, n;
177         char buf[32];
178         ulong path;
179
180         path = fid->qid.path;
181         if(!(fid->qid.type&QTDIR))
182                 return "walk in non-directory";
183
184         if(strcmp(name, "..") == 0){
185                 switch(TYPE(path)){
186                 case Qroot:
187                         return nil;
188                 case Qiface:
189                         qid->path = PATH(Qroot, 0);
190                         qid->type = tab[Qroot].mode>>24;
191                         return nil;
192                 case Qndir:
193                         qid->path = PATH(Qiface, 0);
194                         qid->type = tab[Qiface].mode>>24;
195                         return nil;
196                 default:
197                         return "bug in fswalk1";
198                 }
199         }
200
201         for(i = TYPE(path)+1; i<nelem(tab); i++){
202                 if(i==Qndir){
203                         n = atoi(name);
204                         snprint(buf, sizeof buf, "%d", n);
205                         if(n < nconn && strcmp(buf, name) == 0){
206                                 qid->path = PATH(i, n);
207                                 qid->type = tab[i].mode>>24;
208                                 return nil;
209                         }
210                         break;
211                 }
212                 if(strcmp(name, tab[i].name) == 0){
213                         qid->path = PATH(i, NUM(path));
214                         qid->type = tab[i].mode>>24;
215                         return nil;
216                 }
217                 if(tab[i].mode&DMDIR)
218                         break;
219         }
220         return "directory entry not found";
221 }
222
223 static void
224 matchrq(Dq *d)
225 {
226         Req *r;
227         Block *b;
228
229         while(r = d->r){
230                 int n;
231
232                 if((b = d->q) == nil)
233                         break;
234
235                 d->size -= BLEN(b);
236                 if((d->q = b->next) == nil)
237                         d->qt = &d->q;
238                 if((d->r = (Req*)r->aux) == nil)
239                         d->rt = &d->r;
240
241                 n = r->ifcall.count;
242                 if(n > BLEN(b))
243                         n = BLEN(b);
244                 memmove(r->ofcall.data, b->rp, n);
245                 r->ofcall.count = n;
246                 freeb(b);
247
248                 respond(r, nil);
249         }
250 }
251
252 static void
253 readconndata(Req *r)
254 {
255         Dq *d;
256
257         d = r->fid->aux;
258         qlock(d);
259         if(d->q==nil && d->nb){
260                 qunlock(d);
261                 r->ofcall.count = 0;
262                 respond(r, nil);
263                 return;
264         }
265         r->aux = nil;
266         *d->rt = r;
267         d->rt = (Req**)&r->aux;
268         matchrq(d);
269         qunlock(d);
270 }
271
272 static void
273 writeconndata(Req *r)
274 {
275         Dq *d;
276         void *p;
277         int n;
278         Block *b;
279
280         d = r->fid->aux;
281         p = r->ifcall.data;
282         n = r->ifcall.count;
283         if((n == 11) && memcmp(p, "nonblocking", n)==0){
284                 d->nb = 1;
285                 goto out;
286         }
287
288         /* minimum frame length for rtl8150 */
289         if(n < 60)
290                 n = 60;
291
292         /* slack space for header and trailers */
293         n += 2*16;
294
295         b = allocb(n);
296
297         /* header space */
298         b->wp += 16;
299         b->rp = b->wp;
300
301         /* copy in the ethernet packet */
302         memmove(b->wp, p, r->ifcall.count);
303         b->wp += r->ifcall.count;
304
305         etheriq(b, 0);
306
307 out:
308         r->ofcall.count = r->ifcall.count;
309         respond(r, nil);
310 }
311
312 static char*
313 mac2str(uchar *m)
314 {
315         int i;
316         char *t = "0123456789abcdef";
317         static char buf[13];
318         buf[13] = 0;
319         for(i=0; i<6; i++){
320                 buf[i*2] = t[m[i]>>4];
321                 buf[i*2+1] = t[m[i]&0xF];
322         }
323         return buf;
324 }
325
326 static void
327 fsread(Req *r)
328 {
329         char buf[200];
330         char e[ERRMAX];
331         ulong path;
332
333         path = r->fid->qid.path;
334
335         switch(TYPE(path)){
336         default:
337                 snprint(e, sizeof e, "bug in fsread path=%lux", path);
338                 respond(r, e);
339                 break;
340
341         case Qroot:
342                 dirread9p(r, rootgen, nil);
343                 respond(r, nil);
344                 break;
345
346         case Qiface:
347                 dirread9p(r, ifacegen, nil);
348                 respond(r, nil);
349                 break;
350
351         case Qstats:
352                 snprint(buf, sizeof(buf),
353                         "in: %d\n"
354                         "out: %d\n"
355                         "mbps: %d\n"
356                         "addr: %E\n",
357                         stats.in, stats.out, 10, macaddr);
358                 readstr(r, buf);
359                 respond(r, nil);
360                 break;
361
362         case Qaddr:
363                 snprint(buf, sizeof(buf), "%E", macaddr);
364                 readstr(r, buf);
365                 respond(r, nil);
366                 break;
367
368         case Qndir:
369                 dirread9p(r, ndirgen, &conn[NUM(path)]);
370                 respond(r, nil);
371                 break;
372
373         case Qctl:
374                 snprint(buf, sizeof(buf), "%11d ", NUM(path));
375                 readstr(r, buf);
376                 respond(r, nil);
377                 break;
378
379         case Qtype:
380                 snprint(buf, sizeof(buf), "%11d ", conn[NUM(path)].type);
381                 readstr(r, buf);
382                 respond(r, nil);
383                 break;
384
385         case Qdata:
386                 readconndata(r);
387                 break;
388         }
389 }
390
391 static void
392 fswrite(Req *r)
393 {
394         char e[ERRMAX];
395         ulong path;
396         char *p;
397         int n;
398
399         path = r->fid->qid.path;
400         switch(TYPE(path)){
401         case Qctl:
402                 n = r->ifcall.count;
403                 p = (char*)r->ifcall.data;
404                 if((n == 11) && memcmp(p, "promiscuous", 11)==0)
405                         conn[NUM(path)].prom = 1;
406                 if((n > 8) && memcmp(p, "connect ", 8)==0){
407                         char x[12];
408
409                         if(n - 8 >= sizeof(x)){
410                                 respond(r, "invalid control msg");
411                                 return;
412                         }
413
414                         p += 8;
415                         memcpy(x, p, n-8);
416                         x[n-8] = 0;
417
418                         conn[NUM(path)].type = atoi(p);
419                 }
420                 r->ofcall.count = n;
421                 respond(r, nil);
422                 break;
423         case Qdata:
424                 writeconndata(r);
425                 break;
426         default:
427                 snprint(e, sizeof e, "bug in fswrite path=%lux", path);
428                 respond(r, e);
429         }
430 }
431
432 static void
433 fsopen(Req *r)
434 {
435         static int need[4] = { 4, 2, 6, 1 };
436         ulong path;
437         int i, n;
438         Tab *t;
439         Dq *d;
440         Conn *c;
441
442         /*
443          * lib9p already handles the blatantly obvious.
444          * we just have to enforce the permissions we have set.
445          */
446         path = r->fid->qid.path;
447         t = &tab[TYPE(path)];
448         n = need[r->ifcall.mode&3];
449         if((n&t->mode) != n){
450                 respond(r, "permission denied");
451                 return;
452         }
453
454         d = nil;
455         r->fid->aux = nil;
456
457         switch(TYPE(path)){
458         case Qclone:
459                 for(i=0; i<nelem(conn); i++){
460                         if(conn[i].used)
461                                 continue;
462                         if(i >= nconn)
463                                 nconn = i+1;
464                         path = PATH(Qctl, i);
465                         goto CaseConn;
466                 }
467                 respond(r, "out of connections");
468                 return;
469         case Qdata:
470                 d = emalloc9p(sizeof(*d));
471                 memset(d, 0, sizeof(*d));
472                 d->qt = &d->q;
473                 d->rt = &d->r;
474                 r->fid->aux = d;
475         case Qndir:
476         case Qctl:
477         case Qtype:
478         CaseConn:
479                 c = &conn[NUM(path)];
480                 qlock(c);
481                 if(c->used++ == 0){
482                         c->type = 0;
483                         c->prom = 0;
484                 }
485                 if(d != nil){
486                         d->next = c->dq;
487                         c->dq = d;
488                 }
489                 qunlock(c);
490                 break;
491         }
492
493         r->fid->qid.path = path;
494         r->ofcall.qid.path = path;
495         respond(r, nil);
496 }
497
498 static void
499 fsflush(Req *r)
500 {
501         Req *o, **p;
502         Fid *f;
503         Dq *d;
504
505         o = r->oldreq;
506         f = o->fid;
507         if(TYPE(f->qid.path) == Qdata){
508                 d = f->aux;
509                 qlock(d);
510                 for(p=&d->r; *p; p=(Req**)&((*p)->aux)){
511                         if(*p == o){
512                                 if((*p = (Req*)o->aux) == nil)
513                                         d->rt = p;
514                                 r->oldreq = nil;
515                                 respond(o, "interrupted");
516                                 break;
517                         }
518                 }
519                 qunlock(d);
520         }
521         respond(r, nil);
522 }
523
524
525 static void
526 fsdestroyfid(Fid *fid)
527 {
528         Conn *c;
529         Dq **x, *d;
530         Block *b;
531
532         if(TYPE(fid->qid.path) >= Qndir){
533                 c = &conn[NUM(fid->qid.path)];
534                 qlock(c);
535                 if(d = fid->aux){
536                         fid->aux = nil;
537                         for(x=&c->dq; *x; x=&((*x)->next)){
538                                 if(*x == d){
539                                         *x = d->next;
540                                         break;
541                                 }
542                         }
543                         while(b = d->q){
544                                 d->q = b->next;
545                                 freeb(b);
546                         }
547                         free(d);
548                 }
549                 if(TYPE(fid->qid.path) == Qctl)
550                         c->prom = 0;
551                 c->used--;
552                 qunlock(c);
553         }
554 }
555
556 static void
557 setalt(Dev *d, int ifcid, int altid)
558 {
559         if(usbcmd(d, Rh2d|Rstd|Riface, Rsetiface, altid, ifcid, nil, 0) < 0)
560                 dprint(2, "%s: setalt ifc %d alt %d: %r\n", argv0, ifcid, altid);
561 }
562
563 static int
564 ifaceinit(Dev *d, Iface *ifc, int *ei, int *eo)
565 {
566         int i, epin, epout;
567         Ep *ep;
568
569         if(ifc == nil)
570                 return -1;
571
572         epin = epout = -1;
573         for(i = 0; (epin < 0 || epout < 0) && i < nelem(ifc->ep); i++)
574                 if((ep = ifc->ep[i]) != nil && ep->type == Ebulk){
575                         if(ep->dir == Eboth || ep->dir == Ein)
576                                 if(epin == -1)
577                                         epin =  ep->id;
578                         if(ep->dir == Eboth || ep->dir == Eout)
579                                 if(epout == -1)
580                                         epout = ep->id;
581                 }
582         if(epin == -1 || epout == -1)
583                 return -1;
584
585         for(i = 0; i < nelem(ifc->altc); i++)
586                 if(ifc->altc[i] != nil)
587                         setalt(d, ifc->id, i);
588
589         *ei = epin;
590         *eo = epout;
591         return 0;
592 }
593
594 int
595 findendpoints(Dev *d, int *ei, int *eo)
596 {
597         int i, j, ctlid, datid;
598         Iface *ctlif, *datif;
599         Usbdev *ud;
600         Desc *desc;
601         Conf *c;
602
603         ud = d->usb;
604         *ei = *eo = -1;
605
606         /* look for union descriptor with ethernet ctrl interface */
607         for(i = 0; i < nelem(ud->ddesc); i++){
608                 if((desc = ud->ddesc[i]) == nil)
609                         continue;
610                 if(desc->data.bLength < 5 || desc->data.bbytes[0] != Cdcunion)
611                         continue;
612
613                 ctlid = desc->data.bbytes[1];
614                 datid = desc->data.bbytes[2];
615
616                 if((c = desc->conf) == nil)
617                         continue;
618
619                 ctlif = datif = nil;
620                 for(j = 0; j < nelem(c->iface); j++){
621                         if(c->iface[j] == nil)
622                                 continue;
623                         if(c->iface[j]->id == ctlid)
624                                 ctlif = c->iface[j];
625                         if(c->iface[j]->id == datid)
626                                 datif = c->iface[j];
627
628                         if(datif != nil && ctlif != nil){
629                                 if(Subclass(ctlif->csp) == Scether)
630                                         if(ifaceinit(d, datif, ei, eo) != -1)
631                                                 return 0;
632                                 break;
633                         }
634                 }               
635         }
636
637         /* try any other one that seems to be ok */
638         for(i = 0; i < nelem(ud->conf); i++)
639                 if((c = ud->conf[i]) != nil)
640                         for(j = 0; j < nelem(c->iface); j++)
641                                 if(ifaceinit(d,c->iface[j],ei,eo) != -1)
642                                         return 0;
643
644         return -1;
645 }
646
647 static int
648 inote(void *, char *msg)
649 {
650         if(strstr(msg, "interrupt"))
651                 return 1;
652         return 0;
653 }
654
655 void
656 etheriq(Block *b, int wire)
657 {
658         int i, t;
659         Block *q;
660         Conn *c;
661         Dq *d;
662         Ehdr *h;
663
664         if(BLEN(b) < Ehdrsz){
665                 freeb(b);
666                 return;
667         }
668
669         h = (Ehdr*)b->rp;
670         t = (h->type[0]<<8)|h->type[1];
671
672         for(i=0; i<nconn; i++){
673                 c = &conn[i];
674                 qlock(c);
675                 if(!c->used)
676                         goto next;
677                 if(c->type > 0)
678                         if(c->type != t)
679                                 goto next;
680                 if(!c->prom && !(h->d[0]&1))
681                         if(memcmp(h->d, macaddr, sizeof(macaddr)))
682                                 goto next;
683                 for(d=c->dq; d; d=d->next){
684                         if(d->size > 100000)
685                                 continue;
686                         if(c->type == -2) {
687                                 q = copyblock(b, 64);
688                         } else if(wire && b->ref == 1) {
689                                 incref(b);
690                                 q = b;
691                         } else {
692                                 q = copyblock(b, BLEN(b));
693                         }
694                         qlock(d);
695                         q->next = nil;
696                         *d->qt = q;
697                         d->qt = &q->next;
698                         d->size += BLEN(q);
699                         matchrq(d);
700                         qunlock(d);
701                 }
702 next:
703                 qunlock(c);
704         }
705         if(wire) {
706                 freeb(b);
707                 stats.in++;
708         } else {
709                 /* transmit frees buffer */
710                 (*eptransmit)(epout, b);
711                 stats.out++;
712         }
713 }
714
715 static void
716 usbreadproc(void *)
717 {
718         char err[ERRMAX];
719         int nerr;
720
721         atnotify(inote, 1);
722
723         threadsetname("usbreadproc");
724
725         nerr = 0;
726         for(;;){
727                 /* receive allocates buffer and calls etheriq(b, 1); */
728                 if((*epreceive)(epin) < 0){
729                         rerrstr(err, sizeof(err));
730                         if(strstr(err, "interrupted") || strstr(err, "timed out"))
731                                 continue;
732                         fprint(2, "usbreadproc: %s\n", err);
733                         if(++nerr < 3)
734                                 continue;
735                         threadexitsall(err);
736                 }
737                 nerr = 0;
738         }
739 }
740
741 Srv fs = 
742 {
743 .attach=                fsattach,
744 .destroyfid=    fsdestroyfid,
745 .walk1=         fswalk1,
746 .open=          fsopen,
747 .read=          fsread,
748 .write=         fswrite,
749 .stat=          fsstat,
750 .flush=         fsflush,
751 };
752
753 static void
754 usage(void)
755 {
756         fprint(2, "usage: %s [-dD] [-t type] [-a addr] devid\n", argv0);
757         exits("usage");
758 }
759
760 extern int aueinit(Dev *);
761 extern int a88178init(Dev *);
762 extern int a88772init(Dev *);
763 extern int smscinit(Dev *);
764 extern int cdcinit(Dev *);
765 extern int urlinit(Dev *);
766 extern int rndisinit(Dev *);
767
768 static struct {
769         char *name;
770         int (*init)(Dev*);
771 } ethertype[] = {
772         "cdc",          cdcinit,
773         "smsc",         smscinit,
774         "a88178",       a88178init,
775         "a88772",       a88772init,
776         "aue",          aueinit,
777         "url",          urlinit,
778         "rndis",        rndisinit,
779 };
780
781 void
782 threadmain(int argc, char **argv)
783 {
784         char s[64], *t;
785         int et, ei, eo;
786         Dev *d;
787
788         fmtinstall('E', eipfmt);
789
790         et = 0; /* CDC */
791         ARGBEGIN {
792         case 'd':
793                 debug = 1;
794                 break;
795         case 'D':
796                 chatty9p++;
797                 break;
798         case 'a':
799                 setmac = 1;
800                 parseether(macaddr, EARGF(usage()));
801                 break;
802         case 't':
803                 t = EARGF(usage());
804                 for(et=0; et<nelem(ethertype); et++)
805                         if(strcmp(t, ethertype[et].name) == 0)
806                                 break;
807                 if(et == nelem(ethertype)){
808                         fprint(2, "unsupported ethertype -t %s, supported types are: ", t);
809                         for(et=0; et<nelem(ethertype); et++)
810                                 fprint(2, "%s ", ethertype[et].name);
811                         fprint(2, "\n");
812                         exits("usage");
813                 }
814                 break;
815         default:
816                 usage();
817         } ARGEND;
818
819         if(argc != 1)
820                 usage();
821
822         if((d = getdev(atoi(*argv))) == nil)
823                 sysfatal("getdev: %r");
824         if(findendpoints(d, &ei, &eo) < 0)
825                 sysfatal("no endpoints found");
826
827         werrstr("");
828         if((*ethertype[et].init)(d) < 0)
829                 sysfatal("%s init failed: %r", ethertype[et].name);
830         if(epreceive == nil || eptransmit == nil)
831                 sysfatal("bug in init");
832
833         if((epin = openep(d, ei)) == nil)
834                 sysfatal("openep: %r");
835         if(ei == eo){
836                 incref(epin);
837                 epout = epin;
838                 opendevdata(epin, ORDWR);
839         } else {
840                 if((epout = openep(d, eo)) == nil)
841                         sysfatal("openep: %r");
842                 opendevdata(epin, OREAD);
843                 opendevdata(epout, OWRITE);
844         }
845
846         proccreate(usbreadproc, nil, 8*1024);
847
848         atnotify(inote, 1);
849         time0 = time(0);
850         tab[Qiface].name = smprint("etherU%d", d->id);
851         snprint(s, sizeof(s), "%d.ether", d->id);
852         closedev(d);
853         threadpostsharesrv(&fs, nil, "usbnet", s);
854
855         threadexits(0);
856 }
857
858 Block*
859 allocb(int size)
860 {
861         Block *b;
862
863         b = emalloc9p(sizeof(*b) + size);
864         b->lim = b->base + size;
865         b->rp = b->base;
866         b->wp = b->base;
867         b->next = nil;
868         b->ref = 1;
869         return b;
870 }
871
872 void
873 freeb(Block *b)
874 {
875         if(decref(b) == 0)
876                 free(b);
877 }
878
879 Block*
880 copyblock(Block *b, int count)
881 {
882         Block *nb;
883
884         if(count > BLEN(b))
885                 count = BLEN(b);
886         nb = allocb(count);
887         memmove(nb->wp, b->rp, count);
888         nb->wp += count;
889         return nb;
890 }