ifdef PUP include files
[unix-history] / usr / src / sys / vax / if / if_vv.c
index b16f8ba..074792b 100644 (file)
@@ -1,39 +1,45 @@
-/*     if_vv.c 4.5     82/06/20        */
+/*     if_vv.c 6.6     84/08/29        */
+
+#include "vv.h"
 
 /*
  * Proteon 10 Meg Ring Driver.
  * This device is called "vv" because its "real name",
  * V2LNI won't work if shortened to the obvious "v2".
  * Hence the subterfuge.
 
 /*
  * Proteon 10 Meg Ring Driver.
  * This device is called "vv" because its "real name",
  * V2LNI won't work if shortened to the obvious "v2".
  * Hence the subterfuge.
+ *
  */
  */
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/mbuf.h"
-#include "../h/pte.h"
-#include "../h/buf.h"
-#include "../h/protosw.h"
-#include "../h/socket.h"
-#include "../h/ubareg.h"
-#include "../h/ubavar.h"
-#include "../h/cpu.h"
-#include "../h/mtpr.h"
-#include "../h/vmmac.h"
-#include "../net/in.h"
-#include "../net/in_systm.h"
+#include "../machine/pte.h"
+
+#include "param.h"
+#include "systm.h"
+#include "mbuf.h"
+#include "buf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "vmmac.h"
+#include "errno.h"
+#include "ioctl.h"
+
 #include "../net/if.h"
 #include "../net/if.h"
-#include "../net/if_vv.h"
-#include "../net/if_uba.h"
-#include "../net/ip.h"
-#include "../net/ip_var.h"
+#include "../net/netisr.h"
 #include "../net/route.h"
 #include "../net/route.h"
-
-#include "vv.h"
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "if_vv.h"
+#include "if_uba.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
 
 /*
  * N.B. - if WIRECENTER is defined wrong, it can well break
  * the hardware!!
  */
 
 /*
  * N.B. - if WIRECENTER is defined wrong, it can well break
  * the hardware!!
  */
-#undef AUTOIDENTIFY
 #define        WIRECENTER
 
 #ifdef WIRECENTER
 #define        WIRECENTER
 
 #ifdef WIRECENTER
 #endif
 
 #define        VVMTU   (1024+512)
 #endif
 
 #define        VVMTU   (1024+512)
