Ejemplo n.º 1
0
/*
 * IPsec input callback for INET protocols.
 * This routine is called as the transform callback.
 * Takes care of filtering and other sanity checks on
 * the processed packet.
 */
int
ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
    int protoff)
{
	char buf[INET6_ADDRSTRLEN];
	struct ipsec_ctx_data ctx;
	int prot, af, sproto, isr_prot;
	struct ip *ip;
	struct m_tag *mtag;
	struct tdb_ident *tdbi;
	struct secasindex *saidx;
	int error;
#ifdef INET6
#ifdef notyet
	char ip6buf[INET6_ADDRSTRLEN];
#endif
#endif

	IPSEC_ASSERT(m != NULL, ("null mbuf"));
	IPSEC_ASSERT(sav != NULL, ("null SA"));
	IPSEC_ASSERT(sav->sah != NULL, ("null SAH"));
	saidx = &sav->sah->saidx;
	af = saidx->dst.sa.sa_family;
	IPSEC_ASSERT(af == AF_INET, ("unexpected af %u", af));
	sproto = saidx->proto;
	IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH ||
		sproto == IPPROTO_IPCOMP,
		("unexpected security protocol %u", sproto));

	/* Sanity check */
	if (m == NULL) {
		DPRINTF(("%s: null mbuf", __func__));
		IPSEC_ISTAT(sproto, badkcr);
		KEY_FREESAV(&sav);
		return EINVAL;
	}

	if (skip != 0) {
		/*
		 * Fix IPv4 header
		 * XXXGL: do we need this entire block?
		 */
		if (m->m_len < skip && (m = m_pullup(m, skip)) == NULL) {
			DPRINTF(("%s: processing failed for SA %s/%08lx\n",
			    __func__, ipsec_address(&sav->sah->saidx.dst,
			    buf, sizeof(buf)), (u_long) ntohl(sav->spi)));
			IPSEC_ISTAT(sproto, hdrops);
			error = ENOBUFS;
			goto bad;
		}

		ip = mtod(m, struct ip *);
		ip->ip_len = htons(m->m_pkthdr.len);
		ip->ip_sum = 0;
		ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
	} else {
Ejemplo n.º 2
0
/*
 * IPsec input callback, called by the transform callback. Takes care of
 * filtering and other sanity checks on the processed packet.
 */
int
ipsec_common_input_cb(struct mbuf *m, struct tdb *tdbp, int skip, int protoff,
    struct m_tag *mt)
{
	int af, sproto;
	u_char prot;

#if NBPFILTER > 0
	struct ifnet *encif;
#endif

#ifdef INET
	struct ip *ip, ipn;
#endif /* INET */

#ifdef INET6
	struct ip6_hdr *ip6, ip6n;
#endif /* INET6 */
	struct m_tag *mtag;
	struct tdb_ident *tdbi;

	af = tdbp->tdb_dst.sa.sa_family;
	sproto = tdbp->tdb_sproto;

	tdbp->tdb_last_used = time_second;

	/* Sanity check */
	if (m == NULL) {
		/* The called routine will print a message if necessary */
		IPSEC_ISTAT(espstat.esps_badkcr, ahstat.ahs_badkcr,
		    ipcompstat.ipcomps_badkcr);
		return EINVAL;
	}

#ifdef INET
	/* Fix IPv4 header */
	if (af == AF_INET) {
		if ((m->m_len < skip) && ((m = m_pullup(m, skip)) == NULL)) {
			DPRINTF(("ipsec_common_input_cb(): processing failed "
			    "for SA %s/%08x\n", ipsp_address(tdbp->tdb_dst),
			    ntohl(tdbp->tdb_spi)));
			IPSEC_ISTAT(espstat.esps_hdrops, ahstat.ahs_hdrops,
			    ipcompstat.ipcomps_hdrops);
			return ENOBUFS;
		}

		ip = mtod(m, struct ip *);
		ip->ip_len = htons(m->m_pkthdr.len);
		ip->ip_sum = 0;
		ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
		prot = ip->ip_p;

		/* IP-in-IP encapsulation */
		if (prot == IPPROTO_IPIP) {
			if (m->m_pkthdr.len - skip < sizeof(struct ip)) {
				m_freem(m);
				IPSEC_ISTAT(espstat.esps_hdrops,
				    ahstat.ahs_hdrops,
				    ipcompstat.ipcomps_hdrops);
				return EINVAL;
			}
			/* ipn will now contain the inner IPv4 header */
			m_copydata(m, skip, sizeof(struct ip),
			    (caddr_t) &ipn);

			/*
			 * Check that the inner source address is the same as
			 * the proxy address, if available.
			 */
			if ((tdbp->tdb_proxy.sa.sa_family == AF_INET &&
			    tdbp->tdb_proxy.sin.sin_addr.s_addr !=
			    INADDR_ANY &&
			    ipn.ip_src.s_addr !=
			    tdbp->tdb_proxy.sin.sin_addr.s_addr) ||
			    (tdbp->tdb_proxy.sa.sa_family != AF_INET &&
				tdbp->tdb_proxy.sa.sa_family != 0)) {
#if ENCDEBUG
				char addr[INET_ADDRSTRLEN];
#endif

				DPRINTF(("ipsec_common_input_cb(): inner "
				    "source address %s doesn't correspond to "
				    "expected proxy source %s, SA %s/%08x\n",
				    inet_ntop(AF_INET, &ipn.ip_src,
					addr, sizeof(addr)),
				    ipsp_address(tdbp->tdb_proxy),
				    ipsp_address(tdbp->tdb_dst),
				    ntohl(tdbp->tdb_spi)));

				m_freem(m);
				IPSEC_ISTAT(espstat.esps_pdrops,
				    ahstat.ahs_pdrops,
				    ipcompstat.ipcomps_pdrops);
				return EACCES;
			}
		}

#ifdef INET6
		/* IPv6-in-IP encapsulation. */
		if (prot == IPPROTO_IPV6) {
			if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) {
				m_freem(m);
				IPSEC_ISTAT(espstat.esps_hdrops,
				    ahstat.ahs_hdrops,
				    ipcompstat.ipcomps_hdrops);
				return EINVAL;
			}
			/* ip6n will now contain the inner IPv6 header. */
			m_copydata(m, skip, sizeof(struct ip6_hdr),
			    (caddr_t) &ip6n);

			/*
			 * Check that the inner source address is the same as
			 * the proxy address, if available.
			 */
			if ((tdbp->tdb_proxy.sa.sa_family == AF_INET6 &&
			    !IN6_IS_ADDR_UNSPECIFIED(&tdbp->tdb_proxy.sin6.sin6_addr) &&
			    !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
				&tdbp->tdb_proxy.sin6.sin6_addr)) ||
			    (tdbp->tdb_proxy.sa.sa_family != AF_INET6 &&
				tdbp->tdb_proxy.sa.sa_family != 0)) {
#if ENCDEBUG
				char addr[INET6_ADDRSTRLEN];
#endif

				DPRINTF(("ipsec_common_input_cb(): inner "
				    "source address %s doesn't correspond to "
				    "expected proxy source %s, SA %s/%08x\n",
				    inet_ntop(AF_INET6, &ip6n.ip6_src,
					addr, sizeof(addr)),
				    ipsp_address(tdbp->tdb_proxy),
				    ipsp_address(tdbp->tdb_dst),
				    ntohl(tdbp->tdb_spi)));

				m_freem(m);
				IPSEC_ISTAT(espstat.esps_pdrops,
				    ahstat.ahs_pdrops,
				    ipcompstat.ipcomps_pdrops);
				return EACCES;
			}
		}
#endif /* INET6 */
	}
