

#include <openssl/ssl.h>
#include "internal/quic_record_rx.h"
#include "quic_record_shared.h"
#include "internal/common.h"
#include "internal/list.h"
#include "../ssl_local.h"


static ossl_inline void pkt_mark(uint64_t *bitf, size_t pkt_idx)
{
    assert(pkt_idx < QUIC_MAX_PKT_PER_URXE);
    *bitf |= ((uint64_t)1) << pkt_idx;
}


static ossl_inline int pkt_is_marked(const uint64_t *bitf, size_t pkt_idx)
{
    assert(pkt_idx < QUIC_MAX_PKT_PER_URXE);
    return (*bitf & (((uint64_t)1) << pkt_idx)) != 0;
}


typedef struct rxe_st RXE;

struct rxe_st {
    OSSL_QRX_PKT        pkt;
    OSSL_LIST_MEMBER(rxe, RXE);
    size_t              data_len, alloc_len, refcount;

    
    QUIC_PKT_HDR        hdr; 

    
    QUIC_PN             pn;

    
    BIO_ADDR            peer, local;

    
    OSSL_TIME           time;

    
    size_t              datagram_len;

    
    uint64_t            key_epoch;

    
    uint64_t            datagram_id;

    
};

DEFINE_LIST_OF(rxe, RXE);
typedef OSSL_LIST(rxe) RXE_LIST;

static ossl_inline unsigned char *rxe_data(const RXE *e)
{
    return (unsigned char *)(e + 1);
}


struct ossl_qrx_st {
    OSSL_LIB_CTX               *libctx;
    const char                 *propq;

    
    QUIC_DEMUX                 *demux;

    
    size_t                      short_conn_id_len;

    
    size_t                      max_deferred;

    
    size_t                      num_deferred;

    
    QUIC_URXE_LIST              urx_pending;

    
    QUIC_URXE_LIST              urx_deferred;

    
    RXE_LIST                    rx_free;

    
    RXE_LIST                    rx_pending;

    
    QUIC_PN                     largest_pn[QUIC_PN_SPACE_NUM];

    
    OSSL_QRL_ENC_LEVEL_SET      el_set;

    
    uint64_t                    bytes_received;

    
    uint64_t                    forged_pkt_count;

    
    uint64_t                    cur_epoch_start_pn;

    
    ossl_qrx_late_validation_cb    *validation_cb;
    void                           *validation_cb_arg;

    
    ossl_qrx_key_update_cb         *key_update_cb;
    void                           *key_update_cb_arg;

    
    unsigned char                   init_key_phase_bit;

    
    unsigned char                   allow_1rtt;

    
    ossl_msg_cb msg_callback;
    void *msg_callback_arg;
    SSL *msg_callback_ssl;
};

OSSL_QRX *ossl_qrx_new(const OSSL_QRX_ARGS *args)
{
    OSSL_QRX *qrx;
    size_t i;

    if (args->demux == NULL || args->max_deferred == 0)
        return NULL;

    qrx = OPENSSL_zalloc(sizeof(OSSL_QRX));
    if (qrx == NULL)
        return NULL;

    for (i = 0; i < OSSL_NELEM(qrx->largest_pn); ++i)
        qrx->largest_pn[i] = args->init_largest_pn[i];

    qrx->libctx                 = args->libctx;
    qrx->propq                  = args->propq;
    qrx->demux                  = args->demux;
    qrx->short_conn_id_len      = args->short_conn_id_len;
    qrx->init_key_phase_bit     = args->init_key_phase_bit;
    qrx->max_deferred           = args->max_deferred;
    return qrx;
}

static void qrx_cleanup_rxl(RXE_LIST *l)
{
    RXE *e, *enext;

    for (e = ossl_list_rxe_head(l); e != NULL; e = enext) {
        enext = ossl_list_rxe_next(e);
        ossl_list_rxe_remove(l, e);
        OPENSSL_free(e);
    }
}

