]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/if_gif.c
xnu-201.42.3.tar.gz
[apple/xnu.git] / bsd / net / if_gif.c
CommitLineData
1c79356b
A
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/* $KAME: if_gif.c,v 1.15 2000/02/22 14:01:46 itojun Exp $ */
23
24/*
25 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
26 * All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. Neither the name of the project nor the names of its contributors
37 * may be used to endorse or promote products derived from this software
38 * without specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 */
52
53/*
54 * gif.c
55 */
56#if BSD310
57#include "opt_inet.h"
58#endif
59
60#include <sys/param.h>
61#include <sys/systm.h>
62#include <sys/kernel.h>
63#include <sys/malloc.h>
64#include <sys/mbuf.h>
65#include <sys/socket.h>
66#include <sys/sockio.h>
67#include <sys/errno.h>
68#include <sys/time.h>
69#include <sys/syslog.h>
70#include <kern/cpu_number.h>
71
72#include <net/if.h>
73#include <net/if_types.h>
74#include <net/netisr.h>
75#include <net/route.h>
76#include <net/bpf.h>
77
78#if INET
79#include <netinet/in.h>
80#include <netinet/in_systm.h>
81#include <netinet/in_var.h>
82#include <netinet/ip.h>
83#include <netinet/in_gif.h>
84#endif /* INET */
85
86#if INET6
87#ifndef INET
88#include <netinet/in.h>
89#endif
90#include <netinet6/in6_var.h>
91#include <netinet/ip6.h>
92#include <netinet6/ip6_var.h>
93#include <netinet6/in6_gif.h>
94#include <netinet6/ip6protosw.h>
95#endif /* INET6 */
96
97#include <netinet/ip_encap.h>
98#include <net/dlil.h>
99#include <net/if_gif.h>
100
101#include "gif.h"
102#include "bpfilter.h"
103
104#include <net/net_osdep.h>
105
106#if NGIF > 0
107
108void gifattach __P((void *));
109int gif_pre_output __P((struct ifnet *, register struct mbuf **, struct sockaddr *,
110 register struct rtentry *, char *, char *, u_long));
111
112/*
113 * gif global variable definitions
114 */
115int ngif = NGIF; /* number of interfaces */
116struct gif_softc *gif = 0;
117static struct if_proto *gif_array[NGIF];
118static gif_count = 0 ;
119#ifndef MAX_GIF_NEST
120/*
121 * This macro controls the upper limitation on nesting of gif tunnels.
122 * Since, setting a large value to this macro with a careless configuration
123 * may introduce system crash, we don't allow any nestings by default.
124 * If you need to configure nested gif tunnels, you can define this macro
125 * in your kernel configuration file. However, if you do so, please be
126 * careful to configure the tunnels so that it won't make a loop.
127 */
128#define MAX_GIF_NEST 1
129#endif
130static int max_gif_nesting = MAX_GIF_NEST;
131
132
133
134#if 0
135int gif_demux(ifp, m, frame_header, proto)
136 struct ifnet *ifp;
137 struct mbuf *m;
138 char *frame_header;
139 struct if_proto **proto;
140{
141 int i;
142 return 0;
143}
144
145int gif_framer(ifp, m, dest, dest_linkaddr, frame_type)
146 struct ifnet *ifp;
147 struct mbuf **m;
148 struct sockaddr *dest;
149 char *dest_linkaddr;
150 char *frame_type;
151
152{
153 char *to_ptr;
154
155 return 0;
156}
157#endif
158static
159int gif_add_if(struct ifnet *ifp)
160{
161 ifp->if_demux = 0;
162 ifp->if_framer = 0;
163 return 0;
164}
165
166static
167int gif_del_if(struct ifnet *ifp)
168{
169 return 0;
170}
171
172static
173int gif_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long dl_tag)
174{
175 int i;
176
177 for (i=0; i < gif_count; i++)
178 if (gif_array[i] == 0) {
179 gif_array[gif_count] = proto;
180 return 0;
181 }
182
183 if ((i == gif_count) && (gif_count == NGIF))
184 panic("gif_add_proto -- Too many attachments\n");
185
186 gif_array[gif_count++] = proto;
187
188 return (0);
189}
190
191static
192int gif_del_proto(struct if_proto *proto, u_long dl_tag)
193{
194 int i;
195
196 for (i=0; i < gif_count; i++)
197 if (gif_array[i] == proto) {
198 gif_array[i] = 0;
199 return 0;
200 }
201
202 return ENOENT;
203}
204
205int gif_shutdown()
206{
207 return 0;
208}
209
210void gif_reg_if_mods()
211{
212 struct dlil_ifmod_reg_str gif_ifmod;
213
214 gif_ifmod.add_if = gif_add_if;
215 gif_ifmod.del_if = gif_del_if;
216 gif_ifmod.add_proto = gif_add_proto;
217 gif_ifmod.del_proto = gif_del_proto;
218 gif_ifmod.ifmod_ioctl = 0;
219 gif_ifmod.shutdown = gif_shutdown;
220
221 if (dlil_reg_if_modules(APPLE_IF_FAM_GIF, &gif_ifmod))
222 panic("Couldn't register gif modules\n");
223
224}
225
226u_long gif_attach_inet(struct ifnet *ifp)
227{
228 struct dlil_proto_reg_str reg;
229 struct dlil_demux_desc desc;
230 u_long dl_tag=0;
231 short native=0;
232 int stat;
233 int i;
234
235 for (i=0; i < gif_count; i++) {
236 if (gif_array[i] && (gif_array[i]->ifp == ifp) &&
237 (gif_array[i]->protocol_family == PF_INET)) {
238#if 0
239 kprintf("gif_attach for %s%d found dl_tag=%d\n",
240 ifp->if_name, ifp->if_unit, gif_array[i]->dl_tag);
241#endif
242 return gif_array[i]->dl_tag;
243
244 }
245 }
246
247 TAILQ_INIT(&reg.demux_desc_head);
248 desc.type = DLIL_DESC_RAW;
249 desc.variants.bitmask.proto_id_length = 0;
250 desc.variants.bitmask.proto_id = 0;
251 desc.variants.bitmask.proto_id_mask = 0;
252 desc.native_type = (char *) &native;
253 TAILQ_INSERT_TAIL(&reg.demux_desc_head, &desc, next);
254 reg.interface_family = ifp->if_family;
255 reg.unit_number = ifp->if_unit;
256 reg.input = gif_input;
257 reg.pre_output = gif_pre_output;
258 reg.event = 0;
259 reg.offer = 0;
260 reg.ioctl = gif_ioctl;
261 reg.default_proto = 0;
262 reg.protocol_family = PF_INET;
263
264 stat = dlil_attach_protocol(&reg, &dl_tag);
265 if (stat) {
266 panic("gif_attach_inet can't attach interface\n");
267 }
268
269 return dl_tag;
270}
271
272void
273gifattach(dummy)
274 void *dummy;
275{
276 register struct gif_softc *sc;
277 register int i;
278
279 gif_reg_if_mods(); /* DLIL modules */
280
0b4e3aa0 281 gif = sc = _MALLOC (ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAITOK);
1c79356b
A
282 bzero(sc, ngif * sizeof(struct gif_softc));
283 for (i = 0; i < ngif; sc++, i++) {
284 sc->gif_if.if_name = "gif";
285 sc->gif_if.if_unit = i;
286 sc->gif_if.if_family = APPLE_IF_FAM_GIF;
287 sc->gif_if.if_mtu = GIF_MTU;
288 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
289 sc->gif_if.if_ioctl = gif_ioctl;
290 sc->gif_if.if_output = NULL;
291 sc->gif_if.if_type = IFT_GIF;
292 dlil_if_attach(&sc->gif_if);
293#if 0
294 kprintf("gifattach: Attaching gif%d sc=%x gif_if=%x\n", i, sc, &sc->gif_if);
295#endif
296#if NBPFILTER > 0
297#ifdef HAVE_OLD_BPF
298 bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
299#else
300 bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_NULL, sizeof(u_int));
301#endif
302#endif
303 }
304}
305
306#ifdef __FreeBSD__
307PSEUDO_SET(gifattach, if_gif);
308#endif
309
310int
311gif_pre_output(ifp, m0, dst, rt, frame, address, dl_tag)
312 struct ifnet *ifp;
313 struct mbuf **m0;
314 struct sockaddr *dst;
315 struct rtentry *rt; /* added in net2 */
316 char *frame;
317 char *address;
318 u_long dl_tag;
319{
320 register struct gif_softc *sc = (struct gif_softc*)ifp;
321 register struct mbuf * m = *m0;
322 int error = 0;
323 static int called = 0; /* XXX: MUTEX */
324
325 /*
326 * gif may cause infinite recursion calls when misconfigured.
327 * We'll prevent this by introducing upper limit.
328 * XXX: this mechanism may introduce another problem about
329 * mutual exclusion of the variable CALLED, especially if we
330 * use kernel thread.
331 */
332 if (++called > max_gif_nesting) {
333 log(LOG_NOTICE,
334 "gif_output: recursively called too many times(%d)\n",
335 called);
336 m_freem(m);
337 error = EIO; /* is there better errno? */
338 goto end;
339 }
340
341 getmicrotime(&ifp->if_lastchange);
342 m->m_flags &= ~(M_BCAST|M_MCAST);
343 if (!(ifp->if_flags & IFF_UP) ||
344#if 0
345 sc->gif_flags & GIFF_INUSE ||
346#endif
347 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
348 m_freem(m);
349 error = ENETDOWN;
350 printf("gif_output: packed discarded ENETDOWN\n");
351 goto end;
352 }
353
354#if NBPFILTER > 0
355 if (ifp->if_bpf) {
356 /*
357 * We need to prepend the address family as
358 * a four byte field. Cons up a dummy header
359 * to pacify bpf. This is safe because bpf
360 * will only read from the mbuf (i.e., it won't
361 * try to free it or keep a pointer a to it).
362 */
363 struct mbuf m0;
364 u_int af = dst->sa_family;
365
366 m0.m_next = m;
367 m0.m_len = 4;
368 m0.m_data = (char *)&af;
369
370#ifdef HAVE_OLD_BPF
371 bpf_mtap(ifp, &m0);
372#else
373 bpf_mtap(ifp->if_bpf, &m0);
374#endif
375 }
376#endif
377 ifp->if_opackets++;
378 ifp->if_obytes += m->m_pkthdr.len;
379#if 0
380 s = splnet();
381 sc->gif_flags |= GIFF_INUSE;
382#endif
383
384 switch (sc->gif_psrc->sa_family) {
385#if INET
386 case AF_INET:
387 error = in_gif_output(ifp, dst->sa_family, m, rt);
388 if (error)
389 printf("in_gif_output returned error=%d\n", error);
390 break;
391#endif
392#if INET6
393 case AF_INET6:
394 error = in6_gif_output(ifp, dst->sa_family, m, rt);
395 if (error)
396 printf("in6_gif_output returned error=%d\n", error);
397 break;
398#endif
399 default:
400 m_freem(m);
401 error = ENETDOWN;
402 }
403#if 0
404 sc->gif_flags &= ~GIFF_INUSE;
405 splx(s);
406#endif
407
408 end:
409 called = 0; /* reset recursion counter */
410 if (error) ifp->if_oerrors++;
411 return EJUSTRETURN;
412}
413
414void
415gif_input(m, af, gifp)
416 struct mbuf *m;
417 int af;
418 struct ifnet *gifp;
419{
420 int s, isr;
421 register struct ifqueue *ifq = 0;
422
423 if (gifp == NULL) {
424 /* just in case */
425 m_freem(m);
426 return;
427 }
428
429 if (m->m_pkthdr.rcvif)
430 m->m_pkthdr.rcvif = gifp;
431
432#if NBPFILTER > 0
433 if (gifp->if_bpf) {
434 /*
435 * We need to prepend the address family as
436 * a four byte field. Cons up a dummy header
437 * to pacify bpf. This is safe because bpf
438 * will only read from the mbuf (i.e., it won't
439 * try to free it or keep a pointer a to it).
440 */
441 struct mbuf m0;
442 u_int af = AF_INET6;
443
444 m0.m_next = m;
445 m0.m_len = 4;
446 m0.m_data = (char *)&af;
447
448#ifdef HAVE_OLD_BPF
449 bpf_mtap(gifp, &m0);
450#else
451 bpf_mtap(gifp->if_bpf, &m0);
452#endif
453 }
454#endif /*NBPFILTER > 0*/
455
456 /*
457 * Put the packet to the network layer input queue according to the
458 * specified address family.
459 * Note: older versions of gif_input directly called network layer
460 * input functions, e.g. ip6_input, here. We changed the policy to
461 * prevent too many recursive calls of such input functions, which
462 * might cause kernel panic. But the change may introduce another
463 * problem; if the input queue is full, packets are discarded.
464 * We believed it rarely occurs and changed the policy. If we find
465 * it occurs more times than we thought, we may change the policy
466 * again.
467 */
468 switch (af) {
469#if INET
470 case AF_INET:
471 ifq = &ipintrq;
472 isr = NETISR_IP;
473 break;
474#endif
475#if INET6
476 case AF_INET6:
477 ifq = &ip6intrq;
478 isr = NETISR_IPV6;
479 break;
480#endif
481 default:
482 m_freem(m);
483 return;
484 }
485
486 s = splimp();
487 if (IF_QFULL(ifq)) {
488 IF_DROP(ifq); /* update statistics */
489 m_freem(m);
490 splx(s);
491 return;
492 }
493 IF_ENQUEUE(ifq, m);
494 /* we need schednetisr since the address family may change */
495 schednetisr(isr);
496 gifp->if_ipackets++;
497 gifp->if_ibytes += m->m_pkthdr.len;
498 splx(s);
499
500 return;
501}
502
503/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
504int
505gif_ioctl(ifp, cmd, data)
506 struct ifnet *ifp;
507 u_long cmd;
508 caddr_t data;
509{
510 struct gif_softc *sc = (struct gif_softc*)ifp;
511 struct ifreq *ifr = (struct ifreq*)data;
512 int error = 0, size;
513 struct sockaddr *dst, *src;
514 int i;
515 struct gif_softc *sc2;
516
517 switch (cmd) {
518 case SIOCSIFADDR:
519 break;
520
521 case SIOCSIFDSTADDR:
522 break;
523
524 case SIOCADDMULTI:
525 case SIOCDELMULTI:
526 /* Called from if_addmulti() with data == NULL if __FreeBSD__ >= 3 */
527#if !defined(__APPLE__)
528 switch (ifr->ifr_addr.sa_family) {
529#ifdef INET
530 case AF_INET: /* IP supports Multicast */
531 break;
532#endif /* INET */
533#ifdef INET6
534 case AF_INET6: /* IP6 supports Multicast */
535 break;
536#endif /* INET6 */
537 default: /* Other protocols doesn't support Multicast */
538 error = EAFNOSUPPORT;
539 break;
540 }
541#endif /*not FreeBSD3*/
542 break;
543
544#ifdef SIOCSIFMTU /* xxx */
545#ifndef __OpenBSD__
546 case SIOCGIFMTU:
547 break;
548 case SIOCSIFMTU:
549 {
550#ifdef __bsdi__
551 short mtu;
552 mtu = *(short *)ifr->ifr_data;
553#else
554 u_long mtu;
555 mtu = ifr->ifr_mtu;
556#endif
557 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
558 return (EINVAL);
559 }
560 ifp->if_mtu = mtu;
561 }
562 break;
563#endif
564#endif /* SIOCSIFMTU */
565
566 case SIOCSIFPHYADDR:
567#if INET6
568 case SIOCSIFPHYADDR_IN6:
569#endif /* INET6 */
570 /* can't configure same pair of address onto two gif */
571 src = (struct sockaddr *)
572 &(((struct in_aliasreq *)data)->ifra_addr);
573 dst = (struct sockaddr *)
574 &(((struct in_aliasreq *)data)->ifra_dstaddr);
575 for (i = 0; i < ngif; i++) {
576 sc2 = gif + i;
577 if (sc2 == sc)
578 continue;
579 if (!sc2->gif_pdst || !sc2->gif_psrc)
580 continue;
581 if (sc2->gif_pdst->sa_family == dst->sa_family &&
582 sc2->gif_pdst->sa_len == dst->sa_family &&
583 bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
584 sc2->gif_psrc->sa_family == src->sa_family &&
585 sc2->gif_psrc->sa_len == src->sa_family &&
586 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
587 error = EADDRNOTAVAIL;
588 goto bad;
589 }
590 }
591
592 switch (ifr->ifr_addr.sa_family) {
593#if INET
594 case AF_INET:
595 return in_gif_ioctl(ifp, cmd, data);
596#endif /* INET */
597#if INET6
598 case AF_INET6:
599 return in6_gif_ioctl(ifp, cmd, data);
600#endif /* INET6 */
601 default:
602 error = EPROTOTYPE;
603 goto bad;
604 break;
605 }
606 break;
607
608 case SIOCGIFPSRCADDR:
609#if INET6
610 case SIOCGIFPSRCADDR_IN6:
611#endif /* INET6 */
612 if (sc->gif_psrc == NULL) {
613 error = EADDRNOTAVAIL;
614 goto bad;
615 }
616 src = sc->gif_psrc;
617 switch (sc->gif_psrc->sa_family) {
618#if INET
619 case AF_INET:
620 dst = &ifr->ifr_addr;
621 size = sizeof(struct sockaddr_in);
622 break;
623#endif /* INET */
624#if INET6
625 case AF_INET6:
626 dst = (struct sockaddr *)
627 &(((struct in6_ifreq *)data)->ifr_addr);
628 size = sizeof(struct sockaddr_in6);
629 break;
630#endif /* INET6 */
631 default:
632 error = EADDRNOTAVAIL;
633 goto bad;
634 }
635 bcopy((caddr_t)src, (caddr_t)dst, size);
636 break;
637
638 case SIOCGIFPDSTADDR:
639#if INET6
640 case SIOCGIFPDSTADDR_IN6:
641#endif /* INET6 */
642 if (sc->gif_pdst == NULL) {
643 error = EADDRNOTAVAIL;
644 goto bad;
645 }
646 src = sc->gif_pdst;
647 switch (sc->gif_pdst->sa_family) {
648#if INET
649 case AF_INET:
650 dst = &ifr->ifr_addr;
651 size = sizeof(struct sockaddr_in);
652 break;
653#endif /* INET */
654#if INET6
655 case AF_INET6:
656 dst = (struct sockaddr *)
657 &(((struct in6_ifreq *)data)->ifr_addr);
658 size = sizeof(struct sockaddr_in6);
659 break;
660#endif /* INET6 */
661 default:
662 error = EADDRNOTAVAIL;
663 goto bad;
664 }
665 bcopy((caddr_t)src, (caddr_t)dst, size);
666 break;
667
668 case SIOCSIFFLAGS:
669 if (sc->gif_psrc == NULL)
670 break;
671 switch (sc->gif_psrc->sa_family) {
672#if INET
673 case AF_INET:
674 return in_gif_ioctl(ifp, cmd, data);
675#endif /* INET */
676#if INET6
677 case AF_INET6:
678 return in6_gif_ioctl(ifp, cmd, data);
679#endif /* INET6 */
680 default:
681 error = EPROTOTYPE;
682 goto bad;
683 break;
684 }
685 break;
686
687 default:
688 error = EINVAL;
689 break;
690 }
691 bad:
692 return error;
693}
694#endif /*NGIF > 0*/