ifdef PUP include files
[unix-history] / usr / src / sys / vax / if / if_vv.c
index 1c49fe5..074792b 100644 (file)
@@ -1,4 +1,4 @@
-/*     if_vv.c 6.3     83/12/22        */
+/*     if_vv.c 6.6     84/08/29        */
 
 #include "vv.h"
 
 
 #include "vv.h"
 
  */
 #include "../machine/pte.h"
 
  */
 #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/errno.h"
-#include "../h/time.h"
-#include "../h/kernel.h"
-#include "../h/ioctl.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/netisr.h"
 #include "../net/route.h"
 
 #include "../net/if.h"
 #include "../net/netisr.h"
 #include "../net/route.h"
-
 #include "../netinet/in.h"
 #include "../netinet/in_systm.h"
 #include "../netinet/ip.h"
 #include "../netinet/ip_var.h"
 
 #include "../netinet/in.h"
 #include "../netinet/in_systm.h"
 #include "../netinet/ip.h"
 #include "../netinet/ip_var.h"
 
-#include "../vax/mtpr.h"
 #include "../vax/cpu.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"
 
 #include "../vaxuba/ubareg.h"
 #include "../vaxuba/ubavar.h"
 
-#include "../vaxif/if_vv.h"
-#include "../vaxif/if_uba.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!!
 #define        VVMTU   (1024+512)
 #define VVMRU  (1024+512+16)   /* space for trailer */
 
 #define        VVMTU   (1024+512)
 #define VVMRU  (1024+512+16)   /* space for trailer */
 
-int vv_tracehdr = 0,           /* 1 => trace headers (slowly!!) */
-    vv_logreaderrors = 1;      /* 1 => log all read errors */
+int    vv_tracehdr = 0;        /* 1 => trace headers (slowly!!) */
+int    vv_logreaderrors = 1;   /* 1 => log all read errors */
 
 #define vvtracehdr     if (vv_tracehdr) vvprt_hdr
 
 
 #define vvtracehdr     if (vv_tracehdr) vvprt_hdr
 
-int    vvprobe(), vvattach(), vvrint(), vvxint();
+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(),vvioctl(),vvoutput(),vvreset(),vvsetaddr();
 
 /*
  * Software status of each interface.
 
 /*
  * Software status of each interface.
@@ -86,21 +82,24 @@ struct      vv_softc {
        struct  ifuba vs_ifuba;         /* UNIBUS resources */
        short   vs_oactive;             /* is output active */
        short   vs_olen;                /* length of last output */
        struct  ifuba vs_ifuba;         /* UNIBUS resources */
        short   vs_oactive;             /* is output active */
        short   vs_olen;                /* length of last output */
-       u_short vs_lastx;               /* last destination address */
+       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_nottaken;            /* number of packets refused */
        short   vs_tries;               /* transmit current retry count */
        short   vs_init;                /* number of ring inits */
        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;
@@ -136,6 +135,8 @@ vvattach(ui)
        vs->vs_if.if_ioctl = vvioctl;
        vs->vs_if.if_output = vvoutput;
        vs->vs_if.if_reset = vvreset;
        vs->vs_if.if_ioctl = vvioctl;
        vs->vs_if.if_output = vvoutput;
        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 */
        vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16;
 #if defined(VAX750)
        /* don't chew up 750 bdp's */
@@ -171,8 +172,8 @@ vvinit(unit)
        register struct vv_softc *vs;
        register struct uba_device *ui;
        register struct vvreg *addr;
        register struct vv_softc *vs;
        register struct uba_device *ui;
        register struct vvreg *addr;
-       struct sockaddr_in *sin;
-       int ubainfo, s;
+       register struct sockaddr_in *sin;
+       register int ubainfo, s;
 
        vs = &vv_softc[unit];
        ui = vvinfo[unit];
 
        vs = &vv_softc[unit];
        ui = vvinfo[unit];
@@ -186,7 +187,7 @@ vvinit(unit)
        addr = (struct vvreg *)ui->ui_addr;
        if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
            sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
        addr = (struct vvreg *)ui->ui_addr;
        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);
+               printf("vv%d: can't initialize, if_ubainit() failed\n", unit);
                vs->vs_if.if_flags &= ~IFF_UP;
                return;
        }
                vs->vs_if.if_flags &= ~IFF_UP;
                return;
        }
@@ -194,7 +195,10 @@ vvinit(unit)
         * Now that the uba is set up, figure out our address and
         * update complete our host address.
         */
         * Now that the uba is set up, figure out our address and
         * update complete our host address.
         */