+#define VVMRU  (1024+512+16)   /* space for trailer */
+
+int    vv_tracehdr = 0;        /* 1 => trace headers (slowly!!) */
+int    vv_logreaderrors = 1;   /* 1 => log all read errors */
 
 
-int    vvprobe(), vvattach(), vvrint(), vvxint();
+#define vvtracehdr     if (vv_tracehdr) vvprt_hdr
+
+int    vvprobe(), vvattach(), vvreset(), vvinit();
+int    vvidentify(), vvstart(), vvxint(), vvwatchdog();
+int    vvrint(), vvoutput(), vvioctl(), vvsetaddr();
 struct uba_device *vvinfo[NVV];
 u_short vvstd[] = { 0 };
 struct uba_driver vvdriver =
        { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
 #define        VVUNIT(x)       minor(x)
 struct uba_device *vvinfo[NVV];
 u_short vvstd[] = { 0 };
 struct uba_driver vvdriver =
        { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
 #define        VVUNIT(x)       minor(x)
-int    vvinit(),vvoutput(),vvreset();
 
 /*
  * Software status of each interface.
 
 /*
  * Software status of each interface.
@@ -67,24 +80,26 @@ int vvinit(),vvoutput(),vvreset();
 struct vv_softc {
        struct  ifnet vs_if;            /* network-visible interface */
        struct  ifuba vs_ifuba;         /* UNIBUS resources */
 struct vv_softc {
        struct  ifnet vs_if;            /* network-visible interface */
        struct  ifuba vs_ifuba;         /* UNIBUS resources */
-       short   vs_oactive;             /* is output active? */
+       short   vs_oactive;             /* is output active */
        short   vs_olen;                /* length of last output */
        short   vs_olen;                /* length of last output */
-       u_short vs_lastx;               /* last destination address */
-       short   vs_tries;               /* current retry count */
+       u_short vs_lastx;               /* address of last packet sent */
+       u_short vs_lastr;               /* address of last packet received */
+       short   vs_tries;               /* transmit current retry count */
        short   vs_init;                /* number of ring inits */
        short   vs_init;                /* number of ring inits */
-       short   vs_flush;               /* number of flushed packets */
        short   vs_nottaken;            /* number of packets refused */
        short   vs_nottaken;            /* number of packets refused */
+       short   vs_timeouts;            /* number of transmit timeouts */
 } vv_softc[NVV];
 
 vvprobe(reg)
        caddr_t reg;
 {
        register int br, cvec;
 } vv_softc[NVV];
 
 vvprobe(reg)
        caddr_t reg;
 {
        register int br, cvec;
-       register struct vvreg *addr = (struct vvreg *)reg;
+       register struct vvreg *addr;
 
 #ifdef lint
        br = 0; cvec = br; br = cvec;
 #endif
 
 #ifdef lint
        br = 0; cvec = br; br = cvec;
 #endif
+       addr = (struct vvreg *)reg;
        /* reset interface, enable, and wait till dust settles */
        addr->vvicsr = VV_RST;
        addr->vvocsr = VV_RST;
        /* reset interface, enable, and wait till dust settles */
        addr->vvicsr = VV_RST;
        addr->vvocsr = VV_RST;
@@ -98,7 +113,7 @@ vvprobe(reg)
        DELAY(100000);
        addr->vvocsr = 0;
        if (cvec && cvec != 0x200)
        DELAY(100000);
        addr->vvocsr = 0;
        if (cvec && cvec != 0x200)
-               cvec -= 4;              /* backup so vector => recieve */
+               cvec -= 4;              /* backup so vector => receive */
        return(1);
 }
 
        return(1);
 }
 
@@ -110,28 +125,24 @@ vvprobe(reg)
 vvattach(ui)
        struct uba_device *ui;
 {
 vvattach(ui)
        struct uba_device *ui;
 {
-       register struct vv_softc *vs = &vv_softc[ui->ui_unit];
-       register struct sockaddr_in *sin;
+       register struct vv_softc *vs;
 
 
+       vs = &vv_softc[ui->ui_unit];
        vs->vs_if.if_unit = ui->ui_unit;
        vs->vs_if.if_name = "vv";
        vs->vs_if.if_mtu = VVMTU;
        vs->vs_if.if_unit = ui->ui_unit;
        vs->vs_if.if_name = "vv";
        vs->vs_if.if_mtu = VVMTU;
-       vs->vs_if.if_net = ui->ui_flags;
-       vs->vs_if.if_host[0] = 0;       /* this will be reset in vvinit() */
-
-       sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
-       sin->sin_family = AF_INET;
-       sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
-
-       sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr;
-       sin->sin_family = AF_INET;
-       sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST);
-       vs->vs_if.if_flags = IFF_BROADCAST;
-
        vs->vs_if.if_init = vvinit;
        vs->vs_if.if_init = vvinit;
+       vs->vs_if.if_ioctl = vvioctl;
        vs->vs_if.if_output = vvoutput;
        vs->vs_if.if_output = vvoutput;
-       vs->vs_if.if_ubareset = vvreset;
-       vs->vs_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16;
+       vs->vs_if.if_reset = vvreset;
+       vs->vs_if.if_timer = 0;
+       vs->vs_if.if_watchdog = vvwatchdog;
+       vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16;
+#if defined(VAX750)
+       /* don't chew up 750 bdp's */
+       if (cpu == VAX_750 && ui->ui_unit > 0)
+               vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP;
+#endif
        if_attach(&vs->vs_if);
 }
 
        if_attach(&vs->vs_if);
 }
 
