diff --git a/config/nrfconnect/chip-module/CMakeLists.txt b/config/nrfconnect/chip-module/CMakeLists.txt index 51ca4689de1ca1..29560db74f38cc 100644 --- a/config/nrfconnect/chip-module/CMakeLists.txt +++ b/config/nrfconnect/chip-module/CMakeLists.txt @@ -129,7 +129,7 @@ matter_add_gn_arg_bool ("chip_enable_nfc" CONFIG_CHIP_NF matter_add_gn_arg_bool ("chip_enable_ota_requestor" CONFIG_CHIP_OTA_REQUESTOR) matter_add_gn_arg_bool ("chip_persist_subscriptions" CONFIG_CHIP_PERSISTENT_SUBSCRIPTIONS) matter_add_gn_arg_bool ("chip_monolithic_tests" CONFIG_CHIP_BUILD_TESTS) -matter_add_gn_arg_bool ("chip_inet_config_enable_tcp_endpoint" CONFIG_CHIP_BUILD_TESTS) +matter_add_gn_arg_bool ("chip_inet_config_enable_tcp_endpoint" FALSE) matter_add_gn_arg_bool ("chip_error_logging" CONFIG_MATTER_LOG_LEVEL GREATER_EQUAL 1) matter_add_gn_arg_bool ("chip_progress_logging" CONFIG_MATTER_LOG_LEVEL GREATER_EQUAL 3) matter_add_gn_arg_bool ("chip_detail_logging" CONFIG_MATTER_LOG_LEVEL GREATER_EQUAL 4) diff --git a/src/inet/TCPEndPoint.h b/src/inet/TCPEndPoint.h index 8fc6a6338d4140..57652349cfa83a 100644 --- a/src/inet/TCPEndPoint.h +++ b/src/inet/TCPEndPoint.h @@ -522,7 +522,7 @@ class DLL_EXPORT TCPEndPoint : public EndPointBasis /** * Size of the largest TCP packet that can be received. */ - constexpr static size_t kMaxReceiveMessageSize = System::PacketBuffer::kMaxSizeWithoutReserve; + constexpr static size_t kMaxReceiveMessageSize = System::PacketBuffer::kMaxAllocSize; protected: friend class TCPTest; diff --git a/src/inet/TCPEndPointImplSockets.cpp b/src/inet/TCPEndPointImplSockets.cpp index d21c11b6a42865..6b8965b19d2b4b 100644 --- a/src/inet/TCPEndPointImplSockets.cpp +++ b/src/inet/TCPEndPointImplSockets.cpp @@ -947,10 +947,9 @@ void TCPEndPointImplSockets::ReceiveData() { VerifyOrDie(rcvLen > 0); size_t newDataLength = rcvBuf->DataLength() + static_cast(rcvLen); - VerifyOrDie(CanCastTo(newDataLength)); if (isNewBuf) { - rcvBuf->SetDataLength(static_cast(newDataLength)); + rcvBuf->SetDataLength(newDataLength); rcvBuf.RightSize(); if (mRcvQueue.IsNull()) { @@ -963,7 +962,7 @@ void TCPEndPointImplSockets::ReceiveData() } else { - rcvBuf->SetDataLength(static_cast(newDataLength), mRcvQueue); + rcvBuf->SetDataLength(newDataLength, mRcvQueue); } } } diff --git a/src/system/SystemConfig.h b/src/system/SystemConfig.h index e91f59298f683e..475ab897ba2888 100644 --- a/src/system/SystemConfig.h +++ b/src/system/SystemConfig.h @@ -788,3 +788,12 @@ struct LwIPEvent; #define CHIP_SYSTEM_CONFIG_USE_ZEPHYR_EVENTFD 0 #endif #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_EVENTFD + +/** + * @def CHIP_SYSTEM_CONFIG_MAX_LARGE_BUFFER_SIZE_BYTES + * + * @brief Maximum buffer allocation size of a 'Large' message + */ +#ifndef CHIP_SYSTEM_CONFIG_MAX_LARGE_BUFFER_SIZE_BYTES +#define CHIP_SYSTEM_CONFIG_MAX_LARGE_BUFFER_SIZE_BYTES (64000) +#endif diff --git a/src/system/SystemPacketBuffer.cpp b/src/system/SystemPacketBuffer.cpp index f8dda8b01ab84e..33349f9f139856 100644 --- a/src/system/SystemPacketBuffer.cpp +++ b/src/system/SystemPacketBuffer.cpp @@ -515,6 +515,23 @@ PacketBufferHandle PacketBufferHandle::New(size_t aAvailableSize, uint16_t aRese // Setting a static upper bound on the maximum buffer size allocation for regular sized messages (not large). static_assert(PacketBuffer::kMaxSizeWithoutReserve <= UINT16_MAX, "kMaxSizeWithoutReserve should not exceed UINT16_MAX."); +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + // Setting a static upper bound on the maximum buffer size allocation for + // large messages. +#if CHIP_SYSTEM_CONFIG_USE_LWIP + static_assert(PacketBuffer::kLargeBufMaxSizeWithoutReserve <= UINT16_MAX, + "In LwIP, max size for Large payload buffers cannot exceed UINT16_MAX!"); +#else + static_assert(PacketBuffer::kLargeBufMaxSizeWithoutReserve <= UINT32_MAX, + "Max size for Large payload buffers cannot exceed UINT32_MAX"); +#endif // CHIP_SYSTEM_CONFIG_USE_LWIP + + // Ensure that the definition of the max buffer allocation for regular + // messages is less than that for large ones. + static_assert(PacketBuffer::kMaxSizeWithoutReserve < PacketBuffer::kLargeBufMaxSizeWithoutReserve, + "Large buffer configuration should be greater than the conventional buffer limit"); +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + // Ensure that aAvailableSize is bound within a max and is not big enough to cause overflow during // subsequent addition of all the sizes. if (aAvailableSize > UINT32_MAX) @@ -557,7 +574,7 @@ PacketBufferHandle PacketBufferHandle::New(size_t aAvailableSize, uint16_t aRese CHIP_SYSTEM_FAULT_INJECT(FaultInjection::kFault_PacketBufferNew, return PacketBufferHandle()); - if (lAllocSize > PacketBuffer::kMaxSizeWithoutReserve) + if (lAllocSize > PacketBuffer::kMaxAllocSize) { ChipLogError(chipSystemLayer, "PacketBuffer: allocation exceeding buffer capacity limits."); return PacketBufferHandle(); @@ -621,11 +638,6 @@ PacketBufferHandle PacketBufferHandle::New(size_t aAvailableSize, uint16_t aRese PacketBufferHandle PacketBufferHandle::NewWithData(const void * aData, size_t aDataSize, size_t aAdditionalSize, uint16_t aReservedSize) { - if (aDataSize > UINT16_MAX) - { - ChipLogError(chipSystemLayer, "PacketBuffer: allocation too large."); - return PacketBufferHandle(); - } // Since `aDataSize` fits in uint16_t, the sum `aDataSize + aAdditionalSize` will not overflow. // `New()` will only return a non-null buffer if the total allocation size does not overflow. PacketBufferHandle buffer = New(aDataSize + aAdditionalSize, aReservedSize); @@ -633,6 +645,8 @@ PacketBufferHandle PacketBufferHandle::NewWithData(const void * aData, size_t aD { memcpy(buffer.mBuffer->payload, aData, aDataSize); #if CHIP_SYSTEM_CONFIG_USE_LWIP + // The VerifyOrDie() in the New() call catches buffer allocations greater + // than UINT16_MAX for LwIP based platforms. buffer.mBuffer->len = buffer.mBuffer->tot_len = static_cast(aDataSize); #else buffer.mBuffer->len = buffer.mBuffer->tot_len = aDataSize; @@ -755,18 +769,20 @@ PacketBufferHandle PacketBufferHandle::CloneData() const size_t originalDataSize = original->MaxDataLength(); uint16_t originalReservedSize = original->ReservedSize(); - if (originalDataSize + originalReservedSize > PacketBuffer::kMaxSizeWithoutReserve) + uint32_t maxSize = PacketBuffer::kMaxAllocSize; + + if (originalDataSize + originalReservedSize > maxSize) { // The original memory allocation may have provided a larger block than requested (e.g. when using a shared pool), // and in particular may have provided a larger block than we are able to request from PackBufferHandle::New(). // It is a genuine error if that extra space has been used. - if (originalReservedSize + original->DataLength() > PacketBuffer::kMaxSizeWithoutReserve) + if (originalReservedSize + original->DataLength() > maxSize) { return PacketBufferHandle(); } // Otherwise, reduce the requested data size. This subtraction can not underflow because the above test - // guarantees originalReservedSize <= PacketBuffer::kMaxSizeWithoutReserve. - originalDataSize = PacketBuffer::kMaxSizeWithoutReserve - originalReservedSize; + // guarantees originalReservedSize <= maxSize. + originalDataSize = maxSize - originalReservedSize; } PacketBufferHandle clone = PacketBufferHandle::New(originalDataSize, originalReservedSize); diff --git a/src/system/SystemPacketBuffer.h b/src/system/SystemPacketBuffer.h index 41eaef6d9e305c..f228dcc37d7442 100644 --- a/src/system/SystemPacketBuffer.h +++ b/src/system/SystemPacketBuffer.h @@ -138,6 +138,18 @@ class DLL_EXPORT PacketBuffer : private pbuf */ static constexpr size_t kMaxSize = kMaxSizeWithoutReserve - kDefaultHeaderReserve; +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + static constexpr size_t kLargeBufMaxSizeWithoutReserve = CHIP_SYSTEM_CONFIG_MAX_LARGE_BUFFER_SIZE_BYTES; + + static constexpr size_t kLargeBufMaxSize = kLargeBufMaxSizeWithoutReserve - kDefaultHeaderReserve; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + static constexpr size_t kMaxAllocSize = kLargeBufMaxSizeWithoutReserve; +#else + static constexpr size_t kMaxAllocSize = kMaxSizeWithoutReserve; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + /** * Return the size of the allocation including the reserved and payload data spaces but not including space * allocated for the PacketBuffer structure. diff --git a/src/system/tests/TestSystemPacketBuffer.cpp b/src/system/tests/TestSystemPacketBuffer.cpp index c71ad542d6225a..f9f00a5c9df16d 100644 --- a/src/system/tests/TestSystemPacketBuffer.cpp +++ b/src/system/tests/TestSystemPacketBuffer.cpp @@ -309,7 +309,7 @@ TEST_F_FROM_FIXTURE(TestSystemPacketBuffer, CheckNew) { const PacketBufferHandle buffer = PacketBufferHandle::New(0, config.reserved_size); - if (config.reserved_size > PacketBuffer::kMaxSizeWithoutReserve) + if (config.reserved_size > PacketBuffer::kMaxAllocSize) { EXPECT_TRUE(buffer.IsNull()); continue; @@ -1605,7 +1605,8 @@ TEST_F_FROM_FIXTURE(TestSystemPacketBuffer, CheckHandleRightSize) TEST_F_FROM_FIXTURE(TestSystemPacketBuffer, CheckHandleCloneData) { - uint8_t lPayload[2 * PacketBuffer::kMaxSizeWithoutReserve]; + uint8_t lPayload[2 * PacketBuffer::kMaxAllocSize]; + for (uint8_t & payload : lPayload) { payload = static_cast(random()); @@ -1684,7 +1685,7 @@ TEST_F_FROM_FIXTURE(TestSystemPacketBuffer, CheckHandleCloneData) // This is only testable on heap allocation configurations, where pbuf records the allocation size and we can manually // construct an oversize buffer. - constexpr uint16_t kOversizeDataSize = PacketBuffer::kMaxSizeWithoutReserve + 99; + constexpr size_t kOversizeDataSize = PacketBuffer::kMaxAllocSize + 99; PacketBuffer * p = reinterpret_cast(chip::Platform::MemoryAlloc(kStructureSize + kOversizeDataSize)); ASSERT_NE(p, nullptr); @@ -1698,15 +1699,16 @@ TEST_F_FROM_FIXTURE(TestSystemPacketBuffer, CheckHandleCloneData) PacketBufferHandle handle = PacketBufferHandle::Adopt(p); // Fill the buffer to maximum and verify that it can be cloned. + size_t maxSize = PacketBuffer::kMaxAllocSize; - memset(handle->Start(), 1, PacketBuffer::kMaxSizeWithoutReserve); - handle->SetDataLength(PacketBuffer::kMaxSizeWithoutReserve); - EXPECT_EQ(handle->DataLength(), PacketBuffer::kMaxSizeWithoutReserve); + memset(handle->Start(), 1, maxSize); + handle->SetDataLength(maxSize); + EXPECT_EQ(handle->DataLength(), maxSize); PacketBufferHandle clone = handle.CloneData(); ASSERT_FALSE(clone.IsNull()); - EXPECT_EQ(clone->DataLength(), PacketBuffer::kMaxSizeWithoutReserve); - EXPECT_EQ(memcmp(handle->Start(), clone->Start(), PacketBuffer::kMaxSizeWithoutReserve), 0); + EXPECT_EQ(clone->DataLength(), maxSize); + EXPECT_EQ(memcmp(handle->Start(), clone->Start(), maxSize), 0); // Overfill the buffer and verify that it can not be cloned. memset(handle->Start(), 2, kOversizeDataSize); diff --git a/src/transport/SecureMessageCodec.cpp b/src/transport/SecureMessageCodec.cpp index 3b70026c5681d6..263b4e5e127a5a 100644 --- a/src/transport/SecureMessageCodec.cpp +++ b/src/transport/SecureMessageCodec.cpp @@ -41,7 +41,6 @@ CHIP_ERROR Encrypt(const CryptoContext & context, CryptoContext::ConstNonceView { VerifyOrReturnError(!msgBuf.IsNull(), CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(!msgBuf->HasChainedBuffer(), CHIP_ERROR_INVALID_MESSAGE_LENGTH); - VerifyOrReturnError(msgBuf->TotalLength() <= kMaxAppMessageLen, CHIP_ERROR_MESSAGE_TOO_LONG); ReturnErrorOnFailure(payloadHeader.EncodeBeforeData(msgBuf)); diff --git a/src/transport/SessionManager.cpp b/src/transport/SessionManager.cpp index d49e66fb6f5116..f22c0876df035b 100644 --- a/src/transport/SessionManager.cpp +++ b/src/transport/SessionManager.cpp @@ -201,6 +201,17 @@ CHIP_ERROR SessionManager::PrepareMessage(const SessionHandle & sessionHandle, P packetHeader.SetSecureSessionControlMsg(true); } + if (sessionHandle->AllowsMRP()) + { + VerifyOrReturnError(message->TotalLength() <= kMaxAppMessageLen, CHIP_ERROR_MESSAGE_TOO_LONG); + } +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + else if (sessionHandle->AllowsLargePayload()) + { + VerifyOrReturnError(message->TotalLength() <= kMaxLargeAppMessageLen, CHIP_ERROR_MESSAGE_TOO_LONG); + } +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + #if CHIP_PROGRESS_LOGGING NodeId destination; FabricIndex fabricIndex; diff --git a/src/transport/raw/MessageHeader.h b/src/transport/raw/MessageHeader.h index ef4f86d3993793..4bc292de9e662e 100644 --- a/src/transport/raw/MessageHeader.h +++ b/src/transport/raw/MessageHeader.h @@ -60,7 +60,6 @@ static constexpr size_t kMaxPacketBufferApplicationPayloadAndMICSizeBytes = Syst static constexpr size_t kMaxApplicationPayloadAndMICSizeBytes = min(kMaxPerSpecApplicationPayloadAndMICSizeBytes, kMaxPacketBufferApplicationPayloadAndMICSizeBytes); - } // namespace detail static constexpr size_t kMaxTagLen = 16; @@ -74,6 +73,18 @@ static constexpr size_t kMaxAppMessageLen = detail::kMaxApplicationPayloadAndMIC static constexpr uint16_t kMsgUnicastSessionIdUnsecured = 0x0000; +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +// Minimum header size of TCP + IPv6 without options. +static constexpr size_t kMaxTCPAndIPHeaderSizeBytes = 60; + +// Max space for the Application Payload and MIC for large packet buffers +// This is the size _excluding_ the header reserve. +static constexpr size_t kMaxLargeApplicationPayloadAndMICSizeBytes = + System::PacketBuffer::kLargeBufMaxSize - kMaxTCPAndIPHeaderSizeBytes; + +static constexpr size_t kMaxLargeAppMessageLen = kMaxLargeApplicationPayloadAndMICSizeBytes - kMaxTagLen; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + typedef int PacketHeaderFlags; namespace Header { diff --git a/src/transport/raw/TCP.cpp b/src/transport/raw/TCP.cpp index e33590a63a6fdf..9ffc85b7078330 100644 --- a/src/transport/raw/TCP.cpp +++ b/src/transport/raw/TCP.cpp @@ -39,11 +39,11 @@ namespace { using namespace chip::Encoding; -// Packets start with a 16-bit size -constexpr size_t kPacketSizeBytes = 2; +// Packets start with a 32-bit size field. +constexpr size_t kPacketSizeBytes = sizeof(uint32_t); -// TODO: Actual limit may be lower (spec issue #2119) -constexpr uint16_t kMaxMessageSize = static_cast(System::PacketBuffer::kMaxSizeWithoutReserve - kPacketSizeBytes); +constexpr uint32_t kMaxTCPMessageSize = + static_cast(System::PacketBuffer::kLargeBufMaxSizeWithoutReserve - kPacketSizeBytes); constexpr int kListenBacklogSize = 2; @@ -197,12 +197,12 @@ ActiveTCPConnectionState * TCPBase::FindInUseConnection(const Inet::TCPEndPoint CHIP_ERROR TCPBase::SendMessage(const Transport::PeerAddress & address, System::PacketBufferHandle && msgBuf) { // Sent buffer data format is: - // - packet size as a uint16_t + // - packet size as a uint32_t // - actual data VerifyOrReturnError(address.GetTransportType() == Type::kTcp, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(mState == TCPState::kInitialized, CHIP_ERROR_INCORRECT_STATE); - VerifyOrReturnError(kPacketSizeBytes + msgBuf->DataLength() <= std::numeric_limits::max(), + VerifyOrReturnError(kPacketSizeBytes + msgBuf->DataLength() <= System::PacketBuffer::kLargeBufMaxSizeWithoutReserve, CHIP_ERROR_INVALID_ARGUMENT); // The check above about kPacketSizeBytes + msgBuf->DataLength() means it definitely fits in uint16_t. @@ -211,7 +211,7 @@ CHIP_ERROR TCPBase::SendMessage(const Transport::PeerAddress & address, System:: msgBuf->SetStart(msgBuf->Start() - kPacketSizeBytes); uint8_t * output = msgBuf->Start(); - LittleEndian::Write16(output, static_cast(msgBuf->DataLength() - kPacketSizeBytes)); + LittleEndian::Write32(output, static_cast(msgBuf->DataLength() - kPacketSizeBytes)); // Reuse existing connection if one exists, otherwise a new one // will be established @@ -324,11 +324,11 @@ CHIP_ERROR TCPBase::ProcessReceivedBuffer(Inet::TCPEndPoint * endPoint, const Pe { return err; } - uint16_t messageSize = LittleEndian::Get16(messageSizeBuf); - if (messageSize >= kMaxMessageSize) + uint32_t messageSize = LittleEndian::Get32(messageSizeBuf); + if (messageSize >= kMaxTCPMessageSize) { - - // This message is too long for upper layers. + // Message is too big for node to process. Disconnect with peer. + CloseConnectionInternal(state, CHIP_ERROR_MESSAGE_TOO_LONG, SuppressCallback::No); return CHIP_ERROR_MESSAGE_TOO_LONG; } // The subtraction will not underflow because we successfully read kPacketSizeBytes. @@ -344,7 +344,7 @@ CHIP_ERROR TCPBase::ProcessReceivedBuffer(Inet::TCPEndPoint * endPoint, const Pe return CHIP_NO_ERROR; } -CHIP_ERROR TCPBase::ProcessSingleMessage(const PeerAddress & peerAddress, ActiveTCPConnectionState * state, uint16_t messageSize) +CHIP_ERROR TCPBase::ProcessSingleMessage(const PeerAddress & peerAddress, ActiveTCPConnectionState * state, size_t messageSize) { // We enter with `state->mReceived` containing at least one full message, perhaps in a chain. // `state->mReceived->Start()` currently points to the message data. diff --git a/src/transport/raw/TCP.h b/src/transport/raw/TCP.h index 783f3844d2d16d..d6398616c03cb5 100644 --- a/src/transport/raw/TCP.h +++ b/src/transport/raw/TCP.h @@ -258,7 +258,7 @@ class DLL_EXPORT TCPBase : public Base * is no other data). * @param[in] messageSize Size of the single message. */ - CHIP_ERROR ProcessSingleMessage(const PeerAddress & peerAddress, ActiveTCPConnectionState * state, uint16_t messageSize); + CHIP_ERROR ProcessSingleMessage(const PeerAddress & peerAddress, ActiveTCPConnectionState * state, size_t messageSize); /** * Initiate a connection to the given peer. On connection completion, @@ -308,7 +308,7 @@ class DLL_EXPORT TCPBase : public Base // The max payload size of data over a TCP connection that is transmissible // at a time. - uint32_t mMaxTCPPayloadSize = CHIP_CONFIG_MAX_TCP_PAYLOAD_SIZE_BYTES; + uint32_t mMaxTCPSendAllocSize = System::PacketBuffer::kMaxAllocSize; // Number of active and 'pending connection' endpoints size_t mUsedEndPointCount = 0; diff --git a/src/transport/raw/TCPConfig.h b/src/transport/raw/TCPConfig.h index d54a9466b4d294..4f95978985fd63 100644 --- a/src/transport/raw/TCPConfig.h +++ b/src/transport/raw/TCPConfig.h @@ -63,15 +63,6 @@ namespace chip { #define CHIP_CONFIG_MAX_TCP_PENDING_PACKETS 4 #endif -/** - * @def CHIP_CONFIG_MAX_TCP_PAYLOAD_SIZE_BYTES - * - * @brief Maximum payload size of a message over a TCP connection - */ -#ifndef CHIP_CONFIG_MAX_TCP_PAYLOAD_SIZE_BYTES -#define CHIP_CONFIG_MAX_TCP_PAYLOAD_SIZE_BYTES 1000000 -#endif - /** * @def CHIP_CONFIG_TCP_CONNECT_TIMEOUT_MSECS * diff --git a/src/transport/raw/tests/TestTCP.cpp b/src/transport/raw/tests/TestTCP.cpp index f5e343f1a2ea79..b8794174621b86 100644 --- a/src/transport/raw/tests/TestTCP.cpp +++ b/src/transport/raw/tests/TestTCP.cpp @@ -51,7 +51,7 @@ namespace { constexpr size_t kMaxTcpActiveConnectionCount = 4; constexpr size_t kMaxTcpPendingPackets = 4; -constexpr uint16_t kPacketSizeBytes = static_cast(sizeof(uint16_t)); +constexpr size_t kPacketSizeBytes = sizeof(uint32_t); uint16_t gChipTCPPort = static_cast(CHIP_PORT + chip::Crypto::GetRandU16() % 100); chip::Transport::AppTCPConnectionCallbackCtxt gAppTCPConnCbCtxt; chip::Transport::ActiveTCPConnectionState * gActiveTCPConnState = nullptr; @@ -298,7 +298,7 @@ struct TestData // the last buffer will be made larger. TestData() : mPayload(nullptr), mTotalLength(0), mMessageLength(0), mMessageOffset(0) {} ~TestData() { Free(); } - bool Init(const uint16_t sizes[]); + bool Init(const uint32_t sizes[]); void Free(); bool IsValid() { return !mHandle.IsNull() && (mPayload != nullptr); } @@ -309,7 +309,7 @@ struct TestData size_t mMessageOffset; }; -bool TestData::Init(const uint16_t sizes[]) +bool TestData::Init(const uint32_t sizes[]) { Free(); @@ -325,17 +325,17 @@ bool TestData::Init(const uint16_t sizes[]) mTotalLength += sizes[bufferCount]; } --bufferCount; - uint16_t additionalLength = 0; + uint32_t additionalLength = 0; if (headerLength + kPacketSizeBytes > mTotalLength) { - additionalLength = static_cast((headerLength + kPacketSizeBytes) - mTotalLength); + additionalLength = static_cast((headerLength + kPacketSizeBytes) - mTotalLength); mTotalLength += additionalLength; } - if (mTotalLength > UINT16_MAX) + if (mTotalLength > UINT32_MAX) { return false; } - uint16_t messageLength = static_cast(mTotalLength - kPacketSizeBytes); + uint32_t messageLength = static_cast(mTotalLength - kPacketSizeBytes); // Build the test payload. uint8_t * payload = static_cast(chip::Platform::MemoryCalloc(1, mTotalLength)); @@ -343,7 +343,7 @@ bool TestData::Init(const uint16_t sizes[]) { return false; } - chip::Encoding::LittleEndian::Put16(payload, messageLength); + chip::Encoding::LittleEndian::Put32(payload, messageLength); uint16_t headerSize; CHIP_ERROR err = header.Encode(payload + kPacketSizeBytes, messageLength, &headerSize); if (err != CHIP_NO_ERROR) @@ -363,10 +363,10 @@ bool TestData::Init(const uint16_t sizes[]) System::PacketBufferHandle head = chip::System::PacketBufferHandle::New(sizes[0], 0 /* reserve */); for (int i = 1; i <= bufferCount; ++i) { - uint16_t size = sizes[i]; + size_t size = sizes[i]; if (i == bufferCount) { - size = static_cast(size + additionalLength); + size = size + additionalLength; } chip::System::PacketBufferHandle buffer = chip::System::PacketBufferHandle::New(size, 0 /* reserve */); if (buffer.IsNull()) @@ -395,7 +395,7 @@ bool TestData::Init(const uint16_t sizes[]) if (lToWriteToCurrentBuf != 0) { memcpy(iterator->Start(), writePayload, lToWriteToCurrentBuf); - iterator->SetDataLength(static_cast(iterator->DataLength() + lToWriteToCurrentBuf), head); + iterator->SetDataLength(iterator->DataLength() + lToWriteToCurrentBuf, head); writePayload += lToWriteToCurrentBuf; writeLength -= lToWriteToCurrentBuf; } @@ -634,22 +634,22 @@ TEST_F(TestTCP, CheckProcessReceivedBuffer) // Test a single packet buffer. gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; - EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 111, 0 })); + EXPECT_TRUE(testData[0].Init((const uint32_t[]){ 111, 0 })); err = TestAccess::ProcessReceivedBuffer(tcp, lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 1); // Test a message in a chain of three packet buffers. The message length is split across buffers. gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; - EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 1, 122, 123, 0 })); + EXPECT_TRUE(testData[0].Init((const uint32_t[]){ 1, 122, 123, 0 })); err = TestAccess::ProcessReceivedBuffer(tcp, lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 1); // Test two messages in a chain. gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; - EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 131, 0 })); - EXPECT_TRUE(testData[1].Init((const uint16_t[]){ 132, 0 })); + EXPECT_TRUE(testData[0].Init((const uint32_t[]){ 131, 0 })); + EXPECT_TRUE(testData[1].Init((const uint32_t[]){ 132, 0 })); testData[0].mHandle->AddToEnd(std::move(testData[1].mHandle)); err = TestAccess::ProcessReceivedBuffer(tcp, lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); EXPECT_EQ(err, CHIP_NO_ERROR); @@ -657,24 +657,32 @@ TEST_F(TestTCP, CheckProcessReceivedBuffer) // Test a chain of two messages, each a chain. gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; - EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 141, 142, 0 })); - EXPECT_TRUE(testData[1].Init((const uint16_t[]){ 143, 144, 0 })); + EXPECT_TRUE(testData[0].Init((const uint32_t[]){ 141, 142, 0 })); + EXPECT_TRUE(testData[1].Init((const uint32_t[]){ 143, 144, 0 })); testData[0].mHandle->AddToEnd(std::move(testData[1].mHandle)); err = TestAccess::ProcessReceivedBuffer(tcp, lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 2); + // Test a single packet buffer that is larger than + // kMaxSizeWithoutReserve but less than CHIP_CONFIG_MAX_LARGE_PAYLOAD_SIZE_BYTES. + gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; + EXPECT_TRUE(testData[0].Init((const uint32_t[]){ System::PacketBuffer::kMaxSizeWithoutReserve + 1, 0 })); + err = TestAccess::ProcessReceivedBuffer(tcp, lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); + EXPECT_EQ(err, CHIP_NO_ERROR); + EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 1); + // Test a message that is too large to coalesce into a single packet buffer. gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; gMockTransportMgrDelegate.SetCallback(TestDataCallbackCheck, &testData[1]); - EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 51, System::PacketBuffer::kMaxSizeWithoutReserve, 0 })); + EXPECT_TRUE(testData[0].Init((const uint32_t[]){ 51, CHIP_SYSTEM_CONFIG_MAX_LARGE_BUFFER_SIZE_BYTES, 0 })); // Sending only the first buffer of the long chain. This should be enough to trigger the error. System::PacketBufferHandle head = testData[0].mHandle.PopHead(); err = TestAccess::ProcessReceivedBuffer(tcp, lEndPoint, lPeerAddress, std::move(head)); EXPECT_EQ(err, CHIP_ERROR_MESSAGE_TOO_LONG); - EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 0); - - gMockTransportMgrDelegate.DisconnectTest(tcp, addr); + // The receipt of a message exceeding the allowed size should have + // closed the connection. + EXPECT_EQ(TestAccess::GetEndpoint(state), nullptr); } } // namespace