msm: ipacm: Added unordered addDownstream/removeDownstream handling

addDownstream and removeDownstream events can arrive in any order
during SSC mode 3 and hence these should be handled irrespective
of the order of their arrival

Change-Id: Iff28f9ca0d75fefa49e1f2fb9c8a9a9cb4a58f5d
Acked-by: Abhishek Raghuvanshi <araghuva@qti.qualcomm.com>
Signed-off-by: Chaitanya Pratapa <quic_cpratapa@quicinc.com>
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
index 4201624..88d38bc 100644
--- a/ipacm/src/IPACM_Lan.cpp
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -773,6 +773,32 @@
 		{
 			IPACMDBG_H("Received IPA_DOWNSTREAM_ADD event.\n");
 
+			/* Delete existing downstream if it exists */
+			if (is_downstream_set[data->prefix.iptype] == true)
+			{
+				if (ipv6_prefix[0] != data->prefix.v6Addr[0] ||
+					ipv6_prefix[1] != data->prefix.v6Addr[1])
+				{
+					IPACMDBG_H("Del existing downstream for IP iptype %d.\n", data->prefix.iptype);
+					is_downstream_set[data->prefix.iptype] = false;
+					store_downstream_state(false, data->prefix.iptype);
+					if (is_upstream_set[data->prefix.iptype] == true)
+					{
+						IPACMDBG_H("Upstream was set before, deleting UL rules.\n");
+						if (data->prefix.iptype == IPA_IP_v4)
+						{
+							/* LTE STA */
+							handle_wan_down(IPACM_Wan::backhaul_mode);
+						} else {
+							handle_lan_client_reset_rt(IPA_IP_v6);
+
+							 /* LTE STA */
+							handle_wan_down_v6(IPACM_Wan::backhaul_mode);
+						}
+					}
+				}
+			}
+
 			if (data->prefix.iptype < IPA_IP_MAX && is_downstream_set[data->prefix.iptype] == false)
 			{
 				IPACMDBG_H("Add downstream for IP iptype %d\n", data->prefix.iptype);
@@ -829,18 +855,23 @@
 			IPACMDBG_H("Received IPA_DOWNSTREAM_DEL event.\n");
 			if (is_downstream_set[data->prefix.iptype] == true)
 			{
-				IPACMDBG_H("Del downstream for IP iptype %d.\n", data->prefix.iptype);
-				is_downstream_set[data->prefix.iptype] = false;
-				store_downstream_state(false, data->prefix.iptype);
-				if (is_upstream_set[data->prefix.iptype] == true)
+				/* Handle downstream del event only when the prefix matches */
+				if (ipv6_prefix[0] == data->prefix.v6Addr[0] &&
+					ipv6_prefix[1] == data->prefix.v6Addr[1])
 				{
-					IPACMDBG_H("Upstream was set before, deleting UL rules.\n");
-					if (data->prefix.iptype == IPA_IP_v4)
+					IPACMDBG_H("Del downstream for IP iptype %d.\n", data->prefix.iptype);
+					is_downstream_set[data->prefix.iptype] = false;
+					store_downstream_state(false, data->prefix.iptype);
+					if (is_upstream_set[data->prefix.iptype] == true)
 					{
-						handle_wan_down(IPACM_Wan::backhaul_mode); /* LTE STA */
-					} else {
-						handle_lan_client_reset_rt(IPA_IP_v6);
-						handle_wan_down_v6(IPACM_Wan::backhaul_mode); /* LTE STA */
+						IPACMDBG_H("Upstream was set before, deleting UL rules.\n");
+						if (data->prefix.iptype == IPA_IP_v4)
+						{
+							handle_wan_down(IPACM_Wan::backhaul_mode); /* LTE STA */
+						} else {
+							handle_lan_client_reset_rt(IPA_IP_v6);
+							handle_wan_down_v6(IPACM_Wan::backhaul_mode); /* LTE STA */
+						}
 					}
 				}
 			}
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
index 58bbeee..c596256 100644
--- a/ipacm/src/IPACM_Wlan.cpp
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -562,6 +562,33 @@
 		if(ipa_interface_index == ipa_if_num)
 		{
 			IPACMDBG_H("Received IPA_DOWNSTREAM_ADD event.\n");
+
+			/* Delete any existing downstream before adding a new one*/
+			if(is_downstream_set[data->prefix.iptype] == true)
+			{
+				if (ipv6_prefix[0] != data->prefix.v6Addr[0] ||
+					ipv6_prefix[1] != data->prefix.v6Addr[1])
+				{
+					IPACMDBG_H("Del existing downstream for IP iptype %d.\n", data->prefix.iptype);
+					is_downstream_set[data->prefix.iptype] = false;
+					store_downstream_state(false, data->prefix.iptype);
+					if(is_upstream_set[data->prefix.iptype] == true)
+					{
+						IPACMDBG_H("Upstream was set before, deleting UL rules.\n");
+						if (data->prefix.iptype == IPA_IP_v4)
+						{
+							/* LTE STA */
+							handle_wan_down(IPACM_Wan::backhaul_mode);
+						} else {
+							handle_wlan_client_reset_rt(IPA_IP_v6);
+
+							/* LTE STA */
+							handle_wan_down_v6(IPACM_Wan::backhaul_mode);
+						}
+					}
+				}
+			}
+
 			if(data->prefix.iptype < IPA_IP_MAX && is_downstream_set[data->prefix.iptype] == false)
 			{
 				IPACMDBG_H("Add downstream for IP iptype %d.\n", data->prefix.iptype);
@@ -615,18 +642,23 @@
 			IPACMDBG_H("Received IPA_DOWNSTREAM_DEL event.\n");
 			if(is_downstream_set[data->prefix.iptype] == true)
 			{
-				IPACMDBG_H("Del downstream for IP iptype %d.\n", data->prefix.iptype);
-				is_downstream_set[data->prefix.iptype] = false;
-				store_downstream_state(false, data->prefix.iptype);
-				if(is_upstream_set[data->prefix.iptype] == true)
+				/* Handle downstream del event only when the prefix matches */
+				if (ipv6_prefix[0] == data->prefix.v6Addr[0] &&
+					ipv6_prefix[1] == data->prefix.v6Addr[1])
 				{
-					IPACMDBG_H("Upstream was set before, deleting UL rules.\n");
-					if (data->prefix.iptype == IPA_IP_v4)
+					IPACMDBG_H("Del downstream for IP iptype %d.\n", data->prefix.iptype);
+					is_downstream_set[data->prefix.iptype] = false;
+					store_downstream_state(false, data->prefix.iptype);
+					if(is_upstream_set[data->prefix.iptype] == true)
 					{
-						handle_wan_down(IPACM_Wan::backhaul_mode); /* LTE STA */
-					} else {
-						handle_wlan_client_reset_rt(IPA_IP_v6);
-						handle_wan_down_v6(IPACM_Wan::backhaul_mode); /* LTE STA */
+						IPACMDBG_H("Upstream was set before, deleting UL rules.\n");
+						if (data->prefix.iptype == IPA_IP_v4)
+						{
+							handle_wan_down(IPACM_Wan::backhaul_mode); /* LTE STA */
+						} else {
+							handle_wlan_client_reset_rt(IPA_IP_v6);
+							handle_wan_down_v6(IPACM_Wan::backhaul_mode); /* LTE STA */
+						}
 					}
 				}
 			}