IPACM: add conntrack optimization for lan2lan module

Add conntrack optimization for IPACM lan2lan module such
that we add offload links only for transmission pairs with
active connections.

Change-Id: I8088c38584dc64e96458737002a52c656c17862b
diff --git a/ipacm/inc/IPACM_ConntrackClient.h b/ipacm/inc/IPACM_ConntrackClient.h
index 51855b6..ef0a2ca 100644
--- a/ipacm/inc/IPACM_ConntrackClient.h
+++ b/ipacm/inc/IPACM_ConntrackClient.h
@@ -75,37 +75,38 @@
 {
 
 private:
-	 static IPACM_ConntrackClient *pInstance;
+   static IPACM_ConntrackClient *pInstance;
 
-	 struct nfct_handle *tcp_hdl;
-	 struct nfct_handle *udp_hdl;
-	 struct nfct_filter *tcp_filter;
-	 struct nfct_filter *udp_filter;
-
-	 static int IPA_Conntrack_Filters_Ignore_Local_Addrs(struct nfct_filter *filter);
-	 static int IPA_Conntrack_Filters_Ignore_Bridge_Addrs(struct nfct_filter *filter);
-	 IPACM_ConntrackClient();
+   struct nfct_handle *tcp_hdl;
+   struct nfct_handle *udp_hdl;
+   struct nfct_filter *tcp_filter;
+   struct nfct_filter *udp_filter;
+   static int IPA_Conntrack_Filters_Ignore_Local_Addrs(struct nfct_filter *filter);
+   static int IPA_Conntrack_Filters_Ignore_Bridge_Addrs(struct nfct_filter *filter);
+   static int IPA_Conntrack_Filters_Ignore_Local_Iface(struct nfct_filter *, ipacm_event_iface_up *);
+   IPACM_ConntrackClient();
 
 public:
-	 static int IPAConntrackEventCB(enum nf_conntrack_msg_type type,
-																	struct nf_conntrack *ct,
-																	void *data);
+   static int IPAConntrackEventCB(enum nf_conntrack_msg_type type,
+                                  struct nf_conntrack *ct,
+                                  void *data);
 
-	 static int IPA_Conntrack_UDP_Filter_Init(void);
-	 static int IPA_Conntrack_TCP_Filter_Init(void);
-	 static void* TCPRegisterWithConnTrack(void *);
-	 static void* UDPRegisterWithConnTrack(void *);
-	 static void* UDPConnTimeoutUpdate(void *);
-	 static void* TCPUDP_Timeout_monitor(void *);
+   static int IPA_Conntrack_UDP_Filter_Init(void);
+   static int IPA_Conntrack_TCP_Filter_Init(void);
+   static void* TCPRegisterWithConnTrack(void *);
+   static void* UDPRegisterWithConnTrack(void *);
+   static void* UDPConnTimeoutUpdate(void *);
+   static void* TCPUDP_Timeout_monitor(void *);
 
-	 static void UpdateUDPFilters(void *);
-	 static void UpdateTCPFilters(void *);
-	 static void Read_TcpUdp_Timeout(char *in, int len);
+   static void UpdateUDPFilters(void *, bool);
+   static void UpdateTCPFilters(void *, bool);
+   static void Read_TcpUdp_Timeout(char *in, int len);
 
-	 static IPACM_ConntrackClient* GetInstance();
+   static IPACM_ConntrackClient* GetInstance();
 
 #ifdef IPACM_DEBUG
-	 static void iptodot(const char *type, uint32_t ipAddr);
+#define iptodot(X,Y) \
+		 IPACMLOG(" %s(0x%x): %d.%d.%d.%d\n", X, Y, ((Y>>24) & 0xFF), ((Y>>16) & 0xFF), ((Y>>8) & 0xFF), (Y & 0xFF));
 #endif
 
 };
diff --git a/ipacm/inc/IPACM_ConntrackListener.h b/ipacm/inc/IPACM_ConntrackListener.h
index cc16f86..fc7282c 100644
--- a/ipacm/inc/IPACM_ConntrackListener.h
+++ b/ipacm/inc/IPACM_ConntrackListener.h
@@ -43,6 +43,9 @@
 #include "IPACM_CmdQueue.h"
 #include "IPACM_Conntrack_NATApp.h"
 #include "IPACM_Listener.h"
+#ifdef CT_OPT
+#include "IPACM_LanToLan.h"
+#endif
 
 #define MAX_NAT_IFACES 50
 
@@ -53,6 +56,7 @@
 
 private:
 	 bool isCTReg;
+	 bool isNatThreadStart;
 	 bool WanUp;
 	 NatApp *nat_inst;
 
@@ -61,15 +65,23 @@
 	 uint32_t nat_iface_ipv4_addr[MAX_NAT_IFACES];
 	 uint32_t nonnat_iface_ipv4_addr[MAX_NAT_IFACES];
 	 IPACM_Config *pConfig;
+#ifdef CT_OPT
+	 IPACM_LanToLan *p_lan2lan;
+#endif
 	 
-	 void ProcessCTMessage(void *data);
-	 void ProcessTCPorUDPMsg(struct nf_conntrack *, enum nf_conntrack_msg_type, u_int8_t);
+	 void ProcessCTMessage(void *);
+	 void ProcessTCPorUDPMsg(struct nf_conntrack *,
+			enum nf_conntrack_msg_type, u_int8_t);
 	 void TriggerWANUp(void *);
 	 void TriggerWANDown(uint32_t);
 	 int  CreateNatThreads(void);
+	 int  CreateConnTrackThreads(void);
 
 	 void HandleNeighIpAddrAddEvt(void *);
 	 void HandleNeighIpAddrDelEvt(void *);
+#ifdef CT_OPT
+	 void ProcessCTV6Message(void *);
+#endif
 
 public:
 	 char wan_ifname[IPA_IFACE_NAME_LEN];
@@ -80,8 +92,10 @@
 	 void event_callback(ipa_cm_event_id, void *data);
 	 inline bool isWanUp()
 	 {
-			return WanUp;
+		return WanUp;
 	 }
 };
 
+extern IPACM_ConntrackListener *CtList;
+
 #endif /* IPACM_CONNTRACK_LISTENER */
diff --git a/ipacm/inc/IPACM_Defs.h b/ipacm/inc/IPACM_Defs.h
index 9b9a55b..b5adff3 100644
--- a/ipacm/inc/IPACM_Defs.h
+++ b/ipacm/inc/IPACM_Defs.h
@@ -51,7 +51,7 @@
 #include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
 }
 
-
+#define IF_NAME_LEN 16
 #define IPA_MAX_FILE_LEN  64
 #define IPA_IFACE_NAME_LEN 16
 #define IPA_ALG_PROTOCOL_NAME_LEN  10
@@ -92,6 +92,10 @@
 #define IPA_LAN_TO_LAN_WLAN_HDR_NAME_V6 "Lan2Lan_Wlan_v6"
 #define IPA_LAN_TO_LAN_MAX_WLAN_CLIENT 32
 #define IPA_LAN_TO_LAN_MAX_USB_CLIENT 1
+#define TCP_FIN_SHIFT 16
+#define TCP_SYN_SHIFT 17
+#define TCP_RST_SHIFT 18
+#define NUM_TCP_CTL_FLT_RULE 3
 
 /*---------------------------------------------------------------------------
 										Return values indicating error status
@@ -151,6 +155,7 @@
 	IPA_LAN_DELETE_SELF,					  /* 36 ipacm_event_data_fid */
 	IPA_WLAN_LINK_DOWN_EVENT,                 /* 37 ipacm_event_data_mac */
 	IPA_USB_LINK_UP_EVENT,                    /* 38 ipacm_event_data_fid */
+	IPA_PROCESS_CT_MESSAGE_V6,				  /* 39 ipacm_ct_evt_data */
 	IPACM_EVENT_MAX
 } ipa_cm_event_id;
 
diff --git a/ipacm/inc/IPACM_Iface.h b/ipacm/inc/IPACM_Iface.h
index 2f36714..eb9e265 100644
--- a/ipacm/inc/IPACM_Iface.h
+++ b/ipacm/inc/IPACM_Iface.h
@@ -49,7 +49,6 @@
 #include "IPACM_EvtDispatcher.h"
 #include "IPACM_Xml.h"
 #include "IPACM_Log.h"
-#include "IPACM_Netlink.h"
 #include "IPACM_Config.h"
 #include "IPACM_Defs.h"
 
diff --git a/ipacm/inc/IPACM_Lan.h b/ipacm/inc/IPACM_Lan.h
index 6c41863..7f5229e 100644
--- a/ipacm/inc/IPACM_Lan.h
+++ b/ipacm/inc/IPACM_Lan.h
@@ -177,6 +177,11 @@
 	/* store ipv6 UL filter rule handlers from Q6*/
 	uint32_t wan_ul_fl_rule_hdl_v6[MAX_WAN_UL_FILTER_RULES];
 
+	virtual void install_tcp_ctl_flt_rule(ipa_ip_type iptype);
+
+	uint32_t tcp_ctl_flt_rule_hdl_v4[NUM_TCP_CTL_FLT_RULE];
+	uint32_t tcp_ctl_flt_rule_hdl_v6[NUM_TCP_CTL_FLT_RULE];
+
 	int num_wan_ul_fl_rule_v4;
 	int num_wan_ul_fl_rule_v6;
 
diff --git a/ipacm/inc/IPACM_LanToLan.h b/ipacm/inc/IPACM_LanToLan.h
index dba7fd5..480f76c 100644
--- a/ipacm/inc/IPACM_LanToLan.h
+++ b/ipacm/inc/IPACM_LanToLan.h
@@ -97,6 +97,11 @@
 		IPACM_LanToLan();
 		~IPACM_LanToLan();
 
+		void handle_new_connection(ipacm_event_connection* new_conn);
+		void handle_del_connection(ipacm_event_connection* del_conn);
+
+		static IPACM_LanToLan* getLan2LanInstance();
+
 private:
 
 		uint8_t num_offload_pair_v4_;
@@ -104,6 +109,8 @@
 		client_table_v4 client_info_v4_;
 		client_table_v6 client_info_v6_;
 
+		static IPACM_LanToLan* p_instance;
+
 		void event_callback(ipa_cm_event_id event, void* param);
 
 		void handle_client_active(ipacm_event_lan_client* data);
@@ -131,11 +138,12 @@
 		int add_flt_rules(ipa_ip_type iptype, client_info* client);
 
 //the following are for connections
-		void handle_new_connection(ipacm_event_connection* data);
+
+		void handle_new_lan2lan_connection(ipacm_event_connection* data);
 
 		bool add_connection(client_info* src_client, client_info* dst_client);
 
-		void handle_del_connection(ipacm_event_connection* data);
+		void handle_del_lan2lan_connection(ipacm_event_connection* data);
 
 		bool remove_connection(client_info* src_client, client_info* dst_client);
 
@@ -143,6 +151,8 @@
 
 		void generate_new_connection(ipa_ip_type iptype, client_info* client);
 
+		bool is_lan2lan_connection(ipacm_event_connection* data);
+
 };
 
 #endif
diff --git a/ipacm/inc/IPACM_Log.h b/ipacm/inc/IPACM_Log.h
index 54be34a..c54d05b 100644
--- a/ipacm/inc/IPACM_Log.h
+++ b/ipacm/inc/IPACM_Log.h
@@ -59,8 +59,12 @@
 #ifdef DEBUG
 #define IPACMDBG(fmt, ...) syslog(LOG_DEBUG, "%s:%d %s() " fmt, __FILE__,  __LINE__, __FUNCTION__, ##__VA_ARGS__);\
                            printf("%s:%d %s() " fmt, __FILE__,  __LINE__, __FUNCTION__, ##__VA_ARGS__);
+
+#define IPACMLOG(fmt, ...) syslog(LOG_DEBUG, fmt, ##__VA_ARGS__);\
+                           printf(fmt, ##__VA_ARGS__);
 #else
 #define IPACMDBG(fmt, ...)
+#define IPACMLOG(fmt, ...)
 #endif
 
 
diff --git a/ipacm/inc/IPACM_Netlink.h b/ipacm/inc/IPACM_Netlink.h
index 8665407..d379031 100644
--- a/ipacm/inc/IPACM_Netlink.h
+++ b/ipacm/inc/IPACM_Netlink.h
@@ -60,8 +60,6 @@
 
 #define MAX_NUM_OF_FD 10
 #define IPA_NL_MSG_MAX_LEN (2048)
-#define IF_NAME_LEN 16
-
 
 /*--------------------------------------------------------------------------- 
 	 Type representing enumeration of NetLink event indication messages
diff --git a/ipacm/inc/IPACM_Wlan.h b/ipacm/inc/IPACM_Wlan.h
index b351a68..ce875e0 100644
--- a/ipacm/inc/IPACM_Wlan.h
+++ b/ipacm/inc/IPACM_Wlan.h
@@ -250,6 +250,8 @@
 
 	/* install UL filter rule from Q6 */
 	virtual int handle_uplink_filter_rule(ipacm_ext_prop* prop, ipa_ip_type iptype);
+
+	virtual void install_tcp_ctl_flt_rule(ipa_ip_type iptype);
 };
 
 
diff --git a/ipacm/src/IPACM_Config.cpp b/ipacm/src/IPACM_Config.cpp
index bace803..c8d145a 100644
--- a/ipacm/src/IPACM_Config.cpp
+++ b/ipacm/src/IPACM_Config.cpp
@@ -263,6 +263,7 @@
 		if (res != IPACM_SUCCESS)
 		{
 			delete pInstance;
+			IPACMERR("unable to initialize config instance\n");
 			return NULL;
 		}
 	}
