/*
 * Copyright (c) 2002-2007 Endace Technology Ltd, Hamilton, New Zealand.
 * All rights reserved.
 *
 * This source code is proprietary to Endace Technology Limited and no part
 * of it may be redistributed, published or disclosed except as outlined in
 * the written contract supplied with this product.
 *
 * $Id: ipf_tests.c 15597 2012-03-28 22:21:32Z jomi.gregory $
 */

/* Documentation notes: 
 * --------------------
 *
 * The test cases and the test plan is documented int he IPF and HAT 
 * test plan. Each test case and test doesn't have an in code documentation.
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../../../include/dagcrc.h"
#include "../../../include/dagclarg.h"
#include "../../../include/dag_component.h"
#include "../../../include/dag_component_codes.h"
#include "../../../include/dagapi.h"
#include "../../../include/dagerf.h"
#include "../../../include/dag_config.h"
#include "ipf_tests.h"

/* Some constants */
#define PROT_ICMP (1)
#define PROT_TCP (6)
#define PROT_UDP (17)

#define TCP_FIN (0x01)
#define TCP_SYN (0x02)
#define TCP_RST (0x04)
#define TCP_PSH (0x08)
#define TCP_ACK (0x10)
#define TCP_URG (0x20)

/* Some IP macros to constract and extract the fields */
#define IP_ADDR_B0(x) (x & 0x0ff)
#define IP_ADDR_B1(x) ((x>>8) & 0x0ff)
#define IP_ADDR_B2(x) ((x>>16) & 0x0ff)
#define IP_ADDR_B3(x) ((x>>24) & 0x0ff)

#define IP_ADDR_BRK(x) IP_ADDR_B3(x), IP_ADDR_B2(x), IP_ADDR_B1(x), IP_ADDR_B0(x)

#define IP_ADDR_MAKE(a,b,c,d) (((a&0xff)<<24)|((b&0xff)<<16)|((c&0xff)<<8)|(d&0xff))


/* Command Line Arguments constants */
enum
{
	CLA_TESTCASE,
	CLA_TESTNUM,
	CLA_SYNTH
};

/* Structure to hold the information required by the tests */
typedef struct ipf_fields
{
	uint8_t  ifc;
	uint8_t  rectype;
	uint16_t rlen;
	uint16_t wlen;
	uint16_t colour;
	uint8_t  stream;
	uint8_t  hash;
	uint16_t etype;
	uint32_t src_ip;
	uint32_t dst_ip;
	uint16_t ip_prot;
	uint16_t src_port;
	uint16_t dst_port;
	uint8_t  tcp_flags;
	uint8_t  icmp_type;
	uint8_t  icmp_code;
} ipf_fields_t;

/* Internal Function prototypes */
int ipf_parse_rec(char *rec, int len, ipf_fields_t *flds);
void incr_counters(int res);
void load_hat_table(void);
uint32_t hlb_range_ui2reg(uint32_t ui_value);

int ipf_testcase1(int testnum, ipf_fields_t *flds, uint64_t rec_cnt);
int ipf_testcase2(int testnum, ipf_fields_t *flds, uint64_t rec_cnt);
int ipf_testcase3(int testnum, ipf_fields_t *flds, uint64_t rec_cnt);
int ipf_testcase4(int testnum, ipf_fields_t *flds, uint64_t rec_cnt);
int ipf_testcase5(int testnum, ipf_fields_t *flds, uint64_t rec_cnt);
int ipf_testcase6(int testnum, ipf_fields_t *flds, uint64_t rec_cnt);
int ipf_testcase7(int testnum, ipf_fields_t *flds, uint64_t rec_cnt);
int ipf_testcase8(int testnum, ipf_fields_t *flds, uint64_t rec_cnt);
int ipf_testcase9(int testnum, ipf_fields_t *flds, uint64_t rec_cnt);
int ipf_testcase10(int testnum, ipf_fields_t *flds, uint64_t rec_cnt);

/* Global variables for this test */
char rec_msg[MAX_STR_LEN];
int rec_msg_len = 0;

int testcase;
int testnum;

global_params_t settings;

/* Global counters for final reporting */
uint32_t ipf_total = 0;
uint32_t ipf_ignored = 0;
uint32_t ipf_failed = 0;
uint32_t ipf_passed = 0;
uint32_t ipf_warning = 0;
uint32_t ipf_unknown = 0;

int pkt_cap[MAX_IFC_CNT];

uint32_t hat_table[1024];

int synth_hat = 0;

/* And some configurations... */
test_printf pf;


/* Main initialization of the test.
 * Valid parameters are: 
 * -c <testcase> 
 * -t <testnum>
 */
