int
pfkey_list_insert_socket(struct socket *socketp, struct socket_list **sockets)
{
	struct socket_list *socket_listp;

	PFKEY_DEBUG("called\n");
	if (!socketp) {
		return -EINVAL;
	}

	if (!sockets) {
		return -EINVAL;
	}

	if ((socket_listp = (struct socket_list *)kmalloc(sizeof(struct socket_list), GFP_KERNEL)) == NULL) {
		return -ENOMEM;
	}
	
	socket_listp->socketp = socketp;
	socket_listp->next = *sockets;
	*sockets = socket_listp;
	PFKEY_DEBUG("inserted sock=%p\n", socketp);
	PFKEY_DEBUG("end\n");

	return 0;
}
コード例 #2
0
int sadb_msg_flush_parse(struct sock *sk, struct sadb_msg* msg, struct sadb_msg **reply)
{
	int error = 0;

	if (!msg) {
		PFKEY_DEBUG("msg==null\n");
		error = -EINVAL;
		goto err;
	}

	error = sadb_msg_sanity_check(msg);

	if (error) {
		PFKEY_DEBUG("message is invalid\n");
		goto err;
	}

	switch(msg->sadb_msg_satype) {
	case SADB_SATYPE_AH:
	case SADB_SATYPE_ESP:
		sadb_flush_sa(msg->sadb_msg_satype);
		break;
	default:
		sadb_clear_db(); 
	}

	*reply = kmalloc(sizeof(struct sadb_msg), GFP_KERNEL);
	memcpy(*reply, msg, sizeof(struct sadb_msg));
err:
	return error;
}
static void
pfkey_insert_socket(struct sock *sk)
{
	PFKEY_DEBUG("called\n");
	write_lock_bh(&pfkey_sk_lock);
	sk->next=pfkey_sock_list;
	pfkey_sock_list=sk;
	write_unlock_bh(&pfkey_sk_lock);
	PFKEY_DEBUG("end\n");
}
コード例 #4
0
int sadb_msg_sanity_check(struct sadb_msg* msg)
{
	int error = 0;

	if (!msg) {
		PFKEY_DEBUG("msg==null\n");
		error = -EINVAL;
		goto err;
	}

	error = 
	(msg->sadb_msg_version == PF_KEY_V2) ? 0 :
	(msg->sadb_msg_type > 0 && msg->sadb_msg_type <= SADB_MAX) ? 0 :
	(msg->sadb_msg_satype > 0 &&
		 msg->sadb_msg_satype <= SADB_SATYPE_MAX) ? 0 :
	(msg->sadb_msg_reserved == 0) ? 0 : -EINVAL;

	PFKEY_DEBUG("sadb_msg_version=%d\n", msg->sadb_msg_version);
	PFKEY_DEBUG("sadb_msg_type=%d\n", msg->sadb_msg_type);
	PFKEY_DEBUG("sadb_msg_satype=%d\n", msg->sadb_msg_satype);
	PFKEY_DEBUG("sadb_msg_len=%d\n", msg->sadb_msg_len);
	PFKEY_DEBUG("sadb_msg_reserved=%d\n", msg->sadb_msg_reserved);

err:
	PFKEY_DEBUG("error=%d\n", error);
	return error;
}
コード例 #5
0
int sadb_msg_detect_ext(struct sadb_msg* msg, struct sadb_ext **ext_msgs)
{
	int error = 0, len = 0, msg_size = 0;
	struct sadb_ext *ext_ptr = NULL;

	if (!msg || !ext_msgs) {
		PFKEY_DEBUG("msg or ext_msgs is null.\n");
		error = -EINVAL;
		goto err;
	}

	error = sadb_msg_sanity_check(msg);
	if (error) {
		error = -EINVAL;
		goto err;
	}

	ext_ptr = (struct sadb_ext*)((u8*)msg + sizeof(struct sadb_msg));
	len = (msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_msg);

	while (len >= sizeof(*ext_ptr)) { 
		PFKEY_DEBUG("ext type %d\n", ext_ptr->sadb_ext_type);
		PFKEY_DEBUG("ext length %d\n", ext_ptr->sadb_ext_len);
		msg_size = (ext_ptr->sadb_ext_len) * IPSEC_PFKEYv2_ALIGN;
		if (len < msg_size)
			break;	/* error will be set later */
		ext_msgs[ext_ptr->sadb_ext_type] = ext_ptr;
		ext_ptr = (struct sadb_ext*)((u8*)ext_ptr + msg_size); 
		len -= msg_size;
	}

	if (len)
		error = -EINVAL;

err:
	PFKEY_DEBUG("error=%d\n", error);
	return error;
}		
int
pfkey_list_remove_socket(struct socket *socketp, struct socket_list **sockets)
{
	struct socket_list *socket_listp,*prev;

	PFKEY_DEBUG("called\n");
	if (!socketp) {
		return -EINVAL;
	}

	if (!sockets) {
		return -EINVAL;
	}

	socket_listp = *sockets;
	prev = NULL;
	
	while (socket_listp != NULL) {
		if (socket_listp->socketp == socketp) {
			if (prev != NULL) {
				prev->next = socket_listp->next;
			} else {
				*sockets = socket_listp->next;
			}
			
			kfree((void*)socket_listp);
			PFKEY_DEBUG("removed sock=%p\n", socketp);
			
			break;
		}
		prev = socket_listp;
		socket_listp = socket_listp->next;
	}
	PFKEY_DEBUG("end\n");

	return 0;
}
コード例 #7
0
int sadb_msg_flush_sp_parse(struct sock *sk, struct sadb_msg* msg, struct sadb_msg **reply)
{
	int error = 0;

	if (!msg) {
		PFKEY_DEBUG("msg==null\n");
		error = -EINVAL;
		goto err;
	}

	error = sadb_msg_sanity_check(msg);

	if (error) {
		PFKEY_DEBUG("message is invalid\n");
		goto err;
	}

	spd_clear_db();

	*reply = kmalloc(sizeof(struct sadb_msg), GFP_KERNEL);
	memcpy(*reply, msg, sizeof(struct sadb_msg));
err:
	return error;
}
static void
pfkey_remove_socket(struct sock *sk)
{
	struct sock **s;
	
	PFKEY_DEBUG("called\n");
	s=&pfkey_sock_list;

	while (*s!=NULL) {
		if (*s==sk) {
			*s=sk->next;
			sk->next=NULL;
			goto final;
		}
		s=&((*s)->next);
	}
コード例 #9
0
int lifetime_to_sadb_lifetime(struct sa_lifetime *lifetime, struct sadb_lifetime *ext_msg, int type)
{
	int error = 0;
	if ( !(lifetime&&ext_msg) ) {
		PFKEY_DEBUG("param is null\n");
		error = -EINVAL;
		goto err;
	}

	error = pfkey_lifetime_build((struct sadb_ext**)&ext_msg, type,
					lifetime->allocations,
					lifetime->bytes,
					lifetime->addtime,
					lifetime->usetime);
err:
	return error;
}
コード例 #10
0
int sadb_msg_dump_parse(struct sock *sk, struct sadb_msg* msg, struct sadb_msg **reply)
{
	int error = 0;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];

	if (!msg) {
		PFKEY_DEBUG("msg==null\n");
		error = -EINVAL;
		goto err;
	}

	memset(ext_msgs, 0, sizeof(ext_msgs));
	error = sadb_msg_detect_ext(msg, ext_msgs);

err:
	return error;
}
コード例 #11
0
int sadb_lifetime_to_lifetime(const struct sadb_lifetime* ext_msg, struct sa_lifetime* lifetime)
{
	int error = 0;

	if (!(ext_msg&&lifetime)) {
		PFKEY_DEBUG("param is null\n");
		error = -EINVAL;
		goto err;
	}

	lifetime->allocations 	= ext_msg->sadb_lifetime_allocations;
	lifetime->bytes 	= ext_msg->sadb_lifetime_bytes;
	lifetime->addtime	= ext_msg->sadb_lifetime_addtime;
	lifetime->usetime	= ext_msg->sadb_lifetime_usetime;

err:
	return error;
}
コード例 #12
0
int sadb_msg_expire_parse(struct sock *sk, struct sadb_msg *msg, struct sadb_msg **reply)
{
	int error = -EINVAL;

#if 0 /* kernel never receive SADB_EXPIRE message */

	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];

	if (!msg) {
		PFKEY_DEBUG("msg==null\n");
		error = -EINVAL;
		goto err;
	}

	memset(ext_msgs, 0, sizeof(ext_msgs));
	error = sadb_msg_detect_ext(msg, ext_msgs);

