BSD 4_3_Net_2 release
[unix-history] / usr / src / sys / tahoe / if / if_enp.c
index 1e23939..cd1235c 100644 (file)
@@ -2,14 +2,38 @@
  * Copyright (c) 1988 Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1988 Regents of the University of California.
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that this notice is preserved and that due credit is given
- * to the University of California at Berkeley. The name of the University
- * may not be used to endorse or promote products derived from this
- * software without specific prior written permission. This software
- * is provided ``as is'' without express or implied warranty.
+ * This code is derived from software contributed to Berkeley by
+ * Computer Consoles Inc.
  *
  *
- *     @(#)if_enp.c    1.6 (Berkeley) %G%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)if_enp.c    7.8 (Berkeley) 12/16/90
  */
 
 #include "enp.h"
  */
 
 #include "enp.h"
 /*
  * CMC ENP-20 Ethernet Controller.
  */
 /*
  * CMC ENP-20 Ethernet Controller.
  */
-#include "param.h"
-#include "systm.h"
-#include "mbuf.h"
-#include "buf.h"
-#include "protosw.h"
-#include "socket.h"
-#include "vmmac.h"
-#include "ioctl.h"
-#include "errno.h"
-#include "vmparam.h"
-#include "syslog.h"
-#include "uio.h"
-
-#include "../net/if.h"
-#include "../net/netisr.h"
-#include "../net/route.h"
+#include "sys/param.h"
+#include "sys/systm.h"
+#include "sys/mbuf.h"
+#include "sys/buf.h"
+#include "sys/protosw.h"
+#include "sys/socket.h"
+#include "sys/vmmac.h"
+#include "sys/ioctl.h"
+#include "sys/errno.h"
+#include "sys/vmparam.h"
+#include "sys/syslog.h"
+#include "sys/uio.h"
+
+#include "net/if.h"
+#include "net/netisr.h"
+#include "net/route.h"
 #ifdef INET
 #ifdef INET
-#include "../netinet/in.h"
-#include "../netinet/in_systm.h"
-#include "../netinet/in_var.h"
-#include "../netinet/ip.h"
-#include "../netinet/ip_var.h"
-#include "../netinet/if_ether.h"
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#include "netinet/ip_var.h"
+#include "netinet/if_ether.h"
 #endif
 #ifdef NS
 #endif
 #ifdef NS
-#include "../netns/ns.h"
-#include "../netns/ns_if.h"
+#include "netns/ns.h"
+#include "netns/ns_if.h"
 #endif
 
 #endif
 
-#include "../tahoe/cpu.h"
-#include "../tahoe/pte.h"
-#include "../tahoe/mtpr.h"
+#include "../include/cpu.h"
+#include "../include/pte.h"
+#include "../include/mtpr.h"
 
 
-#include "../tahoevba/vbavar.h"
-#include "../tahoeif/if_enpreg.h"
+#include "../vba/vbavar.h"
+#include "../if/if_enpreg.h"
 
 #define ENPSTART       0xf02000        /* standard enp start addr */
 #define        ENPUNIT(dev)    (minor(dev))    /* for enp ram devices */
 
 #define ENPSTART       0xf02000        /* standard enp start addr */
 #define        ENPUNIT(dev)    (minor(dev))    /* for enp ram devices */
@@ -67,7 +91,7 @@ struct  vba_device *enpinfo[NENP];
 struct  vba_driver enpdriver = 
     { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 };
 
 struct  vba_driver enpdriver = 
     { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 };
 
-int    enpinit(), enpioctl(), enpreset(), enpoutput();
+int    enpinit(), enpioctl(), enpreset(), enpoutput(), enpstart();
 struct  mbuf *enpget();
 
 /*
 struct  mbuf *enpget();
 
 /*
@@ -121,9 +145,10 @@ enpattach(ui)
        ifp->if_mtu = ETHERMTU;
        ifp->if_init = enpinit;
        ifp->if_ioctl = enpioctl;
        ifp->if_mtu = ETHERMTU;
        ifp->if_init = enpinit;
        ifp->if_ioctl = enpioctl;
-       ifp->if_output = enpoutput;
+       ifp->if_output = ether_output;
+       ifp->if_start = enpstart;
        ifp->if_reset = enpreset;
        ifp->if_reset = enpreset;
-       ifp->if_flags = IFF_BROADCAST;
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
        if_attach(ifp);
 }
 
        if_attach(ifp);
 }
 
@@ -182,7 +207,7 @@ enpintr(unit)
        ACK_ENP_INTR(addr);
 #endif
        while ((bcbp = (BCB *)ringget((RING *)&addr->enp_tohost )) != 0) {
        ACK_ENP_INTR(addr);
 #endif
        while ((bcbp = (BCB *)ringget((RING *)&addr->enp_tohost )) != 0) {
-               (void) enpread(&enp_softc[unit], bcbp);
+               enpread(&enp_softc[unit], bcbp);
                (void) ringput((RING *)&addr->enp_enpfree, bcbp); 
        }
 }
                (void) ringput((RING *)&addr->enp_enpfree, bcbp); 
        }
 }
@@ -197,7 +222,6 @@ enpread(es, bcbp)
        register struct ether_header *enp;
        struct mbuf *m;
        int s, len, off, resid;
        register struct ether_header *enp;
        struct mbuf *m;
        int s, len, off, resid;
-       register struct ifqueue *inq;
 
        es->es_if.if_ipackets++; 
        /*
 
        es->es_if.if_ipackets++; 
        /*
@@ -216,219 +240,63 @@ enpread(es, bcbp)
            enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
                off = (enp->ether_type - ETHERTYPE_TRAIL) * 512;
                if (off >= ETHERMTU)
            enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
                off = (enp->ether_type - ETHERTYPE_TRAIL) * 512;
                if (off >= ETHERMTU)
-                       goto setup;
+                       return;
                enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *));
                resid = ntohs(*(enpdataaddr(enp, off+2, u_short *)));
                if (off + resid > len)
                enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *));
                resid = ntohs(*(enpdataaddr(enp, off+2, u_short *)));
                if (off + resid > len)
-                       goto setup;
+                       return;
                len = off + resid;
        } else
                off = 0;
        if (len == 0)
                len = off + resid;
        } else
                off = 0;
        if (len == 0)
-               goto setup;
+               return;
 
        /*
         * Pull packet off interface.  Off is nonzero if packet
         * has trailing header; enpget will then force this header
 
        /*
         * Pull packet off interface.  Off is nonzero if packet
         * has trailing header; enpget 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.
+        * information to be at the front.
         */
        m = enpget((u_char *)enp, len, off, &es->es_if);
        if (m == 0)
         */
        m = enpget((u_char *)enp, len, off, &es->es_if);
        if (m == 0)
-               goto setup;
-       if (off) {
-               struct ifnet *ifp;
-
-               ifp = *(mtod(m, struct ifnet **));
-               m->m_off += 2 * sizeof (u_short);
-               m->m_len -= 2 * sizeof (u_short);
-               *(mtod(m, struct ifnet **)) = ifp;
-       }
-       switch (enp->ether_type) {
-
-#ifdef INET
-       case ETHERTYPE_IP:
-               schednetisr(NETISR_IP);
-               inq = &ipintrq;
-               break;
-#endif
-       case ETHERTYPE_ARP:
-               arpinput(&es->es_ac, m);
-               goto setup;
-
-#ifdef NS
-       case ETHERTYPE_NS:
-               schednetisr(NETISR_NS);
-               inq = &nsintrq;
-               break;
-#endif
-       default:
-               m_freem(m);
-               goto setup;
-       }
-       if (IF_QFULL(inq)) {
-               IF_DROP(inq);
-               m_freem(m);
-               goto setup;
-       }
-       s = splimp();
-       IF_ENQUEUE(inq, m);
-       splx(s);
-setup:
-       return (0);
+               return;
+       ether_input(&es->es_if, enp, m);
 }
 
 }
 
