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