#include "pfkeylib.h"

int pfkey_send_getspi(int socket, struct query_handle *query, uint32_t spimin, uint32_t spimax)
{
	int i;
	int error;
	struct sadb_msg msg_hdr;
	struct sadb_msg* request;

	struct sadb_ext* ext_msgs[SADB_EXT_MAX+1];
	struct	sockaddr* address_src =	(struct sockaddr *)&(query->address_s);	 
	struct	sockaddr* address_dst =	(struct sockaddr *)&(query->address_d);	 


	*ext_msgs = (struct sadb_ext*)&msg_hdr;
	pfkey_msg_build(&request, ext_msgs, 0);


	if(!(address_src&&address_dst)){
		fprintf(stderr, "pfkey_send_getspi: address_src or address_dst is null\n");
		error = -EINVAL;
		goto err;
	}

	memset(&msg_hdr, 0, sizeof(msg_hdr));

	for(i=0; i<=SADB_EXT_MAX; i++ )
		ext_msgs[i] = NULL;

	msg_hdr.sadb_msg_version = PF_KEY_V2;
	msg_hdr.sadb_msg_type = SADB_GETSPI;
	msg_hdr.sadb_msg_errno = 0;
	msg_hdr.sadb_msg_satype = query->satype;
	msg_hdr.sadb_msg_len = DIVUP(sizeof(msg_hdr), IPSEC_PFKEYv2_ALIGN);
	msg_hdr.sadb_msg_seq = query->seq;
	msg_hdr.sadb_msg_pid = getpid();


	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC],
					SADB_EXT_ADDRESS_SRC,
					query->protocol,
					query->prefixlen_s,
					address_src);
	if(error){
		fprintf(stderr, "pfkey_send_getspi: pfkey_address_build(src) failed with return %d\n", error);
		goto err;
	}

	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST],
					SADB_EXT_ADDRESS_DST,
					query->protocol,
					query->prefixlen_d,
					address_dst);
	if(error||!ext_msgs[SADB_EXT_ADDRESS_DST]){
		fprintf(stderr, "pfkey_send_getspi: pfkey_address_build(dst) failed with return %d\n", error);
		goto err;
	}

	error = pfkey_spirange_build(&ext_msgs[SADB_EXT_SPIRANGE],
					SADB_EXT_SPIRANGE,
					spimin,
					spimax);

	if(error||!ext_msgs[SADB_EXT_SPIRANGE]){
		fprintf(stderr, "pfkey_send_getspi: pfkey_spirange_build failed with return %d\n", error);
		goto err;
	}

	*ext_msgs = (struct sadb_ext*)&msg_hdr;
	pfkey_msg_build(&request, ext_msgs, 0);

	errno = 0;
	error = write(socket, (char*) request, request->sadb_msg_len * IPSEC_PFKEYv2_ALIGN /* 64bit allignment */);
	if(error<0){
		fprintf(stderr, "send error with %s\n", strerror(errno));
	}
err:

	if(request){
		free(request);
	}

	for(i=1; i<=SADB_EXT_MAX; i++){
		if(ext_msgs[i]){
			free(ext_msgs[i]);
		}
	}

	return error;

}

