1/*
2 * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/* $FreeBSD: src/sys/net/if_gif.c,v 1.4.2.6 2001/07/24 19:10:18 brooks Exp $ */
29/* $KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 itojun Exp $ */
30
31/*
32 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
33 * All rights reserved.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 *    notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 *    notice, this list of conditions and the following disclaimer in the
42 *    documentation and/or other materials provided with the distribution.
43 * 3. Neither the name of the project nor the names of its contributors
44 *    may be used to endorse or promote products derived from this software
45 *    without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 */
59/*
60 * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce
61 * support for mandatory and extensible security protections.  This notice
62 * is included in support of clause 2.2 (b) of the Apple Public License,
63 * Version 2.0.
64 */
65
66#include <sys/param.h>
67#include <sys/systm.h>
68#include <sys/kernel.h>
69#include <sys/malloc.h>
70#include <sys/mbuf.h>
71#include <sys/socket.h>
72#include <sys/sockio.h>
73#include <sys/errno.h>
74#include <sys/time.h>
75#include <sys/syslog.h>
76#include <sys/protosw.h>
77#include <kern/cpu_number.h>
78
79#include <net/if.h>
80#include <net/if_types.h>
81#include <net/route.h>
82#include <net/bpf.h>
83#include <net/kpi_protocol.h>
84#include <net/kpi_interface.h>
85#include <net/init.h>
86
87#include <netinet/in.h>
88#include <netinet/in_systm.h>
89#include <netinet/ip.h>
90#if	INET
91#include <netinet/in_var.h>
92#include <netinet/in_gif.h>
93#include <netinet/ip_var.h>
94#endif	/* INET */
95
96#if INET6
97#include <netinet6/in6_var.h>
98#include <netinet/ip6.h>
99#include <netinet6/ip6_var.h>
100#include <netinet6/in6_gif.h>
101#include <netinet6/ip6protosw.h>
102#endif /* INET6 */
103
104#include <netinet/ip_encap.h>
105#include <net/dlil.h>
106#include <net/if_gif.h>
107
108#include <net/net_osdep.h>
109
110#if CONFIG_MACF_NET
111#include <security/mac_framework.h>
112#endif
113
114#define	GIFNAME		"gif"
115#define	GIFDEV		"if_gif"
116#define	GIF_MAXUNIT	0x7fff	/* ifp->if_unit is only 15 bits */
117
118/* gif lock variables */
119static lck_grp_t	*gif_mtx_grp;
120static lck_grp_attr_t	*gif_mtx_grp_attr;
121static lck_attr_t	*gif_mtx_attr;
122decl_lck_mtx_data(static, gif_mtx_data);
123static lck_mtx_t	*gif_mtx = &gif_mtx_data;
124
125TAILQ_HEAD(gifhead, gif_softc) gifs = TAILQ_HEAD_INITIALIZER(gifs);
126
127static int gif_encapcheck(const struct mbuf *, int, int, void *);
128static errno_t gif_output(ifnet_t ifp, mbuf_t m);
129static errno_t gif_input(ifnet_t ifp, protocol_family_t protocol_family,
130    mbuf_t m, char *frame_header);
131static errno_t gif_ioctl(ifnet_t ifp, u_long cmd, void *data);
132
133static int ngif = 0;		/* number of interfaces */
134
135#if INET
136static struct protosw in_gif_protosw =
137{
138	.pr_type =		SOCK_RAW,
139	.pr_protocol =		0, /* IPPROTO_IPV[46] */
140	.pr_flags =		PR_ATOMIC|PR_ADDR,
141	.pr_input =		in_gif_input,
142	.pr_usrreqs =		&rip_usrreqs,
143	.pr_unlock =		rip_unlock,
144};
145#endif
146#if INET6
147static struct ip6protosw in6_gif_protosw =
148{
149	.pr_type =		SOCK_RAW,
150	.pr_protocol =		0, /* IPPROTO_IPV[46] */
151	.pr_flags =		PR_ATOMIC|PR_ADDR,
152	.pr_input =		in6_gif_input,
153	.pr_usrreqs =		&rip6_usrreqs,
154	.pr_unlock =		rip_unlock,
155};
156#endif
157
158static if_clone_t gif_cloner = NULL;
159static int gif_clone_create(struct if_clone *, uint32_t, void *);
160static int gif_clone_destroy(struct ifnet *);
161static void gif_delete_tunnel(struct gif_softc *);
162static void gif_detach(struct ifnet *);
163
164/*
165 * Theory of operation: initially, one gif interface is created.
166 * Any time a gif interface is configured, if there are no other
167 * unconfigured gif interfaces, a new gif interface is created.
168 * BSD uses the clone mechanism to dynamically create more
169 * gif interfaces.
170 *
171 * We have some extra glue to support DLIL.
172 */
173
174/* GIF interface module support */
175static int
176gif_demux(
177	ifnet_t ifp,
178	__unused mbuf_t m,
179	__unused char *frame_header,
180	protocol_family_t *protocol_family)
181{
182	struct gif_softc *sc = ifnet_softc(ifp);
183
184	GIF_LOCK(sc);
185	/* Only one protocol may be attached to a gif interface. */
186	*protocol_family = sc->gif_proto;
187	GIF_UNLOCK(sc);
188
189	return (0);
190}
191
192static errno_t
193gif_add_proto(
194	ifnet_t ifp,
195	protocol_family_t protocol_family,
196	__unused const struct ifnet_demux_desc *demux_array,
197	__unused u_int32_t demux_count)
198{
199	/* Only one protocol may be attached at a time */
200	struct gif_softc *sc = ifnet_softc(ifp);
201
202	GIF_LOCK(sc);
203	if (sc->gif_proto != 0)
204		printf("gif_add_proto: request add_proto for gif%d\n",
205		    ifnet_unit(ifp));
206
207	sc->gif_proto = protocol_family;
208	GIF_UNLOCK(sc);
209
210	return (0);
211}
212
213static errno_t
214gif_del_proto(
215	ifnet_t ifp,
216	protocol_family_t protocol_family)
217{
218	struct gif_softc *sc = ifnet_softc(ifp);
219
220	GIF_LOCK(sc);
221	if (sc->gif_proto == protocol_family)
222		sc->gif_proto = 0;
223	GIF_UNLOCK(sc);
224
225	return (0);
226}
227
228/* Glue code to attach inet to a gif interface through DLIL */
229static errno_t
230gif_attach_proto_family(
231	ifnet_t ifp,
232	protocol_family_t protocol_family)
233{
234	struct ifnet_attach_proto_param reg;
235	errno_t stat;
236
237	bzero(&reg, sizeof (reg));
238	reg.input = gif_input;
239
240	stat = ifnet_attach_protocol(ifp, protocol_family, &reg);
241	if (stat && stat != EEXIST) {
242		printf("gif_attach_proto_family can't attach interface	\
243		    fam=%d\n", protocol_family);
244	}
245
246	return (stat);
247}
248
249/* Function to setup the first gif interface */
250void
251gif_init(void)
252{
253	errno_t result;
254	struct ifnet_clone_params ifnet_clone_params;
255	struct if_clone *ifc = NULL;
256
257	/* Initialize the list of interfaces */
258	TAILQ_INIT(&gifs);
259
260	/* Initialize the gif global lock */
261	gif_mtx_grp_attr = lck_grp_attr_alloc_init();
262	gif_mtx_grp = lck_grp_alloc_init("gif", gif_mtx_grp_attr);
263	gif_mtx_attr = lck_attr_alloc_init();
264	lck_mtx_init(gif_mtx, gif_mtx_grp, gif_mtx_attr);
265
266	/* Register protocol registration functions */
267	result = proto_register_plumber(PF_INET, APPLE_IF_FAM_GIF,
268	    gif_attach_proto_family, NULL);
269	if (result != 0)
270		printf("proto_register_plumber failed for AF_INET error=%d\n",
271		    result);
272
273	result = proto_register_plumber(PF_INET6, APPLE_IF_FAM_GIF,
274	    gif_attach_proto_family, NULL);
275	if (result != 0)
276		printf("proto_register_plumber failed for AF_INET6 error=%d\n",
277		    result);
278
279	ifnet_clone_params.ifc_name = "gif";
280	ifnet_clone_params.ifc_create = gif_clone_create;
281	ifnet_clone_params.ifc_destroy = gif_clone_destroy;
282
283	result = ifnet_clone_attach(&ifnet_clone_params, &gif_cloner);
284	if (result != 0)
285		printf("gifattach: ifnet_clone_attach failed %d\n", result);
286
287	/* Create first device */
288	ifc = if_clone_lookup("gif", NULL);
289	gif_clone_create(ifc, 0, NULL);
290}
291
292static errno_t
293gif_set_bpf_tap(
294	ifnet_t ifp,
295	bpf_tap_mode mode,
296	bpf_packet_func callback)
297{
298	struct gif_softc *sc = ifnet_softc(ifp);
299
300	GIF_LOCK(sc);
301	sc->tap_mode = mode;
302	sc->tap_callback = callback;
303	GIF_UNLOCK(sc);
304
305	return (0);
306}
307
308static void
309gif_detach(struct ifnet *ifp)
310{
311	struct gif_softc *sc = ifp->if_softc;
312	lck_mtx_destroy(&sc->gif_lock, gif_mtx_grp);
313	_FREE(ifp->if_softc, M_DEVBUF);
314	ifp->if_softc = NULL;
315	(void) ifnet_release(ifp);
316}
317
318static int
319gif_clone_create(struct if_clone *ifc, uint32_t unit, __unused void *params)
320{
321	struct gif_softc *sc = NULL;
322	struct ifnet_init_params gif_init_params;
323	errno_t error = 0;
324
325	lck_mtx_lock(gif_mtx);
326
327	/* Can't create more than GIF_MAXUNIT */
328	if (ngif >= GIF_MAXUNIT) {
329		error = ENXIO;
330		goto done;
331	}
332
333	sc = _MALLOC(sizeof (struct gif_softc), M_DEVBUF, M_WAITOK);
334	if (sc == NULL) {
335		log(LOG_ERR, "gif_clone_create: failed to allocate gif%d\n",
336		    unit);
337		error = ENOBUFS;
338		goto done;
339	}
340	bzero(sc, sizeof (struct gif_softc));
341
342	/* use the interface name as the unique id for ifp recycle */
343	snprintf(sc->gif_ifname, sizeof (sc->gif_ifname), "%s%d",
344	    ifc->ifc_name, unit);
345
346	lck_mtx_init(&sc->gif_lock, gif_mtx_grp, gif_mtx_attr);
347
348	bzero(&gif_init_params, sizeof (gif_init_params));
349	gif_init_params.uniqueid = sc->gif_ifname;
350	gif_init_params.uniqueid_len = strlen(sc->gif_ifname);
351	gif_init_params.name = GIFNAME;
352	gif_init_params.unit = unit;
353	gif_init_params.type = IFT_GIF;
354	gif_init_params.family = IFNET_FAMILY_GIF;
355	gif_init_params.output = gif_output;
356	gif_init_params.demux = gif_demux;
357	gif_init_params.add_proto = gif_add_proto;
358	gif_init_params.del_proto = gif_del_proto;
359	gif_init_params.softc = sc;
360	gif_init_params.ioctl = gif_ioctl;
361	gif_init_params.set_bpf_tap = gif_set_bpf_tap;
362	gif_init_params.detach = gif_detach;
363
364	error = ifnet_allocate(&gif_init_params, &sc->gif_if);
365	if (error != 0) {
366		printf("gif_clone_create, ifnet_allocate failed - %d\n", error);
367		_FREE(sc, M_DEVBUF);
368		error = ENOBUFS;
369		goto done;
370	}
371
372	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
373#if INET
374	sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
375			gif_encapcheck, &in_gif_protosw, sc);
376	if (sc->encap_cookie4 == NULL) {
377		printf("%s: unable to attach encap4\n", if_name(sc->gif_if));
378		ifnet_release(sc->gif_if);
379		FREE(sc, M_DEVBUF);
380		error = ENOBUFS;
381		goto done;
382	}
383#endif
384#if INET6
385	sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
386	    gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc);
387	if (sc->encap_cookie6 == NULL) {
388		if (sc->encap_cookie4) {
389			encap_detach(sc->encap_cookie4);
390			sc->encap_cookie4 = NULL;
391		}
392		printf("%s: unable to attach encap6\n", if_name(sc->gif_if));
393		ifnet_release(sc->gif_if);
394		FREE(sc, M_DEVBUF);
395		error = ENOBUFS;
396		goto done;
397	}
398#endif
399	sc->gif_called = 0;
400	ifnet_set_mtu(sc->gif_if, GIF_MTU);
401	ifnet_set_flags(sc->gif_if, IFF_POINTOPOINT | IFF_MULTICAST, 0xffff);
402#if 0
403	/* turn off ingress filter */
404	sc->gif_if.if_flags  |= IFF_LINK2;
405#endif
406	error = ifnet_attach(sc->gif_if, NULL);
407	if (error != 0) {
408		printf("gif_clone_create - ifnet_attach failed - %d\n", error);
409		ifnet_release(sc->gif_if);
410		if (sc->encap_cookie4) {
411			encap_detach(sc->encap_cookie4);
412			sc->encap_cookie4 = NULL;
413		}
414		if (sc->encap_cookie6) {
415			encap_detach(sc->encap_cookie6);
416			sc->encap_cookie6 = NULL;
417		}
418		FREE(sc, M_DEVBUF);
419		goto done;
420	}
421#if CONFIG_MACF_NET
422	mac_ifnet_label_init(&sc->gif_if);
423#endif
424	bpfattach(sc->gif_if, DLT_NULL, sizeof (u_int));
425	TAILQ_INSERT_TAIL(&gifs, sc, gif_link);
426	ngif++;
427done:
428	lck_mtx_unlock(gif_mtx);
429
430	return (error);
431}
432
433static int
434gif_clone_destroy(struct ifnet *ifp)
435{
436#if defined(INET) || defined(INET6)
437	int error = 0;
438#endif
439	struct gif_softc *sc = ifp->if_softc;
440
441	lck_mtx_lock(gif_mtx);
442	TAILQ_REMOVE(&gifs, sc, gif_link);
443	ngif--;
444
445	GIF_LOCK(sc);
446	gif_delete_tunnel(sc);
447#ifdef INET6
448	if (sc->encap_cookie6 != NULL) {
449		error = encap_detach(sc->encap_cookie6);
450		KASSERT(error == 0, ("gif_clone_destroy: Unexpected	\
451		    error detaching encap_cookie6"));
452	}
453#endif
454#ifdef INET
455	if (sc->encap_cookie4 != NULL) {
456		error = encap_detach(sc->encap_cookie4);
457		KASSERT(error == 0, ("gif_clone_destroy: Unexpected	\
458		    error detaching encap_cookie4"));
459	}
460#endif
461	error = ifnet_set_flags(ifp, 0, IFF_UP);
462	if (error != 0) {
463		printf("gif_clone_destroy: ifnet_set_flags failed %d\n", error);
464	}
465
466	error = ifnet_detach(ifp);
467	if (error != 0)
468		panic("gif_clone_destroy: ifnet_detach(%p) failed %d\n", ifp,
469		    error);
470
471	GIF_UNLOCK(sc);
472	lck_mtx_unlock(gif_mtx);
473
474	return (0);
475}
476
477static int
478gif_encapcheck(
479	const struct mbuf *m,
480	int off,
481	int proto,
482	void *arg)
483{
484	int error = 0;
485	struct ip ip;
486	struct gif_softc *sc;
487
488	sc = (struct gif_softc *)arg;
489	if (sc == NULL)
490		return (error);
491
492	GIF_LOCK(sc);
493	if ((ifnet_flags(sc->gif_if) & IFF_UP) == 0)
494		goto done;
495
496	/* no physical address */
497	if (!sc->gif_psrc || !sc->gif_pdst)
498		goto done;
499
500	switch (proto) {
501#if INET
502	case IPPROTO_IPV4:
503		break;
504#endif
505#if INET6
506	case IPPROTO_IPV6:
507		break;
508#endif
509	default:
510		goto done;
511	}
512
513	mbuf_copydata((struct mbuf *)(size_t)m, 0, sizeof (ip), &ip);
514
515	switch (ip.ip_v) {
516#if INET
517	case 4:
518		if (sc->gif_psrc->sa_family != AF_INET ||
519		    sc->gif_pdst->sa_family != AF_INET)
520			goto done;
521		error = gif_encapcheck4(m, off, proto, arg);
522#endif
523#if INET6
524	case 6:
525		if (sc->gif_psrc->sa_family != AF_INET6 ||
526		    sc->gif_pdst->sa_family != AF_INET6)
527			goto done;
528		error = gif_encapcheck6(m, off, proto, arg);
529#endif
530	default:
531		goto done;
532	}
533done:
534	GIF_UNLOCK(sc);
535	return (error);
536}
537
538static errno_t
539gif_output(
540	ifnet_t ifp,
541	mbuf_t m)
542{
543	struct gif_softc *sc = ifnet_softc(ifp);
544	struct sockaddr *gif_psrc;
545	struct sockaddr *gif_pdst;
546	int error = 0;
547
548	GIF_LOCK(sc);
549	gif_psrc = sc->gif_psrc;
550	gif_pdst = sc->gif_pdst;
551	GIF_UNLOCK(sc);
552
553	/*
554	 * max_gif_nesting check used to live here. It doesn't anymore
555	 * because there is no guaruntee that we won't be called
556	 * concurrently from more than one thread.
557	 */
558	m->m_flags &= ~(M_BCAST|M_MCAST);
559	if (!(ifnet_flags(ifp) & IFF_UP) ||
560	    gif_psrc == NULL || gif_pdst == NULL) {
561		ifnet_touch_lastchange(ifp);
562		m_freem(m);	/* free it here not in dlil_output */
563		error = ENETDOWN;
564		goto end;
565	}
566
567	bpf_tap_out(ifp, 0, m, &sc->gif_proto, sizeof (sc->gif_proto));
568
569	GIF_LOCK(sc);
570
571	/* inner AF-specific encapsulation */
572
573	/* XXX should we check if our outer source is legal? */
574
575	/* dispatch to output logic based on outer AF */
576	switch (sc->gif_psrc->sa_family) {
577#if INET
578	case AF_INET:
579		error = in_gif_output(ifp, sc->gif_proto, m, NULL);
580		break;
581#endif
582#if INET6
583	case AF_INET6:
584		error = in6_gif_output(ifp, sc->gif_proto, m, NULL);
585		break;
586#endif
587	default:
588		error = ENETDOWN;
589		break;
590	}
591
592	GIF_UNLOCK(sc);
593end:
594	if (error) {
595		/* the mbuf was freed either by in_gif_output or in here */
596		ifnet_stat_increment_out(ifp, 0, 0, 1);
597	} else {
598		ifnet_stat_increment_out(ifp, 1, m->m_pkthdr.len, 0);
599	}
600	if (error == 0)
601		error = EJUSTRETURN; /* if no error, packet got sent already */
602	return (error);
603}
604
605/*
606 * gif_input is the input handler for IP and IPv6 attached to gif
607 */
608static errno_t
609gif_input(
610	ifnet_t ifp,
611	protocol_family_t protocol_family,
612	mbuf_t m,
613	__unused char *frame_header)
614{
615	struct gif_softc *sc = ifnet_softc(ifp);
616
617	bpf_tap_in(ifp, 0, m, &sc->gif_proto, sizeof (sc->gif_proto));
618
619	/*
620	 * Put the packet to the network layer input queue according to the
621	 * specified address family.
622	 * Note: older versions of gif_input directly called network layer
623	 * input functions, e.g. ip6_input, here. We changed the policy to
624	 * prevent too many recursive calls of such input functions, which
625	 * might cause kernel panic. But the change may introduce another
626	 * problem; if the input queue is full, packets are discarded.
627	 * We believed it rarely occurs and changed the policy. If we find
628	 * it occurs more times than we thought, we may change the policy
629	 * again.
630	 */
631	if (proto_input(protocol_family, m) != 0) {
632		ifnet_stat_increment_in(ifp, 0, 0, 1);
633		m_freem(m);
634	} else
635		ifnet_stat_increment_in(ifp, 1, m->m_pkthdr.len, 0);
636
637	return (0);
638}
639
640/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
641static errno_t
642gif_ioctl(
643	ifnet_t			ifp,
644	u_long			cmd,
645	void			*data)
646{
647	struct gif_softc *sc  = ifnet_softc(ifp);
648	struct ifreq *ifr = (struct ifreq *)data;
649	int error = 0, size;
650	struct sockaddr *dst = NULL, *src = NULL;
651	struct sockaddr *sa;
652	struct ifnet *ifp2;
653	struct gif_softc *sc2;
654
655	switch (cmd) {
656	case SIOCSIFADDR:
657		break;
658
659	case SIOCSIFDSTADDR:
660		break;
661
662	case SIOCADDMULTI:
663	case SIOCDELMULTI:
664		break;
665
666#ifdef	SIOCSIFMTU /* xxx */
667	case SIOCGIFMTU:
668		break;
669
670	case SIOCSIFMTU:
671		{
672			u_int32_t mtu;
673			mtu = ifr->ifr_mtu;
674			if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
675				return (EINVAL);
676			}
677			ifnet_set_mtu(ifp, mtu);
678		}
679		break;
680#endif /* SIOCSIFMTU */
681
682	case SIOCSIFPHYADDR:
683#if INET6
684	case SIOCSIFPHYADDR_IN6_32:
685	case SIOCSIFPHYADDR_IN6_64:
686#endif /* INET6 */
687	case SIOCSLIFPHYADDR:
688		switch (cmd) {
689#if INET
690		case SIOCSIFPHYADDR:
691			src = (struct sockaddr *)
692				&(((struct in_aliasreq *)data)->ifra_addr);
693			dst = (struct sockaddr *)
694				&(((struct in_aliasreq *)data)->ifra_dstaddr);
695			break;
696#endif
697#if INET6
698		case SIOCSIFPHYADDR_IN6_32: {
699			struct in6_aliasreq_32 *ifra_32 =
700			    (struct in6_aliasreq_32 *)data;
701
702			src = (struct sockaddr *)&ifra_32->ifra_addr;
703			dst = (struct sockaddr *)&ifra_32->ifra_dstaddr;
704			break;
705		}
706
707		case SIOCSIFPHYADDR_IN6_64: {
708			struct in6_aliasreq_64 *ifra_64 =
709			    (struct in6_aliasreq_64 *)data;
710
711			src = (struct sockaddr *)&ifra_64->ifra_addr;
712			dst = (struct sockaddr *)&ifra_64->ifra_dstaddr;
713			break;
714		}
715#endif
716		case SIOCSLIFPHYADDR:
717			src = (struct sockaddr *)
718				&(((struct if_laddrreq *)data)->addr);
719			dst = (struct sockaddr *)
720				&(((struct if_laddrreq *)data)->dstaddr);
721		}
722
723		/* sa_family must be equal */
724		if (src->sa_family != dst->sa_family)
725			return (EINVAL);
726
727		/* validate sa_len */
728		switch (src->sa_family) {
729#if INET
730		case AF_INET:
731			if (src->sa_len != sizeof (struct sockaddr_in))
732				return (EINVAL);
733			break;
734#endif
735#if INET6
736		case AF_INET6:
737			if (src->sa_len != sizeof (struct sockaddr_in6))
738				return (EINVAL);
739			break;
740#endif
741		default:
742			return (EAFNOSUPPORT);
743		}
744		switch (dst->sa_family) {
745#if INET
746		case AF_INET:
747			if (dst->sa_len != sizeof (struct sockaddr_in))
748				return (EINVAL);
749			break;
750#endif
751#if INET6
752		case AF_INET6:
753			if (dst->sa_len != sizeof (struct sockaddr_in6))
754				return (EINVAL);
755			break;
756#endif
757		default:
758			return (EAFNOSUPPORT);
759		}
760
761		/* check sa_family looks sane for the cmd */
762		switch (cmd) {
763		case SIOCSIFPHYADDR:
764			if (src->sa_family == AF_INET)
765				break;
766			return (EAFNOSUPPORT);
767#if INET6
768		case SIOCSIFPHYADDR_IN6_32:
769		case SIOCSIFPHYADDR_IN6_64:
770			if (src->sa_family == AF_INET6)
771				break;
772			return (EAFNOSUPPORT);
773#endif /* INET6 */
774		case SIOCSLIFPHYADDR:
775			/* checks done in the above */
776			break;
777		}
778
779#define	GIF_ORDERED_LOCK(sc, sc2)	\
780	if (sc < sc2) {			\
781		GIF_LOCK(sc);		\
782		GIF_LOCK(sc2);		\
783	} else {			\
784		GIF_LOCK(sc2);		\
785		GIF_LOCK(sc);		\
786	}
787
788#define	GIF_ORDERED_UNLOCK(sc, sc2)	\
789	if (sc > sc2) {			\
790		GIF_UNLOCK(sc);		\
791		GIF_UNLOCK(sc2);	\
792	} else {			\
793		GIF_UNLOCK(sc2);	\
794		GIF_UNLOCK(sc);		\
795	}
796
797		ifnet_head_lock_shared();
798		TAILQ_FOREACH(ifp2, &ifnet_head, if_link) {
799			if (strcmp(ifnet_name(ifp2), GIFNAME) != 0)
800				continue;
801			sc2 = ifnet_softc(ifp2);
802			if (sc2 == sc)
803				continue;
804			/* lock sc and sc2 in increasing order of ifnet index */
805			GIF_ORDERED_LOCK(sc, sc2);
806			if (!sc2->gif_pdst || !sc2->gif_psrc) {
807				GIF_ORDERED_UNLOCK(sc, sc2);
808				continue;
809			}
810			if (sc2->gif_pdst->sa_family != dst->sa_family ||
811			    sc2->gif_pdst->sa_len != dst->sa_len ||
812			    sc2->gif_psrc->sa_family != src->sa_family ||
813			    sc2->gif_psrc->sa_len != src->sa_len) {
814				GIF_ORDERED_UNLOCK(sc, sc2);
815				continue;
816			}
817#ifndef XBONEHACK
818			/* can't configure same pair of address onto two gifs */
819			if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
820			    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
821				GIF_ORDERED_UNLOCK(sc, sc2);
822				error = EADDRNOTAVAIL;
823				ifnet_head_done();
824				goto bad;
825			}
826#endif
827
828			/* can't configure multiple multi-dest interfaces */
829#define	multidest(x) \
830	(((struct sockaddr_in *)(void *)(x))->sin_addr.s_addr == INADDR_ANY)
831#if INET6
832#define	multidest6(x) \
833	(IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)	\
834	    (void *)(x))->sin6_addr))
835#endif
836			if (dst->sa_family == AF_INET &&
837			    multidest(dst) && multidest(sc2->gif_pdst)) {
838				GIF_ORDERED_UNLOCK(sc, sc2);
839				error = EADDRNOTAVAIL;
840				ifnet_head_done();
841				goto bad;
842			}
843#if INET6
844			if (dst->sa_family == AF_INET6 &&
845			    multidest6(dst) && multidest6(sc2->gif_pdst)) {
846				GIF_ORDERED_UNLOCK(sc, sc2);
847				error = EADDRNOTAVAIL;
848				ifnet_head_done();
849				goto bad;
850			}
851#endif
852			GIF_ORDERED_UNLOCK(sc, sc2);
853		}
854		ifnet_head_done();
855
856		GIF_LOCK(sc);
857		if (sc->gif_psrc)
858			FREE((caddr_t)sc->gif_psrc, M_IFADDR);
859		sa = (struct sockaddr *)_MALLOC(src->sa_len, M_IFADDR,
860		    M_WAITOK);
861		if (sa == NULL) {
862			GIF_UNLOCK(sc);
863			return (ENOBUFS);
864		}
865		bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
866		sc->gif_psrc = sa;
867
868		if (sc->gif_pdst)
869			FREE((caddr_t)sc->gif_pdst, M_IFADDR);
870		sa = (struct sockaddr *)_MALLOC(dst->sa_len, M_IFADDR,
871		    M_WAITOK);
872		if (sa == NULL) {
873			GIF_UNLOCK(sc);
874			return (ENOBUFS);
875		}
876		bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
877		sc->gif_pdst = sa;
878		GIF_UNLOCK(sc);
879
880		ifnet_set_flags(ifp, IFF_RUNNING | IFF_UP, IFF_RUNNING |
881		    IFF_UP);
882
883		error = 0;
884		break;
885
886#ifdef SIOCDIFPHYADDR
887	case SIOCDIFPHYADDR:
888		GIF_LOCK(sc);
889		if (sc->gif_psrc) {
890			FREE((caddr_t)sc->gif_psrc, M_IFADDR);
891			sc->gif_psrc = NULL;
892		}
893		if (sc->gif_pdst) {
894			FREE((caddr_t)sc->gif_pdst, M_IFADDR);
895			sc->gif_pdst = NULL;
896		}
897		GIF_UNLOCK(sc);
898		/* change the IFF_{UP, RUNNING} flag as well? */
899		break;
900#endif
901
902	case SIOCGIFPSRCADDR:
903#if INET6
904	case SIOCGIFPSRCADDR_IN6:
905#endif /* INET6 */
906		GIF_LOCK(sc);
907		if (sc->gif_psrc == NULL) {
908			GIF_UNLOCK(sc);
909			error = EADDRNOTAVAIL;
910			goto bad;
911		}
912		src = sc->gif_psrc;
913		switch (cmd) {
914#if INET
915		case SIOCGIFPSRCADDR:
916			dst = &ifr->ifr_addr;
917			size = sizeof (ifr->ifr_addr);
918			break;
919#endif /* INET */
920#if INET6
921		case SIOCGIFPSRCADDR_IN6:
922			dst = (struct sockaddr *)
923				&(((struct in6_ifreq *)data)->ifr_addr);
924			size = sizeof (((struct in6_ifreq *)data)->ifr_addr);
925			break;
926#endif /* INET6 */
927		default:
928			GIF_UNLOCK(sc);
929			error = EADDRNOTAVAIL;
930			goto bad;
931		}
932		if (src->sa_len > size) {
933			GIF_UNLOCK(sc);
934			return (EINVAL);
935		}
936		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
937		GIF_UNLOCK(sc);
938		break;
939
940	case SIOCGIFPDSTADDR:
941#if INET6
942	case SIOCGIFPDSTADDR_IN6:
943#endif /* INET6 */
944		GIF_LOCK(sc);
945		if (sc->gif_pdst == NULL) {
946			GIF_UNLOCK(sc);
947			error = EADDRNOTAVAIL;
948			goto bad;
949		}
950		src = sc->gif_pdst;
951		switch (cmd) {
952#if INET
953		case SIOCGIFPDSTADDR:
954			dst = &ifr->ifr_addr;
955			size = sizeof (ifr->ifr_addr);
956			break;
957#endif /* INET */
958#if INET6
959		case SIOCGIFPDSTADDR_IN6:
960			dst = (struct sockaddr *)
961				&(((struct in6_ifreq *)data)->ifr_addr);
962			size = sizeof (((struct in6_ifreq *)data)->ifr_addr);
963			break;
964#endif /* INET6 */
965		default:
966			error = EADDRNOTAVAIL;
967			GIF_UNLOCK(sc);
968			goto bad;
969		}
970		if (src->sa_len > size) {
971			GIF_UNLOCK(sc);
972			return (EINVAL);
973		}
974		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
975		GIF_UNLOCK(sc);
976		break;
977
978	case SIOCGLIFPHYADDR:
979		GIF_LOCK(sc);
980		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
981			GIF_UNLOCK(sc);
982			error = EADDRNOTAVAIL;
983			goto bad;
984		}
985
986		/* copy src */
987		src = sc->gif_psrc;
988		dst = (struct sockaddr *)
989			&(((struct if_laddrreq *)data)->addr);
990		size = sizeof (((struct if_laddrreq *)data)->addr);
991		if (src->sa_len > size) {
992			GIF_UNLOCK(sc);
993			return (EINVAL);
994		}
995		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
996
997		/* copy dst */
998		src = sc->gif_pdst;
999		dst = (struct sockaddr *)
1000			&(((struct if_laddrreq *)data)->dstaddr);
1001		size = sizeof (((struct if_laddrreq *)data)->dstaddr);
1002		if (src->sa_len > size) {
1003			GIF_UNLOCK(sc);
1004			return (EINVAL);
1005		}
1006		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
1007		GIF_UNLOCK(sc);
1008		break;
1009
1010	case SIOCSIFFLAGS:
1011		/* if_ioctl() takes care of it */
1012		break;
1013
1014	default:
1015		error = EOPNOTSUPP;
1016		break;
1017	}
1018bad:
1019	return (error);
1020}
1021
1022static void
1023gif_delete_tunnel(struct gif_softc *sc)
1024{
1025	GIF_LOCK_ASSERT(sc);
1026	if (sc->gif_psrc) {
1027		FREE((caddr_t)sc->gif_psrc, M_IFADDR);
1028		sc->gif_psrc = NULL;
1029	}
1030	if (sc->gif_pdst) {
1031		FREE((caddr_t)sc->gif_pdst, M_IFADDR);
1032		sc->gif_pdst = NULL;
1033	}
1034	ROUTE_RELEASE(&sc->gif_ro);
1035	/* change the IFF_UP flag as well? */
1036}
1037