@@ -158,43 +169,104 @@ vvreset(unit, uban)
 vvinit(unit)
        int unit;
 {
 vvinit(unit)
        int unit;
 {
-       register struct vv_softc *vs = &vv_softc[unit];
-       register struct uba_device *ui = vvinfo[unit];
+       register struct vv_softc *vs;
+       register struct uba_device *ui;
        register struct vvreg *addr;
        register struct vvreg *addr;
-       struct sockaddr_in *sin;
-       struct mbuf *m;
-       struct vv_header *v;
-       int ubainfo, retrying, attempts, waitcount, s;
+       register struct sockaddr_in *sin;
+       register int ubainfo, s;
 
 
+       vs = &vv_softc[unit];
+       ui = vvinfo[unit];
+       sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
+       /*
+        * If the network number is still zero, we've been
+        * called too soon.
+        */
+       if (in_netof(sin->sin_addr) == 0)
+               return;
+       addr = (struct vvreg *)ui->ui_addr;
        if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
        if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
-           sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { 
-               printf("vv%d: can't initialize\n", unit);
-               vs->vs_ifuba.if_flags &= ~IFF_UP;
+           sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
+               printf("vv%d: can't initialize, if_ubainit() failed\n", unit);
+               vs->vs_if.if_flags &= ~IFF_UP;
                return;
        }
                return;
        }
-       addr = (struct vvreg *)ui->ui_addr;
+       /*
+        * Now that the uba is set up, figure out our address and
+        * update complete our host address.
+        */
+       if ((vs->vs_if.if_host[0] = vvidentify(unit)) == 0) {
+               vs->vs_if.if_flags &= ~IFF_UP;
+               return;
+       }
+       printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]);
+       sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
+       /*
+        * Reset the interface, and join the ring
+        */
+       addr->vvocsr = VV_RST | VV_CPB;         /* clear packet buffer */
+       addr->vvicsr = VV_RST | VV_CONF;        /* close logical relay */
+       DELAY(500000);                          /* let contacts settle */
+       vs->vs_init = 0;
+       vs->vs_nottaken = 0;
+       vs->vs_timeouts = 0;
+       vs->vs_lastx = 256;                     /* an invalid address */
+       vs->vs_lastr = 256;                     /* an invalid address */
+       /*
+        * Hang a receive and start any
+        * pending writes by faking a transmit complete.
+        */
+       s = splimp();
+       ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
+       addr->vviba = (u_short)ubainfo;
+       addr->vviea = (u_short)(ubainfo >> 16);
+       addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
+       addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB;
+       vs->vs_oactive = 1;
+       vs->vs_if.if_flags |= IFF_UP | IFF_RUNNING;
+       vvxint(unit);
+       splx(s);
+       if_rtinit(&vs->vs_if, RTF_UP);
+}
+
+/*
+ * Return our host address.
+ */
+vvidentify(unit)
+       int unit;
+{
+       register struct vv_softc *vs;
+       register struct uba_device *ui;
+       register struct vvreg *addr;
+       register struct mbuf *m;
+       register struct vv_header *v;
+       register int ubainfo, attempts, waitcount;
 
 
-#ifdef AUTOIDENTIFY
        /*
         * Build a multicast message to identify our address
         */
        /*
         * Build a multicast message to identify our address
         */
+       vs = &vv_softc[unit];
+       ui = vvinfo[unit];
+       addr = (struct vvreg *)ui->ui_addr;
        attempts = 0;           /* total attempts, including bad msg type */
        attempts = 0;           /* total attempts, including bad msg type */
-top:
-       retrying = 0;           /* first time through */
-       m = m_get(M_DONTWAIT);
-       if (m == 0)
-               panic("vvinit: can't get mbuf");
+       m = m_get(M_DONTWAIT, MT_HEADER);
+       if (m == NULL) {
+               printf("vv%d: can't initialize, m_get() failed\n", unit);
+               return (0);
+       }
        m->m_next = 0;
        m->m_off = MMINOFF;
        m->m_len = sizeof(struct vv_header);
        m->m_next = 0;
        m->m_off = MMINOFF;
        m->m_len = sizeof(struct vv_header);
-
        v = mtod(m, struct vv_header *);
        v = mtod(m, struct vv_header *);
-       v->vh_dhost = 0;                /* multicast destination address */
+       v->vh_dhost = VV_BROADCAST;     /* multicast destination address */
        v->vh_shost = 0;                /* will be overwritten with ours */
        v->vh_version = RING_VERSION;
        v->vh_type = RING_WHOAMI;
        v->vh_info = 0;
        v->vh_shost = 0;                /* will be overwritten with ours */
        v->vh_version = RING_VERSION;
        v->vh_type = RING_WHOAMI;
        v->vh_info = 0;
-
+       /* map xmit message into uba */
+       vs->vs_olen =  if_wubaput(&vs->vs_ifuba, m);
+       if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
        /*
         * Reset interface, establish Digital Loopback Mode, and
         * send the multicast (to myself) with Input Copy enabled.
        /*
         * Reset interface, establish Digital Loopback Mode, and
         * send the multicast (to myself) with Input Copy enabled.
@@ -206,96 +278,59 @@ retry:
        addr->vviea = (u_short) (ubainfo >> 16);
        addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
        addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB;
        addr->vviea = (u_short) (ubainfo >> 16);
        addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
        addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB;
-       /* map xmit message into uba if not already there */
-       if (!retrying)
-               vs->vs_olen =  if_wubaput(&vs->vs_ifuba, m);
-       if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
-               UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
+
+       /* let flag timers fire so ring will initialize */
+       DELAY(2000000);                 /* about 2 SECONDS on a 780!! */
+
        addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */
        ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
        addr->vvoba = (u_short) ubainfo;
        addr->vvoea = (u_short) (ubainfo >> 16);
        addr->vvowc = -((vs->vs_olen + 1) >> 1);
        addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
        addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */
        ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
        addr->vvoba = (u_short) ubainfo;
        addr->vvoea = (u_short) (ubainfo >> 16);
        addr->vvowc = -((vs->vs_olen + 1) >> 1);
        addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
-
        /*
         * Wait for receive side to finish.
        /*
         * Wait for receive side to finish.
-        * Extract source address (which will our own),
+        * Extract source address (which will be our own),
         * and post to interface structure.
         */
         * and post to interface structure.
         */
-       DELAY(1000);
-       for (waitcount = 0; ((addr->vvicsr) & VV_RDY) == 0; waitcount++) {
-               if (waitcount < 10)
+       DELAY(10000);
+       for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) {
+               if (waitcount < 10) {
                        DELAY(1000);
                        DELAY(1000);
-               else {
-                       if (attempts++ < 10)s
-                               goto retry;
-                       else {
-                               printf("vv%d: can't initialize\n", unit);
-                               printf("vvinit loopwait: icsr = %b\n",
-                                       0xffff&(addr->vvicsr),VV_IBITS);
-                               vs->vs_ifuba.if_flags &= ~IFF_UP;
-                               return;
-                       }
+                       continue;
                }
                }
+               if (attempts++ < VVIDENTRETRY)
+                       goto retry;
        }
        }
