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