/*
 * Copyright (c) 2004-2005 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: dagipf.h 13453 2010-12-02 23:30:08Z jomi.gregory $
 */
/** \defgroup PFAPI Packet Filtering API
 */
/*@{*/
/**
 * \brief Low-level interface to CAM entries and the coprocessor
 *
 * Data types and functions for the direct manipulation of CAM entires
 * and the coprocessor, hence the 'low-level' in the brief
 * description. Meant to be used by the high-level copro interface
 * functions.
 */
/** \defgroup PFLI Low-level interface to CAM entries and the coprocessor
 */
/*@{*/

#ifndef DAGIPF_H
#define DAGIPF_H

/* Endace headers. */
#include "dagutil.h"

#if defined (_WIN32)
#include "wintypedefs.h"
#include "filtertypedefs.h"
#endif /* _WIN32 */

typedef void* FilterStatePtr; /**< Opaque pointer for filter state. */

#define SC256_CSR0 (0x54/4)
#define SC256_CSR1 (0x58/4)
#define SC256_CSR2 (0x5c/4)
#define SC256_VAL_ARRAY 0x00
#define SC256_RES_ARRAY (0x48/4)
#define SC256_VAL_ARRAY_DEPTH (0x12/4)
#define SCR 0
#define SSR0 2
#define SSR1 4
#define LAR 6

typedef enum
{
	ERR_NOERR = 0,
	ERR_NOT_IMPLEMENTED, /**<  Feature coming soon. */
	ERR_NO_COPRO,
	ERR_INVALID_STATE,
	ERR_INVALID_SEARCH_REGISTER,
	ERR_INVALID_PARAMETER,
	ERR_TOO_MANY_SEARCHES,
	ERR_CAM_OVERFLOW,    /**< Not enough memory in CAM. */
	ERR_OUT_OF_MEMORY,
	ERR_VERIFY_FAILED

} dagipf_error_t;

enum dagipf_flags_t
{
	DAGIPF_FLAG_NOHARDWARE = 1 /**< Don't do anything that would require real hardware. */
};

typedef enum
{
	ACTION_DROP = 1,
	ACTION_PASS = 0,
	ACTION_PASS_DROP_MASK = 1

} dagipf_action_t;

typedef enum
{
	SEARCH_REGISTER_A,
	SEARCH_REGISTER_B,
	SEARCH_REGISTER_C,
	SEARCH_REGISTER_D,
	SEARCH_REGISTER_E

} ipf_search_register_t;

typedef struct
{
	int8_t word;    /**< Which word in the packet.  -1 = do not set. */
	uint8_t nibble; /**< Which nibble in the word. */

} nibble_mapping_t;

typedef struct
{
	uint64_t value[4];   /**< Values to search for.
                          *
                          * Each uint64_t contains 36 bits from search value. 
					  	  * value[0] contains the most significant 36 bits, 
					  	  * value[3] the least significant 36 bits.
					  	  */
	uint64_t mask[4];    /**< Mask for values. */
	uint16_t colour;     /**< Colour to assign when match is made. */
	uint16_t snaplength; /**< Snaplength for packets that match this pattern. */
	uint8_t action;      /**< Action to take for packets that match this pattern. */

} pattern144_t;

typedef struct
{
	nibble_mapping_t register_mapping[36]; /**< Description of how the search register is constructed.
											* register_mapping[0] is most significant nibble, 
											* register_mapping[35] is least.
											*/
	uint32_t length;                       /**< Number of values in the search_value array. */
	pattern144_t* searches;                /**< Array of pattern144_t, one for each search value. */

} search_record144_t;


enum result_mapping_flags_t
{
	RESULT_FLAG_MAPPED = 1,
	RESULT_FLAG_INVERTED = 2
};

typedef struct
{
	uint8_t output_word; /**< Where this bit is going to end up. */
	uint8_t word_bit;    /**< Which bit in the specified output word contains the bit. */
	uint8_t flags;       /**< flags[0] = mapped, flags[1] = inverted. */

} result_bit_mapping_t;

#define RESULT_REGISTER_BITS 128

typedef struct
{
	result_bit_mapping_t bit_mapping[RESULT_REGISTER_BITS];

} result_mapping_t;


typedef struct bit72_word_t
{
	uint64_t lowbits; /**< lower order 64-bits */
	uint8_t highbits; /**< higher order 8-bits */
	
} bit72_word_t;

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */


/* IP Filtering API. */
/** \defgroup PFLIF CAM entries and the coprocessor functions
 */
/*@{*/

FilterStatePtr dagipf_init(int dagfd, uint32_t flags, coprocessor_t cptype);
dagipf_error_t dagipf_dispose(FilterStatePtr ipf_state);

/** Return user-friendly string describing the error. */
const char* dagipf_strerror(dagipf_error_t dagipf_err);

/* Utility routines. */
dagipf_error_t dagipf_copro_enable(FilterStatePtr ipf_state);
dagipf_error_t dagipf_copro_disable(FilterStatePtr ipf_state);
dagipf_error_t dagipf_datapath_enable(FilterStatePtr ipf_state);
dagipf_error_t dagipf_datapath_disable(FilterStatePtr ipf_state);

/** Configure ports and rulesets. 
 *
 * Maximum of 2 ports and 2 rulesets is supported.
 * CAM entries are divided evenly among the configured ports and rulesets.
 * Default configuration if dagipf_configure_rulesets() is not called is 1 port, 1 ruleset.
 */
dagipf_error_t dagipf_configure_rulesets(FilterStatePtr ipf_state, uint8_t ports, uint8_t rulesets);

