xref: /freebsd/sys/net/if_gif.c (revision 262e143bd46171a6415a5b28af260a5efa2a3db8)
1 /*	$FreeBSD$	*/
2 /*	$KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun 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 "opt_inet.h"
34 #include "opt_inet6.h"
35 #include "opt_mac.h"
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/mac.h>
41 #include <sys/malloc.h>
42 #include <sys/mbuf.h>
43 #include <sys/module.h>
44 #include <sys/socket.h>
45 #include <sys/sockio.h>
46 #include <sys/errno.h>
47 #include <sys/time.h>
48 #include <sys/sysctl.h>
49 #include <sys/syslog.h>
50 #include <sys/protosw.h>
51 #include <sys/conf.h>
52 #include <machine/cpu.h>
53 
54 #include <net/if.h>
55 #include <net/if_clone.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 #include <netinet/in_gif.h>
67 #include <netinet/ip_var.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/scope6_var.h>
78 #include <netinet6/in6_gif.h>
79 #include <netinet6/ip6protosw.h>
80 #endif /* INET6 */
81 
82 #include <netinet/ip_encap.h>
83 #include <net/if_gif.h>
84 
85 #include <net/net_osdep.h>
86 
87 #define GIFNAME		"gif"
88 
89 /*
90  * gif_mtx protects the global gif_softc_list.
91  * XXX: Per-softc locking is still required.
92  */
93 static struct mtx gif_mtx;
94 static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
95 static LIST_HEAD(, gif_softc) gif_softc_list;
96 
97 void	(*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af);
98 void	(*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
99 void	(*ng_gif_attach_p)(struct ifnet *ifp);
100 void	(*ng_gif_detach_p)(struct ifnet *ifp);
101 
102 static int	gif_clone_create(struct if_clone *, int);
103 static void	gif_clone_destroy(struct ifnet *);
104 
105 IFC_SIMPLE_DECLARE(gif, 0);
106 
107 static int gifmodevent(module_t, int, void *);
108 
109 SYSCTL_DECL(_net_link);
110 SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
111     "Generic Tunnel Interface");
112 #ifndef MAX_GIF_NEST
113 /*
114  * This macro controls the default upper limitation on nesting of gif tunnels.
115  * Since, setting a large value to this macro with a careless configuration
116  * may introduce system crash, we don't allow any nestings by default.
117  * If you need to configure nested gif tunnels, you can define this macro
118  * in your kernel configuration file.  However, if you do so, please be
119  * careful to configure the tunnels so that it won't make a loop.
120  */
121 #define MAX_GIF_NEST 1
122 #endif
123 static int max_gif_nesting = MAX_GIF_NEST;
124 SYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW,
125     &max_gif_nesting, 0, "Max nested tunnels");
126 
127 /*
128  * By default, we disallow creation of multiple tunnels between the same
129  * pair of addresses.  Some applications require this functionality so
130  * we allow control over this check here.
131  */
132 #ifdef XBONEHACK
133 static int parallel_tunnels = 1;
134 #else
135 static int parallel_tunnels = 0;
136 #endif
137 SYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW,
138     &parallel_tunnels, 0, "Allow parallel tunnels?");
139 
140 static 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_GIF, M_WAITOK | M_ZERO);
148 	GIF2IFP(sc) = if_alloc(IFT_GIF);
149 	if (GIF2IFP(sc) == NULL) {
150 		free(sc, M_GIF);
151 		return (ENOSPC);
152 	}
153 
154 	GIF2IFP(sc)->if_softc = sc;
155 	if_initname(GIF2IFP(sc), ifc->ifc_name, unit);
156 
157 	gifattach0(sc);
158 
159 	mtx_lock(&gif_mtx);
160 	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
161 	mtx_unlock(&gif_mtx);
162 	return (0);
163 }
164 
165 void
166 gifattach0(sc)
167 	struct gif_softc *sc;
168 {
169 
170 	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
171 
172 	GIF2IFP(sc)->if_addrlen = 0;
173 	GIF2IFP(sc)->if_mtu    = GIF_MTU;
174 	GIF2IFP(sc)->if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
175 #if 0
176 	/* turn off ingress filter */
177 	GIF2IFP(sc)->if_flags  |= IFF_LINK2;
178 #endif
179 	GIF2IFP(sc)->if_ioctl  = gif_ioctl;
180 	GIF2IFP(sc)->if_output = gif_output;
181 	GIF2IFP(sc)->if_snd.ifq_maxlen = IFQ_MAXLEN;
182 	if_attach(GIF2IFP(sc));
183 	bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int32_t));
184 	if (ng_gif_attach_p != NULL)
185 		(*ng_gif_attach_p)(GIF2IFP(sc));
186 }
187 
188 static void
189 gif_clone_destroy(ifp)
190 	struct ifnet *ifp;
191 {
192 	int err;
193 	struct gif_softc *sc = ifp->if_softc;
194 
195 	mtx_lock(&gif_mtx);
196 	LIST_REMOVE(sc, gif_list);
197 	mtx_unlock(&gif_mtx);
198 
199 	gif_delete_tunnel(ifp);
200 #ifdef INET6
201 	if (sc->encap_cookie6 != NULL) {
202 		err = encap_detach(sc->encap_cookie6);
203 		KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
204 	}
205 #endif
206 #ifdef INET
207 	if (sc->encap_cookie4 != NULL) {
208 		err = encap_detach(sc->encap_cookie4);
209 		KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
210 	}
211 #endif
212 
213 	if (ng_gif_detach_p != NULL)
214 		(*ng_gif_detach_p)(ifp);
215 	bpfdetach(ifp);
216 	if_detach(ifp);
217 	if_free(ifp);
218 
219 	free(sc, M_GIF);
220 }
221 
222 static int
223 gifmodevent(mod, type, data)
224 	module_t mod;
225 	int type;
226 	void *data;
227 {
228 
229 	switch (type) {
230 	case MOD_LOAD:
231 		mtx_init(&gif_mtx, "gif_mtx", NULL, MTX_DEF);
232 		LIST_INIT(&gif_softc_list);
233 		if_clone_attach(&gif_cloner);
234 
235 #ifdef INET6
236 		ip6_gif_hlim = GIF_HLIM;
237 #endif
238 
239 		break;
240 	case MOD_UNLOAD:
241 		if_clone_detach(&gif_cloner);
242 		mtx_destroy(&gif_mtx);
243 #ifdef INET6
244 		ip6_gif_hlim = 0;
245 #endif
246 		break;
247 	default:
248 		return EOPNOTSUPP;
249 	}
250 	return 0;
251 }
252 
253 static moduledata_t gif_mod = {
254 	"if_gif",
255 	gifmodevent,
256 	0
257 };
258 
259 DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
260 MODULE_VERSION(if_gif, 1);
261 
262 int
263 gif_encapcheck(m, off, proto, arg)
264 	const struct mbuf *m;
265 	int off;
266 	int proto;
267 	void *arg;
268 {
269 	struct ip ip;
270 	struct gif_softc *sc;
271 
272 	sc = (struct gif_softc *)arg;
273 	if (sc == NULL)
274 		return 0;
275 
276 	if ((GIF2IFP(sc)->if_flags & IFF_UP) == 0)
277 		return 0;
278 
279 	/* no physical address */
280 	if (!sc->gif_psrc || !sc->gif_pdst)
281 		return 0;
282 
283 	switch (proto) {
284 #ifdef INET
285 	case IPPROTO_IPV4:
286 		break;
287 #endif
288 #ifdef INET6
289 	case IPPROTO_IPV6:
290 		break;
291 #endif
292 	default:
293 		return 0;
294 	}
295 
296 	/* Bail on short packets */
297 	if (m->m_pkthdr.len < sizeof(ip))
298 		return 0;
299 
300 	m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
301 
302 	switch (ip.ip_v) {
303 #ifdef INET
304 	case 4:
305 		if (sc->gif_psrc->sa_family != AF_INET ||
306 		    sc->gif_pdst->sa_family != AF_INET)
307 			return 0;
308 		return gif_encapcheck4(m, off, proto, arg);
309 #endif
310 #ifdef INET6
311 	case 6:
312 		if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
313 			return 0;
314 		if (sc->gif_psrc->sa_family != AF_INET6 ||
315 		    sc->gif_pdst->sa_family != AF_INET6)
316 			return 0;
317 		return gif_encapcheck6(m, off, proto, arg);
318 #endif
319 	default:
320 		return 0;
321 	}
322 }
323 
324 int
325 gif_output(ifp, m, dst, rt)
326 	struct ifnet *ifp;
327 	struct mbuf *m;
328 	struct sockaddr *dst;
329 	struct rtentry *rt;	/* added in net2 */
330 {
331 	struct gif_softc *sc = ifp->if_softc;
332 	struct m_tag *mtag;
333 	int error = 0;
334 	int gif_called;
335 	u_int32_t af;
336 
337 #ifdef MAC
338 	error = mac_check_ifnet_transmit(ifp, m);
339 	if (error) {
340 		m_freem(m);
341 		goto end;
342 	}
343 #endif
344 
345 	/*
346 	 * gif may cause infinite recursion calls when misconfigured.
347 	 * We'll prevent this by detecting loops.
348 	 *
349 	 * High nesting level may cause stack exhaustion.
350 	 * We'll prevent this by introducing upper limit.
351 	 */
352 	gif_called = 1;
353 	mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, NULL);
354 	while (mtag != NULL) {
355 		if (*(struct ifnet **)(mtag + 1) == ifp) {
356 			log(LOG_NOTICE,
357 			    "gif_output: loop detected on %s\n",
358 			    (*(struct ifnet **)(mtag + 1))->if_xname);
359 			m_freem(m);
360 			error = EIO;	/* is there better errno? */
361 			goto end;
362 		}
363 		mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, mtag);
364 		gif_called++;
365 	}
366 	if (gif_called > max_gif_nesting) {
367 		log(LOG_NOTICE,
368 		    "gif_output: recursively called too many times(%d)\n",
369 		    gif_called);
370 		m_freem(m);
371 		error = EIO;	/* is there better errno? */
372 		goto end;
373 	}
374 	mtag = m_tag_alloc(MTAG_GIF, MTAG_GIF_CALLED, sizeof(struct ifnet *),
375 	    M_NOWAIT);
376 	if (mtag == NULL) {
377 		m_freem(m);
378 		error = ENOMEM;
379 		goto end;
380 	}
381 	*(struct ifnet **)(mtag + 1) = ifp;
382 	m_tag_prepend(m, mtag);
383 
384 	m->m_flags &= ~(M_BCAST|M_MCAST);
385 	if (!(ifp->if_flags & IFF_UP) ||
386 	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
387 		m_freem(m);
388 		error = ENETDOWN;
389 		goto end;
390 	}
391 
392 	/* BPF writes need to be handled specially. */
393 	if (dst->sa_family == AF_UNSPEC) {
394 		bcopy(dst->sa_data, &af, sizeof(af));
395 		dst->sa_family = af;
396 	}
397 
398 	if (ifp->if_bpf) {
399 		af = dst->sa_family;
400 		bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
401 	}
402 	ifp->if_opackets++;
403 	ifp->if_obytes += m->m_pkthdr.len;
404 
405 	/* inner AF-specific encapsulation */
406 
407 	/* XXX should we check if our outer source is legal? */
408 
409 	/* dispatch to output logic based on outer AF */
410 	switch (sc->gif_psrc->sa_family) {
411 #ifdef INET
412 	case AF_INET:
413 		error = in_gif_output(ifp, dst->sa_family, m);
414 		break;
415 #endif
416 #ifdef INET6
417 	case AF_INET6:
418 		error = in6_gif_output(ifp, dst->sa_family, m);
419 		break;
420 #endif
421 	default:
422 		m_freem(m);
423 		error = ENETDOWN;
424 		goto end;
425 	}
426 
427   end:
428 	if (error)
429 		ifp->if_oerrors++;
430 	return error;
431 }
432 
433 void
434 gif_input(m, af, ifp)
435 	struct mbuf *m;
436 	int af;
437 	struct ifnet *ifp;
438 {
439 	int isr;
440 
441 	if (ifp == NULL) {
442 		/* just in case */
443 		m_freem(m);
444 		return;
445 	}
446 
447 	m->m_pkthdr.rcvif = ifp;
448 
449 #ifdef MAC
450 	mac_create_mbuf_from_ifnet(ifp, m);
451 #endif
452 
453 	if (ifp->if_bpf) {
454 		u_int32_t af1 = af;
455 		bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m);
456 	}
457 
458 	if (ng_gif_input_p != NULL) {
459 		(*ng_gif_input_p)(ifp, &m, af);
460 		if (m == NULL)
461 			return;
462 	}
463 
464 	/*
465 	 * Put the packet to the network layer input queue according to the
466 	 * specified address family.
467 	 * Note: older versions of gif_input directly called network layer
468 	 * input functions, e.g. ip6_input, here.  We changed the policy to
469 	 * prevent too many recursive calls of such input functions, which
470 	 * might cause kernel panic.  But the change may introduce another
471 	 * problem; if the input queue is full, packets are discarded.
472 	 * The kernel stack overflow really happened, and we believed
473 	 * queue-full rarely occurs, so we changed the policy.
474 	 */
475 	switch (af) {
476 #ifdef INET
477 	case AF_INET:
478 		isr = NETISR_IP;
479 		break;
480 #endif
481 #ifdef INET6
482 	case AF_INET6:
483 		isr = NETISR_IPV6;
484 		break;
485 #endif
486 	default:
487 		if (ng_gif_input_orphan_p != NULL)
488 			(*ng_gif_input_orphan_p)(ifp, m, af);
489 		else
490 			m_freem(m);
491 		return;
492 	}
493 
494 	ifp->if_ipackets++;
495 	ifp->if_ibytes += m->m_pkthdr.len;
496 	netisr_dispatch(isr, m);
497 }
498 
499 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
500 int
501 gif_ioctl(ifp, cmd, data)
502 	struct ifnet *ifp;
503 	u_long cmd;
504 	caddr_t data;
505 {
506 	struct gif_softc *sc  = ifp->if_softc;
507 	struct ifreq     *ifr = (struct ifreq*)data;
508 	int error = 0, size;
509 	struct sockaddr *dst, *src;
510 #ifdef	SIOCSIFMTU /* xxx */
511 	u_long mtu;
512 #endif
513 
514 	switch (cmd) {
515 	case SIOCSIFADDR:
516 		ifp->if_flags |= IFF_UP;
517 		break;
518 
519 	case SIOCSIFDSTADDR:
520 		break;
521 
522 	case SIOCADDMULTI:
523 	case SIOCDELMULTI:
524 		break;
525 
526 #ifdef	SIOCSIFMTU /* xxx */
527 	case SIOCGIFMTU:
528 		break;
529 
530 	case SIOCSIFMTU:
531 		mtu = ifr->ifr_mtu;
532 		if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX)
533 			return (EINVAL);
534 		ifp->if_mtu = mtu;
535 		break;
536 #endif /* SIOCSIFMTU */
537 
538 #ifdef INET
539 	case SIOCSIFPHYADDR:
540 #endif
541 #ifdef INET6
542 	case SIOCSIFPHYADDR_IN6:
543 #endif /* INET6 */
544 	case SIOCSLIFPHYADDR:
545 		switch (cmd) {
546 #ifdef INET
547 		case SIOCSIFPHYADDR:
548 			src = (struct sockaddr *)
549 				&(((struct in_aliasreq *)data)->ifra_addr);
550 			dst = (struct sockaddr *)
551 				&(((struct in_aliasreq *)data)->ifra_dstaddr);
552 			break;
553 #endif
554 #ifdef INET6
555 		case SIOCSIFPHYADDR_IN6:
556 			src = (struct sockaddr *)
557 				&(((struct in6_aliasreq *)data)->ifra_addr);
558 			dst = (struct sockaddr *)
559 				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
560 			break;
561 #endif
562 		case SIOCSLIFPHYADDR:
563 			src = (struct sockaddr *)
564 				&(((struct if_laddrreq *)data)->addr);
565 			dst = (struct sockaddr *)
566 				&(((struct if_laddrreq *)data)->dstaddr);
567 			break;
568 		default:
569 			return EINVAL;
570 		}
571 
572 		/* sa_family must be equal */
573 		if (src->sa_family != dst->sa_family)
574 			return EINVAL;
575 
576 		/* validate sa_len */
577 		switch (src->sa_family) {
578 #ifdef INET
579 		case AF_INET:
580 			if (src->sa_len != sizeof(struct sockaddr_in))
581 				return EINVAL;
582 			break;
583 #endif
584 #ifdef INET6
585 		case AF_INET6:
586 			if (src->sa_len != sizeof(struct sockaddr_in6))
587 				return EINVAL;
588 			break;
589 #endif
590 		default:
591 			return EAFNOSUPPORT;
592 		}
593 		switch (dst->sa_family) {
594 #ifdef INET
595 		case AF_INET:
596 			if (dst->sa_len != sizeof(struct sockaddr_in))
597 				return EINVAL;
598 			break;
599 #endif
600 #ifdef INET6
601 		case AF_INET6:
602 			if (dst->sa_len != sizeof(struct sockaddr_in6))
603 				return EINVAL;
604 			break;
605 #endif
606 		default:
607 			return EAFNOSUPPORT;
608 		}
609 
610 		/* check sa_family looks sane for the cmd */
611 		switch (cmd) {
612 		case SIOCSIFPHYADDR:
613 			if (src->sa_family == AF_INET)
614 				break;
615 			return EAFNOSUPPORT;
616 #ifdef INET6
617 		case SIOCSIFPHYADDR_IN6:
618 			if (src->sa_family == AF_INET6)
619 				break;
620 			return EAFNOSUPPORT;
621 #endif /* INET6 */
622 		case SIOCSLIFPHYADDR:
623 			/* checks done in the above */
624 			break;
625 		}
626 
627 		error = gif_set_tunnel(GIF2IFP(sc), src, dst);
628 		break;
629 
630 #ifdef SIOCDIFPHYADDR
631 	case SIOCDIFPHYADDR:
632 		gif_delete_tunnel(GIF2IFP(sc));
633 		break;
634 #endif
635 
636 	case SIOCGIFPSRCADDR:
637 #ifdef INET6
638 	case SIOCGIFPSRCADDR_IN6:
639 #endif /* INET6 */
640 		if (sc->gif_psrc == NULL) {
641 			error = EADDRNOTAVAIL;
642 			goto bad;
643 		}
644 		src = sc->gif_psrc;
645 		switch (cmd) {
646 #ifdef INET
647 		case SIOCGIFPSRCADDR:
648 			dst = &ifr->ifr_addr;
649 			size = sizeof(ifr->ifr_addr);
650 			break;
651 #endif /* INET */
652 #ifdef INET6
653 		case SIOCGIFPSRCADDR_IN6:
654 			dst = (struct sockaddr *)
655 				&(((struct in6_ifreq *)data)->ifr_addr);
656 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
657 			break;
658 #endif /* INET6 */
659 		default:
660 			error = EADDRNOTAVAIL;
661 			goto bad;
662 		}
663 		if (src->sa_len > size)
664 			return EINVAL;
665 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
666 #ifdef INET6
667 		if (dst->sa_family == AF_INET6) {
668 			error = sa6_recoverscope((struct sockaddr_in6 *)dst);
669 			if (error != 0)
670 				return (error);
671 		}
672 #endif
673 		break;
674 
675 	case SIOCGIFPDSTADDR:
676 #ifdef INET6
677 	case SIOCGIFPDSTADDR_IN6:
678 #endif /* INET6 */
679 		if (sc->gif_pdst == NULL) {
680 			error = EADDRNOTAVAIL;
681 			goto bad;
682 		}
683 		src = sc->gif_pdst;
684 		switch (cmd) {
685 #ifdef INET
686 		case SIOCGIFPDSTADDR:
687 			dst = &ifr->ifr_addr;
688 			size = sizeof(ifr->ifr_addr);
689 			break;
690 #endif /* INET */
691 #ifdef INET6
692 		case SIOCGIFPDSTADDR_IN6:
693 			dst = (struct sockaddr *)
694 				&(((struct in6_ifreq *)data)->ifr_addr);
695 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
696 			break;
697 #endif /* INET6 */
698 		default:
699 			error = EADDRNOTAVAIL;
700 			goto bad;
701 		}
702 		if (src->sa_len > size)
703 			return EINVAL;
704 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
705 #ifdef INET6
706 		if (dst->sa_family == AF_INET6) {
707 			error = sa6_recoverscope((struct sockaddr_in6 *)dst);
708 			if (error != 0)
709 				return (error);
710 		}
711 #endif
712 		break;
713 
714 	case SIOCGLIFPHYADDR:
715 		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
716 			error = EADDRNOTAVAIL;
717 			goto bad;
718 		}
719 
720 		/* copy src */
721 		src = sc->gif_psrc;
722 		dst = (struct sockaddr *)
723 			&(((struct if_laddrreq *)data)->addr);
724 		size = sizeof(((struct if_laddrreq *)data)->addr);
725 		if (src->sa_len > size)
726 			return EINVAL;
727 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
728 
729 		/* copy dst */
730 		src = sc->gif_pdst;
731 		dst = (struct sockaddr *)
732 			&(((struct if_laddrreq *)data)->dstaddr);
733 		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
734 		if (src->sa_len > size)
735 			return EINVAL;
736 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
737 		break;
738 
739 	case SIOCSIFFLAGS:
740 		/* if_ioctl() takes care of it */
741 		break;
742 
743 	default:
744 		error = EINVAL;
745 		break;
746 	}
747  bad:
748 	return error;
749 }
750 
751 /*
752  * XXXRW: There's a general event-ordering issue here: the code to check
753  * if a given tunnel is already present happens before we perform a
754  * potentially blocking setup of the tunnel.  This code needs to be
755  * re-ordered so that the check and replacement can be atomic using
756  * a mutex.
757  */
758 int
759 gif_set_tunnel(ifp, src, dst)
760 	struct ifnet *ifp;
761 	struct sockaddr *src;
762 	struct sockaddr *dst;
763 {
764 	struct gif_softc *sc = ifp->if_softc;
765 	struct gif_softc *sc2;
766 	struct sockaddr *osrc, *odst, *sa;
767 	int s;
768 	int error = 0;
769 
770 	s = splnet();
771 
772 	mtx_lock(&gif_mtx);
773 	LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
774 		if (sc2 == sc)
775 			continue;
776 		if (!sc2->gif_pdst || !sc2->gif_psrc)
777 			continue;
778 		if (sc2->gif_pdst->sa_family != dst->sa_family ||
779 		    sc2->gif_pdst->sa_len != dst->sa_len ||
780 		    sc2->gif_psrc->sa_family != src->sa_family ||
781 		    sc2->gif_psrc->sa_len != src->sa_len)
782 			continue;
783 
784 		/*
785 		 * Disallow parallel tunnels unless instructed
786 		 * otherwise.
787 		 */
788 		if (!parallel_tunnels &&
789 		    bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
790 		    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
791 			error = EADDRNOTAVAIL;
792 			mtx_unlock(&gif_mtx);
793 			goto bad;
794 		}
795 
796 		/* XXX both end must be valid? (I mean, not 0.0.0.0) */
797 	}
798 	mtx_unlock(&gif_mtx);
799 
800 	/* XXX we can detach from both, but be polite just in case */
801 	if (sc->gif_psrc)
802 		switch (sc->gif_psrc->sa_family) {
803 #ifdef INET
804 		case AF_INET:
805 			(void)in_gif_detach(sc);
806 			break;
807 #endif
808 #ifdef INET6
809 		case AF_INET6:
810 			(void)in6_gif_detach(sc);
811 			break;
812 #endif
813 		}
814 
815 	osrc = sc->gif_psrc;
816 	sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
817 	bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
818 	sc->gif_psrc = sa;
819 
820 	odst = sc->gif_pdst;
821 	sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
822 	bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
823 	sc->gif_pdst = sa;
824 
825 	switch (sc->gif_psrc->sa_family) {
826 #ifdef INET
827 	case AF_INET:
828 		error = in_gif_attach(sc);
829 		break;
830 #endif
831 #ifdef INET6
832 	case AF_INET6:
833 		/*
834 		 * Check validity of the scope zone ID of the addresses, and
835 		 * convert it into the kernel internal form if necessary.
836 		 */
837 		error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_psrc, 0);
838 		if (error != 0)
839 			break;
840 		error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_pdst, 0);
841 		if (error != 0)
842 			break;
843 		error = in6_gif_attach(sc);
844 		break;
845 #endif
846 	}
847 	if (error) {
848 		/* rollback */
849 		free((caddr_t)sc->gif_psrc, M_IFADDR);
850 		free((caddr_t)sc->gif_pdst, M_IFADDR);
851 		sc->gif_psrc = osrc;
852 		sc->gif_pdst = odst;
853 		goto bad;
854 	}
855 
856 	if (osrc)
857 		free((caddr_t)osrc, M_IFADDR);
858 	if (odst)
859 		free((caddr_t)odst, M_IFADDR);
860 
861 	if (sc->gif_psrc && sc->gif_pdst)
862 		ifp->if_drv_flags |= IFF_DRV_RUNNING;
863 	else
864 		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
865 	splx(s);
866 
867 	return 0;
868 
869  bad:
870 	if (sc->gif_psrc && sc->gif_pdst)
871 		ifp->if_drv_flags |= IFF_DRV_RUNNING;
872 	else
873 		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
874 	splx(s);
875 
876 	return error;
877 }
878 
879 void
880 gif_delete_tunnel(ifp)
881 	struct ifnet *ifp;
882 {
883 	struct gif_softc *sc = ifp->if_softc;
884 	int s;
885 
886 	s = splnet();
887 
888 	if (sc->gif_psrc) {
889 		free((caddr_t)sc->gif_psrc, M_IFADDR);
890 		sc->gif_psrc = NULL;
891 	}
892 	if (sc->gif_pdst) {
893 		free((caddr_t)sc->gif_pdst, M_IFADDR);
894 		sc->gif_pdst = NULL;
895 	}
896 	/* it is safe to detach from both */
897 #ifdef INET
898 	(void)in_gif_detach(sc);
899 #endif
900 #ifdef INET6
901 	(void)in6_gif_detach(sc);
902 #endif
903 
904 	if (sc->gif_psrc && sc->gif_pdst)
905 		ifp->if_drv_flags |= IFF_DRV_RUNNING;
906 	else
907 		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
908 	splx(s);
909 }
910