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