if_gif.c revision 111119
162587Sitojun/*	$FreeBSD: head/sys/net/if_gif.c 111119 2003-02-19 05:47:46Z imp $	*/
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 *);
10179106Sbrooks
10291270SbrooksSYSCTL_DECL(_net_link);
10391270SbrooksSYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
10491270Sbrooks    "Generic Tunnel Interface");
10562587Sitojun#ifndef MAX_GIF_NEST
10662587Sitojun/*
10791270Sbrooks * This macro controls the default upper limitation on nesting of gif tunnels.
10862587Sitojun * Since, setting a large value to this macro with a careless configuration
10962587Sitojun * may introduce system crash, we don't allow any nestings by default.
11062587Sitojun * If you need to configure nested gif tunnels, you can define this macro
11195023Ssuz * in your kernel configuration file.  However, if you do so, please be
11262587Sitojun * careful to configure the tunnels so that it won't make a loop.
11362587Sitojun */
11462587Sitojun#define MAX_GIF_NEST 1
11562587Sitojun#endif
11662587Sitojunstatic int max_gif_nesting = MAX_GIF_NEST;
11791270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW,
11891270Sbrooks    &max_gif_nesting, 0, "Max nested tunnels");
11962587Sitojun
12091270Sbrooks/*
12191270Sbrooks * By default, we disallow creation of multiple tunnels between the same
12291270Sbrooks * pair of addresses.  Some applications require this functionality so
12391270Sbrooks * we allow control over this check here.
12491270Sbrooks */
12591270Sbrooks#ifdef XBONEHACK
12691270Sbrooksstatic int parallel_tunnels = 1;
12791270Sbrooks#else
12891270Sbrooksstatic int parallel_tunnels = 0;
12991270Sbrooks#endif
13091270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW,
13191270Sbrooks    &parallel_tunnels, 0, "Allow parallel tunnels?");
13291270Sbrooks
13379106Sbrooksint
13479106Sbrooksgif_clone_create(ifc, unit)
13579106Sbrooks	struct if_clone *ifc;
13692081Smux	int unit;
13754263Sshin{
13878064Sume	struct gif_softc *sc;
13954263Sshin
140111119Simp	sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK);
14179106Sbrooks	bzero(sc, sizeof(struct gif_softc));
14279106Sbrooks
14379106Sbrooks	sc->gif_if.if_softc = sc;
14479106Sbrooks	sc->gif_if.if_name = GIFNAME;
14592081Smux	sc->gif_if.if_unit = unit;
14679106Sbrooks
147105293Sume	gifattach0(sc);
148105293Sume
149105293Sume	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
150105293Sume	return (0);
151105293Sume}
152105293Sume
153105293Sumevoid
154105293Sumegifattach0(sc)
155105293Sume	struct gif_softc *sc;
156105293Sume{
157105293Sume
15879106Sbrooks	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
15962587Sitojun
160105293Sume	sc->gif_if.if_addrlen = 0;
16179106Sbrooks	sc->gif_if.if_mtu    = GIF_MTU;
16279106Sbrooks	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
16378064Sume#if 0
16479106Sbrooks	/* turn off ingress filter */
16579106Sbrooks	sc->gif_if.if_flags  |= IFF_LINK2;
16678064Sume#endif
16779106Sbrooks	sc->gif_if.if_ioctl  = gif_ioctl;
16879106Sbrooks	sc->gif_if.if_output = gif_output;
16979106Sbrooks	sc->gif_if.if_type   = IFT_GIF;
17079106Sbrooks	sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
17179106Sbrooks	if_attach(&sc->gif_if);
17279106Sbrooks	bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
17383998Sbrooks	if (ng_gif_attach_p != NULL)
17483998Sbrooks		(*ng_gif_attach_p)(&sc->gif_if);
17579106Sbrooks}
17679106Sbrooks
17797289Sbrooksvoid
17879106Sbrooksgif_clone_destroy(ifp)
17979106Sbrooks	struct ifnet *ifp;
18079106Sbrooks{
18179106Sbrooks	int err;
18279106Sbrooks	struct gif_softc *sc = ifp->if_softc;
18379106Sbrooks
184105293Sume	gif_delete_tunnel(&sc->gif_if);
185105293Sume	LIST_REMOVE(sc, gif_list);
186105293Sume#ifdef INET6
187105293Sume	if (sc->encap_cookie6 != NULL) {
188105293Sume		err = encap_detach(sc->encap_cookie6);
189105293Sume		KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
190105293Sume	}
191105293Sume#endif
192105293Sume#ifdef INET
19379106Sbrooks	if (sc->encap_cookie4 != NULL) {
19479106Sbrooks		err = encap_detach(sc->encap_cookie4);
19579106Sbrooks		KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
19679106Sbrooks	}
197105293Sume#endif
19879106Sbrooks
19983998Sbrooks	if (ng_gif_detach_p != NULL)
20083998Sbrooks		(*ng_gif_detach_p)(ifp);
20179106Sbrooks	bpfdetach(ifp);
20279106Sbrooks	if_detach(ifp);
20379106Sbrooks
20479106Sbrooks	free(sc, M_GIF);
20579106Sbrooks}
20679106Sbrooks
20779106Sbrooksstatic int
20879106Sbrooksgifmodevent(mod, type, data)
20979106Sbrooks	module_t mod;
21079106Sbrooks	int type;
21179106Sbrooks	void *data;
21279106Sbrooks{
21379106Sbrooks
21479106Sbrooks	switch (type) {
21579106Sbrooks	case MOD_LOAD:
21683997Sbrooks		LIST_INIT(&gif_softc_list);
21779106Sbrooks		if_clone_attach(&gif_cloner);
21879106Sbrooks
21979106Sbrooks#ifdef INET6
22079106Sbrooks		ip6_gif_hlim = GIF_HLIM;
22162587Sitojun#endif
22279106Sbrooks
22379106Sbrooks		break;
22479106Sbrooks	case MOD_UNLOAD:
22579106Sbrooks		if_clone_detach(&gif_cloner);
22679106Sbrooks
22783997Sbrooks		while (!LIST_EMPTY(&gif_softc_list))
22883997Sbrooks			gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if);
22979106Sbrooks
23079106Sbrooks#ifdef INET6
23179106Sbrooks		ip6_gif_hlim = 0;
23262587Sitojun#endif
23379106Sbrooks		break;
23454263Sshin	}
23579106Sbrooks	return 0;
23654263Sshin}
23754263Sshin
23879106Sbrooksstatic moduledata_t gif_mod = {
23979106Sbrooks	"if_gif",
24079106Sbrooks	gifmodevent,
24179106Sbrooks	0
24279106Sbrooks};
24354263Sshin
24479106SbrooksDECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
24583997SbrooksMODULE_VERSION(if_gif, 1);
24679106Sbrooks
247105293Sumeint
24862587Sitojungif_encapcheck(m, off, proto, arg)
24962587Sitojun	const struct mbuf *m;
25062587Sitojun	int off;
25162587Sitojun	int proto;
25262587Sitojun	void *arg;
25362587Sitojun{
25462587Sitojun	struct ip ip;
25562587Sitojun	struct gif_softc *sc;
25662587Sitojun
25762587Sitojun	sc = (struct gif_softc *)arg;
25862587Sitojun	if (sc == NULL)
25962587Sitojun		return 0;
26062587Sitojun
26162587Sitojun	if ((sc->gif_if.if_flags & IFF_UP) == 0)
26262587Sitojun		return 0;
26362587Sitojun
26462587Sitojun	/* no physical address */
26562587Sitojun	if (!sc->gif_psrc || !sc->gif_pdst)
26662587Sitojun		return 0;
26762587Sitojun
26862587Sitojun	switch (proto) {
26962587Sitojun#ifdef INET
27062587Sitojun	case IPPROTO_IPV4:
27162587Sitojun		break;
27262587Sitojun#endif
27362587Sitojun#ifdef INET6
27462587Sitojun	case IPPROTO_IPV6:
27562587Sitojun		break;
27662587Sitojun#endif
27762587Sitojun	default:
27862587Sitojun		return 0;
27962587Sitojun	}
28062587Sitojun
281105339Sume	/* Bail on short packets */
282105339Sume	if (m->m_pkthdr.len < sizeof(ip))
283105339Sume		return 0;
284105339Sume
28591327Sbrooks	m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
28662587Sitojun
28762587Sitojun	switch (ip.ip_v) {
28862587Sitojun#ifdef INET
28962587Sitojun	case 4:
29062587Sitojun		if (sc->gif_psrc->sa_family != AF_INET ||
29162587Sitojun		    sc->gif_pdst->sa_family != AF_INET)
29262587Sitojun			return 0;
29362587Sitojun		return gif_encapcheck4(m, off, proto, arg);
29462587Sitojun#endif
29562587Sitojun#ifdef INET6
29662587Sitojun	case 6:
297105293Sume		if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
298105293Sume			return 0;
29962587Sitojun		if (sc->gif_psrc->sa_family != AF_INET6 ||
30062587Sitojun		    sc->gif_pdst->sa_family != AF_INET6)
30162587Sitojun			return 0;
30262587Sitojun		return gif_encapcheck6(m, off, proto, arg);
30362587Sitojun#endif
30462587Sitojun	default:
30562587Sitojun		return 0;
30662587Sitojun	}
30762587Sitojun}
30862587Sitojun
30954263Sshinint
31054263Sshingif_output(ifp, m, dst, rt)
31154263Sshin	struct ifnet *ifp;
31254263Sshin	struct mbuf *m;
31354263Sshin	struct sockaddr *dst;
31454263Sshin	struct rtentry *rt;	/* added in net2 */
31554263Sshin{
31678064Sume	struct gif_softc *sc = (struct gif_softc*)ifp;
31754263Sshin	int error = 0;
318103273Ssobomax	static int called = 0;	/* XXX: MUTEX */
31954263Sshin
320101182Srwatson#ifdef MAC
321101182Srwatson	error = mac_check_ifnet_transmit(ifp, m);
322101739Srwatson	if (error) {
323101739Srwatson		m_freem(m);
324101739Srwatson		goto end;
325101739Srwatson	}
326101182Srwatson#endif
327101182Srwatson
32854263Sshin	/*
32954263Sshin	 * gif may cause infinite recursion calls when misconfigured.
33054263Sshin	 * We'll prevent this by introducing upper limit.
331103273Ssobomax	 * XXX: this mechanism may introduce another problem about
332103273Ssobomax	 *      mutual exclusion of the variable CALLED, especially if we
333103273Ssobomax	 *      use kernel thread.
33454263Sshin	 */
335103273Ssobomax	if (++called > max_gif_nesting) {
33654263Sshin		log(LOG_NOTICE,
33754263Sshin		    "gif_output: recursively called too many times(%d)\n",
338103273Ssobomax		    called);
33954263Sshin		m_freem(m);
34054263Sshin		error = EIO;	/* is there better errno? */
34154263Sshin		goto end;
34254263Sshin	}
34362587Sitojun
34454263Sshin	m->m_flags &= ~(M_BCAST|M_MCAST);
34554263Sshin	if (!(ifp->if_flags & IFF_UP) ||
34654263Sshin	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
34754263Sshin		m_freem(m);
34854263Sshin		error = ENETDOWN;
34954263Sshin		goto end;
35054263Sshin	}
35154263Sshin
35254263Sshin	if (ifp->if_bpf) {
35354263Sshin		/*
35454263Sshin		 * We need to prepend the address family as
35554263Sshin		 * a four byte field.  Cons up a dummy header
35654263Sshin		 * to pacify bpf.  This is safe because bpf
35754263Sshin		 * will only read from the mbuf (i.e., it won't
35854263Sshin		 * try to free it or keep a pointer a to it).
35954263Sshin		 */
36054263Sshin		struct mbuf m0;
36178064Sume		u_int32_t af = dst->sa_family;
36254263Sshin
36354263Sshin		m0.m_next = m;
36454263Sshin		m0.m_len = 4;
36554263Sshin		m0.m_data = (char *)&af;
36662587Sitojun
367106939Ssam		BPF_MTAP(ifp, &m0);
36854263Sshin	}
36962587Sitojun	ifp->if_opackets++;
37054263Sshin	ifp->if_obytes += m->m_pkthdr.len;
37154263Sshin
37278064Sume	/* inner AF-specific encapsulation */
37378064Sume
37462587Sitojun	/* XXX should we check if our outer source is legal? */
37562587Sitojun
37678064Sume	/* dispatch to output logic based on outer AF */
37754263Sshin	switch (sc->gif_psrc->sa_family) {
37854263Sshin#ifdef INET
37954263Sshin	case AF_INET:
380105340Sume		error = in_gif_output(ifp, dst->sa_family, m);
38154263Sshin		break;
38254263Sshin#endif
38354263Sshin#ifdef INET6
38454263Sshin	case AF_INET6:
385105340Sume		error = in6_gif_output(ifp, dst->sa_family, m);
38654263Sshin		break;
38754263Sshin#endif
38854263Sshin	default:
38962587Sitojun		m_freem(m);
39054263Sshin		error = ENETDOWN;
39178064Sume		goto end;
39254263Sshin	}
39354263Sshin
39454263Sshin  end:
395103273Ssobomax	called = 0;		/* reset recursion counter */
39678064Sume	if (error)
39778064Sume		ifp->if_oerrors++;
39854263Sshin	return error;
39954263Sshin}
40054263Sshin
40154263Sshinvoid
402105338Sumegif_input(m, af, ifp)
40354263Sshin	struct mbuf *m;
40454263Sshin	int af;
405105338Sume	struct ifnet *ifp;
40654263Sshin{
40769152Sjlemon	int isr;
408105339Sume	struct ifqueue *ifq = NULL;
40954263Sshin
410105338Sume	if (ifp == NULL) {
41154263Sshin		/* just in case */
41254263Sshin		m_freem(m);
41354263Sshin		return;
41454263Sshin	}
41554263Sshin
416105338Sume	m->m_pkthdr.rcvif = ifp;
417101182Srwatson
418101182Srwatson#ifdef MAC
419105338Sume	mac_create_mbuf_from_ifnet(ifp, m);
420101182Srwatson#endif
421101182Srwatson
422105338Sume	if (ifp->if_bpf) {
42354263Sshin		/*
42454263Sshin		 * We need to prepend the address family as
42554263Sshin		 * a four byte field.  Cons up a dummy header
42654263Sshin		 * to pacify bpf.  This is safe because bpf
42754263Sshin		 * will only read from the mbuf (i.e., it won't
42854263Sshin		 * try to free it or keep a pointer a to it).
42954263Sshin		 */
43054263Sshin		struct mbuf m0;
43178064Sume		u_int32_t af1 = af;
43262587Sitojun
43354263Sshin		m0.m_next = m;
43454263Sshin		m0.m_len = 4;
43578064Sume		m0.m_data = (char *)&af1;
43662587Sitojun
437106939Ssam		BPF_MTAP(ifp, &m0);
43854263Sshin	}
43954263Sshin
44083998Sbrooks	if (ng_gif_input_p != NULL) {
441105338Sume		(*ng_gif_input_p)(ifp, &m, af);
44283998Sbrooks		if (m == NULL)
44383998Sbrooks			return;
44483998Sbrooks	}
44583998Sbrooks
44654263Sshin	/*
44754263Sshin	 * Put the packet to the network layer input queue according to the
44854263Sshin	 * specified address family.
44954263Sshin	 * Note: older versions of gif_input directly called network layer
45095023Ssuz	 * input functions, e.g. ip6_input, here.  We changed the policy to
45154263Sshin	 * prevent too many recursive calls of such input functions, which
45295023Ssuz	 * might cause kernel panic.  But the change may introduce another
45354263Sshin	 * problem; if the input queue is full, packets are discarded.
45495023Ssuz	 * The kernel stack overflow really happened, and we believed
45595023Ssuz	 * queue-full rarely occurs, so we changed the policy.
45654263Sshin	 */
45754263Sshin	switch (af) {
45854263Sshin#ifdef INET
45954263Sshin	case AF_INET:
46054263Sshin		ifq = &ipintrq;
46154263Sshin		isr = NETISR_IP;
46254263Sshin		break;
46354263Sshin#endif
46454263Sshin#ifdef INET6
46554263Sshin	case AF_INET6:
46654263Sshin		ifq = &ip6intrq;
46754263Sshin		isr = NETISR_IPV6;
46854263Sshin		break;
46954263Sshin#endif
47054263Sshin	default:
47183998Sbrooks		if (ng_gif_input_orphan_p != NULL)
472105338Sume			(*ng_gif_input_orphan_p)(ifp, m, af);
47383998Sbrooks		else
47483998Sbrooks			m_freem(m);
47554263Sshin		return;
47654263Sshin	}
47754263Sshin
478105338Sume	ifp->if_ipackets++;
479105338Sume	ifp->if_ibytes += m->m_pkthdr.len;
48069152Sjlemon	(void) IF_HANDOFF(ifq, m, NULL);
48154263Sshin	/* we need schednetisr since the address family may change */
48254263Sshin	schednetisr(isr);
48354263Sshin
48454263Sshin	return;
48554263Sshin}
48654263Sshin
48762587Sitojun/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
48854263Sshinint
48954263Sshingif_ioctl(ifp, cmd, data)
49054263Sshin	struct ifnet *ifp;
49154263Sshin	u_long cmd;
49254263Sshin	caddr_t data;
49354263Sshin{
49454263Sshin	struct gif_softc *sc  = (struct gif_softc*)ifp;
49554263Sshin	struct ifreq     *ifr = (struct ifreq*)data;
49654263Sshin	int error = 0, size;
49762587Sitojun	struct sockaddr *dst, *src;
498105339Sume#ifdef	SIOCSIFMTU /* xxx */
499105339Sume	u_long mtu;
500105339Sume#endif
501105339Sume
50254263Sshin	switch (cmd) {
50354263Sshin	case SIOCSIFADDR:
504105293Sume		ifp->if_flags |= IFF_UP;
50554263Sshin		break;
50662587Sitojun
50754263Sshin	case SIOCSIFDSTADDR:
50854263Sshin		break;
50954263Sshin
51054263Sshin	case SIOCADDMULTI:
51154263Sshin	case SIOCDELMULTI:
51254263Sshin		break;
51354263Sshin
51462587Sitojun#ifdef	SIOCSIFMTU /* xxx */
51554263Sshin	case SIOCGIFMTU:
51654263Sshin		break;
51762587Sitojun
51854263Sshin	case SIOCSIFMTU:
519105339Sume		mtu = ifr->ifr_mtu;
520105339Sume		if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX)
521105339Sume			return (EINVAL);
522105339Sume		ifp->if_mtu = mtu;
52354263Sshin		break;
52462587Sitojun#endif /* SIOCSIFMTU */
52554263Sshin
526105339Sume#ifdef INET
52754263Sshin	case SIOCSIFPHYADDR:
528105339Sume#endif
52954263Sshin#ifdef INET6
53054263Sshin	case SIOCSIFPHYADDR_IN6:
53154263Sshin#endif /* INET6 */
53278064Sume	case SIOCSLIFPHYADDR:
53362587Sitojun		switch (cmd) {
53478064Sume#ifdef INET
53562587Sitojun		case SIOCSIFPHYADDR:
53654263Sshin			src = (struct sockaddr *)
53754263Sshin				&(((struct in_aliasreq *)data)->ifra_addr);
53854263Sshin			dst = (struct sockaddr *)
53954263Sshin				&(((struct in_aliasreq *)data)->ifra_dstaddr);
54062587Sitojun			break;
54178064Sume#endif
54262587Sitojun#ifdef INET6
54362587Sitojun		case SIOCSIFPHYADDR_IN6:
54462587Sitojun			src = (struct sockaddr *)
54562587Sitojun				&(((struct in6_aliasreq *)data)->ifra_addr);
54662587Sitojun			dst = (struct sockaddr *)
54762587Sitojun				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
54862587Sitojun			break;
54962587Sitojun#endif
55078064Sume		case SIOCSLIFPHYADDR:
55178064Sume			src = (struct sockaddr *)
55278064Sume				&(((struct if_laddrreq *)data)->addr);
55378064Sume			dst = (struct sockaddr *)
55478064Sume				&(((struct if_laddrreq *)data)->dstaddr);
555105293Sume			break;
55691327Sbrooks		default:
557105293Sume			return EINVAL;
55862587Sitojun		}
55954263Sshin
56078064Sume		/* sa_family must be equal */
56178064Sume		if (src->sa_family != dst->sa_family)
56278064Sume			return EINVAL;
56378064Sume
56478064Sume		/* validate sa_len */
56578064Sume		switch (src->sa_family) {
56678064Sume#ifdef INET
56778064Sume		case AF_INET:
56878064Sume			if (src->sa_len != sizeof(struct sockaddr_in))
56978064Sume				return EINVAL;
57078064Sume			break;
57178064Sume#endif
57278064Sume#ifdef INET6
57378064Sume		case AF_INET6:
57478064Sume			if (src->sa_len != sizeof(struct sockaddr_in6))
57578064Sume				return EINVAL;
57678064Sume			break;
57778064Sume#endif
57878064Sume		default:
57978064Sume			return EAFNOSUPPORT;
58078064Sume		}
58178064Sume		switch (dst->sa_family) {
58278064Sume#ifdef INET
58378064Sume		case AF_INET:
58478064Sume			if (dst->sa_len != sizeof(struct sockaddr_in))
58578064Sume				return EINVAL;
58678064Sume			break;
58778064Sume#endif
58878064Sume#ifdef INET6
58978064Sume		case AF_INET6:
59078064Sume			if (dst->sa_len != sizeof(struct sockaddr_in6))
59178064Sume				return EINVAL;
59278064Sume			break;
59378064Sume#endif
59478064Sume		default:
59578064Sume			return EAFNOSUPPORT;
59678064Sume		}
59778064Sume
59878064Sume		/* check sa_family looks sane for the cmd */
59978064Sume		switch (cmd) {
60078064Sume		case SIOCSIFPHYADDR:
60178064Sume			if (src->sa_family == AF_INET)
60278064Sume				break;
60378064Sume			return EAFNOSUPPORT;
60478064Sume#ifdef INET6
60578064Sume		case SIOCSIFPHYADDR_IN6:
60678064Sume			if (src->sa_family == AF_INET6)
60778064Sume				break;
60878064Sume			return EAFNOSUPPORT;
60978064Sume#endif /* INET6 */
61078064Sume		case SIOCSLIFPHYADDR:
61178064Sume			/* checks done in the above */
61278064Sume			break;
61378064Sume		}
61478064Sume
615105293Sume		error = gif_set_tunnel(&sc->gif_if, src, dst);
61662587Sitojun		break;
61762587Sitojun
61862587Sitojun#ifdef SIOCDIFPHYADDR
61962587Sitojun	case SIOCDIFPHYADDR:
620105293Sume		gif_delete_tunnel(&sc->gif_if);
62154263Sshin		break;
62262587Sitojun#endif
62362587Sitojun
62454263Sshin	case SIOCGIFPSRCADDR:
62554263Sshin#ifdef INET6
62654263Sshin	case SIOCGIFPSRCADDR_IN6:
62754263Sshin#endif /* INET6 */
62854263Sshin		if (sc->gif_psrc == NULL) {
62954263Sshin			error = EADDRNOTAVAIL;
63054263Sshin			goto bad;
63154263Sshin		}
63254263Sshin		src = sc->gif_psrc;
63378064Sume		switch (cmd) {
63454263Sshin#ifdef INET
63578064Sume		case SIOCGIFPSRCADDR:
63654263Sshin			dst = &ifr->ifr_addr;
63778064Sume			size = sizeof(ifr->ifr_addr);
63854263Sshin			break;
63954263Sshin#endif /* INET */
64054263Sshin#ifdef INET6
64178064Sume		case SIOCGIFPSRCADDR_IN6:
64254263Sshin			dst = (struct sockaddr *)
64354263Sshin				&(((struct in6_ifreq *)data)->ifr_addr);
64478064Sume			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
64554263Sshin			break;
64654263Sshin#endif /* INET6 */
64754263Sshin		default:
64854263Sshin			error = EADDRNOTAVAIL;
64954263Sshin			goto bad;
65054263Sshin		}
65178064Sume		if (src->sa_len > size)
65278064Sume			return EINVAL;
65378064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
65454263Sshin		break;
65562587Sitojun
65654263Sshin	case SIOCGIFPDSTADDR:
65754263Sshin#ifdef INET6
65854263Sshin	case SIOCGIFPDSTADDR_IN6:
65954263Sshin#endif /* INET6 */
66054263Sshin		if (sc->gif_pdst == NULL) {
66154263Sshin			error = EADDRNOTAVAIL;
66254263Sshin			goto bad;
66354263Sshin		}
66454263Sshin		src = sc->gif_pdst;
66578064Sume		switch (cmd) {
66654263Sshin#ifdef INET
66778064Sume		case SIOCGIFPDSTADDR:
66854263Sshin			dst = &ifr->ifr_addr;
66978064Sume			size = sizeof(ifr->ifr_addr);
67054263Sshin			break;
67154263Sshin#endif /* INET */
67254263Sshin#ifdef INET6
67378064Sume		case SIOCGIFPDSTADDR_IN6:
67454263Sshin			dst = (struct sockaddr *)
67554263Sshin				&(((struct in6_ifreq *)data)->ifr_addr);
67678064Sume			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
67754263Sshin			break;
67854263Sshin#endif /* INET6 */
67954263Sshin		default:
68054263Sshin			error = EADDRNOTAVAIL;
68154263Sshin			goto bad;
68254263Sshin		}
68378064Sume		if (src->sa_len > size)
68478064Sume			return EINVAL;
68578064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
68654263Sshin		break;
68754263Sshin
68878064Sume	case SIOCGLIFPHYADDR:
68978064Sume		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
69078064Sume			error = EADDRNOTAVAIL;
69178064Sume			goto bad;
69278064Sume		}
69378064Sume
69478064Sume		/* copy src */
69578064Sume		src = sc->gif_psrc;
69678064Sume		dst = (struct sockaddr *)
69778064Sume			&(((struct if_laddrreq *)data)->addr);
69878064Sume		size = sizeof(((struct if_laddrreq *)data)->addr);
69978064Sume		if (src->sa_len > size)
70078064Sume			return EINVAL;
70178064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
70278064Sume
70378064Sume		/* copy dst */
70478064Sume		src = sc->gif_pdst;
70578064Sume		dst = (struct sockaddr *)
70678064Sume			&(((struct if_laddrreq *)data)->dstaddr);
70778064Sume		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
70878064Sume		if (src->sa_len > size)
70978064Sume			return EINVAL;
71078064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
71178064Sume		break;
71278064Sume
71354263Sshin	case SIOCSIFFLAGS:
71462587Sitojun		/* if_ioctl() takes care of it */
71554263Sshin		break;
71654263Sshin
71754263Sshin	default:
71854263Sshin		error = EINVAL;
71954263Sshin		break;
72054263Sshin	}
72154263Sshin bad:
72254263Sshin	return error;
72354263Sshin}
72479106Sbrooks
725105293Sumeint
726105293Sumegif_set_tunnel(ifp, src, dst)
727105293Sume	struct ifnet *ifp;
728105293Sume	struct sockaddr *src;
729105293Sume	struct sockaddr *dst;
730105293Sume{
731105293Sume	struct gif_softc *sc = (struct gif_softc *)ifp;
732105293Sume	struct gif_softc *sc2;
733105293Sume	struct sockaddr *osrc, *odst, *sa;
734105293Sume	int s;
735105293Sume	int error = 0;
736105293Sume
737105293Sume	s = splnet();
738105293Sume
739105293Sume	LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
740105293Sume		if (sc2 == sc)
741105293Sume			continue;
742105293Sume		if (!sc2->gif_pdst || !sc2->gif_psrc)
743105293Sume			continue;
744105293Sume		if (sc2->gif_pdst->sa_family != dst->sa_family ||
745105293Sume		    sc2->gif_pdst->sa_len != dst->sa_len ||
746105293Sume		    sc2->gif_psrc->sa_family != src->sa_family ||
747105293Sume		    sc2->gif_psrc->sa_len != src->sa_len)
748105293Sume			continue;
749105293Sume
750105293Sume		/*
751105293Sume		 * Disallow parallel tunnels unless instructed
752105293Sume		 * otherwise.
753105293Sume		 */
754105293Sume		if (!parallel_tunnels &&
755105293Sume		    bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
756105293Sume		    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
757105293Sume			error = EADDRNOTAVAIL;
758105293Sume			goto bad;
759105293Sume		}
760105293Sume
761105293Sume		/* XXX both end must be valid? (I mean, not 0.0.0.0) */
762105293Sume	}
763105293Sume
764105293Sume	/* XXX we can detach from both, but be polite just in case */
765105293Sume	if (sc->gif_psrc)
766105293Sume		switch (sc->gif_psrc->sa_family) {
767105293Sume#ifdef INET
768105293Sume		case AF_INET:
769105293Sume			(void)in_gif_detach(sc);
770105293Sume			break;
771105293Sume#endif
772105293Sume#ifdef INET6
773105293Sume		case AF_INET6:
774105293Sume			(void)in6_gif_detach(sc);
775105293Sume			break;
776105293Sume#endif
777105293Sume		}
778105293Sume
779105293Sume	osrc = sc->gif_psrc;
780111119Simp	sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
781105293Sume	bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
782105293Sume	sc->gif_psrc = sa;
783105293Sume
784105293Sume	odst = sc->gif_pdst;
785111119Simp	sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
786105293Sume	bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
787105293Sume	sc->gif_pdst = sa;
788105293Sume
789105293Sume	switch (sc->gif_psrc->sa_family) {
790105293Sume#ifdef INET
791105293Sume	case AF_INET:
792105293Sume		error = in_gif_attach(sc);
793105293Sume		break;
794105293Sume#endif
795105293Sume#ifdef INET6
796105293Sume	case AF_INET6:
797105293Sume		error = in6_gif_attach(sc);
798105293Sume		break;
799105293Sume#endif
800105293Sume	}
801105293Sume	if (error) {
802105293Sume		/* rollback */
803105293Sume		free((caddr_t)sc->gif_psrc, M_IFADDR);
804105293Sume		free((caddr_t)sc->gif_pdst, M_IFADDR);
805105293Sume		sc->gif_psrc = osrc;
806105293Sume		sc->gif_pdst = odst;
807105293Sume		goto bad;
808105293Sume	}
809105293Sume
810105293Sume	if (osrc)
811105293Sume		free((caddr_t)osrc, M_IFADDR);
812105293Sume	if (odst)
813105293Sume		free((caddr_t)odst, M_IFADDR);
814105293Sume
815105293Sume	if (sc->gif_psrc && sc->gif_pdst)
816105293Sume		ifp->if_flags |= IFF_RUNNING;
817105293Sume	else
818105293Sume		ifp->if_flags &= ~IFF_RUNNING;
819105293Sume	splx(s);
820105293Sume
821105293Sume	return 0;
822105293Sume
823105293Sume bad:
824105293Sume	if (sc->gif_psrc && sc->gif_pdst)
825105293Sume		ifp->if_flags |= IFF_RUNNING;
826105293Sume	else
827105293Sume		ifp->if_flags &= ~IFF_RUNNING;
828105293Sume	splx(s);
829105293Sume
830105293Sume	return error;
831105293Sume}
832105293Sume
83379106Sbrooksvoid
834105293Sumegif_delete_tunnel(ifp)
835105293Sume	struct ifnet *ifp;
83679106Sbrooks{
837105293Sume	struct gif_softc *sc = (struct gif_softc *)ifp;
838105293Sume	int s;
83979106Sbrooks
840105293Sume	s = splnet();
841105293Sume
84279106Sbrooks	if (sc->gif_psrc) {
84379106Sbrooks		free((caddr_t)sc->gif_psrc, M_IFADDR);
84479106Sbrooks		sc->gif_psrc = NULL;
84579106Sbrooks	}
84679106Sbrooks	if (sc->gif_pdst) {
84779106Sbrooks		free((caddr_t)sc->gif_pdst, M_IFADDR);
84879106Sbrooks		sc->gif_pdst = NULL;
84979106Sbrooks	}
850105293Sume	/* it is safe to detach from both */
851105293Sume#ifdef INET
852105293Sume	(void)in_gif_detach(sc);
853105293Sume#endif
854105293Sume#ifdef INET6
855105293Sume	(void)in6_gif_detach(sc);
856105293Sume#endif
857105293Sume
858105293Sume	if (sc->gif_psrc && sc->gif_pdst)
859105293Sume		ifp->if_flags |= IFF_RUNNING;
860105293Sume	else
861105293Sume		ifp->if_flags &= ~IFF_RUNNING;
862105293Sume	splx(s);
86379106Sbrooks}
864