#endif /* INET */

#ifdef INET6
	/* Fix IPv6 header */
	if (af == AF_INET6)
	{
		if (m->m_len < sizeof(struct ip6_hdr) &&
		    (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {

			DPRINTF(("ipsec_common_input_cb(): processing failed "
			    "for SA %s/%08x\n", ipsp_address(tdbp->tdb_dst),
			    ntohl(tdbp->tdb_spi)));

			IPSEC_ISTAT(espstat.esps_hdrops, ahstat.ahs_hdrops,
			    ipcompstat.ipcomps_hdrops);
			return EACCES;
		}

		ip6 = mtod(m, struct ip6_hdr *);
		ip6->ip6_plen = htons(m->m_pkthdr.len - skip);

		/* Save protocol */
		m_copydata(m, protoff, 1, (caddr_t) &prot);

#ifdef INET
		/* IP-in-IP encapsulation */
		if (prot == IPPROTO_IPIP) {
			if (m->m_pkthdr.len - skip < sizeof(struct ip)) {
				m_freem(m);
				IPSEC_ISTAT(espstat.esps_hdrops,
				    ahstat.ahs_hdrops,
				    ipcompstat.ipcomps_hdrops);
				return EINVAL;
			}
			/* ipn will now contain the inner IPv4 header */
			m_copydata(m, skip, sizeof(struct ip), (caddr_t) &ipn);

			/*
			 * Check that the inner source address is the same as
			 * the proxy address, if available.
			 */
			if ((tdbp->tdb_proxy.sa.sa_family == AF_INET &&
			    tdbp->tdb_proxy.sin.sin_addr.s_addr !=
			    INADDR_ANY &&
			    ipn.ip_src.s_addr !=
				tdbp->tdb_proxy.sin.sin_addr.s_addr) ||
			    (tdbp->tdb_proxy.sa.sa_family != AF_INET &&
				tdbp->tdb_proxy.sa.sa_family != 0)) {
#if ENCDEBUG
				char addr[INET_ADDRSTRLEN];
#endif

				DPRINTF(("ipsec_common_input_cb(): inner "
				    "source address %s doesn't correspond to "
				    "expected proxy source %s, SA %s/%08x\n",
				    inet_ntop(AF_INET, &ipn.ip_src,
					addr, sizeof(addr)),
				    ipsp_address(tdbp->tdb_proxy),
				    ipsp_address(tdbp->tdb_dst),
				    ntohl(tdbp->tdb_spi)));

				m_freem(m);
				IPSEC_ISTAT(espstat.esps_pdrops,
				    ahstat.ahs_pdrops,
				    ipcompstat.ipcomps_pdrops);
				return EACCES;
			}
		}
#endif /* INET */

		/* IPv6-in-IP encapsulation */
		if (prot == IPPROTO_IPV6) {
			if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) {
				m_freem(m);
				IPSEC_ISTAT(espstat.esps_hdrops,
				    ahstat.ahs_hdrops,
				    ipcompstat.ipcomps_hdrops);
				return EINVAL;
			}
			/* ip6n will now contain the inner IPv6 header. */
			m_copydata(m, skip, sizeof(struct ip6_hdr),
			    (caddr_t) &ip6n);

			/*
			 * Check that the inner source address is the same as
			 * the proxy address, if available.
			 */
			if ((tdbp->tdb_proxy.sa.sa_family == AF_INET6 &&
			    !IN6_IS_ADDR_UNSPECIFIED(&tdbp->tdb_proxy.sin6.sin6_addr) &&
			    !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
				&tdbp->tdb_proxy.sin6.sin6_addr)) ||
			    (tdbp->tdb_proxy.sa.sa_family != AF_INET6 &&
				tdbp->tdb_proxy.sa.sa_family != 0)) {
#if ENCDEBUG
				char addr[INET6_ADDRSTRLEN];
#endif

				DPRINTF(("ipsec_common_input_cb(): inner "
				    "source address %s doesn't correspond to "
				    "expected proxy source %s, SA %s/%08x\n",
				    inet_ntop(AF_INET6, &ip6n.ip6_src,
					addr, sizeof(addr)),
				    ipsp_address(tdbp->tdb_proxy),
				    ipsp_address(tdbp->tdb_dst),
				    ntohl(tdbp->tdb_spi)));

				m_freem(m);
				IPSEC_ISTAT(espstat.esps_pdrops,
				    ahstat.ahs_pdrops,
				    ipcompstat.ipcomps_pdrops);
				return EACCES;
			}
		}
	}
