1 1.1 christos /* 2 1.1.1.2 christos * Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved. 3 1.1.1.2 christos * 4 1.1.1.2 christos * Licensed under the Apache License 2.0 (the "License"). You may not use 5 1.1.1.2 christos * this file except in compliance with the License. You can obtain a copy 6 1.1.1.2 christos * in the file LICENSE in the source distribution or at 7 1.1.1.2 christos * https://www.openssl.org/source/license.html 8 1.1.1.2 christos */ 9 1.1 christos 10 1.1 christos #ifndef OSSL_INTERNAL_QUIC_RCIDM_H 11 1.1.1.2 christos #define OSSL_INTERNAL_QUIC_RCIDM_H 12 1.1.1.2 christos #pragma once 13 1.1 christos 14 1.1.1.2 christos #include "internal/e_os.h" 15 1.1.1.2 christos #include "internal/time.h" 16 1.1.1.2 christos #include "internal/quic_types.h" 17 1.1.1.2 christos #include "internal/quic_wire.h" 18 1.1 christos 19 1.1.1.2 christos #ifndef OPENSSL_NO_QUIC 20 1.1 christos 21 1.1 christos /* 22 1.1 christos * QUIC Remote Connection ID Manager 23 1.1 christos * ================================= 24 1.1 christos * 25 1.1 christos * This manages connection IDs for the TX side. The RCIDM tracks remote CIDs 26 1.1 christos * (RCIDs) which a peer has issued to us and which we can use as the DCID of 27 1.1 christos * packets we transmit. It is entirely separate from the LCIDM, which handles 28 1.1 christos * routing received packets by their DCIDs. 29 1.1 christos * 30 1.1 christos * RCIDs fall into four categories: 31 1.1 christos * 32 1.1 christos * 1. A client's Initial ODCID (0..1) 33 1.1 christos * 2. A peer's Initial SCID (1) 34 1.1 christos * 3. A server's Retry SCID (0..1) 35 1.1 christos * 4. A CID issued via a NEW_CONNECTION_ID frame (n) 36 1.1 christos * 37 1.1 christos * Unlike a LCIDM, which is per port, a RCIDM is per connection, as there is no 38 1.1 christos * need for routing of outgoing packets. 39 1.1 christos */ 40 1.1 christos typedef struct quic_rcidm_st QUIC_RCIDM; 41 1.1 christos 42 1.1 christos /* 43 1.1 christos * Creates a new RCIDM. Returns NULL on failure. 44 1.1 christos * 45 1.1 christos * For a client, initial_odcid is the client's Initial ODCID. 46 1.1 christos * For a server, initial_odcid is NULL. 47 1.1 christos */ 48 1.1 christos QUIC_RCIDM *ossl_quic_rcidm_new(const QUIC_CONN_ID *initial_odcid); 49 1.1 christos 50 1.1 christos /* Frees a RCIDM. */ 51 1.1 christos void ossl_quic_rcidm_free(QUIC_RCIDM *rcidm); 52 1.1 christos 53 1.1 christos /* 54 1.1 christos * CID Events 55 1.1 christos * ========== 56 1.1 christos */ 57 1.1 christos 58 1.1 christos /* 59 1.1 christos * To be called by a client when a server responds to the first Initial packet 60 1.1 christos * sent with its own Initial packet with its own SCID; or to be called by a 61 1.1 christos * server when we first get an Initial packet from a client with the client's 62 1.1 christos * supplied SCID. The added RCID implicitly has a sequence number of 0. 63 1.1 christos * 64 1.1 christos * We immediately switch to using this SCID as our preferred RCID. This SCID 65 1.1 christos * must be enrolled using this function. May only be called once. 66 1.1 christos */ 67 1.1 christos int ossl_quic_rcidm_add_from_initial(QUIC_RCIDM *rcidm, 68 1.1.1.2 christos const QUIC_CONN_ID *rcid); 69 1.1 christos 70 1.1 christos /* 71 1.1 christos * To be called by a client when a server responds to the first Initial packet 72 1.1 christos * sent with a Retry packet with its own SCID (the "Retry ODCID"). We 73 1.1 christos * immediately switch to using this SCID as our preferred RCID when conducting 74 1.1 christos * the retry. This SCID must be enrolled using this function. May only be called 75 1.1 christos * once. The added RCID has no sequence number associated with it as it is 76 1.1 christos * essentially a new ODCID (hereafter a Retry ODCID). 77 1.1 christos * 78 1.1 christos * Not for server use. 79 1.1 christos */ 80 1.1 christos int ossl_quic_rcidm_add_from_server_retry(QUIC_RCIDM *rcidm, 81 1.1.1.2 christos const QUIC_CONN_ID *retry_odcid); 82 1.1 christos 83 1.1 christos /* 84 1.1 christos * Processes an incoming NEW_CONN_ID frame, recording the new CID as a potential 85 1.1 christos * RCID. The RCIDM retirement mechanism is ratcheted according to the 86 1.1 christos * ncid->retire_prior_to field. The stateless_reset field is ignored; the caller 87 1.1 christos * is responsible for handling it separately. 88 1.1 christos */ 89 1.1 christos int ossl_quic_rcidm_add_from_ncid(QUIC_RCIDM *rcidm, 90 1.1.1.2 christos const OSSL_QUIC_FRAME_NEW_CONN_ID *ncid); 91 1.1 christos 92 1.1 christos /* 93 1.1 christos * Other Events 94 1.1 christos * ============ 95 1.1 christos */ 96 1.1 christos 97 1.1 christos /* 98 1.1 christos * Notifies the RCIDM that the handshake for a connection is complete. 99 1.1 christos * Should only be called once; further calls are ignored. 100 1.1 christos * 101 1.1 christos * This may influence the RCIDM's RCID change policy. 102 1.1 christos */ 103 1.1 christos void ossl_quic_rcidm_on_handshake_complete(QUIC_RCIDM *rcidm); 104 1.1 christos 105 1.1 christos /* 106 1.1 christos * Notifies the RCIDM that one or more packets have been sent. 107 1.1 christos * 108 1.1 christos * This may influence the RCIDM's RCID change policy. 109 1.1 christos */ 110 1.1 christos void ossl_quic_rcidm_on_packet_sent(QUIC_RCIDM *rcidm, uint64_t num_packets); 111 1.1 christos 112 1.1 christos /* 113 1.1 christos * Manually request switching to a new RCID as soon as possible. 114 1.1 christos */ 115 1.1 christos void ossl_quic_rcidm_request_roll(QUIC_RCIDM *rcidm); 116 1.1 christos 117 1.1 christos /* 118 1.1 christos * Queries 119 1.1 christos * ======= 120 1.1 christos */ 121 1.1 christos 122 1.1 christos /* 123 1.1 christos * The RCIDM decides when it will never use a given RCID again. When it does 124 1.1 christos * this, it outputs the sequence number of that RCID using this function, which 125 1.1 christos * pops from a logical queue of retired RCIDs. The caller is responsible 126 1.1 christos * for polling this function and generating Retire CID frames from the result. 127 1.1 christos * 128 1.1 christos * If nothing needs doing and the queue is empty, this function returns 0. If 129 1.1 christos * there is an RCID which needs retiring, the sequence number of that RCID is 130 1.1 christos * written to *seq_num (if seq_num is non-NULL) and this function returns 1. The 131 1.1 christos * queue entry is popped (and the caller is thus assumed to have taken 132 1.1 christos * responsibility for transmitting the necessary Retire CID frame). 133 1.1 christos * 134 1.1 christos * Note that the caller should not transmit a Retire CID frame immediately as 135 1.1 christos * packets using the RCID may still be in flight. The caller must determine an 136 1.1 christos * appropriate delay using knowledge of network conditions (RTT, etc.) which is 137 1.1 christos * outside the scope of the RCIDM. The caller is responsible for implementing 138 1.1 christos * this delay based on the last time a packet was transmitted using the RCID 139 1.1 christos * being retired. 140 1.1 christos */ 141 1.1 christos int ossl_quic_rcidm_pop_retire_seq_num(QUIC_RCIDM *rcid, uint64_t *seq_num); 142 1.1 christos 143 1.1 christos /* 144 1.1 christos * Like ossl_quic_rcidm_pop_retire_seq_num, but does not pop the item from the 145 1.1 christos * queue. If this call succeeds, the next call to 146 1.1 christos * ossl_quic_rcidm_pop_retire_seq_num is guaranteed to output the same sequence 147 1.1 christos * number. 148 1.1 christos */ 149 1.1 christos int ossl_quic_rcidm_peek_retire_seq_num(QUIC_RCIDM *rcid, uint64_t *seq_num); 150 1.1 christos 151 1.1 christos /* 152 1.1 christos * Writes the DCID preferred for a newly transmitted packet at this time to 153 1.1 christos * *tx_dcid. This function should be called to determine what DCID to use when 154 1.1 christos * transmitting a packet to the peer. The RCIDM may implement arbitrary policy 155 1.1 christos * to decide when to change the preferred RCID. 156 1.1 christos * 157 1.1 christos * Returns 1 on success and 0 on failure. 158 1.1 christos */ 159 1.1 christos int ossl_quic_rcidm_get_preferred_tx_dcid(QUIC_RCIDM *rcidm, 160 1.1.1.2 christos QUIC_CONN_ID *tx_dcid); 161 1.1 christos 162 1.1 christos /* 163 1.1 christos * Returns 1 if the value output by ossl_quic_rcidm_get_preferred_tx_dcid() has 164 1.1 christos * changed since the last call to this function with clear set. If clear is set, 165 1.1 christos * clears the changed flag. Returns the old value of the changed flag. 166 1.1 christos */ 167 1.1 christos int ossl_quic_rcidm_get_preferred_tx_dcid_changed(QUIC_RCIDM *rcidm, 168 1.1.1.2 christos int clear); 169 1.1 christos 170 1.1 christos /* 171 1.1 christos * Returns the number of active numbered RCIDs we have. Note that this includes 172 1.1 christos * RCIDs on the retir*ing* queue accessed via 173 1.1 christos * ossl_quic_rcidm_pop_retire_seq_num() as these are still active until actually 174 1.1 christos * retired. 175 1.1 christos */ 176 1.1 christos size_t ossl_quic_rcidm_get_num_active(const QUIC_RCIDM *rcidm); 177 1.1 christos 178 1.1 christos /* 179 1.1 christos * Returns the number of retir*ing* numbered RCIDs we have. 180 1.1 christos */ 181 1.1 christos size_t ossl_quic_rcidm_get_num_retiring(const QUIC_RCIDM *rcidm); 182 1.1 christos 183 1.1.1.2 christos #endif 184 1.1 christos 185 1.1 christos #endif 186