MINOR: quic: Add a lock for RX packets

We must protect from concurrent the tree which stores the QUIC packets received
by the dgram I/O handler, these packets being also parsed by the xprt task.
diff --git a/include/haproxy/thread.h b/include/haproxy/thread.h
index b962535..97470dd 100644
--- a/include/haproxy/thread.h
+++ b/include/haproxy/thread.h
@@ -413,6 +413,7 @@
 	SSL_SERVER_LOCK,
 	SFT_LOCK, /* sink forward target */
 	IDLE_CONNS_LOCK,
+	QUIC_LOCK,
 	OTHER_LOCK,
 	/* WT: make sure never to use these ones outside of development,
 	 * we need them for lock profiling!
@@ -466,6 +467,7 @@
 	case SSL_SERVER_LOCK:      return "SSL_SERVER";
 	case SFT_LOCK:             return "SFT";
 	case IDLE_CONNS_LOCK:      return "IDLE_CONNS";
+	case QUIC_LOCK:            return "QUIC";
 	case OTHER_LOCK:           return "OTHER";
 	case DEBUG1_LOCK:          return "DEBUG1";
 	case DEBUG2_LOCK:          return "DEBUG2";
diff --git a/include/haproxy/xprt_quic-t.h b/include/haproxy/xprt_quic-t.h
index bf4f5f5..6c6a206 100644
--- a/include/haproxy/xprt_quic-t.h
+++ b/include/haproxy/xprt_quic-t.h
@@ -530,6 +530,8 @@
 		/* The packets received by the listener I/O handler
 		   with header protection removed. */
 		struct eb_root pkts;
+		/* <pkts> must be protected from concurrent accesses */
+		__decl_thread(HA_RWLOCK_T rwlock);
 		/* Liste of QUIC packets with protected header. */
 		struct list pqpkts;
 		/* Crypto frames */
diff --git a/src/xprt_quic.c b/src/xprt_quic.c
index f4b95e7..b7a1918 100644
--- a/src/xprt_quic.c
+++ b/src/xprt_quic.c
@@ -2403,7 +2403,9 @@
 			pqpkt->aad_len = pqpkt->pn_offset + pqpkt->pnl;
 			/* Store the packet into the tree of packets to decrypt. */
 			pqpkt->pn_node.key = pqpkt->pn;
+			HA_RWLOCK_WRLOCK(QUIC_LOCK, &el->rx.rwlock);
 			quic_rx_packet_eb64_insert(&el->rx.pkts, &pqpkt->pn_node);
+			HA_RWLOCK_WRUNLOCK(QUIC_LOCK, &el->rx.rwlock);
 			TRACE_PROTO("hp removed", QUIC_EV_CONN_ELRMHP, ctx->conn, pqpkt);
 		}
 		quic_rx_packet_list_del(pqpkt);
@@ -2457,6 +2459,7 @@
 
 	TRACE_ENTER(QUIC_EV_CONN_ELRXPKTS, ctx->conn);
 	tls_ctx = &el->tls_ctx;
+	HA_RWLOCK_WRLOCK(QUIC_LOCK, &el->rx.rwlock);
 	node = eb64_first(&el->rx.pkts);
 	while (node) {
 		struct quic_rx_packet *pkt;
@@ -2495,6 +2498,7 @@
 		node = eb64_next(node);
 		quic_rx_packet_eb64_delete(&pkt->pn_node);
 	}
+	HA_RWLOCK_WRUNLOCK(QUIC_LOCK, &el->rx.rwlock);
 
 	if (!qc_treat_rx_crypto_frms(el, ctx))
 		goto err;
@@ -2624,6 +2628,7 @@
 	qel->tls_ctx.tx.flags = 0;
 
 	qel->rx.pkts = EB_ROOT;
+	HA_RWLOCK_INIT(&qel->rx.rwlock);
 	LIST_INIT(&qel->rx.pqpkts);
 
 	/* Allocate only one buffer. */
@@ -3002,7 +3007,9 @@
 		qpkt_trace = pkt;
 		/* Store the packet */
 		pkt->pn_node.key = pkt->pn;
+		HA_RWLOCK_WRLOCK(QUIC_LOCK, &qel->rx.rwlock);
 		quic_rx_packet_eb64_insert(&qel->rx.pkts, &pkt->pn_node);
+		HA_RWLOCK_WRUNLOCK(QUIC_LOCK, &qel->rx.rwlock);
 	}
 	else if (qel) {
 		TRACE_PROTO("hp not removed", QUIC_EV_CONN_TRMHP, ctx ? ctx->conn : NULL, pkt);