The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/if_iso88025subr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1998, Larry Lile
    3  * All rights reserved.
    4  *
    5  * For latest sources and information on this driver, please
    6  * go to http://anarchy.stdio.com.
    7  *
    8  * Questions, comments or suggestions should be directed to
    9  * Larry Lile <lile@stdio.com>.
   10  * 
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice unmodified, this list of conditions, and the following
   16  *    disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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  * $FreeBSD$
   34  *
   35  */
   36 
   37 /*
   38  *
   39  * General ISO 802.5 (Token Ring) support routines
   40  * 
   41  */
   42 
   43 #include "opt_inet.h"
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/kernel.h>
   48 #include <sys/malloc.h>
   49 #include <sys/mbuf.h>
   50 #include <sys/socket.h>
   51 #include <sys/sockio.h> 
   52 #include <sys/sysctl.h>
   53 
   54 #include <net/if.h>
   55 #include <net/netisr.h>
   56 #include <net/route.h>
   57 #include <net/if_llc.h>
   58 #include <net/if_dl.h>
   59 #include <net/if_types.h>
   60 
   61 #include <net/if_arp.h>
   62 
   63 #include <net/iso88025.h>
   64 
   65 #ifdef INET
   66 #include <netinet/in.h>
   67 #include <netinet/in_var.h>
   68 #include <netinet/if_ether.h>
   69 #endif
   70 
   71 #if NBPFILTER > 0
   72 #include <net/bpf.h>
   73 #include <net/bpfdesc.h>
   74 #endif
   75 
   76 #include <machine/clock.h>
   77 #include <machine/md_var.h>
   78 
   79 #include <i386/isa/isa_device.h>
   80 
   81 #include <vm/vm.h>
   82 #include <vm/vm_param.h>
   83 #include <vm/pmap.h>
   84 
   85 #include <sys/kernel.h>
   86 #include <net/iso88025.h>
   87 
   88 void
   89 iso88025_ifattach(ifp)
   90     register struct ifnet *ifp;
   91 {
   92     register struct ifaddr *ifa = NULL;
   93     register struct sockaddr_dl *sdl;
   94 
   95     ifp->if_type = IFT_ISO88025;
   96     ifp->if_addrlen = 6;
   97     ifp->if_hdrlen=18;
   98     if (ifp->if_baudrate == 0)
   99         ifp->if_baudrate = 16000000; /* 1, 4, or 16Mbit default? */
  100     if (ifp->if_mtu == 0)
  101         ifp->if_mtu = ISO88025_DEFAULT_MTU;
  102 
  103         ifa = ifnet_addrs[ifp->if_index - 1];
  104         if (ifa == 0) {
  105                 printf("iso88025_ifattach: no lladdr!\n");
  106                 return;
  107         }
  108         sdl = (struct sockaddr_dl *)ifa->ifa_addr;
  109         sdl->sdl_type = IFT_ISO88025;
  110         sdl->sdl_alen = ifp->if_addrlen;
  111         bcopy(((struct arpcom *)ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
  112 }
  113 
  114 int
  115 iso88025_ioctl(struct ifnet *ifp, int command, caddr_t data)
  116 {
  117         struct ifaddr *ifa = (struct ifaddr *) data;
  118         struct ifreq *ifr = (struct ifreq *) data;
  119         int error = 0;
  120 
  121         switch (command) {
  122         case SIOCSIFADDR:
  123                 ifp->if_flags |= IFF_UP;
  124 
  125                 switch (ifa->ifa_addr->sa_family) {
  126 #ifdef INET
  127                 case AF_INET:
  128                         ifp->if_init(ifp->if_softc);    /* before arpwhohas */
  129                         arp_ifinit((struct arpcom *)ifp, ifa);
  130                         break;
  131 #endif
  132                 default:
  133                         ifp->if_init(ifp->if_softc);
  134                         break;
  135                 }
  136                 break;
  137 
  138         case SIOCGIFADDR:
  139                 {
  140                         struct sockaddr *sa;
  141 
  142                         sa = (struct sockaddr *) & ifr->ifr_data;
  143                         bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr,
  144                               (caddr_t) sa->sa_data, ISO88025_ADDR_LEN);
  145                 }
  146                 break;
  147 
  148         case SIOCSIFMTU:
  149                 /*
  150                  * Set the interface MTU.
  151                  */
  152                 if (ifr->ifr_mtu > ISO88025MTU) {
  153                         error = EINVAL;
  154                 } else {
  155                         ifp->if_mtu = ifr->ifr_mtu;
  156                 }
  157                 break;
  158         }
  159         return (error);
  160 }
  161 
  162 /*
  163  * ISO88025 encapsulation
  164  */
  165 int
  166 iso88025_output(ifp, m0, dst, rt0)
  167         register struct ifnet *ifp;
  168         struct mbuf *m0;
  169         struct sockaddr *dst;
  170         struct rtentry *rt0;
  171 {
  172         register struct iso88025_header *th;
  173         struct iso88025_header gen_th;
  174         register struct iso88025_sockaddr_data *sd = (struct iso88025_sockaddr_data *)dst->sa_data;
  175         register struct llc *l;
  176         register struct sockaddr_dl *sdl = NULL;
  177         int s, error = 0, rif_len = 0;
  178         u_char edst[6];
  179         register struct mbuf *m = m0;
  180         register struct rtentry *rt;
  181         int len = m->m_pkthdr.len, loop_copy = 0;
  182         struct arpcom *ac = (struct arpcom *)ifp;
  183 
  184         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
  185                 senderr(ENETDOWN);
  186         rt = rt0;
  187         if (rt) {
  188                 if ((rt->rt_flags & RTF_UP) == 0) {
  189                         rt0 = rt = rtalloc1(dst, 1, 0UL);
  190                         if (rt0)
  191                                 rt->rt_refcnt--;
  192                         else
  193                                 senderr(EHOSTUNREACH);
  194                 }
  195                 if (rt->rt_flags & RTF_GATEWAY) {
  196                         if (rt->rt_gwroute == 0)
  197                                 goto lookup;
  198                         if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
  199                                 rtfree(rt); rt = rt0;
  200                         lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1,
  201                                                           0UL);
  202                                 if ((rt = rt->rt_gwroute) == 0)
  203                                         senderr(EHOSTUNREACH);
  204                         }
  205                 }
  206                 if (rt->rt_flags & RTF_REJECT)
  207                         if (rt->rt_rmx.rmx_expire == 0 ||
  208                             time_second < rt->rt_rmx.rmx_expire)
  209                                 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
  210         }
  211 
  212         /* Calculate routing info length based on arp table entry */
  213         if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway))
  214                 if (sdl->sdl_rcf != NULL)
  215                         rif_len = (ntohs(sdl->sdl_rcf) & 0x1f00) >> 8;
  216 
  217         /* Generate a generic 802.5 header for the packet */
  218         gen_th.ac = 0x10;
  219         gen_th.fc = 0x40;
  220         memcpy(gen_th.iso88025_shost, ac->ac_enaddr, sizeof(ac->ac_enaddr));
  221         if (rif_len) {
  222                 gen_th.iso88025_shost[0] |= 0x80;
  223                 if (rif_len > 2) {
  224                         gen_th.rcf = sdl->sdl_rcf;
  225                         memcpy(gen_th.rseg, sdl->sdl_route, rif_len - 2);
  226                 }
  227         }
  228         
  229 
  230         switch (dst->sa_family) {
  231 #ifdef INET
  232         case AF_INET:
  233                 if (!arpresolve(ac, rt, m, dst, edst, rt0))
  234                         return (0);     /* if not yet resolved */
  235                 /* Add LLC and SNAP headers */
  236                 M_PREPEND(m, 8, M_DONTWAIT);
  237                 if (m == 0)
  238                         senderr(ENOBUFS);
  239                 l = mtod(m, struct llc *);
  240                 l->llc_un.type_snap.ether_type = htons(ETHERTYPE_IP);
  241                 l->llc_dsap = 0xaa;
  242                 l->llc_ssap = 0xaa;
  243                 l->llc_un.type_snap.control = 0x3;
  244                 l->llc_un.type_snap.org_code[0] = 0x0;
  245                 l->llc_un.type_snap.org_code[1] = 0x0;
  246                 l->llc_un.type_snap.org_code[2] = 0x0;
  247                 memcpy(gen_th.iso88025_dhost, edst, sizeof(edst));
  248                 break;
  249 #endif
  250 
  251         case AF_UNSPEC:
  252                 /*
  253                  * For AF_UNSPEC sockaddr.sa_data must contain all of the
  254                  * mac information needed to send the packet.  This allows
  255                  * full mac, llc, and source routing function to be controlled.
  256                  * llc and source routing information must already be in the
  257                  * mbuf provided, ac/fc are set in sa_data.  sockaddr.sa_data
  258                  * should be a iso88025_sockaddr_data structure see iso88025.h
  259                  */
  260                 loop_copy = -1;
  261                 sd = (struct iso88025_sockaddr_data *)dst->sa_data;
  262                 gen_th.ac = sd->ac;
  263                 gen_th.fc = sd->fc;
  264                 memcpy(gen_th.iso88025_dhost, sd->ether_dhost, sizeof(sd->ether_dhost));
  265                 memcpy(gen_th.iso88025_shost, sd->ether_shost, sizeof(sd->ether_shost));
  266                 rif_len = 0;
  267                 break;
  268 
  269         default:
  270                 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
  271                         dst->sa_family);
  272                 senderr(EAFNOSUPPORT);
  273         }
  274 
  275         /*
  276          * Add local net header.  If no space in first mbuf,
  277          * allocate another.
  278          */
  279         
  280         M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_DONTWAIT);
  281         if (m == 0)
  282                 senderr(ENOBUFS);
  283 
  284         /* Copy as much of the generic header as is needed into the mbuf */
  285         th = mtod(m, struct iso88025_header *);
  286         memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len);
  287 
  288         /*
  289          * If a simplex interface, and the packet is being sent to our
  290          * Ethernet address or a broadcast address, loopback a copy.
  291          * XXX To make a simplex device behave exactly like a duplex
  292          * device, we should copy in the case of sending to our own
  293          * ethernet address (thus letting the original actually appear
  294          * on the wire). However, we don't do that here for security
  295          * reasons and compatibility with the original behavior.
  296          */     
  297         if ((ifp->if_flags & IFF_SIMPLEX) &&
  298            (loop_copy != -1)) {
  299                 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 
  300                         struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
  301                         /*printf("iso88025_output: if_simloop broadcast.\n");*/
  302                         (void) if_simloop(ifp, n, dst, ISO88025_HDR_LEN);
  303                 } else if (bcmp(th->iso88025_dhost,
  304                     th->iso88025_shost, ETHER_ADDR_LEN) == 0) {
  305                         /*printf("iso88025_output: if_simloop to ourselves.\n");*/
  306                         (void) if_simloop(ifp, m, dst, ISO88025_HDR_LEN);
  307                         return(0);      /* XXX */
  308                 }       
  309         }      
  310 
  311         s = splimp();
  312         /*
  313          * Queue message on interface, and start output if interface
  314          * not yet active.
  315          */
  316         if (IF_QFULL(&ifp->if_snd)) {
  317             printf("iso88025_output: packet dropped QFULL.\n");
  318                 IF_DROP(&ifp->if_snd);
  319                 splx(s);
  320                 senderr(ENOBUFS);
  321         }
  322         IF_ENQUEUE(&ifp->if_snd, m);
  323         /*printf("iso88025_output: packet queued.\n");*/
  324         if ((ifp->if_flags & IFF_OACTIVE) == 0)
  325                 (*ifp->if_start)(ifp);
  326         splx(s);
  327         ifp->if_obytes += len + ISO88025_HDR_LEN + 8;
  328         if (m->m_flags & M_MCAST)
  329                 ifp->if_omcasts++;
  330         return (error);
  331 
  332 bad:
  333         if (m)
  334                 m_freem(m);
  335         /*printf("iso88025_output: something went wrong, bailing to bad.\n");*/
  336         return (error);
  337 }
  338 
  339 /*
  340  * ISO 88025 de-encapsulation
  341  */
  342 void
  343 iso88025_input(ifp, th, m)
  344         struct ifnet *ifp;
  345         register struct iso88025_header *th;
  346         struct mbuf *m;
  347 {
  348         register struct ifqueue *inq;
  349         u_short ether_type;
  350         int s;
  351         register struct llc *l = mtod(m, struct llc *);
  352 
  353         /*printf("iso88025_input: entered.\n");*/
  354 
  355         /*m->m_pkthdr.len = m->m_len = m->m_len - 8;*/ /* Length of LLC header in our case */
  356         m->m_pkthdr.len -= 8;
  357         m->m_len -= 8;
  358         m->m_data += 8; /* Length of LLC header in our case */
  359 
  360         if ((ifp->if_flags & IFF_UP) == 0) {
  361                 m_freem(m);
  362                 return;
  363         }
  364         ifp->if_ibytes += m->m_pkthdr.len + sizeof (*th);
  365         if (th->iso88025_dhost[0] & 1) {
  366                 if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)th->iso88025_dhost,
  367                          sizeof(etherbroadcastaddr)) == 0)
  368                         m->m_flags |= M_BCAST;
  369                 else
  370                         m->m_flags |= M_MCAST;
  371         } 
  372         if (m->m_flags & (M_BCAST|M_MCAST))
  373                 ifp->if_imcasts++;
  374 
  375         ether_type = ntohs(l->llc_un.type_snap.ether_type);
  376 
  377         /*printf("iso88025_input: source %6D dest %6D ethertype %x\n", th->iso88025_shost, ":", th->iso88025_dhost, ":", ether_type);*/
  378 
  379         switch (ether_type) {
  380 #ifdef INET
  381         case ETHERTYPE_IP:
  382             /*printf("iso88025_input: IP Packet\n");*/
  383                 th->iso88025_shost[0] &= ~(0x80); /* Turn off source route bit XXX */
  384                 if (ipflow_fastforward(m))
  385                         return;
  386                 schednetisr(NETISR_IP);
  387                 inq = &ipintrq;
  388                 break;
  389 
  390         case ETHERTYPE_ARP:
  391             /*printf("iso88025_input: ARP Packet\n");*/
  392                 schednetisr(NETISR_ARP);
  393                 inq = &arpintrq;
  394                 break;
  395 #endif
  396         default:
  397             m_freem(m);
  398             return;
  399         }
  400 
  401         s = splimp();
  402         if (IF_QFULL(inq)) {
  403                 IF_DROP(inq);
  404                 m_freem(m);
  405                 printf("iso88025_input: Packet dropped (Queue full).\n");
  406         } else
  407                 IF_ENQUEUE(inq, m);
  408                 /*printf("iso88025_input: Packet queued.\n");*/
  409         splx(s);
  410 }

Cache object: 73ddbaf9ff745fe348803a5b1934900e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.