BSD 4_2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Fri, 29 Jul 1983 00:16:00 +0000 (16:16 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Fri, 29 Jul 1983 00:16:00 +0000 (16:16 -0800)
Work on file usr/src/sys/netimp/if_imphost.c
Work on file usr/src/sys/netimp/if_imp.c
Work on file usr/src/sys/netimp/if_imp.h
Work on file usr/src/sys/netimp/raw_imp.c
Work on file usr/src/sys/netimp/if_imphost.h

Synthesized-from: CSRG/cd1/4.2

usr/src/sys/netimp/if_imp.c [new file with mode: 0644]
usr/src/sys/netimp/if_imp.h [new file with mode: 0644]
usr/src/sys/netimp/if_imphost.c [new file with mode: 0644]
usr/src/sys/netimp/if_imphost.h [new file with mode: 0644]
usr/src/sys/netimp/raw_imp.c [new file with mode: 0644]

diff --git a/usr/src/sys/netimp/if_imp.c b/usr/src/sys/netimp/if_imp.c
new file mode 100644 (file)
index 0000000..fb08167
--- /dev/null
@@ -0,0 +1,661 @@
+/*     if_imp.c        6.1     83/07/29        */
+
+#include "imp.h"
+#if NIMP > 0
+/*
+ * ARPANET IMP interface driver.
+ *
+ * The IMP-host protocol is handled here, leaving
+ * hardware specifics to the lower level interface driver.
+ *
+ * NB: only handles IMPS on class A networks.
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/mbuf.h"
+#include "../h/buf.h"
+#include "../h/protosw.h"
+#include "../h/socket.h"
+#include "../h/vmmac.h"
+#include "../h/time.h"
+#include "../h/kernel.h"
+#include "../h/errno.h"
+#include "../h/ioctl.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+#include "../net/if.h"
+#include "../net/route.h"
+
+#include "../net/netisr.h"
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+/* define IMPLEADERS here to get leader printing code */
+#include "../netimp/if_imp.h"
+#include "../netimp/if_imphost.h"
+
+/*
+ * IMP software status per interface.
+ * (partially shared with the hardware specific module)
+ *
+ * Each interface is referenced by a network interface structure,
+ * imp_if, which the routing code uses to locate the interface.
+ * This structure contains the output queue for the interface, its
+ * address, ...  IMP specific structures used in connecting the
+ * IMP software modules to the hardware specific interface routines
+ * are stored here.  The common structures are made visible to the
+ * interface driver by passing a pointer to the hardware routine
+ * at "attach" time.
+ *
+ * NOTE: imp_if and imp_cb are assumed adjacent in hardware code.
+ */
+struct imp_softc {
+       struct  ifnet imp_if;           /* network visible interface */
+       struct  impcb imp_cb;           /* hooks to hardware module */
+       u_char  imp_state;              /* current state of IMP */
+       char    imp_dropcnt;            /* used during initialization */
+} imp_softc[NIMP];
+
+/*
+ * Messages from IMP regarding why
+ * it's going down.
+ */
+static char *impmessage[] = {
+       "in 30 seconds",
+       "for hardware PM",
+       "to reload software",
+       "for emergency reset"
+};
+
+int    impdown(), impinit(), impioctl(), impoutput();
+
+/*
+ * IMP attach routine.  Called from hardware device attach routine
+ * at configuration time with a pointer to the UNIBUS device structure.
+ * Sets up local state and returns pointer to base of ifnet+impcb
+ * structures.  This is then used by the device's attach routine
+ * set up its back pointers. 
+ */
+impattach(ui, reset)
+       struct uba_device *ui;
+       int (*reset)();
+{
+       struct imp_softc *sc = &imp_softc[ui->ui_unit];
+       register struct ifnet *ifp = &sc->imp_if;
+
+       /* UNIT COULD BE AMBIGUOUS */
+       ifp->if_unit = ui->ui_unit;
+       ifp->if_name = "imp";
+       ifp->if_mtu = IMPMTU - sizeof(struct imp_leader);
+       ifp->if_reset = reset;
+       ifp->if_init = impinit;
+       ifp->if_ioctl = impioctl;
+       ifp->if_output = impoutput;
+       /* reset is handled at the hardware level */
+       if_attach(ifp);
+       return ((int)&sc->imp_if);
+}
+
+/*
+ * IMP initialization routine: call hardware module to
+ * setup UNIBUS resources, init state and get ready for
+ * NOOPs the IMP should send us, and that we want to drop.
+ */
+impinit(unit)
+       int unit;
+{
+       int s = splimp();
+       register struct imp_softc *sc = &imp_softc[unit];
+       struct sockaddr_in *sin;
+
+       sin = (struct sockaddr_in *)&sc->imp_if.if_addr;
+       if (in_netof(sin->sin_addr) == 0)
+               return;
+       if ((*sc->imp_cb.ic_init)(unit) == 0) {
+               sc->imp_state = IMPS_DOWN;
+               sc->imp_if.if_flags &= ~IFF_UP;
+               splx(s);
+               return;
+       }
+       sc->imp_if.if_flags |= IFF_RUNNING;
+       sc->imp_state = IMPS_INIT;
+       impnoops(sc);
+       splx(s);
+}
+
+struct sockproto impproto = { PF_IMPLINK };
+struct sockaddr_in impdst = { AF_IMPLINK };
+struct sockaddr_in impsrc = { AF_IMPLINK };
+#ifdef IMPLEADERS
+int    impprintfs = 0;
+#endif
+
+/*
+ * ARPAnet 1822 input routine.
+ * Called from hardware input interrupt routine to handle 1822
+ * IMP-host messages.  Type 0 messages (non-control) are
+ * passed to higher level protocol processors on the basis
+ * of link number.  Other type messages (control) are handled here.
+ */
+impinput(unit, m)
+       int unit;
+       register struct mbuf *m;
+{
+       register struct imp_leader *ip;
+       register struct imp_softc *sc = &imp_softc[unit];
+       register struct host *hp;
+       register struct ifqueue *inq;
+       struct control_leader *cp;
+       struct in_addr addr;
+       struct mbuf *next;
+       struct sockaddr_in *sin;
+
+       /* verify leader length. */
+       if (m->m_len < sizeof(struct control_leader) &&
+           (m = m_pullup(m, sizeof(struct control_leader))) == 0)
+               return;
+       cp = mtod(m, struct control_leader *);
+       if (cp->dl_mtype == IMPTYPE_DATA)
+               if (m->m_len < sizeof(struct imp_leader) &&
+                   (m = m_pullup(m, sizeof(struct imp_leader))) == 0)
+                       return;
+       ip = mtod(m, struct imp_leader *);
+#ifdef IMPLEADERS
+       if (impprintfs)
+               printleader("impinput", ip);
+#endif
+
+       /* check leader type */
+       if (ip->il_format != IMP_NFF) {
+               sc->imp_if.if_collisions++;     /* XXX */
+               goto drop;
+       }
+
+       if (ip->il_mtype != IMPTYPE_DATA) {
+#ifdef notdef
+               addr.s_net = ip->il_network;
+#else
+               addr.s_net = sc->imp_if.if_net;
+#endif
+               addr.s_imp = ip->il_imp;
+               addr.s_host = ip->il_host;
+       }
+       switch (ip->il_mtype) {
+
+       case IMPTYPE_DATA:
+               break;
+
+       /*
+        * IMP leader error.  Reset the IMP and discard the packet.
+        */
+       case IMPTYPE_BADLEADER:
+               /*
+                * According to 1822 document, this message
+                * will be generated in response to the
+                * first noop sent to the IMP after
+                * the host resets the IMP interface.
+                */
+               if (sc->imp_state != IMPS_INIT) {
+                       impmsg(sc, "leader error");
+                       hostreset(sc->imp_if.if_net);
+                       impnoops(sc);
+               }
+               goto drop;
+
+       /*
+        * IMP going down.  Print message, and if not immediate,
+        * set off a timer to insure things will be reset at the
+        * appropriate time.
+        */
+       case IMPTYPE_DOWN:
+               if (sc->imp_state < IMPS_INIT)
+                       goto drop;
+               if ((ip->il_link & IMP_DMASK) == 0) {
+                       sc->imp_state = IMPS_GOINGDOWN;
+                       timeout(impdown, (caddr_t)sc, 30 * hz);
+               }
+               impmsg(sc, "going down %s",
+                       (u_int)impmessage[ip->il_link&IMP_DMASK]);
+               goto drop;
+
+       /*
+        * A NOP usually seen during the initialization sequence.
+        * Compare the local address with that in the message.
+        * Reset the local address notion if it doesn't match.
+        */
+       case IMPTYPE_NOOP:
+               if (sc->imp_state == IMPS_DOWN) {
+                       sc->imp_state = IMPS_INIT;
+                       sc->imp_dropcnt = IMP_DROPCNT;
+               }
+               if (sc->imp_state == IMPS_INIT && --sc->imp_dropcnt > 0)
+                       goto drop;
+               sin = (struct sockaddr_in *)&sc->imp_if.if_addr;
+               if (sin->sin_addr.s_host != ip->il_host ||
+                   sin->sin_addr.s_imp != ip->il_imp) {
+                       sc->imp_if.if_host[0] =
+                               sin->sin_addr.s_host = ip->il_host;
+                       sin->sin_addr.s_imp = ip->il_imp;
+                       impmsg(sc, "reset (host %d/imp %d)", (u_int)ip->il_host,
+                               ntohs(ip->il_imp));
+               }
+               sc->imp_state = IMPS_UP;
+               sc->imp_if.if_flags |= IFF_UP;
+               if_rtinit(&sc->imp_if, RTF_UP);
+               goto drop;
+
+       /*
+        * RFNM or INCOMPLETE message, send next
+        * message on the q.  We could pass incomplete's
+        * up to the next level, but this currently isn't
+        * needed.
+        */
+       case IMPTYPE_RFNM:
+       case IMPTYPE_INCOMPLETE:
+               if (hp = hostlookup(addr)) {
+                       if (hp->h_rfnm == 0)
+                               hp->h_flags &= ~HF_INUSE;
+                       else if (next = hostdeque(hp))
+                               (void) impsnd(&sc->imp_if, next);
+               }
+               goto drop;
+
+       /*
+        * Host or IMP can't be reached.  Flush any packets
+        * awaiting transmission and release the host structure.
+        */
+       case IMPTYPE_HOSTDEAD:
+       case IMPTYPE_HOSTUNREACH:
+               impnotify((int)ip->il_mtype, (struct control_leader *)ip,
+                   hostlookup(addr));
+               goto rawlinkin;
+
+       /*
+        * Error in data.  Clear RFNM status for this host and send
+        * noops to the IMP to clear the interface.
+        */
+       case IMPTYPE_BADDATA:
+               impmsg(sc, "data error");
+               if (hp = hostlookup(addr))
+                       hp->h_rfnm = 0;
+               impnoops(sc);
+               goto drop;
+
+       /*
+        * Interface reset.
+        */
+       case IMPTYPE_RESET:
+               impmsg(sc, "interface reset");
+               impnoops(sc);
+               goto drop;
+
+       default:
+               sc->imp_if.if_collisions++;             /* XXX */
+               goto drop;
+       }
+
+       /*
+        * Data for a protocol.  Dispatch to the appropriate
+        * protocol routine (running at software interrupt).
+        * If this isn't a raw interface, advance pointer
+        * into mbuf past leader.
+        */
+       switch (ip->il_link) {
+
+#ifdef INET
+       case IMPLINK_IP:
+               m->m_len -= sizeof(struct imp_leader);
+               m->m_off += sizeof(struct imp_leader);
+               schednetisr(NETISR_IP);
+               inq = &ipintrq;
+               break;
+#endif
+
+       default:
+       rawlinkin:
+               impproto.sp_protocol = ip->il_link;
+               sin = (struct sockaddr_in *)&sc->imp_if.if_addr;
+               impdst.sin_addr = sin->sin_addr;;
+               impsrc.sin_addr.s_net = ip->il_network;
+               impsrc.sin_addr.s_host = ip->il_host;
+               impsrc.sin_addr.s_imp = ip->il_imp;
+               raw_input(m, &impproto, (struct sockaddr *)&impsrc,
+                 (struct sockaddr *)&impdst);
+               return;
+       }
+       if (IF_QFULL(inq)) {
+               IF_DROP(inq);
+               goto drop;
+       }
+       IF_ENQUEUE(inq, m);
+       return;
+
+drop:
+       m_freem(m);
+}
+
+/*
+ * Bring the IMP down after notification.
+ */
+impdown(sc)
+       struct imp_softc *sc;
+{
+       int s = splimp();
+
+       sc->imp_state = IMPS_DOWN;
+       impmsg(sc, "marked down");
+       hostreset(sc->imp_if.if_net);
+       if_down(&sc->imp_if);
+       splx(s);
+}
+
+/*VARARGS*/
+impmsg(sc, fmt, a1, a2)
+       struct imp_softc *sc;
+       char *fmt;
+       u_int a1;
+{
+
+       printf("imp%d: ", sc->imp_if.if_unit);
+       printf(fmt, a1, a2);
+       printf("\n");
+}
+
+/*
+ * Process an IMP "error" message, passing this
+ * up to the higher level protocol.
+ */
+impnotify(what, cp, hp)
+       int what;
+       struct control_leader *cp;
+       struct host *hp;
+{
+       struct in_addr in;
+
+#ifdef notdef
+       in.s_net = cp->dl_network;
+#else
+       in.s_net = 10;                  /* XXX */
+#endif
+       in.s_host = cp->dl_host;
+       in.s_imp = cp->dl_imp;
+       if (cp->dl_link != IMPLINK_IP)
+               raw_ctlinput(what, (caddr_t)&in);
+       else
+               ip_ctlinput(what, (caddr_t)&in);
+       if (hp) {
+               hp->h_flags |= (1 << what);
+               hostfree(hp);
+       }
+}
+
+/*
+ * ARPAnet 1822 output routine.
+ * Called from higher level protocol routines to set up messages for
+ * transmission to the imp.  Sets up the header and calls impsnd to
+ * enqueue the message for this IMP's hardware driver.
+ */
+impoutput(ifp, m0, dst)
+       register struct ifnet *ifp;
+       struct mbuf *m0;
+       struct sockaddr *dst;
+{
+       register struct imp_leader *imp;
+       register struct mbuf *m = m0;
+       int dhost, dimp, dlink, len, dnet;
+       int error = 0;
+
+       /*
+        * Don't even try if the IMP is unavailable.
+        */
+       if (imp_softc[ifp->if_unit].imp_state != IMPS_UP) {
+               error = ENETDOWN;
+               goto drop;
+       }
+
+       switch (dst->sa_family) {
+
+#ifdef INET
+       case AF_INET: {
+               struct ip *ip = mtod(m0, struct ip *);
+               struct sockaddr_in *sin = (struct sockaddr_in *)dst;
+
+               dhost = sin->sin_addr.s_host;
+               dimp = sin->sin_addr.s_impno;
+               dlink = IMPLINK_IP;
+               dnet = 0;
+               len = ntohs((u_short)ip->ip_len);
+               break;
+       }
+#endif
+       case AF_IMPLINK:
+               goto leaderexists;
+
+       default:
+               printf("imp%d: can't handle af%d\n", ifp->if_unit, 
+                       dst->sa_family);
+               error = EAFNOSUPPORT;
+               goto drop;
+       }
+
+       /*
+        * Add IMP leader.  If there's not enough space in the
+        * first mbuf, allocate another.  If that should fail, we
+        * drop this sucker.
+        */
+       if (m->m_off > MMAXOFF ||
+           MMINOFF + sizeof(struct imp_leader) > m->m_off) {
+               m = m_get(M_DONTWAIT, MT_HEADER);
+               if (m == 0) {
+                       error = ENOBUFS;
+                       goto drop;
+               }
+               m->m_next = m0;
+               m->m_len = sizeof(struct imp_leader);
+       } else {
+               m->m_off -= sizeof(struct imp_leader);
+               m->m_len += sizeof(struct imp_leader);
+       }
+       imp = mtod(m, struct imp_leader *);
+       imp->il_format = IMP_NFF;
+       imp->il_mtype = IMPTYPE_DATA;
+       imp->il_network = dnet;
+       imp->il_host = dhost;
+       imp->il_imp = htons((u_short)dimp);
+       imp->il_length =
+               htons((u_short)(len + sizeof(struct imp_leader)) << 3);
+       imp->il_link = dlink;
+       imp->il_flags = imp->il_htype = imp->il_subtype = 0;
+
+leaderexists:
+       return (impsnd(ifp, m));
+drop:
+       m_freem(m0);
+       return (error);
+}
+
+/* 
+ * Put a message on an interface's output queue. 
+ * Perform RFNM counting: no more than 8 message may be
+ * in flight to any one host.
+ */
+impsnd(ifp, m)             
+       struct ifnet *ifp;
+       struct mbuf *m;
+{
+       register struct imp_leader *ip;
+       register struct host *hp;
+       struct impcb *icp;
+       int s, error;
+
+       ip = mtod(m, struct imp_leader *);
+
+       /*
+        * Do RFNM counting for data messages
+        * (no more than 8 outstanding to any host)
+        */ 
+       s = splimp();
+       if (ip->il_mtype == IMPTYPE_DATA) {
+               struct in_addr addr;
+
+#ifdef notdef
+                addr.s_net = ip->il_network;
+#else
+               addr.s_net = ifp->if_net;       /* XXX */
+#endif
+                addr.s_host = ip->il_host;
+                addr.s_imp = ip->il_imp;
+               if ((hp = hostlookup(addr)) == 0)
+                       hp = hostenter(addr);
+               if (hp && (hp->h_flags & (HF_DEAD|HF_UNREACH))) {
+                       error = hp->h_flags&HF_DEAD ? EHOSTDOWN : EHOSTUNREACH;
+                       hp->h_timer = HOSTTIMER;
+                       hp->h_flags &= ~HF_INUSE;
+                       goto bad;
+               }
+
+               /*
+                * If IMP would block, queue until RFNM
+                */
+               if (hp) {
+                       if (hp->h_rfnm < 8) {
+                               hp->h_rfnm++;
+                               goto enque;
+                       }
+                       if (hp->h_qcnt < 8) {   /* high water mark */
+                               HOST_ENQUE(hp, m);
+                               goto start;
+                       }
+               }
+               error = ENOBUFS;
+               goto bad;
+       }
+enque:
+       if (IF_QFULL(&ifp->if_snd)) {
+               IF_DROP(&ifp->if_snd);
+               error = ENOBUFS;
+bad:
+               m_freem(m);
+               splx(s);
+               return (error);
+       }
+       IF_ENQUEUE(&ifp->if_snd, m);
+start:
+       icp = &imp_softc[ifp->if_unit].imp_cb;
+       if (icp->ic_oactive == 0)
+               (*icp->ic_start)(ifp->if_unit);
+       splx(s);
+       return (0);
+}
+
+/*
+ * Put three 1822 NOOPs at the head of the output queue. 
+ * Part of host-IMP initialization procedure.
+ * (Should return success/failure, but noone knows
+ * what to do with this, so why bother?)
+ * This routine is always called at splimp, so we don't
+ * protect the call to IF_PREPEND.
+ */
+impnoops(sc)             
+       register struct imp_softc *sc;
+{
+       register i;
+       register struct mbuf *m;
+       register struct control_leader *cp;
+
+       sc->imp_dropcnt = IMP_DROPCNT;
+       for (i = 0; i < IMP_DROPCNT + 1; i++ ) { 
+               if ((m = m_getclr(M_DONTWAIT, MT_HEADER)) == 0) 
+                       return;
+               m->m_len = sizeof(struct control_leader);
+               cp = mtod(m, struct control_leader *);
+               cp->dl_format = IMP_NFF;
+                cp->dl_link = i;
+                cp->dl_mtype = IMPTYPE_NOOP;
+               IF_PREPEND(&sc->imp_if.if_snd, m);
+       }
+       if (sc->imp_cb.ic_oactive == 0)
+               (*sc->imp_cb.ic_start)(sc->imp_if.if_unit);
+}
+
+/*
+ * Process an ioctl request.
+ */
+impioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
+{
+       struct ifreq *ifr = (struct ifreq *)data;
+       struct sockaddr_in *sin;
+       int s = splimp(), error = 0;
+
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, -1);     /* delete previous route */
+               sin = (struct sockaddr_in *)&ifr->ifr_addr;
+               ifp->if_net = in_netof(sin->sin_addr);
+               sin = (struct sockaddr_in *)&ifp->if_addr;
+               sin->sin_family = AF_INET;
+               /* host number filled in already, or filled in later */
+               sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, RTF_UP);
+               else
+                       impinit(ifp->if_unit);
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       splx(s);
+       return (error);
+}
+
+#ifdef IMPLEADERS
+printleader(routine, ip)
+       char *routine;
+       register struct imp_leader *ip;
+{
+       printf("%s: ", routine);
+       printbyte((char *)ip, 12);
+       printf("<fmt=%x,net=%x,flags=%x,mtype=", ip->il_format, ip->il_network,
+               ip->il_flags);
+       if (ip->il_mtype <= IMPTYPE_READY)
+               printf("%s,", impleaders[ip->il_mtype]);
+       else
+               printf("%x,", ip->il_mtype);
+       printf("htype=%x,host=%x,imp=%x,link=", ip->il_htype, ip->il_host,
+               ntohs(ip->il_imp));
+       if (ip->il_link == IMPLINK_IP)
+               printf("ip,");
+       else
+               printf("%x,", ip->il_link);
+       printf("subtype=%x,len=%x>\n",ip->il_subtype,ntohs(ip->il_length)>>3);
+}
+
+printbyte(cp, n)
+       register char *cp;
+       int n;
+{
+       register i, j, c;
+
+       for (i=0; i<n; i++) {
+               c = *cp++;
+               for (j=0; j<2; j++)
+                       putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf]);
+               putchar(' ');
+       }
+       putchar('\n');
+}
+#endif
+#endif
diff --git a/usr/src/sys/netimp/if_imp.h b/usr/src/sys/netimp/if_imp.h
new file mode 100644 (file)
index 0000000..d1b6bc7
--- /dev/null
@@ -0,0 +1,154 @@
+/*     if_imp.h        6.1     83/07/29        */
+
+/*
+ * Structure of IMP 1822 long leader.
+ */
+struct control_leader {
+       u_char  dl_format;      /* leader format */
+       u_char  dl_network;     /* src/dest network */
+       u_char  dl_flags;       /* leader flags */
+       u_char  dl_mtype;       /* message type */
+       u_char  dl_htype;       /* handling type */
+       u_char  dl_host;        /* host number */
+       u_short dl_imp;         /* imp field */
+       u_char  dl_link;        /* link number */
+       u_char  dl_subtype;     /* message subtype */
+};
+
+struct imp_leader {
+       struct  control_leader il_dl;
+#define        il_format       il_dl.dl_format
+#define        il_network      il_dl.dl_network
+#define        il_flags        il_dl.dl_flags
+#define        il_mtype        il_dl.dl_mtype
+#define        il_htype        il_dl.dl_htype
+#define        il_host         il_dl.dl_host
+#define        il_imp          il_dl.dl_imp
+#define        il_link         il_dl.dl_link
+#define        il_subtype      il_dl.dl_subtype
+       u_short il_length;      /* message length */
+};
+
+#define        IMP_DROPCNT     2       /* # of noops from imp to ignore */
+/* insure things are even... */
+#define        IMPMTU          ((8159 / NBBY) & ~01)
+
+/*
+ * IMP-host flags
+ */
+#define        IMP_NFF         0xf     /* 96-bit (new) format */
+#define        IMP_TRACE       0x8     /* trace message route */
+
+#define        IMP_DMASK       0x3     /* host going down mask */
+
+/*
+ * IMP-host message types.
+ */
+#define        IMPTYPE_DATA            0       /* data for protocol */
+#define        IMPTYPE_BADLEADER       1       /* leader error */
+#define        IMPTYPE_DOWN            2       /* imp going down */
+#define        IMPTYPE_NOOP            4       /* noop seen during initialization */
+#define        IMPTYPE_RFNM            5       /* request for new messages */
+#define        IMPTYPE_HOSTDEAD        6       /* host doesn't respond */
+#define        IMPTYPE_HOSTUNREACH     7       /* host unreachable */
+#define        IMPTYPE_BADDATA         8       /* data error */
+#define        IMPTYPE_INCOMPLETE      9       /* incomplete message, send rest */
+#define        IMPTYPE_RESET           10      /* reset complete */
+/* non-blocking IMP interface */
+#define        IMPTYPE_RETRY           11      /* IMP refused, try again */
+#define        IMPTYPE_NOTIFY          12      /* IMP refused, will notify */
+#define        IMPTYPE_TRYING          13      /* IMP refused, still rexmt'ng */
+#define        IMPTYPE_READY           14      /* ready for next message */
+
+/*
+ * IMPTYPE_DOWN subtypes.
+ */
+#define        IMPDOWN_GOING           0       /* 30 secs */
+#define        IMPDOWN_PM              1       /* hardware PM */
+#define        IMPDOWN_RELOAD          2       /* software reload */
+#define        IMPDOWN_RESTART         3       /* emergency restart */
+
+/*
+ * IMPTYPE_BADLEADER subtypes.
+ */
+#define        IMPLEADER_ERR           0       /* error flip-flop set */
+#define        IMPLEADER_SHORT         1       /* leader < 80 bits */
+#define        IMPLEADER_TYPE          2       /* illegal type field */
+#define        IMPLEADER_OPPOSITE      3       /* opposite leader type */
+
+/*
+ * IMPTYPE_HOSTDEAD subtypes.
+ */
+#define        IMPHOST_NORDY           1       /* ready-line negated */
+#define        IMPHOST_TARDY           2       /* tardy receiving mesgs */
+#define        IMPHOST_NOEXIST         3       /* NCC doesn't know host */
+#define        IMPHOST_IMPSOFT         4       /* IMP software won't allow mesgs */
+#define        IMPHOST_PM              5       /* host down for scheduled PM */
+#define        IMPHOST_HARDSCHED       6       /* " " " " hardware work */
+#define        IMPHOST_SOFTSCHED       7       /* " " " " software work */
+#define        IMPHOST_RESTART         8       /* host down for emergency restart */
+#define        IMPHOST_POWER           9       /* down because of power outage */
+#define        IMPHOST_BREAKPOINT      10      /* host stopped at a breakpoint */
+#define        IMPHOST_HARDWARE        11      /* hardware failure */
+#define        IMPHOST_NOTUP           12      /* host not scheduled to be up */
+/* 13-14 currently unused */
+#define        IMPHOST_COMINGUP        15      /* host in process of coming up */
+
+/*
+ * IMPTYPE_HOSTUNREACH subtypes.
+ */
+#define        IMPREACH_IMP            0       /* destination IMP can't be reached */
+#define        IMPREACH_HOSTUP         1       /* destination host isn't up */
+#define        IMPREACH_LEADER         2       /* host doesn't support long leader */
+#define        IMPREACH_PROHIBITED     3       /* communication is prohibited */
+
+/*
+ * IMPTYPE_INCOMPLETE subtypes.
+ */
+#define        IMPCOMPLETE_SLOW        0       /* host didn't take data fast enough */
+#define        IMPCOMPLETE_TOOLONG     1       /* message was too long */
+#define        IMPCOMPLETE_TIMEOUT     2       /* mesg transmission time > 15 sec. */
+#define        IMPCOMPLETE_FAILURE     3       /* IMP/circuit failure */
+#define        IMPCOMPLETE_NOSPACE     4       /* no resources within 15 sec. */
+#define        IMPCOMPLETE_IMPIO       5       /* src IMP I/O failure during receipt */
+
+/*
+ * IMPTYPE_RETRY subtypes.
+ */
+#define        IMPRETRY_BUFFER         0       /* IMP buffer wasn't available */
+#define        IMPRETRY_BLOCK          1       /* connection block unavailable */
+
+/*
+ * Data structure shared between IMP protocol module and hardware
+ * interface driver.  Used to allow layering of IMP routines on top
+ * of varying device drivers.  NOTE: there's a possible problem 
+ * with ambiguity in the ``unit'' definition which is implicitly
+ * shared by the both IMP and device code.  If we have two IMPs,
+ * with each on top of a device of the same unit, things won't work.
+ * The assumption is if you've got multiple IMPs, then they all run
+ * on top of the same type of device, or they must have different units.
+ */
+struct impcb {
+       char    ic_oactive;             /* output in progress */
+       int     (*ic_init)();           /* hardware init routine */
+       int     (*ic_start)();          /* hardware start output routine */
+};
+
+/*
+ * State of an IMP.
+ */
+#define        IMPS_DOWN       0               /* unavailable, don't use */
+#define        IMPS_GOINGDOWN  1               /* been told we go down soon */
+#define        IMPS_INIT       2               /* coming up */
+#define        IMPS_UP         3               /* ready to go */
+#define        IMPS_RESET      4               /* reset in progress */
+
+#define        IMPTV_DOWN      (30*60)         /* going down timer 30 secs */
+
+#ifdef IMPLEADERS
+char *impleaders[IMPTYPE_READY+1] = {
+       "DATA", "BADLEADER", "DOWN", "bad", "NOOP", "RFNM", "HOSTDEAD",
+       "HOSTUNREACH", "BADDATA", "INCOMPLETE", "RESET", "RETRY",
+       "NOTIFY", "TRYING", "READY"
+};
+#endif
diff --git a/usr/src/sys/netimp/if_imphost.c b/usr/src/sys/netimp/if_imphost.c
new file mode 100644 (file)
index 0000000..3592e7c
--- /dev/null
@@ -0,0 +1,214 @@
+/*     if_imphost.c    6.1     83/07/29        */
+
+#include "imp.h"
+#if NIMP > 0
+/*
+ * Host table manipulation routines.
+ * Only needed when shipping stuff through an IMP.
+ *
+ * Everything in here is called at splimp from
+ * from the IMP protocol code (if_imp.c), or
+ * interlocks with the code at splimp.
+ */
+#include "../h/param.h"
+#include "../h/mbuf.h"
+
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+
+#include "../netimp/if_imp.h"
+#include "../netimp/if_imphost.h"
+
+/*
+ * Head of host table hash chains.
+ */
+struct mbuf *hosts;
+
+/*
+ * Given an internet address
+ * return a host structure (if it exists).
+ */
+struct host *
+hostlookup(addr)
+       struct in_addr addr;
+{
+       register struct host *hp;
+       register struct mbuf *m;
+       register int hash = HOSTHASH(addr);
+
+       for (m = hosts; m; m = m->m_next) {
+               hp = &mtod(m, struct hmbuf *)->hm_hosts[hash];
+               if (hp->h_addr.s_addr == addr.s_addr) {
+                       hp->h_flags |= HF_INUSE;
+                       return (hp);
+               }
+       }
+       return ((struct host *)0);
+}
+
+/*
+ * Enter a reference to this host's internet
+ * address.  If no host structure exists, create
+ * one and hook it into the host database.
+ */
+struct host *
+hostenter(addr)                 
+       struct in_addr addr;
+{
+       register struct mbuf *m, **mprev;
+       register struct host *hp, *hp0 = 0;
+       register int hash = HOSTHASH(addr);
+
+       mprev = &hosts;
+       while (m = *mprev) {
+               mprev = &m->m_next;
+               hp = &mtod(m, struct hmbuf *)->hm_hosts[hash];
+               if ((hp->h_flags & HF_INUSE) == 0) {
+                       if (hp->h_addr.s_addr == addr.s_addr)
+                               goto foundhost;
+                       if (hp0 == 0)
+                               hp0 = hp;
+                       continue;
+               }
+               if (hp->h_addr.s_addr == addr.s_addr)    
+                       goto foundhost;
+       }
+
+       /*
+        * No current host structure, make one.
+        * If our search ran off the end of the
+        * chain of mbuf's, allocate another.
+        */
+       if (hp0 == 0) {
+               m = m_getclr(M_DONTWAIT, MT_HTABLE);
+               if (m == NULL)
+                       return ((struct host *)0);
+               *mprev = m;
+               hp0 = &mtod(m, struct hmbuf *)->hm_hosts[hash];
+       }
+       mtod(dtom(hp0), struct hmbuf *)->hm_count++;
+       hp = hp0;
+       hp->h_addr = addr;
+       hp->h_timer = 0;
+       hp->h_flags = 0;
+
+foundhost:
+       hp->h_flags |= HF_INUSE;
+       return (hp);
+}
+
+/*
+ * Mark a host structure free and set it's
+ * timer going.
+ */
+hostfree(hp)                               
+       register struct host *hp;
+{
+
+       hp->h_flags &= ~HF_INUSE;
+       hp->h_timer = HOSTTIMER;
+       hp->h_rfnm = 0;
+}
+
+/*
+ * Reset a given network's host entries.
+ */
+hostreset(net)     
+       int net;
+{
+       register struct mbuf *m;
+       register struct host *hp, *lp;
+       struct hmbuf *hm;
+
+       for (m = hosts; m; m = m->m_next) {
+               hm = mtod(m, struct hmbuf *);
+               hp = hm->hm_hosts; 
+               lp = hp + HPMBUF;
+               while (hm->hm_count > 0 && hp < lp) {
+                       if (hp->h_addr.s_net == net) {
+                               hp->h_flags &= ~HF_INUSE;
+                               hostrelease(hp);
+                       }
+                       hp++;
+               }
+       }
+}
+
+/*
+ * Remove a host structure and release
+ * any resources it's accumulated.
+ */
+hostrelease(hp)
+       register struct host *hp;
+{
+       register struct mbuf *m, **mprev, *mh = dtom(hp);
+
+       /*
+        * Discard any packets left on the waiting q
+        */
+       if (m = hp->h_q) {
+               register struct mbuf *n;
+
+               do {
+                       n = m->m_act;
+                       m_freem(m);
+                       m = n;
+               } while (m != hp->h_q);
+               hp->h_q = 0;
+       }
+       hp->h_flags = 0;
+       if (--mtod(mh, struct hmbuf *)->hm_count)
+               return;
+       mprev = &hosts;
+       while ((m = *mprev) != mh)
+               mprev = &m->m_next;
+       *mprev = m_free(mh);
+}
+
+/*
+ * Remove a packet from the holding q.
+ * The RFNM counter is also bumped.
+ */
+struct mbuf *
+hostdeque(hp)
+       register struct host *hp;
+{
+       register struct mbuf *m;
+
+       hp->h_rfnm--;
+       HOST_DEQUE(hp, m);
+       if (m)
+               return (m);
+       if (hp->h_rfnm == 0)
+               hostfree(hp);
+       return (0);
+}
+
+/*
+ * Host data base timer routine.
+ * Decrement timers on structures which are
+ * waiting to be deallocated.  On expiration
+ * release resources, possibly deallocating
+ * mbuf associated with structure.
+ */
+hostslowtimo()
+{
+       register struct mbuf *m;
+       register struct host *hp, *lp;
+       struct hmbuf *hm;
+       int s = splimp();
+
+       for (m = hosts; m; m = m->m_next) {
+               hm = mtod(m, struct hmbuf *);
+               hp = hm->hm_hosts; 
+               lp = hp + HPMBUF;
+               for (; hm->hm_count > 0 && hp < lp; hp++) {
+                       if (hp->h_flags & HF_INUSE)
+                               continue;
+                       if (hp->h_timer && --hp->h_timer == 0)
+                               hostrelease(hp);
+               }
+       }
+       splx(s);
+}
+#endif
diff --git a/usr/src/sys/netimp/if_imphost.h b/usr/src/sys/netimp/if_imphost.h
new file mode 100644 (file)
index 0000000..124a0c2
--- /dev/null
@@ -0,0 +1,85 @@
+/*     if_imphost.h    6.1     83/07/29        */
+
+/*
+ * Host structure used with IMP's.
+ * Used to hold outgoing packets which
+ * would exceed allowed RFNM count.
+ *
+ * These structures are packed into
+ * mbuf's and kept as small as possible.
+ */
+struct host {
+       struct  mbuf *h_q;              /* holding queue */
+       struct  in_addr h_addr;         /* host's address */
+       u_char  h_qcnt;                 /* size of holding q */
+       u_char  h_timer;                /* used to stay off deletion */
+       u_char  h_rfnm;                 /* # outstanding rfnm's */
+       u_char  h_flags;                /* see below */
+};
+
+/*
+ * A host structure is kept around (even when there are no
+ * references to it) for a spell to avoid constant reallocation
+ * and also to reflect IMP status back to sites which aren't
+ * directly connected to the IMP.  When structures are marked
+ * free, a timer is started; when the timer expires the structure
+ * is scavenged.
+ */
+#define        HF_INUSE        0x1
+#define        HF_DEAD         (1<<IMPTYPE_HOSTDEAD)
+#define        HF_UNREACH      (1<<IMPTYPE_HOSTUNREACH)
+
+#define        HOSTTIMER       128             /* keep structure around awhile */
+
+/*
+ * Host structures, as seen inside an mbuf.
+ * Hashing on the host address is used to
+ * select an index into the first mbuf.  Collisions
+ * are then resolved by searching successive
+ * mbuf's at the same index.  Reclamation is done
+ * automatically at the time a structure is free'd.
+ */
+#define        HPMBUF  ((MLEN - sizeof(int)) / sizeof(struct host))
+#if vax
+#define        HOSTHASH(a)     ((((a).s_addr>>8)+(a).s_net) % HPMBUF)
+#endif
+
+/*
+ * In-line expansions for queuing operations on
+ * host message holding queue.  Queue is maintained
+ * as circular list with the head pointing to the
+ * last message in the queue.
+ */
+#define        HOST_ENQUE(hp, m) { \
+       register struct mbuf *n; \
+       (hp)->h_qcnt++; \
+       if ((n = (hp)->h_q) == 0) \
+               (hp)->h_q = (m)->m_act = (m); \
+       else { \
+               (m)->m_act = n->m_act; \
+               (hp)->h_q = n->m_act = (m); \
+       } \
+}
+#define        HOST_DEQUE(hp, m) { \
+       if ((m) = (hp)->h_q) { \
+               if ((m)->m_act == (m)) \
+                       (hp)->h_q = 0; \
+               else { \
+                       (m) = (m)->m_act; \
+                       (hp)->h_q->m_act = (m)->m_act; \
+               } \
+               (hp)->h_qcnt--; \
+               (m)->m_act = 0; \
+       } \
+}
+
+struct hmbuf {
+       int     hm_count;               /* # of struct's in use */
+       struct  host hm_hosts[HPMBUF];  /* data structures proper */
+};
+
+#ifdef KERNEL
+struct host *hostlookup();
+struct host *hostenter();
+struct mbuf *hostdeque();
+#endif
diff --git a/usr/src/sys/netimp/raw_imp.c b/usr/src/sys/netimp/raw_imp.c
new file mode 100644 (file)
index 0000000..84b199e
--- /dev/null
@@ -0,0 +1,94 @@
+/*     raw_imp.c       6.1     83/07/29        */
+
+#include "../h/param.h"
+#include "../h/mbuf.h"
+#include "../h/socket.h"
+#include "../h/protosw.h"
+#include "../h/socketvar.h"
+#include "../h/errno.h"
+
+#include "../net/if.h"
+#include "../net/route.h"
+#include "../net/raw_cb.h"
+
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netimp/if_imp.h"
+
+/*
+ * Raw interface to IMP.
+ */
+
+/*
+ * Generate IMP leader and pass packet to impoutput.
+ * The user must create a skeletal leader in order to
+ * communicate message type, message subtype, etc.
+ * We fill in holes where needed and verify parameters
+ * supplied by user.
+ */
+rimp_output(m, so)
+       register struct mbuf *m;
+       struct socket *so;
+{
+       struct mbuf *n;
+       int len, error = 0;
+       register struct imp_leader *ip;
+       register struct sockaddr_in *sin;
+       register struct rawcb *rp = sotorawcb(so);
+       struct ifnet *ifp;
+       struct control_leader *cp;
+
+       /*
+        * Verify user has supplied necessary space
+        * for the leader and check parameters in it.
+        */
+       if ((m->m_off > MMAXOFF || m->m_len < sizeof(struct control_leader)) &&
+           (m = m_pullup(m, sizeof(struct control_leader))) == 0) {
+               error = EMSGSIZE;       /* XXX */
+               goto bad;
+       }
+       cp = mtod(m, struct control_leader *);
+       if (cp->dl_mtype == IMPTYPE_DATA)
+               if (m->m_len < sizeof(struct imp_leader) &&
+                   (m = m_pullup(m, sizeof(struct imp_leader))) == 0) {
+                       error = EMSGSIZE;       /* XXX */
+                       goto bad;
+               }
+       ip = mtod(m, struct imp_leader *);
+       if (ip->il_format != IMP_NFF) {
+               error = EMSGSIZE;               /* XXX */
+               goto bad;
+       }
+#ifdef notdef
+       if (ip->il_link != IMPLINK_IP &&
+           (ip->il_link<IMPLINK_LOWEXPER || ip->il_link>IMPLINK_HIGHEXPER)) {
+               error = EPERM;
+               goto bad;
+       }
+#endif
+
+       /*
+        * Fill in IMP leader -- impoutput refrains from rebuilding
+        * the leader when it sees the protocol family PF_IMPLINK.
+        * (message size calculated by walking through mbuf's)
+        */
+       for (len = 0, n = m; n; n = n->m_next)
+               len += n->m_len;
+       ip->il_length = htons((u_short)(len << 3));
+       sin = (struct sockaddr_in *)&rp->rcb_faddr;
+#ifdef notdef
+       ip->il_network = sin->sin_addr.s_net;
+#else
+       ip->il_network = 0;
+#endif
+       ip->il_host = sin->sin_addr.s_host;
+       ip->il_imp = sin->sin_addr.s_imp;
+       /* no routing here */
+       ifp = if_ifonnetof((int)sin->sin_addr.s_net);
+       if (ifp)
+               return (impoutput(ifp, m, (struct sockaddr *)sin));
+       error = ENETUNREACH;
+bad:
+       m_freem(m);
+       return (error);
+}