/*
 * Copyright (c) 2002-2008 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: ipfv2_filter_tests.c 15597 2012-03-28 22:21:32Z jomi.gregory $
 */

/* Documentation notes: 
 * --------------------
 *
 * This file contains the implemetation to test  ipfv2 filtering.
 *
 */

#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 "ipfv2_filter_tests.h"

#include "dagcam/infiniband_proto.h"
#include "../../../lib/dagcam/ipf_v2_parse.h"

/* Some constants */
#define IPF_TEST_MAX_RULES 128
#define FILENAME_BYTES 256
static char uInfileBuf[FILENAME_BYTES] = "";





/* Command Line Arguments constants */
enum
{
    CLA_TESTCASE,
    CLA_TESTNUM,
    CLA_INPUT_FILE
};
//#define IPFV2_FILTER_TEST_DEBUG
#ifdef IPFV2_FILTER_TEST_DEBUG
#define DEBUG_OUT  stdout
#endif

/* IPv6 Extension header values */
#define HOPOPT_EXT_HEADER		0	
#define ROUTE_EXT_HEADER		43
#define FRAG_EXT_HEADER			44
#define AUTH_EXT_HEADER			51
#define ESP_EXT_HEADER			50
#define OPTS_EXT_HEADER			60

/* internal representation of the filter rules */


uint32_t filter_rules_count  = 0;
static ipf_v2_filter_rule_t ipfv2_filter_test_rules[IPF_TEST_MAX_RULES];
static uint8_t is_valid_rule[IPF_TEST_MAX_RULES] = {0};
/* Internal Function prototypes */
void incr_counters(int res);

/* Functions to parse the filter rules */
static int ipfv2_filter_test_parse_rules(const char* filter_rule_filename);

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


global_params_t settings;

/* Global counters for final reporting */
static uint32_t ipfv2_filter_total = 0;
static uint32_t ipfv2_filter_ignored = 0;
static uint32_t ipfv2_filter_failed = 0;
static uint32_t ipfv2_filter_passed = 0;
static uint32_t ipfv2_filter_warning = 0;
static uint32_t ipfv2_filter_unknown = 0;

static int pkt_cap[MAX_IFC_CNT];

typedef struct ipfv2_header_ptrs_struct_s
{
    uint8_t *ip_header_ptr;
    uint8_t *tcp_udp_header_ptr;
    int     erf_type;
    uint8_t ip_protocol ; /* to distinguish tcp / udp */
    
}ipfv2_header_ptrs_struct_t;

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

/* static functions declaration */
static int ipfv2_filter_tests_validate_match(const char* const in_rec, const int len,const  ipf_v2_filter_rule_t* const matched_rule );
static int ipfv2_filter_test_verify_mpls_vlan( const char* const in_rec, int len, ipfv2_header_ptrs_struct_t *in_header_ptr, ipf_v2_filter_rule_t const* in_rule);
static int ipfv2_filter_test_parse_verify_ip_header( ipfv2_header_ptrs_struct_t *in_header_ptr, /* int rem_len ,*/ ipf_v2_filter_rule_t const* in_rule) ;
static int ipfv2_filter_test_parse_verify_transport_header( ipfv2_header_ptrs_struct_t *in_header_ptr, /* int rem_len ,*/ ipf_v2_filter_rule_t const* in_rule);

/* taking the loss counter filed */
static inline uint32_t ipfv2_filter_test_get_color(char *erf_header, int len)
{
#if 0
    dag_record_t* drec = (dag_record_t *) erf_header;
    return ntohs(drec->lctr);
#endif
    uint64_t hdr;
    uint8_t  hdr_type;
    uint32_t hdr_num;
    int len_print = 0;

    /* TODO sanity checks on len*/
  
    /* loop over the extension headers */
    hdr_num = 0;
    do {
    
        /* get the header type */
        hdr_type = erf_header[(8 + (hdr_num * 8))];

        /* get the header value */
        hdr = *((uint64_t*) (&erf_header[(8 + (hdr_num * 8))]));
        hdr = bswap_64(hdr);

        hdr_num++;

        /* display the header */
        switch ( hdr_type & 0x7F )
        {
            case EXT_HDR_TYPE_BFS:
#ifdef IPFV2_FILTER_TEST_DEBUG
        fprintf(DEBUG_OUT, "%s: %u Color frm ExtHdrs: %u\n", __FUNCTION__, __LINE__, (uint32_t)((hdr >> 32) & 0x03fff));
#endif 
                return (uint32_t)((hdr >> 32) & 0x03fff);
            default:
                break;
        }
    } while ( hdr_type & 0x80 );
    len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, "Could not locate BFS ext header\n");
    rec_msg_len += len_print;
    return IPF_TEST_MAX_RULES;
}