err:
#endif /* kernel never receive SADB_EXPIRE message */

	return error;
}
コード例 #13
0
int sadb_address_to_sockaddr(const struct sadb_address *ext_msg, struct sockaddr* addr)
{
	int error = 0, len = 0;
	struct sockaddr* tmp_addr = NULL;
#ifdef CONFIG_IPSEC_DEBUG
	char buf[BUF_SIZE];
#endif

	if ( !(ext_msg&&addr) ) {
		PFKEY_DEBUG("msg or addr is null\n");
		error = -EINVAL;
		goto err;
	}

	len = ext_msg->sadb_address_len - sizeof(struct sadb_address);
	if (len < sizeof(struct sockaddr)) {
		PFKEY_DEBUG("sadb_address_len is small len=%d\n", len);
		error = -EINVAL;
		goto err;
	}

	tmp_addr = (struct sockaddr*)((char*)ext_msg + sizeof(struct sadb_address));
	if (!tmp_addr) {
		PFKEY_DEBUG("address==null\n");
		error = -EINVAL;
		goto err;
	}

	switch (tmp_addr->sa_family) {

	case AF_INET:
#ifdef CONFIG_IPSEC_DEBUG
		PFKEY_DEBUG("address family is AF_INET\n");
		sockaddrtoa((struct sockaddr*)tmp_addr, buf, BUF_SIZE);
		PFKEY_DEBUG("address=%s\n", buf);
#endif
		memcpy(addr, tmp_addr, sizeof(struct sockaddr_in)); 
	break;

	case AF_INET6:
#ifdef CONFIG_IPSEC_DEBUG
		PFKEY_DEBUG("address family is AF_INET6\n");
		sockaddrtoa((struct sockaddr*)tmp_addr, buf, BUF_SIZE);
		PFKEY_DEBUG("address=%s\n", buf);
#endif
		memcpy(addr, tmp_addr, sizeof(struct sockaddr_in6)); 
	break;

	default:
		PFKEY_DEBUG("address family is unknown\n");
		error = -EINVAL;
		goto err;
	}

err:
#ifdef CONFIG_IPSEC_DEBUG
	if (!error)
		PFKEY_DEBUG("error=%d\n", error);
#endif
	return error;
}
コード例 #14
0
int sadb_msg_send_expire(struct ipsec_sa *sa)
{
	int i=0, error = 0;
	struct sadb_msg *msg = NULL;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
	struct socket_list *pfkey_socketsp = NULL;

	if (!sa) {
		PFKEY_DEBUG("sa is null\n");
		return -EINVAL;
	}

	memset(ext_msgs, 0, sizeof(ext_msgs));

	error = pfkey_msg_hdr_build(&ext_msgs[0],
				    SADB_EXPIRE,
				    sa->ipsec_proto,
				    0,
				    0,
				    0);
	if (error) {
		PFKEY_DEBUG("pfkey_msg_hdr_build is failed\n");
		goto free_ext_finish;
	}

	error = pfkey_sa_build(&ext_msgs[SADB_EXT_SA],
				   SADB_EXT_SA,
				   sa->spi,
				   64,
				   sa->state,
				   sa->auth_algo.algo,
				   sa->esp_algo.algo,
				   0); /* TODO: add pfs flag to struct ipsec_sa */
	if (error) {
		PFKEY_DEBUG("pfkey_sa_build is failed\n");
		goto free_ext_finish;
	}

	error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_CURRENT],
					 SADB_EXT_LIFETIME_CURRENT,
					 sa->lifetime_c.allocations,
					 sa->lifetime_c.bytes,
					 sa->lifetime_c.addtime,
					 sa->lifetime_c.usetime);
	if (error) {
		PFKEY_DEBUG("pfkey_lifetime_build is failed\n");
		goto free_ext_finish;
	}

	switch(sa->state) {
	case SADB_SASTATE_DEAD:
		error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_HARD],
						 SADB_EXT_LIFETIME_HARD,
						 sa->lifetime_h.allocations,
						 sa->lifetime_h.bytes,
						 sa->lifetime_h.addtime,
						 sa->lifetime_h.usetime);
		if (error) {
			PFKEY_DEBUG("pfkey_liftime_build(hard) is failed\n");
			goto free_ext_finish;
		}
		break;

	case SADB_SASTATE_DYING:
		error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_SOFT],
						 SADB_EXT_LIFETIME_SOFT,
						 sa->lifetime_s.allocations,
						 sa->lifetime_s.bytes,
						 sa->lifetime_s.addtime,
						 sa->lifetime_s.usetime);
		if (error) {
			PFKEY_DEBUG("pfkey_lifetime_build(soft) is failed\n");
			goto free_ext_finish;
		}
		break;

	case SADB_SASTATE_LARVAL:
	case SADB_SASTATE_MATURE:
	default:
		error = -EINVAL;
		goto free_ext_finish;

	}
	
	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC],
					SADB_EXT_ADDRESS_SRC,
					sa->proto,
					sa->prefixlen_s,
					(struct sockaddr*)&sa->src);
	if (error) goto free_ext_finish;

	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST],
					SADB_EXT_ADDRESS_DST,
					sa->proto,
					sa->prefixlen_d,
					(struct sockaddr*)&sa->dst);
	if (error) goto free_ext_finish;

	error = pfkey_msg_build(&msg, ext_msgs, EXT_BITS_OUT);

	write_lock(&pfkey_sk_lock);
	for (pfkey_socketsp = pfkey_open_sockets;
		pfkey_socketsp;
			pfkey_socketsp = pfkey_socketsp->next)
	{
		pfkey_upmsg(pfkey_socketsp->socketp, msg);
	}
	write_unlock(&pfkey_sk_lock);

	kfree(msg);

