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