fix bug in routing socket, add sanity check . . .
[unix-history] / usr / src / sys / net / if_ethersubr.c
index 9aec93a..4fd566a 100644 (file)
@@ -1,20 +1,10 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * Copyright (c) 1982, 1989 Regents of the University of California.
  * All rights reserved.
  *
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, 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'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  *
  *
- *     @(#)if_ethersubr.c      7.2 (Berkeley) %G%
+ *     @(#)if_ethersubr.c      7.10 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -31,8 +21,9 @@
 #include "netisr.h"
 #include "route.h"
 #include "if_llc.h"
 #include "netisr.h"
 #include "route.h"
 #include "if_llc.h"
+#include "if_dl.h"
 
 
-#include "../machine/mtpr.h"
+#include "machine/mtpr.h"
 
 #ifdef INET
 #include "../netinet/in.h"
 
 #ifdef INET
 #include "../netinet/in.h"
@@ -49,6 +40,7 @@
 #include "../netiso/argo_debug.h"
 #include "../netiso/iso.h"
 #include "../netiso/iso_var.h"
 #include "../netiso/argo_debug.h"
 #include "../netiso/iso.h"
 #include "../netiso/iso_var.h"
+#include "../netiso/iso_snpac.h"
 #endif
 
 u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 #endif
 
 u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -61,10 +53,11 @@ extern      struct ifnet loif;
  * packet leaves a multiple of 512 bytes of data in remainder.
  * Assumes that ifp is actually pointer to arpcom structure.
  */
  * packet leaves a multiple of 512 bytes of data in remainder.
  * Assumes that ifp is actually pointer to arpcom structure.
  */
-ether_output(ifp, m0, dst)
+ether_output(ifp, m0, dst, rt)
        register struct ifnet *ifp;
        struct mbuf *m0;
        struct sockaddr *dst;
        register struct ifnet *ifp;
        struct mbuf *m0;
        struct sockaddr *dst;
+       struct rtentry *rt;
 {
        short type;
        int s, error = 0;
 {
        short type;
        int s, error = 0;
@@ -73,16 +66,15 @@ ether_output(ifp, m0, dst)
        register struct mbuf *m = m0;
        struct mbuf *mcopy = (struct mbuf *)0;
        register struct ether_header *eh;
        register struct mbuf *m = m0;
        struct mbuf *mcopy = (struct mbuf *)0;
        register struct ether_header *eh;
-       int usetrailers, off;
+       int usetrailers, off, len = m->m_pkthdr.len;
+       extern struct timeval time;
 #define        ac ((struct arpcom *)ifp)
 
        if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
                error = ENETDOWN;
                goto bad;
        }
 #define        ac ((struct arpcom *)ifp)
 
        if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
                error = ENETDOWN;
                goto bad;
        }
-       if (ifp->if_flags & IFF_SIMPLEX && dst->sa_family != AF_UNSPEC &&
-           !bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr, sizeof (edst)))
-               mcopy = m_copy(m, 0, (int)M_COPYALL);
+       ifp->if_lastchange = time;
        switch (dst->sa_family) {
 
 #ifdef INET
        switch (dst->sa_family) {
 
 #ifdef INET
@@ -91,7 +83,7 @@ ether_output(ifp, m0, dst)
                if (!arpresolve(ac, m, &idst, edst, &usetrailers))
                        return (0);     /* if not yet resolved */
                if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
                if (!arpresolve(ac, m, &idst, edst, &usetrailers))
                        return (0);     /* if not yet resolved */
                if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
-                   mcopy = m_copy(m, 0, (int)M_COPYALL);
+                       mcopy = m_copy(m, 0, (int)M_COPYALL);
                off = m->m_pkthdr.len - m->m_len;
                if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
                    (m->m_flags & M_EXT) == 0 &&
                off = m->m_pkthdr.len - m->m_len;
                if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
                    (m->m_flags & M_EXT) == 0 &&
@@ -99,6 +91,7 @@ ether_output(ifp, m0, dst)
                        type = ETHERTYPE_TRAIL + (off>>9);
                        m->m_data -= 2 * sizeof (u_short);
                        m->m_len += 2 * sizeof (u_short);
                        type = ETHERTYPE_TRAIL + (off>>9);
                        m->m_data -= 2 * sizeof (u_short);
                        m->m_len += 2 * sizeof (u_short);
+                       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;
                        *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
                        *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
                        goto gottrailertype;
@@ -109,35 +102,50 @@ ether_output(ifp, m0, dst)
 #ifdef NS
        case AF_NS:
                type = ETHERTYPE_NS;
 #ifdef NS
        case AF_NS:
                type = ETHERTYPE_NS;
-               if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
-                       return(looutput(&loif, m, dst));
                bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
                    (caddr_t)edst, sizeof (edst));
                bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
                    (caddr_t)edst, sizeof (edst));
+               if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
+                       return (looutput(&loif, m, dst));
                if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
                if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
-                   mcopy = m_copy(m, 0, (int)M_COPYALL);
+                       mcopy = m_copy(m, 0, (int)M_COPYALL);
                goto gottype;
 #endif
 #ifdef ISO
        case AF_ISO: {
                goto gottype;
 #endif
 #ifdef ISO
        case AF_ISO: {
-               int     len;
-               int     ret;
+               int     snpalen;
                struct  llc *l;
 
                struct  llc *l;
 
-               if ((ret = iso_tryloopback(m, (struct sockaddr_iso *)dst)) >= 0)
-                       return (ret);
-               ret = iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
-                                       (char *)edst, &len);
-               if (ret > 0) {
-                       m_freem(m); /* Not Resolved */
-                       return(ret);
+       iso_again:
+               iso_etherout();
+               if (rt && rt->rt_gateway && (rt->rt_flags & RTF_UP)) {
+                       if (rt->rt_flags & RTF_GATEWAY) {
+                               if (rt->rt_llinfo) {
+                                       rt = (struct rtentry *)rt->rt_llinfo;
+                                       goto iso_again;
+                               }
+                       } else {
+                               register struct sockaddr_dl *sdl = 
+                                       (struct sockaddr_dl *)rt->rt_gateway;
+                               if (sdl && sdl->sdl_family == AF_LINK
+                                   && sdl->sdl_alen > 0) {
+                                       bcopy(LLADDR(sdl), (char *)edst,
+                                                               sizeof(edst));
+                                       goto iso_resolved;
+                               }
+                       }
                }
                }
+               if ((error = iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
+                                       (char *)edst, &snpalen)) > 0)
+                       goto bad; /* Not Resolved */
+       iso_resolved:
                M_PREPEND(m, 3, M_DONTWAIT);
                if (m == NULL)
                M_PREPEND(m, 3, M_DONTWAIT);
                if (m == NULL)
-                       return(0);
+                       return (0);
                type = m->m_pkthdr.len;
                l = mtod(m, struct llc *);
                l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
                l->llc_control = LLC_UI;
                type = m->m_pkthdr.len;
                l = mtod(m, struct llc *);
                l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
                l->llc_control = LLC_UI;
+               len += 3;
                IFDEBUG(D_ETHER)
                        int i;
                        printf("unoutput: sending pkt to: ");
                IFDEBUG(D_ETHER)
                        int i;
                        printf("unoutput: sending pkt to: ");
@@ -147,6 +155,17 @@ ether_output(ifp, m0, dst)
                ENDDEBUG
                } goto gottype;
 #endif ISO
                ENDDEBUG
                } goto gottype;
 #endif ISO
