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