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