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