/*
 * Copyright (c) 2004-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: dagpf.h 11730 2009-08-06 07:23:46Z wilson.zhu $
 */

/**
 * \defgroup PFAPI Packet Filtering API 
 *
 * The Packet Filtering API allows programs to be written that can
 * configure and control the packet filtering functionality of the DAG
 * coprocessors. See the following header files for further details on
 * the interface:
 *
 * - dagpf.h: Converting and loading rule files
 *
 * The interface described in the above header files is simple and
 * provides basic functionality: it works with text files and can
 * update entire rulesets in the coprocessor. However if lower-level
 * access is necessary, i.e. individual rules must be created or
 * manipulated then the following header files should be consulted:
 * 
 * - filter_rule_types.h: high-level filter rule data types (Endace rules)
 * - filters.h:	high-level filter processing (creating, modifying rules)
 * - dag_filter.h: coprocessor control (loading rules, activating ruleset, etc.)
 *
 * The lowest level of abstraction is the direct access to CAM entries
 * and coprocessor registers:
 *
 * - dagipf.h: Low-level interface to CAM entries and the coprocessor
 */
/*@{*/

/**
 * \brief Converting and loading rule files
 *
 * Functions read Endace rules from file, convert
 * address/port/etc. tokens to CAM entries and load them to CAM.
 *
 * The recommended way to use these functions (opening/closing the
 * device or files is the user's responsibility and omitted from the
 * steps below):
 *
 * - initialise library   -- dagpf_init
 * - check coprocessor    -- dagpf_check_copro
 * - read rules from file -- dagpf_read_filters
 * - load rules to CAM    -- dagpf_load_filters
 * - clean up library     -- dagpf_cleanup
 *
 * The functions are reentrant.
 */

#ifndef DAGPF_H
#define DAGPF_H

#include <stdio.h>
//#include "dagpci.h"
#include "dagutil.h"

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

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

/** \defgroup PFCAL Converting and loading rule files
 */
/*@{*/

/* Constants. */
#define FILTER_LOADER_MAX_INTERFACES 2


#ifndef IPPROTO_IGRP
#define IPPROTO_IGRP 9
#endif /* IPPROTO_IGRP */

#ifndef IPPROTO_ALL
#define IPPROTO_ALL 255
#endif /* IPPROTO_ALL */

/**
 * The action to be taken when the packet matches the rule
 */
typedef enum
{
	ACCEPT = 0,
	kFirstAction = ACCEPT,
	REJECT,
	kLastAction = REJECT

} filter_action_t;


/**
 * Bitfield for packet destinations: bit 0 = buffer 1, bit 1 = buffer 2.
 * Currently only 2 ring buffers are supported.
 */
typedef enum
{
	DST_BUFFER_NONE = 0x00, /**< Drop packet. */
	DST_BUFFER_RED =  0x01, /**< Send packet to buffer 1 */
	DST_BUFFER_BLUE = 0x02, /**< Send packet to buffer 2 */
	DST_BUFFER_BOTH = 0x03

} destination_buffer_t;

typedef enum
{
	DF_LINK_UNKNOWN,
	DF_LINK_ETHERNET,
	DF_LINK_POS4_CHDLC,
	DF_LINK_POS4 = DF_LINK_POS4_CHDLC,
	DF_LINK_POS4_PPP,
	DF_LINK_POS6

} linktype_t;

/**
 * Color-mapping types
 *
 * IDs for the different mapping methods, i.e. the location of the
 * color info in the ERF record
 */
typedef enum
{
	DF_MAPPING_UNKNOWN,
	DF_MAPPING_NONE,                  /**< do not map results at all (for testing purposes only). */
	DF_MAPPING_COLOURED_ERF,          /**< map colour into the lcntr/colour field and use one of the TYPE_COLOR_HDLC_POS/TYPE_COLOR_ERF codes for generated ERF records. */
	DF_MAPPING_COLORED_ERF = DF_MAPPING_COLOURED_ERF,
	DF_MAPPING_COLOURED_ERF_STREAM0,  /**< map colour into the lcntr/colour field and use one of the TYPE_COLOR_HDLC_POS/TYPE_COLOR_ERF codes for generated ERF records. */
	DF_MAPPING_COLORED_ERF_STREAM0 = DF_MAPPING_COLOURED_ERF_STREAM0,
	DF_MAPPING_RXERROR,               /**< map colour bit 0 into RX Error bit. */
	DF_MAPPING_PADOFFSET,             /**< map colour into ERF pad and offset bytes (Ethernet only). */
	DF_MAPPING_PADOFFSET_STREAM0,     /**< as for DF_MAPPING_PADOFFSET but force all packets to stream 0. */
	DF_MAPPING_HDLC_HEADER,           /**< map colour into ERF HDLC header bytes (PoS4 only, can be CHDLC or PPP). */
	DF_MAPPING_HDLC_HEADER_STREAM0,   /**< as for DF_MAPPING_HDLC_HEADER but force all packets to stream 0. */
	DF_MAPPING_ENTIRE_REGISTER        /**< map entire Results Register, beginning at ERF pad and offset bytes (Ethernet only). */

} mapping_t;

/**
 * IPv4 address with possible don't care bits (mask)
 */
typedef struct ip_address
{
	in_addr_t ip4_addr; /**< network byte order */
	uint32_t mask;      /**< network byte order */
} ip_address_t;