-
-       if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
-               UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
-       if (vs->vs_ifuba.ifu_xtofree)
+       /* deallocate mbuf used for send packet */
+       if (vs->vs_ifuba.ifu_xtofree) {
                m_freem(vs->vs_ifuba.ifu_xtofree);
                m_freem(vs->vs_ifuba.ifu_xtofree);
+               vs->vs_ifuba.ifu_xtofree = 0;
+       }
+       if (attempts >= VVIDENTRETRY) {
+               printf("vv%d: can't initialize after %d tries, icsr = %b\n",
+                   unit, VVIDENTRETRY, 0xffff&(addr->vvicsr), VV_IBITS);
+               return (0);
+       }
+       /* Purge BDP before looking at packet we just received */
        if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
                UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
        m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0);
        if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
                UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
        m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0);
-       if (m)
+       if (m != NULL)
                m_freem(m);
        /*
                m_freem(m);
        /*
-        * check message type before we believe the source host address
+        * Check message type before we believe the source host address
         */
        v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
         */
        v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
-       if (v->vh_type == RING_WHOAMI)
-               vs->vs_if.if_host[0] = v->vh_shost;
-       else
-               goto top;
-#else
-       vs->vs_if.if_host[0] = 24;
-#endif
-
-       printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]);
-       sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
-       sin->sin_family = AF_INET;
-       sin->sin_addr =
-           if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
-
-       /*
-        * Reset the interface, and join the ring
-        */
-       addr->vvocsr = VV_RST | VV_CPB;         /* clear packet buffer */
-       addr->vvicsr = VV_RST | VV_CONF;        /* close logical relay */
-       sleep((caddr_t)&lbolt, PZERO);          /* let contacts settle */
-       vs->vs_init = 0;
-       vs->vs_flush = 0;
-       vs->vs_nottaken = 0;
-
-       /*
-        * Hang a receive and start any
-        * pending writes by faking a transmit complete.
-        */
-       s = splimp();
-       ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
-       addr->vviba = (u_short) ubainfo;
-       addr->vviea = (u_short) (ubainfo >> 16);
-       addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
-       addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB;
-       vs->vs_oactive = 1;
-       vs->vs_ifuba.if_flags |= IFF_UP;
-       vvxint(unit);
-       splx(s);
-       if_rtinit(&vs->vs_if, RTF_UP);
+       if (v->vh_type != RING_WHOAMI)
+               goto retry;
+       return(v->vh_shost);
 }
 
 /*
  * Start or restart output on interface.
 }
 
 /*
  * Start or restart output on interface.
+ * If interface is active, this is a retransmit, so just
+ * restuff registers and go.
  * If interface is not already active, get another datagram
  * to send off of the interface queue, and map it to the interface
  * before starting the output.
  * If interface is not already active, get another datagram
  * to send off of the interface queue, and map it to the interface
  * before starting the output.
@@ -303,36 +338,43 @@ retry:
 vvstart(dev)
        dev_t dev;
 {
 vvstart(dev)
        dev_t dev;
 {
-        int unit = VVUNIT(dev);
-       struct uba_device *ui = vvinfo[unit];
-       register struct vv_softc *vs = &vv_softc[unit];
+       register struct uba_device *ui;
+       register struct vv_softc *vs;
        register struct vvreg *addr;
        register struct vvreg *addr;
-       struct mbuf *m;
-       int ubainfo;
-       int dest;
+       register struct mbuf *m;
+       register int unit, ubainfo, dest, s;
 
 
+       unit = VVUNIT(dev);
+       ui = vvinfo[unit];
+       vs = &vv_softc[unit];
        if (vs->vs_oactive)
                goto restart;
        if (vs->vs_oactive)
                goto restart;
-
        /*
         * Not already active: dequeue another request
         * and map it to the UNIBUS.  If no more requests,
         * just return.
         */
        /*
         * Not already active: dequeue another request
         * and map it to the UNIBUS.  If no more requests,
         * just return.
         */
+       s = splimp();
        IF_DEQUEUE(&vs->vs_if.if_snd, m);
        IF_DEQUEUE(&vs->vs_if.if_snd, m);
-       if (m == 0) {
+       splx(s);
+       if (m == NULL) {
                vs->vs_oactive = 0;
                return;
        }
        dest = mtod(m, struct vv_header *)->vh_dhost;
        vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
        vs->vs_lastx = dest;
                vs->vs_oactive = 0;
                return;
        }
        dest = mtod(m, struct vv_header *)->vh_dhost;
        vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
        vs->vs_lastx = dest;
