#ifndef	__FASTPATH_CORE_H__
#define	__FASTPATH_CORE_H__

#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter/xt_dscp.h>
#include <net/dst.h>
#include <net/route.h>

#include "../net/bridge/br_private.h"
#include "./rtl_queue.h"			/* X-Queue Marco Function */
#include <net/netfilter/nf_conntrack.h>

#if defined(CONFIG_RTL_ADV_FAST_PATH)
// QoS definitions, and pass these information to linux kernel
#define QOS_8021P_OFFSET        0
#define QOS_8021P_MASK      (0x7<<QOS_8021P_OFFSET)

#define QOS_SWQID_OFFSET        3
#define QOS_SWQID_MASK      (0xF<<QOS_SWQID_OFFSET)

#define SW_QOS_ENABLE       (1<<16)
#define QOS_ENTRY_OFFSET    8
#define QOS_ENTRY_MASK      (0xFF<<QOS_ENTRY_OFFSET)
 
#define QOS_DNS_Bind_OFFSET     17
#define QOS_DNS_Bind_MASK   (0x7<<QOS_DNS_Bind_OFFSET)

#define DSCP_MASK   		XT_DSCP_MASK
#define DSCP_SHIFT  		XT_DSCP_SHIFT
#define DSCP_MAX    		XT_DSCP_MAX
#endif /* CONFIG_RTL_ADV_FAST_PATH */

#if defined(CONFIG_RTL_HARDWARE_NAT) && defined(CONFIG_RTL8676_Dynamic_ACL) && defined(CONFIG_RTL_LAYERED_DRIVER) && defined(CONFIG_RTL_LAYERED_DRIVER_L2)
#define TRAFFIC_MONITOR
#define SIP_LIMIT_CHECK
#endif

#ifndef SUCCESS
#define SUCCESS 	0
#endif
#ifndef FAILED
#define FAILED -1
#endif

#ifndef TRUE
#define TRUE	1
#endif
#ifndef FALSE
#define FALSE	0
#endif



/*
	Virtual Rome Driver API & System (Light Rome Driver Simulator)
*/
#ifdef CONFIG_DATA_IN_IMEM
//#define	__IRAM_GEN	//__attribute__	((section(".iram-gen") target("code-readable=no")))
#else
//#define	__IRAM_GEN	//__attribute__	((section(".iram-gen")))
#endif
#define	ip_t		__u32
/* ---------------------------------------------------------------------------------------------------- */


#define NIPQUAD(addr) \
	((unsigned char *)&addr)[0], \
	((unsigned char *)&addr)[1], \
	((unsigned char *)&addr)[2], \
	((unsigned char *)&addr)[3]
#define NIPQUAD_FMT "%u.%u.%u.%u"

#define	IFNAME_LEN_MAX		16
#define	MAC_ADDR_LEN_MAX		18
#define	ARP_TABLE_LIST_MAX		32
#define	ARP_TABLE_ENTRY_MAX	256
#define	ROUTE_TABLE_LIST_MAX	16
#define	ROUTE_TABLE_ENTRY_MAX	64
#if defined(CONFIG_RTL_HW_NAPT_4KENTRY)
#define NAPT_TABLE_HASHING_BIT_NUM 13 //8k
#else
#define NAPT_TABLE_HASHING_BIT_NUM 11 //2k
#endif
#define	NAPT_TABLE_LIST_MAX	(0x1<<NAPT_TABLE_HASHING_BIT_NUM)
#define	NAPT_TABLE_ENTRY_MAX	(0x1<<NAPT_TABLE_HASHING_BIT_NUM)
#define	PATH_TABLE_LIST_MAX	(0x1<<NAPT_TABLE_HASHING_BIT_NUM)
#define	PATH_TABLE_ENTRY_MAX (NAPT_TABLE_ENTRY_MAX*2)	//(NAPT_TABLE_ENTRY_MAX * 2)  //cathy
#define	INTERFACE_ENTRY_MAX	8

#define	ETHER_ADDR_LEN		6
typedef struct ether_s {
        __u8 octet[ETHER_ADDR_LEN];
} ether_t;

#if 0
#define DEBUGP_API printk
#else
#define DEBUGP_API(format, args...)
#endif

#if 1
#define DEBUGP_PKT(format, args...) if(unlikely(DumpTrapCPUpkt_debug && DumpTrapCPUpkt_debug_LIMIT>0)) printk(format, ## args)
#else
#define DEBUGP_PKT(format, args...)
#endif

#if 0
#define DEBUGP_SYS printk
#else
#define DEBUGP_SYS(format, args...)
#endif

