]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/if_gif.c
xnu-1699.22.73.tar.gz
[apple/xnu.git] / bsd / net / if_gif.c
CommitLineData
1c79356b 1/*
b0d623f7 2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
9bccf70c
A
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 $ */
1c79356b
A
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 */
2d21ac55
A
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 */
1c79356b 65
1c79356b
A
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>
9bccf70c 76#include <sys/protosw.h>
1c79356b
A
77#include <kern/cpu_number.h>
78
79#include <net/if.h>
80#include <net/if_types.h>
1c79356b
A
81#include <net/route.h>
82#include <net/bpf.h>
2d21ac55
A
83#include <net/kpi_protocol.h>
84#include <net/kpi_interface.h>
1c79356b 85
1c79356b
A
86#include <netinet/in.h>
87#include <netinet/in_systm.h>
1c79356b 88#include <netinet/ip.h>
9bccf70c
A
89#if INET
90#include <netinet/in_var.h>
1c79356b 91#include <netinet/in_gif.h>
9bccf70c 92#include <netinet/ip_var.h>
1c79356b
A
93#endif /* INET */
94
95#if INET6
1c79356b
A
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
1c79356b
A
107#include <net/net_osdep.h>
108
2d21ac55
A
109#if CONFIG_MACF_NET
110#include <security/mac_framework.h>
111#endif
112
9bccf70c
A
113#define GIFNAME "gif"
114#define GIFDEV "if_gif"
115#define GIF_MAXUNIT 0x7fff /* ifp->if_unit is only 15 bits */
1c79356b 116
9bccf70c
A
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__
91447636 124void gifattach(void);
9bccf70c 125static int gif_encapcheck(const struct mbuf*, int, int, void*);
2d21ac55
A
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);
b0d623f7 129static errno_t gif_ioctl(ifnet_t ifp, u_long cmd, void *data);
9bccf70c
A
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,
91447636 139 0, 0, 0, 0,
9bccf70c 140 0,
91447636 141 &rip_usrreqs,
2d21ac55 142 0, rip_unlock, 0, {0, 0}, 0, {0}
9bccf70c
A
143};
144#endif
145#if INET6
146struct ip6protosw in6_gif_protosw =
147{ SOCK_RAW, 0, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR,
91447636 148 in6_gif_input, 0, 0, 0,
9bccf70c
A
149 0,
150 0, 0, 0, 0,
91447636
A
151 0,
152 &rip6_usrreqs,
2d21ac55 153 0, rip_unlock, 0, {0, 0}, 0, {0}
91447636 154
9bccf70c
A
155};
156#endif
1c79356b 157
6d2010ae
A
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
9bccf70c
A
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 */
2d21ac55
A
175static int gif_demux(
176 ifnet_t ifp,
177 __unused mbuf_t m,
178 __unused char *frame_header,
179 protocol_family_t *protocol_family)
1c79356b 180{
9bccf70c 181 /* Only one protocol may be attached to a gif interface. */
2d21ac55 182 *protocol_family = ((struct gif_softc*)ifnet_softc(ifp))->gif_proto;
9bccf70c
A
183
184 return 0;
1c79356b
A
185}
186
2d21ac55
A
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)
9bccf70c
A
193{
194 /* Only one protocol may be attached at a time */
2d21ac55 195 struct gif_softc* gif = ifnet_softc(ifp);
1c79356b 196
91447636 197 if (gif->gif_proto != 0)
2d21ac55 198 printf("gif_add_proto: request add_proto for gif%d\n", ifnet_unit(ifp));
1c79356b 199
91447636 200 gif->gif_proto = protocol_family;
1c79356b 201
9bccf70c 202 return 0;
1c79356b
A
203}
204
2d21ac55
A
205static errno_t
206gif_del_proto(
207 ifnet_t ifp,
208 protocol_family_t protocol_family)
9bccf70c 209{
2d21ac55
A
210 if (((struct gif_softc*)ifnet_softc(ifp))->gif_proto == protocol_family)
211 ((struct gif_softc*)ifnet_softc(ifp))->gif_proto = 0;
212
9bccf70c 213 return 0;
1c79356b
A
214}
215
9bccf70c 216/* Glue code to attach inet to a gif interface through DLIL */
2d21ac55 217static errno_t
91447636 218gif_attach_proto_family(
2d21ac55
A
219 ifnet_t ifp,
220 protocol_family_t protocol_family)
1c79356b 221{
2d21ac55
A
222 struct ifnet_attach_proto_param reg;
223 errno_t stat;
9bccf70c 224
91447636 225 bzero(&reg, sizeof(reg));
1c79356b 226 reg.input = gif_input;
1c79356b 227
2d21ac55 228 stat = ifnet_attach_protocol(ifp, protocol_family, &reg);
91447636 229 if (stat && stat != EEXIST) {
2d21ac55
A
230 printf("gif_attach_proto_family can't attach interface fam=%d\n",
231 protocol_family);
9bccf70c 232 }
55e303ae 233
91447636 234 return stat;
55e303ae
A
235}
236
9bccf70c
A
237#endif
238
239/* Function to setup the first gif interface */
2d21ac55 240__private_extern__ void
9bccf70c 241gifattach(void)
1c79356b 242{
2d21ac55 243 errno_t result;
6d2010ae
A
244 struct ifnet_clone_params ifnet_clone_params;
245 struct if_clone *ifc = NULL;
55e303ae 246
9bccf70c
A
247 /* Init the list of interfaces */
248 TAILQ_INIT(&gifs);
1c79356b 249
55e303ae 250 /* Register protocol registration functions */
2d21ac55
A
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);
55e303ae 255
2d21ac55
A
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);
55e303ae 260
6d2010ae
A
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
9bccf70c 269 /* Create first device */
6d2010ae
A
270 ifc = if_clone_lookup("gif", NULL);
271 gif_clone_create(ifc, 0, NULL);
9bccf70c
A
272}
273
2d21ac55
A
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
6d2010ae
A
288
289static int
290gif_clone_create(struct if_clone *ifc, uint32_t unit, __unused void *params)
9bccf70c 291{
6d2010ae
A
292 struct gif_softc *sc = NULL;
293 struct ifnet_init_params gif_init;
294 errno_t result = 0;
295
9bccf70c
A
296 /* Can't create more than GIF_MAXUNIT */
297 if (ngif >= GIF_MAXUNIT)
6d2010ae 298 return (ENXIO);
9bccf70c
A
299
300 sc = _MALLOC(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK);
301 if (sc == NULL) {
6d2010ae
A
302 log(LOG_ERR, "gif_clone_create: failed to allocate gif%d\n", unit);
303 return ENOBUFS;
9bccf70c 304 }
6d2010ae
A
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
2d21ac55 311 bzero(&gif_init, sizeof(gif_init));
6d2010ae
A
312 gif_init.uniqueid = sc->gif_ifname;
313 gif_init.uniqueid_len = strlen(sc->gif_ifname);
2d21ac55 314 gif_init.name = GIFNAME;
6d2010ae 315 gif_init.unit = unit;
2d21ac55
A
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;
9bccf70c 325
2d21ac55
A
326 result = ifnet_allocate(&gif_init, &sc->gif_if);
327 if (result != 0) {
6d2010ae 328 printf("gif_clone_create, ifnet_allocate failed - %d\n", result);
2d21ac55 329 _FREE(sc, M_DEVBUF);
6d2010ae 330 return ENOBUFS;
2d21ac55 331 }
6d2010ae 332
9bccf70c 333 sc->encap_cookie4 = sc->encap_cookie6 = NULL;
2d21ac55 334#if INET
9bccf70c 335 sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
6d2010ae 336 gif_encapcheck, &in_gif_protosw, sc);
9bccf70c 337 if (sc->encap_cookie4 == NULL) {
2d21ac55
A
338 printf("%s: unable to attach encap4\n", if_name(sc->gif_if));
339 ifnet_release(sc->gif_if);
9bccf70c 340 FREE(sc, M_DEVBUF);
6d2010ae 341 return ENOBUFS;
9bccf70c
A
342 }
343#endif
2d21ac55 344#if INET6
9bccf70c
A
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 }
2d21ac55
A
352 printf("%s: unable to attach encap6\n", if_name(sc->gif_if));
353 ifnet_release(sc->gif_if);
9bccf70c 354 FREE(sc, M_DEVBUF);
6d2010ae 355 return ENOBUFS;
9bccf70c
A
356 }
357#endif
91447636 358 sc->gif_called = 0;
2d21ac55
A
359 ifnet_set_mtu(sc->gif_if, GIF_MTU);
360 ifnet_set_flags(sc->gif_if, IFF_POINTOPOINT | IFF_MULTICAST, 0xffff);
1c79356b 361#if 0
9bccf70c
A
362 /* turn off ingress filter */
363 sc->gif_if.if_flags |= IFF_LINK2;
1c79356b 364#endif
2d21ac55
A
365 result = ifnet_attach(sc->gif_if, NULL);
366 if (result != 0) {
6d2010ae 367 printf("gif_clone_create - ifnet_attach failed - %d\n", result);
2d21ac55 368 ifnet_release(sc->gif_if);
6d2010ae
A
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 }
2d21ac55 377 FREE(sc, M_DEVBUF);
6d2010ae 378 return result;
2d21ac55
A
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));
9bccf70c
A
384 TAILQ_INSERT_TAIL(&gifs, sc, gif_link);
385 ngif++;
6d2010ae
A
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;
9bccf70c
A
423}
424
425static int
2d21ac55
A
426gif_encapcheck(
427 const struct mbuf *m,
428 int off,
429 int proto,
430 void *arg)
9bccf70c
A
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
2d21ac55 439 if ((ifnet_flags(sc->gif_if) & IFF_UP) == 0)
9bccf70c
A
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;
1c79356b 450#endif
9bccf70c
A
451#if INET6
452 case IPPROTO_IPV6:
453 break;
1c79356b 454#endif
9bccf70c
A
455 default:
456 return 0;
1c79356b 457 }
1c79356b 458
b0d623f7 459 mbuf_copydata((struct mbuf *)(size_t)m, 0, sizeof(ip), &ip);
9bccf70c
A
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);
1c79356b 475#endif
9bccf70c
A
476 default:
477 return 0;
478 }
479}
1c79356b 480
2d21ac55
A
481static errno_t
482gif_output(
483 ifnet_t ifp,
484 mbuf_t m)
1c79356b 485{
2d21ac55 486 struct gif_softc *sc = ifnet_softc(ifp);
1c79356b 487 int error = 0;
91447636 488
1c79356b 489 /*
2d21ac55
A
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.
1c79356b 493 */
2d21ac55 494
1c79356b 495 m->m_flags &= ~(M_BCAST|M_MCAST);
2d21ac55 496 if (!(ifnet_flags(ifp) & IFF_UP) ||
1c79356b 497 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
2d21ac55 498 ifnet_touch_lastchange(ifp);
55e303ae 499 m_freem(m); /* free it here not in dlil_output */
1c79356b 500 error = ENETDOWN;
1c79356b
A
501 goto end;
502 }
503
2d21ac55
A
504 bpf_tap_out(ifp, 0, m, &sc->gif_proto, sizeof(sc->gif_proto));
505
9bccf70c
A
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 */
1c79356b
A
511 switch (sc->gif_psrc->sa_family) {
512#if INET
513 case AF_INET:
2d21ac55 514 error = in_gif_output(ifp, sc->gif_proto, m, NULL);
1c79356b
A
515 break;
516#endif
517#if INET6
518 case AF_INET6:
2d21ac55 519 error = in6_gif_output(ifp, sc->gif_proto, m, NULL);
1c79356b
A
520 break;
521#endif
522 default:
1c79356b 523 error = ENETDOWN;
9bccf70c 524 goto end;
1c79356b 525 }
1c79356b
A
526
527 end:
55e303ae
A
528 if (error) {
529 /* the mbuf was freed either by in_gif_output or in here */
2d21ac55
A
530 ifnet_stat_increment_out(ifp, 0, 0, 1);
531 }
532 else {
533 ifnet_stat_increment_out(ifp, 1, m->m_pkthdr.len, 0);
55e303ae 534 }
9bccf70c
A
535 if (error == 0)
536 error = EJUSTRETURN; /* if no error, packet got sent already */
537 return error;
1c79356b
A
538}
539
2d21ac55
A
540/*
541 * gif_input is the input handler for IP and IPv6 attached to gif
542 */
543static errno_t
91447636 544gif_input(
2d21ac55
A
545 ifnet_t ifp,
546 protocol_family_t protocol_family,
547 mbuf_t m,
548 __unused char *frame_header)
1c79356b 549{
2d21ac55 550 struct gif_softc *sc = ifnet_softc(ifp);
1c79356b 551
2d21ac55 552 bpf_tap_in(ifp, 0, m, &sc->gif_proto, sizeof(sc->gif_proto));
1c79356b
A
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 */
6d2010ae
A
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);
1c79356b 571
9bccf70c 572 return (0);
1c79356b
A
573}
574
575/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
2d21ac55
A
576static errno_t
577gif_ioctl(
578 ifnet_t ifp,
b0d623f7 579 u_long cmd,
2d21ac55 580 void *data)
1c79356b 581{
2d21ac55 582 struct gif_softc *sc = ifnet_softc(ifp);
1c79356b
A
583 struct ifreq *ifr = (struct ifreq*)data;
584 int error = 0, size;
2d21ac55 585 struct sockaddr *dst = NULL, *src = NULL;
9bccf70c 586 struct sockaddr *sa;
9bccf70c 587 struct ifnet *ifp2;
1c79356b 588 struct gif_softc *sc2;
b0d623f7 589
1c79356b
A
590 switch (cmd) {
591 case SIOCSIFADDR:
592 break;
b0d623f7 593
1c79356b
A
594 case SIOCSIFDSTADDR:
595 break;
596
597 case SIOCADDMULTI:
598 case SIOCDELMULTI:
1c79356b
A
599 break;
600
601#ifdef SIOCSIFMTU /* xxx */
1c79356b
A
602 case SIOCGIFMTU:
603 break;
9bccf70c 604
1c79356b
A
605 case SIOCSIFMTU:
606 {
b0d623f7 607 u_int32_t mtu;
1c79356b 608 mtu = ifr->ifr_mtu;
1c79356b
A
609 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
610 return (EINVAL);
611 }
2d21ac55 612 ifnet_set_mtu(ifp, mtu);
1c79356b
A
613 }
614 break;
1c79356b
A
615#endif /* SIOCSIFMTU */
616
617 case SIOCSIFPHYADDR:
618#if INET6
b0d623f7
A
619 case SIOCSIFPHYADDR_IN6_32:
620 case SIOCSIFPHYADDR_IN6_64:
1c79356b 621#endif /* INET6 */
9bccf70c
A
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
b0d623f7
A
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;
9bccf70c 639 break;
b0d623f7
A
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 }
9bccf70c
A
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
b0d623f7
A
703 case SIOCSIFPHYADDR_IN6_32:
704 case SIOCSIFPHYADDR_IN6_64:
9bccf70c
A
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
91447636
A
714 ifnet_head_lock_shared();
715 TAILQ_FOREACH(ifp2, &ifnet_head, if_link) {
2d21ac55 716 if (strcmp(ifnet_name(ifp2), GIFNAME) != 0)
9bccf70c 717 continue;
2d21ac55 718 sc2 = ifnet_softc(ifp2);
1c79356b
A
719 if (sc2 == sc)
720 continue;
721 if (!sc2->gif_pdst || !sc2->gif_psrc)
722 continue;
9bccf70c
A
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 &&
1c79356b
A
731 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
732 error = EADDRNOTAVAIL;
91447636 733 ifnet_head_done();
1c79356b
A
734 goto bad;
735 }
9bccf70c 736#endif
1c79356b 737
9bccf70c
A
738 /* can't configure multiple multi-dest interfaces */
739#define multidest(x) \
740 (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
1c79356b 741#if INET6
9bccf70c
A
742#define multidest6(x) \
743 (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
744#endif
745 if (dst->sa_family == AF_INET &&
746 multidest(dst) && multidest(sc2->gif_pdst)) {
747 error = EADDRNOTAVAIL;
91447636 748 ifnet_head_done();
9bccf70c
A
749 goto bad;
750 }
751#if INET6
752 if (dst->sa_family == AF_INET6 &&
753 multidest6(dst) && multidest6(sc2->gif_pdst)) {
754 error = EADDRNOTAVAIL;
91447636 755 ifnet_head_done();
9bccf70c
A
756 goto bad;
757 }
758#endif
1c79356b 759 }
91447636 760 ifnet_head_done();
9bccf70c
A
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);
b0d623f7
A
765 if (sa == NULL)
766 return ENOBUFS;
9bccf70c
A
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);
b0d623f7
A
773 if (sa == NULL)
774 return ENOBUFS;
9bccf70c
A
775 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
776 sc->gif_pdst = sa;
777
2d21ac55
A
778 ifnet_set_flags(ifp, IFF_RUNNING | IFF_UP, IFF_RUNNING | IFF_UP);
779
9bccf70c 780 error = 0;
1c79356b 781 break;
9bccf70c
A
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
1c79356b
A
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;
9bccf70c 806 switch (cmd) {
1c79356b 807#if INET
9bccf70c 808 case SIOCGIFPSRCADDR:
1c79356b 809 dst = &ifr->ifr_addr;
9bccf70c 810 size = sizeof(ifr->ifr_addr);
1c79356b
A
811 break;
812#endif /* INET */
813#if INET6
9bccf70c 814 case SIOCGIFPSRCADDR_IN6:
1c79356b
A
815 dst = (struct sockaddr *)
816 &(((struct in6_ifreq *)data)->ifr_addr);
9bccf70c 817 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
1c79356b
A
818 break;
819#endif /* INET6 */
820 default:
821 error = EADDRNOTAVAIL;
822 goto bad;
823 }
9bccf70c
A
824 if (src->sa_len > size)
825 return EINVAL;
826 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
1c79356b
A
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;
9bccf70c 838 switch (cmd) {
1c79356b 839#if INET
9bccf70c 840 case SIOCGIFPDSTADDR:
1c79356b 841 dst = &ifr->ifr_addr;
9bccf70c 842 size = sizeof(ifr->ifr_addr);
1c79356b
A
843 break;
844#endif /* INET */
845#if INET6
9bccf70c 846 case SIOCGIFPDSTADDR_IN6:
1c79356b
A
847 dst = (struct sockaddr *)
848 &(((struct in6_ifreq *)data)->ifr_addr);
9bccf70c 849 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
1c79356b
A
850 break;
851#endif /* INET6 */
852 default:
853 error = EADDRNOTAVAIL;
854 goto bad;
855 }
9bccf70c
A
856 if (src->sa_len > size)
857 return EINVAL;
858 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
1c79356b
A
859 break;
860
9bccf70c
A
861 case SIOCGLIFPHYADDR:
862 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
863 error = EADDRNOTAVAIL;
1c79356b 864 goto bad;
1c79356b 865 }
9bccf70c
A
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 */
1c79356b
A
888 break;
889
890 default:
9bccf70c 891 error = EOPNOTSUPP;
1c79356b
A
892 break;
893 }
894 bad:
895 return error;
896}
9bccf70c 897
91447636 898/* This function is not used in our stack */
9bccf70c
A
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}