static void qrx_cleanup_urxl(OSSL_QRX *qrx, QUIC_URXE_LIST *l)
{
    QUIC_URXE *e, *enext;

    for (e = ossl_list_urxe_head(l); e != NULL; e = enext) {
        enext = ossl_list_urxe_next(e);
        ossl_list_urxe_remove(l, e);
        ossl_quic_demux_release_urxe(qrx->demux, e);
    }
}

void ossl_qrx_free(OSSL_QRX *qrx)
{
    uint32_t i;

    if (qrx == NULL)
        return;

    
    qrx_cleanup_rxl(&qrx->rx_free);
    qrx_cleanup_rxl(&qrx->rx_pending);
    qrx_cleanup_urxl(qrx, &qrx->urx_pending);
    qrx_cleanup_urxl(qrx, &qrx->urx_deferred);

    
    for (i = 0; i < QUIC_ENC_LEVEL_NUM; ++i)
        ossl_qrl_enc_level_set_discard(&qrx->el_set, i);

    OPENSSL_free(qrx);
}

void ossl_qrx_inject_urxe(OSSL_QRX *qrx, QUIC_URXE *urxe)
{
    
    urxe->processed     = 0;
    urxe->hpr_removed   = 0;
    urxe->deferred      = 0;
    ossl_list_urxe_insert_tail(&qrx->urx_pending, urxe);

    if (qrx->msg_callback != NULL)
        qrx->msg_callback(0, OSSL_QUIC1_VERSION, SSL3_RT_QUIC_DATAGRAM, urxe + 1,
                          urxe->data_len, qrx->msg_callback_ssl,
                          qrx->msg_callback_arg);
}

static void qrx_requeue_deferred(OSSL_QRX *qrx)
{
    QUIC_URXE *e;

    while ((e = ossl_list_urxe_head(&qrx->urx_deferred)) != NULL) {
        ossl_list_urxe_remove(&qrx->urx_deferred, e);
        ossl_list_urxe_insert_tail(&qrx->urx_pending, e);
    }
}

int ossl_qrx_provide_secret(OSSL_QRX *qrx, uint32_t enc_level,
                            uint32_t suite_id, EVP_MD *md,
                            const unsigned char *secret, size_t secret_len)
{
    if (enc_level >= QUIC_ENC_LEVEL_NUM)
        return 0;

    if (!ossl_qrl_enc_level_set_provide_secret(&qrx->el_set,
                                               qrx->libctx,
                                               qrx->propq,
                                               enc_level,
                                               suite_id,
                                               md,
                                               secret,
                                               secret_len,
                                               qrx->init_key_phase_bit,
                                               0))
        return 0;

    
    qrx_requeue_deferred(qrx);
    return 1;
}

int ossl_qrx_discard_enc_level(OSSL_QRX *qrx, uint32_t enc_level)
{
    if (enc_level >= QUIC_ENC_LEVEL_NUM)
        return 0;

    ossl_qrl_enc_level_set_discard(&qrx->el_set, enc_level);
    return 1;
}


int ossl_qrx_processed_read_pending(OSSL_QRX *qrx)
{
    return !ossl_list_rxe_is_empty(&qrx->rx_pending);
}


int ossl_qrx_unprocessed_read_pending(OSSL_QRX *qrx)
{
    return !ossl_list_urxe_is_empty(&qrx->urx_pending)
           || !ossl_list_urxe_is_empty(&qrx->urx_deferred);
}


static RXE *qrx_pop_pending_rxe(OSSL_QRX *qrx)
{
    RXE *rxe = ossl_list_rxe_head(&qrx->rx_pending);

    if (rxe == NULL)
        return NULL;

    ossl_list_rxe_remove(&qrx->rx_pending, rxe);
    return rxe;
}


