Coverage Report

Created: 2026-09-03 07:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/third_party/ngtcp2/lib/ngtcp2_rtb.c
Line
Count
Source
1
/*
2
 * ngtcp2
3
 *
4
 * Copyright (c) 2017 ngtcp2 contributors
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining
7
 * a copy of this software and associated documentation files (the
8
 * "Software"), to deal in the Software without restriction, including
9
 * without limitation the rights to use, copy, modify, merge, publish,
10
 * distribute, sublicense, and/or sell copies of the Software, and to
11
 * permit persons to whom the Software is furnished to do so, subject to
12
 * the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be
15
 * included in all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
 */
25
#include "ngtcp2_rtb.h"
26
27
#include <assert.h>
28
#include <string.h>
29
30
#include "ngtcp2_macro.h"
31
#include "ngtcp2_conn.h"
32
#include "ngtcp2_log.h"
33
#include "ngtcp2_vec.h"
34
#include "ngtcp2_cc.h"
35
#include "ngtcp2_rcvry.h"
36
#include "ngtcp2_rst.h"
37
#include "ngtcp2_unreachable.h"
38
#include "ngtcp2_tstamp.h"
39
#include "ngtcp2_frame_chain.h"
40
41
0
ngtcp2_objalloc_def(rtb_entry, ngtcp2_rtb_entry, oplent)
Unexecuted instantiation: ngtcp2_objalloc_rtb_entry_get
Unexecuted instantiation: ngtcp2_objalloc_rtb_entry_len_get
42
43
static void rtb_entry_init(ngtcp2_rtb_entry *ent, const ngtcp2_pkt_hd *hd,
44
                           ngtcp2_frame_chain *frc, ngtcp2_tstamp ts,
45
0
                           size_t pktlen, uint16_t flags) {
46
0
  *ent = (ngtcp2_rtb_entry){
47
0
    .hd =
48
0
      {
49
0
        .pkt_num = hd->pkt_num,
50
0
        .type = hd->type,
51
0
        .flags = hd->flags,
52
0
      },
53
0
    .frc = frc,
54
0
    .ts = ts,
55
0
    .lost_ts = UINT64_MAX,
56
0
    .pktlen = pktlen,
57
0
    .flags = flags,
58
0
  };
59
0
}
60
61
int ngtcp2_rtb_entry_objalloc_new(ngtcp2_rtb_entry **pent,
62
                                  const ngtcp2_pkt_hd *hd,
63
                                  ngtcp2_frame_chain *frc, ngtcp2_tstamp ts,
64
                                  size_t pktlen, uint16_t flags,
65
0
                                  ngtcp2_objalloc *objalloc) {
66
0
  *pent = ngtcp2_objalloc_rtb_entry_get(objalloc);
67
0
  if (*pent == NULL) {
68
0
    return NGTCP2_ERR_NOMEM;
69
0
  }
70
71
0
  rtb_entry_init(*pent, hd, frc, ts, pktlen, flags);
72
73
0
  return 0;
74
0
}
75
76
void ngtcp2_rtb_entry_objalloc_del(ngtcp2_rtb_entry *ent,
77
                                   ngtcp2_objalloc *objalloc,
78
                                   ngtcp2_objalloc *frc_objalloc,
79
0
                                   const ngtcp2_mem *mem) {
80
0
  ngtcp2_frame_chain_list_objalloc_del(ent->frc, frc_objalloc, mem);
81
82
0
  ent->frc = NULL;
83
84
0
  ngtcp2_objalloc_rtb_entry_release(objalloc, ent);
85
0
}
86
87
void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_rst *rst, ngtcp2_cc *cc,
88
                     int64_t cc_pkt_num, ngtcp2_log *log, ngtcp2_qlog *qlog,
89
                     ngtcp2_objalloc *rtb_entry_objalloc,
90
0
                     ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) {
91
0
  rtb->rtb_entry_objalloc = rtb_entry_objalloc;
92
0
  rtb->frc_objalloc = frc_objalloc;
93
0
  ngtcp2_ksl_init(&rtb->ents, ngtcp2_ksl_int64_greater,
94
0
                  ngtcp2_ksl_int64_greater_search, sizeof(int64_t), mem);
95
0
  rtb->rst = rst;
96
0
  rtb->cc = cc;
97
0
  rtb->log = log;
98
0
  rtb->qlog = qlog;
99
0
  rtb->mem = mem;
100
0
  rtb->largest_acked_tx_pkt_num = -1;
101
0
  rtb->num_ack_eliciting = 0;
102
0
  rtb->num_retransmittable = 0;
103
0
  rtb->num_pto_eliciting = 0;
104
0
  rtb->probe_pkt_left = 0;
105
0
  rtb->cc_pkt_num = cc_pkt_num;
106
0
  rtb->cc_bytes_in_flight = 0;
107
0
  rtb->num_lost_pkts = 0;
108
0
  rtb->num_lost_ignore_pkts = 0;
109
0
}
110
111
0
void ngtcp2_rtb_free(ngtcp2_rtb *rtb) {
112
0
  ngtcp2_ksl_it it;
113
114
0
  if (rtb == NULL) {
115
0
    return;
116
0
  }
117
118
0
  it = ngtcp2_ksl_begin(&rtb->ents);
119
120
0
  for (; !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) {
121
0
    ngtcp2_rtb_entry_objalloc_del(ngtcp2_ksl_it_get(&it),
122
0
                                  rtb->rtb_entry_objalloc, rtb->frc_objalloc,
123
0
                                  rtb->mem);
124
0
  }
125
126
0
  ngtcp2_ksl_free(&rtb->ents);
127
0
}
128
129
static void rtb_on_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
130
0
                       ngtcp2_conn_stat *cstat) {
131
0
  assert(rtb->cc_pkt_num <= ent->hd.pkt_num);
132
133
0
  cstat->bytes_in_flight += ent->pktlen;
134
0
  rtb->cc_bytes_in_flight += ent->pktlen;
135
136
0
  ngtcp2_rst_on_pkt_sent(rtb->rst, ent, cstat);
137
0
  ngtcp2_rst_update_app_limited(rtb->rst, cstat);
138
139
0
  if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
140
0
    ++rtb->num_ack_eliciting;
141
0
  }
142
143
0
  if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE) {
144
0
    ++rtb->num_retransmittable;
145
0
  }
146
147
0
  if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING) {
148
0
    ++rtb->num_pto_eliciting;
149
0
  }
150
0
}
151
152
static size_t rtb_on_remove(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
153
0
                            ngtcp2_conn_stat *cstat) {
154
0
  if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED) {
155
0
    assert(rtb->num_lost_pkts);
156
0
    --rtb->num_lost_pkts;
157
158
0
    if (ent->flags &
159
0
        (NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) {
160
0
      assert(rtb->num_lost_ignore_pkts);
161
0
      --rtb->num_lost_ignore_pkts;
162
0
    }
163
164
0
    return 0;
165
0
  }
166
167
0
  if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
168
0
    assert(rtb->num_ack_eliciting);
169
0
    --rtb->num_ack_eliciting;
170
0
  }
171
172
0
  if ((ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE) &&
173
0
      !(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED)) {
174
0
    assert(rtb->num_retransmittable);
175
0
    --rtb->num_retransmittable;
176
0
  }
177
178
0
  if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING) {
179
0
    assert(rtb->num_pto_eliciting);
180
0
    --rtb->num_pto_eliciting;
181
0
  }
182
183
0
  if (rtb->cc_pkt_num <= ent->hd.pkt_num) {
184
0
    assert(cstat->bytes_in_flight >= ent->pktlen);
185
0
    cstat->bytes_in_flight -= ent->pktlen;
186
187
0
    assert(rtb->cc_bytes_in_flight >= ent->pktlen);
188
0
    rtb->cc_bytes_in_flight -= ent->pktlen;
189
190
    /* If PMTUD packet is lost, we do not report the lost bytes to the
191
       caller in order to ignore loss of PMTUD packet. */
192
0
    if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) {
193
0
      return 0;
194
0
    }
195
196
0
    return ent->pktlen;
197
0
  }
198
199
0
  return 0;
