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 ClearAllBytes(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 ClearAllBytes(mTimers);
96 ClearAllBytes(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 ClearAllBytes(*tpl);
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 ClearAllBytes(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 ClearAllBytes(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 ClearAllBytes(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