Deleted Added
full compact
1/*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/sys/netinet6/in6_gif.c 54263 1999-12-07 17:39:16Z shin $
29 * $FreeBSD: head/sys/netinet6/in6_gif.c 55009 1999-12-22 19:13:38Z shin $
30 */
31
32/*
33 * in6_gif.c
34 */
35
36#include "opt_inet.h"
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/socket.h>
41#include <sys/sockio.h>
42#include <sys/mbuf.h>
43#include <sys/errno.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#ifdef INET
52#include <netinet/ip.h>
53#endif
54#include <netinet6/ip6.h>
55#include <netinet6/ip6_var.h>
56#include <netinet6/in6_gif.h>
57#include <netinet6/ip6.h>
58#include <netinet/ip_ecn.h>
59#include <netinet6/ip6_ecn.h>
60
61#include <net/if_gif.h>
62
63#include <net/net_osdep.h>
64
65int
66in6_gif_output(ifp, family, m, rt)
67 struct ifnet *ifp;
68 int family; /* family of the packet to be encapsulate. */
69 struct mbuf *m;
70 struct rtentry *rt;
71{
72 struct gif_softc *sc = (struct gif_softc*)ifp;
73 struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
74 struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
75 struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
76 struct ip6_hdr *ip6;
77 int proto;
78 u_int8_t itos, otos;
79
80 if (sin6_src == NULL || sin6_dst == NULL ||
81 sin6_src->sin6_family != AF_INET6 ||
82 sin6_dst->sin6_family != AF_INET6) {
83 m_freem(m);
84 return EAFNOSUPPORT;
85 }
86
87 switch (family) {
88#ifdef INET
89 case AF_INET:
90 {
91 struct ip *ip;
92
93 proto = IPPROTO_IPV4;
94 if (m->m_len < sizeof(*ip)) {
95 m = m_pullup(m, sizeof(*ip));
96 if (!m)
97 return ENOBUFS;
98 }
99 ip = mtod(m, struct ip *);
100 itos = ip->ip_tos;
101 break;
102 }
103#endif
104 case AF_INET6:
105 {
106 struct ip6_hdr *ip6;
107 proto = IPPROTO_IPV6;
108 if (m->m_len < sizeof(*ip6)) {
109 m = m_pullup(m, sizeof(*ip6));
110 if (!m)
111 return ENOBUFS;
112 }
113 ip6 = mtod(m, struct ip6_hdr *);
114 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
115 break;
116 }
117 default:
118#ifdef DIAGNOSTIC
119 printf("in6_gif_output: warning: unknown family %d passed\n",
120 family);
121#endif
122 m_freem(m);
123 return EAFNOSUPPORT;
124 }
125
126 /* prepend new IP header */
127 M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
128 if (m && m->m_len < sizeof(struct ip6_hdr))
129 m = m_pullup(m, sizeof(struct ip6_hdr));
130 if (m == NULL) {
131 printf("ENOBUFS in in6_gif_output %d\n", __LINE__);
132 return ENOBUFS;
133 }
134
135 ip6 = mtod(m, struct ip6_hdr *);
136 ip6->ip6_flow = 0;
137 ip6->ip6_vfc = IPV6_VERSION;
138 ip6->ip6_plen = htons((u_short)m->m_pkthdr.len);
139 ip6->ip6_nxt = proto;
140 ip6->ip6_hlim = ip6_gif_hlim;
141 ip6->ip6_src = sin6_src->sin6_addr;
142 if (ifp->if_flags & IFF_LINK0) {
143 /* multi-destination mode */
144 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
145 ip6->ip6_dst = sin6_dst->sin6_addr;
146 else if (rt) {
147 ip6->ip6_dst = ((struct sockaddr_in6 *)(rt->rt_gateway))->sin6_addr;
148 } else {
149 m_freem(m);
150 return ENETUNREACH;
151 }
152 } else {
153 /* bidirectional configured tunnel mode */
154 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
155 ip6->ip6_dst = sin6_dst->sin6_addr;
156 else {
157 m_freem(m);
158 return ENETUNREACH;
159 }
160 }
161 if (ifp->if_flags & IFF_LINK1) {
162 otos = 0;
163 ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
164 ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
165 }
166
167 if (dst->sin6_family != sin6_dst->sin6_family ||
168 !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
169 /* cache route doesn't match */
170 bzero(dst, sizeof(*dst));
171 dst->sin6_family = sin6_dst->sin6_family;
172 dst->sin6_len = sizeof(struct sockaddr_in6);
173 dst->sin6_addr = sin6_dst->sin6_addr;
174 if (sc->gif_ro6.ro_rt) {
175 RTFREE(sc->gif_ro6.ro_rt);
176 sc->gif_ro6.ro_rt = NULL;
177 }
178 }
179
180 if (sc->gif_ro6.ro_rt == NULL) {
181 rtalloc((struct route *)&sc->gif_ro6);
182 if (sc->gif_ro6.ro_rt == NULL) {
183 m_freem(m);
184 return ENETUNREACH;
185 }
186 }
187
178#ifdef IPSEC
179 m->m_pkthdr.rcvif = NULL;
180#endif /*IPSEC*/
188 return(ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL));
189}
190
191int in6_gif_input(mp, offp, proto)
192 struct mbuf **mp;
193 int *offp, proto;
194{
195 struct mbuf *m = *mp;
196 struct gif_softc *sc;
197 struct ifnet *gifp = NULL;
198 struct ip6_hdr *ip6;
199 int i;
200 int af = 0;
201 u_int32_t otos;
202
203 ip6 = mtod(m, struct ip6_hdr *);
204
205#define satoin6(sa) (((struct sockaddr_in6 *)(sa))->sin6_addr)
206 for (i = 0, sc = gif; i < ngif; i++, sc++) {
207 if (sc->gif_psrc == NULL ||
208 sc->gif_pdst == NULL ||
209 sc->gif_psrc->sa_family != AF_INET6 ||
210 sc->gif_pdst->sa_family != AF_INET6) {
211 continue;
212 }
213 if ((sc->gif_if.if_flags & IFF_UP) == 0)
214 continue;
215 if ((sc->gif_if.if_flags & IFF_LINK0) &&
216 IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) &&
217 IN6_IS_ADDR_UNSPECIFIED(&satoin6(sc->gif_pdst))) {
218 gifp = &sc->gif_if;
219 continue;
220 }
221 if (IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) &&
222 IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_pdst), &ip6->ip6_src)) {
223 gifp = &sc->gif_if;
224 break;
225 }
226 }
227
228 if (gifp == NULL) {
229 m_freem(m);
230 ip6stat.ip6s_nogif++;
231 return IPPROTO_DONE;
232 }
225
233
234 otos = ip6->ip6_flow;
235 m_adj(m, *offp);
236
237 switch (proto) {
238#ifdef INET
239 case IPPROTO_IPV4:
240 {
241 struct ip *ip;
242 u_int8_t otos8;
243 af = AF_INET;
244 otos8 = (ntohl(otos) >> 20) & 0xff;
245 if (m->m_len < sizeof(*ip)) {
246 m = m_pullup(m, sizeof(*ip));
247 if (!m)
248 return IPPROTO_DONE;
249 }
250 ip = mtod(m, struct ip *);
251 if (gifp->if_flags & IFF_LINK1)
252 ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos);
253 break;
254 }
255#endif /* INET */
256 case IPPROTO_IPV6:
257 {
258 struct ip6_hdr *ip6;
259 af = AF_INET6;
260 if (m->m_len < sizeof(*ip6)) {
261 m = m_pullup(m, sizeof(*ip6));
262 if (!m)
263 return IPPROTO_DONE;
264 }
265 ip6 = mtod(m, struct ip6_hdr *);
266 if (gifp->if_flags & IFF_LINK1)
267 ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow);
268 break;
269 }
270 default:
271 ip6stat.ip6s_nogif++;
272 m_freem(m);
273 return IPPROTO_DONE;
274 }
275
276 gif_input(m, af, gifp);
277 return IPPROTO_DONE;
278}