|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: * ! 6: * @(#)if_ec.c 7.1 (Berkeley) 6/5/86 ! 7: */ ! 8: ! 9: #include "ec.h" ! 10: #include "enetfilter.h" ! 11: #if NEC > 0 ! 12: ! 13: /* ! 14: * 3Com Ethernet Controller interface ! 15: */ ! 16: #include "../machine/pte.h" ! 17: ! 18: #include "param.h" ! 19: #include "systm.h" ! 20: #include "mbuf.h" ! 21: #include "buf.h" ! 22: #include "protosw.h" ! 23: #include "socket.h" ! 24: #include "syslog.h" ! 25: #include "vmmac.h" ! 26: #include "ioctl.h" ! 27: #include "errno.h" ! 28: ! 29: #include "../net/if.h" ! 30: #include "../net/netisr.h" ! 31: #include "../net/route.h" ! 32: ! 33: #ifdef INET ! 34: #include "../netinet/in.h" ! 35: #include "../netinet/in_systm.h" ! 36: #include "../netinet/in_var.h" ! 37: #include "../netinet/ip.h" ! 38: #include "../netinet/if_ether.h" ! 39: #endif ! 40: ! 41: #ifdef NS ! 42: #include "../netns/ns.h" ! 43: #include "../netns/ns_if.h" ! 44: #endif ! 45: ! 46: #include "../vax/cpu.h" ! 47: #include "../vax/mtpr.h" ! 48: #include "if_ecreg.h" ! 49: #include "if_uba.h" ! 50: #if NENETFILTER > 0 ! 51: #include "../net/enet.h" ! 52: #endif NENETFILTER > 0 ! 53: #include "../vaxuba/ubareg.h" ! 54: #include "../vaxuba/ubavar.h" ! 55: ! 56: #if CLSIZE == 2 ! 57: #define ECBUFSIZE 32 /* on-board memory, clusters */ ! 58: #endif ! 59: ! 60: int ecubamem(), ecprobe(), ecattach(), ecrint(), ecxint(), eccollide(); ! 61: struct uba_device *ecinfo[NEC]; ! 62: u_short ecstd[] = { 0 }; ! 63: struct uba_driver ecdriver = ! 64: { ecprobe, 0, ecattach, 0, ecstd, "ec", ecinfo, 0, 0, 0, ecubamem }; ! 65: ! 66: int ecinit(),ecioctl(),ecoutput(),ecreset(); ! 67: struct mbuf *ecget(); ! 68: ! 69: extern struct ifnet loif; ! 70: ! 71: /* ! 72: * Ethernet software status per interface. ! 73: * ! 74: * Each interface is referenced by a network interface structure, ! 75: * es_if, which the routing code uses to locate the interface. ! 76: * This structure contains the output queue for the interface, its address, ... ! 77: * We also have, for each interface, a UBA interface structure, which ! 78: * contains information about the UNIBUS resources held by the interface: ! 79: * map registers, buffered data paths, etc. Information is cached in this ! 80: * structure for use by the if_uba.c routines in running the interface ! 81: * efficiently. ! 82: */ ! 83: struct ec_softc { ! 84: struct arpcom es_ac; /* common Ethernet structures */ ! 85: #define es_if es_ac.ac_if /* network-visible interface */ ! 86: #define es_addr es_ac.ac_enaddr /* hardware Ethernet address */ ! 87: struct ifuba es_ifuba; /* UNIBUS resources */ ! 88: short es_mask; /* mask for current output delay */ ! 89: short es_oactive; /* is output active? */ ! 90: #if NENETFILTER > 0 ! 91: short es_enetunit; /* unit number for enet filtering */ ! 92: #endif NENETFILTER > 0 ! 93: u_char *es_buf[16]; /* virtual addresses of buffers */ ! 94: } ec_softc[NEC]; ! 95: ! 96: /* ! 97: * Configure on-board memory for an interface. ! 98: * Called from autoconfig and after a uba reset. ! 99: * The address of the memory on the uba is supplied in the device flags. ! 100: */ ! 101: ecubamem(ui, uban) ! 102: register struct uba_device *ui; ! 103: { ! 104: register caddr_t ecbuf = (caddr_t) &umem[uban][ui->ui_flags]; ! 105: register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; ! 106: ! 107: /* ! 108: * Make sure csr is there (we run before ecprobe). ! 109: */ ! 110: if (badaddr((caddr_t)addr, 2)) ! 111: return (-1); ! 112: #if VAX780 ! 113: if (cpu == VAX_780 && uba_hd[uban].uh_uba->uba_sr) { ! 114: uba_hd[uban].uh_uba->uba_sr = uba_hd[uban].uh_uba->uba_sr; ! 115: return (-1); ! 116: } ! 117: #endif ! 118: /* ! 119: * Make sure memory is turned on ! 120: */ ! 121: addr->ec_rcr = EC_AROM; ! 122: /* ! 123: * Tell the system that the board has memory here, so it won't ! 124: * attempt to allocate the addresses later. ! 125: */ ! 126: if (ubamem(uban, ui->ui_flags, ECBUFSIZE*CLSIZE, 1) == 0) { ! 127: printf("ec%d: cannot reserve uba addresses\n", ui->ui_unit); ! 128: addr->ec_rcr = EC_MDISAB; /* disable memory */ ! 129: return (-1); ! 130: } ! 131: /* ! 132: * Check for existence of buffers on Unibus. ! 133: */ ! 134: if (badaddr((caddr_t)ecbuf, 2)) { ! 135: bad: ! 136: printf("ec%d: buffer mem not found\n", ui->ui_unit); ! 137: (void) ubamem(uban, ui->ui_flags, ECBUFSIZE*2, 0); ! 138: addr->ec_rcr = EC_MDISAB; /* disable memory */ ! 139: return (-1); ! 140: } ! 141: #if VAX780 ! 142: if (cpu == VAX_780 && uba_hd[uban].uh_uba->uba_sr) { ! 143: uba_hd[uban].uh_uba->uba_sr = uba_hd[uban].uh_uba->uba_sr; ! 144: goto bad; ! 145: } ! 146: #endif ! 147: if (ui->ui_alive == 0) /* Only printf from autoconfig */ ! 148: printf("ec%d: mem %x-%x\n", ui->ui_unit, ! 149: ui->ui_flags, ui->ui_flags + ECBUFSIZE*CLBYTES - 1); ! 150: ui->ui_type = 1; /* Memory on, allocated */ ! 151: return (0); ! 152: } ! 153: ! 154: /* ! 155: * Do output DMA to determine interface presence and ! 156: * interrupt vector. DMA is too short to disturb other hosts. ! 157: */ ! 158: ecprobe(reg, ui) ! 159: caddr_t reg; ! 160: struct uba_device *ui; ! 161: { ! 162: register int br, cvec; /* r11, r10 value-result */ ! 163: register struct ecdevice *addr = (struct ecdevice *)reg; ! 164: register caddr_t ecbuf = (caddr_t) &umem[ui->ui_ubanum][ui->ui_flags]; ! 165: ! 166: #ifdef lint ! 167: br = 0; cvec = br; br = cvec; ! 168: ecrint(0); ecxint(0); eccollide(0); ! 169: #endif ! 170: ! 171: /* ! 172: * Check that buffer memory was found and enabled. ! 173: */ ! 174: if (ui->ui_type == 0) ! 175: return(0); ! 176: /* ! 177: * Make a one byte packet in what should be buffer #0. ! 178: * Submit it for sending. This should cause an xmit interrupt. ! 179: * The xmit interrupt vector is 8 bytes after the receive vector, ! 180: * so adjust for this before returning. ! 181: */ ! 182: *(u_short *)ecbuf = (u_short) 03777; ! 183: ecbuf[03777] = '\0'; ! 184: addr->ec_xcr = EC_XINTEN|EC_XWBN; ! 185: DELAY(100000); ! 186: addr->ec_xcr = EC_XCLR; ! 187: if (cvec > 0 && cvec != 0x200) { ! 188: if (cvec & 04) { /* collision interrupt */ ! 189: cvec -= 04; ! 190: br += 1; /* rcv is collision + 1 */ ! 191: } else { /* xmit interrupt */ ! 192: cvec -= 010; ! 193: br += 2; /* rcv is xmit + 2 */ ! 194: } ! 195: } ! 196: return (1); ! 197: } ! 198: ! 199: /* ! 200: * Interface exists: make available by filling in network interface ! 201: * record. System will initialize the interface when it is ready ! 202: * to accept packets. ! 203: */ ! 204: ecattach(ui) ! 205: struct uba_device *ui; ! 206: { ! 207: struct ec_softc *es = &ec_softc[ui->ui_unit]; ! 208: register struct ifnet *ifp = &es->es_if; ! 209: register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; ! 210: int i, j; ! 211: u_char *cp; ! 212: ! 213: ifp->if_unit = ui->ui_unit; ! 214: ifp->if_name = "ec"; ! 215: ifp->if_mtu = ETHERMTU; ! 216: ! 217: /* ! 218: * Read the ethernet address off the board, one nibble at a time. ! 219: */ ! 220: addr->ec_xcr = EC_UECLR; /* zero address pointer */ ! 221: addr->ec_rcr = EC_AROM; ! 222: cp = es->es_addr; ! 223: #define NEXTBIT addr->ec_rcr = EC_AROM|EC_ASTEP; addr->ec_rcr = EC_AROM ! 224: for (i=0; i < sizeof (es->es_addr); i++) { ! 225: *cp = 0; ! 226: for (j=0; j<=4; j+=4) { ! 227: *cp |= ((addr->ec_rcr >> 8) & 0xf) << j; ! 228: NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT; ! 229: } ! 230: cp++; ! 231: } ! 232: printf("ec%d: hardware address %s\n", ui->ui_unit, ! 233: ether_sprintf(es->es_addr)); ! 234: ifp->if_init = ecinit; ! 235: ifp->if_ioctl = ecioctl; ! 236: ifp->if_output = ecoutput; ! 237: ifp->if_reset = ecreset; ! 238: ifp->if_flags = IFF_BROADCAST; ! 239: for (i=0; i<16; i++) ! 240: es->es_buf[i] ! 241: = (u_char *)&umem[ui->ui_ubanum][ui->ui_flags + 2048*i]; ! 242: #if NENETFILTER > 0 ! 243: { ! 244: struct endevp enp; ! 245: ! 246: enp.end_dev_type = ENDT_10MB; ! 247: enp.end_addr_len = sizeof(es->es_addr); ! 248: enp.end_hdr_len = sizeof(struct ether_header); ! 249: enp.end_MTU = ETHERMTU; ! 250: bcopy((caddr_t)es->es_addr, ! 251: (caddr_t)(enp.end_addr), sizeof(es->es_addr)); ! 252: bcopy((caddr_t)etherbroadcastaddr, ! 253: (caddr_t)(enp.end_broadaddr), sizeof(es->es_addr)); ! 254: ! 255: es->es_enetunit = enetattach(&es->es_if, &enp); ! 256: } ! 257: #endif NENETFILTER > 0 ! 258: if_attach(ifp); ! 259: } ! 260: ! 261: /* ! 262: * Reset of interface after UNIBUS reset. ! 263: * If interface is on specified uba, reset its state. ! 264: */ ! 265: ecreset(unit, uban) ! 266: int unit, uban; ! 267: { ! 268: register struct uba_device *ui; ! 269: ! 270: if (unit >= NEC || (ui = ecinfo[unit]) == 0 || ui->ui_alive == 0 || ! 271: ui->ui_ubanum != uban) ! 272: return; ! 273: printf(" ec%d", unit); ! 274: ec_softc[unit].es_if.if_flags &= ~IFF_RUNNING; ! 275: ecinit(unit); ! 276: } ! 277: ! 278: /* ! 279: * Initialization of interface; clear recorded pending ! 280: * operations, and reinitialize UNIBUS usage. ! 281: */ ! 282: ecinit(unit) ! 283: int unit; ! 284: { ! 285: struct ec_softc *es = &ec_softc[unit]; ! 286: struct ecdevice *addr; ! 287: register struct ifnet *ifp = &es->es_if; ! 288: int i, s; ! 289: ! 290: /* not yet, if address still unknown */ ! 291: if (ifp->if_addrlist == (struct ifaddr *)0) ! 292: return; ! 293: ! 294: /* ! 295: * Hang receive buffers and start any pending writes. ! 296: * Writing into the rcr also makes sure the memory ! 297: * is turned on. ! 298: */ ! 299: if ((ifp->if_flags & IFF_RUNNING) == 0) { ! 300: addr = (struct ecdevice *)ecinfo[unit]->ui_addr; ! 301: s = splimp(); ! 302: /* ! 303: * write our ethernet address into the address recognition ROM ! 304: * so we can always use the same EC_READ bits (referencing ROM), ! 305: * in case we change the address sometime. ! 306: * Note that this is safe here as the receiver is NOT armed. ! 307: */ ! 308: ec_setaddr(es->es_addr, unit); ! 309: /* ! 310: * Arm the receiver ! 311: */ ! 312: for (i = ECRHBF; i >= ECRLBF; i--) ! 313: addr->ec_rcr = EC_READ | i; ! 314: es->es_oactive = 0; ! 315: es->es_mask = ~0; ! 316: es->es_if.if_flags |= IFF_RUNNING; ! 317: if (es->es_if.if_snd.ifq_head) ! 318: ecstart(unit); ! 319: splx(s); ! 320: } ! 321: } ! 322: ! 323: /* ! 324: * Start output on interface. Get another datagram to send ! 325: * off of the interface queue, and copy it to the interface ! 326: * before starting the output. ! 327: */ ! 328: ecstart(unit) ! 329: { ! 330: register struct ec_softc *es = &ec_softc[unit]; ! 331: struct ecdevice *addr; ! 332: struct mbuf *m; ! 333: ! 334: if ((es->es_if.if_flags & IFF_RUNNING) == 0) ! 335: return; ! 336: IF_DEQUEUE(&es->es_if.if_snd, m); ! 337: if (m == 0) ! 338: return; ! 339: ecput(es->es_buf[ECTBF], m); ! 340: addr = (struct ecdevice *)ecinfo[unit]->ui_addr; ! 341: addr->ec_xcr = EC_WRITE|ECTBF; ! 342: es->es_oactive = 1; ! 343: } ! 344: ! 345: /* ! 346: * Ethernet interface transmitter interrupt. ! 347: * Start another output if more data to send. ! 348: */ ! 349: ecxint(unit) ! 350: int unit; ! 351: { ! 352: register struct ec_softc *es = &ec_softc[unit]; ! 353: register struct ecdevice *addr = ! 354: (struct ecdevice *)ecinfo[unit]->ui_addr; ! 355: ! 356: if (es->es_oactive == 0) ! 357: return; ! 358: if ((addr->ec_xcr&EC_XDONE) == 0 || (addr->ec_xcr&EC_XBN) != ECTBF) { ! 359: printf("ec%d: stray xmit interrupt, xcr=%b\n", unit, ! 360: addr->ec_xcr, EC_XBITS); ! 361: es->es_oactive = 0; ! 362: addr->ec_xcr = EC_XCLR; ! 363: return; ! 364: } ! 365: es->es_if.if_opackets++; ! 366: es->es_oactive = 0; ! 367: es->es_mask = ~0; ! 368: addr->ec_xcr = EC_XCLR; ! 369: if (es->es_if.if_snd.ifq_head) ! 370: ecstart(unit); ! 371: } ! 372: ! 373: /* ! 374: * Collision on ethernet interface. Do exponential ! 375: * backoff, and retransmit. If have backed off all ! 376: * the way print warning diagnostic, and drop packet. ! 377: */ ! 378: eccollide(unit) ! 379: int unit; ! 380: { ! 381: register struct ec_softc *es = &ec_softc[unit]; ! 382: register struct ecdevice *addr = ! 383: (struct ecdevice *)ecinfo[unit]->ui_addr; ! 384: register i; ! 385: int delay; ! 386: ! 387: es->es_if.if_collisions++; ! 388: if (es->es_oactive == 0) ! 389: return; ! 390: ! 391: /* ! 392: * Es_mask is a 16 bit number with n low zero bits, with ! 393: * n the number of backoffs. When es_mask is 0 we have ! 394: * backed off 16 times, and give up. ! 395: */ ! 396: if (es->es_mask == 0) { ! 397: es->es_if.if_oerrors++; ! 398: log(LOG_ERR, "ec%d: send error\n", unit); ! 399: /* ! 400: * Reset interface, then requeue rcv buffers. ! 401: * Some incoming packets may be lost, but that ! 402: * can't be helped. ! 403: */ ! 404: addr->ec_xcr = EC_UECLR; ! 405: for (i=ECRHBF; i>=ECRLBF; i--) ! 406: addr->ec_rcr = EC_READ|i; ! 407: /* ! 408: * Reset and transmit next packet (if any). ! 409: */ ! 410: es->es_oactive = 0; ! 411: es->es_mask = ~0; ! 412: if (es->es_if.if_snd.ifq_head) ! 413: ecstart(unit); ! 414: return; ! 415: } ! 416: /* ! 417: * Do exponential backoff. Compute delay based on low bits ! 418: * of the interval timer (1 bit for each transmission attempt, ! 419: * but at most 5 bits). Then delay for that number of ! 420: * slot times. A slot time is 51.2 microseconds (rounded to 51). ! 421: * This does not take into account the time already used to ! 422: * process the interrupt. ! 423: */ ! 424: es->es_mask <<= 1; ! 425: delay = mfpr(ICR) & 0x1f &~ es->es_mask; ! 426: DELAY(delay * 51); ! 427: /* ! 428: * Clear the controller's collision flag, thus enabling retransmit. ! 429: */ ! 430: addr->ec_xcr = EC_CLEAR; ! 431: } ! 432: ! 433: /* ! 434: * Ethernet interface receiver interrupt. ! 435: * If input error just drop packet. ! 436: * Otherwise examine ! 437: * packet to determine type. If can't determine length ! 438: * from type, then have to drop packet. Othewise decapsulate ! 439: * packet based on type and pass to type specific higher-level ! 440: * input routine. ! 441: */ ! 442: ecrint(unit) ! 443: int unit; ! 444: { ! 445: struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; ! 446: ! 447: while (addr->ec_rcr & EC_RDONE) ! 448: ecread(unit); ! 449: } ! 450: ! 451: ecread(unit) ! 452: int unit; ! 453: { ! 454: register struct ec_softc *es = &ec_softc[unit]; ! 455: struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; ! 456: register struct ether_header *ec; ! 457: struct mbuf *m; ! 458: int len, off, resid, ecoff, rbuf; ! 459: register struct ifqueue *inq; ! 460: u_char *ecbuf; ! 461: ! 462: es->es_if.if_ipackets++; ! 463: rbuf = addr->ec_rcr & EC_RBN; ! 464: if (rbuf < ECRLBF || rbuf > ECRHBF) ! 465: panic("ecrint"); ! 466: ecbuf = es->es_buf[rbuf]; ! 467: ecoff = *(short *)ecbuf; ! 468: if (ecoff <= ECRDOFF || ecoff > 2046) { ! 469: es->es_if.if_ierrors++; ! 470: #ifdef notdef ! 471: if (es->es_if.if_ierrors % 100 == 0) ! 472: printf("ec%d: += 100 input errors\n", unit); ! 473: #endif ! 474: goto setup; ! 475: } ! 476: ! 477: /* ! 478: * Get input data length. ! 479: * Get pointer to ethernet header (in input buffer). ! 480: * Deal with trailer protocol: if type is trailer type ! 481: * get true type from first 16-bit word past data. ! 482: * Remember that type was trailer by setting off. ! 483: */ ! 484: len = ecoff - ECRDOFF - sizeof (struct ether_header); ! 485: ec = (struct ether_header *)(ecbuf + ECRDOFF); ! 486: ec->ether_type = ntohs((u_short)ec->ether_type); ! 487: #define ecdataaddr(ec, off, type) ((type)(((caddr_t)((ec)+1)+(off)))) ! 488: if (ec->ether_type >= ETHERTYPE_TRAIL && ! 489: ec->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { ! 490: off = (ec->ether_type - ETHERTYPE_TRAIL) * 512; ! 491: if (off >= ETHERMTU) ! 492: goto setup; /* sanity */ ! 493: ec->ether_type = ntohs(*ecdataaddr(ec, off, u_short *)); ! 494: resid = ntohs(*(ecdataaddr(ec, off+2, u_short *))); ! 495: if (off + resid > len) ! 496: goto setup; /* sanity */ ! 497: len = off + resid; ! 498: } else ! 499: off = 0; ! 500: if (len == 0) ! 501: goto setup; ! 502: ! 503: /* ! 504: * Pull packet off interface. Off is nonzero if packet ! 505: * has trailing header; ecget will then force this header ! 506: * information to be at the front, but we still have to drop ! 507: * the type and length which are at the front of any trailer data. ! 508: */ ! 509: m = ecget(ecbuf, len, off, &es->es_if); ! 510: if (m == 0) ! 511: goto setup; ! 512: if (off) { ! 513: struct ifnet *ifp; ! 514: ! 515: ifp = *(mtod(m, struct ifnet **)); ! 516: m->m_off += 2 * sizeof (u_short); ! 517: m->m_len -= 2 * sizeof (u_short); ! 518: *(mtod(m, struct ifnet **)) = ifp; ! 519: } ! 520: switch (ec->ether_type) { ! 521: ! 522: #ifdef INET ! 523: case ETHERTYPE_IP: ! 524: schednetisr(NETISR_IP); ! 525: inq = &ipintrq; ! 526: break; ! 527: ! 528: case ETHERTYPE_ARP: ! 529: arpinput(&es->es_ac, m); ! 530: goto setup; ! 531: #endif ! 532: #ifdef NS ! 533: case ETHERTYPE_NS: ! 534: schednetisr(NETISR_NS); ! 535: inq = &nsintrq; ! 536: break; ! 537: ! 538: #endif ! 539: #if NENETFILTER > 0 ! 540: default: ! 541: { ! 542: register struct mbuf *mtop; ! 543: register short *sp,*sp2; ! 544: int i; ! 545: /* ! 546: * We need the local net header after all. Oh well, ! 547: * this could be improved. ! 548: */ ! 549: MGET(mtop, M_DONTWAIT, MT_DATA); ! 550: if (mtop == 0) { /* no more mbufs? */ ! 551: m_freem(m); /* wasted effort */ ! 552: goto setup; ! 553: } ! 554: ec->ether_type = htons((u_short)ec->ether_type); ! 555: sp = (short *) ec; ! 556: sp2 = mtod(mtop, short *); ! 557: for (i = 0 ; i < (sizeof(struct ether_header)/2) ; i++) ! 558: *sp2++ = *sp++; ! 559: mtop->m_len = sizeof(struct ether_header); ! 560: IF_ADJ(m); ! 561: mtop->m_next = m; ! 562: enetFilter(es->es_enetunit, mtop, ! 563: (len + sizeof(struct ether_header)) ); ! 564: goto setup; ! 565: } ! 566: #else ! 567: default: ! 568: m_freem(m); ! 569: goto setup; ! 570: #endif NENETFILTER > 0 ! 571: } ! 572: ! 573: if (IF_QFULL(inq)) { ! 574: IF_DROP(inq); ! 575: m_freem(m); ! 576: goto setup; ! 577: } ! 578: IF_ENQUEUE(inq, m); ! 579: ! 580: setup: ! 581: /* ! 582: * Reset for next packet. ! 583: */ ! 584: addr->ec_rcr = EC_READ|EC_RCLR|rbuf; ! 585: } ! 586: ! 587: /* ! 588: * Ethernet output routine. ! 589: * Encapsulate a packet of type family for the local net. ! 590: * Use trailer local net encapsulation if enough data in first ! 591: * packet leaves a multiple of 512 bytes of data in remainder. ! 592: * If destination is this address or broadcast, send packet to ! 593: * loop device to kludge around the fact that 3com interfaces can't ! 594: * talk to themselves. ! 595: */ ! 596: ecoutput(ifp, m0, dst) ! 597: struct ifnet *ifp; ! 598: struct mbuf *m0; ! 599: struct sockaddr *dst; ! 600: { ! 601: int type, s, error; ! 602: u_char edst[6]; ! 603: struct in_addr idst; ! 604: register struct ec_softc *es = &ec_softc[ifp->if_unit]; ! 605: register struct mbuf *m = m0; ! 606: register struct ether_header *ec; ! 607: register int off; ! 608: struct mbuf *mcopy = (struct mbuf *)0; ! 609: #if NENETFILTER > 0 ! 610: struct mbuf *enetcopy = (struct mbuf *)0; ! 611: #endif NENETFILTER ! 612: int usetrailers; ! 613: ! 614: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { ! 615: error = ENETDOWN; ! 616: goto bad; ! 617: } ! 618: switch (dst->sa_family) { ! 619: ! 620: #ifdef INET ! 621: case AF_INET: ! 622: idst = ((struct sockaddr_in *)dst)->sin_addr; ! 623: if (!arpresolve(&es->es_ac, m, &idst, edst, &usetrailers)) ! 624: return (0); /* if not yet resolved */ ! 625: if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr, ! 626: sizeof(edst))) ! 627: mcopy = m_copy(m, 0, (int)M_COPYALL); ! 628: off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; ! 629: /* need per host negotiation */ ! 630: if (usetrailers && off > 0 && (off & 0x1ff) == 0 && ! 631: m->m_off >= MMINOFF + 2 * sizeof (u_short)) { ! 632: type = ETHERTYPE_TRAIL + (off>>9); ! 633: m->m_off -= 2 * sizeof (u_short); ! 634: m->m_len += 2 * sizeof (u_short); ! 635: *mtod(m, u_short *) = ntohs((u_short)ETHERTYPE_IP); ! 636: *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len); ! 637: goto gottrailertype; ! 638: } ! 639: type = ETHERTYPE_IP; ! 640: off = 0; ! 641: goto gottype; ! 642: #endif ! 643: #ifdef NS ! 644: case AF_NS: ! 645: bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), ! 646: (caddr_t)edst, sizeof (edst)); ! 647: ! 648: if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, ! 649: sizeof(edst))) { ! 650: ! 651: mcopy = m_copy(m, 0, (int)M_COPYALL); ! 652: } else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, ! 653: sizeof(edst))) { ! 654: ! 655: return(looutput(&loif, m, dst)); ! 656: } ! 657: type = ETHERTYPE_NS; ! 658: off = 0; ! 659: goto gottype; ! 660: #endif ! 661: #if NENETFILTER > 0 ! 662: case AF_IMPLINK: ! 663: ec = mtod(m, struct ether_header *); ! 664: /* see if we need to fake loopback */ ! 665: if ( /* is packet to us? */ ! 666: (!bcmp((caddr_t)ec->ether_dhost, ! 667: (caddr_t)es->es_addr, ! 668: sizeof(ec->ether_dhost))) ! 669: || /* or is it a broadcast? */ ! 670: (!bcmp((caddr_t)ec->ether_dhost, ! 671: (caddr_t)etherbroadcastaddr, ! 672: sizeof(ec->ether_dhost))) ! 673: ) { ! 674: enetcopy = m_copy(m, 0, (int)M_COPYALL); ! 675: } ! 676: goto gotheader; ! 677: #endif NENETFILTER ! 678: ! 679: case AF_UNSPEC: ! 680: ec = (struct ether_header *)dst->sa_data; ! 681: bcopy((caddr_t)ec->ether_dhost, (caddr_t)edst, sizeof (edst)); ! 682: type = ec->ether_type; ! 683: goto gottype; ! 684: ! 685: default: ! 686: printf("ec%d: can't handle af%d\n", ifp->if_unit, ! 687: dst->sa_family); ! 688: error = EAFNOSUPPORT; ! 689: goto bad; ! 690: } ! 691: ! 692: gottrailertype: ! 693: /* ! 694: * Packet to be sent as trailer: move first packet ! 695: * (control information) to end of chain. ! 696: */ ! 697: while (m->m_next) ! 698: m = m->m_next; ! 699: m->m_next = m0; ! 700: m = m0->m_next; ! 701: m0->m_next = 0; ! 702: m0 = m; ! 703: ! 704: gottype: ! 705: /* ! 706: * Add local net header. If no space in first mbuf, ! 707: * allocate another. ! 708: */ ! 709: if (m->m_off > MMAXOFF || ! 710: MMINOFF + sizeof (struct ether_header) > m->m_off) { ! 711: m = m_get(M_DONTWAIT, MT_HEADER); ! 712: if (m == 0) { ! 713: error = ENOBUFS; ! 714: goto bad; ! 715: } ! 716: m->m_next = m0; ! 717: m->m_off = MMINOFF; ! 718: m->m_len = sizeof (struct ether_header); ! 719: } else { ! 720: m->m_off -= sizeof (struct ether_header); ! 721: m->m_len += sizeof (struct ether_header); ! 722: } ! 723: ec = mtod(m, struct ether_header *); ! 724: ec->ether_type = htons((u_short)type); ! 725: bcopy((caddr_t)edst, (caddr_t)ec->ether_dhost, sizeof (edst)); ! 726: #if NENETFILTER > 0 ! 727: gotheader: ! 728: #endif NENETFILTER ! 729: bcopy((caddr_t)es->es_addr, (caddr_t)ec->ether_shost, ! 730: sizeof(ec->ether_shost)); ! 731: ! 732: /* ! 733: * Queue message on interface, and start output if interface ! 734: * not yet active. ! 735: */ ! 736: s = splimp(); ! 737: if (IF_QFULL(&ifp->if_snd)) { ! 738: IF_DROP(&ifp->if_snd); ! 739: error = ENOBUFS; ! 740: goto qfull; ! 741: } ! 742: IF_ENQUEUE(&ifp->if_snd, m); ! 743: if (es->es_oactive == 0) ! 744: ecstart(ifp->if_unit); ! 745: #if NENETFILTER > 0 ! 746: if (enetcopy) { /* we have a loopback that isn't an IP */ ! 747: register int count = 0; ! 748: register struct mbuf *mt = enetcopy; ! 749: ! 750: /* figure out how long the packet is */ ! 751: do { ! 752: count += mt->m_len; ! 753: mt = mt->m_next; ! 754: } while (mt); ! 755: ! 756: /* ! 757: * should perhaps reject certain packet types here, ! 758: * but probably less total effort to let enetFilter ! 759: * reject them. ! 760: */ ! 761: enetFilter(es->es_enetunit, enetcopy, count); ! 762: } ! 763: #endif NENETFILTER ! 764: splx(s); ! 765: return (mcopy ? looutput(&loif, mcopy, dst) : 0); ! 766: ! 767: qfull: ! 768: m0 = m; ! 769: splx(s); ! 770: bad: ! 771: m_freem(m0); ! 772: if (mcopy) ! 773: m_freem(mcopy); ! 774: #if NENETFILTER > 0 ! 775: if (enetcopy) ! 776: m_freem(enetcopy); ! 777: #endif NENETFILTER ! 778: return (error); ! 779: } ! 780: ! 781: /* ! 782: * Routine to copy from mbuf chain to transmit ! 783: * buffer in UNIBUS memory. ! 784: * If packet size is less than the minimum legal size, ! 785: * the buffer is expanded. We probably should zero out the extra ! 786: * bytes for security, but that would slow things down. ! 787: */ ! 788: ecput(ecbuf, m) ! 789: u_char *ecbuf; ! 790: struct mbuf *m; ! 791: { ! 792: register struct mbuf *mp; ! 793: register int off; ! 794: u_char *bp; ! 795: ! 796: for (off = 2048, mp = m; mp; mp = mp->m_next) ! 797: off -= mp->m_len; ! 798: if (2048 - off < ETHERMIN + sizeof (struct ether_header)) ! 799: off = 2048 - ETHERMIN - sizeof (struct ether_header); ! 800: *(u_short *)ecbuf = off; ! 801: bp = (u_char *)(ecbuf + off); ! 802: for (mp = m; mp; mp = mp->m_next) { ! 803: register unsigned len = mp->m_len; ! 804: u_char *mcp; ! 805: ! 806: if (len == 0) ! 807: continue; ! 808: mcp = mtod(mp, u_char *); ! 809: if ((unsigned)bp & 01) { ! 810: *bp++ = *mcp++; ! 811: len--; ! 812: } ! 813: if (off = (len >> 1)) { ! 814: register u_short *to, *from; ! 815: ! 816: to = (u_short *)bp; ! 817: from = (u_short *)mcp; ! 818: do ! 819: *to++ = *from++; ! 820: while (--off > 0); ! 821: bp = (u_char *)to, ! 822: mcp = (u_char *)from; ! 823: } ! 824: if (len & 01) ! 825: *bp++ = *mcp++; ! 826: } ! 827: m_freem(m); ! 828: } ! 829: ! 830: /* ! 831: * Routine to copy from UNIBUS memory into mbufs. ! 832: * Similar in spirit to if_rubaget. ! 833: * ! 834: * Warning: This makes the fairly safe assumption that ! 835: * mbufs have even lengths. ! 836: */ ! 837: struct mbuf * ! 838: ecget(ecbuf, totlen, off0, ifp) ! 839: u_char *ecbuf; ! 840: int totlen, off0; ! 841: struct ifnet *ifp; ! 842: { ! 843: register struct mbuf *m; ! 844: struct mbuf *top = 0, **mp = ⊤ ! 845: register int off = off0, len; ! 846: u_char *cp; ! 847: ! 848: cp = ecbuf + ECRDOFF + sizeof (struct ether_header); ! 849: while (totlen > 0) { ! 850: register int words; ! 851: u_char *mcp; ! 852: ! 853: MGET(m, M_DONTWAIT, MT_DATA); ! 854: if (m == 0) ! 855: goto bad; ! 856: if (off) { ! 857: len = totlen - off; ! 858: cp = ecbuf + ECRDOFF + ! 859: sizeof (struct ether_header) + off; ! 860: } else ! 861: len = totlen; ! 862: if (ifp) ! 863: len += sizeof(ifp); ! 864: if (len >= NBPG) { ! 865: MCLGET(m); ! 866: if (m->m_len == CLBYTES) ! 867: m->m_len = len = MIN(len, CLBYTES); ! 868: else ! 869: m->m_len = len = MIN(MLEN, len); ! 870: } else { ! 871: m->m_len = len = MIN(MLEN, len); ! 872: m->m_off = MMINOFF; ! 873: } ! 874: mcp = mtod(m, u_char *); ! 875: if (ifp) { ! 876: /* ! 877: * Prepend interface pointer to first mbuf. ! 878: */ ! 879: *(mtod(m, struct ifnet **)) = ifp; ! 880: mcp += sizeof(ifp); ! 881: len -= sizeof(ifp); ! 882: ifp = (struct ifnet *)0; ! 883: } ! 884: if (words = (len >> 1)) { ! 885: register u_short *to, *from; ! 886: ! 887: to = (u_short *)mcp; ! 888: from = (u_short *)cp; ! 889: do ! 890: *to++ = *from++; ! 891: while (--words > 0); ! 892: mcp = (u_char *)to; ! 893: cp = (u_char *)from; ! 894: } ! 895: if (len & 01) ! 896: *mcp++ = *cp++; ! 897: *mp = m; ! 898: mp = &m->m_next; ! 899: if (off == 0) { ! 900: totlen -= len; ! 901: continue; ! 902: } ! 903: off += len; ! 904: if (off == totlen) { ! 905: cp = ecbuf + ECRDOFF + sizeof (struct ether_header); ! 906: off = 0; ! 907: totlen = off0; ! 908: } ! 909: } ! 910: return (top); ! 911: bad: ! 912: m_freem(top); ! 913: return (0); ! 914: } ! 915: ! 916: /* ! 917: * Process an ioctl request. ! 918: */ ! 919: ecioctl(ifp, cmd, data) ! 920: register struct ifnet *ifp; ! 921: int cmd; ! 922: caddr_t data; ! 923: { ! 924: register struct ifaddr *ifa = (struct ifaddr *)data; ! 925: struct ec_softc *es = &ec_softc[ifp->if_unit]; ! 926: struct ecdevice *addr; ! 927: int s = splimp(), error = 0; ! 928: ! 929: addr = (struct ecdevice *)(ecinfo[ifp->if_unit]->ui_addr); ! 930: ! 931: switch (cmd) { ! 932: ! 933: case SIOCSIFADDR: ! 934: ifp->if_flags |= IFF_UP; ! 935: ! 936: switch (ifa->ifa_addr.sa_family) { ! 937: #ifdef INET ! 938: case AF_INET: ! 939: ecinit(ifp->if_unit); /* before arpwhohas */ ! 940: ((struct arpcom *)ifp)->ac_ipaddr = ! 941: IA_SIN(ifa)->sin_addr; ! 942: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); ! 943: break; ! 944: #endif ! 945: #ifdef NS ! 946: case AF_NS: ! 947: { ! 948: register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); ! 949: ! 950: if (ns_nullhost(*ina)) ! 951: ina->x_host = *(union ns_host *)(es->es_addr); ! 952: else { ! 953: /* ! 954: * The manual says we can't change the address ! 955: * while the receiver is armed, ! 956: * so reset everything ! 957: */ ! 958: ifp->if_flags &= ~IFF_RUNNING; ! 959: bcopy((caddr_t)ina->x_host.c_host, ! 960: (caddr_t)es->es_addr, sizeof(es->es_addr)); ! 961: } ! 962: ecinit(ifp->if_unit); /* does ec_setaddr() */ ! 963: break; ! 964: } ! 965: #endif ! 966: default: ! 967: ecinit(ifp->if_unit); ! 968: break; ! 969: } ! 970: break; ! 971: ! 972: case SIOCSIFFLAGS: ! 973: if ((ifp->if_flags & IFF_UP) == 0 && ! 974: ifp->if_flags & IFF_RUNNING) { ! 975: addr->ec_xcr = EC_UECLR; ! 976: ifp->if_flags &= ~IFF_RUNNING; ! 977: } else if (ifp->if_flags & IFF_UP && ! 978: (ifp->if_flags & IFF_RUNNING) == 0) ! 979: ecinit(ifp->if_unit); ! 980: break; ! 981: ! 982: default: ! 983: error = EINVAL; ! 984: } ! 985: splx(s); ! 986: return (error); ! 987: } ! 988: ! 989: ec_setaddr(physaddr,unit) ! 990: u_char *physaddr; ! 991: int unit; ! 992: { ! 993: struct ec_softc *es = &ec_softc[unit]; ! 994: struct uba_device *ui = ecinfo[unit]; ! 995: register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; ! 996: register char nibble; ! 997: register int i, j; ! 998: ! 999: /* ! 1000: * Use the ethernet address supplied ! 1001: * Note that we do a UECLR here, so the receive buffers ! 1002: * must be requeued. ! 1003: */ ! 1004: ! 1005: #ifdef DEBUG ! 1006: printf("ec_setaddr: setting address for unit %d = %s", ! 1007: unit, ether_sprintf(physaddr)); ! 1008: #endif ! 1009: addr->ec_xcr = EC_UECLR; ! 1010: addr->ec_rcr = 0; ! 1011: /* load requested address */ ! 1012: for (i = 0; i < 6; i++) { /* 6 bytes of address */ ! 1013: es->es_addr[i] = physaddr[i]; ! 1014: nibble = physaddr[i] & 0xf; /* lower nibble */ ! 1015: addr->ec_rcr = (nibble << 8); ! 1016: addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */ ! 1017: addr->ec_rcr = (nibble << 8); ! 1018: for (j=0; j < 4; j++) { ! 1019: addr->ec_rcr = 0; ! 1020: addr->ec_rcr = EC_ASTEP; /* step counter */ ! 1021: addr->ec_rcr = 0; ! 1022: } ! 1023: nibble = (physaddr[i] >> 4) & 0xf; /* upper nibble */ ! 1024: addr->ec_rcr = (nibble << 8); ! 1025: addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */ ! 1026: addr->ec_rcr = (nibble << 8); ! 1027: for (j=0; j < 4; j++) { ! 1028: addr->ec_rcr = 0; ! 1029: addr->ec_rcr = EC_ASTEP; /* step counter */ ! 1030: addr->ec_rcr = 0; ! 1031: } ! 1032: } ! 1033: #ifdef DEBUG ! 1034: /* ! 1035: * Read the ethernet address off the board, one nibble at a time. ! 1036: */ ! 1037: addr->ec_xcr = EC_UECLR; ! 1038: addr->ec_rcr = 0; /* read RAM */ ! 1039: cp = es->es_addr; ! 1040: #undef NEXTBIT ! 1041: #define NEXTBIT addr->ec_rcr = EC_ASTEP; addr->ec_rcr = 0 ! 1042: for (i=0; i < sizeof (es->es_addr); i++) { ! 1043: *cp = 0; ! 1044: for (j=0; j<=4; j+=4) { ! 1045: *cp |= ((addr->ec_rcr >> 8) & 0xf) << j; ! 1046: NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT; ! 1047: } ! 1048: cp++; ! 1049: } ! 1050: printf("ec_setaddr: RAM address for unit %d = %s", ! 1051: unit, ether_sprintf(physaddr)); ! 1052: #endif ! 1053: } ! 1054: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.