Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / net / quic / quic_framer_test.cc
index d14e673..2c3d274 100644 (file)
@@ -460,7 +460,7 @@ class QuicFramerTest : public ::testing::TestWithParam<QuicVersion> {
   void CheckStreamFrameBoundaries(unsigned char* packet,
                                   size_t stream_id_size,
                                   bool include_version) {
-    // Now test framing boundaries
+    // Now test framing boundaries.
     for (size_t i = kQuicFrameTypeSize; i < GetMinStreamFrameSize(); ++i) {
       string expected_error;
       if (i < kQuicFrameTypeSize + stream_id_size) {
@@ -682,7 +682,7 @@ TEST_P(QuicFramerTest, PacketHeader) {
   EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
   EXPECT_EQ(0x00u, visitor_.header_->fec_group);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = 0;
        i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
                                PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -735,7 +735,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith4ByteConnectionId) {
   EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
   EXPECT_EQ(0x00u, visitor_.header_->fec_group);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = 0;
        i < GetPacketHeaderSize(PACKET_4BYTE_CONNECTION_ID, !kIncludeVersion,
                                PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -791,7 +791,7 @@ TEST_P(QuicFramerTest, PacketHeader1ByteConnectionId) {
   EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
   EXPECT_EQ(0x00u, visitor_.header_->fec_group);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = 0;
        i < GetPacketHeaderSize(PACKET_1BYTE_CONNECTION_ID, !kIncludeVersion,
                                PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -846,7 +846,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
   EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
   EXPECT_EQ(0x00u, visitor_.header_->fec_group);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = 0;
        i < GetPacketHeaderSize(PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion,
                                PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -903,7 +903,7 @@ TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
   EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
   EXPECT_EQ(0x00u, visitor_.header_->fec_group);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = 0;
        i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, kIncludeVersion,
                                PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -958,7 +958,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith4ByteSequenceNumber) {
   EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
   EXPECT_EQ(0x00u, visitor_.header_->fec_group);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = 0;
        i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
                                PACKET_4BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -1013,7 +1013,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith2ByteSequenceNumber) {
   EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
   EXPECT_EQ(0x00u, visitor_.header_->fec_group);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = 0;
        i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
                                PACKET_2BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -1068,7 +1068,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith1ByteSequenceNumber) {
   EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
   EXPECT_EQ(0x00u, visitor_.header_->fec_group);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = 0;
        i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
                                PACKET_1BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -1307,7 +1307,7 @@ TEST_P(QuicFramerTest, StreamFrame) {
             visitor_.stream_frames_[0]->offset);
   CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   CheckStreamFrameBoundaries(packet, kQuicMaxStreamIdSize, !kIncludeVersion);
 }
 
@@ -1355,7 +1355,7 @@ TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) {
             visitor_.stream_frames_[0]->offset);
   CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   const size_t stream_id_size = 3;
   CheckStreamFrameBoundaries(packet, stream_id_size, !kIncludeVersion);
 }
@@ -1404,7 +1404,7 @@ TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) {
             visitor_.stream_frames_[0]->offset);
   CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   const size_t stream_id_size = 2;
   CheckStreamFrameBoundaries(packet, stream_id_size, !kIncludeVersion);
 }
@@ -1453,7 +1453,7 @@ TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) {
             visitor_.stream_frames_[0]->offset);
   CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   const size_t stream_id_size = 1;
   CheckStreamFrameBoundaries(packet, stream_id_size, !kIncludeVersion);
 }
@@ -1506,7 +1506,7 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) {
             visitor_.stream_frames_[0]->offset);
   CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   CheckStreamFrameBoundaries(packet, kQuicMaxStreamIdSize, kIncludeVersion);
 }
 
@@ -1682,7 +1682,445 @@ TEST_P(QuicFramerTest, StreamFrameInFecGroup) {
   CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
 }
 
