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