| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2023-09-07 16:59:15 +08:00
										 |  |  |  * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License 2.0 (the "License").  You may not use | 
					
						
							|  |  |  |  * this file except in compliance with the License.  You can obtain a copy | 
					
						
							|  |  |  |  * in the file LICENSE in the source distribution or at | 
					
						
							|  |  |  |  * https://www.openssl.org/source/license.html
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "testutil.h"
 | 
					
						
							|  |  |  | #include <openssl/ssl.h>
 | 
					
						
							|  |  |  | #include "internal/quic_ackm.h"
 | 
					
						
							|  |  |  | #include "internal/quic_cc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-15 23:45:17 +08:00
										 |  |  | static OSSL_TIME fake_time = {0}; | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-15 23:45:17 +08:00
										 |  |  | #define TIME_BASE (ossl_ticks2time(123 * OSSL_TIME_SECOND))
 | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | static OSSL_TIME fake_now(void *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return fake_time; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct pkt_info { | 
					
						
							|  |  |  |     OSSL_ACKM_TX_PKT *pkt; | 
					
						
							|  |  |  |     int lost, acked, discarded; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void on_lost(void *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct pkt_info *info = arg; | 
					
						
							|  |  |  |     ++info->lost; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void on_acked(void *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct pkt_info *info = arg; | 
					
						
							|  |  |  |     ++info->acked; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void on_discarded(void *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct pkt_info *info = arg; | 
					
						
							|  |  |  |     ++info->discarded; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct helper { | 
					
						
							|  |  |  |     OSSL_ACKM *ackm; | 
					
						
							|  |  |  |     struct pkt_info *pkts; | 
					
						
							|  |  |  |     size_t num_pkts; | 
					
						
							|  |  |  |     OSSL_CC_DATA *ccdata; | 
					
						
							|  |  |  |     OSSL_STATM statm; | 
					
						
							|  |  |  |     int have_statm; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void helper_destroy(struct helper *h) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     size_t i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (h->ackm != NULL) { | 
					
						
							|  |  |  |         ossl_ackm_free(h->ackm); | 
					
						
							|  |  |  |         h->ackm = NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (h->ccdata != NULL) { | 
					
						
							|  |  |  |         ossl_cc_dummy_method.free(h->ccdata); | 
					
						
							|  |  |  |         h->ccdata = NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (h->have_statm) { | 
					
						
							|  |  |  |         ossl_statm_destroy(&h->statm); | 
					
						
							|  |  |  |         h->have_statm = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (h->pkts != NULL) { | 
					
						
							|  |  |  |         for (i = 0; i < h->num_pkts; ++i) { | 
					
						
							|  |  |  |             OPENSSL_free(h->pkts[i].pkt); | 
					
						
							|  |  |  |             h->pkts[i].pkt = NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         OPENSSL_free(h->pkts); | 
					
						
							|  |  |  |         h->pkts = NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int helper_init(struct helper *h, size_t num_pkts) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int rc = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     memset(h, 0, sizeof(*h)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fake_time = TIME_BASE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Initialise statistics tracker. */ | 
					
						
							|  |  |  |     if (!TEST_int_eq(ossl_statm_init(&h->statm), 1)) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     h->have_statm = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Initialise congestion controller. */ | 
					
						
							| 
									
										
										
										
											2023-03-02 00:52:40 +08:00
										 |  |  |     h->ccdata = ossl_cc_dummy_method.new(fake_now, NULL); | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |     if (!TEST_ptr(h->ccdata)) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Initialise ACK manager. */ | 
					
						
							|  |  |  |     h->ackm = ossl_ackm_new(fake_now, NULL, &h->statm, | 
					
						
							| 
									
										
										
										
											2025-07-15 21:09:40 +08:00
										 |  |  |                             &ossl_cc_dummy_method, h->ccdata, | 
					
						
							|  |  |  |                             /* is_server */0); | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |     if (!TEST_ptr(h->ackm)) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Allocate our array of packet information. */ | 
					
						
							|  |  |  |     h->num_pkts = num_pkts; | 
					
						
							|  |  |  |     if (num_pkts > 0) { | 
					
						
							|  |  |  |         h->pkts = OPENSSL_zalloc(sizeof(struct pkt_info) * num_pkts); | 
					
						
							|  |  |  |         if (!TEST_ptr(h->pkts)) | 
					
						
							|  |  |  |             goto err; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         h->pkts = NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rc = 1; | 
					
						
							|  |  |  | err: | 
					
						
							|  |  |  |     if (rc == 0) | 
					
						
							|  |  |  |         helper_destroy(h); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return rc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const QUIC_PN linear_20[] = { | 
					
						
							|  |  |  |     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const QUIC_PN high_linear_20[] = { | 
					
						
							|  |  |  |     1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, | 
					
						
							|  |  |  |     1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, | 
					
						
							|  |  |  |     1018, 1019 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * TX ACK (Packet Threshold) Test Cases | 
					
						
							|  |  |  |  * ****************************************************************** | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct tx_ack_test_case { | 
					
						
							|  |  |  |     const QUIC_PN              *pn_table; | 
					
						
							|  |  |  |     size_t                      pn_table_len; | 
					
						
							|  |  |  |     const OSSL_QUIC_ACK_RANGE  *ack_ranges; | 
					
						
							|  |  |  |     size_t                      num_ack_ranges; | 
					
						
							|  |  |  |     const char                 *expect_ack; /* 1=ack, 2=lost, 4=discarded */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define DEFINE_TX_ACK_CASE(n, pntable)                          \
 | 
					
						
							|  |  |  |     static const struct tx_ack_test_case tx_ack_case_##n = {    \ | 
					
						
							|  |  |  |         (pntable), OSSL_NELEM(pntable),                         \ | 
					
						
							|  |  |  |         tx_ack_range_##n, OSSL_NELEM(tx_ack_range_##n),         \ | 
					
						
							|  |  |  |         tx_ack_expect_##n                                       \ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* One range, partial coverage of space */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE tx_ack_range_1[] = { | 
					
						
							|  |  |  |     { 0, 10 }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static const char tx_ack_expect_1[] = { | 
					
						
							|  |  |  |     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | DEFINE_TX_ACK_CASE(1, linear_20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Two ranges, partial coverage of space, overlapping by 1 */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE tx_ack_range_2[] = { | 
					
						
							|  |  |  |     { 5, 10 }, { 0, 5 } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static const char tx_ack_expect_2[] = { | 
					
						
							|  |  |  |     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | DEFINE_TX_ACK_CASE(2, linear_20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Two ranges, partial coverage of space, together contiguous */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE tx_ack_range_3[] = { | 
					
						
							|  |  |  |     { 6, 10 }, { 0, 5 } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static const char tx_ack_expect_3[] = { | 
					
						
							|  |  |  |     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | DEFINE_TX_ACK_CASE(3, linear_20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Two ranges, partial coverage of space, non-contiguous by 1 | 
					
						
							|  |  |  |  * Causes inferred loss due to packet threshold being exceeded. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE tx_ack_range_4[] = { | 
					
						
							|  |  |  |     { 7, 10 }, { 0, 5 } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static const char tx_ack_expect_4[] = { | 
					
						
							|  |  |  |     1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | DEFINE_TX_ACK_CASE(4, linear_20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Two ranges, partial coverage of space, non-contiguous by 2 | 
					
						
							|  |  |  |  * Causes inferred loss due to packet threshold being exceeded. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE tx_ack_range_5[] = { | 
					
						
							|  |  |  |     { 7, 10 }, { 0, 4 } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static const char tx_ack_expect_5[] = { | 
					
						
							|  |  |  |     1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | DEFINE_TX_ACK_CASE(5, linear_20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* One range, covering entire space */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE tx_ack_range_6[] = { | 
					
						
							|  |  |  |     { 0, 20 }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static const char tx_ack_expect_6[] = { | 
					
						
							|  |  |  |     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | DEFINE_TX_ACK_CASE(6, linear_20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* One range, covering more space than exists */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE tx_ack_range_7[] = { | 
					
						
							|  |  |  |     { 0, 30 }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static const char tx_ack_expect_7[] = { | 
					
						
							|  |  |  |     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | DEFINE_TX_ACK_CASE(7, linear_20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* One range, covering nothing (too high) */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE tx_ack_range_8[] = { | 
					
						
							|  |  |  |     { 21, 30 }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static const char tx_ack_expect_8[] = { | 
					
						
							|  |  |  |     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | DEFINE_TX_ACK_CASE(8, linear_20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* One range, covering nothing (too low) */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE tx_ack_range_9[] = { | 
					
						
							|  |  |  |     { 0, 999 }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static const char tx_ack_expect_9[] = { | 
					
						
							|  |  |  |     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | DEFINE_TX_ACK_CASE(9, high_linear_20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* One single packet at start of PN set */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE tx_ack_range_10[] = { | 
					
						
							|  |  |  |     { 0, 0 }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static const char tx_ack_expect_10[] = { | 
					
						
							|  |  |  |     1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | DEFINE_TX_ACK_CASE(10, linear_20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * One single packet in middle of PN set | 
					
						
							|  |  |  |  * Causes inferred loss of one packet due to packet threshold being exceeded, | 
					
						
							|  |  |  |  * but several other previous packets survive as they are under the threshold. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE tx_ack_range_11[] = { | 
					
						
							|  |  |  |     { 3, 3 }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static const char tx_ack_expect_11[] = { | 
					
						
							|  |  |  |     2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | DEFINE_TX_ACK_CASE(11, linear_20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * One single packet at end of PN set | 
					
						
							|  |  |  |  * Causes inferred loss due to packet threshold being exceeded. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE tx_ack_range_12[] = { | 
					
						
							|  |  |  |     { 19, 19 }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static const char tx_ack_expect_12[] = { | 
					
						
							|  |  |  |     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 1 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | DEFINE_TX_ACK_CASE(12, linear_20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Mixed straddling | 
					
						
							|  |  |  |  * Causes inferred loss due to packet threshold being exceeded. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE tx_ack_range_13[] = { | 
					
						
							|  |  |  |     { 1008, 1008 }, { 1004, 1005 }, { 1001, 1002 } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static const char tx_ack_expect_13[] = { | 
					
						
							|  |  |  |     2, 1, 1, 2, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | DEFINE_TX_ACK_CASE(13, high_linear_20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct tx_ack_test_case *const tx_ack_cases[] = { | 
					
						
							|  |  |  |     &tx_ack_case_1, | 
					
						
							|  |  |  |     &tx_ack_case_2, | 
					
						
							|  |  |  |     &tx_ack_case_3, | 
					
						
							|  |  |  |     &tx_ack_case_4, | 
					
						
							|  |  |  |     &tx_ack_case_5, | 
					
						
							|  |  |  |     &tx_ack_case_6, | 
					
						
							|  |  |  |     &tx_ack_case_7, | 
					
						
							|  |  |  |     &tx_ack_case_8, | 
					
						
							|  |  |  |     &tx_ack_case_9, | 
					
						
							|  |  |  |     &tx_ack_case_10, | 
					
						
							|  |  |  |     &tx_ack_case_11, | 
					
						
							|  |  |  |     &tx_ack_case_12, | 
					
						
							|  |  |  |     &tx_ack_case_13, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum { | 
					
						
							|  |  |  |     MODE_ACK, MODE_DISCARD, MODE_PTO, MODE_NUM | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int test_probe_counts(const OSSL_ACKM_PROBE_INFO *p, | 
					
						
							| 
									
										
										
										
											2022-12-16 18:11:10 +08:00
										 |  |  |                              uint32_t anti_deadlock_handshake, | 
					
						
							|  |  |  |                              uint32_t anti_deadlock_initial, | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |                              uint32_t pto_initial, | 
					
						
							|  |  |  |                              uint32_t pto_handshake, | 
					
						
							|  |  |  |                              uint32_t pto_app) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-16 18:11:10 +08:00
										 |  |  |     if (!TEST_uint_eq(p->anti_deadlock_handshake, anti_deadlock_handshake)) | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |         return 0; | 
					
						
							| 
									
										
										
										
											2022-12-16 18:11:10 +08:00
										 |  |  |     if (!TEST_uint_eq(p->anti_deadlock_initial, anti_deadlock_initial)) | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     if (!TEST_uint_eq(p->pto[QUIC_PN_SPACE_INITIAL], pto_initial)) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     if (!TEST_uint_eq(p->pto[QUIC_PN_SPACE_HANDSHAKE], pto_handshake)) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     if (!TEST_uint_eq(p->pto[QUIC_PN_SPACE_APP], pto_app)) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void on_loss_detection_deadline_callback(OSSL_TIME deadline, void *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     *(OSSL_TIME *)arg = deadline; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int test_tx_ack_case_actual(int tidx, int space, int mode) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int testresult = 0; | 
					
						
							|  |  |  |     struct helper h; | 
					
						
							|  |  |  |     size_t i; | 
					
						
							|  |  |  |     OSSL_ACKM_TX_PKT *tx; | 
					
						
							|  |  |  |     const struct tx_ack_test_case *c = tx_ack_cases[tidx]; | 
					
						
							|  |  |  |     OSSL_QUIC_FRAME_ACK ack = {0}; | 
					
						
							| 
									
										
										
										
											2022-08-15 23:45:17 +08:00
										 |  |  |     OSSL_TIME loss_detection_deadline = ossl_time_zero(); | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Cannot discard app space, so skip this */ | 
					
						
							|  |  |  |     if (mode == MODE_DISCARD && space == QUIC_PN_SPACE_APP) { | 
					
						
							|  |  |  |         TEST_skip("skipping test for app space"); | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!TEST_int_eq(helper_init(&h, c->pn_table_len), 1)) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Arm callback. */ | 
					
						
							|  |  |  |     ossl_ackm_set_loss_detection_deadline_callback(h.ackm, | 
					
						
							|  |  |  |                                                    on_loss_detection_deadline_callback, | 
					
						
							|  |  |  |                                                    &loss_detection_deadline); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Allocate TX packet structures. */ | 
					
						
							|  |  |  |     for (i = 0; i < c->pn_table_len; ++i) { | 
					
						
							|  |  |  |         h.pkts[i].pkt = tx = OPENSSL_zalloc(sizeof(*tx)); | 
					
						
							|  |  |  |         if (!TEST_ptr(tx)) | 
					
						
							|  |  |  |             goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         tx->pkt_num             = c->pn_table[i]; | 
					
						
							|  |  |  |         tx->pkt_space           = space; | 
					
						
							|  |  |  |         tx->is_inflight         = 1; | 
					
						
							|  |  |  |         tx->is_ack_eliciting    = 1; | 
					
						
							|  |  |  |         tx->num_bytes           = 123; | 
					
						
							|  |  |  |         tx->largest_acked       = QUIC_PN_INVALID; | 
					
						
							|  |  |  |         tx->on_lost             = on_lost; | 
					
						
							|  |  |  |         tx->on_acked            = on_acked; | 
					
						
							|  |  |  |         tx->on_discarded        = on_discarded; | 
					
						
							|  |  |  |         tx->cb_arg              = &h.pkts[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         tx->time  = fake_time; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!TEST_int_eq(ossl_ackm_on_tx_packet(h.ackm, tx), 1)) | 
					
						
							|  |  |  |             goto err; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mode == MODE_DISCARD) { | 
					
						
							|  |  |  |         /* Try discarding. */ | 
					
						
							|  |  |  |         if (!TEST_int_eq(ossl_ackm_on_pkt_space_discarded(h.ackm, space), 1)) | 
					
						
							|  |  |  |             goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Check all discard callbacks were called. */ | 
					
						
							|  |  |  |         for (i  = 0; i < c->pn_table_len; ++i) { | 
					
						
							|  |  |  |             if (!TEST_int_eq(h.pkts[i].acked, 0)) | 
					
						
							|  |  |  |                 goto err; | 
					
						
							|  |  |  |             if (!TEST_int_eq(h.pkts[i].lost, 0)) | 
					
						
							|  |  |  |                 goto err; | 
					
						
							|  |  |  |             if (!TEST_int_eq(h.pkts[i].discarded, 1)) | 
					
						
							|  |  |  |                 goto err; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else if (mode == MODE_ACK) { | 
					
						
							|  |  |  |         /* Try acknowledging. */ | 
					
						
							|  |  |  |         ack.ack_ranges      = (OSSL_QUIC_ACK_RANGE *)c->ack_ranges; | 
					
						
							|  |  |  |         ack.num_ack_ranges  = c->num_ack_ranges; | 
					
						
							|  |  |  |         if (!TEST_int_eq(ossl_ackm_on_rx_ack_frame(h.ackm, &ack, space, fake_time), 1)) | 
					
						
							|  |  |  |             goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Check correct ranges were acknowledged. */ | 
					
						
							|  |  |  |         for (i = 0; i < c->pn_table_len; ++i) { | 
					
						
							|  |  |  |             if (!TEST_int_eq(h.pkts[i].acked, | 
					
						
							|  |  |  |                              (c->expect_ack[i] & 1) != 0 ? 1 : 0)) | 
					
						
							|  |  |  |                 goto err; | 
					
						
							|  |  |  |             if (!TEST_int_eq(h.pkts[i].lost, | 
					
						
							|  |  |  |                              (c->expect_ack[i] & 2) != 0 ? 1 : 0)) | 
					
						
							|  |  |  |                 goto err; | 
					
						
							|  |  |  |             if (!TEST_int_eq(h.pkts[i].discarded, | 
					
						
							|  |  |  |                              (c->expect_ack[i] & 4) != 0 ? 1 : 0)) | 
					
						
							|  |  |  |                 goto err; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else if (mode == MODE_PTO) { | 
					
						
							|  |  |  |         OSSL_TIME deadline = ossl_ackm_get_loss_detection_deadline(h.ackm); | 
					
						
							| 
									
										
										
										
											2022-12-16 18:53:02 +08:00
										 |  |  |         OSSL_ACKM_PROBE_INFO probe; | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-15 23:45:17 +08:00
										 |  |  |         if (!TEST_int_eq(ossl_time_compare(deadline, loss_detection_deadline), 0)) | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |             goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* We should have a PTO deadline. */ | 
					
						
							| 
									
										
										
										
											2022-08-15 23:45:17 +08:00
										 |  |  |         if (!TEST_int_gt(ossl_time_compare(deadline, fake_time), 0)) | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |             goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Should not have any probe requests yet. */ | 
					
						
							| 
									
										
										
										
											2023-01-26 21:30:38 +08:00
										 |  |  |         probe = *ossl_ackm_get0_probe_request(h.ackm); | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |         if (!TEST_int_eq(test_probe_counts(&probe, 0, 0, 0, 0, 0), 1)) | 
					
						
							|  |  |  |             goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * If in app space, confirm handshake, as this is necessary to enable | 
					
						
							|  |  |  |          * app space PTO probe requests. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         if (space == QUIC_PN_SPACE_APP) | 
					
						
							|  |  |  |             if (!TEST_int_eq(ossl_ackm_on_handshake_confirmed(h.ackm), 1)) | 
					
						
							|  |  |  |                 goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Advance to the PTO deadline. */ | 
					
						
							| 
									
										
										
										
											2022-08-15 23:45:17 +08:00
										 |  |  |         fake_time = ossl_time_add(deadline, ossl_ticks2time(1)); | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (!TEST_int_eq(ossl_ackm_on_timeout(h.ackm), 1)) | 
					
						
							|  |  |  |             goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Should have a probe request. Not cleared by first call. */ | 
					
						
							|  |  |  |         for (i = 0; i < 3; ++i) { | 
					
						
							| 
									
										
										
										
											2023-01-26 21:30:38 +08:00
										 |  |  |             probe = *ossl_ackm_get0_probe_request(h.ackm); | 
					
						
							| 
									
										
										
										
											2022-12-16 18:53:02 +08:00
										 |  |  |             if (i > 0) | 
					
						
							| 
									
										
										
										
											2023-01-26 21:30:38 +08:00
										 |  |  |                 memset(ossl_ackm_get0_probe_request(h.ackm), 0, sizeof(probe)); | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if (i == 2) { | 
					
						
							|  |  |  |                 if (!TEST_int_eq(test_probe_counts(&probe, 0, 0, 0, 0, 0), 1)) | 
					
						
							|  |  |  |                     goto err; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 if (!TEST_int_eq(test_probe_counts(&probe, 0, 0, | 
					
						
							|  |  |  |                                                    space == QUIC_PN_SPACE_INITIAL, | 
					
						
							|  |  |  |                                                    space == QUIC_PN_SPACE_HANDSHAKE, | 
					
						
							|  |  |  |                                                    space == QUIC_PN_SPACE_APP), 1)) | 
					
						
							|  |  |  |                     goto err; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } else | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     testresult = 1; | 
					
						
							|  |  |  | err: | 
					
						
							|  |  |  |     helper_destroy(&h); | 
					
						
							|  |  |  |     return testresult; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * TX ACK (Time Threshold) Test | 
					
						
							|  |  |  |  * ****************************************************************** | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | enum { | 
					
						
							|  |  |  |     TX_ACK_TIME_OP_END, | 
					
						
							|  |  |  |     TX_ACK_TIME_OP_PKT,     /* TX packets */ | 
					
						
							|  |  |  |     TX_ACK_TIME_OP_ACK,     /* Synthesise incoming ACK of single PN range */ | 
					
						
							|  |  |  |     TX_ACK_TIME_OP_EXPECT   /* Ack/loss assertion */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct tx_ack_time_op { | 
					
						
							|  |  |  |     int       kind; | 
					
						
							| 
									
										
										
										
											2022-08-15 23:45:17 +08:00
										 |  |  |     uint64_t  time_advance; /* all ops */ | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |     QUIC_PN   pn;           /* PKT, ACK */ | 
					
						
							|  |  |  |     size_t    num_pn;       /* PKT, ACK */ | 
					
						
							|  |  |  |     const char *expect;     /* 1=ack, 2=lost, 4=discarded */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define TX_OP_PKT(advance, pn, num_pn) \
 | 
					
						
							|  |  |  |     { TX_ACK_TIME_OP_PKT, (advance) * OSSL_TIME_MS, (pn), (num_pn), NULL }, | 
					
						
							|  |  |  | #define TX_OP_ACK(advance, pn, num_pn) \
 | 
					
						
							|  |  |  |     { TX_ACK_TIME_OP_ACK, (advance) * OSSL_TIME_MS, (pn), (num_pn), NULL }, | 
					
						
							|  |  |  | #define TX_OP_EXPECT(expect) \
 | 
					
						
							|  |  |  |     { TX_ACK_TIME_OP_EXPECT, 0, 0, 0, (expect) }, | 
					
						
							|  |  |  | #define TX_OP_END { TX_ACK_TIME_OP_END }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char tx_ack_time_script_1_expect[] = { | 
					
						
							|  |  |  |     2, 1 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct tx_ack_time_op tx_ack_time_script_1[] = { | 
					
						
							|  |  |  |     TX_OP_PKT   (      0, 0, 1) | 
					
						
							|  |  |  |     TX_OP_PKT   (3600000, 1, 1) | 
					
						
							|  |  |  |     TX_OP_ACK   (   1000, 1, 1) | 
					
						
							|  |  |  |     TX_OP_EXPECT(tx_ack_time_script_1_expect) | 
					
						
							|  |  |  |     TX_OP_END | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct tx_ack_time_op *const tx_ack_time_scripts[] = { | 
					
						
							|  |  |  |     tx_ack_time_script_1, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int test_tx_ack_time_script(int tidx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int testresult = 0; | 
					
						
							|  |  |  |     struct helper h; | 
					
						
							|  |  |  |     OSSL_ACKM_TX_PKT *tx = NULL; | 
					
						
							|  |  |  |     OSSL_QUIC_FRAME_ACK ack = {0}; | 
					
						
							|  |  |  |     OSSL_QUIC_ACK_RANGE ack_range = {0}; | 
					
						
							|  |  |  |     size_t i, num_pkts = 0, pkt_idx = 0; | 
					
						
							|  |  |  |     const struct tx_ack_time_op *script = tx_ack_time_scripts[tidx], *s; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Calculate number of packets. */ | 
					
						
							|  |  |  |     for (s = script; s->kind != TX_ACK_TIME_OP_END; ++s) | 
					
						
							|  |  |  |         if (s->kind == TX_ACK_TIME_OP_PKT) | 
					
						
							|  |  |  |             num_pkts += s->num_pn; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Initialise ACK manager and packet structures. */ | 
					
						
							|  |  |  |     if (!TEST_int_eq(helper_init(&h, num_pkts), 1)) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < num_pkts; ++i) { | 
					
						
							|  |  |  |         h.pkts[i].pkt = tx = OPENSSL_zalloc(sizeof(*tx)); | 
					
						
							|  |  |  |         if (!TEST_ptr(tx)) | 
					
						
							|  |  |  |             goto err; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Run script. */ | 
					
						
							|  |  |  |     for (s = script; s->kind != TX_ACK_TIME_OP_END; ++s) | 
					
						
							|  |  |  |         switch (s->kind) { | 
					
						
							|  |  |  |             case TX_ACK_TIME_OP_PKT: | 
					
						
							|  |  |  |                 for (i = 0; i < s->num_pn; ++i) { | 
					
						
							|  |  |  |                     tx = h.pkts[pkt_idx + i].pkt; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     tx->pkt_num             = s->pn + i; | 
					
						
							|  |  |  |                     tx->pkt_space           = QUIC_PN_SPACE_INITIAL; | 
					
						
							|  |  |  |                     tx->num_bytes           = 123; | 
					
						
							|  |  |  |                     tx->largest_acked       = QUIC_PN_INVALID; | 
					
						
							|  |  |  |                     tx->is_inflight         = 1; | 
					
						
							|  |  |  |                     tx->is_ack_eliciting    = 1; | 
					
						
							|  |  |  |                     tx->on_lost             = on_lost; | 
					
						
							|  |  |  |                     tx->on_acked            = on_acked; | 
					
						
							|  |  |  |                     tx->on_discarded        = on_discarded; | 
					
						
							|  |  |  |                     tx->cb_arg              = &h.pkts[pkt_idx + i]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-15 23:45:17 +08:00
										 |  |  |                     fake_time = ossl_time_add(fake_time, | 
					
						
							|  |  |  |                                               ossl_ticks2time(s->time_advance)); | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |                     tx->time   = fake_time; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if (!TEST_int_eq(ossl_ackm_on_tx_packet(h.ackm, tx), 1)) | 
					
						
							|  |  |  |                         goto err; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 pkt_idx += s->num_pn; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             case TX_ACK_TIME_OP_ACK: | 
					
						
							|  |  |  |                 ack.ack_ranges      = &ack_range; | 
					
						
							|  |  |  |                 ack.num_ack_ranges  = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 ack_range.start     = s->pn; | 
					
						
							|  |  |  |                 ack_range.end       = s->pn + s->num_pn; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-15 23:45:17 +08:00
										 |  |  |                 fake_time = ossl_time_add(fake_time, | 
					
						
							|  |  |  |                                           ossl_ticks2time(s->time_advance)); | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 if (!TEST_int_eq(ossl_ackm_on_rx_ack_frame(h.ackm, &ack, | 
					
						
							|  |  |  |                                                            QUIC_PN_SPACE_INITIAL, | 
					
						
							|  |  |  |                                                            fake_time), 1)) | 
					
						
							|  |  |  |                     goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             case TX_ACK_TIME_OP_EXPECT: | 
					
						
							|  |  |  |                 for (i = 0; i < num_pkts; ++i) { | 
					
						
							|  |  |  |                     if (!TEST_int_eq(h.pkts[i].acked, | 
					
						
							|  |  |  |                                      (s->expect[i] & 1) != 0 ? 1 : 0)) | 
					
						
							|  |  |  |                         goto err; | 
					
						
							|  |  |  |                     if (!TEST_int_eq(h.pkts[i].lost, | 
					
						
							|  |  |  |                                      (s->expect[i] & 2) != 0 ? 1 : 0)) | 
					
						
							|  |  |  |                         goto err; | 
					
						
							|  |  |  |                     if (!TEST_int_eq(h.pkts[i].discarded, | 
					
						
							|  |  |  |                                      (s->expect[i] & 4) != 0 ? 1 : 0)) | 
					
						
							|  |  |  |                         goto err; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     testresult = 1; | 
					
						
							|  |  |  | err: | 
					
						
							|  |  |  |     helper_destroy(&h); | 
					
						
							|  |  |  |     return testresult; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * RX ACK Test | 
					
						
							|  |  |  |  * ****************************************************************** | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | enum { | 
					
						
							|  |  |  |     RX_OPK_END, | 
					
						
							|  |  |  |     RX_OPK_PKT,              /* RX packet */ | 
					
						
							|  |  |  |     RX_OPK_CHECK_UNPROC,     /* check PNs unprocessable */ | 
					
						
							|  |  |  |     RX_OPK_CHECK_PROC,       /* check PNs processable */ | 
					
						
							|  |  |  |     RX_OPK_CHECK_STATE,      /* check is_desired/deadline */ | 
					
						
							|  |  |  |     RX_OPK_CHECK_ACKS,       /* check ACK ranges */ | 
					
						
							|  |  |  |     RX_OPK_TX,               /* TX packet */ | 
					
						
							| 
									
										
										
										
											2023-07-03 22:45:25 +08:00
										 |  |  |     RX_OPK_RX_ACK,           /* RX ACK frame */ | 
					
						
							|  |  |  |     RX_OPK_SKIP_IF_PN_SPACE  /* skip for a given PN space */ | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct rx_test_op { | 
					
						
							|  |  |  |     int                         kind; | 
					
						
							| 
									
										
										
										
											2022-08-15 23:45:17 +08:00
										 |  |  |     uint64_t                    time_advance; | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     QUIC_PN                     pn;     /* PKT, CHECK_(UN)PROC, TX, RX_ACK */ | 
					
						
							|  |  |  |     size_t                      num_pn; /* PKT, CHECK_(UN)PROC, TX, RX_ACK */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     char                        expect_desired;     /* CHECK_STATE */ | 
					
						
							|  |  |  |     char                        expect_deadline;    /* CHECK_STATE */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const OSSL_QUIC_ACK_RANGE  *ack_ranges;         /* CHECK_ACKS */ | 
					
						
							|  |  |  |     size_t                      num_ack_ranges;     /* CHECK_ACKS */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QUIC_PN                     largest_acked;      /* TX */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define RX_OP_PKT(advance, pn, num_pn)                              \
 | 
					
						
							|  |  |  |     {                                                               \ | 
					
						
							|  |  |  |       RX_OPK_PKT, (advance) * OSSL_TIME_MS, (pn), (num_pn),         \ | 
					
						
							|  |  |  |       0, 0, NULL, 0, 0                                              \ | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define RX_OP_CHECK_UNPROC(advance, pn, num_pn)                     \
 | 
					
						
							|  |  |  |     {                                                               \ | 
					
						
							|  |  |  |       RX_OPK_CHECK_UNPROC, (advance) * OSSL_TIME_MS, (pn), (num_pn),\ | 
					
						
							|  |  |  |       0, 0, NULL, 0, 0                                              \ | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define RX_OP_CHECK_PROC(advance, pn, num_pn)                       \
 | 
					
						
							|  |  |  |     {                                                               \ | 
					
						
							|  |  |  |       RX_OPK_CHECK_PROC, (advance) * OSSL_TIME_MS, (pn), (num_pn),  \ | 
					
						
							|  |  |  |       0, 0, NULL, 0, 0                                              \ | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define RX_OP_CHECK_STATE(advance, expect_desired, expect_deadline) \
 | 
					
						
							|  |  |  |     {                                                               \ | 
					
						
							|  |  |  |       RX_OPK_CHECK_STATE, (advance) * OSSL_TIME_MS, 0, 0,           \ | 
					
						
							|  |  |  |       (expect_desired), (expect_deadline), NULL, 0, 0               \ | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define RX_OP_CHECK_ACKS(advance, ack_ranges)                       \
 | 
					
						
							|  |  |  |     {                                                               \ | 
					
						
							|  |  |  |       RX_OPK_CHECK_ACKS, (advance) * OSSL_TIME_MS, 0, 0,            \ | 
					
						
							|  |  |  |       0, 0, (ack_ranges), OSSL_NELEM(ack_ranges), 0                 \ | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define RX_OP_CHECK_NO_ACKS(advance)                                \
 | 
					
						
							|  |  |  |     {                                                               \ | 
					
						
							|  |  |  |       RX_OPK_CHECK_ACKS, (advance) * OSSL_TIME_MS, 0, 0,            \ | 
					
						
							|  |  |  |       0, 0, NULL, 0, 0                                              \ | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define RX_OP_TX(advance, pn, largest_acked)                        \
 | 
					
						
							|  |  |  |     {                                                               \ | 
					
						
							|  |  |  |       RX_OPK_TX, (advance) * OSSL_TIME_MS, (pn), 1,                 \ | 
					
						
							|  |  |  |       0, 0, NULL, 0, (largest_acked)                                \ | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define RX_OP_RX_ACK(advance, pn, num_pn)                           \
 | 
					
						
							|  |  |  |     {                                                               \ | 
					
						
							|  |  |  |       RX_OPK_RX_ACK, (advance) * OSSL_TIME_MS, (pn), (num_pn),      \ | 
					
						
							|  |  |  |       0, 0, NULL, 0, 0                                              \ | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-03 22:45:25 +08:00
										 |  |  | #define RX_OP_SKIP_IF_PN_SPACE(pn_space)                            \
 | 
					
						
							|  |  |  |     {                                                               \ | 
					
						
							|  |  |  |       RX_OPK_SKIP_IF_PN_SPACE, 0, (pn_space), 0,                    \ | 
					
						
							|  |  |  |       0, 0, NULL, 0, 0                                              \ | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  | #define RX_OP_END                                                   \
 | 
					
						
							|  |  |  |     { RX_OPK_END } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* RX 1. Simple Test with ACK Desired (Packet Threshold, Exactly) */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_1a[] = { | 
					
						
							|  |  |  |     { 0, 1 } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct rx_test_op rx_script_1[] = { | 
					
						
							|  |  |  |     RX_OP_CHECK_STATE   (0, 0, 0)   /* no threshold yet */ | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 0, 3) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     RX_OP_PKT           (0, 0, 2)   /* two packets, threshold */ | 
					
						
							|  |  |  |     RX_OP_CHECK_UNPROC  (0, 0, 2) | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 2, 1) | 
					
						
							|  |  |  |     RX_OP_CHECK_STATE   (0, 1, 0)   /* threshold met, immediate */ | 
					
						
							|  |  |  |     RX_OP_CHECK_ACKS    (0, rx_ack_ranges_1a) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* At this point we would generate e.g. a packet with an ACK. */ | 
					
						
							|  |  |  |     RX_OP_TX            (0, 0, 1)   /* ACKs both */ | 
					
						
							|  |  |  |     RX_OP_CHECK_ACKS    (0, rx_ack_ranges_1a) /* not provably ACKed yet */ | 
					
						
							|  |  |  |     RX_OP_RX_ACK        (0, 0, 1)   /* TX'd packet is ACK'd */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     RX_OP_CHECK_NO_ACKS (0)         /* nothing more to ACK */ | 
					
						
							|  |  |  |     RX_OP_CHECK_UNPROC  (0, 0, 2)   /* still unprocessable */ | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 2, 1)   /* still processable */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     RX_OP_END | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-03 22:45:25 +08:00
										 |  |  | /* RX 2. Simple Test with ACK Not Yet Desired (Packet Threshold) (1-RTT) */ | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  | static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_2a[] = { | 
					
						
							|  |  |  |     { 0, 0 } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_2b[] = { | 
					
						
							|  |  |  |     { 0, 2 } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct rx_test_op rx_script_2[] = { | 
					
						
							| 
									
										
										
										
											2023-07-03 22:45:25 +08:00
										 |  |  |     /*
 | 
					
						
							|  |  |  |      * We skip this for INITIAL/HANDSHAKE and use a separate version | 
					
						
							|  |  |  |      * (rx_script_4) for those spaces as those spaces should not delay ACK | 
					
						
							|  |  |  |      * generation, so a different RX_OP_CHECK_STATE test is needed. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     RX_OP_SKIP_IF_PN_SPACE(QUIC_PN_SPACE_INITIAL) | 
					
						
							|  |  |  |     RX_OP_SKIP_IF_PN_SPACE(QUIC_PN_SPACE_HANDSHAKE) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |     RX_OP_CHECK_STATE   (0, 0, 0)   /* no threshold yet */ | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 0, 3) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* First packet always generates an ACK so get it out of the way. */ | 
					
						
							|  |  |  |     RX_OP_PKT           (0, 0, 1) | 
					
						
							|  |  |  |     RX_OP_CHECK_UNPROC  (0, 0, 1) | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 1, 1) | 
					
						
							|  |  |  |     RX_OP_CHECK_STATE   (0, 1, 0)   /* first packet always causes ACK */ | 
					
						
							|  |  |  |     RX_OP_CHECK_ACKS    (0, rx_ack_ranges_2a) /* clears packet counter */ | 
					
						
							|  |  |  |     RX_OP_CHECK_STATE   (0, 0, 0)   /* desired state should have been cleared */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Second packet should not cause ACK-desired state */ | 
					
						
							|  |  |  |     RX_OP_PKT           (0, 1, 1)   /* just one packet, threshold is 2 */ | 
					
						
							|  |  |  |     RX_OP_CHECK_UNPROC  (0, 0, 2) | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 2, 1) | 
					
						
							|  |  |  |     RX_OP_CHECK_STATE   (0, 0, 1)   /* threshold not yet met, so deadline */ | 
					
						
							|  |  |  |     /* Don't check ACKs here, as it would reset our threshold counter. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Now receive a second packet, triggering the threshold */ | 
					
						
							|  |  |  |     RX_OP_PKT           (0, 2, 1)   /* second packet meets threshold */ | 
					
						
							|  |  |  |     RX_OP_CHECK_UNPROC  (0, 0, 3) | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 3, 1) | 
					
						
							|  |  |  |     RX_OP_CHECK_STATE   (0, 1, 0)   /* desired immediately */ | 
					
						
							|  |  |  |     RX_OP_CHECK_ACKS    (0, rx_ack_ranges_2b) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* At this point we would generate e.g. a packet with an ACK. */ | 
					
						
							|  |  |  |     RX_OP_TX            (0, 0, 2)   /* ACKs all */ | 
					
						
							|  |  |  |     RX_OP_CHECK_ACKS    (0, rx_ack_ranges_2b) /* not provably ACKed yet */ | 
					
						
							|  |  |  |     RX_OP_RX_ACK        (0, 0, 1)   /* TX'd packet is ACK'd */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     RX_OP_CHECK_NO_ACKS (0)         /* nothing more to ACK */ | 
					
						
							|  |  |  |     RX_OP_CHECK_UNPROC  (0, 0, 3)   /* still unprocessable */ | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 3, 1)   /* still processable */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     RX_OP_END | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* RX 3. Simple Test with ACK Desired (Packet Threshold, Multiple Watermarks) */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_3a[] = { | 
					
						
							|  |  |  |     { 0, 0 } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_3b[] = { | 
					
						
							|  |  |  |     { 0, 10 } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_3c[] = { | 
					
						
							|  |  |  |     { 6, 10 } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct rx_test_op rx_script_3[] = { | 
					
						
							|  |  |  |     RX_OP_CHECK_STATE   (0, 0, 0)   /* no threshold yet */ | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 0, 11) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* First packet always generates an ACK so get it out of the way. */ | 
					
						
							|  |  |  |     RX_OP_PKT           (0, 0, 1) | 
					
						
							|  |  |  |     RX_OP_CHECK_UNPROC  (0, 0, 1) | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 1, 1) | 
					
						
							|  |  |  |     RX_OP_CHECK_STATE   (0, 1, 0)   /* first packet always causes ACK */ | 
					
						
							|  |  |  |     RX_OP_CHECK_ACKS    (0, rx_ack_ranges_3a) /* clears packet counter */ | 
					
						
							|  |  |  |     RX_OP_CHECK_STATE   (0, 0, 0)   /* desired state should have been cleared */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Generate ten packets, exceeding the threshold. */ | 
					
						
							|  |  |  |     RX_OP_PKT           (0, 1, 10)  /* ten packets, threshold is 2 */ | 
					
						
							|  |  |  |     RX_OP_CHECK_UNPROC  (0, 0, 11) | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 11, 1) | 
					
						
							|  |  |  |     RX_OP_CHECK_STATE   (0, 1, 0)   /* threshold met, immediate */ | 
					
						
							|  |  |  |     RX_OP_CHECK_ACKS    (0, rx_ack_ranges_3b) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Test TX'ing a packet which doesn't ACK anything. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     RX_OP_TX            (0, 0, QUIC_PN_INVALID) | 
					
						
							|  |  |  |     RX_OP_RX_ACK        (0, 0, 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * At this point we would generate a packet with an ACK immediately. | 
					
						
							|  |  |  |      * TX a packet which when ACKed makes [0,5] provably ACKed. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     RX_OP_TX            (0, 1, 5) | 
					
						
							|  |  |  |     RX_OP_CHECK_ACKS    (0, rx_ack_ranges_3b) /* not provably ACKed yet */ | 
					
						
							|  |  |  |     RX_OP_RX_ACK        (0, 1, 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     RX_OP_CHECK_ACKS    (0, rx_ack_ranges_3c) /* provably ACKed now gone */ | 
					
						
							|  |  |  |     RX_OP_CHECK_UNPROC  (0, 0, 11) /* still unprocessable */ | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 11, 1) /* still processable */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Now TX another packet which provably ACKs the rest when ACKed. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     RX_OP_TX            (0, 2, 10) | 
					
						
							|  |  |  |     RX_OP_CHECK_ACKS    (0, rx_ack_ranges_3c) /* not provably ACKed yet */ | 
					
						
							|  |  |  |     RX_OP_RX_ACK        (0, 2, 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     RX_OP_CHECK_NO_ACKS (0)         /* provably ACKed now gone */ | 
					
						
							|  |  |  |     RX_OP_CHECK_UNPROC  (0, 0, 11)  /* still unprocessable */ | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 11, 1)  /* still processable */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     RX_OP_END | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-03 22:45:25 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * RX 4. Simple Test with ACK Not Yet Desired (Packet Threshold) | 
					
						
							|  |  |  |  * (Initial/Handshake) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_4a[] = { | 
					
						
							|  |  |  |     { 0, 1 } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct rx_test_op rx_script_4[] = { | 
					
						
							|  |  |  |     /* The application PN space is tested in rx_script_2. */ | 
					
						
							|  |  |  |     RX_OP_SKIP_IF_PN_SPACE(QUIC_PN_SPACE_APP) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     RX_OP_CHECK_STATE   (0, 0, 0)   /* no threshold yet */ | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 0, 3) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* First packet always generates an ACK so get it out of the way. */ | 
					
						
							|  |  |  |     RX_OP_PKT           (0, 0, 1) | 
					
						
							|  |  |  |     RX_OP_CHECK_UNPROC  (0, 0, 1) | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 1, 1) | 
					
						
							|  |  |  |     RX_OP_CHECK_STATE   (0, 1, 0)   /* first packet always causes ACK */ | 
					
						
							|  |  |  |     RX_OP_CHECK_ACKS    (0, rx_ack_ranges_2a) /* clears packet counter */ | 
					
						
							|  |  |  |     RX_OP_CHECK_STATE   (0, 0, 0)   /* desired state should have been cleared */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Second packet should cause ACK-desired state because we are | 
					
						
							|  |  |  |      * INITIAL/HANDSHAKE (RFC 9000 s. 13.2.1) | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     RX_OP_PKT           (0, 1, 1)   /* just one packet, threshold is 2 */ | 
					
						
							|  |  |  |     RX_OP_CHECK_UNPROC  (0, 0, 2) | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 2, 1) | 
					
						
							|  |  |  |     RX_OP_CHECK_STATE   (0, 1, 1) | 
					
						
							|  |  |  |     RX_OP_CHECK_ACKS    (0, rx_ack_ranges_4a) | 
					
						
							|  |  |  |     RX_OP_CHECK_STATE   (0, 0, 0)   /* desired state should have been cleared */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* At this point we would generate e.g. a packet with an ACK. */ | 
					
						
							|  |  |  |     RX_OP_TX            (0, 0, 1)   /* ACKs all */ | 
					
						
							|  |  |  |     RX_OP_CHECK_ACKS    (0, rx_ack_ranges_4a) /* not provably ACKed yet */ | 
					
						
							|  |  |  |     RX_OP_RX_ACK        (0, 0, 1)   /* TX'd packet is ACK'd */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     RX_OP_CHECK_NO_ACKS (0)         /* nothing more to ACK */ | 
					
						
							|  |  |  |     RX_OP_CHECK_UNPROC  (0, 0, 2)   /* still unprocessable */ | 
					
						
							|  |  |  |     RX_OP_CHECK_PROC    (0, 2, 1)   /* still processable */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     RX_OP_END | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  | static const struct rx_test_op *const rx_test_scripts[] = { | 
					
						
							|  |  |  |     rx_script_1, | 
					
						
							|  |  |  |     rx_script_2, | 
					
						
							| 
									
										
										
										
											2023-07-03 22:45:25 +08:00
										 |  |  |     rx_script_3, | 
					
						
							|  |  |  |     rx_script_4 | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void on_ack_deadline_callback(OSSL_TIME deadline, | 
					
						
							|  |  |  |                                      int pkt_space, void *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ((OSSL_TIME *)arg)[pkt_space] = deadline; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int test_rx_ack_actual(int tidx, int space) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int testresult = 0; | 
					
						
							|  |  |  |     struct helper h; | 
					
						
							|  |  |  |     const struct rx_test_op *script = rx_test_scripts[tidx], *s; | 
					
						
							|  |  |  |     size_t i, num_tx = 0, txi = 0; | 
					
						
							|  |  |  |     const OSSL_QUIC_FRAME_ACK *ack; | 
					
						
							|  |  |  |     OSSL_QUIC_FRAME_ACK rx_ack = {0}; | 
					
						
							|  |  |  |     OSSL_QUIC_ACK_RANGE rx_ack_range = {0}; | 
					
						
							|  |  |  |     struct pkt_info *pkts = NULL; | 
					
						
							|  |  |  |     OSSL_ACKM_TX_PKT *txs = NULL, *tx; | 
					
						
							| 
									
										
										
										
											2022-08-15 23:45:17 +08:00
										 |  |  |     OSSL_TIME ack_deadline[QUIC_PN_SPACE_NUM]; | 
					
						
							| 
									
										
										
										
											2023-07-03 22:45:25 +08:00
										 |  |  |     size_t opn = 0; | 
					
						
							| 
									
										
										
										
											2025-06-18 17:59:04 +08:00
										 |  |  |     int j; | 
					
						
							| 
									
										
										
										
											2022-08-15 23:45:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < QUIC_PN_SPACE_NUM; ++i) | 
					
						
							|  |  |  |         ack_deadline[i] = ossl_time_infinite(); | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Initialise ACK manager. */ | 
					
						
							|  |  |  |     if (!TEST_int_eq(helper_init(&h, 0), 1)) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Arm callback for testing. */ | 
					
						
							|  |  |  |     ossl_ackm_set_ack_deadline_callback(h.ackm, on_ack_deadline_callback, | 
					
						
							|  |  |  |                                         ack_deadline); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Determine how many packets we are TXing, and therefore how many packet | 
					
						
							|  |  |  |      * structures we need. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     for (s = script; s->kind != RX_OPK_END; ++s) | 
					
						
							|  |  |  |         if (s->kind == RX_OPK_TX) | 
					
						
							|  |  |  |             num_tx += s->num_pn; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Allocate packet information structures. */ | 
					
						
							|  |  |  |     txs = OPENSSL_zalloc(sizeof(*txs) * num_tx); | 
					
						
							|  |  |  |     if (!TEST_ptr(txs)) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pkts = OPENSSL_zalloc(sizeof(*pkts) * num_tx); | 
					
						
							|  |  |  |     if (!TEST_ptr(pkts)) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Run script. */ | 
					
						
							| 
									
										
										
										
											2023-07-03 22:45:25 +08:00
										 |  |  |     for (s = script; s->kind != RX_OPK_END; ++s, ++opn) { | 
					
						
							| 
									
										
										
										
											2022-08-15 23:45:17 +08:00
										 |  |  |         fake_time = ossl_time_add(fake_time, | 
					
						
							|  |  |  |                                   ossl_ticks2time(s->time_advance)); | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |         switch (s->kind) { | 
					
						
							|  |  |  |         case RX_OPK_PKT: | 
					
						
							|  |  |  |             for (i = 0; i < s->num_pn; ++i) { | 
					
						
							|  |  |  |                 OSSL_ACKM_RX_PKT pkt = {0}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 pkt.pkt_num             = s->pn + i; | 
					
						
							|  |  |  |                 pkt.time                = fake_time; | 
					
						
							|  |  |  |                 pkt.pkt_space           = space; | 
					
						
							|  |  |  |                 pkt.is_ack_eliciting    = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 /* The packet should be processable before we feed it. */ | 
					
						
							|  |  |  |                 if (!TEST_int_eq(ossl_ackm_is_rx_pn_processable(h.ackm, | 
					
						
							|  |  |  |                                                                 pkt.pkt_num, | 
					
						
							|  |  |  |                                                                 pkt.pkt_space), 1)) | 
					
						
							|  |  |  |                     goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (!TEST_int_eq(ossl_ackm_on_rx_packet(h.ackm, &pkt), 1)) | 
					
						
							|  |  |  |                     goto err; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case RX_OPK_CHECK_UNPROC: | 
					
						
							|  |  |  |         case RX_OPK_CHECK_PROC: | 
					
						
							|  |  |  |             for (i = 0; i < s->num_pn; ++i) | 
					
						
							|  |  |  |                 if (!TEST_int_eq(ossl_ackm_is_rx_pn_processable(h.ackm, | 
					
						
							|  |  |  |                                                                 s->pn + i, space), | 
					
						
							|  |  |  |                                  (s->kind == RX_OPK_CHECK_PROC))) | 
					
						
							|  |  |  |                     goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case RX_OPK_CHECK_STATE: | 
					
						
							|  |  |  |             if (!TEST_int_eq(ossl_ackm_is_ack_desired(h.ackm, space), | 
					
						
							|  |  |  |                              s->expect_desired)) | 
					
						
							|  |  |  |                 goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-15 23:45:17 +08:00
										 |  |  |             if (!TEST_int_eq(!ossl_time_is_infinite(ossl_ackm_get_ack_deadline(h.ackm, space)) | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |                              && !ossl_time_is_zero(ossl_ackm_get_ack_deadline(h.ackm, space)), | 
					
						
							|  |  |  |                              s->expect_deadline)) | 
					
						
							|  |  |  |                 goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-18 17:59:04 +08:00
										 |  |  |             for (j = 0; j < QUIC_PN_SPACE_NUM; ++j) { | 
					
						
							|  |  |  |                 if (j != space | 
					
						
							|  |  |  |                         && !TEST_true(ossl_time_is_infinite(ossl_ackm_get_ack_deadline(h.ackm, j)))) | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |                     goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-18 17:59:04 +08:00
										 |  |  |                 if (!TEST_int_eq(ossl_time_compare(ossl_ackm_get_ack_deadline(h.ackm, j), | 
					
						
							|  |  |  |                                                    ack_deadline[j]), 0)) | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |                     goto err; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case RX_OPK_CHECK_ACKS: | 
					
						
							|  |  |  |             ack = ossl_ackm_get_ack_frame(h.ackm, space); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* Should always be able to get an ACK frame. */ | 
					
						
							|  |  |  |             if (!TEST_ptr(ack)) | 
					
						
							|  |  |  |                 goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!TEST_size_t_eq(ack->num_ack_ranges, s->num_ack_ranges)) | 
					
						
							|  |  |  |                 goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (i = 0; i < ack->num_ack_ranges; ++i) { | 
					
						
							|  |  |  |                 if (!TEST_uint64_t_eq(ack->ack_ranges[i].start, | 
					
						
							|  |  |  |                                       s->ack_ranges[i].start)) | 
					
						
							|  |  |  |                     goto err; | 
					
						
							|  |  |  |                 if (!TEST_uint64_t_eq(ack->ack_ranges[i].end, | 
					
						
							|  |  |  |                                       s->ack_ranges[i].end)) | 
					
						
							|  |  |  |                     goto err; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case RX_OPK_TX: | 
					
						
							|  |  |  |             pkts[txi].pkt = tx = &txs[txi]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             tx->pkt_num             = s->pn; | 
					
						
							|  |  |  |             tx->pkt_space           = space; | 
					
						
							|  |  |  |             tx->num_bytes           = 123; | 
					
						
							|  |  |  |             tx->largest_acked       = s->largest_acked; | 
					
						
							|  |  |  |             tx->is_inflight         = 1; | 
					
						
							|  |  |  |             tx->is_ack_eliciting    = 1; | 
					
						
							|  |  |  |             tx->on_lost             = on_lost; | 
					
						
							|  |  |  |             tx->on_acked            = on_acked; | 
					
						
							|  |  |  |             tx->on_discarded        = on_discarded; | 
					
						
							|  |  |  |             tx->cb_arg              = &pkts[txi]; | 
					
						
							|  |  |  |             tx->time                = fake_time; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!TEST_int_eq(ossl_ackm_on_tx_packet(h.ackm, tx), 1)) | 
					
						
							|  |  |  |                 goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ++txi; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case RX_OPK_RX_ACK: | 
					
						
							|  |  |  |             rx_ack.ack_ranges       = &rx_ack_range; | 
					
						
							|  |  |  |             rx_ack.num_ack_ranges   = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             rx_ack_range.start      = s->pn; | 
					
						
							|  |  |  |             rx_ack_range.end        = s->pn + s->num_pn - 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!TEST_int_eq(ossl_ackm_on_rx_ack_frame(h.ackm, &rx_ack, | 
					
						
							|  |  |  |                                                        space, fake_time), 1)) | 
					
						
							|  |  |  |                 goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-03 22:45:25 +08:00
										 |  |  |         case RX_OPK_SKIP_IF_PN_SPACE: | 
					
						
							| 
									
										
										
										
											2023-07-03 23:41:51 +08:00
										 |  |  |             if (space == (int)s->pn) { | 
					
						
							| 
									
										
										
										
											2023-07-03 22:45:25 +08:00
										 |  |  |                 testresult = 1; | 
					
						
							|  |  |  |                 goto err; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |         default: | 
					
						
							|  |  |  |             goto err; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     testresult = 1; | 
					
						
							|  |  |  | err: | 
					
						
							| 
									
										
										
										
											2023-07-03 22:45:25 +08:00
										 |  |  |     if (!testresult) | 
					
						
							|  |  |  |         TEST_error("error in ACKM RX script %d, op %zu", tidx + 1, opn + 1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-28 20:52:48 +08:00
										 |  |  |     helper_destroy(&h); | 
					
						
							|  |  |  |     OPENSSL_free(pkts); | 
					
						
							|  |  |  |     OPENSSL_free(txs); | 
					
						
							|  |  |  |     return testresult; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Driver | 
					
						
							|  |  |  |  * ****************************************************************** | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int test_tx_ack_case(int idx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int tidx, space; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tidx = idx % OSSL_NELEM(tx_ack_cases); | 
					
						
							|  |  |  |     idx /= OSSL_NELEM(tx_ack_cases); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     space = idx % QUIC_PN_SPACE_NUM; | 
					
						
							|  |  |  |     idx /= QUIC_PN_SPACE_NUM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return test_tx_ack_case_actual(tidx, space, idx); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int test_rx_ack(int idx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int tidx; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tidx = idx % OSSL_NELEM(rx_test_scripts); | 
					
						
							|  |  |  |     idx /= OSSL_NELEM(rx_test_scripts); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return test_rx_ack_actual(tidx, idx); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int setup_tests(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ADD_ALL_TESTS(test_tx_ack_case, | 
					
						
							|  |  |  |                   OSSL_NELEM(tx_ack_cases) * MODE_NUM * QUIC_PN_SPACE_NUM); | 
					
						
							|  |  |  |     ADD_ALL_TESTS(test_tx_ack_time_script, OSSL_NELEM(tx_ack_time_scripts)); | 
					
						
							|  |  |  |     ADD_ALL_TESTS(test_rx_ack, OSSL_NELEM(rx_test_scripts) * QUIC_PN_SPACE_NUM); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } |