Add copyright
[unix-history] / usr / src / sys / vax / if / if_en.c
index 1e0c8f7..89fe9bd 100644 (file)
@@ -1,34 +1,51 @@
-/*     if_en.c 4.39    82/03/13        */
+/*
+ * Copyright (c) 1982 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ *     @(#)if_en.c     6.8 (Berkeley) %G%
+ */
 
 #include "en.h"
 
 /*
  * Xerox prototype (3 Mb) Ethernet interface driver.
  */
 
 #include "en.h"
 
 /*
  * Xerox prototype (3 Mb) Ethernet interface driver.
  */
+#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 "errno.h"
+#include "ioctl.h"
 
 
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/mbuf.h"
-#include "../h/pte.h"
-#include "../h/buf.h"
-#include "../h/protosw.h"
-#include "../h/socket.h"
-#include "../h/ubareg.h"
-#include "../h/ubavar.h"
-#include "../h/enreg.h"
-#include "../h/cpu.h"
-#include "../h/mtpr.h"
-#include "../h/vmmac.h"
-#include "../net/in.h"
-#include "../net/in_systm.h"
 #include "../net/if.h"
 #include "../net/if.h"
-#include "../net/if_en.h"
-#include "../net/if_uba.h"
-#include "../net/ip.h"
-#include "../net/ip_var.h"
-#include "../net/pup.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/in_var.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+#ifdef PUP
+#include "../netpup/pup.h"
+#include "../netpup/ether.h"
+#endif
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "if_en.h"
+#include "if_enreg.h"
+#include "if_uba.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
 
 #define        ENMTU   (1024+512)
 
 #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];
 
 int    enprobe(), enattach(), enrint(), enxint(), encollide();
 struct uba_device *eninfo[NEN];
@@ -37,7 +54,15 @@ struct       uba_driver endriver =
        { enprobe, 0, enattach, 0, enstd, "en", eninfo };
 #define        ENUNIT(x)       minor(x)
 
        { enprobe, 0, enattach, 0, enstd, "en", eninfo };
 #define        ENUNIT(x)       minor(x)
 
-int    eninit(),enoutput(),enreset();
+int    eninit(),enoutput(),enreset(),enioctl();
+
+#ifdef notdef
+/*
+ * If you need to byte swap IP's in the system, define
+ * this and do a SIOCSIFFLAGS at boot time.
+ */
+#define        ENF_SWABIPS     0x1000
+#endif
 
 /*
  * Ethernet software status per interface.
 
 /*
  * Ethernet software status per interface.
@@ -54,9 +79,10 @@ int  eninit(),enoutput(),enreset();
 struct en_softc {
        struct  ifnet es_if;            /* network-visible interface */
        struct  ifuba es_ifuba;         /* UNIBUS resources */
 struct en_softc {
        struct  ifnet es_if;            /* network-visible interface */
        struct  ifuba es_ifuba;         /* UNIBUS resources */
+       short   es_host;                /* hardware host number */
        short   es_delay;               /* current output delay */
        short   es_mask;                /* mask for current output delay */
        short   es_delay;               /* current output delay */
        short   es_mask;                /* mask for current output delay */
-       u_char  es_lastx;               /* host last transmitted to */
+       short   es_lastx;               /* host last transmitted to */
        short   es_oactive;             /* is output active? */
        short   es_olen;                /* length of last output */
 } en_softc[NEN];
        short   es_oactive;             /* is output active? */
        short   es_olen;                /* length of last output */
 } en_softc[NEN];
@@ -71,7 +97,6 @@ enprobe(reg)
        register int br, cvec;          /* r11, r10 value-result */
        register struct endevice *addr = (struct endevice *)reg;
 
        register int br, cvec;          /* r11, r10 value-result */
        register struct endevice *addr = (struct endevice *)reg;
 
-COUNT(ENPROBE);
 #ifdef lint
        br = 0; cvec = br; br = cvec;
        enrint(0); enxint(0); encollide(0);
 #ifdef lint
        br = 0; cvec = br; br = cvec;
        enrint(0); enxint(0); encollide(0);
