Merge "IPACM: add TCP SYN/FIN/RST flt rules"
diff --git a/ipacm/inc/IPACM_Defs.h b/ipacm/inc/IPACM_Defs.h
index 237ac5b..ed2eb9b 100644
--- a/ipacm/inc/IPACM_Defs.h
+++ b/ipacm/inc/IPACM_Defs.h
@@ -55,6 +55,7 @@
 #define IPA_MAX_FILE_LEN  64
 #define IPA_IFACE_NAME_LEN 16
 #define IPA_ALG_PROTOCOL_NAME_LEN  10
+#define MAX_COMMAND_LEN 1024
 
 #define IPA_WLAN_PARTIAL_HDR_OFFSET  0 // dst mac first then src mac
 //#define IPA_ETH_PARTIAL_HDR_OFFSET  8 // dst mac first then src mac
@@ -186,6 +187,8 @@
 	IPA_WLAN_SWITCH_TO_MCC,                   /* 51 No Data */
 	IPA_CRADLE_WAN_MODE_SWITCH,               /* 52 ipacm_event_cradle_wan_mode */
 	IPA_WAN_XLAT_CONNECT_EVENT,               /* 53 ipacm_event_data_fid */
+	IPA_TETHERING_STATS_UPDATE_EVENT,         /* 54 ipacm_event_data_fid */
+	IPA_NETWORK_STATS_UPDATE_EVENT,           /* 55 ipacm_event_data_fid */
 	IPACM_EVENT_MAX
 } ipa_cm_event_id;
 
diff --git a/ipacm/inc/IPACM_Lan.h b/ipacm/inc/IPACM_Lan.h
index 386b050..5031c05 100644
--- a/ipacm/inc/IPACM_Lan.h
+++ b/ipacm/inc/IPACM_Lan.h
@@ -58,6 +58,12 @@
 #define NUM_IPV6_PREFIX_FLT_RULE 1
 #define NUM_IPV6_ICMP_FLT_RULE 1
 
+/* ndc bandwidth ipatetherstats <ifaceIn> <ifaceOut> */
+/* <in->out_bytes> <in->out_pkts> <out->in_bytes> <out->in_pkts */
+
+#define PIPE_STATS "echo %s %s %lu %lu %lu %lu > %s"
+#define IPA_PIPE_STATS_FILE_NAME "/data/misc/ipa/tether_stats"
+
 /* store each lan-iface unicast routing rule and its handler*/
 struct ipa_lan_rt_rule
 {
@@ -306,6 +312,9 @@
 
 	void post_del_self_evt();
 
+	/* handle tethering stats */
+	int handle_tethering_stats_event(ipa_get_data_stats_resp_msg_v01 *data);
+
 	lan2lan_flt_rule_hdl lan2lan_flt_rule_hdl_v4[MAX_OFFLOAD_PAIR];
 	lan2lan_flt_rule_hdl lan2lan_flt_rule_hdl_v6[MAX_OFFLOAD_PAIR];
 
diff --git a/ipacm/inc/IPACM_Wan.h b/ipacm/inc/IPACM_Wan.h
index f8be65c..1452edb 100644
--- a/ipacm/inc/IPACM_Wan.h
+++ b/ipacm/inc/IPACM_Wan.h
@@ -58,6 +58,9 @@
 #define IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6 3
 #endif
 
+#define NETWORK_STATS "echo %s %lu %lu %lu %lu > %s"
+#define IPA_NETWORK_STATS_FILE_NAME "/data/misc/ipa/network_stats"
+
 typedef struct _wan_client_rt_hdl
 {
 	uint32_t wan_rt_rule_hdl_v4;
@@ -92,6 +95,8 @@
 	static bool wan_up;
 	static bool wan_up_v6;
 	static uint8_t xlat_mux_id;
+	/* IPACM interface name */
+	static char wan_up_dev_name[IF_NAME_LEN];
 
 	IPACM_Wan(int, ipacm_wan_iface_type, uint8_t *);
 	virtual ~IPACM_Wan();
@@ -183,6 +188,8 @@
 	uint8_t invalid_mac[IPA_MAC_ADDR_SIZE];
 	bool is_xlat;
 
+	/* update network stats for CNE */
+	int ipa_network_stats_fd;
 
 	inline ipa_wan_client* get_client_memptr(ipa_wan_client *param, int cnt)
 	{
@@ -381,8 +388,11 @@
 	void handle_wlan_SCC_MCC_switch(bool, ipa_ip_type);
 	void handle_wan_client_SCC_MCC_switch(bool, ipa_ip_type);
 
+	int handle_network_stats_evt();
+
 	int m_fd_ipa;
 
+	int handle_network_stats_update(ipa_get_apn_data_stats_resp_msg_v01 *data);
 };
 
 #endif /* IPACM_WAN_H */
diff --git a/ipacm/src/IPACM_IfaceManager.cpp b/ipacm/src/IPACM_IfaceManager.cpp
index 0f6424c..c8eb2c9 100644
--- a/ipacm/src/IPACM_IfaceManager.cpp
+++ b/ipacm/src/IPACM_IfaceManager.cpp
@@ -228,6 +228,9 @@
 				IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_HDR_PROC_CTX_SET_EVENT, lan);
 				IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_HDR_PROC_CTX_UNSET_EVENT, lan);
 #endif
