if_gif.c revision 92081
162587Sitojun/*	$FreeBSD: head/sys/net/if_gif.c 92081 2002-03-11 09:26:07Z mux $	*/
278064Sume/*	$KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 itojun Exp $	*/
362587Sitojun
454263Sshin/*
554263Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
654263Sshin * All rights reserved.
754263Sshin *
854263Sshin * Redistribution and use in source and binary forms, with or without
954263Sshin * modification, are permitted provided that the following conditions
1054263Sshin * are met:
1154263Sshin * 1. Redistributions of source code must retain the above copyright
1254263Sshin *    notice, this list of conditions and the following disclaimer.
1354263Sshin * 2. Redistributions in binary form must reproduce the above copyright
1454263Sshin *    notice, this list of conditions and the following disclaimer in the
1554263Sshin *    documentation and/or other materials provided with the distribution.
1654263Sshin * 3. Neither the name of the project nor the names of its contributors
1754263Sshin *    may be used to endorse or promote products derived from this software
1854263Sshin *    without specific prior written permission.
1954263Sshin *
2054263Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2154263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2254263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2354263Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2454263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2554263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2654263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2754263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2854263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2954263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3054263Sshin * SUCH DAMAGE.
3154263Sshin */
3254263Sshin
3354263Sshin#include "opt_inet.h"
3454263Sshin#include "opt_inet6.h"
3554263Sshin
3654263Sshin#include <sys/param.h>
3754263Sshin#include <sys/systm.h>
3854263Sshin#include <sys/kernel.h>
3954263Sshin#include <sys/malloc.h>
4054263Sshin#include <sys/mbuf.h>
4154263Sshin#include <sys/socket.h>
4254263Sshin#include <sys/sockio.h>
4354263Sshin#include <sys/errno.h>
4454263Sshin#include <sys/time.h>
4591270Sbrooks#include <sys/sysctl.h>
4654263Sshin#include <sys/syslog.h>
4762587Sitojun#include <sys/protosw.h>
4879106Sbrooks#include <sys/conf.h>
4954263Sshin#include <machine/cpu.h>
5054263Sshin
5154263Sshin#include <net/if.h>
5254263Sshin#include <net/if_types.h>
5354263Sshin#include <net/netisr.h>
5454263Sshin#include <net/route.h>
5554263Sshin#include <net/bpf.h>
5654263Sshin
5754263Sshin#include <netinet/in.h>
5854263Sshin#include <netinet/in_systm.h>
5978064Sume#include <netinet/ip.h>
6078064Sume#ifdef	INET
6154263Sshin#include <netinet/in_var.h>
6254263Sshin#include <netinet/in_gif.h>
6379106Sbrooks#include <netinet/ip_var.h>
6454263Sshin#endif	/* INET */
6554263Sshin
6654263Sshin#ifdef INET6
6754263Sshin#ifndef INET
6854263Sshin#include <netinet/in.h>
6954263Sshin#endif
7054263Sshin#include <netinet6/in6_var.h>
7154263Sshin#include <netinet/ip6.h>
7254263Sshin#include <netinet6/ip6_var.h>
7354263Sshin#include <netinet6/in6_gif.h>
7462587Sitojun#include <netinet6/ip6protosw.h>
7554263Sshin#endif /* INET6 */
7654263Sshin
7762587Sitojun#include <netinet/ip_encap.h>
7854263Sshin#include <net/if_gif.h>
7954263Sshin
8054263Sshin#include <net/net_osdep.h>
8154263Sshin
8279106Sbrooks#define GIFNAME		"gif"
8362587Sitojun
8479106Sbrooksstatic MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
8589065Smsmithstatic LIST_HEAD(, gif_softc) gif_softc_list;
8679106Sbrooks
8783998Sbrooksvoid	(*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af);
8883998Sbrooksvoid	(*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
8983998Sbrooksvoid	(*ng_gif_attach_p)(struct ifnet *ifp);
9083998Sbrooksvoid	(*ng_gif_detach_p)(struct ifnet *ifp);
9183998Sbrooks
9292081Smuxint	gif_clone_create __P((struct if_clone *, int));
9391647Sbrooksint	gif_clone_destroy __P((struct ifnet *));
9479106Sbrooks
9592081Smuxstruct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif",
9692081Smux    gif_clone_create, gif_clone_destroy, IF_MAXUNIT);
9779106Sbrooks
9879106Sbrooksstatic int gifmodevent __P((module_t, int, void *));
9979106Sbrooksvoid gif_delete_tunnel __P((struct gif_softc *));
10062587Sitojunstatic int gif_encapcheck __P((const struct mbuf *, int, int, void *));
10179106Sbrooks
10262587Sitojun#ifdef INET
10379106Sbrooksextern  struct domain inetdomain;
10482884Sjulianstruct protosw in_gif_protosw =
10579106Sbrooks{ SOCK_RAW,	&inetdomain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
10691327Sbrooks  in_gif_input,	(pr_output_t*)rip_output, 0,		rip_ctloutput,
10779106Sbrooks  0,
10879106Sbrooks  0,		0,		0,		0,
10979106Sbrooks  &rip_usrreqs
11079106Sbrooks};
11162587Sitojun#endif
11262587Sitojun#ifdef INET6
11391327Sbrooksextern  struct domain inet6domain;
11479106Sbrooksstruct ip6protosw in6_gif_protosw =
11579106Sbrooks{ SOCK_RAW,	&inet6domain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
11679106Sbrooks  in6_gif_input, rip6_output,	0,		rip6_ctloutput,
11779106Sbrooks  0,
11879106Sbrooks  0,		0,		0,		0,
11979106Sbrooks  &rip6_usrreqs
12079106Sbrooks};
12162587Sitojun#endif
12254263Sshin
12391270SbrooksSYSCTL_DECL(_net_link);
12491270SbrooksSYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
12591270Sbrooks    "Generic Tunnel Interface");
12662587Sitojun#ifndef MAX_GIF_NEST
12762587Sitojun/*
12891270Sbrooks * This macro controls the default upper limitation on nesting of gif tunnels.
12962587Sitojun * Since, setting a large value to this macro with a careless configuration
13062587Sitojun * may introduce system crash, we don't allow any nestings by default.
13162587Sitojun * If you need to configure nested gif tunnels, you can define this macro
13262587Sitojun * in your kernel configuration file. However, if you do so, please be
13362587Sitojun * careful to configure the tunnels so that it won't make a loop.
13462587Sitojun */
13562587Sitojun#define MAX_GIF_NEST 1
13662587Sitojun#endif
13762587Sitojunstatic int max_gif_nesting = MAX_GIF_NEST;
13891270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW,
13991270Sbrooks    &max_gif_nesting, 0, "Max nested tunnels");
14062587Sitojun
14191270Sbrooks/*
14291270Sbrooks * By default, we disallow creation of multiple tunnels between the same
14391270Sbrooks * pair of addresses.  Some applications require this functionality so
14491270Sbrooks * we allow control over this check here.
14591270Sbrooks */
14691270Sbrooks#ifdef XBONEHACK
14791270Sbrooksstatic int parallel_tunnels = 1;
14891270Sbrooks#else
14991270Sbrooksstatic int parallel_tunnels = 0;
15091270Sbrooks#endif
15191270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW,
15291270Sbrooks    &parallel_tunnels, 0, "Allow parallel tunnels?");
15391270Sbrooks
15479106Sbrooksint
15579106Sbrooksgif_clone_create(ifc, unit)
15679106Sbrooks	struct if_clone *ifc;
15792081Smux	int unit;
15854263Sshin{
15978064Sume	struct gif_softc *sc;
16054263Sshin
16179106Sbrooks	sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK);
16279106Sbrooks	bzero(sc, sizeof(struct gif_softc));
16379106Sbrooks
16479106Sbrooks	sc->gif_if.if_softc = sc;
16579106Sbrooks	sc->gif_if.if_name = GIFNAME;
16692081Smux	sc->gif_if.if_unit = unit;
16779106Sbrooks
16879106Sbrooks	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
16962587Sitojun#ifdef INET
17079106Sbrooks	sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
17179106Sbrooks	    gif_encapcheck, (struct protosw*)&in_gif_protosw, sc);
17279106Sbrooks	if (sc->encap_cookie4 == NULL) {
17379106Sbrooks		printf("%s: unable to attach encap4\n", if_name(&sc->gif_if));
17479106Sbrooks		free(sc, M_GIF);
17579106Sbrooks		return (EIO);	/* XXX */
17679106Sbrooks	}
17762587Sitojun#endif
17862587Sitojun#ifdef INET6
17979106Sbrooks	sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
18079106Sbrooks	    gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc);
18179106Sbrooks	if (sc->encap_cookie6 == NULL) {
18279106Sbrooks		if (sc->encap_cookie4) {
18379106Sbrooks			encap_detach(sc->encap_cookie4);
18479106Sbrooks			sc->encap_cookie4 = NULL;
18562587Sitojun		}
18679106Sbrooks		printf("%s: unable to attach encap6\n", if_name(&sc->gif_if));
18779106Sbrooks		free(sc, M_GIF);
18879106Sbrooks		return (EIO);	/* XXX */
18979106Sbrooks	}
19062587Sitojun#endif
19162587Sitojun
19279106Sbrooks	sc->gif_if.if_mtu    = GIF_MTU;
19379106Sbrooks	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
19478064Sume#if 0
19579106Sbrooks	/* turn off ingress filter */
19679106Sbrooks	sc->gif_if.if_flags  |= IFF_LINK2;
19778064Sume#endif
19879106Sbrooks	sc->gif_if.if_ioctl  = gif_ioctl;
19979106Sbrooks	sc->gif_if.if_output = gif_output;
20079106Sbrooks	sc->gif_if.if_type   = IFT_GIF;
20179106Sbrooks	sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
20279106Sbrooks	if_attach(&sc->gif_if);
20379106Sbrooks	bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
20483998Sbrooks	if (ng_gif_attach_p != NULL)
20583998Sbrooks		(*ng_gif_attach_p)(&sc->gif_if);
20683997Sbrooks	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_link);
20779106Sbrooks	return (0);
20879106Sbrooks}
20979106Sbrooks
21091647Sbrooksint
21179106Sbrooksgif_clone_destroy(ifp)
21279106Sbrooks	struct ifnet *ifp;
21379106Sbrooks{
21479106Sbrooks	int err;
21579106Sbrooks	struct gif_softc *sc = ifp->if_softc;
21679106Sbrooks
21779106Sbrooks	gif_delete_tunnel(sc);
21883997Sbrooks	LIST_REMOVE(sc, gif_link);
21979106Sbrooks	if (sc->encap_cookie4 != NULL) {
22079106Sbrooks		err = encap_detach(sc->encap_cookie4);
22179106Sbrooks		KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
22279106Sbrooks	}
22379106Sbrooks	if (sc->encap_cookie6 != NULL) {
22479106Sbrooks		err = encap_detach(sc->encap_cookie6);
22579106Sbrooks		KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
22679106Sbrooks	}
22779106Sbrooks
22883998Sbrooks	if (ng_gif_detach_p != NULL)
22983998Sbrooks		(*ng_gif_detach_p)(ifp);
23079106Sbrooks	bpfdetach(ifp);
23179106Sbrooks	if_detach(ifp);
23279106Sbrooks
23379106Sbrooks	free(sc, M_GIF);
23491647Sbrooks	return (0);
23579106Sbrooks}
23679106Sbrooks
23779106Sbrooksstatic int
23879106Sbrooksgifmodevent(mod, type, data)
23979106Sbrooks	module_t mod;
24079106Sbrooks	int type;
24179106Sbrooks	void *data;
24279106Sbrooks{
24379106Sbrooks
24479106Sbrooks	switch (type) {
24579106Sbrooks	case MOD_LOAD:
24683997Sbrooks		LIST_INIT(&gif_softc_list);
24779106Sbrooks		if_clone_attach(&gif_cloner);
24879106Sbrooks
24979106Sbrooks#ifdef INET6
25079106Sbrooks		ip6_gif_hlim = GIF_HLIM;
25162587Sitojun#endif
25279106Sbrooks
25379106Sbrooks		break;
25479106Sbrooks	case MOD_UNLOAD:
25579106Sbrooks		if_clone_detach(&gif_cloner);
25679106Sbrooks
25783997Sbrooks		while (!LIST_EMPTY(&gif_softc_list))
25883997Sbrooks			gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if);
25979106Sbrooks
26079106Sbrooks#ifdef INET6
26179106Sbrooks		ip6_gif_hlim = 0;
26262587Sitojun#endif
26379106Sbrooks		break;
26454263Sshin	}
26579106Sbrooks	return 0;
26654263Sshin}
26754263Sshin
26879106Sbrooksstatic moduledata_t gif_mod = {
26979106Sbrooks	"if_gif",
27079106Sbrooks	gifmodevent,
27179106Sbrooks	0
27279106Sbrooks};
27354263Sshin
27479106SbrooksDECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
27583997SbrooksMODULE_VERSION(if_gif, 1);
27679106Sbrooks
27762587Sitojunstatic int
27862587Sitojungif_encapcheck(m, off, proto, arg)
27962587Sitojun	const struct mbuf *m;
28062587Sitojun	int off;
28162587Sitojun	int proto;
28262587Sitojun	void *arg;
28362587Sitojun{
28462587Sitojun	struct ip ip;
28562587Sitojun	struct gif_softc *sc;
28662587Sitojun
28762587Sitojun	sc = (struct gif_softc *)arg;
28862587Sitojun	if (sc == NULL)
28962587Sitojun		return 0;
29062587Sitojun
29162587Sitojun	if ((sc->gif_if.if_flags & IFF_UP) == 0)
29262587Sitojun		return 0;
29362587Sitojun
29462587Sitojun	/* no physical address */
29562587Sitojun	if (!sc->gif_psrc || !sc->gif_pdst)
29662587Sitojun		return 0;
29762587Sitojun
29862587Sitojun	switch (proto) {
29962587Sitojun#ifdef INET
30062587Sitojun	case IPPROTO_IPV4:
30162587Sitojun		break;
30262587Sitojun#endif
30362587Sitojun#ifdef INET6
30462587Sitojun	case IPPROTO_IPV6:
30562587Sitojun		break;
30662587Sitojun#endif
30762587Sitojun	default:
30862587Sitojun		return 0;
30962587Sitojun	}
31062587Sitojun
31191327Sbrooks	m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
31262587Sitojun
31362587Sitojun	switch (ip.ip_v) {
31462587Sitojun#ifdef INET
31562587Sitojun	case 4:
31662587Sitojun		if (sc->gif_psrc->sa_family != AF_INET ||
31762587Sitojun		    sc->gif_pdst->sa_family != AF_INET)
31862587Sitojun			return 0;
31962587Sitojun		return gif_encapcheck4(m, off, proto, arg);
32062587Sitojun#endif
32162587Sitojun#ifdef INET6
32262587Sitojun	case 6:
32362587Sitojun		if (sc->gif_psrc->sa_family != AF_INET6 ||
32462587Sitojun		    sc->gif_pdst->sa_family != AF_INET6)
32562587Sitojun			return 0;
32662587Sitojun		return gif_encapcheck6(m, off, proto, arg);
32762587Sitojun#endif
32862587Sitojun	default:
32962587Sitojun		return 0;
33062587Sitojun	}
33162587Sitojun}
33262587Sitojun
33354263Sshinint
33454263Sshingif_output(ifp, m, dst, rt)
33554263Sshin	struct ifnet *ifp;
33654263Sshin	struct mbuf *m;
33754263Sshin	struct sockaddr *dst;
33854263Sshin	struct rtentry *rt;	/* added in net2 */
33954263Sshin{
34078064Sume	struct gif_softc *sc = (struct gif_softc*)ifp;
34154263Sshin	int error = 0;
34254263Sshin	static int called = 0;	/* XXX: MUTEX */
34354263Sshin
34454263Sshin	/*
34554263Sshin	 * gif may cause infinite recursion calls when misconfigured.
34654263Sshin	 * We'll prevent this by introducing upper limit.
34754263Sshin	 * XXX: this mechanism may introduce another problem about
34854263Sshin	 *      mutual exclusion of the variable CALLED, especially if we
34954263Sshin	 *      use kernel thread.
35054263Sshin	 */
35162587Sitojun	if (++called > max_gif_nesting) {
35254263Sshin		log(LOG_NOTICE,
35354263Sshin		    "gif_output: recursively called too many times(%d)\n",
35454263Sshin		    called);
35554263Sshin		m_freem(m);
35654263Sshin		error = EIO;	/* is there better errno? */
35754263Sshin		goto end;
35854263Sshin	}
35962587Sitojun
36054263Sshin	m->m_flags &= ~(M_BCAST|M_MCAST);
36154263Sshin	if (!(ifp->if_flags & IFF_UP) ||
36254263Sshin	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
36354263Sshin		m_freem(m);
36454263Sshin		error = ENETDOWN;
36554263Sshin		goto end;
36654263Sshin	}
36754263Sshin
36854263Sshin	if (ifp->if_bpf) {
36954263Sshin		/*
37054263Sshin		 * We need to prepend the address family as
37154263Sshin		 * a four byte field.  Cons up a dummy header
37254263Sshin		 * to pacify bpf.  This is safe because bpf
37354263Sshin		 * will only read from the mbuf (i.e., it won't
37454263Sshin		 * try to free it or keep a pointer a to it).
37554263Sshin		 */
37654263Sshin		struct mbuf m0;
37778064Sume		u_int32_t af = dst->sa_family;
37854263Sshin
37954263Sshin		m0.m_next = m;
38054263Sshin		m0.m_len = 4;
38154263Sshin		m0.m_data = (char *)&af;
38262587Sitojun
38354263Sshin		bpf_mtap(ifp, &m0);
38454263Sshin	}
38562587Sitojun	ifp->if_opackets++;
38654263Sshin	ifp->if_obytes += m->m_pkthdr.len;
38754263Sshin
38878064Sume	/* inner AF-specific encapsulation */
38978064Sume
39062587Sitojun	/* XXX should we check if our outer source is legal? */
39162587Sitojun
39278064Sume	/* dispatch to output logic based on outer AF */
39354263Sshin	switch (sc->gif_psrc->sa_family) {
39454263Sshin#ifdef INET
39554263Sshin	case AF_INET:
39654263Sshin		error = in_gif_output(ifp, dst->sa_family, m, rt);
39754263Sshin		break;
39854263Sshin#endif
39954263Sshin#ifdef INET6
40054263Sshin	case AF_INET6:
40154263Sshin		error = in6_gif_output(ifp, dst->sa_family, m, rt);
40254263Sshin		break;
40354263Sshin#endif
40454263Sshin	default:
40562587Sitojun		m_freem(m);
40654263Sshin		error = ENETDOWN;
40778064Sume		goto end;
40854263Sshin	}
40954263Sshin
41054263Sshin  end:
41154263Sshin	called = 0;		/* reset recursion counter */
41278064Sume	if (error)
41378064Sume		ifp->if_oerrors++;
41454263Sshin	return error;
41554263Sshin}
41654263Sshin
41754263Sshinvoid
41854263Sshingif_input(m, af, gifp)
41954263Sshin	struct mbuf *m;
42054263Sshin	int af;
42154263Sshin	struct ifnet *gifp;
42254263Sshin{
42369152Sjlemon	int isr;
42478064Sume	struct ifqueue *ifq = 0;
42554263Sshin
42654263Sshin	if (gifp == NULL) {
42754263Sshin		/* just in case */
42854263Sshin		m_freem(m);
42954263Sshin		return;
43054263Sshin	}
43154263Sshin
43262587Sitojun	m->m_pkthdr.rcvif = gifp;
43362587Sitojun
43454263Sshin	if (gifp->if_bpf) {
43554263Sshin		/*
43654263Sshin		 * We need to prepend the address family as
43754263Sshin		 * a four byte field.  Cons up a dummy header
43854263Sshin		 * to pacify bpf.  This is safe because bpf
43954263Sshin		 * will only read from the mbuf (i.e., it won't
44054263Sshin		 * try to free it or keep a pointer a to it).
44154263Sshin		 */
44254263Sshin		struct mbuf m0;
44378064Sume		u_int32_t af1 = af;
44462587Sitojun
44554263Sshin		m0.m_next = m;
44654263Sshin		m0.m_len = 4;
44778064Sume		m0.m_data = (char *)&af1;
44862587Sitojun
44954263Sshin		bpf_mtap(gifp, &m0);
45054263Sshin	}
45154263Sshin
45283998Sbrooks	if (ng_gif_input_p != NULL) {
45383998Sbrooks		(*ng_gif_input_p)(gifp, &m, af);
45483998Sbrooks		if (m == NULL)
45583998Sbrooks			return;
45683998Sbrooks	}
45783998Sbrooks
45854263Sshin	/*
45954263Sshin	 * Put the packet to the network layer input queue according to the
46054263Sshin	 * specified address family.
46154263Sshin	 * Note: older versions of gif_input directly called network layer
46254263Sshin	 * input functions, e.g. ip6_input, here. We changed the policy to
46354263Sshin	 * prevent too many recursive calls of such input functions, which
46454263Sshin	 * might cause kernel panic. But the change may introduce another
46554263Sshin	 * problem; if the input queue is full, packets are discarded.
46654263Sshin	 * We believed it rarely occurs and changed the policy. If we find
46754263Sshin	 * it occurs more times than we thought, we may change the policy
46854263Sshin	 * again.
46954263Sshin	 */
47054263Sshin	switch (af) {
47154263Sshin#ifdef INET
47254263Sshin	case AF_INET:
47354263Sshin		ifq = &ipintrq;
47454263Sshin		isr = NETISR_IP;
47554263Sshin		break;
47654263Sshin#endif
47754263Sshin#ifdef INET6
47854263Sshin	case AF_INET6:
47954263Sshin		ifq = &ip6intrq;
48054263Sshin		isr = NETISR_IPV6;
48154263Sshin		break;
48254263Sshin#endif
48354263Sshin	default:
48483998Sbrooks		if (ng_gif_input_orphan_p != NULL)
48583998Sbrooks			(*ng_gif_input_orphan_p)(gifp, m, af);
48683998Sbrooks		else
48783998Sbrooks			m_freem(m);
48854263Sshin		return;
48954263Sshin	}
49054263Sshin
49169152Sjlemon	gifp->if_ipackets++;
49269152Sjlemon	gifp->if_ibytes += m->m_pkthdr.len;
49369152Sjlemon	(void) IF_HANDOFF(ifq, m, NULL);
49454263Sshin	/* we need schednetisr since the address family may change */
49554263Sshin	schednetisr(isr);
49654263Sshin
49754263Sshin	return;
49854263Sshin}
49954263Sshin
50062587Sitojun/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
50154263Sshinint
50254263Sshingif_ioctl(ifp, cmd, data)
50354263Sshin	struct ifnet *ifp;
50454263Sshin	u_long cmd;
50554263Sshin	caddr_t data;
50654263Sshin{
50754263Sshin	struct gif_softc *sc  = (struct gif_softc*)ifp;
50854263Sshin	struct ifreq     *ifr = (struct ifreq*)data;
50954263Sshin	int error = 0, size;
51062587Sitojun	struct sockaddr *dst, *src;
51162587Sitojun	struct sockaddr *sa;
51277658Syar	int s;
51379106Sbrooks	struct ifnet *ifp2;
51462587Sitojun	struct gif_softc *sc2;
51562587Sitojun
51654263Sshin	switch (cmd) {
51754263Sshin	case SIOCSIFADDR:
51854263Sshin		break;
51962587Sitojun
52054263Sshin	case SIOCSIFDSTADDR:
52154263Sshin		break;
52254263Sshin
52354263Sshin	case SIOCADDMULTI:
52454263Sshin	case SIOCDELMULTI:
52554263Sshin		break;
52654263Sshin
52762587Sitojun#ifdef	SIOCSIFMTU /* xxx */
52854263Sshin	case SIOCGIFMTU:
52954263Sshin		break;
53062587Sitojun
53154263Sshin	case SIOCSIFMTU:
53254263Sshin		{
53354263Sshin			u_long mtu;
53454263Sshin			mtu = ifr->ifr_mtu;
53554263Sshin			if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
53654263Sshin				return (EINVAL);
53754263Sshin			}
53854263Sshin			ifp->if_mtu = mtu;
53954263Sshin		}
54054263Sshin		break;
54162587Sitojun#endif /* SIOCSIFMTU */
54254263Sshin
54354263Sshin	case SIOCSIFPHYADDR:
54454263Sshin#ifdef INET6
54554263Sshin	case SIOCSIFPHYADDR_IN6:
54654263Sshin#endif /* INET6 */
54778064Sume	case SIOCSLIFPHYADDR:
54862587Sitojun		switch (cmd) {
54978064Sume#ifdef INET
55062587Sitojun		case SIOCSIFPHYADDR:
55154263Sshin			src = (struct sockaddr *)
55254263Sshin				&(((struct in_aliasreq *)data)->ifra_addr);
55354263Sshin			dst = (struct sockaddr *)
55454263Sshin				&(((struct in_aliasreq *)data)->ifra_dstaddr);
55562587Sitojun			break;
55678064Sume#endif
55762587Sitojun#ifdef INET6
55862587Sitojun		case SIOCSIFPHYADDR_IN6:
55962587Sitojun			src = (struct sockaddr *)
56062587Sitojun				&(((struct in6_aliasreq *)data)->ifra_addr);
56162587Sitojun			dst = (struct sockaddr *)
56262587Sitojun				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
56362587Sitojun			break;
56462587Sitojun#endif
56578064Sume		case SIOCSLIFPHYADDR:
56678064Sume			src = (struct sockaddr *)
56778064Sume				&(((struct if_laddrreq *)data)->addr);
56878064Sume			dst = (struct sockaddr *)
56978064Sume				&(((struct if_laddrreq *)data)->dstaddr);
57091327Sbrooks		default:
57191327Sbrooks			error = EADDRNOTAVAIL;
57291327Sbrooks			goto bad;
57362587Sitojun		}
57454263Sshin
57578064Sume		/* sa_family must be equal */
57678064Sume		if (src->sa_family != dst->sa_family)
57778064Sume			return EINVAL;
57878064Sume
57978064Sume		/* validate sa_len */
58078064Sume		switch (src->sa_family) {
58178064Sume#ifdef INET
58278064Sume		case AF_INET:
58378064Sume			if (src->sa_len != sizeof(struct sockaddr_in))
58478064Sume				return EINVAL;
58578064Sume			break;
58678064Sume#endif
58778064Sume#ifdef INET6
58878064Sume		case AF_INET6:
58978064Sume			if (src->sa_len != sizeof(struct sockaddr_in6))
59078064Sume				return EINVAL;
59178064Sume			break;
59278064Sume#endif
59378064Sume		default:
59478064Sume			return EAFNOSUPPORT;
59578064Sume		}
59678064Sume		switch (dst->sa_family) {
59778064Sume#ifdef INET
59878064Sume		case AF_INET:
59978064Sume			if (dst->sa_len != sizeof(struct sockaddr_in))
60078064Sume				return EINVAL;
60178064Sume			break;
60278064Sume#endif
60378064Sume#ifdef INET6
60478064Sume		case AF_INET6:
60578064Sume			if (dst->sa_len != sizeof(struct sockaddr_in6))
60678064Sume				return EINVAL;
60778064Sume			break;
60878064Sume#endif
60978064Sume		default:
61078064Sume			return EAFNOSUPPORT;
61178064Sume		}
61278064Sume
61378064Sume		/* check sa_family looks sane for the cmd */
61478064Sume		switch (cmd) {
61578064Sume		case SIOCSIFPHYADDR:
61678064Sume			if (src->sa_family == AF_INET)
61778064Sume				break;
61878064Sume			return EAFNOSUPPORT;
61978064Sume#ifdef INET6
62078064Sume		case SIOCSIFPHYADDR_IN6:
62178064Sume			if (src->sa_family == AF_INET6)
62278064Sume				break;
62378064Sume			return EAFNOSUPPORT;
62478064Sume#endif /* INET6 */
62578064Sume		case SIOCSLIFPHYADDR:
62678064Sume			/* checks done in the above */
62778064Sume			break;
62878064Sume		}
62978064Sume
63079106Sbrooks		TAILQ_FOREACH(ifp2, &ifnet, if_link) {
63179106Sbrooks			if (strcmp(ifp2->if_name, GIFNAME) != 0)
63279106Sbrooks				continue;
63379106Sbrooks			sc2 = ifp2->if_softc;
63462587Sitojun			if (sc2 == sc)
63562587Sitojun				continue;
63662587Sitojun			if (!sc2->gif_pdst || !sc2->gif_psrc)
63762587Sitojun				continue;
63862587Sitojun			if (sc2->gif_pdst->sa_family != dst->sa_family ||
63962587Sitojun			    sc2->gif_pdst->sa_len != dst->sa_len ||
64062587Sitojun			    sc2->gif_psrc->sa_family != src->sa_family ||
64162587Sitojun			    sc2->gif_psrc->sa_len != src->sa_len)
64262587Sitojun				continue;
64391270Sbrooks
64491270Sbrooks			/*
64591270Sbrooks			 * Disallow parallel tunnels unless instructed
64691270Sbrooks			 * otherwise.
64791270Sbrooks			 */
64891270Sbrooks			if (!parallel_tunnels &&
64991270Sbrooks			    bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
65062587Sitojun			    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
65162587Sitojun				error = EADDRNOTAVAIL;
65262587Sitojun				goto bad;
65362587Sitojun			}
65454263Sshin
65562587Sitojun			/* can't configure multiple multi-dest interfaces */
65662587Sitojun#define multidest(x) \
65762587Sitojun	(((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
65857903Sshin#ifdef INET6
65962587Sitojun#define multidest6(x) \
66062587Sitojun	(IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
66157903Sshin#endif
66262587Sitojun			if (dst->sa_family == AF_INET &&
66362587Sitojun			    multidest(dst) && multidest(sc2->gif_pdst)) {
66462587Sitojun				error = EADDRNOTAVAIL;
66562587Sitojun				goto bad;
66662587Sitojun			}
66762587Sitojun#ifdef INET6
66862587Sitojun			if (dst->sa_family == AF_INET6 &&
66962587Sitojun			    multidest6(dst) && multidest6(sc2->gif_pdst)) {
67062587Sitojun				error = EADDRNOTAVAIL;
67162587Sitojun				goto bad;
67262587Sitojun			}
67362587Sitojun#endif
67462587Sitojun		}
67557903Sshin
67662587Sitojun		if (sc->gif_psrc)
67754263Sshin			free((caddr_t)sc->gif_psrc, M_IFADDR);
67878064Sume		sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
67978064Sume		bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
68054263Sshin		sc->gif_psrc = sa;
68154263Sshin
68262587Sitojun		if (sc->gif_pdst)
68362587Sitojun			free((caddr_t)sc->gif_pdst, M_IFADDR);
68478064Sume		sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
68578064Sume		bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
68654263Sshin		sc->gif_pdst = sa;
68754263Sshin
68877658Syar		ifp->if_flags |= IFF_RUNNING;
68977658Syar		s = splimp();
69077658Syar		if_up(ifp);	/* mark interface UP and send up RTM_IFINFO */
69177658Syar		splx(s);
69254263Sshin
69362587Sitojun		error = 0;
69462587Sitojun		break;
69562587Sitojun
69662587Sitojun#ifdef SIOCDIFPHYADDR
69762587Sitojun	case SIOCDIFPHYADDR:
69862587Sitojun		if (sc->gif_psrc) {
69962587Sitojun			free((caddr_t)sc->gif_psrc, M_IFADDR);
70062587Sitojun			sc->gif_psrc = NULL;
70157536Sshin		}
70262587Sitojun		if (sc->gif_pdst) {
70362587Sitojun			free((caddr_t)sc->gif_pdst, M_IFADDR);
70462587Sitojun			sc->gif_pdst = NULL;
70562587Sitojun		}
70678064Sume		/* change the IFF_{UP, RUNNING} flag as well? */
70754263Sshin		break;
70862587Sitojun#endif
70962587Sitojun
71054263Sshin	case SIOCGIFPSRCADDR:
71154263Sshin#ifdef INET6
71254263Sshin	case SIOCGIFPSRCADDR_IN6:
71354263Sshin#endif /* INET6 */
71454263Sshin		if (sc->gif_psrc == NULL) {
71554263Sshin			error = EADDRNOTAVAIL;
71654263Sshin			goto bad;
71754263Sshin		}
71854263Sshin		src = sc->gif_psrc;
71978064Sume		switch (cmd) {
72054263Sshin#ifdef INET
72178064Sume		case SIOCGIFPSRCADDR:
72254263Sshin			dst = &ifr->ifr_addr;
72378064Sume			size = sizeof(ifr->ifr_addr);
72454263Sshin			break;
72554263Sshin#endif /* INET */
72654263Sshin#ifdef INET6
72778064Sume		case SIOCGIFPSRCADDR_IN6:
72854263Sshin			dst = (struct sockaddr *)
72954263Sshin				&(((struct in6_ifreq *)data)->ifr_addr);
73078064Sume			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
73154263Sshin			break;
73254263Sshin#endif /* INET6 */
73354263Sshin		default:
73454263Sshin			error = EADDRNOTAVAIL;
73554263Sshin			goto bad;
73654263Sshin		}
73778064Sume		if (src->sa_len > size)
73878064Sume			return EINVAL;
73978064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
74054263Sshin		break;
74162587Sitojun
74254263Sshin	case SIOCGIFPDSTADDR:
74354263Sshin#ifdef INET6
74454263Sshin	case SIOCGIFPDSTADDR_IN6:
74554263Sshin#endif /* INET6 */
74654263Sshin		if (sc->gif_pdst == NULL) {
74754263Sshin			error = EADDRNOTAVAIL;
74854263Sshin			goto bad;
74954263Sshin		}
75054263Sshin		src = sc->gif_pdst;
75178064Sume		switch (cmd) {
75254263Sshin#ifdef INET
75378064Sume		case SIOCGIFPDSTADDR:
75454263Sshin			dst = &ifr->ifr_addr;
75578064Sume			size = sizeof(ifr->ifr_addr);
75654263Sshin			break;
75754263Sshin#endif /* INET */
75854263Sshin#ifdef INET6
75978064Sume		case SIOCGIFPDSTADDR_IN6:
76054263Sshin			dst = (struct sockaddr *)
76154263Sshin				&(((struct in6_ifreq *)data)->ifr_addr);
76278064Sume			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
76354263Sshin			break;
76454263Sshin#endif /* INET6 */
76554263Sshin		default:
76654263Sshin			error = EADDRNOTAVAIL;
76754263Sshin			goto bad;
76854263Sshin		}
76978064Sume		if (src->sa_len > size)
77078064Sume			return EINVAL;
77178064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
77254263Sshin		break;
77354263Sshin
77478064Sume	case SIOCGLIFPHYADDR:
77578064Sume		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
77678064Sume			error = EADDRNOTAVAIL;
77778064Sume			goto bad;
77878064Sume		}
77978064Sume
78078064Sume		/* copy src */
78178064Sume		src = sc->gif_psrc;
78278064Sume		dst = (struct sockaddr *)
78378064Sume			&(((struct if_laddrreq *)data)->addr);
78478064Sume		size = sizeof(((struct if_laddrreq *)data)->addr);
78578064Sume		if (src->sa_len > size)
78678064Sume			return EINVAL;
78778064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
78878064Sume
78978064Sume		/* copy dst */
79078064Sume		src = sc->gif_pdst;
79178064Sume		dst = (struct sockaddr *)
79278064Sume			&(((struct if_laddrreq *)data)->dstaddr);
79378064Sume		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
79478064Sume		if (src->sa_len > size)
79578064Sume			return EINVAL;
79678064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
79778064Sume		break;
79878064Sume
79954263Sshin	case SIOCSIFFLAGS:
80062587Sitojun		/* if_ioctl() takes care of it */
80154263Sshin		break;
80254263Sshin
80354263Sshin	default:
80454263Sshin		error = EINVAL;
80554263Sshin		break;
80654263Sshin	}
80754263Sshin bad:
80854263Sshin	return error;
80954263Sshin}
81079106Sbrooks
81179106Sbrooksvoid
81279106Sbrooksgif_delete_tunnel(sc)
81379106Sbrooks	struct gif_softc *sc;
81479106Sbrooks{
81579106Sbrooks	/* XXX: NetBSD protects this function with splsoftnet() */
81679106Sbrooks
81779106Sbrooks	if (sc->gif_psrc) {
81879106Sbrooks		free((caddr_t)sc->gif_psrc, M_IFADDR);
81979106Sbrooks		sc->gif_psrc = NULL;
82079106Sbrooks	}
82179106Sbrooks	if (sc->gif_pdst) {
82279106Sbrooks		free((caddr_t)sc->gif_pdst, M_IFADDR);
82379106Sbrooks		sc->gif_pdst = NULL;
82479106Sbrooks	}
82579106Sbrooks	/* change the IFF_UP flag as well? */
82679106Sbrooks}
827