1/*
2 * Copyright (c) 2000-2008 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
86#include <netinet/in.h>
87#include <netinet/in_systm.h>
88#include <netinet/ip.h>
89#if	INET
90#include <netinet/in_var.h>
91#include <netinet/in_gif.h>
92#include <netinet/ip_var.h>
93#endif	/* INET */
94
95#if INET6
96#include <netinet6/in6_var.h>
97#include <netinet/ip6.h>
98#include <netinet6/ip6_var.h>
99#include <netinet6/in6_gif.h>
100#include <netinet6/ip6protosw.h>
101#endif /* INET6 */
102
103#include <netinet/ip_encap.h>
104#include <net/dlil.h>
105#include <net/if_gif.h>
106
107#include <net/net_osdep.h>
108
109#if CONFIG_MACF_NET
110#include <security/mac_framework.h>
111#endif
112
113#define GIFNAME		"gif"
114#define GIFDEV		"if_gif"
115#define GIF_MAXUNIT	0x7fff	/* ifp->if_unit is only 15 bits */
116
117#ifndef __APPLE__
118static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
119#endif
120
121TAILQ_HEAD(gifhead, gif_softc) gifs = TAILQ_HEAD_INITIALIZER(gifs);
122
123#ifdef __APPLE__
124void gifattach(void);
125static int gif_encapcheck(const struct mbuf*, int, int, void*);
126static errno_t gif_output(ifnet_t ifp, mbuf_t m);
127static errno_t gif_input(ifnet_t ifp, protocol_family_t protocol_family,
128						 mbuf_t m, char *frame_header);
129static errno_t gif_ioctl(ifnet_t ifp, u_long cmd, void *data);
130
131int ngif = 0;		/* number of interfaces */
132#endif
133
134#if INET
135struct protosw in_gif_protosw =
136{ SOCK_RAW,	0,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
137  in_gif_input,	0,	0,		0,
138  0,
139  0,		0,	0,	0,
140  0,
141  &rip_usrreqs,
142  0,		rip_unlock,	0, {0, 0}, 0, {0}
143};
144#endif
145#if INET6
146struct ip6protosw in6_gif_protosw =
147{ SOCK_RAW,	0,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
148  in6_gif_input, 0,		0,		0,
149  0,
150  0,		0,		0,		0,
151  0,
152  &rip6_usrreqs,
153  0,		rip_unlock,		0, {0, 0}, 0, {0}
154
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 *);
162
163#ifdef __APPLE__
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 gif_demux(
176    ifnet_t					ifp,
177    __unused mbuf_t			m,
178    __unused char			*frame_header,
179    protocol_family_t		*protocol_family)
180{
181	/* Only one protocol may be attached to a gif interface. */
182	*protocol_family = ((struct gif_softc*)ifnet_softc(ifp))->gif_proto;
183
184	return 0;
185}
186
187static errno_t
188gif_add_proto(
189	ifnet_t									ifp,
190	protocol_family_t						protocol_family,
191	__unused const struct ifnet_demux_desc	*demux_array,
192	__unused u_int32_t						demux_count)
193{
194	/* Only one protocol may be attached at a time */
195	struct gif_softc* gif = ifnet_softc(ifp);
196
197	if (gif->gif_proto != 0)
198		printf("gif_add_proto: request add_proto for gif%d\n", ifnet_unit(ifp));
199
200	gif->gif_proto = protocol_family;
201
202	return 0;
203}
204
205static errno_t
206gif_del_proto(
207	ifnet_t				ifp,
208	protocol_family_t	protocol_family)
209{
210	if (((struct gif_softc*)ifnet_softc(ifp))->gif_proto == protocol_family)
211		((struct gif_softc*)ifnet_softc(ifp))->gif_proto = 0;
212
213	return 0;
214}
215
216/* Glue code to attach inet to a gif interface through DLIL */
217static errno_t
218gif_attach_proto_family(
219	ifnet_t				ifp,
220	protocol_family_t	protocol_family)
221{
222    struct ifnet_attach_proto_param	reg;
223    errno_t							stat;
224
225	bzero(&reg, sizeof(reg));
226    reg.input            = gif_input;
227
228    stat = ifnet_attach_protocol(ifp, protocol_family, &reg);
229    if (stat && stat != EEXIST) {
230        printf("gif_attach_proto_family can't attach interface fam=%d\n",
231        	   protocol_family);
232    }
233
234    return stat;
235}
236
237#endif
238
239/* Function to setup the first gif interface */
240__private_extern__ void
241gifattach(void)
242{
243	errno_t result;
244	struct ifnet_clone_params ifnet_clone_params;
245	struct if_clone *ifc = NULL;
246
247	/* Init the list of interfaces */
248	TAILQ_INIT(&gifs);
249
250	/* Register protocol registration functions */
251	result = proto_register_plumber(PF_INET, APPLE_IF_FAM_GIF,
252									gif_attach_proto_family, NULL);
253	if (result != 0)
254		printf("proto_register_plumber failed for AF_INET error=%d\n", result);
255
256	result = proto_register_plumber(PF_INET6, APPLE_IF_FAM_GIF,
257									gif_attach_proto_family, NULL);
258	if (result != 0)
259		printf("proto_register_plumber failed for AF_INET6 error=%d\n", result);
260
261	ifnet_clone_params.ifc_name = "gif";
262	ifnet_clone_params.ifc_create = gif_clone_create;
263	ifnet_clone_params.ifc_destroy = gif_clone_destroy;
264
265	result = ifnet_clone_attach(&ifnet_clone_params, &gif_cloner);
266	if (result != 0)
267		printf("gifattach: ifnet_clone_attach failed %d\n", result);
268
269	/* Create first device */
270	ifc = if_clone_lookup("gif", NULL);
271	gif_clone_create(ifc, 0, NULL);
272}
273
274static errno_t
275gif_set_bpf_tap(
276	ifnet_t			ifp,
277	bpf_tap_mode	mode,
278	bpf_packet_func	callback)
279{
280	struct gif_softc	*sc = ifnet_softc(ifp);
281
282	sc->tap_mode = mode;
283	sc->tap_callback = callback;
284
285	return 0;
286}
287
288
289static int
290gif_clone_create(struct if_clone *ifc, uint32_t unit, __unused void *params)
291{
292	struct gif_softc	*sc = NULL;
293	struct ifnet_init_params gif_init;
294	errno_t result = 0;
295
296	/* Can't create more than GIF_MAXUNIT */
297	if (ngif >= GIF_MAXUNIT)
298		return (ENXIO);
299
300	sc = _MALLOC(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK);
301	if (sc == NULL) {
302		log(LOG_ERR, "gif_clone_create: failed to allocate gif%d\n", unit);
303		return ENOBUFS;
304	}
305	bzero(sc, sizeof(struct gif_softc));
306
307	/* use the interface name as the unique id for ifp recycle */
308	snprintf(sc->gif_ifname, sizeof(sc->gif_ifname), "%s%d",
309			ifc->ifc_name, unit);
310
311	bzero(&gif_init, sizeof(gif_init));
312	gif_init.uniqueid = sc->gif_ifname;
313	gif_init.uniqueid_len = strlen(sc->gif_ifname);
314	gif_init.name = GIFNAME;
315	gif_init.unit = unit;
316	gif_init.type = IFT_GIF;
317	gif_init.family = IFNET_FAMILY_GIF;
318	gif_init.output = gif_output;
319	gif_init.demux = gif_demux;
320	gif_init.add_proto = gif_add_proto;
321	gif_init.del_proto = gif_del_proto;
322	gif_init.softc = sc;
323	gif_init.ioctl = gif_ioctl;
324	gif_init.set_bpf_tap = gif_set_bpf_tap;
325
326	result = ifnet_allocate(&gif_init, &sc->gif_if);
327	if (result != 0) {
328		printf("gif_clone_create, ifnet_allocate failed - %d\n", result);
329		_FREE(sc, M_DEVBUF);
330		return ENOBUFS;
331	}
332
333	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
334#if INET
335	sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
336			gif_encapcheck, &in_gif_protosw, sc);
337	if (sc->encap_cookie4 == NULL) {
338		printf("%s: unable to attach encap4\n", if_name(sc->gif_if));
339		ifnet_release(sc->gif_if);
340		FREE(sc, M_DEVBUF);
341		return ENOBUFS;
342	}
343#endif
344#if INET6
345	sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
346	    gif_encapcheck, (struct protosw*)&in6_gif_protosw, sc);
347	if (sc->encap_cookie6 == NULL) {
348		if (sc->encap_cookie4) {
349			encap_detach(sc->encap_cookie4);
350			sc->encap_cookie4 = NULL;
351		}
352		printf("%s: unable to attach encap6\n", if_name(sc->gif_if));
353		ifnet_release(sc->gif_if);
354		FREE(sc, M_DEVBUF);
355		return ENOBUFS;
356	}
357#endif
358	sc->gif_called = 0;
359	ifnet_set_mtu(sc->gif_if, GIF_MTU);
360	ifnet_set_flags(sc->gif_if, IFF_POINTOPOINT | IFF_MULTICAST, 0xffff);
361#if 0
362	/* turn off ingress filter */
363	sc->gif_if.if_flags  |= IFF_LINK2;
364#endif
365	result = ifnet_attach(sc->gif_if, NULL);
366	if (result != 0) {
367		printf("gif_clone_create - ifnet_attach failed - %d\n", result);
368		ifnet_release(sc->gif_if);
369		if (sc->encap_cookie4) {
370			encap_detach(sc->encap_cookie4);
371			sc->encap_cookie4 = NULL;
372		}
373		if (sc->encap_cookie6) {
374			encap_detach(sc->encap_cookie6);
375			sc->encap_cookie6 = NULL;
376		}
377		FREE(sc, M_DEVBUF);
378		return result;
379	}
380#if CONFIG_MACF_NET
381	mac_ifnet_label_init(&sc->gif_if);
382#endif
383	bpfattach(sc->gif_if, DLT_NULL, sizeof(u_int));
384	TAILQ_INSERT_TAIL(&gifs, sc, gif_link);
385	ngif++;
386	return 0;
387}
388
389static int
390gif_clone_destroy(struct ifnet *ifp)
391{
392#if defined(INET) || defined(INET6)
393	int err = 0;
394#endif
395	struct gif_softc *sc = ifp->if_softc;
396
397	TAILQ_REMOVE(&gifs, sc, gif_link);
398
399	gif_delete_tunnel(sc);
400#ifdef INET6
401	if (sc->encap_cookie6 != NULL) {
402		err = encap_detach(sc->encap_cookie6);
403		KASSERT(err == 0, ("gif_clone_destroy: Unexpected error detaching encap_cookie6"));
404	}
405#endif
406#ifdef INET
407	if (sc->encap_cookie4 != NULL) {
408		err = encap_detach(sc->encap_cookie4);
409		KASSERT(err == 0, ("gif_clone_destroy: Unexpected error detaching encap_cookie4"));
410	}
411#endif
412	err = ifnet_set_flags(ifp, 0, IFF_UP);
413	if (err != 0) {
414		printf("gif_clone_destroy: ifnet_set_flags failed %d\n", err);
415	}
416
417	err = ifnet_detach(ifp);
418	if (err != 0)
419		panic("gif_clone_destroy: ifnet_detach(%p) failed %d\n", ifp, err);
420	FREE(sc, M_DEVBUF);
421	ngif--;
422	return 0;
423}
424
425static int
426gif_encapcheck(
427	const struct mbuf *m,
428	int off,
429	int proto,
430	void *arg)
431{
432	struct ip ip;
433	struct gif_softc *sc;
434
435	sc = (struct gif_softc *)arg;
436	if (sc == NULL)
437		return 0;
438
439	if ((ifnet_flags(sc->gif_if) & IFF_UP) == 0)
440		return 0;
441
442	/* no physical address */
443	if (!sc->gif_psrc || !sc->gif_pdst)
444		return 0;
445
446	switch (proto) {
447#if INET
448	case IPPROTO_IPV4:
449		break;
450#endif
451#if INET6
452	case IPPROTO_IPV6:
453		break;
454#endif
455	default:
456		return 0;
457	}
458
459	mbuf_copydata((struct mbuf *)(size_t)m, 0, sizeof(ip), &ip);
460
461	switch (ip.ip_v) {
462#if INET
463	case 4:
464		if (sc->gif_psrc->sa_family != AF_INET ||
465		    sc->gif_pdst->sa_family != AF_INET)
466			return 0;
467		return gif_encapcheck4(m, off, proto, arg);
468#endif
469#if INET6
470	case 6:
471		if (sc->gif_psrc->sa_family != AF_INET6 ||
472		    sc->gif_pdst->sa_family != AF_INET6)
473			return 0;
474		return gif_encapcheck6(m, off, proto, arg);
475#endif
476	default:
477		return 0;
478	}
479}
480
481static errno_t
482gif_output(
483	ifnet_t		ifp,
484	mbuf_t		m)
485{
486	struct gif_softc *sc = ifnet_softc(ifp);
487	int error = 0;
488
489	/*
490	   max_gif_nesting check used to live here. It doesn't anymore
491	   because there is no guaruntee that we won't be called
492	   concurrently from more than one thread.
493	 */
494
495	m->m_flags &= ~(M_BCAST|M_MCAST);
496	if (!(ifnet_flags(ifp) & IFF_UP) ||
497	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
498		ifnet_touch_lastchange(ifp);
499		m_freem(m);	/* free it here not in dlil_output */
500		error = ENETDOWN;
501		goto end;
502	}
503
504	bpf_tap_out(ifp, 0, m, &sc->gif_proto, sizeof(sc->gif_proto));
505
506	/* inner AF-specific encapsulation */
507
508	/* XXX should we check if our outer source is legal? */
509
510	/* dispatch to output logic based on outer AF */
511	switch (sc->gif_psrc->sa_family) {
512#if INET
513	case AF_INET:
514		error = in_gif_output(ifp, sc->gif_proto, m, NULL);
515		break;
516#endif
517#if INET6
518	case AF_INET6:
519		error = in6_gif_output(ifp, sc->gif_proto, m, NULL);
520		break;
521#endif
522	default:
523		error = ENETDOWN;
524		goto end;
525	}
526
527  end:
528	if (error) {
529		/* the mbuf was freed either by in_gif_output or in here */
530		ifnet_stat_increment_out(ifp, 0, 0, 1);
531	}
532	else {
533		ifnet_stat_increment_out(ifp, 1, m->m_pkthdr.len, 0);
534	}
535	if (error == 0)
536		error = EJUSTRETURN; /* if no error, packet got sent already */
537	return error;
538}
539
540/*
541 * gif_input is the input handler for IP and IPv6 attached to gif
542 */
543static errno_t
544gif_input(
545	ifnet_t				ifp,
546	protocol_family_t	protocol_family,
547	mbuf_t				m,
548	__unused char		*frame_header)
549{
550	struct gif_softc *sc = ifnet_softc(ifp);
551
552	bpf_tap_in(ifp, 0, m, &sc->gif_proto, sizeof(sc->gif_proto));
553
554	/*
555	 * Put the packet to the network layer input queue according to the
556	 * specified address family.
557	 * Note: older versions of gif_input directly called network layer
558	 * input functions, e.g. ip6_input, here. We changed the policy to
559	 * prevent too many recursive calls of such input functions, which
560	 * might cause kernel panic. But the change may introduce another
561	 * problem; if the input queue is full, packets are discarded.
562	 * We believed it rarely occurs and changed the policy. If we find
563	 * it occurs more times than we thought, we may change the policy
564	 * again.
565	 */
566	if (proto_input(protocol_family, m) != 0) {
567		ifnet_stat_increment_in(ifp, 0, 0, 1);
568		m_freem(m);
569	} else
570		ifnet_stat_increment_in(ifp, 1, m->m_pkthdr.len, 0);
571
572	return (0);
573}
574
575/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
576static errno_t
577gif_ioctl(
578	ifnet_t			ifp,
579	u_long			cmd,
580	void			*data)
581{
582	struct gif_softc *sc  = ifnet_softc(ifp);
583	struct ifreq     *ifr = (struct ifreq*)data;
584	int error = 0, size;
585	struct sockaddr *dst = NULL, *src = NULL;
586	struct sockaddr *sa;
587	struct ifnet *ifp2;
588	struct gif_softc *sc2;
589
590	switch (cmd) {
591	case SIOCSIFADDR:
592		break;
593
594	case SIOCSIFDSTADDR:
595		break;
596
597	case SIOCADDMULTI:
598	case SIOCDELMULTI:
599		break;
600
601#ifdef	SIOCSIFMTU /* xxx */
602	case SIOCGIFMTU:
603		break;
604
605	case SIOCSIFMTU:
606		{
607			u_int32_t mtu;
608			mtu = ifr->ifr_mtu;
609			if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
610				return (EINVAL);
611			}
612			ifnet_set_mtu(ifp, mtu);
613		}
614		break;
615#endif /* SIOCSIFMTU */
616
617	case SIOCSIFPHYADDR:
618#if INET6
619	case SIOCSIFPHYADDR_IN6_32:
620	case SIOCSIFPHYADDR_IN6_64:
621#endif /* INET6 */
622	case SIOCSLIFPHYADDR:
623		switch (cmd) {
624#if INET
625		case SIOCSIFPHYADDR:
626			src = (struct sockaddr *)
627				&(((struct in_aliasreq *)data)->ifra_addr);
628			dst = (struct sockaddr *)
629				&(((struct in_aliasreq *)data)->ifra_dstaddr);
630			break;
631#endif
632#if INET6
633		case SIOCSIFPHYADDR_IN6_32: {
634			struct in6_aliasreq_32 *ifra_32 =
635			    (struct in6_aliasreq_32 *)data;
636
637			src = (struct sockaddr *)&ifra_32->ifra_addr;
638			dst = (struct sockaddr *)&ifra_32->ifra_dstaddr;
639			break;
640		}
641
642		case SIOCSIFPHYADDR_IN6_64: {
643			struct in6_aliasreq_64 *ifra_64 =
644			    (struct in6_aliasreq_64 *)data;
645
646			src = (struct sockaddr *)&ifra_64->ifra_addr;
647			dst = (struct sockaddr *)&ifra_64->ifra_dstaddr;
648			break;
649		}
650#endif
651		case SIOCSLIFPHYADDR:
652			src = (struct sockaddr *)
653				&(((struct if_laddrreq *)data)->addr);
654			dst = (struct sockaddr *)
655				&(((struct if_laddrreq *)data)->dstaddr);
656		}
657
658		/* sa_family must be equal */
659		if (src->sa_family != dst->sa_family)
660			return EINVAL;
661
662		/* validate sa_len */
663		switch (src->sa_family) {
664#if INET
665		case AF_INET:
666			if (src->sa_len != sizeof(struct sockaddr_in))
667				return EINVAL;
668			break;
669#endif
670#if INET6
671		case AF_INET6:
672			if (src->sa_len != sizeof(struct sockaddr_in6))
673				return EINVAL;
674			break;
675#endif
676		default:
677			return EAFNOSUPPORT;
678		}
679		switch (dst->sa_family) {
680#if INET
681		case AF_INET:
682			if (dst->sa_len != sizeof(struct sockaddr_in))
683				return EINVAL;
684			break;
685#endif
686#if INET6
687		case AF_INET6:
688			if (dst->sa_len != sizeof(struct sockaddr_in6))
689				return EINVAL;
690			break;
691#endif
692		default:
693			return EAFNOSUPPORT;
694		}
695
696		/* check sa_family looks sane for the cmd */
697		switch (cmd) {
698		case SIOCSIFPHYADDR:
699			if (src->sa_family == AF_INET)
700				break;
701			return EAFNOSUPPORT;
702#if INET6
703		case SIOCSIFPHYADDR_IN6_32:
704		case SIOCSIFPHYADDR_IN6_64:
705			if (src->sa_family == AF_INET6)
706				break;
707			return EAFNOSUPPORT;
708#endif /* INET6 */
709		case SIOCSLIFPHYADDR:
710			/* checks done in the above */
711			break;
712		}
713
714		ifnet_head_lock_shared();
715		TAILQ_FOREACH(ifp2, &ifnet_head, if_link) {
716			if (strcmp(ifnet_name(ifp2), GIFNAME) != 0)
717				continue;
718			sc2 = ifnet_softc(ifp2);
719			if (sc2 == sc)
720				continue;
721			if (!sc2->gif_pdst || !sc2->gif_psrc)
722				continue;
723			if (sc2->gif_pdst->sa_family != dst->sa_family ||
724			    sc2->gif_pdst->sa_len != dst->sa_len ||
725			    sc2->gif_psrc->sa_family != src->sa_family ||
726			    sc2->gif_psrc->sa_len != src->sa_len)
727				continue;
728#ifndef XBONEHACK
729			/* can't configure same pair of address onto two gifs */
730			if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
731			    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
732				error = EADDRNOTAVAIL;
733				ifnet_head_done();
734				goto bad;
735			}
736#endif
737
738			/* can't configure multiple multi-dest interfaces */
739#define multidest(x) \
740	(((struct sockaddr_in *)(void *)(x))->sin_addr.s_addr == INADDR_ANY)
741#if INET6
742#define multidest6(x) \
743	(IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(void *)(x))->sin6_addr))
744#endif
745			if (dst->sa_family == AF_INET &&
746			    multidest(dst) && multidest(sc2->gif_pdst)) {
747				error = EADDRNOTAVAIL;
748				ifnet_head_done();
749				goto bad;
750			}
751#if INET6
752			if (dst->sa_family == AF_INET6 &&
753			    multidest6(dst) && multidest6(sc2->gif_pdst)) {
754				error = EADDRNOTAVAIL;
755				ifnet_head_done();
756				goto bad;
757			}
758#endif
759		}
760		ifnet_head_done();
761
762		if (sc->gif_psrc)
763			FREE((caddr_t)sc->gif_psrc, M_IFADDR);
764		sa = (struct sockaddr *)_MALLOC(src->sa_len, M_IFADDR, M_WAITOK);
765		if (sa == NULL)
766			return ENOBUFS;
767		bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
768		sc->gif_psrc = sa;
769
770		if (sc->gif_pdst)
771			FREE((caddr_t)sc->gif_pdst, M_IFADDR);
772		sa = (struct sockaddr *)_MALLOC(dst->sa_len, M_IFADDR, M_WAITOK);
773		if (sa == NULL)
774			return ENOBUFS;
775		bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
776		sc->gif_pdst = sa;
777
778		ifnet_set_flags(ifp, IFF_RUNNING | IFF_UP, IFF_RUNNING | IFF_UP);
779
780		error = 0;
781		break;
782
783#ifdef SIOCDIFPHYADDR
784	case SIOCDIFPHYADDR:
785		if (sc->gif_psrc) {
786			FREE((caddr_t)sc->gif_psrc, M_IFADDR);
787			sc->gif_psrc = NULL;
788		}
789		if (sc->gif_pdst) {
790			FREE((caddr_t)sc->gif_pdst, M_IFADDR);
791			sc->gif_pdst = NULL;
792		}
793		/* change the IFF_{UP, RUNNING} flag as well? */
794		break;
795#endif
796
797	case SIOCGIFPSRCADDR:
798#if INET6
799	case SIOCGIFPSRCADDR_IN6:
800#endif /* INET6 */
801		if (sc->gif_psrc == NULL) {
802			error = EADDRNOTAVAIL;
803			goto bad;
804		}
805		src = sc->gif_psrc;
806		switch (cmd) {
807#if INET
808		case SIOCGIFPSRCADDR:
809			dst = &ifr->ifr_addr;
810			size = sizeof(ifr->ifr_addr);
811			break;
812#endif /* INET */
813#if INET6
814		case SIOCGIFPSRCADDR_IN6:
815			dst = (struct sockaddr *)
816				&(((struct in6_ifreq *)data)->ifr_addr);
817			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
818			break;
819#endif /* INET6 */
820		default:
821			error = EADDRNOTAVAIL;
822			goto bad;
823		}
824		if (src->sa_len > size)
825			return EINVAL;
826		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
827		break;
828
829	case SIOCGIFPDSTADDR:
830#if INET6
831	case SIOCGIFPDSTADDR_IN6:
832#endif /* INET6 */
833		if (sc->gif_pdst == NULL) {
834			error = EADDRNOTAVAIL;
835			goto bad;
836		}
837		src = sc->gif_pdst;
838		switch (cmd) {
839#if INET
840		case SIOCGIFPDSTADDR:
841			dst = &ifr->ifr_addr;
842			size = sizeof(ifr->ifr_addr);
843			break;
844#endif /* INET */
845#if INET6
846		case SIOCGIFPDSTADDR_IN6:
847			dst = (struct sockaddr *)
848				&(((struct in6_ifreq *)data)->ifr_addr);
849			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
850			break;
851#endif /* INET6 */
852		default:
853			error = EADDRNOTAVAIL;
854			goto bad;
855		}
856		if (src->sa_len > size)
857			return EINVAL;
858		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
859		break;
860
861	case SIOCGLIFPHYADDR:
862		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
863			error = EADDRNOTAVAIL;
864			goto bad;
865		}
866
867		/* copy src */
868		src = sc->gif_psrc;
869		dst = (struct sockaddr *)
870			&(((struct if_laddrreq *)data)->addr);
871		size = sizeof(((struct if_laddrreq *)data)->addr);
872		if (src->sa_len > size)
873			return EINVAL;
874		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
875
876		/* copy dst */
877		src = sc->gif_pdst;
878		dst = (struct sockaddr *)
879			&(((struct if_laddrreq *)data)->dstaddr);
880		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
881		if (src->sa_len > size)
882			return EINVAL;
883		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
884		break;
885
886	case SIOCSIFFLAGS:
887		/* if_ioctl() takes care of it */
888		break;
889
890	default:
891		error = EOPNOTSUPP;
892		break;
893	}
894 bad:
895	return error;
896}
897
898/* This function is not used in our stack */
899void
900gif_delete_tunnel(sc)
901	struct gif_softc *sc;
902{
903	/* XXX: NetBSD protects this function with splsoftnet() */
904
905	if (sc->gif_psrc) {
906		FREE((caddr_t)sc->gif_psrc, M_IFADDR);
907		sc->gif_psrc = NULL;
908	}
909	if (sc->gif_pdst) {
910		FREE((caddr_t)sc->gif_pdst, M_IFADDR);
911		sc->gif_pdst = NULL;
912	}
913	/* change the IFF_UP flag as well? */
914}
915