@@ -2822,14 +2822,30 @@ int Dtls13DoScheduledWork(WOLFSSL* ssl)
28222822 * shared WriteDup struct so the write side sends the ACK instead. */
28232823 if (ssl -> dupWrite != NULL && ssl -> dupSide == READ_DUP_SIDE ) {
28242824 struct Dtls13RecordNumber * * tail = NULL ;
2825+ int count = 0 ;
28252826 if (wc_LockMutex (& ssl -> dupWrite -> dupMutex ) != 0 )
28262827 return BAD_MUTEX_E ;
2828+ /* Walk to the tail, counting what is already queued. */
28272829 tail = (struct Dtls13RecordNumber * * )& ssl -> dupWrite -> sendAckList ;
2828- while (* tail != NULL )
2830+ while (* tail != NULL ) {
28292831 tail = & (* tail )-> next ;
2830- * tail = ssl -> dtls13Rtx .seenRecords ;
2831- ssl -> dtls13Rtx .seenRecords = NULL ;
2832- ssl -> dtls13Rtx .seenRecordsCount = 0 ;
2832+ count ++ ;
2833+ }
2834+ /* Each transferred batch is already capped at
2835+ * DTLS13_ACK_MAX_RECORDS. Only splice a new batch while the queue
2836+ * is below the cap so repeated scheduled-work cycles cannot grow
2837+ * it without bound (aggregate stays under 2 *
2838+ * DTLS13_ACK_MAX_RECORDS). Otherwise drop the batch: ACKs are
2839+ * best-effort and the peer retransmits if one is lost. */
2840+ if (count < DTLS13_ACK_MAX_RECORDS ) {
2841+ * tail = ssl -> dtls13Rtx .seenRecords ;
2842+ ssl -> dtls13Rtx .seenRecords = NULL ;
2843+ ssl -> dtls13Rtx .seenRecordsCount = 0 ;
2844+ }
2845+ else {
2846+ /* Queue already at the cap: drop this batch. */
2847+ Dtls13RtxFlushAcks (ssl );
2848+ }
28332849 ssl -> dupWrite -> sendAcks = 1 ;
28342850 wc_UnLockMutex (& ssl -> dupWrite -> dupMutex );
28352851 }
0 commit comments