free_ext_finish:
	for(i=0; i<SADB_MAX+1; i++) {
		if (ext_msgs[i]) {
			kfree(ext_msgs[i]);
		}
	}

	return 0;

}
/* derived from FreeS/WAN-1.9 pfkey_v2_parse.c (mk) */
int
pfkey_msg_interp(struct sock *sk, struct sadb_msg *pfkey_msg)
{
	int error = 0;
	struct sadb_msg *pfkey_reply = NULL;
	struct sadb_ext *reply_ext_msgs[SADB_EXT_MAX+1];
	struct socket_list *pfkey_socketsp = 0;

	if (pfkey_msg->sadb_msg_satype > SADB_SATYPE_MAX) {
		return -EINVAL;
	}
	
	memset(reply_ext_msgs, 0, SADB_EXT_MAX+1);

	switch (pfkey_msg->sadb_msg_type) {
	case SADB_GETSPI:
		error = sadb_msg_add_parse(sk, pfkey_msg, &pfkey_reply);
		PFKEY_DEBUG("PF_KEY:interp: SADB_GETSPI\n");
		break;
	case SADB_UPDATE:
		error = -EINVAL;/* XXX */
		PFKEY_DEBUG("PF_KEY:interp: SADB_UPDATE\n");
		break;
	case SADB_ADD:
		error = sadb_msg_add_parse(sk, pfkey_msg, &pfkey_reply);
		PFKEY_DEBUG("PF_KEY:interp: SADB_ADD\n");
		break;
	case SADB_DELETE:
		error = sadb_msg_delete_parse(sk, pfkey_msg, &pfkey_reply);
		PFKEY_DEBUG("PF_KEY:interp: SADB_DELETE\n");
		break;
	case SADB_FLUSH:
		error = sadb_msg_flush_parse(sk, pfkey_msg, &pfkey_reply);
		PFKEY_DEBUG("PF_KEY:interp: SADB_FLUSH\n");
		break;
	case SADB_REGISTER:
		error = sadb_msg_register_parse(sk, pfkey_msg, &pfkey_reply);
		PFKEY_DEBUG("PF_KEY:interp: SADB_REGISTER\n");
		break;
	case SADB_X_GRPSA:
		error =  -EINVAL;/* XXX */
		PFKEY_DEBUG("PF_KEY:interp: SADB_X_GRPSA\n");
		break;
	case SADB_X_ADDFLOW:
		error = sadb_msg_addflow_parse(sk, pfkey_msg, &pfkey_reply);
		PFKEY_DEBUG("PF_KEY:interp: SADB_ADDFLOW\n");
		break;
	case SADB_X_DELFLOW:
		error = sadb_msg_delflow_parse(sk, pfkey_msg, &pfkey_reply);
		PFKEY_DEBUG("PF_KEY:interp: SADB_DELFLOW\n");
		break;

	case SADB_X_FLUSH_SP:
		error = sadb_msg_flush_sp_parse(sk, pfkey_msg, &pfkey_reply);
		PFKEY_DEBUG("PFKEY:interp: SADB_X_FLUSH_SP\n");
		break;
	default:
		error = -EINVAL;
		break;
	}
	
	if (error) {
		PFKEY_DEBUG("PFKEY:interp: parse routine return error=%d\n", error);
		goto err;
	}

	switch (pfkey_msg->sadb_msg_type) {

	case SADB_GETSPI:
	case SADB_UPDATE:
	case SADB_ADD:
	case SADB_DELETE:
	case SADB_FLUSH:
	case SADB_X_ADDFLOW:
	case SADB_X_DELFLOW:
	case SADB_X_FLUSH_SP:
		write_lock_bh(&pfkey_sk_lock);
		for (pfkey_socketsp = pfkey_open_sockets;
	    		pfkey_socketsp;
	    			pfkey_socketsp = pfkey_socketsp->next)
		{
			pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply);
		}
		write_unlock_bh(&pfkey_sk_lock);
		break;

	case SADB_GET:
	case SADB_DUMP:
	case SADB_REGISTER:
		write_lock_bh(&pfkey_sk_lock);
		pfkey_upmsg(sk->socket, pfkey_reply);
		write_unlock_bh(&pfkey_sk_lock);
		break;

	case SADB_ACQUIRE:
		write_lock_bh(&pfkey_sk_lock);
		for (pfkey_socketsp = pfkey_registered_sockets[pfkey_msg->sadb_msg_satype];
			pfkey_socketsp;
				pfkey_socketsp = pfkey_socketsp->next)
		{
			pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply);
		}
		write_unlock_bh(&pfkey_sk_lock);
		break;

	default:
		error = -EINVAL;
		goto err;
	}

	if (pfkey_reply)
		kfree(pfkey_reply);

	return 0;
