#include <u.h>#include <libc.h>#include <thread.h>#include <bio.h>#include <auth.h>#include <fcall.h>#include <9p.h> #include "usb.h" typedef struct Tab Tab;typedef struct Qbuf Qbuf;typedef struct Dq Dq;typedef struct Conn Conn;typedef struct Ehdr Ehdr;typedef struct Stats Stats; enum{ SC_ACM = 2, SC_ETHER = 6, FUNCTION = 0x24, FN_HEADER = 0, FN_UNION = 6, FN_ETHER = 15,}; enum{ Qroot, Qiface, Qclone, Qstats, Qaddr, Qndir, Qctl, Qdata, Qtype, Qmax,}; struct Tab{ char *name; ulong mode;}; Tab tab[] ={ "/", DMDIR|0555, "etherU", DMDIR|0555, /* calling it *ether* makes snoopy(8) happy */ "clone", 0666, "stats", 0666, "addr", 0444, "%ud", DMDIR|0555, "ctl", 0666, "data", 0666, "type", 0444,}; struct Qbuf{ Qbuf *next; int ndata; uchar data[];}; struct Dq{ QLock l; Dq *next; Req *r; Req **rt; Qbuf *q; Qbuf **qt; int nb;}; struct Conn{ QLock l; int used; int type; int prom; Dq *dq;}; struct Ehdr{ uchar d[6]; uchar s[6]; uchar type[2];}; struct Stats{ int in; int out;}; Conn conn[32];int nconn = 0; int debug;ulong time0;int usbfdin = -1;int usbfdout = -1; Stats stats; uchar macaddr[6];int iunion[8][2];int niunion;int maxpacket = 64; char *uname; #define PATH(type, n) ((type)|((n)<<8))#define TYPE(path) (((uint)(path) & 0x000000FF)>>0)#define NUM(path) (((uint)(path) & 0xFFFFFF00)>>8)#define NUMCONN(c) (((long)(c)-(long)&conn[0])/sizeof(conn[0])) static intreceivepacket(void *buf, int len); static voidfillstat(Dir *d, uvlong path){ Tab *t; memset(d, 0, sizeof(*d)); d->uid = estrdup9p(uname); d->gid = estrdup9p(uname); d->qid.path = path; d->atime = d->mtime = time0; t = &tab[TYPE(path)]; d->name = smprint(t->name, NUM(path)); d->qid.type = t->mode>>24; d->mode = t->mode;} static voidfsattach(Req *r){ if(r->ifcall.aname && r->ifcall.aname[0]){ respond(r, "invalid attach specifier"); return; } if(uname == nil) uname = estrdup9p(r->ifcall.uname); r->fid->qid.path = PATH(Qroot, 0); r->fid->qid.type = QTDIR; r->fid->qid.vers = 0; r->ofcall.qid = r->fid->qid; respond(r, nil);} static voidfsstat(Req *r){ fillstat(&r->d, r->fid->qid.path); respond(r, nil);} static introotgen(int i, Dir *d, void*){ i += Qroot+1; if(i == Qiface){ fillstat(d, i); return 0; } return -1;} static intifacegen(int i, Dir *d, void*){ i += Qiface+1; if(i < Qndir){ fillstat(d, i); return 0; } i -= Qndir; if(i < nconn){ fillstat(d, PATH(Qndir, i)); return 0; } return -1;} static intndirgen(int i, Dir *d, void *aux){ i += Qndir+1; if(i < Qmax){ fillstat(d, PATH(i, NUMCONN(aux))); return 0; } return -1;} static char*fswalk1(Fid *fid, char *name, Qid *qid){ int i, n; char buf[32]; ulong path; path = fid->qid.path; if(!(fid->qid.type&QTDIR)) return "walk in non-directory"; if(strcmp(name, "..") == 0){ switch(TYPE(path)){ case Qroot: return nil; case Qiface: qid->path = PATH(Qroot, 0); qid->type = tab[Qroot].mode>>24; return nil; case Qndir: qid->path = PATH(Qiface, 0); qid->type = tab[Qiface].mode>>24; return nil; default: return "bug in fswalk1"; } } for(i = TYPE(path)+1; i<nelem(tab); i++){ if(i==Qndir){ n = atoi(name); snprint(buf, sizeof buf, "%d", n); if(n < nconn && strcmp(buf, name) == 0){ qid->path = PATH(i, n); qid->type = tab[i].mode>>24; return nil; } break; } if(strcmp(name, tab[i].name) == 0){ qid->path = PATH(i, NUM(path)); qid->type = tab[i].mode>>24; return nil; } if(tab[i].mode&DMDIR) break; } return "directory entry not found";} static voidmatchrq(Dq *d){ Req *r; Qbuf *b; while(r = d->r){ int n; if((b = d->q) == nil) break; if((d->q = b->next) == nil) d->qt = &d->q; if((d->r = (Req*)r->aux) == nil) d->rt = &d->r; n = r->ifcall.count; if(n > b->ndata) n = b->ndata; memmove(r->ofcall.data, b->data, n); free(b); r->ofcall.count = n; respond(r, nil); }} static voidreadconndata(Req *r){ Dq *d; d = r->fid->aux; qlock(&d->l); if(d->q==nil && d->nb){ qunlock(&d->l); r->ofcall.count = 0; respond(r, nil); return; } // enqueue request r->aux = nil; *d->rt = r; d->rt = (Req**)&r->aux; matchrq(d); qunlock(&d->l);} static voidwriteconndata(Req *r){ char e[ERRMAX]; Dq *d; void *p; int n; d = r->fid->aux; p = r->ifcall.data; n = r->ifcall.count; if((n == 11) && memcmp(p, "nonblocking", n)==0){ d->nb = 1; goto out; } n = write(usbfdout, p, n); if(n < 0){ rerrstr(e, sizeof(e)); respond(r, e); return; } /* * this may not work with all CDC devices. the * linux driver sends one more random byte * instead of a zero byte transaction. maybe we * should do the same? */ if(n % maxpacket == 0) write(usbfdout, "", 0); if(receivepacket(p, n) == 0) stats.out++;out: r->ofcall.count = n; respond(r, nil);} static char*mac2str(uchar *m){ int i; char *t = "0123456789abcdef"; static char buf[13]; buf[13] = 0; for(i=0; i<6; i++){ buf[i*2] = t[m[i]>>4]; buf[i*2+1] = t[m[i]&0xF]; } return buf;} static intstr2mac(uchar *m, char *s){ int i; if(strlen(s) != 12) return -1; for(i=0; i<12; i++){ uchar v; if(s[i] >= 'A' && s[i] <= 'F'){ v = 10 + s[i] - 'A'; } else if(s[i] >= 'a' && s[i] <= 'f'){ v = 10 + s[i] - 'a'; } else if(s[i] >= '0' && s[i] <= '9'){ v = s[i] - '0'; } else { v = 0; } if(i&1){ m[i/2] |= v; } else { m[i/2] = v<<4; } } return 0;} static voidfsread(Req *r){ char buf[200]; char e[ERRMAX]; ulong path; path = r->fid->qid.path; switch(TYPE(path)){ default: snprint(e, sizeof e, "bug in fsread path=%lux", path); respond(r, e); break; case Qroot: dirread9p(r, rootgen, nil); respond(r, nil); break; case Qiface: dirread9p(r, ifacegen, nil); respond(r, nil); break; case Qstats: snprint(buf, sizeof(buf), "in: %d\n" "out: %d\n" "mbps: %d\n" "addr: %s\n", stats.in, stats.out, 10, mac2str(macaddr)); readstr(r, buf); respond(r, nil); break; case Qaddr: readstr(r, mac2str(macaddr)); respond(r, nil); break; case Qndir: dirread9p(r, ndirgen, &conn[NUM(path)]); respond(r, nil); break; case Qctl: snprint(buf, sizeof(buf), "%11d ", NUM(path)); readstr(r, buf); respond(r, nil); break; case Qtype: snprint(buf, sizeof(buf), "%11d ", conn[NUM(path)].type); readstr(r, buf); respond(r, nil); break; case Qdata: readconndata(r); break; }} static voidfswrite(Req *r){ char e[ERRMAX]; ulong path; char *p; int n; path = r->fid->qid.path; switch(TYPE(path)){ case Qctl: n = r->ifcall.count; p = (char*)r->ifcall.data; if((n == 11) && memcmp(p, "promiscuous", 11)==0) conn[NUM(path)].prom = 1; if((n > 8) && memcmp(p, "connect ", 8)==0){ char x[12]; if(n - 8 >= sizeof(x)){ respond(r, "invalid control msg"); return; } p += 8; memcpy(x, p, n-8); x[n-8] = 0; conn[NUM(path)].type = atoi(p); } r->ofcall.count = n; respond(r, nil); break; case Qdata: writeconndata(r); break; default: snprint(e, sizeof e, "bug in fswrite path=%lux", path); respond(r, e); }} static voidfsopen(Req *r){ static int need[4] = { 4, 2, 6, 1 }; ulong path; int i, n; Tab *t; Dq *d; Conn *c; /*Lines 1–500 of 993. Load more
#include <u.h> #include <libc.h> #include <thread.h> #include <bio.h> #include <auth.h> #include <fcall.h> #include <9p.h> #include "usb.h" typedef struct Tab Tab; typedef struct Qbuf Qbuf; typedef struct Dq Dq; typedef struct Conn Conn; typedef struct Ehdr Ehdr; typedef struct Stats Stats; enum { SC_ACM = 2, SC_ETHER = 6, FUNCTION = 0x24, FN_HEADER = 0, FN_UNION = 6, FN_ETHER = 15, }; enum { Qroot, Qiface, Qclone, Qstats, Qaddr, Qndir, Qctl, Qdata, Qtype, Qmax, }; struct Tab { char *name; ulong mode; }; Tab tab[] = { "/", DMDIR|0555, "etherU", DMDIR|0555, /* calling it *ether* makes snoopy(8) happy */ "clone", 0666, "stats", 0666, "addr", 0444, "%ud", DMDIR|0555, "ctl", 0666, "data", 0666, "type", 0444, }; struct Qbuf { Qbuf *next; int ndata; uchar data[]; }; struct Dq { QLock l; Dq *next; Req *r; Req **rt; Qbuf *q; Qbuf **qt; int nb; }; struct Conn { QLock l; int used; int type; int prom; Dq *dq; }; struct Ehdr { uchar d[6]; uchar s[6]; uchar type[2]; }; struct Stats { int in; int out; }; Conn conn[32]; int nconn = 0; int debug; ulong time0; int usbfdin = -1; int usbfdout = -1; Stats stats; uchar macaddr[6]; int iunion[8][2]; int niunion; int maxpacket = 64; char *uname; #define PATH(type, n) ((type)|((n)<<8)) #define TYPE(path) (((uint)(path) & 0x000000FF)>>0) #define NUM(path) (((uint)(path) & 0xFFFFFF00)>>8) #define NUMCONN(c) (((long)(c)-(long)&conn[0])/sizeof(conn[0])) static int receivepacket(void *buf, int len); static void fillstat(Dir *d, uvlong path) { Tab *t; memset(d, 0, sizeof(*d)); d->uid = estrdup9p(uname); d->gid = estrdup9p(uname); d->qid.path = path; d->atime = d->mtime = time0; t = &tab[TYPE(path)]; d->name = smprint(t->name, NUM(path)); d->qid.type = t->mode>>24; d->mode = t->mode; } static void fsattach(Req *r) { if(r->ifcall.aname && r->ifcall.aname[0]){ respond(r, "invalid attach specifier"); return; } if(uname == nil) uname = estrdup9p(r->ifcall.uname); r->fid->qid.path = PATH(Qroot, 0); r->fid->qid.type = QTDIR; r->fid->qid.vers = 0; r->ofcall.qid = r->fid->qid; respond(r, nil); } static void fsstat(Req *r) { fillstat(&r->d, r->fid->qid.path); respond(r, nil); } static int rootgen(int i, Dir *d, void*) { i += Qroot+1; if(i == Qiface){ fillstat(d, i); return 0; } return -1; } static int ifacegen(int i, Dir *d, void*) { i += Qiface+1; if(i < Qndir){ fillstat(d, i); return 0; } i -= Qndir; if(i < nconn){ fillstat(d, PATH(Qndir, i)); return 0; } return -1; } static int ndirgen(int i, Dir *d, void *aux) { i += Qndir+1; if(i < Qmax){ fillstat(d, PATH(i, NUMCONN(aux))); return 0; } return -1; } static char* fswalk1(Fid *fid, char *name, Qid *qid) { int i, n; char buf[32]; ulong path; path = fid->qid.path; if(!(fid->qid.type&QTDIR)) return "walk in non-directory"; if(strcmp(name, "..") == 0){ switch(TYPE(path)){ case Qroot: return nil; case Qiface: qid->path = PATH(Qroot, 0); qid->type = tab[Qroot].mode>>24; return nil; case Qndir: qid->path = PATH(Qiface, 0); qid->type = tab[Qiface].mode>>24; return nil; default: return "bug in fswalk1"; } } for(i = TYPE(path)+1; i<nelem(tab); i++){ if(i==Qndir){ n = atoi(name); snprint(buf, sizeof buf, "%d", n); if(n < nconn && strcmp(buf, name) == 0){ qid->path = PATH(i, n); qid->type = tab[i].mode>>24; return nil; } break; } if(strcmp(name, tab[i].name) == 0){ qid->path = PATH(i, NUM(path)); qid->type = tab[i].mode>>24; return nil; } if(tab[i].mode&DMDIR) break; } return "directory entry not found"; } static void matchrq(Dq *d) { Req *r; Qbuf *b; while(r = d->r){ int n; if((b = d->q) == nil) break; if((d->q = b->next) == nil) d->qt = &d->q; if((d->r = (Req*)r->aux) == nil) d->rt = &d->r; n = r->ifcall.count; if(n > b->ndata) n = b->ndata; memmove(r->ofcall.data, b->data, n); free(b); r->ofcall.count = n; respond(r, nil); } } static void readconndata(Req *r) { Dq *d; d = r->fid->aux; qlock(&d->l); if(d->q==nil && d->nb){ qunlock(&d->l); r->ofcall.count = 0; respond(r, nil); return; } // enqueue request r->aux = nil; *d->rt = r; d->rt = (Req**)&r->aux; matchrq(d); qunlock(&d->l); } static void writeconndata(Req *r) { char e[ERRMAX]; Dq *d; void *p; int n; d = r->fid->aux; p = r->ifcall.data; n = r->ifcall.count; if((n == 11) && memcmp(p, "nonblocking", n)==0){ d->nb = 1; goto out; } n = write(usbfdout, p, n); if(n < 0){ rerrstr(e, sizeof(e)); respond(r, e); return; } /* * this may not work with all CDC devices. the * linux driver sends one more random byte * instead of a zero byte transaction. maybe we * should do the same? */ if(n % maxpacket == 0) write(usbfdout, "", 0); if(receivepacket(p, n) == 0) stats.out++; out: r->ofcall.count = n; respond(r, nil); } static char* mac2str(uchar *m) { int i; char *t = "0123456789abcdef"; static char buf[13]; buf[13] = 0; for(i=0; i<6; i++){ buf[i*2] = t[m[i]>>4]; buf[i*2+1] = t[m[i]&0xF]; } return buf; } static int str2mac(uchar *m, char *s) { int i; if(strlen(s) != 12) return -1; for(i=0; i<12; i++){ uchar v; if(s[i] >= 'A' && s[i] <= 'F'){ v = 10 + s[i] - 'A'; } else if(s[i] >= 'a' && s[i] <= 'f'){ v = 10 + s[i] - 'a'; } else if(s[i] >= '0' && s[i] <= '9'){ v = s[i] - '0'; } else { v = 0; } if(i&1){ m[i/2] |= v; } else { m[i/2] = v<<4; } } return 0; } static void fsread(Req *r) { char buf[200]; char e[ERRMAX]; ulong path; path = r->fid->qid.path; switch(TYPE(path)){ default: snprint(e, sizeof e, "bug in fsread path=%lux", path); respond(r, e); break; case Qroot: dirread9p(r, rootgen, nil); respond(r, nil); break; case Qiface: dirread9p(r, ifacegen, nil); respond(r, nil); break; case Qstats: snprint(buf, sizeof(buf), "in: %d\n" "out: %d\n" "mbps: %d\n" "addr: %s\n", stats.in, stats.out, 10, mac2str(macaddr)); readstr(r, buf); respond(r, nil); break; case Qaddr: readstr(r, mac2str(macaddr)); respond(r, nil); break; case Qndir: dirread9p(r, ndirgen, &conn[NUM(path)]); respond(r, nil); break; case Qctl: snprint(buf, sizeof(buf), "%11d ", NUM(path)); readstr(r, buf); respond(r, nil); break; case Qtype: snprint(buf, sizeof(buf), "%11d ", conn[NUM(path)].type); readstr(r, buf); respond(r, nil); break; case Qdata: readconndata(r); break; } } static void fswrite(Req *r) { char e[ERRMAX]; ulong path; char *p; int n; path = r->fid->qid.path; switch(TYPE(path)){ case Qctl: n = r->ifcall.count; p = (char*)r->ifcall.data; if((n == 11) && memcmp(p, "promiscuous", 11)==0) conn[NUM(path)].prom = 1; if((n > 8) && memcmp(p, "connect ", 8)==0){ char x[12]; if(n - 8 >= sizeof(x)){ respond(r, "invalid control msg"); return; } p += 8; memcpy(x, p, n-8); x[n-8] = 0; conn[NUM(path)].type = atoi(p); } r->ofcall.count = n; respond(r, nil); break; case Qdata: writeconndata(r); break; default: snprint(e, sizeof e, "bug in fswrite path=%lux", path); respond(r, e); } } static void fsopen(Req *r) { static int need[4] = { 4, 2, 6, 1 }; ulong path; int i, n; Tab *t; Dq *d; Conn *c; /*