-/*
- * Ethernet output routine. (called by user)
- * 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.
- * If destination is this address or broadcast, send packet to
- * loop device to kludge around the fact that 3com interfaces can't
- * talk to themselves.
- */
-enpoutput(ifp, m0, dst)
+enpstart(ifp)
        struct ifnet *ifp;
        struct ifnet *ifp;
-       struct mbuf *m0;
-       struct sockaddr *dst;
 {
 {
-       register struct enp_softc *es = &enp_softc[ifp->if_unit];
-       register struct mbuf *m = m0;
-       register struct ether_header *enp;
-       register int off;
-       struct mbuf *mcopy = (struct mbuf *)0;
-       int type, s, error, usetrailers;
-       u_char edst[6];
-       struct in_addr idst;
-
-       if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
-               error = ENETDOWN;
-               goto bad;
-       }
-       switch (dst->sa_family) {
-#ifdef INET
-       case AF_INET:
-               idst = ((struct sockaddr_in *)dst)->sin_addr;
-               if (!arpresolve(&es->es_ac, m, &idst, edst, &usetrailers))
-                       return (0);     /* if not yet resolved */
-               if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr,
-                   sizeof (edst)))
-                       mcopy = m_copy(m, 0, (int)M_COPYALL);
-               off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
-               if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
-                   m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
-                       type = ETHERTYPE_TRAIL + (off>>9);
-                       m->m_off -= 2 * sizeof (u_short);
-                       m->m_len += 2 * sizeof (u_short);
-                       *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
-                       *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
-                       goto gottrailertype;
-               }
-               type = ETHERTYPE_IP;
-               off = 0;
-               goto gottype;
-#endif
-#ifdef NS
-       case AF_NS:
-               bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
-                   (caddr_t)edst, sizeof (edst));
-               if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof (edst)))
-                       mcopy = m_copy(m, 0, (int)M_COPYALL);
-               else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost,
-                   sizeof (edst)))
-                       return (looutput(&loif, m, dst));
-               type = ETHERTYPE_NS;
-               off = 0;
-               goto gottype;
-#endif
-       case AF_UNSPEC:
-               enp = (struct ether_header *)dst->sa_data;
-               bcopy((caddr_t)enp->ether_dhost, (caddr_t)edst, sizeof (edst));
-               type = enp->ether_type;
-               goto gottype;
-
-       default:
-               log(LOG_ERR, "enp%d: can't handle af%d\n",
-                   ifp->if_unit, dst->sa_family);
-               error = EAFNOSUPPORT;
-               goto bad;
-       }
 
 
-gottrailertype:
-       /*
-        * Packet to be sent as trailer: move first packet
-        * (control information) to end of chain.
-        */
-       while (m->m_next)
-               m = m->m_next;
-       m->m_next = m0;
-       m = m0->m_next;
-       m0->m_next = 0;
-       m0 = m;
-
-gottype:
-       /*
-         * Add local net header.  If no space in first mbuf,
-         * allocate another.
-         */
-       if (m->m_off > MMAXOFF ||
-           MMINOFF + sizeof (struct ether_header) > m->m_off) {
-               m = m_get(M_DONTWAIT, MT_HEADER);
-               if (m == 0) {
-                       error = ENOBUFS;
-                       goto bad;
-               }
-               m->m_next = m0;
-               m->m_off = MMINOFF;
-               m->m_len = sizeof (struct ether_header);
-       } else {
-               m->m_off -= sizeof (struct ether_header);
-               m->m_len += sizeof (struct ether_header);
-       }
-       enp = mtod(m, struct ether_header *);
-       bcopy((caddr_t)edst, (caddr_t)enp->ether_dhost, sizeof (edst));
-       bcopy((caddr_t)es->es_addr, (caddr_t)enp->ether_shost,
-           sizeof (es->es_addr));
-       enp->ether_type = htons((u_short)type);
-
-       /*
-        * Queue message on interface if possible 
-        */
-       s = splimp();   
-       if (enpput(ifp->if_unit, m)) {
-               error = ENOBUFS;
-               goto qfull;
-       }
-       splx(s);        
-       es->es_if.if_opackets++; 
-       return (mcopy ? looutput(&loif, mcopy, dst) : 0);
-qfull:
-       splx(s);        
-       m0 = m;
-bad:
-       m_freem(m0);
-       if (mcopy)
-               m_freem(mcopy);
-       return (error);
+       if (enpput(ifp))
+               return (ENOBUFS);
+       else
+               return (0);
 }
 
 /*
  * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus.
  */
 }
 
 /*
  * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus.
  */
