1 /* $NetBSD: in6_gif.c,v 1.37 2003/10/30 01:43:09 simonb Exp $ */
2 /* $KAME: in6_gif.c,v 1.62 2001/07/29 04:27:25 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 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: in6_gif.c,v 1.37 2003/10/30 01:43:09 simonb Exp $");
35
36 #include "opt_inet.h"
37 #include "opt_iso.h"
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/socket.h>
42 #include <sys/sockio.h>
43 #include <sys/mbuf.h>
44 #include <sys/errno.h>
45 #include <sys/ioctl.h>
46 #include <sys/queue.h>
47 #include <sys/syslog.h>
48 #include <sys/protosw.h>
49
50 #include <net/if.h>
51 #include <net/route.h>
52
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #ifdef INET
56 #include <netinet/ip.h>
57 #endif
58 #include <netinet/ip_encap.h>
59 #ifdef INET6
60 #include <netinet/ip6.h>
61 #include <netinet6/ip6_var.h>
62 #include <netinet6/in6_gif.h>
63 #include <netinet6/in6_var.h>
64 #endif
65 #include <netinet6/ip6protosw.h>
66 #include <netinet/ip_ecn.h>
67
68 #include <net/if_gif.h>
69
70 #include <net/net_osdep.h>
71
72 static int gif_validate6 __P((const struct ip6_hdr *, struct gif_softc *,
73 struct ifnet *));
74
75 int ip6_gif_hlim = GIF_HLIM;
76
77 extern struct domain inet6domain;
78 struct ip6protosw in6_gif_protosw =
79 { SOCK_RAW, &inet6domain, 0/* IPPROTO_IPV[46] */, PR_ATOMIC|PR_ADDR,
80 in6_gif_input, rip6_output, in6_gif_ctlinput, rip6_ctloutput,
81 rip6_usrreq,
82 0, 0, 0, 0,
83 };
84
85 extern LIST_HEAD(, gif_softc) gif_softc_list;
86
87 int
88 in6_gif_output(ifp, family, m)
89 struct ifnet *ifp;
90 int family; /* family of the packet to be encapsulate. */
91 struct mbuf *m;
92 {
93 struct gif_softc *sc = (struct gif_softc*)ifp;
94 struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
95 struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
96 struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
97 struct ip6_hdr *ip6;
98 int proto, error;
99 u_int8_t itos, otos;
100
101 if (sin6_src == NULL || sin6_dst == NULL ||
102 sin6_src->sin6_family != AF_INET6 ||
103 sin6_dst->sin6_family != AF_INET6) {
104 m_freem(m);
105 return EAFNOSUPPORT;
106 }
107
108 switch (family) {
109 #ifdef INET
110 case AF_INET:
111 {
112 struct ip *ip;
113
114 proto = IPPROTO_IPV4;
115 if (m->m_len < sizeof(*ip)) {
116 m = m_pullup(m, sizeof(*ip));
117 if (!m)
118 return ENOBUFS;
119 }
120 ip = mtod(m, struct ip *);
121 itos = ip->ip_tos;
122 break;
123 }
124 #endif
125 #ifdef INET6
126 case AF_INET6:
127 {
128 struct ip6_hdr *ip6;
129 proto = IPPROTO_IPV6;
130 if (m->m_len < sizeof(*ip6)) {
131 m = m_pullup(m, sizeof(*ip6));
132 if (!m)
133 return ENOBUFS;
134 }
135 ip6 = mtod(m, struct ip6_hdr *);
136 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
137 break;
138 }
139 #endif
140 #ifdef ISO
141 case AF_ISO:
142 proto = IPPROTO_EON;
143 itos = 0;
144 break;
145 #endif
146 default:
147 #ifdef DEBUG
148 printf("in6_gif_output: warning: unknown family %d passed\n",
149 family);
150 #endif
151 m_freem(m);
152 return EAFNOSUPPORT;
153 }
154
155 /* prepend new IP header */
156 M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
157 if (m && m->m_len < sizeof(struct ip6_hdr))
158 m = m_pullup(m, sizeof(struct ip6_hdr));
159 if (m == NULL)
160 return ENOBUFS;
161
162 ip6 = mtod(m, struct ip6_hdr *);
163 ip6->ip6_flow = 0;
164 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
165 ip6->ip6_vfc |= IPV6_VERSION;
166 #if 0 /* ip6->ip6_plen will be filled by ip6_output */
167 ip6->ip6_plen = htons((u_int16_t)m->m_pkthdr.len);
168 #endif
169 ip6->ip6_nxt = proto;
170 ip6->ip6_hlim = ip6_gif_hlim;
171 ip6->ip6_src = sin6_src->sin6_addr;
172 /* bidirectional configured tunnel mode */
173 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
174 ip6->ip6_dst = sin6_dst->sin6_addr;
175 else {
176 m_freem(m);
177 return ENETUNREACH;
178 }
179 if (ifp->if_flags & IFF_LINK1)
180 ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
181 else
182 ip_ecn_ingress(ECN_NOCARE, &otos, &itos);
183 ip6->ip6_flow &= ~ntohl(0xff00000);
184 ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
185
186 if (dst->sin6_family != sin6_dst->sin6_family ||
187 !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
188 /* cache route doesn't match */
189 bzero(dst, sizeof(*dst));
190 dst->sin6_family = sin6_dst->sin6_family;
191 dst->sin6_len = sizeof(struct sockaddr_in6);
192 dst->sin6_addr = sin6_dst->sin6_addr;
193 if (sc->gif_ro6.ro_rt) {
194 RTFREE(sc->gif_ro6.ro_rt);
195 sc->gif_ro6.ro_rt = NULL;
196 }
197 }
198
199 if (sc->gif_ro6.ro_rt == NULL) {
200 rtalloc((struct route *)&sc->gif_ro6);
201 if (sc->gif_ro6.ro_rt == NULL) {
202 m_freem(m);
203 return ENETUNREACH;
204 }
205
206 /* if it constitutes infinite encapsulation, punt. */
207 if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
208 m_freem(m);
209 return ENETUNREACH; /* XXX */
210 }
211 }
212
213 #ifdef 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 error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU,
220 (struct ip6_moptions *)NULL, (struct socket *)NULL, NULL);
221 #else
222 error = ip6_output(m, 0, &sc->gif_ro6, 0,
223 (struct ip6_moptions *)NULL, (struct socket *)NULL, NULL);
224 #endif
225
226 return (error);
227 }
228
229 int in6_gif_input(mp, offp, proto)
230 struct mbuf **mp;
231 int *offp, proto;
232 {
233 struct mbuf *m = *mp;
234 struct ifnet *gifp = NULL;
235 struct ip6_hdr *ip6;
236 int af = 0;
237 u_int32_t otos;
238
239 ip6 = mtod(m, struct ip6_hdr *);
240
241 gifp = (struct ifnet *)encap_getarg(m);
242
243 if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
244 m_freem(m);
245 ip6stat.ip6s_nogif++;
246 return IPPROTO_DONE;
247 }
248 #ifndef GIF_ENCAPCHECK
249 if (!gif_validate6(ip6, (struct gif_softc *)gifp, m->m_pkthdr.rcvif)) {
250 m_freem(m);
251 ip6stat.ip6s_nogif++;
252 return IPPROTO_DONE;
253 }
254 #endif
255
256 otos = ip6->ip6_flow;
257 m_adj(m, *offp);
258
259 switch (proto) {
260 #ifdef INET
261 case IPPROTO_IPV4:
262 {
263 struct ip *ip;
264 u_int8_t otos8;
265 af = AF_INET;
266 otos8 = (ntohl(otos) >> 20) & 0xff;
267 if (m->m_len < sizeof(*ip)) {
268 m = m_pullup(m, sizeof(*ip));
269 if (!m)
270 return IPPROTO_DONE;
271 }
272 ip = mtod(m, struct ip *);
273 if (gifp->if_flags & IFF_LINK1)
274 ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos);
275 else
276 ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos);
277 break;
278 }
279 #endif /* INET */
280 #ifdef INET6
281 case IPPROTO_IPV6:
282 {
283 struct ip6_hdr *ip6;
284 af = AF_INET6;
285 if (m->m_len < sizeof(*ip6)) {
286 m = m_pullup(m, sizeof(*ip6));
287 if (!m)
288 return IPPROTO_DONE;
289 }
290 ip6 = mtod(m, struct ip6_hdr *);
291 if (gifp->if_flags & IFF_LINK1)
292 ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow);
293 else
294 ip6_ecn_egress(ECN_NOCARE, &otos, &ip6->ip6_flow);
295 break;
296 }
297 #endif
298 #ifdef ISO
299 case IPPROTO_EON:
300 af = AF_ISO;
301 break;
302 #endif
303 default:
304 ip6stat.ip6s_nogif++;
305 m_freem(m);
306 return IPPROTO_DONE;
307 }
308
309 gif_input(m, af, gifp);
310 return IPPROTO_DONE;
311 }
312
313 /*
314 * validate outer address.
315 */
316 static int
317 gif_validate6(ip6, sc, ifp)
318 const struct ip6_hdr *ip6;
319 struct gif_softc *sc;
320 struct ifnet *ifp;
321 {
322 struct sockaddr_in6 *src, *dst;
323
324 src = (struct sockaddr_in6 *)sc->gif_psrc;
325 dst = (struct sockaddr_in6 *)sc->gif_pdst;
326
327 /* check for address match */
328 if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) ||
329 !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src))
330 return 0;
331
332 /* martian filters on outer source - done in ip6_input */
333
334 /* ingress filters on outer source */
335 if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) {
336 struct sockaddr_in6 sin6;
337 struct rtentry *rt;
338
339 bzero(&sin6, sizeof(sin6));
340 sin6.sin6_family = AF_INET6;
341 sin6.sin6_len = sizeof(struct sockaddr_in6);
342 sin6.sin6_addr = ip6->ip6_src;
343 /* XXX scopeid */
344 rt = rtalloc1((struct sockaddr *)&sin6, 0);
345 if (!rt || rt->rt_ifp != ifp) {
346 #if 0
347 log(LOG_WARNING, "%s: packet from %s dropped "
348 "due to ingress filter\n", if_name(&sc->gif_if),
349 ip6_sprintf(&sin6.sin6_addr));
350 #endif
351 if (rt)
352 rtfree(rt);
353 return 0;
354 }
355 rtfree(rt);
356 }
357
358 return 128 * 2;
359 }
360
361 #ifdef GIF_ENCAPCHECK
362 /*
363 * we know that we are in IFF_UP, outer address available, and outer family
364 * matched the physical addr family. see gif_encapcheck().
365 */
366 int
367 gif_encapcheck6(m, off, proto, arg)
368 const struct mbuf *m;
369 int off;
370 int proto;
371 void *arg;
372 {
373 struct ip6_hdr ip6;
374 struct gif_softc *sc;
375 struct ifnet *ifp;
376
377 /* sanity check done in caller */
378 sc = (struct gif_softc *)arg;
379
380 /* LINTED const cast */
381 m_copydata((struct mbuf *)m, 0, sizeof(ip6), (caddr_t)&ip6);
382 ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
383
384 return gif_validate6(&ip6, sc, ifp);
385 }
386 #endif
387
388 int
389 in6_gif_attach(sc)
390 struct gif_softc *sc;
391 {
392 #ifndef GIF_ENCAPCHECK
393 struct sockaddr_in6 mask6;
394
395 bzero(&mask6, sizeof(mask6));
396 mask6.sin6_len = sizeof(struct sockaddr_in6);
397 mask6.sin6_addr.s6_addr32[0] = mask6.sin6_addr.s6_addr32[1] =
398 mask6.sin6_addr.s6_addr32[2] = mask6.sin6_addr.s6_addr32[3] = ~0;
399
400 if (!sc->gif_psrc || !sc->gif_pdst)
401 return EINVAL;
402 sc->encap_cookie6 = encap_attach(AF_INET6, -1, sc->gif_psrc,
403 (struct sockaddr *)&mask6, sc->gif_pdst, (struct sockaddr *)&mask6,
404 (void *)&in6_gif_protosw, sc);
405 #else
406 sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck,
407 (struct protosw *)&in6_gif_protosw, sc);
408 #endif
409 if (sc->encap_cookie6 == NULL)
410 return EEXIST;
411 return 0;
412 }
413
414 int
415 in6_gif_detach(sc)
416 struct gif_softc *sc;
417 {
418 int error;
419
420 error = encap_detach(sc->encap_cookie6);
421 if (error == 0)
422 sc->encap_cookie6 = NULL;
423 return error;
424 }
425
426 void
427 in6_gif_ctlinput(cmd, sa, d)
428 int cmd;
429 struct sockaddr *sa;
430 void *d;
431 {
432 struct gif_softc *sc;
433 struct ip6ctlparam *ip6cp = NULL;
434 struct ip6_hdr *ip6;
435 struct sockaddr_in6 *dst6;
436
437 if (sa->sa_family != AF_INET6 ||
438 sa->sa_len != sizeof(struct sockaddr_in6))
439 return;
440
441 if ((unsigned)cmd >= PRC_NCMDS)
442 return;
443 if (cmd == PRC_HOSTDEAD)
444 d = NULL;
445 else if (inet6ctlerrmap[cmd] == 0)
446 return;
447
448 /* if the parameter is from icmp6, decode it. */
449 if (d != NULL) {
450 ip6cp = (struct ip6ctlparam *)d;
451 ip6 = ip6cp->ip6c_ip6;
452 } else {
453 ip6 = NULL;
454 }
455
456 if (!ip6)
457 return;
458
459 /*
460 * for now we don't care which type it was, just flush the route cache.
461 * XXX slow. sc (or sc->encap_cookie6) should be passed from
462 * ip_encap.c.
463 */
464 for (sc = LIST_FIRST(&gif_softc_list); sc;
465 sc = LIST_NEXT(sc, gif_list)) {
466 if ((sc->gif_if.if_flags & IFF_RUNNING) == 0)
467 continue;
468 if (sc->gif_psrc->sa_family != AF_INET6)
469 continue;
470 if (!sc->gif_ro6.ro_rt)
471 continue;
472
473 dst6 = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
474 /* XXX scope */
475 if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst6->sin6_addr)) {
476 /* flush route cache */
477 RTFREE(sc->gif_ro6.ro_rt);
478 sc->gif_ro6.ro_rt = NULL;
479 }
480 }
481 }
Cache object: 3e473e4254e26181d273703077056fa1
|