int pfkey_send_update(int socket, struct query_handle *query, uint8_t state)
{
	int i;
	int error;
	struct sadb_msg msg_hdr;
	struct sadb_msg* request;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
	struct sockaddr *address_dst = (struct sockaddr *)&(query->address_d);
	struct sockaddr *address_src = (struct sockaddr *)&(query->address_s);

	if(!(address_src&&address_dst)){
		fprintf(stderr, "pfkey_send_update: address_src or address_dst is null\n");
		error = -EINVAL;
		goto err;
	}

	if(!(query->key_a)&& !(query->key_e)){
		fprintf(stderr, "pfkey_send_update: There is not any key information\n");
		error = -EINVAL;
		goto err;
	}

	memset(&msg_hdr, 0, sizeof(msg_hdr));

	for(i=0; i<=SADB_EXT_MAX; i++ )
		ext_msgs[i] = NULL;

	msg_hdr.sadb_msg_version = PF_KEY_V2;
	msg_hdr.sadb_msg_type = SADB_UPDATE;
	msg_hdr.sadb_msg_errno = 0;
	msg_hdr.sadb_msg_satype = query->satype;
	msg_hdr.sadb_msg_len = DIVUP(sizeof(msg_hdr), IPSEC_PFKEYv2_ALIGN);
	msg_hdr.sadb_msg_seq = query->seq;
	msg_hdr.sadb_msg_pid = getpid();

	error = pfkey_sa_build(&ext_msgs[SADB_EXT_SA],
				SADB_EXT_SA,
				htonl(query->spi), /* in network order */
				query->replay,
				state,
				query->aalg,
				query->ealg,
				query->flags);
	if(error){
		fprintf(stderr, "pfkey_send_update: pfkey_sa_build failed with return %d\n", error);
		goto err;
	}


	error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_HARD],
					SADB_EXT_LIFETIME_HARD,
					query->lifetime_h.allocation,
					query->lifetime_h.byte,
					query->lifetime_h.add,
				query->lifetime_h.use);
	if(error){
		fprintf(stderr, "pfkey_send_update: pfkey_lifetime_build(hard) failed with return %d\n", error);
		goto err;
	}
	
	error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_SOFT],
					SADB_EXT_LIFETIME_SOFT,
					query->lifetime_s.allocation,
					query->lifetime_s.byte,
					query->lifetime_s.add,
					query->lifetime_s.use);
	if(error){
		fprintf(stderr, "pfkey_send_update: pfkey_lifetime_build(soft) failed with return %d\n", error);
		goto err;
	}

	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC],
					SADB_EXT_ADDRESS_SRC,
					query->protocol,
					query->prefixlen_s,
					address_src);
	if(error){
		fprintf(stderr, "pfkey_send_update: pfkey_address_build(src) failed with return %d\n", error);
		goto err;
	}

	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST],
					SADB_EXT_ADDRESS_DST,
					query->protocol,
					query->prefixlen_d,
					address_dst);
	if(error||!ext_msgs[SADB_EXT_ADDRESS_DST]){
		fprintf(stderr, "pfkey_send_update: pfkey_address_build(dst) failed with return %d\n", error);
		goto err;
	}

	switch(query->aalg){
		case SADB_AALG_MD5HMAC:
		case SADB_AALG_SHA1HMAC:

			if(query->key_a){
				error = pfkey_key_build(&ext_msgs[SADB_EXT_KEY_AUTH],
							SADB_EXT_KEY_AUTH,
							query->key_bits_a,
							query->key_a);
			}else{
				fprintf(stderr, "pfkey_send_update: auth_key is null\n");
			}	
			break;

		default:

	}
	if(error){
		fprintf(stderr, "pfkey_send_update: pfkey_key_build(auth) failed with return %d\n", error);
		goto err;
	}

	switch(query->ealg){
		case SADB_EALG_DESCBC:
		case SADB_EALG_3DESCBC:
		case SADB_EALG_AES:
			if(query->key_e){
				error = pfkey_key_build(&ext_msgs[SADB_EXT_KEY_ENCRYPT],
							SADB_EXT_KEY_ENCRYPT,
							query->key_bits_e,
							query->key_e);
			}else{
				fprintf(stderr, "pfkey_send_update: esp_key is null\n");
			}
			break;

		default:
	}
	if(error){
		fprintf(stderr, "pfkey_send_update: pfkey_address_build(dst) failed with return %d\n", error);
		goto err;
	}

	*ext_msgs = (struct sadb_ext*)&msg_hdr;
	pfkey_msg_build(&request, ext_msgs, 0);

	errno = 0;
	error = write(socket, (char*) request, request->sadb_msg_len * IPSEC_PFKEYv2_ALIGN /* 64bit allignment */);
	if(error<0){
		fprintf(stderr, "pfkey_send_update: send error with %s\n", strerror(errno));
	}
err:

	if(request){
		free(request);
	}

	for(i=1; i<=SADB_EXT_MAX; i++){
		if(ext_msgs[i]){
			free(ext_msgs[i]);
		}
	}

	return error;
}

