[tcp] add rewrite of TCPlp's interface code to support OpenThread's TCP API (#7190)

This commit is contained in:
Sam Kumar
2021-11-20 18:06:50 -08:00
committed by Jonathan Hui
parent a7b6eac41d
commit 876aa82164
11 changed files with 1003 additions and 171 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (187)
#define OPENTHREAD_API_VERSION (188)
/**
* @addtogroup api-instance
+39 -10
View File
@@ -191,6 +191,16 @@ typedef enum otTcpDisconnectedReason
*/
typedef void (*otTcpDisconnected)(otTcpEndpoint *aEndpoint, otTcpDisconnectedReason aReason);
/**
* OT_TCP_ENDPOINT_TCB_SIZE_BASE and OT_TCP_ENDPOINT_TCB_NUM_POINTERS are
* chosen such that the mTcb field of otTcpEndpoint has the same size as
* struct tcpcb in TCPlp. This is necessary because the mTcb field, although
* opaque in its declaration, is treated as struct tcpcb in the TCP
* implementation.
*/
#define OT_TCP_ENDPOINT_TCB_SIZE_BASE 368
#define OT_TCP_ENDPOINT_TCB_NUM_PTR 36
/**
* This structure represents a TCP endpoint.
*
@@ -205,9 +215,14 @@ typedef void (*otTcpDisconnected)(otTcpEndpoint *aEndpoint, otTcpDisconnectedRea
*/
struct otTcpEndpoint
{
struct otTcpEndpoint *mNext; ///< A pointer to the next TCP endpoint (internal use only)
otInstance * mInstance; ///< A pointer to the OpenThread instance associated with this TCP endpoint
void * mContext; ///< A pointer to application-specific context
union
{
uint8_t mSize[OT_TCP_ENDPOINT_TCB_SIZE_BASE + OT_TCP_ENDPOINT_TCB_NUM_PTR * sizeof(void *)];
uint64_t mAlign;
} mTcb;
struct otTcpEndpoint *mNext; ///< A pointer to the next TCP endpoint (internal use only)
void * mContext; ///< A pointer to application-specific context
otTcpEstablished mEstablishedCallback; ///< "Established" callback function
otTcpSendDone mSendDoneCallback; ///< "Send done" callback function
@@ -217,7 +232,8 @@ struct otTcpEndpoint
uint32_t mTimers[4];
/* Other implementation-defined fields go here. */
otLinkedBuffer mReceiveLinks[2];
otSockAddr mSockAddr;
};
/**
@@ -438,7 +454,7 @@ otError otTcpSendByExtension(otTcpEndpoint *aEndpoint, size_t aNumBytes, uint32_
* @retval OT_ERROR_FAILED Failed to complete the operation.
*
*/
otError otTcpReceiveByReference(const otTcpEndpoint *aEndpoint, const otLinkedBuffer **aBuffer);
otError otTcpReceiveByReference(otTcpEndpoint *aEndpoint, const otLinkedBuffer **aBuffer);
/**
* Reorganizes the receive buffer to be entirely contiguous in memory.
@@ -598,6 +614,16 @@ typedef otTcpIncomingConnectionAction (*otTcpAcceptReady)(otTcpListener * aLis
*/
typedef void (*otTcpAcceptDone)(otTcpListener *aListener, otTcpEndpoint *aEndpoint, const otSockAddr *aPeer);
/**
* OT_TCP_LISTENER_TCB_SIZE_BASE and OT_TCP_LISTENER_TCB_NUM_POINTERS are
* chosen such that the mTcbListener field of otTcpListener has the same size
* as struct tcpcb_listen in TCPlp. This is necessary because the mTcbListen
* field, though opaque in its declaration, is treated as struct tcpcb in the
* TCP implementation.
*/
#define OT_TCP_LISTENER_TCB_SIZE_BASE 16
#define OT_TCP_LISTENER_TCB_NUM_PTR 3
/**
* This structure represents a TCP listener.
*
@@ -610,14 +636,17 @@ typedef void (*otTcpAcceptDone)(otTcpListener *aListener, otTcpEndpoint *aEndpoi
*/
struct otTcpListener
{
struct otTcpListener *mNext; ///< A pointer to the next TCP listener (internal use only)
otInstance * mInstance; ///< A pointer to the OpenThread instance associated with this TCP listener
void * mContext; ///< A pointer to application-specific context
union
{
uint8_t mSize[OT_TCP_LISTENER_TCB_SIZE_BASE + OT_TCP_LISTENER_TCB_NUM_PTR * sizeof(void *)];
void * mAlign;
} mTcbListen;
struct otTcpListener *mNext; ///< A pointer to the next TCP listener (internal use only)
void * mContext; ///< A pointer to application-specific context
otTcpAcceptReady mAcceptReadyCallback; ///< "Accept ready" callback function
otTcpAcceptDone mAcceptDoneCallback; ///< "Accept done" callback function
/* Other implementation-defined fields go here. */
};
/**
+1 -1
View File
@@ -87,7 +87,7 @@ otError otTcpSendByExtension(otTcpEndpoint *aEndpoint, size_t aNumBytes, uint32_
return AsCoreType(aEndpoint).SendByExtension(aNumBytes, aFlags);
}
otError otTcpReceiveByReference(const otTcpEndpoint *aEndpoint, const otLinkedBuffer **aBuffer)
otError otTcpReceiveByReference(otTcpEndpoint *aEndpoint, const otLinkedBuffer **aBuffer)
{
return AsCoreType(aEndpoint).ReceiveByReference(*aBuffer);
}
+671 -47
View File
@@ -42,11 +42,19 @@
#include "common/error.hpp"
#include "common/instance.hpp"
#include "common/logging.hpp"
#include "common/random.hpp"
#include "net/checksum.hpp"
#include "net/ip6.hpp"
#include "net/netif.hpp"
#include "../../third_party/tcplp/tcplp.h"
namespace ot {
namespace Ip6 {
using ot::Encoding::BigEndian::HostSwap16;
using ot::Encoding::BigEndian::HostSwap32;
Tcp::Tcp(Instance &aInstance)
: InstanceLocator(aInstance)
, mTimer(aInstance, Tcp::HandleTimer)
@@ -57,7 +65,8 @@ Tcp::Tcp(Instance &aInstance)
Error Tcp::Endpoint::Initialize(Instance &aInstance, otTcpEndpointInitializeArgs &aArgs)
{
Error error;
Error error;
struct tcpcb &tp = GetTcb();
SuccessOrExit(error = aInstance.Get<Tcp>().mEndpoints.Add(*this));
@@ -68,9 +77,30 @@ Error Tcp::Endpoint::Initialize(Instance &aInstance, otTcpEndpointInitializeArgs
mReceiveAvailableCallback = aArgs.mReceiveAvailableCallback;
mDisconnectedCallback = aArgs.mDisconnectedCallback;
mInstance = &aInstance;
memset(mTimers, 0x00, sizeof(mTimers));
memset(&mSockAddr, 0x00, sizeof(mSockAddr));
memset(&tp, 0x00, sizeof(tp));
/*
* Initialize buffers --- formerly in initialize_tcb.
*/
{
uint8_t *recvbuf = static_cast<uint8_t *>(aArgs.mReceiveBuffer);
size_t recvbuflen = aArgs.mReceiveBufferSize - ((aArgs.mReceiveBufferSize + 8) / 9);
uint8_t *reassbmp = recvbuf + recvbuflen;
lbuf_init(&tp.sendbuf);
cbuf_init(&tp.recvbuf, recvbuf, recvbuflen);
tp.reassbmp = reassbmp;
bmp_init(tp.reassbmp, BITS_TO_BYTES(recvbuflen));
}
tp.accepted_from = nullptr;
initialize_tcb(&tp);
/* Note that we do not need to zero-initialize mReceiveLinks. */
tp.instance = &aInstance;
exit:
return error;
@@ -78,57 +108,100 @@ exit:
Instance &Tcp::Endpoint::GetInstance(void)
{
return AsCoreType(mInstance);
struct tcpcb &tp = GetTcb();
return AsCoreType(tp.instance);
}
const SockAddr &Tcp::Endpoint::GetLocalAddress(void) const
{
const struct tcpcb &tp = GetTcb();
static otSockAddr temp;
memcpy(&temp.mAddress, &tp.laddr, sizeof(temp.mAddress));
temp.mPort = HostSwap16(tp.lport);
return AsCoreType(&temp);
}
const SockAddr &Tcp::Endpoint::GetPeerAddress(void) const
{
const struct tcpcb &tp = GetTcb();
static otSockAddr temp;
memcpy(&temp.mAddress, &tp.faddr, sizeof(temp.mAddress));
temp.mPort = HostSwap16(tp.fport);
return AsCoreType(&temp);
}
Error Tcp::Endpoint::Bind(const SockAddr &aSockName)
{
OT_UNUSED_VARIABLE(aSockName);
Error error;
struct tcpcb &tp = GetTcb();
return kErrorNotImplemented;
VerifyOrExit(!AsCoreType(&aSockName.mAddress).IsUnspecified(), error = kErrorInvalidArgs);
VerifyOrExit(GetInstance().Get<Tcp>().CanBind(aSockName), error = kErrorInvalidState);
memcpy(&tp.laddr, &aSockName.mAddress, sizeof(tp.laddr));
tp.lport = HostSwap16(aSockName.mPort);
error = kErrorNone;
exit:
return error;
}
Error Tcp::Endpoint::Connect(const SockAddr &aSockName, uint32_t aFlags)
{
OT_UNUSED_VARIABLE(aSockName);
Error error = kErrorNone;
struct tcpcb & tp = GetTcb();
struct sockaddr_in6 sin6p;
OT_UNUSED_VARIABLE(aFlags);
return kErrorNotImplemented;
VerifyOrExit(tp.t_state == TCP6S_CLOSED, error = kErrorInvalidState);
memcpy(&sin6p.sin6_addr, &aSockName.mAddress, sizeof(sin6p.sin6_addr));
sin6p.sin6_port = HostSwap16(aSockName.mPort);
error = BsdErrorToOtError(tcp6_usr_connect(&tp, &sin6p));
exit:
return error;
}
Error Tcp::Endpoint::SendByReference(otLinkedBuffer &aBuffer, uint32_t aFlags)
{
OT_UNUSED_VARIABLE(aBuffer);
OT_UNUSED_VARIABLE(aFlags);
struct tcpcb &tp = GetTcb();
return kErrorNotImplemented;
return BsdErrorToOtError(tcp_usr_send(&tp, (aFlags & OT_TCP_SEND_MORE_TO_COME) != 0, &aBuffer, 0));
}
Error Tcp::Endpoint::SendByExtension(size_t aNumBytes, uint32_t aFlags)
{
OT_UNUSED_VARIABLE(aNumBytes);
OT_UNUSED_VARIABLE(aFlags);
Error error;
bool moreToCome = (aFlags & OT_TCP_SEND_MORE_TO_COME) != 0;
struct tcpcb &tp = GetTcb();
int bsdError;
return kErrorNotImplemented;
VerifyOrExit(lbuf_head(&tp.sendbuf) != nullptr, error = kErrorInvalidState);
bsdError = tcp_usr_send(&tp, moreToCome ? 1 : 0, nullptr, aNumBytes);
SuccessOrExit(error = BsdErrorToOtError(bsdError));
exit:
return error;
}
Error Tcp::Endpoint::ReceiveByReference(const otLinkedBuffer *&aBuffer) const
Error Tcp::Endpoint::ReceiveByReference(const otLinkedBuffer *&aBuffer)
{
OT_UNUSED_VARIABLE(aBuffer);
struct tcpcb &tp = GetTcb();
return kErrorNotImplemented;
cbuf_reference(&tp.recvbuf, &mReceiveLinks[0], &mReceiveLinks[1]);
aBuffer = &mReceiveLinks[0];
return kErrorNone;
}
Error Tcp::Endpoint::ReceiveContiguify(void)
@@ -138,20 +211,35 @@ Error Tcp::Endpoint::ReceiveContiguify(void)
Error Tcp::Endpoint::CommitReceive(size_t aNumBytes, uint32_t aFlags)
{
OT_UNUSED_VARIABLE(aNumBytes);
Error error = kErrorNone;
struct tcpcb &tp = GetTcb();
OT_UNUSED_VARIABLE(aFlags);
return kErrorNotImplemented;
VerifyOrExit(cbuf_used_space(&tp.recvbuf) >= aNumBytes, error = kErrorFailed);
VerifyOrExit(aNumBytes > 0, error = kErrorNone);
cbuf_pop(&tp.recvbuf, aNumBytes);
error = BsdErrorToOtError(tcp_usr_rcvd(&tp));
exit:
return error;
}
Error Tcp::Endpoint::SendEndOfStream(void)
{
return kErrorNotImplemented;
struct tcpcb &tp = GetTcb();
return BsdErrorToOtError(tcp_usr_shutdown(&tp));
}
Error Tcp::Endpoint::Abort(void)
{
return kErrorNotImplemented;
struct tcpcb &tp = GetTcb();
tcp_usr_abort(&tp);
/* connection_lost will do any reinitialization work for this socket. */
return kErrorNone;
}
Error Tcp::Endpoint::Deinitialize(void)
@@ -163,25 +251,59 @@ Error Tcp::Endpoint::Deinitialize(void)
SuccessOrExit(error = tcp.mEndpoints.Remove(*this));
SetNext(nullptr);
SuccessOrExit(error = Abort());
exit:
return error;
}
uint8_t Tcp::Endpoint::TimerFlagToIndex(uint8_t aTimerFlag)
{
OT_UNUSED_VARIABLE(aTimerFlag);
/*
* TODO: Convert from the timer flag provided by TCPlp to the index in
* our timers array.
*/
return 0;
uint8_t timerIndex = 0;
switch (aTimerFlag)
{
case TT_DELACK:
timerIndex = kTimerDelack;
break;
case TT_REXMT:
case TT_PERSIST:
timerIndex = kTimerRexmtPersist;
break;
case TT_KEEP:
timerIndex = kTimerKeep;
break;
case TT_2MSL:
timerIndex = kTimer2Msl;
break;
}
return timerIndex;
}
bool Tcp::Endpoint::IsTimerActive(uint8_t aTimerIndex)
{
OT_UNUSED_VARIABLE(aTimerIndex);
/* TODO: Check whether TCPlp has marked this timer as active. */
return false;
bool active = false;
struct tcpcb *tp = &GetTcb();
OT_ASSERT(aTimerIndex < kNumTimers);
switch (aTimerIndex)
{
case kTimerDelack:
active = tcp_timer_active(tp, TT_DELACK);
break;
case kTimerRexmtPersist:
active = tcp_timer_active(tp, TT_REXMT) || tcp_timer_active(tp, TT_PERSIST);
break;
case kTimerKeep:
active = tcp_timer_active(tp, TT_KEEP);
break;
case kTimer2Msl:
active = tcp_timer_active(tp, TT_2MSL);
break;
}
return active;
}
void Tcp::Endpoint::SetTimer(uint8_t aTimerFlag, uint32_t aDelay)
@@ -219,6 +341,9 @@ void Tcp::Endpoint::CancelTimer(uint8_t aTimerFlag)
bool Tcp::Endpoint::FirePendingTimers(TimeMilli aNow, bool &aHasFutureTimer, TimeMilli &aEarliestFutureExpiry)
{
bool calledUserCallback = false;
struct tcpcb *tp = &GetTcb();
/*
* NOTE: Firing a timer might potentially activate/deactivate other timers.
* If timers x and y expire at the same time, but the callback for timer x
@@ -242,8 +367,36 @@ bool Tcp::Endpoint::FirePendingTimers(TimeMilli aNow, bool &aHasFutureTimer, Tim
if (expiry <= aNow)
{
/* TODO: Call TCPlp's callback for this timer. */
/* If a user callback is called, then return true. */
/*
* If a user callback is called, then return true. For TCPlp,
* this only happens if the connection is dropped (e.g., it
* times out).
*/
int dropped;
switch (timerIndex)
{
case kTimerDelack:
dropped = tcp_timer_delack(tp);
break;
case kTimerRexmtPersist:
if (tcp_timer_active(tp, TT_REXMT))
{
dropped = tcp_timer_rexmt(tp);
}
else
{
dropped = tcp_timer_persist(tp);
}
break;
case kTimerKeep:
dropped = tcp_timer_keep(tp);
break;
case kTimer2Msl:
dropped = tcp_timer_2msl(tp);
break;
}
VerifyOrExit(dropped == 0, calledUserCallback = true);
}
else
{
@@ -253,12 +406,31 @@ bool Tcp::Endpoint::FirePendingTimers(TimeMilli aNow, bool &aHasFutureTimer, Tim
}
}
return false;
exit:
return calledUserCallback;
}
bool Tcp::Endpoint::Matches(const MessageInfo &aMessageInfo) const
{
bool matches = false;
const struct tcpcb *tp = &GetTcb();
VerifyOrExit(tp->t_state != TCP6S_CLOSED);
VerifyOrExit(tp->lport == HostSwap16(aMessageInfo.GetSockPort()));
VerifyOrExit(tp->fport == HostSwap16(aMessageInfo.GetPeerPort()));
VerifyOrExit(GetLocalIp6Address().IsUnspecified() || GetLocalIp6Address() == aMessageInfo.GetSockAddr());
VerifyOrExit(GetForeignIp6Address() == aMessageInfo.GetPeerAddr());
matches = true;
exit:
return matches;
}
Error Tcp::Listener::Initialize(Instance &aInstance, otTcpListenerInitializeArgs &aArgs)
{
Error error;
Error error;
struct tcpcb_listen *tpl = &GetTcbListen();
SuccessOrExit(error = aInstance.Get<Tcp>().mListeners.Add(*this));
@@ -266,7 +438,8 @@ Error Tcp::Listener::Initialize(Instance &aInstance, otTcpListenerInitializeArgs
mAcceptReadyCallback = aArgs.mAcceptReadyCallback;
mAcceptDoneCallback = aArgs.mAcceptDoneCallback;
mInstance = &aInstance;
memset(tpl, 0x00, sizeof(struct tcpcb_listen));
tpl->instance = &aInstance;
exit:
return error;
@@ -274,19 +447,36 @@ exit:
Instance &Tcp::Listener::GetInstance(void)
{
return AsCoreType(mInstance);
struct tcpcb_listen *tpl = &GetTcbListen();
return AsCoreType(tpl->instance);
}
Error Tcp::Listener::Listen(const SockAddr &aSockName)
{
OT_UNUSED_VARIABLE(aSockName);
Error error;
uint16_t port = HostSwap16(aSockName.mPort);
struct tcpcb_listen *tpl = &GetTcbListen();
return kErrorNotImplemented;
VerifyOrExit(GetInstance().Get<Tcp>().CanBind(aSockName), error = kErrorInvalidState);
memcpy(&tpl->laddr, &aSockName.mAddress, sizeof(tpl->laddr));
tpl->lport = port;
tpl->t_state = TCP6S_LISTEN;
error = kErrorNone;
exit:
return error;
}
Error Tcp::Listener::StopListening(void)
{
return kErrorNotImplemented;
struct tcpcb_listen *tpl = &GetTcbListen();
memset(&tpl->laddr, 0x00, sizeof(tpl->laddr));
tpl->lport = 0;
tpl->t_state = TCP6S_CLOSED;
return kErrorNone;
}
Error Tcp::Listener::Deinitialize(void)
@@ -302,27 +492,238 @@ exit:
return error;
}
bool Tcp::Listener::Matches(const MessageInfo &aMessageInfo) const
{
bool matches = false;
const struct tcpcb_listen *tpl = &GetTcbListen();
VerifyOrExit(tpl->t_state == TCP6S_LISTEN);
VerifyOrExit(tpl->lport == HostSwap16(aMessageInfo.GetSockPort()));
VerifyOrExit(GetLocalIp6Address().IsUnspecified() || GetLocalIp6Address() == aMessageInfo.GetSockAddr());
matches = true;
exit:
return matches;
}
Error Tcp::HandleMessage(ot::Ip6::Header &aIp6Header, Message &aMessage, MessageInfo &aMessageInfo)
{
OT_UNUSED_VARIABLE(aIp6Header);
OT_UNUSED_VARIABLE(aMessage);
OT_UNUSED_VARIABLE(aMessageInfo);
Error error = kErrorNotImplemented;
for (Endpoint &active : mEndpoints)
/*
* The type uint32_t was chosen for alignment purposes. The size is the
* maximum TCP header size, including options.
*/
uint32_t header[15];
uint16_t length = aIp6Header.GetPayloadLength();
uint8_t headerSize;
struct ip6_hdr *ip6Header;
struct tcphdr * tcpHeader;
Endpoint *endpoint;
Endpoint *endpointPrev;
Listener *listener;
Listener *listenerPrev;
VerifyOrExit(length == aMessage.GetLength() - aMessage.GetOffset(), error = kErrorParse);
VerifyOrExit(length >= sizeof(Tcp::Header), error = kErrorParse);
SuccessOrExit(error = aMessage.Read(aMessage.GetOffset() + offsetof(struct tcphdr, th_off_x2), headerSize));
headerSize = static_cast<uint8_t>((headerSize >> TH_OFF_SHIFT) << 2);
VerifyOrExit(headerSize >= sizeof(struct tcphdr) && headerSize <= sizeof(header) &&
static_cast<uint16_t>(headerSize) <= length,
error = kErrorParse);
SuccessOrExit(error = Checksum::VerifyMessageChecksum(aMessage, aMessageInfo, kProtoTcp));
SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), &header[0], headerSize));
ip6Header = reinterpret_cast<struct ip6_hdr *>(&aIp6Header);
tcpHeader = reinterpret_cast<struct tcphdr *>(&header[0]);
tcp_fields_to_host(tcpHeader);
aMessageInfo.mPeerPort = HostSwap16(tcpHeader->th_sport);
aMessageInfo.mSockPort = HostSwap16(tcpHeader->th_dport);
endpoint = mEndpoints.FindMatching(aMessageInfo, endpointPrev);
if (endpoint != nullptr)
{
OT_UNUSED_VARIABLE(active);
struct signals sig;
int nextAction;
struct tcpcb * tp = &endpoint->GetTcb();
otLinkedBuffer *priorHead = lbuf_head(&tp->sendbuf);
memset(&sig, 0x00, sizeof(sig));
nextAction = tcp_input(ip6Header, tcpHeader, &aMessage, tp, nullptr, &sig);
if (nextAction != RELOOKUP_REQUIRED)
{
ProcessSignals(*endpoint, priorHead, sig);
ExitNow();
}
/* If the matching socket was in the TIME-WAIT state, then we try passive sockets. */
}
for (Listener &passive : mListeners)
listener = mListeners.FindMatching(aMessageInfo, listenerPrev);
if (listener != nullptr)
{
OT_UNUSED_VARIABLE(passive);
struct tcpcb_listen *tpl = &listener->GetTcbListen();
tcp_input(ip6Header, tcpHeader, &aMessage, nullptr, tpl, nullptr);
ExitNow();
}
tcp_dropwithreset(ip6Header, tcpHeader, nullptr, &InstanceLocator::GetInstance(), length - headerSize,
ECONNREFUSED);
exit:
return error;
}
void Tcp::ProcessSignals(Endpoint &aEndpoint, otLinkedBuffer *aPriorHead, struct signals &aSignals)
{
VerifyOrExit(IsInitialized(aEndpoint) && !aEndpoint.IsClosed());
if (aEndpoint.mSendDoneCallback != nullptr)
{
otLinkedBuffer *curr = aPriorHead;
for (int i = 0; i != aSignals.links_popped; i++)
{
otLinkedBuffer *next = curr->mNext;
VerifyOrExit(i == 0 || (IsInitialized(aEndpoint) && !aEndpoint.IsClosed()));
curr->mNext = nullptr;
aEndpoint.mSendDoneCallback(&aEndpoint, curr);
curr = next;
}
}
VerifyOrExit(IsInitialized(aEndpoint) && !aEndpoint.IsClosed());
if (aSignals.conn_established && aEndpoint.mEstablishedCallback != nullptr)
{
aEndpoint.mEstablishedCallback(&aEndpoint);
}
VerifyOrExit(IsInitialized(aEndpoint) && !aEndpoint.IsClosed());
if ((aSignals.recvbuf_notempty || aSignals.rcvd_fin) && aEndpoint.mReceiveAvailableCallback != nullptr)
{
aEndpoint.mReceiveAvailableCallback(&aEndpoint, cbuf_used_space(&aEndpoint.GetTcb().recvbuf),
aEndpoint.GetTcb().reass_fin_index != -1,
cbuf_free_space(&aEndpoint.GetTcb().recvbuf));
}
VerifyOrExit(IsInitialized(aEndpoint) && !aEndpoint.IsClosed());
if (aEndpoint.GetTcb().t_state == TCP6S_TIME_WAIT && aEndpoint.mDisconnectedCallback != nullptr)
{
aEndpoint.mDisconnectedCallback(&aEndpoint, OT_TCP_DISCONNECTED_REASON_TIME_WAIT);
}
exit:
return;
}
Error Tcp::BsdErrorToOtError(int aBsdError)
{
Error error = kErrorFailed;
switch (aBsdError)
{
case 0:
error = kErrorNone;
break;
}
return error;
}
bool Tcp::CanBind(const SockAddr &aSockName)
{
uint16_t port = HostSwap16(aSockName.mPort);
bool allowed = false;
for (Endpoint *endpoint = mEndpoints.GetHead(); endpoint != nullptr; endpoint = endpoint->GetNext())
{
struct tcpcb *tp = &endpoint->GetTcb();
if (tp->lport == port)
{
VerifyOrExit(!aSockName.GetAddress().IsUnspecified());
VerifyOrExit(!reinterpret_cast<Address *>(&tp->laddr)->IsUnspecified());
VerifyOrExit(memcmp(&endpoint->GetTcb().laddr, &aSockName.mAddress, sizeof(tp->laddr)) != 0);
}
}
for (Listener *listener = mListeners.GetHead(); listener != nullptr; listener = listener->GetNext())
{
struct tcpcb_listen *tpl = &listener->GetTcbListen();
if (tpl->lport == port)
{
VerifyOrExit(!aSockName.GetAddress().IsUnspecified());
VerifyOrExit(!reinterpret_cast<Address *>(&tpl->laddr)->IsUnspecified());
VerifyOrExit(memcmp(&tpl->laddr, &aSockName.mAddress, sizeof(tpl->laddr)) != 0);
}
}
allowed = true;
exit:
return allowed;
}
bool Tcp::AutoBind(const SockAddr &aPeer, SockAddr &aToBind, bool aBindAddress, bool aBindPort)
{
bool success;
if (aBindAddress)
{
MessageInfo peerInfo;
const Netif::UnicastAddress *netifAddress;
peerInfo.Clear();
peerInfo.SetPeerAddr(aPeer.GetAddress());
netifAddress = InstanceLocator::GetInstance().Get<Ip6>().SelectSourceAddress(peerInfo);
VerifyOrExit(netifAddress != nullptr, success = false);
aToBind.GetAddress() = netifAddress->GetAddress();
}
if (aBindPort)
{
/*
* TODO: Use a less naive algorithm to allocate ephemeral ports. For
* example, see RFC 6056.
*/
for (uint16_t i = 0; i != kDynamicPortMax - kDynamicPortMin + 1; i++)
{
aToBind.SetPort(mEphemeralPort);
if (mEphemeralPort == kDynamicPortMax)
{
mEphemeralPort = kDynamicPortMin;
}
else
{
mEphemeralPort++;
}
if (CanBind(aToBind))
{
ExitNow(success = true);
}
}
ExitNow(success = false);
}
success = CanBind(aToBind);
exit:
return success;
}
void Tcp::HandleTimer(Timer &aTimer)
{
OT_ASSERT(&aTimer == &aTimer.GetInstance().Get<Tcp>().mTimer);
@@ -395,4 +796,227 @@ restart:
} // namespace Ip6
} // namespace ot
/*
* Implement TCPlp system stubs declared in tcplp.h.
*
* Because these functions have C linkage, it is important that only one
* definition is given for each function name, regardless of the namespace it
* in. For example, if we give two definitions of tcplp_sys_new_message, we
* will get errors, even if they are in different namespaces. To avoid
* confusion, I've put these functions outside of any namespace.
*/
using namespace ot;
using namespace ot::Ip6;
extern "C" {
otMessage *tcplp_sys_new_message(otInstance *aInstance)
{
Instance &instance = AsCoreType(aInstance);
Message * message = instance.Get<ot::Ip6::Ip6>().NewMessage(0);
if (message)
{
message->SetLinkSecurityEnabled(true);
}
return message;
}
void tcplp_sys_free_message(otInstance *aInstance, otMessage *aMessage)
{
OT_UNUSED_VARIABLE(aInstance);
Message &message = AsCoreType(aMessage);
message.Free();
}
void tcplp_sys_send_message(otInstance *aInstance, otMessage *aMessage, otMessageInfo *aMessageInfo)
{
Instance & instance = AsCoreType(aInstance);
Message & message = AsCoreType(aMessage);
MessageInfo &info = AsCoreType(aMessageInfo);
otLogDebgTcp("Sending TCP segment: payload_size = %d", static_cast<int>(message.GetLength()));
IgnoreError(instance.Get<ot::Ip6::Ip6>().SendDatagram(message, info, kProtoTcp));
}
uint32_t tcplp_sys_get_ticks(void)
{
return TimerMilli::GetNow().GetValue();
}
uint32_t tcplp_sys_get_millis(void)
{
return TimerMilli::GetNow().GetValue();
}
void tcplp_sys_set_timer(struct tcpcb *aTcb, uint8_t aTimerFlag, uint32_t aDelay)
{
Tcp::Endpoint &endpoint = Tcp::Endpoint::FromTcb(*aTcb);
endpoint.SetTimer(aTimerFlag, aDelay);
}
void tcplp_sys_stop_timer(struct tcpcb *aTcb, uint8_t aTimerFlag)
{
Tcp::Endpoint &endpoint = Tcp::Endpoint::FromTcb(*aTcb);
endpoint.CancelTimer(aTimerFlag);
}
struct tcpcb *tcplp_sys_accept_ready(struct tcpcb_listen *aTcbListen, struct in6_addr *aAddr, uint16_t aPort)
{
Tcp::Listener & listener = Tcp::Listener::FromTcbListen(*aTcbListen);
Tcp & tcp = listener.GetInstance().Get<Tcp>();
struct tcpcb * rv = (struct tcpcb *)-1;
otSockAddr addr;
otTcpEndpoint * endpointPtr;
otTcpIncomingConnectionAction action;
VerifyOrExit(listener.mAcceptReadyCallback != nullptr);
memcpy(&addr.mAddress, aAddr, sizeof(addr.mAddress));
addr.mPort = HostSwap16(aPort);
action = listener.mAcceptReadyCallback(&listener, &addr, &endpointPtr);
VerifyOrExit(tcp.IsInitialized(listener) && !listener.IsClosed());
switch (action)
{
case OT_TCP_INCOMING_CONNECTION_ACTION_ACCEPT:
{
Tcp::Endpoint &endpoint = AsCoreType(endpointPtr);
/*
* The documentation says that the user must initialize the
* endpoint before passing it here, so we do a sanity check to make
* sure the endpoint is initialized and closed. That check may not
* be necessary, but we do it anyway.
*/
VerifyOrExit(tcp.IsInitialized(endpoint) && endpoint.IsClosed());
rv = &endpoint.GetTcb();
break;
}
case OT_TCP_INCOMING_CONNECTION_ACTION_DEFER:
rv = nullptr;
break;
case OT_TCP_INCOMING_CONNECTION_ACTION_REFUSE:
rv = (struct tcpcb *)-1;
break;
}
exit:
return rv;
}
bool tcplp_sys_accepted_connection(struct tcpcb_listen *aTcbListen,
struct tcpcb * aAccepted,
struct in6_addr * aAddr,
uint16_t aPort)
{
Tcp::Listener &listener = Tcp::Listener::FromTcbListen(*aTcbListen);
Tcp::Endpoint &endpoint = Tcp::Endpoint::FromTcb(*aAccepted);
Tcp & tcp = endpoint.GetInstance().Get<Tcp>();
bool accepted = true;
if (listener.mAcceptDoneCallback != nullptr)
{
otSockAddr addr;
memcpy(&addr.mAddress, aAddr, sizeof(addr.mAddress));
addr.mPort = HostSwap16(aPort);
listener.mAcceptDoneCallback(&listener, &endpoint, &addr);
if (!tcp.IsInitialized(endpoint) || endpoint.IsClosed())
{
accepted = false;
}
}
return accepted;
}
void tcplp_sys_connection_lost(struct tcpcb *aTcb, uint8_t aErrNum)
{
Tcp::Endpoint &endpoint = Tcp::Endpoint::FromTcb(*aTcb);
if (endpoint.mDisconnectedCallback != nullptr)
{
otTcpDisconnectedReason reason;
switch (aErrNum)
{
case CONN_LOST_NORMAL:
reason = OT_TCP_DISCONNECTED_REASON_NORMAL;
break;
case ECONNREFUSED:
reason = OT_TCP_DISCONNECTED_REASON_REFUSED;
break;
case ETIMEDOUT:
reason = OT_TCP_DISCONNECTED_REASON_TIMED_OUT;
break;
case ECONNRESET:
default:
reason = OT_TCP_DISCONNECTED_REASON_RESET;
break;
}
endpoint.mDisconnectedCallback(&endpoint, reason);
}
}
void tcplp_sys_on_state_change(struct tcpcb *aTcb, int aNewState)
{
if (aNewState == TCP6S_CLOSED)
{
/* Re-initialize the TCB. */
cbuf_pop(&aTcb->recvbuf, cbuf_used_space(&aTcb->recvbuf));
aTcb->accepted_from = nullptr;
initialize_tcb(aTcb);
}
/* Any adaptive changes to the sleep interval would go here. */
}
void tcplp_sys_log(const char *aFormat, ...)
{
char buffer[128];
va_list args;
va_start(args, aFormat);
vsnprintf(buffer, sizeof(buffer), aFormat, args);
va_end(args);
otLogDebgTcp(buffer);
}
bool tcplp_sys_autobind(otInstance * aInstance,
const otSockAddr *aPeer,
otSockAddr * aToBind,
bool aBindAddress,
bool aBindPort)
{
Instance &instance = AsCoreType(aInstance);
return instance.Get<Tcp>().AutoBind(*static_cast<const SockAddr *>(aPeer), *static_cast<SockAddr *>(aToBind),
aBindAddress, aBindPort);
}
uint32_t tcplp_sys_generate_isn()
{
uint32_t isn;
IgnoreError(Random::Crypto::FillBuffer(reinterpret_cast<uint8_t *>(&isn), sizeof(isn)));
return isn;
}
uint16_t tcplp_sys_hostswap16(uint16_t aHostPort)
{
return HostSwap16(aHostPort);
}
uint32_t tcplp_sys_hostswap32(uint32_t aHostPort)
{
return HostSwap32(aHostPort);
}
}
#endif // OPENTHREAD_CONFIG_TCP_ENABLE
+113 -1
View File
@@ -46,6 +46,8 @@
#include "net/ip6_headers.hpp"
#include "net/socket.hpp"
#include "../../third_party/tcplp/tcplp.h"
namespace ot {
namespace Ip6 {
@@ -73,6 +75,7 @@ public:
class Endpoint : public otTcpEndpoint, public LinkedListEntry<Endpoint>
{
friend class Tcp;
friend class LinkedList<Endpoint>;
public:
/**
@@ -236,7 +239,7 @@ public:
* @retval kErrorNone Successfully completed the operation.
* @retval kErrorFailed Failed to complete the operation.
*/
Error ReceiveByReference(const otLinkedBuffer *&aBuffer) const;
Error ReceiveByReference(const otLinkedBuffer *&aBuffer);
/**
* Reorganizes the receive buffer to be entirely contiguous in memory.
@@ -329,7 +332,32 @@ public:
*/
Error Deinitialize(void);
/**
* Converts a reference to a struct tcpcb to a reference to its
* enclosing Endpoint.
*/
static Endpoint &FromTcb(struct tcpcb &aTcb) { return *reinterpret_cast<Endpoint *>(&aTcb); }
/**
* Obtains a reference to this Endpoint's struct tcpcb.
*/
struct tcpcb &GetTcb(void) { return *reinterpret_cast<struct tcpcb *>(&mTcb); }
/**
* Obtains a const reference to this Endpoint's struct tcpcb.
*/
const struct tcpcb &GetTcb(void) const { return *reinterpret_cast<const struct tcpcb *>(&mTcb); }
/**
* Checks if this Endpoint is in the closed state.
*/
bool IsClosed(void) const { return GetTcb().t_state == TCP6S_CLOSED; }
private:
friend void ::tcplp_sys_set_timer(struct tcpcb *aTcb, uint8_t aTimerFlag, uint32_t aDelay);
friend void ::tcplp_sys_stop_timer(struct tcpcb *aTcb, uint8_t aTimerFlag);
friend void ::tcplp_sys_connection_lost(struct tcpcb *aTcb, uint8_t aErrNum);
enum : uint8_t
{
kTimerDelack = 0,
@@ -345,14 +373,27 @@ public:
void SetTimer(uint8_t aTimerFlag, uint32_t aDelay);
void CancelTimer(uint8_t aTimerFlag);
bool FirePendingTimers(TimeMilli aNow, bool &aHasFutureTimer, TimeMilli &aEarliestFutureExpiry);
Address & GetLocalIp6Address(void) { return *reinterpret_cast<Address *>(&GetTcb().laddr); }
const Address &GetLocalIp6Address(void) const { return *reinterpret_cast<const Address *>(&GetTcb().laddr); }
Address & GetForeignIp6Address(void) { return *reinterpret_cast<Address *>(&GetTcb().faddr); }
const Address &GetForeignIp6Address(void) const { return *reinterpret_cast<const Address *>(&GetTcb().faddr); }
bool Matches(const MessageInfo &aMessageInfo) const;
};
static_assert(sizeof(struct tcpcb) == sizeof(Endpoint::mTcb), "mTcb field in otTcpEndpoint is sized incorrectly");
static_assert(alignof(struct tcpcb) == alignof(decltype(Endpoint::mTcb)),
"mTcb field in otTcpEndpoint is aligned incorrectly");
static_assert(offsetof(Endpoint, mTcb) == 0, "mTcb field in otTcpEndpoint has nonzero offset");
/**
* This class represents a TCP/IPv6 listener.
*
*/
class Listener : public otTcpListener, public LinkedListEntry<Listener>
{
friend class LinkedList<Listener>;
public:
/**
* Initializes a TCP listener.
@@ -438,8 +479,49 @@ public:
*
*/
Error Deinitialize(void);
/**
* Converts a reference to a struct tcpcb_listen to a reference to its
* enclosing Listener.
*/
static Listener &FromTcbListen(struct tcpcb_listen &aTcbListen)
{
return *reinterpret_cast<Listener *>(&aTcbListen);
}
/**
* Obtains a reference to this Listener's struct tcpcb_listen.
*/
struct tcpcb_listen &GetTcbListen(void) { return *reinterpret_cast<struct tcpcb_listen *>(&mTcbListen); }
/**
* Obtains a const reference to this Listener's struct tcpcb_listen.
*/
const struct tcpcb_listen &GetTcbListen(void) const
{
return *reinterpret_cast<const struct tcpcb_listen *>(&mTcbListen);
}
/**
* Checks if this Listener is in the closed state.
*/
bool IsClosed(void) const { return GetTcbListen().t_state == TCP6S_CLOSED; }
private:
Address & GetLocalIp6Address(void) { return *reinterpret_cast<Address *>(&GetTcbListen().laddr); }
const Address &GetLocalIp6Address(void) const
{
return *reinterpret_cast<const Address *>(&GetTcbListen().laddr);
}
bool Matches(const MessageInfo &aMessageInfo) const;
};
static_assert(sizeof(struct tcpcb_listen) == sizeof(Listener::mTcbListen),
"mTcbListen field in otTcpListener is sized incorrectly");
static_assert(alignof(struct tcpcb_listen) == alignof(decltype(Listener::mTcbListen)),
"mTcbListen field in otTcpListener is aligned incorrectly");
static_assert(offsetof(Listener, mTcbListen) == 0, "mTcbListen field in otTcpEndpoint has nonzero offset");
/**
* This class implements TCP header parsing.
*
@@ -546,6 +628,31 @@ public:
*/
Error HandleMessage(ot::Ip6::Header &aIp6Header, Message &aMessage, MessageInfo &aMessageInfo);
/**
* Automatically selects a local address and/or port for communication with the specified peer.
*
* @param[in] aPeer The peer's address and port.
* @param[in,out] aToBind The SockAddr into which to store the selected address and/or port.
* @param[in] aBindAddress If true, the local address is selected; if not, the current address
* in @p aToBind is treated as a given.
* @param[in] aBindPort If true, the local port is selected; if not, the current port in
* @p aToBind is treated as a given.
*
* @returns True if successful, false otherwise.
*
*/
bool AutoBind(const SockAddr &aPeer, SockAddr &aToBind, bool aBindAddress, bool aBindPort);
/**
* Checks if an Endpoint is in the list of initialized endpoints.
*/
bool IsInitialized(const Endpoint &aEndpoint) const { return mEndpoints.Contains(aEndpoint); }
/**
* Checks if a Listener is in the list of initialized Listeners.
*/
bool IsInitialized(const Listener &aListener) const { return mListeners.Contains(aListener); }
private:
enum
{
@@ -553,6 +660,11 @@ private:
kDynamicPortMax = 65535, ///< Service Name and Transport Protocol Port Number Registry
};
void ProcessSignals(Endpoint &aEndpoint, otLinkedBuffer *aPriorHead, struct signals &aSignals);
static Error BsdErrorToOtError(int aBsdError);
bool CanBind(const SockAddr &aSockName);
static void HandleTimer(Timer &aTimer);
void ProcessTimers(void);
+125 -82
View File
@@ -28,6 +28,8 @@
include $(abs_top_nlbuild_autotools_dir)/automake/pre.am
COMMON_LIBTOOLFLAGS = --preserve-dup-deps
#
# Local headers to build against and distribute but not to install
# since they are not part of the package.
@@ -74,7 +76,6 @@ AM_CPPFLAGS += \
endif
COMMON_LDADD = \
$(top_builddir)/third_party/tcplp/libtcplp.a \
$(NULL)
if OPENTHREAD_ENABLE_NCP
@@ -84,6 +85,8 @@ COMMON_LDADD += \
endif
COMMON_LDADD += \
$(top_builddir)/src/core/libopenthread-ftd.a \
$(top_builddir)/third_party/tcplp/libtcplp.a \
$(top_builddir)/src/core/libopenthread-ftd.a \
-lpthread \
$(NULL)
@@ -184,128 +187,168 @@ COMMON_SOURCES = test_platform.cpp test_util.cpp
# Source, compiler, and linker options for test programs.
ot_test_aes_LDADD = $(COMMON_LDADD)
ot_test_aes_SOURCES = $(COMMON_SOURCES) test_aes.cpp
ot_test_aes_LDADD = $(COMMON_LDADD)
ot_test_aes_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_aes_SOURCES = $(COMMON_SOURCES) test_aes.cpp
ot_test_array_LDADD = $(COMMON_LDADD)
ot_test_array_SOURCES = $(COMMON_SOURCES) test_array.cpp
ot_test_array_LDADD = $(COMMON_LDADD)
ot_test_array_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_array_SOURCES = $(COMMON_SOURCES) test_array.cpp
ot_test_binary_search_LDADD = $(COMMON_LDADD)
ot_test_binary_search_SOURCES = $(COMMON_SOURCES) test_binary_search.cpp
ot_test_binary_search_LDADD = $(COMMON_LDADD)
ot_test_binary_search_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_binary_search_SOURCES = $(COMMON_SOURCES) test_binary_search.cpp
ot_test_checksum_LDADD = $(COMMON_LDADD)
ot_test_checksum_SOURCES = $(COMMON_SOURCES) test_checksum.cpp
ot_test_checksum_LDADD = $(COMMON_LDADD)
ot_test_checksum_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_checksum_SOURCES = $(COMMON_SOURCES) test_checksum.cpp
ot_test_child_LDADD = $(COMMON_LDADD)
ot_test_child_SOURCES = $(COMMON_SOURCES) test_child.cpp
ot_test_child_LDADD = $(COMMON_LDADD)
ot_test_child_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_child_SOURCES = $(COMMON_SOURCES) test_child.cpp
ot_test_child_table_LDADD = $(COMMON_LDADD)
ot_test_child_table_SOURCES = $(COMMON_SOURCES) test_child_table.cpp
ot_test_child_table_LDADD = $(COMMON_LDADD)
ot_test_child_table_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_child_table_SOURCES = $(COMMON_SOURCES) test_child_table.cpp
ot_test_cmd_line_parser_LDADD = $(COMMON_LDADD)
ot_test_cmd_line_parser_SOURCES = $(COMMON_SOURCES) test_cmd_line_parser.cpp
ot_test_cmd_line_parser_LDADD = $(COMMON_LDADD)
ot_test_cmd_line_parser_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_cmd_line_parser_SOURCES = $(COMMON_SOURCES) test_cmd_line_parser.cpp
ot_test_data_LDADD = $(COMMON_LDADD)
ot_test_data_SOURCES = $(COMMON_SOURCES) test_data.cpp
ot_test_data_LDADD = $(COMMON_LDADD)
ot_test_data_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_data_SOURCES = $(COMMON_SOURCES) test_data.cpp
ot_test_dns_LDADD = $(COMMON_LDADD)
ot_test_dns_SOURCES = $(COMMON_SOURCES) test_dns.cpp
ot_test_dns_LDADD = $(COMMON_LDADD)
ot_test_dns_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_dns_SOURCES = $(COMMON_SOURCES) test_dns.cpp
ot_test_dso_LDADD = $(COMMON_LDADD)
ot_test_dso_SOURCES = $(COMMON_SOURCES) test_dso.cpp
ot_test_dso_LDADD = $(COMMON_LDADD)
ot_test_dso_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_dso_SOURCES = $(COMMON_SOURCES) test_dso.cpp
ot_test_ecdsa_LDADD = $(COMMON_LDADD)
ot_test_ecdsa_SOURCES = $(COMMON_SOURCES) test_ecdsa.cpp
ot_test_ecdsa_LDADD = $(COMMON_LDADD)
ot_test_ecdsa_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_ecdsa_SOURCES = $(COMMON_SOURCES) test_ecdsa.cpp
ot_test_flash_LDADD = $(COMMON_LDADD)
ot_test_flash_SOURCES = $(COMMON_SOURCES) test_flash.cpp
ot_test_flash_LDADD = $(COMMON_LDADD)
ot_test_flash_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_flash_SOURCES = $(COMMON_SOURCES) test_flash.cpp
ot_test_hdlc_LDADD = $(COMMON_LDADD)
ot_test_hdlc_SOURCES = $(COMMON_SOURCES) test_hdlc.cpp
ot_test_hdlc_LDADD = $(COMMON_LDADD)
ot_test_hdlc_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_hdlc_SOURCES = $(COMMON_SOURCES) test_hdlc.cpp
ot_test_heap_LDADD = $(COMMON_LDADD)
ot_test_heap_SOURCES = $(COMMON_SOURCES) test_heap.cpp
ot_test_heap_LDADD = $(COMMON_LDADD)
ot_test_heap_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_heap_SOURCES = $(COMMON_SOURCES) test_heap.cpp
ot_test_heap_string_LDADD = $(COMMON_LDADD)
ot_test_heap_string_SOURCES = $(COMMON_SOURCES) test_heap_string.cpp
ot_test_heap_string_LDADD = $(COMMON_LDADD)
ot_test_heap_string_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_heap_string_SOURCES = $(COMMON_SOURCES) test_heap_string.cpp
ot_test_hkdf_sha256_LDADD = $(COMMON_LDADD)
ot_test_hkdf_sha256_SOURCES = $(COMMON_SOURCES) test_hkdf_sha256.cpp
ot_test_hkdf_sha256_LDADD = $(COMMON_LDADD)
ot_test_hkdf_sha256_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_hkdf_sha256_SOURCES = $(COMMON_SOURCES) test_hkdf_sha256.cpp
ot_test_hmac_sha256_LDADD = $(COMMON_LDADD)
ot_test_hmac_sha256_SOURCES = $(COMMON_SOURCES) test_hmac_sha256.cpp
ot_test_hmac_sha256_LDADD = $(COMMON_LDADD)
ot_test_hmac_sha256_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_hmac_sha256_SOURCES = $(COMMON_SOURCES) test_hmac_sha256.cpp
ot_test_ip_address_LDADD = $(COMMON_LDADD)
ot_test_ip_address_SOURCES = $(COMMON_SOURCES) test_ip_address.cpp
ot_test_ip_address_LDADD = $(COMMON_LDADD)
ot_test_ip_address_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_ip_address_SOURCES = $(COMMON_SOURCES) test_ip_address.cpp
ot_test_link_quality_LDADD = $(COMMON_LDADD)
ot_test_link_quality_SOURCES = $(COMMON_SOURCES) test_link_quality.cpp
ot_test_link_quality_LDADD = $(COMMON_LDADD)
ot_test_link_quality_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_link_quality_SOURCES = $(COMMON_SOURCES) test_link_quality.cpp
ot_test_linked_list_LDADD = $(COMMON_LDADD)
ot_test_linked_list_SOURCES = $(COMMON_SOURCES) test_linked_list.cpp
ot_test_linked_list_LDADD = $(COMMON_LDADD)
ot_test_linked_list_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_linked_list_SOURCES = $(COMMON_SOURCES) test_linked_list.cpp
ot_test_lowpan_LDADD = $(COMMON_LDADD)
ot_test_lowpan_SOURCES = $(COMMON_SOURCES) test_lowpan.cpp
ot_test_lowpan_LDADD = $(COMMON_LDADD)
ot_test_lowpan_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_lowpan_SOURCES = $(COMMON_SOURCES) test_lowpan.cpp
ot_test_mac_frame_LDADD = $(COMMON_LDADD)
ot_test_mac_frame_SOURCES = $(COMMON_SOURCES) test_mac_frame.cpp
ot_test_mac_frame_LDADD = $(COMMON_LDADD)
ot_test_mac_frame_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_mac_frame_SOURCES = $(COMMON_SOURCES) test_mac_frame.cpp
ot_test_macros_LDADD = $(COMMON_LDADD)
ot_test_macros_SOURCES = $(COMMON_SOURCES) test_macros.cpp
ot_test_macros_LDADD = $(COMMON_LDADD)
ot_test_macros_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_macros_SOURCES = $(COMMON_SOURCES) test_macros.cpp
ot_test_message_LDADD = $(COMMON_LDADD)
ot_test_message_SOURCES = $(COMMON_SOURCES) test_message.cpp
ot_test_message_LDADD = $(COMMON_LDADD)
ot_test_message_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_message_SOURCES = $(COMMON_SOURCES) test_message.cpp
ot_test_message_queue_LDADD = $(COMMON_LDADD)
ot_test_message_queue_SOURCES = $(COMMON_SOURCES) test_message_queue.cpp
ot_test_message_queue_LDADD = $(COMMON_LDADD)
ot_test_message_queue_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_message_queue_SOURCES = $(COMMON_SOURCES) test_message_queue.cpp
ot_test_multicast_listeners_table_LDADD = $(COMMON_LDADD)
ot_test_multicast_listeners_table_LDADD = $(COMMON_LDADD)
ot_test_multicast_listeners_table_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_multicast_listeners_table_SOURCES = $(COMMON_SOURCES) test_multicast_listeners_table.cpp
ot_test_spinel_buffer_LDADD = $(COMMON_LDADD)
ot_test_spinel_buffer_SOURCES = $(COMMON_SOURCES) test_spinel_buffer.cpp
ot_test_spinel_buffer_LDADD = $(COMMON_LDADD)
ot_test_spinel_buffer_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_spinel_buffer_SOURCES = $(COMMON_SOURCES) test_spinel_buffer.cpp
ot_test_ndproxy_table_LDADD = $(COMMON_LDADD)
ot_test_ndproxy_table_SOURCES = $(COMMON_SOURCES) test_ndproxy_table.cpp
ot_test_ndproxy_table_LDADD = $(COMMON_LDADD)
ot_test_ndproxy_table_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_ndproxy_table_SOURCES = $(COMMON_SOURCES) test_ndproxy_table.cpp
ot_test_netif_LDADD = $(COMMON_LDADD)
ot_test_netif_SOURCES = $(COMMON_SOURCES) test_netif.cpp
ot_test_netif_LDADD = $(COMMON_LDADD)
ot_test_netif_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_netif_SOURCES = $(COMMON_SOURCES) test_netif.cpp
ot_test_network_data_LDADD = $(COMMON_LDADD)
ot_test_network_data_SOURCES = $(COMMON_SOURCES) test_network_data.cpp
ot_test_network_data_LDADD = $(COMMON_LDADD)
ot_test_network_data_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_network_data_SOURCES = $(COMMON_SOURCES) test_network_data.cpp
ot_test_pool_LDADD = $(COMMON_LDADD)
ot_test_pool_SOURCES = $(COMMON_SOURCES) test_pool.cpp
ot_test_pool_LDADD = $(COMMON_LDADD)
ot_test_pool_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_pool_SOURCES = $(COMMON_SOURCES) test_pool.cpp
ot_test_priority_queue_LDADD = $(COMMON_LDADD)
ot_test_priority_queue_SOURCES = $(COMMON_SOURCES) test_priority_queue.cpp
ot_test_priority_queue_LDADD = $(COMMON_LDADD)
ot_test_priority_queue_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_priority_queue_SOURCES = $(COMMON_SOURCES) test_priority_queue.cpp
ot_test_pskc_LDADD = $(COMMON_LDADD)
ot_test_pskc_SOURCES = $(COMMON_SOURCES) test_pskc.cpp
ot_test_pskc_LDADD = $(COMMON_LDADD)
ot_test_pskc_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_pskc_SOURCES = $(COMMON_SOURCES) test_pskc.cpp
ot_test_smart_ptrs_LDADD = $(COMMON_LDADD)
ot_test_smart_ptrs_SOURCES = $(COMMON_SOURCES) test_smart_ptrs.cpp
ot_test_smart_ptrs_LDADD = $(COMMON_LDADD)
ot_test_smart_ptrs_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_smart_ptrs_SOURCES = $(COMMON_SOURCES) test_smart_ptrs.cpp
ot_test_meshcop_LDADD = $(COMMON_LDADD)
ot_test_meshcop_SOURCES = $(COMMON_SOURCES) test_meshcop.cpp
ot_test_meshcop_LDADD = $(COMMON_LDADD)
ot_test_meshcop_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_meshcop_SOURCES = $(COMMON_SOURCES) test_meshcop.cpp
ot_test_serial_number_LDADD = $(COMMON_LDADD)
ot_test_serial_number_SOURCES = $(COMMON_SOURCES) test_serial_number.cpp
ot_test_serial_number_LDADD = $(COMMON_LDADD)
ot_test_serial_number_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_serial_number_SOURCES = $(COMMON_SOURCES) test_serial_number.cpp
ot_test_string_LDADD = $(COMMON_LDADD)
ot_test_string_SOURCES = $(COMMON_SOURCES) test_string.cpp
ot_test_string_LDADD = $(COMMON_LDADD)
ot_test_string_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_string_SOURCES = $(COMMON_SOURCES) test_string.cpp
ot_test_spinel_decoder_LDADD = $(COMMON_LDADD)
ot_test_spinel_decoder_SOURCES = $(COMMON_SOURCES) test_spinel_decoder.cpp
ot_test_spinel_decoder_LDADD = $(COMMON_LDADD)
ot_test_spinel_decoder_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_spinel_decoder_SOURCES = $(COMMON_SOURCES) test_spinel_decoder.cpp
ot_test_spinel_encoder_LDADD = $(COMMON_LDADD)
ot_test_spinel_encoder_SOURCES = $(COMMON_SOURCES) test_spinel_encoder.cpp
ot_test_spinel_encoder_LDADD = $(COMMON_LDADD)
ot_test_spinel_encoder_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_spinel_encoder_SOURCES = $(COMMON_SOURCES) test_spinel_encoder.cpp
ot_test_timer_LDADD = $(COMMON_LDADD)
ot_test_timer_SOURCES = $(COMMON_SOURCES) test_timer.cpp
ot_test_timer_LDADD = $(COMMON_LDADD)
ot_test_timer_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
ot_test_timer_SOURCES = $(COMMON_SOURCES) test_timer.cpp
ot_test_toolchain_LDADD = $(NULL)
ot_test_toolchain_SOURCES = test_toolchain.cpp test_toolchain_c.c
ot_test_toolchain_LDADD = $(NULL)
ot_test_toolchain_SOURCES = test_toolchain.cpp test_toolchain_c.c
if OPENTHREAD_BUILD_COVERAGE
CLEANFILES = $(wildcard *.gcda *.gcno)
+15 -1
View File
@@ -43,9 +43,23 @@
#include "tcp_var.h"
#include "tcp_timer.h"
/*
* samkumar: these are TCPlp-specific constants that I added. They were not
* present in the FreeBSD-derived code.
*/
#define FRAMES_PER_SEG 5
#define FRAMECAP_6LOWPAN (122 - 11 - 5)
#define IP6HDR_SIZE (2 + 1 + 1 + 16 + 16) // IPHC header (2) + Next header (1) + Hop count (1) + Dest. addr (16) + Src. addr (16)
#define MSS_6LOWPAN ((FRAMES_PER_SEG * FRAMECAP_6LOWPAN) - IP6HDR_SIZE - sizeof(struct tcphdr))
// I may change some of these flags later
/*
* samkumar: The remaining constants were present in the original FreeBSD code,
* but I set their values.
*/
#define hz 1000 // number of ticks per second, assuming millisecond ticks
enum tcp_input_consts {
tcp_keepcnt = TCPTV_KEEPCNT,
tcp_fast_finwait2_recycle = 0,
+5 -5
View File
@@ -48,12 +48,12 @@
#include "tcp_const.h"
/* samkumar: Eventually, replace this with OpenThread's random generator. */
// A simple linear congruential number generator
tcp_seq seed = (tcp_seq) 0xbeaddeed;
/*
* samkumar: This is rewritten to have the host network stack to generate the
* ISN with appropriate randomness.
*/
tcp_seq tcp_new_isn(struct tcpcb* tp) {
seed = (((tcp_seq) 0xfaded011) * seed) + (tcp_seq) 0x1ead1eaf;
return seed;
return (uint32_t) tcplp_sys_generate_isn();
}
/*
+23 -10
View File
@@ -59,10 +59,11 @@ int V_tcp_pmtud_blackhole_activated_min_mss = 0;
/*
* samkumar: I changed these functions to accept "struct tcpcb* tp" their
* argument instead of "void *xtp". This is possible since we're no longer
* relying on FreeBSD's callout subsystem in TCPlp.
* relying on FreeBSD's callout subsystem in TCPlp. I also changed them to
* return 1 if the connection is dropped, or 0 otherwise.
*/
void
int
tcp_timer_delack(struct tcpcb* tp)
{
/* samkumar: I added this, to replace the code I removed below. */
@@ -80,9 +81,10 @@ tcp_timer_delack(struct tcpcb* tp)
*/
tp->t_flags |= TF_ACKNOW;
(void) tcp_output(tp);
return 0;
}
void
int
tcp_timer_keep(struct tcpcb* tp)
{
uint32_t ticks = tcplp_sys_get_ticks();
@@ -158,17 +160,19 @@ tcp_timer_keep(struct tcpcb* tp)
* that handled debug tracing/probes, vnet, and locking. I removed that
* code.
*/
return;
return 0;
dropit:
tp = tcp_drop(tp, ETIMEDOUT);
(void) tp; /* samkumar: prevent a compiler warning */
return 1;
}
void
int
tcp_timer_persist(struct tcpcb* tp)
{
uint32_t ticks = tcplp_sys_get_ticks();
int dropped = 0;
/* samkumar: I added this, to replace the code I removed below. */
KASSERT(tpistimeractive(tp, TT_PERSIST), ("Persist timer running, but unmarked\n"));
@@ -202,6 +206,7 @@ tcp_timer_persist(struct tcpcb* tp)
(ticks - tp->t_rcvtime >= tcp_maxpersistidle ||
ticks - tp->t_rcvtime >= TCP_REXMTVAL(tp) * tcp_totbackoff)) {
tp = tcp_drop(tp, ETIMEDOUT);
dropped = 1;
goto out;
}
@@ -212,6 +217,7 @@ tcp_timer_persist(struct tcpcb* tp)
if (tp->t_state > TCPS_CLOSE_WAIT &&
(ticks - tp->t_rcvtime) >= TCPTV_PERSMAX) {
tp = tcp_drop(tp, ETIMEDOUT);
dropped = 1;
goto out;
}
@@ -227,13 +233,14 @@ out:
* tracing/probes, vnet, and locking. I removed that code.
*/
(void) tp; /* samkumar: prevent a compiler warning */
return;
return dropped;
}
void
int
tcp_timer_2msl(struct tcpcb* tp)
{
uint32_t ticks = tcplp_sys_get_ticks();
int dropped = 0;
/* samkumar: I added this, to replace the code I removed below. */
KASSERT(tpistimeractive(tp, TT_2MSL), ("2MSL timer running, but unmarked\n"));
@@ -281,7 +288,8 @@ tcp_timer_2msl(struct tcpcb* tp)
if (tp->t_state == TCP6S_TIME_WAIT) {
tp = tcp_close(tp);
tcplp_sys_connection_lost(tp, CONN_LOST_NORMAL);
return;
dropped = 1;
return dropped;
}
/*
* samkumar: This if statement also used to check that an inpcb is still
@@ -297,6 +305,7 @@ tcp_timer_2msl(struct tcpcb* tp)
tpiscantrcv(tp)) {
tp = tcp_close(tp);
tcplp_sys_connection_lost(tp, CONN_LOST_NORMAL);
dropped = 1;
} else {
if (ticks - tp->t_rcvtime <= TP_MAXIDLE(tp)) {
/*
@@ -308,19 +317,22 @@ tcp_timer_2msl(struct tcpcb* tp)
} else {
tp = tcp_close(tp);
tcplp_sys_connection_lost(tp, CONN_LOST_NORMAL);
dropped = 1;
}
}
/*
* samkumar: There used to be some code here that handled debug
* tracing/probes, vnet, and locking. I removed that code.
*/
return dropped;
}
void
int
tcp_timer_rexmt(struct tcpcb *tp)
{
int rexmt;
uint32_t ticks = tcplp_sys_get_ticks();
int dropped = 0;
/* samkumar: I added this, to replace the code I removed below. */
KASSERT(tpistimeractive(tp, TT_REXMT), ("Rexmt timer running, but unmarked\n"));
@@ -348,6 +360,7 @@ tcp_timer_rexmt(struct tcpcb *tp)
tp = tcp_drop(tp, tp->t_softerror ?
tp->t_softerror : ETIMEDOUT);
dropped = 1;
goto out;
}
if (tp->t_state == TCPS_SYN_SENT) {
@@ -450,7 +463,7 @@ out:
* tracing/probes, vnet, and locking. I removed that code.
*/
(void) tp; /* samkumar: Prevent a compiler warning */
return;
return dropped;
}
int
+9 -5
View File
@@ -154,11 +154,15 @@ static const int tcp_backoff[TCP_MAXRXTSHIFT + 1] =
static const int tcp_totbackoff = 2559; /* sum of tcp_backoff[] */
void tcp_timer_delack(struct tcpcb* tp);
void tcp_timer_keep(struct tcpcb* tp);
void tcp_timer_persist(struct tcpcb* tp);
void tcp_timer_2msl(struct tcpcb* tp);
void tcp_timer_rexmt(struct tcpcb *tp);
/*
* samkumar: Changed return value to int to indicate whether connection was
* dropped or not.
*/
int tcp_timer_delack(struct tcpcb* tp);
int tcp_timer_keep(struct tcpcb* tp);
int tcp_timer_persist(struct tcpcb* tp);
int tcp_timer_2msl(struct tcpcb* tp);
int tcp_timer_rexmt(struct tcpcb *tp);
int tcp_timer_active(struct tcpcb *tp, uint32_t timer_type);
/*
+1 -8
View File
@@ -50,14 +50,6 @@ extern "C" {
#include <openthread/ip6.h>
#include <openthread/message.h>
#define hz 1000 // number of ticks per second
#define MICROS_PER_TICK 1000 // number of microseconds per tick
#define FRAMES_PER_SEG 5
#define FRAMECAP_6LOWPAN (122 - 11 - 5)
#define IP6HDR_SIZE (2 + 1 + 1 + 16 + 16) // IPHC header (2) + Next header (1) + Hop count (1) + Dest. addr (16) + Src. addr (16)
#define RELOOKUP_REQUIRED -1
#define CONN_LOST_NORMAL 0
@@ -85,6 +77,7 @@ void tcplp_sys_connection_lost(struct tcpcb* tcb, uint8_t errnum);
void tcplp_sys_on_state_change(struct tcpcb* tcb, int newstate);
void tcplp_sys_log(const char* format, ...);
bool tcplp_sys_autobind(otInstance *aInstance, const otSockAddr *aPeer, otSockAddr *aToBind, bool aBindAddress, bool aBindPort);
uint32_t tcplp_sys_generate_isn();
#ifdef __cplusplus
} // extern "C"