Merge "IPA configuration manager daemon and IPA NAT library."
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;
+}
+
+