@@ -94,28 +119,21 @@ enattach(ui)
        struct uba_device *ui;
 {
        register struct en_softc *es = &en_softc[ui->ui_unit];
        struct uba_device *ui;
 {
        register struct en_softc *es = &en_softc[ui->ui_unit];
-COUNT(ENATTACH);
 
        es->es_if.if_unit = ui->ui_unit;
        es->es_if.if_name = "en";
        es->es_if.if_mtu = ENMTU;
 
        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;
-#ifdef ENKLUDGE
-       if (es->es_if.if_net == 10) {
-               es->es_if.if_host[0] <<= 16;
-               es->es_if.if_host[0] |= 0x4e;
-       }
-#endif
-       es->es_if.if_addr =
-           if_makeaddr(es->es_if.if_net, es->es_if.if_host[0]);
-       es->es_if.if_broadaddr =
-           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_init = eninit;
        es->es_if.if_output = enoutput;
-       es->es_if.if_ubareset = enreset;
-       es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16;
+       es->es_if.if_ioctl = enioctl;
+       es->es_if.if_reset = enreset;
+       es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT;
+#if defined(VAX750)
+       /* don't chew up 750 bdp's */
+       if (cpu == VAX_750 && ui->ui_unit > 0)
+               es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP;
+#endif
        if_attach(&es->es_if);
 }
 
        if_attach(&es->es_if);
 }
 
@@ -127,7 +145,6 @@ enreset(unit, uban)
        int unit, uban;
 {
        register struct uba_device *ui;
        int unit, uban;
 {
        register struct uba_device *ui;
-COUNT(ENRESET);
 
        if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 ||
            ui->ui_ubanum != uban)
 
        if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 ||
            ui->ui_ubanum != uban)
@@ -148,9 +165,12 @@ eninit(unit)
        register struct endevice *addr;
        int s;
 
        register struct endevice *addr;
        int s;
 
+       if (es->es_if.if_addrlist == (struct ifaddr *)0)
+               return;
        if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
        if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
-           sizeof (struct en_header), (int)btoc(ENMTU)) == 0) { 
+           sizeof (struct en_header), (int)btoc(ENMRU)) == 0) { 
                printf("en%d: can't initialize\n", unit);
                printf("en%d: can't initialize\n", unit);
+               es->es_if.if_flags &= ~IFF_UP;
                return;
        }
        addr = (struct endevice *)ui->ui_addr;
                return;
        }
        addr = (struct endevice *)ui->ui_addr;
@@ -162,14 +182,17 @@ eninit(unit)
         */
        s = splimp();
        addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
         */
        s = splimp();
        addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
-       addr->en_iwc = -(sizeof (struct en_header) + ENMTU) >> 1;
+       addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
        addr->en_istat = EN_IEN|EN_GO;
        es->es_oactive = 1;
        addr->en_istat = EN_IEN|EN_GO;
        es->es_oactive = 1;
+       es->es_if.if_flags |= IFF_RUNNING;
        enxint(unit);
        splx(s);
 }
 
        enxint(unit);
        splx(s);
 }
 
-int    enlastdel = 25;
+int    enalldelay = 0;
+int    enlastdel = 50;
+int    enlastmask = (~0) << 5;
 
 /*
  * Start or restart output on interface.
 
 /*
  * Start or restart output on interface.
@@ -186,9 +209,9 @@ enstart(dev)
        struct uba_device *ui = eninfo[unit];
        register struct en_softc *es = &en_softc[unit];
        register struct endevice *addr;
        struct uba_device *ui = eninfo[unit];
        register struct en_softc *es = &en_softc[unit];
        register struct endevice *addr;
+       register struct en_header *en;
        struct mbuf *m;
        int dest;
        struct mbuf *m;
        int dest;
-COUNT(ENSTART);
 
        if (es->es_oactive)
                goto restart;
 
        if (es->es_oactive)
                goto restart;
@@ -203,26 +226,48 @@ COUNT(ENSTART);
                es->es_oactive = 0;
                return;
        }
                es->es_oactive = 0;
                return;
        }
-       dest = mtod(m, struct en_header *)->en_dhost;
+       en = mtod(m, struct en_header *);
+       dest = en->en_dhost;
+       en->en_shost = es->es_host;
        es->es_olen = if_wubaput(&es->es_ifuba, m);
        es->es_olen = if_wubaput(&es->es_ifuba, m);
+#ifdef ENF_SWABIPS
+       /*
+        * The Xerox interface does word at a time DMA, so
+        * someone must do byte swapping of user data if high
+        * and low ender machines are to communicate.  It doesn't
+        * belong here, but certain people depend on it, so...
+        *
+        * Should swab everybody, but this is a kludge anyway.
+        */
+       if (es->es_if.if_flags & ENF_SWABIPS) {
+               en = (struct en_header *)es->es_ifuba.ifu_w.ifrw_addr;
+               if (en->en_type == ENTYPE_IP)
+                       enswab((caddr_t)(en + 1), (caddr_t)(en + 1),
+                           es->es_olen - sizeof (struct en_header) + 1);
+       }
+#endif
 
        /*
         * Ethernet cannot take back-to-back packets (no
 
        /*
         * Ethernet cannot take back-to-back packets (no
-        * buffering in interface.  To avoid overrunning
-        * receiver, enforce a small delay (about 1ms) in interface
-        * on successive packets sent to same host.
+        * 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 (es->es_lastx && es->es_lastx == dest)
+       if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) {
                es->es_delay = enlastdel;
                es->es_delay = enlastdel;
-       else
-               es->es_lastx = dest;
+               es->es_mask = enlastmask;
+       }
+       es->es_lastx = dest;
 
 restart:
        /*
         * Have request mapped to UNIBUS for transmission.
         * Purge any stale data from this BDP, and start the otput.
         */
 
 restart:
        /*
         * Have request mapped to UNIBUS for transmission.
         * Purge any stale data from this BDP, and start the otput.
         */