200
0
}
201
202
/* NGTCP2_RECLAIM_FLAG_NONE indicates that no flag is set. */
203
0
#define NGTCP2_RECLAIM_FLAG_NONE 0x00U
204
/* NGTCP2_RECLAIM_FLAG_ON_LOSS indicates that frames are reclaimed
205
   because of the packet loss.*/
206
0
#define NGTCP2_RECLAIM_FLAG_ON_LOSS 0x01U
207
208
/*
209
 * rtb_reclaim_frame copies and queues frames included in |ent| for
210
 * retransmission.  The frames are not deleted from |ent|.  It returns
211
 * the number of frames queued.  |flags| is bitwise OR of 0 or more of
212
 * NGTCP2_RECLAIM_FLAG_*.
213
 */
214
static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags,
215
                                      ngtcp2_conn *conn, ngtcp2_pktns *pktns,
216
0
                                      ngtcp2_rtb_entry *ent) {
217
0
  ngtcp2_frame_chain *frc, *nfrc, **pfrc = &pktns->tx.frq;
218
0
  ngtcp2_frame *fr;
219
0
  ngtcp2_strm *strm;
220
0
  ngtcp2_range gap, range;
221
0
  size_t num_reclaimed = 0;
222
0
  int rv;
223
224
0
  assert(ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE);
225
226
  /* TODO Reconsider the order of pfrc */
227
0
  for (frc = ent->frc; frc; frc = frc->next) {
228
0
    fr = &frc->fr;
229
230
    /* Check that a late ACK acknowledged this frame. */
231
0
    if (frc->binder &&
232
0
        (frc->binder->flags & NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK)) {
233
0
      continue;
234
0
    }
235
236
0
    switch (frc->fr.hd.type) {
237
0
    case NGTCP2_FRAME_STREAM:
238
0
      strm = ngtcp2_conn_find_stream(conn, fr->stream.stream_id);
239
0
      if (strm == NULL || (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM)) {
240
0
        continue;
241
0
      }
242
243
0
      gap = ngtcp2_strm_get_unacked_range_after(strm, fr->stream.offset);
244
245
0
      range.begin = fr->stream.offset;
246
0
      range.end =
247
0
        fr->stream.offset + ngtcp2_vec_len(fr->stream.data, fr->stream.datacnt);
248
0
      range = ngtcp2_range_intersect(&range, &gap);
249
250
0
      if (ngtcp2_range_len(&range) == 0 && !fr->stream.fin &&
251
          /* 0 length STREAM frame with offset == 0 must be
252
             retransmitted if no non-empty data are sent to this
253
             stream, fin flag is not set, and no data in this stream
254
             are acknowledged. */
255
0
          (fr->stream.offset != 0 || fr->stream.datacnt != 0 ||
256
0
           strm->tx.offset ||
257
0
           (strm->flags &
258
0
            (NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_ANY_ACKED)))) {
259
0
        continue;
260
0
      }
261
262
0
      if ((flags & NGTCP2_RECLAIM_FLAG_ON_LOSS) &&
263
0
          ent->hd.pkt_num != strm->tx.last_lost_pkt_num) {
264
0
        strm->tx.last_lost_pkt_num = ent->hd.pkt_num;
265
0
        ++strm->tx.loss_count;
266
0
      }
267
268
0
      rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
269
0
        &nfrc, fr->stream.datacnt, rtb->frc_objalloc, rtb->mem);
270
0
      if (rv != 0) {
271
0
        return rv;
272
0
      }
273
274
0
      nfrc->fr.stream.type = fr->stream.type;
275
0
      nfrc->fr.stream.flags = fr->stream.flags;
276
0
      nfrc->fr.stream.fin = fr->stream.fin;
277
0
      nfrc->fr.stream.stream_id = fr->stream.stream_id;
278
0
      nfrc->fr.stream.offset = fr->stream.offset;
279
0
      nfrc->fr.stream.datacnt = fr->stream.datacnt;
280
0
      ngtcp2_vec_copy(nfrc->fr.stream.data, fr->stream.data,
281
0
                      fr->stream.datacnt);
282
283
0
      rv = ngtcp2_strm_streamfrq_push(strm, nfrc);
284
0
      if (rv != 0) {
285
0
        ngtcp2_frame_chain_objalloc_del(nfrc, rtb->frc_objalloc, rtb->mem);
286
0
        return rv;
287
0
      }
288
289
0
      if (!ngtcp2_strm_is_tx_queued(strm)) {
290
0
        strm->cycle = ngtcp2_conn_tx_strmq_first_cycle(conn);
291
292
0
        rv = ngtcp2_conn_tx_strmq_push(conn, strm);
293
0
        if (rv != 0) {
294
0
          return rv;
295
0
        }
296
0
      }
297
298
0
      ++num_reclaimed;
299
300
0
      continue;
301
0
    case NGTCP2_FRAME_CRYPTO:
302
      /* Do not resend CRYPTO frame if the whole region it contains
303
         has been acknowledged */
304
0
      gap = ngtcp2_strm_get_unacked_range_after(&pktns->crypto.strm,
305
0
                                                fr->stream.offset);
306
307
0
      range.begin = fr->stream.offset;
308
0
      range.end =
309
0
        fr->stream.offset + ngtcp2_vec_len(fr->stream.data, fr->stream.datacnt);
310
0
      range = ngtcp2_range_intersect(&range, &gap);
311
312
0
      if (ngtcp2_range_len(&range) == 0) {
313
0
        continue;
314
0
      }
315
316
0
      rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
317
0
        &nfrc, fr->stream.datacnt, rtb->frc_objalloc, rtb->mem);
318
0
      if (rv != 0) {
319
0
        return rv;
320
0
      }
321
322
0
      nfrc->fr.stream.type = fr->stream.type;
323
0
      nfrc->fr.stream.flags = 0;
324
0
      nfrc->fr.stream.fin = 0;
325
0
      nfrc->fr.stream.stream_id = 0;
326
0
      nfrc->fr.stream.offset = fr->stream.offset;
327
0
      nfrc->fr.stream.datacnt = fr->stream.datacnt;
328
0
      ngtcp2_vec_copy(nfrc->fr.stream.data, fr->stream.data,
329
0
                      fr->stream.datacnt);
330
331
0
      rv = ngtcp2_strm_streamfrq_push(&pktns->crypto.strm, nfrc);
332
0
      if (rv != 0) {
333
0
        assert(ngtcp2_err_is_fatal(rv));
334
0
        ngtcp2_frame_chain_objalloc_del(nfrc, rtb->frc_objalloc, rtb->mem);
335
0
        return rv;
336
0
      }
337
338
0
      ++num_reclaimed;
339
340
0
      continue;
341
0
    case NGTCP2_FRAME_NEW_TOKEN:
342
0
      rv = ngtcp2_frame_chain_new_token_objalloc_new(
343
0
        &nfrc, fr->new_token.token, fr->new_token.tokenlen, rtb->frc_objalloc,
344
0
        rtb->mem);
345
0
      if (rv != 0) {
346
0
        return rv;
347
0
      }
348
349
0
      rv = ngtcp2_bind_frame_chains(frc, nfrc, rtb->mem);
350
0
      if (rv != 0) {
351
0
        return rv;
352
0
      }
353
354
0
      ++num_reclaimed;
355
356
0
      nfrc->next = *pfrc;
357
0
      *pfrc = nfrc;
358
0
      pfrc = &nfrc->next;
359
360
0
      continue;
361
0
    case NGTCP2_FRAME_DATAGRAM:
362
0
    case NGTCP2_FRAME_DATAGRAM_LEN:
363
0
      continue;
364
0
    case NGTCP2_FRAME_RESET_STREAM:
365
0
      strm = ngtcp2_conn_find_stream(conn, fr->reset_stream.stream_id);
366
0
      if (strm == NULL || !ngtcp2_strm_require_retransmit_reset_stream(strm)) {
367
0
        continue;
368
0
      }
369
370
0
      break;
371
0
    case NGTCP2_FRAME_STOP_SENDING:
372
0
      strm = ngtcp2_conn_find_stream(conn, fr->stop_sending.stream_id);
373
0
      if (strm == NULL || !ngtcp2_strm_require_retransmit_stop_sending(strm)) {
374
0
        continue;
375
0
      }
376
377
0
      break;
378
0
    case NGTCP2_FRAME_MAX_STREAM_DATA:
379
0
      strm = ngtcp2_conn_find_stream(conn, fr->max_stream_data.stream_id);
380
0
      if (strm == NULL || !ngtcp2_strm_require_retransmit_max_stream_data(
381
0
                            strm, &fr->max_stream_data)) {
382
0
        continue;
383
0
      }
384
385
0
      break;
386
0
    case NGTCP2_FRAME_STREAM_DATA_BLOCKED:
387
0
      strm = ngtcp2_conn_find_stream(conn, fr->stream_data_blocked.stream_id);
388
0
      if (strm == NULL || !ngtcp2_strm_require_retransmit_stream_data_blocked(
389
0
                            strm, &fr->stream_data_blocked)) {
390
0
        continue;
391
0
      }
392
393
0
      break;
394
0
    }