+#ifdef FEATURE_IPA_ANDROID
+				IPACM_EvtDispatcher::registr(IPA_TETHERING_STATS_UPDATE_EVENT, lan);
+#endif
 				IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, lan);
 				IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, lan);
 				IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, lan);
@@ -341,6 +344,8 @@
 #ifndef FEATURE_IPA_ANDROID
 				IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_SCC, wl);
 				IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_MCC, wl);
+#else
+				IPACM_EvtDispatcher::registr(IPA_TETHERING_STATS_UPDATE_EVENT, wl);
 #endif
 				IPACMDBG_H("ipa_WLAN (%s):ipa_index (%d) instance open/registr ok\n", wl->dev_name, wl->ipa_if_num);
 				registr(ipa_interface_index, wl);
@@ -366,6 +371,10 @@
 					IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, w);
 #ifdef FEATURE_IPA_ANDROID
 					IPACM_EvtDispatcher::registr(IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, w);
+					if(is_sta_mode == Q6_WAN)
+					{
+						IPACM_EvtDispatcher::registr(IPA_NETWORK_STATS_UPDATE_EVENT, w);
+					};
 #else/* defined(FEATURE_IPA_ANDROID) */
 					IPACM_EvtDispatcher::registr(IPA_ROUTE_ADD_EVENT, w);
 					IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, w);
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
index 5a5aa7e..e108d15 100644
--- a/ipacm/src/IPACM_Lan.cpp
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -969,6 +969,28 @@
 	}
 	break;
 
+	case IPA_TETHERING_STATS_UPDATE_EVENT:
+	{
+		IPACMDBG_H("Received IPA_TETHERING_STATS_UPDATE_EVENT event.\n");
+		if (IPACM_Wan::isWanUP())
+		{
+			if(IPACM_Wan::backhaul_is_sta_mode == false) /* LTE */
+			{
+				ipa_get_data_stats_resp_msg_v01 *data = (ipa_get_data_stats_resp_msg_v01 *)param;
+				IPACMDBG("Received IPA_TETHERING_STATS_UPDATE_STATS ipa_stats_type: %d\n",data->ipa_stats_type);
+				IPACMDBG("Received %d UL, %d DL pipe stats\n",data->ul_src_pipe_stats_list_len,
+					data->dl_dst_pipe_stats_list_len);
+				if (data->ipa_stats_type != QMI_IPA_STATS_TYPE_PIPE_V01)
+				{
+					IPACMERR("not valid pipe stats enum(%d)\n", data->ipa_stats_type);
+					return;
+				}
+				handle_tethering_stats_event(data);
+			}
+		}
+	}
+	break;
+
 	default:
 		break;
 	}
@@ -6745,5 +6767,103 @@
 	return IPACM_SUCCESS;
 }
 
