1 /*
2 * Copyright 2022-2023 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_calloc(num_pkts, sizeof(struct pkt_info));
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, MODE_DISCARD, MODE_PTO, MODE_NUM
310 };
311
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)312 static int test_probe_counts(const OSSL_ACKM_PROBE_INFO *p,
313 uint32_t anti_deadlock_handshake,
314 uint32_t anti_deadlock_initial,
315 uint32_t pto_initial,
316 uint32_t pto_handshake,
317 uint32_t pto_app)
318 {
319 if (!TEST_uint_eq(p->anti_deadlock_handshake, anti_deadlock_handshake))
320 return 0;
321 if (!TEST_uint_eq(p->anti_deadlock_initial, anti_deadlock_initial))
322 return 0;
323 if (!TEST_uint_eq(p->pto[QUIC_PN_SPACE_INITIAL], pto_initial))
324 return 0;
325 if (!TEST_uint_eq(p->pto[QUIC_PN_SPACE_HANDSHAKE], pto_handshake))
326 return 0;
327 if (!TEST_uint_eq(p->pto[QUIC_PN_SPACE_APP], pto_app))
328 return 0;
329 return 1;
330 }
331
on_loss_detection_deadline_callback(OSSL_TIME deadline,void * arg)332 static void on_loss_detection_deadline_callback(OSSL_TIME deadline, void *arg)
333 {
334 *(OSSL_TIME *)arg = deadline;
335 }
336
test_tx_ack_case_actual(int tidx,int space,int mode)337 static int test_tx_ack_case_actual(int tidx, int space, int mode)
338 {
339 int testresult = 0;
340 struct helper h;
341 size_t i;
342 OSSL_ACKM_TX_PKT *tx;
343 const struct tx_ack_test_case *c = tx_ack_cases[tidx];
344 OSSL_QUIC_FRAME_ACK ack = {0};
345 OSSL_TIME loss_detection_deadline = ossl_time_zero();
346
347 /* Cannot discard app space, so skip this */
348 if (mode == MODE_DISCARD && space == QUIC_PN_SPACE_APP) {
349 TEST_skip("skipping test for app space");
350 return 1;
351 }
352
353 if (!TEST_int_eq(helper_init(&h, c->pn_table_len), 1))
354 goto err;
355
356 /* Arm callback. */
357 ossl_ackm_set_loss_detection_deadline_callback(h.ackm,
358 on_loss_detection_deadline_callback,
359 &loss_detection_deadline);
360
361 /* Allocate TX packet structures. */
362 for (i = 0; i < c->pn_table_len; ++i) {
363 h.pkts[i].pkt = tx = OPENSSL_zalloc(sizeof(*tx));
364 if (!TEST_ptr(tx))
365 goto err;
366
367 tx->pkt_num = c->pn_table[i];
368 tx->pkt_space = space;
369 tx->is_inflight = 1;
370 tx->is_ack_eliciting = 1;
371 tx->num_bytes = 123;
372 tx->largest_acked = QUIC_PN_INVALID;
373 tx->on_lost = on_lost;
374 tx->on_acked = on_acked;
375 tx->on_discarded = on_discarded;
376 tx->cb_arg = &h.pkts[i];
377
378 tx->time = fake_time;
379
380 if (!TEST_int_eq(ossl_ackm_on_tx_packet(h.ackm, tx), 1))
381 goto err;
382 }
383
384 if (mode == MODE_DISCARD) {
385 /* Try discarding. */
386 if (!TEST_int_eq(ossl_ackm_on_pkt_space_discarded(h.ackm, space), 1))
387 goto err;
388
389 /* Check all discard callbacks were called. */
390 for (i = 0; i < c->pn_table_len; ++i) {
391 if (!TEST_int_eq(h.pkts[i].acked, 0))
392 goto err;
393 if (!TEST_int_eq(h.pkts[i].lost, 0))
394 goto err;
395 if (!TEST_int_eq(h.pkts[i].discarded, 1))
396 goto err;
397 }
398 } else if (mode == MODE_ACK) {
399 /* Try acknowledging. */
400 ack.ack_ranges = (OSSL_QUIC_ACK_RANGE *)c->ack_ranges;
401 ack.num_ack_ranges = c->num_ack_ranges;
402 if (!TEST_int_eq(ossl_ackm_on_rx_ack_frame(h.ackm, &ack, space, fake_time), 1))
403 goto err;
404
405 /* Check correct ranges were acknowledged. */
406 for (i = 0; i < c->pn_table_len; ++i) {
407 if (!TEST_int_eq(h.pkts[i].acked,
408 (c->expect_ack[i] & 1) != 0 ? 1 : 0))
409 goto err;
410 if (!TEST_int_eq(h.pkts[i].lost,
411 (c->expect_ack[i] & 2) != 0 ? 1 : 0))
412 goto err;
413 if (!TEST_int_eq(h.pkts[i].discarded,
414 (c->expect_ack[i] & 4) != 0 ? 1 : 0))
415 goto err;
416 }
417 } else if (mode == MODE_PTO) {
418 OSSL_TIME deadline = ossl_ackm_get_loss_detection_deadline(h.ackm);
419 OSSL_ACKM_PROBE_INFO probe;
420
421 if (!TEST_int_eq(ossl_time_compare(deadline, loss_detection_deadline), 0))
422 goto err;
423
424 /* We should have a PTO deadline. */
425 if (!TEST_int_gt(ossl_time_compare(deadline, fake_time), 0))
426 goto err;
427
428 /* Should not have any probe requests yet. */
429 probe = *ossl_ackm_get0_probe_request(h.ackm);
430 if (!TEST_int_eq(test_probe_counts(&probe, 0, 0, 0, 0, 0), 1))
431 goto err;
432
433 /*
434 * If in app space, confirm handshake, as this is necessary to enable
435 * app space PTO probe requests.
436 */
437 if (space == QUIC_PN_SPACE_APP)
438 if (!TEST_int_eq(ossl_ackm_on_handshake_confirmed(h.ackm), 1))
439 goto err;
440
441 /* Advance to the PTO deadline. */
442 fake_time = ossl_time_add(deadline, ossl_ticks2time(1));
443
444 if (!TEST_int_eq(ossl_ackm_on_timeout(h.ackm), 1))
445 goto err;
446
447 /* Should have a probe request. Not cleared by first call. */
448 for (i = 0; i < 3; ++i) {
449 probe = *ossl_ackm_get0_probe_request(h.ackm);
450 if (i > 0)
451 memset(ossl_ackm_get0_probe_request(h.ackm), 0, sizeof(probe));
452
453 if (i == 2) {
454 if (!TEST_int_eq(test_probe_counts(&probe, 0, 0, 0, 0, 0), 1))
455 goto err;
456 } else {
457 if (!TEST_int_eq(test_probe_counts(&probe, 0, 0,
458 space == QUIC_PN_SPACE_INITIAL,
459 space == QUIC_PN_SPACE_HANDSHAKE,
460 space == QUIC_PN_SPACE_APP), 1))
461 goto err;
462 }
463 }
464
465 } else
466 goto err;
467
468 testresult = 1;
469 err:
470 helper_destroy(&h);
471 return testresult;
472 }
473
474 /*
475 * TX ACK (Time Threshold) Test
476 * ******************************************************************
477 */
478 enum {
479 TX_ACK_TIME_OP_END,
480 TX_ACK_TIME_OP_PKT, /* TX packets */
481 TX_ACK_TIME_OP_ACK, /* Synthesise incoming ACK of single PN range */
482 TX_ACK_TIME_OP_EXPECT /* Ack/loss assertion */
483 };
484
485 struct tx_ack_time_op {
486 int kind;
487 uint64_t time_advance; /* all ops */
488 QUIC_PN pn; /* PKT, ACK */
489 size_t num_pn; /* PKT, ACK */
490 const char *expect; /* 1=ack, 2=lost, 4=discarded */
491 };
492
493 #define TX_OP_PKT(advance, pn, num_pn) \
494 { TX_ACK_TIME_OP_PKT, (advance) * OSSL_TIME_MS, (pn), (num_pn), NULL },
495 #define TX_OP_ACK(advance, pn, num_pn) \
496 { TX_ACK_TIME_OP_ACK, (advance) * OSSL_TIME_MS, (pn), (num_pn), NULL },
497 #define TX_OP_EXPECT(expect) \
498 { TX_ACK_TIME_OP_EXPECT, 0, 0, 0, (expect) },
499 #define TX_OP_END { TX_ACK_TIME_OP_END }
500
501 static const char tx_ack_time_script_1_expect[] = {
502 2, 1
503 };
504
505 static const struct tx_ack_time_op tx_ack_time_script_1[] = {
506 TX_OP_PKT ( 0, 0, 1)
507 TX_OP_PKT (3600000, 1, 1)
508 TX_OP_ACK ( 1000, 1, 1)
509 TX_OP_EXPECT(tx_ack_time_script_1_expect)
510 TX_OP_END
511 };
512
513 static const struct tx_ack_time_op *const tx_ack_time_scripts[] = {
514 tx_ack_time_script_1,
515 };
516
test_tx_ack_time_script(int tidx)517 static int test_tx_ack_time_script(int tidx)
518 {
519 int testresult = 0;
520 struct helper h;
521 OSSL_ACKM_TX_PKT *tx = NULL;
522 OSSL_QUIC_FRAME_ACK ack = {0};
523 OSSL_QUIC_ACK_RANGE ack_range = {0};
524 size_t i, num_pkts = 0, pkt_idx = 0;
525 const struct tx_ack_time_op *script = tx_ack_time_scripts[tidx], *s;
526
527 /* Calculate number of packets. */
528 for (s = script; s->kind != TX_ACK_TIME_OP_END; ++s)
529 if (s->kind == TX_ACK_TIME_OP_PKT)
530 num_pkts += s->num_pn;
531
532 /* Initialise ACK manager and packet structures. */
533 if (!TEST_int_eq(helper_init(&h, num_pkts), 1))
534 goto err;
535
536 for (i = 0; i < num_pkts; ++i) {
537 h.pkts[i].pkt = tx = OPENSSL_zalloc(sizeof(*tx));
538 if (!TEST_ptr(tx))
539 goto err;
540 }
541
542 /* Run script. */
543 for (s = script; s->kind != TX_ACK_TIME_OP_END; ++s)
544 switch (s->kind) {
545 case TX_ACK_TIME_OP_PKT:
546 for (i = 0; i < s->num_pn; ++i) {
547 tx = h.pkts[pkt_idx + i].pkt;
548
549 tx->pkt_num = s->pn + i;
550 tx->pkt_space = QUIC_PN_SPACE_INITIAL;
551 tx->num_bytes = 123;
552 tx->largest_acked = QUIC_PN_INVALID;
553 tx->is_inflight = 1;
554 tx->is_ack_eliciting = 1;
555 tx->on_lost = on_lost;
556 tx->on_acked = on_acked;
557 tx->on_discarded = on_discarded;
558 tx->cb_arg = &h.pkts[pkt_idx + i];
559
560 fake_time = ossl_time_add(fake_time,
561 ossl_ticks2time(s->time_advance));
562 tx->time = fake_time;
563
564 if (!TEST_int_eq(ossl_ackm_on_tx_packet(h.ackm, tx), 1))
565 goto err;
566 }
567
568 pkt_idx += s->num_pn;
569 break;
570
571 case TX_ACK_TIME_OP_ACK:
572 ack.ack_ranges = &ack_range;
573 ack.num_ack_ranges = 1;
574
575 ack_range.start = s->pn;
576 ack_range.end = s->pn + s->num_pn;
577
578 fake_time = ossl_time_add(fake_time,
579 ossl_ticks2time(s->time_advance));
580
581 if (!TEST_int_eq(ossl_ackm_on_rx_ack_frame(h.ackm, &ack,
582 QUIC_PN_SPACE_INITIAL,
583 fake_time), 1))
584 goto err;
585
586 break;
587
588 case TX_ACK_TIME_OP_EXPECT:
589 for (i = 0; i < num_pkts; ++i) {
590 if (!TEST_int_eq(h.pkts[i].acked,
591 (s->expect[i] & 1) != 0 ? 1 : 0))
592 goto err;
593 if (!TEST_int_eq(h.pkts[i].lost,
594 (s->expect[i] & 2) != 0 ? 1 : 0))
595 goto err;
596 if (!TEST_int_eq(h.pkts[i].discarded,
597 (s->expect[i] & 4) != 0 ? 1 : 0))
598 goto err;
599 }
600
601 break;
602 }
603
604 testresult = 1;
605 err:
606 helper_destroy(&h);
607 return testresult;
608 }
609
610 /*
611 * RX ACK Test
612 * ******************************************************************
613 */
614 enum {
615 RX_OPK_END,
616 RX_OPK_PKT, /* RX packet */
617 RX_OPK_CHECK_UNPROC, /* check PNs unprocessable */
618 RX_OPK_CHECK_PROC, /* check PNs processable */
619 RX_OPK_CHECK_STATE, /* check is_desired/deadline */
620 RX_OPK_CHECK_ACKS, /* check ACK ranges */
621 RX_OPK_TX, /* TX packet */
622 RX_OPK_RX_ACK, /* RX ACK frame */
623 RX_OPK_SKIP_IF_PN_SPACE /* skip for a given PN space */
624 };
625
626 struct rx_test_op {
627 int kind;
628 uint64_t time_advance;
629
630 QUIC_PN pn; /* PKT, CHECK_(UN)PROC, TX, RX_ACK */
631 size_t num_pn; /* PKT, CHECK_(UN)PROC, TX, RX_ACK */
632
633 char expect_desired; /* CHECK_STATE */
634 char expect_deadline; /* CHECK_STATE */
635
636 const OSSL_QUIC_ACK_RANGE *ack_ranges; /* CHECK_ACKS */
637 size_t num_ack_ranges; /* CHECK_ACKS */
638
639 QUIC_PN largest_acked; /* TX */
640 };
641
642 #define RX_OP_PKT(advance, pn, num_pn) \
643 { \
644 RX_OPK_PKT, (advance) * OSSL_TIME_MS, (pn), (num_pn), \
645 0, 0, NULL, 0, 0 \
646 },
647
648 #define RX_OP_CHECK_UNPROC(advance, pn, num_pn) \
649 { \
650 RX_OPK_CHECK_UNPROC, (advance) * OSSL_TIME_MS, (pn), (num_pn),\
651 0, 0, NULL, 0, 0 \
652 },
653
654 #define RX_OP_CHECK_PROC(advance, pn, num_pn) \
655 { \
656 RX_OPK_CHECK_PROC, (advance) * OSSL_TIME_MS, (pn), (num_pn), \
657 0, 0, NULL, 0, 0 \
658 },
659
660 #define RX_OP_CHECK_STATE(advance, expect_desired, expect_deadline) \
661 { \
662 RX_OPK_CHECK_STATE, (advance) * OSSL_TIME_MS, 0, 0, \
663 (expect_desired), (expect_deadline), NULL, 0, 0 \
664 },
665
666 #define RX_OP_CHECK_ACKS(advance, ack_ranges) \
667 { \
668 RX_OPK_CHECK_ACKS, (advance) * OSSL_TIME_MS, 0, 0, \
669 0, 0, (ack_ranges), OSSL_NELEM(ack_ranges), 0 \
670 },
671
672 #define RX_OP_CHECK_NO_ACKS(advance) \
673 { \
674 RX_OPK_CHECK_ACKS, (advance) * OSSL_TIME_MS, 0, 0, \
675 0, 0, NULL, 0, 0 \
676 },
677
678 #define RX_OP_TX(advance, pn, largest_acked) \
679 { \
680 RX_OPK_TX, (advance) * OSSL_TIME_MS, (pn), 1, \
681 0, 0, NULL, 0, (largest_acked) \
682 },
683
684 #define RX_OP_RX_ACK(advance, pn, num_pn) \
685 { \
686 RX_OPK_RX_ACK, (advance) * OSSL_TIME_MS, (pn), (num_pn), \
687 0, 0, NULL, 0, 0 \
688 },
689
690 #define RX_OP_SKIP_IF_PN_SPACE(pn_space) \
691 { \
692 RX_OPK_SKIP_IF_PN_SPACE, 0, (pn_space), 0, \
693 0, 0, NULL, 0, 0 \
694 },
695
696 #define RX_OP_END \
697 { RX_OPK_END }
698
699 /* RX 1. Simple Test with ACK Desired (Packet Threshold, Exactly) */
700 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_1a[] = {
701 { 0, 1 }
702 };
703
704 static const struct rx_test_op rx_script_1[] = {
705 RX_OP_CHECK_STATE (0, 0, 0) /* no threshold yet */
706 RX_OP_CHECK_PROC (0, 0, 3)
707
708 RX_OP_PKT (0, 0, 2) /* two packets, threshold */
709 RX_OP_CHECK_UNPROC (0, 0, 2)
710 RX_OP_CHECK_PROC (0, 2, 1)
711 RX_OP_CHECK_STATE (0, 1, 0) /* threshold met, immediate */
712 RX_OP_CHECK_ACKS (0, rx_ack_ranges_1a)
713
714 /* At this point we would generate e.g. a packet with an ACK. */
715 RX_OP_TX (0, 0, 1) /* ACKs both */
716 RX_OP_CHECK_ACKS (0, rx_ack_ranges_1a) /* not provably ACKed yet */
717 RX_OP_RX_ACK (0, 0, 1) /* TX'd packet is ACK'd */
718
719 RX_OP_CHECK_NO_ACKS (0) /* nothing more to ACK */
720 RX_OP_CHECK_UNPROC (0, 0, 2) /* still unprocessable */
721 RX_OP_CHECK_PROC (0, 2, 1) /* still processable */
722
723 RX_OP_END
724 };
725
726 /* RX 2. Simple Test with ACK Not Yet Desired (Packet Threshold) (1-RTT) */
727 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_2a[] = {
728 { 0, 0 }
729 };
730
731 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_2b[] = {
732 { 0, 2 }
733 };
734
735 static const struct rx_test_op rx_script_2[] = {
736 /*
737 * We skip this for INITIAL/HANDSHAKE and use a separate version
738 * (rx_script_4) for those spaces as those spaces should not delay ACK
739 * generation, so a different RX_OP_CHECK_STATE test is needed.
740 */
741 RX_OP_SKIP_IF_PN_SPACE(QUIC_PN_SPACE_INITIAL)
742 RX_OP_SKIP_IF_PN_SPACE(QUIC_PN_SPACE_HANDSHAKE)
743
744 RX_OP_CHECK_STATE (0, 0, 0) /* no threshold yet */
745 RX_OP_CHECK_PROC (0, 0, 3)
746
747 /* First packet always generates an ACK so get it out of the way. */
748 RX_OP_PKT (0, 0, 1)
749 RX_OP_CHECK_UNPROC (0, 0, 1)
750 RX_OP_CHECK_PROC (0, 1, 1)
751 RX_OP_CHECK_STATE (0, 1, 0) /* first packet always causes ACK */
752 RX_OP_CHECK_ACKS (0, rx_ack_ranges_2a) /* clears packet counter */
753 RX_OP_CHECK_STATE (0, 0, 0) /* desired state should have been cleared */
754
755 /* Second packet should not cause ACK-desired state */
756 RX_OP_PKT (0, 1, 1) /* just one packet, threshold is 2 */
757 RX_OP_CHECK_UNPROC (0, 0, 2)
758 RX_OP_CHECK_PROC (0, 2, 1)
759 RX_OP_CHECK_STATE (0, 0, 1) /* threshold not yet met, so deadline */
760 /* Don't check ACKs here, as it would reset our threshold counter. */
761
762 /* Now receive a second packet, triggering the threshold */
763 RX_OP_PKT (0, 2, 1) /* second packet meets threshold */
764 RX_OP_CHECK_UNPROC (0, 0, 3)
765 RX_OP_CHECK_PROC (0, 3, 1)
766 RX_OP_CHECK_STATE (0, 1, 0) /* desired immediately */
767 RX_OP_CHECK_ACKS (0, rx_ack_ranges_2b)
768
769 /* At this point we would generate e.g. a packet with an ACK. */
770 RX_OP_TX (0, 0, 2) /* ACKs all */
771 RX_OP_CHECK_ACKS (0, rx_ack_ranges_2b) /* not provably ACKed yet */
772 RX_OP_RX_ACK (0, 0, 1) /* TX'd packet is ACK'd */
773
774 RX_OP_CHECK_NO_ACKS (0) /* nothing more to ACK */
775 RX_OP_CHECK_UNPROC (0, 0, 3) /* still unprocessable */
776 RX_OP_CHECK_PROC (0, 3, 1) /* still processable */
777
778 RX_OP_END
779 };
780
781 /* RX 3. Simple Test with ACK Desired (Packet Threshold, Multiple Watermarks) */
782 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_3a[] = {
783 { 0, 0 }
784 };
785
786 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_3b[] = {
787 { 0, 10 }
788 };
789
790 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_3c[] = {
791 { 6, 10 }
792 };
793
794 static const struct rx_test_op rx_script_3[] = {
795 RX_OP_CHECK_STATE (0, 0, 0) /* no threshold yet */
796 RX_OP_CHECK_PROC (0, 0, 11)
797
798 /* First packet always generates an ACK so get it out of the way. */
799 RX_OP_PKT (0, 0, 1)
800 RX_OP_CHECK_UNPROC (0, 0, 1)
801 RX_OP_CHECK_PROC (0, 1, 1)
802 RX_OP_CHECK_STATE (0, 1, 0) /* first packet always causes ACK */
803 RX_OP_CHECK_ACKS (0, rx_ack_ranges_3a) /* clears packet counter */
804 RX_OP_CHECK_STATE (0, 0, 0) /* desired state should have been cleared */
805
806 /* Generate ten packets, exceeding the threshold. */
807 RX_OP_PKT (0, 1, 10) /* ten packets, threshold is 2 */
808 RX_OP_CHECK_UNPROC (0, 0, 11)
809 RX_OP_CHECK_PROC (0, 11, 1)
810 RX_OP_CHECK_STATE (0, 1, 0) /* threshold met, immediate */
811 RX_OP_CHECK_ACKS (0, rx_ack_ranges_3b)
812
813 /*
814 * Test TX'ing a packet which doesn't ACK anything.
815 */
816 RX_OP_TX (0, 0, QUIC_PN_INVALID)
817 RX_OP_RX_ACK (0, 0, 1)
818
819 /*
820 * At this point we would generate a packet with an ACK immediately.
821 * TX a packet which when ACKed makes [0,5] provably ACKed.
822 */
823 RX_OP_TX (0, 1, 5)
824 RX_OP_CHECK_ACKS (0, rx_ack_ranges_3b) /* not provably ACKed yet */
825 RX_OP_RX_ACK (0, 1, 1)
826
827 RX_OP_CHECK_ACKS (0, rx_ack_ranges_3c) /* provably ACKed now gone */
828 RX_OP_CHECK_UNPROC (0, 0, 11) /* still unprocessable */
829 RX_OP_CHECK_PROC (0, 11, 1) /* still processable */
830
831 /*
832 * Now TX another packet which provably ACKs the rest when ACKed.
833 */
834 RX_OP_TX (0, 2, 10)
835 RX_OP_CHECK_ACKS (0, rx_ack_ranges_3c) /* not provably ACKed yet */
836 RX_OP_RX_ACK (0, 2, 1)
837
838 RX_OP_CHECK_NO_ACKS (0) /* provably ACKed now gone */
839 RX_OP_CHECK_UNPROC (0, 0, 11) /* still unprocessable */
840 RX_OP_CHECK_PROC (0, 11, 1) /* still processable */
841
842 RX_OP_END
843 };
844
845 /*
846 * RX 4. Simple Test with ACK Not Yet Desired (Packet Threshold)
847 * (Initial/Handshake)
848 */
849 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_4a[] = {
850 { 0, 1 }
851 };
852
853 static const struct rx_test_op rx_script_4[] = {
854 /* The application PN space is tested in rx_script_2. */
855 RX_OP_SKIP_IF_PN_SPACE(QUIC_PN_SPACE_APP)
856
857 RX_OP_CHECK_STATE (0, 0, 0) /* no threshold yet */
858 RX_OP_CHECK_PROC (0, 0, 3)
859
860 /* First packet always generates an ACK so get it out of the way. */
861 RX_OP_PKT (0, 0, 1)
862 RX_OP_CHECK_UNPROC (0, 0, 1)
863 RX_OP_CHECK_PROC (0, 1, 1)
864 RX_OP_CHECK_STATE (0, 1, 0) /* first packet always causes ACK */
865 RX_OP_CHECK_ACKS (0, rx_ack_ranges_2a) /* clears packet counter */
866 RX_OP_CHECK_STATE (0, 0, 0) /* desired state should have been cleared */
867
868 /*
869 * Second packet should cause ACK-desired state because we are
870 * INITIAL/HANDSHAKE (RFC 9000 s. 13.2.1)
871 */
872 RX_OP_PKT (0, 1, 1) /* just one packet, threshold is 2 */
873 RX_OP_CHECK_UNPROC (0, 0, 2)
874 RX_OP_CHECK_PROC (0, 2, 1)
875 RX_OP_CHECK_STATE (0, 1, 1)
876 RX_OP_CHECK_ACKS (0, rx_ack_ranges_4a)
877 RX_OP_CHECK_STATE (0, 0, 0) /* desired state should have been cleared */
878
879 /* At this point we would generate e.g. a packet with an ACK. */
880 RX_OP_TX (0, 0, 1) /* ACKs all */
881 RX_OP_CHECK_ACKS (0, rx_ack_ranges_4a) /* not provably ACKed yet */
882 RX_OP_RX_ACK (0, 0, 1) /* TX'd packet is ACK'd */
883
884 RX_OP_CHECK_NO_ACKS (0) /* nothing more to ACK */
885 RX_OP_CHECK_UNPROC (0, 0, 2) /* still unprocessable */
886 RX_OP_CHECK_PROC (0, 2, 1) /* still processable */
887
888 RX_OP_END
889 };
890
891 static const struct rx_test_op *const rx_test_scripts[] = {
892 rx_script_1,
893 rx_script_2,
894 rx_script_3,
895 rx_script_4
896 };
897
on_ack_deadline_callback(OSSL_TIME deadline,int pkt_space,void * arg)898 static void on_ack_deadline_callback(OSSL_TIME deadline,
899 int pkt_space, void *arg)
900 {
901 ((OSSL_TIME *)arg)[pkt_space] = deadline;
902 }
903
test_rx_ack_actual(int tidx,int space)904 static int test_rx_ack_actual(int tidx, int space)
905 {
906 int testresult = 0;
907 struct helper h;
908 const struct rx_test_op *script = rx_test_scripts[tidx], *s;
909 size_t i, num_tx = 0, txi = 0;
910 const OSSL_QUIC_FRAME_ACK *ack;
911 OSSL_QUIC_FRAME_ACK rx_ack = {0};
912 OSSL_QUIC_ACK_RANGE rx_ack_range = {0};
913 struct pkt_info *pkts = NULL;
914 OSSL_ACKM_TX_PKT *txs = NULL, *tx;
915 OSSL_TIME ack_deadline[QUIC_PN_SPACE_NUM];
916 size_t opn = 0;
917 int j;
918
919 for (i = 0; i < QUIC_PN_SPACE_NUM; ++i)
920 ack_deadline[i] = ossl_time_infinite();
921
922 /* Initialise ACK manager. */
923 if (!TEST_int_eq(helper_init(&h, 0), 1))
924 goto err;
925
926 /* Arm callback for testing. */
927 ossl_ackm_set_ack_deadline_callback(h.ackm, on_ack_deadline_callback,
928 ack_deadline);
929
930 /*
931 * Determine how many packets we are TXing, and therefore how many packet
932 * structures we need.
933 */
934 for (s = script; s->kind != RX_OPK_END; ++s)
935 if (s->kind == RX_OPK_TX)
936 num_tx += s->num_pn;
937
938 /* Allocate packet information structures. */
939 txs = OPENSSL_calloc(num_tx, sizeof(*txs));
940 if (!TEST_ptr(txs))
941 goto err;
942
943 pkts = OPENSSL_calloc(num_tx, sizeof(*pkts));
944 if (!TEST_ptr(pkts))
945 goto err;
946
947 /* Run script. */
948 for (s = script; s->kind != RX_OPK_END; ++s, ++opn) {
949 fake_time = ossl_time_add(fake_time,
950 ossl_ticks2time(s->time_advance));
951 switch (s->kind) {
952 case RX_OPK_PKT:
953 for (i = 0; i < s->num_pn; ++i) {
954 OSSL_ACKM_RX_PKT pkt = {0};
955
956 pkt.pkt_num = s->pn + i;
957 pkt.time = fake_time;
958 pkt.pkt_space = space;
959 pkt.is_ack_eliciting = 1;
960
961 /* The packet should be processable before we feed it. */
962 if (!TEST_int_eq(ossl_ackm_is_rx_pn_processable(h.ackm,
963 pkt.pkt_num,
964 pkt.pkt_space), 1))
965 goto err;
966
967 if (!TEST_int_eq(ossl_ackm_on_rx_packet(h.ackm, &pkt), 1))
968 goto err;
969 }
970
971 break;
972
973 case RX_OPK_CHECK_UNPROC:
974 case RX_OPK_CHECK_PROC:
975 for (i = 0; i < s->num_pn; ++i)
976 if (!TEST_int_eq(ossl_ackm_is_rx_pn_processable(h.ackm,
977 s->pn + i, space),
978 (s->kind == RX_OPK_CHECK_PROC)))
979 goto err;
980
981 break;
982
983 case RX_OPK_CHECK_STATE:
984 if (!TEST_int_eq(ossl_ackm_is_ack_desired(h.ackm, space),
985 s->expect_desired))
986 goto err;
987
988 if (!TEST_int_eq(!ossl_time_is_infinite(ossl_ackm_get_ack_deadline(h.ackm, space))
989 && !ossl_time_is_zero(ossl_ackm_get_ack_deadline(h.ackm, space)),
990 s->expect_deadline))
991 goto err;
992
993 for (j = 0; j < QUIC_PN_SPACE_NUM; ++j) {
994 if (j != space
995 && !TEST_true(ossl_time_is_infinite(ossl_ackm_get_ack_deadline(h.ackm, j))))
996 goto err;
997
998 if (!TEST_int_eq(ossl_time_compare(ossl_ackm_get_ack_deadline(h.ackm, j),
999 ack_deadline[j]), 0))
1000 goto err;
1001 }
1002
1003 break;
1004
1005 case RX_OPK_CHECK_ACKS:
1006 ack = ossl_ackm_get_ack_frame(h.ackm, space);
1007
1008 /* Should always be able to get an ACK frame. */
1009 if (!TEST_ptr(ack))
1010 goto err;
1011
1012 if (!TEST_size_t_eq(ack->num_ack_ranges, s->num_ack_ranges))
1013 goto err;
1014
1015 for (i = 0; i < ack->num_ack_ranges; ++i) {
1016 if (!TEST_uint64_t_eq(ack->ack_ranges[i].start,
1017 s->ack_ranges[i].start))
1018 goto err;
1019 if (!TEST_uint64_t_eq(ack->ack_ranges[i].end,
1020 s->ack_ranges[i].end))
1021 goto err;
1022 }
1023
1024 break;
1025
1026 case RX_OPK_TX:
1027 pkts[txi].pkt = tx = &txs[txi];
1028
1029 tx->pkt_num = s->pn;
1030 tx->pkt_space = space;
1031 tx->num_bytes = 123;
1032 tx->largest_acked = s->largest_acked;
1033 tx->is_inflight = 1;
1034 tx->is_ack_eliciting = 1;
1035 tx->on_lost = on_lost;
1036 tx->on_acked = on_acked;
1037 tx->on_discarded = on_discarded;
1038 tx->cb_arg = &pkts[txi];
1039 tx->time = fake_time;
1040
1041 if (!TEST_int_eq(ossl_ackm_on_tx_packet(h.ackm, tx), 1))
1042 goto err;
1043
1044 ++txi;
1045 break;
1046
1047 case RX_OPK_RX_ACK:
1048 rx_ack.ack_ranges = &rx_ack_range;
1049 rx_ack.num_ack_ranges = 1;
1050
1051 rx_ack_range.start = s->pn;
1052 rx_ack_range.end = s->pn + s->num_pn - 1;
1053
1054 if (!TEST_int_eq(ossl_ackm_on_rx_ack_frame(h.ackm, &rx_ack,
1055 space, fake_time), 1))
1056 goto err;
1057
1058 break;
1059
1060 case RX_OPK_SKIP_IF_PN_SPACE:
1061 if (space == (int)s->pn) {
1062 testresult = 1;
1063 goto err;
1064 }
1065
1066 break;
1067
1068 default:
1069 goto err;
1070 }
1071 }
1072
1073 testresult = 1;
1074 err:
1075 if (!testresult)
1076 TEST_error("error in ACKM RX script %d, op %zu", tidx + 1, opn + 1);
1077
1078 helper_destroy(&h);
1079 OPENSSL_free(pkts);
1080 OPENSSL_free(txs);
1081 return testresult;
1082 }
1083
1084 /*
1085 * Driver
1086 * ******************************************************************
1087 */
test_tx_ack_case(int idx)1088 static int test_tx_ack_case(int idx)
1089 {
1090 int tidx, space;
1091
1092 tidx = idx % OSSL_NELEM(tx_ack_cases);
1093 idx /= OSSL_NELEM(tx_ack_cases);
1094
1095 space = idx % QUIC_PN_SPACE_NUM;
1096 idx /= QUIC_PN_SPACE_NUM;
1097
1098 return test_tx_ack_case_actual(tidx, space, idx);
1099 }
1100
test_rx_ack(int idx)1101 static int test_rx_ack(int idx)
1102 {
1103 int tidx;
1104
1105 tidx = idx % OSSL_NELEM(rx_test_scripts);
1106 idx /= OSSL_NELEM(rx_test_scripts);
1107
1108 return test_rx_ack_actual(tidx, idx);
1109 }
1110
setup_tests(void)1111 int setup_tests(void)
1112 {
1113 ADD_ALL_TESTS(test_tx_ack_case,
1114 OSSL_NELEM(tx_ack_cases) * MODE_NUM * QUIC_PN_SPACE_NUM);
1115 ADD_ALL_TESTS(test_tx_ack_time_script, OSSL_NELEM(tx_ack_time_scripts));
1116 ADD_ALL_TESTS(test_rx_ack, OSSL_NELEM(rx_test_scripts) * QUIC_PN_SPACE_NUM);
1117 return 1;
1118 }
1119