/* to get the matching rule for a given color.*/
/* for the time being, we store the rules indexed by their color */
/* thus putting an allowed range on the colors allowed */
static inline uint32_t get_matched_rule_index(uint32_t color)
{
    if ( color >=  IPF_TEST_MAX_RULES )
    {
         len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, "Color(%u) not in allowed range\n", color);
        rec_msg_len += len_print;
        return IPF_TEST_MAX_RULES;
    }
    if ( !is_valid_rule[color] )
    {
        len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len, "Color(%u) not in the rule file\n", color);
        rec_msg_len += len_print;
        return IPF_TEST_MAX_RULES;
    }
    return color;
}




int ipfv2_filter_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;
    int retval = 0;

    /* 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_string(clarg, "Name of a text file containing one filter per line.", "--infile", 'i', "filename", uInfileBuf, FILENAME_BYTES, CLA_INPUT_FILE);
    /* 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_INPUT_FILE:
            /*What to do? */
            break;
        default:
            if (params[argindex][0] == '-')
            {
                /* Unknown option. */
                dagutil_error("unknown option %s\n", params[argindex]);
                /* print_usage(clarg);*/
                return EXIT_FAILURE;
            }
            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;
    }
    
    /* parse and store the rules in internal structure*/
    retval = ipfv2_filter_test_parse_rules(uInfileBuf/*params to decide */);

    return retval;
}

/* 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 ipfv2_filter_tests_run(char *rec, int len, char* lastpkt, struct_protocol_t prot, uint64_t rec_cnt)
{

    int ret_val = TEST_PASS;
    rec_msg_len = 0;
    uint32_t incoming_color = IPF_TEST_MAX_RULES;/* initializing */
    uint32_t matched_rule_index = IPF_TEST_MAX_RULES; /* initializing */

    /*Get the color of the incoming packet  */
    incoming_color = ipfv2_filter_test_get_color(rec, len );
    matched_rule_index  = get_matched_rule_index(incoming_color);
    if ( matched_rule_index >=  IPF_TEST_MAX_RULES )
    {
        /* message must have been printed already */
        incr_counters(TEST_FAIL);
        return TEST_FAIL;
    }
#ifdef IPFV2_FILTER_TEST_DEBUG
        fprintf(DEBUG_OUT, "%s: %u Color: %u\n", __FUNCTION__, __LINE__, incoming_color);
#endif 
    ret_val = ipfv2_filter_tests_validate_match(rec, len,&ipfv2_filter_test_rules[incoming_color]); 
    incr_counters(ret_val);
    return ret_val;
}

int ipfv2_filter_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 ipfv2_filter_tests_final_msg(char *buf, int size)
{
    char msg[MAX_STR_LEN];

    snprintf(msg, MAX_STR_LEN, "IPFv2 filter:\n \tpass %u\n \tfail %u\n \twarning %u\n \tignore %u\n", ipfv2_filter_passed,ipfv2_filter_failed, ipfv2_filter_warning,ipfv2_filter_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 ((ipfv2_filter_failed > 0) || (ipfv2_filter_total == 0))
        return TEST_FAIL;
    else if ((ipfv2_filter_warning > 0) || (ipfv2_filter_ignored > 0))
        return TEST_WARNING;
    else
        return TEST_PASS;
}

int ipfv2_filter_tests_cleanup()
{
    return TEST_PASS;
}

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

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

    return TEST_PASS;
}


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

    case TEST_IGNORE:
        ipfv2_filter_ignored++;
        break;

    case TEST_FAIL:
        ipfv2_filter_failed++;
        break;
        
    case TEST_WARNING:
        ipfv2_filter_warning++;
        break;

    default:
        ipfv2_filter_unknown++;
        break;
    }
}


