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