1139823Simp/*-
254263Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
354263Sshin * All rights reserved.
454263Sshin *
554263Sshin * Redistribution and use in source and binary forms, with or without
654263Sshin * modification, are permitted provided that the following conditions
754263Sshin * are met:
854263Sshin * 1. Redistributions of source code must retain the above copyright
954263Sshin *    notice, this list of conditions and the following disclaimer.
1054263Sshin * 2. Redistributions in binary form must reproduce the above copyright
1154263Sshin *    notice, this list of conditions and the following disclaimer in the
1254263Sshin *    documentation and/or other materials provided with the distribution.
1354263Sshin * 3. Neither the name of the project nor the names of its contributors
1454263Sshin *    may be used to endorse or promote products derived from this software
1554263Sshin *    without specific prior written permission.
1654263Sshin *
1754263Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1854263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1954263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2054263Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2154263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2254263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2354263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2454263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2554263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2654263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2754263Sshin * SUCH DAMAGE.
28273087Sae *
29273087Sae *	$KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $
3054263Sshin */
3154263Sshin
32273087Sae#include <sys/cdefs.h>
33273087Sae__FBSDID("$FreeBSD: stable/11/sys/net/if_gif.c 338937 2018-09-25 23:33:30Z jpaetzel $");
34273087Sae
3554263Sshin#include "opt_inet.h"
3654263Sshin#include "opt_inet6.h"
3754263Sshin
3854263Sshin#include <sys/param.h>
3954263Sshin#include <sys/systm.h>
40219206Sbz#include <sys/jail.h>
4154263Sshin#include <sys/kernel.h>
42273087Sae#include <sys/lock.h>
4354263Sshin#include <sys/malloc.h>
4454263Sshin#include <sys/mbuf.h>
45129880Sphk#include <sys/module.h>
46273087Sae#include <sys/rmlock.h>
4754263Sshin#include <sys/socket.h>
4854263Sshin#include <sys/sockio.h>
49273087Sae#include <sys/sx.h>
5054263Sshin#include <sys/errno.h>
5154263Sshin#include <sys/time.h>
5291270Sbrooks#include <sys/sysctl.h>
5354263Sshin#include <sys/syslog.h>
54193664Shrs#include <sys/priv.h>
55178888Sjulian#include <sys/proc.h>
5662587Sitojun#include <sys/protosw.h>
5779106Sbrooks#include <sys/conf.h>
5854263Sshin#include <machine/cpu.h>
5954263Sshin
6054263Sshin#include <net/if.h>
61257176Sglebius#include <net/if_var.h>
62130933Sbrooks#include <net/if_clone.h>
6354263Sshin#include <net/if_types.h>
6454263Sshin#include <net/netisr.h>
6554263Sshin#include <net/route.h>
6654263Sshin#include <net/bpf.h>
67196019Srwatson#include <net/vnet.h>
6854263Sshin
6954263Sshin#include <netinet/in.h>
7054263Sshin#include <netinet/in_systm.h>
7178064Sume#include <netinet/ip.h>
72273087Sae#include <netinet/ip_ecn.h>
7378064Sume#ifdef	INET
7454263Sshin#include <netinet/in_var.h>
7579106Sbrooks#include <netinet/ip_var.h>
7654263Sshin#endif	/* INET */
7754263Sshin
7854263Sshin#ifdef INET6
7954263Sshin#ifndef INET
8054263Sshin#include <netinet/in.h>
8154263Sshin#endif
8254263Sshin#include <netinet6/in6_var.h>
8354263Sshin#include <netinet/ip6.h>
84273087Sae#include <netinet6/ip6_ecn.h>
8554263Sshin#include <netinet6/ip6_var.h>
86148385Sume#include <netinet6/scope6_var.h>
8762587Sitojun#include <netinet6/ip6protosw.h>
8854263Sshin#endif /* INET6 */
8954263Sshin
9062587Sitojun#include <netinet/ip_encap.h>
91153621Sthompsa#include <net/ethernet.h>
92153621Sthompsa#include <net/if_bridgevar.h>
9354263Sshin#include <net/if_gif.h>
9454263Sshin
95163606Srwatson#include <security/mac/mac_framework.h>
96163606Srwatson
97241610Sglebiusstatic const char gifname[] = "gif";
9862587Sitojun
99127305Srwatson/*
100271917Shrs * gif_mtx protects a per-vnet gif_softc_list.
101127305Srwatson */
102271917Shrsstatic VNET_DEFINE(struct mtx, gif_mtx);
103271917Shrs#define	V_gif_mtx		VNET(gif_mtx)
10479106Sbrooksstatic MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
105215701Sdimstatic VNET_DEFINE(LIST_HEAD(, gif_softc), gif_softc_list);
106195727Srwatson#define	V_gif_softc_list	VNET(gif_softc_list)
107273087Saestatic struct sx gif_ioctl_sx;
108273087SaeSX_SYSINIT(gif_ioctl_sx, &gif_ioctl_sx, "gif_ioctl");
109195699Srwatson
110271917Shrs#define	GIF_LIST_LOCK_INIT(x)		mtx_init(&V_gif_mtx, "gif_mtx", \
111271917Shrs					    NULL, MTX_DEF)
112271917Shrs#define	GIF_LIST_LOCK_DESTROY(x)	mtx_destroy(&V_gif_mtx)
113271917Shrs#define	GIF_LIST_LOCK(x)		mtx_lock(&V_gif_mtx)
114271917Shrs#define	GIF_LIST_UNLOCK(x)		mtx_unlock(&V_gif_mtx)
115271917Shrs
11683998Sbrooksvoid	(*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af);
11783998Sbrooksvoid	(*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
11883998Sbrooksvoid	(*ng_gif_attach_p)(struct ifnet *ifp);
11983998Sbrooksvoid	(*ng_gif_detach_p)(struct ifnet *ifp);
12083998Sbrooks
121276907Saestatic int	gif_check_nesting(struct ifnet *, struct mbuf *);
122273087Saestatic int	gif_set_tunnel(struct ifnet *, struct sockaddr *,
123273087Sae    struct sockaddr *);
124273087Saestatic void	gif_delete_tunnel(struct ifnet *);
125273087Saestatic int	gif_ioctl(struct ifnet *, u_long, caddr_t);
126273087Saestatic int	gif_transmit(struct ifnet *, struct mbuf *);
127273087Saestatic void	gif_qflush(struct ifnet *);
128160195Ssamstatic int	gif_clone_create(struct if_clone *, int, caddr_t);
129128209Sbrooksstatic void	gif_clone_destroy(struct ifnet *);
130271917Shrsstatic VNET_DEFINE(struct if_clone *, gif_cloner);
131271917Shrs#define	V_gif_cloner	VNET(gif_cloner)
13279106Sbrooks
13392725Salfredstatic int gifmodevent(module_t, int, void *);
13479106Sbrooks
13591270SbrooksSYSCTL_DECL(_net_link);
136227309Sedstatic SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
13791270Sbrooks    "Generic Tunnel Interface");
13862587Sitojun#ifndef MAX_GIF_NEST
13962587Sitojun/*
14091270Sbrooks * This macro controls the default upper limitation on nesting of gif tunnels.
14162587Sitojun * Since, setting a large value to this macro with a careless configuration
14262587Sitojun * may introduce system crash, we don't allow any nestings by default.
14362587Sitojun * If you need to configure nested gif tunnels, you can define this macro
14495023Ssuz * in your kernel configuration file.  However, if you do so, please be
14562587Sitojun * careful to configure the tunnels so that it won't make a loop.
14662587Sitojun */
14762587Sitojun#define MAX_GIF_NEST 1
14862587Sitojun#endif
149215701Sdimstatic VNET_DEFINE(int, max_gif_nesting) = MAX_GIF_NEST;
150195837Srwatson#define	V_max_gif_nesting	VNET(max_gif_nesting)
151274225SglebiusSYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_VNET | CTLFLAG_RW,
152195699Srwatson    &VNET_NAME(max_gif_nesting), 0, "Max nested tunnels");
15362587Sitojun
15491270Sbrooks/*
15591270Sbrooks * By default, we disallow creation of multiple tunnels between the same
15691270Sbrooks * pair of addresses.  Some applications require this functionality so
15791270Sbrooks * we allow control over this check here.
15891270Sbrooks */
159195837Srwatson#ifdef XBONEHACK
160215701Sdimstatic VNET_DEFINE(int, parallel_tunnels) = 1;
161195837Srwatson#else
162215701Sdimstatic VNET_DEFINE(int, parallel_tunnels) = 0;
163195837Srwatson#endif
164195837Srwatson#define	V_parallel_tunnels	VNET(parallel_tunnels)
165274225SglebiusSYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels,
166274225Sglebius    CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(parallel_tunnels), 0,
167274225Sglebius    "Allow parallel tunnels?");
16891270Sbrooks
169128209Sbrooksstatic int
170258167Saegif_clone_create(struct if_clone *ifc, int unit, caddr_t params)
17154263Sshin{
17278064Sume	struct gif_softc *sc;
17354263Sshin
174131672Sbms	sc = malloc(sizeof(struct gif_softc), M_GIF, M_WAITOK | M_ZERO);
175178888Sjulian	sc->gif_fibnum = curthread->td_proc->p_fibnum;
176147256Sbrooks	GIF2IFP(sc) = if_alloc(IFT_GIF);
177155037Sglebius	GIF_LOCK_INIT(sc);
178147256Sbrooks	GIF2IFP(sc)->if_softc = sc;
179241610Sglebius	if_initname(GIF2IFP(sc), gifname, unit);
18079106Sbrooks
181147256Sbrooks	GIF2IFP(sc)->if_addrlen = 0;
182147256Sbrooks	GIF2IFP(sc)->if_mtu    = GIF_MTU;
183147256Sbrooks	GIF2IFP(sc)->if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
18478064Sume#if 0
18579106Sbrooks	/* turn off ingress filter */
186147256Sbrooks	GIF2IFP(sc)->if_flags  |= IFF_LINK2;
18778064Sume#endif
188147256Sbrooks	GIF2IFP(sc)->if_ioctl  = gif_ioctl;
189273087Sae	GIF2IFP(sc)->if_transmit  = gif_transmit;
190273087Sae	GIF2IFP(sc)->if_qflush  = gif_qflush;
191147256Sbrooks	GIF2IFP(sc)->if_output = gif_output;
192288575Shrs	GIF2IFP(sc)->if_capabilities |= IFCAP_LINKSTATE;
193288575Shrs	GIF2IFP(sc)->if_capenable |= IFCAP_LINKSTATE;
194147256Sbrooks	if_attach(GIF2IFP(sc));
195147611Sdwmalone	bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int32_t));
19683998Sbrooks	if (ng_gif_attach_p != NULL)
197147256Sbrooks		(*ng_gif_attach_p)(GIF2IFP(sc));
198155037Sglebius
199271917Shrs	GIF_LIST_LOCK();
200181803Sbz	LIST_INSERT_HEAD(&V_gif_softc_list, sc, gif_list);
201271917Shrs	GIF_LIST_UNLOCK();
202155037Sglebius	return (0);
20379106Sbrooks}
20479106Sbrooks
205127305Srwatsonstatic void
206258167Saegif_clone_destroy(struct ifnet *ifp)
20779106Sbrooks{
208273087Sae	struct gif_softc *sc;
20979106Sbrooks
210273087Sae	sx_xlock(&gif_ioctl_sx);
211273087Sae	sc = ifp->if_softc;
212273087Sae	gif_delete_tunnel(ifp);
213271917Shrs	GIF_LIST_LOCK();
214151266Sthompsa	LIST_REMOVE(sc, gif_list);
215271917Shrs	GIF_LIST_UNLOCK();
21683998Sbrooks	if (ng_gif_detach_p != NULL)
21783998Sbrooks		(*ng_gif_detach_p)(ifp);
21879106Sbrooks	bpfdetach(ifp);
21979106Sbrooks	if_detach(ifp);
220273087Sae	ifp->if_softc = NULL;
221273087Sae	sx_xunlock(&gif_ioctl_sx);
222273087Sae
223147256Sbrooks	if_free(ifp);
224155037Sglebius	GIF_LOCK_DESTROY(sc);
22579106Sbrooks	free(sc, M_GIF);
22679106Sbrooks}
22779106Sbrooks
228195837Srwatsonstatic void
229195837Srwatsonvnet_gif_init(const void *unused __unused)
230190787Szec{
231190787Szec
232190787Szec	LIST_INIT(&V_gif_softc_list);
233271917Shrs	GIF_LIST_LOCK_INIT();
234271917Shrs	V_gif_cloner = if_clone_simple(gifname, gif_clone_create,
235271917Shrs	    gif_clone_destroy, 0);
236190787Szec}
237271917ShrsVNET_SYSINIT(vnet_gif_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
238271917Shrs    vnet_gif_init, NULL);
239190787Szec
240271917Shrsstatic void
241271917Shrsvnet_gif_uninit(const void *unused __unused)
242271917Shrs{
243271917Shrs
244271917Shrs	if_clone_detach(V_gif_cloner);
245271917Shrs	GIF_LIST_LOCK_DESTROY();
246271917Shrs}
247271917ShrsVNET_SYSUNINIT(vnet_gif_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
248271917Shrs    vnet_gif_uninit, NULL);
249271917Shrs
250190787Szecstatic int
251258167Saegifmodevent(module_t mod, int type, void *data)
25279106Sbrooks{
25379106Sbrooks
25479106Sbrooks	switch (type) {
25579106Sbrooks	case MOD_LOAD:
25679106Sbrooks	case MOD_UNLOAD:
25779106Sbrooks		break;
258132199Sphk	default:
259271917Shrs		return (EOPNOTSUPP);
26054263Sshin	}
261271917Shrs	return (0);
26254263Sshin}
26354263Sshin
26479106Sbrooksstatic moduledata_t gif_mod = {
26579106Sbrooks	"if_gif",
26679106Sbrooks	gifmodevent,
267241394Skevlo	0
26879106Sbrooks};
26954263Sshin
27079106SbrooksDECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
27183997SbrooksMODULE_VERSION(if_gif, 1);
27279106Sbrooks
273105293Sumeint
274258167Saegif_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
27562587Sitojun{
276273087Sae	GIF_RLOCK_TRACKER;
277286013Sae	const struct ip *ip;
27862587Sitojun	struct gif_softc *sc;
279273087Sae	int ret;
28062587Sitojun
28162587Sitojun	sc = (struct gif_softc *)arg;
282273087Sae	if (sc == NULL || (GIF2IFP(sc)->if_flags & IFF_UP) == 0)
283273087Sae		return (0);
28462587Sitojun
285273087Sae	ret = 0;
286273087Sae	GIF_RLOCK(sc);
28762587Sitojun
28862587Sitojun	/* no physical address */
289273087Sae	if (sc->gif_family == 0)
290273087Sae		goto done;
29162587Sitojun
29262587Sitojun	switch (proto) {
29362587Sitojun#ifdef INET
29462587Sitojun	case IPPROTO_IPV4:
29562587Sitojun#endif
29662587Sitojun#ifdef INET6
29762587Sitojun	case IPPROTO_IPV6:
29862587Sitojun#endif
299153621Sthompsa	case IPPROTO_ETHERIP:
300153621Sthompsa		break;
30162587Sitojun	default:
302273087Sae		goto done;
30362587Sitojun	}
30462587Sitojun
305105339Sume	/* Bail on short packets */
306286013Sae	M_ASSERTPKTHDR(m);
307273087Sae	if (m->m_pkthdr.len < sizeof(struct ip))
308273087Sae		goto done;
309105339Sume
310286013Sae	ip = mtod(m, const struct ip *);
311286013Sae	switch (ip->ip_v) {
31262587Sitojun#ifdef INET
31362587Sitojun	case 4:
314273087Sae		if (sc->gif_family != AF_INET)
315273087Sae			goto done;
316273087Sae		ret = in_gif_encapcheck(m, off, proto, arg);
317273087Sae		break;
31862587Sitojun#endif
31962587Sitojun#ifdef INET6
32062587Sitojun	case 6:
321105293Sume		if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
322273087Sae			goto done;
323273087Sae		if (sc->gif_family != AF_INET6)
324273087Sae			goto done;
325273087Sae		ret = in6_gif_encapcheck(m, off, proto, arg);
326273087Sae		break;
32762587Sitojun#endif
32862587Sitojun	}
329273087Saedone:
330273087Sae	GIF_RUNLOCK(sc);
331273087Sae	return (ret);
33262587Sitojun}
333273087Sae
334273087Saestatic int
335273087Saegif_transmit(struct ifnet *ifp, struct mbuf *m)
336273087Sae{
337273087Sae	struct gif_softc *sc;
338273087Sae	struct etherip_header *eth;
339236951Srrs#ifdef INET
340273087Sae	struct ip *ip;
341236951Srrs#endif
342236951Srrs#ifdef INET6
343273087Sae	struct ip6_hdr *ip6;
344273087Sae	uint32_t t;
345236951Srrs#endif
346236951Srrs	uint32_t af;
347273087Sae	uint8_t proto, ecn;
348273087Sae	int error;
349153621Sthompsa
350276907Sae#ifdef MAC
351276907Sae	error = mac_ifnet_check_transmit(ifp, m);
352276907Sae	if (error) {
353276907Sae		m_freem(m);
354276907Sae		goto err;
355276907Sae	}
356276907Sae#endif
357273087Sae	error = ENETDOWN;
358153621Sthompsa	sc = ifp->if_softc;
359276907Sae	if ((ifp->if_flags & IFF_MONITOR) != 0 ||
360276907Sae	    (ifp->if_flags & IFF_UP) == 0 ||
361276907Sae	    sc->gif_family == 0 ||
362276907Sae	    (error = gif_check_nesting(ifp, m)) != 0) {
363273087Sae		m_freem(m);
364273087Sae		goto err;
365273087Sae	}
366273087Sae	/* Now pull back the af that we stashed in the csum_data. */
367276907Sae	if (ifp->if_bridge)
368276907Sae		af = AF_LINK;
369276907Sae	else
370276907Sae		af = m->m_pkthdr.csum_data;
371276907Sae	m->m_flags &= ~(M_BCAST|M_MCAST);
372276907Sae	M_SETFIB(m, sc->gif_fibnum);
373273087Sae	BPF_MTAP2(ifp, &af, sizeof(af), m);
374273087Sae	if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
375273087Sae	if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
376273087Sae	/* inner AF-specific encapsulation */
377273087Sae	ecn = 0;
378273087Sae	switch (af) {
379236951Srrs#ifdef INET
380273087Sae	case AF_INET:
381273087Sae		proto = IPPROTO_IPV4;
382273087Sae		if (m->m_len < sizeof(struct ip))
383273087Sae			m = m_pullup(m, sizeof(struct ip));
384273087Sae		if (m == NULL) {
385273087Sae			error = ENOBUFS;
386273087Sae			goto err;
387273087Sae		}
388273087Sae		ip = mtod(m, struct ip *);
389273087Sae		ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED:
390273087Sae		    ECN_NOCARE, &ecn, &ip->ip_tos);
391273087Sae		break;
392236951Srrs#endif
393236951Srrs#ifdef INET6
394273087Sae	case AF_INET6:
395273087Sae		proto = IPPROTO_IPV6;
396273087Sae		if (m->m_len < sizeof(struct ip6_hdr))
397273087Sae			m = m_pullup(m, sizeof(struct ip6_hdr));
398273087Sae		if (m == NULL) {
399273087Sae			error = ENOBUFS;
400273087Sae			goto err;
401273087Sae		}
402273087Sae		t = 0;
403273087Sae		ip6 = mtod(m, struct ip6_hdr *);
404273087Sae		ip6_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED:
405273087Sae		    ECN_NOCARE, &t, &ip6->ip6_flow);
406273087Sae		ecn = (ntohl(t) >> 20) & 0xff;
407273087Sae		break;
408236951Srrs#endif
409273087Sae	case AF_LINK:
410273087Sae		proto = IPPROTO_ETHERIP;
411273087Sae		M_PREPEND(m, sizeof(struct etherip_header), M_NOWAIT);
412273087Sae		if (m == NULL) {
413273087Sae			error = ENOBUFS;
414273087Sae			goto err;
415273087Sae		}
416273087Sae		eth = mtod(m, struct etherip_header *);
417273087Sae		eth->eip_resvh = 0;
418287607Shrs		eth->eip_ver = ETHERIP_VERSION;
419287607Shrs		eth->eip_resvl = 0;
420273087Sae		break;
421273087Sae	default:
422273087Sae		error = EAFNOSUPPORT;
423273087Sae		m_freem(m);
424273087Sae		goto err;
425273087Sae	}
426273087Sae	/* XXX should we check if our outer source is legal? */
427273087Sae	/* dispatch to output logic based on outer AF */
428273087Sae	switch (sc->gif_family) {
429236951Srrs#ifdef INET
430273087Sae	case AF_INET:
431273087Sae		error = in_gif_output(ifp, m, proto, ecn);
432273087Sae		break;
433236951Srrs#endif
434236951Srrs#ifdef INET6
435273087Sae	case AF_INET6:
436273087Sae		error = in6_gif_output(ifp, m, proto, ecn);
437273087Sae		break;
438236951Srrs#endif
439273087Sae	default:
440273087Sae		m_freem(m);
441153621Sthompsa	}
442273087Saeerr:
443273087Sae	if (error)
444273087Sae		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
445273087Sae	return (error);
446153621Sthompsa}
447153621Sthompsa
448273087Saestatic void
449273087Saegif_qflush(struct ifnet *ifp __unused)
450273087Sae{
451273087Sae
452273087Sae}
453273087Sae
454276901Sae#define	MTAG_GIF	1080679712
455276901Saestatic int
456276901Saegif_check_nesting(struct ifnet *ifp, struct mbuf *m)
457276901Sae{
458276901Sae	struct m_tag *mtag;
459276901Sae	int count;
460276901Sae
461276901Sae	/*
462276901Sae	 * gif may cause infinite recursion calls when misconfigured.
463276901Sae	 * We'll prevent this by detecting loops.
464276901Sae	 *
465276901Sae	 * High nesting level may cause stack exhaustion.
466276901Sae	 * We'll prevent this by introducing upper limit.
467276901Sae	 */
468276901Sae	count = 1;
469276901Sae	mtag = NULL;
470276901Sae	while ((mtag = m_tag_locate(m, MTAG_GIF, 0, mtag)) != NULL) {
471276901Sae		if (*(struct ifnet **)(mtag + 1) == ifp) {
472276903Sae			log(LOG_NOTICE, "%s: loop detected\n", if_name(ifp));
473276901Sae			return (EIO);
474276901Sae		}
475276901Sae		count++;
476276901Sae	}
477276901Sae	if (count > V_max_gif_nesting) {
478276901Sae		log(LOG_NOTICE,
479276901Sae		    "%s: if_output recursively called too many times(%d)\n",
480276901Sae		    if_name(ifp), count);
481276901Sae		return (EIO);
482276901Sae	}
483276901Sae	mtag = m_tag_alloc(MTAG_GIF, 0, sizeof(struct ifnet *), M_NOWAIT);
484276901Sae	if (mtag == NULL)
485276901Sae		return (ENOMEM);
486276901Sae	*(struct ifnet **)(mtag + 1) = ifp;
487276901Sae	m_tag_prepend(m, mtag);
488276901Sae	return (0);
489276901Sae}
490276901Sae
49154263Sshinint
492249925Sglebiusgif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
493249925Sglebius	struct route *ro)
49454263Sshin{
495273087Sae	uint32_t af;
496101182Srwatson
497249925Sglebius	if (dst->sa_family == AF_UNSPEC)
498236951Srrs		bcopy(dst->sa_data, &af, sizeof(af));
499249925Sglebius	else
500249925Sglebius		af = dst->sa_family;
501273087Sae	/*
502273087Sae	 * Now save the af in the inbound pkt csum data, this is a cheat since
503273087Sae	 * we are using the inbound csum_data field to carry the af over to
504273087Sae	 * the gif_transmit() routine, avoiding using yet another mtag.
505236951Srrs	 */
506236955Srrs	m->m_pkthdr.csum_data = af;
507273087Sae	return (ifp->if_transmit(ifp, m));
50854263Sshin}
50954263Sshin
51054263Sshinvoid
511273087Saegif_input(struct mbuf *m, struct ifnet *ifp, int proto, uint8_t ecn)
51254263Sshin{
513273087Sae	struct etherip_header *eip;
514273087Sae#ifdef INET
515273087Sae	struct ip *ip;
516273087Sae#endif
517273087Sae#ifdef INET6
518273087Sae	struct ip6_hdr *ip6;
519273087Sae	uint32_t t;
520273087Sae#endif
521198357Sbrueffer	struct gif_softc *sc;
522176879Sthompsa	struct ether_header *eh;
523176879Sthompsa	struct ifnet *oldifp;
524273087Sae	int isr, n, af;
52554263Sshin
526105338Sume	if (ifp == NULL) {
52754263Sshin		/* just in case */
52854263Sshin		m_freem(m);
52954263Sshin		return;
53054263Sshin	}
531198357Sbrueffer	sc = ifp->if_softc;
532105338Sume	m->m_pkthdr.rcvif = ifp;
533272770Sae	m_clrprotoflags(m);
534273087Sae	switch (proto) {
535273087Sae#ifdef INET
536273087Sae	case IPPROTO_IPV4:
537273087Sae		af = AF_INET;
538273087Sae		if (m->m_len < sizeof(struct ip))
539273087Sae			m = m_pullup(m, sizeof(struct ip));
540273087Sae		if (m == NULL)
541273087Sae			goto drop;
542273087Sae		ip = mtod(m, struct ip *);
543273087Sae		if (ip_ecn_egress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED:
544273087Sae		    ECN_NOCARE, &ecn, &ip->ip_tos) == 0) {
545273087Sae			m_freem(m);
546273087Sae			goto drop;
547273087Sae		}
548273087Sae		break;
549273087Sae#endif
550273087Sae#ifdef INET6
551273087Sae	case IPPROTO_IPV6:
552273087Sae		af = AF_INET6;
553273087Sae		if (m->m_len < sizeof(struct ip6_hdr))
554273087Sae			m = m_pullup(m, sizeof(struct ip6_hdr));
555273087Sae		if (m == NULL)
556273087Sae			goto drop;
557273087Sae		t = htonl((uint32_t)ecn << 20);
558273087Sae		ip6 = mtod(m, struct ip6_hdr *);
559273087Sae		if (ip6_ecn_egress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED:
560273087Sae		    ECN_NOCARE, &t, &ip6->ip6_flow) == 0) {
561273087Sae			m_freem(m);
562273087Sae			goto drop;
563273087Sae		}
564273087Sae		break;
565273087Sae#endif
566273087Sae	case IPPROTO_ETHERIP:
567273087Sae		af = AF_LINK;
568273087Sae		break;
569273087Sae	default:
570273087Sae		m_freem(m);
571273087Sae		goto drop;
572273087Sae	}
573101182Srwatson
574101182Srwatson#ifdef MAC
575172930Srwatson	mac_ifnet_create_mbuf(ifp, m);
576101182Srwatson#endif
577101182Srwatson
578159180Scsjp	if (bpf_peers_present(ifp->if_bpf)) {
579273087Sae		uint32_t af1 = af;
580123922Ssam		bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m);
58154263Sshin	}
58254263Sshin
583253261Shrs	if ((ifp->if_flags & IFF_MONITOR) != 0) {
584271867Sglebius		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
585271867Sglebius		if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
586253261Shrs		m_freem(m);
587253261Shrs		return;
588253261Shrs	}
589253261Shrs
59083998Sbrooks	if (ng_gif_input_p != NULL) {
591105338Sume		(*ng_gif_input_p)(ifp, &m, af);
59283998Sbrooks		if (m == NULL)
593273087Sae			goto drop;
59483998Sbrooks	}
59583998Sbrooks
59654263Sshin	/*
59754263Sshin	 * Put the packet to the network layer input queue according to the
59854263Sshin	 * specified address family.
59954263Sshin	 * Note: older versions of gif_input directly called network layer
60095023Ssuz	 * input functions, e.g. ip6_input, here.  We changed the policy to
60154263Sshin	 * prevent too many recursive calls of such input functions, which
60295023Ssuz	 * might cause kernel panic.  But the change may introduce another
60354263Sshin	 * problem; if the input queue is full, packets are discarded.
60495023Ssuz	 * The kernel stack overflow really happened, and we believed
60595023Ssuz	 * queue-full rarely occurs, so we changed the policy.
60654263Sshin	 */
60754263Sshin	switch (af) {
60854263Sshin#ifdef INET
60954263Sshin	case AF_INET:
61054263Sshin		isr = NETISR_IP;
61154263Sshin		break;
61254263Sshin#endif
61354263Sshin#ifdef INET6
61454263Sshin	case AF_INET6:
61554263Sshin		isr = NETISR_IPV6;
61654263Sshin		break;
61754263Sshin#endif
618153621Sthompsa	case AF_LINK:
619153621Sthompsa		n = sizeof(struct etherip_header) + sizeof(struct ether_header);
620273087Sae		if (n > m->m_len)
621153621Sthompsa			m = m_pullup(m, n);
622273087Sae		if (m == NULL)
623273087Sae			goto drop;
624153621Sthompsa		eip = mtod(m, struct etherip_header *);
625273087Sae		if (eip->eip_ver != ETHERIP_VERSION) {
626287607Shrs			/* discard unknown versions */
627287607Shrs			m_freem(m);
628287607Shrs			goto drop;
629153621Sthompsa		}
630153621Sthompsa		m_adj(m, sizeof(struct etherip_header));
631153621Sthompsa
632153621Sthompsa		m->m_flags &= ~(M_BCAST|M_MCAST);
633153621Sthompsa		m->m_pkthdr.rcvif = ifp;
634153621Sthompsa
635176879Sthompsa		if (ifp->if_bridge) {
636176879Sthompsa			oldifp = ifp;
637176879Sthompsa			eh = mtod(m, struct ether_header *);
638176879Sthompsa			if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
639176879Sthompsa				if (ETHER_IS_BROADCAST(eh->ether_dhost))
640176879Sthompsa					m->m_flags |= M_BCAST;
641176879Sthompsa				else
642176879Sthompsa					m->m_flags |= M_MCAST;
643271867Sglebius				if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1);
644176879Sthompsa			}
645153621Sthompsa			BRIDGE_INPUT(ifp, m);
646176879Sthompsa
647176879Sthompsa			if (m != NULL && ifp != oldifp) {
648176879Sthompsa				/*
649176879Sthompsa				 * The bridge gave us back itself or one of the
650176879Sthompsa				 * members for which the frame is addressed.
651176879Sthompsa				 */
652176879Sthompsa				ether_demux(ifp, m);
653176879Sthompsa				return;
654176879Sthompsa			}
655176879Sthompsa		}
656153621Sthompsa		if (m != NULL)
657153621Sthompsa			m_freem(m);
658153621Sthompsa		return;
659153621Sthompsa
66054263Sshin	default:
66183998Sbrooks		if (ng_gif_input_orphan_p != NULL)
662105338Sume			(*ng_gif_input_orphan_p)(ifp, m, af);
66383998Sbrooks		else
66483998Sbrooks			m_freem(m);
66554263Sshin		return;
66654263Sshin	}
66754263Sshin
668271867Sglebius	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
669271867Sglebius	if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
670223741Sbz	M_SETFIB(m, ifp->if_fib);
671111888Sjlemon	netisr_dispatch(isr, m);
672273087Sae	return;
673273087Saedrop:
674273087Sae	if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
67554263Sshin}
67654263Sshin
67762587Sitojun/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
67854263Sshinint
679258167Saegif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
68054263Sshin{
681273087Sae	GIF_RLOCK_TRACKER;
682273087Sae	struct ifreq *ifr = (struct ifreq*)data;
68362587Sitojun	struct sockaddr *dst, *src;
684273087Sae	struct gif_softc *sc;
685273087Sae#ifdef INET
686273087Sae	struct sockaddr_in *sin = NULL;
687105339Sume#endif
688273087Sae#ifdef INET6
689273087Sae	struct sockaddr_in6 *sin6 = NULL;
690273087Sae#endif
691273087Sae	u_int options;
692273087Sae	int error;
693105339Sume
69454263Sshin	switch (cmd) {
69554263Sshin	case SIOCSIFADDR:
696105293Sume		ifp->if_flags |= IFF_UP;
69754263Sshin	case SIOCADDMULTI:
69854263Sshin	case SIOCDELMULTI:
69954263Sshin	case SIOCGIFMTU:
700273087Sae	case SIOCSIFFLAGS:
701273087Sae		return (0);
70254263Sshin	case SIOCSIFMTU:
703273087Sae		if (ifr->ifr_mtu < GIF_MTU_MIN ||
704273087Sae		    ifr->ifr_mtu > GIF_MTU_MAX)
705105339Sume			return (EINVAL);
706273087Sae		else
707273087Sae			ifp->if_mtu = ifr->ifr_mtu;
708273087Sae		return (0);
709273087Sae	}
710273087Sae	sx_xlock(&gif_ioctl_sx);
711273087Sae	sc = ifp->if_softc;
712273087Sae	if (sc == NULL) {
713273087Sae		error = ENXIO;
714273087Sae		goto bad;
715273087Sae	}
716273087Sae	error = 0;
717273087Sae	switch (cmd) {
71854263Sshin	case SIOCSIFPHYADDR:
719273091Sae#ifdef INET6
72054263Sshin	case SIOCSIFPHYADDR_IN6:
721273091Sae#endif
722273087Sae		error = EINVAL;
72362587Sitojun		switch (cmd) {
72478064Sume#ifdef INET
72562587Sitojun		case SIOCSIFPHYADDR:
72654263Sshin			src = (struct sockaddr *)
72754263Sshin				&(((struct in_aliasreq *)data)->ifra_addr);
72854263Sshin			dst = (struct sockaddr *)
72954263Sshin				&(((struct in_aliasreq *)data)->ifra_dstaddr);
73062587Sitojun			break;
73178064Sume#endif
73262587Sitojun#ifdef INET6
73362587Sitojun		case SIOCSIFPHYADDR_IN6:
73462587Sitojun			src = (struct sockaddr *)
73562587Sitojun				&(((struct in6_aliasreq *)data)->ifra_addr);
73662587Sitojun			dst = (struct sockaddr *)
73762587Sitojun				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
73862587Sitojun			break;
73962587Sitojun#endif
74091327Sbrooks		default:
741273087Sae			goto bad;
74262587Sitojun		}
74378064Sume		/* sa_family must be equal */
744273087Sae		if (src->sa_family != dst->sa_family ||
745273087Sae		    src->sa_len != dst->sa_len)
746273087Sae			goto bad;
74778064Sume
74878064Sume		/* validate sa_len */
749287607Shrs		/* check sa_family looks sane for the cmd */
75078064Sume		switch (src->sa_family) {
75178064Sume#ifdef INET
75278064Sume		case AF_INET:
75378064Sume			if (src->sa_len != sizeof(struct sockaddr_in))
754273087Sae				goto bad;
755287607Shrs			if (cmd != SIOCSIFPHYADDR) {
756287607Shrs				error = EAFNOSUPPORT;
757287607Shrs				goto bad;
758287607Shrs			}
759287607Shrs			if (satosin(src)->sin_addr.s_addr == INADDR_ANY ||
760287607Shrs			    satosin(dst)->sin_addr.s_addr == INADDR_ANY) {
761287607Shrs				error = EADDRNOTAVAIL;
762287607Shrs				goto bad;
763287607Shrs			}
76478064Sume			break;
76578064Sume#endif
76678064Sume#ifdef INET6
76778064Sume		case AF_INET6:
76878064Sume			if (src->sa_len != sizeof(struct sockaddr_in6))
769273087Sae				goto bad;
770287607Shrs			if (cmd != SIOCSIFPHYADDR_IN6) {
771287607Shrs				error = EAFNOSUPPORT;
772273087Sae				goto bad;
773287607Shrs			}
774287607Shrs			error = EADDRNOTAVAIL;
775273087Sae			if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(src)->sin6_addr)
776273087Sae			    ||
777273087Sae			    IN6_IS_ADDR_UNSPECIFIED(&satosin6(dst)->sin6_addr))
778273087Sae				goto bad;
779273087Sae			/*
780273087Sae			 * Check validity of the scope zone ID of the
781273087Sae			 * addresses, and convert it into the kernel
782273087Sae			 * internal form if necessary.
783273087Sae			 */
784273087Sae			error = sa6_embedscope(satosin6(src), 0);
785273087Sae			if (error != 0)
786273087Sae				goto bad;
787273087Sae			error = sa6_embedscope(satosin6(dst), 0);
788273087Sae			if (error != 0)
789273087Sae				goto bad;
790287607Shrs			break;
791273087Sae#endif
792287607Shrs		default:
793287607Shrs			error = EAFNOSUPPORT;
794287607Shrs			goto bad;
795287607Shrs		}
796273087Sae		error = gif_set_tunnel(ifp, src, dst);
79762587Sitojun		break;
79862587Sitojun	case SIOCDIFPHYADDR:
799273087Sae		gif_delete_tunnel(ifp);
80054263Sshin		break;
80154263Sshin	case SIOCGIFPSRCADDR:
802273087Sae	case SIOCGIFPDSTADDR:
803273091Sae#ifdef INET6
80454263Sshin	case SIOCGIFPSRCADDR_IN6:
805273087Sae	case SIOCGIFPDSTADDR_IN6:
806273091Sae#endif
807273087Sae		if (sc->gif_family == 0) {
80854263Sshin			error = EADDRNOTAVAIL;
809273087Sae			break;
81054263Sshin		}
811273087Sae		GIF_RLOCK(sc);
81278064Sume		switch (cmd) {
81354263Sshin#ifdef INET
81478064Sume		case SIOCGIFPSRCADDR:
815273087Sae		case SIOCGIFPDSTADDR:
816273087Sae			if (sc->gif_family != AF_INET) {
817273087Sae				error = EADDRNOTAVAIL;
818273087Sae				break;
819273087Sae			}
820273087Sae			sin = (struct sockaddr_in *)&ifr->ifr_addr;
821273087Sae			memset(sin, 0, sizeof(*sin));
822273087Sae			sin->sin_family = AF_INET;
823273087Sae			sin->sin_len = sizeof(*sin);
82454263Sshin			break;
825273087Sae#endif
82654263Sshin#ifdef INET6
82778064Sume		case SIOCGIFPSRCADDR_IN6:
828273087Sae		case SIOCGIFPDSTADDR_IN6:
829273087Sae			if (sc->gif_family != AF_INET6) {
830273087Sae				error = EADDRNOTAVAIL;
831273087Sae				break;
832273087Sae			}
833273087Sae			sin6 = (struct sockaddr_in6 *)
83454263Sshin				&(((struct in6_ifreq *)data)->ifr_addr);
835273087Sae			memset(sin6, 0, sizeof(*sin6));
836273087Sae			sin6->sin6_family = AF_INET6;
837273087Sae			sin6->sin6_len = sizeof(*sin6);
83854263Sshin			break;
839273087Sae#endif
84054263Sshin		default:
841273087Sae			error = EAFNOSUPPORT;
84254263Sshin		}
843273087Sae		if (error == 0) {
844273087Sae			switch (cmd) {
845273087Sae#ifdef INET
846273087Sae			case SIOCGIFPSRCADDR:
847273087Sae				sin->sin_addr = sc->gif_iphdr->ip_src;
848273087Sae				break;
849273087Sae			case SIOCGIFPDSTADDR:
850273087Sae				sin->sin_addr = sc->gif_iphdr->ip_dst;
851273087Sae				break;
852273087Sae#endif
853148385Sume#ifdef INET6
854273087Sae			case SIOCGIFPSRCADDR_IN6:
855273087Sae				sin6->sin6_addr = sc->gif_ip6hdr->ip6_src;
856273087Sae				break;
857273087Sae			case SIOCGIFPDSTADDR_IN6:
858273087Sae				sin6->sin6_addr = sc->gif_ip6hdr->ip6_dst;
859273087Sae				break;
860148385Sume#endif
861273087Sae			}
86254263Sshin		}
863273087Sae		GIF_RUNLOCK(sc);
864273087Sae		if (error != 0)
865273087Sae			break;
86678064Sume		switch (cmd) {
86754263Sshin#ifdef INET
868273087Sae		case SIOCGIFPSRCADDR:
86978064Sume		case SIOCGIFPDSTADDR:
870273087Sae			error = prison_if(curthread->td_ucred,
871273087Sae			    (struct sockaddr *)sin);
872273087Sae			if (error != 0)
873273087Sae				memset(sin, 0, sizeof(*sin));
87454263Sshin			break;
875273087Sae#endif
87654263Sshin#ifdef INET6
877273087Sae		case SIOCGIFPSRCADDR_IN6:
87878064Sume		case SIOCGIFPDSTADDR_IN6:
879273087Sae			error = prison_if(curthread->td_ucred,
880273087Sae			    (struct sockaddr *)sin6);
881273087Sae			if (error == 0)
882273087Sae				error = sa6_recoverscope(sin6);
883148385Sume			if (error != 0)
884273087Sae				memset(sin6, 0, sizeof(*sin6));
885273090Sae#endif
886148385Sume		}
88754263Sshin		break;
888282809Sae	case SIOCGTUNFIB:
889282809Sae		ifr->ifr_fib = sc->gif_fibnum;
890282809Sae		break;
891282809Sae	case SIOCSTUNFIB:
892282809Sae		if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0)
893282809Sae			break;
894282809Sae		if (ifr->ifr_fib >= rt_numfibs)
895282809Sae			error = EINVAL;
896282809Sae		else
897282809Sae			sc->gif_fibnum = ifr->ifr_fib;
898282809Sae		break;
899193664Shrs	case GIFGOPTS:
900193664Shrs		options = sc->gif_options;
901332288Sbrooks		error = copyout(&options, ifr_data_get_ptr(ifr),
902332288Sbrooks		    sizeof(options));
903193664Shrs		break;
904193664Shrs	case GIFSOPTS:
905193664Shrs		if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0)
906193664Shrs			break;
907332288Sbrooks		error = copyin(ifr_data_get_ptr(ifr), &options,
908332288Sbrooks		    sizeof(options));
909193815Shrs		if (error)
910193815Shrs			break;
911193815Shrs		if (options & ~GIF_OPTMASK)
912193815Shrs			error = EINVAL;
913193815Shrs		else
914193815Shrs			sc->gif_options = options;
915193664Shrs		break;
91654263Sshin	default:
91754263Sshin		error = EINVAL;
91854263Sshin		break;
91954263Sshin	}
920273087Saebad:
921273087Sae	sx_xunlock(&gif_ioctl_sx);
922273087Sae	return (error);
92354263Sshin}
92479106Sbrooks
925273087Saestatic void
926273087Saegif_detach(struct gif_softc *sc)
927105293Sume{
928105293Sume
929273087Sae	sx_assert(&gif_ioctl_sx, SA_XLOCKED);
930273087Sae	if (sc->gif_ecookie != NULL)
931273087Sae		encap_detach(sc->gif_ecookie);
932273087Sae	sc->gif_ecookie = NULL;
933273087Sae}
934105293Sume
935273087Saestatic int
936273087Saegif_attach(struct gif_softc *sc, int af)
937273087Sae{
938105293Sume
939273087Sae	sx_assert(&gif_ioctl_sx, SA_XLOCKED);
940273087Sae	switch (af) {
941273087Sae#ifdef INET
942273087Sae	case AF_INET:
943273087Sae		return (in_gif_attach(sc));
944273087Sae#endif
945273087Sae#ifdef INET6
946273087Sae	case AF_INET6:
947273087Sae		return (in6_gif_attach(sc));
948273087Sae#endif
949105293Sume	}
950273087Sae	return (EAFNOSUPPORT);
951273087Sae}
952105293Sume
953273087Saestatic int
954273087Saegif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
955273087Sae{
956273087Sae	struct gif_softc *sc = ifp->if_softc;
957273087Sae	struct gif_softc *tsc;
958105293Sume#ifdef INET
959273087Sae	struct ip *ip;
960105293Sume#endif
961105293Sume#ifdef INET6
962273087Sae	struct ip6_hdr *ip6;
963105293Sume#endif
964273087Sae	void *hdr;
965273087Sae	int error = 0;
966105293Sume
967273087Sae	if (sc == NULL)
968273087Sae		return (ENXIO);
969273087Sae	/* Disallow parallel tunnels unless instructed otherwise. */
970273087Sae	if (V_parallel_tunnels == 0) {
971273087Sae		GIF_LIST_LOCK();
972273087Sae		LIST_FOREACH(tsc, &V_gif_softc_list, gif_list) {
973273087Sae			if (tsc == sc || tsc->gif_family != src->sa_family)
974273087Sae				continue;
975105293Sume#ifdef INET
976273087Sae			if (tsc->gif_family == AF_INET &&
977273087Sae			    tsc->gif_iphdr->ip_src.s_addr ==
978273087Sae			    satosin(src)->sin_addr.s_addr &&
979273087Sae			    tsc->gif_iphdr->ip_dst.s_addr ==
980273087Sae			    satosin(dst)->sin_addr.s_addr) {
981273087Sae				error = EADDRNOTAVAIL;
982273087Sae				GIF_LIST_UNLOCK();
983273087Sae				goto bad;
984273087Sae			}
985273087Sae#endif
986273087Sae#ifdef INET6
987273087Sae			if (tsc->gif_family == AF_INET6 &&
988273087Sae			    IN6_ARE_ADDR_EQUAL(&tsc->gif_ip6hdr->ip6_src,
989273087Sae			    &satosin6(src)->sin6_addr) &&
990273087Sae			    IN6_ARE_ADDR_EQUAL(&tsc->gif_ip6hdr->ip6_dst,
991273087Sae			    &satosin6(dst)->sin6_addr)) {
992273087Sae				error = EADDRNOTAVAIL;
993273087Sae				GIF_LIST_UNLOCK();
994273087Sae				goto bad;
995273087Sae			}
996273087Sae#endif
997273087Sae		}
998273087Sae		GIF_LIST_UNLOCK();
999273087Sae	}
1000273087Sae	switch (src->sa_family) {
1001273087Sae#ifdef INET
1002105293Sume	case AF_INET:
1003273087Sae		hdr = ip = malloc(sizeof(struct ip), M_GIF,
1004273087Sae		    M_WAITOK | M_ZERO);
1005273087Sae		ip->ip_src.s_addr = satosin(src)->sin_addr.s_addr;
1006273087Sae		ip->ip_dst.s_addr = satosin(dst)->sin_addr.s_addr;
1007105293Sume		break;
1008105293Sume#endif
1009105293Sume#ifdef INET6
1010105293Sume	case AF_INET6:
1011273087Sae		hdr = ip6 = malloc(sizeof(struct ip6_hdr), M_GIF,
1012273087Sae		    M_WAITOK | M_ZERO);
1013273087Sae		ip6->ip6_src = satosin6(src)->sin6_addr;
1014273087Sae		ip6->ip6_dst = satosin6(dst)->sin6_addr;
1015273087Sae		ip6->ip6_vfc = IPV6_VERSION;
1016105293Sume		break;
1017105293Sume#endif
1018273087Sae	default:
1019273087Sae		return (EAFNOSUPPORT);
1020297793Spfg	}
1021105293Sume
1022273087Sae	if (sc->gif_family != src->sa_family)
1023273087Sae		gif_detach(sc);
1024273087Sae	if (sc->gif_family == 0 ||
1025273087Sae	    sc->gif_family != src->sa_family)
1026273087Sae		error = gif_attach(sc, src->sa_family);
1027105293Sume
1028273087Sae	GIF_WLOCK(sc);
1029273087Sae	if (sc->gif_family != 0)
1030273087Sae		free(sc->gif_hdr, M_GIF);
1031273087Sae	sc->gif_family = src->sa_family;
1032273087Sae	sc->gif_hdr = hdr;
1033273087Sae	GIF_WUNLOCK(sc);
1034273091Sae#if defined(INET) || defined(INET6)
1035273087Saebad:
1036273091Sae#endif
1037288575Shrs	if (error == 0 && sc->gif_family != 0) {
1038148887Srwatson		ifp->if_drv_flags |= IFF_DRV_RUNNING;
1039288575Shrs		if_link_state_change(ifp, LINK_STATE_UP);
1040288575Shrs	} else {
1041148887Srwatson		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1042288575Shrs		if_link_state_change(ifp, LINK_STATE_DOWN);
1043288575Shrs	}
1044273087Sae	return (error);
1045105293Sume}
1046105293Sume
1047273087Saestatic void
1048258167Saegif_delete_tunnel(struct ifnet *ifp)
104979106Sbrooks{
1050147256Sbrooks	struct gif_softc *sc = ifp->if_softc;
1051273087Sae	int family;
105279106Sbrooks
1053273087Sae	if (sc == NULL)
1054273087Sae		return;
1055273087Sae
1056273087Sae	GIF_WLOCK(sc);
1057273087Sae	family = sc->gif_family;
1058273087Sae	sc->gif_family = 0;
1059273087Sae	GIF_WUNLOCK(sc);
1060273087Sae	if (family != 0) {
1061273087Sae		gif_detach(sc);
1062273087Sae		free(sc->gif_hdr, M_GIF);
106379106Sbrooks	}
1064160018Syar	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1065288575Shrs	if_link_state_change(ifp, LINK_STATE_DOWN);
106679106Sbrooks}
1067