xref: /netbsd-src/sys/net/if_gif.c (revision 212397c69a103ae7e5eafa8731ddfae671d2dee7)
1 /*	$NetBSD: if_gif.c,v 1.105 2016/01/18 06:08:26 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.105 2016/01/18 06:08:26 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/cpu.h>
53 #include <sys/intr.h>
54 #include <sys/kmem.h>
55 #include <sys/sysctl.h>
56 
57 #include <net/if.h>
58 #include <net/if_types.h>
59 #include <net/netisr.h>
60 #include <net/route.h>
61 #include <net/bpf.h>
62 
63 #include <netinet/in.h>
64 #include <netinet/in_systm.h>
65 #include <netinet/ip.h>
66 #ifdef	INET
67 #include <netinet/in_var.h>
68 #endif	/* INET */
69 #include <netinet/in_gif.h>
70 
71 #ifdef INET6
72 #ifndef INET
73 #include <netinet/in.h>
74 #endif
75 #include <netinet6/in6_var.h>
76 #include <netinet/ip6.h>
77 #include <netinet6/ip6_var.h>
78 #include <netinet6/in6_gif.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 void	gif_sysctl_setup(struct sysctllog **);
96 
97 static int	gif_clone_create(struct if_clone *, int);
98 static int	gif_clone_destroy(struct ifnet *);
99 static int	gif_check_nesting(struct ifnet *, struct mbuf *);
100 
101 static int	gif_encap_attach(struct gif_softc *);
102 static int	gif_encap_detach(struct gif_softc *);
103 
104 static struct if_clone gif_cloner =
105     IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
106 
107 #ifndef MAX_GIF_NEST
108 /*
109  * This macro controls the upper limitation on nesting of gif tunnels.
110  * Since, setting a large value to this macro with a careless configuration
111  * may introduce system crash, we don't allow any nestings by default.
112  * If you need to configure nested gif tunnels, you can define this macro
113  * in your kernel configuration file.  However, if you do so, please be
114  * careful to configure the tunnels so that it won't make a loop.
115  */
116 #define MAX_GIF_NEST 1
117 #endif
118 static int max_gif_nesting = MAX_GIF_NEST;
119 
120 static void
121 gif_sysctl_setup(struct sysctllog **clog)
122 {
123 
124 #ifdef INET
125 	sysctl_createv(clog, 0, NULL, NULL,
126 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
127 		       CTLTYPE_INT, "gifttl",
128 		       SYSCTL_DESCR("Default TTL for a gif tunnel datagram"),
129 		       NULL, 0, &ip_gif_ttl, 0,
130 		       CTL_NET, PF_INET, IPPROTO_IP,
131 		       IPCTL_GIF_TTL, CTL_EOL);
132 #endif
133 #ifdef INET6
134 	sysctl_createv(clog, 0, NULL, NULL,
135 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
136 		       CTLTYPE_INT, "gifhlim",
137 		       SYSCTL_DESCR("Default hop limit for a gif tunnel datagram"),
138 		       NULL, 0, &ip6_gif_hlim, 0,
139 		       CTL_NET, PF_INET6, IPPROTO_IPV6,
140 		       IPV6CTL_GIF_HLIM, CTL_EOL);
141 #endif
142 }
143 
144 /* ARGSUSED */
145 void
146 gifattach(int count)
147 {
148 
149 	LIST_INIT(&gif_softc_list);
150 	if_clone_attach(&gif_cloner);
151 
152 	gif_sysctl_setup(NULL);
153 }
154 
155 static int
156 gif_clone_create(struct if_clone *ifc, int unit)
157 {
158 	struct gif_softc *sc;
159 
160 	sc = kmem_zalloc(sizeof(struct gif_softc), KM_SLEEP);
161 	if (sc == NULL)
162 		return ENOMEM;
163 
164 	if_initname(&sc->gif_if, ifc->ifc_name, unit);
165 
166 	gifattach0(sc);
167 
168 	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
169 	return (0);
170 }
171 
172 void
173 gifattach0(struct gif_softc *sc)
174 {
175 
176 	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
177 
178 	sc->gif_if.if_addrlen = 0;
179 	sc->gif_if.if_mtu    = GIF_MTU;
180 	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
181 	sc->gif_if.if_ioctl  = gif_ioctl;
182 	sc->gif_if.if_output = gif_output;
183 	sc->gif_if.if_type   = IFT_GIF;
184 	sc->gif_if.if_dlt    = DLT_NULL;
185 	sc->gif_if.if_softc  = sc;
186 	IFQ_SET_READY(&sc->gif_if.if_snd);
187 	if_attach(&sc->gif_if);
188 	if_alloc_sadl(&sc->gif_if);
189 	bpf_attach(&sc->gif_if, DLT_NULL, sizeof(u_int));
190 }
191 
192 static int
193 gif_clone_destroy(struct ifnet *ifp)
194 {
195 	struct gif_softc *sc = (void *) ifp;
196 
197 	LIST_REMOVE(sc, gif_list);
198 
199 	gif_delete_tunnel(&sc->gif_if);
200 	bpf_detach(ifp);
201 	if_detach(ifp);
202 	rtcache_free(&sc->gif_ro);
203 
204 	kmem_free(sc, sizeof(struct gif_softc));
205 
206 	return (0);
207 }
208 
209 #ifdef GIF_ENCAPCHECK
210 int
211 gif_encapcheck(struct mbuf *m, int off, int proto, void *arg)
212 {
213 	struct ip ip;
214 	struct gif_softc *sc;
215 
216 	sc = arg;
217 	if (sc == NULL)
218 		return 0;
219 
220 	if ((sc->gif_if.if_flags & IFF_UP) == 0)
221 		return 0;
222 
223 	/* no physical address */
224 	if (!sc->gif_psrc || !sc->gif_pdst)
225 		return 0;
226 
227 	switch (proto) {
228 #ifdef INET
229 	case IPPROTO_IPV4:
230 		break;
231 #endif
232 #ifdef INET6
233 	case IPPROTO_IPV6:
234 		break;
235 #endif
236 	default:
237 		return 0;
238 	}
239 
240 	/* Bail on short packets */
241 	KASSERT(m->m_flags & M_PKTHDR);
242 	if (m->m_pkthdr.len < sizeof(ip))
243 		return 0;
244 
245 	m_copydata(m, 0, sizeof(ip), &ip);
246 
247 	switch (ip.ip_v) {
248 #ifdef INET
249 	case 4:
250 		if (sc->gif_psrc->sa_family != AF_INET ||
251 		    sc->gif_pdst->sa_family != AF_INET)
252 			return 0;
253 		return gif_encapcheck4(m, off, proto, arg);
254 #endif
255 #ifdef INET6
256 	case 6:
257 		if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
258 			return 0;
259 		if (sc->gif_psrc->sa_family != AF_INET6 ||
260 		    sc->gif_pdst->sa_family != AF_INET6)
261 			return 0;
262 		return gif_encapcheck6(m, off, proto, arg);
263 #endif
264 	default:
265 		return 0;
266 	}
267 }
268 #endif
269 
270 /*
271  * gif may cause infinite recursion calls when misconfigured.
272  * We'll prevent this by introducing upper limit.
273  */
274 static int
275 gif_check_nesting(struct ifnet *ifp, struct mbuf *m)
276 {
277 	struct m_tag *mtag;
278 	int *count;
279 
280 	mtag = m_tag_find(m, PACKET_TAG_TUNNEL_INFO, NULL);
281 	if (mtag != NULL) {
282 		count = (int *)(mtag + 1);
283 		if (++(*count) > max_gif_nesting) {
284 			log(LOG_NOTICE,
285 			    "%s: recursively called too many times(%d)\n",
286 			    if_name(ifp),
287 			    *count);
288 			return EIO;
289 		}
290 	} else {
291 		mtag = m_tag_get(PACKET_TAG_TUNNEL_INFO, sizeof(*count),
292 		    M_NOWAIT);
293 		if (mtag != NULL) {
294 			m_tag_prepend(m, mtag);
295 			count = (int *)(mtag + 1);
296 			*count = 0;
297 		} else {
298 			log(LOG_DEBUG,
299 			    "%s: m_tag_get() failed, recursion calls are not prevented.\n",
300 			    if_name(ifp));
301 		}
302 	}
303 
304 	return 0;
305 }
306 
307 int
308 gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
309     struct rtentry *rt)
310 {
311 	struct gif_softc *sc = ifp->if_softc;
312 	int error = 0;
313 	ALTQ_DECL(struct altq_pktattr pktattr;)
314 	int s;
315 
316 	IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
317 
318 	if ((error = gif_check_nesting(ifp, m)) != 0) {
319 		m_free(m);
320 		goto end;
321 	}
322 
323 	m->m_flags &= ~(M_BCAST|M_MCAST);
324 	if (!(ifp->if_flags & IFF_UP) ||
325 	    sc->gif_psrc == NULL || sc->gif_pdst == NULL ||
326 	    sc->gif_si == NULL) {
327 		m_freem(m);
328 		error = ENETDOWN;
329 		goto end;
330 	}
331 
332 	/* XXX should we check if our outer source is legal? */
333 
334 	/* use DLT_NULL encapsulation here to pass inner af type */
335 	M_PREPEND(m, sizeof(int), M_DONTWAIT);
336 	if (!m) {
337 		error = ENOBUFS;
338 		goto end;
339 	}
340 	*mtod(m, int *) = dst->sa_family;
341 
342 	/* Clear checksum-offload flags. */
343 	m->m_pkthdr.csum_flags = 0;
344 	m->m_pkthdr.csum_data = 0;
345 
346 	s = splnet();
347 	IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
348 	if (error) {
349 		splx(s);
350 		goto end;
351 	}
352 
353 	/* softint_schedule() must be called with kpreempt_disabled() */
354 	softint_schedule(sc->gif_si);
355 	splx(s);
356 
357 	error = 0;
358 
359   end:
360 	if (error)
361 		ifp->if_oerrors++;
362 	return error;
363 }
364 
365 static void
366 gifintr(void *arg)
367 {
368 	struct gif_softc *sc;
369 	struct ifnet *ifp;
370 	struct mbuf *m;
371 	int family;
372 	int len;
373 	int s;
374 	int error;
375 
376 	sc = arg;
377 	ifp = &sc->gif_if;
378 
379 	/*
380 	 * other CPUs does {set,delete}_tunnel after curcpu have done
381 	 * softint_schedule().
382 	 */
383 	if (sc->gif_pdst == NULL || sc->gif_psrc == NULL) {
384 		IFQ_PURGE(&ifp->if_snd);
385 		return;
386 	}
387 
388 	/* output processing */
389 	while (1) {
390 		s = splnet();
391 		IFQ_DEQUEUE(&sc->gif_if.if_snd, m);
392 		splx(s);
393 		if (m == NULL)
394 			break;
395 
396 		/* grab and chop off inner af type */
397 		if (sizeof(int) > m->m_len) {
398 			m = m_pullup(m, sizeof(int));
399 			if (!m) {
400 				ifp->if_oerrors++;
401 				continue;
402 			}
403 		}
404 		family = *mtod(m, int *);
405 		bpf_mtap(ifp, m);
406 		m_adj(m, sizeof(int));
407 
408 		len = m->m_pkthdr.len;
409 
410 		/* dispatch to output logic based on outer AF */
411 		switch (sc->gif_psrc->sa_family) {
412 #ifdef INET
413 		case AF_INET:
414 			mutex_enter(softnet_lock);
415 			error = in_gif_output(ifp, family, m);
416 			mutex_exit(softnet_lock);
417 			break;
418 #endif
419 #ifdef INET6
420 		case AF_INET6:
421 			mutex_enter(softnet_lock);
422 			error = in6_gif_output(ifp, family, m);
423 			mutex_exit(softnet_lock);
424 			break;
425 #endif
426 		default:
427 			m_freem(m);
428 			error = ENETDOWN;
429 			break;
430 		}
431 
432 		if (error)
433 			ifp->if_oerrors++;
434 		else {
435 			ifp->if_opackets++;
436 			ifp->if_obytes += len;
437 		}
438 	}
439 }
440 
441 void
442 gif_input(struct mbuf *m, int af, struct ifnet *ifp)
443 {
444 	pktqueue_t *pktq;
445 	size_t pktlen;
446 	int s;
447 
448 	if (ifp == NULL) {
449 		/* just in case */
450 		m_freem(m);
451 		return;
452 	}
453 
454 	m->m_pkthdr.rcvif = ifp;
455 	pktlen = m->m_pkthdr.len;
456 
457 	bpf_mtap_af(ifp, af, m);
458 
459 	/*
460 	 * Put the packet to the network layer input queue according to the
461 	 * specified address family.  Note: we avoid direct call to the
462 	 * input function of the network layer in order to avoid recursion.
463 	 * This may be revisited in the future.
464 	 */
465 	switch (af) {
466 #ifdef INET
467 	case AF_INET:
468 		pktq = ip_pktq;
469 		break;
470 #endif
471 #ifdef INET6
472 	case AF_INET6:
473 		pktq = ip6_pktq;
474 		break;
475 #endif
476 	default:
477 		m_freem(m);
478 		return;
479 	}
480 
481 	s = splnet();
482 	if (__predict_true(pktq_enqueue(pktq, m, 0))) {
483 		ifp->if_ibytes += pktlen;
484 		ifp->if_ipackets++;
485 	} else {
486 		m_freem(m);
487 	}
488 	splx(s);
489 }
490 
491 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
492 int
493 gif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
494 {
495 	struct gif_softc *sc  = ifp->if_softc;
496 	struct ifreq     *ifr = (struct ifreq*)data;
497 	struct ifaddr    *ifa = (struct ifaddr*)data;
498 	int error = 0, size;
499 	struct sockaddr *dst, *src;
500 
501 	switch (cmd) {
502 	case SIOCINITIFADDR:
503 		ifp->if_flags |= IFF_UP;
504 		ifa->ifa_rtrequest = p2p_rtrequest;
505 		break;
506 
507 	case SIOCADDMULTI:
508 	case SIOCDELMULTI:
509 		switch (ifr->ifr_addr.sa_family) {
510 #ifdef INET
511 		case AF_INET:	/* IP supports Multicast */
512 			break;
513 #endif /* INET */
514 #ifdef INET6
515 		case AF_INET6:	/* IP6 supports Multicast */
516 			break;
517 #endif /* INET6 */
518 		default:  /* Other protocols doesn't support Multicast */
519 			error = EAFNOSUPPORT;
520 			break;
521 		}
522 		break;
523 
524 	case SIOCSIFMTU:
525 		if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX)
526 			return EINVAL;
527 		else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
528 			error = 0;
529 		break;
530 
531 #ifdef INET
532 	case SIOCSIFPHYADDR:
533 #endif
534 #ifdef INET6
535 	case SIOCSIFPHYADDR_IN6:
536 #endif /* INET6 */
537 	case SIOCSLIFPHYADDR:
538 		switch (cmd) {
539 #ifdef INET
540 		case SIOCSIFPHYADDR:
541 			src = (struct sockaddr *)
542 				&(((struct in_aliasreq *)data)->ifra_addr);
543 			dst = (struct sockaddr *)
544 				&(((struct in_aliasreq *)data)->ifra_dstaddr);
545 			break;
546 #endif
547 #ifdef INET6
548 		case SIOCSIFPHYADDR_IN6:
549 			src = (struct sockaddr *)
550 				&(((struct in6_aliasreq *)data)->ifra_addr);
551 			dst = (struct sockaddr *)
552 				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
553 			break;
554 #endif
555 		case SIOCSLIFPHYADDR:
556 			src = (struct sockaddr *)
557 				&(((struct if_laddrreq *)data)->addr);
558 			dst = (struct sockaddr *)
559 				&(((struct if_laddrreq *)data)->dstaddr);
560 			break;
561 		default:
562 			return EINVAL;
563 		}
564 
565 		/* sa_family must be equal */
566 		if (src->sa_family != dst->sa_family)
567 			return EINVAL;
568 
569 		/* validate sa_len */
570 		switch (src->sa_family) {
571 #ifdef INET
572 		case AF_INET:
573 			if (src->sa_len != sizeof(struct sockaddr_in))
574 				return EINVAL;
575 			break;
576 #endif
577 #ifdef INET6
578 		case AF_INET6:
579 			if (src->sa_len != sizeof(struct sockaddr_in6))
580 				return EINVAL;
581 			break;
582 #endif
583 		default:
584 			return EAFNOSUPPORT;
585 		}
586 		switch (dst->sa_family) {
587 #ifdef INET
588 		case AF_INET:
589 			if (dst->sa_len != sizeof(struct sockaddr_in))
590 				return EINVAL;
591 			break;
592 #endif
593 #ifdef INET6
594 		case AF_INET6:
595 			if (dst->sa_len != sizeof(struct sockaddr_in6))
596 				return EINVAL;
597 			break;
598 #endif
599 		default:
600 			return EAFNOSUPPORT;
601 		}
602 
603 		/* check sa_family looks sane for the cmd */
604 		switch (cmd) {
605 		case SIOCSIFPHYADDR:
606 			if (src->sa_family == AF_INET)
607 				break;
608 			return EAFNOSUPPORT;
609 #ifdef INET6
610 		case SIOCSIFPHYADDR_IN6:
611 			if (src->sa_family == AF_INET6)
612 				break;
613 			return EAFNOSUPPORT;
614 #endif /* INET6 */
615 		case SIOCSLIFPHYADDR:
616 			/* checks done in the above */
617 			break;
618 		}
619 
620 		error = gif_set_tunnel(&sc->gif_if, src, dst);
621 		break;
622 
623 #ifdef SIOCDIFPHYADDR
624 	case SIOCDIFPHYADDR:
625 		gif_delete_tunnel(&sc->gif_if);
626 		break;
627 #endif
628 
629 	case SIOCGIFPSRCADDR:
630 #ifdef INET6
631 	case SIOCGIFPSRCADDR_IN6:
632 #endif /* INET6 */
633 		if (sc->gif_psrc == NULL) {
634 			error = EADDRNOTAVAIL;
635 			goto bad;
636 		}
637 		src = sc->gif_psrc;
638 		switch (cmd) {
639 #ifdef INET
640 		case SIOCGIFPSRCADDR:
641 			dst = &ifr->ifr_addr;
642 			size = sizeof(ifr->ifr_addr);
643 			break;
644 #endif /* INET */
645 #ifdef INET6
646 		case SIOCGIFPSRCADDR_IN6:
647 			dst = (struct sockaddr *)
648 				&(((struct in6_ifreq *)data)->ifr_addr);
649 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
650 			break;
651 #endif /* INET6 */
652 		default:
653 			error = EADDRNOTAVAIL;
654 			goto bad;
655 		}
656 		if (src->sa_len > size)
657 			return EINVAL;
658 		memcpy(dst, src, src->sa_len);
659 		break;
660 
661 	case SIOCGIFPDSTADDR:
662 #ifdef INET6
663 	case SIOCGIFPDSTADDR_IN6:
664 #endif /* INET6 */
665 		if (sc->gif_pdst == NULL) {
666 			error = EADDRNOTAVAIL;
667 			goto bad;
668 		}
669 		src = sc->gif_pdst;
670 		switch (cmd) {
671 #ifdef INET
672 		case SIOCGIFPDSTADDR:
673 			dst = &ifr->ifr_addr;
674 			size = sizeof(ifr->ifr_addr);
675 			break;
676 #endif /* INET */
677 #ifdef INET6
678 		case SIOCGIFPDSTADDR_IN6:
679 			dst = (struct sockaddr *)
680 				&(((struct in6_ifreq *)data)->ifr_addr);
681 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
682 			break;
683 #endif /* INET6 */
684 		default:
685 			error = EADDRNOTAVAIL;
686 			goto bad;
687 		}
688 		if (src->sa_len > size)
689 			return EINVAL;
690 		memcpy(dst, src, src->sa_len);
691 		break;
692 
693 	case SIOCGLIFPHYADDR:
694 		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
695 			error = EADDRNOTAVAIL;
696 			goto bad;
697 		}
698 
699 		/* copy src */
700 		src = sc->gif_psrc;
701 		dst = (struct sockaddr *)
702 			&(((struct if_laddrreq *)data)->addr);
703 		size = sizeof(((struct if_laddrreq *)data)->addr);
704 		if (src->sa_len > size)
705 			return EINVAL;
706 		memcpy(dst, src, src->sa_len);
707 
708 		/* copy dst */
709 		src = sc->gif_pdst;
710 		dst = (struct sockaddr *)
711 			&(((struct if_laddrreq *)data)->dstaddr);
712 		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
713 		if (src->sa_len > size)
714 			return EINVAL;
715 		memcpy(dst, src, src->sa_len);
716 		break;
717 
718 	default:
719 		return ifioctl_common(ifp, cmd, data);
720 	}
721  bad:
722 	return error;
723 }
724 
725 static int
726 gif_encap_attach(struct gif_softc *sc)
727 {
728 	int error;
729 
730 	if (sc == NULL || sc->gif_psrc == NULL)
731 		return EINVAL;
732 
733 	switch (sc->gif_psrc->sa_family) {
734 #ifdef INET
735 	case AF_INET:
736 		error = in_gif_attach(sc);
737 		break;
738 #endif
739 #ifdef INET6
740 	case AF_INET6:
741 		error = in6_gif_attach(sc);
742 		break;
743 #endif
744 	default:
745 		error = EINVAL;
746 		break;
747 	}
748 
749 	return error;
750 }
751 
752 static int
753 gif_encap_detach(struct gif_softc *sc)
754 {
755 	int error;
756 
757 	if (sc == NULL || sc->gif_psrc == NULL)
758 		return EINVAL;
759 
760 	switch (sc->gif_psrc->sa_family) {
761 #ifdef INET
762 	case AF_INET:
763 		error = in_gif_detach(sc);
764 		break;
765 #endif
766 #ifdef INET6
767 	case AF_INET6:
768 		error = in6_gif_detach(sc);
769 		break;
770 #endif
771 	default:
772 		error = EINVAL;
773 		break;
774 	}
775 
776 	return error;
777 }
778 
779 int
780 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
781 {
782 	struct gif_softc *sc = ifp->if_softc;
783 	struct gif_softc *sc2;
784 	struct sockaddr *osrc, *odst;
785 	struct sockaddr *nsrc, *ndst;
786 	void *osi;
787 	int s;
788 	int error;
789 
790 	s = splsoftnet();
791 
792 	LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
793 		if (sc2 == sc)
794 			continue;
795 		if (!sc2->gif_pdst || !sc2->gif_psrc)
796 			continue;
797 		/* can't configure same pair of address onto two gifs */
798 		if (sockaddr_cmp(sc2->gif_pdst, dst) == 0 &&
799 		    sockaddr_cmp(sc2->gif_psrc, src) == 0) {
800 			/* continue to use the old configureation. */
801 			splx(s);
802 			return EADDRNOTAVAIL;
803 		}
804 
805 		/* XXX both end must be valid? (I mean, not 0.0.0.0) */
806 	}
807 
808 	if ((nsrc = sockaddr_dup(src, M_WAITOK)) == NULL) {
809 		splx(s);
810 		return ENOMEM;
811 	}
812 	if ((ndst = sockaddr_dup(dst, M_WAITOK)) == NULL) {
813 		sockaddr_free(nsrc);
814 		splx(s);
815 		return ENOMEM;
816 	}
817 
818 	/* Firstly, clear old configurations. */
819 	if (sc->gif_si) {
820 		osrc = sc->gif_psrc;
821 		odst = sc->gif_pdst;
822 		osi = sc->gif_si;
823 		sc->gif_psrc = NULL;
824 		sc->gif_pdst = NULL;
825 		sc->gif_si = NULL;
826 		/*
827 		 * At this point, gif_output() does not softint_schedule()
828 		 * any more. However, there are below 2 fears of other CPUs
829 		 * which would cause panic because of the race between
830 		 * softint_execute() and softint_disestablish().
831 		 *     (a) gif_output() has done softint_schedule(), and softint
832 		 *         (gifintr()) is waiting for execution
833 		 *         => This pattern is avoided by waiting SOFTINT_PENDING
834 		 *            CPUs in softint_disestablish()
835 		 *     (b) gifintr() is already running
836 		 *         => This pattern is avoided by waiting SOFTINT_ACTIVE
837 		 *            CPUs in softint_disestablish()
838 		 */
839 
840 		softint_disestablish(osi);
841 		sc->gif_psrc = osrc;
842 		sc->gif_pdst = odst;
843 		osrc = NULL;
844 		odst = NULL;
845 	}
846 	/* XXX we can detach from both, but be polite just in case */
847 	if (sc->gif_psrc)
848 		(void)gif_encap_detach(sc);
849 
850 	/*
851 	 * Secondly, try to set new configurations.
852 	 * If the setup failed, rollback to old configurations.
853 	 */
854 	do {
855 		osrc = sc->gif_psrc;
856 		odst = sc->gif_pdst;
857 		sc->gif_psrc = nsrc;
858 		sc->gif_pdst = ndst;
859 
860 		error = gif_encap_attach(sc);
861 		if (error) {
862 			/* rollback to the last configuration. */
863 			nsrc = osrc;
864 			ndst = odst;
865 			osrc = sc->gif_psrc;
866 			odst = sc->gif_pdst;
867 
868 			continue;
869 		}
870 
871 		sc->gif_si = softint_establish(SOFTINT_NET, gifintr, sc);
872 		if (sc->gif_si == NULL) {
873 			(void)gif_encap_detach(sc);
874 
875 			/* rollback to the last configuration. */
876 			nsrc = osrc;
877 			ndst = odst;
878 			osrc = sc->gif_psrc;
879 			odst = sc->gif_pdst;
880 
881 			error = ENOMEM;
882 			continue;
883 		}
884 	} while (error != 0 && (nsrc != NULL && ndst != NULL));
885 	/* Thirdly, even rollback failed, clear configurations. */
886 	if (error) {
887 		osrc = sc->gif_psrc;
888 		odst = sc->gif_pdst;
889 		sc->gif_psrc = NULL;
890 		sc->gif_pdst = NULL;
891 	}
892 
893 	if (osrc)
894 		sockaddr_free(osrc);
895 	if (odst)
896 		sockaddr_free(odst);
897 
898 	if (sc->gif_psrc && sc->gif_pdst)
899 		ifp->if_flags |= IFF_RUNNING;
900 	else
901 		ifp->if_flags &= ~IFF_RUNNING;
902 
903 	splx(s);
904 	return error;
905 }
906 
907 void
908 gif_delete_tunnel(struct ifnet *ifp)
909 {
910 	struct gif_softc *sc = ifp->if_softc;
911 	struct sockaddr *osrc, *odst;
912 	void *osi;
913 	int s;
914 
915 	s = splsoftnet();
916 
917 	if (sc->gif_si) {
918 		osrc = sc->gif_psrc;
919 		odst = sc->gif_pdst;
920 		osi = sc->gif_si;
921 
922 		sc->gif_psrc = NULL;
923 		sc->gif_pdst = NULL;
924 		sc->gif_si = NULL;
925 
926 		softint_disestablish(osi);
927 		sc->gif_psrc = osrc;
928 		sc->gif_pdst = odst;
929 	}
930 	if (sc->gif_psrc) {
931 		sockaddr_free(sc->gif_psrc);
932 		sc->gif_psrc = NULL;
933 	}
934 	if (sc->gif_pdst) {
935 		sockaddr_free(sc->gif_pdst);
936 		sc->gif_pdst = NULL;
937 	}
938 	/* it is safe to detach from both */
939 #ifdef INET
940 	(void)in_gif_detach(sc);
941 #endif
942 #ifdef INET6
943 	(void)in6_gif_detach(sc);
944 #endif
945 
946 	if (sc->gif_psrc && sc->gif_pdst)
947 		ifp->if_flags |= IFF_RUNNING;
948 	else
949 		ifp->if_flags &= ~IFF_RUNNING;
950 	splx(s);
951 }
952