restore missing default
[unix-history] / usr / src / sys / vax / if / if_en.c
index dd48f0a..b9fe1c5 100644 (file)
@@ -1,6 +1,7 @@
-/*     if_en.c 4.18    81/12/09        */
+/*     if_en.c 4.51    82/04/04        */
 
 #include "en.h"
 
 #include "en.h"
+#include "imp.h"
 
 /*
  * Xerox prototype (3 Mb) Ethernet interface driver.
 
 /*
  * Xerox prototype (3 Mb) Ethernet interface driver.
@@ -26,6 +27,8 @@
 #include "../net/if_uba.h"
 #include "../net/ip.h"
 #include "../net/ip_var.h"
 #include "../net/if_uba.h"
 #include "../net/ip.h"
 #include "../net/ip_var.h"
+#include "../net/pup.h"
+#include "../net/route.h"
 
 #define        ENMTU   (1024+512)
 
 
 #define        ENMTU   (1024+512)
 
@@ -55,7 +58,7 @@ struct        en_softc {
        struct  ifuba es_ifuba;         /* UNIBUS resources */
        short   es_delay;               /* current output delay */
        short   es_mask;                /* mask for current output delay */
        struct  ifuba es_ifuba;         /* UNIBUS resources */
        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];
@@ -93,20 +96,31 @@ 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];
+       register struct sockaddr_in *sin;
 COUNT(ENATTACH);
 
        es->es_if.if_unit = ui->ui_unit;
        es->es_if.if_name = "en";
        es->es_if.if_mtu = ENMTU;
 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_net = ui->ui_flags;
+       es->es_if.if_net = ui->ui_flags & 0xff;
        es->es_if.if_host[0] =
        es->es_if.if_host[0] =
-           (~(((struct endevice *)eninfo[ui->ui_unit]->ui_addr)->en_addr)) & 0xff;
-       es->es_if.if_addr =
-           if_makeaddr(es->es_if.if_net, 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_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;
        if_attach(&es->es_if);
        if_attach(&es->es_if);
+#if NIMP == 0
+       /* here's one for you john baby.... */
+       enlhinit((ui->ui_flags &~ 0xff) | 0x0a);
+#endif
 }
 
 /*
 }
 
 /*
@@ -139,8 +153,9 @@ eninit(unit)
        int s;
 
        if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
        int s;
 
        if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
-           sizeof (struct en_header), (int)btop(ENMTU)) == 0) { 
+           sizeof (struct en_header), (int)btoc(ENMTU)) == 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;
@@ -155,11 +170,15 @@ eninit(unit)
        addr->en_iwc = -(sizeof (struct en_header) + ENMTU) >> 1;
        addr->en_istat = EN_IEN|EN_GO;
        es->es_oactive = 1;
        addr->en_iwc = -(sizeof (struct en_header) + ENMTU) >> 1;
        addr->en_istat = EN_IEN|EN_GO;
        es->es_oactive = 1;
+       es->es_if.if_flags |= IFF_UP;
        enxint(unit);
        splx(s);
        enxint(unit);
        splx(s);
+       if_rtinit(&es->es_if, RTF_DIRECT|RTF_UP);
 }
 
 }
 
+int    enalldelay = 0;
 int    enlastdel = 25;
 int    enlastdel = 25;
+int    enlastmask = (~0) << 5;
 
 /*
  * Start or restart output on interface.
 
 /*
  * Start or restart output on interface.
@@ -194,28 +213,29 @@ COUNT(ENSTART);
                return;
        }
        dest = mtod(m, struct en_header *)->en_dhost;
                return;
        }
        dest = mtod(m, struct en_header *)->en_dhost;
-printf("if_wubaput m=%x\n", m);
        es->es_olen = if_wubaput(&es->es_ifuba, m);
        es->es_olen = if_wubaput(&es->es_ifuba, m);
-printf("wubaput to %x len %d\n", es->es_ifuba.ifu_w.ifrw_addr, es->es_olen);
-asm("halt");
 
        /*
         * 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;
@@ -233,26 +253,28 @@ 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;
+       register struct endevice *addr = (struct endevice *)ui->ui_addr;
 COUNT(ENXINT);
 
 COUNT(ENXINT);
 
-printf("enxint\n");
        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++;
+               if (es->es_if.if_oerrors % 100 == 0)
+                       printf("en%d: += 100 output errors\n", unit);
+               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)
-               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_if.if_snd.ifq_head == 0) {
-               es->es_if.if_oerrors++;
-               if (es->es_ifuba.ifu_xtofree) {
-                       m_freem(es->es_ifuba.ifu_xtofree);
-                       es->es_ifuba.ifu_xtofree = 0;
-               }
-               es->es_lastx = 0;
+               es->es_lastx = 256;             /* putatively illegal */
                return;
        }
        enstart(unit);
                return;
        }
        enstart(unit);
