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_etherip.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_etherip.c,v 1.3 2006/11/24 01:04:30 rpaulo Exp $        */
    2 
    3 /*
    4  *  Copyright (c) 2006, Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
    5  *  All rights reserved.
    6  *
    7  *  Redistribution and use in source and binary forms, with or without
    8  *  modification, are permitted provided that the following conditions
    9  *  are met:
   10  *  1. Redistributions of source code must retain the above copyright
   11  *     notice, this list of conditions and the following disclaimer.
   12  *  2. Redistributions in binary form must reproduce the above copyright
   13  *     notice, this list of conditions and the following disclaimer in the
   14  *     documentation and/or other materials provided with the distribution.
   15  *  3. Neither the name of Hans Rosenfeld nor the names of his
   16  *     contributors may be used to endorse or promote products derived
   17  *     from this software without specific prior written permission.
   18  *
   19  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   20  *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  *  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   23  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  *  SUCH DAMAGE.
   30  *
   31  *
   32  *  Copyright (c) 2003, 2004 The NetBSD Foundation.
   33  *  All rights reserved.
   34  *
   35  *  This code is derived from software contributed to the NetBSD Foundation
   36  *   by Quentin Garnier
   37  *
   38  *  Redistribution and use in source and binary forms, with or without
   39  *  modification, are permitted provided that the following conditions
   40  *  are met:
   41  *  1. Redistributions of source code must retain the above copyright
   42  *     notice, this list of conditions and the following disclaimer.
   43  *  2. Redistributions in binary form must reproduce the above copyright
   44  *     notice, this list of conditions and the following disclaimer in the
   45  *     documentation and/or other materials provided with the distribution.
   46  *  3. All advertising materials mentioning features or use of this software
   47  *     must display the following acknowledgement:
   48  *         This product includes software developed by the NetBSD
   49  *         Foundation, Inc. and its contributors.
   50  *  4. Neither the name of The NetBSD Foundation nor the names of its
   51  *     contributors may be used to endorse or promote products derived
   52  *     from this software without specific prior written permission.
   53  *
   54  *  THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   55  *  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   56  *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   57  *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   58  *  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   59  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   60  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   61  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   62  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   63  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   64  *  POSSIBILITY OF SUCH DAMAGE.
   65  *
   66  *
   67  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
   68  * All rights reserved.
   69  *
   70  * Redistribution and use in source and binary forms, with or without
   71  * modification, are permitted provided that the following conditions
   72  * are met:
   73  * 1. Redistributions of source code must retain the above copyright
   74  *    notice, this list of conditions and the following disclaimer.
   75  * 2. Redistributions in binary form must reproduce the above copyright
   76  *    notice, this list of conditions and the following disclaimer in the
   77  *    documentation and/or other materials provided with the distribution.
   78  * 3. Neither the name of the project nor the names of its contributors
   79  *    may be used to endorse or promote products derived from this software
   80  *    without specific prior written permission.
   81  *
   82  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   83  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   84  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   85  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   86  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   87  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   88  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   89  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   90  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   91  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   92  * SUCH DAMAGE.
   93  */
   94 
   95 #include <sys/cdefs.h>
   96 
   97 #include "opt_inet.h"
   98 #include "bpfilter.h"
   99 
  100 #include <sys/param.h>
  101 #include <sys/systm.h>
  102 #include <sys/kernel.h>
  103 #include <sys/malloc.h>
  104 #include <sys/conf.h>
  105 #include <sys/device.h>
  106 #include <sys/errno.h>
  107 #include <sys/time.h>
  108 #include <sys/sysctl.h>
  109 #include <sys/queue.h>
  110 #include <sys/kauth.h>
  111 #include <sys/socket.h>
  112 
  113 #include <net/if.h>
  114 #include <net/if_dl.h>
  115 #include <net/if_ether.h>
  116 #include <net/if_media.h>
  117 #include <net/route.h>
  118 #include <net/if_etherip.h>
  119 #if NBPFILTER > 0
  120 #include <net/bpf.h>
  121 #endif
  122 
  123 #include <netinet/in.h>
  124 #include <netinet/in_systm.h>
  125 #include <netinet/ip.h>
  126 #ifdef  INET
  127 #include <netinet/in_var.h>
  128 #endif  /* INET */
  129 #include <netinet/ip_etherip.h>
  130 
  131 #ifdef INET6
  132 #include <netinet6/ip6_etherip.h>
  133 #ifndef INET
  134 #include <netinet/in.h>
  135 #endif
  136 #include <netinet6/in6_var.h>
  137 #include <netinet/ip6.h>
  138 #include <netinet6/ip6_var.h>
  139 #include <netinet6/in6_gif.h>
  140 #include <netinet6/ip6protosw.h>
  141 #endif /* INET6 */
  142 
  143 static int etherip_node;
  144 static int etherip_sysctl_handler(SYSCTLFN_PROTO);
  145 SYSCTL_SETUP_PROTO(sysctl_etherip_setup);
  146 
  147 void etheripattach(int);
  148 
  149 static int  etherip_match(struct device *, struct cfdata *, void *);
  150 static void etherip_attach(struct device *, struct device *, void *);
  151 static int  etherip_detach(struct device *, int);
  152 
  153 CFATTACH_DECL(etherip, sizeof(struct etherip_softc),
  154               etherip_match, etherip_attach, etherip_detach, NULL);
  155 extern struct cfdriver etherip_cd;
  156 
  157 static void etherip_start(struct ifnet *);
  158 static void etherip_stop(struct ifnet *, int);
  159 static int  etherip_init(struct ifnet *);
  160 static int  etherip_ioctl(struct ifnet *, u_long, caddr_t);
  161 
  162 static int  etherip_mediachange(struct ifnet *);
  163 static void etherip_mediastatus(struct ifnet *, struct ifmediareq *);
  164 
  165 static int  etherip_clone_create(struct if_clone *, int);
  166 static int  etherip_clone_destroy(struct ifnet *);
  167 
  168 static struct if_clone etherip_cloners = IF_CLONE_INITIALIZER(
  169         "etherip", etherip_clone_create, etherip_clone_destroy);
  170 
  171 static int  etherip_set_tunnel(struct ifnet *,
  172                                struct sockaddr *, struct sockaddr *);
  173 static void etherip_delete_tunnel(struct ifnet *);
  174 static void etheripintr(void *);
  175 
  176 void
  177 etheripattach(int count)
  178 {
  179         int error;
  180 
  181         error = config_cfattach_attach(etherip_cd.cd_name, &etherip_ca);
  182 
  183         if (error) {
  184                 aprint_error("%s: unable to register cfattach\n",
  185                              etherip_cd.cd_name);
  186                 (void)config_cfdriver_detach(&etherip_cd);
  187                 return;
  188         }
  189 
  190         LIST_INIT(&etherip_softc_list);
  191         if_clone_attach(&etherip_cloners);
  192 }
  193 
  194 /* Pretty much useless for a pseudo-device */
  195 static int
  196 etherip_match(struct device *self, struct cfdata *cfdata, void *arg)
  197 {
  198         return 1;
  199 }
  200 
  201 static void
  202 etherip_attach(struct device *parent, struct device *self, void *aux)
  203 {
  204         struct etherip_softc *sc = (struct etherip_softc *)self;
  205         struct ifnet *ifp;
  206         const struct sysctlnode *node;
  207         u_int8_t enaddr[ETHER_ADDR_LEN] =
  208                 { 0xf2, 0x0b, 0xa5, 0xff, 0xff, 0xff };
  209         char enaddrstr[3 * ETHER_ADDR_LEN];
  210         struct timeval tv;
  211         uint32_t ui;
  212         int error;
  213 
  214 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  215         sc->sc_si  = NULL;
  216 #endif
  217         sc->sc_src = NULL;
  218         sc->sc_dst = NULL;
  219         sc->sc_route_expire = 0;
  220 
  221         /*
  222          * In order to obtain unique initial Ethernet address on a host,
  223          * do some randomisation using the current uptime.  It's not meant
  224          * for anything but avoiding hard-coding an address.
  225          */
  226         getmicrouptime(&tv);
  227         ui = (tv.tv_sec ^ tv.tv_usec) & 0xffffff;
  228         memcpy(enaddr+3, (u_int8_t *)&ui, 3);
  229         
  230         aprint_verbose("%s: Ethernet address %s\n", sc->sc_dev.dv_xname,
  231                        ether_snprintf(enaddrstr, sizeof(enaddrstr), enaddr));
  232 
  233         /*
  234          * Why 1000baseT? Why not? You can add more.
  235          *
  236          * Note that there are 3 steps: init, one or several additions to
  237          * list of supported media, and in the end, the selection of one
  238          * of them.
  239          */
  240         ifmedia_init(&sc->sc_im, 0, etherip_mediachange, etherip_mediastatus);
  241         ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_1000_T, 0, NULL);
  242         ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_1000_T|IFM_FDX, 0, NULL);
  243         ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_100_TX, 0, NULL);
  244         ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
  245         ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_10_T, 0, NULL);
  246         ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
  247         ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_AUTO, 0, NULL);
  248         ifmedia_set(&sc->sc_im, IFM_ETHER|IFM_AUTO);
  249         
  250         /*
  251          * One should note that an interface must do multicast in order
  252          * to support IPv6.
  253          */
  254         ifp = &sc->sc_ec.ec_if;
  255         strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
  256         ifp->if_softc = sc;
  257         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  258         ifp->if_ioctl = etherip_ioctl;
  259         ifp->if_start = etherip_start;
  260         ifp->if_stop  = etherip_stop;
  261         ifp->if_init  = etherip_init;
  262         IFQ_SET_READY(&ifp->if_snd);
  263         
  264         sc->sc_ec.ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU;
  265         
  266         /* 
  267          * Those steps are mandatory for an Ethernet driver, the first call
  268          * being common to all network interface drivers.
  269          */
  270         if_attach(ifp);
  271         ether_ifattach(ifp, enaddr);
  272 
  273         /*
  274          * Add a sysctl node for that interface.
  275          *
  276          * The pointer transmitted is not a string, but instead a pointer to
  277          * the softc structure, which we can use to build the string value on
  278          * the fly in the helper function of the node.  See the comments for
  279          * etherip_sysctl_handler for details.
  280          */
  281         error = sysctl_createv(NULL, 0, NULL, &node, CTLFLAG_READWRITE, 
  282                                CTLTYPE_STRING, sc->sc_dev.dv_xname, NULL,
  283                                etherip_sysctl_handler, 0, sc, 18, CTL_NET,
  284                                AF_LINK, etherip_node, device_unit(&sc->sc_dev),
  285                                CTL_EOL);
  286         if (error)
  287                 aprint_error("%s: sysctl_createv returned %d, ignoring\n",
  288                              sc->sc_dev.dv_xname, error);
  289 
  290         /* insert into etherip_softc_list */
  291         LIST_INSERT_HEAD(&etherip_softc_list, sc, etherip_list);
  292 }
  293 
  294 /*
  295  * When detaching, we do the inverse of what is done in the attach
  296  * routine, in reversed order.
  297  */
  298 static int
  299 etherip_detach(struct device* self, int flags)
  300 {
  301         struct etherip_softc *sc = (struct etherip_softc *)self;
  302         struct ifnet *ifp = &sc->sc_ec.ec_if;
  303         int error, s;
  304 
  305         s = splnet();
  306         etherip_stop(ifp, 1);
  307         if_down(ifp);
  308         splx(s);
  309 
  310         /*
  311          * Destroying a single leaf is a very straightforward operation using
  312          * sysctl_destroyv.  One should be sure to always end the path with
  313          * CTL_EOL.
  314          */
  315         error = sysctl_destroyv(NULL, CTL_NET, AF_LINK, etherip_node,
  316                                 device_unit(&sc->sc_dev), CTL_EOL);
  317         if (error)
  318                 aprint_error("%s: sysctl_destroyv returned %d, ignoring\n",
  319                              sc->sc_dev.dv_xname, error);
  320 
  321         LIST_REMOVE(sc, etherip_list);
  322         etherip_delete_tunnel(ifp);
  323         ether_ifdetach(ifp);
  324         if_detach(ifp);
  325         ifmedia_delete_instance(&sc->sc_im, IFM_INST_ANY);
  326 
  327         return 0;
  328 }
  329 
  330 /*
  331  * This function is called by the ifmedia layer to notify the driver
  332  * that the user requested a media change.  A real driver would
  333  * reconfigure the hardware.
  334  */
  335 static int
  336 etherip_mediachange(struct ifnet *ifp)
  337 {
  338         return 0;
  339 }
  340 
  341 /*
  342  * Here the user asks for the currently used media.
  343  */
  344 static void
  345 etherip_mediastatus(struct ifnet *ifp, struct ifmediareq *imr)
  346 {
  347         struct etherip_softc *sc = (struct etherip_softc *)ifp->if_softc;
  348 
  349         imr->ifm_active = sc->sc_im.ifm_cur->ifm_media;
  350 }
  351 
  352 static void
  353 etherip_start(struct ifnet *ifp)
  354 {
  355         struct etherip_softc *sc = (struct etherip_softc *)ifp->if_softc;
  356 
  357 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  358         if(sc->sc_si)
  359                 softintr_schedule(sc->sc_si);
  360 #else
  361         etheripintr(sc);
  362 #endif
  363 }
  364 
  365 static void
  366 etheripintr(void *arg)
  367 {
  368         struct etherip_softc *sc = (struct etherip_softc *)arg;;
  369         struct ifnet *ifp = &sc->sc_ec.ec_if;;
  370         struct mbuf *m;
  371         int s, error;
  372 
  373         for (;;) {
  374                 s = splnet();
  375                 IFQ_DEQUEUE(&ifp->if_snd, m);
  376                 splx(s);
  377                 if (m == NULL)
  378                         return;
  379                 
  380 #if NBPFILTER > 0
  381                 if (ifp->if_bpf)
  382                         bpf_mtap(ifp->if_bpf, m);
  383 #endif
  384                 
  385                 ifp->if_opackets++;
  386                 if (sc->sc_src && sc->sc_dst) {
  387                         ifp->if_flags |= IFF_OACTIVE;
  388                         switch (sc->sc_src->sa_family) {
  389 #ifdef INET
  390                         case AF_INET:
  391                                 error = ip_etherip_output(ifp, m);
  392                                 break;
  393 #endif
  394 #ifdef INET6
  395                         case AF_INET6:
  396                                 error = ip6_etherip_output(ifp, m);
  397                                 break;
  398 #endif
  399                         default:
  400                                 error = ENETDOWN;
  401                         }
  402                         ifp->if_flags &= ~IFF_OACTIVE;
  403                 } else  m_freem(m);
  404         }
  405 }
  406 
  407 static int
  408 etherip_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  409 {
  410         struct etherip_softc *sc = (struct etherip_softc *)ifp->if_softc;
  411         struct ifreq *ifr = (struct ifreq *)data;
  412         struct sockaddr *src, *dst;
  413         int s, error;
  414 
  415         switch (cmd) {
  416         case SIOCSLIFPHYADDR:
  417                 src = (struct sockaddr *)
  418                         &(((struct if_laddrreq *)data)->addr);
  419                 dst = (struct sockaddr *)
  420                         &(((struct if_laddrreq *)data)->dstaddr);
  421 
  422                 /* sa_family must be equal */
  423                 if (src->sa_family != dst->sa_family)
  424                         return EINVAL;
  425 
  426                 /* validate sa_len */
  427                 switch (src->sa_family) {
  428 #ifdef INET
  429                 case AF_INET:
  430                         if (src->sa_len != sizeof(struct sockaddr_in) ||
  431                             dst->sa_len != sizeof(struct sockaddr_in))
  432                                 return EINVAL;
  433                         break;
  434 #endif
  435 #ifdef INET6
  436                 case AF_INET6:
  437                         if (src->sa_len != sizeof(struct sockaddr_in6) ||
  438                             dst->sa_len != sizeof(struct sockaddr_in6))
  439                                 return EINVAL;
  440                         break;
  441 #endif
  442                 default:
  443                         return EAFNOSUPPORT;
  444                 }
  445                 
  446                 error = etherip_set_tunnel(ifp, src, dst);
  447                 break;
  448 
  449         case SIOCDIFPHYADDR:
  450                 etherip_delete_tunnel(ifp);
  451                 error = 0;
  452                 break;
  453 
  454         case SIOCGLIFPHYADDR:
  455                 if (sc->sc_src == NULL || sc->sc_dst == NULL)
  456                         return EADDRNOTAVAIL;
  457 
  458                 /* copy src */
  459                 src = sc->sc_src;
  460                 dst = (struct sockaddr *)
  461                         &(((struct if_laddrreq *)data)->addr);
  462                 if (src->sa_len > sizeof(((struct if_laddrreq *)data)->addr))
  463                         return EINVAL;
  464                 memcpy(dst, src, src->sa_len);
  465 
  466                 /* copy dst */
  467                 src = sc->sc_dst;
  468                 dst = (struct sockaddr *)
  469                         &(((struct if_laddrreq *)data)->dstaddr);
  470                 if (src->sa_len > sizeof(((struct if_laddrreq *)data)->dstaddr))
  471                         return EINVAL;
  472                 memcpy(dst, src, src->sa_len);
  473 
  474                 error = 0;
  475                 break;
  476 
  477         case SIOCSIFMEDIA:
  478         case SIOCGIFMEDIA:
  479                 s = splnet();
  480                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_im, cmd);
  481                 splx(s);
  482                 break;
  483 
  484         default:
  485                 s = splnet();
  486                 error = ether_ioctl(ifp, cmd, data);
  487                 splx(s);
  488                 if (error == ENETRESET)
  489                         error = 0;
  490                 break;
  491         }
  492         
  493         return (error);
  494 }
  495 
  496 static int
  497 etherip_set_tunnel(struct ifnet *ifp, 
  498                    struct sockaddr *src, 
  499                    struct sockaddr *dst)
  500 {
  501         struct etherip_softc *sc = (struct etherip_softc *)ifp->if_softc;
  502         struct etherip_softc *sc2;
  503         struct sockaddr *osrc, *odst;
  504         int s, error = 0;
  505 
  506         s = splsoftnet();
  507 
  508         LIST_FOREACH(sc2, &etherip_softc_list, etherip_list) {
  509                 if (sc2 == sc)
  510                         continue;
  511                 if (!sc2->sc_dst || !sc2->sc_src)
  512                         continue;
  513                 if (sc2->sc_dst->sa_family != dst->sa_family ||
  514                     sc2->sc_dst->sa_len    != dst->sa_len    ||
  515                     sc2->sc_src->sa_family != src->sa_family ||
  516                     sc2->sc_src->sa_len    != src->sa_len)
  517                         continue;
  518                 /* can't configure same pair of address onto two tunnels */
  519                 if (bcmp(sc2->sc_dst, dst, dst->sa_len) == 0 &&
  520                     bcmp(sc2->sc_src, src, src->sa_len) == 0) {
  521                         error = EADDRNOTAVAIL;
  522                         goto out;
  523                 }
  524                 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
  525         }
  526 
  527 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  528         if (sc->sc_si) {
  529                 softintr_disestablish(sc->sc_si);
  530                 sc->sc_si = NULL;
  531         }
  532 #endif
  533 
  534         ifp->if_flags &= ~IFF_RUNNING;
  535 
  536         osrc = sc->sc_src; sc->sc_src = NULL;
  537         odst = sc->sc_dst; sc->sc_dst = NULL;
  538 
  539         sc->sc_src = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
  540         memcpy(sc->sc_src, src, src->sa_len);
  541         if (osrc) FREE(osrc, M_IFADDR);
  542 
  543         sc->sc_dst = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
  544         memcpy(sc->sc_dst, dst, dst->sa_len);
  545         if (odst) FREE(odst, M_IFADDR);
  546 
  547         ifp->if_flags |= IFF_RUNNING;
  548 
  549 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  550         sc->sc_si = softintr_establish(IPL_SOFTNET, etheripintr, sc);
  551         if (sc->sc_si == NULL)
  552                 error = ENOMEM;
  553 #endif
  554 
  555 out:
  556         splx(s);
  557 
  558         return(error);
  559 }
  560 
  561 static void
  562 etherip_delete_tunnel(struct ifnet *ifp)
  563 {
  564         struct etherip_softc *sc = (struct etherip_softc *)ifp->if_softc;
  565         int s;
  566 
  567         s = splsoftnet();
  568 
  569 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  570         if (sc->sc_si) {
  571                 softintr_disestablish(sc->sc_si);
  572                 sc->sc_si = NULL;
  573         }
  574 #endif
  575 
  576         if (sc->sc_src) {
  577                 FREE(sc->sc_src, M_IFADDR);
  578                 sc->sc_src = NULL;
  579         }
  580         if (sc->sc_dst) {
  581                 FREE(sc->sc_dst, M_IFADDR);
  582                 sc->sc_dst = NULL;
  583         }
  584 
  585         ifp->if_flags &= ~IFF_RUNNING;
  586         splx(s);
  587 }
  588 
  589 static int
  590 etherip_init(struct ifnet *ifp)
  591 {
  592 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  593         struct etherip_softc *sc = ifp->if_softc;
  594 
  595         if (sc->sc_si == NULL)
  596                 sc->sc_si = softintr_establish(IPL_SOFTNET, etheripintr, sc);
  597 
  598         if (sc->sc_si == NULL)
  599                 return(ENOMEM);
  600 #endif
  601 
  602         ifp->if_flags |= IFF_RUNNING;
  603         etherip_start(ifp);
  604 
  605         return 0;
  606 }
  607 
  608 static void
  609 etherip_stop(struct ifnet *ifp, int disable)
  610 {
  611         ifp->if_flags &= ~IFF_RUNNING;
  612 }
  613 
  614 static int
  615 etherip_clone_create(struct if_clone *ifc, int unit)
  616 {
  617         struct cfdata *cf;
  618 
  619         MALLOC(cf, struct cfdata *, sizeof(struct cfdata), M_DEVBUF, M_WAITOK);
  620         cf->cf_name   = etherip_cd.cd_name;
  621         cf->cf_atname = etherip_ca.ca_name;
  622         cf->cf_unit   = unit;
  623         cf->cf_fstate = FSTATE_STAR;
  624 
  625         if (config_attach_pseudo(cf) == NULL) {
  626                 aprint_error("%s%d: unable to attach an instance\n",
  627                              etherip_cd.cd_name, unit);
  628                 return (ENXIO);
  629         }
  630 
  631         return 0;
  632 }
  633 
  634 static int
  635 etherip_clone_destroy(struct ifnet *ifp)
  636 {
  637         struct device *dev = (struct device *)ifp->if_softc;
  638         struct cfdata *cf = device_cfdata(dev);
  639         int error;
  640 
  641         if ((error = config_detach(dev, 0)) != 0)
  642                 aprint_error("%s: unable to detach instance\n",
  643                              dev->dv_xname);
  644         FREE(cf, M_DEVBUF);
  645 
  646         return error;
  647 }
  648 
  649 SYSCTL_SETUP(sysctl_etherip_setup, "sysctl net.link.etherip subtree setup")
  650 {
  651         const struct sysctlnode *node;
  652         int error = 0;
  653 
  654         error = sysctl_createv(clog, 0, NULL, NULL,
  655                                CTLFLAG_PERMANENT,
  656                                CTLTYPE_NODE, "net", NULL,
  657                                NULL, 0, NULL, 0,
  658                                CTL_NET, CTL_EOL);
  659         if (error)
  660                 return;
  661 
  662         error = sysctl_createv(clog, 0, NULL, NULL,
  663                                CTLFLAG_PERMANENT,
  664                                CTLTYPE_NODE, "link", NULL,
  665                                NULL, 0, NULL, 0,
  666                                CTL_NET, AF_LINK, CTL_EOL);
  667         if (error)
  668                 return;
  669 
  670         error = sysctl_createv(clog, 0, NULL, &node,
  671                                CTLFLAG_PERMANENT,
  672                                CTLTYPE_NODE, "etherip", NULL,
  673                                NULL, 0, NULL, 0,
  674                                CTL_NET, AF_LINK, CTL_CREATE, CTL_EOL);
  675         if (error)
  676                 return;
  677 
  678         etherip_node = node->sysctl_num;
  679 }
  680 
  681 static int
  682 etherip_sysctl_handler(SYSCTLFN_ARGS)
  683 {
  684         struct sysctlnode node;
  685         struct etherip_softc *sc;
  686         struct ifnet *ifp;
  687         int error;
  688         size_t len;
  689         char addr[3 * ETHER_ADDR_LEN];
  690 
  691         node = *rnode;
  692         sc = node.sysctl_data;
  693         ifp = &sc->sc_ec.ec_if;
  694         (void)ether_snprintf(addr, sizeof(addr), LLADDR(ifp->if_sadl));
  695         node.sysctl_data = addr;
  696         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  697         if (error || newp == NULL)
  698                 return error;
  699 
  700         len = strlen(addr);
  701         if (len < 11 || len > 17)
  702                 return EINVAL;
  703 
  704         /* Commit change */
  705         if (ether_nonstatic_aton(LLADDR(ifp->if_sadl), addr) != 0)
  706                 return EINVAL;
  707 
  708         return error;
  709 }
  710 

Cache object: 66c855d6d6170ae5a74e815ef0fd73df


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