Home | History | Annotate | Line # | Download | only in net
if_gif.c revision 1.94
      1 /*	$NetBSD: if_gif.c,v 1.94 2015/12/03 03:03:58 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.94 2015/12/03 03:03:58 knakahara Exp $");
     35 
     36 #ifdef _KERNEL_OPT
     37 #include "opt_inet.h"
     38 #endif
     39 
     40 #include <sys/param.h>
     41 #include <sys/systm.h>
     42 #include <sys/kernel.h>
     43 #include <sys/mbuf.h>
     44 #include <sys/socket.h>
     45 #include <sys/sockio.h>
     46 #include <sys/errno.h>
     47 #include <sys/ioctl.h>
     48 #include <sys/time.h>
     49 #include <sys/socketvar.h>
     50 #include <sys/syslog.h>
     51 #include <sys/proc.h>
     52 #include <sys/protosw.h>
     53 #include <sys/cpu.h>
     54 #include <sys/intr.h>
     55 
     56 #include <net/if.h>
     57 #include <net/if_types.h>
     58 #include <net/netisr.h>
     59 #include <net/route.h>
     60 #include <net/bpf.h>
     61 
     62 #include <netinet/in.h>
     63 #include <netinet/in_systm.h>
     64 #include <netinet/ip.h>
     65 #ifdef	INET
     66 #include <netinet/in_var.h>
     67 #endif	/* INET */
     68 #include <netinet/in_gif.h>
     69 
     70 #ifdef INET6
     71 #ifndef INET
     72 #include <netinet/in.h>
     73 #endif
     74 #include <netinet6/in6_var.h>
     75 #include <netinet/ip6.h>
     76 #include <netinet6/ip6_var.h>
     77 #include <netinet6/in6_gif.h>
     78 #include <netinet6/ip6protosw.h>
     79 #endif /* INET6 */
     80 
     81 #include <netinet/ip_encap.h>
     82 #include <net/if_gif.h>
     83 
     84 #include <net/net_osdep.h>
     85 
     86 #include "ioconf.h"
     87 
     88 static void	gifintr(void *);
     89 
     90 /*
     91  * gif global variable definitions
     92  */
     93 LIST_HEAD(, gif_softc) gif_softc_list;	/* XXX should be static */
     94 
     95 static int	gif_clone_create(struct if_clone *, int);
     96 static int	gif_clone_destroy(struct ifnet *);
     97 
     98 static struct if_clone gif_cloner =
     99     IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
    100 
    101 #ifndef MAX_GIF_NEST
    102 /*
    103  * This macro controls the upper limitation on nesting of gif tunnels.
    104  * Since, setting a large value to this macro with a careless configuration
    105  * may introduce system crash, we don't allow any nestings by default.
    106  * If you need to configure nested gif tunnels, you can define this macro
    107  * in your kernel configuration file.  However, if you do so, please be
    108  * careful to configure the tunnels so that it won't make a loop.
    109  */
    110 #define MAX_GIF_NEST 1
    111 #endif
    112 static int max_gif_nesting = MAX_GIF_NEST;
    113 
    114 /* ARGSUSED */
    115 void
    116 gifattach(int count)
    117 {
    118 
    119 	LIST_INIT(&gif_softc_list);
    120 	if_clone_attach(&gif_cloner);
    121 }
    122 
    123 static int
    124 gif_clone_create(struct if_clone *ifc, int unit)
    125 {
    126 	struct gif_softc *sc;
    127 
    128 	sc = malloc(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK|M_ZERO);
    129 
    130 	if_initname(&sc->gif_if, ifc->ifc_name, unit);
    131 
    132 	gifattach0(sc);
    133 
    134 	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
    135 	return (0);
    136 }
    137 
    138 void
    139 gifattach0(struct gif_softc *sc)
    140 {
    141 
    142 	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
    143 
    144 	sc->gif_if.if_addrlen = 0;
    145 	sc->gif_if.if_mtu    = GIF_MTU;
    146 	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
    147 	sc->gif_if.if_ioctl  = gif_ioctl;
    148 	sc->gif_if.if_output = gif_output;
    149 	sc->gif_if.if_type   = IFT_GIF;
    150 	sc->gif_if.if_dlt    = DLT_NULL;
    151 	sc->gif_if.if_softc  = sc;
    152 	IFQ_SET_READY(&sc->gif_if.if_snd);
    153 	if_attach(&sc->gif_if);
    154 	if_alloc_sadl(&sc->gif_if);
    155 	bpf_attach(&sc->gif_if, DLT_NULL, sizeof(u_int));
    156 }
    157 
    158 static int
    159 gif_clone_destroy(struct ifnet *ifp)
    160 {
    161 	struct gif_softc *sc = (void *) ifp;
    162 
    163 	LIST_REMOVE(sc, gif_list);
    164 
    165 	gif_delete_tunnel(&sc->gif_if);
    166 	bpf_detach(ifp);
    167 	if_detach(ifp);
    168 	rtcache_free(&sc->gif_ro);
    169 
    170 	free(sc, M_DEVBUF);
    171 
    172 	return (0);
    173 }
    174 
    175 #ifdef GIF_ENCAPCHECK
    176 int
    177 gif_encapcheck(struct mbuf *m, int off, int proto, void *arg)
    178 {
    179 	struct ip ip;
    180 	struct gif_softc *sc;
    181 
    182 	sc = arg;
    183 	if (sc == NULL)
    184 		return 0;
    185 
    186 	if ((sc->gif_if.if_flags & IFF_UP) == 0)
    187 		return 0;
    188 
    189 	/* no physical address */
    190 	if (!sc->gif_psrc || !sc->gif_pdst)
    191 		return 0;
    192 
    193 	switch (proto) {
    194 #ifdef INET
    195 	case IPPROTO_IPV4:
    196 		break;
    197 #endif
    198 #ifdef INET6
    199 	case IPPROTO_IPV6:
    200 		break;
    201 #endif
    202 	default:
    203 		return 0;
    204 	}
    205 
    206 	/* Bail on short packets */
    207 	KASSERT(m->m_flags & M_PKTHDR);
    208 	if (m->m_pkthdr.len < sizeof(ip))
    209 		return 0;
    210 
    211 	m_copydata(m, 0, sizeof(ip), &ip);
    212 
    213 	switch (ip.ip_v) {
    214 #ifdef INET
    215 	case 4:
    216 		if (sc->gif_psrc->sa_family != AF_INET ||
    217 		    sc->gif_pdst->sa_family != AF_INET)
    218 			return 0;
    219 		return gif_encapcheck4(m, off, proto, arg);
    220 #endif
    221 #ifdef INET6
    222 	case 6:
    223 		if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
    224 			return 0;
    225 		if (sc->gif_psrc->sa_family != AF_INET6 ||
    226 		    sc->gif_pdst->sa_family != AF_INET6)
    227 			return 0;
    228 		return gif_encapcheck6(m, off, proto, arg);
    229 #endif
    230 	default:
    231 		return 0;
    232 	}
    233 }
    234 #endif
    235 
    236 int
    237 gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
    238     struct rtentry *rt)
    239 {
    240 	struct gif_softc *sc = ifp->if_softc;
    241 	int error = 0;
    242 	static int called = 0;	/* XXX: MUTEX */
    243 	ALTQ_DECL(struct altq_pktattr pktattr;)
    244 	int s;
    245 
    246 	IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
    247 
    248 	/*
    249 	 * gif may cause infinite recursion calls when misconfigured.
    250 	 * We'll prevent this by introducing upper limit.
    251 	 * XXX: this mechanism may introduce another problem about
    252 	 *      mutual exclusion of the variable CALLED, especially if we
    253 	 *      use kernel thread.
    254 	 */
    255 	if (++called > max_gif_nesting) {
    256 		log(LOG_NOTICE,
    257 		    "gif_output: recursively called too many times(%d)\n",
    258 		    called);
    259 		m_freem(m);
    260 		error = EIO;	/* is there better errno? */
    261 		goto end;
    262 	}
    263 
    264 	m->m_flags &= ~(M_BCAST|M_MCAST);
    265 	if (!(ifp->if_flags & IFF_UP) ||
    266 	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
    267 		m_freem(m);
    268 		error = ENETDOWN;
    269 		goto end;
    270 	}
    271 
    272 	/* XXX should we check if our outer source is legal? */
    273 
    274 	/* use DLT_NULL encapsulation here to pass inner af type */
    275 	M_PREPEND(m, sizeof(int), M_DONTWAIT);
    276 	if (!m) {
    277 		error = ENOBUFS;
    278 		goto end;
    279 	}
    280 	*mtod(m, int *) = dst->sa_family;
    281 
    282 	/* Clear checksum-offload flags. */
    283 	m->m_pkthdr.csum_flags = 0;
    284 	m->m_pkthdr.csum_data = 0;
    285 
    286 	s = splnet();
    287 	IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
    288 	if (error) {
    289 		splx(s);
    290 		goto end;
    291 	}
    292 	splx(s);
    293 
    294 	softint_schedule(sc->gif_si);
    295 	error = 0;
    296 
    297   end:
    298 	called = 0;		/* reset recursion counter */
    299 	if (error)
    300 		ifp->if_oerrors++;
    301 	return error;
    302 }
    303 
    304 static void
    305 gifintr(void *arg)
    306 {
    307 	struct gif_softc *sc;
    308 	struct ifnet *ifp;
    309 	struct mbuf *m;
    310 	int family;
    311 	int len;
    312 	int s;
    313 	int error;
    314 
    315 	sc = arg;
    316 	ifp = &sc->gif_if;
    317 
    318 	/* output processing */
    319 	while (1) {
    320 		s = splnet();
    321 		IFQ_DEQUEUE(&sc->gif_if.if_snd, m);
    322 		splx(s);
    323 		if (m == NULL)
    324 			break;
    325 
    326 		/* grab and chop off inner af type */
    327 		if (sizeof(int) > m->m_len) {
    328 			m = m_pullup(m, sizeof(int));
    329 			if (!m) {
    330 				ifp->if_oerrors++;
    331 				continue;
    332 			}
    333 		}
    334 		family = *mtod(m, int *);
    335 		bpf_mtap(ifp, m);
    336 		m_adj(m, sizeof(int));
    337 
    338 		len = m->m_pkthdr.len;
    339 
    340 		/* dispatch to output logic based on outer AF */
    341 		switch (sc->gif_psrc->sa_family) {
    342 #ifdef INET
    343 		case AF_INET:
    344 			mutex_enter(softnet_lock);
    345 			error = in_gif_output(ifp, family, m);
    346 			mutex_exit(softnet_lock);
    347 			break;
    348 #endif
    349 #ifdef INET6
    350 		case AF_INET6:
    351 			mutex_enter(softnet_lock);
    352 			error = in6_gif_output(ifp, family, m);
    353 			mutex_exit(softnet_lock);
    354 			break;
    355 #endif
    356 		default:
    357 			m_freem(m);
    358 			error = ENETDOWN;
    359 			break;
    360 		}
    361 
    362 		if (error)
    363 			ifp->if_oerrors++;
    364 		else {
    365 			ifp->if_opackets++;
    366 			ifp->if_obytes += len;
    367 		}
    368 	}
    369 }
    370 
    371 void
    372 gif_input(struct mbuf *m, int af, struct ifnet *ifp)
    373 {
    374 	pktqueue_t *pktq;
    375 	size_t pktlen;
    376 	int s;
    377 
    378 	if (ifp == NULL) {
    379 		/* just in case */
    380 		m_freem(m);
    381 		return;
    382 	}
    383 
    384 	m->m_pkthdr.rcvif = ifp;
    385 	pktlen = m->m_pkthdr.len;
    386 
    387 	bpf_mtap_af(ifp, af, m);
    388 
    389 	/*
    390 	 * Put the packet to the network layer input queue according to the
    391 	 * specified address family.  Note: we avoid direct call to the
    392 	 * input function of the network layer in order to avoid recursion.
    393 	 * This may be revisited in the future.
    394 	 */
    395 	switch (af) {
    396 #ifdef INET
    397 	case AF_INET:
    398 		pktq = ip_pktq;
    399 		break;
    400 #endif
    401 #ifdef INET6
    402 	case AF_INET6:
    403 		pktq = ip6_pktq;
    404 		break;
    405 #endif
    406 	default:
    407 		m_freem(m);
    408 		return;
    409 	}
    410 
    411 	s = splnet();
    412 	if (__predict_true(pktq_enqueue(pktq, m, 0))) {
    413 		ifp->if_ibytes += pktlen;
    414 		ifp->if_ipackets++;
    415 	} else {
    416 		m_freem(m);
    417 	}
    418 	splx(s);
    419 }
    420 
    421 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
    422 int
    423 gif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
    424 {
    425 	struct gif_softc *sc  = ifp->if_softc;
    426 	struct ifreq     *ifr = (struct ifreq*)data;
    427 	struct ifaddr    *ifa = (struct ifaddr*)data;
    428 	int error = 0, size;
    429 	struct sockaddr *dst, *src;
    430 
    431 	switch (cmd) {
    432 	case SIOCINITIFADDR:
    433 		ifp->if_flags |= IFF_UP;
    434 		ifa->ifa_rtrequest = p2p_rtrequest;
    435 		break;
    436 
    437 	case SIOCADDMULTI:
    438 	case SIOCDELMULTI:
    439 		switch (ifr->ifr_addr.sa_family) {
    440 #ifdef INET
    441 		case AF_INET:	/* IP supports Multicast */
    442 			break;
    443 #endif /* INET */
    444 #ifdef INET6
    445 		case AF_INET6:	/* IP6 supports Multicast */
    446 			break;
    447 #endif /* INET6 */
    448 		default:  /* Other protocols doesn't support Multicast */
    449 			error = EAFNOSUPPORT;
    450 			break;
    451 		}
    452 		break;
    453 
    454 	case SIOCSIFMTU:
    455 		if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX)
    456 			return EINVAL;
    457 		else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
    458 			error = 0;
    459 		break;
    460 
    461 #ifdef INET
    462 	case SIOCSIFPHYADDR:
    463 #endif
    464 #ifdef INET6
    465 	case SIOCSIFPHYADDR_IN6:
    466 #endif /* INET6 */
    467 	case SIOCSLIFPHYADDR:
    468 		switch (cmd) {
    469 #ifdef INET
    470 		case SIOCSIFPHYADDR:
    471 			src = (struct sockaddr *)
    472 				&(((struct in_aliasreq *)data)->ifra_addr);
    473 			dst = (struct sockaddr *)
    474 				&(((struct in_aliasreq *)data)->ifra_dstaddr);
    475 			break;
    476 #endif
    477 #ifdef INET6
    478 		case SIOCSIFPHYADDR_IN6:
    479 			src = (struct sockaddr *)
    480 				&(((struct in6_aliasreq *)data)->ifra_addr);
    481 			dst = (struct sockaddr *)
    482 				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
    483 			break;
    484 #endif
    485 		case SIOCSLIFPHYADDR:
    486 			src = (struct sockaddr *)
    487 				&(((struct if_laddrreq *)data)->addr);
    488 			dst = (struct sockaddr *)
    489 				&(((struct if_laddrreq *)data)->dstaddr);
    490 			break;
    491 		default:
    492 			return EINVAL;
    493 		}
    494 
    495 		/* sa_family must be equal */
    496 		if (src->sa_family != dst->sa_family)
    497 			return EINVAL;
    498 
    499 		/* validate sa_len */
    500 		switch (src->sa_family) {
    501 #ifdef INET
    502 		case AF_INET:
    503 			if (src->sa_len != sizeof(struct sockaddr_in))
    504 				return EINVAL;
    505 			break;
    506 #endif
    507 #ifdef INET6
    508 		case AF_INET6:
    509 			if (src->sa_len != sizeof(struct sockaddr_in6))
    510 				return EINVAL;
    511 			break;
    512 #endif
    513 		default:
    514 			return EAFNOSUPPORT;
    515 		}
    516 		switch (dst->sa_family) {
    517 #ifdef INET
    518 		case AF_INET:
    519 			if (dst->sa_len != sizeof(struct sockaddr_in))
    520 				return EINVAL;
    521 			break;
    522 #endif
    523 #ifdef INET6
    524 		case AF_INET6:
    525 			if (dst->sa_len != sizeof(struct sockaddr_in6))
    526 				return EINVAL;
    527 			break;
    528 #endif
    529 		default:
    530 			return EAFNOSUPPORT;
    531 		}
    532 
    533 		/* check sa_family looks sane for the cmd */
    534 		switch (cmd) {
    535 		case SIOCSIFPHYADDR:
    536 			if (src->sa_family == AF_INET)
    537 				break;
    538 			return EAFNOSUPPORT;
    539 #ifdef INET6
    540 		case SIOCSIFPHYADDR_IN6:
    541 			if (src->sa_family == AF_INET6)
    542 				break;
    543 			return EAFNOSUPPORT;
    544 #endif /* INET6 */
    545 		case SIOCSLIFPHYADDR:
    546 			/* checks done in the above */
    547 			break;
    548 		}
    549 
    550 		error = gif_set_tunnel(&sc->gif_if, src, dst);
    551 		break;
    552 
    553 #ifdef SIOCDIFPHYADDR
    554 	case SIOCDIFPHYADDR:
    555 		gif_delete_tunnel(&sc->gif_if);
    556 		break;
    557 #endif
    558 
    559 	case SIOCGIFPSRCADDR:
    560 #ifdef INET6
    561 	case SIOCGIFPSRCADDR_IN6:
    562 #endif /* INET6 */
    563 		if (sc->gif_psrc == NULL) {
    564 			error = EADDRNOTAVAIL;
    565 			goto bad;
    566 		}
    567 		src = sc->gif_psrc;
    568 		switch (cmd) {
    569 #ifdef INET
    570 		case SIOCGIFPSRCADDR:
    571 			dst = &ifr->ifr_addr;
    572 			size = sizeof(ifr->ifr_addr);
    573 			break;
    574 #endif /* INET */
    575 #ifdef INET6
    576 		case SIOCGIFPSRCADDR_IN6:
    577 			dst = (struct sockaddr *)
    578 				&(((struct in6_ifreq *)data)->ifr_addr);
    579 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
    580 			break;
    581 #endif /* INET6 */
    582 		default:
    583 			error = EADDRNOTAVAIL;
    584 			goto bad;
    585 		}
    586 		if (src->sa_len > size)
    587 			return EINVAL;
    588 		memcpy(dst, src, src->sa_len);
    589 		break;
    590 
    591 	case SIOCGIFPDSTADDR:
    592 #ifdef INET6
    593 	case SIOCGIFPDSTADDR_IN6:
    594 #endif /* INET6 */
    595 		if (sc->gif_pdst == NULL) {
    596 			error = EADDRNOTAVAIL;
    597 			goto bad;
    598 		}
    599 		src = sc->gif_pdst;
    600 		switch (cmd) {
    601 #ifdef INET
    602 		case SIOCGIFPDSTADDR:
    603 			dst = &ifr->ifr_addr;
    604 			size = sizeof(ifr->ifr_addr);
    605 			break;
    606 #endif /* INET */
    607 #ifdef INET6
    608 		case SIOCGIFPDSTADDR_IN6:
    609 			dst = (struct sockaddr *)
    610 				&(((struct in6_ifreq *)data)->ifr_addr);
    611 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
    612 			break;
    613 #endif /* INET6 */
    614 		default:
    615 			error = EADDRNOTAVAIL;
    616 			goto bad;
    617 		}
    618 		if (src->sa_len > size)
    619 			return EINVAL;
    620 		memcpy(dst, src, src->sa_len);
    621 		break;
    622 
    623 	case SIOCGLIFPHYADDR:
    624 		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
    625 			error = EADDRNOTAVAIL;
    626 			goto bad;
    627 		}
    628 
    629 		/* copy src */
    630 		src = sc->gif_psrc;
    631 		dst = (struct sockaddr *)
    632 			&(((struct if_laddrreq *)data)->addr);
    633 		size = sizeof(((struct if_laddrreq *)data)->addr);
    634 		if (src->sa_len > size)
    635 			return EINVAL;
    636 		memcpy(dst, src, src->sa_len);
    637 
    638 		/* copy dst */
    639 		src = sc->gif_pdst;
    640 		dst = (struct sockaddr *)
    641 			&(((struct if_laddrreq *)data)->dstaddr);
    642 		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
    643 		if (src->sa_len > size)
    644 			return EINVAL;
    645 		memcpy(dst, src, src->sa_len);
    646 		break;
    647 
    648 	default:
    649 		return ifioctl_common(ifp, cmd, data);
    650 	}
    651  bad:
    652 	return error;
    653 }
    654 
    655 int
    656 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
    657 {
    658 	struct gif_softc *sc = ifp->if_softc;
    659 	struct gif_softc *sc2;
    660 	struct sockaddr *osrc, *odst;
    661 	int s;
    662 	int error;
    663 
    664 	s = splsoftnet();
    665 
    666 	LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
    667 		if (sc2 == sc)
    668 			continue;
    669 		if (!sc2->gif_pdst || !sc2->gif_psrc)
    670 			continue;
    671 		/* can't configure same pair of address onto two gifs */
    672 		if (sockaddr_cmp(sc2->gif_pdst, dst) == 0 &&
    673 		    sockaddr_cmp(sc2->gif_psrc, src) == 0) {
    674 			error = EADDRNOTAVAIL;
    675 			/* continue to use the old configureation. */
    676 			goto out;
    677 		}
    678 
    679 		/* XXX both end must be valid? (I mean, not 0.0.0.0) */
    680 	}
    681 
    682 	if (sc->gif_si) {
    683 		softint_disestablish(sc->gif_si);
    684 		sc->gif_si = NULL;
    685 	}
    686 
    687 	/* XXX we can detach from both, but be polite just in case */
    688 	if (sc->gif_psrc)
    689 		switch (sc->gif_psrc->sa_family) {
    690 #ifdef INET
    691 		case AF_INET:
    692 			(void)in_gif_detach(sc);
    693 			break;
    694 #endif
    695 #ifdef INET6
    696 		case AF_INET6:
    697 			(void)in6_gif_detach(sc);
    698 			break;
    699 #endif
    700 		}
    701 
    702 	osrc = sc->gif_psrc;
    703 	odst = sc->gif_pdst;
    704 	sc->gif_psrc = sc->gif_pdst = NULL;
    705 	sc->gif_si = softint_establish(SOFTINT_NET, gifintr, sc);
    706 	if (sc->gif_si == NULL) {
    707 		error = ENOMEM;
    708 		goto rollback;
    709 	}
    710 
    711 	if ((sc->gif_psrc = sockaddr_dup(src, M_WAITOK)) == NULL) {
    712 		error = ENOMEM;
    713 		goto rollback;
    714 	}
    715 
    716 	if ((sc->gif_pdst = sockaddr_dup(dst, M_WAITOK)) == NULL) {
    717 		error = ENOMEM;
    718 		goto rollback;
    719 	}
    720 
    721 	switch (sc->gif_psrc->sa_family) {
    722 #ifdef INET
    723 	case AF_INET:
    724 		error = in_gif_attach(sc);
    725 		break;
    726 #endif
    727 #ifdef INET6
    728 	case AF_INET6:
    729 		error = in6_gif_attach(sc);
    730 		break;
    731 #endif
    732 	default:
    733 		error = EINVAL;
    734 		break;
    735 	}
    736 	if (error)
    737 		goto rollback;
    738 
    739 	if (osrc)
    740 		sockaddr_free(osrc);
    741 	if (odst)
    742 		sockaddr_free(odst);
    743 
    744 	error = 0;
    745 	goto out;
    746 
    747 rollback:
    748 	if (sc->gif_psrc != NULL)
    749 		sockaddr_free(sc->gif_psrc);
    750 	if (sc->gif_pdst != NULL)
    751 		sockaddr_free(sc->gif_pdst);
    752 	sc->gif_psrc = osrc;
    753 	sc->gif_pdst = odst;
    754 
    755 	if (sc->gif_si) {
    756 		softint_disestablish(sc->gif_si);
    757 		sc->gif_si = NULL;
    758 	}
    759 
    760 out:
    761 	if (sc->gif_psrc && sc->gif_pdst)
    762 		ifp->if_flags |= IFF_RUNNING;
    763 	else
    764 		ifp->if_flags &= ~IFF_RUNNING;
    765 
    766 	splx(s);
    767 	return error;
    768 }
    769 
    770 void
    771 gif_delete_tunnel(struct ifnet *ifp)
    772 {
    773 	struct gif_softc *sc = ifp->if_softc;
    774 	int s;
    775 
    776 	s = splsoftnet();
    777 
    778 	if (sc->gif_si) {
    779 		softint_disestablish(sc->gif_si);
    780 		sc->gif_si = NULL;
    781 	}
    782 	if (sc->gif_psrc) {
    783 		sockaddr_free(sc->gif_psrc);
    784 		sc->gif_psrc = NULL;
    785 	}
    786 	if (sc->gif_pdst) {
    787 		sockaddr_free(sc->gif_pdst);
    788 		sc->gif_pdst = NULL;
    789 	}
    790 	/* it is safe to detach from both */
    791 #ifdef INET
    792 	(void)in_gif_detach(sc);
    793 #endif
    794 #ifdef INET6
    795 	(void)in6_gif_detach(sc);
    796 #endif
    797 
    798 	if (sc->gif_psrc && sc->gif_pdst)
    799 		ifp->if_flags |= IFF_RUNNING;
    800 	else
    801 		ifp->if_flags &= ~IFF_RUNNING;
    802 	splx(s);
    803 }
    804