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

Cache object: cff68937df2ca233c0629cd3c8f19688


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