1 /* $NetBSD: in6_gif.c,v 1.9 1999/12/15 06:28:44 itojun Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 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. 18 * 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 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * in6_gif.c 34 */ 35 36 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) 37 #include "opt_inet.h" 38 #ifdef __NetBSD__ /*XXX*/ 39 #include "opt_ipsec.h" 40 #endif 41 #endif 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/socket.h> 46 #include <sys/sockio.h> 47 #include <sys/mbuf.h> 48 #include <sys/errno.h> 49 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) 50 #include <sys/ioctl.h> 51 #endif 52 #include <sys/protosw.h> 53 54 #include <net/if.h> 55 #include <net/route.h> 56 57 #include <netinet/in.h> 58 #include <netinet/in_systm.h> 59 #ifdef INET 60 #include <netinet/ip.h> 61 #endif 62 #include <netinet6/ip6.h> 63 #include <netinet6/ip6_var.h> 64 #include <netinet6/in6_gif.h> 65 #ifdef INET6 66 #include <netinet6/ip6.h> 67 #endif 68 #include <netinet/ip_ecn.h> 69 70 #include <net/if_gif.h> 71 72 #include <net/net_osdep.h> 73 74 int 75 in6_gif_output(ifp, family, m, rt) 76 struct ifnet *ifp; 77 int family; /* family of the packet to be encapsulate. */ 78 struct mbuf *m; 79 struct rtentry *rt; 80 { 81 struct gif_softc *sc = (struct gif_softc*)ifp; 82 struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst; 83 struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc; 84 struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst; 85 struct ip6_hdr *ip6; 86 int proto; 87 u_int8_t itos, otos; 88 89 if (sin6_src == NULL || sin6_dst == NULL || 90 sin6_src->sin6_family != AF_INET6 || 91 sin6_dst->sin6_family != AF_INET6) { 92 m_freem(m); 93 return EAFNOSUPPORT; 94 } 95 96 switch (family) { 97 #ifdef INET 98 case AF_INET: 99 { 100 struct ip *ip; 101 102 proto = IPPROTO_IPV4; 103 if (m->m_len < sizeof(*ip)) { 104 m = m_pullup(m, sizeof(*ip)); 105 if (!m) 106 return ENOBUFS; 107 } 108 ip = mtod(m, struct ip *); 109 itos = ip->ip_tos; 110 break; 111 } 112 #endif 113 #ifdef INET6 114 case AF_INET6: 115 { 116 struct ip6_hdr *ip6; 117 proto = IPPROTO_IPV6; 118 if (m->m_len < sizeof(*ip6)) { 119 m = m_pullup(m, sizeof(*ip6)); 120 if (!m) 121 return ENOBUFS; 122 } 123 ip6 = mtod(m, struct ip6_hdr *); 124 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 125 break; 126 } 127 #endif 128 default: 129 #ifdef DIAGNOSTIC 130 printf("in6_gif_output: warning: unknown family %d passed\n", 131 family); 132 #endif 133 m_freem(m); 134 return EAFNOSUPPORT; 135 } 136 137 /* prepend new IP header */ 138 M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); 139 if (m && m->m_len < sizeof(struct ip6_hdr)) 140 m = m_pullup(m, sizeof(struct ip6_hdr)); 141 if (m == NULL) { 142 printf("ENOBUFS in in6_gif_output %d\n", __LINE__); 143 return ENOBUFS; 144 } 145 146 ip6 = mtod(m, struct ip6_hdr *); 147 ip6->ip6_flow = 0; 148 ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 149 ip6->ip6_vfc |= IPV6_VERSION; 150 ip6->ip6_plen = htons((u_short)m->m_pkthdr.len); 151 ip6->ip6_nxt = proto; 152 ip6->ip6_hlim = ip6_gif_hlim; 153 ip6->ip6_src = sin6_src->sin6_addr; 154 if (ifp->if_flags & IFF_LINK0) { 155 /* multi-destination mode */ 156 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) 157 ip6->ip6_dst = sin6_dst->sin6_addr; 158 else if (rt) { 159 if (family != AF_INET6) { 160 m_freem(m); 161 return EINVAL; /*XXX*/ 162 } 163 ip6->ip6_dst = ((struct sockaddr_in6 *)(rt->rt_gateway))->sin6_addr; 164 } else { 165 m_freem(m); 166 return ENETUNREACH; 167 } 168 } else { 169 /* bidirectional configured tunnel mode */ 170 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) 171 ip6->ip6_dst = sin6_dst->sin6_addr; 172 else { 173 m_freem(m); 174 return ENETUNREACH; 175 } 176 } 177 if (ifp->if_flags & IFF_LINK1) { 178 otos = 0; 179 ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 180 ip6->ip6_flow |= htonl((u_int32_t)otos << 20); 181 } 182 183 if (dst->sin6_family != sin6_dst->sin6_family || 184 !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) { 185 /* cache route doesn't match */ 186 bzero(dst, sizeof(*dst)); 187 dst->sin6_family = sin6_dst->sin6_family; 188 dst->sin6_len = sizeof(struct sockaddr_in6); 189 dst->sin6_addr = sin6_dst->sin6_addr; 190 if (sc->gif_ro6.ro_rt) { 191 RTFREE(sc->gif_ro6.ro_rt); 192 sc->gif_ro6.ro_rt = NULL; 193 } 194 #if 0 195 sc->gif_if.if_mtu = GIF_MTU; 196 #endif 197 } 198 199 if (sc->gif_ro6.ro_rt == NULL) { 200 rtalloc((struct route *)&sc->gif_ro6); 201 if (sc->gif_ro6.ro_rt == NULL) { 202 m_freem(m); 203 return ENETUNREACH; 204 } 205 #if 0 206 ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu 207 - sizeof(struct ip6_hdr); 208 #endif 209 } 210 211 #ifdef IPSEC 212 #ifndef __OpenBSD__ /*KAME IPSEC*/ 213 m->m_pkthdr.rcvif = NULL; 214 #endif 215 #endif /*IPSEC*/ 216 return(ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL)); 217 } 218 219 int in6_gif_input(mp, offp, proto) 220 struct mbuf **mp; 221 int *offp, proto; 222 { 223 struct mbuf *m = *mp; 224 struct gif_softc *sc; 225 struct ifnet *gifp = NULL; 226 struct ip6_hdr *ip6; 227 int i; 228 int af = 0; 229 u_int32_t otos; 230 231 ip6 = mtod(m, struct ip6_hdr *); 232 233 #define satoin6(sa) (((struct sockaddr_in6 *)(sa))->sin6_addr) 234 for (i = 0, sc = gif; i < ngif; i++, sc++) { 235 if (sc->gif_psrc == NULL || 236 sc->gif_pdst == NULL || 237 sc->gif_psrc->sa_family != AF_INET6 || 238 sc->gif_pdst->sa_family != AF_INET6) { 239 continue; 240 } 241 if ((sc->gif_if.if_flags & IFF_UP) == 0) 242 continue; 243 if ((sc->gif_if.if_flags & IFF_LINK0) && 244 IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) && 245 IN6_IS_ADDR_UNSPECIFIED(&satoin6(sc->gif_pdst))) { 246 gifp = &sc->gif_if; 247 continue; 248 } 249 if (IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) && 250 IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_pdst), &ip6->ip6_src)) { 251 gifp = &sc->gif_if; 252 break; 253 } 254 } 255 256 if (gifp == NULL) { 257 m_freem(m); 258 ip6stat.ip6s_nogif++; 259 return IPPROTO_DONE; 260 } 261 262 otos = ip6->ip6_flow; 263 m_adj(m, *offp); 264 265 switch (proto) { 266 #ifdef INET 267 case IPPROTO_IPV4: 268 { 269 struct ip *ip; 270 u_int8_t otos8; 271 af = AF_INET; 272 otos8 = (ntohl(otos) >> 20) & 0xff; 273 if (m->m_len < sizeof(*ip)) { 274 m = m_pullup(m, sizeof(*ip)); 275 if (!m) 276 return IPPROTO_DONE; 277 } 278 ip = mtod(m, struct ip *); 279 if (gifp->if_flags & IFF_LINK1) 280 ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos); 281 break; 282 } 283 #endif /* INET */ 284 #ifdef INET6 285 case IPPROTO_IPV6: 286 { 287 struct ip6_hdr *ip6; 288 af = AF_INET6; 289 if (m->m_len < sizeof(*ip6)) { 290 m = m_pullup(m, sizeof(*ip6)); 291 if (!m) 292 return IPPROTO_DONE; 293 } 294 ip6 = mtod(m, struct ip6_hdr *); 295 if (gifp->if_flags & IFF_LINK1) 296 ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow); 297 break; 298 } 299 #endif 300 default: 301 ip6stat.ip6s_nogif++; 302 m_freem(m); 303 return IPPROTO_DONE; 304 } 305 306 gif_input(m, af, gifp); 307 return IPPROTO_DONE; 308 } 309