diff --git a/ipacm/src/IPACM_ConntrackClient.cpp b/ipacm/src/IPACM_ConntrackClient.cpp
index 75c4c2e..457e48a 100644
--- a/ipacm/src/IPACM_ConntrackClient.cpp
+++ b/ipacm/src/IPACM_ConntrackClient.cpp
@@ -43,31 +43,15 @@
 #define LO_NAME "lo"
 
 extern IPACM_EvtDispatcher cm_dis;
+extern void ParseCTMessage(struct nf_conntrack *ct);
 
-IPACM_ConntrackClient *IPACM_ConntrackClient::pInstance = IPACM_ConntrackClient::GetInstance();
-IPACM_ConntrackListener *CtList = new IPACM_ConntrackListener();
+IPACM_ConntrackClient *IPACM_ConntrackClient::pInstance = NULL;
+IPACM_ConntrackListener *CtList = NULL;
 
 /* ================================
 		 Local Function Definitions
 		 =================================
 */
-#ifdef IPACM_DEBUG
-void IPACM_ConntrackClient::iptodot(const char *type, uint32_t ipAddr)
-{
-	int i;
-	unsigned char octet[4] = { 0 };
-	IPACMDBG("Received IPv4 addr: 0x%x\n", ipAddr);
-
-	for(i = 0; i < 4; i++)
-	{
-		octet[i] = (ipAddr >> (i * 8)) & 0xFF;
-	}
-
-	IPACMDBG("%s:", type);
-	IPACMDBG("%d.%d.%d.%d\n", octet[3], octet[2], octet[1], octet[0]);
-}
-#endif
-
 IPACM_ConntrackClient::IPACM_ConntrackClient()
 {
 	IPACMDBG("\n");
@@ -106,7 +90,6 @@
 	return pInstance;
 }
 
-extern void ParseCTMessage(struct nf_conntrack *ct);
 int IPACM_ConntrackClient::IPAConntrackEventCB
 (
 	 enum nf_conntrack_msg_type type,
@@ -116,21 +99,34 @@
 {
 	ipacm_cmd_q_data evt_data;
 	ipacm_ct_evt_data *ct_data;
+	uint8_t ip_type = 0;
 
 	IPACMDBG("Event callback called with msgtype: %d\n",type);
 
+	/* Retrieve ip type */
+	ip_type = nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO);
+
+#ifndef CT_OPT
+	if(AF_INET6 == ip_type)
+	{
+		IPACMDBG("Ignoring ipv6(%d) connections\n", ip_type);
+		goto IGNORE;
+	}
+
 	if(!CtList->isWanUp())
 	{
 #ifdef IPACM_DEBUG
+		IPACMDBG("Wan is not up, ignoring below connections\n");
 		char buf[1024];
 		nfct_snprintf(buf, sizeof(buf), ct,
 									type, NFCT_O_PLAIN, NFCT_OF_TIME);
-	  IPACMDBG("%s\n", buf);
-	  IPACMDBG("\n");
+		IPACMDBG("%s\n", buf);
+		IPACMDBG("\n");
 		ParseCTMessage(ct);
 #endif
 		goto IGNORE;
 	}
+#endif
 
 	ct_data = (ipacm_ct_evt_data *)malloc(sizeof(ipacm_ct_evt_data));
 	if(ct_data == NULL)
@@ -145,6 +141,13 @@
 	evt_data.event = IPA_PROCESS_CT_MESSAGE;
 	evt_data.evt_data = (void *)ct_data;
 
+#ifdef CT_OPT
+	if(AF_INET6 == ip_type)
+	{
+		evt_data.event = IPA_PROCESS_CT_MESSAGE_V6;
+	}
+#endif
+
 	if(0 != IPACM_EvtDispatcher::PostEvt(&evt_data))
 	{
 		IPACMERR("Error sending Conntrack message to processing thread!\n");
@@ -215,6 +218,56 @@
   return 0;
 }
 
+int IPACM_ConntrackClient::IPA_Conntrack_Filters_Ignore_Local_Iface
+(
+	 struct nfct_filter *filter,
+	 ipacm_event_iface_up *param
+)
+{
+	struct nfct_filter_ipv4 filter_ipv4;
+
+	filter_ipv4.addr = param->ipv4_addr;
+	filter_ipv4.mask = 0xffffffff;
+
+	/* ignore whatever is destined to local interfaces */
+	IPACMDBG("Ignore connections destinated to interface %s", param->ifname);
+	iptodot("with ipv4 address", param->ipv4_addr);
+	nfct_filter_set_logic(filter,
+												NFCT_FILTER_DST_IPV4,
+												NFCT_FILTER_LOGIC_NEGATIVE);
+
+	nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+	IPACMDBG("Ignore connections orignated from interface %s", param->ifname);
+	iptodot("with ipv4 address", filter_ipv4.addr);
+	nfct_filter_set_logic(filter,
+												NFCT_FILTER_SRC_IPV4,
+												NFCT_FILTER_LOGIC_NEGATIVE);
+
+	nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
+
+	/* Retrieve broadcast address */
+	/* Intialize with 255.255.255.255 */
+	uint32_t bc_ip_addr = 0xFFFFFFFF;
+
+	/* calculate broadcast address from addr and addr_mask */
+	bc_ip_addr = (bc_ip_addr & (~param->addr_mask));
+	bc_ip_addr = (bc_ip_addr | (param->ipv4_addr & param->addr_mask));
+
+	/* netfitler expecting in host-byte order */
+	filter_ipv4.addr = bc_ip_addr;
+	filter_ipv4.mask = 0xffffffff;
+
+	iptodot("with broadcast address", filter_ipv4.addr);
+	nfct_filter_set_logic(filter,
+												NFCT_FILTER_DST_IPV4,
+												NFCT_FILTER_LOGIC_NEGATIVE);
+
+	nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+	return 0;
+}
+
 /* Function which sets up filters to ignore
 		 connections to and from local interfaces */
 int IPACM_ConntrackClient::IPA_Conntrack_Filters_Ignore_Local_Addrs
@@ -222,10 +275,6 @@
 	 struct nfct_filter *filter
 )
 {
-	char   buf[1024];
-	struct ifconf ifc;
-	struct ifreq *ifr;
-	int    i, sck, nInterfaces;
 	struct nfct_filter_ipv4 filter_ipv4;
 
 	/* ignore whatever is destined to or originates from broadcast ip address */
@@ -244,124 +293,6 @@
 
 	nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
 
-
-
-	/* Get a socket handle. */
-	sck = socket(AF_INET, SOCK_DGRAM, 0);
-	if(sck < 0)
-	{
-		PERROR("socket");
-		return -1;
-	}
-
-	/* Query available interfaces. */
-	ifc.ifc_len = sizeof(buf);
-	ifc.ifc_buf = buf;
-
-	/* get iface list */
-	if(ioctl(sck, SIOCGIFCONF, &ifc) < 0)
-	{
-		PERROR("ioctl(SIOCGIFCONF)");
-		close(sck);
-		return -1;
-	}
-
-	/* Iterate through the list of interfaces. */
-	ifr         = ifc.ifc_req;
-	nInterfaces = ifc.ifc_len / sizeof(struct ifreq);
-
-#ifdef IPACM_DEBUG
-	IPACMDBG("====Printing Local Interfaces=====\n");
-#endif
-
-	for(i = 0; i < nInterfaces; i++)
-	{
-		/* Interface request structure */
-		struct ifreq *item = &ifr[i];
-
-#ifdef IPACM_DEBUG
-		/* Show the device name and IP address */
-		if(item->ifr_name != NULL)
-		{
-			IPACMDBG("%s: IP %s\n",
-							 item->ifr_name,
-							 inet_ntoa(((struct sockaddr_in *)&item->ifr_addr)->sin_addr));
-		}
-#endif
-
-		/* Convert data to host-byte order */
-		filter_ipv4.addr =
-			 ntohl(inet_addr(inet_ntoa(((struct sockaddr_in *)&item->ifr_addr)->sin_addr)));
-		filter_ipv4.mask = 0xffffffff;
-
-		if(item->ifr_name != NULL)
-		{
-			/* check whether interface is non wan iface */
-			if(strncmp(CtList->wan_ifname, item->ifr_name, strlen(item->ifr_name)) != 0)
-			{
-				/* ignore whatever is destined to local interfaces */
-				IPACMDBG("ignore connections destinated to interface %s\n", item->ifr_name);
-				IPACM_ConntrackClient::iptodot("with ipv4 address:", filter_ipv4.addr);
-				nfct_filter_set_logic(filter,
-															NFCT_FILTER_DST_IPV4,
-															NFCT_FILTER_LOGIC_NEGATIVE);
-
-				nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
-
-				/* In AP+STA mode only listen to connections orignated from local interface */
-        if(!CtList->isStaMode) {
-					IPACMDBG("ignore connections orignated from interface %s\n", item->ifr_name);
-					IPACM_ConntrackClient::iptodot("with ipv4 address:", filter_ipv4.addr);
-					nfct_filter_set_logic(filter,
-																NFCT_FILTER_SRC_IPV4,
-																NFCT_FILTER_LOGIC_NEGATIVE);
-
-					nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
-				}
-
-			}
-		}
-
-		/* Find broadcast address for non lo interfaces */
-		if(strncmp(LO_NAME, item->ifr_name, 2) != 0)
-		{
-			/* Get the broadcast address */
-			if(ioctl(sck, SIOCGIFBRDADDR, item) < 0)
-			{
-				PERROR("broadcast address error: ioctl(SIOCGIFBRDADDR)");
-				close(sck);
-				return -1;
-			}
-
-#ifdef IPACM_DEBUG
-			/* Show the device name and IP address */
-			if(item->ifr_name != NULL)
-			{
-				IPACMDBG("%s: BroadCast IP %s\n",
-								 item->ifr_name,
-								 inet_ntoa(((struct sockaddr_in *)&item->ifr_broadaddr)->sin_addr));
-			}
-#endif
-
-			/* Convert data to host-byte order */
-			filter_ipv4.addr =
-				 ntohl(inet_addr(inet_ntoa(((struct sockaddr_in *)&item->ifr_broadaddr)->sin_addr)));
-			filter_ipv4.mask = 0xffffffff;
-			
-			IPACMDBG("ignore connections destinated to interface %s broadcast\n", item->ifr_name);
-			IPACM_ConntrackClient::iptodot("with ipv4 address:", filter_ipv4.addr);
-			nfct_filter_set_logic(filter,
-														NFCT_FILTER_DST_IPV4,
-														NFCT_FILTER_LOGIC_NEGATIVE);
-
-			nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
-		}
-
-	}
-
-	close(sck);
-	IPA_Conntrack_Filters_Ignore_Bridge_Addrs(filter);
-
 	return 0;
 } /* IPA_Conntrack_Filters_Ignore_Local_Addrs() */
 
@@ -380,13 +311,6 @@
 		return -1;
 	}
 
-	ret = IPA_Conntrack_Filters_Ignore_Local_Addrs(pClient->tcp_filter);
-	if(ret == -1)
-	{
-		IPACMERR("Unable to set local addr filters\n");
-		return -1;
-	}
-
 	ret = nfct_filter_set_logic(pClient->tcp_filter,
 															NFCT_FILTER_L4PROTO,
 															NFCT_FILTER_LOGIC_POSITIVE);
@@ -440,11 +364,9 @@
 {
 	int ret = 0;
 	IPACM_ConntrackClient *pClient = IPACM_ConntrackClient::GetInstance();
-
-	ret = IPA_Conntrack_Filters_Ignore_Local_Addrs(pClient->udp_filter);
-	if(ret == -1)
+	if(pClient == NULL)
 	{
-		IPACMERR("Unable to set local addr filters\n");
+		IPACMERR("unable to get conntrack client instance\n");
 		return -1;
 	}
 
@@ -494,6 +416,7 @@
 {
 	int ret;
 	IPACM_ConntrackClient *pClient;
+	unsigned subscrips = 0;
 
 	IPACMDBG("\n");
 
@@ -504,24 +427,18 @@
 		return NULL;
 	}
 
-	pClient->tcp_hdl = nfct_open(CONNTRACK, 
-						(NF_NETLINK_CONNTRACK_UPDATE |NF_NETLINK_CONNTRACK_DESTROY));
+	subscrips = (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY);
+#ifdef CT_OPT
+	subscrips |= NF_NETLINK_CONNTRACK_NEW;
+#endif
+
+	pClient->tcp_hdl = nfct_open(CONNTRACK, subscrips);
 	if(pClient->tcp_hdl == NULL)
 	{
 		PERROR("nfct_open\n");
 		return NULL;
 	}
 
-	/* Allocate new filter */
-	#if 0
-	pClient->tcp_filter = nfct_filter_create();
-	if(pClient->tcp_filter == NULL)
-	{
-		IPACMERR("unable to create TCP filter\n");
-		return NULL;
-	}
-	#endif
-
 	/* Initialize the filter */
 	ret = IPA_Conntrack_TCP_Filter_Init();
 	if(ret == -1)
@@ -531,8 +448,7 @@
 	}
 
 	/* Attach the filter to net filter handler */
