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