if_gif.c revision 105293
1178476Sjb/*	$FreeBSD: head/sys/net/if_gif.c 105293 2002-10-16 19:49:37Z ume $	*/
2178476Sjb/*	$KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $	*/
3178476Sjb
4178476Sjb/*
5178476Sjb * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6178476Sjb * All rights reserved.
7178476Sjb *
8178476Sjb * Redistribution and use in source and binary forms, with or without
9178476Sjb * modification, are permitted provided that the following conditions
10178476Sjb * are met:
11178476Sjb * 1. Redistributions of source code must retain the above copyright
12178476Sjb *    notice, this list of conditions and the following disclaimer.
13178476Sjb * 2. Redistributions in binary form must reproduce the above copyright
14178476Sjb *    notice, this list of conditions and the following disclaimer in the
15178476Sjb *    documentation and/or other materials provided with the distribution.
16178476Sjb * 3. Neither the name of the project nor the names of its contributors
17178476Sjb *    may be used to endorse or promote products derived from this software
18178476Sjb *    without specific prior written permission.
19178476Sjb *
20178476Sjb * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21178476Sjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22178476Sjb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23178476Sjb * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24178476Sjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25178476Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26178476Sjb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27178476Sjb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28178476Sjb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29178476Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30178476Sjb * SUCH DAMAGE.
31178476Sjb */
32178476Sjb
33178476Sjb#include "opt_inet.h"
34178476Sjb#include "opt_inet6.h"
35178476Sjb#include "opt_mac.h"
36178476Sjb
37178476Sjb#include <sys/param.h>
38178476Sjb#include <sys/systm.h>
39178476Sjb#include <sys/kernel.h>
40178476Sjb#include <sys/mac.h>
41178476Sjb#include <sys/malloc.h>
42178476Sjb#include <sys/mbuf.h>
43178476Sjb#include <sys/socket.h>
44178476Sjb#include <sys/sockio.h>
45178476Sjb#include <sys/errno.h>
46178476Sjb#include <sys/time.h>
47178476Sjb#include <sys/sysctl.h>
48178476Sjb#include <sys/syslog.h>
49178476Sjb#include <sys/protosw.h>
50178476Sjb#include <sys/conf.h>
51178476Sjb#include <machine/cpu.h>
52178476Sjb
53178476Sjb#include <net/if.h>
54178476Sjb#include <net/if_types.h>
55178476Sjb#include <net/netisr.h>
56178476Sjb#include <net/route.h>
57178476Sjb#include <net/bpf.h>
58178476Sjb
59178476Sjb#include <netinet/in.h>
60178476Sjb#include <netinet/in_systm.h>
61178476Sjb#include <netinet/ip.h>
62178476Sjb#ifdef	INET
63178476Sjb#include <netinet/in_var.h>
64178476Sjb#include <netinet/in_gif.h>
65178476Sjb#include <netinet/ip_var.h>
66178476Sjb#endif	/* INET */
67178476Sjb
68178476Sjb#ifdef INET6
69178476Sjb#ifndef INET
70178476Sjb#include <netinet/in.h>
71178476Sjb#endif
72178476Sjb#include <netinet6/in6_var.h>
73178476Sjb#include <netinet/ip6.h>
74178476Sjb#include <netinet6/ip6_var.h>
75178476Sjb#include <netinet6/in6_gif.h>
76178476Sjb#include <netinet6/ip6protosw.h>
77178476Sjb#endif /* INET6 */
78178476Sjb
79178476Sjb#include <netinet/ip_encap.h>
80178476Sjb#include <net/if_gif.h>
81178476Sjb
82178476Sjb#include <net/net_osdep.h>
83178476Sjb
84178476Sjb#define GIFNAME		"gif"
85178476Sjb
86178476Sjbstatic MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
87178476Sjbstatic LIST_HEAD(, gif_softc) gif_softc_list;
88178476Sjb
89178476Sjbvoid	(*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af);
90178476Sjbvoid	(*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
91178476Sjbvoid	(*ng_gif_attach_p)(struct ifnet *ifp);
92178476Sjbvoid	(*ng_gif_detach_p)(struct ifnet *ifp);
93178476Sjb
94178476Sjbint	gif_clone_create(struct if_clone *, int);
95178476Sjbvoid	gif_clone_destroy(struct ifnet *);
96178476Sjb
97178476Sjbstruct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif",
98178476Sjb    gif_clone_create, gif_clone_destroy, 0, IF_MAXUNIT);
99178476Sjb
100178476Sjbstatic int gifmodevent(module_t, int, void *);
101178476Sjb
102178476SjbSYSCTL_DECL(_net_link);
103178476SjbSYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
104178476Sjb    "Generic Tunnel Interface");
105178476Sjb#ifndef MAX_GIF_NEST
106178476Sjb/*
107178476Sjb * This macro controls the default upper limitation on nesting of gif tunnels.
108178476Sjb * Since, setting a large value to this macro with a careless configuration
109178476Sjb * may introduce system crash, we don't allow any nestings by default.
110178476Sjb * If you need to configure nested gif tunnels, you can define this macro
111178476Sjb * in your kernel configuration file.  However, if you do so, please be
112178476Sjb * careful to configure the tunnels so that it won't make a loop.
113178476Sjb */
114178476Sjb#define MAX_GIF_NEST 1
115178476Sjb#endif
116178476Sjbstatic int max_gif_nesting = MAX_GIF_NEST;
117178476SjbSYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW,
118178476Sjb    &max_gif_nesting, 0, "Max nested tunnels");
119178476Sjb
120178476Sjb/*
121178476Sjb * By default, we disallow creation of multiple tunnels between the same
122178476Sjb * pair of addresses.  Some applications require this functionality so
123178476Sjb * we allow control over this check here.
124178476Sjb */
125178476Sjb#ifdef XBONEHACK
126178476Sjbstatic int parallel_tunnels = 1;
127178476Sjb#else
128178476Sjbstatic int parallel_tunnels = 0;
129178476Sjb#endif
130178476SjbSYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW,
131178476Sjb    &parallel_tunnels, 0, "Allow parallel tunnels?");
132178476Sjb
133178476Sjbint
134178476Sjbgif_clone_create(ifc, unit)
135178476Sjb	struct if_clone *ifc;
136178476Sjb	int unit;
137178476Sjb{
138178476Sjb	struct gif_softc *sc;
139178476Sjb
140178476Sjb	sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK);
141178476Sjb	bzero(sc, sizeof(struct gif_softc));
142178476Sjb
143178476Sjb	sc->gif_if.if_softc = sc;
144178476Sjb	sc->gif_if.if_name = GIFNAME;
145	sc->gif_if.if_unit = unit;
146
147	gifattach0(sc);
148
149	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
150	return (0);
151}
152
153void
154gifattach0(sc)
155	struct gif_softc *sc;
156{
157
158	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
159
160	sc->gif_if.if_addrlen = 0;
161	sc->gif_if.if_mtu    = GIF_MTU;
162	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
163#if 0
164	/* turn off ingress filter */
165	sc->gif_if.if_flags  |= IFF_LINK2;
166#endif
167	sc->gif_if.if_ioctl  = gif_ioctl;
168	sc->gif_if.if_output = gif_output;
169	sc->gif_if.if_type   = IFT_GIF;
170	sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
171	if_attach(&sc->gif_if);
172	bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
173	if (ng_gif_attach_p != NULL)
174		(*ng_gif_attach_p)(&sc->gif_if);
175}
176
177void
178gif_clone_destroy(ifp)
179	struct ifnet *ifp;
180{
181	int err;
182	struct gif_softc *sc = ifp->if_softc;
183
184	gif_delete_tunnel(&sc->gif_if);
185	LIST_REMOVE(sc, gif_list);
186#ifdef INET6
187	if (sc->encap_cookie6 != NULL) {
188		err = encap_detach(sc->encap_cookie6);
189		KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
190	}
191#endif
192#ifdef INET
193	if (sc->encap_cookie4 != NULL) {
194		err = encap_detach(sc->encap_cookie4);
195		KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
196	}
197#endif
198
199	if (ng_gif_detach_p != NULL)
200		(*ng_gif_detach_p)(ifp);
201	bpfdetach(ifp);
202	if_detach(ifp);
203
204	free(sc, M_GIF);
205}
206
207static int
208gifmodevent(mod, type, data)
209	module_t mod;
210	int type;
211	void *data;
212{
213
214	switch (type) {
215	case MOD_LOAD:
216		LIST_INIT(&gif_softc_list);
217		if_clone_attach(&gif_cloner);
218
219#ifdef INET6
220		ip6_gif_hlim = GIF_HLIM;
221#endif
222
223		break;
224	case MOD_UNLOAD:
225		if_clone_detach(&gif_cloner);
226
227		while (!LIST_EMPTY(&gif_softc_list))
228			gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if);
229
230#ifdef INET6
231		ip6_gif_hlim = 0;
232#endif
233		break;
234	}
235	return 0;
236}
237
238static moduledata_t gif_mod = {
239	"if_gif",
240	gifmodevent,
241	0
242};
243
244DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
245MODULE_VERSION(if_gif, 1);
246
247int
248gif_encapcheck(m, off, proto, arg)
249	const struct mbuf *m;
250	int off;
251	int proto;
252	void *arg;
253{
254	struct ip ip;
255	struct gif_softc *sc;
256
257	sc = (struct gif_softc *)arg;
258	if (sc == NULL)
259		return 0;
260
261	if ((sc->gif_if.if_flags & IFF_UP) == 0)
262		return 0;
263
264	/* no physical address */
265	if (!sc->gif_psrc || !sc->gif_pdst)
266		return 0;
267
268	switch (proto) {
269#ifdef INET
270	case IPPROTO_IPV4:
271		break;
272#endif
273#ifdef INET6
274	case IPPROTO_IPV6:
275		break;
276#endif
277	default:
278		return 0;
279	}
280
281	m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
282
283	switch (ip.ip_v) {
284#ifdef INET
285	case 4:
286		if (sc->gif_psrc->sa_family != AF_INET ||
287		    sc->gif_pdst->sa_family != AF_INET)
288			return 0;
289		return gif_encapcheck4(m, off, proto, arg);
290#endif
291#ifdef INET6
292	case 6:
293		if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
294			return 0;
295		if (sc->gif_psrc->sa_family != AF_INET6 ||
296		    sc->gif_pdst->sa_family != AF_INET6)
297			return 0;
298		return gif_encapcheck6(m, off, proto, arg);
299#endif
300	default:
301		return 0;
302	}
303}
304
305int
306gif_output(ifp, m, dst, rt)
307	struct ifnet *ifp;
308	struct mbuf *m;
309	struct sockaddr *dst;
310	struct rtentry *rt;	/* added in net2 */
311{
312	struct gif_softc *sc = (struct gif_softc*)ifp;
313	int error = 0;
314	static int called = 0;	/* XXX: MUTEX */
315
316#ifdef MAC
317	error = mac_check_ifnet_transmit(ifp, m);
318	if (error) {
319		m_freem(m);
320		goto end;
321	}
322#endif
323
324	/*
325	 * gif may cause infinite recursion calls when misconfigured.
326	 * We'll prevent this by introducing upper limit.
327	 * XXX: this mechanism may introduce another problem about
328	 *      mutual exclusion of the variable CALLED, especially if we
329	 *      use kernel thread.
330	 */
331	if (++called > max_gif_nesting) {
332		log(LOG_NOTICE,
333		    "gif_output: recursively called too many times(%d)\n",
334		    called);
335		m_freem(m);
336		error = EIO;	/* is there better errno? */
337		goto end;
338	}
339
340	m->m_flags &= ~(M_BCAST|M_MCAST);
341	if (!(ifp->if_flags & IFF_UP) ||
342	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
343		m_freem(m);
344		error = ENETDOWN;
345		goto end;
346	}
347
348	if (ifp->if_bpf) {
349		/*
350		 * We need to prepend the address family as
351		 * a four byte field.  Cons up a dummy header
352		 * to pacify bpf.  This is safe because bpf
353		 * will only read from the mbuf (i.e., it won't
354		 * try to free it or keep a pointer a to it).
355		 */
356		struct mbuf m0;
357		u_int32_t af = dst->sa_family;
358
359		m0.m_next = m;
360		m0.m_len = 4;
361		m0.m_data = (char *)&af;
362
363		bpf_mtap(ifp, &m0);
364	}
365	ifp->if_opackets++;
366	ifp->if_obytes += m->m_pkthdr.len;
367
368	/* inner AF-specific encapsulation */
369
370	/* XXX should we check if our outer source is legal? */
371
372	/* dispatch to output logic based on outer AF */
373	switch (sc->gif_psrc->sa_family) {
374#ifdef INET
375	case AF_INET:
376		error = in_gif_output(ifp, dst->sa_family, m, rt);
377		break;
378#endif
379#ifdef INET6
380	case AF_INET6:
381		error = in6_gif_output(ifp, dst->sa_family, m, rt);
382		break;
383#endif
384	default:
385		m_freem(m);
386		error = ENETDOWN;
387		goto end;
388	}
389
390  end:
391	called = 0;		/* reset recursion counter */
392	if (error)
393		ifp->if_oerrors++;
394	return error;
395}
396
397void
398gif_input(m, af, gifp)
399	struct mbuf *m;
400	int af;
401	struct ifnet *gifp;
402{
403	int isr;
404	struct ifqueue *ifq = 0;
405
406	if (gifp == NULL) {
407		/* just in case */
408		m_freem(m);
409		return;
410	}
411
412	m->m_pkthdr.rcvif = gifp;
413
414#ifdef MAC
415	mac_create_mbuf_from_ifnet(gifp, m);
416#endif
417
418	if (gifp->if_bpf) {
419		/*
420		 * We need to prepend the address family as
421		 * a four byte field.  Cons up a dummy header
422		 * to pacify bpf.  This is safe because bpf
423		 * will only read from the mbuf (i.e., it won't
424		 * try to free it or keep a pointer a to it).
425		 */
426		struct mbuf m0;
427		u_int32_t af1 = af;
428
429		m0.m_next = m;
430		m0.m_len = 4;
431		m0.m_data = (char *)&af1;
432
433		bpf_mtap(gifp, &m0);
434	}
435
436	if (ng_gif_input_p != NULL) {
437		(*ng_gif_input_p)(gifp, &m, af);
438		if (m == NULL)
439			return;
440	}
441
442	/*
443	 * Put the packet to the network layer input queue according to the
444	 * specified address family.
445	 * Note: older versions of gif_input directly called network layer
446	 * input functions, e.g. ip6_input, here.  We changed the policy to
447	 * prevent too many recursive calls of such input functions, which
448	 * might cause kernel panic.  But the change may introduce another
449	 * problem; if the input queue is full, packets are discarded.
450	 * The kernel stack overflow really happened, and we believed
451	 * queue-full rarely occurs, so we changed the policy.
452	 */
453	switch (af) {
454#ifdef INET
455	case AF_INET:
456		ifq = &ipintrq;
457		isr = NETISR_IP;
458		break;
459#endif
460#ifdef INET6
461	case AF_INET6:
462		ifq = &ip6intrq;
463		isr = NETISR_IPV6;
464		break;
465#endif
466	default:
467		if (ng_gif_input_orphan_p != NULL)
468			(*ng_gif_input_orphan_p)(gifp, m, af);
469		else
470			m_freem(m);
471		return;
472	}
473
474	gifp->if_ipackets++;
475	gifp->if_ibytes += m->m_pkthdr.len;
476	(void) IF_HANDOFF(ifq, m, NULL);
477	/* we need schednetisr since the address family may change */
478	schednetisr(isr);
479
480	return;
481}
482
483/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
484int
485gif_ioctl(ifp, cmd, data)
486	struct ifnet *ifp;
487	u_long cmd;
488	caddr_t data;
489{
490	struct gif_softc *sc  = (struct gif_softc*)ifp;
491	struct ifreq     *ifr = (struct ifreq*)data;
492	int error = 0, size;
493	struct sockaddr *dst, *src;
494
495	switch (cmd) {
496	case SIOCSIFADDR:
497		ifp->if_flags |= IFF_UP;
498		break;
499
500	case SIOCSIFDSTADDR:
501		break;
502
503	case SIOCADDMULTI:
504	case SIOCDELMULTI:
505		break;
506
507#ifdef	SIOCSIFMTU /* xxx */
508	case SIOCGIFMTU:
509		break;
510
511	case SIOCSIFMTU:
512		{
513			u_long mtu;
514			mtu = ifr->ifr_mtu;
515			if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
516				return (EINVAL);
517			}
518			ifp->if_mtu = mtu;
519		}
520		break;
521#endif /* SIOCSIFMTU */
522
523	case SIOCSIFPHYADDR:
524#ifdef INET6
525	case SIOCSIFPHYADDR_IN6:
526#endif /* INET6 */
527	case SIOCSLIFPHYADDR:
528		switch (cmd) {
529#ifdef INET
530		case SIOCSIFPHYADDR:
531			src = (struct sockaddr *)
532				&(((struct in_aliasreq *)data)->ifra_addr);
533			dst = (struct sockaddr *)
534				&(((struct in_aliasreq *)data)->ifra_dstaddr);
535			break;
536#endif
537#ifdef INET6
538		case SIOCSIFPHYADDR_IN6:
539			src = (struct sockaddr *)
540				&(((struct in6_aliasreq *)data)->ifra_addr);
541			dst = (struct sockaddr *)
542				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
543			break;
544#endif
545		case SIOCSLIFPHYADDR:
546			src = (struct sockaddr *)
547				&(((struct if_laddrreq *)data)->addr);
548			dst = (struct sockaddr *)
549				&(((struct if_laddrreq *)data)->dstaddr);
550			break;
551		default:
552			return EINVAL;
553		}
554
555		/* sa_family must be equal */
556		if (src->sa_family != dst->sa_family)
557			return EINVAL;
558
559		/* validate sa_len */
560		switch (src->sa_family) {
561#ifdef INET
562		case AF_INET:
563			if (src->sa_len != sizeof(struct sockaddr_in))
564				return EINVAL;
565			break;
566#endif
567#ifdef INET6
568		case AF_INET6:
569			if (src->sa_len != sizeof(struct sockaddr_in6))
570				return EINVAL;
571			break;
572#endif
573		default:
574			return EAFNOSUPPORT;
575		}
576		switch (dst->sa_family) {
577#ifdef INET
578		case AF_INET:
579			if (dst->sa_len != sizeof(struct sockaddr_in))
580				return EINVAL;
581			break;
582#endif
583#ifdef INET6
584		case AF_INET6:
585			if (dst->sa_len != sizeof(struct sockaddr_in6))
586				return EINVAL;
587			break;
588#endif
589		default:
590			return EAFNOSUPPORT;
591		}
592
593		/* check sa_family looks sane for the cmd */
594		switch (cmd) {
595		case SIOCSIFPHYADDR:
596			if (src->sa_family == AF_INET)
597				break;
598			return EAFNOSUPPORT;
599#ifdef INET6
600		case SIOCSIFPHYADDR_IN6:
601			if (src->sa_family == AF_INET6)
602				break;
603			return EAFNOSUPPORT;
604#endif /* INET6 */
605		case SIOCSLIFPHYADDR:
606			/* checks done in the above */
607			break;
608		}
609
610		error = gif_set_tunnel(&sc->gif_if, src, dst);
611		break;
612
613#ifdef SIOCDIFPHYADDR
614	case SIOCDIFPHYADDR:
615		gif_delete_tunnel(&sc->gif_if);
616		break;
617#endif
618
619	case SIOCGIFPSRCADDR:
620#ifdef INET6
621	case SIOCGIFPSRCADDR_IN6:
622#endif /* INET6 */
623		if (sc->gif_psrc == NULL) {
624			error = EADDRNOTAVAIL;
625			goto bad;
626		}
627		src = sc->gif_psrc;
628		switch (cmd) {
629#ifdef INET
630		case SIOCGIFPSRCADDR:
631			dst = &ifr->ifr_addr;
632			size = sizeof(ifr->ifr_addr);
633			break;
634#endif /* INET */
635#ifdef INET6
636		case SIOCGIFPSRCADDR_IN6:
637			dst = (struct sockaddr *)
638				&(((struct in6_ifreq *)data)->ifr_addr);
639			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
640			break;
641#endif /* INET6 */
642		default:
643			error = EADDRNOTAVAIL;
644			goto bad;
645		}
646		if (src->sa_len > size)
647			return EINVAL;
648		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
649		break;
650
651	case SIOCGIFPDSTADDR:
652#ifdef INET6
653	case SIOCGIFPDSTADDR_IN6:
654#endif /* INET6 */
655		if (sc->gif_pdst == NULL) {
656			error = EADDRNOTAVAIL;
657			goto bad;
658		}
659		src = sc->gif_pdst;
660		switch (cmd) {
661#ifdef INET
662		case SIOCGIFPDSTADDR:
663			dst = &ifr->ifr_addr;
664			size = sizeof(ifr->ifr_addr);
665			break;
666#endif /* INET */
667#ifdef INET6
668		case SIOCGIFPDSTADDR_IN6:
669			dst = (struct sockaddr *)
670				&(((struct in6_ifreq *)data)->ifr_addr);
671			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
672			break;
673#endif /* INET6 */
674		default:
675			error = EADDRNOTAVAIL;
676			goto bad;
677		}
678		if (src->sa_len > size)
679			return EINVAL;
680		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
681		break;
682
683	case SIOCGLIFPHYADDR:
684		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
685			error = EADDRNOTAVAIL;
686			goto bad;
687		}
688
689		/* copy src */
690		src = sc->gif_psrc;
691		dst = (struct sockaddr *)
692			&(((struct if_laddrreq *)data)->addr);
693		size = sizeof(((struct if_laddrreq *)data)->addr);
694		if (src->sa_len > size)
695			return EINVAL;
696		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
697
698		/* copy dst */
699		src = sc->gif_pdst;
700		dst = (struct sockaddr *)
701			&(((struct if_laddrreq *)data)->dstaddr);
702		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
703		if (src->sa_len > size)
704			return EINVAL;
705		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
706		break;
707
708	case SIOCSIFFLAGS:
709		/* if_ioctl() takes care of it */
710		break;
711
712	default:
713		error = EINVAL;
714		break;
715	}
716 bad:
717	return error;
718}
719
720int
721gif_set_tunnel(ifp, src, dst)
722	struct ifnet *ifp;
723	struct sockaddr *src;
724	struct sockaddr *dst;
725{
726	struct gif_softc *sc = (struct gif_softc *)ifp;
727	struct gif_softc *sc2;
728	struct sockaddr *osrc, *odst, *sa;
729	int s;
730	int error = 0;
731
732	s = splnet();
733
734	LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
735		if (sc2 == sc)
736			continue;
737		if (!sc2->gif_pdst || !sc2->gif_psrc)
738			continue;
739		if (sc2->gif_pdst->sa_family != dst->sa_family ||
740		    sc2->gif_pdst->sa_len != dst->sa_len ||
741		    sc2->gif_psrc->sa_family != src->sa_family ||
742		    sc2->gif_psrc->sa_len != src->sa_len)
743			continue;
744
745		/*
746		 * Disallow parallel tunnels unless instructed
747		 * otherwise.
748		 */
749		if (!parallel_tunnels &&
750		    bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
751		    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
752			error = EADDRNOTAVAIL;
753			goto bad;
754		}
755
756		/* XXX both end must be valid? (I mean, not 0.0.0.0) */
757	}
758
759	/* XXX we can detach from both, but be polite just in case */
760	if (sc->gif_psrc)
761		switch (sc->gif_psrc->sa_family) {
762#ifdef INET
763		case AF_INET:
764			(void)in_gif_detach(sc);
765			break;
766#endif
767#ifdef INET6
768		case AF_INET6:
769			(void)in6_gif_detach(sc);
770			break;
771#endif
772		}
773
774	osrc = sc->gif_psrc;
775	sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
776	bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
777	sc->gif_psrc = sa;
778
779	odst = sc->gif_pdst;
780	sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
781	bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
782	sc->gif_pdst = sa;
783
784	switch (sc->gif_psrc->sa_family) {
785#ifdef INET
786	case AF_INET:
787		error = in_gif_attach(sc);
788		break;
789#endif
790#ifdef INET6
791	case AF_INET6:
792		error = in6_gif_attach(sc);
793		break;
794#endif
795	}
796	if (error) {
797		/* rollback */
798		free((caddr_t)sc->gif_psrc, M_IFADDR);
799		free((caddr_t)sc->gif_pdst, M_IFADDR);
800		sc->gif_psrc = osrc;
801		sc->gif_pdst = odst;
802		goto bad;
803	}
804
805	if (osrc)
806		free((caddr_t)osrc, M_IFADDR);
807	if (odst)
808		free((caddr_t)odst, M_IFADDR);
809
810	if (sc->gif_psrc && sc->gif_pdst)
811		ifp->if_flags |= IFF_RUNNING;
812	else
813		ifp->if_flags &= ~IFF_RUNNING;
814	splx(s);
815
816	return 0;
817
818 bad:
819	if (sc->gif_psrc && sc->gif_pdst)
820		ifp->if_flags |= IFF_RUNNING;
821	else
822		ifp->if_flags &= ~IFF_RUNNING;
823	splx(s);
824
825	return error;
826}
827
828void
829gif_delete_tunnel(ifp)
830	struct ifnet *ifp;
831{
832	struct gif_softc *sc = (struct gif_softc *)ifp;
833	int s;
834
835	s = splnet();
836
837	if (sc->gif_psrc) {
838		free((caddr_t)sc->gif_psrc, M_IFADDR);
839		sc->gif_psrc = NULL;
840	}
841	if (sc->gif_pdst) {
842		free((caddr_t)sc->gif_pdst, M_IFADDR);
843		sc->gif_pdst = NULL;
844	}
845	/* it is safe to detach from both */
846#ifdef INET
847	(void)in_gif_detach(sc);
848#endif
849#ifdef INET6
850	(void)in6_gif_detach(sc);
851#endif
852
853	if (sc->gif_psrc && sc->gif_pdst)
854		ifp->if_flags |= IFF_RUNNING;
855	else
856		ifp->if_flags &= ~IFF_RUNNING;
857	splx(s);
858}
859