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);
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 kfree_type(struct gif_softc, 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 = kalloc_type(struct gif_softc, Z_WAITOK_ZERO_NOFAIL);
321
322 /* use the interface name as the unique id for ifp recycle */
323 snprintf(sc->gif_ifname, sizeof(sc->gif_ifname), "%s%d",
324 ifc->ifc_name, unit);
325
326 lck_mtx_init(&sc->gif_lock, &gif_mtx_grp, &gif_mtx_attr);
327
328 bzero(&gif_init_params, sizeof(gif_init_params));
329 gif_init_params.ver = IFNET_INIT_CURRENT_VERSION;
330 gif_init_params.len = sizeof(gif_init_params);
331 gif_init_params.flags = IFNET_INIT_LEGACY;
332 gif_init_params.uniqueid = sc->gif_ifname;
333 gif_init_params.uniqueid_len = strlen(sc->gif_ifname);
334 gif_init_params.name = GIFNAME;
335 gif_init_params.unit = unit;
336 gif_init_params.type = IFT_GIF;
337 gif_init_params.family = IFNET_FAMILY_GIF;
338 gif_init_params.output = gif_output;
339 gif_init_params.demux = gif_demux;
340 gif_init_params.add_proto = gif_add_proto;
341 gif_init_params.del_proto = gif_del_proto;
342 gif_init_params.softc = sc;
343 gif_init_params.ioctl = gif_ioctl;
344 gif_init_params.set_bpf_tap = gif_set_bpf_tap;
345 gif_init_params.detach = gif_detach;
346
347 error = ifnet_allocate_extended(&gif_init_params, &sc->gif_if);
348 if (error != 0) {
349 printf("gif_clone_create, ifnet_allocate failed - %d\n", error);
350 kfree_type(struct gif_softc, sc);
351 error = ENOBUFS;
352 goto done;
353 }
354
355 sc->encap_cookie4 = sc->encap_cookie6 = NULL;
356 #if INET
357 sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
358 gif_encapcheck, &in_gif_protosw, sc);
359 if (sc->encap_cookie4 == NULL) {
360 printf("%s: unable to attach encap4\n", if_name(sc->gif_if));
361 ifnet_release(sc->gif_if);
362 kfree_type(struct gif_softc, sc);
363 error = ENOBUFS;
364 goto done;
365 }
366 #endif
367 sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
368 gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc);
369 if (sc->encap_cookie6 == NULL) {
370 if (sc->encap_cookie4) {
371 encap_detach(sc->encap_cookie4);
372 sc->encap_cookie4 = NULL;
373 }
374 printf("%s: unable to attach encap6\n", if_name(sc->gif_if));
375 ifnet_release(sc->gif_if);
376 kfree_type(struct gif_softc, sc);
377 error = ENOBUFS;
378 goto done;
379 }
380 sc->gif_called = 0;
381 ifnet_set_mtu(sc->gif_if, GIF_MTU);
382 ifnet_set_flags(sc->gif_if, IFF_POINTOPOINT | IFF_MULTICAST, 0xffff);
383 sc->gif_flags |= IFGIF_DETACHING;
384 error = ifnet_attach(sc->gif_if, NULL);
385 if (error != 0) {
386 printf("gif_clone_create - ifnet_attach failed - %d\n", error);
387 ifnet_release(sc->gif_if);
388 if (sc->encap_cookie4) {
389 encap_detach(sc->encap_cookie4);
390 sc->encap_cookie4 = NULL;
391 }
392 if (sc->encap_cookie6) {
393 encap_detach(sc->encap_cookie6);
394 sc->encap_cookie6 = NULL;
395 }
396 kfree_type(struct gif_softc, sc);
397 goto done;
398 }
399 bpfattach(sc->gif_if, DLT_NULL, sizeof(u_int));
400 sc->gif_flags &= ~IFGIF_DETACHING;
401 TAILQ_INSERT_TAIL(&gifs, sc, gif_link);
402 ngif++;
403 done:
404 lck_mtx_unlock(&gif_mtx);
405
406 return error;
407 }
408
409 static int
gif_remove(struct ifnet * ifp)410 gif_remove(struct ifnet *ifp)
411 {
412 int error = 0;
413 struct gif_softc *sc = NULL;
414 const struct encaptab *encap_cookie4 = NULL;
415 const struct encaptab *encap_cookie6 = NULL;
416
417 lck_mtx_lock(&gif_mtx);
418 sc = ifp->if_softc;
419
420 if (sc == NULL) {
421 error = EINVAL;
422 goto done;
423 }
424
425 GIF_LOCK(sc);
426 if (sc->gif_flags & IFGIF_DETACHING) {
427 error = EINVAL;
428 goto done;
429 }
430
431 sc->gif_flags |= IFGIF_DETACHING;
432 TAILQ_REMOVE(&gifs, sc, gif_link);
433 ngif--;
434
435 gif_delete_tunnel(sc);
436 encap_cookie6 = sc->encap_cookie6;
437 #ifdef INET
438 encap_cookie4 = sc->encap_cookie4;
439 #endif
440 done:
441 if (sc != NULL) {
442 GIF_UNLOCK(sc);
443 }
444 lck_mtx_unlock(&gif_mtx);
445
446 if (encap_cookie6 != NULL) {
447 error = encap_detach(encap_cookie6);
448 KASSERT(error == 0, ("gif_clone_destroy: Unexpected "
449 "error detaching encap_cookie6"));
450 }
451
452 if (encap_cookie4 != NULL) {
453 error = encap_detach(encap_cookie4);
454 KASSERT(error == 0, ("gif_clone_destroy: Unexpected "
455 "error detaching encap_cookie4"));
456 }
457
458 return error;
459 }
460
461 static int
gif_clone_destroy(struct ifnet * ifp)462 gif_clone_destroy(struct ifnet *ifp)
463 {
464 int error = 0;
465
466 error = gif_remove(ifp);
467 if (error != 0) {
468 printf("gif_clone_destroy: gif remove failed %d\n", error);
469 return error;
470 }
471
472 error = ifnet_set_flags(ifp, 0, IFF_UP);
473 if (error != 0) {
474 printf("gif_clone_destroy: ifnet_set_flags failed %d\n", error);
475 }
476
477 error = ifnet_detach(ifp);
478 if (error != 0) {
479 panic("gif_clone_destroy: ifnet_detach(%p) failed %d", ifp,
480 error);
481 }
482 return 0;
483 }
484
485 static int
gif_encapcheck(const struct mbuf * m,int off,int proto,void * arg)486 gif_encapcheck(
487 const struct mbuf *m,
488 int off,
489 int proto,
490 void *arg)
491 {
492 int error = 0;
493 struct ip ip;
494 struct gif_softc *sc;
495
496 sc = (struct gif_softc *)arg;
497 if (sc == NULL) {
498 return error;
499 }
500
501 GIF_LOCK(sc);
502 if ((ifnet_flags(sc->gif_if) & IFF_UP) == 0) {
503 goto done;
504 }
505
506 /* no physical address */
507 if (!sc->gif_psrc || !sc->gif_pdst) {
508 goto done;
509 }
510
511 switch (proto) {
512 #if INET
513 case IPPROTO_IPV4:
514 break;
515 #endif
516 case IPPROTO_IPV6:
517 break;
518 default:
519 goto done;
520 }
521
522 mbuf_copydata((struct mbuf *)(size_t)m, 0, sizeof(ip), &ip);
523
524 switch (ip.ip_v) {
525 #if INET
526 case 4:
527 if (sc->gif_psrc->sa_family != AF_INET ||
528 sc->gif_pdst->sa_family != AF_INET) {
529 goto done;
530 }
531 error = gif_encapcheck4(m, off, proto, arg);
532 #endif
533 OS_FALLTHROUGH;
534 case 6:
535 if (sc->gif_psrc->sa_family != AF_INET6 ||
536 sc->gif_pdst->sa_family != AF_INET6) {
537 goto done;
538 }
539 error = gif_encapcheck6(m, off, proto, arg);
540 OS_FALLTHROUGH;
541 default:
542 goto done;
543 }
544 done:
545 GIF_UNLOCK(sc);
546 return error;
547 }
548
549 static errno_t
gif_output(ifnet_t ifp,mbuf_t m)550 gif_output(
551 ifnet_t ifp,
552 mbuf_t m)
553 {
554 struct gif_softc *sc = ifnet_softc(ifp);
555 struct sockaddr *gif_psrc;
556 struct sockaddr *gif_pdst;
557 int error = 0;
558
559 GIF_LOCK(sc);
560 gif_psrc = sc->gif_psrc;
561 gif_pdst = sc->gif_pdst;
562 GIF_UNLOCK(sc);
563
564 /*
565 * max_gif_nesting check used to live here. It doesn't anymore
566 * because there is no guaruntee that we won't be called
567 * concurrently from more than one thread.
568 */
569 m->m_flags &= ~(M_BCAST | M_MCAST);
570 if (!(ifnet_flags(ifp) & IFF_UP) ||
571 gif_psrc == NULL || gif_pdst == NULL) {
572 ifnet_touch_lastchange(ifp);
573 m_freem(m); /* free it here not in dlil_output */
574 error = ENETDOWN;
575 goto end;
576 }
577
578 bpf_tap_out(ifp, 0, m, &sc->gif_proto, sizeof(sc->gif_proto));
579
580 GIF_LOCK(sc);
581
582 /* inner AF-specific encapsulation */
583
584 /* XXX should we check if our outer source is legal? */
585
586 /*
587 * Save the length as m may be free by the output functions
588 * as they call m_pullup
589 */
590 u_int32_t bytes_out = m->m_pkthdr.len;
591
592 /* dispatch to output logic based on outer AF */
593 switch (sc->gif_psrc->sa_family) {
594 #if INET
595 case AF_INET:
596 error = in_gif_output(ifp, sc->gif_proto, m, NULL);
597 break;
598 #endif
599 case AF_INET6:
600 error = in6_gif_output(ifp, sc->gif_proto, m, NULL);
601 break;
602 default:
603 error = ENETDOWN;
604 break;
605 }
606
607 GIF_UNLOCK(sc);
608 end:
609 if (error) {
610 /* the mbuf was freed either by in_gif_output or in here */
611 ifnet_stat_increment_out(ifp, 0, 0, 1);
612 } else {
613 ifnet_stat_increment_out(ifp, 1, bytes_out, 0);
614 }
615 if (error == 0) {
616 error = EJUSTRETURN; /* if no error, packet got sent already */
617 }
618 return error;
619 }
620
621 /*
622 * gif_input is the input handler for IP and IPv6 attached to gif
623 */
624 static errno_t
gif_input(ifnet_t ifp,protocol_family_t protocol_family,mbuf_t m,__unused char * frame_header)625 gif_input(
626 ifnet_t ifp,
627 protocol_family_t protocol_family,
628 mbuf_t m,
629 __unused char *frame_header)
630 {
631 struct gif_softc *sc = ifnet_softc(ifp);
632
633 bpf_tap_in(ifp, 0, m, &sc->gif_proto, sizeof(sc->gif_proto));
634
635 /*
636 * Put the packet to the network layer input queue according to the
637 * specified address family.
638 * Note: older versions of gif_input directly called network layer
639 * input functions, e.g. ip6_input, here. We changed the policy to
640 * prevent too many recursive calls of such input functions, which
641 * might cause kernel panic. But the change may introduce another
642 * problem; if the input queue is full, packets are discarded.
643 * We believed it rarely occurs and changed the policy. If we find
644 * it occurs more times than we thought, we may change the policy
645 * again.
646 */
647 int32_t pktlen = m->m_pkthdr.len;
648 if (proto_input(protocol_family, m) != 0) {
649 ifnet_stat_increment_in(ifp, 0, 0, 1);
650 m_freem(m);
651 } else {
652 ifnet_stat_increment_in(ifp, 1, pktlen, 0);
653 }
654
655 return 0;
656 }
657
658 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
659 static errno_t
gif_ioctl(ifnet_t ifp,u_long cmd,void * data)660 gif_ioctl(
661 ifnet_t ifp,
662 u_long cmd,
663 void *data)
664 {
665 struct gif_softc *sc = ifnet_softc(ifp);
666 struct ifreq *ifr = (struct ifreq *)data;
667 int error = 0, size;
668 struct sockaddr *dst = NULL, *src = NULL;
669 struct sockaddr *sa;
670 struct ifnet *ifp2;
671 struct gif_softc *sc2;
672
673 switch (cmd) {
674 case SIOCSIFADDR:
675 break;
676
677 case SIOCSIFDSTADDR:
678 break;
679
680 case SIOCADDMULTI:
681 case SIOCDELMULTI:
682 break;
683
684 #ifdef SIOCSIFMTU /* xxx */
685 case SIOCGIFMTU:
686 break;
687
688 case SIOCSIFMTU:
689 {
690 u_int32_t mtu;
691 mtu = ifr->ifr_mtu;
692 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
693 return EINVAL;
694 }
695 ifnet_set_mtu(ifp, mtu);
696 }
697 break;
698 #endif /* SIOCSIFMTU */
699
700 case SIOCSIFPHYADDR:
701 case SIOCSIFPHYADDR_IN6_32:
702 case SIOCSIFPHYADDR_IN6_64:
703 switch (cmd) {
704 #if INET
705 case SIOCSIFPHYADDR:
706 src = (struct sockaddr *)
707 &(((struct in_aliasreq *)data)->ifra_addr);
708 dst = (struct sockaddr *)
709 &(((struct in_aliasreq *)data)->ifra_dstaddr);
710 break;
711 #endif
712 case SIOCSIFPHYADDR_IN6_32: {
713 struct in6_aliasreq_32 *ifra_32 =
714 (struct in6_aliasreq_32 *)data;
715
716 src = (struct sockaddr *)&ifra_32->ifra_addr;
717 dst = (struct sockaddr *)&ifra_32->ifra_dstaddr;
718 break;
719 }
720
721 case SIOCSIFPHYADDR_IN6_64: {
722 struct in6_aliasreq_64 *ifra_64 =
723 (struct in6_aliasreq_64 *)data;
724
725 src = (struct sockaddr *)&ifra_64->ifra_addr;
726 dst = (struct sockaddr *)&ifra_64->ifra_dstaddr;
727 break;
728 }
729 }
730
731 /* sa_family must be equal */
732 if (src->sa_family != dst->sa_family) {
733 return EINVAL;
734 }
735
736 /* validate sa_len */
737 switch (src->sa_family) {
738 #if INET
739 case AF_INET:
740 if (src->sa_len != sizeof(struct sockaddr_in)) {
741 return EINVAL;
742 }
743 break;
744 #endif
745 case AF_INET6:
746 if (src->sa_len != sizeof(struct sockaddr_in6)) {
747 return EINVAL;
748 }
749 break;
750 default:
751 return EAFNOSUPPORT;
752 }
753 switch (dst->sa_family) {
754 #if INET
755 case AF_INET:
756 if (dst->sa_len != sizeof(struct sockaddr_in)) {
757 return EINVAL;
758 }
759 break;
760 #endif
761 case AF_INET6:
762 if (dst->sa_len != sizeof(struct sockaddr_in6)) {
763 return EINVAL;
764 }
765 break;
766 default:
767 return EAFNOSUPPORT;
768 }
769
770 /* check sa_family looks sane for the cmd */
771 switch (cmd) {
772 case SIOCSIFPHYADDR:
773 if (src->sa_family == AF_INET) {
774 break;
775 }
776 return EAFNOSUPPORT;
777 case SIOCSIFPHYADDR_IN6_32:
778 case SIOCSIFPHYADDR_IN6_64:
779 if (src->sa_family == AF_INET6) {
780 break;
781 }
782 return EAFNOSUPPORT;
783 }
784
785 #define GIF_ORDERED_LOCK(sc, sc2) \
786 if (sc < sc2) { \
787 GIF_LOCK(sc); \
788 GIF_LOCK(sc2); \
789 } else { \
790 GIF_LOCK(sc2); \
791 GIF_LOCK(sc); \
792 }
793
794 #define GIF_ORDERED_UNLOCK(sc, sc2) \
795 if (sc > sc2) { \
796 GIF_UNLOCK(sc); \
797 GIF_UNLOCK(sc2); \
798 } else { \
799 GIF_UNLOCK(sc2); \
800 GIF_UNLOCK(sc); \
801 }
802
803 ifnet_head_lock_shared();
804 TAILQ_FOREACH(ifp2, &ifnet_head, if_link) {
805 if (strcmp(ifnet_name(ifp2), GIFNAME) != 0) {
806 continue;
807 }
808 sc2 = ifnet_softc(ifp2);
809 if (sc2 == sc) {
810 continue;
811 }
812 /* lock sc and sc2 in increasing order of ifnet index */
813 GIF_ORDERED_LOCK(sc, sc2);
814 if (!sc2->gif_pdst || !sc2->gif_psrc) {
815 GIF_ORDERED_UNLOCK(sc, sc2);
816 continue;
817 }
818 if (sc2->gif_pdst->sa_family != dst->sa_family ||
819 sc2->gif_pdst->sa_len != dst->sa_len ||
820 sc2->gif_psrc->sa_family != src->sa_family ||
821 sc2->gif_psrc->sa_len != src->sa_len) {
822 GIF_ORDERED_UNLOCK(sc, sc2);
823 continue;
824 }
825 #ifndef XBONEHACK
826 /* can't configure same pair of address onto two gifs */
827 if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
828 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
829 GIF_ORDERED_UNLOCK(sc, sc2);
830 error = EADDRNOTAVAIL;
831 ifnet_head_done();
832 goto bad;
833 }
834 #endif
835
836 /* can't configure multiple multi-dest interfaces */
837 #define multidest(x) \
838 (((struct sockaddr_in *)(void *)(x))->sin_addr.s_addr == INADDR_ANY)
839 #define multidest6(x) \
840 (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) \
841 (void *)(x))->sin6_addr))
842 if (dst->sa_family == AF_INET &&
843 multidest(dst) && multidest(sc2->gif_pdst)) {
844 GIF_ORDERED_UNLOCK(sc, sc2);
845 error = EADDRNOTAVAIL;
846 ifnet_head_done();
847 goto bad;
848 }
849 if (dst->sa_family == AF_INET6 &&
850 multidest6(dst) && multidest6(sc2->gif_pdst)) {
851 GIF_ORDERED_UNLOCK(sc, sc2);
852 error = EADDRNOTAVAIL;
853 ifnet_head_done();
854 goto bad;
855 }
856 GIF_ORDERED_UNLOCK(sc, sc2);
857 }
858 ifnet_head_done();
859
860 GIF_LOCK(sc);
861 if (sc->gif_psrc) {
862 kfree_data(sc->gif_psrc, sc->gif_psrc->sa_len);
863 }
864 sa = (struct sockaddr *)kalloc_data(src->sa_len, Z_WAITOK);
865 if (sa == NULL) {
866 GIF_UNLOCK(sc);
867 return ENOBUFS;
868 }
869 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
870 sc->gif_psrc = sa;
871
872 if (sc->gif_pdst) {
873 kfree_data(sc->gif_pdst, sc->gif_pdst->sa_len);
874 }
875 sa = (struct sockaddr *)kalloc_data(dst->sa_len, Z_WAITOK);
876 if (sa == NULL) {
877 GIF_UNLOCK(sc);
878 return ENOBUFS;
879 }
880 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
881 sc->gif_pdst = sa;
882 GIF_UNLOCK(sc);
883
884 ifnet_set_flags(ifp, IFF_RUNNING | IFF_UP, IFF_RUNNING |
885 IFF_UP);
886
887 error = 0;
888 break;
889
890 #ifdef SIOCDIFPHYADDR
891 case SIOCDIFPHYADDR:
892 GIF_LOCK(sc);
893 if (sc->gif_psrc) {
894 kfree_data(sc->gif_psrc, sc->gif_psrc->sa_len);
895 sc->gif_psrc = NULL;
896 }
897 if (sc->gif_pdst) {
898 kfree_data(sc->gif_pdst, sc->gif_pdst->sa_len);
899 sc->gif_pdst = NULL;
900 }
901 GIF_UNLOCK(sc);
902 /* change the IFF_{UP, RUNNING} flag as well? */
903 break;
904 #endif
905
906 case SIOCGIFPSRCADDR:
907 case SIOCGIFPSRCADDR_IN6:
908 GIF_LOCK(sc);
909 if (sc->gif_psrc == NULL) {
910 GIF_UNLOCK(sc);
911 error = EADDRNOTAVAIL;
912 goto bad;
913 }
914 src = sc->gif_psrc;
915 switch (cmd) {
916 #if INET
917 case SIOCGIFPSRCADDR:
918 dst = &ifr->ifr_addr;
919 size = sizeof(ifr->ifr_addr);
920 break;
921 #endif /* INET */
922 case SIOCGIFPSRCADDR_IN6:
923 dst = (struct sockaddr *)
924 &(((struct in6_ifreq *)data)->ifr_addr);
925 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
926 break;
927 default:
928 GIF_UNLOCK(sc);
929 error = EADDRNOTAVAIL;
930 goto bad;
931 }
932 if (src->sa_len > size) {
933 GIF_UNLOCK(sc);
934 return EINVAL;
935 }
936 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
937 GIF_UNLOCK(sc);
938 break;
939
940 case SIOCGIFPDSTADDR:
941 case SIOCGIFPDSTADDR_IN6:
942 GIF_LOCK(sc);
943 if (sc->gif_pdst == NULL) {
944 GIF_UNLOCK(sc);
945 error = EADDRNOTAVAIL;
946 goto bad;
947 }
948 src = sc->gif_pdst;
949 switch (cmd) {
950 #if INET
951 case SIOCGIFPDSTADDR:
952 dst = &ifr->ifr_addr;
953 size = sizeof(ifr->ifr_addr);
954 break;
955 #endif /* INET */
956 case SIOCGIFPDSTADDR_IN6:
957 dst = (struct sockaddr *)
958 &(((struct in6_ifreq *)data)->ifr_addr);
959 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
960 break;
961 default:
962 error = EADDRNOTAVAIL;
963 GIF_UNLOCK(sc);
964 goto bad;
965 }
966 if (src->sa_len > size) {
967 GIF_UNLOCK(sc);
968 return EINVAL;
969 }
970 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
971 GIF_UNLOCK(sc);
972 break;
973
974 case SIOCSIFFLAGS:
975 /* if_ioctl() takes care of it */
976 break;
977
978 default:
979 error = EOPNOTSUPP;
980 break;
981 }
982 bad:
983 return error;
984 }
985
986 static void
gif_delete_tunnel(struct gif_softc * sc)987 gif_delete_tunnel(struct gif_softc *sc)
988 {
989 GIF_LOCK_ASSERT(sc);
990 if (sc->gif_psrc) {
991 kfree_data(sc->gif_psrc, sc->gif_psrc->sa_len);
992 sc->gif_psrc = NULL;
993 }
994 if (sc->gif_pdst) {
995 kfree_data(sc->gif_pdst, sc->gif_pdst->sa_len);
996 sc->gif_pdst = NULL;
997 }
998 ROUTE_RELEASE(&sc->gif_ro);
999 /* change the IFF_UP flag as well? */
1000 }
1001