Some conversions to use PacketBufferHandle (#3909)

Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/examples/all-clusters-app/esp32/main/EchoServer.cpp b/examples/all-clusters-app/esp32/main/EchoServer.cpp
index c469c59..232de50 100644
--- a/examples/all-clusters-app/esp32/main/EchoServer.cpp
+++ b/examples/all-clusters-app/esp32/main/EchoServer.cpp
@@ -123,14 +123,14 @@
 {
 public:
     void OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader,
-                           const Transport::PeerConnectionState * state, System::PacketBuffer * buffer,
+                           const Transport::PeerConnectionState * state, System::PacketBufferHandle buffer,
                            SecureSessionMgr * mgr) override
     {
         CHIP_ERROR err;
         const size_t data_len = buffer->DataLength();
 
         // as soon as a client connects, assume it is connected
-        VerifyOrExit(mgr != NULL && buffer != NULL, ESP_LOGE(TAG, "Received data but couldn't process it..."));
+        VerifyOrExit(mgr != NULL && !buffer.IsNull(), ESP_LOGE(TAG, "Received data but couldn't process it..."));
         VerifyOrExit(state->GetPeerNodeId() != kUndefinedNodeId, ESP_LOGE(TAG, "Unknown source for received message"));
 
         {
@@ -148,8 +148,7 @@
         // port from data model processing.
         if (ContentMayBeADataModelMessage(buffer))
         {
-            HandleDataModelMessage(header, buffer, mgr);
-            buffer = NULL;
+            HandleDataModelMessage(header, std::move(buffer), mgr);
         }
         else
         {
@@ -160,8 +159,7 @@
             ESP_LOGI(TAG, "Client sent: %s", logmsg);
 
             // Attempt to echo back
-            err    = mgr->SendMessage(header.GetSourceNodeId().Value(), buffer);
-            buffer = NULL;
+            err = mgr->SendMessage(header.GetSourceNodeId().Value(), buffer.Release_ForNow());
             if (err != CHIP_NO_ERROR)
             {
                 ESP_LOGE(TAG, "Unable to echo back to client: %s", ErrorStr(err));
@@ -172,13 +170,7 @@
             }
         }
 
-    exit:
-
-        // SendTo calls Free on the buffer without an AddRef, if SendTo was not called, free the buffer.
-        if (buffer != NULL)
-        {
-            System::PacketBuffer::Free(buffer);
-        }
+    exit:;
     }
 
     void OnReceiveError(CHIP_ERROR error, const Transport::PeerAddress & source, SecureSessionMgr * mgr) override
@@ -201,7 +193,7 @@
      * Echo messages should generally not have a first byte with those values, so we
      * can use that to try to distinguish between the two.
      */
-    bool ContentMayBeADataModelMessage(System::PacketBuffer * buffer)
+    bool ContentMayBeADataModelMessage(const System::PacketBufferHandle & buffer)
     {
         const size_t data_len      = buffer->DataLength();
         const uint8_t * data       = buffer->Start();
diff --git a/examples/chip-tool/commands/clusters/Commands.h b/examples/chip-tool/commands/clusters/Commands.h
index b6a1767..5bc109c 100644
--- a/examples/chip-tool/commands/clusters/Commands.h
+++ b/examples/chip-tool/commands/clusters/Commands.h
@@ -932,7 +932,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeBarrierControlClusterGoToPercentCommand(buffer->Start(), bufferSize, endPointId, mPercentOpen);
     }
@@ -956,7 +956,7 @@
 public:
     BarrierControlStop() : ModelCommand("stop", kBarrierControlClusterId, 0x01) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeBarrierControlClusterStopCommand(buffer->Start(), bufferSize, endPointId);
     }
@@ -977,7 +977,7 @@
 public:
     DiscoverBarrierControlAttributes() : ModelCommand("discover", kBarrierControlClusterId, 0x0c) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeBarrierControlClusterDiscoverAttributes(buffer->Start(), bufferSize, endPointId);
     }
@@ -1002,7 +1002,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeBarrierControlClusterReadMovingStateAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -1026,7 +1026,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeBarrierControlClusterReportMovingStateAttribute(buffer->Start(), bufferSize, endPointId, mMinInterval,
                                                                      mMaxInterval);
@@ -1056,7 +1056,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeBarrierControlClusterReadSafetyStatusAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -1080,7 +1080,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeBarrierControlClusterReportSafetyStatusAttribute(buffer->Start(), bufferSize, endPointId, mMinInterval,
                                                                       mMaxInterval);
@@ -1110,7 +1110,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeBarrierControlClusterReadCapabilitiesAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -1135,7 +1135,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeBarrierControlClusterReadBarrierPositionAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -1160,7 +1160,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeBarrierControlClusterReportBarrierPositionAttribute(buffer->Start(), bufferSize, endPointId, mMinInterval,
                                                                          mMaxInterval, mChange);
@@ -1204,7 +1204,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeBasicClusterResetToFactoryDefaultsCommand(buffer->Start(), bufferSize, endPointId);
     }
@@ -1225,7 +1225,7 @@
 public:
     DiscoverBasicAttributes() : ModelCommand("discover", kBasicClusterId, 0x0c) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeBasicClusterDiscoverAttributes(buffer->Start(), bufferSize, endPointId);
     }
@@ -1250,7 +1250,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeBasicClusterReadZCLVersionAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -1275,7 +1275,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeBasicClusterReadPowerSourceAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -1367,7 +1367,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterMoveColorCommand(buffer->Start(), bufferSize, endPointId, mRateX, mRateY, mOptionsMask,
                                                          mOptionsOverride);
@@ -1404,7 +1404,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterMoveColorTemperatureCommand(buffer->Start(), bufferSize, endPointId, mMoveMode, mRate,
                                                                     mColorTemperatureMinimumMireds, mColorTemperatureMaximumMireds,
@@ -1442,7 +1442,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterMoveHueCommand(buffer->Start(), bufferSize, endPointId, mMoveMode, mRate, mOptionsMask,
                                                        mOptionsOverride);
@@ -1477,7 +1477,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterMoveSaturationCommand(buffer->Start(), bufferSize, endPointId, mMoveMode, mRate,
                                                               mOptionsMask, mOptionsOverride);
@@ -1513,7 +1513,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterMoveToColorCommand(buffer->Start(), bufferSize, endPointId, mColorX, mColorY,
                                                            mTransitionTime, mOptionsMask, mOptionsOverride);
@@ -1549,7 +1549,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterMoveToColorTemperatureCommand(
             buffer->Start(), bufferSize, endPointId, mColorTemperatureMireds, mTransitionTime, mOptionsMask, mOptionsOverride);
@@ -1585,7 +1585,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterMoveToHueCommand(buffer->Start(), bufferSize, endPointId, mHue, mDirection, mTransitionTime,
                                                          mOptionsMask, mOptionsOverride);
@@ -1622,7 +1622,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterMoveToHueAndSaturationCommand(buffer->Start(), bufferSize, endPointId, mHue, mSaturation,
                                                                       mTransitionTime, mOptionsMask, mOptionsOverride);
@@ -1658,7 +1658,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterMoveToSaturationCommand(buffer->Start(), bufferSize, endPointId, mSaturation,
                                                                 mTransitionTime, mOptionsMask, mOptionsOverride);
@@ -1694,7 +1694,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterStepColorCommand(buffer->Start(), bufferSize, endPointId, mStepX, mStepY, mTransitionTime,
                                                          mOptionsMask, mOptionsOverride);
@@ -1733,7 +1733,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterStepColorTemperatureCommand(buffer->Start(), bufferSize, endPointId, mStepMode, mStepSize,
                                                                     mTransitionTime, mColorTemperatureMinimumMireds,
@@ -1773,7 +1773,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterStepHueCommand(buffer->Start(), bufferSize, endPointId, mStepMode, mStepSize,
                                                        mTransitionTime, mOptionsMask, mOptionsOverride);
@@ -1810,7 +1810,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterStepSaturationCommand(buffer->Start(), bufferSize, endPointId, mStepMode, mStepSize,
                                                               mTransitionTime, mOptionsMask, mOptionsOverride);
@@ -1844,7 +1844,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterStopMoveStepCommand(buffer->Start(), bufferSize, endPointId, mOptionsMask,
                                                             mOptionsOverride);
@@ -1870,7 +1870,7 @@
 public:
     DiscoverColorControlAttributes() : ModelCommand("discover", kColorControlClusterId, 0x0c) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterDiscoverAttributes(buffer->Start(), bufferSize, endPointId);
     }
@@ -1895,7 +1895,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadCurrentHueAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -1920,7 +1920,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReportCurrentHueAttribute(buffer->Start(), bufferSize, endPointId, mMinInterval,
                                                                   mMaxInterval, mChange);
@@ -1951,7 +1951,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadCurrentSaturationAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -1976,7 +1976,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReportCurrentSaturationAttribute(buffer->Start(), bufferSize, endPointId, mMinInterval,
                                                                          mMaxInterval, mChange);
@@ -2007,7 +2007,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadRemainingTimeAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2032,7 +2032,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadCurrentXAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2057,7 +2057,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReportCurrentXAttribute(buffer->Start(), bufferSize, endPointId, mMinInterval, mMaxInterval,
                                                                 mChange);
@@ -2088,7 +2088,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadCurrentYAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2113,7 +2113,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReportCurrentYAttribute(buffer->Start(), bufferSize, endPointId, mMinInterval, mMaxInterval,
                                                                 mChange);
@@ -2144,7 +2144,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadColorTemperatureMiredsAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2169,7 +2169,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReportColorTemperatureMiredsAttribute(buffer->Start(), bufferSize, endPointId, mMinInterval,
                                                                               mMaxInterval, mChange);
@@ -2200,7 +2200,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadColorModeAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2225,7 +2225,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadOptionsAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2248,7 +2248,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterWriteOptionsAttribute(buffer->Start(), bufferSize, endPointId, mOptions);
     }
@@ -2276,7 +2276,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadNumberOfPrimariesAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2301,7 +2301,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary1XAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2326,7 +2326,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary1YAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2351,7 +2351,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary1IntensityAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2376,7 +2376,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary2XAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2401,7 +2401,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary2YAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2426,7 +2426,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary2IntensityAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2451,7 +2451,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary3XAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2476,7 +2476,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary3YAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2501,7 +2501,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary3IntensityAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2526,7 +2526,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary4XAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2551,7 +2551,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary4YAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2576,7 +2576,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary4IntensityAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2601,7 +2601,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary5XAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2626,7 +2626,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary5YAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2651,7 +2651,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary5IntensityAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2676,7 +2676,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary6XAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2701,7 +2701,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary6YAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2726,7 +2726,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadPrimary6IntensityAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2751,7 +2751,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadEnhancedCurrentHueAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2776,7 +2776,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadEnhancedColorModeAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2801,7 +2801,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadColorLoopActiveAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2826,7 +2826,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadColorLoopDirectionAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2851,7 +2851,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadColorLoopTimeAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2876,7 +2876,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadColorLoopStartEnhancedHueAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2901,7 +2901,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadColorLoopStoredEnhancedHueAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2926,7 +2926,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadColorCapabilitiesAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2951,7 +2951,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadColorTempPhysicalMinMiredsAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -2976,7 +2976,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadColorTempPhysicalMaxMiredsAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -3001,7 +3001,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadCoupleColorTempToLevelMinMiredsAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -3026,7 +3026,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterReadStartUpColorTemperatureMiredsAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -3049,7 +3049,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeColorControlClusterWriteStartUpColorTemperatureMiredsAttribute(buffer->Start(), bufferSize, endPointId,
                                                                                     mStartUpColorTemperatureMireds);
@@ -3726,7 +3726,7 @@
 public:
     DoorLockClearAllPINCodes() : ModelCommand("clear-all-pincodes", kDoorLockClusterId, 0x08) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterClearAllPINCodesCommand(buffer->Start(), bufferSize, endPointId);
     }
@@ -3754,7 +3754,7 @@
 public:
     DoorLockClearAllRFIDCodes() : ModelCommand("clear-all-rfidcodes", kDoorLockClusterId, 0x19) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterClearAllRFIDCodesCommand(buffer->Start(), bufferSize, endPointId);
     }
@@ -3786,7 +3786,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterClearHolidayScheduleCommand(buffer->Start(), bufferSize, endPointId, mHolidayScheduleID);
     }
@@ -3821,7 +3821,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterClearPINCodeCommand(buffer->Start(), bufferSize, endPointId, mUserID);
     }
@@ -3856,7 +3856,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterClearRFIDCodeCommand(buffer->Start(), bufferSize, endPointId, mUserID);
     }
@@ -3892,7 +3892,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterClearWeekdayScheduleCommand(buffer->Start(), bufferSize, endPointId, mScheduleID, mUserID);
     }
@@ -3929,7 +3929,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterClearYearDayScheduleCommand(buffer->Start(), bufferSize, endPointId, mScheduleID, mUserID);
     }
@@ -3965,7 +3965,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterGetHolidayScheduleCommand(buffer->Start(), bufferSize, endPointId, mHolidayScheduleID);
     }
@@ -4000,7 +4000,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterGetPINCodeCommand(buffer->Start(), bufferSize, endPointId, mUserID);
     }
@@ -4035,7 +4035,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterGetRFIDCodeCommand(buffer->Start(), bufferSize, endPointId, mUserID);
     }
@@ -4070,7 +4070,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterGetUserTypeCommand(buffer->Start(), bufferSize, endPointId, mUserID);
     }
@@ -4106,7 +4106,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterGetWeekdayScheduleCommand(buffer->Start(), bufferSize, endPointId, mScheduleID, mUserID);
     }
@@ -4143,7 +4143,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterGetYearDayScheduleCommand(buffer->Start(), bufferSize, endPointId, mScheduleID, mUserID);
     }
@@ -4179,7 +4179,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterLockDoorCommand(buffer->Start(), bufferSize, endPointId, mPINOrRFIDCode);
     }
@@ -4217,7 +4217,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterSetHolidayScheduleCommand(buffer->Start(), bufferSize, endPointId, mHolidayScheduleID,
                                                               mLocalStartTime, mLocalEndTime, mOperatingModeDuringHoliday);
@@ -4259,7 +4259,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterSetPINCodeCommand(buffer->Start(), bufferSize, endPointId, mUserID, mUserStatus, mUserType,
                                                       mPIN);
@@ -4301,7 +4301,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterSetRFIDCodeCommand(buffer->Start(), bufferSize, endPointId, mUserID, mUserStatus, mUserType,
                                                        mRFIDCode);
@@ -4341,7 +4341,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterSetUserTypeCommand(buffer->Start(), bufferSize, endPointId, mUserID, mUserType);
     }
@@ -4383,7 +4383,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterSetWeekdayScheduleCommand(buffer->Start(), bufferSize, endPointId, mScheduleID, mUserID,
                                                               mDaysMask, mStartHour, mStartMinute, mEndHour, mEndMinute);
@@ -4428,7 +4428,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterSetYearDayScheduleCommand(buffer->Start(), bufferSize, endPointId, mScheduleID, mUserID,
                                                               mLocalStartTime, mLocalEndTime);
@@ -4467,7 +4467,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterUnlockDoorCommand(buffer->Start(), bufferSize, endPointId, mPINOrRFIDCode);
     }
@@ -4503,7 +4503,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterUnlockWithTimeoutCommand(buffer->Start(), bufferSize, endPointId, mTimeoutInSeconds,
                                                              mPINOrRFIDCode);
@@ -4536,7 +4536,7 @@
 public:
     DiscoverDoorLockAttributes() : ModelCommand("discover", kDoorLockClusterId, 0x0c) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterDiscoverAttributes(buffer->Start(), bufferSize, endPointId);
     }
@@ -4561,7 +4561,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterReadLockStateAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -4585,7 +4585,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterReportLockStateAttribute(buffer->Start(), bufferSize, endPointId, mMinInterval, mMaxInterval);
     }
@@ -4614,7 +4614,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterReadLockTypeAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -4639,7 +4639,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeDoorLockClusterReadActuatorEnabledAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -4806,7 +4806,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeGroupsClusterAddGroupCommand(buffer->Start(), bufferSize, endPointId, mGroupId, mGroupName);
     }
@@ -4843,7 +4843,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeGroupsClusterAddGroupIfIdentifyingCommand(buffer->Start(), bufferSize, endPointId, mGroupId, mGroupName);
     }
@@ -4875,7 +4875,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeGroupsClusterGetGroupMembershipCommand(buffer->Start(), bufferSize, endPointId, mGroupCount, mGroupList);
     }
@@ -4907,7 +4907,7 @@
 public:
     GroupsRemoveAllGroups() : ModelCommand("remove-all-groups", kGroupsClusterId, 0x04) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeGroupsClusterRemoveAllGroupsCommand(buffer->Start(), bufferSize, endPointId);
     }
@@ -4932,7 +4932,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeGroupsClusterRemoveGroupCommand(buffer->Start(), bufferSize, endPointId, mGroupId);
     }
@@ -4967,7 +4967,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeGroupsClusterViewGroupCommand(buffer->Start(), bufferSize, endPointId, mGroupId);
     }
@@ -4998,7 +4998,7 @@
 public:
     DiscoverGroupsAttributes() : ModelCommand("discover", kGroupsClusterId, 0x0c) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeGroupsClusterDiscoverAttributes(buffer->Start(), bufferSize, endPointId);
     }
@@ -5023,7 +5023,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeGroupsClusterReadNameSupportAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -5060,7 +5060,7 @@
 public:
     DiscoverIASZoneAttributes() : ModelCommand("discover", kIASZoneClusterId, 0x0c) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeIASZoneClusterDiscoverAttributes(buffer->Start(), bufferSize, endPointId);
     }
@@ -5085,7 +5085,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeIASZoneClusterReadZoneStateAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -5110,7 +5110,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeIASZoneClusterReadZoneTypeAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -5135,7 +5135,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeIASZoneClusterReadZoneStatusAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -5160,7 +5160,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeIASZoneClusterReadIASCIEAddressAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -5183,7 +5183,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeIASZoneClusterWriteIASCIEAddressAttribute(buffer->Start(), bufferSize, endPointId, mIASCIEAddress);
     }
@@ -5211,7 +5211,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeIASZoneClusterReadZoneIDAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -5272,7 +5272,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeIdentifyClusterIdentifyCommand(buffer->Start(), bufferSize, endPointId, mIdentifyTime);
     }
@@ -5296,7 +5296,7 @@
 public:
     IdentifyIdentifyQuery() : ModelCommand("identify-query", kIdentifyClusterId, 0x01) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeIdentifyClusterIdentifyQueryCommand(buffer->Start(), bufferSize, endPointId);
     }
@@ -5324,7 +5324,7 @@
 public:
     DiscoverIdentifyAttributes() : ModelCommand("discover", kIdentifyClusterId, 0x0c) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeIdentifyClusterDiscoverAttributes(buffer->Start(), bufferSize, endPointId);
     }
@@ -5349,7 +5349,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeIdentifyClusterReadIdentifyTimeAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -5372,7 +5372,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeIdentifyClusterWriteIdentifyTimeAttribute(buffer->Start(), bufferSize, endPointId, mIdentifyTime);
     }
@@ -5423,7 +5423,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeLevelClusterMoveCommand(buffer->Start(), bufferSize, endPointId, mMoveMode, mRate, mOptionsMask,
                                              mOptionsOverride);
@@ -5458,7 +5458,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeLevelClusterMoveToLevelCommand(buffer->Start(), bufferSize, endPointId, mLevel, mTransitionTime, mOptionsMask,
                                                     mOptionsOverride);
@@ -5493,7 +5493,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeLevelClusterMoveToLevelWithOnOffCommand(buffer->Start(), bufferSize, endPointId, mLevel, mTransitionTime,
                                                              mOptionsMask, mOptionsOverride);
@@ -5528,7 +5528,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeLevelClusterMoveWithOnOffCommand(buffer->Start(), bufferSize, endPointId, mMoveMode, mRate, mOptionsMask,
                                                       mOptionsOverride);
@@ -5564,7 +5564,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeLevelClusterStepCommand(buffer->Start(), bufferSize, endPointId, mStepMode, mStepSize, mTransitionTime,
                                              mOptionsMask, mOptionsOverride);
@@ -5601,7 +5601,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeLevelClusterStepWithOnOffCommand(buffer->Start(), bufferSize, endPointId, mStepMode, mStepSize,
                                                       mTransitionTime, mOptionsMask, mOptionsOverride);
@@ -5635,7 +5635,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeLevelClusterStopCommand(buffer->Start(), bufferSize, endPointId, mOptionsMask, mOptionsOverride);
     }
@@ -5665,7 +5665,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeLevelClusterStopWithOnOffCommand(buffer->Start(), bufferSize, endPointId, mOptionsMask, mOptionsOverride);
     }
@@ -5690,7 +5690,7 @@
 public:
     DiscoverLevelAttributes() : ModelCommand("discover", kLevelClusterId, 0x0c) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeLevelClusterDiscoverAttributes(buffer->Start(), bufferSize, endPointId);
     }