/* ########### API #################################################################################### */
enum LR_RESULT
{
	/* Common error code */
	LR_SUCCESS = 0,						/* Function Success */
	LR_FAILED = -1,						/* General Failure, not recommended to use */
	LR_ERROR_PARAMETER = -2,				/* The given parameter error */
	LR_EXIST = -3,							/* The entry you want to add has been existed, add failed */
	LR_NONEXIST = -4,						/* The specified entry is not found */
	
	LR_NOBUFFER = -1000,					/* Out of Entry Space */
	LR_INVAPARAM = -1001,					/* Invalid parameters */
	LR_NOTFOUND = -1002,					/* Entry not found */
	LR_DUPENTRY = -1003,					/* Duplicate entry found */
};


enum ARP_FLAGS
{
	ARP_NONE = 0,
};

enum RT_FLAGS
{
	RT_NONE = 0,
};

enum SE_TYPE
{
	SE_PPPOE = 1,
	SE_PPTP = 2,
	SE_L2TP = 3,
};
enum SE_FLAGS
{
	SE_NONE = 0,
};

enum NP_FLAGS
{
	NP_NONE = 0,
};

/* ---------------------------------------------------------------------------------------------------- */
enum LR_RESULT fastpath_addArp( ip_t ip, ether_t* mac, enum ARP_FLAGS flags );
enum LR_RESULT fastpath_modifyArp( ip_t ip, ether_t* mac, enum ARP_FLAGS flags );
enum LR_RESULT fastpath_delArp( ip_t ip );
enum LR_RESULT fastpath_addRoute( ip_t ip, ip_t mask, ip_t gateway, __u8* ifname, enum RT_FLAGS flags, int type);
enum LR_RESULT fastpath_modifyRoute( ip_t ip, ip_t mask, ip_t gateway, __u8* ifname, enum RT_FLAGS flags, int type );
enum LR_RESULT fastpath_delRoute( ip_t ip, ip_t mask );
enum LR_RESULT fastpath_addSession( __u8* ifname, enum SE_TYPE seType, __u32 sessionId, enum SE_FLAGS flags );
enum LR_RESULT fastpath_delSession( __u8* ifname );

//andrew
void fastpath_notify(int event);

//cathy
enum LR_RESULT fastpath_addRoutedNaptConnection(struct sk_buff *skb, struct nf_conn *ct,struct nf_conntrack_tuple ori_tuple,
		struct nf_conntrack_tuple reply_tuple, enum NP_FLAGS flags, int state);

enum LR_RESULT fastpath_delRoutedNaptConnection (struct nf_conntrack_tuple ori_tuple,
		struct nf_conntrack_tuple reply_tuple);


/* [MARCO FUNCTION] ========================================================================= */
#define	MAC2STR(addr) \
	((unsigned char *)&addr)[0], \
	((unsigned char *)&addr)[1], \
	((unsigned char *)&addr)[2], \
	((unsigned char *)&addr)[3], \
	((unsigned char *)&addr)[4], \
	((unsigned char *)&addr)[5]

#define	FASTPATH_MAC2STR(mac, hbuffer) \
	do { \
		int j,k; \
		const char hexbuf[] =  "0123456789ABCDEF"; \
		for (k=0,j=0;k<MAC_ADDR_LEN_MAX && j<6;j++) { \
			hbuffer[k++]=hexbuf[(mac->octet[j]>>4)&15 ]; \
			hbuffer[k++]=hexbuf[mac->octet[j]&15     ]; \
			hbuffer[k++]=':'; \
		} \
		hbuffer[--k]=0; \
	} while(0)	/* Mac Address to String */

#define FASTPATH_ADJUST_CHKSUM_NAT_UDP(ip_mod, ip_org, chksum) \
	do { \
		s32 accumulate = 0; \
		if (chksum == 0) break; \
		if (((ip_mod) != 0) && ((ip_org) != 0)){ \
			accumulate = ((ip_org) & 0xffff); \
			accumulate += (( (ip_org) >> 16 ) & 0xffff); \
			accumulate -= ((ip_mod) & 0xffff); \
			accumulate -= (( (ip_mod) >> 16 ) & 0xffff); \
		} \
		accumulate += ntohs(chksum); \
		if (accumulate < 0) { \
			accumulate = -accumulate; \
			accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
			accumulate += accumulate >> 16; \
			chksum = htons((__u16) ~accumulate); \
		} else { \
			accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
			accumulate += accumulate >> 16; \
			chksum = htons((__u16) accumulate); \
		} \
	}while(0)	/* Checksum adjustment */