int pfkey_send_add(int socket, struct query_handle *query, uint8_t state)
{
	int i;
	int error;
	struct sadb_msg msg_hdr;
	struct sadb_msg* request;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
	struct sockaddr *address_src = (struct sockaddr *)&(query->address_s);
	struct sockaddr *address_dst = (struct sockaddr *)&(query->address_d);

	if(!(address_src&&address_dst)){
		fprintf(stderr, "pfkey_send_add: address_src or address_dst is null\n");
		error = -EINVAL;
		goto err;
	}

	if(!(query->key_a) && !(query->key_e)){
		fprintf(stderr, "pfkey_send_add: There is not any key information\n");
		error = -EINVAL;
		goto err;
	}

	memset(&msg_hdr, 0, sizeof(msg_hdr));

	for(i=0; i<=SADB_EXT_MAX; i++ )
		ext_msgs[i] = NULL;

	msg_hdr.sadb_msg_version = PF_KEY_V2;
	msg_hdr.sadb_msg_type = SADB_ADD;
	msg_hdr.sadb_msg_errno = 0;
	msg_hdr.sadb_msg_satype = query->satype;
	msg_hdr.sadb_msg_len = DIVUP(sizeof(msg_hdr), IPSEC_PFKEYv2_ALIGN);
	msg_hdr.sadb_msg_seq = query->seq;
	msg_hdr.sadb_msg_pid = getpid();

	switch (msg_hdr.sadb_msg_satype) {
	case SADB_SATYPE_AH:
	case SADB_SATYPE_ESP:
		error = pfkey_sa_build(&ext_msgs[SADB_EXT_SA],
					SADB_EXT_SA,
					htonl(query->spi), /* in network order */
					query->replay,
					state,
					query->aalg,
					query->ealg,
					query->flags);
		break;
	case SADB_X_SATYPE_COMP:
		error = pfkey_sa_build(&ext_msgs[SADB_EXT_SA],
					SADB_EXT_SA,
					htonl(query->spi), /* in network order */
					query->replay,
					state,
					query->aalg,
					query->ealg,
					query->flags);
		break;
	default:
		error = -EINVAL;
	}

	if(error){
		fprintf(stderr, "pfkey_send_add: pfkey_sa_build failed with return %d\n", error);
		goto err;
	}


	error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_HARD],
					SADB_EXT_LIFETIME_HARD,
					query->lifetime_h.allocation,
					query->lifetime_h.byte,
					query->lifetime_h.add,
					query->lifetime_h.use);
	if(error){
		fprintf(stderr, "pfkey_send_add: pfkey_lifetime_build(hard) failed with return %d\n", error);
		goto err;
	}
	
	error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_SOFT],
					SADB_EXT_LIFETIME_SOFT,
					query->lifetime_s.allocation,
					query->lifetime_s.byte,
					query->lifetime_s.add,
					query->lifetime_s.use);
	if(error){
		fprintf(stderr, "pfkey_send_add: pfkey_lifetime_build(soft) failed with return %d\n", error);
		goto err;
	}

	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC],
					SADB_EXT_ADDRESS_SRC,
					query->protocol,
					query->prefixlen_s,
					address_src);
	if(error){
		fprintf(stderr, "pfkey_send_add: pfkey_address_build(src) failed with return %d\n", error);
		goto err;
	}

	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST],
					SADB_EXT_ADDRESS_DST,
					query->protocol,
					query->prefixlen_d,
					address_dst);
	if(error||!ext_msgs[SADB_EXT_ADDRESS_DST]){
		fprintf(stderr, "pfkey_send_add: pfkey_address_build(dst) failed with return %d\n", error);
		goto err;
	}

	switch(query->aalg){
		case SADB_AALG_MD5HMAC:
		case SADB_AALG_SHA1HMAC:

			if(query->key_a){
				error = pfkey_key_build(&ext_msgs[SADB_EXT_KEY_AUTH],
							SADB_EXT_KEY_AUTH,
							query->key_bits_a,
							query->key_a);
			}else{
				fprintf(stderr, "pfkey_send_add: auth_key is null\n");
			}	
			break;

		default:

	}
	if(error){
		fprintf(stderr, "pfkey_send_add: pfkey_key_build(auth) failed with return %d\n", error);
		goto err;
	}

	switch(query->ealg){
		case SADB_EALG_DESCBC:
		case SADB_EALG_3DESCBC:
		case SADB_EALG_AES:
			if(query->key_e){
				error = pfkey_key_build(&ext_msgs[SADB_EXT_KEY_ENCRYPT],
							SADB_EXT_KEY_ENCRYPT,
							query->key_bits_e,
							query->key_e);
			}else{
				fprintf(stderr, "pfkey_send_add: esp_key is null\n");
			}
			break;
		case SADB_EALG_NULL:
		default:
	}
	if(error){
		fprintf(stderr, "pfkey_send_add: pfkey_address_build(dst) failed with return %d\n", error);
		goto err;
	}

	*ext_msgs = (struct sadb_ext*)&msg_hdr;
	pfkey_msg_build(&request, ext_msgs, 0);

	errno = 0;
	error = write(socket, (char*) request, request->sadb_msg_len * IPSEC_PFKEYv2_ALIGN /* 64bit allignment */);
	if(error<0){
		fprintf(stderr, "send error with %s\n", strerror(errno));
	}

	if(request){
		free(request);
	}