395
396
0
    rv = ngtcp2_frame_chain_objalloc_new(&nfrc, rtb->frc_objalloc);
397
0
    if (rv != 0) {
398
0
      return rv;
399
0
    }
400
401
0
    nfrc->fr = *fr;
402
403
0
    rv = ngtcp2_bind_frame_chains(frc, nfrc, rtb->mem);
404
0
    if (rv != 0) {
405
0
      return rv;
406
0
    }
407
408
0
    ++num_reclaimed;
409
410
0
    nfrc->next = *pfrc;
411
0
    *pfrc = nfrc;
412
0
    pfrc = &nfrc->next;
413
0
  }
414
415
0
  return (ngtcp2_ssize)num_reclaimed;
416
0
}
417
418
/*
419
 * conn_process_lost_datagram calls ngtcp2_lost_datagram callback for
420
 * lost DATAGRAM frames.
421
 */
422
static int conn_process_lost_datagram(ngtcp2_conn *conn,
423
0
                                      ngtcp2_rtb_entry *ent) {
424
0
  ngtcp2_frame_chain *frc;
425
0
  int rv;
426
427
0
  for (frc = ent->frc; frc; frc = frc->next) {
428
0
    switch (frc->fr.hd.type) {
429
0
    case NGTCP2_FRAME_DATAGRAM:
430
0
    case NGTCP2_FRAME_DATAGRAM_LEN:
431
0
      assert(conn->callbacks.lost_datagram);
432
433
0
      rv = conn->callbacks.lost_datagram(conn, frc->fr.datagram.dgram_id,
434
0
                                         conn->user_data);
435
0
      if (rv != 0) {
436
0
        return NGTCP2_ERR_CALLBACK_FAILURE;
437
0
      }
438
439
0
      break;
440
0
    }
441
0
  }
442
443
0
  return 0;
444
0
}
445
446
static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
447
                           ngtcp2_conn_stat *cstat, ngtcp2_conn *conn,
448
0
                           ngtcp2_pktns *pktns, ngtcp2_tstamp ts) {
449
0
  int rv;
450
0
  ngtcp2_ssize reclaimed;
451
0
  ngtcp2_cc *cc = rtb->cc;
452
0
  ngtcp2_cc_pkt pkt;
453
454
0
  if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_SKIP)) {
455
0
    ngtcp2_log_pkt_lost(rtb->log, ent->hd.pkt_num, ent->hd.type, ent->hd.flags,
456
0
                        ent->ts);
457
458
0
    if (rtb->qlog) {
459
0
      ngtcp2_qlog_pkt_lost(rtb->qlog, ent);
460
0
    }
461
0
  }
462
463
0
  if (ent->flags &
464
0
      (NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) {
465
0
    ++rtb->num_lost_ignore_pkts;
466
0
  } else {
467
0
    ++cstat->pkt_lost;
468
0
    cstat->bytes_lost += ent->pktlen;
469
470
0
    if (ent->hd.pkt_num >= rtb->cc_pkt_num) {
471
0
      rtb->rst->lost += ent->pktlen;
472
473
0
      if (rtb->cc->on_pkt_lost) {
474
0
        cc->on_pkt_lost(cc, cstat,
475
0
                        ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen,
476
0
                                           pktns->id, ent->ts, ent->rst.lost,
477
0
                                           ent->rst.tx_in_flight,
478
0
                                           ent->rst.is_app_limited),
479
0
                        ts);
480
0
      }
481
0
    }
482
0
  }
483
484
0
  if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) {
485
0
    ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
486
0
                     "pkn=%" PRId64 " has already been reclaimed on PTO",
487
0
                     ent->hd.pkt_num);
488
0
    assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED));
489
0
    assert(UINT64_MAX == ent->lost_ts);
490
0
  } else {
491
0
    if (conn->callbacks.lost_datagram &&
492
0
        (ent->flags & NGTCP2_RTB_ENTRY_FLAG_DATAGRAM)) {
493
0
      rv = conn_process_lost_datagram(conn, ent);
494
0
      if (rv != 0) {
495
0
        return rv;
496
0
      }
497
0
    }
498
499
0
    if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE) {
500
0
      assert(ent->frc);
501
0
      assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED));
502
0
      assert(UINT64_MAX == ent->lost_ts);
503
504
0
      reclaimed =
505
0
        rtb_reclaim_frame(rtb, NGTCP2_RECLAIM_FLAG_ON_LOSS, conn, pktns, ent);
506
0
      if (reclaimed < 0) {
507
0
        return (int)reclaimed;
508
0
      }
509
0
    }
510
0
  }
511
512
0
  ent->flags |= NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED;
513
0
  ent->lost_ts = ts;
514
515
0
  ++rtb->num_lost_pkts;
516
517
0
  return 0;
