create netif directory
[unix-history] / usr / src / sys / vax / if / if_en.c
index ea478e0..6299fcb 100644 (file)
-/* if_en.c 4.8 81/11/15 */
+/*     if_en.c 4.71    82/10/24        */
 
 #include "en.h"
 
 #include "en.h"
+
 /*
 /*
- * Ethernet interface driver
+ * Xerox prototype (3 Mb) Ethernet interface driver.
  */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 #include "../h/mbuf.h"
  */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 #include "../h/mbuf.h"
-#include "../net/inet.h"
-#include "../net/inet_pcb.h"
-#include "../net/inet_systm.h"
-#include "../net/imp.h"
-#include "../net/ip.h"
-#include "../net/ip_var.h"
-#include "../net/tcp.h"                        /* XXX */
-#include "../net/tcp_var.h"
-#include "../h/map.h"
 #include "../h/pte.h"
 #include "../h/buf.h"
 #include "../h/pte.h"
 #include "../h/buf.h"
-#include "../h/ubareg.h"
-#include "../h/ubavar.h"
-#include "../h/conf.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/proc.h"
-#include "../h/enreg.h"
-#include "../h/mtpr.h"
-#include "../h/cpu.h"
-#include "../h/cmap.h"
-
-int    enrswaps, enwswaps;
+#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 "../netpup/pup.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "../vaxif/if_en.h"
+#include "../vaxif/if_enreg.h"
+#include "../vaxif/if_uba.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+#define        ENMTU   (1024+512)
+#define        ENMRU   (1024+512+16)           /* 16 is enough to receive trailer */
+
 int    enprobe(), enattach(), enrint(), enxint(), encollide();
 struct uba_device *eninfo[NEN];
 u_short enstd[] = { 0 };
 struct uba_driver endriver =
        { enprobe, 0, enattach, 0, enstd, "en", eninfo };
 int    enprobe(), enattach(), enrint(), enxint(), encollide();
 struct uba_device *eninfo[NEN];
 u_short enstd[] = { 0 };
 struct uba_driver endriver =
        { enprobe, 0, enattach, 0, enstd, "en", eninfo };
-
 #define        ENUNIT(x)       minor(x)
 
 #define        ENUNIT(x)       minor(x)
 
-struct en_packet *xpkt, *rpkt;
-struct en_prefix {
-       struct en_header enp_h;
-       struct tcpiphdr enp_th;
-};
-struct uba_regs *enuba;
-struct pte *enrmr, *enxmr;
-int    enrbdp, enwbdp;
-int    enrproto, enwproto;
-struct pte enxmap[2];
-int    enxswapd;
+int    eninit(),enoutput(),enreset();
+
+/*
+ * Ethernet software status per interface.
+ *
+ * Each interface is referenced by a network interface structure,
+ * es_if, which the routing code uses to locate the interface.
+ * This structure contains the output queue for the interface, its address, ...
+ * We also have, for each interface, a UBA interface structure, which
+ * contains information about the UNIBUS resources held by the interface:
+ * map registers, buffered data paths, etc.  Information is cached in this
+ * structure for use by the if_uba.c routines in running the interface
+ * efficiently.
+ */
+struct en_softc {
+       struct  ifnet es_if;            /* network-visible interface */
+       struct  ifuba es_ifuba;         /* UNIBUS resources */
+       short   es_delay;               /* current output delay */
+       short   es_mask;                /* mask for current output delay */
+       short   es_lastx;               /* host last transmitted to */
+       short   es_oactive;             /* is output active? */
+       short   es_olen;                /* length of last output */
+} en_softc[NEN];
 
 
+/*
+ * Do output DMA to determine interface presence and
+ * interrupt vector.  DMA is too short to disturb other hosts.
+ */
 enprobe(reg)
        caddr_t reg;
 {
 enprobe(reg)
        caddr_t reg;
 {
-       register int br, cvec;
+       register int br, cvec;          /* r11, r10 value-result */
        register struct endevice *addr = (struct endevice *)reg;
 
 #ifdef lint
        br = 0; cvec = br; br = cvec;
        register struct endevice *addr = (struct endevice *)reg;
 
 #ifdef lint
        br = 0; cvec = br; br = cvec;
+       enrint(0); enxint(0); encollide(0);
 #endif
 #endif
-
        addr->en_istat = 0;
        addr->en_istat = 0;
-       addr->en_ostat = 0;
        addr->en_owc = -1;
        addr->en_oba = 0;
        addr->en_ostat = EN_IEN|EN_GO;
        DELAY(100000);
        addr->en_ostat = 0;
        addr->en_owc = -1;
        addr->en_oba = 0;
        addr->en_ostat = EN_IEN|EN_GO;
        DELAY(100000);
        addr->en_ostat = 0;
-       printf("ethernet address %d\n", ~addr->en_addr&0xff);
+#ifdef ECHACK
+       br = 0x16;
+#endif
        return (1);
 }
 
        return (1);
 }
 
