BSD 4_3_Net_2 release
[unix-history] / usr / src / sys / vax / if / if_il.c
index f63f54f..13b5d34 100644 (file)
@@ -1,59 +1,81 @@
 /*
 /*
- * Copyright (c) 1982 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)if_il.c     6.9 (Berkeley) %G%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)if_il.c     7.8 (Berkeley) 12/16/90
  */
 
 #include "il.h"
  */
 
 #include "il.h"
+#if NIL > 0
 
 /*
  * 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 "../net/if.h"
-#include "../net/netisr.h"
-#include "../net/route.h"
-
-#ifdef BBNNET
-#define        INET
-#endif
-#ifdef INET
-#include "../netinet/in.h"
-#include "../netinet/in_systm.h"
-#include "../netinet/in_var.h"
-#include "../netinet/ip.h"
-#include "../netinet/if_ether.h"
-#endif
+#include "../include/pte.h"
+
+#include "sys/param.h"
+#include "sys/systm.h"
+#include "sys/mbuf.h"
+#include "sys/buf.h"
+#include "sys/protosw.h"
+#include "sys/socket.h"
+#include "sys/vmmac.h"
+#include "sys/ioctl.h"
+#include "sys/errno.h"
+#include "sys/syslog.h"
+
+#include "net/if.h"
+#include "net/netisr.h"
+#include "net/route.h"
 
 
-#ifdef PUP
-#include "../netpup/pup.h"
+#ifdef INET
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#include "netinet/if_ether.h"
 #endif
 
 #ifdef NS
 #endif
 
 #ifdef NS
-#include "../netns/ns.h"
-#include "../netns/ns_if.h"
+#include "netns/ns.h"
+#include "netns/ns_if.h"
 #endif
 
 #endif
 
-#include "../vax/cpu.h"
-#include "../vax/mtpr.h"
+#include "../include/cpu.h"
+#include "../include/mtpr.h"
 #include "if_il.h"
 #include "if_ilreg.h"
 #include "if_uba.h"
 #include "if_il.h"
 #include "if_ilreg.h"
 #include "if_uba.h"
-#include "../vaxuba/ubareg.h"
-#include "../vaxuba/ubavar.h"
+#include "../uba/ubareg.h"
+#include "../uba/ubavar.h"
 
 int    ilprobe(), ilattach(), ilrint(), ilcint();
 struct uba_device *ilinfo[NIL];
 
 int    ilprobe(), ilattach(), ilrint(), ilcint();
 struct uba_device *ilinfo[NIL];
@@ -61,7 +83,8 @@ u_short ilstd[] = { 0 };
 struct uba_driver ildriver =
        { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo };
 #define        ILUNIT(x)       minor(x)
 struct uba_driver ildriver =
        { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo };
 #define        ILUNIT(x)       minor(x)
-int    ilinit(),iloutput(),ilioctl(),ilreset(),ilwatch();
+int    ilinit(),iloutput(),ilioctl(),ilreset(),ilwatch(),ilstart();
+int    ildebug = 0;
 
 /*
  * Ethernet software status per interface.
 
 /*
  * Ethernet software status per interface.
@@ -75,19 +98,29 @@ int ilinit(),iloutput(),ilioctl(),ilreset(),ilwatch();
  * structure for use by the if_uba.c routines in running the interface
  * efficiently.
  */
  * structure for use by the if_uba.c routines in running the interface
  * efficiently.
  */
+
+struct ether_addr {
+       u_char  addr[6];
+};
 struct il_softc {
        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 */
        int     is_flags;
 struct il_softc {
        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 */
        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 */
 #define        ILF_RCVPENDING  0x2             /* start rcv in ilcint */
 #define        ILF_STATPENDING 0x4             /* stat cmd pending */
+#define        ILF_RUNNING     0x8             /* board is running */
+#define        ILF_SETADDR     0x10            /* physical address is changed */
        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 */
        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 */
+       union {
+           struct      il_stats isu_stats;     /* holds on-board statistics */
+           struct      ether_addr isu_maddrs[63];      /* multicast addrs */
+       }       is_isu;
+#define is_stats       is_isu.isu_stats
+#define is_maddrs      is_isu.isu_maddrs
        struct  il_stats is_sum;        /* summation over time */
        int     is_ubaddr;              /* mapping registers of is_stats */
 } il_softc[NIL];
        struct  il_stats is_sum;        /* summation over time */
        int     is_ubaddr;              /* mapping registers of is_stats */
 } il_softc[NIL];