static RXE *qrx_alloc_rxe(size_t alloc_len)
{
    RXE *rxe;

    if (alloc_len >= SIZE_MAX - sizeof(RXE))
        return NULL;

    rxe = OPENSSL_malloc(sizeof(RXE) + alloc_len);
    if (rxe == NULL)
        return NULL;

    ossl_list_rxe_init_elem(rxe);
    rxe->alloc_len = alloc_len;
    rxe->data_len  = 0;
    rxe->refcount  = 0;
    return rxe;
}


static RXE *qrx_ensure_free_rxe(OSSL_QRX *qrx, size_t alloc_len)
{
    RXE *rxe;

    if (ossl_list_rxe_head(&qrx->rx_free) != NULL)
        return ossl_list_rxe_head(&qrx->rx_free);

    rxe = qrx_alloc_rxe(alloc_len);
    if (rxe == NULL)
        return NULL;

    ossl_list_rxe_insert_tail(&qrx->rx_free, rxe);
    return rxe;
}


static RXE *qrx_resize_rxe(RXE_LIST *rxl, RXE *rxe, size_t n)
{
    RXE *rxe2, *p;

    
    if (rxe == NULL)
        return NULL;

    if (n >= SIZE_MAX - sizeof(RXE))
        return NULL;

    
    p = ossl_list_rxe_prev(rxe);
    ossl_list_rxe_remove(rxl, rxe);

    
    if (!ossl_assert(rxe->refcount == 0))
        return NULL;

    
    rxe2 = OPENSSL_realloc(rxe, sizeof(RXE) + n);
    if (rxe2 == NULL) {
        
        if (p == NULL)
            ossl_list_rxe_insert_head(rxl, rxe);
        else
            ossl_list_rxe_insert_after(rxl, p, rxe);
        return NULL;
    }

    if (p == NULL)
        ossl_list_rxe_insert_head(rxl, rxe2);
    else
        ossl_list_rxe_insert_after(rxl, p, rxe2);

    rxe2->alloc_len = n;
    return rxe2;
}


static RXE *qrx_reserve_rxe(RXE_LIST *rxl,
                            RXE *rxe, size_t n)
{
    if (rxe->alloc_len >= n)
        return rxe;

    return qrx_resize_rxe(rxl, rxe, n);
}


static void qrx_recycle_rxe(OSSL_QRX *qrx, RXE *rxe)
{
    
    assert(ossl_list_rxe_prev(rxe) == NULL && ossl_list_rxe_next(rxe) == NULL);
    rxe->pkt.hdr    = NULL;
    rxe->pkt.peer   = NULL;
    rxe->pkt.local  = NULL;
    ossl_list_rxe_insert_tail(&qrx->rx_free, rxe);
}


static int qrx_relocate_buffer(OSSL_QRX *qrx, RXE **prxe, size_t *pi,
                               const unsigned char **pptr, size_t buf_len)
{
    RXE *rxe;
    unsigned char *dst;

    if (!buf_len)
        return 1;

    if ((rxe = qrx_reserve_rxe(&qrx->rx_free, *prxe, *pi + buf_len)) == NULL)
        return 0;

    *prxe = rxe;
    dst = (unsigned char *)rxe_data(rxe) + *pi;

    memcpy(dst, *pptr, buf_len);
    *pi += buf_len;
    *pptr = dst;
    return 1;
}

static uint32_t qrx_determine_enc_level(const QUIC_PKT_HDR *hdr)
{
    switch (hdr->type) {
        case QUIC_PKT_TYPE_INITIAL:
            return QUIC_ENC_LEVEL_INITIAL;
        case QUIC_PKT_TYPE_HANDSHAKE:
            return QUIC_ENC_LEVEL_HANDSHAKE;
        case QUIC_PKT_TYPE_0RTT:
            return QUIC_ENC_LEVEL_0RTT;
        case QUIC_PKT_TYPE_1RTT:
            return QUIC_ENC_LEVEL_1RTT;

        default:
            assert(0);
        case QUIC_PKT_TYPE_RETRY:
        case QUIC_PKT_TYPE_VERSION_NEG:
            return QUIC_ENC_LEVEL_INITIAL; 
    }
}

