/* $USAGI: pfkey_v2_msg_update.c,v 1.1 2001/12/23 16:01:12 mk Exp $ */
/*
 * Copyright (C)2001 USAGI/WIDE Project
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
/*
 * This is a parse routine for a message of SADB_UPDATE.
 */

#ifdef MODULE
#include <linux/module.h>
#  ifdef MODVERSIONS
#  include <linux/modversions.h>
#  endif
#endif

#include <linux/config.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/random.h>
#include <linux/ipsec.h>

#include <net/pfkeyv2.h>
#include <net/sadb.h>

#include "pfkey_v2_msg.h"
#include "sadb_utils.h" /* esptoa authtoa */
			/* sockaddrtoa ultoa */
#define BUFSIZE 64

int sadb_msg_update_parse(struct sock *sk, struct sadb_msg* msg, struct sadb_msg **reply)
{
	int error = 0;
	__u32 spi = 0;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
	struct sadb_sa *sa = NULL;
	struct sadb_address *src = NULL;
	struct sadb_address *dst = NULL;
	struct sadb_address *pxy = NULL;
	struct ipsec_sa *sa_entry = NULL;
	struct sockaddr_storage saddr, daddr, paddr;

	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);
	
	if (ext_msgs[SADB_EXT_SA] &&
	    ext_msgs[SADB_EXT_ADDRESS_SRC] &&
	    ext_msgs[SADB_EXT_ADDRESS_DST] &&
	   (ext_msgs[SADB_EXT_KEY_AUTH] ||
	    ext_msgs[SADB_EXT_KEY_ENCRYPT]))
	{
		
		memset(&saddr, 0, sizeof(struct sockaddr_storage));
		memset(&daddr, 0, sizeof(struct sockaddr_storage));
		memset(&paddr, 0, sizeof(struct sockaddr_storage));

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

		spi = sa->sadb_sa_spi;

		error = sadb_address_to_sockaddr( src, (struct sockaddr*)&saddr);

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

		if (ext_msgs[SADB_EXT_ADDRESS_PROXY]) {
			pxy = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_PROXY];
			error = sadb_address_to_sockaddr( pxy, (struct sockaddr*)&paddr);
			if (error) {
				PFKEY_DEBUG("pxy translation falied\n");
				goto err;
			}
		}

		if (sa->sadb_sa_auth && !(ext_msgs[SADB_EXT_KEY_AUTH])) {
			PFKEY_DEBUG("sa has auth algo but there is no key for auth\n");
			error = -EINVAL;
			goto err;
		}

		if (sa->sadb_sa_encrypt && !(ext_msgs[SADB_EXT_KEY_ENCRYPT])) {
			PFKEY_DEBUG("sa has esp algo but there is no key for esp\n");
			error = -EINVAL;
			goto err;
		}

		if (ext_msgs[SADB_EXT_ADDRESS_PROXY]) { 
			error = sadb_find_by_address_proto_spi((struct sockaddr*)&saddr, src->sadb_address_prefixlen,
						 (struct sockaddr*)&daddr, dst->sadb_address_prefixlen,
						 (struct sockaddr*)&paddr, 0,
						 msg->sadb_msg_type,
						 spi,
						 &sa_entry);
		} else { 
			error = sadb_find_by_address_proto_spi((struct sockaddr*)&saddr, src->sadb_address_prefixlen,
						 (struct sockaddr*)&daddr, dst->sadb_address_prefixlen,
						 NULL, 0,/* ignore proxy */
						 msg->sadb_msg_type,
						 spi,
						 &sa_entry);

		}

		if (error) {
			PFKEY_DEBUG("could not find sa\n");
			goto err;
		}

		switch (sa_entry->state) {

		case SADB_SASTATE_LARVAL:

		break;

		case SADB_SASTATE_MATURE:
		case SADB_SASTATE_DYING:

		break;

		case SADB_SASTATE_DEAD:
		default:

		}

	}
	/* mask auth key and esp key */
err:
	return error;
}

