Latest fixes from Nesheim@cornell
[unix-history] / usr / src / sys / vax / if / if_il.c
index 4c7bea5..57802c7 100644 (file)
@@ -1,48 +1,65 @@
-/*     if_il.c 4.1     82/05/21        */
+/*
+ * Copyright (c) 1982 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ *     @(#)if_il.c     6.8 (Berkeley) %G%
+ */
 
 #include "il.h"
 
 #include "il.h"
-#include "imp.h"
-#include "loop.h"
 
 /*
  * Interlan Ethernet Communications Controller interface
  */
 
 /*
  * Interlan Ethernet Communications Controller interface
  */
+#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 "ioctl.h"
+#include "errno.h"
 
 
-#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/ilreg.h"
-#include "../h/cpu.h"
-#include "../h/mtpr.h"
-#include "../h/vmmac.h"
-#include "../net/in.h"
-#include "../net/in_systm.h"
 #include "../net/if.h"
 #include "../net/if.h"
-#include "../net/if_il.h"
-#include "../net/if_uba.h"
-#include "../net/ip.h"
-#include "../net/ip_var.h"
-#include "../net/pup.h"
+#include "../net/netisr.h"
 #include "../net/route.h"
 #include "../net/route.h"
-#include <errno.h>
 
 
-#define        ILMTU   1500
+#ifdef INET
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/in_var.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+#include "../netinet/if_ether.h"
+#endif
+
+#ifdef PUP
+#include "../netpup/pup.h"
+#endif
+
+#ifdef NS
+#include "../netns/ns.h"
+#include "../netns/ns_if.h"
+#endif
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "if_il.h"
+#include "if_ilreg.h"
+#include "if_uba.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
 
 int    ilprobe(), ilattach(), ilrint(), ilcint();
 struct uba_device *ilinfo[NIL];
 u_short ilstd[] = { 0 };
 struct uba_driver ildriver =
        { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo };
 
 int    ilprobe(), ilattach(), ilrint(), ilcint();
 struct uba_device *ilinfo[NIL];
 u_short ilstd[] = { 0 };
 struct uba_driver ildriver =
        { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo };
-u_char il_ectop[3] = { 0x02, 0x60, 0x8c };
 #define        ILUNIT(x)       minor(x)
 #define        ILUNIT(x)       minor(x)
-
-int    ilinit(),iloutput(),ilreset();
+int    ilinit(),iloutput(),ilioctl(),ilreset(),ilwatch();
 
 /*
  * Ethernet software status per interface.
 
 /*
  * Ethernet software status per interface.
@@ -57,17 +74,22 @@ int ilinit(),iloutput(),ilreset();
  * efficiently.
  */
 struct il_softc {
  * efficiently.
  */
 struct il_softc {
-       struct  ifnet is_if;            /* network-visible interface */
+       struct  arpcom is_ac;           /* Ethernet common part */
+#define        is_if   is_ac.ac_if             /* network-visible interface */
+#define        is_addr is_ac.ac_enaddr         /* hardware Ethernet address */
        struct  ifuba is_ifuba;         /* UNIBUS resources */
        struct  ifuba is_ifuba;         /* UNIBUS resources */
-       short   is_oactive;             /* is output active? */
-       short   is_startrcv;            /* hang receive next chance */
-       u_char  is_enaddr[6];           /* board's ethernet address */
+       int     is_flags;
+#define        ILF_OACTIVE     0x1             /* output is active */
+#define        ILF_RCVPENDING  0x2             /* start rcv in ilcint */
+#define        ILF_STATPENDING 0x4             /* stat cmd pending */
+       short   is_lastcmd;             /* can't read csr, so must save it */
+       short   is_scaninterval;        /* interval of stat collection */
+#define        ILWATCHINTERVAL 60              /* once every 60 seconds */
+       struct  il_stats is_stats;      /* holds on-board statistics */
+       struct  il_stats is_sum;        /* summation over time */
+       int     is_ubaddr;              /* mapping registers of is_stats */
 } il_softc[NIL];
 
 } il_softc[NIL];
 
