|
|
1.1 ! root 1: #include "u.h" ! 2: #include "../port/lib.h" ! 3: #include "mem.h" ! 4: #include "dat.h" ! 5: #include "fns.h" ! 6: #include "../port/error.h" ! 7: #include "io.h" ! 8: #include "devtab.h" ! 9: ! 10: #include "ether.h" ! 11: ! 12: /* ! 13: * Half-arsed attempt at a general top-level ! 14: * ethernet driver. Needs work: ! 15: * handle multiple controllers ! 16: * much tidying ! 17: * set ethernet address ! 18: * need a ctl file passed down to card drivers ! 19: * so we can set options. ! 20: */ ! 21: ! 22: struct Ctlr *softctlr; ! 23: ! 24: Chan* ! 25: etherclone(Chan *c, Chan *nc) ! 26: { ! 27: return devclone(c, nc); ! 28: } ! 29: ! 30: int ! 31: etherwalk(Chan *c, char *name) ! 32: { ! 33: return netwalk(c, name, &softctlr->net); ! 34: } ! 35: ! 36: void ! 37: etherstat(Chan *c, char *dp) ! 38: { ! 39: netstat(c, dp, &softctlr->net); ! 40: } ! 41: ! 42: Chan* ! 43: etheropen(Chan *c, int omode) ! 44: { ! 45: return netopen(c, omode, &softctlr->net); ! 46: } ! 47: ! 48: void ! 49: ethercreate(Chan *c, char *name, int omode, ulong perm) ! 50: { ! 51: USED(c, name, omode, perm); ! 52: error(Eperm); ! 53: } ! 54: ! 55: void ! 56: etherclose(Chan *c) ! 57: { ! 58: if(c->stream) ! 59: streamclose(c); ! 60: } ! 61: ! 62: long ! 63: etherread(Chan *c, void *a, long n, ulong offset) ! 64: { ! 65: return netread(c, a, n, offset, &softctlr->net); ! 66: } ! 67: ! 68: long ! 69: etherwrite(Chan *c, char *a, long n, ulong offset) ! 70: { ! 71: USED(offset); ! 72: return streamwrite(c, a, n, 0); ! 73: } ! 74: ! 75: void ! 76: etherremove(Chan *c) ! 77: { ! 78: USED(c); ! 79: error(Eperm); ! 80: } ! 81: ! 82: void ! 83: etherwstat(Chan *c, char *dp) ! 84: { ! 85: netwstat(c, dp, &softctlr->net); ! 86: } ! 87: ! 88: static int ! 89: isobuf(void *arg) ! 90: { ! 91: Ctlr *ctlr = arg; ! 92: ! 93: return ctlr->tb[ctlr->th].owner == Host; ! 94: } ! 95: ! 96: static void ! 97: etheroput(Queue *q, Block *bp) ! 98: { ! 99: Ctlr *ctlr; ! 100: Type *type; ! 101: Etherpkt *pkt; ! 102: RingBuf *ring; ! 103: int len, n, s; ! 104: Block *nbp; ! 105: uchar ea[6]; ! 106: char *err; ! 107: ! 108: type = q->ptr; ! 109: ctlr = type->ctlr; ! 110: if(bp->type == M_CTL){ ! 111: err = 0; ! 112: qlock(ctlr); ! 113: if(streamparse("connect", bp)){ ! 114: if(type->type == -1) ! 115: ctlr->all--; ! 116: type->type = strtol((char*)bp->rptr, 0, 0); ! 117: if(type->type == -1) ! 118: ctlr->all++; ! 119: } ! 120: else if(streamparse("promiscuous", bp)) { ! 121: if(type->prom) ! 122: goto ctlout; ! 123: if(type->filter){ ! 124: err = "address already set"; ! 125: goto ctlout; ! 126: } ! 127: type->prom = 1; ! 128: ctlr->prom++; ! 129: if(ctlr->prom+ctlr->filter == 1) ! 130: (*ctlr->card.mode)(ctlr, 1); ! 131: } ! 132: else if(streamparse("address", bp)) { ! 133: if(type->prom){ ! 134: err = "already promiscuous"; ! 135: goto ctlout; ! 136: } ! 137: if(parseether(ea, bp->rptr) < 0){ ! 138: err = "bad ether address"; ! 139: goto ctlout; ! 140: } ! 141: memmove(type->ea, ea, sizeof(ea)); ! 142: if(!type->filter){ ! 143: type->filter = 1; ! 144: ctlr->filter++; ! 145: if(ctlr->filter == 1) ! 146: (*ctlr->card.mode)(ctlr, 3); ! 147: } ! 148: } ! 149: ctlout: ! 150: qunlock(ctlr); ! 151: freeb(bp); ! 152: if(err) ! 153: error(err); ! 154: return; ! 155: } ! 156: ! 157: /* ! 158: * Give packet a local address, return upstream if destined for ! 159: * this machine. ! 160: */ ! 161: if(BLEN(bp) < ETHERHDRSIZE && (bp = pullup(bp, ETHERHDRSIZE)) == 0) ! 162: return; ! 163: pkt = (Etherpkt*)bp->rptr; ! 164: memmove(pkt->s, type->ea, sizeof(type->ea)); ! 165: if(memcmp(ctlr->ea, pkt->d, sizeof(ctlr->ea)) == 0){ ! 166: len = blen(bp); ! 167: if(bp = expandb(bp, len >= ETHERMINTU ? len: ETHERMINTU)){ ! 168: putq(&ctlr->lbq, bp); ! 169: wakeup(&ctlr->rr); ! 170: } ! 171: return; ! 172: } ! 173: if(memcmp(ctlr->ba, pkt->d, sizeof(ctlr->ba)) == 0 || ctlr->prom || ctlr->all){ ! 174: len = blen(bp); ! 175: nbp = copyb(bp, len); ! 176: if(nbp = expandb(nbp, len >= ETHERMINTU ? len: ETHERMINTU)){ ! 177: nbp->wptr = nbp->rptr+len; ! 178: putq(&ctlr->lbq, nbp); ! 179: wakeup(&ctlr->rr); ! 180: } ! 181: } ! 182: ! 183: /* ! 184: * Only one transmitter at a time. ! 185: */ ! 186: qlock(&ctlr->tlock); ! 187: if(waserror()){ ! 188: qunlock(&ctlr->tlock); ! 189: freeb(bp); ! 190: nexterror(); ! 191: } ! 192: ! 193: /* ! 194: * Wait till we get an output buffer. ! 195: * should try to restart. ! 196: */ ! 197: if(isobuf(ctlr) == 0){ ! 198: tsleep(&ctlr->tr, isobuf, ctlr, 3*1000); ! 199: if(isobuf(ctlr) == 0){ ! 200: qunlock(&ctlr->tlock); ! 201: freeb(bp); ! 202: poperror(); ! 203: return; ! 204: } ! 205: } ! 206: ! 207: ring = &ctlr->tb[ctlr->th]; ! 208: ! 209: /* ! 210: * Copy message into buffer. ! 211: */ ! 212: len = 0; ! 213: for(nbp = bp; nbp; nbp = nbp->next){ ! 214: if(sizeof(Etherpkt) - len >= (n = BLEN(nbp))){ ! 215: memmove(ring->pkt+len, nbp->rptr, n); ! 216: len += n; ! 217: } ! 218: if(bp->flags & S_DELIM) ! 219: break; ! 220: } ! 221: ! 222: /* ! 223: * Pad the packet (zero the pad). ! 224: */ ! 225: if(len < ETHERMINTU){ ! 226: memset(ring->pkt+len, 0, ETHERMINTU-len); ! 227: len = ETHERMINTU; ! 228: } ! 229: ! 230: /* ! 231: * Set up the transmit buffer and ! 232: * start the transmission. ! 233: */ ! 234: s = splhi(); ! 235: ring->len = len; ! 236: ring->owner = Interface; ! 237: ctlr->th = NEXT(ctlr->th, ctlr->ntb); ! 238: (*ctlr->card.transmit)(ctlr); ! 239: ctlr->outpackets++; ! 240: splx(s); ! 241: ! 242: qunlock(&ctlr->tlock); ! 243: freeb(bp); ! 244: poperror(); ! 245: } ! 246: ! 247: /* ! 248: * Open an ether line discipline. ! 249: */ ! 250: static void ! 251: etherstopen(Queue *q, Stream *s) ! 252: { ! 253: Ctlr *ctlr = softctlr; ! 254: Type *type; ! 255: ! 256: type = &ctlr->type[s->id]; ! 257: RD(q)->ptr = WR(q)->ptr = type; ! 258: type->type = 0; ! 259: type->q = RD(q); ! 260: type->inuse = 1; ! 261: memmove(type->ea, ctlr->ea, sizeof(type->ea)); ! 262: type->ctlr = ctlr; ! 263: } ! 264: ! 265: /* ! 266: * Close ether line discipline. ! 267: * ! 268: * The locking is to synchronize changing the ethertype with ! 269: * sending packets up the stream on interrupts. ! 270: */ ! 271: static int ! 272: isclosed(void *arg) ! 273: { ! 274: return ((Type*)arg)->q == 0; ! 275: } ! 276: ! 277: static void ! 278: etherstclose(Queue *q) ! 279: { ! 280: Type *type = (Type*)(q->ptr); ! 281: Ctlr *ctlr = type->ctlr; ! 282: ! 283: if(type->prom){ ! 284: qlock(ctlr); ! 285: ctlr->prom--; ! 286: if(ctlr->prom+ctlr->filter == 0) ! 287: (*ctlr->card.mode)(ctlr, 0); ! 288: qunlock(ctlr); ! 289: } ! 290: if(type->filter){ ! 291: qlock(ctlr); ! 292: ctlr->filter--; ! 293: if(ctlr->filter == 0) ! 294: (*ctlr->card.mode)(ctlr, ctlr->prom ? 1 : 0); ! 295: qunlock(ctlr); ! 296: } ! 297: if(type->type == -1){ ! 298: qlock(ctlr); ! 299: ctlr->all--; ! 300: qunlock(ctlr); ! 301: } ! 302: ! 303: /* ! 304: * Mark as closing and wait for kproc ! 305: * to close us. ! 306: */ ! 307: lock(&ctlr->clock); ! 308: type->clist = ctlr->clist; ! 309: ctlr->clist = type; ! 310: unlock(&ctlr->clock); ! 311: wakeup(&ctlr->rr); ! 312: sleep(&type->cr, isclosed, type); ! 313: ! 314: type->type = 0; ! 315: type->prom = 0; ! 316: type->filter = 0; ! 317: type->inuse = 0; ! 318: netdisown(type); ! 319: type->ctlr = 0; ! 320: } ! 321: ! 322: static Qinfo info = { ! 323: nullput, ! 324: etheroput, ! 325: etherstopen, ! 326: etherstclose, ! 327: "ether" ! 328: }; ! 329: ! 330: static int ! 331: clonecon(Chan *c) ! 332: { ! 333: Ctlr *ctlr = softctlr; ! 334: Type *type; ! 335: ! 336: USED(c); ! 337: for(type = ctlr->type; type < &ctlr->type[NType]; type++){ ! 338: qlock(type); ! 339: if(type->inuse || type->q){ ! 340: qunlock(type); ! 341: continue; ! 342: } ! 343: type->inuse = 1; ! 344: memmove(type->ea, ctlr->ea, sizeof(type->ea)); ! 345: netown(type, u->p->user, 0); ! 346: qunlock(type); ! 347: return type - ctlr->type; ! 348: } ! 349: exhausted("ether channels"); ! 350: return 0; ! 351: } ! 352: ! 353: static void ! 354: statsfill(Chan *c, char *p, int n) ! 355: { ! 356: Ctlr *ctlr = softctlr; ! 357: char buf[256]; ! 358: ! 359: USED(c); ! 360: sprint(buf, "in: %d\nout: %d\ncrc errs %d\noverflows: %d\nframe errs %d\nbuff errs: %d\noerrs %d\naddr: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x\n", ! 361: ctlr->inpackets, ctlr->outpackets, ctlr->crcs, ! 362: ctlr->overflows, ctlr->frames, ctlr->buffs, ctlr->oerrs, ! 363: ctlr->ea[0], ctlr->ea[1], ctlr->ea[2], ! 364: ctlr->ea[3], ctlr->ea[4], ctlr->ea[5]); ! 365: strncpy(p, buf, n); ! 366: } ! 367: ! 368: static void ! 369: typefill(Chan *c, char *p, int n) ! 370: { ! 371: char buf[16]; ! 372: Type *type; ! 373: ! 374: type = &softctlr->type[STREAMID(c->qid.path)]; ! 375: sprint(buf, "%d", type->type); ! 376: strncpy(p, buf, n); ! 377: } ! 378: ! 379: int ! 380: eaddrmatch(Ctlr *ctlr, uchar *ea) ! 381: { ! 382: Type *type; ! 383: ! 384: for(type = &ctlr->type[0]; type < &ctlr->type[NType]; type++){ ! 385: if(type->q == 0 || ea[0] != type->ea[0]) ! 386: continue; ! 387: if(memcmp(ea, type->ea, sizeof(type->ea)) == 0) ! 388: return 1; ! 389: } ! 390: return 0; ! 391: } ! 392: ! 393: static void ! 394: etherup(Ctlr *ctlr, Etherpkt *pkt, int len) ! 395: { ! 396: int t; ! 397: Type *type; ! 398: Block *bp; ! 399: ! 400: t = (pkt->type[0]<<8)|pkt->type[1]; ! 401: for(type = &ctlr->type[0]; type < &ctlr->type[NType]; type++){ ! 402: ! 403: /* ! 404: * Check for open, the right type, and flow control. ! 405: */ ! 406: if(type->q == 0) ! 407: continue; ! 408: if(t != type->type && type->type >= 0) ! 409: continue; ! 410: if(type->q->next->len > Streamhi) ! 411: continue; ! 412: ! 413: /* ! 414: * Only a trace channel gets packets destined for other machines. ! 415: */ ! 416: if(type->type != -1 && pkt->d[0] != 0xFF ! 417: && (*pkt->d != *type->ea || memcmp(pkt->d, type->ea, sizeof(pkt->d)))) ! 418: continue; ! 419: ! 420: if(waserror() == 0){ ! 421: bp = allocb(len); ! 422: memmove(bp->rptr, pkt, len); ! 423: bp->wptr += len; ! 424: bp->flags |= S_DELIM; ! 425: PUTNEXT(type->q, bp); ! 426: poperror(); ! 427: } ! 428: } ! 429: } ! 430: ! 431: static int ! 432: isinput(void *arg) ! 433: { ! 434: Ctlr *ctlr = arg; ! 435: ! 436: return ctlr->lbq.first || ctlr->rb[ctlr->rh].owner == Host || ctlr->clist; ! 437: } ! 438: ! 439: static void ! 440: etherkproc(void *arg) ! 441: { ! 442: Ctlr *ctlr = arg; ! 443: RingBuf *ring; ! 444: Block *bp; ! 445: Type *type; ! 446: ! 447: if(waserror()){ ! 448: print("%s noted\n", ctlr->name); ! 449: /* fix ! 450: if(ctlr->card.reset) ! 451: (*ctlr->card.reset)(ctlr); ! 452: */ ! 453: ctlr->kproc = 0; ! 454: nexterror(); ! 455: } ! 456: ! 457: for(;;){ ! 458: tsleep(&ctlr->rr, isinput, ctlr, 500); ! 459: if(ctlr->card.watch) ! 460: (*ctlr->card.watch)(ctlr); ! 461: ! 462: /* ! 463: * Process any internal loopback packets. ! 464: */ ! 465: while(bp = getq(&ctlr->lbq)){ ! 466: ctlr->inpackets++; ! 467: etherup(ctlr, (Etherpkt*)bp->rptr, BLEN(bp)); ! 468: freeb(bp); ! 469: } ! 470: ! 471: /* ! 472: * Process any received packets. ! 473: */ ! 474: while(ctlr->rb[ctlr->rh].owner == Host){ ! 475: ctlr->inpackets++; ! 476: ring = &ctlr->rb[ctlr->rh]; ! 477: etherup(ctlr, (Etherpkt*)ring->pkt, ring->len); ! 478: ring->owner = Interface; ! 479: ctlr->rh = NEXT(ctlr->rh, ctlr->nrb); ! 480: } ! 481: ! 482: /* ! 483: * Close Types requesting it. ! 484: */ ! 485: if(ctlr->clist){ ! 486: lock(&ctlr->clock); ! 487: for(type = ctlr->clist; type; type = type->clist){ ! 488: type->q = 0; ! 489: wakeup(&type->cr); ! 490: } ! 491: ctlr->clist = 0; ! 492: unlock(&ctlr->clock); ! 493: } ! 494: } ! 495: } ! 496: ! 497: static void ! 498: etherintr(Ureg *ur, void *a) ! 499: { ! 500: Ctlr *ctlr = softctlr; ! 501: ! 502: USED(ur, a); ! 503: (*ctlr->card.intr)(ctlr); ! 504: } ! 505: ! 506: static void ! 507: reset(Ctlr *ctlr) ! 508: { ! 509: int i; ! 510: ! 511: if(ctlr->nrb == 0) ! 512: ctlr->nrb = Nrb; ! 513: ctlr->rb = xalloc(sizeof(RingBuf)*ctlr->nrb); ! 514: if(ctlr->ntb == 0) ! 515: ctlr->ntb = Ntb; ! 516: ctlr->tb = xalloc(sizeof(RingBuf)*ctlr->ntb); ! 517: ! 518: memset(ctlr->ba, 0xFF, sizeof(ctlr->ba)); ! 519: ! 520: ctlr->net.name = "ether"; ! 521: ctlr->net.nconv = NType; ! 522: ctlr->net.devp = &info; ! 523: ctlr->net.protop = 0; ! 524: ctlr->net.listen = 0; ! 525: ctlr->net.clone = clonecon; ! 526: ctlr->net.ninfo = 2; ! 527: ctlr->net.info[0].name = "stats"; ! 528: ctlr->net.info[0].fill = statsfill; ! 529: ctlr->net.info[1].name = "type"; ! 530: ctlr->net.info[1].fill = typefill; ! 531: for(i = 0; i < NType; i++) ! 532: netadd(&ctlr->net, &ctlr->type[i], i); ! 533: } ! 534: ! 535: extern int wd8003reset(Ctlr*); ! 536: extern int ne2000reset(Ctlr*); ! 537: extern int ccc509reset(Ctlr*); ! 538: extern int nsciareset(Ctlr*); ! 539: extern int ne2000PCMreset(Ctlr*); ! 540: ! 541: #define NCARD 32 ! 542: struct { ! 543: char *type; ! 544: int (*reset)(Ctlr*); ! 545: } cards[NCARD+1]; ! 546: ! 547: void ! 548: addethercard(char *t, int (*r)(Ctlr*)) ! 549: { ! 550: static int ncard; ! 551: ! 552: if(ncard == NCARD) ! 553: panic("too many ether cards"); ! 554: cards[ncard].type = t; ! 555: cards[ncard].reset = r; ! 556: ncard++; ! 557: } ! 558: ! 559: void ! 560: etherreset(void) ! 561: { ! 562: Ctlr *ctlr; ! 563: int i, n, ctlrno; ! 564: ! 565: if(softctlr == 0) ! 566: softctlr = xalloc(sizeof(Ctlr)); ! 567: else ! 568: memset(softctlr, 0, sizeof(Ctlr)); ! 569: ctlr = softctlr; ! 570: ! 571: for(ctlrno = i = 0; isaconfig("ether", i, &ctlr->card); i++){ ! 572: for(n = 0; cards[n].type; n++){ ! 573: if(strcmp(cards[n].type, ctlr->card.type)) ! 574: continue; ! 575: ctlr->ctlrno = ctlrno; ! 576: memmove(ctlr->ea, ctlr->card.ea, sizeof(ctlr->ea)); ! 577: if((*cards[n].reset)(ctlr)) ! 578: break; ! 579: ! 580: /*ctlrno++;*/ ! 581: ctlr->present = 1; ! 582: /* ! 583: * IRQ2 doesn't really exist, it's used to gang the interrupt ! 584: * controllers together. A device set to IRQ2 will appear on ! 585: * the second interrupt controller as IRQ9. ! 586: */ ! 587: if(ctlr->card.irq == 2) ! 588: ctlr->card.irq = 9; ! 589: setvec(Int0vec + ctlr->card.irq, etherintr, 0); ! 590: ! 591: print("ether%d:%s: port %lux irq %d addr %lux size %d width %d:", ! 592: ctlr->ctlrno, ctlr->card.type, ctlr->card.port, ctlr->card.irq, ! 593: ctlr->card.mem, ctlr->card.size, ctlr->card.bit16 ? 16: 8); ! 594: for(i = 0; i < sizeof(ctlr->ea); i++) ! 595: print("%2.2ux", ctlr->ea[i]); ! 596: print("\n"); ! 597: ! 598: reset(ctlr); ! 599: return; ! 600: } ! 601: memset(softctlr, 0, sizeof(Ctlr)); ! 602: } ! 603: } ! 604: ! 605: void ! 606: etherinit(void) ! 607: { ! 608: Ctlr *ctlr = softctlr; ! 609: int i; ! 610: ! 611: if(ctlr->present == 0) ! 612: return; ! 613: ! 614: ctlr->rh = 0; ! 615: ctlr->ri = 0; ! 616: for(i = 0; i < ctlr->nrb; i++) ! 617: ctlr->rb[i].owner = Interface; ! 618: ! 619: ctlr->th = 0; ! 620: ctlr->ti = 0; ! 621: for(i = 0; i < ctlr->ntb; i++) ! 622: ctlr->tb[i].owner = Host; ! 623: } ! 624: ! 625: Chan* ! 626: etherattach(char *spec) ! 627: { ! 628: Ctlr *ctlr = softctlr; ! 629: ! 630: if(ctlr->present == 0) ! 631: error(Enodev); ! 632: ! 633: /* ! 634: * Enable the interface ! 635: * and start the kproc. ! 636: */ ! 637: (*ctlr->card.attach)(ctlr); ! 638: if(ctlr->kproc == 0){ ! 639: sprint(ctlr->name, "ether%dkproc", 0); ! 640: ctlr->kproc = 1; ! 641: kproc(ctlr->name, etherkproc, ctlr); ! 642: } ! 643: return devattach('l', spec); ! 644: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.