1 /* $KAME: in6_gif.c,v 1.27 2000/03/25 07:23:43 sumikawa Exp $ */
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/socket.h>
43 #include <sys/sockio.h>
45 #include <sys/errno.h>
46 #if !defined(__FreeBSD__) || __FreeBSD__ < 3
47 #include <sys/ioctl.h>
49 #include <sys/malloc.h>
50 #include <sys/protosw.h>
53 #include <net/route.h>
55 #include <netinet/in.h>
56 #include <netinet/in_systm.h>
58 #include <netinet/ip.h>
60 #include <netinet/ip_encap.h>
62 #include <netinet/ip6.h>
63 #include <netinet6/ip6_var.h>
64 #include <netinet6/in6_gif.h>
65 #include <netinet6/in6_var.h>
66 #include <netinet6/ip6protosw.h>
68 #include <netinet/ip_ecn.h>
70 #include <net/if_gif.h>
72 #include <net/net_osdep.h>
75 extern struct ip6protosw in6_gif_protosw
;
79 in6_gif_output(ifp
, family
, m
, rt
)
81 int family
; /* family of the packet to be encapsulate. */
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
;
93 if (sin6_src
== NULL
|| sin6_dst
== NULL
||
94 sin6_src
->sin6_family
!= AF_INET6
||
95 sin6_dst
->sin6_family
!= AF_INET6
) {
106 proto
= IPPROTO_IPV4
;
107 if (m
->m_len
< sizeof(*ip
)) {
108 m
= m_pullup(m
, sizeof(*ip
));
112 ip
= mtod(m
, struct ip
*);
121 proto
= IPPROTO_IPV6
;
122 if (m
->m_len
< sizeof(*ip6
)) {
123 m
= m_pullup(m
, sizeof(*ip6
));
127 ip6
= mtod(m
, struct ip6_hdr
*);
128 itos
= (ntohl(ip6
->ip6_flow
) >> 20) & 0xff;
134 printf("in6_gif_output: warning: unknown family %d passed\n",
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
));
146 printf("ENOBUFS in in6_gif_output %d\n", __LINE__
);
150 ip6
= mtod(m
, struct ip6_hdr
*);
152 ip6
->ip6_vfc
&= ~IPV6_VERSION_MASK
;
153 ip6
->ip6_vfc
|= IPV6_VERSION
;
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
;
163 if (family
!= AF_INET6
) {
165 return EINVAL
; /*XXX*/
167 ip6
->ip6_dst
= ((struct sockaddr_in6
*)(rt
->rt_gateway
))->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
;
181 if (ifp
->if_flags
& IFF_LINK1
) {
183 ip_ecn_ingress(ECN_ALLOWED
, &otos
, &itos
);
184 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 (sc
->gif_ro6
.ro_rt
) {
195 RTFREE(sc
->gif_ro6
.ro_rt
);
196 sc
->gif_ro6
.ro_rt
= NULL
;
199 sc
->gif_if
.if_mtu
= GIF_MTU
;
203 if (sc
->gif_ro6
.ro_rt
== NULL
) {
204 rtalloc((struct route
*)&sc
->gif_ro6
);
205 if (sc
->gif_ro6
.ro_rt
== NULL
) {
210 ifp
->if_mtu
= sc
->gif_ro6
.ro_rt
->rt_ifp
->if_mtu
211 - sizeof(struct ip6_hdr
);
215 return(ip6_output(m
, 0, &sc
->gif_ro6
, 0, 0, NULL
));
218 int in6_gif_input(mp
, offp
, proto
)
222 struct mbuf
*m
= *mp
;
224 struct gif_softc
*sc
;
226 struct ifnet
*gifp
= NULL
;
234 ip6
= mtod(m
, struct ip6_hdr
*);
237 #define satoin6(sa) (((struct sockaddr_in6 *)(sa))->sin6_addr)
238 for (i
= 0, sc
= gif
; i
< ngif
; i
++, sc
++) {
239 if (sc
->gif_psrc
== NULL
||
240 sc
->gif_pdst
== NULL
||
241 sc
->gif_psrc
->sa_family
!= AF_INET6
||
242 sc
->gif_pdst
->sa_family
!= AF_INET6
) {
245 if ((sc
->gif_if
.if_flags
& IFF_UP
) == 0)
247 if ((sc
->gif_if
.if_flags
& IFF_LINK0
) &&
248 IN6_ARE_ADDR_EQUAL(&satoin6(sc
->gif_psrc
), &ip6
->ip6_dst
) &&
249 IN6_IS_ADDR_UNSPECIFIED(&satoin6(sc
->gif_pdst
))) {
253 if (IN6_ARE_ADDR_EQUAL(&satoin6(sc
->gif_psrc
), &ip6
->ip6_dst
) &&
254 IN6_ARE_ADDR_EQUAL(&satoin6(sc
->gif_pdst
), &ip6
->ip6_src
)) {
260 gifp
= (struct ifnet
*)encap_getarg(m
);
265 ip6stat
.ip6s_nogif
++;
269 if ((gifp
->if_flags
& IFF_UP
) == 0) {
271 ip6stat
.ip6s_nogif
++;
275 otos
= ip6
->ip6_flow
;
285 otos8
= (ntohl(otos
) >> 20) & 0xff;
286 if (m
->m_len
< sizeof(*ip
)) {
287 m
= m_pullup(m
, sizeof(*ip
));
291 ip
= mtod(m
, struct ip
*);
292 if (gifp
->if_flags
& IFF_LINK1
)
293 ip_ecn_egress(ECN_ALLOWED
, &otos8
, &ip
->ip_tos
);
302 if (m
->m_len
< sizeof(*ip6
)) {
303 m
= m_pullup(m
, sizeof(*ip6
));
307 ip6
= mtod(m
, struct ip6_hdr
*);
308 if (gifp
->if_flags
& IFF_LINK1
)
309 ip6_ecn_egress(ECN_ALLOWED
, &otos
, &ip6
->ip6_flow
);
314 ip6stat
.ip6s_nogif
++;
319 gif_input(m
, af
, gifp
);
324 in6_gif_ioctl(ifp
, cmd
, data
)
326 #if defined(__FreeBSD__) && __FreeBSD__ < 3
333 struct gif_softc
*sc
= (struct gif_softc
*)ifp
;
334 struct ifreq
*ifr
= (struct ifreq
*)data
;
336 struct sockaddr
*sa
, *dst
, *src
;
337 const struct encaptab
*p
;
338 struct sockaddr_in6 smask6
, dmask6
;
343 * whenever we change our idea about multi-destination mode
344 * we need to update encap attachment.
346 if (((ifp
->if_flags
^ sc
->gif_oflags
) & IFF_LINK0
) == 0)
348 if (sc
->gif_psrc
== NULL
|| sc
->gif_pdst
== NULL
||
349 sc
->gif_psrc
->sa_family
!= sc
->gif_pdst
->sa_family
)
351 bzero(&smask6
, sizeof(smask6
));
352 smask6
.sin6_addr
.s6_addr32
[0] = ~0;
353 smask6
.sin6_addr
.s6_addr32
[1] = ~0;
354 smask6
.sin6_addr
.s6_addr32
[2] = ~0;
355 smask6
.sin6_addr
.s6_addr32
[3] = ~0;
356 #if 0 /* we'll need to do this soon */
357 smask6
.sin6_scope_id
= ~0;
360 if ((ifp
->if_flags
& IFF_LINK0
) == 0 &&
361 IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6
*)dst
)->sin6_addr
)) {
362 bzero(&dmask6
, sizeof(dmask6
));
363 #if 0 /* we'll need to do this soon */
364 dmask6
.sin6_scope_id
= ~0;
367 p
= encap_attach(sc
->gif_psrc
->sa_family
, -1, sc
->gif_psrc
,
368 (struct sockaddr
*)&smask6
, sc
->gif_pdst
,
369 (struct sockaddr
*)&dmask6
,
370 (struct protosw
*)&in6_gif_protosw
, &sc
->gif_if
);
375 if (sc
->encap_cookie
!= NULL
)
376 (void)encap_detach(sc
->encap_cookie
);
377 sc
->encap_cookie
= p
;
378 sc
->gif_oflags
= ifp
->if_flags
;
383 case SIOCSIFPHYADDR_IN6
:
385 switch (ifr
->ifr_addr
.sa_family
) {
388 src
= (struct sockaddr
*)
389 &(((struct in6_aliasreq
*)data
)->ifra_addr
);
390 dst
= (struct sockaddr
*)
391 &(((struct in6_aliasreq
*)data
)->ifra_dstaddr
);
393 bzero(&smask6
, sizeof(smask6
));
394 smask6
.sin6_addr
.s6_addr32
[0] = ~0;
395 smask6
.sin6_addr
.s6_addr32
[1] = ~0;
396 smask6
.sin6_addr
.s6_addr32
[2] = ~0;
397 smask6
.sin6_addr
.s6_addr32
[3] = ~0;
398 #if 0 /* we'll need to do this soon */
399 smask6
.sin6_scope_id
= ~0;
402 if ((ifp
->if_flags
& IFF_LINK0
) == 0 &&
403 IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6
*)dst
)->sin6_addr
)) {
404 bzero(&dmask6
, sizeof(dmask6
));
405 #if 0 /* we'll need to do this soon */
406 dmask6
.sin6_scope_id
= ~0;
409 size
= sizeof(struct sockaddr_in6
);
413 error
= EAFNOSUPPORT
;
417 if (sc
->encap_cookie
!= NULL
)
418 (void)encap_detach(sc
->encap_cookie
);
419 if (sc
->gif_psrc
!= NULL
) {
420 _FREE((caddr_t
)sc
->gif_psrc
, M_IFADDR
);
423 if (sc
->gif_pdst
!= NULL
) {
424 _FREE((caddr_t
)sc
->gif_pdst
, M_IFADDR
);
428 p
= encap_attach(ifr
->ifr_addr
.sa_family
, -1, src
,
429 (struct sockaddr
*)&smask6
, dst
,
430 (struct sockaddr
*)&dmask6
,
431 (struct protosw
*)&in6_gif_protosw
, &sc
->gif_if
);
436 sc
->encap_cookie
= p
;
437 sc
->gif_oflags
= ifp
->if_flags
;
439 sa
= (struct sockaddr
*)_MALLOC(size
, M_IFADDR
, M_WAITOK
);
440 bcopy((caddr_t
)src
, (caddr_t
)sa
, size
);
443 sa
= (struct sockaddr
*)_MALLOC(size
, M_IFADDR
, M_WAITOK
);
444 bcopy((caddr_t
)dst
, (caddr_t
)sa
, size
);
447 ifp
->if_flags
|= IFF_UP
;
448 if_up(ifp
); /* send up RTM_IFINFO */