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