1686cdd19SJun-ichiro itojun Hagino /* $FreeBSD$ */ 288ff5695SSUZUKI Shinsuke /* $KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $ */ 3686cdd19SJun-ichiro itojun Hagino 4c398230bSWarner Losh /*- 5cfa1ca9dSYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6cfa1ca9dSYoshinobu Inoue * All rights reserved. 7cfa1ca9dSYoshinobu Inoue * 8cfa1ca9dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 9cfa1ca9dSYoshinobu Inoue * modification, are permitted provided that the following conditions 10cfa1ca9dSYoshinobu Inoue * are met: 11cfa1ca9dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 12cfa1ca9dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 13cfa1ca9dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 14cfa1ca9dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 15cfa1ca9dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 16cfa1ca9dSYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 17cfa1ca9dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 18cfa1ca9dSYoshinobu Inoue * without specific prior written permission. 19cfa1ca9dSYoshinobu Inoue * 20cfa1ca9dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21cfa1ca9dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22cfa1ca9dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23cfa1ca9dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24cfa1ca9dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25cfa1ca9dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26cfa1ca9dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27cfa1ca9dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28cfa1ca9dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29cfa1ca9dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30cfa1ca9dSYoshinobu Inoue * SUCH DAMAGE. 31cfa1ca9dSYoshinobu Inoue */ 32cfa1ca9dSYoshinobu Inoue 33cfa1ca9dSYoshinobu Inoue #include "opt_inet.h" 34cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 35cfa1ca9dSYoshinobu Inoue 36cfa1ca9dSYoshinobu Inoue #include <sys/param.h> 37cfa1ca9dSYoshinobu Inoue #include <sys/systm.h> 38e3416ab0SBjoern A. Zeeb #include <sys/jail.h> 39cfa1ca9dSYoshinobu Inoue #include <sys/kernel.h> 40cfa1ca9dSYoshinobu Inoue #include <sys/malloc.h> 41cfa1ca9dSYoshinobu Inoue #include <sys/mbuf.h> 425dba30f1SPoul-Henning Kamp #include <sys/module.h> 43cfa1ca9dSYoshinobu Inoue #include <sys/socket.h> 44cfa1ca9dSYoshinobu Inoue #include <sys/sockio.h> 45cfa1ca9dSYoshinobu Inoue #include <sys/errno.h> 46cfa1ca9dSYoshinobu Inoue #include <sys/time.h> 47872f786aSBrooks Davis #include <sys/sysctl.h> 48cfa1ca9dSYoshinobu Inoue #include <sys/syslog.h> 49dbe59260SHiroki Sato #include <sys/priv.h> 508b07e49aSJulian Elischer #include <sys/proc.h> 51686cdd19SJun-ichiro itojun Hagino #include <sys/protosw.h> 5253dab5feSBrooks Davis #include <sys/conf.h> 53cfa1ca9dSYoshinobu Inoue #include <machine/cpu.h> 54cfa1ca9dSYoshinobu Inoue 55cfa1ca9dSYoshinobu Inoue #include <net/if.h> 56f889d2efSBrooks Davis #include <net/if_clone.h> 57cfa1ca9dSYoshinobu Inoue #include <net/if_types.h> 58cfa1ca9dSYoshinobu Inoue #include <net/netisr.h> 59cfa1ca9dSYoshinobu Inoue #include <net/route.h> 60cfa1ca9dSYoshinobu Inoue #include <net/bpf.h> 61530c0060SRobert Watson #include <net/vnet.h> 62cfa1ca9dSYoshinobu Inoue 63cfa1ca9dSYoshinobu Inoue #include <netinet/in.h> 64cfa1ca9dSYoshinobu Inoue #include <netinet/in_systm.h> 65cfa1ca9dSYoshinobu Inoue #include <netinet/ip.h> 6633841545SHajimu UMEMOTO #ifdef INET 6733841545SHajimu UMEMOTO #include <netinet/in_var.h> 68cfa1ca9dSYoshinobu Inoue #include <netinet/in_gif.h> 6953dab5feSBrooks Davis #include <netinet/ip_var.h> 70cfa1ca9dSYoshinobu Inoue #endif /* INET */ 71cfa1ca9dSYoshinobu Inoue 72cfa1ca9dSYoshinobu Inoue #ifdef INET6 73cfa1ca9dSYoshinobu Inoue #ifndef INET 74cfa1ca9dSYoshinobu Inoue #include <netinet/in.h> 75cfa1ca9dSYoshinobu Inoue #endif 76cfa1ca9dSYoshinobu Inoue #include <netinet6/in6_var.h> 77cfa1ca9dSYoshinobu Inoue #include <netinet/ip6.h> 78cfa1ca9dSYoshinobu Inoue #include <netinet6/ip6_var.h> 79a1f7e5f8SHajimu UMEMOTO #include <netinet6/scope6_var.h> 80cfa1ca9dSYoshinobu Inoue #include <netinet6/in6_gif.h> 81686cdd19SJun-ichiro itojun Hagino #include <netinet6/ip6protosw.h> 82cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 83cfa1ca9dSYoshinobu Inoue 84686cdd19SJun-ichiro itojun Hagino #include <netinet/ip_encap.h> 8573ff045cSAndrew Thompson #include <net/ethernet.h> 8673ff045cSAndrew Thompson #include <net/if_bridgevar.h> 87cfa1ca9dSYoshinobu Inoue #include <net/if_gif.h> 88cfa1ca9dSYoshinobu Inoue 89aed55708SRobert Watson #include <security/mac/mac_framework.h> 90aed55708SRobert Watson 9142a58907SGleb Smirnoff static const char gifname[] = "gif"; 92686cdd19SJun-ichiro itojun Hagino 9317d5cb2dSRobert Watson /* 948c7e1947SRuslan Ermilov * gif_mtx protects the global gif_softc_list. 9517d5cb2dSRobert Watson */ 9617d5cb2dSRobert Watson static struct mtx gif_mtx; 9753dab5feSBrooks Davis static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); 983e288e62SDimitry Andric static VNET_DEFINE(LIST_HEAD(, gif_softc), gif_softc_list); 991e77c105SRobert Watson #define V_gif_softc_list VNET(gif_softc_list) 100eddfbb76SRobert Watson 10194408d94SBrooks Davis void (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); 10294408d94SBrooks Davis void (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); 10394408d94SBrooks Davis void (*ng_gif_attach_p)(struct ifnet *ifp); 10494408d94SBrooks Davis void (*ng_gif_detach_p)(struct ifnet *ifp); 10594408d94SBrooks Davis 10673ff045cSAndrew Thompson static void gif_start(struct ifnet *); 1076b7330e2SSam Leffler static int gif_clone_create(struct if_clone *, int, caddr_t); 108bb2bfb4fSBrooks Davis static void gif_clone_destroy(struct ifnet *); 10942a58907SGleb Smirnoff static struct if_clone *gif_cloner; 11053dab5feSBrooks Davis 111929ddbbbSAlfred Perlstein static int gifmodevent(module_t, int, void *); 112cfa1ca9dSYoshinobu Inoue 113872f786aSBrooks Davis SYSCTL_DECL(_net_link); 1146472ac3dSEd Schouten static SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0, 115872f786aSBrooks Davis "Generic Tunnel Interface"); 116686cdd19SJun-ichiro itojun Hagino #ifndef MAX_GIF_NEST 117686cdd19SJun-ichiro itojun Hagino /* 118872f786aSBrooks Davis * This macro controls the default upper limitation on nesting of gif tunnels. 119686cdd19SJun-ichiro itojun Hagino * Since, setting a large value to this macro with a careless configuration 120686cdd19SJun-ichiro itojun Hagino * may introduce system crash, we don't allow any nestings by default. 121686cdd19SJun-ichiro itojun Hagino * If you need to configure nested gif tunnels, you can define this macro 122686cdd19SJun-ichiro itojun Hagino * in your kernel configuration file. However, if you do so, please be 123686cdd19SJun-ichiro itojun Hagino * careful to configure the tunnels so that it won't make a loop. 124686cdd19SJun-ichiro itojun Hagino */ 125686cdd19SJun-ichiro itojun Hagino #define MAX_GIF_NEST 1 126686cdd19SJun-ichiro itojun Hagino #endif 1273e288e62SDimitry Andric static VNET_DEFINE(int, max_gif_nesting) = MAX_GIF_NEST; 128d0728d71SRobert Watson #define V_max_gif_nesting VNET(max_gif_nesting) 129eddfbb76SRobert Watson SYSCTL_VNET_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW, 130eddfbb76SRobert Watson &VNET_NAME(max_gif_nesting), 0, "Max nested tunnels"); 1318b615593SMarko Zec 132872f786aSBrooks Davis /* 133872f786aSBrooks Davis * By default, we disallow creation of multiple tunnels between the same 134872f786aSBrooks Davis * pair of addresses. Some applications require this functionality so 135872f786aSBrooks Davis * we allow control over this check here. 136872f786aSBrooks Davis */ 137d0728d71SRobert Watson #ifdef XBONEHACK 1383e288e62SDimitry Andric static VNET_DEFINE(int, parallel_tunnels) = 1; 139d0728d71SRobert Watson #else 1403e288e62SDimitry Andric static VNET_DEFINE(int, parallel_tunnels) = 0; 141d0728d71SRobert Watson #endif 142d0728d71SRobert Watson #define V_parallel_tunnels VNET(parallel_tunnels) 143eddfbb76SRobert Watson SYSCTL_VNET_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW, 144eddfbb76SRobert Watson &VNET_NAME(parallel_tunnels), 0, "Allow parallel tunnels?"); 145cfa1ca9dSYoshinobu Inoue 14656abdd33SAndrew Thompson /* copy from src/sys/net/if_ethersubr.c */ 14756abdd33SAndrew Thompson static const u_char etherbroadcastaddr[ETHER_ADDR_LEN] = 14856abdd33SAndrew Thompson { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 14956abdd33SAndrew Thompson #ifndef ETHER_IS_BROADCAST 15056abdd33SAndrew Thompson #define ETHER_IS_BROADCAST(addr) \ 15156abdd33SAndrew Thompson (bcmp(etherbroadcastaddr, (addr), ETHER_ADDR_LEN) == 0) 15256abdd33SAndrew Thompson #endif 15356abdd33SAndrew Thompson 154bb2bfb4fSBrooks Davis static int 1556b7330e2SSam Leffler gif_clone_create(ifc, unit, params) 15653dab5feSBrooks Davis struct if_clone *ifc; 1573b16e7b2SMaxime Henrion int unit; 1586b7330e2SSam Leffler caddr_t params; 159cfa1ca9dSYoshinobu Inoue { 16033841545SHajimu UMEMOTO struct gif_softc *sc; 161cfa1ca9dSYoshinobu Inoue 162e1a8c3dcSBruce M Simpson sc = malloc(sizeof(struct gif_softc), M_GIF, M_WAITOK | M_ZERO); 1638b07e49aSJulian Elischer sc->gif_fibnum = curthread->td_proc->p_fibnum; 164fc74a9f9SBrooks Davis GIF2IFP(sc) = if_alloc(IFT_GIF); 165fc74a9f9SBrooks Davis if (GIF2IFP(sc) == NULL) { 166fc74a9f9SBrooks Davis free(sc, M_GIF); 167fc74a9f9SBrooks Davis return (ENOSPC); 168fc74a9f9SBrooks Davis } 16953dab5feSBrooks Davis 17025af0bb5SGleb Smirnoff GIF_LOCK_INIT(sc); 17125af0bb5SGleb Smirnoff 172fc74a9f9SBrooks Davis GIF2IFP(sc)->if_softc = sc; 17342a58907SGleb Smirnoff if_initname(GIF2IFP(sc), gifname, unit); 174686cdd19SJun-ichiro itojun Hagino 1759426aedfSHajimu UMEMOTO sc->encap_cookie4 = sc->encap_cookie6 = NULL; 176dbe59260SHiroki Sato sc->gif_options = GIF_ACCEPT_REVETHIP; 1779426aedfSHajimu UMEMOTO 178fc74a9f9SBrooks Davis GIF2IFP(sc)->if_addrlen = 0; 179fc74a9f9SBrooks Davis GIF2IFP(sc)->if_mtu = GIF_MTU; 180fc74a9f9SBrooks Davis GIF2IFP(sc)->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 18133841545SHajimu UMEMOTO #if 0 18233841545SHajimu UMEMOTO /* turn off ingress filter */ 183fc74a9f9SBrooks Davis GIF2IFP(sc)->if_flags |= IFF_LINK2; 18433841545SHajimu UMEMOTO #endif 185fc74a9f9SBrooks Davis GIF2IFP(sc)->if_ioctl = gif_ioctl; 18673ff045cSAndrew Thompson GIF2IFP(sc)->if_start = gif_start; 187fc74a9f9SBrooks Davis GIF2IFP(sc)->if_output = gif_output; 188e50d35e6SMaxim Sobolev GIF2IFP(sc)->if_snd.ifq_maxlen = ifqmaxlen; 189fc74a9f9SBrooks Davis if_attach(GIF2IFP(sc)); 19001399f34SDavid Malone bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int32_t)); 19194408d94SBrooks Davis if (ng_gif_attach_p != NULL) 192fc74a9f9SBrooks Davis (*ng_gif_attach_p)(GIF2IFP(sc)); 19325af0bb5SGleb Smirnoff 19425af0bb5SGleb Smirnoff mtx_lock(&gif_mtx); 195603724d3SBjoern A. Zeeb LIST_INSERT_HEAD(&V_gif_softc_list, sc, gif_list); 19625af0bb5SGleb Smirnoff mtx_unlock(&gif_mtx); 19725af0bb5SGleb Smirnoff 19825af0bb5SGleb Smirnoff return (0); 199cfa1ca9dSYoshinobu Inoue } 200cfa1ca9dSYoshinobu Inoue 20117d5cb2dSRobert Watson static void 202febd0759SAndrew Thompson gif_clone_destroy(ifp) 203febd0759SAndrew Thompson struct ifnet *ifp; 20453dab5feSBrooks Davis { 205e0de57f9SBjoern A. Zeeb #if defined(INET) || defined(INET6) 20653dab5feSBrooks Davis int err; 207e0de57f9SBjoern A. Zeeb #endif 208febd0759SAndrew Thompson struct gif_softc *sc = ifp->if_softc; 209febd0759SAndrew Thompson 210febd0759SAndrew Thompson mtx_lock(&gif_mtx); 211febd0759SAndrew Thompson LIST_REMOVE(sc, gif_list); 212febd0759SAndrew Thompson mtx_unlock(&gif_mtx); 21353dab5feSBrooks Davis 21417d5cb2dSRobert Watson gif_delete_tunnel(ifp); 2159426aedfSHajimu UMEMOTO #ifdef INET6 21653dab5feSBrooks Davis if (sc->encap_cookie6 != NULL) { 21753dab5feSBrooks Davis err = encap_detach(sc->encap_cookie6); 21853dab5feSBrooks Davis KASSERT(err == 0, ("Unexpected error detaching encap_cookie6")); 21953dab5feSBrooks Davis } 2209426aedfSHajimu UMEMOTO #endif 2219426aedfSHajimu UMEMOTO #ifdef INET 2229426aedfSHajimu UMEMOTO if (sc->encap_cookie4 != NULL) { 2239426aedfSHajimu UMEMOTO err = encap_detach(sc->encap_cookie4); 2249426aedfSHajimu UMEMOTO KASSERT(err == 0, ("Unexpected error detaching encap_cookie4")); 2259426aedfSHajimu UMEMOTO } 2269426aedfSHajimu UMEMOTO #endif 22753dab5feSBrooks Davis 22894408d94SBrooks Davis if (ng_gif_detach_p != NULL) 22994408d94SBrooks Davis (*ng_gif_detach_p)(ifp); 23053dab5feSBrooks Davis bpfdetach(ifp); 23153dab5feSBrooks Davis if_detach(ifp); 232fc74a9f9SBrooks Davis if_free(ifp); 23353dab5feSBrooks Davis 23425af0bb5SGleb Smirnoff GIF_LOCK_DESTROY(sc); 23525af0bb5SGleb Smirnoff 23653dab5feSBrooks Davis free(sc, M_GIF); 23753dab5feSBrooks Davis } 23853dab5feSBrooks Davis 239d0728d71SRobert Watson static void 240d0728d71SRobert Watson vnet_gif_init(const void *unused __unused) 2411ed81b73SMarko Zec { 2421ed81b73SMarko Zec 2431ed81b73SMarko Zec LIST_INIT(&V_gif_softc_list); 2441ed81b73SMarko Zec } 245d0728d71SRobert Watson VNET_SYSINIT(vnet_gif_init, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, vnet_gif_init, 246d0728d71SRobert Watson NULL); 2471ed81b73SMarko Zec 2481ed81b73SMarko Zec static int 24953dab5feSBrooks Davis gifmodevent(mod, type, data) 25053dab5feSBrooks Davis module_t mod; 25153dab5feSBrooks Davis int type; 25253dab5feSBrooks Davis void *data; 25353dab5feSBrooks Davis { 25453dab5feSBrooks Davis 25553dab5feSBrooks Davis switch (type) { 25653dab5feSBrooks Davis case MOD_LOAD: 25717d5cb2dSRobert Watson mtx_init(&gif_mtx, "gif_mtx", NULL, MTX_DEF); 25842a58907SGleb Smirnoff gif_cloner = if_clone_simple(gifname, gif_clone_create, 25942a58907SGleb Smirnoff gif_clone_destroy, 0); 26053dab5feSBrooks Davis break; 261d0728d71SRobert Watson 26253dab5feSBrooks Davis case MOD_UNLOAD: 26342a58907SGleb Smirnoff if_clone_detach(gif_cloner); 26417d5cb2dSRobert Watson mtx_destroy(&gif_mtx); 26553dab5feSBrooks Davis break; 2663e019deaSPoul-Henning Kamp default: 2673e019deaSPoul-Henning Kamp return EOPNOTSUPP; 26853dab5feSBrooks Davis } 26953dab5feSBrooks Davis return 0; 27053dab5feSBrooks Davis } 27153dab5feSBrooks Davis 27253dab5feSBrooks Davis static moduledata_t gif_mod = { 27353dab5feSBrooks Davis "if_gif", 27453dab5feSBrooks Davis gifmodevent, 2759823d527SKevin Lo 0 27653dab5feSBrooks Davis }; 27753dab5feSBrooks Davis 27853dab5feSBrooks Davis DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 27920af0ffaSBrooks Davis MODULE_VERSION(if_gif, 1); 280cfa1ca9dSYoshinobu Inoue 2819426aedfSHajimu UMEMOTO int 282686cdd19SJun-ichiro itojun Hagino gif_encapcheck(m, off, proto, arg) 283686cdd19SJun-ichiro itojun Hagino const struct mbuf *m; 284686cdd19SJun-ichiro itojun Hagino int off; 285686cdd19SJun-ichiro itojun Hagino int proto; 286686cdd19SJun-ichiro itojun Hagino void *arg; 287686cdd19SJun-ichiro itojun Hagino { 288686cdd19SJun-ichiro itojun Hagino struct ip ip; 289686cdd19SJun-ichiro itojun Hagino struct gif_softc *sc; 290686cdd19SJun-ichiro itojun Hagino 291686cdd19SJun-ichiro itojun Hagino sc = (struct gif_softc *)arg; 292686cdd19SJun-ichiro itojun Hagino if (sc == NULL) 293686cdd19SJun-ichiro itojun Hagino return 0; 294686cdd19SJun-ichiro itojun Hagino 295fc74a9f9SBrooks Davis if ((GIF2IFP(sc)->if_flags & IFF_UP) == 0) 296686cdd19SJun-ichiro itojun Hagino return 0; 297686cdd19SJun-ichiro itojun Hagino 298686cdd19SJun-ichiro itojun Hagino /* no physical address */ 299686cdd19SJun-ichiro itojun Hagino if (!sc->gif_psrc || !sc->gif_pdst) 300686cdd19SJun-ichiro itojun Hagino return 0; 301686cdd19SJun-ichiro itojun Hagino 302686cdd19SJun-ichiro itojun Hagino switch (proto) { 303686cdd19SJun-ichiro itojun Hagino #ifdef INET 304686cdd19SJun-ichiro itojun Hagino case IPPROTO_IPV4: 305686cdd19SJun-ichiro itojun Hagino break; 306686cdd19SJun-ichiro itojun Hagino #endif 307686cdd19SJun-ichiro itojun Hagino #ifdef INET6 308686cdd19SJun-ichiro itojun Hagino case IPPROTO_IPV6: 309686cdd19SJun-ichiro itojun Hagino break; 310686cdd19SJun-ichiro itojun Hagino #endif 31173ff045cSAndrew Thompson case IPPROTO_ETHERIP: 31273ff045cSAndrew Thompson break; 31373ff045cSAndrew Thompson 314686cdd19SJun-ichiro itojun Hagino default: 315686cdd19SJun-ichiro itojun Hagino return 0; 316686cdd19SJun-ichiro itojun Hagino } 317686cdd19SJun-ichiro itojun Hagino 3183bb61ca6SHajimu UMEMOTO /* Bail on short packets */ 3193bb61ca6SHajimu UMEMOTO if (m->m_pkthdr.len < sizeof(ip)) 3203bb61ca6SHajimu UMEMOTO return 0; 3213bb61ca6SHajimu UMEMOTO 3226f4ded3aSBrooks Davis m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 323686cdd19SJun-ichiro itojun Hagino 324686cdd19SJun-ichiro itojun Hagino switch (ip.ip_v) { 325686cdd19SJun-ichiro itojun Hagino #ifdef INET 326686cdd19SJun-ichiro itojun Hagino case 4: 327686cdd19SJun-ichiro itojun Hagino if (sc->gif_psrc->sa_family != AF_INET || 328686cdd19SJun-ichiro itojun Hagino sc->gif_pdst->sa_family != AF_INET) 329686cdd19SJun-ichiro itojun Hagino return 0; 330686cdd19SJun-ichiro itojun Hagino return gif_encapcheck4(m, off, proto, arg); 331686cdd19SJun-ichiro itojun Hagino #endif 332686cdd19SJun-ichiro itojun Hagino #ifdef INET6 333686cdd19SJun-ichiro itojun Hagino case 6: 3349426aedfSHajimu UMEMOTO if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 3359426aedfSHajimu UMEMOTO return 0; 336686cdd19SJun-ichiro itojun Hagino if (sc->gif_psrc->sa_family != AF_INET6 || 337686cdd19SJun-ichiro itojun Hagino sc->gif_pdst->sa_family != AF_INET6) 338686cdd19SJun-ichiro itojun Hagino return 0; 339686cdd19SJun-ichiro itojun Hagino return gif_encapcheck6(m, off, proto, arg); 340686cdd19SJun-ichiro itojun Hagino #endif 341686cdd19SJun-ichiro itojun Hagino default: 342686cdd19SJun-ichiro itojun Hagino return 0; 343686cdd19SJun-ichiro itojun Hagino } 344686cdd19SJun-ichiro itojun Hagino } 345776b7288SRandall Stewart #ifdef INET 346776b7288SRandall Stewart #define GIF_HDR_LEN (ETHER_HDR_LEN + sizeof (struct ip)) 347776b7288SRandall Stewart #endif 348776b7288SRandall Stewart #ifdef INET6 349776b7288SRandall Stewart #define GIF_HDR_LEN6 (ETHER_HDR_LEN + sizeof (struct ip6_hdr)) 350776b7288SRandall Stewart #endif 351686cdd19SJun-ichiro itojun Hagino 35273ff045cSAndrew Thompson static void 35373ff045cSAndrew Thompson gif_start(struct ifnet *ifp) 35473ff045cSAndrew Thompson { 35573ff045cSAndrew Thompson struct gif_softc *sc; 35673ff045cSAndrew Thompson struct mbuf *m; 357776b7288SRandall Stewart uint32_t af; 358776b7288SRandall Stewart int error = 0; 35973ff045cSAndrew Thompson 36073ff045cSAndrew Thompson sc = ifp->if_softc; 361776b7288SRandall Stewart GIF_LOCK(sc); 36273ff045cSAndrew Thompson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 363776b7288SRandall Stewart while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 364776b7288SRandall Stewart 365776b7288SRandall Stewart IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 36673ff045cSAndrew Thompson if (m == 0) 36773ff045cSAndrew Thompson break; 36873ff045cSAndrew Thompson 369776b7288SRandall Stewart #ifdef ALTQ 370776b7288SRandall Stewart /* Take out those altq bytes we add in gif_output */ 371776b7288SRandall Stewart #ifdef INET 372776b7288SRandall Stewart if (sc->gif_psrc->sa_family == AF_INET) 373776b7288SRandall Stewart m->m_pkthdr.len -= GIF_HDR_LEN; 374776b7288SRandall Stewart #endif 375776b7288SRandall Stewart #ifdef INET6 376776b7288SRandall Stewart if (sc->gif_psrc->sa_family == AF_INET6) 377776b7288SRandall Stewart m->m_pkthdr.len -= GIF_HDR_LEN6; 378776b7288SRandall Stewart #endif 379776b7288SRandall Stewart #endif 38040138788SRandall Stewart /* 38140138788SRandall Stewart * Now pull back the af that we 38240138788SRandall Stewart * stashed in the csum_data. 383776b7288SRandall Stewart */ 384cef68c63SRandall Stewart af = m->m_pkthdr.csum_data; 385cef68c63SRandall Stewart 386776b7288SRandall Stewart if (ifp->if_bridge) 387776b7288SRandall Stewart af = AF_LINK; 388776b7288SRandall Stewart 389776b7288SRandall Stewart BPF_MTAP2(ifp, &af, sizeof(af), m); 390776b7288SRandall Stewart ifp->if_opackets++; 391776b7288SRandall Stewart 392776b7288SRandall Stewart /* Done by IFQ_HANDOFF */ 393776b7288SRandall Stewart /* ifp->if_obytes += m->m_pkthdr.len;*/ 394776b7288SRandall Stewart /* override to IPPROTO_ETHERIP for bridged traffic */ 395776b7288SRandall Stewart 396776b7288SRandall Stewart M_SETFIB(m, sc->gif_fibnum); 397776b7288SRandall Stewart /* inner AF-specific encapsulation */ 398776b7288SRandall Stewart /* XXX should we check if our outer source is legal? */ 399776b7288SRandall Stewart /* dispatch to output logic based on outer AF */ 400776b7288SRandall Stewart switch (sc->gif_psrc->sa_family) { 401776b7288SRandall Stewart #ifdef INET 402776b7288SRandall Stewart case AF_INET: 403776b7288SRandall Stewart error = in_gif_output(ifp, af, m); 404776b7288SRandall Stewart break; 405776b7288SRandall Stewart #endif 406776b7288SRandall Stewart #ifdef INET6 407776b7288SRandall Stewart case AF_INET6: 408776b7288SRandall Stewart error = in6_gif_output(ifp, af, m); 409776b7288SRandall Stewart break; 410776b7288SRandall Stewart #endif 411776b7288SRandall Stewart default: 412776b7288SRandall Stewart m_freem(m); 413776b7288SRandall Stewart error = ENETDOWN; 414776b7288SRandall Stewart } 415776b7288SRandall Stewart if (error) 416776b7288SRandall Stewart ifp->if_oerrors++; 41773ff045cSAndrew Thompson 41873ff045cSAndrew Thompson } 41973ff045cSAndrew Thompson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 420776b7288SRandall Stewart GIF_UNLOCK(sc); 42173ff045cSAndrew Thompson return; 42273ff045cSAndrew Thompson } 42373ff045cSAndrew Thompson 424cfa1ca9dSYoshinobu Inoue int 425*47e8d432SGleb Smirnoff gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 426*47e8d432SGleb Smirnoff struct route *ro) 427cfa1ca9dSYoshinobu Inoue { 428fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 4298c7e1947SRuslan Ermilov struct m_tag *mtag; 430cfa1ca9dSYoshinobu Inoue int error = 0; 4318c7e1947SRuslan Ermilov int gif_called; 432776b7288SRandall Stewart uint32_t af; 43310722b85SRobert Watson #ifdef MAC 43430d239bcSRobert Watson error = mac_ifnet_check_transmit(ifp, m); 435e0852ce2SRobert Watson if (error) { 436e0852ce2SRobert Watson m_freem(m); 437e0852ce2SRobert Watson goto end; 438e0852ce2SRobert Watson } 43910722b85SRobert Watson #endif 44010722b85SRobert Watson 441cfa1ca9dSYoshinobu Inoue /* 442cfa1ca9dSYoshinobu Inoue * gif may cause infinite recursion calls when misconfigured. 4438c7e1947SRuslan Ermilov * We'll prevent this by detecting loops. 4448c7e1947SRuslan Ermilov * 4458c7e1947SRuslan Ermilov * High nesting level may cause stack exhaustion. 446cfa1ca9dSYoshinobu Inoue * We'll prevent this by introducing upper limit. 447cfa1ca9dSYoshinobu Inoue */ 4488c7e1947SRuslan Ermilov gif_called = 1; 4498c7e1947SRuslan Ermilov mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, NULL); 4508c7e1947SRuslan Ermilov while (mtag != NULL) { 4518c7e1947SRuslan Ermilov if (*(struct ifnet **)(mtag + 1) == ifp) { 4528c7e1947SRuslan Ermilov log(LOG_NOTICE, 4538c7e1947SRuslan Ermilov "gif_output: loop detected on %s\n", 4548c7e1947SRuslan Ermilov (*(struct ifnet **)(mtag + 1))->if_xname); 4558c7e1947SRuslan Ermilov m_freem(m); 4568c7e1947SRuslan Ermilov error = EIO; /* is there better errno? */ 4578c7e1947SRuslan Ermilov goto end; 4588c7e1947SRuslan Ermilov } 4598c7e1947SRuslan Ermilov mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, mtag); 4608c7e1947SRuslan Ermilov gif_called++; 4618c7e1947SRuslan Ermilov } 462603724d3SBjoern A. Zeeb if (gif_called > V_max_gif_nesting) { 463cfa1ca9dSYoshinobu Inoue log(LOG_NOTICE, 464cfa1ca9dSYoshinobu Inoue "gif_output: recursively called too many times(%d)\n", 465523ebc4eSRobert Watson gif_called); 466cfa1ca9dSYoshinobu Inoue m_freem(m); 467cfa1ca9dSYoshinobu Inoue error = EIO; /* is there better errno? */ 468cfa1ca9dSYoshinobu Inoue goto end; 469cfa1ca9dSYoshinobu Inoue } 4708c7e1947SRuslan Ermilov mtag = m_tag_alloc(MTAG_GIF, MTAG_GIF_CALLED, sizeof(struct ifnet *), 4718c7e1947SRuslan Ermilov M_NOWAIT); 4728c7e1947SRuslan Ermilov if (mtag == NULL) { 4738c7e1947SRuslan Ermilov m_freem(m); 4748c7e1947SRuslan Ermilov error = ENOMEM; 4758c7e1947SRuslan Ermilov goto end; 4768c7e1947SRuslan Ermilov } 4778c7e1947SRuslan Ermilov *(struct ifnet **)(mtag + 1) = ifp; 4788c7e1947SRuslan Ermilov m_tag_prepend(m, mtag); 479686cdd19SJun-ichiro itojun Hagino 480cfa1ca9dSYoshinobu Inoue m->m_flags &= ~(M_BCAST|M_MCAST); 48101399f34SDavid Malone /* BPF writes need to be handled specially. */ 482*47e8d432SGleb Smirnoff if (dst->sa_family == AF_UNSPEC) 48301399f34SDavid Malone bcopy(dst->sa_data, &af, sizeof(af)); 484*47e8d432SGleb Smirnoff else 48501399f34SDavid Malone af = dst->sa_family; 48640138788SRandall Stewart /* 48740138788SRandall Stewart * Now save the af in the inbound pkt csum 48840138788SRandall Stewart * data, this is a cheat since we are using 48940138788SRandall Stewart * the inbound csum_data field to carry the 49040138788SRandall Stewart * af over to the gif_start() routine, avoiding 49140138788SRandall Stewart * using yet another mtag. 492776b7288SRandall Stewart */ 493cef68c63SRandall Stewart m->m_pkthdr.csum_data = af; 494776b7288SRandall Stewart if (!(ifp->if_flags & IFF_UP) || 495776b7288SRandall Stewart sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 496cfa1ca9dSYoshinobu Inoue m_freem(m); 497cfa1ca9dSYoshinobu Inoue error = ENETDOWN; 498776b7288SRandall Stewart goto end; 499cfa1ca9dSYoshinobu Inoue } 500776b7288SRandall Stewart #ifdef ALTQ 50140138788SRandall Stewart /* 50240138788SRandall Stewart * Make altq aware of the bytes we will add 503776b7288SRandall Stewart * when we actually send it. 504776b7288SRandall Stewart */ 505776b7288SRandall Stewart #ifdef INET 506776b7288SRandall Stewart if (sc->gif_psrc->sa_family == AF_INET) 507776b7288SRandall Stewart m->m_pkthdr.len += GIF_HDR_LEN; 508776b7288SRandall Stewart #endif 509776b7288SRandall Stewart #ifdef INET6 510776b7288SRandall Stewart if (sc->gif_psrc->sa_family == AF_INET6) 511776b7288SRandall Stewart m->m_pkthdr.len += GIF_HDR_LEN6; 512776b7288SRandall Stewart #endif 513776b7288SRandall Stewart #endif 514776b7288SRandall Stewart /* 515776b7288SRandall Stewart * Queue message on interface, update output statistics if 516776b7288SRandall Stewart * successful, and start output if interface not yet active. 517776b7288SRandall Stewart */ 518776b7288SRandall Stewart IFQ_HANDOFF(ifp, m, error); 519cfa1ca9dSYoshinobu Inoue end: 52033841545SHajimu UMEMOTO if (error) 52133841545SHajimu UMEMOTO ifp->if_oerrors++; 52225af0bb5SGleb Smirnoff return (error); 523cfa1ca9dSYoshinobu Inoue } 524cfa1ca9dSYoshinobu Inoue 525cfa1ca9dSYoshinobu Inoue void 52621fb391fSHajimu UMEMOTO gif_input(m, af, ifp) 527cfa1ca9dSYoshinobu Inoue struct mbuf *m; 528cfa1ca9dSYoshinobu Inoue int af; 52921fb391fSHajimu UMEMOTO struct ifnet *ifp; 530cfa1ca9dSYoshinobu Inoue { 53173ff045cSAndrew Thompson int isr, n; 5324382b068SChristian Brueffer struct gif_softc *sc; 53373ff045cSAndrew Thompson struct etherip_header *eip; 53456abdd33SAndrew Thompson struct ether_header *eh; 53556abdd33SAndrew Thompson struct ifnet *oldifp; 536cfa1ca9dSYoshinobu Inoue 53721fb391fSHajimu UMEMOTO if (ifp == NULL) { 538cfa1ca9dSYoshinobu Inoue /* just in case */ 539cfa1ca9dSYoshinobu Inoue m_freem(m); 540cfa1ca9dSYoshinobu Inoue return; 541cfa1ca9dSYoshinobu Inoue } 5424382b068SChristian Brueffer sc = ifp->if_softc; 54321fb391fSHajimu UMEMOTO m->m_pkthdr.rcvif = ifp; 544cfa1ca9dSYoshinobu Inoue 54510722b85SRobert Watson #ifdef MAC 54630d239bcSRobert Watson mac_ifnet_create_mbuf(ifp, m); 54710722b85SRobert Watson #endif 54810722b85SRobert Watson 54916d878ccSChristian S.J. Peron if (bpf_peers_present(ifp->if_bpf)) { 55033841545SHajimu UMEMOTO u_int32_t af1 = af; 551437ffe18SSam Leffler bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m); 552cfa1ca9dSYoshinobu Inoue } 553cfa1ca9dSYoshinobu Inoue 55494408d94SBrooks Davis if (ng_gif_input_p != NULL) { 55521fb391fSHajimu UMEMOTO (*ng_gif_input_p)(ifp, &m, af); 55694408d94SBrooks Davis if (m == NULL) 55794408d94SBrooks Davis return; 55894408d94SBrooks Davis } 55994408d94SBrooks Davis 560cfa1ca9dSYoshinobu Inoue /* 561cfa1ca9dSYoshinobu Inoue * Put the packet to the network layer input queue according to the 562cfa1ca9dSYoshinobu Inoue * specified address family. 563cfa1ca9dSYoshinobu Inoue * Note: older versions of gif_input directly called network layer 564cfa1ca9dSYoshinobu Inoue * input functions, e.g. ip6_input, here. We changed the policy to 565cfa1ca9dSYoshinobu Inoue * prevent too many recursive calls of such input functions, which 566cfa1ca9dSYoshinobu Inoue * might cause kernel panic. But the change may introduce another 567cfa1ca9dSYoshinobu Inoue * problem; if the input queue is full, packets are discarded. 56888ff5695SSUZUKI Shinsuke * The kernel stack overflow really happened, and we believed 56988ff5695SSUZUKI Shinsuke * queue-full rarely occurs, so we changed the policy. 570cfa1ca9dSYoshinobu Inoue */ 571cfa1ca9dSYoshinobu Inoue switch (af) { 572cfa1ca9dSYoshinobu Inoue #ifdef INET 573cfa1ca9dSYoshinobu Inoue case AF_INET: 574cfa1ca9dSYoshinobu Inoue isr = NETISR_IP; 575cfa1ca9dSYoshinobu Inoue break; 576cfa1ca9dSYoshinobu Inoue #endif 577cfa1ca9dSYoshinobu Inoue #ifdef INET6 578cfa1ca9dSYoshinobu Inoue case AF_INET6: 579cfa1ca9dSYoshinobu Inoue isr = NETISR_IPV6; 580cfa1ca9dSYoshinobu Inoue break; 581cfa1ca9dSYoshinobu Inoue #endif 58273ff045cSAndrew Thompson case AF_LINK: 58373ff045cSAndrew Thompson n = sizeof(struct etherip_header) + sizeof(struct ether_header); 58473ff045cSAndrew Thompson if (n > m->m_len) { 58573ff045cSAndrew Thompson m = m_pullup(m, n); 58673ff045cSAndrew Thompson if (m == NULL) { 58773ff045cSAndrew Thompson ifp->if_ierrors++; 58873ff045cSAndrew Thompson return; 58973ff045cSAndrew Thompson } 59073ff045cSAndrew Thompson } 59173ff045cSAndrew Thompson 59273ff045cSAndrew Thompson eip = mtod(m, struct etherip_header *); 593dbe59260SHiroki Sato /* 594dbe59260SHiroki Sato * GIF_ACCEPT_REVETHIP (enabled by default) intentionally 595dbe59260SHiroki Sato * accepts an EtherIP packet with revered version field in 596dbe59260SHiroki Sato * the header. This is a knob for backward compatibility 597dbe59260SHiroki Sato * with FreeBSD 7.2R or prior. 598dbe59260SHiroki Sato */ 599dbe59260SHiroki Sato if (sc->gif_options & GIF_ACCEPT_REVETHIP) { 600dbe59260SHiroki Sato if (eip->eip_resvl != ETHERIP_VERSION 601dbe59260SHiroki Sato && eip->eip_ver != ETHERIP_VERSION) { 60273ff045cSAndrew Thompson /* discard unknown versions */ 60373ff045cSAndrew Thompson m_freem(m); 60473ff045cSAndrew Thompson return; 60573ff045cSAndrew Thompson } 606dbe59260SHiroki Sato } else { 607dbe59260SHiroki Sato if (eip->eip_ver != ETHERIP_VERSION) { 608dbe59260SHiroki Sato /* discard unknown versions */ 609dbe59260SHiroki Sato m_freem(m); 610dbe59260SHiroki Sato return; 611dbe59260SHiroki Sato } 612dbe59260SHiroki Sato } 61373ff045cSAndrew Thompson m_adj(m, sizeof(struct etherip_header)); 61473ff045cSAndrew Thompson 61573ff045cSAndrew Thompson m->m_flags &= ~(M_BCAST|M_MCAST); 61673ff045cSAndrew Thompson m->m_pkthdr.rcvif = ifp; 61773ff045cSAndrew Thompson 61856abdd33SAndrew Thompson if (ifp->if_bridge) { 61956abdd33SAndrew Thompson oldifp = ifp; 62056abdd33SAndrew Thompson eh = mtod(m, struct ether_header *); 62156abdd33SAndrew Thompson if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 62256abdd33SAndrew Thompson if (ETHER_IS_BROADCAST(eh->ether_dhost)) 62356abdd33SAndrew Thompson m->m_flags |= M_BCAST; 62456abdd33SAndrew Thompson else 62556abdd33SAndrew Thompson m->m_flags |= M_MCAST; 62656abdd33SAndrew Thompson ifp->if_imcasts++; 62756abdd33SAndrew Thompson } 62873ff045cSAndrew Thompson BRIDGE_INPUT(ifp, m); 62973ff045cSAndrew Thompson 63056abdd33SAndrew Thompson if (m != NULL && ifp != oldifp) { 63156abdd33SAndrew Thompson /* 63256abdd33SAndrew Thompson * The bridge gave us back itself or one of the 63356abdd33SAndrew Thompson * members for which the frame is addressed. 63456abdd33SAndrew Thompson */ 63556abdd33SAndrew Thompson ether_demux(ifp, m); 63656abdd33SAndrew Thompson return; 63756abdd33SAndrew Thompson } 63856abdd33SAndrew Thompson } 63973ff045cSAndrew Thompson if (m != NULL) 64073ff045cSAndrew Thompson m_freem(m); 64173ff045cSAndrew Thompson return; 64273ff045cSAndrew Thompson 643cfa1ca9dSYoshinobu Inoue default: 64494408d94SBrooks Davis if (ng_gif_input_orphan_p != NULL) 64521fb391fSHajimu UMEMOTO (*ng_gif_input_orphan_p)(ifp, m, af); 64694408d94SBrooks Davis else 647cfa1ca9dSYoshinobu Inoue m_freem(m); 648cfa1ca9dSYoshinobu Inoue return; 649cfa1ca9dSYoshinobu Inoue } 650cfa1ca9dSYoshinobu Inoue 65121fb391fSHajimu UMEMOTO ifp->if_ipackets++; 65221fb391fSHajimu UMEMOTO ifp->if_ibytes += m->m_pkthdr.len; 653a34c6aebSBjoern A. Zeeb M_SETFIB(m, ifp->if_fib); 6541cafed39SJonathan Lemon netisr_dispatch(isr, m); 655cfa1ca9dSYoshinobu Inoue } 656cfa1ca9dSYoshinobu Inoue 657686cdd19SJun-ichiro itojun Hagino /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 658cfa1ca9dSYoshinobu Inoue int 659cfa1ca9dSYoshinobu Inoue gif_ioctl(ifp, cmd, data) 660cfa1ca9dSYoshinobu Inoue struct ifnet *ifp; 661cfa1ca9dSYoshinobu Inoue u_long cmd; 662cfa1ca9dSYoshinobu Inoue caddr_t data; 663cfa1ca9dSYoshinobu Inoue { 664fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 665cfa1ca9dSYoshinobu Inoue struct ifreq *ifr = (struct ifreq*)data; 666cfa1ca9dSYoshinobu Inoue int error = 0, size; 667dbe59260SHiroki Sato u_int options; 668686cdd19SJun-ichiro itojun Hagino struct sockaddr *dst, *src; 6693bb61ca6SHajimu UMEMOTO #ifdef SIOCSIFMTU /* xxx */ 6703bb61ca6SHajimu UMEMOTO u_long mtu; 6713bb61ca6SHajimu UMEMOTO #endif 672cfa1ca9dSYoshinobu Inoue 673cfa1ca9dSYoshinobu Inoue switch (cmd) { 674cfa1ca9dSYoshinobu Inoue case SIOCSIFADDR: 6759426aedfSHajimu UMEMOTO ifp->if_flags |= IFF_UP; 676cfa1ca9dSYoshinobu Inoue break; 677cfa1ca9dSYoshinobu Inoue 678cfa1ca9dSYoshinobu Inoue case SIOCSIFDSTADDR: 679cfa1ca9dSYoshinobu Inoue break; 680cfa1ca9dSYoshinobu Inoue 681cfa1ca9dSYoshinobu Inoue case SIOCADDMULTI: 682cfa1ca9dSYoshinobu Inoue case SIOCDELMULTI: 683cfa1ca9dSYoshinobu Inoue break; 684cfa1ca9dSYoshinobu Inoue 685686cdd19SJun-ichiro itojun Hagino #ifdef SIOCSIFMTU /* xxx */ 686cfa1ca9dSYoshinobu Inoue case SIOCGIFMTU: 687cfa1ca9dSYoshinobu Inoue break; 688686cdd19SJun-ichiro itojun Hagino 689cfa1ca9dSYoshinobu Inoue case SIOCSIFMTU: 690cfa1ca9dSYoshinobu Inoue mtu = ifr->ifr_mtu; 6913bb61ca6SHajimu UMEMOTO if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) 692cfa1ca9dSYoshinobu Inoue return (EINVAL); 693cfa1ca9dSYoshinobu Inoue ifp->if_mtu = mtu; 694cfa1ca9dSYoshinobu Inoue break; 695686cdd19SJun-ichiro itojun Hagino #endif /* SIOCSIFMTU */ 696cfa1ca9dSYoshinobu Inoue 6973bb61ca6SHajimu UMEMOTO #ifdef INET 698cfa1ca9dSYoshinobu Inoue case SIOCSIFPHYADDR: 6993bb61ca6SHajimu UMEMOTO #endif 700cfa1ca9dSYoshinobu Inoue #ifdef INET6 701cfa1ca9dSYoshinobu Inoue case SIOCSIFPHYADDR_IN6: 702cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 70333841545SHajimu UMEMOTO case SIOCSLIFPHYADDR: 704686cdd19SJun-ichiro itojun Hagino switch (cmd) { 70533841545SHajimu UMEMOTO #ifdef INET 706686cdd19SJun-ichiro itojun Hagino case SIOCSIFPHYADDR: 707cfa1ca9dSYoshinobu Inoue src = (struct sockaddr *) 708cfa1ca9dSYoshinobu Inoue &(((struct in_aliasreq *)data)->ifra_addr); 709cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 710cfa1ca9dSYoshinobu Inoue &(((struct in_aliasreq *)data)->ifra_dstaddr); 711cfa1ca9dSYoshinobu Inoue break; 71233841545SHajimu UMEMOTO #endif 713cfa1ca9dSYoshinobu Inoue #ifdef INET6 714686cdd19SJun-ichiro itojun Hagino case SIOCSIFPHYADDR_IN6: 715cfa1ca9dSYoshinobu Inoue src = (struct sockaddr *) 716cfa1ca9dSYoshinobu Inoue &(((struct in6_aliasreq *)data)->ifra_addr); 717cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 718cfa1ca9dSYoshinobu Inoue &(((struct in6_aliasreq *)data)->ifra_dstaddr); 719686cdd19SJun-ichiro itojun Hagino break; 720686cdd19SJun-ichiro itojun Hagino #endif 72133841545SHajimu UMEMOTO case SIOCSLIFPHYADDR: 72233841545SHajimu UMEMOTO src = (struct sockaddr *) 72333841545SHajimu UMEMOTO &(((struct if_laddrreq *)data)->addr); 72433841545SHajimu UMEMOTO dst = (struct sockaddr *) 72533841545SHajimu UMEMOTO &(((struct if_laddrreq *)data)->dstaddr); 7269426aedfSHajimu UMEMOTO break; 7276f4ded3aSBrooks Davis default: 7289426aedfSHajimu UMEMOTO return EINVAL; 72933841545SHajimu UMEMOTO } 73033841545SHajimu UMEMOTO 73133841545SHajimu UMEMOTO /* sa_family must be equal */ 73233841545SHajimu UMEMOTO if (src->sa_family != dst->sa_family) 73333841545SHajimu UMEMOTO return EINVAL; 73433841545SHajimu UMEMOTO 73533841545SHajimu UMEMOTO /* validate sa_len */ 73633841545SHajimu UMEMOTO switch (src->sa_family) { 73733841545SHajimu UMEMOTO #ifdef INET 73833841545SHajimu UMEMOTO case AF_INET: 73933841545SHajimu UMEMOTO if (src->sa_len != sizeof(struct sockaddr_in)) 74033841545SHajimu UMEMOTO return EINVAL; 74133841545SHajimu UMEMOTO break; 74233841545SHajimu UMEMOTO #endif 74333841545SHajimu UMEMOTO #ifdef INET6 74433841545SHajimu UMEMOTO case AF_INET6: 74533841545SHajimu UMEMOTO if (src->sa_len != sizeof(struct sockaddr_in6)) 74633841545SHajimu UMEMOTO return EINVAL; 74733841545SHajimu UMEMOTO break; 74833841545SHajimu UMEMOTO #endif 74933841545SHajimu UMEMOTO default: 75033841545SHajimu UMEMOTO return EAFNOSUPPORT; 75133841545SHajimu UMEMOTO } 75233841545SHajimu UMEMOTO switch (dst->sa_family) { 75333841545SHajimu UMEMOTO #ifdef INET 75433841545SHajimu UMEMOTO case AF_INET: 75533841545SHajimu UMEMOTO if (dst->sa_len != sizeof(struct sockaddr_in)) 75633841545SHajimu UMEMOTO return EINVAL; 75733841545SHajimu UMEMOTO break; 75833841545SHajimu UMEMOTO #endif 75933841545SHajimu UMEMOTO #ifdef INET6 76033841545SHajimu UMEMOTO case AF_INET6: 76133841545SHajimu UMEMOTO if (dst->sa_len != sizeof(struct sockaddr_in6)) 76233841545SHajimu UMEMOTO return EINVAL; 76333841545SHajimu UMEMOTO break; 76433841545SHajimu UMEMOTO #endif 76533841545SHajimu UMEMOTO default: 76633841545SHajimu UMEMOTO return EAFNOSUPPORT; 76733841545SHajimu UMEMOTO } 76833841545SHajimu UMEMOTO 76933841545SHajimu UMEMOTO /* check sa_family looks sane for the cmd */ 77033841545SHajimu UMEMOTO switch (cmd) { 77133841545SHajimu UMEMOTO case SIOCSIFPHYADDR: 77233841545SHajimu UMEMOTO if (src->sa_family == AF_INET) 77333841545SHajimu UMEMOTO break; 77433841545SHajimu UMEMOTO return EAFNOSUPPORT; 77533841545SHajimu UMEMOTO #ifdef INET6 77633841545SHajimu UMEMOTO case SIOCSIFPHYADDR_IN6: 77733841545SHajimu UMEMOTO if (src->sa_family == AF_INET6) 77833841545SHajimu UMEMOTO break; 77933841545SHajimu UMEMOTO return EAFNOSUPPORT; 78033841545SHajimu UMEMOTO #endif /* INET6 */ 78133841545SHajimu UMEMOTO case SIOCSLIFPHYADDR: 78233841545SHajimu UMEMOTO /* checks done in the above */ 78333841545SHajimu UMEMOTO break; 784686cdd19SJun-ichiro itojun Hagino } 785cfa1ca9dSYoshinobu Inoue 786fc74a9f9SBrooks Davis error = gif_set_tunnel(GIF2IFP(sc), src, dst); 787cfa1ca9dSYoshinobu Inoue break; 788cfa1ca9dSYoshinobu Inoue 789686cdd19SJun-ichiro itojun Hagino #ifdef SIOCDIFPHYADDR 790686cdd19SJun-ichiro itojun Hagino case SIOCDIFPHYADDR: 791fc74a9f9SBrooks Davis gif_delete_tunnel(GIF2IFP(sc)); 792686cdd19SJun-ichiro itojun Hagino break; 793686cdd19SJun-ichiro itojun Hagino #endif 794686cdd19SJun-ichiro itojun Hagino 795cfa1ca9dSYoshinobu Inoue case SIOCGIFPSRCADDR: 796cfa1ca9dSYoshinobu Inoue #ifdef INET6 797cfa1ca9dSYoshinobu Inoue case SIOCGIFPSRCADDR_IN6: 798cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 799cfa1ca9dSYoshinobu Inoue if (sc->gif_psrc == NULL) { 800cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 801cfa1ca9dSYoshinobu Inoue goto bad; 802cfa1ca9dSYoshinobu Inoue } 803cfa1ca9dSYoshinobu Inoue src = sc->gif_psrc; 80433841545SHajimu UMEMOTO switch (cmd) { 805cfa1ca9dSYoshinobu Inoue #ifdef INET 80633841545SHajimu UMEMOTO case SIOCGIFPSRCADDR: 807cfa1ca9dSYoshinobu Inoue dst = &ifr->ifr_addr; 80833841545SHajimu UMEMOTO size = sizeof(ifr->ifr_addr); 809cfa1ca9dSYoshinobu Inoue break; 810cfa1ca9dSYoshinobu Inoue #endif /* INET */ 811cfa1ca9dSYoshinobu Inoue #ifdef INET6 81233841545SHajimu UMEMOTO case SIOCGIFPSRCADDR_IN6: 813cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 814cfa1ca9dSYoshinobu Inoue &(((struct in6_ifreq *)data)->ifr_addr); 81533841545SHajimu UMEMOTO size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 816cfa1ca9dSYoshinobu Inoue break; 817cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 818cfa1ca9dSYoshinobu Inoue default: 819cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 820cfa1ca9dSYoshinobu Inoue goto bad; 821cfa1ca9dSYoshinobu Inoue } 82233841545SHajimu UMEMOTO if (src->sa_len > size) 82333841545SHajimu UMEMOTO return EINVAL; 82433841545SHajimu UMEMOTO bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 825a1f7e5f8SHajimu UMEMOTO #ifdef INET6 826a1f7e5f8SHajimu UMEMOTO if (dst->sa_family == AF_INET6) { 827a1f7e5f8SHajimu UMEMOTO error = sa6_recoverscope((struct sockaddr_in6 *)dst); 828a1f7e5f8SHajimu UMEMOTO if (error != 0) 829a1f7e5f8SHajimu UMEMOTO return (error); 830a1f7e5f8SHajimu UMEMOTO } 831a1f7e5f8SHajimu UMEMOTO #endif 832cfa1ca9dSYoshinobu Inoue break; 833cfa1ca9dSYoshinobu Inoue 834cfa1ca9dSYoshinobu Inoue case SIOCGIFPDSTADDR: 835cfa1ca9dSYoshinobu Inoue #ifdef INET6 836cfa1ca9dSYoshinobu Inoue case SIOCGIFPDSTADDR_IN6: 837cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 838cfa1ca9dSYoshinobu Inoue if (sc->gif_pdst == NULL) { 839cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 840cfa1ca9dSYoshinobu Inoue goto bad; 841cfa1ca9dSYoshinobu Inoue } 842cfa1ca9dSYoshinobu Inoue src = sc->gif_pdst; 84333841545SHajimu UMEMOTO switch (cmd) { 844cfa1ca9dSYoshinobu Inoue #ifdef INET 84533841545SHajimu UMEMOTO case SIOCGIFPDSTADDR: 846cfa1ca9dSYoshinobu Inoue dst = &ifr->ifr_addr; 84733841545SHajimu UMEMOTO size = sizeof(ifr->ifr_addr); 848cfa1ca9dSYoshinobu Inoue break; 849cfa1ca9dSYoshinobu Inoue #endif /* INET */ 850cfa1ca9dSYoshinobu Inoue #ifdef INET6 85133841545SHajimu UMEMOTO case SIOCGIFPDSTADDR_IN6: 852cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 853cfa1ca9dSYoshinobu Inoue &(((struct in6_ifreq *)data)->ifr_addr); 85433841545SHajimu UMEMOTO size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 855cfa1ca9dSYoshinobu Inoue break; 856cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 857cfa1ca9dSYoshinobu Inoue default: 858cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 859cfa1ca9dSYoshinobu Inoue goto bad; 860cfa1ca9dSYoshinobu Inoue } 86133841545SHajimu UMEMOTO if (src->sa_len > size) 86233841545SHajimu UMEMOTO return EINVAL; 863e3416ab0SBjoern A. Zeeb error = prison_if(curthread->td_ucred, src); 864e3416ab0SBjoern A. Zeeb if (error != 0) 865e3416ab0SBjoern A. Zeeb return (error); 866e3416ab0SBjoern A. Zeeb error = prison_if(curthread->td_ucred, dst); 867e3416ab0SBjoern A. Zeeb if (error != 0) 868e3416ab0SBjoern A. Zeeb return (error); 86933841545SHajimu UMEMOTO bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 870a1f7e5f8SHajimu UMEMOTO #ifdef INET6 871a1f7e5f8SHajimu UMEMOTO if (dst->sa_family == AF_INET6) { 872a1f7e5f8SHajimu UMEMOTO error = sa6_recoverscope((struct sockaddr_in6 *)dst); 873a1f7e5f8SHajimu UMEMOTO if (error != 0) 874a1f7e5f8SHajimu UMEMOTO return (error); 875a1f7e5f8SHajimu UMEMOTO } 876a1f7e5f8SHajimu UMEMOTO #endif 87733841545SHajimu UMEMOTO break; 87833841545SHajimu UMEMOTO 87933841545SHajimu UMEMOTO case SIOCGLIFPHYADDR: 88033841545SHajimu UMEMOTO if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 88133841545SHajimu UMEMOTO error = EADDRNOTAVAIL; 88233841545SHajimu UMEMOTO goto bad; 88333841545SHajimu UMEMOTO } 88433841545SHajimu UMEMOTO 88533841545SHajimu UMEMOTO /* copy src */ 88633841545SHajimu UMEMOTO src = sc->gif_psrc; 88733841545SHajimu UMEMOTO dst = (struct sockaddr *) 88833841545SHajimu UMEMOTO &(((struct if_laddrreq *)data)->addr); 88933841545SHajimu UMEMOTO size = sizeof(((struct if_laddrreq *)data)->addr); 89033841545SHajimu UMEMOTO if (src->sa_len > size) 89133841545SHajimu UMEMOTO return EINVAL; 89233841545SHajimu UMEMOTO bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 89333841545SHajimu UMEMOTO 89433841545SHajimu UMEMOTO /* copy dst */ 89533841545SHajimu UMEMOTO src = sc->gif_pdst; 89633841545SHajimu UMEMOTO dst = (struct sockaddr *) 89733841545SHajimu UMEMOTO &(((struct if_laddrreq *)data)->dstaddr); 89833841545SHajimu UMEMOTO size = sizeof(((struct if_laddrreq *)data)->dstaddr); 89933841545SHajimu UMEMOTO if (src->sa_len > size) 90033841545SHajimu UMEMOTO return EINVAL; 90133841545SHajimu UMEMOTO bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 902cfa1ca9dSYoshinobu Inoue break; 903cfa1ca9dSYoshinobu Inoue 904cfa1ca9dSYoshinobu Inoue case SIOCSIFFLAGS: 905686cdd19SJun-ichiro itojun Hagino /* if_ioctl() takes care of it */ 906cfa1ca9dSYoshinobu Inoue break; 907cfa1ca9dSYoshinobu Inoue 908dbe59260SHiroki Sato case GIFGOPTS: 909dbe59260SHiroki Sato options = sc->gif_options; 910dbe59260SHiroki Sato error = copyout(&options, ifr->ifr_data, 911dbe59260SHiroki Sato sizeof(options)); 912dbe59260SHiroki Sato break; 913dbe59260SHiroki Sato 914dbe59260SHiroki Sato case GIFSOPTS: 915dbe59260SHiroki Sato if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0) 916dbe59260SHiroki Sato break; 9174cd5f57dSHiroki Sato error = copyin(ifr->ifr_data, &options, sizeof(options)); 9184cd5f57dSHiroki Sato if (error) 9194cd5f57dSHiroki Sato break; 9204cd5f57dSHiroki Sato if (options & ~GIF_OPTMASK) 921dbe59260SHiroki Sato error = EINVAL; 9224cd5f57dSHiroki Sato else 9234cd5f57dSHiroki Sato sc->gif_options = options; 924dbe59260SHiroki Sato break; 925dbe59260SHiroki Sato 926cfa1ca9dSYoshinobu Inoue default: 927cfa1ca9dSYoshinobu Inoue error = EINVAL; 928cfa1ca9dSYoshinobu Inoue break; 929cfa1ca9dSYoshinobu Inoue } 930cfa1ca9dSYoshinobu Inoue bad: 931cfa1ca9dSYoshinobu Inoue return error; 932cfa1ca9dSYoshinobu Inoue } 93353dab5feSBrooks Davis 93417d5cb2dSRobert Watson /* 93517d5cb2dSRobert Watson * XXXRW: There's a general event-ordering issue here: the code to check 93617d5cb2dSRobert Watson * if a given tunnel is already present happens before we perform a 93717d5cb2dSRobert Watson * potentially blocking setup of the tunnel. This code needs to be 93817d5cb2dSRobert Watson * re-ordered so that the check and replacement can be atomic using 93917d5cb2dSRobert Watson * a mutex. 94017d5cb2dSRobert Watson */ 9419426aedfSHajimu UMEMOTO int 9429426aedfSHajimu UMEMOTO gif_set_tunnel(ifp, src, dst) 9439426aedfSHajimu UMEMOTO struct ifnet *ifp; 9449426aedfSHajimu UMEMOTO struct sockaddr *src; 9459426aedfSHajimu UMEMOTO struct sockaddr *dst; 94653dab5feSBrooks Davis { 947fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 9489426aedfSHajimu UMEMOTO struct gif_softc *sc2; 9499426aedfSHajimu UMEMOTO struct sockaddr *osrc, *odst, *sa; 9509426aedfSHajimu UMEMOTO int error = 0; 9519426aedfSHajimu UMEMOTO 95217d5cb2dSRobert Watson mtx_lock(&gif_mtx); 953603724d3SBjoern A. Zeeb LIST_FOREACH(sc2, &V_gif_softc_list, gif_list) { 9549426aedfSHajimu UMEMOTO if (sc2 == sc) 9559426aedfSHajimu UMEMOTO continue; 9569426aedfSHajimu UMEMOTO if (!sc2->gif_pdst || !sc2->gif_psrc) 9579426aedfSHajimu UMEMOTO continue; 9589426aedfSHajimu UMEMOTO if (sc2->gif_pdst->sa_family != dst->sa_family || 9599426aedfSHajimu UMEMOTO sc2->gif_pdst->sa_len != dst->sa_len || 9609426aedfSHajimu UMEMOTO sc2->gif_psrc->sa_family != src->sa_family || 9619426aedfSHajimu UMEMOTO sc2->gif_psrc->sa_len != src->sa_len) 9629426aedfSHajimu UMEMOTO continue; 9639426aedfSHajimu UMEMOTO 9649426aedfSHajimu UMEMOTO /* 9659426aedfSHajimu UMEMOTO * Disallow parallel tunnels unless instructed 9669426aedfSHajimu UMEMOTO * otherwise. 9679426aedfSHajimu UMEMOTO */ 968603724d3SBjoern A. Zeeb if (!V_parallel_tunnels && 9699426aedfSHajimu UMEMOTO bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 9709426aedfSHajimu UMEMOTO bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 9719426aedfSHajimu UMEMOTO error = EADDRNOTAVAIL; 97217d5cb2dSRobert Watson mtx_unlock(&gif_mtx); 9739426aedfSHajimu UMEMOTO goto bad; 9749426aedfSHajimu UMEMOTO } 9759426aedfSHajimu UMEMOTO 9769426aedfSHajimu UMEMOTO /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 9779426aedfSHajimu UMEMOTO } 97817d5cb2dSRobert Watson mtx_unlock(&gif_mtx); 9799426aedfSHajimu UMEMOTO 9809426aedfSHajimu UMEMOTO /* XXX we can detach from both, but be polite just in case */ 9819426aedfSHajimu UMEMOTO if (sc->gif_psrc) 9829426aedfSHajimu UMEMOTO switch (sc->gif_psrc->sa_family) { 9839426aedfSHajimu UMEMOTO #ifdef INET 9849426aedfSHajimu UMEMOTO case AF_INET: 9859426aedfSHajimu UMEMOTO (void)in_gif_detach(sc); 9869426aedfSHajimu UMEMOTO break; 9879426aedfSHajimu UMEMOTO #endif 9889426aedfSHajimu UMEMOTO #ifdef INET6 9899426aedfSHajimu UMEMOTO case AF_INET6: 9909426aedfSHajimu UMEMOTO (void)in6_gif_detach(sc); 9919426aedfSHajimu UMEMOTO break; 9929426aedfSHajimu UMEMOTO #endif 9939426aedfSHajimu UMEMOTO } 9949426aedfSHajimu UMEMOTO 9959426aedfSHajimu UMEMOTO osrc = sc->gif_psrc; 996a163d034SWarner Losh sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); 9979426aedfSHajimu UMEMOTO bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 9989426aedfSHajimu UMEMOTO sc->gif_psrc = sa; 9999426aedfSHajimu UMEMOTO 10009426aedfSHajimu UMEMOTO odst = sc->gif_pdst; 1001a163d034SWarner Losh sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); 10029426aedfSHajimu UMEMOTO bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 10039426aedfSHajimu UMEMOTO sc->gif_pdst = sa; 10049426aedfSHajimu UMEMOTO 10059426aedfSHajimu UMEMOTO switch (sc->gif_psrc->sa_family) { 10069426aedfSHajimu UMEMOTO #ifdef INET 10079426aedfSHajimu UMEMOTO case AF_INET: 10089426aedfSHajimu UMEMOTO error = in_gif_attach(sc); 10099426aedfSHajimu UMEMOTO break; 10109426aedfSHajimu UMEMOTO #endif 10119426aedfSHajimu UMEMOTO #ifdef INET6 10129426aedfSHajimu UMEMOTO case AF_INET6: 1013a1f7e5f8SHajimu UMEMOTO /* 1014a1f7e5f8SHajimu UMEMOTO * Check validity of the scope zone ID of the addresses, and 1015a1f7e5f8SHajimu UMEMOTO * convert it into the kernel internal form if necessary. 1016a1f7e5f8SHajimu UMEMOTO */ 1017a1f7e5f8SHajimu UMEMOTO error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_psrc, 0); 1018a1f7e5f8SHajimu UMEMOTO if (error != 0) 1019a1f7e5f8SHajimu UMEMOTO break; 1020a1f7e5f8SHajimu UMEMOTO error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_pdst, 0); 1021a1f7e5f8SHajimu UMEMOTO if (error != 0) 1022a1f7e5f8SHajimu UMEMOTO break; 10239426aedfSHajimu UMEMOTO error = in6_gif_attach(sc); 10249426aedfSHajimu UMEMOTO break; 10259426aedfSHajimu UMEMOTO #endif 10269426aedfSHajimu UMEMOTO } 10279426aedfSHajimu UMEMOTO if (error) { 10289426aedfSHajimu UMEMOTO /* rollback */ 10299426aedfSHajimu UMEMOTO free((caddr_t)sc->gif_psrc, M_IFADDR); 10309426aedfSHajimu UMEMOTO free((caddr_t)sc->gif_pdst, M_IFADDR); 10319426aedfSHajimu UMEMOTO sc->gif_psrc = osrc; 10329426aedfSHajimu UMEMOTO sc->gif_pdst = odst; 10339426aedfSHajimu UMEMOTO goto bad; 10349426aedfSHajimu UMEMOTO } 10359426aedfSHajimu UMEMOTO 10369426aedfSHajimu UMEMOTO if (osrc) 10379426aedfSHajimu UMEMOTO free((caddr_t)osrc, M_IFADDR); 10389426aedfSHajimu UMEMOTO if (odst) 10399426aedfSHajimu UMEMOTO free((caddr_t)odst, M_IFADDR); 10409426aedfSHajimu UMEMOTO 10419426aedfSHajimu UMEMOTO bad: 10429426aedfSHajimu UMEMOTO if (sc->gif_psrc && sc->gif_pdst) 104313f4c340SRobert Watson ifp->if_drv_flags |= IFF_DRV_RUNNING; 10449426aedfSHajimu UMEMOTO else 104513f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 10469426aedfSHajimu UMEMOTO 10479426aedfSHajimu UMEMOTO return error; 10489426aedfSHajimu UMEMOTO } 10499426aedfSHajimu UMEMOTO 10509426aedfSHajimu UMEMOTO void 10519426aedfSHajimu UMEMOTO gif_delete_tunnel(ifp) 10529426aedfSHajimu UMEMOTO struct ifnet *ifp; 10539426aedfSHajimu UMEMOTO { 1054fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 105553dab5feSBrooks Davis 105653dab5feSBrooks Davis if (sc->gif_psrc) { 105753dab5feSBrooks Davis free((caddr_t)sc->gif_psrc, M_IFADDR); 105853dab5feSBrooks Davis sc->gif_psrc = NULL; 105953dab5feSBrooks Davis } 106053dab5feSBrooks Davis if (sc->gif_pdst) { 106153dab5feSBrooks Davis free((caddr_t)sc->gif_pdst, M_IFADDR); 106253dab5feSBrooks Davis sc->gif_pdst = NULL; 106353dab5feSBrooks Davis } 10649426aedfSHajimu UMEMOTO /* it is safe to detach from both */ 10659426aedfSHajimu UMEMOTO #ifdef INET 10669426aedfSHajimu UMEMOTO (void)in_gif_detach(sc); 10679426aedfSHajimu UMEMOTO #endif 10689426aedfSHajimu UMEMOTO #ifdef INET6 10699426aedfSHajimu UMEMOTO (void)in6_gif_detach(sc); 10709426aedfSHajimu UMEMOTO #endif 107113f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 107253dab5feSBrooks Davis } 1073