+TEST_P(QuicFramerTest, AckFramev22) {
+  if (version_ > QUIC_VERSION_22) {
+    return;
+  }
+  unsigned char packet[] = {
+    // public flags (8 byte connection_id)
+    0x3C,
+    // connection_id
+    0x10, 0x32, 0x54, 0x76,
+    0x98, 0xBA, 0xDC, 0xFE,
+    // packet sequence number
+    0xA8, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // private flags (entropy)
+    0x01,
+
+    // frame type (ack frame)
+    // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+    0x6C,
+    // entropy hash of all received packets.
+    0xBA,
+    // largest observed packet sequence number
+    0xBF, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // Zero delta time.
+    0x0, 0x0,
+    // num missing packets
+    0x01,
+    // missing packet delta
+    0x01,
+    // 0 more missing packets in range.
+    0x00,
+    // Number of revived packets.
+    0x00,
+  };
+
+  QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+  EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+  EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+  ASSERT_TRUE(visitor_.header_.get());
+  EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+  EXPECT_EQ(0u, visitor_.stream_frames_.size());
+  ASSERT_EQ(1u, visitor_.ack_frames_.size());
+  const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+  EXPECT_EQ(0xBA, frame.entropy_hash);
+  EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed);
+  ASSERT_EQ(1u, frame.missing_packets.size());
+  SequenceNumberSet::const_iterator missing_iter =
+      frame.missing_packets.begin();
+  EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+
+  const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+  const size_t kLargestObservedOffset = kReceivedEntropyOffset +
+      kQuicEntropyHashSize;
+  const size_t kMissingDeltaTimeOffset = kLargestObservedOffset +
+      PACKET_6BYTE_SEQUENCE_NUMBER;
+  const size_t kNumMissingPacketOffset = kMissingDeltaTimeOffset +
+      kQuicDeltaTimeLargestObservedSize;
+  const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
+      kNumberOfNackRangesSize;
+  const size_t kMissingPacketsRange = kMissingPacketsOffset +
+      PACKET_1BYTE_SEQUENCE_NUMBER;
+  const size_t kRevivedPacketsLength = kMissingPacketsRange +
+      PACKET_1BYTE_SEQUENCE_NUMBER;
+  // Now test framing boundaries.
+  const size_t ack_frame_size = kRevivedPacketsLength +
+      PACKET_1BYTE_SEQUENCE_NUMBER;
+  for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+    string expected_error;
+    if (i < kLargestObservedOffset) {
+      expected_error = "Unable to read entropy hash for received packets.";
+    } else if (i < kMissingDeltaTimeOffset) {
+      expected_error = "Unable to read largest observed.";
+    } else if (i < kNumMissingPacketOffset) {
+      expected_error = "Unable to read delta time largest observed.";
+    } else if (i < kMissingPacketsOffset) {
+      expected_error = "Unable to read num missing packet ranges.";
+    } else if (i < kMissingPacketsRange) {
+      expected_error = "Unable to read missing sequence number delta.";
+    } else if (i < kRevivedPacketsLength) {
+      expected_error = "Unable to read missing sequence number range.";
+    } else {
+      expected_error = "Unable to read num revived packets.";
+    }
+    CheckProcessingFails(
+        packet,
+        i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+                                PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+        expected_error, QUIC_INVALID_ACK_DATA);
+  }
+}
+
+
+TEST_P(QuicFramerTest, AckFrameTwoTimestamp) {
+  if (version_ <= QUIC_VERSION_22) {
+    return;
+  }
+  unsigned char packet[] = {
+    // public flags (8 byte connection_id)
+    0x3C,
+    // connection_id
+    0x10, 0x32, 0x54, 0x76,
+    0x98, 0xBA, 0xDC, 0xFE,
+    // packet sequence number
+    0xA8, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // private flags (entropy)
+    0x01,
+
+    // frame type (ack frame)
+    // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+    0x6C,
+    // entropy hash of all received packets.
+    0xBA,
+    // largest observed packet sequence number
+    0xBF, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // Zero delta time.
+    0x0, 0x0,
+    // Number of timestamps.
+    0x02,
+    // Delta from largest observed.
+    0x01,
+    // Delta time.
+    0x10, 0x32, 0x54, 0x76,
+    // Delta from largest observed.
+    0x02,
+    // Delta time.
+    0x10, 0x32,
+    // num missing packets
+    0x01,
+    // missing packet delta
+    0x01,
+    // 0 more missing packets in range.
+    0x00,
+    // Number of revived packets.
+    0x00,
+  };
+
+  QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+  EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+  EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+  ASSERT_TRUE(visitor_.header_.get());
+  EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+  EXPECT_EQ(0u, visitor_.stream_frames_.size());
+  ASSERT_EQ(1u, visitor_.ack_frames_.size());
+  const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+  EXPECT_EQ(0xBA, frame.entropy_hash);
+  EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed);
+  ASSERT_EQ(1u, frame.missing_packets.size());
+  ASSERT_EQ(2u, frame.received_packet_times.size());
+  SequenceNumberSet::const_iterator missing_iter =
+      frame.missing_packets.begin();
+  EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+
+  const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+  const size_t kLargestObservedOffset = kReceivedEntropyOffset +
+      kQuicEntropyHashSize;
+  const size_t kMissingDeltaTimeOffset = kLargestObservedOffset +
+      PACKET_6BYTE_SEQUENCE_NUMBER;
+  const size_t kNumTimestampsOffset = kMissingDeltaTimeOffset +
+      kQuicDeltaTimeLargestObservedSize;
+  const size_t kTimestampDeltaLargestObserved1 = kNumTimestampsOffset +
+      kQuicNumTimestampsSize;
+  const size_t kTimestampTimeDeltaLargestObserved1 =
+      kTimestampDeltaLargestObserved1 + 1;
+  const size_t kTimestampDeltaLargestObserved2 =
+      kTimestampTimeDeltaLargestObserved1 + 4;
+  const size_t kTimestampTimeDeltaLargestObserved2 =
+      kTimestampDeltaLargestObserved2 + 1;
+  const size_t kNumMissingPacketOffset =
+      kTimestampTimeDeltaLargestObserved2 + 2;
+  const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
+      kNumberOfNackRangesSize;
+  const size_t kMissingPacketsRange = kMissingPacketsOffset +
+      PACKET_1BYTE_SEQUENCE_NUMBER;
+  const size_t kRevivedPacketsLength = kMissingPacketsRange +
+      PACKET_1BYTE_SEQUENCE_NUMBER;
+  // Now test framing boundaries.
+  const size_t ack_frame_size = kRevivedPacketsLength +
+      PACKET_1BYTE_SEQUENCE_NUMBER;
+  for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+    string expected_error;
+    if (i < kLargestObservedOffset) {
+      expected_error = "Unable to read entropy hash for received packets.";
+    } else if (i < kMissingDeltaTimeOffset) {
+      expected_error = "Unable to read largest observed.";
+    } else if (i < kNumTimestampsOffset) {
+      expected_error = "Unable to read delta time largest observed.";
+    } else if (i < kTimestampDeltaLargestObserved1) {
+      expected_error = "Unable to read num received packets.";
+    } else if (i < kTimestampTimeDeltaLargestObserved1) {
+      expected_error = "Unable to read sequence delta in received packets.";
+    } else if (i < kTimestampDeltaLargestObserved2) {
+      expected_error = "Unable to read time delta in received packets.";
+    } else if (i < kTimestampTimeDeltaLargestObserved2) {
+      expected_error = "Unable to read sequence delta in received packets.";
+    } else if (i < kNumMissingPacketOffset) {
+      expected_error =
+          "Unable to read incremental time delta in received packets.";
+    } else if (i < kMissingPacketsOffset) {
+      expected_error = "Unable to read num missing packet ranges.";
+    } else if (i < kMissingPacketsRange) {
+      expected_error = "Unable to read missing sequence number delta.";
+    } else if (i < kRevivedPacketsLength) {
+      expected_error = "Unable to read missing sequence number range.";
+    } else {
+      expected_error = "Unable to read num revived packets.";
+    }
+    CheckProcessingFails(
+        packet,
+        i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+                                PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+        expected_error, QUIC_INVALID_ACK_DATA);
+  }
+}
+
+
+TEST_P(QuicFramerTest, AckFrameOneTimestamp) {
+  if (version_ <= QUIC_VERSION_22) {
+    return;
+  }
+  unsigned char packet[] = {
+    // public flags (8 byte connection_id)
+    0x3C,
+    // connection_id
+    0x10, 0x32, 0x54, 0x76,
+    0x98, 0xBA, 0xDC, 0xFE,
+    // packet sequence number
+    0xA8, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // private flags (entropy)
+    0x01,
+
+    // frame type (ack frame)
+    // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+    0x6C,
+    // entropy hash of all received packets.
+    0xBA,
+    // largest observed packet sequence number
+    0xBF, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // Zero delta time.
+    0x0, 0x0,
+    // Number of timestamps.
+    0x01,
+    // Delta from largest observed.
+    0x01,
+    // Delta time.
+    0x10, 0x32, 0x54, 0x76,
+    // num missing packets
+    0x01,
+    // missing packet delta
+    0x01,
+    // 0 more missing packets in range.
+    0x00,
+    // Number of revived packets.
+    0x00,
+  };
+
+  QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+  EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+  EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+  ASSERT_TRUE(visitor_.header_.get());
+  EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+  EXPECT_EQ(0u, visitor_.stream_frames_.size());
+  ASSERT_EQ(1u, visitor_.ack_frames_.size());
+  const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+  EXPECT_EQ(0xBA, frame.entropy_hash);
+  EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed);
+  ASSERT_EQ(1u, frame.missing_packets.size());
+  ASSERT_EQ(1u, frame.received_packet_times.size());
+  SequenceNumberSet::const_iterator missing_iter =
+      frame.missing_packets.begin();
+  EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+
+  const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+  const size_t kLargestObservedOffset = kReceivedEntropyOffset +
+      kQuicEntropyHashSize;
+  const size_t kMissingDeltaTimeOffset = kLargestObservedOffset +
+      PACKET_6BYTE_SEQUENCE_NUMBER;
+  const size_t kNumTimestampsOffset = kMissingDeltaTimeOffset +
+      kQuicDeltaTimeLargestObservedSize;
+  const size_t kTimestampDeltaLargestObserved = kNumTimestampsOffset +
+      kQuicNumTimestampsSize;
+  const size_t kTimestampTimeDeltaLargestObserved =
+    kTimestampDeltaLargestObserved + 1;
+  const size_t kNumMissingPacketOffset = kTimestampTimeDeltaLargestObserved + 4;
+  const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
+      kNumberOfNackRangesSize;
+  const size_t kMissingPacketsRange = kMissingPacketsOffset +
+      PACKET_1BYTE_SEQUENCE_NUMBER;
+  const size_t kRevivedPacketsLength = kMissingPacketsRange +
+      PACKET_1BYTE_SEQUENCE_NUMBER;
+  // Now test framing boundaries.
+  const size_t ack_frame_size = kRevivedPacketsLength +
+      PACKET_1BYTE_SEQUENCE_NUMBER;
+  for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+    string expected_error;
+    if (i < kLargestObservedOffset) {
+      expected_error = "Unable to read entropy hash for received packets.";
+    } else if (i < kMissingDeltaTimeOffset) {
+      expected_error = "Unable to read largest observed.";
+    } else if (i < kNumTimestampsOffset) {
+      expected_error = "Unable to read delta time largest observed.";
+    } else if (i < kTimestampDeltaLargestObserved) {
+      expected_error = "Unable to read num received packets.";
+    } else if (i < kTimestampTimeDeltaLargestObserved) {
+      expected_error = "Unable to read sequence delta in received packets.";
+    } else if (i < kNumMissingPacketOffset) {
+      expected_error = "Unable to read time delta in received packets.";
+    } else if (i < kMissingPacketsOffset) {
+      expected_error = "Unable to read num missing packet ranges.";
+    } else if (i < kMissingPacketsRange) {
+      expected_error = "Unable to read missing sequence number delta.";
+    } else if (i < kRevivedPacketsLength) {
+      expected_error = "Unable to read missing sequence number range.";
+    } else {
+      expected_error = "Unable to read num revived packets.";
+    }
+    CheckProcessingFails(
+        packet,
+        i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+                                PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+        expected_error, QUIC_INVALID_ACK_DATA);
+  }
+}
+
+
 TEST_P(QuicFramerTest, AckFrame) {
+  if (version_ <= QUIC_VERSION_22) {
+    return;
+  }
+  unsigned char packet[] = {
+    // public flags (8 byte connection_id)
+    0x3C,
+    // connection_id
+    0x10, 0x32, 0x54, 0x76,
+    0x98, 0xBA, 0xDC, 0xFE,
+    // packet sequence number
+    0xA8, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // private flags (entropy)
+    0x01,
+
+    // frame type (ack frame)
+    // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+    0x6C,
+    // entropy hash of all received packets.
+    0xBA,
+    // largest observed packet sequence number
+    0xBF, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // Zero delta time.
+    0x0, 0x0,
+    // Number of timestamps.
+    0x00,
+    // num missing packets
+    0x01,
+    // missing packet delta
+    0x01,
+    // 0 more missing packets in range.
+    0x00,
+    // Number of revived packets.
+    0x00,
+  };
+
+  QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+  EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+  EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+  ASSERT_TRUE(visitor_.header_.get());
+  EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+  EXPECT_EQ(0u, visitor_.stream_frames_.size());
+  ASSERT_EQ(1u, visitor_.ack_frames_.size());
+  const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+  EXPECT_EQ(0xBA, frame.entropy_hash);
+  EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed);
+  ASSERT_EQ(1u, frame.missing_packets.size());
+  SequenceNumberSet::const_iterator missing_iter =
+      frame.missing_packets.begin();
+  EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+
+  const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+  const size_t kLargestObservedOffset = kReceivedEntropyOffset +
+      kQuicEntropyHashSize;
+  const size_t kMissingDeltaTimeOffset = kLargestObservedOffset +
+      PACKET_6BYTE_SEQUENCE_NUMBER;
+  const size_t kNumTimestampsOffset = kMissingDeltaTimeOffset +
+      kQuicDeltaTimeLargestObservedSize;
+  const size_t kNumMissingPacketOffset = kNumTimestampsOffset +
+      kQuicNumTimestampsSize;
+  const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
+      kNumberOfNackRangesSize;
+  const size_t kMissingPacketsRange = kMissingPacketsOffset +
+      PACKET_1BYTE_SEQUENCE_NUMBER;
+  const size_t kRevivedPacketsLength = kMissingPacketsRange +
+      PACKET_1BYTE_SEQUENCE_NUMBER;
+  // Now test framing boundaries.
+  const size_t ack_frame_size = kRevivedPacketsLength +
+      PACKET_1BYTE_SEQUENCE_NUMBER;
+  for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+    string expected_error;
+    if (i < kLargestObservedOffset) {
+      expected_error = "Unable to read entropy hash for received packets.";
+    } else if (i < kMissingDeltaTimeOffset) {
+      expected_error = "Unable to read largest observed.";
+    } else if (i < kNumTimestampsOffset) {
+      expected_error = "Unable to read delta time largest observed.";
+    } else if (i < kNumMissingPacketOffset) {
+      expected_error = "Unable to read num received packets.";
+    } else if (i < kMissingPacketsOffset) {
+      expected_error = "Unable to read num missing packet ranges.";
+    } else if (i < kMissingPacketsRange) {
+      expected_error = "Unable to read missing sequence number delta.";
+    } else if (i < kRevivedPacketsLength) {
+      expected_error = "Unable to read missing sequence number range.";
+    } else {
+      expected_error = "Unable to read num revived packets.";
+    }
+    CheckProcessingFails(
+        packet,
+        i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+                                PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+        expected_error, QUIC_INVALID_ACK_DATA);
+  }
+}
+
+TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
+  if (version_ <= QUIC_VERSION_22) {
+    return;
+  }
   unsigned char packet[] = {
     // public flags (8 byte connection_id)
     0x3C,
@@ -1705,6 +2143,8 @@ TEST_P(QuicFramerTest, AckFrame) {
     0x34, 0x12,
     // Zero delta time.
     0x0, 0x0,
+    // num received packets.
+    0x00,
     // num missing packets
     0x01,
     // missing packet delta
@@ -1712,6 +2152,11 @@ TEST_P(QuicFramerTest, AckFrame) {
     // 0 more missing packets in range.
     0x00,
     // Number of revived packets.
+    0x01,
+    // Revived packet sequence number.
+    0xBE, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // Number of revived packets.
     0x00,
   };
 
@@ -1737,33 +2182,43 @@ TEST_P(QuicFramerTest, AckFrame) {
       kQuicEntropyHashSize;
   const size_t kMissingDeltaTimeOffset = kLargestObservedOffset +
       PACKET_6BYTE_SEQUENCE_NUMBER;
-  const size_t kNumMissingPacketOffset = kMissingDeltaTimeOffset +
+  const size_t kNumTimestampsOffset = kMissingDeltaTimeOffset +
       kQuicDeltaTimeLargestObservedSize;
+  const size_t kNumMissingPacketOffset = kNumTimestampsOffset +
+      kQuicNumTimestampsSize;
   const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
       kNumberOfNackRangesSize;
   const size_t kMissingPacketsRange = kMissingPacketsOffset +
       PACKET_1BYTE_SEQUENCE_NUMBER;
   const size_t kRevivedPacketsLength = kMissingPacketsRange +
       PACKET_1BYTE_SEQUENCE_NUMBER;
-  // Now test framing boundaries
-  const size_t ack_frame_size = kRevivedPacketsLength +
+  const size_t kRevivedPacketSequenceNumberLength = kRevivedPacketsLength +
       PACKET_1BYTE_SEQUENCE_NUMBER;
+  // Now test framing boundaries.
+  const size_t ack_frame_size = kRevivedPacketSequenceNumberLength +
+      PACKET_6BYTE_SEQUENCE_NUMBER;
   for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
     string expected_error;
-    if (i < kLargestObservedOffset) {
+    if (i < kReceivedEntropyOffset) {
+      expected_error = "Unable to read least unacked delta.";
+    } else if (i < kLargestObservedOffset) {
       expected_error = "Unable to read entropy hash for received packets.";
     } else if (i < kMissingDeltaTimeOffset) {
       expected_error = "Unable to read largest observed.";
-    } else if (i < kNumMissingPacketOffset) {
+    } else if (i < kNumTimestampsOffset) {
       expected_error = "Unable to read delta time largest observed.";
+    } else if (i < kNumMissingPacketOffset) {
+      expected_error = "Unable to read num received packets.";
     } else if (i < kMissingPacketsOffset) {
       expected_error = "Unable to read num missing packet ranges.";
     } else if (i < kMissingPacketsRange) {
       expected_error = "Unable to read missing sequence number delta.";
     } else if (i < kRevivedPacketsLength) {
       expected_error = "Unable to read missing sequence number range.";
-    } else {
+    } else if (i < kRevivedPacketSequenceNumberLength) {
       expected_error = "Unable to read num revived packets.";
+    } else {
+      expected_error = "Unable to read revived packet.";
     }
     CheckProcessingFails(
         packet,
@@ -1773,7 +2228,10 @@ TEST_P(QuicFramerTest, AckFrame) {
   }
 }
 
-TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
+TEST_P(QuicFramerTest, AckFrameRevivedPacketsv22) {
+  if (version_ > QUIC_VERSION_22) {
+    return;
+  }
   unsigned char packet[] = {
     // public flags (8 byte connection_id)
     0x3C,
@@ -1807,6 +2265,8 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
     // Revived packet sequence number.
     0xBE, 0x9A, 0x78, 0x56,
     0x34, 0x12,
+    // Number of revived packets.
+    0x00,
   };
 
   QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
@@ -1841,7 +2301,7 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
       PACKET_1BYTE_SEQUENCE_NUMBER;
   const size_t kRevivedPacketSequenceNumberLength = kRevivedPacketsLength +
       PACKET_1BYTE_SEQUENCE_NUMBER;
-  // Now test framing boundaries
+  // Now test framing boundaries.
   const size_t ack_frame_size = kRevivedPacketSequenceNumberLength +
       PACKET_6BYTE_SEQUENCE_NUMBER;
   for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
@@ -1873,7 +2333,63 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
   }
 }
 
+TEST_P(QuicFramerTest, AckFrameNoNacksv22) {
+  if (version_ > QUIC_VERSION_22) {
+    return;
+  }
+  unsigned char packet[] = {
+    // public flags (8 byte connection_id)
+    0x3C,
+    // connection_id
+    0x10, 0x32, 0x54, 0x76,
+    0x98, 0xBA, 0xDC, 0xFE,
+    // packet sequence number
+    0xA8, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // private flags (entropy)
+    0x01,
+
+    // frame type (ack frame)
+    // (no nacks, not truncated, 6 byte largest observed, 1 byte delta)
+    0x4C,
+    // entropy hash of all received packets.
+    0xBA,
+    // largest observed packet sequence number
+    0xBF, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // Zero delta time.
+    0x0, 0x0,
+  };
+
+  QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+  EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+  EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+  ASSERT_TRUE(visitor_.header_.get());
+  EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+  EXPECT_EQ(0u, visitor_.stream_frames_.size());
+  ASSERT_EQ(1u, visitor_.ack_frames_.size());
+  QuicAckFrame* frame = visitor_.ack_frames_[0];
+  EXPECT_EQ(0xBA, frame->entropy_hash);
+  EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame->largest_observed);
+  ASSERT_EQ(0u, frame->missing_packets.size());
+
+  // Verify that the packet re-serializes identically.
+  QuicFrames frames;
+  frames.push_back(QuicFrame(frame));
+  scoped_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
+  ASSERT_TRUE(data != NULL);
+
+  test::CompareCharArraysWithHexError("constructed packet",
+                                      data->data(), data->length(),
+                                      AsChars(packet), arraysize(packet));
+}
+
 TEST_P(QuicFramerTest, AckFrameNoNacks) {
+  if (version_ <= QUIC_VERSION_22) {
+    return;
+  }
   unsigned char packet[] = {
     // public flags (8 byte connection_id)
     0x3C,
@@ -1896,6 +2412,8 @@ TEST_P(QuicFramerTest, AckFrameNoNacks) {
     0x34, 0x12,
     // Zero delta time.
     0x0, 0x0,
+    // Number of received packets.
+    0x00,
   };
 
   QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
@@ -1923,7 +2441,83 @@ TEST_P(QuicFramerTest, AckFrameNoNacks) {
                                       AsChars(packet), arraysize(packet));
 }
 
+TEST_P(QuicFramerTest, AckFrame500Nacksv22) {
+  if (version_ > QUIC_VERSION_22) {
+    return;
+  }
+  unsigned char packet[] = {
+    // public flags (8 byte connection_id)
+    0x3C,
+    // connection_id
+    0x10, 0x32, 0x54, 0x76,
+    0x98, 0xBA, 0xDC, 0xFE,
+    // packet sequence number
+    0xA8, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // private flags (entropy)
+    0x01,
+
+    // frame type (ack frame)
+    // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+    0x6C,
+    // entropy hash of all received packets.
+    0xBA,
+    // largest observed packet sequence number
+    0xBF, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // Zero delta time.
+    0x0, 0x0,
+    // num missing packet ranges
+    0x02,
+    // missing packet delta
+    0x01,
+    // 243 more missing packets in range.
+    // The ranges are listed in this order so the re-constructed packet matches.
+    0xF3,
+    // No gap between ranges
+    0x00,
+    // 255 more missing packets in range.
+    0xFF,
+    // No revived packets.
+    0x00,
+  };
+
+  QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+  EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+  EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+  ASSERT_TRUE(visitor_.header_.get());
+  EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+  EXPECT_EQ(0u, visitor_.stream_frames_.size());
+  ASSERT_EQ(1u, visitor_.ack_frames_.size());
+  QuicAckFrame* frame = visitor_.ack_frames_[0];
+  EXPECT_EQ(0xBA, frame->entropy_hash);
+  EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame->largest_observed);
+  EXPECT_EQ(0u, frame->revived_packets.size());
+  ASSERT_EQ(500u, frame->missing_packets.size());
+  SequenceNumberSet::const_iterator first_missing_iter =
+      frame->missing_packets.begin();
+  EXPECT_EQ(GG_UINT64_C(0x0123456789ABE) - 499, *first_missing_iter);
+  SequenceNumberSet::const_reverse_iterator last_missing_iter =
+      frame->missing_packets.rbegin();
+  EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *last_missing_iter);
+
+  // Verify that the packet re-serializes identically.
+  QuicFrames frames;
+  frames.push_back(QuicFrame(frame));
+  scoped_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
+  ASSERT_TRUE(data != NULL);
+
+  test::CompareCharArraysWithHexError("constructed packet",
+                                      data->data(), data->length(),
+                                      AsChars(packet), arraysize(packet));
+}
+
 TEST_P(QuicFramerTest, AckFrame500Nacks) {
+  if (version_ <= QUIC_VERSION_22) {
+    return;
+  }
   unsigned char packet[] = {
     // public flags (8 byte connection_id)
     0x3C,
@@ -1946,6 +2540,8 @@ TEST_P(QuicFramerTest, AckFrame500Nacks) {
     0x34, 0x12,
     // Zero delta time.
     0x0, 0x0,
+    // No received packets.
+    0x00,
     // num missing packet ranges
     0x02,
     // missing packet delta
@@ -2028,7 +2624,7 @@ TEST_P(QuicFramerTest, CongestionFeedbackFrameTCP) {
   ASSERT_EQ(kTCP, frame.type);
   EXPECT_EQ(0x4030u, frame.tcp.receive_window);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = kQuicFrameTypeSize; i < 4; ++i) {
     string expected_error;
     if (i < 2) {
@@ -2170,7 +2766,7 @@ TEST_P(QuicFramerTest, RstStreamFrameQuic) {
   EXPECT_EQ(GG_UINT64_C(0x0807060504030201),
             visitor_.rst_stream_frame_.byte_offset);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = kQuicFrameTypeSize;
        i < QuicFramer::GetMinRstStreamFrameSize(); ++i) {
     string expected_error;
@@ -2234,7 +2830,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) {
 
   ASSERT_EQ(0u, visitor_.ack_frames_.size());
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = kQuicFrameTypeSize;
        i < QuicFramer::GetMinConnectionCloseFrameSize(); ++i) {
     string expected_error;
@@ -2292,7 +2888,7 @@ TEST_P(QuicFramerTest, GoAwayFrame) {
   EXPECT_EQ("because I can", visitor_.goaway_frame_.reason_phrase);
 
   const size_t reason_size = arraysize("because I can") - 1;
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = kQuicFrameTypeSize;
        i < QuicFramer::GetMinGoAwayFrameSize() + reason_size; ++i) {
     string expected_error;
@@ -2347,7 +2943,7 @@ TEST_P(QuicFramerTest, WindowUpdateFrame) {
   EXPECT_EQ(GG_UINT64_C(0x0c0b0a0908070605),
             visitor_.window_update_frame_.byte_offset);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = kQuicFrameTypeSize;
        i < QuicFramer::GetWindowUpdateFrameSize(); ++i) {
     string expected_error;
@@ -2394,7 +2990,7 @@ TEST_P(QuicFramerTest, BlockedFrame) {
   EXPECT_EQ(GG_UINT64_C(0x01020304),
             visitor_.blocked_frame_.stream_id);
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetBlockedFrameSize();
        ++i) {
     string expected_error = "Unable to read stream_id.";
@@ -2481,7 +3077,7 @@ TEST_P(QuicFramerTest, PublicResetPacket) {
   EXPECT_TRUE(
       visitor_.public_reset_packet_->client_address.address().empty());
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = 0; i < arraysize(packet); ++i) {
     string expected_error;
     DVLOG(1) << "iteration: " << i;
@@ -2587,7 +3183,7 @@ TEST_P(QuicFramerTest, PublicResetPacketWithClientAddress) {
                 client_address.address()));
   EXPECT_EQ(443, visitor_.public_reset_packet_->client_address.port());
 
-  // Now test framing boundaries
+  // Now test framing boundaries.
   for (size_t i = 0; i < arraysize(packet); ++i) {
     string expected_error;
     DVLOG(1) << "iteration: " << i;
@@ -3042,10 +3638,73 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
     'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
   };
 
-  QuicVersionVector versions;
-  versions.push_back(GetParam());
-  scoped_ptr<QuicEncryptedPacket> data(
-      framer_.BuildVersionNegotiationPacket(header, versions));
+  QuicVersionVector versions;
+  versions.push_back(GetParam());
+  scoped_ptr<QuicEncryptedPacket> data(
+      framer_.BuildVersionNegotiationPacket(header, versions));
+
+  test::CompareCharArraysWithHexError("constructed packet",
+                                      data->data(), data->length(),
+                                      AsChars(packet), arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, BuildAckFramePacketv22) {
+  if (version_ > QUIC_VERSION_22) {
+    return;
+  }
+  QuicPacketHeader header;
+  header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+  header.public_header.reset_flag = false;
+  header.public_header.version_flag = false;
+  header.fec_flag = false;
+  header.entropy_flag = true;
+  header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8);
+  header.fec_group = 0;
+
+  QuicAckFrame ack_frame;
+  ack_frame.entropy_hash = 0x43;
+  ack_frame.largest_observed = GG_UINT64_C(0x770123456789ABF);
+  ack_frame.delta_time_largest_observed = QuicTime::Delta::Zero();
+  ack_frame.missing_packets.insert(
+      GG_UINT64_C(0x770123456789ABE));
+
+  QuicFrames frames;
+  frames.push_back(QuicFrame(&ack_frame));
+
+  unsigned char packet[] = {
+    // public flags (8 byte connection_id)
+    0x3C,
+    // connection_id
+    0x10, 0x32, 0x54, 0x76,
+    0x98, 0xBA, 0xDC, 0xFE,
+    // packet sequence number
+    0xA8, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // private flags (entropy)
+    0x01,
+
+    // frame type (ack frame)
+    // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+    0x6C,
+    // entropy hash of all received packets.
+    0x43,
+    // largest observed packet sequence number
+    0xBF, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // Zero delta time.
+    0x0, 0x0,
+    // num missing packet ranges
+    0x01,
+    // missing packet delta
+    0x01,
+    // 0 more missing packets in range.
+    0x00,
+    // 0 revived packets.
+    0x00,
+  };
+
+  scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+  ASSERT_TRUE(data != NULL);
 
   test::CompareCharArraysWithHexError("constructed packet",
                                       data->data(), data->length(),
@@ -3053,6 +3712,9 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
 }
 
 TEST_P(QuicFramerTest, BuildAckFramePacket) {
+  if (version_ <= QUIC_VERSION_22) {
+    return;
+  }
   QuicPacketHeader header;
   header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -3094,6 +3756,8 @@ TEST_P(QuicFramerTest, BuildAckFramePacket) {
     0x34, 0x12,
     // Zero delta time.
     0x0, 0x0,
+    // num received packets.
+    0x00,
     // num missing packet ranges
     0x01,
     // missing packet delta
@@ -3114,7 +3778,126 @@ TEST_P(QuicFramerTest, BuildAckFramePacket) {
 
 // TODO(jri): Add test for tuncated packets in which the original ack frame had
 // revived packets. (In both the large and small packet cases below).
+
+TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacketv22) {
+  if (version_ > QUIC_VERSION_22) {
+    return;
+  }
+  QuicPacketHeader header;
+  header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+  header.public_header.reset_flag = false;
+  header.public_header.version_flag = false;
+  header.fec_flag = false;
+  header.entropy_flag = true;
+  header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8);
+  header.fec_group = 0;
+
+  QuicAckFrame ack_frame;
+  // This entropy hash is different from what shows up in the packet below,
+  // since entropy is recomputed by the framer on ack truncation (by
+  // TestEntropyCalculator for this test.)
+  ack_frame.entropy_hash = 0x43;
+  ack_frame.largest_observed = 2 * 300;
+  ack_frame.delta_time_largest_observed = QuicTime::Delta::Zero();
+  for (size_t i = 1; i < 2 * 300; i += 2) {
+    ack_frame.missing_packets.insert(i);
+  }
+
+  QuicFrames frames;
+  frames.push_back(QuicFrame(&ack_frame));
+
+  unsigned char packet[] = {
+    // public flags (8 byte connection_id)
+    0x3C,
+    // connection_id
+    0x10, 0x32, 0x54, 0x76,
+    0x98, 0xBA, 0xDC, 0xFE,
+    // packet sequence number
+    0xA8, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // private flags (entropy)
+    0x01,
+
+    // frame type (ack frame)
+    // (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
+    0x74,
+    // entropy hash of all received packets, set to 1 by TestEntropyCalculator
+    // since ack is truncated.
+    0x01,
+    // 2-byte largest observed packet sequence number.
+    // Expected to be 510 (0x1FE), since only 255 nack ranges can fit.
+    0xFE, 0x01,
+    // Zero delta time.
+    0x0, 0x0,
+    // num missing packet ranges (limited to 255 by size of this field).
+    0xFF,
+    // {missing packet delta, further missing packets in range}
+    // 6 nack ranges x 42 + 3 nack ranges
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+    // 0 revived packets.
+    0x00,
+  };
+
+  scoped_ptr<QuicPacket> data(
+      framer_.BuildDataPacket(header, frames, kMaxPacketSize).packet);
+  ASSERT_TRUE(data != NULL);
+
+  test::CompareCharArraysWithHexError("constructed packet",
+                                      data->data(), data->length(),
+                                      AsChars(packet), arraysize(packet));
+}
+
 TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacket) {
+  if (version_ <= QUIC_VERSION_22) {
+    return;
+  }
   QuicPacketHeader header;
   header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -3227,7 +4010,79 @@ TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacket) {
 }
 
 
+TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacketv22) {
+  if (version_ > QUIC_VERSION_22) {
+    return;
+  }
+  QuicPacketHeader header;
+  header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+  header.public_header.reset_flag = false;
+  header.public_header.version_flag = false;
+  header.fec_flag = false;
+  header.entropy_flag = true;
+  header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8);
+  header.fec_group = 0;
+
+  QuicAckFrame ack_frame;
+  // This entropy hash is different from what shows up in the packet below,
+  // since entropy is recomputed by the framer on ack truncation (by
+  // TestEntropyCalculator for this test.)
+  ack_frame.entropy_hash = 0x43;
+  ack_frame.largest_observed = 2 * 300;
+  ack_frame.delta_time_largest_observed = QuicTime::Delta::Zero();
+  for (size_t i = 1; i < 2 * 300; i += 2) {
+    ack_frame.missing_packets.insert(i);
+  }
+
+  QuicFrames frames;
+  frames.push_back(QuicFrame(&ack_frame));
+
+  unsigned char packet[] = {
+    // public flags (8 byte connection_id)
+    0x3C,
+    // connection_id
+    0x10, 0x32, 0x54, 0x76,
+    0x98, 0xBA, 0xDC, 0xFE,
+    // packet sequence number
+    0xA8, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // private flags (entropy)
+    0x01,
+
+    // frame type (ack frame)
+    // (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
+    0x74,
+    // entropy hash of all received packets, set to 1 by TestEntropyCalculator
+    // since ack is truncated.
+    0x01,
+    // 2-byte largest observed packet sequence number.
+    // Expected to be 12 (0x0C), since only 6 nack ranges can fit.
+    0x0C, 0x00,
+    // Zero delta time.
+    0x0, 0x0,
+    // num missing packet ranges (limited to 6 by packet size of 37).
+    0x06,
+    // {missing packet delta, further missing packets in range}
+    // 6 nack ranges
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    // 0 revived packets.
+    0x00,
+  };
+
+  scoped_ptr<QuicPacket> data(
+      framer_.BuildDataPacket(header, frames, 37u).packet);
+  ASSERT_TRUE(data != NULL);
+  // Expect 1 byte unused since at least 2 bytes are needed to fit more nacks.
+  EXPECT_EQ(36u, data->length());
+  test::CompareCharArraysWithHexError("constructed packet",
+                                      data->data(), data->length(),
+                                      AsChars(packet), arraysize(packet));
+}
+
 TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacket) {
+  if (version_ <= QUIC_VERSION_22) {
+    return;
+  }
   QuicPacketHeader header;
   header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -3396,7 +4251,7 @@ TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketInvalidFeedback) {
 
   QuicCongestionFeedbackFrame congestion_feedback_frame;
   congestion_feedback_frame.type =
-      static_cast<CongestionFeedbackType>(kTimestamp + 1);
+      static_cast<CongestionFeedbackType>(kTCP + 1);
 
   QuicFrames frames;
   frames.push_back(QuicFrame(&congestion_feedback_frame));
@@ -3953,7 +4808,54 @@ TEST_P(QuicFramerTest, AckTruncationLargePacket) {
   EXPECT_EQ(509u, *last_missing_iter);
 }
 
+TEST_P(QuicFramerTest, AckTruncationSmallPacketv22) {
+  if (version_ > QUIC_VERSION_22) {
+    return;
+  }
+  QuicPacketHeader header;
+  header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+  header.public_header.reset_flag = false;
+  header.public_header.version_flag = false;
+  header.fec_flag = false;
+  header.entropy_flag = false;
+  header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+  header.fec_group = 0;
+
+  // Create a packet with just the ack.
+  QuicAckFrame ack_frame = MakeAckFrameWithNackRanges(300, 0u);
+  QuicFrame frame;
+  frame.type = ACK_FRAME;
+  frame.ack_frame = &ack_frame;
+  QuicFrames frames;
+  frames.push_back(frame);
+
+  // Build an ack packet with truncation due to limit in number of nack ranges.
+  scoped_ptr<QuicPacket> raw_ack_packet(
+      framer_.BuildDataPacket(header, frames, 500).packet);
+  ASSERT_TRUE(raw_ack_packet != NULL);
+  scoped_ptr<QuicEncryptedPacket> ack_packet(
+      framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
+                            *raw_ack_packet));
+  // Now make sure we can turn our ack packet back into an ack frame.
+  ASSERT_TRUE(framer_.ProcessPacket(*ack_packet));
+  ASSERT_EQ(1u, visitor_.ack_frames_.size());
+  QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
+  EXPECT_TRUE(processed_ack_frame.is_truncated);
+  EXPECT_EQ(476u, processed_ack_frame.largest_observed);
+  ASSERT_EQ(238u, processed_ack_frame.missing_packets.size());
+  SequenceNumberSet::const_iterator missing_iter =
+      processed_ack_frame.missing_packets.begin();
+  EXPECT_EQ(1u, *missing_iter);
+  SequenceNumberSet::const_reverse_iterator last_missing_iter =
+      processed_ack_frame.missing_packets.rbegin();
+  EXPECT_EQ(475u, *last_missing_iter);
+}
+
+
 TEST_P(QuicFramerTest, AckTruncationSmallPacket) {
+  if (version_ <= QUIC_VERSION_22) {
+    return;
+  }
   QuicPacketHeader header;
   header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;