#define QUIC_FL_TX_PACKET_PADDING (1UL << 1)
/* Flag a sent packet as being in flight. */
#define QUIC_FL_TX_PACKET_IN_FLIGHT (QUIC_FL_TX_PACKET_ACK_ELICITING | QUIC_FL_TX_PACKET_PADDING)
+/* Flag a sent packet as containg a CONNECTION_CLOSE frame */
+#define QUIC_FL_TX_PACKET_CC (1UL << 2)
/* Flag a sent packet as containg an ACK frame */
-#define QUIC_FL_TX_PACKET_ACK (1UL << 2)
+#define QUIC_FL_TX_PACKET_ACK (1UL << 3)
/* Structure to store enough information about TX QUIC packets. */
struct quic_tx_packet {
#define QUIC_FL_CONN_LISTENER (1U << 3)
#define QUIC_FL_CONN_ACCEPT_REGISTERED (1U << 4)
#define QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ (1U << 6)
+#define QUIC_FL_CONN_CLOSING (1U << 29)
#define QUIC_FL_CONN_DRAINING (1U << 30)
#define QUIC_FL_CONN_IMMEDIATE_CLOSE (1U << 31)
struct quic_conn {
struct task *idle_timer_task;
unsigned int flags;
+ /* When in closing state, number of packet before sending CC */
+ unsigned int nb_pkt_for_cc;
+ /* When in closing state, number of packet since receiving CC */
+ unsigned int nb_pkt_since_cc;
+
const struct qcc_app_ops *app_ops;
};
if (qc->flags & QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ)
qc_idle_timer_rearm(qc, 0);
}
+ if (!(qc->flags & QUIC_FL_CONN_CLOSING) &&
+ (pkt->flags & QUIC_FL_TX_PACKET_CC)) {
+ qc->flags |= QUIC_FL_CONN_CLOSING;
+ /* RFC 9000 10.2. Immediate Close:
+ * The closing and draining connection states exist to ensure
+ * that connections close cleanly and that delayed or reordered
+ * packets are properly discarded. These states SHOULD persist
+ * for at least three times the current PTO interval...
+ *
+ * Rearm the idle timeout only one time when entering closing
+ * state.
+ */
+ qc_idle_timer_do_rearm(qc);
+ if (qc->timer_task) {
+ task_destroy(qc->timer_task);
+ qc->timer_task = NULL;
+ }
+ }
qc->path->in_flight += pkt->in_flight_len;
pkt->pktns->tx.in_flight += pkt->in_flight_len;
if (pkt->in_flight_len)
/* RX part. */
qc->rx.bytes = 0;
qc->rx.buf = b_make(buf_area, QUIC_CONN_RX_BUFSZ, 0, 0);
+
+ qc->nb_pkt_for_cc = 1;
+ qc->nb_pkt_since_cc = 0;
+
LIST_INIT(&qc->rx.pkt_list);
if (!quic_tls_ku_init(qc)) {
TRACE_PROTO("Key update initialization failed", QUIC_EV_CONN_INIT, qc);
pkt->qc = qc;
}
+ if (qc->flags & QUIC_FL_CONN_CLOSING) {
+ if (++qc->nb_pkt_since_cc >= qc->nb_pkt_for_cc) {
+ qc->flags |= QUIC_FL_CONN_IMMEDIATE_CLOSE;
+ qc->nb_pkt_for_cc++;
+ qc->nb_pkt_since_cc = 0;
+ }
+ /* Skip the entire datagram */
+ pkt->len = end - beg;
+ TRACE_PROTO("Closing state connection", QUIC_EV_CONN_LPKT, pkt->qc);
+ goto out;
+ }
/* When multiple QUIC packets are coalesced on the same UDP datagram,
* they must have the same DCID.
}
/* Build a CONNECTION_CLOSE frame if needed. */
- if (cc && !qc_build_frm(&pos, end, &cc_frm, pkt, qc))
- goto no_room;
+ if (cc) {
+ if (!qc_build_frm(&pos, end, &cc_frm, pkt, qc))
+ goto no_room;
+
+ pkt->flags |= QUIC_FL_TX_PACKET_CC;
+ }
/* Build a PADDING frame if needed. */
if (padding_len) {