+/*
+ * Interface exists: make available by filling in network interface
+ * record.  System will initialize the interface when it is ready
+ * to accept packets.
+ */
 enattach(ui)
        struct uba_device *ui;
 {
 enattach(ui)
        struct uba_device *ui;
 {
+       register struct en_softc *es = &en_softc[ui->ui_unit];
+       register struct sockaddr_in *sin;
 
 
+       es->es_if.if_unit = ui->ui_unit;
+       es->es_if.if_name = "en";
+       es->es_if.if_mtu = ENMTU;
+       es->es_if.if_net = ui->ui_flags;
+       es->es_if.if_host[0] =
+        (~(((struct endevice *)eninfo[ui->ui_unit]->ui_addr)->en_addr)) & 0xff;
+       sin = (struct sockaddr_in *)&es->es_if.if_addr;
+       sin->sin_family = AF_INET;
+       sin->sin_addr = if_makeaddr(es->es_if.if_net, es->es_if.if_host[0]);
+       sin = (struct sockaddr_in *)&es->es_if.if_broadaddr;
+       sin->sin_family = AF_INET;
+       sin->sin_addr = if_makeaddr(es->es_if.if_net, 0);
+       es->es_if.if_flags = IFF_BROADCAST;
+       es->es_if.if_init = eninit;
+       es->es_if.if_output = enoutput;
+       es->es_if.if_ubareset = enreset;
+       es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT;
+       if_attach(&es->es_if);
 }
 
 }
 
-eninit(unit)
-       int unit;
-{      
-       register struct endevice *addr;
+/*
+ * Reset of interface after UNIBUS reset.
+ * If interface is on specified uba, reset its state.
+ */
+enreset(unit, uban)
+       int unit, uban;
+{
        register struct uba_device *ui;
        register struct uba_device *ui;
-       int uban, x;
-       static reenter;
 
 
-       if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0) {
-               printf("en%d: not alive\n", unit);
+       if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 ||
+           ui->ui_ubanum != uban)
                return;
                return;
-       }
-       x = splimp();
-       if (reenter == 0) {
-               int n, j, i, k; char *cp;
-               reenter = 1;
-               n = 10;
-               k = n<<1;
-               i = rmalloc(mbmap, n*2);
-               if (i == 0)
-                       panic("eninit");
-               j = i << 1;
-               cp = (char *)pftom(i);
-               if (memall(&Mbmap[j], k, proc, CSYS) == 0)
-                       return (0);
-               vmaccess(&Mbmap[j], (caddr_t)cp, k);
-               rpkt = (struct en_packet *)
-                   (cp + 1024 - sizeof (struct en_prefix));
-               xpkt = (struct en_packet *)
-                   (cp + 5 * 1024 + 1024 - sizeof (struct en_prefix));
-               for (j = 0; j < n; j++)
-                       mprefcnt[i+j] = 1;
-       }
-       uban = ui->ui_ubanum;
-       addr = (struct endevice *)ui->ui_addr;
-       addr->en_istat = 0;
-       addr->en_ostat = 0;
-       imp_stat.iaddr =
-           uballoc(uban, (caddr_t)rpkt, 1024+512, UBA_NEED16|UBA_NEEDBDP);
-       imp_stat.oaddr =
-           uballoc(uban, (caddr_t)xpkt, 1024+512, UBA_NEED16|UBA_NEEDBDP);
-       enuba = ui->ui_hd->uh_uba;
-       enrbdp = (imp_stat.iaddr >> 28) & 0xf;
-       enwbdp = (imp_stat.oaddr >> 28) & 0xf;
-       enrproto = UBAMR_MRV | (enrbdp << 21);
-       enwproto = UBAMR_MRV | (enwbdp << 21);
-       enrmr = &enuba->uba_map[((imp_stat.iaddr>>9)&0x1ff) + 1];
-       enxmr = &enuba->uba_map[((imp_stat.oaddr>>9)&0x1ff) + 1];
-       enxmap[0] = enxmr[0];
-       enxmap[1] = enxmr[1];
-       enxswapd = 0;
-       printf("enrbdp %x enrproto %x enrmr %x imp_stat.iaddr %x\n",
-           enrbdp, enrproto, enrmr, imp_stat.iaddr);
-       imp_stat.impopen = 1;
-       imp_stat.flush = 0;
-       splx(x);
-#ifdef IMPDEBUG
-       printf("eninit(%d): iaddr = %x, oaddr = %x\n",
-               unit, imp_stat.iaddr, imp_stat.oaddr);
-#endif
+       printf(" en%d", unit);
+       eninit(unit);
 }
 
 }
 
