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