+#ifdef RMP
+       case AF_RMP:
+               /*
+                *  This is IEEE 802.3 -- the Ethernet `type' field is
+                *  really a `length' field.
+                */
+               type = m->m_len;
+               bcopy((caddr_t)dst->sa_data, (caddr_t)edst, sizeof(edst));
+               break;
+#endif
+
        case AF_UNSPEC:
                eh = (struct ether_header *)dst->sa_data;
                bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
        case AF_UNSPEC:
                eh = (struct ether_header *)dst->sa_data;
                bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
@@ -201,10 +220,13 @@ gottype:
        }
        IF_ENQUEUE(&ifp->if_snd, m);
        if ((ifp->if_flags & IFF_OACTIVE) == 0)
        }
        IF_ENQUEUE(&ifp->if_snd, m);
        if ((ifp->if_flags & IFF_OACTIVE) == 0)
-               error = (*ifp->if_start)(ifp);
+               (*ifp->if_start)(ifp);
        splx(s);
        if (mcopy)
                (void) looutput(&loif, mcopy, dst);
        splx(s);
        if (mcopy)
                (void) looutput(&loif, mcopy, dst);
+       ifp->if_obytes += len + sizeof (struct ether_header);
+       if (edst[0] & 1)
+               ifp->if_omcasts++;
        return (error);
 
 bad:
        return (error);
 
 bad:
