BSD 4_3_Net_2 release
[unix-history] / usr / src / sys / vax / if / if_il.c
index e94213f..13b5d34 100644 (file)
@@ -1,38 +1,81 @@
-/*     if_il.c 4.20    83/05/27        */
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * 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 "../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 <errno.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/if_ether.h"
-#include "../netpup/pup.h"
-
-#include "../vax/cpu.h"
-#include "../vax/mtpr.h"
-#include "../vaxif/if_il.h"
-#include "../vaxif/if_ilreg.h"
-#include "../vaxif/if_uba.h"
-#include "../vaxuba/ubareg.h"
-#include "../vaxuba/ubavar.h"
+#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 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
+#include "netns/ns.h"
+#include "netns/ns_if.h"
+#endif
+
+#include "../include/cpu.h"
+#include "../include/mtpr.h"
+#include "if_il.h"
+#include "if_ilreg.h"
+#include "if_uba.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];
@@ -40,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(),ilreset(),ilwatch();
+int    ilinit(),iloutput(),ilioctl(),ilreset(),ilwatch(),ilstart();
+int    ildebug = 0;
 
 /*
  * Ethernet software status per interface.
 
 /*
  * Ethernet software status per interface.
@@ -54,19 +98,29 @@ int ilinit(),iloutput(),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];
@@ -103,60 +157,58 @@ ilattach(ui)
        register struct il_softc *is = &il_softc[ui->ui_unit];
        register struct ifnet *ifp = &is->is_if;
        register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
        register struct il_softc *is = &il_softc[ui->ui_unit];
        register struct ifnet *ifp = &is->is_if;
        register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
-       struct sockaddr_in *sin;
 
        ifp->if_unit = ui->ui_unit;
        ifp->if_name = "il";
        ifp->if_mtu = ETHERMTU;
 
        ifp->if_unit = ui->ui_unit;
        ifp->if_name = "il";
        ifp->if_mtu = ETHERMTU;
+       ifp->if_flags = IFF_BROADCAST;
 
        /*
         * Reset the board and map the statistics
         * buffer onto the Unibus.
         */
        addr->il_csr = ILC_RESET;
 
        /*
         * Reset the board and map the statistics
         * 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,
        
        is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats,
-               sizeof (struct il_stats), 0);
+           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;
        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
-       bcopy((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr,
-           sizeof (is->is_addr));
-       sin = (struct sockaddr_in *)&ifp->if_addr;
-       sin->sin_family = AF_INET;
-       sin->sin_addr = arpmyaddr((struct arpcom *)0);
+       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));
+       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_reset = ilreset;
-       ifp->if_watchdog = ilwatch;
-       is->is_scaninterval = ILWATCHINTERVAL;
-       ifp->if_timer = is->is_scaninterval;
+       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.
@@ -170,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);
 }
 
@@ -183,28 +237,28 @@ 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;
-       int s;
        register struct ifnet *ifp = &is->is_if;
        register struct ifnet *ifp = &is->is_if;
-       register struct sockaddr_in *sin, *sinb;
+       int s;
 
 
-       sin = (struct sockaddr_in *)&ifp->if_addr;
-       if (sin->sin_addr.s_addr == 0)  /* if address still unknown */
+       /* not yet, if address still unknown */
+       if (ifp->if_addrlist == (struct ifaddr *)0)
                return;
                return;