-
 restart:
        /*
         * Have request mapped to UNIBUS for transmission.
 restart:
        /*
         * Have request mapped to UNIBUS for transmission.
-        * Purge any stale data from this BDP, and start the otput.
+        * Purge any stale data from this BDP, and start the output.
+        *
+        * Make sure this packet will fit in the interface.
         */
         */
+       if (vs->vs_olen > VVMTU + sizeof (struct vv_header)) {
+               printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen);
+               panic("vvdriver vs_olen botch");
+       }
        if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
                UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
        addr = (struct vvreg *)ui->ui_addr;
        if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
                UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
        addr = (struct vvreg *)ui->ui_addr;
@@ -341,6 +383,7 @@ restart:
        addr->vvoea = (u_short) (ubainfo >> 16);
        addr->vvowc = -((vs->vs_olen + 1) >> 1);
        addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
        addr->vvoea = (u_short) (ubainfo >> 16);
        addr->vvowc = -((vs->vs_olen + 1) >> 1);
        addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
+       vs->vs_if.if_timer = VVTIMEOUT;
        vs->vs_oactive = 1;
 }
 
        vs->vs_oactive = 1;
 }
 
@@ -351,29 +394,33 @@ restart:
 vvxint(unit)
        int unit;
 {
 vvxint(unit)
        int unit;
 {
-       register struct uba_device *ui = vvinfo[unit];
-       register struct vv_softc *vs = &vv_softc[unit];
+       register struct uba_device *ui;
+       register struct vv_softc *vs;
        register struct vvreg *addr;
        register int oc;
 
        register struct vvreg *addr;
        register int oc;
 
+       ui = vvinfo[unit];
+       vs = &vv_softc[unit];
+       vs->vs_if.if_timer = 0;
        addr = (struct vvreg *)ui->ui_addr;
        oc = 0xffff & (addr->vvocsr);
        if (vs->vs_oactive == 0) {
                printf("vv%d: stray interrupt vvocsr = %b\n", unit,
        addr = (struct vvreg *)ui->ui_addr;
        oc = 0xffff & (addr->vvocsr);
        if (vs->vs_oactive == 0) {
                printf("vv%d: stray interrupt vvocsr = %b\n", unit,
-                       oc, VV_OBITS);
+                   oc, VV_OBITS);
                return;
        }
        if (oc &  (VV_OPT | VV_RFS)) {
                return;
        }
        if (oc &  (VV_OPT | VV_RFS)) {
-               if (++(vs->vs_tries) < VVRETRY) {
+               vs->vs_if.if_collisions++;
+               if (vs->vs_tries++ < VVRETRY) {
                        if (oc & VV_OPT)
                                vs->vs_init++;
                        if (oc & VV_RFS)
                                vs->vs_nottaken++;
                        if (oc & VV_OPT)
                                vs->vs_init++;
                        if (oc & VV_RFS)
                                vs->vs_nottaken++;
-                       addr->vvocsr = VV_IEN | VV_ENB | VV_INR;
+                       vvstart(unit);          /* restart this message */
                        return;
                }
                if (oc & VV_OPT)
                        return;
                }
                if (oc & VV_OPT)
-                       printf("vv%d: output timeout\n");
+                       printf("vv%d: output timeout\n", unit);
        }
        vs->vs_if.if_opackets++;
        vs->vs_oactive = 0;
        }
        vs->vs_if.if_opackets++;
        vs->vs_oactive = 0;
@@ -381,94 +428,179 @@ vvxint(unit)
        if (oc & VVXERR) {
                vs->vs_if.if_oerrors++;
                printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
        if (oc & VVXERR) {
                vs->vs_if.if_oerrors++;
                printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
-                       VV_OBITS);
+                   VV_OBITS);
        }
        if (vs->vs_ifuba.ifu_xtofree) {
                m_freem(vs->vs_ifuba.ifu_xtofree);
                vs->vs_ifuba.ifu_xtofree = 0;
        }
        }
        if (vs->vs_ifuba.ifu_xtofree) {
                m_freem(vs->vs_ifuba.ifu_xtofree);
                vs->vs_ifuba.ifu_xtofree = 0;
        }
-       if (vs->vs_if.if_snd.ifq_head == 0) {
-               vs->vs_lastx = 0;
-               return;
-       }
        vvstart(unit);
 }
 
        vvstart(unit);
 }
 
