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