home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / net / if_ethersubr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-06  |  10.7 KB  |  418 lines

  1. /*
  2.  * Copyright (c) 1982, 1989 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  *    @(#)if_ethersubr.c    7.13 (Berkeley) 4/20/91
  34.  */
  35.  
  36. #include "param.h"
  37. #include "systm.h"
  38. #include "kernel.h"
  39. #include "malloc.h"
  40. #include "mbuf.h"
  41. #include "protosw.h"
  42. #include "socket.h"
  43. #include "ioctl.h"
  44. #include "errno.h"
  45. #include "syslog.h"
  46.  
  47. #include "if.h"
  48. #include "netisr.h"
  49. #include "route.h"
  50. #include "if_llc.h"
  51. #include "if_dl.h"
  52.  
  53. #include "machine/mtpr.h"
  54.  
  55. #ifdef INET
  56. #include "../netinet/in.h"
  57. #include "../netinet/in_var.h"
  58. #endif
  59. #include "../netinet/if_ether.h"
  60.  
  61. #ifdef NS
  62. #include "../netns/ns.h"
  63. #include "../netns/ns_if.h"
  64. #endif
  65.  
  66. #ifdef ISO
  67. #include "../netiso/argo_debug.h"
  68. #include "../netiso/iso.h"
  69. #include "../netiso/iso_var.h"
  70. #include "../netiso/iso_snpac.h"
  71. #endif
  72.  
  73. u_char    etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  74. extern    struct ifnet loif;
  75.  
  76. /*
  77.  * Ethernet output routine.
  78.  * Encapsulate a packet of type family for the local net.
  79.  * Use trailer local net encapsulation if enough data in first
  80.  * packet leaves a multiple of 512 bytes of data in remainder.
  81.  * Assumes that ifp is actually pointer to arpcom structure.
  82.  */
  83. ether_output(ifp, m0, dst, rt)
  84.     register struct ifnet *ifp;
  85.     struct mbuf *m0;
  86.     struct sockaddr *dst;
  87.     struct rtentry *rt;
  88. {
  89.     short type;
  90.     int s, error = 0;
  91.      u_char edst[6];
  92.     struct in_addr idst;
  93.     register struct mbuf *m = m0;
  94.     struct mbuf *mcopy = (struct mbuf *)0;
  95.     register struct ether_header *eh;
  96.     int usetrailers, off, len = m->m_pkthdr.len;
  97. #define    ac ((struct arpcom *)ifp)
  98.  
  99.     if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
  100.         error = ENETDOWN;
  101.         goto bad;
  102.     }
  103.     ifp->if_lastchange = time;
  104.     switch (dst->sa_family) {
  105.  
  106. #ifdef INET
  107.     case AF_INET:
  108.         idst = ((struct sockaddr_in *)dst)->sin_addr;
  109.          if (!arpresolve(ac, m, &idst, edst, &usetrailers))
  110.             return (0);    /* if not yet resolved */
  111.         if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
  112.             mcopy = m_copy(m, 0, (int)M_COPYALL);
  113.         off = m->m_pkthdr.len - m->m_len;
  114.         if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
  115.             (m->m_flags & M_EXT) == 0 &&
  116.             m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
  117.             type = ETHERTYPE_TRAIL + (off>>9);
  118.             m->m_data -= 2 * sizeof (u_short);
  119.             m->m_len += 2 * sizeof (u_short);
  120.             len += 2 * sizeof (u_short);
  121.             *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
  122.             *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
  123.             goto gottrailertype;
  124.         }
  125.         type = ETHERTYPE_IP;
  126.         goto gottype;
  127. #endif
  128. #ifdef NS
  129.     case AF_NS:
  130.         type = ETHERTYPE_NS;
  131.          bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
  132.             (caddr_t)edst, sizeof (edst));
  133.         if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
  134.             return (looutput(ifp, m, dst, rt));
  135.         if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
  136.             mcopy = m_copy(m, 0, (int)M_COPYALL);
  137.         goto gottype;
  138. #endif
  139. #ifdef    ISO
  140.     case AF_ISO: {
  141.         int    snpalen;
  142.         struct    llc *l;
  143.  
  144.     iso_again:
  145.         if (rt && rt->rt_gateway && (rt->rt_flags & RTF_UP)) {
  146.             if (rt->rt_flags & RTF_GATEWAY) {
  147.                 if (rt->rt_llinfo) {
  148.                     rt = (struct rtentry *)rt->rt_llinfo;
  149.                     goto iso_again;
  150.                 }
  151.             } else {
  152.                 register struct sockaddr_dl *sdl = 
  153.                     (struct sockaddr_dl *)rt->rt_gateway;
  154.                 if (sdl && sdl->sdl_family == AF_LINK
  155.                     && sdl->sdl_alen > 0) {
  156.                     bcopy(LLADDR(sdl), (char *)edst,
  157.                                 sizeof(edst));
  158.                     goto iso_resolved;
  159.                 }
  160.             }
  161.         }
  162.         if ((error = iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
  163.                     (char *)edst, &snpalen)) > 0)
  164.             goto bad; /* Not Resolved */
  165.     iso_resolved:
  166.         if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) &&
  167.             (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
  168.             M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
  169.             if (mcopy) {
  170.                 eh = mtod(mcopy, struct ether_header *);
  171.                 bcopy((caddr_t)edst,
  172.                       (caddr_t)eh->ether_dhost, sizeof (edst));
  173.                 bcopy((caddr_t)ac->ac_enaddr,
  174.                       (caddr_t)eh->ether_shost, sizeof (edst));
  175.             }
  176.         }
  177.         M_PREPEND(m, 3, M_DONTWAIT);
  178.         if (m == NULL)
  179.             return (0);
  180.         type = m->m_pkthdr.len;
  181.         l = mtod(m, struct llc *);
  182.         l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
  183.         l->llc_control = LLC_UI;
  184.         len += 3;
  185.         IFDEBUG(D_ETHER)
  186.             int i;
  187.             printf("unoutput: sending pkt to: ");
  188.             for (i=0; i<6; i++)
  189.                 printf("%x ", edst[i] & 0xff);
  190.             printf("\n");
  191.         ENDDEBUG
  192.         } goto gottype;
  193. #endif    ISO
  194. #ifdef RMP
  195.     case AF_RMP:
  196.         /*
  197.          *  This is IEEE 802.3 -- the Ethernet `type' field is
  198.          *  really a `length' field.
  199.          */
  200.         type = m->m_len;
  201.          bcopy((caddr_t)dst->sa_data, (caddr_t)edst, sizeof(edst));
  202.         break;
  203. #endif
  204.  
  205.     case AF_UNSPEC:
  206.         eh = (struct ether_header *)dst->sa_data;
  207.          bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
  208.         type = eh->ether_type;
  209.         goto gottype;
  210.  
  211.     default:
  212.         printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
  213.             dst->sa_family);
  214.         error = EAFNOSUPPORT;
  215.         goto bad;
  216.     }
  217.  
  218. gottrailertype:
  219.     /*
  220.      * Packet to be sent as trailer: move first packet
  221.      * (control information) to end of chain.
  222.      */
  223.     while (m->m_next)
  224.         m = m->m_next;
  225.     m->m_next = m0;
  226.     m = m0->m_next;
  227.     m0->m_next = 0;
  228.  
  229. gottype:
  230.     if (mcopy)
  231.         (void) looutput(ifp, mcopy, dst, rt);
  232.     /*
  233.      * Add local net header.  If no space in first mbuf,
  234.      * allocate another.
  235.      */
  236.     M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
  237.     if (m == 0) {
  238.         error = ENOBUFS;
  239.         goto bad;
  240.     }
  241.     eh = mtod(m, struct ether_header *);
  242.     type = htons((u_short)type);
  243.     bcopy((caddr_t)&type,(caddr_t)&eh->ether_type,
  244.         sizeof(eh->ether_type));
  245.      bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
  246.      bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
  247.         sizeof(eh->ether_shost));
  248.     s = splimp();
  249.     /*
  250.      * Queue message on interface, and start output if interface
  251.      * not yet active.
  252.      */
  253.     if (IF_QFULL(&ifp->if_snd)) {
  254.         IF_DROP(&ifp->if_snd);
  255.         splx(s);
  256.         error = ENOBUFS;
  257.         goto bad;
  258.     }
  259.     IF_ENQUEUE(&ifp->if_snd, m);
  260.     if ((ifp->if_flags & IFF_OACTIVE) == 0)
  261.         (*ifp->if_start)(ifp);
  262.     splx(s);
  263.     ifp->if_obytes += len + sizeof (struct ether_header);
  264.     if (edst[0] & 1)
  265.         ifp->if_omcasts++;
  266.     return (error);
  267.  
  268. bad:
  269.     if (m)
  270.         m_freem(m);
  271.     return (error);
  272. }
  273.  
  274. /*
  275.  * Process a received Ethernet packet;
  276.  * the packet is in the mbuf chain m without
  277.  * the ether header, which is provided separately.
  278.  */
  279. ether_input(ifp, eh, m)
  280.     struct ifnet *ifp;
  281.     register struct ether_header *eh;
  282.     struct mbuf *m;
  283. {
  284.     register struct ifqueue *inq;
  285.     register struct llc *l;
  286.     int s;
  287.  
  288.     ifp->if_lastchange = time;
  289.     ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
  290.     if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
  291.         sizeof(etherbroadcastaddr)) == 0)
  292.         m->m_flags |= M_BCAST;
  293.     else if (eh->ether_dhost[0] & 1)
  294.         m->m_flags |= M_MCAST;
  295.     if (m->m_flags & (M_BCAST|M_MCAST))
  296.         ifp->if_imcasts++;
  297.  
  298.     switch (eh->ether_type) {
  299. #ifdef INET
  300.     case ETHERTYPE_IP:
  301.         schednetisr(NETISR_IP);
  302.         inq = &ipintrq;
  303.         break;
  304.  
  305.     case ETHERTYPE_ARP:
  306.         arpinput((struct arpcom *)ifp, m);
  307.         return;
  308. #endif
  309. #ifdef NS
  310.     case ETHERTYPE_NS:
  311.         schednetisr(NETISR_NS);
  312.         inq = &nsintrq;
  313.         break;
  314.  
  315. #endif
  316.     default:
  317. #ifdef    ISO
  318.         if (eh->ether_type > ETHERMTU)
  319.             goto dropanyway;
  320.         l = mtod(m, struct llc *);
  321.         switch (l->llc_control) {
  322.         case LLC_UI:
  323.         /* LLC_UI_P forbidden in class 1 service */
  324.             if ((l->llc_dsap == LLC_ISO_LSAP) &&
  325.             (l->llc_ssap == LLC_ISO_LSAP)) {
  326.                 /* LSAP for ISO */
  327.             if (m->m_pkthdr.len > eh->ether_type)
  328.                 m_adj(m, eh->ether_type - m->m_pkthdr.len);
  329.             m->m_data += 3;        /* XXX */
  330.             m->m_len -= 3;        /* XXX */
  331.             m->m_pkthdr.len -= 3;    /* XXX */
  332.             M_PREPEND(m, sizeof *eh, M_DONTWAIT);
  333.             if (m == 0)
  334.                 return;
  335.             *mtod(m, struct ether_header *) = *eh;
  336.             IFDEBUG(D_ETHER)
  337.                 printf("clnp packet");
  338.             ENDDEBUG
  339.             schednetisr(NETISR_ISO);
  340.             inq = &clnlintrq;
  341.             break;
  342.             }
  343.             goto dropanyway;
  344.  
  345.         case LLC_XID:
  346.         case LLC_XID_P:
  347.             if(m->m_len < 6)
  348.             goto dropanyway;
  349.             l->llc_window = 0;
  350.             l->llc_fid = 9;
  351.             l->llc_class = 1;
  352.             l->llc_dsap = l->llc_ssap = 0;
  353.             /* Fall through to */
  354.         case LLC_TEST:
  355.         case LLC_TEST_P:
  356.         {
  357.             struct sockaddr sa;
  358.             register struct ether_header *eh2;
  359.             int i;
  360.             u_char c = l->llc_dsap;
  361.             l->llc_dsap = l->llc_ssap;
  362.             l->llc_ssap = c;
  363.             if (m->m_flags & (M_BCAST | M_MCAST))
  364.             bcopy((caddr_t)ac->ac_enaddr,
  365.                   (caddr_t)eh->ether_dhost, 6);
  366.             sa.sa_family = AF_UNSPEC;
  367.             sa.sa_len = sizeof(sa);
  368.             eh2 = (struct ether_header *)sa.sa_data;
  369.             for (i = 0; i < 6; i++) {
  370.             eh2->ether_shost[i] = c = eh->ether_dhost[i];
  371.             eh2->ether_dhost[i] = 
  372.                 eh->ether_dhost[i] = eh->ether_shost[i];
  373.             eh->ether_shost[i] = c;
  374.             }
  375.             ifp->if_output(ifp, m, &sa);
  376.             return;
  377.         }
  378.         dropanyway:
  379.         default:
  380.             m_freem(m);
  381.             return;
  382.         }
  383. #else
  384.         m_freem(m);
  385.         return;
  386. #endif    ISO
  387.     }
  388.  
  389.     s = splimp();
  390.     if (IF_QFULL(inq)) {
  391.         IF_DROP(inq);
  392.         m_freem(m);
  393.     } else
  394.         IF_ENQUEUE(inq, m);
  395.     splx(s);
  396. }
  397.  
  398. /*
  399.  * Convert Ethernet address to printable (loggable) representation.
  400.  */
  401. static char digits[] = "0123456789abcdef";
  402. char *
  403. ether_sprintf(ap)
  404.     register u_char *ap;
  405. {
  406.     register i;
  407.     static char etherbuf[18];
  408.     register char *cp = etherbuf;
  409.  
  410.     for (i = 0; i < 6; i++) {
  411.         *cp++ = digits[*ap >> 4];
  412.         *cp++ = digits[*ap++ & 0xf];
  413.         *cp++ = ':';
  414.     }
  415.     *--cp = 0;
  416.     return (etherbuf);
  417. }
  418.