err:
	if (pfkey_reply)
		kfree(pfkey_reply);

	pfkey_reply = kmalloc(sizeof(struct sadb_msg), GFP_KERNEL);
	if (!pfkey_reply){
		return -ENOMEM;
	}
	memcpy(pfkey_reply, pfkey_msg, sizeof(pfkey_reply));
	pfkey_reply->sadb_msg_errno = error;

	write_lock_bh(&pfkey_sk_lock);
	pfkey_upmsg(sk->socket, pfkey_reply);
	for (pfkey_socketsp = pfkey_registered_sockets[pfkey_msg->sadb_msg_satype];
		pfkey_socketsp;
			pfkey_socketsp = pfkey_socketsp->next)
	{
		pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply);
	}
	write_unlock_bh(&pfkey_sk_lock);

	if (pfkey_reply) {
		kfree(pfkey_reply);
	}

	return error;
}
コード例 #16
0
int sadb_key_to_esp(const __u8 esp_algo, const struct sadb_key* ext_msg, struct ipsec_sa* sa_entry)
{
	int error = 0;
	char *algoname = NULL;
	struct cipher_implementation *ci=NULL;

	if (!sa_entry) {
		PFKEY_DEBUG("sa_entry is null\n");
		error = -EINVAL;
		goto err;
	}

	if (esp_algo != SADB_EALG_NULL && !ext_msg) {
		PFKEY_DEBUG("ext_msg is null\n");
		error = -EINVAL;
		goto err;
	}

	switch (esp_algo) {
	case SADB_EALG_DESCBC:
		algoname = "des-cbc";
		PFKEY_DEBUG("esp algorithm is DES-CBC\n");
		if(ext_msg->sadb_key_bits != ESP_DES_KEY_BITS){
			PFKEY_DEBUG("the key length is not match\n");
			error = -EINVAL;
			goto err;
		} 
		break;
	case SADB_EALG_3DESCBC:
		algoname = "des_ede3-cbc";
		PFKEY_DEBUG("esp algorithm is 3DES-CBC\n");
		if(ext_msg->sadb_key_bits != ESP_3DES_KEY_BITS){
			PFKEY_DEBUG("the key length is not match\n");
			error = -EINVAL;
			goto err;
		}
		break;
	case SADB_EALG_NULL:
		algoname = "null-algo";
		PFKEY_DEBUG("esp algorithm is NULL\n");
		break; 
	case SADB_EALG_AES:
		algoname = "aes-cbc";
		PFKEY_DEBUG("esp algorithm is AES(128-bit)\n");
		if (ext_msg->sadb_key_bits != ESP_AES_KEY_BITS) {
			PFKEY_DEBUG("the key length is no match\n");
			error = -EINVAL;
			goto err;
		}
		break;
	case SADB_EALG_NONE: /* currently not enter */
	default:
		PFKEY_DEBUG("esp_algo is NONE or not supported one\n");
		error = -EINVAL;
		goto err;
	}	

	ci = find_cipher_by_name(algoname, 1);
	if(!ci){
		PFKEY_DEBUG("algorithm %u:%s is not supported\n", esp_algo, algoname);
		error = -EINVAL;
		goto err;
	}
	ci->lock();

	sa_entry->esp_algo.algo = esp_algo;

	if (esp_algo != SADB_EALG_NULL) {
		sa_entry->esp_algo.key_len = (ext_msg->sadb_key_bits)/OCTETBITS;
	} else {
		sa_entry->esp_algo.key_len = 0;
	}

	sa_entry->esp_algo.cx = ci->realloc_context (NULL, ci, sa_entry->esp_algo.key_len);
	if (!sa_entry->esp_algo.cx) {
		ci->unlock();
		error = -EINVAL;
		goto err;
	}
	sa_entry->esp_algo.cx->ci = ci;

	if (esp_algo != SADB_EALG_NULL) {
		sa_entry->esp_algo.key = kmalloc(sa_entry->esp_algo.key_len, GFP_KERNEL);
		if (!sa_entry->esp_algo.key) {
			PFKEY_DEBUG("could not allocate memory for key\n");
			ci->wipe_context(sa_entry->esp_algo.cx);
			ci->free_context(sa_entry->esp_algo.cx);
			ci->unlock();
			error = -ENOMEM;
			goto err;
		}
		memset(sa_entry->esp_algo.key, 0, sa_entry->esp_algo.key_len);
		memcpy(sa_entry->esp_algo.key, ((char*)ext_msg)+sizeof(struct sadb_key), sa_entry->esp_algo.key_len);

		sa_entry->esp_algo.cx->keyinfo = (u32*)kmalloc(ci->key_schedule_size, GFP_KERNEL);
		if (!sa_entry->esp_algo.cx->keyinfo) {
			PFKEY_DEBUG("could not allocate memory for keyinfo\n");
			ci->unlock();
			error = -ENOMEM;
			goto err;
		}

		memset(sa_entry->esp_algo.cx->keyinfo, 0, ci->key_schedule_size);

		error = ci->set_key(sa_entry->esp_algo.cx, ((char*)ext_msg)+sizeof(struct sadb_key), sa_entry->esp_algo.key_len);
		if (error < 0) {
			PFKEY_DEBUG("set_key failed, key is wondered weak \n");
			ci->wipe_context(sa_entry->esp_algo.cx);
			ci->free_context(sa_entry->esp_algo.cx);
			ci->unlock();
			goto err;
		}
	}
err:
	return error;

}
コード例 #17
0
int sadb_key_to_auth(const __u8 auth_algo, const struct sadb_key* ext_msg, struct ipsec_sa* sa_entry)
{
	int error = 0;
	char *algoname = NULL;
	__u16 digest_len = 0;
	struct digest_implementation *di = NULL;

	if(!(ext_msg&&sa_entry)){
		PFKEY_DEBUG("msg or sa_entry is null\n");
		error = -EINVAL;
		goto err;
	}

	switch(auth_algo){

	case SADB_AALG_MD5HMAC:
		algoname = "md5";
		digest_len = 12; /* 96 bit length */
		PFKEY_DEBUG("auth algorithm is HMAC-MD5\n");

		if(ext_msg->sadb_key_bits != AUTH_MD5HMAC_KEY_BITS){
			PFKEY_DEBUG("the key length is %d\n", ext_msg->sadb_key_bits);
			PFKEY_DEBUG("the key length is not match\n");
			error = -EINVAL;
			goto err;
		} 

			
	break;

	case SADB_AALG_SHA1HMAC:
		algoname = "sha1";
		digest_len = 12; /* 96 bit length */
		PFKEY_DEBUG("auth algorithm is HMAC-SHA1\n");

		if(ext_msg->sadb_key_bits != AUTH_SHA1HMAC_KEY_BITS){
			PFKEY_DEBUG("the key length is %d\n", ext_msg->sadb_key_bits);
			PFKEY_DEBUG("the key length is not match\n");
			error = -EINVAL;
			goto err;
		} 

	break;

	case SADB_AALG_NONE:
	default:
		PFKEY_DEBUG("auth_algo is NONE or not supported one\n");
		error = -EINVAL;
		goto err;
	}

	di = find_digest_by_name(algoname, 0);
	if (!di) {
		PFKEY_DEBUG("algorithm %u:%s is not supported\n", auth_algo, algoname);
		error = -EINVAL;
		goto err;
	}
	di->lock();

	sa_entry->auth_algo.algo = auth_algo;
	sa_entry->auth_algo.key_len = (ext_msg->sadb_key_bits)/OCTETBITS;
	sa_entry->auth_algo.digest_len = digest_len;
	sa_entry->auth_algo.dx = di->realloc_context(NULL, di);
	if (!sa_entry->auth_algo.dx) {
		di->unlock();
		error = -EINVAL;
		goto err;
	}
	sa_entry->auth_algo.dx->di = di;

	sa_entry->auth_algo.dx->digest_info = (u32 *)kmalloc(sa_entry->auth_algo.dx->di->working_size, GFP_KERNEL);
	if (!sa_entry->auth_algo.dx->digest_info) {
		PFKEY_DEBUG("cannot allocate digest_info\n");
		di->free_context(sa_entry->auth_algo.dx);
		di->unlock();
		error = -ENOMEM;
		goto err;
	}

	sa_entry->auth_algo.key = kmalloc(sa_entry->auth_algo.key_len, GFP_KERNEL);
	if (!sa_entry->auth_algo.key) {
		PFKEY_DEBUG("cannot allocate key\n");
		di->free_context(sa_entry->auth_algo.dx);
		di->unlock();
		error = -ENOMEM;
		kfree(sa_entry->auth_algo.dx->digest_info);
		goto err;
	}

	memcpy(sa_entry->auth_algo.key, (char *)ext_msg+sizeof(struct sadb_key),
			sa_entry->auth_algo.key_len);
err:
	return error;
}
コード例 #18
0
int sadb_msg_register_parse(struct sock *sk, struct sadb_msg *msg, struct sadb_msg **reply)
{
	int error = 0;
	uint  alg_num = 0;
	struct sadb_alg algs[5];
	struct digest_implementation *di = NULL;
	struct cipher_implementation *ci = NULL;
	struct sadb_ext *reply_ext_msgs[SADB_EXT_MAX+1];

	if (!(sk&&msg)) {
		PFKEY_DEBUG("msg or sk is null\n");
		error = -EINVAL;
		PFKEY_DEBUG("msg or *reply is null\n");
		goto err; 	
	}

	error = sadb_msg_sanity_check(msg);
	if (error) {
		goto err;
	}

	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
	memset(algs, 0, sizeof(algs));

	switch (msg->sadb_msg_satype) {

	case SADB_SATYPE_AH:
	case SADB_SATYPE_ESP:
		break;
	case SADB_SATYPE_RSVP:
	case SADB_SATYPE_OSPFV2:
	case SADB_SATYPE_RIPV2:
	case SADB_SATYPE_MIP:
	case SADB_X_SATYPE_IPIP:
	case SADB_X_SATYPE_COMP:
	case SADB_X_SATYPE_INT:

	default:
		error = -EINVAL;
		goto err;
	}

	write_lock(&pfkey_sk_lock);
	/*
	 register a socket with the proper SA type's socket list
	 it will be release in pfkey_release process (file:pfkey_v2.c).
	*/
	error = pfkey_list_insert_socket(sk->socket, &pfkey_registered_sockets[msg->sadb_msg_satype]);
	if (error) {
		goto err;
	}
	write_unlock(&pfkey_sk_lock);

	PFKEY_DEBUG("socket=%p registered, SA type is %d\n", sk->socket, msg->sadb_msg_satype);

	reply_ext_msgs[0] = (struct sadb_ext*)msg;

	if (msg->sadb_msg_satype == SADB_SATYPE_AH || msg->sadb_msg_satype == SADB_SATYPE_ESP) {
		di = find_digest_by_name("md5", 0 /* atomic */);
		if (di) {
			algs[alg_num].sadb_alg_id = SADB_AALG_MD5HMAC;
			algs[alg_num].sadb_alg_ivlen = 0;
			algs[alg_num].sadb_alg_minbits = AUTH_MD5HMAC_KEY_BITS;
			algs[alg_num].sadb_alg_maxbits = AUTH_MD5HMAC_KEY_BITS;
			algs[alg_num].sadb_alg_reserved = 0;
			alg_num++;
			di = NULL;	
		}
	
		di = find_digest_by_name("sha1", 0 /* atomic */);
		if (di) {
			algs[alg_num].sadb_alg_id = SADB_AALG_SHA1HMAC;
			algs[alg_num].sadb_alg_ivlen = 0;
			algs[alg_num].sadb_alg_minbits = AUTH_SHA1HMAC_KEY_BITS;
			algs[alg_num].sadb_alg_maxbits = AUTH_SHA1HMAC_KEY_BITS;
			algs[alg_num].sadb_alg_reserved = 0;
			alg_num++;
			di = NULL;
		}

		if (msg->sadb_msg_satype == SADB_SATYPE_AH) {
			error = pfkey_supported_build(&reply_ext_msgs[SADB_EXT_SUPPORTED_AUTH],
						SADB_EXT_SUPPORTED_AUTH,
						alg_num,
						algs);
			if (error) goto free_ext_finish;
		}

	}

	if (msg->sadb_msg_satype == SADB_SATYPE_ESP) {
		ci = find_cipher_by_name("des-cbc", 1 /* atomic */);
		if (ci) {
			ci->lock();
			algs[alg_num].sadb_alg_id = SADB_EALG_DESCBC;
			algs[alg_num].sadb_alg_ivlen = ci->ivsize;
			algs[alg_num].sadb_alg_minbits = ESP_DES_KEY_BITS;
			algs[alg_num].sadb_alg_maxbits = ESP_DES_KEY_BITS;
			algs[alg_num].sadb_alg_reserved = 0;
			alg_num++;
			ci->unlock();
			ci = NULL;
		}

		ci = find_cipher_by_name("des_ede3-cbc", 1 /* atomic */);
		if (ci) {
			ci->lock();
			algs[alg_num].sadb_alg_id = SADB_EALG_3DESCBC;
			algs[alg_num].sadb_alg_ivlen = ci->ivsize;
			algs[alg_num].sadb_alg_minbits = ESP_3DES_KEY_BITS;
			algs[alg_num].sadb_alg_maxbits = ESP_3DES_KEY_BITS;
			algs[alg_num].sadb_alg_reserved = 0;
			alg_num++;
			ci->unlock();
			ci = NULL;
		}
		ci = find_cipher_by_name("aes-cbc", 1 /* atomic */);
		if (ci) {
			ci->lock();
			algs[alg_num].sadb_alg_id = SADB_EALG_AES;
			algs[alg_num].sadb_alg_ivlen = ci->ivsize;
			algs[alg_num].sadb_alg_minbits = ESP_AES_KEY_BITS;
			algs[alg_num].sadb_alg_maxbits = ESP_AES_KEY_BITS;
			algs[alg_num].sadb_alg_reserved = 0;
			alg_num++;
			ci->unlock();
			ci = NULL;
		}

		error = pfkey_supported_build(&reply_ext_msgs[SADB_EXT_SUPPORTED_ENCRYPT],
						SADB_EXT_SUPPORTED_ENCRYPT,
						alg_num,
						algs);
		if (error) goto free_ext_finish;

	}

	pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT);