@@ -135,44 +168,47 @@ ilattach(ui)
         * buffer onto the Unibus.
         */
        addr->il_csr = ILC_RESET;
         * buffer onto the Unibus.
         */
        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);
+       (void)ilwait(ui, "reset");
        
        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;
        
        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);
+       (void)ilwait(ui, "status");
        ubarelse(ui->ui_ubanum, &is->is_ubaddr);
        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,
-               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
+       if (ildebug)
+               printf("il%d: module=%s firmware=%s\n", ui->ui_unit,
+                       is->is_stats.ils_module, is->is_stats.ils_firmware);
        bcopy((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr,
            sizeof (is->is_addr));
        bcopy((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr,
            sizeof (is->is_addr));
+       printf("il%d: hardware address %s\n", ui->ui_unit,
+               ether_sprintf(is->is_addr));
        ifp->if_init = ilinit;
        ifp->if_init = ilinit;
-       ifp->if_output = iloutput;
+       ifp->if_output = ether_output;
        ifp->if_ioctl = ilioctl;
        ifp->if_reset = ilreset;
        ifp->if_ioctl = ilioctl;
        ifp->if_reset = ilreset;
+       ifp->if_start = ilstart;
        is->is_ifuba.ifu_flags = UBA_CANTWAIT;
        is->is_ifuba.ifu_flags = UBA_CANTWAIT;
-#ifdef notdef
-       is->is_ifuba.ifu_flags |= UBA_NEEDBDP;
-#endif
        if_attach(ifp);
 }
 
        if_attach(ifp);
 }
 
+ilwait(ui, op)
+       struct uba_device *ui;
+       char *op;
+{
+       register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
+
+       while ((addr->il_csr&IL_CDONE) == 0)
+               ;
+       if (addr->il_csr&IL_STATUS) {
+               printf("il%d: %s failed, csr=%b\n", ui->ui_unit, op,
+                       addr->il_csr, IL_BITS);
+               return (-1);
+       }
+       return (0);
+}
+
 /*
  * Reset of interface after UNIBUS reset.
  * If interface is on specified uba, reset its state.
 /*
  * Reset of interface after UNIBUS reset.
  * If interface is on specified uba, reset its state.
@@ -186,6 +222,8 @@ ilreset(unit, uban)
            ui->ui_ubanum != uban)
                return;
        printf(" il%d", unit);
            ui->ui_ubanum != uban)
                return;
        printf(" il%d", unit);
+       il_softc[unit].is_if.if_flags &= ~IFF_RUNNING;
+       il_softc[unit].is_flags &= ~ILF_RUNNING;
        ilinit(unit);
 }
 
        ilinit(unit);
 }
 
@@ -205,17 +243,19 @@ ilinit(unit)
        /* not yet, if address still unknown */
        if (ifp->if_addrlist == (struct ifaddr *)0)
                return;
        /* 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,
-           sizeof (struct il_rheader), (int)btoc(ETHERMTU)) == 0) { 
-               printf("il%d: can't initialize\n", unit);
-               is->is_if.if_flags &= ~IFF_UP;
+       if (is->is_flags & ILF_RUNNING)
                return;
                return;
+
+       if ((ifp->if_flags & IFF_RUNNING) == 0) {
+               if (if_ubainit(&is->is_ifuba, ui->ui_ubanum,
+                   sizeof (struct il_rheader), (int)btoc(ETHERMTU)) == 0) { 
+                       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_isu,
+                   sizeof (is->is_isu), 0);
        }
        }
-       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;
        ifp->if_watchdog = ilwatch;
        is->is_scaninterval = ILWATCHINTERVAL;
        ifp->if_timer = is->is_scaninterval;
@@ -228,17 +268,91 @@ ilinit(unit)
         * first.
         */
        s = splimp();
         * first.
         */
        s = splimp();
