1906943f9SDavid du Colombier /* 2906943f9SDavid du Colombier * usb/ether - usb ethernet adapter. 3906943f9SDavid du Colombier * BUG: This should use /dev/etherfile to 4906943f9SDavid du Colombier * use the kernel ether device code. 5906943f9SDavid du Colombier */ 6906943f9SDavid du Colombier #include <u.h> 7906943f9SDavid du Colombier #include <libc.h> 8906943f9SDavid du Colombier #include <fcall.h> 9906943f9SDavid du Colombier #include <thread.h> 10906943f9SDavid du Colombier #include "usb.h" 11906943f9SDavid du Colombier #include "usbfs.h" 12906943f9SDavid du Colombier #include "ether.h" 13906943f9SDavid du Colombier 14906943f9SDavid du Colombier typedef struct Dirtab Dirtab; 15906943f9SDavid du Colombier 16906943f9SDavid du Colombier enum 17906943f9SDavid du Colombier { 18906943f9SDavid du Colombier /* Qids. Maintain order (relative to dirtabs structs) */ 19906943f9SDavid du Colombier Qroot = 0, 20906943f9SDavid du Colombier Qclone, 21906943f9SDavid du Colombier Qaddr, 22906943f9SDavid du Colombier Qifstats, 23906943f9SDavid du Colombier Qstats, 24906943f9SDavid du Colombier Qndir, 25906943f9SDavid du Colombier Qndata, 26906943f9SDavid du Colombier Qnctl, 27906943f9SDavid du Colombier Qnifstats, 28906943f9SDavid du Colombier Qnstats, 29906943f9SDavid du Colombier Qntype, 30906943f9SDavid du Colombier Qmax, 31906943f9SDavid du Colombier }; 32906943f9SDavid du Colombier 33906943f9SDavid du Colombier struct Dirtab 34906943f9SDavid du Colombier { 35906943f9SDavid du Colombier char *name; 36906943f9SDavid du Colombier int qid; 37906943f9SDavid du Colombier int mode; 38906943f9SDavid du Colombier }; 39906943f9SDavid du Colombier 40906943f9SDavid du Colombier typedef int (*Resetf)(Ether*); 41906943f9SDavid du Colombier 42906943f9SDavid du Colombier /* 43906943f9SDavid du Colombier * Controllers by vid/vid. Used to locate 44906943f9SDavid du Colombier * specific adapters that do not implement cdc ethernet 45906943f9SDavid du Colombier * Keep null terminated. 46906943f9SDavid du Colombier */ 47906943f9SDavid du Colombier Cinfo cinfo[] = 48906943f9SDavid du Colombier { 49906943f9SDavid du Colombier /* Asix controllers. 50906943f9SDavid du Colombier * Only A88178 and A881772 are implemented. 51906943f9SDavid du Colombier * Others are easy to add by borrowing code 52906943f9SDavid du Colombier * from other systems. 53906943f9SDavid du Colombier */ 54906943f9SDavid du Colombier {0x077b, 0x2226, A8817x}, 55906943f9SDavid du Colombier {0x0b95, 0x1720, A8817x}, 56906943f9SDavid du Colombier {0x0557, 0x2009, A8817x}, 57906943f9SDavid du Colombier {0x0411, 0x003d, A8817x}, 58906943f9SDavid du Colombier {0x0411, 0x006e, A88178}, 59906943f9SDavid du Colombier {0x6189, 0x182d, A8817x}, 60906943f9SDavid du Colombier {0x07aa, 0x0017, A8817x}, 61906943f9SDavid du Colombier {0x1189, 0x0893, A8817x}, 62906943f9SDavid du Colombier {0x1631, 0x6200, A8817x}, 63906943f9SDavid du Colombier {0x04f1, 0x3008, A8817x}, 64906943f9SDavid du Colombier {0x0b95, 0x1780, A88178}, /* Geoff */ 65906943f9SDavid du Colombier {0x13b1, 0x0018, A88772}, 66906943f9SDavid du Colombier {0x1557, 0x7720, A88772}, 67906943f9SDavid du Colombier {0x07d1, 0x3c05, A88772}, 68906943f9SDavid du Colombier {0x2001, 0x3c05, A88772}, 69906943f9SDavid du Colombier {0x1737, 0x0039, A88178}, 70906943f9SDavid du Colombier {0x050d, 0x5055, A88178}, 71906943f9SDavid du Colombier {0x05ac, 0x1402, A88772}, /* Apple */ 72906943f9SDavid du Colombier {0x0b95, 0x772a, A88772}, 73906943f9SDavid du Colombier {0x14ea, 0xab11, A88178}, 74906943f9SDavid du Colombier {0x0db0, 0xa877, A88772}, 75906943f9SDavid du Colombier {0, 0, 0}, 76906943f9SDavid du Colombier }; 77906943f9SDavid du Colombier 78906943f9SDavid du Colombier /* 79906943f9SDavid du Colombier * Each etherU%d is the root of our file system, 80906943f9SDavid du Colombier * which is added to the usb root directory. We only 81906943f9SDavid du Colombier * have to concern ourselfs with each /etherU%d subtree. 82906943f9SDavid du Colombier * 83906943f9SDavid du Colombier * NB: Maintain order in dirtabs, relative to the Qids enum. 84906943f9SDavid du Colombier */ 85906943f9SDavid du Colombier 86906943f9SDavid du Colombier static Dirtab rootdirtab[] = 87906943f9SDavid du Colombier { 88906943f9SDavid du Colombier "/", Qroot, DMDIR|0555, /* etherU%d */ 89906943f9SDavid du Colombier "clone", Qclone, 0666, 90906943f9SDavid du Colombier "addr", Qaddr, 0444, 91906943f9SDavid du Colombier "ifstats", Qifstats, 0444, 92906943f9SDavid du Colombier "stats", Qstats, 0444, 93906943f9SDavid du Colombier /* one dir per connection here */ 94906943f9SDavid du Colombier nil, 0, 0, 95906943f9SDavid du Colombier }; 96906943f9SDavid du Colombier 97906943f9SDavid du Colombier static Dirtab conndirtab[] = 98906943f9SDavid du Colombier { 99906943f9SDavid du Colombier "%d", Qndir, DMDIR|0555, 100906943f9SDavid du Colombier "data", Qndata, 0666, 101906943f9SDavid du Colombier "ctl", Qnctl, 0666, 102906943f9SDavid du Colombier "ifstats", Qnifstats, 0444, 103906943f9SDavid du Colombier "stats", Qnstats, 0444, 104906943f9SDavid du Colombier "type", Qntype, 0444, 105906943f9SDavid du Colombier nil, 0, 106906943f9SDavid du Colombier }; 107906943f9SDavid du Colombier 108906943f9SDavid du Colombier int etherdebug; 109906943f9SDavid du Colombier 110906943f9SDavid du Colombier Resetf ethers[] = 111906943f9SDavid du Colombier { 112906943f9SDavid du Colombier asixreset, 113906943f9SDavid du Colombier cdcreset, /* keep last */ 114906943f9SDavid du Colombier }; 115906943f9SDavid du Colombier 116906943f9SDavid du Colombier static int 117906943f9SDavid du Colombier qtype(vlong q) 118906943f9SDavid du Colombier { 119906943f9SDavid du Colombier return q&0xFF; 120906943f9SDavid du Colombier } 121906943f9SDavid du Colombier 122906943f9SDavid du Colombier static int 123906943f9SDavid du Colombier qnum(vlong q) 124906943f9SDavid du Colombier { 125906943f9SDavid du Colombier return (q >> 8) & 0xFFFFFF; 126906943f9SDavid du Colombier } 127906943f9SDavid du Colombier 128906943f9SDavid du Colombier static uvlong 129906943f9SDavid du Colombier mkqid(int n, int t) 130906943f9SDavid du Colombier { 131906943f9SDavid du Colombier uvlong q; 132906943f9SDavid du Colombier 133906943f9SDavid du Colombier q = (n&0xFFFFFF) << 8 | t&0xFF; 134906943f9SDavid du Colombier return q; 135906943f9SDavid du Colombier } 136906943f9SDavid du Colombier 137906943f9SDavid du Colombier static void 138906943f9SDavid du Colombier freebuf(Ether *e, Buf *bp) 139906943f9SDavid du Colombier { 140906943f9SDavid du Colombier if(0)deprint(2, "%s: freebuf %#p\n", argv0, bp); 141906943f9SDavid du Colombier if(bp != nil){ 142906943f9SDavid du Colombier qlock(e); 143906943f9SDavid du Colombier e->nbufs--; 144906943f9SDavid du Colombier qunlock(e); 145906943f9SDavid du Colombier sendp(e->bc, bp); 146906943f9SDavid du Colombier } 147906943f9SDavid du Colombier } 148906943f9SDavid du Colombier 149906943f9SDavid du Colombier static Buf* 150906943f9SDavid du Colombier allocbuf(Ether *e) 151906943f9SDavid du Colombier { 152906943f9SDavid du Colombier Buf *bp; 153906943f9SDavid du Colombier 154906943f9SDavid du Colombier bp = nbrecvp(e->bc); 155906943f9SDavid du Colombier if(bp == nil){ 156906943f9SDavid du Colombier qlock(e); 157906943f9SDavid du Colombier if(e->nabufs < Nconns){ 158906943f9SDavid du Colombier bp = emallocz(sizeof(Buf), 1); 159906943f9SDavid du Colombier e->nabufs++; 160906943f9SDavid du Colombier setmalloctag(bp, getcallerpc(&e)); 161906943f9SDavid du Colombier deprint(2, "%s: %d buffers\n", argv0, e->nabufs); 162906943f9SDavid du Colombier } 163906943f9SDavid du Colombier qunlock(e); 164906943f9SDavid du Colombier } 165906943f9SDavid du Colombier if(bp == nil) 166906943f9SDavid du Colombier bp = recvp(e->bc); 167906943f9SDavid du Colombier bp->rp = bp->data + Hdrsize; 168906943f9SDavid du Colombier bp->ndata = 0; 169906943f9SDavid du Colombier if(0)deprint(2, "%s: allocbuf %#p\n", argv0, bp); 170906943f9SDavid du Colombier qlock(e); 171906943f9SDavid du Colombier e->nbufs++; 172906943f9SDavid du Colombier qunlock(e); 173906943f9SDavid du Colombier return bp; 174906943f9SDavid du Colombier } 175906943f9SDavid du Colombier 176906943f9SDavid du Colombier static Conn* 177906943f9SDavid du Colombier newconn(Ether *e) 178906943f9SDavid du Colombier { 179906943f9SDavid du Colombier int i; 180906943f9SDavid du Colombier Conn *c; 181906943f9SDavid du Colombier 182906943f9SDavid du Colombier qlock(e); 183906943f9SDavid du Colombier for(i = 0; i < nelem(e->conns); i++){ 184906943f9SDavid du Colombier c = e->conns[i]; 185906943f9SDavid du Colombier if(c == nil || c->ref == 0){ 186906943f9SDavid du Colombier if(c == nil){ 187906943f9SDavid du Colombier c = emallocz(sizeof(Conn), 1); 188906943f9SDavid du Colombier c->rc = chancreate(sizeof(Buf*), 2); 189906943f9SDavid du Colombier c->nb = i; 190906943f9SDavid du Colombier } 191906943f9SDavid du Colombier c->ref = 1; 192906943f9SDavid du Colombier if(i == e->nconns) 193906943f9SDavid du Colombier e->nconns++; 194906943f9SDavid du Colombier e->conns[i] = c; 195906943f9SDavid du Colombier deprint(2, "%s: newconn %d\n", argv0, i); 196906943f9SDavid du Colombier qunlock(e); 197906943f9SDavid du Colombier return c; 198906943f9SDavid du Colombier } 199906943f9SDavid du Colombier } 200906943f9SDavid du Colombier qunlock(e); 201906943f9SDavid du Colombier return nil; 202906943f9SDavid du Colombier } 203906943f9SDavid du Colombier 204906943f9SDavid du Colombier static char* 205906943f9SDavid du Colombier seprintaddr(char *s, char *se, uchar *addr) 206906943f9SDavid du Colombier { 207906943f9SDavid du Colombier int i; 208906943f9SDavid du Colombier 209906943f9SDavid du Colombier for(i = 0; i < Eaddrlen; i++) 210906943f9SDavid du Colombier s = seprint(s, se, "%02x", addr[i]); 211906943f9SDavid du Colombier return s; 212906943f9SDavid du Colombier } 213906943f9SDavid du Colombier 214906943f9SDavid du Colombier void 215906943f9SDavid du Colombier dumpframe(char *tag, void *p, int n) 216906943f9SDavid du Colombier { 217906943f9SDavid du Colombier Etherpkt *ep; 218906943f9SDavid du Colombier char buf[128]; 219906943f9SDavid du Colombier char *s, *se; 220906943f9SDavid du Colombier int i; 221906943f9SDavid du Colombier 222906943f9SDavid du Colombier ep = p; 223906943f9SDavid du Colombier if(n < Eaddrlen * 2 + 2){ 224906943f9SDavid du Colombier fprint(2, "short packet (%d bytes)\n", n); 225906943f9SDavid du Colombier return; 226906943f9SDavid du Colombier } 227906943f9SDavid du Colombier se = buf+sizeof(buf); 228906943f9SDavid du Colombier s = seprint(buf, se, "%s [%d]: ", tag, n); 229906943f9SDavid du Colombier s = seprintaddr(s, se, ep->s); 230906943f9SDavid du Colombier s = seprint(s, se, " -> "); 231906943f9SDavid du Colombier s = seprintaddr(s, se, ep->d); 232906943f9SDavid du Colombier s = seprint(s, se, " type 0x%02ux%02ux ", ep->type[0], ep->type[1]); 233906943f9SDavid du Colombier n -= Eaddrlen * 2 + 2; 234906943f9SDavid du Colombier for(i = 0; i < n && i < 16; i++) 235906943f9SDavid du Colombier s = seprint(s, se, "%02x", ep->data[i]); 236906943f9SDavid du Colombier if(n >= 16) 237906943f9SDavid du Colombier fprint(2, "%s...\n", buf); 238906943f9SDavid du Colombier else 239906943f9SDavid du Colombier fprint(2, "%s\n", buf); 240906943f9SDavid du Colombier } 241906943f9SDavid du Colombier 242906943f9SDavid du Colombier static char* 243906943f9SDavid du Colombier seprintstats(char *s, char *se, Ether *e) 244906943f9SDavid du Colombier { 245906943f9SDavid du Colombier qlock(e); 246906943f9SDavid du Colombier s = seprint(s, se, "in: %ld\n", e->nin); 247906943f9SDavid du Colombier s = seprint(s, se, "out: %ld\n", e->nout); 248906943f9SDavid du Colombier s = seprint(s, se, "input errs: %ld\n", e->nierrs); 249906943f9SDavid du Colombier s = seprint(s, se, "output errs: %ld\n", e->noerrs); 250906943f9SDavid du Colombier s = seprint(s, se, "mbps: %d\n", e->mbps); 251906943f9SDavid du Colombier s = seprint(s, se, "prom: %ld\n", e->prom.ref); 252906943f9SDavid du Colombier s = seprint(s, se, "addr: "); 253906943f9SDavid du Colombier s = seprintaddr(s, se, e->addr); 254906943f9SDavid du Colombier s = seprint(s, se, "\n"); 255906943f9SDavid du Colombier qunlock(e); 256906943f9SDavid du Colombier return s; 257906943f9SDavid du Colombier } 258906943f9SDavid du Colombier 259906943f9SDavid du Colombier static char* 260906943f9SDavid du Colombier seprintifstats(char *s, char *se, Ether *e) 261906943f9SDavid du Colombier { 262906943f9SDavid du Colombier int i; 263906943f9SDavid du Colombier Conn *c; 264906943f9SDavid du Colombier 265906943f9SDavid du Colombier qlock(e); 266906943f9SDavid du Colombier s = seprint(s, se, "ctlr id: %#x\n", e->cid); 267906943f9SDavid du Colombier s = seprint(s, se, "phy: %#x\n", e->phy); 268*d37e33ffSDavid du Colombier s = seprint(s, se, "exiting: %s\n", e->exiting ? "y" : "n"); 269906943f9SDavid du Colombier s = seprint(s, se, "conns: %d\n", e->nconns); 270906943f9SDavid du Colombier s = seprint(s, se, "allocated bufs: %d\n", e->nabufs); 271906943f9SDavid du Colombier s = seprint(s, se, "used bufs: %d\n", e->nbufs); 272906943f9SDavid du Colombier for(i = 0; i < nelem(e->conns); i++){ 273906943f9SDavid du Colombier c = e->conns[i]; 274906943f9SDavid du Colombier if(c == nil) 275906943f9SDavid du Colombier continue; 276906943f9SDavid du Colombier if(c->ref == 0) 277906943f9SDavid du Colombier s = seprint(s, se, "c[%d]: free\n", i); 278906943f9SDavid du Colombier else{ 279906943f9SDavid du Colombier s = seprint(s, se, "c[%d]: refs %ld t %#x h %d p %d\n", 280906943f9SDavid du Colombier c->nb, c->ref, c->type, c->headersonly, c->prom); 281906943f9SDavid du Colombier } 282906943f9SDavid du Colombier } 283906943f9SDavid du Colombier qunlock(e); 284906943f9SDavid du Colombier return s; 285906943f9SDavid du Colombier } 286906943f9SDavid du Colombier 287906943f9SDavid du Colombier static void 288906943f9SDavid du Colombier etherdump(Ether *e) 289906943f9SDavid du Colombier { 290906943f9SDavid du Colombier char buf[256]; 291906943f9SDavid du Colombier 292906943f9SDavid du Colombier if(etherdebug == 0) 293906943f9SDavid du Colombier return; 294906943f9SDavid du Colombier seprintifstats(buf, buf+sizeof(buf), e); 295906943f9SDavid du Colombier fprint(2, "%s: ether %#p:\n%s\n", argv0, e, buf); 296906943f9SDavid du Colombier } 297906943f9SDavid du Colombier 298906943f9SDavid du Colombier static Conn* 299906943f9SDavid du Colombier getconn(Ether *e, int i, int idleok) 300906943f9SDavid du Colombier { 301906943f9SDavid du Colombier Conn *c; 302906943f9SDavid du Colombier 303906943f9SDavid du Colombier qlock(e); 304906943f9SDavid du Colombier if(i < 0 || i >= e->nconns) 305906943f9SDavid du Colombier c = nil; 306906943f9SDavid du Colombier else{ 307906943f9SDavid du Colombier c = e->conns[i]; 308906943f9SDavid du Colombier if(idleok == 0 && c != nil && c->ref == 0) 309906943f9SDavid du Colombier c = nil; 310906943f9SDavid du Colombier } 311906943f9SDavid du Colombier qunlock(e); 312906943f9SDavid du Colombier return c; 313906943f9SDavid du Colombier } 314906943f9SDavid du Colombier 315906943f9SDavid du Colombier static void 316906943f9SDavid du Colombier filldir(Usbfs *fs, Dir *d, Dirtab *tab, int cn) 317906943f9SDavid du Colombier { 318906943f9SDavid du Colombier d->qid.path = mkqid(cn, tab->qid); 319906943f9SDavid du Colombier d->qid.path |= fs->qid; 320906943f9SDavid du Colombier d->mode = tab->mode; 321906943f9SDavid du Colombier if((d->mode & DMDIR) != 0) 322906943f9SDavid du Colombier d->qid.type = QTDIR; 323906943f9SDavid du Colombier else 324906943f9SDavid du Colombier d->qid.type = QTFILE; 325906943f9SDavid du Colombier if(tab->qid == Qndir) 326906943f9SDavid du Colombier sprint(d->name, "%d", cn); 327906943f9SDavid du Colombier else 328906943f9SDavid du Colombier d->name = tab->name; 329906943f9SDavid du Colombier } 330906943f9SDavid du Colombier 331906943f9SDavid du Colombier static int 332906943f9SDavid du Colombier rootdirgen(Usbfs *fs, Qid, int i, Dir *d, void *) 333906943f9SDavid du Colombier { 334906943f9SDavid du Colombier Ether *e; 335906943f9SDavid du Colombier Dirtab *tab; 336906943f9SDavid du Colombier int cn; 337906943f9SDavid du Colombier 338906943f9SDavid du Colombier e = fs->aux; 339906943f9SDavid du Colombier i++; /* skip root */ 340906943f9SDavid du Colombier cn = 0; 341906943f9SDavid du Colombier if(i < nelem(rootdirtab) - 1) /* null terminated */ 342906943f9SDavid du Colombier tab = &rootdirtab[i]; 343906943f9SDavid du Colombier else{ 344906943f9SDavid du Colombier cn = i - nelem(rootdirtab) + 1; 345906943f9SDavid du Colombier if(cn < e->nconns) 346906943f9SDavid du Colombier tab = &conndirtab[0]; 347906943f9SDavid du Colombier else 348906943f9SDavid du Colombier return -1; 349906943f9SDavid du Colombier } 350906943f9SDavid du Colombier filldir(fs, d, tab, cn); 351906943f9SDavid du Colombier return 0; 352906943f9SDavid du Colombier 353906943f9SDavid du Colombier } 354906943f9SDavid du Colombier 355906943f9SDavid du Colombier static int 356906943f9SDavid du Colombier conndirgen(Usbfs *fs, Qid q, int i, Dir *d, void *) 357906943f9SDavid du Colombier { 358906943f9SDavid du Colombier Dirtab *tab; 359906943f9SDavid du Colombier 360906943f9SDavid du Colombier i++; /* skip root */ 361906943f9SDavid du Colombier if(i < nelem(conndirtab) - 1) /* null terminated */ 362906943f9SDavid du Colombier tab = &conndirtab[i]; 363906943f9SDavid du Colombier else 364906943f9SDavid du Colombier return -1; 365906943f9SDavid du Colombier filldir(fs, d, tab, qnum(q.path)); 366906943f9SDavid du Colombier return 0; 367906943f9SDavid du Colombier } 368906943f9SDavid du Colombier 369906943f9SDavid du Colombier static int 370906943f9SDavid du Colombier fswalk(Usbfs *fs, Fid *fid, char *name) 371906943f9SDavid du Colombier { 372*d37e33ffSDavid du Colombier int cn, i; 373906943f9SDavid du Colombier char *es; 374906943f9SDavid du Colombier Dirtab *tab; 375*d37e33ffSDavid du Colombier Ether *e; 376*d37e33ffSDavid du Colombier Qid qid; 377906943f9SDavid du Colombier 378906943f9SDavid du Colombier e = fs->aux; 379906943f9SDavid du Colombier qid = fid->qid; 380906943f9SDavid du Colombier qid.path &= ~fs->qid; 381906943f9SDavid du Colombier if((qid.type & QTDIR) == 0){ 382906943f9SDavid du Colombier werrstr("walk in non-directory"); 383906943f9SDavid du Colombier return -1; 384906943f9SDavid du Colombier } 385906943f9SDavid du Colombier 386906943f9SDavid du Colombier if(strcmp(name, "..") == 0){ 387906943f9SDavid du Colombier /* must be /etherU%d; i.e. our root dir. */ 388906943f9SDavid du Colombier fid->qid.path = mkqid(0, Qroot) | fs->qid; 389906943f9SDavid du Colombier fid->qid.vers = 0; 390906943f9SDavid du Colombier fid->qid.type = QTDIR; 391906943f9SDavid du Colombier return 0; 392906943f9SDavid du Colombier } 393906943f9SDavid du Colombier switch(qtype(qid.path)){ 394906943f9SDavid du Colombier case Qroot: 395906943f9SDavid du Colombier if(name[0] >= '0' && name[0] <= '9'){ 396906943f9SDavid du Colombier es = name; 397906943f9SDavid du Colombier cn = strtoul(name, &es, 10); 398906943f9SDavid du Colombier if(cn >= e->nconns || *es != 0){ 399906943f9SDavid du Colombier werrstr(Enotfound); 400906943f9SDavid du Colombier return -1; 401906943f9SDavid du Colombier } 402906943f9SDavid du Colombier fid->qid.path = mkqid(cn, Qndir) | fs->qid; 403906943f9SDavid du Colombier fid->qid.vers = 0; 404906943f9SDavid du Colombier return 0; 405906943f9SDavid du Colombier } 406906943f9SDavid du Colombier /* fall */ 407906943f9SDavid du Colombier case Qndir: 408906943f9SDavid du Colombier if(qtype(qid.path) == Qroot) 409906943f9SDavid du Colombier tab = rootdirtab; 410906943f9SDavid du Colombier else 411906943f9SDavid du Colombier tab = conndirtab; 412906943f9SDavid du Colombier cn = qnum(qid.path); 413906943f9SDavid du Colombier for(i = 0; tab[i].name != nil; tab++) 414906943f9SDavid du Colombier if(strcmp(tab[i].name, name) == 0){ 415906943f9SDavid du Colombier fid->qid.path = mkqid(cn, tab[i].qid)|fs->qid; 416906943f9SDavid du Colombier fid->qid.vers = 0; 417906943f9SDavid du Colombier if((tab[i].mode & DMDIR) != 0) 418906943f9SDavid du Colombier fid->qid.type = QTDIR; 419906943f9SDavid du Colombier else 420906943f9SDavid du Colombier fid->qid.type = QTFILE; 421906943f9SDavid du Colombier return 0; 422906943f9SDavid du Colombier } 423906943f9SDavid du Colombier break; 424906943f9SDavid du Colombier default: 425906943f9SDavid du Colombier sysfatal("usb: ether: fswalk bug"); 426906943f9SDavid du Colombier } 427906943f9SDavid du Colombier return -1; 428906943f9SDavid du Colombier } 429906943f9SDavid du Colombier 430906943f9SDavid du Colombier static Dirtab* 431906943f9SDavid du Colombier qdirtab(vlong q) 432906943f9SDavid du Colombier { 433*d37e33ffSDavid du Colombier int i, qt; 434906943f9SDavid du Colombier Dirtab *tab; 435906943f9SDavid du Colombier 436906943f9SDavid du Colombier qt = qtype(q); 437906943f9SDavid du Colombier if(qt < nelem(rootdirtab) - 1){ /* null terminated */ 438906943f9SDavid du Colombier tab = rootdirtab; 439906943f9SDavid du Colombier i = qt; 440906943f9SDavid du Colombier }else{ 441906943f9SDavid du Colombier tab = conndirtab; 442906943f9SDavid du Colombier i = qt - (nelem(rootdirtab) - 1); 443906943f9SDavid du Colombier assert(i < nelem(conndirtab) - 1); 444906943f9SDavid du Colombier } 445906943f9SDavid du Colombier return &tab[i]; 446906943f9SDavid du Colombier } 447906943f9SDavid du Colombier 448906943f9SDavid du Colombier static int 449906943f9SDavid du Colombier fsstat(Usbfs *fs, Qid qid, Dir *d) 450906943f9SDavid du Colombier { 451906943f9SDavid du Colombier filldir(fs, d, qdirtab(qid.path), qnum(qid.path)); 452906943f9SDavid du Colombier return 0; 453906943f9SDavid du Colombier } 454906943f9SDavid du Colombier 455906943f9SDavid du Colombier static int 456906943f9SDavid du Colombier fsopen(Usbfs *fs, Fid *fid, int omode) 457906943f9SDavid du Colombier { 458906943f9SDavid du Colombier int qt; 459906943f9SDavid du Colombier vlong qid; 460*d37e33ffSDavid du Colombier Conn *c; 461*d37e33ffSDavid du Colombier Dirtab *tab; 462*d37e33ffSDavid du Colombier Ether *e; 463906943f9SDavid du Colombier 464906943f9SDavid du Colombier qid = fid->qid.path & ~fs->qid; 465906943f9SDavid du Colombier e = fs->aux; 466906943f9SDavid du Colombier qt = qtype(qid); 467906943f9SDavid du Colombier tab = qdirtab(qid); 468906943f9SDavid du Colombier omode &= 3; 469906943f9SDavid du Colombier if(omode != OREAD && (tab->mode&0222) == 0){ 470906943f9SDavid du Colombier werrstr(Eperm); 471906943f9SDavid du Colombier return -1; 472906943f9SDavid du Colombier } 473906943f9SDavid du Colombier switch(qt){ 474906943f9SDavid du Colombier case Qclone: 475906943f9SDavid du Colombier c = newconn(e); 476906943f9SDavid du Colombier if(c == nil){ 477906943f9SDavid du Colombier werrstr("no more connections"); 478906943f9SDavid du Colombier return -1; 479906943f9SDavid du Colombier } 480906943f9SDavid du Colombier fid->qid.type = QTFILE; 481906943f9SDavid du Colombier fid->qid.path = mkqid(c->nb, Qnctl)|fs->qid; 482906943f9SDavid du Colombier fid->qid.vers = 0; 483906943f9SDavid du Colombier break; 484906943f9SDavid du Colombier case Qndata: 485906943f9SDavid du Colombier case Qnctl: 486906943f9SDavid du Colombier case Qnifstats: 487906943f9SDavid du Colombier case Qnstats: 488906943f9SDavid du Colombier case Qntype: 489906943f9SDavid du Colombier c = getconn(e, qnum(qid), 1); 490906943f9SDavid du Colombier if(c == nil) 491906943f9SDavid du Colombier sysfatal("usb: ether: fsopen bug"); 492906943f9SDavid du Colombier incref(c); 493906943f9SDavid du Colombier break; 494906943f9SDavid du Colombier } 495906943f9SDavid du Colombier etherdump(e); 496906943f9SDavid du Colombier return 0; 497906943f9SDavid du Colombier } 498906943f9SDavid du Colombier 499906943f9SDavid du Colombier static int 500906943f9SDavid du Colombier prom(Ether *e, int set) 501906943f9SDavid du Colombier { 502906943f9SDavid du Colombier if(e->promiscuous != nil) 503906943f9SDavid du Colombier return e->promiscuous(e, set); 504906943f9SDavid du Colombier return 0; 505906943f9SDavid du Colombier } 506906943f9SDavid du Colombier 507906943f9SDavid du Colombier static void 508906943f9SDavid du Colombier fsclunk(Usbfs *fs, Fid *fid) 509906943f9SDavid du Colombier { 510906943f9SDavid du Colombier int qt; 511906943f9SDavid du Colombier vlong qid; 512906943f9SDavid du Colombier Buf *bp; 513*d37e33ffSDavid du Colombier Conn *c; 514*d37e33ffSDavid du Colombier Ether *e; 515906943f9SDavid du Colombier 516906943f9SDavid du Colombier e = fs->aux; 517906943f9SDavid du Colombier qid = fid->qid.path & ~fs->qid; 518906943f9SDavid du Colombier qt = qtype(qid); 519906943f9SDavid du Colombier switch(qt){ 520906943f9SDavid du Colombier case Qndata: 521906943f9SDavid du Colombier case Qnctl: 522906943f9SDavid du Colombier case Qnifstats: 523906943f9SDavid du Colombier case Qnstats: 524906943f9SDavid du Colombier case Qntype: 525906943f9SDavid du Colombier if(fid->omode != ONONE){ 526906943f9SDavid du Colombier c = getconn(e, qnum(qid), 0); 527906943f9SDavid du Colombier if(c == nil) 528906943f9SDavid du Colombier sysfatal("usb: ether: fsopen bug"); 529906943f9SDavid du Colombier if(decref(c) == 0){ 530906943f9SDavid du Colombier while((bp = nbrecvp(c->rc)) != nil) 531906943f9SDavid du Colombier freebuf(e, bp); 532906943f9SDavid du Colombier qlock(e); 533906943f9SDavid du Colombier if(c->prom != 0) 534906943f9SDavid du Colombier if(decref(&e->prom) == 0) 535906943f9SDavid du Colombier prom(e, 0); 536906943f9SDavid du Colombier c->prom = c->type = 0; 537906943f9SDavid du Colombier qunlock(e); 538906943f9SDavid du Colombier } 539906943f9SDavid du Colombier } 540906943f9SDavid du Colombier break; 541906943f9SDavid du Colombier } 542906943f9SDavid du Colombier etherdump(e); 543906943f9SDavid du Colombier } 544906943f9SDavid du Colombier 545906943f9SDavid du Colombier int 546906943f9SDavid du Colombier parseaddr(uchar *m, char *s) 547906943f9SDavid du Colombier { 548*d37e33ffSDavid du Colombier int i, n; 549906943f9SDavid du Colombier uchar v; 550906943f9SDavid du Colombier 551906943f9SDavid du Colombier if(strlen(s) < 12) 552906943f9SDavid du Colombier return -1; 553906943f9SDavid du Colombier if(strlen(s) > 12 && strlen(s) < 17) 554906943f9SDavid du Colombier return -1; 555906943f9SDavid du Colombier for(i = n = 0; i < strlen(s); i++){ 556906943f9SDavid du Colombier if(s[i] == ':') 557906943f9SDavid du Colombier continue; 558906943f9SDavid du Colombier if(s[i] >= 'A' && s[i] <= 'F') 559906943f9SDavid du Colombier v = 10 + s[i] - 'A'; 560906943f9SDavid du Colombier else if(s[i] >= 'a' && s[i] <= 'f') 561906943f9SDavid du Colombier v = 10 + s[i] - 'a'; 562906943f9SDavid du Colombier else if(s[i] >= '0' && s[i] <= '9') 563906943f9SDavid du Colombier v = s[i] - '0'; 564906943f9SDavid du Colombier else 565906943f9SDavid du Colombier return -1; 566906943f9SDavid du Colombier if(n&1) 567906943f9SDavid du Colombier m[n/2] |= v; 568906943f9SDavid du Colombier else 569906943f9SDavid du Colombier m[n/2] = v<<4; 570906943f9SDavid du Colombier n++; 571906943f9SDavid du Colombier } 572906943f9SDavid du Colombier return 0; 573906943f9SDavid du Colombier } 574906943f9SDavid du Colombier 575906943f9SDavid du Colombier static long 576906943f9SDavid du Colombier fsread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset) 577906943f9SDavid du Colombier { 578*d37e33ffSDavid du Colombier int cn, qt; 579*d37e33ffSDavid du Colombier char *s, *se; 580906943f9SDavid du Colombier char buf[128]; 581*d37e33ffSDavid du Colombier Buf *bp; 582906943f9SDavid du Colombier Conn *c; 583*d37e33ffSDavid du Colombier Ether *e; 584*d37e33ffSDavid du Colombier Qid q; 585906943f9SDavid du Colombier 586906943f9SDavid du Colombier q = fid->qid; 587906943f9SDavid du Colombier q.path &= ~fs->qid; 588906943f9SDavid du Colombier e = fs->aux; 589906943f9SDavid du Colombier s = buf; 590906943f9SDavid du Colombier se = buf+sizeof(buf); 591906943f9SDavid du Colombier qt = qtype(q.path); 592906943f9SDavid du Colombier cn = qnum(q.path); 593906943f9SDavid du Colombier switch(qt){ 594906943f9SDavid du Colombier case Qroot: 595906943f9SDavid du Colombier count = usbdirread(fs, q, data, count, offset, rootdirgen, nil); 596906943f9SDavid du Colombier break; 597906943f9SDavid du Colombier case Qaddr: 598906943f9SDavid du Colombier s = seprintaddr(s, se, e->addr); 599906943f9SDavid du Colombier count = usbreadbuf(data, count, offset, buf, s - buf); 600906943f9SDavid du Colombier break; 601906943f9SDavid du Colombier case Qnifstats: 602906943f9SDavid du Colombier /* BUG */ 603906943f9SDavid du Colombier case Qifstats: 604906943f9SDavid du Colombier s = seprintifstats(s, se, e); 605906943f9SDavid du Colombier if(e->seprintstats != nil) 606906943f9SDavid du Colombier s = e->seprintstats(s, se, e); 607906943f9SDavid du Colombier count = usbreadbuf(data, count, offset, buf, s - buf); 608906943f9SDavid du Colombier break; 609906943f9SDavid du Colombier case Qnstats: 610906943f9SDavid du Colombier /* BUG */ 611906943f9SDavid du Colombier case Qstats: 612906943f9SDavid du Colombier s = seprintstats(s, se, e); 613906943f9SDavid du Colombier count = usbreadbuf(data, count, offset, buf, s - buf); 614906943f9SDavid du Colombier break; 615906943f9SDavid du Colombier 616906943f9SDavid du Colombier case Qndir: 617906943f9SDavid du Colombier count = usbdirread(fs, q, data, count, offset, conndirgen, nil); 618906943f9SDavid du Colombier break; 619906943f9SDavid du Colombier case Qndata: 620906943f9SDavid du Colombier c = getconn(e, cn, 0); 621906943f9SDavid du Colombier if(c == nil){ 622906943f9SDavid du Colombier werrstr(Eio); 623906943f9SDavid du Colombier return -1; 624906943f9SDavid du Colombier } 625906943f9SDavid du Colombier bp = recvp(c->rc); 626906943f9SDavid du Colombier if(bp == nil) 627906943f9SDavid du Colombier return -1; 628906943f9SDavid du Colombier if(etherdebug > 1) 629906943f9SDavid du Colombier dumpframe("etherin", bp->rp, bp->ndata); 630906943f9SDavid du Colombier count = usbreadbuf(data, count, 0LL, bp->rp, bp->ndata); 631906943f9SDavid du Colombier freebuf(e, bp); 632906943f9SDavid du Colombier break; 633906943f9SDavid du Colombier case Qnctl: 634906943f9SDavid du Colombier s = seprint(s, se, "%11d ", cn); 635906943f9SDavid du Colombier count = usbreadbuf(data, count, offset, buf, s - buf); 636906943f9SDavid du Colombier break; 637906943f9SDavid du Colombier case Qntype: 638906943f9SDavid du Colombier c = getconn(e, cn, 0); 639906943f9SDavid du Colombier if(c == nil) 640906943f9SDavid du Colombier s = seprint(s, se, "%11d ", 0); 641906943f9SDavid du Colombier else 642906943f9SDavid du Colombier s = seprint(s, se, "%11d ", c->type); 643906943f9SDavid du Colombier count = usbreadbuf(data, count, offset, buf, s - buf); 644906943f9SDavid du Colombier break; 645906943f9SDavid du Colombier default: 646906943f9SDavid du Colombier sysfatal("usb: ether: fsread bug"); 647906943f9SDavid du Colombier } 648906943f9SDavid du Colombier return count; 649906943f9SDavid du Colombier } 650906943f9SDavid du Colombier 651906943f9SDavid du Colombier static int 652906943f9SDavid du Colombier typeinuse(Ether *e, int t) 653906943f9SDavid du Colombier { 654906943f9SDavid du Colombier int i; 655906943f9SDavid du Colombier 656906943f9SDavid du Colombier for(i = 0; i < e->nconns; i++) 657906943f9SDavid du Colombier if(e->conns[i]->ref > 0 && e->conns[i]->type == t) 658906943f9SDavid du Colombier return 1; 659906943f9SDavid du Colombier return 0; 660906943f9SDavid du Colombier } 661906943f9SDavid du Colombier 662906943f9SDavid du Colombier static int 663906943f9SDavid du Colombier isloopback(Ether *e, Buf *) 664906943f9SDavid du Colombier { 665906943f9SDavid du Colombier return e->prom.ref > 0; /* BUG: also loopbacks and broadcasts */ 666906943f9SDavid du Colombier } 667906943f9SDavid du Colombier 668906943f9SDavid du Colombier static int 669906943f9SDavid du Colombier etherctl(Ether *e, Conn *c, char *buf) 670906943f9SDavid du Colombier { 671906943f9SDavid du Colombier uchar addr[Eaddrlen]; 672906943f9SDavid du Colombier int t; 673906943f9SDavid du Colombier 674906943f9SDavid du Colombier deprint(2, "%s: etherctl: %s\n", argv0, buf); 675906943f9SDavid du Colombier if(strncmp(buf, "connect ", 8) == 0){ 676906943f9SDavid du Colombier t = atoi(buf+8); 677906943f9SDavid du Colombier qlock(e); 678906943f9SDavid du Colombier if(typeinuse(e, t)){ 679906943f9SDavid du Colombier werrstr("type already in use"); 680906943f9SDavid du Colombier qunlock(e); 681906943f9SDavid du Colombier return -1; 682906943f9SDavid du Colombier } 683906943f9SDavid du Colombier c->type = atoi(buf+8); 684906943f9SDavid du Colombier qunlock(e); 685906943f9SDavid du Colombier return 0; 686906943f9SDavid du Colombier } 687906943f9SDavid du Colombier if(strncmp(buf, "nonblocking", 11) == 0){ 688906943f9SDavid du Colombier if(buf[11] == '\n' || buf[11] == 0) 689906943f9SDavid du Colombier e->nblock = 1; 690906943f9SDavid du Colombier else 691906943f9SDavid du Colombier e->nblock = atoi(buf + 12); 692906943f9SDavid du Colombier deprint(2, "%s: nblock %d\n", argv0, e->nblock); 693906943f9SDavid du Colombier return 0; 694906943f9SDavid du Colombier } 695906943f9SDavid du Colombier if(strncmp(buf, "promiscuous", 11) == 0){ 696906943f9SDavid du Colombier if(c->prom == 0) 697906943f9SDavid du Colombier incref(&e->prom); 698906943f9SDavid du Colombier c->prom = 1; 699906943f9SDavid du Colombier return prom(e, 1); 700906943f9SDavid du Colombier } 701906943f9SDavid du Colombier if(strncmp(buf, "headersonly", 11) == 0){ 702906943f9SDavid du Colombier c->headersonly = 1; 703906943f9SDavid du Colombier return 0; 704906943f9SDavid du Colombier } 705*d37e33ffSDavid du Colombier if(strncmp(buf, "addmulti ", 9) == 0 || strncmp(buf, "remmulti ", 9) == 0){ 706906943f9SDavid du Colombier if(parseaddr(addr, buf+9) < 0){ 707906943f9SDavid du Colombier werrstr("bad address"); 708906943f9SDavid du Colombier return -1; 709906943f9SDavid du Colombier } 710906943f9SDavid du Colombier if(e->multicast == nil) 711906943f9SDavid du Colombier return 0; 712906943f9SDavid du Colombier if(strncmp(buf, "add", 3) == 0){ 713906943f9SDavid du Colombier e->nmcasts++; 714906943f9SDavid du Colombier return e->multicast(e, addr, 1); 715906943f9SDavid du Colombier }else{ 716906943f9SDavid du Colombier e->nmcasts--; 717906943f9SDavid du Colombier return e->multicast(e, addr, 0); 718906943f9SDavid du Colombier } 719906943f9SDavid du Colombier } 720906943f9SDavid du Colombier 721906943f9SDavid du Colombier if(e->ctl != nil) 722906943f9SDavid du Colombier return e->ctl(e, buf); 723906943f9SDavid du Colombier werrstr(Ebadctl); 724906943f9SDavid du Colombier return -1; 725906943f9SDavid du Colombier } 726906943f9SDavid du Colombier 727906943f9SDavid du Colombier static long 728906943f9SDavid du Colombier etherbread(Ether *e, Buf *bp) 729906943f9SDavid du Colombier { 730906943f9SDavid du Colombier deprint(2, "%s: etherbread\n", argv0); 731906943f9SDavid du Colombier bp->rp = bp->data + Hdrsize; 732*d37e33ffSDavid du Colombier bp->ndata = -1; 733906943f9SDavid du Colombier bp->ndata = read(e->epin->dfd, bp->rp, sizeof(bp->data)-Hdrsize); 734*d37e33ffSDavid du Colombier if(bp->ndata < 0) 735*d37e33ffSDavid du Colombier deprint(2, "%s: etherbread: %r\n", argv0); 736*d37e33ffSDavid du Colombier else 737*d37e33ffSDavid du Colombier deprint(2, "%s: etherbread: got %d bytes\n", argv0, bp->ndata); 738906943f9SDavid du Colombier return bp->ndata; 739906943f9SDavid du Colombier } 740906943f9SDavid du Colombier 741906943f9SDavid du Colombier static long 742906943f9SDavid du Colombier etherbwrite(Ether *e, Buf *bp) 743906943f9SDavid du Colombier { 744906943f9SDavid du Colombier long n; 745906943f9SDavid du Colombier 746906943f9SDavid du Colombier deprint(2, "%s: etherbwrite %d bytes\n", argv0, bp->ndata); 747906943f9SDavid du Colombier n = write(e->epout->dfd, bp->rp, bp->ndata); 748*d37e33ffSDavid du Colombier if(n < 0) 749*d37e33ffSDavid du Colombier deprint(2, "%s: etherbwrite: %r\n", argv0); 750*d37e33ffSDavid du Colombier else 751906943f9SDavid du Colombier deprint(2, "%s: etherbwrite wrote %ld bytes\n", argv0, n); 752906943f9SDavid du Colombier if(n <= 0) 753906943f9SDavid du Colombier return n; 754906943f9SDavid du Colombier if((bp->ndata % e->epout->maxpkt) == 0){ 755906943f9SDavid du Colombier deprint(2, "%s: short pkt write\n", argv0); 756*d37e33ffSDavid du Colombier write(e->epout->dfd, "", 1); 757906943f9SDavid du Colombier } 758906943f9SDavid du Colombier return n; 759906943f9SDavid du Colombier } 760906943f9SDavid du Colombier 761906943f9SDavid du Colombier static long 762906943f9SDavid du Colombier fswrite(Usbfs *fs, Fid *fid, void *data, long count, vlong) 763906943f9SDavid du Colombier { 764*d37e33ffSDavid du Colombier int cn, qt; 765906943f9SDavid du Colombier char buf[128]; 766906943f9SDavid du Colombier Buf *bp; 767*d37e33ffSDavid du Colombier Conn *c; 768*d37e33ffSDavid du Colombier Ether *e; 769*d37e33ffSDavid du Colombier Qid q; 770906943f9SDavid du Colombier 771906943f9SDavid du Colombier q = fid->qid; 772906943f9SDavid du Colombier q.path &= ~fs->qid; 773906943f9SDavid du Colombier e = fs->aux; 774906943f9SDavid du Colombier qt = qtype(q.path); 775906943f9SDavid du Colombier cn = qnum(q.path); 776906943f9SDavid du Colombier switch(qt){ 777906943f9SDavid du Colombier case Qndata: 778906943f9SDavid du Colombier c = getconn(e, cn, 0); 779906943f9SDavid du Colombier if(c == nil){ 780906943f9SDavid du Colombier werrstr(Eio); 781906943f9SDavid du Colombier return -1; 782906943f9SDavid du Colombier } 783906943f9SDavid du Colombier bp = allocbuf(e); 784906943f9SDavid du Colombier if(count > sizeof(bp->data)-Hdrsize) 785906943f9SDavid du Colombier count = sizeof(bp->data)-Hdrsize; 786906943f9SDavid du Colombier memmove(bp->rp, data, count); 787906943f9SDavid du Colombier bp->ndata = count; 788906943f9SDavid du Colombier if(etherdebug > 1) 789906943f9SDavid du Colombier dumpframe("etherout", bp->rp, bp->ndata); 790906943f9SDavid du Colombier if(e->nblock == 0) 791906943f9SDavid du Colombier sendp(e->wc, bp); 792906943f9SDavid du Colombier else if(nbsendp(e->wc, bp) < 0){ 793906943f9SDavid du Colombier deprint(2, "%s: (out) packet lost\n", argv0); 794906943f9SDavid du Colombier freebuf(e, bp); 795906943f9SDavid du Colombier } 796906943f9SDavid du Colombier break; 797906943f9SDavid du Colombier case Qnctl: 798906943f9SDavid du Colombier c = getconn(e, cn, 0); 799906943f9SDavid du Colombier if(c == nil){ 800906943f9SDavid du Colombier werrstr(Eio); 801906943f9SDavid du Colombier return -1; 802906943f9SDavid du Colombier } 803906943f9SDavid du Colombier if(count > sizeof(buf) - 1) 804906943f9SDavid du Colombier count = sizeof(buf) - 1; 805906943f9SDavid du Colombier memmove(buf, data, count); 806906943f9SDavid du Colombier buf[count] = 0; 807906943f9SDavid du Colombier if(etherctl(e, c, buf) < 0) 808906943f9SDavid du Colombier return -1; 809906943f9SDavid du Colombier break; 810906943f9SDavid du Colombier default: 811906943f9SDavid du Colombier sysfatal("usb: ether: fsread bug"); 812906943f9SDavid du Colombier } 813906943f9SDavid du Colombier return count; 814906943f9SDavid du Colombier } 815906943f9SDavid du Colombier 816906943f9SDavid du Colombier static int 817906943f9SDavid du Colombier openeps(Ether *e, int epin, int epout) 818906943f9SDavid du Colombier { 819906943f9SDavid du Colombier e->epin = openep(e->dev, epin); 820906943f9SDavid du Colombier if(e->epin == nil){ 821906943f9SDavid du Colombier fprint(2, "ether: in: openep %d: %r\n", epin); 822906943f9SDavid du Colombier return -1; 823906943f9SDavid du Colombier } 824906943f9SDavid du Colombier if(epout == epin){ 825906943f9SDavid du Colombier incref(e->epin); 826906943f9SDavid du Colombier e->epout = e->epin; 827906943f9SDavid du Colombier }else 828906943f9SDavid du Colombier e->epout = openep(e->dev, epout); 829906943f9SDavid du Colombier if(e->epout == nil){ 830906943f9SDavid du Colombier fprint(2, "ether: out: openep %d: %r\n", epout); 831906943f9SDavid du Colombier closedev(e->epin); 832906943f9SDavid du Colombier return -1; 833906943f9SDavid du Colombier } 834906943f9SDavid du Colombier if(e->epin == e->epout) 835906943f9SDavid du Colombier opendevdata(e->epin, ORDWR); 836906943f9SDavid du Colombier else{ 837906943f9SDavid du Colombier opendevdata(e->epin, OREAD); 838906943f9SDavid du Colombier opendevdata(e->epout, OWRITE); 839906943f9SDavid du Colombier } 840906943f9SDavid du Colombier if(e->epin->dfd < 0 || e->epout->dfd < 0){ 841906943f9SDavid du Colombier fprint(2, "ether: open i/o ep data: %r\n"); 842906943f9SDavid du Colombier closedev(e->epin); 843906943f9SDavid du Colombier closedev(e->epout); 844906943f9SDavid du Colombier return -1; 845906943f9SDavid du Colombier } 846*d37e33ffSDavid du Colombier dprint(2, "ether: ep in %s maxpkt %d; ep out %s maxpkt %d\n", 847*d37e33ffSDavid du Colombier e->epin->dir, e->epin->maxpkt, e->epout->dir, e->epout->maxpkt); 848*d37e33ffSDavid du Colombier 849*d37e33ffSDavid du Colombier /* time outs are not activated for I/O endpoints */ 850906943f9SDavid du Colombier 851906943f9SDavid du Colombier if(usbdebug > 2 || etherdebug > 2){ 852906943f9SDavid du Colombier devctl(e->epin, "debug 1"); 853906943f9SDavid du Colombier devctl(e->epout, "debug 1"); 854906943f9SDavid du Colombier devctl(e->dev, "debug 1"); 855906943f9SDavid du Colombier } 856*d37e33ffSDavid du Colombier 857906943f9SDavid du Colombier return 0; 858906943f9SDavid du Colombier } 859906943f9SDavid du Colombier 860906943f9SDavid du Colombier static int 861906943f9SDavid du Colombier usage(void) 862906943f9SDavid du Colombier { 863906943f9SDavid du Colombier werrstr("usage: usb/ether [-d]"); 864906943f9SDavid du Colombier return -1; 865906943f9SDavid du Colombier } 866906943f9SDavid du Colombier 867906943f9SDavid du Colombier static Usbfs etherfs = { 868906943f9SDavid du Colombier .walk = fswalk, 869906943f9SDavid du Colombier .open = fsopen, 870906943f9SDavid du Colombier .read = fsread, 871906943f9SDavid du Colombier .write = fswrite, 872906943f9SDavid du Colombier .stat = fsstat, 873906943f9SDavid du Colombier .clunk = fsclunk, 874906943f9SDavid du Colombier }; 875906943f9SDavid du Colombier 876906943f9SDavid du Colombier static void 877*d37e33ffSDavid du Colombier shutdownchan(Channel *c) 878*d37e33ffSDavid du Colombier { 879*d37e33ffSDavid du Colombier Buf *bp; 880*d37e33ffSDavid du Colombier 881*d37e33ffSDavid du Colombier while((bp=nbrecvp(c)) != nil) 882*d37e33ffSDavid du Colombier free(bp); 883*d37e33ffSDavid du Colombier chanfree(c); 884*d37e33ffSDavid du Colombier } 885*d37e33ffSDavid du Colombier 886*d37e33ffSDavid du Colombier static void 887906943f9SDavid du Colombier etherfree(Ether *e) 888906943f9SDavid du Colombier { 889906943f9SDavid du Colombier int i; 890906943f9SDavid du Colombier Buf *bp; 891906943f9SDavid du Colombier 892906943f9SDavid du Colombier if(e->free != nil) 893906943f9SDavid du Colombier e->free(e); 894906943f9SDavid du Colombier closedev(e->epin); 895906943f9SDavid du Colombier closedev(e->epout); 896*d37e33ffSDavid du Colombier if(e->rc == nil){ /* not really started */ 897906943f9SDavid du Colombier free(e); 898906943f9SDavid du Colombier return; 899906943f9SDavid du Colombier } 900906943f9SDavid du Colombier for(i = 0; i < e->nconns; i++) 901906943f9SDavid du Colombier if(e->conns[i] != nil){ 902906943f9SDavid du Colombier while((bp = nbrecvp(e->conns[i]->rc)) != nil) 903906943f9SDavid du Colombier free(bp); 904906943f9SDavid du Colombier chanfree(e->conns[i]->rc); 905906943f9SDavid du Colombier free(e->conns[i]); 906906943f9SDavid du Colombier } 907*d37e33ffSDavid du Colombier shutdownchan(e->bc); 908*d37e33ffSDavid du Colombier shutdownchan(e->rc); 909*d37e33ffSDavid du Colombier shutdownchan(e->wc); 910906943f9SDavid du Colombier e->epin = e->epout = nil; 911906943f9SDavid du Colombier free(e); 912906943f9SDavid du Colombier 913906943f9SDavid du Colombier } 914906943f9SDavid du Colombier 915*d37e33ffSDavid du Colombier static void 916*d37e33ffSDavid du Colombier etherdevfree(void *a) 917*d37e33ffSDavid du Colombier { 918*d37e33ffSDavid du Colombier Ether *e = a; 919*d37e33ffSDavid du Colombier 920*d37e33ffSDavid du Colombier if(e != nil) 921*d37e33ffSDavid du Colombier etherfree(e); 922*d37e33ffSDavid du Colombier } 923*d37e33ffSDavid du Colombier 924906943f9SDavid du Colombier /* must return 1 if c wants bp; 0 if not */ 925906943f9SDavid du Colombier static int 926906943f9SDavid du Colombier cwantsbp(Conn *c, Buf *bp) 927906943f9SDavid du Colombier { 928906943f9SDavid du Colombier if(c->ref != 0 && (c->prom != 0 || c->type < 0 || c->type == bp->type)) 929906943f9SDavid du Colombier return 1; 930906943f9SDavid du Colombier return 0; 931906943f9SDavid du Colombier } 932906943f9SDavid du Colombier 933906943f9SDavid du Colombier static void 934906943f9SDavid du Colombier etherwriteproc(void *a) 935906943f9SDavid du Colombier { 936906943f9SDavid du Colombier Ether *e = a; 937906943f9SDavid du Colombier Buf *bp; 938906943f9SDavid du Colombier Channel *wc; 939906943f9SDavid du Colombier 940906943f9SDavid du Colombier wc = e->wc; 941906943f9SDavid du Colombier while(e->exiting == 0){ 942906943f9SDavid du Colombier bp = recvp(wc); 943906943f9SDavid du Colombier if(bp == nil || e->exiting != 0) 944906943f9SDavid du Colombier break; 945906943f9SDavid du Colombier e->nout++; 946906943f9SDavid du Colombier if(e->bwrite(e, bp) < 0) 947906943f9SDavid du Colombier e->noerrs++; 948*d37e33ffSDavid du Colombier if(isloopback(e, bp) && e->exiting == 0) 949906943f9SDavid du Colombier sendp(e->rc, bp); /* send to input queue */ 950906943f9SDavid du Colombier else 951906943f9SDavid du Colombier freebuf(e, bp); 952906943f9SDavid du Colombier } 953906943f9SDavid du Colombier deprint(2, "%s: writeproc exiting\n", argv0); 954*d37e33ffSDavid du Colombier closedev(e->dev); 955*d37e33ffSDavid du Colombier } 956*d37e33ffSDavid du Colombier 957*d37e33ffSDavid du Colombier static void 958*d37e33ffSDavid du Colombier setbuftype(Buf *bp) 959*d37e33ffSDavid du Colombier { 960*d37e33ffSDavid du Colombier uchar *p; 961*d37e33ffSDavid du Colombier 962*d37e33ffSDavid du Colombier bp->type = 0; 963*d37e33ffSDavid du Colombier if(bp->ndata >= Ehdrsize){ 964*d37e33ffSDavid du Colombier p = bp->rp + Eaddrlen*2; 965*d37e33ffSDavid du Colombier bp->type = p[0]<<8 | p[1]; 966*d37e33ffSDavid du Colombier } 967*d37e33ffSDavid du Colombier } 968*d37e33ffSDavid du Colombier 969*d37e33ffSDavid du Colombier static void 970*d37e33ffSDavid du Colombier etherexiting(Ether *e) 971*d37e33ffSDavid du Colombier { 972*d37e33ffSDavid du Colombier devctl(e->dev, "detach"); 973*d37e33ffSDavid du Colombier e->exiting = 1; 974*d37e33ffSDavid du Colombier close(e->epin->dfd); 975*d37e33ffSDavid du Colombier e->epin->dfd = -1; 976*d37e33ffSDavid du Colombier close(e->epout->dfd); 977*d37e33ffSDavid du Colombier e->epout->dfd = -1; 978*d37e33ffSDavid du Colombier nbsend(e->wc, nil); 979906943f9SDavid du Colombier } 980906943f9SDavid du Colombier 981906943f9SDavid du Colombier static void 982906943f9SDavid du Colombier etherreadproc(void *a) 983906943f9SDavid du Colombier { 984*d37e33ffSDavid du Colombier int i, n, nwants; 985*d37e33ffSDavid du Colombier Buf *bp, *dbp; 986906943f9SDavid du Colombier Ether *e = a; 987906943f9SDavid du Colombier 988906943f9SDavid du Colombier while(e->exiting == 0){ 989906943f9SDavid du Colombier bp = nbrecvp(e->rc); 990906943f9SDavid du Colombier if(bp == nil){ 991*d37e33ffSDavid du Colombier bp = allocbuf(e); /* leak() may think we leak */ 992906943f9SDavid du Colombier if(e->bread(e, bp) < 0){ 993906943f9SDavid du Colombier freebuf(e, bp); 994906943f9SDavid du Colombier break; 995906943f9SDavid du Colombier } 996906943f9SDavid du Colombier if(bp->ndata == 0){ 997906943f9SDavid du Colombier /* may be a short packet; continue */ 998906943f9SDavid du Colombier if(0)dprint(2, "%s: read: short\n", argv0); 999906943f9SDavid du Colombier freebuf(e, bp); 1000906943f9SDavid du Colombier continue; 1001*d37e33ffSDavid du Colombier }else 1002*d37e33ffSDavid du Colombier setbuftype(bp); 1003906943f9SDavid du Colombier } 1004906943f9SDavid du Colombier e->nin++; 1005906943f9SDavid du Colombier nwants = 0; 1006906943f9SDavid du Colombier for(i = 0; i < e->nconns; i++) 1007906943f9SDavid du Colombier nwants += cwantsbp(e->conns[i], bp); 1008906943f9SDavid du Colombier for(i = 0; nwants > 0 && i < e->nconns; i++) 1009906943f9SDavid du Colombier if(cwantsbp(e->conns[i], bp)){ 1010906943f9SDavid du Colombier n = bp->ndata; 1011906943f9SDavid du Colombier if(e->conns[i]->type == -2 && n > 64) 1012906943f9SDavid du Colombier n = 64; 1013906943f9SDavid du Colombier if(nwants-- == 1){ 1014906943f9SDavid du Colombier bp->ndata = n; 1015906943f9SDavid du Colombier dbp = bp; 1016906943f9SDavid du Colombier bp = nil; 1017906943f9SDavid du Colombier }else{ 1018906943f9SDavid du Colombier dbp = allocbuf(e); 1019906943f9SDavid du Colombier memmove(dbp->rp, bp->rp, n); 1020906943f9SDavid du Colombier dbp->ndata = n; 1021*d37e33ffSDavid du Colombier dbp->type = bp->type; 1022906943f9SDavid du Colombier } 1023906943f9SDavid du Colombier if(nbsendp(e->conns[i]->rc, dbp) < 0){ 1024906943f9SDavid du Colombier e->nierrs++; 1025906943f9SDavid du Colombier freebuf(e, dbp); 1026906943f9SDavid du Colombier } 1027906943f9SDavid du Colombier } 1028906943f9SDavid du Colombier freebuf(e, bp); 1029906943f9SDavid du Colombier } 1030906943f9SDavid du Colombier deprint(2, "%s: writeproc exiting\n", argv0); 1031*d37e33ffSDavid du Colombier etherexiting(e); 1032*d37e33ffSDavid du Colombier closedev(e->dev); 1033906943f9SDavid du Colombier } 1034906943f9SDavid du Colombier 1035906943f9SDavid du Colombier static void 1036906943f9SDavid du Colombier setalt(Dev *d, int ifcid, int altid) 1037906943f9SDavid du Colombier { 1038*d37e33ffSDavid du Colombier if(usbcmd(d, Rh2d|Rstd|Riface, Rsetiface, altid, ifcid, nil, 0) < 0) 1039906943f9SDavid du Colombier dprint(2, "%s: setalt ifc %d alt %d: %r\n", argv0, ifcid, altid); 1040906943f9SDavid du Colombier } 1041906943f9SDavid du Colombier 1042906943f9SDavid du Colombier static int 1043906943f9SDavid du Colombier ifaceinit(Ether *e, Iface *ifc, int *ei, int *eo) 1044906943f9SDavid du Colombier { 1045906943f9SDavid du Colombier Ep *ep; 1046*d37e33ffSDavid du Colombier int epin, epout, i; 1047906943f9SDavid du Colombier 1048906943f9SDavid du Colombier if(ifc == nil) 1049906943f9SDavid du Colombier return -1; 1050906943f9SDavid du Colombier 1051*d37e33ffSDavid du Colombier epin = epout = -1; 1052906943f9SDavid du Colombier for(i = 0; (epin < 0 || epout < 0) && i < nelem(ifc->ep); i++) 1053906943f9SDavid du Colombier if((ep = ifc->ep[i]) != nil && ep->type == Ebulk){ 1054906943f9SDavid du Colombier if(ep->dir == Eboth || ep->dir == Ein) 1055906943f9SDavid du Colombier if(epin == -1) 1056906943f9SDavid du Colombier epin = ep->id; 1057906943f9SDavid du Colombier if(ep->dir == Eboth || ep->dir == Eout) 1058906943f9SDavid du Colombier if(epout == -1) 1059906943f9SDavid du Colombier epout = ep->id; 1060906943f9SDavid du Colombier } 1061906943f9SDavid du Colombier if(epin == -1 || epout == -1) 1062906943f9SDavid du Colombier return -1; 1063*d37e33ffSDavid du Colombier 1064906943f9SDavid du Colombier dprint(2, "ether: ep ids: in %d out %d\n", epin, epout); 1065906943f9SDavid du Colombier for(i = 0; i < nelem(ifc->altc); i++) 1066*d37e33ffSDavid du Colombier if(ifc->altc[i] != nil) 1067*d37e33ffSDavid du Colombier setalt(e->dev, ifc->id, i); 1068906943f9SDavid du Colombier 1069906943f9SDavid du Colombier *ei = epin; 1070906943f9SDavid du Colombier *eo = epout; 1071906943f9SDavid du Colombier return 0; 1072906943f9SDavid du Colombier } 1073906943f9SDavid du Colombier 1074906943f9SDavid du Colombier static int 1075906943f9SDavid du Colombier etherinit(Ether *e, int *ei, int *eo) 1076906943f9SDavid du Colombier { 1077*d37e33ffSDavid du Colombier int ctlid, datid, i, j; 1078906943f9SDavid du Colombier Conf *c; 1079*d37e33ffSDavid du Colombier Desc *desc; 1080*d37e33ffSDavid du Colombier Iface *ctlif, *datif; 1081*d37e33ffSDavid du Colombier Usbdev *ud; 1082906943f9SDavid du Colombier 1083906943f9SDavid du Colombier *ei = *eo = -1; 1084906943f9SDavid du Colombier ud = e->dev->usb; 1085*d37e33ffSDavid du Colombier 1086*d37e33ffSDavid du Colombier /* look for union descriptor with ethernet ctrl interface */ 1087*d37e33ffSDavid du Colombier for(i = 0; i < nelem(ud->ddesc); i++){ 1088*d37e33ffSDavid du Colombier if((desc = ud->ddesc[i]) == nil) 1089*d37e33ffSDavid du Colombier continue; 1090*d37e33ffSDavid du Colombier if(desc->data.bLength < 5 || desc->data.bbytes[0] != Cdcunion) 1091*d37e33ffSDavid du Colombier continue; 1092*d37e33ffSDavid du Colombier 1093*d37e33ffSDavid du Colombier ctlid = desc->data.bbytes[1]; 1094*d37e33ffSDavid du Colombier datid = desc->data.bbytes[2]; 1095*d37e33ffSDavid du Colombier 1096*d37e33ffSDavid du Colombier if((c = desc->conf) == nil) 1097*d37e33ffSDavid du Colombier continue; 1098*d37e33ffSDavid du Colombier 1099*d37e33ffSDavid du Colombier ctlif = datif = nil; 1100*d37e33ffSDavid du Colombier for(j = 0; j < nelem(c->iface); j++){ 1101*d37e33ffSDavid du Colombier if(c->iface[j] == nil) 1102*d37e33ffSDavid du Colombier continue; 1103*d37e33ffSDavid du Colombier if(c->iface[j]->id == ctlid) 1104*d37e33ffSDavid du Colombier ctlif = c->iface[j]; 1105*d37e33ffSDavid du Colombier if(c->iface[j]->id == datid) 1106*d37e33ffSDavid du Colombier datif = c->iface[j]; 1107*d37e33ffSDavid du Colombier 1108*d37e33ffSDavid du Colombier if(datif != nil && ctlif != nil){ 1109*d37e33ffSDavid du Colombier if(Subclass(ctlif->csp) == Scether && 1110*d37e33ffSDavid du Colombier ifaceinit(e, datif, ei, eo) != -1) 1111*d37e33ffSDavid du Colombier return 0; 1112*d37e33ffSDavid du Colombier break; 1113*d37e33ffSDavid du Colombier } 1114*d37e33ffSDavid du Colombier } 1115*d37e33ffSDavid du Colombier } 1116*d37e33ffSDavid du Colombier /* try any other one that seems to be ok */ 1117906943f9SDavid du Colombier for(i = 0; i < nelem(ud->conf); i++) 1118906943f9SDavid du Colombier if((c = ud->conf[i]) != nil) 1119906943f9SDavid du Colombier for(j = 0; j < nelem(c->iface); j++) 1120906943f9SDavid du Colombier if(ifaceinit(e, c->iface[j], ei, eo) != -1) 1121906943f9SDavid du Colombier return 0; 1122906943f9SDavid du Colombier dprint(2, "%s: no valid endpoints", argv0); 1123906943f9SDavid du Colombier return -1; 1124906943f9SDavid du Colombier } 1125906943f9SDavid du Colombier 1126906943f9SDavid du Colombier int 1127906943f9SDavid du Colombier ethermain(Dev *dev, int argc, char **argv) 1128906943f9SDavid du Colombier { 1129*d37e33ffSDavid du Colombier int epin, epout, i; 1130906943f9SDavid du Colombier Ether *e; 1131906943f9SDavid du Colombier 1132906943f9SDavid du Colombier ARGBEGIN{ 1133906943f9SDavid du Colombier case 'd': 1134906943f9SDavid du Colombier if(etherdebug == 0) 1135906943f9SDavid du Colombier fprint(2, "ether debug on\n"); 1136906943f9SDavid du Colombier etherdebug++; 1137906943f9SDavid du Colombier break; 1138906943f9SDavid du Colombier default: 1139906943f9SDavid du Colombier return usage(); 1140906943f9SDavid du Colombier }ARGEND 1141906943f9SDavid du Colombier if(argc != 0) 1142906943f9SDavid du Colombier return usage(); 1143906943f9SDavid du Colombier 1144906943f9SDavid du Colombier e = dev->aux = emallocz(sizeof(Ether), 1); 1145906943f9SDavid du Colombier e->dev = dev; 1146906943f9SDavid du Colombier dev->free = etherdevfree; 1147906943f9SDavid du Colombier 1148906943f9SDavid du Colombier for(i = 0; i < nelem(ethers); i++) 1149906943f9SDavid du Colombier if(ethers[i](e) == 0) 1150906943f9SDavid du Colombier break; 1151906943f9SDavid du Colombier if(i == nelem(ethers)) 1152906943f9SDavid du Colombier return -1; 1153906943f9SDavid du Colombier if(e->init == nil) 1154906943f9SDavid du Colombier e->init = etherinit; 1155906943f9SDavid du Colombier if(e->init(e, &epin, &epout) < 0) 1156906943f9SDavid du Colombier return -1; 1157906943f9SDavid du Colombier if(e->bwrite == nil) 1158906943f9SDavid du Colombier e->bwrite = etherbwrite; 1159906943f9SDavid du Colombier if(e->bread == nil) 1160906943f9SDavid du Colombier e->bread = etherbread; 1161906943f9SDavid du Colombier 1162906943f9SDavid du Colombier if(openeps(e, epin, epout) < 0) 1163906943f9SDavid du Colombier return -1; 1164906943f9SDavid du Colombier e->fs = etherfs; 1165906943f9SDavid du Colombier snprint(e->fs.name, sizeof(e->fs.name), "etherU%d", dev->id); 1166906943f9SDavid du Colombier e->fs.dev = dev; 1167906943f9SDavid du Colombier e->fs.aux = e; 1168906943f9SDavid du Colombier e->bc = chancreate(sizeof(Buf*), Nconns); 1169906943f9SDavid du Colombier e->rc = chancreate(sizeof(Buf*), Nconns/2); 1170906943f9SDavid du Colombier e->wc = chancreate(sizeof(Buf*), Nconns*2); 1171*d37e33ffSDavid du Colombier incref(e->dev); 1172906943f9SDavid du Colombier proccreate(etherwriteproc, e, 16*1024); 1173*d37e33ffSDavid du Colombier incref(e->dev); 1174906943f9SDavid du Colombier proccreate(etherreadproc, e, 16*1024); 1175906943f9SDavid du Colombier deprint(2, "%s: dev ref %ld\n", argv0, dev->ref); 1176906943f9SDavid du Colombier usbfsadd(&e->fs); 1177906943f9SDavid du Colombier return 0; 1178906943f9SDavid du Colombier } 1179