start routines can't reliably return errors;fix bug in ISO processing;
[unix-history] / usr / src / sys / net / if_ethersubr.c
index 92e4460..02109b1 100644 (file)
@@ -14,7 +14,7 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- *     @(#)if_ethersubr.c      1.1 (Berkeley) %G%
+ *     @(#)if_ethersubr.c      7.4 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -30,8 +30,9 @@
 #include "if.h"
 #include "netisr.h"
 #include "route.h"
 #include "if.h"
 #include "netisr.h"
 #include "route.h"
+#include "if_llc.h"
 
 
-#include "../machine/mtpr.h"
+#include "machine/mtpr.h"
 
 #ifdef INET
 #include "../netinet/in.h"
 
 #ifdef INET
 #include "../netinet/in.h"
 #include "../netns/ns_if.h"
 #endif
 
 #include "../netns/ns_if.h"
 #endif
 
+#ifdef ISO
+#include "../netiso/argo_debug.h"
+#include "../netiso/iso.h"
+#include "../netiso/iso_var.h"
+#endif
+
 u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+extern struct ifnet loif;
 
 /*
  * Ethernet output routine.
 
 /*
  * Ethernet output routine.
@@ -53,24 +61,28 @@ u_char      etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  * 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.
  */
-enoutput(ifp, m0, dst)
+ether_output(ifp, m0, dst)
        register struct ifnet *ifp;
        struct mbuf *m0;
        struct sockaddr *dst;
 {
        register struct ifnet *ifp;
        struct mbuf *m0;
        struct sockaddr *dst;
 {
-       int type, s, error;
+       short type;
+       int s, error = 0;
        u_char edst[6];
        struct in_addr idst;
        register struct mbuf *m = m0;
        u_char edst[6];
        struct in_addr idst;
        register struct mbuf *m = m0;
+       struct mbuf *mcopy = (struct mbuf *)0;
        register struct ether_header *eh;
        register struct ether_header *eh;
-       register int off;
-       int usetrailers;
+       int usetrailers, off;
 #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);
        switch (dst->sa_family) {
 
 #ifdef INET
        switch (dst->sa_family) {
 
 #ifdef INET
@@ -78,6 +90,8 @@ enoutput(ifp, m0, dst)
                idst = ((struct sockaddr_in *)dst)->sin_addr;
                if (!arpresolve(ac, m, &idst, edst, &usetrailers))
                        return (0);     /* if not yet resolved */
                idst = ((struct sockaddr_in *)dst)->sin_addr;
                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);
                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 &&
@@ -90,18 +104,49 @@ enoutput(ifp, m0, dst)
                        goto gottrailertype;
                }
                type = ETHERTYPE_IP;
                        goto gottrailertype;
                }
                type = ETHERTYPE_IP;
-               off = 0;
                goto gottype;
 #endif
 #ifdef NS
        case AF_NS:
                type = ETHERTYPE_NS;
                goto gottype;
 #endif
 #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),
                bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
-               (caddr_t)edst, sizeof (edst));
-               off = 0;
+                   (caddr_t)edst, sizeof (edst));
+               if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
+                   mcopy = m_copy(m, 0, (int)M_COPYALL);
                goto gottype;
 #endif
                goto gottype;
 #endif
+#ifdef ISO
+       case AF_ISO: {
+               int     len;
+               int     ret;
+               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);
+               }
+               M_PREPEND(m, 3, M_DONTWAIT);
+               if (m == NULL)
+                       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;
+               IFDEBUG(D_ETHER)
+                       int i;
+                       printf("unoutput: sending pkt to: ");
+                       for (i=0; i<6; i++)
+                               printf("%x ", edst[i] & 0xff);
+                       printf("\n");
+               ENDDEBUG
+               } goto gottype;
+#endif ISO
        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));
@@ -125,7 +170,6 @@ gottrailertype:
        m->m_next = m0;
        m = m0->m_next;
        m0->m_next = 0;
        m->m_next = m0;
        m = m0->m_next;
        m0->m_next = 0;
-       m0 = m;
 
 gottype:
        /*
 
 gottype:
        /*
@@ -138,11 +182,12 @@ gottype:
                goto bad;
        }
        eh = mtod(m, struct ether_header *);
                goto bad;
        }
        eh = mtod(m, struct ether_header *);
-       eh->ether_type = htons((u_short)type);
+       type = htons((u_short)type);
+       bcopy((caddr_t)&type,(caddr_t)&eh->ether_type,
+               sizeof(eh->ether_type));
        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));
-
        /*
         * Queue message on interface, and start output if interface
         * not yet active.
        /*
         * Queue message on interface, and start output if interface
         * not yet active.
@@ -151,36 +196,44 @@ gottype:
        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);
-               m_freem(m);
-               return (ENOBUFS);
+               error = ENOBUFS;
+               goto bad;
        }
        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)
-               (*ifp->if_start)(ifp->if_unit);
+               (*ifp->if_start)(ifp);
        splx(s);
        splx(s);
-       return (0);
+       if (mcopy)
+               (void) looutput(&loif, mcopy, dst);
+       return (error);
 
 bad:
 
 bad:
-       m_freem(m0);
+       if (mcopy)
+               m_freem(mcopy);
+       if (m)
+               m_freem(m);
        return (error);
 }
 
 /*
        return (error);
 }
 
 /*
- * 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.
  */
  */