int ipf_tests_init(char *params[], int param_cnt, global_params_t *global_params, test_printf f)
{

	ClArgPtr clarg = NULL;
	FILE* errorfile = NULL;
	int argindex = 0;
	int clarg_result = 0;
	int code = 0;
	int cnt;

	/* Have a local copy of the settings */
	memcpy(&settings, global_params, sizeof(settings));

	/* Set up the command line options. */
	clarg = dagclarg_init(param_cnt, (const char* const *) params);
	
	/* General options. */
	dagclarg_add_int(clarg, "Select test set", "--test_case", 'c', "n", &testcase, CLA_TESTCASE);
	dagclarg_add_int(clarg, "Select a test from the test set", "--test_num", 't', "n", &testnum, CLA_TESTNUM);
	dagclarg_add(clarg, "Use synthetic HAT Values", "--synth_hat", 's', CLA_SYNTH);

	/* Parse the command line options. */
	clarg_result = dagclarg_parse(clarg, errorfile, &argindex, &code);
	while (1 == clarg_result)
	{
		switch (code)
		{
		case CLA_TESTCASE:
		case CLA_TESTNUM:
			/* Do nothing */
			break;

		case CLA_SYNTH:
			synth_hat = 1;
			break;
			
		default:
			if (params[argindex][0] == '-')
			{
				/* Unknown option. */
				dagutil_error("unknown option %s\n", params[argindex]);
				/* print_usage(clarg);*/
				return TEST_FAIL;
			}
			break;
		}
		clarg_result = dagclarg_parse(clarg, errorfile, &argindex, &code);
	}

	/* Check for errors in the arguments */
	if (-1 == clarg_result)
	{
		if (argindex < param_cnt)
		{
			dagutil_error("while processing option %s\n", params[argindex]);
		}
		dagclarg_display_usage(clarg, stderr);
		return TEST_FAIL;
	}

	/* Initialize local variables */
	for (cnt=0; cnt<MAX_IFC_CNT; cnt++)
	{
		pkt_cap[cnt] = 0;
	}

	/* Initialize hash tables when we run tests that need it */
	if (testcase == 9)
	{
		dagcrc_make_aal5_table();
		load_hat_table();
	}

	return TEST_PASS;
}

/* This is the main test function.
 *
 * This function basically calls the correct function for testing
 * and increments the correct counters depending on the test result.
 *
 */
int ipf_tests_run(char *rec, int len, char* lastpkt, struct_protocol_t prot, uint64_t rec_cnt)
{

	ipf_fields_t flds;
	int ret_val;

	rec_msg_len = 0;

	/* Parse the record and verify that we have a correct record. */
	if ((ret_val = ipf_parse_rec(rec, len, &flds)) != TEST_PASS)
	{
		incr_counters(ret_val);
		return ret_val;
	}

	/* Select the correct test case and test to run, return the result */
	switch (testcase)
	{
	case 1:
		ret_val = ipf_testcase1(testnum, &flds, rec_cnt);
		incr_counters(ret_val);
		break;
	case 2:
		ret_val = ipf_testcase2(testnum, &flds, rec_cnt);
		incr_counters(ret_val);
		break;
	case 3:
		ret_val = ipf_testcase3(testnum, &flds, rec_cnt);
		incr_counters(ret_val);
		break;
	case 4:
		ret_val = ipf_testcase4(testnum, &flds, rec_cnt);
		incr_counters(ret_val);
		break;
	case 5:
		ret_val = ipf_testcase5(testnum, &flds, rec_cnt);
		incr_counters(ret_val);
		break;
	case 6:
		ret_val = ipf_testcase6(testnum, &flds, rec_cnt);
		incr_counters(ret_val);
		break;
	case 7:
		ret_val = ipf_testcase7(testnum, &flds, rec_cnt);
		incr_counters(ret_val);
		break;
	case 8:
		ret_val = ipf_testcase8(testnum, &flds, rec_cnt);
		incr_counters(ret_val);
		break;
	case 9:
		ret_val = ipf_testcase9(testnum, &flds, rec_cnt);
		incr_counters(ret_val);
		break;
	case 10:
		ret_val = ipf_testcase10(testnum, &flds, rec_cnt);
		incr_counters(ret_val);
		break;
	default:
		incr_counters(TEST_WARNING);
		return TEST_WARNING;
	}

	return ret_val;
}

int ipf_tests_err_msg(char *buf, int size)
{
    if (size > 0)
    {
	    strncpy(buf, rec_msg, size);
	    buf[size-1] = '\0'; /* Just in case the buffer was too short...*/
    }
	return TEST_PASS;
}

int ipf_tests_final_msg(char *buf, int size)
{
	char msg[MAX_STR_LEN];

	snprintf(msg, MAX_STR_LEN, 
		 "ipf: %d.%d pass %u\nipf: %d.%d fail %u\nipf: %d.%d warning %u\nipf: %d.%d ignore %u\n",
		 testcase, testnum, ipf_passed, 
		 testcase, testnum, ipf_failed, 
		 testcase, testnum, ipf_warning, 
		 testcase, testnum, ipf_ignored);

    if (size > 0)
    {
	    strncpy(buf, msg, size);
	    buf[size-1] = '\0';
    }

	/* Test will fail if we had failuirs captures or we didn't capture any packets */
	/* Test will have wanting if we idn't fail, but we encountered wanting during the test, or we ignored packets */
	/* Otherwise, we pass the test */
	if ((ipf_failed > 0) || (ipf_total == 0))
		return TEST_FAIL;
	else if ((ipf_warning > 0) || (ipf_ignored > 0))
		return TEST_WARNING;
	else
		return TEST_PASS;
}

