1 /* $NetBSD: in6_gif.c,v 1.52 2007/05/23 17:15:01 christos Exp $ */ 2 /* $KAME: in6_gif.c,v 1.62 2001/07/29 04:27:25 itojun Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 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. 19 * 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 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: in6_gif.c,v 1.52 2007/05/23 17:15:01 christos Exp $"); 35 36 #include "opt_inet.h" 37 #include "opt_iso.h" 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/socket.h> 42 #include <sys/sockio.h> 43 #include <sys/mbuf.h> 44 #include <sys/errno.h> 45 #include <sys/ioctl.h> 46 #include <sys/queue.h> 47 #include <sys/syslog.h> 48 #include <sys/protosw.h> 49 #include <sys/kernel.h> 50 51 #include <net/if.h> 52 #include <net/route.h> 53 54 #include <netinet/in.h> 55 #include <netinet/in_systm.h> 56 #ifdef INET 57 #include <netinet/ip.h> 58 #endif 59 #include <netinet/ip_encap.h> 60 #ifdef INET6 61 #include <netinet/ip6.h> 62 #include <netinet6/ip6_var.h> 63 #include <netinet6/in6_gif.h> 64 #include <netinet6/in6_var.h> 65 #endif 66 #include <netinet6/ip6protosw.h> 67 #include <netinet/ip_ecn.h> 68 69 #include <net/if_gif.h> 70 71 #include <net/net_osdep.h> 72 73 static int gif_validate6 __P((const struct ip6_hdr *, struct gif_softc *, 74 struct ifnet *)); 75 76 int ip6_gif_hlim = GIF_HLIM; 77 78 extern struct domain inet6domain; 79 const struct ip6protosw in6_gif_protosw = 80 { SOCK_RAW, &inet6domain, 0/* IPPROTO_IPV[46] */, PR_ATOMIC|PR_ADDR, 81 in6_gif_input, rip6_output, in6_gif_ctlinput, rip6_ctloutput, 82 rip6_usrreq, 83 0, 0, 0, 0, 84 }; 85 86 extern LIST_HEAD(, gif_softc) gif_softc_list; 87 88 /* 89 * family - family of the packet to be encapsulate. 90 */ 91 92 int 93 in6_gif_output(struct ifnet *ifp, int family, struct mbuf *m) 94 { 95 struct gif_softc *sc = (struct gif_softc*)ifp; 96 struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc; 97 struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst; 98 struct ip6_hdr *ip6; 99 int proto, error; 100 u_int8_t itos, otos; 101 union { 102 struct sockaddr dst; 103 struct sockaddr_in6 dst6; 104 } u; 105 106 if (sin6_src == NULL || sin6_dst == NULL || 107 sin6_src->sin6_family != AF_INET6 || 108 sin6_dst->sin6_family != AF_INET6) { 109 m_freem(m); 110 return EAFNOSUPPORT; 111 } 112 113 switch (family) { 114 #ifdef INET 115 case AF_INET: 116 { 117 struct ip *ip; 118 119 proto = IPPROTO_IPV4; 120 if (m->m_len < sizeof(*ip)) { 121 m = m_pullup(m, sizeof(*ip)); 122 if (!m) 123 return ENOBUFS; 124 } 125 ip = mtod(m, struct ip *); 126 itos = ip->ip_tos; 127 break; 128 } 129 #endif 130 #ifdef INET6 131 case AF_INET6: 132 { 133 proto = IPPROTO_IPV6; 134 if (m->m_len < sizeof(*ip6)) { 135 m = m_pullup(m, sizeof(*ip6)); 136 if (!m) 137 return ENOBUFS; 138 } 139 ip6 = mtod(m, struct ip6_hdr *); 140 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 141 break; 142 } 143 #endif 144 #ifdef ISO 145 case AF_ISO: 146 proto = IPPROTO_EON; 147 itos = 0; 148 break; 149 #endif 150 default: 151 #ifdef DEBUG 152 printf("in6_gif_output: warning: unknown family %d passed\n", 153 family); 154 #endif 155 m_freem(m); 156 return EAFNOSUPPORT; 157 } 158 159 /* prepend new IP header */ 160 M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); 161 if (m && m->m_len < sizeof(struct ip6_hdr)) 162 m = m_pullup(m, sizeof(struct ip6_hdr)); 163 if (m == NULL) 164 return ENOBUFS; 165 166 ip6 = mtod(m, struct ip6_hdr *); 167 ip6->ip6_flow = 0; 168 ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 169 ip6->ip6_vfc |= IPV6_VERSION; 170 #if 0 /* ip6->ip6_plen will be filled by ip6_output */ 171 ip6->ip6_plen = htons((u_int16_t)m->m_pkthdr.len); 172 #endif 173 ip6->ip6_nxt = proto; 174 ip6->ip6_hlim = ip6_gif_hlim; 175 ip6->ip6_src = sin6_src->sin6_addr; 176 /* bidirectional configured tunnel mode */ 177 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) 178 ip6->ip6_dst = sin6_dst->sin6_addr; 179 else { 180 m_freem(m); 181 return ENETUNREACH; 182 } 183 if (ifp->if_flags & IFF_LINK1) 184 ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 185 else 186 ip_ecn_ingress(ECN_NOCARE, &otos, &itos); 187 ip6->ip6_flow &= ~ntohl(0xff00000); 188 ip6->ip6_flow |= htonl((u_int32_t)otos << 20); 189 190 sockaddr_in6_init(&u.dst6, &sin6_dst->sin6_addr, 0, 0, 0); 191 if (rtcache_lookup(&sc->gif_ro, &u.dst) == NULL) { 192 m_freem(m); 193 return ENETUNREACH; 194 } 195 196 /* If the route constitutes infinite encapsulation, punt. */ 197 if (sc->gif_ro.ro_rt->rt_ifp == ifp) { 198 m_freem(m); 199 return ENETUNREACH; /* XXX */ 200 } 201 202 #ifdef IPV6_MINMTU 203 /* 204 * force fragmentation to minimum MTU, to avoid path MTU discovery. 205 * it is too painful to ask for resend of inner packet, to achieve 206 * path MTU discovery for encapsulated packets. 207 */ 208 error = ip6_output(m, 0, &sc->gif_ro, IPV6_MINMTU, 209 (struct ip6_moptions *)NULL, (struct socket *)NULL, NULL); 210 #else 211 error = ip6_output(m, 0, &sc->gif_ro, 0, 212 (struct ip6_moptions *)NULL, (struct socket *)NULL, NULL); 213 #endif 214 215 return (error); 216 } 217 218 int in6_gif_input(struct mbuf **mp, int *offp, int proto) 219 { 220 struct mbuf *m = *mp; 221 struct ifnet *gifp = NULL; 222 struct ip6_hdr *ip6; 223 int af = 0; 224 u_int32_t otos; 225 226 ip6 = mtod(m, struct ip6_hdr *); 227 228 gifp = (struct ifnet *)encap_getarg(m); 229 230 if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { 231 m_freem(m); 232 ip6stat.ip6s_nogif++; 233 return IPPROTO_DONE; 234 } 235 #ifndef GIF_ENCAPCHECK 236 if (!gif_validate6(ip6, (struct gif_softc *)gifp, m->m_pkthdr.rcvif)) { 237 m_freem(m); 238 ip6stat.ip6s_nogif++; 239 return IPPROTO_DONE; 240 } 241 #endif 242 243 otos = ip6->ip6_flow; 244 m_adj(m, *offp); 245 246 switch (proto) { 247 #ifdef INET 248 case IPPROTO_IPV4: 249 { 250 struct ip *ip; 251 u_int8_t otos8; 252 af = AF_INET; 253 otos8 = (ntohl(otos) >> 20) & 0xff; 254 if (m->m_len < sizeof(*ip)) { 255 m = m_pullup(m, sizeof(*ip)); 256 if (!m) 257 return IPPROTO_DONE; 258 } 259 ip = mtod(m, struct ip *); 260 if (gifp->if_flags & IFF_LINK1) 261 ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos); 262 else 263 ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos); 264 break; 265 } 266 #endif /* INET */ 267 #ifdef INET6 268 case IPPROTO_IPV6: 269 { 270 struct ip6_hdr *ip6x; 271 af = AF_INET6; 272 if (m->m_len < sizeof(*ip6x)) { 273 m = m_pullup(m, sizeof(*ip6x)); 274 if (!m) 275 return IPPROTO_DONE; 276 } 277 ip6x = mtod(m, struct ip6_hdr *); 278 if (gifp->if_flags & IFF_LINK1) 279 ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6x->ip6_flow); 280 else 281 ip6_ecn_egress(ECN_NOCARE, &otos, &ip6x->ip6_flow); 282 break; 283 } 284 #endif 285 #ifdef ISO 286 case IPPROTO_EON: 287 af = AF_ISO; 288 break; 289 #endif 290 default: 291 ip6stat.ip6s_nogif++; 292 m_freem(m); 293 return IPPROTO_DONE; 294 } 295 296 gif_input(m, af, gifp); 297 return IPPROTO_DONE; 298 } 299 300 /* 301 * validate outer address. 302 */ 303 static int 304 gif_validate6(const struct ip6_hdr *ip6, struct gif_softc *sc, 305 struct ifnet *ifp) 306 { 307 const struct sockaddr_in6 *src, *dst; 308 309 src = (struct sockaddr_in6 *)sc->gif_psrc; 310 dst = (struct sockaddr_in6 *)sc->gif_pdst; 311 312 /* check for address match */ 313 if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) || 314 !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src)) 315 return 0; 316 317 /* martian filters on outer source - done in ip6_input */ 318 319 /* ingress filters on outer source */ 320 if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) { 321 struct sockaddr_in6 sin6; 322 struct rtentry *rt; 323 324 memset(&sin6, 0, sizeof(sin6)); 325 sin6.sin6_family = AF_INET6; 326 sin6.sin6_len = sizeof(struct sockaddr_in6); 327 sin6.sin6_addr = ip6->ip6_src; 328 /* XXX scopeid */ 329 rt = rtalloc1((struct sockaddr *)&sin6, 0); 330 if (!rt || rt->rt_ifp != ifp) { 331 #if 0 332 log(LOG_WARNING, "%s: packet from %s dropped " 333 "due to ingress filter\n", if_name(&sc->gif_if), 334 ip6_sprintf(&sin6.sin6_addr)); 335 #endif 336 if (rt) 337 rtfree(rt); 338 return 0; 339 } 340 rtfree(rt); 341 } 342 343 return 128 * 2; 344 } 345 346 #ifdef GIF_ENCAPCHECK 347 /* 348 * we know that we are in IFF_UP, outer address available, and outer family 349 * matched the physical addr family. see gif_encapcheck(). 350 */ 351 int 352 gif_encapcheck6(struct mbuf *m, int off, int proto, void *arg) 353 { 354 struct ip6_hdr ip6; 355 struct gif_softc *sc; 356 struct ifnet *ifp; 357 358 /* sanity check done in caller */ 359 sc = (struct gif_softc *)arg; 360 361 m_copydata(m, 0, sizeof(ip6), (void *)&ip6); 362 ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; 363 364 return gif_validate6(&ip6, sc, ifp); 365 } 366 #endif 367 368 int 369 in6_gif_attach(struct gif_softc *sc) 370 { 371 #ifndef GIF_ENCAPCHECK 372 struct sockaddr_in6 mask6; 373 374 bzero(&mask6, sizeof(mask6)); 375 mask6.sin6_len = sizeof(struct sockaddr_in6); 376 mask6.sin6_addr.s6_addr32[0] = mask6.sin6_addr.s6_addr32[1] = 377 mask6.sin6_addr.s6_addr32[2] = mask6.sin6_addr.s6_addr32[3] = ~0; 378 379 if (!sc->gif_psrc || !sc->gif_pdst) 380 return EINVAL; 381 sc->encap_cookie6 = encap_attach(AF_INET6, -1, sc->gif_psrc, 382 (struct sockaddr *)&mask6, sc->gif_pdst, (struct sockaddr *)&mask6, 383 (const void *)&in6_gif_protosw, sc); 384 #else 385 sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck, 386 (struct protosw *)&in6_gif_protosw, sc); 387 #endif 388 if (sc->encap_cookie6 == NULL) 389 return EEXIST; 390 return 0; 391 } 392 393 int 394 in6_gif_detach(struct gif_softc *sc) 395 { 396 int error; 397 398 error = encap_detach(sc->encap_cookie6); 399 if (error == 0) 400 sc->encap_cookie6 = NULL; 401 402 rtcache_free(&sc->gif_ro); 403 404 return error; 405 } 406 407 void 408 in6_gif_ctlinput(int cmd, const struct sockaddr *sa, void *d) 409 { 410 struct gif_softc *sc; 411 struct ip6ctlparam *ip6cp = NULL; 412 struct ip6_hdr *ip6; 413 const struct sockaddr_in6 *dst6; 414 415 if (sa->sa_family != AF_INET6 || 416 sa->sa_len != sizeof(struct sockaddr_in6)) 417 return; 418 419 if ((unsigned)cmd >= PRC_NCMDS) 420 return; 421 if (cmd == PRC_HOSTDEAD) 422 d = NULL; 423 else if (inet6ctlerrmap[cmd] == 0) 424 return; 425 426 /* if the parameter is from icmp6, decode it. */ 427 if (d != NULL) { 428 ip6cp = (struct ip6ctlparam *)d; 429 ip6 = ip6cp->ip6c_ip6; 430 } else { 431 ip6 = NULL; 432 } 433 434 if (!ip6) 435 return; 436 437 /* 438 * for now we don't care which type it was, just flush the route cache. 439 * XXX slow. sc (or sc->encap_cookie6) should be passed from 440 * ip_encap.c. 441 */ 442 LIST_FOREACH(sc, &gif_softc_list, gif_list) { 443 if ((sc->gif_if.if_flags & IFF_RUNNING) == 0) 444 continue; 445 if (sc->gif_psrc->sa_family != AF_INET6) 446 continue; 447 if (sc->gif_ro.ro_rt == NULL) 448 continue; 449 450 dst6 = satocsin6(rtcache_getdst(&sc->gif_ro)); 451 /* XXX scope */ 452 if (dst6 == NULL) 453 ; 454 else if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst6->sin6_addr)) 455 rtcache_free(&sc->gif_ro); 456 } 457 } 458