if_gif.c revision 78064
162587Sitojun/*	$FreeBSD: head/sys/net/if_gif.c 78064 2001-06-11 12:39:29Z ume $	*/
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>
4754263Sshin#include <machine/cpu.h>
4854263Sshin
4954263Sshin#include <net/if.h>
5054263Sshin#include <net/if_types.h>
5154263Sshin#include <net/netisr.h>
5254263Sshin#include <net/route.h>
5354263Sshin#include <net/bpf.h>
5454263Sshin
5554263Sshin#include <netinet/in.h>
5654263Sshin#include <netinet/in_systm.h>
5778064Sume#include <netinet/ip.h>
5878064Sume#ifdef	INET
5954263Sshin#include <netinet/in_var.h>
6054263Sshin#include <netinet/in_gif.h>
6154263Sshin#endif	/* INET */
6254263Sshin
6354263Sshin#ifdef INET6
6454263Sshin#ifndef INET
6554263Sshin#include <netinet/in.h>
6654263Sshin#endif
6754263Sshin#include <netinet6/in6_var.h>
6854263Sshin#include <netinet/ip6.h>
6954263Sshin#include <netinet6/ip6_var.h>
7054263Sshin#include <netinet6/in6_gif.h>
7162587Sitojun#include <netinet6/ip6protosw.h>
7254263Sshin#endif /* INET6 */
7354263Sshin
7462587Sitojun#include <netinet/ip_encap.h>
7554263Sshin#include <net/if_gif.h>
7654263Sshin
7754263Sshin#include "gif.h"
7862587Sitojun#include "bpf.h"
7962587Sitojun#define NBPFILTER	NBPF
8054263Sshin
8154263Sshin#include <net/net_osdep.h>
8254263Sshin
8362587Sitojun#if NGIF > 0
8462587Sitojun
8554263Sshinvoid gifattach __P((void *));
8662587Sitojunstatic int gif_encapcheck __P((const struct mbuf *, int, int, void *));
8762587Sitojun#ifdef INET
8862587Sitojunextern struct protosw in_gif_protosw;
8962587Sitojun#endif
9062587Sitojun#ifdef INET6
9162587Sitojunextern struct ip6protosw in6_gif_protosw;
9262587Sitojun#endif
9354263Sshin
9454263Sshin/*
9554263Sshin * gif global variable definitions
9654263Sshin */
9762587Sitojunstatic int ngif;		/* number of interfaces */
9862587Sitojunstatic struct gif_softc *gif = 0;
9954263Sshin
10062587Sitojun#ifndef MAX_GIF_NEST
10162587Sitojun/*
10262587Sitojun * This macro controls the upper limitation on nesting of gif tunnels.
10362587Sitojun * Since, setting a large value to this macro with a careless configuration
10462587Sitojun * may introduce system crash, we don't allow any nestings by default.
10562587Sitojun * If you need to configure nested gif tunnels, you can define this macro
10662587Sitojun * in your kernel configuration file. However, if you do so, please be
10762587Sitojun * careful to configure the tunnels so that it won't make a loop.
10862587Sitojun */
10962587Sitojun#define MAX_GIF_NEST 1
11062587Sitojun#endif
11162587Sitojunstatic int max_gif_nesting = MAX_GIF_NEST;
11262587Sitojun
11354263Sshinvoid
11454263Sshingifattach(dummy)
11554263Sshin	void *dummy;
11654263Sshin{
11778064Sume	struct gif_softc *sc;
11878064Sume	int i;
11954263Sshin
12062587Sitojun	ngif = NGIF;
12178064Sume	gif = sc = malloc(ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAITOK);
12254263Sshin	bzero(sc, ngif * sizeof(struct gif_softc));
12362587Sitojun	for (i = 0; i < ngif; sc++, i++) {
12454263Sshin		sc->gif_if.if_name = "gif";
12554263Sshin		sc->gif_if.if_unit = i;
12662587Sitojun
12762587Sitojun		sc->encap_cookie4 = sc->encap_cookie6 = NULL;
12862587Sitojun#ifdef INET
12962587Sitojun		sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
13062587Sitojun		    gif_encapcheck, &in_gif_protosw, sc);
13162587Sitojun		if (sc->encap_cookie4 == NULL) {
13262587Sitojun			printf("%s: attach failed\n", if_name(&sc->gif_if));
13362587Sitojun			continue;
13462587Sitojun		}
13562587Sitojun#endif
13662587Sitojun#ifdef INET6
13762587Sitojun		sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
13862587Sitojun		    gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc);
13962587Sitojun		if (sc->encap_cookie6 == NULL) {
14062587Sitojun			if (sc->encap_cookie4) {
14162587Sitojun				encap_detach(sc->encap_cookie4);
14262587Sitojun				sc->encap_cookie4 = NULL;
14362587Sitojun			}
14462587Sitojun			printf("%s: attach failed\n", if_name(&sc->gif_if));
14562587Sitojun			continue;
14662587Sitojun		}
14762587Sitojun#endif
14862587Sitojun
14954263Sshin		sc->gif_if.if_mtu    = GIF_MTU;
15054263Sshin		sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
15178064Sume#if 0
15278064Sume		/* turn off ingress filter */
15378064Sume		sc->gif_if.if_flags  |= IFF_LINK2;
15478064Sume#endif
15554263Sshin		sc->gif_if.if_ioctl  = gif_ioctl;
15654263Sshin		sc->gif_if.if_output = gif_output;
15754263Sshin		sc->gif_if.if_type   = IFT_GIF;
15862587Sitojun		sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
15954263Sshin		if_attach(&sc->gif_if);
16062587Sitojun#if NBPFILTER > 0
16162587Sitojun#ifdef HAVE_OLD_BPF
16254263Sshin		bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
16362587Sitojun#else
16462587Sitojun		bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_NULL, sizeof(u_int));
16562587Sitojun#endif
16662587Sitojun#endif
16754263Sshin	}
16854263Sshin}
16954263Sshin
17054263SshinPSEUDO_SET(gifattach, if_gif);
17154263Sshin
17262587Sitojunstatic int
17362587Sitojungif_encapcheck(m, off, proto, arg)
17462587Sitojun	const struct mbuf *m;
17562587Sitojun	int off;
17662587Sitojun	int proto;
17762587Sitojun	void *arg;
17862587Sitojun{
17962587Sitojun	struct ip ip;
18062587Sitojun	struct gif_softc *sc;
18162587Sitojun
18262587Sitojun	sc = (struct gif_softc *)arg;
18362587Sitojun	if (sc == NULL)
18462587Sitojun		return 0;
18562587Sitojun
18662587Sitojun	if ((sc->gif_if.if_flags & IFF_UP) == 0)
18762587Sitojun		return 0;
18862587Sitojun
18962587Sitojun	/* no physical address */
19062587Sitojun	if (!sc->gif_psrc || !sc->gif_pdst)
19162587Sitojun		return 0;
19262587Sitojun
19362587Sitojun	switch (proto) {
19462587Sitojun#ifdef INET
19562587Sitojun	case IPPROTO_IPV4:
19662587Sitojun		break;
19762587Sitojun#endif
19862587Sitojun#ifdef INET6
19962587Sitojun	case IPPROTO_IPV6:
20062587Sitojun		break;
20162587Sitojun#endif
20262587Sitojun	default:
20362587Sitojun		return 0;
20462587Sitojun	}
20562587Sitojun
20662587Sitojun	/* LINTED const cast */
20762587Sitojun	m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
20862587Sitojun
20962587Sitojun	switch (ip.ip_v) {
21062587Sitojun#ifdef INET
21162587Sitojun	case 4:
21262587Sitojun		if (sc->gif_psrc->sa_family != AF_INET ||
21362587Sitojun		    sc->gif_pdst->sa_family != AF_INET)
21462587Sitojun			return 0;
21562587Sitojun		return gif_encapcheck4(m, off, proto, arg);
21662587Sitojun#endif
21762587Sitojun#ifdef INET6
21862587Sitojun	case 6:
21962587Sitojun		if (sc->gif_psrc->sa_family != AF_INET6 ||
22062587Sitojun		    sc->gif_pdst->sa_family != AF_INET6)
22162587Sitojun			return 0;
22262587Sitojun		return gif_encapcheck6(m, off, proto, arg);
22362587Sitojun#endif
22462587Sitojun	default:
22562587Sitojun		return 0;
22662587Sitojun	}
22762587Sitojun}
22862587Sitojun
22954263Sshinint
23054263Sshingif_output(ifp, m, dst, rt)
23154263Sshin	struct ifnet *ifp;
23254263Sshin	struct mbuf *m;
23354263Sshin	struct sockaddr *dst;
23454263Sshin	struct rtentry *rt;	/* added in net2 */
23554263Sshin{
23678064Sume	struct gif_softc *sc = (struct gif_softc*)ifp;
23754263Sshin	int error = 0;
23854263Sshin	static int called = 0;	/* XXX: MUTEX */
23954263Sshin
24054263Sshin	/*
24154263Sshin	 * gif may cause infinite recursion calls when misconfigured.
24254263Sshin	 * We'll prevent this by introducing upper limit.
24354263Sshin	 * XXX: this mechanism may introduce another problem about
24454263Sshin	 *      mutual exclusion of the variable CALLED, especially if we
24554263Sshin	 *      use kernel thread.
24654263Sshin	 */
24762587Sitojun	if (++called > max_gif_nesting) {
24854263Sshin		log(LOG_NOTICE,
24954263Sshin		    "gif_output: recursively called too many times(%d)\n",
25054263Sshin		    called);
25154263Sshin		m_freem(m);
25254263Sshin		error = EIO;	/* is there better errno? */
25354263Sshin		goto end;
25454263Sshin	}
25562587Sitojun
25654263Sshin	getmicrotime(&ifp->if_lastchange);
25754263Sshin	m->m_flags &= ~(M_BCAST|M_MCAST);
25854263Sshin	if (!(ifp->if_flags & IFF_UP) ||
25954263Sshin	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
26054263Sshin		m_freem(m);
26154263Sshin		error = ENETDOWN;
26254263Sshin		goto end;
26354263Sshin	}
26454263Sshin
26562587Sitojun#if NBPFILTER > 0
26654263Sshin	if (ifp->if_bpf) {
26754263Sshin		/*
26854263Sshin		 * We need to prepend the address family as
26954263Sshin		 * a four byte field.  Cons up a dummy header
27054263Sshin		 * to pacify bpf.  This is safe because bpf
27154263Sshin		 * will only read from the mbuf (i.e., it won't
27254263Sshin		 * try to free it or keep a pointer a to it).
27354263Sshin		 */
27454263Sshin		struct mbuf m0;
27578064Sume		u_int32_t af = dst->sa_family;
27654263Sshin
27754263Sshin		m0.m_next = m;
27854263Sshin		m0.m_len = 4;
27954263Sshin		m0.m_data = (char *)&af;
28062587Sitojun
28162587Sitojun#ifdef HAVE_OLD_BPF
28254263Sshin		bpf_mtap(ifp, &m0);
28362587Sitojun#else
28462587Sitojun		bpf_mtap(ifp->if_bpf, &m0);
28562587Sitojun#endif
28654263Sshin	}
28762587Sitojun#endif
28862587Sitojun	ifp->if_opackets++;
28954263Sshin	ifp->if_obytes += m->m_pkthdr.len;
29054263Sshin
29178064Sume	/* inner AF-specific encapsulation */
29278064Sume
29362587Sitojun	/* XXX should we check if our outer source is legal? */
29462587Sitojun
29578064Sume	/* dispatch to output logic based on outer AF */
29654263Sshin	switch (sc->gif_psrc->sa_family) {
29754263Sshin#ifdef INET
29854263Sshin	case AF_INET:
29954263Sshin		error = in_gif_output(ifp, dst->sa_family, m, rt);
30054263Sshin		break;
30154263Sshin#endif
30254263Sshin#ifdef INET6
30354263Sshin	case AF_INET6:
30454263Sshin		error = in6_gif_output(ifp, dst->sa_family, m, rt);
30554263Sshin		break;
30654263Sshin#endif
30754263Sshin	default:
30862587Sitojun		m_freem(m);
30954263Sshin		error = ENETDOWN;
31078064Sume		goto end;
31154263Sshin	}
31254263Sshin
31354263Sshin  end:
31454263Sshin	called = 0;		/* reset recursion counter */
31578064Sume	if (error)
31678064Sume		ifp->if_oerrors++;
31754263Sshin	return error;
31854263Sshin}
31954263Sshin
32054263Sshinvoid
32154263Sshingif_input(m, af, gifp)
32254263Sshin	struct mbuf *m;
32354263Sshin	int af;
32454263Sshin	struct ifnet *gifp;
32554263Sshin{
32669152Sjlemon	int isr;
32778064Sume	struct ifqueue *ifq = 0;
32854263Sshin
32954263Sshin	if (gifp == NULL) {
33054263Sshin		/* just in case */
33154263Sshin		m_freem(m);
33254263Sshin		return;
33354263Sshin	}
33454263Sshin
33562587Sitojun	m->m_pkthdr.rcvif = gifp;
33662587Sitojun
33762587Sitojun#if NBPFILTER > 0
33854263Sshin	if (gifp->if_bpf) {
33954263Sshin		/*
34054263Sshin		 * We need to prepend the address family as
34154263Sshin		 * a four byte field.  Cons up a dummy header
34254263Sshin		 * to pacify bpf.  This is safe because bpf
34354263Sshin		 * will only read from the mbuf (i.e., it won't
34454263Sshin		 * try to free it or keep a pointer a to it).
34554263Sshin		 */
34654263Sshin		struct mbuf m0;
34778064Sume		u_int32_t af1 = af;
34862587Sitojun
34954263Sshin		m0.m_next = m;
35054263Sshin		m0.m_len = 4;
35178064Sume		m0.m_data = (char *)&af1;
35262587Sitojun
35362587Sitojun#ifdef HAVE_OLD_BPF
35454263Sshin		bpf_mtap(gifp, &m0);
35562587Sitojun#else
35662587Sitojun		bpf_mtap(gifp->if_bpf, &m0);
35762587Sitojun#endif
35854263Sshin	}
35962587Sitojun#endif /*NBPFILTER > 0*/
36054263Sshin
36154263Sshin	/*
36254263Sshin	 * Put the packet to the network layer input queue according to the
36354263Sshin	 * specified address family.
36454263Sshin	 * Note: older versions of gif_input directly called network layer
36554263Sshin	 * input functions, e.g. ip6_input, here. We changed the policy to
36654263Sshin	 * prevent too many recursive calls of such input functions, which
36754263Sshin	 * might cause kernel panic. But the change may introduce another
36854263Sshin	 * problem; if the input queue is full, packets are discarded.
36954263Sshin	 * We believed it rarely occurs and changed the policy. If we find
37054263Sshin	 * it occurs more times than we thought, we may change the policy
37154263Sshin	 * again.
37254263Sshin	 */
37354263Sshin	switch (af) {
37454263Sshin#ifdef INET
37554263Sshin	case AF_INET:
37654263Sshin		ifq = &ipintrq;
37754263Sshin		isr = NETISR_IP;
37854263Sshin		break;
37954263Sshin#endif
38054263Sshin#ifdef INET6
38154263Sshin	case AF_INET6:
38254263Sshin		ifq = &ip6intrq;
38354263Sshin		isr = NETISR_IPV6;
38454263Sshin		break;
38554263Sshin#endif
38654263Sshin	default:
38754263Sshin		m_freem(m);
38854263Sshin		return;
38954263Sshin	}
39054263Sshin
39169152Sjlemon	gifp->if_ipackets++;
39269152Sjlemon	gifp->if_ibytes += m->m_pkthdr.len;
39369152Sjlemon	(void) IF_HANDOFF(ifq, m, NULL);
39454263Sshin	/* we need schednetisr since the address family may change */
39554263Sshin	schednetisr(isr);
39654263Sshin
39754263Sshin	return;
39854263Sshin}
39954263Sshin
40062587Sitojun/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
40154263Sshinint
40254263Sshingif_ioctl(ifp, cmd, data)
40354263Sshin	struct ifnet *ifp;
40454263Sshin	u_long cmd;
40554263Sshin	caddr_t data;
40654263Sshin{
40754263Sshin	struct gif_softc *sc  = (struct gif_softc*)ifp;
40854263Sshin	struct ifreq     *ifr = (struct ifreq*)data;
40954263Sshin	int error = 0, size;
41062587Sitojun	struct sockaddr *dst, *src;
41162587Sitojun	struct sockaddr *sa;
41262587Sitojun	int i;
41377658Syar	int s;
41462587Sitojun	struct gif_softc *sc2;
41562587Sitojun
41654263Sshin	switch (cmd) {
41754263Sshin	case SIOCSIFADDR:
41854263Sshin		break;
41962587Sitojun
42054263Sshin	case SIOCSIFDSTADDR:
42154263Sshin		break;
42254263Sshin
42354263Sshin	case SIOCADDMULTI:
42454263Sshin	case SIOCDELMULTI:
42554263Sshin		break;
42654263Sshin
42762587Sitojun#ifdef	SIOCSIFMTU /* xxx */
42854263Sshin	case SIOCGIFMTU:
42954263Sshin		break;
43062587Sitojun
43154263Sshin	case SIOCSIFMTU:
43254263Sshin		{
43354263Sshin			u_long mtu;
43454263Sshin			mtu = ifr->ifr_mtu;
43554263Sshin			if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
43654263Sshin				return (EINVAL);
43754263Sshin			}
43854263Sshin			ifp->if_mtu = mtu;
43954263Sshin		}
44054263Sshin		break;
44162587Sitojun#endif /* SIOCSIFMTU */
44254263Sshin
44354263Sshin	case SIOCSIFPHYADDR:
44454263Sshin#ifdef INET6
44554263Sshin	case SIOCSIFPHYADDR_IN6:
44654263Sshin#endif /* INET6 */
44778064Sume	case SIOCSLIFPHYADDR:
44862587Sitojun		switch (cmd) {
44978064Sume#ifdef INET
45062587Sitojun		case SIOCSIFPHYADDR:
45154263Sshin			src = (struct sockaddr *)
45254263Sshin				&(((struct in_aliasreq *)data)->ifra_addr);
45354263Sshin			dst = (struct sockaddr *)
45454263Sshin				&(((struct in_aliasreq *)data)->ifra_dstaddr);
45562587Sitojun			break;
45678064Sume#endif
45762587Sitojun#ifdef INET6
45862587Sitojun		case SIOCSIFPHYADDR_IN6:
45962587Sitojun			src = (struct sockaddr *)
46062587Sitojun				&(((struct in6_aliasreq *)data)->ifra_addr);
46162587Sitojun			dst = (struct sockaddr *)
46262587Sitojun				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
46362587Sitojun			break;
46462587Sitojun#endif
46578064Sume		case SIOCSLIFPHYADDR:
46678064Sume			src = (struct sockaddr *)
46778064Sume				&(((struct if_laddrreq *)data)->addr);
46878064Sume			dst = (struct sockaddr *)
46978064Sume				&(((struct if_laddrreq *)data)->dstaddr);
47062587Sitojun		}
47154263Sshin
47278064Sume		/* sa_family must be equal */
47378064Sume		if (src->sa_family != dst->sa_family)
47478064Sume			return EINVAL;
47578064Sume
47678064Sume		/* validate sa_len */
47778064Sume		switch (src->sa_family) {
47878064Sume#ifdef INET
47978064Sume		case AF_INET:
48078064Sume			if (src->sa_len != sizeof(struct sockaddr_in))
48178064Sume				return EINVAL;
48278064Sume			break;
48378064Sume#endif
48478064Sume#ifdef INET6
48578064Sume		case AF_INET6:
48678064Sume			if (src->sa_len != sizeof(struct sockaddr_in6))
48778064Sume				return EINVAL;
48878064Sume			break;
48978064Sume#endif
49078064Sume		default:
49178064Sume			return EAFNOSUPPORT;
49278064Sume		}
49378064Sume		switch (dst->sa_family) {
49478064Sume#ifdef INET
49578064Sume		case AF_INET:
49678064Sume			if (dst->sa_len != sizeof(struct sockaddr_in))
49778064Sume				return EINVAL;
49878064Sume			break;
49978064Sume#endif
50078064Sume#ifdef INET6
50178064Sume		case AF_INET6:
50278064Sume			if (dst->sa_len != sizeof(struct sockaddr_in6))
50378064Sume				return EINVAL;
50478064Sume			break;
50578064Sume#endif
50678064Sume		default:
50778064Sume			return EAFNOSUPPORT;
50878064Sume		}
50978064Sume
51078064Sume		/* check sa_family looks sane for the cmd */
51178064Sume		switch (cmd) {
51278064Sume		case SIOCSIFPHYADDR:
51378064Sume			if (src->sa_family == AF_INET)
51478064Sume				break;
51578064Sume			return EAFNOSUPPORT;
51678064Sume#ifdef INET6
51778064Sume		case SIOCSIFPHYADDR_IN6:
51878064Sume			if (src->sa_family == AF_INET6)
51978064Sume				break;
52078064Sume			return EAFNOSUPPORT;
52178064Sume#endif /* INET6 */
52278064Sume		case SIOCSLIFPHYADDR:
52378064Sume			/* checks done in the above */
52478064Sume			break;
52578064Sume		}
52678064Sume
52762587Sitojun		for (i = 0; i < ngif; i++) {
52862587Sitojun			sc2 = gif + i;
52962587Sitojun			if (sc2 == sc)
53062587Sitojun				continue;
53162587Sitojun			if (!sc2->gif_pdst || !sc2->gif_psrc)
53262587Sitojun				continue;
53362587Sitojun			if (sc2->gif_pdst->sa_family != dst->sa_family ||
53462587Sitojun			    sc2->gif_pdst->sa_len != dst->sa_len ||
53562587Sitojun			    sc2->gif_psrc->sa_family != src->sa_family ||
53662587Sitojun			    sc2->gif_psrc->sa_len != src->sa_len)
53762587Sitojun				continue;
53863577Skris#ifndef XBONEHACK
53962587Sitojun			/* can't configure same pair of address onto two gifs */
54062587Sitojun			if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
54162587Sitojun			    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
54262587Sitojun				error = EADDRNOTAVAIL;
54362587Sitojun				goto bad;
54462587Sitojun			}
54563577Skris#endif
54654263Sshin
54762587Sitojun			/* can't configure multiple multi-dest interfaces */
54862587Sitojun#define multidest(x) \
54962587Sitojun	(((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
55057903Sshin#ifdef INET6
55162587Sitojun#define multidest6(x) \
55262587Sitojun	(IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
55357903Sshin#endif
55462587Sitojun			if (dst->sa_family == AF_INET &&
55562587Sitojun			    multidest(dst) && multidest(sc2->gif_pdst)) {
55662587Sitojun				error = EADDRNOTAVAIL;
55762587Sitojun				goto bad;
55862587Sitojun			}
55962587Sitojun#ifdef INET6
56062587Sitojun			if (dst->sa_family == AF_INET6 &&
56162587Sitojun			    multidest6(dst) && multidest6(sc2->gif_pdst)) {
56262587Sitojun				error = EADDRNOTAVAIL;
56362587Sitojun				goto bad;
56462587Sitojun			}
56562587Sitojun#endif
56662587Sitojun		}
56757903Sshin
56862587Sitojun		if (sc->gif_psrc)
56954263Sshin			free((caddr_t)sc->gif_psrc, M_IFADDR);
57078064Sume		sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
57178064Sume		bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
57254263Sshin		sc->gif_psrc = sa;
57354263Sshin
57462587Sitojun		if (sc->gif_pdst)
57562587Sitojun			free((caddr_t)sc->gif_pdst, M_IFADDR);
57678064Sume		sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
57778064Sume		bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
57854263Sshin		sc->gif_pdst = sa;
57954263Sshin
58077658Syar		ifp->if_flags |= IFF_RUNNING;
58177658Syar		s = splimp();
58277658Syar		if_up(ifp);	/* mark interface UP and send up RTM_IFINFO */
58377658Syar		splx(s);
58454263Sshin
58562587Sitojun		error = 0;
58662587Sitojun		break;
58762587Sitojun
58862587Sitojun#ifdef SIOCDIFPHYADDR
58962587Sitojun	case SIOCDIFPHYADDR:
59062587Sitojun		if (sc->gif_psrc) {
59162587Sitojun			free((caddr_t)sc->gif_psrc, M_IFADDR);
59262587Sitojun			sc->gif_psrc = NULL;
59357536Sshin		}
59462587Sitojun		if (sc->gif_pdst) {
59562587Sitojun			free((caddr_t)sc->gif_pdst, M_IFADDR);
59662587Sitojun			sc->gif_pdst = NULL;
59762587Sitojun		}
59878064Sume		/* change the IFF_{UP, RUNNING} flag as well? */
59954263Sshin		break;
60062587Sitojun#endif
60162587Sitojun
60254263Sshin	case SIOCGIFPSRCADDR:
60354263Sshin#ifdef INET6
60454263Sshin	case SIOCGIFPSRCADDR_IN6:
60554263Sshin#endif /* INET6 */
60654263Sshin		if (sc->gif_psrc == NULL) {
60754263Sshin			error = EADDRNOTAVAIL;
60854263Sshin			goto bad;
60954263Sshin		}
61054263Sshin		src = sc->gif_psrc;
61178064Sume		switch (cmd) {
61254263Sshin#ifdef INET
61378064Sume		case SIOCGIFPSRCADDR:
61454263Sshin			dst = &ifr->ifr_addr;
61578064Sume			size = sizeof(ifr->ifr_addr);
61654263Sshin			break;
61754263Sshin#endif /* INET */
61854263Sshin#ifdef INET6
61978064Sume		case SIOCGIFPSRCADDR_IN6:
62054263Sshin			dst = (struct sockaddr *)
62154263Sshin				&(((struct in6_ifreq *)data)->ifr_addr);
62278064Sume			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
62354263Sshin			break;
62454263Sshin#endif /* INET6 */
62554263Sshin		default:
62654263Sshin			error = EADDRNOTAVAIL;
62754263Sshin			goto bad;
62854263Sshin		}
62978064Sume		if (src->sa_len > size)
63078064Sume			return EINVAL;
63178064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
63254263Sshin		break;
63362587Sitojun
63454263Sshin	case SIOCGIFPDSTADDR:
63554263Sshin#ifdef INET6
63654263Sshin	case SIOCGIFPDSTADDR_IN6:
63754263Sshin#endif /* INET6 */
63854263Sshin		if (sc->gif_pdst == NULL) {
63954263Sshin			error = EADDRNOTAVAIL;
64054263Sshin			goto bad;
64154263Sshin		}
64254263Sshin		src = sc->gif_pdst;
64378064Sume		switch (cmd) {
64454263Sshin#ifdef INET
64578064Sume		case SIOCGIFPDSTADDR:
64654263Sshin			dst = &ifr->ifr_addr;
64778064Sume			size = sizeof(ifr->ifr_addr);
64854263Sshin			break;
64954263Sshin#endif /* INET */
65054263Sshin#ifdef INET6
65178064Sume		case SIOCGIFPDSTADDR_IN6:
65254263Sshin			dst = (struct sockaddr *)
65354263Sshin				&(((struct in6_ifreq *)data)->ifr_addr);
65478064Sume			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
65554263Sshin			break;
65654263Sshin#endif /* INET6 */
65754263Sshin		default:
65854263Sshin			error = EADDRNOTAVAIL;
65954263Sshin			goto bad;
66054263Sshin		}
66178064Sume		if (src->sa_len > size)
66278064Sume			return EINVAL;
66378064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
66454263Sshin		break;
66554263Sshin
66678064Sume	case SIOCGLIFPHYADDR:
66778064Sume		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
66878064Sume			error = EADDRNOTAVAIL;
66978064Sume			goto bad;
67078064Sume		}
67178064Sume
67278064Sume		/* copy src */
67378064Sume		src = sc->gif_psrc;
67478064Sume		dst = (struct sockaddr *)
67578064Sume			&(((struct if_laddrreq *)data)->addr);
67678064Sume		size = sizeof(((struct if_laddrreq *)data)->addr);
67778064Sume		if (src->sa_len > size)
67878064Sume			return EINVAL;
67978064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
68078064Sume
68178064Sume		/* copy dst */
68278064Sume		src = sc->gif_pdst;
68378064Sume		dst = (struct sockaddr *)
68478064Sume			&(((struct if_laddrreq *)data)->dstaddr);
68578064Sume		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
68678064Sume		if (src->sa_len > size)
68778064Sume			return EINVAL;
68878064Sume		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
68978064Sume		break;
69078064Sume
69154263Sshin	case SIOCSIFFLAGS:
69262587Sitojun		/* if_ioctl() takes care of it */
69354263Sshin		break;
69454263Sshin
69554263Sshin	default:
69654263Sshin		error = EINVAL;
69754263Sshin		break;
69854263Sshin	}
69954263Sshin bad:
70054263Sshin	return error;
70154263Sshin}
70262587Sitojun#endif /*NGIF > 0*/
703