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