]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_gif.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / bsd / net / if_gif.c
1 /*
2 * Copyright (c) 2000-2008 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
86 #include <netinet/in.h>
87 #include <netinet/in_systm.h>
88 #include <netinet/ip.h>
89 #if INET
90 #include <netinet/in_var.h>
91 #include <netinet/in_gif.h>
92 #include <netinet/ip_var.h>
93 #endif /* INET */
94
95 #if INET6
96 #include <netinet6/in6_var.h>
97 #include <netinet/ip6.h>
98 #include <netinet6/ip6_var.h>
99 #include <netinet6/in6_gif.h>
100 #include <netinet6/ip6protosw.h>
101 #endif /* INET6 */
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 #if CONFIG_MACF_NET
110 #include <security/mac_framework.h>
111 #endif
112
113 #define GIFNAME "gif"
114 #define GIFDEV "if_gif"
115 #define GIF_MAXUNIT 0x7fff /* ifp->if_unit is only 15 bits */
116
117 #ifndef __APPLE__
118 static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
119 #endif
120
121 TAILQ_HEAD(gifhead, gif_softc) gifs = TAILQ_HEAD_INITIALIZER(gifs);
122
123 #ifdef __APPLE__
124 void gifattach(void);
125 static void gif_create_dev(void);
126 static int gif_encapcheck(const struct mbuf*, int, int, void*);
127 static errno_t gif_output(ifnet_t ifp, mbuf_t m);
128 static errno_t gif_input(ifnet_t ifp, protocol_family_t protocol_family,
129 mbuf_t m, char *frame_header);
130 static errno_t gif_ioctl(ifnet_t ifp, u_long cmd, void *data);
131
132 int ngif = 0; /* number of interfaces */
133 #endif
134
135 #if INET
136 struct protosw in_gif_protosw =
137 { SOCK_RAW, 0, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR,
138 in_gif_input, 0, 0, 0,
139 0,
140 0, 0, 0, 0,
141 0,
142 &rip_usrreqs,
143 0, rip_unlock, 0, {0, 0}, 0, {0}
144 };
145 #endif
146 #if INET6
147 struct ip6protosw in6_gif_protosw =
148 { SOCK_RAW, 0, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR,
149 in6_gif_input, 0, 0, 0,
150 0,
151 0, 0, 0, 0,
152 0,
153 &rip6_usrreqs,
154 0, rip_unlock, 0, {0, 0}, 0, {0}
155
156 };
157 #endif
158
159 #ifdef __APPLE__
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(
172 ifnet_t ifp,
173 __unused mbuf_t m,
174 __unused char *frame_header,
175 protocol_family_t *protocol_family)
176 {
177 /* Only one protocol may be attached to a gif interface. */
178 *protocol_family = ((struct gif_softc*)ifnet_softc(ifp))->gif_proto;
179
180 return 0;
181 }
182
183 static errno_t
184 gif_add_proto(
185 ifnet_t ifp,
186 protocol_family_t protocol_family,
187 __unused const struct ifnet_demux_desc *demux_array,
188 __unused u_int32_t demux_count)
189 {
190 /* Only one protocol may be attached at a time */
191 struct gif_softc* gif = ifnet_softc(ifp);
192
193 if (gif->gif_proto != 0)
194 printf("gif_add_proto: request add_proto for gif%d\n", ifnet_unit(ifp));
195
196 gif->gif_proto = protocol_family;
197
198 return 0;
199 }
200
201 static errno_t
202 gif_del_proto(
203 ifnet_t ifp,
204 protocol_family_t protocol_family)
205 {
206 if (((struct gif_softc*)ifnet_softc(ifp))->gif_proto == protocol_family)
207 ((struct gif_softc*)ifnet_softc(ifp))->gif_proto = 0;
208
209 return 0;
210 }
211
212 /* Glue code to attach inet to a gif interface through DLIL */
213 static errno_t
214 gif_attach_proto_family(
215 ifnet_t ifp,
216 protocol_family_t protocol_family)
217 {
218 struct ifnet_attach_proto_param reg;
219 errno_t stat;
220
221 bzero(&reg, sizeof(reg));
222 reg.input = gif_input;
223
224 stat = ifnet_attach_protocol(ifp, protocol_family, &reg);
225 if (stat && stat != EEXIST) {
226 printf("gif_attach_proto_family can't attach interface fam=%d\n",
227 protocol_family);
228 }
229
230 return stat;
231 }
232
233 #endif
234
235 /* Function to setup the first gif interface */
236 __private_extern__ void
237 gifattach(void)
238 {
239 errno_t result;
240
241 /* Init the list of interfaces */
242 TAILQ_INIT(&gifs);
243
244 /* Register protocol registration functions */
245 result = proto_register_plumber(PF_INET, APPLE_IF_FAM_GIF,
246 gif_attach_proto_family, NULL);
247 if (result != 0)
248 printf("proto_register_plumber failed for AF_INET error=%d\n", result);
249
250 result = proto_register_plumber(PF_INET6, APPLE_IF_FAM_GIF,
251 gif_attach_proto_family, NULL);
252 if (result != 0)
253 printf("proto_register_plumber failed for AF_INET6 error=%d\n", result);
254
255 /* Create first device */
256 gif_create_dev();
257 }
258
259 static errno_t
260 gif_set_bpf_tap(
261 ifnet_t ifp,
262 bpf_tap_mode mode,
263 bpf_packet_func callback)
264 {
265 struct gif_softc *sc = ifnet_softc(ifp);
266
267 sc->tap_mode = mode;
268 sc->tap_callback = callback;
269
270 return 0;
271 }
272
273 /* Creates another gif device if there are none free */
274 static void
275 gif_create_dev(void)
276 {
277 struct gif_softc *sc;
278 struct ifnet_init_params gif_init;
279 errno_t result = 0;
280
281
282 /* Can't create more than GIF_MAXUNIT */
283 if (ngif >= GIF_MAXUNIT)
284 return;
285
286 /* Check for unused gif interface */
287 TAILQ_FOREACH(sc, &gifs, gif_link) {
288 /* If unused, return, no need to create a new interface */
289 if ((ifnet_flags(sc->gif_if) & IFF_RUNNING) == 0)
290 return;
291 }
292
293 sc = _MALLOC(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK);
294 if (sc == NULL) {
295 log(LOG_ERR, "gifattach: failed to allocate gif%d\n", ngif);
296 return;
297 }
298
299 bzero(&gif_init, sizeof(gif_init));
300 gif_init.name = GIFNAME;
301 gif_init.unit = ngif;
302 gif_init.type = IFT_GIF;
303 gif_init.family = IFNET_FAMILY_GIF;
304 gif_init.output = gif_output;
305 gif_init.demux = gif_demux;
306 gif_init.add_proto = gif_add_proto;
307 gif_init.del_proto = gif_del_proto;
308 gif_init.softc = sc;
309 gif_init.ioctl = gif_ioctl;
310 gif_init.set_bpf_tap = gif_set_bpf_tap;
311
312 bzero(sc, sizeof(struct gif_softc));
313 result = ifnet_allocate(&gif_init, &sc->gif_if);
314 if (result != 0) {
315 printf("gif_create_dev, ifnet_allocate failed - %d\n", result);
316 _FREE(sc, M_DEVBUF);
317 return;
318 }
319 sc->encap_cookie4 = sc->encap_cookie6 = NULL;
320 #if INET
321 sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
322 gif_encapcheck, &in_gif_protosw, sc);
323 if (sc->encap_cookie4 == NULL) {
324 printf("%s: unable to attach encap4\n", if_name(sc->gif_if));
325 ifnet_release(sc->gif_if);
326 FREE(sc, M_DEVBUF);
327 return;
328 }
329 #endif
330 #if INET6
331 sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
332 gif_encapcheck, (struct protosw*)&in6_gif_protosw, sc);
333 if (sc->encap_cookie6 == NULL) {
334 if (sc->encap_cookie4) {
335 encap_detach(sc->encap_cookie4);
336 sc->encap_cookie4 = NULL;
337 }
338 printf("%s: unable to attach encap6\n", if_name(sc->gif_if));
339 ifnet_release(sc->gif_if);
340 FREE(sc, M_DEVBUF);
341 return;
342 }
343 #endif
344 sc->gif_called = 0;
345 ifnet_set_mtu(sc->gif_if, GIF_MTU);
346 ifnet_set_flags(sc->gif_if, IFF_POINTOPOINT | IFF_MULTICAST, 0xffff);
347 #if 0
348 /* turn off ingress filter */
349 sc->gif_if.if_flags |= IFF_LINK2;
350 #endif
351 result = ifnet_attach(sc->gif_if, NULL);
352 if (result != 0) {
353 printf("gif_create_dev - ifnet_attach failed - %d\n", result);
354 ifnet_release(sc->gif_if);
355 FREE(sc, M_DEVBUF);
356 return;
357 }
358 #if CONFIG_MACF_NET
359 mac_ifnet_label_init(&sc->gif_if);
360 #endif
361 bpfattach(sc->gif_if, DLT_NULL, sizeof(u_int));
362 TAILQ_INSERT_TAIL(&gifs, sc, gif_link);
363 ngif++;
364 }
365
366 static int
367 gif_encapcheck(
368 const struct mbuf *m,
369 int off,
370 int proto,
371 void *arg)
372 {
373 struct ip ip;
374 struct gif_softc *sc;
375
376 sc = (struct gif_softc *)arg;
377 if (sc == NULL)
378 return 0;
379
380 if ((ifnet_flags(sc->gif_if) & IFF_UP) == 0)
381 return 0;
382
383 /* no physical address */
384 if (!sc->gif_psrc || !sc->gif_pdst)
385 return 0;
386
387 switch (proto) {
388 #if INET
389 case IPPROTO_IPV4:
390 break;
391 #endif
392 #if INET6
393 case IPPROTO_IPV6:
394 break;
395 #endif
396 default:
397 return 0;
398 }
399
400 mbuf_copydata((struct mbuf *)(size_t)m, 0, sizeof(ip), &ip);
401
402 switch (ip.ip_v) {
403 #if INET
404 case 4:
405 if (sc->gif_psrc->sa_family != AF_INET ||
406 sc->gif_pdst->sa_family != AF_INET)
407 return 0;
408 return gif_encapcheck4(m, off, proto, arg);
409 #endif
410 #if INET6
411 case 6:
412 if (sc->gif_psrc->sa_family != AF_INET6 ||
413 sc->gif_pdst->sa_family != AF_INET6)
414 return 0;
415 return gif_encapcheck6(m, off, proto, arg);
416 #endif
417 default:
418 return 0;
419 }
420 }
421
422 static errno_t
423 gif_output(
424 ifnet_t ifp,
425 mbuf_t m)
426 {
427 struct gif_softc *sc = ifnet_softc(ifp);
428 int error = 0;
429
430 /*
431 max_gif_nesting check used to live here. It doesn't anymore
432 because there is no guaruntee that we won't be called
433 concurrently from more than one thread.
434 */
435
436 m->m_flags &= ~(M_BCAST|M_MCAST);
437 if (!(ifnet_flags(ifp) & IFF_UP) ||
438 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
439 ifnet_touch_lastchange(ifp);
440 m_freem(m); /* free it here not in dlil_output */
441 error = ENETDOWN;
442 goto end;
443 }
444
445 bpf_tap_out(ifp, 0, m, &sc->gif_proto, sizeof(sc->gif_proto));
446
447 /* inner AF-specific encapsulation */
448
449 /* XXX should we check if our outer source is legal? */
450
451 /* dispatch to output logic based on outer AF */
452 switch (sc->gif_psrc->sa_family) {
453 #if INET
454 case AF_INET:
455 error = in_gif_output(ifp, sc->gif_proto, m, NULL);
456 break;
457 #endif
458 #if INET6
459 case AF_INET6:
460 error = in6_gif_output(ifp, sc->gif_proto, m, NULL);
461 break;
462 #endif
463 default:
464 error = ENETDOWN;
465 goto end;
466 }
467
468 end:
469 if (error) {
470 /* the mbuf was freed either by in_gif_output or in here */
471 ifnet_stat_increment_out(ifp, 0, 0, 1);
472 }
473 else {
474 ifnet_stat_increment_out(ifp, 1, m->m_pkthdr.len, 0);
475 }
476 if (error == 0)
477 error = EJUSTRETURN; /* if no error, packet got sent already */
478 return error;
479 }
480
481 /*
482 * gif_input is the input handler for IP and IPv6 attached to gif
483 */
484 static errno_t
485 gif_input(
486 ifnet_t ifp,
487 protocol_family_t protocol_family,
488 mbuf_t m,
489 __unused char *frame_header)
490 {
491 errno_t error;
492 struct gif_softc *sc = ifnet_softc(ifp);
493
494 bpf_tap_in(ifp, 0, m, &sc->gif_proto, sizeof(sc->gif_proto));
495
496 /*
497 * Put the packet to the network layer input queue according to the
498 * specified address family.
499 * Note: older versions of gif_input directly called network layer
500 * input functions, e.g. ip6_input, here. We changed the policy to
501 * prevent too many recursive calls of such input functions, which
502 * might cause kernel panic. But the change may introduce another
503 * problem; if the input queue is full, packets are discarded.
504 * We believed it rarely occurs and changed the policy. If we find
505 * it occurs more times than we thought, we may change the policy
506 * again.
507 */
508 error = proto_input(protocol_family, m);
509 ifnet_stat_increment_in(ifp, 1, m->m_pkthdr.len, 0);
510
511 return (0);
512 }
513
514 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
515 static errno_t
516 gif_ioctl(
517 ifnet_t ifp,
518 u_long cmd,
519 void *data)
520 {
521 struct gif_softc *sc = ifnet_softc(ifp);
522 struct ifreq *ifr = (struct ifreq*)data;
523 int error = 0, size;
524 struct sockaddr *dst = NULL, *src = NULL;
525 struct sockaddr *sa;
526 struct ifnet *ifp2;
527 struct gif_softc *sc2;
528
529 switch (cmd) {
530 case SIOCSIFADDR:
531 break;
532
533 case SIOCSIFDSTADDR:
534 break;
535
536 case SIOCADDMULTI:
537 case SIOCDELMULTI:
538 break;
539
540 #ifdef SIOCSIFMTU /* xxx */
541 case SIOCGIFMTU:
542 break;
543
544 case SIOCSIFMTU:
545 {
546 u_int32_t mtu;
547 mtu = ifr->ifr_mtu;
548 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
549 return (EINVAL);
550 }
551 ifnet_set_mtu(ifp, mtu);
552 }
553 break;
554 #endif /* SIOCSIFMTU */
555
556 case SIOCSIFPHYADDR:
557 #if INET6
558 case SIOCSIFPHYADDR_IN6_32:
559 case SIOCSIFPHYADDR_IN6_64:
560 #endif /* INET6 */
561 case SIOCSLIFPHYADDR:
562 switch (cmd) {
563 #if INET
564 case SIOCSIFPHYADDR:
565 src = (struct sockaddr *)
566 &(((struct in_aliasreq *)data)->ifra_addr);
567 dst = (struct sockaddr *)
568 &(((struct in_aliasreq *)data)->ifra_dstaddr);
569 break;
570 #endif
571 #if INET6
572 case SIOCSIFPHYADDR_IN6_32: {
573 struct in6_aliasreq_32 *ifra_32 =
574 (struct in6_aliasreq_32 *)data;
575
576 src = (struct sockaddr *)&ifra_32->ifra_addr;
577 dst = (struct sockaddr *)&ifra_32->ifra_dstaddr;
578 break;
579 }
580
581 case SIOCSIFPHYADDR_IN6_64: {
582 struct in6_aliasreq_64 *ifra_64 =
583 (struct in6_aliasreq_64 *)data;
584
585 src = (struct sockaddr *)&ifra_64->ifra_addr;
586 dst = (struct sockaddr *)&ifra_64->ifra_dstaddr;
587 break;
588 }
589 #endif
590 case SIOCSLIFPHYADDR:
591 src = (struct sockaddr *)
592 &(((struct if_laddrreq *)data)->addr);
593 dst = (struct sockaddr *)
594 &(((struct if_laddrreq *)data)->dstaddr);
595 }
596
597 /* sa_family must be equal */
598 if (src->sa_family != dst->sa_family)
599 return EINVAL;
600
601 /* validate sa_len */
602 switch (src->sa_family) {
603 #if INET
604 case AF_INET:
605 if (src->sa_len != sizeof(struct sockaddr_in))
606 return EINVAL;
607 break;
608 #endif
609 #if INET6
610 case AF_INET6:
611 if (src->sa_len != sizeof(struct sockaddr_in6))
612 return EINVAL;
613 break;
614 #endif
615 default:
616 return EAFNOSUPPORT;
617 }
618 switch (dst->sa_family) {
619 #if INET
620 case AF_INET:
621 if (dst->sa_len != sizeof(struct sockaddr_in))
622 return EINVAL;
623 break;
624 #endif
625 #if INET6
626 case AF_INET6:
627 if (dst->sa_len != sizeof(struct sockaddr_in6))
628 return EINVAL;
629 break;
630 #endif
631 default:
632 return EAFNOSUPPORT;
633 }
634
635 /* check sa_family looks sane for the cmd */
636 switch (cmd) {
637 case SIOCSIFPHYADDR:
638 if (src->sa_family == AF_INET)
639 break;
640 return EAFNOSUPPORT;
641 #if INET6
642 case SIOCSIFPHYADDR_IN6_32:
643 case SIOCSIFPHYADDR_IN6_64:
644 if (src->sa_family == AF_INET6)
645 break;
646 return EAFNOSUPPORT;
647 #endif /* INET6 */
648 case SIOCSLIFPHYADDR:
649 /* checks done in the above */
650 break;
651 }
652
653 ifnet_head_lock_shared();
654 TAILQ_FOREACH(ifp2, &ifnet_head, if_link) {
655 if (strcmp(ifnet_name(ifp2), GIFNAME) != 0)
656 continue;
657 sc2 = ifnet_softc(ifp2);
658 if (sc2 == sc)
659 continue;
660 if (!sc2->gif_pdst || !sc2->gif_psrc)
661 continue;
662 if (sc2->gif_pdst->sa_family != dst->sa_family ||
663 sc2->gif_pdst->sa_len != dst->sa_len ||
664 sc2->gif_psrc->sa_family != src->sa_family ||
665 sc2->gif_psrc->sa_len != src->sa_len)
666 continue;
667 #ifndef XBONEHACK
668 /* can't configure same pair of address onto two gifs */
669 if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
670 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
671 error = EADDRNOTAVAIL;
672 ifnet_head_done();
673 goto bad;
674 }
675 #endif
676
677 /* can't configure multiple multi-dest interfaces */
678 #define multidest(x) \
679 (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
680 #if INET6
681 #define multidest6(x) \
682 (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
683 #endif
684 if (dst->sa_family == AF_INET &&
685 multidest(dst) && multidest(sc2->gif_pdst)) {
686 error = EADDRNOTAVAIL;
687 ifnet_head_done();
688 goto bad;
689 }
690 #if INET6
691 if (dst->sa_family == AF_INET6 &&
692 multidest6(dst) && multidest6(sc2->gif_pdst)) {
693 error = EADDRNOTAVAIL;
694 ifnet_head_done();
695 goto bad;
696 }
697 #endif
698 }
699 ifnet_head_done();
700
701 if (sc->gif_psrc)
702 FREE((caddr_t)sc->gif_psrc, M_IFADDR);
703 sa = (struct sockaddr *)_MALLOC(src->sa_len, M_IFADDR, M_WAITOK);
704 if (sa == NULL)
705 return ENOBUFS;
706 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
707 sc->gif_psrc = sa;
708
709 if (sc->gif_pdst)
710 FREE((caddr_t)sc->gif_pdst, M_IFADDR);
711 sa = (struct sockaddr *)_MALLOC(dst->sa_len, M_IFADDR, M_WAITOK);
712 if (sa == NULL)
713 return ENOBUFS;
714 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
715 sc->gif_pdst = sa;
716
717 ifnet_set_flags(ifp, IFF_RUNNING | IFF_UP, IFF_RUNNING | IFF_UP);
718
719 #ifdef __APPLE__
720 /* Make sure at least one unused device is still available */
721 gif_create_dev();
722 #endif
723
724 error = 0;
725 break;
726
727 #ifdef SIOCDIFPHYADDR
728 case SIOCDIFPHYADDR:
729 if (sc->gif_psrc) {
730 FREE((caddr_t)sc->gif_psrc, M_IFADDR);
731 sc->gif_psrc = NULL;
732 }
733 if (sc->gif_pdst) {
734 FREE((caddr_t)sc->gif_pdst, M_IFADDR);
735 sc->gif_pdst = NULL;
736 }
737 /* change the IFF_{UP, RUNNING} flag as well? */
738 break;
739 #endif
740
741 case SIOCGIFPSRCADDR:
742 #if INET6
743 case SIOCGIFPSRCADDR_IN6:
744 #endif /* INET6 */
745 if (sc->gif_psrc == NULL) {
746 error = EADDRNOTAVAIL;
747 goto bad;
748 }
749 src = sc->gif_psrc;
750 switch (cmd) {
751 #if INET
752 case SIOCGIFPSRCADDR:
753 dst = &ifr->ifr_addr;
754 size = sizeof(ifr->ifr_addr);
755 break;
756 #endif /* INET */
757 #if INET6
758 case SIOCGIFPSRCADDR_IN6:
759 dst = (struct sockaddr *)
760 &(((struct in6_ifreq *)data)->ifr_addr);
761 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
762 break;
763 #endif /* INET6 */
764 default:
765 error = EADDRNOTAVAIL;
766 goto bad;
767 }
768 if (src->sa_len > size)
769 return EINVAL;
770 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
771 break;
772
773 case SIOCGIFPDSTADDR:
774 #if INET6
775 case SIOCGIFPDSTADDR_IN6:
776 #endif /* INET6 */
777 if (sc->gif_pdst == NULL) {
778 error = EADDRNOTAVAIL;
779 goto bad;
780 }
781 src = sc->gif_pdst;
782 switch (cmd) {
783 #if INET
784 case SIOCGIFPDSTADDR:
785 dst = &ifr->ifr_addr;
786 size = sizeof(ifr->ifr_addr);
787 break;
788 #endif /* INET */
789 #if INET6
790 case SIOCGIFPDSTADDR_IN6:
791 dst = (struct sockaddr *)
792 &(((struct in6_ifreq *)data)->ifr_addr);
793 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
794 break;
795 #endif /* INET6 */
796 default:
797 error = EADDRNOTAVAIL;
798 goto bad;
799 }
800 if (src->sa_len > size)
801 return EINVAL;
802 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
803 break;
804
805 case SIOCGLIFPHYADDR:
806 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
807 error = EADDRNOTAVAIL;
808 goto bad;
809 }
810
811 /* copy src */
812 src = sc->gif_psrc;
813 dst = (struct sockaddr *)
814 &(((struct if_laddrreq *)data)->addr);
815 size = sizeof(((struct if_laddrreq *)data)->addr);
816 if (src->sa_len > size)
817 return EINVAL;
818 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
819
820 /* copy dst */
821 src = sc->gif_pdst;
822 dst = (struct sockaddr *)
823 &(((struct if_laddrreq *)data)->dstaddr);
824 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
825 if (src->sa_len > size)
826 return EINVAL;
827 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
828 break;
829
830 case SIOCSIFFLAGS:
831 /* if_ioctl() takes care of it */
832 break;
833
834 default:
835 error = EOPNOTSUPP;
836 break;
837 }
838 bad:
839 return error;
840 }
841
842 #ifndef __APPLE__
843 /* This function is not used in our stack */
844 void
845 gif_delete_tunnel(sc)
846 struct gif_softc *sc;
847 {
848 /* XXX: NetBSD protects this function with splsoftnet() */
849
850 if (sc->gif_psrc) {
851 FREE((caddr_t)sc->gif_psrc, M_IFADDR);
852 sc->gif_psrc = NULL;
853 }
854 if (sc->gif_pdst) {
855 FREE((caddr_t)sc->gif_pdst, M_IFADDR);
856 sc->gif_pdst = NULL;
857 }
858 /* change the IFF_UP flag as well? */
859 }
860 #endif