if_gif.c revision 127303
162587Sitojun/*	$FreeBSD: head/sys/net/if_gif.c 127303 2004-03-22 14:24:26Z 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
89127303Srwatson/*
90127303Srwatson * XXX: gif_called is a recursion counter to prevent misconfiguration to
91127303Srwatson * cause unbounded looping in the network stack.  However, this is a flawed
92127303Srwatson * approach as it assumes non-reentrance in the stack.  This should be
93127303Srwatson * changed to use packet tags to track recusion..
94127303Srwatson */
95127303Srwatsonstatic int gif_called = 0;
96127303Srwatson
9783998Sbrooksvoid	(*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af);
9883998Sbrooksvoid	(*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
9983998Sbrooksvoid	(*ng_gif_attach_p)(struct ifnet *ifp);
10083998Sbrooksvoid	(*ng_gif_detach_p)(struct ifnet *ifp);
10183998Sbrooks
10292725Salfredint	gif_clone_create(struct if_clone *, int);
10397289Sbrooksvoid	gif_clone_destroy(struct ifnet *);
10479106Sbrooks
10592081Smuxstruct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif",
10697289Sbrooks    gif_clone_create, gif_clone_destroy, 0, IF_MAXUNIT);
10779106Sbrooks
10892725Salfredstatic int gifmodevent(module_t, int, void *);
10979106Sbrooks
11091270SbrooksSYSCTL_DECL(_net_link);
11191270SbrooksSYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
11291270Sbrooks    "Generic Tunnel Interface");
11362587Sitojun#ifndef MAX_GIF_NEST
11462587Sitojun/*
11591270Sbrooks * This macro controls the default upper limitation on nesting of gif tunnels.
11662587Sitojun * Since, setting a large value to this macro with a careless configuration
11762587Sitojun * may introduce system crash, we don't allow any nestings by default.
11862587Sitojun * If you need to configure nested gif tunnels, you can define this macro
11995023Ssuz * in your kernel configuration file.  However, if you do so, please be
12062587Sitojun * careful to configure the tunnels so that it won't make a loop.
12162587Sitojun */
12262587Sitojun#define MAX_GIF_NEST 1
12362587Sitojun#endif
12462587Sitojunstatic int max_gif_nesting = MAX_GIF_NEST;
12591270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW,
12691270Sbrooks    &max_gif_nesting, 0, "Max nested tunnels");
12762587Sitojun
12891270Sbrooks/*
12991270Sbrooks * By default, we disallow creation of multiple tunnels between the same
13091270Sbrooks * pair of addresses.  Some applications require this functionality so
13191270Sbrooks * we allow control over this check here.
13291270Sbrooks */
13391270Sbrooks#ifdef XBONEHACK
13491270Sbrooksstatic int parallel_tunnels = 1;
13591270Sbrooks#else
13691270Sbrooksstatic int parallel_tunnels = 0;
13791270Sbrooks#endif
13891270SbrooksSYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW,
13991270Sbrooks    &parallel_tunnels, 0, "Allow parallel tunnels?");
14091270Sbrooks
14179106Sbrooksint
14279106Sbrooksgif_clone_create(ifc, unit)
14379106Sbrooks	struct if_clone *ifc;
14492081Smux	int unit;
14554263Sshin{
14678064Sume	struct gif_softc *sc;
14754263Sshin
148111119Simp	sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK);
14979106Sbrooks	bzero(sc, sizeof(struct gif_softc));
15079106Sbrooks
15179106Sbrooks	sc->gif_if.if_softc = sc;
152121816Sbrooks	if_initname(&sc->gif_if, ifc->ifc_name, unit);
15379106Sbrooks
154105293Sume	gifattach0(sc);
155105293Sume
156105293Sume	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
157105293Sume	return (0);
158105293Sume}
159105293Sume
160105293Sumevoid
161105293Sumegifattach0(sc)
162105293Sume	struct gif_softc *sc;
163105293Sume{
164105293Sume
16579106Sbrooks	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
16662587Sitojun
167105293Sume	sc->gif_if.if_addrlen = 0;
16879106Sbrooks	sc->gif_if.if_mtu    = GIF_MTU;
16979106Sbrooks	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
17078064Sume#if 0
17179106Sbrooks	/* turn off ingress filter */
17279106Sbrooks	sc->gif_if.if_flags  |= IFF_LINK2;
17378064Sume#endif
17479106Sbrooks	sc->gif_if.if_ioctl  = gif_ioctl;
17579106Sbrooks	sc->gif_if.if_output = gif_output;
17679106Sbrooks	sc->gif_if.if_type   = IFT_GIF;
17779106Sbrooks	sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
17879106Sbrooks	if_attach(&sc->gif_if);
17979106Sbrooks	bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
18083998Sbrooks	if (ng_gif_attach_p != NULL)
18183998Sbrooks		(*ng_gif_attach_p)(&sc->gif_if);
18279106Sbrooks}
18379106Sbrooks
18497289Sbrooksvoid
18579106Sbrooksgif_clone_destroy(ifp)
18679106Sbrooks	struct ifnet *ifp;
18779106Sbrooks{
18879106Sbrooks	int err;
18979106Sbrooks	struct gif_softc *sc = ifp->if_softc;
19079106Sbrooks
191105293Sume	gif_delete_tunnel(&sc->gif_if);
192105293Sume	LIST_REMOVE(sc, gif_list);
193105293Sume#ifdef INET6
194105293Sume	if (sc->encap_cookie6 != NULL) {
195105293Sume		err = encap_detach(sc->encap_cookie6);
196105293Sume		KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
197105293Sume	}
198105293Sume#endif
199105293Sume#ifdef INET
20079106Sbrooks	if (sc->encap_cookie4 != NULL) {
20179106Sbrooks		err = encap_detach(sc->encap_cookie4);
20279106Sbrooks		KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
20379106Sbrooks	}
204105293Sume#endif
20579106Sbrooks
20683998Sbrooks	if (ng_gif_detach_p != NULL)
20783998Sbrooks		(*ng_gif_detach_p)(ifp);
20879106Sbrooks	bpfdetach(ifp);
20979106Sbrooks	if_detach(ifp);
21079106Sbrooks
21179106Sbrooks	free(sc, M_GIF);
21279106Sbrooks}
21379106Sbrooks
21479106Sbrooksstatic int
21579106Sbrooksgifmodevent(mod, type, data)
21679106Sbrooks	module_t mod;
21779106Sbrooks	int type;
21879106Sbrooks	void *data;
21979106Sbrooks{
22079106Sbrooks
22179106Sbrooks	switch (type) {
22279106Sbrooks	case MOD_LOAD:
22383997Sbrooks		LIST_INIT(&gif_softc_list);
22479106Sbrooks		if_clone_attach(&gif_cloner);
22579106Sbrooks
22679106Sbrooks#ifdef INET6
22779106Sbrooks		ip6_gif_hlim = GIF_HLIM;
22862587Sitojun#endif
22979106Sbrooks
23079106Sbrooks		break;
23179106Sbrooks	case MOD_UNLOAD:
23279106Sbrooks		if_clone_detach(&gif_cloner);
23379106Sbrooks
23483997Sbrooks		while (!LIST_EMPTY(&gif_softc_list))
23583997Sbrooks			gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if);
23679106Sbrooks
23779106Sbrooks#ifdef INET6
23879106Sbrooks		ip6_gif_hlim = 0;
23962587Sitojun#endif
24079106Sbrooks		break;
24154263Sshin	}
24279106Sbrooks	return 0;
24354263Sshin}
24454263Sshin
24579106Sbrooksstatic moduledata_t gif_mod = {
24679106Sbrooks	"if_gif",
24779106Sbrooks	gifmodevent,
24879106Sbrooks	0
24979106Sbrooks};
25054263Sshin
25179106SbrooksDECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
25283997SbrooksMODULE_VERSION(if_gif, 1);
25379106Sbrooks
254105293Sumeint
25562587Sitojungif_encapcheck(m, off, proto, arg)
25662587Sitojun	const struct mbuf *m;
25762587Sitojun	int off;
25862587Sitojun	int proto;
25962587Sitojun	void *arg;
26062587Sitojun{
26162587Sitojun	struct ip ip;
26262587Sitojun	struct gif_softc *sc;
26362587Sitojun
26462587Sitojun	sc = (struct gif_softc *)arg;
26562587Sitojun	if (sc == NULL)
26662587Sitojun		return 0;
26762587Sitojun
26862587Sitojun	if ((sc->gif_if.if_flags & IFF_UP) == 0)
26962587Sitojun		return 0;
27062587Sitojun
27162587Sitojun	/* no physical address */
27262587Sitojun	if (!sc->gif_psrc || !sc->gif_pdst)
27362587Sitojun		return 0;
27462587Sitojun
27562587Sitojun	switch (proto) {
27662587Sitojun#ifdef INET
27762587Sitojun	case IPPROTO_IPV4:
27862587Sitojun		break;
27962587Sitojun#endif
28062587Sitojun#ifdef INET6
28162587Sitojun	case IPPROTO_IPV6:
28262587Sitojun		break;
28362587Sitojun#endif
28462587Sitojun	default:
28562587Sitojun		return 0;
28662587Sitojun	}
28762587Sitojun
288105339Sume	/* Bail on short packets */
289105339Sume	if (m->m_pkthdr.len < sizeof(ip))
290105339Sume		return 0;
291105339Sume
29291327Sbrooks	m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
29362587Sitojun
29462587Sitojun	switch (ip.ip_v) {
29562587Sitojun#ifdef INET
29662587Sitojun	case 4:
29762587Sitojun		if (sc->gif_psrc->sa_family != AF_INET ||
29862587Sitojun		    sc->gif_pdst->sa_family != AF_INET)
29962587Sitojun			return 0;
30062587Sitojun		return gif_encapcheck4(m, off, proto, arg);
30162587Sitojun#endif
30262587Sitojun#ifdef INET6
30362587Sitojun	case 6:
304105293Sume		if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
305105293Sume			return 0;
30662587Sitojun		if (sc->gif_psrc->sa_family != AF_INET6 ||
30762587Sitojun		    sc->gif_pdst->sa_family != AF_INET6)
30862587Sitojun			return 0;
30962587Sitojun		return gif_encapcheck6(m, off, proto, arg);
31062587Sitojun#endif
31162587Sitojun	default:
31262587Sitojun		return 0;
31362587Sitojun	}
31462587Sitojun}
31562587Sitojun
31654263Sshinint
31754263Sshingif_output(ifp, m, dst, rt)
31854263Sshin	struct ifnet *ifp;
31954263Sshin	struct mbuf *m;
32054263Sshin	struct sockaddr *dst;
32154263Sshin	struct rtentry *rt;	/* added in net2 */
32254263Sshin{
32378064Sume	struct gif_softc *sc = (struct gif_softc*)ifp;
32454263Sshin	int error = 0;
32554263Sshin
326101182Srwatson#ifdef MAC
327101182Srwatson	error = mac_check_ifnet_transmit(ifp, m);
328101739Srwatson	if (error) {
329101739Srwatson		m_freem(m);
330101739Srwatson		goto end;
331101739Srwatson	}
332101182Srwatson#endif
333101182Srwatson
33454263Sshin	/*
33554263Sshin	 * gif may cause infinite recursion calls when misconfigured.
33654263Sshin	 * We'll prevent this by introducing upper limit.
337103273Ssobomax	 * XXX: this mechanism may introduce another problem about
338103273Ssobomax	 *      mutual exclusion of the variable CALLED, especially if we
339103273Ssobomax	 *      use kernel thread.
34054263Sshin	 */
341127303Srwatson	if (++gif_called > max_gif_nesting) {
34254263Sshin		log(LOG_NOTICE,
34354263Sshin		    "gif_output: recursively called too many times(%d)\n",
344127303Srwatson		    gif_called);
34554263Sshin		m_freem(m);
34654263Sshin		error = EIO;	/* is there better errno? */
34754263Sshin		goto end;
34854263Sshin	}
34962587Sitojun
35054263Sshin	m->m_flags &= ~(M_BCAST|M_MCAST);
35154263Sshin	if (!(ifp->if_flags & IFF_UP) ||
35254263Sshin	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
35354263Sshin		m_freem(m);
35454263Sshin		error = ENETDOWN;
35554263Sshin		goto end;
35654263Sshin	}
35754263Sshin
35854263Sshin	if (ifp->if_bpf) {
35978064Sume		u_int32_t af = dst->sa_family;
360123922Ssam		bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
36154263Sshin	}
36262587Sitojun	ifp->if_opackets++;
36354263Sshin	ifp->if_obytes += m->m_pkthdr.len;
36454263Sshin
36578064Sume	/* inner AF-specific encapsulation */
36678064Sume
36762587Sitojun	/* XXX should we check if our outer source is legal? */
36862587Sitojun
36978064Sume	/* dispatch to output logic based on outer AF */
37054263Sshin	switch (sc->gif_psrc->sa_family) {
37154263Sshin#ifdef INET
37254263Sshin	case AF_INET:
373105340Sume		error = in_gif_output(ifp, dst->sa_family, m);
37454263Sshin		break;
37554263Sshin#endif
37654263Sshin#ifdef INET6
37754263Sshin	case AF_INET6:
378105340Sume		error = in6_gif_output(ifp, dst->sa_family, m);
37954263Sshin		break;
38054263Sshin#endif
38154263Sshin	default:
38262587Sitojun		m_freem(m);
38354263Sshin		error = ENETDOWN;
38478064Sume		goto end;
38554263Sshin	}
38654263Sshin
38754263Sshin  end:
388127303Srwatson	gif_called = 0;		/* reset recursion counter */
38978064Sume	if (error)
39078064Sume		ifp->if_oerrors++;
39154263Sshin	return error;
39254263Sshin}
39354263Sshin
39454263Sshinvoid
395105338Sumegif_input(m, af, ifp)
39654263Sshin	struct mbuf *m;
39754263Sshin	int af;
398105338Sume	struct ifnet *ifp;
39954263Sshin{
40069152Sjlemon	int isr;
40154263Sshin
402105338Sume	if (ifp == NULL) {
40354263Sshin		/* just in case */
40454263Sshin		m_freem(m);
40554263Sshin		return;
40654263Sshin	}
40754263Sshin
408105338Sume	m->m_pkthdr.rcvif = ifp;
409101182Srwatson
410101182Srwatson#ifdef MAC
411105338Sume	mac_create_mbuf_from_ifnet(ifp, m);
412101182Srwatson#endif
413101182Srwatson
414105338Sume	if (ifp->if_bpf) {
41578064Sume		u_int32_t af1 = af;
416123922Ssam		bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m);
41754263Sshin	}
41854263Sshin
41983998Sbrooks	if (ng_gif_input_p != NULL) {
420105338Sume		(*ng_gif_input_p)(ifp, &m, af);
42183998Sbrooks		if (m == NULL)
42283998Sbrooks			return;
42383998Sbrooks	}
42483998Sbrooks
42554263Sshin	/*
42654263Sshin	 * Put the packet to the network layer input queue according to the
42754263Sshin	 * specified address family.
42854263Sshin	 * Note: older versions of gif_input directly called network layer
42995023Ssuz	 * input functions, e.g. ip6_input, here.  We changed the policy to
43054263Sshin	 * prevent too many recursive calls of such input functions, which
43195023Ssuz	 * might cause kernel panic.  But the change may introduce another
43254263Sshin	 * problem; if the input queue is full, packets are discarded.
43395023Ssuz	 * The kernel stack overflow really happened, and we believed
43495023Ssuz	 * queue-full rarely occurs, so we changed the policy.
43554263Sshin	 */
43654263Sshin	switch (af) {
43754263Sshin#ifdef INET
43854263Sshin	case AF_INET:
43954263Sshin		isr = NETISR_IP;
44054263Sshin		break;
44154263Sshin#endif
44254263Sshin#ifdef INET6
44354263Sshin	case AF_INET6:
44454263Sshin		isr = NETISR_IPV6;
44554263Sshin		break;
44654263Sshin#endif
44754263Sshin	default:
44883998Sbrooks		if (ng_gif_input_orphan_p != NULL)
449105338Sume			(*ng_gif_input_orphan_p)(ifp, m, af);
45083998Sbrooks		else
45183998Sbrooks			m_freem(m);
45254263Sshin		return;
45354263Sshin	}
45454263Sshin
455105338Sume	ifp->if_ipackets++;
456105338Sume	ifp->if_ibytes += m->m_pkthdr.len;
457111888Sjlemon	netisr_dispatch(isr, m);
45854263Sshin}
45954263Sshin
46062587Sitojun/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
46154263Sshinint
46254263Sshingif_ioctl(ifp, cmd, data)
46354263Sshin	struct ifnet *ifp;
46454263Sshin	u_long cmd;
46554263Sshin	caddr_t data;
46654263Sshin{
46754263Sshin	struct gif_softc *sc  = (struct gif_softc*)ifp;
46854263Sshin	struct ifreq     *ifr = (struct ifreq*)data;
46954263Sshin	int error = 0, size;
47062587Sitojun	struct sockaddr *dst, *src;
471105339Sume#ifdef	SIOCSIFMTU /* xxx */
472105339Sume	u_long mtu;
473105339Sume#endif
474105339Sume
47554263Sshin	switch (cmd) {
47654263Sshin	case SIOCSIFADDR:
477105293Sume		ifp->if_flags |= IFF_UP;
47854263Sshin		break;
47962587Sitojun
48054263Sshin	case SIOCSIFDSTADDR:
48154263Sshin		break;
48254263Sshin
48354263Sshin	case SIOCADDMULTI:
48454263Sshin	case SIOCDELMULTI:
48554263Sshin		break;
48654263Sshin
48762587Sitojun#ifdef	SIOCSIFMTU /* xxx */
48854263Sshin	case SIOCGIFMTU:
48954263Sshin		break;
49062587Sitojun
49154263Sshin	case SIOCSIFMTU:
492105339Sume		mtu = ifr->ifr_mtu;
493105339Sume		if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX)
494105339Sume			return (EINVAL);
495105339Sume		ifp->if_mtu = mtu;
49654263Sshin		break;
49762587Sitojun#endif /* SIOCSIFMTU */
49854263Sshin
499105339Sume#ifdef INET
50054263Sshin	case SIOCSIFPHYADDR:
501105339Sume#endif
50254263Sshin#ifdef INET6
50354263Sshin	case SIOCSIFPHYADDR_IN6:
50454263Sshin#endif /* INET6 */
50578064Sume	case SIOCSLIFPHYADDR:
50662587Sitojun		switch (cmd) {
50778064Sume#ifdef INET
50862587Sitojun		case SIOCSIFPHYADDR:
50954263Sshin			src = (struct sockaddr *)
51054263Sshin				&(((struct in_aliasreq *)data)->ifra_addr);
51154263Sshin			dst = (struct sockaddr *)
51254263Sshin				&(((struct in_aliasreq *)data)->ifra_dstaddr);
51362587Sitojun			break;
51478064Sume#endif
51562587Sitojun#ifdef INET6
51662587Sitojun		case SIOCSIFPHYADDR_IN6:
51762587Sitojun			src = (struct sockaddr *)
51862587Sitojun				&(((struct in6_aliasreq *)data)->ifra_addr);
51962587Sitojun			dst = (struct sockaddr *)
52062587Sitojun				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
52162587Sitojun			break;
52262587Sitojun#endif
52378064Sume		case SIOCSLIFPHYADDR:
52478064Sume			src = (struct sockaddr *)
52578064Sume				&(((struct if_laddrreq *)data)->addr);
52678064Sume			dst = (struct sockaddr *)
52778064Sume				&(((struct if_laddrreq *)data)->dstaddr);
528105293Sume			break;
52991327Sbrooks		default:
530105293Sume			return EINVAL;
53162587Sitojun		}
53254263Sshin
53378064Sume		/* sa_family must be equal */
53478064Sume		if (src->sa_family != dst->sa_family)
53578064Sume			return EINVAL;
53678064Sume
53778064Sume		/* validate sa_len */
53878064Sume		switch (src->sa_family) {
53978064Sume#ifdef INET
54078064Sume		case AF_INET:
54178064Sume			if (src->sa_len != sizeof(struct sockaddr_in))
54278064Sume				return EINVAL;
54378064Sume			break;
54478064Sume#endif
54578064Sume#ifdef INET6
54678064Sume		case AF_INET6:
54778064Sume			if (src->sa_len != sizeof(struct sockaddr_in6))
54878064Sume				return EINVAL;
54978064Sume			break;
55078064Sume#endif
55178064Sume		default:
55278064Sume			return EAFNOSUPPORT;
55378064Sume		}
55478064Sume		switch (dst->sa_family) {
55578064Sume#ifdef INET
55678064Sume		case AF_INET:
55778064Sume			if (dst->sa_len != sizeof(struct sockaddr_in))
55878064Sume				return EINVAL;
55978064Sume			break;
56078064Sume#endif
56178064Sume#ifdef INET6
56278064Sume		case AF_INET6:
56378064Sume			if (dst->sa_len != sizeof(struct sockaddr_in6))
56478064Sume				return EINVAL;
56578064Sume			break;
56678064Sume#endif
56778064Sume		default:
56878064Sume			return EAFNOSUPPORT;
56978064Sume		}
57078064Sume
57178064Sume		/* check sa_family looks sane for the cmd */
57278064Sume		switch (cmd) {
57378064Sume		case SIOCSIFPHYADDR:
57478064Sume			if (src->sa_family == AF_INET)
57578064Sume				break;
57678064Sume			return EAFNOSUPPORT;
57778064Sume#ifdef INET6
57878064Sume		case SIOCSIFPHYADDR_IN6:
57978064Sume			if (src->sa_family == AF_INET6)
58078064Sume				break;
58178064Sume			return EAFNOSUPPORT;
58278064Sume#endif /* INET6 */
58378064Sume		case SIOCSLIFPHYADDR:
58478064Sume			/* checks done in the above */
58578064Sume			break;
58678064Sume		}
58778064Sume
588105293Sume		error = gif_set_tunnel(&sc->gif_if, src, dst);
58962587Sitojun		break;
59062587Sitojun
59162587Sitojun#ifdef SIOCDIFPHYADDR
59262587Sitojun	case SIOCDIFPHYADDR:
593105293Sume		gif_delete_tunnel(&sc->gif_if);
59454263Sshin		break;
59562587Sitojun#endif
59662587Sitojun
59754263Sshin	case SIOCGIFPSRCADDR:
59854263Sshin#ifdef INET6
59954263Sshin	case SIOCGIFPSRCADDR_IN6:
60054263Sshin#endif /* INET6 */
60154263Sshin		if (sc->gif_psrc == NULL) {
60254263Sshin			error = EADDRNOTAVAIL;
60354263Sshin			goto bad;
60454263Sshin		}
60554263Sshin		src = sc->gif_psrc;
60678064Sume		switch (cmd) {
60754263Sshin#ifdef INET
60878064Sume		case SIOCGIFPSRCADDR:
60954263Sshin			dst = &ifr->ifr_addr;
61078064Sume			size = sizeof(ifr->ifr_addr);
61154263Sshin			break;
61254263Sshin#endif /* INET */
61354263Sshin#ifdef INET6
61478064Sume		case SIOCGIFPSRCADDR_IN6:
61554263Sshin			dst = (struct sockaddr *)
61654263Sshin				&(((struct in6_ifreq *)data)->ifr_addr);
61778064Sume			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
61854263Sshin			break;
61954263Sshin#endif /* INET6 */
62054263Sshin		default:
62154263Sshin			error = EADDRNOTAVAIL;
62254263Sshin			goto bad;
62354263Sshin		}
62478064Sume		if (src->sa_len > size)
62578064Sume			return EINVAL;
62678064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
62754263Sshin		break;
62862587Sitojun
62954263Sshin	case SIOCGIFPDSTADDR:
63054263Sshin#ifdef INET6
63154263Sshin	case SIOCGIFPDSTADDR_IN6:
63254263Sshin#endif /* INET6 */
63354263Sshin		if (sc->gif_pdst == NULL) {
63454263Sshin			error = EADDRNOTAVAIL;
63554263Sshin			goto bad;
63654263Sshin		}
63754263Sshin		src = sc->gif_pdst;
63878064Sume		switch (cmd) {
63954263Sshin#ifdef INET
64078064Sume		case SIOCGIFPDSTADDR:
64154263Sshin			dst = &ifr->ifr_addr;
64278064Sume			size = sizeof(ifr->ifr_addr);
64354263Sshin			break;
64454263Sshin#endif /* INET */
64554263Sshin#ifdef INET6
64678064Sume		case SIOCGIFPDSTADDR_IN6:
64754263Sshin			dst = (struct sockaddr *)
64854263Sshin				&(((struct in6_ifreq *)data)->ifr_addr);
64978064Sume			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
65054263Sshin			break;
65154263Sshin#endif /* INET6 */
65254263Sshin		default:
65354263Sshin			error = EADDRNOTAVAIL;
65454263Sshin			goto bad;
65554263Sshin		}
65678064Sume		if (src->sa_len > size)
65778064Sume			return EINVAL;
65878064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
65954263Sshin		break;
66054263Sshin
66178064Sume	case SIOCGLIFPHYADDR:
66278064Sume		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
66378064Sume			error = EADDRNOTAVAIL;
66478064Sume			goto bad;
66578064Sume		}
66678064Sume
66778064Sume		/* copy src */
66878064Sume		src = sc->gif_psrc;
66978064Sume		dst = (struct sockaddr *)
67078064Sume			&(((struct if_laddrreq *)data)->addr);
67178064Sume		size = sizeof(((struct if_laddrreq *)data)->addr);
67278064Sume		if (src->sa_len > size)
67378064Sume			return EINVAL;
67478064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
67578064Sume
67678064Sume		/* copy dst */
67778064Sume		src = sc->gif_pdst;
67878064Sume		dst = (struct sockaddr *)
67978064Sume			&(((struct if_laddrreq *)data)->dstaddr);
68078064Sume		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
68178064Sume		if (src->sa_len > size)
68278064Sume			return EINVAL;
68378064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
68478064Sume		break;
68578064Sume
68654263Sshin	case SIOCSIFFLAGS:
68762587Sitojun		/* if_ioctl() takes care of it */
68854263Sshin		break;
68954263Sshin
69054263Sshin	default:
69154263Sshin		error = EINVAL;
69254263Sshin		break;
69354263Sshin	}
69454263Sshin bad:
69554263Sshin	return error;
69654263Sshin}
69779106Sbrooks
698105293Sumeint
699105293Sumegif_set_tunnel(ifp, src, dst)
700105293Sume	struct ifnet *ifp;
701105293Sume	struct sockaddr *src;
702105293Sume	struct sockaddr *dst;
703105293Sume{
704105293Sume	struct gif_softc *sc = (struct gif_softc *)ifp;
705105293Sume	struct gif_softc *sc2;
706105293Sume	struct sockaddr *osrc, *odst, *sa;
707105293Sume	int s;
708105293Sume	int error = 0;
709105293Sume
710105293Sume	s = splnet();
711105293Sume
712105293Sume	LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
713105293Sume		if (sc2 == sc)
714105293Sume			continue;
715105293Sume		if (!sc2->gif_pdst || !sc2->gif_psrc)
716105293Sume			continue;
717105293Sume		if (sc2->gif_pdst->sa_family != dst->sa_family ||
718105293Sume		    sc2->gif_pdst->sa_len != dst->sa_len ||
719105293Sume		    sc2->gif_psrc->sa_family != src->sa_family ||
720105293Sume		    sc2->gif_psrc->sa_len != src->sa_len)
721105293Sume			continue;
722105293Sume
723105293Sume		/*
724105293Sume		 * Disallow parallel tunnels unless instructed
725105293Sume		 * otherwise.
726105293Sume		 */
727105293Sume		if (!parallel_tunnels &&
728105293Sume		    bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
729105293Sume		    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
730105293Sume			error = EADDRNOTAVAIL;
731105293Sume			goto bad;
732105293Sume		}
733105293Sume
734105293Sume		/* XXX both end must be valid? (I mean, not 0.0.0.0) */
735105293Sume	}
736105293Sume
737105293Sume	/* XXX we can detach from both, but be polite just in case */
738105293Sume	if (sc->gif_psrc)
739105293Sume		switch (sc->gif_psrc->sa_family) {
740105293Sume#ifdef INET
741105293Sume		case AF_INET:
742105293Sume			(void)in_gif_detach(sc);
743105293Sume			break;
744105293Sume#endif
745105293Sume#ifdef INET6
746105293Sume		case AF_INET6:
747105293Sume			(void)in6_gif_detach(sc);
748105293Sume			break;
749105293Sume#endif
750105293Sume		}
751105293Sume
752105293Sume	osrc = sc->gif_psrc;
753111119Simp	sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
754105293Sume	bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
755105293Sume	sc->gif_psrc = sa;
756105293Sume
757105293Sume	odst = sc->gif_pdst;
758111119Simp	sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
759105293Sume	bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
760105293Sume	sc->gif_pdst = sa;
761105293Sume
762105293Sume	switch (sc->gif_psrc->sa_family) {
763105293Sume#ifdef INET
764105293Sume	case AF_INET:
765105293Sume		error = in_gif_attach(sc);
766105293Sume		break;
767105293Sume#endif
768105293Sume#ifdef INET6
769105293Sume	case AF_INET6:
770105293Sume		error = in6_gif_attach(sc);
771105293Sume		break;
772105293Sume#endif
773105293Sume	}
774105293Sume	if (error) {
775105293Sume		/* rollback */
776105293Sume		free((caddr_t)sc->gif_psrc, M_IFADDR);
777105293Sume		free((caddr_t)sc->gif_pdst, M_IFADDR);
778105293Sume		sc->gif_psrc = osrc;
779105293Sume		sc->gif_pdst = odst;
780105293Sume		goto bad;
781105293Sume	}
782105293Sume
783105293Sume	if (osrc)
784105293Sume		free((caddr_t)osrc, M_IFADDR);
785105293Sume	if (odst)
786105293Sume		free((caddr_t)odst, M_IFADDR);
787105293Sume
788105293Sume	if (sc->gif_psrc && sc->gif_pdst)
789105293Sume		ifp->if_flags |= IFF_RUNNING;
790105293Sume	else
791105293Sume		ifp->if_flags &= ~IFF_RUNNING;
792105293Sume	splx(s);
793105293Sume
794105293Sume	return 0;
795105293Sume
796105293Sume bad:
797105293Sume	if (sc->gif_psrc && sc->gif_pdst)
798105293Sume		ifp->if_flags |= IFF_RUNNING;
799105293Sume	else
800105293Sume		ifp->if_flags &= ~IFF_RUNNING;
801105293Sume	splx(s);
802105293Sume
803105293Sume	return error;
804105293Sume}
805105293Sume
80679106Sbrooksvoid
807105293Sumegif_delete_tunnel(ifp)
808105293Sume	struct ifnet *ifp;
80979106Sbrooks{
810105293Sume	struct gif_softc *sc = (struct gif_softc *)ifp;
811105293Sume	int s;
81279106Sbrooks
813105293Sume	s = splnet();
814105293Sume
81579106Sbrooks	if (sc->gif_psrc) {
81679106Sbrooks		free((caddr_t)sc->gif_psrc, M_IFADDR);
81779106Sbrooks		sc->gif_psrc = NULL;
81879106Sbrooks	}
81979106Sbrooks	if (sc->gif_pdst) {
82079106Sbrooks		free((caddr_t)sc->gif_pdst, M_IFADDR);
82179106Sbrooks		sc->gif_pdst = NULL;
82279106Sbrooks	}
823105293Sume	/* it is safe to detach from both */
824105293Sume#ifdef INET
825105293Sume	(void)in_gif_detach(sc);
826105293Sume#endif
827105293Sume#ifdef INET6
828105293Sume	(void)in6_gif_detach(sc);
829105293Sume#endif
830105293Sume
831105293Sume	if (sc->gif_psrc && sc->gif_pdst)
832105293Sume		ifp->if_flags |= IFF_RUNNING;
833105293Sume	else
834105293Sume		ifp->if_flags &= ~IFF_RUNNING;
835105293Sume	splx(s);
83679106Sbrooks}
837