fix copyright, this was done from scratch
[unix-history] / usr / src / sys / net / if_ethersubr.c
index 4a9247e..1996513 100644 (file)
@@ -2,23 +2,14 @@
  * Copyright (c) 1982, 1989 Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1982, 1989 Regents of the University of California.
  * 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.7 (Berkeley) %G%
+ *     @(#)if_ethersubr.c      7.14 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "systm.h"
  */
 
 #include "param.h"
 #include "systm.h"
+#include "kernel.h"
 #include "malloc.h"
 #include "mbuf.h"
 #include "protosw.h"
 #include "malloc.h"
 #include "mbuf.h"
 #include "protosw.h"
@@ -38,8 +29,8 @@
 #ifdef INET
 #include "../netinet/in.h"
 #include "../netinet/in_var.h"
 #ifdef INET
 #include "../netinet/in.h"
 #include "../netinet/in_var.h"
-#include "../netinet/if_ether.h"
 #endif
 #endif
+#include "../netinet/if_ether.h"
 
 #ifdef NS
 #include "../netns/ns.h"
 
 #ifdef NS
 #include "../netns/ns.h"
 #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 };
 extern struct ifnet loif;
 #endif
 
 u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 extern struct ifnet loif;
+#define senderr(e) { error = (e); goto bad;}
 
 /*
  * Ethernet output routine.
 
 /*
  * Ethernet output routine.
@@ -62,34 +55,53 @@ 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, rt)
+ether_output(ifp, m0, dst, rt0)
        register struct ifnet *ifp;
        struct mbuf *m0;
        struct sockaddr *dst;
        register struct ifnet *ifp;
        struct mbuf *m0;
        struct sockaddr *dst;
-       struct rtentry *rt;
+       struct rtentry *rt0;
 {
        short type;
        int s, error = 0;
        u_char edst[6];
 {
        short type;
        int s, error = 0;
        u_char edst[6];
-       struct in_addr idst;
        register struct mbuf *m = m0;
        register struct mbuf *m = m0;
+       register struct rtentry *rt;
        struct mbuf *mcopy = (struct mbuf *)0;
        register struct ether_header *eh;
        int usetrailers, off, len = m->m_pkthdr.len;
        struct mbuf *mcopy = (struct mbuf *)0;
        register struct ether_header *eh;
        int usetrailers, off, len = m->m_pkthdr.len;
-       extern struct timeval time;
 #define        ac ((struct arpcom *)ifp)
 
 #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_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+               senderr(ENETDOWN);
        ifp->if_lastchange = time;
        ifp->if_lastchange = time;
+       if (rt = rt0) {
+               if ((rt->rt_flags & RTF_UP) == 0) {
+                       if (rt0 = rt = rtalloc1(dst, 1))
+                               rt->rt_refcnt--;
+                       else 
+                               return (EHOSTUNREACH);
+               }
+               if (rt->rt_flags & RTF_GATEWAY) {
+                       if (rt->rt_gwroute == 0)
+                               goto lookup;
+                       if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
+                               rtfree(rt); rt = rt0;
+                       lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
+                               if ((rt = rt->rt_gwroute) == 0)
+                                       return (EHOSTUNREACH);
+                       }
+               }
+               if (rt->rt_flags & RTF_REJECT)
+                       if (rt->rt_rmx.rmx_expire == 0 ||
+                           time.tv_sec < rt->rt_rmx.rmx_expire)
+                               return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
+       }
        switch (dst->sa_family) {
 
 #ifdef INET
        case AF_INET:
        switch (dst->sa_family) {
 
 #ifdef INET
        case AF_INET:
-               idst = ((struct sockaddr_in *)dst)->sin_addr;
-               if (!arpresolve(ac, m, &idst, edst, &usetrailers))
+               if (!arpresolve(ac, rt, m, (struct sockaddr_in *)dst,
+                               edst, &usetrailers))
                        return (0);     /* if not yet resolved */
                if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
                        mcopy = m_copy(m, 0, (int)M_COPYALL);
                        return (0);     /* if not yet resolved */
                if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
                        mcopy = m_copy(m, 0, (int)M_COPYALL);
@@ -114,38 +126,38 @@ ether_output(ifp, m0, dst, rt)
                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)))
                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));