int ipfv2_filter_test_parse_rules(const char* filter_rule_filename)
{
    int retval = 0;
    FILE * fin;
    
    memset(&ipfv2_filter_test_rules, 0, IPF_TEST_MAX_RULES * sizeof(ipf_v2_filter_rule_t));

    fin = fopen(filter_rule_filename,"r");
    if( fin == NULL )
    {
        printf("File is missing or no access\n");
        return -1;
    }
    ipf_v2restart(fin);
    while(1)
    {
        retval = ipf_v2lex();
        if(retval == T_RULE_DONE)
        {
            filter_rules_count ++;
            
        if (filter_rules_count > IPF_TEST_MAX_RULES )
        {
            filter_rules_count = IPF_TEST_MAX_RULES ;
            printf("Warning. Only %d Rules are taken\n", filter_rules_count);
            break;
        }
        }
        else if (retval == T_RULE_CONTINUE)
        {
            printf("This state is unused please contact suppot@endace.com \
 and send the rule file used and this line print out. retval: %d rules_count:%d\n",retval,filter_rules_count);
        }
        else if ( retval < 0 )
        {
            printf(" errors flex returns: %d at rule: %d\n",retval,filter_rules_count);
            break;
        }
        else if (retval == 0)
        {
            break;
            
        } else {
            printf("Unknown state please contact suppot@endace.com \
 and send the rule file used and this line print out. retval: %d rules_count:%d\n",retval,filter_rules_count);
        }
        /* check the color ( user tag) is within max allowed by the test */
        if(ipf_v2_filter_rule.user_tag >= IPF_TEST_MAX_RULES)
        {
            printf("Error. Invalid Color(%u). Allowed color values are 0 - %u\n",ipf_v2_filter_rule.user_tag, (IPF_TEST_MAX_RULES -1) );
            return TEST_FAIL;
        }
        memcpy( &ipfv2_filter_test_rules[ipf_v2_filter_rule.user_tag],&ipf_v2_filter_rule,sizeof(ipf_v2_filter_rule) );
        is_valid_rule[ipf_v2_filter_rule.user_tag] = 1;
        memset( &ipf_v2_filter_rule, 0, sizeof (ipf_v2_filter_rule));
    } 
    /* clean up */
    fclose(fin);
    if ( retval < 0 )
        return TEST_FAIL;
    /* complete */
    printf("Ruleset file parsed successifully, %d rules have been created.\n", filter_rules_count);
    return TEST_PASS;
}
int ipfv2_filter_tests_validate_match(const char* const in_rec, const int len,const  ipf_v2_filter_rule_t* const matched_rule )
{
    /* to parse and store different protocol start pointers */
    ipfv2_header_ptrs_struct_t parse_res_struct = {NULL,NULL,0,0};
    
    /* flags for checking whether  layer's fields are needs to be verified */
    uint8_t is_l3_0_verification_needed = ( (matched_rule->dst_ip.mask != 0) ||
                                            (matched_rule->src_ip.mask != 0) ||
                                            (matched_rule->ip_prot.mask != 0) );
    uint8_t is_l4_0_verification_needed = ( (matched_rule->src_port.mask != 0) ||
                                            (matched_rule->dst_port.mask != 0) ||
                                            (matched_rule->tcp_flags.mask != 0) );
   
    if ( (matched_rule->iface.mask & ((dag_record_t*)in_rec)->flags.iface) != matched_rule->iface.data)
    {
        /* intrface   is given in the rule, but doesn't match with the rule */
        len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u iface did not match \n",matched_rule->user_tag);
        rec_msg_len += len_print;
        return TEST_FAIL;
    }
    if ( TEST_FAIL == ipfv2_filter_test_verify_mpls_vlan(in_rec, len, &parse_res_struct, matched_rule) )
    {
        return TEST_FAIL;
    }
    
    /* now parse and validate IP header onwards */
    if (  (is_l3_0_verification_needed || is_l4_0_verification_needed) )
    {
        if (parse_res_struct.ip_header_ptr == NULL )
        {
            /* the rule has ip / tcp/udp fields, but pakt does not seem to hv an IP header */
            len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u Could not find IP header to verify IP fields \n",matched_rule->user_tag);
            rec_msg_len += len_print;
            return TEST_FAIL;
        }
        else if ( TEST_FAIL == ipfv2_filter_test_parse_verify_ip_header(&parse_res_struct, matched_rule) )
        {
            return TEST_FAIL;
        }
    }
    if ( is_l4_0_verification_needed  )
    {
        if ( parse_res_struct.tcp_udp_header_ptr == NULL )
        {
            /* the rule has  tcp/udp fields, but pakt does not seem to hv found a transport hdr */
            len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u Could not find TCP  header to verify  fields \n",matched_rule->user_tag);
            rec_msg_len += len_print;
            return TEST_FAIL;
        }
        else if ( TEST_FAIL == ipfv2_filter_test_parse_verify_transport_header(&parse_res_struct, matched_rule) )
        {
            return TEST_FAIL;
        }
    }
    
    return TEST_PASS;
}