static uint32_t rxe_determine_pn_space(RXE *rxe)
{
    uint32_t enc_level;

    enc_level = qrx_determine_enc_level(&rxe->hdr);
    return ossl_quic_enc_level_to_pn_space(enc_level);
}

static int qrx_validate_hdr_early(OSSL_QRX *qrx, RXE *rxe,
                                  const QUIC_CONN_ID *first_dcid)
{
    
    if (rxe->hdr.version != QUIC_VERSION_1
        && rxe->hdr.version != QUIC_VERSION_NONE)
        return 0;

    
    if (rxe->hdr.type == QUIC_PKT_TYPE_0RTT)
        return 0;

    
    if (first_dcid != NULL && !ossl_quic_pkt_type_can_share_dgram(rxe->hdr.type))
        return 0;

    
    if (first_dcid != NULL) {
        if (!ossl_assert(first_dcid->id_len < QUIC_MAX_CONN_ID_LEN)
            || !ossl_quic_conn_id_eq(first_dcid,
                                     &rxe->hdr.dst_conn_id))
        return 0;
    }

    return 1;
}


static int qrx_validate_hdr(OSSL_QRX *qrx, RXE *rxe)
{
    int pn_space = rxe_determine_pn_space(rxe);

    if (!ossl_quic_wire_decode_pkt_hdr_pn(rxe->hdr.pn, rxe->hdr.pn_len,
                                          qrx->largest_pn[pn_space],
                                          &rxe->pn))
        return 0;

    return 1;
}


static int qrx_validate_hdr_late(OSSL_QRX *qrx, RXE *rxe)
{
    int pn_space = rxe_determine_pn_space(rxe);

    
    if (qrx->validation_cb != NULL
        && !qrx->validation_cb(rxe->pn, pn_space, qrx->validation_cb_arg))
        return 0;

    return 1;
}


static size_t qrx_get_cipher_ctx_idx(OSSL_QRX *qrx, OSSL_QRL_ENC_LEVEL *el,
                                     uint32_t enc_level,
                                     unsigned char key_phase_bit,
                                     uint64_t *rx_key_epoch,
                                     int *is_old_key)
{
    size_t idx;

    *is_old_key = 0;

    if (enc_level != QUIC_ENC_LEVEL_1RTT) {
        *rx_key_epoch = 0;
        return 0;
    }

    if (!ossl_assert(key_phase_bit <= 1))
        return SIZE_MAX;

    
    idx = (el->state == QRL_EL_STATE_PROV_COOLDOWN ? el->key_epoch & 1
                                                   : key_phase_bit);

    
    switch (el->state) {
    case QRL_EL_STATE_PROV_NORMAL:
        
        *rx_key_epoch
            = el->key_epoch + ((el->key_epoch & 1) ^ (uint64_t)key_phase_bit);
        break;

    case QRL_EL_STATE_PROV_UPDATING:
        
        *is_old_key = (el->key_epoch & 1) ^ (uint64_t)key_phase_bit;
        *rx_key_epoch = el->key_epoch - (uint64_t)*is_old_key;
        break;

    case QRL_EL_STATE_PROV_COOLDOWN:
        
        *rx_key_epoch = el->key_epoch;
        break;
    }

    return idx;
}


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)
{
    int l = 0, l2 = 0, is_old_key, nonce_len;
    unsigned char nonce[EVP_MAX_IV_LENGTH];
    size_t i, cctx_idx;
    OSSL_QRL_ENC_LEVEL *el = ossl_qrl_enc_level_set_get(&qrx->el_set,
                                                        enc_level, 1);
    EVP_CIPHER_CTX *cctx;

    if (src_len > INT_MAX || aad_len > INT_MAX)
        return 0;

    
    if (!ossl_assert(el != NULL))
        return 0;

    if (el->tag_len >= src_len)
        return 0;

    
    if (qrx->forged_pkt_count >= ossl_qrl_get_suite_max_forged_pkt(el->suite_id))
        return 0;

    cctx_idx = qrx_get_cipher_ctx_idx(qrx, el, enc_level, key_phase_bit,
                                      rx_key_epoch, &is_old_key);
    if (!ossl_assert(cctx_idx < OSSL_NELEM(el->cctx)))
        return 0;

    if (is_old_key && pn >= qrx->cur_epoch_start_pn)
        
        return 0;

    cctx = el->cctx[cctx_idx];

    
    nonce_len = EVP_CIPHER_CTX_get_iv_length(cctx);
    if (!ossl_assert(nonce_len >= (int)sizeof(QUIC_PN)))
        return 0;

    memcpy(nonce, el->iv[cctx_idx], nonce_len);
    for (i = 0; i < sizeof(QUIC_PN); ++i)
        nonce[nonce_len - i - 1] ^= (unsigned char)(pn >> (i * 8));

    
    if (EVP_CipherInit_ex(cctx, NULL,
                          NULL, NULL, nonce, 0) != 1)
        return 0;

    
    if (EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_SET_TAG,
                            el->tag_len,
                            (unsigned char *)src + src_len - el->tag_len) != 1)
        return 0;

    
    if (EVP_CipherUpdate(cctx, NULL, &l, aad, aad_len) != 1)
        return 0;

    
    if (EVP_CipherUpdate(cctx, dst, &l, src, src_len - el->tag_len) != 1)
        return 0;

