Path: blob/main/crypto/openssl/ssl/quic/quic_txp.c
48266 views
/*1* Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89#include "internal/quic_txp.h"10#include "internal/quic_fifd.h"11#include "internal/quic_stream_map.h"12#include "internal/quic_error.h"13#include "internal/common.h"14#include <openssl/err.h>1516#define MIN_CRYPTO_HDR_SIZE 31718#define MIN_FRAME_SIZE_HANDSHAKE_DONE 119#define MIN_FRAME_SIZE_MAX_DATA 220#define MIN_FRAME_SIZE_ACK 521#define MIN_FRAME_SIZE_CRYPTO (MIN_CRYPTO_HDR_SIZE + 1)22#define MIN_FRAME_SIZE_STREAM 3 /* minimum useful size (for non-FIN) */23#define MIN_FRAME_SIZE_MAX_STREAMS_BIDI 224#define MIN_FRAME_SIZE_MAX_STREAMS_UNI 22526/*27* Packet Archetypes28* =================29*/3031/* Generate normal packets containing most frame types, subject to EL. */32#define TX_PACKETISER_ARCHETYPE_NORMAL 03334/*35* A probe packet is different in that:36* - It bypasses CC, but *is* counted as in flight for purposes of CC;37* - It must be ACK-eliciting.38*/39#define TX_PACKETISER_ARCHETYPE_PROBE 14041/*42* An ACK-only packet is different in that:43* - It bypasses CC, and is considered a 'non-inflight' packet;44* - It may not contain anything other than an ACK frame, not even padding.45*/46#define TX_PACKETISER_ARCHETYPE_ACK_ONLY 24748#define TX_PACKETISER_ARCHETYPE_NUM 34950struct ossl_quic_tx_packetiser_st {51OSSL_QUIC_TX_PACKETISER_ARGS args;5253/*54* Opaque initial token blob provided by caller. TXP frees using the55* callback when it is no longer needed.56*/57const unsigned char *initial_token;58size_t initial_token_len;59ossl_quic_initial_token_free_fn *initial_token_free_cb;60void *initial_token_free_cb_arg;6162/* Subcomponents of the TXP that we own. */63QUIC_FIFD fifd; /* QUIC Frame-in-Flight Dispatcher */6465/* Internal state. */66uint64_t next_pn[QUIC_PN_SPACE_NUM]; /* Next PN to use in given PN space. */67OSSL_TIME last_tx_time; /* Last time a packet was generated, or 0. */6869size_t unvalidated_credit; /* Limit of data we can send until validated */7071/* Internal state - frame (re)generation flags. */72unsigned int want_handshake_done : 1;73unsigned int want_max_data : 1;74unsigned int want_max_streams_bidi : 1;75unsigned int want_max_streams_uni : 1;7677/* Internal state - frame (re)generation flags - per PN space. */78unsigned int want_ack : QUIC_PN_SPACE_NUM;79unsigned int force_ack_eliciting : QUIC_PN_SPACE_NUM;8081/*82* Internal state - connection close terminal state.83* Once this is set, it is not unset unlike other want_ flags - we keep84* sending it in every packet.85*/86unsigned int want_conn_close : 1;8788/* Has the handshake been completed? */89unsigned int handshake_complete : 1;9091OSSL_QUIC_FRAME_CONN_CLOSE conn_close_frame;9293/*94* Counts of the number of bytes received and sent while in the closing95* state.96*/97uint64_t closing_bytes_recv;98uint64_t closing_bytes_xmit;99100/* Internal state - packet assembly. */101struct txp_el {102unsigned char *scratch; /* scratch buffer for packet assembly */103size_t scratch_len; /* number of bytes allocated for scratch */104OSSL_QTX_IOVEC *iovec; /* scratch iovec array for use with QTX */105size_t alloc_iovec; /* size of iovec array */106} el[QUIC_ENC_LEVEL_NUM];107108/* Message callback related arguments */109ossl_msg_cb msg_callback;110void *msg_callback_arg;111SSL *msg_callback_ssl;112113/* Callbacks. */114void (*ack_tx_cb)(const OSSL_QUIC_FRAME_ACK *ack,115uint32_t pn_space,116void *arg);117void *ack_tx_cb_arg;118};119120/*121* The TX helper records state used while generating frames into packets. It122* enables serialization into the packet to be done "transactionally" where123* serialization of a frame can be rolled back if it fails midway (e.g. if it124* does not fit).125*/126struct tx_helper {127OSSL_QUIC_TX_PACKETISER *txp;128/*129* The Maximum Packet Payload Length in bytes. This is the amount of130* space we have to generate frames into.131*/132size_t max_ppl;133/*134* Number of bytes we have generated so far.135*/136size_t bytes_appended;137/*138* Number of scratch bytes in txp->scratch we have used so far. Some iovecs139* will reference this scratch buffer. When we need to use more of it (e.g.140* when we need to put frame headers somewhere), we append to the scratch141* buffer, resizing if necessary, and increase this accordingly.142*/143size_t scratch_bytes;144/*145* Bytes reserved in the MaxPPL budget. We keep this number of bytes spare146* until reserve_allowed is set to 1. Currently this is always at most 1, as147* a PING frame takes up one byte and this mechanism is only used to ensure148* we can encode a PING frame if we have been asked to ensure a packet is149* ACK-eliciting and we are unusure if we are going to add any other150* ACK-eliciting frames before we reach our MaxPPL budget.151*/152size_t reserve;153/*154* Number of iovecs we have currently appended. This is the number of155* entries valid in txp->iovec.156*/157size_t num_iovec;158/* The EL this TX helper is being used for. */159uint32_t enc_level;160/*161* Whether we are allowed to make use of the reserve bytes in our MaxPPL162* budget. This is used to ensure we have room to append a PING frame later163* if we need to. Once we know we will not need to append a PING frame, this164* is set to 1.165*/166unsigned int reserve_allowed : 1;167/*168* Set to 1 if we have appended a STREAM frame with an implicit length. If169* this happens we should never append another frame after that frame as it170* cannot be validly encoded. This is just a safety check.171*/172unsigned int done_implicit : 1;173struct {174/*175* The fields in this structure are valid if active is set, which means176* that a serialization transaction is currently in progress.177*/178unsigned char *data;179WPACKET wpkt;180unsigned int active : 1;181} txn;182};183184static void tx_helper_rollback(struct tx_helper *h);185static int txp_el_ensure_iovec(struct txp_el *el, size_t num);186187/* Initialises the TX helper. */188static int tx_helper_init(struct tx_helper *h, OSSL_QUIC_TX_PACKETISER *txp,189uint32_t enc_level, size_t max_ppl, size_t reserve)190{191if (reserve > max_ppl)192return 0;193194h->txp = txp;195h->enc_level = enc_level;196h->max_ppl = max_ppl;197h->reserve = reserve;198h->num_iovec = 0;199h->bytes_appended = 0;200h->scratch_bytes = 0;201h->reserve_allowed = 0;202h->done_implicit = 0;203h->txn.data = NULL;204h->txn.active = 0;205206if (max_ppl > h->txp->el[enc_level].scratch_len) {207unsigned char *scratch;208209scratch = OPENSSL_realloc(h->txp->el[enc_level].scratch, max_ppl);210if (scratch == NULL)211return 0;212213h->txp->el[enc_level].scratch = scratch;214h->txp->el[enc_level].scratch_len = max_ppl;215}216217return 1;218}219220static void tx_helper_cleanup(struct tx_helper *h)221{222if (h->txn.active)223tx_helper_rollback(h);224225h->txp = NULL;226}227228static void tx_helper_unrestrict(struct tx_helper *h)229{230h->reserve_allowed = 1;231}232233/*234* Append an extent of memory to the iovec list. The memory must remain235* allocated until we finish generating the packet and call the QTX.236*237* In general, the buffers passed to this function will be from one of two238* ranges:239*240* - Application data contained in stream buffers managed elsewhere241* in the QUIC stack; or242*243* - Control frame data appended into txp->scratch using tx_helper_begin and244* tx_helper_commit.245*246*/247static int tx_helper_append_iovec(struct tx_helper *h,248const unsigned char *buf,249size_t buf_len)250{251struct txp_el *el = &h->txp->el[h->enc_level];252253if (buf_len == 0)254return 1;255256if (!ossl_assert(!h->done_implicit))257return 0;258259if (!txp_el_ensure_iovec(el, h->num_iovec + 1))260return 0;261262el->iovec[h->num_iovec].buf = buf;263el->iovec[h->num_iovec].buf_len = buf_len;264265++h->num_iovec;266h->bytes_appended += buf_len;267return 1;268}269270/*271* How many more bytes of space do we have left in our plaintext packet payload?272*/273static size_t tx_helper_get_space_left(struct tx_helper *h)274{275return h->max_ppl276- (h->reserve_allowed ? 0 : h->reserve) - h->bytes_appended;277}278279/*280* Begin a control frame serialization transaction. This allows the281* serialization of the control frame to be backed out if it turns out it won't282* fit. Write the control frame to the returned WPACKET. Ensure you always283* call tx_helper_rollback or tx_helper_commit (or tx_helper_cleanup). Returns284* NULL on failure.285*/286static WPACKET *tx_helper_begin(struct tx_helper *h)287{288size_t space_left, len;289unsigned char *data;290struct txp_el *el = &h->txp->el[h->enc_level];291292if (!ossl_assert(!h->txn.active))293return NULL;294295if (!ossl_assert(!h->done_implicit))296return NULL;297298data = (unsigned char *)el->scratch + h->scratch_bytes;299len = el->scratch_len - h->scratch_bytes;300301space_left = tx_helper_get_space_left(h);302if (!ossl_assert(space_left <= len))303return NULL;304305if (!WPACKET_init_static_len(&h->txn.wpkt, data, len, 0))306return NULL;307308if (!WPACKET_set_max_size(&h->txn.wpkt, space_left)) {309WPACKET_cleanup(&h->txn.wpkt);310return NULL;311}312313h->txn.data = data;314h->txn.active = 1;315return &h->txn.wpkt;316}317318static void tx_helper_end(struct tx_helper *h, int success)319{320if (success)321WPACKET_finish(&h->txn.wpkt);322else323WPACKET_cleanup(&h->txn.wpkt);324325h->txn.active = 0;326h->txn.data = NULL;327}328329/* Abort a control frame serialization transaction. */330static void tx_helper_rollback(struct tx_helper *h)331{332if (!h->txn.active)333return;334335tx_helper_end(h, 0);336}337338/* Commit a control frame. */339static int tx_helper_commit(struct tx_helper *h)340{341size_t l = 0;342343if (!h->txn.active)344return 0;345346if (!WPACKET_get_total_written(&h->txn.wpkt, &l)) {347tx_helper_end(h, 0);348return 0;349}350351if (!tx_helper_append_iovec(h, h->txn.data, l)) {352tx_helper_end(h, 0);353return 0;354}355356if (h->txp->msg_callback != NULL && l > 0) {357uint64_t ftype;358int ctype = SSL3_RT_QUIC_FRAME_FULL;359PACKET pkt;360361if (!PACKET_buf_init(&pkt, h->txn.data, l)362|| !ossl_quic_wire_peek_frame_header(&pkt, &ftype, NULL)) {363tx_helper_end(h, 0);364return 0;365}366367if (ftype == OSSL_QUIC_FRAME_TYPE_PADDING)368ctype = SSL3_RT_QUIC_FRAME_PADDING;369else if (OSSL_QUIC_FRAME_TYPE_IS_STREAM(ftype)370|| ftype == OSSL_QUIC_FRAME_TYPE_CRYPTO)371ctype = SSL3_RT_QUIC_FRAME_HEADER;372373h->txp->msg_callback(1, OSSL_QUIC1_VERSION, ctype, h->txn.data, l,374h->txp->msg_callback_ssl,375h->txp->msg_callback_arg);376}377378h->scratch_bytes += l;379tx_helper_end(h, 1);380return 1;381}382383struct archetype_data {384unsigned int allow_ack : 1;385unsigned int allow_ping : 1;386unsigned int allow_crypto : 1;387unsigned int allow_handshake_done : 1;388unsigned int allow_path_challenge : 1;389unsigned int allow_path_response : 1;390unsigned int allow_new_conn_id : 1;391unsigned int allow_retire_conn_id : 1;392unsigned int allow_stream_rel : 1;393unsigned int allow_conn_fc : 1;394unsigned int allow_conn_close : 1;395unsigned int allow_cfq_other : 1;396unsigned int allow_new_token : 1;397unsigned int allow_force_ack_eliciting : 1;398unsigned int allow_padding : 1;399unsigned int require_ack_eliciting : 1;400unsigned int bypass_cc : 1;401};402403struct txp_pkt_geom {404size_t cmpl, cmppl, hwm, pkt_overhead;405uint32_t archetype;406struct archetype_data adata;407};408409struct txp_pkt {410struct tx_helper h;411int h_valid;412QUIC_TXPIM_PKT *tpkt;413QUIC_STREAM *stream_head;414QUIC_PKT_HDR phdr;415struct txp_pkt_geom geom;416int force_pad;417};418419static QUIC_SSTREAM *get_sstream_by_id(uint64_t stream_id, uint32_t pn_space,420void *arg);421static void on_regen_notify(uint64_t frame_type, uint64_t stream_id,422QUIC_TXPIM_PKT *pkt, void *arg);423static void on_confirm_notify(uint64_t frame_type, uint64_t stream_id,424QUIC_TXPIM_PKT *pkt, void *arg);425static void on_sstream_updated(uint64_t stream_id, void *arg);426static int sstream_is_pending(QUIC_SSTREAM *sstream);427static int txp_should_try_staging(OSSL_QUIC_TX_PACKETISER *txp,428uint32_t enc_level,429uint32_t archetype,430uint64_t cc_limit,431uint32_t *conn_close_enc_level);432static size_t txp_determine_pn_len(OSSL_QUIC_TX_PACKETISER *txp);433static int txp_determine_ppl_from_pl(OSSL_QUIC_TX_PACKETISER *txp,434size_t pl,435uint32_t enc_level,436size_t hdr_len,437size_t *r);438static size_t txp_get_mdpl(OSSL_QUIC_TX_PACKETISER *txp);439static int txp_generate_for_el(OSSL_QUIC_TX_PACKETISER *txp,440struct txp_pkt *pkt,441int chosen_for_conn_close);442static int txp_pkt_init(struct txp_pkt *pkt, OSSL_QUIC_TX_PACKETISER *txp,443uint32_t enc_level, uint32_t archetype,444size_t running_total);445static void txp_pkt_cleanup(struct txp_pkt *pkt, OSSL_QUIC_TX_PACKETISER *txp);446static int txp_pkt_postgen_update_pkt_overhead(struct txp_pkt *pkt,447OSSL_QUIC_TX_PACKETISER *txp);448static int txp_pkt_append_padding(struct txp_pkt *pkt,449OSSL_QUIC_TX_PACKETISER *txp, size_t num_bytes);450static int txp_pkt_commit(OSSL_QUIC_TX_PACKETISER *txp, struct txp_pkt *pkt,451uint32_t archetype, int *txpim_pkt_reffed);452static uint32_t txp_determine_archetype(OSSL_QUIC_TX_PACKETISER *txp,453uint64_t cc_limit);454455/**456* Sets the validated state of a QUIC TX packetiser.457*458* This function marks the provided QUIC TX packetiser as having its credit459* fully validated by setting its `unvalidated_credit` field to `SIZE_MAX`.460*461* @param txp A pointer to the OSSL_QUIC_TX_PACKETISER structure to update.462*/463void ossl_quic_tx_packetiser_set_validated(OSSL_QUIC_TX_PACKETISER *txp)464{465txp->unvalidated_credit = SIZE_MAX;466return;467}468469/**470* Adds unvalidated credit to a QUIC TX packetiser.471*472* This function increases the unvalidated credit of the provided QUIC TX473* packetiser. If the current unvalidated credit is not `SIZE_MAX`, the474* function adds three times the specified `credit` value, ensuring it does475* not exceed the maximum allowable value (`SIZE_MAX - 1`). If the addition476* would cause an overflow, the unvalidated credit is capped at477* `SIZE_MAX - 1`. If the current unvalidated credit is already `SIZE_MAX`,478* the function does nothing.479*480* @param txp A pointer to the OSSL_QUIC_TX_PACKETISER structure to update.481* @param credit The amount of credit to add, multiplied by 3.482*/483void ossl_quic_tx_packetiser_add_unvalidated_credit(OSSL_QUIC_TX_PACKETISER *txp,484size_t credit)485{486if (txp->unvalidated_credit != SIZE_MAX) {487if ((SIZE_MAX - txp->unvalidated_credit) > (credit * 3))488txp->unvalidated_credit += credit * 3;489else490txp->unvalidated_credit = SIZE_MAX - 1;491}492493return;494}495496/**497* Consumes unvalidated credit from a QUIC TX packetiser.498*499* This function decreases the unvalidated credit of the specified500* QUIC TX packetiser by the given `credit` value. If the unvalidated credit501* is set to `SIZE_MAX`, the function does nothing, as `SIZE_MAX` represents502* an unlimited credit state.503*504* @param txp A pointer to the OSSL_QUIC_TX_PACKETISER structure to update.505* @param credit The amount of credit to consume.506*/507void ossl_quic_tx_packetiser_consume_unvalidated_credit(OSSL_QUIC_TX_PACKETISER *txp,508size_t credit)509{510if (txp->unvalidated_credit != SIZE_MAX) {511if (txp->unvalidated_credit < credit)512txp->unvalidated_credit = 0;513else514txp->unvalidated_credit -= credit;515}516}517518/**519* Checks if the QUIC TX packetiser has sufficient unvalidated credit.520*521* This function determines whether the unvalidated credit of the specified522* QUIC TX packetiser exceeds the required credit value (`req_credit`).523* If the unvalidated credit is greater than `req_credit`, the function524* returns 1 (true); otherwise, it returns 0 (false).525*526* @param txp A pointer to the OSSL_QUIC_TX_PACKETISER structure to check.527* @param req_credit The required credit value to compare against.528*529* @return 1 if the unvalidated credit exceeds `req_credit`, 0 otherwise.530*/531int ossl_quic_tx_packetiser_check_unvalidated_credit(OSSL_QUIC_TX_PACKETISER *txp,532size_t req_credit)533{534return (txp->unvalidated_credit > req_credit);535}536537OSSL_QUIC_TX_PACKETISER *ossl_quic_tx_packetiser_new(const OSSL_QUIC_TX_PACKETISER_ARGS *args)538{539OSSL_QUIC_TX_PACKETISER *txp;540541if (args == NULL542|| args->qtx == NULL543|| args->txpim == NULL544|| args->cfq == NULL545|| args->ackm == NULL546|| args->qsm == NULL547|| args->conn_txfc == NULL548|| args->conn_rxfc == NULL549|| args->max_streams_bidi_rxfc == NULL550|| args->max_streams_uni_rxfc == NULL551|| args->protocol_version == 0) {552ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);553return NULL;554}555556txp = OPENSSL_zalloc(sizeof(*txp));557if (txp == NULL)558return NULL;559560txp->args = *args;561txp->last_tx_time = ossl_time_zero();562563if (!ossl_quic_fifd_init(&txp->fifd,564txp->args.cfq, txp->args.ackm, txp->args.txpim,565get_sstream_by_id, txp,566on_regen_notify, txp,567on_confirm_notify, txp,568on_sstream_updated, txp,569args->get_qlog_cb,570args->get_qlog_cb_arg)) {571OPENSSL_free(txp);572return NULL;573}574575return txp;576}577578void ossl_quic_tx_packetiser_free(OSSL_QUIC_TX_PACKETISER *txp)579{580uint32_t enc_level;581582if (txp == NULL)583return;584585ossl_quic_tx_packetiser_set_initial_token(txp, NULL, 0, NULL, NULL);586ossl_quic_fifd_cleanup(&txp->fifd);587OPENSSL_free(txp->conn_close_frame.reason);588589for (enc_level = QUIC_ENC_LEVEL_INITIAL;590enc_level < QUIC_ENC_LEVEL_NUM;591++enc_level) {592OPENSSL_free(txp->el[enc_level].iovec);593OPENSSL_free(txp->el[enc_level].scratch);594}595596OPENSSL_free(txp);597}598599/*600* Determine if an Initial packet token length is reasonable based on the601* current MDPL, returning 1 if it is OK.602*603* The real PMTU to the peer could differ from our (pessimistic) understanding604* of the PMTU, therefore it is possible we could receive an Initial token from605* a server in a Retry packet which is bigger than the MDPL. In this case it is606* impossible for us ever to make forward progress and we need to error out607* and fail the connection attempt.608*609* The specific boundary condition is complex: for example, after the size of610* the Initial token, there are the Initial packet header overheads and then611* encryption/AEAD tag overheads. After that, the minimum room for frame data in612* order to guarantee forward progress must be guaranteed. For example, a crypto613* stream needs to always be able to serialize at least one byte in a CRYPTO614* frame in order to make forward progress. Because the offset field of a CRYPTO615* frame uses a variable-length integer, the number of bytes needed to ensure616* this also varies.617*618* Rather than trying to get this boundary condition check actually right,619* require a reasonable amount of slack to avoid pathological behaviours. (After620* all, transmitting a CRYPTO stream one byte at a time is probably not621* desirable anyway.)622*623* We choose 160 bytes as the required margin, which is double the rough624* estimation of the minimum we would require to guarantee forward progress625* under worst case packet overheads.626*/627#define TXP_REQUIRED_TOKEN_MARGIN 160628629static int txp_check_token_len(size_t token_len, size_t mdpl)630{631if (token_len == 0)632return 1;633634if (token_len >= mdpl)635return 0;636637if (TXP_REQUIRED_TOKEN_MARGIN >= mdpl)638/* (should not be possible because MDPL must be at least 1200) */639return 0;640641if (token_len > mdpl - TXP_REQUIRED_TOKEN_MARGIN)642return 0;643644return 1;645}646647int ossl_quic_tx_packetiser_set_initial_token(OSSL_QUIC_TX_PACKETISER *txp,648const unsigned char *token,649size_t token_len,650ossl_quic_initial_token_free_fn *free_cb,651void *free_cb_arg)652{653if (!txp_check_token_len(token_len, txp_get_mdpl(txp)))654return 0;655656if (txp->initial_token != NULL && txp->initial_token_free_cb != NULL)657txp->initial_token_free_cb(txp->initial_token, txp->initial_token_len,658txp->initial_token_free_cb_arg);659660txp->initial_token = token;661txp->initial_token_len = token_len;662txp->initial_token_free_cb = free_cb;663txp->initial_token_free_cb_arg = free_cb_arg;664return 1;665}666667int ossl_quic_tx_packetiser_set_protocol_version(OSSL_QUIC_TX_PACKETISER *txp,668uint32_t protocol_version)669{670txp->args.protocol_version = protocol_version;671return 1;672}673674int ossl_quic_tx_packetiser_set_cur_dcid(OSSL_QUIC_TX_PACKETISER *txp,675const QUIC_CONN_ID *dcid)676{677if (dcid == NULL) {678ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);679return 0;680}681682txp->args.cur_dcid = *dcid;683return 1;684}685686int ossl_quic_tx_packetiser_set_cur_scid(OSSL_QUIC_TX_PACKETISER *txp,687const QUIC_CONN_ID *scid)688{689if (scid == NULL) {690ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);691return 0;692}693694txp->args.cur_scid = *scid;695return 1;696}697698/* Change the destination L4 address the TXP uses to send datagrams. */699int ossl_quic_tx_packetiser_set_peer(OSSL_QUIC_TX_PACKETISER *txp,700const BIO_ADDR *peer)701{702if (peer == NULL) {703BIO_ADDR_clear(&txp->args.peer);704return 1;705}706707return BIO_ADDR_copy(&txp->args.peer, peer);708}709710void ossl_quic_tx_packetiser_set_ack_tx_cb(OSSL_QUIC_TX_PACKETISER *txp,711void (*cb)(const OSSL_QUIC_FRAME_ACK *ack,712uint32_t pn_space,713void *arg),714void *cb_arg)715{716txp->ack_tx_cb = cb;717txp->ack_tx_cb_arg = cb_arg;718}719720void ossl_quic_tx_packetiser_set_qlog_cb(OSSL_QUIC_TX_PACKETISER *txp,721QLOG *(*get_qlog_cb)(void *arg),722void *get_qlog_cb_arg)723{724ossl_quic_fifd_set_qlog_cb(&txp->fifd, get_qlog_cb, get_qlog_cb_arg);725726}727728int ossl_quic_tx_packetiser_discard_enc_level(OSSL_QUIC_TX_PACKETISER *txp,729uint32_t enc_level)730{731if (enc_level >= QUIC_ENC_LEVEL_NUM) {732ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);733return 0;734}735736if (enc_level != QUIC_ENC_LEVEL_0RTT)737txp->args.crypto[ossl_quic_enc_level_to_pn_space(enc_level)] = NULL;738739return 1;740}741742void ossl_quic_tx_packetiser_notify_handshake_complete(OSSL_QUIC_TX_PACKETISER *txp)743{744txp->handshake_complete = 1;745}746747void ossl_quic_tx_packetiser_schedule_handshake_done(OSSL_QUIC_TX_PACKETISER *txp)748{749txp->want_handshake_done = 1;750}751752void ossl_quic_tx_packetiser_schedule_ack_eliciting(OSSL_QUIC_TX_PACKETISER *txp,753uint32_t pn_space)754{755txp->force_ack_eliciting |= (1UL << pn_space);756}757758void ossl_quic_tx_packetiser_schedule_ack(OSSL_QUIC_TX_PACKETISER *txp,759uint32_t pn_space)760{761txp->want_ack |= (1UL << pn_space);762}763764#define TXP_ERR_INTERNAL 0 /* Internal (e.g. alloc) error */765#define TXP_ERR_SUCCESS 1 /* Success */766#define TXP_ERR_SPACE 2 /* Not enough room for another packet */767#define TXP_ERR_INPUT 3 /* Invalid/malformed input */768769/*770* Generates a datagram by polling the various ELs to determine if they want to771* generate any frames, and generating a datagram which coalesces packets for772* any ELs which do.773*/774int ossl_quic_tx_packetiser_generate(OSSL_QUIC_TX_PACKETISER *txp,775QUIC_TXP_STATUS *status)776{777/*778* Called to generate one or more datagrams, each containing one or more779* packets.780*781* There are some tricky things to note here:782*783* - The TXP is only concerned with generating encrypted packets;784* other packets use a different path.785*786* - Any datagram containing an Initial packet must have a payload length787* (DPL) of at least 1200 bytes. This padding need not necessarily be788* found in the Initial packet.789*790* - It is desirable to be able to coalesce an Initial packet791* with a Handshake packet. Since, before generating the Handshake792* packet, we do not know how long it will be, we cannot know the793* correct amount of padding to ensure a DPL of at least 1200 bytes.794* Thus this padding must added to the Handshake packet (or whatever795* packet is the last in the datagram).796*797* - However, at the time that we generate the Initial packet,798* we do not actually know for sure that we will be followed799* in the datagram by another packet. For example, suppose we have800* some queued data (e.g. crypto stream data for the HANDSHAKE EL)801* it looks like we will want to send on the HANDSHAKE EL.802* We could assume padding will be placed in the Handshake packet803* subsequently and avoid adding any padding to the Initial packet804* (which would leave no room for the Handshake packet in the805* datagram).806*807* However, this is not actually a safe assumption. Suppose that we808* are using a link with a MDPL of 1200 bytes, the minimum allowed by809* QUIC. Suppose that the Initial packet consumes 1195 bytes in total.810* Since it is not possible to fit a Handshake packet in just 5 bytes,811* upon trying to add a Handshake packet after generating the Initial812* packet, we will discover we have no room to fit it! This is not a813* problem in itself as another datagram can be sent subsequently, but814* it is a problem because we were counting to use that packet to hold815* the essential padding. But if we have already finished encrypting816* the Initial packet, we cannot go and add padding to it anymore.817* This leaves us stuck.818*819* Because of this, we have to plan multiple packets simultaneously, such820* that we can start generating a Handshake (or 0-RTT or 1-RTT, or so on)821* packet while still having the option to go back and add padding to the822* Initial packet if it turns out to be needed.823*824* Trying to predict ahead of time (e.g. during Initial packet generation)825* whether we will successfully generate a subsequent packet is fraught with826* error as it relies on a large number of variables:827*828* - Do we have room to fit a packet header? (Consider that due to829* variable-length integer encoding this is highly variable and can even830* depend on payload length due to a variable-length Length field.)831*832* - Can we fit even a single one of the frames we want to put in this833* packet in the packet? (Each frame type has a bespoke encoding. While834* our encodings of some frame types are adaptive based on the available835* room - e.g. STREAM frames - ultimately all frame types have some836* absolute minimum number of bytes to be successfully encoded. For837* example, if after an Initial packet there is enough room to encode838* only one byte of frame data, it is quite likely we can't send any of839* the frames we wanted to send.) While this is not strictly a problem840* because we could just fill the packet with padding frames, this is a841* pointless packet and is wasteful.842*843* Thus we adopt a multi-phase architecture:844*845* 1. Archetype Selection: Determine desired packet archetype.846*847* 2. Packet Staging: Generation of packet information and packet payload848* data (frame data) into staging areas.849*850* 3. Packet Adjustment: Adjustment of staged packets, adding padding to851* the staged packets if needed.852*853* 4. Commit: The packets are sent to the QTX and recorded as having been854* sent to the FIFM.855*856*/857int res = 0, rc;858uint32_t archetype, enc_level;859uint32_t conn_close_enc_level = QUIC_ENC_LEVEL_NUM;860struct txp_pkt pkt[QUIC_ENC_LEVEL_NUM];861size_t pkts_done = 0;862uint64_t cc_limit = txp->args.cc_method->get_tx_allowance(txp->args.cc_data);863int need_padding = 0, txpim_pkt_reffed;864865memset(status, 0, sizeof(*status));866867for (enc_level = QUIC_ENC_LEVEL_INITIAL;868enc_level < QUIC_ENC_LEVEL_NUM;869++enc_level)870pkt[enc_level].h_valid = 0;871872873/*874* Should not be needed, but a sanity check in case anyone else has been875* using the QTX.876*/877ossl_qtx_finish_dgram(txp->args.qtx);878879/* 1. Archetype Selection */880archetype = txp_determine_archetype(txp, cc_limit);881882/* 2. Packet Staging */883for (enc_level = QUIC_ENC_LEVEL_INITIAL;884enc_level < QUIC_ENC_LEVEL_NUM;885++enc_level) {886size_t running_total = (enc_level > QUIC_ENC_LEVEL_INITIAL)887? pkt[enc_level - 1].geom.hwm : 0;888889pkt[enc_level].geom.hwm = running_total;890891if (!txp_should_try_staging(txp, enc_level, archetype, cc_limit,892&conn_close_enc_level))893continue;894895if (!txp_pkt_init(&pkt[enc_level], txp, enc_level, archetype,896running_total))897/*898* If this fails this is not a fatal error - it means the geometry899* planning determined there was not enough space for another900* packet. So just proceed with what we've already planned for.901*/902break;903904rc = txp_generate_for_el(txp, &pkt[enc_level],905conn_close_enc_level == enc_level);906if (rc != TXP_ERR_SUCCESS)907goto out;908909if (pkt[enc_level].force_pad)910/*911* txp_generate_for_el emitted a frame which forces packet padding.912*/913need_padding = 1;914915pkt[enc_level].geom.hwm = running_total916+ pkt[enc_level].h.bytes_appended917+ pkt[enc_level].geom.pkt_overhead;918}919920/* 3. Packet Adjustment */921if (pkt[QUIC_ENC_LEVEL_INITIAL].h_valid922&& pkt[QUIC_ENC_LEVEL_INITIAL].h.bytes_appended > 0)923/*924* We have an Initial packet in this datagram, so we need to make sure925* the total size of the datagram is adequate.926*/927need_padding = 1;928929if (need_padding) {930size_t total_dgram_size = 0;931const size_t min_dpl = QUIC_MIN_INITIAL_DGRAM_LEN;932uint32_t pad_el = QUIC_ENC_LEVEL_NUM;933934for (enc_level = QUIC_ENC_LEVEL_INITIAL;935enc_level < QUIC_ENC_LEVEL_NUM;936++enc_level)937if (pkt[enc_level].h_valid && pkt[enc_level].h.bytes_appended > 0) {938if (pad_el == QUIC_ENC_LEVEL_NUM939/*940* We might not be able to add padding, for example if we941* are using the ACK_ONLY archetype.942*/943&& pkt[enc_level].geom.adata.allow_padding944&& !pkt[enc_level].h.done_implicit)945pad_el = enc_level;946947txp_pkt_postgen_update_pkt_overhead(&pkt[enc_level], txp);948total_dgram_size += pkt[enc_level].geom.pkt_overhead949+ pkt[enc_level].h.bytes_appended;950}951952if (pad_el != QUIC_ENC_LEVEL_NUM && total_dgram_size < min_dpl) {953size_t deficit = min_dpl - total_dgram_size;954955if (!txp_pkt_append_padding(&pkt[pad_el], txp, deficit))956goto out;957958total_dgram_size += deficit;959960/*961* Padding frames make a packet ineligible for being a non-inflight962* packet.963*/964pkt[pad_el].tpkt->ackm_pkt.is_inflight = 1;965}966967/*968* If we have failed to make a datagram of adequate size, for example969* because we have a padding requirement but are using the ACK_ONLY970* archetype (because we are CC limited), which precludes us from971* sending padding, give up on generating the datagram - there is972* nothing we can do.973*/974if (total_dgram_size < min_dpl) {975res = 1;976goto out;977}978}979980/* 4. Commit */981for (enc_level = QUIC_ENC_LEVEL_INITIAL;982enc_level < QUIC_ENC_LEVEL_NUM;983++enc_level) {984985if (!pkt[enc_level].h_valid)986/* Did not attempt to generate a packet for this EL. */987continue;988989if (pkt[enc_level].h.bytes_appended == 0)990/* Nothing was generated for this EL, so skip. */991continue;992993if (!ossl_quic_tx_packetiser_check_unvalidated_credit(txp,994pkt[enc_level].h.bytes_appended)) {995res = TXP_ERR_SPACE;996goto out;997}998ossl_quic_tx_packetiser_consume_unvalidated_credit(txp, pkt[enc_level].h.bytes_appended);9991000rc = txp_pkt_commit(txp, &pkt[enc_level], archetype,1001&txpim_pkt_reffed);1002if (rc) {1003status->sent_ack_eliciting1004= status->sent_ack_eliciting1005|| pkt[enc_level].tpkt->ackm_pkt.is_ack_eliciting;10061007if (enc_level == QUIC_ENC_LEVEL_HANDSHAKE)1008status->sent_handshake1009= (pkt[enc_level].h_valid1010&& pkt[enc_level].h.bytes_appended > 0);1011}10121013if (txpim_pkt_reffed)1014pkt[enc_level].tpkt = NULL; /* don't free */10151016if (!rc)1017goto out;10181019++pkts_done;10201021}10221023/* Flush & Cleanup */1024res = 1;1025out:1026ossl_qtx_finish_dgram(txp->args.qtx);10271028for (enc_level = QUIC_ENC_LEVEL_INITIAL;1029enc_level < QUIC_ENC_LEVEL_NUM;1030++enc_level)1031txp_pkt_cleanup(&pkt[enc_level], txp);10321033status->sent_pkt = pkts_done;10341035return res;1036}10371038static const struct archetype_data archetypes[QUIC_ENC_LEVEL_NUM][TX_PACKETISER_ARCHETYPE_NUM] = {1039/* EL 0(INITIAL) */1040{1041/* EL 0(INITIAL) - Archetype 0(NORMAL) */1042{1043/*allow_ack =*/ 1,1044/*allow_ping =*/ 1,1045/*allow_crypto =*/ 1,1046/*allow_handshake_done =*/ 0,1047/*allow_path_challenge =*/ 0,1048/*allow_path_response =*/ 0,1049/*allow_new_conn_id =*/ 0,1050/*allow_retire_conn_id =*/ 0,1051/*allow_stream_rel =*/ 0,1052/*allow_conn_fc =*/ 0,1053/*allow_conn_close =*/ 1,1054/*allow_cfq_other =*/ 0,1055/*allow_new_token =*/ 0,1056/*allow_force_ack_eliciting =*/ 1,1057/*allow_padding =*/ 1,1058/*require_ack_eliciting =*/ 0,1059/*bypass_cc =*/ 0,1060},1061/* EL 0(INITIAL) - Archetype 1(PROBE) */1062{1063/*allow_ack =*/ 1,1064/*allow_ping =*/ 1,1065/*allow_crypto =*/ 1,1066/*allow_handshake_done =*/ 0,1067/*allow_path_challenge =*/ 0,1068/*allow_path_response =*/ 0,1069/*allow_new_conn_id =*/ 0,1070/*allow_retire_conn_id =*/ 0,1071/*allow_stream_rel =*/ 0,1072/*allow_conn_fc =*/ 0,1073/*allow_conn_close =*/ 1,1074/*allow_cfq_other =*/ 0,1075/*allow_new_token =*/ 0,1076/*allow_force_ack_eliciting =*/ 1,1077/*allow_padding =*/ 1,1078/*require_ack_eliciting =*/ 1,1079/*bypass_cc =*/ 1,1080},1081/* EL 0(INITIAL) - Archetype 2(ACK_ONLY) */1082{1083/*allow_ack =*/ 1,1084/*allow_ping =*/ 0,1085/*allow_crypto =*/ 0,1086/*allow_handshake_done =*/ 0,1087/*allow_path_challenge =*/ 0,1088/*allow_path_response =*/ 0,1089/*allow_new_conn_id =*/ 0,1090/*allow_retire_conn_id =*/ 0,1091/*allow_stream_rel =*/ 0,1092/*allow_conn_fc =*/ 0,1093/*allow_conn_close =*/ 0,1094/*allow_cfq_other =*/ 0,1095/*allow_new_token =*/ 0,1096/*allow_force_ack_eliciting =*/ 1,1097/*allow_padding =*/ 0,1098/*require_ack_eliciting =*/ 0,1099/*bypass_cc =*/ 1,1100},1101},1102/* EL 1(0RTT) */1103{1104/* EL 1(0RTT) - Archetype 0(NORMAL) */1105{1106/*allow_ack =*/ 0,1107/*allow_ping =*/ 1,1108/*allow_crypto =*/ 0,1109/*allow_handshake_done =*/ 0,1110/*allow_path_challenge =*/ 0,1111/*allow_path_response =*/ 0,1112/*allow_new_conn_id =*/ 1,1113/*allow_retire_conn_id =*/ 1,1114/*allow_stream_rel =*/ 1,1115/*allow_conn_fc =*/ 1,1116/*allow_conn_close =*/ 1,1117/*allow_cfq_other =*/ 0,1118/*allow_new_token =*/ 0,1119/*allow_force_ack_eliciting =*/ 0,1120/*allow_padding =*/ 1,1121/*require_ack_eliciting =*/ 0,1122/*bypass_cc =*/ 0,1123},1124/* EL 1(0RTT) - Archetype 1(PROBE) */1125{1126/*allow_ack =*/ 0,1127/*allow_ping =*/ 1,1128/*allow_crypto =*/ 0,1129/*allow_handshake_done =*/ 0,1130/*allow_path_challenge =*/ 0,1131/*allow_path_response =*/ 0,1132/*allow_new_conn_id =*/ 1,1133/*allow_retire_conn_id =*/ 1,1134/*allow_stream_rel =*/ 1,1135/*allow_conn_fc =*/ 1,1136/*allow_conn_close =*/ 1,1137/*allow_cfq_other =*/ 0,1138/*allow_new_token =*/ 0,1139/*allow_force_ack_eliciting =*/ 0,1140/*allow_padding =*/ 1,1141/*require_ack_eliciting =*/ 1,1142/*bypass_cc =*/ 1,1143},1144/* EL 1(0RTT) - Archetype 2(ACK_ONLY) */1145{1146/*allow_ack =*/ 0,1147/*allow_ping =*/ 0,1148/*allow_crypto =*/ 0,1149/*allow_handshake_done =*/ 0,1150/*allow_path_challenge =*/ 0,1151/*allow_path_response =*/ 0,1152/*allow_new_conn_id =*/ 0,1153/*allow_retire_conn_id =*/ 0,1154/*allow_stream_rel =*/ 0,1155/*allow_conn_fc =*/ 0,1156/*allow_conn_close =*/ 0,1157/*allow_cfq_other =*/ 0,1158/*allow_new_token =*/ 0,1159/*allow_force_ack_eliciting =*/ 0,1160/*allow_padding =*/ 0,1161/*require_ack_eliciting =*/ 0,1162/*bypass_cc =*/ 1,1163},1164},1165/* EL (HANDSHAKE) */1166{1167/* EL 2(HANDSHAKE) - Archetype 0(NORMAL) */1168{1169/*allow_ack =*/ 1,1170/*allow_ping =*/ 1,1171/*allow_crypto =*/ 1,1172/*allow_handshake_done =*/ 0,1173/*allow_path_challenge =*/ 0,1174/*allow_path_response =*/ 0,1175/*allow_new_conn_id =*/ 0,1176/*allow_retire_conn_id =*/ 0,1177/*allow_stream_rel =*/ 0,1178/*allow_conn_fc =*/ 0,1179/*allow_conn_close =*/ 1,1180/*allow_cfq_other =*/ 0,1181/*allow_new_token =*/ 0,1182/*allow_force_ack_eliciting =*/ 1,1183/*allow_padding =*/ 1,1184/*require_ack_eliciting =*/ 0,1185/*bypass_cc =*/ 0,1186},1187/* EL 2(HANDSHAKE) - Archetype 1(PROBE) */1188{1189/*allow_ack =*/ 1,1190/*allow_ping =*/ 1,1191/*allow_crypto =*/ 1,1192/*allow_handshake_done =*/ 0,1193/*allow_path_challenge =*/ 0,1194/*allow_path_response =*/ 0,1195/*allow_new_conn_id =*/ 0,1196/*allow_retire_conn_id =*/ 0,1197/*allow_stream_rel =*/ 0,1198/*allow_conn_fc =*/ 0,1199/*allow_conn_close =*/ 1,1200/*allow_cfq_other =*/ 0,1201/*allow_new_token =*/ 0,1202/*allow_force_ack_eliciting =*/ 1,1203/*allow_padding =*/ 1,1204/*require_ack_eliciting =*/ 1,1205/*bypass_cc =*/ 1,1206},1207/* EL 2(HANDSHAKE) - Archetype 2(ACK_ONLY) */1208{1209/*allow_ack =*/ 1,1210/*allow_ping =*/ 0,1211/*allow_crypto =*/ 0,1212/*allow_handshake_done =*/ 0,1213/*allow_path_challenge =*/ 0,1214/*allow_path_response =*/ 0,1215/*allow_new_conn_id =*/ 0,1216/*allow_retire_conn_id =*/ 0,1217/*allow_stream_rel =*/ 0,1218/*allow_conn_fc =*/ 0,1219/*allow_conn_close =*/ 0,1220/*allow_cfq_other =*/ 0,1221/*allow_new_token =*/ 0,1222/*allow_force_ack_eliciting =*/ 1,1223/*allow_padding =*/ 0,1224/*require_ack_eliciting =*/ 0,1225/*bypass_cc =*/ 1,1226},1227},1228/* EL 3(1RTT) */1229{1230/* EL 3(1RTT) - Archetype 0(NORMAL) */1231{1232/*allow_ack =*/ 1,1233/*allow_ping =*/ 1,1234/*allow_crypto =*/ 1,1235/*allow_handshake_done =*/ 1,1236/*allow_path_challenge =*/ 0,1237/*allow_path_response =*/ 1,1238/*allow_new_conn_id =*/ 1,1239/*allow_retire_conn_id =*/ 1,1240/*allow_stream_rel =*/ 1,1241/*allow_conn_fc =*/ 1,1242/*allow_conn_close =*/ 1,1243/*allow_cfq_other =*/ 1,1244/*allow_new_token =*/ 1,1245/*allow_force_ack_eliciting =*/ 1,1246/*allow_padding =*/ 1,1247/*require_ack_eliciting =*/ 0,1248/*bypass_cc =*/ 0,1249},1250/* EL 3(1RTT) - Archetype 1(PROBE) */1251{1252/*allow_ack =*/ 1,1253/*allow_ping =*/ 1,1254/*allow_crypto =*/ 1,1255/*allow_handshake_done =*/ 1,1256/*allow_path_challenge =*/ 0,1257/*allow_path_response =*/ 1,1258/*allow_new_conn_id =*/ 1,1259/*allow_retire_conn_id =*/ 1,1260/*allow_stream_rel =*/ 1,1261/*allow_conn_fc =*/ 1,1262/*allow_conn_close =*/ 1,1263/*allow_cfq_other =*/ 1,1264/*allow_new_token =*/ 1,1265/*allow_force_ack_eliciting =*/ 1,1266/*allow_padding =*/ 1,1267/*require_ack_eliciting =*/ 1,1268/*bypass_cc =*/ 1,1269},1270/* EL 3(1RTT) - Archetype 2(ACK_ONLY) */1271{1272/*allow_ack =*/ 1,1273/*allow_ping =*/ 0,1274/*allow_crypto =*/ 0,1275/*allow_handshake_done =*/ 0,1276/*allow_path_challenge =*/ 0,1277/*allow_path_response =*/ 0,1278/*allow_new_conn_id =*/ 0,1279/*allow_retire_conn_id =*/ 0,1280/*allow_stream_rel =*/ 0,1281/*allow_conn_fc =*/ 0,1282/*allow_conn_close =*/ 0,1283/*allow_cfq_other =*/ 0,1284/*allow_new_token =*/ 0,1285/*allow_force_ack_eliciting =*/ 1,1286/*allow_padding =*/ 0,1287/*require_ack_eliciting =*/ 0,1288/*bypass_cc =*/ 1,1289}1290}1291};12921293static int txp_get_archetype_data(uint32_t enc_level,1294uint32_t archetype,1295struct archetype_data *a)1296{1297if (enc_level >= QUIC_ENC_LEVEL_NUM1298|| archetype >= TX_PACKETISER_ARCHETYPE_NUM)1299return 0;13001301/* No need to avoid copying this as it should not exceed one int in size. */1302*a = archetypes[enc_level][archetype];1303return 1;1304}13051306static int txp_determine_geometry(OSSL_QUIC_TX_PACKETISER *txp,1307uint32_t archetype,1308uint32_t enc_level,1309size_t running_total,1310QUIC_PKT_HDR *phdr,1311struct txp_pkt_geom *geom)1312{1313size_t mdpl, cmpl, hdr_len;13141315/* Get information about packet archetype. */1316if (!txp_get_archetype_data(enc_level, archetype, &geom->adata))1317return 0;13181319/* Assemble packet header. */1320phdr->type = ossl_quic_enc_level_to_pkt_type(enc_level);1321phdr->spin_bit = 0;1322phdr->pn_len = txp_determine_pn_len(txp);1323phdr->partial = 0;1324phdr->fixed = 1;1325phdr->reserved = 0;1326phdr->version = txp->args.protocol_version;1327phdr->dst_conn_id = txp->args.cur_dcid;1328phdr->src_conn_id = txp->args.cur_scid;13291330/*1331* We need to know the length of the payload to get an accurate header1332* length for non-1RTT packets, because the Length field found in1333* Initial/Handshake/0-RTT packets uses a variable-length encoding. However,1334* we don't have a good idea of the length of our payload, because the1335* length of the payload depends on the room in the datagram after fitting1336* the header, which depends on the size of the header.1337*1338* In general, it does not matter if a packet is slightly shorter (because1339* e.g. we predicted use of a 2-byte length field, but ended up only needing1340* a 1-byte length field). However this does matter for Initial packets1341* which must be at least 1200 bytes, which is also the assumed default MTU;1342* therefore in many cases Initial packets will be padded to 1200 bytes,1343* which means if we overestimated the header size, we will be short by a1344* few bytes and the server will ignore the packet for being too short. In1345* this case, however, such packets always *will* be padded to meet 12001346* bytes, which requires a 2-byte length field, so we don't actually need to1347* worry about this. Thus we estimate the header length assuming a 2-byte1348* length field here, which should in practice work well in all cases.1349*/1350phdr->len = OSSL_QUIC_VLINT_2B_MAX - phdr->pn_len;13511352if (enc_level == QUIC_ENC_LEVEL_INITIAL) {1353phdr->token = txp->initial_token;1354phdr->token_len = txp->initial_token_len;1355} else {1356phdr->token = NULL;1357phdr->token_len = 0;1358}13591360hdr_len = ossl_quic_wire_get_encoded_pkt_hdr_len(phdr->dst_conn_id.id_len,1361phdr);1362if (hdr_len == 0)1363return 0;13641365/* MDPL: Maximum datagram payload length. */1366mdpl = txp_get_mdpl(txp);13671368/*1369* CMPL: Maximum encoded packet size we can put into this datagram given any1370* previous packets coalesced into it.1371*/1372if (running_total > mdpl)1373/* Should not be possible, but if it happens: */1374cmpl = 0;1375else1376cmpl = mdpl - running_total;13771378/* CMPPL: Maximum amount we can put into the current packet payload */1379if (!txp_determine_ppl_from_pl(txp, cmpl, enc_level, hdr_len, &geom->cmppl))1380return 0;13811382geom->cmpl = cmpl;1383geom->pkt_overhead = cmpl - geom->cmppl;1384geom->archetype = archetype;1385return 1;1386}13871388static uint32_t txp_determine_archetype(OSSL_QUIC_TX_PACKETISER *txp,1389uint64_t cc_limit)1390{1391OSSL_ACKM_PROBE_INFO *probe_info1392= ossl_ackm_get0_probe_request(txp->args.ackm);1393uint32_t pn_space;13941395/*1396* If ACKM has requested probe generation (e.g. due to PTO), we generate a1397* Probe-archetype packet. Actually, we determine archetype on a1398* per-datagram basis, so if any EL wants a probe, do a pass in which1399* we try and generate a probe (if needed) for all ELs.1400*/1401if (probe_info->anti_deadlock_initial > 01402|| probe_info->anti_deadlock_handshake > 0)1403return TX_PACKETISER_ARCHETYPE_PROBE;14041405for (pn_space = QUIC_PN_SPACE_INITIAL;1406pn_space < QUIC_PN_SPACE_NUM;1407++pn_space)1408if (probe_info->pto[pn_space] > 0)1409return TX_PACKETISER_ARCHETYPE_PROBE;14101411/*1412* If we are out of CC budget, we cannot send a normal packet,1413* but we can do an ACK-only packet (potentially, if we1414* want to send an ACK).1415*/1416if (cc_limit == 0)1417return TX_PACKETISER_ARCHETYPE_ACK_ONLY;14181419/* All other packets. */1420return TX_PACKETISER_ARCHETYPE_NORMAL;1421}14221423static int txp_should_try_staging(OSSL_QUIC_TX_PACKETISER *txp,1424uint32_t enc_level,1425uint32_t archetype,1426uint64_t cc_limit,1427uint32_t *conn_close_enc_level)1428{1429struct archetype_data a;1430uint32_t pn_space = ossl_quic_enc_level_to_pn_space(enc_level);1431QUIC_CFQ_ITEM *cfq_item;14321433if (!ossl_qtx_is_enc_level_provisioned(txp->args.qtx, enc_level))1434return 0;14351436if (!txp_get_archetype_data(enc_level, archetype, &a))1437return 0;14381439if (!a.bypass_cc && cc_limit == 0)1440/* CC not allowing us to send. */1441return 0;14421443/*1444* We can produce CONNECTION_CLOSE frames on any EL in principle, which1445* means we need to choose which EL we would prefer to use. After a1446* connection is fully established we have only one provisioned EL and this1447* is a non-issue. Where multiple ELs are provisioned, it is possible the1448* peer does not have the keys for the EL yet, which suggests in general it1449* is preferable to use the lowest EL which is still provisioned.1450*1451* However (RFC 9000 s. 10.2.3 & 12.5) we are also required to not send1452* application CONNECTION_CLOSE frames in non-1-RTT ELs, so as to not1453* potentially leak application data on a connection which has yet to be1454* authenticated. Thus when we have an application CONNECTION_CLOSE frame1455* queued and need to send it on a non-1-RTT EL, we have to convert it1456* into a transport CONNECTION_CLOSE frame which contains no application1457* data. Since this loses information, it suggests we should use the 1-RTT1458* EL to avoid this if possible, even if a lower EL is also available.1459*1460* At the same time, just because we have the 1-RTT EL provisioned locally1461* does not necessarily mean the peer does, for example if a handshake1462* CRYPTO frame has been lost. It is fairly important that CONNECTION_CLOSE1463* is signalled in a way we know our peer can decrypt, as we stop processing1464* connection retransmission logic for real after connection close and1465* simply 'blindly' retransmit the same CONNECTION_CLOSE frame.1466*1467* This is not a major concern for clients, since if a client has a 1-RTT EL1468* provisioned the server is guaranteed to also have a 1-RTT EL provisioned.1469*1470* TODO(QUIC FUTURE): Revisit this when when have reached a decision on how1471* best to implement this1472*/1473if (*conn_close_enc_level > enc_level1474&& *conn_close_enc_level != QUIC_ENC_LEVEL_1RTT)1475*conn_close_enc_level = enc_level;14761477/* Do we need to send a PTO probe? */1478if (a.allow_force_ack_eliciting) {1479OSSL_ACKM_PROBE_INFO *probe_info1480= ossl_ackm_get0_probe_request(txp->args.ackm);14811482if ((enc_level == QUIC_ENC_LEVEL_INITIAL1483&& probe_info->anti_deadlock_initial > 0)1484|| (enc_level == QUIC_ENC_LEVEL_HANDSHAKE1485&& probe_info->anti_deadlock_handshake > 0)1486|| probe_info->pto[pn_space] > 0)1487return 1;1488}14891490/* Does the crypto stream for this EL want to produce anything? */1491if (a.allow_crypto && sstream_is_pending(txp->args.crypto[pn_space]))1492return 1;14931494/* Does the ACKM for this PN space want to produce anything? */1495if (a.allow_ack && (ossl_ackm_is_ack_desired(txp->args.ackm, pn_space)1496|| (txp->want_ack & (1UL << pn_space)) != 0))1497return 1;14981499/* Do we need to force emission of an ACK-eliciting packet? */1500if (a.allow_force_ack_eliciting1501&& (txp->force_ack_eliciting & (1UL << pn_space)) != 0)1502return 1;15031504/* Does the connection-level RXFC want to produce a frame? */1505if (a.allow_conn_fc && (txp->want_max_data1506|| ossl_quic_rxfc_has_cwm_changed(txp->args.conn_rxfc, 0)))1507return 1;15081509/* Do we want to produce a MAX_STREAMS frame? */1510if (a.allow_conn_fc1511&& (txp->want_max_streams_bidi1512|| ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_bidi_rxfc,15130)1514|| txp->want_max_streams_uni1515|| ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_uni_rxfc,15160)))1517return 1;15181519/* Do we want to produce a HANDSHAKE_DONE frame? */1520if (a.allow_handshake_done && txp->want_handshake_done)1521return 1;15221523/* Do we want to produce a CONNECTION_CLOSE frame? */1524if (a.allow_conn_close && txp->want_conn_close &&1525*conn_close_enc_level == enc_level)1526/*1527* This is a bit of a special case since CONNECTION_CLOSE can appear in1528* most packet types, and when we decide we want to send it this status1529* isn't tied to a specific EL. So if we want to send it, we send it1530* only on the lowest non-dropped EL.1531*/1532return 1;15331534/* Does the CFQ have any frames queued for this PN space? */1535if (enc_level != QUIC_ENC_LEVEL_0RTT)1536for (cfq_item = ossl_quic_cfq_get_priority_head(txp->args.cfq, pn_space);1537cfq_item != NULL;1538cfq_item = ossl_quic_cfq_item_get_priority_next(cfq_item, pn_space)) {1539uint64_t frame_type = ossl_quic_cfq_item_get_frame_type(cfq_item);15401541switch (frame_type) {1542case OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID:1543if (a.allow_new_conn_id)1544return 1;1545break;1546case OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID:1547if (a.allow_retire_conn_id)1548return 1;1549break;1550case OSSL_QUIC_FRAME_TYPE_NEW_TOKEN:1551if (a.allow_new_token)1552return 1;1553break;1554case OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE:1555if (a.allow_path_response)1556return 1;1557break;1558default:1559if (a.allow_cfq_other)1560return 1;1561break;1562}1563}15641565if (a.allow_stream_rel && txp->handshake_complete) {1566QUIC_STREAM_ITER it;15671568/* If there are any active streams, 0/1-RTT wants to produce a packet.1569* Whether a stream is on the active list is required to be precise1570* (i.e., a stream is never on the active list if we cannot produce a1571* frame for it), and all stream-related frames are governed by1572* a.allow_stream_rel (i.e., if we can send one type of stream-related1573* frame, we can send any of them), so we don't need to inspect1574* individual streams on the active list, just confirm that the active1575* list is non-empty.1576*/1577ossl_quic_stream_iter_init(&it, txp->args.qsm, 0);1578if (it.stream != NULL)1579return 1;1580}15811582return 0;1583}15841585static int sstream_is_pending(QUIC_SSTREAM *sstream)1586{1587OSSL_QUIC_FRAME_STREAM hdr;1588OSSL_QTX_IOVEC iov[2];1589size_t num_iov = OSSL_NELEM(iov);15901591return ossl_quic_sstream_get_stream_frame(sstream, 0, &hdr, iov, &num_iov);1592}15931594/* Determine how many bytes we should use for the encoded PN. */1595static size_t txp_determine_pn_len(OSSL_QUIC_TX_PACKETISER *txp)1596{1597return 4; /* TODO(QUIC FUTURE) */1598}15991600/* Determine plaintext packet payload length from payload length. */1601static int txp_determine_ppl_from_pl(OSSL_QUIC_TX_PACKETISER *txp,1602size_t pl,1603uint32_t enc_level,1604size_t hdr_len,1605size_t *r)1606{1607if (pl < hdr_len)1608return 0;16091610pl -= hdr_len;16111612if (!ossl_qtx_calculate_plaintext_payload_len(txp->args.qtx, enc_level,1613pl, &pl))1614return 0;16151616*r = pl;1617return 1;1618}16191620static size_t txp_get_mdpl(OSSL_QUIC_TX_PACKETISER *txp)1621{1622return ossl_qtx_get_mdpl(txp->args.qtx);1623}16241625static QUIC_SSTREAM *get_sstream_by_id(uint64_t stream_id, uint32_t pn_space,1626void *arg)1627{1628OSSL_QUIC_TX_PACKETISER *txp = arg;1629QUIC_STREAM *s;16301631if (stream_id == UINT64_MAX)1632return txp->args.crypto[pn_space];16331634s = ossl_quic_stream_map_get_by_id(txp->args.qsm, stream_id);1635if (s == NULL)1636return NULL;16371638return s->sstream;1639}16401641static void on_regen_notify(uint64_t frame_type, uint64_t stream_id,1642QUIC_TXPIM_PKT *pkt, void *arg)1643{1644OSSL_QUIC_TX_PACKETISER *txp = arg;16451646switch (frame_type) {1647case OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE:1648txp->want_handshake_done = 1;1649break;1650case OSSL_QUIC_FRAME_TYPE_MAX_DATA:1651txp->want_max_data = 1;1652break;1653case OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI:1654txp->want_max_streams_bidi = 1;1655break;1656case OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI:1657txp->want_max_streams_uni = 1;1658break;1659case OSSL_QUIC_FRAME_TYPE_ACK_WITH_ECN:1660txp->want_ack |= (1UL << pkt->ackm_pkt.pkt_space);1661break;1662case OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA:1663{1664QUIC_STREAM *s1665= ossl_quic_stream_map_get_by_id(txp->args.qsm, stream_id);16661667if (s == NULL)1668return;16691670s->want_max_stream_data = 1;1671ossl_quic_stream_map_update_state(txp->args.qsm, s);1672}1673break;1674case OSSL_QUIC_FRAME_TYPE_STOP_SENDING:1675{1676QUIC_STREAM *s1677= ossl_quic_stream_map_get_by_id(txp->args.qsm, stream_id);16781679if (s == NULL)1680return;16811682ossl_quic_stream_map_schedule_stop_sending(txp->args.qsm, s);1683}1684break;1685case OSSL_QUIC_FRAME_TYPE_RESET_STREAM:1686{1687QUIC_STREAM *s1688= ossl_quic_stream_map_get_by_id(txp->args.qsm, stream_id);16891690if (s == NULL)1691return;16921693s->want_reset_stream = 1;1694ossl_quic_stream_map_update_state(txp->args.qsm, s);1695}1696break;1697default:1698assert(0);1699break;1700}1701}17021703static int txp_need_ping(OSSL_QUIC_TX_PACKETISER *txp,1704uint32_t pn_space,1705const struct archetype_data *adata)1706{1707return adata->allow_ping1708&& (adata->require_ack_eliciting1709|| (txp->force_ack_eliciting & (1UL << pn_space)) != 0);1710}17111712static int txp_pkt_init(struct txp_pkt *pkt, OSSL_QUIC_TX_PACKETISER *txp,1713uint32_t enc_level, uint32_t archetype,1714size_t running_total)1715{1716uint32_t pn_space = ossl_quic_enc_level_to_pn_space(enc_level);17171718if (!txp_determine_geometry(txp, archetype, enc_level,1719running_total, &pkt->phdr, &pkt->geom))1720return 0;17211722/*1723* Initialise TX helper. If we must be ACK eliciting, reserve 1 byte for1724* PING.1725*/1726if (!tx_helper_init(&pkt->h, txp, enc_level,1727pkt->geom.cmppl,1728txp_need_ping(txp, pn_space, &pkt->geom.adata) ? 1 : 0))1729return 0;17301731pkt->h_valid = 1;1732pkt->tpkt = NULL;1733pkt->stream_head = NULL;1734pkt->force_pad = 0;1735return 1;1736}17371738static void txp_pkt_cleanup(struct txp_pkt *pkt, OSSL_QUIC_TX_PACKETISER *txp)1739{1740if (!pkt->h_valid)1741return;17421743tx_helper_cleanup(&pkt->h);1744pkt->h_valid = 0;17451746if (pkt->tpkt != NULL) {1747ossl_quic_txpim_pkt_release(txp->args.txpim, pkt->tpkt);1748pkt->tpkt = NULL;1749}1750}17511752static int txp_pkt_postgen_update_pkt_overhead(struct txp_pkt *pkt,1753OSSL_QUIC_TX_PACKETISER *txp)1754{1755/*1756* After we have staged and generated our packets, but before we commit1757* them, it is possible for the estimated packet overhead (packet header +1758* AEAD tag size) to shrink slightly because we generated a short packet1759* whose which can be represented in fewer bytes as a variable-length1760* integer than we were (pessimistically) budgeting for. We need to account1761* for this to ensure that we get our padding calculation exactly right.1762*1763* Update pkt_overhead to be accurate now that we know how much data is1764* going in a packet.1765*/1766size_t hdr_len, ciphertext_len;17671768if (pkt->h.enc_level == QUIC_ENC_LEVEL_INITIAL)1769/*1770* Don't update overheads for the INITIAL EL - we have not finished1771* appending padding to it and would potentially miscalculate the1772* correct padding if we now update the pkt_overhead field to switch to1773* e.g. a 1-byte length field in the packet header. Since we are padding1774* to QUIC_MIN_INITIAL_DGRAM_LEN which requires a 2-byte length field,1775* this is guaranteed to be moot anyway. See comment in1776* txp_determine_geometry for more information.1777*/1778return 1;17791780if (!ossl_qtx_calculate_ciphertext_payload_len(txp->args.qtx, pkt->h.enc_level,1781pkt->h.bytes_appended,1782&ciphertext_len))1783return 0;17841785pkt->phdr.len = ciphertext_len;17861787hdr_len = ossl_quic_wire_get_encoded_pkt_hdr_len(pkt->phdr.dst_conn_id.id_len,1788&pkt->phdr);17891790pkt->geom.pkt_overhead = hdr_len + ciphertext_len - pkt->h.bytes_appended;1791return 1;1792}17931794static void on_confirm_notify(uint64_t frame_type, uint64_t stream_id,1795QUIC_TXPIM_PKT *pkt, void *arg)1796{1797OSSL_QUIC_TX_PACKETISER *txp = arg;17981799switch (frame_type) {1800case OSSL_QUIC_FRAME_TYPE_STOP_SENDING:1801{1802QUIC_STREAM *s1803= ossl_quic_stream_map_get_by_id(txp->args.qsm, stream_id);18041805if (s == NULL)1806return;18071808s->acked_stop_sending = 1;1809ossl_quic_stream_map_update_state(txp->args.qsm, s);1810}1811break;1812case OSSL_QUIC_FRAME_TYPE_RESET_STREAM:1813{1814QUIC_STREAM *s1815= ossl_quic_stream_map_get_by_id(txp->args.qsm, stream_id);18161817if (s == NULL)1818return;18191820/*1821* We must already be in RESET_SENT or RESET_RECVD if we are1822* here, so we don't need to check state here.1823*/1824ossl_quic_stream_map_notify_reset_stream_acked(txp->args.qsm, s);1825ossl_quic_stream_map_update_state(txp->args.qsm, s);1826}1827break;1828default:1829assert(0);1830break;1831}1832}18331834static int txp_pkt_append_padding(struct txp_pkt *pkt,1835OSSL_QUIC_TX_PACKETISER *txp, size_t num_bytes)1836{1837WPACKET *wpkt;18381839if (num_bytes == 0)1840return 1;18411842if (!ossl_assert(pkt->h_valid))1843return 0;18441845if (!ossl_assert(pkt->tpkt != NULL))1846return 0;18471848wpkt = tx_helper_begin(&pkt->h);1849if (wpkt == NULL)1850return 0;18511852if (!ossl_quic_wire_encode_padding(wpkt, num_bytes)) {1853tx_helper_rollback(&pkt->h);1854return 0;1855}18561857if (!tx_helper_commit(&pkt->h))1858return 0;18591860pkt->tpkt->ackm_pkt.num_bytes += num_bytes;1861/* Cannot be non-inflight if we have a PADDING frame */1862pkt->tpkt->ackm_pkt.is_inflight = 1;1863return 1;1864}18651866static void on_sstream_updated(uint64_t stream_id, void *arg)1867{1868OSSL_QUIC_TX_PACKETISER *txp = arg;1869QUIC_STREAM *s;18701871s = ossl_quic_stream_map_get_by_id(txp->args.qsm, stream_id);1872if (s == NULL)1873return;18741875ossl_quic_stream_map_update_state(txp->args.qsm, s);1876}18771878/*1879* Returns 1 if we can send that many bytes in closing state, 0 otherwise.1880* Also maintains the bytes sent state if it returns a success.1881*/1882static int try_commit_conn_close(OSSL_QUIC_TX_PACKETISER *txp, size_t n)1883{1884int res;18851886/* We can always send the first connection close frame */1887if (txp->closing_bytes_recv == 0)1888return 1;18891890/*1891* RFC 9000 s. 10.2.1 Closing Connection State:1892* To avoid being used for an amplification attack, such1893* endpoints MUST limit the cumulative size of packets it sends1894* to three times the cumulative size of the packets that are1895* received and attributed to the connection.1896* and:1897* An endpoint in the closing state MUST either discard packets1898* received from an unvalidated address or limit the cumulative1899* size of packets it sends to an unvalidated address to three1900* times the size of packets it receives from that address.1901*/1902res = txp->closing_bytes_xmit + n <= txp->closing_bytes_recv * 3;19031904/*1905* Attribute the bytes to the connection, if we are allowed to send them1906* and this isn't the first closing frame.1907*/1908if (res && txp->closing_bytes_recv != 0)1909txp->closing_bytes_xmit += n;1910return res;1911}19121913void ossl_quic_tx_packetiser_record_received_closing_bytes(1914OSSL_QUIC_TX_PACKETISER *txp, size_t n)1915{1916txp->closing_bytes_recv += n;1917}19181919static int txp_generate_pre_token(OSSL_QUIC_TX_PACKETISER *txp,1920struct txp_pkt *pkt,1921int chosen_for_conn_close,1922int *can_be_non_inflight)1923{1924const uint32_t enc_level = pkt->h.enc_level;1925const uint32_t pn_space = ossl_quic_enc_level_to_pn_space(enc_level);1926const struct archetype_data *a = &pkt->geom.adata;1927QUIC_TXPIM_PKT *tpkt = pkt->tpkt;1928struct tx_helper *h = &pkt->h;1929const OSSL_QUIC_FRAME_ACK *ack;1930OSSL_QUIC_FRAME_ACK ack2;19311932tpkt->ackm_pkt.largest_acked = QUIC_PN_INVALID;19331934/* ACK Frames (Regenerate) */1935if (a->allow_ack1936&& tx_helper_get_space_left(h) >= MIN_FRAME_SIZE_ACK1937&& (((txp->want_ack & (1UL << pn_space)) != 0)1938|| ossl_ackm_is_ack_desired(txp->args.ackm, pn_space))1939&& (ack = ossl_ackm_get_ack_frame(txp->args.ackm, pn_space)) != NULL) {1940WPACKET *wpkt = tx_helper_begin(h);19411942if (wpkt == NULL)1943return 0;19441945/* We do not currently support ECN */1946ack2 = *ack;1947ack2.ecn_present = 0;19481949if (ossl_quic_wire_encode_frame_ack(wpkt,1950txp->args.ack_delay_exponent,1951&ack2)) {1952if (!tx_helper_commit(h))1953return 0;19541955tpkt->had_ack_frame = 1;19561957if (ack->num_ack_ranges > 0)1958tpkt->ackm_pkt.largest_acked = ack->ack_ranges[0].end;19591960if (txp->ack_tx_cb != NULL)1961txp->ack_tx_cb(&ack2, pn_space, txp->ack_tx_cb_arg);1962} else {1963tx_helper_rollback(h);1964}1965}19661967/* CONNECTION_CLOSE Frames (Regenerate) */1968if (a->allow_conn_close && txp->want_conn_close && chosen_for_conn_close) {1969WPACKET *wpkt = tx_helper_begin(h);1970OSSL_QUIC_FRAME_CONN_CLOSE f, *pf = &txp->conn_close_frame;1971size_t l;19721973if (wpkt == NULL)1974return 0;19751976/*1977* Application CONNECTION_CLOSE frames may only be sent in the1978* Application PN space, as otherwise they may be sent before a1979* connection is authenticated and leak application data. Therefore, if1980* we need to send a CONNECTION_CLOSE frame in another PN space and were1981* given an application CONNECTION_CLOSE frame, convert it into a1982* transport CONNECTION_CLOSE frame, removing any sensitive application1983* data.1984*1985* RFC 9000 s. 10.2.3: "A CONNECTION_CLOSE of type 0x1d MUST be replaced1986* by a CONNECTION_CLOSE of type 0x1c when sending the frame in Initial1987* or Handshake packets. Otherwise, information about the application1988* state might be revealed. Endpoints MUST clear the value of the Reason1989* Phrase field and SHOULD use the APPLICATION_ERROR code when1990* converting to a CONNECTION_CLOSE of type 0x1c."1991*/1992if (pn_space != QUIC_PN_SPACE_APP && pf->is_app) {1993pf = &f;1994pf->is_app = 0;1995pf->frame_type = 0;1996pf->error_code = OSSL_QUIC_ERR_APPLICATION_ERROR;1997pf->reason = NULL;1998pf->reason_len = 0;1999}20002001if (ossl_quic_wire_encode_frame_conn_close(wpkt, pf)2002&& WPACKET_get_total_written(wpkt, &l)2003&& try_commit_conn_close(txp, l)) {2004if (!tx_helper_commit(h))2005return 0;20062007tpkt->had_conn_close = 1;2008*can_be_non_inflight = 0;2009} else {2010tx_helper_rollback(h);2011}2012}20132014return 1;2015}20162017static int try_len(size_t space_left, size_t orig_len,2018size_t base_hdr_len, size_t lenbytes,2019uint64_t maxn, size_t *hdr_len, size_t *payload_len)2020{2021size_t n;2022size_t maxn_ = maxn > SIZE_MAX ? SIZE_MAX : (size_t)maxn;20232024*hdr_len = base_hdr_len + lenbytes;20252026if (orig_len == 0 && space_left >= *hdr_len) {2027*payload_len = 0;2028return 1;2029}20302031n = orig_len;2032if (n > maxn_)2033n = maxn_;2034if (n + *hdr_len > space_left)2035n = (space_left >= *hdr_len) ? space_left - *hdr_len : 0;20362037*payload_len = n;2038return n > 0;2039}20402041static int determine_len(size_t space_left, size_t orig_len,2042size_t base_hdr_len,2043uint64_t *hlen, uint64_t *len)2044{2045int ok = 0;2046size_t chosen_payload_len = 0;2047size_t chosen_hdr_len = 0;2048size_t payload_len[4], hdr_len[4];2049int i, valid[4] = {0};20502051valid[0] = try_len(space_left, orig_len, base_hdr_len,20521, OSSL_QUIC_VLINT_1B_MAX,2053&hdr_len[0], &payload_len[0]);2054valid[1] = try_len(space_left, orig_len, base_hdr_len,20552, OSSL_QUIC_VLINT_2B_MAX,2056&hdr_len[1], &payload_len[1]);2057valid[2] = try_len(space_left, orig_len, base_hdr_len,20584, OSSL_QUIC_VLINT_4B_MAX,2059&hdr_len[2], &payload_len[2]);2060valid[3] = try_len(space_left, orig_len, base_hdr_len,20618, OSSL_QUIC_VLINT_8B_MAX,2062&hdr_len[3], &payload_len[3]);20632064for (i = OSSL_NELEM(valid) - 1; i >= 0; --i)2065if (valid[i] && payload_len[i] >= chosen_payload_len) {2066chosen_payload_len = payload_len[i];2067chosen_hdr_len = hdr_len[i];2068ok = 1;2069}20702071*hlen = chosen_hdr_len;2072*len = chosen_payload_len;2073return ok;2074}20752076/*2077* Given a CRYPTO frame header with accurate chdr->len and a budget2078* (space_left), try to find the optimal value of chdr->len to fill as much of2079* the budget as possible. This is slightly hairy because larger values of2080* chdr->len cause larger encoded sizes of the length field of the frame, which2081* in turn mean less space available for payload data. We check all possible2082* encodings and choose the optimal encoding.2083*/2084static int determine_crypto_len(struct tx_helper *h,2085OSSL_QUIC_FRAME_CRYPTO *chdr,2086size_t space_left,2087uint64_t *hlen,2088uint64_t *len)2089{2090size_t orig_len;2091size_t base_hdr_len; /* CRYPTO header length without length field */20922093if (chdr->len > SIZE_MAX)2094return 0;20952096orig_len = (size_t)chdr->len;20972098chdr->len = 0;2099base_hdr_len = ossl_quic_wire_get_encoded_frame_len_crypto_hdr(chdr);2100chdr->len = orig_len;2101if (base_hdr_len == 0)2102return 0;21032104--base_hdr_len;21052106return determine_len(space_left, orig_len, base_hdr_len, hlen, len);2107}21082109static int determine_stream_len(struct tx_helper *h,2110OSSL_QUIC_FRAME_STREAM *shdr,2111size_t space_left,2112uint64_t *hlen,2113uint64_t *len)2114{2115size_t orig_len;2116size_t base_hdr_len; /* STREAM header length without length field */21172118if (shdr->len > SIZE_MAX)2119return 0;21202121orig_len = (size_t)shdr->len;21222123shdr->len = 0;2124base_hdr_len = ossl_quic_wire_get_encoded_frame_len_stream_hdr(shdr);2125shdr->len = orig_len;2126if (base_hdr_len == 0)2127return 0;21282129if (shdr->has_explicit_len)2130--base_hdr_len;21312132return determine_len(space_left, orig_len, base_hdr_len, hlen, len);2133}21342135static int txp_generate_crypto_frames(OSSL_QUIC_TX_PACKETISER *txp,2136struct txp_pkt *pkt,2137int *have_ack_eliciting)2138{2139const uint32_t enc_level = pkt->h.enc_level;2140const uint32_t pn_space = ossl_quic_enc_level_to_pn_space(enc_level);2141QUIC_TXPIM_PKT *tpkt = pkt->tpkt;2142struct tx_helper *h = &pkt->h;2143size_t num_stream_iovec;2144OSSL_QUIC_FRAME_STREAM shdr = {0};2145OSSL_QUIC_FRAME_CRYPTO chdr = {0};2146OSSL_QTX_IOVEC iov[2];2147uint64_t hdr_bytes;2148WPACKET *wpkt;2149QUIC_TXPIM_CHUNK chunk = {0};2150size_t i, space_left;21512152for (i = 0;; ++i) {2153space_left = tx_helper_get_space_left(h);21542155if (space_left < MIN_FRAME_SIZE_CRYPTO)2156return 1; /* no point trying */21572158/* Do we have any CRYPTO data waiting? */2159num_stream_iovec = OSSL_NELEM(iov);2160if (!ossl_quic_sstream_get_stream_frame(txp->args.crypto[pn_space],2161i, &shdr, iov,2162&num_stream_iovec))2163return 1; /* nothing to do */21642165/* Convert STREAM frame header to CRYPTO frame header */2166chdr.offset = shdr.offset;2167chdr.len = shdr.len;21682169if (chdr.len == 0)2170return 1; /* nothing to do */21712172/* Find best fit (header length, payload length) combination. */2173if (!determine_crypto_len(h, &chdr, space_left, &hdr_bytes,2174&chdr.len))2175return 1; /* can't fit anything */21762177/*2178* Truncate IOVs to match our chosen length.2179*2180* The length cannot be more than SIZE_MAX because this length comes2181* from our send stream buffer.2182*/2183ossl_quic_sstream_adjust_iov((size_t)chdr.len, iov, num_stream_iovec);21842185/*2186* Ensure we have enough iovecs allocated (1 for the header, up to 2 for2187* the stream data.)2188*/2189if (!txp_el_ensure_iovec(&txp->el[enc_level], h->num_iovec + 3))2190return 0; /* alloc error */21912192/* Encode the header. */2193wpkt = tx_helper_begin(h);2194if (wpkt == NULL)2195return 0; /* alloc error */21962197if (!ossl_quic_wire_encode_frame_crypto_hdr(wpkt, &chdr)) {2198tx_helper_rollback(h);2199return 1; /* can't fit */2200}22012202if (!tx_helper_commit(h))2203return 0; /* alloc error */22042205/* Add payload iovecs to the helper (infallible). */2206for (i = 0; i < num_stream_iovec; ++i)2207tx_helper_append_iovec(h, iov[i].buf, iov[i].buf_len);22082209*have_ack_eliciting = 1;2210tx_helper_unrestrict(h); /* no longer need PING */22112212/* Log chunk to TXPIM. */2213chunk.stream_id = UINT64_MAX; /* crypto stream */2214chunk.start = chdr.offset;2215chunk.end = chdr.offset + chdr.len - 1;2216chunk.has_fin = 0; /* Crypto stream never ends */2217if (!ossl_quic_txpim_pkt_append_chunk(tpkt, &chunk))2218return 0; /* alloc error */2219}2220}22212222struct chunk_info {2223OSSL_QUIC_FRAME_STREAM shdr;2224uint64_t orig_len;2225OSSL_QTX_IOVEC iov[2];2226size_t num_stream_iovec;2227int valid;2228};22292230static int txp_plan_stream_chunk(OSSL_QUIC_TX_PACKETISER *txp,2231struct tx_helper *h,2232QUIC_SSTREAM *sstream,2233QUIC_TXFC *stream_txfc,2234size_t skip,2235struct chunk_info *chunk,2236uint64_t consumed)2237{2238uint64_t fc_credit, fc_swm, fc_limit;22392240chunk->num_stream_iovec = OSSL_NELEM(chunk->iov);2241chunk->valid = ossl_quic_sstream_get_stream_frame(sstream, skip,2242&chunk->shdr,2243chunk->iov,2244&chunk->num_stream_iovec);2245if (!chunk->valid)2246return 1;22472248if (!ossl_assert(chunk->shdr.len > 0 || chunk->shdr.is_fin))2249/* Should only have 0-length chunk if FIN */2250return 0;22512252chunk->orig_len = chunk->shdr.len;22532254/* Clamp according to connection and stream-level TXFC. */2255fc_credit = ossl_quic_txfc_get_credit(stream_txfc, consumed);2256fc_swm = ossl_quic_txfc_get_swm(stream_txfc);2257fc_limit = fc_swm + fc_credit;22582259if (chunk->shdr.len > 0 && chunk->shdr.offset + chunk->shdr.len > fc_limit) {2260chunk->shdr.len = (fc_limit <= chunk->shdr.offset)2261? 0 : fc_limit - chunk->shdr.offset;2262chunk->shdr.is_fin = 0;2263}22642265if (chunk->shdr.len == 0 && !chunk->shdr.is_fin) {2266/*2267* Nothing to do due to TXFC. Since SSTREAM returns chunks in ascending2268* order of offset we don't need to check any later chunks, so stop2269* iterating here.2270*/2271chunk->valid = 0;2272return 1;2273}22742275return 1;2276}22772278/*2279* Returns 0 on fatal error (e.g. allocation failure), 1 on success.2280* *packet_full is set to 1 if there is no longer enough room for another STREAM2281* frame.2282*/2283static int txp_generate_stream_frames(OSSL_QUIC_TX_PACKETISER *txp,2284struct txp_pkt *pkt,2285uint64_t id,2286QUIC_SSTREAM *sstream,2287QUIC_TXFC *stream_txfc,2288QUIC_STREAM *next_stream,2289int *have_ack_eliciting,2290int *packet_full,2291uint64_t *new_credit_consumed,2292uint64_t conn_consumed)2293{2294int rc = 0;2295struct chunk_info chunks[2] = {0};2296const uint32_t enc_level = pkt->h.enc_level;2297QUIC_TXPIM_PKT *tpkt = pkt->tpkt;2298struct tx_helper *h = &pkt->h;2299OSSL_QUIC_FRAME_STREAM *shdr;2300WPACKET *wpkt;2301QUIC_TXPIM_CHUNK chunk;2302size_t i, j, space_left;2303int can_fill_payload, use_explicit_len;2304int could_have_following_chunk;2305uint64_t orig_len;2306uint64_t hdr_len_implicit, payload_len_implicit;2307uint64_t hdr_len_explicit, payload_len_explicit;2308uint64_t fc_swm, fc_new_hwm;23092310fc_swm = ossl_quic_txfc_get_swm(stream_txfc);2311fc_new_hwm = fc_swm;23122313/*2314* Load the first two chunks if any offered by the send stream. We retrieve2315* the next chunk in advance so we can determine if we need to send any more2316* chunks from the same stream after this one, which is needed when2317* determining when we can use an implicit length in a STREAM frame.2318*/2319for (i = 0; i < 2; ++i) {2320if (!txp_plan_stream_chunk(txp, h, sstream, stream_txfc, i, &chunks[i],2321conn_consumed))2322goto err;23232324if (i == 0 && !chunks[i].valid) {2325/* No chunks, nothing to do. */2326rc = 1;2327goto err;2328}2329chunks[i].shdr.stream_id = id;2330}23312332for (i = 0;; ++i) {2333space_left = tx_helper_get_space_left(h);23342335if (!chunks[i % 2].valid) {2336/* Out of chunks; we're done. */2337rc = 1;2338goto err;2339}23402341if (space_left < MIN_FRAME_SIZE_STREAM) {2342*packet_full = 1;2343rc = 1;2344goto err;2345}23462347if (!ossl_assert(!h->done_implicit))2348/*2349* Logic below should have ensured we didn't append an2350* implicit-length unless we filled the packet or didn't have2351* another stream to handle, so this should not be possible.2352*/2353goto err;23542355shdr = &chunks[i % 2].shdr;2356orig_len = chunks[i % 2].orig_len;2357if (i > 0)2358/* Load next chunk for lookahead. */2359if (!txp_plan_stream_chunk(txp, h, sstream, stream_txfc, i + 1,2360&chunks[(i + 1) % 2], conn_consumed))2361goto err;23622363/*2364* Find best fit (header length, payload length) combination for if we2365* use an implicit length.2366*/2367shdr->has_explicit_len = 0;2368hdr_len_implicit = payload_len_implicit = 0;2369if (!determine_stream_len(h, shdr, space_left,2370&hdr_len_implicit, &payload_len_implicit)) {2371*packet_full = 1;2372rc = 1;2373goto err; /* can't fit anything */2374}23752376/*2377* If there is a next stream, we don't use the implicit length so we can2378* add more STREAM frames after this one, unless there is enough data2379* for this STREAM frame to fill the packet.2380*/2381can_fill_payload = (hdr_len_implicit + payload_len_implicit2382>= space_left);23832384/*2385* Is there is a stream after this one, or another chunk pending2386* transmission in this stream?2387*/2388could_have_following_chunk2389= (next_stream != NULL || chunks[(i + 1) % 2].valid);23902391/* Choose between explicit or implicit length representations. */2392use_explicit_len = !((can_fill_payload || !could_have_following_chunk)2393&& !pkt->force_pad);23942395if (use_explicit_len) {2396/*2397* Find best fit (header length, payload length) combination for if2398* we use an explicit length.2399*/2400shdr->has_explicit_len = 1;2401hdr_len_explicit = payload_len_explicit = 0;2402if (!determine_stream_len(h, shdr, space_left,2403&hdr_len_explicit, &payload_len_explicit)) {2404*packet_full = 1;2405rc = 1;2406goto err; /* can't fit anything */2407}24082409shdr->len = payload_len_explicit;2410} else {2411*packet_full = 1;2412shdr->has_explicit_len = 0;2413shdr->len = payload_len_implicit;2414}24152416/* If this is a FIN, don't keep filling the packet with more FINs. */2417if (shdr->is_fin)2418chunks[(i + 1) % 2].valid = 0;24192420/*2421* We are now committed to our length (shdr->len can't change).2422* If we truncated the chunk, clear the FIN bit.2423*/2424if (shdr->len < orig_len)2425shdr->is_fin = 0;24262427/* Truncate IOVs to match our chosen length. */2428ossl_quic_sstream_adjust_iov((size_t)shdr->len, chunks[i % 2].iov,2429chunks[i % 2].num_stream_iovec);24302431/*2432* Ensure we have enough iovecs allocated (1 for the header, up to 2 for2433* the stream data.)2434*/2435if (!txp_el_ensure_iovec(&txp->el[enc_level], h->num_iovec + 3))2436goto err; /* alloc error */24372438/* Encode the header. */2439wpkt = tx_helper_begin(h);2440if (wpkt == NULL)2441goto err; /* alloc error */24422443if (!ossl_assert(ossl_quic_wire_encode_frame_stream_hdr(wpkt, shdr))) {2444/* (Should not be possible.) */2445tx_helper_rollback(h);2446*packet_full = 1;2447rc = 1;2448goto err; /* can't fit */2449}24502451if (!tx_helper_commit(h))2452goto err; /* alloc error */24532454/* Add payload iovecs to the helper (infallible). */2455for (j = 0; j < chunks[i % 2].num_stream_iovec; ++j)2456tx_helper_append_iovec(h, chunks[i % 2].iov[j].buf,2457chunks[i % 2].iov[j].buf_len);24582459*have_ack_eliciting = 1;2460tx_helper_unrestrict(h); /* no longer need PING */2461if (!shdr->has_explicit_len)2462h->done_implicit = 1;24632464/* Log new TXFC credit which was consumed. */2465if (shdr->len > 0 && shdr->offset + shdr->len > fc_new_hwm)2466fc_new_hwm = shdr->offset + shdr->len;24672468/* Log chunk to TXPIM. */2469chunk.stream_id = shdr->stream_id;2470chunk.start = shdr->offset;2471chunk.end = shdr->offset + shdr->len - 1;2472chunk.has_fin = shdr->is_fin;2473chunk.has_stop_sending = 0;2474chunk.has_reset_stream = 0;2475if (!ossl_quic_txpim_pkt_append_chunk(tpkt, &chunk))2476goto err; /* alloc error */24772478if (shdr->len < orig_len) {2479/*2480* If we did not serialize all of this chunk we definitely do not2481* want to try the next chunk2482*/2483rc = 1;2484goto err;2485}2486}24872488err:2489*new_credit_consumed = fc_new_hwm - fc_swm;2490return rc;2491}24922493static void txp_enlink_tmp(QUIC_STREAM **tmp_head, QUIC_STREAM *stream)2494{2495stream->txp_next = *tmp_head;2496*tmp_head = stream;2497}24982499static int txp_generate_stream_related(OSSL_QUIC_TX_PACKETISER *txp,2500struct txp_pkt *pkt,2501int *have_ack_eliciting,2502QUIC_STREAM **tmp_head)2503{2504QUIC_STREAM_ITER it;2505WPACKET *wpkt;2506uint64_t cwm;2507QUIC_STREAM *stream, *snext;2508struct tx_helper *h = &pkt->h;2509uint64_t conn_consumed = 0;25102511for (ossl_quic_stream_iter_init(&it, txp->args.qsm, 1);2512it.stream != NULL;) {25132514stream = it.stream;2515ossl_quic_stream_iter_next(&it);2516snext = it.stream;25172518stream->txp_sent_fc = 0;2519stream->txp_sent_stop_sending = 0;2520stream->txp_sent_reset_stream = 0;2521stream->txp_blocked = 0;2522stream->txp_txfc_new_credit_consumed = 0;25232524/* Stream Abort Frames (STOP_SENDING, RESET_STREAM) */2525if (stream->want_stop_sending) {2526OSSL_QUIC_FRAME_STOP_SENDING f;25272528wpkt = tx_helper_begin(h);2529if (wpkt == NULL)2530return 0; /* alloc error */25312532f.stream_id = stream->id;2533f.app_error_code = stream->stop_sending_aec;2534if (!ossl_quic_wire_encode_frame_stop_sending(wpkt, &f)) {2535tx_helper_rollback(h); /* can't fit */2536txp_enlink_tmp(tmp_head, stream);2537break;2538}25392540if (!tx_helper_commit(h))2541return 0; /* alloc error */25422543*have_ack_eliciting = 1;2544tx_helper_unrestrict(h); /* no longer need PING */2545stream->txp_sent_stop_sending = 1;2546}25472548if (stream->want_reset_stream) {2549OSSL_QUIC_FRAME_RESET_STREAM f;25502551if (!ossl_assert(stream->send_state == QUIC_SSTREAM_STATE_RESET_SENT))2552return 0;25532554wpkt = tx_helper_begin(h);2555if (wpkt == NULL)2556return 0; /* alloc error */25572558f.stream_id = stream->id;2559f.app_error_code = stream->reset_stream_aec;2560if (!ossl_quic_stream_send_get_final_size(stream, &f.final_size))2561return 0; /* should not be possible */25622563if (!ossl_quic_wire_encode_frame_reset_stream(wpkt, &f)) {2564tx_helper_rollback(h); /* can't fit */2565txp_enlink_tmp(tmp_head, stream);2566break;2567}25682569if (!tx_helper_commit(h))2570return 0; /* alloc error */25712572*have_ack_eliciting = 1;2573tx_helper_unrestrict(h); /* no longer need PING */2574stream->txp_sent_reset_stream = 1;25752576/*2577* The final size of the stream as indicated by RESET_STREAM is used2578* to ensure a consistent view of flow control state by both2579* parties; if we happen to send a RESET_STREAM that consumes more2580* flow control credit, make sure we account for that.2581*/2582if (!ossl_assert(f.final_size <= ossl_quic_txfc_get_swm(&stream->txfc)))2583return 0;25842585stream->txp_txfc_new_credit_consumed2586= f.final_size - ossl_quic_txfc_get_swm(&stream->txfc);2587}25882589/*2590* Stream Flow Control Frames (MAX_STREAM_DATA)2591*2592* RFC 9000 s. 13.3: "An endpoint SHOULD stop sending MAX_STREAM_DATA2593* frames when the receiving part of the stream enters a "Size Known" or2594* "Reset Recvd" state." -- In practice, RECV is the only state2595* in which it makes sense to generate more MAX_STREAM_DATA frames.2596*/2597if (stream->recv_state == QUIC_RSTREAM_STATE_RECV2598&& (stream->want_max_stream_data2599|| ossl_quic_rxfc_has_cwm_changed(&stream->rxfc, 0))) {26002601wpkt = tx_helper_begin(h);2602if (wpkt == NULL)2603return 0; /* alloc error */26042605cwm = ossl_quic_rxfc_get_cwm(&stream->rxfc);26062607if (!ossl_quic_wire_encode_frame_max_stream_data(wpkt, stream->id,2608cwm)) {2609tx_helper_rollback(h); /* can't fit */2610txp_enlink_tmp(tmp_head, stream);2611break;2612}26132614if (!tx_helper_commit(h))2615return 0; /* alloc error */26162617*have_ack_eliciting = 1;2618tx_helper_unrestrict(h); /* no longer need PING */2619stream->txp_sent_fc = 1;2620}26212622/*2623* Stream Data Frames (STREAM)2624*2625* RFC 9000 s. 3.3: A sender MUST NOT send a STREAM [...] frame for a2626* stream in the "Reset Sent" state [or any terminal state]. We don't2627* send any more STREAM frames if we are sending, have sent, or are2628* planning to send, RESET_STREAM. The other terminal state is Data2629* Recvd, but txp_generate_stream_frames() is guaranteed to generate2630* nothing in this case.2631*/2632if (ossl_quic_stream_has_send_buffer(stream)2633&& !ossl_quic_stream_send_is_reset(stream)) {2634int packet_full = 0;26352636if (!ossl_assert(!stream->want_reset_stream))2637return 0;26382639if (!txp_generate_stream_frames(txp, pkt,2640stream->id, stream->sstream,2641&stream->txfc,2642snext,2643have_ack_eliciting,2644&packet_full,2645&stream->txp_txfc_new_credit_consumed,2646conn_consumed)) {2647/* Fatal error (allocation, etc.) */2648txp_enlink_tmp(tmp_head, stream);2649return 0;2650}2651conn_consumed += stream->txp_txfc_new_credit_consumed;26522653if (packet_full) {2654txp_enlink_tmp(tmp_head, stream);2655break;2656}2657}26582659txp_enlink_tmp(tmp_head, stream);2660}26612662return 1;2663}26642665static int txp_generate_for_el(OSSL_QUIC_TX_PACKETISER *txp,2666struct txp_pkt *pkt,2667int chosen_for_conn_close)2668{2669int rc = TXP_ERR_SUCCESS;2670const uint32_t enc_level = pkt->h.enc_level;2671const uint32_t pn_space = ossl_quic_enc_level_to_pn_space(enc_level);2672int have_ack_eliciting = 0, done_pre_token = 0;2673const struct archetype_data a = pkt->geom.adata;2674/*2675* Cleared if we encode any non-ACK-eliciting frame type which rules out the2676* packet being a non-inflight frame. This means any non-ACK ACK-eliciting2677* frame, even PADDING frames. ACK eliciting frames always cause a packet to2678* become ineligible for non-inflight treatment so it is not necessary to2679* clear this in cases where have_ack_eliciting is set, as it is ignored in2680* that case.2681*/2682int can_be_non_inflight = 1;2683QUIC_CFQ_ITEM *cfq_item;2684QUIC_TXPIM_PKT *tpkt = NULL;2685struct tx_helper *h = &pkt->h;26862687/* Maximum PN reached? */2688if (!ossl_quic_pn_valid(txp->next_pn[pn_space]))2689goto fatal_err;26902691if (!ossl_assert(pkt->tpkt == NULL))2692goto fatal_err;26932694if ((pkt->tpkt = tpkt = ossl_quic_txpim_pkt_alloc(txp->args.txpim)) == NULL)2695goto fatal_err;26962697/*2698* Frame Serialization2699* ===================2700*2701* We now serialize frames into the packet in descending order of priority.2702*/27032704/* HANDSHAKE_DONE (Regenerate) */2705if (a.allow_handshake_done && txp->want_handshake_done2706&& tx_helper_get_space_left(h) >= MIN_FRAME_SIZE_HANDSHAKE_DONE) {2707WPACKET *wpkt = tx_helper_begin(h);27082709if (wpkt == NULL)2710goto fatal_err;27112712if (ossl_quic_wire_encode_frame_handshake_done(wpkt)) {2713tpkt->had_handshake_done_frame = 1;2714have_ack_eliciting = 1;27152716if (!tx_helper_commit(h))2717goto fatal_err;27182719tx_helper_unrestrict(h); /* no longer need PING */2720} else {2721tx_helper_rollback(h);2722}2723}27242725/* MAX_DATA (Regenerate) */2726if (a.allow_conn_fc2727&& (txp->want_max_data2728|| ossl_quic_rxfc_has_cwm_changed(txp->args.conn_rxfc, 0))2729&& tx_helper_get_space_left(h) >= MIN_FRAME_SIZE_MAX_DATA) {2730WPACKET *wpkt = tx_helper_begin(h);2731uint64_t cwm = ossl_quic_rxfc_get_cwm(txp->args.conn_rxfc);27322733if (wpkt == NULL)2734goto fatal_err;27352736if (ossl_quic_wire_encode_frame_max_data(wpkt, cwm)) {2737tpkt->had_max_data_frame = 1;2738have_ack_eliciting = 1;27392740if (!tx_helper_commit(h))2741goto fatal_err;27422743tx_helper_unrestrict(h); /* no longer need PING */2744} else {2745tx_helper_rollback(h);2746}2747}27482749/* MAX_STREAMS_BIDI (Regenerate) */2750if (a.allow_conn_fc2751&& (txp->want_max_streams_bidi2752|| ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_bidi_rxfc, 0))2753&& tx_helper_get_space_left(h) >= MIN_FRAME_SIZE_MAX_STREAMS_BIDI) {2754WPACKET *wpkt = tx_helper_begin(h);2755uint64_t max_streams2756= ossl_quic_rxfc_get_cwm(txp->args.max_streams_bidi_rxfc);27572758if (wpkt == NULL)2759goto fatal_err;27602761if (ossl_quic_wire_encode_frame_max_streams(wpkt, /*is_uni=*/0,2762max_streams)) {2763tpkt->had_max_streams_bidi_frame = 1;2764have_ack_eliciting = 1;27652766if (!tx_helper_commit(h))2767goto fatal_err;27682769tx_helper_unrestrict(h); /* no longer need PING */2770} else {2771tx_helper_rollback(h);2772}2773}27742775/* MAX_STREAMS_UNI (Regenerate) */2776if (a.allow_conn_fc2777&& (txp->want_max_streams_uni2778|| ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_uni_rxfc, 0))2779&& tx_helper_get_space_left(h) >= MIN_FRAME_SIZE_MAX_STREAMS_UNI) {2780WPACKET *wpkt = tx_helper_begin(h);2781uint64_t max_streams2782= ossl_quic_rxfc_get_cwm(txp->args.max_streams_uni_rxfc);27832784if (wpkt == NULL)2785goto fatal_err;27862787if (ossl_quic_wire_encode_frame_max_streams(wpkt, /*is_uni=*/1,2788max_streams)) {2789tpkt->had_max_streams_uni_frame = 1;2790have_ack_eliciting = 1;27912792if (!tx_helper_commit(h))2793goto fatal_err;27942795tx_helper_unrestrict(h); /* no longer need PING */2796} else {2797tx_helper_rollback(h);2798}2799}28002801/* GCR Frames */2802for (cfq_item = ossl_quic_cfq_get_priority_head(txp->args.cfq, pn_space);2803cfq_item != NULL;2804cfq_item = ossl_quic_cfq_item_get_priority_next(cfq_item, pn_space)) {2805uint64_t frame_type = ossl_quic_cfq_item_get_frame_type(cfq_item);2806const unsigned char *encoded = ossl_quic_cfq_item_get_encoded(cfq_item);2807size_t encoded_len = ossl_quic_cfq_item_get_encoded_len(cfq_item);28082809switch (frame_type) {2810case OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID:2811if (!a.allow_new_conn_id)2812continue;2813break;2814case OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID:2815if (!a.allow_retire_conn_id)2816continue;2817break;2818case OSSL_QUIC_FRAME_TYPE_NEW_TOKEN:2819if (!a.allow_new_token)2820continue;28212822/*2823* NEW_TOKEN frames are handled via GCR, but some2824* Regenerate-strategy frames should come before them (namely2825* ACK, CONNECTION_CLOSE, PATH_CHALLENGE and PATH_RESPONSE). If2826* we find a NEW_TOKEN frame, do these now. If there are no2827* NEW_TOKEN frames in the GCR queue we will handle these below.2828*/2829if (!done_pre_token)2830if (txp_generate_pre_token(txp, pkt,2831chosen_for_conn_close,2832&can_be_non_inflight))2833done_pre_token = 1;28342835break;2836case OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE:2837if (!a.allow_path_response)2838continue;28392840/*2841* RFC 9000 s. 8.2.2: An endpoint MUST expand datagrams that2842* contain a PATH_RESPONSE frame to at least the smallest2843* allowed maximum datagram size of 1200 bytes.2844*/2845pkt->force_pad = 1;2846break;2847default:2848if (!a.allow_cfq_other)2849continue;2850break;2851}28522853/*2854* If the frame is too big, don't try to schedule any more GCR frames in2855* this packet rather than sending subsequent ones out of order.2856*/2857if (encoded_len > tx_helper_get_space_left(h))2858break;28592860if (!tx_helper_append_iovec(h, encoded, encoded_len))2861goto fatal_err;28622863ossl_quic_txpim_pkt_add_cfq_item(tpkt, cfq_item);28642865if (ossl_quic_frame_type_is_ack_eliciting(frame_type)) {2866have_ack_eliciting = 1;2867tx_helper_unrestrict(h); /* no longer need PING */2868}2869}28702871/*2872* If we didn't generate ACK, CONNECTION_CLOSE, PATH_CHALLENGE or2873* PATH_RESPONSE (as desired) before, do so now.2874*/2875if (!done_pre_token)2876if (txp_generate_pre_token(txp, pkt,2877chosen_for_conn_close,2878&can_be_non_inflight))2879done_pre_token = 1;28802881/* CRYPTO Frames */2882if (a.allow_crypto)2883if (!txp_generate_crypto_frames(txp, pkt, &have_ack_eliciting))2884goto fatal_err;28852886/* Stream-specific frames */2887if (a.allow_stream_rel && txp->handshake_complete)2888if (!txp_generate_stream_related(txp, pkt,2889&have_ack_eliciting,2890&pkt->stream_head))2891goto fatal_err;28922893/* PING */2894tx_helper_unrestrict(h);28952896if (!have_ack_eliciting && txp_need_ping(txp, pn_space, &a)) {2897WPACKET *wpkt;28982899assert(h->reserve > 0);2900wpkt = tx_helper_begin(h);2901if (wpkt == NULL)2902goto fatal_err;29032904if (!ossl_quic_wire_encode_frame_ping(wpkt)2905|| !tx_helper_commit(h))2906/*2907* We treat a request to be ACK-eliciting as a requirement, so this2908* is an error.2909*/2910goto fatal_err;29112912have_ack_eliciting = 1;2913}29142915/* PADDING is added by ossl_quic_tx_packetiser_generate(). */29162917/*2918* ACKM Data2919* =========2920*/2921if (have_ack_eliciting)2922can_be_non_inflight = 0;29232924/* ACKM Data */2925tpkt->ackm_pkt.num_bytes = h->bytes_appended + pkt->geom.pkt_overhead;2926tpkt->ackm_pkt.pkt_num = txp->next_pn[pn_space];2927/* largest_acked is set in txp_generate_pre_token */2928tpkt->ackm_pkt.pkt_space = pn_space;2929tpkt->ackm_pkt.is_inflight = !can_be_non_inflight;2930tpkt->ackm_pkt.is_ack_eliciting = have_ack_eliciting;2931tpkt->ackm_pkt.is_pto_probe = 0;2932tpkt->ackm_pkt.is_mtu_probe = 0;2933tpkt->ackm_pkt.time = txp->args.now(txp->args.now_arg);2934tpkt->pkt_type = pkt->phdr.type;29352936/* Done. */2937return rc;29382939fatal_err:2940/*2941* Handler for fatal errors, i.e. errors causing us to abort the entire2942* packet rather than just one frame. Examples of such errors include2943* allocation errors.2944*/2945if (tpkt != NULL) {2946ossl_quic_txpim_pkt_release(txp->args.txpim, tpkt);2947pkt->tpkt = NULL;2948}2949return TXP_ERR_INTERNAL;2950}29512952/*2953* Commits and queues a packet for transmission. There is no backing out after2954* this.2955*2956* This:2957*2958* - Sends the packet to the QTX for encryption and transmission;2959*2960* - Records the packet as having been transmitted in FIFM. ACKM is informed,2961* etc. and the TXPIM record is filed.2962*2963* - Informs various subsystems of frames that were sent and clears frame2964* wanted flags so that we do not generate the same frames again.2965*2966* Assumptions:2967*2968* - pkt is a txp_pkt for the correct EL;2969*2970* - pkt->tpkt is valid;2971*2972* - pkt->tpkt->ackm_pkt has been fully filled in;2973*2974* - Stream chunk records have been appended to pkt->tpkt for STREAM and2975* CRYPTO frames, but not for RESET_STREAM or STOP_SENDING frames;2976*2977* - The chosen stream list for the packet can be fully walked from2978* pkt->stream_head using stream->txp_next;2979*2980* - pkt->has_ack_eliciting is set correctly.2981*2982*/2983static int txp_pkt_commit(OSSL_QUIC_TX_PACKETISER *txp,2984struct txp_pkt *pkt,2985uint32_t archetype,2986int *txpim_pkt_reffed)2987{2988int rc = 1;2989uint32_t enc_level = pkt->h.enc_level;2990uint32_t pn_space = ossl_quic_enc_level_to_pn_space(enc_level);2991QUIC_TXPIM_PKT *tpkt = pkt->tpkt;2992QUIC_STREAM *stream;2993OSSL_QTX_PKT txpkt;2994struct archetype_data a;29952996*txpim_pkt_reffed = 0;29972998/* Cannot send a packet with an empty payload. */2999if (pkt->h.bytes_appended == 0)3000return 0;30013002if (!txp_get_archetype_data(enc_level, archetype, &a))3003return 0;30043005/* Packet Information for QTX */3006txpkt.hdr = &pkt->phdr;3007txpkt.iovec = txp->el[enc_level].iovec;3008txpkt.num_iovec = pkt->h.num_iovec;3009txpkt.local = NULL;3010txpkt.peer = BIO_ADDR_family(&txp->args.peer) == AF_UNSPEC3011? NULL : &txp->args.peer;3012txpkt.pn = txp->next_pn[pn_space];3013txpkt.flags = OSSL_QTX_PKT_FLAG_COALESCE; /* always try to coalesce */30143015/* Generate TXPIM chunks representing STOP_SENDING and RESET_STREAM frames. */3016for (stream = pkt->stream_head; stream != NULL; stream = stream->txp_next)3017if (stream->txp_sent_stop_sending || stream->txp_sent_reset_stream) {3018/* Log STOP_SENDING/RESET_STREAM chunk to TXPIM. */3019QUIC_TXPIM_CHUNK chunk;30203021chunk.stream_id = stream->id;3022chunk.start = UINT64_MAX;3023chunk.end = 0;3024chunk.has_fin = 0;3025chunk.has_stop_sending = stream->txp_sent_stop_sending;3026chunk.has_reset_stream = stream->txp_sent_reset_stream;3027if (!ossl_quic_txpim_pkt_append_chunk(tpkt, &chunk))3028return 0; /* alloc error */3029}30303031/* Dispatch to FIFD. */3032if (!ossl_quic_fifd_pkt_commit(&txp->fifd, tpkt))3033return 0;30343035/*3036* Transmission and Post-Packet Generation Bookkeeping3037* ===================================================3038*3039* No backing out anymore - at this point the ACKM has recorded the packet3040* as having been sent, so we need to increment our next PN counter, or3041* the ACKM will complain when we try to record a duplicate packet with3042* the same PN later. At this point actually sending the packet may still3043* fail. In this unlikely event it will simply be handled as though it3044* were a lost packet.3045*/3046++txp->next_pn[pn_space];3047*txpim_pkt_reffed = 1;30483049/* Send the packet. */3050if (!ossl_qtx_write_pkt(txp->args.qtx, &txpkt))3051return 0;30523053/*3054* Record FC and stream abort frames as sent; deactivate streams which no3055* longer have anything to do.3056*/3057for (stream = pkt->stream_head; stream != NULL; stream = stream->txp_next) {3058if (stream->txp_sent_fc) {3059stream->want_max_stream_data = 0;3060ossl_quic_rxfc_has_cwm_changed(&stream->rxfc, 1);3061}30623063if (stream->txp_sent_stop_sending)3064stream->want_stop_sending = 0;30653066if (stream->txp_sent_reset_stream)3067stream->want_reset_stream = 0;30683069if (stream->txp_txfc_new_credit_consumed > 0) {3070if (!ossl_assert(ossl_quic_txfc_consume_credit(&stream->txfc,3071stream->txp_txfc_new_credit_consumed)))3072/*3073* Should not be possible, but we should continue with our3074* bookkeeping as we have already committed the packet to the3075* FIFD. Just change the value we return.3076*/3077rc = 0;30783079stream->txp_txfc_new_credit_consumed = 0;3080}30813082/*3083* If we no longer need to generate any flow control (MAX_STREAM_DATA),3084* STOP_SENDING or RESET_STREAM frames, nor any STREAM frames (because3085* the stream is drained of data or TXFC-blocked), we can mark the3086* stream as inactive.3087*/3088ossl_quic_stream_map_update_state(txp->args.qsm, stream);30893090if (ossl_quic_stream_has_send_buffer(stream)3091&& !ossl_quic_sstream_has_pending(stream->sstream)3092&& ossl_quic_sstream_get_final_size(stream->sstream, NULL))3093/*3094* Transition to DATA_SENT if stream has a final size and we have3095* sent all data.3096*/3097ossl_quic_stream_map_notify_all_data_sent(txp->args.qsm, stream);3098}30993100/* We have now sent the packet, so update state accordingly. */3101if (tpkt->ackm_pkt.is_ack_eliciting)3102txp->force_ack_eliciting &= ~(1UL << pn_space);31033104if (tpkt->had_handshake_done_frame)3105txp->want_handshake_done = 0;31063107if (tpkt->had_max_data_frame) {3108txp->want_max_data = 0;3109ossl_quic_rxfc_has_cwm_changed(txp->args.conn_rxfc, 1);3110}31113112if (tpkt->had_max_streams_bidi_frame) {3113txp->want_max_streams_bidi = 0;3114ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_bidi_rxfc, 1);3115}31163117if (tpkt->had_max_streams_uni_frame) {3118txp->want_max_streams_uni = 0;3119ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_uni_rxfc, 1);3120}31213122if (tpkt->had_ack_frame)3123txp->want_ack &= ~(1UL << pn_space);31243125if (tpkt->had_conn_close)3126txp->want_conn_close = 0;31273128/*3129* Decrement probe request counts if we have sent a packet that meets3130* the requirement of a probe, namely being ACK-eliciting.3131*/3132if (tpkt->ackm_pkt.is_ack_eliciting) {3133OSSL_ACKM_PROBE_INFO *probe_info3134= ossl_ackm_get0_probe_request(txp->args.ackm);31353136if (enc_level == QUIC_ENC_LEVEL_INITIAL3137&& probe_info->anti_deadlock_initial > 0)3138--probe_info->anti_deadlock_initial;31393140if (enc_level == QUIC_ENC_LEVEL_HANDSHAKE3141&& probe_info->anti_deadlock_handshake > 0)3142--probe_info->anti_deadlock_handshake;31433144if (a.allow_force_ack_eliciting /* (i.e., not for 0-RTT) */3145&& probe_info->pto[pn_space] > 0)3146--probe_info->pto[pn_space];3147}31483149return rc;3150}31513152/* Ensure the iovec array is at least num elements long. */3153static int txp_el_ensure_iovec(struct txp_el *el, size_t num)3154{3155OSSL_QTX_IOVEC *iovec;31563157if (el->alloc_iovec >= num)3158return 1;31593160num = el->alloc_iovec != 0 ? el->alloc_iovec * 2 : 8;31613162iovec = OPENSSL_realloc(el->iovec, sizeof(OSSL_QTX_IOVEC) * num);3163if (iovec == NULL)3164return 0;31653166el->iovec = iovec;3167el->alloc_iovec = num;3168return 1;3169}31703171int ossl_quic_tx_packetiser_schedule_conn_close(OSSL_QUIC_TX_PACKETISER *txp,3172const OSSL_QUIC_FRAME_CONN_CLOSE *f)3173{3174char *reason = NULL;3175size_t reason_len = f->reason_len;3176size_t max_reason_len = txp_get_mdpl(txp) / 2;31773178if (txp->want_conn_close)3179return 0;31803181/*3182* Arbitrarily limit the length of the reason length string to half of the3183* MDPL.3184*/3185if (reason_len > max_reason_len)3186reason_len = max_reason_len;31873188if (reason_len > 0) {3189reason = OPENSSL_memdup(f->reason, reason_len);3190if (reason == NULL)3191return 0;3192}31933194txp->conn_close_frame = *f;3195txp->conn_close_frame.reason = reason;3196txp->conn_close_frame.reason_len = reason_len;3197txp->want_conn_close = 1;3198return 1;3199}32003201void ossl_quic_tx_packetiser_set_msg_callback(OSSL_QUIC_TX_PACKETISER *txp,3202ossl_msg_cb msg_callback,3203SSL *msg_callback_ssl)3204{3205txp->msg_callback = msg_callback;3206txp->msg_callback_ssl = msg_callback_ssl;3207}32083209void ossl_quic_tx_packetiser_set_msg_callback_arg(OSSL_QUIC_TX_PACKETISER *txp,3210void *msg_callback_arg)3211{3212txp->msg_callback_arg = msg_callback_arg;3213}32143215QUIC_PN ossl_quic_tx_packetiser_get_next_pn(OSSL_QUIC_TX_PACKETISER *txp,3216uint32_t pn_space)3217{3218if (pn_space >= QUIC_PN_SPACE_NUM)3219return UINT64_MAX;32203221return txp->next_pn[pn_space];3222}32233224OSSL_TIME ossl_quic_tx_packetiser_get_deadline(OSSL_QUIC_TX_PACKETISER *txp)3225{3226/*3227* TXP-specific deadline computations which rely on TXP innards. This is in3228* turn relied on by the QUIC_CHANNEL code to determine the channel event3229* handling deadline.3230*/3231OSSL_TIME deadline = ossl_time_infinite();3232uint32_t enc_level, pn_space;32333234/*3235* ACK generation is not CC-gated - packets containing only ACKs are allowed3236* to bypass CC. We want to generate ACK frames even if we are currently3237* restricted by CC so the peer knows we have received data. The generate3238* call will take care of selecting the correct packet archetype.3239*/3240for (enc_level = QUIC_ENC_LEVEL_INITIAL;3241enc_level < QUIC_ENC_LEVEL_NUM;3242++enc_level)3243if (ossl_qtx_is_enc_level_provisioned(txp->args.qtx, enc_level)) {3244pn_space = ossl_quic_enc_level_to_pn_space(enc_level);3245deadline = ossl_time_min(deadline,3246ossl_ackm_get_ack_deadline(txp->args.ackm, pn_space));3247}32483249/* When will CC let us send more? */3250if (txp->args.cc_method->get_tx_allowance(txp->args.cc_data) == 0)3251deadline = ossl_time_min(deadline,3252txp->args.cc_method->get_wakeup_deadline(txp->args.cc_data));32533254return deadline;3255}325632573258