LCOV - code coverage report
Current view: top level - lib/support - ThreadOperationalDataset.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 220 237 92.8 %
Date: 2024-02-15 08:20:41 Functions: 39 41 95.1 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2021 Project CHIP Authors
       4             :  *
       5             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6             :  *    you may not use this file except in compliance with the License.
       7             :  *    You may obtain a copy of the License at
       8             :  *
       9             :  *        http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  *    Unless required by applicable law or agreed to in writing, software
      12             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  *    See the License for the specific language governing permissions and
      15             :  *    limitations under the License.
      16             :  */
      17             : 
      18             : #include <assert.h>
      19             : #include <string.h>
      20             : 
      21             : #include <lib/support/ThreadOperationalDataset.h>
      22             : 
      23             : namespace chip {
      24             : namespace Thread {
      25             : 
      26             : /**
      27             :  * Thread Operational Dataset TLV is defined in Thread Specification as the following format:
      28             :  *
      29             :  * +---------+---------+-------------------------+
      30             :  * | uint8_t | uint8_t | network byte order data |
      31             :  * | 1 byte  | 1 byte  | n byte (0 <= n < 255)   |
      32             :  * +---------+---------+-------------------------+
      33             :  * |  Type   | Length  | Value                   |
      34             :  * +---------+---------+-------------------------+
      35             :  *
      36             :  */
      37             : class ThreadTLV final
      38             : {
      39             :     static constexpr uint8_t kLengthEscape = 0xff; ///< This length value indicates the actual length is of two-bytes length, which
      40             :                                                    ///< not allowed in Thread Operational Dataset TLVs.
      41             : 
      42             : public:
      43             :     enum : uint8_t
      44             :     {
      45             :         kChannel         = 0,
      46             :         kPanId           = 1,
      47             :         kExtendedPanId   = 2,
      48             :         kNetworkName     = 3,
      49             :         kPSKc            = 4,
      50             :         kMasterKey       = 5,
      51             :         kMeshLocalPrefix = 7,
      52             :         kActiveTimestamp = 14,
      53             :     };
      54             : 
      55          21 :     uint8_t GetSize() const { return static_cast<uint8_t>(sizeof(*this) + GetLength()); }
      56             : 
      57         159 :     uint8_t GetType() const { return mType; }
      58             : 
      59          11 :     void SetType(uint8_t aType) { mType = aType; }
      60             : 
      61         177 :     uint8_t GetLength() const
      62             :     {
      63         177 :         assert(mLength != kLengthEscape);
      64         177 :         return mLength;
      65             :     }
      66             : 
      67          11 :     void SetLength(uint8_t aLength)
      68             :     {
      69          11 :         assert(mLength != kLengthEscape);
      70          11 :         mLength = aLength;
      71          11 :     }
      72             : 
      73         171 :     const void * GetValue() const
      74             :     {
      75         171 :         assert(mLength != kLengthEscape);
      76             : 
      77             :         static_assert(sizeof(*this) == sizeof(ThreadTLV::mType) + sizeof(ThreadTLV::mLength), "Wrong size for ThreadTLV header");
      78             : 
      79         171 :         return reinterpret_cast<const uint8_t *>(this) + sizeof(*this);
      80             :     }
      81             : 
      82          14 :     void * GetValue() { return const_cast<void *>(const_cast<const ThreadTLV *>(this)->GetValue()); }
      83             : 
      84           2 :     void Get64(uint64_t & aValue) const
      85             :     {
      86           2 :         assert(GetLength() >= sizeof(aValue));
      87             : 
      88           2 :         const uint8_t * p = reinterpret_cast<const uint8_t *>(GetValue());
      89           2 :         aValue            =                       //
      90           2 :             (static_cast<uint64_t>(p[0]) << 56) | //
      91           2 :             (static_cast<uint64_t>(p[1]) << 48) | //
      92           2 :             (static_cast<uint64_t>(p[2]) << 40) | //
      93           2 :             (static_cast<uint64_t>(p[3]) << 32) | //
      94           2 :             (static_cast<uint64_t>(p[4]) << 24) | //
      95           2 :             (static_cast<uint64_t>(p[5]) << 16) | //
      96           2 :             (static_cast<uint64_t>(p[6]) << 8) |  //
      97           2 :             (static_cast<uint64_t>(p[7]));
      98           2 :     }
      99             : 
     100           2 :     void Get16(uint16_t & aValue) const
     101             :     {
     102           2 :         assert(GetLength() >= sizeof(aValue));
     103             : 
     104           2 :         const uint8_t * p = static_cast<const uint8_t *>(GetValue());
     105             : 
     106           2 :         aValue = static_cast<uint16_t>(p[0] << 8 | p[1]);
     107           2 :     }
     108             : 
     109             :     void Get8(uint8_t & aValue) const
     110             :     {
     111             :         assert(GetLength() >= sizeof(aValue));
     112             :         aValue = *static_cast<const uint8_t *>(GetValue());
     113             :     }
     114             : 
     115           1 :     void Set64(uint64_t aValue)
     116             :     {
     117           1 :         uint8_t * value = static_cast<uint8_t *>(GetValue());
     118             : 
     119           1 :         SetLength(sizeof(aValue));
     120             : 
     121           1 :         value[0] = static_cast<uint8_t>((aValue >> 56) & 0xff);
     122           1 :         value[1] = static_cast<uint8_t>((aValue >> 48) & 0xff);
     123           1 :         value[2] = static_cast<uint8_t>((aValue >> 40) & 0xff);
     124           1 :         value[3] = static_cast<uint8_t>((aValue >> 32) & 0xff);
     125           1 :         value[4] = static_cast<uint8_t>((aValue >> 24) & 0xff);
     126           1 :         value[5] = static_cast<uint8_t>((aValue >> 16) & 0xff);
     127           1 :         value[6] = static_cast<uint8_t>((aValue >> 8) & 0xff);
     128           1 :         value[7] = static_cast<uint8_t>(aValue & 0xff);
     129           1 :     }
     130             : 
     131           1 :     void Set16(uint16_t aValue)
     132             :     {
     133           1 :         uint8_t * value = static_cast<uint8_t *>(GetValue());
     134             : 
     135           1 :         SetLength(sizeof(aValue));
     136             : 
     137           1 :         value[0] = static_cast<uint8_t>(aValue >> 8);
     138           1 :         value[1] = static_cast<uint8_t>(aValue & 0xff);
     139           1 :     }
     140             : 
     141             :     void Set8(uint8_t aValue)
     142             :     {
     143             :         SetLength(sizeof(aValue));
     144             :         *static_cast<uint8_t *>(GetValue()) = aValue;
     145             :     }
     146             : 
     147             :     void Set8(int8_t aValue)
     148             :     {
     149             :         SetLength(sizeof(aValue));
     150             :         *static_cast<int8_t *>(GetValue()) = aValue;
     151             :     }
     152             : 
     153           9 :     void SetValue(const void * aValue, uint8_t aLength)
     154             :     {
     155           9 :         SetLength(aLength);
     156           9 :         memcpy(GetValue(), aValue, aLength);
     157           9 :     }
     158             : 
     159         138 :     const ThreadTLV * GetNext() const
     160             :     {
     161             :         static_assert(alignof(ThreadTLV) == 1, "Wrong alignment for ThreadTLV header");
     162         138 :         return reinterpret_cast<const ThreadTLV *>(static_cast<const uint8_t *>(GetValue()) + GetLength());
     163             :     }
     164             : 
     165           3 :     ThreadTLV * GetNext() { return reinterpret_cast<ThreadTLV *>(static_cast<uint8_t *>(GetValue()) + GetLength()); }
     166             : 
     167           2 :     static bool IsValid(ByteSpan aData)
     168             :     {
     169           2 :         const uint8_t * const end = aData.data() + aData.size();
     170           2 :         const uint8_t * curr      = aData.data();
     171             : 
     172           3 :         while (curr + sizeof(ThreadTLV) < end)
     173             :         {
     174           1 :             const ThreadTLV * tlv = reinterpret_cast<const ThreadTLV *>(curr);
     175             : 
     176           1 :             if (tlv->GetLength() == kLengthEscape)
     177             :             {
     178           0 :                 break;
     179             :             }
     180             : 
     181           1 :             curr = reinterpret_cast<const uint8_t *>(tlv->GetNext());
     182             :         }
     183             : 
     184           2 :         return curr == end;
     185             :     }
     186             : 
     187             : private:
     188             :     uint8_t mType;
     189             :     uint8_t mLength;
     190             : };
     191             : 
     192           0 : bool OperationalDataset::IsValid(ByteSpan aData)
     193             : {
     194           0 :     return ThreadTLV::IsValid(aData);
     195             : }
     196             : 
     197           4 : CHIP_ERROR OperationalDataset::Init(ByteSpan aData)
     198             : {
     199           4 :     if (aData.size() > sizeof(mData))
     200             :     {
     201           1 :         return CHIP_ERROR_INVALID_ARGUMENT;
     202             :     }
     203             : 
     204           3 :     if (aData.size() > 0)
     205             :     {
     206           2 :         if (!ThreadTLV::IsValid(aData))
     207             :         {
     208           2 :             return CHIP_ERROR_INVALID_ARGUMENT;
     209             :         }
     210             : 
     211           0 :         memcpy(mData, aData.data(), aData.size());
     212             :     }
     213             : 
     214           1 :     mLength = static_cast<uint8_t>(aData.size());
     215           1 :     return CHIP_NO_ERROR;
     216             : }
     217             : 
     218           3 : CHIP_ERROR OperationalDataset::GetActiveTimestamp(uint64_t & aActiveTimestamp) const
     219             : {
     220           3 :     const ThreadTLV * tlv = Locate(ThreadTLV::kActiveTimestamp);
     221             : 
     222           3 :     if (tlv != nullptr)
     223             :     {
     224           2 :         tlv->Get64(aActiveTimestamp);
     225           2 :         return CHIP_NO_ERROR;
     226             :     }
     227             : 
     228           1 :     return CHIP_ERROR_TLV_TAG_NOT_FOUND;
     229             : }
     230             : 
     231           1 : CHIP_ERROR OperationalDataset::SetActiveTimestamp(uint64_t aActiveTimestamp)
     232             : {
     233           1 :     ThreadTLV * tlv = MakeRoom(ThreadTLV::kActiveTimestamp, sizeof(*tlv) + sizeof(aActiveTimestamp));
     234             : 
     235           1 :     if (tlv == nullptr)
     236             :     {
     237           0 :         return CHIP_ERROR_NO_MEMORY;
     238             :     }
     239             : 
     240           1 :     tlv->Set64(aActiveTimestamp);
     241             : 
     242           1 :     mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
     243             : 
     244           1 :     return CHIP_NO_ERROR;
     245             : }
     246             : 
     247           3 : CHIP_ERROR OperationalDataset::GetChannel(uint16_t & aChannel) const
     248             : {
     249           3 :     const ThreadTLV * tlv = Locate(ThreadTLV::kChannel);
     250             : 
     251           3 :     if (tlv != nullptr)
     252             :     {
     253           2 :         const uint8_t * value = reinterpret_cast<const uint8_t *>(tlv->GetValue());
     254           2 :         aChannel              = static_cast<uint16_t>((value[1] << 8) | value[2]);
     255           2 :         return CHIP_NO_ERROR;
     256             :     }
     257             : 
     258           1 :     return CHIP_ERROR_TLV_TAG_NOT_FOUND;
     259             : }
     260             : 
     261           1 : CHIP_ERROR OperationalDataset::SetChannel(uint16_t aChannel)
     262             : {
     263           1 :     uint8_t value[] = { 0, static_cast<uint8_t>(aChannel >> 8), static_cast<uint8_t>(aChannel & 0xff) };
     264           1 :     ThreadTLV * tlv = MakeRoom(ThreadTLV::kChannel, sizeof(*tlv) + sizeof(value));
     265             : 
     266           1 :     if (tlv == nullptr)
     267             :     {
     268           0 :         return CHIP_ERROR_NO_MEMORY;
     269             :     }
     270             : 
     271           1 :     tlv->SetValue(value, sizeof(value));
     272             : 
     273           1 :     mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
     274             : 
     275           1 :     return CHIP_NO_ERROR;
     276             : }
     277             : 
     278           3 : CHIP_ERROR OperationalDataset::GetExtendedPanId(uint8_t (&aExtendedPanId)[kSizeExtendedPanId]) const
     279             : {
     280           3 :     ByteSpan extPanIdSpan;
     281           3 :     CHIP_ERROR error = GetExtendedPanIdAsByteSpan(extPanIdSpan);
     282             : 
     283           3 :     if (error != CHIP_NO_ERROR)
     284             :     {
     285           1 :         return error;
     286             :     }
     287             : 
     288           2 :     memcpy(aExtendedPanId, extPanIdSpan.data(), extPanIdSpan.size());
     289           2 :     return CHIP_NO_ERROR;
     290             : }
     291             : 
     292           4 : CHIP_ERROR OperationalDataset::GetExtendedPanIdAsByteSpan(ByteSpan & span) const
     293             : {
     294           4 :     const ThreadTLV * tlv = Locate(ThreadTLV::kExtendedPanId);
     295             : 
     296           4 :     if (tlv == nullptr)
     297             :     {
     298           1 :         return CHIP_ERROR_TLV_TAG_NOT_FOUND;
     299             :     }
     300             : 
     301           3 :     if (tlv->GetLength() != kSizeExtendedPanId)
     302             :     {
     303           0 :         return CHIP_ERROR_INVALID_TLV_ELEMENT;
     304             :     }
     305             : 
     306           3 :     span = ByteSpan(static_cast<const uint8_t *>(tlv->GetValue()), tlv->GetLength());
     307           3 :     return CHIP_NO_ERROR;
     308             : }
     309             : 
     310           1 : CHIP_ERROR OperationalDataset::SetExtendedPanId(const uint8_t (&aExtendedPanId)[kSizeExtendedPanId])
     311             : {
     312           1 :     ThreadTLV * tlv = MakeRoom(ThreadTLV::kExtendedPanId, sizeof(*tlv) + sizeof(aExtendedPanId));
     313             : 
     314           1 :     if (tlv == nullptr)
     315             :     {
     316           0 :         return CHIP_ERROR_NO_MEMORY;
     317             :     }
     318             : 
     319           1 :     tlv->SetValue(aExtendedPanId, sizeof(aExtendedPanId));
     320             : 
     321           1 :     assert(mLength + tlv->GetSize() <= sizeof(mData));
     322             : 
     323           1 :     mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
     324             : 
     325           1 :     return CHIP_NO_ERROR;
     326             : }
     327             : 
     328           5 : CHIP_ERROR OperationalDataset::GetMasterKey(uint8_t (&aMasterKey)[kSizeMasterKey]) const
     329             : {
     330           5 :     const ThreadTLV * tlv = Locate(ThreadTLV::kMasterKey);
     331             : 
     332           5 :     if (tlv != nullptr)
     333             :     {
     334           3 :         memcpy(aMasterKey, tlv->GetValue(), sizeof(aMasterKey));
     335           3 :         return CHIP_NO_ERROR;
     336             :     }
     337             : 
     338           2 :     return CHIP_ERROR_TLV_TAG_NOT_FOUND;
     339             : }
     340             : 
     341           2 : CHIP_ERROR OperationalDataset::SetMasterKey(const uint8_t (&aMasterKey)[kSizeMasterKey])
     342             : {
     343           2 :     ThreadTLV * tlv = MakeRoom(ThreadTLV::kMasterKey, sizeof(*tlv) + sizeof(aMasterKey));
     344             : 
     345           2 :     if (tlv == nullptr)
     346             :     {
     347           0 :         return CHIP_ERROR_NO_MEMORY;
     348             :     }
     349             : 
     350           2 :     tlv->SetValue(aMasterKey, sizeof(aMasterKey));
     351             : 
     352           2 :     assert(mLength + tlv->GetSize() <= sizeof(mData));
     353             : 
     354           2 :     mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
     355             : 
     356           2 :     return CHIP_NO_ERROR;
     357             : }
     358             : 
     359           3 : CHIP_ERROR OperationalDataset::GetMeshLocalPrefix(uint8_t (&aMeshLocalPrefix)[kSizeMeshLocalPrefix]) const
     360             : {
     361           3 :     const ThreadTLV * tlv = Locate(ThreadTLV::kMeshLocalPrefix);
     362             : 
     363           3 :     if (tlv != nullptr)
     364             :     {
     365           2 :         memcpy(aMeshLocalPrefix, tlv->GetValue(), sizeof(aMeshLocalPrefix));
     366           2 :         return CHIP_NO_ERROR;
     367             :     }
     368             : 
     369           1 :     return CHIP_ERROR_TLV_TAG_NOT_FOUND;
     370             : }
     371             : 
     372           1 : CHIP_ERROR OperationalDataset::SetMeshLocalPrefix(const uint8_t (&aMeshLocalPrefix)[kSizeMeshLocalPrefix])
     373             : {
     374           1 :     ThreadTLV * tlv = MakeRoom(ThreadTLV::kMeshLocalPrefix, sizeof(*tlv) + sizeof(aMeshLocalPrefix));
     375             : 
     376           1 :     if (tlv == nullptr)
     377             :     {
     378           0 :         return CHIP_ERROR_NO_MEMORY;
     379             :     }
     380             : 
     381           1 :     tlv->SetValue(aMeshLocalPrefix, sizeof(aMeshLocalPrefix));
     382             : 
     383           1 :     mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
     384             : 
     385           1 :     return CHIP_NO_ERROR;
     386             : }
     387             : 
     388           3 : CHIP_ERROR OperationalDataset::GetNetworkName(char (&aNetworkName)[kSizeNetworkName + 1]) const
     389             : {
     390           3 :     const ThreadTLV * tlv = Locate(ThreadTLV::kNetworkName);
     391             : 
     392           3 :     if (tlv != nullptr)
     393             :     {
     394           2 :         memcpy(aNetworkName, tlv->GetValue(), tlv->GetLength());
     395           2 :         aNetworkName[tlv->GetLength()] = '\0';
     396           2 :         return CHIP_NO_ERROR;
     397             :     }
     398             : 
     399           1 :     return CHIP_ERROR_TLV_TAG_NOT_FOUND;
     400             : }
     401             : 
     402           4 : CHIP_ERROR OperationalDataset::SetNetworkName(const char * aNetworkName)
     403             : {
     404           4 :     size_t len = strlen(aNetworkName);
     405             : 
     406           4 :     if (len > kSizeNetworkName || len == 0)
     407             :     {
     408           2 :         return CHIP_ERROR_INVALID_STRING_LENGTH;
     409             :     }
     410             : 
     411           2 :     ThreadTLV * tlv = MakeRoom(ThreadTLV::kNetworkName, static_cast<uint8_t>(sizeof(*tlv) + static_cast<uint8_t>(len)));
     412             : 
     413           2 :     if (tlv == nullptr)
     414             :     {
     415           0 :         return CHIP_ERROR_NO_MEMORY;
     416             :     }
     417             : 
     418           2 :     tlv->SetValue(aNetworkName, static_cast<uint8_t>(len));
     419             : 
     420           2 :     mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
     421             : 
     422           2 :     return CHIP_NO_ERROR;
     423             : }
     424             : 
     425           3 : CHIP_ERROR OperationalDataset::GetPanId(uint16_t & aPanId) const
     426             : {
     427           3 :     const ThreadTLV * tlv = Locate(ThreadTLV::kPanId);
     428             : 
     429           3 :     if (tlv != nullptr)
     430             :     {
     431           2 :         tlv->Get16(aPanId);
     432           2 :         return CHIP_NO_ERROR;
     433             :     }
     434             : 
     435           1 :     return CHIP_ERROR_TLV_TAG_NOT_FOUND;
     436             : }
     437             : 
     438           1 : CHIP_ERROR OperationalDataset::SetPanId(uint16_t aPanId)
     439             : {
     440           1 :     ThreadTLV * tlv = MakeRoom(ThreadTLV::kPanId, sizeof(*tlv) + sizeof(aPanId));
     441             : 
     442           1 :     if (tlv == nullptr)
     443             :     {
     444           0 :         return CHIP_ERROR_NO_MEMORY;
     445             :     }
     446             : 
     447           1 :     tlv->Set16(aPanId);
     448             : 
     449           1 :     mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
     450             : 
     451           1 :     return CHIP_NO_ERROR;
     452             : }
     453             : 
     454           5 : CHIP_ERROR OperationalDataset::GetPSKc(uint8_t (&aPSKc)[kSizePSKc]) const
     455             : {
     456           5 :     const ThreadTLV * tlv = Locate(ThreadTLV::kPSKc);
     457             : 
     458           5 :     if (tlv != nullptr)
     459             :     {
     460           3 :         memcpy(aPSKc, tlv->GetValue(), sizeof(aPSKc));
     461           3 :         return CHIP_NO_ERROR;
     462             :     }
     463             : 
     464           2 :     return CHIP_ERROR_TLV_TAG_NOT_FOUND;
     465             : }
     466             : 
     467           2 : CHIP_ERROR OperationalDataset::SetPSKc(const uint8_t (&aPSKc)[kSizePSKc])
     468             : {
     469           2 :     ThreadTLV * tlv = MakeRoom(ThreadTLV::kPSKc, sizeof(*tlv) + sizeof(aPSKc));
     470             : 
     471           2 :     if (tlv == nullptr)
     472             :     {
     473           0 :         return CHIP_ERROR_NO_MEMORY;
     474             :     }
     475             : 
     476           2 :     tlv->SetValue(aPSKc, sizeof(aPSKc));
     477             : 
     478           2 :     mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
     479             : 
     480           2 :     return CHIP_NO_ERROR;
     481             : }
     482             : 
     483           1 : void OperationalDataset::UnsetMasterKey()
     484             : {
     485           1 :     Remove(ThreadTLV::kMasterKey);
     486           1 : }
     487             : 
     488           1 : void OperationalDataset::UnsetPSKc()
     489             : {
     490           1 :     Remove(ThreadTLV::kPSKc);
     491           1 : }
     492             : 
     493           0 : bool OperationalDataset::IsCommissioned() const
     494             : {
     495           0 :     return Has(ThreadTLV::kPanId) && Has(ThreadTLV::kMasterKey) && Has(ThreadTLV::kExtendedPanId) && Has(ThreadTLV::kChannel);
     496             : }
     497             : 
     498          42 : const ThreadTLV * OperationalDataset::Locate(uint8_t aType) const
     499             : {
     500          42 :     const ThreadTLV * tlv = &Begin();
     501          42 :     const ThreadTLV * end = &End();
     502             : 
     503         179 :     while (tlv < end)
     504             :     {
     505         159 :         if (tlv->GetType() == aType)
     506          22 :             break;
     507         137 :         tlv = tlv->GetNext();
     508             :     }
     509             : 
     510          42 :     assert(tlv < reinterpret_cast<const ThreadTLV *>(&mData[sizeof(mData)]));
     511             : 
     512          42 :     return tlv != end ? tlv : nullptr;
     513             : }
     514             : 
     515           3 : void OperationalDataset::Remove(ThreadTLV & aThreadTLV)
     516             : {
     517           3 :     uint8_t offset = static_cast<uint8_t>(reinterpret_cast<uint8_t *>(&aThreadTLV) - mData);
     518             : 
     519           3 :     if (offset < mLength && mLength >= (offset + aThreadTLV.GetSize()))
     520             :     {
     521           3 :         mLength = static_cast<uint8_t>(mLength - aThreadTLV.GetSize());
     522           3 :         memmove(&aThreadTLV, aThreadTLV.GetNext(), mLength - offset);
     523             :     }
     524           3 : }
     525             : 
     526           2 : void OperationalDataset::Remove(uint8_t aType)
     527             : {
     528           2 :     ThreadTLV * tlv = Locate(aType);
     529             : 
     530           2 :     if (tlv != nullptr)
     531             :     {
     532           2 :         Remove(*tlv);
     533             :     }
     534           2 : }
     535             : 
     536          11 : ThreadTLV * OperationalDataset::MakeRoom(uint8_t aType, uint8_t aSize)
     537             : {
     538          11 :     ThreadTLV * tlv = Locate(aType);
     539             : 
     540          11 :     size_t freeSpace = sizeof(mData) - mLength;
     541             : 
     542          11 :     if (tlv != nullptr)
     543             :     {
     544           1 :         if (freeSpace + tlv->GetSize() < aSize)
     545             :         {
     546           0 :             return nullptr;
     547             :         }
     548             : 
     549           1 :         Remove(*tlv);
     550             :     }
     551          10 :     else if (freeSpace < aSize)
     552             :     {
     553           0 :         return nullptr;
     554             :     }
     555             : 
     556          11 :     End().SetType(aType);
     557             : 
     558          11 :     return &End();
     559             : }
     560             : 
     561             : } // namespace Thread
     562             : } // namespace chip

Generated by: LCOV version 1.14