]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/in_gif.c
   2  * Copyright (c) 2000-2007 Apple Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   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. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  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. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  28 /*      $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */ 
  31  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 
  32  * All rights reserved. 
  34  * Redistribution and use in source and binary forms, with or without 
  35  * modification, are permitted provided that the following conditions 
  37  * 1. Redistributions of source code must retain the above copyright 
  38  *    notice, this list of conditions and the following disclaimer. 
  39  * 2. Redistributions in binary form must reproduce the above copyright 
  40  *    notice, this list of conditions and the following disclaimer in the 
  41  *    documentation and/or other materials provided with the distribution. 
  42  * 3. Neither the name of the project nor the names of its contributors 
  43  *    may be used to endorse or promote products derived from this software 
  44  *    without specific prior written permission. 
  46  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 
  47  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  48  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  49  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 
  50  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
  51  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
  52  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  53  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
  54  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
  55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  60 #include <sys/param.h> 
  61 #include <sys/systm.h> 
  62 #include <sys/socket.h> 
  63 #include <sys/sockio.h> 
  65 #include <sys/errno.h> 
  66 #include <sys/kernel.h> 
  67 #include <sys/sysctl.h> 
  69 #include <sys/malloc.h> 
  70 #include <libkern/OSAtomic.h> 
  73 #include <net/route.h> 
  75 #include <netinet/in.h> 
  76 #include <netinet/in_systm.h> 
  77 #include <netinet/ip.h> 
  78 #include <netinet/ip_var.h> 
  79 #include <netinet/in_gif.h> 
  80 #include <netinet/in_var.h> 
  81 #include <netinet/ip_encap.h> 
  82 #include <netinet/ip_ecn.h> 
  85 #include <netinet/ip6.h> 
  89 #include <netinet/ip_mroute.h> 
  92 #include <net/if_gif.h>  
  94 #include <net/net_osdep.h> 
  96 extern u_long  route_generation
; 
  98 int ip_gif_ttl 
= GIF_TTL
; 
  99 SYSCTL_INT(_net_inet_ip
, IPCTL_GIF_TTL
, gifttl
, CTLFLAG_RW
, 
 107         __unused 
struct rtentry 
*rt
) 
 109         struct gif_softc 
*sc 
= ifnet_softc(ifp
); 
 110         struct sockaddr_in 
*dst 
= (struct sockaddr_in 
*)&sc
->gif_ro
.ro_dst
; 
 111         struct sockaddr_in 
*sin_src 
= (struct sockaddr_in 
*)sc
->gif_psrc
; 
 112         struct sockaddr_in 
*sin_dst 
= (struct sockaddr_in 
*)sc
->gif_pdst
; 
 113         struct ip iphdr