@@ -5715,7 +5715,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeLevelClusterReadCurrentLevelAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -5740,7 +5740,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeLevelClusterReportCurrentLevelAttribute(buffer->Start(), bufferSize, endPointId, mMinInterval, mMaxInterval,
                                                              mChange);
@@ -5782,7 +5782,7 @@
 public:
     OnOffOff() : ModelCommand("off", kOnOffClusterId, 0x00) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeOnOffClusterOffCommand(buffer->Start(), bufferSize, endPointId);
     }
@@ -5803,7 +5803,7 @@
 public:
     OnOffOn() : ModelCommand("on", kOnOffClusterId, 0x01) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeOnOffClusterOnCommand(buffer->Start(), bufferSize, endPointId);
     }
@@ -5824,7 +5824,7 @@
 public:
     OnOffToggle() : ModelCommand("toggle", kOnOffClusterId, 0x02) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeOnOffClusterToggleCommand(buffer->Start(), bufferSize, endPointId);
     }
@@ -5845,7 +5845,7 @@
 public:
     DiscoverOnOffAttributes() : ModelCommand("discover", kOnOffClusterId, 0x0c) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeOnOffClusterDiscoverAttributes(buffer->Start(), bufferSize, endPointId);
     }
@@ -5870,7 +5870,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeOnOffClusterReadOnOffAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -5894,7 +5894,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeOnOffClusterReportOnOffAttribute(buffer->Start(), bufferSize, endPointId, mMinInterval, mMaxInterval);
     }
@@ -6171,7 +6171,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeScenesClusterAddSceneCommand(buffer->Start(), bufferSize, endPointId, mGroupID, mSceneID, mTransitionTime,
                                                   mSceneName, mClusterId, mExtensionFieldSet);
@@ -6212,7 +6212,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeScenesClusterGetSceneMembershipCommand(buffer->Start(), bufferSize, endPointId, mGroupID);
     }
@@ -6249,7 +6249,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeScenesClusterRecallSceneCommand(buffer->Start(), bufferSize, endPointId, mGroupID, mSceneID, mTransitionTime);
     }
@@ -6279,7 +6279,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeScenesClusterRemoveAllScenesCommand(buffer->Start(), bufferSize, endPointId, mGroupID);
     }
@@ -6315,7 +6315,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeScenesClusterRemoveSceneCommand(buffer->Start(), bufferSize, endPointId, mGroupID, mSceneID);
     }
@@ -6352,7 +6352,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeScenesClusterStoreSceneCommand(buffer->Start(), bufferSize, endPointId, mGroupID, mSceneID);
     }
@@ -6389,7 +6389,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeScenesClusterViewSceneCommand(buffer->Start(), bufferSize, endPointId, mGroupID, mSceneID);
     }
@@ -6421,7 +6421,7 @@
 public:
     DiscoverScenesAttributes() : ModelCommand("discover", kScenesClusterId, 0x0c) { ModelCommand::AddArguments(); }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeScenesClusterDiscoverAttributes(buffer->Start(), bufferSize, endPointId);
     }
@@ -6446,7 +6446,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeScenesClusterReadSceneCountAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -6471,7 +6471,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeScenesClusterReadCurrentSceneAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -6496,7 +6496,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeScenesClusterReadCurrentGroupAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -6521,7 +6521,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeScenesClusterReadSceneValidAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -6546,7 +6546,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeScenesClusterReadNameSupportAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -6584,7 +6584,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeTemperatureMeasurementClusterDiscoverAttributes(buffer->Start(), bufferSize, endPointId);
     }
@@ -6609,7 +6609,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeTemperatureMeasurementClusterReadMeasuredValueAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -6634,7 +6634,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeTemperatureMeasurementClusterReportMeasuredValueAttribute(buffer->Start(), bufferSize, endPointId,
                                                                                mMinInterval, mMaxInterval, mChange);
@@ -6665,7 +6665,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeTemperatureMeasurementClusterReadMinMeasuredValueAttribute(buffer->Start(), bufferSize, endPointId);
     }
@@ -6690,7 +6690,7 @@
         ModelCommand::AddArguments();
     }
 
-    uint16_t EncodeCommand(PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) override
+    uint16_t EncodeCommand(const PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) override
     {
         return encodeTemperatureMeasurementClusterReadMaxMeasuredValueAttribute(buffer->Start(), bufferSize, endPointId);
     }
diff --git a/examples/chip-tool/commands/common/EchoCommand.cpp b/examples/chip-tool/commands/common/EchoCommand.cpp
index 0ce23f8..4eb460a 100644
--- a/examples/chip-tool/commands/common/EchoCommand.cpp
+++ b/examples/chip-tool/commands/common/EchoCommand.cpp
@@ -56,7 +56,7 @@
     }
 }
 
-void EchoCommand::ReceiveEcho(PacketBuffer * buffer) const
+void EchoCommand::ReceiveEcho(PacketBufferHandle buffer) const
 {
     // attempt to print the incoming message
     size_t data_len               = buffer->DataLength();
diff --git a/examples/chip-tool/commands/common/EchoCommand.h b/examples/chip-tool/commands/common/EchoCommand.h
index 97a2adb..6a6a116 100644
--- a/examples/chip-tool/commands/common/EchoCommand.h
+++ b/examples/chip-tool/commands/common/EchoCommand.h
@@ -30,12 +30,12 @@
 
     /////////// IPCommand Interface /////////
     void OnConnect(ChipDeviceController * dc) override { mController = dc; }
-    void OnMessage(ChipDeviceController * dc, chip::System::PacketBuffer * buffer) override { ReceiveEcho(buffer); }
+    void OnMessage(ChipDeviceController * dc, chip::System::PacketBufferHandle buffer) override { ReceiveEcho(std::move(buffer)); }
     void OnError(ChipDeviceController * dc, CHIP_ERROR err) override { mController = nullptr; }
 
 private:
     void SendEcho(void) const;
-    void ReceiveEcho(chip::System::PacketBuffer * buffer) const;
+    void ReceiveEcho(chip::System::PacketBufferHandle buffer) const;
 
     ChipDeviceController * mController = nullptr;
 };
diff --git a/examples/chip-tool/commands/common/ModelCommand.cpp b/examples/chip-tool/commands/common/ModelCommand.cpp
index c7ce32c..9d983cb 100644
--- a/examples/chip-tool/commands/common/ModelCommand.cpp
+++ b/examples/chip-tool/commands/common/ModelCommand.cpp
@@ -58,9 +58,9 @@
     UpdateWaitForResponse(false);
 }
 
-void ModelCommand::OnMessage(ChipDeviceController * dc, PacketBuffer * buffer)
+void ModelCommand::OnMessage(ChipDeviceController * dc, PacketBufferHandle buffer)
 {
-    SetCommandExitStatus(ReceiveCommandResponse(dc, buffer));
+    SetCommandExitStatus(ReceiveCommandResponse(dc, std::move(buffer)));
     UpdateWaitForResponse(false);
 }
 
@@ -95,7 +95,7 @@
     ChipLogProgress(chipTool, "Endpoint id: '0x%02x', Cluster id: '0x%04x', Command id: '0x%02x'", mEndPointId, mClusterId,
                     mCommandId);
 
-    uint16_t dataLength = EncodeCommand(buffer.Get_ForNow(), bufferSize, mEndPointId);
+    uint16_t dataLength = EncodeCommand(buffer, bufferSize, mEndPointId);
     if (dataLength == 0)
     {
         ChipLogError(chipTool, "Error while encoding data for command: %s", GetName());
@@ -106,14 +106,14 @@
     ChipLogDetail(chipTool, "Encoded data of length %d", dataLength);
 
 #ifdef DEBUG
-    PrintBuffer(buffer.Get_ForNow());
+    PrintBuffer(buffer);
 #endif
 
     dc->SendMessage(NULL, buffer.Release_ForNow());
     return true;
 }
 
-bool ModelCommand::ReceiveCommandResponse(ChipDeviceController * dc, PacketBuffer * buffer) const
+bool ModelCommand::ReceiveCommandResponse(ChipDeviceController * dc, PacketBufferHandle buffer) const
 {
     EmberApsFrame frame;
     uint8_t * message;
@@ -126,7 +126,6 @@
     if (extractApsFrame(buffer->Start(), buffer->DataLength(), &frame) == 0)
     {
         ChipLogError(chipTool, "APS frame processing failure!");
-        PacketBuffer::Free(buffer);
         ExitNow();
     }
     ChipLogDetail(chipTool, "APS frame processing success!");
@@ -171,7 +170,7 @@
     }
 }
 
-void ModelCommand::PrintBuffer(PacketBuffer * buffer) const
+void ModelCommand::PrintBuffer(const PacketBufferHandle & buffer) const
 {
     const size_t data_len = buffer->DataLength();
 
diff --git a/examples/chip-tool/commands/common/ModelCommand.h b/examples/chip-tool/commands/common/ModelCommand.h
index 0907f71..cfdbd8b 100644
--- a/examples/chip-tool/commands/common/ModelCommand.h
+++ b/examples/chip-tool/commands/common/ModelCommand.h
@@ -50,19 +50,19 @@
     /////////// IPCommand Interface /////////
     void OnConnect(ChipDeviceController * dc) override;
     void OnError(ChipDeviceController * dc, CHIP_ERROR err) override;
-    void OnMessage(ChipDeviceController * dc, chip::System::PacketBuffer * buffer) override;
+    void OnMessage(ChipDeviceController * dc, chip::System::PacketBufferHandle buffer) override;
 
-    virtual uint16_t EncodeCommand(chip::System::PacketBuffer * buffer, uint16_t bufferSize, uint8_t endPointId) = 0;
+    virtual uint16_t EncodeCommand(const chip::System::PacketBufferHandle & buffer, uint16_t bufferSize, uint8_t endPointId) = 0;
     virtual bool HandleGlobalResponse(uint8_t commandId, uint8_t * message, uint16_t messageLen) const { return false; }
     virtual bool HandleSpecificResponse(uint8_t commandId, uint8_t * message, uint16_t messageLen) const { return false; }
 
 private:
     bool SendCommand(ChipDeviceController * dc);
-    bool ReceiveCommandResponse(ChipDeviceController * dc, chip::System::PacketBuffer * buffer) const;
+    bool ReceiveCommandResponse(ChipDeviceController * dc, chip::System::PacketBufferHandle buffer) const;
 
     void UpdateWaitForResponse(bool value);
     void WaitForResponse(void);
-    void PrintBuffer(chip::System::PacketBuffer * buffer) const;
+    void PrintBuffer(const chip::System::PacketBufferHandle & buffer) const;
 
     std::condition_variable cvWaitingForResponse;
     std::mutex cvWaitingForResponseMutex;
diff --git a/examples/chip-tool/commands/common/NetworkCommand.cpp b/examples/chip-tool/commands/common/NetworkCommand.cpp
index 4109f21..ff1cb43 100644
--- a/examples/chip-tool/commands/common/NetworkCommand.cpp
+++ b/examples/chip-tool/commands/common/NetworkCommand.cpp
@@ -38,14 +38,12 @@
     command->OnError(dc, err);
 }
 
-static void onMessage(ChipDeviceController * dc, void * appReqState, PacketBuffer * buffer)
+static void onMessage(ChipDeviceController * dc, void * appReqState, PacketBufferHandle buffer)
 {
     ChipLogDetail(chipTool, "OnMessage: Received %zu bytes", buffer->DataLength());
 
     NetworkCommand * command = reinterpret_cast<NetworkCommand *>(dc->AppState);
-    command->OnMessage(dc, buffer);
-
-    PacketBuffer::Free(buffer);
+    command->OnMessage(dc, std::move(buffer));
 }
 
 CHIP_ERROR NetworkCommand::Run(ChipDeviceController * dc, NodeId remoteId)
diff --git a/examples/chip-tool/commands/common/NetworkCommand.h b/examples/chip-tool/commands/common/NetworkCommand.h
index 10893b1..b84ac8b 100644
--- a/examples/chip-tool/commands/common/NetworkCommand.h
+++ b/examples/chip-tool/commands/common/NetworkCommand.h
@@ -51,9 +51,9 @@
 
     const char * GetNetworkName(void) const { return mName; }
 
-    virtual void OnConnect(ChipDeviceController * dc)                                      = 0;
-    virtual void OnError(ChipDeviceController * dc, CHIP_ERROR err)                        = 0;
-    virtual void OnMessage(ChipDeviceController * dc, chip::System::PacketBuffer * buffer) = 0;
+    virtual void OnConnect(ChipDeviceController * dc)                                          = 0;
+    virtual void OnError(ChipDeviceController * dc, CHIP_ERROR err)                            = 0;
+    virtual void OnMessage(ChipDeviceController * dc, chip::System::PacketBufferHandle buffer) = 0;
 
     CHIP_ERROR Run(ChipDeviceController * dc, NodeId remoteId) override;
 
diff --git a/examples/common/chip-app-server/DataModelHandler.cpp b/examples/common/chip-app-server/DataModelHandler.cpp
index 18d0d5a..ab10b1f 100644
--- a/examples/common/chip-app-server/DataModelHandler.cpp
+++ b/examples/common/chip-app-server/DataModelHandler.cpp
@@ -40,7 +40,7 @@
  * @param [in] buffer The buffer holding the message.  This function guarantees
  *                    that it will free the buffer before returning.
  */
-void HandleDataModelMessage(const PacketHeader & header, System::PacketBuffer * buffer, SecureSessionMgr * mgr)
+void HandleDataModelMessage(const PacketHeader & header, System::PacketBufferHandle buffer, SecureSessionMgr * mgr)
 {
     EmberApsFrame frame;
     bool ok = extractApsFrame(buffer->Start(), buffer->DataLength(), &frame) > 0;
@@ -51,7 +51,6 @@
     else
     {
         ChipLogProgress(Zcl, "APS frame processing failure!");
-        System::PacketBuffer::Free(buffer);
         return;
     }
 
@@ -63,8 +62,6 @@
                                header.GetSourceNodeId().Value(), // source identifier
                                NULL);
 
-    System::PacketBuffer::Free(buffer);
-
     if (ok)
     {
         ChipLogProgress(Zcl, "Data model processing success!");
diff --git a/examples/common/chip-app-server/RendezvousServer.cpp b/examples/common/chip-app-server/RendezvousServer.cpp
index 5d8d8c6..0996c2b 100644
--- a/examples/common/chip-app-server/RendezvousServer.cpp
+++ b/examples/common/chip-app-server/RendezvousServer.cpp
@@ -57,10 +57,8 @@
 }
 
 void RendezvousServer::OnRendezvousMessageReceived(const PacketHeader & packetHeader, const PeerAddress & peerAddress,
-                                                   PacketBuffer * buffer)
-{
-    chip::System::PacketBuffer::Free(buffer);
-}
+                                                   System::PacketBufferHandle buffer)
+{}
 
 void RendezvousServer::OnRendezvousComplete()
 {
diff --git a/examples/common/chip-app-server/Server.cpp b/examples/common/chip-app-server/Server.cpp
index 0410326..ac0f87947 100644
--- a/examples/common/chip-app-server/Server.cpp
+++ b/examples/common/chip-app-server/Server.cpp
@@ -46,14 +46,14 @@
 {
 public:
     void OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader,
-                           const Transport::PeerConnectionState * state, System::PacketBuffer * buffer,
+                           const Transport::PeerConnectionState * state, System::PacketBufferHandle buffer,
                            SecureSessionMgr * mgr) override
     {
         const size_t data_len = buffer->DataLength();
         char src_addr[PeerAddress::kMaxToStringSize];
 
         // as soon as a client connects, assume it is connected
-        VerifyOrExit(buffer != NULL, ChipLogProgress(AppServer, "Received data but couldn't process it..."));
+        VerifyOrExit(!buffer.IsNull(), ChipLogProgress(AppServer, "Received data but couldn't process it..."));
         VerifyOrExit(header.GetSourceNodeId().HasValue(), ChipLogProgress(AppServer, "Unknown source for received message"));
 
         VerifyOrExit(state->GetPeerNodeId() != kUndefinedNodeId, ChipLogProgress(AppServer, "Unknown source for received message"));
@@ -62,16 +62,9 @@
 
         ChipLogProgress(AppServer, "Packet received from %s: %zu bytes", src_addr, static_cast<size_t>(data_len));
 
-        HandleDataModelMessage(header, buffer, mgr);
-        buffer = NULL;
+        HandleDataModelMessage(header, std::move(buffer), mgr);
 
-    exit:
-        // HandleDataModelMessage calls Free on the buffer without an AddRef, if HandleDataModelMessage was not called, free the
-        // buffer.
-        if (buffer != NULL)
-        {
-            System::PacketBuffer::Free(buffer);
-        }
+    exit:;
     }
 
     void OnNewConnection(const Transport::PeerConnectionState * state, SecureSessionMgr * mgr) override
diff --git a/examples/common/chip-app-server/include/DataModelHandler.h b/examples/common/chip-app-server/include/DataModelHandler.h
index 35a4524..39854b8 100644
--- a/examples/common/chip-app-server/include/DataModelHandler.h
+++ b/examples/common/chip-app-server/include/DataModelHandler.h
@@ -33,5 +33,6 @@
  * @param [in] buffer The buffer holding the message.  This function guarantees
  *                    that it will free the buffer before returning.
  */
-void HandleDataModelMessage(const chip::PacketHeader & header, chip::System::PacketBuffer * buffer, chip::SecureSessionMgr * mgr);
+void HandleDataModelMessage(const chip::PacketHeader & header, chip::System::PacketBufferHandle buffer,
+                            chip::SecureSessionMgr * mgr);
 void InitDataModelHandler();
diff --git a/examples/common/chip-app-server/include/RendezvousServer.h b/examples/common/chip-app-server/include/RendezvousServer.h
index 5af5e9b..027d367 100644
--- a/examples/common/chip-app-server/include/RendezvousServer.h
+++ b/examples/common/chip-app-server/include/RendezvousServer.h
@@ -35,7 +35,7 @@
     void OnRendezvousConnectionClosed() override;
     void OnRendezvousError(CHIP_ERROR err) override;
     void OnRendezvousMessageReceived(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
-                                     System::PacketBuffer * buffer) override;
+                                     System::PacketBufferHandle buffer) override;
     void OnRendezvousComplete() override;
     void OnRendezvousStatusUpdate(Status status, CHIP_ERROR err) override;
     RendezvousSession * GetRendezvousSession() { return &mRendezvousSession; };
diff --git a/examples/temperature-measurement-app/esp32/main/ResponseServer.cpp b/examples/temperature-measurement-app/esp32/main/ResponseServer.cpp
index bbc8576..99297da 100644
--- a/examples/temperature-measurement-app/esp32/main/ResponseServer.cpp
+++ b/examples/temperature-measurement-app/esp32/main/ResponseServer.cpp
@@ -62,14 +62,14 @@
 {
 public:
     void OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader,
-                           const Transport::PeerConnectionState * state, System::PacketBuffer * buffer,
+                           const Transport::PeerConnectionState * state, System::PacketBufferHandle buffer,
                            SecureSessionMgr * mgr) override
     {
         CHIP_ERROR err;
         const size_t data_len = buffer->DataLength();
 
         // as soon as a client connects, assume it is connected
-        VerifyOrExit(mgr != nullptr && buffer != nullptr, ESP_LOGE(TAG, "Received data but couldn't process it..."));
+        VerifyOrExit(mgr != nullptr && !buffer.IsNull(), ESP_LOGE(TAG, "Received data but couldn't process it..."));
         VerifyOrExit(state->GetPeerNodeId() != kUndefinedNodeId, ESP_LOGE(TAG, "Unknown source for received message"));
 
         {
@@ -80,16 +80,9 @@
             ESP_LOGI(TAG, "Packet received from %s: %zu bytes", src_addr, static_cast<size_t>(data_len));
         }
 
-        HandleDataModelMessage(header, buffer, mgr);
-        buffer = nullptr;
+        HandleDataModelMessage(header, std::move(buffer), mgr);
 
-    exit:
-
-        // SendTo calls Free on the buffer without an AddRef, if SendTo was not called, free the buffer.
-        if (buffer != nullptr)
-        {
-            System::PacketBuffer::Free(buffer);
-        }
+    exit:;
     }
 
     void OnReceiveError(CHIP_ERROR error, const Transport::PeerAddress & source, SecureSessionMgr * mgr) override
@@ -111,7 +104,7 @@
      * Echo messages should generally not have a first byte with those values, so we
      * can use that to try to distinguish between the two.
      */
-    bool ContentMayBeADataModelMessage(System::PacketBuffer * buffer)
+    bool ContentMayBeADataModelMessage(const System::PacketBufferHandle & buffer)
     {
         const size_t data_len      = buffer->DataLength();
         const uint8_t * data       = buffer->Start();
diff --git a/src/ble/BLEEndPoint.cpp b/src/ble/BLEEndPoint.cpp
index 0064608..a72485f 100644
--- a/src/ble/BLEEndPoint.cpp
+++ b/src/ble/BLEEndPoint.cpp
@@ -132,7 +132,7 @@
         req.SetSupportedProtocolVersion(i, CHIP_BLE_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION - i);
     }
 
-    err = req.Encode(buf.Get_ForNow());
+    err = req.Encode(buf);
     SuccessOrExit(err);
 
     // Start connect timer. Canceled when end point freed or connection established.
@@ -722,7 +722,9 @@
         sentAck = false;
     }
 
-    return mBtpEngine.HandleCharacteristicSend(data, sentAck);
+    System::PacketBufferHandle data_ForNow;
+    data_ForNow.Adopt(data);
+    return mBtpEngine.HandleCharacteristicSend(std::move(data_ForNow), sentAck);
 }
 
 BLE_ERROR BLEEndPoint::SendNextMessage()
@@ -1104,7 +1106,7 @@
     return err;
 }
 
-BLE_ERROR BLEEndPoint::HandleCapabilitiesRequestReceived(PacketBuffer * data)
+BLE_ERROR BLEEndPoint::HandleCapabilitiesRequestReceived(PacketBufferHandle data)
 {
     BLE_ERROR err = BLE_NO_ERROR;
     BleTransportCapabilitiesRequestMessage req;
@@ -1112,7 +1114,7 @@
     PacketBufferHandle responseBuf;
     uint16_t mtu;
 
-    VerifyOrExit(data != nullptr, err = BLE_ERROR_BAD_ARGS);
+    VerifyOrExit(!data.IsNull(), err = BLE_ERROR_BAD_ARGS);
 
     mState = kState_Connecting;
 
@@ -1179,7 +1181,7 @@
     }
     ChipLogProgress(Ble, "using BTP fragment sizes rx %d / tx %d.", mBtpEngine.GetRxFragmentSize(), mBtpEngine.GetTxFragmentSize());
 
-    err = resp.Encode(responseBuf.Get_ForNow());
+    err = resp.Encode(responseBuf);
     SuccessOrExit(err);
 
     // Stash capabilities response payload and wait for subscription from central.
@@ -1190,20 +1192,15 @@
     SuccessOrExit(err);
 
 exit:
-    if (data != nullptr)
-    {
-        PacketBuffer::Free(data);
-    }
-
     return err;
 }
 
-BLE_ERROR BLEEndPoint::HandleCapabilitiesResponseReceived(PacketBuffer * data)
+BLE_ERROR BLEEndPoint::HandleCapabilitiesResponseReceived(PacketBufferHandle data)
 {
     BLE_ERROR err = BLE_NO_ERROR;
     BleTransportCapabilitiesResponseMessage resp;
 
-    VerifyOrExit(data != nullptr, err = BLE_ERROR_BAD_ARGS);
+    VerifyOrExit(!data.IsNull(), err = BLE_ERROR_BAD_ARGS);
 
     // Decode BTP capabilities response.
     err = BleTransportCapabilitiesResponseMessage::Decode((*data), resp);
@@ -1259,11 +1256,6 @@
     SuccessOrExit(err);
 
 exit:
-    if (data != nullptr)
-    {
-        PacketBuffer::Free(data);
-    }
-
     return err;
 }
 
@@ -1292,7 +1284,7 @@
     return (newRemoteWindowBoundary - newestUnackedSentSeqNum);
 }
 
-BLE_ERROR BLEEndPoint::Receive(PacketBuffer * data)
+BLE_ERROR BLEEndPoint::Receive(PacketBufferHandle data)
 {
     ChipLogDebugBleEndPoint(Ble, "+++++++++++++++++++++ entered receive");
     BLE_ERROR err                = BLE_NO_ERROR;
@@ -1324,8 +1316,7 @@
                 VerifyOrExit(mState == kState_Connecting, err = BLE_ERROR_INCORRECT_STATE);
                 SetFlag(mConnStateFlags, kConnState_CapabilitiesMsgReceived, true);
 
-                err  = HandleCapabilitiesResponseReceived(data);
-                data = nullptr;
+                err = HandleCapabilitiesResponseReceived(std::move(data));
                 SuccessOrExit(err);
             }
             else // Or, a peripheral receiving a capabilities request write...
@@ -1334,8 +1325,7 @@
                 VerifyOrExit(mState == kState_Ready, err = BLE_ERROR_INCORRECT_STATE);
                 SetFlag(mConnStateFlags, kConnState_CapabilitiesMsgReceived, true);
 
-                err  = HandleCapabilitiesRequestReceived(data);
-                data = nullptr;
+                err = HandleCapabilitiesRequestReceived(std::move(data));
 
                 if (err != BLE_NO_ERROR)
                 {
@@ -1368,8 +1358,7 @@
     mBtpEngine.LogStateDebug();
 
     // Pass received packet into BTP protocol engine.
-    err  = mBtpEngine.HandleCharacteristicReceived(data, receivedAck, didReceiveAck);
-    data = nullptr; // Buffer consumed by protocol engine; either freed or added to message reassembly area.
+    err = mBtpEngine.HandleCharacteristicReceived(std::move(data), receivedAck, didReceiveAck);
 
     ChipLogDebugBleEndPoint(Ble, "BTP rx'd characteristic, state after:");
     mBtpEngine.LogStateDebug();
@@ -1457,7 +1446,8 @@
     if (mBtpEngine.RxState() == BtpEngine::kState_Complete)
     {
         // Take ownership of message PacketBuffer
-        PacketBuffer * full_packet = mBtpEngine.RxPacket();
+        System::PacketBufferHandle full_packet;
+        full_packet.Adopt(mBtpEngine.RxPacket());
         mBtpEngine.ClearRxPacket();
 
         ChipLogDebugBleEndPoint(Ble, "reassembled whole msg, len = %d", full_packet->DataLength());
@@ -1470,7 +1460,7 @@
                                     full_packet->DataLength(), mBtpEngine.RxPacketType());
             // Pass received control message up the stack.
             mBtpEngine.SetRxPacketSeq(receivedAck);
-            OnCommandReceived(this, full_packet);
+            OnCommandReceived(this, std::move(full_packet));
         }
         else
 #endif
@@ -1478,21 +1468,11 @@
             if (OnMessageReceived && mState != kState_Closing)
         {
             // Pass received message up the stack.
-            OnMessageReceived(this, full_packet);
-        }
-        else
-        {
-            // Free received message if there's no one to own it.
-            PacketBuffer::Free(full_packet);
+            OnMessageReceived(this, std::move(full_packet));
         }
     }
 
 exit:
-    if (data != nullptr)
-    {
-        PacketBuffer::Free(data);
-    }
-
     if (err != BLE_NO_ERROR)
     {
         DoClose(closeFlags, err);
diff --git a/src/ble/BLEEndPoint.h b/src/ble/BLEEndPoint.h
index 15f04a5..7e38654 100644
--- a/src/ble/BLEEndPoint.h
+++ b/src/ble/BLEEndPoint.h
@@ -81,14 +81,14 @@
     typedef void (*OnConnectCompleteFunct)(BLEEndPoint * endPoint, BLE_ERROR err);
     OnConnectCompleteFunct OnConnectComplete;
 
-    typedef void (*OnMessageReceivedFunct)(BLEEndPoint * endPoint, PacketBuffer * msg);
+    typedef void (*OnMessageReceivedFunct)(BLEEndPoint * endPoint, PacketBufferHandle msg);
     OnMessageReceivedFunct OnMessageReceived;
 
     typedef void (*OnConnectionClosedFunct)(BLEEndPoint * endPoint, BLE_ERROR err);
     OnConnectionClosedFunct OnConnectionClosed;
 
 #if CHIP_ENABLE_CHIPOBLE_TEST
-    typedef void (*OnCommandReceivedFunct)(BLEEndPoint * endPoint, PacketBuffer * msg);
+    typedef void (*OnCommandReceivedFunct)(BLEEndPoint * endPoint, PacketBufferHandle msg);
     OnCommandReceivedFunct OnCommandReceived;
     inline void SetOnCommandReceivedCB(OnCommandReceivedFunct cb) { OnCommandReceived = cb; };
     BtpEngineTest mBtpEngineTest;
@@ -98,7 +98,7 @@
 
     // Public functions:
     BLE_ERROR Send(PacketBuffer * data);
-    BLE_ERROR Receive(PacketBuffer * data);
+    BLE_ERROR Receive(PacketBufferHandle data);
     BLE_ERROR StartConnect();
 
     bool IsUnsubscribePending() const;
@@ -184,8 +184,8 @@
     BLE_ERROR HandleGattSendConfirmationReceived();
     BLE_ERROR HandleHandshakeConfirmationReceived();
     BLE_ERROR HandleFragmentConfirmationReceived();
-    BLE_ERROR HandleCapabilitiesRequestReceived(PacketBuffer * data);
-    BLE_ERROR HandleCapabilitiesResponseReceived(PacketBuffer * data);
+    BLE_ERROR HandleCapabilitiesRequestReceived(PacketBufferHandle data);
+    BLE_ERROR HandleCapabilitiesResponseReceived(PacketBufferHandle data);
     SequenceNumber_t AdjustRemoteReceiveWindow(SequenceNumber_t lastReceivedAck, SequenceNumber_t maxRemoteWindowSize,
                                                SequenceNumber_t newestUnackedSentSeqNum);
 
diff --git a/src/ble/BleLayer.cpp b/src/ble/BleLayer.cpp
index 749ad56..f25a0a2 100644
--- a/src/ble/BleLayer.cpp
+++ b/src/ble/BleLayer.cpp
@@ -197,7 +197,7 @@
     mSupportedProtocolVersions[(index / 2)] |= version;
 }
 
-BLE_ERROR BleTransportCapabilitiesRequestMessage::Encode(PacketBuffer * msgBuf) const
+BLE_ERROR BleTransportCapabilitiesRequestMessage::Encode(const PacketBufferHandle & msgBuf) const
 {
     uint8_t * p   = msgBuf->Start();
     BLE_ERROR err = BLE_NO_ERROR;
@@ -247,7 +247,7 @@
 
 // BleTransportCapabilitiesResponseMessage implementation:
 
-BLE_ERROR BleTransportCapabilitiesResponseMessage::Encode(PacketBuffer * msgBuf) const
+BLE_ERROR BleTransportCapabilitiesResponseMessage::Encode(const PacketBufferHandle & msgBuf) const
 {
     uint8_t * p   = msgBuf->Start();
     BLE_ERROR err = BLE_NO_ERROR;
@@ -415,7 +415,7 @@
 }
 
 // Handle remote central's initiation of CHIP over BLE protocol handshake.
-BLE_ERROR BleLayer::HandleBleTransportConnectionInitiated(BLE_CONNECTION_OBJECT connObj, PacketBuffer * pBuf)
+BLE_ERROR BleLayer::HandleBleTransportConnectionInitiated(BLE_CONNECTION_OBJECT connObj, PacketBufferHandle pBuf)
 {
     BLE_ERROR err             = BLE_NO_ERROR;
     BLEEndPoint * newEndPoint = nullptr;
@@ -427,16 +427,10 @@
 
     newEndPoint->mAppState = mAppState;
 
-    err  = newEndPoint->Receive(pBuf);
-    pBuf = nullptr;
+    err = newEndPoint->Receive(std::move(pBuf));
     SuccessOrExit(err); // If we fail here, end point will have already released connection and freed itself.
 
 exit:
-    if (pBuf != nullptr)
-    {
-        PacketBuffer::Free(pBuf);
-    }
-
     // If we failed to allocate a new end point, release underlying BLE connection. Central's handshake will time out
     // if the application decides to keep the BLE connection open.
     if (newEndPoint == nullptr)
@@ -453,7 +447,7 @@
 }
 
 bool BleLayer::HandleWriteReceived(BLE_CONNECTION_OBJECT connObj, const ChipBleUUID * svcId, const ChipBleUUID * charId,
-                                   PacketBuffer * pBuf)
+                                   PacketBufferHandle pBuf)
 {
     if (!UUIDsMatch(&CHIP_BLE_SVC_ID, svcId))
     {
@@ -463,7 +457,7 @@
 
     if (UUIDsMatch(&CHIP_BLE_CHAR_1_ID, charId))
     {
-        if (pBuf == nullptr)
+        if (pBuf.IsNull())
         {
             ChipLogError(Ble, "rcvd null ble write");
             ExitNow();
@@ -474,8 +468,7 @@
 
         if (endPoint != nullptr)
         {
-            BLE_ERROR status = endPoint->Receive(pBuf);
-            pBuf             = nullptr;
+            BLE_ERROR status = endPoint->Receive(std::move(pBuf));
             if (status != BLE_NO_ERROR)
             {
                 ChipLogError(Ble, "BLEEndPoint rcv failed, err = %d", status);
@@ -483,8 +476,7 @@
         }
         else
         {
-            BLE_ERROR status = HandleBleTransportConnectionInitiated(connObj, pBuf);
-            pBuf             = nullptr;
+            BLE_ERROR status = HandleBleTransportConnectionInitiated(connObj, std::move(pBuf));
             if (status != BLE_NO_ERROR)
             {
                 ChipLogError(Ble, "failed handle new chip BLE connection, status = %d", status);
@@ -497,16 +489,11 @@
     }
 
 exit:
-    if (pBuf != nullptr)
-    {
-        PacketBuffer::Free(pBuf);
-    }
-
     return true;
 }
 
 bool BleLayer::HandleIndicationReceived(BLE_CONNECTION_OBJECT connObj, const ChipBleUUID * svcId, const ChipBleUUID * charId,
-                                        PacketBuffer * pBuf)
+                                        PacketBufferHandle pBuf)
 {
     if (!UUIDsMatch(&CHIP_BLE_SVC_ID, svcId))
     {
@@ -515,7 +502,7 @@
 
     if (UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId))
     {
-        if (pBuf == nullptr)
+        if (pBuf.IsNull())
         {
             ChipLogError(Ble, "rcvd null ble indication");
             ExitNow();
@@ -526,8 +513,7 @@
 
         if (endPoint != nullptr)
         {
-            BLE_ERROR status = endPoint->Receive(pBuf);
-            pBuf             = nullptr;
+            BLE_ERROR status = endPoint->Receive(std::move(pBuf));
             if (status != BLE_NO_ERROR)
             {
                 ChipLogError(Ble, "BLEEndPoint rcv failed, err = %d", status);
@@ -544,11 +530,6 @@
     }
 
 exit:
-    if (pBuf != nullptr)
-    {
-        PacketBuffer::Free(pBuf);
-    }
-
     return true;
 }
 
diff --git a/src/ble/BleLayer.h b/src/ble/BleLayer.h
index 12f64c4..b1ddd0a 100644
--- a/src/ble/BleLayer.h
+++ b/src/ble/BleLayer.h
@@ -154,7 +154,7 @@
     void SetSupportedProtocolVersion(uint8_t index, uint8_t version);
 
     /// Must be able to reserve 20 byte data length in msgBuf.
-    BLE_ERROR Encode(PacketBuffer * msgBuf) const;
+    BLE_ERROR Encode(const System::PacketBufferHandle & msgBuf) const;
 
     static BLE_ERROR Decode(const PacketBuffer & msgBuf, BleTransportCapabilitiesRequestMessage & msg);
 };
@@ -188,7 +188,7 @@
     uint8_t mWindowSize;
 
     /// Must be able to reserve 20 byte data length in msgBuf.
-    BLE_ERROR Encode(PacketBuffer * msgBuf) const;
+    BLE_ERROR Encode(const System::PacketBufferHandle & msgBuf) const;
 
     static BLE_ERROR Decode(const PacketBuffer & msgBuf, BleTransportCapabilitiesResponseMessage & msg);
 };
@@ -298,11 +298,11 @@
 
     /// Call when a GATT write request is received.
     bool HandleWriteReceived(BLE_CONNECTION_OBJECT connObj, const ChipBleUUID * svcId, const ChipBleUUID * charId,
-                             PacketBuffer * pBuf);
+                             System::PacketBufferHandle pBuf);
 
     /// Call when a GATT indication is received.
     bool HandleIndicationReceived(BLE_CONNECTION_OBJECT connObj, const ChipBleUUID * svcId, const ChipBleUUID * charId,
-                                  PacketBuffer * pBuf);
+                                  System::PacketBufferHandle pBuf);
 
     /// Call when an outstanding GATT write request receives a positive receipt confirmation.
     bool HandleWriteConfirmation(BLE_CONNECTION_OBJECT connObj, const ChipBleUUID * svcId, const ChipBleUUID * charId);
@@ -346,7 +346,7 @@
     void HandleDataReceived(BLE_CONNECTION_OBJECT connObj, PacketBuffer * pBuf);
     void HandleAckReceived(BLE_CONNECTION_OBJECT connObj);
     void DriveSending();
-    BLE_ERROR HandleBleTransportConnectionInitiated(BLE_CONNECTION_OBJECT connObj, PacketBuffer * pBuf);
+    BLE_ERROR HandleBleTransportConnectionInitiated(BLE_CONNECTION_OBJECT connObj, System::PacketBufferHandle pBuf);
 
     static BleTransportProtocolVersion GetHighestSupportedProtocolVersion(const BleTransportCapabilitiesRequestMessage & reqMsg);
 };
diff --git a/src/ble/BtpEngine.cpp b/src/ble/BtpEngine.cpp
index 6798a7f..6530deb 100644
--- a/src/ble/BtpEngine.cpp
+++ b/src/ble/BtpEngine.cpp
@@ -77,7 +77,7 @@
             GetFlag(rx_flags, BtpEngine::kHeaderFlag_EndMessage));
 }
 
