Annotation of src/sys/netinet6/in6_gif.c, Revision 1.14.4.1
1.14.4.1! he 1: /* $NetBSD: in6_gif.c,v 1.14 2000/04/19 06:30:56 itojun Exp $ */
! 2: /* $KAME: in6_gif.c,v 1.43 2001/01/22 07:27:17 itojun Exp $ */
1.3 thorpej 3:
1.2 itojun 4: /*
5: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6: * All rights reserved.
1.14 itojun 7: *
1.2 itojun 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.
1.14 itojun 19: *
1.2 itojun 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: * in6_gif.c
35: */
36:
1.14 itojun 37: #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
1.2 itojun 38: #include "opt_inet.h"
1.14 itojun 39: #endif
1.2 itojun 40:
41: #include <sys/param.h>
42: #include <sys/systm.h>
43: #include <sys/socket.h>
44: #include <sys/sockio.h>
45: #include <sys/mbuf.h>
46: #include <sys/errno.h>
1.14 itojun 47: #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
1.2 itojun 48: #include <sys/ioctl.h>
1.14 itojun 49: #endif
1.14.4.1! he 50: #include <sys/queue.h>
! 51: #include <sys/syslog.h>
1.14 itojun 52:
53: #if defined(__FreeBSD__) && __FreeBSD__ >= 3
54: #include <sys/malloc.h>
55: #endif
1.2 itojun 56:
57: #include <net/if.h>
58: #include <net/route.h>
59:
60: #include <netinet/in.h>
61: #include <netinet/in_systm.h>
62: #ifdef INET
63: #include <netinet/ip.h>
64: #endif
1.14 itojun 65: #include <netinet/ip_encap.h>
1.11 itojun 66: #ifdef INET6
67: #include <netinet/ip6.h>
1.2 itojun 68: #include <netinet6/ip6_var.h>
69: #include <netinet6/in6_gif.h>
1.14 itojun 70: #include <netinet6/in6_var.h>
1.2 itojun 71: #endif
72: #include <netinet/ip_ecn.h>
73:
74: #include <net/if_gif.h>
75:
1.8 itojun 76: #include <net/net_osdep.h>
77:
1.2 itojun 78: int
79: in6_gif_output(ifp, family, m, rt)
80: struct ifnet *ifp;
81: int family; /* family of the packet to be encapsulate. */
82: struct mbuf *m;
83: struct rtentry *rt;
84: {
85: struct gif_softc *sc = (struct gif_softc*)ifp;
86: struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
87: struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
88: struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
89: struct ip6_hdr *ip6;
90: int proto;
91: u_int8_t itos, otos;
92:
93: if (sin6_src == NULL || sin6_dst == NULL ||
94: sin6_src->sin6_family != AF_INET6 ||
95: sin6_dst->sin6_family != AF_INET6) {
96: m_freem(m);
97: return EAFNOSUPPORT;
98: }
99:
100: switch (family) {
101: #ifdef INET
102: case AF_INET:
103: {
104: struct ip *ip;
105:
106: proto = IPPROTO_IPV4;
107: if (m->m_len < sizeof(*ip)) {
108: m = m_pullup(m, sizeof(*ip));
109: if (!m)
110: return ENOBUFS;
111: }
112: ip = mtod(m, struct ip *);
113: itos = ip->ip_tos;
114: break;
115: }
116: #endif
117: #ifdef INET6
118: case AF_INET6:
119: {
120: struct ip6_hdr *ip6;
121: proto = IPPROTO_IPV6;
122: if (m->m_len < sizeof(*ip6)) {
123: m = m_pullup(m, sizeof(*ip6));
124: if (!m)
125: return ENOBUFS;
126: }
127: ip6 = mtod(m, struct ip6_hdr *);
128: itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
129: break;
130: }
131: #endif
132: default:
1.12 itojun 133: #ifdef DEBUG
1.2 itojun 134: printf("in6_gif_output: warning: unknown family %d passed\n",
135: family);
136: #endif
137: m_freem(m);
138: return EAFNOSUPPORT;
139: }
140:
141: /* prepend new IP header */
142: M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
143: if (m && m->m_len < sizeof(struct ip6_hdr))
144: m = m_pullup(m, sizeof(struct ip6_hdr));
145: if (m == NULL) {
146: printf("ENOBUFS in in6_gif_output %d\n", __LINE__);
147: return ENOBUFS;
148: }
149:
150: ip6 = mtod(m, struct ip6_hdr *);
151: ip6->ip6_flow = 0;
1.9 itojun 152: ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
153: ip6->ip6_vfc |= IPV6_VERSION;
1.2 itojun 154: ip6->ip6_plen = htons((u_short)m->m_pkthdr.len);
155: ip6->ip6_nxt = proto;
156: ip6->ip6_hlim = ip6_gif_hlim;
157: ip6->ip6_src = sin6_src->sin6_addr;
158: if (ifp->if_flags & IFF_LINK0) {
159: /* multi-destination mode */
160: if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
161: ip6->ip6_dst = sin6_dst->sin6_addr;
162: else if (rt) {
1.8 itojun 163: if (family != AF_INET6) {
164: m_freem(m);
165: return EINVAL; /*XXX*/
166: }
1.2 itojun 167: ip6->ip6_dst = ((struct sockaddr_in6 *)(rt->rt_gateway))->sin6_addr;
168: } else {
169: m_freem(m);
170: return ENETUNREACH;
171: }
172: } else {
173: /* bidirectional configured tunnel mode */
174: if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
175: ip6->ip6_dst = sin6_dst->sin6_addr;
176: else {
177: m_freem(m);
178: return ENETUNREACH;
179: }
180: }
181: if (ifp->if_flags & IFF_LINK1) {
182: otos = 0;
183: ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
184: ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
185: }
186:
187: if (dst->sin6_family != sin6_dst->sin6_family ||
188: !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
189: /* cache route doesn't match */
190: bzero(dst, sizeof(*dst));
191: dst->sin6_family = sin6_dst->sin6_family;
192: dst->sin6_len = sizeof(struct sockaddr_in6);
193: dst->sin6_addr = sin6_dst->sin6_addr;
194: if (sc->gif_ro6.ro_rt) {
195: RTFREE(sc->gif_ro6.ro_rt);
196: sc->gif_ro6.ro_rt = NULL;
197: }
198: #if 0
199: sc->gif_if.if_mtu = GIF_MTU;
200: #endif
201: }
202:
203: if (sc->gif_ro6.ro_rt == NULL) {
204: rtalloc((struct route *)&sc->gif_ro6);
205: if (sc->gif_ro6.ro_rt == NULL) {
206: m_freem(m);
207: return ENETUNREACH;
208: }
1.14 itojun 209:
210: /* if it constitutes infinite encapsulation, punt. */
211: if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
212: m_freem(m);
213: return ENETUNREACH; /*XXX*/
214: }
1.2 itojun 215: #if 0
216: ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu
217: - sizeof(struct ip6_hdr);
218: #endif
219: }
220:
1.14 itojun 221: #ifdef IPV6_MINMTU
222: /*
223: * force fragmentation to minimum MTU, to avoid path MTU discovery.
224: * it is too painful to ask for resend of inner packet, to achieve
225: * path MTU discovery for encapsulated packets.
226: */
227: return(ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL));
228: #else
1.8 itojun 229: return(ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL));
1.14 itojun 230: #endif
1.2 itojun 231: }
232:
233: int in6_gif_input(mp, offp, proto)
234: struct mbuf **mp;
235: int *offp, proto;
236: {
237: struct mbuf *m = *mp;
238: struct ifnet *gifp = NULL;
239: struct ip6_hdr *ip6;
240: int af = 0;
241: u_int32_t otos;
242:
243: ip6 = mtod(m, struct ip6_hdr *);
244:
1.14 itojun 245: gifp = (struct ifnet *)encap_getarg(m);
1.2 itojun 246:
1.14 itojun 247: if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
1.2 itojun 248: m_freem(m);
249: ip6stat.ip6s_nogif++;
250: return IPPROTO_DONE;
251: }
1.14 itojun 252:
1.2 itojun 253: otos = ip6->ip6_flow;
254: m_adj(m, *offp);
255:
256: switch (proto) {
257: #ifdef INET
258: case IPPROTO_IPV4:
259: {
260: struct ip *ip;
261: u_int8_t otos8;
262: af = AF_INET;
263: otos8 = (ntohl(otos) >> 20) & 0xff;
264: if (m->m_len < sizeof(*ip)) {
265: m = m_pullup(m, sizeof(*ip));
266: if (!m)
267: return IPPROTO_DONE;
268: }
269: ip = mtod(m, struct ip *);
270: if (gifp->if_flags & IFF_LINK1)
271: ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos);
272: break;
273: }
274: #endif /* INET */
275: #ifdef INET6
276: case IPPROTO_IPV6:
277: {
278: struct ip6_hdr *ip6;
279: af = AF_INET6;
280: if (m->m_len < sizeof(*ip6)) {
281: m = m_pullup(m, sizeof(*ip6));
282: if (!m)
283: return IPPROTO_DONE;
284: }
285: ip6 = mtod(m, struct ip6_hdr *);
286: if (gifp->if_flags & IFF_LINK1)
287: ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow);
288: break;
289: }
290: #endif
291: default:
292: ip6stat.ip6s_nogif++;
293: m_freem(m);
294: return IPPROTO_DONE;
295: }
296:
297: gif_input(m, af, gifp);
298: return IPPROTO_DONE;
1.14 itojun 299: }
300:
301: /*
302: * we know that we are in IFF_UP, outer address available, and outer family
303: * matched the physical addr family. see gif_encapcheck().
304: */
305: int
306: gif_encapcheck6(m, off, proto, arg)
307: const struct mbuf *m;
308: int off;
309: int proto;
310: void *arg;
311: {
312: struct ip6_hdr ip6;
313: struct gif_softc *sc;
314: struct sockaddr_in6 *src, *dst;
315: int addrmatch;
316:
317: /* sanity check done in caller */
318: sc = (struct gif_softc *)arg;
319: src = (struct sockaddr_in6 *)sc->gif_psrc;
320: dst = (struct sockaddr_in6 *)sc->gif_pdst;
321:
322: /* LINTED const cast */
323: m_copydata((struct mbuf *)m, 0, sizeof(ip6), (caddr_t)&ip6);
324:
325: /* check for address match */
326: addrmatch = 0;
327: if (IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6.ip6_dst))
328: addrmatch |= 1;
329: if (IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6.ip6_src))
330: addrmatch |= 2;
331: else if ((sc->gif_if.if_flags & IFF_LINK0) != 0 &&
332: IN6_IS_ADDR_UNSPECIFIED(&dst->sin6_addr)) {
333: addrmatch |= 2; /* we accept any source */
334: }
335: if (addrmatch != 3)
336: return 0;
337:
338: /* martian filters on outer source - done in ip6_input */
339:
340: /* ingress filters on outer source */
1.14.4.1! he 341: if ((sc->gif_if.if_flags & IFF_LINK2) == 0 &&
! 342: (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) {
1.14 itojun 343: struct sockaddr_in6 sin6;
344: struct rtentry *rt;
345:
346: bzero(&sin6, sizeof(sin6));
347: sin6.sin6_family = AF_INET6;
348: sin6.sin6_len = sizeof(struct sockaddr_in6);
349: sin6.sin6_addr = ip6.ip6_src;
350: /* XXX scopeid */
351: #ifdef __FreeBSD__
352: rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
353: #else
354: rt = rtalloc1((struct sockaddr *)&sin6, 0);
355: #endif
1.14.4.1! he 356: if (!rt || rt->rt_ifp != m->m_pkthdr.rcvif) {
! 357: #if 0
! 358: log(LOG_WARNING, "%s: packet from %s dropped "
! 359: "due to ingress filter\n", if_name(&sc->gif_if),
! 360: ip6_sprintf(&sin6.sin6_addr));
! 361: #endif
! 362: if (rt)
! 363: rtfree(rt);
1.14 itojun 364: return 0;
365: }
366: rtfree(rt);
367: }
368:
369: /* prioritize: IFF_LINK0 mode is less preferred */
370: return (sc->gif_if.if_flags & IFF_LINK0) ? 128 : 128 * 2;
1.2 itojun 371: }
CVSweb <webmaster@jp.NetBSD.org>