/** Retrieves the number of ports configured. */
dagipf_error_t dagipf_get_port_count(FilterStatePtr ipf_state, uint8_t* count);

/** Retrieves the number of rulesets associated with the port. */
dagipf_error_t dagipf_get_port_ruleset_count(FilterStatePtr ipf_state, uint8_t port, uint8_t* count);

/** Retrieves the value of the currently active ruleset for the port. */	
dagipf_error_t dagipf_get_port_ruleset(FilterStatePtr ipf_state, uint8_t port, uint8_t* ruleset);

/** Switches the coprocessor to use the specified ruleset for the given port.  
 * Ports and rulesets are numbered from zero. 
 */
dagipf_error_t dagipf_set_port_ruleset(FilterStatePtr ipf_state, uint8_t port, uint8_t ruleset);

/** Load state into coprocessor and start filtering. */
dagipf_error_t dagipf_activate(FilterStatePtr ipf_state);

/**Load state into coprocessor 256 and start filtering */
dagipf_error_t dagipf_activate256(FilterStatePtr ipf_state);

/** Reset state.  Does not affect coprocessor until next dagipf_activate() call. */
dagipf_error_t dagipf_reset(FilterStatePtr ipf_state);

/** Clear all payload searches. */
dagipf_error_t dagipf_clear_payload_searches(FilterStatePtr ipf_state);

/** Clear all header searches. */
dagipf_error_t dagipf_clear_header_searches(FilterStatePtr ipf_state);

/** Configure IP length field filtering. */
dagipf_error_t dagipf_set_ip_length_range(FilterStatePtr ipf_state, uint16_t min, uint16_t max);

/** Configure IP TTL field filtering. */
dagipf_error_t dagipf_set_ttl_range(FilterStatePtr ipf_state, uint8_t min, uint8_t max);

/** Enable/disable individual search registers. */
dagipf_error_t dagipf_enable_search_register(FilterStatePtr ipf_state, 
											 ipf_search_register_t search_reg);
dagipf_error_t dagipf_disable_search_register(FilterStatePtr ipf_state, 
											  ipf_search_register_t search_reg);

/** Add a payload search.  
 * String length is specified explicitly so that embedded null characters can be passed in. 
 */
dagipf_error_t dagipf_add_payload_search(FilterStatePtr ipf_state, const char* payload, 
										 uint16_t length, uint16_t colour);

/** Get and dispose new search records.  
 *
 * Search records are disposed by the dagipf module if passed to one of the 
 * dagipf_add_XXbit_header_search() routine.  Note that although the CAM supports 36 and 
 * 72 bit searches, 4 bits of each of these is used to differentiate tags.
 * So from a client's point of view there are 32 bit searches, 68 bit searches and 144 bit searches.
 */
search_record144_t* dagipf_new_144bit_search(FilterStatePtr ipf_state, uint32_t values);
void dagipf_dispose_144bit_search(search_record144_t* search);

/** Add a header search. 
 * 
 * The search_record144_t is owned by the IP filtering module after this call. 
 */
dagipf_error_t dagipf_add_144bit_header_search(FilterStatePtr ipf_state, 
											   search_record144_t* search);

/** Add additional searches that use the same search template initially passed to 
 * dagipf_add_144bit_header_search().  Used to configure a specific ruleset 
 * or port.
 * The searches array is owned by the IP filtering module after this call. 
 */
dagipf_error_t dagipf_add_144bit_searches(FilterStatePtr ipf_state,
										  uint8_t port,
										  uint8_t ruleset,
										  uint32_t search_count,
										  pattern144_t* searches,
                                          bool verify);

/** Create array of pattern144_t structs.  
 * Necessary to work around a problem with Windows libraries statically linked against the C Runtime Library.
 */
pattern144_t* dagipf_new_search_array(unsigned int count);

/** Dispose array of pattern144_t structs.  
 * Necessary to work around a problem with Windows libraries statically linked against the C Runtime Library.
 */
void dagipf_dispose_search_array(pattern144_t* searches);

/** Configure the mapping of the Results Register into the packet. 
 * The result_mapping_t* is still owned by the caller after this call. 
 */
dagipf_error_t dagipf_add_results_mapping(FilterStatePtr ipf_state, result_mapping_t* mapping);

/**
 * Return the version number of the IPF firmware module
 */
int dagipf_get_version(FilterStatePtr ipf_state);

/**
 * Set the linktype
 *
 * \param value 0 for Pos/PPP, 1 for Ethernet - IPFv2 only
 */ 
dagipf_error_t dagipf_set_linktype_eth(FilterStatePtr ipf_state, uint8_t value);

/**
 * Set the colour embedding - IPFv2 only
 *
 * \param value 0: in the PAD Offset (Ethernet) or over the link header (PoS/PPP) 1: loss counter field
 */ 
dagipf_error_t dagipf_set_color_lctr(FilterStatePtr ipf_state, uint8_t value);


/**
 * Set the RX error field overwriting - IPFv2 only
 *
 * \param value 0: do not overwrite 1: overwrite RX error field in ERF header
 */ 
dagipf_error_t dagipf_set_rx_error(FilterStatePtr ipf_state, uint8_t value);

/**
 * Enable packet dropping - IPFv2 only
 */
dagipf_error_t dagipf_enable_drop(FilterStatePtr ipf_state, uint8_t value);

/**
 * Reset control register of IPFv2 - IPFv2 only
 */
dagipf_error_t dagipf_reset_control(FilterStatePtr ipf_state);

/*@}*/
#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* DAGIPF_H */
/*@}*/
/*@}*/

