Commit 76c333d2e8 for frr

commit 76c333d2e828e65f03128f2db3cfc115db69cc93
Author: Chenlang Li <lichenlang@catalystovo.com>
Date:   Fri Nov 6 23:26:36 2026 +0800

    ospf6d: track the neighbor's seqnumber_mismatch/bad_lsreq events

    seqnumber_mismatch() and bad_lsreq() are queued with event_add_event()
    and the neighbor as the event argument, with NULL as the event handle.
    Nothing can cancel them by hand, so if the neighbor is deleted before
    they run - a link state request or a bad sequence number arriving in the
    same event batch as an interface teardown - the callback reads the freed
    neighbor.

    Give the neighbor a handle for each of them, pass it at every queue site
    and cancel both in ospf6_neighbor_delete(), next to the other per-
    neighbor handles.  event_cancel() before re-arming keeps at most one
    event pending per handle, and _event_add_event() refuses a second one
    while the handle is set, so an earlier event cannot be orphaned.

    Signed-off-by: Chenlang Li <lichenlang@catalystovo.com>

diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index 9d3ca5284d..62412a026c 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -1155,7 +1155,8 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
 			new->name);

 		/* BadLSReq */
-		event_add_event(master, bad_lsreq, from, 0, NULL);
+		event_cancel(&from->thread_bad_lsreq);
+		event_add_event(master, bad_lsreq, from, 0, &from->thread_bad_lsreq);

 		ospf6_lsa_delete(new);
 		return;
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index aa39a95cb2..c5fdd37e65 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -691,24 +691,27 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
 			zlog_warn(
 				"DbDesc recv: Master/Slave bit mismatch Nbr %s",
 				on->name);
+			event_cancel(&on->thread_seqnumber_mismatch);
 			event_add_event(master, seqnumber_mismatch, on, 0,
-					NULL);
+					&on->thread_seqnumber_mismatch);
 			return;
 		}

 		if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)) {
 			zlog_warn("DbDesc recv: Initialize bit mismatch Nbr %s",
 				  on->name);
+			event_cancel(&on->thread_seqnumber_mismatch);
 			event_add_event(master, seqnumber_mismatch, on, 0,
-					NULL);
+					&on->thread_seqnumber_mismatch);
 			return;
 		}

 		if (memcmp(on->options, dbdesc->options, sizeof(on->options))) {
 			zlog_warn("DbDesc recv: Option field mismatch Nbr %s",
 				  on->name);
+			event_cancel(&on->thread_seqnumber_mismatch);
 			event_add_event(master, seqnumber_mismatch, on, 0,
-					NULL);
+					&on->thread_seqnumber_mismatch);
 			return;
 		}

@@ -717,8 +720,9 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
 				"DbDesc recv: Sequence number mismatch Nbr %s (received %#lx, %#lx expected)",
 				on->name, (unsigned long)ntohl(dbdesc->seqnum),
 				(unsigned long)on->dbdesc_seqnum);
+			event_cancel(&on->thread_seqnumber_mismatch);
 			event_add_event(master, seqnumber_mismatch, on, 0,
-					 NULL);
+					&on->thread_seqnumber_mismatch);
 			return;
 		}
 		break;
@@ -738,7 +742,8 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
 		zlog_warn(
 			"DbDesc recv: Not duplicate dbdesc in state %s Nbr %s",
 			ospf6_neighbor_state_str[on->state], on->name);
-		event_add_event(master, seqnumber_mismatch, on, 0, NULL);
+		event_cancel(&on->thread_seqnumber_mismatch);
+		event_add_event(master, seqnumber_mismatch, on, 0, &on->thread_seqnumber_mismatch);
 		return;

 	default:
@@ -784,8 +789,9 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
 				zlog_debug(
 					"SeqNumMismatch (E-bit mismatch), discard");
 			ospf6_lsa_delete(his);
+			event_cancel(&on->thread_seqnumber_mismatch);
 			event_add_event(master, seqnumber_mismatch, on, 0,
-					NULL);
+					&on->thread_seqnumber_mismatch);
 			return;
 		}

@@ -914,8 +920,9 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
 			zlog_warn(
 				"DbDesc slave recv: Master/Slave bit mismatch Nbr %s",
 				on->name);
