if_gif.c revision 101739
162587Sitojun/*	$FreeBSD: head/sys/net/if_gif.c 101739 2002-08-12 16:08:23Z rwatson $	*/
295023Ssuz/*	$KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 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"
35101739Srwatson#include "opt_mac.h"
3654263Sshin
3754263Sshin#include <sys/param.h>
3854263Sshin#include <sys/systm.h>
3954263Sshin#include <sys/kernel.h>
40101182Srwatson#include <sys/mac.h>
4154263Sshin#include <sys/malloc.h>
4254263Sshin#include <sys/mbuf.h>
4354263Sshin#include <sys/socket.h>
4454263Sshin#include <sys/sockio.h>
4554263Sshin#include <sys/errno.h>
4654263Sshin#include <sys/time.h>
4791270Sbrooks#include <sys/sysctl.h>
4854263Sshin#include <sys/syslog.h>
4962587Sitojun#include <sys/protosw.h>
5079106Sbrooks#include <sys/conf.h>
5154263Sshin#include <machine/cpu.h>
5254263Sshin
5354263Sshin#include <net/if.h>
5454263Sshin#include <net/if_types.h>
5554263Sshin#include <net/netisr.h>
5654263Sshin#include <net/route.h>
5754263Sshin#include <net/bpf.h>
5854263Sshin
5954263Sshin#include <netinet/in.h>
6054263Sshin#include <netinet/in_systm.h>
6178064Sume#include <netinet/ip.h>
6278064Sume#ifdef	INET
6354263Sshin#include <netinet/in_var.h>
6454263Sshin#include <netinet/in_gif.h>
6579106Sbrooks#include <netinet/ip_var.h>
6654263Sshin#endif	/* INET */
6754263Sshin
6854263Sshin#ifdef INET6
6954263Sshin#ifndef INET
7054263Sshin#include <netinet/in.h>
7154263Sshin#endif
7254263Sshin#include <netinet6/in6_var.h>
7354263Sshin#include <netinet/ip6.h>
7454263Sshin#include <netinet6/ip6_var.h>
7554263Sshin#include <netinet6/in6_gif.h>
7662587Sitojun#include <netinet6/ip6protosw.h>
7754263Sshin#endif /* INET6 */
7854263Sshin
7962587Sitojun#include <netinet/ip_encap.h>
8054263Sshin#include <net/if_gif.h>
8154263Sshin
8254263Sshin#include <net/net_osdep.h>
8354263Sshin
8479106Sbrooks#define GIFNAME		"gif"
8562587Sitojun
8679106Sbrooksstatic MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
8789065Smsmithstatic LIST_HEAD(, gif_softc) gif_softc_list;
8879106Sbrooks
8983998Sbrooksvoid	(*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af);
9083998Sbrooksvoid	(*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
9183998Sbrooksvoid	(*ng_gif_attach_p)(struct ifnet *ifp);
9283998Sbrooksvoid	(*ng_gif_detach_p)(struct ifnet *ifp);
9383998Sbrooks
9492725Salfredint	gif_clone_create(struct if_clone *, int);
9597289Sbrooksvoid	gif_clone_destroy(struct ifnet *);
9679106Sbrooks
9792081Smuxstruct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif",
9897289Sbrooks    gif_clone_create, gif_clone_destroy, 0, IF_MAXUNIT);
9979106Sbrooks
10092725Salfredstatic int gifmodevent(module_t, int, void *);
10192725Salfredvoid gif_delete_tunnel(struct gif_softc *);
10292725Salfredstatic int gif_encapcheck(const struct mbuf *, int, int, void *);
10379106Sbrooks
10462587Sitojun#ifdef INET
10579106Sbrooksextern  struct domain inetdomain;
10682884Sjulianstruct protosw in_gif_protosw =
10779106Sbrooks{ SOCK_RAW,	&inetdomain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
10891327Sbrooks  in_gif_input,	(pr_output_t*)rip_output, 0,		rip_ctloutput,
10979106Sbrooks  0,
11079106Sbrooks  0,		0,		0,		0,
11179106Sbrooks  &rip_usrreqs
11279106Sbrooks};
11362587Sitojun#endif
11462587Sitojun#ifdef INET6
11591327Sbrooksextern  struct domain inet6domain;
11679106Sbrooksstruct ip6protosw in6_gif_protosw =
11779106Sbrooks{ SOCK_RAW,	&inet6domain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
11879106Sbrooks  in6_gif_input, rip6_output,	0,		rip6_ctloutput,
11979106Sbrooks  0,
12079106Sbrooks  0,		0,		0,		0,
12179106Sbrooks  &rip6_usrreqs
12279106Sbrooks};
12362587Sitojun#endif
12454263Sshin
12591270SbrooksSYSCTL_DECL(_net_link);
12691270SbrooksSYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
12791270Sbrooks    "Generic Tunnel Interface");
12862587Sitojun#ifndef MAX_GIF_NEST
12962587Sitojun/*
13091270Sbrooks * This macro controls the default upper limitation on nesting of gif tunnels.
13162587Sitojun * Since, setting a large value to this macro with a careless configuration
13262587Sitojun * may introduce system crash, we don't allow any nestings by default.
13362587Sitojun * If you need to configure nested gif tunnels, you can define this macro
13495023Ssuz * in your kernel configuration file.  However, if you do so, please be
13562587Sitojun * careful to configure the tunnels so that it won't make a loop.
13662587Sitojun */
13762587Sitojun#define MAX_GIF_NEST 1
13862587Sitojun#endif
13962587Sitojunstatic int max_gif_nesting = MAX_GIF_NEST;
14091270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW,
14191270Sbrooks    &max_gif_nesting, 0, "Max nested tunnels");
14262587Sitojun
14391270Sbrooks/*
14491270Sbrooks * By default, we disallow creation of multiple tunnels between the same
14591270Sbrooks * pair of addresses.  Some applications require this functionality so
14691270Sbrooks * we allow control over this check here.
14791270Sbrooks */
14891270Sbrooks#ifdef XBONEHACK
14991270Sbrooksstatic int parallel_tunnels = 1;
15091270Sbrooks#else
15191270Sbrooksstatic int parallel_tunnels = 0;
15291270Sbrooks#endif
15391270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW,
15491270Sbrooks    &parallel_tunnels, 0, "Allow parallel tunnels?");
15591270Sbrooks
15679106Sbrooksint
15779106Sbrooksgif_clone_create(ifc, unit)
15879106Sbrooks	struct if_clone *ifc;
15992081Smux	int unit;
16054263Sshin{
16178064Sume	struct gif_softc *sc;
16254263Sshin
16379106Sbrooks	sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK);
16479106Sbrooks	bzero(sc, sizeof(struct gif_softc));
16579106Sbrooks
16679106Sbrooks	sc->gif_if.if_softc = sc;
16779106Sbrooks	sc->gif_if.if_name = GIFNAME;
16892081Smux	sc->gif_if.if_unit = unit;
16979106Sbrooks
17079106Sbrooks	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
17162587Sitojun#ifdef INET
17279106Sbrooks	sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
17379106Sbrooks	    gif_encapcheck, (struct protosw*)&in_gif_protosw, sc);
17479106Sbrooks	if (sc->encap_cookie4 == NULL) {
17579106Sbrooks		printf("%s: unable to attach encap4\n", if_name(&sc->gif_if));
17679106Sbrooks		free(sc, M_GIF);
17779106Sbrooks		return (EIO);	/* XXX */
17879106Sbrooks	}
17962587Sitojun#endif
18062587Sitojun#ifdef INET6
18179106Sbrooks	sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
18279106Sbrooks	    gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc);
18379106Sbrooks	if (sc->encap_cookie6 == NULL) {
18479106Sbrooks		if (sc->encap_cookie4) {
18579106Sbrooks			encap_detach(sc->encap_cookie4);
18679106Sbrooks			sc->encap_cookie4 = NULL;
18762587Sitojun		}
18879106Sbrooks		printf("%s: unable to attach encap6\n", if_name(&sc->gif_if));
18979106Sbrooks		free(sc, M_GIF);
19079106Sbrooks		return (EIO);	/* XXX */
19179106Sbrooks	}
19262587Sitojun#endif
19362587Sitojun
19479106Sbrooks	sc->gif_if.if_mtu    = GIF_MTU;
19579106Sbrooks	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
19678064Sume#if 0
19779106Sbrooks	/* turn off ingress filter */
19879106Sbrooks	sc->gif_if.if_flags  |= IFF_LINK2;
19978064Sume#endif
20079106Sbrooks	sc->gif_if.if_ioctl  = gif_ioctl;
20179106Sbrooks	sc->gif_if.if_output = gif_output;
20279106Sbrooks	sc->gif_if.if_type   = IFT_GIF;
20379106Sbrooks	sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
20479106Sbrooks	if_attach(&sc->gif_if);
20579106Sbrooks	bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
20683998Sbrooks	if (ng_gif_attach_p != NULL)
20783998Sbrooks		(*ng_gif_attach_p)(&sc->gif_if);
20883997Sbrooks	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_link);
20979106Sbrooks	return (0);
21079106Sbrooks}
21179106Sbrooks
21297289Sbrooksvoid
21379106Sbrooksgif_clone_destroy(ifp)
21479106Sbrooks	struct ifnet *ifp;
21579106Sbrooks{
21679106Sbrooks	int err;
21779106Sbrooks	struct gif_softc *sc = ifp->if_softc;
21879106Sbrooks
21979106Sbrooks	gif_delete_tunnel(sc);
22083997Sbrooks	LIST_REMOVE(sc, gif_link);
22179106Sbrooks	if (sc->encap_cookie4 != NULL) {
22279106Sbrooks		err = encap_detach(sc->encap_cookie4);
22379106Sbrooks		KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
22479106Sbrooks	}
22579106Sbrooks	if (sc->encap_cookie6 != NULL) {
22679106Sbrooks		err = encap_detach(sc->encap_cookie6);
22779106Sbrooks		KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
22879106Sbrooks	}
22979106Sbrooks
23083998Sbrooks	if (ng_gif_detach_p != NULL)
23183998Sbrooks		(*ng_gif_detach_p)(ifp);
23279106Sbrooks	bpfdetach(ifp);
23379106Sbrooks	if_detach(ifp);
23479106Sbrooks
23579106Sbrooks	free(sc, M_GIF);
23679106Sbrooks}
23779106Sbrooks
23879106Sbrooksstatic int
23979106Sbrooksgifmodevent(mod, type, data)
24079106Sbrooks	module_t mod;
24179106Sbrooks	int type;
24279106Sbrooks	void *data;
24379106Sbrooks{
24479106Sbrooks
24579106Sbrooks	switch (type) {
24679106Sbrooks	case MOD_LOAD:
24783997Sbrooks		LIST_INIT(&gif_softc_list);
24879106Sbrooks		if_clone_attach(&gif_cloner);
24979106Sbrooks
25079106Sbrooks#ifdef INET6
25179106Sbrooks		ip6_gif_hlim = GIF_HLIM;
25262587Sitojun#endif
25379106Sbrooks
25479106Sbrooks		break;
25579106Sbrooks	case MOD_UNLOAD:
25679106Sbrooks		if_clone_detach(&gif_cloner);
25779106Sbrooks
25883997Sbrooks		while (!LIST_EMPTY(&gif_softc_list))
25983997Sbrooks			gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if);
26079106Sbrooks
26179106Sbrooks#ifdef INET6
26279106Sbrooks		ip6_gif_hlim = 0;
26362587Sitojun#endif
26479106Sbrooks		break;
26554263Sshin	}
26679106Sbrooks	return 0;
26754263Sshin}
26854263Sshin
26979106Sbrooksstatic moduledata_t gif_mod = {
27079106Sbrooks	"if_gif",
27179106Sbrooks	gifmodevent,
27279106Sbrooks	0
27379106Sbrooks};
27454263Sshin
27579106SbrooksDECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
27683997SbrooksMODULE_VERSION(if_gif, 1);
27779106Sbrooks
27862587Sitojunstatic int
27962587Sitojungif_encapcheck(m, off, proto, arg)
28062587Sitojun	const struct mbuf *m;
28162587Sitojun	int off;
28262587Sitojun	int proto;
28362587Sitojun	void *arg;
28462587Sitojun{
28562587Sitojun	struct ip ip;
28662587Sitojun	struct gif_softc *sc;
28762587Sitojun
28862587Sitojun	sc = (struct gif_softc *)arg;
28962587Sitojun	if (sc == NULL)
29062587Sitojun		return 0;
29162587Sitojun
29262587Sitojun	if ((sc->gif_if.if_flags & IFF_UP) == 0)
29362587Sitojun		return 0;
29462587Sitojun
29562587Sitojun	/* no physical address */
29662587Sitojun	if (!sc->gif_psrc || !sc->gif_pdst)
29762587Sitojun		return 0;
29862587Sitojun
29962587Sitojun	switch (proto) {
30062587Sitojun#ifdef INET
30162587Sitojun	case IPPROTO_IPV4:
30262587Sitojun		break;
30362587Sitojun#endif
30462587Sitojun#ifdef INET6
30562587Sitojun	case IPPROTO_IPV6:
30662587Sitojun		break;
30762587Sitojun#endif
30862587Sitojun	default:
30962587Sitojun		return 0;
31062587Sitojun	}
31162587Sitojun
31291327Sbrooks	m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
31362587Sitojun
31462587Sitojun	switch (ip.ip_v) {
31562587Sitojun#ifdef INET
31662587Sitojun	case 4:
31762587Sitojun		if (sc->gif_psrc->sa_family != AF_INET ||
31862587Sitojun		    sc->gif_pdst->sa_family != AF_INET)
31962587Sitojun			return 0;
32062587Sitojun		return gif_encapcheck4(m, off, proto, arg);
32162587Sitojun#endif
32262587Sitojun#ifdef INET6
32362587Sitojun	case 6:
32462587Sitojun		if (sc->gif_psrc->sa_family != AF_INET6 ||
32562587Sitojun		    sc->gif_pdst->sa_family != AF_INET6)
32662587Sitojun			return 0;
32762587Sitojun		return gif_encapcheck6(m, off, proto, arg);
32862587Sitojun#endif
32962587Sitojun	default:
33062587Sitojun		return 0;
33162587Sitojun	}
33262587Sitojun}
33362587Sitojun
33454263Sshinint
33554263Sshingif_output(ifp, m, dst, rt)
33654263Sshin	struct ifnet *ifp;
33754263Sshin	struct mbuf *m;
33854263Sshin	struct sockaddr *dst;
33954263Sshin	struct rtentry *rt;	/* added in net2 */
34054263Sshin{
34178064Sume	struct gif_softc *sc = (struct gif_softc*)ifp;
34254263Sshin	int error = 0;
34354263Sshin	static int called = 0;	/* XXX: MUTEX */
34454263Sshin
345101182Srwatson#ifdef MAC
346101182Srwatson	error = mac_check_ifnet_transmit(ifp, m);
347101739Srwatson	if (error) {
348101739Srwatson		m_freem(m);
349101739Srwatson		goto end;
350101739Srwatson	}
351101182Srwatson#endif
352101182Srwatson
35354263Sshin	/*
35454263Sshin	 * gif may cause infinite recursion calls when misconfigured.
35554263Sshin	 * We'll prevent this by introducing upper limit.
35654263Sshin	 * XXX: this mechanism may introduce another problem about
35754263Sshin	 *      mutual exclusion of the variable CALLED, especially if we
35854263Sshin	 *      use kernel thread.
35954263Sshin	 */
36062587Sitojun	if (++called > max_gif_nesting) {
36154263Sshin		log(LOG_NOTICE,
36254263Sshin		    "gif_output: recursively called too many times(%d)\n",
36354263Sshin		    called);
36454263Sshin		m_freem(m);
36554263Sshin		error = EIO;	/* is there better errno? */
36654263Sshin		goto end;
36754263Sshin	}
36862587Sitojun
36954263Sshin	m->m_flags &= ~(M_BCAST|M_MCAST);
37054263Sshin	if (!(ifp->if_flags & IFF_UP) ||
37154263Sshin	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
37254263Sshin		m_freem(m);
37354263Sshin		error = ENETDOWN;
37454263Sshin		goto end;
37554263Sshin	}
37654263Sshin
37754263Sshin	if (ifp->if_bpf) {
37854263Sshin		/*
37954263Sshin		 * We need to prepend the address family as
38054263Sshin		 * a four byte field.  Cons up a dummy header
38154263Sshin		 * to pacify bpf.  This is safe because bpf
38254263Sshin		 * will only read from the mbuf (i.e., it won't
38354263Sshin		 * try to free it or keep a pointer a to it).
38454263Sshin		 */
38554263Sshin		struct mbuf m0;
38678064Sume		u_int32_t af = dst->sa_family;
38754263Sshin
38854263Sshin		m0.m_next = m;
38954263Sshin		m0.m_len = 4;
39054263Sshin		m0.m_data = (char *)&af;
39162587Sitojun
39254263Sshin		bpf_mtap(ifp, &m0);
39354263Sshin	}
39462587Sitojun	ifp->if_opackets++;
39554263Sshin	ifp->if_obytes += m->m_pkthdr.len;
39654263Sshin
39778064Sume	/* inner AF-specific encapsulation */
39878064Sume
39962587Sitojun	/* XXX should we check if our outer source is legal? */
40062587Sitojun
40178064Sume	/* dispatch to output logic based on outer AF */
40254263Sshin	switch (sc->gif_psrc->sa_family) {
40354263Sshin#ifdef INET
40454263Sshin	case AF_INET:
40554263Sshin		error = in_gif_output(ifp, dst->sa_family, m, rt);
40654263Sshin		break;
40754263Sshin#endif
40854263Sshin#ifdef INET6
40954263Sshin	case AF_INET6:
41054263Sshin		error = in6_gif_output(ifp, dst->sa_family, m, rt);
41154263Sshin		break;
41254263Sshin#endif
41354263Sshin	default:
41462587Sitojun		m_freem(m);
41554263Sshin		error = ENETDOWN;
41678064Sume		goto end;
41754263Sshin	}
41854263Sshin
41954263Sshin  end:
42054263Sshin	called = 0;		/* reset recursion counter */
42178064Sume	if (error)
42278064Sume		ifp->if_oerrors++;
42354263Sshin	return error;
42454263Sshin}
42554263Sshin
42654263Sshinvoid
42754263Sshingif_input(m, af, gifp)
42854263Sshin	struct mbuf *m;
42954263Sshin	int af;
43054263Sshin	struct ifnet *gifp;
43154263Sshin{
43269152Sjlemon	int isr;
43378064Sume	struct ifqueue *ifq = 0;
43454263Sshin
43554263Sshin	if (gifp == NULL) {
43654263Sshin		/* just in case */
43754263Sshin		m_freem(m);
43854263Sshin		return;
43954263Sshin	}
44054263Sshin
44162587Sitojun	m->m_pkthdr.rcvif = gifp;
442101182Srwatson
443101182Srwatson#ifdef MAC
444101182Srwatson	mac_create_mbuf_from_ifnet(gifp, m);
445101182Srwatson#endif
446101182Srwatson
44754263Sshin	if (gifp->if_bpf) {
44854263Sshin		/*
44954263Sshin		 * We need to prepend the address family as
45054263Sshin		 * a four byte field.  Cons up a dummy header
45154263Sshin		 * to pacify bpf.  This is safe because bpf
45254263Sshin		 * will only read from the mbuf (i.e., it won't
45354263Sshin		 * try to free it or keep a pointer a to it).
45454263Sshin		 */
45554263Sshin		struct mbuf m0;
45678064Sume		u_int32_t af1 = af;
45762587Sitojun
45854263Sshin		m0.m_next = m;
45954263Sshin		m0.m_len = 4;
46078064Sume		m0.m_data = (char *)&af1;
46162587Sitojun
46254263Sshin		bpf_mtap(gifp, &m0);
46354263Sshin	}
46454263Sshin
46583998Sbrooks	if (ng_gif_input_p != NULL) {
46683998Sbrooks		(*ng_gif_input_p)(gifp, &m, af);
46783998Sbrooks		if (m == NULL)
46883998Sbrooks			return;
46983998Sbrooks	}
47083998Sbrooks
47154263Sshin	/*
47254263Sshin	 * Put the packet to the network layer input queue according to the
47354263Sshin	 * specified address family.
47454263Sshin	 * Note: older versions of gif_input directly called network layer
47595023Ssuz	 * input functions, e.g. ip6_input, here.  We changed the policy to
47654263Sshin	 * prevent too many recursive calls of such input functions, which
47795023Ssuz	 * might cause kernel panic.  But the change may introduce another
47854263Sshin	 * problem; if the input queue is full, packets are discarded.
47995023Ssuz	 * The kernel stack overflow really happened, and we believed
48095023Ssuz	 * queue-full rarely occurs, so we changed the policy.
48154263Sshin	 */
48254263Sshin	switch (af) {
48354263Sshin#ifdef INET
48454263Sshin	case AF_INET:
48554263Sshin		ifq = &ipintrq;
48654263Sshin		isr = NETISR_IP;
48754263Sshin		break;
48854263Sshin#endif
48954263Sshin#ifdef INET6
49054263Sshin	case AF_INET6:
49154263Sshin		ifq = &ip6intrq;
49254263Sshin		isr = NETISR_IPV6;
49354263Sshin		break;
49454263Sshin#endif
49554263Sshin	default:
49683998Sbrooks		if (ng_gif_input_orphan_p != NULL)
49783998Sbrooks			(*ng_gif_input_orphan_p)(gifp, m, af);
49883998Sbrooks		else
49983998Sbrooks			m_freem(m);
50054263Sshin		return;
50154263Sshin	}
50254263Sshin
50369152Sjlemon	gifp->if_ipackets++;
50469152Sjlemon	gifp->if_ibytes += m->m_pkthdr.len;
50569152Sjlemon	(void) IF_HANDOFF(ifq, m, NULL);
50654263Sshin	/* we need schednetisr since the address family may change */
50754263Sshin	schednetisr(isr);
50854263Sshin
50954263Sshin	return;
51054263Sshin}
51154263Sshin
51262587Sitojun/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
51354263Sshinint
51454263Sshingif_ioctl(ifp, cmd, data)
51554263Sshin	struct ifnet *ifp;
51654263Sshin	u_long cmd;
51754263Sshin	caddr_t data;
51854263Sshin{
51954263Sshin	struct gif_softc *sc  = (struct gif_softc*)ifp;
52054263Sshin	struct ifreq     *ifr = (struct ifreq*)data;
52154263Sshin	int error = 0, size;
52262587Sitojun	struct sockaddr *dst, *src;
52362587Sitojun	struct sockaddr *sa;
52477658Syar	int s;
52579106Sbrooks	struct ifnet *ifp2;
52662587Sitojun	struct gif_softc *sc2;
52762587Sitojun
52854263Sshin	switch (cmd) {
52954263Sshin	case SIOCSIFADDR:
53054263Sshin		break;
53162587Sitojun
53254263Sshin	case SIOCSIFDSTADDR:
53354263Sshin		break;
53454263Sshin
53554263Sshin	case SIOCADDMULTI:
53654263Sshin	case SIOCDELMULTI:
53754263Sshin		break;
53854263Sshin
53962587Sitojun#ifdef	SIOCSIFMTU /* xxx */
54054263Sshin	case SIOCGIFMTU:
54154263Sshin		break;
54262587Sitojun
54354263Sshin	case SIOCSIFMTU:
54454263Sshin		{
54554263Sshin			u_long mtu;
54654263Sshin			mtu = ifr->ifr_mtu;
54754263Sshin			if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
54854263Sshin				return (EINVAL);
54954263Sshin			}
55054263Sshin			ifp->if_mtu = mtu;
55154263Sshin		}
55254263Sshin		break;
55362587Sitojun#endif /* SIOCSIFMTU */
55454263Sshin
55554263Sshin	case SIOCSIFPHYADDR:
55654263Sshin#ifdef INET6
55754263Sshin	case SIOCSIFPHYADDR_IN6:
55854263Sshin#endif /* INET6 */
55978064Sume	case SIOCSLIFPHYADDR:
56062587Sitojun		switch (cmd) {
56178064Sume#ifdef INET
56262587Sitojun		case SIOCSIFPHYADDR:
56354263Sshin			src = (struct sockaddr *)
56454263Sshin				&(((struct in_aliasreq *)data)->ifra_addr);
56554263Sshin			dst = (struct sockaddr *)
56654263Sshin				&(((struct in_aliasreq *)data)->ifra_dstaddr);
56762587Sitojun			break;
56878064Sume#endif
56962587Sitojun#ifdef INET6
57062587Sitojun		case SIOCSIFPHYADDR_IN6:
57162587Sitojun			src = (struct sockaddr *)
57262587Sitojun				&(((struct in6_aliasreq *)data)->ifra_addr);
57362587Sitojun			dst = (struct sockaddr *)
57462587Sitojun				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
57562587Sitojun			break;
57662587Sitojun#endif
57778064Sume		case SIOCSLIFPHYADDR:
57878064Sume			src = (struct sockaddr *)
57978064Sume				&(((struct if_laddrreq *)data)->addr);
58078064Sume			dst = (struct sockaddr *)
58178064Sume				&(((struct if_laddrreq *)data)->dstaddr);
58291327Sbrooks		default:
58391327Sbrooks			error = EADDRNOTAVAIL;
58491327Sbrooks			goto bad;
58562587Sitojun		}
58654263Sshin
58778064Sume		/* sa_family must be equal */
58878064Sume		if (src->sa_family != dst->sa_family)
58978064Sume			return EINVAL;
59078064Sume
59178064Sume		/* validate sa_len */
59278064Sume		switch (src->sa_family) {
59378064Sume#ifdef INET
59478064Sume		case AF_INET:
59578064Sume			if (src->sa_len != sizeof(struct sockaddr_in))
59678064Sume				return EINVAL;
59778064Sume			break;
59878064Sume#endif
59978064Sume#ifdef INET6
60078064Sume		case AF_INET6:
60178064Sume			if (src->sa_len != sizeof(struct sockaddr_in6))
60278064Sume				return EINVAL;
60378064Sume			break;
60478064Sume#endif
60578064Sume		default:
60678064Sume			return EAFNOSUPPORT;
60778064Sume		}
60878064Sume		switch (dst->sa_family) {
60978064Sume#ifdef INET
61078064Sume		case AF_INET:
61178064Sume			if (dst->sa_len != sizeof(struct sockaddr_in))
61278064Sume				return EINVAL;
61378064Sume			break;
61478064Sume#endif
61578064Sume#ifdef INET6
61678064Sume		case AF_INET6:
61778064Sume			if (dst->sa_len != sizeof(struct sockaddr_in6))
61878064Sume				return EINVAL;
61978064Sume			break;
62078064Sume#endif
62178064Sume		default:
62278064Sume			return EAFNOSUPPORT;
62378064Sume		}
62478064Sume
62578064Sume		/* check sa_family looks sane for the cmd */
62678064Sume		switch (cmd) {
62778064Sume		case SIOCSIFPHYADDR:
62878064Sume			if (src->sa_family == AF_INET)
62978064Sume				break;
63078064Sume			return EAFNOSUPPORT;
63178064Sume#ifdef INET6
63278064Sume		case SIOCSIFPHYADDR_IN6:
63378064Sume			if (src->sa_family == AF_INET6)
63478064Sume				break;
63578064Sume			return EAFNOSUPPORT;
63678064Sume#endif /* INET6 */
63778064Sume		case SIOCSLIFPHYADDR:
63878064Sume			/* checks done in the above */
63978064Sume			break;
64078064Sume		}
64178064Sume
64279106Sbrooks		TAILQ_FOREACH(ifp2, &ifnet, if_link) {
64379106Sbrooks			if (strcmp(ifp2->if_name, GIFNAME) != 0)
64479106Sbrooks				continue;
64579106Sbrooks			sc2 = ifp2->if_softc;
64662587Sitojun			if (sc2 == sc)
64762587Sitojun				continue;
64862587Sitojun			if (!sc2->gif_pdst || !sc2->gif_psrc)
64962587Sitojun				continue;
65062587Sitojun			if (sc2->gif_pdst->sa_family != dst->sa_family ||
65162587Sitojun			    sc2->gif_pdst->sa_len != dst->sa_len ||
65262587Sitojun			    sc2->gif_psrc->sa_family != src->sa_family ||
65362587Sitojun			    sc2->gif_psrc->sa_len != src->sa_len)
65462587Sitojun				continue;
65591270Sbrooks
65691270Sbrooks			/*
65791270Sbrooks			 * Disallow parallel tunnels unless instructed
65891270Sbrooks			 * otherwise.
65991270Sbrooks			 */
66091270Sbrooks			if (!parallel_tunnels &&
66191270Sbrooks			    bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
66262587Sitojun			    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
66362587Sitojun				error = EADDRNOTAVAIL;
66462587Sitojun				goto bad;
66562587Sitojun			}
66654263Sshin
66762587Sitojun			/* can't configure multiple multi-dest interfaces */
66862587Sitojun#define multidest(x) \
66962587Sitojun	(((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
67057903Sshin#ifdef INET6
67162587Sitojun#define multidest6(x) \
67262587Sitojun	(IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
67357903Sshin#endif
67462587Sitojun			if (dst->sa_family == AF_INET &&
67562587Sitojun			    multidest(dst) && multidest(sc2->gif_pdst)) {
67662587Sitojun				error = EADDRNOTAVAIL;
67762587Sitojun				goto bad;
67862587Sitojun			}
67962587Sitojun#ifdef INET6
68062587Sitojun			if (dst->sa_family == AF_INET6 &&
68162587Sitojun			    multidest6(dst) && multidest6(sc2->gif_pdst)) {
68262587Sitojun				error = EADDRNOTAVAIL;
68362587Sitojun				goto bad;
68462587Sitojun			}
68562587Sitojun#endif
68662587Sitojun		}
68757903Sshin
68862587Sitojun		if (sc->gif_psrc)
68954263Sshin			free((caddr_t)sc->gif_psrc, M_IFADDR);
69078064Sume		sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
69178064Sume		bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
69254263Sshin		sc->gif_psrc = sa;
69354263Sshin
69462587Sitojun		if (sc->gif_pdst)
69562587Sitojun			free((caddr_t)sc->gif_pdst, M_IFADDR);
69678064Sume		sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
69778064Sume		bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
69854263Sshin		sc->gif_pdst = sa;
69954263Sshin
70077658Syar		ifp->if_flags |= IFF_RUNNING;
70177658Syar		s = splimp();
70277658Syar		if_up(ifp);	/* mark interface UP and send up RTM_IFINFO */
70377658Syar		splx(s);
70454263Sshin
70562587Sitojun		error = 0;
70662587Sitojun		break;
70762587Sitojun
70862587Sitojun#ifdef SIOCDIFPHYADDR
70962587Sitojun	case SIOCDIFPHYADDR:
71062587Sitojun		if (sc->gif_psrc) {
71162587Sitojun			free((caddr_t)sc->gif_psrc, M_IFADDR);
71262587Sitojun			sc->gif_psrc = NULL;
71357536Sshin		}
71462587Sitojun		if (sc->gif_pdst) {
71562587Sitojun			free((caddr_t)sc->gif_pdst, M_IFADDR);
71662587Sitojun			sc->gif_pdst = NULL;
71762587Sitojun		}
71878064Sume		/* change the IFF_{UP, RUNNING} flag as well? */
71954263Sshin		break;
72062587Sitojun#endif
72162587Sitojun
72254263Sshin	case SIOCGIFPSRCADDR:
72354263Sshin#ifdef INET6
72454263Sshin	case SIOCGIFPSRCADDR_IN6:
72554263Sshin#endif /* INET6 */
72654263Sshin		if (sc->gif_psrc == NULL) {
72754263Sshin			error = EADDRNOTAVAIL;
72854263Sshin			goto bad;
72954263Sshin		}
73054263Sshin		src = sc->gif_psrc;
73178064Sume		switch (cmd) {
73254263Sshin#ifdef INET
73378064Sume		case SIOCGIFPSRCADDR:
73454263Sshin			dst = &ifr->ifr_addr;
73578064Sume			size = sizeof(ifr->ifr_addr);
73654263Sshin			break;
73754263Sshin#endif /* INET */
73854263Sshin#ifdef INET6
73978064Sume		case SIOCGIFPSRCADDR_IN6:
74054263Sshin			dst = (struct sockaddr *)
74154263Sshin				&(((struct in6_ifreq *)data)->ifr_addr);
74278064Sume			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
74354263Sshin			break;
74454263Sshin#endif /* INET6 */
74554263Sshin		default:
74654263Sshin			error = EADDRNOTAVAIL;
74754263Sshin			goto bad;
74854263Sshin		}
74978064Sume		if (src->sa_len > size)
75078064Sume			return EINVAL;
75178064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
75254263Sshin		break;
75362587Sitojun
75454263Sshin	case SIOCGIFPDSTADDR:
75554263Sshin#ifdef INET6
75654263Sshin	case SIOCGIFPDSTADDR_IN6:
75754263Sshin#endif /* INET6 */
75854263Sshin		if (sc->gif_pdst == NULL) {
75954263Sshin			error = EADDRNOTAVAIL;
76054263Sshin			goto bad;
76154263Sshin		}
76254263Sshin		src = sc->gif_pdst;
76378064Sume		switch (cmd) {
76454263Sshin#ifdef INET
76578064Sume		case SIOCGIFPDSTADDR:
76654263Sshin			dst = &ifr->ifr_addr;
76778064Sume			size = sizeof(ifr->ifr_addr);
76854263Sshin			break;
76954263Sshin#endif /* INET */
77054263Sshin#ifdef INET6
77178064Sume		case SIOCGIFPDSTADDR_IN6:
77254263Sshin			dst = (struct sockaddr *)
77354263Sshin				&(((struct in6_ifreq *)data)->ifr_addr);
77478064Sume			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
77554263Sshin			break;
77654263Sshin#endif /* INET6 */
77754263Sshin		default:
77854263Sshin			error = EADDRNOTAVAIL;
77954263Sshin			goto bad;
78054263Sshin		}
78178064Sume		if (src->sa_len > size)
78278064Sume			return EINVAL;
78378064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
78454263Sshin		break;
78554263Sshin
78678064Sume	case SIOCGLIFPHYADDR:
78778064Sume		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
78878064Sume			error = EADDRNOTAVAIL;
78978064Sume			goto bad;
79078064Sume		}
79178064Sume
79278064Sume		/* copy src */
79378064Sume		src = sc->gif_psrc;
79478064Sume		dst = (struct sockaddr *)
79578064Sume			&(((struct if_laddrreq *)data)->addr);
79678064Sume		size = sizeof(((struct if_laddrreq *)data)->addr);
79778064Sume		if (src->sa_len > size)
79878064Sume			return EINVAL;
79978064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
80078064Sume
80178064Sume		/* copy dst */
80278064Sume		src = sc->gif_pdst;
80378064Sume		dst = (struct sockaddr *)
80478064Sume			&(((struct if_laddrreq *)data)->dstaddr);
80578064Sume		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
80678064Sume		if (src->sa_len > size)
80778064Sume			return EINVAL;
80878064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
80978064Sume		break;
81078064Sume
81154263Sshin	case SIOCSIFFLAGS:
81262587Sitojun		/* if_ioctl() takes care of it */
81354263Sshin		break;
81454263Sshin
81554263Sshin	default:
81654263Sshin		error = EINVAL;
81754263Sshin		break;
81854263Sshin	}
81954263Sshin bad:
82054263Sshin	return error;
82154263Sshin}
82279106Sbrooks
82379106Sbrooksvoid
82479106Sbrooksgif_delete_tunnel(sc)
82579106Sbrooks	struct gif_softc *sc;
82679106Sbrooks{
82779106Sbrooks	/* XXX: NetBSD protects this function with splsoftnet() */
82879106Sbrooks
82979106Sbrooks	if (sc->gif_psrc) {
83079106Sbrooks		free((caddr_t)sc->gif_psrc, M_IFADDR);
83179106Sbrooks		sc->gif_psrc = NULL;
83279106Sbrooks	}
83379106Sbrooks	if (sc->gif_pdst) {
83479106Sbrooks		free((caddr_t)sc->gif_pdst, M_IFADDR);
83579106Sbrooks		sc->gif_pdst = NULL;
83679106Sbrooks	}
83779106Sbrooks	/* change the IFF_UP flag as well? */
83879106Sbrooks}
839