/**
 * Port number with possible don't care bits (mask)
 * (as opposed to ipf_port, which is a range of numbers)
 */
typedef struct cam_port
{
	uint16_t port;    /**< network byte order */
	uint16_t mask;    /**< network byte order */
} cam_port_t;

/**
 * TCP flags byte with possible don't care bits (mask)
 */
typedef struct tcp_flags
{
	uint8_t flags;
	uint8_t mask;
} tcp_flags_t;

/**
 * Protocol number with possible don't care bits (mask)
 */
typedef struct protocol
{
	uint8_t protocol;
	uint8_t mask;
} protocol_t;

/**
 * L2 Protocol number with possible don't care bits (mask)
 */
typedef struct l2_protocol
{
	uint16_t protocol;
	uint16_t mask;
} l2_protocol_t;

/**
 * Data structure describing a line in CAM
 */
typedef struct cam_entry 
{
	cam_port_t src_port;
	cam_port_t dest_port;
	ip_address_t source;
	ip_address_t dest;
	uint16_t colour;
	uint16_t snaplength;
	protocol_t protocol;
    l2_protocol_t l2_protocol;
	uint8_t action;
	tcp_flags_t tcp_flags;
} cam_entry_t;

/**
 * Filtering configuration parameters
 */ 
typedef struct filter_param_t {
    	coprocessor_t coprocessor_type; /**< Coprocessor type. todo: find a better place for
 					 * this variable, as it is not a configuration 
 					 * parameter but determined runtime 
					 */
     	bool initialise; /**< Whether to initialise the coprocessor from scratch or hot-swap the rules. */
   	bool drop;	/**< Drop packets when a receive stream is full (e.g. one of the streams has no reader).*/
	int _port;	/** Interface to filter. */
    uint8_t init_interfaces; /**< Only valid when initialising the coprocessor - number of interfaces. */
    uint8_t init_rulesets;   /**< Only valid when initialising the coprocessor - rulesets per interface. */
    uint32_t snaplength;     /**< Default snap length to apply to filters that do not have an explicit snaplength. */
    linktype_t linktype;     /**< Ethernet or PoS (4/6 byte headers). */
    mapping_t mapping;       /**< Where to put the data. */
    bool verify;             /**< Enable/disable verification */
} filter_param_t;


/**
 * Filter
 *
 * An item of the filter list. It contains the CAM entry and a
 * pointer to the next filter.
 */
typedef struct filter_t
{
	struct filter_t* next; /**< pointer to the next filter item */
	cam_entry_t entry; /**< filter item (low level format, i.e. CAM entry)*/
} filter_t;

/**
 * Filter list
 *
 * Helper structure to handle the linked list of filters, with
 * references to the first and last filter item, and the number of the
 * items.
 */
typedef struct filter_list_t
{
	filter_t* head; /**< first filter element */
	filter_t* tail; /**< last filter element */
	unsigned int items; /**< number of filter items */

} filter_list_t;

/** \defgroup PFCALF Loading rules functions
 */
/*@{*/

/**
 * Initialize filter loader library
 *
 * Allocate memory for the data structures and return pointers to them. 
 *
 * \param filterlist  pointer to an array of filterlists (for both interfaces plus a default list)
 * \param param       pointer to pointer to parameter structure
 *
 * \return non-zero in case of errors, zero otherwise
 */
int dagpf_init(filter_list_t** filterlist, filter_param_t** param);


/**
 * Coprocessor check
 *
 * Check coprocessor type and loaded image. Store the copro type in
 * the corresponding field of 'param' to be used by filter loading.
 *
 * \param dagfd  file descriptor for the DAG device
 * \param param  pointer to the parameter structure to fill in
 * 
 * \return non-zero in case of errors, zero otherwise
 */
int dagpf_check_copro(int dagfd, filter_param_t* param);

/**
 * Cleanup filter loader library
 *
 * Free allocated memory, close files.
 *
 * \param filterlist  an array of filterlists (for both interfaces plus a default list)
 * \param param       pointer to parameter structure
 *
 * \return non-zero in case of errors, zero otherwise
 */
 int dagpf_cleanup(filter_list_t* filterlist, filter_param_t* param);


/**
 * Read filters from file
 *
 * Read the input file line-by-line and parse each line(rule) to
 * create the corresponding CAM entries and store them in
 * filterlist. The filterlist must be initialised properly.
 *
 * \param infile      pointer to file descriptor of input file
 * \param filterlist  an array of filterlists (for both interfaces plus a default list)
 * \param snaplen     the default snaplength to use when none is provided in the input file
 *
 * \return non-zero in case of errors, zero otherwise
 */
int dagpf_read_filters(FILE* infile, filter_list_t* filterlist, filter_param_t* param);


/**
 * Load filters to DAG card
 *
 * Convert the list of filters into an array and load them to CAM. Use
 * the parameters given in 'param', i.e. which ruleset to use, drop
 * policy, etc. See the type definition of the filter_param_t.
 *
 * \param dagfd  file descriptor of the device
 * \param list   pointer to list of filters
 * \param param  parameters affecting filter loading
 *
 * \return non-zero if reset is required after loading filters
 */
int dagpf_load_filters(int dagfd, filter_list_t* list, filter_param_t* param);
/*@}*/

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* DAGPF_H */
/*@}*/
/*@}*/