free_ext_finish:

	if (reply_ext_msgs[SADB_EXT_SUPPORTED_AUTH])
		kfree(reply_ext_msgs[SADB_EXT_SUPPORTED_AUTH]);

	if (reply_ext_msgs[SADB_EXT_SUPPORTED_ENCRYPT])
		kfree(reply_ext_msgs[SADB_EXT_SUPPORTED_ENCRYPT]);


err:

	return error;
}
コード例 #19
0
int sadb_msg_send_acquire(struct ipsec_sa *sa)
{
	int i=0, error = 0;
	uint  comb_num = 0;
	struct sadb_comb combs[4];
	struct digest_implementation *di = NULL;
	struct cipher_implementation *ci = NULL;
	struct sadb_msg *msg = NULL;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
	struct socket_list *pfkey_socketsp = NULL;

	memset(ext_msgs, 0, sizeof(ext_msgs));
	memset(combs, 0, sizeof(combs));

	if (sa->ipsec_proto == SADB_SATYPE_AH || sa->ipsec_proto == SADB_SATYPE_ESP) {
		di = find_digest_by_name("md5", 0 /* atomic */);
		if (di) {
			combs[comb_num].sadb_comb_auth = SADB_AALG_MD5HMAC;
			combs[comb_num].sadb_comb_auth_minbits = AUTH_MD5HMAC_KEY_BITS;
			combs[comb_num].sadb_comb_auth_maxbits = AUTH_MD5HMAC_KEY_BITS;
			combs[comb_num].sadb_comb_reserved = 0;
			combs[comb_num].sadb_comb_soft_allocations = 0;
			combs[comb_num].sadb_comb_hard_allocations = 0;
			combs[comb_num].sadb_comb_soft_bytes = 0;
			combs[comb_num].sadb_comb_hard_bytes = 0;
			combs[comb_num].sadb_comb_soft_addtime = 57600;
			combs[comb_num].sadb_comb_hard_addtime = 86400;
			combs[comb_num].sadb_comb_soft_usetime = 57600;
			combs[comb_num].sadb_comb_hard_usetime = 86400;
			comb_num++;
			di = NULL;	
		}
	
		di = find_digest_by_name("sha1", 0 /* atomic */);
		if (di) {
			combs[comb_num].sadb_comb_auth = SADB_AALG_SHA1HMAC;
			combs[comb_num].sadb_comb_auth_minbits = AUTH_SHA1HMAC_KEY_BITS;
			combs[comb_num].sadb_comb_auth_maxbits = AUTH_SHA1HMAC_KEY_BITS;
			combs[comb_num].sadb_comb_reserved = 0;
			combs[comb_num].sadb_comb_soft_allocations = 0;
			combs[comb_num].sadb_comb_hard_allocations = 0;
			combs[comb_num].sadb_comb_soft_bytes = 0;
			combs[comb_num].sadb_comb_hard_bytes = 0;
			combs[comb_num].sadb_comb_soft_addtime = 57600;
			combs[comb_num].sadb_comb_hard_addtime = 86400;
			combs[comb_num].sadb_comb_soft_usetime = 57600;
			combs[comb_num].sadb_comb_hard_usetime = 86400;
			comb_num++;
			di = NULL;
		}
	}

	if (sa->ipsec_proto == SADB_SATYPE_ESP) {
		ci = find_cipher_by_name("des-cbc", 1 /* atomic */);
		if (ci) {
			combs[comb_num].sadb_comb_encrypt = SADB_EALG_DESCBC;
			combs[comb_num].sadb_comb_encrypt_minbits = ESP_DES_KEY_BITS;
			combs[comb_num].sadb_comb_encrypt_maxbits = ESP_DES_KEY_BITS;
			combs[comb_num].sadb_comb_reserved = 0;
			combs[comb_num].sadb_comb_soft_allocations = 0;
			combs[comb_num].sadb_comb_hard_allocations = 0;
			combs[comb_num].sadb_comb_soft_bytes = 0;
			combs[comb_num].sadb_comb_hard_bytes = 0;
			combs[comb_num].sadb_comb_soft_addtime = 57600;
			combs[comb_num].sadb_comb_hard_addtime = 86400;
			combs[comb_num].sadb_comb_soft_usetime = 57600;
			combs[comb_num].sadb_comb_hard_usetime = 86400;
			comb_num++;
			ci = NULL;
		}

		ci = find_cipher_by_name("des_ede3-cbc", 1 /* atomic */);
		if (ci) {
			combs[comb_num].sadb_comb_encrypt = SADB_EALG_3DESCBC;
			combs[comb_num].sadb_comb_encrypt_minbits = ESP_3DES_KEY_BITS;
			combs[comb_num].sadb_comb_encrypt_maxbits = ESP_3DES_KEY_BITS;
			combs[comb_num].sadb_comb_reserved = 0;
			combs[comb_num].sadb_comb_soft_allocations = 0;
			combs[comb_num].sadb_comb_hard_allocations = 0;
			combs[comb_num].sadb_comb_soft_bytes = 0;
			combs[comb_num].sadb_comb_hard_bytes = 0;
			combs[comb_num].sadb_comb_soft_addtime = 57600;
			combs[comb_num].sadb_comb_hard_addtime = 86400;
			combs[comb_num].sadb_comb_soft_usetime = 57600;
			combs[comb_num].sadb_comb_hard_usetime = 86400;
			comb_num++;
			ci = NULL;
		}

		ci = find_cipher_by_name("aes-cbc", 1 /* atomic */);
		if (ci) {
			combs[comb_num].sadb_comb_encrypt = SADB_EALG_AES;
			combs[comb_num].sadb_comb_encrypt_minbits = ESP_AES_KEY_BITS;
			combs[comb_num].sadb_comb_encrypt_maxbits = ESP_AES_KEY_BITS;
			combs[comb_num].sadb_comb_reserved = 0;
			combs[comb_num].sadb_comb_soft_allocations = 0;
			combs[comb_num].sadb_comb_hard_allocations = 0;
			combs[comb_num].sadb_comb_soft_bytes = 0;
			combs[comb_num].sadb_comb_hard_bytes = 0;
			combs[comb_num].sadb_comb_soft_addtime = 57600;
			combs[comb_num].sadb_comb_hard_addtime = 86400;
			combs[comb_num].sadb_comb_soft_usetime = 57600;
			combs[comb_num].sadb_comb_hard_usetime = 86400;
			comb_num++;
			ci = NULL;
		}
	}

	error = pfkey_msg_hdr_build(&ext_msgs[0],
				    SADB_ACQUIRE,
				    sa->ipsec_proto,
				    0,
				    0,
				    0);
	if (error) {
		PFKEY_DEBUG("pfkey_msg_hdr_build is failed\n");
		goto free_ext_finish;
	}

	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC],
					SADB_EXT_ADDRESS_SRC,
					sa->proto,
					sa->prefixlen_s,
					(struct sockaddr*)&sa->src);
	if (error) goto free_ext_finish;

	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST],
					SADB_EXT_ADDRESS_DST,
					sa->proto,
					sa->prefixlen_d,
					(struct sockaddr*)&sa->dst);
	if (error) goto free_ext_finish;

	error = pfkey_prop_build(&ext_msgs[SADB_EXT_PROPOSAL],
					64,
					comb_num,
					combs);
	if (error) goto free_ext_finish;


	error = pfkey_msg_build(&msg, ext_msgs, EXT_BITS_OUT);

	write_lock(&pfkey_sk_lock);
	for (pfkey_socketsp = pfkey_registered_sockets[sa->ipsec_proto];
		pfkey_socketsp;
			pfkey_socketsp = pfkey_socketsp->next)
	{
		pfkey_upmsg(pfkey_socketsp->socketp, msg);
	}
	write_unlock(&pfkey_sk_lock);

	kfree(msg);