+/*
+ * Transmit watchdog timer routine.
+ * This routine gets called when we lose a transmit interrupt.
+ * The best we can do is try to restart output.
+ */
+vvwatchdog(unit)
+       int unit;
+{
+       register struct vv_softc *vs;
+       register int s;
+
+       vs = &vv_softc[unit];
+       if (vs->vs_if.if_flags & IFF_DEBUG)
+               printf("vv%d: lost a transmit interrupt.\n", unit);
+       vs->vs_timeouts++;
+       s = splimp();
+       vvstart(unit);
+       splx(s);
+}
+
 /*
  * V2lni interface receiver interrupt.
  * If input error just drop packet.
 /*
  * V2lni interface receiver interrupt.
  * If input error just drop packet.
- * Otherwise purge input buffered data path and examine 
+ * Otherwise purge input buffered data path and examine
  * packet to determine type.  If can't determine length
  * packet to determine type.  If can't determine length
- * from type, then have to drop packet.  Othewise decapsulate
+ * from type, then have to drop packet.  Otherwise decapsulate
  * packet based on type and pass to type specific higher-level
  * input routine.
  */
 vvrint(unit)
        int unit;
 {
  * packet based on type and pass to type specific higher-level
  * input routine.
  */
 vvrint(unit)
        int unit;
 {
-       register struct vv_softc *vs = &vv_softc[unit];
-       struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr;
+       register struct vv_softc *vs;
+       register struct vvreg *addr;
        register struct vv_header *vv;
        register struct ifqueue *inq;
        register struct vv_header *vv;
        register struct ifqueue *inq;
-       struct mbuf *m;
-       int ubainfo, len, off;
+       register struct mbuf *m;
+       int ubainfo, len, off, s;
+       short resid;
 
 
+       vs = &vv_softc[unit];
        vs->vs_if.if_ipackets++;
        vs->vs_if.if_ipackets++;
+       addr = (struct vvreg *)vvinfo[unit]->ui_addr;
        /*
         * Purge BDP; drop if input error indicated.
         */
        if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
                UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
        if (addr->vvicsr & VVRERR) {
        /*
         * Purge BDP; drop if input error indicated.
         */
        if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
                UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
        if (addr->vvicsr & VVRERR) {
-               vs->vs_if.if_ierrors++;
-               printf("vv%d: error vvicsr = %b\n", unit,
-                       0xffff&(addr->vvicsr), VV_IBITS);
-               goto setup;
+               if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
+                       printf("vv%d: VVRERR, vvicsr = %b\n", unit,
+                           0xffff&(addr->vvicsr), VV_IBITS);
+               goto dropit;
        }
        }
-       off = 0;
-       len = 0;
+
+       /*
+        * Get packet length from word count residue
+        *
+        * Compute header offset if trailer protocol
+        *
+        * Pull packet off interface.  Off is nonzero if packet
+        * has trailing header; if_rubaget will then force this header
+        * information to be at the front.  The vh_info field
+        * carries the offset to the trailer data in trailer
+        * format packets.
+        */
        vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
        vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
+       vvtracehdr("vi", vv);
+       resid = addr->vviwc;
+       if (resid)
+               resid |= 0176000;               /* ugly!!!! */
+       len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1;
+       len -= sizeof(struct vv_header);
+       if (len > VVMRU || len <= 0) {
+               if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
+                       printf("vv%d: len too big, len = %d, vvicsr = %b\n",
+                           unit, len, 0xffff&(addr->vvicsr), VV_IBITS);
+               goto dropit;
+       }
+#define        vvdataaddr(vv, off, type)       ((type)(((caddr_t)((vv)+1)+(off))))
+       if (vv->vh_type >= RING_IPTrailer &&
+            vv->vh_type < RING_IPTrailer+RING_IPNTrailer) {
+               off = (vv->vh_type - RING_IPTrailer) * 512;
+               if (off > VVMTU) {
+                       if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
+                               printf("vv%d: VVMTU, off = %d, vvicsr = %b\n",
+                                   unit, off, 0xffff&(addr->vvicsr), VV_IBITS);
+                       goto dropit;
+               }
+               vv->vh_type = *vvdataaddr(vv, off, u_short *);
+               resid = *(vvdataaddr(vv, off+2, u_short *));
+               if (off + resid > len) {
+                       if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
+                               printf(
+                                   "vv%d: off = %d, resid = %d, vvicsr = %b\n",
+                                   unit, off, resid,
+                                   0xffff&(addr->vvicsr), VV_IBITS);
+                       goto dropit;
+               }
+               len = off + resid;
+       } else
+               off = 0;
+       if (len == 0) {
+               if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
+                       printf("vv%d: len is zero, vvicsr = %b\n", unit,
+                           0xffff&(addr->vvicsr), VV_IBITS);
+               goto dropit;
+       }
+       m = if_rubaget(&vs->vs_ifuba, len, off);
+       if (m == NULL) {
+               if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
+                       printf("vv%d: if_rubaget failed, vvicsr = %b\n", unit,
+                           0xffff&(addr->vvicsr), VV_IBITS);
+               goto dropit;
+       }
+       if (off) {
+               m->m_off += 2 * sizeof(u_short);
+               m->m_len -= 2 * sizeof(u_short);
+       }
+
+       /* Keep track of source address of this packet */
+       vs->vs_lastr = vv->vh_shost;
        /*
        /*
-        * Demultiplex on packet type and deal with oddities of
-        * trailer protocol format
+        * Demultiplex on packet type
         */
        switch (vv->vh_type) {
 
 #ifdef INET
        case RING_IP:
         */
        switch (vv->vh_type) {
 
 #ifdef INET
        case RING_IP:
-               len = htons((u_short)((struct ip *) vv)->ip_len);
                schednetisr(NETISR_IP);
                inq = &ipintrq;
                break;
 #endif
        default:
                printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
                schednetisr(NETISR_IP);
                inq = &ipintrq;
                break;
 #endif
        default:
                printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
+               m_freem(m);
                goto setup;
        }
                goto setup;
        }
-       if (len == 0)
-               goto setup;
-       /*
-        * Pull packet off interface.  Off is nonzero if packet
-        * has trailing header; if_rubaget will then force this header
-        * information to be at the front, but we still have to drop
-        * the two-byte type which is at the front of any trailer data.
-        */
-       m = if_rubaget(&vs->vs_ifuba, len, off);
-       if (m == 0)
-               goto setup;
-       IF_ENQUEUE(inq, m);
+       s = splimp();
+       if (IF_QFULL(inq)) {
+               IF_DROP(inq);
+               m_freem(m);
+       } else
+               IF_ENQUEUE(inq, m);
 
 
-setup:
+       splx(s);
        /*
        /*
-        * Reset for next packet.
+        * Reset for the next packet.
         */
         */
+setup:
        ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
        addr->vviba = (u_short) ubainfo;
        addr->vviea = (u_short) (ubainfo >> 16);
        addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
        addr->vvicsr = VV_RST | VV_CONF;
        addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
        ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
        addr->vviba = (u_short) ubainfo;
        addr->vviea = (u_short) (ubainfo >> 16);
        addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
        addr->vvicsr = VV_RST | VV_CONF;
        addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
+       return;
 
 
+       /*
+        * Drop packet on floor -- count them!!
+        */
+dropit:
+       vs->vs_if.if_ierrors++;
+       goto setup;
 }
 
 /*
 }
 
 /*
@@ -482,28 +614,68 @@ vvoutput(ifp, m0, dst)
        struct mbuf *m0;
        struct sockaddr *dst;
 {
        struct mbuf *m0;
        struct sockaddr *dst;
 {
-       register struct mbuf *m = m0;
+       register struct mbuf *m;
        register struct vv_header *vv;
        register struct vv_header *vv;
-       int type, dest, s;
+       register int off;
+       register int unit;
+       register struct vvreg *addr;
+       register struct vv_softc *vs;
+       register int s;
+       int type, dest, error;
+
+       m = m0;
+       unit = ifp->if_unit;
+       addr = (struct vvreg *)vvinfo[unit]->ui_addr;
+       vs = &vv_softc[unit];
+       /*
+        * Check to see if the input side has wedged.
+        *
+        * We are lower than device ipl when we enter this routine,
+        * so if the interface is ready with an input packet then
+        * an input interrupt must have slipped through the cracks.
+        *
+        * Avoid the race with an input interrupt by watching to see
+        * if any packets come in.
+        */
+       s = vs->vs_if.if_ipackets;
+       if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) {
+               if (vs->vs_if.if_flags & IFF_DEBUG)
+                       printf("vv%d: lost a receive interrupt, icsr = %b\n",
+                           unit, 0xffff&(addr->vvicsr), VV_IBITS);
+               s = splimp();
+               vvrint(unit);
+               splx(s);
+       }
 
        switch (dst->sa_family) {
 
 #ifdef INET
 
        switch (dst->sa_family) {
 
 #ifdef INET
-       case AF_INET: {
-               register struct ip *ip = mtod(m0, struct ip *);
-               int off;
-
-               dest = ip->ip_dst.s_addr >> 24;
+       case AF_INET:
+               dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
+               if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) {
+                       error = EPERM;
+                       goto bad;
+               }
+               off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
+               /* Need per host negotiation. */
+               if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
+               if (off > 0 && (off & 0x1ff) == 0 &&
+                   m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
+                       type = RING_IPTrailer + (off>>9);
+                       m->m_off -= 2 * sizeof (u_short);
+                       m->m_len += 2 * sizeof (u_short);
+                       *mtod(m, u_short *) = RING_IP;
+                       *(mtod(m, u_short *) + 1) = m->m_len;
+                       goto gottrailertype;
+               }
                type = RING_IP;
                off = 0;
                goto gottype;
                type = RING_IP;
                off = 0;
                goto gottype;
-               }
 #endif
        default:
 #endif
        default:
-               printf("vv%d: can't handle af%d\n", ifp->if_unit,
-                       dst->sa_family);
-               m_freem(m0);
-               return (0);
+               printf("vv%d: can't handle af%d\n", unit, dst->sa_family);
+               error = EAFNOSUPPORT;
+               goto bad;
        }
 
 gottrailertype:
        }
 
 gottrailertype:
