Matter SDK Coverage Report
Current view: top level - credentials - GroupDataProviderImpl.cpp (source / functions) Coverage Total Hit
Test: SHA:e021a368d10ac6f3f201c101585146211fdcdaa2 Lines: 95.2 % 1088 1036
Test Date: 2026-02-13 08:13:38 Functions: 98.4 % 127 125

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021-2022 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              : #include <credentials/GroupDataProviderImpl.h>
      18              : #include <crypto/CHIPCryptoPAL.h>
      19              : #include <lib/core/TLV.h>
      20              : #include <lib/support/CodeUtils.h>
      21              : #include <lib/support/CommonPersistentData.h>
      22              : #include <lib/support/DefaultStorageKeyAllocator.h>
      23              : #include <lib/support/PersistentData.h>
      24              : #include <lib/support/Pool.h>
      25              : #include <stdlib.h>
      26              : 
      27              : namespace chip {
      28              : namespace Credentials {
      29              : 
      30              : using GroupInfo     = GroupDataProvider::GroupInfo;
      31              : using GroupKey      = GroupDataProvider::GroupKey;
      32              : using GroupEndpoint = GroupDataProvider::GroupEndpoint;
      33              : using EpochKey      = GroupDataProvider::EpochKey;
      34              : using KeySet        = GroupDataProvider::KeySet;
      35              : using GroupSession  = GroupDataProvider::GroupSession;
      36              : 
      37              : struct FabricList : public CommonPersistentData::FabricList
      38              : {
      39          993 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
      40              :     {
      41          993 :         key = DefaultStorageKeyAllocator::GroupFabricList();
      42          993 :         return CHIP_NO_ERROR;
      43              :     }
      44              : };
      45              : 
      46              : constexpr size_t kPersistentBufferMax = 128;
      47              : 
      48              : struct LinkedData : public PersistableData<kPersistentBufferMax>
      49              : {
      50              :     static constexpr uint16_t kMinLinkId = 1;
      51              : 
      52           66 :     LinkedData() = default;
      53          617 :     LinkedData(uint16_t linked_id) : id(linked_id) {}
      54              :     uint16_t id     = kMinLinkId;
      55              :     uint16_t index  = 0;
      56              :     uint16_t next   = 0;
      57              :     uint16_t prev   = 0;
      58              :     uint16_t max_id = 0;
      59              :     bool first      = true;
      60              : };
      61              : 
      62              : struct FabricData : public PersistableData<kPersistentBufferMax>
      63              : {
      64         3930 :     static constexpr TLV::Tag TagFirstGroup() { return TLV::ContextTag(1); }
      65         3930 :     static constexpr TLV::Tag TagGroupCount() { return TLV::ContextTag(2); }
      66         3930 :     static constexpr TLV::Tag TagFirstMap() { return TLV::ContextTag(3); }
      67         3930 :     static constexpr TLV::Tag TagMapCount() { return TLV::ContextTag(4); }
      68         3930 :     static constexpr TLV::Tag TagFirstKeyset() { return TLV::ContextTag(5); }
      69         3930 :     static constexpr TLV::Tag TagKeysetCount() { return TLV::ContextTag(6); }
      70         3930 :     static constexpr TLV::Tag TagNext() { return TLV::ContextTag(7); }
      71              : 
      72              :     chip::FabricIndex fabric_index = kUndefinedFabricIndex;
      73              :     chip::GroupId first_group      = kUndefinedGroupId;
      74              :     uint16_t group_count           = 0;
      75              :     uint16_t first_map             = 0;
      76              :     uint16_t map_count             = 0;
      77              :     chip::KeysetId first_keyset    = kInvalidKeysetId;
      78              :     uint16_t keyset_count          = 0;
      79              :     chip::FabricIndex next         = kUndefinedFabricIndex;
      80              : 
      81           23 :     FabricData() = default;
      82         3279 :     FabricData(chip::FabricIndex fabric) : fabric_index(fabric) {}
      83              : 
      84         4170 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
      85              :     {
      86         4170 :         VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX);
      87         4168 :         key = DefaultStorageKeyAllocator::FabricGroups(fabric_index);
      88         4168 :         return CHIP_NO_ERROR;
      89              :     }
      90              : 
      91         3319 :     void Clear() override
      92              :     {
      93         3319 :         first_group  = kUndefinedGroupId;
      94         3319 :         group_count  = 0;
      95         3319 :         first_keyset = kInvalidKeysetId;
      96         3319 :         keyset_count = 0;
      97         3319 :         next         = kUndefinedFabricIndex;
      98         3319 :     }
      99              : 
     100          830 :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
     101              :     {
     102              :         TLV::TLVType container;
     103          830 :         ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
     104              : 
     105          830 :         ReturnErrorOnFailure(writer.Put(TagFirstGroup(), static_cast<uint16_t>(first_group)));
     106          830 :         ReturnErrorOnFailure(writer.Put(TagGroupCount(), static_cast<uint16_t>(group_count)));
     107          830 :         ReturnErrorOnFailure(writer.Put(TagFirstMap(), static_cast<uint16_t>(first_map)));
     108          830 :         ReturnErrorOnFailure(writer.Put(TagMapCount(), static_cast<uint16_t>(map_count)));
     109          830 :         ReturnErrorOnFailure(writer.Put(TagFirstKeyset(), static_cast<uint16_t>(first_keyset)));
     110          830 :         ReturnErrorOnFailure(writer.Put(TagKeysetCount(), static_cast<uint16_t>(keyset_count)));
     111          830 :         ReturnErrorOnFailure(writer.Put(TagNext(), static_cast<uint16_t>(next)));
     112              : 
     113          830 :         return writer.EndContainer(container);
     114              :     }
     115         3100 :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override
     116              :     {
     117         3100 :         ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     118         3100 :         VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     119              : 
     120              :         TLV::TLVType container;
     121         3100 :         ReturnErrorOnFailure(reader.EnterContainer(container));
     122              : 
     123              :         // first_group
     124         3100 :         ReturnErrorOnFailure(reader.Next(TagFirstGroup()));
     125         3100 :         ReturnErrorOnFailure(reader.Get(first_group));
     126              :         // group_count
     127         3100 :         ReturnErrorOnFailure(reader.Next(TagGroupCount()));
     128         3100 :         ReturnErrorOnFailure(reader.Get(group_count));
     129              :         // first_map
     130         3100 :         ReturnErrorOnFailure(reader.Next(TagFirstMap()));
     131         3100 :         ReturnErrorOnFailure(reader.Get(first_map));
     132              :         // map_count
     133         3100 :         ReturnErrorOnFailure(reader.Next(TagMapCount()));
     134         3100 :         ReturnErrorOnFailure(reader.Get(map_count));
     135              :         // first_keyset
     136         3100 :         ReturnErrorOnFailure(reader.Next(TagFirstKeyset()));
     137         3100 :         ReturnErrorOnFailure(reader.Get(first_keyset));
     138              :         // keyset_count
     139         3100 :         ReturnErrorOnFailure(reader.Next(TagKeysetCount()));
     140         3100 :         ReturnErrorOnFailure(reader.Get(keyset_count));
     141              :         // next
     142         3100 :         ReturnErrorOnFailure(reader.Next(TagNext()));
     143         3100 :         ReturnErrorOnFailure(reader.Get(next));
     144              : 
     145         3100 :         return reader.ExitContainer(container);
     146              :     }
     147              : 
     148              :     // Register the fabric in the fabrics' linked-list
     149          830 :     CHIP_ERROR Register(PersistentStorageDelegate * storage)
     150              :     {
     151          830 :         FabricList fabric_list;
     152          830 :         CHIP_ERROR err = fabric_list.Load(storage);
     153         1660 :         if (CHIP_ERROR_NOT_FOUND == err)
     154              :         {
     155              :             // New fabric list
     156           91 :             fabric_list.first_entry = fabric_index;
     157           91 :             fabric_list.entry_count = 1;
     158           91 :             return fabric_list.Save(storage);
     159              :         }
     160          739 :         ReturnErrorOnFailure(err);
     161              : 
     162              :         // Existing fabric list, search for existing entry
     163          739 :         FabricData fabric(fabric_list.first_entry);
     164          795 :         for (size_t i = 0; i < fabric_list.entry_count; i++)
     165              :         {
     166          774 :             err = fabric.Load(storage);
     167         1548 :             if (CHIP_NO_ERROR != err)
     168              :             {
     169            0 :                 break;
     170              :             }
     171          774 :             if (fabric.fabric_index == this->fabric_index)
     172              :             {
     173              :                 // Fabric already registered
     174          718 :                 return CHIP_NO_ERROR;
     175              :             }
     176           56 :             fabric.fabric_index = fabric.next;
     177              :         }
     178              :         // Add this fabric to the fabric list
     179           21 :         this->next              = fabric_list.first_entry;
     180           21 :         fabric_list.first_entry = this->fabric_index;
     181           21 :         fabric_list.entry_count++;
     182           21 :         return fabric_list.Save(storage);
     183          830 :     }
     184              : 
     185              :     // Remove the fabric from the fabrics' linked list
     186           23 :     CHIP_ERROR Unregister(PersistentStorageDelegate * storage) const
     187              :     {
     188           23 :         FabricList fabric_list;
     189           23 :         CHIP_ERROR err = fabric_list.Load(storage);
     190           48 :         VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
     191              : 
     192              :         // Existing fabric list, search for existing entry
     193           23 :         FabricData fabric(fabric_list.first_entry);
     194           23 :         FabricData prev;
     195              : 
     196           33 :         for (size_t i = 0; i < fabric_list.entry_count; i++)
     197              :         {
     198           29 :             err = fabric.Load(storage);
     199           58 :             if (CHIP_NO_ERROR != err)
     200              :             {
     201            0 :                 break;
     202              :             }
     203           29 :             if (fabric.fabric_index == this->fabric_index)
     204              :             {
     205              :                 // Fabric found
     206           19 :                 if (i == 0)
     207              :                 {
     208              :                     // Remove first fabric
     209           10 :                     fabric_list.first_entry = this->next;
     210              :                 }
     211              :                 else
     212              :                 {
     213              :                     // Remove intermediate fabric
     214            9 :                     prev.next = this->next;
     215            9 :                     ReturnErrorOnFailure(prev.Save(storage));
     216              :                 }
     217           19 :                 VerifyOrReturnError(fabric_list.entry_count > 0, CHIP_ERROR_INTERNAL);
     218           19 :                 fabric_list.entry_count--;
     219           19 :                 return fabric_list.Save(storage);
     220              :             }
     221           10 :             prev                = fabric;
     222           10 :             fabric.fabric_index = fabric.next;
     223              :         }
     224              :         // Fabric not in the list
     225            4 :         return CHIP_ERROR_NOT_FOUND;
     226           23 :     }
     227              : 
     228              :     // Check the fabric is registered in the fabrics' linked list
     229              :     CHIP_ERROR Validate(PersistentStorageDelegate * storage) const
     230              :     {
     231              :         FabricList fabric_list;
     232              :         ReturnErrorOnFailure(fabric_list.Load(storage));
     233              : 
     234              :         // Existing fabric list, search for existing entry
     235              :         FabricData fabric(fabric_list.first_entry);
     236              : 
     237              :         for (size_t i = 0; i < fabric_list.entry_count; i++)
     238              :         {
     239              :             ReturnErrorOnFailure(fabric.Load(storage));
     240              :             if (fabric.fabric_index == this->fabric_index)
     241              :             {
     242              :                 return CHIP_NO_ERROR;
     243              :             }
     244              :             fabric.fabric_index = fabric.next;
     245              :         }
     246              :         // Fabric not in the list
     247              :         return CHIP_ERROR_NOT_FOUND;
     248              :     }
     249              : 
     250          830 :     CHIP_ERROR Save(PersistentStorageDelegate * storage) // NOLINT(bugprone-derived-method-shadowing-base-method)
     251              :     {
     252          830 :         ReturnErrorOnFailure(Register(storage));
     253          830 :         return PersistableData::Save(storage);
     254              :     }
     255              : 
     256           23 :     CHIP_ERROR Delete(PersistentStorageDelegate * storage) // NOLINT(bugprone-derived-method-shadowing-base-method)
     257              :     {
     258           23 :         ReturnErrorOnFailure(Unregister(storage));
     259           19 :         return PersistableData::Delete(storage);
     260              :     }
     261              : };
     262              : 
     263              : struct GroupData : public GroupDataProvider::GroupInfo, PersistableData<kPersistentBufferMax>
     264              : {
     265         4608 :     static constexpr TLV::Tag TagName() { return TLV::ContextTag(1); }
     266         4608 :     static constexpr TLV::Tag TagFirstEndpoint() { return TLV::ContextTag(2); }
     267         4608 :     static constexpr TLV::Tag TagEndpointCount() { return TLV::ContextTag(3); }
     268         4608 :     static constexpr TLV::Tag TagNext() { return TLV::ContextTag(4); }
     269         4608 :     static constexpr TLV::Tag TagFlags() { return TLV::ContextTag(5); }
     270              : 
     271              :     chip::FabricIndex fabric_index  = kUndefinedFabricIndex;
     272              :     chip::EndpointId first_endpoint = kInvalidEndpointId;
     273              :     uint16_t endpoint_count         = 0;
     274              :     uint16_t index                  = 0;
     275              :     chip::GroupId next              = 0;
     276              :     chip::GroupId prev              = 0;
     277              :     bool first                      = true;
     278              : 
     279         1595 :     GroupData() : GroupInfo(nullptr){};
     280              :     GroupData(chip::FabricIndex fabric) : fabric_index(fabric) {}
     281         1238 :     GroupData(chip::FabricIndex fabric, chip::GroupId group) : GroupInfo(group, nullptr), fabric_index(fabric) {}
     282              : 
     283         4648 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
     284              :     {
     285         4648 :         VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX);
     286         4648 :         key = DefaultStorageKeyAllocator::FabricGroup(fabric_index, group_id);
     287         4648 :         return CHIP_NO_ERROR;
     288              :     }
     289              : 
     290         3317 :     void Clear() override
     291              :     {
     292         3317 :         SetName(CharSpan());
     293         3317 :         first_endpoint = kInvalidEndpointId;
     294         3317 :         endpoint_count = 0;
     295         3317 :         next           = 0;
     296         3317 :         flags          = 0;
     297         3317 :     }
     298              : 
     299         1292 :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
     300              :     {
     301              :         TLV::TLVType container;
     302         1292 :         ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
     303              : 
     304         1292 :         size_t name_size = strnlen(name, GroupDataProvider::GroupInfo::kGroupNameMax);
     305         1292 :         ReturnErrorOnFailure(writer.PutString(TagName(), name, static_cast<uint32_t>(name_size)));
     306         1292 :         ReturnErrorOnFailure(writer.Put(TagFirstEndpoint(), static_cast<uint16_t>(first_endpoint)));
     307         1292 :         ReturnErrorOnFailure(writer.Put(TagEndpointCount(), static_cast<uint16_t>(endpoint_count)));
     308         1292 :         ReturnErrorOnFailure(writer.Put(TagNext(), static_cast<uint16_t>(next)));
     309         1292 :         ReturnErrorOnFailure(writer.Put(TagFlags(), static_cast<uint8_t>(flags)));
     310         1292 :         return writer.EndContainer(container);
     311              :     }
     312              : 
     313         3316 :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override
     314              :     {
     315         3316 :         ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     316         3316 :         VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     317              : 
     318              :         TLV::TLVType container;
     319         3316 :         ReturnErrorOnFailure(reader.EnterContainer(container));
     320              : 
     321              :         // name
     322         3316 :         ReturnErrorOnFailure(reader.Next(TagName()));
     323         3316 :         ReturnErrorOnFailure(reader.GetString(name, sizeof(name)));
     324         3316 :         size_t size = strnlen(name, kGroupNameMax);
     325         3316 :         name[size]  = 0;
     326              :         // first_endpoint
     327         3316 :         ReturnErrorOnFailure(reader.Next(TagFirstEndpoint()));
     328         3316 :         ReturnErrorOnFailure(reader.Get(first_endpoint));
     329              :         // endpoint_count
     330         3316 :         ReturnErrorOnFailure(reader.Next(TagEndpointCount()));
     331         3316 :         ReturnErrorOnFailure(reader.Get(endpoint_count));
     332              :         // next
     333         3316 :         ReturnErrorOnFailure(reader.Next(TagNext()));
     334         3316 :         ReturnErrorOnFailure(reader.Get(next));
     335              :         // Groupcast
     336         3316 :         CHIP_ERROR err = reader.Next(TagFlags());
     337         6632 :         if (CHIP_NO_ERROR == err)
     338              :         {
     339              :             // flags
     340         3316 :             uint8_t value = 0;
     341         3316 :             ReturnErrorOnFailure(reader.Get(value));
     342         3316 :             flags = value;
     343              :         }
     344         3316 :         return reader.ExitContainer(container);
     345              :     }
     346              : 
     347           83 :     bool Get(PersistentStorageDelegate * storage, const FabricData & fabric, size_t target_index)
     348              :     {
     349           83 :         fabric_index = fabric.fabric_index;
     350           83 :         group_id     = fabric.first_group;
     351           83 :         index        = 0;
     352           83 :         first        = true;
     353              : 
     354          142 :         while (index < fabric.group_count)
     355              :         {
     356          248 :             if (CHIP_NO_ERROR != Load(storage))
     357              :             {
     358            0 :                 break;
     359              :             }
     360          124 :             if (index == target_index)
     361              :             {
     362              :                 // Target index found
     363           65 :                 return true;
     364              :             }
     365              : 
     366           59 :             first    = false;
     367           59 :             prev     = group_id;
     368           59 :             group_id = next;
     369           59 :             index++;
     370              :         }
     371              : 
     372           18 :         return false;
     373              :     }
     374              : 
     375         1488 :     bool Find(PersistentStorageDelegate * storage, const FabricData & fabric, chip::GroupId target_group)
     376              :     {
     377         1488 :         fabric_index = fabric.fabric_index;
     378         1488 :         group_id     = fabric.first_group;
     379         1488 :         index        = 0;
     380         1488 :         first        = true;
     381              : 
     382         2449 :         while (index < fabric.group_count)
     383              :         {
     384         3900 :             if (CHIP_NO_ERROR != Load(storage))
     385              :             {
     386            0 :                 break;
     387              :             }
     388         1950 :             if (group_id == target_group)
     389              :             {
     390              :                 // Target index found
     391          989 :                 return true;
     392              :             }
     393          961 :             first    = false;
     394          961 :             prev     = group_id;
     395          961 :             group_id = next;
     396          961 :             index++;
     397              :         }
     398          499 :         return false;
     399              :     }
     400              : };
     401              : 
     402              : struct KeyMapData : public GroupDataProvider::GroupKey, LinkedData
     403              : {
     404         1416 :     static constexpr TLV::Tag TagGroupId() { return TLV::ContextTag(1); }
     405         1416 :     static constexpr TLV::Tag TagKeysetId() { return TLV::ContextTag(2); }
     406         1416 :     static constexpr TLV::Tag TagNext() { return TLV::ContextTag(3); }
     407              : 
     408              :     chip::FabricIndex fabric_index = kUndefinedFabricIndex;
     409              :     chip::GroupId group_id         = kUndefinedGroupId;
     410              :     chip::KeysetId keyset_id       = 0;
     411              : 
     412           66 :     KeyMapData(){};
     413          617 :     KeyMapData(chip::FabricIndex fabric, uint16_t link_id = 0, chip::GroupId group = kUndefinedGroupId, chip::KeysetId keyset = 0) :
     414          617 :         GroupKey(group, keyset), LinkedData(link_id), fabric_index(fabric)
     415          617 :     {}
     416              : 
     417         1433 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
     418              :     {
     419         1433 :         VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX);
     420         1433 :         key = DefaultStorageKeyAllocator::FabricGroupKey(fabric_index, id);
     421         1433 :         return CHIP_NO_ERROR;
     422              :     }
     423              : 
     424          965 :     void Clear() override {}
     425              : 
     426          451 :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
     427              :     {
     428              :         TLV::TLVType container;
     429          451 :         ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
     430              : 
     431          451 :         ReturnErrorOnFailure(writer.Put(TagGroupId(), static_cast<uint16_t>(group_id)));
     432          451 :         ReturnErrorOnFailure(writer.Put(TagKeysetId(), static_cast<uint16_t>(keyset_id)));
     433          451 :         ReturnErrorOnFailure(writer.Put(TagNext(), static_cast<uint16_t>(next)));
     434          451 :         return writer.EndContainer(container);
     435              :     }
     436              : 
     437          965 :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override
     438              :     {
     439          965 :         ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     440          965 :         VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     441              : 
     442              :         TLV::TLVType container;
     443          965 :         ReturnErrorOnFailure(reader.EnterContainer(container));
     444              : 
     445              :         // first_endpoint
     446          965 :         ReturnErrorOnFailure(reader.Next(TagGroupId()));
     447          965 :         ReturnErrorOnFailure(reader.Get(group_id));
     448              :         // endpoint_count
     449          965 :         ReturnErrorOnFailure(reader.Next(TagKeysetId()));
     450          965 :         ReturnErrorOnFailure(reader.Get(keyset_id));
     451              :         // next
     452          965 :         ReturnErrorOnFailure(reader.Next(TagNext()));
     453          965 :         ReturnErrorOnFailure(reader.Get(next));
     454              : 
     455          965 :         return reader.ExitContainer(container);
     456              :     }
     457              : 
     458          300 :     bool Get(PersistentStorageDelegate * storage, const FabricData & fabric, size_t target_index)
     459              :     {
     460          300 :         fabric_index = fabric.fabric_index;
     461          300 :         id           = fabric.first_map;
     462          300 :         max_id       = 0;
     463          300 :         index        = 0;
     464          300 :         first        = true;
     465              : 
     466          609 :         while (index < fabric.map_count)
     467              :         {
     468          700 :             if (CHIP_NO_ERROR != Load(storage))
     469              :             {
     470            0 :                 break;
     471              :             }
     472          350 :             if (index == target_index)
     473              :             {
     474              :                 // Target index found
     475           41 :                 return true;
     476              :             }
     477          309 :             max_id = std::max(id, max_id);
     478          309 :             first  = false;
     479          309 :             prev   = id;
     480          309 :             id     = next;
     481          309 :             index++;
     482              :         }
     483              : 
     484          259 :         id = static_cast<uint16_t>(max_id + 1);
     485          259 :         return false;
     486              :     }
     487              : 
     488          264 :     bool Find(PersistentStorageDelegate * storage, const FabricData & fabric, const GroupKey & map)
     489              :     {
     490          264 :         fabric_index = fabric.fabric_index;
     491          264 :         id           = fabric.first_map;
     492          264 :         max_id       = 0;
     493          264 :         index        = 0;
     494          264 :         first        = true;
     495              : 
     496          531 :         while (index < fabric.map_count)
     497              :         {
     498          552 :             if (CHIP_NO_ERROR != Load(storage))
     499              :             {
     500            0 :                 break;
     501              :             }
     502          276 :             if ((group_id == map.group_id) && (keyset_id == map.keyset_id))
     503              :             {
     504              :                 // Match found
     505            9 :                 return true;
     506              :             }
     507          267 :             max_id = std::max(id, max_id);
     508          267 :             first  = false;
     509          267 :             prev   = id;
     510          267 :             id     = next;
     511          267 :             index++;
     512              :         }
     513              : 
     514          255 :         id = static_cast<uint16_t>(max_id + 1);
     515          255 :         return false;
     516              :     }
     517              : 
     518              :     // returns index if the find_id is found, otherwise std::numeric_limits<size_t>::max
     519            0 :     size_t Find(PersistentStorageDelegate * storage, const FabricData & fabric, const KeysetId find_id)
     520              :     {
     521            0 :         fabric_index = fabric.fabric_index;
     522            0 :         id           = fabric.first_map;
     523            0 :         max_id       = 0;
     524            0 :         index        = 0;
     525            0 :         first        = true;
     526              : 
     527            0 :         while (index < fabric.map_count)
     528              :         {
     529            0 :             if (CHIP_NO_ERROR != Load(storage))
     530              :             {
     531            0 :                 break;
     532              :             }
     533            0 :             if (keyset_id == find_id)
     534              :             {
     535              :                 // Match found
     536            0 :                 return index;
     537              :             }
     538            0 :             max_id = std::max(id, max_id);
     539            0 :             first  = false;
     540            0 :             prev   = id;
     541            0 :             id     = next;
     542            0 :             index++;
     543              :         }
     544              : 
     545            0 :         id = static_cast<uint16_t>(max_id + 1);
     546            0 :         return std::numeric_limits<size_t>::max();
     547              :     }
     548              : };
     549              : 
     550              : struct EndpointData : GroupDataProvider::GroupEndpoint, PersistableData<kPersistentBufferMax>
     551              : {
     552        62302 :     static constexpr TLV::Tag TagEndpoint() { return TLV::ContextTag(1); }
     553        62302 :     static constexpr TLV::Tag TagNext() { return TLV::ContextTag(2); }
     554              : 
     555              :     chip::FabricIndex fabric_index = kUndefinedFabricIndex;
     556              :     uint16_t index                 = 0;
     557              :     chip::EndpointId next          = 0;
     558              :     chip::EndpointId prev          = 0;
     559              :     bool first                     = true;
     560              : 
     561          934 :     EndpointData() = default;
     562         1608 :     EndpointData(chip::FabricIndex fabric, chip::GroupId group = kUndefinedGroupId,
     563         1608 :                  chip::EndpointId endpoint = kInvalidEndpointId) :
     564              :         GroupEndpoint(group, endpoint),
     565         1608 :         fabric_index(fabric)
     566         1608 :     {}
     567              : 
     568        62379 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
     569              :     {
     570        62379 :         VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX);
     571        62379 :         key = DefaultStorageKeyAllocator::FabricGroupEndpoint(fabric_index, group_id, endpoint_id);
     572        62379 :         return CHIP_NO_ERROR;
     573              :     }
     574              : 
     575        60356 :     void Clear() override { next = kInvalidEndpointId; }
     576              : 
     577         1957 :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
     578              :     {
     579              :         TLV::TLVType container;
     580         1957 :         ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
     581              : 
     582         1957 :         ReturnErrorOnFailure(writer.Put(TagEndpoint(), static_cast<uint16_t>(endpoint_id)));
     583         1957 :         ReturnErrorOnFailure(writer.Put(TagNext(), static_cast<uint16_t>(next)));
     584              : 
     585         1957 :         return writer.EndContainer(container);
     586              :     }
     587        60345 :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override
     588              :     {
     589        60345 :         ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     590        60345 :         VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     591              : 
     592              :         TLV::TLVType container;
     593        60345 :         ReturnErrorOnFailure(reader.EnterContainer(container));
     594              : 
     595              :         // endpoint_id
     596        60345 :         ReturnErrorOnFailure(reader.Next(TagEndpoint()));
     597        60345 :         ReturnErrorOnFailure(reader.Get(endpoint_id));
     598              :         // next
     599        60345 :         ReturnErrorOnFailure(reader.Next(TagNext()));
     600        60345 :         ReturnErrorOnFailure(reader.Get(next));
     601              : 
     602        60345 :         return reader.ExitContainer(container);
     603              :     }
     604              : 
     605          919 :     bool Find(PersistentStorageDelegate * storage, const FabricData & fabric, const GroupData & group, chip::EndpointId target_id)
     606              :     {
     607          919 :         fabric_index = fabric.fabric_index;
     608          919 :         group_id     = group.group_id;
     609          919 :         endpoint_id  = group.first_endpoint;
     610          919 :         index        = 0;
     611          919 :         first        = true;
     612              : 
     613        58641 :         while (index < group.endpoint_count)
     614              :         {
     615       115684 :             if (CHIP_NO_ERROR != Load(storage))
     616              :             {
     617            0 :                 break;
     618              :             }
     619        57842 :             if (this->endpoint_id == target_id)
     620              :             {
     621              :                 // Match found
     622          120 :                 return true;
     623              :             }
     624              : 
     625        57722 :             first       = false;
     626        57722 :             prev        = endpoint_id;
     627        57722 :             endpoint_id = next;
     628        57722 :             index++;
     629              :         }
     630              : 
     631          799 :         return false;
     632              :     }
     633              : };
     634              : 
     635              : struct KeySetData : PersistableData<kPersistentBufferMax>
     636              : {
     637          755 :     static constexpr TLV::Tag TagPolicy() { return TLV::ContextTag(1); }
     638          755 :     static constexpr TLV::Tag TagNumKeys() { return TLV::ContextTag(2); }
     639          755 :     static constexpr TLV::Tag TagGroupCredentials() { return TLV::ContextTag(3); }
     640         2265 :     static constexpr TLV::Tag TagStartTime() { return TLV::ContextTag(4); }
     641         2265 :     static constexpr TLV::Tag TagKeyHash() { return TLV::ContextTag(5); }
     642         2265 :     static constexpr TLV::Tag TagKeyValue() { return TLV::ContextTag(6); }
     643          755 :     static constexpr TLV::Tag TagNext() { return TLV::ContextTag(7); }
     644              : 
     645              :     chip::FabricIndex fabric_index = kUndefinedFabricIndex;
     646              :     chip::KeysetId next            = kInvalidKeysetId;
     647              :     chip::KeysetId prev            = kInvalidKeysetId;
     648              :     bool first                     = true;
     649              : 
     650              :     uint16_t keyset_id                       = 0;
     651              :     GroupDataProvider::SecurityPolicy policy = GroupDataProvider::SecurityPolicy::kCacheAndSync;
     652              :     uint8_t keys_count                       = 0;
     653              :     Crypto::GroupOperationalCredentials operational_keys[KeySet::kEpochKeysMax];
     654              : 
     655          446 :     KeySetData() = default;
     656           34 :     KeySetData(chip::FabricIndex fabric, chip::KeysetId id) : fabric_index(fabric) { keyset_id = id; }
     657              :     KeySetData(chip::FabricIndex fabric, chip::KeysetId id, GroupDataProvider::SecurityPolicy policy_id, uint8_t num_keys) :
     658              :         fabric_index(fabric), keyset_id(id), policy(policy_id), keys_count(num_keys)
     659              :     {}
     660              : 
     661          779 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
     662              :     {
     663          779 :         VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX);
     664          779 :         VerifyOrReturnError(kInvalidKeysetId != keyset_id, CHIP_ERROR_INVALID_KEY_ID);
     665          779 :         key = DefaultStorageKeyAllocator::FabricKeyset(fabric_index, keyset_id);
     666          779 :         return CHIP_NO_ERROR;
     667              :     }
     668              : 
     669          510 :     void Clear() override
     670              :     {
     671          510 :         policy     = GroupDataProvider::SecurityPolicy::kCacheAndSync;
     672          510 :         keys_count = 0;
     673          510 :         memset(operational_keys, 0x00, sizeof(operational_keys));
     674          510 :         next = kInvalidKeysetId;
     675          510 :     }
     676              : 
     677            4 :     Crypto::GroupOperationalCredentials * GetCurrentGroupCredentials()
     678              :     {
     679              :         // An epoch key update SHALL order the keys from oldest to newest,
     680              :         // the current epoch key having the second newest time if time
     681              :         // synchronization is not achieved or guaranteed.
     682            4 :         switch (this->keys_count)
     683              :         {
     684            1 :         case 1:
     685              :         case 2:
     686            1 :             return &operational_keys[0];
     687            3 :         case 3:
     688            3 :             return &operational_keys[1];
     689            0 :         default:
     690            0 :             return nullptr;
     691              :         }
     692              :     }
     693              : 
     694          245 :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
     695              :     {
     696              :         TLV::TLVType container;
     697          245 :         ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
     698              : 
     699              :         // policy
     700          245 :         ReturnErrorOnFailure(writer.Put(TagPolicy(), static_cast<uint16_t>(policy)));
     701              :         // keys_count
     702          245 :         ReturnErrorOnFailure(writer.Put(TagNumKeys(), static_cast<uint16_t>(keys_count)));
     703              :         // operational_keys
     704              :         {
     705              :             TLV::TLVType array, item;
     706          245 :             ReturnErrorOnFailure(writer.StartContainer(TagGroupCredentials(), TLV::kTLVType_Array, array));
     707          245 :             uint8_t keyCount   = 0;
     708          245 :             uint64_t startTime = 0;
     709          245 :             uint16_t hash      = 0;
     710              :             uint8_t encryptionKey[Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES];
     711          980 :             for (auto & key : operational_keys)
     712              :             {
     713          735 :                 startTime = 0;
     714          735 :                 hash      = 0;
     715          735 :                 memset(encryptionKey, 0, sizeof(encryptionKey));
     716          735 :                 ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, item));
     717              : 
     718          735 :                 if (keyCount++ < keys_count)
     719              :                 {
     720          641 :                     startTime = key.start_time;
     721          641 :                     hash      = key.hash;
     722          641 :                     memcpy(encryptionKey, key.encryption_key, sizeof(encryptionKey));
     723              :                 }
     724          735 :                 ReturnErrorOnFailure(writer.Put(TagStartTime(), static_cast<uint64_t>(startTime)));
     725          735 :                 ReturnErrorOnFailure(writer.Put(TagKeyHash(), hash));
     726          735 :                 ReturnErrorOnFailure(writer.Put(TagKeyValue(), ByteSpan(encryptionKey)));
     727              : 
     728          735 :                 ReturnErrorOnFailure(writer.EndContainer(item));
     729              :             }
     730          245 :             ReturnErrorOnFailure(writer.EndContainer(array));
     731              :         }
     732              :         // next keyset
     733          245 :         ReturnErrorOnFailure(writer.Put(TagNext(), static_cast<uint16_t>(next)));
     734              : 
     735          245 :         return writer.EndContainer(container);
     736              :     }
     737              : 
     738          510 :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override
     739              :     {
     740          510 :         ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     741          510 :         VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     742              : 
     743              :         TLV::TLVType container;
     744          510 :         ReturnErrorOnFailure(reader.EnterContainer(container));
     745              : 
     746              :         // policy
     747          510 :         ReturnErrorOnFailure(reader.Next(TagPolicy()));
     748          510 :         ReturnErrorOnFailure(reader.Get(policy));
     749              :         // keys_count
     750          510 :         ReturnErrorOnFailure(reader.Next(TagNumKeys()));
     751          510 :         ReturnErrorOnFailure(reader.Get(keys_count));
     752              :         // TODO(#21614): Enforce maximum number of 3 keys in a keyset
     753              :         {
     754              :             // operational_keys
     755          510 :             ReturnErrorOnFailure(reader.Next(TagGroupCredentials()));
     756          510 :             VerifyOrReturnError(TLV::kTLVType_Array == reader.GetType(), CHIP_ERROR_INTERNAL);
     757              : 
     758              :             TLV::TLVType array, item;
     759          510 :             ReturnErrorOnFailure(reader.EnterContainer(array));
     760         2040 :             for (auto & key : operational_keys)
     761              :             {
     762         1530 :                 ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     763         1530 :                 VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     764              : 
     765         1530 :                 ReturnErrorOnFailure(reader.EnterContainer(item));
     766              :                 // start_time
     767         1530 :                 ReturnErrorOnFailure(reader.Next(TagStartTime()));
     768         1530 :                 ReturnErrorOnFailure(reader.Get(key.start_time));
     769              :                 // key hash
     770         1530 :                 ReturnErrorOnFailure(reader.Next(TagKeyHash()));
     771         1530 :                 ReturnErrorOnFailure(reader.Get(key.hash));
     772              :                 // key value
     773         1530 :                 ByteSpan encryption_key;
     774         1530 :                 ReturnErrorOnFailure(reader.Next(TagKeyValue()));
     775         1530 :                 ReturnErrorOnFailure(reader.Get(encryption_key));
     776         1530 :                 VerifyOrReturnError(Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES == encryption_key.size(), CHIP_ERROR_INTERNAL);
     777         1530 :                 memcpy(key.encryption_key, encryption_key.data(), encryption_key.size());
     778              :                 // Re-derive privacy key from encryption key when loading from storage to save on storage size.
     779         1530 :                 MutableByteSpan privacy_key(key.privacy_key);
     780         1530 :                 ReturnErrorOnFailure(Crypto::DeriveGroupPrivacyKey(encryption_key, privacy_key));
     781         1530 :                 ReturnErrorOnFailure(reader.ExitContainer(item));
     782              :             }
     783          510 :             ReturnErrorOnFailure(reader.ExitContainer(array));
     784              :         }
     785              :         // next keyset
     786          510 :         ReturnErrorOnFailure(reader.Next(TagNext()));
     787          510 :         ReturnErrorOnFailure(reader.Get(next));
     788              : 
     789          510 :         return reader.ExitContainer(container);
     790              :     }
     791              : 
     792          438 :     bool Find(PersistentStorageDelegate * storage, const FabricData & fabric, size_t target_id)
     793              :     {
     794          438 :         uint16_t count = 0;
     795              : 
     796          438 :         fabric_index = fabric.fabric_index;
     797          438 :         keyset_id    = fabric.first_keyset;
     798          438 :         first        = true;
     799              : 
     800          739 :         while (count++ < fabric.keyset_count)
     801              :         {
     802          968 :             if (CHIP_NO_ERROR != Load(storage))
     803              :             {
     804            0 :                 break;
     805              :             }
     806              : 
     807          484 :             if (keyset_id == target_id)
     808              :             {
     809              :                 // Target id found
     810          183 :                 return true;
     811              :             }
     812              : 
     813          301 :             first     = false;
     814          301 :             prev      = keyset_id;
     815          301 :             keyset_id = next;
     816              :         }
     817              : 
     818          255 :         return false;
     819              :     }
     820              : };
     821              : 
     822              : //
     823              : // General
     824              : //
     825              : 
     826              : constexpr size_t GroupDataProvider::GroupInfo::kGroupNameMax;
     827              : constexpr size_t GroupDataProviderImpl::kIteratorsMax;
     828              : 
     829          105 : CHIP_ERROR GroupDataProviderImpl::Init()
     830              : {
     831          105 :     if (mStorage == nullptr || mSessionKeystore == nullptr)
     832              :     {
     833            0 :         return CHIP_ERROR_INCORRECT_STATE;
     834              :     }
     835          105 :     return CHIP_NO_ERROR;
     836              : }
     837              : 
     838          101 : void GroupDataProviderImpl::Finish()
     839              : {
     840          101 :     mGroupInfoIterators.ReleaseAll();
     841          101 :     mGroupKeyIterators.ReleaseAll();
     842          101 :     mEndpointIterators.ReleaseAll();
     843          101 :     mKeySetIterators.ReleaseAll();
     844          101 :     mGroupSessionsIterator.ReleaseAll();
     845          101 :     mGroupKeyContexPool.ReleaseAll();
     846          101 : }
     847              : 
     848          105 : void GroupDataProviderImpl::SetStorageDelegate(PersistentStorageDelegate * storage)
     849              : {
     850          105 :     VerifyOrDie(storage != nullptr);
     851          105 :     mStorage = storage;
     852          105 : }
     853              : 
     854              : //
     855              : // Group Info
     856              : //
     857              : 
     858          253 : CHIP_ERROR GroupDataProviderImpl::SetGroupInfo(chip::FabricIndex fabric_index, const GroupInfo & info)
     859              : {
     860          253 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
     861              : 
     862          253 :     FabricData fabric(fabric_index);
     863          253 :     GroupData group;
     864              : 
     865              :     // Load fabric data (defaults to zero)
     866          253 :     CHIP_ERROR err = fabric.Load(mStorage);
     867          566 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
     868              : 
     869          253 :     if (group.Find(mStorage, fabric, info.group_id))
     870              :     {
     871              :         // Existing group_id
     872           31 :         group.Copy(info);
     873           31 :         return group.Save(mStorage);
     874              :     }
     875              : 
     876              :     // New group_id
     877          222 :     group.Copy(info);
     878          222 :     return SetGroupInfoAt(fabric_index, fabric.group_count, group);
     879          253 : }
     880              : 
     881           46 : CHIP_ERROR GroupDataProviderImpl::GetGroupInfo(chip::FabricIndex fabric_index, chip::GroupId group_id, GroupInfo & info)
     882              : {
     883           46 :     FabricData fabric(fabric_index);
     884           46 :     GroupData group;
     885              : 
     886           46 :     ReturnErrorOnFailure(fabric.Load(mStorage));
     887           41 :     info.count = fabric.group_count;
     888           41 :     VerifyOrReturnError(group.Find(mStorage, fabric, group_id), CHIP_ERROR_NOT_FOUND);
     889              : 
     890           35 :     info.Copy(group);
     891           35 :     return CHIP_NO_ERROR;
     892           46 : }
     893              : 
     894            1 : CHIP_ERROR GroupDataProviderImpl::RemoveGroupInfo(chip::FabricIndex fabric_index, chip::GroupId group_id)
     895              : {
     896            1 :     FabricData fabric(fabric_index);
     897            1 :     GroupData group;
     898              : 
     899            1 :     ReturnErrorOnFailure(fabric.Load(mStorage));
     900            1 :     VerifyOrReturnError(group.Find(mStorage, fabric, group_id), CHIP_ERROR_NOT_FOUND);
     901              : 
     902            1 :     return RemoveGroupInfoAt(fabric_index, group.index);
     903            1 : }
     904              : 
     905          263 : CHIP_ERROR GroupDataProviderImpl::SetGroupInfoAt(chip::FabricIndex fabric_index, size_t index, const GroupInfo & info)
     906              : {
     907          263 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
     908              : 
     909          263 :     FabricData fabric(fabric_index);
     910          263 :     GroupData group;
     911              : 
     912              :     // Load fabric, defaults to zero
     913          263 :     CHIP_ERROR err = fabric.Load(mStorage);
     914          596 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
     915              : 
     916              :     // If the group exists, the index must match
     917          263 :     bool found = group.Find(mStorage, fabric, info.group_id);
     918          263 :     VerifyOrReturnError(!found || (group.index == index), CHIP_ERROR_DUPLICATE_KEY_ID);
     919              : 
     920          259 :     group.Copy(info);
     921          259 :     group.endpoint_count = 0;
     922              : 
     923          259 :     if (found)
     924              :     {
     925              :         // Update existing entry
     926            6 :         return group.Save(mStorage);
     927              :     }
     928          253 :     if (index < fabric.group_count)
     929              :     {
     930              :         // Replace existing entry with a new group
     931            1 :         GroupData old_group;
     932            1 :         old_group.Get(mStorage, fabric, index);
     933            1 :         group.first = old_group.first;
     934            1 :         group.prev  = old_group.prev;
     935            1 :         group.next  = old_group.next;
     936              : 
     937            1 :         ReturnErrorOnFailure(RemoveEndpoints(fabric_index, old_group.group_id));
     938            1 :         ReturnErrorOnFailure(old_group.Delete(mStorage));
     939            1 :         GroupRemoved(fabric_index, old_group);
     940            1 :     }
     941              :     else
     942              :     {
     943              :         // Insert last
     944          252 :         VerifyOrReturnError(fabric.group_count == index, CHIP_ERROR_INVALID_ARGUMENT);
     945          251 :         VerifyOrReturnError(fabric.group_count < mMaxGroupsPerFabric, CHIP_ERROR_INVALID_LIST_LENGTH);
     946          249 :         fabric.group_count++;
     947              :     }
     948              : 
     949          250 :     ReturnErrorOnFailure(group.Save(mStorage));
     950              : 
     951          250 :     if (group.first)
     952              :     {
     953              :         // First group, update fabric
     954           93 :         fabric.first_group = group.group_id;
     955              :     }
     956              :     else
     957              :     {
     958              :         // Second to last group, update previous
     959          157 :         GroupData prev(fabric_index, group.prev);
     960          157 :         ReturnErrorOnFailure(prev.Load(mStorage));
     961          157 :         prev.next = group.group_id;
     962          157 :         ReturnErrorOnFailure(prev.Save(mStorage));
     963          157 :     }
     964              :     // Update fabric
     965          250 :     ReturnErrorOnFailure(fabric.Save(mStorage));
     966          250 :     GroupAdded(fabric_index, group);
     967          250 :     return CHIP_NO_ERROR;
     968          263 : }
     969              : 
     970           52 : CHIP_ERROR GroupDataProviderImpl::GetGroupInfoAt(chip::FabricIndex fabric_index, size_t index, GroupInfo & info)
     971              : {
     972           52 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
     973              : 
     974           52 :     FabricData fabric(fabric_index);
     975           52 :     GroupData group;
     976              : 
     977           52 :     ReturnErrorOnFailure(fabric.Load(mStorage));
     978           44 :     VerifyOrReturnError(group.Get(mStorage, fabric, index), CHIP_ERROR_NOT_FOUND);
     979              : 
     980              :     // Target group found
     981           26 :     info.Copy(group);
     982           26 :     return CHIP_NO_ERROR;
     983           52 : }
     984              : 
     985           38 : CHIP_ERROR GroupDataProviderImpl::RemoveGroupInfoAt(chip::FabricIndex fabric_index, size_t index)
     986              : {
     987           38 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
     988              : 
     989           38 :     FabricData fabric(fabric_index);
     990           38 :     GroupData group;
     991              : 
     992           38 :     ReturnErrorOnFailure(fabric.Load(mStorage));
     993           38 :     VerifyOrReturnError(group.Get(mStorage, fabric, index), CHIP_ERROR_NOT_FOUND);
     994              : 
     995              :     // Remove endpoints
     996           38 :     EndpointData endpoint(fabric_index, group.group_id, group.first_endpoint);
     997           38 :     size_t count = 0;
     998           64 :     while (count++ < group.endpoint_count)
     999              :     {
    1000           74 :         if (CHIP_NO_ERROR != endpoint.Load(mStorage))
    1001              :         {
    1002           11 :             break;
    1003              :         }
    1004           26 :         TEMPORARY_RETURN_IGNORED endpoint.Delete(mStorage);
    1005           26 :         endpoint.endpoint_id = endpoint.next;
    1006              :     }
    1007              : 
    1008           38 :     ReturnErrorOnFailure(group.Delete(mStorage));
    1009           38 :     if (group.first)
    1010              :     {
    1011              :         // Remove first group
    1012           19 :         fabric.first_group = group.next;
    1013              :     }
    1014              :     else
    1015              :     {
    1016              :         // Remove intermediate group, update previous
    1017           19 :         GroupData prev_data(fabric_index, group.prev);
    1018           19 :         ReturnErrorOnFailure(prev_data.Load(mStorage));
    1019           19 :         prev_data.next = group.next;
    1020           19 :         ReturnErrorOnFailure(prev_data.Save(mStorage));
    1021           19 :     }
    1022           38 :     if (fabric.group_count > 0)
    1023              :     {
    1024           38 :         fabric.group_count--;
    1025              :     }
    1026              :     // Update fabric info
    1027           38 :     ReturnErrorOnFailure(fabric.Save(mStorage));
    1028           38 :     GroupRemoved(fabric_index, group);
    1029           38 :     return CHIP_NO_ERROR;
    1030           38 : }
    1031              : 
    1032           96 : bool GroupDataProviderImpl::HasEndpoint(chip::FabricIndex fabric_index, chip::GroupId group_id, chip::EndpointId endpoint_id)
    1033              : {
    1034           96 :     VerifyOrReturnError(IsInitialized(), false);
    1035              : 
    1036           96 :     FabricData fabric(fabric_index);
    1037           96 :     GroupData group;
    1038           96 :     EndpointData endpoint;
    1039              : 
    1040          192 :     VerifyOrReturnError(CHIP_NO_ERROR == fabric.Load(mStorage), false);
    1041           85 :     VerifyOrReturnError(group.Find(mStorage, fabric, group_id), false);
    1042           77 :     return endpoint.Find(mStorage, fabric, group, endpoint_id);
    1043           96 : }
    1044              : 
    1045          802 : CHIP_ERROR GroupDataProviderImpl::AddEndpoint(chip::FabricIndex fabric_index, chip::GroupId group_id, chip::EndpointId endpoint_id)
    1046              : {
    1047          802 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1048              : 
    1049          802 :     FabricData fabric(fabric_index);
    1050          802 :     GroupData group;
    1051              : 
    1052              :     // Load fabric data (defaults to zero)
    1053          802 :     CHIP_ERROR err = fabric.Load(mStorage);
    1054         1608 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
    1055              : 
    1056          802 :     if (!group.Find(mStorage, fabric, group_id))
    1057              :     {
    1058              :         // New group
    1059            9 :         VerifyOrReturnError(fabric.group_count < mMaxGroupsPerFabric, CHIP_ERROR_INVALID_LIST_LENGTH);
    1060            9 :         ReturnErrorOnFailure(EndpointData(fabric_index, group_id, endpoint_id).Save(mStorage));
    1061              :         // Save the new group into the fabric
    1062            9 :         group.group_id       = group_id;
    1063            9 :         group.name[0]        = 0;
    1064            9 :         group.first_endpoint = endpoint_id;
    1065            9 :         group.endpoint_count = 1;
    1066            9 :         group.next           = fabric.first_group;
    1067            9 :         group.prev           = kUndefinedGroupId;
    1068            9 :         ReturnErrorOnFailure(group.Save(mStorage));
    1069              :         // Update fabric
    1070            9 :         fabric.first_group = group.group_id;
    1071            9 :         fabric.group_count++;
    1072            9 :         ReturnErrorOnFailure(fabric.Save(mStorage));
    1073            9 :         GroupAdded(fabric_index, group);
    1074            9 :         return CHIP_NO_ERROR;
    1075              :     }
    1076              : 
    1077              :     // Existing group
    1078          793 :     EndpointData endpoint;
    1079          793 :     VerifyOrReturnError(!endpoint.Find(mStorage, fabric, group, endpoint_id), CHIP_NO_ERROR);
    1080              : 
    1081              :     // New endpoint, insert last
    1082          790 :     endpoint.endpoint_id = endpoint_id;
    1083          790 :     ReturnErrorOnFailure(endpoint.Save(mStorage));
    1084          790 :     if (endpoint.first)
    1085              :     {
    1086              :         // First endpoint of group
    1087          224 :         group.first_endpoint = endpoint.endpoint_id;
    1088              :     }
    1089              :     else
    1090              :     {
    1091              :         // Previous endpoint(s)
    1092          566 :         ReturnErrorOnFailure(endpoint.Save(mStorage));
    1093          566 :         EndpointData prev(fabric_index, group.group_id, endpoint.prev);
    1094          566 :         ReturnErrorOnFailure(prev.Load(mStorage));
    1095          566 :         prev.next = endpoint.endpoint_id;
    1096          566 :         ReturnErrorOnFailure(prev.Save(mStorage));
    1097          566 :     }
    1098          790 :     group.endpoint_count++;
    1099          790 :     return group.Save(mStorage);
    1100          802 : }
    1101              : 
    1102           42 : CHIP_ERROR GroupDataProviderImpl::RemoveEndpoint(chip::FabricIndex fabric_index, chip::GroupId group_id,
    1103              :                                                  chip::EndpointId endpoint_id)
    1104              : {
    1105           42 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1106              : 
    1107           42 :     FabricData fabric(fabric_index);
    1108           42 :     GroupData group;
    1109           42 :     EndpointData endpoint;
    1110              : 
    1111           42 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1112           42 :     VerifyOrReturnError(group.Find(mStorage, fabric, group_id), CHIP_ERROR_NOT_FOUND);
    1113           41 :     VerifyOrReturnError(endpoint.Find(mStorage, fabric, group, endpoint_id), CHIP_ERROR_NOT_FOUND);
    1114              : 
    1115              :     // Existing endpoint
    1116           40 :     TEMPORARY_RETURN_IGNORED endpoint.Delete(mStorage);
    1117              : 
    1118           40 :     if (endpoint.first)
    1119              :     {
    1120              :         // Remove first
    1121           14 :         group.first_endpoint = endpoint.next;
    1122              :     }
    1123              :     else
    1124              :     {
    1125              :         // Remove middle
    1126           26 :         EndpointData prev(fabric_index, group.group_id, endpoint.prev);
    1127           26 :         ReturnErrorOnFailure(prev.Load(mStorage));
    1128           26 :         prev.next = endpoint.next;
    1129           26 :         ReturnErrorOnFailure(prev.Save(mStorage));
    1130           26 :     }
    1131              : 
    1132           40 :     if (group.endpoint_count > 1)
    1133              :     {
    1134           29 :         group.endpoint_count--;
    1135           29 :         return group.Save(mStorage);
    1136              :     }
    1137              : 
    1138              :     // No more endpoints, remove the group
    1139           11 :     return RemoveGroupInfoAt(fabric_index, group.index);
    1140           42 : }
    1141              : 
    1142            4 : CHIP_ERROR GroupDataProviderImpl::RemoveEndpoint(chip::FabricIndex fabric_index, chip::EndpointId endpoint_id)
    1143              : {
    1144            4 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1145              : 
    1146            4 :     FabricData fabric(fabric_index);
    1147              : 
    1148            4 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1149              : 
    1150            3 :     GroupData group(fabric_index, fabric.first_group);
    1151            3 :     size_t group_index = 0;
    1152            3 :     EndpointData endpoint;
    1153              : 
    1154              :     // Loop through all the groups
    1155           11 :     while (group_index < fabric.group_count)
    1156              :     {
    1157           16 :         if (CHIP_NO_ERROR != group.Load(mStorage))
    1158              :         {
    1159            0 :             break;
    1160              :         }
    1161            8 :         if (endpoint.Find(mStorage, fabric, group, endpoint_id))
    1162              :         {
    1163              :             // Endpoint found in group
    1164            8 :             ReturnErrorOnFailure(RemoveEndpoint(fabric_index, group.group_id, endpoint_id));
    1165              :         }
    1166              : 
    1167            8 :         group.group_id = group.next;
    1168            8 :         group_index++;
    1169              :     }
    1170              : 
    1171            3 :     return CHIP_NO_ERROR;
    1172            4 : }
    1173              : 
    1174           17 : GroupDataProvider::GroupInfoIterator * GroupDataProviderImpl::IterateGroupInfo(chip::FabricIndex fabric_index)
    1175              : {
    1176           17 :     VerifyOrReturnError(IsInitialized(), nullptr);
    1177           17 :     return mGroupInfoIterators.CreateObject(*this, fabric_index);
    1178              : }
    1179              : 
    1180           17 : GroupDataProviderImpl::GroupInfoIteratorImpl::GroupInfoIteratorImpl(GroupDataProviderImpl & provider,
    1181           17 :                                                                     chip::FabricIndex fabric_index) :
    1182           17 :     mProvider(provider),
    1183           17 :     mFabric(fabric_index)
    1184              : {
    1185           17 :     FabricData fabric(fabric_index);
    1186           34 :     if (CHIP_NO_ERROR == fabric.Load(provider.mStorage))
    1187              :     {
    1188           16 :         mNextId = fabric.first_group;
    1189           16 :         mTotal  = fabric.group_count;
    1190           16 :         mCount  = 0;
    1191              :     }
    1192           17 : }
    1193              : 
    1194            4 : size_t GroupDataProviderImpl::GroupInfoIteratorImpl::Count()
    1195              : {
    1196            4 :     return mTotal;
    1197              : }
    1198              : 
    1199           40 : bool GroupDataProviderImpl::GroupInfoIteratorImpl::Next(GroupInfo & output)
    1200              : {
    1201           40 :     VerifyOrReturnError(mCount < mTotal, false);
    1202              : 
    1203           26 :     GroupData group(mFabric, mNextId);
    1204           26 :     CHIP_ERROR err = group.Load(mProvider.mStorage);
    1205           52 :     VerifyOrReturnError(CHIP_NO_ERROR == err, false);
    1206              : 
    1207           26 :     mCount++;
    1208           26 :     mNextId = group.next;
    1209           26 :     output.Copy(group);
    1210           26 :     return true;
    1211           26 : }
    1212              : 
    1213           17 : void GroupDataProviderImpl::GroupInfoIteratorImpl::Release()
    1214              : {
    1215           17 :     mProvider.mGroupInfoIterators.ReleaseObject(this);
    1216           17 : }
    1217              : 
    1218           31 : GroupDataProvider::EndpointIterator * GroupDataProviderImpl::IterateEndpoints(chip::FabricIndex fabric_index,
    1219              :                                                                               std::optional<GroupId> group_id)
    1220              : {
    1221           31 :     VerifyOrReturnError(IsInitialized(), nullptr);
    1222           31 :     return mEndpointIterators.CreateObject(*this, fabric_index, group_id);
    1223              : }
    1224              : 
    1225           31 : GroupDataProviderImpl::EndpointIteratorImpl::EndpointIteratorImpl(GroupDataProviderImpl & provider, chip::FabricIndex fabric_index,
    1226           31 :                                                                   std::optional<GroupId> group_id) :
    1227           31 :     mProvider(provider),
    1228           31 :     mFabric(fabric_index)
    1229              : {
    1230           31 :     FabricData fabric(fabric_index);
    1231           62 :     VerifyOrReturn(CHIP_NO_ERROR == fabric.Load(provider.mStorage));
    1232              : 
    1233           29 :     if (group_id.has_value())
    1234              :     {
    1235           19 :         GroupData group(fabric_index, *group_id);
    1236           38 :         VerifyOrReturn(CHIP_NO_ERROR == group.Load(provider.mStorage));
    1237              : 
    1238           18 :         mGroup         = *group_id;
    1239           18 :         mFirstGroup    = *group_id;
    1240           18 :         mGroupCount    = 1;
    1241           18 :         mEndpoint      = group.first_endpoint;
    1242           18 :         mEndpointCount = group.endpoint_count;
    1243           19 :     }
    1244              :     else
    1245              :     {
    1246           10 :         GroupData group(fabric_index, fabric.first_group);
    1247           20 :         VerifyOrReturn(CHIP_NO_ERROR == group.Load(provider.mStorage));
    1248              : 
    1249           10 :         mGroup         = fabric.first_group;
    1250           10 :         mFirstGroup    = fabric.first_group;
    1251           10 :         mGroupCount    = fabric.group_count;
    1252           10 :         mEndpoint      = group.first_endpoint;
    1253           10 :         mEndpointCount = group.endpoint_count;
    1254           10 :     }
    1255           31 : }
    1256              : 
    1257           24 : size_t GroupDataProviderImpl::EndpointIteratorImpl::Count()
    1258              : {
    1259           24 :     GroupData group(mFabric, mFirstGroup);
    1260           24 :     size_t group_index    = 0;
    1261           24 :     size_t endpoint_index = 0;
    1262           24 :     size_t count          = 0;
    1263              : 
    1264           48 :     while (group_index++ < mGroupCount)
    1265              :     {
    1266           48 :         if (CHIP_NO_ERROR != group.Load(mProvider.mStorage))
    1267              :         {
    1268            0 :             break;
    1269              :         }
    1270           24 :         EndpointData endpoint(mFabric, group.group_id, group.first_endpoint);
    1271          965 :         while (endpoint_index++ < group.endpoint_count)
    1272              :         {
    1273         1882 :             if (CHIP_NO_ERROR != endpoint.Load(mProvider.mStorage))
    1274              :             {
    1275            0 :                 break;
    1276              :             }
    1277          941 :             endpoint.endpoint_id = endpoint.next;
    1278          941 :             count++;
    1279              :         }
    1280           24 :         group.group_id = group.next;
    1281           24 :         endpoint_index = 0;
    1282           24 :     }
    1283           48 :     return count;
    1284           24 : }
    1285              : 
    1286          970 : bool GroupDataProviderImpl::EndpointIteratorImpl::Next(GroupEndpoint & output)
    1287              : {
    1288         1006 :     while (mGroupIndex < mGroupCount)
    1289              :     {
    1290          980 :         GroupData group(mFabric, mGroup);
    1291         1960 :         if (CHIP_NO_ERROR != group.Load(mProvider.mStorage))
    1292              :         {
    1293            0 :             mGroupIndex = mGroupCount;
    1294            0 :             return false;
    1295              :         }
    1296          980 :         if (mFirstEndpoint)
    1297              :         {
    1298           36 :             mEndpoint      = group.first_endpoint;
    1299           36 :             mEndpointIndex = 0;
    1300           36 :             mEndpointCount = group.endpoint_count;
    1301           36 :             mFirstEndpoint = false;
    1302              :         }
    1303          980 :         if (mEndpointIndex < mEndpointCount)
    1304              :         {
    1305          944 :             EndpointData endpoint(mFabric, mGroup, mEndpoint);
    1306         1888 :             if (CHIP_NO_ERROR == endpoint.Load(mProvider.mStorage))
    1307              :             {
    1308          944 :                 output.group_id    = group.group_id;
    1309          944 :                 output.endpoint_id = endpoint.endpoint_id;
    1310          944 :                 mEndpoint          = endpoint.next;
    1311          944 :                 mEndpointIndex++;
    1312          944 :                 return true;
    1313              :             }
    1314          944 :         }
    1315           36 :         mGroup = group.next;
    1316           36 :         mGroupIndex++;
    1317           36 :         mFirstEndpoint = true;
    1318          980 :     }
    1319           26 :     return false;
    1320              : }
    1321              : 
    1322           31 : void GroupDataProviderImpl::EndpointIteratorImpl::Release()
    1323              : {
    1324           31 :     mProvider.mEndpointIterators.ReleaseObject(this);
    1325           31 : }
    1326              : 
    1327            1 : CHIP_ERROR GroupDataProviderImpl::RemoveEndpoints(chip::FabricIndex fabric_index, chip::GroupId group_id)
    1328              : {
    1329            1 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1330              : 
    1331            1 :     FabricData fabric(fabric_index);
    1332            1 :     GroupData group;
    1333              : 
    1334            2 :     VerifyOrReturnError(CHIP_NO_ERROR == fabric.Load(mStorage), CHIP_ERROR_INVALID_FABRIC_INDEX);
    1335            1 :     VerifyOrReturnError(group.Find(mStorage, fabric, group_id), CHIP_ERROR_KEY_NOT_FOUND);
    1336              : 
    1337            1 :     EndpointData endpoint(fabric_index, group.group_id, group.first_endpoint);
    1338            1 :     size_t endpoint_index = 0;
    1339            1 :     while (endpoint_index < group.endpoint_count)
    1340              :     {
    1341            0 :         ReturnErrorOnFailure(endpoint.Load(mStorage));
    1342            0 :         TEMPORARY_RETURN_IGNORED endpoint.Delete(mStorage);
    1343            0 :         endpoint.endpoint_id = endpoint.next;
    1344            0 :         endpoint_index++;
    1345              :     }
    1346            1 :     group.first_endpoint = kInvalidEndpointId;
    1347            1 :     group.endpoint_count = 0;
    1348            1 :     ReturnErrorOnFailure(group.Save(mStorage));
    1349              : 
    1350            1 :     return CHIP_NO_ERROR;
    1351            1 : }
    1352              : 
    1353              : //
    1354              : // Group-Key map
    1355              : //
    1356              : 
    1357           36 : CHIP_ERROR GroupDataProviderImpl::SetGroupKey(FabricIndex fabric_index, GroupId group_id, KeysetId keyset_id)
    1358              : {
    1359           36 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1360              : 
    1361           36 :     FabricData fabric(fabric_index);
    1362           36 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1363              : 
    1364              :     // Search for an existing mapping
    1365           36 :     size_t count = 0;
    1366           36 :     KeyMapData map(fabric_index, fabric.first_map);
    1367           48 :     while (count++ < fabric.map_count)
    1368              :     {
    1369           39 :         ReturnErrorOnFailure(map.Load(mStorage));
    1370           39 :         if (map.group_id == group_id)
    1371              :         {
    1372              :             // Existing group, replace keyset
    1373           27 :             map.keyset_id = keyset_id;
    1374           27 :             return map.Save(mStorage);
    1375              :         }
    1376           12 :         map.id = map.next;
    1377              :     }
    1378              : 
    1379              :     // New group, insert last
    1380            9 :     GroupKey entry(group_id, keyset_id);
    1381            9 :     return SetGroupKeyAt(fabric_index, fabric.map_count, entry);
    1382           36 : }
    1383              : 
    1384          264 : CHIP_ERROR GroupDataProviderImpl::SetGroupKeyAt(chip::FabricIndex fabric_index, size_t index, const GroupKey & in_map)
    1385              : {
    1386          264 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1387              : 
    1388          264 :     FabricData fabric(fabric_index);
    1389          264 :     KeyMapData map(fabric_index);
    1390              : 
    1391              :     // Load fabric, defaults to zero
    1392          264 :     CHIP_ERROR err = fabric.Load(mStorage);
    1393          536 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
    1394              : 
    1395              :     // If the group exists, the index must match
    1396          264 :     bool found = map.Find(mStorage, fabric, in_map);
    1397          264 :     VerifyOrReturnError(!found || (map.index == index), CHIP_ERROR_DUPLICATE_KEY_ID);
    1398              : 
    1399          259 :     found         = map.Get(mStorage, fabric, index);
    1400          259 :     map.group_id  = in_map.group_id;
    1401          259 :     map.keyset_id = in_map.keyset_id;
    1402              : 
    1403          259 :     if (found)
    1404              :     {
    1405              :         // Update existing map
    1406            8 :         return map.Save(mStorage);
    1407              :     }
    1408              : 
    1409              :     // Insert last
    1410          251 :     VerifyOrReturnError(fabric.map_count == index, CHIP_ERROR_INVALID_ARGUMENT);
    1411          250 :     VerifyOrReturnError(fabric.map_count < mMaxGroupsPerFabric, CHIP_ERROR_INVALID_LIST_LENGTH);
    1412              : 
    1413          249 :     map.next = 0;
    1414          249 :     ReturnErrorOnFailure(map.Save(mStorage));
    1415              : 
    1416          249 :     if (map.first)
    1417              :     {
    1418              :         // First map, update fabric
    1419           92 :         fabric.first_map = map.id;
    1420              :     }
    1421              :     else
    1422              :     {
    1423              :         // Last map, update previous
    1424          157 :         KeyMapData prev(fabric_index, map.prev);
    1425          157 :         ReturnErrorOnFailure(prev.Load(mStorage));
    1426          157 :         prev.next = map.id;
    1427          157 :         ReturnErrorOnFailure(prev.Save(mStorage));
    1428          157 :     }
    1429              :     // Update fabric
    1430          249 :     fabric.map_count++;
    1431          249 :     return fabric.Save(mStorage);
    1432          264 : }
    1433              : 
    1434           16 : CHIP_ERROR GroupDataProviderImpl::GetGroupKey(FabricIndex fabric_index, GroupId group_id, KeysetId & keyset_id)
    1435              : {
    1436           16 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1437              : 
    1438           16 :     FabricData fabric(fabric_index);
    1439           16 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1440              : 
    1441           16 :     size_t count = 0;
    1442           16 :     KeyMapData map(fabric_index, fabric.first_map);
    1443           22 :     while (count++ < fabric.map_count)
    1444              :     {
    1445           22 :         ReturnErrorOnFailure(map.Load(mStorage));
    1446           22 :         if (map.group_id == group_id)
    1447              :         {
    1448           16 :             keyset_id = map.keyset_id;
    1449           16 :             return CHIP_NO_ERROR;
    1450              :         }
    1451            6 :         map.id = map.next;
    1452              :     }
    1453            0 :     return CHIP_ERROR_NOT_FOUND;
    1454           16 : }
    1455              : 
    1456           28 : CHIP_ERROR GroupDataProviderImpl::GetGroupKeyAt(chip::FabricIndex fabric_index, size_t index, GroupKey & out_map)
    1457              : {
    1458           28 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1459              : 
    1460           28 :     FabricData fabric(fabric_index);
    1461           28 :     KeyMapData map;
    1462              : 
    1463           28 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1464           27 :     VerifyOrReturnError(map.Get(mStorage, fabric, index), CHIP_ERROR_NOT_FOUND);
    1465              : 
    1466              :     // Target map found
    1467           19 :     out_map.group_id  = map.group_id;
    1468           19 :     out_map.keyset_id = map.keyset_id;
    1469           19 :     return CHIP_NO_ERROR;
    1470           28 : }
    1471              : 
    1472           14 : CHIP_ERROR GroupDataProviderImpl::RemoveGroupKeyAt(chip::FabricIndex fabric_index, size_t index)
    1473              : {
    1474           14 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1475              : 
    1476           14 :     FabricData fabric(fabric_index);
    1477           14 :     KeyMapData map;
    1478              : 
    1479           14 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1480           14 :     VerifyOrReturnError(map.Get(mStorage, fabric, index), CHIP_ERROR_NOT_FOUND);
    1481              : 
    1482           14 :     ReturnErrorOnFailure(map.Delete(mStorage));
    1483           14 :     if (map.first)
    1484              :     {
    1485              :         // Remove first map
    1486            4 :         fabric.first_map = map.next;
    1487              :     }
    1488              :     else
    1489              :     {
    1490              :         // Remove intermediate map, update previous
    1491           10 :         KeyMapData prev_data(fabric_index, map.prev);
    1492           10 :         ReturnErrorOnFailure(prev_data.Load(mStorage));
    1493           10 :         prev_data.next = map.next;
    1494           10 :         ReturnErrorOnFailure(prev_data.Save(mStorage));
    1495           10 :     }
    1496           14 :     if (fabric.map_count > 0)
    1497              :     {
    1498           14 :         fabric.map_count--;
    1499              :     }
    1500              :     // Update fabric
    1501           14 :     return fabric.Save(mStorage);
    1502           14 : }
    1503              : 
    1504            4 : CHIP_ERROR GroupDataProviderImpl::RemoveGroupKeys(chip::FabricIndex fabric_index)
    1505              : {
    1506            4 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1507              : 
    1508            4 :     FabricData fabric(fabric_index);
    1509            8 :     VerifyOrReturnError(CHIP_NO_ERROR == fabric.Load(mStorage), CHIP_ERROR_INVALID_FABRIC_INDEX);
    1510              : 
    1511            1 :     size_t count = 0;
    1512            1 :     KeyMapData map(fabric_index, fabric.first_map);
    1513            4 :     while (count++ < fabric.map_count)
    1514              :     {
    1515            6 :         if (CHIP_NO_ERROR != map.Load(mStorage))
    1516              :         {
    1517            0 :             break;
    1518              :         }
    1519            3 :         TEMPORARY_RETURN_IGNORED map.Delete(mStorage);
    1520            3 :         map.id = map.next;
    1521              :     }
    1522              : 
    1523              :     // Update fabric
    1524            1 :     fabric.first_map = 0;
    1525            1 :     fabric.map_count = 0;
    1526            1 :     return fabric.Save(mStorage);
    1527            4 : }
    1528              : 
    1529           39 : GroupDataProvider::GroupKeyIterator * GroupDataProviderImpl::IterateGroupKeys(chip::FabricIndex fabric_index)
    1530              : {
    1531           39 :     VerifyOrReturnError(IsInitialized(), nullptr);
    1532           39 :     return mGroupKeyIterators.CreateObject(*this, fabric_index);
    1533              : }
    1534              : 
    1535           39 : GroupDataProviderImpl::GroupKeyIteratorImpl::GroupKeyIteratorImpl(GroupDataProviderImpl & provider,
    1536           39 :                                                                   chip::FabricIndex fabric_index) :
    1537           39 :     mProvider(provider),
    1538           39 :     mFabric(fabric_index)
    1539              : {
    1540           39 :     FabricData fabric(fabric_index);
    1541           78 :     if (CHIP_NO_ERROR == fabric.Load(provider.mStorage))
    1542              :     {
    1543           37 :         mNextId = fabric.first_map;
    1544           37 :         mTotal  = fabric.map_count;
    1545           37 :         mCount  = 0;
    1546              :     }
    1547           39 : }
    1548              : 
    1549            7 : size_t GroupDataProviderImpl::GroupKeyIteratorImpl::Count()
    1550              : {
    1551            7 :     return mTotal;
    1552              : }
    1553              : 
    1554           74 : bool GroupDataProviderImpl::GroupKeyIteratorImpl::Next(GroupKey & output)
    1555              : {
    1556           74 :     VerifyOrReturnError(mCount < mTotal, false);
    1557              : 
    1558           66 :     KeyMapData map(mFabric, mNextId);
    1559          132 :     VerifyOrReturnError(CHIP_NO_ERROR == map.Load(mProvider.mStorage), false);
    1560              : 
    1561           66 :     mCount++;
    1562           66 :     mNextId          = map.next;
    1563           66 :     output.group_id  = map.group_id;
    1564           66 :     output.keyset_id = map.keyset_id;
    1565           66 :     return true;
    1566           66 : }
    1567              : 
    1568           39 : void GroupDataProviderImpl::GroupKeyIteratorImpl::Release()
    1569              : {
    1570           39 :     mProvider.mGroupKeyIterators.ReleaseObject(this);
    1571           39 : }
    1572              : 
    1573              : //
    1574              : // Key Sets
    1575              : //
    1576              : 
    1577              : constexpr size_t GroupDataProvider::EpochKey::kLengthBytes;
    1578              : 
    1579          242 : CHIP_ERROR GroupDataProviderImpl::SetKeySet(chip::FabricIndex fabric_index, const ByteSpan & compressed_fabric_id,
    1580              :                                             const KeySet & in_keyset)
    1581              : {
    1582          242 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1583              : 
    1584          242 :     FabricData fabric(fabric_index);
    1585          242 :     KeySetData keyset;
    1586              : 
    1587              :     // Load fabric, defaults to zero
    1588          242 :     CHIP_ERROR err = fabric.Load(mStorage);
    1589          516 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
    1590              : 
    1591              :     // Search existing keyset
    1592          242 :     bool found = keyset.Find(mStorage, fabric, in_keyset.keyset_id);
    1593              : 
    1594          242 :     keyset.keyset_id  = in_keyset.keyset_id;
    1595          242 :     keyset.policy     = in_keyset.policy;
    1596          242 :     keyset.keys_count = in_keyset.num_keys_used;
    1597          242 :     memset(keyset.operational_keys, 0x00, sizeof(keyset.operational_keys));
    1598          242 :     keyset.operational_keys[0].start_time = in_keyset.epoch_keys[0].start_time;
    1599          242 :     keyset.operational_keys[1].start_time = in_keyset.epoch_keys[1].start_time;
    1600          242 :     keyset.operational_keys[2].start_time = in_keyset.epoch_keys[2].start_time;
    1601              : 
    1602              :     // Store the operational keys and hash instead of the epoch keys
    1603          875 :     for (size_t i = 0; i < in_keyset.num_keys_used; ++i)
    1604              :     {
    1605          633 :         ByteSpan epoch_key(in_keyset.epoch_keys[i].key, Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES);
    1606          633 :         ReturnErrorOnFailure(
    1607              :             Crypto::DeriveGroupOperationalCredentials(epoch_key, compressed_fabric_id, keyset.operational_keys[i]));
    1608              :     }
    1609              : 
    1610          242 :     if (found)
    1611              :     {
    1612              :         // Update existing keyset info, keep next
    1613            5 :         return keyset.Save(mStorage);
    1614              :     }
    1615              : 
    1616              :     // New keyset
    1617          237 :     VerifyOrReturnError(fabric.keyset_count < mMaxGroupKeysPerFabric, CHIP_ERROR_INVALID_LIST_LENGTH);
    1618              : 
    1619              :     // Insert first
    1620          236 :     keyset.next = fabric.first_keyset;
    1621          236 :     ReturnErrorOnFailure(keyset.Save(mStorage));
    1622              :     // Update fabric
    1623          236 :     fabric.keyset_count++;
    1624          236 :     fabric.first_keyset = in_keyset.keyset_id;
    1625          236 :     return fabric.Save(mStorage);
    1626          242 : }
    1627              : 
    1628          105 : CHIP_ERROR GroupDataProviderImpl::GetKeySet(chip::FabricIndex fabric_index, uint16_t target_id, KeySet & out_keyset)
    1629              : {
    1630          105 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1631              : 
    1632          105 :     FabricData fabric(fabric_index);
    1633          105 :     KeySetData keyset;
    1634              : 
    1635          105 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1636           97 :     VerifyOrReturnError(keyset.Find(mStorage, fabric, target_id), CHIP_ERROR_NOT_FOUND);
    1637              : 
    1638              :     // Target keyset found
    1639           85 :     out_keyset.ClearKeys();
    1640           85 :     out_keyset.keyset_id     = keyset.keyset_id;
    1641           85 :     out_keyset.policy        = keyset.policy;
    1642           85 :     out_keyset.num_keys_used = keyset.keys_count;
    1643              :     // Epoch keys are not read back, only start times
    1644           85 :     out_keyset.epoch_keys[0].start_time = keyset.operational_keys[0].start_time;
    1645           85 :     out_keyset.epoch_keys[1].start_time = keyset.operational_keys[1].start_time;
    1646           85 :     out_keyset.epoch_keys[2].start_time = keyset.operational_keys[2].start_time;
    1647              : 
    1648           85 :     return CHIP_NO_ERROR;
    1649          105 : }
    1650              : 
    1651           28 : CHIP_ERROR GroupDataProviderImpl::RemoveKeySet(chip::FabricIndex fabric_index, uint16_t target_id)
    1652              : {
    1653           28 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1654              : 
    1655           28 :     FabricData fabric(fabric_index);
    1656           28 :     KeySetData keyset;
    1657              : 
    1658           28 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1659           28 :     VerifyOrReturnError(keyset.Find(mStorage, fabric, target_id), CHIP_ERROR_NOT_FOUND);
    1660           24 :     ReturnErrorOnFailure(keyset.Delete(mStorage));
    1661              : 
    1662           24 :     if (keyset.first)
    1663              :     {
    1664              :         // Remove first keyset
    1665           20 :         fabric.first_keyset = keyset.next;
    1666              :     }
    1667              :     else
    1668              :     {
    1669              :         // Remove intermediate keyset, update previous
    1670            4 :         KeySetData prev_data(fabric_index, keyset.prev);
    1671            4 :         ReturnErrorOnFailure(prev_data.Load(mStorage));
    1672            4 :         prev_data.next = keyset.next;
    1673            4 :         ReturnErrorOnFailure(prev_data.Save(mStorage));
    1674            4 :     }
    1675           24 :     if (fabric.keyset_count > 0)
    1676              :     {
    1677           24 :         fabric.keyset_count--;
    1678              :     }
    1679              :     // Update fabric info
    1680           24 :     ReturnErrorOnFailure(fabric.Save(mStorage));
    1681              : 
    1682              :     // Removing a key set also removes the associated group mappings
    1683           24 :     KeyMapData map;
    1684           24 :     uint16_t original_count = fabric.map_count;
    1685           24 :     for (uint16_t i = 0; i < original_count; ++i)
    1686              :     {
    1687            0 :         TEMPORARY_RETURN_IGNORED fabric.Load(mStorage);
    1688            0 :         size_t idx = map.Find(mStorage, fabric, target_id);
    1689            0 :         if (idx == std::numeric_limits<size_t>::max())
    1690              :         {
    1691            0 :             break;
    1692              :         }
    1693              :         // NOTE: It's unclear what should happen here if we have removed the key set
    1694              :         // and possibly some mappings before failing. For now, ignoring errors, but
    1695              :         // open to suggestsions for the correct behavior.
    1696            0 :         TEMPORARY_RETURN_IGNORED RemoveGroupKeyAt(fabric_index, idx);
    1697              :     }
    1698           24 :     return CHIP_NO_ERROR;
    1699           28 : }
    1700              : 
    1701            2 : GroupDataProvider::KeySetIterator * GroupDataProviderImpl::IterateKeySets(chip::FabricIndex fabric_index)
    1702              : {
    1703            2 :     VerifyOrReturnError(IsInitialized(), nullptr);
    1704            2 :     return mKeySetIterators.CreateObject(*this, fabric_index);
    1705              : }
    1706              : 
    1707            2 : GroupDataProviderImpl::KeySetIteratorImpl::KeySetIteratorImpl(GroupDataProviderImpl & provider, chip::FabricIndex fabric_index) :
    1708            2 :     mProvider(provider), mFabric(fabric_index)
    1709              : {
    1710            2 :     FabricData fabric(fabric_index);
    1711            4 :     if (CHIP_NO_ERROR == fabric.Load(provider.mStorage))
    1712              :     {
    1713            2 :         mNextId = fabric.first_keyset;
    1714            2 :         mTotal  = fabric.keyset_count;
    1715            2 :         mCount  = 0;
    1716              :     }
    1717            2 : }
    1718              : 
    1719            2 : size_t GroupDataProviderImpl::KeySetIteratorImpl::Count()
    1720              : {
    1721            2 :     return mTotal;
    1722              : }
    1723              : 
    1724            9 : bool GroupDataProviderImpl::KeySetIteratorImpl::Next(KeySet & output)
    1725              : {
    1726            9 :     VerifyOrReturnError(mCount < mTotal, false);
    1727              : 
    1728            7 :     KeySetData keyset(mFabric, mNextId);
    1729           14 :     VerifyOrReturnError(CHIP_NO_ERROR == keyset.Load(mProvider.mStorage), false);
    1730              : 
    1731            7 :     mCount++;
    1732            7 :     mNextId = keyset.next;
    1733            7 :     output.ClearKeys();
    1734            7 :     output.keyset_id     = keyset.keyset_id;
    1735            7 :     output.policy        = keyset.policy;
    1736            7 :     output.num_keys_used = keyset.keys_count;
    1737              :     // Epoch keys are not read back, only start times
    1738            7 :     output.epoch_keys[0].start_time = keyset.operational_keys[0].start_time;
    1739            7 :     output.epoch_keys[1].start_time = keyset.operational_keys[1].start_time;
    1740            7 :     output.epoch_keys[2].start_time = keyset.operational_keys[2].start_time;
    1741            7 :     return true;
    1742            7 : }
    1743              : 
    1744            2 : void GroupDataProviderImpl::KeySetIteratorImpl::Release()
    1745              : {
    1746            2 :     mProvider.mKeySetIterators.ReleaseObject(this);
    1747            2 : }
    1748              : 
    1749              : //
    1750              : // Fabrics
    1751              : //
    1752              : 
    1753           23 : CHIP_ERROR GroupDataProviderImpl::RemoveFabric(chip::FabricIndex fabric_index)
    1754              : {
    1755           23 :     FabricData fabric(fabric_index);
    1756              : 
    1757              :     // Fabric data defaults to zero, so if not entry is found, no mappings, or keys are removed
    1758              :     // However, states has a separate list, and needs to be removed regardless
    1759           23 :     CHIP_ERROR err = fabric.Load(mStorage);
    1760           50 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
    1761              : 
    1762              :     // Remove Group mappings
    1763              : 
    1764           35 :     for (size_t i = 0; i < fabric.map_count; i++)
    1765              :     {
    1766           12 :         TEMPORARY_RETURN_IGNORED RemoveGroupKeyAt(fabric_index, fabric.map_count - i - 1);
    1767              :     }
    1768              : 
    1769              :     // Remove group info
    1770              : 
    1771           48 :     for (size_t i = 0; i < fabric.group_count; i++)
    1772              :     {
    1773           25 :         TEMPORARY_RETURN_IGNORED RemoveGroupInfoAt(fabric_index, fabric.group_count - i - 1);
    1774              :     }
    1775              : 
    1776              :     // Remove Keysets
    1777              : 
    1778           23 :     KeySetData keyset(fabric_index, fabric.first_keyset);
    1779           23 :     size_t keyset_count = 0;
    1780              : 
    1781              :     // Loop the keysets associated with the target fabric
    1782           38 :     while (keyset_count < fabric.keyset_count)
    1783              :     {
    1784           30 :         if (CHIP_NO_ERROR != keyset.Load(mStorage))
    1785              :         {
    1786            0 :             break;
    1787              :         }
    1788           15 :         TEMPORARY_RETURN_IGNORED RemoveKeySet(fabric_index, keyset.keyset_id);
    1789           15 :         keyset.keyset_id = keyset.next;
    1790           15 :         keyset_count++;
    1791              :     }
    1792              : 
    1793              :     // Remove fabric
    1794           23 :     return fabric.Delete(mStorage);
    1795           23 : }
    1796              : 
    1797              : //
    1798              : // Cryptography
    1799              : //
    1800              : 
    1801            4 : Crypto::SymmetricKeyContext * GroupDataProviderImpl::GetKeyContext(FabricIndex fabric_index, GroupId group_id)
    1802              : {
    1803            4 :     FabricData fabric(fabric_index);
    1804            8 :     VerifyOrReturnError(CHIP_NO_ERROR == fabric.Load(mStorage), nullptr);
    1805              : 
    1806            4 :     KeyMapData mapping(fabric.fabric_index, fabric.first_map);
    1807              : 
    1808              :     // Look for the target group in the fabric's keyset-group pairs
    1809            4 :     for (uint16_t i = 0; i < fabric.map_count; ++i, mapping.id = mapping.next)
    1810              :     {
    1811            8 :         VerifyOrReturnError(CHIP_NO_ERROR == mapping.Load(mStorage), nullptr);
    1812              :         // GroupKeySetID of 0 is reserved for the Identity Protection Key (IPK),
    1813              :         // it cannot be used for operational group communication.
    1814            4 :         if (mapping.keyset_id > 0 && mapping.group_id == group_id)
    1815              :         {
    1816              :             // Group found, get the keyset
    1817            4 :             KeySetData keyset;
    1818            4 :             VerifyOrReturnError(keyset.Find(mStorage, fabric, mapping.keyset_id), nullptr);
    1819            4 :             Crypto::GroupOperationalCredentials * creds = keyset.GetCurrentGroupCredentials();
    1820            4 :             if (nullptr != creds)
    1821              :             {
    1822            4 :                 return mGroupKeyContexPool.CreateObject(*this, creds->encryption_key, creds->hash, creds->privacy_key);
    1823              :             }
    1824            4 :         }
    1825              :     }
    1826            0 :     return nullptr;
    1827            4 : }
    1828              : 
    1829           30 : CHIP_ERROR GroupDataProviderImpl::GetIpkKeySet(FabricIndex fabric_index, KeySet & out_keyset)
    1830              : {
    1831           30 :     FabricData fabric(fabric_index);
    1832           60 :     VerifyOrReturnError(CHIP_NO_ERROR == fabric.Load(mStorage), CHIP_ERROR_NOT_FOUND);
    1833              : 
    1834           29 :     KeyMapData mapping(fabric.fabric_index, fabric.first_map);
    1835              : 
    1836              :     // Fabric found, get the keyset
    1837           29 :     KeySetData keyset;
    1838           29 :     VerifyOrReturnError(keyset.Find(mStorage, fabric, kIdentityProtectionKeySetId), CHIP_ERROR_NOT_FOUND);
    1839              : 
    1840              :     // If the keyset ID doesn't match, we have a ... problem.
    1841           27 :     VerifyOrReturnError(keyset.keyset_id == kIdentityProtectionKeySetId, CHIP_ERROR_INTERNAL);
    1842              : 
    1843           27 :     out_keyset.keyset_id     = keyset.keyset_id;
    1844           27 :     out_keyset.num_keys_used = keyset.keys_count;
    1845           27 :     out_keyset.policy        = keyset.policy;
    1846              : 
    1847          108 :     for (size_t key_idx = 0; key_idx < MATTER_ARRAY_SIZE(out_keyset.epoch_keys); ++key_idx)
    1848              :     {
    1849           81 :         out_keyset.epoch_keys[key_idx].Clear();
    1850           81 :         if (key_idx < keyset.keys_count)
    1851              :         {
    1852           27 :             out_keyset.epoch_keys[key_idx].start_time = keyset.operational_keys[key_idx].start_time;
    1853           27 :             memcpy(&out_keyset.epoch_keys[key_idx].key[0], keyset.operational_keys[key_idx].encryption_key, EpochKey::kLengthBytes);
    1854              :         }
    1855              :     }
    1856              : 
    1857           27 :     return CHIP_NO_ERROR;
    1858           30 : }
    1859              : 
    1860            4 : void GroupDataProviderImpl::GroupKeyContext::Release()
    1861              : {
    1862            4 :     ReleaseKeys();
    1863            4 :     mProvider.mGroupKeyContexPool.ReleaseObject(this);
    1864            4 : }
    1865              : 
    1866            4 : CHIP_ERROR GroupDataProviderImpl::GroupKeyContext::MessageEncrypt(const ByteSpan & plaintext, const ByteSpan & aad,
    1867              :                                                                   const ByteSpan & nonce, MutableByteSpan & mic,
    1868              :                                                                   MutableByteSpan & ciphertext) const
    1869              : {
    1870            4 :     uint8_t * output = ciphertext.data();
    1871            4 :     return Crypto::AES_CCM_encrypt(plaintext.data(), plaintext.size(), aad.data(), aad.size(), mEncryptionKey, nonce.data(),
    1872            4 :                                    nonce.size(), output, mic.data(), mic.size());
    1873              : }
    1874              : 
    1875            8 : CHIP_ERROR GroupDataProviderImpl::GroupKeyContext::MessageDecrypt(const ByteSpan & ciphertext, const ByteSpan & aad,
    1876              :                                                                   const ByteSpan & nonce, const ByteSpan & mic,
    1877              :                                                                   MutableByteSpan & plaintext) const
    1878              : {
    1879            8 :     uint8_t * output = plaintext.data();
    1880           16 :     return Crypto::AES_CCM_decrypt(ciphertext.data(), ciphertext.size(), aad.data(), aad.size(), mic.data(), mic.size(),
    1881           16 :                                    mEncryptionKey, nonce.data(), nonce.size(), output);
    1882              : }
    1883              : 
    1884            0 : CHIP_ERROR GroupDataProviderImpl::GroupKeyContext::PrivacyEncrypt(const ByteSpan & input, const ByteSpan & nonce,
    1885              :                                                                   MutableByteSpan & output) const
    1886              : {
    1887            0 :     return Crypto::AES_CTR_crypt(input.data(), input.size(), mPrivacyKey, nonce.data(), nonce.size(), output.data());
    1888              : }
    1889              : 
    1890            3 : CHIP_ERROR GroupDataProviderImpl::GroupKeyContext::PrivacyDecrypt(const ByteSpan & input, const ByteSpan & nonce,
    1891              :                                                                   MutableByteSpan & output) const
    1892              : {
    1893            3 :     return Crypto::AES_CTR_crypt(input.data(), input.size(), mPrivacyKey, nonce.data(), nonce.size(), output.data());
    1894              : }
    1895              : 
    1896            9 : GroupDataProviderImpl::GroupSessionIterator * GroupDataProviderImpl::IterateGroupSessions(uint16_t session_id)
    1897              : {
    1898            9 :     VerifyOrReturnError(IsInitialized(), nullptr);
    1899            9 :     return mGroupSessionsIterator.CreateObject(*this, session_id);
    1900              : }
    1901              : 
    1902            9 : GroupDataProviderImpl::GroupSessionIteratorImpl::GroupSessionIteratorImpl(GroupDataProviderImpl & provider, uint16_t session_id) :
    1903            9 :     mProvider(provider), mSessionId(session_id), mGroupKeyContext(provider)
    1904              : {
    1905            9 :     FabricList fabric_list;
    1906            9 :     ReturnOnFailure(fabric_list.Load(provider.mStorage));
    1907            9 :     mFirstFabric = fabric_list.first_entry;
    1908            9 :     mFabric      = fabric_list.first_entry;
    1909            9 :     mFabricCount = 0;
    1910            9 :     mFabricTotal = fabric_list.entry_count;
    1911            9 :     mMapCount    = 0;
    1912            9 :     mFirstMap    = true;
    1913            9 : }
    1914              : 
    1915            1 : size_t GroupDataProviderImpl::GroupSessionIteratorImpl::Count()
    1916              : {
    1917            1 :     FabricData fabric(mFirstFabric);
    1918            1 :     size_t count = 0;
    1919              : 
    1920            3 :     for (size_t i = 0; i < mFabricTotal; i++, fabric.fabric_index = fabric.next)
    1921              :     {
    1922            4 :         if (CHIP_NO_ERROR != fabric.Load(mProvider.mStorage))
    1923              :         {
    1924            0 :             break;
    1925              :         }
    1926              : 
    1927              :         // Iterate key sets
    1928            2 :         KeyMapData mapping(fabric.fabric_index, fabric.first_map);
    1929              : 
    1930              :         // Look for the target group in the fabric's keyset-group pairs
    1931            8 :         for (uint16_t j = 0; j < fabric.map_count; ++j, mapping.id = mapping.next)
    1932              :         {
    1933           12 :             if (CHIP_NO_ERROR != mapping.Load(mProvider.mStorage))
    1934              :             {
    1935            0 :                 break;
    1936              :             }
    1937              : 
    1938              :             // Group found, get the keyset
    1939            6 :             KeySetData keyset;
    1940            6 :             if (!keyset.Find(mProvider.mStorage, fabric, mapping.keyset_id))
    1941              :             {
    1942            0 :                 break;
    1943              :             }
    1944           20 :             for (uint16_t k = 0; k < keyset.keys_count; ++k)
    1945              :             {
    1946           14 :                 if (keyset.operational_keys[k].hash == mSessionId)
    1947              :                 {
    1948            1 :                     count++;
    1949              :                 }
    1950              :             }
    1951            6 :         }
    1952            2 :     }
    1953            2 :     return count;
    1954            1 : }
    1955              : 
    1956           11 : bool GroupDataProviderImpl::GroupSessionIteratorImpl::Next(GroupSession & output)
    1957              : {
    1958           37 :     while (mFabricCount < mFabricTotal)
    1959              :     {
    1960           35 :         FabricData fabric(mFabric);
    1961           70 :         VerifyOrReturnError(CHIP_NO_ERROR == fabric.Load(mProvider.mStorage), false);
    1962              : 
    1963           35 :         if (mMapCount >= fabric.map_count)
    1964              :         {
    1965              :             // No more keyset/group mappings on the current fabric, try next fabric
    1966            3 :             mFabric = fabric.next;
    1967            3 :             mFabricCount++;
    1968            3 :             mFirstMap = true;
    1969            3 :             mMapCount = 0;
    1970            3 :             continue;
    1971              :         }
    1972              : 
    1973           32 :         if (mFirstMap)
    1974              :         {
    1975           10 :             mMapping  = fabric.first_map;
    1976           10 :             mFirstMap = false;
    1977              :         }
    1978              : 
    1979           32 :         KeyMapData mapping(mFabric, mMapping);
    1980           64 :         VerifyOrReturnError(CHIP_NO_ERROR == mapping.Load(mProvider.mStorage), false);
    1981              : 
    1982              :         // Group found, get the keyset
    1983           32 :         KeySetData keyset;
    1984           32 :         VerifyOrReturnError(keyset.Find(mProvider.mStorage, fabric, mapping.keyset_id), false);
    1985              : 
    1986           32 :         if (mKeyIndex >= keyset.keys_count || (mKeyIndex >= KeySet::kEpochKeysMax))
    1987              :         {
    1988              :             // No more keys in current keyset, try next
    1989            7 :             mMapping = mapping.next;
    1990            7 :             mMapCount++;
    1991            7 :             mKeyIndex = 0;
    1992            7 :             continue;
    1993              :         }
    1994              : 
    1995           25 :         Crypto::GroupOperationalCredentials & creds = keyset.operational_keys[mKeyIndex++];
    1996           25 :         if (creds.hash == mSessionId)
    1997              :         {
    1998            9 :             TEMPORARY_RETURN_IGNORED mGroupKeyContext.Initialize(creds.encryption_key, mSessionId, creds.privacy_key);
    1999            9 :             output.fabric_index    = fabric.fabric_index;
    2000            9 :             output.group_id        = mapping.group_id;
    2001            9 :             output.security_policy = keyset.policy;
    2002            9 :             output.keyContext      = &mGroupKeyContext;
    2003            9 :             return true;
    2004              :         }
    2005           67 :     }
    2006              : 
    2007            2 :     return false;
    2008              : }
    2009              : 
    2010            9 : void GroupDataProviderImpl::GroupSessionIteratorImpl::Release()
    2011              : {
    2012            9 :     mGroupKeyContext.ReleaseKeys();
    2013            9 :     mProvider.mGroupSessionsIterator.ReleaseObject(this);
    2014            9 : }
    2015              : 
    2016              : namespace {
    2017              : 
    2018              : GroupDataProvider * gGroupsProvider = nullptr;
    2019              : 
    2020              : } // namespace
    2021              : 
    2022           93 : GroupDataProvider * GetGroupDataProvider()
    2023              : {
    2024           93 :     return gGroupsProvider;
    2025              : }
    2026              : 
    2027          142 : void SetGroupDataProvider(GroupDataProvider * provider)
    2028              : {
    2029          142 :     gGroupsProvider = provider;
    2030          142 : }
    2031              : 
    2032              : } // namespace Credentials
    2033              : } // namespace chip
        

Generated by: LCOV version 2.0-1