diff --git a/include/internal/quic_channel.h b/include/internal/quic_channel.h index 543a5900b9..b782f0d66b 100644 --- a/include/internal/quic_channel.h +++ b/include/internal/quic_channel.h @@ -116,6 +116,7 @@ typedef struct quic_channel_args_st { QUIC_LCIDM *lcidm; /* SRTM to register SRTs with. */ QUIC_SRTM *srtm; + OSSL_QRX *qrx; int is_server; SSL *tls; @@ -123,6 +124,8 @@ typedef struct quic_channel_args_st { /* Whether to use qlog. */ int use_qlog; + int is_tserver_ch; + /* Title to use for the qlog session, or NULL. */ const char *qlog_title; } QUIC_CHANNEL_ARGS; @@ -177,6 +180,7 @@ typedef struct quic_terminate_cause_st { */ QUIC_CHANNEL *ossl_quic_channel_alloc(const QUIC_CHANNEL_ARGS *args); int ossl_quic_channel_init(QUIC_CHANNEL *ch); +void ossl_quic_channel_bind_qrx(QUIC_CHANNEL *tserver_ch, OSSL_QRX *qrx); /* No-op if ch is NULL. */ diff --git a/include/internal/quic_predef.h b/include/internal/quic_predef.h index 21cc074a74..7d9385d950 100644 --- a/include/internal/quic_predef.h +++ b/include/internal/quic_predef.h @@ -31,6 +31,7 @@ typedef struct quic_reactor_st QUIC_REACTOR; typedef struct quic_reactor_wait_ctx_st QUIC_REACTOR_WAIT_CTX; typedef struct ossl_statm_st OSSL_STATM; typedef struct quic_demux_st QUIC_DEMUX; +typedef struct ossl_qrx_st OSSL_QRX; typedef struct ossl_qrx_pkt_st OSSL_QRX_PKT; typedef struct ossl_qtx_pkt_st OSSL_QTX_PKT; typedef struct quic_tick_result_st QUIC_TICK_RESULT; diff --git a/include/internal/quic_record_rx.h b/include/internal/quic_record_rx.h index 10b2e0def4..54f3a6321b 100644 --- a/include/internal/quic_record_rx.h +++ b/include/internal/quic_record_rx.h @@ -23,7 +23,6 @@ * QUIC Record Layer - RX * ====================== */ -typedef struct ossl_qrx_st OSSL_QRX; typedef struct ossl_qrx_args_st { OSSL_LIB_CTX *libctx; @@ -321,6 +320,8 @@ int ossl_qrx_set_late_validation_cb(OSSL_QRX *qrx, * establish a new connection. */ void ossl_qrx_inject_urxe(OSSL_QRX *qrx, QUIC_URXE *e); +int ossl_qrx_validate_initial_packet(OSSL_QRX *qrx, QUIC_URXE *urxe, + const QUIC_CONN_ID *dcid); /* * Decryption of 1-RTT packets must be explicitly enabled by calling this diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 4c52fd4949..262962973f 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -295,23 +295,44 @@ static int ch_init(QUIC_CHANNEL *ch) ossl_quic_tx_packetiser_set_ack_tx_cb(ch->txp, ch_on_txp_ack_tx, ch); - qrx_args.libctx = ch->port->engine->libctx; - qrx_args.demux = ch->port->demux; - qrx_args.short_conn_id_len = rx_short_dcid_len; - qrx_args.max_deferred = 32; + /* + * qrx does not exist yet, then we must be dealing with client channel + * (QUIC connection initiator). + * If qrx exists already, then we are dealing with server channel which + * qrx gets created by port_default_packet_handler() before + * port_default_packet_handler() accepts connection and creates channel + * for it. + * The exception here is tserver which always creates channel, + * before the first packet is ever seen. + */ + if (ch->qrx == NULL && ch->is_tserver_ch == 0) { + /* we are regular client, create channel */ + qrx_args.libctx = ch->port->engine->libctx; + qrx_args.demux = ch->port->demux; + qrx_args.short_conn_id_len = rx_short_dcid_len; + qrx_args.max_deferred = 32; - if ((ch->qrx = ossl_qrx_new(&qrx_args)) == NULL) - goto err; + if ((ch->qrx = ossl_qrx_new(&qrx_args)) == NULL) + goto err; + } - if (!ossl_qrx_set_late_validation_cb(ch->qrx, - rx_late_validate, - ch)) - goto err; + if (ch->qrx != NULL) { + /* + * callbacks for channels associated with tserver's port + * are set up later when we call ossl_quic_channel_bind_qrx() + * in port_default_packet_handler() + */ + if (!ossl_qrx_set_late_validation_cb(ch->qrx, + rx_late_validate, + ch)) + goto err; + + if (!ossl_qrx_set_key_update_cb(ch->qrx, + rxku_detected, + ch)) + goto err; + } - if (!ossl_qrx_set_key_update_cb(ch->qrx, - rxku_detected, - ch)) - goto err; for (pn_space = QUIC_PN_SPACE_INITIAL; pn_space < QUIC_PN_SPACE_NUM; ++pn_space) { ch->crypto_recv[pn_space] = ossl_quic_rstream_new(NULL, NULL, 0); @@ -426,6 +447,17 @@ int ossl_quic_channel_init(QUIC_CHANNEL *ch) return ch_init(ch); } +void ossl_quic_channel_bind_qrx(QUIC_CHANNEL *tserver_ch, OSSL_QRX *qrx) +{ + if (tserver_ch->qrx == NULL && tserver_ch->is_tserver_ch == 1) { + tserver_ch->qrx = qrx; + ossl_qrx_set_late_validation_cb(tserver_ch->qrx, rx_late_validate, + tserver_ch); + ossl_qrx_set_key_update_cb(tserver_ch->qrx, rxku_detected, + tserver_ch); + } +} + QUIC_CHANNEL *ossl_quic_channel_alloc(const QUIC_CHANNEL_ARGS *args) { QUIC_CHANNEL *ch = NULL; @@ -433,11 +465,13 @@ QUIC_CHANNEL *ossl_quic_channel_alloc(const QUIC_CHANNEL_ARGS *args) if ((ch = OPENSSL_zalloc(sizeof(*ch))) == NULL) return NULL; - ch->port = args->port; - ch->is_server = args->is_server; - ch->tls = args->tls; - ch->lcidm = args->lcidm; - ch->srtm = args->srtm; + ch->port = args->port; + ch->is_server = args->is_server; + ch->tls = args->tls; + ch->lcidm = args->lcidm; + ch->srtm = args->srtm; + ch->qrx = args->qrx; + ch->is_tserver_ch = args->is_tserver_ch; #ifndef OPENSSL_NO_QLOG ch->use_qlog = args->use_qlog; @@ -570,7 +604,7 @@ err: size_t ossl_quic_channel_get_short_header_conn_id_len(QUIC_CHANNEL *ch) { - return ossl_qrx_get_short_hdr_conn_id_len(ch->qrx); + return ossl_quic_port_get_rx_short_dcid_len(ch->port); } QUIC_STREAM *ossl_quic_channel_get_stream_by_id(QUIC_CHANNEL *ch, @@ -3655,12 +3689,15 @@ static int ch_on_new_conn_common(QUIC_CHANNEL *ch, const BIO_ADDR *peer, ossl_qtx_set_qlog_cb(ch->qtx, ch_get_qlog_cb, ch); ossl_quic_tx_packetiser_set_qlog_cb(ch->txp, ch_get_qlog_cb, ch); - /* Plug in secrets for the Initial EL. */ + /* + * Plug in secrets for the Initial EL. secrets for QRX were created in + * port_default_packet_handler() already. + */ if (!ossl_quic_provide_initial_secret(ch->port->engine->libctx, ch->port->engine->propq, &ch->init_dcid, /*is_server=*/1, - ch->qrx, ch->qtx)) + NULL, ch->qtx)) return 0; /* Register the peer ODCID in the LCIDM. */ @@ -3976,7 +4013,12 @@ void ossl_quic_channel_set_msg_callback(QUIC_CHANNEL *ch, ossl_qtx_set_msg_callback(ch->qtx, msg_callback, msg_callback_ssl); ossl_quic_tx_packetiser_set_msg_callback(ch->txp, msg_callback, msg_callback_ssl); - ossl_qrx_set_msg_callback(ch->qrx, msg_callback, msg_callback_ssl); + /* + * postpone msg callback setting for tserver until port calls + * port_bind_channel(). + */ + if (ch->is_tserver_ch == 0) + ossl_qrx_set_msg_callback(ch->qrx, msg_callback, msg_callback_ssl); } void ossl_quic_channel_set_msg_callback_arg(QUIC_CHANNEL *ch, @@ -3985,7 +4027,13 @@ void ossl_quic_channel_set_msg_callback_arg(QUIC_CHANNEL *ch, ch->msg_callback_arg = msg_callback_arg; ossl_qtx_set_msg_callback_arg(ch->qtx, msg_callback_arg); ossl_quic_tx_packetiser_set_msg_callback_arg(ch->txp, msg_callback_arg); - ossl_qrx_set_msg_callback_arg(ch->qrx, msg_callback_arg); + + /* + * postpone msg callback setting for tserver until port calls + * port_bind_channel(). + */ + if (ch->is_tserver_ch == 0) + ossl_qrx_set_msg_callback_arg(ch->qrx, msg_callback_arg); } void ossl_quic_channel_set_txku_threshold_override(QUIC_CHANNEL *ch, diff --git a/ssl/quic/quic_channel_local.h b/ssl/quic/quic_channel_local.h index 6ba6366f4b..cdd0969586 100644 --- a/ssl/quic/quic_channel_local.h +++ b/ssl/quic/quic_channel_local.h @@ -452,6 +452,9 @@ struct quic_channel_st { /* Has qlog been requested? */ unsigned int use_qlog : 1; + /* Has qlog been requested? */ + unsigned int is_tserver_ch : 1; + /* Saved error stack in case permanent error was encountered */ ERR_STATE *err_state; diff --git a/ssl/quic/quic_port.c b/ssl/quic/quic_port.c index ad0c2ffef2..db1bd48822 100644 --- a/ssl/quic/quic_port.c +++ b/ssl/quic/quic_port.c @@ -498,15 +498,18 @@ static SSL *port_new_handshake_layer(QUIC_PORT *port, QUIC_CHANNEL *ch) return tls; } -static QUIC_CHANNEL *port_make_channel(QUIC_PORT *port, SSL *tls, int is_server) +static QUIC_CHANNEL *port_make_channel(QUIC_PORT *port, SSL *tls, OSSL_QRX *qrx, + int is_server, int is_tserver) { QUIC_CHANNEL_ARGS args = {0}; QUIC_CHANNEL *ch; - args.port = port; - args.is_server = is_server; - args.lcidm = port->lcidm; - args.srtm = port->srtm; + args.port = port; + args.is_server = is_server; + args.lcidm = port->lcidm; + args.srtm = port->srtm; + args.qrx = qrx; + args.is_tserver_ch = is_tserver; /* * Creating a a new channel is made a bit tricky here as there is a @@ -556,7 +559,8 @@ static QUIC_CHANNEL *port_make_channel(QUIC_PORT *port, SSL *tls, int is_server) QUIC_CHANNEL *ossl_quic_port_create_outgoing(QUIC_PORT *port, SSL *tls) { - return port_make_channel(port, tls, /*is_server=*/0); + return port_make_channel(port, tls, NULL, /* is_server= */ 0, + /* is_tserver= */ 0); } QUIC_CHANNEL *ossl_quic_port_create_incoming(QUIC_PORT *port, SSL *tls) @@ -565,7 +569,12 @@ QUIC_CHANNEL *ossl_quic_port_create_incoming(QUIC_PORT *port, SSL *tls) assert(port->tserver_ch == NULL); - ch = port_make_channel(port, tls, /*is_server=*/1); + /* + * pass -1 for qrx to indicate port will create qrx + * later in port_default_packet_handler() when calling port_bind_channel(). + */ + ch = port_make_channel(port, tls, NULL, /* is_server= */ 1, + /* is_tserver_ch */ 1); port->tserver_ch = ch; port->allow_incoming = 1; return ch; @@ -708,7 +717,8 @@ static void port_rx_pre(QUIC_PORT *port) */ static void port_bind_channel(QUIC_PORT *port, const BIO_ADDR *peer, const QUIC_CONN_ID *scid, const QUIC_CONN_ID *dcid, - const QUIC_CONN_ID *odcid, QUIC_CHANNEL **new_ch) + const QUIC_CONN_ID *odcid, OSSL_QRX *qrx, + QUIC_CHANNEL **new_ch) { QUIC_CHANNEL *ch; @@ -719,8 +729,13 @@ static void port_bind_channel(QUIC_PORT *port, const BIO_ADDR *peer, if (port->tserver_ch != NULL) { ch = port->tserver_ch; port->tserver_ch = NULL; + ossl_quic_channel_bind_qrx(ch, qrx); + ossl_qrx_set_msg_callback(ch->qrx, ch->msg_callback, + ch->msg_callback_ssl); + ossl_qrx_set_msg_callback_arg(ch->qrx, ch->msg_callback_arg); } else { - ch = port_make_channel(port, NULL, /* is_server= */1); + ch = port_make_channel(port, NULL, qrx, /* is_server= */ 1, + /* is_tserver */ 0); } if (ch == NULL) @@ -1444,6 +1459,8 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, QUIC_CHANNEL *ch = NULL, *new_ch = NULL; QUIC_CONN_ID odcid, scid; uint8_t gen_new_token = 0; + OSSL_QRX *qrx = NULL; + OSSL_QRX_ARGS qrx_args = {0}; uint64_t cause_flags = 0; /* Don't handle anything if we are no longer running. */ @@ -1528,6 +1545,31 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, odcid.id_len = 0; + /* + * Create qrx now so we can check integrity of packet + * which does not belong to any channel. + */ + qrx_args.libctx = port->engine->libctx; + qrx_args.demux = port->demux; + qrx_args.short_conn_id_len = dcid->id_len; + qrx_args.max_deferred = 32; + qrx = ossl_qrx_new(&qrx_args); + if (qrx == NULL) + goto undesirable; + + /* + * Derive secrets for qrx only. + */ + if (!ossl_quic_provide_initial_secret(port->engine->libctx, + port->engine->propq, + &hdr.dst_conn_id, + /* is_server */ 1, + qrx, NULL)) + goto undesirable; + + if (ossl_qrx_validate_initial_packet(qrx, e, (const QUIC_CONN_ID *)dcid) == 0) + goto undesirable; + /* * TODO(QUIC FUTURE): there should be some logic similar to accounting half-open * states in TCP. If we reach certain threshold, then we want to @@ -1535,6 +1577,13 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, */ if (port->validate_addr == 1 && hdr.token == NULL) { port_send_retry(port, &e->peer, &hdr); + /* + * This is a kind of bummer because we forget secrets for initial + * level encryption. The secrets costs us CPU to compute. What we can + * do here is to store them within retry token. Then we can retrieve them + * from initial packet which will carry our retry token to validate + * client's address. + */ goto undesirable; } @@ -1560,13 +1609,24 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, * the request is valid */ if (port->validate_addr == 1) { + /* + * Again: we should consider saving initial encryption level + * secrets to token here to save some CPU cycles. + */ port_send_retry(port, &e->peer, &hdr); goto undesirable; } } port_bind_channel(port, &e->peer, &scid, &hdr.dst_conn_id, - &odcid, &new_ch); + &odcid, qrx, &new_ch); + + /* + * if packet validates it gets moved to channel, we've just bound + * to port. + */ + if (new_ch == NULL) + goto undesirable; /* * Generate a token for sending in a later NEW_TOKEN frame @@ -1575,16 +1635,25 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, generate_new_token(new_ch, &e->peer); /* - * The channel will do all the LCID registration needed, but as an - * optimization inject this packet directly into the channel's QRX for - * processing without going through the DEMUX again. + * The qrx belongs to channel now, so don't free it. + */ + qrx = NULL; + + /* + * If function reaches this place, then packet got validated in + * ossl_qrx_validate_initial_packet(). Keep in mind the function + * ossl_qrx_validate_initial_packet() decrypts the packet to validate it. + * If packet validation was successful (and it was because we are here), + * then the function puts the packet to qrx->rx_pending. We must not call + * ossl_qrx_inject_urxe() here now, because we don't want to insert + * the packet to qrx->urx_pending which keeps packet waiting for decryption. + * + * We are going to call ossl_quic_demux_release_urxe() to dispose buffer + * which still holds encrypted data. */ - if (new_ch != NULL) { - ossl_qrx_inject_urxe(new_ch->qrx, e); - return; - } undesirable: + ossl_qrx_free(qrx); ossl_quic_demux_release_urxe(port->demux, e); } diff --git a/ssl/quic/quic_record_rx.c b/ssl/quic/quic_record_rx.c index 666b37f38b..63aa9aff8f 100644 --- a/ssl/quic/quic_record_rx.c +++ b/ssl/quic/quic_record_rx.c @@ -173,6 +173,24 @@ struct ossl_qrx_st { SSL *msg_callback_ssl; }; +static RXE *qrx_ensure_free_rxe(OSSL_QRX *qrx, size_t alloc_len); +static int qrx_validate_hdr_early(OSSL_QRX *qrx, RXE *rxe, + const QUIC_CONN_ID *first_dcid); +static int qrx_relocate_buffer(OSSL_QRX *qrx, RXE **prxe, size_t *pi, + const unsigned char **pptr, size_t buf_len); +static int qrx_validate_hdr(OSSL_QRX *qrx, RXE *rxe); +static RXE *qrx_reserve_rxe(RXE_LIST *rxl, RXE *rxe, size_t n); +static int qrx_decrypt_pkt_body(OSSL_QRX *qrx, unsigned char *dst, + const unsigned char *src, + size_t src_len, size_t *dec_len, + const unsigned char *aad, size_t aad_len, + QUIC_PN pn, uint32_t enc_level, + unsigned char key_phase_bit, + uint64_t *rx_key_epoch); +static int qrx_validate_hdr_late(OSSL_QRX *qrx, RXE *rxe); +static uint32_t rxe_determine_pn_space(RXE *rxe); +static void ignore_res(int x); + OSSL_QRX *ossl_qrx_new(const OSSL_QRX_ARGS *args) { OSSL_QRX *qrx; @@ -253,6 +271,192 @@ void ossl_qrx_inject_urxe(OSSL_QRX *qrx, QUIC_URXE *urxe) qrx->msg_callback_arg); } +/* + * qrx_validate_initial_pkt() is derived from qrx_process_pkt(). Unlike + * qrx_process_pkt() the qrx_validate_initial_pkt() function can process + * initial packet only. All other packets should be discarded. This allows + * port_default_packet_handler() to validate incoming packet. If packet + * is not valid, then port_default_packet_handler() must discard the + * packet instead of creating a new channel for it. + */ +static int qrx_validate_initial_pkt(OSSL_QRX *qrx, QUIC_URXE *urxe, + const QUIC_CONN_ID *first_dcid, + size_t datagram_len) +{ + PACKET pkt, orig_pkt; + RXE *rxe; + size_t i = 0, aad_len = 0, dec_len = 0; + const unsigned char *sop; + unsigned char *dst; + QUIC_PKT_HDR_PTRS ptrs; + uint32_t pn_space; + OSSL_QRL_ENC_LEVEL *el = NULL; + uint64_t rx_key_epoch = UINT64_MAX; + + if (!PACKET_buf_init(&pkt, ossl_quic_urxe_data(urxe), urxe->data_len)) + return 0; + + orig_pkt = pkt; + sop = PACKET_data(&pkt); + + /* + * Get a free RXE. If we need to allocate a new one, use the packet length + * as a good ballpark figure. + */ + rxe = qrx_ensure_free_rxe(qrx, PACKET_remaining(&pkt)); + if (rxe == NULL) + return 0; + + /* + * we expect INITIAL packet only, therefore it is OK to pass + * short_conn_id_len as 0. + */ + if (!ossl_quic_wire_decode_pkt_hdr(&pkt, + 0, /* short_conn_id_len */ + 1, /* need second decode */ + 0, /* nodata -> want to read data */ + &rxe->hdr, &ptrs, + NULL)) + goto malformed; + + if (rxe->hdr.type != QUIC_PKT_TYPE_INITIAL) + goto malformed; + + if (!qrx_validate_hdr_early(qrx, rxe, NULL)) + goto malformed; + + if (ossl_qrl_enc_level_set_have_el(&qrx->el_set, QUIC_ENC_LEVEL_INITIAL) != 1) + goto malformed; + + if (rxe->hdr.type == QUIC_PKT_TYPE_INITIAL) { + const unsigned char *token = rxe->hdr.token; + + /* + * This may change the value of rxe and change the value of the token + * pointer as well. So we must make a temporary copy of the pointer to + * the token, and then copy it back into the new location of the rxe + */ + if (!qrx_relocate_buffer(qrx, &rxe, &i, &token, rxe->hdr.token_len)) + goto malformed; + + rxe->hdr.token = token; + } + + pkt = orig_pkt; + + el = ossl_qrl_enc_level_set_get(&qrx->el_set, QUIC_ENC_LEVEL_INITIAL, 1); + assert(el != NULL); /* Already checked above */ + + if (!ossl_quic_hdr_protector_decrypt(&el->hpr, &ptrs)) + goto malformed; + + /* + * We have removed header protection, so don't attempt to do it again if + * the packet gets deferred and processed again. + */ + pkt_mark(&urxe->hpr_removed, 0); + + /* Decode the now unprotected header. */ + if (ossl_quic_wire_decode_pkt_hdr(&pkt, 0, + 0, 0, &rxe->hdr, NULL, NULL) != 1) + goto malformed; + + /* Validate header and decode PN. */ + if (!qrx_validate_hdr(qrx, rxe)) + goto malformed; + + /* + * The AAD data is the entire (unprotected) packet header including the PN. + * The packet header has been unprotected in place, so we can just reuse the + * PACKET buffer. The header ends where the payload begins. + */ + aad_len = rxe->hdr.data - sop; + + /* Ensure the RXE buffer size is adequate for our payload. */ + if ((rxe = qrx_reserve_rxe(&qrx->rx_free, rxe, rxe->hdr.len + i)) == NULL) + goto malformed; + + /* + * We decrypt the packet body to immediately after the token at the start of + * the RXE buffer (where present). + * + * Do the decryption from the PACKET (which points into URXE memory) to our + * RXE payload (single-copy decryption), then fixup the pointers in the + * header to point to our new buffer. + * + * If decryption fails this is considered a permanent error; we defer + * packets we don't yet have decryption keys for above, so if this fails, + * something has gone wrong with the handshake process or a packet has been + * corrupted. + */ + dst = (unsigned char *)rxe_data(rxe) + i; + if (!qrx_decrypt_pkt_body(qrx, dst, rxe->hdr.data, rxe->hdr.len, + &dec_len, sop, aad_len, rxe->pn, QUIC_ENC_LEVEL_INITIAL, + rxe->hdr.key_phase, &rx_key_epoch)) + goto malformed; + + /* + * ----------------------------------------------------- + * IMPORTANT: ANYTHING ABOVE THIS LINE IS UNVERIFIED + * AND MUST BE TIMING-CHANNEL SAFE. + * ----------------------------------------------------- + * + * At this point, we have successfully authenticated the AEAD tag and no + * longer need to worry about exposing the PN, PN length or Key Phase bit in + * timing channels. Invoke any configured validation callback to allow for + * rejection of duplicate PNs. + */ + if (!qrx_validate_hdr_late(qrx, rxe)) + goto malformed; + + pkt_mark(&urxe->processed, 0); + + /* + * Update header to point to the decrypted buffer, which may be shorter + * due to AEAD tags, block padding, etc. + */ + rxe->hdr.data = dst; + rxe->hdr.len = dec_len; + rxe->data_len = dec_len; + rxe->datagram_len = datagram_len; + rxe->key_epoch = rx_key_epoch; + + /* We processed the PN successfully, so update largest processed PN. */ + pn_space = rxe_determine_pn_space(rxe); + if (rxe->pn > qrx->largest_pn[pn_space]) + qrx->largest_pn[pn_space] = rxe->pn; + + /* Copy across network addresses and RX time from URXE to RXE. */ + rxe->peer = urxe->peer; + rxe->local = urxe->local; + rxe->time = urxe->time; + rxe->datagram_id = urxe->datagram_id; + + /* + * The packet is decrypted, we are going to move it from + * rx_pending queue where it waits to be further processed + * by ch_rx(). + */ + ossl_list_rxe_remove(&qrx->rx_free, rxe); + ossl_list_rxe_insert_tail(&qrx->rx_pending, rxe); + + return 1; + +malformed: + /* caller (port_default_packet_handler()) should discard urxe */ + return 0; +} + +int ossl_qrx_validate_initial_packet(OSSL_QRX *qrx, QUIC_URXE *urxe, + const QUIC_CONN_ID *dcid) +{ + urxe->processed = 0; + urxe->hpr_removed = 0; + urxe->deferred = 0; + + return qrx_validate_initial_pkt(qrx, urxe, dcid, urxe->data_len); +} + static void qrx_requeue_deferred(OSSL_QRX *qrx) { QUIC_URXE *e;