1105197Ssam/* $FreeBSD$ */ 2105197Ssam/* $OpenBSD: ip_ipip.c,v 1.25 2002/06/10 18:04:55 itojun Exp $ */ 3139823Simp/*- 4105197Ssam * The authors of this code are John Ioannidis (ji@tla.org), 5105197Ssam * Angelos D. Keromytis (kermit@csd.uch.gr) and 6105197Ssam * Niels Provos (provos@physnet.uni-hamburg.de). 7105197Ssam * 8105197Ssam * The original version of this code was written by John Ioannidis 9105197Ssam * for BSD/OS in Athens, Greece, in November 1995. 10105197Ssam * 11105197Ssam * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 12105197Ssam * by Angelos D. Keromytis. 13105197Ssam * 14105197Ssam * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis 15105197Ssam * and Niels Provos. 16105197Ssam * 17105197Ssam * Additional features in 1999 by Angelos D. Keromytis. 18105197Ssam * 19105197Ssam * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis, 20105197Ssam * Angelos D. Keromytis and Niels Provos. 21105197Ssam * Copyright (c) 2001, Angelos D. Keromytis. 22105197Ssam * 23105197Ssam * Permission to use, copy, and modify this software with or without fee 24105197Ssam * is hereby granted, provided that this entire notice is included in 25105197Ssam * all copies of any software which is or includes a copy or 26105197Ssam * modification of this software. 27105197Ssam * You may use this code under the GNU public license if you so wish. Please 28105197Ssam * contribute changes back to the authors under this freer than GPL license 29105197Ssam * so that we may further the use of strong encryption without limitations to 30105197Ssam * all. 31105197Ssam * 32105197Ssam * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 33105197Ssam * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 34105197Ssam * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 35105197Ssam * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 36105197Ssam * PURPOSE. 37105197Ssam */ 38105197Ssam 39105197Ssam/* 40105197Ssam * IP-inside-IP processing 41105197Ssam */ 42105197Ssam#include "opt_inet.h" 43105197Ssam#include "opt_inet6.h" 44159965Sthompsa#include "opt_enc.h" 45105197Ssam 46105197Ssam#include <sys/param.h> 47105197Ssam#include <sys/systm.h> 48105197Ssam#include <sys/mbuf.h> 49105197Ssam#include <sys/socket.h> 50105197Ssam#include <sys/kernel.h> 51105197Ssam#include <sys/protosw.h> 52105197Ssam#include <sys/sysctl.h> 53105197Ssam 54105197Ssam#include <net/if.h> 55171497Sbz#include <net/pfil.h> 56105197Ssam#include <net/route.h> 57105197Ssam#include <net/netisr.h> 58185571Sbz#include <net/vnet.h> 59105197Ssam 60105197Ssam#include <netinet/in.h> 61105197Ssam#include <netinet/in_systm.h> 62105197Ssam#include <netinet/in_var.h> 63105197Ssam#include <netinet/ip.h> 64105197Ssam#include <netinet/ip_ecn.h> 65105197Ssam#include <netinet/ip_var.h> 66105197Ssam#include <netinet/ip_encap.h> 67105197Ssam 68105197Ssam#include <netipsec/ipsec.h> 69105197Ssam#include <netipsec/xform.h> 70105197Ssam 71105197Ssam#include <netipsec/ipip_var.h> 72105197Ssam 73105197Ssam#ifdef INET6 74105197Ssam#include <netinet/ip6.h> 75105197Ssam#include <netipsec/ipsec6.h> 76105197Ssam#include <netinet6/ip6_ecn.h> 77105197Ssam#include <netinet6/in6_var.h> 78105197Ssam#include <netinet6/ip6protosw.h> 79105197Ssam#endif 80105197Ssam 81105197Ssam#include <netipsec/key.h> 82105197Ssam#include <netipsec/key_debug.h> 83105197Ssam 84105197Ssam#include <machine/stdarg.h> 85105197Ssam 86105197Ssam/* 87105197Ssam * We can control the acceptance of IP4 packets by altering the sysctl 88105197Ssam * net.inet.ipip.allow value. Zero means drop them, all else is acceptance. 89105197Ssam */ 90195699SrwatsonVNET_DEFINE(int, ipip_allow) = 0; 91195699SrwatsonVNET_DEFINE(struct ipipstat, ipipstat); 92105197Ssam 93105197SsamSYSCTL_DECL(_net_inet_ipip); 94195699SrwatsonSYSCTL_VNET_INT(_net_inet_ipip, OID_AUTO, 95195699Srwatson ipip_allow, CTLFLAG_RW, &VNET_NAME(ipip_allow), 0, ""); 96195699SrwatsonSYSCTL_VNET_STRUCT(_net_inet_ipip, IPSECCTL_STATS, 97195699Srwatson stats, CTLFLAG_RD, &VNET_NAME(ipipstat), ipipstat, ""); 98105197Ssam 99105197Ssam/* XXX IPCOMP */ 100105197Ssam#define M_IPSEC (M_AUTHIPHDR|M_AUTHIPDGM|M_DECRYPTED) 101105197Ssam 102105197Ssamstatic void _ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp); 103105197Ssam 104105197Ssam#ifdef INET6 105105197Ssam/* 106105197Ssam * Really only a wrapper for ipip_input(), for use with IPv6. 107105197Ssam */ 108105197Ssamint 109105197Ssamip4_input6(struct mbuf **m, int *offp, int proto) 110105197Ssam{ 111105197Ssam#if 0 112105197Ssam /* If we do not accept IP-in-IP explicitly, drop. */ 113181803Sbz if (!V_ipip_allow && ((*m)->m_flags & M_IPSEC) == 0) { 114120585Ssam DPRINTF(("%s: dropped due to policy\n", __func__)); 115252693Sae IPIPSTAT_INC(ipips_pdrops); 116105197Ssam m_freem(*m); 117105197Ssam return IPPROTO_DONE; 118105197Ssam } 119105197Ssam#endif 120105197Ssam _ipip_input(*m, *offp, NULL); 121105197Ssam return IPPROTO_DONE; 122105197Ssam} 123105197Ssam#endif /* INET6 */ 124105197Ssam 125105197Ssam#ifdef INET 126105197Ssam/* 127105197Ssam * Really only a wrapper for ipip_input(), for use with IPv4. 128105197Ssam */ 129105197Ssamvoid 130157306Sbzip4_input(struct mbuf *m, int off) 131105197Ssam{ 132105197Ssam#if 0 133105197Ssam /* If we do not accept IP-in-IP explicitly, drop. */ 134181803Sbz if (!V_ipip_allow && (m->m_flags & M_IPSEC) == 0) { 135120585Ssam DPRINTF(("%s: dropped due to policy\n", __func__)); 136252693Sae IPIPSTAT_INC(ipips_pdrops); 137105197Ssam m_freem(m); 138105197Ssam return; 139105197Ssam } 140105197Ssam#endif 141157306Sbz _ipip_input(m, off, NULL); 142105197Ssam} 143105197Ssam#endif /* INET */ 144105197Ssam 145105197Ssam/* 146105197Ssam * ipip_input gets called when we receive an IP{46} encapsulated packet, 147105197Ssam * either because we got it at a real interface, or because AH or ESP 148105197Ssam * were being used in tunnel mode (in which case the rcvif element will 149105197Ssam * contain the address of the encX interface associated with the tunnel. 150105197Ssam */ 151105197Ssam 152105197Ssamstatic void 153105197Ssam_ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp) 154105197Ssam{ 155105197Ssam struct ip *ipo; 156105197Ssam#ifdef INET6 157105197Ssam struct ip6_hdr *ip6 = NULL; 158105197Ssam u_int8_t itos; 159105197Ssam#endif 160105197Ssam int isr; 161105197Ssam u_int8_t otos; 162105197Ssam u_int8_t v; 163105197Ssam int hlen; 164105197Ssam 165252693Sae IPIPSTAT_INC(ipips_ipackets); 166105197Ssam 167105197Ssam m_copydata(m, 0, 1, &v); 168105197Ssam 169105197Ssam switch (v >> 4) { 170105197Ssam#ifdef INET 171105197Ssam case 4: 172105197Ssam hlen = sizeof(struct ip); 173105197Ssam break; 174105197Ssam#endif /* INET */ 175105197Ssam#ifdef INET6 176105197Ssam case 6: 177105197Ssam hlen = sizeof(struct ip6_hdr); 178105197Ssam break; 179105197Ssam#endif 180105197Ssam default: 181252693Sae IPIPSTAT_INC(ipips_family); 182105197Ssam m_freem(m); 183105197Ssam return /* EAFNOSUPPORT */; 184105197Ssam } 185105197Ssam 186105197Ssam /* Bring the IP header in the first mbuf, if not there already */ 187105197Ssam if (m->m_len < hlen) { 188105197Ssam if ((m = m_pullup(m, hlen)) == NULL) { 189120585Ssam DPRINTF(("%s: m_pullup (1) failed\n", __func__)); 190252693Sae IPIPSTAT_INC(ipips_hdrops); 191105197Ssam return; 192105197Ssam } 193105197Ssam } 194105197Ssam ipo = mtod(m, struct ip *); 195105197Ssam 196105197Ssam /* Keep outer ecn field. */ 197105197Ssam switch (v >> 4) { 198105197Ssam#ifdef INET 199105197Ssam case 4: 200105197Ssam otos = ipo->ip_tos; 201105197Ssam break; 202105197Ssam#endif /* INET */ 203105197Ssam#ifdef INET6 204105197Ssam case 6: 205105197Ssam otos = (ntohl(mtod(m, struct ip6_hdr *)->ip6_flow) >> 20) & 0xff; 206105197Ssam break; 207105197Ssam#endif 208105197Ssam default: 209105197Ssam panic("ipip_input: unknown ip version %u (outer)", v>>4); 210105197Ssam } 211105197Ssam 212105197Ssam /* Remove outer IP header */ 213105197Ssam m_adj(m, iphlen); 214105197Ssam 215105197Ssam /* Sanity check */ 216105197Ssam if (m->m_pkthdr.len < sizeof(struct ip)) { 217252693Sae IPIPSTAT_INC(ipips_hdrops); 218105197Ssam m_freem(m); 219105197Ssam return; 220105197Ssam } 221105197Ssam 222105197Ssam m_copydata(m, 0, 1, &v); 223105197Ssam 224105197Ssam switch (v >> 4) { 225105197Ssam#ifdef INET 226105197Ssam case 4: 227105197Ssam hlen = sizeof(struct ip); 228105197Ssam break; 229105197Ssam#endif /* INET */ 230105197Ssam 231105197Ssam#ifdef INET6 232105197Ssam case 6: 233105197Ssam hlen = sizeof(struct ip6_hdr); 234105197Ssam break; 235105197Ssam#endif 236105197Ssam default: 237252693Sae IPIPSTAT_INC(ipips_family); 238105197Ssam m_freem(m); 239105197Ssam return; /* EAFNOSUPPORT */ 240105197Ssam } 241105197Ssam 242105197Ssam /* 243105197Ssam * Bring the inner IP header in the first mbuf, if not there already. 244105197Ssam */ 245105197Ssam if (m->m_len < hlen) { 246105197Ssam if ((m = m_pullup(m, hlen)) == NULL) { 247120585Ssam DPRINTF(("%s: m_pullup (2) failed\n", __func__)); 248252693Sae IPIPSTAT_INC(ipips_hdrops); 249105197Ssam return; 250105197Ssam } 251105197Ssam } 252105197Ssam 253105197Ssam /* 254105197Ssam * RFC 1853 specifies that the inner TTL should not be touched on 255105197Ssam * decapsulation. There's no reason this comment should be here, but 256105197Ssam * this is as good as any a position. 257105197Ssam */ 258105197Ssam 259105197Ssam /* Some sanity checks in the inner IP header */ 260105197Ssam switch (v >> 4) { 261105197Ssam#ifdef INET 262105197Ssam case 4: 263105197Ssam ipo = mtod(m, struct ip *); 264181803Sbz ip_ecn_egress(V_ip4_ipsec_ecn, &otos, &ipo->ip_tos); 265105197Ssam break; 266105197Ssam#endif /* INET */ 267105197Ssam#ifdef INET6 268105197Ssam case 6: 269105197Ssam ip6 = (struct ip6_hdr *) ipo; 270105197Ssam itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 271181803Sbz ip_ecn_egress(V_ip6_ipsec_ecn, &otos, &itos); 272105197Ssam ip6->ip6_flow &= ~htonl(0xff << 20); 273105197Ssam ip6->ip6_flow |= htonl((u_int32_t) itos << 20); 274105197Ssam break; 275105197Ssam#endif 276105197Ssam default: 277105197Ssam panic("ipip_input: unknown ip version %u (inner)", v>>4); 278105197Ssam } 279105197Ssam 280105197Ssam /* Check for local address spoofing. */ 281105197Ssam if ((m->m_pkthdr.rcvif == NULL || 282105197Ssam !(m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK)) && 283181803Sbz V_ipip_allow != 2) { 284105197Ssam#ifdef INET 285264815Sae if ((v >> 4) == IPVERSION && 286264815Sae in_localip(ipo->ip_src) != 0) { 287264815Sae IPIPSTAT_INC(ipips_spoof); 288264815Sae m_freem(m); 289264815Sae return; 290264815Sae } 291264815Sae#endif 292105197Ssam#ifdef INET6 293264815Sae if ((v & IPV6_VERSION_MASK) == IPV6_VERSION && 294264815Sae in6_localip(&ip6->ip6_src) != 0) { 295264815Sae IPIPSTAT_INC(ipips_spoof); 296264815Sae m_freem(m); 297264815Sae return; 298105197Ssam } 299264815Sae#endif 300105197Ssam } 301105197Ssam 302105197Ssam /* Statistics */ 303252693Sae IPIPSTAT_ADD(ipips_ibytes, m->m_pkthdr.len - iphlen); 304105197Ssam 305159965Sthompsa#ifdef DEV_ENC 306174054Sbz switch (v >> 4) { 307174054Sbz#ifdef INET 308174054Sbz case 4: 309174054Sbz ipsec_bpf(m, NULL, AF_INET, ENC_IN|ENC_AFTER); 310174054Sbz break; 311174054Sbz#endif 312174054Sbz#ifdef INET6 313174054Sbz case 6: 314174054Sbz ipsec_bpf(m, NULL, AF_INET6, ENC_IN|ENC_AFTER); 315174054Sbz break; 316174054Sbz#endif 317174054Sbz default: 318174054Sbz panic("%s: bogus ip version %u", __func__, v>>4); 319174054Sbz } 320159965Sthompsa /* pass the mbuf to enc0 for packet filtering */ 321174054Sbz if (ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_AFTER) != 0) 322159965Sthompsa return; 323159965Sthompsa#endif 324159965Sthompsa 325105197Ssam /* 326105197Ssam * Interface pointer stays the same; if no IPsec processing has 327105197Ssam * been done (or will be done), this will point to a normal 328105197Ssam * interface. Otherwise, it'll point to an enc interface, which 329105197Ssam * will allow a packet filter to distinguish between secure and 330105197Ssam * untrusted packets. 331105197Ssam */ 332105197Ssam 333105197Ssam switch (v >> 4) { 334105197Ssam#ifdef INET 335105197Ssam case 4: 336105197Ssam isr = NETISR_IP; 337105197Ssam break; 338105197Ssam#endif 339105197Ssam#ifdef INET6 340105197Ssam case 6: 341105197Ssam isr = NETISR_IPV6; 342105197Ssam break; 343105197Ssam#endif 344105197Ssam default: 345120585Ssam panic("%s: bogus ip version %u", __func__, v>>4); 346105197Ssam } 347105197Ssam 348223637Sbz m_addr_changed(m); 349223637Sbz 350134391Sandre if (netisr_queue(isr, m)) { /* (0) on success. */ 351252693Sae IPIPSTAT_INC(ipips_qfull); 352120585Ssam DPRINTF(("%s: packet dropped because of full queue\n", 353120585Ssam __func__)); 354105197Ssam } 355105197Ssam} 356105197Ssam 357105197Ssamint 358105197Ssamipip_output( 359105197Ssam struct mbuf *m, 360105197Ssam struct ipsecrequest *isr, 361105197Ssam struct mbuf **mp, 362105197Ssam int skip, 363105197Ssam int protoff 364105197Ssam) 365105197Ssam{ 366105197Ssam struct secasvar *sav; 367105197Ssam u_int8_t tp, otos; 368105197Ssam struct secasindex *saidx; 369105197Ssam int error; 370221129Sbz#if defined(INET) || defined(INET6) 371221129Sbz u_int8_t itos; 372221129Sbz#endif 373105197Ssam#ifdef INET 374105197Ssam struct ip *ipo; 375105197Ssam#endif /* INET */ 376105197Ssam#ifdef INET6 377105197Ssam struct ip6_hdr *ip6, *ip6o; 378105197Ssam#endif /* INET6 */ 379105197Ssam 380105197Ssam sav = isr->sav; 381120585Ssam IPSEC_ASSERT(sav != NULL, ("null SA")); 382120585Ssam IPSEC_ASSERT(sav->sah != NULL, ("null SAH")); 383105197Ssam 384105197Ssam /* XXX Deal with empty TDB source/destination addresses. */ 385105197Ssam 386105197Ssam m_copydata(m, 0, 1, &tp); 387105197Ssam tp = (tp >> 4) & 0xff; /* Get the IP version number. */ 388105197Ssam 389105197Ssam saidx = &sav->sah->saidx; 390105197Ssam switch (saidx->dst.sa.sa_family) { 391105197Ssam#ifdef INET 392105197Ssam case AF_INET: 393105197Ssam if (saidx->src.sa.sa_family != AF_INET || 394105197Ssam saidx->src.sin.sin_addr.s_addr == INADDR_ANY || 395105197Ssam saidx->dst.sin.sin_addr.s_addr == INADDR_ANY) { 396120585Ssam DPRINTF(("%s: unspecified tunnel endpoint " 397120585Ssam "address in SA %s/%08lx\n", __func__, 398105197Ssam ipsec_address(&saidx->dst), 399105197Ssam (u_long) ntohl(sav->spi))); 400252693Sae IPIPSTAT_INC(ipips_unspec); 401105197Ssam error = EINVAL; 402105197Ssam goto bad; 403105197Ssam } 404105197Ssam 405111119Simp M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 406105197Ssam if (m == 0) { 407120585Ssam DPRINTF(("%s: M_PREPEND failed\n", __func__)); 408252693Sae IPIPSTAT_INC(ipips_hdrops); 409105197Ssam error = ENOBUFS; 410105197Ssam goto bad; 411105197Ssam } 412105197Ssam 413105197Ssam ipo = mtod(m, struct ip *); 414105197Ssam 415105197Ssam ipo->ip_v = IPVERSION; 416105197Ssam ipo->ip_hl = 5; 417105197Ssam ipo->ip_len = htons(m->m_pkthdr.len); 418181803Sbz ipo->ip_ttl = V_ip_defttl; 419105197Ssam ipo->ip_sum = 0; 420105197Ssam ipo->ip_src = saidx->src.sin.sin_addr; 421105197Ssam ipo->ip_dst = saidx->dst.sin.sin_addr; 422105197Ssam 423133720Sdwmalone ipo->ip_id = ip_newid(); 424105197Ssam 425105197Ssam /* If the inner protocol is IP... */ 426221129Sbz switch (tp) { 427221129Sbz case IPVERSION: 428105197Ssam /* Save ECN notification */ 429105197Ssam m_copydata(m, sizeof(struct ip) + 430105197Ssam offsetof(struct ip, ip_tos), 431105197Ssam sizeof(u_int8_t), (caddr_t) &itos); 432105197Ssam 433105197Ssam ipo->ip_p = IPPROTO_IPIP; 434105197Ssam 435105197Ssam /* 436105197Ssam * We should be keeping tunnel soft-state and 437105197Ssam * send back ICMPs if needed. 438105197Ssam */ 439105197Ssam m_copydata(m, sizeof(struct ip) + 440105197Ssam offsetof(struct ip, ip_off), 441105197Ssam sizeof(u_int16_t), (caddr_t) &ipo->ip_off); 442105197Ssam ipo->ip_off = ntohs(ipo->ip_off); 443105197Ssam ipo->ip_off &= ~(IP_DF | IP_MF | IP_OFFMASK); 444105197Ssam ipo->ip_off = htons(ipo->ip_off); 445221129Sbz break; 446105197Ssam#ifdef INET6 447221129Sbz case (IPV6_VERSION >> 4): 448221129Sbz { 449105197Ssam u_int32_t itos32; 450105197Ssam 451105197Ssam /* Save ECN notification. */ 452105197Ssam m_copydata(m, sizeof(struct ip) + 453105197Ssam offsetof(struct ip6_hdr, ip6_flow), 454105197Ssam sizeof(u_int32_t), (caddr_t) &itos32); 455105197Ssam itos = ntohl(itos32) >> 20; 456105197Ssam ipo->ip_p = IPPROTO_IPV6; 457105197Ssam ipo->ip_off = 0; 458221129Sbz break; 459105197Ssam } 460105197Ssam#endif /* INET6 */ 461221129Sbz default: 462105197Ssam goto nofamily; 463105197Ssam } 464105197Ssam 465105197Ssam otos = 0; 466105197Ssam ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 467105197Ssam ipo->ip_tos = otos; 468105197Ssam break; 469105197Ssam#endif /* INET */ 470105197Ssam 471105197Ssam#ifdef INET6 472105197Ssam case AF_INET6: 473105197Ssam if (IN6_IS_ADDR_UNSPECIFIED(&saidx->dst.sin6.sin6_addr) || 474105197Ssam saidx->src.sa.sa_family != AF_INET6 || 475105197Ssam IN6_IS_ADDR_UNSPECIFIED(&saidx->src.sin6.sin6_addr)) { 476120585Ssam DPRINTF(("%s: unspecified tunnel endpoint " 477120585Ssam "address in SA %s/%08lx\n", __func__, 478105197Ssam ipsec_address(&saidx->dst), 479105197Ssam (u_long) ntohl(sav->spi))); 480252693Sae IPIPSTAT_INC(ipips_unspec); 481105197Ssam error = ENOBUFS; 482105197Ssam goto bad; 483105197Ssam } 484105197Ssam 485105197Ssam /* scoped address handling */ 486105197Ssam ip6 = mtod(m, struct ip6_hdr *); 487105197Ssam if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) 488105197Ssam ip6->ip6_src.s6_addr16[1] = 0; 489105197Ssam if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) 490105197Ssam ip6->ip6_dst.s6_addr16[1] = 0; 491105197Ssam 492111119Simp M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); 493105197Ssam if (m == 0) { 494120585Ssam DPRINTF(("%s: M_PREPEND failed\n", __func__)); 495252693Sae IPIPSTAT_INC(ipips_hdrops); 496105197Ssam error = ENOBUFS; 497105197Ssam goto bad; 498105197Ssam } 499105197Ssam 500105197Ssam /* Initialize IPv6 header */ 501105197Ssam ip6o = mtod(m, struct ip6_hdr *); 502105197Ssam ip6o->ip6_flow = 0; 503105197Ssam ip6o->ip6_vfc &= ~IPV6_VERSION_MASK; 504105197Ssam ip6o->ip6_vfc |= IPV6_VERSION; 505105197Ssam ip6o->ip6_plen = htons(m->m_pkthdr.len); 506181803Sbz ip6o->ip6_hlim = V_ip_defttl; 507105197Ssam ip6o->ip6_dst = saidx->dst.sin6.sin6_addr; 508105197Ssam ip6o->ip6_src = saidx->src.sin6.sin6_addr; 509105197Ssam 510221129Sbz switch (tp) { 511105197Ssam#ifdef INET 512221129Sbz case IPVERSION: 513105197Ssam /* Save ECN notification */ 514105197Ssam m_copydata(m, sizeof(struct ip6_hdr) + 515105197Ssam offsetof(struct ip, ip_tos), sizeof(u_int8_t), 516105197Ssam (caddr_t) &itos); 517105197Ssam 518105197Ssam /* This is really IPVERSION. */ 519105197Ssam ip6o->ip6_nxt = IPPROTO_IPIP; 520221129Sbz break; 521105197Ssam#endif /* INET */ 522221129Sbz case (IPV6_VERSION >> 4): 523221129Sbz { 524221129Sbz u_int32_t itos32; 525105197Ssam 526221129Sbz /* Save ECN notification. */ 527221129Sbz m_copydata(m, sizeof(struct ip6_hdr) + 528221129Sbz offsetof(struct ip6_hdr, ip6_flow), 529221129Sbz sizeof(u_int32_t), (caddr_t) &itos32); 530221129Sbz itos = ntohl(itos32) >> 20; 531105197Ssam 532221129Sbz ip6o->ip6_nxt = IPPROTO_IPV6; 533241076Skevlo break; 534221129Sbz } 535221129Sbz default: 536221129Sbz goto nofamily; 537221129Sbz } 538105197Ssam 539105197Ssam otos = 0; 540105197Ssam ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 541105197Ssam ip6o->ip6_flow |= htonl((u_int32_t) otos << 20); 542105197Ssam break; 543105197Ssam#endif /* INET6 */ 544105197Ssam 545105197Ssam default: 546105197Ssamnofamily: 547120585Ssam DPRINTF(("%s: unsupported protocol family %u\n", __func__, 548105197Ssam saidx->dst.sa.sa_family)); 549252693Sae IPIPSTAT_INC(ipips_family); 550105197Ssam error = EAFNOSUPPORT; /* XXX diffs from openbsd */ 551105197Ssam goto bad; 552105197Ssam } 553105197Ssam 554252693Sae IPIPSTAT_INC(ipips_opackets); 555105197Ssam *mp = m; 556105197Ssam 557105197Ssam#ifdef INET 558105197Ssam if (saidx->dst.sa.sa_family == AF_INET) { 559105197Ssam#if 0 560105197Ssam if (sav->tdb_xform->xf_type == XF_IP4) 561105197Ssam tdb->tdb_cur_bytes += 562105197Ssam m->m_pkthdr.len - sizeof(struct ip); 563105197Ssam#endif 564252693Sae IPIPSTAT_ADD(ipips_obytes, 565252693Sae m->m_pkthdr.len - sizeof(struct ip)); 566105197Ssam } 567105197Ssam#endif /* INET */ 568105197Ssam 569105197Ssam#ifdef INET6 570105197Ssam if (saidx->dst.sa.sa_family == AF_INET6) { 571105197Ssam#if 0 572105197Ssam if (sav->tdb_xform->xf_type == XF_IP4) 573105197Ssam tdb->tdb_cur_bytes += 574105197Ssam m->m_pkthdr.len - sizeof(struct ip6_hdr); 575105197Ssam#endif 576252693Sae IPIPSTAT_ADD(ipips_obytes, 577252693Sae m->m_pkthdr.len - sizeof(struct ip6_hdr)); 578105197Ssam } 579105197Ssam#endif /* INET6 */ 580105197Ssam 581105197Ssam return 0; 582105197Ssambad: 583105197Ssam if (m) 584124765Ssam m_freem(m); 585124765Ssam *mp = NULL; 586105197Ssam return (error); 587105197Ssam} 588105197Ssam 589171167Sgnn#ifdef IPSEC 590221129Sbz#if defined(INET) || defined(INET6) 591105197Ssamstatic int 592105197Ssamipe4_init(struct secasvar *sav, struct xformsw *xsp) 593105197Ssam{ 594105197Ssam sav->tdb_xform = xsp; 595105197Ssam return 0; 596105197Ssam} 597105197Ssam 598105197Ssamstatic int 599105197Ssamipe4_zeroize(struct secasvar *sav) 600105197Ssam{ 601105197Ssam sav->tdb_xform = NULL; 602105197Ssam return 0; 603105197Ssam} 604105197Ssam 605105197Ssamstatic int 606105197Ssamipe4_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) 607105197Ssam{ 608105197Ssam /* This is a rather serious mistake, so no conditional printing. */ 609120585Ssam printf("%s: should never be called\n", __func__); 610105197Ssam if (m) 611105197Ssam m_freem(m); 612105197Ssam return EOPNOTSUPP; 613105197Ssam} 614105197Ssam 615105197Ssamstatic struct xformsw ipe4_xformsw = { 616105197Ssam XF_IP4, 0, "IPv4 Simple Encapsulation", 617105197Ssam ipe4_init, ipe4_zeroize, ipe4_input, ipip_output, 618105197Ssam}; 619105197Ssam 620105197Ssamextern struct domain inetdomain; 621221129Sbz#endif /* INET || INET6 */ 622221129Sbz#ifdef INET 623186791Sbzstatic struct protosw ipe4_protosw = { 624186791Sbz .pr_type = SOCK_RAW, 625186791Sbz .pr_domain = &inetdomain, 626186791Sbz .pr_protocol = IPPROTO_IPV4, 627186791Sbz .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 628186791Sbz .pr_input = ip4_input, 629186791Sbz .pr_ctloutput = rip_ctloutput, 630186791Sbz .pr_usrreqs = &rip_usrreqs 631157306Sbz}; 632221129Sbz#endif /* INET */ 633221129Sbz#if defined(INET6) && defined(INET) 634186791Sbzstatic struct ip6protosw ipe6_protosw = { 635186791Sbz .pr_type = SOCK_RAW, 636186791Sbz .pr_domain = &inetdomain, 637186791Sbz .pr_protocol = IPPROTO_IPV6, 638186791Sbz .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 639186791Sbz .pr_input = ip4_input6, 640186791Sbz .pr_ctloutput = rip_ctloutput, 641186791Sbz .pr_usrreqs = &rip_usrreqs 642157306Sbz}; 643221129Sbz#endif /* INET6 && INET */ 644105197Ssam 645221129Sbz#if defined(INET) 646105197Ssam/* 647105197Ssam * Check the encapsulated packet to see if we want it 648105197Ssam */ 649105197Ssamstatic int 650105197Ssamipe4_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 651105197Ssam{ 652105197Ssam /* 653105197Ssam * Only take packets coming from IPSEC tunnels; the rest 654105197Ssam * must be handled by the gif tunnel code. Note that we 655105197Ssam * also return a minimum priority when we want the packet 656105197Ssam * so any explicit gif tunnels take precedence. 657105197Ssam */ 658105197Ssam return ((m->m_flags & M_IPSEC) != 0 ? 1 : 0); 659105197Ssam} 660221129Sbz#endif /* INET */ 661105197Ssam 662105197Ssamstatic void 663105197Ssamipe4_attach(void) 664105197Ssam{ 665185088Szec 666105197Ssam xform_register(&ipe4_xformsw); 667105197Ssam /* attach to encapsulation framework */ 668105197Ssam /* XXX save return cookie for detach on module remove */ 669221129Sbz#ifdef INET 670105197Ssam (void) encap_attach_func(AF_INET, -1, 671157306Sbz ipe4_encapcheck, &ipe4_protosw, NULL); 672221129Sbz#endif 673221129Sbz#if defined(INET6) && defined(INET) 674105197Ssam (void) encap_attach_func(AF_INET6, -1, 675157306Sbz ipe4_encapcheck, (struct protosw *)&ipe6_protosw, NULL); 676105197Ssam#endif 677105197Ssam} 678105197SsamSYSINIT(ipe4_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ipe4_attach, NULL); 679171167Sgnn#endif /* IPSEC */ 680