MINOR: quic: refactor frame parsing

This patch refactors parsing in QUIC frame module. Function
qc_parse_frm() has been splitted in three :
* qc_parse_frm_type()
* qc_parse_frm_pkt()
* qc_parse_frm_payload()

No functional change. The main objective of this patch is to facilitate
a QMux implementation. One of the gain is the ability to manipulate QUIC
frames without any reference to a QUIC packet as it is irrelevant for
QMux. Also, quic_set_connection_close() calls are extracted as this
relies on qc type. The caller is now responsible to set the required
error code.
This commit is contained in:
Amaury Denoyelle 2025-02-19 14:53:14 +01:00
parent 1e08247961
commit 48e41e4ce0
3 changed files with 81 additions and 33 deletions

View File

@ -38,9 +38,16 @@ int qc_build_frm(unsigned char **pos, const unsigned char *end,
struct quic_frame *frm, struct quic_tx_packet *pkt,
struct quic_conn *conn);
int qc_parse_frm(struct quic_frame *frm, struct quic_rx_packet *pkt,
const unsigned char **pos, const unsigned char *end,
struct quic_conn *conn);
int qc_parse_frm_type(struct quic_frame *frm,
const unsigned char **pos, const unsigned char *end,
struct quic_conn *conn);
int qc_parse_frm_pkt(const struct quic_frame *frm,
const struct quic_rx_packet *pkt, int *flags);
int qc_parse_frm_payload(struct quic_frame *frm,
const unsigned char **pos, const unsigned char *end,
struct quic_conn *qc);
void qc_release_frm(struct quic_conn *qc, struct quic_frame *frm);

View File

@ -1150,17 +1150,19 @@ const struct quic_frame_builder *qf_builder(uint64_t type)
return NULL;
}
/* Decode a QUIC frame at <pos> buffer position into <frm> frame.
* Returns 1 if succeeded (enough data at <pos> buffer position to parse the frame), 0 if not.
/* Parse frame type in buffer starting at <pos> and ending at <end> and store
* it in <frm> object.
*
* Returns 1 on success else 0.
*/
int qc_parse_frm(struct quic_frame *frm, struct quic_rx_packet *pkt,
const unsigned char **pos, const unsigned char *end,
struct quic_conn *qc)
int qc_parse_frm_type(struct quic_frame *frm,
const unsigned char **pos, const unsigned char *end,
struct quic_conn *qc)
{
int ret = 0;
const struct quic_frame_parser *parser;
TRACE_ENTER(QUIC_EV_CONN_PRSFRM, qc);
if (end <= *pos) {
TRACE_DEVEL("wrong frame", QUIC_EV_CONN_PRSFRM, qc);
goto leave;
@ -1168,34 +1170,50 @@ int qc_parse_frm(struct quic_frame *frm, struct quic_rx_packet *pkt,
if (!quic_dec_int(&frm->type, pos, end)) {
TRACE_ERROR("malformed frame type", QUIC_EV_CONN_PRSFRM, qc);
quic_set_connection_close(qc, quic_err_transport(QC_ERR_FRAME_ENCODING_ERROR));
goto leave;
}
if (!quic_frame_type_is_known(frm->type)) {
/* RFC 9000 12.4. Frames and Frame Types
*
* An endpoint MUST treat the receipt of a frame of unknown type as a
* connection error of type FRAME_ENCODING_ERROR.
*/
TRACE_DEVEL("wrong frame type", QUIC_EV_CONN_PRSFRM, qc, frm);
quic_set_connection_close(qc, quic_err_transport(QC_ERR_FRAME_ENCODING_ERROR));
goto leave;
}
ret = 1;
leave:
TRACE_LEAVE(QUIC_EV_CONN_PRSFRM, qc);
return ret;
}
/* Checks that <frm> frame is authorized in <pkt> packet. Output parameter <flags>
* may be updated if the frame characteristics impacts the containing packet.
*
* Returns true for a valid frame else false.
*/
int qc_parse_frm_pkt(const struct quic_frame *frm,
const struct quic_rx_packet *pkt, int *flags)
{
const struct quic_frame_parser *parser = qf_parser(frm->type);
if (!(parser->mask & (1U << pkt->type)))
return 0;
*flags = parser->flags;
return 1;
}
/* Parse frame content in buffer starting at <pos> and ending at <end>.
*
* Returns 1 on success else 0.
*/
int qc_parse_frm_payload(struct quic_frame *frm,
const unsigned char **pos, const unsigned char *end,
struct quic_conn *qc)
{
int ret = 0;
const struct quic_frame_parser *parser;
TRACE_ENTER(QUIC_EV_CONN_PRSFRM, qc);
parser = qf_parser(frm->type);
if (!(parser->mask & (1U << pkt->type))) {
/* RFC 9000 12.4. Frames and Frame Types
*
* An endpoint MUST treat
* receipt of a frame in a packet type that is not permitted as a
* connection error of type PROTOCOL_VIOLATION.
*/
TRACE_DEVEL("unauthorized frame", QUIC_EV_CONN_PRSFRM, qc, frm);
quic_set_connection_close(qc, quic_err_transport(QC_ERR_PROTOCOL_VIOLATION));
goto leave;
}
if (!parser->func(frm, qc, pos, end)) {
TRACE_DEVEL("parsing error", QUIC_EV_CONN_PRSFRM, qc, frm);
goto leave;
@ -1203,8 +1221,6 @@ int qc_parse_frm(struct quic_frame *frm, struct quic_rx_packet *pkt,
TRACE_PROTO("RX frm", QUIC_EV_CONN_PSTRM, qc, frm);
pkt->flags |= parser->flags;
ret = 1;
leave:
TRACE_LEAVE(QUIC_EV_CONN_PRSFRM, qc);

View File

@ -840,7 +840,7 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
{
struct quic_frame *frm = NULL;
const unsigned char *pos, *end;
int fast_retrans = 0, ret;
int fast_retrans = 0, pkt_flags = 0, ret;
TRACE_ENTER(QUIC_EV_CONN_PRSHPKT, qc);
/* Skip the AAD */
@ -867,7 +867,32 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
goto err;
}
if (!qc_parse_frm(frm, pkt, &pos, end, qc)) {
if (!qc_parse_frm_type(frm, &pos, end, qc)) {
/* RFC 9000 12.4. Frames and Frame Types
*
* An endpoint MUST treat the receipt of a frame of unknown type as a
* connection error of type FRAME_ENCODING_ERROR.
*/
quic_set_connection_close(qc, quic_err_transport(QC_ERR_FRAME_ENCODING_ERROR));
/* trace already emitted by above function */
goto err;
}
/* RFC 9000 12.4. Frames and Frame Types
*
* An endpoint MUST treat
* receipt of a frame in a packet type that is not permitted as a
* connection error of type PROTOCOL_VIOLATION.
*/
if (!qc_parse_frm_pkt(frm, pkt, &pkt_flags)) {
TRACE_ERROR("unauthorized frame", QUIC_EV_CONN_PRSFRM, qc, frm);
quic_set_connection_close(qc, quic_err_transport(QC_ERR_PROTOCOL_VIOLATION));
goto err;
}
pkt->flags |= pkt_flags;
if (!qc_parse_frm_payload(frm, &pos, end, qc)) {
// trace already emitted by function above
goto err;
}
@ -1147,7 +1172,7 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
qc->state = QUIC_HS_ST_CONFIRMED;
break;
default:
/* Unknown frame type must be rejected by qc_parse_frm(). */
/* Unknown frame type must be rejected by qc_parse_frm_type(). */
ABORT_NOW();
}
}