int ipf_tests_cleanup()
{
	return TEST_PASS;
}

int ipf_tests_printf (char *format, ...)
{

	printf ("%s: %s - Test printf\n", __FILE__, __FUNCTION__);

	return TEST_PASS;
}

int ipf_testcase1(int testnum, ipf_fields_t *flds, uint64_t rec_cnt)
{
	int ret_val = TEST_PASS;
	int len_incr;

	switch(testnum)
	{
	case 1:
		if (flds->stream != 1)
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, "Stream recieved was not 0\n");
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		if (flds->ifc < MAX_IFC_CNT)
			pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		break;

	case 2:
		if (flds->stream != 2)
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, "Stream recieved was not 2\n");
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}		
		if (flds->ifc < MAX_IFC_CNT)
			pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		break;

	case 3:
		if (flds->stream != 3)
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, "Stream recieved was not 0 & 2\n");
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}		
		if (flds->ifc < MAX_IFC_CNT)
			pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		break;

	case 4:
		if (flds->ifc < MAX_IFC_CNT)
			pkt_cap[flds->ifc]++;
		len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, "Test recieved data.\n");
		rec_msg_len += len_incr;
		ret_val = TEST_FAIL;
		break;

	case 5:
		if (settings.ifc_cnt < 2)
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Test %d.%d is only for dual interface card.\n", testcase, testnum);
			rec_msg_len += len_incr;
			ret_val = TEST_WARNING;
		} 
		else
		{
			if ((flds->stream != 1) && (flds->ifc != 0))
			{
				len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
						    "Stream (%u) and interface (%u) do not match\n",
						    flds->stream, flds->ifc);
				rec_msg_len += len_incr;
				ret_val = TEST_WARNING;
			}		
			if (flds->ifc < MAX_IFC_CNT)
				pkt_cap[flds->ifc]++;
			else 
			{
				len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
						    "Interface reported was not valid (%u)\n", flds->ifc);
				rec_msg_len += len_incr;
				ret_val = TEST_FAIL;
			}
		}
		break;

	case 6:
		if (settings.ifc_cnt < 2)
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,
					    "Test %d.%d is only for dual interface card.\n", testcase, testnum);
			rec_msg_len += len_incr;
			ret_val = TEST_WARNING;
		} 
		else
		{
			if ((flds->stream != 2) && (flds->ifc != 0))
			{
				len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
						    "Stream (%u) and interface (%u) do not match\n",
						    flds->stream, flds->ifc);
				rec_msg_len += len_incr;
				ret_val = TEST_WARNING;
			}		
			if (flds->ifc < MAX_IFC_CNT)
				pkt_cap[flds->ifc]++;
			else 
			{
				len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
						    "Interface reported was not valid (%u)\n", flds->ifc);
				rec_msg_len += len_incr;
				ret_val = TEST_FAIL;
			}
		}
		break;

	case 7:
		if (settings.ifc_cnt < 2)
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,
					    "Test %d.%d is only for dual interface card.\n", testcase, testnum);
			rec_msg_len += len_incr;
			ret_val = TEST_WARNING;
		} 
		else
		{
			if ((flds->stream != 1) && (flds->ifc != 1))
			{
				len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
						    "Stream (%u) and interface (%u) do not match\n",
						    flds->stream, flds->ifc);
				rec_msg_len += len_incr;
				ret_val = TEST_WARNING;
			}		
			if (flds->ifc < MAX_IFC_CNT)
				pkt_cap[flds->ifc]++;
			else 
			{
				len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
						    "Interface reported was not valid (%u)\n", flds->ifc);
				rec_msg_len += len_incr;
				ret_val = TEST_FAIL;
			}
		}		
		break;

	case 8:
		if (settings.ifc_cnt < 2)
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,
					    "Test %d.%d is only for dual interface card.\n", testcase, testnum);
			rec_msg_len += len_incr;
			ret_val = TEST_WARNING;
		} 
		else
		{
			if ((flds->stream != 2) && (flds->ifc != 1))
			{
				len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
						    "Stream (%u) and interface (%u) do not match\n",
						    flds->stream, flds->ifc);
				rec_msg_len += len_incr;
				ret_val = TEST_WARNING;
			}		
			if (flds->ifc < MAX_IFC_CNT)
				pkt_cap[flds->ifc]++;
			else 
			{
				len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
						    "Interface reported was not valid (%u)\n", flds->ifc);
				rec_msg_len += len_incr;
				ret_val = TEST_FAIL;
			}
		}		
		break;

	default:
		len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Warning: Test case 1 recieved an unknown test\n");
		rec_msg_len += len_incr;
		return TEST_WARNING;
		break;

	}

	return ret_val;
}

int ipf_testcase2(int testnum, ipf_fields_t *flds, uint64_t rec_cnt)
{
	int len_incr = 0;

	len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, "Warning: IPF test case 2 is deprecated.\n");
	rec_msg_len += len_incr;
	
	return TEST_WARNING;
}

