fix to use only one soft intr for net thereby fixing bug in raw sockets
[unix-history] / usr / src / sys / vax / if / if_en.c
index 9048145..4df49c8 100644 (file)
@@ -1,4 +1,4 @@
-/*     if_en.c 4.15    81/11/29        */
+/*     if_en.c 4.43    82/03/19        */
 
 #include "en.h"
 
 
 #include "en.h"
 
 #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"
 
 
-#define        ENMTU   1024
+#define        ENMTU   (1024+512)
 
 int    enprobe(), enattach(), enrint(), enxint(), encollide();
 struct uba_device *eninfo[NEN];
 u_short enstd[] = { 0 };
 struct uba_driver endriver =
 
 int    enprobe(), enattach(), enrint(), enxint(), encollide();
 struct uba_device *eninfo[NEN];
 u_short enstd[] = { 0 };
 struct uba_driver endriver =
-       { enprobe, 0, enattach, 0, enstd, "es", eninfo };
+       { enprobe, 0, enattach, 0, enstd, "en", eninfo };
 #define        ENUNIT(x)       minor(x)
 
 int    eninit(),enoutput(),enreset();
 #define        ENUNIT(x)       minor(x)
 
 int    eninit(),enoutput(),enreset();
@@ -67,7 +68,7 @@ struct        en_softc {
 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;
 
 COUNT(ENPROBE);
        register struct endevice *addr = (struct endevice *)reg;
 
 COUNT(ENPROBE);
@@ -96,15 +97,26 @@ enattach(ui)
 COUNT(ENATTACH);
 
        es->es_if.if_unit = 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_net = ui->ui_flags;
        es->es_if.if_host[0] =
        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])->en_addr) & 0xff;
+           (~(((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_addr =
            if_makeaddr(es->es_if.if_net, es->es_if.if_host[0]);
-       es->es_if.if_output = enoutput;
+       es->es_if.if_broadaddr =
+           if_makeaddr(es->es_if.if_net, 0);
        es->es_if.if_init = eninit;
        es->es_if.if_init = eninit;
+       es->es_if.if_output = enoutput;
        es->es_if.if_ubareset = enreset;
        es->es_if.if_ubareset = enreset;
+       es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16;
+       if_attach(&es->es_if);
 }
 
 /*
 }
 
 /*
@@ -117,12 +129,10 @@ enreset(unit, uban)
        register struct uba_device *ui;
 COUNT(ENRESET);
 
        register struct uba_device *ui;
 COUNT(ENRESET);
 
-       if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0) {
-               printf("es%d: not alive\n", unit);
-               return;
-       }
-       if (ui->ui_ubanum != uban)
+       if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 ||
+           ui->ui_ubanum != uban)
                return;
                return;
+       printf(" en%d", unit);
        eninit(unit);
 }
 
        eninit(unit);
 }
 
@@ -133,26 +143,28 @@ COUNT(ENRESET);
 eninit(unit)
        int unit;
 {
 eninit(unit)
        int unit;
 {
-       register struct uba_device *ui;
+       register struct en_softc *es = &en_softc[unit];
+       register struct uba_device *ui = eninfo[unit];
        register struct endevice *addr;
        register struct endevice *addr;
-       register struct en_softc *es;
        int s;
 
        int s;
 
-       es = &en_softc[unit];
-       ui = eninfo[unit];
        if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
        if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
-           sizeof (struct en_header), (int)btop(ENMTU)) == 0) { 
-               printf("es%d: can't initialize\n", unit);
+           sizeof (struct en_header), (int)btoc(ENMTU)) == 0) { 
+               printf("en%d: can't initialize\n", unit);
                return;
        }
        addr = (struct endevice *)ui->ui_addr;
        addr->en_istat = addr->en_ostat = 0;
 
        /*
                return;
        }
        addr = (struct endevice *)ui->ui_addr;
        addr->en_istat = addr->en_ostat = 0;
 
        /*
-        * Hang pending read, start any writes.
+        * Hang a receive and start any
+        * pending writes by faking a transmit complete.
         */
        s = splimp();
         */
        s = splimp();
-       enstart(unit);
+       addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
+       addr->en_iwc = -(sizeof (struct en_header) + ENMTU) >> 1;
+       addr->en_istat = EN_IEN|EN_GO;
+       es->es_oactive = 1;
        enxint(unit);
        splx(s);
 }
        enxint(unit);
        splx(s);
 }
@@ -170,17 +182,14 @@ int       enlastdel = 25;
 enstart(dev)
        dev_t dev;
 {
 enstart(dev)
        dev_t dev;
 {
-        int unit;
-       struct uba_device *ui;
+        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 struct en_softc *es;
        struct mbuf *m;
        int dest;
 COUNT(ENSTART);
 
        struct mbuf *m;
        int dest;
 COUNT(ENSTART);
 
-       unit = ENUNIT(dev);
-       ui = eninfo[unit];
-       es = &en_softc[unit];
        if (es->es_oactive)
                goto restart;
 
        if (es->es_oactive)
                goto restart;
 
@@ -194,6 +203,7 @@ COUNT(ENSTART);
                es->es_oactive = 0;
                return;
        }
                es->es_oactive = 0;
                return;
        }
+       dest = mtod(m, struct en_header *)->en_dhost;
        es->es_olen = if_wubaput(&es->es_ifuba, m);
 
        /*
        es->es_olen = if_wubaput(&es->es_ifuba, m);
 
        /*
@@ -202,7 +212,6 @@ COUNT(ENSTART);
         * receiver, enforce a small delay (about 1ms) in interface
         * on successive packets sent to same host.
         */
         * receiver, enforce a small delay (about 1ms) in interface
         * on successive packets sent to same host.
         */
-       dest = mtod(m, struct en_header *)->en_dhost;
        if (es->es_lastx && es->es_lastx == dest)
                es->es_delay = enlastdel;
        else
        if (es->es_lastx && es->es_lastx == dest)
                es->es_delay = enlastdel;
        else
@@ -215,7 +224,7 @@ restart:
         */
        UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp);
        addr = (struct endevice *)ui->ui_addr;
         */
        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_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_odelay = es->es_delay;
        addr->en_owc = -((es->es_olen + 1) >> 1);
        addr->en_ostat = EN_IEN|EN_GO;
