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