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