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