Merge "[qca-nss-ecm] Fix destroy re-try mechanism."
diff --git a/ecm_db.c b/ecm_db.c
index ebcf79c..d15e33b 100644
--- a/ecm_db.c
+++ b/ecm_db.c
@@ -1040,6 +1040,8 @@
  */
 static void ecm_db_connection_defunct_callback(void *arg)
 {
+	struct ecm_front_end_connection_instance *feci;
+	ecm_front_end_acceleration_mode_t accel_mode;
 	struct ecm_db_connection_instance *ci = (struct ecm_db_connection_instance *)arg;
 	DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
 
@@ -1049,7 +1051,20 @@
 		ci->defunct(ci->feci);
 	}
 
-	ecm_db_connection_deref(ci);
+	feci = ecm_db_connection_front_end_get_and_ref(ci);
+	accel_mode = feci->accel_state_get(feci);
+	feci->deref(feci);
+
+	/*
+	 * It is possible that the defunct process fails and re-try is in progress.
+	 * In that case we set the accel mode of the connection to
+	 * ECM_FRONT_END_ACCELERATION_MODE_ACCEL so that in the next destroy try the connection
+	 * status would be correct. So, if the accel_mode is ECM_FRONT_END_ACCELERATION_MODE_ACCEL,
+	 * we shouldn't release the last reference count.
+	 */
+	if (accel_mode != ECM_FRONT_END_ACCELERATION_MODE_ACCEL) {
+		ecm_db_connection_deref(ci);
+	}
 }
 
 /*
@@ -2385,6 +2400,42 @@
 EXPORT_SYMBOL(ecm_db_timer_group_entry_set);
 
 /*
+ * ecm_db_connection_defunct_timer_remove_and_set()
+ *	Move the connection to a new timer group.
+ *
+ * Before setting the new group, check if the timer group is set. If it is set,
+ * remove it first from the current group.
+ *
+ */
+void ecm_db_connection_defunct_timer_remove_and_set(struct ecm_db_connection_instance *ci, ecm_db_timer_group_t tg)
+{
+	struct ecm_db_timer_group_entry *tge;
+
+	DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
+	DEBUG_TRACE("%p: ecm_db_connection_defunct_timer_remove_and_set\n", ci);
+
+	spin_lock_bh(&ecm_db_lock);
+	tge = &ci->defunct_timer;
+	if (tge->group == tg) {
+		spin_unlock_bh(&ecm_db_lock);
+		DEBUG_TRACE("%p: timer group is aslready equal to %d\n", ci, tg);
+		return;
+	}
+
+	if (tge->group != ECM_DB_TIMER_GROUPS_MAX) {
+		_ecm_db_timer_group_entry_remove(tge);
+	}
+
+	/*
+	 * Set new group
+	 */
+	_ecm_db_timer_group_entry_set(tge, tg);
+	spin_unlock_bh(&ecm_db_lock);
+	DEBUG_TRACE("%p: New timer group is: %d\n", ci, tge->group);
+}
+EXPORT_SYMBOL(ecm_db_connection_defunct_timer_remove_and_set);
+
+/*
  * ecm_db_timer_group_entry_init()
  *	Initialise a timer entry ready for setting
  */
diff --git a/ecm_db.h b/ecm_db.h
index d42bcef..6786f46 100644
--- a/ecm_db.h
+++ b/ecm_db.h
@@ -38,6 +38,7 @@
 void ecm_db_connection_data_totals_update_dropped(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets);
 void ecm_db_connection_data_totals_update(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets);
 
+void ecm_db_connection_defunct_timer_remove_and_set(struct ecm_db_connection_instance *ci, ecm_db_timer_group_t tg);
 int ecm_db_connection_elapsed_defunct_timer(struct ecm_db_connection_instance *ci);
 bool ecm_db_connection_defunct_timer_reset(struct ecm_db_connection_instance *ci, ecm_db_timer_group_t tg);
 bool ecm_db_connection_defunct_timer_touch(struct ecm_db_connection_instance *ci);
diff --git a/frontends/ecm_front_end_common.c b/frontends/ecm_front_end_common.c
index 6ed9d4b..37e02f0 100644
--- a/frontends/ecm_front_end_common.c
+++ b/frontends/ecm_front_end_common.c
@@ -110,8 +110,8 @@
 	spin_unlock_bh(&feci->lock);
 
 	/*
-	 * Reset the defunct timer to a smaller timeout value so that the connection will be
+	 * Set the defunct timer to a smaller timeout value so that the connection will be
 	 * tried to be defuncted again, when the timeout expires (its value is 5 seconds).
 	 */
-	ecm_db_connection_defunct_timer_reset(feci->ci, ECM_DB_TIMER_GROUPS_CONNECTION_DEFUNCT_RETRY_TIMEOUT);
+	ecm_db_connection_defunct_timer_remove_and_set(feci->ci, ECM_DB_TIMER_GROUPS_CONNECTION_DEFUNCT_RETRY_TIMEOUT);
 }