1 /*
2  *  Copyright (c) 2021, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file implements TCP/IPv6 sockets.
32  */
33 
34 #include "openthread-core-config.h"
35 
36 #if OPENTHREAD_CONFIG_TCP_ENABLE
37 
38 #include "tcp6.hpp"
39 
40 #include "common/as_core_type.hpp"
41 #include "common/code_utils.hpp"
42 #include "common/error.hpp"
43 #include "common/locator_getters.hpp"
44 #include "common/log.hpp"
45 #include "common/num_utils.hpp"
46 #include "common/random.hpp"
47 #include "instance/instance.hpp"
48 #include "net/checksum.hpp"
49 #include "net/ip6.hpp"
50 #include "net/netif.hpp"
51 
52 #include "../../third_party/tcplp/tcplp.h"
53 
54 namespace ot {
55 namespace Ip6 {
56 
57 RegisterLogModule("Tcp");
58 
59 static_assert(sizeof(struct tcpcb) == sizeof(Tcp::Endpoint::mTcb), "mTcb field in otTcpEndpoint is sized incorrectly");
60 static_assert(alignof(struct tcpcb) == alignof(decltype(Tcp::Endpoint::mTcb)),
61               "mTcb field in otTcpEndpoint is aligned incorrectly");
62 static_assert(offsetof(Tcp::Endpoint, mTcb) == 0, "mTcb field in otTcpEndpoint has nonzero offset");
63 
64 static_assert(sizeof(struct tcpcb_listen) == sizeof(Tcp::Listener::mTcbListen),
65               "mTcbListen field in otTcpListener is sized incorrectly");
66 static_assert(alignof(struct tcpcb_listen) == alignof(decltype(Tcp::Listener::mTcbListen)),
67               "mTcbListen field in otTcpListener is aligned incorrectly");
68 static_assert(offsetof(Tcp::Listener, mTcbListen) == 0, "mTcbListen field in otTcpEndpoint has nonzero offset");
69 
Tcp(Instance & aInstance)70 Tcp::Tcp(Instance &aInstance)
71     : InstanceLocator(aInstance)
72     , mTimer(aInstance)
73     , mTasklet(aInstance)
74     , mEphemeralPort(kDynamicPortMin)
75 {
76     OT_UNUSED_VARIABLE(mEphemeralPort);
77 }
78 
Initialize(Instance & aInstance,const otTcpEndpointInitializeArgs & aArgs)79 Error Tcp::Endpoint::Initialize(Instance &aInstance, const otTcpEndpointInitializeArgs &aArgs)
80 {
81     Error         error;
82     struct tcpcb &tp = GetTcb();
83 
84     memset(&tp, 0x00, sizeof(tp));
85 
86     SuccessOrExit(error = aInstance.Get<Tcp>().mEndpoints.Add(*this));
87 
88     mContext                  = aArgs.mContext;
89     mEstablishedCallback      = aArgs.mEstablishedCallback;
90     mSendDoneCallback         = aArgs.mSendDoneCallback;
91     mForwardProgressCallback  = aArgs.mForwardProgressCallback;
92     mReceiveAvailableCallback = aArgs.mReceiveAvailableCallback;
93     mDisconnectedCallback     = aArgs.mDisconnectedCallback;
94 
95     memset(mTimers, 0x00, sizeof(mTimers));
96     memset(&mSockAddr, 0x00, sizeof(mSockAddr));
97     mPendingCallbacks = 0;
98 
99     /*
100      * Initialize buffers --- formerly in initialize_tcb.
101      */
102     {
103         uint8_t *recvbuf    = static_cast<uint8_t *>(aArgs.mReceiveBuffer);
104         size_t   recvbuflen = aArgs.mReceiveBufferSize - ((aArgs.mReceiveBufferSize + 8) / 9);
105         uint8_t *reassbmp   = recvbuf + recvbuflen;
106 
107         lbuf_init(&tp.sendbuf);
108         cbuf_init(&tp.recvbuf, recvbuf, recvbuflen);
109         tp.reassbmp = reassbmp;
110         bmp_init(tp.reassbmp, BITS_TO_BYTES(recvbuflen));
111     }
112 
113     tp.accepted_from = nullptr;
114     initialize_tcb(&tp);
115 
116     /* Note that we do not need to zero-initialize mReceiveLinks. */
117 
118     tp.instance = &aInstance;
119 
120 exit:
121     return error;
122 }
123 
GetInstance(void) const124 Instance &Tcp::Endpoint::GetInstance(void) const { return AsNonConst(AsCoreType(GetTcb().instance)); }
125 
GetLocalAddress(void) const126 const SockAddr &Tcp::Endpoint::GetLocalAddress(void) const
127 {
128     const struct tcpcb &tp = GetTcb();
129 
130     static otSockAddr temp;
131 
132     memcpy(&temp.mAddress, &tp.laddr, sizeof(temp.mAddress));
133     temp.mPort = BigEndian::HostSwap16(tp.lport);
134 
135     return AsCoreType(&temp);
136 }
137 
GetPeerAddress(void) const138 const SockAddr &Tcp::Endpoint::GetPeerAddress(void) const
139 {
140     const struct tcpcb &tp = GetTcb();
141 
142     static otSockAddr temp;
143 
144     memcpy(&temp.mAddress, &tp.faddr, sizeof(temp.mAddress));
145     temp.mPort = BigEndian::HostSwap16(tp.fport);
146 
147     return AsCoreType(&temp);
148 }
149 
Bind(const SockAddr & aSockName)150 Error Tcp::Endpoint::Bind(const SockAddr &aSockName)
151 {
152     Error         error;
153     struct tcpcb &tp = GetTcb();
154 
155     VerifyOrExit(!AsCoreType(&aSockName.mAddress).IsUnspecified(), error = kErrorInvalidArgs);
156     VerifyOrExit(Get<Tcp>().CanBind(aSockName), error = kErrorInvalidState);
157 
158     memcpy(&tp.laddr, &aSockName.mAddress, sizeof(tp.laddr));
159     tp.lport = BigEndian::HostSwap16(aSockName.mPort);
160     error    = kErrorNone;
161 
162 exit:
163     return error;
164 }
165 
Connect(const SockAddr & aSockName,uint32_t aFlags)166 Error Tcp::Endpoint::Connect(const SockAddr &aSockName, uint32_t aFlags)
167 {
168     Error         error = kErrorNone;
169     struct tcpcb &tp    = GetTcb();
170 
171     VerifyOrExit(tp.t_state == TCP6S_CLOSED, error = kErrorInvalidState);
172 
173     if (aFlags & OT_TCP_CONNECT_NO_FAST_OPEN)
174     {
175         struct sockaddr_in6 sin6p;
176 
177         tp.t_flags &= ~TF_FASTOPEN;
178         memcpy(&sin6p.sin6_addr, &aSockName.mAddress, sizeof(sin6p.sin6_addr));
179         sin6p.sin6_port = BigEndian::HostSwap16(aSockName.mPort);
180         error           = BsdErrorToOtError(tcp6_usr_connect(&tp, &sin6p));
181     }
182     else
183     {
184         tp.t_flags |= TF_FASTOPEN;
185 
186         /* Stash the destination address in tp. */
187         memcpy(&tp.faddr, &aSockName.mAddress, sizeof(tp.faddr));
188         tp.fport = BigEndian::HostSwap16(aSockName.mPort);
189     }
190 
191 exit:
192     return error;
193 }
194 
SendByReference(otLinkedBuffer & aBuffer,uint32_t aFlags)195 Error Tcp::Endpoint::SendByReference(otLinkedBuffer &aBuffer, uint32_t aFlags)
196 {
197     Error         error;
198     struct tcpcb &tp = GetTcb();
199 
200     size_t backlogBefore = GetBacklogBytes();
201     size_t sent          = aBuffer.mLength;
202 
203     struct sockaddr_in6  sin6p;
204     struct sockaddr_in6 *name = nullptr;
205 
206     if (IS_FASTOPEN(tp.t_flags))
207     {
208         memcpy(&sin6p.sin6_addr, &tp.faddr, sizeof(sin6p.sin6_addr));
209         sin6p.sin6_port = tp.fport;
210         name            = &sin6p;
211     }
212     SuccessOrExit(
213         error = BsdErrorToOtError(tcp_usr_send(&tp, (aFlags & OT_TCP_SEND_MORE_TO_COME) != 0, &aBuffer, 0, name)));
214 
215     PostCallbacksAfterSend(sent, backlogBefore);
216 
217 exit:
218     return error;
219 }
220 
SendByExtension(size_t aNumBytes,uint32_t aFlags)221 Error Tcp::Endpoint::SendByExtension(size_t aNumBytes, uint32_t aFlags)
222 {
223     Error         error;
224     bool          moreToCome    = (aFlags & OT_TCP_SEND_MORE_TO_COME) != 0;
225     struct tcpcb &tp            = GetTcb();
226     size_t        backlogBefore = GetBacklogBytes();
227     int           bsdError;
228 
229     struct sockaddr_in6  sin6p;
230     struct sockaddr_in6 *name = nullptr;
231 
232     VerifyOrExit(lbuf_head(&tp.sendbuf) != nullptr, error = kErrorInvalidState);
233 
234     if (IS_FASTOPEN(tp.t_flags))
235     {
236         memcpy(&sin6p.sin6_addr, &tp.faddr, sizeof(sin6p.sin6_addr));
237         sin6p.sin6_port = tp.fport;
238         name            = &sin6p;
239     }
240 
241     bsdError = tcp_usr_send(&tp, moreToCome ? 1 : 0, nullptr, aNumBytes, name);
242     SuccessOrExit(error = BsdErrorToOtError(bsdError));
243 
244     PostCallbacksAfterSend(aNumBytes, backlogBefore);
245 
246 exit:
247     return error;
248 }
249 
ReceiveByReference(const otLinkedBuffer * & aBuffer)250 Error Tcp::Endpoint::ReceiveByReference(const otLinkedBuffer *&aBuffer)
251 {
252     struct tcpcb &tp = GetTcb();
253 
254     cbuf_reference(&tp.recvbuf, &mReceiveLinks[0], &mReceiveLinks[1]);
255     aBuffer = &mReceiveLinks[0];
256 
257     return kErrorNone;
258 }
259 
ReceiveContiguify(void)260 Error Tcp::Endpoint::ReceiveContiguify(void)
261 {
262     struct tcpcb &tp = GetTcb();
263 
264     cbuf_contiguify(&tp.recvbuf, tp.reassbmp);
265 
266     return kErrorNone;
267 }
268 
CommitReceive(size_t aNumBytes,uint32_t aFlags)269 Error Tcp::Endpoint::CommitReceive(size_t aNumBytes, uint32_t aFlags)
270 {
271     Error         error = kErrorNone;
272     struct tcpcb &tp    = GetTcb();
273 
274     OT_UNUSED_VARIABLE(aFlags);
275 
276     VerifyOrExit(cbuf_used_space(&tp.recvbuf) >= aNumBytes, error = kErrorFailed);
277     VerifyOrExit(aNumBytes > 0, error = kErrorNone);
278 
279     cbuf_pop(&tp.recvbuf, aNumBytes);
280     error = BsdErrorToOtError(tcp_usr_rcvd(&tp));
281 
282 exit:
283     return error;
284 }
285 
SendEndOfStream(void)286 Error Tcp::Endpoint::SendEndOfStream(void)
287 {
288     struct tcpcb &tp = GetTcb();
289 
290     return BsdErrorToOtError(tcp_usr_shutdown(&tp));
291 }
292 
Abort(void)293 Error Tcp::Endpoint::Abort(void)
294 {
295     struct tcpcb &tp = GetTcb();
296 
297     tcp_usr_abort(&tp);
298     /* connection_lost will do any reinitialization work for this socket. */
299     return kErrorNone;
300 }
301 
Deinitialize(void)302 Error Tcp::Endpoint::Deinitialize(void)
303 {
304     Error error;
305 
306     SuccessOrExit(error = Get<Tcp>().mEndpoints.Remove(*this));
307     SetNext(nullptr);
308 
309     SuccessOrExit(error = Abort());
310 
311 exit:
312     return error;
313 }
314 
IsClosed(void) const315 bool Tcp::Endpoint::IsClosed(void) const { return GetTcb().t_state == TCP6S_CLOSED; }
316 
TimerFlagToIndex(uint8_t aTimerFlag)317 uint8_t Tcp::Endpoint::TimerFlagToIndex(uint8_t aTimerFlag)
318 {
319     uint8_t timerIndex = 0;
320 
321     switch (aTimerFlag)
322     {
323     case TT_DELACK:
324         timerIndex = kTimerDelack;
325         break;
326     case TT_REXMT:
327     case TT_PERSIST:
328         timerIndex = kTimerRexmtPersist;
329         break;
330     case TT_KEEP:
331         timerIndex = kTimerKeep;
332         break;
333     case TT_2MSL:
334         timerIndex = kTimer2Msl;
335         break;
336     }
337 
338     return timerIndex;
339 }
340 
IsTimerActive(uint8_t aTimerIndex)341 bool Tcp::Endpoint::IsTimerActive(uint8_t aTimerIndex)
342 {
343     bool          active = false;
344     struct tcpcb *tp     = &GetTcb();
345 
346     OT_ASSERT(aTimerIndex < kNumTimers);
347     switch (aTimerIndex)
348     {
349     case kTimerDelack:
350         active = tcp_timer_active(tp, TT_DELACK);
351         break;
352     case kTimerRexmtPersist:
353         active = tcp_timer_active(tp, TT_REXMT) || tcp_timer_active(tp, TT_PERSIST);
354         break;
355     case kTimerKeep:
356         active = tcp_timer_active(tp, TT_KEEP);
357         break;
358     case kTimer2Msl:
359         active = tcp_timer_active(tp, TT_2MSL);
360         break;
361     }
362 
363     return active;
364 }
365 
SetTimer(uint8_t aTimerFlag,uint32_t aDelay)366 void Tcp::Endpoint::SetTimer(uint8_t aTimerFlag, uint32_t aDelay)
367 {
368     /*
369      * TCPlp has already set the flag for this timer to record that it's
370      * running. So, all that's left to do is record the expiry time and
371      * (re)set the main timer as appropriate.
372      */
373 
374     TimeMilli now         = TimerMilli::GetNow();
375     TimeMilli newFireTime = now + aDelay;
376     uint8_t   timerIndex  = TimerFlagToIndex(aTimerFlag);
377 
378     mTimers[timerIndex] = newFireTime.GetValue();
379     LogDebg("Endpoint %p set timer %u to %u ms", static_cast<void *>(this), static_cast<unsigned int>(timerIndex),
380             static_cast<unsigned int>(aDelay));
381 
382     Get<Tcp>().mTimer.FireAtIfEarlier(newFireTime);
383 }
384 
CancelTimer(uint8_t aTimerFlag)385 void Tcp::Endpoint::CancelTimer(uint8_t aTimerFlag)
386 {
387     /*
388      * TCPlp has already cleared the timer flag before calling this. Since the
389      * main timer's callback properly handles the case where no timers are
390      * actually due, there's actually no work to be done here.
391      */
392 
393     OT_UNUSED_VARIABLE(aTimerFlag);
394 
395     LogDebg("Endpoint %p cancelled timer %u", static_cast<void *>(this),
396             static_cast<unsigned int>(TimerFlagToIndex(aTimerFlag)));
397 }
398 
FirePendingTimers(TimeMilli aNow,bool & aHasFutureTimer,TimeMilli & aEarliestFutureExpiry)399 bool Tcp::Endpoint::FirePendingTimers(TimeMilli aNow, bool &aHasFutureTimer, TimeMilli &aEarliestFutureExpiry)
400 {
401     bool          calledUserCallback = false;
402     struct tcpcb *tp                 = &GetTcb();
403 
404     /*
405      * NOTE: Firing a timer might potentially activate/deactivate other timers.
406      * If timers x and y expire at the same time, but the callback for timer x
407      * (for x < y) cancels or postpones timer y, should timer y's callback be
408      * called? Our answer is no, since timer x's callback has updated the
409      * TCP stack's state in such a way that it no longer expects timer y's
410      * callback to to be called. Because the TCP stack thinks that timer y
411      * has been cancelled, calling timer y's callback could potentially cause
412      * problems.
413      *
414      * If the timer callbacks set other timers, then they may not be taken
415      * into account when setting aEarliestFutureExpiry. But mTimer's expiry
416      * time will be updated by those, so we can just compare against mTimer's
417      * expiry time when resetting mTimer.
418      */
419     for (uint8_t timerIndex = 0; timerIndex != kNumTimers; timerIndex++)
420     {
421         if (IsTimerActive(timerIndex))
422         {
423             TimeMilli expiry(mTimers[timerIndex]);
424 
425             if (expiry <= aNow)
426             {
427                 /*
428                  * If a user callback is called, then return true. For TCPlp,
429                  * this only happens if the connection is dropped (e.g., it
430                  * times out).
431                  */
432                 int dropped = 0;
433 
434                 switch (timerIndex)
435                 {
436                 case kTimerDelack:
437                     dropped = tcp_timer_delack(tp);
438                     break;
439                 case kTimerRexmtPersist:
440                     if (tcp_timer_active(tp, TT_REXMT))
441                     {
442                         dropped = tcp_timer_rexmt(tp);
443                     }
444                     else
445                     {
446                         dropped = tcp_timer_persist(tp);
447                     }
448                     break;
449                 case kTimerKeep:
450                     dropped = tcp_timer_keep(tp);
451                     break;
452                 case kTimer2Msl:
453                     dropped = tcp_timer_2msl(tp);
454                     break;
455                 }
456                 VerifyOrExit(dropped == 0, calledUserCallback = true);
457             }
458             else
459             {
460                 aHasFutureTimer       = true;
461                 aEarliestFutureExpiry = Min(aEarliestFutureExpiry, expiry);
462             }
463         }
464     }
465 
466 exit:
467     return calledUserCallback;
468 }
469 
PostCallbacksAfterSend(size_t aSent,size_t aBacklogBefore)470 void Tcp::Endpoint::PostCallbacksAfterSend(size_t aSent, size_t aBacklogBefore)
471 {
472     size_t backlogAfter = GetBacklogBytes();
473 
474     if (backlogAfter < aBacklogBefore + aSent && mForwardProgressCallback != nullptr)
475     {
476         mPendingCallbacks |= kForwardProgressCallbackFlag;
477         Get<Tcp>().mTasklet.Post();
478     }
479 }
480 
FirePendingCallbacks(void)481 bool Tcp::Endpoint::FirePendingCallbacks(void)
482 {
483     bool calledUserCallback = false;
484 
485     if ((mPendingCallbacks & kForwardProgressCallbackFlag) != 0 && mForwardProgressCallback != nullptr)
486     {
487         mForwardProgressCallback(this, GetSendBufferBytes(), GetBacklogBytes());
488         calledUserCallback = true;
489     }
490 
491     mPendingCallbacks = 0;
492 
493     return calledUserCallback;
494 }
495 
GetSendBufferBytes(void) const496 size_t Tcp::Endpoint::GetSendBufferBytes(void) const
497 {
498     const struct tcpcb &tp = GetTcb();
499     return lbuf_used_space(&tp.sendbuf);
500 }
501 
GetInFlightBytes(void) const502 size_t Tcp::Endpoint::GetInFlightBytes(void) const
503 {
504     const struct tcpcb &tp = GetTcb();
505     return tp.snd_max - tp.snd_una;
506 }
507 
GetBacklogBytes(void) const508 size_t Tcp::Endpoint::GetBacklogBytes(void) const { return GetSendBufferBytes() - GetInFlightBytes(); }
509 
GetLocalIp6Address(void)510 Address &Tcp::Endpoint::GetLocalIp6Address(void) { return *reinterpret_cast<Address *>(&GetTcb().laddr); }
511 
GetLocalIp6Address(void) const512 const Address &Tcp::Endpoint::GetLocalIp6Address(void) const
513 {
514     return *reinterpret_cast<const Address *>(&GetTcb().laddr);
515 }
516 
GetForeignIp6Address(void)517 Address &Tcp::Endpoint::GetForeignIp6Address(void) { return *reinterpret_cast<Address *>(&GetTcb().faddr); }
518 
GetForeignIp6Address(void) const519 const Address &Tcp::Endpoint::GetForeignIp6Address(void) const
520 {
521     return *reinterpret_cast<const Address *>(&GetTcb().faddr);
522 }
523 
Matches(const MessageInfo & aMessageInfo) const524 bool Tcp::Endpoint::Matches(const MessageInfo &aMessageInfo) const
525 {
526     bool                matches = false;
527     const struct tcpcb *tp      = &GetTcb();
528 
529     VerifyOrExit(tp->t_state != TCP6S_CLOSED);
530     VerifyOrExit(tp->lport == BigEndian::HostSwap16(aMessageInfo.GetSockPort()));
531     VerifyOrExit(tp->fport == BigEndian::HostSwap16(aMessageInfo.GetPeerPort()));
532     VerifyOrExit(GetLocalIp6Address().IsUnspecified() || GetLocalIp6Address() == aMessageInfo.GetSockAddr());
533     VerifyOrExit(GetForeignIp6Address() == aMessageInfo.GetPeerAddr());
534 
535     matches = true;
536 
537 exit:
538     return matches;
539 }
540 
Initialize(Instance & aInstance,const otTcpListenerInitializeArgs & aArgs)541 Error Tcp::Listener::Initialize(Instance &aInstance, const otTcpListenerInitializeArgs &aArgs)
542 {
543     Error                error;
544     struct tcpcb_listen *tpl = &GetTcbListen();
545 
546     SuccessOrExit(error = aInstance.Get<Tcp>().mListeners.Add(*this));
547 
548     mContext             = aArgs.mContext;
549     mAcceptReadyCallback = aArgs.mAcceptReadyCallback;
550     mAcceptDoneCallback  = aArgs.mAcceptDoneCallback;
551 
552     memset(tpl, 0x00, sizeof(struct tcpcb_listen));
553     tpl->instance = &aInstance;
554 
555 exit:
556     return error;
557 }
558 
GetInstance(void) const559 Instance &Tcp::Listener::GetInstance(void) const { return AsNonConst(AsCoreType(GetTcbListen().instance)); }
560 
Listen(const SockAddr & aSockName)561 Error Tcp::Listener::Listen(const SockAddr &aSockName)
562 {
563     Error                error;
564     uint16_t             port = BigEndian::HostSwap16(aSockName.mPort);
565     struct tcpcb_listen *tpl  = &GetTcbListen();
566 
567     VerifyOrExit(Get<Tcp>().CanBind(aSockName), error = kErrorInvalidState);
568 
569     memcpy(&tpl->laddr, &aSockName.mAddress, sizeof(tpl->laddr));
570     tpl->lport   = port;
571     tpl->t_state = TCP6S_LISTEN;
572     error        = kErrorNone;
573 
574 exit:
575     return error;
576 }
577 
StopListening(void)578 Error Tcp::Listener::StopListening(void)
579 {
580     struct tcpcb_listen *tpl = &GetTcbListen();
581 
582     memset(&tpl->laddr, 0x00, sizeof(tpl->laddr));
583     tpl->lport   = 0;
584     tpl->t_state = TCP6S_CLOSED;
585     return kErrorNone;
586 }
587 
Deinitialize(void)588 Error Tcp::Listener::Deinitialize(void)
589 {
590     Error error;
591 
592     SuccessOrExit(error = Get<Tcp>().mListeners.Remove(*this));
593     SetNext(nullptr);
594 
595 exit:
596     return error;
597 }
598 
IsClosed(void) const599 bool Tcp::Listener::IsClosed(void) const { return GetTcbListen().t_state == TCP6S_CLOSED; }
600 
GetLocalIp6Address(void)601 Address &Tcp::Listener::GetLocalIp6Address(void) { return *reinterpret_cast<Address *>(&GetTcbListen().laddr); }
602 
GetLocalIp6Address(void) const603 const Address &Tcp::Listener::GetLocalIp6Address(void) const
604 {
605     return *reinterpret_cast<const Address *>(&GetTcbListen().laddr);
606 }
607 
Matches(const MessageInfo & aMessageInfo) const608 bool Tcp::Listener::Matches(const MessageInfo &aMessageInfo) const
609 {
610     bool                       matches = false;
611     const struct tcpcb_listen *tpl     = &GetTcbListen();
612 
613     VerifyOrExit(tpl->t_state == TCP6S_LISTEN);
614     VerifyOrExit(tpl->lport == BigEndian::HostSwap16(aMessageInfo.GetSockPort()));
615     VerifyOrExit(GetLocalIp6Address().IsUnspecified() || GetLocalIp6Address() == aMessageInfo.GetSockAddr());
616 
617     matches = true;
618 
619 exit:
620     return matches;
621 }
622 
HandleMessage(ot::Ip6::Header & aIp6Header,Message & aMessage,MessageInfo & aMessageInfo)623 Error Tcp::HandleMessage(ot::Ip6::Header &aIp6Header, Message &aMessage, MessageInfo &aMessageInfo)
624 {
625     Error error = kErrorNotImplemented;
626 
627     /*
628      * The type uint32_t was chosen for alignment purposes. The size is the
629      * maximum TCP header size, including options.
630      */
631     uint32_t header[15];
632 
633     uint16_t length = aIp6Header.GetPayloadLength();
634     uint8_t  headerSize;
635 
636     struct ip6_hdr *ip6Header;
637     struct tcphdr  *tcpHeader;
638 
639     Endpoint *endpoint;
640     Endpoint *endpointPrev;
641 
642     Listener *listener;
643     Listener *listenerPrev;
644 
645     struct tcplp_signals sig;
646     int                  nextAction;
647 
648     VerifyOrExit(length == aMessage.GetLength() - aMessage.GetOffset(), error = kErrorParse);
649     VerifyOrExit(length >= sizeof(Tcp::Header), error = kErrorParse);
650     SuccessOrExit(error = aMessage.Read(aMessage.GetOffset() + offsetof(struct tcphdr, th_off_x2), headerSize));
651     headerSize = static_cast<uint8_t>((headerSize >> TH_OFF_SHIFT) << 2);
652     VerifyOrExit(headerSize >= sizeof(struct tcphdr) && headerSize <= sizeof(header) &&
653                      static_cast<uint16_t>(headerSize) <= length,
654                  error = kErrorParse);
655     SuccessOrExit(error = Checksum::VerifyMessageChecksum(aMessage, aMessageInfo, kProtoTcp));
656     SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), &header[0], headerSize));
657 
658     ip6Header = reinterpret_cast<struct ip6_hdr *>(&aIp6Header);
659     tcpHeader = reinterpret_cast<struct tcphdr *>(&header[0]);
660     tcp_fields_to_host(tcpHeader);
661 
662     aMessageInfo.mPeerPort = BigEndian::HostSwap16(tcpHeader->th_sport);
663     aMessageInfo.mSockPort = BigEndian::HostSwap16(tcpHeader->th_dport);
664 
665     endpoint = mEndpoints.FindMatching(aMessageInfo, endpointPrev);
666     if (endpoint != nullptr)
667     {
668         struct tcpcb *tp = &endpoint->GetTcb();
669 
670         otLinkedBuffer *priorHead    = lbuf_head(&tp->sendbuf);
671         size_t          priorBacklog = endpoint->GetSendBufferBytes() - endpoint->GetInFlightBytes();
672 
673         memset(&sig, 0x00, sizeof(sig));
674         nextAction = tcp_input(ip6Header, tcpHeader, &aMessage, tp, nullptr, &sig);
675         if (nextAction != RELOOKUP_REQUIRED)
676         {
677             ProcessSignals(*endpoint, priorHead, priorBacklog, sig);
678             ExitNow();
679         }
680         /* If the matching socket was in the TIME-WAIT state, then we try passive sockets. */
681     }
682 
683     listener = mListeners.FindMatching(aMessageInfo, listenerPrev);
684     if (listener != nullptr)
685     {
686         struct tcpcb_listen *tpl = &listener->GetTcbListen();
687 
688         memset(&sig, 0x00, sizeof(sig));
689         nextAction = tcp_input(ip6Header, tcpHeader, &aMessage, nullptr, tpl, &sig);
690         OT_ASSERT(nextAction != RELOOKUP_REQUIRED);
691         if (sig.accepted_connection != nullptr)
692         {
693             ProcessSignals(Tcp::Endpoint::FromTcb(*sig.accepted_connection), nullptr, 0, sig);
694         }
695         ExitNow();
696     }
697 
698     tcp_dropwithreset(ip6Header, tcpHeader, nullptr, &InstanceLocator::GetInstance(), length - headerSize,
699                       ECONNREFUSED);
700 
701 exit:
702     return error;
703 }
704 
ProcessSignals(Endpoint & aEndpoint,otLinkedBuffer * aPriorHead,size_t aPriorBacklog,struct tcplp_signals & aSignals) const705 void Tcp::ProcessSignals(Endpoint             &aEndpoint,
706                          otLinkedBuffer       *aPriorHead,
707                          size_t                aPriorBacklog,
708                          struct tcplp_signals &aSignals) const
709 {
710     VerifyOrExit(IsInitialized(aEndpoint) && !aEndpoint.IsClosed());
711     if (aSignals.conn_established && aEndpoint.mEstablishedCallback != nullptr)
712     {
713         aEndpoint.mEstablishedCallback(&aEndpoint);
714     }
715 
716     VerifyOrExit(IsInitialized(aEndpoint) && !aEndpoint.IsClosed());
717     if (aEndpoint.mSendDoneCallback != nullptr)
718     {
719         otLinkedBuffer *curr = aPriorHead;
720 
721         OT_ASSERT(curr != nullptr || aSignals.links_popped == 0);
722 
723         for (uint32_t i = 0; i != aSignals.links_popped; i++)
724         {
725             otLinkedBuffer *next = curr->mNext;
726 
727             VerifyOrExit(i == 0 || (IsInitialized(aEndpoint) && !aEndpoint.IsClosed()));
728 
729             curr->mNext = nullptr;
730             aEndpoint.mSendDoneCallback(&aEndpoint, curr);
731             curr = next;
732         }
733     }
734 
735     VerifyOrExit(IsInitialized(aEndpoint) && !aEndpoint.IsClosed());
736     if (aEndpoint.mForwardProgressCallback != nullptr)
737     {
738         size_t backlogBytes = aEndpoint.GetBacklogBytes();
739 
740         if (aSignals.bytes_acked > 0 || backlogBytes < aPriorBacklog)
741         {
742             aEndpoint.mForwardProgressCallback(&aEndpoint, aEndpoint.GetSendBufferBytes(), backlogBytes);
743             aEndpoint.mPendingCallbacks &= ~kForwardProgressCallbackFlag;
744         }
745     }
746 
747     VerifyOrExit(IsInitialized(aEndpoint) && !aEndpoint.IsClosed());
748     if ((aSignals.recvbuf_added || aSignals.rcvd_fin) && aEndpoint.mReceiveAvailableCallback != nullptr)
749     {
750         aEndpoint.mReceiveAvailableCallback(&aEndpoint, cbuf_used_space(&aEndpoint.GetTcb().recvbuf),
751                                             aEndpoint.GetTcb().reass_fin_index != -1,
752                                             cbuf_free_space(&aEndpoint.GetTcb().recvbuf));
753     }
754 
755     VerifyOrExit(IsInitialized(aEndpoint) && !aEndpoint.IsClosed());
756     if (aEndpoint.GetTcb().t_state == TCP6S_TIME_WAIT && aEndpoint.mDisconnectedCallback != nullptr)
757     {
758         aEndpoint.mDisconnectedCallback(&aEndpoint, OT_TCP_DISCONNECTED_REASON_TIME_WAIT);
759     }
760 
761 exit:
762     return;
763 }
764 
BsdErrorToOtError(int aBsdError)765 Error Tcp::BsdErrorToOtError(int aBsdError)
766 {
767     Error error = kErrorFailed;
768 
769     switch (aBsdError)
770     {
771     case 0:
772         error = kErrorNone;
773         break;
774     }
775 
776     return error;
777 }
778 
CanBind(const SockAddr & aSockName)779 bool Tcp::CanBind(const SockAddr &aSockName)
780 {
781     uint16_t port    = BigEndian::HostSwap16(aSockName.mPort);
782     bool     allowed = false;
783 
784     for (Endpoint &endpoint : mEndpoints)
785     {
786         struct tcpcb *tp = &endpoint.GetTcb();
787 
788         if (tp->lport == port)
789         {
790             VerifyOrExit(!aSockName.GetAddress().IsUnspecified());
791             VerifyOrExit(!reinterpret_cast<Address *>(&tp->laddr)->IsUnspecified());
792             VerifyOrExit(memcmp(&endpoint.GetTcb().laddr, &aSockName.mAddress, sizeof(tp->laddr)) != 0);
793         }
794     }
795 
796     for (Listener &listener : mListeners)
797     {
798         struct tcpcb_listen *tpl = &listener.GetTcbListen();
799 
800         if (tpl->lport == port)
801         {
802             VerifyOrExit(!aSockName.GetAddress().IsUnspecified());
803             VerifyOrExit(!reinterpret_cast<Address *>(&tpl->laddr)->IsUnspecified());
804             VerifyOrExit(memcmp(&tpl->laddr, &aSockName.mAddress, sizeof(tpl->laddr)) != 0);
805         }
806     }
807 
808     allowed = true;
809 
810 exit:
811     return allowed;
812 }
813 
AutoBind(const SockAddr & aPeer,SockAddr & aToBind,bool aBindAddress,bool aBindPort)814 bool Tcp::AutoBind(const SockAddr &aPeer, SockAddr &aToBind, bool aBindAddress, bool aBindPort)
815 {
816     bool success;
817 
818     if (aBindAddress)
819     {
820         const Address *source;
821 
822         source = Get<Ip6>().SelectSourceAddress(aPeer.GetAddress());
823         VerifyOrExit(source != nullptr, success = false);
824         aToBind.SetAddress(*source);
825     }
826 
827     if (aBindPort)
828     {
829         /*
830          * TODO: Use a less naive algorithm to allocate ephemeral ports. For
831          * example, see RFC 6056.
832          */
833 
834         for (uint16_t i = 0; i != kDynamicPortMax - kDynamicPortMin + 1; i++)
835         {
836             aToBind.SetPort(mEphemeralPort);
837 
838             if (mEphemeralPort == kDynamicPortMax)
839             {
840                 mEphemeralPort = kDynamicPortMin;
841             }
842             else
843             {
844                 mEphemeralPort++;
845             }
846 
847             if (CanBind(aToBind))
848             {
849                 ExitNow(success = true);
850             }
851         }
852 
853         ExitNow(success = false);
854     }
855 
856     success = CanBind(aToBind);
857 
858 exit:
859     return success;
860 }
861 
HandleTimer(void)862 void Tcp::HandleTimer(void)
863 {
864     TimeMilli now = TimerMilli::GetNow();
865     bool      pendingTimer;
866     TimeMilli earliestPendingTimerExpiry;
867 
868     LogDebg("Main TCP timer expired");
869 
870     /*
871      * The timer callbacks could potentially set/reset/cancel timers.
872      * Importantly, Endpoint::SetTimer and Endpoint::CancelTimer do not call
873      * this function to recompute the timer. If they did, we'd have a
874      * re-entrancy problem, where the callbacks called in this function could
875      * wind up re-entering this function in a nested call frame.
876      *
877      * In general, calling this function from Endpoint::SetTimer and
878      * Endpoint::CancelTimer could be inefficient, since those functions are
879      * called multiple times on each received TCP segment. If we want to
880      * prevent the main timer from firing except when an actual TCP timer
881      * expires, a better alternative is to reset the main timer in
882      * HandleMessage, right before processing signals. That would achieve that
883      * objective while avoiding re-entrancy issues altogether.
884      */
885 restart:
886     pendingTimer               = false;
887     earliestPendingTimerExpiry = now.GetDistantFuture();
888 
889     for (Endpoint &endpoint : mEndpoints)
890     {
891         if (endpoint.FirePendingTimers(now, pendingTimer, earliestPendingTimerExpiry))
892         {
893             /*
894              * If a non-OpenThread callback is called --- which, in practice,
895              * happens if the connection times out and the user-defined
896              * connection lost callback is called --- then we might have to
897              * start over. The reason is that the user might deinitialize
898              * endpoints, changing the structure of the linked list. For
899              * example, if the user deinitializes both this endpoint and the
900              * next one in the linked list, then we can't continue traversing
901              * the linked list.
902              */
903             goto restart;
904         }
905     }
906 
907     if (pendingTimer)
908     {
909         /*
910          * We need to use Timer::FireAtIfEarlier instead of timer::FireAt
911          * because one of the earlier callbacks might have set TCP timers,
912          * in which case `mTimer` would have been set to the earliest of those
913          * timers.
914          */
915         mTimer.FireAtIfEarlier(earliestPendingTimerExpiry);
916         LogDebg("Reset main TCP timer to %u ms", static_cast<unsigned int>(earliestPendingTimerExpiry - now));
917     }
918     else
919     {
920         LogDebg("Did not reset main TCP timer");
921     }
922 }
923 
ProcessCallbacks(void)924 void Tcp::ProcessCallbacks(void)
925 {
926     for (Endpoint &endpoint : mEndpoints)
927     {
928         if (endpoint.FirePendingCallbacks())
929         {
930             mTasklet.Post();
931             break;
932         }
933     }
934 }
935 
936 } // namespace Ip6
937 } // namespace ot
938 
939 /*
940  * Implement TCPlp system stubs declared in tcplp.h.
941  *
942  * Because these functions have C linkage, it is important that only one
943  * definition is given for each function name, regardless of the namespace it
944  * in. For example, if we give two definitions of tcplp_sys_new_message, we
945  * will get errors, even if they are in different namespaces. To avoid
946  * confusion, I've put these functions outside of any namespace.
947  */
948 
949 using namespace ot;
950 using namespace ot::Ip6;
951 
952 extern "C" {
953 
tcplp_sys_new_message(otInstance * aInstance)954 otMessage *tcplp_sys_new_message(otInstance *aInstance)
955 {
956     Instance &instance = AsCoreType(aInstance);
957     Message  *message  = instance.Get<ot::Ip6::Ip6>().NewMessage(0);
958 
959     if (message)
960     {
961         message->SetLinkSecurityEnabled(true);
962     }
963 
964     return message;
965 }
966 
tcplp_sys_free_message(otInstance * aInstance,otMessage * aMessage)967 void tcplp_sys_free_message(otInstance *aInstance, otMessage *aMessage)
968 {
969     OT_UNUSED_VARIABLE(aInstance);
970     Message &message = AsCoreType(aMessage);
971     message.Free();
972 }
973 
tcplp_sys_send_message(otInstance * aInstance,otMessage * aMessage,otMessageInfo * aMessageInfo)974 void tcplp_sys_send_message(otInstance *aInstance, otMessage *aMessage, otMessageInfo *aMessageInfo)
975 {
976     Instance    &instance = AsCoreType(aInstance);
977     Message     &message  = AsCoreType(aMessage);
978     MessageInfo &info     = AsCoreType(aMessageInfo);
979 
980     LogDebg("Sending TCP segment: payload_size = %d", static_cast<int>(message.GetLength()));
981 
982     IgnoreError(instance.Get<ot::Ip6::Ip6>().SendDatagram(message, info, kProtoTcp));
983 }
984 
tcplp_sys_get_ticks(void)985 uint32_t tcplp_sys_get_ticks(void) { return TimerMilli::GetNow().GetValue(); }
986 
tcplp_sys_get_millis(void)987 uint32_t tcplp_sys_get_millis(void) { return TimerMilli::GetNow().GetValue(); }
988 
tcplp_sys_set_timer(struct tcpcb * aTcb,uint8_t aTimerFlag,uint32_t aDelay)989 void tcplp_sys_set_timer(struct tcpcb *aTcb, uint8_t aTimerFlag, uint32_t aDelay)
990 {
991     Tcp::Endpoint &endpoint = Tcp::Endpoint::FromTcb(*aTcb);
992     endpoint.SetTimer(aTimerFlag, aDelay);
993 }
994 
tcplp_sys_stop_timer(struct tcpcb * aTcb,uint8_t aTimerFlag)995 void tcplp_sys_stop_timer(struct tcpcb *aTcb, uint8_t aTimerFlag)
996 {
997     Tcp::Endpoint &endpoint = Tcp::Endpoint::FromTcb(*aTcb);
998     endpoint.CancelTimer(aTimerFlag);
999 }
1000 
tcplp_sys_accept_ready(struct tcpcb_listen * aTcbListen,struct in6_addr * aAddr,uint16_t aPort)1001 struct tcpcb *tcplp_sys_accept_ready(struct tcpcb_listen *aTcbListen, struct in6_addr *aAddr, uint16_t aPort)
1002 {
1003     Tcp::Listener                &listener = Tcp::Listener::FromTcbListen(*aTcbListen);
1004     Tcp                          &tcp      = listener.Get<Tcp>();
1005     struct tcpcb                 *rv       = (struct tcpcb *)-1;
1006     otSockAddr                    addr;
1007     otTcpEndpoint                *endpointPtr;
1008     otTcpIncomingConnectionAction action;
1009 
1010     VerifyOrExit(listener.mAcceptReadyCallback != nullptr);
1011 
1012     memcpy(&addr.mAddress, aAddr, sizeof(addr.mAddress));
1013     addr.mPort = BigEndian::HostSwap16(aPort);
1014     action     = listener.mAcceptReadyCallback(&listener, &addr, &endpointPtr);
1015 
1016     VerifyOrExit(tcp.IsInitialized(listener) && !listener.IsClosed());
1017 
1018     switch (action)
1019     {
1020     case OT_TCP_INCOMING_CONNECTION_ACTION_ACCEPT:
1021     {
1022         Tcp::Endpoint &endpoint = AsCoreType(endpointPtr);
1023 
1024         /*
1025          * The documentation says that the user must initialize the
1026          * endpoint before passing it here, so we do a sanity check to make
1027          * sure the endpoint is initialized and closed. That check may not
1028          * be necessary, but we do it anyway.
1029          */
1030         VerifyOrExit(tcp.IsInitialized(endpoint) && endpoint.IsClosed());
1031 
1032         rv = &endpoint.GetTcb();
1033 
1034         break;
1035     }
1036     case OT_TCP_INCOMING_CONNECTION_ACTION_DEFER:
1037         rv = nullptr;
1038         break;
1039     case OT_TCP_INCOMING_CONNECTION_ACTION_REFUSE:
1040         rv = (struct tcpcb *)-1;
1041         break;
1042     }
1043 
1044 exit:
1045     return rv;
1046 }
1047 
tcplp_sys_accepted_connection(struct tcpcb_listen * aTcbListen,struct tcpcb * aAccepted,struct in6_addr * aAddr,uint16_t aPort)1048 bool tcplp_sys_accepted_connection(struct tcpcb_listen *aTcbListen,
1049                                    struct tcpcb        *aAccepted,
1050                                    struct in6_addr     *aAddr,
1051                                    uint16_t             aPort)
1052 {
1053     Tcp::Listener &listener = Tcp::Listener::FromTcbListen(*aTcbListen);
1054     Tcp::Endpoint &endpoint = Tcp::Endpoint::FromTcb(*aAccepted);
1055     Tcp           &tcp      = endpoint.Get<Tcp>();
1056     bool           accepted = true;
1057 
1058     if (listener.mAcceptDoneCallback != nullptr)
1059     {
1060         otSockAddr addr;
1061 
1062         memcpy(&addr.mAddress, aAddr, sizeof(addr.mAddress));
1063         addr.mPort = BigEndian::HostSwap16(aPort);
1064         listener.mAcceptDoneCallback(&listener, &endpoint, &addr);
1065 
1066         if (!tcp.IsInitialized(endpoint) || endpoint.IsClosed())
1067         {
1068             accepted = false;
1069         }
1070     }
1071 
1072     return accepted;
1073 }
1074 
tcplp_sys_connection_lost(struct tcpcb * aTcb,uint8_t aErrNum)1075 void tcplp_sys_connection_lost(struct tcpcb *aTcb, uint8_t aErrNum)
1076 {
1077     Tcp::Endpoint &endpoint = Tcp::Endpoint::FromTcb(*aTcb);
1078 
1079     if (endpoint.mDisconnectedCallback != nullptr)
1080     {
1081         otTcpDisconnectedReason reason;
1082 
1083         switch (aErrNum)
1084         {
1085         case CONN_LOST_NORMAL:
1086             reason = OT_TCP_DISCONNECTED_REASON_NORMAL;
1087             break;
1088         case ECONNREFUSED:
1089             reason = OT_TCP_DISCONNECTED_REASON_REFUSED;
1090             break;
1091         case ETIMEDOUT:
1092             reason = OT_TCP_DISCONNECTED_REASON_TIMED_OUT;
1093             break;
1094         case ECONNRESET:
1095         default:
1096             reason = OT_TCP_DISCONNECTED_REASON_RESET;
1097             break;
1098         }
1099         endpoint.mDisconnectedCallback(&endpoint, reason);
1100     }
1101 }
1102 
tcplp_sys_on_state_change(struct tcpcb * aTcb,int aNewState)1103 void tcplp_sys_on_state_change(struct tcpcb *aTcb, int aNewState)
1104 {
1105     if (aNewState == TCP6S_CLOSED)
1106     {
1107         /* Re-initialize the TCB. */
1108         cbuf_pop(&aTcb->recvbuf, cbuf_used_space(&aTcb->recvbuf));
1109         aTcb->accepted_from = nullptr;
1110         initialize_tcb(aTcb);
1111     }
1112     /* Any adaptive changes to the sleep interval would go here. */
1113 }
1114 
tcplp_sys_log(const char * aFormat,...)1115 void tcplp_sys_log(const char *aFormat, ...)
1116 {
1117     char    buffer[128];
1118     va_list args;
1119     va_start(args, aFormat);
1120     vsnprintf(buffer, sizeof(buffer), aFormat, args);
1121     va_end(args);
1122 
1123     LogDebg("%s", buffer);
1124 }
1125 
tcplp_sys_panic(const char * aFormat,...)1126 void tcplp_sys_panic(const char *aFormat, ...)
1127 {
1128     char    buffer[128];
1129     va_list args;
1130     va_start(args, aFormat);
1131     vsnprintf(buffer, sizeof(buffer), aFormat, args);
1132     va_end(args);
1133 
1134     LogCrit("%s", buffer);
1135 
1136     OT_ASSERT(false);
1137 }
1138 
tcplp_sys_autobind(otInstance * aInstance,const otSockAddr * aPeer,otSockAddr * aToBind,bool aBindAddress,bool aBindPort)1139 bool tcplp_sys_autobind(otInstance       *aInstance,
1140                         const otSockAddr *aPeer,
1141                         otSockAddr       *aToBind,
1142                         bool              aBindAddress,
1143                         bool              aBindPort)
1144 {
1145     Instance &instance = AsCoreType(aInstance);
1146 
1147     return instance.Get<Tcp>().AutoBind(*static_cast<const SockAddr *>(aPeer), *static_cast<SockAddr *>(aToBind),
1148                                         aBindAddress, aBindPort);
1149 }
1150 
tcplp_sys_generate_isn()1151 uint32_t tcplp_sys_generate_isn()
1152 {
1153     uint32_t isn;
1154     IgnoreError(Random::Crypto::Fill(isn));
1155     return isn;
1156 }
1157 
tcplp_sys_hostswap16(uint16_t aHostPort)1158 uint16_t tcplp_sys_hostswap16(uint16_t aHostPort) { return BigEndian::HostSwap16(aHostPort); }
1159 
tcplp_sys_hostswap32(uint32_t aHostPort)1160 uint32_t tcplp_sys_hostswap32(uint32_t aHostPort) { return BigEndian::HostSwap32(aHostPort); }
1161 }
1162 
1163 #endif // OPENTHREAD_CONFIG_TCP_ENABLE
1164