err:
	for(i=1; i<=SADB_EXT_MAX; i++){
		if(ext_msgs[i]){
			free(ext_msgs[i]);
		}
	}

	return error;
}

int pfkey_send_delete(int socket, struct query_handle *query)
{
	int i;
	int error;
	struct sadb_msg msg_hdr;
	struct sadb_msg* request;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
	struct sockaddr *address_src = (struct sockaddr *)&(query->address_s);
	struct sockaddr *address_dst = (struct sockaddr *)&(query->address_d);

	if(!(address_src&&address_dst)){
		fprintf(stderr, "pfkey_send_add: address_src or address_dst is null\n");
		error = -EINVAL;
		goto err;
	}

	memset(&msg_hdr, 0, sizeof(msg_hdr));

	for(i=0; i<=SADB_EXT_MAX; i++ )
		ext_msgs[i] = NULL;

	msg_hdr.sadb_msg_version = PF_KEY_V2;
	msg_hdr.sadb_msg_type = SADB_DELETE;
	msg_hdr.sadb_msg_errno = 0;
	msg_hdr.sadb_msg_satype = query->satype;
	msg_hdr.sadb_msg_len = DIVUP(sizeof(msg_hdr), IPSEC_PFKEYv2_ALIGN);
	msg_hdr.sadb_msg_seq = query->seq;
	msg_hdr.sadb_msg_pid = getpid();

	error = pfkey_sa_build(&ext_msgs[SADB_EXT_SA],
				SADB_EXT_SA,
				htonl(query->spi), /* in network order */
				0,
				0, 
				0,
				0,
				0);

	if(error){
		fprintf(stderr, "pfkey_send_delete: pfkey_sa_build failed with return %d\n", error);
		goto err;
	}


	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC],
					SADB_EXT_ADDRESS_SRC,
					query->protocol,
					query->prefixlen_s,
					address_src);
	if(error){
		fprintf(stderr, "pfkey_send_delete: pfkey_address_build(src) failed with return %d\n", error);
		goto err;
	}


	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST],
					SADB_EXT_ADDRESS_DST,
					query->protocol,
					query->prefixlen_d,
					address_dst);
	if(error){
		fprintf(stderr, "pfkey_send_delete: pfkey_address_build(dst) failed with return %d\n", error);
		goto err;
	}

	*ext_msgs = (struct sadb_ext*)&msg_hdr;
	pfkey_msg_build(&request, ext_msgs, 0);
	if(error){
		fprintf(stderr, "pfkey_send_delete: pfkey_msg_build failed with return %d\n", error );
		goto err;
	}

	errno = 0;
	error = write(socket, (char*) request, request->sadb_msg_len * IPSEC_PFKEYv2_ALIGN /* 64bit allignment */);
	if(error<0){
		fprintf(stderr, "pfkey_send_delete: send error with %s\n", strerror(errno));
	}
err:
	if(request){
		free(request);
	}

	for(i=1; i<=SADB_EXT_MAX; i++){
		if(ext_msgs[i]){
			free(ext_msgs[i]);
		}
	}

	return error;
}

