Exemple #1
0
static void check_and_compress_jpeg(int quality, unsigned char *outbuf, const unsigned char *inbuf,
                                    int width, int height, int bufsize)
{
	/* JPEG's are always multiples of 16, extra is ignored in AVI's */
	if ((width & 0xF) || (height & 0xF)) {
		int i, rrowstride, jrowstride;
		int jwidth = PADUP(width, 16);
		int jheight = PADUP(height, 16);
		unsigned char *tmpbuf = MEM_mallocN(jwidth * jheight * 3, "avi.check_and_compress_jpeg");

		/* resize the realbuf into the tmpbuf */
		rrowstride = width * 3;
		jrowstride = jwidth * 3;
		for (i = 0; i < jheight; i++) {
			if (i < height)
				memcpy(&tmpbuf[i * jrowstride], &inbuf[i * rrowstride], rrowstride);
			else
				memset(&tmpbuf[i * jrowstride], 0, rrowstride);
			memset(&tmpbuf[i * jrowstride + rrowstride], 0, jrowstride - rrowstride);
		}

		Compress_JPEG(quality, outbuf, tmpbuf, jwidth, jheight, bufsize);

		MEM_freeN(tmpbuf);
	}
	else {
		Compress_JPEG(quality, outbuf, inbuf, width, height, bufsize);
	}
}
Exemple #2
0
void
export_identity(void **p, struct tdb *tdb, int type)
{
	struct ipsec_ref **ipr;
	struct sadb_ident *sadb_ident = (struct sadb_ident *) *p;

	if (type == PFKEYV2_IDENTITY_SRC)
		ipr = &tdb->tdb_srcid;
	else
		ipr = &tdb->tdb_dstid;

	sadb_ident->sadb_ident_len = (sizeof(struct sadb_ident) +
	    PADUP((*ipr)->ref_len)) / sizeof(uint64_t);

	switch ((*ipr)->ref_type) {
	case IPSP_IDENTITY_PREFIX:
		sadb_ident->sadb_ident_type = SADB_IDENTTYPE_PREFIX;
		break;
	case IPSP_IDENTITY_FQDN:
		sadb_ident->sadb_ident_type = SADB_IDENTTYPE_FQDN;
		break;
	case IPSP_IDENTITY_USERFQDN:
		sadb_ident->sadb_ident_type = SADB_IDENTTYPE_USERFQDN;
		break;
	case IPSP_IDENTITY_CONNECTION:
		sadb_ident->sadb_ident_type = SADB_X_IDENTTYPE_CONNECTION;
		break;
	}
	*p += sizeof(struct sadb_ident);
	bcopy((*ipr) + 1, *p, (*ipr)->ref_len);
	*p += PADUP((*ipr)->ref_len);
}
Exemple #3
0
void
export_credentials(void **p, struct tdb *tdb, int dstcred)
{
	struct ipsec_ref **ipr;
	struct sadb_x_cred *sadb_cred = (struct sadb_x_cred *) *p;

	if (dstcred == PFKEYV2_CRED_REMOTE)
		ipr = &tdb->tdb_remote_cred;
	else
		ipr = &tdb->tdb_local_cred;

	sadb_cred->sadb_x_cred_len = (sizeof(struct sadb_x_cred) +
	    PADUP((*ipr)->ref_len)) / sizeof(uint64_t);

	switch ((*ipr)->ref_type) {
	case IPSP_CRED_KEYNOTE:
		sadb_cred->sadb_x_cred_type = SADB_X_CREDTYPE_KEYNOTE;
		break;
	case IPSP_CRED_X509:
		sadb_cred->sadb_x_cred_type = SADB_X_CREDTYPE_X509;
		break;
	}
	*p += sizeof(struct sadb_x_cred);
	bcopy((*ipr) + 1, *p, (*ipr)->ref_len);
	*p += PADUP((*ipr)->ref_len);
}
Exemple #4
0
void
export_auth(void **p, struct tdb *tdb, int dstauth)
{
	struct ipsec_ref **ipr;
	struct sadb_x_cred *sadb_auth = (struct sadb_x_cred *) *p;

	if (dstauth == PFKEYV2_AUTH_REMOTE)
		ipr = &tdb->tdb_remote_auth;
	else
		ipr = &tdb->tdb_local_auth;

	sadb_auth->sadb_x_cred_len = (sizeof(struct sadb_x_cred) +
	    PADUP((*ipr)->ref_len)) / sizeof(uint64_t);

	switch ((*ipr)->ref_type) {
	case IPSP_AUTH_PASSPHRASE:
		sadb_auth->sadb_x_cred_type = SADB_X_AUTHTYPE_PASSPHRASE;
		break;
	case IPSP_AUTH_RSA:
		sadb_auth->sadb_x_cred_type = SADB_X_AUTHTYPE_RSA;
		break;
	}
	*p += sizeof(struct sadb_x_cred);
	bcopy((*ipr) + 1, *p, (*ipr)->ref_len);
	*p += PADUP((*ipr)->ref_len);
}
void *BLI_memarena_alloc(MemArena *ma, size_t size)
{
	void *ptr;

	/* ensure proper alignment by rounding
	 * size up to multiple of 8 */
	size = PADUP(size, ma->align);

	if (UNLIKELY(size > ma->cursize)) {
		if (size > ma->bufsize - (ma->align - 1)) {
			ma->cursize = PADUP(size + 1, ma->align);
		}
		else {
			ma->cursize = ma->bufsize;
		}

		ma->curbuf = (ma->use_calloc ? MEM_callocN : MEM_mallocN)(ma->cursize, ma->name);
		BLI_linklist_prepend(&ma->bufs, ma->curbuf);
		memarena_curbuf_align(ma);
	}

	ptr = ma->curbuf;
	ma->curbuf += size;
	ma->cursize -= size;

#ifdef WITH_MEM_VALGRIND
	VALGRIND_MEMPOOL_ALLOC(ma, ptr, size);
#endif

	return ptr;
}
Exemple #6
0
void *BLI_memarena_alloc(MemArena *ma, int size) {
	void *ptr;

		/* ensure proper alignment by rounding
		 * size up to multiple of 8 */	
	size= PADUP(size, ma->align);
	
	if (size>ma->cursize) {
		unsigned char *tmp;
		
		if(size > ma->bufsize - (ma->align - 1))
		{
			ma->cursize = PADUP(size+1, ma->align);
		}
		else ma->cursize = ma->bufsize;

		if(ma->use_calloc)
			ma->curbuf= MEM_callocN(ma->cursize, ma->name);
		else
			ma->curbuf= MEM_mallocN(ma->cursize, ma->name);
		
		BLI_linklist_prepend(&ma->bufs, ma->curbuf);

		/* align alloc'ed memory (needed if align > 8) */
		tmp = (unsigned char*)PADUP( (intptr_t) ma->curbuf, ma->align);
		ma->cursize -= (tmp - ma->curbuf);
		ma->curbuf = tmp;		
	}
	
	ptr= ma->curbuf;
	ma->curbuf+= size;
	ma->cursize-= size;
	
	return ptr;
}
Exemple #7
0
/* Export PF tag information for SA */
void
export_tag(void **p, struct tdb *tdb)
{
	struct sadb_x_tag *stag = (struct sadb_x_tag *)*p;
	char *s = (char *)(stag + 1);

	pf_tag2tagname(tdb->tdb_tag, s);
	stag->sadb_x_tag_taglen = strlen(s) + 1;
	stag->sadb_x_tag_len = (sizeof(struct sadb_x_tag) +
	    PADUP(stag->sadb_x_tag_taglen)) / sizeof(uint64_t);
	*p += PADUP(stag->sadb_x_tag_taglen) + sizeof(struct sadb_x_tag);
}
Exemple #8
0
/*
 * Export a struct sockaddr as an SADB_ADDRESS payload.
 */
