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