#define FASTPATH_ADJUST_CHKSUM_NPT_UDP(port_mod, port_org, chksum) \
	do { \
		s32 accumulate = 0; \
		if (chksum == 0) break; \
		if (((port_mod) != 0) && ((port_org) != 0)){ \
			accumulate += (port_org); \
			accumulate -= (port_mod); \
		} \
		accumulate += ntohs(chksum); \
		if (accumulate < 0) { \
			accumulate = -accumulate; \
			accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
			accumulate += accumulate >> 16; \
			chksum = htons((__u16) ~accumulate); \
		} else { \
			accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
			accumulate += accumulate >> 16; \
			chksum = htons((__u16) accumulate); \
		} \
	}while(0)	/* Checksum adjustment */


#define FASTPATH_ADJUST_CHKSUM_NAPT_UDP(ip_mod, ip_org, port_mod, port_org, chksum) \
	do { \
		s32 accumulate = 0; \
		if (chksum == 0) break; \
		if (((ip_mod) != 0) && ((ip_org) != 0)){ \
			accumulate = ((ip_org) & 0xffff); \
			accumulate += (( (ip_org) >> 16 ) & 0xffff); \
			accumulate -= ((ip_mod) & 0xffff); \
			accumulate -= (( (ip_mod) >> 16 ) & 0xffff); \
		} \
		if (((port_mod) != 0) && ((port_org) != 0)){ \
			accumulate += (port_org); \
			accumulate -= (port_mod); \
		} \
		accumulate += ntohs(chksum); \
		if (accumulate < 0) { \
			accumulate = -accumulate; \
			accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
			accumulate += accumulate >> 16; \
			chksum = htons((__u16) ~accumulate); \
		} else { \
			accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
			accumulate += accumulate >> 16; \
			chksum = htons((__u16) accumulate); \
		} \
	}while(0)	/* Checksum adjustment */

#define FASTPATH_ADJUST_CHKSUM_NAT(ip_mod, ip_org, chksum) \
	do { \
		s32 accumulate = 0; \
		if (((ip_mod) != 0) && ((ip_org) != 0)){ \
			accumulate = ((ip_org) & 0xffff); \
			accumulate += (( (ip_org) >> 16 ) & 0xffff); \
			accumulate -= ((ip_mod) & 0xffff); \
			accumulate -= (( (ip_mod) >> 16 ) & 0xffff); \
		} \
		accumulate += ntohs(chksum); \
		if (accumulate < 0) { \
			accumulate = -accumulate; \
			accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
			accumulate += accumulate >> 16; \
			chksum = htons((__u16) ~accumulate); \
		} else { \
			accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
			accumulate += accumulate >> 16; \
			chksum = htons((__u16) accumulate); \
		} \
	}while(0)	/* Checksum adjustment */

#define FASTPATH_ADJUST_CHKSUM_NPT(port_mod, port_org, chksum) \
	do { \
		s32 accumulate = 0; \
		if (((port_mod) != 0) && ((port_org) != 0)){ \
			accumulate += (port_org); \
			accumulate -= (port_mod); \
		} \
		accumulate += ntohs(chksum); \
		if (accumulate < 0) { \
			accumulate = -accumulate; \
			accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
			accumulate += accumulate >> 16; \
			chksum = htons((__u16) ~accumulate); \
		} else { \
			accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
			accumulate += accumulate >> 16; \
			chksum = htons((__u16) accumulate); \
		} \
	}while(0)	/* Checksum adjustment */


#define FASTPATH_ADJUST_CHKSUM_NAPT(ip_mod, ip_org, port_mod, port_org, chksum) \
	do { \
		s32 accumulate = 0; \
		if (((ip_mod) != 0) && ((ip_org) != 0)){ \
			accumulate = ((ip_org) & 0xffff); \
			accumulate += (( (ip_org) >> 16 ) & 0xffff); \
			accumulate -= ((ip_mod) & 0xffff); \
			accumulate -= (( (ip_mod) >> 16 ) & 0xffff); \
		} \
		if (((port_mod) != 0) && ((port_org) != 0)){ \
			accumulate += (port_org); \
			accumulate -= (port_mod); \
		} \
		accumulate += ntohs(chksum); \
		if (accumulate < 0) { \
			accumulate = -accumulate; \
			accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
			accumulate += accumulate >> 16; \
			chksum = htons((__u16) ~accumulate); \
		} else { \
			accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
			accumulate += accumulate >> 16; \
			chksum = htons((__u16) accumulate); \
		} \
	}while(0)	/* Checksum adjustment */

#define FASTPATH_ADJUST_CHKSUM_TOS(tos_mod, tos_org, chksum) \
		do { \
			s32 accumulate = 0; \
			if (tos_mod != tos_org){ \
				accumulate += (tos_org); \
				accumulate -= (tos_mod); \
			} \
			else break; \
			accumulate += ntohs(chksum); \
			if (accumulate < 0) { \
				accumulate = -accumulate; \
				accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
				accumulate += accumulate >> 16; \
				chksum = htons((__u16) ~accumulate); \
			} else { \
				accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
				accumulate += accumulate >> 16; \
				chksum = htons((__u16) accumulate); \
			} \
		}while(0)	/* Checksum adjustment */

#define FASTPATH_ADJUST_CHKSUM_TOS_UDP(tos_mod, tos_org, chksum) \
		do { \
			s32 accumulate = 0; \
			if (chksum == 0) break; \
			if (tos_mod != tos_org){ \
				accumulate += (tos_org); \
				accumulate -= (tos_mod); \
			} \
			else break; \
			accumulate += ntohs(chksum); \
			if (accumulate < 0) { \
				accumulate = -accumulate; \
				accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
				accumulate += accumulate >> 16; \
				chksum = htons((__u16) ~accumulate); \
			} else { \
				accumulate = (accumulate >> 16) + (accumulate & 0xffff); \
				accumulate += accumulate >> 16; \
				chksum = htons((__u16) accumulate); \
			} \
		}while(0)	/* Checksum adjustment */

/* ---------------------------------------------------------------------------------------------------- */
__u8 *FastPath_Route(ip_t dIp);
int FastPath_Enter(struct sk_buff *skb);
int clearFastPathEntry(void);
/* ---------------------------------------------------------------------------------------------------- */

struct Arp_List_Entry
{
	__u8 valid;
	ip_t ip;
	ether_t mac;
	enum ARP_FLAGS flags;
	CTAILQ_ENTRY(Arp_List_Entry) arp_link;
	CTAILQ_ENTRY(Arp_List_Entry) tqe_link;
};

struct Route_List_Entry
{
	__u8 valid;
	ip_t ip;
	ip_t mask;
	ip_t gateway;
	__u8 ifname[IFNAME_LEN_MAX];
	enum RT_FLAGS flags;
	CTAILQ_ENTRY(Route_List_Entry) route_link;
	CTAILQ_ENTRY(Route_List_Entry) tqe_link;
};


struct FP_NAPT_entry {
	ip_t intIp;
	ip_t extIp;
	ip_t remIp;
	ip_t int_remIp;
	__u32 intPort;
	__u32 extPort;
	__u32 remPort;
	__u32 int_remPort;
	__u16 protocol;
    struct nf_conn * ct;
	enum NP_FLAGS flags;
	struct dst_entry * dst;
};

