+}
+
+/*
+ * vvtimeout() - called by timer flywheel to monitor input packet
+ * discard rate. Interfaces getting too many errors are shut
+ * down for a while. If the condition persists, the interface
+ * is marked down.
+ */
+
+vvtimeout(junk)
+int junk;
+{
+ register struct vv_softc *vs;
+ register int i;
+ register struct vvreg *addr;
+ int ubainfo;
+
+ timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL);
+
+ for (i=0; i<NVV; i++) {
+ vs = &vv_softc[i];
+ addr = (struct vvreg *)vvinfo[i]->ui_addr;
+ if (vs->vs_if.if_flags & IFF_UP == 0) continue;
+ switch (vs->vs_major) {
+
+ /*
+ * MODE0: generally OK, just check error rate
+ */
+
+ case MODE0:
+ if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
+ vs->vs_dropped = 0;
+ continue;
+ }
+ else {
+ /* suspend reads for a while */
+ vvtrprintf("vv%d going MODE1 in vvtimeout\n",i);
+ vs->vs_major = MODE1;
+ vs->vs_iactive = PAUSE; /* no new reads */
+ vs->vs_retry = VV_MODE1ATTEMPTS;
+ vs->vs_delayclock = VV_MODE1DELAY;
+ vs->vs_minor = 0;
+ continue;
+ }
+
+ /*
+ * MODE1: excessive error rate observed
+ * Scheme: try simply suspending reads for a
+ * short while a small number of times
+ */
+
+ case MODE1:
+ if (vs->vs_delayclock > 0) {
+ vs->vs_delayclock--;
+ continue;
+ }
+ switch (vs->vs_minor) {
+ case 0: /* reenable reads */
+ vvtrprintf("vv%d M1m0\n",i);
+ vs->vs_dropped = 0;
+ vs->vs_iactive = ACTIVE;
+ vs->vs_minor = 1; /* next state */
+ 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;
+ continue;
+ case 1: /* see if it worked */
+ vvtrprintf("vv%d M1m1\n",i);
+ if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
+ vs->vs_dropped = 0;
+ vs->vs_major = MODE0; /* yeah!! */
+ continue;
+ }
+ else {
+ if (vs->vs_retry -- > 0) {
+ vs->vs_dropped = 0;
+ vs->vs_iactive = PAUSE;
+ vs->vs_delayclock = VV_MODE1DELAY;
+ vs->vs_minor = 0; /* recheck */
+ continue;
+ }
+ else {
+ vs->vs_major = MODE2;
+ vs->vs_minor = 0;
+ vs->vs_dropped = 0;
+ vs->vs_iactive = OPEN;
+ vs->vs_delayrange = VV_MODE2DELAY;
+ vs->vs_delayclock = VV_MODE2DELAY;
+ }
+ }
+ }
+
+ /*
+ * MODE2: simply ignoring traffic didn't relieve condition
+ * Scheme: open host relay for intervals linearly
+ * increasing up to some maximum of a several minutes.
+ * This allows broken networks to return to operation
+ * without rebooting.
+ */
+
+ case MODE2:
+ if (vs->vs_delayclock > 0) {
+ vs->vs_delayclock--;
+ continue;
+ }
+ switch (vs->vs_minor) {
+ case 0: /* close relay and reenable reads */
+ vvtrprintf("vv%d M2m0\n",i);
+ vs->vs_dropped = 0;
+ vs->vs_iactive = ACTIVE;
+ vs->vs_minor = 1; /* next state */
+ 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;
+ continue;
+ case 1: /* see if it worked */
+ vvtrprintf("vv%d M2m1\n",i);
+ if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
+ vs->vs_dropped = 0;
+ vs->vs_major = MODE0; /* yeah!! */
+ continue;
+ }
+ else {
+ vvtrprintf("vv%d M2m1 ++ delay\n",i);
+ vs->vs_dropped = 0;
+ vs->vs_iactive = OPEN;
+ vs->vs_minor = 0;
+ if (vs->vs_delayrange < VV_MAXDELAY)
+ vs->vs_delayrange += (vs->vs_delayrange/2);
+ vs->vs_delayclock = vs->vs_delayrange;
+ continue;
+ }
+ }
+
+
+ default:
+ printf("vv%d: major state screwed\n", i);
+ vs->vs_if.if_flags &= ~IFF_UP;
+ }
+ }