-static void PrintBufDebug(PacketBuffer * buf)
+static void PrintBufDebug(const System::PacketBuffer * buf)
 {
 #ifdef CHIP_BTP_PROTOCOL_ENGINE_DEBUG_LOGGING_ENABLED
     uint8_t * b = buf->Start();
@@ -258,14 +258,15 @@
 //   function returns.
 //
 //   Upper layer must immediately clean up and reinitialize protocol engine if returned err != BLE_NO_ERROR.
-BLE_ERROR BtpEngine::HandleCharacteristicReceived(PacketBuffer * data, SequenceNumber_t & receivedAck, bool & didReceiveAck)
+BLE_ERROR BtpEngine::HandleCharacteristicReceived(System::PacketBufferHandle data, SequenceNumber_t & receivedAck,
+                                                  bool & didReceiveAck)
 {
     BLE_ERROR err            = BLE_NO_ERROR;
     uint8_t rx_flags         = 0;
     uint8_t cursor           = 0;
     uint8_t * characteristic = data->Start();
 
-    VerifyOrExit(data != nullptr, err = BLE_ERROR_BAD_ARGS);
+    VerifyOrExit(!data.IsNull(), err = BLE_ERROR_BAD_ARGS);
 
     mRxCharCount++;
 
@@ -301,10 +302,6 @@
     // If fragment was stand-alone ack, we're done here; no payload for message reassembler.
     if (!DidReceiveData(rx_flags))
     {
-        // Free stand-alone ack buffer.
-        PacketBuffer::Free(data);
-        data = nullptr;
-
         ExitNow();
     }
 
@@ -313,7 +310,7 @@
     data->SetDataLength(chip::min(data->DataLength(), mRxFragmentSize));
 
     ChipLogDebugBtpEngine(Ble, ">>> BTP reassembler received data:");
-    PrintBufDebug(data);
+    PrintBufDebug(data.Get_ForNow());
 
     if (mRxState == kState_Idle)
     {
@@ -332,9 +329,8 @@
 
         VerifyOrExit(mRxBuf != nullptr, err = BLE_ERROR_NO_MEMORY);
 
-        mRxBuf->AddToEnd(data);
+        mRxBuf->AddToEnd(data.Release_ForNow());
         mRxBuf->CompactHead(); // will free 'data' and adjust rx buf's end/length
-        data = nullptr;
     }
     else if (mRxState == kState_InProgress)
     {
@@ -347,9 +343,8 @@
 
         // Add received fragment to reassembled message buffer.
         data->SetStart(&(characteristic[cursor]));
-        mRxBuf->AddToEnd(data);
+        mRxBuf->AddToEnd(data.Release_ForNow());
         mRxBuf->CompactHead(); // will free 'data' and adjust rx buf's end/length
-        data = nullptr;
 
         // For now, limit BtpEngine message size to max length of 1 pbuf, as we do for chip messages sent via IP.
         // TODO add support for BtpEngine messages longer than 1 pbuf
@@ -396,16 +391,16 @@
         }
         LogState();
 
-        if (data != nullptr)
+        if (!data.IsNull())
         {
             // Tack received data onto rx buffer, to be freed when end point resets protocol engine on close.
             if (mRxBuf != nullptr)
             {
-                mRxBuf->AddToEnd(data);
+                mRxBuf->AddToEnd(data.Release_ForNow());
             }
             else
             {
-                mRxBuf = data;
+                mRxBuf = data.Release_ForNow();
             }
         }
     }
@@ -434,8 +429,9 @@
 // Calling convention:
 //   May only be called if data arg is commited for immediate, synchronous subsequent transmission.
 //   Returns false on error. Caller must free data arg on error.
-bool BtpEngine::HandleCharacteristicSend(PacketBuffer * data, bool send_ack)
+bool BtpEngine::HandleCharacteristicSend(System::PacketBufferHandle data_ForNow, bool send_ack)
 {
+    PacketBuffer * data = data_ForNow.Release_ForNow();
     uint8_t * characteristic;
     mTxCharCount++;
 
diff --git a/src/ble/BtpEngine.h b/src/ble/BtpEngine.h
index d182707..14984f6 100644
--- a/src/ble/BtpEngine.h
+++ b/src/ble/BtpEngine.h
@@ -117,7 +117,7 @@
     inline SequenceNumber_t SetRxPacketSeq(SequenceNumber_t seq) { return (mRxPacketSeq = seq); }
     inline SequenceNumber_t TxPacketSeq() { return mTxPacketSeq; }
     inline SequenceNumber_t RxPacketSeq() { return mRxPacketSeq; }
-    inline bool IsCommandPacket(PacketBuffer * p) { return GetFlag(*(p->Start()), kHeaderFlag_CommandMessage); }
+    inline bool IsCommandPacket(const PacketBufferHandle & p) { return GetFlag(*(p->Start()), kHeaderFlag_CommandMessage); }
     inline void PushPacketTag(PacketBuffer * p, PacketType_t type)
     {
         p->SetStart(p->Start() - sizeof(type));
@@ -134,8 +134,8 @@
 
     bool HasUnackedData() const;
 
-    BLE_ERROR HandleCharacteristicReceived(PacketBuffer * data, SequenceNumber_t & receivedAck, bool & didReceiveAck);
-    bool HandleCharacteristicSend(PacketBuffer * data, bool send_ack);
+    BLE_ERROR HandleCharacteristicReceived(System::PacketBufferHandle data, SequenceNumber_t & receivedAck, bool & didReceiveAck);
+    bool HandleCharacteristicSend(System::PacketBufferHandle data, bool send_ack);
     BLE_ERROR EncodeStandAloneAck(PacketBuffer * data);
 
     PacketBuffer * RxPacket();
diff --git a/src/controller/CHIPDevice.cpp b/src/controller/CHIPDevice.cpp
index ec1f9d3..451b332 100644
--- a/src/controller/CHIPDevice.cpp
+++ b/src/controller/CHIPDevice.cpp
@@ -171,13 +171,14 @@
 }
 
 void Device::OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader,
-                               const Transport::PeerConnectionState * state, System::PacketBuffer * msgBuf, SecureSessionMgr * mgr)
+                               const Transport::PeerConnectionState * state, System::PacketBufferHandle msgBuf,
+                               SecureSessionMgr * mgr)
 {
     if (mState == ConnectionState::SecureConnected)
     {
         if (mStatusDelegate != nullptr)
         {
-            mStatusDelegate->OnMessage(msgBuf);
+            mStatusDelegate->OnMessage(std::move(msgBuf));
         }
 
         // TODO: The following callback processing will need further work
diff --git a/src/controller/CHIPDevice.h b/src/controller/CHIPDevice.h
index e03959d..c13bd71 100644
--- a/src/controller/CHIPDevice.h
+++ b/src/controller/CHIPDevice.h
@@ -174,7 +174,7 @@
      * @param[in] mgr           Pointer to secure session manager which received the message
      */
     void OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader,
-                           const Transport::PeerConnectionState * state, System::PacketBuffer * msgBuf, SecureSessionMgr * mgr);
+                           const Transport::PeerConnectionState * state, System::PacketBufferHandle msgBuf, SecureSessionMgr * mgr);
 
     /**
      * @brief
@@ -276,7 +276,7 @@
      *
      * @param[in] msg Received message buffer.
      */
-    virtual void OnMessage(System::PacketBuffer * msg) = 0;
+    virtual void OnMessage(System::PacketBufferHandle msg) = 0;
 
     /**
      * @brief
diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp
index 8b06432..5b31b2c 100644
--- a/src/controller/CHIPDeviceController.cpp
+++ b/src/controller/CHIPDeviceController.cpp
@@ -319,7 +319,7 @@
 void DeviceController::OnNewConnection(const Transport::PeerConnectionState * peerConnection, SecureSessionMgr * mgr) {}
 
 void DeviceController::OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader,
-                                         const Transport::PeerConnectionState * state, System::PacketBuffer * msgBuf,
+                                         const Transport::PeerConnectionState * state, System::PacketBufferHandle msgBuf,
                                          SecureSessionMgr * mgr)
 {
     CHIP_ERROR err = CHIP_NO_ERROR;
@@ -333,7 +333,7 @@
     index = FindDeviceIndex(peer);
     VerifyOrExit(index < kNumMaxActiveDevices, err = CHIP_ERROR_INVALID_DEVICE_DESCRIPTOR);
 
-    mActiveDevices[index].OnMessageReceived(header, payloadHeader, state, msgBuf, mgr);
+    mActiveDevices[index].OnMessageReceived(header, payloadHeader, state, std::move(msgBuf), mgr);
 
 exit:
     if (err != CHIP_NO_ERROR)
diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h
index 58e0e34..3c7050a 100644
--- a/src/controller/CHIPDeviceController.h
+++ b/src/controller/CHIPDeviceController.h
@@ -196,7 +196,7 @@
 private:
     //////////// SecureSessionMgrDelegate Implementation ///////////////
     void OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader,
-                           const Transport::PeerConnectionState * state, System::PacketBuffer * msgBuf,
+                           const Transport::PeerConnectionState * state, System::PacketBufferHandle msgBuf,
                            SecureSessionMgr * mgr) override;
 
     void OnNewConnection(const Transport::PeerConnectionState * state, SecureSessionMgr * mgr) override;
diff --git a/src/controller/CHIPDeviceController_deprecated.cpp b/src/controller/CHIPDeviceController_deprecated.cpp
index eaaa237..20c94a3 100644
--- a/src/controller/CHIPDeviceController_deprecated.cpp
+++ b/src/controller/CHIPDeviceController_deprecated.cpp
@@ -227,11 +227,11 @@
     return CHIP_NO_ERROR;
 }
 
-void ChipDeviceController::OnMessage(System::PacketBuffer * msgBuf)
+void ChipDeviceController::OnMessage(System::PacketBufferHandle msgBuf)
 {
     if (mOnComplete.Response != nullptr)
     {
-        mOnComplete.Response(this, mAppReqState, msgBuf);
+        mOnComplete.Response(this, mAppReqState, std::move(msgBuf));
     }
 }
 
diff --git a/src/controller/CHIPDeviceController_deprecated.h b/src/controller/CHIPDeviceController_deprecated.h
index c2d05ce..462523d 100644
--- a/src/controller/CHIPDeviceController_deprecated.h
+++ b/src/controller/CHIPDeviceController_deprecated.h
@@ -50,7 +50,8 @@
 typedef void (*CompleteHandler)(ChipDeviceController * deviceController, void * appReqState);
 typedef void (*ErrorHandler)(ChipDeviceController * deviceController, void * appReqState, CHIP_ERROR err,
                              const Inet::IPPacketInfo * pktInfo);
-typedef void (*MessageReceiveHandler)(ChipDeviceController * deviceController, void * appReqState, System::PacketBuffer * payload);
+typedef void (*MessageReceiveHandler)(ChipDeviceController * deviceController, void * appReqState,
+                                      System::PacketBufferHandle payload);
 
 class DLL_EXPORT ChipDeviceController : public Controller::DeviceStatusDelegate
 {
@@ -181,7 +182,7 @@
     CHIP_ERROR SetDevicePairingDelegate(Controller::DevicePairingDelegate * pairingDelegate);
 
     //////////// DeviceStatusDelegate Implementation ///////////////
-    void OnMessage(System::PacketBuffer * msg) override;
+    void OnMessage(System::PacketBufferHandle msg) override;
 
 private:
     enum
diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp
index f68fd75..44ed801 100644
--- a/src/controller/java/CHIPDeviceController-JNI.cpp
+++ b/src/controller/java/CHIPDeviceController-JNI.cpp
@@ -68,7 +68,7 @@
 
 static void HandleKeyExchange(ChipDeviceController * deviceController, const Transport::PeerConnectionState * state,
                               void * appReqState);
-static void HandleEchoResponse(ChipDeviceController * deviceController, void * appReqState, System::PacketBuffer * payload);
+static void HandleEchoResponse(ChipDeviceController * deviceController, void * appReqState, System::PacketBufferHandle payload);
 static void HandleSimpleOperationComplete(ChipDeviceController * deviceController, const char * operation);
 static void HandleNotifyChipConnectionClosed(BLE_CONNECTION_OBJECT connObj);
 static bool HandleSendCharacteristic(BLE_CONNECTION_OBJECT connObj, const uint8_t * svcId, const uint8_t * charId,
@@ -469,7 +469,7 @@
     buffer->SetDataLength(valueLength);
 
     pthread_mutex_lock(&sStackLock);
-    sBleLayer.HandleIndicationReceived(connObj, &svcUUID, &charUUID, buffer.Release_ForNow());
+    sBleLayer.HandleIndicationReceived(connObj, &svcUUID, &charUUID, std::move(buffer));
     pthread_mutex_unlock(&sStackLock);
 exit:
     env->ReleaseByteArrayElements(value, valueBegin, 0);
@@ -670,7 +670,7 @@
     HandleSimpleOperationComplete(deviceController, (const char *) appReqState);
 }
 
-void HandleEchoResponse(ChipDeviceController * deviceController, void * appReqState, System::PacketBuffer * payload)
+void HandleEchoResponse(ChipDeviceController * deviceController, void * appReqState, System::PacketBufferHandle payload)
 {
     StackUnlockGuard unlockGuard;
     JNIEnv * env;
@@ -703,7 +703,6 @@
 
 exit:
     env->ExceptionClear();
-    System::PacketBuffer::Free(payload);
 }
 
 void HandleNotifyChipConnectionClosed(BLE_CONNECTION_OBJECT connObj)
diff --git a/src/controller/python/ChipDeviceController-ScriptBinding.cpp b/src/controller/python/ChipDeviceController-ScriptBinding.cpp
index 35063b0..3518f94 100644
--- a/src/controller/python/ChipDeviceController-ScriptBinding.cpp
+++ b/src/controller/python/ChipDeviceController-ScriptBinding.cpp
@@ -64,7 +64,7 @@
 typedef void (*OnErrorFunct)(chip::DeviceController::ChipDeviceController * dc, void * appReqState, CHIP_ERROR err,
                              const chip::Inet::IPPacketInfo * pi);
 typedef void (*OnMessageFunct)(chip::DeviceController::ChipDeviceController * dc, void * appReqState,
-                               chip::System::PacketBuffer * buffer);
+                               chip::System::PacketBufferHandle buffer);
 }
 
 enum BleEventType
@@ -240,8 +240,7 @@
     int maxFDs = 0;
 #if CONFIG_NETWORK_LAYER_BLE
     uint8_t bleWakeByte;
-    bool result = false;
-    chip::System::PacketBuffer * msgBuf;
+    chip::System::PacketBufferHandle msgBuf;
     ChipBleUUID svcId, charId;
     union
     {
@@ -305,8 +304,8 @@
                     {
                     case kBleEventType_Rx:
                         // build a packet buffer from the rxEv and send to blelayer.
-                        msgBuf = chip::System::PacketBuffer::New().Release_ForNow();
-                        VerifyOrExit(msgBuf != NULL, err = CHIP_ERROR_NO_MEMORY);
+                        msgBuf = chip::System::PacketBuffer::New();
+                        VerifyOrExit(!msgBuf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
 
                         memcpy(msgBuf->Start(), evu.rxEv->buffer, evu.rxEv->length);
                         msgBuf->SetDataLength(evu.rxEv->length);
@@ -315,14 +314,7 @@
                         memcpy(svcId.bytes, evu.rxEv->svcId, sizeof(svcId.bytes));
                         memcpy(charId.bytes, evu.rxEv->charId, sizeof(charId.bytes));
 
-                        result = sBle.HandleIndicationReceived(evu.txEv->connObj, &svcId, &charId, msgBuf);
-
-                        if (!result)
-                        {
-                            chip::System::PacketBuffer::Free(msgBuf);
-                        }
-
-                        msgBuf = NULL;
+                        sBle.HandleIndicationReceived(evu.txEv->connObj, &svcId, &charId, std::move(msgBuf));
                         break;
 
                     case kBleEventType_Tx:
@@ -330,7 +322,7 @@
                         memcpy(svcId.bytes, evu.txEv->svcId, sizeof(svcId.bytes));
                         memcpy(charId.bytes, evu.txEv->charId, sizeof(charId.bytes));
 
-                        result = sBle.HandleWriteConfirmation(evu.txEv->connObj, &svcId, &charId);
+                        sBle.HandleWriteConfirmation(evu.txEv->connObj, &svcId, &charId);
                         break;
 
                     case kBleEventType_Subscribe:
@@ -342,7 +334,7 @@
                         case kBleSubOp_Subscribe:
                             if (evu.subscribeEv->status)
                             {
-                                result = sBle.HandleSubscribeComplete(evu.subscribeEv->connObj, &svcId, &charId);
+                                sBle.HandleSubscribeComplete(evu.subscribeEv->connObj, &svcId, &charId);
                             }
                             else
                             {
@@ -353,7 +345,7 @@
                         case kBleSubOp_Unsubscribe:
                             if (evu.subscribeEv->status)
                             {
-                                result = sBle.HandleUnsubscribeComplete(evu.subscribeEv->connObj, &svcId, &charId);
+                                sBle.HandleUnsubscribeComplete(evu.subscribeEv->connObj, &svcId, &charId);
                             }
                             else
                             {
diff --git a/src/inet/IPEndPointBasis.cpp b/src/inet/IPEndPointBasis.cpp
index 4c69254..264de17 100644
--- a/src/inet/IPEndPointBasis.cpp
+++ b/src/inet/IPEndPointBasis.cpp
@@ -30,6 +30,7 @@
 #include "IPEndPointBasis.h"
 
 #include <string.h>
+#include <utility>
 
 #include <inet/EndPointBasis.h>
 #include <inet/InetInterface.h>
@@ -608,7 +609,7 @@
 }
 
 #if CHIP_SYSTEM_CONFIG_USE_LWIP
-void IPEndPointBasis::HandleDataReceived(PacketBuffer * aBuffer)
+void IPEndPointBasis::HandleDataReceived(System::PacketBufferHandle aBuffer)
 {
     if ((mState == kState_Listening) && (OnMessageReceived != NULL))
     {
@@ -618,19 +619,14 @@
         {
             const IPPacketInfo pktInfoCopy = *pktInfo; // copy the address info so that the app can free the
                                                        // PacketBuffer without affecting access to address info.
-            OnMessageReceived(this, aBuffer, &pktInfoCopy);
+            OnMessageReceived(this, std::move(aBuffer), &pktInfoCopy);
         }
         else
         {
             if (OnReceiveError != NULL)
                 OnReceiveError(this, INET_ERROR_INBOUND_MESSAGE_TOO_BIG, NULL);
-            PacketBuffer::Free(aBuffer);
         }
     }
-    else
-    {
-        PacketBuffer::Free(aBuffer);
-    }
 }
 
 /**
@@ -659,7 +655,7 @@
  *     packets that arrive without an Ethernet header.
  *
  */
