#endif
uint64_t next_cid_seq_num;
+ /* Highest CID sequence number sent to the peer. <next_cid_seq_num>
+ * counts allocated CIDs: a NEW_CONNECTION_ID frame may still be queued
+ * or in flight for a recently allocated one.
+ */
+ uint64_t max_sent_cid_seq_num;
/* Initial hash computed from first ID (derived from ODCID).
* it could be reused to derive extra CIDs from the same hash
*/
#define QUIC_FL_TX_PACKET_COALESCED (1UL << 4)
/* Flag a sent packet as being probing with old data */
#define QUIC_FL_TX_PACKET_PROBE_WITH_OLD_DATA (1UL << 5)
+/* Flag a sent packet as containing NEW_CONNECTION_ID frame(s). */
+#define QUIC_FL_TX_PACKET_NCIDS (1UL << 6)
/* Structure to store enough information about TX QUIC packets. */
struct quic_tx_packet {
}
*qc->cids = EB_ROOT;
qc->next_cid_seq_num = 0;
+ qc->max_sent_cid_seq_num = 0;
qc->scid = conn_id->cid;
/* QUIC Server (or listener). */
[QUIC_FT_STREAM_DATA_BLOCKED] = { .func = quic_build_stream_data_blocked_frame, .flags = QUIC_FL_TX_PACKET_ACK_ELICITING, .mask = QUIC_FT_PKT_TYPE___01_BITMASK, },
[QUIC_FT_STREAMS_BLOCKED_BIDI] = { .func = quic_build_streams_blocked_bidi_frame, .flags = QUIC_FL_TX_PACKET_ACK_ELICITING, .mask = QUIC_FT_PKT_TYPE___01_BITMASK, },
[QUIC_FT_STREAMS_BLOCKED_UNI] = { .func = quic_build_streams_blocked_uni_frame, .flags = QUIC_FL_TX_PACKET_ACK_ELICITING, .mask = QUIC_FT_PKT_TYPE___01_BITMASK, },
- [QUIC_FT_NEW_CONNECTION_ID] = { .func = quic_build_new_connection_id_frame, .flags = QUIC_FL_TX_PACKET_ACK_ELICITING, .mask = QUIC_FT_PKT_TYPE___01_BITMASK, },
+ [QUIC_FT_NEW_CONNECTION_ID] = { .func = quic_build_new_connection_id_frame, .flags = QUIC_FL_TX_PACKET_ACK_ELICITING | QUIC_FL_TX_PACKET_NCIDS, .mask = QUIC_FT_PKT_TYPE___01_BITMASK, },
[QUIC_FT_RETIRE_CONNECTION_ID] = { .func = quic_build_retire_connection_id_frame, .flags = QUIC_FL_TX_PACKET_ACK_ELICITING, .mask = QUIC_FT_PKT_TYPE___01_BITMASK, },
[QUIC_FT_PATH_CHALLENGE] = { .func = quic_build_path_challenge_frame, .flags = QUIC_FL_TX_PACKET_ACK_ELICITING, .mask = QUIC_FT_PKT_TYPE___01_BITMASK, },
[QUIC_FT_PATH_RESPONSE] = { .func = quic_build_path_response_frame, .flags = QUIC_FL_TX_PACKET_ACK_ELICITING, .mask = QUIC_FT_PKT_TYPE___01_BITMASK, },
goto protocol_violation;
}
+ /* RFC 9000 19.16. RETIRE_CONNECTION_ID Frames:
+ * Receipt of a RETIRE_CONNECTION_ID frame containing a sequence number
+ * greater than any previously sent to the peer MUST be treated as a
+ * connection error of type PROTOCOL_VIOLATION.
+ */
+ /* Note that <next_cid_seq_num> counts CIDs at allocation time. */
+ if (rcid_frm->seq_num > qc->max_sent_cid_seq_num) {
+ TRACE_PROTO("CID seq. number not sent to peer", QUIC_EV_CONN_PSTRM, qc, frm);
+ goto protocol_violation;
+ }
+
/* RFC 9000 19.16. RETIRE_CONNECTION_ID Frames:
* The sequence number specified in a RETIRE_CONNECTION_ID frame MUST NOT refer to
* the Destination Connection ID field of the packet in which the frame is contained.
pkt->time_sent_ns = time_sent_ns;
pkt->time_sent_ms = time_sent_ms;
+ /* Record the NEW_CONNECTION_ID sequence numbers as sent */
+ if (pkt->flags & QUIC_FL_TX_PACKET_NCIDS) {
+ struct quic_frame *f;
+
+ list_for_each_entry(f, &pkt->frms, list) {
+ if (f->type != QUIC_FT_NEW_CONNECTION_ID)
+ continue;
+
+ qc->max_sent_cid_seq_num =
+ QUIC_MAX(qc->max_sent_cid_seq_num,
+ f->new_connection_id.seq_num);
+ }
+ }
if (pkt->flags & QUIC_FL_TX_PACKET_ACK_ELICITING) {
pkt->pktns->tx.time_of_last_eliciting = time_sent_ms;
qc->path->ifae_pkts++;