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