518
0
}
519
520
int ngtcp2_rtb_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
521
0
                   ngtcp2_conn_stat *cstat) {
522
0
  int rv;
523
524
0
  rv = ngtcp2_ksl_insert(&rtb->ents, NULL, &ent->hd.pkt_num, ent);
525
0
  if (rv != 0) {
526
0
    return rv;
527
0
  }
528
529
0
  rtb_on_add(rtb, ent, cstat);
530
531
0
  return 0;
532
0
}
533
534
0
ngtcp2_ksl_it ngtcp2_rtb_head(const ngtcp2_rtb *rtb) {
535
0
  return ngtcp2_ksl_begin(&rtb->ents);
536
0
}
537
538
static void rtb_remove(ngtcp2_rtb *rtb, ngtcp2_ksl_it *it,
539
                       ngtcp2_rtb_entry **pent, ngtcp2_rtb_entry *ent,
540
0
                       ngtcp2_conn_stat *cstat) {
541
0
  int rv;
542
0
  (void)rv;
543
544
0
  rtb_on_remove(rtb, ent, cstat);
545
546
0
  rv = ngtcp2_ksl_remove_hint(&rtb->ents, it, it, &ent->hd.pkt_num);
547
0
  assert(0 == rv);
548
549
0
  assert(ent->next == NULL);
550
551
0
  ngtcp2_list_insert(ent, pent);
552
0
}
553
554
static void conn_ack_crypto_data(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
555
0
                                 uint64_t datalen) {
556
0
  ngtcp2_buf_chain **pbufchain, *bufchain;
557
0
  size_t left;
558
559
0
  for (pbufchain = &pktns->crypto.tx.data; *pbufchain;) {
560
0
    left = ngtcp2_buf_len(&(*pbufchain)->buf);
561
0
    if (left > datalen) {
562
0
      (*pbufchain)->buf.pos += datalen;
563
0
      return;
564
0
    }
565
566
0
    bufchain = *pbufchain;
567
0
    *pbufchain = bufchain->next;
568
569
0
    ngtcp2_mem_free(conn->mem, bufchain);
570
571
0
    datalen -= left;
572
573
0
    if (datalen == 0) {
574
0
      return;
575
0
    }
576
0
  }
577
578
0
  assert(datalen == 0);
579
580
0
  return;
581
0
}
582
583
static int process_acked_pkt(ngtcp2_rtb_entry *ent, ngtcp2_conn *conn,
584
0
                             ngtcp2_pktns *pktns) {
585
0
  ngtcp2_frame_chain *frc;
586
0
  uint64_t prev_stream_offset, stream_offset;
587
0
  ngtcp2_strm *strm;
588
0
  int rv;
589
0
  uint64_t datalen;
590
0
  ngtcp2_strm *crypto = &pktns->crypto.strm;
591
592
0
  if ((ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) && conn->pmtud &&
593
0
      conn->pmtud->tx_pkt_num <= ent->hd.pkt_num) {
594
0
    ngtcp2_pmtud_probe_success(conn->pmtud, ent->pktlen);
595
596
0
    if (conn->dcid.current.max_udp_payload_size < ent->pktlen) {
597
0
      conn->dcid.current.max_udp_payload_size = ent->pktlen;
598
0
      conn->cstat.max_tx_udp_payload_size =
599
0
        ngtcp2_conn_get_path_max_tx_udp_payload_size(conn);
600
0
    }
601
602
0
    if (ngtcp2_pmtud_finished(conn->pmtud)) {
603
0
      ngtcp2_conn_stop_pmtud(conn);
604
0
    }
605
0
  }
606
607
0
  for (frc = ent->frc; frc; frc = frc->next) {
608
0
    if (frc->binder) {
609
0
      if (frc->binder->flags & NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK) {
610
0
        continue;
611
0
      }
612
613
0
      frc->binder->flags |= NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK;
614
0
    }
615
616
0
    switch (frc->fr.hd.type) {
617
0
    case NGTCP2_FRAME_STREAM:
618
0
      strm = ngtcp2_conn_find_stream(conn, frc->fr.stream.stream_id);
619
0
      if (strm == NULL) {
620
0
        break;
621
0
      }
622
623
0
      strm->flags |= NGTCP2_STRM_FLAG_ANY_ACKED;
624
625
0
      if (frc->fr.stream.fin) {
626
0
        strm->flags |= NGTCP2_STRM_FLAG_FIN_ACKED;
627
0
      }
628
629
0
      prev_stream_offset = ngtcp2_strm_get_acked_offset(strm);
630
631
0
      rv = ngtcp2_strm_ack_data(
632
0
        strm, frc->fr.stream.offset,
633
0
        ngtcp2_vec_len(frc->fr.stream.data, frc->fr.stream.datacnt));
634
0
      if (rv != 0) {
635
0
        return rv;
636
0
      }
637
638
0
      if (conn->callbacks.acked_stream_data_offset) {
639
0
        stream_offset = ngtcp2_strm_get_acked_offset(strm);
640
641
0
        datalen = stream_offset - prev_stream_offset;
642
0
        if (datalen == 0 && !frc->fr.stream.fin) {
643
0
          break;
644
0
        }
645
646
0
        rv = conn->callbacks.acked_stream_data_offset(
647
0
          conn, strm->stream_id, prev_stream_offset, datalen, conn->user_data,
648
0
          strm->stream_user_data);
649
0
        if (rv != 0) {
650
0
          return NGTCP2_ERR_CALLBACK_FAILURE;
651
0
        }
652
0
      }
653
654
0
      rv = ngtcp2_conn_close_stream_if_shut_rdwr(conn, strm);
655
0
      if (rv != 0) {
656
0
        return rv;
657
0
      }
658
659
0
      break;
660
0
    case NGTCP2_FRAME_CRYPTO:
661
0
      prev_stream_offset = ngtcp2_strm_get_acked_offset(crypto);
662
663
0
      rv = ngtcp2_strm_ack_data(
664
0
        crypto, frc->fr.stream.offset,
665
0
        ngtcp2_vec_len(frc->fr.stream.data, frc->fr.stream.datacnt));
666
0
      if (rv != 0) {
667
0
        return rv;
668
0
      }
669
670
0
      stream_offset = ngtcp2_strm_get_acked_offset(crypto);
671
672
0
      datalen = stream_offset - prev_stream_offset;
673
0
      if (datalen == 0) {
674
0
        break;
675
0
      }
676
677
0
      conn_ack_crypto_data(conn, pktns, datalen);
678
679
0
      break;
680
0
    case NGTCP2_FRAME_RESET_STREAM:
681
0
      strm = ngtcp2_conn_find_stream(conn, frc->fr.reset_stream.stream_id);
682
0
      if (strm == NULL) {
683
0
        break;
684
0
      }
685
686
0
      strm->flags |= NGTCP2_STRM_FLAG_RESET_STREAM_ACKED;
687
688
0
      rv = ngtcp2_conn_close_stream_if_shut_rdwr(conn, strm);
689
0
      if (rv != 0) {
690
0
        return rv;
691
0
      }
692
693
0
      break;
694
0
    case NGTCP2_FRAME_RETIRE_CONNECTION_ID:
695
0
      ngtcp2_dcidtr_untrack_retired_seq(&conn->dcid.dtr,
696
0
                                        frc->fr.retire_connection_id.seq);
697
0
      break;
698
0
    case NGTCP2_FRAME_NEW_CONNECTION_ID:
699
0
      assert(conn->scid.num_in_flight);
700
701
0
      --conn->scid.num_in_flight;
702
703
0
      break;
704
0
    case NGTCP2_FRAME_DATAGRAM:
705
0
    case NGTCP2_FRAME_DATAGRAM_LEN:
706
0
      if (!conn->callbacks.ack_datagram) {
707
0
        break;
708
0
      }
709
710
0
      rv = conn->callbacks.ack_datagram(conn, frc->fr.datagram.dgram_id,
711
0
                                        conn->user_data);
712
0
      if (rv != 0) {
713
0
        return NGTCP2_ERR_CALLBACK_FAILURE;
714
0
      }
715
716
0
      break;
717
0
    }
718
0
  }
719
720
0
  return 0;
721
0
}
722
723
static void rtb_on_pkt_acked(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
724
                             ngtcp2_conn_stat *cstat, const ngtcp2_pktns *pktns,
725
0
                             ngtcp2_tstamp ts) {
726
0
  ngtcp2_cc *cc = rtb->cc;
727
0
  ngtcp2_cc_pkt pkt;
728
729
0
  assert(ent->hd.pkt_num >= rtb->cc_pkt_num);
730
731
0
  ngtcp2_rst_update_rate_sample(rtb->rst, ent, ts);
732
733
0
  if (cc->on_pkt_acked) {
734
0
    cc->on_pkt_acked(cc, cstat,
735
0
                     ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen,
736
0
                                        pktns->id, ent->ts, ent->rst.lost,
737
0
                                        ent->rst.tx_in_flight,
738
0
                                        ent->rst.is_app_limited),
739
0
                     ts);
740
0
  }
741
742
0
  if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PROBE) &&
743
0
      (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
744
0
    cstat->pto_count = 0;
745
0
  }
746
0
}
747
748
static void conn_verify_ecn(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
749
                            ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
750
                            const ngtcp2_ack *fr, size_t ecn_acked,
751
0
                            const ngtcp2_cc_ack *cc_ack, ngtcp2_tstamp ts) {
752
0
  if (conn->tx.ecn.state == NGTCP2_ECN_STATE_FAILED) {
753
0
    return;
754
0
  }
755
756
0
  if ((ecn_acked && fr->type == NGTCP2_FRAME_ACK) ||
757
0
      (fr->type == NGTCP2_FRAME_ACK_ECN &&
758
0
       (pktns->acktr.ecn.ack.ect0 > fr->ecn.ect0 ||
759
0
        pktns->acktr.ecn.ack.ect1 > fr->ecn.ect1 ||
760
0
        pktns->acktr.ecn.ack.ce > fr->ecn.ce ||
761
0
        (fr->ecn.ect0 - pktns->acktr.ecn.ack.ect0) +
762
0
            (fr->ecn.ce - pktns->acktr.ecn.ack.ce) <
763
0
          ecn_acked ||
764
0
        fr->ecn.ect0 > pktns->tx.ecn.ect0 || fr->ecn.ect1))) {
765
0
    ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
766
0
                    "path is not ECN capable");
767
0
    conn->tx.ecn.state = NGTCP2_ECN_STATE_FAILED;
768
769
0
    return;
770
0
  }
771
772
0
  if (conn->tx.ecn.state != NGTCP2_ECN_STATE_CAPABLE && ecn_acked) {
773
0
    ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "path is ECN capable");
774
0
    conn->tx.ecn.state = NGTCP2_ECN_STATE_CAPABLE;
775
0
  }
