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