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