776
777
0
  if (fr->type == NGTCP2_FRAME_ACK_ECN) {
778
0
    if (cc->congestion_event && cc_ack->largest_pkt_sent_ts != UINT64_MAX &&
779
0
        fr->ecn.ce > pktns->acktr.ecn.ack.ce) {
780
0
      cc->congestion_event(cc, cstat, cc_ack->largest_pkt_sent_ts, cc_ack, ts);
781
0
    }
782
783
0
    pktns->acktr.ecn.ack.ect0 = fr->ecn.ect0;
784
0
    pktns->acktr.ecn.ack.ect1 = fr->ecn.ect1;
785
0
    pktns->acktr.ecn.ack.ce = fr->ecn.ce;
786
0
  }
787
0
}
788
789
static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_cc_ack *cc_ack,
790
                               ngtcp2_conn *conn, ngtcp2_pktns *pktns,
791
                               ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts);
792
793
ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
794
                                 ngtcp2_conn_stat *cstat, ngtcp2_conn *conn,
795
                                 ngtcp2_pktns *pktns, ngtcp2_tstamp pkt_ts,
796
0
                                 ngtcp2_tstamp ts) {
797
0
  ngtcp2_rtb_entry *ent;
798
0
  int64_t largest_ack = fr->largest_ack, min_ack;
799
0
  size_t i;
800
0
  int rv;
801
0
  ngtcp2_ksl_it it;
802
0
  size_t num_acked = 0;
803
0
  int64_t pkt_num;
804
0
  ngtcp2_cc *cc = rtb->cc;
805
0
  ngtcp2_rtb_entry *acked_ent = NULL;
806
0
  int ack_eliciting_pkt_acked = 0;
807
0
  size_t ecn_acked = 0;
808
0
  int verify_ecn = 0;
809
0
  ngtcp2_cc_ack cc_ack = {
810
0
    .largest_pkt_sent_ts = UINT64_MAX,
811
0
    .rtt = UINT64_MAX,
812
0
  };
813
0
  size_t num_lost_pkts = rtb->num_lost_pkts - rtb->num_lost_ignore_pkts;
814
815
0
  if (conn && (conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED) &&
816
0
      (conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR) &&
817
0
      largest_ack >= conn->pktns.crypto.tx.ckm->pkt_num) {
818
0
    conn->flags &= (uint32_t)~(NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED |
819
0
                               NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR);
820
0
    conn->crypto.key_update.confirmed_ts = ts;
821
822
0
    ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_CRY, "key update confirmed");
823
0
  }
824
825
0
  if (rtb->largest_acked_tx_pkt_num < largest_ack) {
826
0
    rtb->largest_acked_tx_pkt_num = largest_ack;
827
0
    verify_ecn = 1;
828
0
  }
829
830
0
  ngtcp2_rst_reset_rate_sample(rtb->rst, cstat);
831
832
  /* Assume that ngtcp2_pkt_validate_ack(fr) returns 0 */
833
0
  it = ngtcp2_ksl_lower_bound(&rtb->ents, &largest_ack);
834
0
  if (ngtcp2_ksl_it_end(&it)) {
835
0
    if (conn && verify_ecn) {
836
0
      conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked, &cc_ack, ts);
837
0
    }
838
839
0
    if (cc->on_ack_recv) {
840
0
      cc->on_ack_recv(cc, cstat, &cc_ack, ts);
841
0
    }
842
843
0
    return 0;
844
0
  }
845
846
0
  min_ack = largest_ack - (int64_t)fr->first_ack_range;
847
848
0
  for (; !ngtcp2_ksl_it_end(&it);) {
849
0
    pkt_num = *(int64_t *)ngtcp2_ksl_it_key(&it);
850
851
0
    assert(pkt_num <= largest_ack);
852
853
0
    if (pkt_num < min_ack) {
854
0
      break;
855
0
    }
856
857
0
    ent = ngtcp2_ksl_it_get(&it);
858
859
0
    if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_SKIP) {
860
0
      rv = NGTCP2_ERR_PROTO;
861
0
      goto fail;
862
0
    }
863
864
0
    if (rtb->largest_acked_tx_pkt_num == pkt_num) {
865
0
      cc_ack.largest_pkt_sent_ts = ent->ts;
866
0
    }
867
868
0
    if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
869
0
      ack_eliciting_pkt_acked = 1;
870
0
    }
871
872
0
    rtb_remove(rtb, &it, &acked_ent, ent, cstat);
873
0
  }
874
875
0
  for (i = 0; i < fr->rangecnt; ++i) {
876
0
    largest_ack = min_ack - (int64_t)fr->ranges[i].gap - 2;
877
0
    min_ack = largest_ack - (int64_t)fr->ranges[i].len;
878
879
0
    it = ngtcp2_ksl_lower_bound(&rtb->ents, &largest_ack);
880
0
    if (ngtcp2_ksl_it_end(&it)) {
881
0
      break;
882
0
    }
883
884
0
    for (; !ngtcp2_ksl_it_end(&it);) {
885
0
      pkt_num = *(int64_t *)ngtcp2_ksl_it_key(&it);
886
0
      if (pkt_num < min_ack) {
887
0
        break;
888
0
      }
889
890
0
      ent = ngtcp2_ksl_it_get(&it);
891
892
0
      if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_SKIP) {
893
0
        rv = NGTCP2_ERR_PROTO;
894
0
        goto fail;
895
0
      }
896
897
0
      if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
898
0
        ack_eliciting_pkt_acked = 1;
899
0
      }
900
901
0
      rtb_remove(rtb, &it, &acked_ent, ent, cstat);
902
0
    }
903
0
  }
904
905
0
  if (cc_ack.largest_pkt_sent_ts != UINT64_MAX && ack_eliciting_pkt_acked) {
906
0
    cc_ack.rtt = ngtcp2_max_uint64(pkt_ts - cc_ack.largest_pkt_sent_ts,
907
0
                                   NGTCP2_NANOSECONDS);
908
909
0
    ngtcp2_conn_update_rtt(conn, cc_ack.rtt, fr->ack_delay_unscaled, ts);
910
0
  }
911
912
0
  if (conn) {
913
0
    for (ent = acked_ent; ent; ent = acked_ent) {
914
0
      if (ent->hd.pkt_num >= pktns->tx.ecn.start_pkt_num &&
915
0
          (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ECN)) {
916
0
        ++ecn_acked;
917
0
      }
918
919
0
      rv = process_acked_pkt(ent, conn, pktns);
920
0
      if (rv != 0) {
921
0
        goto fail;
922
0
      }
923
924
0
      if (ent->hd.pkt_num >= rtb->cc_pkt_num) {
925
0
        assert(cc_ack.pkt_delivered <= ent->rst.delivered);
926
927
0
        cc_ack.bytes_delivered += ent->pktlen;
928
0
        cc_ack.pkt_delivered = ent->rst.delivered;
929
930
0
        rtb_on_pkt_acked(rtb, ent, cstat, pktns, ts);
931
932
0
        ++num_acked;
933
0
      }
934
935
0
      acked_ent = ent->next;
936
0
      ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
937
0
                                    rtb->frc_objalloc, rtb->mem);
938
0
    }
939
0
  } else {
940
    /* For unit tests */
941
0
    for (ent = acked_ent; ent; ent = acked_ent) {
942
0
      rtb_on_pkt_acked(rtb, ent, cstat, pktns, ts);
943
0
      acked_ent = ent->next;
944
0
      ++num_acked;
945
0
      ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
946
0
                                    rtb->frc_objalloc, rtb->mem);
947
0
    }
948
0
  }
949
950
0
  if (rtb->cc->on_spurious_congestion && num_lost_pkts &&
951
0
      rtb->num_lost_pkts == rtb->num_lost_ignore_pkts) {
952
0
    rtb->cc->on_spurious_congestion(cc, cstat, ts);
953
0
  }
954
955
0
  if (num_acked) {
956
0
    ngtcp2_rst_on_ack_recv(rtb->rst, cstat);
957
958
0
    if (conn) {
959
0
      rv = rtb_detect_lost_pkt(rtb, &cc_ack, conn, pktns, cstat, ts);
960
0
      if (rv != 0) {
961
0
        return rv;
962
0
      }
963
0
    }
964
0
  }
965
966
0
  if (conn && verify_ecn) {
967
0
    conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked, &cc_ack, ts);
968
0
  }
969
970
0
  if (cc->on_ack_recv) {
971
0
    cc->on_ack_recv(cc, cstat, &cc_ack, ts);
972
0
  }
