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