in6_gif.c revision 155037
1208149Snwhitehorn/* $FreeBSD: head/sys/netinet6/in6_gif.c 155037 2006-01-30 08:39:09Z glebius $ */ 2208149Snwhitehorn/* $KAME: in6_gif.c,v 1.49 2001/05/14 14:02:17 itojun Exp $ */ 3208149Snwhitehorn 4208149Snwhitehorn/*- 5208149Snwhitehorn * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6208149Snwhitehorn * All rights reserved. 7208149Snwhitehorn * 8208149Snwhitehorn * Redistribution and use in source and binary forms, with or without 9208149Snwhitehorn * modification, are permitted provided that the following conditions 10208149Snwhitehorn * are met: 11208149Snwhitehorn * 1. Redistributions of source code must retain the above copyright 12208149Snwhitehorn * notice, this list of conditions and the following disclaimer. 13208149Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 14208149Snwhitehorn * notice, this list of conditions and the following disclaimer in the 15208149Snwhitehorn * documentation and/or other materials provided with the distribution. 16208149Snwhitehorn * 3. Neither the name of the project nor the names of its contributors 17208149Snwhitehorn * may be used to endorse or promote products derived from this software 18208149Snwhitehorn * without specific prior written permission. 19208149Snwhitehorn * 20208149Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21208149Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22208149Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23208149Snwhitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24208149Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25208149Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26227843Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27227843Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28227843Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29208149Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30208149Snwhitehorn * SUCH DAMAGE. 31208149Snwhitehorn */ 32208149Snwhitehorn 33208149Snwhitehorn#include "opt_inet.h" 34208149Snwhitehorn#include "opt_inet6.h" 35208149Snwhitehorn 36208149Snwhitehorn#include <sys/param.h> 37208149Snwhitehorn#include <sys/systm.h> 38208149Snwhitehorn#include <sys/socket.h> 39208149Snwhitehorn#include <sys/sockio.h> 40208149Snwhitehorn#include <sys/mbuf.h> 41208149Snwhitehorn#include <sys/errno.h> 42208149Snwhitehorn#include <sys/queue.h> 43208149Snwhitehorn#include <sys/syslog.h> 44208149Snwhitehorn#include <sys/protosw.h> 45208149Snwhitehorn 46208149Snwhitehorn#include <sys/malloc.h> 47208149Snwhitehorn 48208149Snwhitehorn#include <net/if.h> 49208149Snwhitehorn#include <net/route.h> 50208149Snwhitehorn 51208149Snwhitehorn#include <netinet/in.h> 52230993Snwhitehorn#include <netinet/in_systm.h> 53208149Snwhitehorn#ifdef INET 54208149Snwhitehorn#include <netinet/ip.h> 55208149Snwhitehorn#endif 56208149Snwhitehorn#include <netinet/ip_encap.h> 57208149Snwhitehorn#ifdef INET6 58208149Snwhitehorn#include <netinet/ip6.h> 59208149Snwhitehorn#include <netinet6/ip6_var.h> 60208149Snwhitehorn#include <netinet6/in6_gif.h> 61208149Snwhitehorn#include <netinet6/in6_var.h> 62208149Snwhitehorn#endif 63208149Snwhitehorn#include <netinet6/ip6protosw.h> 64208149Snwhitehorn#include <netinet/ip_ecn.h> 65208149Snwhitehorn#ifdef INET6 66208149Snwhitehorn#include <netinet6/ip6_ecn.h> 67208149Snwhitehorn#endif 68208149Snwhitehorn 69208149Snwhitehorn#include <net/if_gif.h> 70208149Snwhitehorn 71208149Snwhitehorn#include <net/net_osdep.h> 72208149Snwhitehorn 73208149Snwhitehornstatic int gif_validate6(const struct ip6_hdr *, struct gif_softc *, 74208149Snwhitehorn struct ifnet *); 75208149Snwhitehorn 76208149Snwhitehornextern struct domain inet6domain; 77208149Snwhitehornstruct ip6protosw in6_gif_protosw = 78208149Snwhitehorn{ SOCK_RAW, &inet6domain, 0/* IPPROTO_IPV[46] */, PR_ATOMIC|PR_ADDR, 79208149Snwhitehorn in6_gif_input, rip6_output, 0, rip6_ctloutput, 80208149Snwhitehorn 0, 81208149Snwhitehorn 0, 0, 0, 0, 82208149Snwhitehorn &rip6_usrreqs 83208149Snwhitehorn}; 84208149Snwhitehorn 85208149Snwhitehornint 86208149Snwhitehornin6_gif_output(ifp, family, m) 87208149Snwhitehorn struct ifnet *ifp; 88208149Snwhitehorn int family; /* family of the packet to be encapsulate. */ 89208149Snwhitehorn struct mbuf *m; 90208149Snwhitehorn{ 91208149Snwhitehorn struct gif_softc *sc = ifp->if_softc; 92208149Snwhitehorn struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst; 93208149Snwhitehorn struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc; 94227843Smarius struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst; 95208149Snwhitehorn struct ip6_hdr *ip6; 96208149Snwhitehorn struct etherip_header eiphdr; 97208149Snwhitehorn int proto, error; 98208149Snwhitehorn u_int8_t itos, otos; 99230993Snwhitehorn 100230993Snwhitehorn GIF_LOCK_ASSERT(sc); 101266160Sian 102208149Snwhitehorn if (sin6_src == NULL || sin6_dst == NULL || 103208149Snwhitehorn sin6_src->sin6_family != AF_INET6 || 104208149Snwhitehorn sin6_dst->sin6_family != AF_INET6) { 105208149Snwhitehorn m_freem(m); 106208149Snwhitehorn return EAFNOSUPPORT; 107208149Snwhitehorn } 108208149Snwhitehorn 109208149Snwhitehorn switch (family) { 110208149Snwhitehorn#ifdef INET 111208149Snwhitehorn case AF_INET: 112208149Snwhitehorn { 113208149Snwhitehorn struct ip *ip; 114208149Snwhitehorn 115208149Snwhitehorn proto = IPPROTO_IPV4; 116208149Snwhitehorn if (m->m_len < sizeof(*ip)) { 117208149Snwhitehorn m = m_pullup(m, sizeof(*ip)); 118208149Snwhitehorn if (!m) 119208149Snwhitehorn return ENOBUFS; 120208149Snwhitehorn } 121208149Snwhitehorn ip = mtod(m, struct ip *); 122208149Snwhitehorn itos = ip->ip_tos; 123208149Snwhitehorn break; 124208149Snwhitehorn } 125208149Snwhitehorn#endif 126208149Snwhitehorn#ifdef INET6 127208149Snwhitehorn case AF_INET6: 128208149Snwhitehorn { 129208149Snwhitehorn struct ip6_hdr *ip6; 130208149Snwhitehorn proto = IPPROTO_IPV6; 131208149Snwhitehorn if (m->m_len < sizeof(*ip6)) { 132208149Snwhitehorn m = m_pullup(m, sizeof(*ip6)); 133208149Snwhitehorn if (!m) 134208149Snwhitehorn return ENOBUFS; 135208149Snwhitehorn } 136208149Snwhitehorn ip6 = mtod(m, struct ip6_hdr *); 137266019Sian itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 138266019Sian break; 139266019Sian } 140208149Snwhitehorn#endif 141208149Snwhitehorn case AF_LINK: 142208149Snwhitehorn proto = IPPROTO_ETHERIP; 143208149Snwhitehorn eiphdr.eip_ver = ETHERIP_VERSION & ETHERIP_VER_VERS_MASK; 144208149Snwhitehorn eiphdr.eip_pad = 0; 145208149Snwhitehorn /* prepend Ethernet-in-IP header */ 146208149Snwhitehorn M_PREPEND(m, sizeof(struct etherip_header), M_DONTWAIT); 147208149Snwhitehorn if (m && m->m_len < sizeof(struct etherip_header)) 148208149Snwhitehorn m = m_pullup(m, sizeof(struct etherip_header)); 149208149Snwhitehorn if (m == NULL) 150208149Snwhitehorn return ENOBUFS; 151208149Snwhitehorn bcopy(&eiphdr, mtod(m, struct etherip_header *), 152208149Snwhitehorn sizeof(struct etherip_header)); 153208149Snwhitehorn break; 154266019Sian 155266019Sian default: 156266019Sian#ifdef DEBUG 157266019Sian printf("in6_gif_output: warning: unknown family %d passed\n", 158266019Sian family); 159266019Sian#endif 160266019Sian m_freem(m); 161208149Snwhitehorn return EAFNOSUPPORT; 162208149Snwhitehorn } 163266019Sian 164266019Sian /* prepend new IP header */ 165266019Sian M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); 166230993Snwhitehorn if (m && m->m_len < sizeof(struct ip6_hdr)) 167208149Snwhitehorn m = m_pullup(m, sizeof(struct ip6_hdr)); 168208149Snwhitehorn if (m == NULL) { 169208149Snwhitehorn printf("ENOBUFS in in6_gif_output %d\n", __LINE__); 170208149Snwhitehorn return ENOBUFS; 171208149Snwhitehorn } 172208149Snwhitehorn 173208149Snwhitehorn ip6 = mtod(m, struct ip6_hdr *); 174208149Snwhitehorn ip6->ip6_flow = 0; 175208149Snwhitehorn ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 176208149Snwhitehorn ip6->ip6_vfc |= IPV6_VERSION; 177208149Snwhitehorn ip6->ip6_plen = htons((u_short)m->m_pkthdr.len); 178208149Snwhitehorn ip6->ip6_nxt = proto; 179208149Snwhitehorn ip6->ip6_hlim = ip6_gif_hlim; 180208149Snwhitehorn ip6->ip6_src = sin6_src->sin6_addr; 181208149Snwhitehorn /* bidirectional configured tunnel mode */ 182208149Snwhitehorn if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) 183208149Snwhitehorn ip6->ip6_dst = sin6_dst->sin6_addr; 184208149Snwhitehorn else { 185208149Snwhitehorn m_freem(m); 186208149Snwhitehorn return ENETUNREACH; 187208149Snwhitehorn } 188208149Snwhitehorn ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE, 189208149Snwhitehorn &otos, &itos); 190208149Snwhitehorn ip6->ip6_flow &= ~htonl(0xff << 20); 191208149Snwhitehorn ip6->ip6_flow |= htonl((u_int32_t)otos << 20); 192208149Snwhitehorn 193208149Snwhitehorn if (dst->sin6_family != sin6_dst->sin6_family || 194208149Snwhitehorn !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) { 195208149Snwhitehorn /* cache route doesn't match */ 196208149Snwhitehorn bzero(dst, sizeof(*dst)); 197208149Snwhitehorn dst->sin6_family = sin6_dst->sin6_family; 198208149Snwhitehorn dst->sin6_len = sizeof(struct sockaddr_in6); 199208149Snwhitehorn dst->sin6_addr = sin6_dst->sin6_addr; 200208149Snwhitehorn if (sc->gif_ro6.ro_rt) { 201208149Snwhitehorn RTFREE(sc->gif_ro6.ro_rt); 202208149Snwhitehorn sc->gif_ro6.ro_rt = NULL; 203208149Snwhitehorn } 204208149Snwhitehorn#if 0 205208149Snwhitehorn GIF2IFP(sc)->if_mtu = GIF_MTU; 206208149Snwhitehorn#endif 207208149Snwhitehorn } 208208149Snwhitehorn 209208149Snwhitehorn if (sc->gif_ro6.ro_rt == NULL) { 210208149Snwhitehorn rtalloc((struct route *)&sc->gif_ro6); 211208149Snwhitehorn if (sc->gif_ro6.ro_rt == NULL) { 212208149Snwhitehorn m_freem(m); 213208149Snwhitehorn return ENETUNREACH; 214208149Snwhitehorn } 215208149Snwhitehorn 216208149Snwhitehorn /* if it constitutes infinite encapsulation, punt. */ 217208149Snwhitehorn if (sc->gif_ro.ro_rt->rt_ifp == ifp) { 218208149Snwhitehorn m_freem(m); 219208149Snwhitehorn return ENETUNREACH; /*XXX*/ 220208149Snwhitehorn } 221208149Snwhitehorn#if 0 222208149Snwhitehorn ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu 223208149Snwhitehorn - sizeof(struct ip6_hdr); 224208149Snwhitehorn#endif 225208149Snwhitehorn } 226208149Snwhitehorn 227208149Snwhitehorn#ifdef IPV6_MINMTU 228230993Snwhitehorn /* 229230993Snwhitehorn * force fragmentation to minimum MTU, to avoid path MTU discovery. 230208149Snwhitehorn * it is too painful to ask for resend of inner packet, to achieve 231208149Snwhitehorn * path MTU discovery for encapsulated packets. 232208149Snwhitehorn */ 233208149Snwhitehorn error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL, NULL); 234208149Snwhitehorn#else 235208149Snwhitehorn error = ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL, NULL); 236208149Snwhitehorn#endif 237208149Snwhitehorn 238208149Snwhitehorn if (!(GIF2IFP(sc)->if_flags & IFF_LINK0) && 239208149Snwhitehorn sc->gif_ro6.ro_rt != NULL) { 240208149Snwhitehorn RTFREE(sc->gif_ro6.ro_rt); 241230993Snwhitehorn sc->gif_ro6.ro_rt = NULL; 242208149Snwhitehorn } 243208149Snwhitehorn 244208149Snwhitehorn return (error); 245208149Snwhitehorn} 246208149Snwhitehorn 247208149Snwhitehornint 248208149Snwhitehornin6_gif_input(mp, offp, proto) 249208149Snwhitehorn struct mbuf **mp; 250208149Snwhitehorn int *offp, proto; 251208149Snwhitehorn{ 252208149Snwhitehorn struct mbuf *m = *mp; 253208149Snwhitehorn struct ifnet *gifp = NULL; 254208149Snwhitehorn struct gif_softc *sc; 255208149Snwhitehorn struct ip6_hdr *ip6; 256208149Snwhitehorn int af = 0; 257208149Snwhitehorn u_int32_t otos; 258208149Snwhitehorn 259208149Snwhitehorn ip6 = mtod(m, struct ip6_hdr *); 260208149Snwhitehorn 261208149Snwhitehorn sc = (struct gif_softc *)encap_getarg(m); 262208149Snwhitehorn if (sc == NULL) { 263208149Snwhitehorn m_freem(m); 264208149Snwhitehorn ip6stat.ip6s_nogif++; 265 return IPPROTO_DONE; 266 } 267 268 gifp = GIF2IFP(sc); 269 if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { 270 m_freem(m); 271 ip6stat.ip6s_nogif++; 272 return IPPROTO_DONE; 273 } 274 275 otos = ip6->ip6_flow; 276 m_adj(m, *offp); 277 278 switch (proto) { 279#ifdef INET 280 case IPPROTO_IPV4: 281 { 282 struct ip *ip; 283 u_int8_t otos8; 284 af = AF_INET; 285 otos8 = (ntohl(otos) >> 20) & 0xff; 286 if (m->m_len < sizeof(*ip)) { 287 m = m_pullup(m, sizeof(*ip)); 288 if (!m) 289 return IPPROTO_DONE; 290 } 291 ip = mtod(m, struct ip *); 292 if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ? 293 ECN_ALLOWED : ECN_NOCARE, 294 &otos8, &ip->ip_tos) == 0) { 295 m_freem(m); 296 return IPPROTO_DONE; 297 } 298 break; 299 } 300#endif /* INET */ 301#ifdef INET6 302 case IPPROTO_IPV6: 303 { 304 struct ip6_hdr *ip6; 305 af = AF_INET6; 306 if (m->m_len < sizeof(*ip6)) { 307 m = m_pullup(m, sizeof(*ip6)); 308 if (!m) 309 return IPPROTO_DONE; 310 } 311 ip6 = mtod(m, struct ip6_hdr *); 312 if (ip6_ecn_egress((gifp->if_flags & IFF_LINK1) ? 313 ECN_ALLOWED : ECN_NOCARE, 314 &otos, &ip6->ip6_flow) == 0) { 315 m_freem(m); 316 return IPPROTO_DONE; 317 } 318 break; 319 } 320#endif 321 case IPPROTO_ETHERIP: 322 af = AF_LINK; 323 break; 324 325 default: 326 ip6stat.ip6s_nogif++; 327 m_freem(m); 328 return IPPROTO_DONE; 329 } 330 331 gif_input(m, af, gifp); 332 return IPPROTO_DONE; 333} 334 335/* 336 * validate outer address. 337 */ 338static int 339gif_validate6(ip6, sc, ifp) 340 const struct ip6_hdr *ip6; 341 struct gif_softc *sc; 342 struct ifnet *ifp; 343{ 344 struct sockaddr_in6 *src, *dst; 345 346 src = (struct sockaddr_in6 *)sc->gif_psrc; 347 dst = (struct sockaddr_in6 *)sc->gif_pdst; 348 349 /* 350 * Check for address match. Note that the check is for an incoming 351 * packet. We should compare the *source* address in our configuration 352 * and the *destination* address of the packet, and vice versa. 353 */ 354 if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) || 355 !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src)) 356 return 0; 357 358 /* martian filters on outer source - done in ip6_input */ 359 360 /* ingress filters on outer source */ 361 if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) { 362 struct sockaddr_in6 sin6; 363 struct rtentry *rt; 364 365 bzero(&sin6, sizeof(sin6)); 366 sin6.sin6_family = AF_INET6; 367 sin6.sin6_len = sizeof(struct sockaddr_in6); 368 sin6.sin6_addr = ip6->ip6_src; 369 sin6.sin6_scope_id = 0; /* XXX */ 370 371 rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); 372 if (!rt || rt->rt_ifp != ifp) { 373#if 0 374 log(LOG_WARNING, "%s: packet from %s dropped " 375 "due to ingress filter\n", if_name(GIF2IFP(sc)), 376 ip6_sprintf(&sin6.sin6_addr)); 377#endif 378 if (rt) 379 rtfree(rt); 380 return 0; 381 } 382 rtfree(rt); 383 } 384 385 return 128 * 2; 386} 387 388/* 389 * we know that we are in IFF_UP, outer address available, and outer family 390 * matched the physical addr family. see gif_encapcheck(). 391 * sanity check for arg should have been done in the caller. 392 */ 393int 394gif_encapcheck6(m, off, proto, arg) 395 const struct mbuf *m; 396 int off; 397 int proto; 398 void *arg; 399{ 400 struct ip6_hdr ip6; 401 struct gif_softc *sc; 402 struct ifnet *ifp; 403 404 /* sanity check done in caller */ 405 sc = (struct gif_softc *)arg; 406 407 /* LINTED const cast */ 408 m_copydata(m, 0, sizeof(ip6), (caddr_t)&ip6); 409 ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; 410 411 return gif_validate6(&ip6, sc, ifp); 412} 413 414int 415in6_gif_attach(sc) 416 struct gif_softc *sc; 417{ 418 sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck, 419 (struct protosw *)&in6_gif_protosw, sc); 420 if (sc->encap_cookie6 == NULL) 421 return EEXIST; 422 return 0; 423} 424 425int 426in6_gif_detach(sc) 427 struct gif_softc *sc; 428{ 429 int error; 430 431 error = encap_detach(sc->encap_cookie6); 432 if (error == 0) 433 sc->encap_cookie6 = NULL; 434 return error; 435} 436