home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / netimp / if_imp.c next >
Encoding:
C/C++ Source or Header  |  1991-05-07  |  23.1 KB  |  945 lines

  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
  945.