int ipf_testcase3(int testnum, ipf_fields_t *flds, uint64_t rec_cnt)
{
	int len_incr = 0;

	len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, "Warning: IPF test case 3 is deprecated.\n");
	rec_msg_len += len_incr;
	
	return TEST_WARNING;
}

int ipf_testcase4(int testnum, ipf_fields_t *flds, uint64_t rec_cnt)
{

	int ret_val = TEST_PASS;
	int len_incr;

	switch(testnum)
	{
	case 1:
		if (settings.ifc_cnt < 2)
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Test %d.%d is only for dual interface card.\n", testcase, testnum);
			rec_msg_len += len_incr;
			ret_val = TEST_WARNING;
		} 
		else
		{
			if (!(((flds->ifc == 0) && (flds->stream == 1) && (flds->colour == 130)) || 
			      ((flds->ifc == 1) && (flds->stream == 2) && (flds->colour == 200))))
			{
				len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
						    "Stream (%u), Interface (%u) and Colour (%u) do not match\n", 
						    flds->stream, flds->ifc, flds->colour);
				rec_msg_len += len_incr;
				ret_val = TEST_FAIL;
			}
			if (flds->ifc < MAX_IFC_CNT)
				pkt_cap[flds->ifc]++;
			else 
			{
				len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
						    "Interface reported was not valid (%u)\n", flds->ifc);
				rec_msg_len += len_incr;
				ret_val = TEST_FAIL;
			}
		}
		break;

	case 2:
		if (settings.ifc_cnt < 2)
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Test %d.%d is only for dual interface card.\n", testcase, testnum);
			rec_msg_len += len_incr;
			ret_val = TEST_WARNING;
		} 
		else
		{
			if (!(((flds->ifc == 0) && (flds->stream == 2) && (flds->colour == 130)) || 
			      ((flds->ifc == 1) && (flds->stream == 1) && (flds->colour == 200))))
			{
				len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
						    "Stream (%u), Interface (%u) and Colour (%u) do not match\n", 
						    flds->stream, flds->ifc, flds->colour);
				rec_msg_len += len_incr;
				ret_val = TEST_FAIL;
			}
			if (flds->ifc < MAX_IFC_CNT)
				pkt_cap[flds->ifc]++;
			else 
			{
				len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
						    "Interface reported was not valid (%u)\n", flds->ifc);
				rec_msg_len += len_incr;
				ret_val = TEST_FAIL;
			}
		}
		break;

	case 3:
		if (!(((flds->stream == 1) && (flds->colour == 16383) && (flds->ip_prot == PROT_TCP)) || 
		      ((flds->stream == 2) && (flds->colour == 8191) && (flds->ip_prot == PROT_UDP))))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u), IP Protocol (%u) and Colour (%u) do not match\n", 
					    flds->stream, flds->ip_prot, flds->colour);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		if (flds->ifc < MAX_IFC_CNT)
				pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		break;

	case 4:
		if (!(((flds->stream == 1) && ((flds->etype == 0x0800) || (flds->etype == 0x0021))) || 
		      ((flds->stream == 2) && (flds->etype != 0x0800) && (flds->etype != 0x0021))))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u) and Etyer-type (%u) do not match\n", 
					    flds->stream, flds->etype);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		if (flds->ifc < MAX_IFC_CNT)
				pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		break;

	case 5:
		if (!(((flds->stream == 1) && (flds-> colour == (flds->src_ip & 0xff)) && ((flds->src_ip >> 16) == (192<<8|128))) ||
		      ((flds->stream == 2) && (flds-> colour == (flds->src_ip & 0xff)) && ((flds->src_ip >> 16) != (192<<8|128)))))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u) Colour (%u) and Source IP Address (%u.%u.%u.%u) do not match\n", 
					    flds->stream, flds->colour, IP_ADDR_BRK(flds->src_ip));
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		if (flds->ifc < MAX_IFC_CNT)
				pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		break;

	case 6:
		if (!(((flds->stream == 1) && (flds-> colour == (flds->dst_ip & 0xff)) && ((flds->dst_ip >> 8) == (192<<16|128<<8|200))) ||
		      ((flds->stream == 2) && (flds-> colour == (flds->dst_ip & 0xff)) && ((flds->dst_ip >> 8) != (192<<16|128<<8|200)))))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u), Colour (%u) and Destination IP address (%u.%u.%u.%u) do not match\n", 
					    flds->stream, flds->colour, IP_ADDR_BRK(flds->dst_ip));
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		if (flds->ifc < MAX_IFC_CNT)
				pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		break;

	case 7:
                /* Check TCP Traffic */
		if ((flds->ip_prot == PROT_TCP) && 
		    (!((flds->colour >> 8) == 0) && 
		     ((flds->colour & 0xff) == (flds->src_port & 0xff)) &&
		     (((flds->stream == 1) && (flds->src_port < 1536)) ||
		      ((flds->stream == 2) && (flds->src_port >= 1536)))))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u), Colour (%u), IP Protocol (%u) and Source Port (%u) do not match\n", 
					    flds->stream, flds->colour, flds->ip_prot, flds->src_port);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		/* Check UDP Traffic */
		else if ((flds->ip_prot == PROT_UDP) && 
			 (!((flds->colour >> 8) == 1) && 
			  ((flds->colour & 0xff) == (flds->src_port & 0xff)) &&
			  (((flds->stream == 1) && (flds->src_port >= 2048)) ||
			   ((flds->stream == 2) && (flds->src_port < 2048)))))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u), Colour (%u), IP Protocol (%u) and Source Port (%u) do not match\n", 
					    flds->stream, flds->colour, flds->ip_prot, flds->src_port);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		else if ((flds->ip_prot != PROT_TCP) && (flds->ip_prot != PROT_UDP))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Protocol isn't correct (%d)\n", 
					    flds->ip_prot);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}

		if (flds->ifc < MAX_IFC_CNT)
				pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		break;

	case 8:
		/* Check TCP Traffic */
		if ((flds->ip_prot == PROT_TCP) && 
		    (!((flds->colour >> 8) == 1) && ((flds->colour & 0xff) == (flds->src_port & 0xff)) &&
		     (((flds->stream == 1) && (flds->src_port < 2816)) ||
		      ((flds->stream == 2) && (flds->src_port >= 2816)))))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u), Colour (%u), IP Protcol (%u) and Destination Port (%u) do not match\n", 
					    flds->stream, flds->colour, flds->ip_prot, flds->dst_port);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		/* Check UDP Traffic */
		else if ((flds->ip_prot == PROT_UDP) && 
			 (!((flds->colour >> 8) == 0) && ((flds->colour & 0xff) == (flds->src_port & 0xff)) &&
			  (((flds->stream == 1) && (flds->src_port >= 2560)) ||
			   ((flds->stream == 2) && (flds->src_port < 2560)))))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u), Colour (%u), IP Protcol (%u) and Destination Port (%u) do not match\n", 
					    flds->stream, flds->colour, flds->ip_prot, flds->dst_port);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		else if ((flds->ip_prot != PROT_TCP) && (flds->ip_prot != PROT_UDP))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Protocol isn't correct (%d)\n", 
					    flds->ip_prot);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}

		if (flds->ifc < MAX_IFC_CNT)
				pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		break;

	case 9:
		/* Check TCP Traffic */
		if ((flds->ip_prot == PROT_TCP) && 
		    (!(flds->colour == flds->tcp_flags) && 
		      (((flds->stream == 1) && ((flds->tcp_flags == 0) || (flds->tcp_flags & (TCP_RST | TCP_SYN | TCP_FIN)))) ||
		       ((flds->stream == 2) &&                            (flds->tcp_flags & (TCP_URG | TCP_ACK | TCP_PSH))))))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u), Colour (%u), IP Protocl (%u) and TCP Flags (%u) do not match\n", 
					    flds->stream, flds->colour, flds->ip_prot, flds->tcp_flags);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		else if (flds->ip_prot != PROT_TCP)
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Protocol isn't correct (%d)\n", 
					    flds->ip_prot);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		if (flds->ifc < MAX_IFC_CNT)
				pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		break;

	case 10:
		len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
				   "Warning: IPF test %d.%d is deprecated.\n", testcase, testnum);
		rec_msg_len += len_incr;
		ret_val = TEST_WARNING;
		break;

	default:
		len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Warning: Test case 1 recieved an unknown test\n");
		rec_msg_len += len_incr;
		return TEST_WARNING;
		break;

	}

	return ret_val;
}

