1*e7be843bSPierre Pronchery /*
2*e7be843bSPierre Pronchery * Copyright 2022-2023 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/uint_set.h"
11*e7be843bSPierre Pronchery #include "internal/common.h"
12*e7be843bSPierre Pronchery #include "internal/quic_sf_list.h"
13*e7be843bSPierre Pronchery
14*e7be843bSPierre Pronchery struct stream_frame_st {
15*e7be843bSPierre Pronchery struct stream_frame_st *prev, *next;
16*e7be843bSPierre Pronchery UINT_RANGE range;
17*e7be843bSPierre Pronchery OSSL_QRX_PKT *pkt;
18*e7be843bSPierre Pronchery const unsigned char *data;
19*e7be843bSPierre Pronchery };
20*e7be843bSPierre Pronchery
stream_frame_free(SFRAME_LIST * fl,STREAM_FRAME * sf)21*e7be843bSPierre Pronchery static void stream_frame_free(SFRAME_LIST *fl, STREAM_FRAME *sf)
22*e7be843bSPierre Pronchery {
23*e7be843bSPierre Pronchery if (fl->cleanse && sf->data != NULL)
24*e7be843bSPierre Pronchery OPENSSL_cleanse((unsigned char *)sf->data,
25*e7be843bSPierre Pronchery (size_t)(sf->range.end - sf->range.start));
26*e7be843bSPierre Pronchery ossl_qrx_pkt_release(sf->pkt);
27*e7be843bSPierre Pronchery OPENSSL_free(sf);
28*e7be843bSPierre Pronchery }
29*e7be843bSPierre Pronchery
stream_frame_new(UINT_RANGE * range,OSSL_QRX_PKT * pkt,const unsigned char * data)30*e7be843bSPierre Pronchery static STREAM_FRAME *stream_frame_new(UINT_RANGE *range, OSSL_QRX_PKT *pkt,
31*e7be843bSPierre Pronchery const unsigned char *data)
32*e7be843bSPierre Pronchery {
33*e7be843bSPierre Pronchery STREAM_FRAME *sf = OPENSSL_zalloc(sizeof(*sf));
34*e7be843bSPierre Pronchery
35*e7be843bSPierre Pronchery if (sf == NULL)
36*e7be843bSPierre Pronchery return NULL;
37*e7be843bSPierre Pronchery
38*e7be843bSPierre Pronchery if (pkt != NULL)
39*e7be843bSPierre Pronchery ossl_qrx_pkt_up_ref(pkt);
40*e7be843bSPierre Pronchery
41*e7be843bSPierre Pronchery sf->range = *range;
42*e7be843bSPierre Pronchery sf->pkt = pkt;
43*e7be843bSPierre Pronchery sf->data = data;
44*e7be843bSPierre Pronchery
45*e7be843bSPierre Pronchery return sf;
46*e7be843bSPierre Pronchery }
47*e7be843bSPierre Pronchery
ossl_sframe_list_init(SFRAME_LIST * fl)48*e7be843bSPierre Pronchery void ossl_sframe_list_init(SFRAME_LIST *fl)
49*e7be843bSPierre Pronchery {
50*e7be843bSPierre Pronchery memset(fl, 0, sizeof(*fl));
51*e7be843bSPierre Pronchery }
52*e7be843bSPierre Pronchery
ossl_sframe_list_destroy(SFRAME_LIST * fl)53*e7be843bSPierre Pronchery void ossl_sframe_list_destroy(SFRAME_LIST *fl)
54*e7be843bSPierre Pronchery {
55*e7be843bSPierre Pronchery STREAM_FRAME *sf, *next_frame;
56*e7be843bSPierre Pronchery
57*e7be843bSPierre Pronchery for (sf = fl->head; sf != NULL; sf = next_frame) {
58*e7be843bSPierre Pronchery next_frame = sf->next;
59*e7be843bSPierre Pronchery stream_frame_free(fl, sf);
60*e7be843bSPierre Pronchery }
61*e7be843bSPierre Pronchery }
62*e7be843bSPierre Pronchery
append_frame(SFRAME_LIST * fl,UINT_RANGE * range,OSSL_QRX_PKT * pkt,const unsigned char * data)63*e7be843bSPierre Pronchery static int append_frame(SFRAME_LIST *fl, UINT_RANGE *range,
64*e7be843bSPierre Pronchery OSSL_QRX_PKT *pkt,
65*e7be843bSPierre Pronchery const unsigned char *data)
66*e7be843bSPierre Pronchery {
67*e7be843bSPierre Pronchery STREAM_FRAME *new_frame;
68*e7be843bSPierre Pronchery
69*e7be843bSPierre Pronchery if ((new_frame = stream_frame_new(range, pkt, data)) == NULL)
70*e7be843bSPierre Pronchery return 0;
71*e7be843bSPierre Pronchery new_frame->prev = fl->tail;
72*e7be843bSPierre Pronchery if (fl->tail != NULL)
73*e7be843bSPierre Pronchery fl->tail->next = new_frame;
74*e7be843bSPierre Pronchery fl->tail = new_frame;
75*e7be843bSPierre Pronchery ++fl->num_frames;
76*e7be843bSPierre Pronchery return 1;
77*e7be843bSPierre Pronchery }
78*e7be843bSPierre Pronchery
ossl_sframe_list_insert(SFRAME_LIST * fl,UINT_RANGE * range,OSSL_QRX_PKT * pkt,const unsigned char * data,int fin)79*e7be843bSPierre Pronchery int ossl_sframe_list_insert(SFRAME_LIST *fl, UINT_RANGE *range,
80*e7be843bSPierre Pronchery OSSL_QRX_PKT *pkt,
81*e7be843bSPierre Pronchery const unsigned char *data, int fin)
82*e7be843bSPierre Pronchery {
83*e7be843bSPierre Pronchery STREAM_FRAME *sf, *new_frame, *prev_frame, *next_frame;
84*e7be843bSPierre Pronchery #ifndef NDEBUG
85*e7be843bSPierre Pronchery uint64_t curr_end = fl->tail != NULL ? fl->tail->range.end
86*e7be843bSPierre Pronchery : fl->offset;
87*e7be843bSPierre Pronchery
88*e7be843bSPierre Pronchery /* This check for FINAL_SIZE_ERROR is handled by QUIC FC already */
89*e7be843bSPierre Pronchery assert((!fin || curr_end <= range->end)
90*e7be843bSPierre Pronchery && (!fl->fin || curr_end >= range->end));
91*e7be843bSPierre Pronchery #endif
92*e7be843bSPierre Pronchery
93*e7be843bSPierre Pronchery if (fl->offset >= range->end)
94*e7be843bSPierre Pronchery goto end;
95*e7be843bSPierre Pronchery
96*e7be843bSPierre Pronchery /* nothing there yet */
97*e7be843bSPierre Pronchery if (fl->tail == NULL) {
98*e7be843bSPierre Pronchery fl->tail = fl->head = stream_frame_new(range, pkt, data);
99*e7be843bSPierre Pronchery if (fl->tail == NULL)
100*e7be843bSPierre Pronchery return 0;
101*e7be843bSPierre Pronchery
102*e7be843bSPierre Pronchery ++fl->num_frames;
103*e7be843bSPierre Pronchery goto end;
104*e7be843bSPierre Pronchery }
105*e7be843bSPierre Pronchery
106*e7be843bSPierre Pronchery /* optimize insertion at the end */
107*e7be843bSPierre Pronchery if (fl->tail->range.start < range->start) {
108*e7be843bSPierre Pronchery if (fl->tail->range.end >= range->end)
109*e7be843bSPierre Pronchery goto end;
110*e7be843bSPierre Pronchery
111*e7be843bSPierre Pronchery if (!append_frame(fl, range, pkt, data))
112*e7be843bSPierre Pronchery return 0;
113*e7be843bSPierre Pronchery goto end;
114*e7be843bSPierre Pronchery }
115*e7be843bSPierre Pronchery
116*e7be843bSPierre Pronchery prev_frame = NULL;
117*e7be843bSPierre Pronchery for (sf = fl->head; sf != NULL && sf->range.start < range->start;
118*e7be843bSPierre Pronchery sf = sf->next)
119*e7be843bSPierre Pronchery prev_frame = sf;
120*e7be843bSPierre Pronchery
121*e7be843bSPierre Pronchery if (!ossl_assert(sf != NULL))
122*e7be843bSPierre Pronchery /* frame list invariant broken */
123*e7be843bSPierre Pronchery return 0;
124*e7be843bSPierre Pronchery
125*e7be843bSPierre Pronchery if (prev_frame != NULL && prev_frame->range.end >= range->end)
126*e7be843bSPierre Pronchery goto end;
127*e7be843bSPierre Pronchery
128*e7be843bSPierre Pronchery /*
129*e7be843bSPierre Pronchery * Now we must create a new frame although in the end we might drop it,
130*e7be843bSPierre Pronchery * because we will be potentially dropping existing overlapping frames.
131*e7be843bSPierre Pronchery */
132*e7be843bSPierre Pronchery new_frame = stream_frame_new(range, pkt, data);
133*e7be843bSPierre Pronchery if (new_frame == NULL)
134*e7be843bSPierre Pronchery return 0;
135*e7be843bSPierre Pronchery
136*e7be843bSPierre Pronchery for (next_frame = sf;
137*e7be843bSPierre Pronchery next_frame != NULL && next_frame->range.end <= range->end;) {
138*e7be843bSPierre Pronchery STREAM_FRAME *drop_frame = next_frame;
139*e7be843bSPierre Pronchery
140*e7be843bSPierre Pronchery next_frame = next_frame->next;
141*e7be843bSPierre Pronchery if (next_frame != NULL)
142*e7be843bSPierre Pronchery next_frame->prev = drop_frame->prev;
143*e7be843bSPierre Pronchery if (prev_frame != NULL)
144*e7be843bSPierre Pronchery prev_frame->next = drop_frame->next;
145*e7be843bSPierre Pronchery if (fl->head == drop_frame)
146*e7be843bSPierre Pronchery fl->head = next_frame;
147*e7be843bSPierre Pronchery if (fl->tail == drop_frame)
148*e7be843bSPierre Pronchery fl->tail = prev_frame;
149*e7be843bSPierre Pronchery --fl->num_frames;
150*e7be843bSPierre Pronchery stream_frame_free(fl, drop_frame);
151*e7be843bSPierre Pronchery }
152*e7be843bSPierre Pronchery
153*e7be843bSPierre Pronchery if (next_frame != NULL) {
154*e7be843bSPierre Pronchery /* check whether the new_frame is redundant because there is no gap */
155*e7be843bSPierre Pronchery if (prev_frame != NULL
156*e7be843bSPierre Pronchery && next_frame->range.start <= prev_frame->range.end) {
157*e7be843bSPierre Pronchery stream_frame_free(fl, new_frame);
158*e7be843bSPierre Pronchery goto end;
159*e7be843bSPierre Pronchery }
160*e7be843bSPierre Pronchery next_frame->prev = new_frame;
161*e7be843bSPierre Pronchery } else {
162*e7be843bSPierre Pronchery fl->tail = new_frame;
163*e7be843bSPierre Pronchery }
164*e7be843bSPierre Pronchery
165*e7be843bSPierre Pronchery new_frame->next = next_frame;
166*e7be843bSPierre Pronchery new_frame->prev = prev_frame;
167*e7be843bSPierre Pronchery
168*e7be843bSPierre Pronchery if (prev_frame != NULL)
169*e7be843bSPierre Pronchery prev_frame->next = new_frame;
170*e7be843bSPierre Pronchery else
171*e7be843bSPierre Pronchery fl->head = new_frame;
172*e7be843bSPierre Pronchery
173*e7be843bSPierre Pronchery ++fl->num_frames;
174*e7be843bSPierre Pronchery
175*e7be843bSPierre Pronchery end:
176*e7be843bSPierre Pronchery fl->fin = fin || fl->fin;
177*e7be843bSPierre Pronchery
178*e7be843bSPierre Pronchery return 1;
179*e7be843bSPierre Pronchery }
180*e7be843bSPierre Pronchery
ossl_sframe_list_peek(const SFRAME_LIST * fl,void ** iter,UINT_RANGE * range,const unsigned char ** data,int * fin)181*e7be843bSPierre Pronchery int ossl_sframe_list_peek(const SFRAME_LIST *fl, void **iter,
182*e7be843bSPierre Pronchery UINT_RANGE *range, const unsigned char **data,
183*e7be843bSPierre Pronchery int *fin)
184*e7be843bSPierre Pronchery {
185*e7be843bSPierre Pronchery STREAM_FRAME *sf = *iter;
186*e7be843bSPierre Pronchery uint64_t start;
187*e7be843bSPierre Pronchery
188*e7be843bSPierre Pronchery if (sf == NULL) {
189*e7be843bSPierre Pronchery start = fl->offset;
190*e7be843bSPierre Pronchery sf = fl->head;
191*e7be843bSPierre Pronchery } else {
192*e7be843bSPierre Pronchery start = sf->range.end;
193*e7be843bSPierre Pronchery sf = sf->next;
194*e7be843bSPierre Pronchery }
195*e7be843bSPierre Pronchery
196*e7be843bSPierre Pronchery range->start = start;
197*e7be843bSPierre Pronchery
198*e7be843bSPierre Pronchery if (sf == NULL || sf->range.start > start
199*e7be843bSPierre Pronchery || !ossl_assert(start < sf->range.end)) {
200*e7be843bSPierre Pronchery range->end = start;
201*e7be843bSPierre Pronchery *data = NULL;
202*e7be843bSPierre Pronchery *iter = NULL;
203*e7be843bSPierre Pronchery /* set fin only if we are at the end */
204*e7be843bSPierre Pronchery *fin = sf == NULL ? fl->fin : 0;
205*e7be843bSPierre Pronchery return 0;
206*e7be843bSPierre Pronchery }
207*e7be843bSPierre Pronchery
208*e7be843bSPierre Pronchery range->end = sf->range.end;
209*e7be843bSPierre Pronchery if (sf->data != NULL)
210*e7be843bSPierre Pronchery *data = sf->data + (start - sf->range.start);
211*e7be843bSPierre Pronchery else
212*e7be843bSPierre Pronchery *data = NULL;
213*e7be843bSPierre Pronchery *fin = sf->next == NULL ? fl->fin : 0;
214*e7be843bSPierre Pronchery *iter = sf;
215*e7be843bSPierre Pronchery return 1;
216*e7be843bSPierre Pronchery }
217*e7be843bSPierre Pronchery
ossl_sframe_list_drop_frames(SFRAME_LIST * fl,uint64_t limit)218*e7be843bSPierre Pronchery int ossl_sframe_list_drop_frames(SFRAME_LIST *fl, uint64_t limit)
219*e7be843bSPierre Pronchery {
220*e7be843bSPierre Pronchery STREAM_FRAME *sf;
221*e7be843bSPierre Pronchery
222*e7be843bSPierre Pronchery /* offset cannot move back or past the data received */
223*e7be843bSPierre Pronchery if (!ossl_assert(limit >= fl->offset)
224*e7be843bSPierre Pronchery || !ossl_assert(fl->tail == NULL
225*e7be843bSPierre Pronchery || limit <= fl->tail->range.end)
226*e7be843bSPierre Pronchery || !ossl_assert(fl->tail != NULL
227*e7be843bSPierre Pronchery || limit == fl->offset))
228*e7be843bSPierre Pronchery return 0;
229*e7be843bSPierre Pronchery
230*e7be843bSPierre Pronchery fl->offset = limit;
231*e7be843bSPierre Pronchery
232*e7be843bSPierre Pronchery for (sf = fl->head; sf != NULL && sf->range.end <= limit;) {
233*e7be843bSPierre Pronchery STREAM_FRAME *drop_frame = sf;
234*e7be843bSPierre Pronchery
235*e7be843bSPierre Pronchery sf = sf->next;
236*e7be843bSPierre Pronchery --fl->num_frames;
237*e7be843bSPierre Pronchery stream_frame_free(fl, drop_frame);
238*e7be843bSPierre Pronchery }
239*e7be843bSPierre Pronchery fl->head = sf;
240*e7be843bSPierre Pronchery
241*e7be843bSPierre Pronchery if (sf != NULL)
242*e7be843bSPierre Pronchery sf->prev = NULL;
243*e7be843bSPierre Pronchery else
244*e7be843bSPierre Pronchery fl->tail = NULL;
245*e7be843bSPierre Pronchery
246*e7be843bSPierre Pronchery fl->head_locked = 0;
247*e7be843bSPierre Pronchery
248*e7be843bSPierre Pronchery return 1;
249*e7be843bSPierre Pronchery }
250*e7be843bSPierre Pronchery
ossl_sframe_list_lock_head(SFRAME_LIST * fl,UINT_RANGE * range,const unsigned char ** data,int * fin)251*e7be843bSPierre Pronchery int ossl_sframe_list_lock_head(SFRAME_LIST *fl, UINT_RANGE *range,
252*e7be843bSPierre Pronchery const unsigned char **data,
253*e7be843bSPierre Pronchery int *fin)
254*e7be843bSPierre Pronchery {
255*e7be843bSPierre Pronchery int ret;
256*e7be843bSPierre Pronchery void *iter = NULL;
257*e7be843bSPierre Pronchery
258*e7be843bSPierre Pronchery if (fl->head_locked)
259*e7be843bSPierre Pronchery return 0;
260*e7be843bSPierre Pronchery
261*e7be843bSPierre Pronchery ret = ossl_sframe_list_peek(fl, &iter, range, data, fin);
262*e7be843bSPierre Pronchery if (ret)
263*e7be843bSPierre Pronchery fl->head_locked = 1;
264*e7be843bSPierre Pronchery return ret;
265*e7be843bSPierre Pronchery }
266*e7be843bSPierre Pronchery
ossl_sframe_list_is_head_locked(SFRAME_LIST * fl)267*e7be843bSPierre Pronchery int ossl_sframe_list_is_head_locked(SFRAME_LIST *fl)
268*e7be843bSPierre Pronchery {
269*e7be843bSPierre Pronchery return fl->head_locked;
270*e7be843bSPierre Pronchery }
271*e7be843bSPierre Pronchery
ossl_sframe_list_move_data(SFRAME_LIST * fl,sframe_list_write_at_cb * write_at_cb,void * cb_arg)272*e7be843bSPierre Pronchery int ossl_sframe_list_move_data(SFRAME_LIST *fl,
273*e7be843bSPierre Pronchery sframe_list_write_at_cb *write_at_cb,
274*e7be843bSPierre Pronchery void *cb_arg)
275*e7be843bSPierre Pronchery {
276*e7be843bSPierre Pronchery STREAM_FRAME *sf = fl->head, *prev_frame = NULL;
277*e7be843bSPierre Pronchery uint64_t limit = fl->offset;
278*e7be843bSPierre Pronchery
279*e7be843bSPierre Pronchery if (sf == NULL)
280*e7be843bSPierre Pronchery return 1;
281*e7be843bSPierre Pronchery
282*e7be843bSPierre Pronchery if (fl->head_locked)
283*e7be843bSPierre Pronchery sf = sf->next;
284*e7be843bSPierre Pronchery
285*e7be843bSPierre Pronchery for (; sf != NULL; sf = sf->next) {
286*e7be843bSPierre Pronchery size_t len;
287*e7be843bSPierre Pronchery const unsigned char *data = sf->data;
288*e7be843bSPierre Pronchery
289*e7be843bSPierre Pronchery if (limit < sf->range.start)
290*e7be843bSPierre Pronchery limit = sf->range.start;
291*e7be843bSPierre Pronchery
292*e7be843bSPierre Pronchery if (data != NULL) {
293*e7be843bSPierre Pronchery if (limit > sf->range.start)
294*e7be843bSPierre Pronchery data += (size_t)(limit - sf->range.start);
295*e7be843bSPierre Pronchery len = (size_t)(sf->range.end - limit);
296*e7be843bSPierre Pronchery
297*e7be843bSPierre Pronchery if (!write_at_cb(limit, data, len, cb_arg))
298*e7be843bSPierre Pronchery /* data did not fit */
299*e7be843bSPierre Pronchery return 0;
300*e7be843bSPierre Pronchery
301*e7be843bSPierre Pronchery if (fl->cleanse)
302*e7be843bSPierre Pronchery OPENSSL_cleanse((unsigned char *)sf->data,
303*e7be843bSPierre Pronchery (size_t)(sf->range.end - sf->range.start));
304*e7be843bSPierre Pronchery
305*e7be843bSPierre Pronchery /* release the packet */
306*e7be843bSPierre Pronchery sf->data = NULL;
307*e7be843bSPierre Pronchery ossl_qrx_pkt_release(sf->pkt);
308*e7be843bSPierre Pronchery sf->pkt = NULL;
309*e7be843bSPierre Pronchery }
310*e7be843bSPierre Pronchery
311*e7be843bSPierre Pronchery limit = sf->range.end;
312*e7be843bSPierre Pronchery
313*e7be843bSPierre Pronchery /* merge contiguous frames */
314*e7be843bSPierre Pronchery if (prev_frame != NULL
315*e7be843bSPierre Pronchery && prev_frame->range.end >= sf->range.start) {
316*e7be843bSPierre Pronchery prev_frame->range.end = sf->range.end;
317*e7be843bSPierre Pronchery prev_frame->next = sf->next;
318*e7be843bSPierre Pronchery
319*e7be843bSPierre Pronchery if (sf->next != NULL)
320*e7be843bSPierre Pronchery sf->next->prev = prev_frame;
321*e7be843bSPierre Pronchery else
322*e7be843bSPierre Pronchery fl->tail = prev_frame;
323*e7be843bSPierre Pronchery
324*e7be843bSPierre Pronchery --fl->num_frames;
325*e7be843bSPierre Pronchery stream_frame_free(fl, sf);
326*e7be843bSPierre Pronchery sf = prev_frame;
327*e7be843bSPierre Pronchery continue;
328*e7be843bSPierre Pronchery }
329*e7be843bSPierre Pronchery
330*e7be843bSPierre Pronchery prev_frame = sf;
331*e7be843bSPierre Pronchery }
332*e7be843bSPierre Pronchery
333*e7be843bSPierre Pronchery return 1;
334*e7be843bSPierre Pronchery }
335