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