-/*
- * Do an OFFLINE command.  This will cause an interrupt for the
- * autoconfigure stuff.
- */
 ilprobe(reg)
        caddr_t reg;
 {
 ilprobe(reg)
        caddr_t reg;
 {
@@ -75,21 +97,19 @@ ilprobe(reg)
        register struct ildevice *addr = (struct ildevice *)reg;
        register i;
 
        register struct ildevice *addr = (struct ildevice *)reg;
        register i;
 
-COUNT(ILPROBE);
 #ifdef lint
        br = 0; cvec = br; br = cvec;
 #ifdef lint
        br = 0; cvec = br; br = cvec;
-       ilrint(0); ilcint(0);
+       i = 0; ilrint(i); ilcint(i); ilwatch(i);
 #endif
 
        addr->il_csr = ILC_OFFLINE|IL_CIE;
        DELAY(100000);
 #endif
 
        addr->il_csr = ILC_OFFLINE|IL_CIE;
        DELAY(100000);
-       i = addr->il_csr;               /* Clear CDONE */
+       i = addr->il_csr;               /* clear CDONE */
        if (cvec > 0 && cvec != 0x200)
                cvec -= 4;
        return (1);
 }
 
        if (cvec > 0 && cvec != 0x200)
                cvec -= 4;
        return (1);
 }
 
-struct il_stat ilbuf;
 /*
  * Interface exists: make available by filling in network interface
  * record.  System will initialize the interface when it is ready
 /*
  * Interface exists: make available by filling in network interface
  * record.  System will initialize the interface when it is ready
@@ -100,77 +120,55 @@ ilattach(ui)
        struct uba_device *ui;
 {
        register struct il_softc *is = &il_softc[ui->ui_unit];
        struct uba_device *ui;
 {
        register struct il_softc *is = &il_softc[ui->ui_unit];
-       register struct sockaddr_in *sin;
+       register struct ifnet *ifp = &is->is_if;
        register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
        register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
-       register int i;
-       int s;
-       int ubaddr;
-COUNT(ILATTACH);
 
 
-       is->is_if.if_unit = ui->ui_unit;
-       is->is_if.if_name = "il";
-       is->is_if.if_mtu = ILMTU;
-       is->is_if.if_net = ui->ui_flags & 0xff;
+       ifp->if_unit = ui->ui_unit;
+       ifp->if_name = "il";
+       ifp->if_mtu = ETHERMTU;
+       ifp->if_flags = IFF_BROADCAST;
 
        /*
 
        /*
-        * Reset the board
+        * Reset the board and map the statistics
+        * buffer onto the Unibus.
         */
         */
