Move connectivity probing related code from QuicFramer to QuicPacketCreator.

QuicPacketCreator has access to debug_delegate_, which helps log on path challenge frames.

gfe-relnote: protected by disabled v99 flag.
PiperOrigin-RevId: 273405309
Change-Id: I5f7805e0254fcaa417cababc0af0681bf8901e26
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index f792273..17898a4 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -1188,93 +1188,6 @@
   return writer->length();
 }
 
-size_t QuicFramer::BuildConnectivityProbingPacket(
-    const QuicPacketHeader& header,
-    char* buffer,
-    size_t packet_length,
-    EncryptionLevel level) {
-  QuicFrames frames;
-
-  // Write a PING frame, which has no data payload.
-  QuicPingFrame ping_frame;
-  frames.push_back(QuicFrame(ping_frame));
-
-  // Add padding to the rest of the packet.
-  QuicPaddingFrame padding_frame;
-  frames.push_back(QuicFrame(padding_frame));
-
-  return BuildDataPacket(header, frames, buffer, packet_length, level);
-}
-
-size_t QuicFramer::BuildPaddedPathChallengePacket(
-    const QuicPacketHeader& header,
-    char* buffer,
-    size_t packet_length,
-    QuicPathFrameBuffer* payload,
-    QuicRandom* randomizer,
-    EncryptionLevel level) {
-  if (!VersionHasIetfQuicFrames(version_.transport_version)) {
-    QUIC_BUG << "Attempt to build a PATH_CHALLENGE Connectivity Probing "
-                "packet and not doing IETF QUIC";
-    return 0;
-  }
-  QuicFrames frames;
-
-  // Write a PATH_CHALLENGE frame, which has a random 8-byte payload
-  randomizer->RandBytes(payload->data(), payload->size());
-
-  QuicPathChallengeFrame path_challenge_frame(0, *payload);
-  frames.push_back(QuicFrame(&path_challenge_frame));
-
-  // Add padding to the rest of the packet in order to assess Path MTU
-  // characteristics.
-  QuicPaddingFrame padding_frame;
-  frames.push_back(QuicFrame(padding_frame));
-
-  return BuildDataPacket(header, frames, buffer, packet_length, level);
-}
-
-size_t QuicFramer::BuildPathResponsePacket(
-    const QuicPacketHeader& header,
-    char* buffer,
-    size_t packet_length,
-    const QuicDeque<QuicPathFrameBuffer>& payloads,
-    const bool is_padded,
-    EncryptionLevel level) {
-  if (payloads.empty()) {
-    QUIC_BUG
-        << "Attempt to generate connectivity response with no request payloads";
-    return 0;
-  }
-  if (!VersionHasIetfQuicFrames(version_.transport_version)) {
-    QUIC_BUG << "Attempt to build a PATH_RESPONSE Connectivity Probing "
-                "packet and not doing IETF QUIC";
-    return 0;
-  }
-
-  std::vector<std::unique_ptr<QuicPathResponseFrame>> path_response_frames;
-  for (const QuicPathFrameBuffer& payload : payloads) {
-    // Note that the control frame ID can be 0 since this is not retransmitted.
-    path_response_frames.push_back(
-        std::make_unique<QuicPathResponseFrame>(0, payload));
-  }
-
-  QuicFrames frames;
-  for (const std::unique_ptr<QuicPathResponseFrame>& path_response_frame :
-       path_response_frames) {
-    frames.push_back(QuicFrame(path_response_frame.get()));
-  }
-
-  if (is_padded) {
-    // Add padding to the rest of the packet in order to assess Path MTU
-    // characteristics.
-    QuicPaddingFrame padding_frame;
-    frames.push_back(QuicFrame(padding_frame));
-  }
-
-  return BuildDataPacket(header, frames, buffer, packet_length, level);
-}
-
 // static
 std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildPublicResetPacket(
     const QuicPublicResetPacket& packet) {
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h
index 8421c10..65a0b3b 100644
--- a/quic/core/quic_framer.h
+++ b/quic/core/quic_framer.h
@@ -427,33 +427,6 @@
                          size_t packet_length,
                          EncryptionLevel level);
 
-  // Serializes a probing packet, which is a padded PING packet. Returns the
-  // length of the packet. Returns 0 if it fails to serialize.
-  size_t BuildConnectivityProbingPacket(const QuicPacketHeader& header,
-                                        char* buffer,
-                                        size_t packet_length,
-                                        EncryptionLevel level);
-
-  // Serialize a probing packet that uses IETF QUIC's PATH CHALLENGE frame. Also
-  // fills the packet with padding.
-  size_t BuildPaddedPathChallengePacket(const QuicPacketHeader& header,
-                                        char* buffer,
-                                        size_t packet_length,
-                                        QuicPathFrameBuffer* payload,
-                                        QuicRandom* randomizer,
-                                        EncryptionLevel level);
-
-  // Serialize a probing response packet that uses IETF QUIC's PATH RESPONSE
-  // frame. Also fills the packet with padding if |is_padded| is
-  // true. |payloads| is always emptied, even if the packet can not be
-  // successfully built.
-  size_t BuildPathResponsePacket(const QuicPacketHeader& header,
-                                 char* buffer,
-                                 size_t packet_length,
-                                 const QuicDeque<QuicPathFrameBuffer>& payloads,
-                                 const bool is_padded,
-                                 EncryptionLevel level);
-
   // Returns a new public reset packet.
   static std::unique_ptr<QuicEncryptedPacket> BuildPublicResetPacket(
       const QuicPublicResetPacket& packet);
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index 646e9ee..c7e67fc 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -8511,341 +8511,6 @@
                                       QUIC_ARRAYSIZE(packet46));
 }
 