#endif /* INET6 */

	/*
	 * Fix TCP/UDP checksum of UDP encapsulated transport mode ESP packet.
	 * (RFC3948 3.1.2)
	 */
	if ((af == AF_INET || af == AF_INET6) &&
	    (tdbp->tdb_flags & TDBF_UDPENCAP) &&
	    (tdbp->tdb_flags & TDBF_TUNNELING) == 0) {
		u_int16_t cksum;

		switch (prot) {
		case IPPROTO_UDP:
			if (m->m_pkthdr.len < skip + sizeof(struct udphdr)) {
				m_freem(m);
				IPSEC_ISTAT(espstat.esps_hdrops,
				    ahstat.ahs_hdrops,
				    ipcompstat.ipcomps_hdrops);
				return EINVAL;
			}
			cksum = 0;
			m_copyback(m, skip + offsetof(struct udphdr, uh_sum),
			    sizeof(cksum), &cksum, M_NOWAIT);
#ifdef INET6
			if (af == AF_INET6) {
				cksum = in6_cksum(m, IPPROTO_UDP, skip,
				    m->m_pkthdr.len - skip);
				m_copyback(m, skip + offsetof(struct udphdr,
				    uh_sum), sizeof(cksum), &cksum, M_NOWAIT);
			}
#endif
			break;
		case IPPROTO_TCP:
			if (m->m_pkthdr.len < skip + sizeof(struct tcphdr)) {
				m_freem(m);
				IPSEC_ISTAT(espstat.esps_hdrops,
				    ahstat.ahs_hdrops,
				    ipcompstat.ipcomps_hdrops);
				return EINVAL;
			}
			cksum = 0;
			m_copyback(m, skip + offsetof(struct tcphdr, th_sum),
			    sizeof(cksum), &cksum, M_NOWAIT);
			if (af == AF_INET)
				cksum = in4_cksum(m, IPPROTO_TCP, skip,
				    m->m_pkthdr.len - skip);
#ifdef INET6
			else if (af == AF_INET6)
				cksum = in6_cksum(m, IPPROTO_TCP, skip,
				    m->m_pkthdr.len - skip);
#endif
			m_copyback(m, skip + offsetof(struct tcphdr, th_sum),
			    sizeof(cksum), &cksum, M_NOWAIT);
			break;
		}
Ejemplo n.º 3
0
/*
 * ipsec_common_input gets called when an IPsec-protected packet
 * is received by IPv4 or IPv6.  Its job is to find the right SA
 * and call the appropriate transform.  The transform callback
 * takes care of further processing (like ingress filtering).
 */
int
ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
{
	char buf[INET6_ADDRSTRLEN];
	union sockaddr_union dst_address;
	struct secasvar *sav;
	u_int32_t spi;
	int error;
#ifdef INET
#ifdef IPSEC_NAT_T
	struct m_tag *tag;
#endif
#endif

	IPSEC_ISTAT(sproto, input);

	IPSEC_ASSERT(m != NULL, ("null packet"));

	IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH ||
		sproto == IPPROTO_IPCOMP,
		("unexpected security protocol %u", sproto));

	if ((sproto == IPPROTO_ESP && !V_esp_enable) ||
	    (sproto == IPPROTO_AH && !V_ah_enable) ||
	    (sproto == IPPROTO_IPCOMP && !V_ipcomp_enable)) {
		m_freem(m);
		IPSEC_ISTAT(sproto, pdrops);
		return EOPNOTSUPP;
	}

	if (m->m_pkthdr.len - skip < 2 * sizeof (u_int32_t)) {
		m_freem(m);
		IPSEC_ISTAT(sproto, hdrops);
		DPRINTF(("%s: packet too small\n", __func__));
		return EINVAL;
	}

	/* Retrieve the SPI from the relevant IPsec header */
	if (sproto == IPPROTO_ESP)
		m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi);
	else if (sproto == IPPROTO_AH)
		m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t),
		    (caddr_t) &spi);
	else if (sproto == IPPROTO_IPCOMP) {
		u_int16_t cpi;
		m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t),
		    (caddr_t) &cpi);
		spi = ntohl(htons(cpi));
	}

	/*
	 * Find the SA and (indirectly) call the appropriate
	 * kernel crypto routine. The resulting mbuf chain is a valid
	 * IP packet ready to go through input processing.
	 */
	bzero(&dst_address, sizeof (dst_address));
	dst_address.sa.sa_family = af;
	switch (af) {
#ifdef INET
	case AF_INET:
		dst_address.sin.sin_len = sizeof(struct sockaddr_in);
		m_copydata(m, offsetof(struct ip, ip_dst),
		    sizeof(struct in_addr),
		    (caddr_t) &dst_address.sin.sin_addr);
#ifdef IPSEC_NAT_T
		/* Find the source port for NAT-T; see udp*_espdecap. */
		tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL);
		if (tag != NULL)
			dst_address.sin.sin_port = ((u_int16_t *)(tag + 1))[1];