int ipf_testcase5(int testnum, ipf_fields_t *flds, uint64_t rec_cnt)
{
	int ret_val = TEST_PASS;
	int len_incr;

	switch(testnum)
	{
	case 1:
		if (flds->stream != 1)
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, "Stream recieved was not 0\n");
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		if (flds->ifc < MAX_IFC_CNT)
			pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}		
		break;

	case 2:
	case 3:
	case 4:
		len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
				   "Warning: IPF test %d.%d is deprecated.\n", testcase, testnum);
		rec_msg_len += len_incr;
		ret_val = TEST_WARNING;

	default:
		len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
				    "Warning: Test case %d recieved an unknown test\n", 
				    testcase);
		rec_msg_len += len_incr;
		return TEST_WARNING;
		break;

	}

	return ret_val;
}

int ipf_testcase6(int testnum, ipf_fields_t *flds, uint64_t rec_cnt)
{
	int ret_val = TEST_PASS;
	int len_incr;

	switch(testnum)
	{
	case 1:
		if (!((flds->stream == 1) && (flds->colour == 8091) && (flds->ip_prot == PROT_TCP)))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u), Colour (%u) and IP Protocol (%u) do not match\n",
					    flds->stream, flds->colour, flds->ip_prot);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		if (flds->ifc < MAX_IFC_CNT)
			pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}		
		break;

	case 2:
		if (!((flds->stream == 1) && (flds->colour == 1) && (flds->ip_prot == PROT_TCP) &&
		      (flds->src_ip == IP_ADDR_MAKE(192,128,253,129)) && (flds->src_port == 1024) &&
		      (flds->dst_ip == IP_ADDR_MAKE(192,128,201,128)) && (flds->dst_port == 2000)))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u), Colour (%u) and IP Protocol (%u) do not match\n",
					    flds->stream, flds->colour, flds->ip_prot);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		if (flds->ifc < MAX_IFC_CNT)
			pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}		
		break;

	case 3:
		if (!((flds->stream == 1) && (flds->colour == 1)) && (flds->ip_prot == PROT_TCP))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u), Colour (%u) and IP Protocol (%u) do not match\n",
					    flds->stream, flds->colour, flds->ip_prot);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		else if (!((flds->stream == 2) && (flds->colour == 1)) && (flds->ip_prot == PROT_UDP))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u), Colour (%u) and IP Protocol (%u) do not match\n",
					    flds->stream, flds->colour, flds->ip_prot);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		else if ((flds->ip_prot != PROT_TCP) && (flds->ip_prot != PROT_UDP))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Protocol isn't correct (%d)\n", 
					    flds->ip_prot);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}

		if (flds->ifc < MAX_IFC_CNT)
			pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}		
		break;

	default:
		len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,
				    "Warning: Test case %d recieved an unknown test\n", 
				    testcase);
		rec_msg_len += len_incr;
		return TEST_WARNING;
		break;

	}

	return ret_val;
}