@@ -517,7 +689,6 @@ gottrailertype:
        m = m0->m_next;
        m0->m_next = 0;
        m0 = m;
        m = m0->m_next;
        m0->m_next = 0;
        m0 = m;
-
 gottype:
        /*
         * Add local net header.  If no space in first mbuf,
 gottype:
        /*
         * Add local net header.  If no space in first mbuf,
@@ -525,10 +696,10 @@ gottype:
         */
        if (m->m_off > MMAXOFF ||
            MMINOFF + sizeof (struct vv_header) > m->m_off) {
         */
        if (m->m_off > MMAXOFF ||
            MMINOFF + sizeof (struct vv_header) > m->m_off) {
-               m = m_get(M_DONTWAIT);
-               if (m == 0) {
-                       m_freem(m0);
-                       return (0);
+               m = m_get(M_DONTWAIT, MT_HEADER);
+               if (m == NULL) {
+                       error = ENOBUFS;
+                       goto bad;
                }
                m->m_next = m0;
                m->m_off = MMINOFF;
                }
                m->m_next = m0;
                m->m_off = MMINOFF;
@@ -539,27 +710,94 @@ gottype:
        }
        vv = mtod(m, struct vv_header *);
        vv->vh_shost = ifp->if_host[0];
        }
        vv = mtod(m, struct vv_header *);
        vv->vh_shost = ifp->if_host[0];
