• 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 "instance/instance.hpp"
37 
38 #if OPENTHREAD_MTD || OPENTHREAD_FTD
39 
40 #if OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE && OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
41 #error "OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE conflicts with OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT."
42 #endif
43 
44 namespace ot {
45 
46 RegisterLogModule("Message");
47 
48 //---------------------------------------------------------------------------------------------------------------------
49 // MessagePool
50 
MessagePool(Instance & aInstance)51 MessagePool::MessagePool(Instance &aInstance)
52     : InstanceLocator(aInstance)
53     , mNumAllocated(0)
54     , mMaxAllocated(0)
55 {
56 #if OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
57     otPlatMessagePoolInit(&GetInstance(), kNumBuffers, sizeof(Buffer));
58 #endif
59 }
60 
Allocate(Message::Type aType,uint16_t aReserveHeader,const Message::Settings & aSettings)61 Message *MessagePool::Allocate(Message::Type aType, uint16_t aReserveHeader, const Message::Settings &aSettings)
62 {
63     Error    error = kErrorNone;
64     Message *message;
65 
66     VerifyOrExit((message = static_cast<Message *>(NewBuffer(aSettings.GetPriority()))) != nullptr);
67 
68     ClearAllBytes(*message);
69     message->SetMessagePool(this);
70     message->SetType(aType);
71     message->SetReserved(aReserveHeader);
72     message->SetLinkSecurityEnabled(aSettings.IsLinkSecurityEnabled());
73     message->SetLoopbackToHostAllowed(OPENTHREAD_CONFIG_IP6_ALLOW_LOOP_BACK_HOST_DATAGRAMS);
74     message->SetOrigin(Message::kOriginHostTrusted);
75 
76     SuccessOrExit(error = message->SetPriority(aSettings.GetPriority()));
77     SuccessOrExit(error = message->SetLength(0));
78 
79 exit:
80     if (error != kErrorNone)
81     {
82         Free(message);
83         message = nullptr;
84     }
85 
86     return message;
87 }
88 
Allocate(Message::Type aType)89 Message *MessagePool::Allocate(Message::Type aType) { return Allocate(aType, 0, Message::Settings::GetDefault()); }
90 
Allocate(Message::Type aType,uint16_t aReserveHeader)91 Message *MessagePool::Allocate(Message::Type aType, uint16_t aReserveHeader)
92 {
93     return Allocate(aType, aReserveHeader, Message::Settings::GetDefault());
94 }
95 
Free(Message * aMessage)96 void MessagePool::Free(Message *aMessage)
97 {
98     OT_ASSERT(aMessage->Next() == nullptr && aMessage->Prev() == nullptr);
99 
100     FreeBuffers(static_cast<Buffer *>(aMessage));
101 }
102 
NewBuffer(Message::Priority aPriority)103 Buffer *MessagePool::NewBuffer(Message::Priority aPriority)
104 {
105     Buffer *buffer = nullptr;
106 
107     while ((
108 #if OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE
109                buffer = static_cast<Buffer *>(Heap::CAlloc(1, sizeof(Buffer)))
110 #elif OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
111                buffer = static_cast<Buffer *>(otPlatMessagePoolNew(&GetInstance()))
112 #else
113                buffer = mBufferPool.Allocate()
114 #endif
115                    ) == nullptr)
116     {
117         SuccessOrExit(ReclaimBuffers(aPriority));
118     }
119 
120     mNumAllocated++;
121     mMaxAllocated = Max(mMaxAllocated, mNumAllocated);
122 
123     buffer->SetNextBuffer(nullptr);
124 
125 exit:
126     if (buffer == nullptr)
127     {
128         LogInfo("No available message buffer");
129     }
130 
131     return buffer;
132 }
133 
FreeBuffers(Buffer * aBuffer)134 void MessagePool::FreeBuffers(Buffer *aBuffer)
135 {
136     while (aBuffer != nullptr)
137     {
138         Buffer *next = aBuffer->GetNextBuffer();
139 #if OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE
140         Heap::Free(aBuffer);
141 #elif OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
142         otPlatMessagePoolFree(&GetInstance(), aBuffer);
143 #else
144         mBufferPool.Free(*aBuffer);
145 #endif
146         mNumAllocated--;
147 
148         aBuffer = next;
149     }
150 }
151 
ReclaimBuffers(Message::Priority aPriority)152 Error MessagePool::ReclaimBuffers(Message::Priority aPriority) { return Get<MeshForwarder>().EvictMessage(aPriority); }
153 
GetFreeBufferCount(void) const154 uint16_t MessagePool::GetFreeBufferCount(void) const
155 {
156     uint16_t rval;
157 
158 #if OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE
159 #if !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
160     rval = static_cast<uint16_t>(Instance::GetHeap().GetFreeSize() / sizeof(Buffer));
161 #else
162     rval = NumericLimits<uint16_t>::kMax;
163 #endif
164 #elif OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
165     rval = otPlatMessagePoolNumFreeBuffers(&GetInstance());
166 #else
167     rval = kNumBuffers - mNumAllocated;
168 #endif
169 
170     return rval;
171 }
172 
GetTotalBufferCount(void) const173 uint16_t MessagePool::GetTotalBufferCount(void) const
174 {
175     uint16_t rval;
176 
177 #if OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE
178 #if !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
179     rval = static_cast<uint16_t>(Instance::GetHeap().GetCapacity() / sizeof(Buffer));
180 #else
181     rval = NumericLimits<uint16_t>::kMax;
182 #endif
183 #else
184     rval = OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS;
185 #endif
186 
187     return rval;
188 }
189 
190 //---------------------------------------------------------------------------------------------------------------------
191 // Message::Settings
192 
193 const otMessageSettings Message::Settings::kDefault = {kWithLinkSecurity, kPriorityNormal};
194 
Settings(LinkSecurityMode aSecurityMode,Priority aPriority)195 Message::Settings::Settings(LinkSecurityMode aSecurityMode, Priority aPriority)
196 {
197     mLinkSecurityEnabled = aSecurityMode;
198     mPriority            = aPriority;
199 }
200 
From(const otMessageSettings * aSettings)201 const Message::Settings &Message::Settings::From(const otMessageSettings *aSettings)
202 {
203     return (aSettings == nullptr) ? GetDefault() : AsCoreType(aSettings);
204 }
205 
206 //---------------------------------------------------------------------------------------------------------------------
207 // Message::Iterator
208 
Advance(void)209 void Message::Iterator::Advance(void)
210 {
211     mItem = mNext;
212     mNext = NextMessage(mNext);
213 }
214 
215 //---------------------------------------------------------------------------------------------------------------------
216 // Message
217 
ResizeMessage(uint16_t aLength)218 Error Message::ResizeMessage(uint16_t aLength)
219 {
220     // This method adds or frees message buffers to meet the
221     // requested length.
222 
223     Error    error     = kErrorNone;
224     Buffer  *curBuffer = this;
225     Buffer  *lastBuffer;
226     uint16_t curLength = kHeadBufferDataSize;
227 
228     while (curLength < aLength)
229     {
230         if (curBuffer->GetNextBuffer() == nullptr)
231         {
232             curBuffer->SetNextBuffer(GetMessagePool()->NewBuffer(GetPriority()));
233             VerifyOrExit(curBuffer->GetNextBuffer() != nullptr, error = kErrorNoBufs);
234         }
235 
236         curBuffer = curBuffer->GetNextBuffer();
237         curLength += kBufferDataSize;
238     }
239 
240     lastBuffer = curBuffer;
241     curBuffer  = curBuffer->GetNextBuffer();
242     lastBuffer->SetNextBuffer(nullptr);
243 
244     GetMessagePool()->FreeBuffers(curBuffer);
245 
246 exit:
247     return error;
248 }
249 
Free(void)250 void Message::Free(void) { GetMessagePool()->Free(this); }
251 
GetNext(void) const252 Message *Message::GetNext(void) const
253 {
254     Message *next;
255     Message *tail;
256 
257     if (GetMetadata().mInPriorityQ)
258     {
259         PriorityQueue *priorityQueue = GetPriorityQueue();
260         VerifyOrExit(priorityQueue != nullptr, next = nullptr);
261         tail = priorityQueue->GetTail();
262     }
263     else
264     {
265         MessageQueue *messageQueue = GetMessageQueue();
266         VerifyOrExit(messageQueue != nullptr, next = nullptr);
267         tail = messageQueue->GetTail();
268     }
269 
270     next = (this == tail) ? nullptr : Next();
271 
272 exit:
273     return next;
274 }
275 
SetLength(uint16_t aLength)276 Error Message::SetLength(uint16_t aLength)
277 {
278     Error    error              = kErrorNone;
279     uint16_t totalLengthRequest = GetReserved() + aLength;
280 
281     VerifyOrExit(totalLengthRequest >= GetReserved(), error = kErrorInvalidArgs);
282 
283     SuccessOrExit(error = ResizeMessage(totalLengthRequest));
284     GetMetadata().mLength = aLength;
285 
286     // Correct the offset in case shorter length is set.
287     if (GetOffset() > aLength)
288     {
289         SetOffset(aLength);
290     }
291 
292 exit:
293     return error;
294 }
295 
GetBufferCount(void) const296 uint8_t Message::GetBufferCount(void) const
297 {
298     uint8_t rval = 1;
299 
300     for (const Buffer *curBuffer = GetNextBuffer(); curBuffer; curBuffer = curBuffer->GetNextBuffer())
301     {
302         rval++;
303     }
304 
305     return rval;
306 }
307 
MoveOffset(int aDelta)308 void Message::MoveOffset(int aDelta)
309 {
310     OT_ASSERT(GetOffset() + aDelta <= GetLength());
311     GetMetadata().mOffset += static_cast<int16_t>(aDelta);
312     OT_ASSERT(GetMetadata().mOffset <= GetLength());
313 }
314 
SetOffset(uint16_t aOffset)315 void Message::SetOffset(uint16_t aOffset)
316 {
317     OT_ASSERT(aOffset <= GetLength());
318     GetMetadata().mOffset = aOffset;
319 }
320 
IsMleCommand(Mle::Command aMleCommand) const321 bool Message::IsMleCommand(Mle::Command aMleCommand) const
322 {
323     return (GetSubType() == kSubTypeMle) && (GetMetadata().mMleCommand == aMleCommand);
324 }
325 
SetPriority(Priority aPriority)326 Error Message::SetPriority(Priority aPriority)
327 {
328     Error          error    = kErrorNone;
329     uint8_t        priority = static_cast<uint8_t>(aPriority);
330     PriorityQueue *priorityQueue;
331 
332     static_assert(kNumPriorities <= 4, "`Metadata::mPriority` as a 2-bit field cannot fit all `Priority` values");
333 
334     VerifyOrExit(priority < kNumPriorities, error = kErrorInvalidArgs);
335 
336     VerifyOrExit(IsInAQueue(), GetMetadata().mPriority = priority);
337     VerifyOrExit(GetMetadata().mPriority != priority);
338 
339     priorityQueue = GetPriorityQueue();
340 
341     if (priorityQueue != nullptr)
342     {
343         priorityQueue->Dequeue(*this);
344     }
345 
346     GetMetadata().mPriority = priority;
347 
348     if (priorityQueue != nullptr)
349     {
350         priorityQueue->Enqueue(*this);
351     }
352 
353 exit:
354     return error;
355 }
356 
PriorityToString(Priority aPriority)357 const char *Message::PriorityToString(Priority aPriority)
358 {
359     static const char *const kPriorityStrings[] = {
360         "low",    // (0) kPriorityLow
361         "normal", // (1) kPriorityNormal
362         "high",   // (2) kPriorityHigh
363         "net",    // (3) kPriorityNet
364     };
365 
366     struct EnumCheck
367     {
368         InitEnumValidatorCounter();
369         ValidateNextEnum(kPriorityLow);
370         ValidateNextEnum(kPriorityNormal);
371         ValidateNextEnum(kPriorityHigh);
372         ValidateNextEnum(kPriorityNet);
373     };
374 
375     return kPriorityStrings[aPriority];
376 }
377 
AppendBytes(const void * aBuf,uint16_t aLength)378 Error Message::AppendBytes(const void *aBuf, uint16_t aLength)
379 {
380     Error    error     = kErrorNone;
381     uint16_t oldLength = GetLength();
382 
383     SuccessOrExit(error = SetLength(GetLength() + aLength));
384     WriteBytes(oldLength, aBuf, aLength);
385 
386 exit:
387     return error;
388 }
389 
AppendBytesFromMessage(const Message & aMessage,const OffsetRange & aOffsetRange)390 Error Message::AppendBytesFromMessage(const Message &aMessage, const OffsetRange &aOffsetRange)
391 {
392     return AppendBytesFromMessage(aMessage, aOffsetRange.GetOffset(), aOffsetRange.GetLength());
393 }
394 
AppendBytesFromMessage(const Message & aMessage,uint16_t aOffset,uint16_t aLength)395 Error Message::AppendBytesFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength)
396 {
397     Error    error       = kErrorNone;
398     uint16_t writeOffset = GetLength();
399     Chunk    chunk;
400 
401     VerifyOrExit(aMessage.GetLength() >= aOffset + aLength, error = kErrorParse);
402     SuccessOrExit(error = SetLength(GetLength() + aLength));
403 
404     aMessage.GetFirstChunk(aOffset, aLength, chunk);
405 
406     while (chunk.GetLength() > 0)
407     {
408         WriteBytes(writeOffset, chunk.GetBytes(), chunk.GetLength());
409         writeOffset += chunk.GetLength();
410         aMessage.GetNextChunk(aLength, chunk);
411     }
412 
413 exit:
414     return error;
415 }
416 
PrependBytes(const void * aBuf,uint16_t aLength)417 Error Message::PrependBytes(const void *aBuf, uint16_t aLength)
418 {
419     Error   error     = kErrorNone;
420     Buffer *newBuffer = nullptr;
421 
422     while (aLength > GetReserved())
423     {
424         VerifyOrExit((newBuffer = GetMessagePool()->NewBuffer(GetPriority())) != nullptr, error = kErrorNoBufs);
425 
426         newBuffer->SetNextBuffer(GetNextBuffer());
427         SetNextBuffer(newBuffer);
428 
429         if (GetReserved() < sizeof(mBuffer.mHead.mData))
430         {
431             // Copy payload from the first buffer.
432             memcpy(newBuffer->mBuffer.mHead.mData + GetReserved(), mBuffer.mHead.mData + GetReserved(),
433                    sizeof(mBuffer.mHead.mData) - GetReserved());
434         }
435 
436         SetReserved(GetReserved() + kBufferDataSize);
437     }
438 
439     SetReserved(GetReserved() - aLength);
440     GetMetadata().mLength += aLength;
441     SetOffset(GetOffset() + aLength);
442 
443     if (aBuf != nullptr)
444     {
445         WriteBytes(0, aBuf, aLength);
446     }
447 
448 exit:
449     return error;
450 }
451 
RemoveHeader(uint16_t aLength)452 void Message::RemoveHeader(uint16_t aLength)
453 {
454     OT_ASSERT(aLength <= GetMetadata().mLength);
455 
456     GetMetadata().mReserved += aLength;
457     GetMetadata().mLength -= aLength;
458 
459     if (GetMetadata().mOffset > aLength)
460     {
461         GetMetadata().mOffset -= aLength;
462     }
463     else
464     {
465         GetMetadata().mOffset = 0;
466     }
467 }
468 
RemoveHeader(uint16_t aOffset,uint16_t aLength)469 void Message::RemoveHeader(uint16_t aOffset, uint16_t aLength)
470 {
471     // To shrink the header, we copy the header byte before `aOffset`
472     // forward. Starting at offset `aLength`, we write bytes we read
473     // from offset `0` onward and copy a total of `aOffset` bytes.
474     // Then remove the first `aLength` bytes from message.
475     //
476     //
477     // 0                   aOffset  aOffset + aLength
478     // +-----------------------+---------+------------------------+
479     // | / / / / / / / / / / / | x x x x |                        |
480     // +-----------------------+---------+------------------------+
481     //
482     // 0       aLength                aOffset + aLength
483     // +---------+-----------------------+------------------------+
484     // |         | / / / / / / / / / / / |                        |
485     // +---------+-----------------------+------------------------+
486     //
487     //  0                    aOffset
488     //  +-----------------------+------------------------+
489     //  | / / / / / / / / / / / |                        |
490     //  +-----------------------+------------------------+
491     //
492 
493     WriteBytesFromMessage(/* aWriteOffset */ aLength, *this, /* aReadOffset */ 0, /* aLength */ aOffset);
494     RemoveHeader(aLength);
495 }
496 
InsertHeader(uint16_t aOffset,uint16_t aLength)497 Error Message::InsertHeader(uint16_t aOffset, uint16_t aLength)
498 {
499     Error error;
500 
501     // To make space in header at `aOffset`, we first prepend
502     // `aLength` bytes at front. Then copy the existing bytes
503     // backwards. Starting at offset `0`, we write bytes we read
504     // from offset `aLength` onward and copy a total of `aOffset`
505     // bytes.
506     //
507     // 0                    aOffset
508     // +-----------------------+------------------------+
509     // | / / / / / / / / / / / |                        |
510     // +-----------------------+------------------------+
511     //
512     // 0       aLength                aOffset + aLength
513     // +---------+-----------------------+------------------------+
514     // |         | / / / / / / / / / / / |                        |
515     // +---------+-----------------------+------------------------+
516     //
517     // 0                   aOffset  aOffset + aLength
518     // +-----------------------+---------+------------------------+
519     // | / / / / / / / / / / / |  N E W  |                        |
520     // +-----------------------+---------+------------------------+
521     //
522 
523     SuccessOrExit(error = PrependBytes(nullptr, aLength));
524     WriteBytesFromMessage(/* aWriteOffset */ 0, *this, /* aReadOffset */ aLength, /* aLength */ aOffset);
525 
526 exit:
527     return error;
528 }
529 
RemoveFooter(uint16_t aLength)530 void Message::RemoveFooter(uint16_t aLength) { IgnoreError(SetLength(GetLength() - Min(aLength, GetLength()))); }
531 
GetFirstChunk(uint16_t aOffset,uint16_t & aLength,Chunk & aChunk) const532 void Message::GetFirstChunk(uint16_t aOffset, uint16_t &aLength, Chunk &aChunk) const
533 {
534     // This method gets the first message chunk (contiguous data
535     // buffer) corresponding to a given offset and length. On exit
536     // `aChunk` is updated such that `aChunk.GetBytes()` gives the
537     // pointer to the start of chunk and `aChunk.GetLength()` gives
538     // its length. The `aLength` is also decreased by the chunk
539     // length.
540 
541     VerifyOrExit(aOffset < GetLength(), aChunk.SetLength(0));
542 
543     if (aOffset + aLength >= GetLength())
544     {
545         aLength = GetLength() - aOffset;
546     }
547 
548     aOffset += GetReserved();
549 
550     aChunk.SetBuffer(this);
551 
552     // Special case for the first buffer
553 
554     if (aOffset < kHeadBufferDataSize)
555     {
556         aChunk.Init(GetFirstData() + aOffset, kHeadBufferDataSize - aOffset);
557         ExitNow();
558     }
559 
560     aOffset -= kHeadBufferDataSize;
561 
562     // Find the `Buffer` matching the offset
563 
564     while (true)
565     {
566         aChunk.SetBuffer(aChunk.GetBuffer()->GetNextBuffer());
567 
568         OT_ASSERT(aChunk.GetBuffer() != nullptr);
569 
570         if (aOffset < kBufferDataSize)
571         {
572             aChunk.Init(aChunk.GetBuffer()->GetData() + aOffset, kBufferDataSize - aOffset);
573             ExitNow();
574         }
575 
576         aOffset -= kBufferDataSize;
577     }
578 
579 exit:
580     if (aChunk.GetLength() > aLength)
581     {
582         aChunk.SetLength(aLength);
583     }
584 
585     aLength -= aChunk.GetLength();
586 }
587 
GetNextChunk(uint16_t & aLength,Chunk & aChunk) const588 void Message::GetNextChunk(uint16_t &aLength, Chunk &aChunk) const
589 {
590     // This method gets the next message chunk. On input, the
591     // `aChunk` should be the previous chunk. On exit, it is
592     // updated to provide info about next chunk, and `aLength`
593     // is decreased by the chunk length. If there is no more
594     // chunk, `aChunk.GetLength()` would be zero.
595 
596     VerifyOrExit(aLength > 0, aChunk.SetLength(0));
597 
598     aChunk.SetBuffer(aChunk.GetBuffer()->GetNextBuffer());
599 
600     OT_ASSERT(aChunk.GetBuffer() != nullptr);
601 
602     aChunk.Init(aChunk.GetBuffer()->GetData(), kBufferDataSize);
603 
604     if (aChunk.GetLength() > aLength)
605     {
606         aChunk.SetLength(aLength);
607     }
608 
609     aLength -= aChunk.GetLength();
610 
611 exit:
612     return;
613 }
614 
ReadBytes(uint16_t aOffset,void * aBuf,uint16_t aLength) const615 uint16_t Message::ReadBytes(uint16_t aOffset, void *aBuf, uint16_t aLength) const
616 {
617     uint8_t *bufPtr = reinterpret_cast<uint8_t *>(aBuf);
618     Chunk    chunk;
619 
620     GetFirstChunk(aOffset, aLength, chunk);
621 
622     while (chunk.GetLength() > 0)
623     {
624         chunk.CopyBytesTo(bufPtr);
625         bufPtr += chunk.GetLength();
626         GetNextChunk(aLength, chunk);
627     }
628 
629     return static_cast<uint16_t>(bufPtr - reinterpret_cast<uint8_t *>(aBuf));
630 }
631 
ReadBytes(const OffsetRange & aOffsetRange,void * aBuf) const632 uint16_t Message::ReadBytes(const OffsetRange &aOffsetRange, void *aBuf) const
633 {
634     return ReadBytes(aOffsetRange.GetOffset(), aBuf, aOffsetRange.GetLength());
635 }
636 
Read(uint16_t aOffset,void * aBuf,uint16_t aLength) const637 Error Message::Read(uint16_t aOffset, void *aBuf, uint16_t aLength) const
638 {
639     Error error = kErrorNone;
640 
641     VerifyOrExit(aOffset + aLength <= GetLength(), error = kErrorParse);
642     ReadBytes(aOffset, aBuf, aLength);
643 
644 exit:
645     return error;
646 }
647 
Read(const OffsetRange & aOffsetRange,void * aBuf,uint16_t aLength) const648 Error Message::Read(const OffsetRange &aOffsetRange, void *aBuf, uint16_t aLength) const
649 {
650     Error error = kErrorNone;
651 
652     VerifyOrExit(aOffsetRange.Contains(aLength), error = kErrorParse);
653     error = Read(aOffsetRange.GetOffset(), aBuf, aLength);
654 
655 exit:
656     return error;
657 }
658 
CompareBytes(uint16_t aOffset,const void * aBuf,uint16_t aLength,ByteMatcher aMatcher) const659 bool Message::CompareBytes(uint16_t aOffset, const void *aBuf, uint16_t aLength, ByteMatcher aMatcher) const
660 {
661     uint16_t       bytesToCompare = aLength;
662     const uint8_t *bufPtr         = reinterpret_cast<const uint8_t *>(aBuf);
663     Chunk          chunk;
664 
665     GetFirstChunk(aOffset, aLength, chunk);
666 
667     while (chunk.GetLength() > 0)
668     {
669         VerifyOrExit(chunk.MatchesBytesIn(bufPtr, aMatcher));
670         bufPtr += chunk.GetLength();
671         bytesToCompare -= chunk.GetLength();
672         GetNextChunk(aLength, chunk);
673     }
674 
675 exit:
676     return (bytesToCompare == 0);
677 }
678 
CompareBytes(uint16_t aOffset,const Message & aOtherMessage,uint16_t aOtherOffset,uint16_t aLength,ByteMatcher aMatcher) const679 bool Message::CompareBytes(uint16_t       aOffset,
680                            const Message &aOtherMessage,
681                            uint16_t       aOtherOffset,
682                            uint16_t       aLength,
683                            ByteMatcher    aMatcher) const
684 {
685     uint16_t bytesToCompare = aLength;
686     Chunk    chunk;
687 
688     GetFirstChunk(aOffset, aLength, chunk);
689 
690     while (chunk.GetLength() > 0)
691     {
692         VerifyOrExit(aOtherMessage.CompareBytes(aOtherOffset, chunk.GetBytes(), chunk.GetLength(), aMatcher));
693         aOtherOffset += chunk.GetLength();
694         bytesToCompare -= chunk.GetLength();
695         GetNextChunk(aLength, chunk);
696     }
697 
698 exit:
699     return (bytesToCompare == 0);
700 }
701 
WriteBytes(uint16_t aOffset,const void * aBuf,uint16_t aLength)702 void Message::WriteBytes(uint16_t aOffset, const void *aBuf, uint16_t aLength)
703 {
704     const uint8_t *bufPtr = reinterpret_cast<const uint8_t *>(aBuf);
705     MutableChunk   chunk;
706 
707     OT_ASSERT(aOffset + aLength <= GetLength());
708 
709     GetFirstChunk(aOffset, aLength, chunk);
710 
711     while (chunk.GetLength() > 0)
712     {
713         memmove(chunk.GetBytes(), bufPtr, chunk.GetLength());
714         bufPtr += chunk.GetLength();
715         GetNextChunk(aLength, chunk);
716     }
717 }
718 
WriteBytesFromMessage(uint16_t aWriteOffset,const Message & aMessage,uint16_t aReadOffset,uint16_t aLength)719 void Message::WriteBytesFromMessage(uint16_t       aWriteOffset,
720                                     const Message &aMessage,
721                                     uint16_t       aReadOffset,
722                                     uint16_t       aLength)
723 {
724     if ((&aMessage != this) || (aReadOffset >= aWriteOffset))
725     {
726         Chunk chunk;
727 
728         aMessage.GetFirstChunk(aReadOffset, aLength, chunk);
729 
730         while (chunk.GetLength() > 0)
731         {
732             WriteBytes(aWriteOffset, chunk.GetBytes(), chunk.GetLength());
733             aWriteOffset += chunk.GetLength();
734             aMessage.GetNextChunk(aLength, chunk);
735         }
736     }
737     else
738     {
739         // We are copying bytes within the same message forward.
740         // To ensure copy forward works, we read and write from
741         // end of range and move backwards.
742 
743         static constexpr uint16_t kBufSize = 32;
744 
745         uint8_t buf[kBufSize];
746 
747         aWriteOffset += aLength;
748         aReadOffset += aLength;
749 
750         while (aLength > 0)
751         {
752             uint16_t copyLength = Min(kBufSize, aLength);
753 
754             aLength -= copyLength;
755             aReadOffset -= copyLength;
756             aWriteOffset -= copyLength;
757 
758             ReadBytes(aReadOffset, buf, copyLength);
759             WriteBytes(aWriteOffset, buf, copyLength);
760         }
761     }
762 }
763 
Clone(uint16_t aLength) const764 Message *Message::Clone(uint16_t aLength) const
765 {
766     Error    error = kErrorNone;
767     Message *messageCopy;
768     Settings settings(IsLinkSecurityEnabled() ? kWithLinkSecurity : kNoLinkSecurity, GetPriority());
769     uint16_t offset;
770 
771     aLength     = Min(GetLength(), aLength);
772     messageCopy = GetMessagePool()->Allocate(GetType(), GetReserved(), settings);
773     VerifyOrExit(messageCopy != nullptr, error = kErrorNoBufs);
774     SuccessOrExit(error = messageCopy->AppendBytesFromMessage(*this, 0, aLength));
775 
776     // Copy selected message information.
777 
778     offset = Min(GetOffset(), aLength);
779     messageCopy->SetOffset(offset);
780 
781     messageCopy->SetSubType(GetSubType());
782     messageCopy->SetLoopbackToHostAllowed(IsLoopbackToHostAllowed());
783     messageCopy->SetOrigin(GetOrigin());
784     messageCopy->SetTimestamp(GetTimestamp());
785     messageCopy->SetMeshDest(GetMeshDest());
786     messageCopy->SetPanId(GetPanId());
787     messageCopy->SetChannel(GetChannel());
788     messageCopy->SetRssAverager(GetRssAverager());
789     messageCopy->SetLqiAverager(GetLqiAverager());
790 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
791     messageCopy->SetTimeSync(IsTimeSync());
792 #endif
793 
794 exit:
795     FreeAndNullMessageOnError(messageCopy, error);
796     return messageCopy;
797 }
798 
GetLinkInfo(ThreadLinkInfo & aLinkInfo) const799 Error Message::GetLinkInfo(ThreadLinkInfo &aLinkInfo) const
800 {
801     Error error = kErrorNone;
802 
803     VerifyOrExit(IsOriginThreadNetif(), error = kErrorNotFound);
804 
805     aLinkInfo.Clear();
806 
807     aLinkInfo.mPanId               = GetPanId();
808     aLinkInfo.mChannel             = GetChannel();
809     aLinkInfo.mRss                 = GetAverageRss();
810     aLinkInfo.mLqi                 = GetAverageLqi();
811     aLinkInfo.mLinkSecurity        = IsLinkSecurityEnabled();
812     aLinkInfo.mIsDstPanIdBroadcast = IsDstPanIdBroadcast();
813 
814 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
815     aLinkInfo.mTimeSyncSeq       = GetTimeSyncSeq();
816     aLinkInfo.mNetworkTimeOffset = GetNetworkTimeOffset();
817 #endif
818 
819 #if OPENTHREAD_CONFIG_MULTI_RADIO
820     aLinkInfo.mRadioType = GetRadioType();
821 #endif
822 
823 exit:
824     return error;
825 }
826 
UpdateLinkInfoFrom(const ThreadLinkInfo & aLinkInfo)827 void Message::UpdateLinkInfoFrom(const ThreadLinkInfo &aLinkInfo)
828 {
829     SetPanId(aLinkInfo.mPanId);
830     SetChannel(aLinkInfo.mChannel);
831     AddRss(aLinkInfo.mRss);
832     AddLqi(aLinkInfo.mLqi);
833     SetLinkSecurityEnabled(aLinkInfo.mLinkSecurity);
834     GetMetadata().mIsDstPanIdBroadcast = aLinkInfo.IsDstPanIdBroadcast();
835 
836 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
837     SetTimeSyncSeq(aLinkInfo.mTimeSyncSeq);
838     SetNetworkTimeOffset(aLinkInfo.mNetworkTimeOffset);
839 #endif
840 
841 #if OPENTHREAD_CONFIG_MULTI_RADIO
842     SetRadioType(static_cast<Mac::RadioType>(aLinkInfo.mRadioType));
843 #endif
844 }
845 
IsTimeSync(void) const846 bool Message::IsTimeSync(void) const
847 {
848 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
849     return GetMetadata().mTimeSync;
850 #else
851     return false;
852 #endif
853 }
854 
SetMessageQueue(MessageQueue * aMessageQueue)855 void Message::SetMessageQueue(MessageQueue *aMessageQueue)
856 {
857     GetMetadata().mQueue       = aMessageQueue;
858     GetMetadata().mInPriorityQ = false;
859 }
860 
SetPriorityQueue(PriorityQueue * aPriorityQueue)861 void Message::SetPriorityQueue(PriorityQueue *aPriorityQueue)
862 {
863     GetMetadata().mQueue       = aPriorityQueue;
864     GetMetadata().mInPriorityQ = true;
865 }
866 
867 //---------------------------------------------------------------------------------------------------------------------
868 // MessageQueue
869 
Enqueue(Message & aMessage,QueuePosition aPosition)870 void MessageQueue::Enqueue(Message &aMessage, QueuePosition aPosition)
871 {
872     OT_ASSERT(!aMessage.IsInAQueue());
873     OT_ASSERT((aMessage.Next() == nullptr) && (aMessage.Prev() == nullptr));
874 
875     aMessage.SetMessageQueue(this);
876 
877     if (GetTail() == nullptr)
878     {
879         aMessage.Next() = &aMessage;
880         aMessage.Prev() = &aMessage;
881 
882         SetTail(&aMessage);
883     }
884     else
885     {
886         Message *head = GetTail()->Next();
887 
888         aMessage.Next() = head;
889         aMessage.Prev() = GetTail();
890 
891         head->Prev()      = &aMessage;
892         GetTail()->Next() = &aMessage;
893 
894         if (aPosition == kQueuePositionTail)
895         {
896             SetTail(&aMessage);
897         }
898     }
899 }
900 
Dequeue(Message & aMessage)901 void MessageQueue::Dequeue(Message &aMessage)
902 {
903     OT_ASSERT(aMessage.GetMessageQueue() == this);
904     OT_ASSERT((aMessage.Next() != nullptr) && (aMessage.Prev() != nullptr));
905 
906     if (&aMessage == GetTail())
907     {
908         SetTail(GetTail()->Prev());
909 
910         if (&aMessage == GetTail())
911         {
912             SetTail(nullptr);
913         }
914     }
915 
916     aMessage.Prev()->Next() = aMessage.Next();
917     aMessage.Next()->Prev() = aMessage.Prev();
918 
919     aMessage.Prev() = nullptr;
920     aMessage.Next() = nullptr;
921 
922     aMessage.SetMessageQueue(nullptr);
923 }
924 
DequeueAndFree(Message & aMessage)925 void MessageQueue::DequeueAndFree(Message &aMessage)
926 {
927     Dequeue(aMessage);
928     aMessage.Free();
929 }
930 
DequeueAndFreeAll(void)931 void MessageQueue::DequeueAndFreeAll(void)
932 {
933     Message *message;
934 
935     while ((message = GetHead()) != nullptr)
936     {
937         DequeueAndFree(*message);
938     }
939 }
940 
begin(void)941 Message::Iterator MessageQueue::begin(void) { return Message::Iterator(GetHead()); }
942 
begin(void) const943 Message::ConstIterator MessageQueue::begin(void) const { return Message::ConstIterator(GetHead()); }
944 
GetInfo(Info & aInfo) const945 void MessageQueue::GetInfo(Info &aInfo) const
946 {
947     for (const Message &message : *this)
948     {
949         aInfo.mNumMessages++;
950         aInfo.mNumBuffers += message.GetBufferCount();
951         aInfo.mTotalBytes += message.GetLength();
952     }
953 }
954 
955 //---------------------------------------------------------------------------------------------------------------------
956 // PriorityQueue
957 
FindFirstNonNullTail(Message::Priority aStartPriorityLevel) const958 const Message *PriorityQueue::FindFirstNonNullTail(Message::Priority aStartPriorityLevel) const
959 {
960     // Find the first non-`nullptr` tail starting from the given priority
961     // level and moving forward (wrapping from priority value
962     // `kNumPriorities` -1 back to 0).
963 
964     const Message *tail = nullptr;
965     uint8_t        priority;
966 
967     priority = static_cast<uint8_t>(aStartPriorityLevel);
968 
969     do
970     {
971         if (mTails[priority] != nullptr)
972         {
973             tail = mTails[priority];
974             break;
975         }
976 
977         priority = PrevPriority(priority);
978     } while (priority != aStartPriorityLevel);
979 
980     return tail;
981 }
982 
GetHead(void) const983 const Message *PriorityQueue::GetHead(void) const
984 {
985     return Message::NextOf(FindFirstNonNullTail(Message::kPriorityLow));
986 }
987 
GetHeadForPriority(Message::Priority aPriority) const988 const Message *PriorityQueue::GetHeadForPriority(Message::Priority aPriority) const
989 {
990     const Message *head;
991     const Message *previousTail;
992 
993     if (mTails[aPriority] != nullptr)
994     {
995         previousTail = FindFirstNonNullTail(static_cast<Message::Priority>(PrevPriority(aPriority)));
996 
997         OT_ASSERT(previousTail != nullptr);
998 
999         head = previousTail->Next();
1000     }
1001     else
1002     {
1003         head = nullptr;
1004     }
1005 
1006     return head;
1007 }
1008 
GetTail(void) const1009 const Message *PriorityQueue::GetTail(void) const { return FindFirstNonNullTail(Message::kPriorityLow); }
1010 
Enqueue(Message & aMessage)1011 void PriorityQueue::Enqueue(Message &aMessage)
1012 {
1013     Message::Priority priority;
1014     Message          *tail;
1015     Message          *next;
1016 
1017     OT_ASSERT(!aMessage.IsInAQueue());
1018 
1019     aMessage.SetPriorityQueue(this);
1020 
1021     priority = aMessage.GetPriority();
1022 
1023     tail = FindFirstNonNullTail(priority);
1024 
1025     if (tail != nullptr)
1026     {
1027         next = tail->Next();
1028 
1029         aMessage.Next() = next;
1030         aMessage.Prev() = tail;
1031         next->Prev()    = &aMessage;
1032         tail->Next()    = &aMessage;
1033     }
1034     else
1035     {
1036         aMessage.Next() = &aMessage;
1037         aMessage.Prev() = &aMessage;
1038     }
1039 
1040     mTails[priority] = &aMessage;
1041 }
1042 
Dequeue(Message & aMessage)1043 void PriorityQueue::Dequeue(Message &aMessage)
1044 {
1045     Message::Priority priority;
1046     Message          *tail;
1047 
1048     OT_ASSERT(aMessage.GetPriorityQueue() == this);
1049 
1050     priority = aMessage.GetPriority();
1051 
1052     tail = mTails[priority];
1053 
1054     if (&aMessage == tail)
1055     {
1056         tail = tail->Prev();
1057 
1058         if ((&aMessage == tail) || (tail->GetPriority() != priority))
1059         {
1060             tail = nullptr;
1061         }
1062 
1063         mTails[priority] = tail;
1064     }
1065 
1066     aMessage.Next()->Prev() = aMessage.Prev();
1067     aMessage.Prev()->Next() = aMessage.Next();
1068     aMessage.Next()         = nullptr;
1069     aMessage.Prev()         = nullptr;
1070 
1071     aMessage.SetPriorityQueue(nullptr);
1072 }
1073 
DequeueAndFree(Message & aMessage)1074 void PriorityQueue::DequeueAndFree(Message &aMessage)
1075 {
1076     Dequeue(aMessage);
1077     aMessage.Free();
1078 }
1079 
DequeueAndFreeAll(void)1080 void PriorityQueue::DequeueAndFreeAll(void)
1081 {
1082     Message *message;
1083 
1084     while ((message = GetHead()) != nullptr)
1085     {
1086         DequeueAndFree(*message);
1087     }
1088 }
1089 
begin(void)1090 Message::Iterator PriorityQueue::begin(void) { return Message::Iterator(GetHead()); }
1091 
begin(void) const1092 Message::ConstIterator PriorityQueue::begin(void) const { return Message::ConstIterator(GetHead()); }
1093 
GetInfo(Info & aInfo) const1094 void PriorityQueue::GetInfo(Info &aInfo) const
1095 {
1096     for (const Message &message : *this)
1097     {
1098         aInfo.mNumMessages++;
1099         aInfo.mNumBuffers += message.GetBufferCount();
1100         aInfo.mTotalBytes += message.GetLength();
1101     }
1102 }
1103 
1104 } // namespace ot
1105 #endif // OPENTHREAD_MTD || OPENTHREAD_FTD
1106