-enreset(uban)
-       int uban;
+/*
+ * Initialization of interface; clear recorded pending
+ * operations, and reinitialize UNIBUS usage.
+ */
+eninit(unit)
+       int unit;
 {
 {
-       register int unit;
-       struct uba_device *ui;
+       register struct en_softc *es = &en_softc[unit];
+       register struct uba_device *ui = eninfo[unit];
+       register struct endevice *addr;
+       int s;
 
 
-       for (unit = 0; unit < NEN; unit++) {
-               ui = eninfo[unit];
-               if (ui == 0 || ui->ui_ubanum != uban || ui->ui_alive == 0)
-                       continue;
-               if (imp_stat.iaddr)
-                       ubarelse(uban, imp_stat.iaddr);
-               if (imp_stat.oaddr)
-                       ubarelse(uban, imp_stat.oaddr);
-               eninit(unit);
-               printf("en%d ", unit);
+       if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
+           sizeof (struct en_header), (int)btoc(ENMRU)) == 0) { 
+               printf("en%d: can't initialize\n", unit);
+               es->es_if.if_flags &= ~IFF_UP;
+               return;
        }
        }
+       addr = (struct endevice *)ui->ui_addr;
+       addr->en_istat = addr->en_ostat = 0;
+
+       /*
+        * Hang a receive and start any
+        * pending writes by faking a transmit complete.
+        */
+       s = splimp();
+       addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
+       addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
+       addr->en_istat = EN_IEN|EN_GO;
+       es->es_oactive = 1;
+       es->es_if.if_flags |= IFF_UP;
+       enxint(unit);
+       splx(s);
+       if_rtinit(&es->es_if, RTF_UP);
 }
 
 }
 
-int    enlastdel = 25;
-int    enlastx = 0;
+int    enalldelay = 0;
+int    enlastdel = 50;
+int    enlastmask = (~0) << 5;
+
+/*
+ * Start or restart output on interface.
+ * If interface is already active, then this is a retransmit
+ * after a collision, and just restuff registers and delay.
+ * If interface is not already active, get another datagram
+ * to send off of the interface queue, and map it to the interface
+ * before starting the output.
+ */
 enstart(dev)
        dev_t dev;
 {
 enstart(dev)
        dev_t dev;
 {
-       register struct mbuf *m, *mp;
+        int unit = ENUNIT(dev);
+       struct uba_device *ui = eninfo[unit];
+       register struct en_softc *es = &en_softc[unit];
        register struct endevice *addr;
        register struct endevice *addr;
-       register caddr_t cp, top;
-        int unit;
-        register int len;
-       u_short uaddr;
-       struct uba_device *ui;
-       int enxswapnow = 0;
-COUNT(ENSTART);
+       struct mbuf *m;
+       int dest;
 
 
-       unit = ENUNIT(dev);
-       ui = eninfo[unit];
-       if (ui == 0 || ui->ui_alive == 0) {
-               printf("en%d (imp_output): not alive\n", unit);
-               return;
-       }
-       addr = (struct endevice *)ui->ui_addr;
-       if (!imp_stat.outactive) {
-               if ((m = imp_stat.outq_head) == NULL)
-                       return;
-               imp_stat.outactive = 1;      /* set myself active */
-               imp_stat.outq_head = m->m_act;  /* -> next packet chain */
-               /*
-                * Pack mbufs into ethernet packet.
-                */
-               cp = (caddr_t)xpkt;
-               top = (caddr_t)xpkt + sizeof(struct en_packet);
-               while (m != NULL) {
-                       char *dp;
-                       if (cp + m->m_len > top) {
-                               printf("imp_snd: my packet runneth over\n");
-                               m_freem(m);
-                               return;
-                       }
-                       dp = mtod(m, char *);
-                       if (((int)cp&0x3ff)==0 && ((int)dp&0x3ff)==0) {
-                               struct pte *pte = &Mbmap[mtopf(dp)*2];
-                               *(int *)enxmr = enwproto | pte++->pg_pfnum;
-                               *(int *)(enxmr+1) = enwproto | pte->pg_pfnum;
-                               enxswapd = enxswapnow = 1;
-                       } else
-                               bcopy((int)m + m->m_off, cp, m->m_len);
-                       cp += m->m_len;
-                       /* too soon! */
-                       MFREE(m, mp);
-                       m = mp;
-               }
-               if (enxswapnow == 0 && enxswapd) {
-                       enxmr[0] = enxmap[0];
-                       enxmr[1] = enxmap[1];
-               }
-               if (enlastx && enlastx == xpkt->Header.en_dhost)
-                       imp_stat.endelay = enlastdel;
-               else
-                       enlastx = xpkt->Header.en_dhost;
-       }
-       len = ntohs(((struct ip *)((int)xpkt + L1822))->ip_len) + L1822;
-       if (len > sizeof(struct en_packet)) {
-               printf("imp_output: ridiculous IP length %d\n", len);
+       if (es->es_oactive)
+               goto restart;
+
+       /*
+        * Not already active: dequeue another request
+        * and map it to the UNIBUS.  If no more requests,
+        * just return.
+        */
+       IF_DEQUEUE(&es->es_if.if_snd, m);
+       if (m == 0) {
+               es->es_oactive = 0;
                return;
        }
                return;
        }
-#if defined(VAX780) || defined(VAX750)
-       switch (cpu) {
-#if defined(VAX780)
-       case VAX_780:
-               UBA_PURGE780(enuba, enwbdp);
-               break;
-#endif
-#if defined(VAX750)
-       case VAX_750:
-               UBA_PURGE750(enuba, enwbdp);
-               break;
-#endif
+       dest = mtod(m, struct en_header *)->en_dhost;
+       es->es_olen = if_wubaput(&es->es_ifuba, m);
+
+       /*
+        * Ethernet cannot take back-to-back packets (no
+        * buffering in interface.  To help avoid overrunning
+        * receivers, enforce a small delay (about 1ms) in interface:
+        *      * between all packets when enalldelay
+        *      * whenever last packet was broadcast
+        *      * whenever this packet is to same host as last packet
+        */
+       if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) {
+               es->es_delay = enlastdel;
+               es->es_mask = enlastmask;
        }
        }
-#endif
-       addr->en_oba = imp_stat.oaddr;
-       addr->en_odelay = imp_stat.endelay;
-       addr->en_owc = -((len + 1) >> 1);
-#ifdef IMPDEBUG
-       printf("en%d: sending packet (%d bytes)\n", unit, len);
-       prt_byte(xpkt, len);
-#endif
+       es->es_lastx = dest;
+
+restart:
+       /*
+        * Have request mapped to UNIBUS for transmission.
+        * Purge any stale data from this BDP, and start the otput.
+        */
+       if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp);
+       addr = (struct endevice *)ui->ui_addr;
+       addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info;
+       addr->en_odelay = es->es_delay;
+       addr->en_owc = -((es->es_olen + 1) >> 1);
        addr->en_ostat = EN_IEN|EN_GO;
        addr->en_ostat = EN_IEN|EN_GO;