973
974
0
  return (ngtcp2_ssize)num_acked;
975
976
0
fail:
977
0
  for (ent = acked_ent; ent; ent = acked_ent) {
978
0
    acked_ent = ent->next;
979
0
    ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
980
0
                                  rtb->frc_objalloc, rtb->mem);
981
0
  }
982
983
0
  return rv;
984
0
}
985
986
static int rtb_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_conn_stat *cstat,
987
                        const ngtcp2_rtb_entry *ent, ngtcp2_duration loss_delay,
988
                        size_t pkt_thres, const ngtcp2_pktns *pktns,
989
0
                        ngtcp2_tstamp ts) {
990
0
  ngtcp2_tstamp loss_time;
991
992
0
  if (ngtcp2_tstamp_elapsed(ent->ts, loss_delay, ts) ||
993
0
      rtb->largest_acked_tx_pkt_num >= ent->hd.pkt_num + (int64_t)pkt_thres) {
994
0
    return 1;
995
0
  }
996
997
0
  loss_time = cstat->loss_time[pktns->id];
998
999
0
  if (loss_time == UINT64_MAX) {
1000
0
    loss_time = ent->ts + loss_delay;
1001
0
  } else {
1002
0
    loss_time = ngtcp2_min_uint64(loss_time, ent->ts + loss_delay);
1003
0
  }
1004
1005
0
  cstat->loss_time[pktns->id] = loss_time;
1006
1007
0
  return 0;
1008
0
}
1009
1010
/*
1011
 * compute_pkt_loss_delay computes loss delay.
1012
 */
1013
0
static ngtcp2_duration compute_pkt_loss_delay(const ngtcp2_conn_stat *cstat) {
1014
  /* 9/8 is kTimeThreshold */
1015
0
  ngtcp2_duration loss_delay =
1016
0
    ngtcp2_max_uint64(cstat->latest_rtt, cstat->smoothed_rtt) * 9 / 8;
1017
0
  return ngtcp2_max_uint64(loss_delay, NGTCP2_GRANULARITY);
1018
0
}
1019
1020
/*
1021
 * conn_all_ecn_pkt_lost returns nonzero if all ECN QUIC packets are
1022
 * lost during validation period.
1023
 */
1024
0
static int conn_all_ecn_pkt_lost(ngtcp2_conn *conn) {
1025
0
  ngtcp2_pktns *in_pktns = conn->in_pktns;
1026
0
  ngtcp2_pktns *hs_pktns = conn->hs_pktns;
1027
0
  ngtcp2_pktns *pktns = &conn->pktns;
1028
1029
0
  return (!in_pktns || in_pktns->tx.ecn.validation_pkt_sent ==
1030
0
                         in_pktns->tx.ecn.validation_pkt_lost) &&
1031
0
         (!hs_pktns || hs_pktns->tx.ecn.validation_pkt_sent ==
1032
0
                         hs_pktns->tx.ecn.validation_pkt_lost) &&
1033
0
         pktns->tx.ecn.validation_pkt_sent == pktns->tx.ecn.validation_pkt_lost;
1034
0
}
1035
1036
/*
1037
 * This function assigns the number of bytes lost to
1038
 * |cc_ack|->bytes_lost if any.
1039
 */
1040
static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_cc_ack *cc_ack,
1041
                               ngtcp2_conn *conn, ngtcp2_pktns *pktns,
1042
0
                               ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) {
1043
0
  ngtcp2_rtb_entry *ent;
1044
0
  ngtcp2_duration loss_delay;
1045
0
  ngtcp2_ksl_it it;
1046
0
  ngtcp2_tstamp latest_ts, oldest_ts;
1047
0
  int64_t last_lost_pkt_num;
1048
0
  ngtcp2_duration loss_window, congestion_period;
1049
0
  ngtcp2_cc *cc = rtb->cc;
1050
0
  int rv;
1051
0
  uint64_t pkt_thres =
1052
0
    rtb->cc_bytes_in_flight / cstat->max_tx_udp_payload_size / 2;
1053
0
  size_t ecn_pkt_lost = 0;
1054
0
  ngtcp2_tstamp start_ts;
1055
0
  ngtcp2_duration pto = ngtcp2_conn_compute_pto(conn, pktns);
1056
0
  uint64_t bytes_lost = 0;
1057
0
  ngtcp2_duration max_ack_delay;
1058
1059
0
  pkt_thres = ngtcp2_max_uint64(pkt_thres, NGTCP2_PKT_THRESHOLD);
1060
0
  pkt_thres = ngtcp2_min_uint64(pkt_thres, 256);
1061
0
  cstat->loss_time[pktns->id] = UINT64_MAX;
1062
0
  loss_delay = compute_pkt_loss_delay(cstat);
1063
1064
0
  it = ngtcp2_ksl_lower_bound(&rtb->ents, &rtb->largest_acked_tx_pkt_num);
1065
0
  for (; !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) {
1066
0
    ent = ngtcp2_ksl_it_get(&it);
1067
1068
0
    if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED) {
1069
0
      break;
1070
0
    }
1071
1072
0
    if (rtb_pkt_lost(rtb, cstat, ent, loss_delay, (size_t)pkt_thres, pktns,
1073
0
                     ts)) {
1074
      /* All entries from ent are considered to be lost. */
1075
0
      latest_ts = oldest_ts = ent->ts;
1076
      /* +1 to pick this packet for persistent congestion in the
1077
         following loop. */
1078
0
      last_lost_pkt_num = ent->hd.pkt_num + 1;
1079
0
      max_ack_delay = conn->remote.transport_params
1080
0
                        ? conn->remote.transport_params->max_ack_delay
1081
0
                        : 0;
1082
1083
0
      congestion_period =
1084
0
        (cstat->smoothed_rtt +
1085
0
         ngtcp2_max_uint64(4 * cstat->rttvar, NGTCP2_GRANULARITY) +
1086
0
         max_ack_delay) *
1087
0
        NGTCP2_PERSISTENT_CONGESTION_THRESHOLD;
1088
1089
0
      start_ts = ngtcp2_max_uint64(conn->handshake_confirmed_ts,
1090
0
                                   cstat->first_rtt_sample_ts);
1091
1092
0
      for (; !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) {
1093
0
        ent = ngtcp2_ksl_it_get(&it);
1094
1095
0
        if (last_lost_pkt_num == ent->hd.pkt_num + 1 && ent->ts >= start_ts) {
1096
0
          last_lost_pkt_num = ent->hd.pkt_num;
1097
0
          oldest_ts = ent->ts;
1098
0
        } else {
1099
0
          last_lost_pkt_num = -1;
1100
0
        }
1101
1102
0
        if ((ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED)) {
1103
0
          if (pktns->id != NGTCP2_PKTNS_ID_APPLICATION ||
1104
0
              last_lost_pkt_num == -1 ||
1105
0
              latest_ts - oldest_ts >= congestion_period) {
1106
0
            break;
1107
0
          }
1108
1109
0
          continue;
1110
0
        }
1111
1112
0
        if (ent->hd.pkt_num >= pktns->tx.ecn.start_pkt_num &&
1113
0
            (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ECN)) {
1114
0
          ++ecn_pkt_lost;
1115
0
        }
1116
1117
0
        bytes_lost += rtb_on_remove(rtb, ent, cstat);
1118
0
        rv = rtb_on_pkt_lost(rtb, ent, cstat, conn, pktns, ts);
1119
0
        if (rv != 0) {
1120
0
          return rv;
1121
0
        }
1122
0
      }
1123
1124
      /* If only PMTUD packets are lost, do not trigger congestion
1125
         event. */
1126
0
      if (bytes_lost == 0) {
1127
0
        break;
1128
0
      }
1129
1130
0
      switch (conn->tx.ecn.state) {
1131
0
      case NGTCP2_ECN_STATE_TESTING:
1132
0
        if (conn->tx.ecn.validation_start_ts == UINT64_MAX) {
1133
0
          break;
1134
0
        }
1135
1136
0
        if (ts - conn->tx.ecn.validation_start_ts < 3 * pto) {
1137
0
          pktns->tx.ecn.validation_pkt_lost += ecn_pkt_lost;
1138
0
          assert(pktns->tx.ecn.validation_pkt_sent >=
1139
0
                 pktns->tx.ecn.validation_pkt_lost);
1140
0
          break;
1141
0
        }
1142
1143
0
        conn->tx.ecn.state = NGTCP2_ECN_STATE_UNKNOWN;
1144
1145
        /* fall through */
1146
0
      case NGTCP2_ECN_STATE_UNKNOWN:
1147
0
        pktns->tx.ecn.validation_pkt_lost += ecn_pkt_lost;
1148
0
        assert(pktns->tx.ecn.validation_pkt_sent >=
1149
0
               pktns->tx.ecn.validation_pkt_lost);
1150
0
        if (conn_all_ecn_pkt_lost(conn)) {
1151
0
          conn->tx.ecn.state = NGTCP2_ECN_STATE_FAILED;
1152
0
        }
1153
0
        break;
1154
0
      default:
1155
0
        break;
1156
0
      }
1157
1158
0
      cc_ack->bytes_lost = bytes_lost;
1159
1160
0
      if (cc->congestion_event) {
1161
0
        cc->congestion_event(cc, cstat, latest_ts, cc_ack, ts);
1162
0
      }
1163
1164
0
      loss_window = latest_ts - oldest_ts;
1165
      /* Persistent congestion situation is only evaluated for app
1166
       * packet number space and for the packets sent after handshake
1167
       * is confirmed.  During handshake, there is not much packets
1168
       * sent and also people seem to do lots of effort not to trigger
1169
       * persistent congestion there, then it is a lot easier to just
1170
       * not enable it during handshake.
1171
       */
1172
0
      if (pktns->id == NGTCP2_PKTNS_ID_APPLICATION && loss_window &&
1173
0
          loss_window >= congestion_period) {
1174
0
        ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
1175
0
                         "persistent congestion loss_window=%" PRIu64
1176
0
                         " congestion_period=%" PRIu64,
1177
0
                         loss_window, congestion_period);
1178
1179
        /* Reset min_rtt, srtt, and rttvar here.  Next new RTT
1180
           sample will be used to recalculate these values. */
1181
0
        cstat->min_rtt = UINT64_MAX;
1182
0
        cstat->smoothed_rtt = conn->local.settings.initial_rtt;
1183
0
        cstat->rttvar = conn->local.settings.initial_rtt / 2;
1184
0
        cstat->first_rtt_sample_ts = UINT64_MAX;
1185
1186
0
        if (cc->on_persistent_congestion) {
1187
0
          cc->on_persistent_congestion(cc, cstat, ts);
1188
0
        }
1189
0
      }
1190
1191
0
      break;
1192
0
    }