-       UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp);
+       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 = (struct endevice *)ui->ui_addr;
        addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info;
        addr->en_odelay = es->es_delay;
@@ -240,26 +285,25 @@ enxint(unit)
 {
        register struct uba_device *ui = eninfo[unit];
        register struct en_softc *es = &en_softc[unit];
 {
        register struct uba_device *ui = eninfo[unit];
        register struct en_softc *es = &en_softc[unit];
-       register struct endevice *addr;
-COUNT(ENXINT);
+       register struct endevice *addr = (struct endevice *)ui->ui_addr;
 
        if (es->es_oactive == 0)
                return;
 
        if (es->es_oactive == 0)
                return;
-       addr = (struct endevice *)ui->ui_addr;
+       if (es->es_mask && (addr->en_ostat&EN_OERROR)) {
+               es->es_if.if_oerrors++;
+               endocoll(unit);
+               return;
+       }
        es->es_if.if_opackets++;
        es->es_oactive = 0;
        es->es_delay = 0;
        es->es_mask = ~0;
        es->es_if.if_opackets++;
        es->es_oactive = 0;
        es->es_delay = 0;
        es->es_mask = ~0;
-       if (addr->en_ostat&EN_OERROR) {
-               es->es_if.if_oerrors++;
-               printf("en%d: output error\n", unit);
-       }
        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) {
        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 = 0;
+               es->es_lastx = 256;             /* putatively illegal */
                return;
        }
        enstart(unit);
                return;
        }
        enstart(unit);
@@ -268,17 +312,24 @@ COUNT(ENXINT);
 /*
  * Collision on ethernet interface.  Do exponential
  * backoff, and retransmit.  If have backed off all
 /*
  * Collision on ethernet interface.  Do exponential
  * backoff, and retransmit.  If have backed off all
- * the way printing warning diagnostic, and drop packet.
+ * the way print warning diagnostic, and drop packet.
  */
 encollide(unit)
        int unit;
 {
  */
 encollide(unit)
        int unit;
 {
-       register struct en_softc *es = &en_softc[unit];
-COUNT(ENCOLLIDE);
+       struct en_softc *es = &en_softc[unit];
 
        es->es_if.if_collisions++;
        if (es->es_oactive == 0)
                return;
 
        es->es_if.if_collisions++;
        if (es->es_oactive == 0)
                return;
+       endocoll(unit);
+}
+
+endocoll(unit)
+       int unit;
+{
+       register struct en_softc *es = &en_softc[unit];
+
        /*
         * 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
        /*
         * 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
@@ -298,10 +349,11 @@ COUNT(ENCOLLIDE);
        enstart(unit);
 }
 
        enstart(unit);
 }
 
-int    enprintierrors;
-struct sockaddr_pup pupsrc = { AF_PUP };
-struct sockaddr_pup pupdst = { AF_PUP };
-struct sockproto pupproto = { PF_PUP };
+#ifdef notdef
+struct sockproto enproto = { AF_ETHERLINK };
+struct sockaddr_en endst = { AF_ETHERLINK };
+struct sockaddr_en ensrc = { AF_ETHERLINK };
+#endif
 /*
  * Ethernet interface receiver interrupt.
  * If input error just drop packet.
 /*
  * Ethernet interface receiver interrupt.
  * If input error just drop packet.
@@ -318,109 +370,111 @@ enrint(unit)
        struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr;
        register struct en_header *en;
        struct mbuf *m;
        struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr;
        register struct en_header *en;
        struct mbuf *m;
-       int len;
+       int len; short resid;
        register struct ifqueue *inq;
        register struct ifqueue *inq;
-       int off;
-COUNT(ENRINT);
+       int off, s;
 
        es->es_if.if_ipackets++;
 
        /*
         * Purge BDP; drop if input error indicated.
         */
 
        es->es_if.if_ipackets++;
 
        /*
         * Purge BDP; drop if input error indicated.
         */
-       UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp);
+       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) {
                es->es_if.if_ierrors++;
        if (addr->en_istat&EN_IERROR) {
                es->es_if.if_ierrors++;
-               if (enprintierrors)
-               printf("en%d: input error\n", unit);
                goto setup;
        }
 
        /*
                goto setup;
        }
 
        /*
+        * 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.
         */
         * 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);
        en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr);