int ipf_testcase7(int testnum, ipf_fields_t *flds, uint64_t rec_cnt)
{
	int ret_val = TEST_PASS;
	int len_incr;

	switch(testnum)
	{
	case 1:
		if (!((flds->stream == 1) && ((flds->rectype == ERF_TYPE_HDLC_POS) || (flds->rectype == ERF_TYPE_ETH))))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u), and ERF Type (%u) do not match\n",
					    flds->stream, flds->rectype);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		if (flds->ifc < MAX_IFC_CNT)
			pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}		
		break;

	case 2:
		if (!((flds->stream == 1) && ((flds->rectype == ERF_TYPE_COLOR_HDLC_POS) || (flds->rectype == ERF_TYPE_COLOR_ETH))))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u), and ERF Type (%u) do not match\n",
					    flds->stream, flds->rectype);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		if (flds->ifc < MAX_IFC_CNT)
			pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}		
		break;

	case 3:
		if (!((flds->stream == 1) && ((flds->rectype == ERF_TYPE_COLOR_HASH_POS) || (flds->rectype == ERF_TYPE_COLOR_HASH_ETH))))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Stream (%u), and ERF Type (%u) do not match\n",
					    flds->stream, flds->rectype);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		if (flds->ifc < MAX_IFC_CNT)
			pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}		
		break;

	case 4:
		ret_val = ipf_testcase6(1, flds, rec_cnt);
		break;

	default:
		len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,
				    "Warning: Test case %d recieved an unknown test\n", 
				    testcase);
		rec_msg_len += len_incr;
		return TEST_WARNING;
		break;

	}

	return ret_val;
}

int ipf_testcase8(int testnum, ipf_fields_t *flds, uint64_t rec_cnt)
{
	int ret_val = TEST_PASS;
	int len_incr;

	switch(testnum)
	{
	case 1:
	case 2:
		if (!((flds->colour == (flds->src_port & 0x03ff)) && ((flds->ip_prot == PROT_TCP) || (flds->ip_prot == PROT_UDP))))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Colour (%u), IP Protoocl (%u) and Source Port (%u) do not match\n",
					    flds->colour, flds->ip_prot, flds->src_port);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		if (flds->ifc < MAX_IFC_CNT)
			pkt_cap[flds->ifc]++;
		else 
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "Interface reported was not valid (%u)\n", flds->ifc);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}		
		break;

	default:
		len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,
				    "Warning: Test case %d recieved an unknown test\n", 
				    testcase);
		rec_msg_len += len_incr;
		return TEST_WARNING;
		break;

	}

	return ret_val;
}