free_ext_finish:

	for(i=0; i<SADB_MAX+1; i++) {
		if (ext_msgs[i]) {
			kfree(ext_msgs[i]);
		}
	}

	return 0;
}
int sadb_msg_add_parse(struct sock *sk, struct sadb_msg *msg, struct sadb_msg **reply)
{
	int error = 0;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1], *reply_ext_msgs[SADB_EXT_MAX+1];
	struct sadb_sa *sa;
	struct sadb_address *src;
	struct sadb_address *dst;
	struct ipsec_sa *sa_entry = NULL;

	if (!msg) {
		PFKEY_DEBUG("msg==null\n");
		error = -EINVAL;
		goto rtn;
	}

	memset(ext_msgs, 0, sizeof(ext_msgs));
	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
	error = sadb_msg_detect_ext(msg, ext_msgs);

	if (ext_msgs[SADB_EXT_SA] &&
		ext_msgs[SADB_EXT_ADDRESS_SRC] &&
		ext_msgs[SADB_EXT_ADDRESS_DST])
	{
		sa  = (struct sadb_sa*)ext_msgs[SADB_EXT_SA];

		if ( ((!sa->sadb_sa_auth && !sa->sadb_sa_encrypt) && msg->sadb_msg_satype != SADB_X_SATYPE_COMP) || 
				sa->sadb_sa_auth > SADB_AALG_MAX || 
				sa->sadb_sa_encrypt > SADB_EALG_MAX ) {
			PFKEY_DEBUG("sa has no transform or invalid transform value\n");
			error = -EINVAL;
			goto rtn;
		}

		switch (msg->sadb_msg_satype) {

		case SADB_SATYPE_AH:
		case SADB_SATYPE_ESP:
		case SADB_X_SATYPE_COMP:
			break;
		case SADB_SATYPE_RSVP:
		case SADB_SATYPE_OSPFV2:
		case SADB_SATYPE_RIPV2:
		case SADB_SATYPE_MIP:
		default:
			PFKEY_DEBUG("invalid sa type\n");
			error = -EINVAL;
			goto rtn;
		}

		if (msg->sadb_msg_satype == SADB_SATYPE_ESP && !(sa->sadb_sa_encrypt)) {
			PFKEY_DEBUG("sa type is esp but no algorithm\n");
			error = -EINVAL;
			goto rtn;
		}

		sa_entry = ipsec_sa_kmalloc();
		if (!sa_entry) {
			PFKEY_DEBUG("sa_entry: null\n");
			error = -ENOMEM;
			goto err;
		}

		src = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_SRC];
		dst = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_DST];

		sa_entry->ipsec_proto = msg->sadb_msg_satype;

		/* SPI which is under 255 is reserved by IANA. 
		 * Additionally, 256 and 257 reserved for our internal use.  */
		if (ntohl(sa->sadb_sa_spi) < 258 && sa_entry->ipsec_proto != SADB_X_SATYPE_COMP) {
			PFKEY_DEBUG("SPI value is reserved.(SPI<258)\n");
			goto err;
		}

		sa_entry->spi = sa->sadb_sa_spi;

		error = sadb_address_to_sockaddr( src,
				(struct sockaddr*)&sa_entry->src);
		if (error) {
			PFKEY_DEBUG("src translation failed\n");
			goto err;
		}
		error = sadb_address_to_sockaddr( dst,
				(struct sockaddr*)&sa_entry->dst);
		if (error) {
			PFKEY_DEBUG("dst translation failed\n");
			goto err;
		}

		if (src->sadb_address_proto == dst->sadb_address_proto) {
			sa_entry->proto = src->sadb_address_proto;
		} else {
			error = -EINVAL;
			goto err;
		} 

		sa_entry->prefixlen_s = src->sadb_address_prefixlen;
		sa_entry->prefixlen_d = dst->sadb_address_prefixlen;

		if (sa->sadb_sa_auth) {
			if( (ext_msgs[SADB_EXT_KEY_AUTH]) ) {
				error = sadb_key_to_auth(sa->sadb_sa_auth,
					(struct sadb_key*) ext_msgs[SADB_EXT_KEY_AUTH], sa_entry);
				if (error)
					goto err;
			} else {
				PFKEY_DEBUG("SA has auth algo but there is no key for auth\n");
				error = -EINVAL;
				goto err;
			}
		}

		if (sa->sadb_sa_encrypt) {
			if (sa->sadb_sa_encrypt == SADB_EALG_NULL && 
					sa->sadb_sa_auth == SADB_AALG_NONE) {
				error = -EINVAL;
				goto err;
			}
			if (msg->sadb_msg_satype != SADB_X_SATYPE_COMP) {
				error = sadb_key_to_esp(sa->sadb_sa_encrypt, 
					(struct sadb_key*) ext_msgs[SADB_EXT_KEY_ENCRYPT], sa_entry);
				if (error)
					goto err;
			}
		}

		if (ext_msgs[SADB_EXT_ADDRESS_PROXY]) {
			printk(KERN_WARNING "PFKEY proxy translation is not supported.\n");
			goto err;
		}

		if (ext_msgs[SADB_EXT_LIFETIME_HARD]) {
			error = sadb_lifetime_to_lifetime((struct sadb_lifetime*)ext_msgs[SADB_EXT_LIFETIME_HARD],
						&sa_entry->lifetime_h);
			if (error) goto err;
		}

		if (ext_msgs[SADB_EXT_LIFETIME_SOFT]) {
			error = sadb_lifetime_to_lifetime((struct sadb_lifetime*)ext_msgs[SADB_EXT_LIFETIME_SOFT],
						&sa_entry->lifetime_s);
			if (error) goto err;
		}

		sa_entry->state = SADB_SASTATE_MATURE;

		error = sadb_append(sa_entry);	
		if (error) goto err;	

		reply_ext_msgs[0] = (struct sadb_ext*) msg;
		reply_ext_msgs[SADB_EXT_SA] = ext_msgs[SADB_EXT_SA];
		reply_ext_msgs[SADB_EXT_ADDRESS_SRC] = ext_msgs[SADB_EXT_ADDRESS_SRC];
		reply_ext_msgs[SADB_EXT_ADDRESS_DST] = ext_msgs[SADB_EXT_ADDRESS_DST];

		if (ext_msgs[SADB_EXT_LIFETIME_HARD])
			reply_ext_msgs[SADB_EXT_LIFETIME_HARD] = ext_msgs[SADB_EXT_LIFETIME_HARD];

		if (ext_msgs[SADB_EXT_LIFETIME_SOFT])
			reply_ext_msgs[SADB_EXT_LIFETIME_SOFT] = ext_msgs[SADB_EXT_LIFETIME_SOFT];

		error = pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT);
		goto rtn;
	} else {
		PFKEY_DEBUG("extensions not enough\n");
		error = -EINVAL;
		goto err;
	}

