xref: /freebsd/sys/net/if_gif.c (revision a220d00e74dd245b4fca59c5eca0c53963686325)
1 /*	$FreeBSD$	*/
2 /*	$KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 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 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/mbuf.h>
41 #include <sys/socket.h>
42 #include <sys/sockio.h>
43 #include <sys/errno.h>
44 #include <sys/time.h>
45 #include <sys/syslog.h>
46 #include <sys/protosw.h>
47 #include <sys/conf.h>
48 #include <machine/bus.h>	/* XXX: Shouldn't really be required! */
49 #include <sys/rman.h>
50 #include <machine/cpu.h>
51 
52 #include <net/if.h>
53 #include <net/if_types.h>
54 #include <net/netisr.h>
55 #include <net/route.h>
56 #include <net/bpf.h>
57 
58 #include <netinet/in.h>
59 #include <netinet/in_systm.h>
60 #include <netinet/ip.h>
61 #ifdef	INET
62 #include <netinet/in_var.h>
63 #include <netinet/in_gif.h>
64 #include <netinet/ip_var.h>
65 #endif	/* INET */
66 
67 #ifdef INET6
68 #ifndef INET
69 #include <netinet/in.h>
70 #endif
71 #include <netinet6/in6_var.h>
72 #include <netinet/ip6.h>
73 #include <netinet6/ip6_var.h>
74 #include <netinet6/in6_gif.h>
75 #include <netinet6/ip6protosw.h>
76 #endif /* INET6 */
77 
78 #include <netinet/ip_encap.h>
79 #include <net/if_gif.h>
80 
81 #include <net/net_osdep.h>
82 
83 #define GIFNAME		"gif"
84 #define GIF_MAXUNIT	0x7fff	/* ifp->if_unit is only 15 bits */
85 
86 static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
87 static struct rman gifunits[1];
88 LIST_HEAD(, gif_softc) gif_softc_list;
89 
90 void	(*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af);
91 void	(*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
92 void	(*ng_gif_attach_p)(struct ifnet *ifp);
93 void	(*ng_gif_detach_p)(struct ifnet *ifp);
94 
95 int	gif_clone_create __P((struct if_clone *, int *));
96 void	gif_clone_destroy __P((struct ifnet *));
97 
98 struct if_clone gif_cloner =
99     IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
100 
101 static int gifmodevent __P((module_t, int, void *));
102 void gif_delete_tunnel __P((struct gif_softc *));
103 static int gif_encapcheck __P((const struct mbuf *, int, int, void *));
104 
105 #ifdef INET
106 extern  struct domain inetdomain;
107 struct protosw in_gif_protosw =
108 { SOCK_RAW,	&inetdomain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
109   in_gif_input,	rip_output,	0,		rip_ctloutput,
110   0,
111   0,		0,		0,		0,
112   &rip_usrreqs
113 };
114 #endif
115 #ifdef INET6
116 extern  struct domain6 inet6domain;
117 struct ip6protosw in6_gif_protosw =
118 { SOCK_RAW,	&inet6domain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
119   in6_gif_input, rip6_output,	0,		rip6_ctloutput,
120   0,
121   0,		0,		0,		0,
122   &rip6_usrreqs
123 };
124 #endif
125 
126 #ifndef MAX_GIF_NEST
127 /*
128  * This macro controls the upper limitation on nesting of gif tunnels.
129  * Since, setting a large value to this macro with a careless configuration
130  * may introduce system crash, we don't allow any nestings by default.
131  * If you need to configure nested gif tunnels, you can define this macro
132  * in your kernel configuration file. However, if you do so, please be
133  * careful to configure the tunnels so that it won't make a loop.
134  */
135 #define MAX_GIF_NEST 1
136 #endif
137 static int max_gif_nesting = MAX_GIF_NEST;
138 
139 int
140 gif_clone_create(ifc, unit)
141 	struct if_clone *ifc;
142 	int *unit;
143 {
144 	struct resource *r;
145 	struct gif_softc *sc;
146 
147 	if (*unit > GIF_MAXUNIT)
148 		return (ENXIO);
149 
150 	if (*unit < 0) {
151 		r = rman_reserve_resource(gifunits, 0, GIF_MAXUNIT, 1,
152 		    RF_ALLOCATED | RF_ACTIVE, NULL);
153 		if (r == NULL)
154 			return (ENOSPC);
155 		*unit = rman_get_start(r);
156 	} else {
157 		r = rman_reserve_resource(gifunits, *unit, *unit, 1,
158 		    RF_ALLOCATED | RF_ACTIVE, NULL);
159 		if (r == NULL)
160 			return (EEXIST);
161 	}
162 
163 	sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK);
164 	bzero(sc, sizeof(struct gif_softc));
165 
166 	sc->gif_if.if_softc = sc;
167 	sc->gif_if.if_name = GIFNAME;
168 	sc->gif_if.if_unit = *unit;
169 	sc->r_unit = r;
170 
171 	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
172 #ifdef INET
173 	sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
174 	    gif_encapcheck, (struct protosw*)&in_gif_protosw, sc);
175 	if (sc->encap_cookie4 == NULL) {
176 		printf("%s: unable to attach encap4\n", if_name(&sc->gif_if));
177 		free(sc, M_GIF);
178 		return (EIO);	/* XXX */
179 	}
180 #endif
181 #ifdef INET6
182 	sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
183 	    gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc);
184 	if (sc->encap_cookie6 == NULL) {
185 		if (sc->encap_cookie4) {
186 			encap_detach(sc->encap_cookie4);
187 			sc->encap_cookie4 = NULL;
188 		}
189 		printf("%s: unable to attach encap6\n", if_name(&sc->gif_if));
190 		free(sc, M_GIF);
191 		return (EIO);	/* XXX */
192 	}
193 #endif
194 
195 	sc->gif_if.if_mtu    = GIF_MTU;
196 	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
197 #if 0
198 	/* turn off ingress filter */
199 	sc->gif_if.if_flags  |= IFF_LINK2;
200 #endif
201 	sc->gif_if.if_ioctl  = gif_ioctl;
202 	sc->gif_if.if_output = gif_output;
203 	sc->gif_if.if_type   = IFT_GIF;
204 	sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
205 	if_attach(&sc->gif_if);
206 	bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
207 	if (ng_gif_attach_p != NULL)
208 		(*ng_gif_attach_p)(&sc->gif_if);
209 	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_link);
210 	return (0);
211 }
212 
213 void
214 gif_clone_destroy(ifp)
215 	struct ifnet *ifp;
216 {
217 	int err;
218 	struct gif_softc *sc = ifp->if_softc;
219 
220 	gif_delete_tunnel(sc);
221 	LIST_REMOVE(sc, gif_link);
222 	if (sc->encap_cookie4 != NULL) {
223 		err = encap_detach(sc->encap_cookie4);
224 		KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
225 	}
226 	if (sc->encap_cookie6 != NULL) {
227 		err = encap_detach(sc->encap_cookie6);
228 		KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
229 	}
230 
231 	if (ng_gif_detach_p != NULL)
232 		(*ng_gif_detach_p)(ifp);
233 	bpfdetach(ifp);
234 	if_detach(ifp);
235 
236 	err = rman_release_resource(sc->r_unit);
237 	KASSERT(err == 0, ("Unexpected error freeing resource"));
238 
239 	free(sc, M_GIF);
240 }
241 
242 static int
243 gifmodevent(mod, type, data)
244 	module_t mod;
245 	int type;
246 	void *data;
247 {
248 	int err;
249 
250 	switch (type) {
251 	case MOD_LOAD:
252 		gifunits->rm_type = RMAN_ARRAY;
253 		gifunits->rm_descr = "configurable if_gif units";
254 		err = rman_init(gifunits);
255 		if (err != 0)
256 			return (err);
257 		err = rman_manage_region(gifunits, 0, GIF_MAXUNIT);
258 		if (err != 0) {
259 			printf("%s: gifunits: rman_manage_region: Failed %d\n",
260 			    GIFNAME, err);
261 			rman_fini(gifunits);
262 			return (err);
263 		}
264 		LIST_INIT(&gif_softc_list);
265 		if_clone_attach(&gif_cloner);
266 
267 #ifdef INET6
268 		ip6_gif_hlim = GIF_HLIM;
269 #endif
270 
271 		break;
272 	case MOD_UNLOAD:
273 		if_clone_detach(&gif_cloner);
274 
275 		while (!LIST_EMPTY(&gif_softc_list))
276 			gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if);
277 
278 		err = rman_fini(gifunits);
279 		if (err != 0)
280 			return (err);
281 #ifdef INET6
282 		ip6_gif_hlim = 0;
283 #endif
284 		break;
285 	}
286 	return 0;
287 }
288 
289 static moduledata_t gif_mod = {
290 	"if_gif",
291 	gifmodevent,
292 	0
293 };
294 
295 DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
296 MODULE_VERSION(if_gif, 1);
297 
298 static int
299 gif_encapcheck(m, off, proto, arg)
300 	const struct mbuf *m;
301 	int off;
302 	int proto;
303 	void *arg;
304 {
305 	struct ip ip;
306 	struct gif_softc *sc;
307 
308 	sc = (struct gif_softc *)arg;
309 	if (sc == NULL)
310 		return 0;
311 
312 	if ((sc->gif_if.if_flags & IFF_UP) == 0)
313 		return 0;
314 
315 	/* no physical address */
316 	if (!sc->gif_psrc || !sc->gif_pdst)
317 		return 0;
318 
319 	switch (proto) {
320 #ifdef INET
321 	case IPPROTO_IPV4:
322 		break;
323 #endif
324 #ifdef INET6
325 	case IPPROTO_IPV6:
326 		break;
327 #endif
328 	default:
329 		return 0;
330 	}
331 
332 	/* LINTED const cast */
333 	m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
334 
335 	switch (ip.ip_v) {
336 #ifdef INET
337 	case 4:
338 		if (sc->gif_psrc->sa_family != AF_INET ||
339 		    sc->gif_pdst->sa_family != AF_INET)
340 			return 0;
341 		return gif_encapcheck4(m, off, proto, arg);
342 #endif
343 #ifdef INET6
344 	case 6:
345 		if (sc->gif_psrc->sa_family != AF_INET6 ||
346 		    sc->gif_pdst->sa_family != AF_INET6)
347 			return 0;
348 		return gif_encapcheck6(m, off, proto, arg);
349 #endif
350 	default:
351 		return 0;
352 	}
353 }
354 
355 int
356 gif_output(ifp, m, dst, rt)
357 	struct ifnet *ifp;
358 	struct mbuf *m;
359 	struct sockaddr *dst;
360 	struct rtentry *rt;	/* added in net2 */
361 {
362 	struct gif_softc *sc = (struct gif_softc*)ifp;
363 	int error = 0;
364 	static int called = 0;	/* XXX: MUTEX */
365 
366 	/*
367 	 * gif may cause infinite recursion calls when misconfigured.
368 	 * We'll prevent this by introducing upper limit.
369 	 * XXX: this mechanism may introduce another problem about
370 	 *      mutual exclusion of the variable CALLED, especially if we
371 	 *      use kernel thread.
372 	 */
373 	if (++called > max_gif_nesting) {
374 		log(LOG_NOTICE,
375 		    "gif_output: recursively called too many times(%d)\n",
376 		    called);
377 		m_freem(m);
378 		error = EIO;	/* is there better errno? */
379 		goto end;
380 	}
381 
382 	m->m_flags &= ~(M_BCAST|M_MCAST);
383 	if (!(ifp->if_flags & IFF_UP) ||
384 	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
385 		m_freem(m);
386 		error = ENETDOWN;
387 		goto end;
388 	}
389 
390 	if (ifp->if_bpf) {
391 		/*
392 		 * We need to prepend the address family as
393 		 * a four byte field.  Cons up a dummy header
394 		 * to pacify bpf.  This is safe because bpf
395 		 * will only read from the mbuf (i.e., it won't
396 		 * try to free it or keep a pointer a to it).
397 		 */
398 		struct mbuf m0;
399 		u_int32_t af = dst->sa_family;
400 
401 		m0.m_next = m;
402 		m0.m_len = 4;
403 		m0.m_data = (char *)&af;
404 
405 		bpf_mtap(ifp, &m0);
406 	}
407 	ifp->if_opackets++;
408 	ifp->if_obytes += m->m_pkthdr.len;
409 
410 	/* inner AF-specific encapsulation */
411 
412 	/* XXX should we check if our outer source is legal? */
413 
414 	/* dispatch to output logic based on outer AF */
415 	switch (sc->gif_psrc->sa_family) {
416 #ifdef INET
417 	case AF_INET:
418 		error = in_gif_output(ifp, dst->sa_family, m, rt);
419 		break;
420 #endif
421 #ifdef INET6
422 	case AF_INET6:
423 		error = in6_gif_output(ifp, dst->sa_family, m, rt);
424 		break;
425 #endif
426 	default:
427 		m_freem(m);
428 		error = ENETDOWN;
429 		goto end;
430 	}
431 
432   end:
433 	called = 0;		/* reset recursion counter */
434 	if (error)
435 		ifp->if_oerrors++;
436 	return error;
437 }
438 
439 void
440 gif_input(m, af, gifp)
441 	struct mbuf *m;
442 	int af;
443 	struct ifnet *gifp;
444 {
445 	int isr;
446 	struct ifqueue *ifq = 0;
447 
448 	if (gifp == NULL) {
449 		/* just in case */
450 		m_freem(m);
451 		return;
452 	}
453 
454 	m->m_pkthdr.rcvif = gifp;
455 
456 	if (gifp->if_bpf) {
457 		/*
458 		 * We need to prepend the address family as
459 		 * a four byte field.  Cons up a dummy header
460 		 * to pacify bpf.  This is safe because bpf
461 		 * will only read from the mbuf (i.e., it won't
462 		 * try to free it or keep a pointer a to it).
463 		 */
464 		struct mbuf m0;
465 		u_int32_t af1 = af;
466 
467 		m0.m_next = m;
468 		m0.m_len = 4;
469 		m0.m_data = (char *)&af1;
470 
471 		bpf_mtap(gifp, &m0);
472 	}
473 
474 	if (ng_gif_input_p != NULL) {
475 		(*ng_gif_input_p)(gifp, &m, af);
476 		if (m == NULL)
477 			return;
478 	}
479 
480 	/*
481 	 * Put the packet to the network layer input queue according to the
482 	 * specified address family.
483 	 * Note: older versions of gif_input directly called network layer
484 	 * input functions, e.g. ip6_input, here. We changed the policy to
485 	 * prevent too many recursive calls of such input functions, which
486 	 * might cause kernel panic. But the change may introduce another
487 	 * problem; if the input queue is full, packets are discarded.
488 	 * We believed it rarely occurs and changed the policy. If we find
489 	 * it occurs more times than we thought, we may change the policy
490 	 * again.
491 	 */
492 	switch (af) {
493 #ifdef INET
494 	case AF_INET:
495 		ifq = &ipintrq;
496 		isr = NETISR_IP;
497 		break;
498 #endif
499 #ifdef INET6
500 	case AF_INET6:
501 		ifq = &ip6intrq;
502 		isr = NETISR_IPV6;
503 		break;
504 #endif
505 	default:
506 		if (ng_gif_input_orphan_p != NULL)
507 			(*ng_gif_input_orphan_p)(gifp, m, af);
508 		else
509 			m_freem(m);
510 		return;
511 	}
512 
513 	gifp->if_ipackets++;
514 	gifp->if_ibytes += m->m_pkthdr.len;
515 	(void) IF_HANDOFF(ifq, m, NULL);
516 	/* we need schednetisr since the address family may change */
517 	schednetisr(isr);
518 
519 	return;
520 }
521 
522 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
523 int
524 gif_ioctl(ifp, cmd, data)
525 	struct ifnet *ifp;
526 	u_long cmd;
527 	caddr_t data;
528 {
529 	struct gif_softc *sc  = (struct gif_softc*)ifp;
530 	struct ifreq     *ifr = (struct ifreq*)data;
531 	int error = 0, size;
532 	struct sockaddr *dst, *src;
533 	struct sockaddr *sa;
534 	int s;
535 	struct ifnet *ifp2;
536 	struct gif_softc *sc2;
537 
538 	switch (cmd) {
539 	case SIOCSIFADDR:
540 		break;
541 
542 	case SIOCSIFDSTADDR:
543 		break;
544 
545 	case SIOCADDMULTI:
546 	case SIOCDELMULTI:
547 		break;
548 
549 #ifdef	SIOCSIFMTU /* xxx */
550 	case SIOCGIFMTU:
551 		break;
552 
553 	case SIOCSIFMTU:
554 		{
555 			u_long mtu;
556 			mtu = ifr->ifr_mtu;
557 			if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
558 				return (EINVAL);
559 			}
560 			ifp->if_mtu = mtu;
561 		}
562 		break;
563 #endif /* SIOCSIFMTU */
564 
565 	case SIOCSIFPHYADDR:
566 #ifdef INET6
567 	case SIOCSIFPHYADDR_IN6:
568 #endif /* INET6 */
569 	case SIOCSLIFPHYADDR:
570 		switch (cmd) {
571 #ifdef INET
572 		case SIOCSIFPHYADDR:
573 			src = (struct sockaddr *)
574 				&(((struct in_aliasreq *)data)->ifra_addr);
575 			dst = (struct sockaddr *)
576 				&(((struct in_aliasreq *)data)->ifra_dstaddr);
577 			break;
578 #endif
579 #ifdef INET6
580 		case SIOCSIFPHYADDR_IN6:
581 			src = (struct sockaddr *)
582 				&(((struct in6_aliasreq *)data)->ifra_addr);
583 			dst = (struct sockaddr *)
584 				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
585 			break;
586 #endif
587 		case SIOCSLIFPHYADDR:
588 			src = (struct sockaddr *)
589 				&(((struct if_laddrreq *)data)->addr);
590 			dst = (struct sockaddr *)
591 				&(((struct if_laddrreq *)data)->dstaddr);
592 		}
593 
594 		/* sa_family must be equal */
595 		if (src->sa_family != dst->sa_family)
596 			return EINVAL;
597 
598 		/* validate sa_len */
599 		switch (src->sa_family) {
600 #ifdef INET
601 		case AF_INET:
602 			if (src->sa_len != sizeof(struct sockaddr_in))
603 				return EINVAL;
604 			break;
605 #endif
606 #ifdef INET6
607 		case AF_INET6:
608 			if (src->sa_len != sizeof(struct sockaddr_in6))
609 				return EINVAL;
610 			break;
611 #endif
612 		default:
613 			return EAFNOSUPPORT;
614 		}
615 		switch (dst->sa_family) {
616 #ifdef INET
617 		case AF_INET:
618 			if (dst->sa_len != sizeof(struct sockaddr_in))
619 				return EINVAL;
620 			break;
621 #endif
622 #ifdef INET6
623 		case AF_INET6:
624 			if (dst->sa_len != sizeof(struct sockaddr_in6))
625 				return EINVAL;
626 			break;
627 #endif
628 		default:
629 			return EAFNOSUPPORT;
630 		}
631 
632 		/* check sa_family looks sane for the cmd */
633 		switch (cmd) {
634 		case SIOCSIFPHYADDR:
635 			if (src->sa_family == AF_INET)
636 				break;
637 			return EAFNOSUPPORT;
638 #ifdef INET6
639 		case SIOCSIFPHYADDR_IN6:
640 			if (src->sa_family == AF_INET6)
641 				break;
642 			return EAFNOSUPPORT;
643 #endif /* INET6 */
644 		case SIOCSLIFPHYADDR:
645 			/* checks done in the above */
646 			break;
647 		}
648 
649 		TAILQ_FOREACH(ifp2, &ifnet, if_link) {
650 			if (strcmp(ifp2->if_name, GIFNAME) != 0)
651 				continue;
652 			sc2 = ifp2->if_softc;
653 			if (sc2 == sc)
654 				continue;
655 			if (!sc2->gif_pdst || !sc2->gif_psrc)
656 				continue;
657 			if (sc2->gif_pdst->sa_family != dst->sa_family ||
658 			    sc2->gif_pdst->sa_len != dst->sa_len ||
659 			    sc2->gif_psrc->sa_family != src->sa_family ||
660 			    sc2->gif_psrc->sa_len != src->sa_len)
661 				continue;
662 #ifndef XBONEHACK
663 			/* can't configure same pair of address onto two gifs */
664 			if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
665 			    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
666 				error = EADDRNOTAVAIL;
667 				goto bad;
668 			}
669 #endif
670 
671 			/* can't configure multiple multi-dest interfaces */
672 #define multidest(x) \
673 	(((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
674 #ifdef INET6
675 #define multidest6(x) \
676 	(IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
677 #endif
678 			if (dst->sa_family == AF_INET &&
679 			    multidest(dst) && multidest(sc2->gif_pdst)) {
680 				error = EADDRNOTAVAIL;
681 				goto bad;
682 			}
683 #ifdef INET6
684 			if (dst->sa_family == AF_INET6 &&
685 			    multidest6(dst) && multidest6(sc2->gif_pdst)) {
686 				error = EADDRNOTAVAIL;
687 				goto bad;
688 			}
689 #endif
690 		}
691 
692 		if (sc->gif_psrc)
693 			free((caddr_t)sc->gif_psrc, M_IFADDR);
694 		sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
695 		bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
696 		sc->gif_psrc = sa;
697 
698 		if (sc->gif_pdst)
699 			free((caddr_t)sc->gif_pdst, M_IFADDR);
700 		sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
701 		bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
702 		sc->gif_pdst = sa;
703 
704 		ifp->if_flags |= IFF_RUNNING;
705 		s = splimp();
706 		if_up(ifp);	/* mark interface UP and send up RTM_IFINFO */
707 		splx(s);
708 
709 		error = 0;
710 		break;
711 
712 #ifdef SIOCDIFPHYADDR
713 	case SIOCDIFPHYADDR:
714 		if (sc->gif_psrc) {
715 			free((caddr_t)sc->gif_psrc, M_IFADDR);
716 			sc->gif_psrc = NULL;
717 		}
718 		if (sc->gif_pdst) {
719 			free((caddr_t)sc->gif_pdst, M_IFADDR);
720 			sc->gif_pdst = NULL;
721 		}
722 		/* change the IFF_{UP, RUNNING} flag as well? */
723 		break;
724 #endif
725 
726 	case SIOCGIFPSRCADDR:
727 #ifdef INET6
728 	case SIOCGIFPSRCADDR_IN6:
729 #endif /* INET6 */
730 		if (sc->gif_psrc == NULL) {
731 			error = EADDRNOTAVAIL;
732 			goto bad;
733 		}
734 		src = sc->gif_psrc;
735 		switch (cmd) {
736 #ifdef INET
737 		case SIOCGIFPSRCADDR:
738 			dst = &ifr->ifr_addr;
739 			size = sizeof(ifr->ifr_addr);
740 			break;
741 #endif /* INET */
742 #ifdef INET6
743 		case SIOCGIFPSRCADDR_IN6:
744 			dst = (struct sockaddr *)
745 				&(((struct in6_ifreq *)data)->ifr_addr);
746 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
747 			break;
748 #endif /* INET6 */
749 		default:
750 			error = EADDRNOTAVAIL;
751 			goto bad;
752 		}
753 		if (src->sa_len > size)
754 			return EINVAL;
755 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
756 		break;
757 
758 	case SIOCGIFPDSTADDR:
759 #ifdef INET6
760 	case SIOCGIFPDSTADDR_IN6:
761 #endif /* INET6 */
762 		if (sc->gif_pdst == NULL) {
763 			error = EADDRNOTAVAIL;
764 			goto bad;
765 		}
766 		src = sc->gif_pdst;
767 		switch (cmd) {
768 #ifdef INET
769 		case SIOCGIFPDSTADDR:
770 			dst = &ifr->ifr_addr;
771 			size = sizeof(ifr->ifr_addr);
772 			break;
773 #endif /* INET */
774 #ifdef INET6
775 		case SIOCGIFPDSTADDR_IN6:
776 			dst = (struct sockaddr *)
777 				&(((struct in6_ifreq *)data)->ifr_addr);
778 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
779 			break;
780 #endif /* INET6 */
781 		default:
782 			error = EADDRNOTAVAIL;
783 			goto bad;
784 		}
785 		if (src->sa_len > size)
786 			return EINVAL;
787 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
788 		break;
789 
790 	case SIOCGLIFPHYADDR:
791 		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
792 			error = EADDRNOTAVAIL;
793 			goto bad;
794 		}
795 
796 		/* copy src */
797 		src = sc->gif_psrc;
798 		dst = (struct sockaddr *)
799 			&(((struct if_laddrreq *)data)->addr);
800 		size = sizeof(((struct if_laddrreq *)data)->addr);
801 		if (src->sa_len > size)
802 			return EINVAL;
803 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
804 
805 		/* copy dst */
806 		src = sc->gif_pdst;
807 		dst = (struct sockaddr *)
808 			&(((struct if_laddrreq *)data)->dstaddr);
809 		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
810 		if (src->sa_len > size)
811 			return EINVAL;
812 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
813 		break;
814 
815 	case SIOCSIFFLAGS:
816 		/* if_ioctl() takes care of it */
817 		break;
818 
819 	default:
820 		error = EINVAL;
821 		break;
822 	}
823  bad:
824 	return error;
825 }
826 
827 void
828 gif_delete_tunnel(sc)
829 	struct gif_softc *sc;
830 {
831 	/* XXX: NetBSD protects this function with splsoftnet() */
832 
833 	if (sc->gif_psrc) {
834 		free((caddr_t)sc->gif_psrc, M_IFADDR);
835 		sc->gif_psrc = NULL;
836 	}
837 	if (sc->gif_pdst) {
838 		free((caddr_t)sc->gif_pdst, M_IFADDR);
839 		sc->gif_pdst = NULL;
840 	}
841 	/* change the IFF_UP flag as well? */
842 }
843