-enpput(unit, m)
-       int unit;
-       struct mbuf *m;
+enpput(ifp)
+struct ifnet *ifp;
 {
        register BCB *bcbp;
        register struct enpdevice *addr;
        register struct mbuf *mp;
        register u_char *bp;
        register u_int len;
 {
        register BCB *bcbp;
        register struct enpdevice *addr;
        register struct mbuf *mp;
        register u_char *bp;
        register u_int len;
-       u_char *mcp;
+       int unit = ifp->if_unit, ret = 1;
+       struct mbuf *m;
 
        addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
 
        addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
-       if (ringempty((RING *)&addr->enp_hostfree)) 
-               return (1);     
+again:
+       if (ringempty((RING *)&addr->enp_hostfree))  {
+       /*      ifp->if_flags |= IFF_OACTIVE; */
+               return (ret);
+       }
+       IF_DEQUEUE(&ifp->if_snd, m);
+       if (m == 0) {
+               ifp->if_flags &= ~IFF_OACTIVE;
+               return (0);
+       }
        bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree);
        bcbp->b_len = 0;
        bp = (u_char *)ENPGETLONG(&bcbp->b_addr);
        bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree);
        bcbp->b_len = 0;
        bp = (u_char *)ENPGETLONG(&bcbp->b_addr);