+       es->es_oactive = 1;
 }
 
 /*
 }
 
 /*
- * Setup for a read
+ * Ethernet interface transmitter interrupt.
+ * Start another output if more data to send.
  */
  */
-ensetup(dev)
-       dev_t dev;
+enxint(unit)
+       int unit;
 {
 {
-       register struct endevice *addr;
-       register struct uba_device *ui;
-        register unsigned ubaddr;
-       register int sps;
-COUNT(ENSETUP);
+       register struct uba_device *ui = eninfo[unit];
+       register struct en_softc *es = &en_softc[unit];
+       register struct endevice *addr = (struct endevice *)ui->ui_addr;
 
 
-       ui = eninfo[ENUNIT(dev)];
-       if (ui == 0 || ui->ui_alive == 0) {
-               printf("en%d (imp_read): not alive\n", ENUNIT(dev));
+       if (es->es_oactive == 0)
+               return;
+       if (es->es_mask && (addr->en_ostat&EN_OERROR)) {
+               es->es_if.if_oerrors++;
+               endocoll(unit);
                return;
        }
                return;
        }
-       addr = (struct endevice *)ui->ui_addr;
-       addr->en_iba = imp_stat.iaddr;
-       addr->en_iwc = -600;    /* a little extra to avoid hardware bugs */
-       addr->en_istat = EN_IEN|EN_GO;
+       es->es_if.if_opackets++;
+       es->es_oactive = 0;
+       es->es_delay = 0;
+       es->es_mask = ~0;
+       if (es->es_ifuba.ifu_xtofree) {
+               m_freem(es->es_ifuba.ifu_xtofree);
+               es->es_ifuba.ifu_xtofree = 0;
+       }
+       if (es->es_if.if_snd.ifq_head == 0) {
+               es->es_lastx = 256;             /* putatively illegal */
+               return;
+       }
+       enstart(unit);
 }
 
 /*
 }
 
 /*
- * Output interrupt handler.
+ * Collision on ethernet interface.  Do exponential
+ * backoff, and retransmit.  If have backed off all
+ * the way print warning diagnostic, and drop packet.
  */
  */
-enxint(unit)
+encollide(unit)
        int unit;
 {
        int unit;
 {
-       register struct endevice *addr;
-       register struct uba_device *ui;
-COUNT(ENXINT);
-
-       ui = eninfo[unit];
-       addr = (struct endevice *)ui->ui_addr;
+       struct en_softc *es = &en_softc[unit];
 
 
-#ifdef IMPDEBUG
-       printf("en%d: enxint ostat=%b\n", unit, addr->en_ostat, EN_BITS);
-#endif
-       if (!imp_stat.outactive) {
-               printf("en%d: phantom output intr ostat=%b\n",
-                       unit, addr->en_ostat, EN_BITS);
+       es->es_if.if_collisions++;
+       if (es->es_oactive == 0)
                return;
                return;
-       }
-       imp_stat.endelay = 0;
-       imp_stat.enmask = ~0;
-       if (addr->en_ostat&EN_OERROR)
-               printf("en%d: output error ostat=%b\n", unit,
-                       addr->en_ostat, EN_BITS);
-       imp_stat.outactive = 0;
-       if (imp_stat.outq_head)
-               enstart(unit);
-       else
-               enlastx = 0;
+       endocoll(unit);
 }
 
 }
 
-int collisions;
-encollide(unit)
+endocoll(unit)
        int unit;
 {
        int unit;
 {
-       register struct endevice *addr;
-       register struct uba_device *ui;
-COUNT(ENCOLLIDE);
-
-       collisions++;
-       ui = eninfo[unit];
-       addr = (struct endevice *)ui->ui_addr;
+       register struct en_softc *es = &en_softc[unit];
 
 
-#ifdef IMPDEBUG
-       printf("en%d: collision ostat=%b\n", unit, addr->en_ostat, EN_BITS);
-#endif
-       if (!imp_stat.outactive) {
-               printf("en%d: phantom collision intr ostat=%b\n",
-                       unit, addr->en_ostat, EN_BITS);
+       /*
+        * Es_mask is a 16 bit number with n low zero bits, with
+        * n the number of backoffs.  When es_mask is 0 we have
+        * backed off 16 times, and give up.
+        */
+       if (es->es_mask == 0) {
+               printf("en%d: send error\n", unit);
+               enxint(unit);
                return;
        }
                return;
        }
-       if (imp_stat.enmask == 0) {
-               printf("en%d: output error ostat=%b\n", unit,
-                       addr->en_ostat, EN_BITS);
-       } else {
-               imp_stat.enmask <<= 1;
-               imp_stat.endelay = mfpr(ICR) & ~imp_stat.enmask;
-       }
+       /*
+        * Another backoff.  Restart with delay based on n low bits
+        * of the interval timer.
+        */
+       es->es_mask <<= 1;
+       es->es_delay = mfpr(ICR) &~ es->es_mask;
        enstart(unit);
 }
 
        enstart(unit);
 }
 
+struct sockaddr_pup pupsrc = { AF_PUP };
+struct sockaddr_pup pupdst = { AF_PUP };
+struct sockproto pupproto = { PF_PUP };
+/*
+ * Ethernet interface receiver interrupt.
+ * If input error just drop packet.
+ * Otherwise purge input buffered data path and examine 
+ * packet to determine type.  If can't determine length
+ * from type, then have to drop packet.  Othewise decapsulate
+ * packet based on type and pass to type specific higher-level
+ * input routine.
+ */
 enrint(unit)
        int unit;
 {
 enrint(unit)
        int unit;
 {
-       register struct mbuf *m;
-       struct mbuf *mp;
-       register struct endevice *addr;
-       register struct uba_device *ui;
-       register int len;
-       register caddr_t cp;
-       struct mbuf *p, *top = 0;
-       struct ip *ip;
-       int j, hlen;
-COUNT(ENRINT);
-
-       ui = eninfo[unit];
-       addr = (struct endevice *)ui->ui_addr;
-#ifdef IMPDEBUG
-       printf("en%d: enrint istat=%b\n", unit, addr->en_istat, EN_BITS);
-#endif
-       if (imp_stat.flush)
-               goto flush;
+       register struct en_softc *es = &en_softc[unit];
+       struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr;
+       register struct en_header *en;
+       struct mbuf *m;
+       int len; short resid;
+       register struct ifqueue *inq;
+       int off;
+
+       es->es_if.if_ipackets++;
+
+       /*
+        * Purge BDP; drop if input error indicated.
+        */
+       if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp);
        if (addr->en_istat&EN_IERROR) {
        if (addr->en_istat&EN_IERROR) {
-#ifdef notdef
-               printf("en%d: input error istat=%b\n", unit,
-                       addr->en_istat, EN_BITS);
-#endif
-               goto flush;
+               es->es_if.if_ierrors++;
+               goto setup;
        }
        }
-#if defined(VAX780) || defined(VAX750)
-       switch (cpu) {
-#if defined(VAX780)
-       case VAX_780:
-               UBA_PURGE780(enuba, enrbdp);
-               break;
-#endif
-#if defined(VAX750)
-       case VAX_750:
-               UBA_PURGE750(enuba, enrbdp);
+
+       /*
+        * Calculate input data length.
+        * Get pointer to ethernet header (in input buffer).
+        * Deal with trailer protocol: if type is PUP trailer
+        * get true type from first 16-bit word past data.
+        * Remember that type was trailer by setting off.
+        */
+       resid = addr->en_iwc;
+       if (resid)
+               resid |= 0176000;
+       len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1;
+       len -= sizeof (struct en_header);
+       if (len > ENMRU)
+               goto setup;                     /* sanity */
+       en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr);
+#define        endataaddr(en, off, type)       ((type)(((caddr_t)((en)+1)+(off))))
+       if (en->en_type >= ENPUP_TRAIL &&
+           en->en_type < ENPUP_TRAIL+ENPUP_NTRAILER) {
+               off = (en->en_type - ENPUP_TRAIL) * 512;
+               if (off > ENMTU)
+                       goto setup;             /* sanity */
+               en->en_type = *endataaddr(en, off, u_short *);
+               resid = *(endataaddr(en, off+2, u_short *));
+               if (off + resid > len)
+                       goto setup;             /* sanity */
+               len = off + resid;
+       } else
+               off = 0;
+       if (len == 0)
+               goto setup;
+       /*
+        * Pull packet off interface.  Off is nonzero if packet
+        * has trailing header; if_rubaget will then force this header
+        * 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(&es->es_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 (en->en_type) {
+
+#ifdef INET
+       case ENPUP_IPTYPE:
+               schednetisr(NETISR_IP);
+               inq = &ipintrq;
                break;
 #endif
                break;
 #endif
+#ifdef PUP
+       case ENPUP_PUPTYPE: {
+               struct pup_header *pup = mtod(m, struct pup_header *);
+
+               pupproto.sp_protocol = pup->pup_type;
+               pupdst.spup_addr = pup->pup_dport;
+               pupsrc.spup_addr = pup->pup_sport;
+               raw_input(m, &pupproto, (struct sockaddr *)&pupsrc,
+                 (struct sockaddr *)&pupdst);
+               goto setup;
        }
 #endif
        }
 #endif
-       ip = (struct ip *)((int)rpkt + L1822);
-       len = ntohs(ip->ip_len) + L1822;
-       if (len > sizeof(struct en_packet) || len < sizeof (struct ip)) {
-               printf("enrint: bad ip length %d\n", len);
-               goto flush;
+       default:
+               m_freem(m);
+               goto setup;
        }
        }
-       hlen = L1822 + sizeof (struct ip);
-       switch (ip->ip_p) {
 
 
-       case IPPROTO_TCP:
-               hlen += ((struct tcpiphdr *)ip)->ti_off << 2;
-               break;
-       }
-       MGET(m, 0);
-       if (m == 0)
-               goto flush;
-       top = m;
-       m->m_off = MMINOFF;
-       m->m_len = hlen;
-       bcopy(rpkt, mtod(m, caddr_t), hlen);
-       len -= hlen;
-       cp = (caddr_t)rpkt + hlen;
-       mp = m;
-       while (len > 0) {
-               MGET(m, 0);
-               if (m == NULL)
-                       goto flush;
-               if (len >= PGSIZE) {
-                       MPGET(p, 1);
-                       if (p == 0)
-                               goto nopage;
-                       m->m_len = PGSIZE;
-                       m->m_off = (int)p - (int)m;
-                       if (((int)cp & 0x3ff) == 0) {
-                               struct pte *cpte = &Mbmap[mtopf(cp)*2];
-                               struct pte *ppte = &Mbmap[mtopf(p)*2];
-                               struct pte t;
-                               enrswaps++;
-                               t = *ppte; *ppte++ = *cpte; *cpte++ = t;
-                               t = *ppte; *ppte = *cpte; *cpte = t;
-                               mtpr(TBIS, (caddr_t)cp);
-                               mtpr(TBIS, (caddr_t)cp+512);
-                               mtpr(TBIS, (caddr_t)p);
-                               mtpr(TBIS, (caddr_t)p+512);
-                               *(int *)(enrmr+1) =
-                                   cpte[0].pg_pfnum | enrproto;
-                               *(int *)(enrmr) =
-                                   cpte[-1].pg_pfnum | enrproto;
-                               goto nocopy;
-                       }
-               } else {
-nopage:
-                       m->m_len = MIN(MLEN, len);
-                       m->m_off = MMINOFF;
-               }
-               bcopy(cp, (int)m + m->m_off, m->m_len);
-nocopy:
-               cp += m->m_len;
-               len -= m->m_len;
-               mp->m_next = m;
-               mp = m;
-       }
-       m = top;
-       if (imp_stat.inq_head != NULL)
-               imp_stat.inq_tail->m_act = m;
-       else
-               imp_stat.inq_head = m;
-       imp_stat.inq_tail = m;
-#ifdef IMPDEBUG
-       printf("en%d: received packet (%d bytes)\n", unit, len);
-       prt_byte(rpkt, len);
-#endif
-       setsoftnet();
-       goto setup;
-flush:
-       m_freem(top);
-#ifdef IMPDEBUG
-       printf("en%d: flushing packet %x\n", unit, top);
-#endif
+       if (IF_QFULL(inq)) {
+               IF_DROP(inq);
+               m_freem(m);
+       } else
+               IF_ENQUEUE(inq, m);
+
 setup:
 setup:
-       addr->en_iba = imp_stat.iaddr;
-       addr->en_iwc = -600;
+       /*
+        * Reset for next packet.
+        */
+       addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
+       addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
        addr->en_istat = EN_IEN|EN_GO;
 }
 
        addr->en_istat = EN_IEN|EN_GO;
 }
 