#endif /* IPSEC_NAT_T */
		break;
#endif /* INET */
#ifdef INET6
	case AF_INET6:
		dst_address.sin6.sin6_len = sizeof(struct sockaddr_in6);
		m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
		    sizeof(struct in6_addr),
		    (caddr_t) &dst_address.sin6.sin6_addr);
		/* We keep addresses in SADB without embedded scope id */
		if (IN6_IS_SCOPE_LINKLOCAL(&dst_address.sin6.sin6_addr)) {
			/* XXX: sa6_recoverscope() */
			dst_address.sin6.sin6_scope_id =
			    ntohs(dst_address.sin6.sin6_addr.s6_addr16[1]);
			dst_address.sin6.sin6_addr.s6_addr16[1] = 0;
		}
		break;
#endif /* INET6 */
	default:
		DPRINTF(("%s: unsupported protocol family %u\n", __func__, af));
		m_freem(m);
		IPSEC_ISTAT(sproto, nopf);
		return EPFNOSUPPORT;
	}

	/* NB: only pass dst since key_allocsa follows RFC2401 */
	sav = KEY_ALLOCSA(&dst_address, sproto, spi);
	if (sav == NULL) {
		DPRINTF(("%s: no key association found for SA %s/%08lx/%u\n",
		    __func__, ipsec_address(&dst_address, buf, sizeof(buf)),
		    (u_long) ntohl(spi), sproto));
		IPSEC_ISTAT(sproto, notdb);
		m_freem(m);
		return ENOENT;
	}

	if (sav->tdb_xform == NULL) {
		DPRINTF(("%s: attempted to use uninitialized SA %s/%08lx/%u\n",
		    __func__, ipsec_address(&dst_address, buf, sizeof(buf)),
		    (u_long) ntohl(spi), sproto));
		IPSEC_ISTAT(sproto, noxform);
		KEY_FREESAV(&sav);
		m_freem(m);
		return ENXIO;
	}

	/*
	 * Call appropriate transform and return -- callback takes care of
	 * everything else.
	 */
	error = (*sav->tdb_xform->xf_input)(m, sav, skip, protoff);
	KEY_FREESAV(&sav);
	return error;
}
Ejemplo n.º 4
0
/*
 * ipsec_common_input() gets called when we receive an IPsec-protected packet
 * in IPv4 or IPv6. All it does is find the right TDB and call the appropriate
 * transform. The callback takes care of further processing (like ingress
 * filtering).
 */