int pfkey_send_get(int socket, struct query_handle *query)
{
	int i;
	int error;
	struct sadb_msg msg_hdr;
	struct sadb_msg* request;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
	struct sockaddr *address_src = (struct sockaddr *)&(query->address_s);
	struct sockaddr *address_dst = (struct sockaddr *)&(query->address_d);

	if(!(address_src&&address_dst)){
		fprintf(stderr, "pfkey_send_get: address_src or address_dst is null\n");
		error = -EINVAL;
		goto err;
	}

	memset(&msg_hdr, 0, sizeof(msg_hdr));

	for(i=0; i<=SADB_EXT_MAX; i++ )
		ext_msgs[i] = NULL;

	msg_hdr.sadb_msg_version = PF_KEY_V2;
	msg_hdr.sadb_msg_type = SADB_GET;
	msg_hdr.sadb_msg_errno = 0;
	msg_hdr.sadb_msg_satype = query->satype;
	msg_hdr.sadb_msg_len = DIVUP(sizeof(msg_hdr), IPSEC_PFKEYv2_ALIGN);
	msg_hdr.sadb_msg_seq = query->seq;
	msg_hdr.sadb_msg_pid = getpid();

	error = pfkey_sa_build(&ext_msgs[SADB_EXT_SA],
		SADB_EXT_SA,
		htonl(query->spi), /* in network order */
		0,
		0, 
		0,
		0,
		0);

	if(error){
		fprintf(stderr, "pfkey_send_get: pfkey_sa_build failed with return %d\n", error);
		goto err;
	}

	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC],
		SADB_EXT_ADDRESS_SRC,
		query->protocol,
		query->prefixlen_s,
		address_src);
	if(error){
		fprintf(stderr, "pfkey_send_get: pfkey_address_build(src) failed with return %d\n", error);
		goto err;
	}

	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST],
		SADB_EXT_ADDRESS_DST,
		query->protocol,
		query->prefixlen_d,
		address_dst);
	if(error){
		fprintf(stderr, "pfkey_send_get: pfkey_address_build(dst) failed with return %d\n", error);
		goto err;
	}

	*ext_msgs = (struct sadb_ext*)&msg_hdr;
	pfkey_msg_build(&request, ext_msgs, 0);
	if(error){
		fprintf(stderr, "pfkey_send_get: pfkey_msg_build failed with return %d\n", error);
		goto err;
	}

	errno = 0;
	error = write(socket, (char*) request, request->sadb_msg_len * IPSEC_PFKEYv2_ALIGN /* 64bit allignment */);
	if(error<0){
		fprintf(stderr, "pfkey_send_get: send error with %s\n", strerror(errno));
	}
err:
	if(request){
		free(request);
	}

	for(i=1; i<=SADB_EXT_MAX; i++){
		if(ext_msgs[i]){
			free(ext_msgs[i]);
		}
	}

	return error;
}

int pfkey_send_flush(int socket, struct query_handle *query)
{

	int error;
	struct sadb_msg msg_hdr;

	memset(&msg_hdr, 0, sizeof(msg_hdr));

	msg_hdr.sadb_msg_version = PF_KEY_V2;
	msg_hdr.sadb_msg_type = SADB_FLUSH;
	msg_hdr.sadb_msg_errno = 0;
	msg_hdr.sadb_msg_satype = query->satype;
	msg_hdr.sadb_msg_len = DIVUP(sizeof(msg_hdr), IPSEC_PFKEYv2_ALIGN);
	msg_hdr.sadb_msg_seq = query->seq;
	msg_hdr.sadb_msg_pid = getpid();

	errno = 0;
	error = write(socket, (char*)&msg_hdr, sizeof(msg_hdr));
	if(error<0){
		fprintf(stderr, "pfkey_send_flush: send error with %s\n", strerror(errno));
	}

	return error;
}

int pfkey_send_flush_sp(int socket, struct query_handle *query)
{

	int error;
	struct sadb_msg msg_hdr;

	memset(&msg_hdr, 0, sizeof(msg_hdr));

	msg_hdr.sadb_msg_version = PF_KEY_V2;
	msg_hdr.sadb_msg_type = SADB_X_FLUSH_SP;
	msg_hdr.sadb_msg_errno = 0;
	msg_hdr.sadb_msg_satype = query->satype;
	msg_hdr.sadb_msg_len = DIVUP(sizeof(msg_hdr), IPSEC_PFKEYv2_ALIGN);
	msg_hdr.sadb_msg_seq = query->seq;
	msg_hdr.sadb_msg_pid = getpid();

	errno = 0;
	error = write(socket, (char*)&msg_hdr, sizeof(msg_hdr));
	if(error<0){
		fprintf(stderr, "pfkey_send_flush: send error with %s\n", strerror(errno));
	}

	return error;
}