err:
	ipsec_sa_kfree(sa_entry);
rtn:
	return error;
}
int sadb_msg_getspi_parse(struct sock *sk, struct sadb_msg* msg, struct sadb_msg **reply) 
{
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1], *reply_ext_msgs[SADB_EXT_MAX+1];
	int error = 0, found_avail = 0;
	__u32 newspi = 0;
	__u32 spi_max = 0, spi_min = 0;
	struct ipsec_sa sadb_entry;
	struct sadb_address *src, *dst;

	if (!msg) {
		PFKEY_DEBUG("msg==null\n");

		error = -EINVAL;
		goto err;
	}

	memset(ext_msgs, 0, sizeof(ext_msgs));
	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
	error = sadb_msg_detect_ext(msg, ext_msgs);

	if (error) {
		PFKEY_DEBUG("error in sadb_msg_detect_ext\n");
		goto err;
	}

	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));

	if (ext_msgs[SADB_EXT_ADDRESS_SRC] &&
	    ext_msgs[SADB_EXT_ADDRESS_DST] &&
	    ext_msgs[SADB_EXT_SPIRANGE])
	{
		src = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_SRC];
		dst = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_DST];

		memset(&sadb_entry, 0, sizeof(struct ipsec_sa));
		error = sadb_address_to_sockaddr(src, (struct sockaddr*)&sadb_entry.src);
		if (error) {
			PFKEY_DEBUG("error in translate src address\n");
			goto err;
		}
		sadb_entry.prefixlen_s = src->sadb_address_prefixlen;

		error = sadb_address_to_sockaddr(dst, (struct sockaddr*)&sadb_entry.dst);
		if (error) {
			PFKEY_DEBUG("error in translate dst address\n");
		}
		sadb_entry.prefixlen_d = dst->sadb_address_prefixlen;

		spi_min = ((struct sadb_spirange*)ext_msgs[SADB_EXT_SPIRANGE])->sadb_spirange_min;
		spi_max = ((struct sadb_spirange*)ext_msgs[SADB_EXT_SPIRANGE])->sadb_spirange_max;

		/* SPI which is under 255 is reserved by IANA. 
		 * Additionally, 256 and 257 reserved ofr internal use.  */
		if (spi_min < 258) {
			PFKEY_DEBUG("SPI value is reserved.(SPI<258)\n");
			goto err;
		}

		if (spi_min == spi_max) {
			PFKEY_DEBUG("spi_min and spi_max are equal\n");

			error = sadb_find_by_address_proto_spi((struct sockaddr*)&sadb_entry.src, sadb_entry.prefixlen_s, 
								(struct sockaddr*)&sadb_entry.dst, sadb_entry.prefixlen_d, 
								spi_min, msg->sadb_msg_type, NULL /*only check*/);
				
			if (error == -ESRCH) {
				newspi = spi_min;
				found_avail = 1;
			} else {
				PFKEY_DEBUG("sadb_find_by_address_proto_spi return %d\n", error);
				goto err;
			}

		} else if (ntohl(spi_min) < ntohl(spi_max)) {
			/* This codes are derived from FreeS/WAN */
			int i = 0;
                	__u32 rand_val;
			__u32 spi_diff;

			PFKEY_DEBUG("spi_min and spi_max are defference\n");

			while ( ( i < (spi_diff = (ntohl(spi_max) - ntohl(spi_min)))) && !found_avail ) {
				get_random_bytes((void*) &rand_val,
				/* sizeof(extr->tdb->tdb_said.spi) */
                                         ( (spi_diff < (2^8))  ? 1 :
                                           ( (spi_diff < (2^16)) ? 2 :
                                             ( (spi_diff < (2^24)) ? 3 :
                                           4 ) ) ) );
				newspi = htonl(ntohl(spi_min) +
					(rand_val % (spi_diff + 1)));
				PFKEY_DEBUG("new spi is %d\n", ntohl(newspi));

				i++;
				error = sadb_find_by_address_proto_spi( (struct sockaddr*)&sadb_entry.src, sadb_entry.prefixlen_s, 
									(struct sockaddr*)&sadb_entry.dst, sadb_entry.prefixlen_d, 
									newspi, msg->sadb_msg_type, NULL /* only check */);
				if (error == -ESRCH) {
					found_avail = 1;
					break;
				} else {
					PFKEY_DEBUG("sadb_find_by_address_proto_spi return %d\n", error);
					goto err;
				}
			}

		} else {
			PFKEY_DEBUG("invalid spi range\n");
			error = -EINVAL;
			goto err;
		}

		if (found_avail) {
			sadb_entry.spi = newspi;
			sadb_entry.state = SADB_SASTATE_LARVAL;
			error = sadb_append(&sadb_entry);
			if (error) {
				PFKEY_DEBUG("sadb_append return %d\n", error);
				goto err;
			}
		} else {
			PFKEY_DEBUG("could not find available spi\n");
			goto err;
		}

	} else {
		PFKEY_DEBUG("necessary ext messages are not available\n");
		error = -EINVAL;
		goto err;
	}

	error = pfkey_sa_build(&reply_ext_msgs[SADB_EXT_SA], SADB_EXT_SA,
			newspi, 0, 0, 0, 0, SADB_SAFLAGS_PFS);
	if (error) {
		PFKEY_DEBUG("pfkey_address_build faild\n");
		goto err;
	}

	reply_ext_msgs[0] = (struct sadb_ext*) msg;
	reply_ext_msgs[SADB_EXT_ADDRESS_SRC] = ext_msgs[SADB_EXT_ADDRESS_SRC];
	reply_ext_msgs[SADB_EXT_ADDRESS_DST] = ext_msgs[SADB_EXT_ADDRESS_DST];
	error = pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT);
err:
	return error;
}