-// Test that the connectivity probing packet is serialized correctly as a
-// padded PING packet.
-TEST_P(QuicFramerTest, BuildConnectivityProbingPacket) {
-  QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
-  QuicPacketHeader header;
-  header.destination_connection_id = FramerTestConnectionId();
-  header.reset_flag = false;
-  header.version_flag = false;
-  header.packet_number = kPacketNumber;
-
-  // clang-format off
-  unsigned char packet[] = {
-    // public flags (8 byte connection_id)
-    0x2C,
-    // connection_id
-    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
-    // packet number
-    0x12, 0x34, 0x56, 0x78,
-
-    // frame type (ping frame)
-    0x07,
-    // frame type (padding frame)
-    0x00,
-    0x00, 0x00, 0x00, 0x00
-  };
-
-  unsigned char packet46[] = {
-    // type (short header, 4 byte packet number)
-    0x43,
-    // connection_id
-    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
-    // packet number
-    0x12, 0x34, 0x56, 0x78,
-
-    // frame type
-    0x07,
-    // frame type (padding frame)
-    0x00,
-    0x00, 0x00, 0x00, 0x00
-  };
-
-  unsigned char packet99[] = {
-    // type (short header, 4 byte packet number)
-    0x43,
-    // connection_id
-    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
-    // packet number
-    0x12, 0x34, 0x56, 0x78,
-
-    // frame type (IETF_PING frame)
-    0x01,
-    // frame type (padding frame)
-    0x00,
-    0x00, 0x00, 0x00, 0x00
-  };
-  // clang-format on
-
-  unsigned char* p = packet;
-  size_t packet_size = QUIC_ARRAYSIZE(packet);
-  if (VersionHasIetfQuicFrames(framer_.transport_version())) {
-    p = packet99;
-    packet_size = QUIC_ARRAYSIZE(packet99);
-  } else if (framer_.transport_version() >= QUIC_VERSION_46) {
-    p = packet46;
-    packet_size = QUIC_ARRAYSIZE(packet46);
-  }
-
-  std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
-
-  size_t length = framer_.BuildConnectivityProbingPacket(
-      header, buffer.get(), packet_size, ENCRYPTION_INITIAL);
-
-  EXPECT_NE(0u, length);
-  QuicPacket data(framer_.transport_version(), buffer.release(), length, true,
-                  header);
-
-  test::CompareCharArraysWithHexError("constructed packet", data.data(),
-                                      data.length(), AsChars(p), packet_size);
-}
-
-// Test that the path challenge connectivity probing packet is serialized
-// correctly as a padded PATH CHALLENGE packet.
-TEST_P(QuicFramerTest, BuildPaddedPathChallengePacket) {
-  if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
-    // This frame is only for IETF QUIC.
-    return;
-  }
-
-  QuicPacketHeader header;
-  header.destination_connection_id = FramerTestConnectionId();
-  header.reset_flag = false;
-  header.version_flag = false;
-  header.packet_number = kPacketNumber;
-  QuicPathFrameBuffer payload;
-
-  // clang-format off
-  unsigned char packet[] = {
-    // type (short header, 4 byte packet number)
-    0x43,
-    // connection_id
-    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
-    // packet number
-    0x12, 0x34, 0x56, 0x78,
-
-    // Path Challenge Frame type (IETF_PATH_CHALLENGE)
-    0x1a,
-    // 8 "random" bytes, MockRandom makes lots of r's
-    'r', 'r', 'r', 'r', 'r', 'r', 'r', 'r',
-    // frame type (padding frame)
-    0x00,
-    0x00, 0x00, 0x00, 0x00
-  };
-  // clang-format on
-
-  std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
-  MockRandom randomizer;
-
-  size_t length = framer_.BuildPaddedPathChallengePacket(
-      header, buffer.get(), QUIC_ARRAYSIZE(packet), &payload, &randomizer,
-      ENCRYPTION_INITIAL);
-  EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
-
-  // Payload has the random bytes that were generated. Copy them into packet,
-  // above, before checking that the generated packet is correct.
-  EXPECT_EQ(kQuicPathFrameBufferSize, payload.size());
-
-  QuicPacket data(framer_.transport_version(), buffer.release(), length, true,
-                  header);
-
-  test::CompareCharArraysWithHexError("constructed packet", data.data(),
-                                      data.length(), AsChars(packet),
-                                      QUIC_ARRAYSIZE(packet));
-}
-
-// Several tests that the path response connectivity probing packet is
-// serialized correctly as either a padded and unpadded PATH RESPONSE
-// packet. Also generates packets with 1 and 3 PATH_RESPONSES in them to
-// exercised the single- and multiple- payload cases.
-TEST_P(QuicFramerTest, BuildPathResponsePacket1ResponseUnpadded) {
-  if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
-    // This frame is only for IETF QUIC.
-    return;
-  }
-
-  QuicPacketHeader header;
-  header.destination_connection_id = FramerTestConnectionId();
-  header.reset_flag = false;
-  header.version_flag = false;
-  header.packet_number = kPacketNumber;
-  QuicPathFrameBuffer payload0 = {
-      {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}};
-
-  // Build 1 PATH RESPONSE, not padded
-  // clang-format off
-  unsigned char packet[] = {
-    // type (short header, 4 byte packet number)
-    0x43,
-    // connection_id
-    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
-    // packet number
-    0x12, 0x34, 0x56, 0x78,
-
-    // Path Response Frame type (IETF_PATH_RESPONSE)
-    0x1b,
-    // 8 "random" bytes
-    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-  };
-  // clang-format on
-  std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
-  QuicDeque<QuicPathFrameBuffer> payloads;
-  payloads.push_back(payload0);
-  size_t length = framer_.BuildPathResponsePacket(
-      header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
-      /*is_padded=*/false, ENCRYPTION_INITIAL);
-  EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
-  QuicPacket data(framer_.transport_version(), buffer.release(), length, true,
-                  header);
-
-  test::CompareCharArraysWithHexError("constructed packet", data.data(),
-                                      data.length(), AsChars(packet),
-                                      QUIC_ARRAYSIZE(packet));
-}
-
-TEST_P(QuicFramerTest, BuildPathResponsePacket1ResponsePadded) {
-  if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
-    // This frame is only for IETF QUIC.
-    return;
-  }
-
-  QuicPacketHeader header;
-  header.destination_connection_id = FramerTestConnectionId();
-  header.reset_flag = false;
-  header.version_flag = false;
-  header.packet_number = kPacketNumber;
-  QuicPathFrameBuffer payload0 = {
-      {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}};
-
-  // Build 1 PATH RESPONSE, padded
-  // clang-format off
-  unsigned char packet[] = {
-    // type (short header, 4 byte packet number)
-    0x43,
-    // connection_id
-    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
-    // packet number
-    0x12, 0x34, 0x56, 0x78,
-
-    // Path Response Frame type (IETF_PATH_RESPONSE)
-    0x1b,
-    // 8 "random" bytes
-    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-    // Padding type and pad
-    0x00, 0x00, 0x00, 0x00, 0x00
-  };
-  // clang-format on
-  std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
-  QuicDeque<QuicPathFrameBuffer> payloads;
-  payloads.push_back(payload0);
-  size_t length = framer_.BuildPathResponsePacket(
-      header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
-      /*is_padded=*/true, ENCRYPTION_INITIAL);
-  EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
-  QuicPacket data(framer_.transport_version(), buffer.release(), length, true,
-                  header);
-
-  test::CompareCharArraysWithHexError("constructed packet", data.data(),
-                                      data.length(), AsChars(packet),
-                                      QUIC_ARRAYSIZE(packet));
-}
-
-TEST_P(QuicFramerTest, BuildPathResponsePacket3ResponsesUnpadded) {
-  if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
-    // This frame is only for IETF QUIC.
-    return;
-  }
-
-  QuicPacketHeader header;
-  header.destination_connection_id = FramerTestConnectionId();
-  header.reset_flag = false;
-  header.version_flag = false;
-  header.packet_number = kPacketNumber;
-  QuicPathFrameBuffer payload0 = {
-      {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}};
-  QuicPathFrameBuffer payload1 = {
-      {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}};
-  QuicPathFrameBuffer payload2 = {
-      {0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28}};
-
-  // Build one packet with 3 PATH RESPONSES, no padding
-  // clang-format off
-  unsigned char packet[] = {
-    // type (short header, 4 byte packet number)
-    0x43,
-    // connection_id
-    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
-    // packet number
-    0x12, 0x34, 0x56, 0x78,
-
-    // 3 path response frames (IETF_PATH_RESPONSE type byte and payload)
-    0x1b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-    0x1b, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
-    0x1b, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
-  };
-  // clang-format on
-
-  std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
-  QuicDeque<QuicPathFrameBuffer> payloads;
-  payloads.push_back(payload0);
-  payloads.push_back(payload1);
-  payloads.push_back(payload2);
-  size_t length = framer_.BuildPathResponsePacket(
-      header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
-      /*is_padded=*/false, ENCRYPTION_INITIAL);
-  EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
-  QuicPacket data(framer_.transport_version(), buffer.release(), length, true,
-                  header);
-
-  test::CompareCharArraysWithHexError("constructed packet", data.data(),
-                                      data.length(), AsChars(packet),
-                                      QUIC_ARRAYSIZE(packet));
-}
-
-TEST_P(QuicFramerTest, BuildPathResponsePacket3ResponsesPadded) {
-  if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
-    // This frame is only for IETF QUIC.
-    return;
-  }
-
-  QuicPacketHeader header;
-  header.destination_connection_id = FramerTestConnectionId();
-  header.reset_flag = false;
-  header.version_flag = false;
-  header.packet_number = kPacketNumber;
-  QuicPathFrameBuffer payload0 = {
-      {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}};
-  QuicPathFrameBuffer payload1 = {
-      {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}};
-  QuicPathFrameBuffer payload2 = {
-      {0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28}};
-
-  // Build one packet with 3 PATH RESPONSES, with padding
-  // clang-format off
-  unsigned char packet[] = {
-    // type (short header, 4 byte packet number)
-    0x43,
-    // connection_id
-    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
-    // packet number
-    0x12, 0x34, 0x56, 0x78,
-
-    // 3 path response frames (IETF_PATH_RESPONSE byte and payload)
-    0x1b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-    0x1b, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
-    0x1b, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
-    // Padding
-    0x00, 0x00, 0x00, 0x00, 0x00
-  };
-  // clang-format on
-
-  std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
-  QuicDeque<QuicPathFrameBuffer> payloads;
-  payloads.push_back(payload0);
-  payloads.push_back(payload1);
-  payloads.push_back(payload2);
-  size_t length = framer_.BuildPathResponsePacket(
-      header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
-      /*is_padded=*/true, ENCRYPTION_INITIAL);
-  EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
-  QuicPacket data(framer_.transport_version(), buffer.release(), length, true,
-                  header);
-
-  test::CompareCharArraysWithHexError("constructed packet", data.data(),
-                                      data.length(), AsChars(packet),
-                                      QUIC_ARRAYSIZE(packet));
-}
 
 // Test that the MTU discovery packet is serialized correctly as a PING packet.
 TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) {
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc
index e7f5185..1a2ca6f 100644
--- a/quic/core/quic_packet_creator.cc
+++ b/quic/core/quic_packet_creator.cc
@@ -5,10 +5,12 @@
 #include "net/third_party/quiche/src/quic/core/quic_packet_creator.h"
 
 #include <algorithm>
+#include <cstddef>
 #include <cstdint>
 #include <string>
 
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h"
 #include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
 #include "net/third_party/quiche/src/quic/core/quic_constants.h"
 #include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
@@ -700,7 +702,7 @@
                 << header;
 
   std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
-  size_t length = framer_->BuildConnectivityProbingPacket(
+  size_t length = BuildConnectivityProbingPacket(
       header, buffer.get(), max_plaintext_size_, packet_.encryption_level);
   DCHECK(length);
 
@@ -734,7 +736,7 @@
   QUIC_DVLOG(2) << ENDPOINT << "Serializing path challenge packet " << header;
 
   std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
-  size_t length = framer_->BuildPaddedPathChallengePacket(
+  size_t length = BuildPaddedPathChallengePacket(
       header, buffer.get(), max_plaintext_size_, payload, random_,
       packet_.encryption_level);
   DCHECK(length);
@@ -770,9 +772,9 @@
   QUIC_DVLOG(2) << ENDPOINT << "Serializing path response packet " << header;
 
   std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
-  size_t length = framer_->BuildPathResponsePacket(
-      header, buffer.get(), max_plaintext_size_, payloads, is_padded,
-      packet_.encryption_level);
+  size_t length =
+      BuildPathResponsePacket(header, buffer.get(), max_plaintext_size_,
+                              payloads, is_padded, packet_.encryption_level);
   DCHECK(length);
 
   const size_t encrypted_length = framer_->EncryptInPlace(
@@ -791,6 +793,92 @@
   return serialize_packet;
 }
 
+size_t QuicPacketCreator::BuildPaddedPathChallengePacket(
+    const QuicPacketHeader& header,
+    char* buffer,
+    size_t packet_length,
+    QuicPathFrameBuffer* payload,
+    QuicRandom* randomizer,
+    EncryptionLevel level) {
+  DCHECK(VersionHasIetfQuicFrames(framer_->transport_version()));
+  QuicFrames frames;
+
+  // Write a PATH_CHALLENGE frame, which has a random 8-byte payload
+  randomizer->RandBytes(payload->data(), payload->size());
+  QuicPathChallengeFrame path_challenge_frame(0, *payload);
+  frames.push_back(QuicFrame(&path_challenge_frame));
+
+  if (debug_delegate_ != nullptr) {
+    debug_delegate_->OnFrameAddedToPacket(QuicFrame(&path_challenge_frame));
+  }
+
+  // Add padding to the rest of the packet in order to assess Path MTU
+  // characteristics.
+  QuicPaddingFrame padding_frame;
+  frames.push_back(QuicFrame(padding_frame));
+
+  return framer_->BuildDataPacket(header, frames, buffer, packet_length, level);
+}
+
+size_t QuicPacketCreator::BuildPathResponsePacket(
+    const QuicPacketHeader& header,
+    char* buffer,
+    size_t packet_length,
+    const QuicDeque<QuicPathFrameBuffer>& payloads,
+    const bool is_padded,
+    EncryptionLevel level) {
+  if (payloads.empty()) {
+    QUIC_BUG
+        << "Attempt to generate connectivity response with no request payloads";
+    return 0;
+  }
+  DCHECK(VersionHasIetfQuicFrames(framer_->transport_version()));
+
+  std::vector<std::unique_ptr<QuicPathResponseFrame>> path_response_frames;
+  for (const QuicPathFrameBuffer& payload : payloads) {
+    // Note that the control frame ID can be 0 since this is not retransmitted.
+    path_response_frames.push_back(
+        std::make_unique<QuicPathResponseFrame>(0, payload));
+  }
+
+  QuicFrames frames;
+  for (const std::unique_ptr<QuicPathResponseFrame>& path_response_frame :
+       path_response_frames) {
+    frames.push_back(QuicFrame(path_response_frame.get()));
+    if (debug_delegate_ != nullptr) {
+      debug_delegate_->OnFrameAddedToPacket(
+          QuicFrame(path_response_frame.get()));
+    }
+  }
+
+  if (is_padded) {
+    // Add padding to the rest of the packet in order to assess Path MTU
+    // characteristics.
+    QuicPaddingFrame padding_frame;
+    frames.push_back(QuicFrame(padding_frame));
+  }
+
+  return framer_->BuildDataPacket(header, frames, buffer, packet_length, level);
+}
+
+size_t QuicPacketCreator::BuildConnectivityProbingPacket(
+    const QuicPacketHeader& header,
+    char* buffer,
+    size_t packet_length,
+    EncryptionLevel level) {
+  QuicFrames frames;
+
+  // Write a PING frame, which has no data payload.
+  QuicPingFrame ping_frame;
+  frames.push_back(QuicFrame(ping_frame));
+
+  // Add padding to the rest of the packet.
+  QuicPaddingFrame padding_frame;
+  frames.push_back(QuicFrame(padding_frame));
+
+  return framer_->BuildDataPacket(header, frames, buffer, packet_length, level);
+}
+
 // TODO(b/74062209): Make this a public method of framer?
 SerializedPacket QuicPacketCreator::NoPacket() {
   return SerializedPacket(QuicPacketNumber(), PACKET_1BYTE_PACKET_NUMBER,
diff --git a/quic/core/quic_packet_creator.h b/quic/core/quic_packet_creator.h
index a654423..f202af0 100644
--- a/quic/core/quic_packet_creator.h
+++ b/quic/core/quic_packet_creator.h
@@ -395,6 +395,33 @@
     return combine_generator_and_creator_;
   }
 
+  // Serialize a probing packet that uses IETF QUIC's PATH CHALLENGE frame. Also
+  // fills the packet with padding.
+  size_t BuildPaddedPathChallengePacket(const QuicPacketHeader& header,
+                                        char* buffer,
+                                        size_t packet_length,
+                                        QuicPathFrameBuffer* payload,
+                                        QuicRandom* randomizer,
+                                        EncryptionLevel level);
+
+  // Serialize a probing response packet that uses IETF QUIC's PATH RESPONSE
+  // frame. Also fills the packet with padding if |is_padded| is
+  // true. |payloads| is always emptied, even if the packet can not be
+  // successfully built.
+  size_t BuildPathResponsePacket(const QuicPacketHeader& header,
+                                 char* buffer,
+                                 size_t packet_length,
+                                 const QuicDeque<QuicPathFrameBuffer>& payloads,
+                                 const bool is_padded,
+                                 EncryptionLevel level);
+
+  // Serializes a probing packet, which is a padded PING packet. Returns the
+  // length of the packet. Returns 0 if it fails to serialize.
+  size_t BuildConnectivityProbingPacket(const QuicPacketHeader& header,
+                                        char* buffer,
+                                        size_t packet_length,
+                                        EncryptionLevel level);
+
  private:
   friend class test::QuicPacketCreatorPeer;
 
diff --git a/quic/core/quic_packet_creator_test.cc b/quic/core/quic_packet_creator_test.cc
index 1e66667..75ea7f5 100644
--- a/quic/core/quic_packet_creator_test.cc
+++ b/quic/core/quic_packet_creator_test.cc
@@ -18,6 +18,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
@@ -39,6 +40,12 @@
 namespace test {
 namespace {
 
+const QuicPacketNumber kPacketNumber = QuicPacketNumber(UINT64_C(0x12345678));
+// Use fields in which each byte is distinct to ensure that every byte is
+// framed correctly. The values are otherwise arbitrary.
+const QuicConnectionId kTestConnectionId =
+    TestConnectionId(UINT64_C(0xFEDCBA9876543210));
+
 // Run tests with combinations of {ParsedQuicVersion,
 // ToggleVersionSerialization}.
 struct TestParams {
@@ -585,8 +592,8 @@
 }
 
 TEST_P(QuicPacketCreatorTest, SerializeConnectionClose) {
-  QuicConnectionCloseFrame frame(GetParam().version.transport_version,
-                                 QUIC_NO_ERROR, "error",
+  QuicConnectionCloseFrame frame(creator_.transport_version(), QUIC_NO_ERROR,
+                                 "error",
                                  /*transport_close_frame_type=*/0);
 
   QuicFrames frames;
@@ -823,7 +830,7 @@
   ParsedQuicVersionVector versions;
   versions.push_back(test::QuicVersionMax());
   const bool ietf_quic =
-      VersionHasIetfInvariantHeader(GetParam().version.transport_version);
+      VersionHasIetfInvariantHeader(creator_.transport_version());
   const bool has_length_prefix =
       GetParam().version.HasLengthPrefixedConnectionIds();
   std::unique_ptr<QuicEncryptedPacket> encrypted(
@@ -840,6 +847,340 @@
   client_framer_.ProcessPacket(*encrypted);
 }
 
+// Test that the path challenge connectivity probing packet is serialized
+// correctly as a padded PATH CHALLENGE packet.
+TEST_P(QuicPacketCreatorTest, BuildPathChallengePacket) {
+  if (!VersionHasIetfQuicFrames(creator_.transport_version())) {
+    // This frame is only for IETF QUIC.
+    return;
+  }
+
+  QuicPacketHeader header;
+  header.destination_connection_id = kTestConnectionId;
+  header.reset_flag = false;
+  header.version_flag = false;
+  header.packet_number = kPacketNumber;
+  QuicPathFrameBuffer payload;
+
+  // clang-format off
+  unsigned char packet[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // Path Challenge Frame type (IETF_PATH_CHALLENGE)
+    0x1a,
+    // 8 "random" bytes, MockRandom makes lots of r's
+    'r', 'r', 'r', 'r', 'r', 'r', 'r', 'r',
+    // frame type (padding frame)
+    0x00,
+    0x00, 0x00, 0x00, 0x00
+  };
+  // clang-format on
+
+  std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
+  MockRandom randomizer;
+
+  size_t length = creator_.BuildPaddedPathChallengePacket(
+      header, buffer.get(), QUIC_ARRAYSIZE(packet), &payload, &randomizer,
+      ENCRYPTION_INITIAL);
+  EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
+
+  // Payload has the random bytes that were generated. Copy them into packet,
+  // above, before checking that the generated packet is correct.
+  EXPECT_EQ(kQuicPathFrameBufferSize, payload.size());
+
+  QuicPacket data(creator_.transport_version(), buffer.release(), length, true,
+                  header);
+
+  test::CompareCharArraysWithHexError(
+      "constructed packet", data.data(), data.length(),
+      reinterpret_cast<char*>(packet), QUIC_ARRAYSIZE(packet));
+}
+
+TEST_P(QuicPacketCreatorTest, BuildConnectivityProbingPacket) {
+  QuicPacketHeader header;
+  header.destination_connection_id = kTestConnectionId;
+  header.reset_flag = false;
+  header.version_flag = false;
+  header.packet_number = kPacketNumber;
+
+  // clang-format off
+  unsigned char packet[] = {
+    // public flags (8 byte connection_id)
+    0x2C,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (ping frame)
+    0x07,
+    // frame type (padding frame)
+    0x00,
+    0x00, 0x00, 0x00, 0x00
+  };
+
+  unsigned char packet46[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type
+    0x07,
+    // frame type (padding frame)
+    0x00,
+    0x00, 0x00, 0x00, 0x00
+  };
+
+  unsigned char packet99[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (IETF_PING frame)
+    0x01,
+    // frame type (padding frame)
+    0x00,
+    0x00, 0x00, 0x00, 0x00
+  };
+  // clang-format on
+
+  unsigned char* p = packet;
+  size_t packet_size = QUIC_ARRAYSIZE(packet);
+  if (VersionHasIetfQuicFrames(creator_.transport_version())) {
+    p = packet99;
+    packet_size = QUIC_ARRAYSIZE(packet99);
+  } else if (creator_.transport_version() >= QUIC_VERSION_46) {
+    p = packet46;
+    packet_size = QUIC_ARRAYSIZE(packet46);
+  }
+
+  std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
+
+  size_t length = creator_.BuildConnectivityProbingPacket(
+      header, buffer.get(), packet_size, ENCRYPTION_INITIAL);
+
+  EXPECT_NE(0u, length);
+  QuicPacket data(creator_.transport_version(), buffer.release(), length, true,
+                  header);
+
+  test::CompareCharArraysWithHexError("constructed packet", data.data(),
+                                      data.length(), reinterpret_cast<char*>(p),
+                                      packet_size);
+}
+
+// Several tests that the path response connectivity probing packet is
+// serialized correctly as either a padded and unpadded PATH RESPONSE
+// packet. Also generates packets with 1 and 3 PATH_RESPONSES in them to
+// exercised the single- and multiple- payload cases.
+TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket1ResponseUnpadded) {
+  if (!VersionHasIetfQuicFrames(creator_.transport_version())) {
+    // This frame is only for IETF QUIC.
+    return;
+  }
+
+  QuicPacketHeader header;
+  header.destination_connection_id = kTestConnectionId;
+  header.reset_flag = false;
+  header.version_flag = false;
+  header.packet_number = kPacketNumber;
+  QuicPathFrameBuffer payload0 = {
+      {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}};
+
+  // Build 1 PATH RESPONSE, not padded
+  // clang-format off
+  unsigned char packet[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // Path Response Frame type (IETF_PATH_RESPONSE)
+    0x1b,
+    // 8 "random" bytes
+    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+  };
+  // clang-format on
+  std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
+  QuicDeque<QuicPathFrameBuffer> payloads;
+  payloads.push_back(payload0);
+  size_t length = creator_.BuildPathResponsePacket(
+      header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
+      /*is_padded=*/false, ENCRYPTION_INITIAL);
+  EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
+  QuicPacket data(creator_.transport_version(), buffer.release(), length, true,
+                  header);
+
+  test::CompareCharArraysWithHexError(
+      "constructed packet", data.data(), data.length(),
+      reinterpret_cast<char*>(packet), QUIC_ARRAYSIZE(packet));
+}
+
+TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket1ResponsePadded) {
+  if (!VersionHasIetfQuicFrames(creator_.transport_version())) {
+    // This frame is only for IETF QUIC.
+    return;
+  }
+
+  QuicPacketHeader header;
+  header.destination_connection_id = kTestConnectionId;
+  header.reset_flag = false;
+  header.version_flag = false;
+  header.packet_number = kPacketNumber;
+  QuicPathFrameBuffer payload0 = {
+      {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}};
+
+  // Build 1 PATH RESPONSE, padded
+  // clang-format off
+  unsigned char packet[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // Path Response Frame type (IETF_PATH_RESPONSE)
+    0x1b,
+    // 8 "random" bytes
+    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+    // Padding type and pad
+    0x00, 0x00, 0x00, 0x00, 0x00
+  };
+  // clang-format on
+  std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
+  QuicDeque<QuicPathFrameBuffer> payloads;
+  payloads.push_back(payload0);
+  size_t length = creator_.BuildPathResponsePacket(
+      header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
+      /*is_padded=*/true, ENCRYPTION_INITIAL);
+  EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
+  QuicPacket data(creator_.transport_version(), buffer.release(), length, true,
+                  header);
+
+  test::CompareCharArraysWithHexError(
+      "constructed packet", data.data(), data.length(),
+      reinterpret_cast<char*>(packet), QUIC_ARRAYSIZE(packet));
+}
+
+TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket3ResponsesUnpadded) {
+  if (!VersionHasIetfQuicFrames(creator_.transport_version())) {
+    // This frame is only for IETF QUIC.
+    return;
+  }
+
+  QuicPacketHeader header;
+  header.destination_connection_id = kTestConnectionId;
+  header.reset_flag = false;
+  header.version_flag = false;
+  header.packet_number = kPacketNumber;
+  QuicPathFrameBuffer payload0 = {
+      {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}};
+  QuicPathFrameBuffer payload1 = {
+      {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}};
+  QuicPathFrameBuffer payload2 = {
+      {0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28}};
+
+  // Build one packet with 3 PATH RESPONSES, no padding
+  // clang-format off
+  unsigned char packet[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // 3 path response frames (IETF_PATH_RESPONSE type byte and payload)
+    0x1b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+    0x1b, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+    0x1b, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+  };
+  // clang-format on
+
+  std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
+  QuicDeque<QuicPathFrameBuffer> payloads;
+  payloads.push_back(payload0);
+  payloads.push_back(payload1);
+  payloads.push_back(payload2);
+  size_t length = creator_.BuildPathResponsePacket(
+      header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
+      /*is_padded=*/false, ENCRYPTION_INITIAL);
+  EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
+  QuicPacket data(creator_.transport_version(), buffer.release(), length, true,
+                  header);
+
+  test::CompareCharArraysWithHexError(
+      "constructed packet", data.data(), data.length(),
+      reinterpret_cast<char*>(packet), QUIC_ARRAYSIZE(packet));
+}
+
+TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket3ResponsesPadded) {
+  if (!VersionHasIetfQuicFrames(creator_.transport_version())) {
+    // This frame is only for IETF QUIC.
+    return;
+  }
+
+  QuicPacketHeader header;
+  header.destination_connection_id = kTestConnectionId;
+  header.reset_flag = false;
+  header.version_flag = false;
+  header.packet_number = kPacketNumber;
+  QuicPathFrameBuffer payload0 = {
+      {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}};
+  QuicPathFrameBuffer payload1 = {
+      {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}};
+  QuicPathFrameBuffer payload2 = {
+      {0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28}};
+
+  // Build one packet with 3 PATH RESPONSES, with padding
+  // clang-format off
+  unsigned char packet[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // 3 path response frames (IETF_PATH_RESPONSE byte and payload)
+    0x1b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+    0x1b, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+    0x1b, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+    // Padding
+    0x00, 0x00, 0x00, 0x00, 0x00
+  };
+  // clang-format on
+
+  std::unique_ptr<char[]> buffer(new char[kMaxOutgoingPacketSize]);
+  QuicDeque<QuicPathFrameBuffer> payloads;
+  payloads.push_back(payload0);
+  payloads.push_back(payload1);
+  payloads.push_back(payload2);
+  size_t length = creator_.BuildPathResponsePacket(
+      header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
+      /*is_padded=*/true, ENCRYPTION_INITIAL);
+  EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
+  QuicPacket data(creator_.transport_version(), buffer.release(), length, true,
+                  header);
+
+  test::CompareCharArraysWithHexError(
+      "constructed packet", data.data(), data.length(),
+      reinterpret_cast<char*>(packet), QUIC_ARRAYSIZE(packet));
+}
+
 TEST_P(QuicPacketCreatorTest, SerializeConnectivityProbingPacket) {
   for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) {
     EncryptionLevel level = static_cast<EncryptionLevel>(i);
@@ -847,7 +1188,7 @@
     creator_.set_encryption_level(level);
 
     OwningSerializedPacketPointer encrypted;
-    if (VersionHasIetfQuicFrames(GetParam().version.transport_version)) {
+    if (VersionHasIetfQuicFrames(creator_.transport_version())) {
       QuicPathFrameBuffer payload = {
           {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}};
       encrypted =
@@ -862,7 +1203,7 @@
       EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
       EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
       EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
-      if (VersionHasIetfQuicFrames(GetParam().version.transport_version)) {
+      if (VersionHasIetfQuicFrames(creator_.transport_version())) {
         EXPECT_CALL(framer_visitor_, OnPathChallengeFrame(_));
         EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
       } else {
@@ -878,7 +1219,7 @@
 }
 
 TEST_P(QuicPacketCreatorTest, SerializePathChallengeProbePacket) {
-  if (!VersionHasIetfQuicFrames(GetParam().version.transport_version)) {
+  if (!VersionHasIetfQuicFrames(creator_.transport_version())) {
     return;
   }
   QuicPathFrameBuffer payload = {
@@ -909,7 +1250,7 @@
 }
 
 TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket1PayloadPadded) {
-  if (!VersionHasIetfQuicFrames(GetParam().version.transport_version)) {
+  if (!VersionHasIetfQuicFrames(creator_.transport_version())) {
     return;
   }
   QuicPathFrameBuffer payload0 = {
@@ -943,7 +1284,7 @@
 
 TEST_P(QuicPacketCreatorTest,
        SerializePathResponseProbePacket1PayloadUnPadded) {
-  if (!VersionHasIetfQuicFrames(GetParam().version.transport_version)) {
+  if (!VersionHasIetfQuicFrames(creator_.transport_version())) {
     return;
   }
   QuicPathFrameBuffer payload0 = {
@@ -975,7 +1316,7 @@
 }
 
 TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket2PayloadsPadded) {
-  if (!VersionHasIetfQuicFrames(GetParam().version.transport_version)) {
+  if (!VersionHasIetfQuicFrames(creator_.transport_version())) {
     return;
   }
   QuicPathFrameBuffer payload0 = {
@@ -1012,7 +1353,7 @@
 
 TEST_P(QuicPacketCreatorTest,
        SerializePathResponseProbePacket2PayloadsUnPadded) {
-  if (!VersionHasIetfQuicFrames(GetParam().version.transport_version)) {
+  if (!VersionHasIetfQuicFrames(creator_.transport_version())) {
     return;
   }
   QuicPathFrameBuffer payload0 = {
@@ -1047,7 +1388,7 @@
 }
 
 TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket3PayloadsPadded) {
-  if (!VersionHasIetfQuicFrames(GetParam().version.transport_version)) {
+  if (!VersionHasIetfQuicFrames(creator_.transport_version())) {
     return;
   }
   QuicPathFrameBuffer payload0 = {
@@ -1087,7 +1428,7 @@
 
 TEST_P(QuicPacketCreatorTest,
        SerializePathResponseProbePacket3PayloadsUnpadded) {
-  if (!VersionHasIetfQuicFrames(GetParam().version.transport_version)) {
+  if (!VersionHasIetfQuicFrames(creator_.transport_version())) {
     return;
   }
   QuicPathFrameBuffer payload0 = {
@@ -1124,7 +1465,7 @@
 }
 
 TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthLeastAwaiting) {
-  if (VersionHasIetfInvariantHeader(GetParam().version.transport_version) &&
+  if (VersionHasIetfInvariantHeader(creator_.transport_version()) &&
       !GetParam().version.SendsVariableLengthPacketNumberInLongHeader()) {
     EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
               QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
@@ -1162,7 +1503,7 @@
 
 TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthCwnd) {
   QuicPacketCreatorPeer::SetPacketNumber(&creator_, 1);
-  if (VersionHasIetfInvariantHeader(GetParam().version.transport_version) &&
+  if (VersionHasIetfInvariantHeader(creator_.transport_version()) &&
       !GetParam().version.SendsVariableLengthPacketNumberInLongHeader()) {
     EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
               QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
@@ -1196,7 +1537,7 @@
 
 TEST_P(QuicPacketCreatorTest, SkipNPacketNumbers) {
   QuicPacketCreatorPeer::SetPacketNumber(&creator_, 1);
-  if (VersionHasIetfInvariantHeader(GetParam().version.transport_version) &&
+  if (VersionHasIetfInvariantHeader(creator_.transport_version()) &&
       !GetParam().version.SendsVariableLengthPacketNumberInLongHeader()) {
     EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
               QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
@@ -1862,7 +2203,7 @@
 
 // Regression test for bugfix of GetPacketHeaderSize.
 TEST_P(QuicPacketCreatorTest, GetGuaranteedLargestMessagePayload) {
-  QuicTransportVersion version = GetParam().version.transport_version;
+  QuicTransportVersion version = creator_.transport_version();
   if (!VersionSupportsMessageFrames(version)) {
     return;
   }