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