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