#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    
    memcpy(dst, src, l);

    
    if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1) {
        
    }
#else
    
    if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1) {
        
        ++qrx->forged_pkt_count;
        return 0;
    }
#endif

    *dec_len = l;
    return 1;
}

static ossl_inline void ignore_res(int x)
{
    
}

static void qrx_key_update_initiated(OSSL_QRX *qrx, QUIC_PN pn)
{
    if (!ossl_qrl_enc_level_set_key_update(&qrx->el_set, QUIC_ENC_LEVEL_1RTT))
        
        return;

    qrx->cur_epoch_start_pn = pn;

    if (qrx->key_update_cb != NULL)
        qrx->key_update_cb(pn, qrx->key_update_cb_arg);
}


static int qrx_process_pkt(OSSL_QRX *qrx, QUIC_URXE *urxe,
                           PACKET *pkt, size_t pkt_idx,
                           QUIC_CONN_ID *first_dcid,
                           size_t datagram_len)
{
    RXE *rxe;
    const unsigned char *eop = NULL;
    size_t i, aad_len = 0, dec_len = 0;
    PACKET orig_pkt = *pkt;
    const unsigned char *sop = PACKET_data(pkt);
    unsigned char *dst;
    char need_second_decode = 0, already_processed = 0;
    QUIC_PKT_HDR_PTRS ptrs;
    uint32_t pn_space, enc_level;
    OSSL_QRL_ENC_LEVEL *el = NULL;
    uint64_t rx_key_epoch = UINT64_MAX;

    
    rxe = qrx_ensure_free_rxe(qrx, PACKET_remaining(pkt));
    if (rxe == NULL)
        return 0;

    
    if (pkt_is_marked(&urxe->processed, pkt_idx))
        already_processed = 1;

    
    need_second_decode = !pkt_is_marked(&urxe->hpr_removed, pkt_idx);
    if (!ossl_quic_wire_decode_pkt_hdr(pkt,
                                       qrx->short_conn_id_len,
                                       need_second_decode, 0, &rxe->hdr, &ptrs))
        goto malformed;

    
    eop = PACKET_data(pkt);

    
    if (pkt_idx == 0)
        *first_dcid = rxe->hdr.dst_conn_id;

    
    if (already_processed
        || !qrx_validate_hdr_early(qrx, rxe, pkt_idx == 0 ? NULL : first_dcid))
        
        goto malformed;

    if (!ossl_quic_pkt_type_is_encrypted(rxe->hdr.type)) {
        

        
        if ((rxe = qrx_reserve_rxe(&qrx->rx_free, rxe, rxe->hdr.len)) == NULL)
            
            goto malformed;

        
        memcpy(rxe_data(rxe), rxe->hdr.data, rxe->hdr.len);
        pkt_mark(&urxe->processed, pkt_idx);

        rxe->hdr.data   = rxe_data(rxe);
        rxe->pn         = QUIC_PN_INVALID;

        rxe->data_len       = rxe->hdr.len;
        rxe->datagram_len   = datagram_len;
        rxe->key_epoch      = 0;
        rxe->peer           = urxe->peer;
        rxe->local          = urxe->local;
        rxe->time           = urxe->time;
        rxe->datagram_id    = urxe->datagram_id;

        
        ossl_list_rxe_remove(&qrx->rx_free, rxe);
        ossl_list_rxe_insert_tail(&qrx->rx_pending, rxe);
        return 0; 
    }

    
    enc_level = qrx_determine_enc_level(&rxe->hdr);

    
    switch (ossl_qrl_enc_level_set_have_el(&qrx->el_set, enc_level)) {
        case 1:
            
            if (enc_level == QUIC_ENC_LEVEL_1RTT && !qrx->allow_1rtt)
                
                goto cannot_decrypt;

            break;
        case 0:
            
            goto cannot_decrypt;
        default:
            
            goto malformed;
    }

    
    i = 0;

    
    if (rxe->hdr.type == QUIC_PKT_TYPE_INITIAL) {
        const unsigned char *token = rxe->hdr.token;

        
        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, enc_level, 1);
    assert(el != NULL); 

    if (need_second_decode) {
        if (!ossl_quic_hdr_protector_decrypt(&el->hpr, &ptrs))
            goto malformed;

        
        pkt_mark(&urxe->hpr_removed, pkt_idx);

        
        if (ossl_quic_wire_decode_pkt_hdr(pkt, qrx->short_conn_id_len,
                                          0, 0, &rxe->hdr, NULL) != 1)
            goto malformed;
    }

    
    if (!qrx_validate_hdr(qrx, rxe))
        goto malformed;

    if (qrx->msg_callback != NULL)
        qrx->msg_callback(0, OSSL_QUIC1_VERSION, SSL3_RT_QUIC_PACKET, sop,
                          eop - sop - rxe->hdr.len, qrx->msg_callback_ssl,
                          qrx->msg_callback_arg);

    
    aad_len = rxe->hdr.data - sop;

    
    if ((rxe = qrx_reserve_rxe(&qrx->rx_free, rxe, rxe->hdr.len + i)) == NULL) {
        
        eop = NULL;
        goto malformed;
    }

    
    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, enc_level,
                              rxe->hdr.key_phase, &rx_key_epoch))
        goto malformed;

    
    if (!qrx_validate_hdr_late(qrx, rxe))
        goto malformed;

    
    if (rxe->hdr.type == QUIC_PKT_TYPE_1RTT
        && rxe->hdr.key_phase != (el->key_epoch & 1))
        qrx_key_update_initiated(qrx, rxe->pn);

    
    pkt_mark(&urxe->processed, pkt_idx);

    
    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;

    
    pn_space = rxe_determine_pn_space(rxe);
    if (rxe->pn > qrx->largest_pn[pn_space])
        qrx->largest_pn[pn_space] = rxe->pn;

    
    rxe->peer           = urxe->peer;
    rxe->local          = urxe->local;
    rxe->time           = urxe->time;
    rxe->datagram_id    = urxe->datagram_id;

    
    ossl_list_rxe_remove(&qrx->rx_free, rxe);
    ossl_list_rxe_insert_tail(&qrx->rx_pending, rxe);
    return 0; 