1193
0
  }
1194
1195
0
  ngtcp2_rtb_remove_excessive_lost_pkt(rtb, (size_t)pkt_thres);
1196
1197
0
  return 0;
1198
0
}
1199
1200
int ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
1201
                               ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat,
1202
0
                               ngtcp2_tstamp ts) {
1203
0
  return rtb_detect_lost_pkt(rtb,
1204
0
                             &(ngtcp2_cc_ack){
1205
0
                               .largest_pkt_sent_ts = UINT64_MAX,
1206
0
                               .rtt = UINT64_MAX,
1207
0
                             },
1208
0
                             conn, pktns, cstat, ts);
1209
0
}
1210
1211
0
void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n) {
1212
0
  ngtcp2_ksl_it it = ngtcp2_ksl_end(&rtb->ents);
1213
0
  ngtcp2_rtb_entry *ent;
1214
0
  int rv;
1215
0
  (void)rv;
1216
1217
0
  for (; rtb->num_lost_pkts > n;) {
1218
0
    assert(ngtcp2_ksl_it_end(&it));
1219
0
    ngtcp2_ksl_it_prev(&it);
1220
0
    ent = ngtcp2_ksl_it_get(&it);
1221
1222
0
    assert(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED);
1223
1224
0
    ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
1225
0
                     "removing stale lost pkn=%" PRId64, ent->hd.pkt_num);
1226
1227
0
    --rtb->num_lost_pkts;
1228
1229
0
    if (ent->flags &
1230
0
        (NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) {
1231
0
      --rtb->num_lost_ignore_pkts;
1232
0
    }
1233
1234
0
    rv = ngtcp2_ksl_remove_hint(&rtb->ents, &it, &it, &ent->hd.pkt_num);
1235
0
    assert(0 == rv);
1236
0
    ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
1237
0
                                  rtb->frc_objalloc, rtb->mem);
1238
0
  }
1239
0
}
1240
1241
void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb,
1242
                                        ngtcp2_duration timeout,
1243
0
                                        ngtcp2_tstamp ts) {
1244
0
  ngtcp2_ksl_it it;
1245
0
  ngtcp2_rtb_entry *ent;
1246
0
  int rv;
1247
0
  (void)rv;
1248
1249
0
  if (rtb->num_lost_pkts == 0) {
1250
0
    return;
1251
0
  }
1252
1253
0
  it = ngtcp2_ksl_end(&rtb->ents);
1254
1255
0
  for (; rtb->num_lost_pkts;) {
1256
0
    assert(ngtcp2_ksl_it_end(&it));
1257
1258
0
    ngtcp2_ksl_it_prev(&it);
1259
0
    ent = ngtcp2_ksl_it_get(&it);
1260
1261
0
    assert(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED);
1262
1263
0
    if (ts - ent->lost_ts < timeout) {
1264
0
      return;
1265
0
    }
1266
1267
0
    ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
1268
0
                     "removing stale lost pkn=%" PRId64, ent->hd.pkt_num);
1269
1270
0
    --rtb->num_lost_pkts;
1271
1272
0
    if (ent->flags &
1273
0
        (NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) {
1274
0
      --rtb->num_lost_ignore_pkts;
1275
0
    }
1276
1277
0
    rv = ngtcp2_ksl_remove_hint(&rtb->ents, &it, &it, &ent->hd.pkt_num);
1278
0
    assert(0 == rv);
1279
0
    ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
1280
0
                                  rtb->frc_objalloc, rtb->mem);
1281
0
  }
1282
0
}
1283
1284
0
ngtcp2_tstamp ngtcp2_rtb_lost_pkt_ts(const ngtcp2_rtb *rtb) {
1285
0
  ngtcp2_ksl_it it;
1286
0
  ngtcp2_rtb_entry *ent;
1287
1288
0
  if (ngtcp2_ksl_len(&rtb->ents) == 0) {
1289
0
    return UINT64_MAX;
1290
0
  }
1291
1292
0
  it = ngtcp2_ksl_end(&rtb->ents);
1293
0
  ngtcp2_ksl_it_prev(&it);
1294
0
  ent = ngtcp2_ksl_it_get(&it);
1295
1296
0
  if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED)) {
1297
0
    return UINT64_MAX;
1298
0
  }
1299
1300
0
  return ent->lost_ts;