-en_doproto(ifp, eh, m)
+ether_input(ifp, eh, m)
        struct ifnet *ifp;
        register struct ether_header *eh;
        struct mbuf *m;
 {
        register struct ifqueue *inq;
        struct ifnet *ifp;
        register struct ether_header *eh;
        struct mbuf *m;
 {
        register struct ifqueue *inq;
+       register struct llc *l;
        int s;
 
        int s;
 
-       if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_shost,
+       if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
            sizeof(etherbroadcastaddr)) == 0)
                m->m_flags |= M_BCAST;
            sizeof(etherbroadcastaddr)) == 0)
                m->m_flags |= M_BCAST;
+       else if (eh->ether_dhost[0] & 1)
+               m->m_flags |= M_MCAST;
 
        switch (eh->ether_type) {
 #ifdef INET
 
        switch (eh->ether_type) {
 #ifdef INET
@@ -201,8 +254,74 @@ en_doproto(ifp, eh, m)
 
 #endif
        default:
 
 #endif
        default:
-               m_freem(m);
-               return;
+#ifdef ISO
+               if (eh->ether_type > ETHERMTU)
+                       goto dropanyway;
+               l = mtod(m, struct llc *);
+               switch (l->llc_control) {
+               case LLC_UI:
+               /* LLC_UI_P forbidden in class 1 service */
+                   if ((l->llc_dsap == LLC_ISO_LSAP) &&
+                       (l->llc_ssap == LLC_ISO_LSAP)) {
+                               /* 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;
+                       *mtod(m, struct ether_header *) = *eh;
+                       IFDEBUG(D_ETHER)
+                           printf("clnp packet");
+                       ENDDEBUG
+                       schednetisr(NETISR_ISO);
+                       inq = &clnlintrq;
+                       break;
+                   }
+                   goto dropanyway;
+
+               case LLC_XID:
+               case LLC_XID_P:
+                   if(m->m_len < 6)
+                       goto dropanyway;
+                   l->llc_window = 0;
+                   l->llc_fid = 9;
+                   l->llc_class = 1;
+                   l->llc_dsap = l->llc_ssap = 0;
+                   /* Fall through to */
+               case LLC_TEST:
+               case LLC_TEST_P:
+               {
+                   struct sockaddr sa;
+                   register struct ether_header *eh2;
+                   int i;
+                   u_char c = l->llc_dsap;
+                   l->llc_dsap = l->llc_ssap;
+                   l->llc_ssap = c;
+                   if (m->m_flags & (M_BCAST | M_MCAST))
+                       bcopy((caddr_t)ac->ac_enaddr,
+                             (caddr_t)eh->ether_dhost, 6);
+                   sa.sa_family = AF_UNSPEC;
+                   sa.sa_len = sizeof(sa);
+                   eh2 = (struct ether_header *)sa.sa_data;
+                   for (i = 0; i < 6; i++) {
+                       eh2->ether_shost[i] = c = eh->ether_dhost[i];
+                       eh2->ether_dhost[i] = 
+                               eh->ether_dhost[i] = eh->ether_shost[i];
+                       eh->ether_shost[i] = c;
+                   }
+                   ifp->if_output(ifp, m, &sa);
+                   return;
+               }
+               dropanyway:
+               default:
+                   m_freem(m);
+                   return;
+           }
+#else
+           m_freem(m);
+           return;
+#endif ISO
        }
 
        s = splimp();
        }
 
        s = splimp();
@@ -217,6 +336,7 @@ en_doproto(ifp, eh, m)
 /*
  * Convert Ethernet address to printable (loggable) representation.
  */
 /*
  * Convert Ethernet address to printable (loggable) representation.
  */
+static char digits[] = "0123456789abcdef";
 char *
 ether_sprintf(ap)
        register u_char *ap;
 char *
 ether_sprintf(ap)
        register u_char *ap;
@@ -224,7 +344,6 @@ ether_sprintf(ap)
        register i;
        static char etherbuf[18];
        register char *cp = etherbuf;
        register i;
        static char etherbuf[18];
        register char *cp = etherbuf;
-       static char digits[] = "0123456789abcdef";
 
        for (i = 0; i < 6; i++) {
                *cp++ = digits[*ap >> 4];
 
        for (i = 0; i < 6; i++) {
                *cp++ = digits[*ap >> 4];