int
ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto,
    int udpencap)
{
#define IPSEC_ISTAT(x,y,z) (sproto == IPPROTO_ESP ? (x)++ : \
			    sproto == IPPROTO_AH ? (y)++ : (z)++)

	union sockaddr_union dst_address;
	struct timeval tv;
	struct tdb *tdbp;
	struct ifnet *encif;
	u_int32_t spi;
	u_int16_t cpi;
	int s, error;

	IPSEC_ISTAT(espstat.esps_input, ahstat.ahs_input,
	    ipcompstat.ipcomps_input);

	if (m == 0) {
		DPRINTF(("ipsec_common_input(): NULL packet received\n"));
		IPSEC_ISTAT(espstat.esps_hdrops, ahstat.ahs_hdrops,
		    ipcompstat.ipcomps_hdrops);
		return EINVAL;
	}

	if ((sproto == IPPROTO_ESP && !esp_enable) ||
	    (sproto == IPPROTO_AH && !ah_enable) ||
#if NPF > 0
	    (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) ||
#endif
	    (sproto == IPPROTO_IPCOMP && !ipcomp_enable)) {
		switch (af) {
#ifdef INET
		case AF_INET:
			rip_input(m, skip, sproto);
			break;
#endif /* INET */
#ifdef INET6
		case AF_INET6:
			rip6_input(&m, &skip, sproto);
			break;
#endif /* INET6 */
		default:
			DPRINTF(("ipsec_common_input(): unsupported protocol "
			    "family %d\n", af));
			m_freem(m);
			IPSEC_ISTAT(espstat.esps_nopf, ahstat.ahs_nopf,
			    ipcompstat.ipcomps_nopf);
			return EPFNOSUPPORT;
		}
		return 0;
	}
	if ((sproto == IPPROTO_IPCOMP) && (m->m_flags & M_COMP)) {
		m_freem(m);
		ipcompstat.ipcomps_pdrops++;
		DPRINTF(("ipsec_common_input(): repeated decompression\n"));
		return EINVAL;
	}

	if (m->m_pkthdr.len - skip < 2 * sizeof(u_int32_t)) {
		m_freem(m);
		IPSEC_ISTAT(espstat.esps_hdrops, ahstat.ahs_hdrops,
		    ipcompstat.ipcomps_hdrops);
		DPRINTF(("ipsec_common_input(): packet too small\n"));
		return EINVAL;
	}

	/* Retrieve the SPI from the relevant IPsec header */
	if (sproto == IPPROTO_ESP)
		m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi);
	else if (sproto == IPPROTO_AH)
		m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t),
		    (caddr_t) &spi);
	else if (sproto == IPPROTO_IPCOMP) {
		m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t),
		    (caddr_t) &cpi);
		spi = ntohl(htons(cpi));
	}

	/*
	 * Find tunnel control block and (indirectly) call the appropriate
	 * kernel crypto routine. The resulting mbuf chain is a valid
	 * IP packet ready to go through input processing.
	 */

	memset(&dst_address, 0, sizeof(dst_address));
	dst_address.sa.sa_family = af;

	switch (af) {
#ifdef INET
	case AF_INET:
		dst_address.sin.sin_len = sizeof(struct sockaddr_in);
		m_copydata(m, offsetof(struct ip, ip_dst),
		    sizeof(struct in_addr),
		    (caddr_t) &(dst_address.sin.sin_addr));
		break;
#endif /* INET */

#ifdef INET6
	case AF_INET6:
		dst_address.sin6.sin6_len = sizeof(struct sockaddr_in6);
		m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
		    sizeof(struct in6_addr),
		    (caddr_t) &(dst_address.sin6.sin6_addr));
		in6_recoverscope(&dst_address.sin6, &dst_address.sin6.sin6_addr,
		    NULL);
		break;
