LCOV - code coverage report
Current view: top level - credentials - GroupDataProviderImpl.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 995 1054 94.4 %
Date: 2024-02-15 08:20:41 Functions: 122 124 98.4 %

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

Generated by: LCOV version 1.14