cannot_decrypt:
    
    assert(eop != NULL && eop >= PACKET_data(pkt));
    
    ignore_res(PACKET_forward(pkt, eop - PACKET_data(pkt)));
    return 1; 

malformed:
    if (eop != NULL) {
        
        assert(eop >= PACKET_data(pkt));
        pkt_mark(&urxe->processed, pkt_idx);
        
        ignore_res(PACKET_forward(pkt, eop - PACKET_data(pkt)));
    } else {
        
        pkt_mark(&urxe->processed, pkt_idx);
        
        ignore_res(PACKET_forward(pkt, PACKET_remaining(pkt)));
    }
    return 0; 
}


static int qrx_process_datagram(OSSL_QRX *qrx, QUIC_URXE *e,
                                const unsigned char *data,
                                size_t data_len)
{
    int have_deferred = 0;
    PACKET pkt;
    size_t pkt_idx = 0;
    QUIC_CONN_ID first_dcid = { 255 };

    qrx->bytes_received += data_len;

    if (!PACKET_buf_init(&pkt, data, data_len))
        return 0;

    for (; PACKET_remaining(&pkt) > 0; ++pkt_idx) {
        
        if (PACKET_remaining(&pkt) < QUIC_MIN_VALID_PKT_LEN
            || pkt_idx >= QUIC_MAX_PKT_PER_URXE)
            break;

        
        if (qrx_process_pkt(qrx, e, &pkt, pkt_idx, &first_dcid, data_len))
            have_deferred = 1;
    }

    
    return have_deferred;
}


