dcsctp: Add parameters, error causes and chunks

Quite a large commit, but mostly trivial. It adds all the (in dcSCTP)
supported parameters, error causes and chunks as an object model, with
serializers and deserializers. They are verified with packet captures
where available, that have been captured with Wireshark against a
reference implementation.

This _could_ be split in parameter/ as one commit, error_cause/ in the
following, and chunk/ as the third, but as each chunk/parameter is
completely isolated from the other, reviewing it should be linear with
the number of chunks/parameters and having them in more commits wouldn't
change that, taken all those three commits into account.

Bug: webrtc:12614
Change-Id: Ie83c9a22cae6e3a39e35ef26fd532837a6387a08
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/213347
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Tommi <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33625}
diff --git a/net/dcsctp/common/internal_types.h b/net/dcsctp/common/internal_types.h
index fcb88f8..8f12d0d 100644
--- a/net/dcsctp/common/internal_types.h
+++ b/net/dcsctp/common/internal_types.h
@@ -10,6 +10,8 @@
 #ifndef NET_DCSCTP_COMMON_INTERNAL_TYPES_H_
 #define NET_DCSCTP_COMMON_INTERNAL_TYPES_H_
 
+#include <utility>
+
 #include "net/dcsctp/public/strong_alias.h"
 
 namespace dcsctp {
diff --git a/net/dcsctp/packet/BUILD.gn b/net/dcsctp/packet/BUILD.gn
index 5189f2d..5bfe74a 100644
--- a/net/dcsctp/packet/BUILD.gn
+++ b/net/dcsctp/packet/BUILD.gn
@@ -62,13 +62,152 @@
   ]
 }
 
