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