1 /* $NetBSD: in6_gif.c,v 1.93 2018/05/01 07:21:39 maxv 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.93 2018/05/01 07:21:39 maxv Exp $"); 35 36 #ifdef _KERNEL_OPT 37 #include "opt_inet.h" 38 #endif 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/socket.h> 43 #include <sys/sockio.h> 44 #include <sys/mbuf.h> 45 #include <sys/errno.h> 46 #include <sys/ioctl.h> 47 #include <sys/queue.h> 48 #include <sys/syslog.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/ip6_private.h> 64 #include <netinet6/in6_gif.h> 65 #include <netinet6/in6_var.h> 66 #endif 67 #include <netinet6/ip6protosw.h> /* for struct ip6ctlparam */ 68 #include <netinet/ip_ecn.h> 69 70 #include <net/if_gif.h> 71 72 static int gif_validate6(const struct ip6_hdr *, struct gif_variant *, 73 struct ifnet *); 74 75 int ip6_gif_hlim = GIF_HLIM; 76 77 static const struct encapsw in6_gif_encapsw; 78 79 /* 80 * family - family of the packet to be encapsulate. 81 */ 82 83 static int 84 in6_gif_output(struct gif_variant *var, int family, struct mbuf *m) 85 { 86 struct rtentry *rt; 87 struct route *ro; 88 struct gif_ro *gro; 89 struct gif_softc *sc; 90 struct sockaddr_in6 *sin6_src; 91 struct sockaddr_in6 *sin6_dst; 92 struct ifnet *ifp; 93 struct ip6_hdr *ip6; 94 int proto, error; 95 u_int8_t itos, otos; 96 97 KASSERT(gif_heldref_variant(var)); 98 99 sin6_src = satosin6(var->gv_psrc); 100 sin6_dst = satosin6(var->gv_pdst); 101 ifp = &var->gv_softc->gif_if; 102 103 if (sin6_src == NULL || sin6_dst == NULL || 104 sin6_src->sin6_family != AF_INET6 || 105 sin6_dst->sin6_family != AF_INET6) { 106 m_freem(m); 107 return EAFNOSUPPORT; 108 } 109 110 switch (family) { 111 #ifdef INET 112 case AF_INET: 113 { 114 struct ip *ip; 115 116 proto = IPPROTO_IPV4; 117 if (m->m_len < sizeof(*ip)) { 118 m = m_pullup(m, sizeof(*ip)); 119 if (!m) 120 return ENOBUFS; 121 } 122 ip = mtod(m, struct ip *); 123 itos = ip->ip_tos; 124 break; 125 } 126 #endif 127 #ifdef INET6 128 case AF_INET6: 129 { 130 proto = IPPROTO_IPV6; 131 if (m->m_len < sizeof(*ip6)) { 132 m = m_pullup(m, sizeof(*ip6)); 133 if (!m) 134 return ENOBUFS; 135 } 136 ip6 = mtod(m, struct ip6_hdr *); 137 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 138 break; 139 } 140 #endif 141 default: 142 #ifdef DEBUG 143 printf("in6_gif_output: warning: unknown family %d passed\n", 144 family); 145 #endif 146 m_freem(m); 147 return EAFNOSUPPORT; 148 } 149 150 /* prepend new IP header */ 151 M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); 152 if (m && m->m_len < sizeof(struct ip6_hdr)) 153 m = m_pullup(m, sizeof(struct ip6_hdr)); 154 if (m == NULL) 155 return ENOBUFS; 156 157 ip6 = mtod(m, struct ip6_hdr *); 158 ip6->ip6_flow = 0; 159 ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 160 ip6->ip6_vfc |= IPV6_VERSION; 161 #if 0 /* ip6->ip6_plen will be filled by ip6_output */ 162 ip6->ip6_plen = htons((u_int16_t)m->m_pkthdr.len); 163 #endif 164 ip6->ip6_nxt = proto; 165 ip6->ip6_hlim = ip6_gif_hlim; 166 ip6->ip6_src = sin6_src->sin6_addr; 167 /* bidirectional configured tunnel mode */ 168 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) 169 ip6->ip6_dst = sin6_dst->sin6_addr; 170 else { 171 m_freem(m); 172 return ENETUNREACH; 173 } 174 if (ifp->if_flags & IFF_LINK1) 175 ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 176 else 177 ip_ecn_ingress(ECN_NOCARE, &otos, &itos); 178 ip6->ip6_flow &= ~ntohl(0xff00000); 179 ip6->ip6_flow |= htonl((u_int32_t)otos << 20); 180 181 sc = ifp->if_softc; 182 gro = percpu_getref(sc->gif_ro_percpu); 183 mutex_enter(gro->gr_lock); 184 ro = &gro->gr_ro; 185 rt = rtcache_lookup(ro, var->gv_pdst); 186 if (rt == NULL) { 187 mutex_exit(gro->gr_lock); 188 percpu_putref(sc->gif_ro_percpu); 189 m_freem(m); 190 return ENETUNREACH; 191 } 192 193 /* If the route constitutes infinite encapsulation, punt. */ 194 if (rt->rt_ifp == ifp) { 195 rtcache_unref(rt, ro); 196 rtcache_free(ro); 197 mutex_exit(gro->gr_lock); 198 percpu_putref(sc->gif_ro_percpu); 199 m_freem(m); 200 return ENETUNREACH; /* XXX */ 201 } 202 rtcache_unref(rt, ro); 203 204 #ifdef IPV6_MINMTU 205 /* 206 * force fragmentation to minimum MTU, to avoid path MTU discovery. 207 * it is too painful to ask for resend of inner packet, to achieve 208 * path MTU discovery for encapsulated packets. 209 */ 210 error = ip6_output(m, 0, ro, IPV6_MINMTU, NULL, NULL, NULL); 211 #else 212 error = ip6_output(m, 0, ro, 0, NULL, NULL, NULL); 213 #endif 214 mutex_exit(gro->gr_lock); 215 percpu_putref(sc->gif_ro_percpu); 216 return (error); 217 } 218 219 int 220 in6_gif_input(struct mbuf **mp, int *offp, int proto, void *eparg) 221 { 222 struct mbuf *m = *mp; 223 struct gif_softc *sc = eparg; 224 struct ifnet *gifp; 225 struct ip6_hdr *ip6; 226 int af = 0; 227 u_int32_t otos; 228 229 KASSERT(sc != NULL); 230 231 ip6 = mtod(m, struct ip6_hdr *); 232 233 gifp = &sc->gif_if; 234 if ((gifp->if_flags & IFF_UP) == 0) { 235 m_freem(m); 236 IP6_STATINC(IP6_STAT_NOGIF); 237 return IPPROTO_DONE; 238 } 239 #ifndef GIF_ENCAPCHECK 240 struct psref psref_var; 241 struct gif_variant *var = gif_getref_variant(sc, &psref_var); 242 /* other CPU do delete_tunnel */ 243 if (var->gv_psrc == NULL || var->gv_pdst == NULL) { 244 gif_putref_variant(var, &psref_var); 245 m_freem(m); 246 IP6_STATINC(IP6_STAT_NOGIF); 247 return IPPROTO_DONE; 248 } 249 250 struct psref psref; 251 struct ifnet *rcvif = m_get_rcvif_psref(m, &psref); 252 if (rcvif == NULL || !gif_validate6(ip6, var, rcvif)) { 253 m_put_rcvif_psref(rcvif, &psref); 254 gif_putref_variant(var, &psref_var); 255 m_freem(m); 256 IP6_STATINC(IP6_STAT_NOGIF); 257 return IPPROTO_DONE; 258 } 259 m_put_rcvif_psref(rcvif, &psref); 260 gif_putref_variant(var, &psref_var); 261 #endif 262 263 otos = ip6->ip6_flow; 264 m_adj(m, *offp); 265 266 switch (proto) { 267 #ifdef INET 268 case IPPROTO_IPV4: 269 { 270 struct ip *ip; 271 u_int8_t otos8; 272 af = AF_INET; 273 otos8 = (ntohl(otos) >> 20) & 0xff; 274 if (m->m_len < sizeof(*ip)) { 275 m = m_pullup(m, sizeof(*ip)); 276 if (!m) 277 return IPPROTO_DONE; 278 } 279 ip = mtod(m, struct ip *); 280 if (gifp->if_flags & IFF_LINK1) 281 ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos); 282 else 283 ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos); 284 break; 285 } 286 #endif /* INET */ 287 #ifdef INET6 288 case IPPROTO_IPV6: 289 { 290 struct ip6_hdr *ip6x; 291 af = AF_INET6; 292 if (m->m_len < sizeof(*ip6x)) { 293 m = m_pullup(m, sizeof(*ip6x)); 294 if (!m) 295 return IPPROTO_DONE; 296 } 297 ip6x = mtod(m, struct ip6_hdr *); 298 if (gifp->if_flags & IFF_LINK1) 299 ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6x->ip6_flow); 300 else 301 ip6_ecn_egress(ECN_NOCARE, &otos, &ip6x->ip6_flow); 302 break; 303 } 304 #endif 305 default: 306 IP6_STATINC(IP6_STAT_NOGIF); 307 m_freem(m); 308 return IPPROTO_DONE; 309 } 310 311 gif_input(m, af, gifp); 312 return IPPROTO_DONE; 313 } 314 315 /* 316 * validate outer address. 317 */ 318 static int 319 gif_validate6(const struct ip6_hdr *ip6, struct gif_variant *var, 320 struct ifnet *ifp) 321 { 322 const struct sockaddr_in6 *src, *dst; 323 int ret; 324 325 src = satosin6(var->gv_psrc); 326 dst = satosin6(var->gv_pdst); 327 328 ret = in6_tunnel_validate(ip6, &src->sin6_addr, &dst->sin6_addr); 329 if (ret == 0) 330 return 0; 331 332 /* ingress filters on outer source */ 333 if ((var->gv_softc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) { 334 union { 335 struct sockaddr sa; 336 struct sockaddr_in6 sin6; 337 } u; 338 struct rtentry *rt; 339 340 /* XXX scopeid */ 341 sockaddr_in6_init(&u.sin6, &ip6->ip6_src, 0, 0, 0); 342 rt = rtalloc1(&u.sa, 0); 343 if (rt == NULL || rt->rt_ifp != ifp) { 344 #if 0 345 char ip6buf[INET6_ADDRSTRLEN]; 346 log(LOG_WARNING, "%s: packet from %s dropped " 347 "due to ingress filter\n", 348 if_name(&var->gv_softc->gif_if), 349 IN6_PRINT(ip6buf, &u.sin6.sin6_addr)); 350 #endif 351 if (rt != NULL) 352 rt_unref(rt); 353 return 0; 354 } 355 rt_unref(rt); 356 } 357 358 return ret; 359 } 360 361 #ifdef GIF_ENCAPCHECK 362 /* 363 * we know that we are in IFF_UP, outer address available, and outer family 364 * matched the physical addr family. see gif_encapcheck(). 365 */ 366 int 367 gif_encapcheck6(struct mbuf *m, int off, int proto, struct gif_variant *var) 368 { 369 struct ip6_hdr ip6; 370 struct ifnet *ifp = NULL; 371 int r; 372 struct psref psref; 373 374 m_copydata(m, 0, sizeof(ip6), (void *)&ip6); 375 if ((m->m_flags & M_PKTHDR) != 0) 376 ifp = m_get_rcvif_psref(m, &psref); 377 378 r = gif_validate6(&ip6, var, ifp); 379 380 m_put_rcvif_psref(ifp, &psref); 381 return r; 382 } 383 #endif 384 385 int 386 in6_gif_attach(struct gif_variant *var) 387 { 388 #ifndef GIF_ENCAPCHECK 389 struct sockaddr_in6 mask6; 390 391 memset(&mask6, 0, sizeof(mask6)); 392 mask6.sin6_len = sizeof(struct sockaddr_in6); 393 mask6.sin6_addr.s6_addr32[0] = mask6.sin6_addr.s6_addr32[1] = 394 mask6.sin6_addr.s6_addr32[2] = mask6.sin6_addr.s6_addr32[3] = ~0; 395 396 if (!var->gv_psrc || !var->gv_pdst) 397 return EINVAL; 398 var->gv_encap_cookie6 = encap_attach(AF_INET6, -1, var->gv_psrc, 399 sin6tosa(&mask6), var->gv_pdst, sin6tosa(&mask6), 400 (const void *)&in6_gif_encapsw, var->gv_softc); 401 #else 402 var->gv_encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck, 403 &in6_gif_encapsw, var->gv_softc); 404 #endif 405 if (var->gv_encap_cookie6 == NULL) 406 return EEXIST; 407 408 var->gv_output = in6_gif_output; 409 return 0; 410 } 411 412 int 413 in6_gif_detach(struct gif_variant *var) 414 { 415 int error; 416 struct gif_softc *sc = var->gv_softc; 417 418 error = encap_detach(var->gv_encap_cookie6); 419 if (error == 0) 420 var->gv_encap_cookie6 = NULL; 421 422 percpu_foreach(sc->gif_ro_percpu, gif_rtcache_free_pc, NULL); 423 424 return error; 425 } 426 427 void * 428 in6_gif_ctlinput(int cmd, const struct sockaddr *sa, void *d, void *eparg) 429 { 430 struct gif_softc *sc = eparg; 431 struct gif_variant *var; 432 struct ip6ctlparam *ip6cp = NULL; 433 struct ip6_hdr *ip6; 434 const struct sockaddr_in6 *dst6; 435 struct route *ro; 436 struct psref psref; 437 438 if (sa->sa_family != AF_INET6 || 439 sa->sa_len != sizeof(struct sockaddr_in6)) 440 return NULL; 441 442 if ((unsigned)cmd >= PRC_NCMDS) 443 return NULL; 444 if (cmd == PRC_HOSTDEAD) 445 d = NULL; 446 else if (inet6ctlerrmap[cmd] == 0) 447 return NULL; 448 449 /* if the parameter is from icmp6, decode it. */ 450 if (d != NULL) { 451 ip6cp = (struct ip6ctlparam *)d; 452 ip6 = ip6cp->ip6c_ip6; 453 } else { 454 ip6 = NULL; 455 } 456 457 if (!ip6) 458 return NULL; 459 460 var = gif_getref_variant(sc, &psref); 461 if (var->gv_psrc == NULL || var->gv_pdst == NULL) { 462 gif_putref_variant(var, &psref); 463 return NULL; 464 } 465 if (var->gv_psrc->sa_family != AF_INET6) { 466 gif_putref_variant(var, &psref); 467 return NULL; 468 } 469 gif_putref_variant(var, &psref); 470 471 ro = percpu_getref(sc->gif_ro_percpu); 472 dst6 = satocsin6(rtcache_getdst(ro)); 473 /* XXX scope */ 474 if (dst6 == NULL) 475 ; 476 else if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst6->sin6_addr)) 477 rtcache_free(ro); 478 479 percpu_putref(sc->gif_ro_percpu); 480 return NULL; 481 } 482 483 ENCAP_PR_WRAP_CTLINPUT(in6_gif_ctlinput) 484 #define in6_gif_ctlinput in6_gif_ctlinput_wrapper 485 486 static const struct encapsw in6_gif_encapsw = { 487 .encapsw6 = { 488 .pr_input = in6_gif_input, 489 .pr_ctlinput = in6_gif_ctlinput, 490 } 491 }; 492