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