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