@@ -261,18 +283,25 @@ printf("enxint\n");
 /*
  * 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];
+       struct en_softc *es = &en_softc[unit];
 COUNT(ENCOLLIDE);
 
 COUNT(ENCOLLIDE);
 
-printf("encollide\n");
        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
@@ -292,6 +321,9 @@ printf("encollide\n");
        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.
 /*
  * Ethernet interface receiver interrupt.
  * If input error just drop packet.
@@ -308,32 +340,40 @@ 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, plen; short resid;
        register struct ifqueue *inq;
        int off;
 COUNT(ENRINT);
 
        register struct ifqueue *inq;
        int off;
 COUNT(ENRINT);
 
-printf("enrint\n");
        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++;
-               printf("en%d: input error\n", unit);
+               if (es->es_if.if_ierrors % 100 == 0)
+                       printf("en%d: += 100 input errors\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) + ENMTU) >> 1) + resid) << 1;
+       len -= sizeof (struct en_header);
+       if (len >= ENMTU)
+               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);
-printf("en %x, en->en_type %d\n", en, en->en_type);
 #define        endataaddr(en, off, type)       ((type)(((caddr_t)((en)+1)+(off))))
        if (en->en_type >= ENPUP_TRAIL &&
            en->en_type < ENPUP_TRAIL+ENPUP_NTRAILER) {
 #define        endataaddr(en, off, type)       ((type)(((caddr_t)((en)+1)+(off))))
        if (en->en_type >= ENPUP_TRAIL &&
            en->en_type < ENPUP_TRAIL+ENPUP_NTRAILER) {
@@ -341,47 +381,57 @@ printf("en %x, en->en_type %d\n", en, en->en_type);
                if (off >= ENMTU)
                        goto setup;             /* sanity */
                en->en_type = *endataaddr(en, off, u_short *);
                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;
        } else
                off = 0;
-
-printf("off %d\n", off);
+       if (len == 0)
+               goto setup;
        /*
        /*
-        * Attempt to infer packet length from type;
-        * can't deal with packet if can't infer length.
+        * 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:
        switch (en->en_type) {
 
 #ifdef INET
        case ENPUP_IPTYPE:
-               len = htons(endataaddr(en, off+2, struct ip *)->ip_len)+2;
-               setipintr();
+               schednetisr(NETISR_IP);
                inq = &ipintrq;
                break;
 #endif
                inq = &ipintrq;
                break;
 #endif
-
-       default:
-               printf("en%d: unknow pkt type 0x%x\n", en->en_type);
+#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 *)&pupdst,
+                 (struct sockaddr *)&pupsrc);
                goto setup;
        }
                goto setup;
        }
-       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 two-byte type which is at the front of any trailer data.
-        */
-       m = if_rubaget(&es->es_ifuba, len, off);
-       if (m == 0)
+#endif
+       default:
+               m_freem(m);
                goto setup;
                goto setup;
-       printf("rubaget returns m %x\n", m);
-       asm("halt");
-       if (off) {
-               m->m_off += 2;
-               m->m_len -= 2;
        }
        }