+rtc_library("parameter") {
+  deps = [
+    ":data",
+    ":tlv_trait",
+    "../../../api:array_view",
+    "../../../rtc_base",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:rtc_base_approved",
+    "../common:math",
+    "../common:str_join",
+  ]
+  sources = [
+    "parameter/add_incoming_streams_request_parameter.cc",
+    "parameter/add_incoming_streams_request_parameter.h",
+    "parameter/add_outgoing_streams_request_parameter.cc",
+    "parameter/add_outgoing_streams_request_parameter.h",
+    "parameter/forward_tsn_supported_parameter.cc",
+    "parameter/forward_tsn_supported_parameter.h",
+    "parameter/heartbeat_info_parameter.cc",
+    "parameter/heartbeat_info_parameter.h",
+    "parameter/incoming_ssn_reset_request_parameter.cc",
+    "parameter/incoming_ssn_reset_request_parameter.h",
+    "parameter/outgoing_ssn_reset_request_parameter.cc",
+    "parameter/outgoing_ssn_reset_request_parameter.h",
+    "parameter/parameter.cc",
+    "parameter/parameter.h",
+    "parameter/reconfiguration_response_parameter.cc",
+    "parameter/reconfiguration_response_parameter.h",
+    "parameter/ssn_tsn_reset_request_parameter.cc",
+    "parameter/ssn_tsn_reset_request_parameter.h",
+    "parameter/state_cookie_parameter.cc",
+    "parameter/state_cookie_parameter.h",
+    "parameter/supported_extensions_parameter.cc",
+    "parameter/supported_extensions_parameter.h",
+  ]
+}
+
+rtc_library("error_cause") {
+  deps = [
+    ":data",
+    ":parameter",
+    ":tlv_trait",
+    "../../../api:array_view",
+    "../../../rtc_base",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:rtc_base_approved",
+    "../common:math",
+    "../common:str_join",
+  ]
+  sources = [
+    "error_cause/cookie_received_while_shutting_down_cause.cc",
+    "error_cause/cookie_received_while_shutting_down_cause.h",
+    "error_cause/error_cause.cc",
+    "error_cause/error_cause.h",
+    "error_cause/invalid_mandatory_parameter_cause.cc",
+    "error_cause/invalid_mandatory_parameter_cause.h",
+    "error_cause/invalid_stream_identifier_cause.cc",
+    "error_cause/invalid_stream_identifier_cause.h",
+    "error_cause/missing_mandatory_parameter_cause.cc",
+    "error_cause/missing_mandatory_parameter_cause.h",
+    "error_cause/no_user_data_cause.cc",
+    "error_cause/no_user_data_cause.h",
+    "error_cause/out_of_resource_error_cause.cc",
+    "error_cause/out_of_resource_error_cause.h",
+    "error_cause/protocol_violation_cause.cc",
+    "error_cause/protocol_violation_cause.h",
+    "error_cause/restart_of_an_association_with_new_address_cause.cc",
+    "error_cause/restart_of_an_association_with_new_address_cause.h",
+    "error_cause/stale_cookie_error_cause.cc",
+    "error_cause/stale_cookie_error_cause.h",
+    "error_cause/unrecognized_chunk_type_cause.cc",
+    "error_cause/unrecognized_chunk_type_cause.h",
+    "error_cause/unrecognized_parameter_cause.cc",
+    "error_cause/unrecognized_parameter_cause.h",
+    "error_cause/unresolvable_address_cause.cc",
+    "error_cause/unresolvable_address_cause.h",
+    "error_cause/user_initiated_abort_cause.cc",
+    "error_cause/user_initiated_abort_cause.h",
+  ]
+}
+
+rtc_library("chunk") {
+  deps = [
+    ":data",
+    ":error_cause",
+    ":parameter",
+    ":tlv_trait",
+    "../../../api:array_view",
+    "../../../rtc_base",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:rtc_base_approved",
+    "../common:math",
+    "../common:str_join",
+  ]
+  sources = [
+    "chunk/abort_chunk.cc",
+    "chunk/abort_chunk.h",
+    "chunk/chunk.cc",
+    "chunk/chunk.h",
+    "chunk/cookie_ack_chunk.cc",
+    "chunk/cookie_ack_chunk.h",
+    "chunk/cookie_echo_chunk.cc",
+    "chunk/cookie_echo_chunk.h",
+    "chunk/data_chunk.cc",
+    "chunk/data_chunk.h",
+    "chunk/data_common.h",
+    "chunk/error_chunk.cc",
+    "chunk/error_chunk.h",
+    "chunk/forward_tsn_chunk.cc",
+    "chunk/forward_tsn_chunk.h",
+    "chunk/forward_tsn_common.h",
+    "chunk/heartbeat_ack_chunk.cc",
+    "chunk/heartbeat_ack_chunk.h",
+    "chunk/heartbeat_request_chunk.cc",
+    "chunk/heartbeat_request_chunk.h",
+    "chunk/idata_chunk.cc",
+    "chunk/idata_chunk.h",
+    "chunk/iforward_tsn_chunk.cc",
+    "chunk/iforward_tsn_chunk.h",
+    "chunk/init_ack_chunk.cc",
+    "chunk/init_ack_chunk.h",
+    "chunk/init_chunk.cc",
+    "chunk/init_chunk.h",
+    "chunk/reconfig_chunk.cc",
+    "chunk/reconfig_chunk.h",
+    "chunk/sack_chunk.cc",
+    "chunk/sack_chunk.h",
+    "chunk/shutdown_ack_chunk.cc",
+    "chunk/shutdown_ack_chunk.h",
+    "chunk/shutdown_chunk.cc",
+    "chunk/shutdown_chunk.h",
+    "chunk/shutdown_complete_chunk.cc",
+    "chunk/shutdown_complete_chunk.h",
+  ]
+}
+
 if (rtc_include_tests) {
   rtc_library("dcsctp_packet_unittests") {
     testonly = true
 
     deps = [
       ":bounded_io",
+      ":chunk",
       ":crc32c",
+      ":error_cause",
+      ":parameter",
       ":tlv_trait",
       "../../../api:array_view",
       "../../../rtc_base:checks",
@@ -79,7 +218,46 @@
     sources = [
       "bounded_byte_reader_test.cc",
       "bounded_byte_writer_test.cc",
+      "chunk/abort_chunk_test.cc",
+      "chunk/cookie_ack_chunk_test.cc",
+      "chunk/cookie_echo_chunk_test.cc",
+      "chunk/data_chunk_test.cc",
+      "chunk/error_chunk_test.cc",
+      "chunk/forward_tsn_chunk_test.cc",
+      "chunk/heartbeat_ack_chunk_test.cc",
+      "chunk/heartbeat_request_chunk_test.cc",
+      "chunk/idata_chunk_test.cc",
+      "chunk/iforward_tsn_chunk_test.cc",
+      "chunk/init_ack_chunk_test.cc",
+      "chunk/init_chunk_test.cc",
+      "chunk/reconfig_chunk_test.cc",
+      "chunk/sack_chunk_test.cc",
+      "chunk/shutdown_ack_chunk_test.cc",
+      "chunk/shutdown_chunk_test.cc",
+      "chunk/shutdown_complete_chunk_test.cc",
       "crc32c_test.cc",
+      "error_cause/cookie_received_while_shutting_down_cause_test.cc",
+      "error_cause/invalid_mandatory_parameter_cause_test.cc",
+      "error_cause/invalid_stream_identifier_cause_test.cc",
+      "error_cause/missing_mandatory_parameter_cause_test.cc",
+      "error_cause/no_user_data_cause_test.cc",
+      "error_cause/out_of_resource_error_cause_test.cc",
+      "error_cause/protocol_violation_cause_test.cc",
+      "error_cause/restart_of_an_association_with_new_address_cause_test.cc",
+      "error_cause/stale_cookie_error_cause_test.cc",
+      "error_cause/unrecognized_chunk_type_cause_test.cc",
+      "error_cause/unrecognized_parameter_cause_test.cc",
+      "error_cause/unresolvable_address_cause_test.cc",
+      "error_cause/user_initiated_abort_cause_test.cc",
+      "parameter/add_incoming_streams_request_parameter_test.cc",
+      "parameter/forward_tsn_supported_parameter_test.cc",
+      "parameter/incoming_ssn_reset_request_parameter_test.cc",
+      "parameter/outgoing_ssn_reset_request_parameter_test.cc",
+      "parameter/parameter_test.cc",
+      "parameter/reconfiguration_response_parameter_test.cc",
+      "parameter/ssn_tsn_reset_request_parameter_test.cc",
+      "parameter/state_cookie_parameter_test.cc",
+      "parameter/supported_extensions_parameter_test.cc",
       "tlv_trait_test.cc",
     ]
   }
diff --git a/net/dcsctp/packet/chunk/abort_chunk.cc b/net/dcsctp/packet/chunk/abort_chunk.cc
new file mode 100644
index 0000000..8348eb9
--- /dev/null
+++ b/net/dcsctp/packet/chunk/abort_chunk.cc
@@ -0,0 +1,65 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/abort_chunk.h"
+
+#include <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.7
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 6    |Reserved     |T|           Length              |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  \                                                               \
+//  /                   zero or more Error Causes                   /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int AbortChunk::kType;
+
+absl::optional<AbortChunk> AbortChunk::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  absl::optional<Parameters> error_causes =
+      Parameters::Parse(reader->variable_data());
+  if (!error_causes.has_value()) {
+    return absl::nullopt;
+  }
+  uint8_t flags = reader->Load8<1>();
+  bool filled_in_verification_tag = (flags & (1 << kFlagsBitT)) == 0;
+  return AbortChunk(filled_in_verification_tag, *std::move(error_causes));
+}
+
+void AbortChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  rtc::ArrayView<const uint8_t> error_causes = error_causes_.data();
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, error_causes.size());
+  writer.Store8<1>(filled_in_verification_tag_ ? 0 : (1 << kFlagsBitT));
+  writer.CopyToVariableData(error_causes);
+}
+
+std::string AbortChunk::ToString() const {
+  return "ABORT";
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/abort_chunk.h b/net/dcsctp/packet/chunk/abort_chunk.h
new file mode 100644
index 0000000..1408a75
--- /dev/null
+++ b/net/dcsctp/packet/chunk/abort_chunk.h
@@ -0,0 +1,64 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_ABORT_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_ABORT_CHUNK_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.7
+struct AbortChunkConfig : ChunkConfig {
+  static constexpr int kType = 6;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class AbortChunk : public Chunk, public TLVTrait<AbortChunkConfig> {
+ public:
+  static constexpr int kType = AbortChunkConfig::kType;
+
+  AbortChunk(bool filled_in_verification_tag, Parameters error_causes)
+      : filled_in_verification_tag_(filled_in_verification_tag),
+        error_causes_(std::move(error_causes)) {}
+
+  AbortChunk(AbortChunk&& other) = default;
+  AbortChunk& operator=(AbortChunk&& other) = default;
+
+  static absl::optional<AbortChunk> Parse(rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  bool filled_in_verification_tag() const {
+    return filled_in_verification_tag_;
+  }
+
+  const Parameters& error_causes() const { return error_causes_; }
+
+ private:
+  static constexpr int kFlagsBitT = 0;
+  bool filled_in_verification_tag_;
+  Parameters error_causes_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_ABORT_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/abort_chunk_test.cc b/net/dcsctp/packet/chunk/abort_chunk_test.cc
new file mode 100644
index 0000000..c1f3a4d
--- /dev/null
+++ b/net/dcsctp/packet/chunk/abort_chunk_test.cc
@@ -0,0 +1,83 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/abort_chunk.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/error_cause/user_initiated_abort_cause.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(AbortChunkTest, FromCapture) {
+  /*
+  ABORT chunk
+      Chunk type: ABORT (6)
+      Chunk flags: 0x00
+      Chunk length: 8
+      User initiated ABORT cause
+  */
+
+  uint8_t data[] = {0x06, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x04};
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(AbortChunk chunk, AbortChunk::Parse(data));
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      UserInitiatedAbortCause cause,
+      chunk.error_causes().get<UserInitiatedAbortCause>());
+
+  EXPECT_EQ(cause.upper_layer_abort_reason(), "");
+}
+
+TEST(AbortChunkTest, SerializeAndDeserialize) {
+  AbortChunk chunk(/*filled_in_verification_tag=*/true,
+                   Parameters::Builder()
+                       .Add(UserInitiatedAbortCause("Close called"))
+                       .Build());
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(AbortChunk deserialized,
+                              AbortChunk::Parse(serialized));
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      UserInitiatedAbortCause cause,
+      deserialized.error_causes().get<UserInitiatedAbortCause>());
+
+  EXPECT_EQ(cause.upper_layer_abort_reason(), "Close called");
+}
+
+// Validates that AbortChunk doesn't make any alignment assumptions.
+TEST(AbortChunkTest, SerializeAndDeserializeOneChar) {
+  AbortChunk chunk(
+      /*filled_in_verification_tag=*/true,
+      Parameters::Builder().Add(UserInitiatedAbortCause("!")).Build());
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(AbortChunk deserialized,
+                              AbortChunk::Parse(serialized));
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      UserInitiatedAbortCause cause,
+      deserialized.error_causes().get<UserInitiatedAbortCause>());
+
+  EXPECT_EQ(cause.upper_layer_abort_reason(), "!");
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/chunk.cc b/net/dcsctp/packet/chunk/chunk.cc
new file mode 100644
index 0000000..832ab82
--- /dev/null
+++ b/net/dcsctp/packet/chunk/chunk.cc
@@ -0,0 +1,85 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/chunk.h"
+
+#include <cstdint>
+#include <memory>
+#include <utility>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/math.h"
+#include "net/dcsctp/packet/chunk/abort_chunk.h"
+#include "net/dcsctp/packet/chunk/cookie_ack_chunk.h"
+#include "net/dcsctp/packet/chunk/cookie_echo_chunk.h"
+#include "net/dcsctp/packet/chunk/data_chunk.h"
+#include "net/dcsctp/packet/chunk/error_chunk.h"
+#include "net/dcsctp/packet/chunk/forward_tsn_chunk.h"
+#include "net/dcsctp/packet/chunk/heartbeat_ack_chunk.h"
+#include "net/dcsctp/packet/chunk/heartbeat_request_chunk.h"
+#include "net/dcsctp/packet/chunk/idata_chunk.h"
+#include "net/dcsctp/packet/chunk/iforward_tsn_chunk.h"
+#include "net/dcsctp/packet/chunk/init_ack_chunk.h"
+#include "net/dcsctp/packet/chunk/init_chunk.h"
+#include "net/dcsctp/packet/chunk/reconfig_chunk.h"
+#include "net/dcsctp/packet/chunk/sack_chunk.h"
+#include "net/dcsctp/packet/chunk/shutdown_ack_chunk.h"
+#include "net/dcsctp/packet/chunk/shutdown_chunk.h"
+#include "net/dcsctp/packet/chunk/shutdown_complete_chunk.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+template <class Chunk>
+bool ParseAndPrint(uint8_t chunk_type,
+                   rtc::ArrayView<const uint8_t> data,
+                   rtc::StringBuilder& sb) {
+  if (chunk_type == Chunk::kType) {
+    absl::optional<Chunk> c = Chunk::Parse(data);
+    if (c.has_value()) {
+      sb << c->ToString();
+    } else {
+      sb << "Failed to parse chunk of type " << chunk_type;
+    }
+    return true;
+  }
+  return false;
+}
+
+std::string DebugConvertChunkToString(rtc::ArrayView<const uint8_t> data) {
+  rtc::StringBuilder sb;
+
+  if (data.empty()) {
+    sb << "Failed to parse chunk due to empty data";
+  } else {
+    uint8_t chunk_type = data[0];
+    if (!ParseAndPrint<DataChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<InitChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<InitAckChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<SackChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<HeartbeatRequestChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<HeartbeatAckChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<AbortChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<ErrorChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<CookieEchoChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<CookieAckChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<ShutdownChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<ShutdownAckChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<ShutdownCompleteChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<ReConfigChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<ForwardTsnChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<IDataChunk>(chunk_type, data, sb) &&
+        !ParseAndPrint<IForwardTsnChunk>(chunk_type, data, sb)) {
+      sb << "Unhandled chunk type: " << static_cast<int>(chunk_type);
+    }
+  }
+  return sb.Release();
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/chunk.h b/net/dcsctp/packet/chunk/chunk.h
new file mode 100644
index 0000000..687aa1d
--- /dev/null
+++ b/net/dcsctp/packet/chunk/chunk.h
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_CHUNK_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <cstdint>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/algorithm/container.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/data.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// Base class for all SCTP chunks
+class Chunk {
+ public:
+  Chunk() {}
+  virtual ~Chunk() = default;
+
+  // Chunks can contain data payloads that shouldn't be copied unnecessarily.
+  Chunk(Chunk&& other) = default;
+  Chunk& operator=(Chunk&& other) = default;
+  Chunk(const Chunk&) = delete;
+  Chunk& operator=(const Chunk&) = delete;
+
+  // Serializes the chunk to `out`, growing it as necessary.
+  virtual void SerializeTo(std::vector<uint8_t>& out) const = 0;
+
+  // Returns a human readable description of this chunk and its parameters.
+  virtual std::string ToString() const = 0;
+};
+
+// Introspects the chunk in `data` and returns a human readable textual
+// representation of it, to be used in debugging.
+std::string DebugConvertChunkToString(rtc::ArrayView<const uint8_t> data);
+
+struct ChunkConfig {
+  static constexpr int kTypeSizeInBytes = 1;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/cookie_ack_chunk.cc b/net/dcsctp/packet/chunk/cookie_ack_chunk.cc
new file mode 100644
index 0000000..4839969
--- /dev/null
+++ b/net/dcsctp/packet/chunk/cookie_ack_chunk.cc
@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/cookie_ack_chunk.h"
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.12
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 11   |Chunk  Flags   |     Length = 4                |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int CookieAckChunk::kType;
+
+absl::optional<CookieAckChunk> CookieAckChunk::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  if (!ParseTLV(data).has_value()) {
+    return absl::nullopt;
+  }
+  return CookieAckChunk();
+}
+
+void CookieAckChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  AllocateTLV(out);
+}
+
+std::string CookieAckChunk::ToString() const {
+  return "COOKIE-ACK";
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/cookie_ack_chunk.h b/net/dcsctp/packet/chunk/cookie_ack_chunk.h
new file mode 100644
index 0000000..f7d4a33
--- /dev/null
+++ b/net/dcsctp/packet/chunk/cookie_ack_chunk.h
@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_COOKIE_ACK_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_COOKIE_ACK_CHUNK_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.12
+struct CookieAckChunkConfig : ChunkConfig {
+  static constexpr int kType = 11;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 0;
+};
+
+class CookieAckChunk : public Chunk, public TLVTrait<CookieAckChunkConfig> {
+ public:
+  static constexpr int kType = CookieAckChunkConfig::kType;
+
+  CookieAckChunk() {}
+
+  static absl::optional<CookieAckChunk> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+};
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_COOKIE_ACK_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/cookie_ack_chunk_test.cc b/net/dcsctp/packet/chunk/cookie_ack_chunk_test.cc
new file mode 100644
index 0000000..3f560c6
--- /dev/null
+++ b/net/dcsctp/packet/chunk/cookie_ack_chunk_test.cc
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/cookie_ack_chunk.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(CookieAckChunkTest, FromCapture) {
+  /*
+  COOKIE_ACK chunk
+      Chunk type: COOKIE_ACK (11)
+      Chunk flags: 0x00
+      Chunk length: 4
+  */
+
+  uint8_t data[] = {0x0b, 0x00, 0x00, 0x04};
+
+  EXPECT_TRUE(CookieAckChunk::Parse(data).has_value());
+}
+
+TEST(CookieAckChunkTest, SerializeAndDeserialize) {
+  CookieAckChunk chunk;
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(CookieAckChunk deserialized,
+                              CookieAckChunk::Parse(serialized));
+  EXPECT_EQ(deserialized.ToString(), "COOKIE-ACK");
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/cookie_echo_chunk.cc b/net/dcsctp/packet/chunk/cookie_echo_chunk.cc
new file mode 100644
index 0000000..a01d0b1
--- /dev/null
+++ b/net/dcsctp/packet/chunk/cookie_echo_chunk.cc
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/cookie_echo_chunk.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.11
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 10   |Chunk  Flags   |         Length                |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  /                     Cookie                                    /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int CookieEchoChunk::kType;
+
+absl::optional<CookieEchoChunk> CookieEchoChunk::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  return CookieEchoChunk(reader->variable_data());
+}
+
+void CookieEchoChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, cookie_.size());
+  writer.CopyToVariableData(cookie_);
+}
+
+std::string CookieEchoChunk::ToString() const {
+  return "COOKIE-ECHO";
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/cookie_echo_chunk.h b/net/dcsctp/packet/chunk/cookie_echo_chunk.h
new file mode 100644
index 0000000..8cb8052
--- /dev/null
+++ b/net/dcsctp/packet/chunk/cookie_echo_chunk.h
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_COOKIE_ECHO_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_COOKIE_ECHO_CHUNK_H_
+#include <stddef.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.11
+struct CookieEchoChunkConfig : ChunkConfig {
+  static constexpr int kType = 10;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class CookieEchoChunk : public Chunk, public TLVTrait<CookieEchoChunkConfig> {
+ public:
+  static constexpr int kType = CookieEchoChunkConfig::kType;
+
+  explicit CookieEchoChunk(rtc::ArrayView<const uint8_t> cookie)
+      : cookie_(cookie.begin(), cookie.end()) {}
+
+  static absl::optional<CookieEchoChunk> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  rtc::ArrayView<const uint8_t> cookie() const { return cookie_; }
+
+ private:
+  std::vector<uint8_t> cookie_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_COOKIE_ECHO_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/cookie_echo_chunk_test.cc b/net/dcsctp/packet/chunk/cookie_echo_chunk_test.cc
new file mode 100644
index 0000000..d06e0a6
--- /dev/null
+++ b/net/dcsctp/packet/chunk/cookie_echo_chunk_test.cc
@@ -0,0 +1,58 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/cookie_echo_chunk.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(CookieEchoChunkTest, FromCapture) {
+  /*
+  COOKIE_ECHO chunk (Cookie length: 256 bytes)
+      Chunk type: COOKIE_ECHO (10)
+      Chunk flags: 0x00
+      Chunk length: 260
+      Cookie: 12345678
+  */
+
+  uint8_t data[] = {0x0a, 0x00, 0x00, 0x08, 0x12, 0x34, 0x56, 0x78};
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(CookieEchoChunk chunk,
+                              CookieEchoChunk::Parse(data));
+
+  EXPECT_THAT(chunk.cookie(), ElementsAre(0x12, 0x34, 0x56, 0x78));
+}
+
+TEST(CookieEchoChunkTest, SerializeAndDeserialize) {
+  uint8_t cookie[] = {1, 2, 3, 4};
+  CookieEchoChunk chunk(cookie);
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(CookieEchoChunk deserialized,
+                              CookieEchoChunk::Parse(serialized));
+
+  EXPECT_THAT(deserialized.cookie(), ElementsAre(1, 2, 3, 4));
+  EXPECT_EQ(deserialized.ToString(), "COOKIE-ECHO");
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/data_chunk.cc b/net/dcsctp/packet/chunk/data_chunk.cc
new file mode 100644
index 0000000..cf65f53
--- /dev/null
+++ b/net/dcsctp/packet/chunk/data_chunk.cc
@@ -0,0 +1,101 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/data_chunk.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/chunk/data_common.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.1
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 0    | Reserved|U|B|E|    Length                     |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                              TSN                              |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |      Stream Identifier S      |   Stream Sequence Number n    |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                  Payload Protocol Identifier                  |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  \                                                               \
+//  /                 User Data (seq n of Stream S)                 /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int DataChunk::kType;
+
+absl::optional<DataChunk> DataChunk::Parse(rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+
+  uint8_t flags = reader->Load8<1>();
+  TSN tsn(reader->Load32<4>());
+  StreamID stream_identifier(reader->Load16<8>());
+  SSN ssn(reader->Load16<10>());
+  PPID ppid(reader->Load32<12>());
+
+  Options options;
+  options.is_end = Data::IsEnd((flags & (1 << kFlagsBitEnd)) != 0);
+  options.is_beginning =
+      Data::IsBeginning((flags & (1 << kFlagsBitBeginning)) != 0);
+  options.is_unordered = IsUnordered((flags & (1 << kFlagsBitUnordered)) != 0);
+  options.immediate_ack =
+      ImmediateAckFlag((flags & (1 << kFlagsBitImmediateAck)) != 0);
+
+  return DataChunk(tsn, stream_identifier, ssn, ppid,
+                   std::vector<uint8_t>(reader->variable_data().begin(),
+                                        reader->variable_data().end()),
+                   options);
+}
+
+void DataChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, payload().size());
+
+  writer.Store8<1>(
+      (*options().is_end ? (1 << kFlagsBitEnd) : 0) |
+      (*options().is_beginning ? (1 << kFlagsBitBeginning) : 0) |
+      (*options().is_unordered ? (1 << kFlagsBitUnordered) : 0) |
+      (*options().immediate_ack ? (1 << kFlagsBitImmediateAck) : 0));
+  writer.Store32<4>(*tsn());
+  writer.Store16<8>(*stream_id());
+  writer.Store16<10>(*ssn());
+  writer.Store32<12>(*ppid());
+
+  writer.CopyToVariableData(payload());
+}
+
+std::string DataChunk::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "DATA, type=" << (options().is_unordered ? "unordered" : "ordered")
+     << "::"
+     << (*options().is_beginning && *options().is_end
+             ? "complete"
+             : *options().is_beginning ? "first"
+                                       : *options().is_end ? "last" : "middle")
+     << ", tsn=" << *tsn() << ", stream_id=" << *stream_id()
+     << ", ppid=" << *ppid() << ", length=" << payload().size();
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/data_chunk.h b/net/dcsctp/packet/chunk/data_chunk.h
new file mode 100644
index 0000000..12bb05f
--- /dev/null
+++ b/net/dcsctp/packet/chunk/data_chunk.h
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_DATA_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_DATA_CHUNK_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/chunk/data_common.h"
+#include "net/dcsctp/packet/data.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.1
+struct DataChunkConfig : ChunkConfig {
+  static constexpr int kType = 0;
+  static constexpr size_t kHeaderSize = 16;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class DataChunk : public AnyDataChunk, public TLVTrait<DataChunkConfig> {
+ public:
+  static constexpr int kType = DataChunkConfig::kType;
+
+  // Exposed to allow the retransmission queue to make room for the correct
+  // header size.
+  static constexpr size_t kHeaderSize = DataChunkConfig::kHeaderSize;
+
+  DataChunk(TSN tsn,
+            StreamID stream_id,
+            SSN ssn,
+            PPID ppid,
+            std::vector<uint8_t> payload,
+            const Options& options)
+      : AnyDataChunk(tsn,
+                     stream_id,
+                     ssn,
+                     MID(0),
+                     FSN(0),
+                     ppid,
+                     std::move(payload),
+                     options) {}
+
+  DataChunk(TSN tsn, Data&& data, bool immediate_ack)
+      : AnyDataChunk(tsn, std::move(data), immediate_ack) {}
+
+  static absl::optional<DataChunk> Parse(rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_DATA_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/data_chunk_test.cc b/net/dcsctp/packet/chunk/data_chunk_test.cc
new file mode 100644
index 0000000..6a5ca82
--- /dev/null
+++ b/net/dcsctp/packet/chunk/data_chunk_test.cc
@@ -0,0 +1,74 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/data_chunk.h"
+
+#include <cstdint>
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(DataChunkTest, FromCapture) {
+  /*
+  DATA chunk(ordered, complete segment, TSN: 1426601532, SID: 2, SSN: 1,
+    PPID: 53, payload length: 4 bytes)
+      Chunk type: DATA (0)
+      Chunk flags: 0x03
+      Chunk length: 20
+      Transmission sequence number: 1426601532
+      Stream identifier: 0x0002
+      Stream sequence number: 1
+      Payload protocol identifier: WebRTC Binary (53)
+  */
+
+  uint8_t data[] = {0x00, 0x03, 0x00, 0x14, 0x55, 0x08, 0x36, 0x3c, 0x00, 0x02,
+                    0x00, 0x01, 0x00, 0x00, 0x00, 0x35, 0x00, 0x01, 0x02, 0x03};
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(DataChunk chunk, DataChunk::Parse(data));
+  EXPECT_EQ(*chunk.tsn(), 1426601532u);
+  EXPECT_EQ(*chunk.stream_id(), 2u);
+  EXPECT_EQ(*chunk.ssn(), 1u);
+  EXPECT_EQ(*chunk.ppid(), 53u);
+  EXPECT_TRUE(*chunk.options().is_beginning);
+  EXPECT_TRUE(*chunk.options().is_end);
+  EXPECT_FALSE(*chunk.options().is_unordered);
+  EXPECT_FALSE(*chunk.options().immediate_ack);
+  EXPECT_THAT(chunk.payload(), ElementsAre(0x0, 0x1, 0x2, 0x3));
+}
+
+TEST(DataChunkTest, SerializeAndDeserialize) {
+  DataChunk chunk(TSN(123), StreamID(456), SSN(789), PPID(9090),
+                  /*payload=*/{1, 2, 3, 4, 5},
+                  /*options=*/{});
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(DataChunk deserialized,
+                              DataChunk::Parse(serialized));
+  EXPECT_EQ(*chunk.tsn(), 123u);
+  EXPECT_EQ(*chunk.stream_id(), 456u);
+  EXPECT_EQ(*chunk.ssn(), 789u);
+  EXPECT_EQ(*chunk.ppid(), 9090u);
+  EXPECT_THAT(chunk.payload(), ElementsAre(1, 2, 3, 4, 5));
+
+  EXPECT_EQ(deserialized.ToString(),
+            "DATA, type=ordered::middle, tsn=123, stream_id=456, ppid=9090, "
+            "length=5");
+}
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/data_common.h b/net/dcsctp/packet/chunk/data_common.h
new file mode 100644
index 0000000..b15a034
--- /dev/null
+++ b/net/dcsctp/packet/chunk/data_common.h
@@ -0,0 +1,97 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_DATA_COMMON_H_
+#define NET_DCSCTP_PACKET_CHUNK_DATA_COMMON_H_
+#include <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/data.h"
+
+namespace dcsctp {
+
+// Base class for DataChunk and IDataChunk
+class AnyDataChunk : public Chunk {
+ public:
+  // Represents the "immediate ack" flag on DATA/I-DATA, from RFC7053.
+  using ImmediateAckFlag = StrongAlias<class ImmediateAckFlagTag, bool>;
+
+  // Data chunk options.
+  // See https://tools.ietf.org/html/rfc4960#section-3.3.1
+  struct Options {
+    Data::IsEnd is_end = Data::IsEnd(false);
+    Data::IsBeginning is_beginning = Data::IsBeginning(false);
+    IsUnordered is_unordered = IsUnordered(false);
+    ImmediateAckFlag immediate_ack = ImmediateAckFlag(false);
+  };
+
+  TSN tsn() const { return tsn_; }
+
+  Options options() const {
+    Options options;
+    options.is_end = data_.is_end;
+    options.is_beginning = data_.is_beginning;
+    options.is_unordered = data_.is_unordered;
+    options.immediate_ack = immediate_ack_;
+    return options;
+  }
+
+  StreamID stream_id() const { return data_.stream_id; }
+  SSN ssn() const { return data_.ssn; }
+  MID message_id() const { return data_.message_id; }
+  FSN fsn() const { return data_.fsn; }
+  PPID ppid() const { return data_.ppid; }
+  rtc::ArrayView<const uint8_t> payload() const { return data_.payload; }
+
+  // Extracts the Data from the chunk, as a destructive action.
+  Data extract() && { return std::move(data_); }
+
+  AnyDataChunk(TSN tsn,
+               StreamID stream_id,
+               SSN ssn,
+               MID message_id,
+               FSN fsn,
+               PPID ppid,
+               std::vector<uint8_t> payload,
+               const Options& options)
+      : tsn_(tsn),
+        data_(stream_id,
+              ssn,
+              message_id,
+              fsn,
+              ppid,
+              std::move(payload),
+              options.is_beginning,
+              options.is_end,
+              options.is_unordered),
+        immediate_ack_(options.immediate_ack) {}
+
+  AnyDataChunk(TSN tsn, Data data, bool immediate_ack)
+      : tsn_(tsn), data_(std::move(data)), immediate_ack_(immediate_ack) {}
+
+ protected:
+  // Bits in `flags` header field.
+  static constexpr int kFlagsBitEnd = 0;
+  static constexpr int kFlagsBitBeginning = 1;
+  static constexpr int kFlagsBitUnordered = 2;
+  static constexpr int kFlagsBitImmediateAck = 3;
+
+ private:
+  TSN tsn_;
+  Data data_;
+  ImmediateAckFlag immediate_ack_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_DATA_COMMON_H_
diff --git a/net/dcsctp/packet/chunk/error_chunk.cc b/net/dcsctp/packet/chunk/error_chunk.cc
new file mode 100644
index 0000000..baac0c5
--- /dev/null
+++ b/net/dcsctp/packet/chunk/error_chunk.cc
@@ -0,0 +1,62 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/error_chunk.h"
+
+#include <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 9    | Chunk  Flags  |           Length              |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  \                                                               \
+//  /                    one or more Error Causes                   /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int ErrorChunk::kType;
+
+absl::optional<ErrorChunk> ErrorChunk::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  absl::optional<Parameters> error_causes =
+      Parameters::Parse(reader->variable_data());
+  if (!error_causes.has_value()) {
+    return absl::nullopt;
+  }
+  return ErrorChunk(*std::move(error_causes));
+}
+
+void ErrorChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  rtc::ArrayView<const uint8_t> error_causes = error_causes_.data();
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, error_causes.size());
+  writer.CopyToVariableData(error_causes);
+}
+
+std::string ErrorChunk::ToString() const {
+  return "ERROR";
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/error_chunk.h b/net/dcsctp/packet/chunk/error_chunk.h
new file mode 100644
index 0000000..96122cf
--- /dev/null
+++ b/net/dcsctp/packet/chunk/error_chunk.h
@@ -0,0 +1,57 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_ERROR_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_ERROR_CHUNK_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10
+struct ErrorChunkConfig : ChunkConfig {
+  static constexpr int kType = 9;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 4;
+};
+
+class ErrorChunk : public Chunk, public TLVTrait<ErrorChunkConfig> {
+ public:
+  static constexpr int kType = ErrorChunkConfig::kType;
+
+  explicit ErrorChunk(Parameters error_causes)
+      : error_causes_(std::move(error_causes)) {}
+
+  ErrorChunk(ErrorChunk&& other) = default;
+  ErrorChunk& operator=(ErrorChunk&& other) = default;
+
+  static absl::optional<ErrorChunk> Parse(rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  const Parameters& error_causes() const { return error_causes_; }
+
+ private:
+  Parameters error_causes_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_ERROR_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/error_chunk_test.cc b/net/dcsctp/packet/chunk/error_chunk_test.cc
new file mode 100644
index 0000000..f2b8be1
--- /dev/null
+++ b/net/dcsctp/packet/chunk/error_chunk_test.cc
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/error_chunk.h"
+
+#include <cstdint>
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(ErrorChunkTest, FromCapture) {
+  /*
+   ERROR chunk
+      Chunk type: ERROR (9)
+      Chunk flags: 0x00
+      Chunk length: 12
+      Unrecognized chunk type cause (Type: 73 (unknown))
+  */
+
+  uint8_t data[] = {0x09, 0x00, 0x00, 0x0c, 0x00, 0x06,
+                    0x00, 0x08, 0x49, 0x00, 0x00, 0x04};
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(ErrorChunk chunk, ErrorChunk::Parse(data));
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      UnrecognizedChunkTypeCause cause,
+      chunk.error_causes().get<UnrecognizedChunkTypeCause>());
+
+  EXPECT_THAT(cause.unrecognized_chunk(), ElementsAre(0x49, 0x00, 0x00, 0x04));
+}
+
+TEST(ErrorChunkTest, SerializeAndDeserialize) {
+  ErrorChunk chunk(Parameters::Builder()
+                       .Add(UnrecognizedChunkTypeCause({1, 2, 3, 4}))
+                       .Build());
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(ErrorChunk deserialized,
+                              ErrorChunk::Parse(serialized));
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      UnrecognizedChunkTypeCause cause,
+      deserialized.error_causes().get<UnrecognizedChunkTypeCause>());
+
+  EXPECT_THAT(cause.unrecognized_chunk(), ElementsAre(1, 2, 3, 4));
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/forward_tsn_chunk.cc b/net/dcsctp/packet/chunk/forward_tsn_chunk.cc
new file mode 100644
index 0000000..f015050
--- /dev/null
+++ b/net/dcsctp/packet/chunk/forward_tsn_chunk.cc
@@ -0,0 +1,92 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/forward_tsn_chunk.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/chunk/forward_tsn_common.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc3758#section-3.2
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 192  |  Flags = 0x00 |        Length = Variable      |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                      New Cumulative TSN                       |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |         Stream-1              |       Stream Sequence-1       |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  \                                                               /
+//  /                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |         Stream-N              |       Stream Sequence-N       |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int ForwardTsnChunk::kType;
+
+absl::optional<ForwardTsnChunk> ForwardTsnChunk::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  TSN new_cumulative_tsn(reader->Load32<4>());
+
+  size_t streams_skipped =
+      reader->variable_data_size() / kSkippedStreamBufferSize;
+
+  std::vector<SkippedStream> skipped_streams;
+  skipped_streams.reserve(streams_skipped);
+  for (size_t i = 0; i < streams_skipped; ++i) {
+    BoundedByteReader<kSkippedStreamBufferSize> sub_reader =
+        reader->sub_reader<kSkippedStreamBufferSize>(i *
+                                                     kSkippedStreamBufferSize);
+
+    StreamID stream_id(sub_reader.Load16<0>());
+    SSN ssn(sub_reader.Load16<2>());
+    skipped_streams.emplace_back(stream_id, ssn);
+  }
+  return ForwardTsnChunk(new_cumulative_tsn, std::move(skipped_streams));
+}
+
+void ForwardTsnChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  rtc::ArrayView<const SkippedStream> skipped = skipped_streams();
+  size_t variable_size = skipped.size() * kSkippedStreamBufferSize;
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, variable_size);
+
+  writer.Store32<4>(*new_cumulative_tsn());
+  for (size_t i = 0; i < skipped.size(); ++i) {
+    BoundedByteWriter<kSkippedStreamBufferSize> sub_writer =
+        writer.sub_writer<kSkippedStreamBufferSize>(i *
+                                                    kSkippedStreamBufferSize);
+    sub_writer.Store16<0>(*skipped[i].stream_id);
+    sub_writer.Store16<2>(*skipped[i].ssn);
+  }
+}
+
+std::string ForwardTsnChunk::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "FORWARD-TSN, new_cumulative_tsn=" << *new_cumulative_tsn();
+  return sb.str();
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/forward_tsn_chunk.h b/net/dcsctp/packet/chunk/forward_tsn_chunk.h
new file mode 100644
index 0000000..b9ef666
--- /dev/null
+++ b/net/dcsctp/packet/chunk/forward_tsn_chunk.h
@@ -0,0 +1,55 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_FORWARD_TSN_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_FORWARD_TSN_CHUNK_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/chunk/forward_tsn_common.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc3758#section-3.2
+struct ForwardTsnChunkConfig : ChunkConfig {
+  static constexpr int kType = 192;
+  static constexpr size_t kHeaderSize = 8;
+  static constexpr size_t kVariableLengthAlignment = 4;
+};
+
+class ForwardTsnChunk : public AnyForwardTsnChunk,
+                        public TLVTrait<ForwardTsnChunkConfig> {
+ public:
+  static constexpr int kType = ForwardTsnChunkConfig::kType;
+
+  ForwardTsnChunk(TSN new_cumulative_tsn,
+                  std::vector<SkippedStream> skipped_streams)
+      : AnyForwardTsnChunk(new_cumulative_tsn, std::move(skipped_streams)) {}
+
+  static absl::optional<ForwardTsnChunk> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+ private:
+  static constexpr size_t kSkippedStreamBufferSize = 4;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_FORWARD_TSN_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/forward_tsn_chunk_test.cc b/net/dcsctp/packet/chunk/forward_tsn_chunk_test.cc
new file mode 100644
index 0000000..9420c1f
--- /dev/null
+++ b/net/dcsctp/packet/chunk/forward_tsn_chunk_test.cc
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/forward_tsn_chunk.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/forward_tsn_common.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(ForwardTsnChunkTest, FromCapture) {
+  /*
+  FORWARD_TSN chunk(Cumulative TSN: 1905748778)
+      Chunk type: FORWARD_TSN (192)
+      Chunk flags: 0x00
+      Chunk length: 8
+      New cumulative TSN: 1905748778
+  */
+
+  uint8_t data[] = {0xc0, 0x00, 0x00, 0x08, 0x71, 0x97, 0x6b, 0x2a};
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(ForwardTsnChunk chunk,
+                              ForwardTsnChunk::Parse(data));
+  EXPECT_EQ(*chunk.new_cumulative_tsn(), 1905748778u);
+}
+
+TEST(ForwardTsnChunkTest, SerializeAndDeserialize) {
+  ForwardTsnChunk chunk(
+      TSN(123), {ForwardTsnChunk::SkippedStream(StreamID(1), SSN(23)),
+                 ForwardTsnChunk::SkippedStream(StreamID(42), SSN(99))});
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(ForwardTsnChunk deserialized,
+                              ForwardTsnChunk::Parse(serialized));
+  EXPECT_EQ(*deserialized.new_cumulative_tsn(), 123u);
+  EXPECT_THAT(
+      deserialized.skipped_streams(),
+      ElementsAre(ForwardTsnChunk::SkippedStream(StreamID(1), SSN(23)),
+                  ForwardTsnChunk::SkippedStream(StreamID(42), SSN(99))));
+
+  EXPECT_EQ(deserialized.ToString(), "FORWARD-TSN, new_cumulative_tsn=123");
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/forward_tsn_common.h b/net/dcsctp/packet/chunk/forward_tsn_common.h
new file mode 100644
index 0000000..37bd2aa
--- /dev/null
+++ b/net/dcsctp/packet/chunk/forward_tsn_common.h
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_FORWARD_TSN_COMMON_H_
+#define NET_DCSCTP_PACKET_CHUNK_FORWARD_TSN_COMMON_H_
+#include <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+
+namespace dcsctp {
+
+// Base class for both ForwardTsnChunk and IForwardTsnChunk
+class AnyForwardTsnChunk : public Chunk {
+ public:
+  struct SkippedStream {
+    SkippedStream(StreamID stream_id, SSN ssn)
+        : stream_id(stream_id), ssn(ssn), unordered(false), message_id(0) {}
+    SkippedStream(IsUnordered unordered, StreamID stream_id, MID message_id)
+        : stream_id(stream_id),
+          ssn(0),
+          unordered(unordered),
+          message_id(message_id) {}
+
+    StreamID stream_id;
+
+    // Set for FORWARD_TSN
+    SSN ssn;
+
+    // Set for I-FORWARD_TSN
+    IsUnordered unordered;
+    MID message_id;
+
+    bool operator==(const SkippedStream& other) const {
+      return stream_id == other.stream_id && ssn == other.ssn &&
+             unordered == other.unordered && message_id == other.message_id;
+    }
+  };
+
+  AnyForwardTsnChunk(TSN new_cumulative_tsn,
+                     std::vector<SkippedStream> skipped_streams)
+      : new_cumulative_tsn_(new_cumulative_tsn),
+        skipped_streams_(std::move(skipped_streams)) {}
+
+  TSN new_cumulative_tsn() const { return new_cumulative_tsn_; }
+
+  rtc::ArrayView<const SkippedStream> skipped_streams() const {
+    return skipped_streams_;
+  }
+
+ private:
+  TSN new_cumulative_tsn_;
+  std::vector<SkippedStream> skipped_streams_;
+};
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_FORWARD_TSN_COMMON_H_
diff --git a/net/dcsctp/packet/chunk/heartbeat_ack_chunk.cc b/net/dcsctp/packet/chunk/heartbeat_ack_chunk.cc
new file mode 100644
index 0000000..3cbcd09
--- /dev/null
+++ b/net/dcsctp/packet/chunk/heartbeat_ack_chunk.cc
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/heartbeat_ack_chunk.h"
+
+#include <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.6
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 5    | Chunk  Flags  |    Heartbeat Ack Length       |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  \                                                               \
+//  /            Heartbeat Information TLV (Variable-Length)        /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int HeartbeatAckChunk::kType;
+
+absl::optional<HeartbeatAckChunk> HeartbeatAckChunk::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+
+  absl::optional<Parameters> parameters =
+      Parameters::Parse(reader->variable_data());
+  if (!parameters.has_value()) {
+    return absl::nullopt;
+  }
+  return HeartbeatAckChunk(*std::move(parameters));
+}
+
+void HeartbeatAckChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  rtc::ArrayView<const uint8_t> parameters = parameters_.data();
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, parameters.size());
+  writer.CopyToVariableData(parameters);
+}
+
+std::string HeartbeatAckChunk::ToString() const {
+  return "HEARTBEAT-ACK";
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/heartbeat_ack_chunk.h b/net/dcsctp/packet/chunk/heartbeat_ack_chunk.h
new file mode 100644
index 0000000..a6479f7
--- /dev/null
+++ b/net/dcsctp/packet/chunk/heartbeat_ack_chunk.h
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_HEARTBEAT_ACK_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_HEARTBEAT_ACK_CHUNK_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/parameter/heartbeat_info_parameter.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.6
+struct HeartbeatAckChunkConfig : ChunkConfig {
+  static constexpr int kType = 5;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class HeartbeatAckChunk : public Chunk,
+                          public TLVTrait<HeartbeatAckChunkConfig> {
+ public:
+  static constexpr int kType = HeartbeatAckChunkConfig::kType;
+
+  explicit HeartbeatAckChunk(Parameters parameters)
+      : parameters_(std::move(parameters)) {}
+
+  HeartbeatAckChunk(HeartbeatAckChunk&& other) = default;
+  HeartbeatAckChunk& operator=(HeartbeatAckChunk&& other) = default;
+
+  static absl::optional<HeartbeatAckChunk> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  const Parameters& parameters() const { return parameters_; }
+
+  absl::optional<HeartbeatInfoParameter> info() const {
+    return parameters_.get<HeartbeatInfoParameter>();
+  }
+
+ private:
+  Parameters parameters_;
+};
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_HEARTBEAT_ACK_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/heartbeat_ack_chunk_test.cc b/net/dcsctp/packet/chunk/heartbeat_ack_chunk_test.cc
new file mode 100644
index 0000000..e4d0dd1
--- /dev/null
+++ b/net/dcsctp/packet/chunk/heartbeat_ack_chunk_test.cc
@@ -0,0 +1,79 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/heartbeat_ack_chunk.h"
+
+#include <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/packet/parameter/heartbeat_info_parameter.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(HeartbeatAckChunkTest, FromCapture) {
+  /*
+  HEARTBEAT_ACK chunk (Information: 40 bytes)
+      Chunk type: HEARTBEAT_ACK (5)
+      Chunk flags: 0x00
+      Chunk length: 44
+      Heartbeat info parameter (Information: 36 bytes)
+          Parameter type: Heartbeat info (0x0001)
+          Parameter length: 40
+          Heartbeat information: ad2436603726070000000000000000007b1000000100…
+  */
+
+  uint8_t data[] = {0x05, 0x00, 0x00, 0x2c, 0x00, 0x01, 0x00, 0x28, 0xad,
+                    0x24, 0x36, 0x60, 0x37, 0x26, 0x07, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x10, 0x00,
+                    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(HeartbeatAckChunk chunk,
+                              HeartbeatAckChunk::Parse(data));
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(HeartbeatInfoParameter info, chunk.info());
+
+  EXPECT_THAT(
+      info.info(),
+      ElementsAre(0xad, 0x24, 0x36, 0x60, 0x37, 0x26, 0x07, 0x00, 0x00, 0x00,
+                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x10, 0x00, 0x00,
+                  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
+}
+
+TEST(HeartbeatAckChunkTest, SerializeAndDeserialize) {
+  uint8_t info_data[] = {1, 2, 3, 4};
+  Parameters parameters =
+      Parameters::Builder().Add(HeartbeatInfoParameter(info_data)).Build();
+  HeartbeatAckChunk chunk(std::move(parameters));
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(HeartbeatAckChunk deserialized,
+                              HeartbeatAckChunk::Parse(serialized));
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(HeartbeatInfoParameter info, deserialized.info());
+
+  EXPECT_THAT(info.info(), ElementsAre(1, 2, 3, 4));
+
+  EXPECT_EQ(deserialized.ToString(), "HEARTBEAT-ACK");
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/heartbeat_request_chunk.cc b/net/dcsctp/packet/chunk/heartbeat_request_chunk.cc
new file mode 100644
index 0000000..d759d6b
--- /dev/null
+++ b/net/dcsctp/packet/chunk/heartbeat_request_chunk.cc
@@ -0,0 +1,64 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/heartbeat_request_chunk.h"
+
+#include <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.5
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 4    | Chunk  Flags  |      Heartbeat Length         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  \                                                               \
+//  /            Heartbeat Information TLV (Variable-Length)        /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int HeartbeatRequestChunk::kType;
+
+absl::optional<HeartbeatRequestChunk> HeartbeatRequestChunk::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+
+  absl::optional<Parameters> parameters =
+      Parameters::Parse(reader->variable_data());
+  if (!parameters.has_value()) {
+    return absl::nullopt;
+  }
+  return HeartbeatRequestChunk(*std::move(parameters));
+}
+
+void HeartbeatRequestChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  rtc::ArrayView<const uint8_t> parameters = parameters_.data();
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, parameters.size());
+  writer.CopyToVariableData(parameters);
+}
+
+std::string HeartbeatRequestChunk::ToString() const {
+  return "HEARTBEAT";
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/heartbeat_request_chunk.h b/net/dcsctp/packet/chunk/heartbeat_request_chunk.h
new file mode 100644
index 0000000..fe2ce19
--- /dev/null
+++ b/net/dcsctp/packet/chunk/heartbeat_request_chunk.h
@@ -0,0 +1,62 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_HEARTBEAT_REQUEST_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_HEARTBEAT_REQUEST_CHUNK_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/parameter/heartbeat_info_parameter.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+// https://tools.ietf.org/html/rfc4960#section-3.3.5
+struct HeartbeatRequestChunkConfig : ChunkConfig {
+  static constexpr int kType = 4;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class HeartbeatRequestChunk : public Chunk,
+                              public TLVTrait<HeartbeatRequestChunkConfig> {
+ public:
+  static constexpr int kType = HeartbeatRequestChunkConfig::kType;
+
+  explicit HeartbeatRequestChunk(Parameters parameters)
+      : parameters_(std::move(parameters)) {}
+
+  HeartbeatRequestChunk(HeartbeatRequestChunk&& other) = default;
+  HeartbeatRequestChunk& operator=(HeartbeatRequestChunk&& other) = default;
+
+  static absl::optional<HeartbeatRequestChunk> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  const Parameters& parameters() const { return parameters_; }
+  Parameters extract_parameters() && { return std::move(parameters_); }
+  absl::optional<HeartbeatInfoParameter> info() const {
+    return parameters_.get<HeartbeatInfoParameter>();
+  }
+
+ private:
+  Parameters parameters_;
+};
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_HEARTBEAT_REQUEST_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/heartbeat_request_chunk_test.cc b/net/dcsctp/packet/chunk/heartbeat_request_chunk_test.cc
new file mode 100644
index 0000000..94911fe
--- /dev/null
+++ b/net/dcsctp/packet/chunk/heartbeat_request_chunk_test.cc
@@ -0,0 +1,79 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/heartbeat_request_chunk.h"
+
+#include <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/packet/parameter/heartbeat_info_parameter.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(HeartbeatRequestChunkTest, FromCapture) {
+  /*
+  HEARTBEAT chunk (Information: 40 bytes)
+      Chunk type: HEARTBEAT (4)
+      Chunk flags: 0x00
+      Chunk length: 44
+      Heartbeat info parameter (Information: 36 bytes)
+          Parameter type: Heartbeat info (0x0001)
+          Parameter length: 40
+          Heartbeat information: ad2436603726070000000000000000007b10000001…
+  */
+
+  uint8_t data[] = {0x04, 0x00, 0x00, 0x2c, 0x00, 0x01, 0x00, 0x28, 0xad,
+                    0x24, 0x36, 0x60, 0x37, 0x26, 0x07, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x10, 0x00,
+                    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(HeartbeatRequestChunk chunk,
+                              HeartbeatRequestChunk::Parse(data));
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(HeartbeatInfoParameter info, chunk.info());
+
+  EXPECT_THAT(
+      info.info(),
+      ElementsAre(0xad, 0x24, 0x36, 0x60, 0x37, 0x26, 0x07, 0x00, 0x00, 0x00,
+                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x10, 0x00, 0x00,
+                  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
+}
+
+TEST(HeartbeatRequestChunkTest, SerializeAndDeserialize) {
+  uint8_t info_data[] = {1, 2, 3, 4};
+  Parameters parameters =
+      Parameters::Builder().Add(HeartbeatInfoParameter(info_data)).Build();
+  HeartbeatRequestChunk chunk(std::move(parameters));
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(HeartbeatRequestChunk deserialized,
+                              HeartbeatRequestChunk::Parse(serialized));
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(HeartbeatInfoParameter info, deserialized.info());
+
+  EXPECT_THAT(info.info(), ElementsAre(1, 2, 3, 4));
+
+  EXPECT_EQ(deserialized.ToString(), "HEARTBEAT");
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/idata_chunk.cc b/net/dcsctp/packet/chunk/idata_chunk.cc
new file mode 100644
index 0000000..378c527
--- /dev/null
+++ b/net/dcsctp/packet/chunk/idata_chunk.cc
@@ -0,0 +1,111 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/idata_chunk.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/chunk/data_common.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc8260#section-2.1
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 64   |  Res  |I|U|B|E|       Length = Variable       |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                              TSN                              |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |        Stream Identifier      |           Reserved            |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                      Message Identifier                       |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |    Payload Protocol Identifier / Fragment Sequence Number     |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  \                                                               \
+//  /                           User Data                           /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int IDataChunk::kType;
+
+absl::optional<IDataChunk> IDataChunk::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  uint8_t flags = reader->Load8<1>();
+  TSN tsn(reader->Load32<4>());
+  StreamID stream_identifier(reader->Load16<8>());
+  MID message_id(reader->Load32<12>());
+  uint32_t ppid_or_fsn = reader->Load32<16>();
+
+  Options options;
+  options.is_end = Data::IsEnd((flags & (1 << kFlagsBitEnd)) != 0);
+  options.is_beginning =
+      Data::IsBeginning((flags & (1 << kFlagsBitBeginning)) != 0);
+  options.is_unordered = IsUnordered((flags & (1 << kFlagsBitUnordered)) != 0);
+  options.immediate_ack =
+      ImmediateAckFlag((flags & (1 << kFlagsBitImmediateAck)) != 0);
+
+  return IDataChunk(tsn, stream_identifier, message_id,
+                    PPID(options.is_beginning ? ppid_or_fsn : 0),
+                    FSN(options.is_beginning ? 0 : ppid_or_fsn),
+                    std::vector<uint8_t>(reader->variable_data().begin(),
+                                         reader->variable_data().end()),
+                    options);
+}
+
+void IDataChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, payload().size());
+
+  writer.Store8<1>(
+      (*options().is_end ? (1 << kFlagsBitEnd) : 0) |
+      (*options().is_beginning ? (1 << kFlagsBitBeginning) : 0) |
+      (*options().is_unordered ? (1 << kFlagsBitUnordered) : 0) |
+      (*options().immediate_ack ? (1 << kFlagsBitImmediateAck) : 0));
+  writer.Store32<4>(*tsn());
+  writer.Store16<8>(*stream_id());
+  writer.Store32<12>(*message_id());
+  writer.Store32<16>(options().is_beginning ? *ppid() : *fsn());
+  writer.CopyToVariableData(payload());
+}
+
+std::string IDataChunk::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "I-DATA, type=" << (options().is_unordered ? "unordered" : "ordered")
+     << "::"
+     << (*options().is_beginning && *options().is_end
+             ? "complete"
+             : *options().is_beginning ? "first"
+                                       : *options().is_end ? "last" : "middle")
+     << ", tsn=" << *tsn() << ", stream_id=" << *stream_id()
+     << ", message_id=" << *message_id();
+
+  if (*options().is_beginning) {
+    sb << ", ppid=" << *ppid();
+  } else {
+    sb << ", fsn=" << *fsn();
+  }
+  sb << ", length=" << payload().size();
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/idata_chunk.h b/net/dcsctp/packet/chunk/idata_chunk.h
new file mode 100644
index 0000000..8cdf2a1
--- /dev/null
+++ b/net/dcsctp/packet/chunk/idata_chunk.h
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_IDATA_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_IDATA_CHUNK_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/chunk/data_common.h"
+#include "net/dcsctp/packet/data.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc8260#section-2.1
+struct IDataChunkConfig : ChunkConfig {
+  static constexpr int kType = 64;
+  static constexpr size_t kHeaderSize = 20;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class IDataChunk : public AnyDataChunk, public TLVTrait<IDataChunkConfig> {
+ public:
+  static constexpr int kType = IDataChunkConfig::kType;
+
+  // Exposed to allow the retransmission queue to make room for the correct
+  // header size.
+  static constexpr size_t kHeaderSize = IDataChunkConfig::kHeaderSize;
+  IDataChunk(TSN tsn,
+             StreamID stream_id,
+             MID message_id,
+             PPID ppid,
+             FSN fsn,
+             std::vector<uint8_t> payload,
+             const Options& options)
+      : AnyDataChunk(tsn,
+                     stream_id,
+                     SSN(0),
+                     message_id,
+                     fsn,
+                     ppid,
+                     std::move(payload),
+                     options) {}
+
+  explicit IDataChunk(TSN tsn, Data&& data, bool immediate_ack)
+      : AnyDataChunk(tsn, std::move(data), immediate_ack) {}
+
+  static absl::optional<IDataChunk> Parse(rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_IDATA_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/idata_chunk_test.cc b/net/dcsctp/packet/chunk/idata_chunk_test.cc
new file mode 100644
index 0000000..fea492d
--- /dev/null
+++ b/net/dcsctp/packet/chunk/idata_chunk_test.cc
@@ -0,0 +1,123 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/idata_chunk.h"
+
+#include <cstdint>
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(IDataChunkTest, AtBeginningFromCapture) {
+  /*
+  I_DATA chunk(ordered, first segment, TSN: 2487901653, SID: 1, MID: 0,
+    payload length: 1180 bytes)
+      Chunk type: I_DATA (64)
+      Chunk flags: 0x02
+      Chunk length: 1200
+      Transmission sequence number: 2487901653
+      Stream identifier: 0x0001
+      Reserved: 0
+      Message identifier: 0
+      Payload protocol identifier: WebRTC Binary (53)
+      Reassembled Message in frame: 39
+  */
+
+  uint8_t data[] = {0x40, 0x02, 0x00, 0x15, 0x94, 0x4a, 0x5d, 0xd5,
+                    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x35, 0x01, 0x00, 0x00, 0x00};
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(IDataChunk chunk, IDataChunk::Parse(data));
+  EXPECT_EQ(*chunk.tsn(), 2487901653);
+  EXPECT_EQ(*chunk.stream_id(), 1);
+  EXPECT_EQ(*chunk.message_id(), 0u);
+  EXPECT_EQ(*chunk.ppid(), 53u);
+  EXPECT_EQ(*chunk.fsn(), 0u);  // Not provided (so set to zero)
+}
+
+TEST(IDataChunkTest, AtBeginningSerializeAndDeserialize) {
+  IDataChunk::Options options;
+  options.is_beginning = Data::IsBeginning(true);
+  IDataChunk chunk(TSN(123), StreamID(456), MID(789), PPID(53), FSN(0), {1},
+                   options);
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(IDataChunk deserialized,
+                              IDataChunk::Parse(serialized));
+  EXPECT_EQ(*deserialized.tsn(), 123u);
+  EXPECT_EQ(*deserialized.stream_id(), 456u);
+  EXPECT_EQ(*deserialized.message_id(), 789u);
+  EXPECT_EQ(*deserialized.ppid(), 53u);
+  EXPECT_EQ(*deserialized.fsn(), 0u);
+
+  EXPECT_EQ(deserialized.ToString(),
+            "I-DATA, type=ordered::first, tsn=123, stream_id=456, "
+            "message_id=789, ppid=53, length=1");
+}
+
+TEST(IDataChunkTest, InMiddleFromCapture) {
+  /*
+  I_DATA chunk(ordered, last segment, TSN: 2487901706, SID: 3, MID: 1,
+    FSN: 8, payload length: 560 bytes)
+      Chunk type: I_DATA (64)
+      Chunk flags: 0x01
+      Chunk length: 580
+      Transmission sequence number: 2487901706
+      Stream identifier: 0x0003
+      Reserved: 0
+      Message identifier: 1
+      Fragment sequence number: 8
+      Reassembled SCTP Fragments (10000 bytes, 9 fragments):
+  */
+
+  uint8_t data[] = {0x40, 0x01, 0x00, 0x15, 0x94, 0x4a, 0x5e, 0x0a,
+                    0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+                    0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00};
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(IDataChunk chunk, IDataChunk::Parse(data));
+  EXPECT_EQ(*chunk.tsn(), 2487901706);
+  EXPECT_EQ(*chunk.stream_id(), 3u);
+  EXPECT_EQ(*chunk.message_id(), 1u);
+  EXPECT_EQ(*chunk.ppid(), 0u);  // Not provided (so set to zero)
+  EXPECT_EQ(*chunk.fsn(), 8u);
+}
+
+TEST(IDataChunkTest, InMiddleSerializeAndDeserialize) {
+  IDataChunk chunk(TSN(123), StreamID(456), MID(789), PPID(0), FSN(101112),
+                   {1, 2, 3}, /*options=*/{});
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(IDataChunk deserialized,
+                              IDataChunk::Parse(serialized));
+  EXPECT_EQ(*deserialized.tsn(), 123u);
+  EXPECT_EQ(*deserialized.stream_id(), 456u);
+  EXPECT_EQ(*deserialized.message_id(), 789u);
+  EXPECT_EQ(*deserialized.ppid(), 0u);
+  EXPECT_EQ(*deserialized.fsn(), 101112u);
+  EXPECT_THAT(deserialized.payload(), ElementsAre(1, 2, 3));
+
+  EXPECT_EQ(deserialized.ToString(),
+            "I-DATA, type=ordered::middle, tsn=123, stream_id=456, "
+            "message_id=789, fsn=101112, length=3");
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/iforward_tsn_chunk.cc b/net/dcsctp/packet/chunk/iforward_tsn_chunk.cc
new file mode 100644
index 0000000..a647a8b
--- /dev/null
+++ b/net/dcsctp/packet/chunk/iforward_tsn_chunk.cc
@@ -0,0 +1,104 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/iforward_tsn_chunk.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/chunk/forward_tsn_common.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc8260#section-2.3.1
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 194  | Flags = 0x00  |      Length = Variable        |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                       New Cumulative TSN                      |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |       Stream Identifier       |          Reserved           |U|
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                       Message Identifier                      |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  \                                                               \
+//  /                                                               /
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |       Stream Identifier       |          Reserved           |U|
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                       Message Identifier                      |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int IForwardTsnChunk::kType;
+
+absl::optional<IForwardTsnChunk> IForwardTsnChunk::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+
+  TSN new_cumulative_tsn(reader->Load32<4>());
+
+  size_t streams_skipped =
+      reader->variable_data_size() / kSkippedStreamBufferSize;
+  std::vector<SkippedStream> skipped_streams;
+  skipped_streams.reserve(streams_skipped);
+  size_t offset = 0;
+  for (size_t i = 0; i < streams_skipped; ++i) {
+    BoundedByteReader<kSkippedStreamBufferSize> sub_reader =
+        reader->sub_reader<kSkippedStreamBufferSize>(offset);
+
+    StreamID stream_id(sub_reader.Load16<0>());
+    IsUnordered unordered(sub_reader.Load8<3>() & 0x01);
+    MID message_id(sub_reader.Load32<4>());
+    skipped_streams.emplace_back(unordered, stream_id, message_id);
+    offset += kSkippedStreamBufferSize;
+  }
+  RTC_DCHECK(offset == reader->variable_data_size());
+  return IForwardTsnChunk(new_cumulative_tsn, std::move(skipped_streams));
+}
+
+void IForwardTsnChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  rtc::ArrayView<const SkippedStream> skipped = skipped_streams();
+  size_t variable_size = skipped.size() * kSkippedStreamBufferSize;
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, variable_size);
+
+  writer.Store32<4>(*new_cumulative_tsn());
+  size_t offset = 0;
+  for (size_t i = 0; i < skipped.size(); ++i) {
+    BoundedByteWriter<kSkippedStreamBufferSize> sub_writer =
+        writer.sub_writer<kSkippedStreamBufferSize>(offset);
+
+    sub_writer.Store16<0>(*skipped[i].stream_id);
+    sub_writer.Store8<3>(skipped[i].unordered ? 1 : 0);
+    sub_writer.Store32<4>(*skipped[i].message_id);
+    offset += kSkippedStreamBufferSize;
+  }
+  RTC_DCHECK(offset == variable_size);
+}
+
+std::string IForwardTsnChunk::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "I-FORWARD-TSN, new_cumulative_tsn=" << *new_cumulative_tsn();
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/iforward_tsn_chunk.h b/net/dcsctp/packet/chunk/iforward_tsn_chunk.h
new file mode 100644
index 0000000..54d23f7
--- /dev/null
+++ b/net/dcsctp/packet/chunk/iforward_tsn_chunk.h
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_IFORWARD_TSN_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_IFORWARD_TSN_CHUNK_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/chunk/forward_tsn_common.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc8260#section-2.3.1
+struct IForwardTsnChunkConfig : ChunkConfig {
+  static constexpr int kType = 194;
+  static constexpr size_t kHeaderSize = 8;
+  static constexpr size_t kVariableLengthAlignment = 8;
+};
+
+class IForwardTsnChunk : public AnyForwardTsnChunk,
+                         public TLVTrait<IForwardTsnChunkConfig> {
+ public:
+  static constexpr int kType = IForwardTsnChunkConfig::kType;
+
+  IForwardTsnChunk(TSN new_cumulative_tsn,
+                   std::vector<SkippedStream> skipped_streams)
+      : AnyForwardTsnChunk(new_cumulative_tsn, std::move(skipped_streams)) {}
+
+  static absl::optional<IForwardTsnChunk> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+ private:
+  static constexpr size_t kSkippedStreamBufferSize = 8;
+};
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_IFORWARD_TSN_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/iforward_tsn_chunk_test.cc b/net/dcsctp/packet/chunk/iforward_tsn_chunk_test.cc
new file mode 100644
index 0000000..6a89433
--- /dev/null
+++ b/net/dcsctp/packet/chunk/iforward_tsn_chunk_test.cc
@@ -0,0 +1,73 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/iforward_tsn_chunk.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/forward_tsn_common.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(IForwardTsnChunkTest, FromCapture) {
+  /*
+  I_FORWARD_TSN chunk(Cumulative TSN: 3094631148)
+      Chunk type: I_FORWARD_TSN (194)
+      Chunk flags: 0x00
+      Chunk length: 16
+      New cumulative TSN: 3094631148
+      Stream identifier: 1
+      Flags: 0x0000
+      Message identifier: 2
+  */
+
+  uint8_t data[] = {0xc2, 0x00, 0x00, 0x10, 0xb8, 0x74, 0x52, 0xec,
+                    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02};
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(IForwardTsnChunk chunk,
+                              IForwardTsnChunk::Parse(data));
+  EXPECT_EQ(*chunk.new_cumulative_tsn(), 3094631148u);
+  EXPECT_THAT(chunk.skipped_streams(),
+              ElementsAre(IForwardTsnChunk::SkippedStream(
+                  IsUnordered(false), StreamID(1), MID(2))));
+}
+
+TEST(IForwardTsnChunkTest, SerializeAndDeserialize) {
+  IForwardTsnChunk chunk(
+      TSN(123), {IForwardTsnChunk::SkippedStream(IsUnordered(false),
+                                                 StreamID(1), MID(23)),
+                 IForwardTsnChunk::SkippedStream(IsUnordered(true),
+                                                 StreamID(42), MID(99))});
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(IForwardTsnChunk deserialized,
+                              IForwardTsnChunk::Parse(serialized));
+  EXPECT_EQ(*deserialized.new_cumulative_tsn(), 123u);
+  EXPECT_THAT(deserialized.skipped_streams(),
+              ElementsAre(IForwardTsnChunk::SkippedStream(IsUnordered(false),
+                                                          StreamID(1), MID(23)),
+                          IForwardTsnChunk::SkippedStream(
+                              IsUnordered(true), StreamID(42), MID(99))));
+
+  EXPECT_EQ(deserialized.ToString(), "I-FORWARD-TSN, new_cumulative_tsn=123");
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/init_ack_chunk.cc b/net/dcsctp/packet/chunk/init_ack_chunk.cc
new file mode 100644
index 0000000..14c1265
--- /dev/null
+++ b/net/dcsctp/packet/chunk/init_ack_chunk.cc
@@ -0,0 +1,86 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/init_ack_chunk.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_format.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.3
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 2    |  Chunk Flags  |      Chunk Length             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                         Initiate Tag                          |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |              Advertised Receiver Window Credit                |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |  Number of Outbound Streams   |  Number of Inbound Streams    |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                          Initial TSN                          |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  \                                                               \
+//  /              Optional/Variable-Length Parameters              /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int InitAckChunk::kType;
+
+absl::optional<InitAckChunk> InitAckChunk::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+
+  VerificationTag initiate_tag(reader->Load32<4>());
+  uint32_t a_rwnd = reader->Load32<8>();
+  uint16_t nbr_outbound_streams = reader->Load16<12>();
+  uint16_t nbr_inbound_streams = reader->Load16<14>();
+  TSN initial_tsn(reader->Load32<16>());
+  absl::optional<Parameters> parameters =
+      Parameters::Parse(reader->variable_data());
+  if (!parameters.has_value()) {
+    return absl::nullopt;
+  }
+  return InitAckChunk(initiate_tag, a_rwnd, nbr_outbound_streams,
+                      nbr_inbound_streams, initial_tsn, *std::move(parameters));
+}
+
+void InitAckChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  rtc::ArrayView<const uint8_t> parameters = parameters_.data();
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, parameters.size());
+
+  writer.Store32<4>(*initiate_tag_);
+  writer.Store32<8>(a_rwnd_);
+  writer.Store16<12>(nbr_outbound_streams_);
+  writer.Store16<14>(nbr_inbound_streams_);
+  writer.Store32<16>(*initial_tsn_);
+  writer.CopyToVariableData(parameters);
+}
+
+std::string InitAckChunk::ToString() const {
+  return rtc::StringFormat("INIT_ACK, initiate_tag=0x%0x, initial_tsn=%d",
+                           *initiate_tag(), *initial_tsn());
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/init_ack_chunk.h b/net/dcsctp/packet/chunk/init_ack_chunk.h
new file mode 100644
index 0000000..6fcf64b
--- /dev/null
+++ b/net/dcsctp/packet/chunk/init_ack_chunk.h
@@ -0,0 +1,77 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_INIT_ACK_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_INIT_ACK_CHUNK_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.3
+struct InitAckChunkConfig : ChunkConfig {
+  static constexpr int kType = 2;
+  static constexpr size_t kHeaderSize = 20;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class InitAckChunk : public Chunk, public TLVTrait<InitAckChunkConfig> {
+ public:
+  static constexpr int kType = InitAckChunkConfig::kType;
+
+  InitAckChunk(VerificationTag initiate_tag,
+               uint32_t a_rwnd,
+               uint16_t nbr_outbound_streams,
+               uint16_t nbr_inbound_streams,
+               TSN initial_tsn,
+               Parameters parameters)
+      : initiate_tag_(initiate_tag),
+        a_rwnd_(a_rwnd),
+        nbr_outbound_streams_(nbr_outbound_streams),
+        nbr_inbound_streams_(nbr_inbound_streams),
+        initial_tsn_(initial_tsn),
+        parameters_(std::move(parameters)) {}
+
+  InitAckChunk(InitAckChunk&& other) = default;
+  InitAckChunk& operator=(InitAckChunk&& other) = default;
+
+  static absl::optional<InitAckChunk> Parse(rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  VerificationTag initiate_tag() const { return initiate_tag_; }
+  uint32_t a_rwnd() const { return a_rwnd_; }
+  uint16_t nbr_outbound_streams() const { return nbr_outbound_streams_; }
+  uint16_t nbr_inbound_streams() const { return nbr_inbound_streams_; }
+  TSN initial_tsn() const { return initial_tsn_; }
+  const Parameters& parameters() const { return parameters_; }
+
+ private:
+  VerificationTag initiate_tag_;
+  uint32_t a_rwnd_;
+  uint16_t nbr_outbound_streams_;
+  uint16_t nbr_inbound_streams_;
+  TSN initial_tsn_;
+  Parameters parameters_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_INIT_ACK_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/init_ack_chunk_test.cc b/net/dcsctp/packet/chunk/init_ack_chunk_test.cc
new file mode 100644
index 0000000..184ade7
--- /dev/null
+++ b/net/dcsctp/packet/chunk/init_ack_chunk_test.cc
@@ -0,0 +1,127 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/init_ack_chunk.h"
+
+#include <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/packet/parameter/forward_tsn_supported_parameter.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/parameter/state_cookie_parameter.h"
+#include "net/dcsctp/packet/parameter/supported_extensions_parameter.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(InitAckChunkTest, FromCapture) {
+  /*
+  INIT_ACK chunk (Outbound streams: 1000, inbound streams: 2048)
+      Chunk type: INIT_ACK (2)
+      Chunk flags: 0x00
+      Chunk length: 292
+      Initiate tag: 0x579c2f98
+      Advertised receiver window credit (a_rwnd): 131072
+      Number of outbound streams: 1000
+      Number of inbound streams: 2048
+      Initial TSN: 1670811335
+      Forward TSN supported parameter
+          Parameter type: Forward TSN supported (0xc000)
+          Parameter length: 4
+      Supported Extensions parameter (Supported types: FORWARD_TSN, RE_CONFIG)
+          Parameter type: Supported Extensions (0x8008)
+          Parameter length: 6
+          Supported chunk type: FORWARD_TSN (192)
+          Supported chunk type: RE_CONFIG (130)
+          Parameter padding: 0000
+      State cookie parameter (Cookie length: 256 bytes)
+          Parameter type: State cookie (0x0007)
+          Parameter length: 260
+          State cookie: 4b414d452d42534420312e310000000096b8386000000000…
+  */
+
+  uint8_t data[] = {
+      0x02, 0x00, 0x01, 0x24, 0x57, 0x9c, 0x2f, 0x98, 0x00, 0x02, 0x00, 0x00,
+      0x03, 0xe8, 0x08, 0x00, 0x63, 0x96, 0x8e, 0xc7, 0xc0, 0x00, 0x00, 0x04,
+      0x80, 0x08, 0x00, 0x06, 0xc0, 0x82, 0x00, 0x00, 0x00, 0x07, 0x01, 0x04,
+      0x4b, 0x41, 0x4d, 0x45, 0x2d, 0x42, 0x53, 0x44, 0x20, 0x31, 0x2e, 0x31,
+      0x00, 0x00, 0x00, 0x00, 0x96, 0xb8, 0x38, 0x60, 0x00, 0x00, 0x00, 0x00,
+      0x52, 0x5a, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xea, 0x00, 0x00,
+      0xb5, 0xaa, 0x19, 0xea, 0x31, 0xef, 0xa4, 0x2b, 0x90, 0x16, 0x7a, 0xde,
+      0x57, 0x9c, 0x2f, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x13, 0x88, 0x13, 0x88, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x5a, 0xde, 0x7a, 0x16, 0x90,
+      0x00, 0x02, 0x00, 0x00, 0x03, 0xe8, 0x03, 0xe8, 0x25, 0x0d, 0x37, 0xe8,
+      0x80, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0x04, 0x80, 0x08, 0x00, 0x09,
+      0xc0, 0x0f, 0xc1, 0x80, 0x82, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x24,
+      0xab, 0x31, 0x44, 0x62, 0x12, 0x1a, 0x15, 0x13, 0xfd, 0x5a, 0x5f, 0x69,
+      0xef, 0xaa, 0x06, 0xe9, 0xab, 0xd7, 0x48, 0xcc, 0x3b, 0xd1, 0x4b, 0x60,
+      0xed, 0x7f, 0xa6, 0x44, 0xce, 0x4d, 0xd2, 0xad, 0x80, 0x04, 0x00, 0x06,
+      0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x06, 0x80, 0xc1, 0x00, 0x00,
+      0x02, 0x00, 0x01, 0x24, 0x57, 0x9c, 0x2f, 0x98, 0x00, 0x02, 0x00, 0x00,
+      0x03, 0xe8, 0x08, 0x00, 0x63, 0x96, 0x8e, 0xc7, 0xc0, 0x00, 0x00, 0x04,
+      0x80, 0x08, 0x00, 0x06, 0xc0, 0x82, 0x00, 0x00, 0x51, 0x95, 0x01, 0x88,
+      0x0d, 0x80, 0x7b, 0x19, 0xe7, 0xf9, 0xc6, 0x18, 0x5c, 0x4a, 0xbf, 0x39,
+      0x32, 0xe5, 0x63, 0x8e};
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(InitAckChunk chunk, InitAckChunk::Parse(data));
+
+  EXPECT_EQ(chunk.initiate_tag(), VerificationTag(0x579c2f98u));
+  EXPECT_EQ(chunk.a_rwnd(), 131072u);
+  EXPECT_EQ(chunk.nbr_outbound_streams(), 1000u);
+  EXPECT_EQ(chunk.nbr_inbound_streams(), 2048u);
+  EXPECT_EQ(chunk.initial_tsn(), TSN(1670811335u));
+  EXPECT_TRUE(
+      chunk.parameters().get<ForwardTsnSupportedParameter>().has_value());
+  EXPECT_TRUE(
+      chunk.parameters().get<SupportedExtensionsParameter>().has_value());
+  EXPECT_TRUE(chunk.parameters().get<StateCookieParameter>().has_value());
+}
+
+TEST(InitAckChunkTest, SerializeAndDeserialize) {
+  uint8_t state_cookie[] = {1, 2, 3, 4, 5};
+  Parameters parameters =
+      Parameters::Builder().Add(StateCookieParameter(state_cookie)).Build();
+  InitAckChunk chunk(VerificationTag(123), /*a_rwnd=*/456,
+                     /*nbr_outbound_streams=*/65535,
+                     /*nbr_inbound_streams=*/65534, /*initial_tsn=*/TSN(789),
+                     /*parameters=*/std::move(parameters));
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(InitAckChunk deserialized,
+                              InitAckChunk::Parse(serialized));
+
+  EXPECT_EQ(chunk.initiate_tag(), VerificationTag(123u));
+  EXPECT_EQ(chunk.a_rwnd(), 456u);
+  EXPECT_EQ(chunk.nbr_outbound_streams(), 65535u);
+  EXPECT_EQ(chunk.nbr_inbound_streams(), 65534u);
+  EXPECT_EQ(chunk.initial_tsn(), TSN(789u));
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      StateCookieParameter cookie,
+      deserialized.parameters().get<StateCookieParameter>());
+  EXPECT_THAT(cookie.data(), ElementsAre(1, 2, 3, 4, 5));
+  EXPECT_EQ(deserialized.ToString(),
+            "INIT_ACK, initiate_tag=0x7b, initial_tsn=789");
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/init_chunk.cc b/net/dcsctp/packet/chunk/init_chunk.cc
new file mode 100644
index 0000000..5304350
--- /dev/null
+++ b/net/dcsctp/packet/chunk/init_chunk.cc
@@ -0,0 +1,88 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/init_chunk.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_format.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.2
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 1    |  Chunk Flags  |      Chunk Length             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                         Initiate Tag                          |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |           Advertised Receiver Window Credit (a_rwnd)          |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |  Number of Outbound Streams   |  Number of Inbound Streams    |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                          Initial TSN                          |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  \                                                               \
+//  /              Optional/Variable-Length Parameters              /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int InitChunk::kType;
+
+absl::optional<InitChunk> InitChunk::Parse(rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+
+  VerificationTag initiate_tag(reader->Load32<4>());
+  uint32_t a_rwnd = reader->Load32<8>();
+  uint16_t nbr_outbound_streams = reader->Load16<12>();
+  uint16_t nbr_inbound_streams = reader->Load16<14>();
+  TSN initial_tsn(reader->Load32<16>());
+
+  absl::optional<Parameters> parameters =
+      Parameters::Parse(reader->variable_data());
+  if (!parameters.has_value()) {
+    return absl::nullopt;
+  }
+  return InitChunk(initiate_tag, a_rwnd, nbr_outbound_streams,
+                   nbr_inbound_streams, initial_tsn, *std::move(parameters));
+}
+
+void InitChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  rtc::ArrayView<const uint8_t> parameters = parameters_.data();
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, parameters.size());
+
+  writer.Store32<4>(*initiate_tag_);
+  writer.Store32<8>(a_rwnd_);
+  writer.Store16<12>(nbr_outbound_streams_);
+  writer.Store16<14>(nbr_inbound_streams_);
+  writer.Store32<16>(*initial_tsn_);
+
+  writer.CopyToVariableData(parameters);
+}
+
+std::string InitChunk::ToString() const {
+  return rtc::StringFormat("INIT, initiate_tag=0x%0x, initial_tsn=%d",
+                           *initiate_tag(), *initial_tsn());
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/init_chunk.h b/net/dcsctp/packet/chunk/init_chunk.h
new file mode 100644
index 0000000..38f9994
--- /dev/null
+++ b/net/dcsctp/packet/chunk/init_chunk.h
@@ -0,0 +1,77 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_INIT_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_INIT_CHUNK_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.2
+struct InitChunkConfig : ChunkConfig {
+  static constexpr int kType = 1;
+  static constexpr size_t kHeaderSize = 20;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class InitChunk : public Chunk, public TLVTrait<InitChunkConfig> {
+ public:
+  static constexpr int kType = InitChunkConfig::kType;
+
+  InitChunk(VerificationTag initiate_tag,
+            uint32_t a_rwnd,
+            uint16_t nbr_outbound_streams,
+            uint16_t nbr_inbound_streams,
+            TSN initial_tsn,
+            Parameters parameters)
+      : initiate_tag_(initiate_tag),
+        a_rwnd_(a_rwnd),
+        nbr_outbound_streams_(nbr_outbound_streams),
+        nbr_inbound_streams_(nbr_inbound_streams),
+        initial_tsn_(initial_tsn),
+        parameters_(std::move(parameters)) {}
+
+  InitChunk(InitChunk&& other) = default;
+  InitChunk& operator=(InitChunk&& other) = default;
+
+  static absl::optional<InitChunk> Parse(rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  VerificationTag initiate_tag() const { return initiate_tag_; }
+  uint32_t a_rwnd() const { return a_rwnd_; }
+  uint16_t nbr_outbound_streams() const { return nbr_outbound_streams_; }
+  uint16_t nbr_inbound_streams() const { return nbr_inbound_streams_; }
+  TSN initial_tsn() const { return initial_tsn_; }
+  const Parameters& parameters() const { return parameters_; }
+
+ private:
+  VerificationTag initiate_tag_;
+  uint32_t a_rwnd_;
+  uint16_t nbr_outbound_streams_;
+  uint16_t nbr_inbound_streams_;
+  TSN initial_tsn_;
+  Parameters parameters_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_INIT_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/init_chunk_test.cc b/net/dcsctp/packet/chunk/init_chunk_test.cc
new file mode 100644
index 0000000..bd36d6f
--- /dev/null
+++ b/net/dcsctp/packet/chunk/init_chunk_test.cc
@@ -0,0 +1,113 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/init_chunk.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "net/dcsctp/packet/parameter/forward_tsn_supported_parameter.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/parameter/supported_extensions_parameter.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(InitChunkTest, FromCapture) {
+  /*
+  INIT chunk (Outbound streams: 1000, inbound streams: 1000)
+      Chunk type: INIT (1)
+      Chunk flags: 0x00
+      Chunk length: 90
+      Initiate tag: 0xde7a1690
+      Advertised receiver window credit (a_rwnd): 131072
+      Number of outbound streams: 1000
+      Number of inbound streams: 1000
+      Initial TSN: 621623272
+      ECN parameter
+          Parameter type: ECN (0x8000)
+          Parameter length: 4
+      Forward TSN supported parameter
+          Parameter type: Forward TSN supported (0xc000)
+          Parameter length: 4
+      Supported Extensions parameter (Supported types: FORWARD_TSN, AUTH,
+  ASCONF, ASCONF_ACK, RE_CONFIG) Parameter type: Supported Extensions (0x8008)
+          Parameter length: 9
+          Supported chunk type: FORWARD_TSN (192)
+          Supported chunk type: AUTH (15)
+          Supported chunk type: ASCONF (193)
+          Supported chunk type: ASCONF_ACK (128)
+          Supported chunk type: RE_CONFIG (130)
+          Parameter padding: 000000
+      Random parameter
+          Parameter type: Random (0x8002)
+          Parameter length: 36
+          Random number: ab314462121a1513fd5a5f69efaa06e9abd748cc3bd14b60…
+      Requested HMAC Algorithm parameter (Supported HMACs: SHA-1)
+          Parameter type: Requested HMAC Algorithm (0x8004)
+          Parameter length: 6
+          HMAC identifier: SHA-1 (1)
+          Parameter padding: 0000
+      Authenticated Chunk list parameter (Chunk types to be authenticated:
+  ASCONF_ACK, ASCONF) Parameter type: Authenticated Chunk list (0x8003)
+          Parameter length: 6
+          Chunk type: ASCONF_ACK (128)
+          Chunk type: ASCONF (193)
+  */
+
+  uint8_t data[] = {
+      0x01, 0x00, 0x00, 0x5a, 0xde, 0x7a, 0x16, 0x90, 0x00, 0x02, 0x00, 0x00,
+      0x03, 0xe8, 0x03, 0xe8, 0x25, 0x0d, 0x37, 0xe8, 0x80, 0x00, 0x00, 0x04,
+      0xc0, 0x00, 0x00, 0x04, 0x80, 0x08, 0x00, 0x09, 0xc0, 0x0f, 0xc1, 0x80,
+      0x82, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x24, 0xab, 0x31, 0x44, 0x62,
+      0x12, 0x1a, 0x15, 0x13, 0xfd, 0x5a, 0x5f, 0x69, 0xef, 0xaa, 0x06, 0xe9,
+      0xab, 0xd7, 0x48, 0xcc, 0x3b, 0xd1, 0x4b, 0x60, 0xed, 0x7f, 0xa6, 0x44,
+      0xce, 0x4d, 0xd2, 0xad, 0x80, 0x04, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00,
+      0x80, 0x03, 0x00, 0x06, 0x80, 0xc1, 0x00, 0x00};
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(InitChunk chunk, InitChunk::Parse(data));
+
+  EXPECT_EQ(chunk.initiate_tag(), VerificationTag(0xde7a1690));
+  EXPECT_EQ(chunk.a_rwnd(), 131072u);
+  EXPECT_EQ(chunk.nbr_outbound_streams(), 1000u);
+  EXPECT_EQ(chunk.nbr_inbound_streams(), 1000u);
+  EXPECT_EQ(chunk.initial_tsn(), TSN(621623272u));
+  EXPECT_TRUE(
+      chunk.parameters().get<ForwardTsnSupportedParameter>().has_value());
+  EXPECT_TRUE(
+      chunk.parameters().get<SupportedExtensionsParameter>().has_value());
+}
+
+TEST(InitChunkTest, SerializeAndDeserialize) {
+  InitChunk chunk(VerificationTag(123), /*a_rwnd=*/456,
+                  /*nbr_outbound_streams=*/65535,
+                  /*nbr_inbound_streams=*/65534, /*initial_tsn=*/TSN(789),
+                  /*parameters=*/Parameters::Builder().Build());
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(InitChunk deserialized,
+                              InitChunk::Parse(serialized));
+
+  EXPECT_EQ(deserialized.initiate_tag(), VerificationTag(123u));
+  EXPECT_EQ(deserialized.a_rwnd(), 456u);
+  EXPECT_EQ(deserialized.nbr_outbound_streams(), 65535u);
+  EXPECT_EQ(deserialized.nbr_inbound_streams(), 65534u);
+  EXPECT_EQ(deserialized.initial_tsn(), TSN(789u));
+  EXPECT_EQ(deserialized.ToString(),
+            "INIT, initiate_tag=0x7b, initial_tsn=789");
+}
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/reconfig_chunk.cc b/net/dcsctp/packet/chunk/reconfig_chunk.cc
new file mode 100644
index 0000000..f39f3b6
--- /dev/null
+++ b/net/dcsctp/packet/chunk/reconfig_chunk.cc
@@ -0,0 +1,69 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/reconfig_chunk.h"
+
+#include <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc6525#section-3.1
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  | Type = 130    |  Chunk Flags  |      Chunk Length             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  \                                                               \
+//  /                  Re-configuration Parameter                   /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  \                                                               \
+//  /             Re-configuration Parameter (optional)             /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int ReConfigChunk::kType;
+
+absl::optional<ReConfigChunk> ReConfigChunk::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+
+  absl::optional<Parameters> parameters =
+      Parameters::Parse(reader->variable_data());
+  if (!parameters.has_value()) {
+    return absl::nullopt;
+  }
+
+  return ReConfigChunk(*std::move(parameters));
+}
+
+void ReConfigChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  rtc::ArrayView<const uint8_t> parameters = parameters_.data();
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, parameters.size());
+  writer.CopyToVariableData(parameters);
+}
+
+std::string ReConfigChunk::ToString() const {
+  return "RE-CONFIG";
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/reconfig_chunk.h b/net/dcsctp/packet/chunk/reconfig_chunk.h
new file mode 100644
index 0000000..9d2539a
--- /dev/null
+++ b/net/dcsctp/packet/chunk/reconfig_chunk.h
@@ -0,0 +1,56 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_RECONFIG_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_RECONFIG_CHUNK_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc6525#section-3.1
+struct ReConfigChunkConfig : ChunkConfig {
+  static constexpr int kType = 130;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class ReConfigChunk : public Chunk, public TLVTrait<ReConfigChunkConfig> {
+ public:
+  static constexpr int kType = ReConfigChunkConfig::kType;
+
+  explicit ReConfigChunk(Parameters parameters)
+      : parameters_(std::move(parameters)) {}
+
+  static absl::optional<ReConfigChunk> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  const Parameters& parameters() const { return parameters_; }
+  Parameters extract_parameters() { return std::move(parameters_); }
+
+ private:
+  Parameters parameters_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_RECONFIG_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/reconfig_chunk_test.cc b/net/dcsctp/packet/chunk/reconfig_chunk_test.cc
new file mode 100644
index 0000000..2eb9419
--- /dev/null
+++ b/net/dcsctp/packet/chunk/reconfig_chunk_test.cc
@@ -0,0 +1,94 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/reconfig_chunk.h"
+
+#include <cstdint>
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+using ::testing::SizeIs;
+
+TEST(ReConfigChunkTest, FromCapture) {
+  /*
+  RE_CONFIG chunk
+      Chunk type: RE_CONFIG (130)
+      Chunk flags: 0x00
+      Chunk length: 22
+      Outgoing SSN reset request parameter
+          Parameter type: Outgoing SSN reset request (0x000d)
+          Parameter length: 18
+          Re-configuration request sequence number: 2270550051
+          Re-configuration response sequence number: 1905748638
+          Senders last assigned TSN: 2270550066
+          Stream Identifier: 6
+      Chunk padding: 0000
+  */
+
+  uint8_t data[] = {0x82, 0x00, 0x00, 0x16, 0x00, 0x0d, 0x00, 0x12,
+                    0x87, 0x55, 0xd8, 0x23, 0x71, 0x97, 0x6a, 0x9e,
+                    0x87, 0x55, 0xd8, 0x32, 0x00, 0x06, 0x00, 0x00};
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(ReConfigChunk chunk, ReConfigChunk::Parse(data));
+
+  const Parameters& parameters = chunk.parameters();
+  EXPECT_THAT(parameters.descriptors(), SizeIs(1));
+  ParameterDescriptor desc = parameters.descriptors()[0];
+  ASSERT_EQ(desc.type, OutgoingSSNResetRequestParameter::kType);
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      OutgoingSSNResetRequestParameter req,
+      OutgoingSSNResetRequestParameter::Parse(desc.data));
+  EXPECT_EQ(*req.request_sequence_number(), 2270550051u);
+  EXPECT_EQ(*req.response_sequence_number(), 1905748638u);
+  EXPECT_EQ(*req.sender_last_assigned_tsn(), 2270550066u);
+  EXPECT_THAT(req.stream_ids(), ElementsAre(StreamID(6)));
+}
+
+TEST(ReConfigChunkTest, SerializeAndDeserialize) {
+  Parameters::Builder params_builder =
+      Parameters::Builder().Add(OutgoingSSNResetRequestParameter(
+          ReconfigRequestSN(123), ReconfigResponseSN(456), TSN(789),
+          {StreamID(42), StreamID(43)}));
+
+  ReConfigChunk chunk(params_builder.Build());
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(ReConfigChunk deserialized,
+                              ReConfigChunk::Parse(serialized));
+
+  const Parameters& parameters = deserialized.parameters();
+  EXPECT_THAT(parameters.descriptors(), SizeIs(1));
+  ParameterDescriptor desc = parameters.descriptors()[0];
+  ASSERT_EQ(desc.type, OutgoingSSNResetRequestParameter::kType);
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      OutgoingSSNResetRequestParameter req,
+      OutgoingSSNResetRequestParameter::Parse(desc.data));
+  EXPECT_EQ(*req.request_sequence_number(), 123u);
+  EXPECT_EQ(*req.response_sequence_number(), 456u);
+  EXPECT_EQ(*req.sender_last_assigned_tsn(), 789u);
+  EXPECT_THAT(req.stream_ids(), ElementsAre(StreamID(42), StreamID(43)));
+
+  EXPECT_EQ(deserialized.ToString(), "RE-CONFIG");
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/sack_chunk.cc b/net/dcsctp/packet/chunk/sack_chunk.cc
new file mode 100644
index 0000000..a9f17d7
--- /dev/null
+++ b/net/dcsctp/packet/chunk/sack_chunk.cc
@@ -0,0 +1,156 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/sack_chunk.h"
+
+#include <stddef.h>
+
+#include <cstdint>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/str_join.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.4
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 3    |Chunk  Flags   |      Chunk Length             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                      Cumulative TSN Ack                       |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |          Advertised Receiver Window Credit (a_rwnd)           |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  | Number of Gap Ack Blocks = N  |  Number of Duplicate TSNs = X |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |  Gap Ack Block #1 Start       |   Gap Ack Block #1 End        |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  /                                                               /
+//  \                              ...                              \
+//  /                                                               /
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Gap Ack Block #N Start      |  Gap Ack Block #N End         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                       Duplicate TSN 1                         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  /                                                               /
+//  \                              ...                              \
+//  /                                                               /
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                       Duplicate TSN X                         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int SackChunk::kType;
+
+absl::optional<SackChunk> SackChunk::Parse(rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+
+  TSN tsn_ack(reader->Load32<4>());
+  uint32_t a_rwnd = reader->Load32<8>();
+  uint16_t nbr_of_gap_blocks = reader->Load16<12>();
+  uint16_t nbr_of_dup_tsns = reader->Load16<14>();
+
+  if (reader->variable_data_size() != nbr_of_gap_blocks * kGapAckBlockSize +
+                                          nbr_of_dup_tsns * kDupTsnBlockSize) {
+    RTC_DLOG(LS_WARNING) << "Invalid number of gap blocks or duplicate TSNs";
+    return absl::nullopt;
+  }
+
+  std::vector<GapAckBlock> gap_ack_blocks;
+  gap_ack_blocks.reserve(nbr_of_gap_blocks);
+  size_t offset = 0;
+  for (int i = 0; i < nbr_of_gap_blocks; ++i) {
+    BoundedByteReader<kGapAckBlockSize> sub_reader =
+        reader->sub_reader<kGapAckBlockSize>(offset);
+
+    uint16_t start = sub_reader.Load16<0>();
+    uint16_t end = sub_reader.Load16<2>();
+    gap_ack_blocks.emplace_back(start, end);
+    offset += kGapAckBlockSize;
+  }
+
+  std::vector<TSN> duplicate_tsns;
+  duplicate_tsns.reserve(nbr_of_gap_blocks);
+  for (int i = 0; i < nbr_of_dup_tsns; ++i) {
+    BoundedByteReader<kDupTsnBlockSize> sub_reader =
+        reader->sub_reader<kDupTsnBlockSize>(offset);
+
+    duplicate_tsns.push_back(TSN(sub_reader.Load32<0>()));
+    offset += kDupTsnBlockSize;
+  }
+  RTC_DCHECK(offset == reader->variable_data_size());
+
+  return SackChunk(tsn_ack, a_rwnd, gap_ack_blocks, duplicate_tsns);
+}
+
+void SackChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  int nbr_of_gap_blocks = gap_ack_blocks_.size();
+  int nbr_of_dup_tsns = duplicate_tsns_.size();
+  size_t variable_size =
+      nbr_of_gap_blocks * kGapAckBlockSize + nbr_of_dup_tsns * kDupTsnBlockSize;
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, variable_size);
+
+  writer.Store32<4>(*cumulative_tsn_ack_);
+  writer.Store32<8>(a_rwnd_);
+  writer.Store16<12>(nbr_of_gap_blocks);
+  writer.Store16<14>(nbr_of_dup_tsns);
+
+  size_t offset = 0;
+  for (int i = 0; i < nbr_of_gap_blocks; ++i) {
+    BoundedByteWriter<kGapAckBlockSize> sub_writer =
+        writer.sub_writer<kGapAckBlockSize>(offset);
+
+    sub_writer.Store16<0>(gap_ack_blocks_[i].start);
+    sub_writer.Store16<2>(gap_ack_blocks_[i].end);
+    offset += kGapAckBlockSize;
+  }
+
+  for (int i = 0; i < nbr_of_dup_tsns; ++i) {
+    BoundedByteWriter<kDupTsnBlockSize> sub_writer =
+        writer.sub_writer<kDupTsnBlockSize>(offset);
+
+    sub_writer.Store32<0>(*duplicate_tsns_[i]);
+    offset += kDupTsnBlockSize;
+  }
+
+  RTC_DCHECK(offset == variable_size);
+}
+
+std::string SackChunk::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "SACK, cum_ack_tsn=" << *cumulative_tsn_ack()
+     << ", a_rwnd=" << a_rwnd();
+  for (const GapAckBlock& gap : gap_ack_blocks_) {
+    uint32_t first = *cumulative_tsn_ack_ + gap.start;
+    uint32_t last = *cumulative_tsn_ack_ + gap.end;
+    sb << ", gap=" << first << "--" << last;
+  }
+  if (!duplicate_tsns_.empty()) {
+    sb << ", dup_tsns="
+       << StrJoin(duplicate_tsns(), ",",
+                  [](rtc::StringBuilder& sb, TSN tsn) { sb << *tsn; });
+  }
+
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/sack_chunk.h b/net/dcsctp/packet/chunk/sack_chunk.h
new file mode 100644
index 0000000..0b464fb
--- /dev/null
+++ b/net/dcsctp/packet/chunk/sack_chunk.h
@@ -0,0 +1,79 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_SACK_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_SACK_CHUNK_H_
+#include <stddef.h>
+
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.4
+struct SackChunkConfig : ChunkConfig {
+  static constexpr int kType = 3;
+  static constexpr size_t kHeaderSize = 16;
+  static constexpr size_t kVariableLengthAlignment = 4;
+};
+
+class SackChunk : public Chunk, public TLVTrait<SackChunkConfig> {
+ public:
+  static constexpr int kType = SackChunkConfig::kType;
+
+  struct GapAckBlock {
+    GapAckBlock(uint16_t start, uint16_t end) : start(start), end(end) {}
+
+    uint16_t start;
+    uint16_t end;
+
+    bool operator==(const GapAckBlock& other) const {
+      return start == other.start && end == other.end;
+    }
+  };
+
+  SackChunk(TSN cumulative_tsn_ack,
+            uint32_t a_rwnd,
+            std::vector<GapAckBlock> gap_ack_blocks,
+            std::vector<TSN> duplicate_tsns)
+      : cumulative_tsn_ack_(cumulative_tsn_ack),
+        a_rwnd_(a_rwnd),
+        gap_ack_blocks_(std::move(gap_ack_blocks)),
+        duplicate_tsns_(std::move(duplicate_tsns)) {}
+  static absl::optional<SackChunk> Parse(rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  TSN cumulative_tsn_ack() const { return cumulative_tsn_ack_; }
+  uint32_t a_rwnd() const { return a_rwnd_; }
+  rtc::ArrayView<const GapAckBlock> gap_ack_blocks() const {
+    return gap_ack_blocks_;
+  }
+  rtc::ArrayView<const TSN> duplicate_tsns() const { return duplicate_tsns_; }
+
+ private:
+  static constexpr size_t kGapAckBlockSize = 4;
+  static constexpr size_t kDupTsnBlockSize = 4;
+
+  const TSN cumulative_tsn_ack_;
+  const uint32_t a_rwnd_;
+  std::vector<GapAckBlock> gap_ack_blocks_;
+  std::vector<TSN> duplicate_tsns_;
+};
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_SACK_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/sack_chunk_test.cc b/net/dcsctp/packet/chunk/sack_chunk_test.cc
new file mode 100644
index 0000000..9122945
--- /dev/null
+++ b/net/dcsctp/packet/chunk/sack_chunk_test.cc
@@ -0,0 +1,84 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/sack_chunk.h"
+
+#include <cstdint>
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(SackChunkTest, FromCapture) {
+  /*
+  SACK chunk (Cumulative TSN: 916312075, a_rwnd: 126323,
+    gaps: 2, duplicate TSNs: 1)
+      Chunk type: SACK (3)
+      Chunk flags: 0x00
+      Chunk length: 28
+      Cumulative TSN ACK: 916312075
+      Advertised receiver window credit (a_rwnd): 126323
+      Number of gap acknowledgement blocks: 2
+      Number of duplicated TSNs: 1
+      Gap Acknowledgement for TSN 916312077 to 916312081
+      Gap Acknowledgement for TSN 916312083 to 916312083
+      [Number of TSNs in gap acknowledgement blocks: 6]
+      Duplicate TSN: 916312081
+
+  */
+
+  uint8_t data[] = {0x03, 0x00, 0x00, 0x1c, 0x36, 0x9d, 0xd0, 0x0b, 0x00, 0x01,
+                    0xed, 0x73, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x06,
+                    0x00, 0x08, 0x00, 0x08, 0x36, 0x9d, 0xd0, 0x11};
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(SackChunk chunk, SackChunk::Parse(data));
+
+  TSN cum_ack_tsn(916312075);
+  EXPECT_EQ(chunk.cumulative_tsn_ack(), cum_ack_tsn);
+  EXPECT_EQ(chunk.a_rwnd(), 126323u);
+  EXPECT_THAT(
+      chunk.gap_ack_blocks(),
+      ElementsAre(SackChunk::GapAckBlock(
+                      static_cast<uint16_t>(916312077 - *cum_ack_tsn),
+                      static_cast<uint16_t>(916312081 - *cum_ack_tsn)),
+                  SackChunk::GapAckBlock(
+                      static_cast<uint16_t>(916312083 - *cum_ack_tsn),
+                      static_cast<uint16_t>(916312083 - *cum_ack_tsn))));
+  EXPECT_THAT(chunk.duplicate_tsns(), ElementsAre(TSN(916312081)));
+}
+
+TEST(SackChunkTest, SerializeAndDeserialize) {
+  SackChunk chunk(TSN(123), /*a_rwnd=*/456, {SackChunk::GapAckBlock(2, 3)},
+                  {TSN(1), TSN(2), TSN(3)});
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(SackChunk deserialized,
+                              SackChunk::Parse(serialized));
+
+  EXPECT_EQ(*deserialized.cumulative_tsn_ack(), 123u);
+  EXPECT_EQ(deserialized.a_rwnd(), 456u);
+  EXPECT_THAT(deserialized.gap_ack_blocks(),
+              ElementsAre(SackChunk::GapAckBlock(2, 3)));
+  EXPECT_THAT(deserialized.duplicate_tsns(),
+              ElementsAre(TSN(1), TSN(2), TSN(3)));
+
+  EXPECT_EQ(deserialized.ToString(),
+            "SACK, cum_ack_tsn=123, a_rwnd=456, gap=125--126, dup_tsns=1,2,3");
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/shutdown_ack_chunk.cc b/net/dcsctp/packet/chunk/shutdown_ack_chunk.cc
new file mode 100644
index 0000000..d42acee
--- /dev/null
+++ b/net/dcsctp/packet/chunk/shutdown_ack_chunk.cc
@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/shutdown_ack_chunk.h"
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.9
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 8    |Chunk  Flags   |      Length = 4               |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int ShutdownAckChunk::kType;
+
+absl::optional<ShutdownAckChunk> ShutdownAckChunk::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  if (!ParseTLV(data).has_value()) {
+    return absl::nullopt;
+  }
+  return ShutdownAckChunk();
+}
+
+void ShutdownAckChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  AllocateTLV(out);
+}
+
+std::string ShutdownAckChunk::ToString() const {
+  return "SHUTDOWN-ACK";
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/shutdown_ack_chunk.h b/net/dcsctp/packet/chunk/shutdown_ack_chunk.h
new file mode 100644
index 0000000..29c1a98
--- /dev/null
+++ b/net/dcsctp/packet/chunk/shutdown_ack_chunk.h
@@ -0,0 +1,47 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_SHUTDOWN_ACK_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_SHUTDOWN_ACK_CHUNK_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.9
+struct ShutdownAckChunkConfig : ChunkConfig {
+  static constexpr int kType = 8;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 0;
+};
+
+class ShutdownAckChunk : public Chunk, public TLVTrait<ShutdownAckChunkConfig> {
+ public:
+  static constexpr int kType = ShutdownAckChunkConfig::kType;
+
+  ShutdownAckChunk() {}
+
+  static absl::optional<ShutdownAckChunk> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_SHUTDOWN_ACK_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/shutdown_ack_chunk_test.cc b/net/dcsctp/packet/chunk/shutdown_ack_chunk_test.cc
new file mode 100644
index 0000000..ef04ea9
--- /dev/null
+++ b/net/dcsctp/packet/chunk/shutdown_ack_chunk_test.cc
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/shutdown_ack_chunk.h"
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(ShutdownAckChunkTest, FromCapture) {
+  /*
+  SHUTDOWN_ACK chunk
+      Chunk type: SHUTDOWN_ACK (8)
+      Chunk flags: 0x00
+      Chunk length: 4
+  */
+
+  uint8_t data[] = {0x08, 0x00, 0x00, 0x04};
+
+  EXPECT_TRUE(ShutdownAckChunk::Parse(data).has_value());
+}
+
+TEST(ShutdownAckChunkTest, SerializeAndDeserialize) {
+  ShutdownAckChunk chunk;
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  EXPECT_TRUE(ShutdownAckChunk::Parse(serialized).has_value());
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/shutdown_chunk.cc b/net/dcsctp/packet/chunk/shutdown_chunk.cc
new file mode 100644
index 0000000..59f806f
--- /dev/null
+++ b/net/dcsctp/packet/chunk/shutdown_chunk.cc
@@ -0,0 +1,55 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/shutdown_chunk.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.8
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 7    | Chunk  Flags  |      Length = 8               |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                      Cumulative TSN Ack                       |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int ShutdownChunk::kType;
+
+absl::optional<ShutdownChunk> ShutdownChunk::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+
+  TSN cumulative_tsn_ack(reader->Load32<4>());
+  return ShutdownChunk(cumulative_tsn_ack);
+}
+
+void ShutdownChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out);
+  writer.Store32<4>(*cumulative_tsn_ack_);
+}
+
+std::string ShutdownChunk::ToString() const {
+  return "SHUTDOWN";
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/shutdown_chunk.h b/net/dcsctp/packet/chunk/shutdown_chunk.h
new file mode 100644
index 0000000..8148cca
--- /dev/null
+++ b/net/dcsctp/packet/chunk/shutdown_chunk.h
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_SHUTDOWN_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_SHUTDOWN_CHUNK_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.8
+struct ShutdownChunkConfig : ChunkConfig {
+  static constexpr int kType = 7;
+  static constexpr size_t kHeaderSize = 8;
+  static constexpr size_t kVariableLengthAlignment = 0;
+};
+
+class ShutdownChunk : public Chunk, public TLVTrait<ShutdownChunkConfig> {
+ public:
+  static constexpr int kType = ShutdownChunkConfig::kType;
+
+  explicit ShutdownChunk(TSN cumulative_tsn_ack)
+      : cumulative_tsn_ack_(cumulative_tsn_ack) {}
+
+  static absl::optional<ShutdownChunk> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  TSN cumulative_tsn_ack() const { return cumulative_tsn_ack_; }
+
+ private:
+  TSN cumulative_tsn_ack_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_SHUTDOWN_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/shutdown_chunk_test.cc b/net/dcsctp/packet/chunk/shutdown_chunk_test.cc
new file mode 100644
index 0000000..16d147c
--- /dev/null
+++ b/net/dcsctp/packet/chunk/shutdown_chunk_test.cc
@@ -0,0 +1,50 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/shutdown_chunk.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+
+namespace dcsctp {
+namespace {
+TEST(ShutdownChunkTest, FromCapture) {
+  /*
+  SHUTDOWN chunk (Cumulative TSN ack: 101831101)
+      Chunk type: SHUTDOWN (7)
+      Chunk flags: 0x00
+      Chunk length: 8
+      Cumulative TSN Ack: 101831101
+  */
+
+  uint8_t data[] = {0x07, 0x00, 0x00, 0x08, 0x06, 0x11, 0xd1, 0xbd};
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(ShutdownChunk chunk, ShutdownChunk::Parse(data));
+  EXPECT_EQ(chunk.cumulative_tsn_ack(), TSN(101831101u));
+}
+
+TEST(ShutdownChunkTest, SerializeAndDeserialize) {
+  ShutdownChunk chunk(TSN(12345678));
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(ShutdownChunk deserialized,
+                              ShutdownChunk::Parse(serialized));
+
+  EXPECT_EQ(deserialized.cumulative_tsn_ack(), TSN(12345678u));
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/shutdown_complete_chunk.cc b/net/dcsctp/packet/chunk/shutdown_complete_chunk.cc
new file mode 100644
index 0000000..3f54857
--- /dev/null
+++ b/net/dcsctp/packet/chunk/shutdown_complete_chunk.cc
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/shutdown_complete_chunk.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.13
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 14   |Reserved     |T|      Length = 4               |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int ShutdownCompleteChunk::kType;
+
+absl::optional<ShutdownCompleteChunk> ShutdownCompleteChunk::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  uint8_t flags = reader->Load8<1>();
+  bool tag_reflected = (flags & (1 << kFlagsBitT)) != 0;
+  return ShutdownCompleteChunk(tag_reflected);
+}
+
+void ShutdownCompleteChunk::SerializeTo(std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out);
+  writer.Store8<1>(tag_reflected_ ? (1 << kFlagsBitT) : 0);
+}
+
+std::string ShutdownCompleteChunk::ToString() const {
+  return "SHUTDOWN-COMPLETE";
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/chunk/shutdown_complete_chunk.h b/net/dcsctp/packet/chunk/shutdown_complete_chunk.h
new file mode 100644
index 0000000..46d28e8
--- /dev/null
+++ b/net/dcsctp/packet/chunk/shutdown_complete_chunk.h
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_CHUNK_SHUTDOWN_COMPLETE_CHUNK_H_
+#define NET_DCSCTP_PACKET_CHUNK_SHUTDOWN_COMPLETE_CHUNK_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/chunk/chunk.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.13
+struct ShutdownCompleteChunkConfig : ChunkConfig {
+  static constexpr int kType = 14;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 0;
+};
+
+class ShutdownCompleteChunk : public Chunk,
+                              public TLVTrait<ShutdownCompleteChunkConfig> {
+ public:
+  static constexpr int kType = ShutdownCompleteChunkConfig::kType;
+
+  explicit ShutdownCompleteChunk(bool tag_reflected)
+      : tag_reflected_(tag_reflected) {}
+
+  static absl::optional<ShutdownCompleteChunk> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+  bool tag_reflected() const { return tag_reflected_; }
+
+ private:
+  static constexpr int kFlagsBitT = 0;
+  bool tag_reflected_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_CHUNK_SHUTDOWN_COMPLETE_CHUNK_H_
diff --git a/net/dcsctp/packet/chunk/shutdown_complete_chunk_test.cc b/net/dcsctp/packet/chunk/shutdown_complete_chunk_test.cc
new file mode 100644
index 0000000..253900d
--- /dev/null
+++ b/net/dcsctp/packet/chunk/shutdown_complete_chunk_test.cc
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/chunk/shutdown_complete_chunk.h"
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(ShutdownCompleteChunkTest, FromCapture) {
+  /*
+  SHUTDOWN_COMPLETE chunk
+      Chunk type: SHUTDOWN_COMPLETE (14)
+      Chunk flags: 0x00
+      Chunk length: 4
+  */
+
+  uint8_t data[] = {0x0e, 0x00, 0x00, 0x04};
+
+  EXPECT_TRUE(ShutdownCompleteChunk::Parse(data).has_value());
+}
+
+TEST(ShutdownCompleteChunkTest, SerializeAndDeserialize) {
+  ShutdownCompleteChunk chunk(/*tag_reflected=*/false);
+
+  std::vector<uint8_t> serialized;
+  chunk.SerializeTo(serialized);
+
+  EXPECT_TRUE(ShutdownCompleteChunk::Parse(serialized).has_value());
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/cookie_received_while_shutting_down_cause.cc b/net/dcsctp/packet/error_cause/cookie_received_while_shutting_down_cause.cc
new file mode 100644
index 0000000..ef67c2a
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/cookie_received_while_shutting_down_cause.cc
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/cookie_received_while_shutting_down_cause.h"
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.10
+
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Cause Code=10              |      Cause Length=4          |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int CookieReceivedWhileShuttingDownCause::kType;
+
+absl::optional<CookieReceivedWhileShuttingDownCause>
+CookieReceivedWhileShuttingDownCause::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  if (!ParseTLV(data).has_value()) {
+    return absl::nullopt;
+  }
+  return CookieReceivedWhileShuttingDownCause();
+}
+
+void CookieReceivedWhileShuttingDownCause::SerializeTo(
+    std::vector<uint8_t>& out) const {
+  AllocateTLV(out);
+}
+
+std::string CookieReceivedWhileShuttingDownCause::ToString() const {
+  return "Cookie Received While Shutting Down";
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/cookie_received_while_shutting_down_cause.h b/net/dcsctp/packet/error_cause/cookie_received_while_shutting_down_cause.h
new file mode 100644
index 0000000..362f181
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/cookie_received_while_shutting_down_cause.h
@@ -0,0 +1,50 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_ERROR_CAUSE_COOKIE_RECEIVED_WHILE_SHUTTING_DOWN_CAUSE_H_
+#define NET_DCSCTP_PACKET_ERROR_CAUSE_COOKIE_RECEIVED_WHILE_SHUTTING_DOWN_CAUSE_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.10
+struct CookieReceivedWhileShuttingDownCauseConfig : public ParameterConfig {
+  static constexpr int kType = 10;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 0;
+};
+
+class CookieReceivedWhileShuttingDownCause
+    : public Parameter,
+      public TLVTrait<CookieReceivedWhileShuttingDownCauseConfig> {
+ public:
+  static constexpr int kType =
+      CookieReceivedWhileShuttingDownCauseConfig::kType;
+
+  CookieReceivedWhileShuttingDownCause() {}
+
+  static absl::optional<CookieReceivedWhileShuttingDownCause> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_ERROR_CAUSE_COOKIE_RECEIVED_WHILE_SHUTTING_DOWN_CAUSE_H_
diff --git a/net/dcsctp/packet/error_cause/cookie_received_while_shutting_down_cause_test.cc b/net/dcsctp/packet/error_cause/cookie_received_while_shutting_down_cause_test.cc
new file mode 100644
index 0000000..afb8364
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/cookie_received_while_shutting_down_cause_test.cc
@@ -0,0 +1,35 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/cookie_received_while_shutting_down_cause.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(CookieReceivedWhileShuttingDownCauseTest, SerializeAndDeserialize) {
+  CookieReceivedWhileShuttingDownCause parameter;
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      CookieReceivedWhileShuttingDownCause deserialized,
+      CookieReceivedWhileShuttingDownCause::Parse(serialized));
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/error_cause.cc b/net/dcsctp/packet/error_cause/error_cause.cc
new file mode 100644
index 0000000..dcd0747
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/error_cause.cc
@@ -0,0 +1,83 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+
+#include <stddef.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/math.h"
+#include "net/dcsctp/packet/error_cause/cookie_received_while_shutting_down_cause.h"
+#include "net/dcsctp/packet/error_cause/invalid_mandatory_parameter_cause.h"
+#include "net/dcsctp/packet/error_cause/invalid_stream_identifier_cause.h"
+#include "net/dcsctp/packet/error_cause/missing_mandatory_parameter_cause.h"
+#include "net/dcsctp/packet/error_cause/no_user_data_cause.h"
+#include "net/dcsctp/packet/error_cause/out_of_resource_error_cause.h"
+#include "net/dcsctp/packet/error_cause/protocol_violation_cause.h"
+#include "net/dcsctp/packet/error_cause/restart_of_an_association_with_new_address_cause.h"
+#include "net/dcsctp/packet/error_cause/stale_cookie_error_cause.h"
+#include "net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause.h"
+#include "net/dcsctp/packet/error_cause/unrecognized_parameter_cause.h"
+#include "net/dcsctp/packet/error_cause/unresolvable_address_cause.h"
+#include "net/dcsctp/packet/error_cause/user_initiated_abort_cause.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+template <class ErrorCause>
+bool ParseAndPrint(ParameterDescriptor descriptor, rtc::StringBuilder& sb) {
+  if (descriptor.type == ErrorCause::kType) {
+    absl::optional<ErrorCause> p = ErrorCause::Parse(descriptor.data);
+    if (p.has_value()) {
+      sb << p->ToString();
+    } else {
+      sb << "Failed to parse error cause of type " << ErrorCause::kType;
+    }
+    return true;
+  }
+  return false;
+}
+
+std::string ErrorCausesToString(const Parameters& parameters) {
+  rtc::StringBuilder sb;
+
+  std::vector<ParameterDescriptor> descriptors = parameters.descriptors();
+  for (size_t i = 0; i < descriptors.size(); ++i) {
+    if (i > 0) {
+      sb << "\n";
+    }
+
+    const ParameterDescriptor& d = descriptors[i];
+    if (!ParseAndPrint<InvalidStreamIdentifierCause>(d, sb) &&
+        !ParseAndPrint<MissingMandatoryParameterCause>(d, sb) &&
+        !ParseAndPrint<StaleCookieErrorCause>(d, sb) &&
+        !ParseAndPrint<OutOfResourceErrorCause>(d, sb) &&
+        !ParseAndPrint<UnresolvableAddressCause>(d, sb) &&
+        !ParseAndPrint<UnrecognizedChunkTypeCause>(d, sb) &&
+        !ParseAndPrint<InvalidMandatoryParameterCause>(d, sb) &&
+        !ParseAndPrint<UnrecognizedParametersCause>(d, sb) &&
+        !ParseAndPrint<NoUserDataCause>(d, sb) &&
+        !ParseAndPrint<CookieReceivedWhileShuttingDownCause>(d, sb) &&
+        !ParseAndPrint<RestartOfAnAssociationWithNewAddressesCause>(d, sb) &&
+        !ParseAndPrint<UserInitiatedAbortCause>(d, sb) &&
+        !ParseAndPrint<ProtocolViolationCause>(d, sb)) {
+      sb << "Unhandled parameter of type: " << d.type;
+    }
+  }
+
+  return sb.Release();
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/error_cause.h b/net/dcsctp/packet/error_cause/error_cause.h
new file mode 100644
index 0000000..fa2bf81
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/error_cause.h
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_ERROR_CAUSE_ERROR_CAUSE_H_
+#define NET_DCSCTP_PACKET_ERROR_CAUSE_ERROR_CAUSE_H_
+
+#include <stddef.h>
+
+#include <cstdint>
+#include <iosfwd>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "absl/algorithm/container.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// Converts the Error Causes in `parameters` to a human readable string,
+// to be used in error reporting and logging.
+std::string ErrorCausesToString(const Parameters& parameters);
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_ERROR_CAUSE_ERROR_CAUSE_H_
diff --git a/net/dcsctp/packet/error_cause/invalid_mandatory_parameter_cause.cc b/net/dcsctp/packet/error_cause/invalid_mandatory_parameter_cause.cc
new file mode 100644
index 0000000..0187544
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/invalid_mandatory_parameter_cause.cc
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/invalid_mandatory_parameter_cause.h"
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.7
+
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Cause Code=7              |      Cause Length=4           |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int InvalidMandatoryParameterCause::kType;
+
+absl::optional<InvalidMandatoryParameterCause>
+InvalidMandatoryParameterCause::Parse(rtc::ArrayView<const uint8_t> data) {
+  if (!ParseTLV(data).has_value()) {
+    return absl::nullopt;
+  }
+  return InvalidMandatoryParameterCause();
+}
+
+void InvalidMandatoryParameterCause::SerializeTo(
+    std::vector<uint8_t>& out) const {
+  AllocateTLV(out);
+}
+
+std::string InvalidMandatoryParameterCause::ToString() const {
+  return "Invalid Mandatory Parameter";
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/invalid_mandatory_parameter_cause.h b/net/dcsctp/packet/error_cause/invalid_mandatory_parameter_cause.h
new file mode 100644
index 0000000..e192b5a
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/invalid_mandatory_parameter_cause.h
@@ -0,0 +1,48 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_ERROR_CAUSE_INVALID_MANDATORY_PARAMETER_CAUSE_H_
+#define NET_DCSCTP_PACKET_ERROR_CAUSE_INVALID_MANDATORY_PARAMETER_CAUSE_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.7
+struct InvalidMandatoryParameterCauseConfig : public ParameterConfig {
+  static constexpr int kType = 7;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 0;
+};
+
+class InvalidMandatoryParameterCause
+    : public Parameter,
+      public TLVTrait<InvalidMandatoryParameterCauseConfig> {
+ public:
+  static constexpr int kType = InvalidMandatoryParameterCauseConfig::kType;
+
+  InvalidMandatoryParameterCause() {}
+
+  static absl::optional<InvalidMandatoryParameterCause> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+};
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_ERROR_CAUSE_INVALID_MANDATORY_PARAMETER_CAUSE_H_
diff --git a/net/dcsctp/packet/error_cause/invalid_mandatory_parameter_cause_test.cc b/net/dcsctp/packet/error_cause/invalid_mandatory_parameter_cause_test.cc
new file mode 100644
index 0000000..3d532d0
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/invalid_mandatory_parameter_cause_test.cc
@@ -0,0 +1,35 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/invalid_mandatory_parameter_cause.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(InvalidMandatoryParameterCauseTest, SerializeAndDeserialize) {
+  InvalidMandatoryParameterCause parameter;
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      InvalidMandatoryParameterCause deserialized,
+      InvalidMandatoryParameterCause::Parse(serialized));
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/invalid_stream_identifier_cause.cc b/net/dcsctp/packet/error_cause/invalid_stream_identifier_cause.cc
new file mode 100644
index 0000000..b2ddd6f
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/invalid_stream_identifier_cause.cc
@@ -0,0 +1,60 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/invalid_stream_identifier_cause.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.1
+
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Cause Code=1              |      Cause Length=8           |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |        Stream Identifier      |         (Reserved)            |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int InvalidStreamIdentifierCause::kType;
+
+absl::optional<InvalidStreamIdentifierCause>
+InvalidStreamIdentifierCause::Parse(rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+
+  StreamID stream_id(reader->Load16<4>());
+  return InvalidStreamIdentifierCause(stream_id);
+}
+
+void InvalidStreamIdentifierCause::SerializeTo(
+    std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out);
+
+  writer.Store16<4>(*stream_id_);
+}
+
+std::string InvalidStreamIdentifierCause::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "Invalid Stream Identifier, stream_id=" << *stream_id_;
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/invalid_stream_identifier_cause.h b/net/dcsctp/packet/error_cause/invalid_stream_identifier_cause.h
new file mode 100644
index 0000000..b7dfe17
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/invalid_stream_identifier_cause.h
@@ -0,0 +1,56 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_ERROR_CAUSE_INVALID_STREAM_IDENTIFIER_CAUSE_H_
+#define NET_DCSCTP_PACKET_ERROR_CAUSE_INVALID_STREAM_IDENTIFIER_CAUSE_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "net/dcsctp/public/types.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.1
+struct InvalidStreamIdentifierCauseConfig : public ParameterConfig {
+  static constexpr int kType = 1;
+  static constexpr size_t kHeaderSize = 8;
+  static constexpr size_t kVariableLengthAlignment = 0;
+};
+
+class InvalidStreamIdentifierCause
+    : public Parameter,
+      public TLVTrait<InvalidStreamIdentifierCauseConfig> {
+ public:
+  static constexpr int kType = InvalidStreamIdentifierCauseConfig::kType;
+
+  explicit InvalidStreamIdentifierCause(StreamID stream_id)
+      : stream_id_(stream_id) {}
+
+  static absl::optional<InvalidStreamIdentifierCause> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  StreamID stream_id() const { return stream_id_; }
+
+ private:
+  StreamID stream_id_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_ERROR_CAUSE_INVALID_STREAM_IDENTIFIER_CAUSE_H_
diff --git a/net/dcsctp/packet/error_cause/invalid_stream_identifier_cause_test.cc b/net/dcsctp/packet/error_cause/invalid_stream_identifier_cause_test.cc
new file mode 100644
index 0000000..a282ce5
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/invalid_stream_identifier_cause_test.cc
@@ -0,0 +1,36 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/invalid_stream_identifier_cause.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(InvalidStreamIdentifierCauseTest, SerializeAndDeserialize) {
+  InvalidStreamIdentifierCause parameter(StreamID(1));
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(InvalidStreamIdentifierCause deserialized,
+                              InvalidStreamIdentifierCause::Parse(serialized));
+
+  EXPECT_EQ(*deserialized.stream_id(), 1);
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/missing_mandatory_parameter_cause.cc b/net/dcsctp/packet/error_cause/missing_mandatory_parameter_cause.cc
new file mode 100644
index 0000000..c4e2961
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/missing_mandatory_parameter_cause.cc
@@ -0,0 +1,90 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/missing_mandatory_parameter_cause.h"
+
+#include <stddef.h>
+
+#include <cstdint>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/str_join.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.2
+
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Cause Code=2              |      Cause Length=8+N*2       |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                   Number of missing params=N                  |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Missing Param Type #1       |   Missing Param Type #2       |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Missing Param Type #N-1     |   Missing Param Type #N       |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int MissingMandatoryParameterCause::kType;
+
+absl::optional<MissingMandatoryParameterCause>
+MissingMandatoryParameterCause::Parse(rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+
+  uint32_t count = reader->Load32<4>();
+  if (reader->variable_data_size() != count * kMissingParameterSize) {
+    RTC_DLOG(LS_WARNING) << "Invalid number of missing parameters";
+    return absl::nullopt;
+  }
+
+  std::vector<uint16_t> missing_parameter_types;
+  missing_parameter_types.reserve(count);
+  for (size_t i = 0; i < count; ++i) {
+    BoundedByteReader<kMissingParameterSize> sub_reader =
+        reader->sub_reader<kMissingParameterSize>(i * kMissingParameterSize);
+
+    missing_parameter_types.push_back(sub_reader.Load16<0>());
+  }
+  return MissingMandatoryParameterCause(missing_parameter_types);
+}
+
+void MissingMandatoryParameterCause::SerializeTo(
+    std::vector<uint8_t>& out) const {
+  size_t variable_size =
+      missing_parameter_types_.size() * kMissingParameterSize;
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, variable_size);
+
+  writer.Store32<4>(missing_parameter_types_.size());
+
+  for (size_t i = 0; i < missing_parameter_types_.size(); ++i) {
+    BoundedByteWriter<kMissingParameterSize> sub_writer =
+        writer.sub_writer<kMissingParameterSize>(i * kMissingParameterSize);
+
+    sub_writer.Store16<0>(missing_parameter_types_[i]);
+  }
+}
+
+std::string MissingMandatoryParameterCause::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "Missing Mandatory Parameter, missing_parameter_types="
+     << StrJoin(missing_parameter_types_, ",");
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/missing_mandatory_parameter_cause.h b/net/dcsctp/packet/error_cause/missing_mandatory_parameter_cause.h
new file mode 100644
index 0000000..4435424
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/missing_mandatory_parameter_cause.h
@@ -0,0 +1,60 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_ERROR_CAUSE_MISSING_MANDATORY_PARAMETER_CAUSE_H_
+#define NET_DCSCTP_PACKET_ERROR_CAUSE_MISSING_MANDATORY_PARAMETER_CAUSE_H_
+#include <stddef.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.2
+struct MissingMandatoryParameterCauseConfig : public ParameterConfig {
+  static constexpr int kType = 2;
+  static constexpr size_t kHeaderSize = 8;
+  static constexpr size_t kVariableLengthAlignment = 2;
+};
+
+class MissingMandatoryParameterCause
+    : public Parameter,
+      public TLVTrait<MissingMandatoryParameterCauseConfig> {
+ public:
+  static constexpr int kType = MissingMandatoryParameterCauseConfig::kType;
+
+  explicit MissingMandatoryParameterCause(
+      rtc::ArrayView<const uint16_t> missing_parameter_types)
+      : missing_parameter_types_(missing_parameter_types.begin(),
+                                 missing_parameter_types.end()) {}
+
+  static absl::optional<MissingMandatoryParameterCause> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  rtc::ArrayView<const uint16_t> missing_parameter_types() const {
+    return missing_parameter_types_;
+  }
+
+ private:
+  static constexpr size_t kMissingParameterSize = 2;
+  std::vector<uint16_t> missing_parameter_types_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_ERROR_CAUSE_MISSING_MANDATORY_PARAMETER_CAUSE_H_
diff --git a/net/dcsctp/packet/error_cause/missing_mandatory_parameter_cause_test.cc b/net/dcsctp/packet/error_cause/missing_mandatory_parameter_cause_test.cc
new file mode 100644
index 0000000..8c04340
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/missing_mandatory_parameter_cause_test.cc
@@ -0,0 +1,41 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/missing_mandatory_parameter_cause.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(MissingMandatoryParameterCauseTest, SerializeAndDeserialize) {
+  uint16_t parameter_types[] = {1, 2, 3};
+  MissingMandatoryParameterCause parameter(parameter_types);
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      MissingMandatoryParameterCause deserialized,
+      MissingMandatoryParameterCause::Parse(serialized));
+
+  EXPECT_THAT(deserialized.missing_parameter_types(), ElementsAre(1, 2, 3));
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/no_user_data_cause.cc b/net/dcsctp/packet/error_cause/no_user_data_cause.cc
new file mode 100644
index 0000000..2853915
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/no_user_data_cause.cc
@@ -0,0 +1,57 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/no_user_data_cause.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.9
+
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Cause Code=9              |      Cause Length=8           |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  /                  TSN value                                    /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int NoUserDataCause::kType;
+
+absl::optional<NoUserDataCause> NoUserDataCause::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  TSN tsn(reader->Load32<4>());
+  return NoUserDataCause(tsn);
+}
+
+void NoUserDataCause::SerializeTo(std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out);
+  writer.Store32<4>(*tsn_);
+}
+
+std::string NoUserDataCause::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "No User Data, tsn=" << *tsn_;
+  return sb.Release();
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/no_user_data_cause.h b/net/dcsctp/packet/error_cause/no_user_data_cause.h
new file mode 100644
index 0000000..1087dcc
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/no_user_data_cause.h
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_ERROR_CAUSE_NO_USER_DATA_CAUSE_H_
+#define NET_DCSCTP_PACKET_ERROR_CAUSE_NO_USER_DATA_CAUSE_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/internal_types.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.9
+struct NoUserDataCauseConfig : public ParameterConfig {
+  static constexpr int kType = 9;
+  static constexpr size_t kHeaderSize = 8;
+  static constexpr size_t kVariableLengthAlignment = 0;
+};
+
+class NoUserDataCause : public Parameter,
+                        public TLVTrait<NoUserDataCauseConfig> {
+ public:
+  static constexpr int kType = NoUserDataCauseConfig::kType;
+
+  explicit NoUserDataCause(TSN tsn) : tsn_(tsn) {}
+
+  static absl::optional<NoUserDataCause> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  TSN tsn() const { return tsn_; }
+
+ private:
+  TSN tsn_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_ERROR_CAUSE_NO_USER_DATA_CAUSE_H_
diff --git a/net/dcsctp/packet/error_cause/no_user_data_cause_test.cc b/net/dcsctp/packet/error_cause/no_user_data_cause_test.cc
new file mode 100644
index 0000000..0a535bf
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/no_user_data_cause_test.cc
@@ -0,0 +1,36 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/no_user_data_cause.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(NoUserDataCauseTest, SerializeAndDeserialize) {
+  NoUserDataCause parameter(TSN(123));
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(NoUserDataCause deserialized,
+                              NoUserDataCause::Parse(serialized));
+
+  EXPECT_EQ(*deserialized.tsn(), 123u);
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/out_of_resource_error_cause.cc b/net/dcsctp/packet/error_cause/out_of_resource_error_cause.cc
new file mode 100644
index 0000000..e5c7c0e
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/out_of_resource_error_cause.cc
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/out_of_resource_error_cause.h"
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.4
+
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Cause Code=4              |      Cause Length=4           |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int OutOfResourceErrorCause::kType;
+
+absl::optional<OutOfResourceErrorCause> OutOfResourceErrorCause::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  if (!ParseTLV(data).has_value()) {
+    return absl::nullopt;
+  }
+  return OutOfResourceErrorCause();
+}
+
+void OutOfResourceErrorCause::SerializeTo(std::vector<uint8_t>& out) const {
+  AllocateTLV(out);
+}
+
+std::string OutOfResourceErrorCause::ToString() const {
+  return "Out Of Resource";
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/out_of_resource_error_cause.h b/net/dcsctp/packet/error_cause/out_of_resource_error_cause.h
new file mode 100644
index 0000000..fc798ca
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/out_of_resource_error_cause.h
@@ -0,0 +1,48 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_ERROR_CAUSE_OUT_OF_RESOURCE_ERROR_CAUSE_H_
+#define NET_DCSCTP_PACKET_ERROR_CAUSE_OUT_OF_RESOURCE_ERROR_CAUSE_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.4
+struct OutOfResourceParameterConfig : public ParameterConfig {
+  static constexpr int kType = 4;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 0;
+};
+
+class OutOfResourceErrorCause : public Parameter,
+                                public TLVTrait<OutOfResourceParameterConfig> {
+ public:
+  static constexpr int kType = OutOfResourceParameterConfig::kType;
+
+  OutOfResourceErrorCause() {}
+
+  static absl::optional<OutOfResourceErrorCause> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_ERROR_CAUSE_OUT_OF_RESOURCE_ERROR_CAUSE_H_
diff --git a/net/dcsctp/packet/error_cause/out_of_resource_error_cause_test.cc b/net/dcsctp/packet/error_cause/out_of_resource_error_cause_test.cc
new file mode 100644
index 0000000..501fc20
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/out_of_resource_error_cause_test.cc
@@ -0,0 +1,34 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/out_of_resource_error_cause.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(OutOfResourceErrorCauseTest, SerializeAndDeserialize) {
+  OutOfResourceErrorCause parameter;
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(OutOfResourceErrorCause deserialized,
+                              OutOfResourceErrorCause::Parse(serialized));
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/protocol_violation_cause.cc b/net/dcsctp/packet/error_cause/protocol_violation_cause.cc
new file mode 100644
index 0000000..1b8d423
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/protocol_violation_cause.cc
@@ -0,0 +1,65 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/protocol_violation_cause.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.13
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |         Cause Code=13         |      Cause Length=Variable    |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  /                    Additional Information                     /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int ProtocolViolationCause::kType;
+
+absl::optional<ProtocolViolationCause> ProtocolViolationCause::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  return ProtocolViolationCause(
+      std::string(reinterpret_cast<const char*>(reader->variable_data().data()),
+                  reader->variable_data().size()));
+}
+
+void ProtocolViolationCause::SerializeTo(std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer =
+      AllocateTLV(out, additional_information_.size());
+  writer.CopyToVariableData(rtc::MakeArrayView(
+      reinterpret_cast<const uint8_t*>(additional_information_.data()),
+      additional_information_.size()));
+}
+
+std::string ProtocolViolationCause::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "Protocol Violation, additional_information="
+     << additional_information_;
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/protocol_violation_cause.h b/net/dcsctp/packet/error_cause/protocol_violation_cause.h
new file mode 100644
index 0000000..3081e1f
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/protocol_violation_cause.h
@@ -0,0 +1,56 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_ERROR_CAUSE_PROTOCOL_VIOLATION_CAUSE_H_
+#define NET_DCSCTP_PACKET_ERROR_CAUSE_PROTOCOL_VIOLATION_CAUSE_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.13
+struct ProtocolViolationCauseConfig : public ParameterConfig {
+  static constexpr int kType = 13;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class ProtocolViolationCause : public Parameter,
+                               public TLVTrait<ProtocolViolationCauseConfig> {
+ public:
+  static constexpr int kType = ProtocolViolationCauseConfig::kType;
+
+  explicit ProtocolViolationCause(absl::string_view additional_information)
+      : additional_information_(additional_information) {}
+
+  static absl::optional<ProtocolViolationCause> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  absl::string_view additional_information() const {
+    return additional_information_;
+  }
+
+ private:
+  std::string additional_information_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_ERROR_CAUSE_PROTOCOL_VIOLATION_CAUSE_H_
diff --git a/net/dcsctp/packet/error_cause/protocol_violation_cause_test.cc b/net/dcsctp/packet/error_cause/protocol_violation_cause_test.cc
new file mode 100644
index 0000000..902d867
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/protocol_violation_cause_test.cc
@@ -0,0 +1,61 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/protocol_violation_cause.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::SizeIs;
+
+TEST(ProtocolViolationCauseTest, EmptyReason) {
+  Parameters causes =
+      Parameters::Builder().Add(ProtocolViolationCause("")).Build();
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(Parameters deserialized,
+                              Parameters::Parse(causes.data()));
+  ASSERT_THAT(deserialized.descriptors(), SizeIs(1));
+  EXPECT_EQ(deserialized.descriptors()[0].type, ProtocolViolationCause::kType);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      ProtocolViolationCause cause,
+      ProtocolViolationCause::Parse(deserialized.descriptors()[0].data));
+
+  EXPECT_EQ(cause.additional_information(), "");
+}
+
+TEST(ProtocolViolationCauseTest, SetReason) {
+  Parameters causes = Parameters::Builder()
+                          .Add(ProtocolViolationCause("Reason goes here"))
+                          .Build();
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(Parameters deserialized,
+                              Parameters::Parse(causes.data()));
+  ASSERT_THAT(deserialized.descriptors(), SizeIs(1));
+  EXPECT_EQ(deserialized.descriptors()[0].type, ProtocolViolationCause::kType);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      ProtocolViolationCause cause,
+      ProtocolViolationCause::Parse(deserialized.descriptors()[0].data));
+
+  EXPECT_EQ(cause.additional_information(), "Reason goes here");
+}
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/restart_of_an_association_with_new_address_cause.cc b/net/dcsctp/packet/error_cause/restart_of_an_association_with_new_address_cause.cc
new file mode 100644
index 0000000..abe5de6
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/restart_of_an_association_with_new_address_cause.cc
@@ -0,0 +1,58 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/restart_of_an_association_with_new_address_cause.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.11
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |         Cause Code=11         |      Cause Length=Variable    |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  /                       New Address TLVs                        /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int RestartOfAnAssociationWithNewAddressesCause::kType;
+
+absl::optional<RestartOfAnAssociationWithNewAddressesCause>
+RestartOfAnAssociationWithNewAddressesCause::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  return RestartOfAnAssociationWithNewAddressesCause(reader->variable_data());
+}
+
+void RestartOfAnAssociationWithNewAddressesCause::SerializeTo(
+    std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer =
+      AllocateTLV(out, new_address_tlvs_.size());
+  writer.CopyToVariableData(new_address_tlvs_);
+}
+
+std::string RestartOfAnAssociationWithNewAddressesCause::ToString() const {
+  return "Restart of an Association with New Addresses";
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/restart_of_an_association_with_new_address_cause.h b/net/dcsctp/packet/error_cause/restart_of_an_association_with_new_address_cause.h
new file mode 100644
index 0000000..a1cccdc
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/restart_of_an_association_with_new_address_cause.h
@@ -0,0 +1,59 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_ERROR_CAUSE_RESTART_OF_AN_ASSOCIATION_WITH_NEW_ADDRESS_CAUSE_H_
+#define NET_DCSCTP_PACKET_ERROR_CAUSE_RESTART_OF_AN_ASSOCIATION_WITH_NEW_ADDRESS_CAUSE_H_
+#include <stddef.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.11
+struct RestartOfAnAssociationWithNewAddressesCauseConfig
+    : public ParameterConfig {
+  static constexpr int kType = 11;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class RestartOfAnAssociationWithNewAddressesCause
+    : public Parameter,
+      public TLVTrait<RestartOfAnAssociationWithNewAddressesCauseConfig> {
+ public:
+  static constexpr int kType =
+      RestartOfAnAssociationWithNewAddressesCauseConfig::kType;
+
+  explicit RestartOfAnAssociationWithNewAddressesCause(
+      rtc::ArrayView<const uint8_t> new_address_tlvs)
+      : new_address_tlvs_(new_address_tlvs.begin(), new_address_tlvs.end()) {}
+
+  static absl::optional<RestartOfAnAssociationWithNewAddressesCause> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  rtc::ArrayView<const uint8_t> new_address_tlvs() const {
+    return new_address_tlvs_;
+  }
+
+ private:
+  std::vector<uint8_t> new_address_tlvs_;
+};
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_ERROR_CAUSE_RESTART_OF_AN_ASSOCIATION_WITH_NEW_ADDRESS_CAUSE_H_
diff --git a/net/dcsctp/packet/error_cause/restart_of_an_association_with_new_address_cause_test.cc b/net/dcsctp/packet/error_cause/restart_of_an_association_with_new_address_cause_test.cc
new file mode 100644
index 0000000..b8ab8b6
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/restart_of_an_association_with_new_address_cause_test.cc
@@ -0,0 +1,41 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/restart_of_an_association_with_new_address_cause.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(RestartOfAnAssociationWithNewAddressesCauseTest, SerializeAndDeserialize) {
+  uint8_t data[] = {1, 2, 3};
+  RestartOfAnAssociationWithNewAddressesCause parameter(data);
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      RestartOfAnAssociationWithNewAddressesCause deserialized,
+      RestartOfAnAssociationWithNewAddressesCause::Parse(serialized));
+
+  EXPECT_THAT(deserialized.new_address_tlvs(), ElementsAre(1, 2, 3));
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/stale_cookie_error_cause.cc b/net/dcsctp/packet/error_cause/stale_cookie_error_cause.cc
new file mode 100644
index 0000000..d77d848
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/stale_cookie_error_cause.cc
@@ -0,0 +1,57 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/stale_cookie_error_cause.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.3
+
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Cause Code=3              |       Cause Length=8          |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                 Measure of Staleness (usec.)                  |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int StaleCookieErrorCause::kType;
+
+absl::optional<StaleCookieErrorCause> StaleCookieErrorCause::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  uint32_t staleness_us = reader->Load32<4>();
+  return StaleCookieErrorCause(staleness_us);
+}
+
+void StaleCookieErrorCause::SerializeTo(std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out);
+  writer.Store32<4>(staleness_us_);
+}
+
+std::string StaleCookieErrorCause::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "Stale Cookie Error, staleness_us=" << staleness_us_;
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/stale_cookie_error_cause.h b/net/dcsctp/packet/error_cause/stale_cookie_error_cause.h
new file mode 100644
index 0000000..d8b7b5b
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/stale_cookie_error_cause.h
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_ERROR_CAUSE_STALE_COOKIE_ERROR_CAUSE_H_
+#define NET_DCSCTP_PACKET_ERROR_CAUSE_STALE_COOKIE_ERROR_CAUSE_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.3
+struct StaleCookieParameterConfig : public ParameterConfig {
+  static constexpr int kType = 3;
+  static constexpr size_t kHeaderSize = 8;
+  static constexpr size_t kVariableLengthAlignment = 0;
+};
+
+class StaleCookieErrorCause : public Parameter,
+                              public TLVTrait<StaleCookieParameterConfig> {
+ public:
+  static constexpr int kType = StaleCookieParameterConfig::kType;
+
+  explicit StaleCookieErrorCause(uint32_t staleness_us)
+      : staleness_us_(staleness_us) {}
+
+  static absl::optional<StaleCookieErrorCause> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  uint16_t staleness_us() const { return staleness_us_; }
+
+ private:
+  uint32_t staleness_us_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_ERROR_CAUSE_STALE_COOKIE_ERROR_CAUSE_H_
diff --git a/net/dcsctp/packet/error_cause/stale_cookie_error_cause_test.cc b/net/dcsctp/packet/error_cause/stale_cookie_error_cause_test.cc
new file mode 100644
index 0000000..c0d1ac1
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/stale_cookie_error_cause_test.cc
@@ -0,0 +1,35 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/stale_cookie_error_cause.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(StaleCookieErrorCauseTest, SerializeAndDeserialize) {
+  StaleCookieErrorCause parameter(123);
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(StaleCookieErrorCause deserialized,
+                              StaleCookieErrorCause::Parse(serialized));
+
+  EXPECT_EQ(deserialized.staleness_us(), 123);
+}
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause.cc b/net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause.cc
new file mode 100644
index 0000000..04b960d
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause.cc
@@ -0,0 +1,64 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause.h"
+
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.6
+
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Cause Code=6              |      Cause Length             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  /                  Unrecognized Chunk                           /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int UnrecognizedChunkTypeCause::kType;
+
+absl::optional<UnrecognizedChunkTypeCause> UnrecognizedChunkTypeCause::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  std::vector<uint8_t> unrecognized_chunk(reader->variable_data().begin(),
+                                          reader->variable_data().end());
+  return UnrecognizedChunkTypeCause(std::move(unrecognized_chunk));
+}
+
+void UnrecognizedChunkTypeCause::SerializeTo(std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer =
+      AllocateTLV(out, unrecognized_chunk_.size());
+  writer.CopyToVariableData(unrecognized_chunk_);
+}
+
+std::string UnrecognizedChunkTypeCause::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "Unrecognized Chunk Type, chunk_type=";
+  if (!unrecognized_chunk_.empty()) {
+    sb << static_cast<int>(unrecognized_chunk_[0]);
+  } else {
+    sb << "<missing>";
+  }
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause.h b/net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause.h
new file mode 100644
index 0000000..26d3d3b
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause.h
@@ -0,0 +1,59 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_ERROR_CAUSE_UNRECOGNIZED_CHUNK_TYPE_CAUSE_H_
+#define NET_DCSCTP_PACKET_ERROR_CAUSE_UNRECOGNIZED_CHUNK_TYPE_CAUSE_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.6
+struct UnrecognizedChunkTypeCauseConfig : public ParameterConfig {
+  static constexpr int kType = 6;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class UnrecognizedChunkTypeCause
+    : public Parameter,
+      public TLVTrait<UnrecognizedChunkTypeCauseConfig> {
+ public:
+  static constexpr int kType = UnrecognizedChunkTypeCauseConfig::kType;
+
+  explicit UnrecognizedChunkTypeCause(std::vector<uint8_t> unrecognized_chunk)
+      : unrecognized_chunk_(std::move(unrecognized_chunk)) {}
+
+  static absl::optional<UnrecognizedChunkTypeCause> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  rtc::ArrayView<const uint8_t> unrecognized_chunk() const {
+    return unrecognized_chunk_;
+  }
+
+ private:
+  std::vector<uint8_t> unrecognized_chunk_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_ERROR_CAUSE_UNRECOGNIZED_CHUNK_TYPE_CAUSE_H_
diff --git a/net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause_test.cc b/net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause_test.cc
new file mode 100644
index 0000000..baff852
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause_test.cc
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause.h"
+
+#include <cstdint>
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(UnrecognizedChunkTypeCauseTest, SerializeAndDeserialize) {
+  UnrecognizedChunkTypeCause parameter({1, 2, 3});
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(UnrecognizedChunkTypeCause deserialized,
+                              UnrecognizedChunkTypeCause::Parse(serialized));
+
+  EXPECT_THAT(deserialized.unrecognized_chunk(), ElementsAre(1, 2, 3));
+}
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/unrecognized_parameter_cause.cc b/net/dcsctp/packet/error_cause/unrecognized_parameter_cause.cc
new file mode 100644
index 0000000..80001a9
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/unrecognized_parameter_cause.cc
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/unrecognized_parameter_cause.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.8
+
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Cause Code=8              |      Cause Length             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  /                  Unrecognized Parameters                      /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int UnrecognizedParametersCause::kType;
+
+absl::optional<UnrecognizedParametersCause> UnrecognizedParametersCause::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  return UnrecognizedParametersCause(reader->variable_data());
+}
+
+void UnrecognizedParametersCause::SerializeTo(std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer =
+      AllocateTLV(out, unrecognized_parameters_.size());
+  writer.CopyToVariableData(unrecognized_parameters_);
+}
+
+std::string UnrecognizedParametersCause::ToString() const {
+  return "Unrecognized Parameters";
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/unrecognized_parameter_cause.h b/net/dcsctp/packet/error_cause/unrecognized_parameter_cause.h
new file mode 100644
index 0000000..ebec5ed
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/unrecognized_parameter_cause.h
@@ -0,0 +1,60 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_ERROR_CAUSE_UNRECOGNIZED_PARAMETER_CAUSE_H_
+#define NET_DCSCTP_PACKET_ERROR_CAUSE_UNRECOGNIZED_PARAMETER_CAUSE_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.8
+struct UnrecognizedParametersCauseConfig : public ParameterConfig {
+  static constexpr int kType = 8;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class UnrecognizedParametersCause
+    : public Parameter,
+      public TLVTrait<UnrecognizedParametersCauseConfig> {
+ public:
+  static constexpr int kType = UnrecognizedParametersCauseConfig::kType;
+
+  explicit UnrecognizedParametersCause(
+      rtc::ArrayView<const uint8_t> unrecognized_parameters)
+      : unrecognized_parameters_(unrecognized_parameters.begin(),
+                                 unrecognized_parameters.end()) {}
+
+  static absl::optional<UnrecognizedParametersCause> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  rtc::ArrayView<const uint8_t> unrecognized_parameters() const {
+    return unrecognized_parameters_;
+  }
+
+ private:
+  std::vector<uint8_t> unrecognized_parameters_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_ERROR_CAUSE_UNRECOGNIZED_PARAMETER_CAUSE_H_
diff --git a/net/dcsctp/packet/error_cause/unrecognized_parameter_cause_test.cc b/net/dcsctp/packet/error_cause/unrecognized_parameter_cause_test.cc
new file mode 100644
index 0000000..0449599
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/unrecognized_parameter_cause_test.cc
@@ -0,0 +1,39 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/unrecognized_parameter_cause.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(UnrecognizedParametersCauseTest, SerializeAndDeserialize) {
+  uint8_t unrecognized_parameters[] = {1, 2, 3};
+  UnrecognizedParametersCause parameter(unrecognized_parameters);
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(UnrecognizedParametersCause deserialized,
+                              UnrecognizedParametersCause::Parse(serialized));
+
+  EXPECT_THAT(deserialized.unrecognized_parameters(), ElementsAre(1, 2, 3));
+}
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/unresolvable_address_cause.cc b/net/dcsctp/packet/error_cause/unresolvable_address_cause.cc
new file mode 100644
index 0000000..8108d31
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/unresolvable_address_cause.cc
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/unresolvable_address_cause.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.5
+
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Cause Code=5              |      Cause Length             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  /                  Unresolvable Address                         /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int UnresolvableAddressCause::kType;
+
+absl::optional<UnresolvableAddressCause> UnresolvableAddressCause::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  return UnresolvableAddressCause(reader->variable_data());
+}
+
+void UnresolvableAddressCause::SerializeTo(std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer =
+      AllocateTLV(out, unresolvable_address_.size());
+  writer.CopyToVariableData(unresolvable_address_);
+}
+
+std::string UnresolvableAddressCause::ToString() const {
+  return "Unresolvable Address";
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/unresolvable_address_cause.h b/net/dcsctp/packet/error_cause/unresolvable_address_cause.h
new file mode 100644
index 0000000..c63b377
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/unresolvable_address_cause.h
@@ -0,0 +1,60 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_ERROR_CAUSE_UNRESOLVABLE_ADDRESS_CAUSE_H_
+#define NET_DCSCTP_PACKET_ERROR_CAUSE_UNRESOLVABLE_ADDRESS_CAUSE_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.5
+struct UnresolvableAddressCauseConfig : public ParameterConfig {
+  static constexpr int kType = 5;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class UnresolvableAddressCause
+    : public Parameter,
+      public TLVTrait<UnresolvableAddressCauseConfig> {
+ public:
+  static constexpr int kType = UnresolvableAddressCauseConfig::kType;
+
+  explicit UnresolvableAddressCause(
+      rtc::ArrayView<const uint8_t> unresolvable_address)
+      : unresolvable_address_(unresolvable_address.begin(),
+                              unresolvable_address.end()) {}
+
+  static absl::optional<UnresolvableAddressCause> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  rtc::ArrayView<const uint8_t> unresolvable_address() const {
+    return unresolvable_address_;
+  }
+
+ private:
+  std::vector<uint8_t> unresolvable_address_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_ERROR_CAUSE_UNRESOLVABLE_ADDRESS_CAUSE_H_
diff --git a/net/dcsctp/packet/error_cause/unresolvable_address_cause_test.cc b/net/dcsctp/packet/error_cause/unresolvable_address_cause_test.cc
new file mode 100644
index 0000000..688730e
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/unresolvable_address_cause_test.cc
@@ -0,0 +1,39 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/unresolvable_address_cause.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(UnresolvableAddressCauseTest, SerializeAndDeserialize) {
+  uint8_t unresolvable_address[] = {1, 2, 3};
+  UnresolvableAddressCause parameter(unresolvable_address);
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(UnresolvableAddressCause deserialized,
+                              UnresolvableAddressCause::Parse(serialized));
+
+  EXPECT_THAT(deserialized.unresolvable_address(), ElementsAre(1, 2, 3));
+}
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/user_initiated_abort_cause.cc b/net/dcsctp/packet/error_cause/user_initiated_abort_cause.cc
new file mode 100644
index 0000000..da99aac
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/user_initiated_abort_cause.cc
@@ -0,0 +1,67 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/user_initiated_abort_cause.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.12
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |         Cause Code=12         |      Cause Length=Variable    |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  /                    Upper Layer Abort Reason                   /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int UserInitiatedAbortCause::kType;
+
+absl::optional<UserInitiatedAbortCause> UserInitiatedAbortCause::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  if (reader->variable_data().empty()) {
+    return UserInitiatedAbortCause("");
+  }
+  return UserInitiatedAbortCause(
+      std::string(reinterpret_cast<const char*>(reader->variable_data().data()),
+                  reader->variable_data().size()));
+}
+
+void UserInitiatedAbortCause::SerializeTo(std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer =
+      AllocateTLV(out, upper_layer_abort_reason_.size());
+  writer.CopyToVariableData(rtc::MakeArrayView(
+      reinterpret_cast<const uint8_t*>(upper_layer_abort_reason_.data()),
+      upper_layer_abort_reason_.size()));
+}
+
+std::string UserInitiatedAbortCause::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "User-Initiated Abort, reason=" << upper_layer_abort_reason_;
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/error_cause/user_initiated_abort_cause.h b/net/dcsctp/packet/error_cause/user_initiated_abort_cause.h
new file mode 100644
index 0000000..9eb1665
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/user_initiated_abort_cause.h
@@ -0,0 +1,56 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_ERROR_CAUSE_USER_INITIATED_ABORT_CAUSE_H_
+#define NET_DCSCTP_PACKET_ERROR_CAUSE_USER_INITIATED_ABORT_CAUSE_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.10.12
+struct UserInitiatedAbortCauseConfig : public ParameterConfig {
+  static constexpr int kType = 12;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class UserInitiatedAbortCause : public Parameter,
+                                public TLVTrait<UserInitiatedAbortCauseConfig> {
+ public:
+  static constexpr int kType = UserInitiatedAbortCauseConfig::kType;
+
+  explicit UserInitiatedAbortCause(absl::string_view upper_layer_abort_reason)
+      : upper_layer_abort_reason_(upper_layer_abort_reason) {}
+
+  static absl::optional<UserInitiatedAbortCause> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  absl::string_view upper_layer_abort_reason() const {
+    return upper_layer_abort_reason_;
+  }
+
+ private:
+  std::string upper_layer_abort_reason_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_ERROR_CAUSE_USER_INITIATED_ABORT_CAUSE_H_
diff --git a/net/dcsctp/packet/error_cause/user_initiated_abort_cause_test.cc b/net/dcsctp/packet/error_cause/user_initiated_abort_cause_test.cc
new file mode 100644
index 0000000..250959e
--- /dev/null
+++ b/net/dcsctp/packet/error_cause/user_initiated_abort_cause_test.cc
@@ -0,0 +1,62 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/error_cause/user_initiated_abort_cause.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/packet/error_cause/error_cause.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::SizeIs;
+
+TEST(UserInitiatedAbortCauseTest, EmptyReason) {
+  Parameters causes =
+      Parameters::Builder().Add(UserInitiatedAbortCause("")).Build();
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(Parameters deserialized,
+                              Parameters::Parse(causes.data()));
+  ASSERT_THAT(deserialized.descriptors(), SizeIs(1));
+  EXPECT_EQ(deserialized.descriptors()[0].type, UserInitiatedAbortCause::kType);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      UserInitiatedAbortCause cause,
+      UserInitiatedAbortCause::Parse(deserialized.descriptors()[0].data));
+
+  EXPECT_EQ(cause.upper_layer_abort_reason(), "");
+}
+
+TEST(UserInitiatedAbortCauseTest, SetReason) {
+  Parameters causes = Parameters::Builder()
+                          .Add(UserInitiatedAbortCause("User called Close"))
+                          .Build();
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(Parameters deserialized,
+                              Parameters::Parse(causes.data()));
+  ASSERT_THAT(deserialized.descriptors(), SizeIs(1));
+  EXPECT_EQ(deserialized.descriptors()[0].type, UserInitiatedAbortCause::kType);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      UserInitiatedAbortCause cause,
+      UserInitiatedAbortCause::Parse(deserialized.descriptors()[0].data));
+
+  EXPECT_EQ(cause.upper_layer_abort_reason(), "User called Close");
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/add_incoming_streams_request_parameter.cc b/net/dcsctp/packet/parameter/add_incoming_streams_request_parameter.cc
new file mode 100644
index 0000000..c33e3e1
--- /dev/null
+++ b/net/dcsctp/packet/parameter/add_incoming_streams_request_parameter.cc
@@ -0,0 +1,68 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/add_incoming_streams_request_parameter.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/internal_types.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc6525#section-4.6
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Parameter Type = 18       |      Parameter Length = 12    |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |          Re-configuration Request Sequence Number             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |      Number of new streams    |         Reserved              |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int AddIncomingStreamsRequestParameter::kType;
+
+absl::optional<AddIncomingStreamsRequestParameter>
+AddIncomingStreamsRequestParameter::Parse(rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  ReconfigRequestSN request_sequence_number(reader->Load32<4>());
+  uint16_t nbr_of_new_streams = reader->Load16<8>();
+
+  return AddIncomingStreamsRequestParameter(request_sequence_number,
+                                            nbr_of_new_streams);
+}
+
+void AddIncomingStreamsRequestParameter::SerializeTo(
+    std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out);
+  writer.Store32<4>(*request_sequence_number_);
+  writer.Store16<8>(nbr_of_new_streams_);
+}
+
+std::string AddIncomingStreamsRequestParameter::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "Add Incoming Streams Request, req_seq_nbr="
+     << *request_sequence_number();
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/add_incoming_streams_request_parameter.h b/net/dcsctp/packet/parameter/add_incoming_streams_request_parameter.h
new file mode 100644
index 0000000..3859eb3
--- /dev/null
+++ b/net/dcsctp/packet/parameter/add_incoming_streams_request_parameter.h
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_PARAMETER_ADD_INCOMING_STREAMS_REQUEST_PARAMETER_H_
+#define NET_DCSCTP_PACKET_PARAMETER_ADD_INCOMING_STREAMS_REQUEST_PARAMETER_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/internal_types.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc6525#section-4.6
+struct AddIncomingStreamsRequestParameterConfig : ParameterConfig {
+  static constexpr int kType = 18;
+  static constexpr size_t kHeaderSize = 12;
+  static constexpr size_t kVariableLengthAlignment = 0;
+};
+
+class AddIncomingStreamsRequestParameter
+    : public Parameter,
+      public TLVTrait<AddIncomingStreamsRequestParameterConfig> {
+ public:
+  static constexpr int kType = AddIncomingStreamsRequestParameterConfig::kType;
+
+  explicit AddIncomingStreamsRequestParameter(
+      ReconfigRequestSN request_sequence_number,
+      uint16_t nbr_of_new_streams)
+      : request_sequence_number_(request_sequence_number),
+        nbr_of_new_streams_(nbr_of_new_streams) {}
+
+  static absl::optional<AddIncomingStreamsRequestParameter> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  ReconfigRequestSN request_sequence_number() const {
+    return request_sequence_number_;
+  }
+  uint16_t nbr_of_new_streams() const { return nbr_of_new_streams_; }
+
+ private:
+  ReconfigRequestSN request_sequence_number_;
+  uint16_t nbr_of_new_streams_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_PARAMETER_ADD_INCOMING_STREAMS_REQUEST_PARAMETER_H_
diff --git a/net/dcsctp/packet/parameter/add_incoming_streams_request_parameter_test.cc b/net/dcsctp/packet/parameter/add_incoming_streams_request_parameter_test.cc
new file mode 100644
index 0000000..a29257a
--- /dev/null
+++ b/net/dcsctp/packet/parameter/add_incoming_streams_request_parameter_test.cc
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/add_incoming_streams_request_parameter.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(AddIncomingStreamsRequestParameterTest, SerializeAndDeserialize) {
+  AddIncomingStreamsRequestParameter parameter(ReconfigRequestSN(1), 2);
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      AddIncomingStreamsRequestParameter deserialized,
+      AddIncomingStreamsRequestParameter::Parse(serialized));
+
+  EXPECT_EQ(*deserialized.request_sequence_number(), 1u);
+  EXPECT_EQ(deserialized.nbr_of_new_streams(), 2u);
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/add_outgoing_streams_request_parameter.cc b/net/dcsctp/packet/parameter/add_outgoing_streams_request_parameter.cc
new file mode 100644
index 0000000..4787ee9
--- /dev/null
+++ b/net/dcsctp/packet/parameter/add_outgoing_streams_request_parameter.cc
@@ -0,0 +1,67 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/add_outgoing_streams_request_parameter.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc6525#section-4.5
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Parameter Type = 17       |      Parameter Length = 12    |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |          Re-configuration Request Sequence Number             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |      Number of new streams    |         Reserved              |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int AddOutgoingStreamsRequestParameter::kType;
+
+absl::optional<AddOutgoingStreamsRequestParameter>
+AddOutgoingStreamsRequestParameter::Parse(rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  ReconfigRequestSN request_sequence_number(reader->Load32<4>());
+  uint16_t nbr_of_new_streams = reader->Load16<8>();
+
+  return AddOutgoingStreamsRequestParameter(request_sequence_number,
+                                            nbr_of_new_streams);
+}
+
+void AddOutgoingStreamsRequestParameter::SerializeTo(
+    std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out);
+  writer.Store32<4>(*request_sequence_number_);
+  writer.Store16<8>(nbr_of_new_streams_);
+}
+
+std::string AddOutgoingStreamsRequestParameter::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "Add Outgoing Streams Request, req_seq_nbr="
+     << *request_sequence_number();
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/add_outgoing_streams_request_parameter.h b/net/dcsctp/packet/parameter/add_outgoing_streams_request_parameter.h
new file mode 100644
index 0000000..01e8f91
--- /dev/null
+++ b/net/dcsctp/packet/parameter/add_outgoing_streams_request_parameter.h
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_PARAMETER_ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_H_
+#define NET_DCSCTP_PACKET_PARAMETER_ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/internal_types.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc6525#section-4.5
+struct AddOutgoingStreamsRequestParameterConfig : ParameterConfig {
+  static constexpr int kType = 17;
+  static constexpr size_t kHeaderSize = 12;
+  static constexpr size_t kVariableLengthAlignment = 0;
+};
+
+class AddOutgoingStreamsRequestParameter
+    : public Parameter,
+      public TLVTrait<AddOutgoingStreamsRequestParameterConfig> {
+ public:
+  static constexpr int kType = AddOutgoingStreamsRequestParameterConfig::kType;
+
+  explicit AddOutgoingStreamsRequestParameter(
+      ReconfigRequestSN request_sequence_number,
+      uint16_t nbr_of_new_streams)
+      : request_sequence_number_(request_sequence_number),
+        nbr_of_new_streams_(nbr_of_new_streams) {}
+
+  static absl::optional<AddOutgoingStreamsRequestParameter> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  ReconfigRequestSN request_sequence_number() const {
+    return request_sequence_number_;
+  }
+  uint16_t nbr_of_new_streams() const { return nbr_of_new_streams_; }
+
+ private:
+  ReconfigRequestSN request_sequence_number_;
+  uint16_t nbr_of_new_streams_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_PARAMETER_ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_H_
diff --git a/net/dcsctp/packet/parameter/add_outgoing_streams_request_parameter_test.cc b/net/dcsctp/packet/parameter/add_outgoing_streams_request_parameter_test.cc
new file mode 100644
index 0000000..d0303b1
--- /dev/null
+++ b/net/dcsctp/packet/parameter/add_outgoing_streams_request_parameter_test.cc
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/add_outgoing_streams_request_parameter.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(AddOutgoingStreamsRequestParameterTest, SerializeAndDeserialize) {
+  AddOutgoingStreamsRequestParameter parameter(ReconfigRequestSN(1), 2);
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      AddOutgoingStreamsRequestParameter deserialized,
+      AddOutgoingStreamsRequestParameter::Parse(serialized));
+
+  EXPECT_EQ(*deserialized.request_sequence_number(), 1u);
+  EXPECT_EQ(deserialized.nbr_of_new_streams(), 2u);
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/forward_tsn_supported_parameter.cc b/net/dcsctp/packet/parameter/forward_tsn_supported_parameter.cc
new file mode 100644
index 0000000..7dd8e19
--- /dev/null
+++ b/net/dcsctp/packet/parameter/forward_tsn_supported_parameter.cc
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/forward_tsn_supported_parameter.h"
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc3758#section-3.1
+
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |    Parameter Type = 49152     |  Parameter Length = 4         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int ForwardTsnSupportedParameter::kType;
+
+absl::optional<ForwardTsnSupportedParameter>
+ForwardTsnSupportedParameter::Parse(rtc::ArrayView<const uint8_t> data) {
+  if (!ParseTLV(data).has_value()) {
+    return absl::nullopt;
+  }
+  return ForwardTsnSupportedParameter();
+}
+
+void ForwardTsnSupportedParameter::SerializeTo(
+    std::vector<uint8_t>& out) const {
+  AllocateTLV(out);
+}
+
+std::string ForwardTsnSupportedParameter::ToString() const {
+  return "Forward TSN Supported";
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/forward_tsn_supported_parameter.h b/net/dcsctp/packet/parameter/forward_tsn_supported_parameter.h
new file mode 100644
index 0000000..d4cff4a
--- /dev/null
+++ b/net/dcsctp/packet/parameter/forward_tsn_supported_parameter.h
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_PARAMETER_FORWARD_TSN_SUPPORTED_PARAMETER_H_
+#define NET_DCSCTP_PACKET_PARAMETER_FORWARD_TSN_SUPPORTED_PARAMETER_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc3758#section-3.1
+struct ForwardTsnSupportedParameterConfig : ParameterConfig {
+  static constexpr int kType = 49152;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 0;
+};
+
+class ForwardTsnSupportedParameter
+    : public Parameter,
+      public TLVTrait<ForwardTsnSupportedParameterConfig> {
+ public:
+  static constexpr int kType = ForwardTsnSupportedParameterConfig::kType;
+
+  ForwardTsnSupportedParameter() {}
+
+  static absl::optional<ForwardTsnSupportedParameter> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_PARAMETER_FORWARD_TSN_SUPPORTED_PARAMETER_H_
diff --git a/net/dcsctp/packet/parameter/forward_tsn_supported_parameter_test.cc b/net/dcsctp/packet/parameter/forward_tsn_supported_parameter_test.cc
new file mode 100644
index 0000000..fb4f983
--- /dev/null
+++ b/net/dcsctp/packet/parameter/forward_tsn_supported_parameter_test.cc
@@ -0,0 +1,34 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/forward_tsn_supported_parameter.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(ForwardTsnSupportedParameterTest, SerializeAndDeserialize) {
+  ForwardTsnSupportedParameter parameter;
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(ForwardTsnSupportedParameter deserialized,
+                              ForwardTsnSupportedParameter::Parse(serialized));
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/heartbeat_info_parameter.cc b/net/dcsctp/packet/parameter/heartbeat_info_parameter.cc
new file mode 100644
index 0000000..918976d
--- /dev/null
+++ b/net/dcsctp/packet/parameter/heartbeat_info_parameter.cc
@@ -0,0 +1,60 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/heartbeat_info_parameter.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.5
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   Type = 4    | Chunk  Flags  |      Heartbeat Length         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  \                                                               \
+//  /            Heartbeat Information TLV (Variable-Length)        /
+//  \                                                               \
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int HeartbeatInfoParameter::kType;
+
+absl::optional<HeartbeatInfoParameter> HeartbeatInfoParameter::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  return HeartbeatInfoParameter(reader->variable_data());
+}
+
+void HeartbeatInfoParameter::SerializeTo(std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, info_.size());
+  writer.CopyToVariableData(info_);
+}
+
+std::string HeartbeatInfoParameter::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "Heartbeat Info parameter (info_length=" << info_.size() << ")";
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/heartbeat_info_parameter.h b/net/dcsctp/packet/parameter/heartbeat_info_parameter.h
new file mode 100644
index 0000000..ec503a94
--- /dev/null
+++ b/net/dcsctp/packet/parameter/heartbeat_info_parameter.h
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_PARAMETER_HEARTBEAT_INFO_PARAMETER_H_
+#define NET_DCSCTP_PACKET_PARAMETER_HEARTBEAT_INFO_PARAMETER_H_
+#include <stddef.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.5
+struct HeartbeatInfoParameterConfig : ParameterConfig {
+  static constexpr int kType = 1;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class HeartbeatInfoParameter : public Parameter,
+                               public TLVTrait<HeartbeatInfoParameterConfig> {
+ public:
+  static constexpr int kType = HeartbeatInfoParameterConfig::kType;
+
+  explicit HeartbeatInfoParameter(rtc::ArrayView<const uint8_t> info)
+      : info_(info.begin(), info.end()) {}
+
+  static absl::optional<HeartbeatInfoParameter> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  rtc::ArrayView<const uint8_t> info() const { return info_; }
+
+ private:
+  std::vector<uint8_t> info_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_PARAMETER_HEARTBEAT_INFO_PARAMETER_H_
diff --git a/net/dcsctp/packet/parameter/incoming_ssn_reset_request_parameter.cc b/net/dcsctp/packet/parameter/incoming_ssn_reset_request_parameter.cc
new file mode 100644
index 0000000..6191adf
--- /dev/null
+++ b/net/dcsctp/packet/parameter/incoming_ssn_reset_request_parameter.cc
@@ -0,0 +1,89 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/incoming_ssn_reset_request_parameter.h"
+
+#include <stddef.h>
+
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc6525#section-4.2
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Parameter Type = 14       |  Parameter Length = 8 + 2 * N |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |          Re-configuration Request Sequence Number             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |  Stream Number 1 (optional)   |    Stream Number 2 (optional) |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  /                            ......                             /
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |  Stream Number N-1 (optional) |    Stream Number N (optional) |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int IncomingSSNResetRequestParameter::kType;
+
+absl::optional<IncomingSSNResetRequestParameter>
+IncomingSSNResetRequestParameter::Parse(rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+
+  ReconfigRequestSN request_sequence_number(reader->Load32<4>());
+
+  size_t stream_count = reader->variable_data_size() / kStreamIdSize;
+  std::vector<StreamID> stream_ids;
+  stream_ids.reserve(stream_count);
+  for (size_t i = 0; i < stream_count; ++i) {
+    BoundedByteReader<kStreamIdSize> sub_reader =
+        reader->sub_reader<kStreamIdSize>(i * kStreamIdSize);
+
+    stream_ids.push_back(StreamID(sub_reader.Load16<0>()));
+  }
+
+  return IncomingSSNResetRequestParameter(request_sequence_number,
+                                          std::move(stream_ids));
+}
+
+void IncomingSSNResetRequestParameter::SerializeTo(
+    std::vector<uint8_t>& out) const {
+  size_t variable_size = stream_ids_.size() * kStreamIdSize;
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, variable_size);
+
+  writer.Store32<4>(*request_sequence_number_);
+
+  for (size_t i = 0; i < stream_ids_.size(); ++i) {
+    BoundedByteWriter<kStreamIdSize> sub_writer =
+        writer.sub_writer<kStreamIdSize>(i * kStreamIdSize);
+    sub_writer.Store16<0>(*stream_ids_[i]);
+  }
+}
+
+std::string IncomingSSNResetRequestParameter::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "Incoming SSN Reset Request, req_seq_nbr="
+     << *request_sequence_number();
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/incoming_ssn_reset_request_parameter.h b/net/dcsctp/packet/parameter/incoming_ssn_reset_request_parameter.h
new file mode 100644
index 0000000..18963ef
--- /dev/null
+++ b/net/dcsctp/packet/parameter/incoming_ssn_reset_request_parameter.h
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_PARAMETER_INCOMING_SSN_RESET_REQUEST_PARAMETER_H_
+#define NET_DCSCTP_PACKET_PARAMETER_INCOMING_SSN_RESET_REQUEST_PARAMETER_H_
+#include <stddef.h>
+
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/internal_types.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/public/types.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc6525#section-4.2
+struct IncomingSSNResetRequestParameterConfig : ParameterConfig {
+  static constexpr int kType = 14;
+  static constexpr size_t kHeaderSize = 8;
+  static constexpr size_t kVariableLengthAlignment = 2;
+};
+
+class IncomingSSNResetRequestParameter
+    : public Parameter,
+      public TLVTrait<IncomingSSNResetRequestParameterConfig> {
+ public:
+  static constexpr int kType = IncomingSSNResetRequestParameterConfig::kType;
+
+  explicit IncomingSSNResetRequestParameter(
+      ReconfigRequestSN request_sequence_number,
+      std::vector<StreamID> stream_ids)
+      : request_sequence_number_(request_sequence_number),
+        stream_ids_(std::move(stream_ids)) {}
+
+  static absl::optional<IncomingSSNResetRequestParameter> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  ReconfigRequestSN request_sequence_number() const {
+    return request_sequence_number_;
+  }
+  rtc::ArrayView<const StreamID> stream_ids() const { return stream_ids_; }
+
+ private:
+  static constexpr size_t kStreamIdSize = sizeof(uint16_t);
+
+  ReconfigRequestSN request_sequence_number_;
+  std::vector<StreamID> stream_ids_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_PARAMETER_INCOMING_SSN_RESET_REQUEST_PARAMETER_H_
diff --git a/net/dcsctp/packet/parameter/incoming_ssn_reset_request_parameter_test.cc b/net/dcsctp/packet/parameter/incoming_ssn_reset_request_parameter_test.cc
new file mode 100644
index 0000000..17793f6
--- /dev/null
+++ b/net/dcsctp/packet/parameter/incoming_ssn_reset_request_parameter_test.cc
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/incoming_ssn_reset_request_parameter.h"
+
+#include <cstdint>
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(IncomingSSNResetRequestParameterTest, SerializeAndDeserialize) {
+  IncomingSSNResetRequestParameter parameter(
+      ReconfigRequestSN(1), {StreamID(2), StreamID(3), StreamID(4)});
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      IncomingSSNResetRequestParameter deserialized,
+      IncomingSSNResetRequestParameter::Parse(serialized));
+
+  EXPECT_EQ(*deserialized.request_sequence_number(), 1u);
+  EXPECT_THAT(deserialized.stream_ids(),
+              ElementsAre(StreamID(2), StreamID(3), StreamID(4)));
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.cc b/net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.cc
new file mode 100644
index 0000000..5c0797e
--- /dev/null
+++ b/net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.cc
@@ -0,0 +1,101 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h"
+
+#include <stddef.h>
+
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/internal_types.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "net/dcsctp/public/types.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc6525#section-4.1
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Parameter Type = 13       | Parameter Length = 16 + 2 * N |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |           Re-configuration Request Sequence Number            |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |           Re-configuration Response Sequence Number           |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                Sender's Last Assigned TSN                     |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |  Stream Number 1 (optional)   |    Stream Number 2 (optional) |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  /                            ......                             /
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |  Stream Number N-1 (optional) |    Stream Number N (optional) |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int OutgoingSSNResetRequestParameter::kType;
+
+absl::optional<OutgoingSSNResetRequestParameter>
+OutgoingSSNResetRequestParameter::Parse(rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+
+  ReconfigRequestSN request_sequence_number(reader->Load32<4>());
+  ReconfigResponseSN response_sequence_number(reader->Load32<8>());
+  TSN sender_last_assigned_tsn(reader->Load32<12>());
+
+  size_t stream_count = reader->variable_data_size() / kStreamIdSize;
+  std::vector<StreamID> stream_ids;
+  stream_ids.reserve(stream_count);
+  for (size_t i = 0; i < stream_count; ++i) {
+    BoundedByteReader<kStreamIdSize> sub_reader =
+        reader->sub_reader<kStreamIdSize>(i * kStreamIdSize);
+
+    stream_ids.push_back(StreamID(sub_reader.Load16<0>()));
+  }
+
+  return OutgoingSSNResetRequestParameter(
+      request_sequence_number, response_sequence_number,
+      sender_last_assigned_tsn, std::move(stream_ids));
+}
+
+void OutgoingSSNResetRequestParameter::SerializeTo(
+    std::vector<uint8_t>& out) const {
+  size_t variable_size = stream_ids_.size() * kStreamIdSize;
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, variable_size);
+
+  writer.Store32<4>(*request_sequence_number_);
+  writer.Store32<8>(*response_sequence_number_);
+  writer.Store32<12>(*sender_last_assigned_tsn_);
+
+  for (size_t i = 0; i < stream_ids_.size(); ++i) {
+    BoundedByteWriter<kStreamIdSize> sub_writer =
+        writer.sub_writer<kStreamIdSize>(i * kStreamIdSize);
+    sub_writer.Store16<0>(*stream_ids_[i]);
+  }
+}
+
+std::string OutgoingSSNResetRequestParameter::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "Outgoing SSN Reset Request, req_seq_nbr=" << *request_sequence_number()
+     << ", resp_seq_nbr=" << *response_sequence_number()
+     << ", sender_last_asg_tsn=" << *sender_last_assigned_tsn();
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h b/net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h
new file mode 100644
index 0000000..ae3e027
--- /dev/null
+++ b/net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h
@@ -0,0 +1,78 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_PARAMETER_OUTGOING_SSN_RESET_REQUEST_PARAMETER_H_
+#define NET_DCSCTP_PACKET_PARAMETER_OUTGOING_SSN_RESET_REQUEST_PARAMETER_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/internal_types.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "net/dcsctp/public/types.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc6525#section-4.1
+struct OutgoingSSNResetRequestParameterConfig : ParameterConfig {
+  static constexpr int kType = 13;
+  static constexpr size_t kHeaderSize = 16;
+  static constexpr size_t kVariableLengthAlignment = 2;
+};
+
+class OutgoingSSNResetRequestParameter
+    : public Parameter,
+      public TLVTrait<OutgoingSSNResetRequestParameterConfig> {
+ public:
+  static constexpr int kType = OutgoingSSNResetRequestParameterConfig::kType;
+
+  explicit OutgoingSSNResetRequestParameter(
+      ReconfigRequestSN request_sequence_number,
+      ReconfigResponseSN response_sequence_number,
+      TSN sender_last_assigned_tsn,
+      std::vector<StreamID> stream_ids)
+      : request_sequence_number_(request_sequence_number),
+        response_sequence_number_(response_sequence_number),
+        sender_last_assigned_tsn_(sender_last_assigned_tsn),
+        stream_ids_(std::move(stream_ids)) {}
+
+  static absl::optional<OutgoingSSNResetRequestParameter> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  ReconfigRequestSN request_sequence_number() const {
+    return request_sequence_number_;
+  }
+  ReconfigResponseSN response_sequence_number() const {
+    return response_sequence_number_;
+  }
+  TSN sender_last_assigned_tsn() const { return sender_last_assigned_tsn_; }
+  rtc::ArrayView<const StreamID> stream_ids() const { return stream_ids_; }
+
+ private:
+  static constexpr size_t kStreamIdSize = sizeof(uint16_t);
+
+  ReconfigRequestSN request_sequence_number_;
+  ReconfigResponseSN response_sequence_number_;
+  TSN sender_last_assigned_tsn_;
+  std::vector<StreamID> stream_ids_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_PARAMETER_OUTGOING_SSN_RESET_REQUEST_PARAMETER_H_
diff --git a/net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter_test.cc b/net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter_test.cc
new file mode 100644
index 0000000..c0466e5
--- /dev/null
+++ b/net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter_test.cc
@@ -0,0 +1,47 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h"
+
+#include <cstdint>
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/common/internal_types.h"
+#include "net/dcsctp/public/types.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(OutgoingSSNResetRequestParameterTest, SerializeAndDeserialize) {
+  OutgoingSSNResetRequestParameter parameter(
+      ReconfigRequestSN(1), ReconfigResponseSN(2), TSN(3),
+      {StreamID(4), StreamID(5), StreamID(6)});
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      OutgoingSSNResetRequestParameter deserialized,
+      OutgoingSSNResetRequestParameter::Parse(serialized));
+
+  EXPECT_EQ(*deserialized.request_sequence_number(), 1u);
+  EXPECT_EQ(*deserialized.response_sequence_number(), 2u);
+  EXPECT_EQ(*deserialized.sender_last_assigned_tsn(), 3u);
+  EXPECT_THAT(deserialized.stream_ids(),
+              ElementsAre(StreamID(4), StreamID(5), StreamID(6)));
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/parameter.cc b/net/dcsctp/packet/parameter/parameter.cc
new file mode 100644
index 0000000..b3b2bff
--- /dev/null
+++ b/net/dcsctp/packet/parameter/parameter.cc
@@ -0,0 +1,96 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/parameter.h"
+
+#include <stddef.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/memory/memory.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/math.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/parameter/add_incoming_streams_request_parameter.h"
+#include "net/dcsctp/packet/parameter/add_outgoing_streams_request_parameter.h"
+#include "net/dcsctp/packet/parameter/forward_tsn_supported_parameter.h"
+#include "net/dcsctp/packet/parameter/heartbeat_info_parameter.h"
+#include "net/dcsctp/packet/parameter/incoming_ssn_reset_request_parameter.h"
+#include "net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h"
+#include "net/dcsctp/packet/parameter/reconfiguration_response_parameter.h"
+#include "net/dcsctp/packet/parameter/ssn_tsn_reset_request_parameter.h"
+#include "net/dcsctp/packet/parameter/state_cookie_parameter.h"
+#include "net/dcsctp/packet/parameter/supported_extensions_parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+constexpr size_t kParameterHeaderSize = 4;
+
+Parameters::Builder& Parameters::Builder::Add(const Parameter& p) {
+  // https://tools.ietf.org/html/rfc4960#section-3.2.1
+  // "If the length of the parameter is not a multiple of 4 bytes, the sender
+  // pads the parameter at the end (i.e., after the Parameter Value field) with
+  // all zero bytes."
+  if (data_.size() % 4 != 0) {
+    data_.resize(RoundUpTo4(data_.size()));
+  }
+
+  p.SerializeTo(data_);
+  return *this;
+}
+
+std::vector<ParameterDescriptor> Parameters::descriptors() const {
+  rtc::ArrayView<const uint8_t> span(data_);
+  std::vector<ParameterDescriptor> result;
+  while (!span.empty()) {
+    BoundedByteReader<kParameterHeaderSize> header(span);
+    uint16_t type = header.Load16<0>();
+    uint16_t length = header.Load16<2>();
+    result.emplace_back(type, span.subview(0, length));
+    size_t length_with_padding = RoundUpTo4(length);
+    if (length_with_padding > span.size()) {
+      break;
+    }
+    span = span.subview(length_with_padding);
+  }
+  return result;
+}
+
+absl::optional<Parameters> Parameters::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  // Validate the parameter descriptors
+  rtc::ArrayView<const uint8_t> span(data);
+  while (!span.empty()) {
+    if (span.size() < kParameterHeaderSize) {
+      RTC_DLOG(LS_WARNING) << "Insufficient parameter length";
+      return absl::nullopt;
+    }
+    BoundedByteReader<kParameterHeaderSize> header(span);
+    uint16_t length = header.Load16<2>();
+    if (length < kParameterHeaderSize || length > span.size()) {
+      RTC_DLOG(LS_WARNING) << "Invalid parameter length field";
+      return absl::nullopt;
+    }
+    size_t length_with_padding = RoundUpTo4(length);
+    if (length_with_padding > span.size()) {
+      break;
+    }
+    span = span.subview(length_with_padding);
+  }
+  return Parameters(std::vector<uint8_t>(data.begin(), data.end()));
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/parameter.h b/net/dcsctp/packet/parameter/parameter.h
new file mode 100644
index 0000000..e8fa67c
--- /dev/null
+++ b/net/dcsctp/packet/parameter/parameter.h
@@ -0,0 +1,96 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_PARAMETER_PARAMETER_H_
+#define NET_DCSCTP_PACKET_PARAMETER_PARAMETER_H_
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "absl/algorithm/container.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+class Parameter {
+ public:
+  Parameter() {}
+  virtual ~Parameter() = default;
+
+  Parameter(const Parameter& other) = default;
+  Parameter& operator=(const Parameter& other) = default;
+
+  virtual void SerializeTo(std::vector<uint8_t>& out) const = 0;
+  virtual std::string ToString() const = 0;
+};
+
+struct ParameterDescriptor {
+  ParameterDescriptor(uint16_t type, rtc::ArrayView<const uint8_t> data)
+      : type(type), data(data) {}
+  uint16_t type;
+  rtc::ArrayView<const uint8_t> data;
+};
+
+class Parameters {
+ public:
+  class Builder {
+   public:
+    Builder() {}
+    Builder& Add(const Parameter& p);
+    Parameters Build() { return Parameters(std::move(data_)); }
+
+   private:
+    std::vector<uint8_t> data_;
+  };
+
+  static absl::optional<Parameters> Parse(rtc::ArrayView<const uint8_t> data);
+
+  Parameters() {}
+  Parameters(Parameters&& other) = default;
+  Parameters& operator=(Parameters&& other) = default;
+
+  rtc::ArrayView<const uint8_t> data() const { return data_; }
+  std::vector<ParameterDescriptor> descriptors() const;
+
+  template <typename P>
+  absl::optional<P> get() const {
+    static_assert(std::is_base_of<Parameter, P>::value,
+                  "Template parameter not derived from Parameter");
+    for (const auto& p : descriptors()) {
+      if (p.type == P::kType) {
+        return P::Parse(p.data);
+      }
+    }
+    return absl::nullopt;
+  }
+
+ private:
+  explicit Parameters(std::vector<uint8_t> data) : data_(std::move(data)) {}
+  std::vector<uint8_t> data_;
+};
+
+struct ParameterConfig {
+  static constexpr int kTypeSizeInBytes = 2;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_PARAMETER_PARAMETER_H_
diff --git a/net/dcsctp/packet/parameter/parameter_test.cc b/net/dcsctp/packet/parameter/parameter_test.cc
new file mode 100644
index 0000000..e76dcad
--- /dev/null
+++ b/net/dcsctp/packet/parameter/parameter_test.cc
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/parameter.h"
+
+#include <cstdint>
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+using ::testing::SizeIs;
+
+TEST(ParameterTest, SerializeDeserializeParameter) {
+  Parameters parameters =
+      Parameters::Builder()
+          .Add(OutgoingSSNResetRequestParameter(ReconfigRequestSN(123),
+                                                ReconfigResponseSN(456),
+                                                TSN(789), {StreamID(42)}))
+          .Build();
+
+  rtc::ArrayView<const uint8_t> serialized = parameters.data();
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(Parameters parsed, Parameters::Parse(serialized));
+  auto descriptors = parsed.descriptors();
+  ASSERT_THAT(descriptors, SizeIs(1));
+  EXPECT_THAT(descriptors[0].type, OutgoingSSNResetRequestParameter::kType);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      OutgoingSSNResetRequestParameter parsed_param,
+      OutgoingSSNResetRequestParameter::Parse(descriptors[0].data));
+  EXPECT_EQ(*parsed_param.request_sequence_number(), 123u);
+  EXPECT_EQ(*parsed_param.response_sequence_number(), 456u);
+  EXPECT_EQ(*parsed_param.sender_last_assigned_tsn(), 789u);
+  EXPECT_THAT(parsed_param.stream_ids(), ElementsAre(StreamID(42)));
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/reconfiguration_response_parameter.cc b/net/dcsctp/packet/parameter/reconfiguration_response_parameter.cc
new file mode 100644
index 0000000..6d4efed
--- /dev/null
+++ b/net/dcsctp/packet/parameter/reconfiguration_response_parameter.cc
@@ -0,0 +1,152 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/reconfiguration_response_parameter.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc6525#section-4.4
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Parameter Type = 16       |      Parameter Length         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |         Re-configuration Response Sequence Number             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                            Result                             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                   Sender's Next TSN (optional)                |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                  Receiver's Next TSN (optional)               |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int ReconfigurationResponseParameter::kType;
+
+absl::string_view ToString(ReconfigurationResponseParameter::Result result) {
+  switch (result) {
+    case ReconfigurationResponseParameter::Result::kSuccessNothingToDo:
+      return "Success: nothing to do";
+    case ReconfigurationResponseParameter::Result::kSuccessPerformed:
+      return "Success: performed";
+    case ReconfigurationResponseParameter::Result::kDenied:
+      return "Denied";
+    case ReconfigurationResponseParameter::Result::kErrorWrongSSN:
+      return "Error: wrong ssn";
+    case ReconfigurationResponseParameter::Result::
+        kErrorRequestAlreadyInProgress:
+      return "Error: request already in progress";
+    case ReconfigurationResponseParameter::Result::kErrorBadSequenceNumber:
+      return "Error: bad sequence number";
+    case ReconfigurationResponseParameter::Result::kInProgress:
+      return "In progress";
+  }
+}
+
+absl::optional<ReconfigurationResponseParameter>
+ReconfigurationResponseParameter::Parse(rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+
+  ReconfigResponseSN response_sequence_number(reader->Load32<4>());
+  Result result;
+  uint32_t result_nbr = reader->Load32<8>();
+  switch (result_nbr) {
+    case 0:
+      result = ReconfigurationResponseParameter::Result::kSuccessNothingToDo;
+      break;
+    case 1:
+      result = ReconfigurationResponseParameter::Result::kSuccessPerformed;
+      break;
+    case 2:
+      result = ReconfigurationResponseParameter::Result::kDenied;
+      break;
+    case 3:
+      result = ReconfigurationResponseParameter::Result::kErrorWrongSSN;
+      break;
+    case 4:
+      result = ReconfigurationResponseParameter::Result::
+          kErrorRequestAlreadyInProgress;
+      break;
+    case 5:
+      result =
+          ReconfigurationResponseParameter::Result::kErrorBadSequenceNumber;
+      break;
+    case 6:
+      result = ReconfigurationResponseParameter::Result::kInProgress;
+      break;
+    default:
+      RTC_DLOG(LS_WARNING) << "Invalid reconfig response result: "
+                           << result_nbr;
+      return absl::nullopt;
+  }
+
+  if (reader->variable_data().empty()) {
+    return ReconfigurationResponseParameter(response_sequence_number, result);
+  } else if (reader->variable_data_size() != kNextTsnHeaderSize) {
+    RTC_DLOG(LS_WARNING) << "Invalid parameter size";
+    return absl::nullopt;
+  }
+
+  BoundedByteReader<kNextTsnHeaderSize> sub_reader =
+      reader->sub_reader<kNextTsnHeaderSize>(0);
+
+  TSN sender_next_tsn(sub_reader.Load32<0>());
+  TSN receiver_next_tsn(sub_reader.Load32<4>());
+
+  return ReconfigurationResponseParameter(response_sequence_number, result,
+                                          sender_next_tsn, receiver_next_tsn);
+}
+
+void ReconfigurationResponseParameter::SerializeTo(
+    std::vector<uint8_t>& out) const {
+  size_t variable_size =
+      (sender_next_tsn().has_value() ? kNextTsnHeaderSize : 0);
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, variable_size);
+
+  writer.Store32<4>(*response_sequence_number_);
+  uint32_t result_nbr =
+      static_cast<std::underlying_type<Result>::type>(result_);
+  writer.Store32<8>(result_nbr);
+
+  if (sender_next_tsn().has_value()) {
+    BoundedByteWriter<kNextTsnHeaderSize> sub_writer =
+        writer.sub_writer<kNextTsnHeaderSize>(0);
+
+    sub_writer.Store32<0>(sender_next_tsn_.has_value() ? **sender_next_tsn_
+                                                       : 0);
+    sub_writer.Store32<4>(receiver_next_tsn_.has_value() ? **receiver_next_tsn_
+                                                         : 0);
+  }
+}
+
+std::string ReconfigurationResponseParameter::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "Re-configuration Response, resp_seq_nbr="
+     << *response_sequence_number();
+  return sb.Release();
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/reconfiguration_response_parameter.h b/net/dcsctp/packet/parameter/reconfiguration_response_parameter.h
new file mode 100644
index 0000000..0933617
--- /dev/null
+++ b/net/dcsctp/packet/parameter/reconfiguration_response_parameter.h
@@ -0,0 +1,92 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_PARAMETER_RECONFIGURATION_RESPONSE_PARAMETER_H_
+#define NET_DCSCTP_PACKET_PARAMETER_RECONFIGURATION_RESPONSE_PARAMETER_H_
+#include <stddef.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/internal_types.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc6525#section-4.4
+struct ReconfigurationResponseParameterConfig : ParameterConfig {
+  static constexpr int kType = 16;
+  static constexpr size_t kHeaderSize = 12;
+  static constexpr size_t kVariableLengthAlignment = 4;
+};
+
+class ReconfigurationResponseParameter
+    : public Parameter,
+      public TLVTrait<ReconfigurationResponseParameterConfig> {
+ public:
+  static constexpr int kType = ReconfigurationResponseParameterConfig::kType;
+
+  enum class Result {
+    kSuccessNothingToDo = 0,
+    kSuccessPerformed = 1,
+    kDenied = 2,
+    kErrorWrongSSN = 3,
+    kErrorRequestAlreadyInProgress = 4,
+    kErrorBadSequenceNumber = 5,
+    kInProgress = 6,
+  };
+
+  ReconfigurationResponseParameter(ReconfigResponseSN response_sequence_number,
+                                   Result result)
+      : response_sequence_number_(response_sequence_number),
+        result_(result),
+        sender_next_tsn_(absl::nullopt),
+        receiver_next_tsn_(absl::nullopt) {}
+
+  explicit ReconfigurationResponseParameter(
+      ReconfigResponseSN response_sequence_number,
+      Result result,
+      TSN sender_next_tsn,
+      TSN receiver_next_tsn)
+      : response_sequence_number_(response_sequence_number),
+        result_(result),
+        sender_next_tsn_(sender_next_tsn),
+        receiver_next_tsn_(receiver_next_tsn) {}
+
+  static absl::optional<ReconfigurationResponseParameter> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  ReconfigResponseSN response_sequence_number() const {
+    return response_sequence_number_;
+  }
+  Result result() const { return result_; }
+  absl::optional<TSN> sender_next_tsn() const { return sender_next_tsn_; }
+  absl::optional<TSN> receiver_next_tsn() const { return receiver_next_tsn_; }
+
+ private:
+  static constexpr size_t kNextTsnHeaderSize = 8;
+  ReconfigResponseSN response_sequence_number_;
+  Result result_;
+  absl::optional<TSN> sender_next_tsn_;
+  absl::optional<TSN> receiver_next_tsn_;
+};
+
+absl::string_view ToString(ReconfigurationResponseParameter::Result result);
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_PARAMETER_RECONFIGURATION_RESPONSE_PARAMETER_H_
diff --git a/net/dcsctp/packet/parameter/reconfiguration_response_parameter_test.cc b/net/dcsctp/packet/parameter/reconfiguration_response_parameter_test.cc
new file mode 100644
index 0000000..f06003d
--- /dev/null
+++ b/net/dcsctp/packet/parameter/reconfiguration_response_parameter_test.cc
@@ -0,0 +1,68 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/reconfiguration_response_parameter.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(ReconfigurationResponseParameterTest, SerializeAndDeserializeFirstForm) {
+  ReconfigurationResponseParameter parameter(
+      ReconfigResponseSN(1),
+      ReconfigurationResponseParameter::Result::kSuccessPerformed);
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      ReconfigurationResponseParameter deserialized,
+      ReconfigurationResponseParameter::Parse(serialized));
+
+  EXPECT_EQ(*deserialized.response_sequence_number(), 1u);
+  EXPECT_EQ(deserialized.result(),
+            ReconfigurationResponseParameter::Result::kSuccessPerformed);
+  EXPECT_EQ(deserialized.sender_next_tsn(), absl::nullopt);
+  EXPECT_EQ(deserialized.receiver_next_tsn(), absl::nullopt);
+}
+
+TEST(ReconfigurationResponseParameterTest,
+     SerializeAndDeserializeFirstFormSecondForm) {
+  ReconfigurationResponseParameter parameter(
+      ReconfigResponseSN(1),
+      ReconfigurationResponseParameter::Result::kSuccessPerformed, TSN(2),
+      TSN(3));
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(
+      ReconfigurationResponseParameter deserialized,
+      ReconfigurationResponseParameter::Parse(serialized));
+
+  EXPECT_EQ(*deserialized.response_sequence_number(), 1u);
+  EXPECT_EQ(deserialized.result(),
+            ReconfigurationResponseParameter::Result::kSuccessPerformed);
+  EXPECT_TRUE(deserialized.sender_next_tsn().has_value());
+  EXPECT_EQ(**deserialized.sender_next_tsn(), 2u);
+  EXPECT_TRUE(deserialized.receiver_next_tsn().has_value());
+  EXPECT_EQ(**deserialized.receiver_next_tsn(), 3u);
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/ssn_tsn_reset_request_parameter.cc b/net/dcsctp/packet/parameter/ssn_tsn_reset_request_parameter.cc
new file mode 100644
index 0000000..d656e0d
--- /dev/null
+++ b/net/dcsctp/packet/parameter/ssn_tsn_reset_request_parameter.cc
@@ -0,0 +1,60 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/ssn_tsn_reset_request_parameter.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc6525#section-4.3
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Parameter Type = 15       |      Parameter Length = 8     |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |         Re-configuration Request Sequence Number              |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int SSNTSNResetRequestParameter::kType;
+
+absl::optional<SSNTSNResetRequestParameter> SSNTSNResetRequestParameter::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  ReconfigRequestSN request_sequence_number(reader->Load32<4>());
+
+  return SSNTSNResetRequestParameter(request_sequence_number);
+}
+
+void SSNTSNResetRequestParameter::SerializeTo(std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out);
+  writer.Store32<4>(*request_sequence_number_);
+}
+
+std::string SSNTSNResetRequestParameter::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "SSN/TSN Reset Request, req_seq_nbr=" << *request_sequence_number();
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/ssn_tsn_reset_request_parameter.h b/net/dcsctp/packet/parameter/ssn_tsn_reset_request_parameter.h
new file mode 100644
index 0000000..e31d7eb
--- /dev/null
+++ b/net/dcsctp/packet/parameter/ssn_tsn_reset_request_parameter.h
@@ -0,0 +1,59 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_PARAMETER_SSN_TSN_RESET_REQUEST_PARAMETER_H_
+#define NET_DCSCTP_PACKET_PARAMETER_SSN_TSN_RESET_REQUEST_PARAMETER_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/internal_types.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc6525#section-4.3
+struct SSNTSNResetRequestParameterConfig : ParameterConfig {
+  static constexpr int kType = 15;
+  static constexpr size_t kHeaderSize = 8;
+  static constexpr size_t kVariableLengthAlignment = 0;
+};
+
+class SSNTSNResetRequestParameter
+    : public Parameter,
+      public TLVTrait<SSNTSNResetRequestParameterConfig> {
+ public:
+  static constexpr int kType = SSNTSNResetRequestParameterConfig::kType;
+
+  explicit SSNTSNResetRequestParameter(
+      ReconfigRequestSN request_sequence_number)
+      : request_sequence_number_(request_sequence_number) {}
+
+  static absl::optional<SSNTSNResetRequestParameter> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  ReconfigRequestSN request_sequence_number() const {
+    return request_sequence_number_;
+  }
+
+ private:
+  ReconfigRequestSN request_sequence_number_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_PARAMETER_SSN_TSN_RESET_REQUEST_PARAMETER_H_
diff --git a/net/dcsctp/packet/parameter/ssn_tsn_reset_request_parameter_test.cc b/net/dcsctp/packet/parameter/ssn_tsn_reset_request_parameter_test.cc
new file mode 100644
index 0000000..eeb973c
--- /dev/null
+++ b/net/dcsctp/packet/parameter/ssn_tsn_reset_request_parameter_test.cc
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/ssn_tsn_reset_request_parameter.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(SSNTSNResetRequestParameterTest, SerializeAndDeserialize) {
+  SSNTSNResetRequestParameter parameter(ReconfigRequestSN(1));
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(SSNTSNResetRequestParameter deserialized,
+                              SSNTSNResetRequestParameter::Parse(serialized));
+
+  EXPECT_EQ(*deserialized.request_sequence_number(), 1u);
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/state_cookie_parameter.cc b/net/dcsctp/packet/parameter/state_cookie_parameter.cc
new file mode 100644
index 0000000..9777aa6
--- /dev/null
+++ b/net/dcsctp/packet/parameter/state_cookie_parameter.cc
@@ -0,0 +1,51 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/state_cookie_parameter.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.3.1
+
+constexpr int StateCookieParameter::kType;
+
+absl::optional<StateCookieParameter> StateCookieParameter::Parse(
+    rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+  return StateCookieParameter(reader->variable_data());
+}
+
+void StateCookieParameter::SerializeTo(std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, data_.size());
+  writer.CopyToVariableData(data_);
+}
+
+std::string StateCookieParameter::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "State Cookie parameter (cookie_length=" << data_.size() << ")";
+  return sb.Release();
+}
+
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/state_cookie_parameter.h b/net/dcsctp/packet/parameter/state_cookie_parameter.h
new file mode 100644
index 0000000..f435549
--- /dev/null
+++ b/net/dcsctp/packet/parameter/state_cookie_parameter.h
@@ -0,0 +1,55 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_PARAMETER_STATE_COOKIE_PARAMETER_H_
+#define NET_DCSCTP_PACKET_PARAMETER_STATE_COOKIE_PARAMETER_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc4960#section-3.3.3.1
+struct StateCookieParameterConfig : ParameterConfig {
+  static constexpr int kType = 7;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class StateCookieParameter : public Parameter,
+                             public TLVTrait<StateCookieParameterConfig> {
+ public:
+  static constexpr int kType = StateCookieParameterConfig::kType;
+
+  explicit StateCookieParameter(rtc::ArrayView<const uint8_t> data)
+      : data_(data.begin(), data.end()) {}
+
+  static absl::optional<StateCookieParameter> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  rtc::ArrayView<const uint8_t> data() const { return data_; }
+
+ private:
+  std::vector<uint8_t> data_;
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_PARAMETER_STATE_COOKIE_PARAMETER_H_
diff --git a/net/dcsctp/packet/parameter/state_cookie_parameter_test.cc b/net/dcsctp/packet/parameter/state_cookie_parameter_test.cc
new file mode 100644
index 0000000..bcca38b
--- /dev/null
+++ b/net/dcsctp/packet/parameter/state_cookie_parameter_test.cc
@@ -0,0 +1,40 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/state_cookie_parameter.h"
+
+#include <stdint.h>
+
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(StateCookieParameterTest, SerializeAndDeserialize) {
+  uint8_t cookie[] = {1, 2, 3};
+  StateCookieParameter parameter(cookie);
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(StateCookieParameter deserialized,
+                              StateCookieParameter::Parse(serialized));
+
+  EXPECT_THAT(deserialized.data(), ElementsAre(1, 2, 3));
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/supported_extensions_parameter.cc b/net/dcsctp/packet/parameter/supported_extensions_parameter.cc
new file mode 100644
index 0000000..6a8fb21
--- /dev/null
+++ b/net/dcsctp/packet/parameter/supported_extensions_parameter.cc
@@ -0,0 +1,65 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/supported_extensions_parameter.h"
+
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/str_join.h"
+#include "net/dcsctp/packet/bounded_byte_reader.h"
+#include "net/dcsctp/packet/bounded_byte_writer.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc5061#section-4.2.7
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     Parameter Type = 0x8008   |      Parameter Length         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  | CHUNK TYPE 1  |  CHUNK TYPE 2 |  CHUNK TYPE 3 |  CHUNK TYPE 4 |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                             ....                              |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  | CHUNK TYPE N  |      PAD      |      PAD      |      PAD      |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr int SupportedExtensionsParameter::kType;
+
+absl::optional<SupportedExtensionsParameter>
+SupportedExtensionsParameter::Parse(rtc::ArrayView<const uint8_t> data) {
+  absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
+  if (!reader.has_value()) {
+    return absl::nullopt;
+  }
+
+  std::vector<uint8_t> chunk_types(reader->variable_data().begin(),
+                                   reader->variable_data().end());
+  return SupportedExtensionsParameter(std::move(chunk_types));
+}
+
+void SupportedExtensionsParameter::SerializeTo(
+    std::vector<uint8_t>& out) const {
+  BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, chunk_types_.size());
+  writer.CopyToVariableData(chunk_types_);
+}
+
+std::string SupportedExtensionsParameter::ToString() const {
+  rtc::StringBuilder sb;
+  sb << "Supported Extensions (" << StrJoin(chunk_types_, ", ") << ")";
+  return sb.Release();
+}
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/parameter/supported_extensions_parameter.h b/net/dcsctp/packet/parameter/supported_extensions_parameter.h
new file mode 100644
index 0000000..5689fd8
--- /dev/null
+++ b/net/dcsctp/packet/parameter/supported_extensions_parameter.h
@@ -0,0 +1,62 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PACKET_PARAMETER_SUPPORTED_EXTENSIONS_PARAMETER_H_
+#define NET_DCSCTP_PACKET_PARAMETER_SUPPORTED_EXTENSIONS_PARAMETER_H_
+#include <stddef.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/packet/parameter/parameter.h"
+#include "net/dcsctp/packet/tlv_trait.h"
+
+namespace dcsctp {
+
+// https://tools.ietf.org/html/rfc5061#section-4.2.7
+struct SupportedExtensionsParameterConfig : ParameterConfig {
+  static constexpr int kType = 0x8008;
+  static constexpr size_t kHeaderSize = 4;
+  static constexpr size_t kVariableLengthAlignment = 1;
+};
+
+class SupportedExtensionsParameter
+    : public Parameter,
+      public TLVTrait<SupportedExtensionsParameterConfig> {
+ public:
+  static constexpr int kType = SupportedExtensionsParameterConfig::kType;
+
+  explicit SupportedExtensionsParameter(std::vector<uint8_t> chunk_types)
+      : chunk_types_(std::move(chunk_types)) {}
+
+  static absl::optional<SupportedExtensionsParameter> Parse(
+      rtc::ArrayView<const uint8_t> data);
+
+  void SerializeTo(std::vector<uint8_t>& out) const override;
+  std::string ToString() const override;
+
+  bool supports(uint8_t chunk_type) const {
+    return std::find(chunk_types_.begin(), chunk_types_.end(), chunk_type) !=
+           chunk_types_.end();
+  }
+
+  rtc::ArrayView<const uint8_t> chunk_types() const { return chunk_types_; }
+
+ private:
+  std::vector<uint8_t> chunk_types_;
+};
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PACKET_PARAMETER_SUPPORTED_EXTENSIONS_PARAMETER_H_
diff --git a/net/dcsctp/packet/parameter/supported_extensions_parameter_test.cc b/net/dcsctp/packet/parameter/supported_extensions_parameter_test.cc
new file mode 100644
index 0000000..c870af2
--- /dev/null
+++ b/net/dcsctp/packet/parameter/supported_extensions_parameter_test.cc
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "net/dcsctp/packet/parameter/supported_extensions_parameter.h"
+
+#include <cstdint>
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/testing/testing_macros.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(SupportedExtensionsParameterTest, SerializeAndDeserialize) {
+  SupportedExtensionsParameter parameter({1, 2, 3});
+
+  std::vector<uint8_t> serialized;
+  parameter.SerializeTo(serialized);
+
+  ASSERT_HAS_VALUE_AND_ASSIGN(SupportedExtensionsParameter deserialized,
+                              SupportedExtensionsParameter::Parse(serialized));
+
+  EXPECT_THAT(deserialized.chunk_types(), ElementsAre(1, 2, 3));
+  EXPECT_TRUE(deserialized.supports(1));
+  EXPECT_TRUE(deserialized.supports(2));
+  EXPECT_TRUE(deserialized.supports(3));
+  EXPECT_FALSE(deserialized.supports(4));
+}
+
+}  // namespace
+}  // namespace dcsctp
diff --git a/net/dcsctp/packet/tlv_trait.h b/net/dcsctp/packet/tlv_trait.h
index 9cdb924..11c3852 100644
--- a/net/dcsctp/packet/tlv_trait.h
+++ b/net/dcsctp/packet/tlv_trait.h
@@ -116,7 +116,7 @@
         tlv_trait_impl::ReportInvalidPadding(padding);
         return absl::nullopt;
       }
-      if ((length % Config::kVariableLengthAlignment) != 0) {
+      if (!ValidateLengthAlignment(length, Config::kVariableLengthAlignment)) {
         tlv_trait_impl::ReportInvalidLengthMultiple(
             length, Config::kVariableLengthAlignment);
         return absl::nullopt;
@@ -147,6 +147,16 @@
     return BoundedByteWriter<Config::kHeaderSize>(
         rtc::ArrayView<uint8_t>(out.data() + offset, size));
   }
+
+ private:
+  static bool ValidateLengthAlignment(uint16_t length, size_t alignment) {
+    // This is to avoid MSVC believing there could be a "mod by zero", when it
+    // certainly can't.
+    if (alignment == 0) {
+      return true;
+    }
+    return (length % alignment) == 0;
+  }
 };
 
 }  // namespace dcsctp