int ipfv2_filter_test_verify_mpls_vlan( const char* const in_rec, int len, ipfv2_header_ptrs_struct_t *in_header_ptr, ipf_v2_filter_rule_t const* in_rule)
{
    dag_record_t* drec = (dag_record_t *) in_rec;
    uint32_t ext_headers_count = 0;
    uint32_t erf_rlen = ntohs(drec->rlen);
    in_header_ptr->erf_type = (drec->type & 0x7F);
    /* skip  past extn headers */
    ext_headers_count = dagerf_ext_header_count ((uint8_t*) in_rec, erf_rlen);
    drec =  (dag_record_t*) ((uintptr_t)drec + (ext_headers_count * 8)) ;
    switch ( in_header_ptr->erf_type )
    {
        case ERF_TYPE_HDLC_POS:
        case ERF_TYPE_COLOR_HDLC_POS:
        case ERF_TYPE_COLOR_HASH_POS:
        case ERF_TYPE_DSM_COLOR_HDLC_POS:
        {
            unsigned int hdlc = ntohl(drec->rec.pos.hdlc);
            uint16_t    temp_eth_type = hdlc & 0xffff;
            /* We can get the l2 proto here. So verify it first, before going furthur */
            if ( (in_rule->l2_proto.mask & temp_eth_type) != in_rule->l2_proto.data)
            {
                /* l2 proto is given in the rule, but doesn't match with the rule */
                len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u L2 proto did not match \n",in_rule->user_tag);
                rec_msg_len += len_print;
                return TEST_FAIL;
            }
            /* Check for MPLS */
            if ( hdlc == 0xFF030281 || hdlc == 0xFF030283 || hdlc == 0x0F008847 || hdlc == 0x0F008848 )
            {
                uint32_t* overlay32 = (uint32_t*) drec->rec.pos.pload;
                uint32_t  mpls_value = 0;
                uint32_t  mpls_index = 0;
                uint32_t  temp_mpls_top = 0;
                
                /* Jump over MPLS Shim headers */
                if ( erf_rlen > 4 )
                {
                    do 
                    {
                        mpls_value = ntohl (overlay32[mpls_index]);
                        if ( mpls_index == 0 ) temp_mpls_top = mpls_value;
                        mpls_index++;
                        erf_rlen -= 4;
    
                    } while ( ((mpls_value & 0x00000100) == 0) && (erf_rlen > 4) );
                }
#ifdef IPFV2_FILTER_TEST_DEBUG
                fprintf(DEBUG_OUT, "%s: %u MPLScount: %u top %u bottom %u\n", __FUNCTION__, __LINE__, mpls_index,temp_mpls_top, mpls_value );
#endif 
                /* validate mpls top and bottom */
                if (  (in_rule->mpls_top.mask & temp_mpls_top) != in_rule->mpls_top.data) 
                {
                    len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u MPLS TOP did not match \n",in_rule->user_tag);
                    rec_msg_len += len_print;
                    return TEST_FAIL;
                } 
                if ( (mpls_index > 1) &&  ((in_rule->mpls_bottom.mask & mpls_value ) != in_rule->mpls_bottom.data) )
                {
                    len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u MPLS BTM did not match \n", in_rule->user_tag);
                    rec_msg_len += len_print;
                    return TEST_FAIL;
                }
                /* validate label cnt field  - for mpls max is 7*/
                if ( mpls_index > 7) mpls_index = 7;
                if (  (in_rule->label_cnt.mask & mpls_index) != in_rule->label_cnt.data) 
                {
                    len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u MPLS count did not match \n",in_rule->user_tag);
                    rec_msg_len += len_print;
                    return TEST_FAIL;
                } 
               in_header_ptr->ip_header_ptr = (uint8_t*) &overlay32[mpls_index];
            }
            else if ( hdlc == 0xFF030021 || hdlc == 0xFF030057 || hdlc == 0x0F000800 || hdlc == 0x0F0086DD )
            {
                if ( ( in_rule->mpls_bottom.mask != 0 ) || ( in_rule->mpls_top.mask != 0 ) )
                {
                    len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u No MPLS  in the packet\n",in_rule->user_tag);
                    rec_msg_len += len_print;
                    return TEST_FAIL;
                }
#ifdef IPFV2_FILTER_TEST_DEBUG
                fprintf(DEBUG_OUT, "%s: %u No MPLS\n", __FUNCTION__, __LINE__);
#endif 
                in_header_ptr->ip_header_ptr =  (uint8_t*) drec->rec.pos.pload;
            }
            break;
        }
        case ERF_TYPE_ETH:
        case ERF_TYPE_COLOR_ETH:
        case ERF_TYPE_COLOR_HASH_ETH:
        case ERF_TYPE_DSM_COLOR_ETH:
        {
            uint16_t ethertype = ntohs(drec->rec.eth.etype);
            uint32_t vlan_count = 0; 
            uint16_t temp_vlan_1 = 0 ;
            uint16_t temp_vlan_2 = 0 ;
            if ( (in_rule->l2_proto.mask & ethertype) != in_rule->l2_proto.data)
            {
                    /* l2 proto is given in the rule, but doesn't match with the rule */
                    len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u L2 proto did not match \n",in_rule->user_tag);
                    rec_msg_len += len_print;
                    return TEST_FAIL;
            }
            if ((ethertype == 0x8100) || (ethertype == 0x88a8) )
            {
                /* VLAN ethernet encapsulations here */
                uint16_t* overlay16;
                int length_type ;
                uint8_t*    temp_pload_ptr = (uint8_t*) drec->rec.eth.pload;
                do{ 
                    overlay16 = (uint16_t*) temp_pload_ptr;
                    length_type = ntohs(overlay16[1]);
                    if( vlan_count == 0 ) temp_vlan_1 = ntohs(overlay16[0]) & 0xfff;
                    if ( vlan_count == 1 ) temp_vlan_2 = ntohs(overlay16[0]) & 0xfff;
                    vlan_count++;
                    /* check if its ipv4 or ipv6 */
                    if((0x0800 == length_type) || (0x86dd == length_type))
                    {
                        /* Found IP header. */
                        in_header_ptr->ip_header_ptr = (uint8_t*) &overlay16[2];
                        break;
                    }
                    temp_pload_ptr = (uint8_t*) &overlay16[2];
                }while ( (length_type == 0x8100) || (length_type == 0x88a8));
                
#ifdef IPFV2_FILTER_TEST_DEBUG
                fprintf(DEBUG_OUT, "%s: %u VLancount: %u vlan-1 %u vlan-2 %u\n", __FUNCTION__, __LINE__, vlan_count,temp_vlan_1, temp_vlan_2 );
#endif 
                /* TODO label cnt here */
                if (  (in_rule->label_cnt.mask & vlan_count) != in_rule->label_cnt.data) 
                {
                    len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u VLAN count did not match \n",in_rule->user_tag);
                    rec_msg_len += len_print;
                    return TEST_FAIL;
                } 
                /* validate vlan tags here */
                if (  (in_rule->vlan_1.mask & temp_vlan_1) != in_rule->vlan_1.data) 
                {
                    len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u VLAN 1 did not match \n",in_rule->user_tag);
                    rec_msg_len += len_print;
                    return TEST_FAIL;
                } 
                if (  (vlan_count >1) && (in_rule->vlan_2.mask & temp_vlan_2) != in_rule->vlan_2.data)
                {
                    len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u VLAN 2 did not match \n",in_rule->user_tag);
                    rec_msg_len += len_print;
                    return TEST_FAIL;
                } 
            }
            else if ((ethertype == 0x0800) || (ethertype == 0x86dd))
            {
                /* Non-VLAN Type-encoded ethernet carrying IP. */
                if ( ( in_rule->vlan_1.mask != 0 ) || ( in_rule->vlan_2.mask != 0 ) )
                {
                    len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u No VLAN in the packet\n",in_rule->user_tag);
                    rec_msg_len += len_print;
                    return TEST_FAIL;
                }
#ifdef IPFV2_FILTER_TEST_DEBUG
                fprintf(DEBUG_OUT, "%s: %u No vlan\n", __FUNCTION__, __LINE__);
#endif 
                in_header_ptr->ip_header_ptr = (uint8_t*) drec->rec.eth.pload;
            }
            break;
        }
        default:
            len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Invalid packet of type %s here %s: %u \n",dagerf_type_to_string(in_header_ptr->erf_type, 0 ),__FILE__, __LINE__);
            rec_msg_len += len_print;
            return TEST_FAIL;
    }   
    return TEST_PASS;
}