-       vv->vh_dhost = dest;
+       /* Map the destination address if it's a broadcast */
+       if ((vv->vh_dhost = dest) == INADDR_ANY)
+               vv->vh_dhost = VV_BROADCAST;
        vv->vh_version = RING_VERSION;
        vv->vh_type = type;
        vv->vh_version = RING_VERSION;
        vv->vh_type = type;
-       vv->vh_info = m->m_len;
+       vv->vh_info = off;
+       vvtracehdr("vo", vv);
 
        /*
         * Queue message on interface, and start output if interface
         * not yet active.
         */
        s = splimp();
 
        /*
         * Queue message on interface, and start output if interface
         * not yet active.
         */
        s = splimp();
+       if (IF_QFULL(&ifp->if_snd)) {
+               IF_DROP(&ifp->if_snd);
+               error = ENOBUFS;
+               goto qfull;
+       }
        IF_ENQUEUE(&ifp->if_snd, m);
        IF_ENQUEUE(&ifp->if_snd, m);
-       if (vv_softc[ifp->if_unit].vs_oactive == 0)
-               vvstart(ifp->if_unit);
+       if (vs->vs_oactive == 0)
+               vvstart(unit);
        splx(s);
        splx(s);
-       return (1);
+       return (0);
+qfull:
+       m0 = m;
+       splx(s);
+bad:
+       m_freem(m0);
+       return(error);
+}
+
+/*
+ * Process an ioctl request.
+ */
+vvioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
+{
+       register struct ifreq *ifr;
+       register int s;
+       int error;
+
+       ifr = (struct ifreq *)data;
+       error = 0;
+       s = splimp();
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, -1);     /* delete previous route */
+               vvsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, RTF_UP);
+               else
+                       vvinit(ifp->if_unit);
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       splx(s);
+       return(error);
+}
+
+/*
+ * Set up the address for this interface. We use the network number
+ * from the passed address and an invalid host number; vvinit() will
+ * figure out the host number and insert it later.
+ */
+vvsetaddr(ifp, sin)
+       register struct ifnet *ifp;
+       register struct sockaddr_in *sin;
+{
+       ifp->if_net = in_netof(sin->sin_addr);
+       ifp->if_host[0] = 256;                  /* an invalid host number */
+       sin = (struct sockaddr_in *)&ifp->if_addr;
+       sin->sin_family = AF_INET;
+       sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
+       sin = (struct sockaddr_in *)&ifp->if_broadaddr;
+       sin->sin_family = AF_INET;
+       sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
+       ifp->if_flags |= IFF_BROADCAST;
 }
 
 }
 
-#ifdef notdef
 /*
  * vvprt_hdr(s, v) print the local net header in "v"
 /*
  * vvprt_hdr(s, v) print the local net header in "v"
- *     with title is "s"
+ *     with title is "s"
  */
 vvprt_hdr(s, v)
        char *s;
  */
 vvprt_hdr(s, v)
        char *s;
@@ -572,10 +810,11 @@ vvprt_hdr(s, v)
                0xffff & (int)(v->vh_info));
 }
 
                0xffff & (int)(v->vh_info));
 }
 
+#ifdef notdef
 /*
  * print "l" hex bytes starting at "s"
  */
 /*
  * print "l" hex bytes starting at "s"
  */
-vvprt_hex(s, l) 
+vvprt_hex(s, l)
        char *s;
        int l;
 {
        char *s;
        int l;
 {