-       ifp->if_net = in_netof(sin->sin_addr);
-       ifp->if_host[0] = in_lnaof(sin->sin_addr);
-       sinb = (struct sockaddr_in *)&ifp->if_broadaddr;
-       sinb->sin_family = AF_INET;
-       sinb->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
-       ifp->if_flags = IFF_BROADCAST;
-
-       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;
        addr = (struct ildevice *)ui->ui_addr;
 
        /*
        addr = (struct ildevice *)ui->ui_addr;
 
        /*
@@ -214,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;
@@ -233,17 +361,14 @@ ilinit(unit)
        addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
        addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
        addr->il_csr =
        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;
+           ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
        while ((addr->il_csr & IL_CDONE) == 0)
                ;
        while ((addr->il_csr & IL_CDONE) == 0)
                ;
-       is->is_flags = ILF_OACTIVE;
-       is->is_if.if_flags |= IFF_UP;
+       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);
-       if_rtinit(&is->is_if, RTF_UP);
-       arpattach(&is->is_ac);
-       arpwhohas(&is->is_ac, &sin->sin_addr);
 }
 
 /*
 }
 
 /*
@@ -251,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;
@@ -265,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;
@@ -292,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);
 }
 
 /*
 }
 
 /*
@@ -306,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;
@@ -318,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) {
 
@@ -345,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);
 }
 
 /*
 }
 
 /*
@@ -364,7 +494,7 @@ 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;
 
        is->is_if.if_ipackets++;
        register struct ifqueue *inq;
 
        is->is_if.if_ipackets++;
@@ -383,15 +513,15 @@ ilrint(unit)
        }
 
        /*
        }
 
        /*
-        * 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.
         */
        il->ilr_type = ntohs((u_short)il->ilr_type);
 #define        ildataaddr(il, off, type)       ((type)(((caddr_t)((il)+1)+(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))))
-       if (il->ilr_type >= ETHERPUP_TRAIL &&
-           il->ilr_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) {
-               off = (il->ilr_type - ETHERPUP_TRAIL) * 512;
+       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 */
                il->ilr_type = ntohs(*ildataaddr(il, off, u_short *));
                if (off >= ETHERMTU)
                        goto setup;             /* sanity */
                il->ilr_type = ntohs(*ildataaddr(il, off, u_short *));
@@ -410,44 +540,16 @@ ilrint(unit)
         * information to be at the front, but we still have to drop
         * the type and length which are at the front of any trailer data.
         */
         * information to be at the front, but we still have to drop
         * the type and length which are at the front of any trailer data.
         */
-       m = if_rubaget(&is->is_ifuba, len, off);
-       if (m == 0)
-               goto setup;
-       if (off) {
-               m->m_off += 2 * sizeof (u_short);
-               m->m_len -= 2 * sizeof (u_short);
-       }
-       switch (il->ilr_type) {
-
-#ifdef INET
-       case ETHERPUP_IPTYPE:
-               schednetisr(NETISR_IP);
-               inq = &ipintrq;
-               break;
-
-       case ETHERPUP_ARPTYPE:
-               arpinput(&is->is_ac, m);
-               return;
-#endif
-       default:
-               m_freem(m);
-               goto setup;
-       }
-
-       if (IF_QFULL(inq)) {
-               IF_DROP(inq);
-               m_freem(m);
-               goto setup;
-       }
-       IF_ENQUEUE(inq, m);
-
+       m = if_rubaget(&is->is_ifuba, len, off, &is->is_if);
+       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;
        }
@@ -455,122 +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;
-               if (off > 0 && (off & 0x1ff) == 0 &&
-                   m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
-                       type = ETHERPUP_TRAIL + (off>>9);
-                       m->m_off -= 2 * sizeof (u_short);
-                       m->m_len += 2 * sizeof (u_short);
-                       *mtod(m, u_short *) = htons((u_short)ETHERPUP_IPTYPE);
-                       *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
-                       goto gottrailertype;
-               }
-               type = ETHERPUP_IPTYPE;
-               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, 6);
-
-       /*
-        * 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.
  */
@@ -587,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;
 }
@@ -607,4 +598,92 @@ 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);
+       }
 }
 }
+
+/*
+ * Process an ioctl request.
+ */
+ilioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       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) {
+
+       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:
+                   {
+                       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);
+                       } else {
+                               il_setaddr(ina->x_host.c_host, ifp->if_unit);
+                               return (0);
+                       }
+                       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);
+}
+
+/*
+ * 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