-       IF_ENQUEUE(inq, m);
+
+       if (IF_QFULL(inq)) {
+               IF_DROP(inq);
+               m_freem(m);
+       } else
+               IF_ENQUEUE(inq, m);
 
 setup:
        /*
 
 setup:
        /*
@@ -398,41 +448,47 @@ 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;
+       int type, dest, s;
        register struct mbuf *m = m0;
        register struct en_header *en;
        register struct mbuf *m = m0;
        register struct en_header *en;
-       int s;
+       register int off;
 
 
-       switch (pf) {
+COUNT(ENOUTPUT);
+       switch (dst->sa_family) {
 
 #ifdef INET
 
 #ifdef INET
-       case PF_INET: {
-               register struct ip *ip = mtod(m0, struct ip *);
-               int off;
-
-               dest = ip->ip_dst.s_addr >> 24;
-               off = ntohs(ip->ip_len) - m->m_len;
-printf("PF_INET enoutput off %d m->m_off %d m->m_len %d\n", off, m->m_off, m->m_len);
-               if (off > 0 && (off & 0x1ff) == 0 && m->m_off >= MMINOFF + 2) {
+       case AF_INET:
+               dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr >> 24;
+               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);
                        type = ENPUP_TRAIL + (off>>9);
-                       m->m_off -= 2;
-                       m->m_len += 2;
+                       m->m_off -= 2 * sizeof (u_short);
+                       m->m_len += 2 * sizeof (u_short);
                        *mtod(m, u_short *) = ENPUP_IPTYPE;
                        *mtod(m, u_short *) = ENPUP_IPTYPE;
+                       *(mtod(m, u_short *) + 1) = m->m_len;
                        goto gottrailertype;
                }
                type = ENPUP_IPTYPE;
                off = 0;
                goto gottype;
                        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:
 #endif
 
        default:
-               printf("en%d: can't encapsulate pf%d\n", ifp->if_unit, pf);
+               printf("en%d: can't handle af%d\n", ifp->if_unit,
+                       dst->sa_family);
                m_freem(m0);
                return (0);
        }
                m_freem(m0);
                return (0);
        }
@@ -449,8 +505,6 @@ gottrailertype:
        m0->m_next = 0;
        m0 = m;
 
        m0->m_next = 0;
        m0 = m;
 
-printf("m %x after trailer futz\n", m);
-asm("halt");
 gottype:
        /*
         * Add local net header.  If no space in first mbuf,
 gottype:
        /*
         * Add local net header.  If no space in first mbuf,
@@ -458,7 +512,7 @@ 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(0);
+               m = m_get(M_DONTWAIT);
                if (m == 0) {
                        m_freem(m0);
                        return (0);
                if (m == 0) {
                        m_freem(m0);
                        return (0);
@@ -480,11 +534,63 @@ gottype:
         * not yet active.
         */
        s = splimp();
         * not yet active.
         */
        s = splimp();
-printf("queueing %x\n", m);
-asm("halt");
+       if (IF_QFULL(&ifp->if_snd)) {
+               IF_DROP(&ifp->if_snd);
+               m_freem(m);
+               splx(s);
+               return (0);
+       }
        IF_ENQUEUE(&ifp->if_snd, m);
        IF_ENQUEUE(&ifp->if_snd, m);
-       splx(s);
        if (en_softc[ifp->if_unit].es_oactive == 0)
                enstart(ifp->if_unit);
        if (en_softc[ifp->if_unit].es_oactive == 0)
                enstart(ifp->if_unit);
+       splx(s);
        return (1);
 }
        return (1);
 }
+
+#if NIMP == 0 && NEN > 0
+/*
+ * Logical host interface driver.
+ * Allows host to appear as an ARPAnet
+ * logical host.  Must also have routing
+ * table entry set up to forward packets
+ * to appropriate gateway on localnet.
+ */
+
+struct ifnet enlhif;
+int    enlhoutput();
+
+/*
+ * Called by localnet interface to allow logical
+ * host interface to "attach".  Nothing should ever
+ * be sent locally to this interface, it's purpose
+ * is simply to establish the host's arpanet address.
+ */
+enlhinit(addr)
+       int addr;
+{
+       register struct ifnet *ifp = &enlhif;
+       register struct sockaddr_in *sin;
+
+COUNT(ENLHINIT);
+       ifp->if_name = "lh";
+       ifp->if_mtu = ENMTU;
+       sin = (struct sockaddr_in *)&ifp->if_addr;
+       sin->sin_family = AF_INET;
+       sin->sin_addr.s_addr = addr;
+       ifp->if_net = sin->sin_addr.s_net;
+       ifp->if_flags = IFF_UP;
+       ifp->if_output = enlhoutput;    /* should never be used */
+       if_attach(ifp);
+}
+
+enlhoutput(ifp, m0, dst)
+       struct ifnet *ifp;
+       struct mbuf *m0;
+       struct sockaddr *dst;
+{
+COUNT(ENLHOUTPUT);
+       ifp->if_oerrors++;
+       m_freem(m0);
+       return (0);
+}
+#endif