xref: /dragonfly/sys/net/gif/if_gif.c (revision 7485684f)
1 /*
2  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the project nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD: src/sys/net/if_gif.c,v 1.4.2.15 2002/11/08 16:57:13 ume Exp $
30  * $KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $
31  */
32 
33 #include "opt_inet.h"
34 #include "opt_inet6.h"
35 #include "opt_xbonehack.h"
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/bus.h>
41 #include <sys/malloc.h>
42 #include <sys/mbuf.h>
43 #include <sys/socket.h>
44 #include <sys/sockio.h>
45 #include <sys/errno.h>
46 #include <sys/time.h>
47 #include <sys/sysctl.h>
48 #include <sys/syslog.h>
49 #include <sys/protosw.h>
50 #include <sys/conf.h>
51 #include <sys/thread2.h>
52 
53 #include <machine/cpu.h>
54 
55 #include <net/if.h>
56 #include <net/if_types.h>
57 #include <net/ifq_var.h>
58 #include <net/netisr2.h>
59 #include <net/route.h>
60 #include <net/bpf.h>
61 #include <net/if_clone.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 #include <netinet/in_gif.h>
69 #include <netinet/ip_var.h>
70 #endif	/* INET */
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 "if_gif.h"
85 
86 #include <net/net_osdep.h>
87 
88 #define GIFNAME		"gif"
89 
90 #define MTAG_GIF	1709048582 /* mtag cookie for nesting check */
91 
92 static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
93 LIST_HEAD(, gif_softc) gif_softc_list;
94 
95 int	gif_clone_create(struct if_clone *, int, caddr_t, caddr_t);
96 int	gif_clone_destroy(struct ifnet *);
97 
98 struct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif", gif_clone_create,
99     gif_clone_destroy, 0, IF_MAXUNIT);
100 
101 static int gifmodevent(module_t, int, void *);
102 static void gif_clear_cache(struct gif_softc *sc);
103 
104 SYSCTL_DECL(_net_link);
105 SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
106     "Generic Tunnel Interface");
107 
108 #ifndef MAX_GIF_NEST
109 /*
110  * This macro controls the default upper limitation on nesting of gif tunnels.
111  * Since, setting a large value to this macro with a careless configuration
112  * may introduce system crash, we don't allow any nestings by default.
113  * If you need to configure nested gif tunnels, you can define this macro
114  * in your kernel configuration file.  However, if you do so, please be
115  * careful to configure the tunnels so that it won't make a loop.
116  */
117 #define MAX_GIF_NEST 1
118 #endif
119 static int max_gif_nesting = MAX_GIF_NEST;
120 SYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW,
121     &max_gif_nesting, 0, "Max nested tunnels");
122 
123 /*
124  * By default, we disallow creation of multiple tunnels between the same
125  * pair of addresses.  Some applications require this functionality so
126  * we allow control over this check here.
127  */
128 #ifdef XBONEHACK
129 static int parallel_tunnels = 1;
130 #else
131 static int parallel_tunnels = 0;
132 #endif
133 SYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW,
134     &parallel_tunnels, 0, "Allow parallel tunnels?");
135 
136 
137 int
138 gif_clone_create(struct if_clone *ifc, int unit,
139 		 caddr_t params __unused, caddr_t data __unused)
140 {
141 	struct gif_softc *sc;
142 
143 	sc = kmalloc (sizeof(struct gif_softc), M_GIF, M_WAITOK | M_ZERO);
144 
145 	sc->gif_if.if_softc = sc;
146 	if_initname(&(sc->gif_if), GIFNAME, unit);
147 
148 	gifattach0(sc);
149 
150 	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
151 	return (0);
152 }
153 
154 void
155 gifattach0(struct gif_softc *sc)
156 {
157 
158 	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
159 
160 	sc->gif_if.if_addrlen = 0;
161 	sc->gif_if.if_mtu    = GIF_MTU;
162 	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
163 #if 0
164 	/* turn off ingress filter */
165 	sc->gif_if.if_flags  |= IFF_LINK2;
166 #endif
167 	sc->gif_if.if_ioctl  = gif_ioctl;
168 	sc->gif_if.if_output = gif_output;
169 	sc->gif_if.if_type   = IFT_GIF;
170 	ifq_set_maxlen(&sc->gif_if.if_snd, IFQ_MAXLEN);
171 	if_attach(&sc->gif_if, NULL);
172 	bpfattach(&sc->gif_if, DLT_NULL, sizeof(uint32_t));
173 }
174 
175 int
176 gif_clone_destroy(struct ifnet *ifp)
177 {
178 	struct gif_softc *sc = ifp->if_softc;
179 	int err;
180 
181 	gif_delete_tunnel(&sc->gif_if);
182 	LIST_REMOVE(sc, gif_list);
183 #ifdef INET6
184 	if (sc->encap_cookie6 != NULL) {
185 		err = encap_detach(sc->encap_cookie6);
186 		KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
187 	}
188 #endif
189 #ifdef INET
190 	if (sc->encap_cookie4 != NULL) {
191 		err = encap_detach(sc->encap_cookie4);
192 		KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
193 	}
194 #endif
195 	gif_clear_cache(sc);
196 
197 	bpfdetach(ifp);
198 	if_detach(ifp);
199 
200 	kfree(sc, M_GIF);
201 
202 	return 0;
203 }
204 
205 static void
206 gif_clear_cache(struct gif_softc *sc)
207 {
208 	struct rtentry *rt;
209 	int n;
210 
211 	for (n = 0; n < netisr_ncpus; ++n) {
212 		rt = sc->gif_ro[n].ro_rt;
213 		if (rt != NULL) {
214 			KASSERT(rt->rt_cpuid == n,
215 			    ("inet rt for cpu%d installed on cpu%d slot",
216 			     rt->rt_cpuid, n));
217 			rtfree_async(rt);
218 			sc->gif_ro[n].ro_rt = NULL;
219 		}
220 #ifdef INET6
221 		rt = sc->gif_ro6[n].ro_rt;
222 		if (rt != NULL) {
223 			KASSERT(rt->rt_cpuid == n,
224 			    ("inet6 rt for cpu%d installed on cpu%d slot",
225 			     rt->rt_cpuid, n));
226 			rtfree_async(rt);
227 			sc->gif_ro6[n].ro_rt = NULL;
228 		}
229 #endif
230 	}
231 }
232 
233 static int
234 gifmodevent(module_t mod, int type, void *data)
235 {
236 
237 	switch (type) {
238 	case MOD_LOAD:
239 		LIST_INIT(&gif_softc_list);
240 		if_clone_attach(&gif_cloner);
241 
242 #ifdef INET6
243 		ip6_gif_hlim = GIF_HLIM;
244 #endif
245 
246 		break;
247 	case MOD_UNLOAD:
248 		if_clone_detach(&gif_cloner);
249 
250 		while (!LIST_EMPTY(&gif_softc_list))
251 			gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if);
252 
253 #ifdef INET6
254 		ip6_gif_hlim = 0;
255 #endif
256 		break;
257 	}
258 	return 0;
259 }
260 
261 static moduledata_t gif_mod = {
262 	"if_gif",
263 	gifmodevent,
264 	0
265 };
266 
267 DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
268 
269 int
270 gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
271 {
272 	struct ip ip;
273 	struct gif_softc *sc;
274 
275 	sc = (struct gif_softc *)arg;
276 	if (sc == NULL)
277 		return 0;
278 
279 	if ((sc->gif_if.if_flags & IFF_UP) == 0)
280 		return 0;
281 
282 	/* no physical address */
283 	if (!sc->gif_psrc || !sc->gif_pdst)
284 		return 0;
285 
286 	switch (proto) {
287 #ifdef INET
288 	case IPPROTO_IPV4:
289 		break;
290 #endif
291 #ifdef INET6
292 	case IPPROTO_IPV6:
293 		break;
294 #endif
295 	default:
296 		return 0;
297 	}
298 
299 	/* Bail on short packets */
300 	if (m->m_pkthdr.len < sizeof(ip))
301 		return 0;
302 
303 	m_copydata(m, 0, sizeof(ip), &ip);
304 
305 	switch (ip.ip_v) {
306 #ifdef INET
307 	case 4:
308 		if (sc->gif_psrc->sa_family != AF_INET ||
309 		    sc->gif_pdst->sa_family != AF_INET)
310 			return 0;
311 		return gif_encapcheck4(m, off, proto, arg);
312 #endif
313 #ifdef INET6
314 	case 6:
315 		if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
316 			return 0;
317 		if (sc->gif_psrc->sa_family != AF_INET6 ||
318 		    sc->gif_pdst->sa_family != AF_INET6)
319 			return 0;
320 		return gif_encapcheck6(m, off, proto, arg);
321 #endif
322 	default:
323 		return 0;
324 	}
325 }
326 
327 /*
328  * Parameters:
329  *	rt:	added in net2
330  */
331 static int
332 gif_output_serialized(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
333 		      struct rtentry *rt)
334 {
335 	struct gif_softc *sc = (struct gif_softc *)ifp;
336 	int error = 0;
337 
338 	error = if_tunnel_check_nesting(ifp, m, MTAG_GIF, max_gif_nesting);
339 	if (error != 0) {
340 		m_freem(m);
341 		goto end;
342 	}
343 
344 	m->m_flags &= ~(M_BCAST|M_MCAST);
345 	if (!(ifp->if_flags & IFF_UP) ||
346 	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
347 		m_freem(m);
348 		error = ENETDOWN;
349 		goto end;
350 	}
351 
352 	if (ifp->if_bpf) {
353 		bpf_gettoken();
354 		if (ifp->if_bpf) {
355 			/*
356 			 * We need to prepend the address family as
357 			 * a four byte field.
358 			 */
359 			uint32_t af = dst->sa_family;
360 
361 			bpf_ptap(ifp->if_bpf, m, &af, sizeof(af));
362 		}
363 		bpf_reltoken();
364 	}
365 	IFNET_STAT_INC(ifp, opackets, 1);
366 	IFNET_STAT_INC(ifp, obytes, m->m_pkthdr.len);
367 
368 	/* inner AF-specific encapsulation */
369 
370 	/* XXX should we check if our outer source is legal? */
371 
372 	/* dispatch to output logic based on outer AF */
373 	switch (sc->gif_psrc->sa_family) {
374 #ifdef INET
375 	case AF_INET:
376 		error = in_gif_output(ifp, dst->sa_family, m);
377 		break;
378 #endif
379 #ifdef INET6
380 	case AF_INET6:
381 		error = in6_gif_output(ifp, dst->sa_family, m);
382 		break;
383 #endif
384 	default:
385 		m_freem(m);
386 		error = ENETDOWN;
387 		goto end;
388 	}
389 
390   end:
391 	if (error)
392 		IFNET_STAT_INC(ifp, oerrors, 1);
393 	return error;
394 }
395 
396 int
397 gif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
398 	   struct rtentry *rt)
399 {
400 	struct ifaltq_subque *ifsq = ifq_get_subq_default(&ifp->if_snd);
401 	int error;
402 
403 	ASSERT_NETISR_NCPUS(mycpuid);
404 
405 	ifsq_serialize_hw(ifsq);
406 	error = gif_output_serialized(ifp, m, dst, rt);
407 	ifsq_deserialize_hw(ifsq);
408 	return error;
409 }
410 
411 void
412 gif_input(struct mbuf *m, int af, struct ifnet *ifp)
413 {
414 	int isr;
415 
416 	if (ifp == NULL) {
417 		/* just in case */
418 		m_freem(m);
419 		return;
420 	}
421 
422 	m->m_pkthdr.rcvif = ifp;
423 
424 	if (ifp->if_bpf) {
425 		bpf_gettoken();
426 		if (ifp->if_bpf) {
427 			/*
428 			 * We need to prepend the address family as
429 			 * a four byte field.
430 			 */
431 			uint32_t af1 = af;
432 
433 			bpf_ptap(ifp->if_bpf, m, &af1, sizeof(af1));
434 		}
435 		bpf_reltoken();
436 	}
437 
438 	/*
439 	 * Put the packet to the network layer input queue according to the
440 	 * specified address family.
441 	 * Note: older versions of gif_input directly called network layer
442 	 * input functions, e.g. ip6_input, here.  We changed the policy to
443 	 * prevent too many recursive calls of such input functions, which
444 	 * might cause kernel panic.  But the change may introduce another
445 	 * problem; if the input queue is full, packets are discarded.
446 	 * The kernel stack overflow really happened, and we believed
447 	 * queue-full rarely occurs, so we changed the policy.
448 	 */
449 	switch (af) {
450 #ifdef INET
451 	case AF_INET:
452 		isr = NETISR_IP;
453 		break;
454 #endif
455 #ifdef INET6
456 	case AF_INET6:
457 		isr = NETISR_IPV6;
458 		break;
459 #endif
460 	default:
461 		m_freem(m);
462 		return;
463 	}
464 
465 	IFNET_STAT_INC(ifp, ipackets, 1);
466 	IFNET_STAT_INC(ifp, ibytes, m->m_pkthdr.len);
467 	m->m_flags &= ~M_HASH;
468 	netisr_queue(isr, m);
469 
470 	return;
471 }
472 
473 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
474 int
475 gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
476 {
477 	struct gif_softc *sc  = (struct gif_softc*)ifp;
478 	struct ifreq     *ifr = (struct ifreq*)data;
479 	int error = 0, size;
480 	struct sockaddr *dst, *src;
481 #ifdef	SIOCSIFMTU /* xxx */
482 	u_long mtu;
483 #endif
484 
485 	switch (cmd) {
486 	case SIOCSIFADDR:
487 		ifp->if_flags |= IFF_UP;
488 		break;
489 
490 	case SIOCSIFDSTADDR:
491 		break;
492 
493 	case SIOCADDMULTI:
494 	case SIOCDELMULTI:
495 		break;
496 
497 #ifdef	SIOCSIFMTU /* xxx */
498 	case SIOCGIFMTU:
499 		break;
500 
501 	case SIOCSIFMTU:
502 		mtu = ifr->ifr_mtu;
503 		if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX)
504 			return (EINVAL);
505 		ifp->if_mtu = mtu;
506 		break;
507 #endif /* SIOCSIFMTU */
508 
509 #ifdef INET
510 	case SIOCSIFPHYADDR:
511 #endif
512 #ifdef INET6
513 	case SIOCSIFPHYADDR_IN6:
514 #endif /* INET6 */
515 	case SIOCSLIFPHYADDR:
516 		switch (cmd) {
517 #ifdef INET
518 		case SIOCSIFPHYADDR:
519 			src = (struct sockaddr *)
520 				&(((struct in_aliasreq *)data)->ifra_addr);
521 			dst = (struct sockaddr *)
522 				&(((struct in_aliasreq *)data)->ifra_dstaddr);
523 			break;
524 #endif
525 #ifdef INET6
526 		case SIOCSIFPHYADDR_IN6:
527 			src = (struct sockaddr *)
528 				&(((struct in6_aliasreq *)data)->ifra_addr);
529 			dst = (struct sockaddr *)
530 				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
531 			break;
532 #endif
533 		case SIOCSLIFPHYADDR:
534 			src = (struct sockaddr *)
535 				&(((struct if_laddrreq *)data)->addr);
536 			dst = (struct sockaddr *)
537 				&(((struct if_laddrreq *)data)->dstaddr);
538 			break;
539 		default:
540 			return EINVAL;
541 		}
542 
543 		/* sa_family must be equal */
544 		if (src->sa_family != dst->sa_family)
545 			return EINVAL;
546 
547 		/* validate sa_len */
548 		switch (src->sa_family) {
549 #ifdef INET
550 		case AF_INET:
551 			if (src->sa_len != sizeof(struct sockaddr_in))
552 				return EINVAL;
553 			break;
554 #endif
555 #ifdef INET6
556 		case AF_INET6:
557 			if (src->sa_len != sizeof(struct sockaddr_in6))
558 				return EINVAL;
559 			break;
560 #endif
561 		default:
562 			return EAFNOSUPPORT;
563 		}
564 		switch (dst->sa_family) {
565 #ifdef INET
566 		case AF_INET:
567 			if (dst->sa_len != sizeof(struct sockaddr_in))
568 				return EINVAL;
569 			break;
570 #endif
571 #ifdef INET6
572 		case AF_INET6:
573 			if (dst->sa_len != sizeof(struct sockaddr_in6))
574 				return EINVAL;
575 			break;
576 #endif
577 		default:
578 			return EAFNOSUPPORT;
579 		}
580 
581 		/* check sa_family looks sane for the cmd */
582 		switch (cmd) {
583 		case SIOCSIFPHYADDR:
584 			if (src->sa_family == AF_INET)
585 				break;
586 			return EAFNOSUPPORT;
587 #ifdef INET6
588 		case SIOCSIFPHYADDR_IN6:
589 			if (src->sa_family == AF_INET6)
590 				break;
591 			return EAFNOSUPPORT;
592 #endif /* INET6 */
593 		case SIOCSLIFPHYADDR:
594 			/* checks done in the above */
595 			break;
596 		}
597 
598 		error = gif_set_tunnel(&sc->gif_if, src, dst);
599 		break;
600 
601 #ifdef SIOCDIFPHYADDR
602 	case SIOCDIFPHYADDR:
603 		gif_delete_tunnel(&sc->gif_if);
604 		break;
605 #endif
606 
607 	case SIOCGIFPSRCADDR:
608 #ifdef INET6
609 	case SIOCGIFPSRCADDR_IN6:
610 #endif /* INET6 */
611 		if (sc->gif_psrc == NULL) {
612 			error = EADDRNOTAVAIL;
613 			goto bad;
614 		}
615 		src = sc->gif_psrc;
616 		switch (cmd) {
617 #ifdef INET
618 		case SIOCGIFPSRCADDR:
619 			dst = &ifr->ifr_addr;
620 			size = sizeof(ifr->ifr_addr);
621 			break;
622 #endif /* INET */
623 #ifdef INET6
624 		case SIOCGIFPSRCADDR_IN6:
625 			dst = (struct sockaddr *)
626 				&(((struct in6_ifreq *)data)->ifr_addr);
627 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
628 			break;
629 #endif /* INET6 */
630 		default:
631 			error = EADDRNOTAVAIL;
632 			goto bad;
633 		}
634 		if (src->sa_len > size)
635 			return EINVAL;
636 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
637 		break;
638 
639 	case SIOCGIFPDSTADDR:
640 #ifdef INET6
641 	case SIOCGIFPDSTADDR_IN6:
642 #endif /* INET6 */
643 		if (sc->gif_pdst == NULL) {
644 			error = EADDRNOTAVAIL;
645 			goto bad;
646 		}
647 		src = sc->gif_pdst;
648 		switch (cmd) {
649 #ifdef INET
650 		case SIOCGIFPDSTADDR:
651 			dst = &ifr->ifr_addr;
652 			size = sizeof(ifr->ifr_addr);
653 			break;
654 #endif /* INET */
655 #ifdef INET6
656 		case SIOCGIFPDSTADDR_IN6:
657 			dst = (struct sockaddr *)
658 				&(((struct in6_ifreq *)data)->ifr_addr);
659 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
660 			break;
661 #endif /* INET6 */
662 		default:
663 			error = EADDRNOTAVAIL;
664 			goto bad;
665 		}
666 		if (src->sa_len > size)
667 			return EINVAL;
668 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
669 		break;
670 
671 	case SIOCGLIFPHYADDR:
672 		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
673 			error = EADDRNOTAVAIL;
674 			goto bad;
675 		}
676 
677 		/* copy src */
678 		src = sc->gif_psrc;
679 		dst = (struct sockaddr *)
680 			&(((struct if_laddrreq *)data)->addr);
681 		size = sizeof(((struct if_laddrreq *)data)->addr);
682 		if (src->sa_len > size)
683 			return EINVAL;
684 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
685 
686 		/* copy dst */
687 		src = sc->gif_pdst;
688 		dst = (struct sockaddr *)
689 			&(((struct if_laddrreq *)data)->dstaddr);
690 		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
691 		if (src->sa_len > size)
692 			return EINVAL;
693 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
694 		break;
695 
696 	case SIOCSIFFLAGS:
697 		/* if_ioctl() takes care of it */
698 		break;
699 
700 	default:
701 		error = EINVAL;
702 		break;
703 	}
704  bad:
705 	return error;
706 }
707 
708 int
709 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
710 {
711 	struct gif_softc *sc = (struct gif_softc *)ifp;
712 	struct gif_softc *sc2;
713 	struct sockaddr *osrc, *odst, *sa;
714 	int error = 0;
715 
716 	crit_enter();
717 
718 	LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
719 		if (sc2 == sc)
720 			continue;
721 		if (!sc2->gif_pdst || !sc2->gif_psrc)
722 			continue;
723 		if (sc2->gif_pdst->sa_family != dst->sa_family ||
724 		    sc2->gif_pdst->sa_len != dst->sa_len ||
725 		    sc2->gif_psrc->sa_family != src->sa_family ||
726 		    sc2->gif_psrc->sa_len != src->sa_len)
727 			continue;
728 
729 		/*
730 		 * Disallow parallel tunnels unless instructed
731 		 * otherwise.
732 		 */
733 		if (!parallel_tunnels &&
734 		    bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
735 		    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
736 			error = EADDRNOTAVAIL;
737 			goto bad;
738 		}
739 
740 		/* XXX both end must be valid? (I mean, not 0.0.0.0) */
741 	}
742 
743 	/* XXX we can detach from both, but be polite just in case */
744 	if (sc->gif_psrc) {
745 		switch (sc->gif_psrc->sa_family) {
746 #ifdef INET
747 		case AF_INET:
748 			in_gif_detach(sc);
749 			break;
750 #endif
751 #ifdef INET6
752 		case AF_INET6:
753 			in6_gif_detach(sc);
754 			break;
755 #endif
756 		}
757 		gif_clear_cache(sc);
758 	}
759 
760 	osrc = sc->gif_psrc;
761 	sa = (struct sockaddr *)kmalloc(src->sa_len, M_IFADDR, M_WAITOK);
762 	bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
763 	sc->gif_psrc = sa;
764 
765 	odst = sc->gif_pdst;
766 	sa = (struct sockaddr *)kmalloc(dst->sa_len, M_IFADDR, M_WAITOK);
767 	bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
768 	sc->gif_pdst = sa;
769 
770 	switch (sc->gif_psrc->sa_family) {
771 #ifdef INET
772 	case AF_INET:
773 		error = in_gif_attach(sc);
774 		break;
775 #endif
776 #ifdef INET6
777 	case AF_INET6:
778 		error = in6_gif_attach(sc);
779 		break;
780 #endif
781 	}
782 	if (error) {
783 		/* rollback */
784 		kfree((caddr_t)sc->gif_psrc, M_IFADDR);
785 		kfree((caddr_t)sc->gif_pdst, M_IFADDR);
786 		sc->gif_psrc = osrc;
787 		sc->gif_pdst = odst;
788 		goto bad;
789 	}
790 
791 	if (osrc)
792 		kfree((caddr_t)osrc, M_IFADDR);
793 	if (odst)
794 		kfree((caddr_t)odst, M_IFADDR);
795 
796 	if (sc->gif_psrc && sc->gif_pdst)
797 		ifp->if_flags |= IFF_RUNNING;
798 	else
799 		ifp->if_flags &= ~IFF_RUNNING;
800 	crit_exit();
801 
802 	return 0;
803 
804  bad:
805 	if (sc->gif_psrc && sc->gif_pdst)
806 		ifp->if_flags |= IFF_RUNNING;
807 	else
808 		ifp->if_flags &= ~IFF_RUNNING;
809 	crit_exit();
810 
811 	return error;
812 }
813 
814 void
815 gif_delete_tunnel(struct ifnet *ifp)
816 {
817 	struct gif_softc *sc = (struct gif_softc *)ifp;
818 
819 	crit_enter();
820 
821 	if (sc->gif_psrc) {
822 		kfree((caddr_t)sc->gif_psrc, M_IFADDR);
823 		sc->gif_psrc = NULL;
824 	}
825 	if (sc->gif_pdst) {
826 		kfree((caddr_t)sc->gif_pdst, M_IFADDR);
827 		sc->gif_pdst = NULL;
828 	}
829 	/* it is safe to detach from both */
830 #ifdef INET
831 	in_gif_detach(sc);
832 #endif
833 #ifdef INET6
834 	in6_gif_detach(sc);
835 #endif
836 	gif_clear_cache(sc);
837 
838 	if (sc->gif_psrc && sc->gif_pdst)
839 		ifp->if_flags |= IFF_RUNNING;
840 	else
841 		ifp->if_flags &= ~IFF_RUNNING;
842 	crit_exit();
843 }
844