diff --git a/lib/ngtcp2_conn.c b/lib/ngtcp2_conn.c index d142856f358e2a801aba5cb3e4621cd97b786012..45f83b8d87e625a2bcd31128b870b859aae74da0 100644 --- a/lib/ngtcp2_conn.c +++ b/lib/ngtcp2_conn.c @@ -6326,6 +6326,116 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, return 0; } +/* + * conn_recv_delayed_handshake_pkt processes the received Handshake + * packet which is received after handshake completed. This function + * does the minimal job, and its purpose is send acknowledgement of + * this packet to the peer. We assume that hd->type == + * NGTCP2_PKT_HANDSHAKE. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGTCP2_ERR_FRAME_ENCODING + * Frame is badly formatted; or frame type is unknown. + * NGTCP2_ERR_NOMEM + * Out of memory + * NGTCP2_ERR_DISCARD_PKT + * Packet was discarded. + * NGTCP2_ERR_ACK_FRAME + * ACK frame is malformed. + * NGTCP2_ERR_PROTO + * Frame that is not allowed in Handshake packet is received. + */ +static int +conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, + size_t pktlen, const uint8_t *payload, + size_t payloadlen, ngtcp2_tstamp pkt_ts, + ngtcp2_tstamp ts) { + ngtcp2_ssize nread; + ngtcp2_max_frame mfr; + ngtcp2_frame *fr = &mfr.fr; + int rv; + int require_ack = 0; + ngtcp2_pktns *pktns; + + assert(hd->type == NGTCP2_PKT_HANDSHAKE); + + pktns = conn->hs_pktns; + + if (payloadlen == 0) { + /* QUIC packet must contain at least one frame */ + return NGTCP2_ERR_DISCARD_PKT; + } + + ngtcp2_qlog_pkt_received_start(&conn->qlog, hd); + + for (; payloadlen;) { + nread = ngtcp2_pkt_decode_frame(fr, payload, payloadlen); + if (nread < 0) { + return (int)nread; + } + + payload += nread; + payloadlen -= (size_t)nread; + + if (fr->type == NGTCP2_FRAME_ACK) { + fr->ack.ack_delay = 0; + fr->ack.ack_delay_unscaled = 0; + } + + ngtcp2_log_rx_fr(&conn->log, hd, fr); + + switch (fr->type) { + case NGTCP2_FRAME_ACK: + case NGTCP2_FRAME_ACK_ECN: + rv = conn_recv_ack(conn, pktns, &fr->ack, pkt_ts, ts); + if (rv != 0) { + return rv; + } + if (!conn->server) { + conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED; + } + break; + case NGTCP2_FRAME_PADDING: + break; + case NGTCP2_FRAME_CONNECTION_CLOSE: + conn_recv_connection_close(conn, &fr->connection_close); + break; + case NGTCP2_FRAME_CRYPTO: + case NGTCP2_FRAME_PING: + require_ack = 1; + break; + default: + return NGTCP2_ERR_PROTO; + } + + ngtcp2_qlog_write_frame(&conn->qlog, fr); + } + + ngtcp2_qlog_pkt_received_end(&conn->qlog, hd, pktlen); + + rv = pktns_commit_recv_pkt_num(pktns, hd->pkt_num); + if (rv != 0) { + return rv; + } + + if (require_ack && ++pktns->acktr.rx_npkt >= NGTCP2_NUM_IMMEDIATE_ACK_PKT) { + ngtcp2_acktr_immediate_ack(&pktns->acktr); + } + + rv = ngtcp2_conn_sched_ack(conn, &pktns->acktr, hd->pkt_num, require_ack, ts); + if (rv != 0) { + return rv; + } + + conn_restart_timer_on_read(conn, ts); + + ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->rcs, &conn->ccs); + + return 0; +} + /* * conn_recv_pkt processes a packet contained in the buffer pointed by * |pkt| of length |pktlen|. |pkt| may contain multiple QUIC packets. @@ -6418,9 +6528,19 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, "delayed Initial packet was discarded"); return (ngtcp2_ssize)pktlen; case NGTCP2_PKT_HANDSHAKE: - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, - "delayed Handshake packet was discarded"); - return (ngtcp2_ssize)pktlen; + if (!conn->hs_pktns) { + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, + "delayed Handshake packet was discarded"); + return (ngtcp2_ssize)pktlen; + } + + pktns = conn->hs_pktns; + ckm = pktns->crypto.rx.ckm; + hp_key = pktns->crypto.rx.hp_key; + hp_mask = conn->callbacks.hp_mask; + decrypt = conn->callbacks.decrypt; + aead_overhead = conn->crypto.aead_overhead; + break; case NGTCP2_PKT_0RTT: if (!conn->server || !conn->early.ckm) { return NGTCP2_ERR_DISCARD_PKT; @@ -6484,9 +6604,8 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_log_rx_pkt_hd(&conn->log, &hd); if (hd.flags & NGTCP2_PKT_FLAG_LONG_FORM) { - assert(hd.type == NGTCP2_PKT_0RTT); - - if (!ngtcp2_cid_eq(&conn->rcid, &hd.dcid)) { + switch (hd.type) { + case NGTCP2_PKT_HANDSHAKE: rv = conn_verify_dcid(conn, NULL, &hd); if (rv != 0) { if (ngtcp2_err_is_fatal(rv)) { @@ -6496,6 +6615,23 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, "packet was ignored because of mismatched DCID"); return NGTCP2_ERR_DISCARD_PKT; } + break; + case NGTCP2_PKT_0RTT: + if (!ngtcp2_cid_eq(&conn->rcid, &hd.dcid)) { + rv = conn_verify_dcid(conn, NULL, &hd); + if (rv != 0) { + if (ngtcp2_err_is_fatal(rv)) { + return rv; + } + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, + "packet was ignored because of mismatched DCID"); + return NGTCP2_ERR_DISCARD_PKT; + } + } + break; + default: + /* Unreachable */ + assert(0); } } else { rv = conn_verify_dcid(conn, &new_cid_used, &hd); @@ -6595,7 +6731,16 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, return NGTCP2_ERR_DISCARD_PKT; } - if (!(hd.flags & NGTCP2_PKT_FLAG_LONG_FORM)) { + if (hd.flags & NGTCP2_PKT_FLAG_LONG_FORM) { + if (hd.type == NGTCP2_PKT_HANDSHAKE) { + rv = conn_recv_delayed_handshake_pkt(conn, &hd, pktlen, payload, + payloadlen, pkt_ts, ts); + if (rv < 0) { + return (ngtcp2_ssize)rv; + } + return (ngtcp2_ssize)pktlen; + } + } else { conn->flags |= NGTCP2_CONN_FLAG_RECV_PROTECTED_PKT; } diff --git a/tests/ngtcp2_conn_test.c b/tests/ngtcp2_conn_test.c index 0fcfd15f2cbd6cecdd985c5f5ed5eaf97d6af229..f45dcb017b4b3489bdfc892131b6d9ebb851a1b2 100644 --- a/tests/ngtcp2_conn_test.c +++ b/tests/ngtcp2_conn_test.c @@ -2391,7 +2391,6 @@ void test_ngtcp2_conn_recv_delayed_handshake_pkt(void) { ngtcp2_frame fr; int rv; - /* Delayed Handshake packet is discarded */ setup_default_client(&conn); fr.type = NGTCP2_FRAME_CRYPTO; @@ -2406,7 +2405,7 @@ void test_ngtcp2_conn_recv_delayed_handshake_pkt(void) { rv = ngtcp2_conn_read_pkt(conn, &null_path, buf, pktlen, 1); CU_ASSERT(0 == rv); - CU_ASSERT(0 == ngtcp2_ksl_len(&conn->hs_pktns->acktr.ents)); + CU_ASSERT(1 == ngtcp2_ksl_len(&conn->hs_pktns->acktr.ents)); ngtcp2_conn_del(conn); } @@ -3699,10 +3698,9 @@ void test_ngtcp2_conn_recv_compound_pkt(void) { CU_ASSERT(ackent->pkt_num == pkt_num); - /* Handshake packet should be discarded */ it = ngtcp2_acktr_get(&conn->hs_pktns->acktr); - CU_ASSERT(ngtcp2_ksl_it_end(&it)); + CU_ASSERT(!ngtcp2_ksl_it_end(&it)); ngtcp2_conn_del(conn); }