MINOR: xprt_qstrm: implement reception of transport parameters

Extend xprt_qstrm to implement the reception of QMux transport
parameters. This is performed via conn_recv_qstrm() which relies on the
lower xprt rcv_buf operation. Once received, parameters are kept in
xprt_qstrm context, so that the MUX can retrieve them on init.

For the reception of parameters to be active, the connection must first
be flagged with CO_FL_QSTRM_RECV.
This commit is contained in:
Amaury Denoyelle 2026-03-25 09:05:21 +01:00
parent 91ea5809e9
commit 531a2b9f1a
2 changed files with 60 additions and 2 deletions

View File

@ -130,7 +130,8 @@ enum {
CO_FL_OPT_TOS = 0x00000020, /* connection has a special sockopt tos */
/* unused : 0x00000040, 0x00000080 */
/* unused : 0x00000040 */
CO_FL_QSTRM_RECV = 0x00000080, /* connection uses QMux protocol, needs to exchange transport parameters before starting mux layer */
/* These flags indicate whether the Control and Transport layers are initialized */
CO_FL_CTRL_READY = 0x00000100, /* FD was registered, fd_delete() needed */

View File

@ -21,14 +21,71 @@ struct xprt_qstrm_ctx {
DECLARE_STATIC_TYPED_POOL(xprt_qstrm_ctx_pool, "xprt_qstrm_ctx", struct xprt_qstrm_ctx);
int conn_recv_qstrm(struct connection *conn, struct xprt_qstrm_ctx *ctx, int flag)
{
struct quic_frame frm;
const unsigned char *pos, *end;
int ret;
if (!conn_ctrl_ready(conn))
goto fail;
BUG_ON(conn->flags & CO_FL_FDLESS);
if (!fd_recv_ready(conn->handle.fd))
goto not_ready;
while (1) {
ret = ctx->ops_lower->rcv_buf(conn, ctx->ctx_lower, &trash, trash.size, NULL, 0, MSG_PEEK);
BUG_ON(conn->flags & CO_FL_ERROR); /* TODO handle fatal errors */
trash.data = ret;
break;
}
if (!trash.data)
goto not_ready;
pos = (unsigned char *)b_orig(&trash);
end = (unsigned char *)(b_orig(&trash) + b_data(&trash));
ret = qc_parse_frm_type(&frm, &pos, end, NULL);
BUG_ON(!ret); /* TODO handle a truncated frame, recv must be performed again. */
/* TODO close connection with TRANSPORT_PARAMETER_ERROR if frame not present. */
BUG_ON(frm.type != QUIC_FT_QX_TRANSPORT_PARAMETERS);
ret = qc_parse_frm_payload(&frm, &pos, end, NULL);
BUG_ON(!ret); /* TODO handle a truncated frame, recv must be performed again. */
ctx->rparams = frm.qmux_transport_params.params;
conn->flags &= ~flag;
return 1;
not_ready:
return 0;
fail:
conn->flags |= CO_FL_ERROR;
return 0;
}
struct task *xprt_qstrm_io_cb(struct task *t, void *context, unsigned int state)
{
struct xprt_qstrm_ctx *ctx = context;
struct connection *conn = ctx->conn;
int ret;
if (conn->flags & CO_FL_QSTRM_RECV) {
if (!conn_recv_qstrm(conn, ctx, CO_FL_QSTRM_RECV)) {
ctx->ops_lower->subscribe(conn, ctx->ctx_lower,
SUB_RETRY_RECV, &ctx->wait_event);
goto out;
}
}
out:
if (conn->flags & CO_FL_ERROR) {
if ((conn->flags & CO_FL_ERROR) ||
!(conn->flags & CO_FL_QSTRM_RECV)) {
/* MUX will access members from xprt_ctx on init, so create
* operation should be called before any members are resetted.
*/