From bc6c1e3717e699a00ba3ad56648d38c23f8cd40c Mon Sep 17 00:00:00 2001
From: Anjan Chanda <anjan.chanda@iopsys.eu>
Date: Tue, 11 Jun 2024 10:55:55 +0200
Subject: [PATCH] unlink hlist entries before delete

---
 src/cmdu_ackq.c | 27 ++++++++++++++++++++++++---
 src/debug.h     | 10 ++++++++++
 src/neigh.c     |  6 +++++-
 3 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/src/cmdu_ackq.c b/src/cmdu_ackq.c
index c7e4bc6f..66d5dc17 100644
--- a/src/cmdu_ackq.c
+++ b/src/cmdu_ackq.c
@@ -20,9 +20,20 @@
 #include "cmdu_ackq.h"
 
 #define err(...)	log_stderr(0, __VA_ARGS__)
+#define warn(...)	log_stderr(1, __VA_ARGS__)
 #define dbg(...)	log_stderr(3, __VA_ARGS__)
 #define loud(...)	log_stderr(5, __VA_ARGS__)
 
+#ifndef warn_on
+#define warn_on(condition)					\
+({								\
+	int __rc = !!(condition);				\
+	if (__rc)						\
+		warn("%s: WARN '%s'\n", __func__, #condition);	\
+	__rc;							\
+})
+#endif
+
 static int timeradd_msecs(struct timeval *a, unsigned long msecs,
 			  struct timeval *res)
 {
@@ -102,10 +113,12 @@ static void cmdu_ackq_delete_msg(struct cmdu_ackq *st, struct cmdu_ackq_entry *m
 		return;
 
 	if (msg->cookie) {
-		if (st->delete_cb)
+		if (st->delete_cb) {
 			st->delete_cb(st, msg);
-		else
+		} else {
 			free(msg->cookie);
+			msg->cookie = NULL;
+		}
 	}
 
 	free(msg);
@@ -241,15 +254,23 @@ void cmdu_ackq_flush(void *cmdu_q)
 {
 	struct cmdu_ackq *q = (struct cmdu_ackq *)cmdu_q;
 	struct cmdu_ackq_entry *msg = NULL;
+	struct hlist_node *tmp;
 	int idx = 0;
 
 	for (idx = 0; idx < CMDU_BACKLOG_MAX; idx++) {
-		hlist_for_each_entry(msg, &q->table[idx], hlist)
+		if (hlist_empty(&q->table[idx]))
+			continue;
+
+		hlist_for_each_entry_safe(msg, tmp, &q->table[idx], hlist) {
+			hlist_del(&msg->hlist, &q->table[idx]);
+			q->pending_cnt--;
 			cmdu_ackq_delete_msg(q, msg);
+		}
 
 		q->table[idx].first = NULL;
 	}
 
+	warn_on(q->pending_cnt != 0);
 	q->pending_cnt = 0;
 }
 
diff --git a/src/debug.h b/src/debug.h
index d52183fc..c10eb6c9 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -41,6 +41,15 @@ void log_cmdu(uint8_t *buf, size_t len, const char *ifname, bool is_rx);
 #define dbg7(fmt, ...)        log_message(7, nocl fmt nocl, ## __VA_ARGS__)
 
 #define logcmdu(b,l,i,t)      log_cmdu(b,l,i,t)
+
+#define warn_on(condition)					\
+({								\
+	int __rc = !!(condition);				\
+	if (__rc)						\
+		warn("%s: WARN '%s'\n", __func__, #condition);	\
+	__rc;							\
+})
+
 #else
 
 #define err(...)	log_message(0, __VA_ARGS__)
@@ -54,6 +63,7 @@ void log_cmdu(uint8_t *buf, size_t len, const char *ifname, bool is_rx);
 #define dbg7(fmt, ...)  log_message(7, __VA_ARGS__)
 
 #define logcmdu(b,l,i,t)
+#define warn_on(condition)
 #endif /* DEBUG_COLOR */
 
 #endif /* DEBUG_H */
diff --git a/src/neigh.c b/src/neigh.c
index 0ecc92a0..b9164518 100644
--- a/src/neigh.c
+++ b/src/neigh.c
@@ -321,12 +321,16 @@ void neigh_queue_flush(void *nq)
 		if (hlist_empty(&q->table[idx]))
 			continue;
 
-		hlist_for_each_entry_safe(e, tmp, &q->table[idx], hlist)
+		hlist_for_each_entry_safe(e, tmp, &q->table[idx], hlist) {
+			hlist_del(&e->hlist, &q->table[idx]);
+			q->pending_cnt--;
 			neigh_entry_delete(e);
+		}
 
 		q->table[idx].first = NULL;
 	}
 
+	warn_on(q->pending_cnt != 0);
 	q->pending_cnt = 0;
 }
 
-- 
GitLab