-IPPacketInfo * IPEndPointBasis::GetPacketInfo(PacketBuffer * aBuffer)
+IPPacketInfo * IPEndPointBasis::GetPacketInfo(const System::PacketBufferHandle & aBuffer)
 {
     uintptr_t lStart;
     uintptr_t lPacketInfoStart;
@@ -1161,7 +1157,7 @@
 
     if (lStatus == INET_NO_ERROR)
     {
-        OnMessageReceived(this, lBuffer.Release_ForNow(), &lPacketInfo);
+        OnMessageReceived(this, std::move(lBuffer), &lPacketInfo);
     }
     else
     {
diff --git a/src/inet/IPEndPointBasis.h b/src/inet/IPEndPointBasis.h
index 6706483..d6e274f 100644
--- a/src/inet/IPEndPointBasis.h
+++ b/src/inet/IPEndPointBasis.h
@@ -90,7 +90,7 @@
      *  member to process message text reception events on \c endPoint where
      *  \c msg is the message text received from the sender at \c senderAddr.
      */
-    typedef void (*OnMessageReceivedFunct)(IPEndPointBasis * endPoint, chip::System::PacketBuffer * msg,
+    typedef void (*OnMessageReceivedFunct)(IPEndPointBasis * endPoint, chip::System::PacketBufferHandle msg,
                                            const IPPacketInfo * pktInfo);
 
     /** The endpoint's message reception event handling function delegate. */
@@ -124,9 +124,9 @@
     static struct netif * FindNetifFromInterfaceId(InterfaceId aInterfaceId);
 
 protected:
-    void HandleDataReceived(chip::System::PacketBuffer * aBuffer);
+    void HandleDataReceived(chip::System::PacketBufferHandle aBuffer);
 
-    static IPPacketInfo * GetPacketInfo(chip::System::PacketBuffer * aBuffer);
+    static IPPacketInfo * GetPacketInfo(const chip::System::PacketBufferHandle & aBuffer);
 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
 
 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
diff --git a/src/inet/InetLayer.cpp b/src/inet/InetLayer.cpp
index d16ba43..f8173bf 100644
--- a/src/inet/InetLayer.cpp
+++ b/src/inet/InetLayer.cpp
@@ -57,6 +57,7 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <string.h>
+#include <utility>
 
 #if CHIP_SYSTEM_CONFIG_USE_LWIP
 #include <lwip/netif.h>
@@ -1079,15 +1080,21 @@
 #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
 
 #if INET_CONFIG_ENABLE_RAW_ENDPOINT
-    case kInetEvent_RawDataReceived:
-        static_cast<RawEndPoint &>(aTarget).HandleDataReceived(reinterpret_cast<chip::System::PacketBuffer *>(aArgument));
-        break;
+    case kInetEvent_RawDataReceived: {
+        chip::System::PacketBufferHandle buf;
+        buf.Adopt(reinterpret_cast<chip::System::PacketBuffer *>(aArgument));
+        static_cast<RawEndPoint &>(aTarget).HandleDataReceived(std::move(buf));
+    }
+    break;
 #endif // INET_CONFIG_ENABLE_RAW_ENDPOINT
 
 #if INET_CONFIG_ENABLE_UDP_ENDPOINT
-    case kInetEvent_UDPDataReceived:
-        static_cast<UDPEndPoint &>(aTarget).HandleDataReceived(reinterpret_cast<chip::System::PacketBuffer *>(aArgument));
-        break;
+    case kInetEvent_UDPDataReceived: {
+        chip::System::PacketBufferHandle buf;
+        buf.Adopt(reinterpret_cast<chip::System::PacketBuffer *>(aArgument));
+        static_cast<UDPEndPoint &>(aTarget).HandleDataReceived(std::move(buf));
+    }
+    break;
 #endif // INET_CONFIG_ENABLE_UDP_ENDPOINT
 
 #if INET_CONFIG_ENABLE_DNS_RESOLVER
diff --git a/src/inet/RawEndPoint.cpp b/src/inet/RawEndPoint.cpp
index b4defce..35c2360 100644
--- a/src/inet/RawEndPoint.cpp
+++ b/src/inet/RawEndPoint.cpp
@@ -69,6 +69,7 @@
 #endif
 
 #include <string.h>
+#include <utility>
 
 namespace chip {
 namespace Inet {
@@ -831,9 +832,9 @@
 
 #if CHIP_SYSTEM_CONFIG_USE_LWIP
 
-void RawEndPoint::HandleDataReceived(PacketBuffer * msg)
+void RawEndPoint::HandleDataReceived(System::PacketBufferHandle msg)
 {
-    IPEndPointBasis::HandleDataReceived(msg);
+    IPEndPointBasis::HandleDataReceived(std::move(msg));
 }
 
 INET_ERROR RawEndPoint::GetPCB(IPAddressType addrType)
@@ -985,7 +986,10 @@
 
     if (enqueue)
     {
-        pktInfo = GetPacketInfo(buf);
+        System::PacketBufferHandle buf_ForNow;
+        buf_ForNow.Adopt(buf);
+        pktInfo = GetPacketInfo(buf_ForNow);
+        buf     = buf_ForNow.Release_ForNow();
 
         if (pktInfo != NULL)
         {
diff --git a/src/inet/RawEndPoint.h b/src/inet/RawEndPoint.h
index 1a80676..5638549 100644
--- a/src/inet/RawEndPoint.h
+++ b/src/inet/RawEndPoint.h
@@ -95,7 +95,7 @@
     uint8_t NumICMPTypes;
     const uint8_t * ICMPTypes;
 
-    void HandleDataReceived(chip::System::PacketBuffer * msg);
+    void HandleDataReceived(chip::System::PacketBufferHandle msg);
     INET_ERROR GetPCB(IPAddressType addrType);
 
 #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
diff --git a/src/inet/TCPEndPoint.cpp b/src/inet/TCPEndPoint.cpp
index 44eedec..dab318c 100644
--- a/src/inet/TCPEndPoint.cpp
+++ b/src/inet/TCPEndPoint.cpp
@@ -62,6 +62,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <utility>
 
 // SOCK_CLOEXEC not defined on all platforms, e.g. iOS/macOS:
 #ifdef SOCK_CLOEXEC
@@ -1385,7 +1386,9 @@
     {
         PacketBuffer * rcvQueue = mRcvQueue;
         mRcvQueue               = nullptr;
-        OnDataReceived(this, rcvQueue);
+        System::PacketBufferHandle rcvQueue_ForNow;
+        rcvQueue_ForNow.Adopt(rcvQueue);
+        OnDataReceived(this, std::move(rcvQueue_ForNow));
     }
 
     // If the connection is closing, and the receive queue is now empty, call DoClose() to complete
diff --git a/src/inet/TCPEndPoint.h b/src/inet/TCPEndPoint.h
index 17559a8..a6f0234 100644
--- a/src/inet/TCPEndPoint.h
+++ b/src/inet/TCPEndPoint.h
@@ -444,7 +444,7 @@
      *  the \c AckReceive method. The \c Free method on the data buffer must
      *  also be invoked unless the \c PutBackReceivedData is used instead.
      */
-    typedef void (*OnDataReceivedFunct)(TCPEndPoint * endPoint, chip::System::PacketBuffer * data);
+    typedef void (*OnDataReceivedFunct)(TCPEndPoint * endPoint, chip::System::PacketBufferHandle data);
 
     /**
      * The endpoint's message text reception event handling function delegate.
diff --git a/src/inet/UDPEndPoint.cpp b/src/inet/UDPEndPoint.cpp
index a16108d..837fc11 100644
--- a/src/inet/UDPEndPoint.cpp
+++ b/src/inet/UDPEndPoint.cpp
@@ -64,6 +64,7 @@
 #include "arpa-inet-compatibility.h"
 
 #include <string.h>
+#include <utility>
 
 // SOCK_CLOEXEC not defined on all platforms, e.g. iOS/macOS:
 #ifdef SOCK_CLOEXEC
@@ -778,9 +779,9 @@
 
 #if CHIP_SYSTEM_CONFIG_USE_LWIP
 
-void UDPEndPoint::HandleDataReceived(PacketBuffer * msg)
+void UDPEndPoint::HandleDataReceived(System::PacketBufferHandle msg)
 {
-    IPEndPointBasis::HandleDataReceived(msg);
+    IPEndPointBasis::HandleDataReceived(std::move(msg));
 }
 
 INET_ERROR UDPEndPoint::GetPCB(IPAddressType addrType)
@@ -874,7 +875,10 @@
     chip::System::Layer & lSystemLayer = ep->SystemLayer();
     IPPacketInfo * pktInfo             = NULL;
 
-    pktInfo = GetPacketInfo(buf);
+    System::PacketBufferHandle buf_ForNow;
+    buf_ForNow.Adopt(buf);
+    pktInfo = GetPacketInfo(buf_ForNow);
+    buf     = buf_ForNow.Release_ForNow();
     if (pktInfo != NULL)
     {
 #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
diff --git a/src/inet/UDPEndPoint.h b/src/inet/UDPEndPoint.h
index c567a14..7092c35 100644
--- a/src/inet/UDPEndPoint.h
+++ b/src/inet/UDPEndPoint.h
@@ -74,7 +74,7 @@
     void Init(InetLayer * inetLayer);
 
 #if CHIP_SYSTEM_CONFIG_USE_LWIP
-    void HandleDataReceived(chip::System::PacketBuffer * msg);
+    void HandleDataReceived(chip::System::PacketBufferHandle msg);
     INET_ERROR GetPCB(IPAddressType addrType4);
 #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
     static void LwIPReceiveUDPMessage(void * arg, struct udp_pcb * pcb, struct pbuf * p, const ip_addr_t * addr, u16_t port);
diff --git a/src/inet/tests/TestInetLayer.cpp b/src/inet/tests/TestInetLayer.cpp
index 92ebd13..1ca62e2 100644
--- a/src/inet/tests/TestInetLayer.cpp
+++ b/src/inet/tests/TestInetLayer.cpp
@@ -498,7 +498,7 @@
     printf("%u/%u received\n", aStats.mReceive.mActual, aStats.mReceive.mExpected);
 }
 
-static bool HandleDataReceived(const PacketBuffer * aBuffer, bool aCheckBuffer, uint8_t aFirstValue)
+static bool HandleDataReceived(const PacketBufferHandle & aBuffer, bool aCheckBuffer, uint8_t aFirstValue)
 {
     const bool lStatsByPacket = true;
     bool lStatus              = true;
@@ -512,7 +512,7 @@
     return (lStatus);
 }
 
-static bool HandleDataReceived(const PacketBuffer * aBuffer, bool aCheckBuffer)
+static bool HandleDataReceived(const PacketBufferHandle & aBuffer, bool aCheckBuffer)
 {
     const uint8_t lFirstValue = 0;
     bool lStatus              = true;
@@ -591,7 +591,7 @@
 
 static void HandleTCPDataSent(TCPEndPoint * aEndPoint, uint16_t len) {}
 
-static void HandleTCPDataReceived(TCPEndPoint * aEndPoint, PacketBuffer * aBuffer)
+static void HandleTCPDataReceived(TCPEndPoint * aEndPoint, PacketBufferHandle aBuffer)
 {
     const uint32_t lFirstValueReceived = sTestState.mStats.mReceive.mActual;
     const uint8_t lFirstValue          = uint8_t(lFirstValueReceived);
@@ -606,12 +606,11 @@
     VerifyOrExit(lFirstValue == lFirstValueReceived, lStatus = INET_ERROR_UNEXPECTED_EVENT);
 
     VerifyOrExit(aEndPoint != nullptr, lStatus = INET_ERROR_BAD_ARGS);
-    VerifyOrExit(aBuffer != nullptr, lStatus = INET_ERROR_BAD_ARGS);
+    VerifyOrExit(!aBuffer.IsNull(), lStatus = INET_ERROR_BAD_ARGS);
 
     if (aEndPoint->State != TCPEndPoint::kState_Connected)
     {
-        lStatus = aEndPoint->PutBackReceivedData(aBuffer);
-        aBuffer = nullptr;
+        lStatus = aEndPoint->PutBackReceivedData(aBuffer.Release_ForNow());
         INET_FAIL_ERROR(lStatus, "TCPEndPoint::PutBackReceivedData failed");
         goto exit;
     }
@@ -631,11 +630,6 @@
     INET_FAIL_ERROR(lStatus, "TCPEndPoint::AckReceive failed");
 
 exit:
-    if (aBuffer != nullptr)
-    {
-        PacketBuffer::Free(aBuffer);
-    }
-
     if (lStatus != INET_NO_ERROR)
     {
         SetStatusFailed(sTestState.mStatus);
@@ -668,7 +662,7 @@
 
 // Raw Endpoint Callbacks
 
-static void HandleRawMessageReceived(IPEndPointBasis * aEndPoint, PacketBuffer * aBuffer, const IPPacketInfo * aPacketInfo)
+static void HandleRawMessageReceived(IPEndPointBasis * aEndPoint, PacketBufferHandle aBuffer, const IPPacketInfo * aPacketInfo)
 {
     const bool lCheckBuffer   = true;
     const bool lStatsByPacket = true;
@@ -676,7 +670,7 @@
     bool lStatus;
 
     VerifyOrExit(aEndPoint != nullptr, lStatus = false);
-    VerifyOrExit(aBuffer != nullptr, lStatus = false);
+    VerifyOrExit(!aBuffer.IsNull(), lStatus = false);
     VerifyOrExit(aPacketInfo != nullptr, lStatus = false);
 
     Common::HandleRawMessageReceived(aEndPoint, aBuffer, aPacketInfo);
@@ -689,11 +683,11 @@
 
         aBuffer->ConsumeHead(kIPv4HeaderSize);
 
-        lStatus = Common::HandleICMPv4DataReceived(aBuffer, sTestState.mStats, !lStatsByPacket, lCheckBuffer);
+        lStatus = Common::HandleICMPv4DataReceived(std::move(aBuffer), sTestState.mStats, !lStatsByPacket, lCheckBuffer);
     }
     else if (lAddressType == kIPAddressType_IPv6)
     {
-        lStatus = Common::HandleICMPv6DataReceived(aBuffer, sTestState.mStats, !lStatsByPacket, lCheckBuffer);
+        lStatus = Common::HandleICMPv6DataReceived(std::move(aBuffer), sTestState.mStats, !lStatsByPacket, lCheckBuffer);
     }
     else
     {
@@ -706,11 +700,6 @@
     }
 
 exit:
-    if (aBuffer != nullptr)
-    {
-        PacketBuffer::Free(aBuffer);
-    }
-
     if (!lStatus)
     {
         SetStatusFailed(sTestState.mStatus);
@@ -726,13 +715,13 @@
 
 // UDP Endpoint Callbacks
 
-static void HandleUDPMessageReceived(IPEndPointBasis * aEndPoint, PacketBuffer * aBuffer, const IPPacketInfo * aPacketInfo)
+static void HandleUDPMessageReceived(IPEndPointBasis * aEndPoint, PacketBufferHandle aBuffer, const IPPacketInfo * aPacketInfo)
 {
     const bool lCheckBuffer = true;
     bool lStatus;
 
     VerifyOrExit(aEndPoint != nullptr, lStatus = false);
-    VerifyOrExit(aBuffer != nullptr, lStatus = false);
+    VerifyOrExit(!aBuffer.IsNull(), lStatus = false);
     VerifyOrExit(aPacketInfo != nullptr, lStatus = false);
 
     Common::HandleUDPMessageReceived(aEndPoint, aBuffer, aPacketInfo);
@@ -740,11 +729,6 @@
     lStatus = HandleDataReceived(aBuffer, lCheckBuffer);
 
 exit:
-    if (aBuffer != nullptr)
-    {
-        PacketBuffer::Free(aBuffer);
-    }
-
     if (!lStatus)
     {
         SetStatusFailed(sTestState.mStatus);
@@ -819,8 +803,8 @@
 
 static INET_ERROR DriveSendForDestination(const IPAddress & aAddress, uint16_t aSize)
 {
-    PacketBuffer * lBuffer = nullptr;
-    INET_ERROR lStatus     = INET_NO_ERROR;
+    PacketBufferHandle lBuffer;
+    INET_ERROR lStatus = INET_NO_ERROR;
 
     if ((gOptFlags & (kOptFlagUseRawIP)) == (kOptFlagUseRawIP))
     {
@@ -832,17 +816,17 @@
         if ((gOptFlags & kOptFlagUseIPv6) == (kOptFlagUseIPv6))
         {
             lBuffer = Common::MakeICMPv6DataBuffer(aSize);
-            VerifyOrExit(lBuffer != nullptr, lStatus = INET_ERROR_NO_MEMORY);
+            VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
         }
 #if INET_CONFIG_ENABLE_IPV4
         else if ((gOptFlags & kOptFlagUseIPv4) == (kOptFlagUseIPv4))
         {
             lBuffer = Common::MakeICMPv4DataBuffer(aSize);
-            VerifyOrExit(lBuffer != nullptr, lStatus = INET_ERROR_NO_MEMORY);
+            VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
         }
 #endif // INET_CONFIG_ENABLE_IPV4
 
-        lStatus = sRawIPEndPoint->SendTo(aAddress, lBuffer);
+        lStatus = sRawIPEndPoint->SendTo(aAddress, lBuffer.Release_ForNow());
         SuccessOrExit(lStatus);
     }
     else
@@ -855,9 +839,9 @@
             // patterned from zero to aSize - 1.
 
             lBuffer = Common::MakeDataBuffer(aSize, lFirstValue);
-            VerifyOrExit(lBuffer != nullptr, lStatus = INET_ERROR_NO_MEMORY);
+            VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
 
-            lStatus = sUDPIPEndPoint->SendTo(aAddress, kUDPPort, lBuffer);
+            lStatus = sUDPIPEndPoint->SendTo(aAddress, kUDPPort, lBuffer.Release_ForNow());
             SuccessOrExit(lStatus);
         }
         else if ((gOptFlags & kOptFlagUseTCPIP) == kOptFlagUseTCPIP)
@@ -871,9 +855,9 @@
             // sTestState.mStats.mTransmit.mExpected - 1.
 
             lBuffer = Common::MakeDataBuffer(aSize, uint8_t(lFirstValue));
-            VerifyOrExit(lBuffer != nullptr, lStatus = INET_ERROR_NO_MEMORY);
+            VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
 
-            lStatus = sTCPIPEndPoint->Send(lBuffer);
+            lStatus = sTCPIPEndPoint->Send(lBuffer.Release_ForNow());
             SuccessOrExit(lStatus);
         }
     }
diff --git a/src/inet/tests/TestInetLayerCommon.cpp b/src/inet/tests/TestInetLayerCommon.cpp
index 8d485f4..076dc7d 100644
--- a/src/inet/tests/TestInetLayerCommon.cpp
+++ b/src/inet/tests/TestInetLayerCommon.cpp
@@ -162,7 +162,7 @@
     return (lStatus);
 }
 
-static PacketBuffer * MakeDataBuffer(uint16_t aDesiredLength, uint16_t aPatternStartOffset, uint8_t aFirstValue)
+static PacketBufferHandle MakeDataBuffer(uint16_t aDesiredLength, uint16_t aPatternStartOffset, uint8_t aFirstValue)
 {
     PacketBufferHandle lBuffer;
 
@@ -178,34 +178,32 @@
     lBuffer->SetDataLength(aDesiredLength);
 
 exit:
-    return lBuffer.Release_ForNow();
+    return lBuffer;
 }
 
-static PacketBuffer * MakeDataBuffer(uint16_t aDesiredLength, uint16_t aPatternStartOffset)
+static PacketBufferHandle MakeDataBuffer(uint16_t aDesiredLength, uint16_t aPatternStartOffset)
 {
-    const uint8_t lFirstValue = 0;
-    PacketBuffer * lBuffer    = nullptr;
-
-    lBuffer = MakeDataBuffer(aDesiredLength, aPatternStartOffset, lFirstValue);
-    VerifyOrExit(lBuffer != nullptr, );
+    constexpr uint8_t lFirstValue = 0;
+    PacketBufferHandle lBuffer    = MakeDataBuffer(aDesiredLength, aPatternStartOffset, lFirstValue);
+    VerifyOrExit(!lBuffer.IsNull(), );
 
 exit:
     return (lBuffer);
 }
 
 template <typename tType>
-static PacketBuffer * MakeICMPDataBuffer(uint16_t aDesiredUserLength, uint16_t aHeaderLength, uint16_t aPatternStartOffset,
-                                         uint8_t aType)
+static PacketBufferHandle MakeICMPDataBuffer(uint16_t aDesiredUserLength, uint16_t aHeaderLength, uint16_t aPatternStartOffset,
+                                             uint8_t aType)
 {
     static uint16_t lSequenceNumber = 0;
-    PacketBuffer * lBuffer          = nullptr;
+    PacketBufferHandle lBuffer;
 
     // To ensure there is enough room for the user data and the ICMP
     // header, include both the user data size and the ICMP header length.
 
     lBuffer = MakeDataBuffer(aDesiredUserLength + aHeaderLength, aPatternStartOffset);
 
-    if (lBuffer != nullptr)
+    if (!lBuffer.IsNull())
     {
         tType * lHeader = reinterpret_cast<tType *>(lBuffer->Start());
 
@@ -219,51 +217,37 @@
     return (lBuffer);
 }
 
-PacketBuffer * MakeICMPv4DataBuffer(uint16_t aDesiredUserLength)
+PacketBufferHandle MakeICMPv4DataBuffer(uint16_t aDesiredUserLength)
 {
-    const uint16_t lICMPHeaderLength   = sizeof(ICMPv4EchoHeader);
-    const uint16_t lPatternStartOffset = lICMPHeaderLength;
-    const uint8_t lType                = gICMPv4Types[kICMP_EchoRequestIndex];
-    PacketBuffer * lBuffer             = nullptr;
+    constexpr uint16_t lICMPHeaderLength   = sizeof(ICMPv4EchoHeader);
+    constexpr uint16_t lPatternStartOffset = lICMPHeaderLength;
+    const uint8_t lType                    = gICMPv4Types[kICMP_EchoRequestIndex];
 
-    lBuffer = MakeICMPDataBuffer<ICMPv4EchoHeader>(aDesiredUserLength, lICMPHeaderLength, lPatternStartOffset, lType);
-
-    return (lBuffer);
+    return MakeICMPDataBuffer<ICMPv4EchoHeader>(aDesiredUserLength, lICMPHeaderLength, lPatternStartOffset, lType);
 }
 
-PacketBuffer * MakeICMPv6DataBuffer(uint16_t aDesiredUserLength)
+PacketBufferHandle MakeICMPv6DataBuffer(uint16_t aDesiredUserLength)
 {
-    const uint16_t lICMPHeaderLength   = sizeof(ICMPv6EchoHeader);
-    const uint16_t lPatternStartOffset = lICMPHeaderLength;
-    const uint8_t lType                = gICMPv6Types[kICMP_EchoRequestIndex];
-    PacketBuffer * lBuffer             = nullptr;
+    constexpr uint16_t lICMPHeaderLength   = sizeof(ICMPv6EchoHeader);
+    constexpr uint16_t lPatternStartOffset = lICMPHeaderLength;
+    const uint8_t lType                    = gICMPv6Types[kICMP_EchoRequestIndex];
 
-    lBuffer = MakeICMPDataBuffer<ICMPv6EchoHeader>(aDesiredUserLength, lICMPHeaderLength, lPatternStartOffset, lType);
-
-    return (lBuffer);
+    return MakeICMPDataBuffer<ICMPv6EchoHeader>(aDesiredUserLength, lICMPHeaderLength, lPatternStartOffset, lType);
 }
 
-PacketBuffer * MakeDataBuffer(uint16_t aDesiredLength, uint8_t aFirstValue)
+PacketBufferHandle MakeDataBuffer(uint16_t aDesiredLength, uint8_t aFirstValue)
 {
-    const uint16_t lPatternStartOffset = 0;
-    PacketBuffer * lBuffer             = nullptr;
-
-    lBuffer = MakeDataBuffer(aDesiredLength, lPatternStartOffset, aFirstValue);
-
-    return (lBuffer);
+    constexpr uint16_t lPatternStartOffset = 0;
+    return MakeDataBuffer(aDesiredLength, lPatternStartOffset, aFirstValue);
 }
 
-PacketBuffer * MakeDataBuffer(uint16_t aDesiredLength)
+PacketBufferHandle MakeDataBuffer(uint16_t aDesiredLength)
 {
-    const uint16_t lPatternStartOffset = 0;
-    PacketBuffer * lBuffer             = nullptr;
-
-    lBuffer = MakeDataBuffer(aDesiredLength, lPatternStartOffset);
-
-    return (lBuffer);
+    constexpr uint16_t lPatternStartOffset = 0;
+    return MakeDataBuffer(aDesiredLength, lPatternStartOffset);
 }
 
-static bool HandleDataReceived(const PacketBuffer * aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer,
+static bool HandleDataReceived(const PacketBufferHandle & aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer,
                                uint16_t aPatternStartOffset, uint8_t aFirstValue)
 {
     bool lStatus              = true;
@@ -272,7 +256,7 @@
     // Walk through each buffer in the packet chain, checking the
     // buffer for the expected pattern, if requested.
 
-    for (const PacketBuffer * lBuffer = aBuffer; lBuffer != nullptr; lBuffer = lBuffer->Next())
+    for (const PacketBuffer * lBuffer = aBuffer.Get_ForNow(); lBuffer != nullptr; lBuffer = lBuffer->Next())
     {
         const uint16_t lDataLength = lBuffer->DataLength();
 
@@ -297,7 +281,7 @@
     return (lStatus);
 }
 
-static bool HandleICMPDataReceived(PacketBuffer * aBuffer, uint16_t aHeaderLength, TransferStats & aStats, bool aStatsByPacket,
+static bool HandleICMPDataReceived(PacketBufferHandle aBuffer, uint16_t aHeaderLength, TransferStats & aStats, bool aStatsByPacket,
                                    bool aCheckBuffer)
 {
     const uint16_t lPatternStartOffset = 0;
@@ -310,27 +294,27 @@
     return (lStatus);
 }
 
-bool HandleICMPv4DataReceived(PacketBuffer * aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer)
+bool HandleICMPv4DataReceived(PacketBufferHandle aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer)
 {
     const uint16_t lICMPHeaderLength = sizeof(ICMPv4EchoHeader);
     bool lStatus;
 
-    lStatus = HandleICMPDataReceived(aBuffer, lICMPHeaderLength, aStats, aStatsByPacket, aCheckBuffer);
+    lStatus = HandleICMPDataReceived(std::move(aBuffer), lICMPHeaderLength, aStats, aStatsByPacket, aCheckBuffer);
 
     return (lStatus);
 }
 
-bool HandleICMPv6DataReceived(PacketBuffer * aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer)
+bool HandleICMPv6DataReceived(PacketBufferHandle aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer)
 {
     const uint16_t lICMPHeaderLength = sizeof(ICMPv6EchoHeader);
     bool lStatus;
 
-    lStatus = HandleICMPDataReceived(aBuffer, lICMPHeaderLength, aStats, aStatsByPacket, aCheckBuffer);
+    lStatus = HandleICMPDataReceived(std::move(aBuffer), lICMPHeaderLength, aStats, aStatsByPacket, aCheckBuffer);
 
     return (lStatus);
 }
 
-bool HandleDataReceived(const PacketBuffer * aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer,
+bool HandleDataReceived(const PacketBufferHandle & aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer,
                         uint8_t aFirstValue)
 {
     const uint16_t lPatternStartOffset = 0;
@@ -341,7 +325,7 @@
     return (lStatus);
 }
 
-bool HandleDataReceived(const PacketBuffer * aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer)
+bool HandleDataReceived(const PacketBufferHandle & aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer)
 {
     const uint8_t lFirstValue          = 0;
     const uint16_t lPatternStartOffset = 0;
@@ -352,7 +336,7 @@
     return (lStatus);
 }
 
-bool HandleUDPDataReceived(const PacketBuffer * aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer)
+bool HandleUDPDataReceived(const PacketBufferHandle & aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer)
 {
     bool lStatus;
 
@@ -361,7 +345,7 @@
     return (lStatus);
 }
 
-bool HandleTCPDataReceived(const PacketBuffer * aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer)
+bool HandleTCPDataReceived(const PacketBufferHandle & aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer)
 {
     bool lStatus;
 
@@ -383,7 +367,8 @@
 
 // Raw Endpoint Callback Handlers
 
-void HandleRawMessageReceived(const IPEndPointBasis * aEndPoint, const PacketBuffer * aBuffer, const IPPacketInfo * aPacketInfo)
+void HandleRawMessageReceived(const IPEndPointBasis * aEndPoint, const PacketBufferHandle & aBuffer,
+                              const IPPacketInfo * aPacketInfo)
 {
     char lSourceAddressBuffer[INET6_ADDRSTRLEN];
     char lDestinationAddressBuffer[INET6_ADDRSTRLEN];
@@ -413,7 +398,8 @@
 
 // UDP Endpoint Callback Handlers
 
-void HandleUDPMessageReceived(const IPEndPointBasis * aEndPoint, const PacketBuffer * aBuffer, const IPPacketInfo * aPacketInfo)
+void HandleUDPMessageReceived(const IPEndPointBasis * aEndPoint, const PacketBufferHandle & aBuffer,
+                              const IPPacketInfo * aPacketInfo)
 {
     char lSourceAddressBuffer[INET6_ADDRSTRLEN];
     char lDestinationAddressBuffer[INET6_ADDRSTRLEN];
diff --git a/src/inet/tests/TestInetLayerCommon.hpp b/src/inet/tests/TestInetLayerCommon.hpp
index ff8a75c..6a2f7b2 100644
--- a/src/inet/tests/TestInetLayerCommon.hpp
+++ b/src/inet/tests/TestInetLayerCommon.hpp
@@ -131,18 +131,18 @@
 extern bool IsTesting(const TestStatus & aTestStatus);
 extern bool WasSuccessful(const TestStatus & aTestStatus);
 
-extern System::PacketBuffer * MakeDataBuffer(uint16_t aDesiredLength, uint8_t aFirstValue);
-extern System::PacketBuffer * MakeDataBuffer(uint16_t aDesiredLength);
-extern System::PacketBuffer * MakeICMPv4DataBuffer(uint16_t aDesiredUserLength);
-extern System::PacketBuffer * MakeICMPv6DataBuffer(uint16_t aDesiredUserLength);
+extern System::PacketBufferHandle MakeDataBuffer(uint16_t aDesiredLength, uint8_t aFirstValue);
+extern System::PacketBufferHandle MakeDataBuffer(uint16_t aDesiredLength);
+extern System::PacketBufferHandle MakeICMPv4DataBuffer(uint16_t aDesiredUserLength);
+extern System::PacketBufferHandle MakeICMPv6DataBuffer(uint16_t aDesiredUserLength);
 
-extern bool HandleDataReceived(const System::PacketBuffer * aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer,
-                               uint8_t aFirstValue);
-extern bool HandleDataReceived(const System::PacketBuffer * aBuffer, TransferStats & aStats, bool aStatsByPacket,
+extern bool HandleDataReceived(const System::PacketBufferHandle & aBuffer, TransferStats & aStats, bool aStatsByPacket,
+                               bool aCheckBuffer, uint8_t aFirstValue);
+extern bool HandleDataReceived(const System::PacketBufferHandle & aBuffer, TransferStats & aStats, bool aStatsByPacket,
                                bool aCheckBuffer);
-extern bool HandleICMPv4DataReceived(System::PacketBuffer * aBuffer, TransferStats & aStats, bool aStatsByPacket,
+extern bool HandleICMPv4DataReceived(System::PacketBufferHandle aBuffer, TransferStats & aStats, bool aStatsByPacket,
                                      bool aCheckBuffer);
-extern bool HandleICMPv6DataReceived(System::PacketBuffer * aBuffer, TransferStats & aStats, bool aStatsByPacket,
+extern bool HandleICMPv6DataReceived(System::PacketBufferHandle aBuffer, TransferStats & aStats, bool aStatsByPacket,
                                      bool aCheckBuffer);
 
 // Timer Callback Handler
@@ -151,14 +151,14 @@
 
 // Raw Endpoint Callback Handlers
 
-extern void HandleRawMessageReceived(const Inet::IPEndPointBasis * aEndPoint, const System::PacketBuffer * aBuffer,
+extern void HandleRawMessageReceived(const Inet::IPEndPointBasis * aEndPoint, const System::PacketBufferHandle & aBuffer,
                                      const Inet::IPPacketInfo * aPacketInfo);
 extern void HandleRawReceiveError(const Inet::IPEndPointBasis * aEndPoint, const INET_ERROR & aError,
                                   const Inet::IPPacketInfo * aPacketInfo);
 
 // UDP Endpoint Callback Handlers
 
-extern void HandleUDPMessageReceived(const Inet::IPEndPointBasis * aEndPoint, const System::PacketBuffer * aBuffer,
+extern void HandleUDPMessageReceived(const Inet::IPEndPointBasis * aEndPoint, const System::PacketBufferHandle & aBuffer,
                                      const Inet::IPPacketInfo * aPacketInfo);
 extern void HandleUDPReceiveError(const Inet::IPEndPointBasis * aEndPoint, const INET_ERROR & aError,
                                   const Inet::IPPacketInfo * aPacketInfo);
diff --git a/src/inet/tests/TestInetLayerMulticast.cpp b/src/inet/tests/TestInetLayerMulticast.cpp
index 7dd76b8..4b36023 100644
--- a/src/inet/tests/TestInetLayerMulticast.cpp
+++ b/src/inet/tests/TestInetLayerMulticast.cpp
@@ -597,7 +597,7 @@
            aGroupAddress.mStats.mReceive.mExpected, aGroupAddress.mGroup);
 }
 
-static bool HandleDataReceived(const PacketBuffer * aBuffer, GroupAddress & aGroupAddress, bool aCheckBuffer)
+static bool HandleDataReceived(const PacketBufferHandle & aBuffer, GroupAddress & aGroupAddress, bool aCheckBuffer)
 {
     const bool lStatsByPacket = true;
     bool lStatus              = true;
@@ -611,7 +611,7 @@
     return (lStatus);
 }
 
-static bool HandleDataReceived(const PacketBuffer * aBuffer, const IPPacketInfo & aPacketInfo, bool aCheckBuffer)
+static bool HandleDataReceived(const PacketBufferHandle & aBuffer, const IPPacketInfo & aPacketInfo, bool aCheckBuffer)
 {
     bool lStatus = true;
     GroupAddress * lGroupAddress;
@@ -630,7 +630,7 @@
 
 // Raw Endpoint Callbacks
 
-static void HandleRawMessageReceived(IPEndPointBasis * aEndPoint, PacketBuffer * aBuffer, const IPPacketInfo * aPacketInfo)
+static void HandleRawMessageReceived(IPEndPointBasis * aEndPoint, PacketBufferHandle aBuffer, const IPPacketInfo * aPacketInfo)
 {
     const bool lCheckBuffer   = true;
     const bool lStatsByPacket = true;
@@ -639,7 +639,7 @@
     GroupAddress * lGroupAddress;
 
     VerifyOrExit(aEndPoint != nullptr, lStatus = false);
-    VerifyOrExit(aBuffer != nullptr, lStatus = false);
+    VerifyOrExit(!aBuffer.IsNull(), lStatus = false);
     VerifyOrExit(aPacketInfo != nullptr, lStatus = false);
 
     Common::HandleRawMessageReceived(aEndPoint, aBuffer, aPacketInfo);
@@ -656,11 +656,11 @@
 
             aBuffer->ConsumeHead(kIPv4HeaderSize);
 
-            lStatus = Common::HandleICMPv4DataReceived(aBuffer, lGroupAddress->mStats, lStatsByPacket, lCheckBuffer);
+            lStatus = Common::HandleICMPv4DataReceived(std::move(aBuffer), lGroupAddress->mStats, lStatsByPacket, lCheckBuffer);
         }
         else if (lAddressType == kIPAddressType_IPv6)
         {
-            lStatus = Common::HandleICMPv6DataReceived(aBuffer, lGroupAddress->mStats, lStatsByPacket, lCheckBuffer);
+            lStatus = Common::HandleICMPv6DataReceived(std::move(aBuffer), lGroupAddress->mStats, lStatsByPacket, lCheckBuffer);
         }
         else
         {
@@ -674,11 +674,6 @@
     }
 
 exit:
-    if (aBuffer != nullptr)
-    {
-        PacketBuffer::Free(aBuffer);
-    }
-
     if (!lStatus)
     {
         SetStatusFailed(sTestState.mStatus);
@@ -694,25 +689,20 @@
 
 // UDP Endpoint Callbacks
 
-static void HandleUDPMessageReceived(IPEndPointBasis * aEndPoint, PacketBuffer * aBuffer, const IPPacketInfo * aPacketInfo)
+static void HandleUDPMessageReceived(IPEndPointBasis * aEndPoint, PacketBufferHandle aBuffer, const IPPacketInfo * aPacketInfo)
 {
     const bool lCheckBuffer = true;
     bool lStatus;
 
     VerifyOrExit(aEndPoint != nullptr, lStatus = false);
-    VerifyOrExit(aBuffer != nullptr, lStatus = false);
+    VerifyOrExit(!aBuffer.IsNull(), lStatus = false);
     VerifyOrExit(aPacketInfo != nullptr, lStatus = false);
 
     Common::HandleUDPMessageReceived(aEndPoint, aBuffer, aPacketInfo);
 
-    lStatus = HandleDataReceived(aBuffer, *aPacketInfo, lCheckBuffer);
+    lStatus = HandleDataReceived(std::move(aBuffer), *aPacketInfo, lCheckBuffer);
 
 exit:
-    if (aBuffer != nullptr)
-    {
-        PacketBuffer::Free(aBuffer);
-    }
-
     if (!lStatus)
     {
         SetStatusFailed(sTestState.mStatus);
@@ -751,8 +741,8 @@
 
 static INET_ERROR DriveSendForDestination(const IPAddress & aAddress, uint16_t aSize)
 {
-    PacketBuffer * lBuffer = nullptr;
-    INET_ERROR lStatus     = INET_NO_ERROR;
+    PacketBufferHandle lBuffer;
+    INET_ERROR lStatus = INET_NO_ERROR;
 
     if ((gOptFlags & (kOptFlagUseRawIP)) == (kOptFlagUseRawIP))
     {
@@ -764,17 +754,17 @@
         if ((gOptFlags & kOptFlagUseIPv6) == (kOptFlagUseIPv6))
         {
             lBuffer = Common::MakeICMPv6DataBuffer(aSize);
-            VerifyOrExit(lBuffer != nullptr, lStatus = INET_ERROR_NO_MEMORY);
+            VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
         }
 #if INET_CONFIG_ENABLE_IPV4
         else if ((gOptFlags & kOptFlagUseIPv4) == (kOptFlagUseIPv4))
         {
             lBuffer = Common::MakeICMPv4DataBuffer(aSize);
-            VerifyOrExit(lBuffer != nullptr, lStatus = INET_ERROR_NO_MEMORY);
+            VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
         }
 #endif // INET_CONFIG_ENABLE_IPV4
 
-        lStatus = sRawIPEndPoint->SendTo(aAddress, lBuffer);
+        lStatus = sRawIPEndPoint->SendTo(aAddress, lBuffer.Release_ForNow());
         SuccessOrExit(lStatus);
     }
     else
@@ -787,9 +777,9 @@
             // patterned from zero to aSize - 1.
 
             lBuffer = Common::MakeDataBuffer(aSize, lFirstValue);
-            VerifyOrExit(lBuffer != nullptr, lStatus = INET_ERROR_NO_MEMORY);
+            VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
 
-            lStatus = sUDPIPEndPoint->SendTo(aAddress, kUDPPort, lBuffer);
+            lStatus = sUDPIPEndPoint->SendTo(aAddress, kUDPPort, lBuffer.Release_ForNow());
             SuccessOrExit(lStatus);
         }
     }
diff --git a/src/messaging/ExchangeContext.cpp b/src/messaging/ExchangeContext.cpp
index 2da53ef..c686747 100644
--- a/src/messaging/ExchangeContext.cpp
+++ b/src/messaging/ExchangeContext.cpp
@@ -47,12 +47,10 @@
 namespace chip {
 
 static void DefaultOnMessageReceived(ExchangeContext * ec, const PacketHeader & packetHeader, uint32_t protocolId, uint8_t msgType,
-                                     PacketBuffer * payload)
+                                     PacketBufferHandle payload)
 {
     ChipLogError(ExchangeManager, "Dropping unexpected message %08" PRIX32 ":%d %04" PRIX16 " MsgId:%08" PRIX32, protocolId,
                  msgType, ec->GetExchangeId(), packetHeader.GetMessageId());
-
-    PacketBuffer::Free(payload);
 }
 
 bool ExchangeContext::IsInitiator() const
@@ -295,7 +293,7 @@
 }
 
 CHIP_ERROR ExchangeContext::HandleMessage(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
-                                          PacketBuffer * msgBuf)
+                                          PacketBufferHandle msgBuf)
 {
     CHIP_ERROR err      = CHIP_NO_ERROR;
     uint16_t protocolId = 0;
@@ -319,12 +317,11 @@
 
     if (mDelegate != nullptr)
     {
-        mDelegate->OnMessageReceived(this, packetHeader, protocolId, messageType, msgBuf);
-        msgBuf = nullptr;
+        mDelegate->OnMessageReceived(this, packetHeader, protocolId, messageType, std::move(msgBuf));
     }
     else
     {
-        DefaultOnMessageReceived(this, packetHeader, protocolId, messageType, msgBuf);
+        DefaultOnMessageReceived(this, packetHeader, protocolId, messageType, std::move(msgBuf));
     }
 
     // Release the reference to the ExchangeContext that was held at the beginning of this function.
@@ -332,11 +329,6 @@
     // already made a prior call to Close().
     Release();
 
-    if (msgBuf != nullptr)
-    {
-        PacketBuffer::Free(msgBuf);
-    }
-
     return err;
 }
 
diff --git a/src/messaging/ExchangeContext.h b/src/messaging/ExchangeContext.h
index e87c3cf..eedeff3 100644
--- a/src/messaging/ExchangeContext.h
+++ b/src/messaging/ExchangeContext.h
@@ -118,14 +118,15 @@
      *
      *  @param[in]    payloadHeader A reference to the PayloadHeader object.
      *
-     *  @param[in]    msgBuf        A pointer to the PacketBuffer object holding the CHIP message.
+     *  @param[in]    msgBuf        A handle to the PacketBuffer object holding the CHIP message.
      *
      *  @retval  #CHIP_ERROR_INVALID_ARGUMENT               if an invalid argument was passed to this HandleMessage API.
      *  @retval  #CHIP_ERROR_INCORRECT_STATE                if the state of the exchange context is incorrect.
      *  @retval  #CHIP_NO_ERROR                             if the CHIP layer successfully delivered the message up to the
      *                                                       protocol layer.
      */
-    CHIP_ERROR HandleMessage(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader, System::PacketBuffer * msgBuf);
+    CHIP_ERROR HandleMessage(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
+                             System::PacketBufferHandle msgBuf);
 
     ExchangeDelegate * GetDelegate() const { return mDelegate; }
     void SetDelegate(ExchangeDelegate * delegate) { mDelegate = delegate; }
diff --git a/src/messaging/ExchangeDelegate.h b/src/messaging/ExchangeDelegate.h
index eaa7d56..3cbf7f2 100644
--- a/src/messaging/ExchangeDelegate.h
+++ b/src/messaging/ExchangeDelegate.h
@@ -53,7 +53,7 @@
      *  @param[in]    payload       A pointer to the PacketBuffer object holding the message payload.
      */
     virtual void OnMessageReceived(ExchangeContext * ec, const PacketHeader & packetHeader, uint32_t protocolId, uint8_t msgType,
-                                   System::PacketBuffer * payload) = 0;
+                                   System::PacketBufferHandle payload) = 0;
 
     /**
      * @brief
diff --git a/src/messaging/ExchangeMgr.cpp b/src/messaging/ExchangeMgr.cpp
index 61d7c6a..397ac77 100644
--- a/src/messaging/ExchangeMgr.cpp
+++ b/src/messaging/ExchangeMgr.cpp
@@ -157,7 +157,8 @@
     return nullptr;
 }
 
-void ExchangeManager::DispatchMessage(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader, PacketBuffer * msgBuf)
+void ExchangeManager::DispatchMessage(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
+                                      System::PacketBufferHandle msgBuf)
 {
     UnsolicitedMessageHandler * umh         = nullptr;
     UnsolicitedMessageHandler * matchingUMH = nullptr;
@@ -169,9 +170,7 @@
         if (ec.GetReferenceCount() > 0 && ec.MatchExchange(packetHeader, payloadHeader))
         {
             // Matched ExchangeContext; send to message handler.
-            ec.HandleMessage(packetHeader, payloadHeader, msgBuf);
-
-            msgBuf = nullptr;
+            ec.HandleMessage(packetHeader, payloadHeader, std::move(msgBuf));
 
             ExitNow(err = CHIP_NO_ERROR);
         }
@@ -219,8 +218,7 @@
         ChipLogProgress(ExchangeManager, "ec pos: %d, id: %d, Delegate: 0x%x", ec - ContextPool.begin(), ec->GetExchangeId(),
                         ec->GetDelegate());
 
-        ec->HandleMessage(packetHeader, payloadHeader, msgBuf);
-        msgBuf = nullptr;
+        ec->HandleMessage(packetHeader, payloadHeader, std::move(msgBuf));
     }
 
 exit:
@@ -228,11 +226,6 @@
     {
         ChipLogError(ExchangeManager, "DispatchMessage failed, err = %d", err);
     }
-
-    if (msgBuf != nullptr)
-    {
-        PacketBuffer::Free(msgBuf);
-    }
 }
 
 CHIP_ERROR ExchangeManager::RegisterUMH(uint32_t protocolId, int16_t msgType, ExchangeDelegate * delegate)
@@ -284,10 +277,10 @@
 }
 
 void ExchangeManager::OnMessageReceived(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
-                                        const Transport::PeerConnectionState * state, System::PacketBuffer * msgBuf,
+                                        const Transport::PeerConnectionState * state, System::PacketBufferHandle msgBuf,
                                         SecureSessionMgr * msgLayer)
 {
-    DispatchMessage(packetHeader, payloadHeader, msgBuf);
+    DispatchMessage(packetHeader, payloadHeader, std::move(msgBuf));
 }
 
 void ExchangeManager::OnConnectionExpired(const Transport::PeerConnectionState * state, SecureSessionMgr * mgr)
diff --git a/src/messaging/ExchangeMgr.h b/src/messaging/ExchangeMgr.h
index 49772ef..feb1697 100644
--- a/src/messaging/ExchangeMgr.h
+++ b/src/messaging/ExchangeMgr.h
@@ -192,7 +192,7 @@
 
     ExchangeContext * AllocContext(uint16_t ExchangeId, uint64_t PeerNodeId, bool Initiator, ExchangeDelegate * delegate);
 
-    void DispatchMessage(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader, System::PacketBuffer * msgBuf);
+    void DispatchMessage(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader, System::PacketBufferHandle msgBuf);
 
     CHIP_ERROR RegisterUMH(uint32_t protocolId, int16_t msgType, ExchangeDelegate * delegate);
     CHIP_ERROR UnregisterUMH(uint32_t protocolId, int16_t msgType);
@@ -200,7 +200,7 @@
     void OnReceiveError(CHIP_ERROR error, const Transport::PeerAddress & source, SecureSessionMgr * msgLayer) override;
 
     void OnMessageReceived(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
-                           const Transport::PeerConnectionState * state, System::PacketBuffer * msgBuf,
+                           const Transport::PeerConnectionState * state, System::PacketBufferHandle msgBuf,
                            SecureSessionMgr * msgLayer) override;
 
     void OnConnectionExpired(const Transport::PeerConnectionState * state, SecureSessionMgr * mgr) override;
diff --git a/src/messaging/tests/TestExchangeMgr.cpp b/src/messaging/tests/TestExchangeMgr.cpp
index c6733a3..e6e1924 100644
--- a/src/messaging/tests/TestExchangeMgr.cpp
+++ b/src/messaging/tests/TestExchangeMgr.cpp
@@ -59,7 +59,9 @@
     CHIP_ERROR SendMessage(const PacketHeader & header, Header::Flags payloadFlags, const PeerAddress & address,
                            System::PacketBuffer * msgBuf) override
     {
-        HandleMessageReceived(header, address, msgBuf);
+        System::PacketBufferHandle msg_ForNow;
+        msg_ForNow.Adopt(msgBuf);
+        HandleMessageReceived(header, address, std::move(msg_ForNow));
         return CHIP_NO_ERROR;
     }
 
@@ -70,7 +72,7 @@
 {
 public:
     void OnMessageReceived(ExchangeContext * ec, const PacketHeader & packetHeader, uint32_t protocolId, uint8_t msgType,
-                           System::PacketBuffer * buffer) override
+                           System::PacketBufferHandle buffer) override
     {
         IsOnMessageReceivedCalled = true;
     }
diff --git a/src/platform/EFR32/BLEManagerImpl.cpp b/src/platform/EFR32/BLEManagerImpl.cpp
index f285b4c..dc9a32e 100644
--- a/src/platform/EFR32/BLEManagerImpl.cpp
+++ b/src/platform/EFR32/BLEManagerImpl.cpp
@@ -376,8 +376,12 @@
 
     case DeviceEventType::kCHIPoBLEWriteReceived: {
         ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEWriteReceived");
-        HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_RX,
-                            event->CHIPoBLEWriteReceived.Data);
+        {
+            System::PacketBufferHandle data_ForNow;
+            data_ForNow.Adopt(event->CHIPoBLEWriteReceived.Data);
+            HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_RX,
+                                std::move(data_ForNow));
+        }
     }
     break;
 
diff --git a/src/platform/ESP32/bluedroid/BLEManagerImpl.cpp b/src/platform/ESP32/bluedroid/BLEManagerImpl.cpp
index 93ed746..0512af9 100644
--- a/src/platform/ESP32/bluedroid/BLEManagerImpl.cpp
+++ b/src/platform/ESP32/bluedroid/BLEManagerImpl.cpp
@@ -248,10 +248,13 @@
         HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
         break;
 
-    case DeviceEventType::kCHIPoBLEWriteReceived:
+    case DeviceEventType::kCHIPoBLEWriteReceived: {
+        System::PacketBufferHandle data_ForNow;
+        data_ForNow.Adopt(event->CHIPoBLEWriteReceived.Data);
         HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_RX,
-                            event->CHIPoBLEWriteReceived.Data);
-        break;
+                            std::move(data_ForNow));
+    }
+    break;
 
     case DeviceEventType::kCHIPoBLEIndicateConfirm:
         HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
diff --git a/src/platform/ESP32/nimble/BLEManagerImpl.cpp b/src/platform/ESP32/nimble/BLEManagerImpl.cpp
index bb45c74..3c8ca5d 100644
--- a/src/platform/ESP32/nimble/BLEManagerImpl.cpp
+++ b/src/platform/ESP32/nimble/BLEManagerImpl.cpp
@@ -241,10 +241,13 @@
         HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX);
         break;
 
-    case DeviceEventType::kCHIPoBLEWriteReceived:
+    case DeviceEventType::kCHIPoBLEWriteReceived: {
+        System::PacketBufferHandle data_ForNow;
+        data_ForNow.Adopt(event->CHIPoBLEWriteReceived.Data);
         HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_RX,
-                            event->CHIPoBLEWriteReceived.Data);
-        break;
+                            std::move(data_ForNow));
+    }
+    break;
 
     case DeviceEventType::kCHIPoBLEIndicateConfirm:
         HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX);
diff --git a/src/platform/Linux/BLEManagerImpl.cpp b/src/platform/Linux/BLEManagerImpl.cpp
index f33d658..4cf4160 100644
--- a/src/platform/Linux/BLEManagerImpl.cpp
+++ b/src/platform/Linux/BLEManagerImpl.cpp
@@ -214,10 +214,13 @@
         HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
         break;
 
-    case DeviceEventType::kCHIPoBLEWriteReceived:
+    case DeviceEventType::kCHIPoBLEWriteReceived: {
+        System::PacketBufferHandle data_ForNow;
+        data_ForNow.Adopt(event->CHIPoBLEWriteReceived.Data);
         HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_RX,
-                            event->CHIPoBLEWriteReceived.Data);
-        break;
+                            std::move(data_ForNow));
+    }
+    break;
 
     case DeviceEventType::kCHIPoBLEIndicateConfirm:
         HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
diff --git a/src/platform/Zephyr/GenericBLEManagerImpl_Zephyr.cpp b/src/platform/Zephyr/GenericBLEManagerImpl_Zephyr.cpp
index 9ea5d12..df7514c 100644
--- a/src/platform/Zephyr/GenericBLEManagerImpl_Zephyr.cpp
+++ b/src/platform/Zephyr/GenericBLEManagerImpl_Zephyr.cpp
@@ -480,7 +480,9 @@
     ChipLogDetail(DeviceLayer, "Write request received for CHIPoBLE RX characteristic (ConnId 0x%02" PRIx16 ")",
                   bt_conn_index(c1WriteEvent->BtConn));
 
-    HandleWriteReceived(c1WriteEvent->BtConn, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_RX, c1WriteEvent->Data);
+    PacketBufferHandle data_ForNow;
+    data_ForNow.Adopt(c1WriteEvent->Data);
+    HandleWriteReceived(c1WriteEvent->BtConn, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_RX, std::move(data_ForNow));
     bt_conn_unref(c1WriteEvent->BtConn);
 
     return CHIP_NO_ERROR;
diff --git a/src/protocols/echo/Echo.h b/src/protocols/echo/Echo.h
index 3a9f7de..d6dea65 100644
--- a/src/protocols/echo/Echo.h
+++ b/src/protocols/echo/Echo.h
@@ -42,7 +42,7 @@
     kEchoMessageType_EchoResponse = 2
 };
 
-typedef void (*EchoFunct)(NodeId nodeId, System::PacketBuffer * payload);
+typedef void (*EchoFunct)(NodeId nodeId, System::PacketBufferHandle payload);
 
 class DLL_EXPORT EchoClient : public ExchangeDelegate
 {
@@ -87,16 +87,16 @@
      *         Other CHIP_ERROR codes as returned by the lower layers.
      *
      */
-    CHIP_ERROR SendEchoRequest(NodeId nodeId, System::PacketBuffer * payload);
+    CHIP_ERROR SendEchoRequest(NodeId nodeId, System::PacketBufferHandle payload);
 
 private:
     ExchangeManager * mExchangeMgr   = nullptr;
     ExchangeContext * mExchangeCtx   = nullptr;
     EchoFunct OnEchoResponseReceived = nullptr;
 
-    CHIP_ERROR SendEchoRequest(System::PacketBuffer * payload);
+    CHIP_ERROR SendEchoRequest(System::PacketBufferHandle payload);
     void OnMessageReceived(ExchangeContext * ec, const PacketHeader & packetHeader, uint32_t protocolId, uint8_t msgType,
-                           System::PacketBuffer * payload) override;
+                           System::PacketBufferHandle payload) override;
     void OnResponseTimeout(ExchangeContext * ec) override;
 };
 
@@ -138,7 +138,7 @@
     EchoFunct OnEchoRequestReceived = nullptr;
 
     void OnMessageReceived(ExchangeContext * ec, const PacketHeader & packetHeader, uint32_t protocolId, uint8_t msgType,
-                           System::PacketBuffer * payload) override;
+                           System::PacketBufferHandle payload) override;
     void OnResponseTimeout(ExchangeContext * ec) override {}
 };
 
diff --git a/src/protocols/echo/EchoClient.cpp b/src/protocols/echo/EchoClient.cpp
index bf12147..e6e7170 100644
--- a/src/protocols/echo/EchoClient.cpp
+++ b/src/protocols/echo/EchoClient.cpp
@@ -50,7 +50,7 @@
     }
 }
 