@@ -436,17 +304,17 @@ enpput(unit, m)
                len = mp->m_len;
                if (len == 0)
                        continue;
                len = mp->m_len;
                if (len == 0)
                        continue;
-               mcp = mtod(mp, u_char *);
-               enpcopy(mcp, bp, len);
+               enpcopy(mtod(mp, u_char *), bp, len);
                bp += len;
                bcbp->b_len += len;
        }
                bp += len;
                bcbp->b_len += len;
        }
-       bcbp->b_len = MAX(ETHERMIN+sizeof (struct ether_header), bcbp->b_len);
+       bcbp->b_len = max(ETHERMIN+sizeof (struct ether_header), bcbp->b_len);
        bcbp->b_reserved = 0;
        if (ringput((RING *)&addr->enp_toenp, bcbp) == 1)
                INTR_ENP(addr);
        m_freem(m);
        bcbp->b_reserved = 0;
        if (ringput((RING *)&addr->enp_toenp, bcbp) == 1)
                INTR_ENP(addr);
        m_freem(m);
-       return (0);
+       ret = 0;
+       goto again;
 }
 
 /*
 }
 
 /*
@@ -456,65 +324,69 @@ enpput(unit, m)
  * mbufs have even lengths.
  */
 struct mbuf *
  * mbufs have even lengths.
  */
 struct mbuf *
-enpget(rxbuf, totlen, off0, ifp)
+enpget(rxbuf, totlen, off, ifp)
        u_char *rxbuf;
        u_char *rxbuf;
