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