+/*handle reset usb-client rt-rules */
+int IPACM_Lan::handle_tethering_stats_event(ipa_get_data_stats_resp_msg_v01 *data)
+{
+	int cnt, pipe_len, fd;
+	uint64_t num_ul_packets, num_ul_bytes;
+	uint64_t num_dl_packets, num_dl_bytes;
+	bool ul_pipe_found, dl_pipe_found;
+	char command[MAX_COMMAND_LEN];
+	fd = open(IPA_DEVICE_NAME, O_RDWR);
+	if (fd < 0)
+	{
+		IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+		return IPACM_FAILURE;
+	}
 
 
+	ul_pipe_found = false;
+	dl_pipe_found = false;
+	num_ul_packets = 0;
+	num_dl_packets = 0;
+	num_ul_bytes = 0;
+	num_dl_bytes = 0;
+
+	if (data->dl_dst_pipe_stats_list_valid)
+	{
+		if(tx_prop != NULL)
+		{
+			for (pipe_len = 0; pipe_len < data->dl_dst_pipe_stats_list_len; pipe_len++)
+			{
+				IPACMDBG_H("Check entry(%d) dl_dst_pipe(%d)\n", pipe_len, data->dl_dst_pipe_stats_list[pipe_len].pipe_index);
+				for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+				{
+					IPACMDBG_H("Check Tx_prop_entry(%d) pipe(%d)\n", cnt, ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, tx_prop->tx[cnt].dst_pipe));
+					if(ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, tx_prop->tx[cnt].dst_pipe) == data->dl_dst_pipe_stats_list[pipe_len].pipe_index)
+					{
+						/* update the DL stats */
+						dl_pipe_found = true;
+						num_dl_packets += data->dl_dst_pipe_stats_list[pipe_len].num_ipv4_packets;
+						num_dl_packets += data->dl_dst_pipe_stats_list[pipe_len].num_ipv6_packets;
+						num_dl_bytes += data->dl_dst_pipe_stats_list[pipe_len].num_ipv4_bytes;
+						num_dl_bytes += data->dl_dst_pipe_stats_list[pipe_len].num_ipv6_bytes;
+						IPACMDBG_H("Got matched dst-pipe (%d) from %d tx props\n", data->dl_dst_pipe_stats_list[pipe_len].pipe_index, cnt);
+						IPACMDBG_H("DL_packets:(%lu) DL_bytes:(%lu) \n", num_dl_packets, num_dl_bytes);
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	if (data->ul_src_pipe_stats_list_valid)
+	{
+		if(rx_prop != NULL)
+		{
+			for (pipe_len = 0; pipe_len < data->ul_src_pipe_stats_list_len; pipe_len++)
+			{
+				IPACMDBG_H("Check entry(%d) dl_dst_pipe(%d)\n", pipe_len, data->ul_src_pipe_stats_list[pipe_len].pipe_index);
+				for (cnt=0; cnt < rx_prop->num_rx_props; cnt++)
+				{
+					IPACMDBG_H("Check Rx_prop_entry(%d) pipe(%d)\n", cnt, ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[cnt].src_pipe));
+					if(ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[cnt].src_pipe) == data->ul_src_pipe_stats_list[pipe_len].pipe_index)
+					{
+						/* update the UL stats */
+						ul_pipe_found = true;
+						num_ul_packets += data->ul_src_pipe_stats_list[pipe_len].num_ipv4_packets;
+						num_ul_packets += data->ul_src_pipe_stats_list[pipe_len].num_ipv6_packets;
+						num_ul_bytes += data->ul_src_pipe_stats_list[pipe_len].num_ipv4_bytes;
+						num_ul_bytes += data->ul_src_pipe_stats_list[pipe_len].num_ipv6_bytes;
+						IPACMDBG_H("Got matched dst-pipe (%d) from %d tx props\n", data->ul_src_pipe_stats_list[pipe_len].pipe_index, cnt);
+						IPACMDBG_H("UL_packets:(%lu) UL_bytes:(%lu) \n", num_ul_packets, num_ul_bytes);
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	if (ul_pipe_found || dl_pipe_found)
+	{
+		IPACMDBG_H("Update IPA_TETHERING_STATS_UPDATE_EVENT, TX(P%lu/B%lu) RX(P%lu/B%lu) DEV(%s) to LTE(%s) \n",
+					num_ul_packets,
+						num_ul_bytes,
+							num_dl_packets,
+								num_dl_bytes,
+									dev_name,
+										IPACM_Wan::wan_up_dev_name);
+			memset(command, 0, sizeof(command));
+			snprintf(command, sizeof(command), PIPE_STATS,
+				dev_name,
+					IPACM_Wan::wan_up_dev_name,
+						num_ul_bytes,
+						num_ul_packets,
+							    num_dl_bytes,
+								num_dl_packets,
+										IPA_PIPE_STATS_FILE_NAME);
+			system(command);
+	}
+	close(fd);
+	return IPACM_SUCCESS;
+}
diff --git a/ipacm/src/IPACM_Main.cpp b/ipacm/src/IPACM_Main.cpp
index 478fad2..a86cfb8 100644
--- a/ipacm/src/IPACM_Main.cpp
+++ b/ipacm/src/IPACM_Main.cpp
@@ -55,6 +55,7 @@
 #include <sys/inotify.h>
 #include <stdlib.h>
 #include <signal.h>
+#include "linux/ipa_qmi_service_v01.h"
 
 #define __stringify_1(x...)	#x
 #define __stringify(x...)	__stringify_1(x)
@@ -140,8 +141,9 @@
 
 #define IPA_DRIVER_WLAN_EVENT_MAX_OF_ATTRIBS  3
 #define IPA_DRIVER_WLAN_EVENT_SIZE  (sizeof(struct ipa_wlan_msg_ex)+ IPA_DRIVER_WLAN_EVENT_MAX_OF_ATTRIBS*sizeof(ipa_wlan_hdr_attrib_val))
+#define IPA_DRIVER_PIPE_STATS_EVENT_SIZE  (sizeof(struct ipa_get_data_stats_resp_msg_v01))
 #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)
+#define IPA_DRIVER_WLAN_BUF_LEN     (IPA_DRIVER_PIPE_STATS_EVENT_SIZE + IPA_DRIVER_WLAN_META_MSG)
 
 uint32_t ipacm_event_stats[IPACM_EVENT_MAX];
 bool ipacm_logging = true;
@@ -264,12 +266,16 @@
 	struct ipa_wlan_msg_ex event_ex_o;
 	struct ipa_wlan_msg *event_wlan=NULL;
 	struct ipa_wlan_msg_ex *event_ex= NULL;
+	struct ipa_get_data_stats_resp_msg_v01 event_data_stats;
+	struct ipa_get_apn_data_stats_resp_msg_v01 event_network_stats;
 
 	ipacm_cmd_q_data evt_data;
 	ipacm_event_data_mac *data = NULL;
 	ipacm_event_data_fid *data_fid = NULL;
 	ipacm_event_data_iptype *data_iptype = NULL;
 	ipacm_event_data_wlan_ex *data_ex;
+	ipa_get_data_stats_resp_msg_v01 *data_tethering_stats = NULL;
+	ipa_get_apn_data_stats_resp_msg_v01 *data_network_stats = NULL;
 
 	ipacm_cmd_q_data new_neigh_evt;
 	ipacm_event_data_all* new_neigh_data;
@@ -290,6 +296,8 @@
 		new_neigh_data = NULL;
 		data = NULL;
 		data_fid = NULL;
+		data_tethering_stats = NULL;
+		data_network_stats = NULL;
 
 		length = read(fd, buffer, IPA_DRIVER_WLAN_BUF_LEN);
 		if (length < 0)
@@ -667,6 +675,40 @@
 			evt_data.evt_data = data_fid;
 			IPACMDBG_H("Posting IPA_WAN_XLAT_CONNECT_EVENT event:%d\n", evt_data.event);
 			break;
+
+		case IPA_TETHERING_STATS_UPDATE_STATS:
+			memcpy(&event_data_stats, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_get_data_stats_resp_msg_v01));
+			data_tethering_stats = (ipa_get_data_stats_resp_msg_v01 *)malloc(sizeof(struct ipa_get_data_stats_resp_msg_v01));
+			if(data_tethering_stats == NULL)
+			{
+				IPACMERR("unable to allocate memory for event data_tethering_stats\n");
+				return NULL;
+			}
+			memcpy(data_tethering_stats,
+					 &event_data_stats,
+						 sizeof(struct ipa_get_data_stats_resp_msg_v01));
+			IPACMDBG("Received IPA_TETHERING_STATS_UPDATE_STATS ipa_stats_type: %d\n",data_tethering_stats->ipa_stats_type);
+			IPACMDBG("Received %d UL, %d DL pipe stats\n",data_tethering_stats->ul_src_pipe_stats_list_len, data_tethering_stats->dl_dst_pipe_stats_list_len);
+			evt_data.event = IPA_TETHERING_STATS_UPDATE_EVENT;
+			evt_data.evt_data = data_tethering_stats;
+			break;
+
+		case IPA_TETHERING_STATS_UPDATE_NETWORK_STATS:
+			memcpy(&event_network_stats, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_get_apn_data_stats_resp_msg_v01));
+			data_network_stats = (ipa_get_apn_data_stats_resp_msg_v01 *)malloc(sizeof(ipa_get_apn_data_stats_resp_msg_v01));
+			if(data_network_stats == NULL)
+			{
+				IPACMERR("unable to allocate memory for event data_network_stats\n");
+				return NULL;
+			}
+			memcpy(data_network_stats,
+					 &event_network_stats,
+						 sizeof(struct ipa_get_apn_data_stats_resp_msg_v01));
+			IPACMDBG("Received %d apn network stats \n", data_network_stats->apn_data_stats_list_len);
+			evt_data.event = IPA_NETWORK_STATS_UPDATE_EVENT;
+			evt_data.evt_data = data_network_stats;
+			break;
+
 		default:
 			IPACMDBG_H("Unhandled message type: %d\n", event_hdr.msg_type);
 			continue;
diff --git a/ipacm/src/IPACM_Wan.cpp b/ipacm/src/IPACM_Wan.cpp
index 8949043..e2ed53e 100644
--- a/ipacm/src/IPACM_Wan.cpp
+++ b/ipacm/src/IPACM_Wan.cpp
@@ -49,6 +49,7 @@
 #include "IPACM_Config.h"
 #include "IPACM_Defs.h"
 #include <IPACM_ConntrackListener.h>
+#include "linux/ipa_qmi_service_v01.h"
 
 bool IPACM_Wan::wan_up = false;
 bool IPACM_Wan::wan_up_v6 = false;
@@ -60,6 +61,8 @@
 struct ipa_flt_rule_add IPACM_Wan::flt_rule_v4[IPA_MAX_FLT_RULE];
 struct ipa_flt_rule_add IPACM_Wan::flt_rule_v6[IPA_MAX_FLT_RULE];
 
+char IPACM_Wan::wan_up_dev_name[IF_NAME_LEN];
+
 bool IPACM_Wan::backhaul_is_sta_mode = false;
 bool IPACM_Wan::is_ext_prop_set = false;
 
@@ -130,6 +133,14 @@
 		IPACMDBG_H("The new WAN interface is modem.\n");
 		is_default_gateway = false;
 		query_ext_prop();
+//#ifdef FEATURE_IPA_ANDROID
+//		ipa_network_stats_fd = open(IPA_NETWORK_STATS_FILE_NAME, O_RDWR | O_CREAT, 0660);
+//		if (ipa_network_stats_fd <= 0)
+//		{
+//			IPACMERR("Failed to open %s, error is %d - %s\n",
+//				IPA_NETWORK_STATS_FILE_NAME, errno, strerror(errno));
+//		}
+//#endif
 	}
 	else
 	{
@@ -165,7 +176,6 @@
 	{
 		IPACMDBG(" IPACM->IPACM_Wan(%d)\n", ipa_if_num);
 	}
-
 	return;
 }
 
@@ -781,7 +791,20 @@
 			}
 		}
 		break;
-
+	case IPA_NETWORK_STATS_UPDATE_EVENT:
+		{
+			ipa_get_apn_data_stats_resp_msg_v01 *data = (ipa_get_apn_data_stats_resp_msg_v01 *)param;
+			if (!data->apn_data_stats_list_valid)
+			{
+				IPACMERR("not valid APN\n");
+				return;
+			}
+			else
+			{
+				handle_network_stats_update(data);
+			}
+		}
+		break;
 	case IPA_ROUTE_ADD_EVENT:
 		{
 			ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
@@ -1386,6 +1409,9 @@
 	{
 		IPACM_Wan::wan_up = true;
 		active_v4 = true;
+		memcpy(IPACM_Wan::wan_up_dev_name,
+			dev_name,
+				sizeof(IPACM_Wan::wan_up_dev_name));
 
 		if(m_is_sta_mode == Q6_WAN)
 		{
@@ -3636,6 +3662,7 @@
 			IPACMDBG_H("setup wan_up/active_v4= false \n");
 			IPACM_Wan::wan_up = false;
 			active_v4 = false;
+			memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
 		}
 		else
 		{
@@ -3730,6 +3757,7 @@
 			IPACMDBG_H("setup wan_up/active_v4= false \n");
 			IPACM_Wan::wan_up = false;
 			active_v4 = false;
+			memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
 		}
 		else
 		{
@@ -4127,10 +4155,11 @@
 		/* only when default gw goes down we post WAN_DOWN event*/
 		if(is_default_gateway == true)
 		{
-		IPACM_Wan::wan_up = 0;
+			IPACM_Wan::wan_up = false;
 			del_wan_firewall_rule(IPA_IP_v4);
 			install_wan_filtering_rule(false);
 			handle_route_del_evt_ex(IPA_IP_v4);
+			memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
 		}
 
 		/* only when the last ipv4 modem interface goes down, delete ipv4 default flt rules*/
@@ -4156,7 +4185,7 @@
 		/* only when default gw goes down we post WAN_DOWN event*/
 		if(is_default_gateway == true)
 		{
-		IPACM_Wan::wan_up_v6 = 0;
+		IPACM_Wan::wan_up_v6 = false;
 			del_wan_firewall_rule(IPA_IP_v6);
 			install_wan_filtering_rule(false);
 			handle_route_del_evt_ex(IPA_IP_v6);
@@ -4190,11 +4219,12 @@
 		/* only when default gw goes down we post WAN_DOWN event*/
 		if(is_default_gateway == true)
 		{
-		IPACM_Wan::wan_up = 0;
+			IPACM_Wan::wan_up = false;
 			del_wan_firewall_rule(IPA_IP_v4);
-		handle_route_del_evt_ex(IPA_IP_v4);
+			handle_route_del_evt_ex(IPA_IP_v4);
+			memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
 
-		IPACM_Wan::wan_up_v6 = 0;
+			IPACM_Wan::wan_up_v6 = false;
 			del_wan_firewall_rule(IPA_IP_v6);
 			handle_route_del_evt_ex(IPA_IP_v6);
 
@@ -5470,3 +5500,32 @@
 	free(rt_rule);
 	return;
 }
+
+/*handle eth client */
+int IPACM_Wan::handle_network_stats_update(ipa_get_apn_data_stats_resp_msg_v01 *data)
+{
+	char command[MAX_COMMAND_LEN];
+	for (int apn_index =0; apn_index < data->apn_data_stats_list_len; apn_index++)
+	{
+		if(data->apn_data_stats_list[apn_index].mux_id == ext_prop->ext[0].mux_id)
+		{
+			IPACMDBG_H("Received IPA_TETHERING_STATS_UPDATE_NETWORK_STATS, MUX ID %d TX (P%lu/B%lu) RX (P%lu/B%lu)\n",
+				data->apn_data_stats_list[apn_index].mux_id,
+					data->apn_data_stats_list[apn_index].num_ul_packets,
+						data->apn_data_stats_list[apn_index].num_ul_bytes,
+							data->apn_data_stats_list[apn_index].num_dl_packets,
+								data->apn_data_stats_list[apn_index].num_dl_bytes);
+			memset(command, 0, sizeof(command));
+			snprintf(command, sizeof(command), NETWORK_STATS,
+				dev_name,
+					data->apn_data_stats_list[apn_index].num_ul_packets,
+						data->apn_data_stats_list[apn_index].num_ul_bytes,
+							data->apn_data_stats_list[apn_index].num_dl_packets,
+								data->apn_data_stats_list[apn_index].num_dl_bytes,
+									IPA_NETWORK_STATS_FILE_NAME);
+			system(command);
+			break;
+		};
+	}
+	return IPACM_SUCCESS;
+}
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
index 2c4d1e2..d178389 100644
--- a/ipacm/src/IPACM_Wlan.cpp
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -877,6 +877,24 @@
 		}
 	}
 	break;
+	case IPA_TETHERING_STATS_UPDATE_EVENT:
+	{
+		IPACMDBG_H("Received IPA_TETHERING_STATS_UPDATE_EVENT event.\n");
+		if (IPACM_Wan::isWanUP())
+		{
+			if(IPACM_Wan::backhaul_is_sta_mode == false) /* LTE */
+			{
+				ipa_get_data_stats_resp_msg_v01 *data = (ipa_get_data_stats_resp_msg_v01 *)param;
+				if (data->ipa_stats_type != QMI_IPA_STATS_TYPE_PIPE_V01)
+				{
+					IPACMERR("not valid pipe stats\n");
+					return;
+				}
+				handle_tethering_stats_event(data);
+			};
+		}
+	}
+	break;
 	default:
 		break;
 	}