]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: quic: do not ack packet with invalid STREAM
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 29 Apr 2022 13:58:22 +0000 (15:58 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 29 Apr 2022 14:16:19 +0000 (16:16 +0200)
If the MUX cannot handle immediately nor buffer a STREAM frame, the
packet containing it must not be acknowledge. This is in conformance
with the RFC9000.

qcc_recv() return codes have been adjusted to differentiate an invalid
frame with an already fully received offset which must be acknowledged.

src/mux_quic.c
src/xprt_quic.c

index 2e5ebdc9fc1d2e0fa751ac6a73a225108307b054..db32de146338223cf57f7e09e3133396302f5c8c 100644 (file)
@@ -345,7 +345,7 @@ struct qcs *qcc_get_qcs(struct qcc *qcc, uint64_t id)
  * to process the frame content.
  *
  * Returns a code indicating how the frame was handled.
- * - 0: frame received completly and can be dropped.
+ * - 0: frame received completely and can be dropped.
  * - 1: frame not received but can be dropped.
  * - 2: frame cannot be handled, either partially or not at all. <done>
  *   indicated the number of bytes handled. The rest should be buffered.
@@ -374,7 +374,7 @@ int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset,
 
        if (offset + len <= qcs->rx.offset) {
                TRACE_DEVEL("leaving on already received offset", QMUX_EV_QCC_RECV|QMUX_EV_QCS_RECV, qcc->conn, qcs);
-               return 1;
+               return 0;
        }
 
        /* Last frame already handled for this stream. */
index 844aa13eada5358cd40d9d2718e20150ca30d02a..3a069df93a77b7935dc1e122ca4ccb6aa585e04d 100644 (file)
@@ -2255,14 +2255,16 @@ static int qc_handle_bidi_strm_frm(struct quic_rx_packet *pkt,
                       strm_frm->offset.key, strm_frm->fin,
                       (char *)strm_frm->data, &qcs, &done);
 
-       /* invalid or already received frame */
+       /* invalid frame */
        if (ret == 1)
+               return 0;
+
+       /* already fully received offset */
+       if (ret == 0 && done == 0)
                return 1;
 
+       /* frame not handled (partially or completely) must be buffered */
        if (ret == 2) {
-               /* frame cannot be parsed at the moment and should be
-                * buffered.
-                */
                frm = new_quic_rx_strm_frm(strm_frm, pkt);
                if (!frm) {
                        TRACE_PROTO("Could not alloc RX STREAM frame",
@@ -2270,6 +2272,7 @@ static int qc_handle_bidi_strm_frm(struct quic_rx_packet *pkt,
                        return 0;
                }
 
+               /* frame partially handled by the MUX */
                if (done) {
                        BUG_ON(done >= frm->len); /* must never happen */
                        frm->len -= done;
@@ -2305,6 +2308,8 @@ static int qc_handle_bidi_strm_frm(struct quic_rx_packet *pkt,
                               frm->offset_node.key, frm->fin,
                               (char *)frm->data, &qcs, &done);
 
+               BUG_ON(ret == 1); /* must never happen for buffered frames */
+
                /* interrupt the parsing if the frame cannot be handled
                 * entirely for the moment only.
                 */
@@ -2423,10 +2428,22 @@ static int qc_handle_uni_strm_frm(struct quic_rx_packet *pkt,
        return 1;
 }
 
+/* Returns 1 on success or 0 on error. On error, the packet containing the
+ * frame must not be acknowledged.
+ */
 static inline int qc_handle_strm_frm(struct quic_rx_packet *pkt,
                                      struct quic_stream *strm_frm,
                                      struct quic_conn *qc)
 {
+       /* RFC9000 13.1.  Packet Processing
+        *
+        * A packet MUST NOT be acknowledged until packet protection has been
+        * successfully removed and all frames contained in the packet have
+        * been processed. For STREAM frames, this means the data has been
+        * enqueued in preparation to be received by the application protocol,
+        * but it does not require that data be delivered and consumed.
+        */
+
        if (strm_frm->id & QCS_ID_DIR_BIT)
                return qc_handle_uni_strm_frm(pkt, strm_frm, qc);
        else