-	ret = nfct_filter_attach(nfct_fd(pClient->tcp_hdl),
-													 pClient->tcp_filter);
+	ret = nfct_filter_attach(nfct_fd(pClient->tcp_hdl), pClient->tcp_filter);
 	if(ret == -1)
 	{
 		IPACMDBG("unable to attach TCP filter\n");
@@ -541,8 +457,13 @@
 
 	/* Register callback with netfilter handler */
 	IPACMDBG("tcp handle:%p, fd:%d\n", pClient->tcp_hdl, nfct_fd(pClient->tcp_hdl));
+#ifndef CT_OPT
 	nfct_callback_register(pClient->tcp_hdl, 
-				(NFCT_T_UPDATE | NFCT_T_DESTROY), IPAConntrackEventCB, NULL);
+				(NFCT_T_UPDATE | NFCT_T_DESTROY | NFCT_T_NEW),
+						IPAConntrackEventCB, NULL);
+#else
+	nfct_callback_register(pClient->tcp_hdl, NFCT_T_ALL, IPAConntrackEventCB, NULL);
+#endif
 
 	/* Block to catch events from net filter connection track */
 	/* nfct_catch() receives conntrack events from kernel-space, by default it 
@@ -619,7 +540,7 @@
 												 NULL);
 
 	/* Block to catch events from net filter connection track */
-	ctcatch:
+ctcatch:
 	ret = nfct_catch(pClient->udp_hdl);
 	if(ret == -1)
 	{
@@ -648,21 +569,12 @@
 	return NULL;
 }
 
-void IPACM_ConntrackClient::UpdateUDPFilters(void *param)
+void IPACM_ConntrackClient::UpdateUDPFilters(void *param, bool isWan)
 {
+	static bool isIgnore = false;
 	int ret = 0;
-	struct nfct_filter_ipv4 filter_ipv4;
 	IPACM_ConntrackClient *pClient = NULL;
 
-	/* Intialize with 255.255.255.255 */
-	uint32_t bc_ip_addr = 0xFFFFFFFF;
-
-	uint32_t ipv4_addr = ((ipacm_event_iface_up *)param)->ipv4_addr;
-  uint32_t ipv4_addr_mask = ((ipacm_event_iface_up *)param)->addr_mask;
-
-	IPACM_ConntrackClient::iptodot("Received ipv4 address and", ipv4_addr);
-	IPACM_ConntrackClient::iptodot("ipv4 address mask", ipv4_addr_mask);
-
 	pClient = IPACM_ConntrackClient::GetInstance();
 	if(pClient == NULL)
 	{
@@ -670,43 +582,22 @@
 		return;
 	}
 
-	/* calculate broadcast address from addr and addr_mask */
-	bc_ip_addr = (bc_ip_addr & (~ipv4_addr_mask));
-	bc_ip_addr = (bc_ip_addr | (ipv4_addr & ipv4_addr_mask));
-
-	/* netfitler expecting in host-byte order */
-	filter_ipv4.addr = ipv4_addr;
-  filter_ipv4.mask = 0xffffffff;
-
-	IPACMDBG("ignoring interface:%s", ((ipacm_event_iface_up *)param)->ifname);
-	IPACM_ConntrackClient::iptodot("with ipv4 address", filter_ipv4.addr);
-	if(pClient->udp_filter != NULL)
+	if(pClient->udp_filter == NULL)
 	{
-		nfct_filter_set_logic(pClient->udp_filter,
-													NFCT_FILTER_DST_IPV4,
-													NFCT_FILTER_LOGIC_NEGATIVE);
-
-		nfct_filter_add_attr(pClient->udp_filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
-
-		nfct_filter_set_logic(pClient->udp_filter,
-													NFCT_FILTER_SRC_IPV4,
-													NFCT_FILTER_LOGIC_NEGATIVE);
-
-		nfct_filter_add_attr(pClient->udp_filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
+		 return;
 	}
 
-  /* netfitler expecting in host-byte order */
-	filter_ipv4.addr = bc_ip_addr;
-	filter_ipv4.mask = 0xffffffff; 
-
-	IPACM_ConntrackClient::iptodot("with broadcast address", filter_ipv4.addr);
-  if(pClient->udp_filter != NULL)
+	if(!isWan)
 	{
-		nfct_filter_set_logic(pClient->udp_filter,
-													NFCT_FILTER_DST_IPV4,
-													NFCT_FILTER_LOGIC_NEGATIVE);
+		IPA_Conntrack_Filters_Ignore_Local_Iface(pClient->udp_filter,
+																		 (ipacm_event_iface_up *)param);
 
-		nfct_filter_add_attr(pClient->udp_filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+		if(!isIgnore)
+		{
+			IPA_Conntrack_Filters_Ignore_Bridge_Addrs(pClient->udp_filter);
+			IPA_Conntrack_Filters_Ignore_Local_Addrs(pClient->udp_filter);
+			isIgnore = true;
+		}
 	}
 
 	/* Attach the filter to udp handle */
@@ -725,15 +616,11 @@
 	return;
 }
 
-void IPACM_ConntrackClient::UpdateTCPFilters(void *param)
+void IPACM_ConntrackClient::UpdateTCPFilters(void *param, bool isWan)
 {
+	static bool isIgnore = false;
 	int ret = 0;
-	uint32_t ipv4_addr = ((ipacm_event_iface_up *)param)->ipv4_addr;
-  uint32_t ipv4_addr_mask = ((ipacm_event_iface_up *)param)->addr_mask;
-	struct nfct_filter_ipv4 filter_ipv4;
 	IPACM_ConntrackClient *pClient = NULL;
-	/* Intialize with 255.255.255.255 */
-	uint32_t bc_ip_addr = 0xFFFFFFFF;
 
 	pClient = IPACM_ConntrackClient::GetInstance();
 	if(pClient == NULL)
@@ -742,44 +629,20 @@
 		return;
 	}
 
-	/* calculate broadcast address from addr and addr_mask */
-	bc_ip_addr = (bc_ip_addr & (~ipv4_addr_mask));
-	bc_ip_addr = (bc_ip_addr | (ipv4_addr & ipv4_addr_mask));
+	if(pClient->tcp_filter == NULL)
+		return;
 
-	/* netfitler expecting in host-byte order */
-	filter_ipv4.addr = ipv4_addr;
-  filter_ipv4.mask = 0xffffffff;
-
-	IPACMDBG("ignoring interface:%s", ((ipacm_event_iface_up *)param)->ifname);
-	IPACM_ConntrackClient::iptodot("with ipv4 address", filter_ipv4.addr);
-
-  if(pClient->tcp_filter != NULL)
+	if(!isWan)
 	{
-		nfct_filter_set_logic(pClient->tcp_filter,
-													NFCT_FILTER_DST_IPV4,
-													NFCT_FILTER_LOGIC_NEGATIVE);
+		IPA_Conntrack_Filters_Ignore_Local_Iface(pClient->tcp_filter,
+																	(ipacm_event_iface_up *)param);
 
-		nfct_filter_add_attr(pClient->tcp_filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
-
-		nfct_filter_set_logic(pClient->tcp_filter,
-													NFCT_FILTER_SRC_IPV4,
-													NFCT_FILTER_LOGIC_NEGATIVE);
-
-		nfct_filter_add_attr(pClient->tcp_filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
-	}
-
-  /* netfitler expecting in host-byte order */
-	filter_ipv4.addr = bc_ip_addr;
-	filter_ipv4.mask = 0xffffffff; 
-
-	IPACM_ConntrackClient::iptodot("with broadcast address", filter_ipv4.addr);
-  if(pClient->tcp_filter != NULL)
-	{
-		nfct_filter_set_logic(pClient->tcp_filter,
-													NFCT_FILTER_DST_IPV4,
-													NFCT_FILTER_LOGIC_NEGATIVE);
-
-		nfct_filter_add_attr(pClient->tcp_filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+		if(!isIgnore)
+		{
+			IPA_Conntrack_Filters_Ignore_Bridge_Addrs(pClient->udp_filter);
+			IPA_Conntrack_Filters_Ignore_Local_Addrs(pClient->udp_filter);
+			isIgnore = true;
+		}
 	}
 
 	/* Attach the filter to tcp handle */
@@ -810,7 +673,7 @@
 	if(nat_inst == NULL)
 	{
 		IPACMERR("unable to create nat instance\n");
-		return NULL;
+		return;
 	}
 
 	if(!strncmp(in, IPACM_TCP_FILE_NAME, len))
@@ -834,7 +697,7 @@
 	{
 		fd = fopen(IPACM_UDP_FULL_FILE_NAME, "r");
 	}
-	if(fd < 0)
+	if(fd == NULL)
 	{
 		PERROR("unable to open file");
 		return;
@@ -869,7 +732,7 @@
 	}
 	
 	to_fd = fopen(IPACM_TCP_FULL_FILE_NAME, "r");
-	if(to_fd < 0)
+	if(to_fd == NULL)
 	{
 	  PERROR("unable to open file \"ip_conntrack_tcp_timeout_established\" ");
 		return NULL;
@@ -882,7 +745,7 @@
 	fclose(to_fd);
 	
 	to_fd = fopen(IPACM_UDP_FULL_FILE_NAME, "r");
-	if(to_fd < 0)
+	if(to_fd == NULL)
 	{
 	  PERROR("unable to open file \"ip_conntrack_udp_timeout_stream\" ");
 		return NULL;
diff --git a/ipacm/src/IPACM_ConntrackListener.cpp b/ipacm/src/IPACM_ConntrackListener.cpp
index c5f94a2..0d53841 100644
--- a/ipacm/src/IPACM_ConntrackListener.cpp
+++ b/ipacm/src/IPACM_ConntrackListener.cpp
@@ -1,4 +1,4 @@
-/* 
+/*
 Copyright (c) 2013, The Linux Foundation. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -38,6 +38,7 @@
 {
 	 IPACMDBG("\n");
 
+	 isNatThreadStart = false;
 	 isCTReg = false;
 	 WanUp = false;
 	 nat_inst = NatApp::GetInstance();
@@ -52,9 +53,18 @@
 	 IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, this);
 	 IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, this);
 	 IPACM_EvtDispatcher::registr(IPA_PROCESS_CT_MESSAGE, this);
+	 IPACM_EvtDispatcher::registr(IPA_PROCESS_CT_MESSAGE_V6, this);
 	 IPACM_EvtDispatcher::registr(IPA_HANDLE_WLAN_UP, this);
+	 IPACM_EvtDispatcher::registr(IPA_HANDLE_LAN_UP, this);
 	 IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, this);
 	 IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT, this);
+
+	IPACMDBG("creating conntrack threads\n");
+	CreateConnTrackThreads();
+
+#ifdef CT_OPT
+	 p_lan2lan = IPACM_LanToLan::getLan2LanInstance();
+#endif
 }
 
 void IPACM_ConntrackListener::event_callback(ipa_cm_event_id evt,
@@ -75,6 +85,13 @@
 			ProcessCTMessage(data);
 			break;
 
+#ifdef CT_OPT
+	 case IPA_PROCESS_CT_MESSAGE_V6:
+			IPACMDBG("Received IPA_PROCESS_CT_MESSAGE_V6 event\n");
+			ProcessCTV6Message(data);
+			break;
+#endif
+
 	 case IPA_HANDLE_WAN_UP:
 			IPACMDBG("Received IPA_HANDLE_WAN_UP event\n");
 			if(!isWanUp())
@@ -96,13 +113,12 @@
 		 tcp/udp filters to ignore local wlan or lan connections */
 	 case IPA_HANDLE_WLAN_UP:
 	 case IPA_HANDLE_LAN_UP:
-			IPACMDBG("Received event: %d\n", evt);
-			if(isWanUp())
-			{
-				 IPACM_ConntrackClient::UpdateUDPFilters(data);
-				 IPACM_ConntrackClient::UpdateTCPFilters(data);
-			}
-			break; 
+			IPACMDBG("Received event: %d with ifname: %s and address: 0x%x\n",
+							 evt, ((ipacm_event_iface_up *)data)->ifname,
+							 ((ipacm_event_iface_up *)data)->ipv4_addr);
+   		IPACM_ConntrackClient::UpdateUDPFilters(data, false);
+			IPACM_ConntrackClient::UpdateTCPFilters(data, false);
+			break;
 
 	 case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
 		 {
@@ -123,7 +139,6 @@
 			break;
 	 }
 }
-
 void IPACM_ConntrackListener::HandleNeighIpAddrAddEvt(void *in_param)
 {
 	ipacm_event_data_all *data = (ipacm_event_data_all *)in_param;
@@ -136,8 +151,8 @@
 		IPACMDBG("Ignoring IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT EVENT\n");
 		return;
 	}
-	IPACMDBG("Received interface index %d with ip type:%d", data->if_index, data->iptype);
-	IPACM_ConntrackClient::iptodot("and received ipv4 address", data->ipv4_addr);
+	IPACMDBG("Received interface index %d with ip type: %d", data->if_index, data->iptype);
+	iptodot(" and ipv4 address", data->ipv4_addr);
 
 	if(pConfig == NULL)
 	{
@@ -219,9 +234,16 @@
 				}
 			}
 
+			if(j == MAX_NAT_IFACES)
+			{
+				IPACMERR("Nat ifaces(%d) exceed maximum\n", j);
+				break;
+			}
+
+
 			isNatIface = true;
-			IPACMDBG("Nating connections of Interface (%s), entry (%d)\n", pNatIfaces[i].iface_name, j);
-			IPACM_ConntrackClient::iptodot("with ipv4 address", nat_iface_ipv4_addr[j]);
+			IPACMDBG("Nating connections of Interface (%s), entry (%d) ", pNatIfaces[i].iface_name, j);
+			iptodot("with ipv4 address", nat_iface_ipv4_addr[j]);
 			break;
 		}
 	}
@@ -259,15 +281,15 @@
 	{
 		if(nat_iface_ipv4_addr[cnt] == data->ipv4_addr)
 		{
-			IPACMDBG("Reseting ct filters of Interface (%d), entry (%d)\n", data->if_index, cnt);
-			IPACM_ConntrackClient::iptodot("with ipv4 address", nat_iface_ipv4_addr[cnt]);
+			IPACMDBG("Reseting ct filters of Interface (%d), entry (%d) ", data->if_index, cnt);
+			iptodot("with ipv4 address", nat_iface_ipv4_addr[cnt]);
 			nat_iface_ipv4_addr[cnt] = 0;
 		}
 
 		if(nonnat_iface_ipv4_addr[cnt] == data->ipv4_addr)
 		{
-			IPACMDBG("Reseting ct filters of Interface (%d), entry (%d)\n", data->if_index, cnt);
-			IPACM_ConntrackClient::iptodot("with ipv4 address", nonnat_iface_ipv4_addr[cnt]);
+			IPACMDBG("Reseting ct filters of Interface (%d), entry (%d) ", data->if_index, cnt);
+			iptodot("with ipv4 address", nonnat_iface_ipv4_addr[cnt]);
 			nonnat_iface_ipv4_addr[cnt] = 0;
 		}
 	}
@@ -280,7 +302,7 @@
 {
 	 ipacm_event_iface_up *wanup_data = (ipacm_event_iface_up *)in_param;
 
-	 IPACMDBG("Recevied below informatoin during wanup:\n");
+	 IPACMDBG("Recevied below information during wanup, ");
 	 IPACMDBG("if_name:%s, ipv4_address:0x%x\n",
 						wanup_data->ifname, wanup_data->ipv4_addr);
 
@@ -290,7 +312,6 @@
 		 return;
 	 }
 
-	 IPACM_ConntrackClient::iptodot("public ip address", wanup_data->ipv4_addr);
 	 WanUp = true;
 	 isStaMode = wanup_data->is_sta;
 	 IPACMDBG("isStaMode: %d\n", isStaMode);
@@ -307,10 +328,10 @@
 	 CreateNatThreads();
 }
 
-int IPACM_ConntrackListener::CreateNatThreads(void)
+int IPACM_ConntrackListener::CreateConnTrackThreads(void)
 {
 	 int ret;
-	 pthread_t tcp_thread = 0, udp_thread = 0, udpcto_thread = 0, to_monitor_thread = 0;
+	 pthread_t tcp_thread = 0, udp_thread = 0;
 
 	 if(isCTReg == false)
 	 {
@@ -341,6 +362,32 @@
 				 IPACMDBG("created UDP conntrack event listner thread\n");
 			}
 
+			isCTReg = true;
+	 }
+
+	 return 0;
+
+error:
+	 if(tcp_thread)
+	 {
+			pthread_cancel(tcp_thread);
+	 }
+
+	 if(udp_thread)
+	 {
+			pthread_cancel(tcp_thread);
+	 }
+
+	 return -1;
+}
+int IPACM_ConntrackListener::CreateNatThreads(void)
+{
+	 int ret;
+	 pthread_t udpcto_thread = 0, to_monitor_thread = 0;
+
+	 if(isNatThreadStart == false)
+	 {
+
 			if(!udpcto_thread)
 			{
 				 ret = pthread_create(&udpcto_thread, NULL, IPACM_ConntrackClient::UDPConnTimeoutUpdate, NULL);
@@ -367,21 +414,11 @@
 				 IPACMDBG("created tcp/udp timeout monitor thread\n");
 			}
 
-			isCTReg = true;
+			isNatThreadStart = true;
 	 }
 	 return 0;
 
 error:
-	 if(tcp_thread)
-	 {
-			pthread_cancel(tcp_thread);
-	 }
-
-	 if(udp_thread)
-	 {
-			pthread_cancel(tcp_thread);
-	 }
-
 	 if(udpcto_thread)
 	 {
 			pthread_cancel(udpcto_thread);
@@ -397,8 +434,8 @@
 
 void IPACM_ConntrackListener::TriggerWANDown(uint32_t wan_addr)
 {
-	 IPACMDBG("Deleting ipv4 nat table with ");
-	 IPACM_ConntrackClient::iptodot("public ip address", wan_addr);
+	 IPACMDBG("Deleting ipv4 nat table with");
+	 iptodot("public ip address", wan_addr);
 	 WanUp = false;
 
 	 if(nat_inst != NULL)
@@ -410,21 +447,21 @@
 
 void ParseCTMessage(struct nf_conntrack *ct)
 {
-	 uint32_t status;
+	 uint32_t status, timeout;
 	 IPACMDBG("Printing conntrack parameters\n");
 
-	 IPACM_ConntrackClient::iptodot("ATTR_IPV4_SRC = ATTR_ORIG_IPV4_SRC:", nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC));
-	 IPACM_ConntrackClient::iptodot("ATTR_IPV4_DST = ATTR_ORIG_IPV4_DST:", nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_DST));
+	 iptodot("ATTR_IPV4_SRC = ATTR_ORIG_IPV4_SRC:", nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC));
+	 iptodot("ATTR_IPV4_DST = ATTR_ORIG_IPV4_DST:", nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_DST));
 	 IPACMDBG("ATTR_PORT_SRC = ATTR_ORIG_PORT_SRC: 0x%x\n", nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC));
 	 IPACMDBG("ATTR_PORT_DST = ATTR_ORIG_PORT_DST: 0x%x\n", nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST));
 