-#ifdef IMPDEBUG
-prt_byte(s, ct)
-       register char *s;
-       int ct;
+/*
+ * 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.
+ */
+enoutput(ifp, m0, dst)
+       struct ifnet *ifp;
+       struct mbuf *m0;
+       struct sockaddr *dst;
 {
 {
-       register i, j, c;
+       int type, dest, s, error;
+       register struct mbuf *m = m0;
+       register struct en_header *en;
+       register int off;
+
+       switch (dst->sa_family) {
+
+#ifdef INET
+       case AF_INET:
+               dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
+               if (dest & 0x00ffff00) {
+                       error = EPERM;          /* ??? */
+                       goto bad;
+               }
+               dest = (dest >> 24) & 0xff;
+               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 = ENPUP_TRAIL + (off>>9);
+                       m->m_off -= 2 * sizeof (u_short);
+                       m->m_len += 2 * sizeof (u_short);
+                       *mtod(m, u_short *) = ENPUP_IPTYPE;
+                       *(mtod(m, u_short *) + 1) = m->m_len;
+                       goto gottrailertype;
+               }
+               type = ENPUP_IPTYPE;
+               off = 0;
+               goto gottype;
+#endif
+#ifdef PUP
+       case AF_PUP:
+               dest = ((struct sockaddr_pup *)dst)->spup_addr.pp_host;
+               type = ENPUP_PUPTYPE;
+               off = 0;
+               goto gottype;
+#endif
+
+       default:
+               printf("en%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 en_header) > m->m_off) {
+               m = m_get(M_DONTWAIT);
+               if (m == 0) {
+                       error = ENOBUFS;
+                       goto bad;
+               }
+               m->m_next = m0;
+               m->m_off = MMINOFF;
+               m->m_len = sizeof (struct en_header);
+       } else {
+               m->m_off -= sizeof (struct en_header);
+               m->m_len += sizeof (struct en_header);
+       }
+       en = mtod(m, struct en_header *);
+       en->en_shost = ifp->if_host[0];
+       en->en_dhost = dest;
+       en->en_type = type;
 
 
-       for (i=0; i<ct; i++) {
-               c = *s++;
-               for (j=0; j<2 ; j++)
-                       putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf]);
-               putchar(' ');
+       /*
+        * 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);
+               error = ENOBUFS;
+               goto qfull;
        }
        }
-       putchar('\n');
+       IF_ENQUEUE(&ifp->if_snd, m);
+       if (en_softc[ifp->if_unit].es_oactive == 0)
+               enstart(ifp->if_unit);
+       splx(s);
+       return (0);
+qfull:
+       m0 = m;
+       splx(s);
+bad:
+       m_freem(m0);
+       return (error);
 }
 }
-#endif IMPDEBUG