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.
28276149Sae *
29276149Sae *	$KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $
3054263Sshin */
3154263Sshin
32276149Sae#include <sys/cdefs.h>
33276149Sae__FBSDID("$FreeBSD$");
34276149Sae
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>
42276149Sae#include <sys/lock.h>
4354263Sshin#include <sys/malloc.h>
4454263Sshin#include <sys/mbuf.h>
45129880Sphk#include <sys/module.h>
46276149Sae#include <sys/rmlock.h>
4754263Sshin#include <sys/socket.h>
4854263Sshin#include <sys/sockio.h>
49276149Sae#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>
61276149Sae#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>
72276149Sae#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>
84276149Sae#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/*
100276068Sae * gif_mtx protects a per-vnet gif_softc_list.
101127305Srwatson */
102276068Saestatic VNET_DEFINE(struct mtx, gif_mtx);
103276068Sae#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)
107276149Saestatic struct sx gif_ioctl_sx;
108276149SaeSX_SYSINIT(gif_ioctl_sx, &gif_ioctl_sx, "gif_ioctl");
109195699Srwatson
110276068Sae#define	GIF_LIST_LOCK_INIT(x)		mtx_init(&V_gif_mtx, "gif_mtx", \
111276068Sae					    NULL, MTX_DEF)
112276068Sae#define	GIF_LIST_LOCK_DESTROY(x)	mtx_destroy(&V_gif_mtx)
113276068Sae#define	GIF_LIST_LOCK(x)		mtx_lock(&V_gif_mtx)
114276068Sae#define	GIF_LIST_UNLOCK(x)		mtx_unlock(&V_gif_mtx)
115276068Sae
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
121277297Saestatic int	gif_check_nesting(struct ifnet *, struct mbuf *);
122276149Saestatic int	gif_set_tunnel(struct ifnet *, struct sockaddr *,
123276149Sae    struct sockaddr *);
124276149Saestatic void	gif_delete_tunnel(struct ifnet *);
125276149Saestatic int	gif_ioctl(struct ifnet *, u_long, caddr_t);
126276149Saestatic int	gif_transmit(struct ifnet *, struct mbuf *);
127276149Saestatic void	gif_qflush(struct ifnet *);
128160195Ssamstatic int	gif_clone_create(struct if_clone *, int, caddr_t);
129128209Sbrooksstatic void	gif_clone_destroy(struct ifnet *);
130276068Saestatic VNET_DEFINE(struct if_clone *, gif_cloner);
131276068Sae#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)
151195699SrwatsonSYSCTL_VNET_INT(_net_link_gif, OID_AUTO, max_nesting, 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)
165195699SrwatsonSYSCTL_VNET_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW,
166195699Srwatson    &VNET_NAME(parallel_tunnels), 0, "Allow parallel tunnels?");
16791270Sbrooks
168176879Sthompsa/* copy from src/sys/net/if_ethersubr.c */
169176879Sthompsastatic const u_char etherbroadcastaddr[ETHER_ADDR_LEN] =
170176879Sthompsa			{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
171176879Sthompsa#ifndef ETHER_IS_BROADCAST
172176879Sthompsa#define ETHER_IS_BROADCAST(addr) \
173176879Sthompsa	(bcmp(etherbroadcastaddr, (addr), ETHER_ADDR_LEN) == 0)
174176879Sthompsa#endif
175176879Sthompsa
176128209Sbrooksstatic int
177276067Saegif_clone_create(struct if_clone *ifc, int unit, caddr_t params)
17854263Sshin{
17978064Sume	struct gif_softc *sc;
18054263Sshin
181131672Sbms	sc = malloc(sizeof(struct gif_softc), M_GIF, M_WAITOK | M_ZERO);
182178888Sjulian	sc->gif_fibnum = curthread->td_proc->p_fibnum;
183147256Sbrooks	GIF2IFP(sc) = if_alloc(IFT_GIF);
184155037Sglebius	GIF_LOCK_INIT(sc);
185147256Sbrooks	GIF2IFP(sc)->if_softc = sc;
186241610Sglebius	if_initname(GIF2IFP(sc), gifname, unit);
18779106Sbrooks
188147256Sbrooks	GIF2IFP(sc)->if_addrlen = 0;
189147256Sbrooks	GIF2IFP(sc)->if_mtu    = GIF_MTU;
190147256Sbrooks	GIF2IFP(sc)->if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
19178064Sume#if 0
19279106Sbrooks	/* turn off ingress filter */
193147256Sbrooks	GIF2IFP(sc)->if_flags  |= IFF_LINK2;
19478064Sume#endif
195147256Sbrooks	GIF2IFP(sc)->if_ioctl  = gif_ioctl;
196276149Sae	GIF2IFP(sc)->if_transmit  = gif_transmit;
197276149Sae	GIF2IFP(sc)->if_qflush  = gif_qflush;
198147256Sbrooks	GIF2IFP(sc)->if_output = gif_output;
199290347Shrs	GIF2IFP(sc)->if_capabilities |= IFCAP_LINKSTATE;
200290347Shrs	GIF2IFP(sc)->if_capenable |= IFCAP_LINKSTATE;
201147256Sbrooks	if_attach(GIF2IFP(sc));
202147611Sdwmalone	bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int32_t));
20383998Sbrooks	if (ng_gif_attach_p != NULL)
204147256Sbrooks		(*ng_gif_attach_p)(GIF2IFP(sc));
205155037Sglebius
206276068Sae	GIF_LIST_LOCK();
207181803Sbz	LIST_INSERT_HEAD(&V_gif_softc_list, sc, gif_list);
208276068Sae	GIF_LIST_UNLOCK();
209155037Sglebius	return (0);
21079106Sbrooks}
21179106Sbrooks
212127305Srwatsonstatic void
213276067Saegif_clone_destroy(struct ifnet *ifp)
21479106Sbrooks{
215276149Sae	struct gif_softc *sc;
21679106Sbrooks
217276149Sae	sx_xlock(&gif_ioctl_sx);
218276149Sae	sc = ifp->if_softc;
219276149Sae	gif_delete_tunnel(ifp);
220276068Sae	GIF_LIST_LOCK();
221151266Sthompsa	LIST_REMOVE(sc, gif_list);
222276068Sae	GIF_LIST_UNLOCK();
22383998Sbrooks	if (ng_gif_detach_p != NULL)
22483998Sbrooks		(*ng_gif_detach_p)(ifp);
22579106Sbrooks	bpfdetach(ifp);
22679106Sbrooks	if_detach(ifp);
227276149Sae	ifp->if_softc = NULL;
228276149Sae	sx_xunlock(&gif_ioctl_sx);
229276149Sae
230147256Sbrooks	if_free(ifp);
231155037Sglebius	GIF_LOCK_DESTROY(sc);
23279106Sbrooks	free(sc, M_GIF);
23379106Sbrooks}
23479106Sbrooks
235195837Srwatsonstatic void
236195837Srwatsonvnet_gif_init(const void *unused __unused)
237190787Szec{
238190787Szec
239190787Szec	LIST_INIT(&V_gif_softc_list);
240276068Sae	GIF_LIST_LOCK_INIT();
241276068Sae	V_gif_cloner = if_clone_simple(gifname, gif_clone_create,
242276068Sae	    gif_clone_destroy, 0);
243190787Szec}
244276068SaeVNET_SYSINIT(vnet_gif_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
245276068Sae    vnet_gif_init, NULL);
246190787Szec
247276068Saestatic void
248276068Saevnet_gif_uninit(const void *unused __unused)
249276068Sae{
250276068Sae
251276068Sae	if_clone_detach(V_gif_cloner);
252276068Sae	GIF_LIST_LOCK_DESTROY();
253276068Sae}
254276068SaeVNET_SYSUNINIT(vnet_gif_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
255276068Sae    vnet_gif_uninit, NULL);
256276068Sae
257190787Szecstatic int
258276067Saegifmodevent(module_t mod, int type, void *data)
25979106Sbrooks{
26079106Sbrooks
26179106Sbrooks	switch (type) {
26279106Sbrooks	case MOD_LOAD:
26379106Sbrooks	case MOD_UNLOAD:
26479106Sbrooks		break;
265132199Sphk	default:
266276068Sae		return (EOPNOTSUPP);
26754263Sshin	}
268276068Sae	return (0);
26954263Sshin}
27054263Sshin
27179106Sbrooksstatic moduledata_t gif_mod = {
27279106Sbrooks	"if_gif",
27379106Sbrooks	gifmodevent,
274241394Skevlo	0
27579106Sbrooks};
27654263Sshin
27779106SbrooksDECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
27883997SbrooksMODULE_VERSION(if_gif, 1);
27979106Sbrooks
280105293Sumeint
281276067Saegif_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
28262587Sitojun{
283276149Sae	GIF_RLOCK_TRACKER;
28462587Sitojun	struct gif_softc *sc;
285276149Sae	int ret;
286276149Sae	uint8_t ver;
28762587Sitojun
28862587Sitojun	sc = (struct gif_softc *)arg;
289276149Sae	if (sc == NULL || (GIF2IFP(sc)->if_flags & IFF_UP) == 0)
290276149Sae		return (0);
29162587Sitojun
292276149Sae	ret = 0;
293276149Sae	GIF_RLOCK(sc);
29462587Sitojun
29562587Sitojun	/* no physical address */
296276149Sae	if (sc->gif_family == 0)
297276149Sae		goto done;
29862587Sitojun
29962587Sitojun	switch (proto) {
30062587Sitojun#ifdef INET
30162587Sitojun	case IPPROTO_IPV4:
30262587Sitojun#endif
30362587Sitojun#ifdef INET6
30462587Sitojun	case IPPROTO_IPV6:
30562587Sitojun#endif
306153621Sthompsa	case IPPROTO_ETHERIP:
307153621Sthompsa		break;
30862587Sitojun	default:
309276149Sae		goto done;
31062587Sitojun	}
31162587Sitojun
312105339Sume	/* Bail on short packets */
313276149Sae	if (m->m_pkthdr.len < sizeof(struct ip))
314276149Sae		goto done;
315105339Sume
316276149Sae	m_copydata(m, 0, 1, &ver);
317276149Sae	switch (ver >> 4) {
31862587Sitojun#ifdef INET
31962587Sitojun	case 4:
320276149Sae		if (sc->gif_family != AF_INET)
321276149Sae			goto done;
322276149Sae		ret = in_gif_encapcheck(m, off, proto, arg);
323276149Sae		break;
32462587Sitojun#endif
32562587Sitojun#ifdef INET6
32662587Sitojun	case 6:
327105293Sume		if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
328276149Sae			goto done;
329276149Sae		if (sc->gif_family != AF_INET6)
330276149Sae			goto done;
331276149Sae		ret = in6_gif_encapcheck(m, off, proto, arg);
332276149Sae		break;
33362587Sitojun#endif
33462587Sitojun	}
335276149Saedone:
336276149Sae	GIF_RUNLOCK(sc);
337276149Sae	return (ret);
33862587Sitojun}
339276149Sae
340276149Saestatic int
341276149Saegif_transmit(struct ifnet *ifp, struct mbuf *m)
342276149Sae{
343276149Sae	struct gif_softc *sc;
344276149Sae	struct etherip_header *eth;
345236951Srrs#ifdef INET
346276149Sae	struct ip *ip;
347236951Srrs#endif
348236951Srrs#ifdef INET6
349276149Sae	struct ip6_hdr *ip6;
350276149Sae	uint32_t t;
351236951Srrs#endif
352236951Srrs	uint32_t af;
353276149Sae	uint8_t proto, ecn;
354276149Sae	int error;
355153621Sthompsa
356277297Sae#ifdef MAC
357277297Sae	error = mac_ifnet_check_transmit(ifp, m);
358277297Sae	if (error) {
359277297Sae		m_freem(m);
360277297Sae		goto err;
361277297Sae	}
362277297Sae#endif
363276149Sae	error = ENETDOWN;
364153621Sthompsa	sc = ifp->if_softc;
365277297Sae	if ((ifp->if_flags & IFF_MONITOR) != 0 ||
366277297Sae	    (ifp->if_flags & IFF_UP) == 0 ||
367277297Sae	    sc->gif_family == 0 ||
368277297Sae	    (error = gif_check_nesting(ifp, m)) != 0) {
369276149Sae		m_freem(m);
370276149Sae		goto err;
371276149Sae	}
372276149Sae	/* Now pull back the af that we stashed in the csum_data. */
373277297Sae	if (ifp->if_bridge)
374277297Sae		af = AF_LINK;
375277297Sae	else
376277297Sae		af = m->m_pkthdr.csum_data;
377277297Sae	m->m_flags &= ~(M_BCAST|M_MCAST);
378277297Sae	M_SETFIB(m, sc->gif_fibnum);
379276149Sae	BPF_MTAP2(ifp, &af, sizeof(af), m);
380276149Sae	if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
381276149Sae	if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
382276149Sae	/* inner AF-specific encapsulation */
383276149Sae	ecn = 0;
384276149Sae	switch (af) {
385236951Srrs#ifdef INET
386276149Sae	case AF_INET:
387276149Sae		proto = IPPROTO_IPV4;
388276149Sae		if (m->m_len < sizeof(struct ip))
389276149Sae			m = m_pullup(m, sizeof(struct ip));
390276149Sae		if (m == NULL) {
391276149Sae			error = ENOBUFS;
392276149Sae			goto err;
393276149Sae		}
394276149Sae		ip = mtod(m, struct ip *);
395276149Sae		ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED:
396276149Sae		    ECN_NOCARE, &ecn, &ip->ip_tos);
397276149Sae		break;
398236951Srrs#endif
399236951Srrs#ifdef INET6
400276149Sae	case AF_INET6:
401276149Sae		proto = IPPROTO_IPV6;
402276149Sae		if (m->m_len < sizeof(struct ip6_hdr))
403276149Sae			m = m_pullup(m, sizeof(struct ip6_hdr));
404276149Sae		if (m == NULL) {
405276149Sae			error = ENOBUFS;
406276149Sae			goto err;
407276149Sae		}
408276149Sae		t = 0;
409276149Sae		ip6 = mtod(m, struct ip6_hdr *);
410276149Sae		ip6_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED:
411276149Sae		    ECN_NOCARE, &t, &ip6->ip6_flow);
412276149Sae		ecn = (ntohl(t) >> 20) & 0xff;
413276149Sae		break;
414236951Srrs#endif
415276149Sae	case AF_LINK:
416276149Sae		proto = IPPROTO_ETHERIP;
417276149Sae		M_PREPEND(m, sizeof(struct etherip_header), M_NOWAIT);
418276149Sae		if (m == NULL) {
419276149Sae			error = ENOBUFS;
420276149Sae			goto err;
421276149Sae		}
422276149Sae		eth = mtod(m, struct etherip_header *);
423276149Sae		eth->eip_resvh = 0;
424287730Shrs		eth->eip_ver = ETHERIP_VERSION;
425287730Shrs		eth->eip_resvl = 0;
426276149Sae		break;
427276149Sae	default:
428276149Sae		error = EAFNOSUPPORT;
429276149Sae		m_freem(m);
430276149Sae		goto err;
431276149Sae	}
432276149Sae	/* XXX should we check if our outer source is legal? */
433276149Sae	/* dispatch to output logic based on outer AF */
434276149Sae	switch (sc->gif_family) {
435236951Srrs#ifdef INET
436276149Sae	case AF_INET:
437276149Sae		error = in_gif_output(ifp, m, proto, ecn);
438276149Sae		break;
439236951Srrs#endif
440236951Srrs#ifdef INET6
441276149Sae	case AF_INET6:
442276149Sae		error = in6_gif_output(ifp, m, proto, ecn);
443276149Sae		break;
444236951Srrs#endif
445276149Sae	default:
446276149Sae		m_freem(m);
447153621Sthompsa	}
448276149Saeerr:
449276149Sae	if (error)
450276149Sae		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
451276149Sae	return (error);
452153621Sthompsa}
453153621Sthompsa
454276149Saestatic void
455276149Saegif_qflush(struct ifnet *ifp __unused)
456276149Sae{
457276149Sae
458276149Sae}
459276149Sae
460277297Sae#define	MTAG_GIF	1080679712
461277297Saestatic int
462277297Saegif_check_nesting(struct ifnet *ifp, struct mbuf *m)
46354263Sshin{
464127898Sru	struct m_tag *mtag;
465277297Sae	int count;
466101182Srwatson
46754263Sshin	/*
46854263Sshin	 * gif may cause infinite recursion calls when misconfigured.
469127898Sru	 * We'll prevent this by detecting loops.
470127898Sru	 *
471127898Sru	 * High nesting level may cause stack exhaustion.
47254263Sshin	 * We'll prevent this by introducing upper limit.
47354263Sshin	 */
474277297Sae	count = 1;
475277297Sae	mtag = NULL;
476277297Sae	while ((mtag = m_tag_locate(m, MTAG_GIF, 0, mtag)) != NULL) {
477127898Sru		if (*(struct ifnet **)(mtag + 1) == ifp) {
478277297Sae			log(LOG_NOTICE, "%s: loop detected\n", ifp->if_xname);
479277297Sae			return (EIO);
480127898Sru		}
481277297Sae		count++;
482127898Sru	}
483277297Sae	if (count > V_max_gif_nesting) {
48454263Sshin		log(LOG_NOTICE,
485277297Sae		    "%s: if_output recursively called too many times(%d)\n",
486277297Sae		    if_name(ifp), count);
487277297Sae		return (EIO);
48854263Sshin	}
489277297Sae	mtag = m_tag_alloc(MTAG_GIF, 0, sizeof(struct ifnet *), M_NOWAIT);
490277297Sae	if (mtag == NULL)
491277297Sae		return (ENOMEM);
492127898Sru	*(struct ifnet **)(mtag + 1) = ifp;
493127898Sru	m_tag_prepend(m, mtag);
494277297Sae	return (0);
495277297Sae}
49662587Sitojun
497277297Saeint
498277297Saegif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
499277297Sae	struct route *ro)
500277297Sae{
501277297Sae	uint32_t af;
502277297Sae
503249925Sglebius	if (dst->sa_family == AF_UNSPEC)
504236951Srrs		bcopy(dst->sa_data, &af, sizeof(af));
505249925Sglebius	else
506249925Sglebius		af = dst->sa_family;
507276149Sae	/*
508276149Sae	 * Now save the af in the inbound pkt csum data, this is a cheat since
509276149Sae	 * we are using the inbound csum_data field to carry the af over to
510276149Sae	 * the gif_transmit() routine, avoiding using yet another mtag.
511236951Srrs	 */
512236955Srrs	m->m_pkthdr.csum_data = af;
513276149Sae	return (ifp->if_transmit(ifp, m));
51454263Sshin}
51554263Sshin
51654263Sshinvoid
517276149Saegif_input(struct mbuf *m, struct ifnet *ifp, int proto, uint8_t ecn)
51854263Sshin{
519276149Sae	struct etherip_header *eip;
520276149Sae#ifdef INET
521276149Sae	struct ip *ip;
522276149Sae#endif
523276149Sae#ifdef INET6
524276149Sae	struct ip6_hdr *ip6;
525276149Sae	uint32_t t;
526276149Sae#endif
527198357Sbrueffer	struct gif_softc *sc;
528176879Sthompsa	struct ether_header *eh;
529176879Sthompsa	struct ifnet *oldifp;
530276149Sae	int isr, n, af;
53154263Sshin
532105338Sume	if (ifp == NULL) {
53354263Sshin		/* just in case */
53454263Sshin		m_freem(m);
53554263Sshin		return;
53654263Sshin	}
537198357Sbrueffer	sc = ifp->if_softc;
538105338Sume	m->m_pkthdr.rcvif = ifp;
539273859Sae	m_clrprotoflags(m);
540276149Sae	switch (proto) {
541276149Sae#ifdef INET
542276149Sae	case IPPROTO_IPV4:
543276149Sae		af = AF_INET;
544276149Sae		if (m->m_len < sizeof(struct ip))
545276149Sae			m = m_pullup(m, sizeof(struct ip));
546276149Sae		if (m == NULL)
547276149Sae			goto drop;
548276149Sae		ip = mtod(m, struct ip *);
549276149Sae		if (ip_ecn_egress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED:
550276149Sae		    ECN_NOCARE, &ecn, &ip->ip_tos) == 0) {
551276149Sae			m_freem(m);
552276149Sae			goto drop;
553276149Sae		}
554276149Sae		break;
555276149Sae#endif
556276149Sae#ifdef INET6
557276149Sae	case IPPROTO_IPV6:
558276149Sae		af = AF_INET6;
559276149Sae		if (m->m_len < sizeof(struct ip6_hdr))
560276149Sae			m = m_pullup(m, sizeof(struct ip6_hdr));
561276149Sae		if (m == NULL)
562276149Sae			goto drop;
563276149Sae		t = htonl((uint32_t)ecn << 20);
564276149Sae		ip6 = mtod(m, struct ip6_hdr *);
565276149Sae		if (ip6_ecn_egress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED:
566276149Sae		    ECN_NOCARE, &t, &ip6->ip6_flow) == 0) {
567276149Sae			m_freem(m);
568276149Sae			goto drop;
569276149Sae		}
570276149Sae		break;
571276149Sae#endif
572276149Sae	case IPPROTO_ETHERIP:
573276149Sae		af = AF_LINK;
574276149Sae		break;
575276149Sae	default:
576276149Sae		m_freem(m);
577276149Sae		goto drop;
578276149Sae	}
579101182Srwatson
580101182Srwatson#ifdef MAC
581172930Srwatson	mac_ifnet_create_mbuf(ifp, m);
582101182Srwatson#endif
583101182Srwatson
584159180Scsjp	if (bpf_peers_present(ifp->if_bpf)) {
585276149Sae		uint32_t af1 = af;
586123922Ssam		bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m);
58754263Sshin	}
58854263Sshin
589253261Shrs	if ((ifp->if_flags & IFF_MONITOR) != 0) {
590276149Sae		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
591276149Sae		if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
592253261Shrs		m_freem(m);
593253261Shrs		return;
594253261Shrs	}
595253261Shrs
59683998Sbrooks	if (ng_gif_input_p != NULL) {
597105338Sume		(*ng_gif_input_p)(ifp, &m, af);
59883998Sbrooks		if (m == NULL)
599276149Sae			goto drop;
60083998Sbrooks	}
60183998Sbrooks
60254263Sshin	/*
60354263Sshin	 * Put the packet to the network layer input queue according to the
60454263Sshin	 * specified address family.
60554263Sshin	 * Note: older versions of gif_input directly called network layer
60695023Ssuz	 * input functions, e.g. ip6_input, here.  We changed the policy to
60754263Sshin	 * prevent too many recursive calls of such input functions, which
60895023Ssuz	 * might cause kernel panic.  But the change may introduce another
60954263Sshin	 * problem; if the input queue is full, packets are discarded.
61095023Ssuz	 * The kernel stack overflow really happened, and we believed
61195023Ssuz	 * queue-full rarely occurs, so we changed the policy.
61254263Sshin	 */
61354263Sshin	switch (af) {
61454263Sshin#ifdef INET
61554263Sshin	case AF_INET:
61654263Sshin		isr = NETISR_IP;
61754263Sshin		break;
61854263Sshin#endif
61954263Sshin#ifdef INET6
62054263Sshin	case AF_INET6:
62154263Sshin		isr = NETISR_IPV6;
62254263Sshin		break;
62354263Sshin#endif
624153621Sthompsa	case AF_LINK:
625153621Sthompsa		n = sizeof(struct etherip_header) + sizeof(struct ether_header);
626276149Sae		if (n > m->m_len)
627153621Sthompsa			m = m_pullup(m, n);
628276149Sae		if (m == NULL)
629276149Sae			goto drop;
630153621Sthompsa		eip = mtod(m, struct etherip_header *);
631276149Sae		if (eip->eip_ver != ETHERIP_VERSION) {
632287730Shrs			/* discard unknown versions */
633287730Shrs			m_freem(m);
634287730Shrs			goto drop;
635153621Sthompsa		}
636153621Sthompsa		m_adj(m, sizeof(struct etherip_header));
637153621Sthompsa
638153621Sthompsa		m->m_flags &= ~(M_BCAST|M_MCAST);
639153621Sthompsa		m->m_pkthdr.rcvif = ifp;
640153621Sthompsa
641176879Sthompsa		if (ifp->if_bridge) {
642176879Sthompsa			oldifp = ifp;
643176879Sthompsa			eh = mtod(m, struct ether_header *);
644176879Sthompsa			if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
645176879Sthompsa				if (ETHER_IS_BROADCAST(eh->ether_dhost))
646176879Sthompsa					m->m_flags |= M_BCAST;
647176879Sthompsa				else
648176879Sthompsa					m->m_flags |= M_MCAST;
649276149Sae				if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1);
650176879Sthompsa			}
651153621Sthompsa			BRIDGE_INPUT(ifp, m);
652176879Sthompsa
653176879Sthompsa			if (m != NULL && ifp != oldifp) {
654176879Sthompsa				/*
655176879Sthompsa				 * The bridge gave us back itself or one of the
656176879Sthompsa				 * members for which the frame is addressed.
657176879Sthompsa				 */
658176879Sthompsa				ether_demux(ifp, m);
659176879Sthompsa				return;
660176879Sthompsa			}
661176879Sthompsa		}
662153621Sthompsa		if (m != NULL)
663153621Sthompsa			m_freem(m);
664153621Sthompsa		return;
665153621Sthompsa
66654263Sshin	default:
66783998Sbrooks		if (ng_gif_input_orphan_p != NULL)
668105338Sume			(*ng_gif_input_orphan_p)(ifp, m, af);
66983998Sbrooks		else
67083998Sbrooks			m_freem(m);
67154263Sshin		return;
67254263Sshin	}
67354263Sshin
674276149Sae	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
675276149Sae	if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
676223741Sbz	M_SETFIB(m, ifp->if_fib);
677111888Sjlemon	netisr_dispatch(isr, m);
678276149Sae	return;
679276149Saedrop:
680276149Sae	if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
68154263Sshin}
68254263Sshin
68362587Sitojun/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
68454263Sshinint
685276067Saegif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
68654263Sshin{
687276149Sae	GIF_RLOCK_TRACKER;
688276149Sae	struct ifreq *ifr = (struct ifreq*)data;
68962587Sitojun	struct sockaddr *dst, *src;
690276149Sae	struct gif_softc *sc;
691276149Sae#ifdef INET
692276149Sae	struct sockaddr_in *sin = NULL;
693105339Sume#endif
694276149Sae#ifdef INET6
695276149Sae	struct sockaddr_in6 *sin6 = NULL;
696276149Sae#endif
697276149Sae	u_int options;
698276149Sae	int error;
699105339Sume
70054263Sshin	switch (cmd) {
70154263Sshin	case SIOCSIFADDR:
702105293Sume		ifp->if_flags |= IFF_UP;
70354263Sshin	case SIOCADDMULTI:
70454263Sshin	case SIOCDELMULTI:
70554263Sshin	case SIOCGIFMTU:
706276149Sae	case SIOCSIFFLAGS:
707276149Sae		return (0);
70854263Sshin	case SIOCSIFMTU:
709276149Sae		if (ifr->ifr_mtu < GIF_MTU_MIN ||
710276149Sae		    ifr->ifr_mtu > GIF_MTU_MAX)
711105339Sume			return (EINVAL);
712276149Sae		else
713276149Sae			ifp->if_mtu = ifr->ifr_mtu;
714276149Sae		return (0);
715276149Sae	}
716276149Sae	sx_xlock(&gif_ioctl_sx);
717276149Sae	sc = ifp->if_softc;
718276149Sae	if (sc == NULL) {
719276149Sae		error = ENXIO;
720276149Sae		goto bad;
721276149Sae	}
722276149Sae	error = 0;
723276149Sae	switch (cmd) {
72454263Sshin	case SIOCSIFPHYADDR:
72554263Sshin#ifdef INET6
72654263Sshin	case SIOCSIFPHYADDR_IN6:
727276149Sae#endif
728276149Sae		error = EINVAL;
72962587Sitojun		switch (cmd) {
73078064Sume#ifdef INET
73162587Sitojun		case SIOCSIFPHYADDR:
73254263Sshin			src = (struct sockaddr *)
73354263Sshin				&(((struct in_aliasreq *)data)->ifra_addr);
73454263Sshin			dst = (struct sockaddr *)
73554263Sshin				&(((struct in_aliasreq *)data)->ifra_dstaddr);
73662587Sitojun			break;
73778064Sume#endif
73862587Sitojun#ifdef INET6
73962587Sitojun		case SIOCSIFPHYADDR_IN6:
74062587Sitojun			src = (struct sockaddr *)
74162587Sitojun				&(((struct in6_aliasreq *)data)->ifra_addr);
74262587Sitojun			dst = (struct sockaddr *)
74362587Sitojun				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
74462587Sitojun			break;
74562587Sitojun#endif
74691327Sbrooks		default:
747276149Sae			goto bad;
74862587Sitojun		}
74978064Sume		/* sa_family must be equal */
750276149Sae		if (src->sa_family != dst->sa_family ||
751276149Sae		    src->sa_len != dst->sa_len)
752276149Sae			goto bad;
75378064Sume
75478064Sume		/* validate sa_len */
755287730Shrs		/* check sa_family looks sane for the cmd */
75678064Sume		switch (src->sa_family) {
75778064Sume#ifdef INET
75878064Sume		case AF_INET:
75978064Sume			if (src->sa_len != sizeof(struct sockaddr_in))
760276149Sae				goto bad;
761287730Shrs			if (cmd != SIOCSIFPHYADDR) {
762287730Shrs				error = EAFNOSUPPORT;
763287730Shrs				goto bad;
764287730Shrs			}
765287730Shrs			if (satosin(src)->sin_addr.s_addr == INADDR_ANY ||
766287730Shrs			    satosin(dst)->sin_addr.s_addr == INADDR_ANY) {
767287730Shrs				error = EADDRNOTAVAIL;
768287730Shrs				goto bad;
769287730Shrs			}
77078064Sume			break;
77178064Sume#endif
77278064Sume#ifdef INET6
77378064Sume		case AF_INET6:
77478064Sume			if (src->sa_len != sizeof(struct sockaddr_in6))
775276149Sae				goto bad;
776287730Shrs			if (cmd != SIOCSIFPHYADDR_IN6) {
777287730Shrs				error = EAFNOSUPPORT;
778276149Sae				goto bad;
779287730Shrs			}
780287730Shrs			error = EADDRNOTAVAIL;
781276149Sae			if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(src)->sin6_addr)
782276149Sae			    ||
783276149Sae			    IN6_IS_ADDR_UNSPECIFIED(&satosin6(dst)->sin6_addr))
784276149Sae				goto bad;
785276149Sae			/*
786276149Sae			 * Check validity of the scope zone ID of the
787276149Sae			 * addresses, and convert it into the kernel
788276149Sae			 * internal form if necessary.
789276149Sae			 */
790276149Sae			error = sa6_embedscope(satosin6(src), 0);
791276149Sae			if (error != 0)
792276149Sae				goto bad;
793276149Sae			error = sa6_embedscope(satosin6(dst), 0);
794276149Sae			if (error != 0)
795276149Sae				goto bad;
796287730Shrs			break;
797276149Sae#endif
798287730Shrs		default:
799287730Shrs			error = EAFNOSUPPORT;
800287730Shrs			goto bad;
801287730Shrs		}
802276149Sae		error = gif_set_tunnel(ifp, src, dst);
80362587Sitojun		break;
80462587Sitojun	case SIOCDIFPHYADDR:
805276149Sae		gif_delete_tunnel(ifp);
80654263Sshin		break;
80754263Sshin	case SIOCGIFPSRCADDR:
808276149Sae	case SIOCGIFPDSTADDR:
80954263Sshin#ifdef INET6
81054263Sshin	case SIOCGIFPSRCADDR_IN6:
811276149Sae	case SIOCGIFPDSTADDR_IN6:
812276149Sae#endif
813276149Sae		if (sc->gif_family == 0) {
81454263Sshin			error = EADDRNOTAVAIL;
815276149Sae			break;
81654263Sshin		}
817276149Sae		GIF_RLOCK(sc);
81878064Sume		switch (cmd) {
81954263Sshin#ifdef INET
82078064Sume		case SIOCGIFPSRCADDR:
821276149Sae		case SIOCGIFPDSTADDR:
822276149Sae			if (sc->gif_family != AF_INET) {
823276149Sae				error = EADDRNOTAVAIL;
824276149Sae				break;
825276149Sae			}
826276149Sae			sin = (struct sockaddr_in *)&ifr->ifr_addr;
827276149Sae			memset(sin, 0, sizeof(*sin));
828276149Sae			sin->sin_family = AF_INET;
829276149Sae			sin->sin_len = sizeof(*sin);
83054263Sshin			break;
831276149Sae#endif
83254263Sshin#ifdef INET6
83378064Sume		case SIOCGIFPSRCADDR_IN6:
834276149Sae		case SIOCGIFPDSTADDR_IN6:
835276149Sae			if (sc->gif_family != AF_INET6) {
836276149Sae				error = EADDRNOTAVAIL;
837276149Sae				break;
838276149Sae			}
839276149Sae			sin6 = (struct sockaddr_in6 *)
84054263Sshin				&(((struct in6_ifreq *)data)->ifr_addr);
841276149Sae			memset(sin6, 0, sizeof(*sin6));
842276149Sae			sin6->sin6_family = AF_INET6;
843276149Sae			sin6->sin6_len = sizeof(*sin6);
84454263Sshin			break;
845276149Sae#endif
84654263Sshin		default:
847276149Sae			error = EAFNOSUPPORT;
84854263Sshin		}
849276149Sae		if (error == 0) {
850276149Sae			switch (cmd) {
851276149Sae#ifdef INET
852276149Sae			case SIOCGIFPSRCADDR:
853276149Sae				sin->sin_addr = sc->gif_iphdr->ip_src;
854276149Sae				break;
855276149Sae			case SIOCGIFPDSTADDR:
856276149Sae				sin->sin_addr = sc->gif_iphdr->ip_dst;
857276149Sae				break;
858276149Sae#endif
859148385Sume#ifdef INET6
860276149Sae			case SIOCGIFPSRCADDR_IN6:
861276149Sae				sin6->sin6_addr = sc->gif_ip6hdr->ip6_src;
862276149Sae				break;
863276149Sae			case SIOCGIFPDSTADDR_IN6:
864276149Sae				sin6->sin6_addr = sc->gif_ip6hdr->ip6_dst;
865276149Sae				break;
866148385Sume#endif
867276149Sae			}
86854263Sshin		}
869276149Sae		GIF_RUNLOCK(sc);
870276149Sae		if (error != 0)
871276149Sae			break;
87278064Sume		switch (cmd) {
87354263Sshin#ifdef INET
874276149Sae		case SIOCGIFPSRCADDR:
87578064Sume		case SIOCGIFPDSTADDR:
876276149Sae			error = prison_if(curthread->td_ucred,
877276149Sae			    (struct sockaddr *)sin);
878276149Sae			if (error != 0)
879276149Sae				memset(sin, 0, sizeof(*sin));
88054263Sshin			break;
881276149Sae#endif
88254263Sshin#ifdef INET6
883276149Sae		case SIOCGIFPSRCADDR_IN6:
88478064Sume		case SIOCGIFPDSTADDR_IN6:
885276149Sae			error = prison_if(curthread->td_ucred,
886276149Sae			    (struct sockaddr *)sin6);
887276149Sae			if (error == 0)
888276149Sae				error = sa6_recoverscope(sin6);
889148385Sume			if (error != 0)
890276149Sae				memset(sin6, 0, sizeof(*sin6));
891148385Sume#endif
89278064Sume		}
89378064Sume		break;
894284074Sae	case SIOCGTUNFIB:
895284074Sae		ifr->ifr_fib = sc->gif_fibnum;
896284074Sae		break;
897284074Sae	case SIOCSTUNFIB:
898284074Sae		if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0)
899284074Sae			break;
900284074Sae		if (ifr->ifr_fib >= rt_numfibs)
901284074Sae			error = EINVAL;
902284074Sae		else
903284074Sae			sc->gif_fibnum = ifr->ifr_fib;
904284074Sae		break;
905193664Shrs	case GIFGOPTS:
906193664Shrs		options = sc->gif_options;
907276149Sae		error = copyout(&options, ifr->ifr_data, sizeof(options));
908193664Shrs		break;
909193664Shrs	case GIFSOPTS:
910193664Shrs		if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0)
911193664Shrs			break;
912193815Shrs		error = copyin(ifr->ifr_data, &options, sizeof(options));
913193815Shrs		if (error)
914193815Shrs			break;
915193815Shrs		if (options & ~GIF_OPTMASK)
916193815Shrs			error = EINVAL;
917193815Shrs		else
918193815Shrs			sc->gif_options = options;
919193664Shrs		break;
92054263Sshin	default:
92154263Sshin		error = EINVAL;
92254263Sshin		break;
92354263Sshin	}
924276149Saebad:
925276149Sae	sx_xunlock(&gif_ioctl_sx);
926276149Sae	return (error);
92754263Sshin}
92879106Sbrooks
929276149Saestatic void
930276149Saegif_detach(struct gif_softc *sc)
931105293Sume{
932105293Sume
933276149Sae	sx_assert(&gif_ioctl_sx, SA_XLOCKED);
934276149Sae	if (sc->gif_ecookie != NULL)
935276149Sae		encap_detach(sc->gif_ecookie);
936276149Sae	sc->gif_ecookie = NULL;
937276149Sae}
938105293Sume
939276149Saestatic int
940276149Saegif_attach(struct gif_softc *sc, int af)
941276149Sae{
942105293Sume
943276149Sae	sx_assert(&gif_ioctl_sx, SA_XLOCKED);
944276149Sae	switch (af) {
945276149Sae#ifdef INET
946276149Sae	case AF_INET:
947276149Sae		return (in_gif_attach(sc));
948276149Sae#endif
949276149Sae#ifdef INET6
950276149Sae	case AF_INET6:
951276149Sae		return (in6_gif_attach(sc));
952276149Sae#endif
953105293Sume	}
954276149Sae	return (EAFNOSUPPORT);
955276149Sae}
956105293Sume
957276149Saestatic int
958276149Saegif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
959276149Sae{
960276149Sae	struct gif_softc *sc = ifp->if_softc;
961276149Sae	struct gif_softc *tsc;
962105293Sume#ifdef INET
963276149Sae	struct ip *ip;
964105293Sume#endif
965105293Sume#ifdef INET6
966276149Sae	struct ip6_hdr *ip6;
967105293Sume#endif
968276149Sae	void *hdr;
969276149Sae	int error = 0;
970105293Sume
971276149Sae	if (sc == NULL)
972276149Sae		return (ENXIO);
973276149Sae	/* Disallow parallel tunnels unless instructed otherwise. */
974276149Sae	if (V_parallel_tunnels == 0) {
975276149Sae		GIF_LIST_LOCK();
976276149Sae		LIST_FOREACH(tsc, &V_gif_softc_list, gif_list) {
977276149Sae			if (tsc == sc || tsc->gif_family != src->sa_family)
978276149Sae				continue;
979105293Sume#ifdef INET
980276149Sae			if (tsc->gif_family == AF_INET &&
981276149Sae			    tsc->gif_iphdr->ip_src.s_addr ==
982276149Sae			    satosin(src)->sin_addr.s_addr &&
983276149Sae			    tsc->gif_iphdr->ip_dst.s_addr ==
984276149Sae			    satosin(dst)->sin_addr.s_addr) {
985276149Sae				error = EADDRNOTAVAIL;
986276149Sae				GIF_LIST_UNLOCK();
987276149Sae				goto bad;
988276149Sae			}
989276149Sae#endif
990276149Sae#ifdef INET6
991276149Sae			if (tsc->gif_family == AF_INET6 &&
992276149Sae			    IN6_ARE_ADDR_EQUAL(&tsc->gif_ip6hdr->ip6_src,
993276149Sae			    &satosin6(src)->sin6_addr) &&
994276149Sae			    IN6_ARE_ADDR_EQUAL(&tsc->gif_ip6hdr->ip6_dst,
995276149Sae			    &satosin6(dst)->sin6_addr)) {
996276149Sae				error = EADDRNOTAVAIL;
997276149Sae				GIF_LIST_UNLOCK();
998276149Sae				goto bad;
999276149Sae			}
1000276149Sae#endif
1001276149Sae		}
1002276149Sae		GIF_LIST_UNLOCK();
1003276149Sae	}
1004276149Sae	switch (src->sa_family) {
1005276149Sae#ifdef INET
1006105293Sume	case AF_INET:
1007276149Sae		hdr = ip = malloc(sizeof(struct ip), M_GIF,
1008276149Sae		    M_WAITOK | M_ZERO);
1009276149Sae		ip->ip_src.s_addr = satosin(src)->sin_addr.s_addr;
1010276149Sae		ip->ip_dst.s_addr = satosin(dst)->sin_addr.s_addr;
1011105293Sume		break;
1012105293Sume#endif
1013105293Sume#ifdef INET6
1014105293Sume	case AF_INET6:
1015276149Sae		hdr = ip6 = malloc(sizeof(struct ip6_hdr), M_GIF,
1016276149Sae		    M_WAITOK | M_ZERO);
1017276149Sae		ip6->ip6_src = satosin6(src)->sin6_addr;
1018276149Sae		ip6->ip6_dst = satosin6(dst)->sin6_addr;
1019276149Sae		ip6->ip6_vfc = IPV6_VERSION;
1020105293Sume		break;
1021105293Sume#endif
1022276149Sae	default:
1023276149Sae		return (EAFNOSUPPORT);
1024276149Sae	};
1025105293Sume
1026276149Sae	if (sc->gif_family != src->sa_family)
1027276149Sae		gif_detach(sc);
1028276149Sae	if (sc->gif_family == 0 ||
1029276149Sae	    sc->gif_family != src->sa_family)
1030276149Sae		error = gif_attach(sc, src->sa_family);
1031105293Sume
1032276149Sae	GIF_WLOCK(sc);
1033276149Sae	if (sc->gif_family != 0)
1034276149Sae		free(sc->gif_hdr, M_GIF);
1035276149Sae	sc->gif_family = src->sa_family;
1036276149Sae	sc->gif_hdr = hdr;
1037276149Sae	GIF_WUNLOCK(sc);
1038276149Sae#if defined(INET) || defined(INET6)
1039276149Saebad:
1040276149Sae#endif
1041290347Shrs	if (error == 0 && sc->gif_family != 0) {
1042148887Srwatson		ifp->if_drv_flags |= IFF_DRV_RUNNING;
1043290347Shrs		if_link_state_change(ifp, LINK_STATE_UP);
1044290347Shrs	} else {
1045148887Srwatson		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1046290347Shrs		if_link_state_change(ifp, LINK_STATE_DOWN);
1047290347Shrs	}
1048276149Sae	return (error);
1049105293Sume}
1050105293Sume
1051276149Saestatic void
1052276067Saegif_delete_tunnel(struct ifnet *ifp)
105379106Sbrooks{
1054147256Sbrooks	struct gif_softc *sc = ifp->if_softc;
1055276149Sae	int family;
105679106Sbrooks
1057276149Sae	if (sc == NULL)
1058276149Sae		return;
1059276149Sae
1060276149Sae	GIF_WLOCK(sc);
1061276149Sae	family = sc->gif_family;
1062276149Sae	sc->gif_family = 0;
1063276149Sae	GIF_WUNLOCK(sc);
1064276149Sae	if (family != 0) {
1065276149Sae		gif_detach(sc);
1066276149Sae		free(sc->gif_hdr, M_GIF);
106779106Sbrooks	}
1068160018Syar	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1069290347Shrs	if_link_state_change(ifp, LINK_STATE_DOWN);
107079106Sbrooks}
1071