xref: /src/crypto/openssl/test/quic_ackm_test.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*
2  * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include "testutil.h"
11 #include <openssl/ssl.h>
12 #include "internal/quic_ackm.h"
13 #include "internal/quic_cc.h"
14 
15 static OSSL_TIME fake_time = { 0 };
16 
17 #define TIME_BASE (ossl_ticks2time(123 * OSSL_TIME_SECOND))
18 
fake_now(void * arg)19 static OSSL_TIME fake_now(void *arg)
20 {
21     return fake_time;
22 }
23 
24 struct pkt_info {
25     OSSL_ACKM_TX_PKT *pkt;
26     int lost, acked, discarded;
27 };
28 
on_lost(void * arg)29 static void on_lost(void *arg)
30 {
31     struct pkt_info *info = arg;
32     ++info->lost;
33 }
34 
on_acked(void * arg)35 static void on_acked(void *arg)
36 {
37     struct pkt_info *info = arg;
38     ++info->acked;
39 }
40 
on_discarded(void * arg)41 static void on_discarded(void *arg)
42 {
43     struct pkt_info *info = arg;
44     ++info->discarded;
45 }
46 
47 struct helper {
48     OSSL_ACKM *ackm;
49     struct pkt_info *pkts;
50     size_t num_pkts;
51     OSSL_CC_DATA *ccdata;
52     OSSL_STATM statm;
53     int have_statm;
54 };
55 
helper_destroy(struct helper * h)56 static void helper_destroy(struct helper *h)
57 {
58     size_t i;
59 
60     if (h->ackm != NULL) {
61         ossl_ackm_free(h->ackm);
62         h->ackm = NULL;
63     }
64 
65     if (h->ccdata != NULL) {
66         ossl_cc_dummy_method.free(h->ccdata);
67         h->ccdata = NULL;
68     }
69 
70     if (h->have_statm) {
71         ossl_statm_destroy(&h->statm);
72         h->have_statm = 0;
73     }
74 
75     if (h->pkts != NULL) {
76         for (i = 0; i < h->num_pkts; ++i) {
77             OPENSSL_free(h->pkts[i].pkt);
78             h->pkts[i].pkt = NULL;
79         }
80 
81         OPENSSL_free(h->pkts);
82         h->pkts = NULL;
83     }
84 }
85 
helper_init(struct helper * h,size_t num_pkts)86 static int helper_init(struct helper *h, size_t num_pkts)
87 {
88     int rc = 0;
89 
90     memset(h, 0, sizeof(*h));
91 
92     fake_time = TIME_BASE;
93 
94     /* Initialise statistics tracker. */
95     if (!TEST_int_eq(ossl_statm_init(&h->statm), 1))
96         goto err;
97 
98     h->have_statm = 1;
99 
100     /* Initialise congestion controller. */
101     h->ccdata = ossl_cc_dummy_method.new(fake_now, NULL);
102     if (!TEST_ptr(h->ccdata))
103         goto err;
104 
105     /* Initialise ACK manager. */
106     h->ackm = ossl_ackm_new(fake_now, NULL, &h->statm,
107         &ossl_cc_dummy_method, h->ccdata,
108         /* is_server */ 0);
109     if (!TEST_ptr(h->ackm))
110         goto err;
111 
112     /* Allocate our array of packet information. */
113     h->num_pkts = num_pkts;
114     if (num_pkts > 0) {
115         h->pkts = OPENSSL_zalloc(sizeof(struct pkt_info) * num_pkts);
116         if (!TEST_ptr(h->pkts))
117             goto err;
118     } else {
119         h->pkts = NULL;
120     }
121 
122     rc = 1;
123 err:
124     if (rc == 0)
125         helper_destroy(h);
126 
127     return rc;
128 }
129 
130 static const QUIC_PN linear_20[] = {
131     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
132 };
133 
134 static const QUIC_PN high_linear_20[] = {
135     1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008,
136     1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017,
137     1018, 1019
138 };
139 
140 /*
141  * TX ACK (Packet Threshold) Test Cases
142  * ******************************************************************
143  */
144 struct tx_ack_test_case {
145     const QUIC_PN *pn_table;
146     size_t pn_table_len;
147     const OSSL_QUIC_ACK_RANGE *ack_ranges;
148     size_t num_ack_ranges;
149     const char *expect_ack; /* 1=ack, 2=lost, 4=discarded */
150 };
151 
152 #define DEFINE_TX_ACK_CASE(n, pntable)                       \
153     static const struct tx_ack_test_case tx_ack_case_##n = { \
154         (pntable), OSSL_NELEM(pntable),                      \
155         tx_ack_range_##n, OSSL_NELEM(tx_ack_range_##n),      \
156         tx_ack_expect_##n                                    \
157     }
158 
159 /* One range, partial coverage of space */
160 static const OSSL_QUIC_ACK_RANGE tx_ack_range_1[] = {
161     { 0, 10 },
162 };
163 static const char tx_ack_expect_1[] = {
164     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
165 };
166 DEFINE_TX_ACK_CASE(1, linear_20);
167 
168 /* Two ranges, partial coverage of space, overlapping by 1 */
169 static const OSSL_QUIC_ACK_RANGE tx_ack_range_2[] = {
170     { 5, 10 }, { 0, 5 }
171 };
172 static const char tx_ack_expect_2[] = {
173     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
174 };
175 DEFINE_TX_ACK_CASE(2, linear_20);
176 
177 /* Two ranges, partial coverage of space, together contiguous */
178 static const OSSL_QUIC_ACK_RANGE tx_ack_range_3[] = {
179     { 6, 10 }, { 0, 5 }
180 };
181 static const char tx_ack_expect_3[] = {
182     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
183 };
184 DEFINE_TX_ACK_CASE(3, linear_20);
185 
186 /*
187  * Two ranges, partial coverage of space, non-contiguous by 1
188  * Causes inferred loss due to packet threshold being exceeded.
189  */
190 static const OSSL_QUIC_ACK_RANGE tx_ack_range_4[] = {
191     { 7, 10 }, { 0, 5 }
192 };
193 static const char tx_ack_expect_4[] = {
194     1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
195 };
196 DEFINE_TX_ACK_CASE(4, linear_20);
197 
198 /*
199  * Two ranges, partial coverage of space, non-contiguous by 2
200  * Causes inferred loss due to packet threshold being exceeded.
201  */
202 static const OSSL_QUIC_ACK_RANGE tx_ack_range_5[] = {
203     { 7, 10 }, { 0, 4 }
204 };
205 static const char tx_ack_expect_5[] = {
206     1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
207 };
208 DEFINE_TX_ACK_CASE(5, linear_20);
209 
210 /* One range, covering entire space */
211 static const OSSL_QUIC_ACK_RANGE tx_ack_range_6[] = {
212     { 0, 20 },
213 };
214 static const char tx_ack_expect_6[] = {
215     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
216 };
217 DEFINE_TX_ACK_CASE(6, linear_20);
218 
219 /* One range, covering more space than exists */
220 static const OSSL_QUIC_ACK_RANGE tx_ack_range_7[] = {
221     { 0, 30 },
222 };
223 static const char tx_ack_expect_7[] = {
224     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
225 };
226 DEFINE_TX_ACK_CASE(7, linear_20);
227 
228 /* One range, covering nothing (too high) */
229 static const OSSL_QUIC_ACK_RANGE tx_ack_range_8[] = {
230     { 21, 30 },
231 };
232 static const char tx_ack_expect_8[] = {
233     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
234 };
235 DEFINE_TX_ACK_CASE(8, linear_20);
236 
237 /* One range, covering nothing (too low) */
238 static const OSSL_QUIC_ACK_RANGE tx_ack_range_9[] = {
239     { 0, 999 },
240 };
241 static const char tx_ack_expect_9[] = {
242     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
243 };
244 DEFINE_TX_ACK_CASE(9, high_linear_20);
245 
246 /* One single packet at start of PN set */
247 static const OSSL_QUIC_ACK_RANGE tx_ack_range_10[] = {
248     { 0, 0 },
249 };
250 static const char tx_ack_expect_10[] = {
251     1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
252 };
253 DEFINE_TX_ACK_CASE(10, linear_20);
254 
255 /*
256  * One single packet in middle of PN set
257  * Causes inferred loss of one packet due to packet threshold being exceeded,
258  * but several other previous packets survive as they are under the threshold.
259  */
260 static const OSSL_QUIC_ACK_RANGE tx_ack_range_11[] = {
261     { 3, 3 },
262 };
263 static const char tx_ack_expect_11[] = {
264     2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
265 };
266 DEFINE_TX_ACK_CASE(11, linear_20);
267 
268 /*
269  * One single packet at end of PN set
270  * Causes inferred loss due to packet threshold being exceeded.
271  */
272 static const OSSL_QUIC_ACK_RANGE tx_ack_range_12[] = {
273     { 19, 19 },
274 };
275 static const char tx_ack_expect_12[] = {
276     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 1
277 };
278 DEFINE_TX_ACK_CASE(12, linear_20);
279 
280 /*
281  * Mixed straddling
282  * Causes inferred loss due to packet threshold being exceeded.
283  */
284 static const OSSL_QUIC_ACK_RANGE tx_ack_range_13[] = {
285     { 1008, 1008 }, { 1004, 1005 }, { 1001, 1002 }
286 };
287 static const char tx_ack_expect_13[] = {
288     2, 1, 1, 2, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
289 };
290 DEFINE_TX_ACK_CASE(13, high_linear_20);
291 
292 static const struct tx_ack_test_case *const tx_ack_cases[] = {
293     &tx_ack_case_1,
294     &tx_ack_case_2,
295     &tx_ack_case_3,
296     &tx_ack_case_4,
297     &tx_ack_case_5,
298     &tx_ack_case_6,
299     &tx_ack_case_7,
300     &tx_ack_case_8,
301     &tx_ack_case_9,
302     &tx_ack_case_10,
303     &tx_ack_case_11,
304     &tx_ack_case_12,
305     &tx_ack_case_13,
306 };
307 
308 enum {
309     MODE_ACK,
310     MODE_DISCARD,
311     MODE_PTO,
312     MODE_NUM
313 };
314 
test_probe_counts(const OSSL_ACKM_PROBE_INFO * p,uint32_t anti_deadlock_handshake,uint32_t anti_deadlock_initial,uint32_t pto_initial,uint32_t pto_handshake,uint32_t pto_app)315 static int test_probe_counts(const OSSL_ACKM_PROBE_INFO *p,
316     uint32_t anti_deadlock_handshake,
317     uint32_t anti_deadlock_initial,
318     uint32_t pto_initial,
319     uint32_t pto_handshake,
320     uint32_t pto_app)
321 {
322     if (!TEST_uint_eq(p->anti_deadlock_handshake, anti_deadlock_handshake))
323         return 0;
324     if (!TEST_uint_eq(p->anti_deadlock_initial, anti_deadlock_initial))
325         return 0;
326     if (!TEST_uint_eq(p->pto[QUIC_PN_SPACE_INITIAL], pto_initial))
327         return 0;
328     if (!TEST_uint_eq(p->pto[QUIC_PN_SPACE_HANDSHAKE], pto_handshake))
329         return 0;
330     if (!TEST_uint_eq(p->pto[QUIC_PN_SPACE_APP], pto_app))
331         return 0;
332     return 1;
333 }
334 
on_loss_detection_deadline_callback(OSSL_TIME deadline,void * arg)335 static void on_loss_detection_deadline_callback(OSSL_TIME deadline, void *arg)
336 {
337     *(OSSL_TIME *)arg = deadline;
338 }
339 
test_tx_ack_case_actual(int tidx,int space,int mode)340 static int test_tx_ack_case_actual(int tidx, int space, int mode)
341 {
342     int testresult = 0;
343     struct helper h;
344     size_t i;
345     OSSL_ACKM_TX_PKT *tx;
346     const struct tx_ack_test_case *c = tx_ack_cases[tidx];
347     OSSL_QUIC_FRAME_ACK ack = { 0 };
348     OSSL_TIME loss_detection_deadline = ossl_time_zero();
349 
350     /* Cannot discard app space, so skip this */
351     if (mode == MODE_DISCARD && space == QUIC_PN_SPACE_APP) {
352         TEST_skip("skipping test for app space");
353         return 1;
354     }
355 
356     if (!TEST_int_eq(helper_init(&h, c->pn_table_len), 1))
357         goto err;
358 
359     /* Arm callback. */
360     ossl_ackm_set_loss_detection_deadline_callback(h.ackm,
361         on_loss_detection_deadline_callback,
362         &loss_detection_deadline);
363 
364     /* Allocate TX packet structures. */
365     for (i = 0; i < c->pn_table_len; ++i) {
366         h.pkts[i].pkt = tx = OPENSSL_zalloc(sizeof(*tx));
367         if (!TEST_ptr(tx))
368             goto err;
369 
370         tx->pkt_num = c->pn_table[i];
371         tx->pkt_space = space;
372         tx->is_inflight = 1;
373         tx->is_ack_eliciting = 1;
374         tx->num_bytes = 123;
375         tx->largest_acked = QUIC_PN_INVALID;
376         tx->on_lost = on_lost;
377         tx->on_acked = on_acked;
378         tx->on_discarded = on_discarded;
379         tx->cb_arg = &h.pkts[i];
380 
381         tx->time = fake_time;
382 
383         if (!TEST_int_eq(ossl_ackm_on_tx_packet(h.ackm, tx), 1))
384             goto err;
385     }
386 
387     if (mode == MODE_DISCARD) {
388         /* Try discarding. */
389         if (!TEST_int_eq(ossl_ackm_on_pkt_space_discarded(h.ackm, space), 1))
390             goto err;
391 
392         /* Check all discard callbacks were called. */
393         for (i = 0; i < c->pn_table_len; ++i) {
394             if (!TEST_int_eq(h.pkts[i].acked, 0))
395                 goto err;
396             if (!TEST_int_eq(h.pkts[i].lost, 0))
397                 goto err;
398             if (!TEST_int_eq(h.pkts[i].discarded, 1))
399                 goto err;
400         }
401     } else if (mode == MODE_ACK) {
402         /* Try acknowledging. */
403         ack.ack_ranges = (OSSL_QUIC_ACK_RANGE *)c->ack_ranges;
404         ack.num_ack_ranges = c->num_ack_ranges;
405         if (!TEST_int_eq(ossl_ackm_on_rx_ack_frame(h.ackm, &ack, space, fake_time), 1))
406             goto err;
407 
408         /* Check correct ranges were acknowledged. */
409         for (i = 0; i < c->pn_table_len; ++i) {
410             if (!TEST_int_eq(h.pkts[i].acked,
411                     (c->expect_ack[i] & 1) != 0 ? 1 : 0))
412                 goto err;
413             if (!TEST_int_eq(h.pkts[i].lost,
414                     (c->expect_ack[i] & 2) != 0 ? 1 : 0))
415                 goto err;
416             if (!TEST_int_eq(h.pkts[i].discarded,
417                     (c->expect_ack[i] & 4) != 0 ? 1 : 0))
418                 goto err;
419         }
420     } else if (mode == MODE_PTO) {
421         OSSL_TIME deadline = ossl_ackm_get_loss_detection_deadline(h.ackm);
422         OSSL_ACKM_PROBE_INFO probe;
423 
424         if (!TEST_int_eq(ossl_time_compare(deadline, loss_detection_deadline), 0))
425             goto err;
426 
427         /* We should have a PTO deadline. */
428         if (!TEST_int_gt(ossl_time_compare(deadline, fake_time), 0))
429             goto err;
430 
431         /* Should not have any probe requests yet. */
432         probe = *ossl_ackm_get0_probe_request(h.ackm);
433         if (!TEST_int_eq(test_probe_counts(&probe, 0, 0, 0, 0, 0), 1))
434             goto err;
435 
436         /*
437          * If in app space, confirm handshake, as this is necessary to enable
438          * app space PTO probe requests.
439          */
440         if (space == QUIC_PN_SPACE_APP)
441             if (!TEST_int_eq(ossl_ackm_on_handshake_confirmed(h.ackm), 1))
442                 goto err;
443 
444         /* Advance to the PTO deadline. */
445         fake_time = ossl_time_add(deadline, ossl_ticks2time(1));
446 
447         if (!TEST_int_eq(ossl_ackm_on_timeout(h.ackm), 1))
448             goto err;
449 
450         /* Should have a probe request. Not cleared by first call. */
451         for (i = 0; i < 3; ++i) {
452             probe = *ossl_ackm_get0_probe_request(h.ackm);
453             if (i > 0)
454                 memset(ossl_ackm_get0_probe_request(h.ackm), 0, sizeof(probe));
455 
456             if (i == 2) {
457                 if (!TEST_int_eq(test_probe_counts(&probe, 0, 0, 0, 0, 0), 1))
458                     goto err;
459             } else {
460                 if (!TEST_int_eq(test_probe_counts(&probe, 0, 0,
461                                      space == QUIC_PN_SPACE_INITIAL,
462                                      space == QUIC_PN_SPACE_HANDSHAKE,
463                                      space == QUIC_PN_SPACE_APP),
464                         1))
465                     goto err;
466             }
467         }
468 
469     } else
470         goto err;
471 
472     testresult = 1;
473 err:
474     helper_destroy(&h);
475     return testresult;
476 }
477 
478 /*
479  * TX ACK (Time Threshold) Test
480  * ******************************************************************
481  */
482 enum {
483     TX_ACK_TIME_OP_END,
484     TX_ACK_TIME_OP_PKT, /* TX packets */
485     TX_ACK_TIME_OP_ACK, /* Synthesise incoming ACK of single PN range */
486     TX_ACK_TIME_OP_EXPECT /* Ack/loss assertion */
487 };
488 
489 struct tx_ack_time_op {
490     int kind;
491     uint64_t time_advance; /* all ops */
492     QUIC_PN pn; /* PKT, ACK */
493     size_t num_pn; /* PKT, ACK */
494     const char *expect; /* 1=ack, 2=lost, 4=discarded */
495 };
496 
497 #define TX_OP_PKT(advance, pn, num_pn) \
498     { TX_ACK_TIME_OP_PKT, (advance) * OSSL_TIME_MS, (pn), (num_pn), NULL },
499 #define TX_OP_ACK(advance, pn, num_pn) \
500     { TX_ACK_TIME_OP_ACK, (advance) * OSSL_TIME_MS, (pn), (num_pn), NULL },
501 #define TX_OP_EXPECT(expect) \
502     { TX_ACK_TIME_OP_EXPECT, 0, 0, 0, (expect) },
503 #define TX_OP_END { TX_ACK_TIME_OP_END }
504 
505 static const char tx_ack_time_script_1_expect[] = {
506     2, 1
507 };
508 
509 static const struct tx_ack_time_op tx_ack_time_script_1[] = {
510     TX_OP_PKT(0, 0, 1)
511         TX_OP_PKT(3600000, 1, 1)
512             TX_OP_ACK(1000, 1, 1)
513                 TX_OP_EXPECT(tx_ack_time_script_1_expect)
514                     TX_OP_END
515 };
516 
517 static const struct tx_ack_time_op *const tx_ack_time_scripts[] = {
518     tx_ack_time_script_1,
519 };
520 
test_tx_ack_time_script(int tidx)521 static int test_tx_ack_time_script(int tidx)
522 {
523     int testresult = 0;
524     struct helper h;
525     OSSL_ACKM_TX_PKT *tx = NULL;
526     OSSL_QUIC_FRAME_ACK ack = { 0 };
527     OSSL_QUIC_ACK_RANGE ack_range = { 0 };
528     size_t i, num_pkts = 0, pkt_idx = 0;
529     const struct tx_ack_time_op *script = tx_ack_time_scripts[tidx], *s;
530 
531     /* Calculate number of packets. */
532     for (s = script; s->kind != TX_ACK_TIME_OP_END; ++s)
533         if (s->kind == TX_ACK_TIME_OP_PKT)
534             num_pkts += s->num_pn;
535 
536     /* Initialise ACK manager and packet structures. */
537     if (!TEST_int_eq(helper_init(&h, num_pkts), 1))
538         goto err;
539 
540     for (i = 0; i < num_pkts; ++i) {
541         h.pkts[i].pkt = tx = OPENSSL_zalloc(sizeof(*tx));
542         if (!TEST_ptr(tx))
543             goto err;
544     }
545 
546     /* Run script. */
547     for (s = script; s->kind != TX_ACK_TIME_OP_END; ++s)
548         switch (s->kind) {
549         case TX_ACK_TIME_OP_PKT:
550             for (i = 0; i < s->num_pn; ++i) {
551                 tx = h.pkts[pkt_idx + i].pkt;
552 
553                 tx->pkt_num = s->pn + i;
554                 tx->pkt_space = QUIC_PN_SPACE_INITIAL;
555                 tx->num_bytes = 123;
556                 tx->largest_acked = QUIC_PN_INVALID;
557                 tx->is_inflight = 1;
558                 tx->is_ack_eliciting = 1;
559                 tx->on_lost = on_lost;
560                 tx->on_acked = on_acked;
561                 tx->on_discarded = on_discarded;
562                 tx->cb_arg = &h.pkts[pkt_idx + i];
563 
564                 fake_time = ossl_time_add(fake_time,
565                     ossl_ticks2time(s->time_advance));
566                 tx->time = fake_time;
567 
568                 if (!TEST_int_eq(ossl_ackm_on_tx_packet(h.ackm, tx), 1))
569                     goto err;
570             }
571 
572             pkt_idx += s->num_pn;
573             break;
574 
575         case TX_ACK_TIME_OP_ACK:
576             ack.ack_ranges = &ack_range;
577             ack.num_ack_ranges = 1;
578 
579             ack_range.start = s->pn;
580             ack_range.end = s->pn + s->num_pn;
581 
582             fake_time = ossl_time_add(fake_time,
583                 ossl_ticks2time(s->time_advance));
584 
585             if (!TEST_int_eq(ossl_ackm_on_rx_ack_frame(h.ackm, &ack,
586                                  QUIC_PN_SPACE_INITIAL,
587                                  fake_time),
588                     1))
589                 goto err;
590 
591             break;
592 
593         case TX_ACK_TIME_OP_EXPECT:
594             for (i = 0; i < num_pkts; ++i) {
595                 if (!TEST_int_eq(h.pkts[i].acked,
596                         (s->expect[i] & 1) != 0 ? 1 : 0))
597                     goto err;
598                 if (!TEST_int_eq(h.pkts[i].lost,
599                         (s->expect[i] & 2) != 0 ? 1 : 0))
600                     goto err;
601                 if (!TEST_int_eq(h.pkts[i].discarded,
602                         (s->expect[i] & 4) != 0 ? 1 : 0))
603                     goto err;
604             }
605 
606             break;
607         }
608 
609     testresult = 1;
610 err:
611     helper_destroy(&h);
612     return testresult;
613 }
614 
615 /*
616  * RX ACK Test
617  * ******************************************************************
618  */
619 enum {
620     RX_OPK_END,
621     RX_OPK_PKT, /* RX packet */
622     RX_OPK_CHECK_UNPROC, /* check PNs unprocessable */
623     RX_OPK_CHECK_PROC, /* check PNs processable */
624     RX_OPK_CHECK_STATE, /* check is_desired/deadline */
625     RX_OPK_CHECK_ACKS, /* check ACK ranges */
626     RX_OPK_TX, /* TX packet */
627     RX_OPK_RX_ACK, /* RX ACK frame */
628     RX_OPK_SKIP_IF_PN_SPACE /* skip for a given PN space */
629 };
630 
631 struct rx_test_op {
632     int kind;
633     uint64_t time_advance;
634 
635     QUIC_PN pn; /* PKT, CHECK_(UN)PROC, TX, RX_ACK */
636     size_t num_pn; /* PKT, CHECK_(UN)PROC, TX, RX_ACK */
637 
638     char expect_desired; /* CHECK_STATE */
639     char expect_deadline; /* CHECK_STATE */
640 
641     const OSSL_QUIC_ACK_RANGE *ack_ranges; /* CHECK_ACKS */
642     size_t num_ack_ranges; /* CHECK_ACKS */
643 
644     QUIC_PN largest_acked; /* TX */
645 };
646 
647 #define RX_OP_PKT(advance, pn, num_pn)                        \
648     {                                                         \
649         RX_OPK_PKT, (advance) * OSSL_TIME_MS, (pn), (num_pn), \
650         0, 0, NULL, 0, 0                                      \
651     },
652 
653 #define RX_OP_CHECK_UNPROC(advance, pn, num_pn)                        \
654     {                                                                  \
655         RX_OPK_CHECK_UNPROC, (advance) * OSSL_TIME_MS, (pn), (num_pn), \
656         0, 0, NULL, 0, 0                                               \
657     },
658 
659 #define RX_OP_CHECK_PROC(advance, pn, num_pn)                        \
660     {                                                                \
661         RX_OPK_CHECK_PROC, (advance) * OSSL_TIME_MS, (pn), (num_pn), \
662         0, 0, NULL, 0, 0                                             \
663     },
664 
665 #define RX_OP_CHECK_STATE(advance, expect_desired, expect_deadline) \
666     {                                                               \
667         RX_OPK_CHECK_STATE, (advance) * OSSL_TIME_MS, 0, 0,         \
668         (expect_desired), (expect_deadline), NULL, 0, 0             \
669     },
670 
671 #define RX_OP_CHECK_ACKS(advance, ack_ranges)              \
672     {                                                      \
673         RX_OPK_CHECK_ACKS, (advance) * OSSL_TIME_MS, 0, 0, \
674         0, 0, (ack_ranges), OSSL_NELEM(ack_ranges), 0      \
675     },
676 
677 #define RX_OP_CHECK_NO_ACKS(advance)                       \
678     {                                                      \
679         RX_OPK_CHECK_ACKS, (advance) * OSSL_TIME_MS, 0, 0, \
680         0, 0, NULL, 0, 0                                   \
681     },
682 
683 #define RX_OP_TX(advance, pn, largest_acked)          \
684     {                                                 \
685         RX_OPK_TX, (advance) * OSSL_TIME_MS, (pn), 1, \
686         0, 0, NULL, 0, (largest_acked)                \
687     },
688 
689 #define RX_OP_RX_ACK(advance, pn, num_pn)                        \
690     {                                                            \
691         RX_OPK_RX_ACK, (advance) * OSSL_TIME_MS, (pn), (num_pn), \
692         0, 0, NULL, 0, 0                                         \
693     },
694 
695 #define RX_OP_SKIP_IF_PN_SPACE(pn_space)           \
696     {                                              \
697         RX_OPK_SKIP_IF_PN_SPACE, 0, (pn_space), 0, \
698         0, 0, NULL, 0, 0                           \
699     },
700 
701 #define RX_OP_END \
702     { RX_OPK_END }
703 
704 /* RX 1. Simple Test with ACK Desired (Packet Threshold, Exactly) */
705 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_1a[] = {
706     { 0, 1 }
707 };
708 
709 static const struct rx_test_op rx_script_1[] = {
710     RX_OP_CHECK_STATE(0, 0, 0) /* no threshold yet */
711     RX_OP_CHECK_PROC(0, 0, 3)
712 
713         RX_OP_PKT(0, 0, 2) /* two packets, threshold */
714     RX_OP_CHECK_UNPROC(0, 0, 2)
715         RX_OP_CHECK_PROC(0, 2, 1)
716             RX_OP_CHECK_STATE(0, 1, 0) /* threshold met, immediate */
717     RX_OP_CHECK_ACKS(0, rx_ack_ranges_1a)
718 
719     /* At this point we would generate e.g. a packet with an ACK. */
720     RX_OP_TX(0, 0, 1) /* ACKs both */
721     RX_OP_CHECK_ACKS(0, rx_ack_ranges_1a) /* not provably ACKed yet */
722     RX_OP_RX_ACK(0, 0, 1) /* TX'd packet is ACK'd */
723 
724     RX_OP_CHECK_NO_ACKS(0) /* nothing more to ACK */
725     RX_OP_CHECK_UNPROC(0, 0, 2) /* still unprocessable */
726     RX_OP_CHECK_PROC(0, 2, 1) /* still processable */
727 
728     RX_OP_END
729 };
730 
731 /* RX 2. Simple Test with ACK Not Yet Desired (Packet Threshold) (1-RTT) */
732 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_2a[] = {
733     { 0, 0 }
734 };
735 
736 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_2b[] = {
737     { 0, 2 }
738 };
739 
740 static const struct rx_test_op rx_script_2[] = {
741     /*
742      * We skip this for INITIAL/HANDSHAKE and use a separate version
743      * (rx_script_4) for those spaces as those spaces should not delay ACK
744      * generation, so a different RX_OP_CHECK_STATE test is needed.
745      */
746     RX_OP_SKIP_IF_PN_SPACE(QUIC_PN_SPACE_INITIAL)
747         RX_OP_SKIP_IF_PN_SPACE(QUIC_PN_SPACE_HANDSHAKE)
748 
749             RX_OP_CHECK_STATE(0, 0, 0) /* no threshold yet */
750     RX_OP_CHECK_PROC(0, 0, 3)
751 
752     /* First packet always generates an ACK so get it out of the way. */
753     RX_OP_PKT(0, 0, 1)
754         RX_OP_CHECK_UNPROC(0, 0, 1)
755             RX_OP_CHECK_PROC(0, 1, 1)
756                 RX_OP_CHECK_STATE(0, 1, 0) /* first packet always causes ACK */
757     RX_OP_CHECK_ACKS(0, rx_ack_ranges_2a) /* clears packet counter */
758     RX_OP_CHECK_STATE(0, 0, 0) /* desired state should have been cleared */
759 
760     /* Second packet should not cause ACK-desired state */
761     RX_OP_PKT(0, 1, 1) /* just one packet, threshold is 2 */
762     RX_OP_CHECK_UNPROC(0, 0, 2)
763         RX_OP_CHECK_PROC(0, 2, 1)
764             RX_OP_CHECK_STATE(0, 0, 1) /* threshold not yet met, so deadline */
765     /* Don't check ACKs here, as it would reset our threshold counter. */
766 
767     /* Now receive a second packet, triggering the threshold */
768     RX_OP_PKT(0, 2, 1) /* second packet meets threshold */
769     RX_OP_CHECK_UNPROC(0, 0, 3)
770         RX_OP_CHECK_PROC(0, 3, 1)
771             RX_OP_CHECK_STATE(0, 1, 0) /* desired immediately */
772     RX_OP_CHECK_ACKS(0, rx_ack_ranges_2b)
773 
774     /* At this point we would generate e.g. a packet with an ACK. */
775     RX_OP_TX(0, 0, 2) /* ACKs all */
776     RX_OP_CHECK_ACKS(0, rx_ack_ranges_2b) /* not provably ACKed yet */
777     RX_OP_RX_ACK(0, 0, 1) /* TX'd packet is ACK'd */
778 
779     RX_OP_CHECK_NO_ACKS(0) /* nothing more to ACK */
780     RX_OP_CHECK_UNPROC(0, 0, 3) /* still unprocessable */
781     RX_OP_CHECK_PROC(0, 3, 1) /* still processable */
782 
783     RX_OP_END
784 };
785 
786 /* RX 3. Simple Test with ACK Desired (Packet Threshold, Multiple Watermarks) */
787 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_3a[] = {
788     { 0, 0 }
789 };
790 
791 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_3b[] = {
792     { 0, 10 }
793 };
794 
795 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_3c[] = {
796     { 6, 10 }
797 };
798 
799 static const struct rx_test_op rx_script_3[] = {
800     RX_OP_CHECK_STATE(0, 0, 0) /* no threshold yet */
801     RX_OP_CHECK_PROC(0, 0, 11)
802 
803     /* First packet always generates an ACK so get it out of the way. */
804     RX_OP_PKT(0, 0, 1)
805         RX_OP_CHECK_UNPROC(0, 0, 1)
806             RX_OP_CHECK_PROC(0, 1, 1)
807                 RX_OP_CHECK_STATE(0, 1, 0) /* first packet always causes ACK */
808     RX_OP_CHECK_ACKS(0, rx_ack_ranges_3a) /* clears packet counter */
809     RX_OP_CHECK_STATE(0, 0, 0) /* desired state should have been cleared */
810 
811     /* Generate ten packets, exceeding the threshold. */
812     RX_OP_PKT(0, 1, 10) /* ten packets, threshold is 2 */
813     RX_OP_CHECK_UNPROC(0, 0, 11)
814         RX_OP_CHECK_PROC(0, 11, 1)
815             RX_OP_CHECK_STATE(0, 1, 0) /* threshold met, immediate */
816     RX_OP_CHECK_ACKS(0, rx_ack_ranges_3b)
817 
818     /*
819      * Test TX'ing a packet which doesn't ACK anything.
820      */
821     RX_OP_TX(0, 0, QUIC_PN_INVALID)
822         RX_OP_RX_ACK(0, 0, 1)
823 
824     /*
825      * At this point we would generate a packet with an ACK immediately.
826      * TX a packet which when ACKed makes [0,5] provably ACKed.
827      */
828     RX_OP_TX(0, 1, 5)
829         RX_OP_CHECK_ACKS(0, rx_ack_ranges_3b) /* not provably ACKed yet */
830     RX_OP_RX_ACK(0, 1, 1)
831 
832         RX_OP_CHECK_ACKS(0, rx_ack_ranges_3c) /* provably ACKed now gone */
833     RX_OP_CHECK_UNPROC(0, 0, 11) /* still unprocessable */
834     RX_OP_CHECK_PROC(0, 11, 1) /* still processable */
835 
836     /*
837      * Now TX another packet which provably ACKs the rest when ACKed.
838      */
839     RX_OP_TX(0, 2, 10)
840         RX_OP_CHECK_ACKS(0, rx_ack_ranges_3c) /* not provably ACKed yet */
841     RX_OP_RX_ACK(0, 2, 1)
842 
843         RX_OP_CHECK_NO_ACKS(0) /* provably ACKed now gone */
844     RX_OP_CHECK_UNPROC(0, 0, 11) /* still unprocessable */
845     RX_OP_CHECK_PROC(0, 11, 1) /* still processable */
846 
847     RX_OP_END
848 };
849 
850 /*
851  * RX 4. Simple Test with ACK Not Yet Desired (Packet Threshold)
852  * (Initial/Handshake)
853  */
854 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_4a[] = {
855     { 0, 1 }
856 };
857 
858 static const struct rx_test_op rx_script_4[] = {
859     /* The application PN space is tested in rx_script_2. */
860     RX_OP_SKIP_IF_PN_SPACE(QUIC_PN_SPACE_APP)
861 
862         RX_OP_CHECK_STATE(0, 0, 0) /* no threshold yet */
863     RX_OP_CHECK_PROC(0, 0, 3)
864 
865     /* First packet always generates an ACK so get it out of the way. */
866     RX_OP_PKT(0, 0, 1)
867         RX_OP_CHECK_UNPROC(0, 0, 1)
868             RX_OP_CHECK_PROC(0, 1, 1)
869                 RX_OP_CHECK_STATE(0, 1, 0) /* first packet always causes ACK */
870     RX_OP_CHECK_ACKS(0, rx_ack_ranges_2a) /* clears packet counter */
871     RX_OP_CHECK_STATE(0, 0, 0) /* desired state should have been cleared */
872 
873     /*
874      * Second packet should cause ACK-desired state because we are
875      * INITIAL/HANDSHAKE (RFC 9000 s. 13.2.1)
876      */
877     RX_OP_PKT(0, 1, 1) /* just one packet, threshold is 2 */
878     RX_OP_CHECK_UNPROC(0, 0, 2)
879         RX_OP_CHECK_PROC(0, 2, 1)
880             RX_OP_CHECK_STATE(0, 1, 1)
881                 RX_OP_CHECK_ACKS(0, rx_ack_ranges_4a)
882                     RX_OP_CHECK_STATE(0, 0, 0) /* desired state should have been cleared */
883 
884     /* At this point we would generate e.g. a packet with an ACK. */
885     RX_OP_TX(0, 0, 1) /* ACKs all */
886     RX_OP_CHECK_ACKS(0, rx_ack_ranges_4a) /* not provably ACKed yet */
887     RX_OP_RX_ACK(0, 0, 1) /* TX'd packet is ACK'd */
888 
889     RX_OP_CHECK_NO_ACKS(0) /* nothing more to ACK */
890     RX_OP_CHECK_UNPROC(0, 0, 2) /* still unprocessable */
891     RX_OP_CHECK_PROC(0, 2, 1) /* still processable */
892 
893     RX_OP_END
894 };
895 
896 static const struct rx_test_op *const rx_test_scripts[] = {
897     rx_script_1,
898     rx_script_2,
899     rx_script_3,
900     rx_script_4
901 };
902 
on_ack_deadline_callback(OSSL_TIME deadline,int pkt_space,void * arg)903 static void on_ack_deadline_callback(OSSL_TIME deadline,
904     int pkt_space, void *arg)
905 {
906     ((OSSL_TIME *)arg)[pkt_space] = deadline;
907 }
908 
test_rx_ack_actual(int tidx,int space)909 static int test_rx_ack_actual(int tidx, int space)
910 {
911     int testresult = 0;
912     struct helper h;
913     const struct rx_test_op *script = rx_test_scripts[tidx], *s;
914     size_t i, num_tx = 0, txi = 0;
915     const OSSL_QUIC_FRAME_ACK *ack;
916     OSSL_QUIC_FRAME_ACK rx_ack = { 0 };
917     OSSL_QUIC_ACK_RANGE rx_ack_range = { 0 };
918     struct pkt_info *pkts = NULL;
919     OSSL_ACKM_TX_PKT *txs = NULL, *tx;
920     OSSL_TIME ack_deadline[QUIC_PN_SPACE_NUM];
921     size_t opn = 0;
922 
923     for (i = 0; i < QUIC_PN_SPACE_NUM; ++i)
924         ack_deadline[i] = ossl_time_infinite();
925 
926     /* Initialise ACK manager. */
927     if (!TEST_int_eq(helper_init(&h, 0), 1))
928         goto err;
929 
930     /* Arm callback for testing. */
931     ossl_ackm_set_ack_deadline_callback(h.ackm, on_ack_deadline_callback,
932         ack_deadline);
933 
934     /*
935      * Determine how many packets we are TXing, and therefore how many packet
936      * structures we need.
937      */
938     for (s = script; s->kind != RX_OPK_END; ++s)
939         if (s->kind == RX_OPK_TX)
940             num_tx += s->num_pn;
941 
942     /* Allocate packet information structures. */
943     txs = OPENSSL_zalloc(sizeof(*txs) * num_tx);
944     if (!TEST_ptr(txs))
945         goto err;
946 
947     pkts = OPENSSL_zalloc(sizeof(*pkts) * num_tx);
948     if (!TEST_ptr(pkts))
949         goto err;
950 
951     /* Run script. */
952     for (s = script; s->kind != RX_OPK_END; ++s, ++opn) {
953         fake_time = ossl_time_add(fake_time,
954             ossl_ticks2time(s->time_advance));
955         switch (s->kind) {
956         case RX_OPK_PKT:
957             for (i = 0; i < s->num_pn; ++i) {
958                 OSSL_ACKM_RX_PKT pkt = { 0 };
959 
960                 pkt.pkt_num = s->pn + i;
961                 pkt.time = fake_time;
962                 pkt.pkt_space = space;
963                 pkt.is_ack_eliciting = 1;
964 
965                 /* The packet should be processable before we feed it. */
966                 if (!TEST_int_eq(ossl_ackm_is_rx_pn_processable(h.ackm,
967                                      pkt.pkt_num,
968                                      pkt.pkt_space),
969                         1))
970                     goto err;
971 
972                 if (!TEST_int_eq(ossl_ackm_on_rx_packet(h.ackm, &pkt), 1))
973                     goto err;
974             }
975 
976             break;
977 
978         case RX_OPK_CHECK_UNPROC:
979         case RX_OPK_CHECK_PROC:
980             for (i = 0; i < s->num_pn; ++i)
981                 if (!TEST_int_eq(ossl_ackm_is_rx_pn_processable(h.ackm,
982                                      s->pn + i, space),
983                         (s->kind == RX_OPK_CHECK_PROC)))
984                     goto err;
985 
986             break;
987 
988         case RX_OPK_CHECK_STATE:
989             if (!TEST_int_eq(ossl_ackm_is_ack_desired(h.ackm, space),
990                     s->expect_desired))
991                 goto err;
992 
993             if (!TEST_int_eq(!ossl_time_is_infinite(ossl_ackm_get_ack_deadline(h.ackm, space))
994                         && !ossl_time_is_zero(ossl_ackm_get_ack_deadline(h.ackm, space)),
995                     s->expect_deadline))
996                 goto err;
997 
998             for (i = 0; i < QUIC_PN_SPACE_NUM; ++i) {
999                 if (i != (size_t)space
1000                     && !TEST_true(ossl_time_is_infinite(ossl_ackm_get_ack_deadline(h.ackm, i))))
1001                     goto err;
1002 
1003                 if (!TEST_int_eq(ossl_time_compare(ossl_ackm_get_ack_deadline(h.ackm, i),
1004                                      ack_deadline[i]),
1005                         0))
1006                     goto err;
1007             }
1008 
1009             break;
1010 
1011         case RX_OPK_CHECK_ACKS:
1012             ack = ossl_ackm_get_ack_frame(h.ackm, space);
1013 
1014             /* Should always be able to get an ACK frame. */
1015             if (!TEST_ptr(ack))
1016                 goto err;
1017 
1018             if (!TEST_size_t_eq(ack->num_ack_ranges, s->num_ack_ranges))
1019                 goto err;
1020 
1021             for (i = 0; i < ack->num_ack_ranges; ++i) {
1022                 if (!TEST_uint64_t_eq(ack->ack_ranges[i].start,
1023                         s->ack_ranges[i].start))
1024                     goto err;
1025                 if (!TEST_uint64_t_eq(ack->ack_ranges[i].end,
1026                         s->ack_ranges[i].end))
1027                     goto err;
1028             }
1029 
1030             break;
1031 
1032         case RX_OPK_TX:
1033             pkts[txi].pkt = tx = &txs[txi];
1034 
1035             tx->pkt_num = s->pn;
1036             tx->pkt_space = space;
1037             tx->num_bytes = 123;
1038             tx->largest_acked = s->largest_acked;
1039             tx->is_inflight = 1;
1040             tx->is_ack_eliciting = 1;
1041             tx->on_lost = on_lost;
1042             tx->on_acked = on_acked;
1043             tx->on_discarded = on_discarded;
1044             tx->cb_arg = &pkts[txi];
1045             tx->time = fake_time;
1046 
1047             if (!TEST_int_eq(ossl_ackm_on_tx_packet(h.ackm, tx), 1))
1048                 goto err;
1049 
1050             ++txi;
1051             break;
1052 
1053         case RX_OPK_RX_ACK:
1054             rx_ack.ack_ranges = &rx_ack_range;
1055             rx_ack.num_ack_ranges = 1;
1056 
1057             rx_ack_range.start = s->pn;
1058             rx_ack_range.end = s->pn + s->num_pn - 1;
1059 
1060             if (!TEST_int_eq(ossl_ackm_on_rx_ack_frame(h.ackm, &rx_ack,
1061                                  space, fake_time),
1062                     1))
1063                 goto err;
1064 
1065             break;
1066 
1067         case RX_OPK_SKIP_IF_PN_SPACE:
1068             if (space == (int)s->pn) {
1069                 testresult = 1;
1070                 goto err;
1071             }
1072 
1073             break;
1074 
1075         default:
1076             goto err;
1077         }
1078     }
1079 
1080     testresult = 1;
1081 err:
1082     if (!testresult)
1083         TEST_error("error in ACKM RX script %d, op %zu", tidx + 1, opn + 1);
1084 
1085     helper_destroy(&h);
1086     OPENSSL_free(pkts);
1087     OPENSSL_free(txs);
1088     return testresult;
1089 }
1090 
1091 /*
1092  * Driver
1093  * ******************************************************************
1094  */
test_tx_ack_case(int idx)1095 static int test_tx_ack_case(int idx)
1096 {
1097     int tidx, space;
1098 
1099     tidx = idx % OSSL_NELEM(tx_ack_cases);
1100     idx /= OSSL_NELEM(tx_ack_cases);
1101 
1102     space = idx % QUIC_PN_SPACE_NUM;
1103     idx /= QUIC_PN_SPACE_NUM;
1104 
1105     return test_tx_ack_case_actual(tidx, space, idx);
1106 }
1107 
test_rx_ack(int idx)1108 static int test_rx_ack(int idx)
1109 {
1110     int tidx;
1111 
1112     tidx = idx % OSSL_NELEM(rx_test_scripts);
1113     idx /= OSSL_NELEM(rx_test_scripts);
1114 
1115     return test_rx_ack_actual(tidx, idx);
1116 }
1117 
setup_tests(void)1118 int setup_tests(void)
1119 {
1120     ADD_ALL_TESTS(test_tx_ack_case,
1121         OSSL_NELEM(tx_ack_cases) * MODE_NUM * QUIC_PN_SPACE_NUM);
1122     ADD_ALL_TESTS(test_tx_ack_time_script, OSSL_NELEM(tx_ack_time_scripts));
1123     ADD_ALL_TESTS(test_rx_ack, OSSL_NELEM(rx_test_scripts) * QUIC_PN_SPACE_NUM);
1124     return 1;
1125 }
1126