int pfkey_send_addflow(int socket, struct query_handle *query)
{
	int i;
	int error;
	struct sadb_msg msg_hdr;
	struct sadb_msg* request;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
	struct sockaddr *address_sas = NULL;
	uint8_t prefixlen_sas = 0;
	struct sockaddr *address_sad = NULL;
	uint8_t prefixlen_sad = 0;
	struct sockaddr *address_src = (struct sockaddr *)&(query->address_s);
	struct sockaddr *address_dst = (struct sockaddr *)&(query->address_d);
	address_sad = (struct sockaddr *)&(query->address_sad);
	prefixlen_sad = query->prefixlen_sad;

	memset(&msg_hdr, 0, sizeof(msg_hdr));

	for(i=0; i<=SADB_EXT_MAX; i++ )
		ext_msgs[i] = NULL;

	msg_hdr.sadb_msg_version = PF_KEY_V2;
	msg_hdr.sadb_msg_type = SADB_X_ADDFLOW;
	msg_hdr.sadb_msg_errno = 0;
	msg_hdr.sadb_msg_satype = query->satype;
	msg_hdr.sadb_msg_len = DIVUP(sizeof(msg_hdr), IPSEC_PFKEYv2_ALIGN);
	msg_hdr.sadb_msg_seq = query->seq;
	msg_hdr.sadb_msg_pid = getpid();

	error = pfkey_sa_build(&ext_msgs[SADB_EXT_SA],
		SADB_EXT_SA,
		htonl(query->spi), /* in network order */
		0,
		0,
		0,
		0,
		query->tunnel? SADB_X_SAFLAGS_TUNNEL: 0);
	if(error){
		fprintf(stderr, "pfkey_send_addflow: pfkey_sa_build failed with return %d\n", error);
		goto err;
	}
#if 0
	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC],
		SADB_EXT_ADDRESS_SRC,
		query->protocol,
		prefixlen_sas,
		address_sas);
	if(error){
		fprintf(stderr, "pfkey_send_addflow: pfkey_address_build(src) failed with return %d\n", error);
		goto err;
	}
#endif
	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST],
		SADB_EXT_ADDRESS_DST,
		query->protocol,
		prefixlen_sad,
		address_sad);
	if(error){
		fprintf(stderr, "pfkey_send_addflow: pfkey_address_build(dst) failed with return %d\n", error);
		goto err;
	}


	error = pfkey_address_build(&ext_msgs[SADB_X_EXT_ADDRESS_SRC_FLOW],
		SADB_X_EXT_ADDRESS_SRC_FLOW,
		query->protocol,
		query->prefixlen_s,
		address_src);
	if(error){
		fprintf(stderr, "pfkey_send_addflow: pfkey_address_build(src) failed with return %d\n", error);
		goto err;
	}

	error = pfkey_address_build(&ext_msgs[SADB_X_EXT_ADDRESS_DST_FLOW],
		SADB_X_EXT_ADDRESS_DST_FLOW,
		query->protocol,
		query->prefixlen_d,
		address_dst);
	if(error){
		fprintf(stderr, "pfkey_send_addflow: pfkey_address_build(dst) failed with return %d\n", error);
		goto err;
	}

	*ext_msgs = (struct sadb_ext*)&msg_hdr;
	error = pfkey_msg_build(&request, ext_msgs, 0);
	if(error){
		fprintf(stderr, "pfkey_send_addflow: pfkey_msg_build failed with return %d\n", error);
		goto err;
	}

	errno = 0;
	error = write(socket, (char*) request, request->sadb_msg_len * IPSEC_PFKEYv2_ALIGN /* 64bit allignment */);
	if(error<0){
		fprintf(stderr, "pfkey_send_addflow: send error with %s\n", strerror(errno));
	}
err:

	if(request){
		free(request);
	}

	for(i=1; i<=SADB_EXT_MAX; i++){
		if(ext_msgs[i]){
			free(ext_msgs[i]);
		}
	}

	return error;
}

