|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1988 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms, with or without ! 6: * modification, are permitted provided that the following conditions ! 7: * are met: ! 8: * 1. Redistributions of source code must retain the above copyright ! 9: * notice, this list of conditions and the following disclaimer. ! 10: * 2. Redistributions in binary form must reproduce the above copyright ! 11: * notice, this list of conditions and the following disclaimer in the ! 12: * documentation and/or other materials provided with the distribution. ! 13: * 3. All advertising materials mentioning features or use of this software ! 14: * must display the following acknowledgement: ! 15: * This product includes software developed by the University of ! 16: * California, Berkeley and its contributors. ! 17: * 4. Neither the name of the University nor the names of its contributors ! 18: * may be used to endorse or promote products derived from this software ! 19: * without specific prior written permission. ! 20: * ! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 31: * SUCH DAMAGE. ! 32: * ! 33: * @(#)if_imp.c 7.13 (Berkeley) 6/28/90 ! 34: */ ! 35: ! 36: #include "imp.h" ! 37: #if NIMP > 0 ! 38: /* ! 39: * ARPANET IMP (PSN) interface driver. ! 40: * ! 41: * The IMP-host protocol (AHIP) is handled here, leaving ! 42: * hardware specifics to the lower level interface driver. ! 43: */ ! 44: #include "param.h" ! 45: #include "systm.h" ! 46: #include "mbuf.h" ! 47: #include "buf.h" ! 48: #include "protosw.h" ! 49: #include "socket.h" ! 50: #include "time.h" ! 51: #include "kernel.h" ! 52: #include "errno.h" ! 53: #include "ioctl.h" ! 54: #include "syslog.h" ! 55: ! 56: #include "machine/mtpr.h" ! 57: ! 58: #include "../net/if.h" ! 59: #include "../net/netisr.h" ! 60: #include "../netinet/in.h" ! 61: #include "../netinet/in_systm.h" ! 62: #include "../netinet/in_var.h" ! 63: #include "../netinet/ip.h" ! 64: #include "../netinet/ip_var.h" ! 65: #define IMPMESSAGES ! 66: /* define IMPLEADERS here to get leader printing code */ ! 67: #include "if_imp.h" ! 68: #include "if_imphost.h" ! 69: ! 70: struct imp_softc imp_softc[NIMP]; ! 71: #ifndef lint ! 72: int nimp = NIMP; /* for netstat */ ! 73: #endif ! 74: struct ifqueue impintrq; ! 75: int impqmaxlen = IFQ_MAXLEN; ! 76: int imphqlen = 12 + IMP_MAXHOSTMSG; /* max packets to queue per host */ ! 77: ! 78: int imppri = LOG_ERR; ! 79: #ifdef IMPLEADERS ! 80: int impprintfs = 0; ! 81: #endif ! 82: #ifdef IMPINIT ! 83: int imptraceinit = 0; ! 84: #endif ! 85: ! 86: ! 87: #define HOSTDEADTIMER (30 * PR_SLOWHZ) /* How long to wait when down */ ! 88: ! 89: int impdown(), impinit(), impioctl(), impoutput(), imptimo(); ! 90: ! 91: /* ! 92: * IMP attach routine. Called from hardware device attach routine ! 93: * at configuration time with a pointer to the device structure. ! 94: * Sets up local state and returns pointer to base of ifnet+impcb ! 95: * structures. This is then used by the device's attach routine ! 96: * set up its back pointers. ! 97: */ ! 98: struct imp_softc * ! 99: impattach(hwname, hwunit, reset) ! 100: char *hwname; ! 101: int hwunit; ! 102: int (*reset)(); ! 103: { ! 104: struct imp_softc *sc; ! 105: register struct ifnet *ifp; ! 106: static int impunit; ! 107: ! 108: #ifdef lint ! 109: impintr(); ! 110: #endif ! 111: if (impunit >= NIMP) { ! 112: printf("imp%d: not configured\n", impunit++); ! 113: return (0); ! 114: } ! 115: sc = &imp_softc[impunit]; ! 116: ifp = &sc->imp_if; ! 117: sc->imp_cb.ic_hwname = hwname; ! 118: sc->imp_cb.ic_hwunit = hwunit; ! 119: ifp->if_unit = impunit; ! 120: ifp->if_name = "imp"; ! 121: ifp->if_mtu = IMPMTU - sizeof(struct imp_leader); ! 122: ifp->if_reset = reset; ! 123: ifp->if_init = impinit; ! 124: ifp->if_ioctl = impioctl; ! 125: ifp->if_output = impoutput; ! 126: ifp->if_watchdog = imptimo; ! 127: if_attach(ifp); ! 128: impunit++; ! 129: return (sc); ! 130: } ! 131: ! 132: /* ! 133: * IMP initialization routine: call hardware module to ! 134: * setup resources, init state and get ready for ! 135: * NOOPs the IMP should send us, and that we want to drop. ! 136: */ ! 137: impinit(unit) ! 138: int unit; ! 139: { ! 140: int s; ! 141: register struct imp_softc *sc = &imp_softc[unit]; ! 142: ! 143: if (sc->imp_if.if_addrlist == 0) ! 144: return; ! 145: s = splimp(); ! 146: #ifdef IMPINIT ! 147: if (imptraceinit) ! 148: log(imppri, "impinit\n"); ! 149: #endif ! 150: sc->imp_state = IMPS_WINIT; ! 151: if ((*sc->imp_cb.ic_init)(sc->imp_cb.ic_hwunit) == 0) ! 152: sc->imp_if.if_flags &= ~IFF_UP; ! 153: impintrq.ifq_maxlen = impqmaxlen; ! 154: splx(s); ! 155: } ! 156: ! 157: /* ! 158: * ARPAnet 1822/AHIP input routine. ! 159: * Called from hardware input interrupt routine to handle 1822 ! 160: * IMP-host messages. Data messages are passed to higher-level ! 161: * protocol processors on the basis of link number. ! 162: * Other type messages (control) are handled here. ! 163: */ ! 164: impinput(unit, m) ! 165: int unit; ! 166: register struct mbuf *m; ! 167: { ! 168: register struct control_leader *cp; ! 169: #define ip ((struct imp_leader *)cp) ! 170: register struct imp_softc *sc = &imp_softc[unit]; ! 171: struct ifnet *ifp; ! 172: register struct host *hp; ! 173: register struct ifqueue *inq; ! 174: struct sockaddr_in *sin; ! 175: int s; ! 176: ! 177: /* ! 178: * Pull the interface pointer out of the mbuf ! 179: * and save for later; adjust mbuf to look at rest of data. ! 180: */ ! 181: if ((m->m_flags && M_PKTHDR) == 0) ! 182: panic("No header in impinput"); ! 183: ifp = m->m_pkthdr.rcvif; ! 184: /* verify leader length. */ ! 185: if (m->m_len < sizeof(struct control_leader) && ! 186: (m = m_pullup(m, sizeof(struct control_leader))) == 0) ! 187: return; ! 188: cp = mtod(m, struct control_leader *); ! 189: if (cp->dl_mtype == IMPTYPE_DATA && ! 190: m->m_len < sizeof(struct imp_leader)) { ! 191: if ((m = m_pullup(m, sizeof(struct imp_leader))) == 0) ! 192: return; ! 193: cp = mtod(m, struct control_leader *); ! 194: } ! 195: #ifdef IMPLEADERS ! 196: if (impprintfs) ! 197: printleader("impinput", ip); ! 198: #endif ! 199: inq = &impintrq; ! 200: ! 201: /* check leader type */ ! 202: if (cp->dl_format != IMP_NFF) { ! 203: /* ! 204: * We get 1822L NOOPs and RESET ! 205: * at initialization. ! 206: */ ! 207: #ifdef IMPINIT ! 208: if (imptraceinit) ! 209: log(imppri, "input, format %x mtype %d\n", ! 210: cp->dl_format, cp->dl_mtype); ! 211: #endif ! 212: if (cp->dl_format != IMP_1822L_I2H || ! 213: (cp->dl_mtype != IMPTYPE_NOOP && ! 214: cp->dl_mtype != IMPTYPE_RESET)) { ! 215: sc->imp_garbage++; ! 216: sc->imp_if.if_collisions++; /* XXX */ ! 217: } ! 218: } else switch (cp->dl_mtype) { ! 219: ! 220: case IMPTYPE_DATA: ! 221: /* ! 222: * Data for a protocol. Dispatch to the appropriate ! 223: * protocol routine (running at software interrupt). ! 224: * If this isn't a raw interface, advance pointer ! 225: * into mbuf past leader. ! 226: */ ! 227: switch (cp->dl_link) { ! 228: ! 229: case IMPLINK_IP: ! 230: m->m_len -= sizeof(struct imp_leader); ! 231: if (m->m_flags & M_PKTHDR) ! 232: m->m_pkthdr.len -= sizeof(struct imp_leader); ! 233: m->m_data += sizeof(struct imp_leader); ! 234: schednetisr(NETISR_IP); ! 235: inq = &ipintrq; ! 236: break; ! 237: ! 238: default: ! 239: break; ! 240: } ! 241: break; ! 242: ! 243: /* ! 244: * IMP leader error. Reset the IMP and discard the packet. ! 245: */ ! 246: case IMPTYPE_BADLEADER: ! 247: /* ! 248: * According to 1822 document, this message ! 249: * will be generated in response to the ! 250: * first noop sent to the IMP after ! 251: * the host resets the IMP interface. ! 252: */ ! 253: #ifdef IMPINIT ! 254: if (imptraceinit) ! 255: log(imppri, "badleader\n"); ! 256: #endif ! 257: if (sc->imp_state != IMPS_INIT) { ! 258: impmsg(sc, "leader error"); ! 259: sc->imp_msgready = 0; ! 260: hostreset(unit); ! 261: impnoops(sc); ! 262: sc->imp_garbage++; ! 263: } ! 264: break; ! 265: ! 266: /* ! 267: * IMP going down. Print message, and if not immediate, ! 268: * set off a timer to insure things will be reset at the ! 269: * appropriate time. ! 270: */ ! 271: case IMPTYPE_DOWN: ! 272: { int type, when; ! 273: ! 274: type = cp->dl_link & IMP_DMASK; ! 275: when = (cp->dl_link & IMPDOWN_WHENMASK) >> IMPDOWN_WHENSHIFT; ! 276: #ifdef IMPINIT ! 277: if (imptraceinit) ! 278: log(imppri, "input DOWN %s %d\n", ! 279: impmessage[type], when * IMPDOWN_WHENUNIT); ! 280: #endif ! 281: if (type != IMPDOWN_GOING && when) ! 282: impmsg(sc, "going down %s in %d minutes", ! 283: (u_int)impmessage[type], when * IMPDOWN_WHENUNIT); ! 284: else ! 285: impmsg(sc, "going down %s", (u_int)impmessage[type]); ! 286: if (sc->imp_state != IMPS_UP) ! 287: break; ! 288: if (type == IMPDOWN_GOING) { ! 289: sc->imp_state = IMPS_GOINGDOWN; ! 290: timeout(impdown, (caddr_t)sc, IMPTV_DOWN * hz); ! 291: } else if (when == 0) ! 292: sc->imp_state = IMPS_WINIT; ! 293: sc->imp_dropcnt = 0; ! 294: break; ! 295: } ! 296: ! 297: /* ! 298: * A NOP, usually seen during the initialization sequence. ! 299: * Compare the local address with that in the message. ! 300: * Reset the local address notion if it doesn't match. ! 301: */ ! 302: case IMPTYPE_NOOP: ! 303: #ifdef IMPINIT ! 304: if (imptraceinit) ! 305: log(imppri, "noop\n"); ! 306: #endif ! 307: if (sc->imp_state == IMPS_WINIT) { ! 308: sc->imp_dropcnt = 0; ! 309: impnoops(sc); ! 310: sc->imp_state = IMPS_INIT; ! 311: } ! 312: sc->imp_dropcnt++; ! 313: if (sc->imp_state == IMPS_INIT && cp->dl_imp != 0) { ! 314: struct in_addr leader_addr; ! 315: ! 316: sin = (struct sockaddr_in *)&sc->imp_if.if_addrlist->ifa_addr; ! 317: imp_leader_to_addr(&leader_addr, cp, &sc->imp_if); ! 318: if (sin->sin_addr.s_addr != leader_addr.s_addr) { ! 319: impmsg(sc, "address reset to x%x (%d/%d)", ! 320: ntohl(leader_addr.s_addr), ! 321: (u_int)cp->dl_host, ! 322: ntohs(cp->dl_imp)); ! 323: sin->sin_addr.s_addr = leader_addr.s_addr; ! 324: } ! 325: } ! 326: break; ! 327: ! 328: /* ! 329: * RFNM or INCOMPLETE message, decrement rfnm count ! 330: * and prepare to send next message. ! 331: * If the rfnm allows another queued ! 332: * message to be sent, bump msgready ! 333: * and start IMP if idle. ! 334: * We could pass incomplete's up to the next level, ! 335: * but this currently isn't needed. ! 336: * Pass "bad" incompletes and rfnms to the raw socket. ! 337: */ ! 338: case IMPTYPE_INCOMPLETE: ! 339: sc->imp_incomplete++; ! 340: /* FALL THROUGH */ ! 341: case IMPTYPE_RFNM: ! 342: if ((hp = hostlookup((int)cp->dl_imp, (int)cp->dl_host, ! 343: unit)) == 0 || hp->h_rfnm == 0) { ! 344: sc->imp_badrfnm++; ! 345: if (hp) ! 346: hostfree(hp); ! 347: break; ! 348: } ! 349: imprestarthost(sc, hp); ! 350: if (cp->dl_mtype == IMPTYPE_RFNM) ! 351: goto drop; ! 352: break; ! 353: ! 354: /* ! 355: * Host or IMP can't be reached. Flush any packets ! 356: * awaiting transmission and release the host structure. ! 357: * Enqueue for notifying protocols at software interrupt time. ! 358: */ ! 359: case IMPTYPE_HOSTDEAD: ! 360: case IMPTYPE_HOSTUNREACH: ! 361: if (hp = hostlookup((int)cp->dl_imp, (int)cp->dl_host, unit)) { ! 362: hp->h_flags |= (1 << (int)cp->dl_mtype); ! 363: sc->imp_msgready -= ! 364: MIN(hp->h_qcnt, IMP_MAXHOSTMSG - hp->h_rfnm); ! 365: hp->h_rfnm = 0; ! 366: hostflush(hp); ! 367: hp->h_timer = HOSTDEADTIMER; ! 368: } ! 369: break; ! 370: ! 371: /* ! 372: * Error in data. Clear RFNM status for this host and send ! 373: * noops to the IMP to clear the interface. ! 374: */ ! 375: case IMPTYPE_BADDATA: ! 376: impmsg(sc, "data error"); ! 377: if (hp = hostlookup((int)cp->dl_imp, (int)cp->dl_host, unit)) { ! 378: sc->imp_msgready -= ! 379: MIN(hp->h_qcnt, IMP_MAXHOSTMSG - hp->h_rfnm); ! 380: if (hp->h_rfnm) ! 381: hostrelease(hp); ! 382: else ! 383: hostfree(hp); ! 384: } ! 385: impnoops(sc); ! 386: break; ! 387: ! 388: /* ! 389: * Interface reset. ! 390: */ ! 391: case IMPTYPE_RESET: ! 392: #ifdef IMPINIT ! 393: if (imptraceinit) ! 394: log(imppri, "reset complete\n"); ! 395: #endif ! 396: if (sc->imp_state != IMPS_INIT) { ! 397: impmsg(sc, "interface reset"); ! 398: impnoops(sc); ! 399: } ! 400: /* clear RFNM counts */ ! 401: sc->imp_msgready = 0; ! 402: hostreset(unit); ! 403: if (sc->imp_state != IMPS_DOWN) { ! 404: sc->imp_state = IMPS_UP; ! 405: sc->imp_if.if_flags |= IFF_UP; ! 406: #ifdef IMPINIT ! 407: if (imptraceinit) ! 408: log(imppri, "IMP UP\n"); ! 409: #endif ! 410: } ! 411: break; ! 412: ! 413: default: ! 414: sc->imp_garbage++; ! 415: sc->imp_if.if_collisions++; /* XXX */ ! 416: break; ! 417: } ! 418: ! 419: if (inq == &impintrq) ! 420: schednetisr(NETISR_IMP); ! 421: s = splimp(); ! 422: if (!IF_QFULL(inq)) { ! 423: IF_ENQUEUE(inq, m); ! 424: splx(s); ! 425: return; ! 426: } ! 427: splx(s); ! 428: IF_DROP(inq); ! 429: drop: ! 430: m_freem(m); ! 431: #undef ip ! 432: } ! 433: ! 434: /* ! 435: * Bring the IMP down after notification. ! 436: */ ! 437: impdown(sc) ! 438: struct imp_softc *sc; ! 439: { ! 440: int s = splimp(); ! 441: ! 442: if (sc->imp_state == IMPS_GOINGDOWN) { ! 443: sc->imp_state = IMPS_WINIT; ! 444: impmsg(sc, "marked down"); ! 445: sc->imp_msgready = 0; ! 446: hostreset(sc->imp_if.if_unit); ! 447: if_down(&sc->imp_if); ! 448: } ! 449: #ifdef IMPINIT ! 450: else if (imptraceinit) ! 451: log(imppri, "impdown, state now %d (ignored)\n", sc->imp_state); ! 452: #endif ! 453: splx(s); ! 454: } ! 455: ! 456: /*VARARGS2*/ ! 457: impmsg(sc, fmt, a1) ! 458: struct imp_softc *sc; ! 459: char *fmt; ! 460: u_int a1; ! 461: { ! 462: ! 463: log(imppri, "imp%d: %r\n", sc->imp_if.if_unit, fmt, &a1); ! 464: } ! 465: ! 466: struct sockproto impproto = { PF_IMPLINK }; ! 467: struct sockaddr_in impdst = { sizeof (impdst), AF_INET }; ! 468: struct sockaddr_in impsrc = { sizeof (impsrc), AF_INET }; ! 469: ! 470: /* ! 471: * Pick up the IMP "error" messages enqueued earlier, ! 472: * passing these up to the higher level protocol ! 473: * and the raw interface. ! 474: */ ! 475: impintr() ! 476: { ! 477: register struct mbuf *m; ! 478: register struct control_leader *cp; ! 479: struct ifnet *ifp; ! 480: int s, code; ! 481: ! 482: for (;;) { ! 483: s = splimp(); ! 484: IF_DEQUEUEIF(&impintrq, m, ifp); ! 485: splx(s); ! 486: if (m == 0) ! 487: return; ! 488: ! 489: cp = mtod(m, struct control_leader *); ! 490: imp_leader_to_addr(&impsrc.sin_addr, cp, ifp); ! 491: impproto.sp_protocol = cp->dl_link; ! 492: impdst.sin_addr = IA_SIN(ifp->if_addrlist)->sin_addr; ! 493: ! 494: if (cp->dl_mtype == IMPTYPE_HOSTDEAD || ! 495: cp->dl_mtype == IMPTYPE_HOSTUNREACH) { ! 496: code = (cp->dl_mtype == IMPTYPE_HOSTDEAD) ? ! 497: PRC_HOSTDEAD : PRC_UNREACH_HOST; ! 498: switch (cp->dl_link) { ! 499: ! 500: case IMPLINK_IP: ! 501: pfctlinput(code, (struct sockaddr *)&impsrc); ! 502: break; ! 503: default: ! 504: raw_ctlinput(code, (struct sockaddr *)&impsrc); ! 505: break; ! 506: } ! 507: } ! 508: ! 509: raw_input(m, &impproto, (struct sockaddr *)&impsrc, ! 510: (struct sockaddr *)&impdst); ! 511: } ! 512: } ! 513: ! 514: /* ! 515: * ARPAnet 1822 output routine. ! 516: * Called from higher level protocol routines to set up messages for ! 517: * transmission to the imp. Sets up the header and calls impsnd to ! 518: * enqueue the message for this IMP's hardware driver. ! 519: */ ! 520: impoutput(ifp, m0, dst) ! 521: register struct ifnet *ifp; ! 522: struct mbuf *m0; ! 523: struct sockaddr *dst; ! 524: { ! 525: register struct imp_leader *imp; ! 526: register struct mbuf *m = m0; ! 527: caddr_t pkt = mtod(m, caddr_t); ! 528: int error = 0; ! 529: ! 530: /* ! 531: * Don't even try if the IMP is unavailable. ! 532: */ ! 533: if (!IMPS_RUNNING(imp_softc[ifp->if_unit].imp_state)) { ! 534: error = ENETDOWN; ! 535: goto drop; ! 536: } ! 537: ! 538: /* ! 539: * If AF_IMPLINK, leader exists; just send. ! 540: * Otherwise, construct leader according to address family. ! 541: */ ! 542: if (dst->sa_family != AF_IMPLINK) { ! 543: /* ! 544: * Add IMP leader. If there's not enough space in the ! 545: * first mbuf, allocate another. If that should fail, we ! 546: * drop this sucker. ! 547: */ ! 548: M_PREPEND(m, sizeof(struct imp_leadr), M_DONTWAIT); ! 549: imp = mtod(m, struct imp_leader *); ! 550: imp->il_format = IMP_NFF; ! 551: imp->il_mtype = IMPTYPE_DATA; ! 552: imp->il_flags = 0; ! 553: imp->il_htype = 0; ! 554: imp->il_subtype = 0; ! 555: ! 556: switch (dst->sa_family) { ! 557: ! 558: case AF_INET: ! 559: imp->il_link = IMPLINK_IP; ! 560: imp_addr_to_leader((struct control_leader *)imp, ! 561: ((struct sockaddr_in *)dst)->sin_addr.s_addr); ! 562: imp->il_length = htons(ntohs((u_short) ! 563: ((struct ip *)pkt)->ip_len) << 3); ! 564: break; ! 565: ! 566: default: ! 567: printf("imp%d: can't handle af%d\n", ifp->if_unit, ! 568: dst->sa_family); ! 569: error = EAFNOSUPPORT; ! 570: m0 = m; ! 571: goto drop; ! 572: } ! 573: } ! 574: return (impsnd(ifp, m)); ! 575: drop: ! 576: m_freem(m0); ! 577: return (error); ! 578: } ! 579: ! 580: /* ! 581: * Put a message on an interface's output queue. ! 582: * Perform RFNM counting: no more than 8 message may be ! 583: * in flight to any one host. ! 584: */ ! 585: impsnd(ifp, m) ! 586: struct ifnet *ifp; ! 587: struct mbuf *m; ! 588: { ! 589: register struct control_leader *imp; ! 590: register struct host *hp; ! 591: register struct imp_softc *sc = &imp_softc[ifp->if_unit]; ! 592: int s, error = 0; ! 593: ! 594: imp = mtod(m, struct control_leader *); ! 595: ! 596: /* ! 597: * Do RFNM counting for data messages ! 598: * (no more than 8 outstanding to any host). ! 599: * Queue data messages per host if 8 are already outstanding ! 600: * or if the hardware interface is already doing output. ! 601: * Increment imp_msgready if the message could be sent now, ! 602: * but must be queued because the imp output is busy. ! 603: */ ! 604: s = splimp(); ! 605: if (imp->dl_mtype == IMPTYPE_DATA) { ! 606: hp = hostenter((int)imp->dl_imp, (int)imp->dl_host, ! 607: ifp->if_unit); ! 608: if (hp) { ! 609: if (hp->h_flags & (HF_DEAD|HF_UNREACH)) ! 610: error = hp->h_flags & HF_DEAD ? ! 611: EHOSTDOWN : EHOSTUNREACH; ! 612: else if (hp->h_rfnm < IMP_MAXHOSTMSG && ! 613: sc->imp_cb.ic_oactive == 0) { ! 614: /* ! 615: * Send without queuing; ! 616: * adjust rfnm count and timer. ! 617: */ ! 618: if (hp->h_rfnm++ == 0) ! 619: hp->h_timer = RFNMTIMER; ! 620: goto send; ! 621: } else if (hp->h_rfnm + hp->h_qcnt < imphqlen) { ! 622: HOST_ENQUE(hp, m); ! 623: if (hp->h_rfnm + hp->h_qcnt <= IMP_MAXHOSTMSG) ! 624: sc->imp_msgready++; ! 625: } else { ! 626: error = ENOBUFS; ! 627: IF_DROP(&ifp->if_snd); ! 628: } ! 629: } else ! 630: error = ENOBUFS; ! 631: } else if (sc->imp_cb.ic_oactive == 0) ! 632: goto send; ! 633: else ! 634: IF_ENQUEUE(&ifp->if_snd, m); ! 635: ! 636: splx(s); ! 637: if (error) ! 638: m_freem(m); ! 639: return (error); ! 640: ! 641: send: ! 642: sc->imp_if.if_timer = IMP_OTIMER; ! 643: (*sc->imp_cb.ic_output)(sc->imp_cb.ic_hwunit, m); ! 644: splx(s); ! 645: return (0); ! 646: } ! 647: ! 648: /* ! 649: * Start another output operation on IMP; called from hardware ! 650: * transmit-complete interrupt routine at splimp or from imp routines ! 651: * when output is not in progress. If there are any packets on shared ! 652: * output queue, send them, otherwise send the next data packet for a host. ! 653: * Host data packets are sent round-robin based on destination by walking ! 654: * the host list. ! 655: */ ! 656: impstart(sc) ! 657: register struct imp_softc *sc; ! 658: { ! 659: register struct mbuf *m; ! 660: int first = 1; /* XXX */ ! 661: register struct host *hp; ! 662: int index; ! 663: ! 664: IF_DEQUEUE(&sc->imp_if.if_snd, m); ! 665: if (m) { ! 666: sc->imp_if.if_timer = IMP_OTIMER; ! 667: (*sc->imp_cb.ic_output)(sc->imp_cb.ic_hwunit, m); ! 668: return; ! 669: } ! 670: if (sc->imp_msgready) { ! 671: if ((m = sc->imp_hostq) == 0 && (m = sc->imp_hosts) == 0) ! 672: panic("imp msgready"); ! 673: index = sc->imp_hostent; ! 674: for (hp = &mtod(m, struct hmbuf *)->hm_hosts[index]; ; ! 675: hp++, index++) { ! 676: if (index >= HPMBUF) { ! 677: if ((m = m->m_next) == 0) ! 678: m = sc->imp_hosts; ! 679: index = 0; ! 680: hp = mtod(m, struct hmbuf *)->hm_hosts; ! 681: first = 0; /* XXX */ ! 682: } ! 683: if (hp->h_qcnt && hp->h_rfnm < IMP_MAXHOSTMSG) { ! 684: /* ! 685: * Found host entry with another message ! 686: * to send. Deliver it to the IMP. ! 687: * Start with succeeding host next time. ! 688: */ ! 689: impstarthost(sc, hp); ! 690: sc->imp_hostq = m; ! 691: sc->imp_hostent = index + 1; ! 692: return; ! 693: } ! 694: if (m == sc->imp_hostq && !first && ! 695: index + 1 >= sc->imp_hostent) { /* XXX */ ! 696: log(imppri, "imp: can't find %d msgready\n", ! 697: sc->imp_msgready); ! 698: sc->imp_msgready = 0; ! 699: break; ! 700: } ! 701: } ! 702: } ! 703: sc->imp_if.if_timer = 0; ! 704: } ! 705: ! 706: /* ! 707: * Restart output for a host that has received a RFNM ! 708: * or incomplete or has timed out while waiting for a RFNM. ! 709: * Must be called at splimp. ! 710: */ ! 711: imprestarthost(sc, hp) ! 712: register struct imp_softc *sc; ! 713: struct host *hp; ! 714: { ! 715: ! 716: if (--hp->h_rfnm > 0) ! 717: hp->h_timer = RFNMTIMER; ! 718: /* ! 719: * If the RFNM moved a queued message into the window, ! 720: * update msgready and start IMP if idle. ! 721: */ ! 722: if (hp->h_qcnt > IMP_MAXHOSTMSG - 1 - hp->h_rfnm) { ! 723: sc->imp_msgready++; ! 724: if (sc->imp_cb.ic_oactive == 0) ! 725: impstarthost(sc, hp); ! 726: } ! 727: if (hp->h_rfnm == 0 && hp->h_qcnt == 0) ! 728: hostidle(hp); ! 729: } ! 730: ! 731: /* ! 732: * Send the next message queued for a host ! 733: * when ready to send another message to the IMP. ! 734: * Called only when output is not in progress. ! 735: * Bump RFNM counter and start RFNM timer ! 736: * when we send the message to the IMP. ! 737: * Must be called at splimp. ! 738: */ ! 739: impstarthost(sc, hp) ! 740: register struct imp_softc *sc; ! 741: register struct host *hp; ! 742: { ! 743: struct mbuf *m; ! 744: ! 745: if (hp->h_rfnm++ == 0) ! 746: hp->h_timer = RFNMTIMER; ! 747: HOST_DEQUE(hp, m); ! 748: sc->imp_if.if_timer = IMP_OTIMER; ! 749: (*sc->imp_cb.ic_output)(sc->imp_cb.ic_hwunit, m); ! 750: sc->imp_msgready--; ! 751: } ! 752: ! 753: /* ! 754: * "Watchdog" timeout. When the output timer expires, ! 755: * we assume we have been blocked by the imp. ! 756: * No need to restart, just collect statistics. ! 757: */ ! 758: imptimo(unit) ! 759: int unit; ! 760: { ! 761: ! 762: imp_softc[unit].imp_block++; ! 763: } ! 764: ! 765: /* ! 766: * Put three 1822 NOOPs at the head of the output queue. ! 767: * Part of host-IMP initialization procedure. ! 768: * (Should return success/failure, but noone knows ! 769: * what to do with this, so why bother?) ! 770: * This routine is always called at splimp, so we don't ! 771: * protect the call to IF_PREPEND. ! 772: */ ! 773: impnoops(sc) ! 774: register struct imp_softc *sc; ! 775: { ! 776: register i; ! 777: register struct mbuf *m; ! 778: register struct control_leader *cp; ! 779: ! 780: #ifdef IMPINIT ! 781: if (imptraceinit) ! 782: log(imppri, "impnoops\n"); ! 783: #endif ! 784: for (i = 0; i < IMP_NOOPCNT; i++) { ! 785: if ((m = m_getclr(M_DONTWAIT, MT_HEADER)) == 0) ! 786: return; ! 787: m->m_len = sizeof(struct control_leader); ! 788: cp = mtod(m, struct control_leader *); ! 789: cp->dl_format = IMP_NFF; ! 790: cp->dl_link = i; ! 791: cp->dl_mtype = IMPTYPE_NOOP; ! 792: IF_PREPEND(&sc->imp_if.if_snd, m); ! 793: } ! 794: if (sc->imp_cb.ic_oactive == 0) ! 795: impstart(sc); ! 796: } ! 797: ! 798: /* ! 799: * Process an ioctl request. ! 800: */ ! 801: impioctl(ifp, cmd, data) ! 802: register struct ifnet *ifp; ! 803: int cmd; ! 804: caddr_t data; ! 805: { ! 806: struct ifaddr *ifa = (struct ifaddr *) data; ! 807: int s = splimp(), error = 0; ! 808: #define sc ((struct imp_softc *)ifp) ! 809: ! 810: switch (cmd) { ! 811: ! 812: case SIOCSIFADDR: ! 813: if (ifa->ifa_addr.sa_family != AF_INET) { ! 814: error = EINVAL; ! 815: break; ! 816: } ! 817: if ((ifp->if_flags & IFF_UP) == 0) ! 818: impinit(ifp->if_unit); ! 819: break; ! 820: ! 821: case SIOCSIFFLAGS: ! 822: if ((ifp->if_flags & IFF_UP) == 0 && ! 823: sc->imp_state != IMPS_DOWN) { ! 824: if (sc->imp_cb.ic_down && ! 825: (*sc->imp_cb.ic_down)(sc->imp_cb.ic_hwunit)) { ! 826: sc->imp_state = IMPS_DOWN; ! 827: sc->imp_msgready = 0; ! 828: hostreset(ifp->if_unit); ! 829: if_down(ifp); ! 830: } ! 831: } else if (ifp->if_flags & IFF_UP && sc->imp_state == IMPS_DOWN) ! 832: impinit(ifp->if_unit); ! 833: break; ! 834: ! 835: default: ! 836: error = EINVAL; ! 837: break; ! 838: } ! 839: splx(s); ! 840: return (error); ! 841: } ! 842: ! 843: #ifdef IMPLEADERS ! 844: printleader(routine, ip) ! 845: char *routine; ! 846: register struct imp_leader *ip; ! 847: { ! 848: printf("%s: ", routine); ! 849: printbyte((char *)ip, 12); ! 850: printf("<fmt=%x,net=%x,flags=%x,mtype=", ip->il_format, ip->il_network, ! 851: ip->il_flags); ! 852: if (ip->il_mtype <= IMPTYPE_READY) ! 853: printf("%s,", impleaders[ip->il_mtype]); ! 854: else ! 855: printf("%x,", ip->il_mtype); ! 856: printf("htype=%x,host=%x,imp=%x,link=", ip->il_htype, ip->il_host, ! 857: ntohs(ip->il_imp)); ! 858: if (ip->il_link == IMPLINK_IP) ! 859: printf("ip,"); ! 860: else ! 861: printf("%x,", ip->il_link); ! 862: printf("subtype=%x,len=%x>\n",ip->il_subtype,ntohs(ip->il_length)>>3); ! 863: } ! 864: ! 865: printbyte(cp, n) ! 866: register char *cp; ! 867: int n; ! 868: { ! 869: register i, j, c; ! 870: ! 871: for (i=0; i<n; i++) { ! 872: c = *cp++; ! 873: for (j=0; j<2; j++) ! 874: putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf], 0); ! 875: putchar(' ', 0); ! 876: } ! 877: putchar('\n', 0); ! 878: } ! 879: #endif ! 880: ! 881: /* ! 882: * Routine to convert from IMP Leader to InterNet Address. ! 883: * ! 884: * This procedure is necessary because IMPs may be assigned Class A, B, or C ! 885: * network numbers, but only have 8 bits in the leader to reflect the ! 886: * IMP "network number". The strategy is to take the network number from ! 887: * the ifnet structure, and blend in the host-on-imp and imp-on-net numbers ! 888: * from the leader. ! 889: * ! 890: * There is no support for "Logical Hosts". ! 891: * ! 892: * Class A: Net.Host.0.Imp ! 893: * Class B: Net.net.Host.Imp ! 894: * Class C: Net.net.net.(Host4|Imp4) ! 895: */ ! 896: imp_leader_to_addr(ap, cp, ifp) ! 897: struct in_addr *ap; ! 898: register struct control_leader *cp; ! 899: struct ifnet *ifp; ! 900: { ! 901: register u_long final; ! 902: register struct sockaddr_in *sin; ! 903: int imp = ntohs(cp->dl_imp); ! 904: ! 905: sin = (struct sockaddr_in *)(&ifp->if_addrlist->ifa_addr); ! 906: final = ntohl(sin->sin_addr.s_addr); ! 907: ! 908: if (IN_CLASSA(final)) { ! 909: final &= IN_CLASSA_NET; ! 910: final |= (imp & 0xFF) | ((cp->dl_host & 0xFF)<<16); ! 911: } else if (IN_CLASSB(final)) { ! 912: final &= IN_CLASSB_NET; ! 913: final |= (imp & 0xFF) | ((cp->dl_host & 0xFF)<<8); ! 914: } else { ! 915: final &= IN_CLASSC_NET; ! 916: final |= (imp & 0x0F) | ((cp->dl_host & 0x0F)<<4); ! 917: } ! 918: ap->s_addr = htonl(final); ! 919: } ! 920: ! 921: /* ! 922: * Function to take InterNet address and fill in IMP leader fields. ! 923: */ ! 924: imp_addr_to_leader(imp, a) ! 925: register struct control_leader *imp; ! 926: u_long a; ! 927: { ! 928: register u_long addr = ntohl(a); ! 929: ! 930: imp->dl_network = 0; /* !! */ ! 931: ! 932: if (IN_CLASSA(addr)) { ! 933: imp->dl_host = ((addr>>16) & 0xFF); ! 934: imp->dl_imp = addr & 0xFF; ! 935: } else if (IN_CLASSB(addr)) { ! 936: imp->dl_host = ((addr>>8) & 0xFF); ! 937: imp->dl_imp = addr & 0xFF; ! 938: } else { ! 939: imp->dl_host = ((addr>>4) & 0xF); ! 940: imp->dl_imp = addr & 0xF; ! 941: } ! 942: imp->dl_imp = htons(imp->dl_imp); ! 943: } ! 944: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.