-       vs->vs_if.if_host[0] = vvidentify(unit);
+       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]);
        /*
        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]);
        /*
@@ -205,6 +209,9 @@ vvinit(unit)
        DELAY(500000);                          /* let contacts settle */
        vs->vs_init = 0;
        vs->vs_nottaken = 0;
        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.
        /*
         * Hang a receive and start any
         * pending writes by faking a transmit complete.
@@ -231,9 +238,9 @@ vvidentify(unit)
        register struct vv_softc *vs;
        register struct uba_device *ui;
        register struct vvreg *addr;
        register struct vv_softc *vs;
        register struct uba_device *ui;
        register struct vvreg *addr;
-       struct mbuf *m;
-       struct vv_header *v;
-       int ubainfo, attempts, waitcount;
+       register struct mbuf *m;
+       register struct vv_header *v;
+       register int ubainfo, attempts, waitcount;
 
        /*
         * Build a multicast message to identify our address
 
        /*
         * Build a multicast message to identify our address
@@ -243,8 +250,10 @@ vvidentify(unit)
        addr = (struct vvreg *)ui->ui_addr;
        attempts = 0;           /* total attempts, including bad msg type */
        m = m_get(M_DONTWAIT, MT_HEADER);
        addr = (struct vvreg *)ui->ui_addr;
        attempts = 0;           /* total attempts, including bad msg type */
        m = m_get(M_DONTWAIT, MT_HEADER);
-       if (m == NULL)
+       if (m == NULL) {
+               printf("vv%d: can't initialize, m_get() failed\n", unit);
                return (0);
                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);
@@ -281,7 +290,7 @@ retry:
        addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
        /*
         * Wait for receive side to finish.
        addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
        /*
         * 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.
         */
        DELAY(10000);
         * and post to interface structure.
         */
        DELAY(10000);
@@ -290,19 +299,20 @@ retry:
                        DELAY(1000);
                        continue;
                }
                        DELAY(1000);
                        continue;
                }
-               if (attempts++ >= 10) {
-                       printf("vv%d: can't initialize\n", unit);
-                       printf("vvinit loopwait: icsr = %b\n",
-                               0xffff&(addr->vvicsr), VV_IBITS);
-                       vs->vs_if.if_flags &= ~IFF_UP;
-                       return (0);
-               }
-               goto retry;
+               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);
@@ -328,14 +338,13 @@ retry:
 vvstart(dev)
        dev_t dev;
 {
 vvstart(dev)
        dev_t dev;
 {
-        int unit = VVUNIT(dev);
-       struct uba_device *ui;
+       register struct uba_device *ui;
        register struct vv_softc *vs;
        register struct vvreg *addr;
        register struct vv_softc *vs;
        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)
        ui = vvinfo[unit];
        vs = &vv_softc[unit];
        if (vs->vs_oactive)
@@ -345,7 +354,9 @@ vvstart(dev)
         * and map it to the UNIBUS.  If no more requests,
         * just return.
         */
         * 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);
+       splx(s);
        if (m == NULL) {
                vs->vs_oactive = 0;
                return;
        if (m == NULL) {
                vs->vs_oactive = 0;
                return;
@@ -356,11 +367,9 @@ vvstart(dev)
 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.
-        */
-       /*
-        * The following test is questionable and isn't done in
-        * the en driver...
+        * 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);
         */
        if (vs->vs_olen > VVMTU + sizeof (struct vv_header)) {
                printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen);
@@ -374,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;
 }
 
@@ -391,6 +401,7 @@ vvxint(unit)
 
        ui = vvinfo[unit];
        vs = &vv_softc[unit];
 
        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) {
        addr = (struct vvreg *)ui->ui_addr;
        oc = 0xffff & (addr->vvocsr);
        if (vs->vs_oactive == 0) {
@@ -423,13 +434,29 @@ vvxint(unit)
                m_freem(vs->vs_ifuba.ifu_xtofree);
                vs->vs_ifuba.ifu_xtofree = 0;
        }
                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 = 256;             /* an invalid address */
-               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.
@@ -443,24 +470,24 @@ vvrint(unit)
        int unit;
 {
        register struct vv_softc *vs;
        int unit;
 {
        register struct vv_softc *vs;
-       struct vvreg *addr;
+       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];
        short resid;
 
        vs = &vv_softc[unit];
-       addr = (struct vvreg *)vvinfo[unit]->ui_addr;
        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) {
-               if (vs->vs_if.if_flags & IFF_DEBUG && vv_logreaderrors)
-                       printf("vv%d: error vvicsr = %b\n", unit,
+               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;
        }
                            0xffff&(addr->vvicsr), VV_IBITS);
                goto dropit;
        }
