Enable ReadHandler to support large payloads (#33814)

* ReadHandler changes for large payloads

When sending reports, if the session established with the peer
supports large payloads, the ReadHandler will allocate a large
buffer to, potentially, fit more attribute and event data.

* Address comments and apply suggestions from code review

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Update src/app/ReadHandler.cpp

Co-authored-by: Andrei Litvin <andy314@gmail.com>

---------

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
Co-authored-by: Andrei Litvin <andy314@gmail.com>
diff --git a/src/app/ReadHandler.cpp b/src/app/ReadHandler.cpp
index dd4c928..487acd2 100644
--- a/src/app/ReadHandler.cpp
+++ b/src/app/ReadHandler.cpp
@@ -919,5 +919,15 @@
     SetStateFlag(aFlag, false);
 }
 
+size_t ReadHandler::GetReportBufferMaxSize()
+{
+    Transport::SecureSession * session = GetSession();
+    if (session && session->AllowsLargePayload())
+    {
+        return kMaxLargeSecureSduLengthBytes;
+    }
+    return kMaxSecureSduLengthBytes;
+}
+
 } // namespace app
 } // namespace chip
diff --git a/src/app/ReadHandler.h b/src/app/ReadHandler.h
index a30f1f8..c973432 100644
--- a/src/app/ReadHandler.h
+++ b/src/app/ReadHandler.h
@@ -333,6 +333,15 @@
      */
     CHIP_ERROR SendReportData(System::PacketBufferHandle && aPayload, bool aMoreChunks);
 
+    /*
+     * Get the appropriate size of a packet buffer to allocate for encoding a Report message.
+     * This size might depend on the underlying session used by the ReadHandler.
+     *
+     * The size returned here is the size not including the various prepended headers
+     * (what System::PacketBuffer calls the "available size").
+     */
+    size_t GetReportBufferMaxSize();
+
     /**
      *  Returns whether this ReadHandler represents a subscription that was created by the other side of the provided exchange.
      */
diff --git a/src/app/StatusResponse.h b/src/app/StatusResponse.h
index 93f2557..e823c33 100644
--- a/src/app/StatusResponse.h
+++ b/src/app/StatusResponse.h
@@ -26,7 +26,8 @@
 
 namespace chip {
 namespace app {
-static constexpr size_t kMaxSecureSduLengthBytes = kMaxAppMessageLen + kMaxTagLen;
+static constexpr size_t kMaxSecureSduLengthBytes      = kMaxAppMessageLen + kMaxTagLen;
+static constexpr size_t kMaxLargeSecureSduLengthBytes = kMaxLargeAppMessageLen + kMaxTagLen;
 
 class StatusResponse
 {
diff --git a/src/app/reporting/Engine.cpp b/src/app/reporting/Engine.cpp
index 39c582f..dfa64cf 100644
--- a/src/app/reporting/Engine.cpp
+++ b/src/app/reporting/Engine.cpp
@@ -492,10 +492,11 @@
     CHIP_ERROR err = CHIP_NO_ERROR;
     chip::System::PacketBufferTLVWriter reportDataWriter;
     ReportDataMessage::Builder reportDataBuilder;
-    chip::System::PacketBufferHandle bufHandle = System::PacketBufferHandle::New(chip::app::kMaxSecureSduLengthBytes);
+    chip::System::PacketBufferHandle bufHandle = nullptr;
     uint16_t reservedSize                      = 0;
     bool hasMoreChunks                         = false;
     bool needCloseReadHandler                  = false;
+    size_t reportBufferMaxSize                 = 0;
 
     // Reserved size for the MoreChunks boolean flag, which takes up 1 byte for the control tag and 1 byte for the context tag.
     const uint32_t kReservedSizeForMoreChunksFlag = 1 + 1;
@@ -512,11 +513,15 @@
 
     VerifyOrExit(apReadHandler != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
     VerifyOrExit(apReadHandler->GetSession() != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
+
+    reportBufferMaxSize = apReadHandler->GetReportBufferMaxSize();
+
+    bufHandle = System::PacketBufferHandle::New(reportBufferMaxSize);
     VerifyOrExit(!bufHandle.IsNull(), err = CHIP_ERROR_NO_MEMORY);
 
-    if (bufHandle->AvailableDataLength() > kMaxSecureSduLengthBytes)
+    if (bufHandle->AvailableDataLength() > reportBufferMaxSize)
     {
-        reservedSize = static_cast<uint16_t>(bufHandle->AvailableDataLength() - kMaxSecureSduLengthBytes);
+        reservedSize = static_cast<uint16_t>(bufHandle->AvailableDataLength() - reportBufferMaxSize);
     }
 
     reportDataWriter.Init(std::move(bufHandle));
@@ -525,8 +530,8 @@
     reportDataWriter.ReserveBuffer(mReservedSize);
 #endif
 
-    // Always limit the size of the generated packet to fit within kMaxSecureSduLengthBytes regardless of the available buffer
-    // capacity.
+    // Always limit the size of the generated packet to fit within the max size returned by the ReadHandler regardless
+    // of the available buffer capacity.
     // Also, we need to reserve some extra space for the MIC field.
     reportDataWriter.ReserveBuffer(static_cast<uint32_t>(reservedSize + chip::Crypto::CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES));