/*
* Copyright 2022-2024 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 <openssl/macros.h>
#include <openssl/objects.h>
#include "internal/quic_ssl.h"
#include "internal/quic_vlint.h"
#include "internal/quic_wire.h"
#include "internal/quic_error.h"
OSSL_SAFE_MATH_UNSIGNED(uint64_t, uint64_t)
int ossl_quic_frame_ack_contains_pn(const OSSL_QUIC_FRAME_ACK *ack, QUIC_PN pn)
{
size_t i;
for (i = 0; i < ack->num_ack_ranges; ++i)
if (pn >= ack->ack_ranges[i].start
&& pn <= ack->ack_ranges[i].end)
return 1;
return 0;
}
/*
* QUIC Wire Format Encoding
* =========================
*/
int ossl_quic_wire_encode_padding(WPACKET *pkt, size_t num_bytes)
{
/*
* PADDING is frame type zero, which as a variable-length integer is
* represented as a single zero byte. As an optimisation, just use memset.
*/
return WPACKET_memset(pkt, 0, num_bytes);
}
static int encode_frame_hdr(WPACKET *pkt, uint64_t frame_type)
{
return WPACKET_quic_write_vlint(pkt, frame_type);
}
int ossl_quic_wire_encode_frame_ping(WPACKET *pkt)
{
return encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_PING);
}
int ossl_quic_wire_encode_frame_ack(WPACKET *pkt,
uint32_t ack_delay_exponent,
const OSSL_QUIC_FRAME_ACK *ack)
{
uint64_t frame_type = ack->ecn_present ? OSSL_QUIC_FRAME_TYPE_ACK_WITH_ECN
: OSSL_QUIC_FRAME_TYPE_ACK_WITHOUT_ECN;
uint64_t largest_ackd, first_ack_range, ack_delay_enc;
uint64_t i, num_ack_ranges = ack->num_ack_ranges;
OSSL_TIME delay;
if (num_ack_ranges == 0)
return 0;
delay = ossl_time_divide(ossl_time_divide(ack->delay_time, OSSL_TIME_US),
(uint64_t)1 << ack_delay_exponent);
ack_delay_enc = ossl_time2ticks(delay);
largest_ackd = ack->ack_ranges[0].end;
first_ack_range = ack->ack_ranges[0].end - ack->ack_ranges[0].start;
if (!encode_frame_hdr(pkt, frame_type)
|| !WPACKET_quic_write_vlint(pkt, largest_ackd)
|| !WPACKET_quic_write_vlint(pkt, ack_delay_enc)
|| !WPACKET_quic_write_vlint(pkt, num_ack_ranges - 1)
|| !WPACKET_quic_write_vlint(pkt, first_ack_range))
return 0;
for (i = 1; i < num_ack_ranges; ++i) {
uint64_t gap, range_len;
gap = ack->ack_ranges[i - 1].start - ack->ack_ranges[i].end - 2;
range_len = ack->ack_ranges[i].end - ack->ack_ranges[i].start;
if (!WPACKET_quic_write_vlint(pkt, gap)
|| !WPACKET_quic_write_vlint(pkt, range_len))
return 0;
}
if (ack->ecn_present)
if (!WPACKET_quic_write_vlint(pkt, ack->ect0)
|| !WPACKET_quic_write_vlint(pkt, ack->ect1)
|| !WPACKET_quic_write_vlint(pkt, ack->ecnce))
return 0;
return 1;
}
int ossl_quic_wire_encode_frame_reset_stream(WPACKET *pkt,
const OSSL_QUIC_FRAME_RESET_STREAM *f)
{
if (!encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_RESET_STREAM)