-CHIP_ERROR EchoClient::SendEchoRequest(NodeId nodeId, System::PacketBuffer * payload)
+CHIP_ERROR EchoClient::SendEchoRequest(NodeId nodeId, System::PacketBufferHandle payload)
 {
     // Discard any existing exchange context. Effectively we can only have one Echo exchange with
     // a single node at any one time.
@@ -64,19 +64,18 @@
     mExchangeCtx = mExchangeMgr->NewContext(nodeId, this);
     if (mExchangeCtx == nullptr)
     {
-        System::PacketBuffer::Free(payload);
         return CHIP_ERROR_NO_MEMORY;
     }
 
-    return SendEchoRequest(payload);
+    return SendEchoRequest(std::move(payload));
 }
 
-CHIP_ERROR EchoClient::SendEchoRequest(System::PacketBuffer * payload)
+CHIP_ERROR EchoClient::SendEchoRequest(System::PacketBufferHandle payload)
 {
     CHIP_ERROR err = CHIP_NO_ERROR;
 
     // Send an Echo Request message.  Discard the exchange context if the send fails.
-    err = mExchangeCtx->SendMessage(kProtocol_Echo, kEchoMessageType_EchoRequest, payload);
+    err = mExchangeCtx->SendMessage(kProtocol_Echo, kEchoMessageType_EchoRequest, payload.Release_ForNow());
 
     if (err != CHIP_NO_ERROR)
     {
@@ -88,7 +87,7 @@
 }
 
 void EchoClient::OnMessageReceived(ExchangeContext * ec, const PacketHeader & packetHeader, uint32_t protocolId, uint8_t msgType,
-                                   System::PacketBuffer * payload)
+                                   System::PacketBufferHandle payload)
 {
     // Assert that the exchange context matches the client's current context.
     // This should never fail because even if SendEchoRequest is called
@@ -115,12 +114,10 @@
     // Call the registered OnEchoResponseReceived handler, if any.
     if (OnEchoResponseReceived != nullptr)
     {
-        OnEchoResponseReceived(packetHeader.GetSourceNodeId().ValueOr(0), payload);
+        OnEchoResponseReceived(packetHeader.GetSourceNodeId().ValueOr(0), std::move(payload));
     }
 
-exit:
-    // Free the payload buffer.
-    System::PacketBuffer::Free(payload);
+exit:;
 }
 
 void EchoClient::OnResponseTimeout(ExchangeContext * ec)
