]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_gif.c
ebeebc1f361391f93a762927d149403cd37b5089
[apple/xnu.git] / bsd / net / if_gif.c
1 /*
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /* $FreeBSD: src/sys/net/if_gif.c,v 1.4.2.6 2001/07/24 19:10:18 brooks Exp $ */
31 /* $KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 itojun Exp $ */
32
33 /*
34 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
35 * All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. Neither the name of the project nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 */
61
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/kernel.h>
65 #include <sys/malloc.h>
66 #include <sys/mbuf.h>
67 #include <sys/socket.h>
68 #include <sys/sockio.h>
69 #include <sys/errno.h>
70 #include <sys/time.h>
71 #include <sys/syslog.h>
72 #include <sys/protosw.h>
73 #include <kern/cpu_number.h>
74
75 #include <net/if.h>
76 #include <net/if_types.h>
77 #include <net/route.h>
78 #include <net/bpf.h>
79
80 #include <netinet/in.h>
81 #include <netinet/in_systm.h>
82 #include <netinet/ip.h>
83 #if INET
84 #include <netinet/in_var.h>
85 #include <netinet/in_gif.h>
86 #include <netinet/ip_var.h>
87 #endif /* INET */
88
89 #if INET6
90 #include <netinet6/in6_var.h>
91 #include <netinet/ip6.h>
92 #include <netinet6/ip6_var.h>
93 #include <netinet6/in6_gif.h>
94 #include <netinet6/ip6protosw.h>
95 #endif /* INET6 */
96
97 #include <netinet/ip_encap.h>
98 #include <net/dlil.h>
99 #include <net/if_gif.h>
100
101 #include <net/net_osdep.h>
102
103 #define GIFNAME "gif"
104 #define GIFDEV "if_gif"
105 #define GIF_MAXUNIT 0x7fff /* ifp->if_unit is only 15 bits */
106
107 #ifndef __APPLE__
108 static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
109 #endif
110
111 TAILQ_HEAD(gifhead, gif_softc) gifs = TAILQ_HEAD_INITIALIZER(gifs);
112
113 #ifdef __APPLE__
114 void gifattach(void);
115 int gif_pre_output(struct ifnet *ifp, u_long protocol_family, struct mbuf **m0,
116 const struct sockaddr *dst, caddr_t rt, char *frame, char *address);
117 static void gif_create_dev(void);
118 static int gif_encapcheck(const struct mbuf*, int, int, void*);
119
120
121 int ngif = 0; /* number of interfaces */
122 #endif
123
124 #if INET
125 struct protosw in_gif_protosw =
126 { SOCK_RAW, 0, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR,
127 in_gif_input, 0, 0, 0,
128 0,
129 0, 0, 0, 0,
130 0,
131 &rip_usrreqs,
132 0, rip_unlock, 0
133 };
134 #endif
135 #if INET6
136 struct ip6protosw in6_gif_protosw =
137 { SOCK_RAW, 0, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR,
138 in6_gif_input, 0, 0, 0,
139 0,
140 0, 0, 0, 0,
141 0,
142 &rip6_usrreqs,
143 0, rip_unlock, 0,
144
145 };
146 #endif
147
148 #ifndef MAX_GIF_NEST
149 /*
150 * This macro controls the upper limitation on nesting of gif tunnels.
151 * Since, setting a large value to this macro with a careless configuration
152 * may introduce system crash, we don't allow any nestings by default.
153 * If you need to configure nested gif tunnels, you can define this macro
154 * in your kernel configuration file. However, if you do so, please be
155 * careful to configure the tunnels so that it won't make a loop.
156 */
157 #define MAX_GIF_NEST 1
158 #endif
159 static int max_gif_nesting = MAX_GIF_NEST;
160
161
162
163 #ifdef __APPLE__
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 int gif_demux(
176 struct ifnet *ifp,
177 struct mbuf *m,
178 char *frame_header,
179 u_long *protocol_family)
180 {
181 struct gif_softc* gif = (struct gif_softc*)ifp->if_softc;
182
183 /* Only one protocol may be attached to a gif interface. */
184 *protocol_family = gif->gif_proto;
185
186 return 0;
187 }
188
189 static
190 int gif_add_proto(struct ifnet *ifp, u_long protocol_family, struct ddesc_head_str *desc_head)
191 {
192 /* Only one protocol may be attached at a time */
193 struct gif_softc* gif = (struct gif_softc*)ifp->if_softc;
194
195 if (gif->gif_proto != 0)
196 printf("gif_add_proto: request add_proto for gif%d\n", gif->gif_if.if_unit);
197
198 gif->gif_proto = protocol_family;
199
200 return 0;
201 }
202
203 static
204 int gif_del_proto(struct ifnet *ifp, u_long protocol_family)
205 {
206 if (((struct gif_softc*)ifp)->gif_proto == protocol_family)
207 ((struct gif_softc*)ifp)->gif_proto = 0;
208 else
209 return ENOENT;
210
211 return 0;
212 }
213
214 /* Glue code to attach inet to a gif interface through DLIL */
215 int
216 gif_attach_proto_family(
217 struct ifnet *ifp,
218 u_long protocol_family)
219 {
220 struct dlil_proto_reg_str reg;
221 int stat;
222
223 bzero(&reg, sizeof(reg));
224 TAILQ_INIT(&reg.demux_desc_head);
225 reg.interface_family = ifp->if_family;
226 reg.unit_number = ifp->if_unit;
227 reg.input = gif_input;
228 reg.pre_output = gif_pre_output;
229 reg.protocol_family = protocol_family;
230
231 stat = dlil_attach_protocol(&reg);
232 if (stat && stat != EEXIST) {
233 panic("gif_attach_proto_family can't attach interface fam=%d\n", protocol_family);
234 }
235
236 return stat;
237 }
238
239 #endif
240
241 /* Function to setup the first gif interface */
242 void
243 gifattach(void)
244 {
245 int error;
246
247 /* Init the list of interfaces */
248 TAILQ_INIT(&gifs);
249
250 /* Register protocol registration functions */
251 if ( error = dlil_reg_proto_module(AF_INET, APPLE_IF_FAM_GIF, gif_attach_proto_family, NULL) != 0)
252 printf("dlil_reg_proto_module failed for AF_INET error=%d\n", error);
253
254 if ( error = dlil_reg_proto_module(AF_INET6, APPLE_IF_FAM_GIF, gif_attach_proto_family, NULL) != 0)
255 printf("dlil_reg_proto_module failed for AF_INET6 error=%d\n", error);
256
257 /* Create first device */
258 gif_create_dev();
259 }
260
261 /* Creates another gif device if there are none free */
262 static void
263 gif_create_dev(void)
264 {
265 struct gif_softc *sc;
266
267
268 /* Can't create more than GIF_MAXUNIT */
269 if (ngif >= GIF_MAXUNIT)
270 return;
271
272 /* Check for unused gif interface */
273 TAILQ_FOREACH(sc, &gifs, gif_link) {
274 /* If unused, return, no need to create a new interface */
275 if ((sc->gif_if.if_flags & IFF_RUNNING) == 0)
276 return;
277 }
278
279 sc = _MALLOC(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK);
280 if (sc == NULL) {
281 log(LOG_ERR, "gifattach: failed to allocate gif%d\n", ngif);
282 return;
283 }
284
285 bzero(sc, sizeof(struct gif_softc));
286 sc->gif_if.if_softc = sc;
287 sc->gif_if.if_name = GIFNAME;
288 sc->gif_if.if_unit = ngif;
289
290 sc->encap_cookie4 = sc->encap_cookie6 = NULL;
291 #ifdef INET
292 sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
293 gif_encapcheck, &in_gif_protosw, sc);
294 if (sc->encap_cookie4 == NULL) {
295 printf("%s: unable to attach encap4\n", if_name(&sc->gif_if));
296 FREE(sc, M_DEVBUF);
297 return;
298 }
299 #endif
300 #ifdef INET6
301 sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
302 gif_encapcheck, (struct protosw*)&in6_gif_protosw, sc);
303 if (sc->encap_cookie6 == NULL) {
304 if (sc->encap_cookie4) {
305 encap_detach(sc->encap_cookie4);
306 sc->encap_cookie4 = NULL;
307 }
308 printf("%s: unable to attach encap6\n", if_name(&sc->gif_if));
309 FREE(sc, M_DEVBUF);
310 return;
311 }
312 #endif
313
314 sc->gif_called = 0;
315 sc->gif_if.if_family= APPLE_IF_FAM_GIF;
316 sc->gif_if.if_mtu = GIF_MTU;
317 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
318 #if 0
319 /* turn off ingress filter */
320 sc->gif_if.if_flags |= IFF_LINK2;
321 #endif
322 sc->gif_if.if_demux = gif_demux;
323 sc->gif_if.if_ioctl = gif_ioctl;
324 sc->gif_if.if_output = NULL; /* pre_output returns error or EJUSTRETURN */
325 sc->gif_if.if_type = IFT_GIF;
326 sc->gif_if.if_add_proto = gif_add_proto;
327 sc->gif_if.if_del_proto = gif_del_proto;
328 dlil_if_attach(&sc->gif_if);
329 bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
330 TAILQ_INSERT_TAIL(&gifs, sc, gif_link);
331 ngif++;
332 }
333
334 static int
335 gif_encapcheck(m, off, proto, arg)
336 const struct mbuf *m;
337 int off;
338 int proto;
339 void *arg;
340 {
341 struct ip ip;
342 struct gif_softc *sc;
343
344 sc = (struct gif_softc *)arg;
345 if (sc == NULL)
346 return 0;
347
348 if ((sc->gif_if.if_flags & IFF_UP) == 0)
349 return 0;
350
351 /* no physical address */
352 if (!sc->gif_psrc || !sc->gif_pdst)
353 return 0;
354
355 switch (proto) {
356 #if INET
357 case IPPROTO_IPV4:
358 break;
359 #endif
360 #if INET6
361 case IPPROTO_IPV6:
362 break;
363 #endif
364 default:
365 return 0;
366 }
367
368 /* LINTED const cast */
369 m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
370
371 switch (ip.ip_v) {
372 #if INET
373 case 4:
374 if (sc->gif_psrc->sa_family != AF_INET ||
375 sc->gif_pdst->sa_family != AF_INET)
376 return 0;
377 return gif_encapcheck4(m, off, proto, arg);
378 #endif
379 #if INET6
380 case 6:
381 if (sc->gif_psrc->sa_family != AF_INET6 ||
382 sc->gif_pdst->sa_family != AF_INET6)
383 return 0;
384 return gif_encapcheck6(m, off, proto, arg);
385 #endif
386 default:
387 return 0;
388 }
389 }
390
391 int
392 gif_pre_output(
393 struct ifnet *ifp,
394 u_long protocol_family,
395 struct mbuf **m0,
396 const struct sockaddr *dst,
397 caddr_t rt,
398 char *frame,
399 char *address)
400 {
401 struct gif_softc *sc = (struct gif_softc*)ifp;
402 register struct mbuf * m = *m0;
403 int error = 0;
404
405 /*
406 * gif may cause infinite recursion calls when misconfigured.
407 * We'll prevent this by introducing upper limit.
408 * XXX: this mechanism may introduce another problem about
409 * mutual exclusion of the variable CALLED, especially if we
410 * use kernel thread.
411 */
412 if (++sc->gif_called > max_gif_nesting) {
413 log(LOG_NOTICE,
414 "gif_output: recursively called too many times(%d)\n",
415 sc->gif_called);
416 m_freem(m); /* free it here not in dlil_output*/
417 error = EIO; /* is there better errno? */
418 goto end;
419 }
420
421 ifnet_touch_lastchange(ifp);
422 m->m_flags &= ~(M_BCAST|M_MCAST);
423 if (!(ifp->if_flags & IFF_UP) ||
424 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
425 m_freem(m); /* free it here not in dlil_output */
426 error = ENETDOWN;
427 goto end;
428 }
429
430 if (ifp->if_bpf) {
431 /*
432 * We need to prepend the address family as
433 * a four byte field. Cons up a dummy header
434 * to pacify bpf. This is safe because bpf
435 * will only read from the mbuf (i.e., it won't
436 * try to free it or keep a pointer a to it).
437 */
438 struct mbuf m0;
439 u_int32_t protocol_family = dst->sa_family;
440
441 m0.m_next = m;
442 m0.m_len = 4;
443 m0.m_data = (char *)&protocol_family;
444
445 bpf_mtap(ifp, &m0);
446 }
447 ifp->if_opackets++;
448 ifp->if_obytes += m->m_pkthdr.len;
449
450 /* inner AF-specific encapsulation */
451
452 /* XXX should we check if our outer source is legal? */
453
454 /* dispatch to output logic based on outer AF */
455 switch (sc->gif_psrc->sa_family) {
456 #if INET
457 case AF_INET:
458 error = in_gif_output(ifp, dst->sa_family, m, (struct rtentry*)rt);
459 break;
460 #endif
461 #if INET6
462 case AF_INET6:
463 error = in6_gif_output(ifp, dst->sa_family, m, (struct rtentry*)rt);
464 break;
465 #endif
466 default:
467 error = ENETDOWN;
468 goto end;
469 }
470
471 end:
472 sc->gif_called = 0; /* reset recursion counter */
473 if (error) {
474 /* the mbuf was freed either by in_gif_output or in here */
475 *m0 = NULL; /* avoid getting dlil_output freeing it */
476 ifp->if_oerrors++;
477 }
478 if (error == 0)
479 error = EJUSTRETURN; /* if no error, packet got sent already */
480 return error;
481 }
482
483 int
484 gif_input(
485 struct mbuf *m,
486 char* frame_header,
487 struct ifnet* gifp,
488 u_long protocol_family,
489 int sync_ok)
490 {
491
492 if (gifp == NULL) {
493 /* just in case */
494 m_freem(m);
495 return;
496 }
497
498 if (m->m_pkthdr.rcvif)
499 m->m_pkthdr.rcvif = gifp;
500
501 if (gifp->if_bpf) {
502 /*
503 * We need to prepend the address family as
504 * a four byte field. Cons up a dummy header
505 * to pacify bpf. This is safe because bpf
506 * will only read from the mbuf (i.e., it won't
507 * try to free it or keep a pointer a to it).
508 */
509 struct mbuf m0;
510 u_int32_t protocol_family1 = protocol_family;
511
512 m0.m_next = m;
513 m0.m_len = 4;
514 m0.m_data = (char *)&protocol_family1;
515
516 bpf_mtap(gifp, &m0);
517 }
518
519 /*
520 * Put the packet to the network layer input queue according to the
521 * specified address family.
522 * Note: older versions of gif_input directly called network layer
523 * input functions, e.g. ip6_input, here. We changed the policy to
524 * prevent too many recursive calls of such input functions, which
525 * might cause kernel panic. But the change may introduce another
526 * problem; if the input queue is full, packets are discarded.
527 * We believed it rarely occurs and changed the policy. If we find
528 * it occurs more times than we thought, we may change the policy
529 * again.
530 */
531 proto_input(protocol_family, m);
532 gifp->if_ipackets++;
533 gifp->if_ibytes += m->m_pkthdr.len;
534
535 return (0);
536 }
537
538 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
539 int
540 gif_ioctl(ifp, cmd, data)
541 struct ifnet *ifp;
542 u_long cmd;
543 void* data;
544 {
545 struct gif_softc *sc = (struct gif_softc*)ifp;
546 struct ifreq *ifr = (struct ifreq*)data;
547 int error = 0, size;
548 struct sockaddr *dst, *src;
549 struct sockaddr *sa;
550 int s;
551 struct ifnet *ifp2;
552 struct gif_softc *sc2;
553
554 switch (cmd) {
555 case SIOCSIFADDR:
556 break;
557
558 case SIOCSIFDSTADDR:
559 break;
560
561 case SIOCADDMULTI:
562 case SIOCDELMULTI:
563 break;
564
565 #ifdef SIOCSIFMTU /* xxx */
566 case SIOCGIFMTU:
567 break;
568
569 case SIOCSIFMTU:
570 {
571 u_long mtu;
572 mtu = ifr->ifr_mtu;
573 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
574 return (EINVAL);
575 }
576 ifp->if_mtu = mtu;
577 }
578 break;
579 #endif /* SIOCSIFMTU */
580
581 case SIOCSIFPHYADDR:
582 #if INET6
583 case SIOCSIFPHYADDR_IN6:
584 #endif /* INET6 */
585 case SIOCSLIFPHYADDR:
586 switch (cmd) {
587 #if INET
588 case SIOCSIFPHYADDR:
589 src = (struct sockaddr *)
590 &(((struct in_aliasreq *)data)->ifra_addr);
591 dst = (struct sockaddr *)
592 &(((struct in_aliasreq *)data)->ifra_dstaddr);
593 break;
594 #endif
595 #if INET6
596 case SIOCSIFPHYADDR_IN6:
597 src = (struct sockaddr *)
598 &(((struct in6_aliasreq *)data)->ifra_addr);
599 dst = (struct sockaddr *)
600 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
601 break;
602 #endif
603 case SIOCSLIFPHYADDR:
604 src = (struct sockaddr *)
605 &(((struct if_laddrreq *)data)->addr);
606 dst = (struct sockaddr *)
607 &(((struct if_laddrreq *)data)->dstaddr);
608 }
609
610 /* sa_family must be equal */
611 if (src->sa_family != dst->sa_family)
612 return EINVAL;
613
614 /* validate sa_len */
615 switch (src->sa_family) {
616 #if INET
617 case AF_INET:
618 if (src->sa_len != sizeof(struct sockaddr_in))
619 return EINVAL;
620 break;
621 #endif
622 #if INET6
623 case AF_INET6:
624 if (src->sa_len != sizeof(struct sockaddr_in6))
625 return EINVAL;
626 break;
627 #endif
628 default:
629 return EAFNOSUPPORT;
630 }
631 switch (dst->sa_family) {
632 #if INET
633 case AF_INET:
634 if (dst->sa_len != sizeof(struct sockaddr_in))
635 return EINVAL;
636 break;
637 #endif
638 #if INET6
639 case AF_INET6:
640 if (dst->sa_len != sizeof(struct sockaddr_in6))
641 return EINVAL;
642 break;
643 #endif
644 default:
645 return EAFNOSUPPORT;
646 }
647
648 /* check sa_family looks sane for the cmd */
649 switch (cmd) {
650 case SIOCSIFPHYADDR:
651 if (src->sa_family == AF_INET)
652 break;
653 return EAFNOSUPPORT;
654 #if INET6
655 case SIOCSIFPHYADDR_IN6:
656 if (src->sa_family == AF_INET6)
657 break;
658 return EAFNOSUPPORT;
659 #endif /* INET6 */
660 case SIOCSLIFPHYADDR:
661 /* checks done in the above */
662 break;
663 }
664
665 ifnet_head_lock_shared();
666 TAILQ_FOREACH(ifp2, &ifnet_head, if_link) {
667 if (strcmp(ifp2->if_name, GIFNAME) != 0)
668 continue;
669 sc2 = ifp2->if_softc;
670 if (sc2 == sc)
671 continue;
672 if (!sc2->gif_pdst || !sc2->gif_psrc)
673 continue;
674 if (sc2->gif_pdst->sa_family != dst->sa_family ||
675 sc2->gif_pdst->sa_len != dst->sa_len ||
676 sc2->gif_psrc->sa_family != src->sa_family ||
677 sc2->gif_psrc->sa_len != src->sa_len)
678 continue;
679 #ifndef XBONEHACK
680 /* can't configure same pair of address onto two gifs */
681 if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
682 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
683 error = EADDRNOTAVAIL;
684 ifnet_head_done();
685 goto bad;
686 }
687 #endif
688
689 /* can't configure multiple multi-dest interfaces */
690 #define multidest(x) \
691 (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
692 #if INET6
693 #define multidest6(x) \
694 (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
695 #endif
696 if (dst->sa_family == AF_INET &&
697 multidest(dst) && multidest(sc2->gif_pdst)) {
698 error = EADDRNOTAVAIL;
699 ifnet_head_done();
700 goto bad;
701 }
702 #if INET6
703 if (dst->sa_family == AF_INET6 &&
704 multidest6(dst) && multidest6(sc2->gif_pdst)) {
705 error = EADDRNOTAVAIL;
706 ifnet_head_done();
707 goto bad;
708 }
709 #endif
710 }
711 ifnet_head_done();
712
713 if (sc->gif_psrc)
714 FREE((caddr_t)sc->gif_psrc, M_IFADDR);
715 sa = (struct sockaddr *)_MALLOC(src->sa_len, M_IFADDR, M_WAITOK);
716 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
717 sc->gif_psrc = sa;
718
719 if (sc->gif_pdst)
720 FREE((caddr_t)sc->gif_pdst, M_IFADDR);
721 sa = (struct sockaddr *)_MALLOC(dst->sa_len, M_IFADDR, M_WAITOK);
722 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
723 sc->gif_pdst = sa;
724
725 ifp->if_flags |= IFF_RUNNING;
726
727 s = splimp();
728 if_up(ifp); /* mark interface UP and send up RTM_IFINFO */
729 #ifdef __APPLE__
730 /* Make sure at least one unused device is still available */
731 gif_create_dev();
732 #endif
733 splx(s);
734
735 error = 0;
736 break;
737
738 #ifdef SIOCDIFPHYADDR
739 case SIOCDIFPHYADDR:
740 if (sc->gif_psrc) {
741 FREE((caddr_t)sc->gif_psrc, M_IFADDR);
742 sc->gif_psrc = NULL;
743 }
744 if (sc->gif_pdst) {
745 FREE((caddr_t)sc->gif_pdst, M_IFADDR);
746 sc->gif_pdst = NULL;
747 }
748 /* change the IFF_{UP, RUNNING} flag as well? */
749 break;
750 #endif
751
752 case SIOCGIFPSRCADDR:
753 #if INET6
754 case SIOCGIFPSRCADDR_IN6:
755 #endif /* INET6 */
756 if (sc->gif_psrc == NULL) {
757 error = EADDRNOTAVAIL;
758 goto bad;
759 }
760 src = sc->gif_psrc;
761 switch (cmd) {
762 #if INET
763 case SIOCGIFPSRCADDR:
764 dst = &ifr->ifr_addr;
765 size = sizeof(ifr->ifr_addr);
766 break;
767 #endif /* INET */
768 #if INET6
769 case SIOCGIFPSRCADDR_IN6:
770 dst = (struct sockaddr *)
771 &(((struct in6_ifreq *)data)->ifr_addr);
772 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
773 break;
774 #endif /* INET6 */
775 default:
776 error = EADDRNOTAVAIL;
777 goto bad;
778 }
779 if (src->sa_len > size)
780 return EINVAL;
781 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
782 break;
783
784 case SIOCGIFPDSTADDR:
785 #if INET6
786 case SIOCGIFPDSTADDR_IN6:
787 #endif /* INET6 */
788 if (sc->gif_pdst == NULL) {
789 error = EADDRNOTAVAIL;
790 goto bad;
791 }
792 src = sc->gif_pdst;
793 switch (cmd) {
794 #if INET
795 case SIOCGIFPDSTADDR:
796 dst = &ifr->ifr_addr;
797 size = sizeof(ifr->ifr_addr);
798 break;
799 #endif /* INET */
800 #if INET6
801 case SIOCGIFPDSTADDR_IN6:
802 dst = (struct sockaddr *)
803 &(((struct in6_ifreq *)data)->ifr_addr);
804 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
805 break;
806 #endif /* INET6 */
807 default:
808 error = EADDRNOTAVAIL;
809 goto bad;
810 }
811 if (src->sa_len > size)
812 return EINVAL;
813 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
814 break;
815
816 case SIOCGLIFPHYADDR:
817 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
818 error = EADDRNOTAVAIL;
819 goto bad;
820 }
821
822 /* copy src */
823 src = sc->gif_psrc;
824 dst = (struct sockaddr *)
825 &(((struct if_laddrreq *)data)->addr);
826 size = sizeof(((struct if_laddrreq *)data)->addr);
827 if (src->sa_len > size)
828 return EINVAL;
829 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
830
831 /* copy dst */
832 src = sc->gif_pdst;
833 dst = (struct sockaddr *)
834 &(((struct if_laddrreq *)data)->dstaddr);
835 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
836 if (src->sa_len > size)
837 return EINVAL;
838 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
839 break;
840
841 case SIOCSIFFLAGS:
842 /* if_ioctl() takes care of it */
843 break;
844
845 default:
846 error = EOPNOTSUPP;
847 break;
848 }
849 bad:
850 return error;
851 }
852
853 #ifndef __APPLE__
854 /* This function is not used in our stack */
855 void
856 gif_delete_tunnel(sc)
857 struct gif_softc *sc;
858 {
859 /* XXX: NetBSD protects this function with splsoftnet() */
860
861 if (sc->gif_psrc) {
862 FREE((caddr_t)sc->gif_psrc, M_IFADDR);
863 sc->gif_psrc = NULL;
864 }
865 if (sc->gif_pdst) {
866 FREE((caddr_t)sc->gif_pdst, M_IFADDR);
867 sc->gif_pdst = NULL;
868 }
869 /* change the IFF_UP flag as well? */
870 }
871 #endif