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