-	 IPACM_ConntrackClient::iptodot("ATTR_REPL_IPV4_SRC:", nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC));
-	 IPACM_ConntrackClient::iptodot("ATTR_REPL_IPV4_DST:", nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST));
+	 iptodot("ATTR_REPL_IPV4_SRC:", nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC));
+	 iptodot("ATTR_REPL_IPV4_DST:", nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST));
 	 IPACMDBG("ATTR_REPL_PORT_SRC: 0x%x\n", nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC));
 	 IPACMDBG("ATTR_REPL_PORT_DST: 0x%x\n", nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST));
 
-	 IPACM_ConntrackClient::iptodot("ATTR_SNAT_IPV4:", nfct_get_attr_u32(ct, ATTR_SNAT_IPV4));
-	 IPACM_ConntrackClient::iptodot("ATTR_DNAT_IPV4:", nfct_get_attr_u32(ct, ATTR_DNAT_IPV4));
+	 iptodot("ATTR_SNAT_IPV4:", nfct_get_attr_u32(ct, ATTR_SNAT_IPV4));
+	 iptodot("ATTR_DNAT_IPV4:", nfct_get_attr_u32(ct, ATTR_DNAT_IPV4));
 	 IPACMDBG("ATTR_SNAT_PORT: 0x%x\n", nfct_get_attr_u16(ct, ATTR_SNAT_PORT));
 	 IPACMDBG("ATTR_DNAT_PORT: 0x%x\n", nfct_get_attr_u16(ct, ATTR_DNAT_PORT));
 
@@ -435,6 +472,9 @@
 	 status = nfct_get_attr_u32(ct, ATTR_STATUS);
 	 IPACMDBG("ATTR_STATUS: 0x%x\n", status);
 
+	 timeout = nfct_get_attr_u32(ct, ATTR_TIMEOUT);
+	 IPACMDBG("ATTR_TIMEOUT: 0x%x\n", timeout);
+
 	 if(IPS_SRC_NAT & status)
 	 {
 			IPACMDBG("IPS_SRC_NAT set\n");
@@ -459,10 +499,55 @@
 	 return;
 }
 
-void IPACM_ConntrackListener::ProcessCTMessage(void *param)
+void ParseCTV6Message(struct nf_conntrack *ct)
 {
-	 ipacm_ct_evt_data *evt_data = (ipacm_ct_evt_data *)param;
-	 u_int8_t l4proto = 0; 
+	 uint32_t status, timeout, secmark;
+	 struct nfct_attr_grp_ipv6 orig_params;
+	 uint8_t l4proto, tcp_flags, tcp_state;
+
+	 IPACMDBG("Printing conntrack parameters\n");
+
+	 nfct_get_attr_grp(ct, ATTR_GRP_ORIG_IPV6, (void *)&orig_params);
+	 IPACMDBG("Orig src_v6_addr: 0x%08x%08x%08x%08x\n", orig_params.src[0], orig_params.src[1],
+                	orig_params.src[2], orig_params.src[3]);
+	IPACMDBG("Orig dst_v6_addr: 0x%08x%08x%08x%08x\n", orig_params.dst[0], orig_params.dst[1],
+                	orig_params.dst[2], orig_params.dst[3]);
+
+	 IPACMDBG("ATTR_PORT_SRC = ATTR_ORIG_PORT_SRC: 0x%x\n", nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC));
+	 IPACMDBG("ATTR_PORT_DST = ATTR_ORIG_PORT_DST: 0x%x\n", nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST));
+
+	 IPACMDBG("ATTR_MARK: 0x%x\n", nfct_get_attr_u32(ct, ATTR_MARK));
+	 IPACMDBG("ATTR_USE: 0x%x\n", nfct_get_attr_u32(ct, ATTR_USE));
+	 IPACMDBG("ATTR_ID: 0x%x\n", nfct_get_attr_u32(ct, ATTR_ID));
+
+	 timeout = nfct_get_attr_u32(ct, ATTR_TIMEOUT);
+	 IPACMDBG("ATTR_TIMEOUT: 0x%x\n", timeout);
+
+	 status = nfct_get_attr_u32(ct, ATTR_STATUS);
+	 IPACMDBG("ATTR_STATUS: 0x%x\n", status);
+
+	 l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO);
+	 IPACMDBG("ATTR_ORIG_L4PROTO: 0x%x\n", l4proto);
+	 if(l4proto == IPPROTO_TCP)
+	 {
+		tcp_state = nfct_get_attr_u8(ct, ATTR_TCP_STATE);
+		IPACMDBG("ATTR_TCP_STATE: 0x%x\n", tcp_state);
+
+		tcp_flags =  nfct_get_attr_u8(ct, ATTR_TCP_FLAGS_ORIG);
+		IPACMDBG("ATTR_TCP_FLAGS_ORIG: 0x%x\n", tcp_flags);
+	 }
+
+	 IPACMDBG("\n");
+	 return;
+}
+
+#ifdef CT_OPT
+void IPACM_ConntrackListener::ProcessCTV6Message(void *param)
+{
+	ipacm_ct_evt_data *evt_data = (ipacm_ct_evt_data *)param;
+	u_int8_t l4proto = 0;
+	uint32_t status = 0;
+	struct nf_conntrack *ct = evt_data->ct;
 
 #ifdef IPACM_DEBUG
 	 char buf[1024];
@@ -472,6 +557,93 @@
 								 evt_data->type, NFCT_O_PLAIN, NFCT_OF_TIME);
 	 IPACMDBG("%s\n", buf);
 	 IPACMDBG("\n");