extern int fp_on;
static inline int FastPath_Enabled(void) {
	return fp_on;
}
static inline int Ip4_FastPath_Enabled(struct sk_buff *skb) {
	if(skb->pkt_type == PACKET_HOST &&
		(fp_on==2 || (fp_on==1 && (skb->dev->priv_flags & IFF_DOMAIN_WAN))))
		return 1;
	return 0;
}
#ifdef CONFIG_DSL_CODESWAP
extern int DSPInShowtime;
#endif
extern int index_dev2ch(struct net_device* dev);
extern int pppoe_fastpath(struct sk_buff *skb);
extern int isPPPoEDev(const char *ifname);
#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)||defined(CONFIG_ATP_SUPPORT_ETHUP)
int pppoe_proxy_output(struct sk_buff *skb, struct net_device *pdev, unsigned int course, unsigned int imq_flags);
#else
int pppoe_proxy_output(struct sk_buff *skb, struct net_device *pdev, unsigned int course);
#endif
extern int fp_iproute_input(void *pSt  /*struct skbuff * */, struct iphdr *iph, __u32 *fp_dip);
extern __u8 * fastpath_getdstifName(void *pSt);
//#if defined(CONFIG_PPTP) || defined(CONFIG_NET_IPIP)
int fp_iproute_output(void *pSt /*struct skbuff* */, struct iphdr *iph);
//#endif//end of CONFIG_PPTP || CONFIG_NET_IPIP
extern void setSkbDst(void *pSt  /*struct skbuff * */, void *dst /*struct dst_entry * */);
extern void SetFPDst(void *pSt /*struct skbuff * */, void **dst /*struct dst_entry ** */);
extern void FastPathHoldDst(void *pSt  /*struct skbuff * */);
extern void initSkbHdr(void *pSt  /*struct skbuff * */);
extern int getSkbMark(void *pskb);
extern int getSkbDscp(void *pskb);
extern u8 getSkbImqFlags(void *pskb);
extern int isDestLo(void *pSt /*struct skbuff * */);
extern void *getDevFromDestentry(void *dSt /* struct dst_entry * */);
extern unsigned short getDevTypeFromDestentry(void *dSt /* struct dst_entry * */);
extern void setQoSMark(void *pSt /*struct skbuff * */, unsigned int mark);
extern void setQosDscp(void *pSt, unsigned int mdscp, unsigned int mark);
extern void setQoSIMQ(void *pSt, u8 imqflags);
extern int isSkbDstAssigned(void *pSt /*struct skbuff * */);
extern int isNotFromPPPItf(void *pSt /*struct skbuff * */);
//#if defined(CONFIG_PPTP) || defined(CONFIG_PPPOL2TP) || defined(CONFIG_NET_IPIP)
ip_t getNetAddrbyName(const char *ifname, ip_t dst);
//#endif//end of CONFIG_PPTP || CONFIG_PPPOL2TP || CONFIG_NET_IPIP
//#ifdef CONFIG_NET_IPIP
void * getSkbDst(void *pSt);
int is_NoARP_Dev(void *dev);
int ipip_sanity_check(void *pskb, void *dst/* struct dst_entry * */);
//#endif//end of CONFIG_NET_IPIP
extern int ppp_proxy_output(struct sk_buff *skb);
enum LR_RESULT  fastpath_addNaptConnection(void *skb,struct FP_NAPT_entry *napt, int state);
enum LR_RESULT  fastpath_delNaptConnection(struct FP_NAPT_entry *napt);
enum LR_RESULT	fastpath_updateNaptConnection(struct FP_NAPT_entry *napt, unsigned int mark, unsigned int mdscp);
extern int checkUpstreamPPP(void *pdev,unsigned int course);//for 3G
extern __IRAM_SYS_MIDDLE int FastPath_Process(void *pskb, struct iphdr *iph,struct net_bridge_port *br_port);
extern void fp_br_fdb_update( struct net_bridge_port *br_port, struct sk_buff *skb);
extern int is3G_output(struct net_device * pdev);
extern int imq_enqueue(struct sk_buff *skb);
/* --- PATH Table Structures --- */
struct Path_List_Entry
{
	__u8			valid;
	//cathy
	__u16			*protocol;
	ip_t		*in_sIp;
	__u32			*in_sPort;
	ip_t		*in_dIp;
	__u32			*in_dPort;
	ip_t		*out_sIp;
	__u32			*out_sPort;
	ip_t		*out_dIp;
	__u32			*out_dPort;
	__u8			*out_ifname;
	struct Arp_List_Entry	*arp_entry;		/* for Out-dMac */
//#ifdef CONFIG_NET_IPIP
	__u8			arp_ignore;
//#endif //end of CONFIG_NET_IPIP
	__u8			course;					/* 1:In-Bonud 2:Out-Bound */
	int		internal_vlan_id;
	//struct dst_entry *dst;
	void			*dst;
	__u8			type;
	#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
	__u8			imq_flags;
	#endif
	__u32			mark;	//for IP QoS, TC
	__u32			mdscp;
	__u32			last_refresh_time;//Kevin, for refreshing nf_conn timer
	struct nf_conn * ct;
	struct nf_conntrack_tuple 	orig_tuple;	// tuple in IP_CT_DIR_ORIGINAL in conntrack
	unsigned long  add_into_asic_checked;
		
	struct Path_List_Entry *pair;
	
	__u32 pps;	/* packets per second */
	CTAILQ_ENTRY(Path_List_Entry) path_link;
	CTAILQ_ENTRY(Path_List_Entry) tqe_link;
};
extern __IRAM_SYS_MIDDLE int ip_finish_output3(struct sk_buff *skb, u8 course, u8 imq_flags);

void fp_updateConxTimer(struct Path_List_Entry *ptr);
#if defined(CONFIG_RTL_HW_NAPT_4KENTRY)
void trf_monitor_timeout(unsigned long data);
#else
void fp_monitor_timeout(unsigned long data);
#endif
unsigned int add_fastpath_to_asic(struct sk_buff *skb, struct Path_List_Entry *entry_path);
void deref_srcIp_entry(u_int32_t refIP,__u8 refCount);
#endif	/* __FASTPATH_CORE_H__ */