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