]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet/in_gif.c
xnu-792.13.8.tar.gz
[apple/xnu.git] / bsd / netinet / in_gif.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
8ad349bb 4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
1c79356b 5 *
8ad349bb
A
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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
1c79356b 29 */
9bccf70c 30/* $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */
1c79356b
A
31
32/*
33 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the project nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
1c79356b
A
61
62#include <sys/param.h>
63#include <sys/systm.h>
64#include <sys/socket.h>
65#include <sys/sockio.h>
1c79356b
A
66#include <sys/mbuf.h>
67#include <sys/errno.h>
1c79356b
A
68#include <sys/kernel.h>
69#include <sys/sysctl.h>
1c79356b 70
1c79356b 71#include <sys/malloc.h>
1c79356b
A
72
73#include <net/if.h>
74#include <net/route.h>
1c79356b
A
75
76#include <netinet/in.h>
77#include <netinet/in_systm.h>
78#include <netinet/ip.h>
79#include <netinet/ip_var.h>
80#include <netinet/in_gif.h>
81#include <netinet/in_var.h>
82#include <netinet/ip_encap.h>
83#include <netinet/ip_ecn.h>
84
85#if INET6
86#include <netinet/ip6.h>
87#endif
88
89#if MROUTING
90#include <netinet/ip_mroute.h>
91#endif /* MROUTING */
92
93#include <net/if_gif.h>
94
1c79356b
A
95#include <net/net_osdep.h>
96
9bccf70c
A
97int ip_gif_ttl = GIF_TTL;
98SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW,
99 &ip_gif_ttl, 0, "");
1c79356b
A
100
101int
91447636
A
102in_gif_output(
103 struct ifnet *ifp,
104 int family,
105 struct mbuf *m,
106 struct rtentry *rt)
1c79356b 107{
9bccf70c 108 struct gif_softc *sc = (struct gif_softc*)ifp;
1c79356b
A
109 struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst;
110 struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc;
111 struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst;
112 struct ip iphdr; /* capsule IP header, host byte ordered */
113 int proto, error;
114 u_int8_t tos;
115
116 if (sin_src == NULL || sin_dst == NULL ||
117 sin_src->sin_family != AF_INET ||
118 sin_dst->sin_family != AF_INET) {
1c79356b
A
119 m_freem(m);
120 return EAFNOSUPPORT;
121 }
122
123 switch (family) {
124#if INET
125 case AF_INET:
126 {
127 struct ip *ip;
128
129 proto = IPPROTO_IPV4;
130 if (m->m_len < sizeof(*ip)) {
131 m = m_pullup(m, sizeof(*ip));
132 if (!m)
133 return ENOBUFS;
134 }
135 ip = mtod(m, struct ip *);
136 tos = ip->ip_tos;
137 break;
138 }
139#endif /*INET*/
140#if INET6
141 case AF_INET6:
142 {
143 struct ip6_hdr *ip6;
144 proto = IPPROTO_IPV6;
145 if (m->m_len < sizeof(*ip6)) {
146 m = m_pullup(m, sizeof(*ip6));
147 if (!m)
148 return ENOBUFS;
149 }
150 ip6 = mtod(m, struct ip6_hdr *);
151 tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
152 break;
153 }
154#endif /*INET6*/
155 default:
156#if DEBUG
157 printf("in_gif_output: warning: unknown family %d passed\n",
158 family);
159#endif
160 m_freem(m);
161 return EAFNOSUPPORT;
162 }
163
164 bzero(&iphdr, sizeof(iphdr));
165 iphdr.ip_src = sin_src->sin_addr;
9bccf70c
A
166 /* bidirectional configured tunnel mode */
167 if (sin_dst->sin_addr.s_addr != INADDR_ANY)
168 iphdr.ip_dst = sin_dst->sin_addr;
169 else {
170 m_freem(m);
171 return ENETUNREACH;
1c79356b
A
172 }
173 iphdr.ip_p = proto;
174 /* version will be set in ip_output() */
175 iphdr.ip_ttl = ip_gif_ttl;
176 iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip);
177 if (ifp->if_flags & IFF_LINK1)
178 ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos);
9bccf70c
A
179 else
180 ip_ecn_ingress(ECN_NOCARE, &iphdr.ip_tos, &tos);
1c79356b
A
181
182 /* prepend new IP header */
183 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
184 if (m && m->m_len < sizeof(struct ip))
185 m = m_pullup(m, sizeof(struct ip));
186 if (m == NULL) {
187 printf("ENOBUFS in in_gif_output %d\n", __LINE__);
188 return ENOBUFS;
189 }
9bccf70c 190 bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip));
1c79356b
A
191
192 if (dst->sin_family != sin_dst->sin_family ||
193 dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) {
194 /* cache route doesn't match */
195 dst->sin_family = sin_dst->sin_family;
196 dst->sin_len = sizeof(struct sockaddr_in);
197 dst->sin_addr = sin_dst->sin_addr;
198 if (sc->gif_ro.ro_rt) {
9bccf70c 199 rtfree(sc->gif_ro.ro_rt);
1c79356b
A
200 sc->gif_ro.ro_rt = NULL;
201 }
202#if 0
203 sc->gif_if.if_mtu = GIF_MTU;
204#endif
205 }
206
207 if (sc->gif_ro.ro_rt == NULL) {
208 rtalloc(&sc->gif_ro);
209 if (sc->gif_ro.ro_rt == NULL) {
210 m_freem(m);
211 return ENETUNREACH;
212 }
9bccf70c
A
213
214 /* if it constitutes infinite encapsulation, punt. */
215 if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
216 m_freem(m);
217 return ENETUNREACH; /*XXX*/
218 }
1c79356b
A
219#if 0
220 ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu
221 - sizeof(struct ip);
222#endif
223 }
224
1c79356b 225 error = ip_output(m, NULL, &sc->gif_ro, 0, NULL);
1c79356b
A
226 return(error);
227}
228
229void
230in_gif_input(m, off)
231 struct mbuf *m;
232 int off;
233{
1c79356b
A
234 struct ifnet *gifp = NULL;
235 struct ip *ip;
236 int i, af, proto;
237 u_int8_t otos;
238
1c79356b 239 ip = mtod(m, struct ip *);
9bccf70c 240 proto = ip->ip_p;
1c79356b 241
1c79356b 242
1c79356b 243 gifp = (struct ifnet *)encap_getarg(m);
1c79356b 244
9bccf70c 245 if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
1c79356b
A
246 m_freem(m);
247 ipstat.ips_nogif++;
248 return;
249 }
250
251 otos = ip->ip_tos;
252 m_adj(m, off);
253
254 switch (proto) {
255#if INET
256 case IPPROTO_IPV4:
257 {
258 struct ip *ip;
259 af = AF_INET;
260 if (m->m_len < sizeof(*ip)) {
261 m = m_pullup(m, sizeof(*ip));
262 if (!m)
263 return;
264 }
265 ip = mtod(m, struct ip *);
266 if (gifp->if_flags & IFF_LINK1)
267 ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos);
9bccf70c
A
268 else
269 ip_ecn_egress(ECN_NOCARE, &otos, &ip->ip_tos);
1c79356b
A
270 break;
271 }
272#endif
273#if INET6
274 case IPPROTO_IPV6:
275 {
276 struct ip6_hdr *ip6;
277 u_int8_t itos;
278 af = AF_INET6;
279 if (m->m_len < sizeof(*ip6)) {
280 m = m_pullup(m, sizeof(*ip6));
281 if (!m)
282 return;
283 }
284 ip6 = mtod(m, struct ip6_hdr *);
285 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
286 if (gifp->if_flags & IFF_LINK1)
287 ip_ecn_egress(ECN_ALLOWED, &otos, &itos);
9bccf70c
A
288 else
289 ip_ecn_egress(ECN_NOCARE, &otos, &itos);
1c79356b
A
290 ip6->ip6_flow &= ~htonl(0xff << 20);
291 ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
292 break;
293 }
294#endif /* INET6 */
295 default:
296 ipstat.ips_nogif++;
297 m_freem(m);
298 return;
299 }
9bccf70c
A
300#ifdef __APPLE__
301 /* Should we free m if dlil_input returns an error? */
302 if (m->m_pkthdr.rcvif) /* replace the rcvif by gifp for dlil to route it correctly */
303 m->m_pkthdr.rcvif = gifp;
304 dlil_input_packet(gifp, m, NULL);
305#else
1c79356b 306 gif_input(m, af, gifp);
9bccf70c 307#endif
1c79356b
A
308 return;
309}
310
9bccf70c
A
311/*
312 * we know that we are in IFF_UP, outer address available, and outer family
313 * matched the physical addr family. see gif_encapcheck().
314 */
1c79356b 315int
9bccf70c
A
316gif_encapcheck4(m, off, proto, arg)
317 const struct mbuf *m;
318 int off;
319 int proto;
320 void *arg;
1c79356b 321{
9bccf70c
A
322 struct ip ip;
323 struct gif_softc *sc;
324 struct sockaddr_in *src, *dst;
325 int addrmatch;
326 struct in_ifaddr *ia4;
327
328 /* sanity check done in caller */
329 sc = (struct gif_softc *)arg;
330 src = (struct sockaddr_in *)sc->gif_psrc;
331 dst = (struct sockaddr_in *)sc->gif_pdst;
332
333 /* LINTED const cast */
334 m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
335
336 /* check for address match */
337 addrmatch = 0;
338 if (src->sin_addr.s_addr == ip.ip_dst.s_addr)
339 addrmatch |= 1;
340 if (dst->sin_addr.s_addr == ip.ip_src.s_addr)
341 addrmatch |= 2;
342 if (addrmatch != 3)
343 return 0;
344
345 /* martian filters on outer source - NOT done in ip_input! */
346 if (IN_MULTICAST(ntohl(ip.ip_src.s_addr)))
347 return 0;
348 switch ((ntohl(ip.ip_src.s_addr) & 0xff000000) >> 24) {
349 case 0: case 127: case 255:
350 return 0;
351 }
352 /* reject packets with broadcast on source */
91447636 353 lck_mtx_lock(rt_mtx);
9bccf70c
A
354 for (ia4 = TAILQ_FIRST(&in_ifaddrhead); ia4;
355 ia4 = TAILQ_NEXT(ia4, ia_link))
356 {
357 if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0)
358 continue;
91447636
A
359 if (ip.ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) {
360 lck_mtx_unlock(rt_mtx);
9bccf70c 361 return 0;
91447636 362 }
9bccf70c 363 }
91447636 364 lck_mtx_unlock(rt_mtx);
1c79356b 365
9bccf70c
A
366 /* ingress filters on outer source */
367 if ((sc->gif_if.if_flags & IFF_LINK2) == 0 &&
368 (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) {
369 struct sockaddr_in sin;
370 struct rtentry *rt;
371
372 bzero(&sin, sizeof(sin));
373 sin.sin_family = AF_INET;
374 sin.sin_len = sizeof(struct sockaddr_in);
375 sin.sin_addr = ip.ip_src;
376 rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL);
377 if (!rt || rt->rt_ifp != m->m_pkthdr.rcvif) {
378#if 0
379 log(LOG_WARNING, "%s: packet from 0x%x dropped "
380 "due to ingress filter\n", if_name(&sc->gif_if),
381 (u_int32_t)ntohl(sin.sin_addr.s_addr));
382#endif
383 if (rt)
384 rtfree(rt);
385 return 0;
1c79356b 386 }
9bccf70c 387 rtfree(rt);
1c79356b
A
388 }
389
9bccf70c 390 return 32 * 2;
1c79356b 391}