Home | History | Annotate | Line # | Download | only in net
if_gif.c revision 1.119
      1 /*	$NetBSD: if_gif.c,v 1.119 2016/07/04 04:43:46 knakahara Exp $	*/
      2 /*	$KAME: if_gif.c,v 1.76 2001/08/20 02:01:02 kjc Exp $	*/
      3 
      4 /*
      5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. Neither the name of the project nor the names of its contributors
     17  *    may be used to endorse or promote products derived from this software
     18  *    without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     30  * SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.119 2016/07/04 04:43:46 knakahara Exp $");
     35 
     36 #ifdef _KERNEL_OPT
     37 #include "opt_inet.h"
     38 #include "opt_net_mpsafe.h"
     39 #endif
     40 
     41 #include <sys/param.h>
     42 #include <sys/systm.h>
     43 #include <sys/kernel.h>
     44 #include <sys/mbuf.h>
     45 #include <sys/socket.h>
     46 #include <sys/sockio.h>
     47 #include <sys/errno.h>
     48 #include <sys/ioctl.h>
     49 #include <sys/time.h>
     50 #include <sys/socketvar.h>
     51 #include <sys/syslog.h>
     52 #include <sys/proc.h>
     53 #include <sys/cpu.h>
     54 #include <sys/intr.h>
     55 #include <sys/kmem.h>
     56 #include <sys/sysctl.h>
     57 #include <sys/xcall.h>
     58 
     59 #include <net/if.h>
     60 #include <net/if_types.h>
     61 #include <net/netisr.h>
     62 #include <net/route.h>
     63 #include <net/bpf.h>
     64 
     65 #include <netinet/in.h>
     66 #include <netinet/in_systm.h>
     67 #include <netinet/ip.h>
     68 #ifdef	INET
     69 #include <netinet/in_var.h>
     70 #endif	/* INET */
     71 #include <netinet/in_gif.h>
     72 
     73 #ifdef INET6
     74 #ifndef INET
     75 #include <netinet/in.h>
     76 #endif
     77 #include <netinet6/in6_var.h>
     78 #include <netinet/ip6.h>
     79 #include <netinet6/ip6_var.h>
     80 #include <netinet6/in6_gif.h>
     81 #endif /* INET6 */
     82 
     83 #include <netinet/ip_encap.h>
     84 #include <net/if_gif.h>
     85 
     86 #include <net/net_osdep.h>
     87 
     88 #include "ioconf.h"
     89 
     90 #ifdef NET_MPSAFE
     91 #define GIF_MPSAFE	1
     92 #endif
     93 
     94 /*
     95  * gif global variable definitions
     96  */
     97 static LIST_HEAD(, gif_softc) gif_softc_list;
     98 
     99 static void	gifattach0(struct gif_softc *);
    100 static int	gif_output(struct ifnet *, struct mbuf *,
    101 			   const struct sockaddr *, const struct rtentry *);
    102 static void	gif_start(struct ifnet *);
    103 static int	gif_transmit(struct ifnet *, struct mbuf *);
    104 static int	gif_ioctl(struct ifnet *, u_long, void *);
    105 static int	gif_set_tunnel(struct ifnet *, struct sockaddr *,
    106 			       struct sockaddr *);
    107 static void	gif_delete_tunnel(struct ifnet *);
    108 
    109 static void	gif_sysctl_setup(struct sysctllog **);
    110 
    111 static int	gif_clone_create(struct if_clone *, int);
    112 static int	gif_clone_destroy(struct ifnet *);
    113 static int	gif_check_nesting(struct ifnet *, struct mbuf *);
    114 
    115 static int	gif_encap_attach(struct gif_softc *);
    116 static int	gif_encap_detach(struct gif_softc *);
    117 static void	gif_encap_pause(struct gif_softc *);
    118 
    119 static struct if_clone gif_cloner =
    120     IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
    121 
    122 #ifndef MAX_GIF_NEST
    123 /*
    124  * This macro controls the upper limitation on nesting of gif tunnels.
    125  * Since, setting a large value to this macro with a careless configuration
    126  * may introduce system crash, we don't allow any nestings by default.
    127  * If you need to configure nested gif tunnels, you can define this macro
    128  * in your kernel configuration file.  However, if you do so, please be
    129  * careful to configure the tunnels so that it won't make a loop.
    130  */
    131 #define MAX_GIF_NEST 1
    132 #endif
    133 static int max_gif_nesting = MAX_GIF_NEST;
    134 
    135 static void
    136 gif_sysctl_setup(struct sysctllog **clog)
    137 {
    138 
    139 #ifdef INET
    140 	sysctl_createv(clog, 0, NULL, NULL,
    141 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
    142 		       CTLTYPE_INT, "gifttl",
    143 		       SYSCTL_DESCR("Default TTL for a gif tunnel datagram"),
    144 		       NULL, 0, &ip_gif_ttl, 0,
    145 		       CTL_NET, PF_INET, IPPROTO_IP,
    146 		       IPCTL_GIF_TTL, CTL_EOL);
    147 #endif
    148 #ifdef INET6
    149 	sysctl_createv(clog, 0, NULL, NULL,
    150 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
    151 		       CTLTYPE_INT, "gifhlim",
    152 		       SYSCTL_DESCR("Default hop limit for a gif tunnel datagram"),
    153 		       NULL, 0, &ip6_gif_hlim, 0,
    154 		       CTL_NET, PF_INET6, IPPROTO_IPV6,
    155 		       IPV6CTL_GIF_HLIM, CTL_EOL);
    156 #endif
    157 }
    158 
    159 /* ARGSUSED */
    160 void
    161 gifattach(int count)
    162 {
    163 
    164 	LIST_INIT(&gif_softc_list);
    165 	if_clone_attach(&gif_cloner);
    166 
    167 	gif_sysctl_setup(NULL);
    168 }
    169 
    170 static int
    171 gif_clone_create(struct if_clone *ifc, int unit)
    172 {
    173 	struct gif_softc *sc;
    174 
    175 	sc = kmem_zalloc(sizeof(struct gif_softc), KM_SLEEP);
    176 	if (sc == NULL)
    177 		return ENOMEM;
    178 
    179 	if_initname(&sc->gif_if, ifc->ifc_name, unit);
    180 
    181 	gifattach0(sc);
    182 
    183 	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
    184 	return (0);
    185 }
    186 
    187 static void
    188 gifattach0(struct gif_softc *sc)
    189 {
    190 
    191 	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
    192 
    193 	sc->gif_if.if_addrlen = 0;
    194 	sc->gif_if.if_mtu    = GIF_MTU;
    195 	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
    196 	sc->gif_if.if_extflags  = IFEF_NO_LINK_STATE_CHANGE;
    197 	sc->gif_if.if_ioctl  = gif_ioctl;
    198 	sc->gif_if.if_output = gif_output;
    199 	sc->gif_if.if_start = gif_start;
    200 	sc->gif_if.if_transmit = gif_transmit;
    201 	sc->gif_if.if_type   = IFT_GIF;
    202 	sc->gif_if.if_dlt    = DLT_NULL;
    203 	sc->gif_if.if_softc  = sc;
    204 	IFQ_SET_READY(&sc->gif_if.if_snd);
    205 	if_initialize(&sc->gif_if);
    206 	if_register(&sc->gif_if);
    207 	if_alloc_sadl(&sc->gif_if);
    208 	bpf_attach(&sc->gif_if, DLT_NULL, sizeof(u_int));
    209 }
    210 
    211 static int
    212 gif_clone_destroy(struct ifnet *ifp)
    213 {
    214 	struct gif_softc *sc = (void *) ifp;
    215 
    216 	LIST_REMOVE(sc, gif_list);
    217 
    218 	gif_delete_tunnel(&sc->gif_if);
    219 	bpf_detach(ifp);
    220 	if_detach(ifp);
    221 	rtcache_free(&sc->gif_ro);
    222 
    223 	kmem_free(sc, sizeof(struct gif_softc));
    224 
    225 	return (0);
    226 }
    227 
    228 #ifdef GIF_ENCAPCHECK
    229 int
    230 gif_encapcheck(struct mbuf *m, int off, int proto, void *arg)
    231 {
    232 	struct ip ip;
    233 	struct gif_softc *sc;
    234 
    235 	sc = arg;
    236 	if (sc == NULL)
    237 		return 0;
    238 
    239 	if ((sc->gif_if.if_flags & (IFF_UP|IFF_RUNNING))
    240 	    != (IFF_UP|IFF_RUNNING))
    241 		return 0;
    242 
    243 	/* no physical address */
    244 	if (!sc->gif_psrc || !sc->gif_pdst)
    245 		return 0;
    246 
    247 	switch (proto) {
    248 #ifdef INET
    249 	case IPPROTO_IPV4:
    250 		break;
    251 #endif
    252 #ifdef INET6
    253 	case IPPROTO_IPV6:
    254 		break;
    255 #endif
    256 	default:
    257 		return 0;
    258 	}
    259 
    260 	/* Bail on short packets */
    261 	KASSERT(m->m_flags & M_PKTHDR);
    262 	if (m->m_pkthdr.len < sizeof(ip))
    263 		return 0;
    264 
    265 	m_copydata(m, 0, sizeof(ip), &ip);
    266 
    267 	switch (ip.ip_v) {
    268 #ifdef INET
    269 	case 4:
    270 		if (sc->gif_psrc->sa_family != AF_INET ||
    271 		    sc->gif_pdst->sa_family != AF_INET)
    272 			return 0;
    273 		return gif_encapcheck4(m, off, proto, arg);
    274 #endif
    275 #ifdef INET6
    276 	case 6:
    277 		if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
    278 			return 0;
    279 		if (sc->gif_psrc->sa_family != AF_INET6 ||
    280 		    sc->gif_pdst->sa_family != AF_INET6)
    281 			return 0;
    282 		return gif_encapcheck6(m, off, proto, arg);
    283 #endif
    284 	default:
    285 		return 0;
    286 	}
    287 }
    288 #endif
    289 
    290 /*
    291  * gif may cause infinite recursion calls when misconfigured.
    292  * We'll prevent this by introducing upper limit.
    293  */
    294 static int
    295 gif_check_nesting(struct ifnet *ifp, struct mbuf *m)
    296 {
    297 	struct m_tag *mtag;
    298 	int *count;
    299 
    300 	mtag = m_tag_find(m, PACKET_TAG_TUNNEL_INFO, NULL);
    301 	if (mtag != NULL) {
    302 		count = (int *)(mtag + 1);
    303 		if (++(*count) > max_gif_nesting) {
    304 			log(LOG_NOTICE,
    305 			    "%s: recursively called too many times(%d)\n",
    306 			    if_name(ifp),
    307 			    *count);
    308 			return EIO;
    309 		}
    310 	} else {
    311 		mtag = m_tag_get(PACKET_TAG_TUNNEL_INFO, sizeof(*count),
    312 		    M_NOWAIT);
    313 		if (mtag != NULL) {
    314 			m_tag_prepend(m, mtag);
    315 			count = (int *)(mtag + 1);
    316 			*count = 0;
    317 		} else {
    318 			log(LOG_DEBUG,
    319 			    "%s: m_tag_get() failed, recursion calls are not prevented.\n",
    320 			    if_name(ifp));
    321 		}
    322 	}
    323 
    324 	return 0;
    325 }
    326 
    327 static int
    328 gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
    329     const struct rtentry *rt)
    330 {
    331 	struct gif_softc *sc = ifp->if_softc;
    332 	int error = 0;
    333 
    334 	IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family);
    335 
    336 	if ((error = gif_check_nesting(ifp, m)) != 0) {
    337 		m_free(m);
    338 		goto end;
    339 	}
    340 
    341 	m->m_flags &= ~(M_BCAST|M_MCAST);
    342 	if (((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) ||
    343 	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
    344 		m_freem(m);
    345 		error = ENETDOWN;
    346 		goto end;
    347 	}
    348 
    349 	/* XXX should we check if our outer source is legal? */
    350 
    351 	/* use DLT_NULL encapsulation here to pass inner af type */
    352 	M_PREPEND(m, sizeof(int), M_DONTWAIT);
    353 	if (!m) {
    354 		error = ENOBUFS;
    355 		goto end;
    356 	}
    357 	*mtod(m, int *) = dst->sa_family;
    358 
    359 	/* Clear checksum-offload flags. */
    360 	m->m_pkthdr.csum_flags = 0;
    361 	m->m_pkthdr.csum_data = 0;
    362 
    363 	error = if_transmit_lock(ifp, m);
    364   end:
    365 	if (error)
    366 		ifp->if_oerrors++;
    367 	return error;
    368 }
    369 
    370 static void
    371 gif_start(struct ifnet *ifp)
    372 {
    373 	struct gif_softc *sc;
    374 	struct mbuf *m;
    375 	int family;
    376 	int len;
    377 #ifndef GIF_MPSAFE
    378 	int s;
    379 #endif
    380 	int error;
    381 
    382 	sc = ifp->if_softc;
    383 
    384 	/* output processing */
    385 	while (1) {
    386 #ifndef GIF_MPSAFE
    387 		s = splnet();
    388 #endif
    389 		IFQ_DEQUEUE(&sc->gif_if.if_snd, m);
    390 #ifndef GIF_MPSAFE
    391 		splx(s);
    392 #endif
    393 		if (m == NULL)
    394 			break;
    395 
    396 		/* grab and chop off inner af type */
    397 		if (sizeof(int) > m->m_len) {
    398 			m = m_pullup(m, sizeof(int));
    399 			if (!m) {
    400 				ifp->if_oerrors++;
    401 				continue;
    402 			}
    403 		}
    404 		family = *mtod(m, int *);
    405 		bpf_mtap(ifp, m);
    406 		m_adj(m, sizeof(int));
    407 
    408 		len = m->m_pkthdr.len;
    409 
    410 		/* dispatch to output logic based on outer AF */
    411 		switch (sc->gif_psrc->sa_family) {
    412 #ifdef INET
    413 		case AF_INET:
    414 			/* XXX
    415 			 * To add mutex_enter(softnet_lock) or
    416 			 * KASSERT(mutex_owned(softnet_lock)) here, we shold
    417 			 * coordinate softnet_lock between in6_if_up() and
    418 			 * in6_purgeif().
    419 			 */
    420 			error = in_gif_output(ifp, family, m);
    421 			break;
    422 #endif
    423 #ifdef INET6
    424 		case AF_INET6:
    425 			/* XXX
    426 			 * the same as in_gif_output()
    427 			 */
    428 			error = in6_gif_output(ifp, family, m);
    429 			break;
    430 #endif
    431 		default:
    432 			m_freem(m);
    433 			error = ENETDOWN;
    434 			break;
    435 		}
    436 
    437 		if (error)
    438 			ifp->if_oerrors++;
    439 		else {
    440 			ifp->if_opackets++;
    441 			ifp->if_obytes += len;
    442 		}
    443 	}
    444 }
    445 
    446 static int
    447 gif_transmit(struct ifnet *ifp, struct mbuf *m)
    448 {
    449 	struct gif_softc *sc;
    450 	int family;
    451 	int len;
    452 	int error;
    453 
    454 	sc = ifp->if_softc;
    455 
    456 	/* output processing */
    457 	if (m == NULL)
    458 		return EINVAL;
    459 
    460 	/* grab and chop off inner af type */
    461 	if (sizeof(int) > m->m_len) {
    462 		m = m_pullup(m, sizeof(int));
    463 		if (!m) {
    464 			ifp->if_oerrors++;
    465 			return ENOBUFS;
    466 		}
    467 	}
    468 	family = *mtod(m, int *);
    469 	bpf_mtap(ifp, m);
    470 	m_adj(m, sizeof(int));
    471 
    472 	len = m->m_pkthdr.len;
    473 
    474 	/* dispatch to output logic based on outer AF */
    475 	switch (sc->gif_psrc->sa_family) {
    476 #ifdef INET
    477 	case AF_INET:
    478 		/* XXX
    479 		 * To add mutex_enter(softnet_lock) or
    480 		 * KASSERT(mutex_owned(softnet_lock)) here, we shold
    481 		 * coordinate softnet_lock between in6_if_up() and
    482 		 * in6_purgeif().
    483 		 */
    484 		error = in_gif_output(ifp, family, m);
    485 		break;
    486 #endif
    487 #ifdef INET6
    488 	case AF_INET6:
    489 		/* XXX
    490 		 * the same as in_gif_output()
    491 		 */
    492 		error = in6_gif_output(ifp, family, m);
    493 		break;
    494 #endif
    495 	default:
    496 		m_freem(m);
    497 		error = ENETDOWN;
    498 		break;
    499 	}
    500 
    501 	if (error)
    502 		ifp->if_oerrors++;
    503 	else {
    504 		ifp->if_opackets++;
    505 		ifp->if_obytes += len;
    506 	}
    507 
    508 	return error;
    509 }
    510 
    511 void
    512 gif_input(struct mbuf *m, int af, struct ifnet *ifp)
    513 {
    514 	pktqueue_t *pktq;
    515 	size_t pktlen;
    516 #ifndef GIF_MPSAFE
    517 	int s;
    518 #endif
    519 
    520 	if (ifp == NULL) {
    521 		/* just in case */
    522 		m_freem(m);
    523 		return;
    524 	}
    525 
    526 	m_set_rcvif(m, ifp);
    527 	pktlen = m->m_pkthdr.len;
    528 
    529 	bpf_mtap_af(ifp, af, m);
    530 
    531 	/*
    532 	 * Put the packet to the network layer input queue according to the
    533 	 * specified address family.  Note: we avoid direct call to the
    534 	 * input function of the network layer in order to avoid recursion.
    535 	 * This may be revisited in the future.
    536 	 */
    537 	switch (af) {
    538 #ifdef INET
    539 	case AF_INET:
    540 		pktq = ip_pktq;
    541 		break;
    542 #endif
    543 #ifdef INET6
    544 	case AF_INET6:
    545 		pktq = ip6_pktq;
    546 		break;
    547 #endif
    548 	default:
    549 		m_freem(m);
    550 		return;
    551 	}
    552 
    553 #ifndef GIF_MPSAFE
    554 	s = splnet();
    555 #endif
    556 	if (__predict_true(pktq_enqueue(pktq, m, 0))) {
    557 		ifp->if_ibytes += pktlen;
    558 		ifp->if_ipackets++;
    559 	} else {
    560 		m_freem(m);
    561 	}
    562 #ifndef GIF_MPSAFE
    563 	splx(s);
    564 #endif
    565 }
    566 
    567 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
    568 static int
    569 gif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
    570 {
    571 	struct gif_softc *sc  = ifp->if_softc;
    572 	struct ifreq     *ifr = (struct ifreq*)data;
    573 	struct ifaddr    *ifa = (struct ifaddr*)data;
    574 	int error = 0, size;
    575 	struct sockaddr *dst, *src;
    576 
    577 	switch (cmd) {
    578 	case SIOCINITIFADDR:
    579 		ifp->if_flags |= IFF_UP;
    580 		ifa->ifa_rtrequest = p2p_rtrequest;
    581 		break;
    582 
    583 	case SIOCADDMULTI:
    584 	case SIOCDELMULTI:
    585 		switch (ifr->ifr_addr.sa_family) {
    586 #ifdef INET
    587 		case AF_INET:	/* IP supports Multicast */
    588 			break;
    589 #endif /* INET */
    590 #ifdef INET6
    591 		case AF_INET6:	/* IP6 supports Multicast */
    592 			break;
    593 #endif /* INET6 */
    594 		default:  /* Other protocols doesn't support Multicast */
    595 			error = EAFNOSUPPORT;
    596 			break;
    597 		}
    598 		break;
    599 
    600 	case SIOCSIFMTU:
    601 		if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX)
    602 			return EINVAL;
    603 		else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
    604 			error = 0;
    605 		break;
    606 
    607 #ifdef INET
    608 	case SIOCSIFPHYADDR:
    609 #endif
    610 #ifdef INET6
    611 	case SIOCSIFPHYADDR_IN6:
    612 #endif /* INET6 */
    613 	case SIOCSLIFPHYADDR:
    614 		switch (cmd) {
    615 #ifdef INET
    616 		case SIOCSIFPHYADDR:
    617 			src = (struct sockaddr *)
    618 				&(((struct in_aliasreq *)data)->ifra_addr);
    619 			dst = (struct sockaddr *)
    620 				&(((struct in_aliasreq *)data)->ifra_dstaddr);
    621 			break;
    622 #endif
    623 #ifdef INET6
    624 		case SIOCSIFPHYADDR_IN6:
    625 			src = (struct sockaddr *)
    626 				&(((struct in6_aliasreq *)data)->ifra_addr);
    627 			dst = (struct sockaddr *)
    628 				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
    629 			break;
    630 #endif
    631 		case SIOCSLIFPHYADDR:
    632 			src = (struct sockaddr *)
    633 				&(((struct if_laddrreq *)data)->addr);
    634 			dst = (struct sockaddr *)
    635 				&(((struct if_laddrreq *)data)->dstaddr);
    636 			break;
    637 		default:
    638 			return EINVAL;
    639 		}
    640 
    641 		/* sa_family must be equal */
    642 		if (src->sa_family != dst->sa_family)
    643 			return EINVAL;
    644 
    645 		/* validate sa_len */
    646 		switch (src->sa_family) {
    647 #ifdef INET
    648 		case AF_INET:
    649 			if (src->sa_len != sizeof(struct sockaddr_in))
    650 				return EINVAL;
    651 			break;
    652 #endif
    653 #ifdef INET6
    654 		case AF_INET6:
    655 			if (src->sa_len != sizeof(struct sockaddr_in6))
    656 				return EINVAL;
    657 			break;
    658 #endif
    659 		default:
    660 			return EAFNOSUPPORT;
    661 		}
    662 		switch (dst->sa_family) {
    663 #ifdef INET
    664 		case AF_INET:
    665 			if (dst->sa_len != sizeof(struct sockaddr_in))
    666 				return EINVAL;
    667 			break;
    668 #endif
    669 #ifdef INET6
    670 		case AF_INET6:
    671 			if (dst->sa_len != sizeof(struct sockaddr_in6))
    672 				return EINVAL;
    673 			break;
    674 #endif
    675 		default:
    676 			return EAFNOSUPPORT;
    677 		}
    678 
    679 		/* check sa_family looks sane for the cmd */
    680 		switch (cmd) {
    681 		case SIOCSIFPHYADDR:
    682 			if (src->sa_family == AF_INET)
    683 				break;
    684 			return EAFNOSUPPORT;
    685 #ifdef INET6
    686 		case SIOCSIFPHYADDR_IN6:
    687 			if (src->sa_family == AF_INET6)
    688 				break;
    689 			return EAFNOSUPPORT;
    690 #endif /* INET6 */
    691 		case SIOCSLIFPHYADDR:
    692 			/* checks done in the above */
    693 			break;
    694 		}
    695 
    696 		error = gif_set_tunnel(&sc->gif_if, src, dst);
    697 		break;
    698 
    699 #ifdef SIOCDIFPHYADDR
    700 	case SIOCDIFPHYADDR:
    701 		gif_delete_tunnel(&sc->gif_if);
    702 		break;
    703 #endif
    704 
    705 	case SIOCGIFPSRCADDR:
    706 #ifdef INET6
    707 	case SIOCGIFPSRCADDR_IN6:
    708 #endif /* INET6 */
    709 		if (sc->gif_psrc == NULL) {
    710 			error = EADDRNOTAVAIL;
    711 			goto bad;
    712 		}
    713 		src = sc->gif_psrc;
    714 		switch (cmd) {
    715 #ifdef INET
    716 		case SIOCGIFPSRCADDR:
    717 			dst = &ifr->ifr_addr;
    718 			size = sizeof(ifr->ifr_addr);
    719 			break;
    720 #endif /* INET */
    721 #ifdef INET6
    722 		case SIOCGIFPSRCADDR_IN6:
    723 			dst = (struct sockaddr *)
    724 				&(((struct in6_ifreq *)data)->ifr_addr);
    725 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
    726 			break;
    727 #endif /* INET6 */
    728 		default:
    729 			error = EADDRNOTAVAIL;
    730 			goto bad;
    731 		}
    732 		if (src->sa_len > size)
    733 			return EINVAL;
    734 		memcpy(dst, src, src->sa_len);
    735 		break;
    736 
    737 	case SIOCGIFPDSTADDR:
    738 #ifdef INET6
    739 	case SIOCGIFPDSTADDR_IN6:
    740 #endif /* INET6 */
    741 		if (sc->gif_pdst == NULL) {
    742 			error = EADDRNOTAVAIL;
    743 			goto bad;
    744 		}
    745 		src = sc->gif_pdst;
    746 		switch (cmd) {
    747 #ifdef INET
    748 		case SIOCGIFPDSTADDR:
    749 			dst = &ifr->ifr_addr;
    750 			size = sizeof(ifr->ifr_addr);
    751 			break;
    752 #endif /* INET */
    753 #ifdef INET6
    754 		case SIOCGIFPDSTADDR_IN6:
    755 			dst = (struct sockaddr *)
    756 				&(((struct in6_ifreq *)data)->ifr_addr);
    757 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
    758 			break;
    759 #endif /* INET6 */
    760 		default:
    761 			error = EADDRNOTAVAIL;
    762 			goto bad;
    763 		}
    764 		if (src->sa_len > size)
    765 			return EINVAL;
    766 		memcpy(dst, src, src->sa_len);
    767 		break;
    768 
    769 	case SIOCGLIFPHYADDR:
    770 		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
    771 			error = EADDRNOTAVAIL;
    772 			goto bad;
    773 		}
    774 
    775 		/* copy src */
    776 		src = sc->gif_psrc;
    777 		dst = (struct sockaddr *)
    778 			&(((struct if_laddrreq *)data)->addr);
    779 		size = sizeof(((struct if_laddrreq *)data)->addr);
    780 		if (src->sa_len > size)
    781 			return EINVAL;
    782 		memcpy(dst, src, src->sa_len);
    783 
    784 		/* copy dst */
    785 		src = sc->gif_pdst;
    786 		dst = (struct sockaddr *)
    787 			&(((struct if_laddrreq *)data)->dstaddr);
    788 		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
    789 		if (src->sa_len > size)
    790 			return EINVAL;
    791 		memcpy(dst, src, src->sa_len);
    792 		break;
    793 
    794 	default:
    795 		return ifioctl_common(ifp, cmd, data);
    796 	}
    797  bad:
    798 	return error;
    799 }
    800 
    801 static int
    802 gif_encap_attach(struct gif_softc *sc)
    803 {
    804 	int error;
    805 
    806 	if (sc == NULL || sc->gif_psrc == NULL)
    807 		return EINVAL;
    808 
    809 	switch (sc->gif_psrc->sa_family) {
    810 #ifdef INET
    811 	case AF_INET:
    812 		error = in_gif_attach(sc);
    813 		break;
    814 #endif
    815 #ifdef INET6
    816 	case AF_INET6:
    817 		error = in6_gif_attach(sc);
    818 		break;
    819 #endif
    820 	default:
    821 		error = EINVAL;
    822 		break;
    823 	}
    824 
    825 	return error;
    826 }
    827 
    828 static int
    829 gif_encap_detach(struct gif_softc *sc)
    830 {
    831 	int error;
    832 
    833 	if (sc == NULL || sc->gif_psrc == NULL)
    834 		return EINVAL;
    835 
    836 	switch (sc->gif_psrc->sa_family) {
    837 #ifdef INET
    838 	case AF_INET:
    839 		error = in_gif_detach(sc);
    840 		break;
    841 #endif
    842 #ifdef INET6
    843 	case AF_INET6:
    844 		error = in6_gif_detach(sc);
    845 		break;
    846 #endif
    847 	default:
    848 		error = EINVAL;
    849 		break;
    850 	}
    851 
    852 	return error;
    853 }
    854 
    855 static void
    856 gif_encap_pause(struct gif_softc *sc)
    857 {
    858 	struct ifnet *ifp;
    859 	uint64_t where;
    860 
    861 	if (sc == NULL || sc->gif_psrc == NULL)
    862 		return;
    863 
    864 	ifp = &sc->gif_if;
    865 	if ((ifp->if_flags & IFF_RUNNING) == 0)
    866 		return;
    867 
    868 	switch (sc->gif_psrc->sa_family) {
    869 #ifdef INET
    870 	case AF_INET:
    871 		(void)in_gif_pause(sc);
    872 		break;
    873 #endif
    874 #ifdef INET6
    875 	case AF_INET6:
    876 		(void)in6_gif_pause(sc);
    877 		break;
    878 #endif
    879 	}
    880 
    881 	ifp->if_flags &= ~IFF_RUNNING;
    882 	/* membar_sync() is done in xc_broadcast(). */
    883 
    884 	/*
    885 	 * Wait for softint_execute()(ipintr() or ip6intr())
    886 	 * completion done by other CPUs which already run over if_flags
    887 	 * check in in_gif_input() or in6_gif_input().
    888 	 * Furthermore, wait for gif_output() completion too.
    889 	 */
    890 	where = xc_broadcast(0, (xcfunc_t)nullop, NULL, NULL);
    891 	xc_wait(where);
    892 }
    893 
    894 static int
    895 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
    896 {
    897 	struct gif_softc *sc = ifp->if_softc;
    898 	struct gif_softc *sc2;
    899 	struct sockaddr *osrc, *odst;
    900 	struct sockaddr *nsrc, *ndst;
    901 	int error;
    902 #ifndef GIF_MPSAFE
    903 	int s;
    904 
    905 	s = splsoftnet();
    906 #endif
    907 	error = encap_lock_enter();
    908 	if (error) {
    909 #ifndef GIF_MPSAFE
    910 		splx(s);
    911 #endif
    912 		return error;
    913 	}
    914 
    915 	LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
    916 		if (sc2 == sc)
    917 			continue;
    918 		if (!sc2->gif_pdst || !sc2->gif_psrc)
    919 			continue;
    920 		/* can't configure same pair of address onto two gifs */
    921 		if (sockaddr_cmp(sc2->gif_pdst, dst) == 0 &&
    922 		    sockaddr_cmp(sc2->gif_psrc, src) == 0) {
    923 			/* continue to use the old configureation. */
    924 			error =  EADDRNOTAVAIL;
    925 			goto out;
    926 		}
    927 
    928 		/* XXX both end must be valid? (I mean, not 0.0.0.0) */
    929 	}
    930 
    931 	if ((nsrc = sockaddr_dup(src, M_WAITOK)) == NULL) {
    932 		error =  ENOMEM;
    933 		goto out;
    934 	}
    935 	if ((ndst = sockaddr_dup(dst, M_WAITOK)) == NULL) {
    936 		sockaddr_free(nsrc);
    937 		error = ENOMEM;
    938 		goto out;
    939 	}
    940 
    941 	gif_encap_pause(sc);
    942 
    943 	/* Firstly, clear old configurations. */
    944 	/* XXX we can detach from both, but be polite just in case */
    945 	if (sc->gif_psrc)
    946 		(void)gif_encap_detach(sc);
    947 
    948 	/*
    949 	 * Secondly, try to set new configurations.
    950 	 * If the setup failed, rollback to old configurations.
    951 	 */
    952 	do {
    953 		osrc = sc->gif_psrc;
    954 		odst = sc->gif_pdst;
    955 		sc->gif_psrc = nsrc;
    956 		sc->gif_pdst = ndst;
    957 
    958 		error = gif_encap_attach(sc);
    959 		if (error) {
    960 			/* rollback to the last configuration. */
    961 			nsrc = osrc;
    962 			ndst = odst;
    963 			osrc = sc->gif_psrc;
    964 			odst = sc->gif_pdst;
    965 
    966 			continue;
    967 		}
    968 	} while (error != 0 && (nsrc != NULL && ndst != NULL));
    969 	/* Thirdly, even rollback failed, clear configurations. */
    970 	if (error) {
    971 		osrc = sc->gif_psrc;
    972 		odst = sc->gif_pdst;
    973 		sc->gif_psrc = NULL;
    974 		sc->gif_pdst = NULL;
    975 	}
    976 
    977 	if (osrc)
    978 		sockaddr_free(osrc);
    979 	if (odst)
    980 		sockaddr_free(odst);
    981 
    982 	if (sc->gif_psrc && sc->gif_pdst)
    983 		ifp->if_flags |= IFF_RUNNING;
    984 	else
    985 		ifp->if_flags &= ~IFF_RUNNING;
    986 
    987  out:
    988 	encap_lock_exit();
    989 #ifndef GIF_MPSAFE
    990 	splx(s);
    991 #endif
    992 	return error;
    993 }
    994 
    995 static void
    996 gif_delete_tunnel(struct ifnet *ifp)
    997 {
    998 	struct gif_softc *sc = ifp->if_softc;
    999 	int error;
   1000 #ifndef GIF_MPSAFE
   1001 	int s;
   1002 
   1003 	s = splsoftnet();
   1004 #endif
   1005 	error = encap_lock_enter();
   1006 	if (error) {
   1007 #ifndef GIF_MPSAFE
   1008 		splx(s);
   1009 #endif
   1010 		return;
   1011 	}
   1012 
   1013 	gif_encap_pause(sc);
   1014 	if (sc->gif_psrc) {
   1015 		sockaddr_free(sc->gif_psrc);
   1016 		sc->gif_psrc = NULL;
   1017 	}
   1018 	if (sc->gif_pdst) {
   1019 		sockaddr_free(sc->gif_pdst);
   1020 		sc->gif_pdst = NULL;
   1021 	}
   1022 	/* it is safe to detach from both */
   1023 #ifdef INET
   1024 	(void)in_gif_detach(sc);
   1025 #endif
   1026 #ifdef INET6
   1027 	(void)in6_gif_detach(sc);
   1028 #endif
   1029 
   1030 	if (sc->gif_psrc && sc->gif_pdst)
   1031 		ifp->if_flags |= IFF_RUNNING;
   1032 	else
   1033 		ifp->if_flags &= ~IFF_RUNNING;
   1034 
   1035 	encap_lock_exit();
   1036 #ifndef GIF_MPSAFE
   1037 	splx(s);
   1038 #endif
   1039 }
   1040