+	 ParseCTV6Message(ct);
+#endif
+
+	if(p_lan2lan == NULL)
+	{
+		IPACMERR("Lan2Lan Instance is null\n");
+		goto IGNORE;
+	}
+
+	status = nfct_get_attr_u32(ct, ATTR_STATUS);
+	if((IPS_DST_NAT & status) || (IPS_SRC_NAT & status))
+	{
+		IPACMDBG("Either Destination or Source nat flag Set\n");
+		goto IGNORE;
+	}
+
+	l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO);
+	if(IPPROTO_UDP != l4proto && IPPROTO_TCP != l4proto)
+	{
+		 IPACMDBG("Received unexpected protocl %d conntrack message\n", l4proto);
+		 goto IGNORE;
+	}
+
+	IPACMDBG("Neither Destination nor Source nat flag Set\n");
+	struct nfct_attr_grp_ipv6 orig_params;
+	nfct_get_attr_grp(ct, ATTR_GRP_ORIG_IPV6, (void *)&orig_params);
+
+	ipacm_event_connection lan2lan_conn;
+	lan2lan_conn.iptype = IPA_IP_v6;
+	memcpy(lan2lan_conn.src_ipv6_addr, orig_params.src,
+				 sizeof(lan2lan_conn.src_ipv6_addr));
+    IPACMDBG("Before convert, src_v6_addr: 0x%08x%08x%08x%08x\n", lan2lan_conn.src_ipv6_addr[0], lan2lan_conn.src_ipv6_addr[1],
+                	lan2lan_conn.src_ipv6_addr[2], lan2lan_conn.src_ipv6_addr[3]);
+    for(int cnt=0; cnt<4; cnt++)
+	{
+	   lan2lan_conn.src_ipv6_addr[cnt] = ntohl(lan2lan_conn.src_ipv6_addr[cnt]);
+	}
+	IPACMDBG("After convert src_v6_addr: 0x%08x%08x%08x%08x\n", lan2lan_conn.src_ipv6_addr[0], lan2lan_conn.src_ipv6_addr[1],
+                	lan2lan_conn.src_ipv6_addr[2], lan2lan_conn.src_ipv6_addr[3]);
+
+	memcpy(lan2lan_conn.dst_ipv6_addr, orig_params.dst,
+				 sizeof(lan2lan_conn.dst_ipv6_addr));
+	IPACMDBG("Before convert, dst_ipv6_addr: 0x%08x%08x%08x%08x\n", lan2lan_conn.dst_ipv6_addr[0], lan2lan_conn.dst_ipv6_addr[1],
+                	lan2lan_conn.dst_ipv6_addr[2], lan2lan_conn.dst_ipv6_addr[3]);
+    for(int cnt=0; cnt<4; cnt++)
+	{
+	   lan2lan_conn.dst_ipv6_addr[cnt] = ntohl(lan2lan_conn.dst_ipv6_addr[cnt]);
+	}
+	IPACMDBG("After convert, dst_ipv6_addr: 0x%08x%08x%08x%08x\n", lan2lan_conn.dst_ipv6_addr[0], lan2lan_conn.dst_ipv6_addr[1],
+                	lan2lan_conn.dst_ipv6_addr[2], lan2lan_conn.dst_ipv6_addr[3]);
+
+	if(((IPPROTO_UDP == l4proto) && (NFCT_T_NEW == evt_data->type)) ||
+		 ((IPPROTO_TCP == l4proto) &&
+			(nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_ESTABLISHED))
+		 )
+	{
+			p_lan2lan->handle_new_connection(&lan2lan_conn);
+	}
+	else if((IPPROTO_UDP == l4proto && NFCT_T_DESTROY == evt_data->type) ||
+					(IPPROTO_TCP == l4proto &&
+					 nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_FIN_WAIT))
+	{
+			p_lan2lan->handle_del_connection(&lan2lan_conn);
+	}
+
+IGNORE:
+	/* Cleanup item that was allocated during the original CT callback */
+	nfct_destroy(ct);
+	return;
+}
+#endif
+
+void IPACM_ConntrackListener::ProcessCTMessage(void *param)
+{
+	 ipacm_ct_evt_data *evt_data = (ipacm_ct_evt_data *)param;
+	 u_int8_t l4proto = 0;
+
+#ifdef IPACM_DEBUG
+	 char buf[1024];
+	 unsigned int out_flags;
+
+	 /* Process message and generate ioctl call to kernel thread */
+	 out_flags = (NFCT_OF_SHOW_LAYER3 | NFCT_OF_TIME | NFCT_OF_ID);
+	 nfct_snprintf(buf, sizeof(buf), evt_data->ct,
+								 evt_data->type, NFCT_O_PLAIN, out_flags);
+	 IPACMDBG("%s\n", buf);
+	 IPACMDBG("\n");
 
 	 ParseCTMessage(evt_data->ct);
 #endif
@@ -505,6 +677,7 @@
 	 uint32_t orig_src_ip, orig_dst_ip;
 	 bool isTempEntry = false;
 
+ 	 memset(&rule, 0, sizeof(rule));
 	 pConfig = IPACM_Config::GetInstance();
 	 if(pConfig == NULL)
 	 {
@@ -514,6 +687,9 @@
 	 IPACMDBG("Received type:%d with proto:%d\n", type, l4proto);
 	 status = nfct_get_attr_u32(ct, ATTR_STATUS);
 
+	 /* Retrieve Protocol */
+	 rule.protocol = nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO);
+
 	 if(IPS_DST_NAT & status)
 	 {
 		 status = IPS_DST_NAT;
@@ -525,7 +701,7 @@
 	 else
 	 {
 		 IPACMDBG("Neither Destination nor Source nat flag Set\n");
-		 orig_src_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC); 
+		 orig_src_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC);
 		 orig_src_ip = ntohl(orig_src_ip);
 		 if(orig_src_ip == 0)
 		 {
@@ -556,21 +732,31 @@
 			 IPACMDBG("Neither orig src ip:0x%x Nor orig Dst IP:0x%x equal to wan ip:0x%x\n",
 						orig_src_ip, orig_dst_ip, wan_ipaddr);
 
-			 if(pConfig != NULL)
-			 {
-				 if(pConfig->isPrivateSubnet(orig_src_ip) &&
-						(IPS_SRC_NAT_DONE & status))
-				 {
-					 IPACMDBG("orig src ip:0x%x match private subnet\n",
-							orig_src_ip);
-					 status = IPS_SRC_NAT;
-				 }
-				 else
-				 {
-					 return;
-				 }
-			 }
+#ifdef CT_OPT
+		if(p_lan2lan == NULL)
+		{
+			IPACMERR("Lan2Lan Instance is null\n");
+			goto IGNORE;
+		}
 
+			 ipacm_event_connection lan2lan_conn = { 0 };
+			 lan2lan_conn.iptype = IPA_IP_v4;
+			 lan2lan_conn.src_ipv4_addr = orig_src_ip;
+			 lan2lan_conn.dst_ipv4_addr = orig_dst_ip;
+
+			 if(((IPPROTO_UDP == rule.protocol) && (NFCT_T_NEW == type)) ||
+					((IPPROTO_TCP == rule.protocol) && (nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_ESTABLISHED)))
+			 {
+				 p_lan2lan->handle_new_connection(&lan2lan_conn);
+			 }
+			 else if((IPPROTO_UDP == rule.protocol && NFCT_T_DESTROY == type) ||
+							 (IPPROTO_TCP == rule.protocol &&
+								nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_FIN_WAIT))
+			 {
+				 p_lan2lan->handle_del_connection(&lan2lan_conn);
+			 }
+#endif
+					 return;
 		 }
 	 }
 
@@ -661,9 +847,6 @@
 		 goto IGNORE;
 	 }
 
-	 /* Retrieve Protocol */
-	 rule.protocol = nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO);
-
 	 if(rule.private_ip != wan_ipaddr)
 	 {
 		 int cnt;
@@ -675,7 +858,7 @@
 						rule.target_ip == nat_iface_ipv4_addr[cnt])
 				 {
 					 IPACMDBG("matched nat_iface_ipv4_addr entry(%d)\n", cnt);
-					 IPACM_ConntrackClient::iptodot("ProcessTCPorUDPMsg(): Nat entry match with ip addr",
+					 iptodot("ProcessTCPorUDPMsg(): Nat entry match with ip addr",
 																					nat_iface_ipv4_addr[cnt]);
 					 break;
 				 }
@@ -715,11 +898,11 @@
 				rule.private_port, rule.public_port);
 		 rule.private_port = rule.public_port;
 	 }
-	 
+
 	 IPACMDBG("Nat Entry with below information will either be added or deleted\n");
-	 IPACM_ConntrackClient::iptodot("target ip or dst ip", rule.target_ip);
+	 iptodot("target ip or dst ip", rule.target_ip);
 	 IPACMDBG("target port or dst port: 0x%x Decimal:%d\n", rule.target_port, rule.target_port);
-	 IPACM_ConntrackClient::iptodot("private ip or src ip", rule.private_ip);
+	 iptodot("private ip or src ip", rule.private_ip);
 	 IPACMDBG("private port or src port: 0x%x, Decimal:%d\n", rule.private_port, rule.private_port);
 	 IPACMDBG("public port or reply dst port: 0x%x, Decimal:%d\n", rule.public_port, rule.public_port);
 	 IPACMDBG("Protocol: %d, destination nat flag: %d\n", rule.protocol, rule.dst_nat);
@@ -806,9 +989,9 @@
 
 IGNORE:
 	IPACMDBG("ignoring below Nat Entry\n");
-	IPACM_ConntrackClient::iptodot("target ip or dst ip", rule.target_ip);
+	iptodot("target ip or dst ip", rule.target_ip);
 	IPACMDBG("target port or dst port: 0x%x Decimal:%d\n", rule.target_port, rule.target_port);
-	IPACM_ConntrackClient::iptodot("private ip or src ip", rule.private_ip);
+	iptodot("private ip or src ip", rule.private_ip);
 	IPACMDBG("private port or src port: 0x%x, Decimal:%d\n", rule.private_port, rule.private_port);
 	IPACMDBG("public port or reply dst port: 0x%x, Decimal:%d\n", rule.public_port, rule.public_port);
 	IPACMDBG("Protocol: %d, destination nat flag: %d\n", rule.protocol, rule.dst_nat);
diff --git a/ipacm/src/IPACM_Conntrack_NATApp.cpp b/ipacm/src/IPACM_Conntrack_NATApp.cpp
index 3cc2f8a..2424248 100644
--- a/ipacm/src/IPACM_Conntrack_NATApp.cpp
+++ b/ipacm/src/IPACM_Conntrack_NATApp.cpp
@@ -188,8 +188,8 @@
 			 cache[cnt].protocol == rule->protocol)
 		{
 			IPACMDBG("Duplicate Rule\n");
-			IPACM_ConntrackClient::iptodot("Private IP", rule->private_ip);
-			IPACM_ConntrackClient::iptodot("Target IP", rule->target_ip);
+			iptodot("Private IP", rule->private_ip);
+			iptodot("Target IP", rule->target_ip);
 			IPACMDBG("Private Port: %d\t Target Port: %d\t", rule->private_port, rule->target_port);
 			IPACMDBG("protocolcol: %d\n", rule->protocol);
 			return true;
@@ -208,8 +208,8 @@
 	CHK_TBL_HDL();
 
   IPACMDBG("Received below nat entry for deletion\n");
-	IPACM_ConntrackClient::iptodot("Private IP", rule->private_ip);
-	IPACM_ConntrackClient::iptodot("Target IP", rule->target_ip);
+	iptodot("Private IP", rule->private_ip);
+	iptodot("Target IP", rule->target_ip);
 	IPACMDBG("Private Port: %d\t Target Port: %d\t", rule->private_port, rule->target_port);
 	IPACMDBG("protocolcol: %d\n", rule->protocol);
 
@@ -257,8 +257,8 @@
 	CHK_TBL_HDL();
 
 	IPACMDBG("Received below nat entry for addition\n");
-	IPACM_ConntrackClient::iptodot("Private IP", rule->private_ip);
-	IPACM_ConntrackClient::iptodot("Target IP", rule->target_ip);
+	iptodot("Private IP", rule->private_ip);
+	iptodot("Target IP", rule->target_ip);
 	IPACMDBG("Private Port: %d\t Target Port: %d\t", rule->private_port, rule->target_port);
 	IPACMDBG("protocolcol: %d\n", rule->protocol);
 
@@ -356,8 +356,8 @@
 {
 	int ret;
 
-	IPACM_ConntrackClient::iptodot("Private IP:", rule->private_ip);
-	IPACM_ConntrackClient::iptodot("Target IP:",  rule->target_ip);
+	iptodot("Private IP:", rule->private_ip);
+	iptodot("Target IP:",  rule->target_ip);
 	IPACMDBG("Private Port: %d, Target Port: %d\n", rule->private_port, rule->target_port);
 
 	if(!ct_hdl)
@@ -413,8 +413,8 @@
 		IPACMDBG("dst nat is set\n");
 	}
 
-	IPACM_ConntrackClient::iptodot("Source IP:", nfct_get_attr_u32(ct, ATTR_IPV4_SRC));
-	IPACM_ConntrackClient::iptodot("Destination IP:",  nfct_get_attr_u32(ct, ATTR_IPV4_DST));
+	iptodot("Source IP:", nfct_get_attr_u32(ct, ATTR_IPV4_SRC));
+	iptodot("Destination IP:",  nfct_get_attr_u32(ct, ATTR_IPV4_DST));
 	IPACMDBG("Source Port: %d, Destination Port: %d\n",
 					 nfct_get_attr_u16(ct, ATTR_PORT_SRC), nfct_get_attr_u16(ct, ATTR_PORT_DST)); 
 	
@@ -593,8 +593,8 @@
 			cache[cnt].enabled = true;
 
 			IPACMDBG("On power reset added below rule successfully\n");
-			IPACM_ConntrackClient::iptodot("Private IP", nat_rule.private_ip);
-			IPACM_ConntrackClient::iptodot("Target IP", nat_rule.target_ip);
+			iptodot("Private IP", nat_rule.private_ip);
+			iptodot("Target IP", nat_rule.target_ip);
 			IPACMDBG("Private Port:%d \t Target Port: %d\t", nat_rule.private_port, nat_rule.target_port);
 			IPACMDBG("Public Port:%d\n", nat_rule.public_port);
 			IPACMDBG("protocol: %d\n", nat_rule.protocol);
@@ -634,8 +634,8 @@
 	int cnt;
 
 	IPACMDBG("Received below nat entry\n");
-	IPACM_ConntrackClient::iptodot("Private IP", new_entry->private_ip);
-	IPACM_ConntrackClient::iptodot("Target IP", new_entry->target_ip);
+	iptodot("Private IP", new_entry->private_ip);
+	iptodot("Target IP", new_entry->target_ip);
 	IPACMDBG("Private Port: %d\t Target Port: %d\t", new_entry->private_port, new_entry->target_port);
 	IPACMDBG("protocolcol: %d\n", new_entry->protocol);
 
@@ -659,8 +659,8 @@
 	int cnt;
 
 	IPACMDBG("Received below nat entry\n");
-	IPACM_ConntrackClient::iptodot("Private IP", entry->private_ip);
-	IPACM_ConntrackClient::iptodot("Target IP", entry->target_ip);
+	iptodot("Private IP", entry->private_ip);
+	iptodot("Target IP", entry->target_ip);
 	IPACMDBG("Private Port: %d\t Target Port: %d\t", entry->private_port, entry->target_port);
 	IPACMDBG("protocolcol: %d\n", entry->protocol);
 
@@ -688,7 +688,7 @@
 	int ret;
 
 	IPACMDBG("Received below with isAdd:%d\n", isAdd);
-	IPACM_ConntrackClient::iptodot("IP Address:", ip_addr);
+	iptodot("IP Address:", ip_addr);
 
 	for(cnt=0; cnt<MAX_TEMP_ENTRIES; cnt++)
 	{
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
index 5063e36..008a185 100644
--- a/ipacm/src/IPACM_Lan.cpp
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -93,6 +93,9 @@
 
 	is_active = true;
 
+	memset(tcp_ctl_flt_rule_hdl_v4, 0, NUM_TCP_CTL_FLT_RULE*sizeof(uint32_t));
+	memset(tcp_ctl_flt_rule_hdl_v6, 0, NUM_TCP_CTL_FLT_RULE*sizeof(uint32_t));
+
 	return;
 }
 
@@ -382,7 +385,13 @@
 		return IPACM_FAILURE;
 	}
 