static int qrx_process_one_urxe(OSSL_QRX *qrx, QUIC_URXE *e)
{
    int was_deferred;

    
    if (!ossl_assert(e == ossl_list_urxe_head(&qrx->urx_pending)))
        return 0;

    
    was_deferred = qrx_process_datagram(qrx, e, ossl_quic_urxe_data(e),
                                        e->data_len);

    
    ossl_list_urxe_remove(&qrx->urx_pending, e);
    if (was_deferred > 0 &&
            (e->deferred || qrx->num_deferred < qrx->max_deferred)) {
        ossl_list_urxe_insert_tail(&qrx->urx_deferred, e);
        if (!e->deferred) {
            e->deferred = 1;
            ++qrx->num_deferred;
        }
    } else {
        if (e->deferred) {
            e->deferred = 0;
            --qrx->num_deferred;
        }
        ossl_quic_demux_release_urxe(qrx->demux, e);
    }

    return 1;
}


static int qrx_process_pending_urxl(OSSL_QRX *qrx)
{
    QUIC_URXE *e;

    while ((e = ossl_list_urxe_head(&qrx->urx_pending)) != NULL)
        if (!qrx_process_one_urxe(qrx, e))
            return 0;

    return 1;
}

int ossl_qrx_read_pkt(OSSL_QRX *qrx, OSSL_QRX_PKT **ppkt)
{
    RXE *rxe;

    if (!ossl_qrx_processed_read_pending(qrx)) {
        if (!qrx_process_pending_urxl(qrx))
            return 0;

        if (!ossl_qrx_processed_read_pending(qrx))
            return 0;
    }

    rxe = qrx_pop_pending_rxe(qrx);
    if (!ossl_assert(rxe != NULL))
        return 0;

    assert(rxe->refcount == 0);
    rxe->refcount = 1;

    rxe->pkt.hdr            = &rxe->hdr;
    rxe->pkt.pn             = rxe->pn;
    rxe->pkt.time           = rxe->time;
    rxe->pkt.datagram_len   = rxe->datagram_len;
    rxe->pkt.peer
        = BIO_ADDR_family(&rxe->peer) != AF_UNSPEC ? &rxe->peer : NULL;
    rxe->pkt.local
        = BIO_ADDR_family(&rxe->local) != AF_UNSPEC ? &rxe->local : NULL;
    rxe->pkt.key_epoch      = rxe->key_epoch;
    rxe->pkt.datagram_id    = rxe->datagram_id;
    rxe->pkt.qrx            = qrx;
    *ppkt = &rxe->pkt;

    return 1;
}