diff --git a/src/protocols/echo/EchoServer.cpp b/src/protocols/echo/EchoServer.cpp
index e556317..3e344fc 100644
--- a/src/protocols/echo/EchoServer.cpp
+++ b/src/protocols/echo/EchoServer.cpp
@@ -53,14 +53,14 @@
 }
 
 void EchoServer::OnMessageReceived(ExchangeContext * ec, const PacketHeader & packetHeader, uint32_t protocolId, uint8_t msgType,
-                                   System::PacketBuffer * payload)
+                                   System::PacketBufferHandle payload)
 {
     // NOTE: we already know this is an Echo Request message because we explicitly registered with the
     // Exchange Manager for unsolicited Echo Requests.
 
     // Call the registered OnEchoRequestReceived handler, if any.
     if (OnEchoRequestReceived != nullptr)
-        OnEchoRequestReceived(ec->GetPeerNodeId(), payload);
+        OnEchoRequestReceived(ec->GetPeerNodeId(), std::move(payload));
 
     // Since we are re-using the inbound EchoRequest buffer to send the EchoResponse, if necessary,
     // adjust the position of the payload within the buffer to ensure there is enough room for the
@@ -69,7 +69,7 @@
     payload->EnsureReservedSize(CHIP_SYSTEM_CONFIG_HEADER_RESERVE_SIZE);
 
     // Send an Echo Response back to the sender.
-    ec->SendMessage(kProtocol_Echo, kEchoMessageType_EchoResponse, payload);
+    ec->SendMessage(kProtocol_Echo, kEchoMessageType_EchoResponse, payload.Release_ForNow());
 
     // Discard the exchange context.
     ec->Close();
diff --git a/src/system/SystemPacketBuffer.h b/src/system/SystemPacketBuffer.h
index 1646253..89e390b 100644
--- a/src/system/SystemPacketBuffer.h
+++ b/src/system/SystemPacketBuffer.h
@@ -278,17 +278,14 @@
         return *this;
     }
 
-    PacketBufferHandle Clone() const
+    PacketBufferHandle Retain() const
     {
         mBuffer->AddRef();
         return PacketBufferHandle(mBuffer);
     }
 
-    PacketBuffer * operator->() { return mBuffer; }
-    PacketBuffer & operator*() { return *mBuffer; }
-
-    const PacketBuffer * operator->() const { return mBuffer; }
-    const PacketBuffer & operator*() const { return *mBuffer; }
+    PacketBuffer * operator->() const { return mBuffer; }
+    PacketBuffer & operator*() const { return *mBuffer; }
 
     // The caller's ownership is transferred to this.
     void Adopt(PacketBuffer * buffer)
@@ -315,6 +312,7 @@
     // a permanent version may be created if/when the need is clear. Most uses will be converted to take a
     // `const PacketBufferHandle &`.
     PacketBuffer * Get_ForNow() { return mBuffer; }
+    const PacketBuffer * Get_ForNow() const { return mBuffer; }
 
     bool IsNull() const { return mBuffer == nullptr; }
 
diff --git a/src/transport/BLE.cpp b/src/transport/BLE.cpp
index 45eecc4..0169848 100644
--- a/src/transport/BLE.cpp
+++ b/src/transport/BLE.cpp
@@ -187,7 +187,7 @@
     }
 }
 
-void BLE::OnBleEndPointReceive(BLEEndPoint * endPoint, PacketBuffer * buffer)
+void BLE::OnBleEndPointReceive(BLEEndPoint * endPoint, PacketBufferHandle buffer)
 {
     BLE * ble      = reinterpret_cast<BLE *>(endPoint->mAppState);
     CHIP_ERROR err = CHIP_NO_ERROR;
@@ -201,7 +201,7 @@
         SuccessOrExit(err);
 
         buffer->ConsumeHead(headerSize);
-        ble->mDelegate->OnRendezvousMessageReceived(header, Transport::PeerAddress(Transport::Type::kBle), buffer);
+        ble->mDelegate->OnRendezvousMessageReceived(header, Transport::PeerAddress(Transport::Type::kBle), std::move(buffer));
     }
 exit:
     if (err != CHIP_NO_ERROR)
diff --git a/src/transport/BLE.h b/src/transport/BLE.h
index 7b156ad..f956dbd 100644
--- a/src/transport/BLE.h
+++ b/src/transport/BLE.h
@@ -98,7 +98,7 @@
     static void OnBleConnectionError(void * appState, BLE_ERROR err);
 
     // Those functions are BLEEndPoint callbacks
-    static void OnBleEndPointReceive(Ble::BLEEndPoint * endPoint, System::PacketBuffer * buffer);
+    static void OnBleEndPointReceive(Ble::BLEEndPoint * endPoint, System::PacketBufferHandle buffer);
     static void OnBleEndPointConnectionComplete(Ble::BLEEndPoint * endPoint, BLE_ERROR err);
     static void OnBleEndPointConnectionClosed(Ble::BLEEndPoint * endPoint, BLE_ERROR err);
 
diff --git a/src/transport/RendezvousSession.cpp b/src/transport/RendezvousSession.cpp
index 220c16a..70d8b7c 100644
--- a/src/transport/RendezvousSession.cpp
+++ b/src/transport/RendezvousSession.cpp
@@ -288,7 +288,7 @@
 }
 
 void RendezvousSession::OnRendezvousMessageReceived(const PacketHeader & packetHeader, const PeerAddress & peerAddress,
-                                                    PacketBuffer * msgBuf)
+                                                    PacketBufferHandle msgBuf)
 {
     CHIP_ERROR err = CHIP_NO_ERROR;
     // TODO: RendezvousSession should handle SecurePairing messages only
@@ -296,11 +296,11 @@
     switch (mCurrentState)
     {
     case State::kSecurePairing:
-        err = HandlePairingMessage(packetHeader, peerAddress, msgBuf);
+        err = HandlePairingMessage(packetHeader, peerAddress, std::move(msgBuf));
         break;
 
     case State::kNetworkProvisioning:
-        err = HandleSecureMessage(packetHeader, peerAddress, msgBuf);
+        err = HandleSecureMessage(packetHeader, peerAddress, std::move(msgBuf));
         break;
 
     default:
@@ -315,24 +315,21 @@
 }
 
 void RendezvousSession::OnMessageReceived(const PacketHeader & header, const Transport::PeerAddress & source,
-                                          System::PacketBuffer * msgBuf)
+                                          System::PacketBufferHandle msgBuf)
 {
     // TODO: OnRendezvousMessageReceived can be renamed to OnMessageReceived after BLE becomes a transport.
-    this->OnRendezvousMessageReceived(header, source, msgBuf);
+    this->OnRendezvousMessageReceived(header, source, std::move(msgBuf));
 }
 
 CHIP_ERROR RendezvousSession::HandlePairingMessage(const PacketHeader & packetHeader, const PeerAddress & peerAddress,
-                                                   PacketBuffer * msgBuf)
+                                                   PacketBufferHandle msgBuf)
 {
-    return mPairingSession.HandlePeerMessage(packetHeader, peerAddress, msgBuf);
+    return mPairingSession.HandlePeerMessage(packetHeader, peerAddress, std::move(msgBuf));
 }
 
 CHIP_ERROR RendezvousSession::HandleSecureMessage(const PacketHeader & packetHeader, const PeerAddress & peerAddress,
-                                                  PacketBuffer * msgIn)
+                                                  PacketBufferHandle msgBuf)
 {
-    System::PacketBufferHandle msgBuf;
-    msgBuf.Adopt(msgIn);
-
     uint16_t headerSize = 0;
     uint8_t * plainText = nullptr;
     uint16_t taglen     = 0;
diff --git a/src/transport/RendezvousSession.h b/src/transport/RendezvousSession.h
index 9f79908..787e057 100644
--- a/src/transport/RendezvousSession.h
+++ b/src/transport/RendezvousSession.h
@@ -112,7 +112,7 @@
     void OnRendezvousConnectionClosed() override;
     void OnRendezvousError(CHIP_ERROR err) override;
     void OnRendezvousMessageReceived(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
-                                     System::PacketBuffer * buffer) override;
+                                     System::PacketBufferHandle buffer) override;
 
     //////////// RendezvousDeviceCredentialsDelegate Implementation ///////////////
     void SendNetworkCredentials(const char * ssid, const char * passwd) override;