int ipfv2_filter_test_parse_verify_ip_header( ipfv2_header_ptrs_struct_t *in_header_ptr, /* int rem_len ,*/ ipf_v2_filter_rule_t const* in_rule)
{
    uint8_t ip_version;
    int layer_4_offset = 0; 
    int option_words_count = 0;
    uint8_t next_header_type = 0;
    uint8_t *ip_header =  in_header_ptr->ip_header_ptr;
    ip_version = ((ip_header[0] & 0xf0) >> 4);
    if (ip_version == 4)
    {
        if ( in_rule->ip_address_type == k128Bit )
        {
            len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u Packet has ipv4, rule is ipv6 \n",in_rule->user_tag);
            rec_msg_len += len_print;
            return TEST_FAIL;
        }
        /* compare ip addresses */
        if( ((uint32_t)(in_rule->src_ip.mask[0]) & ntohl((uint32_t)*((uint32_t*) &ip_header[12]))) != (uint32_t) in_rule->src_ip.data[0])
        {
            len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u SRC IP did not match \n",in_rule->user_tag);
            rec_msg_len += len_print;
            return TEST_FAIL;
        }
        if( ((uint32_t)(in_rule->dst_ip.mask[0]) & ntohl(*((uint32_t*) &ip_header[16])) ) != in_rule->dst_ip.data[0])
        {
            len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u DST IP did not match \n",in_rule->user_tag);
            rec_msg_len += len_print;
            return TEST_FAIL;
        }
        layer_4_offset = 20;
        option_words_count = (ip_header[0] & 0x0f) - 5;
        layer_4_offset += (option_words_count * 4 );
        next_header_type = ip_header[9];
    }
    if (ip_version == 6)
    {
        uint8_t ext_hdr_parse_finished = 0;
        uint8_t next_ext_hdr = 0;
        if ( in_rule->ip_address_type == k32Bit )
        {
            len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u Packet has ipv6, rule is ipv4 \n",in_rule->user_tag);
            rec_msg_len += len_print;
            return TEST_FAIL;
        }
        /* compare ip addresses */
        if( ( in_rule->src_ip.mask[0] & bswap_64(*( (uint64_t*) &ip_header[8]) ))!= in_rule->src_ip.data[0])
        {
            len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u SRC IP did not match \n",in_rule->user_tag);
            rec_msg_len += len_print;
            return TEST_FAIL;
        }
        if( (in_rule->src_ip.mask[1] & bswap_64(*((uint64_t*) &ip_header[16])))!= in_rule->src_ip.data[1])
        {
            len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u SRC IP did not match \n",in_rule->user_tag);
            rec_msg_len += len_print;
            return TEST_FAIL;
        }
        if( (in_rule->dst_ip.mask[0] & bswap_64(*((uint64_t*) &ip_header[24])) ) != in_rule->dst_ip.data[0]) 
        {
            len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u DST IP did not match \n",in_rule->user_tag);
            rec_msg_len += len_print;
            return TEST_FAIL;
        }
        if( (in_rule->dst_ip.mask[1]& bswap_64(*((uint64_t*) &ip_header[32])))  != in_rule->dst_ip.data[1]) 
        {
            len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u DST IP did not match \n",in_rule->user_tag);
            rec_msg_len += len_print;
            return TEST_FAIL;
        }
        layer_4_offset = 40; 
        next_ext_hdr = ip_header[6];
        while ( !ext_hdr_parse_finished)
        {
            switch (next_ext_hdr)
            {
                case HOPOPT_EXT_HEADER:
                    next_ext_hdr = ip_header[layer_4_offset];
                    layer_4_offset += (ip_header[layer_4_offset + 1] * 8) + 8;
                    break;
                    
                case ROUTE_EXT_HEADER:
                    next_ext_hdr = ip_header[layer_4_offset];
                    layer_4_offset += (ip_header[layer_4_offset + 1] * 8) + 8;
                    break;
                    
                case OPTS_EXT_HEADER:
                    next_ext_hdr = ip_header[layer_4_offset];
                    layer_4_offset += (ip_header[layer_4_offset + 1] * 8) + 8;
                    break;
                    
                case FRAG_EXT_HEADER:
                    next_ext_hdr = ip_header[layer_4_offset];
                    layer_4_offset += 8;
                    break;
                    
                case AUTH_EXT_HEADER:
                    next_ext_hdr = ip_header[layer_4_offset];
                    layer_4_offset += (ip_header[layer_4_offset + 1] * 4) + 8;
                    break;
                
                case ESP_EXT_HEADER:
                    ext_hdr_parse_finished = 1;
                    break;

                default:
                    ext_hdr_parse_finished = 1;
            }
        }
        next_header_type = next_ext_hdr;
    }
    if ( (in_rule->ip_prot.mask & next_header_type) != in_rule->ip_prot.data)
    {
        /* ip prot is given in the rule, but doesn't match with the rule */
        len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u IP  prot did not match \n",in_rule->user_tag);
        rec_msg_len += len_print;
        return TEST_FAIL;
    }
    if ( (next_header_type == IPPROTO_TCP) || (next_header_type == IPPROTO_UDP) )
            in_header_ptr->tcp_udp_header_ptr = ip_header +  layer_4_offset;
    
    return TEST_PASS;
}

