• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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