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> 5676039bc8SGleb Smirnoff #include <net/if_var.h> 57f889d2efSBrooks Davis #include <net/if_clone.h> 58cfa1ca9dSYoshinobu Inoue #include <net/if_types.h> 59cfa1ca9dSYoshinobu Inoue #include <net/netisr.h> 60cfa1ca9dSYoshinobu Inoue #include <net/route.h> 61cfa1ca9dSYoshinobu Inoue #include <net/bpf.h> 62530c0060SRobert Watson #include <net/vnet.h> 63cfa1ca9dSYoshinobu Inoue 64cfa1ca9dSYoshinobu Inoue #include <netinet/in.h> 65cfa1ca9dSYoshinobu Inoue #include <netinet/in_systm.h> 66cfa1ca9dSYoshinobu Inoue #include <netinet/ip.h> 6733841545SHajimu UMEMOTO #ifdef INET 6833841545SHajimu UMEMOTO #include <netinet/in_var.h> 69cfa1ca9dSYoshinobu Inoue #include <netinet/in_gif.h> 7053dab5feSBrooks Davis #include <netinet/ip_var.h> 71cfa1ca9dSYoshinobu Inoue #endif /* INET */ 72cfa1ca9dSYoshinobu Inoue 73cfa1ca9dSYoshinobu Inoue #ifdef INET6 74cfa1ca9dSYoshinobu Inoue #ifndef INET 75cfa1ca9dSYoshinobu Inoue #include <netinet/in.h> 76cfa1ca9dSYoshinobu Inoue #endif 77cfa1ca9dSYoshinobu Inoue #include <netinet6/in6_var.h> 78cfa1ca9dSYoshinobu Inoue #include <netinet/ip6.h> 79cfa1ca9dSYoshinobu Inoue #include <netinet6/ip6_var.h> 80a1f7e5f8SHajimu UMEMOTO #include <netinet6/scope6_var.h> 81cfa1ca9dSYoshinobu Inoue #include <netinet6/in6_gif.h> 82686cdd19SJun-ichiro itojun Hagino #include <netinet6/ip6protosw.h> 83cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 84cfa1ca9dSYoshinobu Inoue 85686cdd19SJun-ichiro itojun Hagino #include <netinet/ip_encap.h> 8673ff045cSAndrew Thompson #include <net/ethernet.h> 8773ff045cSAndrew Thompson #include <net/if_bridgevar.h> 88cfa1ca9dSYoshinobu Inoue #include <net/if_gif.h> 89cfa1ca9dSYoshinobu Inoue 90aed55708SRobert Watson #include <security/mac/mac_framework.h> 91aed55708SRobert Watson 9242a58907SGleb Smirnoff static const char gifname[] = "gif"; 93686cdd19SJun-ichiro itojun Hagino 9417d5cb2dSRobert Watson /* 95a7f5886eSHiroki Sato * gif_mtx protects a per-vnet gif_softc_list. 9617d5cb2dSRobert Watson */ 97a7f5886eSHiroki Sato static VNET_DEFINE(struct mtx, gif_mtx); 98a7f5886eSHiroki Sato #define V_gif_mtx VNET(gif_mtx) 9953dab5feSBrooks Davis static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); 1003e288e62SDimitry Andric static VNET_DEFINE(LIST_HEAD(, gif_softc), gif_softc_list); 1011e77c105SRobert Watson #define V_gif_softc_list VNET(gif_softc_list) 102eddfbb76SRobert Watson 103a7f5886eSHiroki Sato #define GIF_LIST_LOCK_INIT(x) mtx_init(&V_gif_mtx, "gif_mtx", \ 104a7f5886eSHiroki Sato NULL, MTX_DEF) 105a7f5886eSHiroki Sato #define GIF_LIST_LOCK_DESTROY(x) mtx_destroy(&V_gif_mtx) 106a7f5886eSHiroki Sato #define GIF_LIST_LOCK(x) mtx_lock(&V_gif_mtx) 107a7f5886eSHiroki Sato #define GIF_LIST_UNLOCK(x) mtx_unlock(&V_gif_mtx) 108a7f5886eSHiroki Sato 10994408d94SBrooks Davis void (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); 11094408d94SBrooks Davis void (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); 11194408d94SBrooks Davis void (*ng_gif_attach_p)(struct ifnet *ifp); 11294408d94SBrooks Davis void (*ng_gif_detach_p)(struct ifnet *ifp); 11394408d94SBrooks Davis 11473ff045cSAndrew Thompson static void gif_start(struct ifnet *); 1156b7330e2SSam Leffler static int gif_clone_create(struct if_clone *, int, caddr_t); 116bb2bfb4fSBrooks Davis static void gif_clone_destroy(struct ifnet *); 117a7f5886eSHiroki Sato static VNET_DEFINE(struct if_clone *, gif_cloner); 118a7f5886eSHiroki Sato #define V_gif_cloner VNET(gif_cloner) 11953dab5feSBrooks Davis 120929ddbbbSAlfred Perlstein static int gifmodevent(module_t, int, void *); 121cfa1ca9dSYoshinobu Inoue 122872f786aSBrooks Davis SYSCTL_DECL(_net_link); 1236472ac3dSEd Schouten static SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0, 124872f786aSBrooks Davis "Generic Tunnel Interface"); 125686cdd19SJun-ichiro itojun Hagino #ifndef MAX_GIF_NEST 126686cdd19SJun-ichiro itojun Hagino /* 127872f786aSBrooks Davis * This macro controls the default upper limitation on nesting of gif tunnels. 128686cdd19SJun-ichiro itojun Hagino * Since, setting a large value to this macro with a careless configuration 129686cdd19SJun-ichiro itojun Hagino * may introduce system crash, we don't allow any nestings by default. 130686cdd19SJun-ichiro itojun Hagino * If you need to configure nested gif tunnels, you can define this macro 131686cdd19SJun-ichiro itojun Hagino * in your kernel configuration file. However, if you do so, please be 132686cdd19SJun-ichiro itojun Hagino * careful to configure the tunnels so that it won't make a loop. 133686cdd19SJun-ichiro itojun Hagino */ 134686cdd19SJun-ichiro itojun Hagino #define MAX_GIF_NEST 1 135686cdd19SJun-ichiro itojun Hagino #endif 1363e288e62SDimitry Andric static VNET_DEFINE(int, max_gif_nesting) = MAX_GIF_NEST; 137d0728d71SRobert Watson #define V_max_gif_nesting VNET(max_gif_nesting) 138eddfbb76SRobert Watson SYSCTL_VNET_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW, 139eddfbb76SRobert Watson &VNET_NAME(max_gif_nesting), 0, "Max nested tunnels"); 1408b615593SMarko Zec 141872f786aSBrooks Davis /* 142872f786aSBrooks Davis * By default, we disallow creation of multiple tunnels between the same 143872f786aSBrooks Davis * pair of addresses. Some applications require this functionality so 144872f786aSBrooks Davis * we allow control over this check here. 145872f786aSBrooks Davis */ 146d0728d71SRobert Watson #ifdef XBONEHACK 1473e288e62SDimitry Andric static VNET_DEFINE(int, parallel_tunnels) = 1; 148d0728d71SRobert Watson #else 1493e288e62SDimitry Andric static VNET_DEFINE(int, parallel_tunnels) = 0; 150d0728d71SRobert Watson #endif 151d0728d71SRobert Watson #define V_parallel_tunnels VNET(parallel_tunnels) 152eddfbb76SRobert Watson SYSCTL_VNET_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW, 153eddfbb76SRobert Watson &VNET_NAME(parallel_tunnels), 0, "Allow parallel tunnels?"); 154cfa1ca9dSYoshinobu Inoue 15556abdd33SAndrew Thompson /* copy from src/sys/net/if_ethersubr.c */ 15656abdd33SAndrew Thompson static const u_char etherbroadcastaddr[ETHER_ADDR_LEN] = 15756abdd33SAndrew Thompson { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 15856abdd33SAndrew Thompson #ifndef ETHER_IS_BROADCAST 15956abdd33SAndrew Thompson #define ETHER_IS_BROADCAST(addr) \ 16056abdd33SAndrew Thompson (bcmp(etherbroadcastaddr, (addr), ETHER_ADDR_LEN) == 0) 16156abdd33SAndrew Thompson #endif 16256abdd33SAndrew Thompson 163bb2bfb4fSBrooks Davis static int 164c72a5d5dSAndrey V. Elsukov gif_clone_create(struct if_clone *ifc, int unit, caddr_t params) 165cfa1ca9dSYoshinobu Inoue { 16633841545SHajimu UMEMOTO struct gif_softc *sc; 167cfa1ca9dSYoshinobu Inoue 168e1a8c3dcSBruce M Simpson sc = malloc(sizeof(struct gif_softc), M_GIF, M_WAITOK | M_ZERO); 1698b07e49aSJulian Elischer sc->gif_fibnum = curthread->td_proc->p_fibnum; 170fc74a9f9SBrooks Davis GIF2IFP(sc) = if_alloc(IFT_GIF); 171fc74a9f9SBrooks Davis if (GIF2IFP(sc) == NULL) { 172fc74a9f9SBrooks Davis free(sc, M_GIF); 173fc74a9f9SBrooks Davis return (ENOSPC); 174fc74a9f9SBrooks Davis } 17553dab5feSBrooks Davis 17625af0bb5SGleb Smirnoff GIF_LOCK_INIT(sc); 17725af0bb5SGleb Smirnoff 178fc74a9f9SBrooks Davis GIF2IFP(sc)->if_softc = sc; 17942a58907SGleb Smirnoff if_initname(GIF2IFP(sc), gifname, unit); 180686cdd19SJun-ichiro itojun Hagino 1819426aedfSHajimu UMEMOTO sc->encap_cookie4 = sc->encap_cookie6 = NULL; 182e9f947e2SHiroki Sato sc->gif_options = 0; 1839426aedfSHajimu UMEMOTO 184fc74a9f9SBrooks Davis GIF2IFP(sc)->if_addrlen = 0; 185fc74a9f9SBrooks Davis GIF2IFP(sc)->if_mtu = GIF_MTU; 186fc74a9f9SBrooks Davis GIF2IFP(sc)->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 18733841545SHajimu UMEMOTO #if 0 18833841545SHajimu UMEMOTO /* turn off ingress filter */ 189fc74a9f9SBrooks Davis GIF2IFP(sc)->if_flags |= IFF_LINK2; 19033841545SHajimu UMEMOTO #endif 191fc74a9f9SBrooks Davis GIF2IFP(sc)->if_ioctl = gif_ioctl; 19273ff045cSAndrew Thompson GIF2IFP(sc)->if_start = gif_start; 193fc74a9f9SBrooks Davis GIF2IFP(sc)->if_output = gif_output; 194e50d35e6SMaxim Sobolev GIF2IFP(sc)->if_snd.ifq_maxlen = ifqmaxlen; 195fc74a9f9SBrooks Davis if_attach(GIF2IFP(sc)); 19601399f34SDavid Malone bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int32_t)); 19794408d94SBrooks Davis if (ng_gif_attach_p != NULL) 198fc74a9f9SBrooks Davis (*ng_gif_attach_p)(GIF2IFP(sc)); 19925af0bb5SGleb Smirnoff 200a7f5886eSHiroki Sato GIF_LIST_LOCK(); 201603724d3SBjoern A. Zeeb LIST_INSERT_HEAD(&V_gif_softc_list, sc, gif_list); 202a7f5886eSHiroki Sato GIF_LIST_UNLOCK(); 20325af0bb5SGleb Smirnoff 20425af0bb5SGleb Smirnoff return (0); 205cfa1ca9dSYoshinobu Inoue } 206cfa1ca9dSYoshinobu Inoue 20717d5cb2dSRobert Watson static void 208c72a5d5dSAndrey V. Elsukov gif_clone_destroy(struct ifnet *ifp) 20953dab5feSBrooks Davis { 210e0de57f9SBjoern A. Zeeb #if defined(INET) || defined(INET6) 21153dab5feSBrooks Davis int err; 212e0de57f9SBjoern A. Zeeb #endif 213febd0759SAndrew Thompson struct gif_softc *sc = ifp->if_softc; 214febd0759SAndrew Thompson 215a7f5886eSHiroki Sato GIF_LIST_LOCK(); 216febd0759SAndrew Thompson LIST_REMOVE(sc, gif_list); 217a7f5886eSHiroki Sato GIF_LIST_UNLOCK(); 21853dab5feSBrooks Davis 21917d5cb2dSRobert Watson gif_delete_tunnel(ifp); 2209426aedfSHajimu UMEMOTO #ifdef INET6 22153dab5feSBrooks Davis if (sc->encap_cookie6 != NULL) { 22253dab5feSBrooks Davis err = encap_detach(sc->encap_cookie6); 22353dab5feSBrooks Davis KASSERT(err == 0, ("Unexpected error detaching encap_cookie6")); 22453dab5feSBrooks Davis } 2259426aedfSHajimu UMEMOTO #endif 2269426aedfSHajimu UMEMOTO #ifdef INET 2279426aedfSHajimu UMEMOTO if (sc->encap_cookie4 != NULL) { 2289426aedfSHajimu UMEMOTO err = encap_detach(sc->encap_cookie4); 2299426aedfSHajimu UMEMOTO KASSERT(err == 0, ("Unexpected error detaching encap_cookie4")); 2309426aedfSHajimu UMEMOTO } 2319426aedfSHajimu UMEMOTO #endif 23253dab5feSBrooks Davis 23394408d94SBrooks Davis if (ng_gif_detach_p != NULL) 23494408d94SBrooks Davis (*ng_gif_detach_p)(ifp); 23553dab5feSBrooks Davis bpfdetach(ifp); 23653dab5feSBrooks Davis if_detach(ifp); 237fc74a9f9SBrooks Davis if_free(ifp); 23853dab5feSBrooks Davis 23925af0bb5SGleb Smirnoff GIF_LOCK_DESTROY(sc); 24025af0bb5SGleb Smirnoff 24153dab5feSBrooks Davis free(sc, M_GIF); 24253dab5feSBrooks Davis } 24353dab5feSBrooks Davis 244d0728d71SRobert Watson static void 245d0728d71SRobert Watson vnet_gif_init(const void *unused __unused) 2461ed81b73SMarko Zec { 2471ed81b73SMarko Zec 2481ed81b73SMarko Zec LIST_INIT(&V_gif_softc_list); 249a7f5886eSHiroki Sato GIF_LIST_LOCK_INIT(); 250a7f5886eSHiroki Sato V_gif_cloner = if_clone_simple(gifname, gif_clone_create, 251a7f5886eSHiroki Sato gif_clone_destroy, 0); 2521ed81b73SMarko Zec } 253a7f5886eSHiroki Sato VNET_SYSINIT(vnet_gif_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 254a7f5886eSHiroki Sato vnet_gif_init, NULL); 255a7f5886eSHiroki Sato 256a7f5886eSHiroki Sato static void 257a7f5886eSHiroki Sato vnet_gif_uninit(const void *unused __unused) 258a7f5886eSHiroki Sato { 259a7f5886eSHiroki Sato 260a7f5886eSHiroki Sato if_clone_detach(V_gif_cloner); 261a7f5886eSHiroki Sato GIF_LIST_LOCK_DESTROY(); 262a7f5886eSHiroki Sato } 263a7f5886eSHiroki Sato VNET_SYSUNINIT(vnet_gif_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 264a7f5886eSHiroki Sato vnet_gif_uninit, NULL); 2651ed81b73SMarko Zec 2661ed81b73SMarko Zec static int 267c72a5d5dSAndrey V. Elsukov gifmodevent(module_t mod, int type, void *data) 26853dab5feSBrooks Davis { 26953dab5feSBrooks Davis 27053dab5feSBrooks Davis switch (type) { 27153dab5feSBrooks Davis case MOD_LOAD: 27253dab5feSBrooks Davis case MOD_UNLOAD: 27353dab5feSBrooks Davis break; 2743e019deaSPoul-Henning Kamp default: 275a7f5886eSHiroki Sato return (EOPNOTSUPP); 27653dab5feSBrooks Davis } 277a7f5886eSHiroki Sato return (0); 27853dab5feSBrooks Davis } 27953dab5feSBrooks Davis 28053dab5feSBrooks Davis static moduledata_t gif_mod = { 28153dab5feSBrooks Davis "if_gif", 28253dab5feSBrooks Davis gifmodevent, 2839823d527SKevin Lo 0 28453dab5feSBrooks Davis }; 28553dab5feSBrooks Davis 28653dab5feSBrooks Davis DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 28720af0ffaSBrooks Davis MODULE_VERSION(if_gif, 1); 288cfa1ca9dSYoshinobu Inoue 2899426aedfSHajimu UMEMOTO int 290c72a5d5dSAndrey V. Elsukov gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 291686cdd19SJun-ichiro itojun Hagino { 292686cdd19SJun-ichiro itojun Hagino struct ip ip; 293686cdd19SJun-ichiro itojun Hagino struct gif_softc *sc; 294686cdd19SJun-ichiro itojun Hagino 295686cdd19SJun-ichiro itojun Hagino sc = (struct gif_softc *)arg; 296686cdd19SJun-ichiro itojun Hagino if (sc == NULL) 297686cdd19SJun-ichiro itojun Hagino return 0; 298686cdd19SJun-ichiro itojun Hagino 299fc74a9f9SBrooks Davis if ((GIF2IFP(sc)->if_flags & IFF_UP) == 0) 300686cdd19SJun-ichiro itojun Hagino return 0; 301686cdd19SJun-ichiro itojun Hagino 302686cdd19SJun-ichiro itojun Hagino /* no physical address */ 303686cdd19SJun-ichiro itojun Hagino if (!sc->gif_psrc || !sc->gif_pdst) 304686cdd19SJun-ichiro itojun Hagino return 0; 305686cdd19SJun-ichiro itojun Hagino 306686cdd19SJun-ichiro itojun Hagino switch (proto) { 307686cdd19SJun-ichiro itojun Hagino #ifdef INET 308686cdd19SJun-ichiro itojun Hagino case IPPROTO_IPV4: 309686cdd19SJun-ichiro itojun Hagino break; 310686cdd19SJun-ichiro itojun Hagino #endif 311686cdd19SJun-ichiro itojun Hagino #ifdef INET6 312686cdd19SJun-ichiro itojun Hagino case IPPROTO_IPV6: 313686cdd19SJun-ichiro itojun Hagino break; 314686cdd19SJun-ichiro itojun Hagino #endif 31573ff045cSAndrew Thompson case IPPROTO_ETHERIP: 31673ff045cSAndrew Thompson break; 31773ff045cSAndrew Thompson 318686cdd19SJun-ichiro itojun Hagino default: 319686cdd19SJun-ichiro itojun Hagino return 0; 320686cdd19SJun-ichiro itojun Hagino } 321686cdd19SJun-ichiro itojun Hagino 3223bb61ca6SHajimu UMEMOTO /* Bail on short packets */ 3233bb61ca6SHajimu UMEMOTO if (m->m_pkthdr.len < sizeof(ip)) 3243bb61ca6SHajimu UMEMOTO return 0; 3253bb61ca6SHajimu UMEMOTO 3266f4ded3aSBrooks Davis m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 327686cdd19SJun-ichiro itojun Hagino 328686cdd19SJun-ichiro itojun Hagino switch (ip.ip_v) { 329686cdd19SJun-ichiro itojun Hagino #ifdef INET 330686cdd19SJun-ichiro itojun Hagino case 4: 331686cdd19SJun-ichiro itojun Hagino if (sc->gif_psrc->sa_family != AF_INET || 332686cdd19SJun-ichiro itojun Hagino sc->gif_pdst->sa_family != AF_INET) 333686cdd19SJun-ichiro itojun Hagino return 0; 334686cdd19SJun-ichiro itojun Hagino return gif_encapcheck4(m, off, proto, arg); 335686cdd19SJun-ichiro itojun Hagino #endif 336686cdd19SJun-ichiro itojun Hagino #ifdef INET6 337686cdd19SJun-ichiro itojun Hagino case 6: 3389426aedfSHajimu UMEMOTO if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 3399426aedfSHajimu UMEMOTO return 0; 340686cdd19SJun-ichiro itojun Hagino if (sc->gif_psrc->sa_family != AF_INET6 || 341686cdd19SJun-ichiro itojun Hagino sc->gif_pdst->sa_family != AF_INET6) 342686cdd19SJun-ichiro itojun Hagino return 0; 343686cdd19SJun-ichiro itojun Hagino return gif_encapcheck6(m, off, proto, arg); 344686cdd19SJun-ichiro itojun Hagino #endif 345686cdd19SJun-ichiro itojun Hagino default: 346686cdd19SJun-ichiro itojun Hagino return 0; 347686cdd19SJun-ichiro itojun Hagino } 348686cdd19SJun-ichiro itojun Hagino } 349776b7288SRandall Stewart #ifdef INET 350776b7288SRandall Stewart #define GIF_HDR_LEN (ETHER_HDR_LEN + sizeof (struct ip)) 351776b7288SRandall Stewart #endif 352776b7288SRandall Stewart #ifdef INET6 353776b7288SRandall Stewart #define GIF_HDR_LEN6 (ETHER_HDR_LEN + sizeof (struct ip6_hdr)) 354776b7288SRandall Stewart #endif 355686cdd19SJun-ichiro itojun Hagino 35673ff045cSAndrew Thompson static void 35773ff045cSAndrew Thompson gif_start(struct ifnet *ifp) 35873ff045cSAndrew Thompson { 35973ff045cSAndrew Thompson struct gif_softc *sc; 36073ff045cSAndrew Thompson struct mbuf *m; 361776b7288SRandall Stewart uint32_t af; 362776b7288SRandall Stewart int error = 0; 36373ff045cSAndrew Thompson 36473ff045cSAndrew Thompson sc = ifp->if_softc; 365776b7288SRandall Stewart GIF_LOCK(sc); 36673ff045cSAndrew Thompson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 367776b7288SRandall Stewart while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 368776b7288SRandall Stewart 369776b7288SRandall Stewart IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 37073ff045cSAndrew Thompson if (m == 0) 37173ff045cSAndrew Thompson break; 37273ff045cSAndrew Thompson 373776b7288SRandall Stewart #ifdef ALTQ 374776b7288SRandall Stewart /* Take out those altq bytes we add in gif_output */ 375776b7288SRandall Stewart #ifdef INET 376776b7288SRandall Stewart if (sc->gif_psrc->sa_family == AF_INET) 377776b7288SRandall Stewart m->m_pkthdr.len -= GIF_HDR_LEN; 378776b7288SRandall Stewart #endif 379776b7288SRandall Stewart #ifdef INET6 380776b7288SRandall Stewart if (sc->gif_psrc->sa_family == AF_INET6) 381776b7288SRandall Stewart m->m_pkthdr.len -= GIF_HDR_LEN6; 382776b7288SRandall Stewart #endif 383776b7288SRandall Stewart #endif 38440138788SRandall Stewart /* 38540138788SRandall Stewart * Now pull back the af that we 38640138788SRandall Stewart * stashed in the csum_data. 387776b7288SRandall Stewart */ 388cef68c63SRandall Stewart af = m->m_pkthdr.csum_data; 389cef68c63SRandall Stewart 390a7f5886eSHiroki Sato /* override to IPPROTO_ETHERIP for bridged traffic */ 391776b7288SRandall Stewart if (ifp->if_bridge) 392776b7288SRandall Stewart af = AF_LINK; 393776b7288SRandall Stewart 394776b7288SRandall Stewart BPF_MTAP2(ifp, &af, sizeof(af), m); 3953751dddbSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 396776b7288SRandall Stewart 397776b7288SRandall Stewart /* Done by IFQ_HANDOFF */ 3983751dddbSGleb Smirnoff /* if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);*/ 399776b7288SRandall Stewart 400776b7288SRandall Stewart M_SETFIB(m, sc->gif_fibnum); 401776b7288SRandall Stewart /* inner AF-specific encapsulation */ 402776b7288SRandall Stewart /* XXX should we check if our outer source is legal? */ 403776b7288SRandall Stewart /* dispatch to output logic based on outer AF */ 404776b7288SRandall Stewart switch (sc->gif_psrc->sa_family) { 405776b7288SRandall Stewart #ifdef INET 406776b7288SRandall Stewart case AF_INET: 407776b7288SRandall Stewart error = in_gif_output(ifp, af, m); 408776b7288SRandall Stewart break; 409776b7288SRandall Stewart #endif 410776b7288SRandall Stewart #ifdef INET6 411776b7288SRandall Stewart case AF_INET6: 412776b7288SRandall Stewart error = in6_gif_output(ifp, af, m); 413776b7288SRandall Stewart break; 414776b7288SRandall Stewart #endif 415776b7288SRandall Stewart default: 416776b7288SRandall Stewart m_freem(m); 417776b7288SRandall Stewart error = ENETDOWN; 418776b7288SRandall Stewart } 419776b7288SRandall Stewart if (error) 4203751dddbSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 42173ff045cSAndrew Thompson 42273ff045cSAndrew Thompson } 42373ff045cSAndrew Thompson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 424776b7288SRandall Stewart GIF_UNLOCK(sc); 42573ff045cSAndrew Thompson return; 42673ff045cSAndrew Thompson } 42773ff045cSAndrew Thompson 428cfa1ca9dSYoshinobu Inoue int 42947e8d432SGleb Smirnoff gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 43047e8d432SGleb Smirnoff struct route *ro) 431cfa1ca9dSYoshinobu Inoue { 432fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 4338c7e1947SRuslan Ermilov struct m_tag *mtag; 434cfa1ca9dSYoshinobu Inoue int error = 0; 4358c7e1947SRuslan Ermilov int gif_called; 436776b7288SRandall Stewart uint32_t af; 43710722b85SRobert Watson #ifdef MAC 43830d239bcSRobert Watson error = mac_ifnet_check_transmit(ifp, m); 439e0852ce2SRobert Watson if (error) { 440e0852ce2SRobert Watson m_freem(m); 441e0852ce2SRobert Watson goto end; 442e0852ce2SRobert Watson } 44310722b85SRobert Watson #endif 444e9f947e2SHiroki Sato if ((ifp->if_flags & IFF_MONITOR) != 0) { 445e9f947e2SHiroki Sato error = ENETDOWN; 446e9f947e2SHiroki Sato m_freem(m); 447e9f947e2SHiroki Sato goto end; 448e9f947e2SHiroki Sato } 44910722b85SRobert Watson 450cfa1ca9dSYoshinobu Inoue /* 451cfa1ca9dSYoshinobu Inoue * gif may cause infinite recursion calls when misconfigured. 4528c7e1947SRuslan Ermilov * We'll prevent this by detecting loops. 4538c7e1947SRuslan Ermilov * 4548c7e1947SRuslan Ermilov * High nesting level may cause stack exhaustion. 455cfa1ca9dSYoshinobu Inoue * We'll prevent this by introducing upper limit. 456cfa1ca9dSYoshinobu Inoue */ 4578c7e1947SRuslan Ermilov gif_called = 1; 4588c7e1947SRuslan Ermilov mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, NULL); 4598c7e1947SRuslan Ermilov while (mtag != NULL) { 4608c7e1947SRuslan Ermilov if (*(struct ifnet **)(mtag + 1) == ifp) { 4618c7e1947SRuslan Ermilov log(LOG_NOTICE, 4628c7e1947SRuslan Ermilov "gif_output: loop detected on %s\n", 4638c7e1947SRuslan Ermilov (*(struct ifnet **)(mtag + 1))->if_xname); 4648c7e1947SRuslan Ermilov m_freem(m); 4658c7e1947SRuslan Ermilov error = EIO; /* is there better errno? */ 4668c7e1947SRuslan Ermilov goto end; 4678c7e1947SRuslan Ermilov } 4688c7e1947SRuslan Ermilov mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, mtag); 4698c7e1947SRuslan Ermilov gif_called++; 4708c7e1947SRuslan Ermilov } 471603724d3SBjoern A. Zeeb if (gif_called > V_max_gif_nesting) { 472cfa1ca9dSYoshinobu Inoue log(LOG_NOTICE, 473cfa1ca9dSYoshinobu Inoue "gif_output: recursively called too many times(%d)\n", 474523ebc4eSRobert Watson gif_called); 475cfa1ca9dSYoshinobu Inoue m_freem(m); 476cfa1ca9dSYoshinobu Inoue error = EIO; /* is there better errno? */ 477cfa1ca9dSYoshinobu Inoue goto end; 478cfa1ca9dSYoshinobu Inoue } 4798c7e1947SRuslan Ermilov mtag = m_tag_alloc(MTAG_GIF, MTAG_GIF_CALLED, sizeof(struct ifnet *), 4808c7e1947SRuslan Ermilov M_NOWAIT); 4818c7e1947SRuslan Ermilov if (mtag == NULL) { 4828c7e1947SRuslan Ermilov m_freem(m); 4838c7e1947SRuslan Ermilov error = ENOMEM; 4848c7e1947SRuslan Ermilov goto end; 4858c7e1947SRuslan Ermilov } 4868c7e1947SRuslan Ermilov *(struct ifnet **)(mtag + 1) = ifp; 4878c7e1947SRuslan Ermilov m_tag_prepend(m, mtag); 488686cdd19SJun-ichiro itojun Hagino 489cfa1ca9dSYoshinobu Inoue m->m_flags &= ~(M_BCAST|M_MCAST); 49001399f34SDavid Malone /* BPF writes need to be handled specially. */ 49147e8d432SGleb Smirnoff if (dst->sa_family == AF_UNSPEC) 49201399f34SDavid Malone bcopy(dst->sa_data, &af, sizeof(af)); 49347e8d432SGleb Smirnoff else 49401399f34SDavid Malone af = dst->sa_family; 49540138788SRandall Stewart /* 49640138788SRandall Stewart * Now save the af in the inbound pkt csum 49740138788SRandall Stewart * data, this is a cheat since we are using 49840138788SRandall Stewart * the inbound csum_data field to carry the 49940138788SRandall Stewart * af over to the gif_start() routine, avoiding 50040138788SRandall Stewart * using yet another mtag. 501776b7288SRandall Stewart */ 502cef68c63SRandall Stewart m->m_pkthdr.csum_data = af; 503776b7288SRandall Stewart if (!(ifp->if_flags & IFF_UP) || 504776b7288SRandall Stewart sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 505cfa1ca9dSYoshinobu Inoue m_freem(m); 506cfa1ca9dSYoshinobu Inoue error = ENETDOWN; 507776b7288SRandall Stewart goto end; 508cfa1ca9dSYoshinobu Inoue } 509776b7288SRandall Stewart #ifdef ALTQ 51040138788SRandall Stewart /* 51140138788SRandall Stewart * Make altq aware of the bytes we will add 512776b7288SRandall Stewart * when we actually send it. 513776b7288SRandall Stewart */ 514776b7288SRandall Stewart #ifdef INET 515776b7288SRandall Stewart if (sc->gif_psrc->sa_family == AF_INET) 516776b7288SRandall Stewart m->m_pkthdr.len += GIF_HDR_LEN; 517776b7288SRandall Stewart #endif 518776b7288SRandall Stewart #ifdef INET6 519776b7288SRandall Stewart if (sc->gif_psrc->sa_family == AF_INET6) 520776b7288SRandall Stewart m->m_pkthdr.len += GIF_HDR_LEN6; 521776b7288SRandall Stewart #endif 522776b7288SRandall Stewart #endif 523776b7288SRandall Stewart /* 524776b7288SRandall Stewart * Queue message on interface, update output statistics if 525776b7288SRandall Stewart * successful, and start output if interface not yet active. 526776b7288SRandall Stewart */ 527776b7288SRandall Stewart IFQ_HANDOFF(ifp, m, error); 528cfa1ca9dSYoshinobu Inoue end: 52933841545SHajimu UMEMOTO if (error) 5303751dddbSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 53125af0bb5SGleb Smirnoff return (error); 532cfa1ca9dSYoshinobu Inoue } 533cfa1ca9dSYoshinobu Inoue 534cfa1ca9dSYoshinobu Inoue void 535c72a5d5dSAndrey V. Elsukov gif_input(struct mbuf *m, int af, struct ifnet *ifp) 536cfa1ca9dSYoshinobu Inoue { 53773ff045cSAndrew Thompson int isr, n; 5384382b068SChristian Brueffer struct gif_softc *sc; 53973ff045cSAndrew Thompson struct etherip_header *eip; 54056abdd33SAndrew Thompson struct ether_header *eh; 54156abdd33SAndrew Thompson struct ifnet *oldifp; 542cfa1ca9dSYoshinobu Inoue 54321fb391fSHajimu UMEMOTO if (ifp == NULL) { 544cfa1ca9dSYoshinobu Inoue /* just in case */ 545cfa1ca9dSYoshinobu Inoue m_freem(m); 546cfa1ca9dSYoshinobu Inoue return; 547cfa1ca9dSYoshinobu Inoue } 5484382b068SChristian Brueffer sc = ifp->if_softc; 54921fb391fSHajimu UMEMOTO m->m_pkthdr.rcvif = ifp; 550*5b7a43f5SAndrey V. Elsukov m_clrprotoflags(m); 551cfa1ca9dSYoshinobu Inoue 55210722b85SRobert Watson #ifdef MAC 55330d239bcSRobert Watson mac_ifnet_create_mbuf(ifp, m); 55410722b85SRobert Watson #endif 55510722b85SRobert Watson 55616d878ccSChristian S.J. Peron if (bpf_peers_present(ifp->if_bpf)) { 55733841545SHajimu UMEMOTO u_int32_t af1 = af; 558437ffe18SSam Leffler bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m); 559cfa1ca9dSYoshinobu Inoue } 560cfa1ca9dSYoshinobu Inoue 561e9f947e2SHiroki Sato if ((ifp->if_flags & IFF_MONITOR) != 0) { 5623751dddbSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 5633751dddbSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 564e9f947e2SHiroki Sato m_freem(m); 565e9f947e2SHiroki Sato return; 566e9f947e2SHiroki Sato } 567e9f947e2SHiroki Sato 56894408d94SBrooks Davis if (ng_gif_input_p != NULL) { 56921fb391fSHajimu UMEMOTO (*ng_gif_input_p)(ifp, &m, af); 57094408d94SBrooks Davis if (m == NULL) 57194408d94SBrooks Davis return; 57294408d94SBrooks Davis } 57394408d94SBrooks Davis 574cfa1ca9dSYoshinobu Inoue /* 575cfa1ca9dSYoshinobu Inoue * Put the packet to the network layer input queue according to the 576cfa1ca9dSYoshinobu Inoue * specified address family. 577cfa1ca9dSYoshinobu Inoue * Note: older versions of gif_input directly called network layer 578cfa1ca9dSYoshinobu Inoue * input functions, e.g. ip6_input, here. We changed the policy to 579cfa1ca9dSYoshinobu Inoue * prevent too many recursive calls of such input functions, which 580cfa1ca9dSYoshinobu Inoue * might cause kernel panic. But the change may introduce another 581cfa1ca9dSYoshinobu Inoue * problem; if the input queue is full, packets are discarded. 58288ff5695SSUZUKI Shinsuke * The kernel stack overflow really happened, and we believed 58388ff5695SSUZUKI Shinsuke * queue-full rarely occurs, so we changed the policy. 584cfa1ca9dSYoshinobu Inoue */ 585cfa1ca9dSYoshinobu Inoue switch (af) { 586cfa1ca9dSYoshinobu Inoue #ifdef INET 587cfa1ca9dSYoshinobu Inoue case AF_INET: 588cfa1ca9dSYoshinobu Inoue isr = NETISR_IP; 589cfa1ca9dSYoshinobu Inoue break; 590cfa1ca9dSYoshinobu Inoue #endif 591cfa1ca9dSYoshinobu Inoue #ifdef INET6 592cfa1ca9dSYoshinobu Inoue case AF_INET6: 593cfa1ca9dSYoshinobu Inoue isr = NETISR_IPV6; 594cfa1ca9dSYoshinobu Inoue break; 595cfa1ca9dSYoshinobu Inoue #endif 59673ff045cSAndrew Thompson case AF_LINK: 59773ff045cSAndrew Thompson n = sizeof(struct etherip_header) + sizeof(struct ether_header); 59873ff045cSAndrew Thompson if (n > m->m_len) { 59973ff045cSAndrew Thompson m = m_pullup(m, n); 60073ff045cSAndrew Thompson if (m == NULL) { 6013751dddbSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 60273ff045cSAndrew Thompson return; 60373ff045cSAndrew Thompson } 60473ff045cSAndrew Thompson } 60573ff045cSAndrew Thompson 60673ff045cSAndrew Thompson eip = mtod(m, struct etherip_header *); 607dbe59260SHiroki Sato /* 608dbe59260SHiroki Sato * GIF_ACCEPT_REVETHIP (enabled by default) intentionally 609dbe59260SHiroki Sato * accepts an EtherIP packet with revered version field in 610dbe59260SHiroki Sato * the header. This is a knob for backward compatibility 611dbe59260SHiroki Sato * with FreeBSD 7.2R or prior. 612dbe59260SHiroki Sato */ 613dbe59260SHiroki Sato if (sc->gif_options & GIF_ACCEPT_REVETHIP) { 614dbe59260SHiroki Sato if (eip->eip_resvl != ETHERIP_VERSION 615dbe59260SHiroki Sato && eip->eip_ver != ETHERIP_VERSION) { 61673ff045cSAndrew Thompson /* discard unknown versions */ 61773ff045cSAndrew Thompson m_freem(m); 61873ff045cSAndrew Thompson return; 61973ff045cSAndrew Thompson } 620dbe59260SHiroki Sato } else { 621dbe59260SHiroki Sato if (eip->eip_ver != ETHERIP_VERSION) { 622dbe59260SHiroki Sato /* discard unknown versions */ 623dbe59260SHiroki Sato m_freem(m); 624dbe59260SHiroki Sato return; 625dbe59260SHiroki Sato } 626dbe59260SHiroki Sato } 62773ff045cSAndrew Thompson m_adj(m, sizeof(struct etherip_header)); 62873ff045cSAndrew Thompson 62973ff045cSAndrew Thompson m->m_flags &= ~(M_BCAST|M_MCAST); 63073ff045cSAndrew Thompson m->m_pkthdr.rcvif = ifp; 63173ff045cSAndrew Thompson 63256abdd33SAndrew Thompson if (ifp->if_bridge) { 63356abdd33SAndrew Thompson oldifp = ifp; 63456abdd33SAndrew Thompson eh = mtod(m, struct ether_header *); 63556abdd33SAndrew Thompson if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 63656abdd33SAndrew Thompson if (ETHER_IS_BROADCAST(eh->ether_dhost)) 63756abdd33SAndrew Thompson m->m_flags |= M_BCAST; 63856abdd33SAndrew Thompson else 63956abdd33SAndrew Thompson m->m_flags |= M_MCAST; 6403751dddbSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1); 64156abdd33SAndrew Thompson } 64273ff045cSAndrew Thompson BRIDGE_INPUT(ifp, m); 64373ff045cSAndrew Thompson 64456abdd33SAndrew Thompson if (m != NULL && ifp != oldifp) { 64556abdd33SAndrew Thompson /* 64656abdd33SAndrew Thompson * The bridge gave us back itself or one of the 64756abdd33SAndrew Thompson * members for which the frame is addressed. 64856abdd33SAndrew Thompson */ 64956abdd33SAndrew Thompson ether_demux(ifp, m); 65056abdd33SAndrew Thompson return; 65156abdd33SAndrew Thompson } 65256abdd33SAndrew Thompson } 65373ff045cSAndrew Thompson if (m != NULL) 65473ff045cSAndrew Thompson m_freem(m); 65573ff045cSAndrew Thompson return; 65673ff045cSAndrew Thompson 657cfa1ca9dSYoshinobu Inoue default: 65894408d94SBrooks Davis if (ng_gif_input_orphan_p != NULL) 65921fb391fSHajimu UMEMOTO (*ng_gif_input_orphan_p)(ifp, m, af); 66094408d94SBrooks Davis else 661cfa1ca9dSYoshinobu Inoue m_freem(m); 662cfa1ca9dSYoshinobu Inoue return; 663cfa1ca9dSYoshinobu Inoue } 664cfa1ca9dSYoshinobu Inoue 6653751dddbSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 6663751dddbSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 667a34c6aebSBjoern A. Zeeb M_SETFIB(m, ifp->if_fib); 6681cafed39SJonathan Lemon netisr_dispatch(isr, m); 669cfa1ca9dSYoshinobu Inoue } 670cfa1ca9dSYoshinobu Inoue 671686cdd19SJun-ichiro itojun Hagino /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 672cfa1ca9dSYoshinobu Inoue int 673c72a5d5dSAndrey V. Elsukov gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 674cfa1ca9dSYoshinobu Inoue { 675fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 676cfa1ca9dSYoshinobu Inoue struct ifreq *ifr = (struct ifreq*)data; 677cfa1ca9dSYoshinobu Inoue int error = 0, size; 678dbe59260SHiroki Sato u_int options; 679686cdd19SJun-ichiro itojun Hagino struct sockaddr *dst, *src; 6803bb61ca6SHajimu UMEMOTO #ifdef SIOCSIFMTU /* xxx */ 6813bb61ca6SHajimu UMEMOTO u_long mtu; 6823bb61ca6SHajimu UMEMOTO #endif 683cfa1ca9dSYoshinobu Inoue 684cfa1ca9dSYoshinobu Inoue switch (cmd) { 685cfa1ca9dSYoshinobu Inoue case SIOCSIFADDR: 6869426aedfSHajimu UMEMOTO ifp->if_flags |= IFF_UP; 687cfa1ca9dSYoshinobu Inoue break; 688cfa1ca9dSYoshinobu Inoue 689cfa1ca9dSYoshinobu Inoue case SIOCADDMULTI: 690cfa1ca9dSYoshinobu Inoue case SIOCDELMULTI: 691cfa1ca9dSYoshinobu Inoue break; 692cfa1ca9dSYoshinobu Inoue 693686cdd19SJun-ichiro itojun Hagino #ifdef SIOCSIFMTU /* xxx */ 694cfa1ca9dSYoshinobu Inoue case SIOCGIFMTU: 695cfa1ca9dSYoshinobu Inoue break; 696686cdd19SJun-ichiro itojun Hagino 697cfa1ca9dSYoshinobu Inoue case SIOCSIFMTU: 698cfa1ca9dSYoshinobu Inoue mtu = ifr->ifr_mtu; 6993bb61ca6SHajimu UMEMOTO if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) 700cfa1ca9dSYoshinobu Inoue return (EINVAL); 701cfa1ca9dSYoshinobu Inoue ifp->if_mtu = mtu; 702cfa1ca9dSYoshinobu Inoue break; 703686cdd19SJun-ichiro itojun Hagino #endif /* SIOCSIFMTU */ 704cfa1ca9dSYoshinobu Inoue 7053bb61ca6SHajimu UMEMOTO #ifdef INET 706cfa1ca9dSYoshinobu Inoue case SIOCSIFPHYADDR: 7073bb61ca6SHajimu UMEMOTO #endif 708cfa1ca9dSYoshinobu Inoue #ifdef INET6 709cfa1ca9dSYoshinobu Inoue case SIOCSIFPHYADDR_IN6: 710cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 711686cdd19SJun-ichiro itojun Hagino switch (cmd) { 71233841545SHajimu UMEMOTO #ifdef INET 713686cdd19SJun-ichiro itojun Hagino case SIOCSIFPHYADDR: 714cfa1ca9dSYoshinobu Inoue src = (struct sockaddr *) 715cfa1ca9dSYoshinobu Inoue &(((struct in_aliasreq *)data)->ifra_addr); 716cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 717cfa1ca9dSYoshinobu Inoue &(((struct in_aliasreq *)data)->ifra_dstaddr); 718cfa1ca9dSYoshinobu Inoue break; 71933841545SHajimu UMEMOTO #endif 720cfa1ca9dSYoshinobu Inoue #ifdef INET6 721686cdd19SJun-ichiro itojun Hagino case SIOCSIFPHYADDR_IN6: 722cfa1ca9dSYoshinobu Inoue src = (struct sockaddr *) 723cfa1ca9dSYoshinobu Inoue &(((struct in6_aliasreq *)data)->ifra_addr); 724cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 725cfa1ca9dSYoshinobu Inoue &(((struct in6_aliasreq *)data)->ifra_dstaddr); 726686cdd19SJun-ichiro itojun Hagino break; 727686cdd19SJun-ichiro itojun Hagino #endif 7286f4ded3aSBrooks Davis default: 7299426aedfSHajimu UMEMOTO return EINVAL; 73033841545SHajimu UMEMOTO } 73133841545SHajimu UMEMOTO 73233841545SHajimu UMEMOTO /* sa_family must be equal */ 73333841545SHajimu UMEMOTO if (src->sa_family != dst->sa_family) 73433841545SHajimu UMEMOTO return EINVAL; 73533841545SHajimu UMEMOTO 73633841545SHajimu UMEMOTO /* validate sa_len */ 73733841545SHajimu UMEMOTO switch (src->sa_family) { 73833841545SHajimu UMEMOTO #ifdef INET 73933841545SHajimu UMEMOTO case AF_INET: 74033841545SHajimu UMEMOTO if (src->sa_len != sizeof(struct sockaddr_in)) 74133841545SHajimu UMEMOTO return EINVAL; 74233841545SHajimu UMEMOTO break; 74333841545SHajimu UMEMOTO #endif 74433841545SHajimu UMEMOTO #ifdef INET6 74533841545SHajimu UMEMOTO case AF_INET6: 74633841545SHajimu UMEMOTO if (src->sa_len != sizeof(struct sockaddr_in6)) 74733841545SHajimu UMEMOTO return EINVAL; 74833841545SHajimu UMEMOTO break; 74933841545SHajimu UMEMOTO #endif 75033841545SHajimu UMEMOTO default: 75133841545SHajimu UMEMOTO return EAFNOSUPPORT; 75233841545SHajimu UMEMOTO } 75333841545SHajimu UMEMOTO switch (dst->sa_family) { 75433841545SHajimu UMEMOTO #ifdef INET 75533841545SHajimu UMEMOTO case AF_INET: 75633841545SHajimu UMEMOTO if (dst->sa_len != sizeof(struct sockaddr_in)) 75733841545SHajimu UMEMOTO return EINVAL; 75833841545SHajimu UMEMOTO break; 75933841545SHajimu UMEMOTO #endif 76033841545SHajimu UMEMOTO #ifdef INET6 76133841545SHajimu UMEMOTO case AF_INET6: 76233841545SHajimu UMEMOTO if (dst->sa_len != sizeof(struct sockaddr_in6)) 76333841545SHajimu UMEMOTO return EINVAL; 76433841545SHajimu UMEMOTO break; 76533841545SHajimu UMEMOTO #endif 76633841545SHajimu UMEMOTO default: 76733841545SHajimu UMEMOTO return EAFNOSUPPORT; 76833841545SHajimu UMEMOTO } 76933841545SHajimu UMEMOTO 77033841545SHajimu UMEMOTO /* check sa_family looks sane for the cmd */ 77133841545SHajimu UMEMOTO switch (cmd) { 77233841545SHajimu UMEMOTO case SIOCSIFPHYADDR: 77333841545SHajimu UMEMOTO if (src->sa_family == AF_INET) 77433841545SHajimu UMEMOTO break; 77533841545SHajimu UMEMOTO return EAFNOSUPPORT; 77633841545SHajimu UMEMOTO #ifdef INET6 77733841545SHajimu UMEMOTO case SIOCSIFPHYADDR_IN6: 77833841545SHajimu UMEMOTO if (src->sa_family == AF_INET6) 77933841545SHajimu UMEMOTO break; 78033841545SHajimu UMEMOTO return EAFNOSUPPORT; 78133841545SHajimu UMEMOTO #endif /* INET6 */ 782686cdd19SJun-ichiro itojun Hagino } 783cfa1ca9dSYoshinobu Inoue 784fc74a9f9SBrooks Davis error = gif_set_tunnel(GIF2IFP(sc), src, dst); 785cfa1ca9dSYoshinobu Inoue break; 786cfa1ca9dSYoshinobu Inoue 787686cdd19SJun-ichiro itojun Hagino #ifdef SIOCDIFPHYADDR 788686cdd19SJun-ichiro itojun Hagino case SIOCDIFPHYADDR: 789fc74a9f9SBrooks Davis gif_delete_tunnel(GIF2IFP(sc)); 790686cdd19SJun-ichiro itojun Hagino break; 791686cdd19SJun-ichiro itojun Hagino #endif 792686cdd19SJun-ichiro itojun Hagino 793cfa1ca9dSYoshinobu Inoue case SIOCGIFPSRCADDR: 794cfa1ca9dSYoshinobu Inoue #ifdef INET6 795cfa1ca9dSYoshinobu Inoue case SIOCGIFPSRCADDR_IN6: 796cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 797cfa1ca9dSYoshinobu Inoue if (sc->gif_psrc == NULL) { 798cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 799cfa1ca9dSYoshinobu Inoue goto bad; 800cfa1ca9dSYoshinobu Inoue } 801cfa1ca9dSYoshinobu Inoue src = sc->gif_psrc; 80233841545SHajimu UMEMOTO switch (cmd) { 803cfa1ca9dSYoshinobu Inoue #ifdef INET 80433841545SHajimu UMEMOTO case SIOCGIFPSRCADDR: 805cfa1ca9dSYoshinobu Inoue dst = &ifr->ifr_addr; 80633841545SHajimu UMEMOTO size = sizeof(ifr->ifr_addr); 807cfa1ca9dSYoshinobu Inoue break; 808cfa1ca9dSYoshinobu Inoue #endif /* INET */ 809cfa1ca9dSYoshinobu Inoue #ifdef INET6 81033841545SHajimu UMEMOTO case SIOCGIFPSRCADDR_IN6: 811cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 812cfa1ca9dSYoshinobu Inoue &(((struct in6_ifreq *)data)->ifr_addr); 81333841545SHajimu UMEMOTO size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 814cfa1ca9dSYoshinobu Inoue break; 815cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 816cfa1ca9dSYoshinobu Inoue default: 817cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 818cfa1ca9dSYoshinobu Inoue goto bad; 819cfa1ca9dSYoshinobu Inoue } 82033841545SHajimu UMEMOTO if (src->sa_len > size) 82133841545SHajimu UMEMOTO return EINVAL; 82233841545SHajimu UMEMOTO bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 823a1f7e5f8SHajimu UMEMOTO #ifdef INET6 824a1f7e5f8SHajimu UMEMOTO if (dst->sa_family == AF_INET6) { 825a1f7e5f8SHajimu UMEMOTO error = sa6_recoverscope((struct sockaddr_in6 *)dst); 826a1f7e5f8SHajimu UMEMOTO if (error != 0) 827a1f7e5f8SHajimu UMEMOTO return (error); 828a1f7e5f8SHajimu UMEMOTO } 829a1f7e5f8SHajimu UMEMOTO #endif 830cfa1ca9dSYoshinobu Inoue break; 831cfa1ca9dSYoshinobu Inoue 832cfa1ca9dSYoshinobu Inoue case SIOCGIFPDSTADDR: 833cfa1ca9dSYoshinobu Inoue #ifdef INET6 834cfa1ca9dSYoshinobu Inoue case SIOCGIFPDSTADDR_IN6: 835cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 836cfa1ca9dSYoshinobu Inoue if (sc->gif_pdst == NULL) { 837cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 838cfa1ca9dSYoshinobu Inoue goto bad; 839cfa1ca9dSYoshinobu Inoue } 840cfa1ca9dSYoshinobu Inoue src = sc->gif_pdst; 84133841545SHajimu UMEMOTO switch (cmd) { 842cfa1ca9dSYoshinobu Inoue #ifdef INET 84333841545SHajimu UMEMOTO case SIOCGIFPDSTADDR: 844cfa1ca9dSYoshinobu Inoue dst = &ifr->ifr_addr; 84533841545SHajimu UMEMOTO size = sizeof(ifr->ifr_addr); 846cfa1ca9dSYoshinobu Inoue break; 847cfa1ca9dSYoshinobu Inoue #endif /* INET */ 848cfa1ca9dSYoshinobu Inoue #ifdef INET6 84933841545SHajimu UMEMOTO case SIOCGIFPDSTADDR_IN6: 850cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 851cfa1ca9dSYoshinobu Inoue &(((struct in6_ifreq *)data)->ifr_addr); 85233841545SHajimu UMEMOTO size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 853cfa1ca9dSYoshinobu Inoue break; 854cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 855cfa1ca9dSYoshinobu Inoue default: 856cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 857cfa1ca9dSYoshinobu Inoue goto bad; 858cfa1ca9dSYoshinobu Inoue } 85933841545SHajimu UMEMOTO if (src->sa_len > size) 86033841545SHajimu UMEMOTO return EINVAL; 861e3416ab0SBjoern A. Zeeb error = prison_if(curthread->td_ucred, src); 862e3416ab0SBjoern A. Zeeb if (error != 0) 863e3416ab0SBjoern A. Zeeb return (error); 864e3416ab0SBjoern A. Zeeb error = prison_if(curthread->td_ucred, dst); 865e3416ab0SBjoern A. Zeeb if (error != 0) 866e3416ab0SBjoern A. Zeeb return (error); 86733841545SHajimu UMEMOTO bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 868a1f7e5f8SHajimu UMEMOTO #ifdef INET6 869a1f7e5f8SHajimu UMEMOTO if (dst->sa_family == AF_INET6) { 870a1f7e5f8SHajimu UMEMOTO error = sa6_recoverscope((struct sockaddr_in6 *)dst); 871a1f7e5f8SHajimu UMEMOTO if (error != 0) 872a1f7e5f8SHajimu UMEMOTO return (error); 873a1f7e5f8SHajimu UMEMOTO } 874a1f7e5f8SHajimu UMEMOTO #endif 87533841545SHajimu UMEMOTO break; 87633841545SHajimu UMEMOTO 877cfa1ca9dSYoshinobu Inoue case SIOCSIFFLAGS: 878686cdd19SJun-ichiro itojun Hagino /* if_ioctl() takes care of it */ 879cfa1ca9dSYoshinobu Inoue break; 880cfa1ca9dSYoshinobu Inoue 881dbe59260SHiroki Sato case GIFGOPTS: 882dbe59260SHiroki Sato options = sc->gif_options; 883dbe59260SHiroki Sato error = copyout(&options, ifr->ifr_data, 884dbe59260SHiroki Sato sizeof(options)); 885dbe59260SHiroki Sato break; 886dbe59260SHiroki Sato 887dbe59260SHiroki Sato case GIFSOPTS: 888dbe59260SHiroki Sato if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0) 889dbe59260SHiroki Sato break; 8904cd5f57dSHiroki Sato error = copyin(ifr->ifr_data, &options, sizeof(options)); 8914cd5f57dSHiroki Sato if (error) 8924cd5f57dSHiroki Sato break; 8934cd5f57dSHiroki Sato if (options & ~GIF_OPTMASK) 894dbe59260SHiroki Sato error = EINVAL; 8954cd5f57dSHiroki Sato else 8964cd5f57dSHiroki Sato sc->gif_options = options; 897dbe59260SHiroki Sato break; 898dbe59260SHiroki Sato 899cfa1ca9dSYoshinobu Inoue default: 900cfa1ca9dSYoshinobu Inoue error = EINVAL; 901cfa1ca9dSYoshinobu Inoue break; 902cfa1ca9dSYoshinobu Inoue } 903cfa1ca9dSYoshinobu Inoue bad: 904cfa1ca9dSYoshinobu Inoue return error; 905cfa1ca9dSYoshinobu Inoue } 90653dab5feSBrooks Davis 90717d5cb2dSRobert Watson /* 90817d5cb2dSRobert Watson * XXXRW: There's a general event-ordering issue here: the code to check 90917d5cb2dSRobert Watson * if a given tunnel is already present happens before we perform a 91017d5cb2dSRobert Watson * potentially blocking setup of the tunnel. This code needs to be 91117d5cb2dSRobert Watson * re-ordered so that the check and replacement can be atomic using 91217d5cb2dSRobert Watson * a mutex. 91317d5cb2dSRobert Watson */ 9149426aedfSHajimu UMEMOTO int 915c72a5d5dSAndrey V. Elsukov gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) 91653dab5feSBrooks Davis { 917fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 9189426aedfSHajimu UMEMOTO struct gif_softc *sc2; 9199426aedfSHajimu UMEMOTO struct sockaddr *osrc, *odst, *sa; 9209426aedfSHajimu UMEMOTO int error = 0; 9219426aedfSHajimu UMEMOTO 922a7f5886eSHiroki Sato GIF_LIST_LOCK(); 923603724d3SBjoern A. Zeeb LIST_FOREACH(sc2, &V_gif_softc_list, gif_list) { 9249426aedfSHajimu UMEMOTO if (sc2 == sc) 9259426aedfSHajimu UMEMOTO continue; 9269426aedfSHajimu UMEMOTO if (!sc2->gif_pdst || !sc2->gif_psrc) 9279426aedfSHajimu UMEMOTO continue; 9289426aedfSHajimu UMEMOTO if (sc2->gif_pdst->sa_family != dst->sa_family || 9299426aedfSHajimu UMEMOTO sc2->gif_pdst->sa_len != dst->sa_len || 9309426aedfSHajimu UMEMOTO sc2->gif_psrc->sa_family != src->sa_family || 9319426aedfSHajimu UMEMOTO sc2->gif_psrc->sa_len != src->sa_len) 9329426aedfSHajimu UMEMOTO continue; 9339426aedfSHajimu UMEMOTO 9349426aedfSHajimu UMEMOTO /* 9359426aedfSHajimu UMEMOTO * Disallow parallel tunnels unless instructed 9369426aedfSHajimu UMEMOTO * otherwise. 9379426aedfSHajimu UMEMOTO */ 938603724d3SBjoern A. Zeeb if (!V_parallel_tunnels && 9399426aedfSHajimu UMEMOTO bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 9409426aedfSHajimu UMEMOTO bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 9419426aedfSHajimu UMEMOTO error = EADDRNOTAVAIL; 942a7f5886eSHiroki Sato GIF_LIST_UNLOCK(); 9439426aedfSHajimu UMEMOTO goto bad; 9449426aedfSHajimu UMEMOTO } 9459426aedfSHajimu UMEMOTO 9469426aedfSHajimu UMEMOTO /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 9479426aedfSHajimu UMEMOTO } 948a7f5886eSHiroki Sato GIF_LIST_UNLOCK(); 9499426aedfSHajimu UMEMOTO 9509426aedfSHajimu UMEMOTO /* XXX we can detach from both, but be polite just in case */ 9519426aedfSHajimu UMEMOTO if (sc->gif_psrc) 9529426aedfSHajimu UMEMOTO switch (sc->gif_psrc->sa_family) { 9539426aedfSHajimu UMEMOTO #ifdef INET 9549426aedfSHajimu UMEMOTO case AF_INET: 9559426aedfSHajimu UMEMOTO (void)in_gif_detach(sc); 9569426aedfSHajimu UMEMOTO break; 9579426aedfSHajimu UMEMOTO #endif 9589426aedfSHajimu UMEMOTO #ifdef INET6 9599426aedfSHajimu UMEMOTO case AF_INET6: 9609426aedfSHajimu UMEMOTO (void)in6_gif_detach(sc); 9619426aedfSHajimu UMEMOTO break; 9629426aedfSHajimu UMEMOTO #endif 9639426aedfSHajimu UMEMOTO } 9649426aedfSHajimu UMEMOTO 9659426aedfSHajimu UMEMOTO osrc = sc->gif_psrc; 966a163d034SWarner Losh sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); 9679426aedfSHajimu UMEMOTO bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 9689426aedfSHajimu UMEMOTO sc->gif_psrc = sa; 9699426aedfSHajimu UMEMOTO 9709426aedfSHajimu UMEMOTO odst = sc->gif_pdst; 971a163d034SWarner Losh sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); 9729426aedfSHajimu UMEMOTO bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 9739426aedfSHajimu UMEMOTO sc->gif_pdst = sa; 9749426aedfSHajimu UMEMOTO 9759426aedfSHajimu UMEMOTO switch (sc->gif_psrc->sa_family) { 9769426aedfSHajimu UMEMOTO #ifdef INET 9779426aedfSHajimu UMEMOTO case AF_INET: 9789426aedfSHajimu UMEMOTO error = in_gif_attach(sc); 9799426aedfSHajimu UMEMOTO break; 9809426aedfSHajimu UMEMOTO #endif 9819426aedfSHajimu UMEMOTO #ifdef INET6 9829426aedfSHajimu UMEMOTO case AF_INET6: 983a1f7e5f8SHajimu UMEMOTO /* 984a1f7e5f8SHajimu UMEMOTO * Check validity of the scope zone ID of the addresses, and 985a1f7e5f8SHajimu UMEMOTO * convert it into the kernel internal form if necessary. 986a1f7e5f8SHajimu UMEMOTO */ 987a1f7e5f8SHajimu UMEMOTO error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_psrc, 0); 988a1f7e5f8SHajimu UMEMOTO if (error != 0) 989a1f7e5f8SHajimu UMEMOTO break; 990a1f7e5f8SHajimu UMEMOTO error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_pdst, 0); 991a1f7e5f8SHajimu UMEMOTO if (error != 0) 992a1f7e5f8SHajimu UMEMOTO break; 9939426aedfSHajimu UMEMOTO error = in6_gif_attach(sc); 9949426aedfSHajimu UMEMOTO break; 9959426aedfSHajimu UMEMOTO #endif 9969426aedfSHajimu UMEMOTO } 9979426aedfSHajimu UMEMOTO if (error) { 9989426aedfSHajimu UMEMOTO /* rollback */ 9999426aedfSHajimu UMEMOTO free((caddr_t)sc->gif_psrc, M_IFADDR); 10009426aedfSHajimu UMEMOTO free((caddr_t)sc->gif_pdst, M_IFADDR); 10019426aedfSHajimu UMEMOTO sc->gif_psrc = osrc; 10029426aedfSHajimu UMEMOTO sc->gif_pdst = odst; 10039426aedfSHajimu UMEMOTO goto bad; 10049426aedfSHajimu UMEMOTO } 10059426aedfSHajimu UMEMOTO 10069426aedfSHajimu UMEMOTO if (osrc) 10079426aedfSHajimu UMEMOTO free((caddr_t)osrc, M_IFADDR); 10089426aedfSHajimu UMEMOTO if (odst) 10099426aedfSHajimu UMEMOTO free((caddr_t)odst, M_IFADDR); 10109426aedfSHajimu UMEMOTO 10119426aedfSHajimu UMEMOTO bad: 10129426aedfSHajimu UMEMOTO if (sc->gif_psrc && sc->gif_pdst) 101313f4c340SRobert Watson ifp->if_drv_flags |= IFF_DRV_RUNNING; 10149426aedfSHajimu UMEMOTO else 101513f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 10169426aedfSHajimu UMEMOTO 10179426aedfSHajimu UMEMOTO return error; 10189426aedfSHajimu UMEMOTO } 10199426aedfSHajimu UMEMOTO 10209426aedfSHajimu UMEMOTO void 1021c72a5d5dSAndrey V. Elsukov gif_delete_tunnel(struct ifnet *ifp) 10229426aedfSHajimu UMEMOTO { 1023fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 102453dab5feSBrooks Davis 102553dab5feSBrooks Davis if (sc->gif_psrc) { 102653dab5feSBrooks Davis free((caddr_t)sc->gif_psrc, M_IFADDR); 102753dab5feSBrooks Davis sc->gif_psrc = NULL; 102853dab5feSBrooks Davis } 102953dab5feSBrooks Davis if (sc->gif_pdst) { 103053dab5feSBrooks Davis free((caddr_t)sc->gif_pdst, M_IFADDR); 103153dab5feSBrooks Davis sc->gif_pdst = NULL; 103253dab5feSBrooks Davis } 10339426aedfSHajimu UMEMOTO /* it is safe to detach from both */ 10349426aedfSHajimu UMEMOTO #ifdef INET 10359426aedfSHajimu UMEMOTO (void)in_gif_detach(sc); 10369426aedfSHajimu UMEMOTO #endif 10379426aedfSHajimu UMEMOTO #ifdef INET6 10389426aedfSHajimu UMEMOTO (void)in6_gif_detach(sc); 10399426aedfSHajimu UMEMOTO #endif 104013f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 104153dab5feSBrooks Davis } 1042