1301
0
}
1302
1303
static int rtb_reclaim_frame_on_retry(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
1304
                                      ngtcp2_pktns *pktns,
1305
0
                                      ngtcp2_rtb_entry *ent) {
1306
0
  ngtcp2_frame_chain **pfrc = &ent->frc, *frc;
1307
0
  ngtcp2_stream *sfr;
1308
0
  ngtcp2_strm *strm;
1309
0
  int rv;
1310
1311
0
  for (; *pfrc;) {
1312
0
    switch ((*pfrc)->fr.hd.type) {
1313
0
    case NGTCP2_FRAME_STREAM:
1314
0
      frc = *pfrc;
1315
1316
0
      *pfrc = frc->next;
1317
0
      frc->next = NULL;
1318
0
      sfr = &frc->fr.stream;
1319
1320
0
      strm = ngtcp2_conn_find_stream(conn, sfr->stream_id);
1321
0
      if (!strm) {
1322
0
        ngtcp2_frame_chain_objalloc_del(frc, rtb->frc_objalloc, rtb->mem);
1323
0
        break;
1324
0
      }
1325
1326
0
      rv = ngtcp2_strm_streamfrq_push(strm, frc);
1327
0
      if (rv != 0) {
1328
0
        ngtcp2_frame_chain_objalloc_del(frc, rtb->frc_objalloc, rtb->mem);
1329
0
        return rv;
1330
0
      }
1331
1332
0
      if (!ngtcp2_strm_is_tx_queued(strm)) {
1333
0
        strm->cycle = ngtcp2_conn_tx_strmq_first_cycle(conn);
1334
0
        rv = ngtcp2_conn_tx_strmq_push(conn, strm);
1335
0
        if (rv != 0) {
1336
0
          return rv;
1337
0
        }
1338
0
      }
1339
1340
0
      break;
1341
0
    case NGTCP2_FRAME_CRYPTO:
1342
0
      frc = *pfrc;
1343
1344
0
      *pfrc = frc->next;
1345
0
      frc->next = NULL;
1346
1347
0
      rv = ngtcp2_strm_streamfrq_push(&pktns->crypto.strm, frc);
1348
0
      if (rv != 0) {
1349
0
        assert(ngtcp2_err_is_fatal(rv));
1350
0
        ngtcp2_frame_chain_objalloc_del(frc, rtb->frc_objalloc, rtb->mem);
1351
0
        return rv;
1352
0
      }
1353
1354
0
      break;
1355
0
    case NGTCP2_FRAME_DATAGRAM:
1356
0
    case NGTCP2_FRAME_DATAGRAM_LEN:
1357
0
      frc = *pfrc;
1358
1359
0
      if (conn->callbacks.lost_datagram) {
1360
0
        rv = conn->callbacks.lost_datagram(conn, frc->fr.datagram.dgram_id,
1361
0
                                           conn->user_data);
1362
0
        if (rv != 0) {
1363
0
          return NGTCP2_ERR_CALLBACK_FAILURE;
1364
0
        }
1365
0
      }
1366
1367
0
      *pfrc = (*pfrc)->next;
1368
1369
0
      ngtcp2_frame_chain_objalloc_del(frc, rtb->frc_objalloc, rtb->mem);
1370
1371
0
      break;
1372
0
    default:
1373
0
      pfrc = &(*pfrc)->next;
1374
0
    }
1375
0
  }
1376
1377
0
  *pfrc = pktns->tx.frq;
1378
0
  pktns->tx.frq = ent->frc;
1379
0
  ent->frc = NULL;
1380
1381
0
  return 0;
1382
0
}
1383
1384
int ngtcp2_rtb_reclaim_on_retry(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
1385
0
                                ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat) {
1386
0
  ngtcp2_rtb_entry *ent;
1387
0
  ngtcp2_ksl_it it = ngtcp2_ksl_begin(&rtb->ents);
1388
0
  int rv;
1389
1390
0
  for (; !ngtcp2_ksl_it_end(&it);) {
1391
0
    ent = ngtcp2_ksl_it_get(&it);
1392
1393
0
    rtb_on_remove(rtb, ent, cstat);
1394
0
    rv = ngtcp2_ksl_remove_hint(&rtb->ents, &it, &it, &ent->hd.pkt_num);
1395
0
    assert(0 == rv);
1396
1397
0
    if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_SKIP)) {
1398
0
      ngtcp2_log_pkt_lost(rtb->log, ent->hd.pkt_num, ent->hd.type,
1399
0
                          ent->hd.flags, ent->ts);
1400
1401
0
      if (rtb->qlog) {
1402
0
        ngtcp2_qlog_pkt_lost(rtb->qlog, ent);
1403
0
      }
1404
0
    }
1405
1406
    /* We never send PING only probe packet because we should have
1407
       CRYPTO data or just nothing.  If we have nothing, then we do
1408
       not send probe packet. */
1409
0
    assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PROBE));
1410
1411
    /* We never get ACK before Retry packet. */
1412
0
    assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED));
1413
0
    assert(0 == rtb->num_lost_pkts);
1414
0
    assert(0 == rtb->num_lost_ignore_pkts);
1415
1416
    /* PMTUD probe must not be sent before handshake completion. */
1417
0
    assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE));
1418
1419
0
    if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) {
1420
0
      ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
1421
0
                       "pkn=%" PRId64 " has already been reclaimed on PTO",
1422
0
                       ent->hd.pkt_num);
1423
1424
0
      ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
1425
0
                                    rtb->frc_objalloc, rtb->mem);
1426
1427
0
      continue;
1428
0
    }
1429
1430
0
    if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE) &&
1431
0
        (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_DATAGRAM) ||
1432
0
         !conn->callbacks.lost_datagram)) {
1433
0
      ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
1434
0
                                    rtb->frc_objalloc, rtb->mem);
1435
1436
0
      continue;
1437
0
    }
1438
1439
0
    rv = rtb_reclaim_frame_on_retry(rtb, conn, pktns, ent);
1440
1441
0
    ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
1442
0
                                  rtb->frc_objalloc, rtb->mem);
1443
1444
0
    if (rv != 0) {
1445
0
      return rv;
1446
0
    }
1447
0
  }
1448
1449
0
  return 0;
1450
0
}
1451
1452
0
void ngtcp2_rtb_remove_early_data(ngtcp2_rtb *rtb, ngtcp2_conn_stat *cstat) {
1453
0
  ngtcp2_rtb_entry *ent;
1454
0
  ngtcp2_ksl_it it;
1455
0
  int rv;
1456
0
  (void)rv;
1457
1458
0
  it = ngtcp2_ksl_begin(&rtb->ents);
1459
1460
0
  for (; !ngtcp2_ksl_it_end(&it);) {
1461
0
    ent = ngtcp2_ksl_it_get(&it);
1462
1463
0
    if (ent->hd.type != NGTCP2_PKT_0RTT) {
1464
0
      ngtcp2_ksl_it_next(&it);
1465
0
      continue;
1466
0
    }
1467
1468
0
    rtb_on_remove(rtb, ent, cstat);
1469
0
    rv = ngtcp2_ksl_remove_hint(&rtb->ents, &it, &it, &ent->hd.pkt_num);
1470
0
    assert(0 == rv);
1471
1472
0
    ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
1473
0
                                  rtb->frc_objalloc, rtb->mem);
1474
0
  }
1475
0
}
1476
1477
0
int ngtcp2_rtb_empty(const ngtcp2_rtb *rtb) {
1478
0
  return ngtcp2_ksl_len(&rtb->ents) == 0;
1479
0
}
1480
1481
0
void ngtcp2_rtb_reset_cc_state(ngtcp2_rtb *rtb, int64_t cc_pkt_num) {
1482
0
  rtb->cc_pkt_num = cc_pkt_num;
1483
0
  rtb->cc_bytes_in_flight = 0;
1484
0
}
1485
1486
ngtcp2_ssize ngtcp2_rtb_reclaim_on_pto(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
1487
0
                                       ngtcp2_pktns *pktns, size_t num_pkts) {
1488
0
  ngtcp2_ksl_it it;
1489
0
  ngtcp2_rtb_entry *ent;
1490
0
  ngtcp2_ssize reclaimed;
1491
0
  size_t atmost = num_pkts;
1492
1493
0
  it = ngtcp2_ksl_end(&rtb->ents);
1494
0
  for (; !ngtcp2_ksl_it_begin(&it) && num_pkts;) {
1495
0
    ngtcp2_ksl_it_prev(&it);
1496
0
    ent = ngtcp2_ksl_it_get(&it);
1497
1498
0
    if ((ent->flags & (NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED |
1499
0
                       NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED)) ||
1500
0
        !(ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE)) {
1501
0
      continue;
1502
0
    }
1503
1504
0
    assert(ent->frc);
1505
1506
0
    reclaimed =
1507
0
      rtb_reclaim_frame(rtb, NGTCP2_RECLAIM_FLAG_NONE, conn, pktns, ent);
1508
0
    if (reclaimed < 0) {
1509
0
      return reclaimed;
1510
0
    }
1511
1512
    /* Mark ent reclaimed even if reclaimed == 0 so that we can skip
1513
       it in the next run. */
1514
0
    ent->flags |= NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED;
1515
1516
0
    assert(rtb->num_retransmittable);
1517
0
    --rtb->num_retransmittable;
1518
1519
0
    if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING) {
1520
0
      ent->flags &= (uint16_t)~NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING;
1521
0
      assert(rtb->num_pto_eliciting);
1522
0
      --rtb->num_pto_eliciting;
1523
0
    }
1524
1525
0
    if (reclaimed) {
1526
0
      --num_pkts;
1527
0
    }
1528
0
  }
1529
1530
0
  return (ngtcp2_ssize)(atmost - num_pkts);
1531
0
}