if_gif.c revision 89065
162587Sitojun/*	$FreeBSD: head/sys/net/if_gif.c 89065 2002-01-08 10:30:09Z msmith $	*/
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>
4554263Sshin#include <sys/syslog.h>
4662587Sitojun#include <sys/protosw.h>
4779106Sbrooks#include <sys/conf.h>
4879106Sbrooks#include <machine/bus.h>	/* XXX: Shouldn't really be required! */
4979106Sbrooks#include <sys/rman.h>
5054263Sshin#include <machine/cpu.h>
5154263Sshin
5254263Sshin#include <net/if.h>
5354263Sshin#include <net/if_types.h>
5454263Sshin#include <net/netisr.h>
5554263Sshin#include <net/route.h>
5654263Sshin#include <net/bpf.h>
5754263Sshin
5854263Sshin#include <netinet/in.h>
5954263Sshin#include <netinet/in_systm.h>
6078064Sume#include <netinet/ip.h>
6178064Sume#ifdef	INET
6254263Sshin#include <netinet/in_var.h>
6354263Sshin#include <netinet/in_gif.h>
6479106Sbrooks#include <netinet/ip_var.h>
6554263Sshin#endif	/* INET */
6654263Sshin
6754263Sshin#ifdef INET6
6854263Sshin#ifndef INET
6954263Sshin#include <netinet/in.h>
7054263Sshin#endif
7154263Sshin#include <netinet6/in6_var.h>
7254263Sshin#include <netinet/ip6.h>
7354263Sshin#include <netinet6/ip6_var.h>
7454263Sshin#include <netinet6/in6_gif.h>
7562587Sitojun#include <netinet6/ip6protosw.h>
7654263Sshin#endif /* INET6 */
7754263Sshin
7862587Sitojun#include <netinet/ip_encap.h>
7954263Sshin#include <net/if_gif.h>
8054263Sshin
8154263Sshin#include <net/net_osdep.h>
8254263Sshin
8379106Sbrooks#define GIFNAME		"gif"
8479106Sbrooks#define GIF_MAXUNIT	0x7fff	/* ifp->if_unit is only 15 bits */
8562587Sitojun
8679106Sbrooksstatic MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
8779106Sbrooksstatic struct rman gifunits[1];
8889065Smsmithstatic LIST_HEAD(, gif_softc) gif_softc_list;
8979106Sbrooks
9083998Sbrooksvoid	(*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af);
9183998Sbrooksvoid	(*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
9283998Sbrooksvoid	(*ng_gif_attach_p)(struct ifnet *ifp);
9383998Sbrooksvoid	(*ng_gif_detach_p)(struct ifnet *ifp);
9483998Sbrooks
9579106Sbrooksint	gif_clone_create __P((struct if_clone *, int *));
9679106Sbrooksvoid	gif_clone_destroy __P((struct ifnet *));
9779106Sbrooks
9879106Sbrooksstruct if_clone gif_cloner =
9979106Sbrooks    IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
10079106Sbrooks
10179106Sbrooksstatic int gifmodevent __P((module_t, int, void *));
10279106Sbrooksvoid gif_delete_tunnel __P((struct gif_softc *));
10362587Sitojunstatic int gif_encapcheck __P((const struct mbuf *, int, int, void *));
10479106Sbrooks
10562587Sitojun#ifdef INET
10679106Sbrooksextern  struct domain inetdomain;
10782884Sjulianstruct protosw in_gif_protosw =
10879106Sbrooks{ SOCK_RAW,	&inetdomain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
10979106Sbrooks  in_gif_input,	rip_output,	0,		rip_ctloutput,
11079106Sbrooks  0,
11179106Sbrooks  0,		0,		0,		0,
11279106Sbrooks  &rip_usrreqs
11379106Sbrooks};
11462587Sitojun#endif
11562587Sitojun#ifdef INET6
11679106Sbrooksextern  struct domain6 inet6domain;
11779106Sbrooksstruct ip6protosw in6_gif_protosw =
11879106Sbrooks{ SOCK_RAW,	&inet6domain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
11979106Sbrooks  in6_gif_input, rip6_output,	0,		rip6_ctloutput,
12079106Sbrooks  0,
12179106Sbrooks  0,		0,		0,		0,
12279106Sbrooks  &rip6_usrreqs
12379106Sbrooks};
12462587Sitojun#endif
12554263Sshin
12662587Sitojun#ifndef MAX_GIF_NEST
12762587Sitojun/*
12862587Sitojun * This macro controls the 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;
13862587Sitojun
13979106Sbrooksint
14079106Sbrooksgif_clone_create(ifc, unit)
14179106Sbrooks	struct if_clone *ifc;
14279106Sbrooks	int *unit;
14354263Sshin{
14479106Sbrooks	struct resource *r;
14578064Sume	struct gif_softc *sc;
14654263Sshin
14779106Sbrooks	if (*unit > GIF_MAXUNIT)
14879106Sbrooks		return (ENXIO);
14962587Sitojun
15079106Sbrooks	if (*unit < 0) {
15179106Sbrooks		r = rman_reserve_resource(gifunits, 0, GIF_MAXUNIT, 1,
15279106Sbrooks		    RF_ALLOCATED | RF_ACTIVE, NULL);
15379106Sbrooks		if (r == NULL)
15479106Sbrooks			return (ENOSPC);
15579106Sbrooks		*unit = rman_get_start(r);
15679106Sbrooks	} else {
15779106Sbrooks		r = rman_reserve_resource(gifunits, *unit, *unit, 1,
15879106Sbrooks		    RF_ALLOCATED | RF_ACTIVE, NULL);
15979106Sbrooks		if (r == NULL)
16079106Sbrooks			return (EEXIST);
16179106Sbrooks	}
16279106Sbrooks
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;
16879106Sbrooks	sc->gif_if.if_unit = *unit;
16979106Sbrooks	sc->r_unit = r;
17079106Sbrooks
17179106Sbrooks	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
17262587Sitojun#ifdef INET
17379106Sbrooks	sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
17479106Sbrooks	    gif_encapcheck, (struct protosw*)&in_gif_protosw, sc);
17579106Sbrooks	if (sc->encap_cookie4 == NULL) {
17679106Sbrooks		printf("%s: unable to attach encap4\n", if_name(&sc->gif_if));
17779106Sbrooks		free(sc, M_GIF);
17879106Sbrooks		return (EIO);	/* XXX */
17979106Sbrooks	}
18062587Sitojun#endif
18162587Sitojun#ifdef INET6
18279106Sbrooks	sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
18379106Sbrooks	    gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc);
18479106Sbrooks	if (sc->encap_cookie6 == NULL) {
18579106Sbrooks		if (sc->encap_cookie4) {
18679106Sbrooks			encap_detach(sc->encap_cookie4);
18779106Sbrooks			sc->encap_cookie4 = NULL;
18862587Sitojun		}
18979106Sbrooks		printf("%s: unable to attach encap6\n", if_name(&sc->gif_if));
19079106Sbrooks		free(sc, M_GIF);
19179106Sbrooks		return (EIO);	/* XXX */
19279106Sbrooks	}
19362587Sitojun#endif
19462587Sitojun
19579106Sbrooks	sc->gif_if.if_mtu    = GIF_MTU;
19679106Sbrooks	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
19778064Sume#if 0
19879106Sbrooks	/* turn off ingress filter */
19979106Sbrooks	sc->gif_if.if_flags  |= IFF_LINK2;
20078064Sume#endif
20179106Sbrooks	sc->gif_if.if_ioctl  = gif_ioctl;
20279106Sbrooks	sc->gif_if.if_output = gif_output;
20379106Sbrooks	sc->gif_if.if_type   = IFT_GIF;
20479106Sbrooks	sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
20579106Sbrooks	if_attach(&sc->gif_if);
20679106Sbrooks	bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
20783998Sbrooks	if (ng_gif_attach_p != NULL)
20883998Sbrooks		(*ng_gif_attach_p)(&sc->gif_if);
20983997Sbrooks	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_link);
21079106Sbrooks	return (0);
21179106Sbrooks}
21279106Sbrooks
21379106Sbrooksvoid
21479106Sbrooksgif_clone_destroy(ifp)
21579106Sbrooks	struct ifnet *ifp;
21679106Sbrooks{
21779106Sbrooks	int err;
21879106Sbrooks	struct gif_softc *sc = ifp->if_softc;
21979106Sbrooks
22079106Sbrooks	gif_delete_tunnel(sc);
22183997Sbrooks	LIST_REMOVE(sc, gif_link);
22279106Sbrooks	if (sc->encap_cookie4 != NULL) {
22379106Sbrooks		err = encap_detach(sc->encap_cookie4);
22479106Sbrooks		KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
22579106Sbrooks	}
22679106Sbrooks	if (sc->encap_cookie6 != NULL) {
22779106Sbrooks		err = encap_detach(sc->encap_cookie6);
22879106Sbrooks		KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
22979106Sbrooks	}
23079106Sbrooks
23183998Sbrooks	if (ng_gif_detach_p != NULL)
23283998Sbrooks		(*ng_gif_detach_p)(ifp);
23379106Sbrooks	bpfdetach(ifp);
23479106Sbrooks	if_detach(ifp);
23579106Sbrooks
23679106Sbrooks	err = rman_release_resource(sc->r_unit);
23779106Sbrooks	KASSERT(err == 0, ("Unexpected error freeing resource"));
23879106Sbrooks
23979106Sbrooks	free(sc, M_GIF);
24079106Sbrooks}
24179106Sbrooks
24279106Sbrooksstatic int
24379106Sbrooksgifmodevent(mod, type, data)
24479106Sbrooks	module_t mod;
24579106Sbrooks	int type;
24679106Sbrooks	void *data;
24779106Sbrooks{
24879106Sbrooks	int err;
24979106Sbrooks
25079106Sbrooks	switch (type) {
25179106Sbrooks	case MOD_LOAD:
25279106Sbrooks		gifunits->rm_type = RMAN_ARRAY;
25379106Sbrooks		gifunits->rm_descr = "configurable if_gif units";
25479106Sbrooks		err = rman_init(gifunits);
25579106Sbrooks		if (err != 0)
25679106Sbrooks			return (err);
25779106Sbrooks		err = rman_manage_region(gifunits, 0, GIF_MAXUNIT);
25879106Sbrooks		if (err != 0) {
25979106Sbrooks			printf("%s: gifunits: rman_manage_region: Failed %d\n",
26079106Sbrooks			    GIFNAME, err);
26179106Sbrooks			rman_fini(gifunits);
26279106Sbrooks			return (err);
26379106Sbrooks		}
26483997Sbrooks		LIST_INIT(&gif_softc_list);
26579106Sbrooks		if_clone_attach(&gif_cloner);
26679106Sbrooks
26779106Sbrooks#ifdef INET6
26879106Sbrooks		ip6_gif_hlim = GIF_HLIM;
26962587Sitojun#endif
27079106Sbrooks
27179106Sbrooks		break;
27279106Sbrooks	case MOD_UNLOAD:
27379106Sbrooks		if_clone_detach(&gif_cloner);
27479106Sbrooks
27583997Sbrooks		while (!LIST_EMPTY(&gif_softc_list))
27683997Sbrooks			gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if);
27779106Sbrooks
27879106Sbrooks		err = rman_fini(gifunits);
27979106Sbrooks		if (err != 0)
28079106Sbrooks			return (err);
28179106Sbrooks#ifdef INET6
28279106Sbrooks		ip6_gif_hlim = 0;
28362587Sitojun#endif
28479106Sbrooks		break;
28554263Sshin	}
28679106Sbrooks	return 0;
28754263Sshin}
28854263Sshin
28979106Sbrooksstatic moduledata_t gif_mod = {
29079106Sbrooks	"if_gif",
29179106Sbrooks	gifmodevent,
29279106Sbrooks	0
29379106Sbrooks};
29454263Sshin
29579106SbrooksDECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
29683997SbrooksMODULE_VERSION(if_gif, 1);
29779106Sbrooks
29862587Sitojunstatic int
29962587Sitojungif_encapcheck(m, off, proto, arg)
30062587Sitojun	const struct mbuf *m;
30162587Sitojun	int off;
30262587Sitojun	int proto;
30362587Sitojun	void *arg;
30462587Sitojun{
30562587Sitojun	struct ip ip;
30662587Sitojun	struct gif_softc *sc;
30762587Sitojun
30862587Sitojun	sc = (struct gif_softc *)arg;
30962587Sitojun	if (sc == NULL)
31062587Sitojun		return 0;
31162587Sitojun
31262587Sitojun	if ((sc->gif_if.if_flags & IFF_UP) == 0)
31362587Sitojun		return 0;
31462587Sitojun
31562587Sitojun	/* no physical address */
31662587Sitojun	if (!sc->gif_psrc || !sc->gif_pdst)
31762587Sitojun		return 0;
31862587Sitojun
31962587Sitojun	switch (proto) {
32062587Sitojun#ifdef INET
32162587Sitojun	case IPPROTO_IPV4:
32262587Sitojun		break;
32362587Sitojun#endif
32462587Sitojun#ifdef INET6
32562587Sitojun	case IPPROTO_IPV6:
32662587Sitojun		break;
32762587Sitojun#endif
32862587Sitojun	default:
32962587Sitojun		return 0;
33062587Sitojun	}
33162587Sitojun
33262587Sitojun	/* LINTED const cast */
33362587Sitojun	m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
33462587Sitojun
33562587Sitojun	switch (ip.ip_v) {
33662587Sitojun#ifdef INET
33762587Sitojun	case 4:
33862587Sitojun		if (sc->gif_psrc->sa_family != AF_INET ||
33962587Sitojun		    sc->gif_pdst->sa_family != AF_INET)
34062587Sitojun			return 0;
34162587Sitojun		return gif_encapcheck4(m, off, proto, arg);
34262587Sitojun#endif
34362587Sitojun#ifdef INET6
34462587Sitojun	case 6:
34562587Sitojun		if (sc->gif_psrc->sa_family != AF_INET6 ||
34662587Sitojun		    sc->gif_pdst->sa_family != AF_INET6)
34762587Sitojun			return 0;
34862587Sitojun		return gif_encapcheck6(m, off, proto, arg);
34962587Sitojun#endif
35062587Sitojun	default:
35162587Sitojun		return 0;
35262587Sitojun	}
35362587Sitojun}
35462587Sitojun
35554263Sshinint
35654263Sshingif_output(ifp, m, dst, rt)
35754263Sshin	struct ifnet *ifp;
35854263Sshin	struct mbuf *m;
35954263Sshin	struct sockaddr *dst;
36054263Sshin	struct rtentry *rt;	/* added in net2 */
36154263Sshin{
36278064Sume	struct gif_softc *sc = (struct gif_softc*)ifp;
36354263Sshin	int error = 0;
36454263Sshin	static int called = 0;	/* XXX: MUTEX */
36554263Sshin
36654263Sshin	/*
36754263Sshin	 * gif may cause infinite recursion calls when misconfigured.
36854263Sshin	 * We'll prevent this by introducing upper limit.
36954263Sshin	 * XXX: this mechanism may introduce another problem about
37054263Sshin	 *      mutual exclusion of the variable CALLED, especially if we
37154263Sshin	 *      use kernel thread.
37254263Sshin	 */
37362587Sitojun	if (++called > max_gif_nesting) {
37454263Sshin		log(LOG_NOTICE,
37554263Sshin		    "gif_output: recursively called too many times(%d)\n",
37654263Sshin		    called);
37754263Sshin		m_freem(m);
37854263Sshin		error = EIO;	/* is there better errno? */
37954263Sshin		goto end;
38054263Sshin	}
38162587Sitojun
38254263Sshin	m->m_flags &= ~(M_BCAST|M_MCAST);
38354263Sshin	if (!(ifp->if_flags & IFF_UP) ||
38454263Sshin	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
38554263Sshin		m_freem(m);
38654263Sshin		error = ENETDOWN;
38754263Sshin		goto end;
38854263Sshin	}
38954263Sshin
39054263Sshin	if (ifp->if_bpf) {
39154263Sshin		/*
39254263Sshin		 * We need to prepend the address family as
39354263Sshin		 * a four byte field.  Cons up a dummy header
39454263Sshin		 * to pacify bpf.  This is safe because bpf
39554263Sshin		 * will only read from the mbuf (i.e., it won't
39654263Sshin		 * try to free it or keep a pointer a to it).
39754263Sshin		 */
39854263Sshin		struct mbuf m0;
39978064Sume		u_int32_t af = dst->sa_family;
40054263Sshin
40154263Sshin		m0.m_next = m;
40254263Sshin		m0.m_len = 4;
40354263Sshin		m0.m_data = (char *)&af;
40462587Sitojun
40554263Sshin		bpf_mtap(ifp, &m0);
40654263Sshin	}
40762587Sitojun	ifp->if_opackets++;
40854263Sshin	ifp->if_obytes += m->m_pkthdr.len;
40954263Sshin
41078064Sume	/* inner AF-specific encapsulation */
41178064Sume
41262587Sitojun	/* XXX should we check if our outer source is legal? */
41362587Sitojun
41478064Sume	/* dispatch to output logic based on outer AF */
41554263Sshin	switch (sc->gif_psrc->sa_family) {
41654263Sshin#ifdef INET
41754263Sshin	case AF_INET:
41854263Sshin		error = in_gif_output(ifp, dst->sa_family, m, rt);
41954263Sshin		break;
42054263Sshin#endif
42154263Sshin#ifdef INET6
42254263Sshin	case AF_INET6:
42354263Sshin		error = in6_gif_output(ifp, dst->sa_family, m, rt);
42454263Sshin		break;
42554263Sshin#endif
42654263Sshin	default:
42762587Sitojun		m_freem(m);
42854263Sshin		error = ENETDOWN;
42978064Sume		goto end;
43054263Sshin	}
43154263Sshin
43254263Sshin  end:
43354263Sshin	called = 0;		/* reset recursion counter */
43478064Sume	if (error)
43578064Sume		ifp->if_oerrors++;
43654263Sshin	return error;
43754263Sshin}
43854263Sshin
43954263Sshinvoid
44054263Sshingif_input(m, af, gifp)
44154263Sshin	struct mbuf *m;
44254263Sshin	int af;
44354263Sshin	struct ifnet *gifp;
44454263Sshin{
44569152Sjlemon	int isr;
44678064Sume	struct ifqueue *ifq = 0;
44754263Sshin
44854263Sshin	if (gifp == NULL) {
44954263Sshin		/* just in case */
45054263Sshin		m_freem(m);
45154263Sshin		return;
45254263Sshin	}
45354263Sshin
45462587Sitojun	m->m_pkthdr.rcvif = gifp;
45562587Sitojun
45654263Sshin	if (gifp->if_bpf) {
45754263Sshin		/*
45854263Sshin		 * We need to prepend the address family as
45954263Sshin		 * a four byte field.  Cons up a dummy header
46054263Sshin		 * to pacify bpf.  This is safe because bpf
46154263Sshin		 * will only read from the mbuf (i.e., it won't
46254263Sshin		 * try to free it or keep a pointer a to it).
46354263Sshin		 */
46454263Sshin		struct mbuf m0;
46578064Sume		u_int32_t af1 = af;
46662587Sitojun
46754263Sshin		m0.m_next = m;
46854263Sshin		m0.m_len = 4;
46978064Sume		m0.m_data = (char *)&af1;
47062587Sitojun
47154263Sshin		bpf_mtap(gifp, &m0);
47254263Sshin	}
47354263Sshin
47483998Sbrooks	if (ng_gif_input_p != NULL) {
47583998Sbrooks		(*ng_gif_input_p)(gifp, &m, af);
47683998Sbrooks		if (m == NULL)
47783998Sbrooks			return;
47883998Sbrooks	}
47983998Sbrooks
48054263Sshin	/*
48154263Sshin	 * Put the packet to the network layer input queue according to the
48254263Sshin	 * specified address family.
48354263Sshin	 * Note: older versions of gif_input directly called network layer
48454263Sshin	 * input functions, e.g. ip6_input, here. We changed the policy to
48554263Sshin	 * prevent too many recursive calls of such input functions, which
48654263Sshin	 * might cause kernel panic. But the change may introduce another
48754263Sshin	 * problem; if the input queue is full, packets are discarded.
48854263Sshin	 * We believed it rarely occurs and changed the policy. If we find
48954263Sshin	 * it occurs more times than we thought, we may change the policy
49054263Sshin	 * again.
49154263Sshin	 */
49254263Sshin	switch (af) {
49354263Sshin#ifdef INET
49454263Sshin	case AF_INET:
49554263Sshin		ifq = &ipintrq;
49654263Sshin		isr = NETISR_IP;
49754263Sshin		break;
49854263Sshin#endif
49954263Sshin#ifdef INET6
50054263Sshin	case AF_INET6:
50154263Sshin		ifq = &ip6intrq;
50254263Sshin		isr = NETISR_IPV6;
50354263Sshin		break;
50454263Sshin#endif
50554263Sshin	default:
50683998Sbrooks		if (ng_gif_input_orphan_p != NULL)
50783998Sbrooks			(*ng_gif_input_orphan_p)(gifp, m, af);
50883998Sbrooks		else
50983998Sbrooks			m_freem(m);
51054263Sshin		return;
51154263Sshin	}
51254263Sshin
51369152Sjlemon	gifp->if_ipackets++;
51469152Sjlemon	gifp->if_ibytes += m->m_pkthdr.len;
51569152Sjlemon	(void) IF_HANDOFF(ifq, m, NULL);
51654263Sshin	/* we need schednetisr since the address family may change */
51754263Sshin	schednetisr(isr);
51854263Sshin
51954263Sshin	return;
52054263Sshin}
52154263Sshin
52262587Sitojun/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
52354263Sshinint
52454263Sshingif_ioctl(ifp, cmd, data)
52554263Sshin	struct ifnet *ifp;
52654263Sshin	u_long cmd;
52754263Sshin	caddr_t data;
52854263Sshin{
52954263Sshin	struct gif_softc *sc  = (struct gif_softc*)ifp;
53054263Sshin	struct ifreq     *ifr = (struct ifreq*)data;
53154263Sshin	int error = 0, size;
53262587Sitojun	struct sockaddr *dst, *src;
53362587Sitojun	struct sockaddr *sa;
53477658Syar	int s;
53579106Sbrooks	struct ifnet *ifp2;
53662587Sitojun	struct gif_softc *sc2;
53762587Sitojun
53854263Sshin	switch (cmd) {
53954263Sshin	case SIOCSIFADDR:
54054263Sshin		break;
54162587Sitojun
54254263Sshin	case SIOCSIFDSTADDR:
54354263Sshin		break;
54454263Sshin
54554263Sshin	case SIOCADDMULTI:
54654263Sshin	case SIOCDELMULTI:
54754263Sshin		break;
54854263Sshin
54962587Sitojun#ifdef	SIOCSIFMTU /* xxx */
55054263Sshin	case SIOCGIFMTU:
55154263Sshin		break;
55262587Sitojun
55354263Sshin	case SIOCSIFMTU:
55454263Sshin		{
55554263Sshin			u_long mtu;
55654263Sshin			mtu = ifr->ifr_mtu;
55754263Sshin			if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
55854263Sshin				return (EINVAL);
55954263Sshin			}
56054263Sshin			ifp->if_mtu = mtu;
56154263Sshin		}
56254263Sshin		break;
56362587Sitojun#endif /* SIOCSIFMTU */
56454263Sshin
56554263Sshin	case SIOCSIFPHYADDR:
56654263Sshin#ifdef INET6
56754263Sshin	case SIOCSIFPHYADDR_IN6:
56854263Sshin#endif /* INET6 */
56978064Sume	case SIOCSLIFPHYADDR:
57062587Sitojun		switch (cmd) {
57178064Sume#ifdef INET
57262587Sitojun		case SIOCSIFPHYADDR:
57354263Sshin			src = (struct sockaddr *)
57454263Sshin				&(((struct in_aliasreq *)data)->ifra_addr);
57554263Sshin			dst = (struct sockaddr *)
57654263Sshin				&(((struct in_aliasreq *)data)->ifra_dstaddr);
57762587Sitojun			break;
57878064Sume#endif
57962587Sitojun#ifdef INET6
58062587Sitojun		case SIOCSIFPHYADDR_IN6:
58162587Sitojun			src = (struct sockaddr *)
58262587Sitojun				&(((struct in6_aliasreq *)data)->ifra_addr);
58362587Sitojun			dst = (struct sockaddr *)
58462587Sitojun				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
58562587Sitojun			break;
58662587Sitojun#endif
58778064Sume		case SIOCSLIFPHYADDR:
58878064Sume			src = (struct sockaddr *)
58978064Sume				&(((struct if_laddrreq *)data)->addr);
59078064Sume			dst = (struct sockaddr *)
59178064Sume				&(((struct if_laddrreq *)data)->dstaddr);
59262587Sitojun		}
59354263Sshin
59478064Sume		/* sa_family must be equal */
59578064Sume		if (src->sa_family != dst->sa_family)
59678064Sume			return EINVAL;
59778064Sume
59878064Sume		/* validate sa_len */
59978064Sume		switch (src->sa_family) {
60078064Sume#ifdef INET
60178064Sume		case AF_INET:
60278064Sume			if (src->sa_len != sizeof(struct sockaddr_in))
60378064Sume				return EINVAL;
60478064Sume			break;
60578064Sume#endif
60678064Sume#ifdef INET6
60778064Sume		case AF_INET6:
60878064Sume			if (src->sa_len != sizeof(struct sockaddr_in6))
60978064Sume				return EINVAL;
61078064Sume			break;
61178064Sume#endif
61278064Sume		default:
61378064Sume			return EAFNOSUPPORT;
61478064Sume		}
61578064Sume		switch (dst->sa_family) {
61678064Sume#ifdef INET
61778064Sume		case AF_INET:
61878064Sume			if (dst->sa_len != sizeof(struct sockaddr_in))
61978064Sume				return EINVAL;
62078064Sume			break;
62178064Sume#endif
62278064Sume#ifdef INET6
62378064Sume		case AF_INET6:
62478064Sume			if (dst->sa_len != sizeof(struct sockaddr_in6))
62578064Sume				return EINVAL;
62678064Sume			break;
62778064Sume#endif
62878064Sume		default:
62978064Sume			return EAFNOSUPPORT;
63078064Sume		}
63178064Sume
63278064Sume		/* check sa_family looks sane for the cmd */
63378064Sume		switch (cmd) {
63478064Sume		case SIOCSIFPHYADDR:
63578064Sume			if (src->sa_family == AF_INET)
63678064Sume				break;
63778064Sume			return EAFNOSUPPORT;
63878064Sume#ifdef INET6
63978064Sume		case SIOCSIFPHYADDR_IN6:
64078064Sume			if (src->sa_family == AF_INET6)
64178064Sume				break;
64278064Sume			return EAFNOSUPPORT;
64378064Sume#endif /* INET6 */
64478064Sume		case SIOCSLIFPHYADDR:
64578064Sume			/* checks done in the above */
64678064Sume			break;
64778064Sume		}
64878064Sume
64979106Sbrooks		TAILQ_FOREACH(ifp2, &ifnet, if_link) {
65079106Sbrooks			if (strcmp(ifp2->if_name, GIFNAME) != 0)
65179106Sbrooks				continue;
65279106Sbrooks			sc2 = ifp2->if_softc;
65362587Sitojun			if (sc2 == sc)
65462587Sitojun				continue;
65562587Sitojun			if (!sc2->gif_pdst || !sc2->gif_psrc)
65662587Sitojun				continue;
65762587Sitojun			if (sc2->gif_pdst->sa_family != dst->sa_family ||
65862587Sitojun			    sc2->gif_pdst->sa_len != dst->sa_len ||
65962587Sitojun			    sc2->gif_psrc->sa_family != src->sa_family ||
66062587Sitojun			    sc2->gif_psrc->sa_len != src->sa_len)
66162587Sitojun				continue;
66263577Skris#ifndef XBONEHACK
66362587Sitojun			/* can't configure same pair of address onto two gifs */
66462587Sitojun			if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
66562587Sitojun			    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
66662587Sitojun				error = EADDRNOTAVAIL;
66762587Sitojun				goto bad;
66862587Sitojun			}
66963577Skris#endif
67054263Sshin
67162587Sitojun			/* can't configure multiple multi-dest interfaces */
67262587Sitojun#define multidest(x) \
67362587Sitojun	(((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
67457903Sshin#ifdef INET6
67562587Sitojun#define multidest6(x) \
67662587Sitojun	(IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
67757903Sshin#endif
67862587Sitojun			if (dst->sa_family == AF_INET &&
67962587Sitojun			    multidest(dst) && multidest(sc2->gif_pdst)) {
68062587Sitojun				error = EADDRNOTAVAIL;
68162587Sitojun				goto bad;
68262587Sitojun			}
68362587Sitojun#ifdef INET6
68462587Sitojun			if (dst->sa_family == AF_INET6 &&
68562587Sitojun			    multidest6(dst) && multidest6(sc2->gif_pdst)) {
68662587Sitojun				error = EADDRNOTAVAIL;
68762587Sitojun				goto bad;
68862587Sitojun			}
68962587Sitojun#endif
69062587Sitojun		}
69157903Sshin
69262587Sitojun		if (sc->gif_psrc)
69354263Sshin			free((caddr_t)sc->gif_psrc, M_IFADDR);
69478064Sume		sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
69578064Sume		bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
69654263Sshin		sc->gif_psrc = sa;
69754263Sshin
69862587Sitojun		if (sc->gif_pdst)
69962587Sitojun			free((caddr_t)sc->gif_pdst, M_IFADDR);
70078064Sume		sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
70178064Sume		bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
70254263Sshin		sc->gif_pdst = sa;
70354263Sshin
70477658Syar		ifp->if_flags |= IFF_RUNNING;
70577658Syar		s = splimp();
70677658Syar		if_up(ifp);	/* mark interface UP and send up RTM_IFINFO */
70777658Syar		splx(s);
70854263Sshin
70962587Sitojun		error = 0;
71062587Sitojun		break;
71162587Sitojun
71262587Sitojun#ifdef SIOCDIFPHYADDR
71362587Sitojun	case SIOCDIFPHYADDR:
71462587Sitojun		if (sc->gif_psrc) {
71562587Sitojun			free((caddr_t)sc->gif_psrc, M_IFADDR);
71662587Sitojun			sc->gif_psrc = NULL;
71757536Sshin		}
71862587Sitojun		if (sc->gif_pdst) {
71962587Sitojun			free((caddr_t)sc->gif_pdst, M_IFADDR);
72062587Sitojun			sc->gif_pdst = NULL;
72162587Sitojun		}
72278064Sume		/* change the IFF_{UP, RUNNING} flag as well? */
72354263Sshin		break;
72462587Sitojun#endif
72562587Sitojun
72654263Sshin	case SIOCGIFPSRCADDR:
72754263Sshin#ifdef INET6
72854263Sshin	case SIOCGIFPSRCADDR_IN6:
72954263Sshin#endif /* INET6 */
73054263Sshin		if (sc->gif_psrc == NULL) {
73154263Sshin			error = EADDRNOTAVAIL;
73254263Sshin			goto bad;
73354263Sshin		}
73454263Sshin		src = sc->gif_psrc;
73578064Sume		switch (cmd) {
73654263Sshin#ifdef INET
73778064Sume		case SIOCGIFPSRCADDR:
73854263Sshin			dst = &ifr->ifr_addr;
73978064Sume			size = sizeof(ifr->ifr_addr);
74054263Sshin			break;
74154263Sshin#endif /* INET */
74254263Sshin#ifdef INET6
74378064Sume		case SIOCGIFPSRCADDR_IN6:
74454263Sshin			dst = (struct sockaddr *)
74554263Sshin				&(((struct in6_ifreq *)data)->ifr_addr);
74678064Sume			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
74754263Sshin			break;
74854263Sshin#endif /* INET6 */
74954263Sshin		default:
75054263Sshin			error = EADDRNOTAVAIL;
75154263Sshin			goto bad;
75254263Sshin		}
75378064Sume		if (src->sa_len > size)
75478064Sume			return EINVAL;
75578064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
75654263Sshin		break;
75762587Sitojun
75854263Sshin	case SIOCGIFPDSTADDR:
75954263Sshin#ifdef INET6
76054263Sshin	case SIOCGIFPDSTADDR_IN6:
76154263Sshin#endif /* INET6 */
76254263Sshin		if (sc->gif_pdst == NULL) {
76354263Sshin			error = EADDRNOTAVAIL;
76454263Sshin			goto bad;
76554263Sshin		}
76654263Sshin		src = sc->gif_pdst;
76778064Sume		switch (cmd) {
76854263Sshin#ifdef INET
76978064Sume		case SIOCGIFPDSTADDR:
77054263Sshin			dst = &ifr->ifr_addr;
77178064Sume			size = sizeof(ifr->ifr_addr);
77254263Sshin			break;
77354263Sshin#endif /* INET */
77454263Sshin#ifdef INET6
77578064Sume		case SIOCGIFPDSTADDR_IN6:
77654263Sshin			dst = (struct sockaddr *)
77754263Sshin				&(((struct in6_ifreq *)data)->ifr_addr);
77878064Sume			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
77954263Sshin			break;
78054263Sshin#endif /* INET6 */
78154263Sshin		default:
78254263Sshin			error = EADDRNOTAVAIL;
78354263Sshin			goto bad;
78454263Sshin		}
78578064Sume		if (src->sa_len > size)
78678064Sume			return EINVAL;
78778064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
78854263Sshin		break;
78954263Sshin
79078064Sume	case SIOCGLIFPHYADDR:
79178064Sume		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
79278064Sume			error = EADDRNOTAVAIL;
79378064Sume			goto bad;
79478064Sume		}
79578064Sume
79678064Sume		/* copy src */
79778064Sume		src = sc->gif_psrc;
79878064Sume		dst = (struct sockaddr *)
79978064Sume			&(((struct if_laddrreq *)data)->addr);
80078064Sume		size = sizeof(((struct if_laddrreq *)data)->addr);
80178064Sume		if (src->sa_len > size)
80278064Sume			return EINVAL;
80378064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
80478064Sume
80578064Sume		/* copy dst */
80678064Sume		src = sc->gif_pdst;
80778064Sume		dst = (struct sockaddr *)
80878064Sume			&(((struct if_laddrreq *)data)->dstaddr);
80978064Sume		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
81078064Sume		if (src->sa_len > size)
81178064Sume			return EINVAL;
81278064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
81378064Sume		break;
81478064Sume
81554263Sshin	case SIOCSIFFLAGS:
81662587Sitojun		/* if_ioctl() takes care of it */
81754263Sshin		break;
81854263Sshin
81954263Sshin	default:
82054263Sshin		error = EINVAL;
82154263Sshin		break;
82254263Sshin	}
82354263Sshin bad:
82454263Sshin	return error;
82554263Sshin}
82679106Sbrooks
82779106Sbrooksvoid
82879106Sbrooksgif_delete_tunnel(sc)
82979106Sbrooks	struct gif_softc *sc;
83079106Sbrooks{
83179106Sbrooks	/* XXX: NetBSD protects this function with splsoftnet() */
83279106Sbrooks
83379106Sbrooks	if (sc->gif_psrc) {
83479106Sbrooks		free((caddr_t)sc->gif_psrc, M_IFADDR);
83579106Sbrooks		sc->gif_psrc = NULL;
83679106Sbrooks	}
83779106Sbrooks	if (sc->gif_pdst) {
83879106Sbrooks		free((caddr_t)sc->gif_pdst, M_IFADDR);
83979106Sbrooks		sc->gif_pdst = NULL;
84079106Sbrooks	}
84179106Sbrooks	/* change the IFF_UP flag as well? */
84279106Sbrooks}
843