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