-       s = splimp();
-       addr->il_csr = ((ubaddr>>2)&0xc000)|ILC_RESET;
-       while (!(addr->il_csr & IL_CDONE))
-               /* Busy wait */;
-       if (addr->il_csr & IL_STATUS)
-               printf("il%d: %s\n", ui->ui_unit,
-                   ildiag[addr->il_csr & IL_STATUS]);
-       splx(s);
+       addr->il_csr = ILC_RESET;
+       while ((addr->il_csr&IL_CDONE) == 0)
+               ;
+       if (addr->il_csr&IL_STATUS)
+               printf("il%d: reset failed, csr=%b\n", ui->ui_unit,
+                       addr->il_csr, IL_BITS);
        
        
-       /*
-        * Map the status buffer to the Unibus, do the status command,
-        * and unmap the buffer.
-        */ 
-       ubaddr = uballoc(ui->ui_ubanum, &ilbuf, sizeof(ilbuf), 0);
-       s = splimp();
-       addr->il_bar = ubaddr & 0xffff;
-       addr->il_bcr = sizeof(ilbuf);
-       addr->il_csr = ((ubaddr>>2)&0xc000)|ILC_STAT;
-       while (!(addr->il_csr & IL_CDONE))
-               /* Busy wait */;
-       if (addr->il_csr & IL_STATUS)
-               printf("il%d: %s\n", ui->ui_unit,
-                   ilerrs[addr->il_csr & IL_STATUS]);
-       splx(s);
-       ubarelse(ui->ui_ubanum, &ubaddr);
-       /*
-        * Fill in the Ethernet address from the status buffer
-        */
-       for (i=0; i<6; i++)
-               is->is_enaddr[i] = ilbuf.ils_addr[i];
+       is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats,
+           sizeof (struct il_stats), 0);
+       addr->il_bar = is->is_ubaddr & 0xffff;
+       addr->il_bcr = sizeof (struct il_stats);
+       addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT;
+       while ((addr->il_csr&IL_CDONE) == 0)
+               ;
+       if (addr->il_csr&IL_STATUS)
+               printf("il%d: status failed, csr=%b\n", ui->ui_unit,
+                       addr->il_csr, IL_BITS);
+       ubarelse(ui->ui_ubanum, &is->is_ubaddr);
+#ifdef notdef
        printf("il%d: addr=%x:%x:%x:%x:%x:%x module=%s firmware=%s\n",
                ui->ui_unit,
        printf("il%d: addr=%x:%x:%x:%x:%x:%x module=%s firmware=%s\n",
                ui->ui_unit,
-               is->is_enaddr[0]&0xff, is->is_enaddr[1]&0xff,
-               is->is_enaddr[2]&0xff, is->is_enaddr[3]&0xff,
-               is->is_enaddr[4]&0xff, is->is_enaddr[5]&0xff,
-               ilbuf.ils_module, ilbuf.ils_firmware);
-       is->is_if.if_host[0] = ((is->is_enaddr[3]&0xff)<<16) | 0x800000 |
-           ((is->is_enaddr[4]&0xff)<<8) | (is->is_enaddr[5]&0xff);
-       sin = (struct sockaddr_in *)&is->is_if.if_addr;
-       sin->sin_family = AF_INET;
-       sin->sin_addr = if_makeaddr(is->is_if.if_net, is->is_if.if_host[0]);
-
-       sin = (struct sockaddr_in *)&is->is_if.if_broadaddr;
-       sin->sin_family = AF_INET;
-       sin->sin_addr = if_makeaddr(is->is_if.if_net, 0);
-       is->is_if.if_flags = IFF_BROADCAST;
-
-       is->is_if.if_init = ilinit;
-       is->is_if.if_output = iloutput;
-       is->is_if.if_ubareset = ilreset;
+               is->is_stats.ils_addr[0]&0xff, is->is_stats.ils_addr[1]&0xff,
+               is->is_stats.ils_addr[2]&0xff, is->is_stats.ils_addr[3]&0xff,
+               is->is_stats.ils_addr[4]&0xff, is->is_stats.ils_addr[5]&0xff,
+               is->is_stats.ils_module, is->is_stats.ils_firmware);
+#endif
+       bcopy((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr,
+           sizeof (is->is_addr));
+       ifp->if_init = ilinit;
+       ifp->if_output = iloutput;
+       ifp->if_ioctl = ilioctl;
+       ifp->if_reset = ilreset;
        is->is_ifuba.ifu_flags = UBA_CANTWAIT;
        is->is_ifuba.ifu_flags = UBA_CANTWAIT;
-       if_attach(&is->is_if);
-#if NIMP == 0
-       if (ui->ui_flags &~ 0xff)
-               illhinit((ui->ui_flags &~ 0xff) | 0x0a);
+#ifdef notdef
+       is->is_ifuba.ifu_flags |= UBA_NEEDBDP;
 #endif
 #endif
+       if_attach(ifp);
 }
 
 /*
 }
 
 /*
@@ -181,7 +179,6 @@ ilreset(unit, uban)
        int unit, uban;
 {
        register struct uba_device *ui;
        int unit, uban;
 {
        register struct uba_device *ui;
-COUNT(ILRESET);
 
        if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 ||
            ui->ui_ubanum != uban)
 
        if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 ||
            ui->ui_ubanum != uban)
@@ -200,17 +197,41 @@ ilinit(unit)
        register struct il_softc *is = &il_softc[unit];
        register struct uba_device *ui = ilinfo[unit];
        register struct ildevice *addr;
        register struct il_softc *is = &il_softc[unit];
        register struct uba_device *ui = ilinfo[unit];
        register struct ildevice *addr;
-       register i;
+       register struct ifnet *ifp = &is->is_if;
        int s;
 
        int s;
 
+       /* not yet, if address still unknown */
+       if (ifp->if_addrlist == (struct ifaddr *)0)
+               return;
+
+       if (ifp->if_flags & IFF_RUNNING)
+               return;
        if (if_ubainit(&is->is_ifuba, ui->ui_ubanum,
        if (if_ubainit(&is->is_ifuba, ui->ui_ubanum,
-           sizeof (struct il_rheader), (int)btoc(ILMTU)) == 0) { 
+           sizeof (struct il_rheader), (int)btoc(ETHERMTU)) == 0) { 
                printf("il%d: can't initialize\n", unit);
                is->is_if.if_flags &= ~IFF_UP;
                return;
        }
                printf("il%d: can't initialize\n", unit);
                is->is_if.if_flags &= ~IFF_UP;
                return;
        }
+       is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats,
+           sizeof (struct il_stats), 0);
+       ifp->if_watchdog = ilwatch;
+       is->is_scaninterval = ILWATCHINTERVAL;
+       ifp->if_timer = is->is_scaninterval;
        addr = (struct ildevice *)ui->ui_addr;
 
        addr = (struct ildevice *)ui->ui_addr;
 
