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

Cache object: 5e2575b9eef3ab7bc937a5d72617213e


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