int ipf_testcase9(int testnum, ipf_fields_t *flds, uint64_t rec_cnt)
{
	int ret_val = TEST_PASS;
	int len_incr;
	uint32_t ports;
	uint32_t val_for_crc, crc_res;
	int check = 1;

	if ((flds->rectype != ERF_TYPE_COLOR_HASH_POS) && (flds->rectype != ERF_TYPE_COLOR_HASH_ETH))
	{
		len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, "Test not supported for ERF Type (%d).\n", flds->rectype);
		rec_msg_len += len_incr;
		ret_val = TEST_IGNORE;
	}
	else
	{
		ports = (uint32_t) ((flds->src_port << 16 ) | flds->dst_port);
		// printf("ports = 0x%x\n", ports);

		switch(testnum)
		{
		case 1: /* 2-tuple */
		case 8:
			val_for_crc = flds->src_ip ^ flds->dst_ip;
			break;
		case 2: /* 3-tuple */
		case 6:
			val_for_crc = flds->src_ip ^ flds->dst_ip ^ flds->ip_prot;
			break;
		case 3: /* 4-tuple */
			val_for_crc = flds->src_ip ^ flds->dst_ip ^ flds->ip_prot ^ flds->ifc;
			break;
		case 4: /* 5-tuple */
		case 7:
			if ((flds->ip_prot != PROT_TCP) && (flds->ip_prot != PROT_UDP))
				check = 0;
			val_for_crc = flds->src_ip ^ flds->dst_ip ^ flds->ip_prot ^ ports;
			break;
		case 5: /* 6-tuple */
			if ((flds->ip_prot != PROT_TCP) && (flds->ip_prot != PROT_UDP))
				check = 0;
			val_for_crc = flds->src_ip ^ flds->dst_ip ^ flds->ip_prot ^ flds->ifc ^ ports;
			break;
			
		default:
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,
					    "Warning: Test case %d recieved an unknown test\n", 
					    testcase);
			rec_msg_len += len_incr;
			return TEST_WARNING;
			break;
			
		}
		
		val_for_crc = bswap_32(val_for_crc);

		crc_res = dagcrc_aal5_crc( CRC_INIT, (char*)&val_for_crc, 4);
		if (check && (hat_table[crc_res & 0x03ff] != flds->hash))
		{
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
					    "HASH and CRC Do not match. (Hash %d, CRC %d, HAT %d)\n",
					    flds->hash, crc_res & 0x03ff, hat_table[crc_res & 0x03ff]);
			rec_msg_len += len_incr;
			ret_val = TEST_FAIL;
		}
		else if (!check)
		{
			printf("check = %d, ip_prot = %d \n", check, flds->ip_prot);
			len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,
					    "5-tuple isn't supported for this IP Protocol (%d)\n", 
					    flds->ip_prot);
			rec_msg_len += len_incr;
			return TEST_WARNING;
		} 
	}

	return ret_val;
}

int ipf_testcase10(int testnum, ipf_fields_t *flds, uint64_t rec_cnt)
{
	int ret_val = TEST_PASS;
	int len_incr;

	if (flds->ip_prot != PROT_TCP)
	{
		len_incr = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, 
				    "IP Protocol captured is not TCP (Got %d)\n",
				    flds->ip_prot);
		rec_msg_len += len_incr;
		ret_val = TEST_FAIL;
	}
	return ret_val;
}

void incr_counters(int res)
{
	switch (res)
	{
	case TEST_PASS:
		ipf_passed++;
		break;

	case TEST_IGNORE:
		ipf_ignored++;
		break;

	case TEST_FAIL:
		ipf_failed++;
		break;
		
	case TEST_WARNING:
		ipf_warning++;
		break;

	default:
		ipf_unknown++;
		break;
	}
}

int  ipf_parse_rec(char *rec, int len, ipf_fields_t *flds)
{
	dag_record_t* drec = (dag_record_t*) rec;
	uint32_t tmp;
	uint16_t color;
	uint16_t stream = 0;
	uint16_t hash = 0;
	uint16_t etype;
	uint8_t  ihl;
	uint8_t *pload;
	uint8_t *tp;
	
	/* We don't handle legacy records, so we ignore them and report that... */
	if (dagerf_is_legacy_type((uint8_t*) rec))
	{
		ipf_ignored++;
		return TEST_IGNORE;
	} 
	
	/* If it's not legacy record than it's modern and we continue... */
	/* We also need at least 20 Bytes to extract the ether-type */
	if (len < 20)
		return TEST_IGNORE;
	else
		len -= 20;

	switch (drec->type) {
	case ERF_TYPE_HDLC_POS:
	case ERF_TYPE_COLOR_HDLC_POS:
	case ERF_TYPE_COLOR_HASH_POS:
		if (drec->type == ERF_TYPE_COLOR_HDLC_POS)
		{
			color = ntohs(drec->lctr);
			stream = color & 0x03;
			color = color >> 2;
			tmp = ntohl(drec->rec.pos.hdlc);
			etype = (uint16_t) (tmp & 0xffff);
		} 
		else if (drec->type == ERF_TYPE_COLOR_HASH_POS)
		{
			color = ntohs(drec->lctr);
			hash = color & 0x0f;
			color = color >> 4;
			tmp = ntohl(drec->rec.pos.hdlc);
			etype = (uint16_t) (tmp & 0xffff);
		} 
		else 
		{
			tmp = ntohl(drec->rec.pos.hdlc);
			color = (uint16_t) ((tmp>>16) & 0xffff);
			stream = color & 0x03;
			color = color >> 2;
			etype = (uint16_t) (tmp & 0xffff);
		}
		flds->ifc = drec->flags.iface;
		flds->rectype = drec->type;
		flds->rlen = ntohs(drec->rlen);
		flds->wlen = ntohs(drec->wlen);
		flds->colour = color;
		flds->stream = stream;
		flds->hash = hash;
		flds->etype = etype;
		
		/* Make sure the payload points to the IP header */
		pload = drec->rec.pos.pload;

		break;
		
	case ERF_TYPE_ETH:
	case ERF_TYPE_COLOR_ETH:
	case ERF_TYPE_COLOR_HASH_ETH:
		if (drec->type == ERF_TYPE_COLOR_ETH)
		{
			color = ntohs(drec->lctr);
			stream = color & 0x03;
			color = color >> 2;
			etype = ntohs(drec->rec.eth.etype);
		} 
		else if (drec->type == ERF_TYPE_COLOR_HASH_ETH)
		{
			color = ntohs(drec->lctr);
			hash = color & 0x0f;
			color = color >> 4;
			etype = ntohs(drec->rec.eth.etype);
		} 
		else 
		{
			tp = &(drec->rec.eth.offset);
			color = ntohs(*(uint16_t*)tp);
			stream = color & 0x03;
			color = color >> 2;
			etype = ntohs(drec->rec.eth.etype);
		}
		pload = drec->rec.eth.pload - 2; /* We want to point to the VLAN label in case we're Q-in-Q */
		while (etype == 0x8100) /* Skip VLAN Tags */
		{
			pload += 4; /* Skip this VLAN */
			etype = ntohs(*pload);
		}
		pload += 2; /* Now we're 2 bytes behind, so we need to atch up */

		flds->ifc = drec->flags.iface;
		flds->rectype = drec->type;
		flds->rlen = ntohs(drec->rlen);
		flds->wlen = ntohs(drec->wlen);
		flds->colour = color;
		flds->stream = stream;
		flds->hash = hash;
		flds->etype = etype;
		break;
		
	default:
		ipf_ignored++;
		return TEST_IGNORE;

	}

	/* We need at least 20 bytes for IP header */
	if (len < 20)
		return TEST_IGNORE;

	if ((etype == 0x0800) || (etype == 0x0021)) /* IP v4 */
	{
		ihl = ((uint8_t) pload[0]) & 0x0f;
		flds->ip_prot = pload[9];
		flds->src_ip = IP_ADDR_MAKE(pload[12], pload[13], pload[14], pload[15]);
		flds->dst_ip = IP_ADDR_MAKE(pload[16], pload[17], pload[18], pload[19]);
		
		len -= 4*ihl;

		pload = pload + 4*ihl;
		if (flds->ip_prot == 1) /* ICMP */
		{
			if (len < 2)
				return TEST_IGNORE;
			flds->icmp_type = pload[0];
			flds->icmp_code = pload[1];
		}
		else if (flds->ip_prot == 6)  /* TCP */
		{
			if (len < 13)
				return TEST_IGNORE;
			flds->src_port = (uint16_t) (pload[0] << 8 | pload[1]);
			flds->dst_port = (uint16_t) (pload[2] << 8 | pload[3]);
			flds->tcp_flags = pload[13];
		}
		else if (flds->ip_prot == 17)  /* UDP */
		{
			if (len < 4)
				return TEST_IGNORE;
			flds->src_port = (uint16_t) (pload[0] << 8 | pload[1]);
			flds->dst_port = (uint16_t) (pload[2] << 8 | pload[3]);
		}
	}
	
	return TEST_PASS;
}