-	flt_rule_count_v4 = IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+#ifdef CT_OPT
+	flt_rule_count_v4 = IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR
+						+ NUM_TCP_CTL_FLT_RULE + IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+#else
+	flt_rule_count_v4 = IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR
+						IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+#endif
 
 	if(is_sta_mode == false)
 	{
@@ -477,8 +486,11 @@
 		dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
         IPACMDBG("ipv4 iface rt-rule hdl1=0x%x\n", dft_rt_rule_hdl[0]);
 		/* initial multicast/broadcast/fragment filter rule */
-		init_fl_rule(data->iptype);
+#ifdef CT_OPT
+		install_tcp_ctl_flt_rule(IPA_IP_v4);
+#endif
 		add_dummy_lan2lan_flt_rule(data->iptype);
+		init_fl_rule(data->iptype);
 	}
 	else
 	{
@@ -563,9 +575,12 @@
 
 		if (num_dft_rt_v6 == 0)
 		{
+#ifdef CT_OPT
+			install_tcp_ctl_flt_rule(IPA_IP_v6);
+#endif
+			add_dummy_lan2lan_flt_rule(data->iptype);
 			/* initial multicast/broadcast/fragment filter rule */
 			init_fl_rule(data->iptype);
-			add_dummy_lan2lan_flt_rule(data->iptype);
 		}
 		num_dft_rt_v6++;
 	}
@@ -1605,15 +1620,20 @@
 	/* delete default filter rules */
 	if (ip_type != IPA_IP_v6 && rx_prop != NULL)
 	{
-		if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl,
-																				IPA_IP_v4,
-																				IPV4_DEFAULT_FILTERTING_RULES) == false)
+		if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES) == false)
 		{
-			IPACMERR("Error Adding Filtering Rule, aborting...\n");
+			IPACMERR("Error deleting default filtering Rule, aborting...\n");
 			res = IPACM_FAILURE;
 			goto fail;
 		}
-
+#ifdef CT_OPT
+		if (m_filtering.DeleteFilteringHdls(tcp_ctl_flt_rule_hdl_v4, IPA_IP_v4, NUM_TCP_CTL_FLT_RULE) == false)
+		{
+			IPACMERR("Error deleting default filtering Rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+#endif
 		for(i=0; i<MAX_OFFLOAD_PAIR; i++)
 		{
 			if(m_filtering.DeleteFilteringHdls(&(lan2lan_flt_rule_hdl_v4[i].rule_hdl), IPA_IP_v4, 1) == false)
@@ -1626,10 +1646,7 @@
 		IPACMDBG("Deleted lan2lan IPv4 flt rules.\n");
 
 		/* free private-subnet ipv4 filter rules */
-		if (m_filtering.DeleteFilteringHdls(
-					private_fl_rule_hdl,
-					IPA_IP_v4,
-					IPACM_Iface::ipacmcfg->ipa_num_private_subnet) == false)
+		if (m_filtering.DeleteFilteringHdls(private_fl_rule_hdl, IPA_IP_v4, IPACM_Iface::ipacmcfg->ipa_num_private_subnet) == false)
 		{
 			IPACMERR("Error Deleting RuleTable(1) to Filtering, aborting...\n");
 			res = IPACM_FAILURE;
@@ -1649,7 +1666,14 @@
 			res = IPACM_FAILURE;
 			goto fail;
 		}
-
+#ifdef CT_OPT
+		if (m_filtering.DeleteFilteringHdls(tcp_ctl_flt_rule_hdl_v6, IPA_IP_v6, NUM_TCP_CTL_FLT_RULE) == false)
+		{
+			IPACMERR("Error deleting default filtering Rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+#endif
 		for(i=0; i<MAX_OFFLOAD_PAIR; i++)
 		{
 			if(m_filtering.DeleteFilteringHdls(&(lan2lan_flt_rule_hdl_v6[i].rule_hdl), IPA_IP_v6, 1) == false)
@@ -1866,7 +1890,11 @@
 		return IPACM_FAILURE;
 	}
 
+#ifdef CT_OPT
+	flt_rule_count_v6 = IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR;
+#else
 	flt_rule_count_v6 = IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR;
+#endif
 
 	if(is_sta_mode == false)
 	{
@@ -2984,3 +3012,103 @@
 	} /* end of for loop */
 	return;
 }
+
+void IPACM_Lan::install_tcp_ctl_flt_rule(ipa_ip_type iptype)
+{
+	if (rx_prop == NULL)
+	{
+		IPACMDBG("No rx properties registered for iface %s\n", dev_name);
+		return;
+	}
+
+	int len, i;
+	struct ipa_flt_rule_add flt_rule;
+	ipa_ioc_add_flt_rule* pFilteringTable;
+
+	len = sizeof(struct ipa_ioc_add_flt_rule) +	NUM_TCP_CTL_FLT_RULE * sizeof(struct ipa_flt_rule_add);
+
+	pFilteringTable = (struct ipa_ioc_add_flt_rule *)malloc(len);
+	if (pFilteringTable == NULL)
+	{
+		IPACMERR("Error allocate flt table memory...\n");
+		return;
+	}
+	memset(pFilteringTable, 0, len);
+
+	pFilteringTable->commit = 1;
+	pFilteringTable->ip = iptype;
+	pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+	pFilteringTable->global = false;
+	pFilteringTable->num_rules = NUM_TCP_CTL_FLT_RULE;
+
+	memset(&flt_rule, 0, sizeof(struct ipa_flt_rule_add));
+
+	flt_rule.at_rear = true;
+	flt_rule.flt_rule_hdl = -1;
+	flt_rule.status = -1;
+
+	flt_rule.rule.retain_hdr = 1;
+	flt_rule.rule.to_uc = 0;
+	flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
+	flt_rule.rule.eq_attrib_type = 1;
+
+	flt_rule.rule.eq_attrib.rule_eq_bitmap = 0;
+
+	flt_rule.rule.eq_attrib.rule_eq_bitmap |= (1<<14);
+	flt_rule.rule.eq_attrib.metadata_meq32_present = 1;
+	flt_rule.rule.eq_attrib.metadata_meq32.offset = 0;
+	flt_rule.rule.eq_attrib.metadata_meq32.value = rx_prop->rx[0].attrib.meta_data;
+	flt_rule.rule.eq_attrib.metadata_meq32.mask = rx_prop->rx[0].attrib.meta_data_mask;
+
+	flt_rule.rule.eq_attrib.rule_eq_bitmap |= (1<<1);
+	flt_rule.rule.eq_attrib.protocol_eq_present = 1;
+	flt_rule.rule.eq_attrib.protocol_eq = IPACM_FIREWALL_IPPROTO_TCP;
+
+	flt_rule.rule.eq_attrib.rule_eq_bitmap |= (1<<8);
+	flt_rule.rule.eq_attrib.num_ihl_offset_meq_32 = 1;
+	flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].offset = 12;
+
+	/* add TCP FIN rule*/
+	flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_FIN_SHIFT);
+	flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_FIN_SHIFT);
+	memcpy(&(pFilteringTable->rules[0]), &flt_rule, sizeof(struct ipa_flt_rule_add));
+
+	/* add TCP SYN rule*/
+	flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_SYN_SHIFT);
+	flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_SYN_SHIFT);
+	memcpy(&(pFilteringTable->rules[1]), &flt_rule, sizeof(struct ipa_flt_rule_add));
+
+	/* add TCP RST rule*/
+	flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_RST_SHIFT);
+	flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_RST_SHIFT);
+	memcpy(&(pFilteringTable->rules[2]), &flt_rule, sizeof(struct ipa_flt_rule_add));
+
+	if (false == m_filtering.AddFilteringRule(pFilteringTable))
+	{
+		IPACMERR("Error adding tcp control flt rule\n");
+		goto fail;
+	}
+	else
+	{
+		if(iptype == IPA_IP_v4)
+		{
+			for(i=0; i<NUM_TCP_CTL_FLT_RULE; i++)
+			{
+				flt_rule_count_v4++;
+				tcp_ctl_flt_rule_hdl_v4[i] = pFilteringTable->rules[i].flt_rule_hdl;
+			}
+		}
+		else
+		{
+			for(i=0; i<NUM_TCP_CTL_FLT_RULE; i++)
+			{
+				flt_rule_count_v6++;
+				tcp_ctl_flt_rule_hdl_v6[i] = pFilteringTable->rules[i].flt_rule_hdl;
+			}
+		}
+	}
+
+fail:
+	free(pFilteringTable);
+	return;
+}
diff --git a/ipacm/src/IPACM_LanToLan.cpp b/ipacm/src/IPACM_LanToLan.cpp
index ed9a671..562c233 100644
--- a/ipacm/src/IPACM_LanToLan.cpp
+++ b/ipacm/src/IPACM_LanToLan.cpp
@@ -43,6 +43,8 @@
 #include "IPACM_LanToLan.h"
 #include "IPACM_Wlan.h"
 
+IPACM_LanToLan* IPACM_LanToLan::p_instance = NULL;
+
 IPACM_LanToLan::IPACM_LanToLan()
 {
 	num_offload_pair_v4_ = 0;
@@ -50,6 +52,8 @@
 	client_info_v4_.reserve(IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_USB_CLIENT);
 	client_info_v6_.reserve(3*(IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_USB_CLIENT));
 
+	p_instance = this;
+
 	IPACM_EvtDispatcher::registr(IPA_LAN_CLIENT_ACTIVE, this);
 	IPACM_EvtDispatcher::registr(IPA_LAN_CLIENT_INACTIVE, this);
 	IPACM_EvtDispatcher::registr(IPA_LAN_CLIENT_DISCONNECT, this);
@@ -115,7 +119,7 @@
 		{
 			IPACMDBG("Get IPA_LAN_TO_LAN_NEW_CONNECTION event.\n");
 			ipacm_event_connection* data = (ipacm_event_connection*)param;
-			handle_new_connection(data);
+			handle_new_lan2lan_connection(data);
 			break;
 		}
 
@@ -123,7 +127,7 @@
 		{
 			IPACMDBG("Get IPA_LAN_TO_LAN_DEL_CONNECTION event.\n");
 			ipacm_event_connection* data = (ipacm_event_connection*)param;
-			handle_del_connection(data);
+			handle_del_lan2lan_connection(data);
 			break;
 		}
 		case IPA_LAN_CLIENT_POWER_SAVE:
@@ -205,7 +209,7 @@
 		client_ptr->is_powersave = false;
 		client_ptr->p_iface = data->p_iface;
 
-		generate_new_connection(data->iptype, client_ptr); //code review: remember of remove this once listening to real connection evt
+		generate_new_connection(data->iptype, client_ptr);
 	}
 	else	//the client is found
 	{
@@ -700,20 +704,9 @@
 	return;
 }
 