-       addr->il_csr = ILC_OFFLINE;
-       while ((addr->il_csr & IL_CDONE) == 0)
-               ;
+       addr->il_csr = ILC_RESET;
+       if (ilwait(ui, "hardware diag")) {
+               is->is_if.if_flags &= ~IFF_UP;
+               splx(s);
+               return;
+       }
        addr->il_csr = ILC_CISA;
        while ((addr->il_csr & IL_CDONE) == 0)
                ;
        addr->il_csr = ILC_CISA;
        while ((addr->il_csr & IL_CDONE) == 0)
                ;
+       /*
+        * If we must reprogram this board's physical ethernet
+        * address (as for secondary XNS interfaces), we do so
+        * before putting it on line, and starting receive requests.
+        * If you try this on an older 1010 board, it will total
+        * wedge the board.
+        */
+       if (is->is_flags & ILF_SETADDR) {
+               bcopy((caddr_t)is->is_addr, (caddr_t)&is->is_isu,
+                                                       sizeof is->is_addr);
+               addr->il_bar = is->is_ubaddr & 0xffff;
+               addr->il_bcr = sizeof is->is_addr;
+               addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_LDPA;
+               if (ilwait(ui, "setaddr"))
+                       return;
+               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;
+               if (ilwait(ui, "verifying setaddr"))
+                       return;
+               if (bcmp((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr,
+                                               sizeof (is->is_addr)) != 0) {
+                       printf("il%d: setaddr didn't work\n", ui->ui_unit);
+                       return;
+               }
+       }
+#ifdef MULTICAST
+       if (is->is_if.if_flags & IFF_PROMISC) {
+               addr->il_csr = ILC_PRMSC;
+               if (ilwait(ui, "all multi"))
+                       return;
+       } else if (is->is_if.if_flags & IFF_ALLMULTI) {
+       too_many_multis:
+               addr->il_csr = ILC_ALLMC;
+               if (ilwait(ui, "all multi"))
+                       return;
+       else {
+               int i;
+               register struct ether_addr *ep = is->is_maddrs;
+               struct ether_multi *enm;
+               struct ether_multistep step;
+               /*
+                * Step through our list of multicast addresses.  If we have
+                * too many multicast addresses, or if we have to listen to
+                * a range of multicast addresses, turn on reception of all
+                * multicasts.
+                */
+               i = 0;
+               ETHER_FIRST_MULTI(step, &is->is_ac, enm);
+               while (enm != NULL) {
+                       if (++i > 63 && k != 0) {
+                               break;
+                       }
+                       *ep++ = *(struct ether_addr *)enm->enm_addrlo;
+                       ETHER_NEXT_MULTI(step, enm);
+               }
+               if (i = 0) {
+                       /* no multicasts! */
+               } else if (i <= 63) {
+                       addr->il_bar = is->is_ubaddr & 0xffff;
+                       addr->il_bcr = i * sizeof (struct ether_addr);
+                       addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|
+                                               LC_LDGRPS;
+                       if (ilwait(ui, "load multi"))
+                               return;
+               } else {
+                   is->is_if.if_flags |= IFF_ALLMULTI;
+                   goto too_many_multis;
+               }
+       }
+#endif MULTI
        /*
         * Set board online.
         * Hang receive buffer and start any pending
         * writes by faking a transmit complete.
        /*
         * Set board online.
         * Hang receive buffer and start any pending
         * writes by faking a transmit complete.
-        * Receive bcr is not a muliple of 4 so buffer
+        * Receive bcr is not a multiple of 8 so buffer
         * chaining can't happen.
         */
        addr->il_csr = ILC_ONLINE;
         * chaining can't happen.
         */
        addr->il_csr = ILC_ONLINE;
@@ -250,8 +364,8 @@ ilinit(unit)
            ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
        while ((addr->il_csr & IL_CDONE) == 0)
                ;
            ((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_if.if_flags |= IFF_RUNNING | IFF_OACTIVE;
+       is->is_flags |= ILF_RUNNING;
        is->is_lastcmd = 0;
        ilcint(unit);
        splx(s);
        is->is_lastcmd = 0;
        ilcint(unit);
        splx(s);
@@ -262,10 +376,10 @@ ilinit(unit)
  * Get another datagram to send off of the interface queue,
  * and map it to the interface before starting the output.
  */
  * Get another datagram to send off of the interface queue,
  * and map it to the interface before starting the output.
  */
-ilstart(dev)
-       dev_t dev;
+ilstart(ifp)
+       register struct ifnet *ifp;
 {
 {
-        int unit = ILUNIT(dev), len;
+        int unit = ifp->if_unit, 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;
@@ -276,7 +390,7 @@ ilstart(dev)
        addr = (struct ildevice *)ui->ui_addr;
        if (m == 0) {
                if ((is->is_flags & ILF_STATPENDING) == 0)
        addr = (struct ildevice *)ui->ui_addr;
        if (m == 0) {
                if ((is->is_flags & ILF_STATPENDING) == 0)
-                       return;
+                       return (0);
                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;
                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;
@@ -303,7 +417,8 @@ ilstart(dev)
 startcmd:
        is->is_lastcmd = csr & IL_CMD;
        addr->il_csr = csr;
 startcmd:
        is->is_lastcmd = csr & IL_CMD;
        addr->il_csr = csr;
-       is->is_flags |= ILF_OACTIVE;
+       is->is_if.if_flags |= IFF_OACTIVE;
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -317,7 +432,7 @@ ilcint(unit)
        register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
        short csr;
 
        register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
        short csr;
 
-       if ((is->is_flags & ILF_OACTIVE) == 0) {
+       if ((is->is_if.if_flags & IFF_OACTIVE) == 0) {
                printf("il%d: stray xmit interrupt, csr=%b\n", unit,
                        addr->il_csr, IL_BITS);
                return;
                printf("il%d: stray xmit interrupt, csr=%b\n", unit,
                        addr->il_csr, IL_BITS);
                return;
@@ -329,15 +444,19 @@ ilcint(unit)
         * be done earlier (in ilrint).
         */
        if (is->is_flags & ILF_RCVPENDING) {
         * be done earlier (in ilrint).
         */
        if (is->is_flags & ILF_RCVPENDING) {
+               int s;
+
                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;
                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;
+               s = splhigh();
                while ((addr->il_csr & IL_CDONE) == 0)
                        ;
                while ((addr->il_csr & IL_CDONE) == 0)
                        ;
+               splx(s);
                is->is_flags &= ~ILF_RCVPENDING;
        }
                is->is_flags &= ~ILF_RCVPENDING;
        }
-       is->is_flags &= ~ILF_OACTIVE;
+       is->is_if.if_flags &= ~IFF_OACTIVE;
        csr &= IL_STATUS;
        switch (is->is_lastcmd) {
 
        csr &= IL_STATUS;
        switch (is->is_lastcmd) {
 
@@ -356,7 +475,7 @@ ilcint(unit)
                m_freem(is->is_ifuba.ifu_xtofree);
                is->is_ifuba.ifu_xtofree = 0;
        }
                m_freem(is->is_ifuba.ifu_xtofree);
                is->is_ifuba.ifu_xtofree = 0;
        }
-       ilstart(unit);
+       (void) ilstart(&is->is_if);
 }
 
 /*
 }
 
 /*
@@ -422,55 +541,15 @@ ilrint(unit)
         * the type and length which are at the front of any trailer data.
         */
        m = if_rubaget(&is->is_ifuba, len, off, &is->is_if);
         * the type and length which are at the front of any trailer data.
         */
        m = if_rubaget(&is->is_ifuba, len, off, &is->is_if);
-       if (m == 0)
-               goto setup;
-       if (off) {
-               struct ifnet *ifp;
-
-               ifp = *(mtod(m, struct ifnet **));
-               m->m_off += 2 * sizeof (u_short);
-               m->m_len -= 2 * sizeof (u_short);
-               *(mtod(m, struct ifnet **)) = ifp;
-       }
-       switch (il->ilr_type) {
-
-#ifdef INET
-       case ETHERTYPE_IP:
-               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;
-       }
-
-       s = splimp();
-       if (IF_QFULL(inq)) {
-               IF_DROP(inq);
-               m_freem(m);
-       } else
-               IF_ENQUEUE(inq, m);
-       splx(s);
-
+       if (m)
+               ether_input(&is->is_if, (struct ether_header *)il->ilr_dhost, m);
 setup:
        /*
         * Reset for next packet if possible.
         * If waiting for transmit command completion, set flag
         * and wait until command completes.
         */
 setup:
        /*
         * Reset for next packet if possible.
         * If waiting for transmit command completion, set flag
         * and wait until command completes.
         */
-       if (is->is_flags & ILF_OACTIVE) {
+       if (is->is_if.if_flags & IFF_OACTIVE) {
                is->is_flags |= ILF_RCVPENDING;
                return;
        }
                is->is_flags |= ILF_RCVPENDING;
                return;
        }
@@ -478,133 +557,11 @@ setup:
        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;
        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;
+       s = splhigh();
        while ((addr->il_csr & IL_CDONE) == 0)
                ;
        while ((addr->il_csr & IL_CDONE) == 0)
                ;
-}
-
-/*
- * Ethernet output routine.
- * Encapsulate a packet of type family for the local net.
- * Use trailer local net encapsulation if enough data in first
- * packet leaves a multiple of 512 bytes of data in remainder.
- */
-iloutput(ifp, m0, dst)
-       struct ifnet *ifp;
-       struct mbuf *m0;
-       struct sockaddr *dst;
-{
-       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 ether_header *il;
-       register int off;
-
-       switch (dst->sa_family) {
-
-#ifdef INET
-       case AF_INET:
-               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;
-               /* 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 = ETHERTYPE_TRAIL + (off>>9);
-                       m->m_off -= 2 * sizeof (u_short);
-                       m->m_len += 2 * sizeof (u_short);
-                       *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
-                       *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
-                       goto gottrailertype;
-               }
-               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
-
-       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);
-               error = EAFNOSUPPORT;
-               goto bad;
-       }
-
-gottrailertype:
-       /*
-        * Packet to be sent as trailer: move first packet
-        * (control information) to end of chain.
-        */
-       while (m->m_next)
-               m = m->m_next;
-       m->m_next = m0;
-       m = m0->m_next;
-       m0->m_next = 0;
-       m0 = m;
-
-gottype:
-       /*
-        * Add local net header.  If no space in first mbuf,
-        * allocate another.
-        */
-       if (m->m_off > MMAXOFF ||
-           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;
-               m->m_len = sizeof (struct ether_header);
-       } else {
-               m->m_off -= sizeof (struct ether_header);
-               m->m_len += sizeof (struct ether_header);
-       }
-       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
-        * not yet active.
-        */
-       s = splimp();
-       if (IF_QFULL(&ifp->if_snd)) {
-               IF_DROP(&ifp->if_snd);
-               splx(s);
-               m_freem(m);
-               return (ENOBUFS);
-       }
-       IF_ENQUEUE(&ifp->if_snd, m);
-       if ((is->is_flags & ILF_OACTIVE) == 0)
-               ilstart(ifp->if_unit);
        splx(s);
        splx(s);
-       return (0);
-
-bad:
-       m_freem(m0);
-       return (error);
 }
 }
-
 /*
  * Watchdog routine, request statistics from board.
  */
 /*
  * Watchdog routine, request statistics from board.
  */
@@ -621,8 +578,8 @@ ilwatch(unit)
        }
        s = splimp();
        is->is_flags |= ILF_STATPENDING;
        }
        s = splimp();
        is->is_flags |= ILF_STATPENDING;
-       if ((is->is_flags & ILF_OACTIVE) == 0)
-               ilstart(ifp->if_unit);
+       if ((is->is_if.if_flags & IFF_OACTIVE) == 0)
+               (void) ilstart(ifp);
        splx(s);
        ifp->if_timer = is->is_scaninterval;
 }
        splx(s);
        ifp->if_timer = is->is_scaninterval;
 }
@@ -641,6 +598,13 @@ iltotal(is)
        while (sum < end)
                *sum++ += *interval++;
        is->is_if.if_collisions = is->is_sum.ils_collis;
        while (sum < end)
                *sum++ += *interval++;
        is->is_if.if_collisions = is->is_sum.ils_collis;
+       if ((is->is_flags & ILF_SETADDR) &&
+           (bcmp((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr,
+                                       sizeof (is->is_addr)) != 0)) {
+               log(LOG_ERR, "il%d: physaddr reverted\n", is->is_if.if_unit);
+               is->is_flags &= ~ILF_RUNNING;
+               ilinit(is->is_if.if_unit);
+       }
 }
 
 /*
 }
 
 /*
@@ -652,6 +616,7 @@ ilioctl(ifp, cmd, data)
        caddr_t data;
 {
        register struct ifaddr *ifa = (struct ifaddr *)data;
        caddr_t data;
 {
        register struct ifaddr *ifa = (struct ifaddr *)data;
+       register struct il_softc *is = &il_softc[ifp->if_unit];
        int s = splimp(), error = 0;
 
        switch (cmd) {
        int s = splimp(), error = 0;
 
        switch (cmd) {
@@ -660,7 +625,7 @@ ilioctl(ifp, cmd, data)
                ifp->if_flags |= IFF_UP;
                ilinit(ifp->if_unit);
 
                ifp->if_flags |= IFF_UP;
                ilinit(ifp->if_unit);
 
-               switch (ifa->ifa_addr.sa_family) {
+               switch (ifa->ifa_addr->sa_family) {
 #ifdef INET
                case AF_INET:
                        ((struct arpcom *)ifp)->ac_ipaddr =
 #ifdef INET
                case AF_INET:
                        ((struct arpcom *)ifp)->ac_ipaddr =
@@ -670,17 +635,55 @@ ilioctl(ifp, cmd, data)
 #endif
 #ifdef NS
                case AF_NS:
 #endif
 #ifdef NS
                case AF_NS:
-                       IA_SNS(ifa)->sns_addr.x_host =
-                               * (union ns_host *) 
+                   {
+                       register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+                       
+                       if (ns_nullhost(*ina)) {
+                               ina->x_host = * (union ns_host *) 
                                     (il_softc[ifp->if_unit].is_addr);
                                     (il_softc[ifp->if_unit].is_addr);
+                       } else {
+                               il_setaddr(ina->x_host.c_host, ifp->if_unit);
+                               return (0);
+                       }
                        break;
                        break;
+                   }
 #endif
                }
                break;
 
 #endif
                }
                break;
 
+       case SIOCSIFFLAGS:
+               if ((ifp->if_flags & IFF_UP) == 0 &&
+                   is->is_flags & ILF_RUNNING) {
+                       ((struct ildevice *)
+                          (ilinfo[ifp->if_unit]->ui_addr))->il_csr = ILC_RESET;
+                       is->is_flags &= ~ILF_RUNNING;
+               } else if (ifp->if_flags & IFF_UP &&
+                   (is->is_flags & ILF_RUNNING) == 0)
+                       ilinit(ifp->if_unit);
+               break;
+
        default:
                error = EINVAL;
        }
        splx(s);
        return (error);
 }
        default:
                error = EINVAL;
        }
        splx(s);
        return (error);
 }
+
+/*
+ * set ethernet address for unit
+ */
+il_setaddr(physaddr, unit)
+u_char *physaddr;
+int unit;
+{
+       register struct il_softc *is = &il_softc[unit];
+       
+       if (! (is->is_flags & ILF_RUNNING))
+               return;
+               
+       bcopy((caddr_t)physaddr, (caddr_t)is->is_addr, sizeof is->is_addr);
+       is->is_flags &= ~ILF_RUNNING;
+       is->is_flags |= ILF_SETADDR;
+       ilinit(unit);
+}
+#endif