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