-void IPACM_LanToLan::handle_new_connection(ipacm_event_connection* data)
+void IPACM_LanToLan::handle_new_lan2lan_connection(ipacm_event_connection* data)
 {
-	if(data == NULL)
-	{
-		IPACMERR("No connection info is found.\n");
-		return;
-	}
-	if(data->iptype != IPA_IP_v4 && data->iptype != IPA_IP_v6)
-	{
-		IPACMERR("IP type is not expected: %d.\n", data->iptype);
-		return;
-	}
-
-	IPACMDBG("New connection info: IP type: %d, src_v4_addr: 0x%08x, dst_v4_addr: 0x%08x\n", data->iptype, data->src_ipv4_addr, data->dst_ipv4_addr);
+	IPACMDBG("New lan2lan connection info: IP type: %d, src_v4_addr: 0x%08x, dst_v4_addr: 0x%08x\n", data->iptype, data->src_ipv4_addr, data->dst_ipv4_addr);
 	IPACMDBG("src_v6_addr: 0x%08x%08x%08x%08x, dst_v6_addr: 0x%08x%08x%08x%08x", data->src_ipv6_addr[0], data->src_ipv6_addr[1], data->src_ipv6_addr[2],
 				data->src_ipv6_addr[3], data->dst_ipv6_addr[0], data->dst_ipv6_addr[1], data->dst_ipv6_addr[2], data->dst_ipv6_addr[3]);
 
@@ -834,20 +827,9 @@
 	return ret;
 }
 
-void IPACM_LanToLan::handle_del_connection(ipacm_event_connection* data)
+void IPACM_LanToLan::handle_del_lan2lan_connection(ipacm_event_connection* data)
 {
-	if(data == NULL)
-	{
-		IPACMERR("No connection info is found.\n");
-		return;
-	}
-	if(data->iptype != IPA_IP_v4 && data->iptype != IPA_IP_v6)
-	{
-		IPACMERR("IP type is not expected: %d.\n", data->iptype)
-		return;
-	}
-
-	IPACMDBG("Del connection info: IP type: %d, src_v4_addr: 0x%08x, dst_v4_addr: 0x%08x\n", data->iptype, data->src_ipv4_addr, data->dst_ipv4_addr);
+	IPACMDBG("Del lan2lan connection info: IP type: %d, src_v4_addr: 0x%08x, dst_v4_addr: 0x%08x\n", data->iptype, data->src_ipv4_addr, data->dst_ipv4_addr);
 	IPACMDBG("src_v6_addr: 0x%08x%08x%08x%08x, dst_v6_addr: 0x%08x%08x%08x%08x", data->src_ipv6_addr[0], data->src_ipv6_addr[1], data->src_ipv6_addr[2],
 				data->src_ipv6_addr[3], data->dst_ipv6_addr[0], data->dst_ipv6_addr[1], data->dst_ipv6_addr[2], data->dst_ipv6_addr[3]);
 
@@ -956,7 +938,7 @@
 			IPACMDBG("Find dst client entry in src peer list, connection count: %d\n", it->num_connection);
 			if(it->num_connection == 0)
 			{
-				IPACMDBG("Need to remove dst entry in src peer list");
+				IPACMDBG("Need to remove dst entry in src peer list.\n");
 				ret = true;
 			}
 			break;
@@ -976,7 +958,7 @@
 			IPACMDBG("Find src client entry in dst peer list, connection count: %d\n", it->num_connection);
 			if(it->num_connection == 0)
 			{
-				IPACMDBG("Need to remove src entry in dst peer list");
+				IPACMDBG("Need to remove src entry in dst peer list.\n");
 				ret = true;
 			}
 			break;
@@ -1042,6 +1024,7 @@
 
 void IPACM_LanToLan::generate_new_connection(ipa_ip_type iptype, client_info* client)
 {
+#ifndef CT_OPT
 	if(client == NULL)
 	{
 		IPACMERR("Client is NULL.\n");
@@ -1121,6 +1104,7 @@
 		IPACMERR("IP type is not expected.\n");
 	}
 	IPACMDBG("Generate %d new connection events in total.\n", num);
+#endif
 	return;
 }
 
@@ -1284,3 +1268,129 @@
 	return IPACM_SUCCESS;
 }
 
+void IPACM_LanToLan::handle_new_connection(ipacm_event_connection* new_conn)
+{
+#ifdef CT_OPT
+	if(new_conn == NULL)
+	{
+		IPACMERR("No connection info is found.\n");
+		return;
+	}
+	if(new_conn->iptype != IPA_IP_v4 && new_conn->iptype != IPA_IP_v6)
+	{
+		IPACMERR("IP type is not expected: %d.\n", new_conn->iptype);
+		return;
+	}
+
+	IPACMDBG("New connection info: IP type: %d, src_v4_addr: 0x%08x, dst_v4_addr: 0x%08x\n", new_conn->iptype, new_conn->src_ipv4_addr, new_conn->dst_ipv4_addr);
+	IPACMDBG("src_v6_addr: 0x%08x%08x%08x%08x, dst_v6_addr: 0x%08x%08x%08x%08x", new_conn->src_ipv6_addr[0], new_conn->src_ipv6_addr[1], new_conn->src_ipv6_addr[2],
+				new_conn->src_ipv6_addr[3], new_conn->dst_ipv6_addr[0], new_conn->dst_ipv6_addr[1], new_conn->dst_ipv6_addr[2], new_conn->dst_ipv6_addr[3]);
+
+	if(is_lan2lan_connection(new_conn) == false)
+	{
+		IPACMDBG("The connection is not lan2lan connection.\n");
+		return;
+	}
+
+	ipacm_cmd_q_data evt;
+	ipacm_event_connection* conn;
+
+	conn = (ipacm_event_connection*)malloc(sizeof(ipacm_event_connection));
+	if(conn == NULL)
+	{
+		IPACMERR("Failed to allocate memory for new_connection event.\n");
+		return;
+	}
+	memcpy(conn, new_conn, sizeof(ipacm_event_connection));
+
+	memset(&evt, 0, sizeof(evt));
+	evt.event = IPA_LAN_TO_LAN_NEW_CONNECTION;
+	evt.evt_data = (void*)conn;
+	IPACM_EvtDispatcher::PostEvt(&evt);
+#endif
+	return;
+}
+
+void IPACM_LanToLan::handle_del_connection(ipacm_event_connection* new_conn)
+{
+#ifdef CT_OPT
+	if(new_conn == NULL)
+	{
+		IPACMERR("No connection info is found.\n");
+		return;
+	}
+	if(new_conn->iptype != IPA_IP_v4 && new_conn->iptype != IPA_IP_v6)
+	{
+		IPACMERR("IP type is not expected: %d.\n", new_conn->iptype);
+		return;
+	}
+
+	IPACMDBG("Del connection info: IP type: %d, src_v4_addr: 0x%08x, dst_v4_addr: 0x%08x\n", new_conn->iptype, new_conn->src_ipv4_addr, new_conn->dst_ipv4_addr);
+	IPACMDBG("src_v6_addr: 0x%08x%08x%08x%08x, dst_v6_addr: 0x%08x%08x%08x%08x", new_conn->src_ipv6_addr[0], new_conn->src_ipv6_addr[1], new_conn->src_ipv6_addr[2],
+				new_conn->src_ipv6_addr[3], new_conn->dst_ipv6_addr[0], new_conn->dst_ipv6_addr[1], new_conn->dst_ipv6_addr[2], new_conn->dst_ipv6_addr[3]);
+
+	if(is_lan2lan_connection(new_conn) == false)
+	{
+		IPACMDBG("The connection is not lan2lan connection.\n");
+		return;
+	}
+
+	ipacm_cmd_q_data evt;
+	ipacm_event_connection* conn;
+
+	conn = (ipacm_event_connection*)malloc(sizeof(ipacm_event_connection));
+	if(conn == NULL)
+	{
+		IPACMERR("Failed to allocate memory for del_connection event.\n");
+		return;
+	}
+	memcpy(conn, new_conn, sizeof(ipacm_event_connection));
+
+	memset(&evt, 0, sizeof(evt));
+	evt.event = IPA_LAN_TO_LAN_DEL_CONNECTION;
+	evt.evt_data = (void*)conn;
+	IPACM_EvtDispatcher::PostEvt(&evt);
+#endif
+	return;
+}
+
+bool IPACM_LanToLan::is_lan2lan_connection(ipacm_event_connection* data)
+{
+	if(data->iptype == IPA_IP_v4)
+	{
+		if(client_info_v4_.count(data->src_ipv4_addr) == 0 || client_info_v4_.count(data->dst_ipv4_addr) == 0)
+		{
+			IPACMDBG("Either source or destination is not in client table\n");
+			return false;
+		}
+
+		ipacm_iface_type src_type, dst_type;
+		src_type = IPACM_Iface::ipacmcfg->iface_table[client_info_v4_[data->src_ipv4_addr].p_iface->ipa_if_num].if_cat;
+		dst_type = IPACM_Iface::ipacmcfg->iface_table[client_info_v4_[data->dst_ipv4_addr].p_iface->ipa_if_num].if_cat;
+
+		return (src_type != dst_type);
+	}
+	else
+	{
+		uint64_t src_v6_addr, dst_v6_addr;
+		memcpy(&src_v6_addr, &(data->src_ipv6_addr[2]), sizeof(uint64_t));
+		memcpy(&dst_v6_addr, &(data->dst_ipv6_addr[2]), sizeof(uint64_t));
+
+		if(client_info_v6_.count(src_v6_addr) == 0 || client_info_v6_.count(dst_v6_addr) == 0)
+		{
+			IPACMDBG("Either source or destination is not in client table\n");
+			return false;
+		}
+
+		ipacm_iface_type src_type, dst_type;
+		src_type = IPACM_Iface::ipacmcfg->iface_table[client_info_v6_[src_v6_addr].p_iface->ipa_if_num].if_cat;
+		dst_type = IPACM_Iface::ipacmcfg->iface_table[client_info_v6_[dst_v6_addr].p_iface->ipa_if_num].if_cat;
+
+		return (src_type != dst_type);
+	}
+}
+
+IPACM_LanToLan* IPACM_LanToLan::getLan2LanInstance()
+{
+	return p_instance;
+}
diff --git a/ipacm/src/IPACM_Main.cpp b/ipacm/src/IPACM_Main.cpp
index e942a1a..cab2963 100644
--- a/ipacm/src/IPACM_Main.cpp
+++ b/ipacm/src/IPACM_Main.cpp
@@ -67,8 +67,9 @@
 #include "IPACM_Log.h"
 
 #include "IPACM_ConntrackListener.h"
-
+#include "IPACM_ConntrackClient.h"
 #include "IPACM_LanToLan.h"
+#include "IPACM_Netlink.h"
 
 const char *ipacm_event_name[] = {
 	__stringify(IPA_LINK_UP_EVENT),
@@ -550,9 +551,12 @@
 	/* check if ipacm is already running or not */
 	ipa_is_ipacm_running();
 
+	IPACMDBG("In main()\n");
 	IPACM_Neighbor *neigh = new IPACM_Neighbor();
 	IPACM_IfaceManager *ifacemgr = new IPACM_IfaceManager();
 	IPACM_LanToLan* lan2lan = new IPACM_LanToLan();
+	IPACM_ConntrackClient *cc = IPACM_ConntrackClient::GetInstance();
+	CtList = new IPACM_ConntrackListener();
 
 	IPACMDBG("Staring IPA main\n");
 	IPACMDBG("ipa_cmdq_successful\n");
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
index 35ea0eb..0d8b916 100644
--- a/ipacm/src/IPACM_Wlan.cpp
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -531,8 +531,13 @@
 			IPACMERR("Dummy ipv4 flt rule has not been installed.\n");
 			return IPACM_FAILURE;
 		}
-
-		offset = wlan_ap_index * (IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+#ifndef CT_OPT
+		offset = wlan_ap_index * (IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet)
+								+ MAX_OFFLOAD_PAIR;
+#else
+		offset = wlan_ap_index * (IPV4_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet)
+								+ NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR;
+#endif
 		len = sizeof(struct ipa_ioc_mdfy_flt_rule) + (IPV4_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_mdfy));
 		pFilteringTable = (struct ipa_ioc_mdfy_flt_rule *)calloc(1, len);
 		if (!pFilteringTable)
@@ -608,8 +613,13 @@
 			IPACMERR("Dummy ipv6 flt rule has not been installed.\n");
 			return IPACM_FAILURE;
 		}
-
-		offset = wlan_ap_index * (IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR);
+#ifndef CT_OPT
+		offset = wlan_ap_index * (IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR)
+								+ MAX_OFFLOAD_PAIR;
+#else
+		offset = wlan_ap_index * (IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR)
+								+ NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR;
+#endif
 		len = sizeof(struct ipa_ioc_mdfy_flt_rule) + (IPV6_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_mdfy));
 		pFilteringTable = (struct ipa_ioc_mdfy_flt_rule *)calloc(1, len);
 		if (!pFilteringTable)
@@ -715,10 +725,16 @@
 			return IPACM_FAILURE;
 		}
 
