IPACM: Handle NEIGH_EVENT for linklocal IP/IPv6 address

NETLINK message with IPA_NEW_NEIGH_EVENT/IPA_DEL_NEIGH_EVENT
event should be ignored if it is IPv4. LAN and WAN routing
rules is deleted if IPA_DEL_NEIGH_EVENT event is received for
for IPv6 address.This event is seen when usb_composition is
switched.

Change-Id: I238bd758b8c9728031134f1c421a8f8f30b6f2ff
diff --git a/ipacm/inc/IPACM_Defs.h b/ipacm/inc/IPACM_Defs.h
index fcb0a04..b424d97 100644
--- a/ipacm/inc/IPACM_Defs.h
+++ b/ipacm/inc/IPACM_Defs.h
@@ -74,6 +74,9 @@
 #define IPA_MAX_ALG_ENTRIES 20
 #define IPA_MAX_RM_ENTRY 6
 
+#define IPV4_ADDR_LINKLOCAL 0xA9FE0000
+#define IPV4_ADDR_LINKLOCAL_MASK 0xFFFF0000
+
 #define V4_DEFAULT_ROUTE_TABLE_NAME  "ipa_dflt_rt"
 #define V4_LAN_ROUTE_TABLE_NAME  "COMRTBLLANv4"
 #define V4_WAN_ROUTE_TABLE_NAME  "WANRTBLv4"
diff --git a/ipacm/inc/IPACM_Lan.h b/ipacm/inc/IPACM_Lan.h
index 83efaf1..94a1c6d 100644
--- a/ipacm/inc/IPACM_Lan.h
+++ b/ipacm/inc/IPACM_Lan.h
@@ -185,6 +185,8 @@
 
 	int handle_addr_evt_odu_bridge(ipacm_event_data_addr* data);
 
+	int handle_del_ipv6_addr(ipacm_event_data_all *data);
+
 	static bool odu_up;
 
 	/* install UL filter rule from Q6 */
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
index 6f5f2ad..2cbab3e 100644
--- a/ipacm/src/IPACM_Lan.cpp
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -756,6 +756,11 @@
 
 			if (ipa_interface_index == ipa_if_num)
 			{
+				if (data->iptype == IPA_IP_v6)
+				{
+					handle_del_ipv6_addr(data);
+					return;
+				}
 #ifdef FEATURE_ETH_BRIDGE_LE
 				if (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat == LAN_IF)
 				{
@@ -1010,6 +1015,83 @@
 	return;
 }
 
+
+int IPACM_Lan::handle_del_ipv6_addr(ipacm_event_data_all *data)
+{
+	uint32_t tx_index;
+	uint32_t rt_hdl;
+	int num_v6, clnt_indx;
+
+	clnt_indx = get_eth_client_index(data->mac_addr);
+	if (clnt_indx == IPACM_INVALID_INDEX)
+	{
+		IPACMERR("eth client not found/attached \n");
+		return IPACM_FAILURE;
+	}
+
+	if(data->iptype == IPA_IP_v6)
+	{
+		if ((data->ipv6_addr[0] != 0) || (data->ipv6_addr[1] != 0) ||
+				(data->ipv6_addr[2] != 0) || (data->ipv6_addr[3] || 0))
+		{
+			IPACMDBG_H("ipv6 address got: 0x%x:%x:%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+			for(num_v6=0;num_v6 < get_client_memptr(eth_client, clnt_indx)->ipv6_set;num_v6++)
+			{
+				if( data->ipv6_addr[0] == get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][0] &&
+					data->ipv6_addr[1] == get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][1] &&
+					data->ipv6_addr[2]== get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][2] &&
+					data->ipv6_addr[3] == get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][3])
+				{
+					IPACMDBG_H("ipv6 addr is found at position:%d for client:%d\n", num_v6, clnt_indx);
+					break;
+				}
+			}
+		}
+		if (num_v6 == IPV6_NUM_ADDR)
+		{
+			IPACMDBG_H("ipv6 addr is not found. \n");
+			return IPACM_FAILURE;
+		}
+
+		for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+		{
+			if((tx_prop->tx[tx_index].ip == IPA_IP_v6) && (get_client_memptr(eth_client, clnt_indx)->route_rule_set_v6 != 0))
+			{
+				IPACMDBG_H("Delete client index %d ipv6 RT-rules for %d-st ipv6 for tx:%d\n", clnt_indx, num_v6, tx_index);
+				rt_hdl = get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6];
+				if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+				{
+					return IPACM_FAILURE;
+				}
+				rt_hdl = get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6];
+				if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+				{
+					return IPACM_FAILURE;
+				}
+				get_client_memptr(eth_client, clnt_indx)->ipv6_set--;
+				get_client_memptr(eth_client, clnt_indx)->route_rule_set_v6--;
+
+				for(num_v6;num_v6< get_client_memptr(eth_client, clnt_indx)->ipv6_set;num_v6++)
+				{
+					get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][0] =
+						get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6+1][0];
+					get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][1] =
+						get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6+1][1];
+					get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][2] =
+						get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6+1][2];
+					get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][3] =
+						get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6+1][3];
+					get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6] =
+						get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6+1];
+					get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6] =
+						get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6+1];
+				}
+			}
+		}
+	}
+	return IPACM_SUCCESS;
+}
+
 /* delete filter rule for wan_down event for IPv4*/
 int IPACM_Lan::handle_wan_down(bool is_sta_mode)
 {
@@ -1818,7 +1900,7 @@
 	int v6_num;
 
 	IPACMDBG_H("number of eth clients: %d\n", num_eth_client);
-	IPACMDBG_H(" event MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+	IPACMDBG_H("event MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
 					 data->mac_addr[0],
 					 data->mac_addr[1],
 					 data->mac_addr[2],
@@ -1850,7 +1932,7 @@
 			   /* check if client got new IPv4 address*/
 			   if(data->ipv4_addr == get_client_memptr(eth_client, clnt_indx)->v4_addr)
 			   {
-			     IPACMDBG_H("Already setup ipv4 addr for client:%d, ipv4 address didn't change\n", clnt_indx);
+				IPACMDBG_H("Already setup ipv4 addr for client:%d, ipv4 address didn't change\n", clnt_indx);
 				 return IPACM_FAILURE;
 			   }
 			   else
@@ -1886,9 +1968,8 @@
 			  	        data->ipv6_addr[2]== get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][2] &&
 			  	         data->ipv6_addr[3] == get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][3])
 			      {
-			  	    IPACMDBG_H("Already see this ipv6 addr for client:%d\n", clnt_indx);
+					IPACMDBG_H("Already see this ipv6 addr at position: %d for client:%d\n", v6_num, clnt_indx);
 			  	    return IPACM_FAILURE; /* not setup the RT rules*/
-			  		break;
 			      }
 		       }
 
