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