+#ifndef CT_OPT
 		offset = wlan_ap_index * (IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+#else
+		offset = wlan_ap_index * (IPV4_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet)
+						+ NUM_TCP_CTL_FLT_RULE;
+#endif
+
 		for (int i = 0; i < MAX_OFFLOAD_PAIR; i++)
 		{
-			lan2lan_flt_rule_hdl_v4[i].rule_hdl = IPACM_Wlan::dummy_flt_rule_hdl_v4[offset+IPV4_DEFAULT_FILTERTING_RULES+i];
+			lan2lan_flt_rule_hdl_v4[i].rule_hdl = IPACM_Wlan::dummy_flt_rule_hdl_v4[offset+i];
 			lan2lan_flt_rule_hdl_v4[i].valid = false;
 			IPACMDBG("Lan2lan v4 flt rule %d hdl:0x%x\n", i, lan2lan_flt_rule_hdl_v4[i].rule_hdl);
 		}
@@ -731,10 +747,16 @@
 			return IPACM_FAILURE;
 		}
 
+#ifndef CT_OPT
 		offset = wlan_ap_index * (IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR);
+#else
+		offset = wlan_ap_index * (IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR)
+						+ NUM_TCP_CTL_FLT_RULE;
+#endif
+
 		for (int i = 0; i < MAX_OFFLOAD_PAIR; i++)
 		{
-			lan2lan_flt_rule_hdl_v6[i].rule_hdl = IPACM_Wlan::dummy_flt_rule_hdl_v6[offset+IPV6_DEFAULT_FILTERTING_RULES+i];
+			lan2lan_flt_rule_hdl_v6[i].rule_hdl = IPACM_Wlan::dummy_flt_rule_hdl_v6[offset+i];
 			lan2lan_flt_rule_hdl_v6[i].valid = false;
 			IPACMDBG("Lan2lan v6 flt rule %d hdl:0x%x\n", i, lan2lan_flt_rule_hdl_v6[i].rule_hdl);
 		}
@@ -769,7 +791,13 @@
 			return IPACM_FAILURE;
 		}
 
-		offset = wlan_ap_index * (IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+#ifndef CT_OPT
+		offset = wlan_ap_index * (IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet)
+						+ IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR;
+#else
+		offset = wlan_ap_index * (IPV4_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet)
+						+ IPV4_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR;
+#endif
 
 		len = sizeof(struct ipa_ioc_mdfy_flt_rule) + (IPACM_Iface::ipacmcfg->ipa_num_private_subnet) * sizeof(struct ipa_flt_rule_mdfy);
 		pFilteringTable = (struct ipa_ioc_mdfy_flt_rule*)malloc(len);
@@ -807,7 +835,7 @@
 
 		for (i = 0; i < (IPACM_Iface::ipacmcfg->ipa_num_private_subnet); i++)
 		{
-			flt_rule.rule_hdl = IPACM_Wlan::dummy_flt_rule_hdl_v4[offset+IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR+i];
+			flt_rule.rule_hdl = IPACM_Wlan::dummy_flt_rule_hdl_v4[offset+i];
 			flt_rule.rule.attrib.u.v4.dst_addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask;
 			flt_rule.rule.attrib.u.v4.dst_addr = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr;
 			memcpy(&(pFilteringTable->rules[i]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
@@ -917,11 +945,19 @@
 
 	if(iptype == IPA_IP_v4)
 	{
+#ifndef CT_OPT
 		offset = 2*(IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+#else
+		offset = 2*(IPV4_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+#endif
 	}
 	else
 	{
+#ifndef CT_OPT
 		offset = 2*(IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR);
+#else
+		offset = 2*(IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR);
+#endif
 	}
 
 	for(cnt=0; cnt<prop->num_ext_props; cnt++)
@@ -1705,7 +1741,7 @@
 		goto fail;
 	}
 
-	/* Delete v6 filtering rules */
+	/* Delete v4 filtering rules */
 	if (ip_type != IPA_IP_v6 && rx_prop != NULL)
 	{
 		IPACMDBG("Delete default v4 filter rules\n");
@@ -1719,7 +1755,18 @@
 				goto fail;
 			}
 		}
-
+#ifdef CT_OPT
+		IPACMDBG("Delete tcp control flt rules.\n");
+		/* Delete tcp control flt rules */
+		for(i=0; i<NUM_TCP_CTL_FLT_RULE; i++)
+		{
+			if(reset_to_dummy_flt_rule(IPA_IP_v4, tcp_ctl_flt_rule_hdl_v4[i]) == IPACM_FAILURE)
+			{
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+		}
+#endif
 		IPACMDBG("Delete lan2lan v4 flt rules.\n");
 		/* delete lan2lan ipv4 flt rules */
 		for(i=0; i<MAX_OFFLOAD_PAIR; i++)
@@ -1745,7 +1792,7 @@
 		}
 	}
 
-	/* Delete v4 filtering rules */
+	/* Delete v6 filtering rules */
 	if (ip_type != IPA_IP_v4 && rx_prop != NULL)
 	{
 		IPACMDBG("Delete default %d v6 filter rules\n", IPV6_DEFAULT_FILTERTING_RULES);
@@ -1758,7 +1805,18 @@
 				goto fail;
 			}
 		}
-
+#ifdef CT_OPT
+		IPACMDBG("Delete tcp control flt rules.\n");
+		/* Delete tcp control flt rules */
+		for(i=0; i<NUM_TCP_CTL_FLT_RULE; i++)
+		{
+			if(reset_to_dummy_flt_rule(IPA_IP_v6, tcp_ctl_flt_rule_hdl_v6[i]) == IPACM_FAILURE)
+			{
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+		}
+#endif
 		IPACMDBG("Delete lan2lan v6 filter rules\n");
 		/* delete lan2lan ipv6 filter rules */
 		for(i=0; i<MAX_OFFLOAD_PAIR; i++)
@@ -2251,10 +2309,13 @@
 			IPACMERR("Either v4 or v6 dummy filtering rule handle is not empty.\n");
 			return;
 		}
-
+#ifndef CT_OPT
 		num_v4_dummy_rule = 2*(IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
 		num_v6_dummy_rule = 2*(IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR);
-
+#else
+		num_v4_dummy_rule = 2*(IPV4_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+		num_v6_dummy_rule = 2*(IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR);
+#endif
 		IPACM_Wlan::dummy_flt_rule_hdl_v4 = (uint32_t*)malloc(num_v4_dummy_rule * sizeof(uint32_t));
 		if(IPACM_Wlan::dummy_flt_rule_hdl_v4 == NULL)
 		{
@@ -2429,9 +2490,13 @@
 			IPACMERR("Either v4 or v6 dummy flt rule is empty.\n");
 			return;
 		}
-
+#ifndef CT_OPT
 		num_v4_dummy_rule = 2*(IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
 		num_v6_dummy_rule = 2*(IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR);
+#else
+		num_v4_dummy_rule = 2*(IPV4_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+		num_v6_dummy_rule = 2*(IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR);
+#endif
 		if(m_filtering.DeleteFilteringHdls(IPACM_Wlan::dummy_flt_rule_hdl_v4, IPA_IP_v4, num_v4_dummy_rule) == false)
 		{
 			IPACMERR("Failed to delete ipv4 dummy flt rules.\n");
@@ -2451,3 +2516,137 @@
 	return;
 }
 
+void IPACM_Wlan::install_tcp_ctl_flt_rule(ipa_ip_type iptype)
+{
+	if (rx_prop == NULL)
+	{
+		IPACMDBG("No rx properties registered for iface %s\n", dev_name);
+		return;
+	}
+
+	int i, len, res = IPACM_SUCCESS, offset;
+	struct ipa_flt_rule_mdfy flt_rule;
+	struct ipa_ioc_mdfy_flt_rule* pFilteringTable;
+
+	if (iptype == IPA_IP_v4)
+	{
+		if(IPACM_Wlan::dummy_flt_rule_hdl_v4 == NULL)
+		{
+			IPACMERR("Dummy ipv4 flt rule has not been installed.\n");
+			return;
+		}
+		offset = wlan_ap_index * (IPV4_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+	}
+	else
+	{
+		if(IPACM_Wlan::dummy_flt_rule_hdl_v6 == NULL)
+		{
+			IPACMERR("Dummy ipv6 flt rule has not been installed.\n");
+			return;
+		}
+		offset = wlan_ap_index * (IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR);
+	}
+
+	len = sizeof(struct ipa_ioc_mdfy_flt_rule) + NUM_TCP_CTL_FLT_RULE * sizeof(struct ipa_flt_rule_mdfy);
+	pFilteringTable = (struct ipa_ioc_mdfy_flt_rule*)malloc(len);
+	if (!pFilteringTable)
+	{
+		IPACMERR("Failed to allocate ipa_ioc_mdfy_flt_rule memory...\n");
+		return;
+	}
+	memset(pFilteringTable, 0, len);
+
+	pFilteringTable->commit = 1;
+	pFilteringTable->ip = iptype;
+	pFilteringTable->num_rules = NUM_TCP_CTL_FLT_RULE;
+
+	memset(&flt_rule, 0, sizeof(struct ipa_flt_rule_mdfy));
+	flt_rule.status = -1;
+
+	flt_rule.rule.retain_hdr = 1;
+	flt_rule.rule.to_uc = 0;
+	flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
+	flt_rule.rule.eq_attrib_type = 1;
+
+	flt_rule.rule.eq_attrib.rule_eq_bitmap = 0;
+
+	flt_rule.rule.eq_attrib.rule_eq_bitmap |= (1<<14);
+	flt_rule.rule.eq_attrib.metadata_meq32_present = 1;
+	flt_rule.rule.eq_attrib.metadata_meq32.offset = 0;
+	flt_rule.rule.eq_attrib.metadata_meq32.value = rx_prop->rx[0].attrib.meta_data;
+	flt_rule.rule.eq_attrib.metadata_meq32.mask = rx_prop->rx[0].attrib.meta_data_mask;
+
+	flt_rule.rule.eq_attrib.rule_eq_bitmap |= (1<<1);
+	flt_rule.rule.eq_attrib.protocol_eq_present = 1;
+	flt_rule.rule.eq_attrib.protocol_eq = IPACM_FIREWALL_IPPROTO_TCP;
+
+	/* add TCP FIN rule*/
+	flt_rule.rule.eq_attrib.rule_eq_bitmap |= (1<<8);
+	flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].offset = 12;
+	flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_FIN_SHIFT);
+	flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_FIN_SHIFT);
+	flt_rule.rule.eq_attrib.num_ihl_offset_meq_32 = 1;
+	if(iptype == IPA_IP_v4)
+	{
+		flt_rule.rule_hdl = IPACM_Wlan::dummy_flt_rule_hdl_v4[offset];
+	}
+	else
+	{
+		flt_rule.rule_hdl = IPACM_Wlan::dummy_flt_rule_hdl_v6[offset];
+	}
+	memcpy(&(pFilteringTable->rules[0]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
+
+	/* add TCP SYN rule*/
+	flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_SYN_SHIFT);
+	flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_SYN_SHIFT);
+	if(iptype == IPA_IP_v4)
+	{
+		flt_rule.rule_hdl = IPACM_Wlan::dummy_flt_rule_hdl_v4[offset+1];
+	}
+	else
+	{
+		flt_rule.rule_hdl = IPACM_Wlan::dummy_flt_rule_hdl_v6[offset+1];
+	}
+	memcpy(&(pFilteringTable->rules[1]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
+
+	/* add TCP RST rule*/
+	flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_RST_SHIFT);
+	flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_RST_SHIFT);
+	if(iptype == IPA_IP_v4)
+	{
+		flt_rule.rule_hdl = IPACM_Wlan::dummy_flt_rule_hdl_v4[offset+2];
+	}
+	else
+	{
+		flt_rule.rule_hdl = IPACM_Wlan::dummy_flt_rule_hdl_v6[offset+2];
+	}
+	memcpy(&(pFilteringTable->rules[2]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
+
+	if (false == m_filtering.ModifyFilteringRule(pFilteringTable))
+	{
+		IPACMERR("Failed to modify tcp control filtering rules.\n");
+		goto fail;
+	}
+	else
+	{
+		if(iptype == IPA_IP_v4)
+		{
+			for(i=0; i<NUM_TCP_CTL_FLT_RULE; i++)
+			{
+				tcp_ctl_flt_rule_hdl_v4[i] = pFilteringTable->rules[i].rule_hdl;
+			}
+		}
+		else
+		{
+			for(i=0; i<NUM_TCP_CTL_FLT_RULE; i++)
+			{
+				tcp_ctl_flt_rule_hdl_v6[i] = pFilteringTable->rules[i].rule_hdl;
+			}
+		}
+	}
+
+fail:
+	free(pFilteringTable);
+	return;
+}
+
diff --git a/ipacm/src/Makefile.am b/ipacm/src/Makefile.am
index 82cc3dc..254a569 100644
--- a/ipacm/src/Makefile.am
+++ b/ipacm/src/Makefile.am
@@ -2,7 +2,7 @@
 	      -I$(top_srcdir)/ipanat/inc \
 	      ${LIBXML_CFLAGS}
 AM_CPPFLAGS += -Wall -Wundef -Wno-trigraphs
-AM_CPPFLAGS	+= -DDEBUG -g
+AM_CPPFLAGS	+= -DDEBUG -g -DCT_OPT
 
 ipacm_SOURCES =	IPACM_Main.cpp \
 		IPACM_Conntrack_NATApp.cpp\