]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/in6_gif.c
xnu-1228.7.58.tar.gz
[apple/xnu.git] / bsd / netinet6 / in6_gif.c
1 /* $FreeBSD: src/sys/netinet6/in6_gif.c,v 1.2.2.3 2001/07/03 11:01:52 ume Exp $ */
2 /* $KAME: in6_gif.c,v 1.49 2001/05/14 14:02:17 itojun Exp $ */
3
4 /*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/socket.h>
37 #include <sys/sockio.h>
38 #include <sys/mbuf.h>
39 #include <sys/errno.h>
40 #include <sys/queue.h>
41 #include <sys/syslog.h>
42
43 #include <sys/malloc.h>
44 #include <sys/protosw.h>
45
46 #include <net/if.h>
47 #include <net/route.h>
48
49 #include <netinet/in.h>
50 #include <netinet/in_systm.h>
51 #if INET
52 #include <netinet/ip.h>
53 #endif
54 #include <netinet/ip_encap.h>
55 #if INET6
56 #include <netinet/ip6.h>
57 #include <netinet6/ip6_var.h>
58 #include <netinet6/in6_gif.h>
59 #include <netinet6/in6_var.h>
60 #endif
61 #include <netinet/ip_ecn.h>
62 #if INET6
63 #include <netinet6/ip6_ecn.h>
64 #endif
65
66 #include <net/if_gif.h>
67
68 #include <net/net_osdep.h>
69
70 extern u_long route_generation;
71
72 static __inline__ void*
73 _cast_non_const(const void * ptr) {
74 union {
75 const void* cval;
76 void* val;
77 } ret;
78
79 ret.cval = ptr;
80 return (ret.val);
81 }
82
83 int
84 in6_gif_output(
85 struct ifnet *ifp,
86 int family, /* family of the packet to be encapsulate. */
87 struct mbuf *m,
88 __unused struct rtentry *rt)
89 {
90 struct gif_softc *sc = ifnet_softc(ifp);
91 struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
92 struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
93 struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
94 struct ip6_hdr *ip6;
95 int proto;
96 u_int8_t itos, otos;
97
98 if (sin6_src == NULL || sin6_dst == NULL ||
99 sin6_src->sin6_family != AF_INET6 ||
100 sin6_dst->sin6_family != AF_INET6) {
101 m_freem(m);
102 return EAFNOSUPPORT;
103 }
104
105 switch (family) {
106 #if INET
107 case AF_INET:
108 {
109 struct ip *ip;
110
111 proto = IPPROTO_IPV4;
112 if (mbuf_len(m) < sizeof(*ip)) {
113 m = m_pullup(m, sizeof(*ip));
114 if (!m)
115 return ENOBUFS;
116 }
117 ip = mtod(m, struct ip *);
118 itos = ip->ip_tos;
119 break;
120 }
121 #endif
122 #if INET6
123 case AF_INET6:
124 {
125 proto = IPPROTO_IPV6;
126 if (mbuf_len(m) < sizeof(*ip6)) {
127 m = m_pullup(m, sizeof(*ip6));
128 if (!m)
129 return ENOBUFS;
130 }
131 ip6 = mtod(m, struct ip6_hdr *);
132 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
133 break;
134 }
135 #endif
136 default:
137 #if DEBUG
138 printf("in6_gif_output: warning: unknown family %d passed\n",
139 family);
140 #endif
141 m_freem(m);
142 return EAFNOSUPPORT;
143 }
144
145 /* prepend new IP header */
146 M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
147 if (m && mbuf_len(m) < sizeof(struct ip6_hdr))
148 m = m_pullup(m, sizeof(struct ip6_hdr));
149 if (m == NULL) {
150 printf("ENOBUFS in in6_gif_output %d\n", __LINE__);
151 return ENOBUFS;
152 }
153
154 ip6 = mtod(m, struct ip6_hdr *);
155 ip6->ip6_flow = 0;
156 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
157 ip6->ip6_vfc |= IPV6_VERSION;
158 ip6->ip6_plen = htons((u_short)m->m_pkthdr.len);
159 ip6->ip6_nxt = proto;
160 ip6->ip6_hlim = ip6_gif_hlim;
161 ip6->ip6_src = sin6_src->sin6_addr;
162 /* bidirectional configured tunnel mode */
163 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
164 ip6->ip6_dst = sin6_dst->sin6_addr;
165 else {
166 m_freem(m);
167 return ENETUNREACH;
168 }
169 if (ifp->if_flags & IFF_LINK1)
170 ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
171 else
172 ip_ecn_ingress(ECN_NOCARE, &otos, &itos);
173 ip6->ip6_flow &= ~ntohl(0xff00000);
174 ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
175
176 if (dst->sin6_family != sin6_dst->sin6_family ||
177 !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr) ||
178 (sc->gif_ro6.ro_rt != NULL &&
179 (sc->gif_ro6.ro_rt->generation_id != route_generation ||
180 sc->gif_ro6.ro_rt->rt_ifp == ifp))) {
181 /* cache route doesn't match */
182 bzero(dst, sizeof(*dst));
183 dst->sin6_family = sin6_dst->sin6_family;
184 dst->sin6_len = sizeof(struct sockaddr_in6);
185 dst->sin6_addr = sin6_dst->sin6_addr;
186 if (sc->gif_ro6.ro_rt) {
187 rtfree(sc->gif_ro6.ro_rt);
188 sc->gif_ro6.ro_rt = NULL;
189 }
190 #if 0
191 sc->gif_if.if_mtu = GIF_MTU;
192 #endif
193 }
194
195 if (sc->gif_ro6.ro_rt == NULL) {
196 rtalloc((struct route *)&sc->gif_ro6);
197 if (sc->gif_ro6.ro_rt == NULL) {
198 m_freem(m);
199 return ENETUNREACH;
200 }
201
202 /* if it constitutes infinite encapsulation, punt. */
203 if (sc->gif_ro6.ro_rt->rt_ifp == ifp) {
204 m_freem(m);
205 return ENETUNREACH; /*XXX*/
206 }
207 #if 0
208 ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu
209 - sizeof(struct ip6_hdr);
210 #endif
211 }
212
213 #if IPV6_MINMTU
214 /*
215 * force fragmentation to minimum MTU, to avoid path MTU discovery.
216 * it is too painful to ask for resend of inner packet, to achieve
217 * path MTU discovery for encapsulated packets.
218 */
219 return(ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL, 0));
220 #else
221 return(ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL, 0));
222 #endif
223 }
224
225 int in6_gif_input(mp, offp)
226 struct mbuf **mp;
227 int *offp;
228 {
229 struct mbuf *m = *mp;
230 struct ifnet *gifp = NULL;
231 struct ip6_hdr *ip6;
232 int af = 0;
233 u_int32_t otos;
234 u_int8_t proto;
235
236 ip6 = mtod(m, struct ip6_hdr *);
237
238 gifp = ((struct gif_softc*)encap_getarg(m))->gif_if;
239
240 if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
241 m_freem(m);
242 ip6stat.ip6s_nogif++;
243 return IPPROTO_DONE;
244 }
245
246 proto = ip6->ip6_nxt;
247 otos = ip6->ip6_flow;
248 m_adj(m, *offp);
249
250 switch (proto) {
251 #if INET
252 case IPPROTO_IPV4:
253 {
254 struct ip *ip;
255 u_int8_t otos8;
256 af = AF_INET;
257 otos8 = (ntohl(otos) >> 20) & 0xff;
258 if (mbuf_len(m) < sizeof(*ip)) {
259 m = m_pullup(m, sizeof(*ip));
260 if (!m)
261 return IPPROTO_DONE;
262 }
263 ip = mtod(m, struct ip *);
264 if (gifp->if_flags & IFF_LINK1)
265 ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos);
266 else
267 ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos);
268 break;
269 }
270 #endif /* INET */
271 #if INET6
272 case IPPROTO_IPV6:
273 {
274 af = AF_INET6;
275 if (mbuf_len(m) < sizeof(*ip6)) {
276 m = m_pullup(m, sizeof(*ip6));
277 if (!m)
278 return IPPROTO_DONE;
279 }
280 ip6 = mtod(m, struct ip6_hdr *);
281 if (gifp->if_flags & IFF_LINK1)
282 ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow);
283 else
284 ip6_ecn_egress(ECN_NOCARE, &otos, &ip6->ip6_flow);
285 break;
286 }
287 #endif
288 default:
289 ip6stat.ip6s_nogif++;
290 m_freem(m);
291 return IPPROTO_DONE;
292 }
293
294 if (m->m_pkthdr.rcvif) /* replace the rcvif by gifp for ifnet_input to route it correctly */
295 m->m_pkthdr.rcvif = gifp;
296
297 ifnet_input(gifp, m, NULL);
298 return IPPROTO_DONE;
299 }
300
301 /*
302 * validate outer address.
303 */
304 static int
305 gif_validate6(
306 const struct ip6_hdr *ip6,
307 struct gif_softc *sc,
308 struct ifnet *ifp)
309 {
310 struct sockaddr_in6 *src, *dst;
311
312 src = (struct sockaddr_in6 *)sc->gif_psrc;
313 dst = (struct sockaddr_in6 *)sc->gif_pdst;
314
315 /*
316 * Check for address match. Note that the check is for an incoming
317 * packet. We should compare the *source* address in our configuration
318 * and the *destination* address of the packet, and vice versa.
319 */
320 if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) ||
321 !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src))
322 return 0;
323
324 /* martian filters on outer source - done in ip6_input */
325
326 /* ingress filters on outer source */
327 if ((ifnet_flags(sc->gif_if) & IFF_LINK2) == 0 && ifp) {
328 struct sockaddr_in6 sin6;
329 struct rtentry *rt;
330
331 bzero(&sin6, sizeof(sin6));
332 sin6.sin6_family = AF_INET6;
333 sin6.sin6_len = sizeof(struct sockaddr_in6);
334 sin6.sin6_addr = ip6->ip6_src;
335 #ifndef SCOPEDROUTING
336 sin6.sin6_scope_id = 0; /* XXX */
337 #endif
338
339 rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
340 if (!rt || rt->rt_ifp != ifp) {
341 #if 0
342 log(LOG_WARNING, "%s: packet from %s dropped "
343 "due to ingress filter\n", if_name(&sc->gif_if),
344 ip6_sprintf(&sin6.sin6_addr));
345 #endif
346 if (rt)
347 rtfree(rt);
348 return 0;
349 }
350 rtfree(rt);
351 }
352
353 return 128 * 2;
354 }
355
356 /*
357 * we know that we are in IFF_UP, outer address available, and outer family
358 * matched the physical addr family. see gif_encapcheck().
359 * sanity check for arg should have been done in the caller.
360 */
361 int
362 gif_encapcheck6(
363 const struct mbuf *m,
364 __unused int off,
365 __unused int proto,
366 void *arg)
367 {
368 struct ip6_hdr ip6;
369 struct gif_softc *sc;
370 struct ifnet *ifp;
371
372 /* sanity check done in caller */
373 sc = (struct gif_softc *)arg;
374
375 mbuf_copydata(m, 0, sizeof(ip6), &ip6);
376 ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
377
378 return gif_validate6(&ip6, sc, ifp);
379 }