+       /*
+        * Turn off source address insertion (it's faster this way),
+        * and set board online.  Former doesn't work if board is
+        * already online (happens on ubareset), so we put it offline
+        * first.
+        */
+       s = splimp();
+       addr->il_csr = ILC_OFFLINE;
+       while ((addr->il_csr & IL_CDONE) == 0)
+               ;
+       addr->il_csr = ILC_CISA;
+       while ((addr->il_csr & IL_CDONE) == 0)
+               ;
        /*
         * Set board online.
         * Hang receive buffer and start any pending
        /*
         * Set board online.
         * Hang receive buffer and start any pending
@@ -218,22 +239,20 @@ ilinit(unit)
         * Receive bcr is not a muliple of 4 so buffer
         * chaining can't happen.
         */
         * Receive bcr is not a muliple of 4 so buffer
         * chaining can't happen.
         */
-       s = splimp();
        addr->il_csr = ILC_ONLINE;
        addr->il_csr = ILC_ONLINE;
-       while (!(addr->il_csr & IL_CDONE))
-               /* Busy wait */;
+       while ((addr->il_csr & IL_CDONE) == 0)
+               ;
        addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
        addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
-       addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6;
-       addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info>>2)&0xc000)|
-                       ILC_RCV|IL_RIE;
-       while (!(addr->il_csr & IL_CDONE))
-               /* Busy wait */;
-       is->is_startrcv = 0;
-       is->is_oactive = 1;
-       is->is_if.if_flags |= IFF_UP;
+       addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
+       addr->il_csr =
+           ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
+       while ((addr->il_csr & IL_CDONE) == 0)
+               ;
+       is->is_flags = ILF_OACTIVE;
+       is->is_if.if_flags |= IFF_RUNNING;
+       is->is_lastcmd = 0;
        ilcint(unit);
        splx(s);
        ilcint(unit);
        splx(s);
-       if_rtinit(&is->is_if, RTF_DIRECT|RTF_UP);
 }
 
 /*
 }
 
 /*
@@ -244,81 +263,97 @@ ilinit(unit)
 ilstart(dev)
        dev_t dev;
 {
 ilstart(dev)
        dev_t dev;
 {
-        int unit = ILUNIT(dev);
+        int unit = ILUNIT(dev), len;
        struct uba_device *ui = ilinfo[unit];
        register struct il_softc *is = &il_softc[unit];
        register struct ildevice *addr;
        struct uba_device *ui = ilinfo[unit];
        register struct il_softc *is = &il_softc[unit];
        register struct ildevice *addr;
-       register len;
        struct mbuf *m;
        struct mbuf *m;
-       int dest;
-COUNT(ILSTART);
+       short csr;
 
 
-       /*
-        * Dequeue another request and copy it into the buffer.
-        * If no more requests, just return.
-        */
        IF_DEQUEUE(&is->is_if.if_snd, m);
        IF_DEQUEUE(&is->is_if.if_snd, m);
-       if (m == 0)
-               return;
+       addr = (struct ildevice *)ui->ui_addr;
+       if (m == 0) {
+               if ((is->is_flags & ILF_STATPENDING) == 0)
+                       return;
+               addr->il_bar = is->is_ubaddr & 0xffff;
+               addr->il_bcr = sizeof (struct il_stats);
+               csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT|IL_RIE|IL_CIE;
+               is->is_flags &= ~ILF_STATPENDING;
+               goto startcmd;
+       }
        len = if_wubaput(&is->is_ifuba, m);
        len = if_wubaput(&is->is_ifuba, m);
-
        /*
        /*
-        * Flush BDP, then start the output.
+        * Ensure minimum packet length.
+        * This makes the safe assumtion that there are no virtual holes
+        * after the data.
+        * For security, it might be wise to zero out the added bytes,
+        * but we're mainly interested in speed at the moment.
         */
         */
+       if (len - sizeof(struct ether_header) < ETHERMIN)
+               len = ETHERMIN + sizeof(struct ether_header);
        if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
                UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp);
        if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
                UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp);
-       addr = (struct ildevice *)ui->ui_addr;
        addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff;
        addr->il_bcr = len;
        addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff;
        addr->il_bcr = len;