+                       return (looutput(ifp, m, dst, rt));
                if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
                        mcopy = m_copy(m, 0, (int)M_COPYALL);
                goto gottype;
 #endif
 #ifdef ISO
        case AF_ISO: {
                if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
                        mcopy = m_copy(m, 0, (int)M_COPYALL);
                goto gottype;
 #endif
 #ifdef ISO
        case AF_ISO: {
-               int     len;
-               int     ret;
+               int     snpalen;
                struct  llc *l;
                struct  llc *l;
+               register struct sockaddr_dl *sdl;
 
 
-               if (rt && rt->rt_gateway &&
-                   rt->rt_gateway->sa_family == AF_LINK) {
-                       register struct sockaddr_dl *sdl;
-                       sdl = (struct sockaddr_dl *)rt->rt_gateway;
-                       if (len = sdl->sdl_nlen) {
-                               bcopy(LLADDR(sdl), (char *)edst, len);
-                               goto iso_resolved;
+               if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) &&
+                   sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) {
+                       bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst));
+               } else if (error =
+                           iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
+                                           (char *)edst, &snpalen))
+                       goto bad; /* Not Resolved */
+               if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) &&
+                   (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
+                       M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
+                       if (mcopy) {
+                               eh = mtod(mcopy, struct ether_header *);
+                               bcopy((caddr_t)edst,
+                                     (caddr_t)eh->ether_dhost, sizeof (edst));
+                               bcopy((caddr_t)ac->ac_enaddr,
+                                     (caddr_t)eh->ether_shost, sizeof (edst));
                        }
                }
                        }
                }
-               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_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;
                type = m->m_pkthdr.len;
                l = mtod(m, struct llc *);
                l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
@@ -180,8 +192,7 @@ ether_output(ifp, m0, dst, rt)
        default:
                printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
                        dst->sa_family);
        default:
                printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
                        dst->sa_family);
-               error = EAFNOSUPPORT;
-               goto bad;
+               senderr(EAFNOSUPPORT);
        }
 
 gottrailertype:
        }
 
 gottrailertype:
@@ -196,15 +207,15 @@ gottrailertype:
        m0->m_next = 0;
 
 gottype:
        m0->m_next = 0;
 
 gottype:
+       if (mcopy)
+               (void) looutput(ifp, mcopy, dst, rt);
        /*
         * Add local net header.  If no space in first mbuf,
         * allocate another.
         */
        M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
        /*
         * Add local net header.  If no space in first mbuf,
         * allocate another.
         */
        M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
-       if (m == 0) {
-               error = ENOBUFS;
-               goto bad;
-       }
+       if (m == 0)
+               senderr(ENOBUFS);
        eh = mtod(m, struct ether_header *);
        type = htons((u_short)type);
        bcopy((caddr_t)&type,(caddr_t)&eh->ether_type,
        eh = mtod(m, struct ether_header *);
        type = htons((u_short)type);
        bcopy((caddr_t)&type,(caddr_t)&eh->ether_type,
@@ -212,31 +223,26 @@ gottype:
        bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
        bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
            sizeof(eh->ether_shost));
        bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
        bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
            sizeof(eh->ether_shost));
+       s = splimp();
        /*
         * Queue message on interface, and start output if interface
         * not yet active.
         */
        /*
         * 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);
                splx(s);
        if (IF_QFULL(&ifp->if_snd)) {
                IF_DROP(&ifp->if_snd);
                splx(s);
-               error = ENOBUFS;
-               goto bad;
+               senderr(ENOBUFS);
        }
        IF_ENQUEUE(&ifp->if_snd, m);
        if ((ifp->if_flags & IFF_OACTIVE) == 0)
                (*ifp->if_start)(ifp);
        splx(s);
        }
        IF_ENQUEUE(&ifp->if_snd, m);
        if ((ifp->if_flags & IFF_OACTIVE) == 0)
                (*ifp->if_start)(ifp);
        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:
        ifp->if_obytes += len + sizeof (struct ether_header);
        if (edst[0] & 1)
                ifp->if_omcasts++;
        return (error);
 
 bad:
-       if (mcopy)
-               m_freem(mcopy);
        if (m)
                m_freem(m);
        return (error);
        if (m)
                m_freem(m);
        return (error);
@@ -274,8 +280,9 @@ ether_input(ifp, eh, m)
                break;
 
        case ETHERTYPE_ARP:
                break;
 
        case ETHERTYPE_ARP:
-               arpinput((struct arpcom *)ifp, m);
-               return;
+               schednetisr(NETISR_ARP);
+               inq = &arpintrq;
+               break;
 #endif
 #ifdef NS
        case ETHERTYPE_NS:
 #endif
 #ifdef NS
        case ETHERTYPE_NS:
@@ -295,6 +302,8 @@ ether_input(ifp, eh, m)
                    if ((l->llc_dsap == LLC_ISO_LSAP) &&
                        (l->llc_ssap == LLC_ISO_LSAP)) {
                                /* LSAP for ISO */
                    if ((l->llc_dsap == LLC_ISO_LSAP) &&
                        (l->llc_ssap == LLC_ISO_LSAP)) {
                                /* LSAP for ISO */
+                       if (m->m_pkthdr.len > eh->ether_type)
+                               m_adj(m, eh->ether_type - m->m_pkthdr.len);
                        m->m_data += 3;         /* XXX */
                        m->m_len -= 3;          /* XXX */
                        m->m_pkthdr.len -= 3;   /* XXX */
                        m->m_data += 3;         /* XXX */
                        m->m_len -= 3;          /* XXX */
                        m->m_pkthdr.len -= 3;   /* XXX */