+       en->en_type = ntohs(en->en_type);
 #define        endataaddr(en, off, type)       ((type)(((caddr_t)((en)+1)+(off))))
 #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)
+       if (en->en_type >= ENTYPE_TRAIL &&
+           en->en_type < ENTYPE_TRAIL+ENTYPE_NTRAILER) {
+               off = (en->en_type - ENTYPE_TRAIL) * 512;
+               if (off > ENMTU)
                        goto setup;             /* sanity */
                        goto setup;             /* sanity */
-               en->en_type = *endataaddr(en, off, u_short *);
+               en->en_type = ntohs(*endataaddr(en, off, u_short *));
+               resid = ntohs(*(endataaddr(en, off+2, u_short *)));
+               if (off + resid > len)
+                       goto setup;             /* sanity */
+               len = off + resid;
        } else
                off = 0;
        } else
                off = 0;
-
-       /*
-        * Attempt to infer packet length from type;
-        * can't deal with packet if can't infer length.
-        */
-       switch (en->en_type) {
-
-#ifdef INET
-       case ENPUP_IPTYPE:
-               len = htons((u_short)endataaddr(en, off ? off+2 : 0, struct ip *)->ip_len);
-               if (off)
-                       len += 2;
-               break;
-#endif
-#ifdef PUP
-       case ENPUP_PUPTYPE:
-               len = endataaddr(en, off, struct pup_header *)->pup_length;
-               if (off)
-                       len -= 2;
-               break;
-#endif
-               
-       default:
-               printf("en%d: unknown pkt type 0x%x\n", unit, en->en_type);
-               goto setup;
-       }
        if (len == 0)
                goto setup;
        if (len == 0)
                goto setup;
-
+#ifdef ENF_SWABIPS
+       if (es->es_if.if_flags & ENF_SWABIPS && en->en_type == ENTYPE_IP)
+               enswab((caddr_t)(en + 1), (caddr_t)(en + 1), len);
+#endif
        /*
         * 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
        /*
         * 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 two-byte type which is at the front of any trailer data.
+        * 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 = if_rubaget(&es->es_ifuba, len, off);
        if (m == 0)
                goto setup;
        if (off) {
-               m->m_off += 2;
-               m->m_len -= 2;
+               m->m_off += 2 * sizeof (u_short);
+               m->m_len -= 2 * sizeof (u_short);
        }
        switch (en->en_type) {
 
 #ifdef INET
        }
        switch (en->en_type) {
 
 #ifdef INET
-       case ENPUP_IPTYPE:
-               setipintr();
+       case ENTYPE_IP:
+               schednetisr(NETISR_IP);
                inq = &ipintrq;
                break;
 #endif
                inq = &ipintrq;
                break;
 #endif
-       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 *)&pupdst,
-                (struct sockaddr *)&pupsrc);
+#ifdef PUP
+       case ENTYPE_PUP:
+               rpup_input(m);
+               goto setup;
+#endif
+       default:
+#ifdef notdef
+               enproto.sp_protocol = en->en_type;
+               endst.sen_host = en->en_dhost;
+               endst.sen_net = ensrc.sen_net = es->es_if.if_net;
+               ensrc.sen_host = en->en_shost;
+               raw_input(m, &enproto,
+                   (struct sockaddr *)&ensrc, (struct sockaddr *)&endst);
+#else
+               m_freem(m);
+#endif
                goto setup;
                goto setup;
-               }
        }
        }
-       IF_ENQUEUE(inq, m);
+
+       s = splimp();
+       if (IF_QFULL(inq)) {
+               IF_DROP(inq);
+               m_freem(m);
+       } else
+               IF_ENQUEUE(inq, m);
+       splx(s);
 
 setup:
        /*
         * Reset for next packet.
         */
        addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
 
 setup:
        /*
         * Reset for next packet.
         */
        addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