-       addr->il_csr = ((is->is_ifuba.ifu_w.ifrw_info>>2)&0xc000)|
-                       ILC_XMIT|IL_CIE|IL_RIE;
-       is->is_oactive = 1;
+       csr =
+         ((is->is_ifuba.ifu_w.ifrw_info >> 2) & IL_EUA)|ILC_XMIT|IL_CIE|IL_RIE;
+
+startcmd:
+       is->is_lastcmd = csr & IL_CMD;
+       addr->il_csr = csr;
+       is->is_flags |= ILF_OACTIVE;
 }
 
 /*
  * Command done interrupt.
 }
 
 /*
  * Command done interrupt.
- * This should only happen after a transmit command,
- * so it is equivalent to a transmit interrupt.
- * Start another output if more data to send.
  */
 ilcint(unit)
        int unit;
 {
  */
 ilcint(unit)
        int unit;
 {
-       register struct uba_device *ui = ilinfo[unit];
        register struct il_softc *is = &il_softc[unit];
        register struct il_softc *is = &il_softc[unit];
+       struct uba_device *ui = ilinfo[unit];
        register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
        register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
-       register int err;
-COUNT(ILCINT);
+       short csr;
 
 
-       if (is->is_oactive == 0) {
-               printf("il%d: strange xmit interrupt!\n", unit);
+       if ((is->is_flags & ILF_OACTIVE) == 0) {
+               printf("il%d: stray xmit interrupt, csr=%b\n", unit,
+                       addr->il_csr, IL_BITS);
                return;
        }
                return;
        }
-       is->is_if.if_opackets++;
-       is->is_oactive = 0;
-       if (err = (addr->il_csr & IL_STATUS)){
-               is->is_if.if_oerrors++;
-               printf("il%d: output error %d\n", unit, err);
-       }
+
+       csr = addr->il_csr;
        /*
        /*
-        * Hang receive buffer if it couldn't be done earlier (in ilrint).
+        * Hang receive buffer if it couldn't
+        * be done earlier (in ilrint).
         */
         */
-       if (is->is_startrcv) {
+       if (is->is_flags & ILF_RCVPENDING) {
                addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
                addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
-               addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6;
-               addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info>>2)&0xc000)|
-                               ILC_RCV|IL_RIE;
-               while (!(addr->il_csr & IL_CDONE))
-                       /* Busy wait */;
-               is->is_startrcv = 0;
+               addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
+               addr->il_csr =
+                 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
+               while ((addr->il_csr & IL_CDONE) == 0)
+                       ;
+               is->is_flags &= ~ILF_RCVPENDING;
+       }
+       is->is_flags &= ~ILF_OACTIVE;
+       csr &= IL_STATUS;
+       switch (is->is_lastcmd) {
+
+       case ILC_XMIT:
+               is->is_if.if_opackets++;
+               if (csr > ILERR_RETRIES)
+                       is->is_if.if_oerrors++;
+               break;
+
+       case ILC_STAT:
+               if (csr == ILERR_SUCCESS)
+                       iltotal(is);
+               break;
        }
        if (is->is_ifuba.ifu_xtofree) {
                m_freem(is->is_ifuba.ifu_xtofree);
                is->is_ifuba.ifu_xtofree = 0;
        }
        }
        if (is->is_ifuba.ifu_xtofree) {
                m_freem(is->is_ifuba.ifu_xtofree);
                is->is_ifuba.ifu_xtofree = 0;
        }
-       if (is->is_if.if_snd.ifq_head == 0) {
-               return;
-       }
        ilstart(unit);
 }
 
        ilstart(unit);
 }
 
@@ -338,39 +373,38 @@ ilrint(unit)
        struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr;
        register struct il_rheader *il;
        struct mbuf *m;
        struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr;
        register struct il_rheader *il;
        struct mbuf *m;
-       int len, off, resid;
+       int len, off, resid, s;
        register struct ifqueue *inq;
 
        register struct ifqueue *inq;
 
-COUNT(ILRINT);
        is->is_if.if_ipackets++;
        if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
                UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp);
        il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr);
        len = il->ilr_length - sizeof(struct il_rheader);
        is->is_if.if_ipackets++;
        if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
                UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp);
        il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr);
        len = il->ilr_length - sizeof(struct il_rheader);