void ossl_qrx_pkt_release(OSSL_QRX_PKT *pkt)
{
    RXE *rxe;

    if (pkt == NULL)
        return;

    rxe = (RXE *)pkt;
    assert(rxe->refcount > 0);
    if (--rxe->refcount == 0)
        qrx_recycle_rxe(pkt->qrx, rxe);
}

void ossl_qrx_pkt_up_ref(OSSL_QRX_PKT *pkt)
{
    RXE *rxe = (RXE *)pkt;

    assert(rxe->refcount > 0);
    ++rxe->refcount;
}

uint64_t ossl_qrx_get_bytes_received(OSSL_QRX *qrx, int clear)
{
    uint64_t v = qrx->bytes_received;

    if (clear)
        qrx->bytes_received = 0;

    return v;
}

int ossl_qrx_set_late_validation_cb(OSSL_QRX *qrx,
                                    ossl_qrx_late_validation_cb *cb,
                                    void *cb_arg)
{
    qrx->validation_cb       = cb;
    qrx->validation_cb_arg   = cb_arg;
    return 1;
}

int ossl_qrx_set_key_update_cb(OSSL_QRX *qrx,
                               ossl_qrx_key_update_cb *cb,
                               void *cb_arg)
{
    qrx->key_update_cb      = cb;
    qrx->key_update_cb_arg  = cb_arg;
    return 1;
}

uint64_t ossl_qrx_get_key_epoch(OSSL_QRX *qrx)
{
    OSSL_QRL_ENC_LEVEL *el = ossl_qrl_enc_level_set_get(&qrx->el_set,
                                                        QUIC_ENC_LEVEL_1RTT, 1);

    return el == NULL ? UINT64_MAX : el->key_epoch;
}

int ossl_qrx_key_update_timeout(OSSL_QRX *qrx, int normal)
{
    OSSL_QRL_ENC_LEVEL *el = ossl_qrl_enc_level_set_get(&qrx->el_set,
                                                        QUIC_ENC_LEVEL_1RTT, 1);

    if (el == NULL)
        return 0;

    if (el->state == QRL_EL_STATE_PROV_UPDATING
        && !ossl_qrl_enc_level_set_key_update_done(&qrx->el_set,
                                                   QUIC_ENC_LEVEL_1RTT))
        return 0;

    if (normal && el->state == QRL_EL_STATE_PROV_COOLDOWN
        && !ossl_qrl_enc_level_set_key_cooldown_done(&qrx->el_set,
                                                     QUIC_ENC_LEVEL_1RTT))
        return 0;

    return 1;
}

uint64_t ossl_qrx_get_cur_forged_pkt_count(OSSL_QRX *qrx)
{
    return qrx->forged_pkt_count;
}

uint64_t ossl_qrx_get_max_forged_pkt_count(OSSL_QRX *qrx,
                                           uint32_t enc_level)
{
    OSSL_QRL_ENC_LEVEL *el = ossl_qrl_enc_level_set_get(&qrx->el_set,
                                                        enc_level, 1);

    return el == NULL ? UINT64_MAX
        : ossl_qrl_get_suite_max_forged_pkt(el->suite_id);
}

void ossl_qrx_allow_1rtt_processing(OSSL_QRX *qrx)
{
    if (qrx->allow_1rtt)
        return;

    qrx->allow_1rtt = 1;
    qrx_requeue_deferred(qrx);
}

void ossl_qrx_set_msg_callback(OSSL_QRX *qrx, ossl_msg_cb msg_callback,
                               SSL *msg_callback_ssl)
{
    qrx->msg_callback = msg_callback;
    qrx->msg_callback_ssl = msg_callback_ssl;
}

void ossl_qrx_set_msg_callback_arg(OSSL_QRX *qrx, void *msg_callback_arg)
{
    qrx->msg_callback_arg = msg_callback_arg;
}
