1 /* 2 * Kernel proxy for usb ethernet device 3 */ 4 5 #include "u.h" 6 #include "../port/lib.h" 7 #include "mem.h" 8 #include "dat.h" 9 #include "fns.h" 10 #include "io.h" 11 #include "../port/error.h" 12 #include "../port/netif.h" 13 14 #include "etherif.h" 15 #include "../ip/ip.h" 16 17 #define GET4(p) ((p)[3]<<24 | (p)[2]<<16 | (p)[1]<<8 | (p)[0]) 18 #define PUT4(p, v) ((p)[0] = (v), (p)[1] = (v)>>8, \ 19 (p)[2] = (v)>>16, (p)[3] = (v)>>24) 20 #define dprint if(debug) print 21 #define ddump if(0) dump 22 23 static int debug = 0; 24 25 enum { 26 Bind = 0, 27 Unbind, 28 29 SmscRxerror = 0x8000, 30 SmscTxfirst = 0x2000, 31 SmscTxlast = 0x1000, 32 }; 33 34 typedef struct Ctlr Ctlr; 35 typedef struct Udev Udev; 36 37 typedef int (Unpackfn)(Ether*, Block*); 38 typedef void (Transmitfn)(Ctlr*, Block*); 39 40 struct Ctlr { 41 Ether* edev; 42 Udev* udev; 43 Chan* inchan; 44 Chan* outchan; 45 char* buf; 46 int bufsize; 47 int maxpkt; 48 uint rxbuf; 49 uint rxpkt; 50 uint txbuf; 51 uint txpkt; 52 QLock; 53 }; 54 55 struct Udev { 56 char *name; 57 Unpackfn *unpack; 58 Transmitfn *transmit; 59 }; 60 61 static Cmdtab cmds[] = { 62 { Bind, "bind", 7, }, 63 { Unbind, "unbind", 0, }, 64 }; 65 66 static Unpackfn unpackcdc, unpackasix, unpacksmsc; 67 static Transmitfn transmitcdc, transmitasix, transmitsmsc; 68 69 static Udev udevtab[] = { 70 { "cdc", unpackcdc, transmitcdc, }, 71 { "asix", unpackasix, transmitasix, }, 72 { "smsc", unpacksmsc, transmitsmsc, }, 73 { nil }, 74 }; 75 76 static void 77 dump(int c, Block *b) 78 { 79 int s, i; 80 81 s = splhi(); 82 print("%c%ld:", c, BLEN(b)); 83 for(i = 0; i < 32; i++) 84 print(" %2.2ux", b->rp[i]); 85 print("\n"); 86 splx(s); 87 } 88 89 static int 90 unpack(Ether *edev, Block *b, int m) 91 { 92 Block *nb; 93 Ctlr *ctlr; 94 95 ctlr = edev->ctlr; 96 ddump('?', b); 97 if(m == BLEN(b)){ 98 etheriq(edev, b, 1); 99 ctlr->rxpkt++; 100 return 1; 101 } 102 nb = iallocb(m); 103 if(nb != nil){ 104 memmove(nb->wp, b->rp, m); 105 nb->wp += m; 106 etheriq(edev, nb, 1); 107 ctlr->rxpkt++; 108 }else 109 edev->soverflows++; 110 b->rp += m; 111 return 0; 112 } 113 114 static int 115 unpackcdc(Ether *edev, Block *b) 116 { 117 int m; 118 119 m = BLEN(b); 120 if(m < 6) 121 return -1; 122 return unpack(edev, b, m); 123 } 124 125 static int 126 unpackasix(Ether *edev, Block *b) 127 { 128 ulong hd; 129 int m; 130 uchar *wp; 131 132 if(BLEN(b) < 4) 133 return -1; 134 hd = GET4(b->rp); 135 b->rp += 4; 136 m = hd & 0xFFFF; 137 hd >>= 16; 138 if(m != (~hd & 0xFFFF)) 139 return -1; 140 m = ROUND(m, 2); 141 if(m < 6 || m > BLEN(b)) 142 return -1; 143 if((wp = b->rp + m) != b->wp && b->wp - wp < 4) 144 b->wp = wp; 145 return unpack(edev, b, m); 146 } 147 148 static int 149 unpacksmsc(Ether *edev, Block *b) 150 { 151 ulong hd; 152 int m; 153 154 ddump('@', b); 155 if(BLEN(b) < 4) 156 return -1; 157 hd = GET4(b->rp); 158 b->rp += 4; 159 m = hd >> 16; 160 if(m < 6 || m > BLEN(b)) 161 return -1; 162 if(BLEN(b) - m < 4) 163 b->wp = b->rp + m; 164 if(hd & SmscRxerror){ 165 edev->frames++; 166 b->rp += m; 167 if(BLEN(b) == 0){ 168 freeb(b); 169 return 1; 170 } 171 }else if(unpack(edev, b, m) == 1) 172 return 1; 173 if((m &= 3) != 0) 174 b->rp += 4 - m; 175 return 0; 176 } 177 178 static void 179 transmit(Ctlr *ctlr, Block *b) 180 { 181 Chan *c; 182 183 ddump('!', b); 184 c = ctlr->outchan; 185 devtab[c->type]->bwrite(c, b, 0); 186 } 187 188 static void 189 transmitcdc(Ctlr *ctlr, Block *b) 190 { 191 transmit(ctlr, b); 192 } 193 194 static void 195 transmitasix(Ctlr *ctlr, Block *b) 196 { 197 int n; 198 199 n = BLEN(b) & 0xFFFF; 200 n |= ~n << 16; 201 padblock(b, 4); 202 PUT4(b->rp, n); 203 if(BLEN(b) % ctlr->maxpkt == 0){ 204 padblock(b, -4); 205 PUT4(b->wp, 0xFFFF0000); 206 b->wp += 4; 207 } 208 transmit(ctlr, b); 209 } 210 211 static void 212 transmitsmsc(Ctlr *ctlr, Block *b) 213 { 214 int n; 215 216 n = BLEN(b) & 0x7FF; 217 padblock(b, 8); 218 PUT4(b->rp, n | SmscTxfirst | SmscTxlast); 219 PUT4(b->rp+4, n); 220 transmit(ctlr, b); 221 } 222 223 static void 224 etherusbproc(void *a) 225 { 226 Ether *edev; 227 Ctlr *ctlr; 228 Chan *c; 229 Block *b; 230 231 edev = a; 232 ctlr = edev->ctlr; 233 c = ctlr->inchan; 234 b = nil; 235 if(waserror()){ 236 print("etherusbproc: error exit %s\n", up->errstr); 237 pexit(up->errstr, 1); 238 return; 239 } 240 for(;;){ 241 if(b == nil){ 242 b = devtab[c->type]->bread(c, ctlr->bufsize, 0); 243 ctlr->rxbuf++; 244 } 245 switch(ctlr->udev->unpack(edev, b)){ 246 case -1: 247 edev->buffs++; 248 freeb(b); 249 /* fall through */ 250 case 1: 251 b = nil; 252 break; 253 } 254 } 255 } 256 257 /* 258 * bind type indev outdev mac bufsize maxpkt 259 */ 260 static void 261 bind(Ctlr *ctlr, Udev *udev, Cmdbuf *cb) 262 { 263 Chan *inchan, *outchan; 264 char *buf; 265 uint bufsize, maxpkt; 266 267 qlock(ctlr); 268 inchan = outchan = nil; 269 buf = nil; 270 if(waserror()){ 271 free(buf); 272 if(inchan) 273 cclose(inchan); 274 if(outchan) 275 cclose(outchan); 276 qunlock(ctlr); 277 nexterror(); 278 } 279 if(ctlr->buf != nil) 280 cmderror(cb, "already bound to a device"); 281 maxpkt = strtol(cb->f[6], 0, 0); 282 if(maxpkt < 8 || maxpkt > 512) 283 cmderror(cb, "bad maxpkt"); 284 bufsize = strtol(cb->f[5], 0, 0); 285 if(bufsize < maxpkt || bufsize > 32*1024) 286 cmderror(cb, "bad bufsize"); 287 buf = smalloc(bufsize); 288 inchan = namec(cb->f[2], Aopen, OREAD, 0); 289 outchan = namec(cb->f[3], Aopen, OWRITE, 0); 290 assert(inchan != nil && outchan != nil); 291 if(parsemac(ctlr->edev->ea, cb->f[4], Eaddrlen) != Eaddrlen) 292 cmderror(cb, "bad etheraddr"); 293 memmove(ctlr->edev->addr, ctlr->edev->ea, Eaddrlen); 294 print("\netherusb %s: %E\n", udev->name, ctlr->edev->addr); 295 ctlr->buf = buf; 296 ctlr->inchan = inchan; 297 ctlr->outchan = outchan; 298 ctlr->bufsize = bufsize; 299 ctlr->maxpkt = maxpkt; 300 ctlr->udev = udev; 301 kproc("etherusb", etherusbproc, ctlr->edev); 302 poperror(); 303 qunlock(ctlr); 304 } 305 306 static void 307 unbind(Ctlr *ctlr) 308 { 309 qlock(ctlr); 310 if(ctlr->buf != nil){ 311 free(ctlr->buf); 312 ctlr->buf = nil; 313 if(ctlr->inchan) 314 cclose(ctlr->inchan); 315 if(ctlr->outchan) 316 cclose(ctlr->outchan); 317 ctlr->inchan = ctlr->outchan = nil; 318 } 319 qunlock(ctlr); 320 } 321 322 static long 323 etherusbifstat(Ether* edev, void* a, long n, ulong offset) 324 { 325 Ctlr *ctlr; 326 char *p; 327 int l; 328 329 ctlr = edev->ctlr; 330 p = malloc(READSTR); 331 l = 0; 332 333 l += snprint(p+l, READSTR-l, "rxbuf: %ud\n", ctlr->rxbuf); 334 l += snprint(p+l, READSTR-l, "rxpkt: %ud\n", ctlr->rxpkt); 335 l += snprint(p+l, READSTR-l, "txbuf: %ud\n", ctlr->txbuf); 336 l += snprint(p+l, READSTR-l, "txpkt: %ud\n", ctlr->txpkt); 337 USED(l); 338 339 n = readstr(offset, a, n, p); 340 free(p); 341 return n; 342 } 343 344 static void 345 etherusbtransmit(Ether *edev) 346 { 347 Ctlr *ctlr; 348 Block *b; 349 350 ctlr = edev->ctlr; 351 while((b = qget(edev->oq)) != nil){ 352 ctlr->txpkt++; 353 if(ctlr->buf == nil) 354 freeb(b); 355 else{ 356 ctlr->udev->transmit(ctlr, b); 357 ctlr->txbuf++; 358 } 359 } 360 } 361 362 static long 363 etherusbctl(Ether* edev, void* buf, long n) 364 { 365 Ctlr *ctlr; 366 Cmdbuf *cb; 367 Cmdtab *ct; 368 Udev *udev; 369 370 if((ctlr = edev->ctlr) == nil) 371 error(Enonexist); 372 373 cb = parsecmd(buf, n); 374 if(waserror()){ 375 free(cb); 376 nexterror(); 377 } 378 ct = lookupcmd(cb, cmds, nelem(cmds)); 379 switch(ct->index){ 380 case Bind: 381 for(udev = udevtab; udev->name; udev++) 382 if(strcmp(cb->f[1], udev->name) == 0) 383 break; 384 if(udev->name == nil) 385 cmderror(cb, "unknown etherusb type"); 386 bind(ctlr, udev, cb); 387 break; 388 case Unbind: 389 unbind(ctlr); 390 break; 391 default: 392 cmderror(cb, "unknown etherusb control message"); 393 } 394 poperror(); 395 free(cb); 396 return n; 397 } 398 399 static void 400 etherusbattach(Ether* edev) 401 { 402 Ctlr *ctlr; 403 404 ctlr = edev->ctlr; 405 ctlr->edev = edev; 406 } 407 408 static int 409 etherusbpnp(Ether* edev) 410 { 411 Ctlr *ctlr; 412 413 ctlr = malloc(sizeof(Ctlr)); 414 edev->ctlr = ctlr; 415 edev->irq = -1; 416 edev->mbps = 100; /* TODO: get this from usbether */ 417 418 /* 419 * Linkage to the generic ethernet driver. 420 */ 421 edev->attach = etherusbattach; 422 edev->transmit = etherusbtransmit; 423 edev->interrupt = nil; 424 edev->ifstat = etherusbifstat; 425 edev->ctl = etherusbctl; 426 427 edev->arg = edev; 428 /* TODO: promiscuous, multicast (for ipv6), shutdown (for reboot) */ 429 // edev->promiscuous = etherusbpromiscuous; 430 // edev->shutdown = etherusbshutdown; 431 // edev->multicast = etherusbmulticast; 432 433 return 0; 434 } 435 436 void 437 etherusblink(void) 438 { 439 addethercard("usb", etherusbpnp); 440 } 441