-       if (il->ilr_status&0x3 || len < 46 || len > ILMTU) {
+       if ((il->ilr_status&(ILFSTAT_A|ILFSTAT_C)) || len < 46 ||
+           len > ETHERMTU) {
                is->is_if.if_ierrors++;
 #ifdef notdef
                if (is->is_if.if_ierrors % 100 == 0)
                        printf("il%d: += 100 input errors\n", unit);
 #endif
                is->is_if.if_ierrors++;
 #ifdef notdef
                if (is->is_if.if_ierrors % 100 == 0)
                        printf("il%d: += 100 input errors\n", unit);
 #endif
-               printf("il%d: input error (status=%x, len=%d)\n", unit,
-                   il->ilr_status, len);
                goto setup;
        }
 
        /*
                goto setup;
        }
 
        /*
-        * Deal with trailer protocol: if type is PUP trailer
+        * Deal with trailer protocol: if type is trailer type
         * get true type from first 16-bit word past data.
         * Remember that type was trailer by setting off.
         */
         * get true type from first 16-bit word past data.
         * Remember that type was trailer by setting off.
         */
+       il->ilr_type = ntohs((u_short)il->ilr_type);
 #define        ildataaddr(il, off, type)       ((type)(((caddr_t)((il)+1)+(off))))
 #define        ildataaddr(il, off, type)       ((type)(((caddr_t)((il)+1)+(off))))
-       if (il->ilr_type >= ILPUP_TRAIL &&
-           il->ilr_type < ILPUP_TRAIL+ILPUP_NTRAILER) {
-               off = (il->ilr_type - ILPUP_TRAIL) * 512;
-               if (off >= ILMTU)
+       if (il->ilr_type >= ETHERTYPE_TRAIL &&
+           il->ilr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+               off = (il->ilr_type - ETHERTYPE_TRAIL) * 512;
+               if (off >= ETHERMTU)
                        goto setup;             /* sanity */
                        goto setup;             /* sanity */
-               il->ilr_type = *ildataaddr(il, off, u_short *);
-               resid = *(ildataaddr(il, off+2, u_short *));
+               il->ilr_type = ntohs(*ildataaddr(il, off, u_short *));
+               resid = ntohs(*(ildataaddr(il, off+2, u_short *)));
                if (off + resid > len)
                        goto setup;             /* sanity */
                len = off + resid;
                if (off + resid > len)
                        goto setup;             /* sanity */
                len = off + resid;
@@ -395,21 +429,34 @@ COUNT(ILRINT);
        switch (il->ilr_type) {
 
 #ifdef INET
        switch (il->ilr_type) {
 
 #ifdef INET
-       case ILPUP_IPTYPE:
+       case ETHERTYPE_IP:
                schednetisr(NETISR_IP);
                inq = &ipintrq;
                break;
                schednetisr(NETISR_IP);
                inq = &ipintrq;
                break;
+
+       case ETHERTYPE_ARP:
+               arpinput(&is->is_ac, m);
+               goto setup;
+#endif
+#ifdef NS
+       case ETHERTYPE_NS:
+               schednetisr(NETISR_NS);
+               inq = &nsintrq;
+               break;
+
 #endif
        default:
                m_freem(m);
                goto setup;
        }
 
 #endif
        default:
                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);
 
 setup:
        /*
 
 setup:
        /*
@@ -417,15 +464,16 @@ setup:
         * If waiting for transmit command completion, set flag
         * and wait until command completes.
         */
         * If waiting for transmit command completion, set flag
         * and wait until command completes.
         */
-       if (!is->is_oactive) {
-               addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
-               addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6;
-               addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info>>2)&0xc000)|
-                               ILC_RCV|IL_RIE;
-               while (!(addr->il_csr & IL_CDONE))
-                       /* Busy wait */;
-       } else
-               is->is_startrcv = 1;
+       if (is->is_flags & ILF_OACTIVE) {
+               is->is_flags |= ILF_RCVPENDING;
+               return;
+       }
+       addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
+       addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
+       addr->il_csr =
+               ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
+       while ((addr->il_csr & IL_CDONE) == 0)
+               ;
 }
 
 /*
 }
 
 /*
@@ -439,34 +487,52 @@ iloutput(ifp, m0, dst)
        struct mbuf *m0;
        struct sockaddr *dst;
 {
        struct mbuf *m0;
        struct sockaddr *dst;
 {
-       int type, dest, s, error;
+       int type, s, error;
+       u_char edst[6];
+       struct in_addr idst;
        register struct il_softc *is = &il_softc[ifp->if_unit];
        register struct mbuf *m = m0;
        register struct il_softc *is = &il_softc[ifp->if_unit];
        register struct mbuf *m = m0;
-       register struct il_xheader *il;
+       register struct ether_header *il;
        register int off;
        register int off;
-       register int i;
 
 
-COUNT(ILOUTPUT);
        switch (dst->sa_family) {
 
 #ifdef INET
        case AF_INET:
        switch (dst->sa_family) {
 
 #ifdef INET
        case AF_INET:
-               dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
+               idst = ((struct sockaddr_in *)dst)->sin_addr;
+               if (!arpresolve(&is->is_ac, m, &idst, edst))
+                       return (0);     /* if not yet resolved */
                off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
                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)) {
                if (off > 0 && (off & 0x1ff) == 0 &&
                    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
-                       type = ILPUP_TRAIL + (off>>9);
+                       type = ETHERTYPE_TRAIL + (off>>9);
                        m->m_off -= 2 * sizeof (u_short);
                        m->m_len += 2 * sizeof (u_short);
                        m->m_off -= 2 * sizeof (u_short);
                        m->m_len += 2 * sizeof (u_short);
-                       *mtod(m, u_short *) = ILPUP_IPTYPE;
-                       *(mtod(m, u_short *) + 1) = m->m_len;
+                       *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
+                       *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
                        goto gottrailertype;
                }
                        goto gottrailertype;
                }