;        /* capsule IP header, host byte ordered */ 
 117         if (sin_src 
== NULL 
|| sin_dst 
== NULL 
|| 
 118             sin_src
->sin_family 
!= AF_INET 
|| 
 119             sin_dst
->sin_family 
!= AF_INET
) { 
 130                 proto 
= IPPROTO_IPV4
; 
 131                 if (mbuf_len(m
) < sizeof(*ip
)) { 
 132                         m 
= m_pullup(m
, sizeof(*ip
)); 
 136                 ip 
= mtod(m
, struct ip 
*); 
 145                 proto 
= IPPROTO_IPV6
; 
 146                 if (mbuf_len(m
) < sizeof(*ip6
)) { 
 147                         m 
= m_pullup(m
, sizeof(*ip6
)); 
 151                 ip6 
= mtod(m
, struct ip6_hdr 
*); 
 152                 tos 
= (ntohl(ip6
->ip6_flow
) >> 20) & 0xff; 
 158                 printf("in_gif_output: warning: unknown family %d passed\n", 
 165         bzero(&iphdr
, sizeof(iphdr
)); 
 166         iphdr
.ip_src 
= sin_src
->sin_addr
; 
 167         /* bidirectional configured tunnel mode */ 
 168         if (sin_dst
->sin_addr
.s_addr 
!= INADDR_ANY
) 
 169                 iphdr
.ip_dst 
= sin_dst
->sin_addr
; 
 175         /* version will be set in ip_output() */ 
 176         iphdr
.ip_ttl 
= ip_gif_ttl
; 
 177         iphdr
.ip_len 
= m
->m_pkthdr
.len 
+ sizeof(struct ip
); 
 178         if (ifp
->if_flags 
& IFF_LINK1
) 
 179                 ip_ecn_ingress(ECN_ALLOWED
, &iphdr
.ip_tos
, &tos
); 
 181                 ip_ecn_ingress(ECN_NOCARE
, &iphdr
.ip_tos
, &tos
); 
 183         /* prepend new IP header */ 
 184         M_PREPEND(m
, sizeof(struct ip
), M_DONTWAIT
); 
 185         if (m 
&& mbuf_len(m
) < sizeof(struct ip
)) 
 186                 m 
= m_pullup(m
, sizeof(struct ip
)); 
 188                 printf("ENOBUFS in in_gif_output %d\n", __LINE__
); 
 191         bcopy(&iphdr
, mtod(m
, struct ip 
*), sizeof(struct ip
)); 
 193         if (dst
->sin_family 
!= sin_dst
->sin_family 
|| 
 194             dst
->sin_addr
.s_addr 
!= sin_dst
->sin_addr
.s_addr 
|| 
 195             (sc
->gif_ro
.ro_rt 
!= NULL 
&& 
 196             (sc
->gif_ro
.ro_rt
->generation_id 
!= route_generation 
|| 
 197             sc
->gif_ro
.ro_rt
->rt_ifp 
== ifp
))) { 
 198                 /* cache route doesn't match */ 
 199                 dst
->sin_family 
= sin_dst
->sin_family
; 
 200                 dst
->sin_len 
= sizeof(struct sockaddr_in
); 
 201                 dst
->sin_addr 
= sin_dst
->sin_addr
; 
 202                 if (sc
->gif_ro
.ro_rt
) { 
 203                         rtfree(sc
->gif_ro
.ro_rt
); 
 204                         sc
->gif_ro
.ro_rt 
= NULL
; 
 207                 sc
->gif_if
.if_mtu 
= GIF_MTU
; 
 211         if (sc
->gif_ro
.ro_rt 
== NULL
) { 
 212                 rtalloc(&sc
->gif_ro
); 
 213                 if (sc
->gif_ro
.ro_rt 
== NULL
) { 
 218                 /* if it constitutes infinite encapsulation, punt. */ 
 219                 if (sc
->gif_ro
.ro_rt
->rt_ifp 
== ifp
) { 
 221                         return ENETUNREACH
;     /*XXX*/ 
 224                 ifp
->if_mtu 
= sc
->gif_ro
.ro_rt
->rt_ifp
->if_mtu
 
 229         error 
= ip_output(m
, NULL
, &sc
->gif_ro
, 0, NULL
, NULL
); 
 238         struct ifnet 
*gifp 
= NULL
; 
 243         ip 
= mtod(m
, struct ip 
*); 
 247         gifp 
= ((struct gif_softc
*)encap_getarg(m
))->gif_if
; 
 249         if (gifp 
== NULL 
|| (gifp
->if_flags 
& IFF_UP
) == 0) { 
 251                 OSAddAtomic(1, (SInt32
*)&ipstat
.ips_nogif
); 
 263                 if (mbuf_len(m
) < sizeof(*ip
)) { 
 264                         m 
= m_pullup(m
, sizeof(*ip
)); 
 268                 ip 
= mtod(m
, struct ip 
*); 
 269                 if (gifp
->if_flags 
& IFF_LINK1
) 
 270                         ip_ecn_egress(ECN_ALLOWED
, &otos
, &ip
->ip_tos
); 
 272                         ip_ecn_egress(ECN_NOCARE
, &otos
, &ip
->ip_tos
); 
 282                 if (mbuf_len(m
) < sizeof(*ip6
)) { 
 283                         m 
= m_pullup(m
, sizeof(*ip6
)); 
 287                 ip6 
= mtod(m
, struct ip6_hdr 
*); 
 288                 itos 
= (ntohl(ip6
->ip6_flow
) >> 20) & 0xff; 
 289                 if (gifp
->if_flags 
& IFF_LINK1
) 
 290                         ip_ecn_egress(ECN_ALLOWED
, &otos
, &itos
); 
 292                         ip_ecn_egress(ECN_NOCARE
, &otos
, &itos
); 
 293                 ip6
->ip6_flow 
&= ~htonl(0xff << 20); 
 294                 ip6
->ip6_flow 
|= htonl((u_int32_t
)itos 
<< 20); 
 299                 OSAddAtomic(1, (SInt32
*)&ipstat
.ips_nogif
); 
 304         /* Should we free m if dlil_input returns an error? */ 
 305         if (m
->m_pkthdr
.rcvif
)  /* replace the rcvif by gifp for dlil to route it correctly */ 
 306                 m
->m_pkthdr
.rcvif 
= gifp
; 
 307         ifnet_input(gifp
, m
, NULL
); 
 309         gif_input(m
, af
, gifp
); 
 314 static __inline__ 
void* 
 315 _cast_non_const(const void * ptr
) { 
 326  * we know that we are in IFF_UP, outer address available, and outer family 
 327  * matched the physical addr family.  see gif_encapcheck(). 
 331         const struct mbuf 
*m
, 
 337         struct gif_softc 
*sc
; 
 338         struct sockaddr_in 
*src
, *dst
; 
 340         struct in_ifaddr 
*ia4
; 
 342         /* sanity check done in caller */ 
 343         sc 
= (struct gif_softc 
*)arg
; 
 344         src 
= (struct sockaddr_in 
*)sc
->gif_psrc
; 
 345         dst 
= (struct sockaddr_in 
*)sc
->gif_pdst
; 
 347         mbuf_copydata(m
, 0, sizeof(ip
), &ip
); 
 349         /* check for address match */ 
 351         if (src
->sin_addr
.s_addr 
== ip
.ip_dst
.s_addr
) 
 353         if (dst
->sin_addr
.s_addr 
== ip
.ip_src
.s_addr
) 
 358         /* martian filters on outer source - NOT done in ip_input! */ 
 359         if (IN_MULTICAST(ntohl(ip
.ip_src
.s_addr
))) 
 361         switch ((ntohl(ip
.ip_src
.s_addr
) & 0xff000000) >> 24) { 
 362         case 0: case 127: case 255: 
 365         /* reject packets with broadcast on source */ 
 366         lck_mtx_lock(rt_mtx
); 
 367         for (ia4 
= TAILQ_FIRST(&in_ifaddrhead
); ia4
; 
 368              ia4 
= TAILQ_NEXT(ia4
, ia_link
)) 
 370                 if ((ifnet_flags(ia4
->ia_ifa
.ifa_ifp
) & IFF_BROADCAST
) == 0) 
 372                 if (ip
.ip_src
.s_addr 
== ia4
->ia_broadaddr
.sin_addr
.s_addr
) { 
 373                         lck_mtx_unlock(rt_mtx
); 
 377         lck_mtx_unlock(rt_mtx
); 
 379         /* ingress filters on outer source */ 
 380         if ((ifnet_flags(sc
->gif_if
) & IFF_LINK2
) == 0 && 
 381             (m
->m_flags 
& M_PKTHDR
) != 0 && m
->m_pkthdr
.rcvif
) { 
 382                 struct sockaddr_in sin
; 
 385                 bzero(&sin
, sizeof(sin
)); 
 386                 sin
.sin_family 
= AF_INET
; 
 387                 sin
.sin_len 
= sizeof(struct sockaddr_in
); 
 388                 sin
.sin_addr 
= ip
.ip_src
; 
 389                 rt 
= rtalloc1((struct sockaddr 
*)&sin
, 0, 0UL); 
 390                 if (!rt 
|| rt
->rt_ifp 
!= m
->m_pkthdr
.rcvif
) { 
 392                         log(LOG_WARNING
, "%s: packet from 0x%x dropped " 
 393                             "due to ingress filter\n", if_name(&sc
->gif_if
), 
 394                             (u_int32_t
)ntohl(sin
.sin_addr
.s_addr
));