int ipfv2_filter_test_parse_verify_transport_header( ipfv2_header_ptrs_struct_t *in_header_ptr, /* int rem_len ,*/ ipf_v2_filter_rule_t const* in_rule)
{
    uint16_t* overlay16 = (uint16_t*) in_header_ptr->tcp_udp_header_ptr;
    if ( (in_rule->src_port.mask & ntohs(overlay16[0])) != in_rule->src_port.data)
    {
        /* src port  is given in the rule, but doesn't match with the rule */
        len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u SRC  port did not match \n",in_rule->user_tag);
        rec_msg_len += len_print;
        return TEST_FAIL;
    }
    if ( (in_rule->dst_port.mask & ntohs(overlay16[1])) != in_rule->dst_port.data)
    {
        /* dst port is given in the rule, but doesn't match with the rule */
        len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u DST  port did not match \n",in_rule->user_tag);
        rec_msg_len += len_print;
        return TEST_FAIL;
    }
    /* TODO additional checks cud be made to chek the proto is TCP for the below chek. but */
    /*    ignoring for the moment */
     if ( (in_rule->tcp_flags.mask &  in_header_ptr->tcp_udp_header_ptr[13]) != in_rule->tcp_flags.data)
    {
        /* tcp flags is given in the rule, but doesn't match with the rule */
        len_print = snprintf(&rec_msg[rec_msg_len], MAX_STR_LEN-rec_msg_len,"Rule:%u TCP flags  did not match \n",in_rule->user_tag);
        rec_msg_len += len_print;
        return TEST_FAIL;
    }
    return TEST_PASS;
}