-               type = ILPUP_IPTYPE;
+               type = ETHERTYPE_IP;
+               off = 0;
+               goto gottype;
+#endif
+#ifdef NS
+       case AF_NS:
+               type = ETHERTYPE_NS;
+               bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
+               (caddr_t)edst, sizeof (edst));
                off = 0;
                goto gottype;
 #endif
 
                off = 0;
                goto gottype;
 #endif
 
+       case AF_UNSPEC:
+               il = (struct ether_header *)dst->sa_data;
+               bcopy((caddr_t)il->ether_dhost, (caddr_t)edst, sizeof (edst));
+               type = il->ether_type;
+               goto gottype;
+
        default:
                printf("il%d: can't handle af%d\n", ifp->if_unit,
                        dst->sa_family);
        default:
                printf("il%d: can't handle af%d\n", ifp->if_unit,
                        dst->sa_family);
@@ -492,38 +558,24 @@ gottype:
         * allocate another.
         */
        if (m->m_off > MMAXOFF ||
         * allocate another.
         */
        if (m->m_off > MMAXOFF ||
-           MMINOFF + sizeof (struct il_xheader) > m->m_off) {
-               m = m_get(M_DONTWAIT);
+           MMINOFF + sizeof (struct ether_header) > m->m_off) {
+               m = m_get(M_DONTWAIT, MT_HEADER);
                if (m == 0) {
                        error = ENOBUFS;
                        goto bad;
                }
                m->m_next = m0;
                m->m_off = MMINOFF;
                if (m == 0) {
                        error = ENOBUFS;
                        goto bad;
                }
                m->m_next = m0;
                m->m_off = MMINOFF;
-               m->m_len = sizeof (struct il_xheader);
+               m->m_len = sizeof (struct ether_header);
        } else {
        } else {
-               m->m_off -= sizeof (struct il_xheader);
-               m->m_len += sizeof (struct il_xheader);
-       }
-       il = mtod(m, struct il_xheader *);
-       if ((dest &~ 0xff) == 0)
-               for (i=0; i<6; i++)
-                       il->ilx_dhost[i] = 0xff;
-       else {
-               if (dest & 0x8000) {
-                       il->ilx_dhost[0] = is->is_enaddr[0];
-                       il->ilx_dhost[1] = is->is_enaddr[1];
-                       il->ilx_dhost[2] = is->is_enaddr[2];
-               } else {
-                       il->ilx_dhost[0] = il_ectop[0];
-                       il->ilx_dhost[1] = il_ectop[1];
-                       il->ilx_dhost[2] = il_ectop[2];
-               }
-               il->ilx_dhost[3] = (dest>>8) & 0x7f;
-               il->ilx_dhost[4] = (dest>>16) & 0xff;
-               il->ilx_dhost[5] = (dest>>24) & 0xff;
+               m->m_off -= sizeof (struct ether_header);
+               m->m_len += sizeof (struct ether_header);
        }
        }
