2 * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
10 #include "internal/quic_txp.h"
11 #include "internal/quic_fifd.h"
12 #include "internal/quic_stream_map.h"
13 #include "internal/common.h"
14 #include <openssl/err.h>
16 #define MIN_CRYPTO_HDR_SIZE 3
18 #define MIN_FRAME_SIZE_HANDSHAKE_DONE 1
19 #define MIN_FRAME_SIZE_MAX_DATA 2
20 #define MIN_FRAME_SIZE_ACK 5
21 #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 2
24 #define MIN_FRAME_SIZE_MAX_STREAMS_UNI 2
26 struct ossl_quic_tx_packetiser_st
{
27 OSSL_QUIC_TX_PACKETISER_ARGS args
;
30 * Opaque initial token blob provided by caller. TXP frees using the
31 * callback when it is no longer needed.
33 const unsigned char *initial_token
;
34 size_t initial_token_len
;
35 ossl_quic_initial_token_free_fn
*initial_token_free_cb
;
36 void *initial_token_free_cb_arg
;
38 /* Subcomponents of the TXP that we own. */
39 QUIC_FIFD fifd
; /* QUIC Frame-in-Flight Dispatcher */
42 uint64_t next_pn
[QUIC_PN_SPACE_NUM
]; /* Next PN to use in given PN space. */
43 OSSL_TIME last_tx_time
; /* Last time a packet was generated, or 0. */
45 /* Internal state - frame (re)generation flags. */
46 unsigned int want_handshake_done
: 1;
47 unsigned int want_max_data
: 1;
48 unsigned int want_max_streams_bidi
: 1;
49 unsigned int want_max_streams_uni
: 1;
51 /* Internal state - frame (re)generation flags - per PN space. */
52 unsigned int want_ack
: QUIC_PN_SPACE_NUM
;
53 unsigned int force_ack_eliciting
: QUIC_PN_SPACE_NUM
;
56 * Internal state - connection close terminal state.
57 * Once this is set, it is not unset unlike other want_ flags - we keep
58 * sending it in every packet.
60 unsigned int want_conn_close
: 1;
62 /* Has the handshake been completed? */
63 unsigned int handshake_complete
: 1;
65 OSSL_QUIC_FRAME_CONN_CLOSE conn_close_frame
;
67 /* Internal state - packet assembly. */
68 unsigned char *scratch
; /* scratch buffer for packet assembly */
69 size_t scratch_len
; /* number of bytes allocated for scratch */
70 OSSL_QTX_IOVEC
*iovec
; /* scratch iovec array for use with QTX */
71 size_t alloc_iovec
; /* size of iovec array */
75 * The TX helper records state used while generating frames into packets. It
76 * enables serialization into the packet to be done "transactionally" where
77 * serialization of a frame can be rolled back if it fails midway (e.g. if it
81 OSSL_QUIC_TX_PACKETISER
*txp
;
83 * The Maximum Packet Payload Length in bytes. This is the amount of
84 * space we have to generate frames into.
88 * Number of bytes we have generated so far.
90 size_t bytes_appended
;
92 * Number of scratch bytes in txp->scratch we have used so far. Some iovecs
93 * will reference this scratch buffer. When we need to use more of it (e.g.
94 * when we need to put frame headers somewhere), we append to the scratch
95 * buffer, resizing if necessary, and increase this accordingly.
99 * Bytes reserved in the MaxPPL budget. We keep this number of bytes spare
100 * until reserve_allowed is set to 1. Currently this is always at most 1, as
101 * a PING frame takes up one byte and this mechanism is only used to ensure
102 * we can encode a PING frame if we have been asked to ensure a packet is
103 * ACK-eliciting and we are unusure if we are going to add any other
104 * ACK-eliciting frames before we reach our MaxPPL budget.
108 * Number of iovecs we have currently appended. This is the number of
109 * entries valid in txp->iovec.
113 * Whether we are allowed to make use of the reserve bytes in our MaxPPL
114 * budget. This is used to ensure we have room to append a PING frame later
115 * if we need to. Once we know we will not need to append a PING frame, this
118 unsigned int reserve_allowed
: 1;
120 * Set to 1 if we have appended a STREAM frame with an implicit length. If
121 * this happens we should never append another frame after that frame as it
122 * cannot be validly encoded. This is just a safety check.
124 unsigned int done_implicit
: 1;
127 * The fields in this structure are valid if active is set, which means
128 * that a serialization transaction is currently in progress.
132 unsigned int active
: 1;
136 static void tx_helper_rollback(struct tx_helper
*h
);
137 static int txp_ensure_iovec(OSSL_QUIC_TX_PACKETISER
*txp
, size_t num
);
139 /* Initialises the TX helper. */
140 static int tx_helper_init(struct tx_helper
*h
, OSSL_QUIC_TX_PACKETISER
*txp
,
141 size_t max_ppl
, size_t reserve
)
143 if (reserve
> max_ppl
)
147 h
->max_ppl
= max_ppl
;
148 h
->reserve
= reserve
;
150 h
->bytes_appended
= 0;
151 h
->scratch_bytes
= 0;
152 h
->reserve_allowed
= 0;
153 h
->done_implicit
= 0;
157 if (max_ppl
> h
->txp
->scratch_len
) {
158 unsigned char *scratch
;
160 scratch
= OPENSSL_realloc(h
->txp
->scratch
, max_ppl
);
164 h
->txp
->scratch
= scratch
;
165 h
->txp
->scratch_len
= max_ppl
;
171 static void tx_helper_cleanup(struct tx_helper
*h
)
174 tx_helper_rollback(h
);
179 static void tx_helper_unrestrict(struct tx_helper
*h
)
181 h
->reserve_allowed
= 1;
185 * Append an extent of memory to the iovec list. The memory must remain
186 * allocated until we finish generating the packet and call the QTX.
188 * In general, the buffers passed to this function will be from one of two
191 * - Application data contained in stream buffers managed elsewhere
192 * in the QUIC stack; or
194 * - Control frame data appended into txp->scratch using tx_helper_begin and
198 static int tx_helper_append_iovec(struct tx_helper
*h
,
199 const unsigned char *buf
,
205 if (!ossl_assert(!h
->done_implicit
))
208 if (!txp_ensure_iovec(h
->txp
, h
->num_iovec
+ 1))
211 h
->txp
->iovec
[h
->num_iovec
].buf
= buf
;
212 h
->txp
->iovec
[h
->num_iovec
].buf_len
= buf_len
;
215 h
->bytes_appended
+= buf_len
;
220 * How many more bytes of space do we have left in our plaintext packet payload?
222 static size_t tx_helper_get_space_left(struct tx_helper
*h
)
225 - (h
->reserve_allowed
? 0 : h
->reserve
) - h
->bytes_appended
;
229 * Begin a control frame serialization transaction. This allows the
230 * serialization of the control frame to be backed out if it turns out it won't
231 * fit. Write the control frame to the returned WPACKET. Ensure you always
232 * call tx_helper_rollback or tx_helper_commit (or tx_helper_cleanup). Returns
235 static WPACKET
*tx_helper_begin(struct tx_helper
*h
)
237 size_t space_left
, len
;
240 if (!ossl_assert(!h
->txn
.active
))
243 if (!ossl_assert(!h
->done_implicit
))
246 data
= (unsigned char *)h
->txp
->scratch
+ h
->scratch_bytes
;
247 len
= h
->txp
->scratch_len
- h
->scratch_bytes
;
249 space_left
= tx_helper_get_space_left(h
);
250 if (!ossl_assert(space_left
<= len
))
253 if (!WPACKET_init_static_len(&h
->txn
.wpkt
, data
, len
, 0))
256 if (!WPACKET_set_max_size(&h
->txn
.wpkt
, space_left
)) {
257 WPACKET_cleanup(&h
->txn
.wpkt
);
266 static void tx_helper_end(struct tx_helper
*h
, int success
)
269 WPACKET_finish(&h
->txn
.wpkt
);
271 WPACKET_cleanup(&h
->txn
.wpkt
);
277 /* Abort a control frame serialization transaction. */
278 static void tx_helper_rollback(struct tx_helper
*h
)
286 /* Commit a control frame. */
287 static int tx_helper_commit(struct tx_helper
*h
)
294 if (!WPACKET_get_total_written(&h
->txn
.wpkt
, &l
)) {
299 if (!tx_helper_append_iovec(h
, h
->txn
.data
, l
)) {
304 h
->scratch_bytes
+= l
;
309 static QUIC_SSTREAM
*get_sstream_by_id(uint64_t stream_id
, uint32_t pn_space
,
311 static void on_regen_notify(uint64_t frame_type
, uint64_t stream_id
,
312 QUIC_TXPIM_PKT
*pkt
, void *arg
);
313 static int sstream_is_pending(QUIC_SSTREAM
*sstream
);
314 static int txp_el_pending(OSSL_QUIC_TX_PACKETISER
*txp
, uint32_t enc_level
,
317 uint32_t *conn_close_enc_level
);
318 static int txp_generate_for_el(OSSL_QUIC_TX_PACKETISER
*txp
, uint32_t enc_level
,
321 int is_last_in_dgram
,
322 int dgram_contains_initial
,
323 int chosen_for_conn_close
,
324 int *sent_ack_eliciting
);
325 static size_t txp_determine_pn_len(OSSL_QUIC_TX_PACKETISER
*txp
);
326 static int txp_determine_ppl_from_pl(OSSL_QUIC_TX_PACKETISER
*txp
,
331 static size_t txp_get_mdpl(OSSL_QUIC_TX_PACKETISER
*txp
);
332 static int txp_generate_for_el_actual(OSSL_QUIC_TX_PACKETISER
*txp
,
339 int chosen_for_conn_close
,
340 int *sent_ack_eliciting
);
342 OSSL_QUIC_TX_PACKETISER
*ossl_quic_tx_packetiser_new(const OSSL_QUIC_TX_PACKETISER_ARGS
*args
)
344 OSSL_QUIC_TX_PACKETISER
*txp
;
348 || args
->txpim
== NULL
350 || args
->ackm
== NULL
352 || args
->conn_txfc
== NULL
353 || args
->conn_rxfc
== NULL
) {
354 ERR_raise(ERR_LIB_SSL
, ERR_R_PASSED_NULL_PARAMETER
);
358 txp
= OPENSSL_zalloc(sizeof(*txp
));
363 txp
->last_tx_time
= ossl_time_zero();
365 if (!ossl_quic_fifd_init(&txp
->fifd
,
366 txp
->args
.cfq
, txp
->args
.ackm
, txp
->args
.txpim
,
367 get_sstream_by_id
, txp
,
368 on_regen_notify
, txp
)) {
376 void ossl_quic_tx_packetiser_free(OSSL_QUIC_TX_PACKETISER
*txp
)
381 ossl_quic_tx_packetiser_set_initial_token(txp
, NULL
, 0, NULL
, NULL
);
382 ossl_quic_fifd_cleanup(&txp
->fifd
);
383 OPENSSL_free(txp
->iovec
);
384 OPENSSL_free(txp
->conn_close_frame
.reason
);
385 OPENSSL_free(txp
->scratch
);
389 void ossl_quic_tx_packetiser_set_initial_token(OSSL_QUIC_TX_PACKETISER
*txp
,
390 const unsigned char *token
,
392 ossl_quic_initial_token_free_fn
*free_cb
,
395 if (txp
->initial_token
!= NULL
&& txp
->initial_token_free_cb
!= NULL
)
396 txp
->initial_token_free_cb(txp
->initial_token
, txp
->initial_token_len
,
397 txp
->initial_token_free_cb_arg
);
399 txp
->initial_token
= token
;
400 txp
->initial_token_len
= token_len
;
401 txp
->initial_token_free_cb
= free_cb
;
402 txp
->initial_token_free_cb_arg
= free_cb_arg
;
405 int ossl_quic_tx_packetiser_set_cur_dcid(OSSL_QUIC_TX_PACKETISER
*txp
,
406 const QUIC_CONN_ID
*dcid
)
409 ERR_raise(ERR_LIB_SSL
, ERR_R_PASSED_NULL_PARAMETER
);
413 txp
->args
.cur_dcid
= *dcid
;
417 int ossl_quic_tx_packetiser_set_cur_scid(OSSL_QUIC_TX_PACKETISER
*txp
,
418 const QUIC_CONN_ID
*scid
)
421 ERR_raise(ERR_LIB_SSL
, ERR_R_PASSED_NULL_PARAMETER
);
425 txp
->args
.cur_scid
= *scid
;
429 /* Change the destination L4 address the TXP uses to send datagrams. */
430 int ossl_quic_tx_packetiser_set_peer(OSSL_QUIC_TX_PACKETISER
*txp
,
431 const BIO_ADDR
*peer
)
434 ERR_raise(ERR_LIB_SSL
, ERR_R_PASSED_NULL_PARAMETER
);
438 txp
->args
.peer
= *peer
;
442 int ossl_quic_tx_packetiser_discard_enc_level(OSSL_QUIC_TX_PACKETISER
*txp
,
445 if (enc_level
>= QUIC_ENC_LEVEL_NUM
) {
446 ERR_raise(ERR_LIB_SSL
, ERR_R_PASSED_INVALID_ARGUMENT
);
450 if (enc_level
!= QUIC_ENC_LEVEL_0RTT
)
451 txp
->args
.crypto
[ossl_quic_enc_level_to_pn_space(enc_level
)] = NULL
;
456 void ossl_quic_tx_packetiser_notify_handshake_complete(OSSL_QUIC_TX_PACKETISER
*txp
)
458 txp
->handshake_complete
= 1;
461 void ossl_quic_tx_packetiser_schedule_handshake_done(OSSL_QUIC_TX_PACKETISER
*txp
)
463 txp
->want_handshake_done
= 1;
466 void ossl_quic_tx_packetiser_schedule_ack_eliciting(OSSL_QUIC_TX_PACKETISER
*txp
,
469 txp
->force_ack_eliciting
|= (1UL << pn_space
);
472 #define TXP_ERR_INTERNAL 0 /* Internal (e.g. alloc) error */
473 #define TXP_ERR_SUCCESS 1 /* Success */
474 #define TXP_ERR_SPACE 2 /* Not enough room for another packet */
475 #define TXP_ERR_INPUT 3 /* Invalid/malformed input */
477 int ossl_quic_tx_packetiser_has_pending(OSSL_QUIC_TX_PACKETISER
*txp
,
481 uint32_t enc_level
, conn_close_enc_level
= QUIC_ENC_LEVEL_NUM
;
482 int bypass_cc
= ((flags
& TX_PACKETISER_BYPASS_CC
) != 0);
486 = (bypass_cc
|| txp
->args
.cc_method
->can_send(txp
->args
.cc_data
));
488 for (enc_level
= QUIC_ENC_LEVEL_INITIAL
;
489 enc_level
< QUIC_ENC_LEVEL_NUM
;
491 if (txp_el_pending(txp
, enc_level
, archetype
, cc_can_send
,
492 &conn_close_enc_level
))
499 * Generates a datagram by polling the various ELs to determine if they want to
500 * generate any frames, and generating a datagram which coalesces packets for
503 int ossl_quic_tx_packetiser_generate(OSSL_QUIC_TX_PACKETISER
*txp
,
505 int *sent_ack_eliciting
)
507 uint32_t enc_level
, conn_close_enc_level
= QUIC_ENC_LEVEL_NUM
;
508 int have_pkt_for_el
[QUIC_ENC_LEVEL_NUM
], is_last_in_dgram
, cc_can_send
;
509 size_t num_el_in_dgram
= 0, pkts_done
= 0;
513 * If CC says we cannot send we still may be able to send any queued probes.
515 cc_can_send
= txp
->args
.cc_method
->can_send(txp
->args
.cc_data
);
517 for (enc_level
= QUIC_ENC_LEVEL_INITIAL
;
518 enc_level
< QUIC_ENC_LEVEL_NUM
;
520 have_pkt_for_el
[enc_level
] = txp_el_pending(txp
, enc_level
, archetype
,
522 &conn_close_enc_level
);
523 if (have_pkt_for_el
[enc_level
])
527 if (num_el_in_dgram
== 0)
528 return TX_PACKETISER_RES_NO_PKT
;
531 * Should not be needed, but a sanity check in case anyone else has been
534 ossl_qtx_finish_dgram(txp
->args
.qtx
);
536 for (enc_level
= QUIC_ENC_LEVEL_INITIAL
;
537 enc_level
< QUIC_ENC_LEVEL_NUM
;
539 if (!have_pkt_for_el
[enc_level
])
542 is_last_in_dgram
= (pkts_done
+ 1 == num_el_in_dgram
);
543 rc
= txp_generate_for_el(txp
, enc_level
, archetype
, cc_can_send
,
545 have_pkt_for_el
[QUIC_ENC_LEVEL_INITIAL
],
546 enc_level
== conn_close_enc_level
,
549 if (rc
!= TXP_ERR_SUCCESS
) {
551 * If we already successfully did at least one, make sure we report
552 * this via the return code.
557 return TX_PACKETISER_RES_FAILURE
;
563 ossl_qtx_finish_dgram(txp
->args
.qtx
);
564 return TX_PACKETISER_RES_SENT_PKT
;
567 struct archetype_data
{
568 unsigned int allow_ack
: 1;
569 unsigned int allow_ping
: 1;
570 unsigned int allow_crypto
: 1;
571 unsigned int allow_handshake_done
: 1;
572 unsigned int allow_path_challenge
: 1;
573 unsigned int allow_path_response
: 1;
574 unsigned int allow_new_conn_id
: 1;
575 unsigned int allow_retire_conn_id
: 1;
576 unsigned int allow_stream_rel
: 1;
577 unsigned int allow_conn_fc
: 1;
578 unsigned int allow_conn_close
: 1;
579 unsigned int allow_cfq_other
: 1;
580 unsigned int allow_new_token
: 1;
581 unsigned int allow_force_ack_eliciting
: 1;
584 static const struct archetype_data archetypes
[QUIC_ENC_LEVEL_NUM
][TX_PACKETISER_ARCHETYPE_NUM
] = {
587 /* EL 0(INITIAL) - Archetype 0(NORMAL) */
591 /*allow_crypto =*/ 1,
592 /*allow_handshake_done =*/ 0,
593 /*allow_path_challenge =*/ 0,
594 /*allow_path_response =*/ 0,
595 /*allow_new_conn_id =*/ 0,
596 /*allow_retire_conn_id =*/ 0,
597 /*allow_stream_rel =*/ 0,
598 /*allow_conn_fc =*/ 0,
599 /*allow_conn_close =*/ 1,
600 /*allow_cfq_other =*/ 1,
601 /*allow_new_token =*/ 0,
602 /*allow_force_ack_eliciting =*/ 1,
604 /* EL 0(INITIAL) - Archetype 1(ACK_ONLY) */
608 /*allow_crypto =*/ 0,
609 /*allow_handshake_done =*/ 0,
610 /*allow_path_challenge =*/ 0,
611 /*allow_path_response =*/ 0,
612 /*allow_new_conn_id =*/ 0,
613 /*allow_retire_conn_id =*/ 0,
614 /*allow_stream_rel =*/ 0,
615 /*allow_conn_fc =*/ 0,
616 /*allow_conn_close =*/ 0,
617 /*allow_cfq_other =*/ 0,
618 /*allow_new_token =*/ 0,
619 /*allow_force_ack_eliciting =*/ 1,
622 /* EL 1(HANDSHAKE) */
624 /* EL 1(HANDSHAKE) - Archetype 0(NORMAL) */
628 /*allow_crypto =*/ 1,
629 /*allow_handshake_done =*/ 0,
630 /*allow_path_challenge =*/ 0,
631 /*allow_path_response =*/ 0,
632 /*allow_new_conn_id =*/ 0,
633 /*allow_retire_conn_id =*/ 0,
634 /*allow_stream_rel =*/ 0,
635 /*allow_conn_fc =*/ 0,
636 /*allow_conn_close =*/ 1,
637 /*allow_cfq_other =*/ 1,
638 /*allow_new_token =*/ 0,
639 /*allow_force_ack_eliciting =*/ 1,
641 /* EL 1(HANDSHAKE) - Archetype 1(ACK_ONLY) */
645 /*allow_crypto =*/ 0,
646 /*allow_handshake_done =*/ 0,
647 /*allow_path_challenge =*/ 0,
648 /*allow_path_response =*/ 0,
649 /*allow_new_conn_id =*/ 0,
650 /*allow_retire_conn_id =*/ 0,
651 /*allow_stream_rel =*/ 0,
652 /*allow_conn_fc =*/ 0,
653 /*allow_conn_close =*/ 0,
654 /*allow_cfq_other =*/ 0,
655 /*allow_new_token =*/ 0,
656 /*allow_force_ack_eliciting =*/ 1,
661 /* EL 2(0RTT) - Archetype 0(NORMAL) */
665 /*allow_crypto =*/ 0,
666 /*allow_handshake_done =*/ 0,
667 /*allow_path_challenge =*/ 0,
668 /*allow_path_response =*/ 0,
669 /*allow_new_conn_id =*/ 1,
670 /*allow_retire_conn_id =*/ 1,
671 /*allow_stream_rel =*/ 1,
672 /*allow_conn_fc =*/ 1,
673 /*allow_conn_close =*/ 1,
674 /*allow_cfq_other =*/ 0,
675 /*allow_new_token =*/ 0,
676 /*allow_force_ack_eliciting =*/ 0,
678 /* EL 2(0RTT) - Archetype 1(ACK_ONLY) */
682 /*allow_crypto =*/ 0,
683 /*allow_handshake_done =*/ 0,
684 /*allow_path_challenge =*/ 0,
685 /*allow_path_response =*/ 0,
686 /*allow_new_conn_id =*/ 0,
687 /*allow_retire_conn_id =*/ 0,
688 /*allow_stream_rel =*/ 0,
689 /*allow_conn_fc =*/ 0,
690 /*allow_conn_close =*/ 0,
691 /*allow_cfq_other =*/ 0,
692 /*allow_new_token =*/ 0,
693 /*allow_force_ack_eliciting =*/ 0,
698 /* EL 3(1RTT) - Archetype 0(NORMAL) */
702 /*allow_crypto =*/ 1,
703 /*allow_handshake_done =*/ 1,
704 /*allow_path_challenge =*/ 0,
705 /*allow_path_response =*/ 0,
706 /*allow_new_conn_id =*/ 1,
707 /*allow_retire_conn_id =*/ 1,
708 /*allow_stream_rel =*/ 1,
709 /*allow_conn_fc =*/ 1,
710 /*allow_conn_close =*/ 1,
711 /*allow_cfq_other =*/ 1,
712 /*allow_new_token =*/ 1,
713 /*allow_force_ack_eliciting =*/ 1,
715 /* EL 3(1RTT) - Archetype 1(ACK_ONLY) */
719 /*allow_crypto =*/ 0,
720 /*allow_handshake_done =*/ 0,
721 /*allow_path_challenge =*/ 0,
722 /*allow_path_response =*/ 0,
723 /*allow_new_conn_id =*/ 0,
724 /*allow_retire_conn_id =*/ 0,
725 /*allow_stream_rel =*/ 0,
726 /*allow_conn_fc =*/ 0,
727 /*allow_conn_close =*/ 0,
728 /*allow_cfq_other =*/ 0,
729 /*allow_new_token =*/ 0,
730 /*allow_force_ack_eliciting =*/ 1,
735 static int txp_get_archetype_data(uint32_t enc_level
,
737 struct archetype_data
*a
)
739 if (enc_level
>= QUIC_ENC_LEVEL_NUM
740 || archetype
>= TX_PACKETISER_ARCHETYPE_NUM
)
743 /* No need to avoid copying this as it should not exceed one int in size. */
744 *a
= archetypes
[enc_level
][archetype
];
749 * Returns 1 if the given EL wants to produce one or more frames.
750 * Always returns 0 if the given EL is discarded.
752 static int txp_el_pending(OSSL_QUIC_TX_PACKETISER
*txp
, uint32_t enc_level
,
755 uint32_t *conn_close_enc_level
)
757 struct archetype_data a
;
758 uint32_t pn_space
= ossl_quic_enc_level_to_pn_space(enc_level
);
759 QUIC_CFQ_ITEM
*cfq_item
;
761 if (!ossl_qtx_is_enc_level_provisioned(txp
->args
.qtx
, enc_level
))
764 if (*conn_close_enc_level
> enc_level
)
765 *conn_close_enc_level
= enc_level
;
767 if (!txp_get_archetype_data(enc_level
, archetype
, &a
))
770 /* Do we need to send a PTO probe? */
771 if (a
.allow_force_ack_eliciting
) {
772 OSSL_ACKM_PROBE_INFO
*probe_info
773 = ossl_ackm_get0_probe_request(txp
->args
.ackm
);
775 if ((enc_level
== QUIC_ENC_LEVEL_INITIAL
776 && probe_info
->anti_deadlock_initial
> 0)
777 || (enc_level
== QUIC_ENC_LEVEL_HANDSHAKE
778 && probe_info
->anti_deadlock_handshake
> 0)
779 || probe_info
->pto
[pn_space
] > 0)
784 /* If CC says we cannot currently send, we can only send probes. */
787 /* Does the crypto stream for this EL want to produce anything? */
788 if (a
.allow_crypto
&& sstream_is_pending(txp
->args
.crypto
[pn_space
]))
791 /* Does the ACKM for this PN space want to produce anything? */
792 if (a
.allow_ack
&& (ossl_ackm_is_ack_desired(txp
->args
.ackm
, pn_space
)
793 || (txp
->want_ack
& (1UL << pn_space
)) != 0))
796 /* Do we need to force emission of an ACK-eliciting packet? */
797 if (a
.allow_force_ack_eliciting
798 && (txp
->force_ack_eliciting
& (1UL << pn_space
)) != 0)
801 /* Does the connection-level RXFC want to produce a frame? */
802 if (a
.allow_conn_fc
&& (txp
->want_max_data
803 || ossl_quic_rxfc_has_cwm_changed(txp
->args
.conn_rxfc
, 0)))
806 /* Do we want to produce a MAX_STREAMS frame? */
807 if (a
.allow_conn_fc
&& (txp
->want_max_streams_bidi
808 || txp
->want_max_streams_uni
))
811 /* Do we want to produce a HANDSHAKE_DONE frame? */
812 if (a
.allow_handshake_done
&& txp
->want_handshake_done
)
815 /* Do we want to produce a CONNECTION_CLOSE frame? */
816 if (a
.allow_conn_close
&& txp
->want_conn_close
&&
817 *conn_close_enc_level
== enc_level
)
819 * This is a bit of a special case since CONNECTION_CLOSE can appear in
820 * most packet types, and when we decide we want to send it this status
821 * isn't tied to a specific EL. So if we want to send it, we send it
822 * only on the lowest non-dropped EL.
826 /* Does the CFQ have any frames queued for this PN space? */
827 if (enc_level
!= QUIC_ENC_LEVEL_0RTT
)
828 for (cfq_item
= ossl_quic_cfq_get_priority_head(txp
->args
.cfq
, pn_space
);
830 cfq_item
= ossl_quic_cfq_item_get_priority_next(cfq_item
, pn_space
)) {
831 uint64_t frame_type
= ossl_quic_cfq_item_get_frame_type(cfq_item
);
833 switch (frame_type
) {
834 case OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID
:
835 if (a
.allow_new_conn_id
)
838 case OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID
:
839 if (a
.allow_retire_conn_id
)
842 case OSSL_QUIC_FRAME_TYPE_NEW_TOKEN
:
843 if (a
.allow_new_token
)
847 if (a
.allow_cfq_other
)
853 if (a
.allow_stream_rel
&& txp
->handshake_complete
) {
856 /* If there are any active streams, 0/1-RTT wants to produce a packet.
857 * Whether a stream is on the active list is required to be precise
858 * (i.e., a stream is never on the active list if we cannot produce a
859 * frame for it), and all stream-related frames are governed by
860 * a.allow_stream_rel (i.e., if we can send one type of stream-related
861 * frame, we can send any of them), so we don't need to inspect
862 * individual streams on the active list, just confirm that the active
865 ossl_quic_stream_iter_init(&it
, txp
->args
.qsm
, 0);
866 if (it
.stream
!= NULL
)
873 static int sstream_is_pending(QUIC_SSTREAM
*sstream
)
875 OSSL_QUIC_FRAME_STREAM hdr
;
876 OSSL_QTX_IOVEC iov
[2];
877 size_t num_iov
= OSSL_NELEM(iov
);
879 return ossl_quic_sstream_get_stream_frame(sstream
, 0, &hdr
, iov
, &num_iov
);
883 * Generates a packet for a given EL, coalescing it into the current datagram.
885 * is_last_in_dgram and dgram_contains_initial are used to determine padding
888 * Returns TXP_ERR_* value.
890 static int txp_generate_for_el(OSSL_QUIC_TX_PACKETISER
*txp
, uint32_t enc_level
,
893 int is_last_in_dgram
,
894 int dgram_contains_initial
,
895 int chosen_for_conn_close
,
896 int *sent_ack_eliciting
)
898 int must_pad
= dgram_contains_initial
&& is_last_in_dgram
;
899 size_t min_dpl
, min_pl
, min_ppl
, cmpl
, cmppl
, running_total
;
900 size_t mdpl
, hdr_len
, pkt_overhead
, cc_limit
;
903 OSSL_TIME time_since_last
;
905 /* Determine the limit CC imposes on what we can send. */
906 if (ossl_time_is_zero(txp
->last_tx_time
))
907 time_since_last
= ossl_time_zero();
909 time_since_last
= ossl_time_subtract(txp
->args
.now(txp
->args
.now_arg
),
914 * If we are called when we cannot send, this must be because we want
915 * to generate a probe. In this circumstance, don't clamp based on CC.
919 /* Allow CC to clamp how much we can send. */
920 cc_limit_
= txp
->args
.cc_method
->get_send_allowance(txp
->args
.cc_data
,
922 ossl_time_is_zero(time_since_last
));
924 cc_limit
= (cc_limit_
> SIZE_MAX
? SIZE_MAX
: (size_t)cc_limit_
);
927 /* Assemble packet header. */
928 phdr
.type
= ossl_quic_enc_level_to_pkt_type(enc_level
);
930 phdr
.pn_len
= txp_determine_pn_len(txp
);
933 phdr
.version
= QUIC_VERSION_1
;
934 phdr
.dst_conn_id
= txp
->args
.cur_dcid
;
935 phdr
.src_conn_id
= txp
->args
.cur_scid
;
938 * We need to know the length of the payload to get an accurate header
939 * length for non-1RTT packets, because the Length field found in
940 * Initial/Handshake/0-RTT packets uses a variable-length encoding. However,
941 * we don't have a good idea of the length of our payload, because the
942 * length of the payload depends on the room in the datagram after fitting
943 * the header, which depends on the size of the header.
945 * In general, it does not matter if a packet is slightly shorter (because
946 * e.g. we predicted use of a 2-byte length field, but ended up only needing
947 * a 1-byte length field). However this does matter for Initial packets
948 * which must be at least 1200 bytes, which is also the assumed default MTU;
949 * therefore in many cases Initial packets will be padded to 1200 bytes,
950 * which means if we overestimated the header size, we will be short by a
951 * few bytes and the server will ignore the packet for being too short. In
952 * this case, however, such packets always *will* be padded to meet 1200
953 * bytes, which requires a 2-byte length field, so we don't actually need to
954 * worry about this. Thus we estimate the header length assuming a 2-byte
955 * length field here, which should in practice work well in all cases.
957 phdr
.len
= OSSL_QUIC_VLINT_2B_MAX
- phdr
.pn_len
;
959 if (enc_level
== QUIC_ENC_LEVEL_INITIAL
) {
960 phdr
.token
= txp
->initial_token
;
961 phdr
.token_len
= txp
->initial_token_len
;
967 hdr_len
= ossl_quic_wire_get_encoded_pkt_hdr_len(phdr
.dst_conn_id
.id_len
,
970 return TXP_ERR_INPUT
;
972 /* MinDPL: Minimum total datagram payload length. */
973 min_dpl
= must_pad
? QUIC_MIN_INITIAL_DGRAM_LEN
: 0;
975 /* How much data is already in the current datagram? */
976 running_total
= ossl_qtx_get_cur_dgram_len_bytes(txp
->args
.qtx
);
978 /* MinPL: Minimum length of the fully encoded packet. */
979 min_pl
= running_total
< min_dpl
? min_dpl
- running_total
: 0;
980 if ((uint64_t)min_pl
> cc_limit
)
982 * Congestion control does not allow us to send a packet of adequate
985 return TXP_ERR_SPACE
;
987 /* MinPPL: Minimum plaintext payload length needed to meet MinPL. */
988 if (!txp_determine_ppl_from_pl(txp
, min_pl
, enc_level
, hdr_len
, &min_ppl
))
989 /* MinPL is less than a valid packet size, so just use a MinPPL of 0. */
992 /* MDPL: Maximum datagram payload length. */
993 mdpl
= txp_get_mdpl(txp
);
996 * CMPL: Maximum encoded packet size we can put into this datagram given any
997 * previous packets coalesced into it.
999 if (running_total
> mdpl
)
1000 /* Should not be possible, but if it happens: */
1003 cmpl
= mdpl
- running_total
;
1005 /* Clamp CMPL based on congestion control limit. */
1006 if (cmpl
> cc_limit
)
1009 /* CMPPL: Maximum amount we can put into the current datagram payload. */
1010 if (!txp_determine_ppl_from_pl(txp
, cmpl
, enc_level
, hdr_len
, &cmppl
))
1011 return TXP_ERR_SPACE
;
1013 /* Packet overhead (size of headers, AEAD tag, etc.) */
1014 pkt_overhead
= cmpl
- cmppl
;
1016 return txp_generate_for_el_actual(txp
, enc_level
, archetype
, min_ppl
, cmppl
,
1017 pkt_overhead
, &phdr
,
1018 chosen_for_conn_close
,
1019 sent_ack_eliciting
);
1022 /* Determine how many bytes we should use for the encoded PN. */
1023 static size_t txp_determine_pn_len(OSSL_QUIC_TX_PACKETISER
*txp
)
1025 return 4; /* TODO(QUIC) */
1028 /* Determine plaintext packet payload length from payload length. */
1029 static int txp_determine_ppl_from_pl(OSSL_QUIC_TX_PACKETISER
*txp
,
1040 if (!ossl_qtx_calculate_plaintext_payload_len(txp
->args
.qtx
, enc_level
,
1048 static size_t txp_get_mdpl(OSSL_QUIC_TX_PACKETISER
*txp
)
1050 return ossl_qtx_get_mdpl(txp
->args
.qtx
);
1053 static QUIC_SSTREAM
*get_sstream_by_id(uint64_t stream_id
, uint32_t pn_space
,
1056 OSSL_QUIC_TX_PACKETISER
*txp
= arg
;
1059 if (stream_id
== UINT64_MAX
)
1060 return txp
->args
.crypto
[pn_space
];
1062 s
= ossl_quic_stream_map_get_by_id(txp
->args
.qsm
, stream_id
);
1069 static void on_regen_notify(uint64_t frame_type
, uint64_t stream_id
,
1070 QUIC_TXPIM_PKT
*pkt
, void *arg
)
1072 OSSL_QUIC_TX_PACKETISER
*txp
= arg
;
1074 switch (frame_type
) {
1075 case OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE
:
1076 txp
->want_handshake_done
= 1;
1078 case OSSL_QUIC_FRAME_TYPE_MAX_DATA
:
1079 txp
->want_max_data
= 1;
1081 case OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI
:
1082 txp
->want_max_streams_bidi
= 1;
1084 case OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI
:
1085 txp
->want_max_streams_uni
= 1;
1087 case OSSL_QUIC_FRAME_TYPE_ACK_WITH_ECN
:
1088 txp
->want_ack
|= (1UL << pkt
->ackm_pkt
.pkt_space
);
1090 case OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA
:
1093 = ossl_quic_stream_map_get_by_id(txp
->args
.qsm
, stream_id
);
1098 s
->want_max_stream_data
= 1;
1099 ossl_quic_stream_map_update_state(txp
->args
.qsm
, s
);
1102 case OSSL_QUIC_FRAME_TYPE_STOP_SENDING
:
1105 = ossl_quic_stream_map_get_by_id(txp
->args
.qsm
, stream_id
);
1110 s
->want_stop_sending
= 1;
1111 ossl_quic_stream_map_update_state(txp
->args
.qsm
, s
);
1114 case OSSL_QUIC_FRAME_TYPE_RESET_STREAM
:
1117 = ossl_quic_stream_map_get_by_id(txp
->args
.qsm
, stream_id
);
1122 s
->want_reset_stream
= 1;
1123 ossl_quic_stream_map_update_state(txp
->args
.qsm
, s
);
1132 static int txp_generate_pre_token(OSSL_QUIC_TX_PACKETISER
*txp
,
1133 struct tx_helper
*h
,
1134 QUIC_TXPIM_PKT
*tpkt
,
1136 struct archetype_data
*a
,
1137 int chosen_for_conn_close
)
1139 const OSSL_QUIC_FRAME_ACK
*ack
;
1140 OSSL_QUIC_FRAME_ACK ack2
;
1142 tpkt
->ackm_pkt
.largest_acked
= QUIC_PN_INVALID
;
1144 /* ACK Frames (Regenerate) */
1146 && tx_helper_get_space_left(h
) >= MIN_FRAME_SIZE_ACK
1148 || ossl_ackm_is_ack_desired(txp
->args
.ackm
, pn_space
))
1149 && (ack
= ossl_ackm_get_ack_frame(txp
->args
.ackm
, pn_space
)) != NULL
) {
1150 WPACKET
*wpkt
= tx_helper_begin(h
);
1155 /* We do not currently support ECN */
1157 ack2
.ecn_present
= 0;
1159 if (ossl_quic_wire_encode_frame_ack(wpkt
,
1160 txp
->args
.ack_delay_exponent
,
1162 if (!tx_helper_commit(h
))
1165 tpkt
->had_ack_frame
= 1;
1167 if (ack
->num_ack_ranges
> 0)
1168 tpkt
->ackm_pkt
.largest_acked
= ack
->ack_ranges
[0].end
;
1170 tx_helper_rollback(h
);
1174 /* CONNECTION_CLOSE Frames (Regenerate) */
1175 if (a
->allow_conn_close
&& txp
->want_conn_close
&& chosen_for_conn_close
) {
1176 WPACKET
*wpkt
= tx_helper_begin(h
);
1181 if (ossl_quic_wire_encode_frame_conn_close(wpkt
,
1182 &txp
->conn_close_frame
)) {
1183 if (!tx_helper_commit(h
))
1186 tx_helper_rollback(h
);
1193 static int try_len(size_t space_left
, size_t orig_len
,
1194 size_t base_hdr_len
, size_t lenbytes
,
1195 uint64_t maxn
, size_t *hdr_len
, size_t *payload_len
)
1198 size_t maxn_
= maxn
> SIZE_MAX
? SIZE_MAX
: (size_t)maxn
;
1200 *hdr_len
= base_hdr_len
+ lenbytes
;
1202 if (orig_len
== 0 && space_left
>= *hdr_len
) {
1210 if (n
+ *hdr_len
> space_left
)
1211 n
= (space_left
>= *hdr_len
) ? space_left
- *hdr_len
: 0;
1217 static int determine_len(size_t space_left
, size_t orig_len
,
1218 size_t base_hdr_len
,
1219 uint64_t *hlen
, uint64_t *len
)
1222 size_t chosen_payload_len
= 0;
1223 size_t chosen_hdr_len
= 0;
1224 size_t payload_len
[4], hdr_len
[4];
1225 int i
, valid
[4] = {0};
1227 valid
[0] = try_len(space_left
, orig_len
, base_hdr_len
,
1228 1, OSSL_QUIC_VLINT_1B_MAX
,
1229 &hdr_len
[0], &payload_len
[0]);
1230 valid
[1] = try_len(space_left
, orig_len
, base_hdr_len
,
1231 2, OSSL_QUIC_VLINT_2B_MAX
,
1232 &hdr_len
[1], &payload_len
[1]);
1233 valid
[2] = try_len(space_left
, orig_len
, base_hdr_len
,
1234 4, OSSL_QUIC_VLINT_4B_MAX
,
1235 &hdr_len
[2], &payload_len
[2]);
1236 valid
[3] = try_len(space_left
, orig_len
, base_hdr_len
,
1237 8, OSSL_QUIC_VLINT_8B_MAX
,
1238 &hdr_len
[3], &payload_len
[3]);
1240 for (i
= OSSL_NELEM(valid
) - 1; i
>= 0; --i
)
1241 if (valid
[i
] && payload_len
[i
] >= chosen_payload_len
) {
1242 chosen_payload_len
= payload_len
[i
];
1243 chosen_hdr_len
= hdr_len
[i
];
1247 *hlen
= chosen_hdr_len
;
1248 *len
= chosen_payload_len
;
1253 * Given a CRYPTO frame header with accurate chdr->len and a budget
1254 * (space_left), try to find the optimal value of chdr->len to fill as much of
1255 * the budget as possible. This is slightly hairy because larger values of
1256 * chdr->len cause larger encoded sizes of the length field of the frame, which
1257 * in turn mean less space available for payload data. We check all possible
1258 * encodings and choose the optimal encoding.
1260 static int determine_crypto_len(struct tx_helper
*h
,
1261 OSSL_QUIC_FRAME_CRYPTO
*chdr
,
1267 size_t base_hdr_len
; /* CRYPTO header length without length field */
1269 if (chdr
->len
> SIZE_MAX
)
1272 orig_len
= (size_t)chdr
->len
;
1275 base_hdr_len
= ossl_quic_wire_get_encoded_frame_len_crypto_hdr(chdr
);
1276 chdr
->len
= orig_len
;
1277 if (base_hdr_len
== 0)
1282 return determine_len(space_left
, orig_len
, base_hdr_len
, hlen
, len
);
1285 static int determine_stream_len(struct tx_helper
*h
,
1286 OSSL_QUIC_FRAME_STREAM
*shdr
,
1292 size_t base_hdr_len
; /* STREAM header length without length field */
1294 if (shdr
->len
> SIZE_MAX
)
1297 orig_len
= (size_t)shdr
->len
;
1300 base_hdr_len
= ossl_quic_wire_get_encoded_frame_len_stream_hdr(shdr
);
1301 shdr
->len
= orig_len
;
1302 if (base_hdr_len
== 0)
1305 if (shdr
->has_explicit_len
)
1308 return determine_len(space_left
, orig_len
, base_hdr_len
, hlen
, len
);
1311 static int txp_generate_crypto_frames(OSSL_QUIC_TX_PACKETISER
*txp
,
1312 struct tx_helper
*h
,
1314 QUIC_TXPIM_PKT
*tpkt
,
1315 int *have_ack_eliciting
)
1317 size_t num_stream_iovec
;
1318 OSSL_QUIC_FRAME_STREAM shdr
= {0};
1319 OSSL_QUIC_FRAME_CRYPTO chdr
= {0};
1320 OSSL_QTX_IOVEC iov
[2];
1323 QUIC_TXPIM_CHUNK chunk
= {0};
1324 size_t i
, space_left
;
1327 space_left
= tx_helper_get_space_left(h
);
1329 if (space_left
< MIN_FRAME_SIZE_CRYPTO
)
1330 return 1; /* no point trying */
1332 /* Do we have any CRYPTO data waiting? */
1333 num_stream_iovec
= OSSL_NELEM(iov
);
1334 if (!ossl_quic_sstream_get_stream_frame(txp
->args
.crypto
[pn_space
],
1337 return 1; /* nothing to do */
1339 /* Convert STREAM frame header to CRYPTO frame header */
1340 chdr
.offset
= shdr
.offset
;
1341 chdr
.len
= shdr
.len
;
1344 return 1; /* nothing to do */
1346 /* Find best fit (header length, payload length) combination. */
1347 if (!determine_crypto_len(h
, &chdr
, space_left
, &hdr_bytes
,
1349 return 1; /* can't fit anything */
1352 * Truncate IOVs to match our chosen length.
1354 * The length cannot be more than SIZE_MAX because this length comes
1355 * from our send stream buffer.
1357 ossl_quic_sstream_adjust_iov((size_t)chdr
.len
, iov
, num_stream_iovec
);
1360 * Ensure we have enough iovecs allocated (1 for the header, up to 2 for
1361 * the the stream data.)
1363 if (!txp_ensure_iovec(txp
, h
->num_iovec
+ 3))
1364 return 0; /* alloc error */
1366 /* Encode the header. */
1367 wpkt
= tx_helper_begin(h
);
1369 return 0; /* alloc error */
1371 if (!ossl_quic_wire_encode_frame_crypto_hdr(wpkt
, &chdr
)) {
1372 tx_helper_rollback(h
);
1373 return 1; /* can't fit */
1376 if (!tx_helper_commit(h
))
1377 return 0; /* alloc error */
1379 /* Add payload iovecs to the helper (infallible). */
1380 for (i
= 0; i
< num_stream_iovec
; ++i
)
1381 tx_helper_append_iovec(h
, iov
[i
].buf
, iov
[i
].buf_len
);
1383 *have_ack_eliciting
= 1;
1384 tx_helper_unrestrict(h
); /* no longer need PING */
1386 /* Log chunk to TXPIM. */
1387 chunk
.stream_id
= UINT64_MAX
; /* crypto stream */
1388 chunk
.start
= chdr
.offset
;
1389 chunk
.end
= chdr
.offset
+ chdr
.len
- 1;
1390 chunk
.has_fin
= 0; /* Crypto stream never ends */
1391 if (!ossl_quic_txpim_pkt_append_chunk(tpkt
, &chunk
))
1392 return 0; /* alloc error */
1397 OSSL_QUIC_FRAME_STREAM shdr
;
1398 OSSL_QTX_IOVEC iov
[2];
1399 size_t num_stream_iovec
;
1403 static int txp_plan_stream_chunk(OSSL_QUIC_TX_PACKETISER
*txp
,
1404 struct tx_helper
*h
,
1405 QUIC_SSTREAM
*sstream
,
1406 QUIC_TXFC
*stream_txfc
,
1408 struct chunk_info
*chunk
)
1410 uint64_t fc_credit
, fc_swm
, fc_limit
;
1412 chunk
->num_stream_iovec
= OSSL_NELEM(chunk
->iov
);
1413 chunk
->valid
= ossl_quic_sstream_get_stream_frame(sstream
, skip
,
1416 &chunk
->num_stream_iovec
);
1420 if (!ossl_assert(chunk
->shdr
.len
> 0 || chunk
->shdr
.is_fin
))
1421 /* Should only have 0-length chunk if FIN */
1424 /* Clamp according to connection and stream-level TXFC. */
1425 fc_credit
= ossl_quic_txfc_get_credit(stream_txfc
);
1426 fc_swm
= ossl_quic_txfc_get_swm(stream_txfc
);
1427 fc_limit
= fc_swm
+ fc_credit
;
1429 if (chunk
->shdr
.len
> 0 && chunk
->shdr
.offset
+ chunk
->shdr
.len
> fc_limit
) {
1430 chunk
->shdr
.len
= (fc_limit
<= chunk
->shdr
.offset
)
1431 ? 0 : fc_limit
- chunk
->shdr
.offset
;
1432 chunk
->shdr
.is_fin
= 0;
1435 if (chunk
->shdr
.len
== 0 && !chunk
->shdr
.is_fin
) {
1437 * Nothing to do due to TXFC. Since SSTREAM returns chunks in ascending
1438 * order of offset we don't need to check any later chunks, so stop
1449 * Returns 0 on fatal error (e.g. allocation failure), 1 on success.
1450 * *packet_full is set to 1 if there is no longer enough room for another STREAM
1451 * frame, and *stream_drained is set to 1 if all stream buffers have now been
1454 static int txp_generate_stream_frames(OSSL_QUIC_TX_PACKETISER
*txp
,
1455 struct tx_helper
*h
,
1457 QUIC_TXPIM_PKT
*tpkt
,
1459 QUIC_SSTREAM
*sstream
,
1460 QUIC_TXFC
*stream_txfc
,
1461 QUIC_STREAM
*next_stream
,
1463 int *have_ack_eliciting
,
1465 int *stream_drained
,
1466 uint64_t *new_credit_consumed
)
1469 struct chunk_info chunks
[2] = {0};
1471 OSSL_QUIC_FRAME_STREAM
*shdr
;
1473 QUIC_TXPIM_CHUNK chunk
;
1474 size_t i
, j
, space_left
;
1475 int needs_padding_if_implicit
, can_fill_payload
, use_explicit_len
;
1476 int could_have_following_chunk
;
1478 uint64_t hdr_len_implicit
, payload_len_implicit
;
1479 uint64_t hdr_len_explicit
, payload_len_explicit
;
1480 uint64_t fc_swm
, fc_new_hwm
;
1482 fc_swm
= ossl_quic_txfc_get_swm(stream_txfc
);
1483 fc_new_hwm
= fc_swm
;
1486 * Load the first two chunks if any offered by the send stream. We retrieve
1487 * the next chunk in advance so we can determine if we need to send any more
1488 * chunks from the same stream after this one, which is needed when
1489 * determining when we can use an implicit length in a STREAM frame.
1491 for (i
= 0; i
< 2; ++i
) {
1492 if (!txp_plan_stream_chunk(txp
, h
, sstream
, stream_txfc
, i
, &chunks
[i
]))
1495 if (i
== 0 && !chunks
[i
].valid
) {
1496 /* No chunks, nothing to do. */
1497 *stream_drained
= 1;
1504 space_left
= tx_helper_get_space_left(h
);
1506 if (!chunks
[i
% 2].valid
) {
1507 /* Out of chunks; we're done. */
1508 *stream_drained
= 1;
1513 if (space_left
< MIN_FRAME_SIZE_STREAM
) {
1519 if (!ossl_assert(!h
->done_implicit
))
1521 * Logic below should have ensured we didn't append an
1522 * implicit-length unless we filled the packet or didn't have
1523 * another stream to handle, so this should not be possible.
1527 shdr
= &chunks
[i
% 2].shdr
;
1528 orig_len
= shdr
->len
;
1530 /* Load next chunk for lookahead. */
1531 if (!txp_plan_stream_chunk(txp
, h
, sstream
, stream_txfc
, i
+ 1,
1532 &chunks
[(i
+ 1) % 2]))
1536 * Find best fit (header length, payload length) combination for if we
1537 * use an implicit length.
1539 shdr
->has_explicit_len
= 0;
1540 hdr_len_implicit
= payload_len_implicit
= 0;
1541 if (!determine_stream_len(h
, shdr
, space_left
,
1542 &hdr_len_implicit
, &payload_len_implicit
)) {
1545 goto err
; /* can't fit anything */
1549 * If using the implicit-length representation would need padding, we
1552 needs_padding_if_implicit
= (h
->bytes_appended
+ hdr_len_implicit
1553 + payload_len_implicit
< min_ppl
);
1556 * If there is a next stream, we don't use the implicit length so we can
1557 * add more STREAM frames after this one, unless there is enough data
1558 * for this STREAM frame to fill the packet.
1560 can_fill_payload
= (hdr_len_implicit
+ payload_len_implicit
1564 * Is there is a stream after this one, or another chunk pending
1565 * transmission in this stream?
1567 could_have_following_chunk
1568 = (next_stream
!= NULL
|| chunks
[(i
+ 1) % 2].valid
);
1570 /* Choose between explicit or implicit length representations. */
1571 use_explicit_len
= !((can_fill_payload
|| !could_have_following_chunk
)
1572 && !needs_padding_if_implicit
);
1574 if (use_explicit_len
) {
1576 * Find best fit (header length, payload length) combination for if
1577 * we use an explicit length.
1579 shdr
->has_explicit_len
= 1;
1580 hdr_len_explicit
= payload_len_explicit
= 0;
1581 if (!determine_stream_len(h
, shdr
, space_left
,
1582 &hdr_len_explicit
, &payload_len_explicit
)) {
1585 goto err
; /* can't fit anything */
1588 shdr
->len
= payload_len_explicit
;
1590 shdr
->has_explicit_len
= 0;
1591 shdr
->len
= payload_len_implicit
;
1594 /* If this is a FIN, don't keep filling the packet with more FINs. */
1596 chunks
[(i
+ 1) % 2].valid
= 0;
1598 /* Truncate IOVs to match our chosen length. */
1599 ossl_quic_sstream_adjust_iov((size_t)shdr
->len
, chunks
[i
% 2].iov
,
1600 chunks
[i
% 2].num_stream_iovec
);
1603 * Ensure we have enough iovecs allocated (1 for the header, up to 2 for
1604 * the the stream data.)
1606 if (!txp_ensure_iovec(txp
, h
->num_iovec
+ 3))
1607 goto err
; /* alloc error */
1609 /* Encode the header. */
1610 wpkt
= tx_helper_begin(h
);
1612 goto err
; /* alloc error */
1614 shdr
->stream_id
= id
;
1615 if (!ossl_assert(ossl_quic_wire_encode_frame_stream_hdr(wpkt
, shdr
))) {
1616 /* (Should not be possible.) */
1617 tx_helper_rollback(h
);
1620 goto err
; /* can't fit */
1623 if (!tx_helper_commit(h
))
1624 goto err
; /* alloc error */
1626 /* Add payload iovecs to the helper (infallible). */
1627 for (j
= 0; j
< chunks
[i
% 2].num_stream_iovec
; ++j
)
1628 tx_helper_append_iovec(h
, chunks
[i
% 2].iov
[j
].buf
,
1629 chunks
[i
% 2].iov
[j
].buf_len
);
1631 *have_ack_eliciting
= 1;
1632 tx_helper_unrestrict(h
); /* no longer need PING */
1633 if (!shdr
->has_explicit_len
)
1634 h
->done_implicit
= 1;
1636 /* Log new TXFC credit which was consumed. */
1637 if (shdr
->len
> 0 && shdr
->offset
+ shdr
->len
> fc_new_hwm
)
1638 fc_new_hwm
= shdr
->offset
+ shdr
->len
;
1640 /* Log chunk to TXPIM. */
1641 chunk
.stream_id
= shdr
->stream_id
;
1642 chunk
.start
= shdr
->offset
;
1643 chunk
.end
= shdr
->offset
+ shdr
->len
- 1;
1644 chunk
.has_fin
= shdr
->is_fin
;
1645 chunk
.has_stop_sending
= 0;
1646 chunk
.has_reset_stream
= 0;
1647 if (!ossl_quic_txpim_pkt_append_chunk(tpkt
, &chunk
))
1648 goto err
; /* alloc error */
1650 if (shdr
->len
< orig_len
) {
1652 * If we did not serialize all of this chunk we definitely do not
1653 * want to try the next chunk (and we must not mark the stream
1662 *new_credit_consumed
= fc_new_hwm
- fc_swm
;
1666 static void txp_enlink_tmp(QUIC_STREAM
**tmp_head
, QUIC_STREAM
*stream
)
1668 stream
->txp_next
= *tmp_head
;
1672 static int txp_generate_stream_related(OSSL_QUIC_TX_PACKETISER
*txp
,
1673 struct tx_helper
*h
,
1675 QUIC_TXPIM_PKT
*tpkt
,
1677 int *have_ack_eliciting
,
1678 QUIC_STREAM
**tmp_head
)
1680 QUIC_STREAM_ITER it
;
1684 QUIC_STREAM
*stream
, *snext
;
1686 for (ossl_quic_stream_iter_init(&it
, txp
->args
.qsm
, 1);
1687 it
.stream
!= NULL
;) {
1690 ossl_quic_stream_iter_next(&it
);
1693 stream
->txp_sent_fc
= 0;
1694 stream
->txp_sent_stop_sending
= 0;
1695 stream
->txp_sent_reset_stream
= 0;
1696 stream
->txp_drained
= 0;
1697 stream
->txp_blocked
= 0;
1698 stream
->txp_txfc_new_credit_consumed
= 0;
1700 rstream
= stream
->rstream
;
1702 /* Stream Abort Frames (STOP_SENDING, RESET_STREAM) */
1703 if (stream
->want_stop_sending
) {
1704 OSSL_QUIC_FRAME_STOP_SENDING f
;
1706 wpkt
= tx_helper_begin(h
);
1708 return 0; /* alloc error */
1710 f
.stream_id
= stream
->id
;
1711 f
.app_error_code
= stream
->stop_sending_aec
;
1712 if (!ossl_quic_wire_encode_frame_stop_sending(wpkt
, &f
)) {
1713 tx_helper_rollback(h
); /* can't fit */
1714 txp_enlink_tmp(tmp_head
, stream
);
1718 if (!tx_helper_commit(h
))
1719 return 0; /* alloc error */
1721 *have_ack_eliciting
= 1;
1722 tx_helper_unrestrict(h
); /* no longer need PING */
1723 stream
->txp_sent_stop_sending
= 1;
1726 if (stream
->want_reset_stream
) {
1727 OSSL_QUIC_FRAME_RESET_STREAM f
;
1729 wpkt
= tx_helper_begin(h
);
1731 return 0; /* alloc error */
1733 f
.stream_id
= stream
->id
;
1734 f
.app_error_code
= stream
->reset_stream_aec
;
1735 f
.final_size
= ossl_quic_sstream_get_cur_size(stream
->sstream
);
1736 if (!ossl_quic_wire_encode_frame_reset_stream(wpkt
, &f
)) {
1737 tx_helper_rollback(h
); /* can't fit */
1738 txp_enlink_tmp(tmp_head
, stream
);
1742 if (!tx_helper_commit(h
))
1743 return 0; /* alloc error */
1745 *have_ack_eliciting
= 1;
1746 tx_helper_unrestrict(h
); /* no longer need PING */
1747 stream
->txp_sent_reset_stream
= 1;
1750 /* Stream Flow Control Frames (MAX_STREAM_DATA) */
1752 && (stream
->want_max_stream_data
1753 || ossl_quic_rxfc_has_cwm_changed(&stream
->rxfc
, 0))) {
1755 wpkt
= tx_helper_begin(h
);
1757 return 0; /* alloc error */
1759 cwm
= ossl_quic_rxfc_get_cwm(&stream
->rxfc
);
1761 if (!ossl_quic_wire_encode_frame_max_stream_data(wpkt
, stream
->id
,
1763 tx_helper_rollback(h
); /* can't fit */
1764 txp_enlink_tmp(tmp_head
, stream
);
1768 if (!tx_helper_commit(h
))
1769 return 0; /* alloc error */
1771 *have_ack_eliciting
= 1;
1772 tx_helper_unrestrict(h
); /* no longer need PING */
1773 stream
->txp_sent_fc
= 1;
1776 /* Stream Data Frames (STREAM) */
1777 if (stream
->sstream
!= NULL
) {
1778 int packet_full
= 0, stream_drained
= 0;
1780 if (!txp_generate_stream_frames(txp
, h
, pn_space
, tpkt
,
1781 stream
->id
, stream
->sstream
,
1787 &stream
->txp_txfc_new_credit_consumed
)) {
1788 /* Fatal error (allocation, etc.) */
1789 txp_enlink_tmp(tmp_head
, stream
);
1794 stream
->txp_drained
= 1;
1797 txp_enlink_tmp(tmp_head
, stream
);
1802 txp_enlink_tmp(tmp_head
, stream
);
1809 * Generates a packet for a given EL with the given minimum and maximum
1810 * plaintext packet payload lengths. Returns TXP_ERR_* value.
1812 static int txp_generate_for_el_actual(OSSL_QUIC_TX_PACKETISER
*txp
,
1817 size_t pkt_overhead
,
1819 int chosen_for_conn_close
,
1820 int *sent_ack_eliciting
)
1822 int rc
= TXP_ERR_SUCCESS
;
1823 struct archetype_data a
;
1824 uint32_t pn_space
= ossl_quic_enc_level_to_pn_space(enc_level
);
1826 int have_helper
= 0, have_ack_eliciting
= 0, done_pre_token
= 0;
1827 int require_ack_eliciting
= 0;
1828 QUIC_CFQ_ITEM
*cfq_item
;
1829 QUIC_TXPIM_PKT
*tpkt
= NULL
;
1831 QUIC_STREAM
*tmp_head
= NULL
, *stream
;
1832 OSSL_ACKM_PROBE_INFO
*probe_info
1833 = ossl_ackm_get0_probe_request(txp
->args
.ackm
);
1835 if (!txp_get_archetype_data(enc_level
, archetype
, &a
))
1838 if (a
.allow_force_ack_eliciting
) {
1840 * Make this packet ACK-eliciting if it has been explicitly requested,
1841 * or if ACKM has requested a probe for this PN space.
1843 if ((txp
->force_ack_eliciting
& (1UL << pn_space
)) != 0
1844 || (enc_level
== QUIC_ENC_LEVEL_INITIAL
1845 && probe_info
->anti_deadlock_initial
> 0)
1846 || (enc_level
== QUIC_ENC_LEVEL_HANDSHAKE
1847 && probe_info
->anti_deadlock_handshake
> 0)
1848 || probe_info
->pto
[pn_space
] > 0)
1849 require_ack_eliciting
= 1;
1852 /* Minimum cannot be bigger than maximum. */
1853 if (min_ppl
> max_ppl
)
1856 /* Maximum PN reached? */
1857 if (txp
->next_pn
[pn_space
] >= (((QUIC_PN
)1) << 62))
1860 if ((tpkt
= ossl_quic_txpim_pkt_alloc(txp
->args
.txpim
)) == NULL
)
1864 * Initialise TX helper. If we must be ACK eliciting, reserve 1 byte for
1867 if (!tx_helper_init(&h
, txp
, max_ppl
, require_ack_eliciting
? 1 : 0))
1873 * Frame Serialization
1874 * ===================
1876 * We now serialize frames into the packet in descending order of priority.
1879 /* HANDSHAKE_DONE (Regenerate) */
1880 if (a
.allow_handshake_done
&& txp
->want_handshake_done
1881 && tx_helper_get_space_left(&h
) >= MIN_FRAME_SIZE_HANDSHAKE_DONE
) {
1882 WPACKET
*wpkt
= tx_helper_begin(&h
);
1887 if (ossl_quic_wire_encode_frame_handshake_done(wpkt
)) {
1888 tpkt
->had_handshake_done_frame
= 1;
1889 have_ack_eliciting
= 1;
1891 if (!tx_helper_commit(&h
))
1894 tx_helper_unrestrict(&h
); /* no longer need PING */
1896 tx_helper_rollback(&h
);
1900 /* MAX_DATA (Regenerate) */
1902 && (txp
->want_max_data
1903 || ossl_quic_rxfc_has_cwm_changed(txp
->args
.conn_rxfc
, 0))
1904 && tx_helper_get_space_left(&h
) >= MIN_FRAME_SIZE_MAX_DATA
) {
1905 WPACKET
*wpkt
= tx_helper_begin(&h
);
1906 uint64_t cwm
= ossl_quic_rxfc_get_cwm(txp
->args
.conn_rxfc
);
1911 if (ossl_quic_wire_encode_frame_max_data(wpkt
, cwm
)) {
1912 tpkt
->had_max_data_frame
= 1;
1913 have_ack_eliciting
= 1;
1915 if (!tx_helper_commit(&h
))
1918 tx_helper_unrestrict(&h
); /* no longer need PING */
1920 tx_helper_rollback(&h
);
1924 /* MAX_STREAMS_BIDI (Regenerate) */
1926 * TODO(STREAMS): Once we support multiple streams, add stream count FC
1930 && txp
->want_max_streams_bidi
1931 && tx_helper_get_space_left(&h
) >= MIN_FRAME_SIZE_MAX_STREAMS_BIDI
) {
1932 WPACKET
*wpkt
= tx_helper_begin(&h
);
1933 uint64_t max_streams
= 1; /* TODO */
1938 if (ossl_quic_wire_encode_frame_max_streams(wpkt
, /*is_uni=*/0,
1940 tpkt
->had_max_streams_bidi_frame
= 1;
1941 have_ack_eliciting
= 1;
1943 if (!tx_helper_commit(&h
))
1946 tx_helper_unrestrict(&h
); /* no longer need PING */
1948 tx_helper_rollback(&h
);
1952 /* MAX_STREAMS_UNI (Regenerate) */
1954 && txp
->want_max_streams_uni
1955 && tx_helper_get_space_left(&h
) >= MIN_FRAME_SIZE_MAX_STREAMS_UNI
) {
1956 WPACKET
*wpkt
= tx_helper_begin(&h
);
1957 uint64_t max_streams
= 0; /* TODO */
1962 if (ossl_quic_wire_encode_frame_max_streams(wpkt
, /*is_uni=*/1,
1964 tpkt
->had_max_streams_uni_frame
= 1;
1965 have_ack_eliciting
= 1;
1967 if (!tx_helper_commit(&h
))
1970 tx_helper_unrestrict(&h
); /* no longer need PING */
1972 tx_helper_rollback(&h
);
1977 for (cfq_item
= ossl_quic_cfq_get_priority_head(txp
->args
.cfq
, pn_space
);
1979 cfq_item
= ossl_quic_cfq_item_get_priority_next(cfq_item
, pn_space
)) {
1980 uint64_t frame_type
= ossl_quic_cfq_item_get_frame_type(cfq_item
);
1981 const unsigned char *encoded
= ossl_quic_cfq_item_get_encoded(cfq_item
);
1982 size_t encoded_len
= ossl_quic_cfq_item_get_encoded_len(cfq_item
);
1984 switch (frame_type
) {
1985 case OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID
:
1986 if (!a
.allow_new_conn_id
)
1989 case OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID
:
1990 if (!a
.allow_retire_conn_id
)
1993 case OSSL_QUIC_FRAME_TYPE_NEW_TOKEN
:
1994 if (!a
.allow_new_token
)
1998 * NEW_TOKEN frames are handled via GCR, but some
1999 * Regenerate-strategy frames should come before them (namely
2000 * ACK, CONNECTION_CLOSE, PATH_CHALLENGE and PATH_RESPONSE). If
2001 * we find a NEW_TOKEN frame, do these now. If there are no
2002 * NEW_TOKEN frames in the GCR queue we will handle these below.
2004 if (!done_pre_token
)
2005 if (txp_generate_pre_token(txp
, &h
, tpkt
, pn_space
, &a
,
2006 chosen_for_conn_close
))
2011 if (!a
.allow_cfq_other
)
2017 * If the frame is too big, don't try to schedule any more GCR frames in
2018 * this packet rather than sending subsequent ones out of order.
2020 if (encoded_len
> tx_helper_get_space_left(&h
))
2023 if (!tx_helper_append_iovec(&h
, encoded
, encoded_len
))
2026 ossl_quic_txpim_pkt_add_cfq_item(tpkt
, cfq_item
);
2028 if (ossl_quic_frame_type_is_ack_eliciting(frame_type
)) {
2029 have_ack_eliciting
= 1;
2030 tx_helper_unrestrict(&h
); /* no longer need PING */
2035 * If we didn't generate ACK, CONNECTION_CLOSE, PATH_CHALLENGE or
2036 * PATH_RESPONSE (as desired) before, do so now.
2038 if (!done_pre_token
)
2039 if (txp_generate_pre_token(txp
, &h
, tpkt
, pn_space
, &a
,
2040 chosen_for_conn_close
))
2045 if (!txp_generate_crypto_frames(txp
, &h
, pn_space
, tpkt
,
2046 &have_ack_eliciting
))
2049 /* Stream-specific frames */
2050 if (a
.allow_stream_rel
&& txp
->handshake_complete
)
2051 if (!txp_generate_stream_related(txp
, &h
, pn_space
, tpkt
, min_ppl
,
2052 &have_ack_eliciting
,
2057 tx_helper_unrestrict(&h
);
2059 if (require_ack_eliciting
&& !have_ack_eliciting
&& a
.allow_ping
) {
2062 wpkt
= tx_helper_begin(&h
);
2066 if (!ossl_quic_wire_encode_frame_ping(wpkt
)
2067 || !tx_helper_commit(&h
))
2069 * We treat a request to be ACK-eliciting as a requirement, so this
2074 have_ack_eliciting
= 1;
2078 if (h
.bytes_appended
< min_ppl
) {
2079 WPACKET
*wpkt
= tx_helper_begin(&h
);
2083 if (!ossl_quic_wire_encode_padding(wpkt
, min_ppl
- h
.bytes_appended
)
2084 || !tx_helper_commit(&h
))
2093 tpkt
->ackm_pkt
.num_bytes
= h
.bytes_appended
+ pkt_overhead
;
2094 tpkt
->ackm_pkt
.pkt_num
= txp
->next_pn
[pn_space
];
2095 /* largest_acked is set in txp_generate_pre_token */
2096 tpkt
->ackm_pkt
.pkt_space
= pn_space
;
2097 tpkt
->ackm_pkt
.is_inflight
= 1;
2098 tpkt
->ackm_pkt
.is_ack_eliciting
= have_ack_eliciting
;
2099 tpkt
->ackm_pkt
.is_pto_probe
= 0;
2100 tpkt
->ackm_pkt
.is_mtu_probe
= 0;
2101 tpkt
->ackm_pkt
.time
= ossl_time_now();
2103 /* Packet Information for QTX */
2105 pkt
.iovec
= txp
->iovec
;
2106 pkt
.num_iovec
= h
.num_iovec
;
2108 pkt
.peer
= BIO_ADDR_family(&txp
->args
.peer
) == AF_UNSPEC
2109 ? NULL
: &txp
->args
.peer
;
2110 pkt
.pn
= txp
->next_pn
[pn_space
];
2111 pkt
.flags
= OSSL_QTX_PKT_FLAG_COALESCE
; /* always try to coalesce */
2113 /* Do TX key update if needed. */
2114 if (enc_level
== QUIC_ENC_LEVEL_1RTT
) {
2115 uint64_t cur_pkt_count
, max_pkt_count
;
2117 cur_pkt_count
= ossl_qtx_get_cur_epoch_pkt_count(txp
->args
.qtx
, enc_level
);
2118 max_pkt_count
= ossl_qtx_get_max_epoch_pkt_count(txp
->args
.qtx
, enc_level
);
2120 if (cur_pkt_count
>= max_pkt_count
/ 2)
2121 if (!ossl_qtx_trigger_key_update(txp
->args
.qtx
))
2125 if (!ossl_assert(h
.bytes_appended
> 0))
2128 /* Generate TXPIM chunks representing STOP_SENDING and RESET_STREAM frames. */
2129 for (stream
= tmp_head
; stream
!= NULL
; stream
= stream
->txp_next
)
2130 if (stream
->txp_sent_stop_sending
|| stream
->txp_sent_reset_stream
) {
2131 /* Log STOP_SENDING chunk to TXPIM. */
2132 QUIC_TXPIM_CHUNK chunk
;
2134 chunk
.stream_id
= stream
->id
;
2135 chunk
.start
= UINT64_MAX
;
2138 chunk
.has_stop_sending
= stream
->txp_sent_stop_sending
;
2139 chunk
.has_reset_stream
= stream
->txp_sent_reset_stream
;
2140 if (!ossl_quic_txpim_pkt_append_chunk(tpkt
, &chunk
))
2141 return 0; /* alloc error */
2144 /* Dispatch to FIFD. */
2145 if (!ossl_quic_fifd_pkt_commit(&txp
->fifd
, tpkt
))
2148 /* Send the packet. */
2149 if (!ossl_qtx_write_pkt(txp
->args
.qtx
, &pkt
))
2152 ++txp
->next_pn
[pn_space
];
2155 * Record FC and stream abort frames as sent; deactivate streams which no
2156 * longer have anything to do.
2158 for (stream
= tmp_head
; stream
!= NULL
; stream
= stream
->txp_next
) {
2159 if (stream
->txp_sent_fc
) {
2160 stream
->want_max_stream_data
= 0;
2161 ossl_quic_rxfc_has_cwm_changed(&stream
->rxfc
, 1);
2164 if (stream
->txp_sent_stop_sending
)
2165 stream
->want_stop_sending
= 0;
2167 if (stream
->txp_sent_reset_stream
)
2168 stream
->want_reset_stream
= 0;
2170 if (stream
->txp_txfc_new_credit_consumed
> 0) {
2171 if (!ossl_assert(ossl_quic_txfc_consume_credit(&stream
->txfc
,
2172 stream
->txp_txfc_new_credit_consumed
)))
2174 * Should not be possible, but we should continue with our
2175 * bookkeeping as we have already committed the packet to the
2176 * FIFD. Just change the value we return.
2178 rc
= TXP_ERR_INTERNAL
;
2180 stream
->txp_txfc_new_credit_consumed
= 0;
2184 * If we no longer need to generate any flow control (MAX_STREAM_DATA),
2185 * STOP_SENDING or RESET_STREAM frames, nor any STREAM frames (because
2186 * the stream is drained of data or TXFC-blocked), we can mark the
2187 * stream as inactive.
2189 ossl_quic_stream_map_update_state(txp
->args
.qsm
, stream
);
2191 if (stream
->txp_drained
)
2192 assert(!ossl_quic_sstream_has_pending(stream
->sstream
));
2195 /* We have now sent the packet, so update state accordingly. */
2196 if (have_ack_eliciting
)
2197 txp
->force_ack_eliciting
&= ~(1UL << pn_space
);
2199 if (tpkt
->had_handshake_done_frame
)
2200 txp
->want_handshake_done
= 0;
2202 if (tpkt
->had_max_data_frame
) {
2203 txp
->want_max_data
= 0;
2204 ossl_quic_rxfc_has_cwm_changed(txp
->args
.conn_rxfc
, 1);
2207 if (tpkt
->had_max_streams_bidi_frame
)
2208 txp
->want_max_streams_bidi
= 0;
2210 if (tpkt
->had_max_streams_uni_frame
)
2211 txp
->want_max_streams_uni
= 0;
2213 if (tpkt
->had_ack_frame
)
2214 txp
->want_ack
&= ~(1UL << pn_space
);
2217 * Decrement probe request counts if we have sent a packet that meets
2218 * the requirement of a probe, namely being ACK-eliciting.
2220 if (have_ack_eliciting
) {
2221 if (enc_level
== QUIC_ENC_LEVEL_INITIAL
2222 && probe_info
->anti_deadlock_initial
> 0)
2223 --probe_info
->anti_deadlock_initial
;
2225 if (enc_level
== QUIC_ENC_LEVEL_HANDSHAKE
2226 && probe_info
->anti_deadlock_handshake
> 0)
2227 --probe_info
->anti_deadlock_handshake
;
2229 if (a
.allow_force_ack_eliciting
/* (i.e., not for 0-RTT) */
2230 && probe_info
->pto
[pn_space
] > 0)
2231 --probe_info
->pto
[pn_space
];
2234 if (have_ack_eliciting
)
2235 *sent_ack_eliciting
= 1;
2238 tx_helper_cleanup(&h
);
2243 * Handler for fatal errors, i.e. errors causing us to abort the entire
2244 * packet rather than just one frame. Examples of such errors include
2245 * allocation errors.
2248 tx_helper_cleanup(&h
);
2250 ossl_quic_txpim_pkt_release(txp
->args
.txpim
, tpkt
);
2251 return TXP_ERR_INTERNAL
;
2254 /* Ensure the iovec array is at least num elements long. */
2255 static int txp_ensure_iovec(OSSL_QUIC_TX_PACKETISER
*txp
, size_t num
)
2257 OSSL_QTX_IOVEC
*iovec
;
2259 if (txp
->alloc_iovec
>= num
)
2262 num
= txp
->alloc_iovec
!= 0 ? txp
->alloc_iovec
* 2 : 8;
2264 iovec
= OPENSSL_realloc(txp
->iovec
, sizeof(OSSL_QTX_IOVEC
) * num
);
2269 txp
->alloc_iovec
= num
;
2273 int ossl_quic_tx_packetiser_schedule_conn_close(OSSL_QUIC_TX_PACKETISER
*txp
,
2274 const OSSL_QUIC_FRAME_CONN_CLOSE
*f
)
2276 char *reason
= NULL
;
2277 size_t reason_len
= f
->reason_len
;
2278 size_t max_reason_len
= txp_get_mdpl(txp
) / 2;
2280 if (txp
->want_conn_close
)
2284 * Arbitrarily limit the length of the reason length string to half of the
2287 if (reason_len
> max_reason_len
)
2288 reason_len
= max_reason_len
;
2290 if (reason_len
> 0) {
2291 reason
= OPENSSL_memdup(f
->reason
, reason_len
);
2296 txp
->conn_close_frame
= *f
;
2297 txp
->conn_close_frame
.reason
= reason
;
2298 txp
->conn_close_frame
.reason_len
= reason_len
;
2299 txp
->want_conn_close
= 1;