#endif /* INET6 */

	default:
		DPRINTF(("ipsec_common_input(): unsupported protocol "
		    "family %d\n", af));
		m_freem(m);
		IPSEC_ISTAT(espstat.esps_nopf, ahstat.ahs_nopf,
		    ipcompstat.ipcomps_nopf);
		return EPFNOSUPPORT;
	}

	s = splsoftnet();
	tdbp = gettdb(rtable_l2(m->m_pkthdr.ph_rtableid),
	    spi, &dst_address, sproto);
	if (tdbp == NULL) {
		splx(s);
		DPRINTF(("ipsec_common_input(): could not find SA for "
		    "packet to %s, spi %08x\n",
		    ipsp_address(dst_address), ntohl(spi)));
		m_freem(m);
		IPSEC_ISTAT(espstat.esps_notdb, ahstat.ahs_notdb,
		    ipcompstat.ipcomps_notdb);
		return ENOENT;
	}

	if (tdbp->tdb_flags & TDBF_INVALID) {
		splx(s);
		DPRINTF(("ipsec_common_input(): attempted to use invalid SA %s/%08x/%u\n", ipsp_address(dst_address), ntohl(spi), tdbp->tdb_sproto));
		m_freem(m);
		IPSEC_ISTAT(espstat.esps_invalid, ahstat.ahs_invalid,
		    ipcompstat.ipcomps_invalid);
		return EINVAL;
	}

	if (udpencap && !(tdbp->tdb_flags & TDBF_UDPENCAP)) {
		splx(s);
		DPRINTF(("ipsec_common_input(): attempted to use non-udpencap SA %s/%08x/%u\n", ipsp_address(dst_address), ntohl(spi), tdbp->tdb_sproto));
		m_freem(m);
		espstat.esps_udpinval++;
		return EINVAL;
	}

	if (tdbp->tdb_xform == NULL) {
		splx(s);
		DPRINTF(("ipsec_common_input(): attempted to use uninitialized SA %s/%08x/%u\n", ipsp_address(dst_address), ntohl(spi), tdbp->tdb_sproto));
		m_freem(m);
		IPSEC_ISTAT(espstat.esps_noxform, ahstat.ahs_noxform,
		    ipcompstat.ipcomps_noxform);
		return ENXIO;
	}

	if (sproto != IPPROTO_IPCOMP) {
		if ((encif = enc_getif(tdbp->tdb_rdomain,
		    tdbp->tdb_tap)) == NULL) {
			splx(s);
			DPRINTF(("ipsec_common_input(): "
			    "no enc%u interface for SA %s/%08x/%u\n",
			    tdbp->tdb_tap, ipsp_address(dst_address),
			    ntohl(spi), tdbp->tdb_sproto));
			m_freem(m);

			IPSEC_ISTAT(espstat.esps_pdrops,
			    ahstat.ahs_pdrops,
			    ipcompstat.ipcomps_pdrops);
			return EACCES;
		}

		/* XXX This conflicts with the scoped nature of IPv6 */
		m->m_pkthdr.rcvif = encif;
	}

	/* Register first use, setup expiration timer. */
	if (tdbp->tdb_first_use == 0) {
		tdbp->tdb_first_use = time_second;

		tv.tv_usec = 0;

		tv.tv_sec = tdbp->tdb_exp_first_use + tdbp->tdb_first_use;
		if (tdbp->tdb_flags & TDBF_FIRSTUSE)
			timeout_add(&tdbp->tdb_first_tmo, hzto(&tv));

		tv.tv_sec = tdbp->tdb_first_use + tdbp->tdb_soft_first_use;
		if (tdbp->tdb_flags & TDBF_SOFT_FIRSTUSE)
			timeout_add(&tdbp->tdb_sfirst_tmo, hzto(&tv));
	}

	/*
	 * Call appropriate transform and return -- callback takes care of
	 * everything else.
	 */
	error = (*(tdbp->tdb_xform->xf_input))(m, tdbp, skip, protoff);
	splx(s);
	return error;
}