IPA configuration manager daemon and IPA NAT library.

These are user-space components which configure IPA
(Internet Protocol Accelerator) HW using the services
provided by the IPA driver (running in kernel space).
NAT stands for Network Address Translation. This is the
initial commit of these components.

Change-Id: I0934f54c36a7134af143e4f1cd9fbb0682df52d0
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..fab2aff
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,3 @@
+ACLOCAL_AMFLAGS = -I m4
+AUTOMAKE_OPTIONS = foreign
+SUBDIRS = ipanat/src ipacm/src/
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..f826305
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,31 @@
+#                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.65])
+AC_INIT(data-ipa, 1.0.0)
+AM_INIT_AUTOMAKE(data-ipa, 1.0.0)
+AC_OUTPUT(Makefile ipanat/src/Makefile ipacm/src/Makefile)
+AC_CONFIG_SRCDIR([ipanat/src/ipa_nat_drv.c])
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+
+
+# Checks for libraries.
+
+# Checks for header files.
+AC_CHECK_HEADERS([fcntl.h netinet/in.h sys/ioctl.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_TYPE_OFF_T
+
+# Checks for library functions.
+AC_FUNC_MALLOC
+AC_FUNC_MMAP
+AC_CHECK_FUNCS([memset munmap])
+
+AC_OUTPUT
diff --git a/ipacm/inc/IPACM_CmdQueue.h b/ipacm/inc/IPACM_CmdQueue.h
new file mode 100644
index 0000000..4eb4be7
--- /dev/null
+++ b/ipacm/inc/IPACM_CmdQueue.h
@@ -0,0 +1,108 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_CmdQueue.h
+
+	@brief
+	This file implements the IPAM Comment Queue definitions
+
+	@Author
+
+*/
+#ifndef IPA_CONNTRACK_MESSAGE_H
+#define IPA_CONNTRACK_MESSAGE_H
+
+#include <iostream>
+#include <pthread.h>
+#include "IPACM_Defs.h"
+
+
+
+/*--------------------------------------------------------------------------- 
+	 Event data required by IPA_CM
+---------------------------------------------------------------------------*/
+
+
+typedef struct _ipacm_cmd_q_data {
+	ipa_cm_event_id event;
+	void *evt_data;
+}ipacm_cmd_q_data;
+
+typedef struct cmd_s
+{
+	void (*callback_ptr)(ipacm_cmd_q_data *);
+	ipacm_cmd_q_data data;
+}cmd_t;
+
+class Message
+{
+private:
+	Message *m_next;
+
+public:
+	cmd_t evt;
+
+	Message()
+	{
+		m_next = NULL;
+		evt.callback_ptr = NULL;
+	}
+	~Message() { }
+	void setnext(Message *item) { m_next = item; }
+	Message* getnext()       { return m_next; }
+};
+
+class MessageQueue
+{
+
+private:
+	Message *Head;
+	Message *Tail;
+	Message* dequeue(void);
+	static MessageQueue *inst;
+
+	MessageQueue()
+	{
+		Head = NULL;
+		Tail = NULL;
+	}
+
+public:
+
+	~MessageQueue() { }
+	void enqueue(Message *item);
+
+	static void* Process(void *);
+	static MessageQueue* getInstance();
+
+};
+
+#endif  /* IPA_CONNTRACK_MESSAGE_H */
+
diff --git a/ipacm/inc/IPACM_Config.h b/ipacm/inc/IPACM_Config.h
new file mode 100644
index 0000000..f0d356f
--- /dev/null
+++ b/ipacm/inc/IPACM_Config.h
@@ -0,0 +1,93 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_Config.h
+
+	@brief
+	This file implements the IPACM Configuration from XML file
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPACM_CONFIG_H
+#define IPACM_CONFIG_H
+
+#include "IPACM_Defs.h"
+#include "IPACM_Xml.h"
+
+/* iface */
+class IPACM_Config
+{
+public:
+
+	/* Store interested interface and their configuration from XML file */
+	ipa_ifi_dev_name_t *iface_table;
+
+	/* Store interested ALG port from XML file */
+	ipacm_alg *alg_table;
+
+	/* Store private subnet configuration from XML file */
+	ipa_private_subnet private_subnet_table[IPA_MAX_PRIVATE_SUBNET_ENTRIES];
+
+	/* Store the number of interface IPACM read from XML file */
+	int ipa_num_ipa_interfaces;
+
+	int ipa_num_private_subnet;
+
+	int ipa_num_alg_ports;
+
+	int ipa_nat_max_entries;
+
+	/* IPACM routing table name for v4/v6 */
+	struct ipa_ioc_get_rt_tbl rt_tbl_lan_v4, rt_tbl_wan_v4, rt_tbl_v6;
+
+	/* To return the instance */
+	static IPACM_Config* GetInstance();
+
+	inline int GetAlgPortCnt()
+	{
+		return ipa_num_alg_ports;
+	}
+
+	int GetAlgPorts(int nPorts, ipacm_alg *pAlgPorts);
+	int GetNatMaxEntries(void)
+	{
+		return ipa_nat_max_entries;
+	}
+
+private:
+	static IPACM_Config *pInstance;
+	IPACM_Config(void);
+	int Init(void);
+
+};
+
+#endif /* IPACM_CONFIG */
diff --git a/ipacm/inc/IPACM_ConntrackClient.h b/ipacm/inc/IPACM_ConntrackClient.h
new file mode 100644
index 0000000..b125c68
--- /dev/null
+++ b/ipacm/inc/IPACM_ConntrackClient.h
@@ -0,0 +1,98 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef IPACM_CONNTRACK_FILTER_H
+#define IPACM_CONNTRACK_FILTER_H
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <errno.h>
+
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Conntrack_NATApp.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Defs.h"
+
+#ifndef IPACM_DEBUG
+#define IPACM_DEBUG
+#endif
+
+extern "C"
+{
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
+}
+
+using namespace std;
+
+#define UDP_TIMEOUT_UPDATE 20
+#define BROADCAST_IPV4_ADDR 0xFFFFFFFF
+
+class IPACM_ConntrackClient
+{
+
+private:
+	 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);
+	 IPACM_ConntrackClient();
+
+public:
+	 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 *ptr);
+
+	 static void UpdateUDPFilters(void *);
+	 static void UpdateTCPFilters(void *);
+
+	 static IPACM_ConntrackClient* GetInstance();
+
+#ifdef IPACM_DEBUG
+	 static void iptodot(const char *type, uint32_t ipAddr);
+#endif
+
+};
+
+#endif  /* IPACM_CONNTRACK_FILTER_H */
diff --git a/ipacm/inc/IPACM_ConntrackListener.h b/ipacm/inc/IPACM_ConntrackListener.h
new file mode 100644
index 0000000..3cea83a
--- /dev/null
+++ b/ipacm/inc/IPACM_ConntrackListener.h
@@ -0,0 +1,68 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef IPACM_CONNTRACK_LISTENER
+#define IPACM_CONNTRACK_LISTENER
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <errno.h>
+
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Conntrack_NATApp.h"
+#include "IPACM_Listener.h"
+
+using namespace std;
+
+class IPACM_ConntrackListener : public IPACM_Listener
+{
+
+private:
+	 bool isCTReg;
+	 bool isWanUp;
+	 
+	 void ProcessCTMessage(void *data);
+	 void ProcessTCPorUDPMsg(struct nf_conntrack *ct, enum nf_conntrack_msg_type, u_int8_t);
+	 void TriggerWANUp(void *);
+	 void TriggerWANDown(uint32_t wan_addr);
+	 int  CreateNatThreads(void);
+
+public:
+	 char wan_ifname[IPA_IFACE_NAME_LEN];
+	 uint32_t wan_ipaddr;
+	 IPACM_ConntrackListener();
+	 void event_callback(ipa_cm_event_id, void *data);
+};
+
+#endif /* IPACM_CONNTRACK_LISTENER */
diff --git a/ipacm/inc/IPACM_Conntrack_NATApp.h b/ipacm/inc/IPACM_Conntrack_NATApp.h
new file mode 100644
index 0000000..3e1f5a6
--- /dev/null
+++ b/ipacm/inc/IPACM_Conntrack_NATApp.h
@@ -0,0 +1,118 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef IPACM_CONNTRACK_NATAPP_H
+#define IPACM_CONNTRACK_NATAPP_H
+
+#include <string.h>  /* for stderror */
+#include <stdlib.h>
+#include <cstdio>  /* for perror */
+
+#include "IPACM_Config.h"
+#include "IPACM_Xml.h"
+
+extern "C"
+{
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <ipa_nat_drv.h>
+}
+
+#define IPACM_DEBUG
+
+typedef struct _nat_table_entry
+{
+	uint32_t private_ip;
+	uint16_t private_port;
+
+	uint32_t target_ip;
+	uint16_t target_port;
+
+	uint16_t public_port;
+
+	u_int8_t  protocol;
+	uint32_t timestamp;
+
+	bool dst_nat;
+	uint32_t rule_hdl;
+
+}nat_table_entry;
+
+#define CHK_TBL_HDL() if(0 == nat_table_hdl){\
+                             int n =0; \
+                             n = snprintf(log_buf, sizeof(log_buf), "%s:%d %s() %s", __FILE__,  __LINE__, __FUNCTION__, "Error:");\
+                             snprintf((log_buf+n), (sizeof(log_buf)-n)-1, "Invalid table handle\n");\
+                             logmessage(log_buf);\
+				  		             }
+
+class NatApp
+{
+private:
+
+	static NatApp *pInstance;
+
+	nat_table_entry *cache;
+	uint32_t pub_ip_addr;
+	uint32_t nat_table_hdl;
+
+	int curCnt, max_entries;
+
+	ipacm_alg *pALGPorts;
+	uint16_t nALGPort;
+
+	uint32_t PwrSaveIfs[IPA_MAX_NUM_WIFI_CLIENTS];
+
+	struct nf_conntrack *ct;
+	struct nfct_handle *ct_hdl;
+
+	NatApp();
+	int Init();
+
+	void UpdateCTUdpTs(nat_table_entry *, uint32_t);
+	bool ChkForDup(const nat_table_entry *);
+	bool isAlgPort(uint8_t, uint16_t);
+	void Reset();
+	bool isPwrSaveIf(uint32_t);
+
+public:
+	static NatApp* GetInstance();
+
+	int AddTable(uint32_t);
+	int DeleteTable(uint32_t);
+
+	int AddEntry(const nat_table_entry *);
+	int DeleteEntry(const nat_table_entry *);
+
+	void UpdateUDPTimeStamp();
+
+	int UpdatePwrSaveIf(uint32_t);
+	int ResetPwrSaveIf(uint32_t);
+};
+
+
+
+#endif /* IPACM_CONNTRACK_NATAPP_H */
diff --git a/ipacm/inc/IPACM_Defs.h b/ipacm/inc/IPACM_Defs.h
new file mode 100644
index 0000000..19ddbec
--- /dev/null
+++ b/ipacm/inc/IPACM_Defs.h
@@ -0,0 +1,178 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_Defs.h
+
+	@brief
+	This file implements the common definitions amon all ifaces.
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPA_CM_DEFS_H
+#define IPA_CM_DEFS_H
+
+#include <linux/msm_ipa.h>
+#include "IPACM_Log.h"
+
+extern "C"
+{
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
+}
+
+
+#define IPA_MAX_FILE_LEN  64
+#define IPA_IFACE_NAME_LEN 16
+#define IPA_ALG_PROTOCOL_NAME_LEN  10
+
+#define IPA_WLAN_PARTIAL_HDR_OFFSET  12 // dst mac first then src mac
+#define IPA_VIRTUAL_IFACE_NAME "bridge0"
+#define IPA_WLAN_PARTIAL_HDR_NAME  "IEEE802_3"
+#define IPA_MAX_IFACE_ENTRIES 15
+#define IPA_MAX_PRIVATE_SUBNET_ENTRIES 3
+#define IPA_MAX_ALG_ENTRIES 10
+
+#define V4_LAN_ROUTE_TABLE_NAME  "COMRTBLLANv4"
+#define V4_WAN_ROUTE_TABLE_NAME  "WANRTBLv4"
+#define V6_COMMON_ROUTE_TABLE_NAME  "COMRTBLv6"
+
+
+
+/*---------------------------------------------------------------------------
+										Return values indicating error status
+---------------------------------------------------------------------------*/
+
+#define IPACM_SUCCESS                0         /* Successful operation   */
+#define IPACM_FAILURE               -1         /* Unsuccessful operation */
+
+#define IPACM_IP_NULL (ipa_ip_type)0xFF
+#define IPACM_INVALID_INDEX (ipa_ip_type)0xFF
+
+#define IPA_MAX_NUM_WIFI_CLIENTS  15
+#define IPA_MAX_NUM_AMPDU_RULE  15
+#define IPA_MAC_ADDR_SIZE  6
+
+/*===========================================================================
+										 GLOBAL DEFINITIONS AND DECLARATIONS
+===========================================================================*/
+typedef enum
+{
+	IPA_LINK_UP_EVENT = 1,                    /* ipacm_event_data_fid */
+	IPA_LINK_DOWN_EVENT,                      /* 2 ipacm_event_data_fid */
+	IPA_ADDR_ADD_EVENT,                       /* 3 ipacm_event_data_addr */
+	IPA_ADDR_DEL_EVENT,                       /* 4 no use */
+	IPA_ROUTE_ADD_EVENT,                      /* 5 ipacm_event_data_addr */
+	IPA_ROUTE_DEL_EVENT,                      /* 6 ipacm_event_data_addr */
+	IPA_FIREWALL_CHANGE_EVENT,                /* 7 NULL */
+	IPA_WLAN_CLIENT_ADD_EVENT,                /* 8 ipacm_event_data_mac */
+	IPA_WLAN_CLIENT_DEL_EVENT,                /* 9 ipacm_event_data_mac */
+	IPA_WLAN_CLIENT_POWER_SAVE_EVENT,         /* 10 ipacm_event_data_mac */
+	IPA_WLAN_CLIENT_RECOVER_EVENT,            /* 11 ipacm_event_data_mac */
+	IPA_NEW_NEIGH_EVENT,                      /* 12 ipacm_event_data_all */
+	IPA_DEL_NEIGH_EVENT,                      /* 13 ipacm_event_data_all */
+	IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT,       /* 14 ipacm_event_data_all */
+	IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT,       /* 15 ipacm_event_data_all */
+	IPA_SW_ROUTING_ENABLE,                    /* 16 NULL */
+	IPA_SW_ROUTING_DISABLE,                   /* 17 NULL */
+	IPA_PROCESS_CT_MESSAGE,                   /* 18 ipacm_ct_evt_data */
+	IPA_HANDLE_WAN_UP,                        /* 19 unsigned long  */
+	IPA_HANDLE_WAN_DOWN,                      /* 20 unsigned long  */
+	IPA_HANDLE_WLAN_UP,                       /* 21 unsigned long  */
+	IPA_HANDLE_LAN_UP                         /* 22 unsigned long  */
+} ipa_cm_event_id;
+
+typedef enum
+{
+	LAN_IF = 0,
+	WLAN_IF,
+	WAN_IF,
+	VIRTUAL_IF
+} ipacm_iface_type;
+
+typedef struct
+{
+	struct nf_conntrack *ct;
+	enum nf_conntrack_msg_type type;
+}ipacm_ct_evt_data;
+
+typedef struct
+{
+	char iface_name[IPA_IFACE_NAME_LEN];
+	ipacm_iface_type if_cat;
+	int netlink_interface_index;
+} ipa_ifi_dev_name_t;
+
+typedef struct
+{
+	uint32_t subnet_addr;
+	uint32_t subnet_mask;
+} ipa_private_subnet;
+
+
+typedef struct _ipacm_event_data_all
+{
+	enum ipa_ip_type iptype;
+	int if_index;
+	uint32_t  ipv4_addr;
+	uint32_t  ipv6_addr[4];
+	uint8_t mac_addr[6];
+} ipacm_event_data_all;
+
+typedef struct _ipacm_event_data_fid
+{
+	int if_index;
+} ipacm_event_data_fid;
+
+typedef struct _ipacm_event_data_addr
+{
+	enum ipa_ip_type iptype;
+	int if_index;
+	uint32_t  ipv4_addr;
+	uint32_t  ipv4_addr_mask;
+	uint32_t  ipv6_addr[4];
+	uint32_t  ipv6_addr_mask[4];
+} ipacm_event_data_addr;
+
+typedef struct _ipacm_event_data_mac
+{
+	int if_index;
+	uint8_t mac_addr[6];
+} ipacm_event_data_mac;
+
+typedef struct _ipacm_event_iface_up
+{
+	char ifname[IPA_IFACE_NAME_LEN];
+	uint32_t ipv4_addr;
+	uint32_t addr_mask;
+}ipacm_event_iface_up;
+
+#endif /* IPA_CM_DEFS_H */
diff --git a/ipacm/inc/IPACM_EvtDispatcher.h b/ipacm/inc/IPACM_EvtDispatcher.h
new file mode 100644
index 0000000..550f4d4
--- /dev/null
+++ b/ipacm/inc/IPACM_EvtDispatcher.h
@@ -0,0 +1,76 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*!
+	@file
+	IPACM_EvtDispatcher.h
+
+	@brief
+	This file implements the IPAM event dispatcher definitions
+
+	@Author
+
+*/
+#ifndef IPACM_EvtDispatcher_H
+#define IPACM_EvtDispatcher_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+#include "IPACM_Defs.h"
+#include "IPACM_Listener.h"
+
+/* queue */
+typedef struct _cmd_evts
+{
+	ipa_cm_event_id event;
+	IPACM_Listener *obj;
+	//int ipa_interface_index;
+	_cmd_evts *next;
+}  cmd_evts;
+
+
+
+class IPACM_EvtDispatcher
+{
+public:
+
+	/* api for all iface instances to register events */
+	static int registr(ipa_cm_event_id event, IPACM_Listener *obj);
+
+	/* api for all iface instances to de-register events */
+	static int deregistr(IPACM_Listener *obj);
+
+	static int PostEvt(ipacm_cmd_q_data *);
+	static void ProcessEvt(ipacm_cmd_q_data *);
+
+private:
+	static cmd_evts *head;
+};
+
+#endif /* IPACM_EvtDispatcher_H */
diff --git a/ipacm/inc/IPACM_Filtering.h b/ipacm/inc/IPACM_Filtering.h
new file mode 100644
index 0000000..2d49abf
--- /dev/null
+++ b/ipacm/inc/IPACM_Filtering.h
@@ -0,0 +1,69 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*!
+	@file
+	IPACM_Filtering.h
+
+	@brief
+	This file implements the IPACM filtering definitions
+
+	@Author
+	Skylar Chang
+
+*/
+
+#ifndef IPACM_FILTERING_H
+#define IPACM_FILTERING_H
+
+#include <stdint.h>
+#include <linux/msm_ipa.h>
+#include <IPACM_Defs.h>
+
+class IPACM_Filtering
+{
+public:
+	IPACM_Filtering();
+	~IPACM_Filtering();
+	bool AddFilteringRule(struct ipa_ioc_add_flt_rule const *ruleTable);
+	bool DeleteFilteringRule(struct ipa_ioc_del_flt_rule *ruleTable);
+	bool Commit(enum ipa_ip_type ip);
+	bool Reset(enum ipa_ip_type ip);
+	bool DeviceNodeIsOpened();
+	bool DeleteFilteringHdls(uint32_t *flt_rule_hdls,
+													 ipa_ip_type ip,
+													 uint8_t num_rules);
+
+private:
+	static const char *DEVICE_NAME;
+	int fd; /* File descriptor of the IPA device node /dev/ipa */
+};
+
+#endif //IPACM_FILTERING_H
+
diff --git a/ipacm/inc/IPACM_Header.h b/ipacm/inc/IPACM_Header.h
new file mode 100644
index 0000000..b6973cb
--- /dev/null
+++ b/ipacm/inc/IPACM_Header.h
@@ -0,0 +1,68 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * IPACM_Header.h
+ *
+ *  Created on: Jun 20, 2012
+ *      Author: tatias
+ */
+
+//////////////////////////////////////////////////////////////////////////////////
+
+#ifndef IPACM_HEADER_H
+#define IPACM_HEADER_H
+
+#include <stdint.h>
+#include "linux/msm_ipa.h"
+
+//////////////////////////////////////////////////////////////////////////////////
+
+class IPACM_Header
+{
+private:
+	int m_fd;
+public:
+	bool AddHeader(struct ipa_ioc_add_hdr   *pHeaderTable);
+	bool DeleteHeader(struct ipa_ioc_del_hdr *pHeaderTable);
+	bool GetHeaderHandle(struct ipa_ioc_get_hdr *pHeaderStruct);
+	bool CopyHeader(struct ipa_ioc_copy_hdr *pCopyHeaderStruct);
+	bool Commit();
+	bool Reset();
+	bool DeleteHeaderHdl(uint32_t hdr_hdl);
+
+	IPACM_Header();
+	~IPACM_Header();
+	bool DeviceNodeIsOpened();
+};
+
+
+#endif
+
+
diff --git a/ipacm/inc/IPACM_Iface.h b/ipacm/inc/IPACM_Iface.h
new file mode 100644
index 0000000..9e3cafd
--- /dev/null
+++ b/ipacm/inc/IPACM_Iface.h
@@ -0,0 +1,131 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+		@file
+		IPACM_iface.h
+
+		@brief
+		This file implements the basis Iface definitions.
+
+		@Author
+		Skylar Chang
+
+*/
+#ifndef IPACM_IFACE_H
+#define IPACM_IFACE_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+#include <linux/msm_ipa.h>
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include "IPACM_Header.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Xml.h"
+#include "IPACM_Log.h"
+#include "IPACM_Netlink.h"
+#include "IPACM_Config.h"
+#include "IPACM_Defs.h"
+
+/* current support 2 ipv6-address*/
+#define MAX_DEFAULT_v6_ROUTE_RULES  2
+#define IPV4_DEFAULT_FILTERTING_RULES 3
+#define IPV6_DEFAULT_FILTERTING_RULES 1
+#define IPV6_DEFAULT_LAN_FILTERTING_RULES 1
+#define MAX_SOFTWAREROUTING_FILTERTING_RULES 2
+
+/* iface */
+class IPACM_Iface : public IPACM_Listener
+{
+public:
+
+    /* Static class for reading IPACM configuration from XML file*/
+    static IPACM_Config *ipacmcfg;
+
+		/* IPACM interface id */
+		int ipa_if_num;
+
+		/* IPACM interface name */
+		char dev_name[IF_NAME_LEN];
+
+		/* IPACM interface iptype v4, v6 or both */
+		ipa_ip_type ip_type;
+
+		uint32_t header_hdl;
+
+		uint32_t software_routing_fl_rule_hdl[MAX_SOFTWAREROUTING_FILTERTING_RULES];
+
+		bool softwarerouting_act;
+
+		int num_dft_rt;
+
+		uint32_t dft_v4fl_rule_hdl[IPV4_DEFAULT_FILTERTING_RULES];
+		uint32_t dft_v6fl_rule_hdl[IPV6_DEFAULT_FILTERTING_RULES + IPV6_DEFAULT_LAN_FILTERTING_RULES];
+		uint32_t dft_rt_rule_hdl[1+MAX_DEFAULT_v6_ROUTE_RULES]; /* 1 for ipv4 */
+
+		ipa_ioc_query_intf *iface_query;
+		ipa_ioc_query_intf_tx_props *tx_prop;
+		ipa_ioc_query_intf_rx_props *rx_prop;
+
+		virtual int handle_down_evt() = 0;
+
+		virtual int handle_addr_evt(ipacm_event_data_addr *data) = 0;
+
+		IPACM_Iface(int iface_index);
+
+		virtual void event_callback(ipa_cm_event_id event,
+																void *data) = 0;
+
+	
+    /* Query ipa_interface_index by given linux interface_index */
+  	static int iface_ipa_index_query(int interface_index);
+	  
+    /*Query the IPA endpoint property */
+    int query_iface_property(void);
+
+		/*Configure the initial filter rules */
+		virtual int init_fl_rule(ipa_ip_type iptype);
+
+		static IPACM_Routing m_routing;
+		static IPACM_Filtering m_filtering;
+		static IPACM_Header m_header;
+
+		/* software routing enable */
+		virtual int handle_software_routing_enable(void);
+
+		/* software routing disable */
+		virtual int handle_software_routing_disable(void);
+
+
+private:
+
+		static const char *DEVICE_NAME;
+};
+
+#endif /* IPACM_IFACE_H */
diff --git a/ipacm/inc/IPACM_IfaceManager.h b/ipacm/inc/IPACM_IfaceManager.h
new file mode 100644
index 0000000..b295658
--- /dev/null
+++ b/ipacm/inc/IPACM_IfaceManager.h
@@ -0,0 +1,91 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_IfaceManager.h
+
+	@brief
+	This file implements the IPAM iface_manager definitions
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPACM_IFACEMANAGER_H
+#define IPACM_IFACEMANAGER_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include "IPACM_Listener.h"
+#include "IPACM_Iface.h"
+
+#define IPA_MAX_NUM_NEIGHBOR_CLIENTS  17
+#define IPA_INSTANCE_NOT_FOUND  0
+#define IPA_INSTANCE_FOUND  1
+
+/* queue */
+typedef struct _iface_instances
+{
+    /* Linux interface id */
+	int ipa_if_index;
+	IPACM_Listener *obj;
+	_iface_instances *next;
+}  iface_instances;
+
+
+class IPACM_IfaceManager : public IPACM_Listener
+{
+
+public:
+
+  IPACM_IfaceManager(); 
+  
+  void event_callback(ipa_cm_event_id event,
+                      void *data);
+
+  /* api for all iface instances to de-register instances */
+  static int deregistr(IPACM_Listener *param);
+
+					  
+private:
+	int create_iface_instance(int if_index);
+
+    /* api to register instances */	
+	int registr(int ipa_if_index, IPACM_Listener *obj);
+		
+	int SearchInstance(int ipa_if_index);
+	
+	static iface_instances *head;
+
+};
+
+#endif /* IPACM_IFACEMANAGER_H */
diff --git a/ipacm/inc/IPACM_Lan.h b/ipacm/inc/IPACM_Lan.h
new file mode 100644
index 0000000..849e5df
--- /dev/null
+++ b/ipacm/inc/IPACM_Lan.h
@@ -0,0 +1,118 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_Lan.h
+
+	@brief
+	This file implements the LAN iface definitions
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPACM_LAN_H
+#define IPACM_LAN_H
+
+#include <stdio.h>
+#include <linux/msm_ipa.h>
+
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Iface.h"
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+
+#define IPA_MAX_NUM_UNICAST_ROUTE_RULES  6
+#define IPA_WAN_DEFAULT_FILTER_RULE_HANDLES  1
+#define IPA_PRIV_SUBNET_FILTER_RULE_HANDLES  3
+
+/* store each lan-iface unicast routing rule and its handler*/
+struct ipa_lan_rt_rule
+{
+	enum ipa_ip_type ip;
+	ipa_rule_attrib rule;
+	uint32_t rt_rule_hdl[0];
+};
+
+/* lan iface */
+class IPACM_Lan : public IPACM_Iface
+{
+public:
+
+	IPACM_Lan(int iface_index);
+	~IPACM_Lan();
+
+	/* store lan's wan-up filter rule handlers */
+	uint32_t lan_wan_fl_rule_hdl[IPA_WAN_DEFAULT_FILTER_RULE_HANDLES];
+
+	/* store private-subnet filter rule handlers */
+	uint32_t private_fl_rule_hdl[IPA_PRIV_SUBNET_FILTER_RULE_HANDLES];
+
+	/* LAN-iface's callback function */
+	void event_callback(ipa_cm_event_id event,
+											void *data);
+
+	/* configure filter rule for wan_up event*/
+	virtual int handle_wan_up(void);
+
+	/* delete filter rule for wan_down event*/
+	virtual int handle_wan_down(void);
+
+	/* configure private subnet filter rules*/
+	virtual int handle_private_subnet(ipa_ip_type iptype);
+
+	/* handle new_address event*/
+	int handle_addr_evt(ipacm_event_data_addr *data);
+
+private:
+
+	/* dynamically allocate lan iface's unicast routing rule structure */
+	int rt_rule_len;
+	ipa_lan_rt_rule *route_rule;
+
+	/* store the number of lan-iface's unicast routing rule */
+	int num_uni_rt;
+
+	inline ipa_lan_rt_rule* get_rt_ruleptr(ipa_lan_rt_rule *param, int cnt)
+	{
+		return (param + (rt_rule_len * cnt));
+	}
+
+	/* handle unicast routing rule add event */
+	int handle_route_add_evt(ipacm_event_data_addr *data);
+
+	/* handle unicast routing rule del event */
+	int handle_route_del_evt(ipacm_event_data_addr *data);
+
+	/*handle wlan iface down event*/
+	int handle_down_evt();
+
+};
+
+#endif /* IPACM_LAN_H */
diff --git a/ipacm/inc/IPACM_Listener.h b/ipacm/inc/IPACM_Listener.h
new file mode 100644
index 0000000..02a082e
--- /dev/null
+++ b/ipacm/inc/IPACM_Listener.h
@@ -0,0 +1,55 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_Listener.h
+
+	@brief
+	This file implements the abstract class notifier.
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPACM_LISTENER_H
+#define IPACM_LISTENER_H
+
+#include "IPACM_Defs.h"
+#include "IPACM_CmdQueue.h"
+
+/* abstract class notifier */
+class IPACM_Listener
+{
+public:
+	virtual void event_callback(ipa_cm_event_id event,
+															void *data) = 0;
+};
+
+#endif /* IPACM_LISTENER_H */
+
diff --git a/ipacm/inc/IPACM_Log.h b/ipacm/inc/IPACM_Log.h
new file mode 100644
index 0000000..785b654
--- /dev/null
+++ b/ipacm/inc/IPACM_Log.h
@@ -0,0 +1,79 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_log.h
+
+	@brief
+	This file implements the IPAM log functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+
+#ifndef IPACM_LOG_H
+#define IPACM_LOG_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#define LOG_SIZE 200
+
+#define PERROR(fmt)   printf("%s:%d %s()", __FILE__, __LINE__, __FUNCTION__);\
+                      perror(fmt);
+
+#define IPACMDBG(fmt, ...) {\
+                             int n =0; \
+                             n = snprintf(log_buf, sizeof(log_buf), "%s:%d %s() ", __FILE__,  __LINE__, __FUNCTION__);\
+                             snprintf((log_buf+n), (sizeof(log_buf)-n-1), fmt, ##__VA_ARGS__);\
+                             logmessage(log_buf);\
+				  		             }
+
+
+#define IPACMERR(fmt, ...) {\
+                             int n =0; \
+                             n = snprintf(log_buf, sizeof(log_buf), "%s:%d %s() %s", __FILE__,  __LINE__, __FUNCTION__, "Error:");\
+                             snprintf((log_buf+n), (sizeof(log_buf)-n-1), fmt, ##__VA_ARGS__);\
+                             logmessage(log_buf);\
+				  		             }
+
+extern void logmessage(char *msg);
+extern char log_buf[LOG_SIZE];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IPACM_LOG_H */
diff --git a/ipacm/inc/IPACM_Neighbor.h b/ipacm/inc/IPACM_Neighbor.h
new file mode 100644
index 0000000..af7ab46
--- /dev/null
+++ b/ipacm/inc/IPACM_Neighbor.h
@@ -0,0 +1,79 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_Neighbor.h
+
+	@brief
+	This file implements the functionality of handling IPACM Neighbor events.
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPACM_NEIGHBOR_H
+#define IPACM_NEIGHBOR_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+#include <linux/msm_ipa.h>
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include "IPACM_Listener.h"
+#include "IPACM_Iface.h"
+
+#define IPA_MAX_NUM_NEIGHBOR_CLIENTS  17
+
+struct ipa_neighbor_client
+{
+	uint8_t mac_addr[6];
+	uint32_t v6_addr[4];
+	int iface_index;
+};
+
+class IPACM_Neighbor : public IPACM_Listener
+{
+
+public:
+
+	IPACM_Neighbor();
+
+	void event_callback(ipa_cm_event_id event,
+											void *data);
+
+private:
+
+	int num_neighbor_client;
+
+	ipa_neighbor_client neighbor_client[IPA_MAX_NUM_NEIGHBOR_CLIENTS];
+
+
+};
+
+#endif /* IPACM_NEIGHBOR_H */
diff --git a/ipacm/inc/IPACM_Netlink.h b/ipacm/inc/IPACM_Netlink.h
new file mode 100644
index 0000000..fe98375
--- /dev/null
+++ b/ipacm/inc/IPACM_Netlink.h
@@ -0,0 +1,221 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPA_Netlink.h
+
+	@brief
+	IPACM Netlink Messaging Implementation File
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPACM_NETLINK_H
+#define IPACM_NETLINK_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_addr.h>
+#include <linux/rtnetlink.h>
+#include <linux/netlink.h>
+#include <netinet/in.h>
+#include "IPACM_Defs.h"
+
+#define MAX_NUM_OF_FD 10
+#define IPA_NL_MSG_MAX_LEN (1024)
+#define IF_NAME_LEN 16
+
+
+/*--------------------------------------------------------------------------- 
+	 Type representing enumeration of NetLink event indication messages
+---------------------------------------------------------------------------*/
+
+/*--------------------------------------------------------------------------- 
+	 Types representing parsed NetLink message
+---------------------------------------------------------------------------*/
+#define IPA_NLA_PARAM_NONE        (0x0000)
+#define IPA_NLA_PARAM_PREFIXADDR  (0x0001)
+#define IPA_NLA_PARAM_LOCALADDR   (0x0002)
+#define IPA_NLA_PARAM_LABELNAME   (0x0004)
+#define IPA_NLA_PARAM_BCASTADDR   (0x0008)
+#define IPA_NLA_PARAM_ACASTADDR   (0x0010)
+#define IPA_NLA_PARAM_MCASTADDR   (0x0020)
+#define IPA_NLA_PARAM_CACHEINFO   (0x0080)
+#define IPA_NLA_PARAM_PROTOINFO   (0x0100)
+#define IPA_NLA_PARAM_FLAGS       (0x0200)
+
+#define IPA_RTA_PARAM_NONE        (0x0000)
+#define IPA_RTA_PARAM_DST         (0x0001)
+#define IPA_RTA_PARAM_SRC         (0x0002)
+#define IPA_RTA_PARAM_GATEWAY     (0x0004)
+#define IPA_RTA_PARAM_IIF         (0x0008)
+#define IPA_RTA_PARAM_OIF         (0x0010)
+#define IPA_RTA_PARAM_CACHEINFO   (0x0020)
+#define IPA_RTA_PARAM_PRIORITY    (0x0080)
+#define IPA_RTA_PARAM_METRICS     (0x0100)
+
+
+/*--------------------------------------------------------------------------- 
+	 Type representing function callback registered with a socket listener 
+	 thread for reading from a socket on receipt of an incoming message
+---------------------------------------------------------------------------*/
+typedef int (*ipa_sock_thrd_fd_read_f)(int fd);
+
+typedef enum
+{
+	IPA_INIT = 0,
+	IPA_LINK_UP_WAIT,
+	IPA_LINK_UP,
+	IPA_LINK_DOWN_WAIT,
+	IPA_LINK_DOWN
+} ipa_nl_state_e;
+
+typedef struct
+{
+	int sk_fd;
+	ipa_sock_thrd_fd_read_f read_func;
+} ipa_nl_sk_fd_map_info_t;
+
+typedef struct
+{
+	ipa_nl_sk_fd_map_info_t sk_fds[MAX_NUM_OF_FD];
+	fd_set fdset;
+	int num_fd;
+	int max_fd;
+} ipa_nl_sk_fd_set_info_t;
+
+typedef struct
+{
+	int                 sk_fd;       /* socket descriptor */
+	struct sockaddr_nl  sk_addr_loc; /* local address of socket */
+} ipa_nl_sk_info_t;
+
+typedef struct ipa_nl_addr_s {
+	struct sockaddr_storage        ip_addr;
+	unsigned int                   mask;
+} ipa_nl_addr_t;
+
+typedef struct ipa_nl_proto_info_s {
+	unsigned int                    param_mask;
+	unsigned int                    flags;
+	struct ifla_cacheinfo           cache_info;
+} ipa_nl_proto_info_t;
+
+typedef struct
+{
+	struct ifinfomsg  metainfo;                   /* from header */
+} ipa_nl_link_info_t;
+
+
+
+typedef struct ipa_nl_addr_info_s {
+	struct ifaddrmsg                metainfo;     /* from header */
+	struct                                      /* attributes  */
+	{
+		unsigned int                  param_mask;
+		unsigned char                 label_name[IF_NAME_LEN];
+		struct sockaddr_storage       prefix_addr;
+	} attr_info;
+} ipa_nl_addr_info_t;
+
+
+typedef struct ipa_nl_neigh_info_s {
+	struct ndmsg                metainfo;     /* from header */
+	struct                                  /* attributes  */
+	{
+		unsigned int                param_mask;
+		struct sockaddr_storage     local_addr;
+		struct  sockaddr            lladdr_hwaddr;
+	} attr_info;
+} ipa_nl_neigh_info_t;
+
+
+
+typedef struct ipa_nl_route_info_s {
+	struct rtmsg                    metainfo;     /* from header */
+	struct                                      /* attributes  */
+	{
+		unsigned int                  param_mask;
+		struct sockaddr_storage       dst_addr;
+		struct sockaddr_storage       src_addr;
+		struct sockaddr_storage       gateway_addr;
+		struct sockaddr_storage       mark_addr;
+		struct rta_cacheinfo          cache_info;
+		__u32		iif_index;                      /* Link index  */
+		__u32		oif_index;                      /* Link index  */
+		__u32       priority;
+		__u32       metrics;
+		ipa_nl_proto_info_t        proto_info;
+	} attr_info;
+} ipa_nl_route_info_t;
+
+#define IPA_FLOW_TYPE_INVALID      (-1)
+
+typedef struct
+{
+	unsigned int type;
+	bool link_event;
+	/* Optional parameters */
+	ipa_nl_link_info_t      nl_link_info;
+	ipa_nl_addr_info_t      nl_addr_info;
+	ipa_nl_neigh_info_t      nl_neigh_info;
+	ipa_nl_route_info_t      nl_route_info;
+} ipa_nl_msg_t;
+
+/* Initialization routine for listener on NetLink sockets interface */
+int ipa_nl_listener_init
+(
+	 unsigned int nl_type,
+	 unsigned int nl_groups,
+	 ipa_nl_sk_fd_set_info_t *sk_fdset,
+	 ipa_sock_thrd_fd_read_f read_f
+	 );
+
+/*  Virtual function registered to receive incoming messages over the NETLINK routing socket*/
+int ipa_nl_recv_msg(int fd);
+
+/* map mask value for ipv6 */
+int mask_v6(int index, uint32_t *mask);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IPACM_NETLINK_H */
diff --git a/ipacm/inc/IPACM_Routing.h b/ipacm/inc/IPACM_Routing.h
new file mode 100644
index 0000000..ca7a5fd
--- /dev/null
+++ b/ipacm/inc/IPACM_Routing.h
@@ -0,0 +1,75 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_Routing.cpp
+
+	@brief
+	This file implements the IPACM routing functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+
+
+#ifndef IPACM_ROUTING_H
+#define IPACM_ROUTING_H
+
+#include <stdint.h>
+#include <linux/msm_ipa.h>
+#include <IPACM_Defs.h>
+
+using namespace std;
+
+class IPACM_Routing
+{
+public:
+	IPACM_Routing();
+	~IPACM_Routing();
+
+	bool AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable);
+	bool DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable);
+
+	bool Commit(enum ipa_ip_type ip);
+	bool Reset(enum ipa_ip_type ip);
+
+	bool GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable);
+	bool PutRoutingTable(uint32_t routingTableHandle);
+
+	bool DeviceNodeIsOpened();
+	bool DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip);
+
+private:
+	static const char *DEVICE_NAME;
+	int m_fd; /* File descriptor of the IPA device node /dev/ipa */
+};
+
+#endif //IPACM_ROUTING_H
+
diff --git a/ipacm/inc/IPACM_Wan.h b/ipacm/inc/IPACM_Wan.h
new file mode 100644
index 0000000..5177fe1
--- /dev/null
+++ b/ipacm/inc/IPACM_Wan.h
@@ -0,0 +1,110 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_Wan.cpp
+
+	@brief
+	This file implements the WAN iface functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+#ifndef IPACM_WAN_H
+#define IPACM_WAN_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+#include <linux/msm_ipa.h>
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include <IPACM_Iface.h>
+#include <IPACM_Defs.h>
+#include <IPACM_Xml.h>
+
+#define IPA_NUM_DEFAULT_WAN_FILTER_RULES 2
+
+/* wan iface */
+class IPACM_Wan : public IPACM_Iface
+{
+
+public:
+
+	static bool wan_up;
+
+	IPACM_Wan(int iface_index);
+	~IPACM_Wan();
+
+	static bool isWanUP()
+	{
+		return wan_up;
+	}
+
+	void event_callback(ipa_cm_event_id event,
+											void *data);
+
+private:
+	uint32_t *wan_route_rule_v4_hdl;
+	uint32_t *wan_route_rule_v6_hdl;
+	uint32_t firewall_hdl_v4[IPACM_MAX_FIREWALL_ENTRIES];
+	uint32_t firewall_hdl_v6[IPACM_MAX_FIREWALL_ENTRIES];
+	uint32_t dft_wan_fl_hdl[IPA_NUM_DEFAULT_WAN_FILTER_RULES];
+	int num_firewall_v4,num_firewall_v6;
+	bool active_v4;
+	bool active_v6;
+	uint32_t wan_v4_addr;
+
+	/* IPACM firewall Configuration file*/
+	IPACM_firewall_conf_t firewall_config;
+
+	/* handle new_address event */
+	int handle_addr_evt(ipacm_event_data_addr *data);
+
+	/* wan default route/filter rule configuration */
+	int handle_route_add_evt(ipacm_event_data_addr *data);
+
+	/* wan default route/filter rule delete */	
+	int handle_route_del_evt(ipa_ip_type iptype);
+
+	/* construct complete ethernet header */
+	int handle_header_add_evt(uint8_t mac_addr[6]);
+
+	/* configure the initial firewall filter rules */
+	int config_dft_firewall_rules(ipa_ip_type ip_type);
+
+	/*clean firewall filter rules */
+	int del_dft_firewall_rules(ipa_ip_type ip_type);
+
+	/*handle wan-iface down event */
+	int handle_down_evt();
+
+};
+
+#endif /* IPACM_WAN_H */
diff --git a/ipacm/inc/IPACM_Wlan.h b/ipacm/inc/IPACM_Wlan.h
new file mode 100644
index 0000000..0535584
--- /dev/null
+++ b/ipacm/inc/IPACM_Wlan.h
@@ -0,0 +1,224 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+		@file
+		IPACM_Wlan.h
+
+		@brief
+		This file implements the WLAN iface functionality.
+
+		@Author
+		Skylar Chang
+
+*/
+#ifndef IPACM_WLAN_H
+#define IPACM_WLAN_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+#include <linux/msm_ipa.h>
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include "IPACM_Lan.h"
+#include "IPACM_Iface.h"
+
+typedef struct _wlan_client_rt_hdl
+{
+	uint32_t wifi_rt_rule_hdl_v4;
+	uint32_t wifi_rt_rule_hdl_v6;
+}wlan_client_rt_hdl;
+
+typedef struct _ipa_wlan_client
+{
+	uint8_t mac[IPA_MAC_ADDR_SIZE];
+	uint32_t v4_addr;
+	uint32_t v6_addr[4];
+	uint32_t hdr_hdl;
+	bool route_rule_set_v4;
+	bool route_rule_set_v6;
+	bool ipv4_set;
+	bool ipv6_set;
+	wlan_client_rt_hdl wifi_rt_hdl[0]; /* depends on number of tx properties */
+}ipa_wlan_client;
+
+typedef struct _wlan_ampdu_flt_rules
+{
+	uint32_t hdl[IPA_MAX_NUM_AMPDU_RULE];
+	ipa_ip_type ip[IPA_MAX_NUM_AMPDU_RULE];
+	int num_rules;
+}wlan_ampdu_flt_rules;
+
+
+
+/* wlan iface */
+class IPACM_Wlan : public IPACM_Lan
+{
+
+public:
+
+	IPACM_Wlan(int iface_index);
+	~IPACM_Wlan(void);
+
+	static int total_num_wifi_clients;
+
+	void event_callback(ipa_cm_event_id event,
+											void *data);
+
+private:
+	int wlan_client_len;
+	ipa_wlan_client *wlan_client;
+
+	int header_name_count; 
+	int num_wifi_client;
+	wlan_ampdu_flt_rules wlan_ampdu_flt_rule;
+
+	inline ipa_wlan_client* get_client_memptr(ipa_wlan_client *param, int cnt)
+	{
+		return (param + (wlan_client_len * cnt));
+	}
+
+	inline int get_wlan_client_index(uint8_t *mac_addr)
+	{
+		int cnt;
+		int num_wifi_client_tmp = num_wifi_client;
+
+		IPACMDBG("Passed MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+						 mac_addr[0], mac_addr[1], mac_addr[2],
+						 mac_addr[3], mac_addr[4], mac_addr[5]);
+
+		for(cnt = 0; cnt < num_wifi_client_tmp; cnt++)
+		{
+			IPACMDBG("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+							 get_client_memptr(wlan_client, cnt)->mac[0],
+							 get_client_memptr(wlan_client, cnt)->mac[1],
+							 get_client_memptr(wlan_client, cnt)->mac[2],
+							 get_client_memptr(wlan_client, cnt)->mac[3],
+							 get_client_memptr(wlan_client, cnt)->mac[4],
+							 get_client_memptr(wlan_client, cnt)->mac[5]);
+
+			if(memcmp(get_client_memptr(wlan_client, cnt)->mac,
+								mac_addr,
+								sizeof(get_client_memptr(wlan_client, cnt)->mac)) == 0)
+			{
+				IPACMDBG("Matched client index: %d\n", cnt);
+				return cnt;
+			}
+		}
+
+		return IPACM_INVALID_INDEX;
+	}
+
+	inline int delete_default_qos_rtrules(int clt_indx)
+	{
+		uint32_t tx_index;
+		uint32_t rt_hdl;
+
+		for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+			if((ip_type != IPA_IP_v6) && (get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4==true)) /* for ipv4 */
+			{
+			  IPACMDBG("Delete client index %d ipv4 Qos rules \n", clt_indx);
+				rt_hdl = get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4;
+
+				if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v4) == false)
+				{
+					return IPACM_FAILURE;
+				}
+			}
+
+			if((ip_type != IPA_IP_v4) && (get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6==true)) /* for ipv6 */
+			{
+			  IPACMDBG("Delete client index %d ipv6 Qos rules \n", clt_indx);
+				rt_hdl = get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6;
+
+				if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+				{
+					return IPACM_FAILURE;
+				}
+			}
+
+		} /* end of for loop */
+		
+		/* clean the 4 Qos ipv4 RT rules for client:clt_indx */
+		if(ip_type != IPA_IP_v6) /* for ipv4 */
+		{
+		  get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4=false;
+        }
+
+		/* clean the 4 Qos ipv6 RT rules for client:clt_indx */
+		if(ip_type != IPA_IP_v4) /* for ipv6 */
+		{
+		  get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6=false;
+        }
+		
+		return IPACM_SUCCESS;
+	}
+
+	/* handle wifi client initial,copy all partial headers (tx property) */
+	int handle_wlan_client_init(uint8_t *mac_addr);
+
+	/*handle wifi client */
+	int handle_wlan_client_ipaddr(ipacm_event_data_all *data);
+
+	/*handle wifi client routing rule*/
+	int handle_wlan_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype);
+
+	/*handle wifi client power-save mode*/
+	int handle_wlan_client_pwrsave(uint8_t *mac_addr);
+
+	/*handle wifi client del mode*/
+	int handle_wlan_client_down_evt(uint8_t *mac_addr);
+
+	/*duplicate ampdu filter rules for private subnet configuration*/
+	int handle_private_subnet(ipa_ip_type iptype);
+
+	/*duplicate ampdu filter rules for initial iface configuration*/
+	int init_fl_rule(ipa_ip_type iptype);
+
+	/*duplicate ampdu filter rules for new_address event*/
+	int handle_addr_evt(ipacm_event_data_addr *data);
+
+	/*duplicate ampdu filter rules for wan_up event*/
+	int handle_wan_up(void);
+
+	/*delete ampdu filter rules for wan_down event*/
+	int handle_wan_down(void);
+
+	/*duplicate ampdu filter rules for software_routing event*/
+	int handle_software_routing_enable(void);
+
+	/*delete ampdu filter rules for disabling software_routing event*/
+	int handle_software_routing_disable(void);
+
+	/*handle wlan iface down event*/
+	int handle_down_evt();
+};
+
+
+#endif /* IPACM_WLAN_H */
diff --git a/ipacm/inc/IPACM_Xml.h b/ipacm/inc/IPACM_Xml.h
new file mode 100644
index 0000000..84f6c6f
--- /dev/null
+++ b/ipacm/inc/IPACM_Xml.h
@@ -0,0 +1,277 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+  @file
+  IPACM_Xml.h
+
+  @brief
+  This file implements the XML specific parsing functionality.
+
+  @Author
+  Skylar Chang/Shihuan Liu
+
+*/
+#ifndef IPACM_XML_H
+#define IPACM_XML_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <linux/msm_ipa.h>
+#include "IPACM_Defs.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <stdint.h>
+#include "libxml/parser.h"
+#include "libxml/tree.h"
+  
+#define IPACM_ASSERT(a)                                            \
+if (!(a)) {                                             \
+    fprintf(stderr, "%s, %d: assertion (a) failed!",    \
+            __FILE__,                                   \
+            __LINE__);                                  \
+    abort();                                         \
+}
+  
+/* Max allowed size of the XML file (2 MB) */
+#define IPACM_XML_MAX_FILESIZE               (2 << 20)
+#define IPACM_MAX_FIREWALL_ENTRIES            50
+#define IPACM_IPV6_ADDR_LEN                   16
+
+/* Defines for clipping space or space & quotes (single, double) */
+#define IPACM_XML_CLIP_SPACE         " "
+#define IPACM_XML_CLIP_SPACE_QUOTES  " '\""
+
+#define MAX_XML_STR_LEN                 120
+  
+/* IPA Config Entries */
+#define system_TAG                           "system"
+#define IPACMCFG_TAG                         "IPACM"
+#define IPACMIFACECFG_TAG                    "IPACMIface"
+#define IFACE_TAG                            "Iface"
+#define NAME_TAG                             "Name"
+#define CATEGORY_TAG                         "Category"
+#define IPACMPRIVATESUBNETCFG_TAG            "IPACMPrivateSubnet"
+#define SUBNET_TAG                           "Subnet"
+#define SUBNETADDRESS_TAG                    "SubnetAddress"
+#define SUBNETMASK_TAG                       "SubnetMask"
+#define WANIF_TAG                            "WAN"
+#define LANIF_TAG                            "LAN"
+#define WLANIF_TAG                           "WLAN"
+#define VIRTUALIF_TAG                        "VIRTUAL"
+#define IPACMALG_TAG                         "IPACMALG"
+#define ALG_TAG                              "ALG"
+#define Protocol_TAG                         "Protocol"
+#define Port_TAG                             "Port"
+#define TCP_PROTOCOL_TAG                     "TCP"
+#define UDP_PROTOCOL_TAG                     "UDP"
+
+/* FIREWALL Config Entries */
+#define Firewall_TAG                         "Firewall"
+#define MobileAPFirewallCfg_TAG              "MobileAPFirewallCfg"
+#define IPFamily_TAG                         "IPFamily"
+#define IPV4SourceAddress_TAG                "IPV4SourceAddress"
+#define IPV4SourceIPAddress_TAG              "IPV4SourceIPAddress"
+#define IPV4SourceSubnetMask_TAG             "IPV4SourceSubnetMask"
+
+#define IPV4DestinationAddress_TAG           "IPV4DestinationAddress"
+#define IPV4DestinationIPAddress_TAG         "IPV4DestinationIPAddress"
+#define IPV4DestinationSubnetMask_TAG        "IPV4DestinationSubnetMask"
+
+#define IPV4TypeOfService_TAG                "IPV4TypeOfService"
+#define TOSValue_TAG                         "TOSValue"
+#define TOSMask_TAG                          "TOSMask"
+
+#define IPV4NextHeaderProtocol_TAG           "IPV4NextHeaderProtocol"
+
+#define IPV6SourceAddress_TAG                "IPV6SourceAddress"
+#define IPV6SourceIPAddress_TAG              "IPV6SourceIPAddress"
+#define IPV6SourcePrefix_TAG                 "IPV6SourcePrefix"
+
+#define IPV6DestinationAddress_TAG           "IPV6DestinationAddress"
+#define IPV6DestinationIPAddress_TAG         "IPV6DestinationIPAddress"
+#define IPV6DestinationPrefix_TAG            "IPV6DestinationPrefix"
+
+#define IPV6TrafficClass_TAG                 "IPV6TrafficClass"
+#define TrfClsValue_TAG                      "TrfClsValue"
+#define TrfClsMask_TAG                       "TrfClsMask"
+
+#define IPV6NextHeaderProtocol_TAG           "IPV6NextHeaderProtocol"
+
+#define TCPSource_TAG                        "TCPSource"
+#define TCPSourcePort_TAG                    "TCPSourcePort"
+#define TCPSourceRange_TAG                   "TCPSourceRange"
+
+#define TCPDestination_TAG                   "TCPDestination"
+#define TCPDestinationPort_TAG               "TCPDestinationPort"
+#define TCPDestinationRange_TAG              "TCPDestinationRange"
+
+#define UDPSource_TAG                        "UDPSource"
+#define UDPSourcePort_TAG                    "UDPSourcePort"
+#define UDPSourceRange_TAG                   "UDPSourceRange"
+
+#define UDPDestination_TAG                   "UDPDestination"
+#define UDPDestinationPort_TAG               "UDPDestinationPort"
+#define UDPDestinationRange_TAG              "UDPDestinationRange"
+
+#define ICMPType_TAG                         "ICMPType"
+#define ICMPCode_TAG                         "ICMPCode"
+
+#define ESP_TAG                              "ESP"
+#define ESPSPI_TAG                           "ESPSPI"
+
+#define TCP_UDPSource_TAG                    "TCP_UDPSource"
+#define TCP_UDPSourcePort_TAG                "TCP_UDPSourcePort"
+#define TCP_UDPSourceRange_TAG               "TCP_UDPSourceRange"
+
+#define TCP_UDPDestination_TAG               "TCP_UDPDestination"
+#define TCP_UDPDestinationPort_TAG           "TCP_UDPDestinationPort"
+#define TCP_UDPDestinationRange_TAG          "TCP_UDPDestinationRange"
+
+#define IPACMNat_TAG                         "IPACMNAT"
+#define NAT_MaxEntries_TAG                   "MaxNatEntries"
+
+
+/*---------------------------------------------------------------------------
+      IP protocol numbers - use in dss_socket() to identify protocols.
+      Also contains the extension header types for IPv6.
+---------------------------------------------------------------------------*/
+typedef enum
+{
+  IPACM_FIREWALL_IPV6_BASE_HDR        = 4,                               /* IPv6 Base Header           */
+  IPACM_FIREWALL_IPPROTO_HOP_BY_HOP_OPT_HDR = 0,                         /* Hop-by-hop Option Header   */
+  IPACM_FIREWALL_IPPROTO_ICMP         = 1,                               /* ICMP protocol */
+  IPACM_FIREWALL_IPPROTO_IGMP         = 2,                               /* IGMP protocol */
+  IPACM_FIREWALL_IPPROTO_IP           = IPACM_FIREWALL_IPV6_BASE_HDR,    /* IPv4          */
+  IPACM_FIREWALL_IPPROTO_TCP          = 6,                               /* TCP Protocol */
+  IPACM_FIREWALL_IPPROTO_UDP          = 17,                              /* UDP Protocol */
+  IPACM_FIREWALL_IPPROTO_IPV6         = 41,                              /* IPv6                       */
+  IPACM_FIREWALL_IPPROTO_ROUTING_HDR  = 43,                              /* Routing Header             */
+  IPACM_FIREWALL_IPPROTO_FRAG_HDR     = 44,                              /* Fragmentation Header       */
+  IPACM_FIREWALL_IPPROTO_GRE          = 47,                              /* GRE Protocol */
+  IPACM_FIREWALL_IPPROTO_ESP          = 50,                              /* ESP Protocol */
+  IPACM_FIREWALL_IPPROTO_AH           = 51,                              /* Authentication Header      */
+  IPACM_FIREWALL_IPPROTO_ICMP6        = 58,                              /* ICMPv6                     */
+  IPACM_FIREWALL_NO_NEXT_HDR          = 59,                              /* No Next Header for IPv6    */
+  IPACM_FIREWALL_IPPROTO_DEST_OPT_HDR = 60,                              /* Destination Options Header */
+  IPACM_FIREWALL_IPPROTO_MOBILITY_HDR = 135,                             /* Mobility Header            */
+  IPACM_FIREWALL_IPPROTO_TCP_UDP      = 253                              /* Unspecified protocol used for IPACM */
+} ipacm_firewall_ip_protocol_enum_type;
+
+/* define as mobileap firewall rule format*/
+typedef enum
+{
+  IP_V4 = 4,
+  IP_V6 = 6
+} firewall_ip_version_enum;
+  
+/*---------------------------------------------------------------------------
+           Extended FireWall Entry Configuration.
+---------------------------------------------------------------------------*/
+typedef struct
+{
+  struct ipa_rule_attrib attrib;
+  firewall_ip_version_enum  ip_vsn;
+} IPACM_extd_firewall_entry_conf_t;
+
+
+/*---------------------------------------------------------------------------
+           Extended FireWall configuration.
+---------------------------------------------------------------------------*/
+typedef union
+{
+  IPACM_extd_firewall_entry_conf_t extd_firewall_entry;
+} IPACM_extd_firewall_conf_t;
+
+
+typedef struct
+{
+  char     firewall_config_file[IPA_MAX_FILE_LEN];
+  uint8_t    num_extd_firewall_entries;
+  IPACM_extd_firewall_entry_conf_t extd_firewall_entries[IPACM_MAX_FIREWALL_ENTRIES];
+} IPACM_firewall_conf_t;
+  
+
+
+typedef struct
+{
+  uint8_t    num_iface_entries;
+  ipa_ifi_dev_name_t iface_entries[IPA_MAX_IFACE_ENTRIES];
+} ipacm_iface_conf_t;
+
+typedef struct
+{
+  uint8_t    num_subnet_entries;
+  ipa_private_subnet private_subnet_entries[IPA_MAX_PRIVATE_SUBNET_ENTRIES];
+} ipacm_private_subnet_conf_t;
+
+typedef struct
+{
+  uint8_t protocol;
+  uint16_t port;
+} ipacm_alg;
+
+typedef struct
+{
+  uint8_t    num_alg_entries;
+  ipacm_alg alg_entries[IPA_MAX_ALG_ENTRIES];
+} ipacm_alg_conf_t;
+
+ 
+typedef struct  _IPACM_conf_t
+{
+  ipacm_iface_conf_t iface_config;
+  ipacm_private_subnet_conf_t private_subnet_config;
+  ipacm_alg_conf_t alg_config;
+	int nat_max_entries;
+} IPACM_conf_t;  
+
+/* This function read IPACM XML configuration*/
+int ipacm_read_cfg_xml
+(
+  char *xml_file,                              /* Filename and path     */
+  IPACM_conf_t *config                         /* Mobile AP config data */
+);
+
+/* This function reads QCMAP Firewall XML and store in IPACM Firewall stucture */
+int IPACM_read_firewall_xml
+(
+  char *xml_file,                                 /* Filename and path     */
+  IPACM_firewall_conf_t *config                   /* Mobile AP config data */
+);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //IPACM_XML
diff --git a/ipacm/src/IPACM_CmdQueue.cpp b/ipacm/src/IPACM_CmdQueue.cpp
new file mode 100644
index 0000000..632ae5d
--- /dev/null
+++ b/ipacm/src/IPACM_CmdQueue.cpp
@@ -0,0 +1,165 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_CmdQueue.cpp
+
+	@brief
+	This file implements the IPAM Comment Queue functionality
+
+	@Author 
+   Sunil
+
+*/
+#include <string.h>
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Log.h"
+
+pthread_mutex_t mutex    = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t  cond_var = PTHREAD_COND_INITIALIZER;
+
+MessageQueue* MessageQueue::inst = NULL;
+MessageQueue* MessageQueue::getInstance()
+{
+	if(inst == NULL)
+	{
+		inst = new MessageQueue();
+		if(inst == NULL)
+		{
+			IPACMERR("unable to create Message Queue instance\n");
+			return NULL;
+		}
+	}
+
+	return inst;
+}
+
+void MessageQueue::enqueue(Message *item)
+{
+	if(!Head)
+	{
+		Tail = item;
+		Head = item;
+	}
+	else
+	{
+		if(Tail == NULL)
+		{
+			IPACMDBG("Tail is null\n");
+			Head->setnext(item);
+		}
+		else
+		{
+			Tail->setnext(item);
+		}
+		Tail = item;
+	}
+}
+
+
+Message* MessageQueue::dequeue(void)
+{
+	if(Head == NULL)
+	{
+		return NULL;
+	}
+	else
+	{
+		Message *tmp = Head;
+		Head = Head->getnext();
+
+		return tmp;
+	}
+}
+
+
+void* MessageQueue::Process(void *param)
+{
+	MessageQueue *MsgQueue = NULL;
+	Message *item = NULL;
+	IPACMDBG("MessageQueue::Process()\n");
+
+	MsgQueue = MessageQueue::getInstance();
+	if(MsgQueue == NULL)
+	{
+		IPACMDBG("unable to start cmd queue process\n");
+		return NULL;
+	}
+
+	while(1)
+	{
+		if(pthread_mutex_lock(&mutex) != 0)
+		{
+			IPACMERR("unable to lock the mutex\n");
+			return NULL;
+		}
+
+		item = MsgQueue->dequeue();
+
+		if(item == NULL)
+		{
+			IPACMDBG("Waiting for Message\n");
+
+			if(pthread_cond_wait(&cond_var, &mutex) != 0)
+			{
+				IPACMERR("unable to lock the mutex\n");
+
+				if(pthread_mutex_unlock(&mutex) != 0)
+				{
+					IPACMERR("unable to unlock the mutex\n");
+					return NULL;
+				}
+
+				return NULL;
+			}
+
+			if(pthread_mutex_unlock(&mutex) != 0)
+			{
+				IPACMERR("unable to unlock the mutex\n");
+				return NULL;
+			}
+
+		}
+		else
+		{
+			if(pthread_mutex_unlock(&mutex) != 0)
+			{
+				IPACMERR("unable to unlock the mutex\n");
+				return NULL;
+			}
+
+			IPACMDBG("Processing item %p\n",item);
+			item->evt.callback_ptr(&item->evt.data);
+			delete item;
+			item = NULL;
+		}
+
+	} /* Go forever until a termination indication is received */
+
+}
diff --git a/ipacm/src/IPACM_Config.cpp b/ipacm/src/IPACM_Config.cpp
new file mode 100644
index 0000000..413d1ba
--- /dev/null
+++ b/ipacm/src/IPACM_Config.cpp
@@ -0,0 +1,190 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+				* Redistributions of source code must retain the above copyright
+						notice, this list of conditions and the following disclaimer.
+				* Redistributions in binary form must reproduce the above
+						copyright notice, this list of conditions and the following
+						disclaimer in the documentation and/or other materials provided
+						with the distribution.
+				* Neither the name of The Linux Foundation nor the names of its
+						contributors may be used to endorse or promote products derived
+						from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+		@file
+		IPACM_Config.cpp
+
+		@brief
+		This file implements the IPACM Configuration from XML file
+
+		@Author
+		Skylar Chang
+
+*/
+#include <IPACM_Config.h>
+#include <IPACM_Log.h>
+#include <IPACM_Iface.h>
+
+IPACM_Config *IPACM_Config::pInstance = NULL;
+
+IPACM_Config::IPACM_Config()
+{
+	iface_table = NULL;
+	alg_table = NULL;
+	memset(&private_subnet_table, 0, sizeof(private_subnet_table));
+
+	ipa_num_ipa_interfaces = 0;
+	ipa_num_private_subnet = 0;
+	ipa_num_alg_ports = 0;
+	ipa_nat_max_entries = 0;
+
+	memset(&rt_tbl_lan_v4, 0, sizeof(rt_tbl_lan_v4));
+	memset(&rt_tbl_wan_v4, 0, sizeof(rt_tbl_wan_v4));
+	memset(&rt_tbl_v6, 0, sizeof(rt_tbl_v6));
+
+	IPACMDBG(" create IPACM_Config constructor\n");
+	return;
+}
+
+int IPACM_Config::Init(void)
+{
+	/* Read IPACM Config file */
+	char	IPACM_config_file[IPA_MAX_FILE_LEN];
+	IPACM_conf_t	*cfg;
+	cfg = (IPACM_conf_t *)malloc(sizeof(IPACM_conf_t));
+	uint32_t subnet_addr;
+	uint32_t subnet_mask;
+	int i, ret = IPACM_SUCCESS;
+
+	strncpy(IPACM_config_file, "/etc/IPACM_cfg.xml", sizeof(IPACM_config_file));
+
+
+	IPACMDBG("\n IPACM XML file is %s \n", IPACM_config_file);
+	if (IPACM_SUCCESS == ipacm_read_cfg_xml(IPACM_config_file, cfg))
+	{
+		IPACMDBG("\n IPACM XML read OK \n");
+	}
+	else
+	{
+		IPACMERR("\n IPACM XML read failed \n");
+		ret = IPACM_FAILURE;
+		goto fail;
+	}
+
+	/* Construct IPACM Iface table */
+	ipa_num_ipa_interfaces = cfg->iface_config.num_iface_entries;
+	iface_table = (ipa_ifi_dev_name_t *)calloc(ipa_num_ipa_interfaces,
+																						 sizeof(ipa_ifi_dev_name_t));
+
+	for (i = 0; i < cfg->iface_config.num_iface_entries; i++)
+	{
+		strncpy(iface_table[i].iface_name, cfg->iface_config.iface_entries[i].iface_name, sizeof(iface_table[i].iface_name));
+		iface_table[i].if_cat = cfg->iface_config.iface_entries[i].if_cat;
+		IPACMDBG("IPACM_Config::iface_table[%d] = %s, cat=%d\n", i, iface_table[i].iface_name, iface_table[i].if_cat);
+	}
+
+	/* Construct IPACM Private_Subnet table */
+	ipa_num_private_subnet = cfg->private_subnet_config.num_subnet_entries;
+
+	for (i = 0; i < cfg->private_subnet_config.num_subnet_entries; i++)
+	{
+		memcpy(&private_subnet_table[i].subnet_addr,
+					 &cfg->private_subnet_config.private_subnet_entries[i].subnet_addr,
+					 sizeof(cfg->private_subnet_config.private_subnet_entries[i].subnet_addr));
+
+		memcpy(&private_subnet_table[i].subnet_mask,
+					 &cfg->private_subnet_config.private_subnet_entries[i].subnet_mask,
+					 sizeof(cfg->private_subnet_config.private_subnet_entries[i].subnet_mask));
+
+		subnet_addr = htonl(private_subnet_table[i].subnet_addr);
+		IPACMDBG("%dst::private_subnet_table= %s \n ", i,
+						 inet_ntoa(*(struct in_addr *)&(subnet_addr)));
+
+		subnet_mask =  htonl(private_subnet_table[i].subnet_mask);
+		IPACMDBG("%dst::private_subnet_table= %s \n ", i,
+						 inet_ntoa(*(struct in_addr *)&(subnet_mask)));
+	}
+
+	/* Construct IPACM ALG table */
+	ipa_num_alg_ports = cfg->alg_config.num_alg_entries;
+	alg_table = (ipacm_alg *)calloc(ipa_num_alg_ports,
+																sizeof(ipacm_alg));
+
+	for (i = 0; i < cfg->alg_config.num_alg_entries; i++)
+	{
+		//strncpy(alg_table[i].protocol, cfg->alg_config.alg_entries[i].protocol, sizeof(alg_table[i].protocol));
+		alg_table[i].protocol = cfg->alg_config.alg_entries[i].protocol;
+		alg_table[i].port = cfg->alg_config.alg_entries[i].port;
+		IPACMDBG("IPACM_Config::ipacm_alg[%d] = %d, port=%d\n", i, alg_table[i].protocol, alg_table[i].port);
+	}
+
+	ipa_nat_max_entries = cfg->nat_max_entries;
+	IPACMDBG("Nat Maximum Entries %d\n", ipa_nat_max_entries);
+
+	/* Construct the routing table ictol name in iface static member*/
+	rt_tbl_lan_v4.ip = IPA_IP_v4;
+	strncpy(rt_tbl_lan_v4.name, V4_LAN_ROUTE_TABLE_NAME, sizeof(rt_tbl_lan_v4.name));
+
+	rt_tbl_v6.ip = IPA_IP_v6;
+	strncpy(rt_tbl_v6.name, V6_COMMON_ROUTE_TABLE_NAME, sizeof(rt_tbl_v6.name));
+
+	rt_tbl_wan_v4.ip = IPA_IP_v4;
+	strncpy(rt_tbl_wan_v4.name, V4_WAN_ROUTE_TABLE_NAME, sizeof(rt_tbl_wan_v4.name));
+
+fail:
+	free(cfg);
+
+	return ret;
+}
+
+IPACM_Config* IPACM_Config::GetInstance()
+{
+	int res = IPACM_SUCCESS;
+
+	if (pInstance == NULL)
+	{
+		pInstance = new IPACM_Config();
+
+		res = pInstance->Init();
+		if (res != IPACM_SUCCESS)
+		{
+			delete pInstance;
+			return NULL;
+		}
+	}
+
+	return pInstance;
+}
+
+int IPACM_Config::GetAlgPorts(int nPorts, ipacm_alg *pAlgPorts)
+{
+	if (nPorts <= 0 || pAlgPorts == NULL)
+	{
+		IPACMERR("Invalid input\n");
+		return -1;
+	}
+
+	for (int cnt = 0; cnt < nPorts; cnt++)
+	{
+		pAlgPorts[cnt].protocol = alg_table[cnt].protocol;
+		pAlgPorts[cnt].port = alg_table[cnt].port;
+	}
+
+	return 0;
+}
diff --git a/ipacm/src/IPACM_ConntrackClient.cpp b/ipacm/src/IPACM_ConntrackClient.cpp
new file mode 100644
index 0000000..7e48822
--- /dev/null
+++ b/ipacm/src/IPACM_ConntrackClient.cpp
@@ -0,0 +1,699 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+				notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+				copyright notice, this list of conditions and the following
+				disclaimer in the documentation and/or other materials provided
+				with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+				contributors may be used to endorse or promote products derived
+				from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <iostream>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+#include "IPACM_ConntrackListener.h"
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_Log.h"
+
+#define LO_NAME "lo"
+
+extern IPACM_EvtDispatcher cm_dis;
+
+IPACM_ConntrackClient *IPACM_ConntrackClient::pInstance = NULL;
+IPACM_ConntrackListener *ct = new IPACM_ConntrackListener();
+
+/* ================================
+		 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("%s %d", __FUNCTION__, __LINE__);
+
+	tcp_hdl = NULL;
+	udp_hdl = NULL;
+	tcp_filter = NULL;
+	udp_filter = NULL;
+}
+
+IPACM_ConntrackClient* IPACM_ConntrackClient::GetInstance()
+{
+	if(pInstance == NULL)
+	{
+		pInstance = new IPACM_ConntrackClient();
+	}
+
+	return pInstance;
+}
+
+int IPACM_ConntrackClient::IPAConntrackEventCB
+(
+	 enum nf_conntrack_msg_type type,
+	 struct nf_conntrack *ct,
+	 void *data
+	 )
+{
+	ipacm_cmd_q_data evt_data;
+	ipacm_ct_evt_data *ct_data;
+
+	IPACMDBG("Event callback called with msgtype: %d\n",type);
+
+	ct_data = (ipacm_ct_evt_data *)malloc(sizeof(ipacm_ct_evt_data));
+	if(ct_data == NULL)
+	{
+		IPACMERR("unable to allocate memory \n");
+		return -1;
+	}
+
+	ct_data->ct = ct;
+	ct_data->type = type;
+
+	evt_data.event = IPA_PROCESS_CT_MESSAGE;
+	evt_data.evt_data = (void *)ct_data;
+
+	if(0 != IPACM_EvtDispatcher::PostEvt(&evt_data))
+	{
+		IPACMERR("Error sending Conntrack message to processing thread!\n");
+		free(ct_data);
+	}
+
+#if 0
+	IPACMDBG("Posted message to Cmd Queue\n");
+#endif
+
+	/* NFCT_CB_STOLEN means that the conntrack object is not released after the
+	 callback That must be manually done later when the object is no longer needed. */
+	return NFCT_CB_STOLEN;
+}
+
+
+/* Function which sets up filters to ignore
+		 connections to and from local interfaces */
+int IPACM_ConntrackClient::IPA_Conntrack_Filters_Ignore_Local_Addrs
+(
+	 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 */
+	filter_ipv4.addr = 0xffffffff;
+	filter_ipv4.mask = 0xffffffff;
+
+	nfct_filter_set_logic(filter,
+												NFCT_FILTER_DST_IPV4,
+												NFCT_FILTER_LOGIC_NEGATIVE);
+
+	nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+	nfct_filter_set_logic(filter,
+												NFCT_FILTER_SRC_IPV4,
+												NFCT_FILTER_LOGIC_NEGATIVE);
+
+	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)");
+		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;
+
+		/* ignore whatever is destined to or originates from local interfaces */
+		if(item->ifr_name != NULL)
+		{
+			if(strncmp(ct->wan_ifname, item->ifr_name, strlen(item->ifr_name)) != 0)
+			{
+				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);
+			}
+		}
+
+		IPACMDBG("ignore connections orignated to 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)");
+				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);
+	return 0;
+} /* IPA_Conntrack_Filters_Ignore_Local_Addrs() */
+
+/* Initialize TCP Filter */
+int IPACM_ConntrackClient::IPA_Conntrack_TCP_Filter_Init(void)
+{
+	int ret = 0;
+	IPACM_ConntrackClient *pClient;
+
+	IPACMDBG("\n");
+
+	pClient = IPACM_ConntrackClient::GetInstance();
+	if(pClient == NULL)
+	{
+		IPACMERR("unable to get conntrack client instance\n");
+		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);
+	if(ret == -1)
+	{
+		IPACMERR("Unable to set filter logic\n");
+		return -1;
+	}
+
+	/* set protocol filters as tcp and udp */
+	nfct_filter_add_attr_u32(pClient->tcp_filter, NFCT_FILTER_L4PROTO, IPPROTO_TCP);
+
+
+	struct nfct_filter_proto tcp_proto_state;
+	tcp_proto_state.proto = IPPROTO_TCP;
+	tcp_proto_state.state = TCP_CONNTRACK_ESTABLISHED;
+
+	ret = nfct_filter_set_logic(pClient->tcp_filter,
+															NFCT_FILTER_L4PROTO_STATE,
+															NFCT_FILTER_LOGIC_POSITIVE);
+	if(ret == -1)
+	{
+		IPACMERR("unable to set filter logic\n");
+		return -1;
+	}
+	nfct_filter_add_attr(pClient->tcp_filter,
+											 NFCT_FILTER_L4PROTO_STATE,
+											 &tcp_proto_state);
+
+
+	tcp_proto_state.proto = IPPROTO_TCP;
+	tcp_proto_state.state = TCP_CONNTRACK_FIN_WAIT;
+	ret = nfct_filter_set_logic(pClient->tcp_filter,
+															NFCT_FILTER_L4PROTO_STATE,
+															NFCT_FILTER_LOGIC_POSITIVE);
+	if(ret == -1)
+	{
+		IPACMERR("unable to set filter logic\n");
+		return -1;
+	}
+
+	nfct_filter_add_attr(pClient->tcp_filter,
+											 NFCT_FILTER_L4PROTO_STATE,
+											 &tcp_proto_state);
+	return 0;
+}
+
+
+/* Initialize UDP Filter */
+int IPACM_ConntrackClient::IPA_Conntrack_UDP_Filter_Init(void)
+{
+	int ret = 0;
+	IPACM_ConntrackClient *pClient = IPACM_ConntrackClient::GetInstance();
+
+	ret = IPA_Conntrack_Filters_Ignore_Local_Addrs(pClient->udp_filter);
+	if(ret == -1)
+	{
+		IPACMERR("Unable to set local addr filters\n");
+		return -1;
+	}
+
+	ret = nfct_filter_set_logic(pClient->udp_filter,
+															NFCT_FILTER_L4PROTO,
+															NFCT_FILTER_LOGIC_POSITIVE);
+	if(ret == -1)
+	{
+		IPACMERR("unable to set filter logic\n");
+	}
+	/* set protocol filters as tcp and udp */
+	nfct_filter_add_attr_u32(pClient->udp_filter, NFCT_FILTER_L4PROTO, IPPROTO_UDP);
+
+	return 0;
+}
+
+void* IPACM_ConntrackClient::UDPConnTimeoutUpdate(void *ptr)
+{
+
+#ifdef IPACM_DEBUG
+	IPACMDBG("\n");
+#endif
+
+	while(1)
+	{
+		NatApp::GetInstance()->UpdateUDPTimeStamp();
+		sleep(UDP_TIMEOUT_UPDATE);
+	} /* end of while(1) loop */
+
+#ifdef IPACM_DEBUG
+	IPACMDBG("Returning from %s() %d\n", __FUNCTION__, __LINE__);
+#endif
+
+	return NULL;
+}
+
+/* Thread to initialize TCP Conntrack Filters*/
+void* IPACM_ConntrackClient::TCPRegisterWithConnTrack(void *)
+{
+	int ret;
+	IPACM_ConntrackClient *pClient;
+
+	IPACMDBG("\n");
+
+	pClient = IPACM_ConntrackClient::GetInstance();
+	if(pClient == NULL)
+	{
+		IPACMERR("unable to get conntrack client instance\n");
+		return -1;
+	}
+
+	pClient->tcp_hdl = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_UPDATE);
+	if(pClient->tcp_hdl == NULL)
+	{
+		PERROR("nfct_open\n");
+		return NULL;
+	}
+
+	/* Allocate new filter */
+	pClient->tcp_filter = nfct_filter_create();
+	if(pClient->tcp_filter == NULL)
+	{
+		IPACMERR("unable to create TCP filter\n");
+		return NULL;
+	}
+
+	/* Initialize the filter */
+	ret = IPA_Conntrack_TCP_Filter_Init();
+	if(ret == -1)
+	{
+		IPACMERR("Unable to initliaze TCP Filter\n");
+		return NULL;
+	}
+
+	/* Attach the filter to net filter handler */
+	ret = nfct_filter_attach(nfct_fd(pClient->tcp_hdl),
+													 pClient->tcp_filter);
+	if(ret == -1)
+	{
+		IPACMDBG("unable to attach TCP filter\n");
+		return NULL;
+	}
+
+	/* Register callback with netfilter handler */
+	IPACMDBG("tcp handle:%p, fd:%d\n", pClient->tcp_hdl, nfct_fd(pClient->tcp_hdl));
+	nfct_callback_register(pClient->tcp_hdl, NFCT_T_UPDATE, IPAConntrackEventCB, NULL);
+
+	/* Block to catch events from net filter connection track */
+	/* nfct_catch() receives conntrack events from kernel-space, by default it 
+			 blocks waiting for events. */
+	IPACMDBG("Waiting for events\n");
+
+	ret = nfct_catch(pClient->tcp_hdl);
+	if(ret == -1)
+	{
+		IPACMERR("(%d)(%s)\n", ret, strerror(errno));
+		return NULL;
+	}
+
+	IPACMDBG("Exit from tcp thread\n");
+
+	/* destroy the filter.. this will not detach the filter */
+	nfct_filter_destroy(pClient->tcp_filter);
+	pClient->tcp_filter = NULL;
+
+	/* de-register the callback */
+	nfct_callback_unregister(pClient->tcp_hdl);
+	/* close the handle */
+	nfct_close(pClient->tcp_hdl);
+  pClient->tcp_hdl = NULL;
+
+	pthread_exit(NULL);
+	return NULL;
+}
+
+/* Thread to initialize UDP Conntrack Filters*/
+void* IPACM_ConntrackClient::UDPRegisterWithConnTrack(void *)
+{
+	int ret;
+	IPACM_ConntrackClient *pClient = NULL;
+	
+	IPACMDBG("\n");
+
+	pClient = IPACM_ConntrackClient::GetInstance();
+	if(pClient == NULL)
+	{
+		IPACMERR("unable to retrieve instance of conntrack client\n");
+		return NULL;
+	}
+
+	pClient->udp_hdl = nfct_open(CONNTRACK,
+															 NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
+	if(pClient->udp_hdl == NULL)
+	{
+		PERROR("nfct_open\n");
+		return NULL;
+	}
+
+	/* Add filter */
+	//struct nfct_filter *udp_filter = NULL;
+
+	/* Allocate new filter */
+	pClient->udp_filter = nfct_filter_create();
+	if(pClient->udp_filter == NULL)
+	{
+		IPACMERR("unable to create UDP filter\n");
+		return NULL;
+	}
+
+	/* Initialize Filter */
+	ret = IPA_Conntrack_UDP_Filter_Init();
+	if(-1 == ret)
+	{
+		IPACMDBG("Unable to initalize udp filters\n");
+		return NULL;
+	}
+
+	/* Attach the filter to net filter handler */
+	ret = nfct_filter_attach(nfct_fd(pClient->udp_hdl), pClient->udp_filter);
+	if(ret == -1)
+	{
+		IPACMDBG("unable to attach the filter\n");
+		return NULL;
+	}
+
+	/* Register callback with netfilter handler */
+	IPACMDBG("udp handle:%p, fd:%d\n", pClient->udp_hdl, nfct_fd(pClient->udp_hdl));
+	nfct_callback_register(pClient->udp_hdl,
+												 (nf_conntrack_msg_type)(NFCT_T_NEW | NFCT_T_DESTROY),
+												 IPAConntrackEventCB,
+												 NULL);
+
+	/* Block to catch events from net filter connection track */
+	ret = nfct_catch(pClient->udp_hdl);
+	if(ret == -1)
+	{
+		IPACMDBG("(%d)(%s)\n", ret, strerror(errno));
+		return NULL;
+	}
+
+
+	IPACMDBG("Exit from udp thread\n");
+
+	/* destroy the filter.. this will not detach the filter */
+	nfct_filter_destroy(pClient->udp_filter);
+	pClient->udp_filter = NULL;
+
+	/* de-register the callback */
+	nfct_callback_unregister(pClient->udp_hdl);
+	/* close the handle */
+	nfct_close(pClient->udp_hdl);
+  pClient->udp_hdl = NULL;
+	
+	pthread_exit(NULL);
+	return NULL;
+}
+
+void IPACM_ConntrackClient::UpdateUDPFilters(void *param)
+{
+	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)
+	{
+		IPACMERR("unable to retrieve conntrack client instance\n");
+		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)
+	{
+		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);
+	}
+
+  /* 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)
+	{
+		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);
+	}
+
+	/* Attach the filter to udp handle */
+	if(pClient->udp_hdl != NULL)
+	{
+		IPACMDBG("attaching the filter to udp handle\n");
+		ret = nfct_filter_attach(nfct_fd(pClient->udp_hdl), pClient->udp_filter);
+		if(ret == -1)
+		{
+			PERROR("unable to attach the filter to udp handle\n");
+			IPACMERR("udp handle:%p, fd:%d Error: %d\n",pClient->udp_hdl, nfct_fd(pClient->udp_hdl), ret);
+			return;
+		}
+	}
+
+	return;
+}
+
+void IPACM_ConntrackClient::UpdateTCPFilters(void *param)
+{
+	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)
+	{
+		IPACMERR("unable to retrieve conntrack client instance\n");
+		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->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);
+
+		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);
+	}
+
+	/* Attach the filter to tcp handle */
+	if(pClient->tcp_hdl != NULL)
+	{
+		IPACMDBG("attaching the filter to tcp handle\n");
+		ret = nfct_filter_attach(nfct_fd(pClient->tcp_hdl), pClient->tcp_filter);
+		if(ret == -1)
+		{
+			PERROR("unable to attach the filter to tcp handle\n");
+			IPACMERR("tcp handle:%p, fd:%d Error: %d\n",pClient->tcp_hdl, nfct_fd(pClient->tcp_hdl), ret);
+			return;
+		}
+	}
+
+  return;
+}
diff --git a/ipacm/src/IPACM_ConntrackListener.cpp b/ipacm/src/IPACM_ConntrackListener.cpp
new file mode 100644
index 0000000..66a6355
--- /dev/null
+++ b/ipacm/src/IPACM_ConntrackListener.cpp
@@ -0,0 +1,429 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+				* Redistributions of source code must retain the above copyright
+								notice, this list of conditions and the following disclaimer.
+				* Redistributions in binary form must reproduce the above
+								copyright notice, this list of conditions and the following
+								disclaimer in the documentation and/or other materials provided
+								with the distribution.
+				* Neither the name of The Linux Foundation nor the names of its
+								contributors may be used to endorse or promote products derived
+								from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "IPACM_ConntrackListener.h"
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_EvtDispatcher.h"
+
+IPACM_ConntrackListener::IPACM_ConntrackListener()
+{
+	 IPACMDBG("%d %s()\n", __LINE__, __FUNCTION__);
+
+	 isCTReg = false;
+	 isWanUp = false;
+
+	 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_HANDLE_WLAN_UP, this);
+}
+
+void IPACM_ConntrackListener::event_callback(ipa_cm_event_id evt,
+																						 void *data)
+{
+	 ipacm_ct_evt_data *evt_data = NULL;
+	 uint32_t *pub_addr = NULL;
+
+	 if(data == NULL)
+	 {
+			IPACMERR("Invalid Data\n");
+			return;
+	 }
+
+	 switch(evt)
+	 {
+	 case IPA_PROCESS_CT_MESSAGE:
+			IPACMDBG("Received IPA_PROCESS_CT_MESSAGE event\n");
+			evt_data = (ipacm_ct_evt_data *)data;
+			ProcessCTMessage(evt_data);
+			break;
+
+	 case IPA_HANDLE_WAN_UP:
+			IPACMDBG("Received IPA_HANDLE_WAN_UP event\n");
+			TriggerWANUp(data);
+			break;
+
+	 case IPA_HANDLE_WAN_DOWN:
+			IPACMDBG("Received IPA_HANDLE_WAN_DOWN event\n");
+			pub_addr = (uint32_t *)data;
+			TriggerWANDown(*pub_addr);
+			break;
+
+	/* if wlan or lan comes up after wan interface, modify
+		 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 == true)
+			{
+				 IPACM_ConntrackClient::UpdateUDPFilters(data);
+				 IPACM_ConntrackClient::UpdateTCPFilters(data);
+			}
+			break; 
+
+	 default:
+			IPACMDBG("Ignore cmd %d\n", evt);
+			break;
+	 }
+}
+
+void IPACM_ConntrackListener::TriggerWANUp(void *in_param)
+{
+	 ipacm_event_iface_up *wanup_data = (ipacm_event_iface_up *)in_param;
+
+	 IPACMDBG("Recevied below informatoin during wanup:\n");
+	 IPACMDBG("if_name:%s, ipv4_address:0x%x\n",
+						wanup_data->ifname, wanup_data->ipv4_addr);
+
+	 isWanUp = true;
+	 wan_ipaddr = wanup_data->ipv4_addr;
+	 IPACM_ConntrackClient::iptodot("public ip address", wanup_data->ipv4_addr);
+
+	 memcpy(wan_ifname, wanup_data->ifname, sizeof(wan_ifname));
+	 NatApp::GetInstance()->AddTable(wanup_data->ipv4_addr);
+
+	 IPACMDBG("creating nat threads\n");
+	 CreateNatThreads();
+}
+
+int IPACM_ConntrackListener::CreateNatThreads(void)
+{
+	 int ret;
+	 pthread_t tcp_thread = 0, udp_thread = 0, udpcto_thread = 0;
+
+	 if(isCTReg == false)
+	 {
+
+			if(!tcp_thread)
+			{
+				 ret = pthread_create(&tcp_thread, NULL, IPACM_ConntrackClient::TCPRegisterWithConnTrack, NULL);
+				 if(0 != ret)
+				 {
+						IPACMERR("unable to create TCP conntrack event listner thread\n");
+						return -1;
+				 }
+
+				 IPACMDBG("created TCP conntrack event listner thread\n");
+			}
+
+			if(!udp_thread)
+			{
+				 ret = pthread_create(&udp_thread, NULL, IPACM_ConntrackClient::UDPRegisterWithConnTrack, NULL);
+				 if(0 != ret)
+				 {
+						IPACMERR("unable to create UDP conntrack event listner thread\n");
+						goto error;
+				 }
+
+				 IPACMDBG("created UDP conntrack event listner thread\n");
+			}
+
+			if(!udpcto_thread)
+			{
+				 ret = pthread_create(&udpcto_thread, NULL, IPACM_ConntrackClient::UDPConnTimeoutUpdate, NULL);
+				 if(0 != ret)
+				 {
+						IPACMERR("unable to create udp conn timeout thread\n");
+						goto error;
+				 }
+
+				 IPACMDBG("created upd conn timeout thread\n");
+			}
+
+			isCTReg = true;
+	 }
+
+	 //pthread_join(tcp_thread, NULL);
+	 //pthread_join(udp_thread, NULL);
+	 //pthread_join(udpcto_thread, NULL);
+
+	 return 0;
+
+error:
+	 if(tcp_thread)
+	 {
+			pthread_cancel(tcp_thread);
+	 }
+
+	 if(udp_thread)
+	 {
+			pthread_cancel(tcp_thread);
+	 }
+
+	 if(udpcto_thread)
+	 {
+			pthread_cancel(udpcto_thread);
+	 }
+
+	 return -1;
+}
+
+void IPACM_ConntrackListener::TriggerWANDown(uint32_t wan_addr)
+{
+	 IPACMDBG("Deleting ipv4 nat table with ");
+	 IPACM_ConntrackClient::iptodot("public ip address", wan_addr);
+	 isWanUp = false;
+
+	 NatApp::GetInstance()->DeleteTable(wan_addr);
+}
+
+
+void ParseCTMessage(struct nf_conntrack *ct)
+{
+	 uint32_t status;
+	 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));
+	 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));
+	 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));
+	 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));
+
+	 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));
+
+	 status = nfct_get_attr_u32(ct, ATTR_STATUS);
+	 IPACMDBG("ATTR_STATUS: 0x:%x\n", status);
+
+	 if(IPS_SRC_NAT & status)
+	 {
+			IPACMDBG("IPS_SRC_NAT set\n");
+	 }
+
+	 if(IPS_DST_NAT & status)
+	 {
+			IPACMDBG("IPS_SRC_NAT set\n");
+	 }
+
+	 if(IPS_SRC_NAT_DONE & status)
+	 {
+			IPACMDBG("IPS_SRC_NAT_DONE set\n");
+	 }
+
+	 if(IPS_DST_NAT_DONE & status)
+	 {
+			IPACMDBG(" IPS_DST_NAT_DONE set\n");
+	 }
+
+	 IPACMDBG("\n");
+	 return;
+}
+
+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];
+
+	 /* Process message and generate ioctl call to kernel thread */
+	 nfct_snprintf(buf, sizeof(buf), evt_data->ct,
+								 evt_data->type, NFCT_O_PLAIN, NFCT_OF_TIME);
+	 IPACMDBG("%s\n", buf);
+	 IPACMDBG("\n");
+
+	 ParseCTMessage(evt_data->ct);
+#endif
+
+	 l4proto = nfct_get_attr_u8(evt_data->ct, ATTR_ORIG_L4PROTO);
+	 if(IPPROTO_UDP != l4proto && IPPROTO_TCP != l4proto)
+	 {
+			IPACMDBG("Received unexpected protocl %d conntrack message\n", l4proto);
+	 }
+	 else
+	 {
+			ProcessTCPorUDPMsg(evt_data->ct, evt_data->type, l4proto);
+	 }
+
+	 /* Cleanup item that was allocated during the original CT callback */
+	 nfct_destroy(evt_data->ct);
+	 return;
+}
+
+
+/* conntrack send in host order and ipa expects in host order */
+void IPACM_ConntrackListener::ProcessTCPorUDPMsg(
+	 struct nf_conntrack *ct,
+	 enum nf_conntrack_msg_type type,
+	 u_int8_t l4proto)
+{
+	 nat_table_entry rule;
+	 u_int8_t tcp_state;
+	 uint32_t status = 0;
+
+	 status = nfct_get_attr_u32(ct, ATTR_STATUS);
+
+	 if(IPS_DST_NAT & status)
+	 {
+			IPACMDBG("Destination nat flag set\n");
+			rule.dst_nat = true;
+
+			IPACMDBG("Parse reply tuple\n");
+			rule.target_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC);
+			rule.target_ip = ntohl(rule.target_ip);
+
+			/* Retriev target/dst port */
+			rule.target_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
+			rule.target_port = ntohs(rule.target_port);
+			if(0 == rule.target_port)
+			{
+				 IPACMDBG("unable to retrieve target port\n");
+			}
+
+			rule.public_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
+			rule.public_port = ntohs(rule.public_port);
+
+			/* Retriev src/private ip address */
+			rule.private_ip = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC);
+			rule.private_ip = ntohl(rule.private_ip);
+			if(0 == rule.private_ip)
+			{
+				 IPACMDBG("unable to retrieve private ip address\n");
+			}
+
+			/* Retriev src/private port */
+			rule.private_port = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC);
+			rule.private_port = ntohs(rule.private_port);
+			if(0 == rule.private_port)
+			{
+				 IPACMDBG("unable to retrieve private port\n");
+			}
+	 }
+	 else
+	 {
+			IPACMDBG("destination nat flag reset\n");
+			rule.dst_nat = false;
+
+			/* Retriev target/dst ip address */
+			IPACMDBG("Parse source tuple\n");
+			rule.target_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_DST);
+			rule.target_ip = ntohl(rule.target_ip);
+			if(0 == rule.target_ip)
+			{
+				 IPACMDBG("unable to retrieve target ip address\n");
+			}
+			/* Retriev target/dst port */
+			rule.target_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
+			rule.target_port = ntohs(rule.target_port);
+			if(0 == rule.target_port)
+			{
+				 IPACMDBG("unable to retrieve target port\n");
+			}
+
+			/* Retriev public port */
+			rule.public_port = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST);
+			rule.public_port = ntohs(rule.public_port);
+			if(0 == rule.public_port)
+			{
+				 IPACMDBG("unable to retrieve public port\n");
+			}
+
+			/* Retriev src/private ip address */
+			rule.private_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC);
+			rule.private_ip = ntohl(rule.private_ip);
+			if(0 == rule.private_ip)
+			{
+				 IPACMDBG("unable to retrieve private ip address\n");
+			}
+
+			/* Retriev src/private port */
+			rule.private_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
+			rule.private_port = ntohs(rule.private_port);
+			if(0 == rule.private_port)
+			{
+				 IPACMDBG("unable to retrieve private port\n");
+			}
+	 }
+	 /* Retrieve Protocol */
+	 rule.protocol = nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO);
+
+
+	 IPACMDBG("Nat Entry with below information will be added\n");
+	 IPACM_ConntrackClient::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);
+	 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);
+
+	 if(IPPROTO_TCP == rule.protocol)
+	 {
+			tcp_state = nfct_get_attr_u8(ct, ATTR_TCP_STATE);
+			if(TCP_CONNTRACK_ESTABLISHED == tcp_state)
+			{
+				 IPACMDBG("TCP state TCP_CONNTRACK_ESTABLISHED(%d)\n", tcp_state);
+				 NatApp::GetInstance()->AddEntry(&rule);
+			}
+			else if(TCP_CONNTRACK_FIN_WAIT == tcp_state)
+			{
+				 IPACMDBG("TCP state TCP_CONNTRACK_FIN_WAIT(%d)\n", tcp_state);
+				 NatApp::GetInstance()->DeleteEntry(&rule);
+			}
+			else
+			{
+				 IPACMDBG("Ignore tcp state: %d and type: %d\n", tcp_state, type);
+			}
+
+	 }
+	 else if(IPPROTO_UDP == rule.protocol)
+	 {
+			if(NFCT_T_NEW == type)
+			{
+				 IPACMDBG("New UDP connection at time %ld\n", time(NULL));
+				 NatApp::GetInstance()->AddEntry(&rule);
+			}
+			else if(NFCT_T_DESTROY == type)
+			{
+				 IPACMDBG("UDP connection close at time %ld\n", time(NULL));
+				 NatApp::GetInstance()->DeleteEntry(&rule);
+			}
+	 }
+	 else
+	 {
+			IPACMDBG("Ignore protocol: %d and type: %d\n", rule.protocol, type);
+	 }
+
+	 return;
+}
+
+
+
+
+
+
diff --git a/ipacm/src/IPACM_Conntrack_NATApp.cpp b/ipacm/src/IPACM_Conntrack_NATApp.cpp
new file mode 100644
index 0000000..63b158c
--- /dev/null
+++ b/ipacm/src/IPACM_Conntrack_NATApp.cpp
@@ -0,0 +1,504 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+				* Redistributions of source code must retain the above copyright
+						notice, this list of conditions and the following disclaimer.
+				* Redistributions in binary form must reproduce the above
+						copyright notice, this list of conditions and the following
+						disclaimer in the documentation and/or other materials provided
+						with the distribution.
+				* Neither the name of The Linux Foundation nor the names of its
+						contributors may be used to endorse or promote products derived
+						from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "IPACM_Conntrack_NATApp.h"
+#include "IPACM_ConntrackClient.h"
+
+#define UDP_TIMEOUT_VALUE 30
+
+/* NatApp class Implementation */
+NatApp *NatApp::pInstance = NULL;
+NatApp::NatApp()
+{
+	max_entries = 0;
+	cache = NULL;
+
+	nat_table_hdl = 0;
+	pub_ip_addr = 0;
+
+	curCnt = 0;
+
+	pALGPorts = NULL;
+	nALGPort = 0;
+
+	ct = NULL;
+	ct_hdl = NULL;
+}
+
+int NatApp::Init(void)
+{
+	IPACM_Config *pConfig;
+
+	pConfig = IPACM_Config::GetInstance();
+	if(pConfig == NULL)
+	{
+		IPACMERR("Unable to get Config instance\n");
+		return -1;
+	}
+
+	max_entries = pConfig->GetNatMaxEntries();
+
+	cache = (nat_table_entry *)malloc(sizeof(nat_table_entry) * max_entries);
+	if(cache == NULL)
+	{
+		IPACMERR("Unable to allocate memory for cache\n");
+		goto fail;
+	}
+	memset(cache, 0, sizeof(nat_table_entry) * max_entries);
+
+	nALGPort = pConfig->GetAlgPortCnt();
+	pALGPorts = (ipacm_alg *)malloc(sizeof(ipacm_alg) * nALGPort);
+	if(pALGPorts == NULL)
+	{
+		IPACMERR("Unable to allocate memory for alg prots\n");
+		goto fail;
+	}
+	memset(pALGPorts, 0, sizeof(ipacm_alg) * nALGPort);
+
+	if(pConfig->GetAlgPorts(nALGPort, pALGPorts) != 0)
+	{
+		IPACMERR("Unable to retrieve ALG prots\n");
+		goto fail;
+	}
+
+	IPACMDBG("Printing %d alg ports information\n", nALGPort);
+	for(int cnt=0; cnt<nALGPort; cnt++)
+	{
+		IPACMDBG("%d: Proto[%d], port[%d]\n", cnt, pALGPorts[cnt].protocol, pALGPorts[cnt].port);
+	}
+
+	return 0;
+
+fail:
+	free(cache);
+	free(pALGPorts);
+	return -1;
+}
+
+NatApp* NatApp::GetInstance()
+{
+	if(pInstance == NULL)
+	{
+		pInstance = new NatApp();
+
+		if(pInstance->Init())
+		{
+			delete pInstance;
+			return NULL;
+		}
+	}
+
+	return pInstance;
+}
+
+/* NAT APP related object function definitions */
+
+int NatApp::AddTable(uint32_t pub_ip)
+{
+	int ret;
+	IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+	ret = ipa_nat_add_ipv4_tbl(pub_ip, max_entries, &nat_table_hdl);
+	if(ret)
+	{
+		IPACMERR("unable to create nat table Error:%d\n", ret);
+		return ret;
+	}
+
+	pub_ip_addr = pub_ip;
+	return 0;
+}
+
+void NatApp::Reset()
+{
+	memset(cache, 0, sizeof(nat_table_entry) * max_entries);
+
+	nat_table_hdl = 0;
+	pub_ip_addr = 0;
+	curCnt = 0;
+}
+
+int NatApp::DeleteTable(uint32_t pub_ip)
+{
+	int ret;
+	IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+	CHK_TBL_HDL();
+
+	if(pub_ip_addr != pub_ip)
+	{
+		IPACMDBG("Public ip address is not matching\n");
+		IPACMERR("unable to delete the nat table\n");
+		return -1;
+	}
+
+	ret = ipa_nat_del_ipv4_tbl(nat_table_hdl);
+	if(ret)
+	{
+		IPACMERR("unable to delete nat table Error: %d\n", ret);;
+		return ret;
+	}
+
+	Reset();
+	return 0;
+}
+
+/* Check for duplicate entries */
+bool NatApp::ChkForDup(const nat_table_entry *rule)
+{
+	int cnt = 0;
+	IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+	for(; cnt < curCnt; cnt++)
+	{
+		if(cache[cnt].private_ip == rule->private_ip &&
+			 cache[cnt].target_ip == rule->target_ip &&
+			 cache[cnt].private_port ==  rule->private_port  &&
+			 cache[cnt].target_port == rule->target_port &&
+			 cache[cnt].protocol == rule->protocol)
+		{
+			IPACMDBG("Duplicate Rule\n");
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/* Delete the entry from Nat table on connection close */
+int NatApp::DeleteEntry(const nat_table_entry *rule)
+{
+	int cnt = 0;
+	IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+	CHK_TBL_HDL();
+
+#ifdef IPACM_DEBUG
+	IPACM_ConntrackClient::iptodot("Private IP", rule->private_ip);
+	IPACM_ConntrackClient::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);
+#endif
+
+	for(; cnt < max_entries; cnt++)
+	{
+		if(cache[cnt].private_ip == rule->private_ip &&
+			 cache[cnt].target_ip == rule->target_ip &&
+			 cache[cnt].private_port ==  rule->private_port  &&
+			 cache[cnt].target_port == rule->target_port &&
+			 cache[cnt].protocol == rule->protocol)
+		{
+
+			if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
+			{
+				IPACMERR("%s() %d\n", __FUNCTION__, __LINE__);
+				return -1;
+			}
+
+			memset(&cache[cnt], 0, sizeof(cache[cnt]));
+			curCnt--;
+		}
+	}
+
+	return 0;
+}
+
+/* Add new entry to the nat table on new connection */
+int NatApp::AddEntry(const nat_table_entry *rule)
+{
+
+	int cnt = 0;
+	ipa_nat_ipv4_rule nat_rule;
+	IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+	CHK_TBL_HDL();
+
+	if(isAlgPort(rule->protocol, rule->private_port) ||
+		 isAlgPort(rule->protocol, rule->target_port))
+	{
+		IPACMERR("connection using ALG Port. Dont insert into nat table\n");
+		return -1;
+	}
+
+	if(isPwrSaveIf(rule->private_ip) ||
+		 isPwrSaveIf(rule->target_ip))
+	{
+		IPACMERR("Device is Power Save mode: Dont insert into nat table\n");
+		return -1;
+	}
+
+	if(!ChkForDup(rule))
+	{
+		for(; cnt < max_entries; cnt++)
+		{
+			if(cache[cnt].private_ip == 0 &&
+				 cache[cnt].target_ip == 0 &&
+				 cache[cnt].private_port == 0  &&
+				 cache[cnt].target_port == 0 &&
+				 cache[cnt].protocol == 0)
+			{
+				break;
+			}
+		}
+
+		if(max_entries == cnt)
+		{
+			IPACMERR("Error: Unable to add, reached maximum rules\n");
+			return -1;
+		}
+		else
+		{
+			nat_rule.private_ip = rule->private_ip;
+			nat_rule.target_ip = rule->target_ip;
+			nat_rule.target_port = rule->target_port;
+			nat_rule.private_port = rule->private_port;
+			nat_rule.public_port = rule->public_port;
+			nat_rule.protocol = rule->protocol;
+
+			if(ipa_nat_add_ipv4_rule(nat_table_hdl, &nat_rule, &cache[cnt].rule_hdl) < 0)
+			{
+				IPACMERR("unable to add the rule\n");
+				return -1;
+			}
+
+			cache[cnt].private_ip = rule->private_ip;
+			cache[cnt].target_ip = rule->target_ip;
+			cache[cnt].target_port = rule->target_port;
+			cache[cnt].private_port = rule->private_port;
+			cache[cnt].protocol = rule->protocol;
+			cache[cnt].timestamp = 0;
+			cache[cnt].public_port = rule->public_port;
+			cache[cnt].dst_nat = rule->dst_nat;
+			curCnt++;
+		}
+
+	}
+	else
+	{
+		IPACMERR("Duplicate rule. Ignore it\n");
+		return -1;
+	}
+
+
+#ifdef IPACM_DEBUG
+	IPACMDBG("Added below rule successfully\n");
+	IPACM_ConntrackClient::iptodot("Private IP", rule->private_ip);
+	IPACM_ConntrackClient::iptodot("Target IP", rule->target_ip);
+	IPACMDBG("Private Port:%d \t Target Port: %d\t", rule->private_port, rule->target_port);
+	IPACMDBG("Public Port:%d\n", rule->public_port);
+	IPACMDBG("protocol: %d\n", rule->protocol);
+#endif
+
+	return 0;
+}
+
+void NatApp::UpdateCTUdpTs(nat_table_entry *rule, uint32_t new_ts)
+{
+	int ret;
+
+#ifdef IPACM_DEBUG
+	IPACM_ConntrackClient::iptodot("Private IP:", rule->private_ip);
+	IPACM_ConntrackClient::iptodot("Target IP:",  rule->target_ip);
+	IPACMDBG("Private Port: %d, Target Port: %d\n", rule->private_port, rule->target_port);
+#endif
+
+	if(!ct_hdl)
+	{
+		ct_hdl = nfct_open(CONNTRACK, 0);
+		if(!ct_hdl)
+		{
+			PERROR("nfct_open");
+			return;
+		}
+	}
+
+	if(!ct)
+	{
+		ct = nfct_new();
+		if(!ct)
+		{
+			PERROR("nfct_new");
+			return;
+		}
+	}
+	
+	nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
+	nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_UDP);
+	nfct_set_attr_u32(ct, ATTR_TIMEOUT, UDP_TIMEOUT_VALUE);
+
+	if(rule->dst_nat == false)
+	{
+		nfct_set_attr_u32(ct, ATTR_IPV4_SRC, htonl(rule->private_ip));
+		nfct_set_attr_u16(ct, ATTR_PORT_SRC, htons(rule->private_port));
+
+		nfct_set_attr_u32(ct, ATTR_IPV4_DST, htonl(rule->target_ip));
+		nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(rule->target_port));
+
+		IPACMDBG("dst nat is not set\n");
+	}
+	else
+	{
+		nfct_set_attr_u32(ct, ATTR_IPV4_SRC, htonl(rule->target_ip));
+		nfct_set_attr_u16(ct, ATTR_PORT_SRC, htons(rule->target_port));
+
+		nfct_set_attr_u32(ct, ATTR_IPV4_DST, htonl(pub_ip_addr));
+		nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(rule->public_port));
+
+		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));
+	IPACMDBG("Source Port: %d, Destination Port: %d\n",
+					 nfct_get_attr_u16(ct, ATTR_PORT_SRC), nfct_get_attr_u16(ct, ATTR_PORT_DST)); 
+	
+	IPACMDBG("updating udp connection with time: %d\n", UDP_TIMEOUT_VALUE);
+	ret = nfct_query(ct_hdl, NFCT_Q_UPDATE, ct);
+	if(ret == -1)
+	{
+		PERROR("unable to update time stamp");
+	}
+	else
+	{
+		rule->timestamp = new_ts;
+		IPACMDBG("Updated time stamp successfully\n");
+	}
+
+	return;
+}
+
+void NatApp::UpdateUDPTimeStamp()
+{
+	int cnt;
+	uint32_t ts;
+
+	for(cnt = 0; cnt < curCnt; cnt++)
+	{
+		ts = 0;
+		if(IPPROTO_UDP == cache[cnt].protocol)
+		{
+			IPACMDBG("\n");
+			if(ipa_nat_query_timestamp(nat_table_hdl, cache[cnt].rule_hdl, &ts) < 0)
+			{
+				IPACMERR("unable to retrieve timeout for rule hanle: %d\n", cache[cnt].rule_hdl);
+				continue;
+			}
+
+			if(ts == cache[cnt].timestamp)
+			{
+				continue;
+			}
+			
+			UpdateCTUdpTs(&cache[cnt], ts);
+		} /* end of outer if */
+
+	} /* end of for loop */
+
+}
+
+bool NatApp::isAlgPort(uint8_t proto, uint16_t port)
+{
+	int cnt;
+	for(cnt = 0; cnt < nALGPort; cnt++)
+	{
+		if(proto == pALGPorts[cnt].protocol &&
+			 port == pALGPorts[cnt].port)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool NatApp::isPwrSaveIf(uint32_t ip_addr)
+{
+	int cnt;
+
+	for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+	{
+		if(0 != PwrSaveIfs[cnt] &&
+			 ip_addr == PwrSaveIfs[cnt])
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+int NatApp::UpdatePwrSaveIf(uint32_t client_lan_ip)
+{
+	int cnt;
+
+	CHK_TBL_HDL();
+
+	for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+	{
+		if(PwrSaveIfs[cnt] == 0)
+		{
+			PwrSaveIfs[cnt] = client_lan_ip;
+		}
+	}
+
+	for(cnt = 0; cnt < curCnt; cnt++)
+	{
+		if(cache[cnt].private_ip == client_lan_ip)
+		{
+			if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
+			{
+				IPACMERR("unable to delete the rule\n");
+				continue;
+			}
+
+			memset(&cache[cnt], 0, sizeof(cache[cnt]));
+			curCnt--;
+		}
+	}
+
+	return 0;
+}
+
+int NatApp::ResetPwrSaveIf(uint32_t client_lan_ip)
+{
+	int cnt;
+
+	for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+	{
+		if(PwrSaveIfs[cnt] == client_lan_ip)
+		{
+			PwrSaveIfs[cnt] = 0;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+
diff --git a/ipacm/src/IPACM_EvtDispatcher.cpp b/ipacm/src/IPACM_EvtDispatcher.cpp
new file mode 100644
index 0000000..2d2909b
--- /dev/null
+++ b/ipacm/src/IPACM_EvtDispatcher.cpp
@@ -0,0 +1,199 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_EvtDispatcher.cpp
+
+	@brief
+	This file implements the IPAM event dispatcher functionality
+
+	@Author
+
+*/
+#include <string.h>
+#include <pthread.h>
+#include <IPACM_EvtDispatcher.h>
+#include <IPACM_Neighbor.h>
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Defs.h"
+
+
+extern pthread_mutex_t mutex;
+extern pthread_cond_t  cond_var;
+
+cmd_evts *IPACM_EvtDispatcher::head = NULL;
+
+int IPACM_EvtDispatcher::PostEvt
+(
+	 ipacm_cmd_q_data *data
+)
+{
+	Message *item = NULL;
+	MessageQueue *MsgQueue = NULL;
+
+	MsgQueue = MessageQueue::getInstance();
+	if(MsgQueue == NULL)
+	{
+		IPACMERR("unable to retrieve MsgQueue instance\n");
+		return IPACM_FAILURE;
+	}
+
+	item = new Message();
+	if(item == NULL)
+	{
+		IPACMERR("unable to create new message item\n");
+		return IPACM_FAILURE;
+	}
+
+	IPACMDBG("Populating item to post to queue\n");
+	item->evt.callback_ptr = IPACM_EvtDispatcher::ProcessEvt;
+	memcpy(&item->evt.data, data, sizeof(ipacm_cmd_q_data));
+
+	if(pthread_mutex_lock(&mutex) != 0)
+	{
+		IPACMERR("unable to lock the mutex\n");
+		return IPACM_FAILURE;
+	}
+
+	IPACMDBG("Enqueing item\n");
+	MsgQueue->enqueue(item);
+	IPACMDBG("Enqueued item %p\n", item);
+
+	if(pthread_cond_signal(&cond_var) != 0)
+	{
+		IPACMDBG("unable to lock the mutex\n");
+		/* Release the mutex before you return failure */
+		if(pthread_mutex_unlock(&mutex) != 0)
+		{
+			IPACMERR("unable to unlock the mutex\n");
+			return IPACM_FAILURE;
+		}
+		return IPACM_FAILURE;
+	}
+
+	if(pthread_mutex_unlock(&mutex) != 0)
+	{
+		IPACMERR("unable to unlock the mutex\n");
+		return IPACM_FAILURE;
+	}
+
+	return IPACM_SUCCESS;
+}
+
+void IPACM_EvtDispatcher::ProcessEvt(ipacm_cmd_q_data *data)
+{
+
+	cmd_evts *tmp = head;
+
+	if(head == NULL)
+	{
+		IPACMDBG("Queue is empty\n");
+	}
+
+	while(tmp != NULL)
+	{
+		if(data->event == tmp->event)
+		{
+			tmp->obj->event_callback(data->event, data->evt_data);
+		}
+		tmp = tmp->next;
+	}
+
+	if(data->evt_data != NULL)
+	{
+		free(data->evt_data);
+	}
+	return;
+}
+
+int IPACM_EvtDispatcher::registr(ipa_cm_event_id event, IPACM_Listener *obj)
+{
+	cmd_evts *tmp = head,*nw;
+
+	nw = (cmd_evts *)malloc(sizeof(cmd_evts));
+	if(nw != NULL)
+	{
+		nw->event = event;
+		nw->obj = obj;
+		nw->next = NULL;
+	}
+	else
+	{
+		return IPACM_FAILURE;
+	}
+
+	if(head == NULL)
+	{
+		head = nw;
+	}
+	else
+	{
+		while(tmp->next)
+		{
+			tmp = tmp->next;
+		}
+		tmp->next = nw;
+	}
+	return IPACM_SUCCESS;
+}
+
+
+int IPACM_EvtDispatcher::deregistr(IPACM_Listener *param)
+{
+	cmd_evts *tmp = head,*tmp1,*prev = head;
+
+	while(tmp != NULL)
+	{
+		if(tmp->obj == param)
+		{
+			tmp1 = tmp;
+			if(tmp == head)
+			{
+				head = head->next;
+			}
+			else if(tmp->next == NULL)
+			{
+				prev->next = NULL;
+			}
+			else
+			{
+				prev->next = tmp->next;
+			}
+
+			tmp = tmp->next;
+			free(tmp1);
+		}
+		else
+		{
+			prev = tmp;
+			tmp = tmp->next;
+		}
+	}
+	return IPACM_SUCCESS;
+}
diff --git a/ipacm/src/IPACM_Filtering.cpp b/ipacm/src/IPACM_Filtering.cpp
new file mode 100644
index 0000000..4241549
--- /dev/null
+++ b/ipacm/src/IPACM_Filtering.cpp
@@ -0,0 +1,223 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_Filtering.cpp
+
+	@brief
+	This file implements the IPACM filtering functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "IPACM_Filtering.h"
+#include <IPACM_Log.h>
+
+const char *IPACM_Filtering::DEVICE_NAME = "/dev/ipa";
+
+IPACM_Filtering::IPACM_Filtering()
+{
+	fd = open(DEVICE_NAME, O_RDWR);
+	if (0 == fd)
+	{
+		IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+	}
+}
+
+IPACM_Filtering::~IPACM_Filtering()
+{
+	close(fd);
+}
+
+bool IPACM_Filtering::DeviceNodeIsOpened()
+{
+	return fd;
+}
+
+bool IPACM_Filtering::AddFilteringRule(struct ipa_ioc_add_flt_rule const *ruleTable)
+{
+	int retval = 0;
+
+	IPACMDBG("Printing filter add attributes\n");
+	IPACMDBG("ip type: %d\n", ruleTable->ip);
+	IPACMDBG("Number of rules: %d\n", ruleTable->num_rules);
+	IPACMDBG("End point: %d and global value: %d\n", ruleTable->ep, ruleTable->global);
+	IPACMDBG("commit value: %d\n", ruleTable->commit);
+	for (int cnt=0; cnt<ruleTable->num_rules; cnt++)
+	{
+		IPACMDBG("Filter rule:%d attrib mask: 0x%x\n",
+						 cnt, 
+						 ruleTable->rules[cnt].rule.attrib.attrib_mask);
+	}
+
+	retval = ioctl(fd, IPA_IOC_ADD_FLT_RULE, ruleTable);
+	if (retval != 0)
+	{
+		IPACMERR("Failed adding Filtering rule %p\n", ruleTable);
+		PERROR("unable to add filter rule:");
+
+		for (int cnt = 0; cnt < ruleTable->num_rules; cnt++)
+		{
+			if (ruleTable->rules[cnt].status != 0)
+			{
+				IPACMERR("Adding Filter rule:%d failed with status:%d\n",
+								 cnt, ruleTable->rules[cnt].status);
+			}
+		}
+		return false;
+	}
+
+	for (int cnt = 0; cnt<ruleTable->num_rules; cnt++)
+	{
+		if(ruleTable->rules[cnt].status != 0)
+		{
+			IPACMERR("Adding Filter rule:%d failed with status:%d\n",
+							 cnt, ruleTable->rules[cnt].status);
+		}
+	}
+
+	IPACMDBG("Added Filtering rule %p\n", ruleTable);
+	return true;
+}
+
+bool IPACM_Filtering::DeleteFilteringRule(struct ipa_ioc_del_flt_rule *ruleTable)
+{
+	int retval = 0;
+
+	retval = ioctl(fd, IPA_IOC_DEL_FLT_RULE, ruleTable);
+	if (retval != 0)
+	{
+		IPACMERR("Failed deleting Filtering rule %p\n", ruleTable);
+		return false;
+	}
+
+	IPACMDBG("Deleted Filtering rule %p\n", ruleTable);
+	return true;
+}
+
+bool IPACM_Filtering::Commit(enum ipa_ip_type ip)
+{
+	int retval = 0;
+
+	retval = ioctl(fd, IPA_IOC_COMMIT_FLT, ip);
+	if (retval != 0)
+	{
+		IPACMERR("failed committing Filtering rules.\n");
+		return false;
+	}
+
+	IPACMDBG("Committed Filtering rules to IPA HW.\n");
+	return true;
+}
+
+bool IPACM_Filtering::Reset(enum ipa_ip_type ip)
+{
+	int retval = 0;
+
+	retval = ioctl(fd, IPA_IOC_RESET_FLT, ip);
+	retval |= ioctl(fd, IPA_IOC_COMMIT_FLT, ip);
+	if (retval)
+	{
+		IPACMERR("failed resetting Filtering block.\n");
+		return false;
+	}
+
+	IPACMDBG("Reset command issued to IPA Filtering block.\n");
+	return true;
+}
+
+bool IPACM_Filtering::DeleteFilteringHdls
+(
+	 uint32_t *flt_rule_hdls,
+	 ipa_ip_type ip,
+	 uint8_t num_rules
+	 )
+{
+	struct ipa_ioc_del_flt_rule *flt_rule;
+	bool res = true;
+	int len = 0, cnt = 0;
+
+	len = (sizeof(struct ipa_ioc_del_flt_rule)) + (num_rules * sizeof(struct ipa_flt_rule_del));
+	flt_rule = (struct ipa_ioc_del_flt_rule *)malloc(len);
+	if (flt_rule == NULL)
+	{
+		IPACMERR("unable to allocate memory for del filter rule\n");
+		return false;
+	}
+
+	memset(flt_rule, 0, len);
+	flt_rule->commit = 1;
+	flt_rule->num_hdls = num_rules;
+	flt_rule->ip = ip;
+
+	for (cnt = 0; cnt < flt_rule->num_hdls; cnt++)
+	{
+
+		if (flt_rule_hdls[cnt] == 0)
+		{
+			IPACMERR("invalid filter handle passed, ignoring it: %d\n", cnt)
+			res = false;
+			goto fail;
+		}
+
+		flt_rule->hdl[cnt].status = -1;
+		flt_rule->hdl[cnt].hdl = flt_rule_hdls[cnt];
+		IPACMDBG("Deleting filter hdl:(0x%x) with ip type: %d\n", flt_rule_hdls[cnt], ip);
+	}
+
+	if (DeleteFilteringRule(flt_rule) == false)
+	{
+		PERROR("Filter rule deletion failed!\n");
+		res = false;
+		goto fail;
+	}
+
+	for (cnt = 0; cnt < flt_rule->num_hdls; cnt++)
+	{
+		if (flt_rule->hdl[cnt].status != 0)
+		{
+			IPACMERR("Filter rule hdl 0x%x deletion failed with error:%d\n",
+							 flt_rule->hdl[cnt].hdl, flt_rule->hdl[cnt].status);
+			res = false;
+		}
+	}
+
+fail:
+	free(flt_rule);
+
+	return res;
+}
+
diff --git a/ipacm/src/IPACM_Header.cpp b/ipacm/src/IPACM_Header.cpp
new file mode 100644
index 0000000..0ebb83d
--- /dev/null
+++ b/ipacm/src/IPACM_Header.cpp
@@ -0,0 +1,200 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "IPACM_Header.h"
+#include "IPACM_Log.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+//All interaction through the driver are made through this inode.
+static const char *DEVICE_NAME = "/dev/ipa";
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+IPACM_Header::IPACM_Header()
+{
+	m_fd = open(DEVICE_NAME, O_RDWR);
+	if (-1 == m_fd)
+	{
+		IPACMDBG("Failed to open %s in IPACM_Header test application constructor.\n", DEVICE_NAME);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+IPACM_Header::~IPACM_Header()
+{
+	if (-1 != m_fd)
+	{
+		close(m_fd);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::DeviceNodeIsOpened()
+{
+	return (-1 != m_fd);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::AddHeader(struct ipa_ioc_add_hdr *pHeaderTableToAdd)
+{
+	int nRetVal = 0;
+	//call the Driver ioctl in order to add header
+	nRetVal = ioctl(m_fd, IPA_IOC_ADD_HDR, pHeaderTableToAdd);
+	IPACMDBG("return value: %d\n", nRetVal);
+	return (-1 != nRetVal);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::DeleteHeader(struct ipa_ioc_del_hdr *pHeaderTableToDelete)
+{
+	int nRetVal = 0;
+	//call the Driver ioctl in order to remove header
+	nRetVal = ioctl(m_fd, IPA_IOC_DEL_HDR, pHeaderTableToDelete);
+	IPACMDBG("return value: %d\n", nRetVal);
+	return (-1 != nRetVal);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::Commit()
+{
+	int nRetVal = 0;
+	nRetVal = ioctl(m_fd, IPA_IOC_COMMIT_HDR);
+	IPACMDBG("return value: %d\n", nRetVal);
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::Reset()
+{
+	int nRetVal = 0;
+
+	nRetVal = ioctl(m_fd, IPA_IOC_RESET_HDR);
+	nRetVal |= ioctl(m_fd, IPA_IOC_COMMIT_HDR);
+	IPACMDBG("return value: %d\n", nRetVal);
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::GetHeaderHandle(struct ipa_ioc_get_hdr *pHeaderStruct)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened()) return false;
+
+	retval = ioctl(m_fd, IPA_IOC_GET_HDR, pHeaderStruct);
+	if (retval)
+	{
+		IPACMERR("IPA_IOC_GET_HDR ioctl failed, routingTable =0x%p, retval=0x%x.\n", pHeaderStruct, retval);
+		return false;
+	}
+
+	IPACMDBG("IPA_IOC_GET_HDR ioctl issued to IPA header insertion block.\n");
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::CopyHeader(struct ipa_ioc_copy_hdr *pCopyHeaderStruct)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened()) return false;
+
+	retval = ioctl(m_fd, IPA_IOC_COPY_HDR, pCopyHeaderStruct);
+	if (retval)
+	{
+		IPACMERR("IPA_IOC_COPY_HDR ioctl failed, retval=0x%x.\n", retval);
+		return false;
+	}
+
+	IPACMDBG("IPA_IOC_COPY_HDR ioctl issued to IPA header insertion block.\n");
+	return true;
+}
+
+bool IPACM_Header::DeleteHeaderHdl(uint32_t hdr_hdl)
+{
+	const uint8_t NUM_HDLS = 1;
+	struct ipa_ioc_del_hdr *pHeaderDescriptor = NULL;
+	struct ipa_hdr_del *hd_rule_entry;
+	int len = 0;
+	bool res = true;
+
+	if (hdr_hdl == 0)
+	{
+		IPACMERR("Invalid header handle passed. Ignoring it\n");
+		return false;
+	}
+
+	len = (sizeof(struct ipa_ioc_del_hdr)) + (NUM_HDLS * sizeof(struct ipa_hdr_del));
+	pHeaderDescriptor = (struct ipa_ioc_del_hdr *)malloc(len);
+	if (pHeaderDescriptor == NULL)
+	{
+		IPACMERR("Unable to allocate memory for del header\n");
+		return false;
+	}
+
+	memset(pHeaderDescriptor, 0, len);
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdls = NUM_HDLS;
+	hd_rule_entry = &pHeaderDescriptor->hdl[0];
+
+	hd_rule_entry->hdl = hdr_hdl;
+	hd_rule_entry->status = -1;
+
+	IPACMDBG("Deleting Header hdl:(%x)\n", hd_rule_entry->hdl);
+	if ((false == DeleteHeader(pHeaderDescriptor)) ||
+			(hd_rule_entry->status))
+	{
+		PERROR("Header deletion failed!\n");
+		res = false;
+		goto fail;
+	}
+
+	IPACMDBG("Deleted Header hdl:(%x) successfully\n", hd_rule_entry->hdl);
+
+fail:
+	free(pHeaderDescriptor);
+
+	return res;
+
+}
+
diff --git a/ipacm/src/IPACM_Iface.cpp b/ipacm/src/IPACM_Iface.cpp
new file mode 100644
index 0000000..cc6ce13
--- /dev/null
+++ b/ipacm/src/IPACM_Iface.cpp
@@ -0,0 +1,598 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the following
+  disclaimer in the documentation and/or other materials provided
+  with the distribution.
+* Neither the name of The Linux Foundation nor the names of its
+  contributors may be used to endorse or promote products derived
+  from this software without specific prior written permission.																																
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.Z
+*/
+/*!
+  @file
+  IPACM_Iface.cpp
+
+  @brief
+  This file implements the basis Iface functionality.
+
+  @Author
+  Skylar Chang
+
+*/
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <ifaddrs.h>
+
+#include <IPACM_Netlink.h>
+#include <IPACM_Iface.h>
+#include <IPACM_Lan.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Wlan.h>
+
+const char *IPACM_Iface::DEVICE_NAME = "/dev/ipa";
+IPACM_Routing IPACM_Iface::m_routing;
+IPACM_Filtering IPACM_Iface::m_filtering;
+IPACM_Header IPACM_Iface::m_header;
+
+IPACM_Config *IPACM_Iface::ipacmcfg = IPACM_Config::GetInstance();
+
+IPACM_Iface::IPACM_Iface(int iface_index)
+{
+	ip_type = IPACM_IP_NULL; /* initially set invalid */
+	num_dft_rt = 0;
+	softwarerouting_act = false;
+	ipa_if_num = iface_index;
+
+	memcpy(dev_name,
+				 IPACM_Iface::ipacmcfg->iface_table[iface_index].iface_name,
+				 sizeof(IPACM_Iface::ipacmcfg->iface_table[iface_index].iface_name));
+
+	memset(dft_v4fl_rule_hdl, 0, sizeof(dft_v4fl_rule_hdl));
+	memset(dft_v6fl_rule_hdl, 0, sizeof(dft_v6fl_rule_hdl));
+
+	memset(dft_rt_rule_hdl, 0, sizeof(dft_rt_rule_hdl));
+	memset(software_routing_fl_rule_hdl, 0, sizeof(software_routing_fl_rule_hdl));
+
+	query_iface_property();
+	IPACMDBG(" create iface-index(%d) constructor\n", ipa_if_num);
+	return;
+}
+
+/* software routing enable */
+int IPACM_Iface::handle_software_routing_enable(void)
+{
+
+	int res = IPACM_SUCCESS;
+	struct ipa_flt_rule_add flt_rule_entry;
+	ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+	IPACMDBG("\n");
+
+	m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+		 calloc(1,
+						sizeof(struct ipa_ioc_add_flt_rule) +
+						1 * sizeof(struct ipa_flt_rule_add)
+						);
+	if (!m_pFilteringTable)
+	{
+		PERROR("Error Locate ipa_flt_rule_add memory...\n");
+		return IPACM_FAILURE;
+	}
+
+	m_pFilteringTable->commit = 1;
+	m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+	m_pFilteringTable->global = false;
+	m_pFilteringTable->num_rules = (uint8_t)1;
+
+
+	/* Configuring Software-Routing Filtering Rule */
+	memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+	flt_rule_entry.at_rear = false;
+	flt_rule_entry.flt_rule_hdl = -1;
+	flt_rule_entry.status = -1;
+	flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+	memcpy(&flt_rule_entry.rule.attrib,
+				 &rx_prop->rx[0].attrib,
+				 sizeof(flt_rule_entry.rule.attrib));
+
+	memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+	/* check iface is v4 or v6 or both*/
+	if (ip_type == IPA_IP_MAX)
+	{
+		/* handle v4 */
+		m_pFilteringTable->ip = IPA_IP_v4;
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			PERROR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (m_pFilteringTable->rules[0].status)
+		{
+			IPACMERR("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+		/* copy filter hdls */
+		software_routing_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+
+
+		/* handle v6*/
+		m_pFilteringTable->ip = IPA_IP_v6;
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			PERROR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (m_pFilteringTable->rules[0].status)
+		{
+			IPACMDBG("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+		/* copy filter hdls */
+		software_routing_fl_rule_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+		softwarerouting_act = true;
+	}
+	else
+	{
+		if (ip_type == IPA_IP_v4) 
+		{
+			m_pFilteringTable->ip = IPA_IP_v4;
+		}
+		else 
+		{
+			m_pFilteringTable->ip = IPA_IP_v6;
+		}
+
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			PERROR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (m_pFilteringTable->rules[0].status)
+		{
+			IPACMERR("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+		/* copy filter hdls */
+		if (ip_type == IPA_IP_v4) 
+		{
+			software_routing_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+		}
+		else 
+		{
+			software_routing_fl_rule_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+		}
+		softwarerouting_act = true;
+	}
+
+fail:
+	free(m_pFilteringTable);
+
+	return res;
+}
+
+/* software routing disable */
+int IPACM_Iface::handle_software_routing_disable(void)
+{
+	int res = IPACM_SUCCESS;
+	ipa_ip_type ip;
+	uint32_t flt_hdl;
+
+	IPACMDBG("ip-type: %d\n", ip_type);
+
+	if (ip_type == IPA_IP_MAX)
+	{
+		/* ipv4 case */
+		if (m_filtering.DeleteFilteringHdls(&software_routing_fl_rule_hdl[0],
+																				IPA_IP_v4, 1) == false)
+		{
+			PERROR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		/* ipv6 case */
+		if (m_filtering.DeleteFilteringHdls(&software_routing_fl_rule_hdl[1],
+																				IPA_IP_v6, 1) == false)
+		{
+			PERROR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		softwarerouting_act = false;
+	}
+	else
+	{
+		if (ip_type == IPA_IP_v4)
+		{
+			ip = IPA_IP_v4;
+		}
+		else
+		{
+			ip = IPA_IP_v6;
+		}
+
+
+		if (ip_type == IPA_IP_v4)
+		{
+			flt_hdl = software_routing_fl_rule_hdl[0];
+		}
+		else
+		{
+			flt_hdl = software_routing_fl_rule_hdl[1];
+		}
+
+		if (m_filtering.DeleteFilteringHdls(&flt_hdl, ip, 1) == false)
+		{
+			PERROR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		softwarerouting_act = false;
+	}
+
+fail:
+	return res;
+}
+
+/* Query ipa_interface_index by given linux interface_index */
+int IPACM_Iface::iface_ipa_index_query
+(
+	 int interface_index
+)
+{
+	int fd;
+	int link = -1;
+	int i = 0;
+	struct ifreq ifr;
+
+
+	/* Search known linux interface-index and map to IPA interface-index*/
+	for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_ipa_interfaces; i++)
+	{
+		if (interface_index == IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index)
+		{
+			link = i;
+			IPACMDBG("Interface (%s) found: linux(%d) ipa(%d) \n",
+							 IPACM_Iface::ipacmcfg->iface_table[i].iface_name,
+							 IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index,
+							 link);
+			return link;
+			break;
+		}
+	}
+
+	/* Search/Configure linux interface-index and map it to IPA interface-index */
+	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+	{
+		PERROR("get interface name socket create failed");
+		return IPACM_FAILURE;
+	}
+
+	memset(&ifr, 0, sizeof(struct ifreq));
+
+	ifr.ifr_ifindex = interface_index;
+	IPACMDBG("Interface index %d\n", interface_index);
+
+	if (ioctl(fd, SIOCGIFNAME, &ifr) < 0)
+	{
+		PERROR("call_ioctl_on_dev: ioctl failed:");
+		close(fd);
+		return IPACM_FAILURE;
+	}
+	close(fd);
+
+	IPACMDBG("Received interface name %s\n", ifr.ifr_name);
+	for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_ipa_interfaces; i++)
+	{
+		if (strncmp(ifr.ifr_name, 
+								IPACM_Iface::ipacmcfg->iface_table[i].iface_name,
+								sizeof(IPACM_Iface::ipacmcfg->iface_table[i].iface_name)) == 0)
+		{
+			IPACMDBG("Interface (%s) linux(%d) mapped to ipa(%d) \n", ifr.ifr_name, 
+							 IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index, i);
+
+			link = i;
+			IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index = interface_index;
+			break;
+		}
+	}
+
+	return link;
+}
+
+/*Query the IPA endpoint property */
+int IPACM_Iface::query_iface_property(void)
+{
+	int res = IPACM_SUCCESS, fd = 0;
+
+	fd = open(DEVICE_NAME, O_RDWR);
+	IPACMDBG("iface query-property \n");
+	if (0 == fd)
+	{
+		IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+		return IPACM_FAILURE;
+	}
+
+	iface_query = (struct ipa_ioc_query_intf *)
+		 calloc(1, sizeof(struct ipa_ioc_query_intf));
+
+	IPACMDBG("iface name %s\n", dev_name);
+	memcpy(iface_query->name, dev_name, sizeof(dev_name));
+
+	if (ioctl(fd, IPA_IOC_QUERY_INTF, iface_query) < 0)
+	{
+		PERROR("ioctl IPA_IOC_QUERY_INTF failed\n");
+		/* iface_query memory will free when iface-down*/
+		res = IPACM_FAILURE;
+	}
+
+	tx_prop = (struct ipa_ioc_query_intf_tx_props *)
+		 calloc(1, sizeof(struct ipa_ioc_query_intf_tx_props) +
+						iface_query->num_tx_props * sizeof(struct ipa_ioc_tx_intf_prop));
+
+	memcpy(tx_prop->name, dev_name, sizeof(tx_prop->name));
+	tx_prop->num_tx_props = iface_query->num_tx_props;
+
+	if (ioctl(fd, IPA_IOC_QUERY_INTF_TX_PROPS, tx_prop) < 0)
+	{
+		PERROR("ioctl IPA_IOC_QUERY_INTF_TX_PROPS failed\n");
+		/* tx_prop memory will free when iface-down*/
+		res = IPACM_FAILURE;
+	}
+
+	rx_prop = (struct ipa_ioc_query_intf_rx_props *)
+		 calloc(1, sizeof(struct ipa_ioc_query_intf_rx_props) +
+						iface_query->num_rx_props * sizeof(struct ipa_ioc_rx_intf_prop));
+
+	memcpy(rx_prop->name, dev_name,
+				 sizeof(rx_prop->name));
+	rx_prop->num_rx_props = iface_query->num_rx_props;
+
+	if (ioctl(fd, IPA_IOC_QUERY_INTF_RX_PROPS, rx_prop) < 0)
+	{
+		PERROR("ioctl IPA_IOC_QUERY_INTF_RX_PROPS failed\n");
+		/* rx_prop memory will free when iface-down*/
+		res = IPACM_FAILURE;
+	}
+
+	if (res != IPACM_FAILURE)
+	{
+		IPACMDBG("Rx property attribute mask:0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
+		for(uint32_t cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+		{
+			IPACMDBG("Tx property:%d attribute mask:0x%x, ip-type: %d\n", 
+							    cnt, tx_prop->tx[0].attrib.attrib_mask,tx_prop->tx[0].ip);
+		}
+	}
+
+	close(fd);
+	return res;
+}
+
+/*Configure the initial filter rules */
+int IPACM_Iface::init_fl_rule(ipa_ip_type iptype)
+{
+
+	int res = IPACM_SUCCESS, len = 0;
+	struct ipa_flt_rule_add flt_rule_entry;
+	ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+	/* update the iface ip-type to be IPA_IP_v4, IPA_IP_v6 or both*/
+	if (iptype == IPA_IP_v4)
+	{
+	
+		if ((ip_type == IPA_IP_v4) || (ip_type == IPA_IP_MAX))
+		{
+			IPACMDBG(" interface(%s:%d) already in ip-type %d\n", dev_name, ipa_if_num, ip_type);
+			return res;
+		}
+	
+		if (ip_type == IPA_IP_v6) 
+		{
+			ip_type = IPA_IP_MAX;
+		}
+		else 
+		{
+			ip_type = IPA_IP_v4; 
+		}
+
+		IPACMDBG(" interface(%s:%d) now ip-type is %d\n", dev_name, ipa_if_num, ip_type);
+	}
+	else
+	{
+
+		if ((ip_type == IPA_IP_v6) || (ip_type == IPA_IP_MAX))
+		{
+			IPACMDBG(" interface(%s:%d) already in ip-type %d\n", dev_name, ipa_if_num, ip_type);
+			return res;
+		}
+	
+		if (ip_type == IPA_IP_v4) 
+		{
+			ip_type = IPA_IP_MAX;
+		}
+		else 
+		{
+			ip_type = IPA_IP_v6;
+		}
+
+		IPACMDBG(" interface(%s:%d) now ip-type is %d\n", dev_name, ipa_if_num, ip_type);
+	}
+
+
+	/* construct ipa_ioc_add_flt_rule with default filter rules */
+	if (iptype == IPA_IP_v4)
+	{
+		len = sizeof(struct ipa_ioc_add_flt_rule) +
+			 (IPV4_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add));
+
+		m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+		if (!m_pFilteringTable)
+		{
+			PERROR("Error Locate ipa_flt_rule_add memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		m_pFilteringTable->commit = 1;
+		m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+		m_pFilteringTable->global = false;
+		m_pFilteringTable->ip = iptype;
+		m_pFilteringTable->num_rules = (uint8_t)IPV4_DEFAULT_FILTERTING_RULES;
+
+		/* Configuring Fragment Filtering Rule */
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+		IPACMDBG("rx property attrib mask:0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
+		memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		/* Configuring Multicast Filtering Rule */
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xF0000000;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xE0000000;
+		memcpy(&(m_pFilteringTable->rules[1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		/* Configuring Broadcast Filtering Rule */
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xFFFFFFFF;
+		memcpy(&(m_pFilteringTable->rules[2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			PERROR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else
+		{
+			/* copy filter hdls */
+			for (int i = 0; i < IPV4_DEFAULT_FILTERTING_RULES; i++)
+			{
+				if (m_pFilteringTable->rules[i].status == 0)
+				{
+					dft_v4fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+					IPACMDBG("Default v4 filter Rule %d HDL:0x%x\n", i, dft_v4fl_rule_hdl[i]);
+				}
+				else
+				{
+					IPACMDBG("Failed adding default v4 Filtering rule %d\n", i);
+				}
+			}
+		}
+	}
+	else
+	{
+		len = sizeof(struct ipa_ioc_add_flt_rule) +
+			 (IPV6_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add));
+
+		m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+		if (!m_pFilteringTable)
+		{
+			PERROR("Error Locate ipa_flt_rule_add memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		m_pFilteringTable->commit = 1;
+		m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+		m_pFilteringTable->global = false;
+		m_pFilteringTable->ip = iptype;
+		m_pFilteringTable->num_rules = (uint8_t)IPV6_DEFAULT_FILTERTING_RULES;
+
+		/* Configuring Fragment Filtering Rule */
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+
+		/* Configuring Multicast Filtering Rule */
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFF000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0XFF000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+		memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		if (m_filtering.AddFilteringRule(m_pFilteringTable) == false)
+		{
+			PERROR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else
+		{
+			/* copy filter hdls */
+			for (int i = 0;
+					 i < IPV6_DEFAULT_FILTERTING_RULES;
+					 i++)
+			{
+				if (m_pFilteringTable->rules[i].status == 0)
+				{
+					dft_v6fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+					IPACMDBG("Default v6 Filter Rule %d HDL:0x%x\n", i, dft_v6fl_rule_hdl[i]);
+				}
+				else
+				{
+					IPACMERR("Failing adding v6 default IPV6 rule %d\n", i);
+				}
+			}
+		}
+	}
+
+
+fail:
+	free(m_pFilteringTable);
+
+	return res;
+}
diff --git a/ipacm/src/IPACM_IfaceManager.cpp b/ipacm/src/IPACM_IfaceManager.cpp
new file mode 100644
index 0000000..747cbfe
--- /dev/null
+++ b/ipacm/src/IPACM_IfaceManager.cpp
@@ -0,0 +1,242 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_IfaceManager.cpp
+
+	@brief
+	This file implements the IPAM iface_manager functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include <IPACM_IfaceManager.h>
+#include <IPACM_EvtDispatcher.h>
+#include <IPACM_Defs.h>
+#include <IPACM_Wlan.h>
+#include <IPACM_Lan.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Iface.h>
+#include <IPACM_Log.h>
+
+iface_instances *IPACM_IfaceManager::head = NULL;
+
+IPACM_IfaceManager::IPACM_IfaceManager() 
+{
+	IPACM_EvtDispatcher::registr(IPA_LINK_UP_EVENT, this); // skylar fix register name, class name
+	return; //skylar no interface_id
+}
+
+void IPACM_IfaceManager::event_callback(ipa_cm_event_id event, void *param) //skylar rename:event_callback
+{
+	ipacm_event_data_fid *evt_data = (ipacm_event_data_fid *)param;
+	IPACMDBG("\n");
+	switch(event)
+	{
+
+	case IPA_LINK_UP_EVENT:
+		IPACMDBG("link up %d: \n", evt_data->if_index);
+		create_iface_instance(evt_data->if_index);
+		break;
+
+	default:
+		break;
+	}
+	return;
+}
+
+int IPACM_IfaceManager::create_iface_instance(int if_index)
+{
+	int ipa_interface_index;
+	ipa_interface_index = IPACM_Iface::iface_ipa_index_query(if_index);
+
+	/* check if duplicate instance*/
+	if(SearchInstance(ipa_interface_index) == IPA_INSTANCE_NOT_FOUND)
+	{
+		/* IPA_INSTANCE_NOT_FOUND */
+		switch(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat)
+		{
+
+		case LAN_IF:
+			{
+				IPACMDBG("Creating Lan interface\n");
+				IPACM_Lan *lan = new IPACM_Lan(ipa_interface_index);
+				IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, lan);
+				IPACM_EvtDispatcher::registr(IPA_ROUTE_ADD_EVENT, lan);
+				IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, lan);
+				IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, lan);
+				IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT, lan);
+				IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, lan);
+				IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, lan);
+				IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, lan);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, lan);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, lan);
+				IPACMDBG("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", lan->dev_name, lan->ipa_if_num);
+				registr(ipa_interface_index, lan);
+			}
+			break;
+
+		case WLAN_IF:
+			{
+				IPACMDBG("Creating WLan interface\n");
+				IPACM_Wlan *wl = new IPACM_Wlan(ipa_interface_index);
+				IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, wl);
+				IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, wl);
+				IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_ADD_EVENT, wl);
+				IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_DEL_EVENT, wl);
+				IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_POWER_SAVE_EVENT, wl);
+				IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_RECOVER_EVENT, wl);
+				IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, wl);
+				IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, wl);
+				IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, wl);
+				IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, wl);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, wl);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, wl);
+				IPACMDBG("ipa_WLAN (%s):ipa_index (%d) instance open/registr ok\n", wl->dev_name, wl->ipa_if_num);
+				registr(ipa_interface_index, wl);
+			}
+			break;
+
+		case WAN_IF:
+			{
+				IPACMDBG("Creating Wan interface\n");
+				IPACM_Wan *w = new IPACM_Wan(ipa_interface_index);
+				IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, w);
+				IPACM_EvtDispatcher::registr(IPA_ROUTE_ADD_EVENT, w);
+				IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, w);
+				IPACM_EvtDispatcher::registr(IPA_FIREWALL_CHANGE_EVENT, w);
+				IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, w);
+				IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, w);
+				IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, w);
+				IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, w);
+				IPACMDBG("ipa_WAN (%s):ipa_index (%d) instance open/registr ok\n", w->dev_name, w->ipa_if_num);
+				registr(ipa_interface_index, w);
+			}
+			break;
+
+		default:
+			IPACMERR("Unhandled interface received\n");
+			return IPACM_SUCCESS;
+		}
+	}
+	return IPACM_SUCCESS;
+}
+
+
+int IPACM_IfaceManager::registr(int ipa_if_index, IPACM_Listener *obj)
+{
+	iface_instances *tmp = head,*nw;
+
+	nw = (iface_instances *)malloc(sizeof(iface_instances));
+	if(nw != NULL)
+	{
+		nw->ipa_if_index = ipa_if_index;
+		nw->obj = obj;
+		nw->next = NULL;
+	}
+	else
+	{
+		return IPACM_FAILURE;
+	}
+
+	if(head == NULL)
+	{
+		head = nw;
+	}
+	else
+	{
+		while(tmp->next)
+		{
+			tmp = tmp->next;
+		}
+		tmp->next = nw;
+	}
+	return IPACM_SUCCESS;
+}
+
+int IPACM_IfaceManager::deregistr(IPACM_Listener *param)
+{
+	iface_instances *tmp = head,*tmp1,*prev = head;
+
+	while(tmp != NULL)
+	{
+		if(tmp->obj == param)
+		{
+			tmp1 = tmp;
+			if(tmp == head)
+			{
+				head = head->next;
+			}
+			else if(tmp->next == NULL)
+			{
+				prev->next = NULL;
+			}
+			else
+			{
+				prev->next = tmp->next;
+			}
+
+			tmp = tmp->next;
+			free(tmp1);
+		}
+		else
+		{
+			prev = tmp;
+			tmp = tmp->next;
+		}
+	}
+	return IPACM_SUCCESS;
+}
+
+
+int IPACM_IfaceManager::SearchInstance(int ipa_if_index)
+{
+
+	iface_instances *tmp = head;
+
+	while(tmp != NULL)
+	{
+		if(ipa_if_index == tmp->ipa_if_index)
+		{
+			IPACMDBG("Find existed iface-instance name: %s\n",
+							 IPACM_Iface::ipacmcfg->iface_table[ipa_if_index].iface_name);
+			return IPA_INSTANCE_FOUND;
+		}
+		tmp = tmp->next;
+	}
+
+	IPACMDBG("No existed iface-instance name: %s,\n",
+					 IPACM_Iface::ipacmcfg->iface_table[ipa_if_index].iface_name);
+
+	return IPA_INSTANCE_NOT_FOUND;
+}
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
new file mode 100644
index 0000000..8b47985
--- /dev/null
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -0,0 +1,902 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer. 
+ 
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following
+disclaimer in the documentation and/or other materials provided
+with the distribution. 
+ 
+* Neither the name of The Linux Foundation nor the names of its
+contributors may be used to endorse or promote products derived
+from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_Lan.cpp
+
+	@brief
+	This file implements the LAN iface functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+#include <string.h>
+#include <sys/ioctl.h>
+#include <IPACM_Netlink.h>
+#include <IPACM_Lan.h>
+#include <IPACM_Wan.h>
+#include <IPACM_IfaceManager.h>
+
+IPACM_Lan::IPACM_Lan(int iface_index) : IPACM_Iface(iface_index)
+{
+	num_uni_rt = 0;
+	num_dft_rt = 0;
+
+	rt_rule_len = sizeof(struct ipa_lan_rt_rule) + (iface_query->num_tx_props * sizeof(uint32_t));
+	route_rule = (struct ipa_lan_rt_rule *)calloc(IPA_MAX_NUM_UNICAST_ROUTE_RULES, rt_rule_len);
+	if (route_rule == NULL)
+	{
+		IPACMERR("unable to allocate memory\n");
+		return;
+	}
+
+	IPACMDBG(" IPACM->IPACM_Lan(%d) constructor: Tx:%d Rx:%d\n", ipa_if_num,
+					 iface_query->num_tx_props, iface_query->num_rx_props);
+
+	return;
+}
+
+IPACM_Lan::~IPACM_Lan()
+{
+	IPACM_EvtDispatcher::deregistr(this);
+	IPACM_IfaceManager::deregistr(this);
+	return;
+}
+
+
+/* LAN-iface's callback function */
+void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param)
+{
+	int ipa_interface_index;
+
+	switch (event)
+	{
+	case IPA_LINK_DOWN_EVENT:
+		{
+			ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_LINK_DOWN_EVENT\n");
+				handle_down_evt();
+				IPACMDBG("ipa_LAN (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+				delete this;
+				return;
+			}
+		}
+		break;
+
+	case IPA_ADDR_ADD_EVENT:
+		{
+			ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_ADDR_ADD_EVENT\n");
+
+				if ((data->iptype != ip_type) && (ip_type != IPA_IP_MAX)) // check not setup before
+				{
+					handle_addr_evt(data);
+					handle_private_subnet(data->iptype);
+					if (IPACM_Wan::isWanUP() && (data->iptype == IPA_IP_v4))
+					{
+						handle_wan_up();
+					}
+
+					/* Post event to NAT */
+					if (data->iptype == IPA_IP_v4)
+					{
+						ipacm_cmd_q_data evt_data;
+						ipacm_event_iface_up *info;
+
+						info = (ipacm_event_iface_up *)
+							 malloc(sizeof(ipacm_event_iface_up));
+						if (info == NULL)
+						{
+							IPACMERR("Unable to allocate memory\n");
+							return;
+						}
+
+						memcpy(info->ifname, dev_name, IF_NAME_LEN);
+						info->ipv4_addr = data->ipv4_addr;
+						info->addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[0].subnet_mask;
+
+						evt_data.event = IPA_HANDLE_LAN_UP;
+						evt_data.evt_data = (void *)info;
+
+						/* Insert IPA_HANDLE_LAN_UP to command queue */
+						IPACMDBG("posting IPA_HANDLE_LAN_UP for IPv4 with below information\n");
+						IPACMDBG("IPv4 address:0x%x, IPv4 address mask:0x%x\n",
+										 info->ipv4_addr, info->addr_mask);
+						IPACM_EvtDispatcher::PostEvt(&evt_data);
+					}
+				}
+			}
+		}
+		break;
+
+	case IPA_HANDLE_WAN_UP:
+		IPACMDBG("Received IPA_HANDLE_WAN_UP event\n");
+		handle_wan_up();
+		break;
+
+	case IPA_ROUTE_ADD_EVENT:
+		{
+			ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+			/* unicast routing rule add */
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_ROUTE_ADD_EVENT\n");
+				handle_route_add_evt(data);
+			}
+		}
+		break;
+
+	case IPA_HANDLE_WAN_DOWN:
+		IPACMDBG("Received IPA_HANDLE_WAN_DOWN event\n");
+		handle_wan_down();
+		break;
+
+	case IPA_ROUTE_DEL_EVENT:
+		{
+			ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+			/* unicast routing rule del */
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_ROUTE_DEL_EVENT\n");
+				handle_route_del_evt(data);
+			}
+		}
+		break;
+
+	case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+		{
+			ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT\n");
+				ipacm_event_data_addr *data_addr;
+				data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+				if (data_addr == NULL)
+				{
+					IPACMERR("unable to allocate memory for event data_addr\n");
+					return;
+				}
+
+				data_addr->if_index = data->if_index;
+				data_addr->iptype = data->iptype;
+				if (data->iptype == IPA_IP_v4)
+				{
+					data_addr->ipv4_addr = data->ipv4_addr;
+					data_addr->ipv4_addr_mask = 0xFFFFFFFF;
+				}
+				else
+				{
+					memcpy(data_addr->ipv6_addr,
+								 data->ipv6_addr,
+								 sizeof(data_addr->ipv6_addr));
+					data_addr->ipv6_addr_mask[0] = 0xFFFFFFFF;
+					data_addr->ipv6_addr_mask[1] = 0xFFFFFFFF;
+					data_addr->ipv6_addr_mask[2] = 0xFFFFFFFF;
+					data_addr->ipv6_addr_mask[3] = 0xFFFFFFFF;
+				}
+				handle_route_add_evt(data_addr);
+			}
+		}
+		break;
+
+	case IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT:
+		{
+			ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT\n");
+				ipacm_event_data_addr *data_addr;
+				data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+				if (data_addr == NULL)
+				{
+					IPACMERR("unable to allocate memory for event data_addr\n");
+					return;
+				}
+
+				data_addr->if_index = data->if_index;
+				data_addr->iptype = data->iptype;
+				if (data->iptype == IPA_IP_v4)
+				{
+					data_addr->ipv4_addr = data->ipv4_addr;
+					data_addr->ipv4_addr_mask = 0xFFFFFFFF;
+				}
+				else
+				{
+					memcpy(data_addr->ipv6_addr,
+								 data->ipv6_addr,
+								 sizeof(data_addr->ipv6_addr));
+					data_addr->ipv6_addr_mask[0] = 0xFFFFFFFF;
+					data_addr->ipv6_addr_mask[1] = 0xFFFFFFFF;
+					data_addr->ipv6_addr_mask[2] = 0xFFFFFFFF;
+					data_addr->ipv6_addr_mask[3] = 0xFFFFFFFF;
+				}
+				handle_route_del_evt(data_addr);
+			}
+		}
+		break;
+
+	case IPA_SW_ROUTING_ENABLE:
+		IPACMDBG("Received IPA_SW_ROUTING_ENABLE\n");
+		/* handle software routing enable event*/
+		handle_software_routing_enable();
+		break;
+
+	case IPA_SW_ROUTING_DISABLE:
+		IPACMDBG("Received IPA_SW_ROUTING_DISABLE\n");
+		/* handle software routing disable event*/
+		handle_software_routing_disable();
+		break;
+
+	default:
+		break;
+	}
+
+	return;
+}
+
+/* handle unicast routing rule add event */
+int IPACM_Lan::handle_route_add_evt(ipacm_event_data_addr *data)
+{
+	/* add unicate route for LAN */
+	struct ipa_ioc_add_rt_rule *rt_rule;
+	struct ipa_rt_rule_add *rt_rule_entry;
+	struct ipa_ioc_get_hdr sRetHeader;
+	uint32_t tx_index;
+
+	IPACMDBG("LAN callback: unicast IPA_ROUTE_ADD_EVENT\n");
+
+	if (num_uni_rt < IPA_MAX_NUM_UNICAST_ROUTE_RULES)
+	{
+		/* unicast RT rule add start */
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+							1 * sizeof(struct ipa_rt_rule_add));
+		if (!rt_rule)
+		{
+			IPACMERR("fail\n");
+			return IPACM_FAILURE;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = (uint8_t)1;
+		rt_rule->ip = data->iptype;
+
+		if (data->iptype == IPA_IP_v4) strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+		else strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
+
+
+		rt_rule_entry = &rt_rule->rules[0];
+		rt_rule_entry->at_rear = 1;
+
+		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+			if (tx_prop->tx[tx_index].hdr_name)
+			{
+				memset(&sRetHeader, 0, sizeof(sRetHeader));
+				strncpy(sRetHeader.name,
+								tx_prop->tx[tx_index].hdr_name,
+								sizeof(tx_prop->tx[tx_index].hdr_name));
+
+				if (false == m_header.GetHeaderHandle(&sRetHeader))
+				{
+					IPACMDBG(" ioctl failed\n");
+				}
+
+				rt_rule_entry->rule.hdr_hdl = sRetHeader.hdl;
+			}
+			rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+			memcpy(&rt_rule_entry->rule.attrib,
+						 &tx_prop->tx[tx_index].attrib,
+						 sizeof(rt_rule_entry->rule.attrib));
+			rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+			if (data->iptype == IPA_IP_v4)
+			{
+				rt_rule_entry->rule.attrib.u.v4.dst_addr      = data->ipv4_addr;
+				rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = data->ipv4_addr_mask;
+			}
+			else
+			{
+				rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+				rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+				rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+				rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = data->ipv6_addr_mask[0];
+				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = data->ipv6_addr_mask[1];
+				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = data->ipv6_addr_mask[2];
+				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = data->ipv6_addr_mask[3];
+			}
+			IPACMDBG("m_routing = %p\n", &m_routing);
+
+			if (false == m_routing.AddRoutingRule(rt_rule))
+			{
+				IPACMERR("Routing rule addition failed!\n");
+				free(rt_rule);
+				return IPACM_FAILURE;
+			}
+
+			IPACMDBG("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+			get_rt_ruleptr(route_rule, num_uni_rt)->rt_rule_hdl[tx_index]
+				 = rt_rule_entry->rt_rule_hdl;
+		}
+		memcpy(&get_rt_ruleptr(route_rule, num_uni_rt)->rule,
+					 &rt_rule_entry->rule.attrib,
+					 sizeof(get_rt_ruleptr(route_rule, num_uni_rt)->rule));
+
+		get_rt_ruleptr(route_rule, num_uni_rt)->ip = data->iptype;
+		free(rt_rule);
+		num_uni_rt++;
+	}
+	else
+	{
+		IPACMDBG("unicast rule oversize\n");
+		return IPACM_FAILURE;
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* handle unicast routing rule del event */
+int IPACM_Lan::handle_route_del_evt(ipacm_event_data_addr *data)
+{
+	int i;
+	uint32_t tx_index;
+
+	/* delete 1 unicast RT rule */
+	for (i = 0; i <= num_uni_rt; i++)
+	{
+
+		if (data->iptype == IPA_IP_v4)
+		{
+			if ((data->ipv4_addr == get_rt_ruleptr(route_rule, i)->rule.u.v4.dst_addr) &&
+					(data->ipv4_addr_mask == get_rt_ruleptr(route_rule, i)->rule.u.v4.dst_addr_mask))
+			{
+				for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+				{
+					if (m_routing.DeleteRoutingHdl(get_rt_ruleptr(route_rule, i)->rt_rule_hdl[tx_index],
+																				 IPA_IP_v4) == false)
+					{
+						IPACMDBG("Routing rule deletion failed!\n");
+						return IPACM_FAILURE;
+					}
+				}
+
+				/* remove that delted route rule entry*/
+				for (; i <= num_uni_rt; i++)
+				{
+					get_rt_ruleptr(route_rule, i)->rule = get_rt_ruleptr(route_rule, (i + 1))->rule;
+					get_rt_ruleptr(route_rule, i)->ip = get_rt_ruleptr(route_rule, (i + 1))->ip;
+
+					for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+					{
+						get_rt_ruleptr(route_rule, i)->rt_rule_hdl[tx_index] = get_rt_ruleptr(route_rule, (i + 1))->rt_rule_hdl[tx_index];
+					}
+				}
+
+				num_uni_rt -= 1;
+				return IPACM_SUCCESS;
+			}
+		}
+		else
+		{
+			if ((data->ipv6_addr[0] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr[0]) &&
+					(data->ipv6_addr[1] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr[1]) &&
+					(data->ipv6_addr[2] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr[2]) &&
+					(data->ipv6_addr[3] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr[3]) &&
+					(data->ipv6_addr_mask[0] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr_mask[0]) &&
+					(data->ipv6_addr_mask[1] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr_mask[1]) &&
+					(data->ipv6_addr_mask[2] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr_mask[2]) &&
+					(data->ipv6_addr_mask[3] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr_mask[3]))
+			{
+
+				for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+				{
+					if (m_routing.DeleteRoutingHdl(get_rt_ruleptr(route_rule, i)->rt_rule_hdl[tx_index],
+																				 IPA_IP_v6) == false)
+					{
+						IPACMERR("Routing rule deletion failed!\n");
+						return IPACM_FAILURE;
+					}
+				}
+
+				/* remove that delted route rule entry*/
+				for (; i <= num_uni_rt; i++)
+				{
+					for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+					{
+						get_rt_ruleptr(route_rule, i)->rt_rule_hdl[tx_index] = get_rt_ruleptr(route_rule, (i + 1))->rt_rule_hdl[tx_index];
+					}
+					get_rt_ruleptr(route_rule, i)->rule = get_rt_ruleptr(route_rule, (i + 1))->rule;
+					get_rt_ruleptr(route_rule, i)->ip = get_rt_ruleptr(route_rule, (i + 1))->ip;
+				}
+
+				num_uni_rt -= 1;
+				return IPACM_SUCCESS;
+			}
+		}
+	}
+
+	return IPACM_FAILURE;
+}
+
+
+
+
+/* configure filter rule for wan_up event*/
+int IPACM_Lan::handle_wan_up(void)
+{
+	struct ipa_flt_rule_add flt_rule_entry;
+	int len = 0;
+	ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+	IPACMDBG("set WAN interface as default filter rule\n");
+
+	len = sizeof(struct ipa_ioc_add_flt_rule) + (1 * sizeof(struct ipa_flt_rule_add));
+	m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+	if (m_pFilteringTable == NULL)
+	{
+		PERROR("Error Locate ipa_flt_rule_add memory...\n");
+		return IPACM_FAILURE;
+	}
+
+	m_pFilteringTable->commit = 1;
+	m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+	m_pFilteringTable->global = false;
+	m_pFilteringTable->ip = IPA_IP_v4;
+	m_pFilteringTable->num_rules = (uint8_t)1;
+
+	IPACMDBG("Retrieving routing hanle for table: %s\n",
+					 IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name);
+	if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4))
+	{
+		IPACMERR("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4=0x%p) Failed.\n",
+						 &IPACM_Iface::ipacmcfg->rt_tbl_wan_v4);
+		return IPACM_FAILURE;
+	}
+	IPACMDBG("Routing hanle for table: %d\n", IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl);
+
+
+	memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add)); // Zero All Fields
+	flt_rule_entry.at_rear = true;
+	flt_rule_entry.flt_rule_hdl = -1;
+	flt_rule_entry.status = -1;
+	flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT; //IPA_PASS_TO_ROUTING
+	flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl;
+
+	memcpy(&flt_rule_entry.rule.attrib,
+				 &rx_prop->rx[0].attrib,
+				 sizeof(flt_rule_entry.rule.attrib));
+
+	flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+	flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x0;
+	flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x0;
+
+	memcpy(&m_pFilteringTable->rules[0], &flt_rule_entry, sizeof(flt_rule_entry));
+	if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+	{
+		IPACMDBG("Error Adding RuleTable(0) to Filtering, aborting...\n");
+		perror("Lan: Unable to add filter rule");
+		free(m_pFilteringTable);
+		return IPACM_FAILURE;
+	}
+	else
+	{
+		IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n",
+						 m_pFilteringTable->rules[0].flt_rule_hdl,
+						 m_pFilteringTable->rules[0].status);
+	}
+
+
+	/* copy filter hdls  */
+	lan_wan_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+	free(m_pFilteringTable);
+
+	return IPACM_SUCCESS;
+}
+
+
+/* delete filter rule for wan_down event*/
+int IPACM_Lan::handle_wan_down(void)
+{
+
+	if (m_filtering.DeleteFilteringHdls(&lan_wan_fl_rule_hdl[0],
+																			IPA_IP_v4, 1) == false)
+	{
+		IPACMDBG("Error Adding RuleTable(1) to Filtering, aborting...\n");
+		return IPACM_FAILURE;
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* handle new_address event*/
+int IPACM_Lan::handle_addr_evt(ipacm_event_data_addr *data)
+{
+	struct ipa_ioc_add_rt_rule *rt_rule;
+	struct ipa_rt_rule_add *rt_rule_entry;
+	struct ipa_flt_rule_add flt_rule_entry;
+	const int NUM_RULES = 1;
+	int res = IPACM_SUCCESS;
+
+	/* construct ipa_ioc_add_flt_rule with 1 rules */
+	ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+	IPACMDBG("set route/filter rule ip-type: %d \n", data->iptype);
+
+	rt_rule = (struct ipa_ioc_add_rt_rule *)
+		 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+						NUM_RULES * sizeof(struct ipa_rt_rule_add));
+
+	if (rt_rule == NULL)
+	{
+		IPACMERR("fail to allocate ipa_ioc_add_rt_rule \n");
+		return IPACM_FAILURE;
+	}
+
+	rt_rule->commit = 1;
+	rt_rule->num_rules = NUM_RULES;
+	rt_rule->ip = data->iptype;
+
+	if (data->iptype == IPA_IP_v4) strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+	else strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
+
+	rt_rule_entry = &rt_rule->rules[0];
+	rt_rule_entry->at_rear = 1;
+	rt_rule_entry->rule.dst = IPA_CLIENT_A5_LAN_WAN_CONS;  //go to A5
+	rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+
+	if (data->iptype == IPA_IP_v4)
+	{
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = data->ipv4_addr;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+	}
+	else
+	{
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+	}
+
+	if (false == m_routing.AddRoutingRule(rt_rule))
+	{
+		IPACMERR("Routing rule addition failed!\n");
+		res = IPACM_FAILURE;
+		goto fail;
+	}
+	else if (rt_rule_entry->status)
+	{
+		IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+		res = rt_rule_entry->status;
+		goto fail;
+	}
+	IPACMDBG("rt rule hdl=%x with ip-type: %d\n", rt_rule_entry->rt_rule_hdl, data->iptype);
+
+	if (data->iptype == IPA_IP_v4)
+	{
+		dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
+
+		/* initial multicast/broadcast/fragment filter rule */
+		IPACM_Iface::init_fl_rule(data->iptype);
+	}
+	else
+	{
+		if (num_dft_rt == 0)
+		{
+			/* initial multicast/broadcast/fragment filter rule */
+			IPACM_Iface::init_fl_rule(data->iptype);
+
+			/* add default v6 filter rule */
+			m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+				 calloc(1,
+								sizeof(struct ipa_ioc_add_flt_rule) +
+								1 * sizeof(struct ipa_flt_rule_add)
+								);
+
+			if (!m_pFilteringTable)
+			{
+				PERROR("Error Locate ipa_flt_rule_add memory...\n");
+				return IPACM_FAILURE;
+			}
+
+			m_pFilteringTable->commit = 1;
+			m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+			m_pFilteringTable->global = false;
+			m_pFilteringTable->ip = IPA_IP_v6;
+			m_pFilteringTable->num_rules = (uint8_t)1;
+
+
+			if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6))
+			{
+				IPACMDBG("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_v6);
+				free(m_pFilteringTable);
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+
+
+			memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+			flt_rule_entry.at_rear = true;
+			flt_rule_entry.flt_rule_hdl = -1;
+			flt_rule_entry.status = -1;
+			flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
+			memcpy(&flt_rule_entry.rule.attrib,
+						 &rx_prop->rx[0].attrib,
+						 sizeof(flt_rule_entry.rule.attrib));
+
+			flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+			memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+			if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+			{
+				IPACMERR("Error Adding Filtering rule, aborting...\n");
+				free(m_pFilteringTable);
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+			else
+			{
+				IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+			}
+
+			/* copy filter hdls */
+			dft_v6fl_rule_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+			free(m_pFilteringTable);
+		}
+
+		dft_rt_rule_hdl[1 + num_dft_rt] = rt_rule_entry->rt_rule_hdl;
+		num_dft_rt++;
+	}
+
+	IPACMDBG("number of default route rules %d\n", num_dft_rt);
+
+fail:
+	free(rt_rule);
+
+	return res;
+}
+
+/* configure private subnet filter rules*/
+int IPACM_Lan::handle_private_subnet(ipa_ip_type iptype)
+{
+	struct ipa_flt_rule_add flt_rule_entry;
+	int i;
+
+	ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+	IPACMDBG("lan->handle_private_subnet(); set route/filter rule \n");
+
+	if (iptype == IPA_IP_v4)
+	{
+
+		m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+			 calloc(1,
+							sizeof(struct ipa_ioc_add_flt_rule) +
+							(IPACM_Iface::ipacmcfg->ipa_num_private_subnet) * sizeof(struct ipa_flt_rule_add)
+							);
+		if (!m_pFilteringTable)
+		{
+			PERROR("Error Locate ipa_flt_rule_add memory...\n");
+			return IPACM_FAILURE;
+		}
+		m_pFilteringTable->commit = 1;
+		m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+		m_pFilteringTable->global = false;
+		m_pFilteringTable->ip = IPA_IP_v4;
+		m_pFilteringTable->num_rules = (uint8_t)IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+
+		if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+		{
+			IPACMERR("LAN m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_lan_v4);
+			free(m_pFilteringTable);
+			return IPACM_FAILURE;
+		}
+
+		for (i = 0; i < (IPACM_Iface::ipacmcfg->ipa_num_private_subnet); i++)
+		{
+			memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+			flt_rule_entry.at_rear = true;
+			flt_rule_entry.flt_rule_hdl = -1;
+			flt_rule_entry.status = -1;
+			flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+			memcpy(&flt_rule_entry.rule.attrib,
+						 &rx_prop->rx[0].attrib,
+						 sizeof(flt_rule_entry.rule.attrib));
+			flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+			flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask;
+			flt_rule_entry.rule.attrib.u.v4.dst_addr = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr;
+			memcpy(&(m_pFilteringTable->rules[i]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+			IPACMDBG("Loop %d  5\n", i);
+		}
+
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			IPACMDBG("Error Adding RuleTable(0) to Filtering, aborting...\n");
+			free(m_pFilteringTable);
+			return IPACM_FAILURE;
+		}
+
+		/* copy filter rule hdls */
+		for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_private_subnet; i++)
+		{
+
+			private_fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+		}
+		free(m_pFilteringTable);
+	}
+	return IPACM_SUCCESS;
+}
+
+
+
+/*handle wlan iface down event*/
+int IPACM_Lan::handle_down_evt()
+{
+	int i;
+	uint32_t tx_index;
+	int res = IPACM_SUCCESS;
+
+	/* no iface address up, directly close iface*/
+	if (ip_type == IPACM_IP_NULL)
+	{
+		goto fail;
+	}
+
+	IPACMDBG("lan handle_down_evt\n ");
+
+	if (ip_type != IPA_IP_v6)
+	{
+		if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4)
+				== false)
+		{
+			IPACMERR("Routing rule deletion failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+	}
+
+	/* delete default v6 routing rule */
+	if (ip_type != IPA_IP_v4)
+	{
+		/* may have multiple ipv6 iface-RT rules*/
+		for (i = 0; i < num_dft_rt; i++)
+		{
+			if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[1 + i], IPA_IP_v6)
+					== false)
+			{
+				IPACMERR("Routing rule deletion failed!\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+		}
+	}
+
+
+	/* free unicast routing rule	*/
+	for (i = 0; i < num_uni_rt; i++)
+	{
+		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+			if (m_routing.DeleteRoutingHdl(get_rt_ruleptr(route_rule, i)->rt_rule_hdl[tx_index],
+																		 get_rt_ruleptr(route_rule, i)->ip) == false)
+			{
+				IPACMERR("Routing rule deletion failed!\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+		}
+
+	}
+
+	/* check software routing fl rule hdl */
+	if (softwarerouting_act == true)
+	{
+		IPACM_Iface::handle_software_routing_disable();
+	}
+
+
+	/* delete default filter rules */
+	if (ip_type != IPA_IP_v6)
+	{
+		if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl,
+																				IPA_IP_v4,
+																				IPV4_DEFAULT_FILTERTING_RULES) == false)
+		{
+			IPACMERR("Error Adding Filtering Rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		/* 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)
+		{
+			IPACMERR("Error Deleting RuleTable(1) to Filtering, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+	}
+
+
+	if (ip_type != IPA_IP_v4)
+	{
+		if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl,
+																				IPA_IP_v6,
+																				(IPV6_DEFAULT_FILTERTING_RULES + IPV6_DEFAULT_LAN_FILTERTING_RULES)) == false)
+		{
+			IPACMERR("Error Adding RuleTable(1) to Filtering, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+	}
+
+	/* delete wan filter rule */
+	if (IPACM_Wan::isWanUP())
+	{
+		handle_wan_down();
+	}
+
+fail:
+	free(tx_prop);
+	free(rx_prop);
+	free(iface_query);
+
+	return res;
+}
diff --git a/ipacm/src/IPACM_Log.cpp b/ipacm/src/IPACM_Log.cpp
new file mode 100644
index 0000000..3333358
--- /dev/null
+++ b/ipacm/src/IPACM_Log.cpp
@@ -0,0 +1,68 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_log.cpp
+
+	@brief
+	This file implements the IPAM log functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+#include "IPACM_Log.h"
+#include <stdlib.h>
+
+#define FILE_NAME "/usr/ipacm_log.txt"
+
+static FILE *fp = NULL;
+char log_buf[LOG_SIZE];
+
+void logmessage(char *msg)
+{
+	 printf("%s\n", msg);
+#if 0
+	 if(fp == NULL)
+	 {
+			fp = fopen(FILE_NAME, "wb+");
+			if(fp  == NULL)
+			{
+				 printf("unable to open file\n");
+				 return;
+			}
+	 }
+
+	 fprintf(fp, msg);
+	 fflush(fp);
+#endif
+	 return;
+}
+
+
diff --git a/ipacm/src/IPACM_Main.cpp b/ipacm/src/IPACM_Main.cpp
new file mode 100644
index 0000000..6369e10
--- /dev/null
+++ b/ipacm/src/IPACM_Main.cpp
@@ -0,0 +1,424 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.																								from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_Main.cpp
+
+	@brief
+	This file implements the IPAM functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+/******************************************************************************
+
+																																																																																																IP_MAIN.C
+
+******************************************************************************/
+
+#include <sys/socket.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <fcntl.h>
+#include <sys/inotify.h>
+#include <stdlib.h>
+
+#include "IPACM_CmdQueue.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Defs.h"
+#include "IPACM_Neighbor.h"
+#include "IPACM_IfaceManager.h"
+#include "IPACM_Log.h"
+
+#include "IPACM_ConntrackListener.h"
+
+#define IPA_DRIVER  "/dev/ipa"
+
+#define IPACM_DIR_NAME     "/etc"
+#define IPACM_FILE_NAME    "mobileap_firewall.xml"
+
+#define INOTIFY_EVENT_SIZE  (sizeof(struct inotify_event))
+#define INOTIFY_BUF_LEN     (INOTIFY_EVENT_SIZE + 2*sizeof(IPACM_FILE_NAME))
+
+#define IPA_DRIVER_WLAN_EVENT_SIZE  (sizeof(struct ipa_wlan_msg))
+#define IPA_DRIVER_WLAN_META_MSG    (sizeof(struct ipa_msg_meta))
+#define IPA_DRIVER_WLAN_BUF_LEN     (IPA_DRIVER_WLAN_EVENT_SIZE + IPA_DRIVER_WLAN_META_MSG)
+
+//char *log_buf = (char *)malloc(LOG_SIZE);
+int ipa_get_if_index(char *if_name, int *if_index);
+
+/* start netlink socket monitor*/
+void* netlink_start(void *param)
+{
+	ipa_nl_sk_fd_set_info_t sk_fdset;
+	int ret_val = 0;
+
+	memset(&sk_fdset, 0, sizeof(ipa_nl_sk_fd_set_info_t));
+	IPACMDBG("netlink starter memset sk_fdset succeeds\n");
+	ret_val = ipa_nl_listener_init(NETLINK_ROUTE, (RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_LINK |
+																										RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NEIGH |
+																										RTNLGRP_IPV6_PREFIX),
+																 &sk_fdset, ipa_nl_recv_msg);
+
+	if (ret_val != IPACM_SUCCESS)
+	{
+		IPACMERR("Failed to initialize IPA netlink event listener\n");
+		return NULL;
+	}
+
+	return NULL;
+}
+
+/* start firewall-rule monitor*/
+void* firewall_monitor(void *param)
+{
+	int length;
+	int wd;
+	char buffer[INOTIFY_BUF_LEN];
+	int inotify_fd;
+	ipacm_cmd_q_data evt_data;
+	uint32_t mask = IN_MODIFY;
+
+	inotify_fd = inotify_init();
+	if (inotify_fd < 0)
+	{
+		PERROR("inotify_init");
+	}
+
+	IPACMDBG("Waiting for nofications in dir %s with mask: 0x%x\n", IPACM_DIR_NAME, mask);
+
+	wd = inotify_add_watch(inotify_fd,
+												 IPACM_DIR_NAME,
+												 mask);
+
+	while (1)
+	{
+		length = read(inotify_fd, buffer, INOTIFY_BUF_LEN);
+		struct inotify_event *event = (struct inotify_event *)buffer;
+
+		if (length < 0)
+		{
+			IPACMDBG("inotify read() error return length: %d and mask: 0x%x 0x%x\n", length, event->mask, mask);
+			return NULL;
+		}
+
+		if (event->len > 0)
+		{
+			if (event->mask & IN_MODIFY)
+			{
+				if (event->mask & IN_ISDIR)
+				{
+					IPACMDBG("The directory %s was 0x%x\n", event->name, event->mask);
+				}
+				else if (!strncmp(event->name, IPACM_FILE_NAME, event->len))
+				{
+					IPACMDBG("File \"%s\" was 0x%x\n", event->name, event->mask);
+					IPACMDBG("The interested file %s .\n", IPACM_FILE_NAME);
+
+					evt_data.event = IPA_FIREWALL_CHANGE_EVENT;
+					evt_data.evt_data = NULL;
+
+					/* Insert IPA_FIREWALL_CHANGE_EVENT to command queue */
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+				}
+			}
+			IPACMDBG("Received monitoring event %s.\n", event->name);
+		}
+	}
+
+	(void)inotify_rm_watch(inotify_fd, wd);
+	(void)close(inotify_fd);
+	return NULL;
+}
+
+
+/* start IPACM WLAN-driver notifier */
+void* ipa_driver_wlan_notifier(void *param)
+{
+	int length, fd;
+	char buffer[IPA_DRIVER_WLAN_BUF_LEN];
+	struct ipa_msg_meta *event_hdr = NULL;
+	struct ipa_wlan_msg *event = NULL;
+
+	ipacm_cmd_q_data evt_data;
+	ipacm_event_data_mac *data;
+
+	fd = open(IPA_DRIVER, O_RDWR);
+	if (fd == 0)
+	{
+		IPACMERR("Failed opening %s.\n", IPA_DRIVER);
+	}
+	
+	while (1)
+	{
+		IPACMDBG("Waiting for nofications from IPA driver \n");
+		memset(buffer, 0, sizeof(buffer));
+
+		length = read(fd, buffer, IPA_DRIVER_WLAN_BUF_LEN);
+		if (length < 0)
+		{
+			PERROR("didn't read IPA_driver correctly");
+			return NULL;
+		}
+
+		event_hdr = (struct ipa_msg_meta *)buffer;
+		IPACMDBG("Message type: %d\n", event_hdr->msg_type);
+		IPACMDBG("Event header length received: %d\n",event_hdr->msg_len);
+
+		if (event_hdr->msg_len > 0)
+		{
+			event = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+		}
+
+		/* Insert WLAN_DRIVER_EVENT to command queue */
+		data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
+		if (data == NULL)
+		{
+			PERROR("unable to allocate memory for event data\n");
+			return NULL;
+		}
+		
+		switch (event_hdr->msg_type)
+		{
+
+		case SW_ROUTING_ENABLE:
+			IPACMDBG("Received SW_ROUTING_ENABLE\n");
+			evt_data.event = IPA_SW_ROUTING_ENABLE;
+			evt_data.evt_data = NULL;
+			break;
+
+		case SW_ROUTING_DISABLE:
+			IPACMDBG("Received SW_ROUTING_DISABLE\n");
+			evt_data.event = IPA_SW_ROUTING_DISABLE;
+			evt_data.evt_data = NULL;
+			break;
+
+		case WLAN_CLIENT_CONNECT:
+			IPACMDBG("Received WLAN_CLIENT_CONNECT\n");
+			IPACMDBG("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+							 event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
+							 event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]); 
+
+		  evt_data.event = IPA_WLAN_CLIENT_ADD_EVENT;
+			evt_data.evt_data = data;
+			ipa_get_if_index(event->name, &(data->if_index));
+			memcpy(data->mac_addr,
+						 event->mac_addr,
+						 sizeof(event->mac_addr));
+			break;
+			
+		case WLAN_CLIENT_DISCONNECT:
+			IPACMDBG("Received WLAN_CLIENT_DISCONNECT\n");
+			IPACMDBG("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+							 event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
+							 event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]); 
+
+			memcpy(data->mac_addr,
+						 event->mac_addr,
+						 sizeof(event->mac_addr));
+			ipa_get_if_index(event->name, &(data->if_index));
+
+			evt_data.event = IPA_WLAN_CLIENT_DEL_EVENT;
+			evt_data.evt_data = data;
+			
+			break;
+
+		case WLAN_CLIENT_POWER_SAVE_MODE:
+			IPACMDBG("Received WLAN_CLIENT_POWER_SAVE_MODE\n");
+			IPACMDBG("Mac Address [0]:%2d [1]:%2d [2]:%2d [3]:%2d [4]:%2d [5]%2d\n",
+							 event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
+							 event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]); 
+
+			ipa_get_if_index(event->name, &(data->if_index));
+
+			evt_data.event = IPA_WLAN_CLIENT_POWER_SAVE_EVENT;
+			evt_data.evt_data = data;
+			memcpy(data->mac_addr,
+						 event->mac_addr,
+						 sizeof(event->mac_addr));
+			
+			break;
+
+		case WLAN_CLIENT_NORMAL_MODE:
+			IPACMDBG("Received WLAN_CLIENT_NORMAL_MODE\n");
+			IPACMDBG("Mac Address [0]:%2d [1]:%2d [2]:%2d [3]:%2d [4]:%2d [5]%2d\n",
+							 event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
+							 event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]); 
+
+			memcpy(data->mac_addr,
+						 event->mac_addr,
+						 sizeof(event->mac_addr));
+			ipa_get_if_index(event->name, &(data->if_index));
+			evt_data.evt_data = data;
+			evt_data.event = IPA_WLAN_CLIENT_RECOVER_EVENT;
+			break;
+
+		default:
+			IPACMDBG("Invalid message\n");
+			free(data);
+			continue;
+
+		}
+
+		/* finish command queue */
+		if (evt_data.evt_data == NULL)
+		{
+			free(data);
+		}
+
+		IPACMDBG("Posting event:%d\n", evt_data.event);
+		IPACM_EvtDispatcher::PostEvt(&evt_data);
+	}
+
+	(void)close(fd);
+	return NULL;
+}
+
+
+int main(int argc, char **argv)
+{
+	int ret;
+	pthread_t netlink_thread = 0, monitor_thread = 0, ipa_driver_thread = 0;
+	pthread_t cmd_queue_thread = 0;
+
+	IPACM_Neighbor *neigh = new IPACM_Neighbor();
+	IPACM_IfaceManager *ifacemgr = new IPACM_IfaceManager();
+
+	IPACMDBG("Staring IPA main\n");
+	IPACMDBG("ipa_cmdq_successful\n");
+
+
+	if (IPACM_SUCCESS == cmd_queue_thread)
+	{
+		ret = pthread_create(&cmd_queue_thread, NULL, MessageQueue::Process, NULL);
+		if (IPACM_SUCCESS != ret)
+		{
+			IPACMERR("unable to command queue thread\n");
+			return ret;
+		}
+		IPACMDBG("created command queue thread\n");
+	}
+
+	if (IPACM_SUCCESS == netlink_thread)
+	{
+		ret = pthread_create(&netlink_thread, NULL, netlink_start, NULL);
+		if (IPACM_SUCCESS != ret)
+		{
+			IPACMERR("unable to create netlink thread\n");
+			return ret;
+		}
+		IPACMDBG("created netlink thread\n");
+	}
+
+
+	if (IPACM_SUCCESS == monitor_thread)
+	{
+		ret = pthread_create(&monitor_thread, NULL, firewall_monitor, NULL);
+		if (IPACM_SUCCESS != ret)
+		{
+			IPACMERR("unable to create monitor thread\n");
+			return ret;
+		}
+		IPACMDBG("created firewall monitor thread\n");
+	}
+
+	if (IPACM_SUCCESS == ipa_driver_thread)
+	{
+		ret = pthread_create(&ipa_driver_thread, NULL, ipa_driver_wlan_notifier, NULL);
+		if (IPACM_SUCCESS != ret)
+		{
+			IPACMERR("unable to create ipa_driver_wlan thread\n");
+			return ret;
+		}
+		IPACMDBG("created ipa_driver_wlan thread\n");
+	}
+
+	pthread_join(cmd_queue_thread, NULL);
+	pthread_join(netlink_thread, NULL);
+	pthread_join(monitor_thread, NULL);
+	pthread_join(ipa_driver_thread, NULL);
+	return IPACM_SUCCESS;
+}
+
+
+/*===========================================================================
+		FUNCTION  ipa_get_if_index
+===========================================================================*/
+/*!
+@brief
+  get ipa interface index by given the interface name
+
+@return
+	IPACM_SUCCESS or IPA_FALUIRE
+
+@note
+
+- Dependencies
+		- None
+
+- Side Effects
+		- None
+*/
+/*=========================================================================*/
+int ipa_get_if_index
+(
+	 char *if_name,
+	 int *if_index
+	 )
+{
+	int fd;
+	struct ifreq ifr;
+
+	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+	{
+		PERROR("get interface index socket create failed");
+		return IPACM_FAILURE;
+	}
+
+	memset(&ifr, 0, sizeof(struct ifreq));
+
+	(void)strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
+
+	if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0)
+	{
+		PERROR("call_ioctl_on_dev: ioctl failed:");
+		close(fd);
+		return IPACM_FAILURE;
+	}
+
+	*if_index = ifr.ifr_ifindex;
+	close(fd);
+	return IPACM_SUCCESS;
+}
diff --git a/ipacm/src/IPACM_Neighbor.cpp b/ipacm/src/IPACM_Neighbor.cpp
new file mode 100644
index 0000000..327b681
--- /dev/null
+++ b/ipacm/src/IPACM_Neighbor.cpp
@@ -0,0 +1,252 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_Neighbor.cpp
+
+	@brief
+	This file implements the functionality of handling IPACM Neighbor events.
+
+	@Author
+	Skylar Chang
+
+*/
+
+#include <sys/ioctl.h>
+#include <IPACM_Neighbor.h>
+#include <IPACM_EvtDispatcher.h>
+#include "IPACM_Defs.h"
+#include "IPACM_Log.h"
+
+
+IPACM_Neighbor::IPACM_Neighbor()
+{
+	num_neighbor_client = 0;
+	IPACM_EvtDispatcher::registr(IPA_NEW_NEIGH_EVENT, this);
+	IPACM_EvtDispatcher::registr(IPA_DEL_NEIGH_EVENT, this);
+	return;
+}
+
+void IPACM_Neighbor::event_callback(ipa_cm_event_id event, void *param)
+{
+	ipacm_event_data_all *data = NULL;
+	int i, ipa_interface_index;
+	ipacm_cmd_q_data evt_data;
+	int num_neighbor_client_temp = num_neighbor_client;
+
+	IPACMDBG("Recieved event %d\n", event);
+
+	data = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+	memcpy(data, param, sizeof(ipacm_event_data_all));
+
+	ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
+	/*No that interface existed in ipa list*/
+	if(ipa_interface_index==-1)
+	  return;
+	
+	if (data->iptype == IPA_IP_v4)
+	{
+		/* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue*/
+		if (event == IPA_NEW_NEIGH_EVENT) 
+			evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+		else 
+			evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+
+		memcpy(&evt_data.evt_data, &data, sizeof(evt_data.evt_data));
+		IPACM_EvtDispatcher::PostEvt(&evt_data);
+		IPACMDBG("Posted event %d with %s\n", evt_data.event,
+						 IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+	}
+	else
+	{
+		if ((data->ipv6_addr[0]) || (data->ipv6_addr[1]) || (data->ipv6_addr[2]) || (data->ipv6_addr[3]))
+		{
+			/* check if iface is not bridge0*/
+			if (strcmp(IPA_VIRTUAL_IFACE_NAME, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) == 0)
+			{
+				/* searh if seen this client or not*/
+				for (i = 0; i < num_neighbor_client_temp; i++)
+				{
+					if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
+					{
+						data->if_index = neighbor_client[i].iface_index;
+						/* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+						if (event == IPA_NEW_NEIGH_EVENT) evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+						else evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+						//evt_data.evt_data=data;
+						memcpy(&evt_data.evt_data, &data, sizeof(evt_data.evt_data));
+						IPACM_EvtDispatcher::PostEvt(&evt_data);
+						/* ask for replaced iface name*/
+						ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
+						/*No that interface existed in ipa list*/
+	          if(ipa_interface_index==-1)
+	            return;
+						
+						IPACMDBG("Posted event %d, with %s\n",
+										 evt_data.event,
+										 IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+
+						/* delete that entry*/
+						for (; i < num_neighbor_client_temp - 1; i++)
+						{
+							memcpy(neighbor_client[i].mac_addr, neighbor_client[i + 1].mac_addr, sizeof(neighbor_client[i].mac_addr));
+							neighbor_client[i].v6_addr[0] = neighbor_client[i + 1].v6_addr[0];
+							neighbor_client[i].v6_addr[1] = neighbor_client[i + 1].v6_addr[1];
+							neighbor_client[i].v6_addr[2] = neighbor_client[i + 1].v6_addr[2];
+							neighbor_client[i].v6_addr[3] = neighbor_client[i + 1].v6_addr[3];
+							neighbor_client[i].iface_index = neighbor_client[i + 1].iface_index;
+						}
+						num_neighbor_client -= 1;
+						break;
+
+					};
+				}
+
+				/* cannot find neighbor client*/
+				if (i == num_neighbor_client_temp)
+				{
+					IPACMDBG("ipv6 with bridge0 with mac, not seen before\n");
+					if (num_neighbor_client_temp < IPA_MAX_NUM_NEIGHBOR_CLIENTS)
+					{
+						memcpy(neighbor_client[num_neighbor_client_temp].mac_addr,
+									 data->mac_addr,
+									 sizeof(data->mac_addr));
+						neighbor_client[num_neighbor_client_temp].v6_addr[0] = data->ipv6_addr[0];
+						neighbor_client[num_neighbor_client_temp].v6_addr[1] = data->ipv6_addr[1];
+						neighbor_client[num_neighbor_client_temp].v6_addr[2] = data->ipv6_addr[2];
+						neighbor_client[num_neighbor_client_temp].v6_addr[3] = data->ipv6_addr[3];
+						IPACMDBG("Copy bridge0 MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
+										 neighbor_client[num_neighbor_client_temp].mac_addr[0],
+										 neighbor_client[num_neighbor_client_temp].mac_addr[1],
+										 neighbor_client[num_neighbor_client_temp].mac_addr[2],
+										 neighbor_client[num_neighbor_client_temp].mac_addr[3],
+										 neighbor_client[num_neighbor_client_temp].mac_addr[4],
+										 neighbor_client[num_neighbor_client_temp].mac_addr[5],
+										 num_neighbor_client_temp);
+						num_neighbor_client++;
+						return;
+					}
+					else
+					{
+						IPACMERR("error:  neighbor client oversize!");
+						return;
+					}
+				}
+			}
+			else
+			{
+				/* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+				if (event == IPA_NEW_NEIGH_EVENT) 
+					evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+				else 
+					evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+
+				memcpy(&evt_data.evt_data, &data, sizeof(evt_data.evt_data));
+				//evt_data.evt_data=data;
+				IPACM_EvtDispatcher::PostEvt(&evt_data);
+				IPACMDBG("Posted event %d with %s\n",
+								 evt_data.event,
+								 IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+
+
+			}
+		}
+		else
+		{
+			/*no ipv6 in data searh if seen this client or not*/
+			for (i = 0; i < num_neighbor_client_temp; i++)
+			{
+				if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
+				{
+					data->ipv6_addr[0] = neighbor_client[i].v6_addr[0];
+					data->ipv6_addr[1] = neighbor_client[i].v6_addr[1];
+					data->ipv6_addr[2] = neighbor_client[i].v6_addr[2];
+					data->ipv6_addr[3] = neighbor_client[i].v6_addr[3];
+
+					/* check if iface is not bridge0*/
+					if (strcmp(IPA_VIRTUAL_IFACE_NAME, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) != 0)
+					{
+						/* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+						if (event == IPA_NEW_NEIGH_EVENT) evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+						else evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+						memcpy(&evt_data.evt_data, &data, sizeof(evt_data.evt_data));
+						IPACM_EvtDispatcher::PostEvt(&evt_data);
+						IPACMDBG("Posted event %d with %s\n",
+										 evt_data.event,
+										 IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+
+
+						/* delete that entry*/
+						for (; i <= num_neighbor_client_temp; i++)
+						{
+							memcpy(neighbor_client[i].mac_addr, neighbor_client[i + 1].mac_addr, sizeof(neighbor_client[i].mac_addr));
+							neighbor_client[i].v6_addr[0] = neighbor_client[i + 1].v6_addr[0];
+							neighbor_client[i].v6_addr[1] = neighbor_client[i + 1].v6_addr[1];
+							neighbor_client[i].v6_addr[2] = neighbor_client[i + 1].v6_addr[2];
+							neighbor_client[i].v6_addr[3] = neighbor_client[i + 1].v6_addr[3];
+							neighbor_client[i].iface_index = neighbor_client[i + 1].iface_index;
+						}
+						num_neighbor_client -= 1;
+					};
+					break;
+				};
+			}
+			/* not find client */
+			if (i == num_neighbor_client_temp)
+			{
+				IPACMDBG("ipv6 with bridge0 with mac, not seen before\n");
+				if (num_neighbor_client_temp < IPA_MAX_NUM_NEIGHBOR_CLIENTS)
+				{
+					memcpy(neighbor_client[num_neighbor_client_temp].mac_addr,
+								 data->mac_addr,
+								 sizeof(data->mac_addr));
+					neighbor_client[num_neighbor_client_temp].iface_index = data->if_index;
+					IPACMDBG("Copy wlan-iface client MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
+									 neighbor_client[num_neighbor_client_temp].mac_addr[0],
+									 neighbor_client[num_neighbor_client_temp].mac_addr[1],
+									 neighbor_client[num_neighbor_client_temp].mac_addr[2],
+									 neighbor_client[num_neighbor_client_temp].mac_addr[3],
+									 neighbor_client[num_neighbor_client_temp].mac_addr[4],
+									 neighbor_client[num_neighbor_client_temp].mac_addr[5],
+									 num_neighbor_client);
+					num_neighbor_client++;
+					return;
+				}
+				else
+				{
+					IPACMDBG("error:  neighbor client oversize!");
+					return;
+				}
+			};
+		}
+	}
+
+	return;
+}
+
diff --git a/ipacm/src/IPACM_Netlink.cpp b/ipacm/src/IPACM_Netlink.cpp
new file mode 100644
index 0000000..eea98ea
--- /dev/null
+++ b/ipacm/src/IPACM_Netlink.cpp
@@ -0,0 +1,1823 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the following
+  disclaimer in the documentation and/or other materials provided
+  with the distribution.
+* Neither the name of The Linux Foundation nor the names of its
+  contributors may be used to endorse or promote products derived
+  from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_Netlink.cpp
+
+	@brief
+	This file implements the IPAM Netlink Socket Parer functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Defs.h"
+#include "IPACM_Netlink.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Log.h"
+
+char dev_pre_name[IF_NAME_LEN];
+struct sockaddr_storage  dst_pre_addr;
+
+int ipa_get_if_name(char *if_name, int if_index);
+int find_mask(int ip_v4_last, int *mask_value);
+
+#define NDA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
+
+/* Opens a netlink socket*/
+static int ipa_nl_open_socket
+(
+	 ipa_nl_sk_info_t *sk_info,
+	 int protocol,
+	 unsigned int grps
+	 )
+{
+	int *p_sk_fd;
+	struct sockaddr_nl *p_sk_addr_loc;
+
+	p_sk_fd = &(sk_info->sk_fd);
+	p_sk_addr_loc = &(sk_info->sk_addr_loc);
+
+	/* Open netlink socket for specified protocol */
+	if((*p_sk_fd = socket(AF_NETLINK, SOCK_RAW, protocol)) < 0)
+	{
+		IPACMERR("cannot open netlink socket\n");
+		return IPACM_FAILURE;
+	}
+
+	/* Initialize socket addresses to null */
+	memset(p_sk_addr_loc, 0, sizeof(struct sockaddr_nl));
+
+	/* Populate local socket address using specified groups */
+	p_sk_addr_loc->nl_family = AF_NETLINK;
+	p_sk_addr_loc->nl_pid = getpid();
+	p_sk_addr_loc->nl_groups = grps;
+
+	/* Bind socket to the local address, i.e. specified groups. This ensures
+	 that multicast messages for these groups are delivered over this 
+	 socket. */
+
+	if(bind(*p_sk_fd,
+					(struct sockaddr *)p_sk_addr_loc,
+					sizeof(struct sockaddr_nl)) < 0)
+	{
+		IPACMDBG("Socket bind failed\n");
+		return IPACM_FAILURE;
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* Add fd to fdmap array and store read handler function ptr (up to MAX_NUM_OF_FD).*/
+static int ipa_nl_addfd_map
+(
+	 ipa_nl_sk_fd_set_info_t *fd_set,
+	 int fd,
+	 ipa_sock_thrd_fd_read_f read_f
+	 )
+{
+	if(fd_set->num_fd < MAX_NUM_OF_FD)
+	{
+		FD_SET(fd, &(fd_set->fdset));
+
+		/* Add fd to fdmap array and store read handler function ptr */
+		fd_set->sk_fds[fd_set->num_fd].sk_fd = fd;
+		fd_set->sk_fds[fd_set->num_fd].read_func = read_f;
+
+		/* Increment number of fds stored in fdmap */
+		fd_set->num_fd++;
+		if(fd_set->max_fd < fd)
+		{
+			fd_set->max_fd = fd;
+		}
+	}
+	else
+	{
+		return IPACM_FAILURE;
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/*  start socket listener */
+static int ipa_nl_sock_listener_start
+(
+	 ipa_nl_sk_fd_set_info_t *sk_fd_set
+	 )
+{
+	int i, ret;
+
+	while(true)
+	{
+		if((ret = select(sk_fd_set->max_fd + 1, &(sk_fd_set->fdset), NULL, NULL, NULL)) < 0)
+		{
+			IPACMERR("ipa_nl select failed\n");
+		}
+		else
+		{
+			for(i = 0; i < sk_fd_set->num_fd; i++)
+			{
+
+				if(FD_ISSET(sk_fd_set->sk_fds[i].sk_fd, &(sk_fd_set->fdset)))
+				{
+
+					if(sk_fd_set->sk_fds[i].read_func)
+					{
+						if(IPACM_SUCCESS != ((sk_fd_set->sk_fds[i].read_func)(sk_fd_set->sk_fds[i].sk_fd)))
+						{
+							IPACMERR("Error on read callback[%d] fd=%d\n",
+											 i,
+											 sk_fd_set->sk_fds[i].sk_fd);
+						}
+					}
+					else
+					{
+						IPACMDBG("No read function\n");
+					}
+				}
+
+			} /* end of for loop*/
+		} /* end of else */
+	} /* end of while */
+
+	return IPACM_SUCCESS;
+}
+
+/* allocate memory for ipa_nl__msg */
+static struct msghdr* ipa_nl_alloc_msg
+(
+	 uint32_t msglen
+	 )
+{
+	unsigned char *buf = NULL;
+	struct sockaddr_nl *nladdr = NULL;
+	struct iovec *iov = NULL;
+	struct msghdr *msgh = NULL;
+
+	if(IPA_NL_MSG_MAX_LEN < msglen)
+	{
+		IPACMERR("Netlink message exceeds maximum length\n");
+		return NULL;
+	}
+
+	msgh = (struct msghdr *)malloc(sizeof(struct msghdr));
+	if(msgh == NULL)
+	{
+		IPACMERR("Failed malloc for msghdr\n");
+		free(msgh);
+		return NULL;
+	}
+
+	nladdr = (struct sockaddr_nl *)malloc(sizeof(struct sockaddr_nl));
+	if(nladdr == NULL)
+	{
+		IPACMERR("Failed malloc for sockaddr\n");
+		free(nladdr);
+		free(msgh);
+		return NULL;
+	}
+
+	iov = (struct iovec *)malloc(sizeof(struct iovec));
+	if(iov == NULL)
+	{
+		PERROR("Failed malloc for iovec");
+		free(iov);
+		free(nladdr);
+		free(msgh);
+		return NULL;
+	}
+
+	buf = (unsigned char *)malloc(msglen);
+	if(buf == NULL)
+	{
+		IPACMERR("Failed malloc for mglen\n");
+		free(buf);
+		free(iov);
+		free(nladdr);
+		free(msgh);
+		return NULL;
+	}
+
+	memset(nladdr, 0, sizeof(struct sockaddr_nl));
+	nladdr->nl_family = AF_NETLINK;
+
+	memset(msgh, 0x0, sizeof(struct msghdr));
+	msgh->msg_name = nladdr;
+	msgh->msg_namelen = sizeof(struct sockaddr_nl);
+	msgh->msg_iov = iov;
+	msgh->msg_iovlen = 1;
+
+	memset(iov, 0x0, sizeof(struct iovec));
+	iov->iov_base = buf;
+	iov->iov_len = msglen;
+
+	return msgh;
+}
+
+/* release IPA message */
+static void ipa_nl_release_msg
+(
+	 struct msghdr *msgh
+	 )
+{
+	unsigned char *buf = NULL;
+	struct sockaddr_nl *nladdr = NULL;
+	struct iovec *iov = NULL;
+
+	if(NULL == msgh)
+	{
+		return;
+	}
+
+	nladdr = (struct sockaddr_nl *)msgh->msg_name;
+	iov = msgh->msg_iov;
+	if(msgh->msg_iov)
+	{
+		buf = (unsigned char *)msgh->msg_iov->iov_base;
+	}
+
+	free(buf);
+	free(iov);
+	free(nladdr);
+	free(msgh);
+
+	return;
+}
+
+/* receive and process nl message */
+static int ipa_nl_recv
+(
+	 int              fd,
+	 struct msghdr **msg_pptr,
+	 unsigned int  *msglen_ptr
+	 )
+{
+	struct msghdr *msgh = NULL;
+	int rmsgl;
+
+	msgh = ipa_nl_alloc_msg(IPA_NL_MSG_MAX_LEN);
+	if(NULL == msgh)
+	{
+		IPACMERR("Failed to allocate NL message\n");
+		goto error;
+	}
+
+
+	/* Receive message over the socket */
+	rmsgl = recvmsg(fd, msgh, 0);
+
+	/* Verify that something was read */
+	if(rmsgl <= 0)
+	{
+		PERROR("NL recv error");
+		goto error;
+	}
+
+	/* Verify that NL address length in the received message is expected value */
+	if(sizeof(struct sockaddr_nl) != msgh->msg_namelen)
+	{
+		IPACMERR("rcvd msg with namelen != sizeof sockaddr_nl\n");
+		goto error;
+	}
+
+	/* Verify that message was not truncated. This should not occur */
+	if(msgh->msg_flags & MSG_TRUNC)
+	{
+		IPACMERR("Rcvd msg truncated!\n");
+		goto error;
+	}
+
+	*msg_pptr    = msgh;
+	*msglen_ptr = rmsgl;
+
+	return IPACM_SUCCESS;
+
+/* An error occurred while receiving the message. Free all memory before 
+				 returning. */
+error:
+	ipa_nl_release_msg(msgh);
+	*msg_pptr    = NULL;
+	*msglen_ptr  = 0;
+
+	return IPACM_FAILURE;
+}
+
+/* decode the rtm netlink message */
+static int ipa_nl_decode_rtm_link
+(
+	 const char              *buffer,
+	 unsigned int             buflen,
+	 ipa_nl_link_info_t      *link_info
+)
+{
+	struct rtattr *rtah = NULL;
+	/* NL message header */
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
+
+	/* Extract the header data */
+	link_info->metainfo = *(struct ifinfomsg *)NLMSG_DATA(nlh);
+	buflen -= sizeof(struct nlmsghdr);
+	rtah = IFA_RTA(NLMSG_DATA(nlh));
+
+	return IPACM_SUCCESS;
+}
+
+/* Decode kernel address message parameters from Netlink attribute TLVs. */
+static int ipa_nl_decode_rtm_addr
+(
+	 const char              *buffer,
+	 unsigned int             buflen,
+	 ipa_nl_addr_info_t   *addr_info
+	 )
+{
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;  /* NL message header */
+	struct rtattr *rtah = NULL;
+	
+	/* Extract the header data */
+	addr_info->metainfo = *((struct ifaddrmsg *)NLMSG_DATA(nlh));
+	buflen -= sizeof(struct nlmsghdr);
+
+	/* Extract the available attributes */
+	addr_info->attr_info.param_mask = IPA_NLA_PARAM_NONE;
+
+	rtah = IFA_RTA(NLMSG_DATA(nlh));
+
+	while(RTA_OK(rtah, buflen))
+	{
+		switch(rtah->rta_type)
+		{
+
+		case IFA_ADDRESS:
+			addr_info->attr_info.prefix_addr.ss_family = addr_info->metainfo.ifa_family;
+			memcpy(&addr_info->attr_info.prefix_addr.__ss_padding,
+						 RTA_DATA(rtah),
+						 sizeof(addr_info->attr_info.prefix_addr.__ss_padding));
+			addr_info->attr_info.param_mask |= IPA_NLA_PARAM_PREFIXADDR;
+			break;
+
+		default:
+			break;
+
+		}
+		/* Advance to next attribute */
+		rtah = RTA_NEXT(rtah, buflen);
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* Decode kernel neighbor message parameters from Netlink attribute TLVs. */
+static int ipa_nl_decode_rtm_neigh
+(
+	 const char              *buffer,
+	 unsigned int             buflen,
+	 ipa_nl_neigh_info_t   *neigh_info
+	 )
+{
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;  /* NL message header */
+	struct rtattr *rtah = NULL;
+	
+	/* Extract the header data */
+	neigh_info->metainfo = *((struct ndmsg *)NLMSG_DATA(nlh));
+	buflen -= sizeof(struct nlmsghdr);
+
+	/* Extract the available attributes */
+	neigh_info->attr_info.param_mask = IPA_NLA_PARAM_NONE;
+
+	rtah = NDA_RTA(NLMSG_DATA(nlh));
+
+	while(RTA_OK(rtah, buflen))
+	{
+		switch(rtah->rta_type)
+		{
+
+		case NDA_DST:
+			neigh_info->attr_info.local_addr.ss_family = neigh_info->metainfo.ndm_family;
+			memcpy(&neigh_info->attr_info.local_addr.__ss_padding,
+						 RTA_DATA(rtah),
+						 sizeof(neigh_info->attr_info.local_addr.__ss_padding));
+			break;
+
+		case NDA_LLADDR:
+			memcpy(neigh_info->attr_info.lladdr_hwaddr.sa_data,
+						 RTA_DATA(rtah),
+						 sizeof(neigh_info->attr_info.lladdr_hwaddr.sa_data));
+			break;
+
+		default:
+			break;
+
+		}
+
+		/* Advance to next attribute */
+		rtah = RTA_NEXT(rtah, buflen);
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* Decode kernel route message parameters from Netlink attribute TLVs. */
+static int ipa_nl_decode_rtm_route
+(
+	 const char              *buffer,
+	 unsigned int             buflen,
+	 ipa_nl_route_info_t   *route_info
+	 )
+{
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;  /* NL message header */
+	struct rtattr *rtah = NULL;
+	
+	/* Extract the header data */
+	route_info->metainfo = *((struct rtmsg *)NLMSG_DATA(nlh));
+	buflen -= sizeof(struct nlmsghdr);
+
+	route_info->attr_info.param_mask = IPA_RTA_PARAM_NONE;
+	rtah = RTM_RTA(NLMSG_DATA(nlh));
+
+	while(RTA_OK(rtah, buflen))
+	{
+		switch(rtah->rta_type)
+		{
+
+		case RTA_DST:
+			if((route_info->metainfo.rtm_type == RTN_UNICAST) &&
+				 (route_info->metainfo.rtm_protocol == RTPROT_BOOT) &&
+				 (route_info->metainfo.rtm_scope == RT_SCOPE_LINK) &&
+				 (route_info->metainfo.rtm_table == RT_TABLE_MAIN))
+			{
+				route_info->metainfo.rtm_type = RTN_BROADCAST;
+				memcpy(&route_info->attr_info.dst_addr.__ss_padding,
+							 dst_pre_addr.__ss_padding,
+							 sizeof(route_info->attr_info.dst_addr.__ss_padding));
+				route_info->attr_info.param_mask |= IPA_RTA_PARAM_DST;
+			}
+			else
+			{
+				route_info->attr_info.dst_addr.ss_family = route_info->metainfo.rtm_family;
+				memcpy(&route_info->attr_info.dst_addr.__ss_padding,
+							 RTA_DATA(rtah),
+							 sizeof(route_info->attr_info.dst_addr.__ss_padding));
+				route_info->attr_info.param_mask |= IPA_RTA_PARAM_DST;
+			}
+			break;
+
+		case RTA_SRC:
+			route_info->attr_info.src_addr.ss_family = route_info->metainfo.rtm_family;
+			memcpy(&route_info->attr_info.src_addr.__ss_padding,
+						 RTA_DATA(rtah),
+						 sizeof(route_info->attr_info.src_addr.__ss_padding));
+			route_info->attr_info.param_mask |= IPA_RTA_PARAM_SRC;
+			break;
+
+		case RTA_GATEWAY:
+			route_info->attr_info.gateway_addr.ss_family = route_info->metainfo.rtm_family;
+			memcpy(&route_info->attr_info.gateway_addr.__ss_padding,
+						 RTA_DATA(rtah),
+						 sizeof(route_info->attr_info.gateway_addr.__ss_padding));
+			route_info->attr_info.param_mask |= IPA_RTA_PARAM_GATEWAY;
+			break;
+
+		case RTA_IIF:
+			memcpy(&route_info->attr_info.iif_index,
+						 RTA_DATA(rtah),
+						 sizeof(route_info->attr_info.iif_index));
+			route_info->attr_info.param_mask |= IPA_RTA_PARAM_IIF;
+			break;
+
+		case RTA_OIF:
+			memcpy(&route_info->attr_info.oif_index,
+						 RTA_DATA(rtah),
+						 sizeof(route_info->attr_info.oif_index));
+			route_info->attr_info.param_mask |= IPA_RTA_PARAM_OIF;
+			break;
+
+		case RTA_PRIORITY:
+			memcpy(&route_info->attr_info.priority,
+						 RTA_DATA(rtah),
+						 sizeof(route_info->attr_info.priority));
+			route_info->attr_info.param_mask |= IPA_RTA_PARAM_PRIORITY;
+			break;
+
+		default:
+			break;
+
+		}
+
+		/* Advance to next attribute */
+		rtah = RTA_NEXT(rtah, buflen);
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* decode the ipa nl-message */
+static int ipa_nl_decode_nlmsg
+(
+	 const char   *buffer,
+	 unsigned int  buflen,
+	 ipa_nl_msg_t  *msg_ptr
+	 )
+{
+	char dev_name[IF_NAME_LEN];
+	int ret_val, mask_value, mask_index, mask_value_v6;
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
+
+	uint32_t if_ipv4_addr =0, if_ipipv4_addr_mask =0, temp =0;
+
+	ipacm_cmd_q_data evt_data;
+	ipacm_event_data_all *data_all;
+	ipacm_event_data_fid *data_fid;
+	ipacm_event_data_addr *data_addr;
+
+
+	while(NLMSG_OK(nlh, buflen))
+	{
+		IPACMDBG("Received msg:%d from netlink\n", nlh->nlmsg_type)
+		switch(nlh->nlmsg_type)
+		{
+		case RTM_NEWLINK:
+			msg_ptr->type = nlh->nlmsg_type;
+			msg_ptr->link_event = true;
+			if(IPACM_SUCCESS != ipa_nl_decode_rtm_link(buffer, buflen, &(msg_ptr->nl_link_info)))
+			{
+				IPACMERR("Failed to decode rtm link message\n");
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				IPACMDBG("Got RTM_NEWLINK with below values\n");
+				IPACMDBG("RTM_NEWLINK, ifi_change:%d\n", msg_ptr->nl_link_info.metainfo.ifi_change);
+				IPACMDBG("RTM_NEWLINK, ifi_flags:%d\n", msg_ptr->nl_link_info.metainfo.ifi_flags);
+				IPACMDBG("RTM_NEWLINK, ifi_index:%d\n", msg_ptr->nl_link_info.metainfo.ifi_index);
+				IPACMDBG("RTM_NEWLINK, family:%d\n", msg_ptr->nl_link_info.metainfo.ifi_family);
+
+				if(IFF_UP & msg_ptr->nl_link_info.metainfo.ifi_change)
+				{
+					IPACMDBG("\n GOT useful newlink event\n");
+					ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+					if(msg_ptr->nl_link_info.metainfo.ifi_flags & IFF_UP)
+					{
+						IPACMDBG("Interface %s bring up with IP-family: %d \n", dev_name, msg_ptr->nl_link_info.metainfo.ifi_family);
+						/* post link up to command queue */
+						evt_data.event = IPA_LINK_UP_EVENT;
+						IPACMDBG("Posting IPA_LINK_UP_EVENT with if index: %d\n",
+										 data_fid->if_index);
+					}
+					else
+					{
+						IPACMDBG("Interface %s bring down with IP-family: %d \n", dev_name, msg_ptr->nl_link_info.metainfo.ifi_family);
+						/* post link down to command queue */
+						evt_data.event = IPA_LINK_DOWN_EVENT;
+						IPACMDBG("Posting IPA_LINK_DOWN_EVENT with if index: %d\n",
+										 data_fid->if_index);
+					}
+
+					data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+					if(data_fid == NULL)
+					{
+						IPACMDBG("unable to allocate memory for event data_fid\n");
+						return IPACM_FAILURE;
+					}
+					data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+
+					evt_data.evt_data = data_fid;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+
+				}
+			}
+			break;
+
+		case RTM_DELLINK:
+			IPACMDBG("\n GOT dellink event\n");
+			msg_ptr->type = nlh->nlmsg_type;
+			msg_ptr->link_event = true;
+			IPACMDBG("entering rtm decode\n");
+			if(IPACM_SUCCESS != ipa_nl_decode_rtm_link(buffer, buflen, &(msg_ptr->nl_link_info)))
+			{
+				IPACMERR("Failed to decode rtm link message\n");
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+				if(ret_val != IPACM_SUCCESS)
+				{
+					IPACMERR("Error while getting interface name\n");
+				}
+				IPACMDBG("Interface %s bring down \n", dev_name);
+
+				/* post link down to command queue */
+				evt_data.event = IPA_LINK_DOWN_EVENT;
+				data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+				if(data_fid == NULL)
+				{
+					IPACMDBG("unable to allocate memory for event data_fid\n");
+					return IPACM_FAILURE;
+				}
+
+				data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+				IPACMDBG("posting IPA_LINK_DOWN_EVENT with if idnex:%d\n",
+								 data_fid->if_index);
+				evt_data.evt_data = data_fid;
+				IPACM_EvtDispatcher::PostEvt(&evt_data);
+				/* finish command queue */
+			}
+			break;
+
+		case RTM_NEWADDR:
+			IPACMDBG("\n GOT RTM_NEWADDR event\n");
+			if(IPACM_SUCCESS != ipa_nl_decode_rtm_addr(buffer, buflen, &(msg_ptr->nl_addr_info)))
+			{
+				IPACMERR("Failed to decode rtm addr message\n");
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_addr_info.metainfo.ifa_index);
+				if(ret_val != IPACM_SUCCESS)
+				{
+					IPACMERR("Error while getting interface name\n");
+				}
+				IPACMDBG("Interface %s \n", dev_name);
+
+				data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+				if(data_addr == NULL)
+				{
+					IPACMDBG("unable to allocate memory for event data_addr\n");
+					return IPACM_FAILURE;
+				}
+
+				if(AF_INET6 == msg_ptr->nl_addr_info.attr_info.prefix_addr.ss_family)
+				{
+					data_addr->iptype = IPA_IP_v6;
+					IPACMDBG("IFA_ADDRESS:IPV6 %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[0])),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[0] >> 16)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[0] >> 32)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[0] >> 48)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[1])),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[1] >> 16)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[1] >> 32)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[1] >> 48)));
+
+					memcpy(data_addr->ipv6_addr,
+								 msg_ptr->nl_addr_info.attr_info.prefix_addr.__ss_padding,
+								 sizeof(data_addr->ipv6_addr));
+				}
+				else
+				{
+					data_addr->iptype = IPA_IP_v4;
+					IPACMDBG("IFA_ADDRESS:IPV4 %d.%d.%d.%d\n",
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding >> 8),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding >> 16),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding >> 24));
+					
+					memcpy(&data_addr->ipv4_addr,
+								 msg_ptr->nl_addr_info.attr_info.prefix_addr.__ss_padding,
+								 sizeof(data_addr->ipv4_addr));
+					data_addr->ipv4_addr = ntohl(data_addr->ipv4_addr);
+         
+				}
+
+				evt_data.event = IPA_ADDR_ADD_EVENT;
+				data_addr->if_index = msg_ptr->nl_addr_info.metainfo.ifa_index;
+
+				IPACMDBG("Posting IPA_ADDR_ADD_EVENT with if index:%d, ipv4 addr:0x%x\n",
+								 data_addr->if_index,
+								 data_addr->ipv4_addr);
+				evt_data.evt_data = data_addr;
+				IPACM_EvtDispatcher::PostEvt(&evt_data);
+			}
+			break;
+
+		case RTM_NEWROUTE:
+
+			if(IPACM_SUCCESS != ipa_nl_decode_rtm_route(buffer, buflen, &(msg_ptr->nl_route_info)))
+			{
+				IPACMERR("Failed to decode rtm route message\n");
+				return IPACM_FAILURE;
+			}
+
+			IPACMDBG("In case RTM_NEWROUTE\n");
+			IPACMDBG("rtm_type: %d\n", msg_ptr->nl_route_info.metainfo.rtm_type);
+			IPACMDBG("ss_padding: %d\n", ((unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24)));
+			IPACMDBG("rtm_type: %d\n", msg_ptr->nl_route_info.metainfo.rtm_type);
+			IPACMDBG("protocol: %d\n", msg_ptr->nl_route_info.metainfo.rtm_protocol);
+			IPACMDBG("rtm_scope: %d\n", msg_ptr->nl_route_info.metainfo.rtm_scope);
+      IPACMDBG("rtm_table: %d\n", msg_ptr->nl_route_info.metainfo.rtm_table);
+			IPACMDBG("rtm_family: %d\n", msg_ptr->nl_route_info.metainfo.rtm_family);
+			IPACMDBG("param_mask: 0x%x\n", msg_ptr->nl_route_info.attr_info.param_mask);
+
+			/* ipv4 interface route and its subnet mask	*/
+			if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_BROADCAST) && 
+				 ((unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24)) != 0)
+			{
+				if(IPACM_SUCCESS != 
+					 find_mask((unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24), &mask_value))
+				{
+					IPACMERR("Failed to decode rtm_addroute message\n");
+				}
+				else
+				{
+					IPACMDBG("\n GOT useful RTM_NEWROUTE event\n");
+
+					/* take care of subnet mask */
+					if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+					{
+						IPACMDBG("DST_ADDRESS:IPV4 %d.%d.%d.0\n",
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16));
+						IPACMDBG("MASK:IPV4 255.255.255.%d\n", mask_value);
+						ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+						if(ret_val != IPACM_SUCCESS)
+						{
+							IPACMERR("Error while getting interface name");
+						}
+						IPACMDBG("RTA_OIF, output Interface %s \n", dev_name);
+						memcpy(&dst_pre_addr.__ss_padding,
+									 msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+									 sizeof(dst_pre_addr.__ss_padding));
+						memcpy(&dev_pre_name,
+									 dev_name,
+									 sizeof(dev_pre_name));
+						IPACMDBG("save pre_DST_ADDRESS:IPV4 %d.%d.%d.%d %s\n",
+										 (unsigned char)(*(unsigned int *)&(dst_pre_addr).__ss_padding),
+										 (unsigned char)(*(unsigned int *)&(dst_pre_addr).__ss_padding >> 8),
+										 (unsigned char)(*(unsigned int *)&(dst_pre_addr).__ss_padding >> 16),
+										 (unsigned char)(*(unsigned int *)&(dst_pre_addr).__ss_padding >> 24), dev_pre_name);
+					}
+
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_addr\n");
+						return IPACM_FAILURE;
+					}
+
+					if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+					{
+						IPACMDBG("route add -net %d.%d.%d.0 netmask 255.255.255.%d dev %s  metric %d \n",
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+										 mask_value,
+										 dev_pre_name,
+										 msg_ptr->nl_route_info.attr_info.priority);
+					}
+					else
+					{
+						IPACMDBG("route add -net %d.%d.%d.0 netmask 255.255.255.%d dev %s \n",
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+										 mask_value,
+										 dev_name);
+					}
+
+					memcpy(&if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+								 sizeof(if_ipv4_addr));
+					if_ipv4_addr = (if_ipv4_addr << 8) >> 8;
+					temp = (-1) << 8;
+					temp = temp | mask_value;
+
+					/* insert to command queue */
+					evt_data.event = IPA_ROUTE_ADD_EVENT;
+
+					data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+					data_addr->iptype = IPA_IP_v4;
+					data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+					data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+					IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 address 0x%x\n",
+									 data_addr->if_index,
+									 data_addr->ipv4_addr);
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+				}
+			}
+
+			
+			/* take care of route add default route & uniroute */
+			if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) && 
+				 (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_BOOT) && 
+				 (msg_ptr->nl_route_info.metainfo.rtm_scope == RT_SCOPE_UNIVERSE) && 
+				 (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+			{
+				IPACMDBG("\n GOT RTM_NEWROUTE event\n");
+
+				if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+				{
+					ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+					if(ret_val != IPACM_SUCCESS)
+					{
+						IPACMERR("Error while getting interface name\n");
+					}
+
+					IPACMDBG("route add -host %d.%d.%d.%d gw %d.%d.%d.%d dev %s\n",
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 8),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 16),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 24),
+									 dev_name
+									 );
+
+					/* insert to command queue */
+					memcpy(&if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+								 sizeof(if_ipv4_addr));
+					temp = (-1);
+
+					evt_data.event = IPA_ROUTE_ADD_EVENT;
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMDBG("unable to allocate memory for event data_addr\n");
+						return IPACM_FAILURE;
+					}
+
+					data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+					data_addr->iptype = IPA_IP_v4;
+					data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+					data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+					IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 address 0x%x, mask:0x%x\n",
+									 data_addr->if_index,
+									 data_addr->ipv4_addr,
+									 data_addr->ipv4_addr_mask);
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+
+				}
+				else
+				{
+					ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+					if(ret_val != IPACM_SUCCESS)
+					{
+						IPACMERR("Error while getting interface name\n");
+					}
+
+					if(AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family)
+					{
+						/* insert to command queue */
+						data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+						if(data_addr == NULL)
+						{
+							IPACMERR("unable to allocate memory for event data_addr\n");
+							return IPACM_FAILURE;
+						}
+
+						if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+						{
+							IPACMDBG("ip -6 route add default dev %s metric %d\n",
+											 dev_name,
+											 msg_ptr->nl_route_info.attr_info.priority);
+						}
+						else
+						{
+							IPACMDBG("ip -6 route add default dev %s\n", dev_name);
+						}
+
+						memcpy(data_addr->ipv6_addr,
+									 msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+									 sizeof(data_addr->ipv6_addr));
+
+						memcpy(data_addr->ipv6_addr_mask,
+									 msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+									 sizeof(data_addr->ipv6_addr_mask));
+
+						evt_data.event = IPA_ROUTE_ADD_EVENT;
+						data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+						data_addr->iptype = IPA_IP_v6;
+
+						IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv6 address\n", 
+										 data_addr->if_index);
+						evt_data.evt_data = data_addr;
+						IPACM_EvtDispatcher::PostEvt(&evt_data);
+						/* finish command queue */
+
+					}
+					else
+					{
+						IPACMDBG("route add default gw %d.%d.%d.%d dev %s dstIP: %d.%d.%d.%d\n",
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding),
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 8),
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 16),
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 24),
+										 dev_name,
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24)
+										 );
+
+						/* insert to command queue */
+						data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+						if(data_addr == NULL)
+						{
+							IPACMERR("unable to allocate memory for event data_addr\n");
+							return IPACM_FAILURE;
+						}
+
+						memcpy(&if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+									 sizeof(if_ipv4_addr));
+						memcpy(&if_ipipv4_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+									 sizeof(if_ipipv4_addr_mask));
+
+						evt_data.event = IPA_ROUTE_ADD_EVENT;
+						data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+						data_addr->iptype = IPA_IP_v4;
+						data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+						data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+            IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 addr:0x%x and maxk: 0x%x\n",
+										 data_addr->if_index,
+										 data_addr->ipv4_addr,
+										 data_addr->ipv4_addr_mask);
+						evt_data.evt_data = data_addr;
+						IPACM_EvtDispatcher::PostEvt(&evt_data);
+						/* finish command queue */
+					}
+				}
+			}
+
+			/* ipv6 routing table */
+			if((AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family) && 
+				 (msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) && 
+				 (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_KERNEL) && 
+				 (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+			{
+				IPACMDBG("\n GOT valid v6-RTM_NEWROUTE event\n");
+				ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+				if(ret_val != IPACM_SUCCESS)
+				{
+					IPACMERR("Error while getting interface name\n");
+					return IPACM_FAILURE;
+				}
+
+				if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+				{
+					IPACMDBG("Route ADD IPV6 DST: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x/%d, metric %d, dev %s\n",
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0])),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 16)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 32)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 48)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1])),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 16)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 32)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 48)),
+									 msg_ptr->nl_route_info.metainfo.rtm_dst_len,
+									 msg_ptr->nl_route_info.attr_info.priority,
+									 dev_name);
+
+					/* insert to command queue */
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMDBG("unable to allocate memory for event data_addr\n");
+						return IPACM_FAILURE;
+					}
+
+					memcpy(data_addr->ipv6_addr, 
+								 msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+								 sizeof(data_addr->ipv6_addr));
+
+					mask_value_v6 = msg_ptr->nl_route_info.metainfo.rtm_dst_len;
+					for(mask_index = 0; mask_index < 4; mask_index++)
+					{
+						if(mask_value_v6 >= 32)
+						{
+							mask_v6(32, &data_addr->ipv6_addr_mask[mask_index]);
+							mask_value_v6 -= 32;
+						}
+						else
+						{
+							mask_v6(mask_value_v6, &data_addr->ipv6_addr_mask[mask_index]);
+							mask_value_v6 = 0;
+						}
+					}
+
+					IPACMDBG("ADD IPV6 MASK %d: %08x:%08x:%08x:%08x \n",
+									 msg_ptr->nl_route_info.metainfo.rtm_dst_len,
+									 data_addr->ipv6_addr_mask[0],
+									 data_addr->ipv6_addr_mask[1],
+									 data_addr->ipv6_addr_mask[2],
+									 data_addr->ipv6_addr_mask[3]);
+
+					evt_data.event = IPA_ROUTE_ADD_EVENT;
+					data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+					data_addr->iptype = IPA_IP_v6;
+
+					IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv6 addr\n",
+									 data_addr->if_index);
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+				}
+				
+				if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_GATEWAY)
+				{
+					IPACMDBG("Route ADD ::/0  Next Hop: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x, metric %d, dev %s\n",
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0])),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 16)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 32)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 48)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1])),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 16)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 32)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 48)),
+									 msg_ptr->nl_route_info.attr_info.priority,
+									 dev_name);
+
+					/* insert to command queue */
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_addr\n");
+						return IPACM_FAILURE;
+					}
+
+					memcpy(data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+								 sizeof(data_addr->ipv6_addr));
+					memcpy(data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+								 sizeof(data_addr->ipv6_addr_mask));
+
+					evt_data.event = IPA_ROUTE_ADD_EVENT;
+					data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+					data_addr->iptype = IPA_IP_v6;
+
+					IPACMDBG("posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv6 address\n",
+									 data_addr->if_index);
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+				}
+
+			}
+			break;
+
+		case RTM_DELROUTE:
+			if(IPACM_SUCCESS != ipa_nl_decode_rtm_route(buffer, buflen, &(msg_ptr->nl_route_info)))
+			{
+				IPACMDBG("Failed to decode rtm route message\n");
+				return IPACM_FAILURE;
+			}
+
+			if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_BROADCAST) && 
+				 ((unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24)) != 0)
+			{
+				if(IPACM_SUCCESS != find_mask((unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24), &mask_value))
+				{
+					IPACMERR("Failed to decode rtm_delroute message\n");
+				}
+				else
+				{
+					IPACMDBG("\n GOT useful RTM_DELROUTE event\n");
+
+					/* take care of subnet mask */
+					if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+					{
+							 IPACMDBG("DST_ADDRESS:IPV4 %d.%d.%d.0\n",
+												(unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+												(unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+												(unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16));
+						IPACMDBG("MASK:IPV4 255.255.255.%d\n", mask_value);
+						ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+						if(ret_val != IPACM_SUCCESS)
+						{
+							IPACMERR("Error while getting interface name\n");
+						}
+						IPACMDBG("RTA_OIF, output Interface %s \n", dev_name);
+					}
+					IPACMDBG("route del -net %d.%d.%d.0 netmask 255.255.255.%d dev %s \n",
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+									 mask_value,
+									 dev_name);
+
+					/* post event to command queue */
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_addr\n");
+						return IPACM_FAILURE;
+					}
+
+					if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+					{
+						IPACMDBG("Priority %d \n",
+										 msg_ptr->nl_route_info.attr_info.priority);
+					}
+					else;
+
+					memcpy(&if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+								 sizeof(if_ipv4_addr));
+					if_ipv4_addr = (if_ipv4_addr << 8) >> 8;
+					temp = (-1) << 8;
+					temp = temp | mask_value;
+					if_ipipv4_addr_mask = ntohl(temp);
+
+					evt_data.event = IPA_ROUTE_DEL_EVENT;
+					data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+					data_addr->iptype = IPA_IP_v4;
+					data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+					data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+					IPACMDBG("Posting IPA_ROUTE_DEL_EVENT with ifindex:%d, ipv4 address 0x%x, mask:0x%x\n",
+									 data_addr->if_index,
+									 data_addr->ipv4_addr,
+									 data_addr->ipv4_addr_mask);
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+				}
+			}
+
+			/* take care of route delete of default route & uniroute */
+			if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) && 
+				 (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_BOOT) && 
+				 (msg_ptr->nl_route_info.metainfo.rtm_scope == 0) && 
+				 (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+			{
+
+				if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+				{
+					ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+					if(ret_val != IPACM_SUCCESS)
+					{
+						IPACMERR("Error while getting interface name\n");
+					}
+					IPACMDBG("route del -host %d.%d.%d.%d gw %d.%d.%d.%d dev %s\n",
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 8),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 16),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 24),
+									 dev_name
+									 );
+
+					/* insert to command queue */
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_addr\n");
+						return IPACM_FAILURE;
+					}
+					memcpy(&if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+								 sizeof(if_ipv4_addr));
+					temp = (-1);
+					if_ipipv4_addr_mask = ntohl(temp);
+
+					evt_data.event = IPA_ROUTE_DEL_EVENT;
+					data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+					data_addr->iptype = IPA_IP_v4;
+					data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+					data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+					IPACMDBG("Posting event IPA_ROUTE_DEL_EVENT with if index:%d, ipv4 address 0x%x, mask:0x%x\n",
+									 data_addr->if_index,
+									 data_addr->ipv4_addr,
+									 data_addr->ipv4_addr_mask);
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+				}
+				else
+				{
+					ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+					if(ret_val != IPACM_SUCCESS)
+					{
+						IPACMERR("Error while getting interface name\n");
+					}
+
+					/* insert to command queue */
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_addr\n");
+						return IPACM_FAILURE;
+					}
+
+					if(AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family)
+					{
+						if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+						{
+							IPACMDBG("ip -6 route del default dev %s metric %d\n",
+											 dev_name,
+											 msg_ptr->nl_route_info.attr_info.priority);
+						}
+						else
+						{
+							IPACMDBG("ip -6 route del default dev %s\n", dev_name);
+						}
+						memcpy(data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+									 sizeof(data_addr->ipv6_addr));
+						memcpy(data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+									 sizeof(data_addr->ipv6_addr_mask));
+						data_addr->iptype = IPA_IP_v6;
+					}
+					else
+					{
+						IPACMDBG("route del default gw %d.%d.%d.%d dev %s\n",
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding),
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 8),
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 16),
+										 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 24),
+										 dev_name);
+
+						memcpy(&data_addr->ipv4_addr,
+									 msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+									 sizeof(data_addr->ipv4_addr));
+						data_addr->ipv4_addr = ntohl(data_addr->ipv4_addr);
+
+						memcpy(&data_addr->ipv4_addr_mask,
+									 msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+									 sizeof(data_addr->ipv4_addr_mask));
+						data_addr->ipv4_addr_mask = ntohl(data_addr->ipv4_addr_mask);
+
+						data_addr->iptype = IPA_IP_v4;
+					}
+
+					evt_data.event = IPA_ROUTE_DEL_EVENT;
+					data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+
+					IPACMDBG("Posting IPA_ROUTE_DEL_EVENT with if index:%d\n",
+									 data_addr->if_index);
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+				}
+			}
+
+			/* ipv6 routing table */
+			if((AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family) && 
+				 (msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) && 
+				 (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_KERNEL) && 
+				 (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+			{
+				IPACMDBG("\n GOT valid v6-RTM_DELROUTE event\n");
+				ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+				if(ret_val != IPACM_SUCCESS)
+				{
+					IPACMERR("Error while getting interface name");
+				}
+
+				if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+				{
+					IPACMDBG("DEL IPV6 DST: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x/%d, metric %d, dev %s\n",
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0])),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 16)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 32)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 48)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1])),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 16)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 32)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 48)),
+									 msg_ptr->nl_route_info.metainfo.rtm_dst_len,
+									 msg_ptr->nl_route_info.attr_info.priority,
+									 dev_name);
+
+					/* insert to command queue */
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_addr\n");
+						return IPACM_FAILURE;
+					}
+
+					memcpy(data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+								 sizeof(data_addr->ipv6_addr));
+
+					mask_value_v6 = msg_ptr->nl_route_info.metainfo.rtm_dst_len;
+					for(mask_index = 0; mask_index < 4; mask_index++)
+					{
+						IPACMDBG("%dst %d \n",
+										 mask_index,
+										 mask_value_v6);
+						if(mask_value_v6 >= 32)
+						{
+							mask_v6(32, &data_addr->ipv6_addr_mask[mask_index]);
+							mask_value_v6 -= 32;
+							IPACMDBG("%dst: %08x \n",
+											 mask_index,
+											 data_addr->ipv6_addr_mask[mask_index]);
+						}
+						else
+						{
+							mask_v6(mask_value_v6, data_addr->ipv6_addr_mask);
+							mask_value_v6 = 0;
+							IPACMDBG("%dst: %08x \n",
+											 mask_index,
+											 data_addr->ipv6_addr_mask[mask_index]);
+						}
+					}
+
+					IPACMDBG("DEL IPV6 MASK 0st: %08x ",
+									 data_addr->ipv6_addr_mask[0]);
+					IPACMDBG("1st: %08x ",
+									 data_addr->ipv6_addr_mask[1]);
+					IPACMDBG("2st: %08x ",
+									 data_addr->ipv6_addr_mask[2]);
+					IPACMDBG("3st: %08x \n",
+									 data_addr->ipv6_addr_mask[3]);
+
+					evt_data.event = IPA_ROUTE_DEL_EVENT;
+					data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+					data_addr->iptype = IPA_IP_v6;
+
+					IPACMDBG("posting event IPA_ROUTE_DEL_EVENT with if index:%d, ipv4 address\n",
+									 data_addr->if_index);
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+				}
+
+				if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_GATEWAY)
+				{
+					IPACMDBG("DEL ::/0  Next Hop: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x, metric %d, dev %s\n",
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0])),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 16)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 32)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 48)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1])),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 16)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 32)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 48)),
+									 msg_ptr->nl_route_info.attr_info.priority,
+									 dev_name);
+
+					/* insert to command queue */
+					data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+					if(data_addr == NULL)
+					{
+						IPACMERR("unable to allocate memory for event data_addr\n");
+						return IPACM_FAILURE;
+					}
+					memcpy(data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+								 sizeof(data_addr->ipv6_addr));
+					memcpy(data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+								 sizeof(data_addr->ipv6_addr_mask));
+
+					evt_data.event = IPA_ROUTE_DEL_EVENT;
+					data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+					data_addr->iptype = IPA_IP_v6;
+
+					IPACMDBG("Posting IPA_ROUTE_DEL_EVENT with if index: %d, ipv6 addr\n",
+									 data_addr->if_index)
+					evt_data.evt_data = data_addr;
+					IPACM_EvtDispatcher::PostEvt(&evt_data);
+					/* finish command queue */
+				}
+
+			}
+			break;
+
+		case RTM_NEWNEIGH:
+			if(IPACM_SUCCESS != ipa_nl_decode_rtm_neigh(buffer, buflen, &(msg_ptr->nl_neigh_info)))
+			{
+				IPACMERR("Failed to decode rtm neighbor message\n");
+				return IPACM_FAILURE;
+			}
+
+			IPACMDBG("RTM_NEWNEIGH, ndm_state:0x%x", msg_ptr->nl_neigh_info.metainfo.ndm_state)
+			if((NUD_PERMANENT | NUD_STALE) & (msg_ptr->nl_neigh_info.metainfo.ndm_state))
+			{
+				IPACMDBG("\n GOT RTM_NEWNEIGH event\n");
+				/* insert to command queue */
+				data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+				if(data_all == NULL)
+				{
+					IPACMERR("unable to allocate memory for event data_all\n");
+					return IPACM_FAILURE;
+				}
+
+				if(AF_INET6 == msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family)
+				{
+					IPACMDBG("IPV6 %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0])),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 16)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 32)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 48)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1])),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 16)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 32)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 48)));
+
+					memcpy(data_all->ipv6_addr, 
+								 msg_ptr->nl_neigh_info.attr_info.local_addr.__ss_padding,
+								 sizeof(data_all->ipv6_addr));
+					data_all->iptype = IPA_IP_v6;
+				}
+				else
+				{
+					IPACMDBG("IPV4 %d.%d.%d.%d\n",
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 8),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 16),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 24));
+
+
+					memcpy(&data_all->ipv4_addr, 
+								 msg_ptr->nl_neigh_info.attr_info.local_addr.__ss_padding,
+								 sizeof(data_all->ipv4_addr));
+					data_all->ipv4_addr = ntohl(data_all->ipv4_addr);
+					data_all->iptype = IPA_IP_v4;
+				}
+
+				memcpy(data_all->mac_addr,
+							 msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr.sa_data,
+							 sizeof(data_all->mac_addr));
+				evt_data.event = IPA_NEW_NEIGH_EVENT;
+				data_all->if_index = msg_ptr->nl_neigh_info.metainfo.ndm_ifindex;
+
+				IPACMDBG("posting IPA_NEW_NEIGH_EVENT with if index:%d\n",
+								 data_all->if_index);
+				evt_data.evt_data = data_all;
+				IPACM_EvtDispatcher::PostEvt(&evt_data);
+				/* finish command queue */
+
+				IPACMDBG("NDA_LLADDR:MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+								 (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[0],
+								 (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[1],
+								 (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[2],
+								 (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[3],
+								 (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[4],
+								 (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[5]);
+
+				ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_neigh_info.metainfo.ndm_ifindex);
+				if(ret_val != IPACM_SUCCESS)
+				{
+					IPACMERR("Error while getting interface index\n");
+				}
+				else
+				{
+					IPACMDBG("Interface %s \n", dev_name);
+				}
+			}
+			break;
+
+		case RTM_DELNEIGH:
+			if(IPACM_SUCCESS != ipa_nl_decode_rtm_neigh(buffer, buflen, &(msg_ptr->nl_neigh_info)))
+			{
+				IPACMERR("Failed to decode rtm neighbor message\n");
+				return IPACM_FAILURE;
+			}
+
+			if((NUD_PERMANENT | NUD_STALE) & (msg_ptr->nl_neigh_info.metainfo.ndm_state))
+			{
+				IPACMDBG("\n GOT RTM_DELNEIGH event\n");
+				/* insert to command queue */
+				data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+				if(data_all == NULL)
+				{
+					IPACMERR("unable to allocate memory for event data_all\n");
+					return IPACM_FAILURE;
+				}
+
+				if(AF_INET6 == msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family)
+				{
+					IPACMDBG("IPV6 %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0])),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 16)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 32)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 48)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1])),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 16)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 32)),
+									 (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 48)));
+
+					memcpy(data_all->ipv6_addr, msg_ptr->nl_neigh_info.attr_info.local_addr.__ss_padding,
+								 sizeof(data_all->ipv6_addr));
+					data_all->iptype = IPA_IP_v6;
+				}
+				else
+				{
+					IPACMDBG("IPV4 %d.%d.%d.%d\n",
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 8),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 16),
+									 (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 24));
+
+
+					memcpy(&data_all->ipv4_addr, msg_ptr->nl_neigh_info.attr_info.local_addr.__ss_padding,
+								 sizeof(data_all->ipv4_addr));
+					data_all->iptype = IPA_IP_v4;
+				}
+
+				memcpy(data_all->mac_addr,
+							 msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr.sa_data,
+							 sizeof(data_all->mac_addr));
+				evt_data.event = IPA_DEL_NEIGH_EVENT;
+				data_all->if_index = msg_ptr->nl_neigh_info.metainfo.ndm_ifindex;
+
+				IPACMDBG("posting IPA_DEL_NEIGH_EVENT with if index:%d\n",
+								 data_all->if_index);
+				evt_data.evt_data = data_all;
+				IPACM_EvtDispatcher::PostEvt(&evt_data);
+				/* finish command queue */
+
+				IPACMDBG("NDA_LLADDR:MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+								 (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[0],
+								 (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[1],
+								 (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[2],
+								 (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[3],
+								 (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[4],
+								 (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[5]);
+
+				ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_neigh_info.metainfo.ndm_ifindex);
+				if(ret_val != IPACM_SUCCESS)
+				{
+					//IPACM_LOG_MSG("Error while getting interface index");
+				}
+				else
+				{
+					IPACMDBG("Interface %s \n", dev_name);
+				}
+			}
+			break;
+
+		default:
+			IPACMDBG(" ignore NL event %d!!!\n ", nlh->nlmsg_type);
+			break;
+
+		}
+		nlh = NLMSG_NEXT(nlh, buflen);
+	}
+
+	return IPACM_SUCCESS;
+}
+
+
+/*  Virtual function registered to receive incoming messages over the NETLINK routing socket*/
+int ipa_nl_recv_msg(int fd)
+{
+	struct msghdr *msghdr = NULL;
+	//struct sockaddr_nl *nladdr = NULL;
+	struct iovec *iov = NULL;
+	unsigned int msglen = 0;
+	ipa_nl_msg_t *nlmsg = NULL;
+
+	nlmsg = (ipa_nl_msg_t *)malloc(sizeof(ipa_nl_msg_t));
+	if(NULL == nlmsg)
+	{
+		IPACMERR("Failed alloc of nlmsg \n");
+		goto error;
+	}
+	else
+	{
+		if(IPACM_SUCCESS != ipa_nl_recv(fd, &msghdr, &msglen))
+		{
+			IPACMERR("Failed to receive nl message \n");
+			goto error;
+		}
+
+		//nladdr = (struct sockaddr_nl *)msghdr->msg_name;
+		iov = msghdr->msg_iov;
+
+		memset(nlmsg, 0, sizeof(ipa_nl_msg_t));
+		if(IPACM_SUCCESS != ipa_nl_decode_nlmsg((char *)iov->iov_base, msglen, nlmsg))
+		{
+			IPACMERR("Failed to decode nl message \n");
+			goto error;
+		}
+
+		ipa_nl_release_msg(msghdr);
+		free(nlmsg);
+	}
+
+	return IPACM_SUCCESS;
+
+error:
+	if(msghdr)
+	{
+		ipa_nl_release_msg(msghdr);
+	}
+	if(nlmsg)
+	{
+		free(nlmsg);
+	}
+
+	return IPACM_FAILURE;
+}
+
+/*  get ipa interface name */
+int ipa_get_if_name
+(
+	 char *if_name,
+	 int if_index
+	 )
+{
+	int fd;
+	struct ifreq ifr;
+
+	if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+	{
+		IPACMERR("get interface name socket create failed \n");
+		return IPACM_FAILURE;
+	}
+
+	memset(&ifr, 0, sizeof(struct ifreq));
+	ifr.ifr_ifindex = if_index;
+	IPACMDBG("Interface index %d\n", if_index);
+
+	if(ioctl(fd, SIOCGIFNAME, &ifr) < 0)
+	{
+		IPACMERR("call_ioctl_on_dev: ioctl failed:\n");
+		close(fd);
+		return IPACM_FAILURE;
+	}
+
+	(void)strncpy(if_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+	IPACMDBG("interface name %s\n", ifr.ifr_name);
+	close(fd);
+
+	return IPACM_SUCCESS;
+}
+
+/* Initialization routine for listener on NetLink sockets interface */
+int ipa_nl_listener_init
+(
+	 unsigned int nl_type,
+	 unsigned int nl_groups,
+	 ipa_nl_sk_fd_set_info_t *sk_fdset,
+	 ipa_sock_thrd_fd_read_f read_f
+	 )
+{
+	ipa_nl_sk_info_t sk_info, sk_info2;
+	int ret_val;
+
+	memset(&sk_info, 0, sizeof(ipa_nl_sk_info_t));
+	IPACMDBG("Entering IPA NL listener init\n");
+
+	if(ipa_nl_open_socket(&sk_info, nl_type, nl_groups) == IPACM_SUCCESS)
+	{
+		IPACMDBG("IPA Open netlink socket succeeds\n");
+	}
+	else
+	{
+		IPACMERR("Netlink socket open failed\n");
+		return IPACM_FAILURE;
+	}
+
+	/* Add NETLINK socket to the list of sockets that the listener 
+					 thread should listen on. */
+
+	if(ipa_nl_addfd_map(sk_fdset, sk_info.sk_fd, read_f) != IPACM_SUCCESS)
+	{
+		IPACMERR("cannot add nl routing sock for reading\n");
+		return IPACM_FAILURE;
+	}
+
+	/* Start the socket listener thread */
+	ret_val = ipa_nl_sock_listener_start(sk_fdset);
+
+	if(ret_val != IPACM_SUCCESS)
+	{
+		IPACMERR("Failed to start NL listener\n");
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* find the newroute subnet mask */
+int find_mask(int ip_v4_last, int *mask_value)
+{
+
+	switch(ip_v4_last)
+	{
+
+	case 3:
+		*mask_value = 252;
+		return IPACM_SUCCESS;
+		break;
+
+	case 7:
+		*mask_value = 248;
+		return IPACM_SUCCESS;
+		break;
+
+	case 15:
+		*mask_value = 240;
+		return IPACM_SUCCESS;
+		break;
+
+	case 31:
+		*mask_value = 224;
+		return IPACM_SUCCESS;
+		break;
+
+	case 63:
+		*mask_value = 192;
+		return IPACM_SUCCESS;
+		break;
+
+	case 127:
+		*mask_value = 128;
+		return IPACM_SUCCESS;
+		break;
+
+	case 255:
+		*mask_value = 0;
+		return IPACM_SUCCESS;
+		break;
+
+	default:
+		return IPACM_FAILURE;
+		break;
+
+	}
+}
+
+/* map mask value for ipv6 */
+int mask_v6(int index, uint32_t *mask)
+{
+	switch(index)
+	{
+
+	case 0:
+		*mask = 0x00000000;
+		return IPACM_SUCCESS;
+		break;
+	case 4:
+		*mask = 0xf0000000;
+		return IPACM_SUCCESS;
+		break;
+	case 8:
+		*mask = 0xff000000;
+		return IPACM_SUCCESS;
+		break;
+	case 12:
+		*mask = 0xfff00000;
+		return IPACM_SUCCESS;
+		break;
+	case 16:
+		*mask = 0xffff0000;
+		return IPACM_SUCCESS;
+		break;
+	case 20:
+		*mask = 0xfffff000;
+		return IPACM_SUCCESS;
+		break;
+	case 24:
+		*mask = 0xffffff00;
+		return IPACM_SUCCESS;
+		break;
+	case 28:
+		*mask = 0xfffffff0;
+		return IPACM_SUCCESS;
+		break;
+	case 32:
+		*mask = 0xffffffff;
+		return IPACM_SUCCESS;
+		break;
+	default:
+		return IPACM_FAILURE;
+		break;
+
+	}
+}
+
+
diff --git a/ipacm/src/IPACM_Routing.cpp b/ipacm/src/IPACM_Routing.cpp
new file mode 100644
index 0000000..1351fbe
--- /dev/null
+++ b/ipacm/src/IPACM_Routing.cpp
@@ -0,0 +1,226 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_Routing.cpp
+
+	@brief
+	This file implements the IPACM routing functionality.
+
+	@Author
+
+*/
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "IPACM_Routing.h"
+#include <IPACM_Log.h>
+
+const char *IPACM_Routing::DEVICE_NAME = "/dev/ipa";
+
+IPACM_Routing::IPACM_Routing()
+{
+	m_fd = open(DEVICE_NAME, O_RDWR);
+	if (0 == m_fd)
+	{
+		IPACMDBG("Failed opening %s.\n", DEVICE_NAME);
+	}
+}
+
+IPACM_Routing::~IPACM_Routing()
+{
+	close(m_fd);
+}
+
+bool IPACM_Routing::DeviceNodeIsOpened()
+{
+	int res = fcntl(m_fd, F_GETFL);
+
+	if (m_fd > 0 && res >= 0) return true;
+	else return false;
+
+}
+
+bool IPACM_Routing::AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened())
+	{
+		IPACMDBG("Device is not opened\n");
+		return false;
+	}
+
+	retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE, ruleTable);
+	if (retval)
+	{
+		IPACMERR("Failed adding routing rule %p\n", ruleTable);
+		return false;
+	}
+
+	IPACMDBG("Added routing rule %p\n", ruleTable);
+	return true;
+}
+
+bool IPACM_Routing::DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened()) return false;
+
+	retval = ioctl(m_fd, IPA_IOC_DEL_RT_RULE, ruleTable);
+	if (retval)
+	{
+		IPACMERR("Failed deleting routing rule table %p\n", ruleTable);
+		return false;
+	}
+
+	IPACMDBG("Deleted routing rule %p\n", ruleTable);
+	return true;
+}
+
+bool IPACM_Routing::Commit(enum ipa_ip_type ip)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened()) return false;
+
+	retval = ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
+	if (retval)
+	{
+		IPACMERR("Failed commiting routing rules.\n");
+		return false;
+	}
+
+	IPACMDBG("Commited routing rules to IPA HW.\n");
+	return true;
+}
+
+bool IPACM_Routing::Reset(enum ipa_ip_type ip)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened()) return false;
+
+	retval = ioctl(m_fd, IPA_IOC_RESET_RT, ip);
+	retval |= ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
+	if (retval)
+	{
+		IPACMERR("Failed resetting routing block.\n");
+		return false;
+	}
+
+	IPACMDBG("Reset command issued to IPA routing block.\n");
+	return true;
+}
+
+bool IPACM_Routing::GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened()) return false;
+
+	retval = ioctl(m_fd, IPA_IOC_GET_RT_TBL, routingTable);
+	if (retval)
+	{
+		IPACMERR("IPA_IOCTL_GET_RT_TBL ioctl failed, routingTable =0x%p, retval=0x%x.\n", routingTable, retval);
+		return false;
+	}
+
+	IPACMDBG("IPA_IOCTL_GET_RT_TBL ioctl issued to IPA routing block.\n");
+	return true;
+}
+
+bool IPACM_Routing::PutRoutingTable(uint32_t routingTableHandle)
+{
+	int retval = 0;
+
+	if (!DeviceNodeIsOpened()) return false;
+
+	retval = ioctl(m_fd, IPA_IOC_PUT_RT_TBL, routingTableHandle);
+	if (retval)
+	{
+		IPACMERR("IPA_IOCTL_PUT_RT_TBL ioctl failed.\n");
+		return false;
+	}
+
+	IPACMDBG("IPA_IOCTL_PUT_RT_TBL ioctl issued to IPA routing block.\n");
+	return true;
+}
+
+bool IPACM_Routing::DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip)
+{
+	const uint8_t NUM_RULES = 1;
+	struct ipa_ioc_del_rt_rule *rt_rule;
+	struct ipa_rt_rule_del *rt_rule_entry;
+	bool res = true;
+	int len = 0;
+
+	if (rt_rule_hdl == 0)
+	{
+		IPACMERR("Invalid route handle passed. Ignoring it\n");
+		return false;
+	}
+
+	len = (sizeof(struct ipa_ioc_del_rt_rule)) + (NUM_RULES * sizeof(struct ipa_rt_rule_del));
+	rt_rule = (struct ipa_ioc_del_rt_rule *)malloc(len);
+	if (rt_rule == NULL)
+	{
+		IPACMERR("unable to allocate memory for del route rule\n");
+		return false;
+	}
+
+	memset(rt_rule, 0, len);
+	rt_rule->commit = 1;
+	rt_rule->num_hdls = NUM_RULES;
+	rt_rule->ip = ip;
+
+	rt_rule_entry = &rt_rule->hdl[0];
+	rt_rule_entry->status = -1;
+	rt_rule_entry->hdl = rt_rule_hdl;
+
+	IPACMDBG("Deleting Route hdl:(0x%x) with ip type: %d\n", rt_rule_entry->hdl, ip);
+	if ((false == DeleteRoutingRule(rt_rule)) ||
+			(rt_rule_entry->status))
+	{
+		PERROR("Routing rule deletion failed!\n");
+		goto fail;
+		res = false;
+	}
+
+fail:
+	free(rt_rule);
+
+	return res;
+}
+
diff --git a/ipacm/src/IPACM_Wan.cpp b/ipacm/src/IPACM_Wan.cpp
new file mode 100644
index 0000000..1a45dc5
--- /dev/null
+++ b/ipacm/src/IPACM_Wan.cpp
@@ -0,0 +1,1249 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+		@file
+		IPACM_Wan.cpp
+
+		@brief
+		This file implements the WAN iface functionality.
+
+		@Author
+		Skylar Chang
+
+*/
+#include <string.h>
+#include <sys/ioctl.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Xml.h>
+#include <IPACM_Log.h>
+#include "IPACM_EvtDispatcher.h"
+#include <IPACM_IfaceManager.h>
+
+bool IPACM_Wan::wan_up = false;
+
+IPACM_Wan::IPACM_Wan(int iface_index) : IPACM_Iface(iface_index)
+{
+	num_firewall_v4 = 0;
+	num_firewall_v6 = 0;
+	num_dft_rt = 0;
+
+	wan_route_rule_v4_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+	wan_route_rule_v6_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+
+	active_v4 = false;
+	active_v6 = false;
+
+	IPACMDBG(" IPACM->IPACM_Wan(%d) constructor: Tx:%d\n", ipa_if_num, iface_query->num_tx_props);
+	return;
+}
+
+IPACM_Wan::~IPACM_Wan()
+{
+	IPACM_EvtDispatcher::deregistr(this);
+	IPACM_IfaceManager::deregistr(this);
+	return;
+}
+
+/* handle new_address event */
+int IPACM_Wan::handle_addr_evt(ipacm_event_data_addr *data)
+{
+	struct ipa_ioc_add_rt_rule *rt_rule;
+	struct ipa_rt_rule_add *rt_rule_entry;
+	const int NUM_RULES = 1;
+	int res = IPACM_SUCCESS;
+
+	/* initial multicast/broadcast/fragment filter rule */
+	init_fl_rule(data->iptype);
+
+	rt_rule = (struct ipa_ioc_add_rt_rule *)
+		 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+						NUM_RULES * sizeof(struct ipa_rt_rule_add));
+
+	if (!rt_rule)
+	{
+		IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+		return IPACM_FAILURE;
+	}
+
+	rt_rule->commit = 1;
+	rt_rule->num_rules = NUM_RULES;
+	rt_rule->ip = data->iptype;
+
+	if (data->iptype == IPA_IP_v4)
+	{
+		strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+	}
+	else
+	{
+		strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
+	}
+
+	rt_rule_entry = &rt_rule->rules[0];
+	rt_rule_entry->at_rear = 1;
+	rt_rule_entry->rule.dst = IPA_CLIENT_A5_LAN_WAN_CONS;  //go to A5
+	rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+
+
+	if (data->iptype == IPA_IP_v6)
+	{
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+	}
+	else
+	{
+		/* still need setup v4 default routing rule to A5*/
+		rt_rule_entry->rule.attrib.u.v4.dst_addr      = data->ipv4_addr;
+		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		
+		wan_v4_addr = data->ipv4_addr;
+		IPACMDBG("Receved wan address:0x%x\n", wan_v4_addr);
+	}
+
+
+	if (false == m_routing.AddRoutingRule(rt_rule))
+	{
+		IPACMERR("Routing rule addition failed!\n");
+		res = IPACM_FAILURE;
+		goto fail;
+	}
+	else if (rt_rule_entry->status)
+	{
+		IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+		res = rt_rule_entry->status;
+		goto fail;
+	}
+	IPACMDBG("rt rule hdl=%x with ip-type: %d\n", rt_rule_entry->rt_rule_hdl, data->iptype);
+
+	if (data->iptype == IPA_IP_v4)
+	{
+		dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
+		IPACMDBG("ipv4 wan rt rule hdl1=0x%x\n", dft_rt_rule_hdl[0]);
+	}
+	else
+	{
+		dft_rt_rule_hdl[1 + num_dft_rt] = rt_rule_entry->rt_rule_hdl;
+		IPACMDBG("ipv6 wan rt rule hdl1=0x%x\n", dft_rt_rule_hdl[1 + num_dft_rt]);
+		num_dft_rt++;
+	}
+
+
+fail:
+	free(rt_rule);
+
+	return res;
+}
+
+void IPACM_Wan::event_callback(ipa_cm_event_id event, void *param)
+{
+	int ipa_interface_index;
+
+	switch (event)
+	{
+
+	case IPA_LINK_DOWN_EVENT:
+		{
+			ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_LINK_DOWN_EVENT\n");
+				handle_down_evt();
+				IPACMDBG("ipa_WAN (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+				delete this;
+				return;
+			}
+		}
+		break;
+
+	case IPA_ADDR_ADD_EVENT:
+		{
+			ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				if ((data->iptype != ip_type) && (ip_type != IPA_IP_MAX)) // check not setup before
+				{
+					IPACMDBG("Received IPA_ADDR_ADD_EVENT\n");
+					handle_addr_evt(data);
+				}
+			}
+		}
+		break;
+
+	case IPA_ROUTE_ADD_EVENT:
+		{
+			ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_ROUTE_ADD_EVENT\n");
+				IPACMDBG("ipv4 addr 0x%x\n", data->ipv4_addr);
+				IPACMDBG("ipv4 addr mask 0x%x\n", data->ipv4_addr_mask);
+
+				/* The special below condition is to handle default gateway */
+				if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask))
+				{
+					IPACMDBG("adding routing table\n");
+					handle_route_add_evt(data);
+					IPACM_Wan::wan_up = true;
+					active_v4 = true;
+					config_dft_firewall_rules(IPA_IP_v4);
+				}
+				else if ((data->iptype == IPA_IP_v6) &&
+								 (!data->ipv6_addr[0]) && (!data->ipv6_addr[1]) && (!data->ipv6_addr[2]) && (!data->ipv6_addr[3]))
+				{
+					IPACMDBG("\n get default v6 route (dst:00.00.00.00)\n");
+					IPACMDBG(" IPV6 value: %08x:%08x:%08x:%08x \n",
+									 data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+					handle_route_add_evt(data);
+					active_v6 = true;
+					config_dft_firewall_rules(IPA_IP_v6);
+				}
+			}
+		}
+		break;
+
+	case IPA_ROUTE_DEL_EVENT:
+		{
+			ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_ROUTE_DEL_EVENT\n");
+				if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask))
+				{
+					IPACMDBG("get del default v4 route (dst:0.0.0.0)\n");
+					del_dft_firewall_rules(IPA_IP_v4);
+					handle_route_del_evt(data->iptype);
+					IPACM_Wan::wan_up = false;
+				}
+				else if ((data->iptype == IPA_IP_v6) && (!data->ipv6_addr[0]) && (!data->ipv6_addr[1]) && (!data->ipv6_addr[2]) && (!data->ipv6_addr[3]))
+				{
+					IPACMDBG("get del default v6 route (dst:00.00.00.00)\n");
+					del_dft_firewall_rules(IPA_IP_v6);
+					handle_route_del_evt(data->iptype);
+				}
+			}
+		}
+		break;
+
+	case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+		{
+			ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT\n");
+				IPACMDBG("I'm in the WAN\n");
+				handle_header_add_evt(data->mac_addr);
+			}
+		}
+		break;
+
+	case IPA_SW_ROUTING_ENABLE:
+		IPACMDBG("Received IPA_SW_ROUTING_ENABLE\n");
+		/* handle software routing enable event */
+		handle_software_routing_enable();
+		break;
+
+	case IPA_SW_ROUTING_DISABLE:
+		IPACMDBG("Received IPA_SW_ROUTING_DISABLE\n");
+		/* handle software routing disable event */
+		handle_software_routing_disable();
+		break;
+
+	case IPA_FIREWALL_CHANGE_EVENT:
+		IPACMDBG("Received IPA_FIREWALL_CHANGE_EVENT\n");
+		/* handle software routing enable event */
+		if (active_v4)
+		{
+			del_dft_firewall_rules(IPA_IP_v4);
+			config_dft_firewall_rules(IPA_IP_v4);
+		}
+
+		if (active_v6)
+		{
+			del_dft_firewall_rules(IPA_IP_v6);
+			config_dft_firewall_rules(IPA_IP_v6);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return;
+}
+
+/* wan default route/filter rule configuration */
+int IPACM_Wan::handle_route_add_evt(ipacm_event_data_addr *data)
+{
+
+	/* add default WAN route */
+	struct ipa_ioc_add_rt_rule *rt_rule;
+	struct ipa_rt_rule_add *rt_rule_entry;
+	struct ipa_ioc_get_hdr sRetHeader;
+	uint32_t tx_index;
+	const int NUM = 1;
+	ipacm_cmd_q_data evt_data;
+
+	IPACMDBG(" ip-type:%d\n", data->iptype);
+
+	rt_rule = (struct ipa_ioc_add_rt_rule *)
+		 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+						NUM * sizeof(struct ipa_rt_rule_add));
+
+	if (!rt_rule)
+	{
+		IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+		return IPACM_FAILURE;
+	}
+
+	rt_rule->commit = 1;
+	rt_rule->num_rules = (uint8_t)NUM;
+	rt_rule->ip = data->iptype;
+
+	if (data->iptype == IPA_IP_v4) 
+	{
+		strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name);
+	}
+	else 
+	{
+		strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
+	}
+
+	IPACMDBG(" WAN table created %s \n", rt_rule->rt_tbl_name);
+	rt_rule_entry = &rt_rule->rules[0];
+	rt_rule_entry->at_rear = 1;
+
+	for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+	{
+		if (data->iptype != tx_prop->tx[tx_index].ip)
+		{
+			continue;
+		}
+
+		if (tx_prop->tx[tx_index].hdr_name !=  NULL)
+		{
+			IPACMDBG(" TX- header hdl %s \n", tx_prop->tx[tx_index].hdr_name);
+			memset(&sRetHeader, 0, sizeof(sRetHeader));
+			strncpy(sRetHeader.name,
+							tx_prop->tx[tx_index].hdr_name,
+							sizeof(tx_prop->tx[tx_index].hdr_name));
+			if (false == m_header.GetHeaderHandle(&sRetHeader))
+
+			{
+				IPACMERR("\n ioctl failed\n");
+				free(rt_rule);
+				return IPACM_FAILURE;
+			}
+			rt_rule_entry->rule.hdr_hdl = sRetHeader.hdl;
+		}
+
+		rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+		memcpy(&rt_rule_entry->rule.attrib,
+					 &tx_prop->tx[tx_index].attrib,
+					 sizeof(rt_rule_entry->rule.attrib));
+
+		rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		if (data->iptype == IPA_IP_v4)
+		{
+			rt_rule_entry->rule.attrib.u.v4.dst_addr      = data->ipv4_addr;
+			rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = data->ipv4_addr_mask;
+		}
+		else
+		{
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = data->ipv6_addr_mask[0];
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = data->ipv6_addr_mask[1];
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = data->ipv6_addr_mask[2];
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = data->ipv6_addr_mask[3];
+		}
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			IPACMERR("Routing rule addition failed!\n");
+			free(rt_rule);
+			return IPACM_FAILURE;
+		}
+
+		if (data->iptype == IPA_IP_v4)
+		{
+			wan_route_rule_v4_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
+			IPACMDBG("Got ipv4 wan-route rule hdl:0x%x,tx:%d,ip-type: %d \n",
+							 wan_route_rule_v4_hdl[tx_index],
+							 tx_index,
+							 data->iptype);
+		}
+		else
+		{
+			wan_route_rule_v6_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
+			IPACMDBG("Got ipv6 wan-route rule hdl:0x%x,tx:%d,ip-type: %d \n",
+							 wan_route_rule_v6_hdl[tx_index],
+							 tx_index,
+							 data->iptype);
+		}
+	}
+	free(rt_rule);
+
+	if (data->iptype == IPA_IP_v4)
+	{
+		ipacm_event_iface_up *wanup_data;
+
+		wanup_data =
+			 (ipacm_event_iface_up *)malloc(sizeof(ipacm_event_iface_up));
+		if (wanup_data == NULL)
+		{
+			IPACMERR("Unable to allocate memory\n");
+			return IPACM_FAILURE;
+		}
+
+		memcpy(wanup_data->ifname, dev_name, sizeof(wanup_data->ifname));
+		wanup_data->ipv4_addr = wan_v4_addr;
+		IPACMDBG("Posting IPA_HANDLE_WAN_UP with below information:\n");
+		IPACMDBG("if_name:%s, ipv4_address:0x%x\n",
+						 wanup_data->ifname, wanup_data->ipv4_addr);
+
+		evt_data.event = IPA_HANDLE_WAN_UP;
+		evt_data.evt_data = (void *)wanup_data;
+		IPACM_EvtDispatcher::PostEvt(&evt_data);
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* wan default route/filter rule delete */
+int IPACM_Wan::handle_route_del_evt(ipa_ip_type iptype)
+{
+	uint32_t tx_index;
+	ipacm_cmd_q_data evt_data;
+
+	IPACMDBG("got handle_route_del_evt with ip-family:%d \n", iptype);
+
+	if (((iptype == IPA_IP_v4) && (active_v4 == true)) ||
+			((iptype == IPA_IP_v6) && (active_v6 == true)))
+	{
+
+		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+			if (iptype == IPA_IP_v4)
+			{
+
+				if (m_routing.DeleteRoutingHdl(wan_route_rule_v4_hdl[tx_index], IPA_IP_v4)
+						== false)
+				{
+					IPACMDBG("IP-family:%d, Routing rule(hdl:0x%x) deletion failed with tx_index %d!\n", IPA_IP_v4, wan_route_rule_v4_hdl[tx_index], tx_index);
+					return IPACM_FAILURE;
+				}
+
+			}
+			else
+			{
+				if (m_routing.DeleteRoutingHdl(wan_route_rule_v6_hdl[tx_index], IPA_IP_v6)
+						== false)
+				{
+					IPACMERR("IP-family:%d, Routing rule(hdl:0x%x) deletion failed with tx_index %d!\n", IPA_IP_v6, wan_route_rule_v6_hdl[tx_index], tx_index);
+					return IPACM_FAILURE;
+				}
+			}
+
+		}
+
+		if (iptype == IPA_IP_v4)
+		{
+
+			uint32_t *wan_ip_addr = (uint32_t *)malloc(sizeof(uint32_t));
+			if (wan_ip_addr == NULL)
+			{
+				IPACMERR("unable to allocate memory\n");
+				return IPACM_FAILURE;
+			}
+
+			*wan_ip_addr = wan_v4_addr;
+			evt_data.event = IPA_HANDLE_WAN_DOWN;
+			evt_data.evt_data = (void *)wan_ip_addr;
+			/* Insert IPA_HANDLE_WAN_DOWN to command queue */
+			IPACMDBG("posting IPA_HANDLE_WAN_DOWN for IPv4 \n");
+			IPACM_EvtDispatcher::PostEvt(&evt_data);
+			IPACM_Wan::wan_up = false;
+			active_v4 = false;
+		}
+		else
+		{
+			active_v6 = false;
+		}
+	}
+	else
+	{
+		IPACMDBG(" The default WAN routing rules are deleted already \n");
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* construct complete ethernet header */
+int IPACM_Wan::handle_header_add_evt(uint8_t mac_addr[6])
+{
+	char index[2];
+	struct ipa_ioc_copy_hdr sCopyHeader;
+	struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+	uint32_t tx_index;
+	int len = 0;
+
+	IPACMDBG("construct header\n");
+
+	/* start of add header */
+	for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+	{
+		/* add header to IPA */
+		len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+		pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+		if (!pHeaderDescriptor)
+		{
+			IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+			return IPACM_FAILURE;
+		}
+
+		/* copy partial header */
+		memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+		memcpy(sCopyHeader.name, tx_prop->tx[tx_index].hdr_name,
+					 sizeof(tx_prop->tx[tx_index].hdr_name));
+
+		IPACMDBG("header name: %s\n", sCopyHeader.name);
+		if (false == m_header.CopyHeader(&sCopyHeader))
+		{
+			IPACMERR("ioctl copy header failed\n");
+			free(pHeaderDescriptor);
+			return IPACM_FAILURE;
+		};
+
+		if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+		{
+			IPACMERR("header oversize\n");
+			free(pHeaderDescriptor);
+			return IPACM_FAILURE;
+		}
+		else
+		{
+			memcpy(pHeaderDescriptor->hdr[0].hdr, sCopyHeader.hdr,
+						 sCopyHeader.hdr_len);
+		}
+
+		/* copy client mac_addr to partial header */
+		memcpy(&pHeaderDescriptor->hdr[0].hdr[IPA_WLAN_PARTIAL_HDR_OFFSET], mac_addr,
+					 IPA_MAC_ADDR_SIZE); /* only copy 6 bytes mac-address */
+
+		pHeaderDescriptor->commit = true;
+		pHeaderDescriptor->num_hdrs = 1;
+		sprintf(index, "%d", ipa_if_num);
+		strncpy(pHeaderDescriptor->hdr[0].name, index, sizeof(index));
+		strncat(pHeaderDescriptor->hdr[0].name, IPA_WLAN_PARTIAL_HDR_NAME, sizeof(IPA_WLAN_PARTIAL_HDR_NAME));
+		strncat(pHeaderDescriptor->hdr[0].name, "tx", sizeof("tx"));
+		sprintf(index, "%d", tx_index);
+		strncat(pHeaderDescriptor->hdr[0].name, index, sizeof(index));
+
+		pHeaderDescriptor->hdr[0].hdr_len = sizeof(sCopyHeader.hdr_len);
+		pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+		pHeaderDescriptor->hdr[0].is_partial = false;
+		pHeaderDescriptor->hdr[0].status = -1;
+
+		if (false == m_header.AddHeader(pHeaderDescriptor))
+		{
+			IPACMERR("ioctl add header failed\n");
+			free(pHeaderDescriptor);
+			return IPACM_FAILURE;
+		}
+
+		memcpy(tx_prop->tx[tx_index].hdr_name, pHeaderDescriptor->hdr[0].name,
+					 sizeof(tx_prop->tx[tx_index].hdr_name));
+		IPACMDBG("add full header name: %s (%x)\n", tx_prop->tx[tx_index].hdr_name, pHeaderDescriptor->hdr[0].hdr_hdl);
+
+
+		free(pHeaderDescriptor);
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/* configure the initial firewall filter rules */
+int IPACM_Wan::config_dft_firewall_rules(ipa_ip_type iptype)
+{
+	struct ipa_flt_rule_add flt_rule_entry;
+	int i, rule_v4 = 0, rule_v6 = 0;
+
+	IPACMDBG("ip-family: %d; \n", iptype);
+	memset(&firewall_config, 0, sizeof(firewall_config));
+	strncpy(firewall_config.firewall_config_file, "/etc/mobileap_firewall.xml", sizeof(firewall_config.firewall_config_file));
+
+	if (firewall_config.firewall_config_file)
+	{
+		IPACMDBG("Firewall XML file is %s \n", firewall_config.firewall_config_file);
+		if (IPACM_SUCCESS == IPACM_read_firewall_xml(firewall_config.firewall_config_file, &firewall_config))
+		{
+			IPACMDBG("QCMAP Firewall XML read OK \n");
+		}
+		else
+		{
+			IPACMERR("QCMAP Firewall XML read failed \n");
+			return IPACM_FAILURE;
+		}
+	}
+	else
+	{
+		IPACMERR("No firewall xml mentioned \n");
+		return IPACM_FAILURE;
+	}
+
+	/* find the number of v4/v6 firewall rules */
+	for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+	{
+		if (firewall_config.extd_firewall_entries[i].ip_vsn == 4)
+		{
+			rule_v4++;
+		}
+		else
+		{
+			rule_v6++;
+		}
+	}
+
+	IPACMDBG("firewall rule v4:%d v6:%d total:%d\n", rule_v4, rule_v6, firewall_config.num_extd_firewall_entries);
+
+	/* construct ipa_ioc_add_flt_rule with N firewall rules */
+	ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+	if (iptype == IPA_IP_v4)
+	{
+		if (rule_v4 == 0)
+		{
+			m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+				 calloc(1,
+								sizeof(struct ipa_ioc_add_flt_rule) +
+								1 * sizeof(struct ipa_flt_rule_add));
+
+			if (!m_pFilteringTable)
+			{
+				IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+				return IPACM_FAILURE;
+			}
+			m_pFilteringTable->commit = 1;
+			m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+			m_pFilteringTable->global = false;
+			m_pFilteringTable->ip = IPA_IP_v4;
+			m_pFilteringTable->num_rules = (uint8_t)1;
+
+			memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+			if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+			{
+				IPACMERR("m_routing.GetRoutingTable(rt_tbl_lan_v4) Failed.\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+
+			flt_rule_entry.at_rear = true;
+			flt_rule_entry.flt_rule_hdl = -1;
+			flt_rule_entry.status = -1;
+
+			flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+			memcpy(&flt_rule_entry.rule.attrib,
+						 &rx_prop->rx[0].attrib,
+						 sizeof(struct ipa_rule_attrib));
+			flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+			flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+			memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+			if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+			{
+				IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+			}
+
+			/* copy filter hdls */
+			dft_wan_fl_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+			free(m_pFilteringTable);
+		}
+		else
+		{
+			m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+				 calloc(1,
+								sizeof(struct ipa_ioc_add_flt_rule) +
+								1 * sizeof(struct ipa_flt_rule_add)
+								);
+
+			if (m_pFilteringTable == NULL)
+			{
+				IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+				return IPACM_FAILURE;
+			}
+
+			m_pFilteringTable->commit = 1;
+			m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+			m_pFilteringTable->global = false;
+			m_pFilteringTable->ip = IPA_IP_v4;
+			m_pFilteringTable->num_rules = (uint8_t)1;
+
+			IPACMDBG("Retreiving Routing handle for routing table name:%s\n",
+							 IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+			if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+			{
+				IPACMERR("m_routing.GetRoutingTable(&rt_tbl_lan_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_lan_v4);
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+			IPACMDBG("Routing handle for wan routing table:0x%x\n", IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl);
+
+			rule_v4 = 0;
+			for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+			{
+				if (firewall_config.extd_firewall_entries[i].ip_vsn == 4)
+				{
+					memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+					flt_rule_entry.at_rear = true;
+					flt_rule_entry.flt_rule_hdl = -1;
+					flt_rule_entry.status = -1;
+					flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION; //Matched the firewall rule, go exception
+					flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+
+					memcpy(&flt_rule_entry.rule.attrib,
+								 &firewall_config.extd_firewall_entries[i].attrib,
+								 sizeof(struct ipa_rule_attrib));
+
+					IPACMDBG("rx property attrib mask: 0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
+					flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+					flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+					flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+					/* check if the rule is define as TCP_UDP, split into 2 rules, 1 for TCP and 1 UDP */
+					if (firewall_config.extd_firewall_entries[i].attrib.u.v4.protocol
+							== IPACM_FIREWALL_IPPROTO_TCP_UDP)
+					{
+						/* insert TCP rule*/
+						flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_TCP;
+						memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+						IPACMDBG("Filter rule attrib mask: 0x%x\n",
+										 m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+						if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+						{
+							IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+							free(m_pFilteringTable);
+							return IPACM_FAILURE;
+						}
+						else
+						{
+							/* save v4 firewall filter rule handler */
+							IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n",
+											 m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
+											 m_pFilteringTable->rules[rule_v4].status);
+							firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
+							num_firewall_v4++;
+							rule_v4++;
+						}
+
+						/* insert UDP rule*/
+						flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_UDP;
+						memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+						IPACMDBG("Filter rule attrib mask: 0x%x\n",
+										 m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+						if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+						{
+							IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+							free(m_pFilteringTable);
+							return IPACM_FAILURE;
+						}
+						else
+						{
+							/* save v4 firewall filter rule handler */
+							IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n",
+											 m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
+											 m_pFilteringTable->rules[rule_v4].status);
+							firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
+							num_firewall_v4++;
+							rule_v4++;
+						}
+					}
+					else
+					{
+						memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+						IPACMDBG("Filter rule attrib mask: 0x%x\n",
+										 m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+						if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+						{
+							IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+							free(m_pFilteringTable);
+							return IPACM_FAILURE;
+						}
+						else
+						{
+							/* save v4 firewall filter rule handler */
+							IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n",
+											 m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
+											 m_pFilteringTable->rules[rule_v4].status);
+							firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
+							num_firewall_v4++;
+							rule_v4++;
+						}
+					}
+				}
+			} /* end of firewall ipv4 filter rule add for loop*/
+
+			/* configure default filter rule */
+			memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+			flt_rule_entry.at_rear = true;
+			flt_rule_entry.flt_rule_hdl = -1;
+			flt_rule_entry.status = -1;
+
+			flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+			memcpy(&flt_rule_entry.rule.attrib,
+						 &rx_prop->rx[0].attrib,
+						 sizeof(struct ipa_rule_attrib));
+			flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+			flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+			memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+			IPACMDBG("Filter rule attrib mask: 0x%x\n",
+							 m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+			if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+			{
+				IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+			}
+
+			/* copy filter hdls */
+			dft_wan_fl_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+			free(m_pFilteringTable);
+		}
+
+	}
+	else
+	{
+		if (rule_v6 == 0)
+		{
+			m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+				 calloc(1,
+								sizeof(struct ipa_ioc_add_flt_rule) +
+								1 * sizeof(struct ipa_flt_rule_add));
+
+
+			if (!m_pFilteringTable)
+			{
+				IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+				return IPACM_FAILURE;
+			}
+			m_pFilteringTable->commit = 1;
+			m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+			m_pFilteringTable->global = false;
+			m_pFilteringTable->ip = IPA_IP_v6;
+			m_pFilteringTable->num_rules = (uint8_t)1;
+
+			memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+			if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6))
+			{
+				IPACMERR("m_routing.GetRoutingTable(rt_tbl_v6) Failed.\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+
+			flt_rule_entry.at_rear = true;
+			flt_rule_entry.flt_rule_hdl = -1;
+			flt_rule_entry.status = -1;
+			flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
+			memcpy(&flt_rule_entry.rule.attrib,
+						 &rx_prop->rx[0].attrib,
+						 sizeof(struct ipa_rule_attrib));
+			flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+			memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+			if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+			{
+				IPACMERR("Error Adding Filtering rules, aborting...\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+			}
+
+			/* copy filter hdls */
+			dft_wan_fl_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+			free(m_pFilteringTable);
+		}
+		else
+		{
+			m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+				 calloc(1,
+								sizeof(struct ipa_ioc_add_flt_rule) +
+								1 * sizeof(struct ipa_flt_rule_add)
+								);
+
+			if (!m_pFilteringTable)
+			{
+				IPACMDBG("Error Locate ipa_flt_rule_add memory...\n");
+				return IPACM_FAILURE;
+			}
+			m_pFilteringTable->commit = 1;
+			m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+			m_pFilteringTable->global = false;
+			m_pFilteringTable->ip = IPA_IP_v4;
+			m_pFilteringTable->num_rules = (uint8_t)1;
+
+			if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6))
+			{
+				IPACMERR("m_routing.GetRoutingTable(rt_tbl_v6) Failed.\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+
+			rule_v6 = 0;
+			for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+			{
+				if (firewall_config.extd_firewall_entries[i].ip_vsn == 6)
+				{
+					memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+					flt_rule_entry.at_rear = true;
+					flt_rule_entry.flt_rule_hdl = -1;
+					flt_rule_entry.status = -1;
+
+					flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+					flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
+					memcpy(&flt_rule_entry.rule.attrib,
+								 &firewall_config.extd_firewall_entries[i].attrib,
+								 sizeof(struct ipa_rule_attrib));
+					flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+					flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+					flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+					/* check if the rule is define as TCP/UDP */
+					if (firewall_config.extd_firewall_entries[i].attrib.u.v6.next_hdr == IPACM_FIREWALL_IPPROTO_TCP_UDP)
+					{
+						/* insert TCP rule*/
+						flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_TCP;
+						memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+						if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+						{
+							IPACMERR("Error Adding Filtering rules, aborting...\n");
+							free(m_pFilteringTable);
+							return IPACM_FAILURE;
+						}
+						else
+						{
+							/* save v4 firewall filter rule handler */
+							IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+							firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
+							num_firewall_v6++;
+							rule_v6++;
+						}
+
+						/* insert UDP rule*/
+						flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_UDP;
+						memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+						if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+						{
+							IPACMERR("Error Adding Filtering rules, aborting...\n");
+							free(m_pFilteringTable);
+							return IPACM_FAILURE;
+						}
+						else
+						{
+							/* save v6 firewall filter rule handler */
+							IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+							firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
+							num_firewall_v6++;
+							rule_v6++;
+						}
+					}
+					else
+					{
+
+						memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+						if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+						{
+							IPACMERR("Error Adding Filtering rules, aborting...\n");
+							free(m_pFilteringTable);
+							return IPACM_FAILURE;
+						}
+						else
+						{
+							/* save v6 firewall filter rule handler */
+							IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+							firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
+							num_firewall_v6++;
+							rule_v6++;
+						}
+					}
+				}
+			} /* end of firewall ipv6 filter rule add for loop*/
+
+			/* setup default wan filter rule */
+			memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+			flt_rule_entry.at_rear = true;
+			flt_rule_entry.flt_rule_hdl = -1;
+			flt_rule_entry.status = -1;
+			flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+			memcpy(&flt_rule_entry.rule.attrib,
+						 &rx_prop->rx[0].attrib,
+						 sizeof(struct ipa_rule_attrib));
+			flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+			memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+			if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+			{
+				IPACMERR("Error Adding Filtering rules, aborting...\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+			}
+			else
+			{
+				IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+			}
+			/* copy filter hdls*/
+			dft_wan_fl_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+			free(m_pFilteringTable);
+		}
+	}
+	return IPACM_SUCCESS;
+}
+
+
+
+/*handle wan-iface down event */
+int IPACM_Wan::handle_down_evt()
+{
+	int res = IPACM_SUCCESS;
+	int i;
+
+	IPACMDBG(" wan handle_down_evt \n");
+
+	/* no iface address up, directly close iface*/
+	if (ip_type == IPACM_IP_NULL)
+	{
+		goto fail;
+	}
+
+	/* make sure default routing rules and firewall rules are deleted*/
+	if (ip_type != IPA_IP_v6)
+	{
+		del_dft_firewall_rules(IPA_IP_v4);
+		handle_route_del_evt(IPA_IP_v4);
+	}
+
+	if (ip_type != IPA_IP_v4)
+	{
+		del_dft_firewall_rules(IPA_IP_v6);
+		handle_route_del_evt(IPA_IP_v6);
+	}
+
+	/* Delete default v4 RT rule */
+	if (ip_type != IPA_IP_v6)
+	{
+		IPACMDBG("Delete default v4 routing rules\n");
+		if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4)
+				== false)
+		{
+			IPACMDBG("Routing rule deletion failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+	}
+
+	/* delete default v6 RT rule */
+	if (ip_type != IPA_IP_v4)
+	{
+		IPACMDBG("Delete default v6 routing rules\n");
+		/* May have multiple ipv6 iface-routing rules*/
+		for (i = 0; i < num_dft_rt; i++)
+		{
+			if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[1 + i], IPA_IP_v6)
+					== false)
+			{
+				IPACMERR("Routing rule deletion failed!\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+		}
+
+		IPACMDBG("finished delete default v6 RT rules\n ");
+	}
+
+	/* check software routing fl rule hdl */
+	if (softwarerouting_act == true)
+	{
+		IPACM_Iface::handle_software_routing_disable();
+		handle_software_routing_disable();
+	}
+
+	/* free filter rule handlers */
+	if (ip_type != IPA_IP_v6)
+	{
+		if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl,
+																				IPA_IP_v4,
+																				IPV4_DEFAULT_FILTERTING_RULES) == false)
+		{
+			IPACMERR("Error Delete Filtering rules, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACMDBG("finished delete default v4 filtering rules\n ");
+	}
+
+
+	if (ip_type != IPA_IP_v4)
+	{
+		if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl,
+																				IPA_IP_v6,
+																				IPV6_DEFAULT_FILTERTING_RULES) == false)
+		{
+			IPACMERR("ErrorDeleting Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACMDBG("finished delete default v6 filtering rules\n ");
+	}
+
+fail:
+	free(tx_prop);
+	free(rx_prop);
+	free(iface_query);
+
+	return res;
+}
+
+/*clean firewall filter rules */
+int IPACM_Wan::del_dft_firewall_rules(ipa_ip_type iptype)
+{
+	/* free v4 firewall filter rule */
+	if ((iptype == IPA_IP_v4) && (active_v4 == true))
+	{
+		if (num_firewall_v4 != 0)
+		{
+			if (m_filtering.DeleteFilteringHdls(firewall_hdl_v4,
+																					IPA_IP_v4, num_firewall_v4) == false)
+			{
+				IPACMERR("Error Deleting Filtering rules, aborting...\n");
+				return IPACM_FAILURE;
+			}
+		}
+		else
+		{
+			IPACMDBG("No ipv4 firewall rules, no need deleted\n");
+		}
+
+		if (m_filtering.DeleteFilteringHdls(dft_wan_fl_hdl,
+																				IPA_IP_v4, 1) == false)
+		{
+			IPACMERR("Error Deleting Filtering rules, aborting...\n");
+			return IPACM_FAILURE;
+		}
+
+		num_firewall_v4 = 0;
+	}
+
+	/* free v6 firewall filter rule */
+	if ((iptype == IPA_IP_v6) && (active_v6 == true))
+	{
+		if (num_firewall_v6 != 0)
+		{
+			if (m_filtering.DeleteFilteringHdls(firewall_hdl_v6,
+																					IPA_IP_v6, num_firewall_v6) == false)
+			{
+				IPACMERR("Error Deleting Filtering rules, aborting...\n");
+				return IPACM_FAILURE;
+			}
+		}
+		else
+		{
+			IPACMDBG("No ipv6 firewall rules, no need deleted\n");
+		}
+
+		if (m_filtering.DeleteFilteringHdls(&dft_wan_fl_hdl[1],
+																				IPA_IP_v6, 1) == false)
+		{
+			IPACMERR("Error Deleting Filtering rules, aborting...\n");
+			return IPACM_FAILURE;
+		}
+		num_firewall_v6 = 0;
+	}
+
+	return IPACM_SUCCESS;
+}
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
new file mode 100644
index 0000000..0160406
--- /dev/null
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -0,0 +1,1421 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+* Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above
+	copyright notice, this list of conditions and the following
+	disclaimer in the documentation and/or other materials provided
+	with the distribution.
+* Neither the name of The Linux Foundation nor the names of its
+	contributors may be used to endorse or promote products derived
+	from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+@file
+IPACM_Wlan.cpp
+
+@brief
+This file implements the WLAN iface functionality.
+
+@Author
+Skylar Chang
+
+*/
+
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <IPACM_Wlan.h>
+#include <IPACM_Netlink.h>
+#include <fcntl.h>
+#include <sys/inotify.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Lan.h>
+#include <IPACM_IfaceManager.h>
+
+/* static member to store the number of total wifi clients within all APs*/
+int IPACM_Wlan::total_num_wifi_clients = 0;
+
+IPACM_Wlan::IPACM_Wlan(int iface_index) : IPACM_Lan(iface_index)
+{
+#define WLAN_AMPDU_DEFAULT_FILTER_RULES 3
+
+	num_wifi_client = 0;
+	header_name_count = 0;
+
+	/* one for WAN and two for Soft-routing */
+	wlan_ampdu_flt_rule.num_rules = WLAN_AMPDU_DEFAULT_FILTER_RULES;
+
+	wlan_ampdu_flt_rule.hdl[0] = 0;            /* for WAN */
+	wlan_ampdu_flt_rule.ip[0] = IPA_IP_v4;     /* for WAN */
+
+	wlan_ampdu_flt_rule.hdl[1] = 0;           /* for Soft-routing */
+	wlan_ampdu_flt_rule.ip[1] = IPA_IP_v4;    /* for Soft-routing */
+
+	wlan_ampdu_flt_rule.hdl[2] = 0;            /* for Soft-routing */
+	wlan_ampdu_flt_rule.ip[2] = IPA_IP_v6;     /* for Soft-routing */
+
+	wlan_client_len = (sizeof(ipa_wlan_client)) + (iface_query->num_tx_props * sizeof(wlan_client_rt_hdl));
+	wlan_client = (ipa_wlan_client *)calloc(IPA_MAX_NUM_WIFI_CLIENTS, wlan_client_len);
+	if (wlan_client == NULL)
+	{
+		IPACMERR("unable to allocate memory\n");
+		return;
+	}
+
+	IPACMDBG("index:%d constructor: Tx properties:%d\n", iface_index, iface_query->num_tx_props);
+	return;
+}
+
+
+IPACM_Wlan::~IPACM_Wlan()
+{
+	IPACM_EvtDispatcher::deregistr(this);
+	IPACM_IfaceManager::deregistr(this);
+	return;
+}
+
+void IPACM_Wlan::event_callback(ipa_cm_event_id event, void *param)
+{
+	int ipa_interface_index;
+
+	switch (event)
+	{
+
+	case IPA_LINK_DOWN_EVENT:
+		{
+			ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_LINK_DOWN_EVENT\n");
+				handle_down_evt();
+				IPACMDBG("ipa_WLAN (%s):ipa_index (%d) instance close \n",
+								 IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+				delete this;
+				return;
+			}
+		}
+		break;
+
+	case IPA_ADDR_ADD_EVENT:
+		{
+			ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+			if (ipa_interface_index == ipa_if_num)
+			{
+				if ((data->iptype != ip_type) && (ip_type != IPA_IP_MAX)) // check not setup before
+				{
+					/* Post event to NAT */
+					if (data->iptype == IPA_IP_v4)
+					{
+						ipacm_cmd_q_data evt_data;
+						ipacm_event_iface_up *info;
+
+						info = (ipacm_event_iface_up *)
+							 malloc(sizeof(ipacm_event_iface_up));
+						if (info == NULL)
+						{
+							IPACMERR("Unable to allocate memory\n");
+							return;
+						}
+
+						memcpy(info->ifname, dev_name, IF_NAME_LEN);
+						info->ipv4_addr = data->ipv4_addr;
+						info->addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[0].subnet_mask;
+
+						evt_data.event = IPA_HANDLE_WLAN_UP;
+						evt_data.evt_data = (void *)info;
+
+						/* Insert IPA_HANDLE_WLAN_UP to command queue */
+						IPACMDBG("posting IPA_HANDLE_WLAN_UP for IPv4 with below information\n");
+						IPACMDBG("IPv4 address:0x%x, IPv4 address mask:0x%x\n",
+										 info->ipv4_addr, info->addr_mask);
+						IPACM_EvtDispatcher::PostEvt(&evt_data);
+					}
+
+					IPACM_Lan::handle_addr_evt(data);
+					handle_addr_evt(data);
+
+					IPACM_Lan::handle_private_subnet(data->iptype);
+					handle_private_subnet(data->iptype);
+
+					if (IPACM_Wan::isWanUP() && (data->iptype == IPA_IP_v4))
+					{
+						IPACM_Lan::handle_wan_up();
+						handle_wan_up();
+					}
+
+					IPACMDBG("posting IPA_HANDLE_WLAN_UP:Finished checking wan_up\n");
+				}
+			}
+		}
+		break;
+
+	case IPA_HANDLE_WAN_UP:
+		IPACMDBG("Received IPA_HANDLE_WAN_UP event\n");
+		IPACM_Lan::handle_wan_up();
+		handle_wan_up();
+		break;
+
+	case IPA_HANDLE_WAN_DOWN:
+		IPACMDBG("Received IPA_HANDLE_WAN_DOWN event\n");
+		IPACM_Lan::handle_wan_down();
+		handle_wan_down();
+		break;
+
+	case IPA_WLAN_CLIENT_ADD_EVENT:
+		{
+			ipacm_event_data_mac *data = (ipacm_event_data_mac *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_WLAN_CLIENT_ADD_EVENT\n");
+				handle_wlan_client_init(data->mac_addr);
+			}
+		}
+		break;
+
+	case IPA_WLAN_CLIENT_DEL_EVENT:
+		{
+			ipacm_event_data_mac *data = (ipacm_event_data_mac *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_WLAN_CLIENT_DEL_EVENT\n");
+				handle_wlan_client_down_evt(data->mac_addr);
+			}
+		}
+		break;
+
+	case IPA_WLAN_CLIENT_POWER_SAVE_EVENT:
+		{
+			ipacm_event_data_mac *data = (ipacm_event_data_mac *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_WLAN_CLIENT_POWER_SAVE_EVENT\n");
+				handle_wlan_client_pwrsave(data->mac_addr);
+			}
+		}
+		break;
+
+	case IPA_WLAN_CLIENT_RECOVER_EVENT:
+		{
+			ipacm_event_data_mac *data = (ipacm_event_data_mac *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_WLAN_CLIENT_RECOVER_EVENT\n");
+				if (ip_type != IPA_IP_v6) /* for ipv4 */
+				{
+					handle_wlan_client_route_rule(data->mac_addr, IPA_IP_v4);
+				}
+
+				if (ip_type != IPA_IP_v4) /* for ipv6 */
+				{
+					handle_wlan_client_route_rule(data->mac_addr, IPA_IP_v6);
+				}
+			}
+		}
+		break;
+
+	case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+		{
+			ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
+			{
+				IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT\n");
+				if (handle_wlan_client_ipaddr(data) == IPACM_FAILURE)
+				{
+					return;
+				}
+				handle_wlan_client_route_rule(data->mac_addr, data->iptype);
+			}
+		}
+		break;
+
+		/* handle software routing enable event*/
+	case IPA_SW_ROUTING_ENABLE:
+		IPACMDBG("Received IPA_SW_ROUTING_ENABLE\n");
+		IPACM_Iface::handle_software_routing_enable();
+		handle_software_routing_enable();
+		break;
+
+		/* handle software routing disable event*/
+	case IPA_SW_ROUTING_DISABLE:
+		IPACMDBG("Received IPA_SW_ROUTING_DISABLE\n");
+		IPACM_Iface::handle_software_routing_disable();
+		handle_software_routing_disable();
+		break;
+
+	default:
+		break;
+	}
+	return;
+}
+
+/* handle wifi client initial,copy all partial headers (tx property) */
+int IPACM_Wlan::handle_wlan_client_init(uint8_t *mac_addr)
+{
+
+#define WLAN_IFACE_INDEX_LEN 2
+
+	int res = IPACM_SUCCESS, len = 0;
+	char index[WLAN_IFACE_INDEX_LEN];
+	struct ipa_ioc_copy_hdr sCopyHeader;
+	struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+
+	/* start of adding header */
+	if ((num_wifi_client >= IPA_MAX_NUM_WIFI_CLIENTS) ||
+			(IPACM_Wlan::total_num_wifi_clients >= IPA_MAX_NUM_WIFI_CLIENTS))
+	{
+		IPACMERR("Reached maximum number of wlan clients\n");
+		return IPACM_FAILURE;
+	}
+
+	IPACMDBG("Wifi client number: %d\n", num_wifi_client);
+
+	IPACMDBG("Received Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 mac_addr[0], mac_addr[1], mac_addr[2],
+					 mac_addr[3], mac_addr[4], mac_addr[5]);
+
+	memcpy(get_client_memptr(wlan_client, num_wifi_client)->mac,
+				 mac_addr,
+				 sizeof(get_client_memptr(wlan_client, num_wifi_client)->mac));
+
+	IPACMDBG("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 get_client_memptr(wlan_client, num_wifi_client)->mac[0],
+					 get_client_memptr(wlan_client, num_wifi_client)->mac[1],
+					 get_client_memptr(wlan_client, num_wifi_client)->mac[2],
+					 get_client_memptr(wlan_client, num_wifi_client)->mac[3],
+					 get_client_memptr(wlan_client, num_wifi_client)->mac[4],
+					 get_client_memptr(wlan_client, num_wifi_client)->mac[5]);
+
+	/* add header to IPA */
+	len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+	pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+	if (pHeaderDescriptor == NULL)
+	{
+		IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+		return IPACM_FAILURE;
+	}
+
+	/* copy partial header */
+	memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+	memcpy(sCopyHeader.name,
+				 tx_prop->tx[0].hdr_name,
+				 sizeof(sCopyHeader.name));
+
+	IPACMDBG("header name: %s\n", sCopyHeader.name);
+	if (m_header.CopyHeader(&sCopyHeader) == false)
+	{
+		PERROR("ioctl copy header failed");
+		res = IPACM_FAILURE;
+		goto fail;
+	}
+
+	IPACMDBG("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+	if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+	{
+		IPACMERR("header oversize\n");
+		res = IPACM_FAILURE;
+		goto fail;
+	}
+	else
+	{
+		memcpy(pHeaderDescriptor->hdr[0].hdr,
+					 sCopyHeader.hdr,
+					 sCopyHeader.hdr_len);
+	}
+
+	/* copy client mac_addr to partial header */
+	memcpy(&pHeaderDescriptor->hdr[0].hdr[IPA_WLAN_PARTIAL_HDR_OFFSET],
+				 get_client_memptr(wlan_client, num_wifi_client)->mac,
+				 IPA_MAC_ADDR_SIZE);
+
+	pHeaderDescriptor->commit = true;
+	pHeaderDescriptor->num_hdrs = 1;
+
+	memset(pHeaderDescriptor->hdr[0].name, 0,
+				 sizeof(pHeaderDescriptor->hdr[0].name));
+
+	sprintf(index, "%d", ipa_if_num);
+	strncpy(pHeaderDescriptor->hdr[0].name, index, sizeof(index));
+
+	strncat(pHeaderDescriptor->hdr[0].name,
+					IPA_WLAN_PARTIAL_HDR_NAME,
+					sizeof(IPA_WLAN_PARTIAL_HDR_NAME));
+
+	sprintf(index, "%d", header_name_count);
+	strncat(pHeaderDescriptor->hdr[0].name, index, sizeof(index));
+
+	pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+	pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+	pHeaderDescriptor->hdr[0].is_partial = 0;
+	pHeaderDescriptor->hdr[0].status = -1;
+
+	if (m_header.AddHeader(pHeaderDescriptor) == false ||
+			pHeaderDescriptor->hdr[0].status != 0)
+	{
+		IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+		res = IPACM_FAILURE;
+		goto fail;
+	}
+
+	get_client_memptr(wlan_client, num_wifi_client)->hdr_hdl = pHeaderDescriptor->hdr[0].hdr_hdl;
+	IPACMDBG("client(%d) full header name:%s header handle:(0x%x)\n",
+					 num_wifi_client,
+					 pHeaderDescriptor->hdr[0].name,
+					 get_client_memptr(wlan_client, num_wifi_client)->hdr_hdl);
+	/* initialize wifi client*/
+	get_client_memptr(wlan_client, num_wifi_client)->route_rule_set_v4 = false;
+	get_client_memptr(wlan_client, num_wifi_client)->route_rule_set_v6 = false;
+	get_client_memptr(wlan_client, num_wifi_client)->ipv4_set = false;
+	get_client_memptr(wlan_client, num_wifi_client)->ipv6_set = false;
+
+	num_wifi_client++;
+	header_name_count++; //keep increasing header_name_count
+	IPACM_Wlan::total_num_wifi_clients++;
+	res = IPACM_SUCCESS;
+
+	IPACMDBG("Wifi client number: %d\n", num_wifi_client);
+
+fail:
+	free(pHeaderDescriptor);
+
+	return res;
+}
+
+/*handle wifi client */
+int IPACM_Wlan::handle_wlan_client_ipaddr(ipacm_event_data_all *data)
+{
+	int clnt_indx;
+
+	IPACMDBG("number of wifi clients: %d\n", num_wifi_client);
+	IPACMDBG(" event MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 data->mac_addr[0],
+					 data->mac_addr[1],
+					 data->mac_addr[2],
+					 data->mac_addr[3],
+					 data->mac_addr[4],
+					 data->mac_addr[5]);
+
+	clnt_indx = get_wlan_client_index(data->mac_addr);
+	if (clnt_indx == IPACM_INVALID_INDEX)
+	{
+		if (clnt_indx == IPACM_INVALID_INDEX)
+		{
+			IPACMDBG("wlan client not found/attached \n");
+			return IPACM_FAILURE;
+		}
+	}
+
+	IPACMDBG("Ip type received %d\n", data->iptype);
+	if (data->iptype == IPA_IP_v4)
+	{
+		IPACMDBG("Ipv4 with ipv4 address: 0x%x\n", data->ipv4_addr);
+		if (data->ipv4_addr != 0) /* not 0.0.0.0 */
+		{
+			if (get_client_memptr(wlan_client, clnt_indx)->ipv4_set == false)
+			{
+				get_client_memptr(wlan_client, clnt_indx)->v4_addr = data->ipv4_addr;
+				get_client_memptr(wlan_client, clnt_indx)->ipv4_set = true;
+			}
+			else
+			{
+				IPACMDBG("Already setup ipv4 addr for client:%d\n", clnt_indx);
+			}
+		}
+	}
+	else
+	{
+		if ((data->ipv6_addr[0] != 0) || (data->ipv6_addr[1] != 0) ||
+				(data->ipv6_addr[2] != 0) || (data->ipv6_addr[3] || 0)) /* check if all 0 not valid ipv6 address */
+		{
+			if (get_client_memptr(wlan_client, clnt_indx)->ipv6_set == false)
+			{
+				get_client_memptr(wlan_client, clnt_indx)->v6_addr[0] = data->ipv6_addr[0];
+				get_client_memptr(wlan_client, clnt_indx)->v6_addr[1] = data->ipv6_addr[1];
+				get_client_memptr(wlan_client, clnt_indx)->v6_addr[2] = data->ipv6_addr[2];
+				get_client_memptr(wlan_client, clnt_indx)->v6_addr[3] = data->ipv6_addr[3];
+				get_client_memptr(wlan_client, clnt_indx)->ipv6_set = true;
+			}
+			else
+			{
+				IPACMDBG("Already setup ipv6 addr for client:%d\n", clnt_indx);
+			}
+		}
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/*handle wifi client routing rule*/
+int IPACM_Wlan::handle_wlan_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype)
+{
+	struct ipa_ioc_add_rt_rule *rt_rule;
+	struct ipa_rt_rule_add *rt_rule_entry;
+	uint32_t tx_index;
+	int wlan_index;
+
+	IPACMDBG("Received mac_addr MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 mac_addr[0], mac_addr[1], mac_addr[2],
+					 mac_addr[3], mac_addr[4], mac_addr[5]);
+
+	wlan_index = get_wlan_client_index(mac_addr);
+	if (wlan_index == IPACM_INVALID_INDEX)
+	{
+		IPACMDBG("wlan client not found/attached \n");
+		return IPACM_SUCCESS;
+	}
+
+	IPACMDBG("wlan client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n", wlan_index, iptype,
+					 get_client_memptr(wlan_client, wlan_index)->ipv4_set,
+					 get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4);
+	/* Add default 4 Qos routing rules if not set yet */
+	if ((iptype == IPA_IP_v4
+			 && get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4 == false
+			 && get_client_memptr(wlan_client, wlan_index)->ipv4_set == true)
+			|| (iptype == IPA_IP_v6
+					&& get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6 == false
+					&& get_client_memptr(wlan_client, wlan_index)->ipv6_set == true))
+	{
+		IPACMDBG("client index(%d):ipv4 address: 0x%x\n", wlan_index, 
+						        get_client_memptr(wlan_client, wlan_index)->v4_addr);
+
+		IPACMDBG("client(%d): header handle:(0x%x), num of rules: %d\n",
+						 wlan_index,
+						 get_client_memptr(wlan_client, wlan_index)->hdr_hdl,
+						 iface_query->num_tx_props);
+
+
+		rt_rule = (struct ipa_ioc_add_rt_rule *)
+			 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+							(iface_query->num_tx_props * sizeof(struct ipa_rt_rule_add)));
+
+		if (rt_rule == NULL)
+		{
+			PERROR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		rt_rule->commit = 1;
+		rt_rule->num_rules = iface_query->num_tx_props;
+		rt_rule->ip = iptype;
+
+		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+			if (iptype == IPA_IP_v4)
+			{
+				strncpy(rt_rule->rt_tbl_name,
+								IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name,
+								sizeof(rt_rule->rt_tbl_name));
+			}
+			else
+			{
+				strncpy(rt_rule->rt_tbl_name,
+								IPACM_Iface::ipacmcfg->rt_tbl_v6.name,
+								sizeof(rt_rule->rt_tbl_name));
+			}
+
+			rt_rule_entry = &rt_rule->rules[tx_index];
+			rt_rule_entry->at_rear = 0;
+			rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+			rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl;
+
+			memcpy(&rt_rule_entry->rule.attrib,
+						 &tx_prop->tx[tx_index].attrib,
+						 sizeof(rt_rule_entry->rule.attrib));
+			rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+
+			if (iptype == IPA_IP_v4)
+			{
+				rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(wlan_client, wlan_index)->v4_addr;
+				rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+			}
+			else if (iptype == IPA_IP_v6)
+			{
+				rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wlan_client, wlan_index)->v6_addr[0];
+				rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wlan_client, wlan_index)->v6_addr[1];
+				rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wlan_client, wlan_index)->v6_addr[2];
+				rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wlan_client, wlan_index)->v6_addr[3];
+				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+			}
+		} /* end of for loop */
+
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			IPACMERR("Routing rule addition failed!\n");
+			free(rt_rule);
+			return IPACM_FAILURE;
+		}
+
+		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+			if (iptype == IPA_IP_v4)
+			{
+				get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4 =
+					 rt_rule->rules[tx_index].rt_rule_hdl;
+				IPACMDBG("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index, 
+								 get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4, iptype);
+			}
+			else if (iptype == IPA_IP_v6)
+			{
+				get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6 =
+					 rt_rule->rules[tx_index].rt_rule_hdl;
+				IPACMDBG("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index, 
+								 get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6, iptype);
+			}
+		}
+
+		free(rt_rule);
+
+		if (iptype == IPA_IP_v4)
+		{
+			get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4 = true;
+		}
+		else
+		{
+			get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6 = true;
+		}
+	}
+
+	return IPACM_SUCCESS;
+}
+
+/*handle wifi client power-save mode*/
+int IPACM_Wlan::handle_wlan_client_pwrsave(uint8_t *mac_addr)
+{
+	int clt_indx;
+	IPACMDBG("wlan->handle_wlan_client_pwrsave();\n");
+
+	clt_indx = get_wlan_client_index(mac_addr);
+	if (clt_indx == IPACM_INVALID_INDEX)
+	{
+		IPACMDBG("wlan client not attached\n");
+		return IPACM_SUCCESS;
+	}
+
+	/*check if got duplicate power-save mode*/
+	if ((ip_type != IPA_IP_v6 && get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4 == true)
+			|| (ip_type != IPA_IP_v4 && get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 == true))
+	{
+		return delete_default_qos_rtrules(clt_indx);
+	}
+	else
+	{
+		IPACMDBG("wlan client already in power-save mode\n");
+		return IPACM_SUCCESS;
+	}
+}
+
+/*handle wifi client del mode*/
+int IPACM_Wlan::handle_wlan_client_down_evt(uint8_t *mac_addr)
+{
+	int clt_indx;
+	uint32_t tx_index;
+	int num_wifi_client_tmp = num_wifi_client;
+
+	IPACMDBG("total client: %d\n", num_wifi_client_tmp);
+
+	clt_indx = get_wlan_client_index(mac_addr);
+	if (clt_indx == IPACM_INVALID_INDEX)
+	{
+		IPACMDBG("wlan client not attached\n");
+		return IPACM_SUCCESS;
+	}
+
+	if (delete_default_qos_rtrules(clt_indx))
+	{
+		IPACMDBG("unbale to delete default qos route rules\n");
+		return IPACM_FAILURE;
+	}
+
+	/* Delete wlan client header */
+	if (m_header.DeleteHeaderHdl(get_client_memptr(wlan_client, clt_indx)->hdr_hdl)
+			== false)
+	{
+		return IPACM_FAILURE;
+	}
+
+	/* Reset ip_set to 0*/
+	get_client_memptr(wlan_client, clt_indx)->ipv4_set = false;
+	get_client_memptr(wlan_client, clt_indx)->ipv6_set = false;
+	get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4 = false;
+	get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 = false;
+
+	for (; clt_indx < num_wifi_client_tmp - 1; clt_indx++)
+	{
+		memcpy(get_client_memptr(wlan_client, clt_indx)->mac,
+					 get_client_memptr(wlan_client, (clt_indx + 1))->mac,
+					 sizeof(get_client_memptr(wlan_client, clt_indx)->mac));
+
+		get_client_memptr(wlan_client, clt_indx)->hdr_hdl = get_client_memptr(wlan_client, (clt_indx + 1))->hdr_hdl;
+		get_client_memptr(wlan_client, clt_indx)->v4_addr = get_client_memptr(wlan_client, (clt_indx + 1))->v4_addr;
+
+		get_client_memptr(wlan_client, clt_indx)->ipv4_set = get_client_memptr(wlan_client, (clt_indx + 1))->ipv4_set;
+		get_client_memptr(wlan_client, clt_indx)->ipv6_set = get_client_memptr(wlan_client, (clt_indx + 1))->ipv6_set;
+		get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4 = get_client_memptr(wlan_client, (clt_indx + 1))->route_rule_set_v4;
+		get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 = get_client_memptr(wlan_client, (clt_indx + 1))->route_rule_set_v6;
+
+		get_client_memptr(wlan_client, clt_indx)->v6_addr[0] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[0];
+		get_client_memptr(wlan_client, clt_indx)->v6_addr[1] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[1];
+		get_client_memptr(wlan_client, clt_indx)->v6_addr[2] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[2];
+		get_client_memptr(wlan_client, clt_indx)->v6_addr[3] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[3];
+
+		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+			get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4 =
+				 get_client_memptr(wlan_client, (clt_indx + 1))->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4;
+
+			get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6 =
+				 get_client_memptr(wlan_client, (clt_indx + 1))->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6;
+		}
+	}
+
+	IPACMDBG(" %d wifi client deleted successfully \n", num_wifi_client);
+	num_wifi_client = num_wifi_client - 1;
+	IPACM_Wlan::total_num_wifi_clients = IPACM_Wlan::total_num_wifi_clients - 1;
+	IPACMDBG(" Number of wifi client: %d\n", num_wifi_client);
+
+	return IPACM_SUCCESS;
+}
+
+/* duplicate ampdu filter rules for wan_up event */
+int IPACM_Wlan::handle_wan_up(void)
+{
+	struct ipa_flt_rule_add flt_rule_entry;
+	IPACMDBG("Wlan->handle_wan_up(); \n");
+
+	ipa_ioc_add_flt_rule *m_pFilteringTable;
+	m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+		 calloc(1,
+						sizeof(struct ipa_ioc_add_flt_rule) +
+						1 * sizeof(struct ipa_flt_rule_add)
+						);
+	if (!m_pFilteringTable)
+	{
+		PERROR("Error Locate ipa_flt_rule_add memory...\n");
+		return IPACM_FAILURE;
+	}
+
+	m_pFilteringTable->commit = 1;
+	m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+	m_pFilteringTable->global = false;
+	m_pFilteringTable->ip = IPA_IP_v4;
+	m_pFilteringTable->num_rules = (uint8_t)1;
+
+	if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4))
+	{
+		IPACMDBG("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_wan_v4);
+		return IPACM_FAILURE;
+	}
+
+	memset(&flt_rule_entry, 0, sizeof(ipa_flt_rule_add));
+	flt_rule_entry.at_rear = true;
+	flt_rule_entry.flt_rule_hdl = -1;
+	flt_rule_entry.status = -1;
+	flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT; //IPA_PASS_TO_ROUTING
+	flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl;
+	memcpy(&flt_rule_entry.rule.attrib,
+				 &rx_prop->rx[0].attrib,
+				 sizeof(flt_rule_entry.rule.attrib));
+
+	/* Match-all rule */
+	flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+	flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+	flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+	memcpy(&m_pFilteringTable->rules[0], &flt_rule_entry, sizeof(flt_rule_entry));
+	if (m_filtering.AddFilteringRule(m_pFilteringTable) == false)
+	{
+		IPACMDBG("Error Adding Filtering Rule, aborting...\n");
+		perror("Wlan: Unable to add filtering table");
+		free(m_pFilteringTable);
+		return IPACM_FAILURE;
+	}
+	else
+	{
+		IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+	}
+
+	/* copy filter hdls  */
+	wlan_ampdu_flt_rule.hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+	free(m_pFilteringTable);
+
+	return IPACM_SUCCESS;
+}
+
+
+/*delete ampdu filter rules for wan_down event*/
+int IPACM_Wlan::handle_wan_down(void)
+{
+	IPACMDBG("\n");
+
+	if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[0],
+																			IPA_IP_v4, 1) == false)
+	{
+		return IPACM_FAILURE;
+	}
+	wlan_ampdu_flt_rule.hdl[0] = 0;
+
+	return IPACM_SUCCESS;
+}
+
+/*duplicate ampdu filter rules for software_routing event*/
+int IPACM_Wlan::handle_software_routing_enable(void)
+{
+
+	struct ipa_flt_rule_add flt_rule_entry;
+	ipa_ioc_add_flt_rule *m_pFilteringTable;
+	int res = IPACM_SUCCESS;
+
+	IPACMDBG("\n");
+
+	m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+		 calloc(1,
+						sizeof(struct ipa_ioc_add_flt_rule) +
+						1 * sizeof(struct ipa_flt_rule_add)
+						);
+
+	if (!m_pFilteringTable)
+	{
+		PERROR("Error Locate ipa_ioc_add_flt_rule memory...\n");
+		return IPACM_FAILURE;
+	}
+
+	m_pFilteringTable->commit = 1;
+	m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+	m_pFilteringTable->global = false;
+	m_pFilteringTable->num_rules = (uint8_t)1;
+
+
+	/* Configuring Software_routing Filtering Rule */
+	memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+	flt_rule_entry.at_rear = false;
+	flt_rule_entry.flt_rule_hdl = -1;
+	flt_rule_entry.status = -1;
+	flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+	memcpy(&flt_rule_entry.rule.attrib,
+				 &rx_prop->rx[0].attrib,
+				 sizeof(flt_rule_entry.rule.attrib));
+
+	memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+
+/* check iface is v4 or v6 or both*/
+	if (ip_type == IPA_IP_MAX)
+	{
+		/* handle v4 */
+		m_pFilteringTable->ip = IPA_IP_v4;
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			PERROR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (m_pFilteringTable->rules[0].status)
+		{
+			IPACMDBG("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+		/* copy filter hdls */
+		wlan_ampdu_flt_rule.hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+
+
+
+		/* handle v6*/
+		m_pFilteringTable->ip = IPA_IP_v6;
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			PERROR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (m_pFilteringTable->rules[0].status)
+		{
+			IPACMDBG("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+		/* copy filter hdls */
+		wlan_ampdu_flt_rule.hdl[2] = m_pFilteringTable->rules[0].flt_rule_hdl;
+
+	}
+	else
+	{
+		if (ip_type == IPA_IP_v4) m_pFilteringTable->ip = IPA_IP_v4;
+		else m_pFilteringTable->ip = IPA_IP_v6;
+
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			PERROR("Error Adding Filtering rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (m_pFilteringTable->rules[0].status)
+		{
+			IPACMDBG("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+		/* copy filter hdls */
+		if (ip_type == IPA_IP_v4) wlan_ampdu_flt_rule.hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+		else wlan_ampdu_flt_rule.hdl[2] = m_pFilteringTable->rules[0].flt_rule_hdl;
+	}
+
+fail:
+	free(m_pFilteringTable);
+
+	return res;
+
+}
+
+/*delete ampdu filter rules for disabling software_routing event*/
+int IPACM_Wlan::handle_software_routing_disable(void)
+{
+
+	if (ip_type == IPA_IP_MAX)
+	{
+		/* ipv4 case */
+		if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[1],
+																				IPA_IP_v4, 1) == false)
+		{
+			return IPACM_FAILURE;
+		}
+
+		/* ipv6 case */
+		if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[2],
+																				IPA_IP_v6, 1) == false)
+		{
+			return IPACM_FAILURE;
+		}
+
+	}
+	else
+	{
+		if (ip_type == IPA_IP_v4)
+		{
+			if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[1],
+																					IPA_IP_v4, 1) == false)
+			{
+				return IPACM_FAILURE;
+			}
+		}
+		else if (ip_type == IPA_IP_v6)
+		{
+			if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[2],
+																					IPA_IP_v6, 1) == false)
+			{
+				return IPACM_FAILURE;
+			}
+		}
+	}
+
+	return IPACM_SUCCESS;
+}
+
+
+/*duplicate ampdu filter rules for initial iface configuration*/
+int IPACM_Wlan::init_fl_rule(ipa_ip_type iptype)
+{
+	int res = IPACM_SUCCESS;
+	struct ipa_flt_rule_add flt_rule_entry;
+	ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+	IPACMDBG("ip-type: %d\n", iptype);
+
+	if (iptype == IPA_IP_v4)
+	{
+		m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+			 calloc(1,
+							sizeof(struct ipa_ioc_add_flt_rule) +
+							IPV4_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add)
+							);
+
+		if (!m_pFilteringTable)
+		{
+			PERROR("Error Locate ipa_flt_rule_add memory...\n");
+			return IPACM_FAILURE;
+		}
+
+
+		m_pFilteringTable->commit = 1;
+		m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+		m_pFilteringTable->global = false;
+		m_pFilteringTable->ip = iptype;
+		m_pFilteringTable->num_rules = (uint8_t)IPV4_DEFAULT_FILTERTING_RULES;
+
+		/* Configuring Fragment Rule */
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
+		memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		/* Configuring Multicast Filtering Rule */
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xF0000000;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xE0000000; /* DST_IP == 224.0.0.0 */
+		memcpy(&(m_pFilteringTable->rules[1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		/* Configuring Broadcast Filtering Rule */
+		flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+		flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xFFFFFFFF; /* Filter DST_IP == 127.0.0.1 */
+		memcpy(&(m_pFilteringTable->rules[2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			PERROR("Error Adding RuleTable(2) to Filtering, aborting...\n");
+			res = IPACM_FAILURE;
+		}
+		else
+		{
+			/* copy filter hdls */
+			wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules] = m_pFilteringTable->rules[0].flt_rule_hdl;
+			wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules + 1] = m_pFilteringTable->rules[1].flt_rule_hdl;
+			wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules + 2] = m_pFilteringTable->rules[2].flt_rule_hdl;
+			wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules] = IPA_IP_v4;
+			wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules + 1] = IPA_IP_v4;
+			wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules + 2] = IPA_IP_v4;
+			wlan_ampdu_flt_rule.num_rules += IPV4_DEFAULT_FILTERTING_RULES;
+		}
+	}
+	else
+	{
+		/* IPv6 filter rule configuration */
+		m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+			 calloc(1,
+							sizeof(struct ipa_ioc_add_flt_rule) +
+							IPV6_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add)
+							);
+
+		if (!m_pFilteringTable)
+		{
+			PERROR("Error Locate ipa_flt_rule_add memory...\n");
+			return IPACM_FAILURE;
+		}
+		m_pFilteringTable->commit = 1;
+		m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+		m_pFilteringTable->global = false;
+		m_pFilteringTable->ip = iptype;
+		m_pFilteringTable->num_rules = (uint8_t)IPV6_DEFAULT_FILTERTING_RULES;
+
+		/* Configuring Fragment Filtering Rule */
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.at_rear = true;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+
+		/* Configuring Multicast Filtering Rule */
+		memcpy(&flt_rule_entry.rule.attrib,
+					 &rx_prop->rx[0].attrib,
+					 sizeof(flt_rule_entry.rule.attrib));
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFF000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0XFF000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+		flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+		memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			PERROR("Error Adding Filtering Rule, aborting...\n");
+			res = IPACM_FAILURE;
+		}
+		else
+		{
+			/* copy filter hdls */
+			wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules] = m_pFilteringTable->rules[0].flt_rule_hdl;
+			//wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules + 1] = m_pFilteringTable->rules[1].flt_rule_hdl;
+			wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules] = IPA_IP_v6;
+			//wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules + 1] = IPA_IP_v6;
+			wlan_ampdu_flt_rule.num_rules += IPV6_DEFAULT_FILTERTING_RULES;
+		}
+	}
+
+	free(m_pFilteringTable);
+	return res;
+}
+
+
+/*duplicate ampdu filter rules for new_address event*/
+int IPACM_Wlan::handle_addr_evt(ipacm_event_data_addr *data)
+{
+	ipa_ioc_add_flt_rule *m_pFilteringTable;
+	struct ipa_flt_rule_add flt_rule_entry;
+	int NUM_RULES = 1;
+
+	IPACMDBG(" set route/filter rule ip-type: %d \n", data->iptype);
+	if (data->iptype == IPA_IP_v6)
+	{
+		if (num_dft_rt == 1) /*LAN handle_addr_evt will update this to 1*/
+		{
+			/* configure ampdu multicast/broadcast/fragment filter rule */
+			init_fl_rule(data->iptype);
+
+			/* add default v6 filter rule */
+			m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+				 calloc(1,
+								sizeof(struct ipa_ioc_add_flt_rule) +
+								NUM_RULES * sizeof(struct ipa_flt_rule_add)
+								);
+
+			if (!m_pFilteringTable)
+			{
+				PERROR("Error Locate ipa_ioc_add_flt_rule memory...\n");
+				return IPACM_FAILURE;
+			}
+
+			m_pFilteringTable->commit = 1;
+			m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+			m_pFilteringTable->global = false;
+			m_pFilteringTable->ip = IPA_IP_v6;
+			m_pFilteringTable->num_rules = (uint8_t)NUM_RULES;
+
+			if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6))
+			{
+				PERROR("m_routing.GetRoutingTable() Failed.\n");
+				return IPACM_FAILURE;
+			}
+
+			memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+			flt_rule_entry.at_rear = true;
+			flt_rule_entry.flt_rule_hdl = -1;
+			flt_rule_entry.status = -1;
+			flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
+			memcpy(&flt_rule_entry.rule.attrib,
+						 &rx_prop->rx[0].attrib,
+						 sizeof(flt_rule_entry.rule.attrib));
+			flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+			flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+			memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+			if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+			{
+				PERROR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+				free(m_pFilteringTable);
+				return IPACM_FAILURE;
+
+			}
+			else
+			{
+				IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+			}
+
+			/* copy filter hdls */
+			wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules] = m_pFilteringTable->rules[0].flt_rule_hdl;
+			wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules] = IPA_IP_v6;
+			wlan_ampdu_flt_rule.num_rules++;
+			free(m_pFilteringTable);
+		}
+	}
+	else
+	{
+		init_fl_rule(data->iptype);
+	}
+	return IPACM_SUCCESS;
+}
+
+/*duplicate ampdu filter rules for private subnet configuration*/
+int IPACM_Wlan::handle_private_subnet(ipa_ip_type iptype)
+{
+	struct ipa_flt_rule_add flt_rule_entry;
+	int i;
+
+	IPACMDBG("wlan->handle_private_subnet(); set route/filter rule \n");
+
+	if (iptype == IPA_IP_v4)
+	{
+		/* construct ipa_ioc_add_flt_rule with 1 rules */
+		ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+		m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+			 calloc(1,
+							sizeof(struct ipa_ioc_add_flt_rule) +
+							(IPACM_Iface::ipacmcfg->ipa_num_private_subnet) * sizeof(struct ipa_flt_rule_add)
+							);
+
+		if (!m_pFilteringTable)
+		{
+			PERROR("Error Locate ipa_ioc_add_flt_rule memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		m_pFilteringTable->commit = 1;
+		m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+		m_pFilteringTable->global = false;
+		m_pFilteringTable->ip = IPA_IP_v4;
+		m_pFilteringTable->num_rules = (uint8_t)IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+
+		if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+		{
+			PERROR("WLAN m_routing.GetRoutingTable(IPACM_Iface::ipacmcfg->rt_tbl_lan_v4) Failed.\n");
+			free(m_pFilteringTable);
+			return IPACM_FAILURE;
+		}
+
+		for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_private_subnet; i++)
+		{
+			memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+			flt_rule_entry.at_rear = true;
+			flt_rule_entry.flt_rule_hdl = -1;
+			flt_rule_entry.status = -1;
+			flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+			memcpy(&flt_rule_entry.rule.attrib,
+						 &rx_prop->rx[0].attrib,
+						 sizeof(flt_rule_entry.rule.attrib));
+			flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+			flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask;
+			flt_rule_entry.rule.attrib.u.v4.dst_addr = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr;
+			memcpy(&(m_pFilteringTable->rules[i]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+		}
+
+		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+		{
+			PERROR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+			free(m_pFilteringTable);
+			return IPACM_FAILURE;
+		};
+
+
+		/* copy filter hdls */
+		for (i = 0; i < (IPACM_Iface::ipacmcfg->ipa_num_private_subnet); i++)
+		{
+			wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules + i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+			wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules + i] = IPA_IP_v4;
+		}
+		wlan_ampdu_flt_rule.num_rules += IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+
+		IPACMDBG("wlan handle private ok~\n");
+		free(m_pFilteringTable);
+	}
+	return IPACM_SUCCESS;
+}
+
+
+/*handle wlan iface down event*/
+int IPACM_Wlan::handle_down_evt()
+{
+	IPACMDBG("ip-type: %d \n", ip_type);
+	uint32_t tx_index, rt_hdl;
+	ipa_ip_type ip;
+	int res = IPACM_SUCCESS, i;
+
+	/* no iface address up, directly close iface*/
+	if (ip_type == IPACM_IP_NULL)
+	{
+		IPACMERR("Invalid iptype: 0x%x\n", ip_type);
+		return IPACM_FAILURE;
+	}
+
+	/* Delete v6 filtering rules */
+	if (ip_type != IPA_IP_v6)
+	{
+		IPACMDBG("Delete default v4 filter rules\n");
+		/* delete default filter rules */
+		if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl,
+																				IPA_IP_v4,
+																				IPV4_DEFAULT_FILTERTING_RULES) == false)
+		{
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		IPACMDBG("Delete private v4 filter rules\n");
+		/* free private-ipv4 filter rules */
+		if (m_filtering.DeleteFilteringHdls(
+					private_fl_rule_hdl,
+					IPA_IP_v4,
+					IPACM_Iface::ipacmcfg->ipa_num_private_subnet) == false)
+		{
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+	}
+
+	/* Delete v4 filtering rules */
+	if (ip_type != IPA_IP_v4)
+	{
+		IPACMDBG("Delete default %d v6 filter rules\n", IPV6_DEFAULT_FILTERTING_RULES);
+		/* delete default filter rules */
+		if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl,
+																				IPA_IP_v6,
+																				IPV6_DEFAULT_FILTERTING_RULES) == false)
+		{
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+	}
+	IPACMDBG("finished delte default filtering rules\n ");
+
+	/* delete WLAN IPA_CLIENT_A5_WLAN_AMPDU_PROD filter rules*/
+	for (i = 3; i < wlan_ampdu_flt_rule.num_rules; i++)
+	{
+		IPACMDBG("Delete WLAN IPA_CLIENT_A5_WLAN_AMPDU_PROD filter rules\n");
+		if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[i],
+																				wlan_ampdu_flt_rule.ip[i], 1) == false)
+		{
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+	}
+	IPACMDBG("finished delte AMPDU filtering rules\n ");
+
+
+	/* Delete default v4 RT rule */
+	if (ip_type != IPA_IP_v6)
+	{
+		IPACMDBG("Delete default v4 routing rules\n");
+		if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4)
+				== false)
+		{
+			IPACMERR("Routing rule deletion failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+	}
+
+	/* Delete default v6 RT rule */
+	if (ip_type != IPA_IP_v4)
+	{
+		IPACMDBG("Delete default v6 routing rules\n");
+		/* May have multiple ipv6 iface-RT rules */
+		for (i = 0; i < num_dft_rt; i++)
+		{
+			if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[i + 1], IPA_IP_v6)
+					== false)
+			{
+				IPACMERR("Routing rule deletion failed!\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+		}
+	}
+	IPACMDBG("finished deleting default RT rules\n ");
+
+
+	/* delete wan filter rule */
+	if (IPACM_Wan::isWanUP())
+	{
+		IPACMDBG("Delete wan filtering rules\n");
+
+		IPACM_Lan::handle_wan_down();
+		handle_wan_down();
+	}
+	IPACMDBG("finished deleting wan filtering rules\n ");
+
+
+	/* check software routing fl rule hdl */
+	if (softwarerouting_act == true)
+	{
+		IPACMDBG("Delete sw routing filtering rules\n");
+		IPACM_Iface::handle_software_routing_disable();
+		handle_software_routing_disable();
+	}
+	IPACMDBG("finished delete software-routing filtering rules\n ");
+
+
+	/* clean wifi-client header, routing rules */
+	/* clean wifi client rule*/
+	IPACMDBG("left %d wifi clients need to be deleted \n ", num_wifi_client);
+	for (i = 0; i < num_wifi_client; i++)
+	{
+
+		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+			if (ip_type != IPA_IP_v6) /* for ipv4 */
+			{
+				rt_hdl = get_client_memptr(wlan_client, i)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4;
+				ip = IPA_IP_v4;
+			}
+			else if (ip_type != IPA_IP_v4) /* for ipv6 */
+			{
+				rt_hdl = get_client_memptr(wlan_client, i)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6;
+				ip = IPA_IP_v6;
+			}
+
+			IPACMDBG("Delete %d client route rule %d\n", num_wifi_client, tx_index);
+			if (m_routing.DeleteRoutingHdl(rt_hdl, ip) == false)
+			{
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+
+		} /* end of tx-index for loop*/
+
+		IPACMDBG("Delete %d client header\n", num_wifi_client);
+		if (m_header.DeleteHeaderHdl(get_client_memptr(wlan_client, i)->hdr_hdl)
+				== false)
+		{
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+	} /* end of for loop */
+
+	/* free the wlan clients cache */
+	IPACMDBG("Free wlan clients cache\n");
+
+fail:
+	free(wlan_client);
+	free(tx_prop);
+	free(rx_prop);
+	free(iface_query);
+
+	return res;
+}
diff --git a/ipacm/src/IPACM_Xml.cpp b/ipacm/src/IPACM_Xml.cpp
new file mode 100644
index 0000000..8871b1d
--- /dev/null
+++ b/ipacm/src/IPACM_Xml.cpp
@@ -0,0 +1,1090 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following
+   disclaimer in the documentation and/or other materials provided
+   with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+   contributors may be used to endorse or promote products derived
+   from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+  @file
+   IPACM_Xml.cpp
+
+  @brief
+   This file implements the XML specific parsing functionality.
+
+  @Author
+   Skylar Chang/Shihuan Liu
+*/
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "IPACM_Xml.h"
+#include "IPACM_Log.h"
+#include "IPACM_Netlink.h"
+
+static char* IPACM_read_content_element
+(
+	 xmlNode* element
+);
+
+static int32_t IPACM_util_icmp_string
+(
+	 const char* xml_str,
+	 const char* str
+);
+
+static int ipacm_cfg_xml_parse_tree
+(
+	 xmlNode* xml_node,
+	 IPACM_conf_t *config
+);
+
+static int IPACM_firewall_xml_parse_tree
+(
+	 xmlNode* xml_node,
+	 IPACM_firewall_conf_t *config
+);
+
+/*Reads content (stored as child) of the element */
+static char* IPACM_read_content_element
+(
+	 xmlNode* element
+)
+{
+	xmlNode* child_ptr;
+
+	for (child_ptr  = element->children;
+			 child_ptr != NULL;
+			 child_ptr  = child_ptr->next)
+	{
+		if (child_ptr->type == XML_TEXT_NODE)
+		{
+			return (char*)child_ptr->content;
+		}
+	}
+	return NULL;
+}
+
+/* insensitive comparison of a libxml's string (xml_str) and a regular string (str)*/
+static int32_t IPACM_util_icmp_string
+(
+	 const char* xml_str,
+	 const char* str
+)
+{
+	int32_t ret = -1;
+
+	if (NULL != xml_str && NULL != str)
+	{
+		uint32_t len1 = strlen(str);
+		uint32_t len2 = strlen(xml_str);
+		/* If the lengths match, do the string comparison */
+		if (len1 == len2)
+		{
+			ret = strncasecmp(xml_str, str, len1);
+		}
+	}
+
+	return ret;
+}
+
+/* This function read IPACM XML and populate the IPA CM Cfg */
+int ipacm_read_cfg_xml(char *xml_file, IPACM_conf_t *config)
+{
+	xmlDocPtr doc = NULL;
+	xmlNode* root = NULL;
+	int ret_val;
+
+	/* Invoke the XML parser and obtain the parse tree */
+	doc = xmlReadFile(xml_file, "UTF-8", XML_PARSE_NOBLANKS);
+	if (doc == NULL) {
+		IPACMDBG("IPACM_xml_parse: libxml returned parse error!\n");
+		return IPACM_FAILURE;
+	}
+
+	/*Get the root of the tree*/
+	root = xmlDocGetRootElement(doc);
+
+	memset(config, 0, sizeof(IPACM_conf_t));
+
+	/* parse the xml tree returned by libxml */
+	ret_val = ipacm_cfg_xml_parse_tree(root, config);
+
+	if (ret_val != IPACM_SUCCESS) 
+		IPACMDBG("IPACM_xml_parse: ipacm_cfg_xml_parse_tree returned parse error!\n");
+
+	/* Free up the libxml's parse tree */
+	xmlFreeDoc(doc);
+	//xmlCleanupParser();
+
+	return ret_val;
+}
+
+/* This function traverses the xml tree*/
+static int ipacm_cfg_xml_parse_tree
+(
+	 xmlNode* xml_node,
+	 IPACM_conf_t *config
+)
+{
+	int32_t ret_val = IPACM_SUCCESS;
+	int str_size;
+	char* content;
+	char content_buf[MAX_XML_STR_LEN];
+
+	if (NULL == xml_node) 
+		return ret_val;
+
+	while ( xml_node != NULL &&
+				 ret_val == IPACM_SUCCESS)
+	{
+		switch (xml_node->type)
+		{
+		case XML_ELEMENT_NODE:
+			{
+				if (IPACM_util_icmp_string((char*)xml_node->name,
+																	 system_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name,
+																	 IPACMCFG_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name,
+																	 IPACMIFACECFG_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name,
+																	 IFACE_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name,
+																	 IPACMPRIVATESUBNETCFG_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name,
+																	 SUBNET_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name,
+																	 IPACMALG_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name,
+																	 ALG_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name,
+																	 IPACMNat_TAG) == 0)
+				{
+					if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																					IFACE_TAG))
+					{
+						/* increase iface entry number */
+						config->iface_config.num_iface_entries++;
+					}
+
+					if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																					SUBNET_TAG))
+					{
+						/* increase iface entry number */
+						config->private_subnet_config.num_subnet_entries++;
+					}
+
+					if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																					ALG_TAG))
+					{
+						/* increase iface entry number */
+						config->alg_config.num_alg_entries++;
+					}
+					/* go to child */
+					ret_val = ipacm_cfg_xml_parse_tree(xml_node->children,
+																						 config);
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name,
+																				NAME_TAG) == 0)
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						strncpy(config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].iface_name, content_buf, str_size);
+						IPACMDBG("Name %s\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].iface_name);
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name,
+																				CATEGORY_TAG) == 0)
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if (0 == strncasecmp(content_buf, WANIF_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = WAN_IF;
+							IPACMDBG("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+						}
+						else if (0 == strncasecmp(content_buf, LANIF_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = LAN_IF;
+							IPACMDBG("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+						}
+						else if (0 == strncasecmp(content_buf, WLANIF_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = WLAN_IF;
+							IPACMDBG("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+						}
+						else  if (0 == strncasecmp(content_buf, VIRTUALIF_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = VIRTUAL_IF;
+							IPACMDBG("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+						}
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name,
+																				SUBNETADDRESS_TAG) == 0)
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->private_subnet_config.private_subnet_entries[config->private_subnet_config.num_subnet_entries - 1].subnet_addr
+							 = ntohl(inet_addr(content_buf));
+						IPACMDBG("subnet_addr: %s \n", content_buf);
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name,
+																				SUBNETMASK_TAG) == 0)
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->private_subnet_config.private_subnet_entries[config->private_subnet_config.num_subnet_entries - 1].subnet_mask
+							 = ntohl(inet_addr(content_buf));
+						IPACMDBG("subnet_mask: %s \n", content_buf);
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name,
+																				Protocol_TAG) == 0)
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+
+						if (0 == strncasecmp(content_buf, TCP_PROTOCOL_TAG, str_size))
+						{
+							config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol = IPPROTO_TCP;
+							IPACMDBG("Protocol %s: %d\n", content_buf, config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol);
+						}
+						else if (0 == strncasecmp(content_buf, UDP_PROTOCOL_TAG, str_size))
+						{
+							config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol = IPPROTO_UDP;
+							IPACMDBG("Protocol %s: %d\n", content_buf, config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol);
+						}
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name,
+																				Port_TAG) == 0)
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].port
+							 = atoi(content_buf);
+						IPACMDBG("port %d\n", config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].port);
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name,
+																				NAT_MaxEntries_TAG) == 0)
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->nat_max_entries = atoi(content_buf);
+						IPACMDBG("Nat Table Max Entries %d\n", config->nat_max_entries);
+					}
+				}
+			}
+			break;
+		default:
+			break;
+		}
+		/* go to sibling */
+		xml_node = xml_node->next;
+	} /* end while */
+	return ret_val;
+}
+
+/* This function read QCMAP CM Firewall XML and populate the QCMAP CM Cfg */
+int IPACM_read_firewall_xml(char *xml_file, IPACM_firewall_conf_t *config)
+{
+	xmlDocPtr doc = NULL;
+	xmlNode* root = NULL;
+	int ret_val;
+
+	IPACM_ASSERT(xml_file != NULL);
+	IPACM_ASSERT(config != NULL);
+
+	/* invoke the XML parser and obtain the parse tree */
+	doc = xmlReadFile(xml_file, "UTF-8", XML_PARSE_NOBLANKS);
+    if (doc == NULL) {
+        IPACMDBG("IPACM_xml_parse: libxml returned parse error\n");
+		return IPACM_FAILURE;
+    }
+	/*get the root of the tree*/
+	root = xmlDocGetRootElement(doc);
+
+	/* parse the xml tree returned by libxml*/
+	ret_val = IPACM_firewall_xml_parse_tree(root, config);
+
+	if (ret_val != IPACM_SUCCESS) 
+		IPACMDBG("IPACM_xml_parse: ipacm_firewall_xml_parse_tree returned parse error!\n");
+
+	/* free the tree */
+    xmlFreeDoc(doc);
+
+	return ret_val;
+}
+
+
+/* This function traverses the firewall xml tree */
+static int IPACM_firewall_xml_parse_tree
+(
+	 xmlNode* xml_node,
+	 IPACM_firewall_conf_t *config
+)
+{
+	int mask_value_v6, mask_index;
+	int32_t ret_val = IPACM_SUCCESS;
+	char *content;
+	int str_size;
+	char content_buf[MAX_XML_STR_LEN];
+	struct in6_addr ip6_addr;
+
+	IPACM_ASSERT(config != NULL);
+
+	if (NULL == xml_node) 
+		return ret_val;
+
+	while ( xml_node != NULL &&
+				 ret_val == IPACM_SUCCESS)
+	{
+		switch (xml_node->type)
+		{
+
+		case XML_ELEMENT_NODE:
+			{
+				if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																				system_TAG) ||
+						0 == IPACM_util_icmp_string((char*)xml_node->name,
+																				MobileAPFirewallCfg_TAG) ||
+						0 == IPACM_util_icmp_string((char*)xml_node->name,
+																				Firewall_TAG)
+						)
+				{
+					if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																					Firewall_TAG))
+					{
+						/* increase firewall entry num */
+						config->num_extd_firewall_entries++;
+					}
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+																									config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPFamily_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].ip_vsn
+							 = (firewall_ip_version_enum)atoi(content_buf);
+						IPACMDBG("\n IP family type is %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].ip_vsn);
+
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV4SourceAddress_TAG))
+				{
+					config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_ADDR;
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+																									config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV4SourceIPAddress_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.src_addr
+							 = ntohl(inet_addr(content_buf));
+						IPACMDBG("IPv4 source address is: %s \n", content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV4SourceSubnetMask_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.src_addr_mask
+							 = ntohl(inet_addr(content_buf));
+						IPACMDBG("IPv4 source subnet mask is: %s \n", content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV4DestinationAddress_TAG))
+				{
+					config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+																									config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV4DestinationIPAddress_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.dst_addr
+							 = ntohl(inet_addr(content_buf));
+						IPACMDBG("IPv4 destination address is: %s \n", content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV4DestinationSubnetMask_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.dst_addr_mask
+							 = ntohl(inet_addr(content_buf));
+						IPACMDBG("IPv4 destination subnet mask is: %s \n", content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV4TypeOfService_TAG))
+				{
+					config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_TOS;
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+																									config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TOSValue_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos
+							 = atoi(content_buf);
+
+						IPACMDBG("\n IPV4 TOS val is %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TOSMask_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos
+							 &= atoi(content_buf);
+
+						IPACMDBG("\n IPv4 TOS mask is %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV4NextHeaderProtocol_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_PROTOCOL;
+
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.protocol = atoi(content_buf);
+
+						IPACMDBG("\n IPv4 next header prot is %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.protocol);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV6SourceAddress_TAG))
+				{
+					config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |=
+						 IPA_FLT_SRC_ADDR;
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+																									config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV6SourceIPAddress_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						inet_pton(AF_INET6, content_buf, &ip6_addr);
+						memcpy(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr,
+									 ip6_addr.s6_addr, IPACM_IPV6_ADDR_LEN * sizeof(uint8_t));
+
+						IPACMDBG("\n ipv6 source addr is %d \n ",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[0]);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV6SourcePrefix_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						mask_value_v6 = atoi(content_buf);
+						for (mask_index = 0; mask_index < 4; mask_index++)
+						{
+							if (mask_value_v6 >= 32)
+							{
+								mask_v6(32, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr_mask[mask_index]));
+								mask_value_v6 -= 32;
+							}
+							else
+							{
+								mask_v6(mask_value_v6, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr_mask[mask_index]));
+								mask_value_v6 = 0;
+							}
+						}
+						IPACMDBG("\n ipv6 source prefix is %d \n",
+										 atoi(content_buf));
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV6DestinationAddress_TAG))
+				{
+					config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |=
+						 IPA_FLT_DST_ADDR;
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+																									config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV6DestinationIPAddress_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						inet_pton(AF_INET6, content_buf, &ip6_addr);
+
+						memcpy(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr,
+									 ip6_addr.s6_addr, IPACM_IPV6_ADDR_LEN * sizeof(uint8_t));
+						IPACMDBG("\n ipv6 dest addr is %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[0]);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV6DestinationPrefix_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						mask_value_v6 = atoi(content_buf);
+						for (mask_index = 0; mask_index < 4; mask_index++)
+						{
+							if (mask_value_v6 >= 32)
+							{
+								mask_v6(32, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr_mask[mask_index]));
+								mask_value_v6 -= 32;
+							}
+							else
+							{
+								mask_v6(mask_value_v6, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr_mask[mask_index]));
+								mask_value_v6 = 0;
+							}
+						}
+						IPACMDBG("\n ipv6 dest prefix is %d \n",
+										 atoi(content_buf));
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV6TrafficClass_TAG))
+				{
+					config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_TC;
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+																									config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TrfClsValue_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.tc
+							 = atoi(content_buf);
+						IPACMDBG("\n ipv6 trf class val is %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.tc);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TrfClsMask_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.tc
+							 &= atoi(content_buf);
+
+						IPACMDBG("\n ipv6 trf class mask is %d \n",
+										 atoi(content_buf));
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 IPV6NextHeaderProtocol_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
+
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.next_hdr
+							 = atoi(content_buf);
+						IPACMDBG("\n ipv6 next header protocol is %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.next_hdr);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TCPSource_TAG))
+				{
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+																									config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TCPSourcePort_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+							 = atoi(content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TCPSourceRange_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if (atoi(content_buf) != 0)
+						{
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT_RANGE;
+ 						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo
+							 = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port;
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi
+							 = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port + atoi(content_buf);	 
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+							 = 0;						 
+						  IPACMDBG("\n tcp source port from %d to %d \n",
+						                 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo,
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi);
+						}
+						else
+						{
+					       config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT;
+                           IPACMDBG("\n tcp source port= %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port);
+
+						}						
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TCPDestination_TAG))
+				{
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+																									config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TCPDestinationPort_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+							 = atoi(content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TCPDestinationRange_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if(atoi(content_buf)!=0)
+						{
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT_RANGE;
+ 						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo
+							 = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port;
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi
+							 = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port + atoi(content_buf);						 
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+							 = 0;						 
+						  IPACMDBG("\n tcp dest port from %d to %d \n",
+						                 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo,
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi);
+						}
+						else
+						{
+					      config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT;
+						  IPACMDBG("\n tcp dest port= %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port);
+						}
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 UDPSource_TAG))
+				{
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+																									config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 UDPSourcePort_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+							 = atoi(content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 UDPSourceRange_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if(atoi(content_buf)!=0)
+						{
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT_RANGE;
+ 						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo
+							 = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port;
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi
+							 = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port + atoi(content_buf);						 
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+							 = 0;						 
+						  IPACMDBG("\n udp source port from %d to %d \n",
+						                 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo,
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi);
+						}
+						else
+						{
+					      config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT;
+						  IPACMDBG("\n udp source port= %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port);
+
+						}
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 UDPDestination_TAG))
+				{
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+																									config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 UDPDestinationPort_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+							 = atoi(content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 UDPDestinationRange_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if(atoi(content_buf)!=0)
+						{
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT_RANGE;
+ 						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo
+							 = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port;
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi
+							 = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port + atoi(content_buf);						 
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+							 = 0;						 
+						  IPACMDBG("\n UDP dest port from %d to %d \n",
+						                 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo,
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi);
+						}
+						else
+						{
+					      config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT;
+						  IPACMDBG("\n UDP dest port= %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port);
+
+						}
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 ICMPType_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.type = atoi(content_buf);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_TYPE;
+						IPACMDBG("\n icmp type is %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.type);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 ICMPCode_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.code = atoi(content_buf);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_CODE;
+						IPACMDBG("\n icmp code is %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.code);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 ESPSPI_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.spi = atoi(content_buf);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SPI;
+						IPACMDBG("\n esp spi is %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.spi);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TCP_UDPSource_TAG))
+				{
+					/* go to child */
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+																									config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TCP_UDPSourcePort_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content,str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+							 = atoi(content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TCP_UDPSourceRange_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if(atoi(content_buf)!=0)
+						{
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT_RANGE;
+ 						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo
+							 = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port;
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi
+							 = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port + atoi(content_buf);						 
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+							 = 0;						 
+						  IPACMDBG("\n tcp_udp source port from %d to %d \n",
+						                 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo,
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi);
+						}
+						else
+						{
+	  				      config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT;
+						  IPACMDBG("\n tcp_udp source port= %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port);
+
+						}
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TCP_UDPDestination_TAG))
+				{
+					ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+																									config);
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TCP_UDPDestinationPort_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+							 = atoi(content_buf);
+					}
+				}
+				else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+																						 TCP_UDPDestinationRange_TAG))
+				{
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if(atoi(content_buf)!=0)
+						{
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT_RANGE;
+ 						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo
+							 = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port;
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi
+							 = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port + atoi(content_buf);						 
+						  config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+							 = 0;						 
+						  IPACMDBG("\n tcp_udp dest port from %d to %d \n",
+						                 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo,
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi);
+						}
+						else
+						{
+					      config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT;
+						  IPACMDBG("\n tcp_udp dest port= %d \n",
+										 config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port);
+
+						}
+					}
+				}
+			}
+			break;
+
+		default:
+			break;
+		}
+		/* go to sibling */
+		xml_node = xml_node->next;
+	} /* end while */
+	return ret_val;
+}
+
+
diff --git a/ipacm/src/IPACM_cfg.xml b/ipacm/src/IPACM_cfg.xml
new file mode 100644
index 0000000..06f20b6
--- /dev/null
+++ b/ipacm/src/IPACM_cfg.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<system xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ipacm_cfg.xsd">
+	<IPACM>
+		<IPACMIface>
+			<Iface>
+			   <Name>rmnet0</Name>
+			   <Category>WAN</Category>
+			</Iface>
+			<Iface>
+			   <Name>rmnet1</Name>
+			   <Category>LAN</Category>
+			</Iface>			
+			<Iface>
+			   <Name>wlan0</Name>
+			   <Category>WLAN</Category>
+			</Iface>			
+			<Iface>
+			   <Name>bridge0</Name>
+			   <Category>VIRTUAL</Category>
+		    </Iface>
+		</IPACMIface>
+		<IPACMPrivateSubnet>
+			<Subnet>
+  			   <SubnetAddress>192.168.1.0</SubnetAddress>
+  			   <SubnetMask>255.255.255.0</SubnetMask>
+		    </Subnet>		
+		</IPACMPrivateSubnet>
+		<IPACMALG>
+			<ALG>
+  			   <Protocol>TCP</Protocol>
+  			   <Port>23</Port>
+		    </ALG>		
+			<ALG>
+  			   <Protocol>UDP</Protocol>
+  			   <Port>250</Port>
+		    </ALG>		
+		</IPACMALG>
+		<IPACMNAT>		
+ 	        <MaxNatEntries>100</MaxNatEntries>
+		</IPACMNAT>
+	</IPACM>
+</system>	
diff --git a/ipacm/src/Makefile.am b/ipacm/src/Makefile.am
new file mode 100644
index 0000000..22fa657
--- /dev/null
+++ b/ipacm/src/Makefile.am
@@ -0,0 +1,41 @@
+EXTRA_CPPFLAGS	= -DDEBUG
+
+AM_CPPFLAGS = -I./../inc -I$(WORKSPACE)/data-ipa/ipanat/inc -I$(WORKSPACE)/kernel/include -I/usr/include/libxml2
+AM_CPPFLAGS += -Wall -Wundef -Wno-trigraphs
+
+ipacm_SOURCES =	IPACM_Main.cpp \
+		IPACM_Conntrack_NATApp.cpp\
+		IPACM_ConntrackClient.cpp \
+		IPACM_ConntrackListener.cpp \
+		IPACM_EvtDispatcher.cpp \
+		IPACM_Config.cpp \
+		IPACM_CmdQueue.cpp \
+		IPACM_Log.cpp \
+		IPACM_Filtering.cpp \
+		IPACM_Routing.cpp \
+		IPACM_Header.cpp \
+		IPACM_Lan.cpp \
+		IPACM_Iface.cpp \
+		IPACM_Wlan.cpp \
+		IPACM_Wan.cpp \
+		IPACM_IfaceManager.cpp \
+		IPACM_Neighbor.cpp \
+		IPACM_Netlink.cpp \
+		IPACM_Xml.cpp		
+		
+bin_PROGRAMS  =  ipacm
+
+requiredlibs =  -lxml2 -lpthread -lnetfilter_conntrack -lnfnetlink\
+               ../../ipanat/src/libipanat.la
+			   
+ipacm_LDADD =  $(requiredlibs)
+			 
+LOCAL_MODULE := libipanat
+LOCAL_PRELINK_MODULE := false
+include $(BUILD_SHARED_LIBRARY)
+
+etcdir = ${sysconfdir}
+etc_SCRIPTS = IPACM_cfg.xml mobileap_firewall.xml
+
+init_ddir = ${sysconfdir}/init.d
+init_d_SCRIPTS = start_ipacm_le
diff --git a/ipacm/src/mobileap_firewall.xml b/ipacm/src/mobileap_firewall.xml
new file mode 100644
index 0000000..c722511
--- /dev/null
+++ b/ipacm/src/mobileap_firewall.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<system xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="mobileap_firewall_cfg.xsd">
+	<MobileAPFirewallCfg>					
+	</MobileAPFirewallCfg>
+</system>
diff --git a/ipacm/src/start_ipacm_le b/ipacm/src/start_ipacm_le
new file mode 100755
index 0000000..3541a0b
--- /dev/null
+++ b/ipacm/src/start_ipacm_le
@@ -0,0 +1,57 @@
+#! /bin/sh
+#
+################################ 
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+# * Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+#   copyright notice, this list of conditions and the following
+#   disclaimer in the documentation and/or other materials provided
+#   with the distribution.
+# * Neither the name of The Linux Foundation nor the names of its
+#   contributors may be used to endorse or promote products derived
+#   from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+################################
+
+# ipacm   init.d script to start the data-ipa Software's ipacm daemon
+
+set -e
+
+case "$1" in
+  start)
+        echo -n "Starting ipacm: "
+        start-stop-daemon -S -b -a ipacm
+        echo "done"
+        ;;
+  stop)
+        echo -n "Stopping ipacm: "
+        start-stop-daemon -K -n ipacm
+        echo "done"
+        ;;
+  restart)
+        $0 stop
+        $0 start
+        ;;
+  *)
+        echo "Usage ipacm { start | stop | restart}" >&2
+        exit 1
+        ;;
+esac
+
+exit 0
diff --git a/ipanat/inc/ipa_nat_drv.h b/ipanat/inc/ipa_nat_drv.h
new file mode 100644
index 0000000..cda63f1
--- /dev/null
+++ b/ipanat/inc/ipa_nat_drv.h
@@ -0,0 +1,118 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "string.h"  /* memset */
+#include "stdlib.h"  /* free, malloc */
+#include "stdint.h"  /* uint32_t */
+
+/**
+ * struct ipa_nat_ipv4_rule - To hold ipv4 nat rule
+ * @target_ip: destination ip address
+ * @private_ip: private ip address
+ * @target_port: destination port
+ * @private_port: private port 
+ * @protocol: protocol of rule (tcp/udp)
+ */
+typedef struct
+{
+  uint32_t target_ip;
+  uint32_t private_ip;
+  uint16_t target_port;
+  uint16_t private_port;
+  uint16_t public_port;
+  uint8_t  protocol;
+
+}ipa_nat_ipv4_rule;
+
+/**
+ * ipa_nat_add_ipv4_tbl() - create ipv4 nat table
+ * @public_ip_addr: [in] public ipv4 address  
+ * @number_of_entries: [in]  number of nat entries 
+ * @table_handle: [out] Handle of new ipv4 nat table 
+ *  
+ * To create new ipv4 nat table 
+ *
+ * Returns:	0  On Success, negative on failure
+ */
+int ipa_nat_add_ipv4_tbl(uint32_t public_ip_addr,
+                         uint16_t number_of_entries,
+                         uint32_t *table_handle);
+
+/**
+ * ipa_nat_del_ipv4_tbl() - delete ipv4 table
+ * @table_handle: [in] Handle of ipv4 nat table 
+ *  
+ * To delete given ipv4 nat table 
+ *
+ * Returns:	0  On Success, negative on failure
+ */
+int ipa_nat_del_ipv4_tbl(uint32_t table_handle);
+
+/**
+ * ipa_nat_add_ipv4_rule() - to insert new ipv4 rule
+ * @table_handle: [in] handle of ipv4 nat table  
+ * @rule: [in]  Pointer to new rule 
+ * @rule_handle: [out] Return the handle to rule 
+ *  
+ * To insert new ipv4 nat rule into ipv4 nat table 
+ *
+ * Returns:	0  On Success, negative on failure
+ */
+int ipa_nat_add_ipv4_rule(uint32_t table_handle,
+                          const ipa_nat_ipv4_rule *rule,
+                          uint32_t *rule_handle);
+
+/**
+ * ipa_nat_del_ipv4_rule() - to delete ipv4 nat rule
+ * @table_handle: [in] handle of ipv4 nat table  
+ * @rule_handle: [in] ipv4 nat rule handle
+ *  
+ * To insert new ipv4 nat rule into ipv4 nat table 
+ *
+ * Returns:	0  On Success, negative on failure
+ */
+int ipa_nat_del_ipv4_rule(uint32_t table_handle,
+                          uint32_t rule_handle);
+
+
+/**
+ * ipa_nat_query_timestamp() - to query timestamp
+ * @table_handle: [in] handle of ipv4 nat table  
+ * @rule_handle: [in] ipv4 nat rule handle 
+ * @time_stamp: [out] time stamp of rule 
+ *  
+ * To retrieve the timestamp that lastly the 
+ * nat rule was accessed 
+ *
+ * Returns:	0  On Success, negative on failure
+ */
+int ipa_nat_query_timestamp(uint32_t  table_handle,
+                            uint32_t  rule_handle,
+                            uint32_t  *time_stamp);
+
diff --git a/ipanat/inc/ipa_nat_drvi.h b/ipanat/inc/ipa_nat_drvi.h
new file mode 100644
index 0000000..9b56cf1
--- /dev/null
+++ b/ipanat/inc/ipa_nat_drvi.h
@@ -0,0 +1,474 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef IPA_NAT_DRVI_H
+#define IPA_NAT_DRVI_H
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <linux/msm_ipa.h>
+#include <netinet/in.h>
+#include <sys/inotify.h>
+
+#include "ipa_nat_logi.h"
+
+#define NAT_DUMP
+//#define IPADBG(fmt, args...) printf(" %s:%d " fmt, __FUNCTION__, __LINE__, ## args) 
+//#define IPAERR(fmt, args...) printf(" %s:%d " fmt, __FUNCTION__, __LINE__, ## args) 
+
+
+/*======= IMPLEMENTATION related data structures and functions ======= */
+#ifdef IPA_ON_R3PC
+#define NAT_MMAP_MEM_SIZE (2 * 1024UL * 1024UL - 1)
+#endif
+
+#define IPA_DEV_NAME       "/dev/ipa"
+#define NAT_DEV_DIR        "/dev"
+#define NAT_DEV_NAME       "ipaNatTable"
+#define NAT_DEV_FULL_NAME  "/dev/ipaNatTable"
+
+#define IPA_NAT_TABLE_VALID 1
+#define IPA_NAT_MAX_IP4_TBLS   1
+#define IPA_NAT_BASE_TABLE_PERCENTAGE       .8
+#define IPA_NAT_EXPANSION_TABLE_PERCENTAGE  .2
+
+#define IPA_NAT_NUM_OF_BASE_TABLES      2
+#define IPA_NAT_UNUSED_BASE_ENTRIES     2
+
+#define IPA_NAT_RULE_FLAG_FIELD_OFFSET        18
+#define IPA_NAT_RULE_NEXT_FIELD_OFFSET        8
+#define IPA_NAT_RULE_PROTO_FIELD_OFFSET       22
+
+#define IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET       2
+#define IPA_NAT_INDEX_RULE_NAT_INDEX_FIELD_OFFSET  0
+
+#define IPA_NAT_RULE_FLAG_FIELD_SIZE       2
+#define IPA_NAT_RULE_NEXTFIELD_FIELD_SIZE  2
+
+#define IPA_NAT_FLAG_ENABLE_BIT_MASK  0x8000
+#define IPA_NAT_FLAG_DISABLE_BIT_MASK 0x0000
+
+#define IPA_NAT_FLAG_ENABLE_BIT  1
+#define IPA_NAT_FLAG_DISABLE_BIT 0
+
+#define IPA_NAT_INVALID_PROTO_FIELD_VALUE 0xFF00
+#define IPA_NAT_INVALID_PROTO_FIELD_CMP   0xFF
+
+#define IPA_NAT_INVALID_INDEX 0xFF
+#define IPA_NAT_INVALID_NAT_ENTRY 0x0
+
+#define INDX_TBL_ENTRY_SIZE_IN_BITS  16
+
+/* ----------- Rule id -----------------------
+ 
+   ------------------------------------------------
+   |  3bits   |    12 bits       |     1 bit      |
+   ------------------------------------------------
+   | reserved | index into table |  0 - base      |
+   |          |                  |  1 - expansion |
+   ------------------------------------------------
+ 
+*/
+#define IPA_NAT_RULE_HDL_TBL_TYPE_BITS        0x1
+#define IPA_NAT_RULE_HDL_TBL_TYPE_MASK        0x1
+
+/* ----------- sw specif parameter -----
+   ------------------------------------
+   |     16 bits     |     16 bits    |
+   ------------------------------------
+   |  index table    |  prev index    |
+   |     entry       |                |
+   ------------------------------------
+-----------------------------------------*/
+#define IPA_NAT_SW_PARAM_PREV_INDX_BYTE       0
+#define IPA_NAT_SW_PARAM_INDX_TBL_ENTRY_BYTE  1 
+
+typedef enum 
+{
+  IPA_NAT_BASE_TBL        = 0,
+  IPA_NAT_EXPN_TBL        = 1,
+  IPA_NAT_INDX_TBL        = 2,
+  IPA_NAT_INDEX_EXPN_TBL  = 3,
+}nat_table_type;
+
+typedef enum
+{
+	NEXT_INDEX_FIELD,
+	PUBLIC_PORT_FILED,
+	PRIVATE_PORT_FIELD,
+	TARGET_PORT_FIELD,
+	IP_CHKSUM_FIELD,
+	ENABLE_FIELD,
+	TIME_STAMP_FIELD,
+	PROTOCOL_FIELD,
+	TCP_UDP_CHKSUM_FIELD,
+	SW_SPEC_PARAM_PREV_INDEX_FIELD,
+  SW_SPEC_PARAM_INDX_TBL_ENTRY_FIELD,
+	INDX_TBL_TBL_ENTRY_FIELD,
+	INDX_TBL_NEXT_INDEX_FILED
+
+}ipa_nat_rule_field_type;
+
+/*
+	---------------------------------------------
+	|     3      |    2    |    1    |    0      |
+	---------------------------------------------
+	| Public Port(2B)     | Next Index(2B)       |
+	---------------------------------------------
+*/
+typedef struct
+{
+	uint32_t next_index:16;
+  uint32_t public_port:16; 
+}next_index_pub_port;
+
+
+/*
+	---------------------------------------------
+	|     3      |    2    |    1    |    0      |
+	---------------------------------------------
+  |       Flags(2B)     | IP check sum Diff(2B)|
+	|EN|FIN|Resv |        |                      |
+	---------------------------------------------
+*/
+typedef struct
+{
+	uint32_t ip_chksum:16;
+  uint32_t rsvd1:14;
+  uint32_t redirect:1;
+  uint32_t enable:1;
+}ipcksum_enbl;
+
+
+/*
+	---------------------------------------
+	|   7    |    6    |   5    |    4    |
+	---------------------------------------
+  | Proto   |      TimeStamp(3B)        |
+	| (1B)    |                           |
+	---------------------------------------
+*/
+typedef struct
+{
+	uint32_t time_stamp:24;
+  uint32_t protocol:8;
+}time_stamp_proto;
+
+
+/*
+	---------------------------------------------
+	|     3      |    2    |    1    |    0      |
+	---------------------------------------------
+  |       next_index     | Table entry         |
+	----------------------------------------------
+*/
+typedef struct {
+  uint16_t tbl_entry;
+  uint16_t next_index;
+}tbl_ent_nxt_indx;
+
+/*-------------------------------------------------- 
+   32 bit sw_spec_params is interpreted as follows 
+   ------------------------------------
+   |     16 bits     |     16 bits    |
+   ------------------------------------
+   |  index table    |  prev index    |
+   |     entry       |                |
+	 ------------------------------------
+--------------------------------------------------*/
+typedef struct {
+  uint16_t prev_index;
+  uint16_t index_table_entry;
+}sw_spec_params;
+
+/*------------------------  NAT Table Entry  ---------------------------------------
+ 
+  -----------------------------------------------------------------------------------
+  |   7    |    6    |   5    |    4    |     3      |    2    |    1    |    0      |
+  -----------------------------------------------------------------------------------
+  |             Target IP(4B)           |             Private IP(4B)                 |
+  -----------------------------------------------------------------------------------
+  |Target Port(2B)   | Private Port(2B) | Public Port(2B)     | Next Index(2B)       |
+  -----------------------------------------------------------------------------------
+  | Proto   |      TimeStamp(3B)        |       Flags(2B)     | IP check sum Diff(2B)|
+  | (1B)    |                           |EN|FIN|Resv |        |                      |  
+  -----------------------------------------------------------------------------------
+  | TCP/UDP checksum |  Reserved(2B)    |    SW Specific Parameters(4B)              |
+  |    diff (2B)                        |                                            |
+  -----------------------------------------------------------------------------------
+ 
+  Dont change below structure definition.
+  It should be same as above(little endian order)
+  -------------------------------------------------------------------------------*/
+struct ipa_nat_rule {
+  uint64_t private_ip:32;
+  uint64_t target_ip:32;
+
+  uint64_t nxt_indx_pub_port:32;
+  uint64_t private_port:16;
+  uint64_t target_port:16;
+
+  uint64_t ip_cksm_enbl:32;
+	uint64_t ts_proto:32;
+  
+  /*-------------------------------------------------- 
+   32 bit sw_spec_params is interpreted as follows 
+   ------------------------------------
+   |     16 bits     |     16 bits    |
+   ------------------------------------
+   |  index table    |  prev index    |
+   |     entry       |                |
+	 ------------------------------------
+  --------------------------------------------------*/
+	uint64_t sw_spec_params:32;
+
+  uint64_t rsvd2:16;
+  uint64_t tcp_udp_chksum:16;
+
+};
+
+struct ipa_nat_sw_rule {
+  uint64_t private_ip:32;
+  uint64_t target_ip:32;
+
+  uint64_t next_index:16;
+  uint64_t public_port:16;
+  uint64_t private_port:16;
+  uint64_t target_port:16;
+
+  uint64_t ip_chksum:16;
+  uint64_t rsvd1:14;
+  uint64_t redirect:1;
+  uint64_t enable:1;
+  uint64_t time_stamp:24;
+  uint64_t protocol:8;
+  
+  /*-------------------------------------------------- 
+   32 bit sw_spec_params is interpreted as follows 
+   ------------------------------------
+   |     16 bits     |     16 bits    |
+   ------------------------------------
+   |  index table    |  prev index    |
+   |     entry       |                |
+   ------------------------------------
+  --------------------------------------------------*/
+  uint64_t prev_index:16;
+  uint64_t indx_tbl_entry:16;
+  uint64_t rsvd2:16;
+  uint64_t tcp_udp_chksum:16;
+
+};
+#define IPA_NAT_TABLE_ENTRY_SIZE        32
+#define IPA_NAT_INDEX_TABLE_ENTRY_SIZE  4 
+
+struct ipa_nat_indx_tbl_rule {
+  uint32_t tbl_entry_nxt_indx;
+};
+
+struct ipa_nat_sw_indx_tbl_rule {
+  uint16_t tbl_entry;
+  uint16_t next_index;
+};
+
+struct ipa_nat_indx_tbl_meta_info {
+  uint16_t prev_index;
+};
+
+struct ipa_nat_ip4_table_cache {
+  uint8_t valid;
+  uint32_t public_addr;
+  
+  int nat_fd;
+  int size;
+  uint32_t tbl_addr_offset;
+  char table_name[IPA_RESOURCE_NAME_MAX];
+
+  char  *ipv4_rules_addr;
+  char  *index_table_addr;
+  uint16_t   table_entries;
+
+  char *ipv4_expn_rules_addr;
+  char *index_table_expn_addr;
+  uint16_t  expn_table_entries;
+  
+  struct ipa_nat_indx_tbl_meta_info *index_expn_table_meta;
+  
+  uint16_t *rule_id_array;
+#ifdef IPA_ON_R3PC
+  uint32_t mmap_offset;
+#endif
+};
+
+struct ipa_nat_cache {
+  struct ipa_nat_ip4_table_cache ip4_tbl[IPA_NAT_MAX_IP4_TBLS];
+  int ipa_fd;
+  uint8_t table_cnt;
+};
+
+struct ipa_nat_indx_tbl_sw_rule {
+  uint16_t tbl_entry;
+  uint16_t next_index;
+  uint16_t prev_index;
+};
+
+typedef enum 
+{
+  IPA_NAT_DEL_TYPE_ONLY_ONE,
+  IPA_NAT_DEL_TYPE_HEAD,
+  IPA_NAT_DEL_TYPE_MIDDLE,
+  IPA_NAT_DEL_TYPE_LAST,
+}del_type;
+
+/**
+ * ipa_nati_parse_ipv4_rule_hdl() - prase rule handle              
+ * @tbl_hdl:	[in] nat table rule 
+ * @rule_hdl: [in] nat rule handle 
+ * @expn_tbl: [out] expansion table or not 
+ * @tbl_entry: [out] index into table  
+ * 
+ * Parse the rule handle to retrieve the nat table 
+ * type and entry of nat table 
+ * 
+ * Returns:	None
+ */
+void ipa_nati_parse_ipv4_rule_hdl(uint8_t tbl_hdl,
+                                  uint16_t rule_hdl,
+                                  uint8_t *expn_tbl,
+                                  uint16_t *tbl_entry);
+
+/**
+ * ipa_nati_make_rule_hdl() - makes nat rule handle
+ * @tbl_hdl: [in] nat table handle 
+ * @tbl_entry: [in]  nat table entry
+ *  
+ * Calculate the nat rule handle which from 
+ * nat entry which will be returned to client of 
+ * nat driver 
+ *
+ * Returns:	>0 nat rule handle
+ */
+uint16_t ipa_nati_make_rule_hdl(uint16_t tbl_hdl, 
+                           uint16_t tbl_entry);
+
+uint32_t ipa_nati_get_index_entry_offset(struct ipa_nat_ip4_table_cache *cache_ptr,
+                                    nat_table_type tbl_type,
+                                    uint16_t indx_tbl_entry);
+uint32_t ipa_nati_get_entry_offset(struct ipa_nat_ip4_table_cache *cache_ptr,
+                              nat_table_type tbl_type,
+                              uint16_t  tbl_entry);
+
+int ipa_nati_add_ipv4_tbl(uint32_t public_ip_addr,
+                          uint16_t number_of_entries,
+                          uint32_t *table_hanle);
+
+int ipa_nati_alloc_table(uint16_t number_of_entries,
+                         struct ipa_ioc_nat_alloc_mem *mem,
+                         uint16_t *tbl_entries, uint16_t *expn_tbl_entries);
+
+int ipa_nati_update_cache(struct ipa_ioc_nat_alloc_mem *,
+                          uint32_t public_ip_addr,
+                          uint16_t tbl_entries,
+                          uint16_t expn_tbl_entries);
+
+int ipa_nati_del_ipv4_table(uint32_t tbl_hdl);
+int ipa_nati_reset_ipv4_table(uint32_t tbl_hdl);
+int ipa_nati_post_ipv4_init_cmd(uint8_t tbl_index);
+
+int ipa_nati_query_timestamp(uint32_t  tbl_hdl,
+                            uint32_t  rule_hdl,
+                            uint32_t  *time_stamp);
+
+uint32_t ipa_nati_add_ipv4_rule(uint32_t tbl_hdl, 
+                           const ipa_nat_ipv4_rule *clnt_rule);
+
+int ipa_nati_generate_rule(uint32_t tbl_hdl,
+                           const ipa_nat_ipv4_rule *clnt_rule,
+                           struct ipa_nat_sw_rule *rule,
+                           struct ipa_nat_indx_tbl_sw_rule *index_sw_rule,
+                           uint16_t *tbl_entry,
+                           uint16_t *indx_tbl_entry);
+uint16_t ipa_nati_expn_tbl_free_entry(struct ipa_nat_rule *expn_tbl,
+                                 uint16_t size);
+uint16_t ipa_nati_generate_tbl_rule(const ipa_nat_ipv4_rule *clnt_rule,
+                               struct ipa_nat_sw_rule *sw_rule,
+                               struct ipa_nat_ip4_table_cache *tbl_ptr);
+uint16_t ipa_nati_generate_index_rule(const ipa_nat_ipv4_rule *clnt_rule,
+                                    struct ipa_nat_indx_tbl_sw_rule *sw_rule,
+                                    struct ipa_nat_ip4_table_cache *tbl_ptr);
+uint16_t ipa_nati_index_expn_get_free_entry(struct ipa_nat_indx_tbl_rule *tbl,
+                                       uint16_t size);
+
+void ipa_nati_copy_ipv4_rule_to_hw(
+                     struct ipa_nat_ip4_table_cache *ipv4_cache,
+                     struct ipa_nat_sw_rule *rule,
+                     uint16_t entry, uint8_t tbl_index);
+void ipa_nati_copy_ipv4_index_rule_to_hw(
+                     struct ipa_nat_ip4_table_cache *ipv4_cache,
+                     struct ipa_nat_indx_tbl_sw_rule *indx_sw_rule,
+                     uint16_t entry, uint8_t tbl_index);
+
+void ipa_nati_write_next_index(uint8_t tbl_indx,
+															nat_table_type tbl_type,
+															uint16_t value,
+															uint32_t offset);
+int ipa_nati_post_ipv4_dma_cmd(uint8_t tbl_indx,
+                               uint16_t entry);
+
+int ipa_nati_del_ipv4_rule(uint32_t tbl_hdl,
+                      uint32_t rule_hdl);
+int ipa_nati_post_del_dma_cmd(uint8_t tbl_indx,
+                              uint16_t tbl_entry,
+                              uint8_t expn_tbl,
+                              del_type rule_pos);
+void ipa_nati_find_index_rule_pos(
+              struct ipa_nat_ip4_table_cache *cache_ptr,
+              uint16_t tbl_entry,
+              del_type *rule_pos);
+void ipa_nati_del_dead_ipv4_head_nodes(uint8_t tbl_indx);
+void ipa_nati_find_rule_pos(struct ipa_nat_ip4_table_cache *cache_ptr,
+                            uint8_t expn_tbl,
+                            uint16_t tbl_entry,
+                            del_type *rule_pos);
+void ipa_nati_del_dead_ipv4_head_nodes(uint8_t tbl_indx);
+
+
+/* ========================================================
+            Debug functions
+   ========================================================*/
+#ifdef NAT_DUMP
+void ipa_nati_print_rule(struct ipa_nat_rule *rule, uint32_t rule_id);
+void ipa_nati_dump_rule_buf(void *param1, uint8_t size, uint32_t rule_id);
+void ipa_nat_dump_ipv4_table(uint32_t tbl_hdl);
+void ipa_nati_dump_index_rule_buf(void *param1, uint8_t size, uint32_t rule_id);
+#endif
+
+#endif /* #ifndef IPA_NAT_DRVI_H */
diff --git a/ipanat/inc/ipa_nat_logi.h b/ipanat/inc/ipa_nat_logi.h
new file mode 100644
index 0000000..0ffa672
--- /dev/null
+++ b/ipanat/inc/ipa_nat_logi.h
@@ -0,0 +1,79 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	ipa_nat_logi.h
+
+	@brief
+	This file implements the IPAM log functionality.
+
+	@Author
+	
+
+*/
+
+#ifndef IPA_NAT_LOGI_H
+#define IPA_NAT_LOGI_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#define NAT_LOG_SIZE 200
+
+#define PERROR(fmt)   printf("%s:%d %s()", __FILE__, __LINE__, __FUNCTION__);\
+                      perror(fmt);
+
+#define IPADBG(fmt, ...) {\
+                             int n =0; \
+                             n = snprintf(nat_log_buf, sizeof(nat_log_buf), "%s:%d %s() ", __FILE__,  __LINE__, __FUNCTION__);\
+                             snprintf((nat_log_buf+n), (sizeof(nat_log_buf)-n-1), fmt, ##__VA_ARGS__);\
+                             log_nat_message(nat_log_buf);\
+				  		             }
+
+
+#define IPAERR(fmt, ...) {\
+                             int n =0; \
+                             n = snprintf(nat_log_buf, sizeof(nat_log_buf), "%s:%d %s() %s", __FILE__,  __LINE__, __FUNCTION__, "Error:");\
+                             snprintf((nat_log_buf+n), (sizeof(nat_log_buf)-n-1), fmt, ##__VA_ARGS__);\
+                             log_nat_message(nat_log_buf);\
+				  		             }
+
+extern void log_nat_message(char *msg);
+extern char nat_log_buf[NAT_LOG_SIZE];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IPA_NAT_LOGI_H */
diff --git a/ipanat/src/Makefile.am b/ipanat/src/Makefile.am
new file mode 100644
index 0000000..cf9fc3f
--- /dev/null
+++ b/ipanat/src/Makefile.am
@@ -0,0 +1,20 @@
+AM_CFLAGS = -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs
+AM_CFLAGS += -I./../inc -I$(WORKSPACE)/kernel/include
+
+c_sources   = ipa_nat_drv.c \
+              ipa_nat_drvi.c \
+			  ipa_nat_logi.c
+
+library_includedir = $(pkgincludedir)
+library_include_HEADERS = ./../inc/ipa_nat_drvi.h \
+                          ./../inc/ipa_nat_drv.h \
+						  ./../inc/ipa_nat_logi.h
+
+lib_LTLIBRARIES = libipanat.la
+libipanat_la_C = @C@
+libipanat_la_SOURCES = $(c_sources)
+libipanat_la_CFLAGS = $(AM_CFLAGS)
+libipanat_la_LDFLAGS = -shared -version-info 1:0:0	
+						  
+
+
diff --git a/ipanat/src/ipa_nat_drv.c b/ipanat/src/ipa_nat_drv.c
new file mode 100644
index 0000000..68e2de8
--- /dev/null
+++ b/ipanat/src/ipa_nat_drv.c
@@ -0,0 +1,177 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "ipa_nat_drv.h"
+#include "ipa_nat_drvi.h"
+
+/**
+ * ipa_nat_add_ipv4_tbl() - create ipv4 nat table
+ * @public_ip_addr: [in] public ipv4 address  
+ * @number_of_entries: [in]  number of nat entries 
+ * @table_handle: [out] Handle of new ipv4 nat table 
+ *  
+ * To create new ipv4 nat table 
+ *
+ * Returns:	0  On Success, negative on failure
+ */
+int ipa_nat_add_ipv4_tbl(uint32_t public_ip_addr,
+                         uint16_t number_of_entries,
+                         uint32_t *tbl_hdl)
+{
+  int ret;
+  
+  if (NULL == tbl_hdl || 0 == number_of_entries)
+  {
+    IPAERR("Invalid parameters \n");
+    return -1;
+  }
+             
+  ret = ipa_nati_add_ipv4_tbl(public_ip_addr,
+                              number_of_entries,
+                              tbl_hdl);
+  if (ret != 0)
+  {
+    IPAERR("unable to add table \n");
+    return -1;
+  }
+  IPADBG("Returning table handle 0x%x\n", *tbl_hdl);
+
+  return ret;
+} /* __ipa_nat_add_ipv4_tbl() */
+
+/**
+ * ipa_nat_del_ipv4_tbl() - delete ipv4 table
+ * @table_handle: [in] Handle of ipv4 nat table 
+ *  
+ * To delete given ipv4 nat table 
+ *
+ * Returns:	0  On Success, negative on failure
+ */
+int ipa_nat_del_ipv4_tbl(uint32_t tbl_hdl)
+{
+  if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl || 
+      tbl_hdl > IPA_NAT_MAX_IP4_TBLS)
+  {
+    IPAERR("invalid table handle passed \n");
+    return -1;
+  }
+  IPADBG("Passed Table Handle: 0x%x\n", tbl_hdl);
+
+  return ipa_nati_del_ipv4_table(tbl_hdl);
+}
+
+/**
+ * ipa_nat_add_ipv4_rule() - to insert new ipv4 rule
+ * @table_handle: [in] handle of ipv4 nat table  
+ * @rule: [in]  Pointer to new rule 
+ * @rule_handle: [out] Return the handle to rule 
+ *  
+ * To insert new ipv4 nat rule into ipv4 nat table 
+ *
+ * Returns:	0  On Success, negative on failure
+ */
+int ipa_nat_add_ipv4_rule(uint32_t tbl_hdl, 
+                          const ipa_nat_ipv4_rule *clnt_rule,
+                          uint32_t *rule_hdl)
+{
+
+  if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl || 
+      tbl_hdl > IPA_NAT_MAX_IP4_TBLS || NULL == rule_hdl ||
+      NULL == clnt_rule)
+  {
+    IPAERR("invalide table handle passed \n");
+    return -1;
+  }
+  IPADBG("Passed Table handle: 0x%x\n", tbl_hdl);
+
+  *rule_hdl = ipa_nati_add_ipv4_rule(tbl_hdl, clnt_rule);
+  IPADBG("returning rule handle 0x%x\n", *rule_hdl);
+
+  return 0;
+}
+
+
+/**
+ * ipa_nat_del_ipv4_rule() - to delete ipv4 nat rule
+ * @table_handle: [in] handle of ipv4 nat table  
+ * @rule_handle: [in] ipv4 nat rule handle
+ *  
+ * To insert new ipv4 nat rule into ipv4 nat table 
+ *
+ * Returns:	0  On Success, negative on failure
+ */
+int ipa_nat_del_ipv4_rule(uint32_t tbl_hdl,
+                          uint32_t rule_hdl)
+{
+
+  if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl ||
+      IPA_NAT_INVALID_NAT_ENTRY == rule_hdl)
+  {
+    IPAERR("invalide parameters\n");
+    return -1;
+  }
+  IPADBG("Passed Table: 0x%x and rule handle 0x%x\n", tbl_hdl, rule_hdl);
+
+  if (-1 == ipa_nati_del_ipv4_rule(tbl_hdl, rule_hdl))
+  {
+    IPAERR("unable to delete rule from hw \n");
+    return -1;
+  }
+
+  return 0;
+}
+
+/**
+ * ipa_nat_query_timestamp() - to query timestamp
+ * @table_handle: [in] handle of ipv4 nat table  
+ * @rule_handle: [in] ipv4 nat rule handle 
+ * @time_stamp: [out] time stamp of rule 
+ *  
+ * To retrieve the timestamp that lastly the 
+ * nat rule was accessed 
+ *
+ * Returns:	0  On Success, negative on failure
+ */
+int ipa_nat_query_timestamp(uint32_t  tbl_hdl,
+                            uint32_t  rule_hdl,
+                            uint32_t  *time_stamp)
+{
+
+  if (0 == tbl_hdl || tbl_hdl > IPA_NAT_MAX_IP4_TBLS ||
+      NULL == time_stamp)
+  {
+    IPAERR("invalid parameters passed \n");
+    return -1;
+  }
+  IPADBG("Passed Table: 0x%x and rule handle 0x%x\n", tbl_hdl, rule_hdl);
+
+  return ipa_nati_query_timestamp(tbl_hdl, rule_hdl, time_stamp);
+}
+
+
diff --git a/ipanat/src/ipa_nat_drvi.c b/ipanat/src/ipa_nat_drvi.c
new file mode 100644
index 0000000..d542a88
--- /dev/null
+++ b/ipanat/src/ipa_nat_drvi.c
@@ -0,0 +1,2387 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "ipa_nat_drv.h"
+#include "ipa_nat_drvi.h"
+
+struct ipa_nat_cache ipv4_nat_cache;
+
+/* ------------------------------------------
+    UTILITY FUNCTIONS START 
+   --------------------------------------------*/
+
+/**
+ * UpdateSwSpecParams() - updates sw specific params
+ * @rule:	[in/out] nat table rule 
+ * @param_type: [in] which param need to update
+ * @value: [in] value of param 
+ *  
+ * Update SW specific params in the passed rule.
+ *
+ * Returns:	None
+ */
+void UpdateSwSpecParams(struct ipa_nat_rule *rule, 
+                              uint8_t param_type, 
+															uint32_t value)
+{
+  
+ uint32_t temp = rule->sw_spec_params;   
+
+  if(IPA_NAT_SW_PARAM_INDX_TBL_ENTRY_BYTE == param_type)
+  {
+		value = (value << INDX_TBL_ENTRY_SIZE_IN_BITS);
+  }
+  
+  temp = (temp | value);
+  rule->sw_spec_params = temp;
+  return;
+}
+
+/**
+ * Read8BitFieldValue()
+ * @rule:	[in/out]
+ * @param_type: [in]
+ * @value: [in]
+ *  
+ * 
+ *
+ * Returns:	None
+ */
+
+uint8_t Read8BitFieldValue(uint32_t param,
+														ipa_nat_rule_field_type fld_type)
+{
+
+	void *temp = (void *)&param;
+
+	switch (fld_type)
+	{
+
+	case PROTOCOL_FIELD:
+		return ((time_stamp_proto *)temp)->protocol;
+
+	default:
+		IPAERR("Invalid Field type passed\n");
+		return 0;
+	}
+
+}
+
+uint16_t Read16BitFieldValue(uint32_t param,
+														 ipa_nat_rule_field_type fld_type)
+{
+
+	void *temp = (void *)&param;
+
+	switch (fld_type)
+	{
+
+	case NEXT_INDEX_FIELD:
+		return ((next_index_pub_port *)temp)->next_index;
+
+	case PUBLIC_PORT_FILED:
+		return ((next_index_pub_port *)temp)->public_port;
+
+	case ENABLE_FIELD:
+		return ((ipcksum_enbl *)temp)->enable;
+
+	case SW_SPEC_PARAM_PREV_INDEX_FIELD:
+		return ((sw_spec_params *)temp)->prev_index;
+
+	case SW_SPEC_PARAM_INDX_TBL_ENTRY_FIELD:
+		return ((sw_spec_params *)temp)->index_table_entry;
+
+	case INDX_TBL_TBL_ENTRY_FIELD:
+		return ((tbl_ent_nxt_indx *)temp)->tbl_entry;
+
+	case INDX_TBL_NEXT_INDEX_FILED:
+		return ((tbl_ent_nxt_indx *)temp)->next_index;
+
+#ifdef NAT_DUMP
+	case IP_CHKSUM_FIELD:
+		return ((ipcksum_enbl *)temp)->ip_chksum;
+#endif
+
+	default:
+		IPAERR("Invalid Field type passed\n");
+		return 0;
+	}
+
+}
+
+uint32_t Read32BitFieldValue(uint32_t param,
+														 ipa_nat_rule_field_type fld_type)
+{
+
+	void *temp = (void *)&param;
+
+	switch (fld_type)
+	{
+
+	case TIME_STAMP_FIELD:
+		return ((time_stamp_proto *)temp)->time_stamp;
+
+	default:
+		IPAERR("Invalid Field type passed\n");
+		return 0;
+	}
+
+}
+
+
+/**
+ * CreateNatDevice() - Create nat devices
+ * @mem: [in] name of device that need to create
+ *	
+ * Create Nat device and Register for file create 
+ * notification in given directory and wait till
+ * receive notification
+ *
+ * Returns:	0 on success, negative on failure
+ */
+int CreateNatDevice(struct ipa_ioc_nat_alloc_mem *mem)
+{
+
+#define EVENT_SIZE  (sizeof (struct inotify_event))
+#define FILE_NAME_LENGTH (sizeof(NAT_DEV_NAME)*2 + 1)
+#define BUF_LEN     (EVENT_SIZE + FILE_NAME_LENGTH)
+
+  int length;
+  int wd;
+  char buffer[BUF_LEN];
+  int ret, inotify_fd;
+
+  inotify_fd = inotify_init();
+  if (inotify_fd < 0)
+  {
+    perror("inotify_init");
+    return -1;
+  }
+
+  IPADBG("Waiting for nofications in dir %s\n", NAT_DEV_DIR);
+  wd = inotify_add_watch(inotify_fd,
+                         NAT_DEV_DIR,
+                         IN_CREATE);
+  
+  ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_ALLOC_NAT_MEM, mem);
+  if (ret != 0)
+  {
+    perror("CreateNatDevice(): ioctl error value");
+    IPAERR("unable to post nat mem init. Error ;%d\n", ret);
+    IPADBG("ipa fd %d\n",ipv4_nat_cache.ipa_fd);
+    return -1;
+  }
+  IPADBG("posted IPA_IOC_ALLOC_NAT_MEM to kernel successfully \n");
+
+  length = read(inotify_fd, buffer, BUF_LEN );  
+
+  if (length < 0)
+  {
+    perror("inotify read");
+    return -1;
+  }
+
+  struct inotify_event *event = (struct inotify_event *)buffer;
+  if(event->len)
+  {
+    if(event->mask & IN_CREATE)
+    {
+      if( event->mask & IN_ISDIR)
+      {
+        IPADBG("The directory %s was created.\n", event->name);       
+      }
+      else
+      {
+        IPADBG("The file %s was created.\n", event->name);
+      }
+    }
+  }
+
+  (void) inotify_rm_watch(inotify_fd, wd);
+  (void) close(inotify_fd);
+  return 0;
+}
+
+/**
+ * GetNearest2Power() - Returns the nearest power of 2
+ * @num: [in] given number
+ * @ret: [out] nearest power of 2
+ *  
+ * Returns the nearest power of 2 for a
+ * given number
+ *
+ * Returns:	0 on success, negative on failure
+ */
+int GetNearest2Power (uint16_t num, uint16_t *ret)
+{
+  uint16_t number = num;
+  uint16_t tmp = 1;
+  *ret = 0;
+
+  if(0 == num)
+  {
+    return -1;
+  }
+
+  if(1 == num)
+  {
+    *ret = 2;
+    return 0;
+  }
+
+  for(;;)
+  {
+    if(1 == num) 
+    {
+      if(number != tmp)
+      {
+        tmp *= 2;
+      }
+
+      *ret = tmp;
+      return 0;
+    }
+
+    num >>= 1;
+    tmp *= 2;
+  }
+
+  return -1;
+}
+
+/**
+ * GetNearestEven() - Returns the nearest even number
+ * @num: [in] given number
+ * @ret: [out] nearest even number
+ *  
+ * Returns the nearest even number for a given number
+ *
+ * Returns:	0 on success, negative on failure
+ */
+void GetNearestEven (uint16_t num, uint16_t *ret)
+{
+
+  if(num < 2)
+  {
+		*ret = 2;
+    return;
+  }
+
+	while ((num % 2) != 0)
+	{
+		num = num + 1;
+	}
+
+	*ret = num;
+  return;
+}
+
+/**
+ * dst_hash() - Find the index into ipv4 base table
+ * @trgt_ip: [in] Target IP address 
+ * @trgt_port: [in]  Target port 
+ * @public_port: [in]  Public port 
+ * @proto: [in] Protocol (TCP/IP) 
+ * @size: [in] size of the ipv4 base Table
+ *  
+ * This hash method is used to find the hash index of new nat 
+ * entry into ipv4 base table. In case of zero index, the 
+ * new entry will be stored into N-1 index where N is size of 
+ * ipv4 base table
+ *
+ * Returns:	>0 index into ipv4 base table, negative on failure
+ */
+static uint16_t dst_hash(uint32_t trgt_ip, uint16_t trgt_port, 
+												 uint16_t public_port, uint8_t proto, 
+												 uint16_t size)
+{
+  uint16_t hash = ((uint16_t)(trgt_ip)) ^ ((uint16_t)(trgt_ip>>16)) ^ 
+             (trgt_port) ^ (public_port) ^ (proto);
+ 
+  IPADBG("trgt_ip: 0x%x trgt_port: 0x%x\n", trgt_ip, trgt_port);
+  IPADBG("public_port: 0x%x\n", public_port);
+  IPADBG("proto: 0x%x size: 0x%x\n", proto, size);
+
+  hash = (hash & size);
+
+  /* If the hash resulted to zero then set it to maximum value
+     as zero is unused entry in nat tables */
+  if (0 == hash)
+  {
+    return size;
+  }
+  
+  IPADBG("dst_hash returning value: %d\n", hash);
+  return hash;
+}
+
+/**
+ * src_hash() - Find the index into ipv4 index base table
+ * @priv_ip: [in] Private IP address 
+ * @priv_port: [in]  Private port 
+ * @trgt_ip: [in]  Target IP address  
+ * @trgt_port: [in] Target Port 
+ * @proto: [in]  Protocol (TCP/IP) 
+ * @size: [in] size of the ipv4 index base Table
+ *  
+ * This hash method is used to find the hash index of new nat 
+ * entry into ipv4 index base table. In case of zero index, the 
+ * new entry will be stored into N-1 index where N is size of 
+ * ipv4 index base table
+ *
+ * Returns:	>0 index into ipv4 index base table, negative on failure
+ */
+static uint16_t src_hash(uint32_t priv_ip, uint16_t priv_port, uint32_t trgt_ip, uint16_t trgt_port, uint8_t proto, uint16_t size)
+{
+  uint16_t hash =  ((uint16_t)(priv_ip)) ^ ((uint16_t)(priv_ip>>16)) ^ 
+              (priv_port) ^ 
+              ((uint16_t)(trgt_ip)) ^ ((uint16_t)(trgt_ip>>16)) ^
+              (trgt_port) ^ (proto);
+
+  IPADBG("priv_ip: 0x%x priv_port: 0x%x\n", priv_ip, priv_port);
+  IPADBG("trgt_ip: 0x%x trgt_port: 0x%x\n", trgt_ip, trgt_port);
+  IPADBG("proto: 0x%x size: 0x%x\n", proto, size);
+  
+  hash = (hash & size);
+
+  /* If the hash resulted to zero then set it to maximum value
+     as zero is unused entry in nat tables */
+  if (0 == hash)
+  {
+    return size;
+  }
+
+  IPADBG("src_hash returning value: %d\n", hash);
+  return hash;
+}
+
+/**
+ * ipa_nati_calc_ip_cksum() - Calculate the source nat
+ *                             IP checksum diff
+ * @pub_ip_addr: [in] public ip address 
+ * @priv_ip_addr: [in]  Private ip address
+ *  
+ * source nat ip checksum different is calculated as 
+ * public_ip_addr - private_ip_addr 
+ * Here we are using 1's complement to represent -ve number.
+ * So take 1's complement of private ip addr and add it 
+ * to public ip addr.
+ *
+ * Returns:	>0 ip checksum diff
+ */
+static uint16_t ipa_nati_calc_ip_cksum(uint32_t pub_ip_addr,
+                                  uint32_t priv_ip_addr)
+{
+   uint16_t ret;
+   uint32_t cksum = 0;
+
+   /* Add LSB(2 bytes) of public ip address to cksum */
+   cksum += (pub_ip_addr & 0xFFFF);
+   
+   /* Add MSB(2 bytes) of public ip address to cksum
+     and check for carry forward(CF), if any add it
+   */
+   cksum += (pub_ip_addr>>16);
+   if (cksum>>16)
+   {
+     cksum = (cksum & 0x0000FFFF);
+     cksum += 1;
+   }
+  
+   /* Calculate the 1's complement of private ip address */
+   priv_ip_addr = (~priv_ip_addr);
+   
+   /* Add LSB(2 bytes) of private ip address to cksum
+      and check for carry forward(CF), if any add it
+   */
+   cksum += (priv_ip_addr & 0xFFFF); 
+   if (cksum>>16)
+   {
+     cksum = (cksum & 0x0000FFFF);
+     cksum += 1;
+   }
+   
+   /* Add MSB(2 bytes) of private ip address to cksum
+      and check for carry forward(CF), if any add it
+   */
+   cksum += (priv_ip_addr>>16);
+   if (cksum>>16)
+   {
+     cksum = (cksum & 0x0000FFFF);
+     cksum += 1;
+   }
+
+   /* Return the LSB(2 bytes) of checksum  */
+   ret = (uint16_t)cksum;
+   return ret;
+
+}
+
+/**
+ * ipa_nati_calc_tcp_udp_cksum() - Calculate the source nat
+ *                                TCP/UDP checksum diff
+ * @pub_ip_addr: [in] public ip address 
+ * @pub_port: [in] public tcp/udp port 
+ * @priv_ip_addr: [in]  Private ip address 
+ * @priv_port: [in] Private tcp/udp prot 
+ *  
+ * source nat tcp/udp checksum is calculated as 
+ * (pub_ip_addr + pub_port) - (priv_ip_addr + priv_port)
+ * Here we are using 1's complement to represent -ve number.
+ * So take 1's complement of prviate ip addr &private port 
+ * and add it public ip addr & public port.
+ *
+ * Returns:	>0 tcp/udp checksum diff
+ */
+static uint16_t ipa_nati_calc_tcp_udp_cksum(uint32_t pub_ip_addr,  uint16_t pub_port,
+                                       uint32_t priv_ip_addr, uint16_t priv_port)
+{
+   uint16_t ret=0;
+   uint32_t cksum =0;
+
+   /* Add LSB(2 bytes) of public ip address to cksum */
+   cksum += (pub_ip_addr & 0xFFFF);
+   
+   /* Add MSB(2 bytes) of public ip address to cksum
+     and check for carry forward(CF), if any add it
+   */   
+   cksum += (pub_ip_addr>>16);
+   if (cksum>>16)
+   {
+     cksum = (cksum & 0x0000FFFF);
+     cksum += 1;
+   }
+   
+   /* Add public port to cksum and 
+      check for carry forward(CF), if any add it */  
+   cksum += pub_port;   
+   if (cksum>>16)
+   {
+     cksum = (cksum & 0x0000FFFF);
+     cksum += 1;
+   }
+
+   /* Calculate the 1's complement of private ip address */
+   priv_ip_addr = (~priv_ip_addr);
+   
+   /* Add LSB(2 bytes) of private ip address to cksum
+      and check for carry forward(CF), if any add it
+   */
+   cksum += (priv_ip_addr & 0xFFFF);
+   if (cksum>>16)
+   {
+     cksum = (cksum & 0x0000FFFF);
+     cksum += 1;
+   }
+   
+   /* Add MSB(2 bytes) of private ip address to cksum
+      and check for carry forward(CF), if any add 
+   */
+   cksum += (priv_ip_addr>>16);
+   if (cksum>>16)
+   {
+     cksum = (cksum & 0x0000FFFF);
+     cksum += 1;
+   }
+
+  /* Calculate the 1's complement of private port */
+   priv_port = (~priv_port);
+   
+   /* Add public port to cksum and 
+    check for carry forward(CF), if any add it */ 
+   cksum += priv_port;
+   if (cksum>>16)
+   {
+     cksum = (cksum & 0x0000FFFF);
+     cksum += 1;
+   }
+
+   /* return the LSB(2 bytes) of checksum */
+   ret = (uint16_t)cksum;
+   return ret;
+   
+}
+
+/**
+ * ipa_nati_make_rule_hdl() - makes nat rule handle
+ * @tbl_hdl: [in] nat table handle 
+ * @tbl_entry: [in]  nat table entry
+ *  
+ * Calculate the nat rule handle which from 
+ * nat entry which will be returned to client of 
+ * nat driver 
+ *
+ * Returns:	>0 nat rule handle
+ */
+uint16_t ipa_nati_make_rule_hdl(uint16_t tbl_hdl, 
+                                uint16_t tbl_entry)
+{
+  struct ipa_nat_ip4_table_cache *tbl_ptr;
+  uint16_t rule_hdl = 0;
+  uint16_t cnt = 0;
+  
+  tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_hdl-1];
+
+  if (tbl_entry >= tbl_ptr->table_entries)
+  {
+    /* Update the index into table */
+    rule_hdl = tbl_entry - tbl_ptr->table_entries;
+    rule_hdl = (rule_hdl << IPA_NAT_RULE_HDL_TBL_TYPE_BITS);
+    /* Update the table type mask */
+    rule_hdl = (rule_hdl | IPA_NAT_RULE_HDL_TBL_TYPE_MASK);
+  }
+  else
+  {
+    rule_hdl = tbl_entry;
+    rule_hdl = (rule_hdl << IPA_NAT_RULE_HDL_TBL_TYPE_BITS);
+  }
+
+  for(; cnt< (tbl_ptr->table_entries + tbl_ptr->expn_table_entries); cnt++)
+  {
+    if (IPA_NAT_INVALID_NAT_ENTRY == tbl_ptr->rule_id_array[cnt])
+    {
+      tbl_ptr->rule_id_array[cnt] = rule_hdl;
+      return (cnt+1);
+    }
+  }
+
+  return cnt;
+}
+
+/**
+ * ipa_nati_parse_ipv4_rule_hdl() - prase rule handle              
+ * @tbl_hdl:	[in] nat table rule 
+ * @rule_hdl: [in] nat rule handle 
+ * @expn_tbl: [out] expansion table or not 
+ * @tbl_entry: [out] index into table  
+ * 
+ * Parse the rule handle to retrieve the nat table 
+ * type and entry of nat table 
+ * 
+ * Returns:	None
+ */
+void ipa_nati_parse_ipv4_rule_hdl(uint8_t tbl_index,
+                                  uint16_t rule_hdl,
+                                  uint8_t *expn_tbl,
+                                  uint16_t *tbl_entry)
+{
+  struct ipa_nat_ip4_table_cache *tbl_ptr;
+  uint16_t rule_id;
+
+  *expn_tbl = 0;
+  *tbl_entry = IPA_NAT_INVALID_NAT_ENTRY;
+  tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_index];
+
+  if (rule_hdl >= (tbl_ptr->table_entries + tbl_ptr->expn_table_entries))
+  {
+    IPAERR("invalid rule handle\n");
+    return;
+  }
+
+  rule_id = tbl_ptr->rule_id_array[rule_hdl-1];
+ 
+  /* Retrieve the table type */
+  *expn_tbl = 0;
+  if(rule_id & IPA_NAT_RULE_HDL_TBL_TYPE_MASK)
+  {
+    *expn_tbl = 1;
+  }
+  
+  /* Retrieve the table entry */
+  *tbl_entry = (rule_id >> IPA_NAT_RULE_HDL_TBL_TYPE_BITS);
+  
+  return;
+}
+
+uint32_t ipa_nati_get_entry_offset(struct ipa_nat_ip4_table_cache *cache_ptr,
+                              nat_table_type tbl_type,
+                              uint16_t  tbl_entry)
+{
+  struct ipa_nat_rule *tbl_ptr;
+  uint32_t ret = 0;
+  
+  if (IPA_NAT_EXPN_TBL == tbl_type)
+  {
+    tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr;
+  }
+  else
+  {
+    tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr;
+  }
+	
+  ret = (char *)&tbl_ptr[tbl_entry] - (char *)tbl_ptr;
+  ret += cache_ptr->tbl_addr_offset;
+  return ret;
+}
+
+uint32_t ipa_nati_get_index_entry_offset(struct ipa_nat_ip4_table_cache *cache_ptr,
+                                    nat_table_type tbl_type,
+                                    uint16_t indx_tbl_entry)
+{
+  struct ipa_nat_indx_tbl_rule *indx_tbl_ptr;
+  uint32_t ret = 0;
+
+  if (IPA_NAT_INDEX_EXPN_TBL == tbl_type)
+  {
+    indx_tbl_ptr = 
+      (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr;
+  }
+  else
+  {
+    indx_tbl_ptr = 
+      (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr;
+  }
+
+  ret = (char *)&indx_tbl_ptr[indx_tbl_entry] - (char *)indx_tbl_ptr;
+  ret += cache_ptr->tbl_addr_offset;
+  return ret;
+}
+
+/* ------------------------------------------
+    UTILITY FUNCTIONS END
+--------------------------------------------*/
+
+/* ------------------------------------------
+   Main Functions
+--------------------------------------------**/
+void ipa_nati_reset_tbl(uint8_t tbl_indx)
+{
+  uint16_t table_entries = ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries;
+  uint16_t expn_table_entries = ipv4_nat_cache.ip4_tbl[tbl_indx].expn_table_entries;
+
+  /* Base table */
+	IPADBG("memset() base table to 0, %p\n",
+				   ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr);
+
+  memset(ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr,
+         0,
+         IPA_NAT_TABLE_ENTRY_SIZE * table_entries);
+
+	/* Base expansino table */
+	IPADBG("memset() expn base table to 0, %p\n",
+				   ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_expn_rules_addr);
+
+  memset(ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_expn_rules_addr,
+         0,
+         IPA_NAT_TABLE_ENTRY_SIZE * expn_table_entries);
+	
+  /* Index table */
+	IPADBG("memset() index table to 0, %p\n",
+				   ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_addr);
+
+  memset(ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_addr,
+         0,
+         IPA_NAT_INDEX_TABLE_ENTRY_SIZE * table_entries);
+
+  /* Index expansion table */
+	IPADBG("memset() index expn table to 0, %p\n",
+				   ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_expn_addr);
+
+  memset(ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_expn_addr,
+         0,
+         IPA_NAT_INDEX_TABLE_ENTRY_SIZE * expn_table_entries);
+
+	IPADBG("returning from ipa_nati_reset_tbl()\n");
+  return;
+}
+
+int ipa_nati_add_ipv4_tbl(uint32_t public_ip_addr,
+                          uint16_t number_of_entries,
+                          uint32_t *tbl_hdl)
+{
+  struct ipa_ioc_nat_alloc_mem mem;
+  uint8_t tbl_indx = ipv4_nat_cache.table_cnt;
+  uint16_t table_entries, expn_table_entries;
+  int ret;
+  
+  *tbl_hdl = 0;
+  /* Allocate table */
+  memset(&mem, 0, sizeof(mem));
+  ret = ipa_nati_alloc_table(number_of_entries,
+                             &mem,
+                             &table_entries,
+                             &expn_table_entries);
+  if (0 != ret)
+  {
+    IPAERR("unable to allocate nat table\n");
+    return -1;
+  }
+
+  /* Update the cache 
+     The (IPA_NAT_UNUSED_BASE_ENTRIES/2) indicates zero entry entries
+     for both base and expansion table
+  */
+  ret = ipa_nati_update_cache(&mem, 
+                              public_ip_addr,
+                              table_entries,
+                              expn_table_entries);
+  if (0 != ret)
+  {
+    IPAERR("unable to update cache Error: %d\n", ret);
+    return -1;
+  }
+
+  /* Initialize the ipa hw with nat table dimensions */
+  ret = ipa_nati_post_ipv4_init_cmd(tbl_indx);
+  if (0 != ret)
+  {
+    IPAERR("unable to post nat_init command Error %d\n", ret);
+    return -1;
+  }
+
+  ipa_nati_reset_tbl(tbl_indx);
+
+  /* Return table handle */
+  ipv4_nat_cache.table_cnt++;
+  *tbl_hdl = ipv4_nat_cache.table_cnt;
+
+#ifdef NAT_DUMP
+  ipa_nat_dump_ipv4_table(*tbl_hdl);
+#endif
+  return 0;
+}
+
+int ipa_nati_alloc_table(uint16_t number_of_entries,
+                         struct ipa_ioc_nat_alloc_mem *mem,
+                         uint16_t *table_entries,
+                         uint16_t *expn_table_entries)
+{
+  int fd = 0, ret;
+  uint16_t total_entries;  
+  
+  /* Copy the table name */
+  strcpy(mem->dev_name, NAT_DEV_NAME);  
+
+  /* Calculate the size for base table and expansion table */
+  *table_entries = (uint16_t)(number_of_entries * IPA_NAT_BASE_TABLE_PERCENTAGE);
+  if(*table_entries == 0)
+  {
+    *table_entries = 1;
+  }
+  if(-1 == GetNearest2Power(*table_entries, table_entries))
+  {
+    IPAERR("unable to calculate power of 2\n");
+    return -1;
+  }
+  
+  *expn_table_entries = (uint16_t)(number_of_entries * IPA_NAT_EXPANSION_TABLE_PERCENTAGE);
+	GetNearestEven(*expn_table_entries, expn_table_entries);
+  
+  total_entries = (*table_entries) + (*expn_table_entries);
+
+  /* Calclate the memory size for both table and index table entries */
+  mem->size = (IPA_NAT_TABLE_ENTRY_SIZE * total_entries);
+  mem->size += (IPA_NAT_INDEX_TABLE_ENTRY_SIZE * total_entries);
+  
+  if (!ipv4_nat_cache.ipa_fd)
+  {
+    fd = open(IPA_DEV_NAME, O_RDONLY);
+    if (fd < 0)
+    {
+      perror("ipa_nati_alloc_table(): open error value:");
+      IPAERR("unable to open ipa device\n");
+      return -1;
+    }
+    ipv4_nat_cache.ipa_fd = fd;
+  }
+
+  ret = CreateNatDevice(mem);
+  return ret;
+}   
+   
+
+int ipa_nati_update_cache(struct ipa_ioc_nat_alloc_mem *mem,
+                          uint32_t public_addr,
+                          uint16_t tbl_entries,
+                          uint16_t expn_tbl_entries)
+{
+  uint32_t index = ipv4_nat_cache.table_cnt;
+  char *ipv4_rules_addr = NULL;
+
+  int fd = 0;
+  int flags = MAP_SHARED;
+  int prot = PROT_READ | PROT_WRITE;
+  off_t offset = 0;
+#ifdef IPA_ON_R3PC
+  int ret = 0;
+  uint32_t nat_mem_offset = 0;
+#endif
+
+  ipv4_nat_cache.ip4_tbl[index].valid = IPA_NAT_TABLE_VALID;
+  ipv4_nat_cache.ip4_tbl[index].public_addr = public_addr;
+  ipv4_nat_cache.ip4_tbl[index].size = mem->size;
+  ipv4_nat_cache.ip4_tbl[index].tbl_addr_offset = mem->offset;
+
+  ipv4_nat_cache.ip4_tbl[index].table_entries = tbl_entries;
+  ipv4_nat_cache.ip4_tbl[index].expn_table_entries = expn_tbl_entries;
+
+  IPADBG("num of ipv4 rules:%d\n",tbl_entries);
+  IPADBG("num of ipv4 expn rules:%d\n",expn_tbl_entries);
+
+  /* allocate memory for nat index expansion table */
+  if (NULL == ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta)
+  {
+    ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta =
+      malloc(sizeof(struct ipa_nat_indx_tbl_meta_info) * expn_tbl_entries);
+
+    if (NULL == ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta)
+    {
+      IPAERR("Fail to allocate ipv4 index expansion table meta\n");
+      return 0;
+    }
+
+    memset(ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta,
+           0,
+           sizeof(struct ipa_nat_indx_tbl_meta_info) * expn_tbl_entries);
+  }
+
+  /* Allocate memory for rule_id_array */
+  if (NULL == ipv4_nat_cache.ip4_tbl[index].rule_id_array)
+  {
+    ipv4_nat_cache.ip4_tbl[index].rule_id_array = 
+      malloc(sizeof(uint16_t) * (tbl_entries + expn_tbl_entries));
+
+    if (NULL == ipv4_nat_cache.ip4_tbl[index].rule_id_array)
+    {
+      IPAERR("Fail to allocate rule id array\n");
+      return 0;
+    }
+
+    memset(ipv4_nat_cache.ip4_tbl[index].rule_id_array,
+           0,
+           sizeof(uint16_t) * (tbl_entries + expn_tbl_entries) );
+  }
+
+  
+  /* open the nat table */
+  strcpy(mem->dev_name, NAT_DEV_FULL_NAME);
+  fd = open(mem->dev_name, O_RDWR);
+  if(fd < 0)
+  {
+     perror("ipa_nati_update_cache(): open error value:");
+     IPAERR("unable to open nat device. Error:%d\n",fd);
+     return -1;
+  }
+
+  /* copy the nat table name */
+  strncpy(ipv4_nat_cache.ip4_tbl[index].table_name,
+          mem->dev_name,
+          IPA_RESOURCE_NAME_MAX);
+  ipv4_nat_cache.ip4_tbl[index].nat_fd = fd;
+
+  /* open the nat device Table */
+#ifndef IPA_ON_R3PC
+  ipv4_rules_addr = (void *)mmap(NULL, mem->size,
+                                 prot, flags,
+                                 fd, offset);
+#else
+  IPADBG("user space r3pc \n");
+  ipv4_rules_addr = (void *)mmap((caddr_t)0, NAT_MMAP_MEM_SIZE,
+                                 prot, flags,
+                                 fd, offset);
+#endif
+  if(NULL == ipv4_rules_addr)
+  {
+    perror("unable to mmap the memory\n");
+    return -1;
+  }
+
+#ifdef IPA_ON_R3PC
+  ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_GET_NAT_OFFSET, &nat_mem_offset);
+  if (ret != 0)
+  {
+    perror("ipa_nati_post_ipv4_init_cmd(): ioctl error value");
+    IPAERR("unable to post ant offset cmd Error: %d\n",ret);
+    IPADBG("ipa fd %d\n",ipv4_nat_cache.ipa_fd);
+    return -1;
+  }
+  ipv4_rules_addr += nat_mem_offset;
+	ipv4_nat_cache.ip4_tbl[index].mmap_offset = nat_mem_offset;
+#endif
+
+  IPADBG("mmap return value 0x%lx\n", (long unsigned int)ipv4_rules_addr);
+
+  ipv4_nat_cache.ip4_tbl[index].ipv4_rules_addr = ipv4_rules_addr;
+
+  ipv4_nat_cache.ip4_tbl[index].ipv4_expn_rules_addr = 
+    ipv4_rules_addr + (IPA_NAT_TABLE_ENTRY_SIZE * tbl_entries);
+    
+  ipv4_nat_cache.ip4_tbl[index].index_table_addr = 
+    ipv4_rules_addr + (IPA_NAT_TABLE_ENTRY_SIZE * (tbl_entries + expn_tbl_entries));
+  
+  ipv4_nat_cache.ip4_tbl[index].index_table_expn_addr = 
+    ipv4_rules_addr + 
+      (IPA_NAT_TABLE_ENTRY_SIZE * (tbl_entries + expn_tbl_entries)) + 
+      (IPA_NAT_INDEX_TABLE_ENTRY_SIZE * tbl_entries);
+  
+  return 0;
+}
+
+/* comment: check the implementation once
+   offset should be in terms of byes */
+int ipa_nati_post_ipv4_init_cmd(uint8_t tbl_index)
+{
+  struct ipa_ioc_v4_nat_init cmd;
+  uint32_t offset = ipv4_nat_cache.ip4_tbl[tbl_index].tbl_addr_offset;
+  int ret;
+    
+  cmd.tbl_index = tbl_index; 
+
+  cmd.ipv4_rules_offset = offset;
+  cmd.expn_rules_offset = cmd.ipv4_rules_offset +
+    (ipv4_nat_cache.ip4_tbl[tbl_index].table_entries * IPA_NAT_TABLE_ENTRY_SIZE);
+
+  cmd.index_offset = cmd.expn_rules_offset + 
+    (ipv4_nat_cache.ip4_tbl[tbl_index].expn_table_entries * IPA_NAT_TABLE_ENTRY_SIZE);
+
+  cmd.index_expn_offset = cmd.index_offset + 
+    (ipv4_nat_cache.ip4_tbl[tbl_index].table_entries * IPA_NAT_INDEX_TABLE_ENTRY_SIZE);
+  
+  cmd.table_entries      = ipv4_nat_cache.ip4_tbl[tbl_index].table_entries - 1; 
+  cmd.expn_table_entries = ipv4_nat_cache.ip4_tbl[tbl_index].expn_table_entries;
+
+  cmd.ip_addr = ipv4_nat_cache.ip4_tbl[tbl_index].public_addr;
+
+  ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_V4_INIT_NAT, &cmd);
+  if (ret != 0)
+  {
+    perror("ipa_nati_post_ipv4_init_cmd(): ioctl error value");
+    IPAERR("unable to post init cmd Error: %d\n",ret);
+    IPADBG("ipa fd %d\n",ipv4_nat_cache.ipa_fd);
+    return -1;
+  }
+  IPADBG("Posted IPA_IOC_V4_INIT_NAT to kernel successfully \n");
+
+  return 0;
+}
+
+int ipa_nati_del_ipv4_table(uint32_t tbl_hdl)
+{
+  uint8_t index = (uint8_t)(tbl_hdl - 1);
+  void *addr = (void *)ipv4_nat_cache.ip4_tbl[index].ipv4_rules_addr;
+  struct ipa_ioc_v4_nat_del del_cmd;
+  int ret;
+  
+  if (!ipv4_nat_cache.ip4_tbl[index].valid)
+  {
+    IPAERR("invalid table handle passed\n");
+    return -1;
+  }
+
+  /* unmap the device memory from user space */
+#ifndef IPA_ON_R3PC
+  munmap(addr, ipv4_nat_cache.ip4_tbl[index].size);
+#else
+  addr = (char *)addr - ipv4_nat_cache.ip4_tbl[index].mmap_offset;
+  munmap(addr, NAT_MMAP_MEM_SIZE);
+#endif
+
+  /* close the file descriptor of nat device */
+  if (close(ipv4_nat_cache.ip4_tbl[index].nat_fd))
+  {
+    IPAERR("unable to close the file descriptor\n");
+    return -1;
+  }
+
+  del_cmd.table_index = index;
+  del_cmd.public_ip_addr = ipv4_nat_cache.ip4_tbl[index].public_addr;
+  ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_V4_DEL_NAT, &del_cmd);
+  if (ret != 0)
+  {
+    perror("ipa_nati_del_ipv4_table(): ioctl error value");
+    IPAERR("unable to post nat del command init Error: %d\n",ret);
+    IPADBG("ipa fd %d\n",ipv4_nat_cache.ipa_fd);
+    return -1;
+  }
+  IPADBG("posted IPA_IOC_V4_DEL_NAT to kernel successfully \n");
+
+  free(ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta);
+  free(ipv4_nat_cache.ip4_tbl[index].rule_id_array);
+  
+  memset(&ipv4_nat_cache.ip4_tbl[index],
+         0,
+         sizeof(ipv4_nat_cache.ip4_tbl[index]));
+
+  /* Decrease the table count by 1*/
+  ipv4_nat_cache.table_cnt--;
+
+  return 0;
+}
+
+int ipa_nati_query_timestamp(uint32_t  tbl_hdl,
+                             uint32_t  rule_hdl,
+                             uint32_t  *time_stamp)
+{
+  uint8_t tbl_index = (uint8_t)(tbl_hdl - 1);
+  uint8_t expn_tbl = 0;
+  uint16_t tbl_entry = 0;
+  struct ipa_nat_rule *tbl_ptr = NULL;
+  
+  if (!ipv4_nat_cache.ip4_tbl[tbl_index].valid)
+  {
+    IPAERR("invalid table handle\n");
+    return -1;
+  }
+
+  ipa_nati_parse_ipv4_rule_hdl(tbl_index, (uint16_t)rule_hdl,
+                               &expn_tbl, &tbl_entry);
+
+  tbl_ptr = 
+    (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_index].ipv4_rules_addr;
+  if (expn_tbl)
+  {
+    tbl_ptr = 
+      (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_index].ipv4_expn_rules_addr;
+  }
+
+  *time_stamp = Read32BitFieldValue(tbl_ptr[tbl_entry].ts_proto,
+																		TIME_STAMP_FIELD);
+  return 0;
+}
+
+uint32_t ipa_nati_add_ipv4_rule(uint32_t tbl_hdl,
+                                const ipa_nat_ipv4_rule *clnt_rule)
+{
+  struct ipa_nat_ip4_table_cache *tbl_ptr;
+  struct ipa_nat_sw_rule sw_rule;
+  struct ipa_nat_indx_tbl_sw_rule index_sw_rule;
+  uint16_t new_entry, new_index_tbl_entry;
+  uint32_t rule_hdl = 0;
+
+  memset(&sw_rule, 0, sizeof(sw_rule));
+  memset(&index_sw_rule, 0, sizeof(index_sw_rule));
+
+  /* Generate rule from client input */
+  if (-1 == ipa_nati_generate_rule(tbl_hdl, clnt_rule,
+                                   &sw_rule, &index_sw_rule,
+                                   &new_entry, &new_index_tbl_entry))
+  {
+    IPAERR("unable to generate rule\n");
+    return -1;
+  }
+ 
+  tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_hdl-1];
+  ipa_nati_copy_ipv4_rule_to_hw(tbl_ptr, &sw_rule, new_entry, (uint8_t)(tbl_hdl-1));
+  ipa_nati_copy_ipv4_index_rule_to_hw(tbl_ptr,
+                                      &index_sw_rule,
+                                      new_index_tbl_entry,
+																			(uint8_t)(tbl_hdl-1));
+
+  IPADBG("new entry:%d, new index entry: %d\n", new_entry, new_index_tbl_entry);
+  if( -1 == ipa_nati_post_ipv4_dma_cmd((uint8_t)(tbl_hdl-1), new_entry))
+  {
+    IPAERR("unable to post dma command\n");
+    return -1;
+  }
+ 
+  /* Generate rule handle */
+  rule_hdl  = ipa_nati_make_rule_hdl((uint16_t)tbl_hdl, new_entry);
+  if (!rule_hdl)
+  {
+    IPAERR("unable to generate rule handle\n");
+    return -1;
+  }
+
+#ifdef NAT_DUMP
+  ipa_nat_dump_ipv4_table(tbl_hdl);
+#endif
+
+  return rule_hdl;
+}
+int ipa_nati_generate_rule(uint32_t tbl_hdl,
+                           const ipa_nat_ipv4_rule *clnt_rule,
+                           struct ipa_nat_sw_rule *rule,
+                           struct ipa_nat_indx_tbl_sw_rule *index_sw_rule,
+                           uint16_t *tbl_entry,
+                           uint16_t *indx_tbl_entry)
+{
+
+  struct ipa_nat_ip4_table_cache *tbl_ptr;
+  uint16_t tmp;
+
+  if (NULL == clnt_rule || NULL == index_sw_rule ||
+      NULL == rule || NULL == tbl_entry  ||
+      NULL == indx_tbl_entry)
+  {
+    IPAERR("invalid parameters\n");
+    return -1;
+  }
+
+  tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_hdl-1];
+
+  *tbl_entry = ipa_nati_generate_tbl_rule(clnt_rule,
+                                          rule,
+                                          tbl_ptr);
+  if (IPA_NAT_INVALID_NAT_ENTRY == *tbl_entry)
+  {
+    IPAERR("unable to generate table entry\n");
+    return -1;
+  }
+
+  index_sw_rule->tbl_entry = *tbl_entry;
+  *indx_tbl_entry = ipa_nati_generate_index_rule(clnt_rule,
+                                                 index_sw_rule,
+                                                 tbl_ptr);
+  if (IPA_NAT_INVALID_NAT_ENTRY == *indx_tbl_entry)
+  {
+    IPAERR("unable to generate index table entry\n");
+    return -1;
+  }
+	
+	rule->indx_tbl_entry = *indx_tbl_entry;
+	if (*indx_tbl_entry >= tbl_ptr->table_entries)
+	{
+		tmp = *indx_tbl_entry - tbl_ptr->table_entries;
+		tbl_ptr->index_expn_table_meta[tmp].prev_index = index_sw_rule->prev_index;
+	}
+
+	return 0; 
+}
+
+uint16_t ipa_nati_generate_tbl_rule(const ipa_nat_ipv4_rule *clnt_rule,
+                                    struct ipa_nat_sw_rule *sw_rule,
+                                    struct ipa_nat_ip4_table_cache *tbl_ptr)
+{
+  uint32_t pub_ip_addr;
+  uint16_t prev=0, nxt_indx=0, new_entry;
+  struct ipa_nat_rule *tbl = NULL, *expn_tbl = NULL;
+  
+  pub_ip_addr = tbl_ptr->public_addr;
+
+  tbl = (struct ipa_nat_rule *)tbl_ptr->ipv4_rules_addr;
+  expn_tbl = (struct ipa_nat_rule *)tbl_ptr->ipv4_expn_rules_addr;
+
+  /* copy the values from client rule to sw rule */
+  sw_rule->private_ip = clnt_rule->private_ip;
+  sw_rule->private_port = clnt_rule->private_port;
+  sw_rule->protocol = clnt_rule->protocol;
+  sw_rule->public_port = clnt_rule->public_port;
+  sw_rule->target_ip = clnt_rule->target_ip;
+  sw_rule->target_port = clnt_rule->target_port;
+
+  /* consider only public and private ip fields */
+  sw_rule->ip_chksum = ipa_nati_calc_ip_cksum(pub_ip_addr,
+                                     clnt_rule->private_ip); 
+
+  if(IPPROTO_TCP == sw_rule->protocol ||
+     IPPROTO_UDP == sw_rule->protocol)
+  {
+    /* consider public and private ip & port fields */
+    sw_rule->tcp_udp_chksum = ipa_nati_calc_tcp_udp_cksum(
+                                  pub_ip_addr,
+                                  clnt_rule->public_port,
+                                  clnt_rule->private_ip,
+                                  clnt_rule->private_port);
+  }
+
+  sw_rule->rsvd1 = 0;
+  sw_rule->enable = IPA_NAT_FLAG_DISABLE_BIT;
+  sw_rule->next_index = 0; 
+
+  /*
+    SW sets this timer to 0.
+    The assumption is that 0 is an invalid clock value and no clock
+    wraparounds are expected
+  */
+  sw_rule->time_stamp = 0;
+  sw_rule->rsvd2 = 0;
+  sw_rule->prev_index = 0;
+  sw_rule->indx_tbl_entry = 0;
+  
+  new_entry = dst_hash(clnt_rule->target_ip, 
+                       clnt_rule->target_port,
+                       clnt_rule->public_port,
+                       clnt_rule->protocol,
+                       tbl_ptr->table_entries-1 );
+  
+  /* check whether there is any collision
+     if no collision return */
+  if (! Read16BitFieldValue(tbl[new_entry].ip_cksm_enbl,
+														ENABLE_FIELD))
+  {
+		sw_rule->prev_index = 0;
+    IPADBG("Destination Nat New Entry Index %d\n",new_entry);
+    return new_entry;
+  }
+
+  /* First collision */
+	if (Read16BitFieldValue(tbl[new_entry].nxt_indx_pub_port,
+													NEXT_INDEX_FIELD) == IPA_NAT_INVALID_NAT_ENTRY)
+	{
+		sw_rule->prev_index = new_entry;
+	}
+  /* check for more than one collision  */
+  else
+  {    
+    /* Find the IPA_NAT_DEL_TYPE_LAST entry in list */
+    nxt_indx = Read16BitFieldValue(tbl[new_entry].nxt_indx_pub_port,
+														 NEXT_INDEX_FIELD);
+    
+    while(nxt_indx != IPA_NAT_INVALID_NAT_ENTRY)
+    {
+      prev = nxt_indx;
+
+      nxt_indx -= tbl_ptr->table_entries;
+      nxt_indx = Read16BitFieldValue(expn_tbl[nxt_indx].nxt_indx_pub_port,
+														 NEXT_INDEX_FIELD);
+
+      /* Handling error case */
+      if(prev == nxt_indx)
+      {
+        IPAERR("Error: Prev index:%d and next:%d index should not be same \n", prev, nxt_indx);
+        return IPA_NAT_INVALID_NAT_ENTRY;
+      }
+    }
+
+		sw_rule->prev_index = prev;
+  }
+
+  /* On collision check for the free entry in expansion table */
+  new_entry = ipa_nati_expn_tbl_free_entry(expn_tbl,
+                                           tbl_ptr->expn_table_entries);
+
+  if (IPA_NAT_INVALID_NAT_ENTRY == new_entry)
+  {
+    /* Expansion table is full return*/
+    IPAERR("expansion table is full\n");
+    return IPA_NAT_INVALID_NAT_ENTRY;
+  }
+  new_entry += tbl_ptr->table_entries;
+  
+  IPADBG("new entry index %d\n",new_entry);
+  return new_entry;
+}
+
+/* returns expn table entry index */
+uint16_t ipa_nati_expn_tbl_free_entry(struct ipa_nat_rule *expn_tbl,
+                                 uint16_t size)
+{
+  int cnt;
+
+  for (cnt=1; cnt<size; cnt++)
+  {
+     if (!Read16BitFieldValue(expn_tbl[cnt].ip_cksm_enbl,
+															ENABLE_FIELD))
+     {
+       IPADBG("new expansion table entry index %d\n",cnt);
+       return cnt;
+     }
+  }
+
+  IPAERR("nat expansion table is full\n");
+  return 0;
+
+}
+
+uint16_t ipa_nati_generate_index_rule(const ipa_nat_ipv4_rule *clnt_rule,
+                                 struct ipa_nat_indx_tbl_sw_rule *sw_rule,
+                                 struct ipa_nat_ip4_table_cache *tbl_ptr)
+{
+  struct ipa_nat_indx_tbl_rule *indx_tbl, *indx_expn_tbl;
+  uint16_t prev=0, nxt_indx=0, new_entry;
+  
+  indx_tbl = 
+    (struct ipa_nat_indx_tbl_rule *)tbl_ptr->index_table_addr;
+  indx_expn_tbl = 
+    (struct ipa_nat_indx_tbl_rule *)tbl_ptr->index_table_expn_addr;
+
+  new_entry = src_hash(clnt_rule->private_ip,
+                       clnt_rule->private_port,
+                       clnt_rule->target_ip,
+                       clnt_rule->target_port,
+                       clnt_rule->protocol,
+                       tbl_ptr->table_entries-1);
+  
+  /* check whether there is any collision
+     if no collision return */
+  if (!Read16BitFieldValue(indx_tbl[new_entry].tbl_entry_nxt_indx,
+						 INDX_TBL_TBL_ENTRY_FIELD) )
+  {
+    sw_rule->prev_index = 0;
+    IPADBG("Source Nat Index Table Entry %d\n",new_entry);
+    return new_entry;
+  }
+
+  /* check for more than one collision  */
+  if (Read16BitFieldValue(indx_tbl[new_entry].tbl_entry_nxt_indx,
+													INDX_TBL_NEXT_INDEX_FILED) == IPA_NAT_INVALID_NAT_ENTRY)
+  {
+    sw_rule->prev_index = new_entry;
+    IPADBG("First collosion. Entry %d\n",new_entry);
+  }
+  else
+  {
+    /* Find the IPA_NAT_DEL_TYPE_LAST entry in list */
+    nxt_indx = Read16BitFieldValue(indx_tbl[new_entry].tbl_entry_nxt_indx,
+																	 INDX_TBL_NEXT_INDEX_FILED);
+    //prev = nxt_indx;
+
+    while(nxt_indx != IPA_NAT_INVALID_NAT_ENTRY)
+    {
+      prev = nxt_indx;
+
+      nxt_indx -= tbl_ptr->table_entries;
+      nxt_indx = Read16BitFieldValue(indx_expn_tbl[nxt_indx].tbl_entry_nxt_indx,
+																		 INDX_TBL_NEXT_INDEX_FILED);
+      
+      /* Handling error case */
+      if(prev == nxt_indx)
+      {
+        IPAERR("Error: Prev:%d and next:%d index should not be same \n", prev, nxt_indx);
+        return IPA_NAT_INVALID_NAT_ENTRY;
+      }
+    }    
+
+    sw_rule->prev_index = prev;
+  }
+
+  /* On collision check for the free entry in expansion table */
+  new_entry = ipa_nati_index_expn_get_free_entry(
+                              indx_expn_tbl,
+                              tbl_ptr->expn_table_entries);
+
+  if ( IPA_NAT_INVALID_NAT_ENTRY == new_entry)
+  {
+    /* Expansion table is full return*/
+    IPAERR("index expansion table is full\n");
+    return IPA_NAT_INVALID_NAT_ENTRY;
+  }
+  new_entry += tbl_ptr->table_entries;
+  
+  IPADBG("index table entry %d\n", new_entry);
+  return new_entry;
+}
+
+/* returns index expn table entry index */
+uint16_t ipa_nati_index_expn_get_free_entry(struct ipa_nat_indx_tbl_rule *indx_tbl,
+                                       uint16_t size)
+{
+  int cnt;
+  for (cnt=1; cnt<size; cnt++)
+  {
+		 if (!Read16BitFieldValue(indx_tbl[cnt].tbl_entry_nxt_indx,
+															INDX_TBL_TBL_ENTRY_FIELD))
+     {
+       return cnt;
+     }
+  }
+
+  IPAERR("nat index expansion table is full\n");
+  return 0;
+}
+
+void ipa_nati_write_next_index(uint8_t tbl_indx,
+															nat_table_type tbl_type,
+															uint16_t value,
+															uint32_t offset)
+{
+	struct ipa_ioc_nat_dma_cmd *cmd;
+
+	IPADBG("Updating next index field of table %d on collosion using dma\n", tbl_type);
+	IPADBG("table index: %d, value: %d offset;%d \n", tbl_indx, value, offset);
+
+	cmd = (struct ipa_ioc_nat_dma_cmd *)
+					malloc( sizeof(struct ipa_ioc_nat_dma_cmd) +
+									sizeof(struct ipa_ioc_nat_dma_one));
+	if(NULL == cmd)
+	{
+		IPAERR("unable to allocate memory\n");
+    return;
+	}
+
+	cmd->dma[0].table_index = tbl_indx;
+	cmd->dma[0].base_addr = tbl_type;
+	cmd->dma[0].data = value;
+	cmd->dma[0].offset = offset;
+
+	cmd->entries = 1;
+	if (ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_NAT_DMA, cmd))
+	{
+		perror("ipa_nati_post_ipv4_dma_cmd(): ioctl error value");
+		IPAERR("unable to call dma icotl to update next index\n");
+		IPAERR("ipa fd %d\n", ipv4_nat_cache.ipa_fd);
+		goto fail;
+	}
+
+	fail:
+		free(cmd);
+
+	return;
+}
+
+void ipa_nati_copy_ipv4_rule_to_hw(
+                     struct ipa_nat_ip4_table_cache *ipv4_cache,
+                     struct ipa_nat_sw_rule *rule,
+                     uint16_t entry, uint8_t tbl_index)
+{
+  struct ipa_nat_rule *tbl_ptr;
+  uint16_t prev_entry = rule->prev_index;
+	nat_table_type tbl_type;
+	uint32_t offset = 0;
+  
+  if (entry < ipv4_cache->table_entries)
+  {
+    tbl_ptr = (struct ipa_nat_rule *)ipv4_cache->ipv4_rules_addr;
+
+    memcpy( &tbl_ptr[entry],
+            rule,
+            sizeof(struct ipa_nat_rule));
+  }
+  else
+  {
+    tbl_ptr = (struct ipa_nat_rule *)ipv4_cache->ipv4_expn_rules_addr;
+    memcpy( &tbl_ptr[entry - ipv4_cache->table_entries],
+            rule,
+            sizeof(struct ipa_nat_rule));
+  }
+
+  /* Update the previos entry next_index */
+  if(IPA_NAT_INVALID_NAT_ENTRY != prev_entry)
+  {
+   
+    if (prev_entry < ipv4_cache->table_entries)
+    {
+			tbl_type = IPA_NAT_BASE_TBL;
+      tbl_ptr = (struct ipa_nat_rule *)ipv4_cache->ipv4_rules_addr;
+    }
+    else
+    {
+			tbl_type = IPA_NAT_EXPN_TBL;
+      /* tbp_ptr is already pointing to expansion table
+         no need to initialize it */
+      prev_entry = prev_entry - ipv4_cache->table_entries;
+    }
+
+		offset = ipa_nati_get_entry_offset(ipv4_cache, tbl_type, prev_entry);
+		offset += IPA_NAT_RULE_NEXT_FIELD_OFFSET;
+    
+		ipa_nati_write_next_index(tbl_index, tbl_type, entry, offset);
+  }
+
+  return;
+}
+
+void ipa_nati_copy_ipv4_index_rule_to_hw(
+              struct ipa_nat_ip4_table_cache *ipv4_cache,
+              struct ipa_nat_indx_tbl_sw_rule *indx_sw_rule,
+              uint16_t entry,
+							uint8_t tbl_index)
+{
+  struct ipa_nat_indx_tbl_rule *tbl_ptr;
+  struct ipa_nat_sw_indx_tbl_rule sw_rule;
+  uint16_t prev_entry = indx_sw_rule->prev_index;  
+	nat_table_type tbl_type;
+	uint16_t offset = 0;
+  
+  sw_rule.next_index = indx_sw_rule->next_index;
+  sw_rule.tbl_entry = indx_sw_rule->tbl_entry;
+
+  if (entry < ipv4_cache->table_entries)
+  {
+    tbl_ptr = (struct ipa_nat_indx_tbl_rule *)ipv4_cache->index_table_addr;
+
+    memcpy( &tbl_ptr[entry],
+            &sw_rule,
+            sizeof(struct ipa_nat_indx_tbl_rule));
+  }
+  else
+  {
+    tbl_ptr = (struct ipa_nat_indx_tbl_rule *)ipv4_cache->index_table_expn_addr;
+   
+    memcpy( &tbl_ptr[entry - ipv4_cache->table_entries],
+            &sw_rule,
+            sizeof(struct ipa_nat_indx_tbl_rule));
+  }
+
+  /* Update the next field of previous entry on collosion */
+  if (IPA_NAT_INVALID_NAT_ENTRY != prev_entry)
+  {
+    if (prev_entry < ipv4_cache->table_entries)
+    {
+			tbl_type = IPA_NAT_INDX_TBL;
+      tbl_ptr = (struct ipa_nat_indx_tbl_rule *)ipv4_cache->index_table_addr;
+    }
+    else
+    {
+			 tbl_type = IPA_NAT_INDEX_EXPN_TBL;
+      /* tbp_ptr is already pointing to expansion table
+       no need to initialize it */
+      prev_entry = prev_entry - ipv4_cache->table_entries;
+    }
+
+		offset = ipa_nati_get_index_entry_offset(ipv4_cache, tbl_type, prev_entry);
+		offset += IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET;
+
+    IPADBG("Updating next index field of index table on collosion using dma()\n");
+		ipa_nati_write_next_index(tbl_index, tbl_type, entry, offset);
+  }
+
+  return;
+}
+
+int ipa_nati_post_ipv4_dma_cmd(uint8_t tbl_indx,
+                               uint16_t entry)
+{
+  struct ipa_ioc_nat_dma_cmd *cmd;
+  struct ipa_nat_rule *tbl_ptr;
+  uint32_t offset = ipv4_nat_cache.ip4_tbl[tbl_indx].tbl_addr_offset;
+	int ret = 0;	
+
+	cmd = (struct ipa_ioc_nat_dma_cmd *)
+					malloc( sizeof(struct ipa_ioc_nat_dma_cmd) +
+									sizeof(struct ipa_ioc_nat_dma_one));
+	if(NULL == cmd)
+	{
+		IPAERR("unable to allocate memory\n");
+    return -1;
+	}
+
+  if (entry < ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries)
+  {
+    tbl_ptr = 
+      (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr;
+
+    cmd->dma[0].table_index = tbl_indx;
+    cmd->dma[0].base_addr = IPA_NAT_BASE_TBL;
+    cmd->dma[0].data = IPA_NAT_FLAG_ENABLE_BIT_MASK;
+
+    cmd->dma[0].offset = (char *)&tbl_ptr[entry] - (char *)tbl_ptr;
+    cmd->dma[0].offset += IPA_NAT_RULE_FLAG_FIELD_OFFSET;
+  }
+  else
+  {
+    tbl_ptr = 
+      (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_expn_rules_addr;
+    entry = entry - ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries;
+
+    cmd->dma[0].table_index = tbl_indx;
+    cmd->dma[0].base_addr = IPA_NAT_EXPN_TBL;
+    cmd->dma[0].data = IPA_NAT_FLAG_ENABLE_BIT_MASK;
+    
+    cmd->dma[0].offset = (char *)&tbl_ptr[entry] - (char *)tbl_ptr;
+    cmd->dma[0].offset += IPA_NAT_RULE_FLAG_FIELD_OFFSET;
+    cmd->dma[0].offset += offset;
+  }
+
+  cmd->entries = 1;
+  if (ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_NAT_DMA, cmd))
+  {
+    perror("ipa_nati_post_ipv4_dma_cmd(): ioctl error value");
+    IPAERR("unable to call dma icotl\n");
+    IPADBG("ipa fd %d\n",ipv4_nat_cache.ipa_fd);
+		ret = -1;
+    goto fail;
+  }  
+  IPADBG("posted IPA_IOC_NAT_DMA to kernel successfully during add operation \n");
+
+
+	fail:
+		free(cmd);
+
+  return ret;
+}
+
+
+int ipa_nati_del_ipv4_rule(uint32_t tbl_hdl,
+                           uint32_t rule_hdl)
+{
+  uint8_t expn_tbl;
+  uint16_t tbl_entry;
+  struct ipa_nat_ip4_table_cache *tbl_ptr;
+  del_type rule_pos;
+  uint8_t tbl_indx = (uint8_t)(tbl_hdl-1);
+
+  /* Parse the rule handle */
+  ipa_nati_parse_ipv4_rule_hdl(tbl_indx, (uint16_t)rule_hdl,
+                               &expn_tbl, &tbl_entry);
+  if (IPA_NAT_INVALID_NAT_ENTRY == tbl_entry)
+  {
+    IPAERR("Invalid Rule Entry\n");
+    return -1;
+  }
+  
+  IPADBG("Delete below rule\n");
+  IPADBG("tbl_entry:%d expn_tbl:%d \n",tbl_entry, expn_tbl);
+
+  tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_indx];
+  if (!tbl_ptr->valid)
+  {
+    IPAERR("invalid table handle\n");
+    return -1;
+  }
+
+  ipa_nati_find_rule_pos(tbl_ptr, expn_tbl,
+                         tbl_entry, &rule_pos);
+  IPADBG("rule_pos:%d\n", rule_pos);
+
+  if(0 != ipa_nati_post_del_dma_cmd(tbl_indx, tbl_entry,
+                                    expn_tbl, rule_pos))
+  {
+	  return -1;
+  }
+
+  ipa_nati_del_dead_ipv4_head_nodes(tbl_indx);
+
+  /* Reset rule_id_array entry */
+  ipv4_nat_cache.ip4_tbl[tbl_indx].rule_id_array[rule_hdl-1] =
+     IPA_NAT_INVALID_NAT_ENTRY;
+
+#ifdef NAT_DUMP
+  IPADBG("Dumping Table after deleting rule\n");
+  ipa_nat_dump_ipv4_table(tbl_hdl);
+#endif
+
+  return 0;
+}
+
+void ReorderCmds(struct ipa_ioc_nat_dma_cmd *cmd, int size)
+{
+	int indx_tbl_start = 0, cnt, cnt1;
+	struct ipa_ioc_nat_dma_cmd *tmp;
+
+	IPADBG("called ReorderCmds() with entries :%d\n", cmd->entries);
+	
+	for (cnt=0; cnt<cmd->entries; cnt++)
+	{
+		if (cmd->dma[cnt].base_addr == IPA_NAT_INDX_TBL ||
+				cmd->dma[cnt].base_addr == IPA_NAT_INDEX_EXPN_TBL)
+		{
+			indx_tbl_start = cnt;
+			break;
+		}
+	}
+
+	if (indx_tbl_start == 0)
+	{
+		IPADBG("Reorder not needed\n");
+		return;
+	}
+
+	tmp = (struct ipa_ioc_nat_dma_cmd *)malloc(size);
+	if (tmp == NULL)
+	{
+		IPAERR("unable to allocate memory\n");
+		return;
+	}
+
+	cnt1 = 0;
+	tmp->entries = cmd->entries;
+	for (cnt=indx_tbl_start; cnt<cmd->entries; cnt++)
+	{
+		memcpy(&tmp->dma[cnt1], &cmd->dma[cnt], 
+					 sizeof(struct ipa_ioc_nat_dma_one));
+		cnt1++;
+	}
+
+	for (cnt = 0; cnt<indx_tbl_start; cnt++)
+	{
+		memcpy(&tmp->dma[cnt1], &cmd->dma[cnt], 
+					 sizeof(struct ipa_ioc_nat_dma_one));
+		cnt1++;
+	}
+
+	memset(cmd, 0, size);
+	memcpy(cmd, tmp, size);
+	free(tmp);
+
+	return;
+}
+
+int ipa_nati_post_del_dma_cmd(uint8_t tbl_indx,
+															uint16_t cur_tbl_entry,
+															uint8_t expn_tbl,
+															del_type rule_pos)
+{
+
+#define MAX_DMA_ENTRIES_FOR_DEL 3
+
+	struct ipa_nat_ip4_table_cache *cache_ptr;
+	struct ipa_nat_indx_tbl_rule *indx_tbl_ptr;
+	struct ipa_nat_rule *tbl_ptr;
+	int ret = 0, size = 0;
+
+	uint16_t indx_tbl_entry = IPA_NAT_INVALID_NAT_ENTRY;
+	del_type indx_rule_pos;
+
+	struct ipa_ioc_nat_dma_cmd *cmd;
+	uint8_t no_of_cmds = 0;
+
+	uint16_t prev_entry = IPA_NAT_INVALID_NAT_ENTRY;
+	uint16_t next_entry = IPA_NAT_INVALID_NAT_ENTRY;
+	uint16_t table_entry;
+
+	size = sizeof(struct ipa_ioc_nat_dma_cmd) +
+		 (MAX_DMA_ENTRIES_FOR_DEL * sizeof(struct ipa_ioc_nat_dma_one));
+
+	cmd = (struct ipa_ioc_nat_dma_cmd *)malloc(size);
+	if (NULL == cmd)
+	{
+		IPAERR("unable to allocate memory\n");
+		return -1;
+	}
+
+	cache_ptr = &ipv4_nat_cache.ip4_tbl[tbl_indx];
+	if (!expn_tbl)
+	{
+		tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr;
+	}
+	else
+	{
+		tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr;
+	}
+
+
+	if (!Read16BitFieldValue(tbl_ptr[cur_tbl_entry].ip_cksm_enbl,
+													 ENABLE_FIELD))
+	{
+		IPAERR("Deleting invalid(not enabled) rule\n");
+		ret = -1;
+		goto fail;
+	}
+
+	indx_tbl_entry = Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params,
+																			 SW_SPEC_PARAM_INDX_TBL_ENTRY_FIELD);
+	/* ================================================
+	 Base Table rule Deletion
+	 ================================================*/
+	/* Just delete the current rule by disabling the flag field */
+	if (IPA_NAT_DEL_TYPE_ONLY_ONE == rule_pos)
+	{
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL;
+		cmd->dma[no_of_cmds].data = IPA_NAT_FLAG_DISABLE_BIT_MASK;
+
+		cmd->dma[no_of_cmds].offset =
+			 ipa_nati_get_entry_offset(cache_ptr,
+																 cmd->dma[no_of_cmds].base_addr,
+																 cur_tbl_entry);
+		cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_FLAG_FIELD_OFFSET;
+	}
+
+	/* Just update the protocol field to invalid */
+	if (IPA_NAT_DEL_TYPE_HEAD == rule_pos)
+	{
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL;
+		cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_PROTO_FIELD_VALUE;
+
+		cmd->dma[no_of_cmds].offset =
+			 ipa_nati_get_entry_offset(cache_ptr,
+																 cmd->dma[no_of_cmds].base_addr,
+																 cur_tbl_entry);
+		cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_PROTO_FIELD_OFFSET;
+
+		IPADBG("writing invalid proto: 0x%x\n", cmd->dma[no_of_cmds].data);
+	}
+
+	/* 
+		 Update the previous entry of next_index field value
+		 with current entry next_index field value
+	*/
+	if (IPA_NAT_DEL_TYPE_MIDDLE == rule_pos)
+	{
+		prev_entry = Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params,
+																		 SW_SPEC_PARAM_PREV_INDEX_FIELD);
+
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].data = Read16BitFieldValue(tbl_ptr[cur_tbl_entry].nxt_indx_pub_port,
+																										NEXT_INDEX_FIELD);
+
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL;
+		if (prev_entry >= cache_ptr->table_entries)
+		{
+			cmd->dma[no_of_cmds].base_addr = IPA_NAT_EXPN_TBL;
+			prev_entry -= cache_ptr->table_entries;
+		}
+
+		cmd->dma[no_of_cmds].offset = ipa_nati_get_entry_offset(cache_ptr,
+																														cmd->dma[no_of_cmds].base_addr,
+																														prev_entry);
+		cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_NEXT_FIELD_OFFSET;
+
+	}
+
+	/* 
+		 Reset the previous entry of next_index field with 0 
+	*/
+	if (IPA_NAT_DEL_TYPE_LAST == rule_pos)
+	{
+		prev_entry = Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params,
+																		 SW_SPEC_PARAM_PREV_INDEX_FIELD);
+
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_NAT_ENTRY;
+
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL;
+		if (prev_entry >= cache_ptr->table_entries)
+		{
+			cmd->dma[no_of_cmds].base_addr = IPA_NAT_EXPN_TBL;
+			prev_entry -= cache_ptr->table_entries;
+		}
+
+		cmd->dma[no_of_cmds].offset = ipa_nati_get_entry_offset(cache_ptr,
+																														cmd->dma[no_of_cmds].base_addr,
+																														prev_entry);
+		cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_NEXT_FIELD_OFFSET;
+	}
+
+	/* ================================================
+	 Base Table rule Deletion End
+	 ================================================*/
+
+	/* ================================================
+	 Index Table rule Deletion
+	 ================================================*/
+	ipa_nati_find_index_rule_pos(cache_ptr,
+															 indx_tbl_entry,
+															 &indx_rule_pos);
+	IPADBG("Index table entry: 0x%x\n", indx_tbl_entry);
+	IPADBG("and position: %d\n", indx_rule_pos);
+	if (indx_tbl_entry >= cache_ptr->table_entries)
+	{
+		indx_tbl_entry -= cache_ptr->table_entries;
+		indx_tbl_ptr =
+			 (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr;
+	}
+	else
+	{
+		indx_tbl_ptr =
+			 (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr;
+	}
+
+	/* Just delete the current rule by resetting nat_table_index field to 0 */
+	if (IPA_NAT_DEL_TYPE_ONLY_ONE == indx_rule_pos)
+	{
+		no_of_cmds++;
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL;
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_NAT_ENTRY;
+
+		cmd->dma[no_of_cmds].offset = ipa_nati_get_index_entry_offset(cache_ptr,
+																																	cmd->dma[no_of_cmds].base_addr,
+																																	indx_tbl_entry);
+		cmd->dma[no_of_cmds].offset += IPA_NAT_INDEX_RULE_NAT_INDEX_FIELD_OFFSET;
+	}
+
+	/* copy the next entry values to current entry */
+	if (IPA_NAT_DEL_TYPE_HEAD == indx_rule_pos)
+	{
+		next_entry = Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx,
+																		 INDX_TBL_NEXT_INDEX_FILED);
+		next_entry -= cache_ptr->table_entries;
+
+		no_of_cmds++;
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL;
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+
+		/* Copy the nat_table_index field value of next entry */
+		indx_tbl_ptr =
+			 (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr;
+		cmd->dma[no_of_cmds].data = Read16BitFieldValue(indx_tbl_ptr[next_entry].tbl_entry_nxt_indx,
+																										INDX_TBL_TBL_ENTRY_FIELD);
+
+		cmd->dma[no_of_cmds].offset = ipa_nati_get_index_entry_offset(cache_ptr,
+																																	cmd->dma[no_of_cmds].base_addr,
+																																	indx_tbl_entry);
+		cmd->dma[no_of_cmds].offset += IPA_NAT_INDEX_RULE_NAT_INDEX_FIELD_OFFSET;
+
+		/* Copy the next_index field value of next entry */
+		no_of_cmds++;
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL;
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].data = Read16BitFieldValue(indx_tbl_ptr[next_entry].tbl_entry_nxt_indx,
+																										INDX_TBL_NEXT_INDEX_FILED);
+
+		cmd->dma[no_of_cmds].offset = ipa_nati_get_index_entry_offset(cache_ptr,
+																																	cmd->dma[no_of_cmds].base_addr,
+																																	indx_tbl_entry);
+		cmd->dma[no_of_cmds].offset += IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET;
+	}
+
+	/* 
+		 Update the previous entry of next_index field value
+		 with current entry next_index field value
+	*/
+	if (IPA_NAT_DEL_TYPE_MIDDLE == indx_rule_pos)
+	{
+		prev_entry = cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index;
+
+		no_of_cmds++;
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].data = Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx,
+																										INDX_TBL_NEXT_INDEX_FILED);
+
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL;
+		if (prev_entry >= cache_ptr->table_entries)
+		{
+			cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDEX_EXPN_TBL;
+			prev_entry -= cache_ptr->table_entries;
+		}
+
+		cmd->dma[no_of_cmds].offset = ipa_nati_get_index_entry_offset(cache_ptr,
+																																	cmd->dma[no_of_cmds].base_addr,
+																																	prev_entry);
+		cmd->dma[no_of_cmds].offset += IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET;
+	}
+
+	/* Reset the previous entry next_index field with 0 */
+	if (IPA_NAT_DEL_TYPE_LAST == indx_rule_pos)
+	{
+		prev_entry = cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index;
+
+		no_of_cmds++;
+		cmd->dma[no_of_cmds].table_index = tbl_indx;
+		cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_NAT_ENTRY;
+
+		cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL;
+		if (prev_entry >= cache_ptr->table_entries)
+		{
+			cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDEX_EXPN_TBL;
+			prev_entry -= cache_ptr->table_entries;
+		}
+
+		cmd->dma[no_of_cmds].offset =
+			 ipa_nati_get_index_entry_offset(cache_ptr,
+																			 cmd->dma[no_of_cmds].base_addr,
+																			 prev_entry);
+		cmd->dma[no_of_cmds].offset += IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET;
+	}
+
+	/* ================================================
+	 Index Table rule Deletion End
+	 ================================================*/
+	cmd->entries = no_of_cmds + 1;
+
+	if (cmd->entries > 1)
+	{
+		ReorderCmds(cmd, size);
+	}
+	if (ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_NAT_DMA, cmd))
+	{
+		perror("ipa_nati_post_del_dma_cmd(): ioctl error value");
+		IPAERR("unable to post cmd\n");
+		IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd);
+		ret = -1;
+		goto fail;
+	}
+
+	/* if entry exist in IPA_NAT_DEL_TYPE_MIDDLE of list
+		 Update the previous entry in sw specific parameters
+	*/
+	if (IPA_NAT_DEL_TYPE_MIDDLE == rule_pos)
+	{
+		/* Retrieve the current entry prev_entry value */
+		prev_entry = Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params,
+																		 SW_SPEC_PARAM_PREV_INDEX_FIELD);
+
+		/* Retrieve the next entry */
+		next_entry = Read16BitFieldValue(tbl_ptr[cur_tbl_entry].nxt_indx_pub_port,
+																		 NEXT_INDEX_FIELD);
+		next_entry -= cache_ptr->table_entries;
+
+		tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr;
+
+		/* copy the current entry prev_entry value to next entry*/
+		UpdateSwSpecParams(&tbl_ptr[next_entry],
+											 IPA_NAT_SW_PARAM_PREV_INDX_BYTE,
+											 prev_entry);
+	}
+
+	/* Reset the other field values of current delete entry
+		 In case of IPA_NAT_DEL_TYPE_HEAD, don't reset */
+	if (IPA_NAT_DEL_TYPE_HEAD != rule_pos)
+	{
+		memset(&tbl_ptr[cur_tbl_entry], 0, sizeof(struct ipa_nat_rule));
+	}
+
+	if (IPA_NAT_DEL_TYPE_HEAD == indx_rule_pos)
+	{
+		/* Reset the next entry to IPA_NAT_DEL_TYPE_HEAD as we copied
+				 the next entry to IPA_NAT_DEL_TYPE_HEAD */
+		indx_tbl_ptr[next_entry].tbl_entry_nxt_indx = 0;
+
+		/* 
+			 In case of IPA_NAT_DEL_TYPE_HEAD, update the sw specific parameters
+			 (index table entry) of base table entry
+		*/
+		indx_tbl_ptr =
+			 (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr;
+		table_entry = Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx,
+																			INDX_TBL_TBL_ENTRY_FIELD);
+		if (table_entry >= cache_ptr->table_entries)
+		{
+			tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr;
+			table_entry -= cache_ptr->table_entries;
+		}
+		else
+		{
+			tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr;
+		}
+
+		UpdateSwSpecParams(&tbl_ptr[table_entry],
+											 IPA_NAT_SW_PARAM_INDX_TBL_ENTRY_BYTE,
+											 indx_tbl_entry);
+	}
+	else
+	{
+		/* Update the prev_entry value (in index_expn_table_meta)
+			 for the next_entry in list with current entry prev_entry value
+		*/
+		if (IPA_NAT_DEL_TYPE_MIDDLE == indx_rule_pos)
+		{
+			next_entry = Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx,
+																			 INDX_TBL_NEXT_INDEX_FILED);
+			if (next_entry >= cache_ptr->table_entries)
+			{
+				next_entry -= cache_ptr->table_entries;
+			}
+
+			cache_ptr->index_expn_table_meta[next_entry].prev_index =
+				 cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index;
+
+			cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index =
+				 IPA_NAT_INVALID_NAT_ENTRY;
+		}
+
+		IPADBG("At, indx_tbl_entry value: %d\n", indx_tbl_entry);
+		IPADBG("At, indx_tbl_entry member address: %p\n",
+					 &indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx);
+
+		indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx = 0;
+
+	}
+
+fail:
+	free(cmd);
+
+	return ret;
+}
+
+void ipa_nati_find_index_rule_pos(
+              struct ipa_nat_ip4_table_cache *cache_ptr,
+              uint16_t tbl_entry,
+              del_type *rule_pos)
+{
+
+  struct ipa_nat_indx_tbl_rule *tbl_ptr;
+  
+  if(tbl_entry >= cache_ptr->table_entries)
+  {
+    tbl_ptr = 
+      (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr;
+
+    tbl_entry -= cache_ptr->table_entries;
+		if (Read16BitFieldValue(tbl_ptr[tbl_entry].tbl_entry_nxt_indx,
+														INDX_TBL_NEXT_INDEX_FILED) == IPA_NAT_INVALID_NAT_ENTRY)
+    {
+      *rule_pos = IPA_NAT_DEL_TYPE_LAST;
+    }
+    else
+    {
+      *rule_pos = IPA_NAT_DEL_TYPE_MIDDLE;
+    }
+  }
+  else
+  {
+    tbl_ptr = 
+      (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr;
+    
+		if (Read16BitFieldValue(tbl_ptr[tbl_entry].tbl_entry_nxt_indx,
+														INDX_TBL_NEXT_INDEX_FILED) == IPA_NAT_INVALID_NAT_ENTRY)
+    {
+      *rule_pos = IPA_NAT_DEL_TYPE_ONLY_ONE;
+    }
+    else
+    {
+      *rule_pos = IPA_NAT_DEL_TYPE_HEAD;
+    }
+  }
+}
+
+void ipa_nati_find_rule_pos(struct ipa_nat_ip4_table_cache *cache_ptr,
+                            uint8_t expn_tbl,
+                            uint16_t tbl_entry,
+                            del_type *rule_pos)
+{
+
+  struct ipa_nat_rule *tbl_ptr;
+  
+  if(expn_tbl)
+  {
+    tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr;
+		if ( Read16BitFieldValue(tbl_ptr[tbl_entry].nxt_indx_pub_port,
+														 NEXT_INDEX_FIELD) == IPA_NAT_INVALID_NAT_ENTRY)
+    {
+      *rule_pos = IPA_NAT_DEL_TYPE_LAST;
+    }
+    else
+    {
+      *rule_pos = IPA_NAT_DEL_TYPE_MIDDLE;
+    }
+  }
+  else
+  {
+    tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr;
+    if( Read16BitFieldValue(tbl_ptr[tbl_entry].nxt_indx_pub_port,
+													 NEXT_INDEX_FIELD) == IPA_NAT_INVALID_NAT_ENTRY)
+    {
+      *rule_pos = IPA_NAT_DEL_TYPE_ONLY_ONE;
+    }
+    else
+    {
+      *rule_pos = IPA_NAT_DEL_TYPE_HEAD;
+    }
+  }
+}
+
+void ipa_nati_del_dead_ipv4_head_nodes(uint8_t tbl_indx)
+{
+  struct ipa_nat_rule *tbl_ptr;
+  uint16_t cnt;
+
+  tbl_ptr = 
+    (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr;
+
+  for(cnt=0; 
+      cnt<ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries;
+      cnt++)
+  {
+
+    if(Read8BitFieldValue(tbl_ptr[cnt].ts_proto,
+												  PROTOCOL_FIELD) == IPA_NAT_INVALID_PROTO_FIELD_CMP 
+			 &&
+			 Read16BitFieldValue(tbl_ptr[cnt].nxt_indx_pub_port,
+													 NEXT_INDEX_FIELD) == IPA_NAT_INVALID_NAT_ENTRY)
+    {
+      /* Delete the IPA_NAT_DEL_TYPE_HEAD node */
+      IPADBG("deleting the dead node 0x%x\n", cnt);
+      memset(&tbl_ptr[cnt], 0, sizeof(struct ipa_nat_rule));
+    }
+  } /* end of for loop */
+
+  return;
+}
+
+
+/* ========================================================
+            Debug functions
+   ========================================================*/
+#ifdef NAT_DUMP
+void ipa_nat_dump_ipv4_table(uint32_t tbl_hdl)
+{
+  struct ipa_nat_rule *tbl_ptr;
+  struct ipa_nat_indx_tbl_rule *indx_tbl_ptr;
+  int cnt;
+  uint8_t atl_one = 0;
+
+  if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl || 
+      tbl_hdl > IPA_NAT_MAX_IP4_TBLS)
+  {
+    IPAERR("invalid table handle passed \n");
+    return;
+  }
+
+  /* Print ipv4 rules */
+  IPADBG("Dumping ipv4 active rules:\n");
+  tbl_ptr = (struct ipa_nat_rule *)
+               ipv4_nat_cache.ip4_tbl[tbl_hdl-1].ipv4_rules_addr;
+  for( cnt=0; 
+       cnt<ipv4_nat_cache.ip4_tbl[tbl_hdl-1].table_entries;
+       cnt++)
+  {
+    if (Read16BitFieldValue( tbl_ptr[cnt].ip_cksm_enbl,
+														 ENABLE_FIELD))
+    {
+      atl_one = 1;
+			ipa_nati_print_rule(&tbl_ptr[cnt], cnt);
+      ipa_nati_dump_rule_buf(&tbl_ptr[cnt], 
+                             sizeof(struct ipa_nat_rule),
+                             cnt);
+    }
+  }
+  if(!atl_one)
+  {
+    IPADBG("No active base rules\n");
+  }
+  atl_one = 0;
+
+  /* Print ipv4 expansion rules */
+  IPADBG("Dumping ipv4 active expansion rules:\n");
+  tbl_ptr = (struct ipa_nat_rule *)
+               ipv4_nat_cache.ip4_tbl[tbl_hdl-1].ipv4_expn_rules_addr;
+  for( cnt=0; 
+       cnt<ipv4_nat_cache.ip4_tbl[tbl_hdl-1].expn_table_entries;
+       cnt++)
+  {
+    if (Read16BitFieldValue(tbl_ptr[cnt].ip_cksm_enbl,
+														ENABLE_FIELD))
+    {
+			ipa_nati_print_rule(&tbl_ptr[cnt], cnt);
+      ipa_nati_dump_rule_buf(&tbl_ptr[cnt], 
+                             sizeof(struct ipa_nat_rule),
+                             cnt);
+    }
+  }
+  if(!atl_one)
+  {
+    IPADBG("No active base expansion rules\n");
+  }
+  atl_one = 0;
+
+   /* Print ipv4 index rules */
+  IPADBG("Dumping ipv4 index active rules: \n");
+  indx_tbl_ptr = (struct ipa_nat_indx_tbl_rule *)
+                 ipv4_nat_cache.ip4_tbl[tbl_hdl-1].index_table_addr;
+   for( cnt=0; 
+        cnt<ipv4_nat_cache.ip4_tbl[tbl_hdl-1].table_entries;
+        cnt++)
+  {
+    if (Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx,
+														INDX_TBL_TBL_ENTRY_FIELD))
+    {
+      ipa_nati_dump_index_rule_buf(&indx_tbl_ptr[cnt], 
+                                   sizeof(struct ipa_nat_indx_tbl_rule),
+                                   cnt);
+    }
+  }
+  if(!atl_one)
+  {
+    IPADBG("No active index table rules\n");
+  }
+  atl_one = 0;
+
+
+   /* Print ipv4 index expansion rules */
+  IPADBG("Dumping ipv4 index expansion active rules: \n");
+  indx_tbl_ptr = (struct ipa_nat_indx_tbl_rule *)
+                 ipv4_nat_cache.ip4_tbl[tbl_hdl-1].index_table_expn_addr;
+  for ( cnt=0; 
+        cnt<ipv4_nat_cache.ip4_tbl[tbl_hdl-1].expn_table_entries;
+        cnt++)
+  {
+    if (Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx,
+														INDX_TBL_TBL_ENTRY_FIELD))
+    {
+      ipa_nati_dump_index_rule_buf(&indx_tbl_ptr[cnt], 
+                                   sizeof(struct ipa_nat_indx_tbl_rule),
+                                   cnt);
+    }
+  }
+  if(!atl_one)
+  {
+    IPADBG("No active index expansion rules\n");
+  }
+  atl_one = 0;
+
+}
+
+
+void ipa_nati_dump_rule_buf(void *param1, uint8_t size, uint32_t rule_id)
+{
+  int cnt = 0;
+	uint8_t temp[IPA_NAT_TABLE_ENTRY_SIZE];
+  uint64_t *rule = NULL;
+
+	memcpy(&temp, param1, sizeof(temp));
+	rule = (uint64_t *)temp;
+
+  IPADBG("Address :%p, rule id: %d size: %d\n", 
+          rule, rule_id, size);
+  for(; cnt<size; )
+  {
+    uint8_t *byte = (uint8_t *)rule;
+
+    IPADBG("uint64[%d]: 0x%x:\n", cnt, (unsigned int)rule);
+    IPADBG("%02x\t%02x\t%02x\t%02x\n", byte[0], byte[1], byte[2], byte[3]);
+    IPADBG("%02x\t%02x\t%02x\t%02x\n", byte[4], byte[5], byte[6], byte[7]);
+
+    cnt += 8;
+    rule++;
+  }
+
+  return;
+}
+
+void ipa_nati_dump_index_rule_buf(void *param1, uint8_t size, uint32_t rule_id)
+{
+  int cnt = 0;
+	uint8_t temp[IPA_NAT_INDEX_TABLE_ENTRY_SIZE];
+  uint16_t *rule = NULL;
+
+	memcpy(&temp, param1, sizeof(temp));
+	rule = (uint16_t *)temp;
+
+  IPADBG("Address :%p, rule id: %d size: %d\n", 
+          rule, rule_id, size);
+
+  for(; cnt<size; )
+  {
+    uint8_t *byte = (uint8_t *)rule;
+
+    IPADBG("uint64[%d]: 0x%x:\n", cnt, (unsigned int)rule);
+    IPADBG("%02x\t%02x\n", byte[0], byte[1]);
+    IPADBG("\n");
+
+    cnt += 2;
+    rule++;
+  }
+
+  return;
+}
+
+void ipa_nati_print_rule(struct ipa_nat_rule *param, uint32_t rule_id)
+{
+	struct ipa_nat_sw_rule sw_rule;
+	memcpy(&sw_rule, param, sizeof(sw_rule));
+
+  IPADBG("Printing NAT Rule:%d at memory location:%p\n", rule_id, param);
+
+  IPADBG("Target IP: 0x%x Target Port: 0x%x\n", 
+         sw_rule.target_ip, sw_rule.target_port);
+
+  IPADBG("Private IP: 0x%x Private Port: 0x%x\n", 
+         sw_rule.private_ip, sw_rule.private_port);
+
+  IPADBG("Public Port: 0x%x Next index: 0x%x\n", 
+         sw_rule.public_port, sw_rule.next_index);
+
+  IPADBG("IP ChkSum: 0x%x Enable bit: 0x%x\n", 
+         sw_rule.ip_chksum, sw_rule.enable);
+
+  IPADBG("Time Stamp: 0x%x Protocol: 0x%x\n", 
+         sw_rule.time_stamp, sw_rule.protocol);
+
+  IPADBG("Prev Index: 0x%x Next Index: 0x%x\n", 
+         sw_rule.prev_index, sw_rule.next_index);
+
+  IPADBG("TCP UDP Chksum: 0x%x\n", sw_rule.tcp_udp_chksum);
+
+  return;
+}
+#endif
diff --git a/ipanat/src/ipa_nat_logi.c b/ipanat/src/ipa_nat_logi.c
new file mode 100644
index 0000000..11991c9
--- /dev/null
+++ b/ipanat/src/ipa_nat_logi.c
@@ -0,0 +1,68 @@
+/* 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+		* Redistributions of source code must retain the above copyright
+			notice, this list of conditions and the following disclaimer.
+		* Redistributions in binary form must reproduce the above
+			copyright notice, this list of conditions and the following
+			disclaimer in the documentation and/or other materials provided
+			with the distribution.
+		* Neither the name of The Linux Foundation nor the names of its
+			contributors may be used to endorse or promote products derived
+			from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+	@file
+	IPACM_log.cpp
+
+	@brief
+	This file implements the IPAM log functionality.
+
+	@Author
+	Skylar Chang
+
+*/
+#include "ipa_nat_logi.h"
+#include <stdlib.h>
+
+#define NAT_FILE_NAME "/usr/ipanat_log.txt"
+
+static FILE *nat_fp = NULL;
+char nat_log_buf[NAT_LOG_SIZE];
+
+void log_nat_message(char *msg)
+{
+	 printf("%s", msg);
+#if 0
+	 if(nat_fp == NULL)
+	 {
+			nat_fp = fopen(NAT_FILE_NAME, "wb+");
+			if(nat_fp  == NULL)
+			{
+				 printf("unable to open file\n");
+				 return;
+			}
+	 }
+
+	 fprintf(nat_fp, msg);
+	 fflush(nat_fp);
+#endif
+	 return;
+}
+
+