@@ -2813,14 +2813,30 @@ int Dtls13DoScheduledWork(WOLFSSL* ssl)
28132813 * shared WriteDup struct so the write side sends the ACK instead. */
28142814 if (ssl -> dupWrite != NULL && ssl -> dupSide == READ_DUP_SIDE ) {
28152815 struct Dtls13RecordNumber * * tail = NULL ;
2816+ int count = 0 ;
28162817 if (wc_LockMutex (& ssl -> dupWrite -> dupMutex ) != 0 )
28172818 return BAD_MUTEX_E ;
2819+ /* Walk to the tail, counting what is already queued. */
28182820 tail = (struct Dtls13RecordNumber * * )& ssl -> dupWrite -> sendAckList ;
2819- while (* tail != NULL )
2821+ while (* tail != NULL ) {
28202822 tail = & (* tail )-> next ;
2821- * tail = ssl -> dtls13Rtx .seenRecords ;
2822- ssl -> dtls13Rtx .seenRecords = NULL ;
2823- ssl -> dtls13Rtx .seenRecordsCount = 0 ;
2823+ count ++ ;
2824+ }
2825+ /* Each transferred batch is already capped at
2826+ * DTLS13_ACK_MAX_RECORDS. Only splice a new batch while the queue
2827+ * is below the cap so repeated scheduled-work cycles cannot grow
2828+ * it without bound (aggregate stays under 2 *
2829+ * DTLS13_ACK_MAX_RECORDS). Otherwise drop the batch: ACKs are
2830+ * best-effort and the peer retransmits if one is lost. */
2831+ if (count < DTLS13_ACK_MAX_RECORDS ) {
2832+ * tail = ssl -> dtls13Rtx .seenRecords ;
2833+ ssl -> dtls13Rtx .seenRecords = NULL ;
2834+ ssl -> dtls13Rtx .seenRecordsCount = 0 ;
2835+ }
2836+ else {
2837+ /* Queue already at the cap: drop this batch. */
2838+ Dtls13RtxFlushAcks (ssl );
2839+ }
28242840 ssl -> dupWrite -> sendAcks = 1 ;
28252841 wc_UnLockMutex (& ssl -> dupWrite -> dupMutex );
28262842 }
0 commit comments