-       il->ilx_type = type;
+       il = mtod(m, struct ether_header *);
+       il->ether_type = htons((u_short)type);
+       bcopy((caddr_t)edst, (caddr_t)il->ether_dhost, sizeof (edst));
+       bcopy((caddr_t)is->is_addr, (caddr_t)il->ether_shost,
+           sizeof(il->ether_shost));
 
        /*
         * Queue message on interface, and start output if interface
 
        /*
         * Queue message on interface, and start output if interface
@@ -532,66 +584,97 @@ gottype:
        s = splimp();
        if (IF_QFULL(&ifp->if_snd)) {
                IF_DROP(&ifp->if_snd);
        s = splimp();
        if (IF_QFULL(&ifp->if_snd)) {
                IF_DROP(&ifp->if_snd);
-               error = ENOBUFS;
-               goto qfull;
+               splx(s);
+               m_freem(m);
+               return (ENOBUFS);
        }
        IF_ENQUEUE(&ifp->if_snd, m);
        }
        IF_ENQUEUE(&ifp->if_snd, m);
-       if (is->is_oactive == 0)
+       if ((is->is_flags & ILF_OACTIVE) == 0)
                ilstart(ifp->if_unit);
        splx(s);
        return (0);
                ilstart(ifp->if_unit);
        splx(s);
        return (0);
-qfull:
-       m0 = m;
-       splx(s);
+
 bad:
        m_freem(m0);
 bad:
        m_freem(m0);
-       return(error);
+       return (error);
 }
 
 }
 
-#if NIMP == 0 && NIL > 0
 /*
 /*
- * Logical host interface driver.
- * Allows host to appear as an ARPAnet
- * logical host.  Must also have routing
- * table entry set up to forward packets
- * to appropriate gateway on localnet.
+ * Watchdog routine, request statistics from board.
  */
  */
+ilwatch(unit)
+       int unit;
+{
+       register struct il_softc *is = &il_softc[unit];
+       register struct ifnet *ifp = &is->is_if;
+       int s;
 
 
-struct ifnet illhif;
-int    illhoutput();
+       if (is->is_flags & ILF_STATPENDING) {
+               ifp->if_timer = is->is_scaninterval;
+               return;
+       }
+       s = splimp();
+       is->is_flags |= ILF_STATPENDING;
+       if ((is->is_flags & ILF_OACTIVE) == 0)
+               ilstart(ifp->if_unit);
+       splx(s);
+       ifp->if_timer = is->is_scaninterval;
+}
 
 /*
 
 /*
- * Called by localnet interface to allow logical
- * host interface to "attach".  Nothing should ever
- * be sent locally to this interface, it's purpose
- * is simply to establish the host's arpanet address.
+ * Total up the on-board statistics.
  */
  */
-illhinit(addr)
-       int addr;
+iltotal(is)
+       register struct il_softc *is;
 {
 {
-       register struct ifnet *ifp = &illhif;
-       register struct sockaddr_in *sin;
-
-COUNT(ILLHINIT);
-       ifp->if_name = "lh";
-       ifp->if_mtu = ILMTU;
-       sin = (struct sockaddr_in *)&ifp->if_addr;
-       sin->sin_family = AF_INET;
-       sin->sin_addr.s_addr = addr;
-       ifp->if_net = sin->sin_addr.s_net;
-       ifp->if_flags = IFF_UP;
-       ifp->if_output = illhoutput;    /* should never be used */
-       if_attach(ifp);
+       register u_short *interval, *sum, *end;
+
+       interval = &is->is_stats.ils_frames;
+       sum = &is->is_sum.ils_frames;
+       end = is->is_sum.ils_fill2;
+       while (sum < end)
+               *sum++ += *interval++;
+       is->is_if.if_collisions = is->is_sum.ils_collis;
 }
 
 }
 
-illhoutput(ifp, m0, dst)
-       struct ifnet *ifp;
-       struct mbuf *m0;
-       struct sockaddr *dst;
+/*
+ * Process an ioctl request.
+ */
+ilioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
 {
 {
-COUNT(ILLHOUTPUT);
-       ifp->if_oerrors++;
-       m_freem(m0);
-       return (0);
-}
+       register struct ifaddr *ifa = (struct ifaddr *)data;
+       int s = splimp(), error = 0;
+
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               ifp->if_flags |= IFF_UP;
+               ilinit(ifp->if_unit);
+
+               switch (ifa->ifa_addr.sa_family) {
+#ifdef INET
+               case AF_INET:
+                       ((struct arpcom *)ifp)->ac_ipaddr =
+                               IA_SIN(ifa)->sin_addr;
+                       arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+                       break;
+#endif
+#ifdef NS
+               case AF_NS:
+                       IA_SNS(ifa)->sns_addr.x_host =
+                               * (union ns_host *) 
+                                    (il_softc[ifp->if_unit].is_addr);
+                       break;
 #endif
 #endif
+               }
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       splx(s);
+       return (error);
+}