@@ -1945,7 +2026,6 @@
 					 get_client_memptr(eth_client, eth_index)->ipv6_set,
 					 get_client_memptr(eth_client, eth_index)->route_rule_set_v6);
 	}
-
 	/* Add default routing rules if not set yet */
 	if ((iptype == IPA_IP_v4
 			 && get_client_memptr(eth_client, eth_index)->route_rule_set_v4 == false
@@ -2105,7 +2185,6 @@
 			get_client_memptr(eth_client, eth_index)->route_rule_set_v6 = get_client_memptr(eth_client, eth_index)->ipv6_set;
 		}
 	}
-
 	return IPACM_SUCCESS;
 }
 
diff --git a/ipacm/src/IPACM_Neighbor.cpp b/ipacm/src/IPACM_Neighbor.cpp
index 270ed7b..6a49502 100644
--- a/ipacm/src/IPACM_Neighbor.cpp
+++ b/ipacm/src/IPACM_Neighbor.cpp
@@ -161,7 +161,13 @@
 			{
 				if (data->ipv4_addr != 0) /* not 0.0.0.0 */
 				{
-					IPACMDBG("Got Neighbor event with ipv4 address \n");
+					IPACMDBG("Got Neighbor event with ipv4 address: 0x%x \n", data->ipv4_addr);
+					/* check if ipv4 address is link local(169.254.xxx.xxx) */
+					if ((data->ipv4_addr & IPV4_ADDR_LINKLOCAL_MASK) == IPV4_ADDR_LINKLOCAL)
+					{
+						IPACMDBG_H("This is link local ipv4 address: 0x%x : ignore this NEIGH_EVENT\n", data->ipv4_addr);
+						return;
+					}
 					/* check if iface is bridge interface*/
 					if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) == 0)
 					{
@@ -355,7 +361,7 @@
 
 				if ((data->ipv6_addr[0]) || (data->ipv6_addr[1]) || (data->ipv6_addr[2]) || (data->ipv6_addr[3]))
 				{
-					IPACMDBG(" Got New_Neighbor event with ipv6 address \n");
+					IPACMDBG("Got New_Neighbor event with ipv6 address \n");
 					/* check if iface is bridge interface*/
 					if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) == 0)
 					{