@@ -216,9 +238,9 @@ bad:
 }
 
 /*
 }
 
 /*
- * Pull packet off interface.  Off is nonzero if packet
- * has trailing header; we still have to drop
- * the type and length which are at the front of any trailer data.
+ * Process a received Ethernet packet;
+ * the packet is in the mbuf chain m without
+ * the ether header, which is provided separately.
  */
 ether_input(ifp, eh, m)
        struct ifnet *ifp;
  */
 ether_input(ifp, eh, m)
        struct ifnet *ifp;
@@ -229,11 +251,15 @@ ether_input(ifp, eh, m)
        register struct llc *l;
        int s;
 
        register struct llc *l;
        int s;
 
+       ifp->if_lastchange = time;
+       ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
        if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
            sizeof(etherbroadcastaddr)) == 0)
                m->m_flags |= M_BCAST;
        else if (eh->ether_dhost[0] & 1)
                m->m_flags |= M_MCAST;
        if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
            sizeof(etherbroadcastaddr)) == 0)
                m->m_flags |= M_BCAST;
        else if (eh->ether_dhost[0] & 1)
                m->m_flags |= M_MCAST;
+       if (m->m_flags & (M_BCAST|M_MCAST))
+               ifp->if_imcasts++;
 
        switch (eh->ether_type) {
 #ifdef INET
 
        switch (eh->ether_type) {
 #ifdef INET
@@ -254,6 +280,7 @@ ether_input(ifp, eh, m)
 
 #endif
        default:
 
 #endif
        default:
+#ifdef ISO
                if (eh->ether_type > ETHERMTU)
                        goto dropanyway;
                l = mtod(m, struct llc *);
                if (eh->ether_type > ETHERMTU)
                        goto dropanyway;
                l = mtod(m, struct llc *);
@@ -262,8 +289,10 @@ ether_input(ifp, eh, m)
                /* LLC_UI_P forbidden in class 1 service */
                    if ((l->llc_dsap == LLC_ISO_LSAP) &&
                        (l->llc_ssap == LLC_ISO_LSAP)) {
                /* LLC_UI_P forbidden in class 1 service */
                    if ((l->llc_dsap == LLC_ISO_LSAP) &&
                        (l->llc_ssap == LLC_ISO_LSAP)) {
-#ifdef ISO
                                /* LSAP for ISO */
                                /* LSAP for ISO */
+                       m->m_data += 3;         /* XXX */
+                       m->m_len -= 3;          /* XXX */
+                       m->m_pkthdr.len -= 3;   /* XXX */
                        M_PREPEND(m, sizeof *eh, M_DONTWAIT);
                        if (m == 0)
                                return;
                        M_PREPEND(m, sizeof *eh, M_DONTWAIT);
                        if (m == 0)
                                return;
@@ -273,22 +302,10 @@ ether_input(ifp, eh, m)
                        ENDDEBUG
                        schednetisr(NETISR_ISO);
                        inq = &clnlintrq;
                        ENDDEBUG
                        schednetisr(NETISR_ISO);
                        inq = &clnlintrq;
-                       if (IF_QFULL(inq)){
-                               IFDEBUG(D_ETHER)
-                                   printf(" qfull\n");
-                               ENDDEBUG
-                               IF_DROP(inq);
-                               m_freem(m);
-                       } else {
-                               IF_ENQUEUE(inq, m);
-                               IFDEBUG(D_ETHER)
-                                   printf(" queued\n");
-                               ENDDEBUG
-                       }
-                       return;
-#endif ISO
+                       break;
                    }
                    }
-                   break;
+                   goto dropanyway;
+
                case LLC_XID:
                case LLC_XID_P:
                    if(m->m_len < 6)
                case LLC_XID:
                case LLC_XID_P:
                    if(m->m_len < 6)
@@ -327,6 +344,10 @@ ether_input(ifp, eh, m)
                    m_freem(m);
                    return;
            }
                    m_freem(m);
                    return;
            }
+#else
+           m_freem(m);
+           return;
+#endif ISO
        }
 
        s = splimp();
        }
 
        s = splimp();
@@ -358,3 +379,4 @@ ether_sprintf(ap)
        *--cp = 0;
        return (etherbuf);
 }
        *--cp = 0;
        return (etherbuf);
 }
+iso_etherout() {}