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_gif.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 /*      $NetBSD: if_gif.c,v 1.44.2.2 2007/03/31 12:44:36 bouyer Exp $   */
    2 /*      $KAME: if_gif.c,v 1.76 2001/08/20 02:01:02 kjc Exp $    */
    3 
    4 /*
    5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the project nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.44.2.2 2007/03/31 12:44:36 bouyer Exp $");
   35 
   36 #include "opt_inet.h"
   37 #include "opt_iso.h"
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/kernel.h>
   42 #include <sys/mbuf.h>
   43 #include <sys/socket.h>
   44 #include <sys/sockio.h>
   45 #include <sys/errno.h>
   46 #include <sys/ioctl.h>
   47 #include <sys/time.h>
   48 #include <sys/syslog.h>
   49 #include <sys/proc.h>
   50 #include <sys/protosw.h>
   51 #include <machine/cpu.h>
   52 #include <machine/intr.h>
   53 
   54 #include <net/if.h>
   55 #include <net/if_types.h>
   56 #include <net/netisr.h>
   57 #include <net/route.h>
   58 #include <net/bpf.h>
   59 
   60 #include <netinet/in.h>
   61 #include <netinet/in_systm.h>
   62 #include <netinet/ip.h>
   63 #ifdef  INET
   64 #include <netinet/in_var.h>
   65 #include <netinet/in_gif.h>
   66 #endif  /* INET */
   67 
   68 #ifdef INET6
   69 #ifndef INET
   70 #include <netinet/in.h>
   71 #endif
   72 #include <netinet6/in6_var.h>
   73 #include <netinet/ip6.h>
   74 #include <netinet6/ip6_var.h>
   75 #include <netinet6/in6_gif.h>
   76 #include <netinet6/ip6protosw.h>
   77 #endif /* INET6 */
   78 
   79 #ifdef ISO
   80 #include <netiso/iso.h>
   81 #include <netiso/iso_var.h>
   82 #endif
   83 
   84 #include <netinet/ip_encap.h>
   85 #include <net/if_gif.h>
   86 
   87 #include "bpfilter.h"
   88 
   89 #include <net/net_osdep.h>
   90 
   91 void gifattach __P((int));
   92 #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
   93 void gifnetisr __P((void));
   94 #endif
   95 void gifintr __P((void *));
   96 #ifdef ISO
   97 static struct mbuf *gif_eon_encap __P((struct mbuf *));
   98 static struct mbuf *gif_eon_decap __P((struct ifnet *, struct mbuf *));
   99 #endif
  100 
  101 /*
  102  * gif global variable definitions
  103  */
  104 LIST_HEAD(, gif_softc) gif_softc_list;
  105 
  106 int     gif_clone_create __P((struct if_clone *, int));
  107 void    gif_clone_destroy __P((struct ifnet *));
  108 
  109 struct if_clone gif_cloner =
  110     IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
  111 
  112 #ifndef MAX_GIF_NEST
  113 /*
  114  * This macro controls the upper limitation on nesting of gif tunnels.
  115  * Since, setting a large value to this macro with a careless configuration
  116  * may introduce system crash, we don't allow any nestings by default.
  117  * If you need to configure nested gif tunnels, you can define this macro
  118  * in your kernel configuration file.  However, if you do so, please be
  119  * careful to configure the tunnels so that it won't make a loop.
  120  */
  121 #define MAX_GIF_NEST 1
  122 #endif
  123 static int max_gif_nesting = MAX_GIF_NEST;
  124 
  125 /* ARGSUSED */
  126 void
  127 gifattach(count)
  128         int count;
  129 {
  130 
  131         LIST_INIT(&gif_softc_list);
  132         if_clone_attach(&gif_cloner);
  133 }
  134 
  135 int
  136 gif_clone_create(ifc, unit)
  137         struct if_clone *ifc;
  138         int unit;
  139 {
  140         struct gif_softc *sc;
  141 
  142         sc = malloc(sizeof(struct gif_softc), M_DEVBUF, M_WAIT);
  143         memset(sc, 0, sizeof(struct gif_softc));
  144 
  145         sprintf(sc->gif_if.if_xname, "%s%d", ifc->ifc_name, unit);
  146 
  147         gifattach0(sc);
  148 
  149         LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
  150         return (0);
  151 }
  152 
  153 void
  154 gifattach0(sc)
  155         struct gif_softc *sc;
  156 {
  157 
  158         sc->encap_cookie4 = sc->encap_cookie6 = NULL;
  159 
  160         sc->gif_if.if_addrlen = 0;
  161         sc->gif_if.if_mtu    = GIF_MTU;
  162         sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
  163         sc->gif_if.if_ioctl  = gif_ioctl;
  164         sc->gif_if.if_output = gif_output;
  165         sc->gif_if.if_type   = IFT_GIF;
  166         sc->gif_if.if_dlt    = DLT_NULL;
  167         IFQ_SET_READY(&sc->gif_if.if_snd);
  168         if_attach(&sc->gif_if);
  169         if_alloc_sadl(&sc->gif_if);
  170 #if NBPFILTER > 0
  171         bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
  172 #endif
  173 }
  174 
  175 void
  176 gif_clone_destroy(ifp)
  177         struct ifnet *ifp;
  178 {
  179         struct gif_softc *sc = (void *) ifp;
  180 
  181         gif_delete_tunnel(&sc->gif_if);
  182         LIST_REMOVE(sc, gif_list);
  183 #ifdef INET6
  184         encap_detach(sc->encap_cookie6);
  185 #endif
  186 #ifdef INET
  187         encap_detach(sc->encap_cookie4);
  188 #endif
  189 
  190 #if NBPFILTER > 0
  191         bpfdetach(ifp);
  192 #endif
  193         if_detach(ifp);
  194 
  195         free(sc, M_DEVBUF);
  196 }
  197 
  198 #ifdef GIF_ENCAPCHECK
  199 int
  200 gif_encapcheck(m, off, proto, arg)
  201         const struct mbuf *m;
  202         int off;
  203         int proto;
  204         void *arg;
  205 {
  206         struct ip ip;
  207         struct gif_softc *sc;
  208 
  209         sc = (struct gif_softc *)arg;
  210         if (sc == NULL)
  211                 return 0;
  212 
  213         if ((sc->gif_if.if_flags & IFF_UP) == 0)
  214                 return 0;
  215 
  216         /* no physical address */
  217         if (!sc->gif_psrc || !sc->gif_pdst)
  218                 return 0;
  219 
  220         switch (proto) {
  221 #ifdef INET
  222         case IPPROTO_IPV4:
  223                 break;
  224 #endif
  225 #ifdef INET6
  226         case IPPROTO_IPV6:
  227                 break;
  228 #endif
  229 #ifdef ISO
  230         case IPPROTO_EON:
  231                 break;
  232 #endif
  233         default:
  234                 return 0;
  235         }
  236 
  237         /* Bail on short packets */
  238         KASSERT(m->m_flags & M_PKTHDR);
  239         if (m->m_pkthdr.len < sizeof(ip))
  240                 return 0;
  241 
  242         /* LINTED const cast */
  243         m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
  244 
  245         switch (ip.ip_v) {
  246 #ifdef INET
  247         case 4:
  248                 if (sc->gif_psrc->sa_family != AF_INET ||
  249                     sc->gif_pdst->sa_family != AF_INET)
  250                         return 0;
  251                 return gif_encapcheck4(m, off, proto, arg);
  252 #endif
  253 #ifdef INET6
  254         case 6:
  255                 if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
  256                         return 0;
  257                 if (sc->gif_psrc->sa_family != AF_INET6 ||
  258                     sc->gif_pdst->sa_family != AF_INET6)
  259                         return 0;
  260                 return gif_encapcheck6(m, off, proto, arg);
  261 #endif
  262         default:
  263                 return 0;
  264         }
  265 }
  266 #endif
  267 
  268 int
  269 gif_output(ifp, m, dst, rt)
  270         struct ifnet *ifp;
  271         struct mbuf *m;
  272         struct sockaddr *dst;
  273         struct rtentry *rt;     /* added in net2 */
  274 {
  275         struct gif_softc *sc = (struct gif_softc*)ifp;
  276         int error = 0;
  277         static int called = 0;  /* XXX: MUTEX */
  278         ALTQ_DECL(struct altq_pktattr pktattr;)
  279         int s;
  280 
  281         IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
  282 
  283         /*
  284          * gif may cause infinite recursion calls when misconfigured.
  285          * We'll prevent this by introducing upper limit.
  286          * XXX: this mechanism may introduce another problem about
  287          *      mutual exclusion of the variable CALLED, especially if we
  288          *      use kernel thread.
  289          */
  290         if (++called > max_gif_nesting) {
  291                 log(LOG_NOTICE,
  292                     "gif_output: recursively called too many times(%d)\n",
  293                     called);
  294                 m_freem(m);
  295                 error = EIO;    /* is there better errno? */
  296                 goto end;
  297         }
  298 
  299         m->m_flags &= ~(M_BCAST|M_MCAST);
  300         if (!(ifp->if_flags & IFF_UP) ||
  301             sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
  302                 m_freem(m);
  303                 error = ENETDOWN;
  304                 goto end;
  305         }
  306 
  307         /* inner AF-specific encapsulation */
  308         switch (dst->sa_family) {
  309 #ifdef ISO
  310         case AF_ISO:
  311                 m = gif_eon_encap(m);
  312                 if (!m) {
  313                         error = ENOBUFS;
  314                         goto end;
  315                 }
  316                 break;
  317 #endif
  318         default:
  319                 break;
  320         }
  321 
  322         /* XXX should we check if our outer source is legal? */
  323 
  324         /* use DLT_NULL encapsulation here to pass inner af type */
  325         M_PREPEND(m, sizeof(int), M_DONTWAIT);
  326         if (!m) {
  327                 error = ENOBUFS;
  328                 goto end;
  329         }
  330         *mtod(m, int *) = dst->sa_family;
  331 
  332         s = splnet();
  333         IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
  334         if (error) {
  335                 splx(s);
  336                 goto end;
  337         }
  338         splx(s);
  339 
  340 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  341         softintr_schedule(sc->gif_si);
  342 #else
  343         /* XXX bad spl level? */
  344         gifnetisr();
  345 #endif
  346         error = 0;
  347 
  348   end:
  349         called = 0;             /* reset recursion counter */
  350         if (error)
  351                 ifp->if_oerrors++;
  352         return error;
  353 }
  354 
  355 #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
  356 void
  357 gifnetisr()
  358 {
  359         struct gif_softc *sc;
  360 
  361         for (sc = LIST_FIRST(&gif_softc_list); sc != NULL;
  362              sc = LIST_NEXT(sc, gif_list)) {
  363                 gifintr(sc);
  364         }
  365 }
  366 #endif
  367 
  368 void
  369 gifintr(arg)
  370         void *arg;
  371 {
  372         struct gif_softc *sc;
  373         struct ifnet *ifp;
  374         struct mbuf *m;
  375         int family;
  376         int len;
  377         int s;
  378         int error;
  379 
  380         sc = (struct gif_softc *)arg;
  381         ifp = &sc->gif_if;
  382 
  383         /* output processing */
  384         while (1) {
  385                 s = splnet();
  386                 IFQ_DEQUEUE(&sc->gif_if.if_snd, m);
  387                 splx(s);
  388                 if (m == NULL)
  389                         break;
  390 
  391                 /* grab and chop off inner af type */
  392                 if (sizeof(int) > m->m_len) {
  393                         m = m_pullup(m, sizeof(int));
  394                         if (!m) {
  395                                 ifp->if_oerrors++;
  396                                 continue;
  397                         }
  398                 }
  399                 family = *mtod(m, int *);
  400 #if NBPFILTER > 0
  401                 if (ifp->if_bpf) {
  402 #ifdef HAVE_OLD_BPF
  403                         bpf_mtap(ifp, m);
  404 #else
  405                         bpf_mtap(ifp->if_bpf, m);
  406 #endif
  407                 }
  408 #endif
  409                 m_adj(m, sizeof(int));
  410 
  411                 len = m->m_pkthdr.len;
  412 
  413                 /* dispatch to output logic based on outer AF */
  414                 switch (sc->gif_psrc->sa_family) {
  415 #ifdef INET
  416                 case AF_INET:
  417                         error = in_gif_output(ifp, family, m);
  418                         break;
  419 #endif
  420 #ifdef INET6
  421                 case AF_INET6:
  422                         error = in6_gif_output(ifp, family, m);
  423                         break;
  424 #endif
  425                 default:
  426                         m_freem(m);             
  427                         error = ENETDOWN;
  428                         break;
  429                 }
  430 
  431                 if (error)
  432                         ifp->if_oerrors++;
  433                 else {
  434                         ifp->if_opackets++;     
  435                         ifp->if_obytes += len;
  436                 }
  437         }
  438 }
  439 
  440 void
  441 gif_input(m, af, ifp)
  442         struct mbuf *m;
  443         int af;
  444         struct ifnet *ifp;
  445 {
  446         int s, isr;
  447         struct ifqueue *ifq = NULL;
  448 
  449         if (ifp == NULL) {
  450                 /* just in case */
  451                 m_freem(m);
  452                 return;
  453         }
  454 
  455         m->m_pkthdr.rcvif = ifp;
  456         
  457 #if NBPFILTER > 0
  458         if (ifp->if_bpf) {
  459                 /*
  460                  * We need to prepend the address family as
  461                  * a four byte field.  Cons up a dummy header
  462                  * to pacify bpf.  This is safe because bpf
  463                  * will only read from the mbuf (i.e., it won't
  464                  * try to free it or keep a pointer a to it).
  465                  */
  466                 struct mbuf m0;
  467                 u_int32_t af1 = af;
  468                 
  469                 m0.m_next = m;
  470                 m0.m_len = 4;
  471                 m0.m_data = (char *)&af1;
  472                 
  473 #ifdef HAVE_OLD_BPF
  474                 bpf_mtap(ifp, &m0);
  475 #else
  476                 bpf_mtap(ifp->if_bpf, &m0);
  477 #endif
  478         }
  479 #endif /*NBPFILTER > 0*/
  480 
  481         /*
  482          * Put the packet to the network layer input queue according to the
  483          * specified address family.
  484          * Note: older versions of gif_input directly called network layer
  485          * input functions, e.g. ip6_input, here.  We changed the policy to
  486          * prevent too many recursive calls of such input functions, which
  487          * might cause kernel panic.  But the change may introduce another
  488          * problem; if the input queue is full, packets are discarded.
  489          * The kernel stack overflow really happened, and we believed
  490          * queue-full rarely occurs, so we changed the policy.
  491          */
  492         switch (af) {
  493 #ifdef INET
  494         case AF_INET:
  495                 ifq = &ipintrq;
  496                 isr = NETISR_IP;
  497                 break;
  498 #endif
  499 #ifdef INET6
  500         case AF_INET6:
  501                 ifq = &ip6intrq;
  502                 isr = NETISR_IPV6;
  503                 break;
  504 #endif
  505 #ifdef ISO
  506         case AF_ISO:
  507                 m = gif_eon_decap(ifp, m);
  508                 if (!m)
  509                         return;
  510                 ifq = &clnlintrq;
  511                 isr = NETISR_ISO;
  512                 break;
  513 #endif
  514         default:
  515                 m_freem(m);
  516                 return;
  517         }
  518 
  519         s = splnet();
  520         if (IF_QFULL(ifq)) {
  521                 IF_DROP(ifq);   /* update statistics */
  522                 m_freem(m);
  523                 splx(s);
  524                 return;
  525         }
  526         ifp->if_ipackets++;
  527         ifp->if_ibytes += m->m_pkthdr.len;
  528         IF_ENQUEUE(ifq, m);
  529         /* we need schednetisr since the address family may change */
  530         schednetisr(isr);
  531         splx(s);
  532 }
  533 
  534 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
  535 int
  536 gif_ioctl(ifp, cmd, data)
  537         struct ifnet *ifp;
  538         u_long cmd;
  539         caddr_t data;
  540 {
  541         struct proc *p = curproc;       /* XXX */
  542         struct gif_softc *sc  = (struct gif_softc*)ifp;
  543         struct ifreq     *ifr = (struct ifreq*)data;
  544         int error = 0, size;
  545         struct sockaddr *dst, *src;
  546 #ifdef SIOCSIFMTU
  547         u_long mtu;
  548 #endif
  549 
  550         switch (cmd) {
  551         case SIOCSIFADDR:
  552                 ifp->if_flags |= IFF_UP;
  553                 break;
  554                 
  555         case SIOCSIFDSTADDR:
  556                 break;
  557 
  558         case SIOCADDMULTI:
  559         case SIOCDELMULTI:
  560                 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
  561                         break;
  562                 switch (ifr->ifr_addr.sa_family) {
  563 #ifdef INET
  564                 case AF_INET:   /* IP supports Multicast */
  565                         break;
  566 #endif /* INET */
  567 #ifdef INET6
  568                 case AF_INET6:  /* IP6 supports Multicast */
  569                         break;
  570 #endif /* INET6 */
  571                 default:  /* Other protocols doesn't support Multicast */
  572                         error = EAFNOSUPPORT;
  573                         break;
  574                 }
  575                 break;
  576 
  577 #ifdef  SIOCSIFMTU /* xxx */
  578         case SIOCGIFMTU:
  579                 break;
  580 
  581         case SIOCSIFMTU:
  582                 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
  583                         break;
  584                 mtu = ifr->ifr_mtu;
  585                 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX)
  586                         return (EINVAL);
  587                 ifp->if_mtu = mtu;
  588                 break;
  589 #endif /* SIOCSIFMTU */
  590 
  591 #ifdef INET
  592         case SIOCSIFPHYADDR:
  593 #endif
  594 #ifdef INET6
  595         case SIOCSIFPHYADDR_IN6:
  596 #endif /* INET6 */
  597         case SIOCSLIFPHYADDR:
  598                 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
  599                         break;
  600                 switch (cmd) {
  601 #ifdef INET
  602                 case SIOCSIFPHYADDR:
  603                         src = (struct sockaddr *)
  604                                 &(((struct in_aliasreq *)data)->ifra_addr);
  605                         dst = (struct sockaddr *)
  606                                 &(((struct in_aliasreq *)data)->ifra_dstaddr);
  607                         break;
  608 #endif
  609 #ifdef INET6
  610                 case SIOCSIFPHYADDR_IN6:
  611                         src = (struct sockaddr *)
  612                                 &(((struct in6_aliasreq *)data)->ifra_addr);
  613                         dst = (struct sockaddr *)
  614                                 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
  615                         break;
  616 #endif
  617                 case SIOCSLIFPHYADDR:
  618                         src = (struct sockaddr *)
  619                                 &(((struct if_laddrreq *)data)->addr);
  620                         dst = (struct sockaddr *)
  621                                 &(((struct if_laddrreq *)data)->dstaddr);
  622                         break;
  623                 default:
  624                         return EINVAL;
  625                 }
  626 
  627                 /* sa_family must be equal */
  628                 if (src->sa_family != dst->sa_family)
  629                         return EINVAL;
  630 
  631                 /* validate sa_len */
  632                 switch (src->sa_family) {
  633 #ifdef INET
  634                 case AF_INET:
  635                         if (src->sa_len != sizeof(struct sockaddr_in))
  636                                 return EINVAL;
  637                         break;
  638 #endif
  639 #ifdef INET6
  640                 case AF_INET6:
  641                         if (src->sa_len != sizeof(struct sockaddr_in6))
  642                                 return EINVAL;
  643                         break;
  644 #endif
  645                 default:
  646                         return EAFNOSUPPORT;
  647                 }
  648                 switch (dst->sa_family) {
  649 #ifdef INET
  650                 case AF_INET:
  651                         if (dst->sa_len != sizeof(struct sockaddr_in))
  652                                 return EINVAL;
  653                         break;
  654 #endif
  655 #ifdef INET6
  656                 case AF_INET6:
  657                         if (dst->sa_len != sizeof(struct sockaddr_in6))
  658                                 return EINVAL;
  659                         break;
  660 #endif
  661                 default:
  662                         return EAFNOSUPPORT;
  663                 }
  664 
  665                 /* check sa_family looks sane for the cmd */
  666                 switch (cmd) {
  667                 case SIOCSIFPHYADDR:
  668                         if (src->sa_family == AF_INET)
  669                                 break;
  670                         return EAFNOSUPPORT;
  671 #ifdef INET6
  672                 case SIOCSIFPHYADDR_IN6:
  673                         if (src->sa_family == AF_INET6)
  674                                 break;
  675                         return EAFNOSUPPORT;
  676 #endif /* INET6 */
  677                 case SIOCSLIFPHYADDR:
  678                         /* checks done in the above */
  679                         break;
  680                 }
  681 
  682                 error = gif_set_tunnel(&sc->gif_if, src, dst);
  683                 break;
  684 
  685 #ifdef SIOCDIFPHYADDR
  686         case SIOCDIFPHYADDR:
  687                 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
  688                         break;
  689                 gif_delete_tunnel(&sc->gif_if);
  690                 break;
  691 #endif
  692                         
  693         case SIOCGIFPSRCADDR:
  694 #ifdef INET6
  695         case SIOCGIFPSRCADDR_IN6:
  696 #endif /* INET6 */
  697                 if (sc->gif_psrc == NULL) {
  698                         error = EADDRNOTAVAIL;
  699                         goto bad;
  700                 }
  701                 src = sc->gif_psrc;
  702                 switch (cmd) {
  703 #ifdef INET
  704                 case SIOCGIFPSRCADDR:
  705                         dst = &ifr->ifr_addr;
  706                         size = sizeof(ifr->ifr_addr);
  707                         break;
  708 #endif /* INET */
  709 #ifdef INET6
  710                 case SIOCGIFPSRCADDR_IN6:
  711                         dst = (struct sockaddr *)
  712                                 &(((struct in6_ifreq *)data)->ifr_addr);
  713                         size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
  714                         break;
  715 #endif /* INET6 */
  716                 default:
  717                         error = EADDRNOTAVAIL;
  718                         goto bad;
  719                 }
  720                 if (src->sa_len > size)
  721                         return EINVAL;
  722                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
  723                 break;
  724                         
  725         case SIOCGIFPDSTADDR:
  726 #ifdef INET6
  727         case SIOCGIFPDSTADDR_IN6:
  728 #endif /* INET6 */
  729                 if (sc->gif_pdst == NULL) {
  730                         error = EADDRNOTAVAIL;
  731                         goto bad;
  732                 }
  733                 src = sc->gif_pdst;
  734                 switch (cmd) {
  735 #ifdef INET
  736                 case SIOCGIFPDSTADDR:
  737                         dst = &ifr->ifr_addr;
  738                         size = sizeof(ifr->ifr_addr);
  739                         break;
  740 #endif /* INET */
  741 #ifdef INET6
  742                 case SIOCGIFPDSTADDR_IN6:
  743                         dst = (struct sockaddr *)
  744                                 &(((struct in6_ifreq *)data)->ifr_addr);
  745                         size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
  746                         break;
  747 #endif /* INET6 */
  748                 default:
  749                         error = EADDRNOTAVAIL;
  750                         goto bad;
  751                 }
  752                 if (src->sa_len > size)
  753                         return EINVAL;
  754                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
  755                 break;
  756 
  757         case SIOCGLIFPHYADDR:
  758                 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
  759                         error = EADDRNOTAVAIL;
  760                         goto bad;
  761                 }
  762 
  763                 /* copy src */
  764                 src = sc->gif_psrc;
  765                 dst = (struct sockaddr *)
  766                         &(((struct if_laddrreq *)data)->addr);
  767                 size = sizeof(((struct if_laddrreq *)data)->addr);
  768                 if (src->sa_len > size)
  769                         return EINVAL;
  770                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
  771 
  772                 /* copy dst */
  773                 src = sc->gif_pdst;
  774                 dst = (struct sockaddr *)
  775                         &(((struct if_laddrreq *)data)->dstaddr);
  776                 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
  777                 if (src->sa_len > size)
  778                         return EINVAL;
  779                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
  780                 break;
  781 
  782         case SIOCSIFFLAGS:
  783                 /* if_ioctl() takes care of it */
  784                 break;
  785 
  786         default:
  787                 error = EINVAL;
  788                 break;
  789         }
  790  bad:
  791         return error;
  792 }
  793 
  794 int
  795 gif_set_tunnel(ifp, src, dst)
  796         struct ifnet *ifp;
  797         struct sockaddr *src;
  798         struct sockaddr *dst;
  799 {
  800         struct gif_softc *sc = (struct gif_softc *)ifp;
  801         struct gif_softc *sc2;
  802         struct sockaddr *osrc, *odst, *sa;
  803         int s;
  804         int error;
  805 
  806         s = splsoftnet();
  807 
  808         for (sc2 = LIST_FIRST(&gif_softc_list); sc2 != NULL;
  809              sc2 = LIST_NEXT(sc2, gif_list)) {
  810                 if (sc2 == sc)
  811                         continue;
  812                 if (!sc2->gif_pdst || !sc2->gif_psrc)
  813                         continue;
  814                 if (sc2->gif_pdst->sa_family != dst->sa_family ||
  815                     sc2->gif_pdst->sa_len != dst->sa_len ||
  816                     sc2->gif_psrc->sa_family != src->sa_family ||
  817                     sc2->gif_psrc->sa_len != src->sa_len)
  818                         continue;
  819                 /* can't configure same pair of address onto two gifs */
  820                 if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
  821                     bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
  822                         error = EADDRNOTAVAIL;
  823                         goto bad;
  824                 }
  825 
  826                 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
  827         }
  828 
  829         /* XXX we can detach from both, but be polite just in case */
  830         if (sc->gif_psrc)
  831                 switch (sc->gif_psrc->sa_family) {
  832 #ifdef INET
  833                 case AF_INET:
  834                         (void)in_gif_detach(sc);
  835                         break;
  836 #endif
  837 #ifdef INET6
  838                 case AF_INET6:
  839                         (void)in6_gif_detach(sc);
  840                         break;
  841 #endif
  842                 }
  843 
  844 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  845         sc->gif_si = softintr_establish(IPL_SOFTNET, gifintr, sc);
  846         if (sc->gif_si == NULL) {
  847                 error = ENOMEM;
  848                 goto bad;
  849         }
  850 #endif
  851 
  852         osrc = sc->gif_psrc;
  853         sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
  854         bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
  855         sc->gif_psrc = sa;
  856 
  857         odst = sc->gif_pdst;
  858         sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
  859         bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
  860         sc->gif_pdst = sa;
  861 
  862         switch (sc->gif_psrc->sa_family) {
  863 #ifdef INET
  864         case AF_INET:
  865                 error = in_gif_attach(sc);
  866                 break;
  867 #endif
  868 #ifdef INET6
  869         case AF_INET6:
  870                 error = in6_gif_attach(sc);
  871                 break;
  872 #endif
  873         default:
  874                 error = EINVAL;
  875                 break;
  876         }
  877         if (error) {
  878                 /* rollback */
  879                 free((caddr_t)sc->gif_psrc, M_IFADDR);
  880                 free((caddr_t)sc->gif_pdst, M_IFADDR);
  881                 sc->gif_psrc = osrc;
  882                 sc->gif_pdst = odst;
  883                 goto bad;
  884         }
  885 
  886         if (osrc)
  887                 free((caddr_t)osrc, M_IFADDR);
  888         if (odst)
  889                 free((caddr_t)odst, M_IFADDR);
  890 
  891         if (sc->gif_psrc && sc->gif_pdst)
  892                 ifp->if_flags |= IFF_RUNNING;
  893         else
  894                 ifp->if_flags &= ~IFF_RUNNING;
  895         splx(s);
  896 
  897         return 0;
  898 
  899  bad:
  900 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  901         if (sc->gif_si) {
  902                 softintr_disestablish(sc->gif_si);
  903                 sc->gif_si = NULL;
  904         }
  905 #endif
  906         if (sc->gif_psrc && sc->gif_pdst)
  907                 ifp->if_flags |= IFF_RUNNING;
  908         else
  909                 ifp->if_flags &= ~IFF_RUNNING;
  910         splx(s);
  911 
  912         return error;
  913 }
  914 
  915 void
  916 gif_delete_tunnel(ifp)
  917         struct ifnet *ifp;
  918 {
  919         struct gif_softc *sc = (struct gif_softc *)ifp;
  920         int s;
  921 
  922         s = splsoftnet();
  923 
  924 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  925         if (sc->gif_si) {
  926                 softintr_disestablish(sc->gif_si);
  927                 sc->gif_si = NULL;
  928         }
  929 #endif
  930         if (sc->gif_psrc) {
  931                 free((caddr_t)sc->gif_psrc, M_IFADDR);
  932                 sc->gif_psrc = NULL;
  933         }
  934         if (sc->gif_pdst) {
  935                 free((caddr_t)sc->gif_pdst, M_IFADDR);
  936                 sc->gif_pdst = NULL;
  937         }
  938         /* it is safe to detach from both */
  939 #ifdef INET
  940         (void)in_gif_detach(sc);
  941 #endif
  942 #ifdef INET6
  943         (void)in6_gif_detach(sc);
  944 #endif
  945 
  946         if (sc->gif_psrc && sc->gif_pdst)
  947                 ifp->if_flags |= IFF_RUNNING;
  948         else
  949                 ifp->if_flags &= ~IFF_RUNNING;
  950         splx(s);
  951 }
  952 
  953 #ifdef ISO
  954 struct eonhdr {
  955         u_int8_t version;
  956         u_int8_t class;
  957         u_int16_t cksum;
  958 };
  959 
  960 /*
  961  * prepend EON header to ISO PDU
  962  */
  963 static struct mbuf *
  964 gif_eon_encap(struct mbuf *m)
  965 {
  966         struct eonhdr *ehdr;
  967 
  968         M_PREPEND(m, sizeof(*ehdr), M_DONTWAIT);
  969         if (m && m->m_len < sizeof(*ehdr))
  970                 m = m_pullup(m, sizeof(*ehdr));
  971         if (m == NULL)
  972                 return NULL;
  973         ehdr = mtod(m, struct eonhdr *);
  974         ehdr->version = 1;
  975         ehdr->class = 0;                /* always unicast */
  976 #if 0
  977         /* calculate the checksum of the eonhdr */
  978         {
  979                 struct mbuf mhead;
  980                 memset(&mhead, 0, sizeof(mhead));
  981                 ehdr->cksum = 0;
  982                 mhead.m_data = (caddr_t)ehdr;
  983                 mhead.m_len = sizeof(*ehdr);
  984                 mhead.m_next = 0;
  985                 iso_gen_csum(&mhead, offsetof(struct eonhdr, cksum),
  986                     mhead.m_len);
  987         }
  988 #else
  989         /* since the data is always constant we'll just plug the value in */
  990         ehdr->cksum = htons(0xfc02);
  991 #endif
  992         return m;
  993 }
  994 
  995 /*
  996  * remove EON header and check checksum
  997  */
  998 static struct mbuf *
  999 gif_eon_decap(struct ifnet *ifp, struct mbuf *m)
 1000 {
 1001         struct eonhdr *ehdr;
 1002 
 1003         if (m->m_len < sizeof(*ehdr) &&
 1004             (m = m_pullup(m, sizeof(*ehdr))) == NULL) {
 1005                 ifp->if_ierrors++;
 1006                 return NULL;
 1007         }
 1008         if (iso_check_csum(m, sizeof(struct eonhdr))) {
 1009                 m_freem(m);
 1010                 return NULL;
 1011         }
 1012         m_adj(m, sizeof(*ehdr));
 1013         return m;
 1014 }
 1015 #endif /*ISO*/

Cache object: 5d3e7089bdbbf9f0e5ffad2584de6920


[ 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.