@@ -126,7 +126,7 @@
 
     //////////// TransportMgrDelegate Implementation ///////////////
     void OnMessageReceived(const PacketHeader & header, const Transport::PeerAddress & source,
-                           System::PacketBuffer * msgBuf) override;
+                           System::PacketBufferHandle msgBuf) override;
 
     /**
      * @brief
@@ -139,12 +139,12 @@
 
 private:
     CHIP_ERROR HandlePairingMessage(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
-                                    System::PacketBuffer * msgBug);
+                                    System::PacketBufferHandle msgBuf);
     CHIP_ERROR Pair(Optional<NodeId> nodeId, uint32_t setupPINCode);
     CHIP_ERROR WaitForPairing(Optional<NodeId> nodeId, uint32_t setupPINCode);
 
     CHIP_ERROR HandleSecureMessage(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
-                                   System::PacketBuffer * msgBuf);
+                                   System::PacketBufferHandle msgBuf);
     Transport::Base * mTransport          = nullptr; ///< Underlying transport
     RendezvousSessionDelegate * mDelegate = nullptr; ///< Underlying transport events
     RendezvousParameters mParams;                    ///< Rendezvous configuration
diff --git a/src/transport/RendezvousSessionDelegate.h b/src/transport/RendezvousSessionDelegate.h
index 3cd6366..28157df 100644
--- a/src/transport/RendezvousSessionDelegate.h
+++ b/src/transport/RendezvousSessionDelegate.h
@@ -42,7 +42,7 @@
     virtual void OnRendezvousError(CHIP_ERROR err) {}
     virtual void OnRendezvousComplete() {}
     virtual void OnRendezvousMessageReceived(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
-                                             System::PacketBuffer * buffer){};
+                                             System::PacketBufferHandle buffer){};
     virtual void OnRendezvousStatusUpdate(Status status, CHIP_ERROR err) {}
 };
 
diff --git a/src/transport/SecurePairingSession.cpp b/src/transport/SecurePairingSession.cpp
index c0a4207..a815901 100644
--- a/src/transport/SecurePairingSession.cpp
+++ b/src/transport/SecurePairingSession.cpp
@@ -429,14 +429,12 @@
 }
 
 CHIP_ERROR SecurePairingSession::HandlePeerMessage(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
-                                                   System::PacketBuffer * msgIn)
+                                                   System::PacketBufferHandle msg)
 {
     CHIP_ERROR err      = CHIP_NO_ERROR;
     uint16_t headerSize = 0;
     PayloadHeader payloadHeader;
-    System::PacketBufferHandle msg;
 
-    msg.Adopt(msgIn);
     VerifyOrExit(!msg.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
 
     err = payloadHeader.Decode(packetHeader.GetFlags(), msg->Start(), msg->DataLength(), &headerSize);
diff --git a/src/transport/SecurePairingSession.h b/src/transport/SecurePairingSession.h
index 0205544..97d4bfc 100644
--- a/src/transport/SecurePairingSession.h
+++ b/src/transport/SecurePairingSession.h
@@ -159,7 +159,7 @@
      * @return CHIP_ERROR The result of message processing
      */
     virtual CHIP_ERROR HandlePeerMessage(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
-                                         System::PacketBuffer * msg);
+                                         System::PacketBufferHandle msg);
 
     /**
      * @brief
@@ -311,7 +311,7 @@
     }
 
     CHIP_ERROR HandlePeerMessage(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
-                                 System::PacketBuffer * msg) override
+                                 System::PacketBufferHandle msg) override
     {
         return CHIP_NO_ERROR;
     }
diff --git a/src/transport/SecureSessionMgr.cpp b/src/transport/SecureSessionMgr.cpp
index ba4d4fd..d6397f4 100644
--- a/src/transport/SecureSessionMgr.cpp
+++ b/src/transport/SecureSessionMgr.cpp
@@ -279,16 +279,13 @@
 }
 
 void SecureSessionMgr::OnMessageReceived(const PacketHeader & packetHeader, const PeerAddress & peerAddress,
-                                         System::PacketBuffer * msgIn)
-
+                                         System::PacketBufferHandle msg)
 {
     CHIP_ERROR err = CHIP_NO_ERROR;
     PeerConnectionState * state =
         mPeerConnections.FindPeerConnectionState(packetHeader.GetSourceNodeId(), packetHeader.GetEncryptionKeyID(), nullptr);
-    PacketBufferHandle msg;
     PacketBufferHandle origMsg;
 
-    msg.Adopt(msgIn);
     VerifyOrExit(!msg.IsNull(), ChipLogError(Inet, "Secure transport received NULL packet, discarding"));
 
     if (state == nullptr)
@@ -352,7 +349,7 @@
 
         if (mCB != nullptr)
         {
-            mCB->OnMessageReceived(packetHeader, payloadHeader, state, msg.Release_ForNow(), this);
+            mCB->OnMessageReceived(packetHeader, payloadHeader, state, std::move(msg), this);
         }
     }
 
diff --git a/src/transport/SecureSessionMgr.h b/src/transport/SecureSessionMgr.h
index dcb73ee..56d3193 100644
--- a/src/transport/SecureSessionMgr.h
+++ b/src/transport/SecureSessionMgr.h
@@ -66,7 +66,7 @@
      * @param mgr           A pointer to the SecureSessionMgr
      */
     virtual void OnMessageReceived(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
-                                   const Transport::PeerConnectionState * state, System::PacketBuffer * msgBuf,
+                                   const Transport::PeerConnectionState * state, System::PacketBufferHandle msgBuf,
                                    SecureSessionMgr * mgr)
     {}
 
@@ -173,7 +173,7 @@
      * @param msgBuf    the buffer of (encrypted) payload
      */
     void OnMessageReceived(const PacketHeader & header, const Transport::PeerAddress & source,
-                           System::PacketBuffer * msgBuf) override;
+                           System::PacketBufferHandle msgBuf) override;
 
 private:
     /**
diff --git a/src/transport/TransportMgr.cpp b/src/transport/TransportMgr.cpp
index 6425866..8cd040a 100644
--- a/src/transport/TransportMgr.cpp
+++ b/src/transport/TransportMgr.cpp
@@ -48,13 +48,13 @@
 }
 
 void TransportMgrBase::HandleMessageReceived(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
-                                             System::PacketBuffer * msg, TransportMgrBase * dispatcher)
+                                             System::PacketBufferHandle msg, TransportMgrBase * dispatcher)
 {
     TransportMgrDelegate * handler =
         packetHeader.GetFlags().Has(Header::FlagValues::kSecure) ? dispatcher->mSecureSessionMgr : dispatcher->mRendezvous;
     if (handler != nullptr)
     {
-        handler->OnMessageReceived(packetHeader, peerAddress, msg);
+        handler->OnMessageReceived(packetHeader, peerAddress, std::move(msg));
     }
     else
     {
diff --git a/src/transport/TransportMgr.h b/src/transport/TransportMgr.h
index af0e3c7..062e1bc 100644
--- a/src/transport/TransportMgr.h
+++ b/src/transport/TransportMgr.h
@@ -51,7 +51,7 @@
      * @param msgBuf    the buffer of (encrypted) payload
      */
     virtual void OnMessageReceived(const PacketHeader & header, const Transport::PeerAddress & source,
-                                   System::PacketBuffer * msgBuf) = 0;
+                                   System::PacketBufferHandle msgBuf) = 0;
 };
 
 class TransportMgrBase
@@ -73,7 +73,7 @@
 
 private:
     static void HandleMessageReceived(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
-                                      System::PacketBuffer * msg, TransportMgrBase * dispatcher);
+                                      System::PacketBufferHandle msg, TransportMgrBase * dispatcher);
 
     TransportMgrDelegate * mSecureSessionMgr = nullptr;
     TransportMgrDelegate * mRendezvous       = nullptr;
diff --git a/src/transport/raw/Base.h b/src/transport/raw/Base.h
index f374bff..b100924 100644
--- a/src/transport/raw/Base.h
+++ b/src/transport/raw/Base.h
@@ -51,7 +51,7 @@
      *
      */
     template <class T>
-    void SetMessageReceiveHandler(void (*handler)(const PacketHeader &, const PeerAddress &, System::PacketBuffer *, T *),
+    void SetMessageReceiveHandler(void (*handler)(const PacketHeader &, const PeerAddress &, System::PacketBufferHandle, T *),
                                   T * param)
     {
         mMessageReceivedArgument = param;
@@ -92,15 +92,11 @@
      * Method used by subclasses to notify that a packet has been received after
      * any associated headers have been decoded.
      */
-    void HandleMessageReceived(const PacketHeader & header, const PeerAddress & source, System::PacketBuffer * buffer)
+    void HandleMessageReceived(const PacketHeader & header, const PeerAddress & source, System::PacketBufferHandle buffer)
     {
         if (OnMessageReceived)
         {
-            OnMessageReceived(header, source, buffer, mMessageReceivedArgument);
-        }
-        else
-        {
-            System::PacketBuffer::Free(buffer);
+            OnMessageReceived(header, source, std::move(buffer), mMessageReceivedArgument);
         }
     }
 
@@ -112,8 +108,8 @@
      *
      * Callback *MUST* free msgBuf as a result of handling.
      */
-    typedef void (*MessageReceiveHandler)(const PacketHeader & header, const PeerAddress & source, System::PacketBuffer * msgBuf,
-                                          void * param);
+    typedef void (*MessageReceiveHandler)(const PacketHeader & header, const PeerAddress & source,
+                                          System::PacketBufferHandle msgBuf, void * param);
 
     MessageReceiveHandler OnMessageReceived = nullptr; ///< Callback on message receiving
     void * mMessageReceivedArgument         = nullptr; ///< Argument for callback
diff --git a/src/transport/raw/TCP.cpp b/src/transport/raw/TCP.cpp
index 7b5c957..9d42e2b 100644
--- a/src/transport/raw/TCP.cpp
+++ b/src/transport/raw/TCP.cpp
@@ -47,7 +47,7 @@
 /**
  *  Determine if the given buffer contains a complete message
  */
-bool ContainsCompleteMessage(System::PacketBuffer * buffer, uint8_t ** start, uint16_t * size)
+bool ContainsCompleteMessage(const System::PacketBufferHandle & buffer, uint8_t ** start, uint16_t * size)
 {
     bool completeMessage = false;
 
@@ -304,7 +304,7 @@
     return err;
 }
 
-CHIP_ERROR TCPBase::ProcessSingleMessageFromBufferHead(const PeerAddress & peerAddress, System::PacketBuffer * buffer,
+CHIP_ERROR TCPBase::ProcessSingleMessageFromBufferHead(const PeerAddress & peerAddress, const System::PacketBufferHandle & buffer,
                                                        uint16_t messageSize)
 {
     CHIP_ERROR err     = CHIP_NO_ERROR;
@@ -323,9 +323,7 @@
 
     // message receive handler will attempt to free the buffer, however as the buffer may
     // contain additional data, we retain it to prevent actual free
-    buffer->AddRef();
-
-    HandleMessageReceived(header, peerAddress, buffer);
+    HandleMessageReceived(header, peerAddress, buffer.Retain());
 
 exit:
     buffer->SetStart(oldStart);
@@ -335,18 +333,16 @@
 }
 
 CHIP_ERROR TCPBase::ProcessReceivedBuffer(Inet::TCPEndPoint * endPoint, const PeerAddress & peerAddress,
-                                          System::PacketBuffer * buffer)
+                                          System::PacketBufferHandle buffer)
 {
     CHIP_ERROR err = CHIP_NO_ERROR;
 
-    while (buffer != nullptr)
+    while (!buffer.IsNull())
     {
         // when a buffer is empty, it can be released back to the app
         if (buffer->DataLength() == 0)
         {
-            System::PacketBuffer * old = buffer;
-            buffer                     = old->DetachTail();
-            System::PacketBuffer::Free(old);
+            buffer.Adopt(buffer->DetachTail());
             continue;
         }
 
@@ -398,16 +394,16 @@
     }
 
 exit:
-    if (buffer != nullptr)
+    if (!buffer.IsNull())
     {
         // Incomplete processing will be retried
-        endPoint->PutBackReceivedData(buffer);
+        endPoint->PutBackReceivedData(buffer.Release_ForNow());
     }
 
     return err;
 }
 
-void TCPBase::OnTcpReceive(Inet::TCPEndPoint * endPoint, System::PacketBuffer * buffer)
+void TCPBase::OnTcpReceive(Inet::TCPEndPoint * endPoint, System::PacketBufferHandle buffer)
 {
     Inet::IPAddress ipAddress;
     uint16_t port;
@@ -416,7 +412,7 @@
     PeerAddress peerAddress = PeerAddress::TCP(ipAddress, port);
 
     TCPBase * tcp  = reinterpret_cast<TCPBase *>(endPoint->AppState);
-    CHIP_ERROR err = tcp->ProcessReceivedBuffer(endPoint, peerAddress, buffer);
+    CHIP_ERROR err = tcp->ProcessReceivedBuffer(endPoint, peerAddress, std::move(buffer));
 
     if (err != CHIP_NO_ERROR)
     {
diff --git a/src/transport/raw/TCP.h b/src/transport/raw/TCP.h
index 0888e3a..5b6f7d8 100644
--- a/src/transport/raw/TCP.h
+++ b/src/transport/raw/TCP.h
@@ -178,7 +178,8 @@
      * Ownership of buffer is taken over and will be freed (or re-enqueued to the endPoint receive queue)
      * as needed during processing.
      */
-    CHIP_ERROR ProcessReceivedBuffer(Inet::TCPEndPoint * endPoint, const PeerAddress & peerAddress, System::PacketBuffer * buffer);
+    CHIP_ERROR ProcessReceivedBuffer(Inet::TCPEndPoint * endPoint, const PeerAddress & peerAddress,
+                                     System::PacketBufferHandle buffer);
 
     /**
      * Process a single message of the specified size from a buffer.
@@ -186,15 +187,13 @@
      * @param peerAddress the peer the data is coming from
      * @param buffer the buffer containing the message
      * @param messageSize how much of the head contains the actual message
-     *
-     * Does *not* free buffer.
      */
-    CHIP_ERROR ProcessSingleMessageFromBufferHead(const PeerAddress & peerAddress, System::PacketBuffer * buffer,
+    CHIP_ERROR ProcessSingleMessageFromBufferHead(const PeerAddress & peerAddress, const System::PacketBufferHandle & buffer,
                                                   uint16_t messageSize);
 
     // Callback handler for TCPEndPoint. TCP message receive handler.
     // @see TCPEndpoint::OnDataReceivedFunct
-    static void OnTcpReceive(Inet::TCPEndPoint * endPoint, System::PacketBuffer * buffer);
+    static void OnTcpReceive(Inet::TCPEndPoint * endPoint, System::PacketBufferHandle buffer);
 
     // Callback handler for TCPEndPoint. Called when a connection has been completed.
     // @see TCPEndpoint::OnConnectCompleteFunct
diff --git a/src/transport/raw/Tuple.h b/src/transport/raw/Tuple.h
index bd887ba..20a2b6b 100644
--- a/src/transport/raw/Tuple.h
+++ b/src/transport/raw/Tuple.h
@@ -227,9 +227,9 @@
      * Calls the underlying Base message receive handler whenever any of the underlying transports
      * receives a message.
      */
-    static void OnMessageReceive(const PacketHeader & header, const PeerAddress & source, System::PacketBuffer * msg, Tuple * t)
+    static void OnMessageReceive(const PacketHeader & header, const PeerAddress & source, System::PacketBufferHandle msg, Tuple * t)
     {
-        t->HandleMessageReceived(header, source, msg);
+        t->HandleMessageReceived(header, source, std::move(msg));
     }
 
     std::tuple<TransportTypes...> mTransports;
diff --git a/src/transport/raw/UDP.cpp b/src/transport/raw/UDP.cpp
index 3542ae3..2ca4931 100644
--- a/src/transport/raw/UDP.cpp
+++ b/src/transport/raw/UDP.cpp
@@ -119,7 +119,7 @@
     return mUDPEndPoint->SendMsg(&addrInfo, msgBuf.Release_ForNow());
 }
 
-void UDP::OnUdpReceive(Inet::IPEndPointBasis * endPoint, System::PacketBuffer * buffer, const Inet::IPPacketInfo * pktInfo)
+void UDP::OnUdpReceive(Inet::IPEndPointBasis * endPoint, System::PacketBufferHandle buffer, const Inet::IPPacketInfo * pktInfo)
 {
     CHIP_ERROR err          = CHIP_NO_ERROR;
     UDP * udp               = reinterpret_cast<UDP *>(endPoint->AppState);
@@ -131,7 +131,7 @@
     SuccessOrExit(err);
 
     buffer->ConsumeHead(headerSize);
-    udp->HandleMessageReceived(header, peerAddress, buffer);
+    udp->HandleMessageReceived(header, peerAddress, std::move(buffer));
 
 exit:
     if (err != CHIP_NO_ERROR)
diff --git a/src/transport/raw/UDP.h b/src/transport/raw/UDP.h
index 2cfbf76..6aac949 100644
--- a/src/transport/raw/UDP.h
+++ b/src/transport/raw/UDP.h
@@ -121,7 +121,8 @@
 
 private:
     // UDP message receive handler.
-    static void OnUdpReceive(Inet::IPEndPointBasis * endPoint, System::PacketBuffer * buffer, const Inet::IPPacketInfo * pktInfo);
+    static void OnUdpReceive(Inet::IPEndPointBasis * endPoint, System::PacketBufferHandle buffer,
+                             const Inet::IPPacketInfo * pktInfo);
 
     Inet::UDPEndPoint * mUDPEndPoint     = nullptr;                                     ///< UDP socket used by the transport
     Inet::IPAddressType mUDPEndpointType = Inet::IPAddressType::kIPAddressType_Unknown; ///< Socket listening type
diff --git a/src/transport/raw/tests/TestTCP.cpp b/src/transport/raw/tests/TestTCP.cpp
index 9581efe..da9ca78 100644
--- a/src/transport/raw/tests/TestTCP.cpp
+++ b/src/transport/raw/tests/TestTCP.cpp
@@ -56,7 +56,7 @@
 const char PAYLOAD[]        = "Hello!";
 int ReceiveHandlerCallCount = 0;
 
-void MessageReceiveHandler(const PacketHeader & header, const Transport::PeerAddress & source, System::PacketBuffer * msgBuf,
+void MessageReceiveHandler(const PacketHeader & header, const Transport::PeerAddress & source, System::PacketBufferHandle msgBuf,
                            nlTestSuite * inSuite)
 {
     NL_TEST_ASSERT(inSuite, header.GetSourceNodeId() == Optional<NodeId>::Value(kSourceNodeId));
@@ -67,8 +67,6 @@
     int compare     = memcmp(msgBuf->Start(), PAYLOAD, data_len);
     NL_TEST_ASSERT(inSuite, compare == 0);
 
-    System::PacketBuffer::Free(msgBuf);
-
     ReceiveHandlerCallCount++;
 }
 
diff --git a/src/transport/raw/tests/TestUDP.cpp b/src/transport/raw/tests/TestUDP.cpp
index b835480..b301f46 100644
--- a/src/transport/raw/tests/TestUDP.cpp
+++ b/src/transport/raw/tests/TestUDP.cpp
@@ -51,7 +51,7 @@
 const char PAYLOAD[]        = "Hello!";
 int ReceiveHandlerCallCount = 0;
 
-void MessageReceiveHandler(const PacketHeader & header, const Transport::PeerAddress & source, System::PacketBuffer * msgBuf,
+void MessageReceiveHandler(const PacketHeader & header, const Transport::PeerAddress & source, System::PacketBufferHandle msgBuf,
                            nlTestSuite * inSuite)
 {
     NL_TEST_ASSERT(inSuite, header.GetSourceNodeId() == Optional<NodeId>::Value(kSourceNodeId));
@@ -62,8 +62,6 @@
     int compare     = memcmp(msgBuf->Start(), PAYLOAD, data_len);
     NL_TEST_ASSERT(inSuite, compare == 0);
 
-    System::PacketBuffer::Free(msgBuf);
-
     ReceiveHandlerCallCount++;
 }
 
diff --git a/src/transport/tests/TestSecurePairingSession.cpp b/src/transport/tests/TestSecurePairingSession.cpp
index dd8a78e..809caf0 100644
--- a/src/transport/tests/TestSecurePairingSession.cpp
+++ b/src/transport/tests/TestSecurePairingSession.cpp
@@ -43,7 +43,9 @@
                                   const Transport::PeerAddress & peerAddress, System::PacketBuffer * msgBuf) override
     {
         mNumMessageSend++;
-        return (peer != nullptr) ? peer->HandlePeerMessage(header, peerAddress, msgBuf) : mMessageSendError;
+        System::PacketBufferHandle msg_ForNow;
+        msg_ForNow.Adopt(msgBuf);
+        return (peer != nullptr) ? peer->HandlePeerMessage(header, peerAddress, std::move(msg_ForNow)) : mMessageSendError;
     }
 
     void OnPairingError(CHIP_ERROR error) override { mNumPairingErrors++; }
diff --git a/src/transport/tests/TestSecureSessionMgr.cpp b/src/transport/tests/TestSecureSessionMgr.cpp
index 9795f43..f5a04a0 100644
--- a/src/transport/tests/TestSecureSessionMgr.cpp
+++ b/src/transport/tests/TestSecureSessionMgr.cpp
@@ -57,7 +57,9 @@
     CHIP_ERROR SendMessage(const PacketHeader & header, Header::Flags payloadFlags, const PeerAddress & address,
                            System::PacketBuffer * msgBuf) override
     {
-        HandleMessageReceived(header, address, msgBuf);
+        System::PacketBufferHandle msg_ForNow;
+        msg_ForNow.Adopt(msgBuf);
+        HandleMessageReceived(header, address, std::move(msg_ForNow));
         return CHIP_NO_ERROR;
     }
 
@@ -68,7 +70,7 @@
 {
 public:
     void OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader, const PeerConnectionState * state,
-                           System::PacketBuffer * msgBuf, SecureSessionMgr * mgr) override
+                           System::PacketBufferHandle msgBuf, SecureSessionMgr * mgr) override
     {
         NL_TEST_ASSERT(mSuite, header.GetSourceNodeId() == Optional<NodeId>::Value(kSourceNodeId));
         NL_TEST_ASSERT(mSuite, header.GetDestinationNodeId() == Optional<NodeId>::Value(kDestinationNodeId));