1*ae50415aSskrll /* $NetBSD: if_gif.c,v 1.159 2024/09/15 09:46:45 skrll Exp $ */ 2e556ec90Sitojun /* $KAME: if_gif.c,v 1.76 2001/08/20 02:01:02 kjc Exp $ */ 38789e600Sitojun 474d3c214Sitojun /* 574d3c214Sitojun * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 674d3c214Sitojun * All rights reserved. 774d3c214Sitojun * 874d3c214Sitojun * Redistribution and use in source and binary forms, with or without 974d3c214Sitojun * modification, are permitted provided that the following conditions 1074d3c214Sitojun * are met: 1174d3c214Sitojun * 1. Redistributions of source code must retain the above copyright 1274d3c214Sitojun * notice, this list of conditions and the following disclaimer. 1374d3c214Sitojun * 2. Redistributions in binary form must reproduce the above copyright 1474d3c214Sitojun * notice, this list of conditions and the following disclaimer in the 1574d3c214Sitojun * documentation and/or other materials provided with the distribution. 1674d3c214Sitojun * 3. Neither the name of the project nor the names of its contributors 1774d3c214Sitojun * may be used to endorse or promote products derived from this software 1874d3c214Sitojun * without specific prior written permission. 1974d3c214Sitojun * 2074d3c214Sitojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2174d3c214Sitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2274d3c214Sitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2374d3c214Sitojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2474d3c214Sitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2574d3c214Sitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2674d3c214Sitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2774d3c214Sitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2874d3c214Sitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2974d3c214Sitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3074d3c214Sitojun * SUCH DAMAGE. 3174d3c214Sitojun */ 3274d3c214Sitojun 3334d65a34Slukem #include <sys/cdefs.h> 34*ae50415aSskrll __KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.159 2024/09/15 09:46:45 skrll Exp $"); 3534d65a34Slukem 361c4a50f1Spooka #ifdef _KERNEL_OPT 3774d3c214Sitojun #include "opt_inet.h" 386284b358Sknakahara #include "opt_net_mpsafe.h" 391c4a50f1Spooka #endif 4074d3c214Sitojun 4174d3c214Sitojun #include <sys/param.h> 4274d3c214Sitojun #include <sys/systm.h> 43ffb7fabaSriastradh #include <sys/atomic.h> 4474d3c214Sitojun #include <sys/kernel.h> 4574d3c214Sitojun #include <sys/mbuf.h> 4674d3c214Sitojun #include <sys/socket.h> 4774d3c214Sitojun #include <sys/sockio.h> 4874d3c214Sitojun #include <sys/errno.h> 4974d3c214Sitojun #include <sys/ioctl.h> 5074d3c214Sitojun #include <sys/time.h> 51de7496deSmartin #include <sys/socketvar.h> 5274d3c214Sitojun #include <sys/syslog.h> 534a0283d9Smartin #include <sys/proc.h> 5446ed8f7dSad #include <sys/cpu.h> 5546ed8f7dSad #include <sys/intr.h> 56849e83faSknakahara #include <sys/kmem.h> 571c5d304eSknakahara #include <sys/sysctl.h> 58d81cd78eSknakahara #include <sys/xcall.h> 591d8e08d4Schristos #include <sys/device.h> 601d8e08d4Schristos #include <sys/module.h> 61493e35e3Sknakahara #include <sys/mutex.h> 62493e35e3Sknakahara #include <sys/pserialize.h> 63493e35e3Sknakahara #include <sys/psref.h> 6474d3c214Sitojun 6574d3c214Sitojun #include <net/if.h> 6674d3c214Sitojun #include <net/if_types.h> 6774d3c214Sitojun #include <net/route.h> 6874d3c214Sitojun #include <net/bpf.h> 6974d3c214Sitojun 7074d3c214Sitojun #include <netinet/in.h> 7174d3c214Sitojun #include <netinet/in_systm.h> 7274d3c214Sitojun #include <netinet/ip.h> 73dcfe05e7Sitojun #ifdef INET 74dcfe05e7Sitojun #include <netinet/in_var.h> 7574d3c214Sitojun #endif /* INET */ 76fffd2322Schristos #include <netinet/in_gif.h> 7774d3c214Sitojun 7874d3c214Sitojun #ifdef INET6 7974d3c214Sitojun #ifndef INET 8074d3c214Sitojun #include <netinet/in.h> 8174d3c214Sitojun #endif 8274d3c214Sitojun #include <netinet6/in6_var.h> 8374d3c214Sitojun #include <netinet/ip6.h> 8474d3c214Sitojun #include <netinet6/ip6_var.h> 8574d3c214Sitojun #include <netinet6/in6_gif.h> 8674d3c214Sitojun #endif /* INET6 */ 8774d3c214Sitojun 8839091335Sitojun #include <netinet/ip_encap.h> 8974d3c214Sitojun #include <net/if_gif.h> 9074d3c214Sitojun 91e7ae23fdSchristos #include "ioconf.h" 92e7ae23fdSchristos 936284b358Sknakahara #ifdef NET_MPSAFE 946284b358Sknakahara #define GIF_MPSAFE 1 956284b358Sknakahara #endif 966284b358Sknakahara 9774d3c214Sitojun /* 9874d3c214Sitojun * gif global variable definitions 9974d3c214Sitojun */ 1001cc266b8Sknakahara static struct { 101b801416bSmsaitoh LIST_HEAD(gif_sclist, gif_softc) list; 1021cc266b8Sknakahara kmutex_t lock; 1031cc266b8Sknakahara } gif_softcs __cacheline_aligned; 104b36ce94cSthorpej 105493e35e3Sknakahara struct psref_class *gv_psref_class __read_mostly; 106493e35e3Sknakahara 1077128a14dSknakahara static pktq_rps_hash_func_t gif_pktq_rps_hash_p; 1087128a14dSknakahara 109916c83eeSmsaitoh static int gifattach0(struct gif_softc *); 110d60d8acaSknakahara static int gif_output(struct ifnet *, struct mbuf *, 111d60d8acaSknakahara const struct sockaddr *, const struct rtentry *); 112ccd8e6e6Sknakahara static void gif_start(struct ifnet *); 1137216411eSknakahara static int gif_transmit(struct ifnet *, struct mbuf *); 114493e35e3Sknakahara static int gif_transmit_direct(struct gif_variant *, struct mbuf *); 115d60d8acaSknakahara static int gif_ioctl(struct ifnet *, u_long, void *); 116d60d8acaSknakahara static int gif_set_tunnel(struct ifnet *, struct sockaddr *, 117d60d8acaSknakahara struct sockaddr *); 118d60d8acaSknakahara static void gif_delete_tunnel(struct ifnet *); 119d60d8acaSknakahara 12063eac52bSthorpej static int gif_clone_create(struct if_clone *, int); 12163eac52bSthorpej static int gif_clone_destroy(struct ifnet *); 122c705cd3cSknakahara static int gif_check_nesting(struct ifnet *, struct mbuf *); 123b36ce94cSthorpej 124493e35e3Sknakahara static int gif_encap_attach(struct gif_variant *); 125493e35e3Sknakahara static int gif_encap_detach(struct gif_variant *); 126493e35e3Sknakahara 127493e35e3Sknakahara static void gif_update_variant(struct gif_softc *, struct gif_variant *); 128d81cd78eSknakahara 12963eac52bSthorpej static struct if_clone gif_cloner = 130b36ce94cSthorpej IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy); 131b36ce94cSthorpej 13239091335Sitojun #ifndef MAX_GIF_NEST 13339091335Sitojun /* 13439091335Sitojun * This macro controls the upper limitation on nesting of gif tunnels. 13539091335Sitojun * Since, setting a large value to this macro with a careless configuration 13639091335Sitojun * may introduce system crash, we don't allow any nestings by default. 13739091335Sitojun * If you need to configure nested gif tunnels, you can define this macro 13839091335Sitojun * in your kernel configuration file. However, if you do so, please be 13939091335Sitojun * careful to configure the tunnels so that it won't make a loop. 14039091335Sitojun */ 14139091335Sitojun #define MAX_GIF_NEST 1 14239091335Sitojun #endif 14339091335Sitojun static int max_gif_nesting = MAX_GIF_NEST; 14474d3c214Sitojun 1451d8e08d4Schristos static struct sysctllog *gif_sysctl; 1461d8e08d4Schristos 14770414ea5Sknakahara #ifdef INET6 14870414ea5Sknakahara static int 14970414ea5Sknakahara sysctl_gif_pmtu_global(SYSCTLFN_ARGS) 15070414ea5Sknakahara { 15170414ea5Sknakahara int error, pmtu; 15270414ea5Sknakahara struct sysctlnode node = *rnode; 15370414ea5Sknakahara 15470414ea5Sknakahara pmtu = ip6_gif_pmtu; 15570414ea5Sknakahara node.sysctl_data = &pmtu; 15670414ea5Sknakahara error = sysctl_lookup(SYSCTLFN_CALL(&node)); 15770414ea5Sknakahara if (error || newp == NULL) 15870414ea5Sknakahara return error; 15970414ea5Sknakahara 16070414ea5Sknakahara switch (pmtu) { 16170414ea5Sknakahara case GIF_PMTU_MINMTU: 16270414ea5Sknakahara case GIF_PMTU_OUTERMTU: 16370414ea5Sknakahara ip6_gif_pmtu = pmtu; 16470414ea5Sknakahara break; 16570414ea5Sknakahara default: 16670414ea5Sknakahara return EINVAL; 16770414ea5Sknakahara } 16870414ea5Sknakahara 16970414ea5Sknakahara return 0; 17070414ea5Sknakahara } 17170414ea5Sknakahara 17270414ea5Sknakahara static int 17370414ea5Sknakahara sysctl_gif_pmtu_perif(SYSCTLFN_ARGS) 17470414ea5Sknakahara { 17570414ea5Sknakahara int error, pmtu; 17670414ea5Sknakahara struct sysctlnode node = *rnode; 17770414ea5Sknakahara struct gif_softc *sc = (struct gif_softc *)node.sysctl_data; 17870414ea5Sknakahara 17970414ea5Sknakahara pmtu = sc->gif_pmtu; 18070414ea5Sknakahara node.sysctl_data = &pmtu; 18170414ea5Sknakahara error = sysctl_lookup(SYSCTLFN_CALL(&node)); 18270414ea5Sknakahara if (error || newp == NULL) 18370414ea5Sknakahara return error; 18470414ea5Sknakahara 18570414ea5Sknakahara switch (pmtu) { 18670414ea5Sknakahara case GIF_PMTU_SYSDEFAULT: 18770414ea5Sknakahara case GIF_PMTU_MINMTU: 18870414ea5Sknakahara case GIF_PMTU_OUTERMTU: 18970414ea5Sknakahara sc->gif_pmtu = pmtu; 19070414ea5Sknakahara break; 19170414ea5Sknakahara default: 19270414ea5Sknakahara return EINVAL; 19370414ea5Sknakahara } 19470414ea5Sknakahara 19570414ea5Sknakahara return 0; 19670414ea5Sknakahara } 19770414ea5Sknakahara #endif 19870414ea5Sknakahara 1991c5d304eSknakahara static void 2001d8e08d4Schristos gif_sysctl_setup(void) 2011c5d304eSknakahara { 2027128a14dSknakahara const struct sysctlnode *node = NULL; 2037128a14dSknakahara 2041d8e08d4Schristos gif_sysctl = NULL; 2051c5d304eSknakahara 2061c5d304eSknakahara #ifdef INET 2077b53554dSknakahara /* 2087b53554dSknakahara * Previously create "net.inet.ip" entry to avoid sysctl_createv error. 2097b53554dSknakahara */ 2107b53554dSknakahara sysctl_createv(NULL, 0, NULL, NULL, 2117b53554dSknakahara CTLFLAG_PERMANENT, 2127b53554dSknakahara CTLTYPE_NODE, "inet", 2137b53554dSknakahara SYSCTL_DESCR("PF_INET related settings"), 2147b53554dSknakahara NULL, 0, NULL, 0, 2157b53554dSknakahara CTL_NET, PF_INET, CTL_EOL); 2167b53554dSknakahara sysctl_createv(NULL, 0, NULL, NULL, 2177b53554dSknakahara CTLFLAG_PERMANENT, 2187b53554dSknakahara CTLTYPE_NODE, "ip", 2197b53554dSknakahara SYSCTL_DESCR("IPv4 related settings"), 2207b53554dSknakahara NULL, 0, NULL, 0, 2217b53554dSknakahara CTL_NET, PF_INET, IPPROTO_IP, CTL_EOL); 2227b53554dSknakahara 2231d8e08d4Schristos sysctl_createv(&gif_sysctl, 0, NULL, NULL, 2241c5d304eSknakahara CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 2251c5d304eSknakahara CTLTYPE_INT, "gifttl", 2261c5d304eSknakahara SYSCTL_DESCR("Default TTL for a gif tunnel datagram"), 2271c5d304eSknakahara NULL, 0, &ip_gif_ttl, 0, 2281c5d304eSknakahara CTL_NET, PF_INET, IPPROTO_IP, 2291c5d304eSknakahara IPCTL_GIF_TTL, CTL_EOL); 2301c5d304eSknakahara #endif 2311c5d304eSknakahara #ifdef INET6 2327b53554dSknakahara /* 2337b53554dSknakahara * Previously create "net.inet6.ip6" entry to avoid sysctl_createv error. 2347b53554dSknakahara */ 2357b53554dSknakahara sysctl_createv(NULL, 0, NULL, NULL, 2367b53554dSknakahara CTLFLAG_PERMANENT, 2377b53554dSknakahara CTLTYPE_NODE, "inet6", 2387b53554dSknakahara SYSCTL_DESCR("PF_INET6 related settings"), 2397b53554dSknakahara NULL, 0, NULL, 0, 2407b53554dSknakahara CTL_NET, PF_INET6, CTL_EOL); 2417b53554dSknakahara sysctl_createv(NULL, 0, NULL, NULL, 2427b53554dSknakahara CTLFLAG_PERMANENT, 2437b53554dSknakahara CTLTYPE_NODE, "ip6", 2447b53554dSknakahara SYSCTL_DESCR("IPv6 related settings"), 2457b53554dSknakahara NULL, 0, NULL, 0, 2467b53554dSknakahara CTL_NET, PF_INET6, IPPROTO_IPV6, CTL_EOL); 2477b53554dSknakahara 2481d8e08d4Schristos sysctl_createv(&gif_sysctl, 0, NULL, NULL, 2491c5d304eSknakahara CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 2501c5d304eSknakahara CTLTYPE_INT, "gifhlim", 2511c5d304eSknakahara SYSCTL_DESCR("Default hop limit for a gif tunnel datagram"), 2521c5d304eSknakahara NULL, 0, &ip6_gif_hlim, 0, 2531c5d304eSknakahara CTL_NET, PF_INET6, IPPROTO_IPV6, 2541c5d304eSknakahara IPV6CTL_GIF_HLIM, CTL_EOL); 25570414ea5Sknakahara 25670414ea5Sknakahara sysctl_createv(&gif_sysctl, 0, NULL, NULL, 25770414ea5Sknakahara CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 25870414ea5Sknakahara CTLTYPE_INT, "gifpmtu", 25970414ea5Sknakahara SYSCTL_DESCR("Default Path MTU setting for gif tunnels"), 26070414ea5Sknakahara sysctl_gif_pmtu_global, 0, NULL, 0, 26170414ea5Sknakahara CTL_NET, PF_INET6, IPPROTO_IPV6, 26270414ea5Sknakahara IPV6CTL_GIF_PMTU, CTL_EOL); 26370414ea5Sknakahara #endif 2647128a14dSknakahara 2657128a14dSknakahara sysctl_createv(&gif_sysctl, 0, NULL, &node, 2667128a14dSknakahara CTLFLAG_PERMANENT, 2677128a14dSknakahara CTLTYPE_NODE, "gif", 2687128a14dSknakahara SYSCTL_DESCR("gif global control"), 2697128a14dSknakahara NULL, 0, NULL, 0, 2707128a14dSknakahara CTL_NET, CTL_CREATE, CTL_EOL); 2717128a14dSknakahara 2727128a14dSknakahara sysctl_createv(&gif_sysctl, 0, &node, NULL, 2737128a14dSknakahara CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 2747128a14dSknakahara CTLTYPE_STRING, "rps_hash", 2757128a14dSknakahara SYSCTL_DESCR("Interface rps hash function control"), 2767128a14dSknakahara sysctl_pktq_rps_hash_handler, 0, (void *)&gif_pktq_rps_hash_p, 2777128a14dSknakahara PKTQ_RPS_HASH_NAME_LEN, 2787128a14dSknakahara CTL_CREATE, CTL_EOL); 27970414ea5Sknakahara } 28070414ea5Sknakahara 28170414ea5Sknakahara static void 28270414ea5Sknakahara gif_perif_sysctl_setup(struct sysctllog **clog, struct gif_softc *sc) 28370414ea5Sknakahara { 28470414ea5Sknakahara #ifdef INET6 28570414ea5Sknakahara const struct sysctlnode *cnode, *rnode; 28670414ea5Sknakahara struct ifnet *ifp = &sc->gif_if; 28770414ea5Sknakahara const char *ifname = ifp->if_xname; 28870414ea5Sknakahara int rv; 28970414ea5Sknakahara 29070414ea5Sknakahara /* 29170414ea5Sknakahara * Already created in sysctl_sndq_setup(). 29270414ea5Sknakahara */ 29370414ea5Sknakahara sysctl_createv(clog, 0, NULL, &rnode, 29470414ea5Sknakahara CTLFLAG_PERMANENT, 29570414ea5Sknakahara CTLTYPE_NODE, "interfaces", 29670414ea5Sknakahara SYSCTL_DESCR("Per-interface controls"), 29770414ea5Sknakahara NULL, 0, NULL, 0, 29870414ea5Sknakahara CTL_NET, CTL_CREATE, CTL_EOL); 29970414ea5Sknakahara sysctl_createv(clog, 0, &rnode, &rnode, 30070414ea5Sknakahara CTLFLAG_PERMANENT, 30170414ea5Sknakahara CTLTYPE_NODE, ifname, 30270414ea5Sknakahara SYSCTL_DESCR("Interface controls"), 30370414ea5Sknakahara NULL, 0, NULL, 0, 30470414ea5Sknakahara CTL_CREATE, CTL_EOL); 30570414ea5Sknakahara 30670414ea5Sknakahara rv = sysctl_createv(clog, 0, &rnode, &cnode, 30770414ea5Sknakahara CTLFLAG_PERMANENT, 30870414ea5Sknakahara CTLTYPE_INT, "pmtu", 30970414ea5Sknakahara SYSCTL_DESCR("Path MTU setting for this gif tunnel"), 31070414ea5Sknakahara sysctl_gif_pmtu_perif, 0, (void *)sc, 0, 31170414ea5Sknakahara CTL_CREATE, CTL_EOL); 31270414ea5Sknakahara if (rv != 0) 31370414ea5Sknakahara log(LOG_WARNING, "%s: could not attach sysctl node pmtu\n", ifname); 31470414ea5Sknakahara 31570414ea5Sknakahara sc->gif_pmtu = GIF_PMTU_SYSDEFAULT; 3161c5d304eSknakahara #endif 3171c5d304eSknakahara } 3181c5d304eSknakahara 319b36ce94cSthorpej /* ARGSUSED */ 32074d3c214Sitojun void 321168cd830Schristos gifattach(int count) 32274d3c214Sitojun { 3231d8e08d4Schristos /* 3241d8e08d4Schristos * Nothing to do here, initialization is handled by the 3251d8e08d4Schristos * module initialization code in gifinit() below). 3261d8e08d4Schristos */ 3271d8e08d4Schristos } 3281d8e08d4Schristos 3291d8e08d4Schristos static void 3301d8e08d4Schristos gifinit(void) 3311d8e08d4Schristos { 33274d3c214Sitojun 3331cc266b8Sknakahara mutex_init(&gif_softcs.lock, MUTEX_DEFAULT, IPL_NONE); 3341cc266b8Sknakahara LIST_INIT(&gif_softcs.list); 335b36ce94cSthorpej if_clone_attach(&gif_cloner); 3361c5d304eSknakahara 337493e35e3Sknakahara gv_psref_class = psref_class_create("gifvar", IPL_SOFTNET); 338493e35e3Sknakahara 3397128a14dSknakahara gif_pktq_rps_hash_p = pktq_rps_hash_default; 3401d8e08d4Schristos gif_sysctl_setup(); 3411d8e08d4Schristos } 3421d8e08d4Schristos 3431d8e08d4Schristos static int 3441d8e08d4Schristos gifdetach(void) 3451d8e08d4Schristos { 3461d8e08d4Schristos 3471cc266b8Sknakahara mutex_enter(&gif_softcs.lock); 3481cc266b8Sknakahara if (!LIST_EMPTY(&gif_softcs.list)) { 3491cc266b8Sknakahara mutex_exit(&gif_softcs.lock); 350c3bbf81dSchristos return EBUSY; 3511cc266b8Sknakahara } 3521d8e08d4Schristos 353493e35e3Sknakahara psref_class_destroy(gv_psref_class); 354493e35e3Sknakahara 3551d8e08d4Schristos if_clone_detach(&gif_cloner); 3561d8e08d4Schristos sysctl_teardown(&gif_sysctl); 357c3bbf81dSchristos mutex_exit(&gif_softcs.lock); 358c3bbf81dSchristos mutex_destroy(&gif_softcs.lock); 359c3bbf81dSchristos return 0; 360b36ce94cSthorpej } 361b36ce94cSthorpej 36263eac52bSthorpej static int 36363eac52bSthorpej gif_clone_create(struct if_clone *ifc, int unit) 364b36ce94cSthorpej { 365b36ce94cSthorpej struct gif_softc *sc; 366493e35e3Sknakahara struct gif_variant *var; 36770414ea5Sknakahara struct ifnet *ifp; 368916c83eeSmsaitoh int rv; 369b36ce94cSthorpej 370849e83faSknakahara sc = kmem_zalloc(sizeof(struct gif_softc), KM_SLEEP); 371b36ce94cSthorpej 372bc168f27Schristos if_initname(&sc->gif_if, ifc->ifc_name, unit); 37339091335Sitojun 374916c83eeSmsaitoh rv = gifattach0(sc); 375916c83eeSmsaitoh if (rv != 0) { 376916c83eeSmsaitoh kmem_free(sc, sizeof(struct gif_softc)); 377916c83eeSmsaitoh return rv; 378916c83eeSmsaitoh } 37939091335Sitojun 38070414ea5Sknakahara ifp = &sc->gif_if; 38170414ea5Sknakahara gif_perif_sysctl_setup(&ifp->if_sysctl_log, sc); 38270414ea5Sknakahara 383493e35e3Sknakahara var = kmem_zalloc(sizeof(*var), KM_SLEEP); 384493e35e3Sknakahara var->gv_softc = sc; 385493e35e3Sknakahara psref_target_init(&var->gv_psref, gv_psref_class); 386493e35e3Sknakahara 387493e35e3Sknakahara sc->gif_var = var; 388493e35e3Sknakahara mutex_init(&sc->gif_lock, MUTEX_DEFAULT, IPL_NONE); 389ebac3c72Sknakahara sc->gif_psz = pserialize_create(); 390ebac3c72Sknakahara 3912da350beSknakahara sc->gif_ro_percpu = if_tunnel_alloc_ro_percpu(); 3921cc266b8Sknakahara mutex_enter(&gif_softcs.lock); 3931cc266b8Sknakahara LIST_INSERT_HEAD(&gif_softcs.list, sc, gif_list); 3941cc266b8Sknakahara mutex_exit(&gif_softcs.lock); 395916c83eeSmsaitoh return 0; 396cad488d0Sitojun } 397cad488d0Sitojun 398916c83eeSmsaitoh static int 39963eac52bSthorpej gifattach0(struct gif_softc *sc) 400cad488d0Sitojun { 401cad488d0Sitojun 402cad488d0Sitojun sc->gif_if.if_addrlen = 0; 40374d3c214Sitojun sc->gif_if.if_mtu = GIF_MTU; 40474d3c214Sitojun sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 4054ba8ad0bSknakahara #ifdef GIF_MPSAFE 406ab3cd725Sozaki-r sc->gif_if.if_extflags |= IFEF_MPSAFE; 4074ba8ad0bSknakahara #endif 40874d3c214Sitojun sc->gif_if.if_ioctl = gif_ioctl; 40974d3c214Sitojun sc->gif_if.if_output = gif_output; 4107216411eSknakahara sc->gif_if.if_start = gif_start; 4117216411eSknakahara sc->gif_if.if_transmit = gif_transmit; 41274d3c214Sitojun sc->gif_if.if_type = IFT_GIF; 413ed7695a7Sthorpej sc->gif_if.if_dlt = DLT_NULL; 414de87fe67Sdyoung sc->gif_if.if_softc = sc; 415e556ec90Sitojun IFQ_SET_READY(&sc->gif_if.if_snd); 416076e3579Sriastradh if_initialize(&sc->gif_if); 417916c83eeSmsaitoh 418680a94beSroy sc->gif_if.if_link_state = LINK_STATE_DOWN; 419fc5dafc7Sthorpej if_alloc_sadl(&sc->gif_if); 42058e86755Sjoerg bpf_attach(&sc->gif_if, DLT_NULL, sizeof(u_int)); 42174ffb1c2Sozaki-r if_register(&sc->gif_if); 422916c83eeSmsaitoh return 0; 42339091335Sitojun } 424b36ce94cSthorpej 42563eac52bSthorpej static int 42663eac52bSthorpej gif_clone_destroy(struct ifnet *ifp) 427b36ce94cSthorpej { 428b36ce94cSthorpej struct gif_softc *sc = (void *) ifp; 429493e35e3Sknakahara struct gif_variant *var; 430b36ce94cSthorpej 431b36ce94cSthorpej LIST_REMOVE(sc, gif_list); 432b36ce94cSthorpej 43348ec8fb3Sknakahara gif_delete_tunnel(&sc->gif_if); 43458e86755Sjoerg bpf_detach(ifp); 435b36ce94cSthorpej if_detach(ifp); 43656188c2aSknakahara 4372da350beSknakahara if_tunnel_free_ro_percpu(sc->gif_ro_percpu); 43856188c2aSknakahara 439ebac3c72Sknakahara pserialize_destroy(sc->gif_psz); 440493e35e3Sknakahara mutex_destroy(&sc->gif_lock); 441493e35e3Sknakahara 442493e35e3Sknakahara var = sc->gif_var; 443493e35e3Sknakahara kmem_free(var, sizeof(*var)); 444849e83faSknakahara kmem_free(sc, sizeof(struct gif_softc)); 445b9c49ebfSpeter 446916c83eeSmsaitoh return 0; 44739091335Sitojun } 44839091335Sitojun 449c8a83266Sitojun #ifdef GIF_ENCAPCHECK 450cad488d0Sitojun int 45163eac52bSthorpej gif_encapcheck(struct mbuf *m, int off, int proto, void *arg) 45239091335Sitojun { 45339091335Sitojun struct ip ip; 45439091335Sitojun struct gif_softc *sc; 455493e35e3Sknakahara struct gif_variant *var; 456493e35e3Sknakahara struct psref psref; 457493e35e3Sknakahara int ret = 0; 45839091335Sitojun 459de87fe67Sdyoung sc = arg; 46039091335Sitojun if (sc == NULL) 46139091335Sitojun return 0; 46239091335Sitojun 463753ed340Sknakahara if ((sc->gif_if.if_flags & IFF_UP) == 0) 46439091335Sitojun return 0; 46539091335Sitojun 466493e35e3Sknakahara var = gif_getref_variant(sc, &psref); 46739091335Sitojun /* no physical address */ 46819e3ef90Sknakahara if (var->gv_psrc == NULL || var->gv_pdst == NULL) 469493e35e3Sknakahara goto out; 47039091335Sitojun 47139091335Sitojun switch (proto) { 47239091335Sitojun #ifdef INET 47339091335Sitojun case IPPROTO_IPV4: 47439091335Sitojun break; 47539091335Sitojun #endif 47639091335Sitojun #ifdef INET6 47739091335Sitojun case IPPROTO_IPV6: 47839091335Sitojun break; 47939091335Sitojun #endif 48039091335Sitojun default: 481493e35e3Sknakahara goto out; 48239091335Sitojun } 48339091335Sitojun 4845c8e1817Schristos /* Bail on short packets */ 4855c8e1817Schristos KASSERT(m->m_flags & M_PKTHDR); 4865c8e1817Schristos if (m->m_pkthdr.len < sizeof(ip)) 487493e35e3Sknakahara goto out; 4885c8e1817Schristos 489de87fe67Sdyoung m_copydata(m, 0, sizeof(ip), &ip); 49039091335Sitojun 49139091335Sitojun switch (ip.ip_v) { 49239091335Sitojun #ifdef INET 49339091335Sitojun case 4: 494493e35e3Sknakahara if (var->gv_psrc->sa_family != AF_INET || 495493e35e3Sknakahara var->gv_pdst->sa_family != AF_INET) 496493e35e3Sknakahara goto out; 497493e35e3Sknakahara ret = gif_encapcheck4(m, off, proto, var); 498493e35e3Sknakahara break; 49939091335Sitojun #endif 50039091335Sitojun #ifdef INET6 50139091335Sitojun case 6: 50200f97b02Sitojun if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 503493e35e3Sknakahara goto out; 504493e35e3Sknakahara if (var->gv_psrc->sa_family != AF_INET6 || 505493e35e3Sknakahara var->gv_pdst->sa_family != AF_INET6) 506493e35e3Sknakahara goto out; 507493e35e3Sknakahara ret = gif_encapcheck6(m, off, proto, var); 508493e35e3Sknakahara break; 50939091335Sitojun #endif 51039091335Sitojun default: 511493e35e3Sknakahara goto out; 51274d3c214Sitojun } 513493e35e3Sknakahara 514493e35e3Sknakahara out: 515493e35e3Sknakahara gif_putref_variant(var, &psref); 516493e35e3Sknakahara return ret; 51774d3c214Sitojun } 518c8a83266Sitojun #endif 51974d3c214Sitojun 520c705cd3cSknakahara /* 521c705cd3cSknakahara * gif may cause infinite recursion calls when misconfigured. 522c705cd3cSknakahara * We'll prevent this by introducing upper limit. 523c705cd3cSknakahara */ 524c705cd3cSknakahara static int 525c705cd3cSknakahara gif_check_nesting(struct ifnet *ifp, struct mbuf *m) 526c705cd3cSknakahara { 527c705cd3cSknakahara 528d4228baeSknakahara return if_tunnel_check_nesting(ifp, m, max_gif_nesting); 529c705cd3cSknakahara } 530c705cd3cSknakahara 531d60d8acaSknakahara static int 5325493f188Sdyoung gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 5332cf7873bSozaki-r const struct rtentry *rt) 53474d3c214Sitojun { 535de87fe67Sdyoung struct gif_softc *sc = ifp->if_softc; 536493e35e3Sknakahara struct gif_variant *var = NULL; 537493e35e3Sknakahara struct psref psref; 53874d3c214Sitojun int error = 0; 53974ad87bcSitojun 540b76ec0b0Sknakahara IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family); 54174d3c214Sitojun 542c705cd3cSknakahara if ((error = gif_check_nesting(ifp, m)) != 0) { 543b17a3c6eSmaxv m_freem(m); 54474d3c214Sitojun goto end; 54574d3c214Sitojun } 54674d3c214Sitojun 547753ed340Sknakahara if ((ifp->if_flags & IFF_UP) == 0) { 54874d3c214Sitojun m_freem(m); 54974d3c214Sitojun error = ENETDOWN; 55074d3c214Sitojun goto end; 55174d3c214Sitojun } 55274d3c214Sitojun 553493e35e3Sknakahara var = gif_getref_variant(sc, &psref); 554493e35e3Sknakahara if (var->gv_psrc == NULL || var->gv_pdst == NULL) { 555493e35e3Sknakahara m_freem(m); 556493e35e3Sknakahara error = ENETDOWN; 557493e35e3Sknakahara goto end; 558493e35e3Sknakahara } 55939091335Sitojun /* XXX should we check if our outer source is legal? */ 56074d3c214Sitojun 561493e35e3Sknakahara m->m_flags &= ~(M_BCAST | M_MCAST); 562493e35e3Sknakahara 56374ad87bcSitojun /* use DLT_NULL encapsulation here to pass inner af type */ 56474ad87bcSitojun M_PREPEND(m, sizeof(int), M_DONTWAIT); 56574ad87bcSitojun if (!m) { 56674ad87bcSitojun error = ENOBUFS; 567cad488d0Sitojun goto end; 56874d3c214Sitojun } 56974ad87bcSitojun *mtod(m, int *) = dst->sa_family; 57074ad87bcSitojun 5710275d524Sdyoung /* Clear checksum-offload flags. */ 5720275d524Sdyoung m->m_pkthdr.csum_flags = 0; 5730275d524Sdyoung m->m_pkthdr.csum_data = 0; 5740275d524Sdyoung 57596d91f81Sknakahara error = if_transmit_lock(ifp, m); 57696d91f81Sknakahara 57774d3c214Sitojun end: 578493e35e3Sknakahara if (var != NULL) 579493e35e3Sknakahara gif_putref_variant(var, &psref); 580cad488d0Sitojun if (error) 58170b554e6Sthorpej if_statinc(ifp, if_oerrors); 58274d3c214Sitojun return error; 58374d3c214Sitojun } 58474d3c214Sitojun 58563eac52bSthorpej static void 586ccd8e6e6Sknakahara gif_start(struct ifnet *ifp) 58774ad87bcSitojun { 58874ad87bcSitojun struct gif_softc *sc; 589493e35e3Sknakahara struct gif_variant *var; 59074ad87bcSitojun struct mbuf *m; 591493e35e3Sknakahara struct psref psref; 59274ad87bcSitojun int family; 59374ad87bcSitojun int len; 59474ad87bcSitojun int error; 59574ad87bcSitojun 596ccd8e6e6Sknakahara sc = ifp->if_softc; 597493e35e3Sknakahara var = gif_getref_variant(sc, &psref); 598493e35e3Sknakahara 599493e35e3Sknakahara KASSERT(var->gv_output != NULL); 600a00e94f4Sknakahara 60174ad87bcSitojun /* output processing */ 60274ad87bcSitojun while (1) { 603e556ec90Sitojun IFQ_DEQUEUE(&sc->gif_if.if_snd, m); 60474ad87bcSitojun if (m == NULL) 60574ad87bcSitojun break; 60674ad87bcSitojun 60774ad87bcSitojun /* grab and chop off inner af type */ 60874ad87bcSitojun if (sizeof(int) > m->m_len) { 60974ad87bcSitojun m = m_pullup(m, sizeof(int)); 61074ad87bcSitojun if (!m) { 61170b554e6Sthorpej if_statinc(ifp, if_oerrors); 61274ad87bcSitojun continue; 61374ad87bcSitojun } 61474ad87bcSitojun } 61574ad87bcSitojun family = *mtod(m, int *); 6163cd62456Smsaitoh bpf_mtap(ifp, m, BPF_D_OUT); 61774ad87bcSitojun m_adj(m, sizeof(int)); 61874ad87bcSitojun 61974ad87bcSitojun len = m->m_pkthdr.len; 62074ad87bcSitojun 621493e35e3Sknakahara error = var->gv_output(var, family, m); 62274ad87bcSitojun if (error) 62370b554e6Sthorpej if_statinc(ifp, if_oerrors); 62470b554e6Sthorpej else 62570b554e6Sthorpej if_statadd2(ifp, if_opackets, 1, if_obytes, len); 62674ad87bcSitojun } 627493e35e3Sknakahara 628493e35e3Sknakahara gif_putref_variant(var, &psref); 62974ad87bcSitojun } 63074ad87bcSitojun 6317216411eSknakahara static int 6327216411eSknakahara gif_transmit(struct ifnet *ifp, struct mbuf *m) 6337216411eSknakahara { 6347216411eSknakahara struct gif_softc *sc; 635493e35e3Sknakahara struct gif_variant *var; 636493e35e3Sknakahara struct psref psref; 6377216411eSknakahara int error; 6387216411eSknakahara 6397216411eSknakahara sc = ifp->if_softc; 6407216411eSknakahara 6417216411eSknakahara /* output processing */ 6427216411eSknakahara if (m == NULL) 6437216411eSknakahara return EINVAL; 6447216411eSknakahara 645493e35e3Sknakahara var = gif_getref_variant(sc, &psref); 646493e35e3Sknakahara error = gif_transmit_direct(var, m); 647493e35e3Sknakahara gif_putref_variant(var, &psref); 648493e35e3Sknakahara 649493e35e3Sknakahara return error; 650493e35e3Sknakahara } 651493e35e3Sknakahara 652493e35e3Sknakahara static int 653493e35e3Sknakahara gif_transmit_direct(struct gif_variant *var, struct mbuf *m) 654493e35e3Sknakahara { 655493e35e3Sknakahara struct ifnet *ifp = &var->gv_softc->gif_if; 656493e35e3Sknakahara int error; 657493e35e3Sknakahara int family; 658493e35e3Sknakahara int len; 659493e35e3Sknakahara 660493e35e3Sknakahara KASSERT(gif_heldref_variant(var)); 661493e35e3Sknakahara KASSERT(var->gv_output != NULL); 662493e35e3Sknakahara 6637216411eSknakahara /* grab and chop off inner af type */ 6647216411eSknakahara if (sizeof(int) > m->m_len) { 6657216411eSknakahara m = m_pullup(m, sizeof(int)); 6667216411eSknakahara if (!m) { 66770b554e6Sthorpej if_statinc(ifp, if_oerrors); 6687216411eSknakahara return ENOBUFS; 6697216411eSknakahara } 6707216411eSknakahara } 6717216411eSknakahara family = *mtod(m, int *); 6723cd62456Smsaitoh bpf_mtap(ifp, m, BPF_D_OUT); 6737216411eSknakahara m_adj(m, sizeof(int)); 6747216411eSknakahara 6757216411eSknakahara len = m->m_pkthdr.len; 6767216411eSknakahara 677493e35e3Sknakahara error = var->gv_output(var, family, m); 6787216411eSknakahara if (error) 67970b554e6Sthorpej if_statinc(ifp, if_oerrors); 68070b554e6Sthorpej else 68170b554e6Sthorpej if_statadd2(ifp, if_opackets, 1, if_obytes, len); 6827216411eSknakahara 6837216411eSknakahara return error; 6847216411eSknakahara } 6857216411eSknakahara 68674ad87bcSitojun void 68763eac52bSthorpej gif_input(struct mbuf *m, int af, struct ifnet *ifp) 68874d3c214Sitojun { 68960d350cfSrmind pktqueue_t *pktq; 69060d350cfSrmind size_t pktlen; 69174d3c214Sitojun 69274ad87bcSitojun if (ifp == NULL) { 69374d3c214Sitojun /* just in case */ 69474d3c214Sitojun m_freem(m); 69574d3c214Sitojun return; 69674d3c214Sitojun } 69774d3c214Sitojun 698d938d837Sozaki-r m_set_rcvif(m, ifp); 69960d350cfSrmind pktlen = m->m_pkthdr.len; 70074d3c214Sitojun 7013cd62456Smsaitoh bpf_mtap_af(ifp, af, m, BPF_D_IN); 70274d3c214Sitojun 70374d3c214Sitojun /* 70474d3c214Sitojun * Put the packet to the network layer input queue according to the 70560d350cfSrmind * specified address family. Note: we avoid direct call to the 70660d350cfSrmind * input function of the network layer in order to avoid recursion. 70760d350cfSrmind * This may be revisited in the future. 70874d3c214Sitojun */ 70974d3c214Sitojun switch (af) { 71074d3c214Sitojun #ifdef INET 71174d3c214Sitojun case AF_INET: 71260d350cfSrmind pktq = ip_pktq; 71374d3c214Sitojun break; 71474d3c214Sitojun #endif 71574d3c214Sitojun #ifdef INET6 71674d3c214Sitojun case AF_INET6: 71760d350cfSrmind pktq = ip6_pktq; 71874d3c214Sitojun break; 71974d3c214Sitojun #endif 72074d3c214Sitojun default: 72174d3c214Sitojun m_freem(m); 72274d3c214Sitojun return; 72374d3c214Sitojun } 72474d3c214Sitojun 7257128a14dSknakahara const uint32_t h = pktq_rps_hash(&gif_pktq_rps_hash_p, m); 726cdd5bc98Sknakahara if (__predict_true(pktq_enqueue(pktq, m, h))) { 72770b554e6Sthorpej if_statadd2(ifp, if_ibytes, pktlen, if_ipackets, 1); 72860d350cfSrmind } else { 72960d350cfSrmind m_freem(m); 73060d350cfSrmind } 73174d3c214Sitojun } 73274d3c214Sitojun 73339091335Sitojun /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 734d60d8acaSknakahara static int 73553524e44Schristos gif_ioctl(struct ifnet *ifp, u_long cmd, void *data) 73674d3c214Sitojun { 737de87fe67Sdyoung struct gif_softc *sc = ifp->if_softc; 73874d3c214Sitojun struct ifreq *ifr = (struct ifreq*)data; 73933e035dcSroy struct ifaddr *ifa = (struct ifaddr*)data; 740493e35e3Sknakahara int error = 0, size, bound; 74139091335Sitojun struct sockaddr *dst, *src; 742493e35e3Sknakahara struct gif_variant *var; 743493e35e3Sknakahara struct psref psref; 74474d3c214Sitojun 74574d3c214Sitojun switch (cmd) { 746de87fe67Sdyoung case SIOCINITIFADDR: 74739bc63e6Sitojun ifp->if_flags |= IFF_UP; 74833e035dcSroy ifa->ifa_rtrequest = p2p_rtrequest; 74974d3c214Sitojun break; 75074d3c214Sitojun 75174d3c214Sitojun case SIOCADDMULTI: 75274d3c214Sitojun case SIOCDELMULTI: 75374d3c214Sitojun switch (ifr->ifr_addr.sa_family) { 75474d3c214Sitojun #ifdef INET 75574d3c214Sitojun case AF_INET: /* IP supports Multicast */ 75674d3c214Sitojun break; 75774d3c214Sitojun #endif /* INET */ 75874d3c214Sitojun #ifdef INET6 75974d3c214Sitojun case AF_INET6: /* IP6 supports Multicast */ 76074d3c214Sitojun break; 76174d3c214Sitojun #endif /* INET6 */ 76274d3c214Sitojun default: /* Other protocols doesn't support Multicast */ 76374d3c214Sitojun error = EAFNOSUPPORT; 76474d3c214Sitojun break; 76574d3c214Sitojun } 76674d3c214Sitojun break; 76774d3c214Sitojun 76874d3c214Sitojun case SIOCSIFMTU: 7692ccede0aSdyoung if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX) 7702ccede0aSdyoung return EINVAL; 7712ccede0aSdyoung else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) 7722ccede0aSdyoung error = 0; 77374d3c214Sitojun break; 77474d3c214Sitojun 775cad488d0Sitojun #ifdef INET 77674d3c214Sitojun case SIOCSIFPHYADDR: 777cad488d0Sitojun #endif 77874d3c214Sitojun #ifdef INET6 77974d3c214Sitojun case SIOCSIFPHYADDR_IN6: 78074d3c214Sitojun #endif /* INET6 */ 7811e48b7fbSitojun case SIOCSLIFPHYADDR: 782948e11b7Sitojun switch (cmd) { 783dcfe05e7Sitojun #ifdef INET 784948e11b7Sitojun case SIOCSIFPHYADDR: 78574d3c214Sitojun src = (struct sockaddr *) 78674d3c214Sitojun &(((struct in_aliasreq *)data)->ifra_addr); 78774d3c214Sitojun dst = (struct sockaddr *) 78874d3c214Sitojun &(((struct in_aliasreq *)data)->ifra_dstaddr); 789948e11b7Sitojun break; 790dcfe05e7Sitojun #endif 791948e11b7Sitojun #ifdef INET6 792948e11b7Sitojun case SIOCSIFPHYADDR_IN6: 793948e11b7Sitojun src = (struct sockaddr *) 794948e11b7Sitojun &(((struct in6_aliasreq *)data)->ifra_addr); 795948e11b7Sitojun dst = (struct sockaddr *) 796948e11b7Sitojun &(((struct in6_aliasreq *)data)->ifra_dstaddr); 797948e11b7Sitojun break; 798948e11b7Sitojun #endif 7991e48b7fbSitojun case SIOCSLIFPHYADDR: 8001e48b7fbSitojun src = (struct sockaddr *) 8011e48b7fbSitojun &(((struct if_laddrreq *)data)->addr); 8021e48b7fbSitojun dst = (struct sockaddr *) 8031e48b7fbSitojun &(((struct if_laddrreq *)data)->dstaddr); 804cad488d0Sitojun break; 805cad488d0Sitojun default: 806cad488d0Sitojun return EINVAL; 8071e48b7fbSitojun } 8081e48b7fbSitojun 8091e48b7fbSitojun /* sa_family must be equal */ 8101e48b7fbSitojun if (src->sa_family != dst->sa_family) 8111e48b7fbSitojun return EINVAL; 8121e48b7fbSitojun 8131e48b7fbSitojun /* validate sa_len */ 8141e48b7fbSitojun switch (src->sa_family) { 8151e48b7fbSitojun #ifdef INET 8161e48b7fbSitojun case AF_INET: 8171e48b7fbSitojun if (src->sa_len != sizeof(struct sockaddr_in)) 8181e48b7fbSitojun return EINVAL; 8191e48b7fbSitojun break; 8201e48b7fbSitojun #endif 8211e48b7fbSitojun #ifdef INET6 8221e48b7fbSitojun case AF_INET6: 8231e48b7fbSitojun if (src->sa_len != sizeof(struct sockaddr_in6)) 8241e48b7fbSitojun return EINVAL; 8251e48b7fbSitojun break; 8261e48b7fbSitojun #endif 8271e48b7fbSitojun default: 8281e48b7fbSitojun return EAFNOSUPPORT; 8291e48b7fbSitojun } 8301e48b7fbSitojun switch (dst->sa_family) { 8311e48b7fbSitojun #ifdef INET 8321e48b7fbSitojun case AF_INET: 8331e48b7fbSitojun if (dst->sa_len != sizeof(struct sockaddr_in)) 8341e48b7fbSitojun return EINVAL; 8351e48b7fbSitojun break; 8361e48b7fbSitojun #endif 8371e48b7fbSitojun #ifdef INET6 8381e48b7fbSitojun case AF_INET6: 8391e48b7fbSitojun if (dst->sa_len != sizeof(struct sockaddr_in6)) 8401e48b7fbSitojun return EINVAL; 8411e48b7fbSitojun break; 8421e48b7fbSitojun #endif 8431e48b7fbSitojun default: 8441e48b7fbSitojun return EAFNOSUPPORT; 8451e48b7fbSitojun } 8461e48b7fbSitojun 8471e48b7fbSitojun /* check sa_family looks sane for the cmd */ 8481e48b7fbSitojun switch (cmd) { 8491e48b7fbSitojun case SIOCSIFPHYADDR: 8501e48b7fbSitojun if (src->sa_family == AF_INET) 8511e48b7fbSitojun break; 8521e48b7fbSitojun return EAFNOSUPPORT; 8531e48b7fbSitojun #ifdef INET6 8541e48b7fbSitojun case SIOCSIFPHYADDR_IN6: 8551e48b7fbSitojun if (src->sa_family == AF_INET6) 8561e48b7fbSitojun break; 8571e48b7fbSitojun return EAFNOSUPPORT; 8581e48b7fbSitojun #endif /* INET6 */ 8591e48b7fbSitojun case SIOCSLIFPHYADDR: 8601e48b7fbSitojun /* checks done in the above */ 8611e48b7fbSitojun break; 862948e11b7Sitojun } 863680a94beSroy 864493e35e3Sknakahara /* 865493e35e3Sknakahara * calls gif_getref_variant() for other softcs to check 8661cd43426Sandvar * address pair duplication 867493e35e3Sknakahara */ 868493e35e3Sknakahara bound = curlwp_bind(); 869cad488d0Sitojun error = gif_set_tunnel(&sc->gif_if, src, dst); 870680a94beSroy if (error == 0) 871680a94beSroy if_link_state_change(&sc->gif_if, LINK_STATE_UP); 872493e35e3Sknakahara curlwp_bindx(bound); 873680a94beSroy 87474d3c214Sitojun break; 87574d3c214Sitojun 87639091335Sitojun #ifdef SIOCDIFPHYADDR 87739091335Sitojun case SIOCDIFPHYADDR: 878493e35e3Sknakahara bound = curlwp_bind(); 879cad488d0Sitojun gif_delete_tunnel(&sc->gif_if); 880680a94beSroy if_link_state_change(&sc->gif_if, LINK_STATE_DOWN); 881493e35e3Sknakahara curlwp_bindx(bound); 88239091335Sitojun break; 88339091335Sitojun #endif 88439091335Sitojun 88574d3c214Sitojun case SIOCGIFPSRCADDR: 88674d3c214Sitojun #ifdef INET6 88774d3c214Sitojun case SIOCGIFPSRCADDR_IN6: 88874d3c214Sitojun #endif /* INET6 */ 889493e35e3Sknakahara bound = curlwp_bind(); 890493e35e3Sknakahara var = gif_getref_variant(sc, &psref); 891493e35e3Sknakahara if (var->gv_psrc == NULL) { 892493e35e3Sknakahara gif_putref_variant(var, &psref); 893493e35e3Sknakahara curlwp_bindx(bound); 89474d3c214Sitojun error = EADDRNOTAVAIL; 89574d3c214Sitojun goto bad; 89674d3c214Sitojun } 897493e35e3Sknakahara src = var->gv_psrc; 89808af3d2fSitojun switch (cmd) { 89974d3c214Sitojun #ifdef INET 90008af3d2fSitojun case SIOCGIFPSRCADDR: 90174d3c214Sitojun dst = &ifr->ifr_addr; 90208af3d2fSitojun size = sizeof(ifr->ifr_addr); 90374d3c214Sitojun break; 90474d3c214Sitojun #endif /* INET */ 90574d3c214Sitojun #ifdef INET6 90608af3d2fSitojun case SIOCGIFPSRCADDR_IN6: 90774d3c214Sitojun dst = (struct sockaddr *) 90874d3c214Sitojun &(((struct in6_ifreq *)data)->ifr_addr); 90908af3d2fSitojun size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 91074d3c214Sitojun break; 91174d3c214Sitojun #endif /* INET6 */ 91274d3c214Sitojun default: 913493e35e3Sknakahara gif_putref_variant(var, &psref); 914493e35e3Sknakahara curlwp_bindx(bound); 91574d3c214Sitojun error = EADDRNOTAVAIL; 91674d3c214Sitojun goto bad; 91774d3c214Sitojun } 918493e35e3Sknakahara if (src->sa_len > size) { 919493e35e3Sknakahara gif_putref_variant(var, &psref); 920493e35e3Sknakahara curlwp_bindx(bound); 92108af3d2fSitojun return EINVAL; 922493e35e3Sknakahara } 92372d41408Sdyoung memcpy(dst, src, src->sa_len); 924493e35e3Sknakahara gif_putref_variant(var, &psref); 925493e35e3Sknakahara curlwp_bindx(bound); 92674d3c214Sitojun break; 92774d3c214Sitojun 92874d3c214Sitojun case SIOCGIFPDSTADDR: 92974d3c214Sitojun #ifdef INET6 93074d3c214Sitojun case SIOCGIFPDSTADDR_IN6: 93174d3c214Sitojun #endif /* INET6 */ 932493e35e3Sknakahara bound = curlwp_bind(); 933493e35e3Sknakahara var = gif_getref_variant(sc, &psref); 934493e35e3Sknakahara if (var->gv_pdst == NULL) { 935493e35e3Sknakahara gif_putref_variant(var, &psref); 936493e35e3Sknakahara curlwp_bindx(bound); 93774d3c214Sitojun error = EADDRNOTAVAIL; 93874d3c214Sitojun goto bad; 93974d3c214Sitojun } 940493e35e3Sknakahara src = var->gv_pdst; 94108af3d2fSitojun switch (cmd) { 94274d3c214Sitojun #ifdef INET 94308af3d2fSitojun case SIOCGIFPDSTADDR: 94474d3c214Sitojun dst = &ifr->ifr_addr; 94508af3d2fSitojun size = sizeof(ifr->ifr_addr); 94674d3c214Sitojun break; 94774d3c214Sitojun #endif /* INET */ 94874d3c214Sitojun #ifdef INET6 94908af3d2fSitojun case SIOCGIFPDSTADDR_IN6: 95074d3c214Sitojun dst = (struct sockaddr *) 95174d3c214Sitojun &(((struct in6_ifreq *)data)->ifr_addr); 95208af3d2fSitojun size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 95374d3c214Sitojun break; 95474d3c214Sitojun #endif /* INET6 */ 95574d3c214Sitojun default: 956493e35e3Sknakahara gif_putref_variant(var, &psref); 957493e35e3Sknakahara curlwp_bindx(bound); 95874d3c214Sitojun error = EADDRNOTAVAIL; 95974d3c214Sitojun goto bad; 96074d3c214Sitojun } 961493e35e3Sknakahara if (src->sa_len > size) { 962493e35e3Sknakahara gif_putref_variant(var, &psref); 963493e35e3Sknakahara curlwp_bindx(bound); 96408af3d2fSitojun return EINVAL; 965493e35e3Sknakahara } 96672d41408Sdyoung memcpy(dst, src, src->sa_len); 967493e35e3Sknakahara gif_putref_variant(var, &psref); 968493e35e3Sknakahara curlwp_bindx(bound); 96974d3c214Sitojun break; 97074d3c214Sitojun 9711e48b7fbSitojun case SIOCGLIFPHYADDR: 972493e35e3Sknakahara bound = curlwp_bind(); 973493e35e3Sknakahara var = gif_getref_variant(sc, &psref); 974493e35e3Sknakahara if (var->gv_psrc == NULL || var->gv_pdst == NULL) { 975493e35e3Sknakahara gif_putref_variant(var, &psref); 976493e35e3Sknakahara curlwp_bindx(bound); 9771e48b7fbSitojun error = EADDRNOTAVAIL; 9781e48b7fbSitojun goto bad; 9791e48b7fbSitojun } 9801e48b7fbSitojun 9811e48b7fbSitojun /* copy src */ 982493e35e3Sknakahara src = var->gv_psrc; 9831e48b7fbSitojun dst = (struct sockaddr *) 9841e48b7fbSitojun &(((struct if_laddrreq *)data)->addr); 9851e48b7fbSitojun size = sizeof(((struct if_laddrreq *)data)->addr); 986493e35e3Sknakahara if (src->sa_len > size) { 987493e35e3Sknakahara gif_putref_variant(var, &psref); 988493e35e3Sknakahara curlwp_bindx(bound); 9891e48b7fbSitojun return EINVAL; 990493e35e3Sknakahara } 99172d41408Sdyoung memcpy(dst, src, src->sa_len); 9921e48b7fbSitojun 9931e48b7fbSitojun /* copy dst */ 994493e35e3Sknakahara src = var->gv_pdst; 9951e48b7fbSitojun dst = (struct sockaddr *) 9961e48b7fbSitojun &(((struct if_laddrreq *)data)->dstaddr); 9971e48b7fbSitojun size = sizeof(((struct if_laddrreq *)data)->dstaddr); 998493e35e3Sknakahara if (src->sa_len > size) { 999493e35e3Sknakahara gif_putref_variant(var, &psref); 1000493e35e3Sknakahara curlwp_bindx(bound); 10011e48b7fbSitojun return EINVAL; 1002493e35e3Sknakahara } 100372d41408Sdyoung memcpy(dst, src, src->sa_len); 1004493e35e3Sknakahara gif_putref_variant(var, &psref); 1005493e35e3Sknakahara curlwp_bindx(bound); 10061e48b7fbSitojun break; 10071e48b7fbSitojun 100874d3c214Sitojun default: 1009de87fe67Sdyoung return ifioctl_common(ifp, cmd, data); 101074d3c214Sitojun } 101174d3c214Sitojun bad: 101274d3c214Sitojun return error; 101374d3c214Sitojun } 1014b36ce94cSthorpej 10155e4601c6Sknakahara static int 1016493e35e3Sknakahara gif_encap_attach(struct gif_variant *var) 10175e4601c6Sknakahara { 10185e4601c6Sknakahara int error; 10195e4601c6Sknakahara 1020493e35e3Sknakahara if (var == NULL || var->gv_psrc == NULL) 10215e4601c6Sknakahara return EINVAL; 10225e4601c6Sknakahara 1023493e35e3Sknakahara switch (var->gv_psrc->sa_family) { 10245e4601c6Sknakahara #ifdef INET 10255e4601c6Sknakahara case AF_INET: 1026493e35e3Sknakahara error = in_gif_attach(var); 10275e4601c6Sknakahara break; 10285e4601c6Sknakahara #endif 10295e4601c6Sknakahara #ifdef INET6 10305e4601c6Sknakahara case AF_INET6: 1031493e35e3Sknakahara error = in6_gif_attach(var); 10325e4601c6Sknakahara break; 10335e4601c6Sknakahara #endif 10345e4601c6Sknakahara default: 10355e4601c6Sknakahara error = EINVAL; 10365e4601c6Sknakahara break; 10375e4601c6Sknakahara } 10385e4601c6Sknakahara 10395e4601c6Sknakahara return error; 10405e4601c6Sknakahara } 10415e4601c6Sknakahara 10425e4601c6Sknakahara static int 1043493e35e3Sknakahara gif_encap_detach(struct gif_variant *var) 10445e4601c6Sknakahara { 10455e4601c6Sknakahara int error; 10465e4601c6Sknakahara 1047493e35e3Sknakahara if (var == NULL || var->gv_psrc == NULL) 10485e4601c6Sknakahara return EINVAL; 10495e4601c6Sknakahara 1050493e35e3Sknakahara switch (var->gv_psrc->sa_family) { 10515e4601c6Sknakahara #ifdef INET 10525e4601c6Sknakahara case AF_INET: 1053493e35e3Sknakahara error = in_gif_detach(var); 10545e4601c6Sknakahara break; 10555e4601c6Sknakahara #endif 10565e4601c6Sknakahara #ifdef INET6 10575e4601c6Sknakahara case AF_INET6: 1058493e35e3Sknakahara error = in6_gif_detach(var); 10595e4601c6Sknakahara break; 10605e4601c6Sknakahara #endif 10615e4601c6Sknakahara default: 10625e4601c6Sknakahara error = EINVAL; 10635e4601c6Sknakahara break; 10645e4601c6Sknakahara } 10655e4601c6Sknakahara 10665e4601c6Sknakahara return error; 10675e4601c6Sknakahara } 10685e4601c6Sknakahara 1069d60d8acaSknakahara static int 107063eac52bSthorpej gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) 1071b36ce94cSthorpej { 1072de87fe67Sdyoung struct gif_softc *sc = ifp->if_softc; 1073cad488d0Sitojun struct gif_softc *sc2; 1074493e35e3Sknakahara struct gif_variant *ovar, *nvar; 1075306b5425Sdyoung struct sockaddr *osrc, *odst; 1076118f179fSknakahara struct sockaddr *nsrc, *ndst; 1077cad488d0Sitojun int error; 10786284b358Sknakahara #ifndef GIF_MPSAFE 10796284b358Sknakahara int s; 1080cad488d0Sitojun 1081cad488d0Sitojun s = splsoftnet(); 10826284b358Sknakahara #endif 1083c544c867Sknakahara error = encap_lock_enter(); 1084c544c867Sknakahara if (error) { 10856284b358Sknakahara #ifndef GIF_MPSAFE 1086c544c867Sknakahara splx(s); 10876284b358Sknakahara #endif 1088c544c867Sknakahara return error; 1089c544c867Sknakahara } 1090cad488d0Sitojun 1091493e35e3Sknakahara nsrc = sockaddr_dup(src, M_WAITOK); 1092493e35e3Sknakahara ndst = sockaddr_dup(dst, M_WAITOK); 1093493e35e3Sknakahara nvar = kmem_alloc(sizeof(*nvar), KM_SLEEP); 1094493e35e3Sknakahara 1095493e35e3Sknakahara mutex_enter(&sc->gif_lock); 1096493e35e3Sknakahara 1097493e35e3Sknakahara ovar = sc->gif_var; 1098493e35e3Sknakahara 1099493e35e3Sknakahara if ((ovar->gv_pdst && sockaddr_cmp(ovar->gv_pdst, dst) == 0) && 1100493e35e3Sknakahara (ovar->gv_psrc && sockaddr_cmp(ovar->gv_psrc, src) == 0)) { 1101493e35e3Sknakahara /* address and port pair not changed. */ 1102493e35e3Sknakahara error = 0; 1103493e35e3Sknakahara goto out; 1104493e35e3Sknakahara } 1105493e35e3Sknakahara 11061cc266b8Sknakahara mutex_enter(&gif_softcs.lock); 11071cc266b8Sknakahara LIST_FOREACH(sc2, &gif_softcs.list, gif_list) { 1108493e35e3Sknakahara struct gif_variant *var2; 1109493e35e3Sknakahara struct psref psref; 1110493e35e3Sknakahara 1111cad488d0Sitojun if (sc2 == sc) 1112cad488d0Sitojun continue; 1113ce1daba5Sknakahara var2 = gif_getref_variant(sc2, &psref); 1114493e35e3Sknakahara if (!var2->gv_pdst || !var2->gv_psrc) { 1115493e35e3Sknakahara gif_putref_variant(var2, &psref); 1116cad488d0Sitojun continue; 1117493e35e3Sknakahara } 1118cad488d0Sitojun /* can't configure same pair of address onto two gifs */ 1119493e35e3Sknakahara if (sockaddr_cmp(var2->gv_pdst, dst) == 0 && 1120493e35e3Sknakahara sockaddr_cmp(var2->gv_psrc, src) == 0) { 11217ad35d74Smsaitoh /* continue to use the old configuration. */ 1122493e35e3Sknakahara gif_putref_variant(var2, &psref); 11231cc266b8Sknakahara mutex_exit(&gif_softcs.lock); 11246284b358Sknakahara error = EADDRNOTAVAIL; 11256284b358Sknakahara goto out; 1126cad488d0Sitojun } 1127493e35e3Sknakahara gif_putref_variant(var2, &psref); 1128cad488d0Sitojun /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 1129cad488d0Sitojun } 11301cc266b8Sknakahara mutex_exit(&gif_softcs.lock); 1131cad488d0Sitojun 1132493e35e3Sknakahara osrc = ovar->gv_psrc; 1133493e35e3Sknakahara odst = ovar->gv_pdst; 1134118f179fSknakahara 1135493e35e3Sknakahara *nvar = *ovar; 1136493e35e3Sknakahara nvar->gv_psrc = nsrc; 1137493e35e3Sknakahara nvar->gv_pdst = ndst; 1138493e35e3Sknakahara nvar->gv_encap_cookie4 = NULL; 1139493e35e3Sknakahara nvar->gv_encap_cookie6 = NULL; 1140493e35e3Sknakahara error = gif_encap_attach(nvar); 1141493e35e3Sknakahara if (error) 1142493e35e3Sknakahara goto out; 1143493e35e3Sknakahara psref_target_init(&nvar->gv_psref, gv_psref_class); 1144493e35e3Sknakahara gif_update_variant(sc, nvar); 1145d81cd78eSknakahara 1146493e35e3Sknakahara mutex_exit(&sc->gif_lock); 1147cad488d0Sitojun 1148493e35e3Sknakahara (void)gif_encap_detach(ovar); 1149493e35e3Sknakahara encap_lock_exit(); 1150cad488d0Sitojun 1151cad488d0Sitojun if (osrc) 1152306b5425Sdyoung sockaddr_free(osrc); 1153cad488d0Sitojun if (odst) 1154306b5425Sdyoung sockaddr_free(odst); 1155493e35e3Sknakahara kmem_free(ovar, sizeof(*ovar)); 1156cad488d0Sitojun 1157493e35e3Sknakahara #ifndef GIF_MPSAFE 1158493e35e3Sknakahara splx(s); 1159493e35e3Sknakahara #endif 1160493e35e3Sknakahara return 0; 1161fd06f200Sknakahara 11626284b358Sknakahara out: 1163*ae50415aSskrll mutex_exit(&sc->gif_lock); 1164*ae50415aSskrll encap_lock_exit(); 1165*ae50415aSskrll 1166493e35e3Sknakahara sockaddr_free(nsrc); 1167493e35e3Sknakahara sockaddr_free(ndst); 1168493e35e3Sknakahara kmem_free(nvar, sizeof(*nvar)); 1169493e35e3Sknakahara 11706284b358Sknakahara #ifndef GIF_MPSAFE 1171cad488d0Sitojun splx(s); 11726284b358Sknakahara #endif 1173cad488d0Sitojun return error; 1174cad488d0Sitojun } 1175cad488d0Sitojun 1176d60d8acaSknakahara static void 117763eac52bSthorpej gif_delete_tunnel(struct ifnet *ifp) 1178cad488d0Sitojun { 1179de87fe67Sdyoung struct gif_softc *sc = ifp->if_softc; 1180493e35e3Sknakahara struct gif_variant *ovar, *nvar; 1181493e35e3Sknakahara struct sockaddr *osrc, *odst; 1182c544c867Sknakahara int error; 11836284b358Sknakahara #ifndef GIF_MPSAFE 11846284b358Sknakahara int s; 1185b36ce94cSthorpej 1186b36ce94cSthorpej s = splsoftnet(); 11876284b358Sknakahara #endif 1188c544c867Sknakahara error = encap_lock_enter(); 1189c544c867Sknakahara if (error) { 11906284b358Sknakahara #ifndef GIF_MPSAFE 1191c544c867Sknakahara splx(s); 11926284b358Sknakahara #endif 1193c544c867Sknakahara return; 1194c544c867Sknakahara } 1195b36ce94cSthorpej 1196493e35e3Sknakahara nvar = kmem_alloc(sizeof(*nvar), KM_SLEEP); 1197b36ce94cSthorpej 1198493e35e3Sknakahara mutex_enter(&sc->gif_lock); 1199d81cd78eSknakahara 1200493e35e3Sknakahara ovar = sc->gif_var; 1201493e35e3Sknakahara osrc = ovar->gv_psrc; 1202493e35e3Sknakahara odst = ovar->gv_pdst; 1203493e35e3Sknakahara if (osrc == NULL || odst == NULL) { 1204493e35e3Sknakahara /* address pair not changed. */ 1205493e35e3Sknakahara mutex_exit(&sc->gif_lock); 1206b71542e5Sknakahara encap_lock_exit(); 1207493e35e3Sknakahara kmem_free(nvar, sizeof(*nvar)); 12083a2cefcbSmaxv #ifndef GIF_MPSAFE 12093a2cefcbSmaxv splx(s); 12103a2cefcbSmaxv #endif 1211493e35e3Sknakahara return; 1212493e35e3Sknakahara } 1213493e35e3Sknakahara 1214493e35e3Sknakahara *nvar = *ovar; 1215493e35e3Sknakahara nvar->gv_psrc = NULL; 1216493e35e3Sknakahara nvar->gv_pdst = NULL; 1217493e35e3Sknakahara nvar->gv_encap_cookie4 = NULL; 1218493e35e3Sknakahara nvar->gv_encap_cookie6 = NULL; 1219493e35e3Sknakahara nvar->gv_output = NULL; 1220493e35e3Sknakahara psref_target_init(&nvar->gv_psref, gv_psref_class); 1221493e35e3Sknakahara gif_update_variant(sc, nvar); 1222493e35e3Sknakahara 1223493e35e3Sknakahara mutex_exit(&sc->gif_lock); 1224493e35e3Sknakahara 1225493e35e3Sknakahara gif_encap_detach(ovar); 1226493e35e3Sknakahara encap_lock_exit(); 1227493e35e3Sknakahara 1228493e35e3Sknakahara sockaddr_free(osrc); 1229493e35e3Sknakahara sockaddr_free(odst); 1230493e35e3Sknakahara kmem_free(ovar, sizeof(*ovar)); 1231493e35e3Sknakahara 12326284b358Sknakahara #ifndef GIF_MPSAFE 1233b36ce94cSthorpej splx(s); 12346284b358Sknakahara #endif 1235b36ce94cSthorpej } 12361d8e08d4Schristos 12371d8e08d4Schristos /* 1238493e35e3Sknakahara * gif_variant update API. 1239493e35e3Sknakahara * 1240493e35e3Sknakahara * Assumption: 1241493e35e3Sknakahara * reader side dereferences sc->gif_var in reader critical section only, 1242493e35e3Sknakahara * that is, all of reader sides do not reader the sc->gif_var after 1243493e35e3Sknakahara * pserialize_perform(). 1244493e35e3Sknakahara */ 1245493e35e3Sknakahara static void 1246493e35e3Sknakahara gif_update_variant(struct gif_softc *sc, struct gif_variant *nvar) 1247493e35e3Sknakahara { 1248493e35e3Sknakahara struct ifnet *ifp = &sc->gif_if; 1249493e35e3Sknakahara struct gif_variant *ovar = sc->gif_var; 1250493e35e3Sknakahara 1251493e35e3Sknakahara KASSERT(mutex_owned(&sc->gif_lock)); 1252493e35e3Sknakahara 1253ffb7fabaSriastradh atomic_store_release(&sc->gif_var, nvar); 1254ebac3c72Sknakahara pserialize_perform(sc->gif_psz); 1255493e35e3Sknakahara psref_target_destroy(&ovar->gv_psref, gv_psref_class); 1256493e35e3Sknakahara 1257493e35e3Sknakahara if (nvar->gv_psrc != NULL && nvar->gv_pdst != NULL) 1258493e35e3Sknakahara ifp->if_flags |= IFF_RUNNING; 1259493e35e3Sknakahara else 1260493e35e3Sknakahara ifp->if_flags &= ~IFF_RUNNING; 1261493e35e3Sknakahara } 1262493e35e3Sknakahara 1263493e35e3Sknakahara /* 12641d8e08d4Schristos * Module infrastructure 12651d8e08d4Schristos */ 12661d8e08d4Schristos #include "if_module.h" 12671d8e08d4Schristos 12682dd28fa0Spgoyette IF_MODULE(MODULE_CLASS_DRIVER, gif, "ip_ecn") 1269