int pfkey_send_delflow(int socket, struct query_handle *query)
{
	int i;
	int error;
	struct sadb_msg msg_hdr;
	struct sadb_msg* request;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
	struct sockaddr *address_src = (struct sockaddr *)&(query->address_s);
	struct sockaddr *address_dst = (struct sockaddr *)&(query->address_d);
	

	if(!(address_src&&address_dst)){
		fprintf(stderr, "pfkey_send_delflow: address_src or address_dst is null\n");
		error = -EINVAL;
		goto err;
	}

	memset(&msg_hdr, 0, sizeof(msg_hdr));

	for(i=0; i<=SADB_EXT_MAX; i++ )
		ext_msgs[i] = NULL;

	msg_hdr.sadb_msg_version = PF_KEY_V2;
	msg_hdr.sadb_msg_type = SADB_X_DELFLOW;
	msg_hdr.sadb_msg_errno = 0;
	msg_hdr.sadb_msg_satype = query->satype;
	msg_hdr.sadb_msg_len = DIVUP(sizeof(msg_hdr), IPSEC_PFKEYv2_ALIGN);
	msg_hdr.sadb_msg_seq = query->seq;
	msg_hdr.sadb_msg_pid = getpid();

	error = pfkey_sa_build(&ext_msgs[SADB_EXT_SA],
		SADB_EXT_SA,
		htonl(query->spi), /* in network order */
		0,
		0,
		0,
		0,
		SADB_X_SAFLAGS_CLEARFLOW | (query->tunnel? SADB_X_SAFLAGS_TUNNEL: 0));
	if(error){
		fprintf(stderr, "pfkey_send_delflow: pfkey_sa_build failed with return %d\n", error);
		goto err;
	}

#if 0
	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC],
		SADB_EXT_ADDRESS_SRC,
		query->protocol,
		query->prefixlen_s,
		address_src);
	if(error){
		fprintf(stderr, "pfkey_send_delflow: pfkey_address_build(src) failed with return %d\n", error);
		goto err;
	}

	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST],
		SADB_EXT_ADDRESS_DST,
		query->protocol,
		query->prefixlen_d,
		address_dst);
	if(error||!ext_msgs[SADB_EXT_ADDRESS_DST]){
		fprintf(stderr, "pfkey_send_delflow: pfkey_address_build(dst) failed with return %d\n", error);
		goto err;
	}
#endif

	error = pfkey_address_build(&ext_msgs[SADB_X_EXT_ADDRESS_SRC_FLOW],
		SADB_X_EXT_ADDRESS_SRC_FLOW,
		query->protocol,
		query->prefixlen_s,
		address_src);
	if(error||!ext_msgs[SADB_X_EXT_ADDRESS_SRC_FLOW]){
		fprintf(stderr, "pfkey_send_delflow: pfkey_address_build(src) failed with return %d\n", error);
		goto err;
	}

	error = pfkey_address_build(&ext_msgs[SADB_X_EXT_ADDRESS_DST_FLOW],
		SADB_X_EXT_ADDRESS_DST_FLOW,
		query->protocol,
		query->prefixlen_d,
		address_dst);
	if(error||!ext_msgs[SADB_X_EXT_ADDRESS_DST_FLOW]){
		fprintf(stderr, "pfkey_send_delflow: pfkey_address_build(dst) failed with return %d\n", error);
		goto err;
	}

	*ext_msgs = (struct sadb_ext*)&msg_hdr;
	error = pfkey_msg_build(&request, ext_msgs, 0);
	if(error){
		fprintf(stderr, "pfkey_send_delflow: pfkey_msg_build failed with return %d\n", error );
		goto err;
	}

	errno = 0;
	error = write(socket, (char*) request, request->sadb_msg_len * IPSEC_PFKEYv2_ALIGN /* 64bit allignment */);
	if(error<0){
		fprintf(stderr, "pfkey_send_delflow: send error with %s\n", strerror(errno));
	}
err:

	if(request){
		free(request);
	}

	for(i=1; i<=SADB_EXT_MAX; i++){
		if(ext_msgs[i]){
			free(ext_msgs[i]);
		}
	}

	return error;
}