@@ -229,22 +238,28 @@ restart:
 enxint(unit)
        int unit;
 {
 enxint(unit)
        int unit;
 {
-       register struct endevice *addr;
-       register struct uba_device *ui;
-       register struct en_softc *es;
+       register struct uba_device *ui = eninfo[unit];
+       register struct en_softc *es = &en_softc[unit];
+       register struct endevice *addr = (struct endevice *)ui->ui_addr;
 COUNT(ENXINT);
 
 COUNT(ENXINT);
 
-       ui = eninfo[unit];
-       es = &en_softc[unit];
        if (es->es_oactive == 0)
                return;
        if (es->es_oactive == 0)
                return;
-       addr = (struct endevice *)ui->ui_addr;
-       es = &en_softc[unit];
+       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_oactive = 0;
        es->es_delay = 0;
        es->es_mask = ~0;
-       if (addr->en_ostat&EN_OERROR)
-               printf("es%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) {
                es->es_lastx = 0;
                return;
        if (es->es_if.if_snd.ifq_head == 0) {
                es->es_lastx = 0;
                return;
@@ -260,23 +275,42 @@ COUNT(ENXINT);
 encollide(unit)
        int unit;
 {
 encollide(unit)
        int unit;
 {
-       register struct en_softc *es;
+       struct en_softc *es = &en_softc[unit];
 COUNT(ENCOLLIDE);
 
 COUNT(ENCOLLIDE);
 
-       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
+        * backed off 16 times, and give up.
+        */
        if (es->es_mask == 0) {
        if (es->es_mask == 0) {
-               printf("es%d: send error\n", unit);
+               printf("en%d: send error\n", unit);
                enxint(unit);
                enxint(unit);
-       } else {
-               es->es_mask <<= 1;
-               es->es_delay = mfpr(ICR) &~ es->es_mask;
-               enstart(unit);
+               return;
        }
        }
+       /*
+        * 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);
 }
 
 }
 
+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.
@@ -289,25 +323,25 @@ COUNT(ENCOLLIDE);
 enrint(unit)
        int unit;
 {
 enrint(unit)
        int unit;
 {
-       struct endevice *addr;
-       register struct en_softc *es;
-       struct en_header *en;
+       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;
        struct mbuf *m;
-       struct ifqueue *inq;
-       register int len;
+       int len;
+       register struct ifqueue *inq;
        int off;
 COUNT(ENRINT);
 
        int off;
 COUNT(ENRINT);
 
-       es = &en_softc[unit];
-       addr = (struct endevice *)eninfo[unit]->ui_addr;
+       es->es_if.if_ipackets++;
 
        /*
 
        /*
-        * Purge BDP; drop error packets.
+        * Purge BDP; drop if input error indicated.
         */
        UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp);
        if (addr->en_istat&EN_IERROR) {
                es->es_if.if_ierrors++;
         */
        UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp);
        if (addr->en_istat&EN_IERROR) {
                es->es_if.if_ierrors++;
-               printf("es%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;
        }
 
@@ -322,8 +356,9 @@ COUNT(ENRINT);
        if (en->en_type >= ENPUP_TRAIL &&
            en->en_type < ENPUP_TRAIL+ENPUP_NTRAILER) {
                off = (en->en_type - ENPUP_TRAIL) * 512;
        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 *);
                en->en_type = *endataaddr(en, off, u_short *);
-               off += 2;
        } else
                off = 0;
 
        } else
                off = 0;
 
@@ -335,14 +370,21 @@ COUNT(ENRINT);
 
 #ifdef INET
        case ENPUP_IPTYPE:
 
 #ifdef INET
        case ENPUP_IPTYPE:
-               len = endataaddr(en, off, struct ip *)->ip_len;
-               setipintr();
-               inq = &ipintrq;
+               len = htons((u_short)endataaddr(en, off ? off+2 : 0, struct ip *)->ip_len);
+               if (off)
+                       len += 2;
                break;
 #endif
                break;
 #endif
-
+#ifdef PUP
+       case ENPUP_PUPTYPE:
+               len = endataaddr(en, off, struct pup_header *)->pup_length;
+               if (off)
+                       len -= 2;
+               break;
+#endif
+               
        default:
        default:
-               printf("en%d: unknow pkt type 0x%x\n", en->en_type);
+               printf("en%d: unknown pkt type 0x%x\n", unit, en->en_type);
                goto setup;
        }
        if (len == 0)
                goto setup;
        }
        if (len == 0)
@@ -352,15 +394,39 @@ COUNT(ENRINT);
         * 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 the trailer data
-        * (which we ``consumed'' above).
+        * the two-byte type which is at the front of any trailer data.
         */
        m = if_rubaget(&es->es_ifuba, len, off);
         */
        m = if_rubaget(&es->es_ifuba, len, off);
+       if (m == 0)
+               goto setup;
        if (off) {
                m->m_off += 2;
                m->m_len -= 2;
        }
        if (off) {
                m->m_off += 2;
                m->m_len -= 2;
        }
-       IF_ENQUEUE(inq, m);
+       switch (en->en_type) {
+
+#ifdef INET
+       case ENPUP_IPTYPE:
+               schednetisr(NETISR_IP);
+               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);
+               goto setup;
+               }
+       }
+       if (IF_QFULL(inq)) {
+               IF_DROP(inq);
+               (void) m_freem(m);
+       } else
+               IF_ENQUEUE(inq, m);
 
 setup:
        /*
 
 setup:
        /*
@@ -382,32 +448,55 @@ enoutput(ifp, m0, pf)
        struct mbuf *m0;
        int pf;
 {
        struct mbuf *m0;
        int pf;
 {
-       int type, dest;
+       int type, dest, s, off;
        register struct mbuf *m = m0;
        register struct en_header *en;
        register struct mbuf *m = m0;
        register struct en_header *en;
-       int s;
 
 
+COUNT(ENOUTPUT);
        switch (pf) {
 
 #ifdef INET
        case PF_INET: {
                register struct ip *ip = mtod(m0, struct ip *);
        switch (pf) {
 
 #ifdef INET
        case PF_INET: {
                register struct ip *ip = mtod(m0, struct ip *);
-               int off;
 
 
+#ifndef ENKLUDGE
                dest = ip->ip_dst.s_addr >> 24;
                dest = ip->ip_dst.s_addr >> 24;
-               off = ip->ip_len - m->m_len;
-               if (off && off % 512 == 0 && m->m_off >= MMINOFF + 2) {
+#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;
                        goto gottrailertype;
                }
                        type = ENPUP_TRAIL + (off>>9);
                        m->m_off -= 2;
                        m->m_len += 2;
                        *mtod(m, u_short *) = ENPUP_IPTYPE;
                        goto gottrailertype;
                }
+#endif
                type = ENPUP_IPTYPE;
                off = 0;
                goto gottype;
                }
 #endif
                type = ENPUP_IPTYPE;
                off = 0;
                goto gottype;
                }
 #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;
+               off = 0;
+               goto gottype;
+               }
+#endif
 
        default:
                printf("en%d: can't encapsulate pf%d\n", ifp->if_unit, pf);
 
        default:
                printf("en%d: can't encapsulate pf%d\n", ifp->if_unit, pf);
@@ -415,25 +504,26 @@ enoutput(ifp, m0, pf)
                return (0);
        }
 
                return (0);
        }
 
+gottrailertype:
        /*
         * Packet to be sent as trailer: move first packet
         * (control information) to end of chain.
         */
        /*
         * Packet to be sent as trailer: move first packet
         * (control information) to end of chain.
         */
