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