diff --git a/Android.mk b/Android.mk index 049a12636..4cb16c6f6 100644 --- a/Android.mk +++ b/Android.mk @@ -212,6 +212,7 @@ LOCAL_SRC_FILES := \ src/core/api/srp_server_api.cpp \ src/core/api/tasklet_api.cpp \ src/core/api/tcp_api.cpp \ + src/core/api/tcp_ext_api.cpp \ src/core/api/thread_api.cpp \ src/core/api/thread_ftd_api.cpp \ src/core/api/trel_api.cpp \ @@ -315,6 +316,7 @@ LOCAL_SRC_FILES := \ src/core/net/srp_client.cpp \ src/core/net/srp_server.cpp \ src/core/net/tcp6.cpp \ + src/core/net/tcp6_ext.cpp \ src/core/net/udp6.cpp \ src/core/radio/radio.cpp \ src/core/radio/radio_callbacks.cpp \ diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 2846d8cb0..5253d69b8 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (244) +#define OPENTHREAD_API_VERSION (245) /** * @addtogroup api-instance diff --git a/include/openthread/tcp_ext.h b/include/openthread/tcp_ext.h index 5c0ddc678..75808abe0 100644 --- a/include/openthread/tcp_ext.h +++ b/include/openthread/tcp_ext.h @@ -88,10 +88,10 @@ extern "C" { */ typedef struct otTcpCircularSendBuffer { - const uint8_t *mDataBuffer; ///< Pointer to data in the circular send buffer - size_t mCapacity; ///< Length of the circular send buffer - size_t mStartIndex; ///< Index of the first valid byte in the send buffer - size_t mCapacityUsed; ///< Number of bytes stored in the send buffer + uint8_t *mDataBuffer; ///< Pointer to data in the circular send buffer + size_t mCapacity; ///< Length of the circular send buffer + size_t mStartIndex; ///< Index of the first valid byte in the send buffer + size_t mCapacityUsed; ///< Number of bytes stored in the send buffer otLinkedBuffer mSendLinks[2]; uint8_t mFirstSendLinkIndex; @@ -107,6 +107,15 @@ typedef struct otTcpCircularSendBuffer */ void otTcpCircularSendBufferInitialize(otTcpCircularSendBuffer *aSendBuffer, void *aDataBuffer, size_t aCapacity); +/** + * This enumeration defines flags passed to @p otTcpCircularSendBufferWrite. + * + */ +enum +{ + OT_TCP_CIRCULAR_SEND_BUFFER_WRITE_MORE_TO_COME = 1 << 0, +}; + /** * Sends out data on a TCP endpoint, using the provided TCP circular send * buffer to manage buffering. @@ -136,15 +145,17 @@ void otTcpCircularSendBufferInitialize(otTcpCircularSendBuffer *aSendBuffer, voi * @param[in] aLength The length of the data pointed to by @p aData to copy into the TCP circular send buffer. * @param[out] aWritten Populated with the amount of data copied into the send buffer, which might be less than * @p aLength if the send buffer reaches capacity. + * @param[in] aFlags Flags specifying options for this operation (see enumeration above). * * @returns OT_ERROR_NONE Successfully copied data into the send buffer and sent it on the TCP endpoint. * @returns OT_ERROR_FAILED Failed to send out data on the TCP endpoint. */ otError otTcpCircularSendBufferWrite(otTcpEndpoint * aEndpoint, otTcpCircularSendBuffer *aSendBuffer, - void * aData, + const void * aData, size_t aLength, - size_t * aWritten); + size_t * aWritten, + uint32_t aFlags); /** * Performs circular-send-buffer-specific handling in the otTcpForwardProgress @@ -175,7 +186,7 @@ void otTcpCircularSendBufferHandleForwardProgress(otTcpCircularSendBuffer *aSend * * @return The amount of free space in the send buffer. */ -size_t otTcpCircularSendBufferFreeSpace(otTcpCircularSendBuffer *aSendBuffer); +size_t otTcpCircularSendBufferGetFreeSpace(const otTcpCircularSendBuffer *aSendBuffer); /** * Forcibly discards all data in the circular send buffer. diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index 9a70976b0..c625335a1 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -351,6 +351,7 @@ openthread_core_files = [ "api/srp_server_api.cpp", "api/tasklet_api.cpp", "api/tcp_api.cpp", + "api/tcp_ext_api.cpp", "api/thread_api.cpp", "api/thread_ftd_api.cpp", "api/trel_api.cpp", @@ -583,6 +584,8 @@ openthread_core_files = [ "net/srp_server.hpp", "net/tcp6.cpp", "net/tcp6.hpp", + "net/tcp6_ext.cpp", + "net/tcp6_ext.hpp", "net/udp6.cpp", "net/udp6.hpp", "radio/max_power_table.hpp", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index bd1060335..230783357 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -78,6 +78,7 @@ set(COMMON_SOURCES api/srp_server_api.cpp api/tasklet_api.cpp api/tcp_api.cpp + api/tcp_ext_api.cpp api/thread_api.cpp api/thread_ftd_api.cpp api/trel_api.cpp @@ -181,6 +182,7 @@ set(COMMON_SOURCES net/srp_client.cpp net/srp_server.cpp net/tcp6.cpp + net/tcp6_ext.cpp net/udp6.cpp radio/radio.cpp radio/radio_callbacks.cpp diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 24a5e081d..309a82975 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -168,6 +168,7 @@ SOURCES_COMMON = \ api/srp_server_api.cpp \ api/tasklet_api.cpp \ api/tcp_api.cpp \ + api/tcp_ext_api.cpp \ api/thread_api.cpp \ api/thread_ftd_api.cpp \ api/trel_api.cpp \ @@ -271,6 +272,7 @@ SOURCES_COMMON = \ net/srp_client.cpp \ net/srp_server.cpp \ net/tcp6.cpp \ + net/tcp6_ext.cpp \ net/udp6.cpp \ radio/radio.cpp \ radio/radio_callbacks.cpp \ @@ -584,6 +586,7 @@ HEADERS_COMMON = \ net/srp_client.hpp \ net/srp_server.hpp \ net/tcp6.hpp \ + net/tcp6_ext.hpp \ net/udp6.hpp \ openthread-core-config.h \ radio/max_power_table.hpp \ diff --git a/src/core/api/tcp_ext_api.cpp b/src/core/api/tcp_ext_api.cpp new file mode 100644 index 000000000..2e98b7f39 --- /dev/null +++ b/src/core/api/tcp_ext_api.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2022, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements extensions to the OpenThread TCP API. + */ + +#include "openthread-core-config.h" + +#if OPENTHREAD_CONFIG_TCP_ENABLE + +#include + +#include "common/as_core_type.hpp" +#include "common/locator_getters.hpp" +#include "net/tcp6_ext.hpp" + +using namespace ot; + +void otTcpCircularSendBufferInitialize(otTcpCircularSendBuffer *aSendBuffer, void *aDataBuffer, size_t aCapacity) +{ + AsCoreType(aSendBuffer).Initialize(aDataBuffer, aCapacity); +} + +otError otTcpCircularSendBufferWrite(otTcpEndpoint * aEndpoint, + otTcpCircularSendBuffer *aSendBuffer, + const void * aData, + size_t aLength, + size_t * aWritten, + uint32_t aFlags) +{ + AssertPointerIsNotNull(aWritten); + return AsCoreType(aSendBuffer).Write(AsCoreType(aEndpoint), aData, aLength, *aWritten, aFlags); +} + +void otTcpCircularSendBufferHandleForwardProgress(otTcpCircularSendBuffer *aSendBuffer, size_t aInSendBuffer) +{ + AsCoreType(aSendBuffer).HandleForwardProgress(aInSendBuffer); +} + +size_t otTcpCircularSendBufferGetFreeSpace(const otTcpCircularSendBuffer *aSendBuffer) +{ + return AsCoreType(aSendBuffer).GetFreeSpace(); +} + +void otTcpCircularSendBufferForceDiscardAll(otTcpCircularSendBuffer *aSendBuffer) +{ + AsCoreType(aSendBuffer).ForceDiscardAll(); +} + +otError otTcpCircularSendBufferDeinitialize(otTcpCircularSendBuffer *aSendBuffer) +{ + return AsCoreType(aSendBuffer).Deinitialize(); +} + +#endif // OPENTHREAD_CONFIG_TCP_ENABLE diff --git a/src/core/net/tcp6_ext.cpp b/src/core/net/tcp6_ext.cpp new file mode 100644 index 000000000..c789d45b4 --- /dev/null +++ b/src/core/net/tcp6_ext.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2022, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements TCP/IPv6 socket extensions. + */ + +#include "openthread-core-config.h" + +#if OPENTHREAD_CONFIG_TCP_ENABLE + +#include "tcp6_ext.hpp" + +#include "common/code_utils.hpp" +#include "common/error.hpp" +#include "common/locator_getters.hpp" +#include "common/log.hpp" + +namespace ot { +namespace Ip6 { + +RegisterLogModule("TcpExt"); + +void TcpCircularSendBuffer::Initialize(void *aDataBuffer, size_t aCapacity) +{ + mDataBuffer = static_cast(aDataBuffer); + mCapacity = aCapacity; + ForceDiscardAll(); +} + +Error TcpCircularSendBuffer::Write(Tcp::Endpoint &aEndpoint, + const void * aData, + size_t aLength, + size_t & aWritten, + uint32_t aFlags) +{ + Error error = kErrorNone; + size_t bytesFree = GetFreeSpace(); + size_t writeIndex; + uint32_t flags = 0; + size_t bytesUntilWrap; + + /* + * Handle the case where we don't have enough space to accommodate all of the + * provided data. + */ + aLength = Min(aLength, bytesFree); + VerifyOrExit(aLength != 0); + + /* + * This is a "simplifying" if statement the removes an edge case from the logic + * below. It guarantees that a write to an empty buffer will never wrap. + */ + if (mCapacityUsed == 0) + { + mStartIndex = 0; + } + + writeIndex = GetIndex(mStartIndex, mCapacityUsed); + + if ((aFlags & OT_TCP_CIRCULAR_SEND_BUFFER_WRITE_MORE_TO_COME) != 0 && aLength < bytesFree) + { + flags |= OT_TCP_SEND_MORE_TO_COME; + } + + bytesUntilWrap = mCapacity - writeIndex; + if (aLength <= bytesUntilWrap) + { + memcpy(&mDataBuffer[writeIndex], aData, aLength); + if (writeIndex == 0) + { + /* + * mCapacityUsed == 0 corresponds to the case where we're writing + * to an empty buffer. mCapacityUsed != 0 && writeIndex == 0 + * corresponds to the case where the buffer is not empty and this is + * writing the first bytes that wrap. + */ + uint8_t linkIndex; + if (mCapacityUsed == 0) + { + linkIndex = mFirstSendLinkIndex; + } + else + { + linkIndex = 1 - mFirstSendLinkIndex; + } + { + otLinkedBuffer &dataSendLink = mSendLinks[linkIndex]; + + dataSendLink.mNext = nullptr; + dataSendLink.mData = &mDataBuffer[writeIndex]; + dataSendLink.mLength = aLength; + + LogDebg("Appending link %u (points to index %u, length %u)", static_cast(linkIndex), + static_cast(writeIndex), static_cast(aLength)); + error = aEndpoint.SendByReference(dataSendLink, flags); + } + } + else + { + LogDebg("Extending tail link by length %u", static_cast(aLength)); + error = aEndpoint.SendByExtension(aLength, flags); + } + VerifyOrExit(error == kErrorNone, aLength = 0); + } + else + { + const uint8_t *dataIndexable = static_cast(aData); + size_t bytesWrapped = aLength - bytesUntilWrap; + + memcpy(&mDataBuffer[writeIndex], &dataIndexable[0], bytesUntilWrap); + memcpy(&mDataBuffer[0], &dataIndexable[bytesUntilWrap], bytesWrapped); + + /* + * Because of the "simplifying" if statement at the top, we don't + * have to worry about starting from an empty buffer in this case. + */ + LogDebg("Extending tail link by length %u (wrapping)", static_cast(bytesUntilWrap)); + error = aEndpoint.SendByExtension(bytesUntilWrap, flags | OT_TCP_SEND_MORE_TO_COME); + VerifyOrExit(error == kErrorNone, aLength = 0); + + { + otLinkedBuffer &wrappedDataSendLink = mSendLinks[1 - mFirstSendLinkIndex]; + + wrappedDataSendLink.mNext = nullptr; + wrappedDataSendLink.mData = &mDataBuffer[0]; + wrappedDataSendLink.mLength = bytesWrapped; + + LogDebg("Appending link %u (wrapping)", static_cast(1 - mFirstSendLinkIndex)); + error = aEndpoint.SendByReference(wrappedDataSendLink, flags); + VerifyOrExit(error == kErrorNone, aLength = bytesUntilWrap); + } + } + +exit: + mCapacityUsed += aLength; + aWritten = aLength; + return error; +} + +void TcpCircularSendBuffer::HandleForwardProgress(size_t aInSendBuffer) +{ + size_t bytesRemoved; + size_t bytesUntilWrap; + + OT_ASSERT(aInSendBuffer <= mCapacityUsed); + LogDebg("Forward progress: %u bytes in send buffer\n", aInSendBuffer); + bytesRemoved = mCapacityUsed - aInSendBuffer; + bytesUntilWrap = mCapacity - mStartIndex; + + if (bytesRemoved < bytesUntilWrap) + { + mStartIndex += bytesRemoved; + } + else + { + mStartIndex = bytesRemoved - bytesUntilWrap; + /* The otLinkedBuffer for the pre-wrap data is now empty. */ + LogDebg("Pre-wrap linked buffer now empty: switching first link index from %u to %u\n", + static_cast(mFirstSendLinkIndex), static_cast(1 - mFirstSendLinkIndex)); + mFirstSendLinkIndex = 1 - mFirstSendLinkIndex; + } + mCapacityUsed = aInSendBuffer; +} + +size_t TcpCircularSendBuffer::GetFreeSpace(void) const +{ + return mCapacity - mCapacityUsed; +} + +void TcpCircularSendBuffer::ForceDiscardAll(void) +{ + mStartIndex = 0; + mCapacityUsed = 0; + mFirstSendLinkIndex = 0; +} + +Error TcpCircularSendBuffer::Deinitialize(void) +{ + return (mCapacityUsed != 0) ? kErrorBusy : kErrorNone; +} + +size_t TcpCircularSendBuffer::GetIndex(size_t aStart, size_t aOffsetFromStart) const +{ + size_t bytesUntilWrap; + size_t index; + + OT_ASSERT(aStart < mCapacity); + bytesUntilWrap = mCapacity - aStart; + if (aOffsetFromStart < bytesUntilWrap) + { + index = aStart + aOffsetFromStart; + } + else + { + index = aOffsetFromStart - bytesUntilWrap; + } + + return index; +} + +} // namespace Ip6 +} // namespace ot + +#endif // OPENTHREAD_CONFIG_TCP_ENABLE diff --git a/src/core/net/tcp6_ext.hpp b/src/core/net/tcp6_ext.hpp new file mode 100644 index 000000000..b40663aed --- /dev/null +++ b/src/core/net/tcp6_ext.hpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2022, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes definitions for TCP/IPv6 socket extensions. + */ + +#ifndef TCP6_EXT_HPP_ +#define TCP6_EXT_HPP_ + +#include "openthread-core-config.h" + +#include + +#include "net/tcp6.hpp" + +namespace ot { +namespace Ip6 { + +/** + * @addtogroup core-tcp-ext + * + * @brief + * This module includes definitions for TCP/IPv6 socket extensions. + * + * @{ + * + */ + +/** + * This class represents a TCP circular send buffer. + * + */ +class TcpCircularSendBuffer : public otTcpCircularSendBuffer +{ +public: + /** + * Initializes a TCP circular send buffer. + * + * @sa otTcpCircularSendBufferInitialize + * + * @param[in] aDataBuffer A pointer to memory to use to store data in the TCP circular send buffer. + * @param[in] aCapacity The capacity, in bytes, of the TCP circular send buffer, which must equal the size + * of the memory pointed to by @p aDataBuffer . + */ + void Initialize(void *aDataBuffer, size_t aCapacity); + + /** + * Sends out data on a TCP endpoint, using this TCP circular send buffer to manage buffering. + * + * @sa otTcpCircularSendBufferWrite, particularly for guidance on how @p aEndpoint must be chosen. + * + * @param[in] aEndpoint The TCP endpoint on which to send out data. + * @param[in] aData A pointer to data to copy into the TCP circular send buffer. + * @param[in] aLength The length of the data pointed to by @p aData to copy into the TCP circular send buffer. + * @param[out] aWritten Populated with the amount of data copied into the send buffer, which might be less than + * @p aLength if the send buffer reaches capacity. + * @param[in] aFlags Flags specifying options for this operation. + * + * @retval kErrorNone on success, or the error returned by the TCP endpoint on failure. + */ + Error Write(Tcp::Endpoint &aEndpoint, const void *aData, size_t aLength, size_t &aWritten, uint32_t aFlags); + + /** + * Performs circular-send-buffer-specific handling in the otTcpForwardProgress callback. + * + * @sa otTcpCircularSendBufferHandleForwardProgress + * + * @param[in] aInSendBuffer Value of @p aInSendBuffer passed to the otTcpForwardProgress() callback. + */ + void HandleForwardProgress(size_t aInSendBuffer); + + /** + * Returns the amount of free space in this TCP circular send buffer. + * + * @sa otTcpCircularSendBufferFreeSpace + * + * @return The amount of free space in the send buffer. + */ + size_t GetFreeSpace(void) const; + + /** + * Forcibly discards all data in this TCP circular send buffer. + * + * @sa otTcpCircularSendBufferForceDiscardAll + * + */ + void ForceDiscardAll(void); + + /** + * Deinitializes this TCP circular send buffer. + * + * @sa otTcpCircularSendBufferDeinitialize + * + * @retval kErrorNone Successfully deinitialized this TCP circular send buffer. + * @retval kErrorFailed Failed to deinitialize the TCP circular send buffer. + */ + Error Deinitialize(void); + +private: + size_t GetIndex(size_t aStart, size_t aOffsetFromStart) const; +}; + +} // namespace Ip6 + +DefineCoreType(otTcpCircularSendBuffer, Ip6::TcpCircularSendBuffer); + +} // namespace ot + +#endif // TCP6_HPP_ diff --git a/third_party/tcplp/lib/lbuf.c b/third_party/tcplp/lib/lbuf.c index 91dd4561b..ba39c5d1c 100644 --- a/third_party/tcplp/lib/lbuf.c +++ b/third_party/tcplp/lib/lbuf.c @@ -55,6 +55,7 @@ void lbuf_append(struct lbufhead* buffer, otLinkedBuffer* newentry) { void lbuf_extend(struct lbufhead* buffer, size_t numbytes) { buffer->tail->mLength += numbytes; + buffer->length += numbytes; } size_t lbuf_pop(struct lbufhead* buffer, size_t numbytes, uint32_t* ntraversed) {