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