-       int totlen, off0;
+       int totlen, off;
        struct ifnet *ifp;
 {
        struct ifnet *ifp;
 {
-       register u_char *cp, *mcp;
+       register u_char *cp;
        register struct mbuf *m;
        struct mbuf *top = 0, **mp = &top;
        register struct mbuf *m;
        struct mbuf *top = 0, **mp = &top;
-       int len, off = off0;
+       int len;
+       u_char *packet_end;
+
+       rxbuf += sizeof (struct ether_header);
+       cp = rxbuf;
+       packet_end = cp + totlen;
+       if (off) {
+               off += 2 * sizeof(u_short);
+               totlen -= 2 *sizeof(u_short);
+               cp = rxbuf + off;
+       }
+
+       MGETHDR(m, M_DONTWAIT, MT_DATA);
+       if (m == 0)
+               return (0);
+       m->m_pkthdr.rcvif = ifp;
+       m->m_pkthdr.len = totlen;
+       m->m_len = MHLEN;
 
 
-       cp = rxbuf + sizeof (struct ether_header);
        while (totlen > 0) {
        while (totlen > 0) {
-               MGET(m, M_DONTWAIT, MT_DATA);
-               if (m == 0) 
-                       goto bad;
-               if (off) {
-                       len = totlen - off;
-                       cp = rxbuf + sizeof (struct ether_header) + off;
-               } else
-                       len = totlen;
-               if (len >= NBPG) {
-                       MCLGET(m);
-                       if (m->m_len == CLBYTES)
-                               m->m_len = len = MIN(len, CLBYTES);
+               if (top) {
+                       MGET(m, M_DONTWAIT, MT_DATA);
+                       if (m == 0) {
+                               m_freem(top);
+                               return (0);
+                       }
+                       m->m_len = MLEN;
+               }
+               len = min(totlen, (packet_end - cp));
+               if (len >= MINCLSIZE) {
+                       MCLGET(m, M_DONTWAIT);
+                       if (m->m_flags & M_EXT)
+                               m->m_len = len = min(len, MCLBYTES);
                        else
                        else
-                               m->m_len = len = MIN(MLEN, len);
+                               len = m->m_len;
                } else {
                } else {
-                       m->m_len = len = MIN(MLEN, len);
-                       m->m_off = MMINOFF;
-               }
-               mcp = mtod(m, u_char *);
-               if (ifp) {
                        /*
                        /*
-                        * Prepend interface pointer to first mbuf.
+                        * Place initial small packet/header at end of mbuf.
                         */
                         */
-                       *(mtod(m, struct ifnet **)) = ifp;
-                       mcp += sizeof (ifp);
-                       len -= sizeof (ifp);
-                       ifp = (struct ifnet *)0;
+                       if (len < m->m_len) {
+                               if (top == 0 && len + max_linkhdr <= m->m_len)
+                                       m->m_data += max_linkhdr;
+                               m->m_len = len;
+                       } else
+                               len = m->m_len;
                }
                }
-               enpcopy(cp, mcp, (u_int)len);
-               cp += len;
+               enpcopy(cp, mtod(m, u_char *), (u_int)len);
                *mp = m;
                mp = &m->m_next;
                *mp = m;
                mp = &m->m_next;
-               if (off == 0) {
-                       totlen -= len;
-                       continue;
-               }
-               off += len;
-               if (off == totlen) {
-                       cp = rxbuf + sizeof (struct ether_header);
-                       off = 0;
-                       totlen = off0;
-               }
+               totlen -= len;
+               cp += len;
+               if (cp == packet_end)
+                       cp = rxbuf;
        }
        return (top);
        }
        return (top);
-bad:
-       m_freem(top);
-       return (0);
 }
 
 enpcopy(from, to, cnt)
 }
 
 enpcopy(from, to, cnt)
@@ -561,7 +433,7 @@ enpioctl(ifp, cmd, data)
 
        case SIOCSIFADDR:
                ifp->if_flags |= IFF_UP;
 
        case SIOCSIFADDR:
                ifp->if_flags |= IFF_UP;
-               switch (ifa->ifa_addr.sa_family) {
+               switch (ifa->ifa_addr->sa_family) {
 #ifdef INET
                case AF_INET:
                        enpinit(ifp->if_unit);
 #ifdef INET
                case AF_INET:
                        enpinit(ifp->if_unit);
@@ -770,6 +642,7 @@ enpr_write(dev, uio)
        enpcopy((u_char *)iov->iov_base,
            (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len);
        uio->uio_resid -= iov->iov_len;
        enpcopy((u_char *)iov->iov_base,
            (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len);
        uio->uio_resid -= iov->iov_len;
+       uio->uio_offset += iov->iov_len;
        iov->iov_len = 0;
        return (0);
 }
        iov->iov_len = 0;
        return (0);
 }