void load_hat_table(void)
{
	dag_component_t root;
	dag_component_t hat = NULL;
	dag_card_ref_t dag_ref = NULL;
	attr_uuid_t attr = 0;
	hat_range_t *hlb_range;

	uint32_t idx, range, start, end;

	memset(hat_table, -1, sizeof(hat_table));

	if (!synth_hat)
	{
		if (NULL == (dag_ref = dag_config_init(settings.dagname)))
		{
			dagutil_panic("Cannot find a the card %s. This test cannot run when checking a file.\n", settings.dagname);
		}
		if (!(root = dag_config_get_root_component(dag_ref)))
		{
			dagutil_panic("Cannot get root component.\n");
		}
		if (!(hat = dag_component_get_subcomponent(root, kComponentHAT, 0)))
		{
			dagutil_panic("Cannot find a HAT component.\n");
		}
		if (!(attr = dag_component_get_attribute_uuid(hat, kStructAttributeHATRange)))
		{
			dagutil_panic("Cannot get HAT Range attribute\n");
		}
		if (kDagErrNone != dag_config_get_struct_attribute(dag_ref, attr, (void *) &hlb_range))
		{
			dagutil_panic("Cannot read HLB Table from cartd\n");
		}
		/* We don'tneed to check for invalid ranges because we don't
		   expect the API to return them */
		for(range=0; range<hlb_range->bin_num; range++)
		{
			start = hlb_range_ui2reg(hlb_range->bin_range[range].min);
			end = hlb_range_ui2reg(hlb_range->bin_range[range].max);
			for (idx = start; idx < end; idx++)
			{
				hat_table[idx] = (range + 1);
				if (hat_table[idx] == 16)
					hat_table[idx] = 0;
				// printf("HAT[%d] = %d\n", idx, hat_table[idx]);
			}
		}
		/* Here we should dispose of the card reference... */
		dag_config_dispose(dag_ref);
	}
	else
	{
		printf("Filling up HAT table with synthetic payload\n");
		for (idx=0; idx<512; idx++)
		{
			hat_table[idx*2] = (idx & 0x0f);
			hat_table[idx*2+1] = (idx & 0x0f);
		}
		for (idx=0; idx<1024; idx++)
		{

			printf("HAT[%d] = %d\n", idx, hat_table[idx]);
		}
	}
}

uint32_t hlb_range_ui2reg(uint32_t ui_value)
{
	uint32_t ret_val;
	if(ui_value==999)
		return 1023;
	ret_val = ui_value*1024/1000;
		return ret_val;	
}
