xref: /freebsd/crypto/openssl/ssl/quic/quic_fifd.c (revision e7be843b4a162e68651d3911f0357ed464915629)
1*e7be843bSPierre Pronchery /*
2*e7be843bSPierre Pronchery  * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved.
3*e7be843bSPierre Pronchery  *
4*e7be843bSPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5*e7be843bSPierre Pronchery  * this file except in compliance with the License.  You can obtain a copy
6*e7be843bSPierre Pronchery  * in the file LICENSE in the source distribution or at
7*e7be843bSPierre Pronchery  * https://www.openssl.org/source/license.html
8*e7be843bSPierre Pronchery  */
9*e7be843bSPierre Pronchery 
10*e7be843bSPierre Pronchery #include "internal/quic_fifd.h"
11*e7be843bSPierre Pronchery #include "internal/quic_wire.h"
12*e7be843bSPierre Pronchery #include "internal/qlog_event_helpers.h"
13*e7be843bSPierre Pronchery 
14*e7be843bSPierre Pronchery DEFINE_LIST_OF(tx_history, OSSL_ACKM_TX_PKT);
15*e7be843bSPierre Pronchery 
ossl_quic_fifd_init(QUIC_FIFD * fifd,QUIC_CFQ * cfq,OSSL_ACKM * ackm,QUIC_TXPIM * txpim,QUIC_SSTREAM * (* get_sstream_by_id)(uint64_t stream_id,uint32_t pn_space,void * arg),void * get_sstream_by_id_arg,void (* regen_frame)(uint64_t frame_type,uint64_t stream_id,QUIC_TXPIM_PKT * pkt,void * arg),void * regen_frame_arg,void (* confirm_frame)(uint64_t frame_type,uint64_t stream_id,QUIC_TXPIM_PKT * pkt,void * arg),void * confirm_frame_arg,void (* sstream_updated)(uint64_t stream_id,void * arg),void * sstream_updated_arg,QLOG * (* get_qlog_cb)(void * arg),void * get_qlog_cb_arg)16*e7be843bSPierre Pronchery int ossl_quic_fifd_init(QUIC_FIFD *fifd,
17*e7be843bSPierre Pronchery                         QUIC_CFQ *cfq,
18*e7be843bSPierre Pronchery                         OSSL_ACKM *ackm,
19*e7be843bSPierre Pronchery                         QUIC_TXPIM *txpim,
20*e7be843bSPierre Pronchery                         /* stream_id is UINT64_MAX for the crypto stream */
21*e7be843bSPierre Pronchery                         QUIC_SSTREAM *(*get_sstream_by_id)(uint64_t stream_id,
22*e7be843bSPierre Pronchery                                                            uint32_t pn_space,
23*e7be843bSPierre Pronchery                                                            void *arg),
24*e7be843bSPierre Pronchery                         void *get_sstream_by_id_arg,
25*e7be843bSPierre Pronchery                         /* stream_id is UINT64_MAX if not applicable */
26*e7be843bSPierre Pronchery                         void (*regen_frame)(uint64_t frame_type,
27*e7be843bSPierre Pronchery                                             uint64_t stream_id,
28*e7be843bSPierre Pronchery                                             QUIC_TXPIM_PKT *pkt,
29*e7be843bSPierre Pronchery                                             void *arg),
30*e7be843bSPierre Pronchery                         void *regen_frame_arg,
31*e7be843bSPierre Pronchery                         void (*confirm_frame)(uint64_t frame_type,
32*e7be843bSPierre Pronchery                                               uint64_t stream_id,
33*e7be843bSPierre Pronchery                                               QUIC_TXPIM_PKT *pkt,
34*e7be843bSPierre Pronchery                                               void *arg),
35*e7be843bSPierre Pronchery                         void *confirm_frame_arg,
36*e7be843bSPierre Pronchery                         void (*sstream_updated)(uint64_t stream_id,
37*e7be843bSPierre Pronchery                                                 void *arg),
38*e7be843bSPierre Pronchery                         void *sstream_updated_arg,
39*e7be843bSPierre Pronchery                         QLOG *(*get_qlog_cb)(void *arg),
40*e7be843bSPierre Pronchery                         void *get_qlog_cb_arg)
41*e7be843bSPierre Pronchery {
42*e7be843bSPierre Pronchery     if (cfq == NULL || ackm == NULL || txpim == NULL
43*e7be843bSPierre Pronchery         || get_sstream_by_id == NULL || regen_frame == NULL)
44*e7be843bSPierre Pronchery         return 0;
45*e7be843bSPierre Pronchery 
46*e7be843bSPierre Pronchery     fifd->cfq                   = cfq;
47*e7be843bSPierre Pronchery     fifd->ackm                  = ackm;
48*e7be843bSPierre Pronchery     fifd->txpim                 = txpim;
49*e7be843bSPierre Pronchery     fifd->get_sstream_by_id     = get_sstream_by_id;
50*e7be843bSPierre Pronchery     fifd->get_sstream_by_id_arg = get_sstream_by_id_arg;
51*e7be843bSPierre Pronchery     fifd->regen_frame           = regen_frame;
52*e7be843bSPierre Pronchery     fifd->regen_frame_arg       = regen_frame_arg;
53*e7be843bSPierre Pronchery     fifd->confirm_frame         = confirm_frame;
54*e7be843bSPierre Pronchery     fifd->confirm_frame_arg     = confirm_frame_arg;
55*e7be843bSPierre Pronchery     fifd->sstream_updated       = sstream_updated;
56*e7be843bSPierre Pronchery     fifd->sstream_updated_arg   = sstream_updated_arg;
57*e7be843bSPierre Pronchery     fifd->get_qlog_cb           = get_qlog_cb;
58*e7be843bSPierre Pronchery     fifd->get_qlog_cb_arg       = get_qlog_cb_arg;
59*e7be843bSPierre Pronchery     return 1;
60*e7be843bSPierre Pronchery }
61*e7be843bSPierre Pronchery 
ossl_quic_fifd_cleanup(QUIC_FIFD * fifd)62*e7be843bSPierre Pronchery void ossl_quic_fifd_cleanup(QUIC_FIFD *fifd)
63*e7be843bSPierre Pronchery {
64*e7be843bSPierre Pronchery     /* No-op. */
65*e7be843bSPierre Pronchery }
66*e7be843bSPierre Pronchery 
on_acked(void * arg)67*e7be843bSPierre Pronchery static void on_acked(void *arg)
68*e7be843bSPierre Pronchery {
69*e7be843bSPierre Pronchery     QUIC_TXPIM_PKT *pkt = arg;
70*e7be843bSPierre Pronchery     QUIC_FIFD *fifd = pkt->fifd;
71*e7be843bSPierre Pronchery     const QUIC_TXPIM_CHUNK *chunks = ossl_quic_txpim_pkt_get_chunks(pkt);
72*e7be843bSPierre Pronchery     size_t i, num_chunks = ossl_quic_txpim_pkt_get_num_chunks(pkt);
73*e7be843bSPierre Pronchery     QUIC_SSTREAM *sstream;
74*e7be843bSPierre Pronchery     QUIC_CFQ_ITEM *cfq_item, *cfq_item_next;
75*e7be843bSPierre Pronchery 
76*e7be843bSPierre Pronchery     /* STREAM and CRYPTO stream chunks, FINs and stream FC frames */
77*e7be843bSPierre Pronchery     for (i = 0; i < num_chunks; ++i) {
78*e7be843bSPierre Pronchery         sstream = fifd->get_sstream_by_id(chunks[i].stream_id,
79*e7be843bSPierre Pronchery                                           pkt->ackm_pkt.pkt_space,
80*e7be843bSPierre Pronchery                                           fifd->get_sstream_by_id_arg);
81*e7be843bSPierre Pronchery         if (sstream == NULL)
82*e7be843bSPierre Pronchery             continue;
83*e7be843bSPierre Pronchery 
84*e7be843bSPierre Pronchery         if (chunks[i].end >= chunks[i].start)
85*e7be843bSPierre Pronchery             /* coverity[check_return]: Best effort - we cannot fail here. */
86*e7be843bSPierre Pronchery             ossl_quic_sstream_mark_acked(sstream,
87*e7be843bSPierre Pronchery                                          chunks[i].start, chunks[i].end);
88*e7be843bSPierre Pronchery 
89*e7be843bSPierre Pronchery         if (chunks[i].has_fin && chunks[i].stream_id != UINT64_MAX)
90*e7be843bSPierre Pronchery             ossl_quic_sstream_mark_acked_fin(sstream);
91*e7be843bSPierre Pronchery 
92*e7be843bSPierre Pronchery         if (chunks[i].has_stop_sending && chunks[i].stream_id != UINT64_MAX)
93*e7be843bSPierre Pronchery             fifd->confirm_frame(OSSL_QUIC_FRAME_TYPE_STOP_SENDING,
94*e7be843bSPierre Pronchery                                 chunks[i].stream_id, pkt,
95*e7be843bSPierre Pronchery                                 fifd->confirm_frame_arg);
96*e7be843bSPierre Pronchery 
97*e7be843bSPierre Pronchery         if (chunks[i].has_reset_stream && chunks[i].stream_id != UINT64_MAX)
98*e7be843bSPierre Pronchery             fifd->confirm_frame(OSSL_QUIC_FRAME_TYPE_RESET_STREAM,
99*e7be843bSPierre Pronchery                                 chunks[i].stream_id, pkt,
100*e7be843bSPierre Pronchery                                 fifd->confirm_frame_arg);
101*e7be843bSPierre Pronchery 
102*e7be843bSPierre Pronchery         if (ossl_quic_sstream_is_totally_acked(sstream))
103*e7be843bSPierre Pronchery             fifd->sstream_updated(chunks[i].stream_id, fifd->sstream_updated_arg);
104*e7be843bSPierre Pronchery     }
105*e7be843bSPierre Pronchery 
106*e7be843bSPierre Pronchery     /* GCR */
107*e7be843bSPierre Pronchery     for (cfq_item = pkt->retx_head; cfq_item != NULL; cfq_item = cfq_item_next) {
108*e7be843bSPierre Pronchery         cfq_item_next = cfq_item->pkt_next;
109*e7be843bSPierre Pronchery         ossl_quic_cfq_release(fifd->cfq, cfq_item);
110*e7be843bSPierre Pronchery     }
111*e7be843bSPierre Pronchery 
112*e7be843bSPierre Pronchery     ossl_quic_txpim_pkt_release(fifd->txpim, pkt);
113*e7be843bSPierre Pronchery }
114*e7be843bSPierre Pronchery 
fifd_get_qlog(QUIC_FIFD * fifd)115*e7be843bSPierre Pronchery static QLOG *fifd_get_qlog(QUIC_FIFD *fifd)
116*e7be843bSPierre Pronchery {
117*e7be843bSPierre Pronchery     if (fifd->get_qlog_cb == NULL)
118*e7be843bSPierre Pronchery         return NULL;
119*e7be843bSPierre Pronchery 
120*e7be843bSPierre Pronchery     return fifd->get_qlog_cb(fifd->get_qlog_cb_arg);
121*e7be843bSPierre Pronchery }
122*e7be843bSPierre Pronchery 
on_lost(void * arg)123*e7be843bSPierre Pronchery static void on_lost(void *arg)
124*e7be843bSPierre Pronchery {
125*e7be843bSPierre Pronchery     QUIC_TXPIM_PKT *pkt = arg;
126*e7be843bSPierre Pronchery     QUIC_FIFD *fifd = pkt->fifd;
127*e7be843bSPierre Pronchery     const QUIC_TXPIM_CHUNK *chunks = ossl_quic_txpim_pkt_get_chunks(pkt);
128*e7be843bSPierre Pronchery     size_t i, num_chunks = ossl_quic_txpim_pkt_get_num_chunks(pkt);
129*e7be843bSPierre Pronchery     QUIC_SSTREAM *sstream;
130*e7be843bSPierre Pronchery     QUIC_CFQ_ITEM *cfq_item, *cfq_item_next;
131*e7be843bSPierre Pronchery     int sstream_updated;
132*e7be843bSPierre Pronchery 
133*e7be843bSPierre Pronchery     ossl_qlog_event_recovery_packet_lost(fifd_get_qlog(fifd), pkt);
134*e7be843bSPierre Pronchery 
135*e7be843bSPierre Pronchery     /* STREAM and CRYPTO stream chunks, FIN and stream FC frames */
136*e7be843bSPierre Pronchery     for (i = 0; i < num_chunks; ++i) {
137*e7be843bSPierre Pronchery         sstream = fifd->get_sstream_by_id(chunks[i].stream_id,
138*e7be843bSPierre Pronchery                                           pkt->ackm_pkt.pkt_space,
139*e7be843bSPierre Pronchery                                           fifd->get_sstream_by_id_arg);
140*e7be843bSPierre Pronchery         if (sstream == NULL)
141*e7be843bSPierre Pronchery             continue;
142*e7be843bSPierre Pronchery 
143*e7be843bSPierre Pronchery         sstream_updated = 0;
144*e7be843bSPierre Pronchery 
145*e7be843bSPierre Pronchery         if (chunks[i].end >= chunks[i].start) {
146*e7be843bSPierre Pronchery             /*
147*e7be843bSPierre Pronchery              * Note: If the stream is being reset, we do not need to retransmit
148*e7be843bSPierre Pronchery              * old data as this is pointless. In this case this will be handled
149*e7be843bSPierre Pronchery              * by (sstream == NULL) above as the QSM will free the QUIC_SSTREAM
150*e7be843bSPierre Pronchery              * and our call to get_sstream_by_id above will return NULL.
151*e7be843bSPierre Pronchery              */
152*e7be843bSPierre Pronchery             ossl_quic_sstream_mark_lost(sstream,
153*e7be843bSPierre Pronchery                                         chunks[i].start, chunks[i].end);
154*e7be843bSPierre Pronchery             sstream_updated = 1;
155*e7be843bSPierre Pronchery         }
156*e7be843bSPierre Pronchery 
157*e7be843bSPierre Pronchery         if (chunks[i].has_fin && chunks[i].stream_id != UINT64_MAX) {
158*e7be843bSPierre Pronchery             ossl_quic_sstream_mark_lost_fin(sstream);
159*e7be843bSPierre Pronchery             sstream_updated = 1;
160*e7be843bSPierre Pronchery         }
161*e7be843bSPierre Pronchery 
162*e7be843bSPierre Pronchery         if (chunks[i].has_stop_sending && chunks[i].stream_id != UINT64_MAX)
163*e7be843bSPierre Pronchery             fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_STOP_SENDING,
164*e7be843bSPierre Pronchery                               chunks[i].stream_id, pkt,
165*e7be843bSPierre Pronchery                               fifd->regen_frame_arg);
166*e7be843bSPierre Pronchery 
167*e7be843bSPierre Pronchery         if (chunks[i].has_reset_stream && chunks[i].stream_id != UINT64_MAX)
168*e7be843bSPierre Pronchery             fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_RESET_STREAM,
169*e7be843bSPierre Pronchery                               chunks[i].stream_id, pkt,
170*e7be843bSPierre Pronchery                               fifd->regen_frame_arg);
171*e7be843bSPierre Pronchery 
172*e7be843bSPierre Pronchery         /*
173*e7be843bSPierre Pronchery          * Inform caller that stream needs an FC frame.
174*e7be843bSPierre Pronchery          *
175*e7be843bSPierre Pronchery          * Note: We could track whether an FC frame was sent originally for the
176*e7be843bSPierre Pronchery          * stream to determine if it really needs to be regenerated or not.
177*e7be843bSPierre Pronchery          * However, if loss has occurred, it's probably better to ensure the
178*e7be843bSPierre Pronchery          * peer has up-to-date flow control data for the stream. Given that
179*e7be843bSPierre Pronchery          * these frames are extremely small, we may as well always send it when
180*e7be843bSPierre Pronchery          * handling loss.
181*e7be843bSPierre Pronchery          */
182*e7be843bSPierre Pronchery         fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA,
183*e7be843bSPierre Pronchery                           chunks[i].stream_id,
184*e7be843bSPierre Pronchery                           pkt,
185*e7be843bSPierre Pronchery                           fifd->regen_frame_arg);
186*e7be843bSPierre Pronchery 
187*e7be843bSPierre Pronchery         if (sstream_updated && chunks[i].stream_id != UINT64_MAX)
188*e7be843bSPierre Pronchery             fifd->sstream_updated(chunks[i].stream_id,
189*e7be843bSPierre Pronchery                                   fifd->sstream_updated_arg);
190*e7be843bSPierre Pronchery     }
191*e7be843bSPierre Pronchery 
192*e7be843bSPierre Pronchery     /* GCR */
193*e7be843bSPierre Pronchery     for (cfq_item = pkt->retx_head; cfq_item != NULL; cfq_item = cfq_item_next) {
194*e7be843bSPierre Pronchery         cfq_item_next = cfq_item->pkt_next;
195*e7be843bSPierre Pronchery         ossl_quic_cfq_mark_lost(fifd->cfq, cfq_item, UINT32_MAX);
196*e7be843bSPierre Pronchery     }
197*e7be843bSPierre Pronchery 
198*e7be843bSPierre Pronchery     /* Regenerate flag frames */
199*e7be843bSPierre Pronchery     if (pkt->had_handshake_done_frame)
200*e7be843bSPierre Pronchery         fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE,
201*e7be843bSPierre Pronchery                           UINT64_MAX, pkt,
202*e7be843bSPierre Pronchery                           fifd->regen_frame_arg);
203*e7be843bSPierre Pronchery 
204*e7be843bSPierre Pronchery     if (pkt->had_max_data_frame)
205*e7be843bSPierre Pronchery         fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_MAX_DATA,
206*e7be843bSPierre Pronchery                           UINT64_MAX, pkt,
207*e7be843bSPierre Pronchery                           fifd->regen_frame_arg);
208*e7be843bSPierre Pronchery 
209*e7be843bSPierre Pronchery     if (pkt->had_max_streams_bidi_frame)
210*e7be843bSPierre Pronchery         fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI,
211*e7be843bSPierre Pronchery                           UINT64_MAX, pkt,
212*e7be843bSPierre Pronchery                           fifd->regen_frame_arg);
213*e7be843bSPierre Pronchery 
214*e7be843bSPierre Pronchery     if (pkt->had_max_streams_uni_frame)
215*e7be843bSPierre Pronchery         fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI,
216*e7be843bSPierre Pronchery                           UINT64_MAX, pkt,
217*e7be843bSPierre Pronchery                           fifd->regen_frame_arg);
218*e7be843bSPierre Pronchery 
219*e7be843bSPierre Pronchery     if (pkt->had_ack_frame)
220*e7be843bSPierre Pronchery         /*
221*e7be843bSPierre Pronchery          * We always use the ACK_WITH_ECN frame type to represent the ACK frame
222*e7be843bSPierre Pronchery          * type in our callback; we assume it is the caller's job to decide
223*e7be843bSPierre Pronchery          * whether it wants to send ECN data or not.
224*e7be843bSPierre Pronchery          */
225*e7be843bSPierre Pronchery         fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_ACK_WITH_ECN,
226*e7be843bSPierre Pronchery                           UINT64_MAX, pkt,
227*e7be843bSPierre Pronchery                           fifd->regen_frame_arg);
228*e7be843bSPierre Pronchery 
229*e7be843bSPierre Pronchery     ossl_quic_txpim_pkt_release(fifd->txpim, pkt);
230*e7be843bSPierre Pronchery }
231*e7be843bSPierre Pronchery 
on_discarded(void * arg)232*e7be843bSPierre Pronchery static void on_discarded(void *arg)
233*e7be843bSPierre Pronchery {
234*e7be843bSPierre Pronchery     QUIC_TXPIM_PKT *pkt = arg;
235*e7be843bSPierre Pronchery     QUIC_FIFD *fifd = pkt->fifd;
236*e7be843bSPierre Pronchery     QUIC_CFQ_ITEM *cfq_item, *cfq_item_next;
237*e7be843bSPierre Pronchery 
238*e7be843bSPierre Pronchery     /*
239*e7be843bSPierre Pronchery      * Don't need to do anything to SSTREAMs for STREAM and CRYPTO streams, as
240*e7be843bSPierre Pronchery      * we assume caller will clean them up.
241*e7be843bSPierre Pronchery      */
242*e7be843bSPierre Pronchery 
243*e7be843bSPierre Pronchery     /* GCR */
244*e7be843bSPierre Pronchery     for (cfq_item = pkt->retx_head; cfq_item != NULL; cfq_item = cfq_item_next) {
245*e7be843bSPierre Pronchery         cfq_item_next = cfq_item->pkt_next;
246*e7be843bSPierre Pronchery         ossl_quic_cfq_release(fifd->cfq, cfq_item);
247*e7be843bSPierre Pronchery     }
248*e7be843bSPierre Pronchery 
249*e7be843bSPierre Pronchery     ossl_quic_txpim_pkt_release(fifd->txpim, pkt);
250*e7be843bSPierre Pronchery }
251*e7be843bSPierre Pronchery 
ossl_quic_fifd_pkt_commit(QUIC_FIFD * fifd,QUIC_TXPIM_PKT * pkt)252*e7be843bSPierre Pronchery int ossl_quic_fifd_pkt_commit(QUIC_FIFD *fifd, QUIC_TXPIM_PKT *pkt)
253*e7be843bSPierre Pronchery {
254*e7be843bSPierre Pronchery     QUIC_CFQ_ITEM *cfq_item;
255*e7be843bSPierre Pronchery     const QUIC_TXPIM_CHUNK *chunks;
256*e7be843bSPierre Pronchery     size_t i, num_chunks;
257*e7be843bSPierre Pronchery     QUIC_SSTREAM *sstream;
258*e7be843bSPierre Pronchery 
259*e7be843bSPierre Pronchery     pkt->fifd                   = fifd;
260*e7be843bSPierre Pronchery 
261*e7be843bSPierre Pronchery     pkt->ackm_pkt.on_lost       = on_lost;
262*e7be843bSPierre Pronchery     pkt->ackm_pkt.on_acked      = on_acked;
263*e7be843bSPierre Pronchery     pkt->ackm_pkt.on_discarded  = on_discarded;
264*e7be843bSPierre Pronchery     pkt->ackm_pkt.cb_arg        = pkt;
265*e7be843bSPierre Pronchery 
266*e7be843bSPierre Pronchery     ossl_list_tx_history_init_elem(&pkt->ackm_pkt);
267*e7be843bSPierre Pronchery     pkt->ackm_pkt.anext = pkt->ackm_pkt.lnext = NULL;
268*e7be843bSPierre Pronchery 
269*e7be843bSPierre Pronchery     /*
270*e7be843bSPierre Pronchery      * Mark the CFQ items which have been added to this packet as having been
271*e7be843bSPierre Pronchery      * transmitted.
272*e7be843bSPierre Pronchery      */
273*e7be843bSPierre Pronchery     for (cfq_item = pkt->retx_head;
274*e7be843bSPierre Pronchery          cfq_item != NULL;
275*e7be843bSPierre Pronchery          cfq_item = cfq_item->pkt_next)
276*e7be843bSPierre Pronchery         ossl_quic_cfq_mark_tx(fifd->cfq, cfq_item);
277*e7be843bSPierre Pronchery 
278*e7be843bSPierre Pronchery     /*
279*e7be843bSPierre Pronchery      * Mark the send stream chunks which have been added to the packet as having
280*e7be843bSPierre Pronchery      * been transmitted.
281*e7be843bSPierre Pronchery      */
282*e7be843bSPierre Pronchery     chunks = ossl_quic_txpim_pkt_get_chunks(pkt);
283*e7be843bSPierre Pronchery     num_chunks = ossl_quic_txpim_pkt_get_num_chunks(pkt);
284*e7be843bSPierre Pronchery     for (i = 0; i < num_chunks; ++i) {
285*e7be843bSPierre Pronchery         sstream = fifd->get_sstream_by_id(chunks[i].stream_id,
286*e7be843bSPierre Pronchery                                           pkt->ackm_pkt.pkt_space,
287*e7be843bSPierre Pronchery                                           fifd->get_sstream_by_id_arg);
288*e7be843bSPierre Pronchery         if (sstream == NULL)
289*e7be843bSPierre Pronchery             continue;
290*e7be843bSPierre Pronchery 
291*e7be843bSPierre Pronchery         if (chunks[i].end >= chunks[i].start
292*e7be843bSPierre Pronchery             && !ossl_quic_sstream_mark_transmitted(sstream,
293*e7be843bSPierre Pronchery                                                    chunks[i].start,
294*e7be843bSPierre Pronchery                                                    chunks[i].end))
295*e7be843bSPierre Pronchery             return 0;
296*e7be843bSPierre Pronchery 
297*e7be843bSPierre Pronchery         if (chunks[i].has_fin
298*e7be843bSPierre Pronchery             && !ossl_quic_sstream_mark_transmitted_fin(sstream,
299*e7be843bSPierre Pronchery                                                        chunks[i].end + 1))
300*e7be843bSPierre Pronchery                 return 0;
301*e7be843bSPierre Pronchery     }
302*e7be843bSPierre Pronchery 
303*e7be843bSPierre Pronchery     /* Inform the ACKM. */
304*e7be843bSPierre Pronchery     return ossl_ackm_on_tx_packet(fifd->ackm, &pkt->ackm_pkt);
305*e7be843bSPierre Pronchery }
306*e7be843bSPierre Pronchery 
ossl_quic_fifd_set_qlog_cb(QUIC_FIFD * fifd,QLOG * (* get_qlog_cb)(void * arg),void * get_qlog_cb_arg)307*e7be843bSPierre Pronchery void ossl_quic_fifd_set_qlog_cb(QUIC_FIFD *fifd, QLOG *(*get_qlog_cb)(void *arg),
308*e7be843bSPierre Pronchery                                 void *get_qlog_cb_arg)
309*e7be843bSPierre Pronchery {
310*e7be843bSPierre Pronchery     fifd->get_qlog_cb       = get_qlog_cb;
311*e7be843bSPierre Pronchery     fifd->get_qlog_cb_arg   = get_qlog_cb_arg;
312*e7be843bSPierre Pronchery }
313