-       addr->en_iwc = -(sizeof (struct en_header) + ENMTU) >> 1;
+       addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
        addr->en_istat = EN_IEN|EN_GO;
 }
 
        addr->en_istat = EN_IEN|EN_GO;
 }
 
@@ -430,65 +484,67 @@ setup:
  * Use trailer local net encapsulation if enough data in first
  * packet leaves a multiple of 512 bytes of data in remainder.
  */
  * Use trailer local net encapsulation if enough data in first
  * packet leaves a multiple of 512 bytes of data in remainder.
  */
-enoutput(ifp, m0, pf)
+enoutput(ifp, m0, dst)
        struct ifnet *ifp;
        struct mbuf *m0;
        struct ifnet *ifp;
        struct mbuf *m0;
-       int pf;
+       struct sockaddr *dst;
 {
 {
-       int type, dest, s, off;
+       int type, dest, s, error;
        register struct mbuf *m = m0;
        register struct en_header *en;
        register struct mbuf *m = m0;
        register struct en_header *en;
+       register int off;
 
 
-COUNT(ENOUTPUT);
-       switch (pf) {
+       switch (dst->sa_family) {
 
 #ifdef INET
 
 #ifdef INET
-       case PF_INET: {
-               register struct ip *ip = mtod(m0, struct ip *);
-
-#ifndef ENKLUDGE
-               dest = ip->ip_dst.s_addr >> 24;
-#else
-               dest = (ip->ip_dst.s_addr >> 8) & 0xff;
-#endif
-               off = ntohs((u_short)ip->ip_len) - m->m_len;
-#ifndef ENKLUDGE
-               if (off > 0 && (off & 0x1ff) == 0 && m->m_off >= MMINOFF + 2) {
-                       type = ENPUP_TRAIL + (off>>9);
-                       m->m_off -= 2;
-                       m->m_len += 2;
-                       *mtod(m, u_short *) = ENPUP_IPTYPE;
+       case AF_INET:
+               {
+               struct in_addr in;
+
+               in = ((struct sockaddr_in *)dst)->sin_addr;
+               if (in_broadcast(in))
+                       dest = EN_BROADCAST;
+               else
+                       dest = in_lnaof(in);
+               }
+               if (dest >= 0x100) {
+                       error = EPERM;          /* ??? */
+                       goto bad;
+               }
+               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 = ENTYPE_TRAIL + (off>>9);
+                       m->m_off -= 2 * sizeof (u_short);
+                       m->m_len += 2 * sizeof (u_short);
+                       *mtod(m, u_short *) = htons((u_short)ENTYPE_IP);
+                       *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len);
                        goto gottrailertype;
                }
                        goto gottrailertype;
                }
-#endif
-               type = ENPUP_IPTYPE;
+               type = ENTYPE_IP;
                off = 0;
                goto gottype;
                off = 0;
                goto gottype;
-               }
 #endif
 #ifdef PUP
 #endif
 #ifdef PUP
-       case PF_PUP: {
-               register struct pup_header *pup = mtod(m, struct pup_header *);
-
-               dest = pup->pup_dhost;
-               off = pup->pup_length - m->m_len;
-               if (off > 0 && (off & 0x1ff) == 0 && m->m_off >= MMINOFF + 2) {
-                       type = ENPUP_TRAIL + (off>>9);
-                       m->m_off -= 2;
-                       m->m_len += 2;
-                       *mtod(m, u_short *) = ENPUP_PUPTYPE;
-                       goto gottrailertype;
-               }
-               type = ENPUP_PUPTYPE;
+       case AF_PUP:
+               dest = ((struct sockaddr_pup *)dst)->spup_host;
+               type = ENTYPE_PUP;
                off = 0;
                goto gottype;
                off = 0;
                goto gottype;
-               }
+#endif
+
+#ifdef notdef
+       case AF_ETHERLINK:
+               goto gotheader;
 #endif
 
        default:
 #endif
 
        default:
-               printf("en%d: can't encapsulate pf%d\n", ifp->if_unit, pf);
-               m_freem(m0);
-               return (0);
+               printf("en%d: can't handle af%d\n", ifp->if_unit,
+                       dst->sa_family);
+               error = EAFNOSUPPORT;
+               goto bad;
        }
 
 gottrailertype:
        }
 
 gottrailertype:
@@ -510,10 +566,10 @@ gottype:
         */
        if (m->m_off > MMAXOFF ||
            MMINOFF + sizeof (struct en_header) > m->m_off) {
         */
        if (m->m_off > MMAXOFF ||
            MMINOFF + sizeof (struct en_header) > m->m_off) {
-               m = m_get(M_DONTWAIT);
+               MGET(m, M_DONTWAIT, MT_HEADER);
                if (m == 0) {
                if (m == 0) {
-                       m_freem(m0);
-                       return (0);
+                       error = ENOBUFS;
+                       goto bad;
                }
                m->m_next = m0;
                m->m_off = MMINOFF;
                }
                m->m_next = m0;
                m->m_off = MMINOFF;
@@ -523,18 +579,99 @@ gottype:
                m->m_len += sizeof (struct en_header);
        }
        en = mtod(m, struct en_header *);
                m->m_len += sizeof (struct en_header);
        }
        en = mtod(m, struct en_header *);
-       en->en_shost = ifp->if_host[0];
+       /* add en_shost later */
        en->en_dhost = dest;
        en->en_dhost = dest;
-       en->en_type = type;
+       en->en_type = htons((u_short)type);
 
 
+gotheader:
        /*
         * Queue message on interface, and start output if interface
         * not yet active.
         */
        s = splimp();
        /*
         * 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;
+       }
        IF_ENQUEUE(&ifp->if_snd, m);
        if (en_softc[ifp->if_unit].es_oactive == 0)
                enstart(ifp->if_unit);
        splx(s);
        IF_ENQUEUE(&ifp->if_snd, m);
        if (en_softc[ifp->if_unit].es_oactive == 0)
                enstart(ifp->if_unit);
        splx(s);
-       return (1);
+       return (0);
+qfull:
+       m0 = m;
+       splx(s);
+bad:
+       m_freem(m0);
+       return (error);
 }
 }
+
+/*
+ * Process an ioctl request.
+ */
+enioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
+{
+       register struct en_softc *es = ((struct en_softc *)ifp);
+       struct ifaddr *ifa = (struct ifaddr *) data;
+       int s = splimp(), error = 0;
+       struct endevice *enaddr;
+
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               enaddr = (struct endevice *)eninfo[ifp->if_unit]->ui_addr;
+               es->es_host = (~enaddr->en_addr) & 0xff;
+               /*
+                * Attempt to check agreement of protocol address
+                * and board address.
+                */
+               switch (ifa->ifa_addr.sa_family) {
+               case AF_INET:
+                       if (in_lnaof(IA_SIN(ifa)->sin_addr) != es->es_host)
+                               return (EADDRNOTAVAIL);
+                       break;
+               }
+               ifp->if_flags |= IFF_UP;
+               if ((ifp->if_flags & IFF_RUNNING) == 0)
+                       eninit(ifp->if_unit);
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       splx(s);
+       return (error);
+}
+
+#ifdef ENF_SWABIPS
+/*
+ * Swab bytes
+ * Jeffrey Mogul, Stanford
+ */
+enswab(from, to, n)
+       register unsigned char *from, *to;
+       register int n;
+{
+       register unsigned long temp;
+
+       if ((n <= 0) || (n > 0xFFFF)) {
+               printf("enswab: bad len %d\n", n);
+               return;
+       }
+       
+       n >>= 1; n++;
+#define        STEP    {temp = *from++;*to++ = *from++;*to++ = temp;}
+       /* round to multiple of 8 */
+       while ((--n) & 07)
+               STEP;
+       n >>= 3;
+       while (--n >= 0) {
+               STEP; STEP; STEP; STEP;
+               STEP; STEP; STEP; STEP;
+       }
+}
+#endif