-gottrailertype:
        while (m->m_next)
                m = m->m_next;
        m->m_next = m0;
        m = m0->m_next;
        m0->m_next = 0;
        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.
         */
        /*
         * Add local net header.  If no space in first mbuf,
         * allocate another.
         */
-gottype:
-       m0 = m;
-       if (MMINOFF + sizeof (struct en_header) > m->m_off) {
-               m = m_get(0);
+       if (m->m_off > MMAXOFF ||
+           MMINOFF + sizeof (struct en_header) > m->m_off) {
+               m = m_get(M_DONTWAIT);
                if (m == 0) {
                        m_freem(m0);
                        return (0);
                if (m == 0) {
                        m_freem(m0);
                        return (0);
@@ -442,7 +532,6 @@ gottype:
                m->m_off = MMINOFF;
                m->m_len = sizeof (struct en_header);
        } else {
                m->m_off = MMINOFF;
                m->m_len = sizeof (struct en_header);
        } else {
-               m = m0;
                m->m_off -= sizeof (struct en_header);
                m->m_len += sizeof (struct en_header);
        }
                m->m_off -= sizeof (struct en_header);
                m->m_len += sizeof (struct en_header);
        }
@@ -456,9 +545,15 @@ gottype:
         * not yet active.
         */
        s = splimp();
         * not yet active.
         */
        s = splimp();
+       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);
 }