void
export_address(void **p, struct sockaddr *sa)
{
	struct sadb_address *sadb_address = (struct sadb_address *) *p;

	sadb_address->sadb_address_len = (sizeof(struct sadb_address) +
	    PADUP(SA_LEN(sa))) / sizeof(uint64_t);

	*p += sizeof(struct sadb_address);
	bcopy(sa, *p, SA_LEN(sa));
	((struct sockaddr *) *p)->sa_family = sa->sa_family;
	*p += PADUP(SA_LEN(sa));
}
/* align alloc'ed memory (needed if align > 8) */
static void memarena_curbuf_align(MemArena *ma)
{
	unsigned char *tmp;

	tmp = (unsigned char *)PADUP((intptr_t)ma->curbuf, (int)ma->align);
	ma->cursize -= (size_t)(tmp - ma->curbuf);
	ma->curbuf = tmp;
}
Exemple #10
0
/*
 * Helper to export addresses from an struct sockaddr_encap.
 */
static void
export_encap(void **p, struct sockaddr_encap *encap, int type)
{
	struct sadb_address *saddr = (struct sadb_address *)*p;
	union sockaddr_union *sunion;

	*p += sizeof(struct sadb_address);
	sunion = (union sockaddr_union *)*p;

	switch (encap->sen_type) {
	case SENT_IP4:
		saddr->sadb_address_len = (sizeof(struct sadb_address) +
		    PADUP(sizeof(struct sockaddr_in))) / sizeof(uint64_t);
		sunion->sa.sa_len = sizeof(struct sockaddr_in);
		sunion->sa.sa_family = AF_INET;
		if (type == SADB_X_EXT_SRC_FLOW ||
		    type == SADB_X_EXT_SRC_MASK) {
			sunion->sin.sin_addr = encap->sen_ip_src;
			sunion->sin.sin_port = encap->sen_sport;
		} else {
			sunion->sin.sin_addr = encap->sen_ip_dst;
			sunion->sin.sin_port = encap->sen_dport;
		}
		*p += PADUP(sizeof(struct sockaddr_in));
		break;
        case SENT_IP6:
		saddr->sadb_address_len = (sizeof(struct sadb_address)
		    + PADUP(sizeof(struct sockaddr_in6))) / sizeof(uint64_t);
		sunion->sa.sa_len = sizeof(struct sockaddr_in6);
		sunion->sa.sa_family = AF_INET6;
		if (type == SADB_X_EXT_SRC_FLOW ||
		    type == SADB_X_EXT_SRC_MASK) {
			sunion->sin6.sin6_addr = encap->sen_ip6_src;
			sunion->sin6.sin6_port = encap->sen_ip6_sport;
		} else {
			sunion->sin6.sin6_addr = encap->sen_ip6_dst;
			sunion->sin6.sin6_port = encap->sen_ip6_dport;
		}
		*p += PADUP(sizeof(struct sockaddr_in6));
		break;
	}
}
Exemple #11
0
static int check_and_decode_jpeg(unsigned char *inbuf, unsigned char *outbuf, int width, int height, int bufsize) {
		/* JPEG's are always multiples of 16, extra is cropped out AVI's */	
	if ((width&0xF) || (height&0xF)) {
		int i, rrowstride, jrowstride;
		int jwidth= PADUP(width, 16);
		int jheight= PADUP(height, 16);
		unsigned char *tmpbuf= MEM_mallocN(jwidth*jheight*3, "avi.check_and_decode_jpeg");
		int ret= Decode_JPEG(inbuf, tmpbuf, jwidth, jheight, bufsize);
		
			/* crop the tmpbuf into the real buffer */
		rrowstride= width*3;
		jrowstride= jwidth*3;
		for (i=0; i<height; i++)
			memcpy(&outbuf[i*rrowstride], &tmpbuf[i*jrowstride], rrowstride);
		MEM_freeN(tmpbuf);
		
		return ret;
	} else {
		return Decode_JPEG(inbuf, outbuf, width, height, bufsize);
	}
}
Exemple #12
0
void
export_key(void **p, struct tdb *tdb, int type)
{
	struct sadb_key *sadb_key = (struct sadb_key *) *p;

	if (type == PFKEYV2_ENCRYPTION_KEY) {
		sadb_key->sadb_key_len = (sizeof(struct sadb_key) +
		    PADUP(tdb->tdb_emxkeylen)) /
		    sizeof(uint64_t);
		sadb_key->sadb_key_bits = tdb->tdb_emxkeylen * 8;
		*p += sizeof(struct sadb_key);
		bcopy(tdb->tdb_emxkey, *p, tdb->tdb_emxkeylen);
		*p += PADUP(tdb->tdb_emxkeylen);
	} else {
		sadb_key->sadb_key_len = (sizeof(struct sadb_key) +
		    PADUP(tdb->tdb_amxkeylen)) /
		    sizeof(uint64_t);
		sadb_key->sadb_key_bits = tdb->tdb_amxkeylen * 8;
		*p += sizeof(struct sadb_key);
		bcopy(tdb->tdb_amxkey, *p, tdb->tdb_amxkeylen);
		*p += PADUP(tdb->tdb_amxkeylen);
	}
}
static void
export_identity(void **p, struct ipsec_id *id)
{
	struct sadb_ident *sadb_ident = (struct sadb_ident *) *p;

	sadb_ident->sadb_ident_len = (sizeof(struct sadb_ident) +
	    PADUP(id->len)) / sizeof(uint64_t);

	switch (id->type) {
	case IPSP_IDENTITY_PREFIX:
		sadb_ident->sadb_ident_type = SADB_IDENTTYPE_PREFIX;
		break;
	case IPSP_IDENTITY_FQDN:
		sadb_ident->sadb_ident_type = SADB_IDENTTYPE_FQDN;
		break;
	case IPSP_IDENTITY_USERFQDN:
		sadb_ident->sadb_ident_type = SADB_IDENTTYPE_USERFQDN;
		break;
	}
	*p += sizeof(struct sadb_ident);
	bcopy(id + 1, *p, id->len);
	*p += PADUP(id->len);
}
Exemple #14
0
int
pfkeyv2_parsemessage(void *p, int len, void **headers)
{
	struct sadb_ext *sadb_ext;
	int i, left = len;
	uint64_t allow, seen = 1;
	struct sadb_msg *sadb_msg = (struct sadb_msg *) p;

	bzero(headers, (SADB_EXT_MAX + 1) * sizeof(void *));

	if (left < sizeof(struct sadb_msg)) {
		DPRINTF(("pfkeyv2_parsemessage: message too short\n"));
		return (EINVAL);
	}

	headers[0] = p;

	if (sadb_msg->sadb_msg_len * sizeof(uint64_t) != left) {
		DPRINTF(("pfkeyv2_parsemessage: length not a multiple of 64\n"));
		return (EINVAL);
	}

	p += sizeof(struct sadb_msg);
	left -= sizeof(struct sadb_msg);

	if (sadb_msg->sadb_msg_reserved) {
		DPRINTF(("pfkeyv2_parsemessage: message header reserved "
		    "field set\n"));
		return (EINVAL);
	}

	if (sadb_msg->sadb_msg_type > SADB_MAX) {
		DPRINTF(("pfkeyv2_parsemessage: message type > %d\n",
		    SADB_MAX));
		return (EINVAL);
	}

	if (!sadb_msg->sadb_msg_type) {
		DPRINTF(("pfkeyv2_parsemessage: message type unset\n"));
		return (EINVAL);
	}

	if (sadb_msg->sadb_msg_pid != curproc->p_pid) {
		DPRINTF(("pfkeyv2_parsemessage: bad PID value\n"));
		return (EINVAL);
	}

	if (sadb_msg->sadb_msg_errno) {
		if (left) {
			DPRINTF(("pfkeyv2_parsemessage: too-large error message\n"));
			return (EINVAL);
		}
		return (0);
	}

	if (sadb_msg->sadb_msg_type == SADB_X_PROMISC) {
		DPRINTF(("pfkeyv2_parsemessage: message type promiscuous\n"));
		return (0);
	}

	allow = sadb_exts_allowed_in[sadb_msg->sadb_msg_type];

	while (left > 0) {
		sadb_ext = (struct sadb_ext *)p;
		if (left < sizeof(struct sadb_ext)) {
			DPRINTF(("pfkeyv2_parsemessage: extension header too "
			    "short\n"));
			return (EINVAL);
		}

		i = sadb_ext->sadb_ext_len * sizeof(uint64_t);
		if (left < i) {
			DPRINTF(("pfkeyv2_parsemessage: extension header "
			    "exceeds message length\n"));
			return (EINVAL);
		}

		if (sadb_ext->sadb_ext_type > SADB_EXT_MAX) {
			DPRINTF(("pfkeyv2_parsemessage: unknown extension "
			    "header %d\n", sadb_ext->sadb_ext_type));
			return (EINVAL);
		}

		if (!sadb_ext->sadb_ext_type) {
			DPRINTF(("pfkeyv2_parsemessage: unset extension "
			    "header\n"));
			return (EINVAL);
		}

		if (!(allow & (1LL << sadb_ext->sadb_ext_type))) {
			DPRINTF(("pfkeyv2_parsemessage: extension header %d "
			    "not permitted on message type %d\n",
			    sadb_ext->sadb_ext_type, sadb_msg->sadb_msg_type));
			return (EINVAL);
		}

		if (headers[sadb_ext->sadb_ext_type]) {
			DPRINTF(("pfkeyv2_parsemessage: duplicate extension "
			    "header %d\n", sadb_ext->sadb_ext_type));
			return (EINVAL);
		}

		seen |= (1LL << sadb_ext->sadb_ext_type);

		switch (sadb_ext->sadb_ext_type) {
		case SADB_EXT_SA:
		case SADB_X_EXT_SA2:
		{
			struct sadb_sa *sadb_sa = (struct sadb_sa *)p;

			if (i != sizeof(struct sadb_sa)) {
				DPRINTF(("pfkeyv2_parsemessage: bad header "
				    "length for SA extension header %d\n",
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (sadb_sa->sadb_sa_state > SADB_SASTATE_MAX) {
				DPRINTF(("pfkeyv2_parsemessage: unknown SA "
				    "state %d in SA extension header %d\n",
				    sadb_sa->sadb_sa_state,
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (sadb_sa->sadb_sa_state == SADB_SASTATE_DEAD) {
				DPRINTF(("pfkeyv2_parsemessage: cannot set SA "
				    "state to dead, SA extension header %d\n",
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (sadb_sa->sadb_sa_encrypt > SADB_EALG_MAX) {
				DPRINTF(("pfkeyv2_parsemessage: unknown "
				    "encryption algorithm %d in SA extension "
				    "header %d\n", sadb_sa->sadb_sa_encrypt,
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (sadb_sa->sadb_sa_auth > SADB_AALG_MAX) {
				DPRINTF(("pfkeyv2_parsemessage: unknown "
				    "authentication algorithm %d in SA "
				    "extension header %d\n",
				    sadb_sa->sadb_sa_auth,
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (sadb_sa->sadb_sa_replay > 32) {
				DPRINTF(("pfkeyv2_parsemessage: unsupported "
				    "replay window size %d in SA extension "
				    "header %d\n", sadb_sa->sadb_sa_replay,
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}
		}
		break;
		case SADB_X_EXT_PROTOCOL:
		case SADB_X_EXT_FLOW_TYPE:
			if (i != sizeof(struct sadb_protocol)) {
				DPRINTF(("pfkeyv2_parsemessage: bad "
				    "PROTOCOL/FLOW header length in extension "
				    "header %d\n", sadb_ext->sadb_ext_type));
				return (EINVAL);
			}
			break;
		case SADB_X_EXT_POLICY:
			if (i != sizeof(struct sadb_x_policy)) {
				DPRINTF(("pfkeyv2_parsemessage: bad POLICY "
				    "header length\n"));
				return (EINVAL);
			}
			break;
		case SADB_EXT_LIFETIME_CURRENT:
		case SADB_EXT_LIFETIME_HARD:
		case SADB_EXT_LIFETIME_SOFT:
		case SADB_X_EXT_LIFETIME_LASTUSE:
			if (i != sizeof(struct sadb_lifetime)) {
				DPRINTF(("pfkeyv2_parsemessage: bad header "
				    "length for LIFETIME extension header "
				    "%d\n", sadb_ext->sadb_ext_type));
				return (EINVAL);
			}
			break;
		case SADB_EXT_ADDRESS_SRC:
		case SADB_EXT_ADDRESS_DST:
		case SADB_X_EXT_SRC_MASK:
		case SADB_X_EXT_DST_MASK:
		case SADB_X_EXT_SRC_FLOW:
		case SADB_X_EXT_DST_FLOW:
		case SADB_X_EXT_DST2:
		case SADB_EXT_ADDRESS_PROXY:
		{
			struct sadb_address *sadb_address =
			    (struct sadb_address *)p;
			struct sockaddr *sa = (struct sockaddr *)(p +
			    sizeof(struct sadb_address));

			if (i < sizeof(struct sadb_address) +
			    sizeof(struct sockaddr)) {
				DPRINTF(("pfkeyv2_parsemessage: bad ADDRESS "
				    "extension header %d length\n",
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (sadb_address->sadb_address_reserved) {
				DPRINTF(("pfkeyv2_parsemessage: ADDRESS "
				    "extension header %d reserved field set\n",
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}
			if (sa->sa_len &&
			    (i != sizeof(struct sadb_address) +
			    PADUP(sa->sa_len))) {
				DPRINTF(("pfkeyv2_parsemessage: bad sockaddr "
				    "length field in ADDRESS extension "
				    "header %d\n", sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			switch (sa->sa_family) {
			case AF_INET:
				if (sizeof(struct sadb_address) +
				    PADUP(sizeof(struct sockaddr_in)) != i) {
					DPRINTF(("pfkeyv2_parsemessage: "
					    "invalid ADDRESS extension header "
					    "%d length\n",
					    sadb_ext->sadb_ext_type));
					return (EINVAL);
				}

				if (sa->sa_len != sizeof(struct sockaddr_in)) {
					DPRINTF(("pfkeyv2_parsemessage: bad "
					    "sockaddr_in length in ADDRESS "
					    "extension header %d\n",
					    sadb_ext->sadb_ext_type));
					return (EINVAL);
				}

				/* Only check the right pieces */
				switch (sadb_ext->sadb_ext_type)
				{
				case SADB_X_EXT_SRC_MASK:
				case SADB_X_EXT_DST_MASK:
				case SADB_X_EXT_SRC_FLOW:
				case SADB_X_EXT_DST_FLOW:
					break;

				default:
					if (((struct sockaddr_in *)sa)->sin_port) {
						DPRINTF(("pfkeyv2_parsemessage"
						    ": port field set in "
						    "sockaddr_in of ADDRESS "
						    "extension header %d\n",
						    sadb_ext->sadb_ext_type));
						return (EINVAL);
					}
					break;
				}

				{
					char zero[sizeof(((struct sockaddr_in *)sa)->sin_zero)];
					bzero(zero, sizeof(zero));

					if (bcmp(&((struct sockaddr_in *)sa)->sin_zero, zero, sizeof(zero))) {
						DPRINTF(("pfkeyv2_parsemessage"
						    ": reserved sockaddr_in "
						    "field non-zero'ed in "
						    "ADDRESS extension header "
						    "%d\n",
						    sadb_ext->sadb_ext_type));
						return (EINVAL);
					}
				}
				break;
#if INET6
			case AF_INET6:
				if (i != sizeof(struct sadb_address) +
				    PADUP(sizeof(struct sockaddr_in6))) {
					DPRINTF(("pfkeyv2_parsemessage: "
					    "invalid sockaddr_in6 length in "
					    "ADDRESS extension header %d\n",
					    sadb_ext->sadb_ext_type));
					return (EINVAL);
				}

				if (sa->sa_len !=
				    sizeof(struct sockaddr_in6)) {
					DPRINTF(("pfkeyv2_parsemessage: bad "
					    "sockaddr_in6 length in ADDRESS "
					    "extension header %d\n",
					    sadb_ext->sadb_ext_type));
					return (EINVAL);
				}

				if (((struct sockaddr_in6 *)sa)->sin6_flowinfo) {
					DPRINTF(("pfkeyv2_parsemessage: "
					    "flowinfo field set in "
					    "sockaddr_in6 of ADDRESS "
					    "extension header %d\n",
					    sadb_ext->sadb_ext_type));
					return (EINVAL);
				}

				/* Only check the right pieces */
				switch (sadb_ext->sadb_ext_type)
				{
				case SADB_X_EXT_SRC_MASK:
				case SADB_X_EXT_DST_MASK:
				case SADB_X_EXT_SRC_FLOW:
				case SADB_X_EXT_DST_FLOW:
					break;

				default:
					if (((struct sockaddr_in6 *)sa)->sin6_port) {
						DPRINTF(("pfkeyv2_parsemessage"
						    ": port field set in "
						    "sockaddr_in6 of ADDRESS "
						    "extension header %d\n",
						    sadb_ext->sadb_ext_type));
						return (EINVAL);
					}
					break;
				}
				break;
#endif /* INET6 */
			default:
				if (sadb_msg->sadb_msg_satype ==
				    SADB_X_SATYPE_TCPSIGNATURE &&
				    sa->sa_family == 0)
					break;
				DPRINTF(("pfkeyv2_parsemessage: unknown "
				    "address family %d in ADDRESS extension "
				    "header %d\n",
				    sa->sa_family, sadb_ext->sadb_ext_type));
				return (EINVAL);
			}
		}
		break;
		case SADB_EXT_KEY_AUTH:
		case SADB_EXT_KEY_ENCRYPT:
		{
			struct sadb_key *sadb_key = (struct sadb_key *)p;

			if (i < sizeof(struct sadb_key)) {
				DPRINTF(("pfkeyv2_parsemessage: bad header "
				    "length in KEY extension header %d\n",
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (!sadb_key->sadb_key_bits) {
				DPRINTF(("pfkeyv2_parsemessage: key length "
				    "unset in KEY extension header %d\n",
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (((sadb_key->sadb_key_bits + 63) / 64) * sizeof(uint64_t) != i - sizeof(struct sadb_key)) {
				DPRINTF(("pfkeyv2_parsemessage: invalid key "
				    "length in KEY extension header %d\n",
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (sadb_key->sadb_key_reserved) {
				DPRINTF(("pfkeyv2_parsemessage: reserved field"
				    " set in KEY extension header %d\n",
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}
		}
		break;
		case SADB_X_EXT_LOCAL_AUTH:
		case SADB_X_EXT_REMOTE_AUTH:
		{
			struct sadb_x_cred *sadb_cred =
			    (struct sadb_x_cred *)p;

			if (i < sizeof(struct sadb_x_cred)) {
				DPRINTF(("pfkeyv2_parsemessage: bad header "
				    "length for AUTH extension header %d\n",
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (sadb_cred->sadb_x_cred_type > SADB_X_AUTHTYPE_MAX) {
				DPRINTF(("pfkeyv2_parsemessage: unknown auth "
				    "type %d in AUTH extension header %d\n",
				    sadb_cred->sadb_x_cred_type,
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (sadb_cred->sadb_x_cred_reserved) {
				DPRINTF(("pfkeyv2_parsemessage: reserved field"
				    " set in AUTH extension header %d\n",
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}
		}
		break;
		case SADB_X_EXT_LOCAL_CREDENTIALS:
		case SADB_X_EXT_REMOTE_CREDENTIALS:
		{
			struct sadb_x_cred *sadb_cred =
			    (struct sadb_x_cred *)p;

			if (i < sizeof(struct sadb_x_cred)) {
				DPRINTF(("pfkeyv2_parsemessage: bad header "
				    "length of CREDENTIALS extension header "
				    "%d\n", sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (sadb_cred->sadb_x_cred_type > SADB_X_CREDTYPE_MAX) {
				DPRINTF(("pfkeyv2_parsemessage: unknown "
				    "credential type %d in CREDENTIALS "
				    "extension header %d\n",
				    sadb_cred->sadb_x_cred_type,
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (sadb_cred->sadb_x_cred_reserved) {
				DPRINTF(("pfkeyv2_parsemessage: reserved "
				    "field set in CREDENTIALS extension "
				    "header %d\n", sadb_ext->sadb_ext_type));
				return (EINVAL);
			}
		}
		break;
		case SADB_EXT_IDENTITY_SRC:
		case SADB_EXT_IDENTITY_DST:
		{
			struct sadb_ident *sadb_ident = (struct sadb_ident *)p;

			if (i < sizeof(struct sadb_ident)) {
				DPRINTF(("pfkeyv2_parsemessage: bad header "
				    "length of IDENTITY extension header %d\n",
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (sadb_ident->sadb_ident_type > SADB_IDENTTYPE_MAX) {
				DPRINTF(("pfkeyv2_parsemessage: unknown "
				    "identity type %d in IDENTITY extension "
				    "header %d\n",
				    sadb_ident->sadb_ident_type,
				    sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (sadb_ident->sadb_ident_reserved) {
				DPRINTF(("pfkeyv2_parsemessage: reserved "
				    "field set in IDENTITY extension header "
				    "%d\n", sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (i > sizeof(struct sadb_ident)) {
				char *c =
				    (char *)(p + sizeof(struct sadb_ident));
				int j;

				if (*(char *)(p + i - 1)) {
					DPRINTF(("pfkeyv2_parsemessage: non "
					    "NUL-terminated identity in "
					    "IDENTITY extension header %d\n",
					    sadb_ext->sadb_ext_type));
					return (EINVAL);
				}

				j = PADUP(strlen(c) + 1) +
				    sizeof(struct sadb_ident);

				if (i != j) {
					DPRINTF(("pfkeyv2_parsemessage: actual"
					    " identity length does not match "
					    "expected length in identity "
					    "extension header %d\n",
					    sadb_ext->sadb_ext_type));
					return (EINVAL);
				}
			}
		}
		break;
		case SADB_EXT_SENSITIVITY:
		{
			struct sadb_sens *sadb_sens = (struct sadb_sens *)p;

			if (i < sizeof(struct sadb_sens)) {
				DPRINTF(("pfkeyv2_parsemessage: bad header "
				    "length for SENSITIVITY extension "
				    "header\n"));
				return (EINVAL);
			}

			if (i != (sadb_sens->sadb_sens_sens_len +
			    sadb_sens->sadb_sens_integ_len) *
			    sizeof(uint64_t) +
			    sizeof(struct sadb_sens)) {
				DPRINTF(("pfkeyv2_parsemessage: bad payload "
				    "length for SENSITIVITY extension "
				    "header\n"));
				return (EINVAL);
			}
		}
		break;
		case SADB_EXT_PROPOSAL:
		{
			struct sadb_prop *sadb_prop = (struct sadb_prop *)p;

			if (i < sizeof(struct sadb_prop)) {
				DPRINTF(("pfkeyv2_parsemessage: bad PROPOSAL "
				    "header length\n"));
				return (EINVAL);
			}

			if (sadb_prop->sadb_prop_reserved) {
				DPRINTF(("pfkeyv2_parsemessage: reserved field"
				    "set in PROPOSAL extension header\n"));
				return (EINVAL);
			}

			if ((i - sizeof(struct sadb_prop)) %
			    sizeof(struct sadb_comb)) {
				DPRINTF(("pfkeyv2_parsemessage: bad proposal "
				    "length\n"));
				return (EINVAL);
			}

			{
				struct sadb_comb *sadb_comb =
				    (struct sadb_comb *)(p +
					sizeof(struct sadb_prop));
				int j;

				for (j = 0;
				    j < (i - sizeof(struct sadb_prop))/
				    sizeof(struct sadb_comb);
				    j++) {
					if (sadb_comb->sadb_comb_auth >
					    SADB_AALG_MAX) {
						DPRINTF(("pfkeyv2_parsemessage"
						    ": unknown authentication "
						    "algorithm %d in "
						    "PROPOSAL\n",
						    sadb_comb->sadb_comb_auth));
						return (EINVAL);
					}

					if (sadb_comb->sadb_comb_encrypt >
					    SADB_EALG_MAX) {
						DPRINTF(("pfkeyv2_parsemessage"
						    ": unknown encryption "
						    "algorithm %d in "
						    "PROPOSAL\n",
						    sadb_comb->sadb_comb_encrypt));
						return (EINVAL);
					}

					if (sadb_comb->sadb_comb_reserved) {
						DPRINTF(("pfkeyv2_parsemessage"
						    ": reserved field set in "
						    "COMB header\n"));
						return (EINVAL);
					}
				}
			}
		}
		break;
		case SADB_EXT_SUPPORTED_AUTH:
		case SADB_EXT_SUPPORTED_ENCRYPT:
		case SADB_X_EXT_SUPPORTED_COMP:
		{
			struct sadb_supported *sadb_supported =
			    (struct sadb_supported *)p;
			int j;

			if (i < sizeof(struct sadb_supported)) {
				DPRINTF(("pfkeyv2_parsemessage: bad header "
				    "length for SUPPORTED extension header "
				    "%d\n", sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			if (sadb_supported->sadb_supported_reserved) {
				DPRINTF(("pfkeyv2_parsemessage: reserved "
				    "field set in SUPPORTED extension "
				    "header %d\n", sadb_ext->sadb_ext_type));
				return (EINVAL);
			}

			{
				struct sadb_alg *sadb_alg =
				    (struct sadb_alg *)(p +
					sizeof(struct sadb_supported));
				int max_alg;

				max_alg = sadb_ext->sadb_ext_type ==
				    SADB_EXT_SUPPORTED_AUTH ?
				    SADB_AALG_MAX : SADB_EXT_SUPPORTED_ENCRYPT ?
				    SADB_EALG_MAX : SADB_X_CALG_MAX;

				for (j = 0;
				    j < sadb_supported->sadb_supported_len - 1;
				    j++) {
					if (sadb_alg->sadb_alg_id > max_alg) {
						DPRINTF(("pfkeyv2_parsemessage"
						    ": unknown algorithm %d "
						    "in SUPPORTED extension "
						    "header %d\n",
						    sadb_alg->sadb_alg_id,
						    sadb_ext->sadb_ext_type));
						return (EINVAL);
					}

					if (sadb_alg->sadb_alg_reserved) {
						DPRINTF(("pfkeyv2_parsemessage"
						    ": reserved field set in "
						    "supported algorithms "
						    "header inside SUPPORTED "
						    "extension header %d\n",
						    sadb_ext->sadb_ext_type));
						return (EINVAL);
					}

					sadb_alg++;
				}
			}
		}
		break;
		case SADB_EXT_SPIRANGE:
		{
			struct sadb_spirange *sadb_spirange =
			    (struct sadb_spirange *)p;

			if (i != sizeof(struct sadb_spirange)) {
				DPRINTF(("pfkeyv2_parsemessage: bad header "
				    "length of SPIRANGE extension header\n"));
				return (EINVAL);
			}

			if (sadb_spirange->sadb_spirange_min >
			    sadb_spirange->sadb_spirange_max) {
				DPRINTF(("pfkeyv2_parsemessage: bad SPI "
				    "range\n"));
				return (EINVAL);
			}
		}
		break;
		case SADB_X_EXT_UDPENCAP:
			if (i != sizeof(struct sadb_x_udpencap)) {
				DPRINTF(("pfkeyv2_parsemessage: bad UDPENCAP "
				    "header length\n"));
				return (EINVAL);
			}
			break;
#if NPF > 0
		case SADB_X_EXT_TAG:
			if (i < sizeof(struct sadb_x_tag)) {
				DPRINTF(("pfkeyv2_parsemessage: "
				    "TAG extension header too small"));
				return (EINVAL);
			}
			if (i > (sizeof(struct sadb_x_tag) +
			    PF_TAG_NAME_SIZE)) {
				DPRINTF(("pfkeyv2_parsemessage: "
				    "TAG extension header too long"));
				return (EINVAL);
			}
			break;
#endif
		default:
			DPRINTF(("pfkeyv2_parsemessage: unknown extension "
			    "header type %d\n",
			    sadb_ext->sadb_ext_type));
			return (EINVAL);
		}

		headers[sadb_ext->sadb_ext_type] = p;
		p += i;
		left -= i;
	}

	if (left) {
		DPRINTF(("pfkeyv2_parsemessage: message too long\n"));
		return (EINVAL);
	}

	{
		uint64_t required;

		required = sadb_exts_required_in[sadb_msg->sadb_msg_type];

		if ((seen & required) != required) {
			DPRINTF(("pfkeyv2_parsemessage: required fields "
			    "missing\n"));
			return (EINVAL);
		}
	}

	switch (((struct sadb_msg *)headers[0])->sadb_msg_type) {
	case SADB_UPDATE:
		if (((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_state !=
		    SADB_SASTATE_MATURE) {
			DPRINTF(("pfkeyv2_parsemessage: updating non-mature "
			    "SA prohibited\n"));
			return (EINVAL);
		}
		break;
	case SADB_ADD:
		if (((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_state !=
		    SADB_SASTATE_MATURE) {
			DPRINTF(("pfkeyv2_parsemessage: adding non-mature "
			    "SA prohibited\n"));
			return (EINVAL);
		}
		break;
	}

	return (0);
}