1 /*
2 * Copyright (c) 2016, 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 the message buffer pool and message buffers.
32 */
33
34 #include "message.hpp"
35
36 #include "common/as_core_type.hpp"
37 #include "common/code_utils.hpp"
38 #include "common/debug.hpp"
39 #include "common/heap.hpp"
40 #include "common/instance.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/log.hpp"
43 #include "common/numeric_limits.hpp"
44 #include "net/checksum.hpp"
45 #include "net/ip6.hpp"
46
47 #if OPENTHREAD_MTD || OPENTHREAD_FTD
48
49 #if OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE && OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
50 #error "OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE conflicts with OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT."
51 #endif
52
53 #if OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE && !OPENTHREAD_CONFIG_DTLS_ENABLE
54 #error "OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE is strongly discouraged when OPENTHREAD_CONFIG_DTLS_ENABLE is off."
55 #endif
56
57 namespace ot {
58
59 RegisterLogModule("Message");
60
61 //---------------------------------------------------------------------------------------------------------------------
62 // MessagePool
63
MessagePool(Instance & aInstance)64 MessagePool::MessagePool(Instance &aInstance)
65 : InstanceLocator(aInstance)
66 #if !OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT && !OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE
67 , mNumFreeBuffers(kNumBuffers)
68 #endif
69 {
70 #if OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
71 otPlatMessagePoolInit(&GetInstance(), kNumBuffers, sizeof(Buffer));
72 #endif
73 }
74
Allocate(Message::Type aType,uint16_t aReserveHeader,const Message::Settings & aSettings)75 Message *MessagePool::Allocate(Message::Type aType, uint16_t aReserveHeader, const Message::Settings &aSettings)
76 {
77 Error error = kErrorNone;
78 Message *message;
79
80 VerifyOrExit((message = static_cast<Message *>(NewBuffer(aSettings.GetPriority()))) != nullptr);
81
82 memset(message, 0, sizeof(*message));
83 message->SetMessagePool(this);
84 message->SetType(aType);
85 message->SetReserved(aReserveHeader);
86 message->SetLinkSecurityEnabled(aSettings.IsLinkSecurityEnabled());
87
88 SuccessOrExit(error = message->SetPriority(aSettings.GetPriority()));
89 SuccessOrExit(error = message->SetLength(0));
90
91 exit:
92 if (error != kErrorNone)
93 {
94 Free(message);
95 message = nullptr;
96 }
97
98 return message;
99 }
100
Free(Message * aMessage)101 void MessagePool::Free(Message *aMessage)
102 {
103 OT_ASSERT(aMessage->Next() == nullptr && aMessage->Prev() == nullptr);
104
105 FreeBuffers(static_cast<Buffer *>(aMessage));
106 }
107
NewBuffer(Message::Priority aPriority)108 Buffer *MessagePool::NewBuffer(Message::Priority aPriority)
109 {
110 Buffer *buffer = nullptr;
111
112 while ((
113 #if OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE
114 buffer = static_cast<Buffer *>(Heap::CAlloc(1, sizeof(Buffer)))
115 #elif OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
116 buffer = static_cast<Buffer *>(otPlatMessagePoolNew(&GetInstance()))
117 #else
118 buffer = mBufferPool.Allocate()
119 #endif
120 ) == nullptr)
121 {
122 SuccessOrExit(ReclaimBuffers(aPriority));
123 }
124
125 #if !OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT && !OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE
126 mNumFreeBuffers--;
127 #endif
128
129 buffer->SetNextBuffer(nullptr);
130
131 exit:
132 if (buffer == nullptr)
133 {
134 LogInfo("No available message buffer");
135 }
136
137 return buffer;
138 }
139
FreeBuffers(Buffer * aBuffer)140 void MessagePool::FreeBuffers(Buffer *aBuffer)
141 {
142 while (aBuffer != nullptr)
143 {
144 Buffer *next = aBuffer->GetNextBuffer();
145 #if OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE
146 Heap::Free(aBuffer);
147 #elif OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
148 otPlatMessagePoolFree(&GetInstance(), aBuffer);
149 #else
150 mBufferPool.Free(*aBuffer);
151 mNumFreeBuffers++;
152 #endif
153 aBuffer = next;
154 }
155 }
156
ReclaimBuffers(Message::Priority aPriority)157 Error MessagePool::ReclaimBuffers(Message::Priority aPriority)
158 {
159 return Get<MeshForwarder>().EvictMessage(aPriority);
160 }
161
GetFreeBufferCount(void) const162 uint16_t MessagePool::GetFreeBufferCount(void) const
163 {
164 uint16_t rval;
165
166 #if OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE
167 #if !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
168 rval = static_cast<uint16_t>(Instance::GetHeap().GetFreeSize() / sizeof(Buffer));
169 #else
170 rval = NumericLimits<uint16_t>::kMax;
171 #endif
172 #elif OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
173 rval = otPlatMessagePoolNumFreeBuffers(&GetInstance());
174 #else
175 rval = mNumFreeBuffers;
176 #endif
177
178 return rval;
179 }
180
GetTotalBufferCount(void) const181 uint16_t MessagePool::GetTotalBufferCount(void) const
182 {
183 uint16_t rval;
184
185 #if OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE
186 #if !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
187 rval = static_cast<uint16_t>(Instance::GetHeap().GetCapacity() / sizeof(Buffer));
188 #else
189 rval = NumericLimits<uint16_t>::kMax;
190 #endif
191 #else
192 rval = OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS;
193 #endif
194
195 return rval;
196 }
197
198 //---------------------------------------------------------------------------------------------------------------------
199 // Message::Settings
200
201 const otMessageSettings Message::Settings::kDefault = {kWithLinkSecurity, kPriorityNormal};
202
Settings(LinkSecurityMode aSecurityMode,Priority aPriority)203 Message::Settings::Settings(LinkSecurityMode aSecurityMode, Priority aPriority)
204 {
205 mLinkSecurityEnabled = aSecurityMode;
206 mPriority = aPriority;
207 }
208
From(const otMessageSettings * aSettings)209 const Message::Settings &Message::Settings::From(const otMessageSettings *aSettings)
210 {
211 return (aSettings == nullptr) ? GetDefault() : AsCoreType(aSettings);
212 }
213
214 //---------------------------------------------------------------------------------------------------------------------
215 // Message::Iterator
216
Advance(void)217 void Message::Iterator::Advance(void)
218 {
219 mItem = mNext;
220 mNext = NextMessage(mNext);
221 }
222
223 //---------------------------------------------------------------------------------------------------------------------
224 // Message
225
ResizeMessage(uint16_t aLength)226 Error Message::ResizeMessage(uint16_t aLength)
227 {
228 // This method adds or frees message buffers to meet the
229 // requested length.
230
231 Error error = kErrorNone;
232 Buffer * curBuffer = this;
233 Buffer * lastBuffer;
234 uint16_t curLength = kHeadBufferDataSize;
235
236 while (curLength < aLength)
237 {
238 if (curBuffer->GetNextBuffer() == nullptr)
239 {
240 curBuffer->SetNextBuffer(GetMessagePool()->NewBuffer(GetPriority()));
241 VerifyOrExit(curBuffer->GetNextBuffer() != nullptr, error = kErrorNoBufs);
242 }
243
244 curBuffer = curBuffer->GetNextBuffer();
245 curLength += kBufferDataSize;
246 }
247
248 lastBuffer = curBuffer;
249 curBuffer = curBuffer->GetNextBuffer();
250 lastBuffer->SetNextBuffer(nullptr);
251
252 GetMessagePool()->FreeBuffers(curBuffer);
253
254 exit:
255 return error;
256 }
257
Free(void)258 void Message::Free(void)
259 {
260 GetMessagePool()->Free(this);
261 }
262
GetNext(void) const263 Message *Message::GetNext(void) const
264 {
265 Message *next;
266 Message *tail;
267
268 if (GetMetadata().mInPriorityQ)
269 {
270 PriorityQueue *priorityQueue = GetPriorityQueue();
271 VerifyOrExit(priorityQueue != nullptr, next = nullptr);
272 tail = priorityQueue->GetTail();
273 }
274 else
275 {
276 MessageQueue *messageQueue = GetMessageQueue();
277 VerifyOrExit(messageQueue != nullptr, next = nullptr);
278 tail = messageQueue->GetTail();
279 }
280
281 next = (this == tail) ? nullptr : Next();
282
283 exit:
284 return next;
285 }
286
SetLength(uint16_t aLength)287 Error Message::SetLength(uint16_t aLength)
288 {
289 Error error = kErrorNone;
290 uint16_t totalLengthRequest = GetReserved() + aLength;
291
292 VerifyOrExit(totalLengthRequest >= GetReserved(), error = kErrorInvalidArgs);
293
294 SuccessOrExit(error = ResizeMessage(totalLengthRequest));
295 GetMetadata().mLength = aLength;
296
297 // Correct the offset in case shorter length is set.
298 if (GetOffset() > aLength)
299 {
300 SetOffset(aLength);
301 }
302
303 exit:
304 return error;
305 }
306
GetBufferCount(void) const307 uint8_t Message::GetBufferCount(void) const
308 {
309 uint8_t rval = 1;
310
311 for (const Buffer *curBuffer = GetNextBuffer(); curBuffer; curBuffer = curBuffer->GetNextBuffer())
312 {
313 rval++;
314 }
315
316 return rval;
317 }
318
MoveOffset(int aDelta)319 void Message::MoveOffset(int aDelta)
320 {
321 OT_ASSERT(GetOffset() + aDelta <= GetLength());
322 GetMetadata().mOffset += static_cast<int16_t>(aDelta);
323 OT_ASSERT(GetMetadata().mOffset <= GetLength());
324 }
325
SetOffset(uint16_t aOffset)326 void Message::SetOffset(uint16_t aOffset)
327 {
328 OT_ASSERT(aOffset <= GetLength());
329 GetMetadata().mOffset = aOffset;
330 }
331
IsSubTypeMle(void) const332 bool Message::IsSubTypeMle(void) const
333 {
334 bool rval;
335
336 switch (GetMetadata().mSubType)
337 {
338 case kSubTypeMleGeneral:
339 case kSubTypeMleAnnounce:
340 case kSubTypeMleDiscoverRequest:
341 case kSubTypeMleDiscoverResponse:
342 case kSubTypeMleChildUpdateRequest:
343 case kSubTypeMleDataResponse:
344 case kSubTypeMleChildIdRequest:
345 rval = true;
346 break;
347
348 default:
349 rval = false;
350 break;
351 }
352
353 return rval;
354 }
355
SetPriority(Priority aPriority)356 Error Message::SetPriority(Priority aPriority)
357 {
358 Error error = kErrorNone;
359 uint8_t priority = static_cast<uint8_t>(aPriority);
360 PriorityQueue *priorityQueue;
361
362 static_assert(kNumPriorities <= 4, "`Metadata::mPriority` as a 2-bit field cannot fit all `Priority` values");
363
364 VerifyOrExit(priority < kNumPriorities, error = kErrorInvalidArgs);
365
366 VerifyOrExit(IsInAQueue(), GetMetadata().mPriority = priority);
367 VerifyOrExit(GetMetadata().mPriority != priority);
368
369 priorityQueue = GetPriorityQueue();
370
371 if (priorityQueue != nullptr)
372 {
373 priorityQueue->Dequeue(*this);
374 }
375
376 GetMetadata().mPriority = priority;
377
378 if (priorityQueue != nullptr)
379 {
380 priorityQueue->Enqueue(*this);
381 }
382
383 exit:
384 return error;
385 }
386
PriorityToString(Priority aPriority)387 const char *Message::PriorityToString(Priority aPriority)
388 {
389 static const char *const kPriorityStrings[] = {
390 "low", // (0) kPriorityLow
391 "normal", // (1) kPriorityNormal
392 "high", // (2) kPriorityHigh
393 "net", // (3) kPriorityNet
394 };
395
396 static_assert(kPriorityLow == 0, "kPriorityLow value is incorrect");
397 static_assert(kPriorityNormal == 1, "kPriorityNormal value is incorrect");
398 static_assert(kPriorityHigh == 2, "kPriorityHigh value is incorrect");
399 static_assert(kPriorityNet == 3, "kPriorityNet value is incorrect");
400
401 return kPriorityStrings[aPriority];
402 }
403
AppendBytes(const void * aBuf,uint16_t aLength)404 Error Message::AppendBytes(const void *aBuf, uint16_t aLength)
405 {
406 Error error = kErrorNone;
407 uint16_t oldLength = GetLength();
408
409 SuccessOrExit(error = SetLength(GetLength() + aLength));
410 WriteBytes(oldLength, aBuf, aLength);
411
412 exit:
413 return error;
414 }
415
AppendBytesFromMessage(const Message & aMessage,uint16_t aOffset,uint16_t aLength)416 Error Message::AppendBytesFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength)
417 {
418 Error error = kErrorNone;
419 uint16_t writeOffset = GetLength();
420 Chunk chunk;
421
422 VerifyOrExit(aMessage.GetLength() >= aOffset + aLength, error = kErrorParse);
423 SuccessOrExit(error = SetLength(GetLength() + aLength));
424
425 aMessage.GetFirstChunk(aOffset, aLength, chunk);
426
427 while (chunk.GetLength() > 0)
428 {
429 WriteBytes(writeOffset, chunk.GetBytes(), chunk.GetLength());
430 writeOffset += chunk.GetLength();
431 aMessage.GetNextChunk(aLength, chunk);
432 }
433
434 exit:
435 return error;
436 }
437
PrependBytes(const void * aBuf,uint16_t aLength)438 Error Message::PrependBytes(const void *aBuf, uint16_t aLength)
439 {
440 Error error = kErrorNone;
441 Buffer *newBuffer = nullptr;
442
443 while (aLength > GetReserved())
444 {
445 VerifyOrExit((newBuffer = GetMessagePool()->NewBuffer(GetPriority())) != nullptr, error = kErrorNoBufs);
446
447 newBuffer->SetNextBuffer(GetNextBuffer());
448 SetNextBuffer(newBuffer);
449
450 if (GetReserved() < sizeof(mBuffer.mHead.mData))
451 {
452 // Copy payload from the first buffer.
453 memcpy(newBuffer->mBuffer.mHead.mData + GetReserved(), mBuffer.mHead.mData + GetReserved(),
454 sizeof(mBuffer.mHead.mData) - GetReserved());
455 }
456
457 SetReserved(GetReserved() + kBufferDataSize);
458 }
459
460 SetReserved(GetReserved() - aLength);
461 GetMetadata().mLength += aLength;
462 SetOffset(GetOffset() + aLength);
463
464 if (aBuf != nullptr)
465 {
466 WriteBytes(0, aBuf, aLength);
467 }
468
469 exit:
470 return error;
471 }
472
RemoveHeader(uint16_t aLength)473 void Message::RemoveHeader(uint16_t aLength)
474 {
475 OT_ASSERT(aLength <= GetMetadata().mLength);
476
477 GetMetadata().mReserved += aLength;
478 GetMetadata().mLength -= aLength;
479
480 if (GetMetadata().mOffset > aLength)
481 {
482 GetMetadata().mOffset -= aLength;
483 }
484 else
485 {
486 GetMetadata().mOffset = 0;
487 }
488 }
489
GetFirstChunk(uint16_t aOffset,uint16_t & aLength,Chunk & aChunk) const490 void Message::GetFirstChunk(uint16_t aOffset, uint16_t &aLength, Chunk &aChunk) const
491 {
492 // This method gets the first message chunk (contiguous data
493 // buffer) corresponding to a given offset and length. On exit
494 // `aChunk` is updated such that `aChunk.GetBytes()` gives the
495 // pointer to the start of chunk and `aChunk.GetLength()` gives
496 // its length. The `aLength` is also decreased by the chunk
497 // length.
498
499 VerifyOrExit(aOffset < GetLength(), aChunk.SetLength(0));
500
501 if (aOffset + aLength >= GetLength())
502 {
503 aLength = GetLength() - aOffset;
504 }
505
506 aOffset += GetReserved();
507
508 aChunk.SetBuffer(this);
509
510 // Special case for the first buffer
511
512 if (aOffset < kHeadBufferDataSize)
513 {
514 aChunk.Init(GetFirstData() + aOffset, kHeadBufferDataSize - aOffset);
515 ExitNow();
516 }
517
518 aOffset -= kHeadBufferDataSize;
519
520 // Find the `Buffer` matching the offset
521
522 while (true)
523 {
524 aChunk.SetBuffer(aChunk.GetBuffer()->GetNextBuffer());
525
526 OT_ASSERT(aChunk.GetBuffer() != nullptr);
527
528 if (aOffset < kBufferDataSize)
529 {
530 aChunk.Init(aChunk.GetBuffer()->GetData() + aOffset, kBufferDataSize - aOffset);
531 ExitNow();
532 }
533
534 aOffset -= kBufferDataSize;
535 }
536
537 exit:
538 if (aChunk.GetLength() > aLength)
539 {
540 aChunk.SetLength(aLength);
541 }
542
543 aLength -= aChunk.GetLength();
544 }
545
GetNextChunk(uint16_t & aLength,Chunk & aChunk) const546 void Message::GetNextChunk(uint16_t &aLength, Chunk &aChunk) const
547 {
548 // This method gets the next message chunk. On input, the
549 // `aChunk` should be the previous chunk. On exit, it is
550 // updated to provide info about next chunk, and `aLength`
551 // is decreased by the chunk length. If there is no more
552 // chunk, `aChunk.GetLength()` would be zero.
553
554 VerifyOrExit(aLength > 0, aChunk.SetLength(0));
555
556 aChunk.SetBuffer(aChunk.GetBuffer()->GetNextBuffer());
557
558 OT_ASSERT(aChunk.GetBuffer() != nullptr);
559
560 aChunk.Init(aChunk.GetBuffer()->GetData(), kBufferDataSize);
561
562 if (aChunk.GetLength() > aLength)
563 {
564 aChunk.SetLength(aLength);
565 }
566
567 aLength -= aChunk.GetLength();
568
569 exit:
570 return;
571 }
572
ReadBytes(uint16_t aOffset,void * aBuf,uint16_t aLength) const573 uint16_t Message::ReadBytes(uint16_t aOffset, void *aBuf, uint16_t aLength) const
574 {
575 uint8_t *bufPtr = reinterpret_cast<uint8_t *>(aBuf);
576 Chunk chunk;
577
578 GetFirstChunk(aOffset, aLength, chunk);
579
580 while (chunk.GetLength() > 0)
581 {
582 chunk.CopyBytesTo(bufPtr);
583 bufPtr += chunk.GetLength();
584 GetNextChunk(aLength, chunk);
585 }
586
587 return static_cast<uint16_t>(bufPtr - reinterpret_cast<uint8_t *>(aBuf));
588 }
589
Read(uint16_t aOffset,void * aBuf,uint16_t aLength) const590 Error Message::Read(uint16_t aOffset, void *aBuf, uint16_t aLength) const
591 {
592 return (ReadBytes(aOffset, aBuf, aLength) == aLength) ? kErrorNone : kErrorParse;
593 }
594
CompareBytes(uint16_t aOffset,const void * aBuf,uint16_t aLength,ByteMatcher aMatcher) const595 bool Message::CompareBytes(uint16_t aOffset, const void *aBuf, uint16_t aLength, ByteMatcher aMatcher) const
596 {
597 uint16_t bytesToCompare = aLength;
598 const uint8_t *bufPtr = reinterpret_cast<const uint8_t *>(aBuf);
599 Chunk chunk;
600
601 GetFirstChunk(aOffset, aLength, chunk);
602
603 while (chunk.GetLength() > 0)
604 {
605 VerifyOrExit(chunk.MatchesBytesIn(bufPtr, aMatcher));
606 bufPtr += chunk.GetLength();
607 bytesToCompare -= chunk.GetLength();
608 GetNextChunk(aLength, chunk);
609 }
610
611 exit:
612 return (bytesToCompare == 0);
613 }
614
CompareBytes(uint16_t aOffset,const Message & aOtherMessage,uint16_t aOtherOffset,uint16_t aLength,ByteMatcher aMatcher) const615 bool Message::CompareBytes(uint16_t aOffset,
616 const Message &aOtherMessage,
617 uint16_t aOtherOffset,
618 uint16_t aLength,
619 ByteMatcher aMatcher) const
620 {
621 uint16_t bytesToCompare = aLength;
622 Chunk chunk;
623
624 GetFirstChunk(aOffset, aLength, chunk);
625
626 while (chunk.GetLength() > 0)
627 {
628 VerifyOrExit(aOtherMessage.CompareBytes(aOtherOffset, chunk.GetBytes(), chunk.GetLength(), aMatcher));
629 aOtherOffset += chunk.GetLength();
630 bytesToCompare -= chunk.GetLength();
631 GetNextChunk(aLength, chunk);
632 }
633
634 exit:
635 return (bytesToCompare == 0);
636 }
637
WriteBytes(uint16_t aOffset,const void * aBuf,uint16_t aLength)638 void Message::WriteBytes(uint16_t aOffset, const void *aBuf, uint16_t aLength)
639 {
640 const uint8_t *bufPtr = reinterpret_cast<const uint8_t *>(aBuf);
641 MutableChunk chunk;
642
643 OT_ASSERT(aOffset + aLength <= GetLength());
644
645 GetFirstChunk(aOffset, aLength, chunk);
646
647 while (chunk.GetLength() > 0)
648 {
649 memmove(chunk.GetBytes(), bufPtr, chunk.GetLength());
650 bufPtr += chunk.GetLength();
651 GetNextChunk(aLength, chunk);
652 }
653 }
654
CopyTo(uint16_t aSourceOffset,uint16_t aDestinationOffset,uint16_t aLength,Message & aMessage) const655 uint16_t Message::CopyTo(uint16_t aSourceOffset, uint16_t aDestinationOffset, uint16_t aLength, Message &aMessage) const
656 {
657 uint16_t bytesCopied = 0;
658 Chunk chunk;
659
660 // This implementing can potentially overwrite the data when bytes are
661 // being copied forward within the same message, i.e., source and
662 // destination messages are the same, and source offset is smaller than
663 // the destination offset. We assert not allowing such a use.
664
665 OT_ASSERT((&aMessage != this) || (aSourceOffset >= aDestinationOffset));
666
667 GetFirstChunk(aSourceOffset, aLength, chunk);
668
669 while (chunk.GetLength() > 0)
670 {
671 aMessage.WriteBytes(aDestinationOffset, chunk.GetBytes(), chunk.GetLength());
672 aDestinationOffset += chunk.GetLength();
673 bytesCopied += chunk.GetLength();
674 GetNextChunk(aLength, chunk);
675 }
676
677 return bytesCopied;
678 }
679
Clone(uint16_t aLength) const680 Message *Message::Clone(uint16_t aLength) const
681 {
682 Error error = kErrorNone;
683 Message *messageCopy;
684 Settings settings(IsLinkSecurityEnabled() ? kWithLinkSecurity : kNoLinkSecurity, GetPriority());
685 uint16_t offset;
686
687 messageCopy = GetMessagePool()->Allocate(GetType(), GetReserved(), settings);
688 VerifyOrExit(messageCopy != nullptr, error = kErrorNoBufs);
689 SuccessOrExit(error = messageCopy->SetLength(aLength));
690 CopyTo(0, 0, aLength, *messageCopy);
691
692 // Copy selected message information.
693 offset = GetOffset() < aLength ? GetOffset() : aLength;
694 messageCopy->SetOffset(offset);
695
696 messageCopy->SetSubType(GetSubType());
697 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
698 messageCopy->SetTimeSync(IsTimeSync());
699 #endif
700
701 exit:
702 FreeAndNullMessageOnError(messageCopy, error);
703 return messageCopy;
704 }
705
GetChildMask(uint16_t aChildIndex) const706 bool Message::GetChildMask(uint16_t aChildIndex) const
707 {
708 return GetMetadata().mChildMask.Get(aChildIndex);
709 }
710
ClearChildMask(uint16_t aChildIndex)711 void Message::ClearChildMask(uint16_t aChildIndex)
712 {
713 GetMetadata().mChildMask.Set(aChildIndex, false);
714 }
715
SetChildMask(uint16_t aChildIndex)716 void Message::SetChildMask(uint16_t aChildIndex)
717 {
718 GetMetadata().mChildMask.Set(aChildIndex, true);
719 }
720
IsChildPending(void) const721 bool Message::IsChildPending(void) const
722 {
723 return GetMetadata().mChildMask.HasAny();
724 }
725
SetLinkInfo(const ThreadLinkInfo & aLinkInfo)726 void Message::SetLinkInfo(const ThreadLinkInfo &aLinkInfo)
727 {
728 SetLinkSecurityEnabled(aLinkInfo.mLinkSecurity);
729 SetPanId(aLinkInfo.mPanId);
730 AddRss(aLinkInfo.mRss);
731 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
732 AddLqi(aLinkInfo.mLqi);
733 #endif
734 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
735 SetTimeSyncSeq(aLinkInfo.mTimeSyncSeq);
736 SetNetworkTimeOffset(aLinkInfo.mNetworkTimeOffset);
737 #endif
738 #if OPENTHREAD_CONFIG_MULTI_RADIO
739 SetRadioType(static_cast<Mac::RadioType>(aLinkInfo.mRadioType));
740 #endif
741 }
742
IsTimeSync(void) const743 bool Message::IsTimeSync(void) const
744 {
745 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
746 return GetMetadata().mTimeSync;
747 #else
748 return false;
749 #endif
750 }
751
SetMessageQueue(MessageQueue * aMessageQueue)752 void Message::SetMessageQueue(MessageQueue *aMessageQueue)
753 {
754 GetMetadata().mQueue = aMessageQueue;
755 GetMetadata().mInPriorityQ = false;
756 }
757
SetPriorityQueue(PriorityQueue * aPriorityQueue)758 void Message::SetPriorityQueue(PriorityQueue *aPriorityQueue)
759 {
760 GetMetadata().mQueue = aPriorityQueue;
761 GetMetadata().mInPriorityQ = true;
762 }
763
764 //---------------------------------------------------------------------------------------------------------------------
765 // MessageQueue
766
Enqueue(Message & aMessage,QueuePosition aPosition)767 void MessageQueue::Enqueue(Message &aMessage, QueuePosition aPosition)
768 {
769 OT_ASSERT(!aMessage.IsInAQueue());
770 OT_ASSERT((aMessage.Next() == nullptr) && (aMessage.Prev() == nullptr));
771
772 aMessage.SetMessageQueue(this);
773
774 if (GetTail() == nullptr)
775 {
776 aMessage.Next() = &aMessage;
777 aMessage.Prev() = &aMessage;
778
779 SetTail(&aMessage);
780 }
781 else
782 {
783 Message *head = GetTail()->Next();
784
785 aMessage.Next() = head;
786 aMessage.Prev() = GetTail();
787
788 head->Prev() = &aMessage;
789 GetTail()->Next() = &aMessage;
790
791 if (aPosition == kQueuePositionTail)
792 {
793 SetTail(&aMessage);
794 }
795 }
796 }
797
Dequeue(Message & aMessage)798 void MessageQueue::Dequeue(Message &aMessage)
799 {
800 OT_ASSERT(aMessage.GetMessageQueue() == this);
801 OT_ASSERT((aMessage.Next() != nullptr) && (aMessage.Prev() != nullptr));
802
803 if (&aMessage == GetTail())
804 {
805 SetTail(GetTail()->Prev());
806
807 if (&aMessage == GetTail())
808 {
809 SetTail(nullptr);
810 }
811 }
812
813 aMessage.Prev()->Next() = aMessage.Next();
814 aMessage.Next()->Prev() = aMessage.Prev();
815
816 aMessage.Prev() = nullptr;
817 aMessage.Next() = nullptr;
818
819 aMessage.SetMessageQueue(nullptr);
820 }
821
DequeueAndFree(Message & aMessage)822 void MessageQueue::DequeueAndFree(Message &aMessage)
823 {
824 Dequeue(aMessage);
825 aMessage.Free();
826 }
827
DequeueAndFreeAll(void)828 void MessageQueue::DequeueAndFreeAll(void)
829 {
830 Message *message;
831
832 while ((message = GetHead()) != nullptr)
833 {
834 DequeueAndFree(*message);
835 }
836 }
837
begin(void)838 Message::Iterator MessageQueue::begin(void)
839 {
840 return Message::Iterator(GetHead());
841 }
842
begin(void) const843 Message::ConstIterator MessageQueue::begin(void) const
844 {
845 return Message::ConstIterator(GetHead());
846 }
847
GetInfo(Info & aInfo) const848 void MessageQueue::GetInfo(Info &aInfo) const
849 {
850 for (const Message &message : *this)
851 {
852 aInfo.mNumMessages++;
853 aInfo.mNumBuffers += message.GetBufferCount();
854 aInfo.mTotalBytes += message.GetLength();
855 }
856 }
857
858 //---------------------------------------------------------------------------------------------------------------------
859 // PriorityQueue
860
FindFirstNonNullTail(Message::Priority aStartPriorityLevel) const861 const Message *PriorityQueue::FindFirstNonNullTail(Message::Priority aStartPriorityLevel) const
862 {
863 // Find the first non-`nullptr` tail starting from the given priority
864 // level and moving forward (wrapping from priority value
865 // `kNumPriorities` -1 back to 0).
866
867 const Message *tail = nullptr;
868 uint8_t priority;
869
870 priority = static_cast<uint8_t>(aStartPriorityLevel);
871
872 do
873 {
874 if (mTails[priority] != nullptr)
875 {
876 tail = mTails[priority];
877 break;
878 }
879
880 priority = PrevPriority(priority);
881 } while (priority != aStartPriorityLevel);
882
883 return tail;
884 }
885
GetHead(void) const886 const Message *PriorityQueue::GetHead(void) const
887 {
888 return Message::NextOf(FindFirstNonNullTail(Message::kPriorityLow));
889 }
890
GetHeadForPriority(Message::Priority aPriority) const891 const Message *PriorityQueue::GetHeadForPriority(Message::Priority aPriority) const
892 {
893 const Message *head;
894 const Message *previousTail;
895
896 if (mTails[aPriority] != nullptr)
897 {
898 previousTail = FindFirstNonNullTail(static_cast<Message::Priority>(PrevPriority(aPriority)));
899
900 OT_ASSERT(previousTail != nullptr);
901
902 head = previousTail->Next();
903 }
904 else
905 {
906 head = nullptr;
907 }
908
909 return head;
910 }
911
GetTail(void) const912 const Message *PriorityQueue::GetTail(void) const
913 {
914 return FindFirstNonNullTail(Message::kPriorityLow);
915 }
916
Enqueue(Message & aMessage)917 void PriorityQueue::Enqueue(Message &aMessage)
918 {
919 Message::Priority priority;
920 Message * tail;
921 Message * next;
922
923 OT_ASSERT(!aMessage.IsInAQueue());
924
925 aMessage.SetPriorityQueue(this);
926
927 priority = aMessage.GetPriority();
928
929 tail = FindFirstNonNullTail(priority);
930
931 if (tail != nullptr)
932 {
933 next = tail->Next();
934
935 aMessage.Next() = next;
936 aMessage.Prev() = tail;
937 next->Prev() = &aMessage;
938 tail->Next() = &aMessage;
939 }
940 else
941 {
942 aMessage.Next() = &aMessage;
943 aMessage.Prev() = &aMessage;
944 }
945
946 mTails[priority] = &aMessage;
947 }
948
Dequeue(Message & aMessage)949 void PriorityQueue::Dequeue(Message &aMessage)
950 {
951 Message::Priority priority;
952 Message * tail;
953
954 OT_ASSERT(aMessage.GetPriorityQueue() == this);
955
956 priority = aMessage.GetPriority();
957
958 tail = mTails[priority];
959
960 if (&aMessage == tail)
961 {
962 tail = tail->Prev();
963
964 if ((&aMessage == tail) || (tail->GetPriority() != priority))
965 {
966 tail = nullptr;
967 }
968
969 mTails[priority] = tail;
970 }
971
972 aMessage.Next()->Prev() = aMessage.Prev();
973 aMessage.Prev()->Next() = aMessage.Next();
974 aMessage.Next() = nullptr;
975 aMessage.Prev() = nullptr;
976
977 aMessage.SetPriorityQueue(nullptr);
978 }
979
DequeueAndFree(Message & aMessage)980 void PriorityQueue::DequeueAndFree(Message &aMessage)
981 {
982 Dequeue(aMessage);
983 aMessage.Free();
984 }
985
DequeueAndFreeAll(void)986 void PriorityQueue::DequeueAndFreeAll(void)
987 {
988 Message *message;
989
990 while ((message = GetHead()) != nullptr)
991 {
992 DequeueAndFree(*message);
993 }
994 }
995
begin(void)996 Message::Iterator PriorityQueue::begin(void)
997 {
998 return Message::Iterator(GetHead());
999 }
1000
begin(void) const1001 Message::ConstIterator PriorityQueue::begin(void) const
1002 {
1003 return Message::ConstIterator(GetHead());
1004 }
1005
GetInfo(Info & aInfo) const1006 void PriorityQueue::GetInfo(Info &aInfo) const
1007 {
1008 for (const Message &message : *this)
1009 {
1010 aInfo.mNumMessages++;
1011 aInfo.mNumBuffers += message.GetBufferCount();
1012 aInfo.mTotalBytes += message.GetLength();
1013 }
1014 }
1015
1016 } // namespace ot
1017 #endif // OPENTHREAD_MTD || OPENTHREAD_FTD
1018