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

Cache object: 496baa48bbd6cafb50b5cc88d0a35f50


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