From b89c81e43b88c48d7cb5ce48665bab6c36ae02ac Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Tue, 18 Apr 2023 19:30:55 +0100 Subject: QUIC QSM: Handle STOP_SENDING correctly Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/20765) --- include/internal/quic_stream_map.h | 7 +++++++ ssl/quic/quic_rx_depack.c | 9 ++++++++- ssl/quic/quic_stream_map.c | 24 ++++++++++++++++++------ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/include/internal/quic_stream_map.h b/include/internal/quic_stream_map.h index 81312e8b4a..2be73286ea 100644 --- a/include/internal/quic_stream_map.h +++ b/include/internal/quic_stream_map.h @@ -237,6 +237,13 @@ void ossl_quic_stream_map_update_state(QUIC_STREAM_MAP *qsm, QUIC_STREAM *s); */ void ossl_quic_stream_map_set_rr_stepping(QUIC_STREAM_MAP *qsm, size_t stepping); +/* + * Resets the sending part of a stream. + */ +void ossl_quic_stream_map_reset_stream_send_part(QUIC_STREAM_MAP *qsm, + QUIC_STREAM *qs, + uint64_t aec); + /* * Adds a stream to the accept queue. */ diff --git a/ssl/quic/quic_rx_depack.c b/ssl/quic/quic_rx_depack.c index a81f47d6d9..2bc4e146e8 100644 --- a/ssl/quic/quic_rx_depack.c +++ b/ssl/quic/quic_rx_depack.c @@ -172,7 +172,14 @@ static int depack_do_frame_stop_sending(PACKET *pkt, } stream->peer_stop_sending = 1; - ossl_quic_stream_map_update_state(&ch->qsm, stream); + + /* + * RFC 9000 s. 3.5: Receiving a STOP_SENDING frame means we must respond in + * turn with a RESET_STREAM frame for the same part of the stream. The other + * part is unaffected. + */ + ossl_quic_stream_map_reset_stream_send_part(&ch->qsm, stream, + frame_data.app_error_code); return 1; } diff --git a/ssl/quic/quic_stream_map.c b/ssl/quic/quic_stream_map.c index a9c616ea9f..2f58b2a51a 100644 --- a/ssl/quic/quic_stream_map.c +++ b/ssl/quic/quic_stream_map.c @@ -271,14 +271,12 @@ void ossl_quic_stream_map_update_state(QUIC_STREAM_MAP *qsm, QUIC_STREAM *s) should_be_active = allowed_by_stream_limit - && !s->peer_stop_sending - && !s->peer_reset_stream - && ((s->rstream != NULL - && (s->want_max_stream_data - || ossl_quic_rxfc_has_cwm_changed(&s->rxfc, 0))) + && ((!s->peer_reset_stream && s->rstream != NULL + && (s->want_max_stream_data + || ossl_quic_rxfc_has_cwm_changed(&s->rxfc, 0))) || s->want_stop_sending || s->want_reset_stream - || stream_has_data_to_send(s)); + || (!s->peer_stop_sending && stream_has_data_to_send(s))); if (should_be_active) stream_map_mark_active(qsm, s); @@ -286,6 +284,20 @@ void ossl_quic_stream_map_update_state(QUIC_STREAM_MAP *qsm, QUIC_STREAM *s) stream_map_mark_inactive(qsm, s); } +void ossl_quic_stream_map_reset_stream_send_part(QUIC_STREAM_MAP *qsm, + QUIC_STREAM *qs, + uint64_t aec) +{ + if (qs->reset_stream) + return; + + qs->reset_stream = 1; + qs->reset_stream_aec = aec; + qs->want_reset_stream = 1; + + ossl_quic_stream_map_update_state(qsm, qs); +} + QUIC_STREAM *ossl_quic_stream_map_peek_accept_queue(QUIC_STREAM_MAP *qsm) { return accept_head(&qsm->accept_list); -- cgit v1.2.1