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> 38cfa1ca9dSYoshinobu Inoue #include <sys/kernel.h> 39cfa1ca9dSYoshinobu Inoue #include <sys/malloc.h> 40cfa1ca9dSYoshinobu Inoue #include <sys/mbuf.h> 415dba30f1SPoul-Henning Kamp #include <sys/module.h> 42cfa1ca9dSYoshinobu Inoue #include <sys/socket.h> 43cfa1ca9dSYoshinobu Inoue #include <sys/sockio.h> 44cfa1ca9dSYoshinobu Inoue #include <sys/errno.h> 45cfa1ca9dSYoshinobu Inoue #include <sys/time.h> 46872f786aSBrooks Davis #include <sys/sysctl.h> 47cfa1ca9dSYoshinobu Inoue #include <sys/syslog.h> 48dbe59260SHiroki Sato #include <sys/priv.h> 498b07e49aSJulian Elischer #include <sys/proc.h> 50686cdd19SJun-ichiro itojun Hagino #include <sys/protosw.h> 5153dab5feSBrooks Davis #include <sys/conf.h> 52603724d3SBjoern A. Zeeb #include <sys/vimage.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> 61cfa1ca9dSYoshinobu Inoue 62cfa1ca9dSYoshinobu Inoue #include <netinet/in.h> 63cfa1ca9dSYoshinobu Inoue #include <netinet/in_systm.h> 64cfa1ca9dSYoshinobu Inoue #include <netinet/ip.h> 6533841545SHajimu UMEMOTO #ifdef INET 6633841545SHajimu UMEMOTO #include <netinet/in_var.h> 67cfa1ca9dSYoshinobu Inoue #include <netinet/in_gif.h> 6853dab5feSBrooks Davis #include <netinet/ip_var.h> 69cfa1ca9dSYoshinobu Inoue #endif /* INET */ 70cfa1ca9dSYoshinobu Inoue 71cfa1ca9dSYoshinobu Inoue #ifdef INET6 72cfa1ca9dSYoshinobu Inoue #ifndef INET 73cfa1ca9dSYoshinobu Inoue #include <netinet/in.h> 74cfa1ca9dSYoshinobu Inoue #endif 75cfa1ca9dSYoshinobu Inoue #include <netinet6/in6_var.h> 76cfa1ca9dSYoshinobu Inoue #include <netinet/ip6.h> 77cfa1ca9dSYoshinobu Inoue #include <netinet6/ip6_var.h> 78a1f7e5f8SHajimu UMEMOTO #include <netinet6/scope6_var.h> 79cfa1ca9dSYoshinobu Inoue #include <netinet6/in6_gif.h> 80686cdd19SJun-ichiro itojun Hagino #include <netinet6/ip6protosw.h> 81cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 82cfa1ca9dSYoshinobu Inoue 83686cdd19SJun-ichiro itojun Hagino #include <netinet/ip_encap.h> 8473ff045cSAndrew Thompson #include <net/ethernet.h> 8573ff045cSAndrew Thompson #include <net/if_bridgevar.h> 86cfa1ca9dSYoshinobu Inoue #include <net/if_gif.h> 87cfa1ca9dSYoshinobu Inoue 88aed55708SRobert Watson #include <security/mac/mac_framework.h> 89aed55708SRobert Watson 9053dab5feSBrooks Davis #define GIFNAME "gif" 91686cdd19SJun-ichiro itojun Hagino 9217d5cb2dSRobert Watson /* 938c7e1947SRuslan Ermilov * gif_mtx protects the global gif_softc_list. 9417d5cb2dSRobert Watson */ 9517d5cb2dSRobert Watson static struct mtx gif_mtx; 9653dab5feSBrooks Davis static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); 9744e33a07SMarko Zec 98eddfbb76SRobert Watson static VNET_DEFINE(LIST_HEAD(, gif_softc), gif_softc_list); 99385195c0SMarko Zec 1001e77c105SRobert Watson #define V_gif_softc_list VNET(gif_softc_list) 101eddfbb76SRobert Watson 10244e33a07SMarko Zec #ifdef INET 103d0728d71SRobert Watson VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL; 1041e77c105SRobert Watson #define V_ip_gif_ttl VNET(ip_gif_ttl) 10544e33a07SMarko Zec #endif 10644e33a07SMarko Zec #ifdef INET6 107d0728d71SRobert Watson VNET_DEFINE(int, ip6_gif_hlim) = GIF_HLIM; 1081e77c105SRobert Watson #define V_ip6_gif_hlim VNET(ip6_gif_hlim) 10944e33a07SMarko Zec #endif 11053dab5feSBrooks Davis 11194408d94SBrooks Davis void (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); 11294408d94SBrooks Davis void (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); 11394408d94SBrooks Davis void (*ng_gif_attach_p)(struct ifnet *ifp); 11494408d94SBrooks Davis void (*ng_gif_detach_p)(struct ifnet *ifp); 11594408d94SBrooks Davis 11673ff045cSAndrew Thompson static void gif_start(struct ifnet *); 1176b7330e2SSam Leffler static int gif_clone_create(struct if_clone *, int, caddr_t); 118bb2bfb4fSBrooks Davis static void gif_clone_destroy(struct ifnet *); 119bfe1aba4SMarko Zec 120f889d2efSBrooks Davis IFC_SIMPLE_DECLARE(gif, 0); 12153dab5feSBrooks Davis 122929ddbbbSAlfred Perlstein static int gifmodevent(module_t, int, void *); 123cfa1ca9dSYoshinobu Inoue 124872f786aSBrooks Davis SYSCTL_DECL(_net_link); 125872f786aSBrooks Davis SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0, 126872f786aSBrooks Davis "Generic Tunnel Interface"); 127686cdd19SJun-ichiro itojun Hagino #ifndef MAX_GIF_NEST 128686cdd19SJun-ichiro itojun Hagino /* 129872f786aSBrooks Davis * This macro controls the default upper limitation on nesting of gif tunnels. 130686cdd19SJun-ichiro itojun Hagino * Since, setting a large value to this macro with a careless configuration 131686cdd19SJun-ichiro itojun Hagino * may introduce system crash, we don't allow any nestings by default. 132686cdd19SJun-ichiro itojun Hagino * If you need to configure nested gif tunnels, you can define this macro 133686cdd19SJun-ichiro itojun Hagino * in your kernel configuration file. However, if you do so, please be 134686cdd19SJun-ichiro itojun Hagino * careful to configure the tunnels so that it won't make a loop. 135686cdd19SJun-ichiro itojun Hagino */ 136686cdd19SJun-ichiro itojun Hagino #define MAX_GIF_NEST 1 137686cdd19SJun-ichiro itojun Hagino #endif 138d0728d71SRobert Watson 139d0728d71SRobert Watson static VNET_DEFINE(int, max_gif_nesting) = MAX_GIF_NEST; 140d0728d71SRobert Watson #define V_max_gif_nesting VNET(max_gif_nesting) 141d0728d71SRobert Watson 142eddfbb76SRobert Watson SYSCTL_VNET_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW, 143eddfbb76SRobert Watson &VNET_NAME(max_gif_nesting), 0, "Max nested tunnels"); 1448b615593SMarko Zec 1458b615593SMarko Zec #ifdef INET6 1468b615593SMarko Zec SYSCTL_DECL(_net_inet6_ip6); 147eddfbb76SRobert Watson SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM, gifhlim, CTLFLAG_RW, 148eddfbb76SRobert Watson &VNET_NAME(ip6_gif_hlim), 0, ""); 1498b615593SMarko Zec #endif 150872f786aSBrooks Davis 151872f786aSBrooks Davis /* 152872f786aSBrooks Davis * By default, we disallow creation of multiple tunnels between the same 153872f786aSBrooks Davis * pair of addresses. Some applications require this functionality so 154872f786aSBrooks Davis * we allow control over this check here. 155872f786aSBrooks Davis */ 156d0728d71SRobert Watson #ifdef XBONEHACK 157d0728d71SRobert Watson static VNET_DEFINE(int, parallel_tunnels) = 1; 158d0728d71SRobert Watson #else 159d0728d71SRobert Watson static VNET_DEFINE(int, parallel_tunnels) = 0; 160d0728d71SRobert Watson #endif 161d0728d71SRobert Watson #define V_parallel_tunnels VNET(parallel_tunnels) 162d0728d71SRobert Watson 163eddfbb76SRobert Watson SYSCTL_VNET_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW, 164eddfbb76SRobert Watson &VNET_NAME(parallel_tunnels), 0, "Allow parallel tunnels?"); 165cfa1ca9dSYoshinobu Inoue 16656abdd33SAndrew Thompson /* copy from src/sys/net/if_ethersubr.c */ 16756abdd33SAndrew Thompson static const u_char etherbroadcastaddr[ETHER_ADDR_LEN] = 16856abdd33SAndrew Thompson { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 16956abdd33SAndrew Thompson #ifndef ETHER_IS_BROADCAST 17056abdd33SAndrew Thompson #define ETHER_IS_BROADCAST(addr) \ 17156abdd33SAndrew Thompson (bcmp(etherbroadcastaddr, (addr), ETHER_ADDR_LEN) == 0) 17256abdd33SAndrew Thompson #endif 17356abdd33SAndrew Thompson 174bb2bfb4fSBrooks Davis static int 1756b7330e2SSam Leffler gif_clone_create(ifc, unit, params) 17653dab5feSBrooks Davis struct if_clone *ifc; 1773b16e7b2SMaxime Henrion int unit; 1786b7330e2SSam Leffler caddr_t params; 179cfa1ca9dSYoshinobu Inoue { 18033841545SHajimu UMEMOTO struct gif_softc *sc; 181cfa1ca9dSYoshinobu Inoue 182e1a8c3dcSBruce M Simpson sc = malloc(sizeof(struct gif_softc), M_GIF, M_WAITOK | M_ZERO); 1838b07e49aSJulian Elischer sc->gif_fibnum = curthread->td_proc->p_fibnum; 184fc74a9f9SBrooks Davis GIF2IFP(sc) = if_alloc(IFT_GIF); 185fc74a9f9SBrooks Davis if (GIF2IFP(sc) == NULL) { 186fc74a9f9SBrooks Davis free(sc, M_GIF); 187fc74a9f9SBrooks Davis return (ENOSPC); 188fc74a9f9SBrooks Davis } 18953dab5feSBrooks Davis 19025af0bb5SGleb Smirnoff GIF_LOCK_INIT(sc); 19125af0bb5SGleb Smirnoff 192fc74a9f9SBrooks Davis GIF2IFP(sc)->if_softc = sc; 193fc74a9f9SBrooks Davis if_initname(GIF2IFP(sc), ifc->ifc_name, unit); 194686cdd19SJun-ichiro itojun Hagino 1959426aedfSHajimu UMEMOTO sc->encap_cookie4 = sc->encap_cookie6 = NULL; 196dbe59260SHiroki Sato sc->gif_options = GIF_ACCEPT_REVETHIP; 1979426aedfSHajimu UMEMOTO 198fc74a9f9SBrooks Davis GIF2IFP(sc)->if_addrlen = 0; 199fc74a9f9SBrooks Davis GIF2IFP(sc)->if_mtu = GIF_MTU; 200fc74a9f9SBrooks Davis GIF2IFP(sc)->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 20133841545SHajimu UMEMOTO #if 0 20233841545SHajimu UMEMOTO /* turn off ingress filter */ 203fc74a9f9SBrooks Davis GIF2IFP(sc)->if_flags |= IFF_LINK2; 20433841545SHajimu UMEMOTO #endif 205fc74a9f9SBrooks Davis GIF2IFP(sc)->if_ioctl = gif_ioctl; 20673ff045cSAndrew Thompson GIF2IFP(sc)->if_start = gif_start; 207fc74a9f9SBrooks Davis GIF2IFP(sc)->if_output = gif_output; 208fc74a9f9SBrooks Davis GIF2IFP(sc)->if_snd.ifq_maxlen = IFQ_MAXLEN; 209fc74a9f9SBrooks Davis if_attach(GIF2IFP(sc)); 21001399f34SDavid Malone bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int32_t)); 21194408d94SBrooks Davis if (ng_gif_attach_p != NULL) 212fc74a9f9SBrooks Davis (*ng_gif_attach_p)(GIF2IFP(sc)); 21325af0bb5SGleb Smirnoff 21425af0bb5SGleb Smirnoff mtx_lock(&gif_mtx); 215603724d3SBjoern A. Zeeb LIST_INSERT_HEAD(&V_gif_softc_list, sc, gif_list); 21625af0bb5SGleb Smirnoff mtx_unlock(&gif_mtx); 21725af0bb5SGleb Smirnoff 21825af0bb5SGleb Smirnoff return (0); 219cfa1ca9dSYoshinobu Inoue } 220cfa1ca9dSYoshinobu Inoue 22117d5cb2dSRobert Watson static void 222febd0759SAndrew Thompson gif_clone_destroy(ifp) 223febd0759SAndrew Thompson struct ifnet *ifp; 22453dab5feSBrooks Davis { 225e0de57f9SBjoern A. Zeeb #if defined(INET) || defined(INET6) 22653dab5feSBrooks Davis int err; 227e0de57f9SBjoern A. Zeeb #endif 228febd0759SAndrew Thompson struct gif_softc *sc = ifp->if_softc; 229febd0759SAndrew Thompson 230febd0759SAndrew Thompson mtx_lock(&gif_mtx); 231febd0759SAndrew Thompson LIST_REMOVE(sc, gif_list); 232febd0759SAndrew Thompson mtx_unlock(&gif_mtx); 23353dab5feSBrooks Davis 23417d5cb2dSRobert Watson gif_delete_tunnel(ifp); 2359426aedfSHajimu UMEMOTO #ifdef INET6 23653dab5feSBrooks Davis if (sc->encap_cookie6 != NULL) { 23753dab5feSBrooks Davis err = encap_detach(sc->encap_cookie6); 23853dab5feSBrooks Davis KASSERT(err == 0, ("Unexpected error detaching encap_cookie6")); 23953dab5feSBrooks Davis } 2409426aedfSHajimu UMEMOTO #endif 2419426aedfSHajimu UMEMOTO #ifdef INET 2429426aedfSHajimu UMEMOTO if (sc->encap_cookie4 != NULL) { 2439426aedfSHajimu UMEMOTO err = encap_detach(sc->encap_cookie4); 2449426aedfSHajimu UMEMOTO KASSERT(err == 0, ("Unexpected error detaching encap_cookie4")); 2459426aedfSHajimu UMEMOTO } 2469426aedfSHajimu UMEMOTO #endif 24753dab5feSBrooks Davis 24894408d94SBrooks Davis if (ng_gif_detach_p != NULL) 24994408d94SBrooks Davis (*ng_gif_detach_p)(ifp); 25053dab5feSBrooks Davis bpfdetach(ifp); 25153dab5feSBrooks Davis if_detach(ifp); 252fc74a9f9SBrooks Davis if_free(ifp); 25353dab5feSBrooks Davis 25425af0bb5SGleb Smirnoff GIF_LOCK_DESTROY(sc); 25525af0bb5SGleb Smirnoff 25653dab5feSBrooks Davis free(sc, M_GIF); 25753dab5feSBrooks Davis } 25853dab5feSBrooks Davis 259d0728d71SRobert Watson static void 260d0728d71SRobert Watson vnet_gif_init(const void *unused __unused) 2611ed81b73SMarko Zec { 2621ed81b73SMarko Zec 2631ed81b73SMarko Zec LIST_INIT(&V_gif_softc_list); 2641ed81b73SMarko Zec } 265d0728d71SRobert Watson VNET_SYSINIT(vnet_gif_init, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, vnet_gif_init, 266d0728d71SRobert Watson NULL); 2671ed81b73SMarko Zec 2681ed81b73SMarko Zec static int 26953dab5feSBrooks Davis gifmodevent(mod, type, data) 27053dab5feSBrooks Davis module_t mod; 27153dab5feSBrooks Davis int type; 27253dab5feSBrooks Davis void *data; 27353dab5feSBrooks Davis { 27453dab5feSBrooks Davis 27553dab5feSBrooks Davis switch (type) { 27653dab5feSBrooks Davis case MOD_LOAD: 27717d5cb2dSRobert Watson mtx_init(&gif_mtx, "gif_mtx", NULL, MTX_DEF); 27844e33a07SMarko Zec if_clone_attach(&gif_cloner); 27953dab5feSBrooks Davis break; 280d0728d71SRobert Watson 28153dab5feSBrooks Davis case MOD_UNLOAD: 28253dab5feSBrooks Davis if_clone_detach(&gif_cloner); 28317d5cb2dSRobert Watson mtx_destroy(&gif_mtx); 28453dab5feSBrooks Davis break; 2853e019deaSPoul-Henning Kamp default: 2863e019deaSPoul-Henning Kamp return EOPNOTSUPP; 28753dab5feSBrooks Davis } 28853dab5feSBrooks Davis return 0; 28953dab5feSBrooks Davis } 29053dab5feSBrooks Davis 29153dab5feSBrooks Davis static moduledata_t gif_mod = { 29253dab5feSBrooks Davis "if_gif", 29353dab5feSBrooks Davis gifmodevent, 29453dab5feSBrooks Davis 0 29553dab5feSBrooks Davis }; 29653dab5feSBrooks Davis 29753dab5feSBrooks Davis DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 29820af0ffaSBrooks Davis MODULE_VERSION(if_gif, 1); 299cfa1ca9dSYoshinobu Inoue 3009426aedfSHajimu UMEMOTO int 301686cdd19SJun-ichiro itojun Hagino gif_encapcheck(m, off, proto, arg) 302686cdd19SJun-ichiro itojun Hagino const struct mbuf *m; 303686cdd19SJun-ichiro itojun Hagino int off; 304686cdd19SJun-ichiro itojun Hagino int proto; 305686cdd19SJun-ichiro itojun Hagino void *arg; 306686cdd19SJun-ichiro itojun Hagino { 307686cdd19SJun-ichiro itojun Hagino struct ip ip; 308686cdd19SJun-ichiro itojun Hagino struct gif_softc *sc; 309686cdd19SJun-ichiro itojun Hagino 310686cdd19SJun-ichiro itojun Hagino sc = (struct gif_softc *)arg; 311686cdd19SJun-ichiro itojun Hagino if (sc == NULL) 312686cdd19SJun-ichiro itojun Hagino return 0; 313686cdd19SJun-ichiro itojun Hagino 314fc74a9f9SBrooks Davis if ((GIF2IFP(sc)->if_flags & IFF_UP) == 0) 315686cdd19SJun-ichiro itojun Hagino return 0; 316686cdd19SJun-ichiro itojun Hagino 317686cdd19SJun-ichiro itojun Hagino /* no physical address */ 318686cdd19SJun-ichiro itojun Hagino if (!sc->gif_psrc || !sc->gif_pdst) 319686cdd19SJun-ichiro itojun Hagino return 0; 320686cdd19SJun-ichiro itojun Hagino 321686cdd19SJun-ichiro itojun Hagino switch (proto) { 322686cdd19SJun-ichiro itojun Hagino #ifdef INET 323686cdd19SJun-ichiro itojun Hagino case IPPROTO_IPV4: 324686cdd19SJun-ichiro itojun Hagino break; 325686cdd19SJun-ichiro itojun Hagino #endif 326686cdd19SJun-ichiro itojun Hagino #ifdef INET6 327686cdd19SJun-ichiro itojun Hagino case IPPROTO_IPV6: 328686cdd19SJun-ichiro itojun Hagino break; 329686cdd19SJun-ichiro itojun Hagino #endif 33073ff045cSAndrew Thompson case IPPROTO_ETHERIP: 33173ff045cSAndrew Thompson break; 33273ff045cSAndrew Thompson 333686cdd19SJun-ichiro itojun Hagino default: 334686cdd19SJun-ichiro itojun Hagino return 0; 335686cdd19SJun-ichiro itojun Hagino } 336686cdd19SJun-ichiro itojun Hagino 3373bb61ca6SHajimu UMEMOTO /* Bail on short packets */ 3383bb61ca6SHajimu UMEMOTO if (m->m_pkthdr.len < sizeof(ip)) 3393bb61ca6SHajimu UMEMOTO return 0; 3403bb61ca6SHajimu UMEMOTO 3416f4ded3aSBrooks Davis m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 342686cdd19SJun-ichiro itojun Hagino 343686cdd19SJun-ichiro itojun Hagino switch (ip.ip_v) { 344686cdd19SJun-ichiro itojun Hagino #ifdef INET 345686cdd19SJun-ichiro itojun Hagino case 4: 346686cdd19SJun-ichiro itojun Hagino if (sc->gif_psrc->sa_family != AF_INET || 347686cdd19SJun-ichiro itojun Hagino sc->gif_pdst->sa_family != AF_INET) 348686cdd19SJun-ichiro itojun Hagino return 0; 349686cdd19SJun-ichiro itojun Hagino return gif_encapcheck4(m, off, proto, arg); 350686cdd19SJun-ichiro itojun Hagino #endif 351686cdd19SJun-ichiro itojun Hagino #ifdef INET6 352686cdd19SJun-ichiro itojun Hagino case 6: 3539426aedfSHajimu UMEMOTO if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) 3549426aedfSHajimu UMEMOTO return 0; 355686cdd19SJun-ichiro itojun Hagino if (sc->gif_psrc->sa_family != AF_INET6 || 356686cdd19SJun-ichiro itojun Hagino sc->gif_pdst->sa_family != AF_INET6) 357686cdd19SJun-ichiro itojun Hagino return 0; 358686cdd19SJun-ichiro itojun Hagino return gif_encapcheck6(m, off, proto, arg); 359686cdd19SJun-ichiro itojun Hagino #endif 360686cdd19SJun-ichiro itojun Hagino default: 361686cdd19SJun-ichiro itojun Hagino return 0; 362686cdd19SJun-ichiro itojun Hagino } 363686cdd19SJun-ichiro itojun Hagino } 364686cdd19SJun-ichiro itojun Hagino 36573ff045cSAndrew Thompson static void 36673ff045cSAndrew Thompson gif_start(struct ifnet *ifp) 36773ff045cSAndrew Thompson { 36873ff045cSAndrew Thompson struct gif_softc *sc; 36973ff045cSAndrew Thompson struct mbuf *m; 37073ff045cSAndrew Thompson 37173ff045cSAndrew Thompson sc = ifp->if_softc; 37273ff045cSAndrew Thompson 37373ff045cSAndrew Thompson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 37473ff045cSAndrew Thompson for (;;) { 37573ff045cSAndrew Thompson IFQ_DEQUEUE(&ifp->if_snd, m); 37673ff045cSAndrew Thompson if (m == 0) 37773ff045cSAndrew Thompson break; 37873ff045cSAndrew Thompson 37973ff045cSAndrew Thompson gif_output(ifp, m, sc->gif_pdst, NULL); 38073ff045cSAndrew Thompson 38173ff045cSAndrew Thompson } 38273ff045cSAndrew Thompson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 38373ff045cSAndrew Thompson 38473ff045cSAndrew Thompson return; 38573ff045cSAndrew Thompson } 38673ff045cSAndrew Thompson 387cfa1ca9dSYoshinobu Inoue int 388279aa3d4SKip Macy gif_output(ifp, m, dst, ro) 389cfa1ca9dSYoshinobu Inoue struct ifnet *ifp; 390cfa1ca9dSYoshinobu Inoue struct mbuf *m; 391cfa1ca9dSYoshinobu Inoue struct sockaddr *dst; 392279aa3d4SKip Macy struct route *ro; 393cfa1ca9dSYoshinobu Inoue { 394fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 3958c7e1947SRuslan Ermilov struct m_tag *mtag; 396cfa1ca9dSYoshinobu Inoue int error = 0; 3978c7e1947SRuslan Ermilov int gif_called; 39801399f34SDavid Malone u_int32_t af; 399cfa1ca9dSYoshinobu Inoue 40010722b85SRobert Watson #ifdef MAC 40130d239bcSRobert Watson error = mac_ifnet_check_transmit(ifp, m); 402e0852ce2SRobert Watson if (error) { 403e0852ce2SRobert Watson m_freem(m); 404e0852ce2SRobert Watson goto end; 405e0852ce2SRobert Watson } 40610722b85SRobert Watson #endif 40710722b85SRobert Watson 408cfa1ca9dSYoshinobu Inoue /* 409cfa1ca9dSYoshinobu Inoue * gif may cause infinite recursion calls when misconfigured. 4108c7e1947SRuslan Ermilov * We'll prevent this by detecting loops. 4118c7e1947SRuslan Ermilov * 4128c7e1947SRuslan Ermilov * High nesting level may cause stack exhaustion. 413cfa1ca9dSYoshinobu Inoue * We'll prevent this by introducing upper limit. 414cfa1ca9dSYoshinobu Inoue */ 4158c7e1947SRuslan Ermilov gif_called = 1; 4168c7e1947SRuslan Ermilov mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, NULL); 4178c7e1947SRuslan Ermilov while (mtag != NULL) { 4188c7e1947SRuslan Ermilov if (*(struct ifnet **)(mtag + 1) == ifp) { 4198c7e1947SRuslan Ermilov log(LOG_NOTICE, 4208c7e1947SRuslan Ermilov "gif_output: loop detected on %s\n", 4218c7e1947SRuslan Ermilov (*(struct ifnet **)(mtag + 1))->if_xname); 4228c7e1947SRuslan Ermilov m_freem(m); 4238c7e1947SRuslan Ermilov error = EIO; /* is there better errno? */ 4248c7e1947SRuslan Ermilov goto end; 4258c7e1947SRuslan Ermilov } 4268c7e1947SRuslan Ermilov mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, mtag); 4278c7e1947SRuslan Ermilov gif_called++; 4288c7e1947SRuslan Ermilov } 429603724d3SBjoern A. Zeeb if (gif_called > V_max_gif_nesting) { 430cfa1ca9dSYoshinobu Inoue log(LOG_NOTICE, 431cfa1ca9dSYoshinobu Inoue "gif_output: recursively called too many times(%d)\n", 432523ebc4eSRobert Watson gif_called); 433cfa1ca9dSYoshinobu Inoue m_freem(m); 434cfa1ca9dSYoshinobu Inoue error = EIO; /* is there better errno? */ 435cfa1ca9dSYoshinobu Inoue goto end; 436cfa1ca9dSYoshinobu Inoue } 4378c7e1947SRuslan Ermilov mtag = m_tag_alloc(MTAG_GIF, MTAG_GIF_CALLED, sizeof(struct ifnet *), 4388c7e1947SRuslan Ermilov M_NOWAIT); 4398c7e1947SRuslan Ermilov if (mtag == NULL) { 4408c7e1947SRuslan Ermilov m_freem(m); 4418c7e1947SRuslan Ermilov error = ENOMEM; 4428c7e1947SRuslan Ermilov goto end; 4438c7e1947SRuslan Ermilov } 4448c7e1947SRuslan Ermilov *(struct ifnet **)(mtag + 1) = ifp; 4458c7e1947SRuslan Ermilov m_tag_prepend(m, mtag); 446686cdd19SJun-ichiro itojun Hagino 447cfa1ca9dSYoshinobu Inoue m->m_flags &= ~(M_BCAST|M_MCAST); 44825af0bb5SGleb Smirnoff 44925af0bb5SGleb Smirnoff GIF_LOCK(sc); 45025af0bb5SGleb Smirnoff 451cfa1ca9dSYoshinobu Inoue if (!(ifp->if_flags & IFF_UP) || 452cfa1ca9dSYoshinobu Inoue sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 4536e860629SGleb Smirnoff GIF_UNLOCK(sc); 454cfa1ca9dSYoshinobu Inoue m_freem(m); 455cfa1ca9dSYoshinobu Inoue error = ENETDOWN; 456cfa1ca9dSYoshinobu Inoue goto end; 457cfa1ca9dSYoshinobu Inoue } 458cfa1ca9dSYoshinobu Inoue 45901399f34SDavid Malone /* BPF writes need to be handled specially. */ 46001399f34SDavid Malone if (dst->sa_family == AF_UNSPEC) { 46101399f34SDavid Malone bcopy(dst->sa_data, &af, sizeof(af)); 46201399f34SDavid Malone dst->sa_family = af; 46301399f34SDavid Malone } 46401399f34SDavid Malone 46501399f34SDavid Malone af = dst->sa_family; 46616d878ccSChristian S.J. Peron BPF_MTAP2(ifp, &af, sizeof(af), m); 467cfa1ca9dSYoshinobu Inoue ifp->if_opackets++; 468cfa1ca9dSYoshinobu Inoue ifp->if_obytes += m->m_pkthdr.len; 469cfa1ca9dSYoshinobu Inoue 47073ff045cSAndrew Thompson /* override to IPPROTO_ETHERIP for bridged traffic */ 47173ff045cSAndrew Thompson if (ifp->if_bridge) 47273ff045cSAndrew Thompson af = AF_LINK; 47373ff045cSAndrew Thompson 4748b07e49aSJulian Elischer M_SETFIB(m, sc->gif_fibnum); 47533841545SHajimu UMEMOTO /* inner AF-specific encapsulation */ 47633841545SHajimu UMEMOTO 477686cdd19SJun-ichiro itojun Hagino /* XXX should we check if our outer source is legal? */ 478686cdd19SJun-ichiro itojun Hagino 47933841545SHajimu UMEMOTO /* dispatch to output logic based on outer AF */ 480cfa1ca9dSYoshinobu Inoue switch (sc->gif_psrc->sa_family) { 481cfa1ca9dSYoshinobu Inoue #ifdef INET 482cfa1ca9dSYoshinobu Inoue case AF_INET: 48373ff045cSAndrew Thompson error = in_gif_output(ifp, af, m); 484cfa1ca9dSYoshinobu Inoue break; 485cfa1ca9dSYoshinobu Inoue #endif 486cfa1ca9dSYoshinobu Inoue #ifdef INET6 487cfa1ca9dSYoshinobu Inoue case AF_INET6: 48873ff045cSAndrew Thompson error = in6_gif_output(ifp, af, m); 489cfa1ca9dSYoshinobu Inoue break; 490cfa1ca9dSYoshinobu Inoue #endif 491cfa1ca9dSYoshinobu Inoue default: 492cfa1ca9dSYoshinobu Inoue m_freem(m); 493cfa1ca9dSYoshinobu Inoue error = ENETDOWN; 494cfa1ca9dSYoshinobu Inoue } 495cfa1ca9dSYoshinobu Inoue 4966e860629SGleb Smirnoff GIF_UNLOCK(sc); 497cfa1ca9dSYoshinobu Inoue end: 49833841545SHajimu UMEMOTO if (error) 49933841545SHajimu UMEMOTO ifp->if_oerrors++; 50025af0bb5SGleb Smirnoff return (error); 501cfa1ca9dSYoshinobu Inoue } 502cfa1ca9dSYoshinobu Inoue 503cfa1ca9dSYoshinobu Inoue void 50421fb391fSHajimu UMEMOTO gif_input(m, af, ifp) 505cfa1ca9dSYoshinobu Inoue struct mbuf *m; 506cfa1ca9dSYoshinobu Inoue int af; 50721fb391fSHajimu UMEMOTO struct ifnet *ifp; 508cfa1ca9dSYoshinobu Inoue { 50973ff045cSAndrew Thompson int isr, n; 510dbe59260SHiroki Sato struct gif_softc *sc = ifp->if_softc; 51173ff045cSAndrew Thompson struct etherip_header *eip; 51256abdd33SAndrew Thompson struct ether_header *eh; 51356abdd33SAndrew Thompson struct ifnet *oldifp; 514cfa1ca9dSYoshinobu Inoue 51521fb391fSHajimu UMEMOTO if (ifp == NULL) { 516cfa1ca9dSYoshinobu Inoue /* just in case */ 517cfa1ca9dSYoshinobu Inoue m_freem(m); 518cfa1ca9dSYoshinobu Inoue return; 519cfa1ca9dSYoshinobu Inoue } 520cfa1ca9dSYoshinobu Inoue 52121fb391fSHajimu UMEMOTO m->m_pkthdr.rcvif = ifp; 522cfa1ca9dSYoshinobu Inoue 52310722b85SRobert Watson #ifdef MAC 52430d239bcSRobert Watson mac_ifnet_create_mbuf(ifp, m); 52510722b85SRobert Watson #endif 52610722b85SRobert Watson 52716d878ccSChristian S.J. Peron if (bpf_peers_present(ifp->if_bpf)) { 52833841545SHajimu UMEMOTO u_int32_t af1 = af; 529437ffe18SSam Leffler bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m); 530cfa1ca9dSYoshinobu Inoue } 531cfa1ca9dSYoshinobu Inoue 53294408d94SBrooks Davis if (ng_gif_input_p != NULL) { 53321fb391fSHajimu UMEMOTO (*ng_gif_input_p)(ifp, &m, af); 53494408d94SBrooks Davis if (m == NULL) 53594408d94SBrooks Davis return; 53694408d94SBrooks Davis } 53794408d94SBrooks Davis 538cfa1ca9dSYoshinobu Inoue /* 539cfa1ca9dSYoshinobu Inoue * Put the packet to the network layer input queue according to the 540cfa1ca9dSYoshinobu Inoue * specified address family. 541cfa1ca9dSYoshinobu Inoue * Note: older versions of gif_input directly called network layer 542cfa1ca9dSYoshinobu Inoue * input functions, e.g. ip6_input, here. We changed the policy to 543cfa1ca9dSYoshinobu Inoue * prevent too many recursive calls of such input functions, which 544cfa1ca9dSYoshinobu Inoue * might cause kernel panic. But the change may introduce another 545cfa1ca9dSYoshinobu Inoue * problem; if the input queue is full, packets are discarded. 54688ff5695SSUZUKI Shinsuke * The kernel stack overflow really happened, and we believed 54788ff5695SSUZUKI Shinsuke * queue-full rarely occurs, so we changed the policy. 548cfa1ca9dSYoshinobu Inoue */ 549cfa1ca9dSYoshinobu Inoue switch (af) { 550cfa1ca9dSYoshinobu Inoue #ifdef INET 551cfa1ca9dSYoshinobu Inoue case AF_INET: 552cfa1ca9dSYoshinobu Inoue isr = NETISR_IP; 553cfa1ca9dSYoshinobu Inoue break; 554cfa1ca9dSYoshinobu Inoue #endif 555cfa1ca9dSYoshinobu Inoue #ifdef INET6 556cfa1ca9dSYoshinobu Inoue case AF_INET6: 557cfa1ca9dSYoshinobu Inoue isr = NETISR_IPV6; 558cfa1ca9dSYoshinobu Inoue break; 559cfa1ca9dSYoshinobu Inoue #endif 56073ff045cSAndrew Thompson case AF_LINK: 56173ff045cSAndrew Thompson n = sizeof(struct etherip_header) + sizeof(struct ether_header); 56273ff045cSAndrew Thompson if (n > m->m_len) { 56373ff045cSAndrew Thompson m = m_pullup(m, n); 56473ff045cSAndrew Thompson if (m == NULL) { 56573ff045cSAndrew Thompson ifp->if_ierrors++; 56673ff045cSAndrew Thompson return; 56773ff045cSAndrew Thompson } 56873ff045cSAndrew Thompson } 56973ff045cSAndrew Thompson 57073ff045cSAndrew Thompson eip = mtod(m, struct etherip_header *); 571dbe59260SHiroki Sato /* 572dbe59260SHiroki Sato * GIF_ACCEPT_REVETHIP (enabled by default) intentionally 573dbe59260SHiroki Sato * accepts an EtherIP packet with revered version field in 574dbe59260SHiroki Sato * the header. This is a knob for backward compatibility 575dbe59260SHiroki Sato * with FreeBSD 7.2R or prior. 576dbe59260SHiroki Sato */ 577dbe59260SHiroki Sato if (sc->gif_options & GIF_ACCEPT_REVETHIP) { 578dbe59260SHiroki Sato if (eip->eip_resvl != ETHERIP_VERSION 579dbe59260SHiroki Sato && eip->eip_ver != ETHERIP_VERSION) { 58073ff045cSAndrew Thompson /* discard unknown versions */ 58173ff045cSAndrew Thompson m_freem(m); 58273ff045cSAndrew Thompson return; 58373ff045cSAndrew Thompson } 584dbe59260SHiroki Sato } else { 585dbe59260SHiroki Sato if (eip->eip_ver != ETHERIP_VERSION) { 586dbe59260SHiroki Sato /* discard unknown versions */ 587dbe59260SHiroki Sato m_freem(m); 588dbe59260SHiroki Sato return; 589dbe59260SHiroki Sato } 590dbe59260SHiroki Sato } 59173ff045cSAndrew Thompson m_adj(m, sizeof(struct etherip_header)); 59273ff045cSAndrew Thompson 59373ff045cSAndrew Thompson m->m_flags &= ~(M_BCAST|M_MCAST); 59473ff045cSAndrew Thompson m->m_pkthdr.rcvif = ifp; 59573ff045cSAndrew Thompson 59656abdd33SAndrew Thompson if (ifp->if_bridge) { 59756abdd33SAndrew Thompson oldifp = ifp; 59856abdd33SAndrew Thompson eh = mtod(m, struct ether_header *); 59956abdd33SAndrew Thompson if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 60056abdd33SAndrew Thompson if (ETHER_IS_BROADCAST(eh->ether_dhost)) 60156abdd33SAndrew Thompson m->m_flags |= M_BCAST; 60256abdd33SAndrew Thompson else 60356abdd33SAndrew Thompson m->m_flags |= M_MCAST; 60456abdd33SAndrew Thompson ifp->if_imcasts++; 60556abdd33SAndrew Thompson } 60673ff045cSAndrew Thompson BRIDGE_INPUT(ifp, m); 60773ff045cSAndrew Thompson 60856abdd33SAndrew Thompson if (m != NULL && ifp != oldifp) { 60956abdd33SAndrew Thompson /* 61056abdd33SAndrew Thompson * The bridge gave us back itself or one of the 61156abdd33SAndrew Thompson * members for which the frame is addressed. 61256abdd33SAndrew Thompson */ 61356abdd33SAndrew Thompson ether_demux(ifp, m); 61456abdd33SAndrew Thompson return; 61556abdd33SAndrew Thompson } 61656abdd33SAndrew Thompson } 61773ff045cSAndrew Thompson if (m != NULL) 61873ff045cSAndrew Thompson m_freem(m); 61973ff045cSAndrew Thompson return; 62073ff045cSAndrew Thompson 621cfa1ca9dSYoshinobu Inoue default: 62294408d94SBrooks Davis if (ng_gif_input_orphan_p != NULL) 62321fb391fSHajimu UMEMOTO (*ng_gif_input_orphan_p)(ifp, m, af); 62494408d94SBrooks Davis else 625cfa1ca9dSYoshinobu Inoue m_freem(m); 626cfa1ca9dSYoshinobu Inoue return; 627cfa1ca9dSYoshinobu Inoue } 628cfa1ca9dSYoshinobu Inoue 62921fb391fSHajimu UMEMOTO ifp->if_ipackets++; 63021fb391fSHajimu UMEMOTO ifp->if_ibytes += m->m_pkthdr.len; 6311cafed39SJonathan Lemon netisr_dispatch(isr, m); 632cfa1ca9dSYoshinobu Inoue } 633cfa1ca9dSYoshinobu Inoue 634686cdd19SJun-ichiro itojun Hagino /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ 635cfa1ca9dSYoshinobu Inoue int 636cfa1ca9dSYoshinobu Inoue gif_ioctl(ifp, cmd, data) 637cfa1ca9dSYoshinobu Inoue struct ifnet *ifp; 638cfa1ca9dSYoshinobu Inoue u_long cmd; 639cfa1ca9dSYoshinobu Inoue caddr_t data; 640cfa1ca9dSYoshinobu Inoue { 641fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 642cfa1ca9dSYoshinobu Inoue struct ifreq *ifr = (struct ifreq*)data; 643cfa1ca9dSYoshinobu Inoue int error = 0, size; 644dbe59260SHiroki Sato u_int options; 645686cdd19SJun-ichiro itojun Hagino struct sockaddr *dst, *src; 6463bb61ca6SHajimu UMEMOTO #ifdef SIOCSIFMTU /* xxx */ 6473bb61ca6SHajimu UMEMOTO u_long mtu; 6483bb61ca6SHajimu UMEMOTO #endif 649cfa1ca9dSYoshinobu Inoue 650cfa1ca9dSYoshinobu Inoue switch (cmd) { 651cfa1ca9dSYoshinobu Inoue case SIOCSIFADDR: 6529426aedfSHajimu UMEMOTO ifp->if_flags |= IFF_UP; 653cfa1ca9dSYoshinobu Inoue break; 654cfa1ca9dSYoshinobu Inoue 655cfa1ca9dSYoshinobu Inoue case SIOCSIFDSTADDR: 656cfa1ca9dSYoshinobu Inoue break; 657cfa1ca9dSYoshinobu Inoue 658cfa1ca9dSYoshinobu Inoue case SIOCADDMULTI: 659cfa1ca9dSYoshinobu Inoue case SIOCDELMULTI: 660cfa1ca9dSYoshinobu Inoue break; 661cfa1ca9dSYoshinobu Inoue 662686cdd19SJun-ichiro itojun Hagino #ifdef SIOCSIFMTU /* xxx */ 663cfa1ca9dSYoshinobu Inoue case SIOCGIFMTU: 664cfa1ca9dSYoshinobu Inoue break; 665686cdd19SJun-ichiro itojun Hagino 666cfa1ca9dSYoshinobu Inoue case SIOCSIFMTU: 667cfa1ca9dSYoshinobu Inoue mtu = ifr->ifr_mtu; 6683bb61ca6SHajimu UMEMOTO if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) 669cfa1ca9dSYoshinobu Inoue return (EINVAL); 670cfa1ca9dSYoshinobu Inoue ifp->if_mtu = mtu; 671cfa1ca9dSYoshinobu Inoue break; 672686cdd19SJun-ichiro itojun Hagino #endif /* SIOCSIFMTU */ 673cfa1ca9dSYoshinobu Inoue 6743bb61ca6SHajimu UMEMOTO #ifdef INET 675cfa1ca9dSYoshinobu Inoue case SIOCSIFPHYADDR: 6763bb61ca6SHajimu UMEMOTO #endif 677cfa1ca9dSYoshinobu Inoue #ifdef INET6 678cfa1ca9dSYoshinobu Inoue case SIOCSIFPHYADDR_IN6: 679cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 68033841545SHajimu UMEMOTO case SIOCSLIFPHYADDR: 681686cdd19SJun-ichiro itojun Hagino switch (cmd) { 68233841545SHajimu UMEMOTO #ifdef INET 683686cdd19SJun-ichiro itojun Hagino case SIOCSIFPHYADDR: 684cfa1ca9dSYoshinobu Inoue src = (struct sockaddr *) 685cfa1ca9dSYoshinobu Inoue &(((struct in_aliasreq *)data)->ifra_addr); 686cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 687cfa1ca9dSYoshinobu Inoue &(((struct in_aliasreq *)data)->ifra_dstaddr); 688cfa1ca9dSYoshinobu Inoue break; 68933841545SHajimu UMEMOTO #endif 690cfa1ca9dSYoshinobu Inoue #ifdef INET6 691686cdd19SJun-ichiro itojun Hagino case SIOCSIFPHYADDR_IN6: 692cfa1ca9dSYoshinobu Inoue src = (struct sockaddr *) 693cfa1ca9dSYoshinobu Inoue &(((struct in6_aliasreq *)data)->ifra_addr); 694cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 695cfa1ca9dSYoshinobu Inoue &(((struct in6_aliasreq *)data)->ifra_dstaddr); 696686cdd19SJun-ichiro itojun Hagino break; 697686cdd19SJun-ichiro itojun Hagino #endif 69833841545SHajimu UMEMOTO case SIOCSLIFPHYADDR: 69933841545SHajimu UMEMOTO src = (struct sockaddr *) 70033841545SHajimu UMEMOTO &(((struct if_laddrreq *)data)->addr); 70133841545SHajimu UMEMOTO dst = (struct sockaddr *) 70233841545SHajimu UMEMOTO &(((struct if_laddrreq *)data)->dstaddr); 7039426aedfSHajimu UMEMOTO break; 7046f4ded3aSBrooks Davis default: 7059426aedfSHajimu UMEMOTO return EINVAL; 70633841545SHajimu UMEMOTO } 70733841545SHajimu UMEMOTO 70833841545SHajimu UMEMOTO /* sa_family must be equal */ 70933841545SHajimu UMEMOTO if (src->sa_family != dst->sa_family) 71033841545SHajimu UMEMOTO return EINVAL; 71133841545SHajimu UMEMOTO 71233841545SHajimu UMEMOTO /* validate sa_len */ 71333841545SHajimu UMEMOTO switch (src->sa_family) { 71433841545SHajimu UMEMOTO #ifdef INET 71533841545SHajimu UMEMOTO case AF_INET: 71633841545SHajimu UMEMOTO if (src->sa_len != sizeof(struct sockaddr_in)) 71733841545SHajimu UMEMOTO return EINVAL; 71833841545SHajimu UMEMOTO break; 71933841545SHajimu UMEMOTO #endif 72033841545SHajimu UMEMOTO #ifdef INET6 72133841545SHajimu UMEMOTO case AF_INET6: 72233841545SHajimu UMEMOTO if (src->sa_len != sizeof(struct sockaddr_in6)) 72333841545SHajimu UMEMOTO return EINVAL; 72433841545SHajimu UMEMOTO break; 72533841545SHajimu UMEMOTO #endif 72633841545SHajimu UMEMOTO default: 72733841545SHajimu UMEMOTO return EAFNOSUPPORT; 72833841545SHajimu UMEMOTO } 72933841545SHajimu UMEMOTO switch (dst->sa_family) { 73033841545SHajimu UMEMOTO #ifdef INET 73133841545SHajimu UMEMOTO case AF_INET: 73233841545SHajimu UMEMOTO if (dst->sa_len != sizeof(struct sockaddr_in)) 73333841545SHajimu UMEMOTO return EINVAL; 73433841545SHajimu UMEMOTO break; 73533841545SHajimu UMEMOTO #endif 73633841545SHajimu UMEMOTO #ifdef INET6 73733841545SHajimu UMEMOTO case AF_INET6: 73833841545SHajimu UMEMOTO if (dst->sa_len != sizeof(struct sockaddr_in6)) 73933841545SHajimu UMEMOTO return EINVAL; 74033841545SHajimu UMEMOTO break; 74133841545SHajimu UMEMOTO #endif 74233841545SHajimu UMEMOTO default: 74333841545SHajimu UMEMOTO return EAFNOSUPPORT; 74433841545SHajimu UMEMOTO } 74533841545SHajimu UMEMOTO 74633841545SHajimu UMEMOTO /* check sa_family looks sane for the cmd */ 74733841545SHajimu UMEMOTO switch (cmd) { 74833841545SHajimu UMEMOTO case SIOCSIFPHYADDR: 74933841545SHajimu UMEMOTO if (src->sa_family == AF_INET) 75033841545SHajimu UMEMOTO break; 75133841545SHajimu UMEMOTO return EAFNOSUPPORT; 75233841545SHajimu UMEMOTO #ifdef INET6 75333841545SHajimu UMEMOTO case SIOCSIFPHYADDR_IN6: 75433841545SHajimu UMEMOTO if (src->sa_family == AF_INET6) 75533841545SHajimu UMEMOTO break; 75633841545SHajimu UMEMOTO return EAFNOSUPPORT; 75733841545SHajimu UMEMOTO #endif /* INET6 */ 75833841545SHajimu UMEMOTO case SIOCSLIFPHYADDR: 75933841545SHajimu UMEMOTO /* checks done in the above */ 76033841545SHajimu UMEMOTO break; 761686cdd19SJun-ichiro itojun Hagino } 762cfa1ca9dSYoshinobu Inoue 763fc74a9f9SBrooks Davis error = gif_set_tunnel(GIF2IFP(sc), src, dst); 764cfa1ca9dSYoshinobu Inoue break; 765cfa1ca9dSYoshinobu Inoue 766686cdd19SJun-ichiro itojun Hagino #ifdef SIOCDIFPHYADDR 767686cdd19SJun-ichiro itojun Hagino case SIOCDIFPHYADDR: 768fc74a9f9SBrooks Davis gif_delete_tunnel(GIF2IFP(sc)); 769686cdd19SJun-ichiro itojun Hagino break; 770686cdd19SJun-ichiro itojun Hagino #endif 771686cdd19SJun-ichiro itojun Hagino 772cfa1ca9dSYoshinobu Inoue case SIOCGIFPSRCADDR: 773cfa1ca9dSYoshinobu Inoue #ifdef INET6 774cfa1ca9dSYoshinobu Inoue case SIOCGIFPSRCADDR_IN6: 775cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 776cfa1ca9dSYoshinobu Inoue if (sc->gif_psrc == NULL) { 777cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 778cfa1ca9dSYoshinobu Inoue goto bad; 779cfa1ca9dSYoshinobu Inoue } 780cfa1ca9dSYoshinobu Inoue src = sc->gif_psrc; 78133841545SHajimu UMEMOTO switch (cmd) { 782cfa1ca9dSYoshinobu Inoue #ifdef INET 78333841545SHajimu UMEMOTO case SIOCGIFPSRCADDR: 784cfa1ca9dSYoshinobu Inoue dst = &ifr->ifr_addr; 78533841545SHajimu UMEMOTO size = sizeof(ifr->ifr_addr); 786cfa1ca9dSYoshinobu Inoue break; 787cfa1ca9dSYoshinobu Inoue #endif /* INET */ 788cfa1ca9dSYoshinobu Inoue #ifdef INET6 78933841545SHajimu UMEMOTO case SIOCGIFPSRCADDR_IN6: 790cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 791cfa1ca9dSYoshinobu Inoue &(((struct in6_ifreq *)data)->ifr_addr); 79233841545SHajimu UMEMOTO size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 793cfa1ca9dSYoshinobu Inoue break; 794cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 795cfa1ca9dSYoshinobu Inoue default: 796cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 797cfa1ca9dSYoshinobu Inoue goto bad; 798cfa1ca9dSYoshinobu Inoue } 79933841545SHajimu UMEMOTO if (src->sa_len > size) 80033841545SHajimu UMEMOTO return EINVAL; 80133841545SHajimu UMEMOTO bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 802a1f7e5f8SHajimu UMEMOTO #ifdef INET6 803a1f7e5f8SHajimu UMEMOTO if (dst->sa_family == AF_INET6) { 804a1f7e5f8SHajimu UMEMOTO error = sa6_recoverscope((struct sockaddr_in6 *)dst); 805a1f7e5f8SHajimu UMEMOTO if (error != 0) 806a1f7e5f8SHajimu UMEMOTO return (error); 807a1f7e5f8SHajimu UMEMOTO } 808a1f7e5f8SHajimu UMEMOTO #endif 809cfa1ca9dSYoshinobu Inoue break; 810cfa1ca9dSYoshinobu Inoue 811cfa1ca9dSYoshinobu Inoue case SIOCGIFPDSTADDR: 812cfa1ca9dSYoshinobu Inoue #ifdef INET6 813cfa1ca9dSYoshinobu Inoue case SIOCGIFPDSTADDR_IN6: 814cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 815cfa1ca9dSYoshinobu Inoue if (sc->gif_pdst == NULL) { 816cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 817cfa1ca9dSYoshinobu Inoue goto bad; 818cfa1ca9dSYoshinobu Inoue } 819cfa1ca9dSYoshinobu Inoue src = sc->gif_pdst; 82033841545SHajimu UMEMOTO switch (cmd) { 821cfa1ca9dSYoshinobu Inoue #ifdef INET 82233841545SHajimu UMEMOTO case SIOCGIFPDSTADDR: 823cfa1ca9dSYoshinobu Inoue dst = &ifr->ifr_addr; 82433841545SHajimu UMEMOTO size = sizeof(ifr->ifr_addr); 825cfa1ca9dSYoshinobu Inoue break; 826cfa1ca9dSYoshinobu Inoue #endif /* INET */ 827cfa1ca9dSYoshinobu Inoue #ifdef INET6 82833841545SHajimu UMEMOTO case SIOCGIFPDSTADDR_IN6: 829cfa1ca9dSYoshinobu Inoue dst = (struct sockaddr *) 830cfa1ca9dSYoshinobu Inoue &(((struct in6_ifreq *)data)->ifr_addr); 83133841545SHajimu UMEMOTO size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 832cfa1ca9dSYoshinobu Inoue break; 833cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 834cfa1ca9dSYoshinobu Inoue default: 835cfa1ca9dSYoshinobu Inoue error = EADDRNOTAVAIL; 836cfa1ca9dSYoshinobu Inoue goto bad; 837cfa1ca9dSYoshinobu Inoue } 83833841545SHajimu UMEMOTO if (src->sa_len > size) 83933841545SHajimu UMEMOTO return EINVAL; 84033841545SHajimu UMEMOTO bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 841a1f7e5f8SHajimu UMEMOTO #ifdef INET6 842a1f7e5f8SHajimu UMEMOTO if (dst->sa_family == AF_INET6) { 843a1f7e5f8SHajimu UMEMOTO error = sa6_recoverscope((struct sockaddr_in6 *)dst); 844a1f7e5f8SHajimu UMEMOTO if (error != 0) 845a1f7e5f8SHajimu UMEMOTO return (error); 846a1f7e5f8SHajimu UMEMOTO } 847a1f7e5f8SHajimu UMEMOTO #endif 84833841545SHajimu UMEMOTO break; 84933841545SHajimu UMEMOTO 85033841545SHajimu UMEMOTO case SIOCGLIFPHYADDR: 85133841545SHajimu UMEMOTO if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 85233841545SHajimu UMEMOTO error = EADDRNOTAVAIL; 85333841545SHajimu UMEMOTO goto bad; 85433841545SHajimu UMEMOTO } 85533841545SHajimu UMEMOTO 85633841545SHajimu UMEMOTO /* copy src */ 85733841545SHajimu UMEMOTO src = sc->gif_psrc; 85833841545SHajimu UMEMOTO dst = (struct sockaddr *) 85933841545SHajimu UMEMOTO &(((struct if_laddrreq *)data)->addr); 86033841545SHajimu UMEMOTO size = sizeof(((struct if_laddrreq *)data)->addr); 86133841545SHajimu UMEMOTO if (src->sa_len > size) 86233841545SHajimu UMEMOTO return EINVAL; 86333841545SHajimu UMEMOTO bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 86433841545SHajimu UMEMOTO 86533841545SHajimu UMEMOTO /* copy dst */ 86633841545SHajimu UMEMOTO src = sc->gif_pdst; 86733841545SHajimu UMEMOTO dst = (struct sockaddr *) 86833841545SHajimu UMEMOTO &(((struct if_laddrreq *)data)->dstaddr); 86933841545SHajimu UMEMOTO size = sizeof(((struct if_laddrreq *)data)->dstaddr); 87033841545SHajimu UMEMOTO if (src->sa_len > size) 87133841545SHajimu UMEMOTO return EINVAL; 87233841545SHajimu UMEMOTO bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 873cfa1ca9dSYoshinobu Inoue break; 874cfa1ca9dSYoshinobu Inoue 875cfa1ca9dSYoshinobu Inoue case SIOCSIFFLAGS: 876686cdd19SJun-ichiro itojun Hagino /* if_ioctl() takes care of it */ 877cfa1ca9dSYoshinobu Inoue break; 878cfa1ca9dSYoshinobu Inoue 879dbe59260SHiroki Sato case GIFGOPTS: 880dbe59260SHiroki Sato options = sc->gif_options; 881dbe59260SHiroki Sato error = copyout(&options, ifr->ifr_data, 882dbe59260SHiroki Sato sizeof(options)); 883dbe59260SHiroki Sato break; 884dbe59260SHiroki Sato 885dbe59260SHiroki Sato case GIFSOPTS: 886dbe59260SHiroki Sato if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0) 887dbe59260SHiroki Sato break; 8884cd5f57dSHiroki Sato error = copyin(ifr->ifr_data, &options, sizeof(options)); 8894cd5f57dSHiroki Sato if (error) 8904cd5f57dSHiroki Sato break; 8914cd5f57dSHiroki Sato if (options & ~GIF_OPTMASK) 892dbe59260SHiroki Sato error = EINVAL; 8934cd5f57dSHiroki Sato else 8944cd5f57dSHiroki Sato sc->gif_options = options; 895dbe59260SHiroki Sato break; 896dbe59260SHiroki Sato 897cfa1ca9dSYoshinobu Inoue default: 898cfa1ca9dSYoshinobu Inoue error = EINVAL; 899cfa1ca9dSYoshinobu Inoue break; 900cfa1ca9dSYoshinobu Inoue } 901cfa1ca9dSYoshinobu Inoue bad: 902cfa1ca9dSYoshinobu Inoue return error; 903cfa1ca9dSYoshinobu Inoue } 90453dab5feSBrooks Davis 90517d5cb2dSRobert Watson /* 90617d5cb2dSRobert Watson * XXXRW: There's a general event-ordering issue here: the code to check 90717d5cb2dSRobert Watson * if a given tunnel is already present happens before we perform a 90817d5cb2dSRobert Watson * potentially blocking setup of the tunnel. This code needs to be 90917d5cb2dSRobert Watson * re-ordered so that the check and replacement can be atomic using 91017d5cb2dSRobert Watson * a mutex. 91117d5cb2dSRobert Watson */ 9129426aedfSHajimu UMEMOTO int 9139426aedfSHajimu UMEMOTO gif_set_tunnel(ifp, src, dst) 9149426aedfSHajimu UMEMOTO struct ifnet *ifp; 9159426aedfSHajimu UMEMOTO struct sockaddr *src; 9169426aedfSHajimu UMEMOTO struct sockaddr *dst; 91753dab5feSBrooks Davis { 918fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 9199426aedfSHajimu UMEMOTO struct gif_softc *sc2; 9209426aedfSHajimu UMEMOTO struct sockaddr *osrc, *odst, *sa; 9219426aedfSHajimu UMEMOTO int error = 0; 9229426aedfSHajimu UMEMOTO 92317d5cb2dSRobert Watson mtx_lock(&gif_mtx); 924603724d3SBjoern A. Zeeb LIST_FOREACH(sc2, &V_gif_softc_list, gif_list) { 9259426aedfSHajimu UMEMOTO if (sc2 == sc) 9269426aedfSHajimu UMEMOTO continue; 9279426aedfSHajimu UMEMOTO if (!sc2->gif_pdst || !sc2->gif_psrc) 9289426aedfSHajimu UMEMOTO continue; 9299426aedfSHajimu UMEMOTO if (sc2->gif_pdst->sa_family != dst->sa_family || 9309426aedfSHajimu UMEMOTO sc2->gif_pdst->sa_len != dst->sa_len || 9319426aedfSHajimu UMEMOTO sc2->gif_psrc->sa_family != src->sa_family || 9329426aedfSHajimu UMEMOTO sc2->gif_psrc->sa_len != src->sa_len) 9339426aedfSHajimu UMEMOTO continue; 9349426aedfSHajimu UMEMOTO 9359426aedfSHajimu UMEMOTO /* 9369426aedfSHajimu UMEMOTO * Disallow parallel tunnels unless instructed 9379426aedfSHajimu UMEMOTO * otherwise. 9389426aedfSHajimu UMEMOTO */ 939603724d3SBjoern A. Zeeb if (!V_parallel_tunnels && 9409426aedfSHajimu UMEMOTO bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 9419426aedfSHajimu UMEMOTO bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 9429426aedfSHajimu UMEMOTO error = EADDRNOTAVAIL; 94317d5cb2dSRobert Watson mtx_unlock(&gif_mtx); 9449426aedfSHajimu UMEMOTO goto bad; 9459426aedfSHajimu UMEMOTO } 9469426aedfSHajimu UMEMOTO 9479426aedfSHajimu UMEMOTO /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 9489426aedfSHajimu UMEMOTO } 94917d5cb2dSRobert Watson mtx_unlock(&gif_mtx); 9509426aedfSHajimu UMEMOTO 9519426aedfSHajimu UMEMOTO /* XXX we can detach from both, but be polite just in case */ 9529426aedfSHajimu UMEMOTO if (sc->gif_psrc) 9539426aedfSHajimu UMEMOTO switch (sc->gif_psrc->sa_family) { 9549426aedfSHajimu UMEMOTO #ifdef INET 9559426aedfSHajimu UMEMOTO case AF_INET: 9569426aedfSHajimu UMEMOTO (void)in_gif_detach(sc); 9579426aedfSHajimu UMEMOTO break; 9589426aedfSHajimu UMEMOTO #endif 9599426aedfSHajimu UMEMOTO #ifdef INET6 9609426aedfSHajimu UMEMOTO case AF_INET6: 9619426aedfSHajimu UMEMOTO (void)in6_gif_detach(sc); 9629426aedfSHajimu UMEMOTO break; 9639426aedfSHajimu UMEMOTO #endif 9649426aedfSHajimu UMEMOTO } 9659426aedfSHajimu UMEMOTO 9669426aedfSHajimu UMEMOTO osrc = sc->gif_psrc; 967a163d034SWarner Losh sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); 9689426aedfSHajimu UMEMOTO bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 9699426aedfSHajimu UMEMOTO sc->gif_psrc = sa; 9709426aedfSHajimu UMEMOTO 9719426aedfSHajimu UMEMOTO odst = sc->gif_pdst; 972a163d034SWarner Losh sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); 9739426aedfSHajimu UMEMOTO bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 9749426aedfSHajimu UMEMOTO sc->gif_pdst = sa; 9759426aedfSHajimu UMEMOTO 9769426aedfSHajimu UMEMOTO switch (sc->gif_psrc->sa_family) { 9779426aedfSHajimu UMEMOTO #ifdef INET 9789426aedfSHajimu UMEMOTO case AF_INET: 9799426aedfSHajimu UMEMOTO error = in_gif_attach(sc); 9809426aedfSHajimu UMEMOTO break; 9819426aedfSHajimu UMEMOTO #endif 9829426aedfSHajimu UMEMOTO #ifdef INET6 9839426aedfSHajimu UMEMOTO case AF_INET6: 984a1f7e5f8SHajimu UMEMOTO /* 985a1f7e5f8SHajimu UMEMOTO * Check validity of the scope zone ID of the addresses, and 986a1f7e5f8SHajimu UMEMOTO * convert it into the kernel internal form if necessary. 987a1f7e5f8SHajimu UMEMOTO */ 988a1f7e5f8SHajimu UMEMOTO error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_psrc, 0); 989a1f7e5f8SHajimu UMEMOTO if (error != 0) 990a1f7e5f8SHajimu UMEMOTO break; 991a1f7e5f8SHajimu UMEMOTO error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_pdst, 0); 992a1f7e5f8SHajimu UMEMOTO if (error != 0) 993a1f7e5f8SHajimu UMEMOTO break; 9949426aedfSHajimu UMEMOTO error = in6_gif_attach(sc); 9959426aedfSHajimu UMEMOTO break; 9969426aedfSHajimu UMEMOTO #endif 9979426aedfSHajimu UMEMOTO } 9989426aedfSHajimu UMEMOTO if (error) { 9999426aedfSHajimu UMEMOTO /* rollback */ 10009426aedfSHajimu UMEMOTO free((caddr_t)sc->gif_psrc, M_IFADDR); 10019426aedfSHajimu UMEMOTO free((caddr_t)sc->gif_pdst, M_IFADDR); 10029426aedfSHajimu UMEMOTO sc->gif_psrc = osrc; 10039426aedfSHajimu UMEMOTO sc->gif_pdst = odst; 10049426aedfSHajimu UMEMOTO goto bad; 10059426aedfSHajimu UMEMOTO } 10069426aedfSHajimu UMEMOTO 10079426aedfSHajimu UMEMOTO if (osrc) 10089426aedfSHajimu UMEMOTO free((caddr_t)osrc, M_IFADDR); 10099426aedfSHajimu UMEMOTO if (odst) 10109426aedfSHajimu UMEMOTO free((caddr_t)odst, M_IFADDR); 10119426aedfSHajimu UMEMOTO 10129426aedfSHajimu UMEMOTO bad: 10139426aedfSHajimu UMEMOTO if (sc->gif_psrc && sc->gif_pdst) 101413f4c340SRobert Watson ifp->if_drv_flags |= IFF_DRV_RUNNING; 10159426aedfSHajimu UMEMOTO else 101613f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 10179426aedfSHajimu UMEMOTO 10189426aedfSHajimu UMEMOTO return error; 10199426aedfSHajimu UMEMOTO } 10209426aedfSHajimu UMEMOTO 10219426aedfSHajimu UMEMOTO void 10229426aedfSHajimu UMEMOTO gif_delete_tunnel(ifp) 10239426aedfSHajimu UMEMOTO struct ifnet *ifp; 10249426aedfSHajimu UMEMOTO { 1025fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 102653dab5feSBrooks Davis 102753dab5feSBrooks Davis if (sc->gif_psrc) { 102853dab5feSBrooks Davis free((caddr_t)sc->gif_psrc, M_IFADDR); 102953dab5feSBrooks Davis sc->gif_psrc = NULL; 103053dab5feSBrooks Davis } 103153dab5feSBrooks Davis if (sc->gif_pdst) { 103253dab5feSBrooks Davis free((caddr_t)sc->gif_pdst, M_IFADDR); 103353dab5feSBrooks Davis sc->gif_pdst = NULL; 103453dab5feSBrooks Davis } 10359426aedfSHajimu UMEMOTO /* it is safe to detach from both */ 10369426aedfSHajimu UMEMOTO #ifdef INET 10379426aedfSHajimu UMEMOTO (void)in_gif_detach(sc); 10389426aedfSHajimu UMEMOTO #endif 10399426aedfSHajimu UMEMOTO #ifdef INET6 10409426aedfSHajimu UMEMOTO (void)in6_gif_detach(sc); 10419426aedfSHajimu UMEMOTO #endif 104213f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 104353dab5feSBrooks Davis } 1044