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