summaryrefslogtreecommitdiff
path: root/ssl
diff options
context:
space:
mode:
authorHugo Landau <hlandau@openssl.org>2022-09-15 12:48:50 +0100
committerHugo Landau <hlandau@openssl.org>2022-11-07 18:18:05 +0000
commit0ede517cfa73fd3566d2ecd32215b4b12dd1d3b5 (patch)
tree8e1b0fba1fd7bb883826178813b65569f7667e4d /ssl
parentd77aea591650cd3bfe7c25cbb6955011bb21b416 (diff)
downloadopenssl-new-0ede517cfa73fd3566d2ecd32215b4b12dd1d3b5.tar.gz
QUIC FIFD
Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/19206)
Diffstat (limited to 'ssl')
-rw-r--r--ssl/quic/build.info2
-rw-r--r--ssl/quic/quic_cfq.c6
-rw-r--r--ssl/quic/quic_fifd.c202
-rw-r--r--ssl/quic/quic_txpim.c12
4 files changed, 220 insertions, 2 deletions
diff --git a/ssl/quic/build.info b/ssl/quic/build.info
index 1f228cb6d7..45440384e1 100644
--- a/ssl/quic/build.info
+++ b/ssl/quic/build.info
@@ -5,4 +5,4 @@ SOURCE[$LIBSSL]=cc_dummy.c quic_demux.c quic_record_rx.c
SOURCE[$LIBSSL]=quic_record_tx.c quic_record_util.c quic_record_shared.c quic_wire_pkt.c
SOURCE[$LIBSSL]=quic_record_rx_wrap.c quic_rx_depack.c
SOURCE[$LIBSSL]=quic_fc.c uint_set.c quic_stream.c
-SOURCE[$LIBSSL]=quic_cfq.c quic_txpim.c
+SOURCE[$LIBSSL]=quic_cfq.c quic_txpim.c quic_fifd.c
diff --git a/ssl/quic/quic_cfq.c b/ssl/quic/quic_cfq.c
index cdd621458c..0b0651289a 100644
--- a/ssl/quic/quic_cfq.c
+++ b/ssl/quic/quic_cfq.c
@@ -320,6 +320,9 @@ QUIC_CFQ_ITEM *ossl_quic_cfq_get_priority_head(QUIC_CFQ *cfq, uint32_t pn_space)
for (; item != NULL && item->pn_space != pn_space; item = item->next);
+ if (item == NULL)
+ return NULL; /* ubsan */
+
return &item->public;
}
@@ -335,5 +338,8 @@ QUIC_CFQ_ITEM *ossl_quic_cfq_item_get_priority_next(QUIC_CFQ_ITEM *item,
for (; ex != NULL && ex->pn_space != pn_space; ex = ex->next);
+ if (ex == NULL)
+ return NULL; /* ubsan */
+
return &ex->public;
}
diff --git a/ssl/quic/quic_fifd.c b/ssl/quic/quic_fifd.c
new file mode 100644
index 0000000000..8f548520b1
--- /dev/null
+++ b/ssl/quic/quic_fifd.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "internal/quic_fifd.h"
+#include "internal/quic_wire.h"
+
+int ossl_quic_fifd_init(QUIC_FIFD *fifd,
+ QUIC_CFQ *cfq,
+ OSSL_ACKM *ackm,
+ QUIC_TXPIM *txpim,
+ /* stream_id is UINT64_MAX for the crypto stream */
+ QUIC_SSTREAM *(*get_sstream_by_id)(uint64_t stream_id,
+ void *arg),
+ void *get_sstream_by_id_arg,
+ /* stream_id is UINT64_MAX if not applicable */
+ void (*regen_frame)(uint64_t frame_type,
+ uint64_t stream_id,
+ void *arg),
+ void *regen_frame_arg)
+{
+ if (cfq == NULL || ackm == NULL || txpim == NULL
+ || get_sstream_by_id == NULL || regen_frame == NULL)
+ return 0;
+
+ fifd->cfq = cfq;
+ fifd->ackm = ackm;
+ fifd->txpim = txpim;
+ fifd->get_sstream_by_id = get_sstream_by_id;
+ fifd->get_sstream_by_id_arg = get_sstream_by_id_arg;
+ fifd->regen_frame = regen_frame;
+ fifd->regen_frame_arg = regen_frame_arg;
+ return 1;
+}
+
+void ossl_quic_fifd_cleanup(QUIC_FIFD *fifd)
+{
+ /* No-op. */
+}
+
+static void on_acked(void *arg)
+{
+ QUIC_TXPIM_PKT *pkt = arg;
+ QUIC_FIFD *fifd = pkt->fifd;
+ const QUIC_TXPIM_CHUNK *chunks = ossl_quic_txpim_pkt_get_chunks(pkt);
+ size_t i, num_chunks = ossl_quic_txpim_pkt_get_num_chunks(pkt);
+ QUIC_SSTREAM *sstream;
+ QUIC_CFQ_ITEM *cfq_item, *cfq_item_next;
+
+ /* STREAM and CRYPTO stream chunks, FINs and stream FC frames */
+ for (i = 0; i < num_chunks; ++i) {
+ sstream = fifd->get_sstream_by_id(chunks[i].stream_id,
+ fifd->get_sstream_by_id_arg);
+ if (sstream == NULL)
+ continue;
+
+ if (chunks[i].end >= chunks[i].start)
+ ossl_quic_sstream_mark_acked(sstream,
+ chunks[i].start, chunks[i].end);
+
+ if (chunks[i].has_fin && chunks[i].stream_id != UINT64_MAX)
+ ossl_quic_sstream_mark_acked_fin(sstream);
+ }
+
+ /* GCR */
+ for (cfq_item = pkt->retx_head; cfq_item != NULL; cfq_item = cfq_item_next) {
+ cfq_item_next = cfq_item->pkt_next;
+ ossl_quic_cfq_release(fifd->cfq, cfq_item);
+ }
+
+ ossl_quic_txpim_pkt_release(fifd->txpim, pkt);
+}
+
+static void on_lost(void *arg)
+{
+ QUIC_TXPIM_PKT *pkt = arg;
+ QUIC_FIFD *fifd = pkt->fifd;
+ const QUIC_TXPIM_CHUNK *chunks = ossl_quic_txpim_pkt_get_chunks(pkt);
+ size_t i, num_chunks = ossl_quic_txpim_pkt_get_num_chunks(pkt);
+ QUIC_SSTREAM *sstream;
+ QUIC_CFQ_ITEM *cfq_item, *cfq_item_next;
+
+ /* STREAM and CRYPTO stream chunks, FIN and stream FC frames */
+ for (i = 0; i < num_chunks; ++i) {
+ sstream = fifd->get_sstream_by_id(chunks[i].stream_id,
+ fifd->get_sstream_by_id_arg);
+ if (sstream == NULL)
+ continue;
+
+ if (chunks[i].end >= chunks[i].start)
+ ossl_quic_sstream_mark_lost(sstream,
+ chunks[i].start, chunks[i].end);
+
+ if (chunks[i].has_fin && chunks[i].stream_id != UINT64_MAX)
+ ossl_quic_sstream_mark_lost_fin(sstream);
+
+ /*
+ * Inform caller that stream needs an FC frame.
+ *
+ * Note: We could track whether an FC frame was sent originally for the
+ * stream to determine if it really needs to be regenerated or not.
+ * However, if loss has occurred, it's probably better to ensure the
+ * peer has up-to-date flow control data for the stream. Given that
+ * these frames are extremely small, we may as well always send it when
+ * handling loss.
+ */
+ fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA,
+ chunks[i].stream_id,
+ fifd->regen_frame_arg);
+ }
+
+ /* GCR */
+ for (cfq_item = pkt->retx_head; cfq_item != NULL; cfq_item = cfq_item_next) {
+ cfq_item_next = cfq_item->pkt_next;
+ ossl_quic_cfq_mark_lost(fifd->cfq, cfq_item, UINT32_MAX);
+ }
+
+ /* Regenerate flag frames */
+ if (pkt->had_handshake_done_frame)
+ fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE,
+ UINT64_MAX,
+ fifd->regen_frame_arg);
+
+ if (pkt->had_max_data_frame)
+ fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_MAX_DATA,
+ UINT64_MAX,
+ fifd->regen_frame_arg);
+
+ if (pkt->had_max_streams_bidi_frame)
+ fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI,
+ UINT64_MAX,
+ fifd->regen_frame_arg);
+
+ if (pkt->had_max_streams_uni_frame)
+ fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI,
+ UINT64_MAX,
+ fifd->regen_frame_arg);
+
+ if (pkt->had_ack_frame)
+ /*
+ * We always use the ACK_WITH_ECN frame type to represent the ACK frame
+ * type in our callback; we assume it is the caller's job to decide
+ * whether it wants to send ECN data or not.
+ */
+ fifd->regen_frame(OSSL_QUIC_FRAME_TYPE_ACK_WITH_ECN,
+ UINT64_MAX,
+ fifd->regen_frame_arg);
+
+ ossl_quic_txpim_pkt_release(fifd->txpim, pkt);
+}
+
+static void on_discarded(void *arg)
+{
+ QUIC_TXPIM_PKT *pkt = arg;
+ QUIC_FIFD *fifd = pkt->fifd;
+ QUIC_CFQ_ITEM *cfq_item, *cfq_item_next;
+
+ /*
+ * Don't need to do anything to SSTREAMs for STREAM and CRYPTO streams, as
+ * we assume caller will clean them up.
+ */
+
+ /* GCR */
+ for (cfq_item = pkt->retx_head; cfq_item != NULL; cfq_item = cfq_item_next) {
+ cfq_item_next = cfq_item->pkt_next;
+ ossl_quic_cfq_release(fifd->cfq, cfq_item);
+ }
+
+ ossl_quic_txpim_pkt_release(fifd->txpim, pkt);
+}
+
+int ossl_quic_fifd_pkt_commit(QUIC_FIFD *fifd, QUIC_TXPIM_PKT *pkt)
+{
+ QUIC_CFQ_ITEM *cfq_item;
+
+ pkt->fifd = fifd;
+
+ pkt->ackm_pkt.on_lost = on_lost;
+ pkt->ackm_pkt.on_acked = on_acked;
+ pkt->ackm_pkt.on_discarded = on_discarded;
+ pkt->ackm_pkt.cb_arg = pkt;
+
+ pkt->ackm_pkt.prev = pkt->ackm_pkt.next
+ = pkt->ackm_pkt.anext = pkt->ackm_pkt.lnext = NULL;
+
+ /*
+ * Mark the CFQ items which have been added to this packet as having been
+ * transmitted.
+ */
+ for (cfq_item = pkt->retx_head;
+ cfq_item != NULL;
+ cfq_item = cfq_item->pkt_next)
+ ossl_quic_cfq_mark_tx(fifd->cfq, cfq_item);
+
+ /* Inform the ACKM. */
+ return ossl_ackm_on_tx_packet(fifd->ackm, &pkt->ackm_pkt);
+}
diff --git a/ssl/quic/quic_txpim.c b/ssl/quic/quic_txpim.c
index 38b16a4561..9693758769 100644
--- a/ssl/quic/quic_txpim.c
+++ b/ssl/quic/quic_txpim.c
@@ -111,7 +111,8 @@ static void txpim_clear(QUIC_TXPIM_PKT_EX *ex)
ex->public.fifd = NULL;
ex->public.had_handshake_done_frame = 0;
ex->public.had_max_data_frame = 0;
- ex->public.had_max_streams_frame = 0;
+ ex->public.had_max_streams_bidi_frame = 0;
+ ex->public.had_max_streams_uni_frame = 0;
ex->public.had_ack_frame = 0;
}
@@ -202,6 +203,10 @@ const QUIC_TXPIM_CHUNK *ossl_quic_txpim_pkt_get_chunks(QUIC_TXPIM_PKT *fpkt)
QUIC_TXPIM_PKT_EX *ex = (QUIC_TXPIM_PKT_EX *)fpkt;
if (ex->chunks_need_sort) {
+ /*
+ * List of chunks will generally be very small so there is no issue
+ * simply sorting here.
+ */
qsort(ex->chunks, ex->num_chunks, sizeof(QUIC_TXPIM_CHUNK), compare);
ex->chunks_need_sort = 0;
}
@@ -215,3 +220,8 @@ size_t ossl_quic_txpim_pkt_get_num_chunks(QUIC_TXPIM_PKT *fpkt)
return ex->num_chunks;
}
+
+size_t ossl_quic_txpim_get_in_use(QUIC_TXPIM *txpim)
+{
+ return txpim->in_use;
+}