1 /* $FreeBSD: src/sys/netinet6/in6_gif.c,v 1.2.2.7 2003/01/23 21:06:47 sam Exp $ */
2 /* $KAME: in6_gif.c,v 1.49 2001/05/14 14:02:17 itojun Exp $ */
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
34 #include "opt_inet6.h"
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/socket.h>
39 #include <sys/sockio.h>
41 #include <sys/errno.h>
42 #include <sys/queue.h>
43 #include <sys/syslog.h>
44 #include <sys/protosw.h>
46 #include <sys/malloc.h>
49 #include <net/route.h>
51 #include <netinet/in.h>
52 #include <netinet/in_systm.h>
54 #include <netinet/ip.h>
56 #include <netinet/ip_encap.h>
58 #include <netinet/ip6.h>
59 #include <netinet6/ip6_var.h>
60 #include <netinet6/in6_gif.h>
61 #include <netinet6/in6_var.h>
63 #include <netinet6/ip6protosw.h>
64 #include <netinet/ip_ecn.h>
66 #include <netinet6/ip6_ecn.h>
69 #include <net/gif/if_gif.h>
71 #include <net/net_osdep.h>
74 static int gif_validate6(const struct ip6_hdr
*, struct gif_softc
*,
77 extern struct domain inet6domain
;
78 struct protosw in6_gif_protosw
=
81 .pr_domain
= &inet6domain
,
82 .pr_protocol
= 0 /* IPPROTO_IPV[46] */,
83 .pr_flags
= PR_ATOMIC
|PR_ADDR
,
85 .pr_input
= in6_gif_input
,
86 .pr_output
= rip6_output
,
88 .pr_ctloutput
= rip6_ctloutput
,
90 .pr_usrreqs
= &rip6_usrreqs
94 * family = family of the packet to be encapsulate.
97 in6_gif_output(struct ifnet
*ifp
, int family
, struct mbuf
*m
)
99 struct gif_softc
*sc
= (struct gif_softc
*)ifp
;
100 struct route_in6
*ro
= &sc
->gif_ro6
[mycpu
->gd_cpuid
];
101 struct sockaddr_in6
*dst
= (struct sockaddr_in6
*)&ro
->ro_dst
;
102 struct sockaddr_in6
*sin6_src
= (struct sockaddr_in6
*)sc
->gif_psrc
;
103 struct sockaddr_in6
*sin6_dst
= (struct sockaddr_in6
*)sc
->gif_pdst
;
108 if (sin6_src
== NULL
|| sin6_dst
== NULL
||
109 sin6_src
->sin6_family
!= AF_INET6
||
110 sin6_dst
->sin6_family
!= AF_INET6
) {
121 proto
= IPPROTO_IPV4
;
122 if (m
->m_len
< sizeof(*ip
)) {
123 m
= m_pullup(m
, sizeof(*ip
));
127 ip
= mtod(m
, struct ip
*);
136 proto
= IPPROTO_IPV6
;
137 if (m
->m_len
< sizeof(*ip6
)) {
138 m
= m_pullup(m
, sizeof(*ip6
));
142 ip6
= mtod(m
, struct ip6_hdr
*);
143 itos
= (ntohl(ip6
->ip6_flow
) >> 20) & 0xff;
149 kprintf("in6_gif_output: warning: unknown family %d passed\n",
156 /* prepend new IP header */
157 M_PREPEND(m
, sizeof(struct ip6_hdr
), M_NOWAIT
);
158 if (m
&& m
->m_len
< sizeof(struct ip6_hdr
))
159 m
= m_pullup(m
, sizeof(struct ip6_hdr
));
161 kprintf("ENOBUFS in in6_gif_output %d\n", __LINE__
);
165 ip6
= mtod(m
, struct ip6_hdr
*);
167 ip6
->ip6_vfc
&= ~IPV6_VERSION_MASK
;
168 ip6
->ip6_vfc
|= IPV6_VERSION
;
169 ip6
->ip6_plen
= htons((u_short
)m
->m_pkthdr
.len
);
170 ip6
->ip6_nxt
= proto
;
171 ip6
->ip6_hlim
= ip6_gif_hlim
;
172 ip6
->ip6_src
= sin6_src
->sin6_addr
;
173 /* bidirectional configured tunnel mode */
174 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst
->sin6_addr
))
175 ip6
->ip6_dst
= sin6_dst
->sin6_addr
;
180 if (ifp
->if_flags
& IFF_LINK1
)
181 ip_ecn_ingress(ECN_ALLOWED
, &otos
, &itos
);
183 ip_ecn_ingress(ECN_NOCARE
, &otos
, &itos
);
184 ip6
->ip6_flow
&= ~ntohl(0xff00000);
185 ip6
->ip6_flow
|= htonl((u_int32_t
)otos
<< 20);
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 (ro
->ro_rt
!= NULL
) {
199 sc
->gif_if
.if_mtu
= GIF_MTU
;
203 if (ro
->ro_rt
== NULL
) {
204 rtalloc((struct route
*)ro
);
205 if (ro
->ro_rt
== NULL
) {
210 /* if it constitutes infinite encapsulation, punt. */
211 if (ro
->ro_rt
->rt_ifp
== ifp
) {
213 return ENETUNREACH
; /*XXX*/
216 ifp
->if_mtu
= ro
->ro_rt
->rt_ifp
->if_mtu
-
217 sizeof(struct ip6_hdr
);
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.
227 return (ip6_output(m
, 0, ro
, IPV6_MINMTU
, 0, NULL
, NULL
));
229 return (ip6_output(m
, 0, ro
, 0, 0, NULL
, NULL
));
234 in6_gif_input(struct mbuf
**mp
, int *offp
, int proto
)
236 struct mbuf
*m
= *mp
;
237 struct ifnet
*gifp
= NULL
;
242 ip6
= mtod(m
, struct ip6_hdr
*);
244 gifp
= (struct ifnet
*)encap_getarg(m
);
246 if (gifp
== NULL
|| !(gifp
->if_flags
& IFF_UP
)) {
248 ip6stat
.ip6s_nogif
++;
252 otos
= ip6
->ip6_flow
;
262 otos8
= (ntohl(otos
) >> 20) & 0xff;
263 if (m
->m_len
< sizeof(*ip
)) {
264 m
= m_pullup(m
, sizeof(*ip
));
268 ip
= mtod(m
, struct ip
*);
269 if (gifp
->if_flags
& IFF_LINK1
)
270 ip_ecn_egress(ECN_ALLOWED
, &otos8
, &ip
->ip_tos
);
272 ip_ecn_egress(ECN_NOCARE
, &otos8
, &ip
->ip_tos
);
281 if (m
->m_len
< sizeof(*ip6
)) {
282 m
= m_pullup(m
, sizeof(*ip6
));
286 ip6
= mtod(m
, struct ip6_hdr
*);
287 if (gifp
->if_flags
& IFF_LINK1
)
288 ip6_ecn_egress(ECN_ALLOWED
, &otos
, &ip6
->ip6_flow
);
290 ip6_ecn_egress(ECN_NOCARE
, &otos
, &ip6
->ip6_flow
);
295 ip6stat
.ip6s_nogif
++;
300 gif_input(m
, af
, gifp
);
305 * validate outer address.
308 gif_validate6(const struct ip6_hdr
*ip6
, struct gif_softc
*sc
,
311 struct sockaddr_in6
*src
, *dst
;
313 src
= (struct sockaddr_in6
*)sc
->gif_psrc
;
314 dst
= (struct sockaddr_in6
*)sc
->gif_pdst
;
317 * Check for address match. Note that the check is for an incoming
318 * packet. We should compare the *source* address in our configuration
319 * and the *destination* address of the packet, and vice versa.
321 if (!IN6_ARE_ADDR_EQUAL(&src
->sin6_addr
, &ip6
->ip6_dst
) ||
322 !IN6_ARE_ADDR_EQUAL(&dst
->sin6_addr
, &ip6
->ip6_src
))
325 /* martian filters on outer source - done in ip6_input */
327 /* ingress filters on outer source */
328 if (!(sc
->gif_if
.if_flags
& IFF_LINK2
) && ifp
) {
329 struct sockaddr_in6 sin6
;
332 bzero(&sin6
, sizeof(sin6
));
333 sin6
.sin6_family
= AF_INET6
;
334 sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
335 sin6
.sin6_addr
= ip6
->ip6_src
;
336 sin6
.sin6_scope_id
= 0; /* XXX */
338 rt
= rtpurelookup((struct sockaddr
*)&sin6
);
341 if (rt
== NULL
|| rt
->rt_ifp
!= ifp
) {
343 log(LOG_WARNING
, "%s: packet from %s dropped "
344 "due to ingress filter\n", if_name(&sc
->gif_if
),
345 ip6_sprintf(&sin6
.sin6_addr
));
355 * we know that we are in IFF_UP, outer address available, and outer family
356 * matched the physical addr family. see gif_encapcheck().
357 * sanity check for arg should have been done in the caller.
360 gif_encapcheck6(const struct mbuf
*m
, int off
, int proto
, void *arg
)
363 struct gif_softc
*sc
;
366 /* sanity check done in caller */
367 sc
= (struct gif_softc
*)arg
;
369 m_copydata(m
, 0, sizeof(ip6
), (caddr_t
)&ip6
);
370 ifp
= (m
->m_flags
& M_PKTHDR
) ? m
->m_pkthdr
.rcvif
: NULL
;
372 return gif_validate6(&ip6
, sc
, ifp
);
376 in6_gif_attach(struct gif_softc
*sc
)
378 sc
->encap_cookie6
= encap_attach_func(AF_INET6
, -1, gif_encapcheck
,
379 &in6_gif_protosw
, sc
);
380 if (sc
->encap_cookie6
== NULL
)
386 in6_gif_detach(struct gif_softc
*sc
)
390 error
= encap_detach(sc
->encap_cookie6
);
392 sc
->encap_cookie6
= NULL
;