+			event_cancel(&on->thread_seqnumber_mismatch);
 			event_add_event(master, seqnumber_mismatch, on, 0,
-					NULL);
+					&on->thread_seqnumber_mismatch);
 			return;
 		}

@@ -923,8 +930,9 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
 			zlog_warn(
 				"DbDesc slave recv: Initialize bit mismatch Nbr %s",
 				on->name);
+			event_cancel(&on->thread_seqnumber_mismatch);
 			event_add_event(master, seqnumber_mismatch, on, 0,
-					NULL);
+					&on->thread_seqnumber_mismatch);
 			return;
 		}

@@ -932,8 +940,9 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
 			zlog_warn(
 				"DbDesc slave recv: Option field mismatch Nbr %s",
 				on->name);
+			event_cancel(&on->thread_seqnumber_mismatch);
 			event_add_event(master, seqnumber_mismatch, on, 0,
-					NULL);
+					&on->thread_seqnumber_mismatch);
 			return;
 		}

@@ -942,8 +951,9 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
 				"DbDesc slave recv: Sequence number mismatch Nbr %s (received %#lx, %#lx expected)",
 				on->name, (unsigned long)ntohl(dbdesc->seqnum),
 				(unsigned long)on->dbdesc_seqnum + 1);
+			event_cancel(&on->thread_seqnumber_mismatch);
 			event_add_event(master, seqnumber_mismatch, on, 0,
-					 NULL);
+					&on->thread_seqnumber_mismatch);
 			return;
 		}
 		break;
@@ -966,7 +976,8 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
 		zlog_warn(
 			"DbDesc slave recv: Not duplicate dbdesc in state %s Nbr %s",
 			ospf6_neighbor_state_str[on->state], on->name);
-		event_add_event(master, seqnumber_mismatch, on, 0, NULL);
+		event_cancel(&on->thread_seqnumber_mismatch);
+		event_add_event(master, seqnumber_mismatch, on, 0, &on->thread_seqnumber_mismatch);
 		return;

 	default:
@@ -1008,8 +1019,9 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
 			if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
 				zlog_debug("E-bit mismatch with LSA Headers");
 			ospf6_lsa_delete(his);
+			event_cancel(&on->thread_seqnumber_mismatch);
 			event_add_event(master, seqnumber_mismatch, on, 0,
-					NULL);
+					&on->thread_seqnumber_mismatch);
 			return;
 		}

@@ -1160,7 +1172,8 @@ static void ospf6_lsreq_recv(struct in6_addr *src, struct in6_addr *dst,
 				"Can't find requested lsa [%s Id:%pI4 Adv:%pI4] send badLSReq",
 				ospf6_lstype_name(e->type), &e->id,
 				&e->adv_router);
-			event_add_event(master, bad_lsreq, on, 0, NULL);
+			event_cancel(&on->thread_bad_lsreq);
+			event_add_event(master, bad_lsreq, on, 0, &on->thread_bad_lsreq);
 			return;
 		}

diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
index 4d079afb1a..fad77861e3 100644
--- a/ospf6d/ospf6_neighbor.c
+++ b/ospf6d/ospf6_neighbor.c
@@ -194,6 +194,10 @@ void ospf6_neighbor_delete(struct ospf6_neighbor *on)
 	event_cancel(&on->gr_helper_info.t_grace_timer);

 	bfd_sess_free(&on->bfd_session);
+
+	event_cancel(&on->thread_seqnumber_mismatch);
+	event_cancel(&on->thread_bad_lsreq);
+
 	XFREE(MTYPE_OSPF6_NEIGHBOR, on);
 }

diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h
index 38ddb46f64..343294dd9d 100644
--- a/ospf6d/ospf6_neighbor.h
+++ b/ospf6d/ospf6_neighbor.h
@@ -137,6 +137,8 @@ struct ospf6_neighbor {
 	struct event *thread_exchange_done;
 	struct event *thread_adj_ok;
 	struct event *event_loading_done;
+	struct event *thread_seqnumber_mismatch;
+	struct event *thread_bad_lsreq;

 	/* BFD information */
 	struct bfd_session_params *bfd_session;