@@ -483,31 +510,55 @@ vvrint(unit)
                resid |= 0176000;               /* ugly!!!! */
        len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1;
        len -= sizeof(struct vv_header);
                resid |= 0176000;               /* ugly!!!! */
        len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1;
        len -= sizeof(struct vv_header);
-       if (len > VVMRU || len <= 0)
+       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;
                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;
 #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 (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;
                        goto dropit;
+               }
                vv->vh_type = *vvdataaddr(vv, off, u_short *);
                resid = *(vvdataaddr(vv, off+2, u_short *));
                vv->vh_type = *vvdataaddr(vv, off, u_short *);
                resid = *(vvdataaddr(vv, off+2, u_short *));
-               if (off + resid > len)
+               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;
                        goto dropit;
+               }
                len = off + resid;
        } else
                off = 0;
                len = off + resid;
        } else
                off = 0;
-       if (len == 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;
                goto dropit;
+       }
        m = if_rubaget(&vs->vs_ifuba, len, off);
        m = if_rubaget(&vs->vs_ifuba, len, off);
-       if (m == NULL)
+       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;
                goto dropit;
+       }
        if (off) {
                m->m_off += 2 * sizeof(u_short);
                m->m_len -= 2 * sizeof(u_short);
        }
 
        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
         */
        /*
         * Demultiplex on packet type
         */
@@ -524,12 +575,14 @@ vvrint(unit)
                m_freem(m);
                goto setup;
        }
                m_freem(m);
                goto setup;
        }
+       s = splimp();
        if (IF_QFULL(inq)) {
                IF_DROP(inq);
                m_freem(m);
        } else
                IF_ENQUEUE(inq, m);
 
        if (IF_QFULL(inq)) {
                IF_DROP(inq);
                m_freem(m);
        } else
                IF_ENQUEUE(inq, m);
 
+       splx(s);
        /*
         * Reset for the next packet.
         */
        /*
         * Reset for the next packet.
         */
@@ -547,9 +600,6 @@ setup:
         */
 dropit:
        vs->vs_if.if_ierrors++;
         */
 dropit:
        vs->vs_if.if_ierrors++;
-       if (vs->vs_if.if_flags & IFF_DEBUG && vv_logreaderrors)
-               printf("vv%d: error vvicsr = %b\n", unit,
-                   0xffff&(addr->vvicsr), VV_IBITS);
        goto setup;
 }
 
        goto setup;
 }
 
@@ -564,10 +614,38 @@ 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 int off;
        register struct vv_header *vv;
        register int off;
-       int type, dest, s, error;
+       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) {
 
 
        switch (dst->sa_family) {
 
@@ -595,8 +673,7 @@ vvoutput(ifp, m0, dst)
                goto gottype;
 #endif
        default:
                goto gottype;
 #endif
        default:
-               printf("vv%d: can't handle af%d\n", ifp->if_unit,
-                       dst->sa_family);
+               printf("vv%d: can't handle af%d\n", unit, dst->sa_family);
                error = EAFNOSUPPORT;
                goto bad;
        }
                error = EAFNOSUPPORT;
                goto bad;
        }
@@ -652,8 +729,8 @@ gottype:
                goto qfull;
        }
        IF_ENQUEUE(&ifp->if_snd, m);
                goto qfull;
        }
        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);
        return (0);
 qfull:
        splx(s);
        return (0);
 qfull:
@@ -672,8 +749,9 @@ vvioctl(ifp, cmd, data)
        int cmd;
        caddr_t data;
 {
        int cmd;
        caddr_t data;
 {
-       struct ifreq *ifr;
-       int s, error;
+       register struct ifreq *ifr;
+       register int s;
+       int error;
 
        ifr = (struct ifreq *)data;
        error = 0;
 
        ifr = (struct ifreq *)data;
        error = 0;
@@ -681,25 +759,26 @@ vvioctl(ifp, cmd, data)
        switch (cmd) {
 
        case SIOCSIFADDR:
        switch (cmd) {
 
        case SIOCSIFADDR:
-               /* too difficult to change addr while running */
-               if ((ifp->if_flags & IFF_RUNNING) == 0) {
-                       vvsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
+               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);
                        vvinit(ifp->if_unit);
-               } else
-                       error = EINVAL;
                break;
 
        default:
                error = EINVAL;
        }
        splx(s);
                break;
 
        default:
                error = EINVAL;
        }
        splx(s);
-       return (error);
+       return(error);
 }
 
 /*
  * Set up the address for this interface. We use the network number
 }
 
 /*
  * Set up the address for this interface. We use the network number
- * from the passed address and an invalid host number because vvinit()
- * is smart enough to figure out the host number out.
+ * 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;
  */
 vvsetaddr(ifp, sin)
        register struct ifnet *ifp;