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