#include <linux/config.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/skbuff.h>
#include <stdio.h>
#include <assert.h>

#include "skb_fake.h"
#include "slab_fake.h"

#include "libreswan.h"
#include "libreswan/ipsec_rcv.h"
#include "libreswan/ipsec_sa.h"
#include "libreswan/ipsec_policy.h"
#include "libreswan/ipsec_proto.h"
#include "libreswan/ipsec_sysctl.h"
#include "pfkeyv2.h"
#include "pfkey.h"

int debug_tunnel;
int debug_eroute;
int debug_spi;
int debug_radij;
int debug_pfkey;
int debug_ah;
int debug_esp;
int debug_netlink;
int sysctl_ipsec_debug_verbose;
int sysctl_ipsec_debug_ipcomp;
int sysctl_ipsec_icmp;
int sysctl_ipsec_tos;
extern int debug_rcv;

struct prng ipsec_prng;

struct supported_list *pfkey_supported_list[SADB_SATYPE_MAX + 1];

bool should_i_fail(const char *func)
{
	return 0;
}

bool should_i_fail_once(const char *func)
{
	return 0;
}

#if 0
void sock_wfree(struct sk_buff *skb)
{
}

void sock_rfree(struct sk_buff *skb)
{
}
#endif

void *field_value(const void *strct, const char *name)
{
	return NULL;
}

void field_attach(const void *strct, const char *name, void *val)
{
}

void field_attach_static(const void *strct, const char *name, void *val)
{
}

void field_detach(const void *strct, const char *name)
{
}

void field_detach_all(const void *strct, const char *name)
{
}

int pfkey_list_insert_supported(struct ipsec_alg_supported *supported,
				struct supported_list **supported_list)
{
	return -1;
}

int pfkey_list_remove_supported(struct ipsec_alg_supported *supported,
				struct supported_list **supported_list)
{
	return -1;
}

int pfkey_register_reply(int satype, struct sadb_msg *sadb_msg)
{
	return 0;
}

#if 0
int netif_rx_count = 0;

int netif_rx(struct sk_buff *skb)
{
	netif_rx_count++;
	return 0;
}

void ipsec_print_ip(struct iphdr *ip)
{
	return;
}

struct net_device *ipsec_get_device(int inst)
{
	struct net_device *ipsec_dev;

	ipsec_dev = NULL;

	return ipsec_dev;
}

int pfkey_expire(struct ipsec_sa *sa, int time)
{
	return 1;
}

int pfkey_nat_t_new_mapping(struct ipsec_sa *sa, struct sockaddr *mapping,
			    __u16 port)
{
	return 1;
}

struct sk_buff *skb_decompress(struct sk_buff *skb)
{
	return skb;
}

struct sk_buff *skb_compress(struct sk_buff *skb)
{
	return skb;
}
#endif

void ipsec_SAtest(void)
{
	IPsecSAref_t SAref = 258;
	struct ipsec_sa ips;

	ips.ips_ref = 772;

	printk("klips_debug:ipsec_SAtest: "
	       "IPSEC_SA_REF_SUBTABLE_IDX_WIDTH=%u\n"
	       "IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES=%u\n"
	       "IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES=%u\n"
	       "IPSEC_SA_REF_HOST_FIELD_WIDTH=%lu\n"
	       "IPSEC_SA_REF_TABLE_MASK=%x\n"
	       "IPSEC_SA_REF_ENTRY_MASK=%x\n"
	       "IPsecSAref2table(%d)=%u\n"
	       "IPsecSAref2entry(%d)=%u\n"
	       "IPsecSAref2NFmark(%d)=%u\n"
	       "IPsecSAref2SA(%d)=%p\n"
	       "IPsecSA2SAref(%p)=%d\n"
	       ,
	       IPSEC_SA_REF_SUBTABLE_IDX_WIDTH,
	       IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES,
	       IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES,
	       (unsigned long) IPSEC_SA_REF_HOST_FIELD_WIDTH,
	       IPSEC_SA_REF_TABLE_MASK,
	       IPSEC_SA_REF_ENTRY_MASK,
	       SAref, IPsecSAref2table(SAref),
	       SAref, IPsecSAref2entry(SAref),
	       SAref, IPsecSAref2NFmark(SAref),
	       SAref, IPsecSAref2SA(SAref),
	       (&ips), IPsecSA2SAref((&ips))
	       );
	return;
}

int main(char *argv[], int argc)
{
	int error = 0;

	talloc_enable_leak_report_full();
	debug_xform = 1;

	ipsec_sadb_init();

	printf("test 0\n");
	{
		volatile IPsecSAref_t sa1, sa2;
		volatile unsigned int nf1;

		sa1 = 1;
		nf1 = IPsecSAref2NFmark(sa1);
		sa2 = NFmark2IPsecSAref(nf1);

		/* Test 0 - basic understanding of macros */
		printf("saref= %08x => nfmark= %08x\n",
		       sa1, nf1);

		printf("nfmark=%08x => saref=  %08x\n",
		       nf1, sa2);

		assert( sa1 == sa2 );
	}

	printf("test 1\n");
	/* Test 1 - allocate an SA and let it get a random SAref */
	{
		struct ipsec_sa *sa1;
		/* allocate a new SA */
		sa1 = ipsec_sa_alloc(&error);
		assert(error == 0);

		/* set it to NULL */
		sa1->ips_ref = IPSEC_SAREF_NULL;

		error = ipsec_sa_intern(sa1);
		assert(sa1->ips_ref != IPSEC_SAREF_NULL);

		ipsec_sa_put(sa1);
	}

	printf("test 2\n");
	/* Test 2 - allocate an SA and give it a known value */
	{
		struct ipsec_sa *sa2;
		/* allocate a new SA */
		sa2 = ipsec_sa_alloc(&error);
		assert(error == 0);

		sa2->ips_ref = 2727;

		error = ipsec_sa_intern(sa2);
		assert(sa2->ips_ref != IPSEC_SAREF_NULL);

		ipsec_sa_put(sa2);
	}

	printf("test 3\n");
	/* Test 2 - allocate an SA, and give it a known value twice */
	{
		struct ipsec_sa *sa1;
		struct ipsec_sa *sa2;
		/* allocate a new SA */
		sa2 = ipsec_sa_alloc(&error);
		assert(error == 0);

		sa2->ips_ref = 27;

		error = ipsec_sa_intern(sa2);
		assert(sa2->ips_ref != IPSEC_SAREF_NULL);

		/* allocate a new SA */
		sa1 = ipsec_sa_alloc(&error);
		assert(error == 0);

		/* set it to 27 */
		sa1->ips_ref = 27;

		error = ipsec_sa_intern(sa1);
		assert(sa1->ips_ref != IPSEC_SAREF_NULL);

		ipsec_sa_put(sa1);
		ipsec_sa_put(sa2);
	}

	printf("freeing things up\n");
	ipsec_sadb_cleanup(0); /* 0 = all protocols */
	ipsec_sadb_free();

	exit(0);
}

