Matter SDK Coverage Report
Current view: top level - credentials - GroupDataProviderImpl.cpp (source / functions) Coverage Total Hit
Test: SHA:2a48c1efeab1c0f76f3adb3a0940b0f7de706453 Lines: 95.2 % 1054 1003
Test Date: 2026-01-31 08:14:20 Functions: 98.4 % 124 122

            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          863 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
      40              :     {
      41          863 :         key = DefaultStorageKeyAllocator::GroupFabricList();
      42          863 :         return CHIP_NO_ERROR;
      43              :     }
      44              : };
      45              : 
      46              : constexpr size_t kPersistentBufferMax = 128;
      47              : 
      48              : struct LinkedData : public PersistableData<kPersistentBufferMax>
      49              : {
      50              :     static constexpr uint16_t kMinLinkId = 1;
      51              : 
      52           66 :     LinkedData() = default;
      53          453 :     LinkedData(uint16_t linked_id) : id(linked_id) {}
      54              :     uint16_t id     = kMinLinkId;
      55              :     uint16_t index  = 0;
      56              :     uint16_t next   = 0;
      57              :     uint16_t prev   = 0;
      58              :     uint16_t max_id = 0;
      59              :     bool first      = true;
      60              : };
      61              : 
      62              : struct FabricData : public PersistableData<kPersistentBufferMax>
      63              : {
      64         2694 :     static constexpr TLV::Tag TagFirstGroup() { return TLV::ContextTag(1); }
      65         2694 :     static constexpr TLV::Tag TagGroupCount() { return TLV::ContextTag(2); }
      66         2694 :     static constexpr TLV::Tag TagFirstMap() { return TLV::ContextTag(3); }
      67         2694 :     static constexpr TLV::Tag TagMapCount() { return TLV::ContextTag(4); }
      68         2694 :     static constexpr TLV::Tag TagFirstKeyset() { return TLV::ContextTag(5); }
      69         2694 :     static constexpr TLV::Tag TagKeysetCount() { return TLV::ContextTag(6); }
      70         2694 :     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         2110 :     FabricData(chip::FabricIndex fabric) : fabric_index(fabric) {}
      83              : 
      84         2893 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
      85              :     {
      86         2893 :         VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX);
      87         2891 :         key = DefaultStorageKeyAllocator::FabricGroups(fabric_index);
      88         2891 :         return CHIP_NO_ERROR;
      89              :     }
      90              : 
      91         2150 :     void Clear() override
      92              :     {
      93         2150 :         first_group  = kUndefinedGroupId;
      94         2150 :         group_count  = 0;
      95         2150 :         first_keyset = kInvalidKeysetId;
      96         2150 :         keyset_count = 0;
      97         2150 :         next         = kUndefinedFabricIndex;
      98         2150 :     }
      99              : 
     100          722 :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
     101              :     {
     102              :         TLV::TLVType container;
     103          722 :         ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
     104              : 
     105          722 :         ReturnErrorOnFailure(writer.Put(TagFirstGroup(), static_cast<uint16_t>(first_group)));
     106          722 :         ReturnErrorOnFailure(writer.Put(TagGroupCount(), static_cast<uint16_t>(group_count)));
     107          722 :         ReturnErrorOnFailure(writer.Put(TagFirstMap(), static_cast<uint16_t>(first_map)));
     108          722 :         ReturnErrorOnFailure(writer.Put(TagMapCount(), static_cast<uint16_t>(map_count)));
     109          722 :         ReturnErrorOnFailure(writer.Put(TagFirstKeyset(), static_cast<uint16_t>(first_keyset)));
     110          722 :         ReturnErrorOnFailure(writer.Put(TagKeysetCount(), static_cast<uint16_t>(keyset_count)));
     111          722 :         ReturnErrorOnFailure(writer.Put(TagNext(), static_cast<uint16_t>(next)));
     112              : 
     113          722 :         return writer.EndContainer(container);
     114              :     }
     115         1972 :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override
     116              :     {
     117         1972 :         ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     118         1972 :         VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     119              : 
     120              :         TLV::TLVType container;
     121         1972 :         ReturnErrorOnFailure(reader.EnterContainer(container));
     122              : 
     123              :         // first_group
     124         1972 :         ReturnErrorOnFailure(reader.Next(TagFirstGroup()));
     125         1972 :         ReturnErrorOnFailure(reader.Get(first_group));
     126              :         // group_count
     127         1972 :         ReturnErrorOnFailure(reader.Next(TagGroupCount()));
     128         1972 :         ReturnErrorOnFailure(reader.Get(group_count));
     129              :         // first_map
     130         1972 :         ReturnErrorOnFailure(reader.Next(TagFirstMap()));
     131         1972 :         ReturnErrorOnFailure(reader.Get(first_map));
     132              :         // map_count
     133         1972 :         ReturnErrorOnFailure(reader.Next(TagMapCount()));
     134         1972 :         ReturnErrorOnFailure(reader.Get(map_count));
     135              :         // first_keyset
     136         1972 :         ReturnErrorOnFailure(reader.Next(TagFirstKeyset()));
     137         1972 :         ReturnErrorOnFailure(reader.Get(first_keyset));
     138              :         // keyset_count
     139         1972 :         ReturnErrorOnFailure(reader.Next(TagKeysetCount()));
     140         1972 :         ReturnErrorOnFailure(reader.Get(keyset_count));
     141              :         // next
     142         1972 :         ReturnErrorOnFailure(reader.Next(TagNext()));
     143         1972 :         ReturnErrorOnFailure(reader.Get(next));
     144              : 
     145         1972 :         return reader.ExitContainer(container);
     146              :     }
     147              : 
     148              :     // Register the fabric in the fabrics' linked-list
     149          722 :     CHIP_ERROR Register(PersistentStorageDelegate * storage)
     150              :     {
     151          722 :         FabricList fabric_list;
     152          722 :         CHIP_ERROR err = fabric_list.Load(storage);
     153         1444 :         if (CHIP_ERROR_NOT_FOUND == err)
     154              :         {
     155              :             // New fabric list
     156           70 :             fabric_list.first_entry = fabric_index;
     157           70 :             fabric_list.entry_count = 1;
     158           70 :             return fabric_list.Save(storage);
     159              :         }
     160          652 :         ReturnErrorOnFailure(err);
     161              : 
     162              :         // Existing fabric list, search for existing entry
     163          652 :         FabricData fabric(fabric_list.first_entry);
     164          707 :         for (size_t i = 0; i < fabric_list.entry_count; i++)
     165              :         {
     166          687 :             err = fabric.Load(storage);
     167         1374 :             if (CHIP_NO_ERROR != err)
     168              :             {
     169            0 :                 break;
     170              :             }
     171          687 :             if (fabric.fabric_index == this->fabric_index)
     172              :             {
     173              :                 // Fabric already registered
     174          632 :                 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          722 :     }
     184              : 
     185              :     // Remove the fabric from the fabrics' linked list
     186           23 :     CHIP_ERROR Unregister(PersistentStorageDelegate * storage) const
     187              :     {
     188           23 :         FabricList fabric_list;
     189           23 :         CHIP_ERROR err = fabric_list.Load(storage);
     190           48 :         VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
     191              : 
     192              :         // Existing fabric list, search for existing entry
     193           23 :         FabricData fabric(fabric_list.first_entry);
     194           23 :         FabricData prev;
     195              : 
     196           33 :         for (size_t i = 0; i < fabric_list.entry_count; i++)
     197              :         {
     198           29 :             err = fabric.Load(storage);
     199           58 :             if (CHIP_NO_ERROR != err)
     200              :             {
     201            0 :                 break;
     202              :             }
     203           29 :             if (fabric.fabric_index == this->fabric_index)
     204              :             {
     205              :                 // Fabric found
     206           19 :                 if (i == 0)
     207              :                 {
     208              :                     // Remove first fabric
     209           10 :                     fabric_list.first_entry = this->next;
     210              :                 }
     211              :                 else
     212              :                 {
     213              :                     // Remove intermediate fabric
     214            9 :                     prev.next = this->next;
     215            9 :                     ReturnErrorOnFailure(prev.Save(storage));
     216              :                 }
     217           19 :                 VerifyOrReturnError(fabric_list.entry_count > 0, CHIP_ERROR_INTERNAL);
     218           19 :                 fabric_list.entry_count--;
     219           19 :                 return fabric_list.Save(storage);
     220              :             }
     221           10 :             prev                = fabric;
     222           10 :             fabric.fabric_index = fabric.next;
     223              :         }
     224              :         // Fabric not in the list
     225            4 :         return CHIP_ERROR_NOT_FOUND;
     226           23 :     }
     227              : 
     228              :     // Check the fabric is registered in the fabrics' linked list
     229              :     CHIP_ERROR Validate(PersistentStorageDelegate * storage) const
     230              :     {
     231              :         FabricList fabric_list;
     232              :         ReturnErrorOnFailure(fabric_list.Load(storage));
     233              : 
     234              :         // Existing fabric list, search for existing entry
     235              :         FabricData fabric(fabric_list.first_entry);
     236              : 
     237              :         for (size_t i = 0; i < fabric_list.entry_count; i++)
     238              :         {
     239              :             ReturnErrorOnFailure(fabric.Load(storage));
     240              :             if (fabric.fabric_index == this->fabric_index)
     241              :             {
     242              :                 return CHIP_NO_ERROR;
     243              :             }
     244              :             fabric.fabric_index = fabric.next;
     245              :         }
     246              :         // Fabric not in the list
     247              :         return CHIP_ERROR_NOT_FOUND;
     248              :     }
     249              : 
     250          722 :     CHIP_ERROR Save(PersistentStorageDelegate * storage) // NOLINT(bugprone-derived-method-shadowing-base-method)
     251              :     {
     252          722 :         ReturnErrorOnFailure(Register(storage));
     253          722 :         return PersistableData::Save(storage);
     254              :     }
     255              : 
     256           23 :     CHIP_ERROR Delete(PersistentStorageDelegate * storage) // NOLINT(bugprone-derived-method-shadowing-base-method)
     257              :     {
     258           23 :         ReturnErrorOnFailure(Unregister(storage));
     259           19 :         return PersistableData::Delete(storage);
     260              :     }
     261              : };
     262              : 
     263              : struct GroupData : public GroupDataProvider::GroupInfo, PersistableData<kPersistentBufferMax>
     264              : {
     265         1902 :     static constexpr TLV::Tag TagName() { return TLV::ContextTag(1); }
     266         1902 :     static constexpr TLV::Tag TagFirstEndpoint() { return TLV::ContextTag(2); }
     267         1902 :     static constexpr TLV::Tag TagEndpointCount() { return TLV::ContextTag(3); }
     268         1902 :     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          768 :     GroupData() : GroupInfo(nullptr){};
     279              :     GroupData(chip::FabricIndex fabric) : fabric_index(fabric) {}
     280          198 :     GroupData(chip::FabricIndex fabric, chip::GroupId group) : GroupInfo(group, nullptr), fabric_index(fabric) {}
     281              : 
     282         1936 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
     283              :     {
     284         1936 :         VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX);
     285         1936 :         key = DefaultStorageKeyAllocator::FabricGroup(fabric_index, group_id);
     286         1936 :         return CHIP_NO_ERROR;
     287              :     }
     288              : 
     289         1293 :     void Clear() override
     290              :     {
     291         1293 :         SetName(CharSpan());
     292         1293 :         first_endpoint = kInvalidEndpointId;
     293         1293 :         endpoint_count = 0;
     294         1293 :         next           = 0;
     295         1293 :     }
     296              : 
     297          610 :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
     298              :     {
     299              :         TLV::TLVType container;
     300          610 :         ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
     301              : 
     302          610 :         size_t name_size = strnlen(name, GroupDataProvider::GroupInfo::kGroupNameMax);
     303          610 :         ReturnErrorOnFailure(writer.PutString(TagName(), name, static_cast<uint32_t>(name_size)));
     304          610 :         ReturnErrorOnFailure(writer.Put(TagFirstEndpoint(), static_cast<uint16_t>(first_endpoint)));
     305          610 :         ReturnErrorOnFailure(writer.Put(TagEndpointCount(), static_cast<uint16_t>(endpoint_count)));
     306          610 :         ReturnErrorOnFailure(writer.Put(TagNext(), static_cast<uint16_t>(next)));
     307          610 :         return writer.EndContainer(container);
     308              :     }
     309              : 
     310         1292 :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override
     311              :     {
     312         1292 :         ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     313         1292 :         VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     314              : 
     315              :         TLV::TLVType container;
     316         1292 :         ReturnErrorOnFailure(reader.EnterContainer(container));
     317              : 
     318              :         // name
     319         1292 :         ReturnErrorOnFailure(reader.Next(TagName()));
     320         1292 :         ReturnErrorOnFailure(reader.GetString(name, sizeof(name)));
     321         1292 :         size_t size = strnlen(name, kGroupNameMax);
     322         1292 :         name[size]  = 0;
     323              :         // first_endpoint
     324         1292 :         ReturnErrorOnFailure(reader.Next(TagFirstEndpoint()));
     325         1292 :         ReturnErrorOnFailure(reader.Get(first_endpoint));
     326              :         // endpoint_count
     327         1292 :         ReturnErrorOnFailure(reader.Next(TagEndpointCount()));
     328         1292 :         ReturnErrorOnFailure(reader.Get(endpoint_count));
     329              :         // next
     330         1292 :         ReturnErrorOnFailure(reader.Next(TagNext()));
     331         1292 :         ReturnErrorOnFailure(reader.Get(next));
     332              : 
     333         1292 :         return reader.ExitContainer(container);
     334              :     }
     335              : 
     336           59 :     bool Get(PersistentStorageDelegate * storage, const FabricData & fabric, size_t target_index)
     337              :     {
     338           59 :         fabric_index = fabric.fabric_index;
     339           59 :         group_id     = fabric.first_group;
     340           59 :         index        = 0;
     341           59 :         first        = true;
     342              : 
     343          115 :         while (index < fabric.group_count)
     344              :         {
     345          224 :             if (CHIP_NO_ERROR != Load(storage))
     346              :             {
     347            0 :                 break;
     348              :             }
     349          112 :             if (index == target_index)
     350              :             {
     351              :                 // Target index found
     352           56 :                 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          695 :     bool Find(PersistentStorageDelegate * storage, const FabricData & fabric, chip::GroupId target_group)
     365              :     {
     366          695 :         fabric_index = fabric.fabric_index;
     367          695 :         group_id     = fabric.first_group;
     368          695 :         index        = 0;
     369          695 :         first        = true;
     370              : 
     371         1388 :         while (index < fabric.group_count)
     372              :         {
     373         1960 :             if (CHIP_NO_ERROR != Load(storage))
     374              :             {
     375            0 :                 break;
     376              :             }
     377          980 :             if (group_id == target_group)
     378              :             {
     379              :                 // Target index found
     380          287 :                 return true;
     381              :             }
     382          693 :             first    = false;
     383          693 :             prev     = group_id;
     384          693 :             group_id = next;
     385          693 :             index++;
     386              :         }
     387          408 :         return false;
     388              :     }
     389              : };
     390              : 
     391              : struct KeyMapData : public GroupDataProvider::GroupKey, LinkedData
     392              : {
     393         1132 :     static constexpr TLV::Tag TagGroupId() { return TLV::ContextTag(1); }
     394         1132 :     static constexpr TLV::Tag TagKeysetId() { return TLV::ContextTag(2); }
     395         1132 :     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          453 :     KeyMapData(chip::FabricIndex fabric, uint16_t link_id = 0, chip::GroupId group = kUndefinedGroupId, chip::KeysetId keyset = 0) :
     403          453 :         GroupKey(group, keyset), LinkedData(link_id), fabric_index(fabric)
     404          453 :     {}
     405              : 
     406         1149 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
     407              :     {
     408         1149 :         VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX);
     409         1149 :         key = DefaultStorageKeyAllocator::FabricGroupKey(fabric_index, id);
     410         1149 :         return CHIP_NO_ERROR;
     411              :     }
     412              : 
     413          768 :     void Clear() override {}
     414              : 
     415          364 :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
     416              :     {
     417              :         TLV::TLVType container;
     418          364 :         ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
     419              : 
     420          364 :         ReturnErrorOnFailure(writer.Put(TagGroupId(), static_cast<uint16_t>(group_id)));
     421          364 :         ReturnErrorOnFailure(writer.Put(TagKeysetId(), static_cast<uint16_t>(keyset_id)));
     422          364 :         ReturnErrorOnFailure(writer.Put(TagNext(), static_cast<uint16_t>(next)));
     423          364 :         return writer.EndContainer(container);
     424              :     }
     425              : 
     426          768 :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override
     427              :     {
     428          768 :         ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     429          768 :         VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     430              : 
     431              :         TLV::TLVType container;
     432          768 :         ReturnErrorOnFailure(reader.EnterContainer(container));
     433              : 
     434              :         // first_endpoint
     435          768 :         ReturnErrorOnFailure(reader.Next(TagGroupId()));
     436          768 :         ReturnErrorOnFailure(reader.Get(group_id));
     437              :         // endpoint_count
     438          768 :         ReturnErrorOnFailure(reader.Next(TagKeysetId()));
     439          768 :         ReturnErrorOnFailure(reader.Get(keyset_id));
     440              :         // next
     441          768 :         ReturnErrorOnFailure(reader.Next(TagNext()));
     442          768 :         ReturnErrorOnFailure(reader.Get(next));
     443              : 
     444          768 :         return reader.ExitContainer(container);
     445              :     }
     446              : 
     447          258 :     bool Get(PersistentStorageDelegate * storage, const FabricData & fabric, size_t target_index)
     448              :     {
     449          258 :         fabric_index = fabric.fabric_index;
     450          258 :         id           = fabric.first_map;
     451          258 :         max_id       = 0;
     452          258 :         index        = 0;
     453          258 :         first        = true;
     454              : 
     455          539 :         while (index < fabric.map_count)
     456              :         {
     457          640 :             if (CHIP_NO_ERROR != Load(storage))
     458              :             {
     459            0 :                 break;
     460              :             }
     461          320 :             if (index == target_index)
     462              :             {
     463              :                 // Target index found
     464           39 :                 return true;
     465              :             }
     466          281 :             max_id = std::max(id, max_id);
     467          281 :             first  = false;
     468          281 :             prev   = id;
     469          281 :             id     = next;
     470          281 :             index++;
     471              :         }
     472              : 
     473          219 :         id = static_cast<uint16_t>(max_id + 1);
     474          219 :         return false;
     475              :     }
     476              : 
     477          222 :     bool Find(PersistentStorageDelegate * storage, const FabricData & fabric, const GroupKey & map)
     478              :     {
     479          222 :         fabric_index = fabric.fabric_index;
     480          222 :         id           = fabric.first_map;
     481          222 :         max_id       = 0;
     482          222 :         index        = 0;
     483          222 :         first        = true;
     484              : 
     485          453 :         while (index < fabric.map_count)
     486              :         {
     487          480 :             if (CHIP_NO_ERROR != Load(storage))
     488              :             {
     489            0 :                 break;
     490              :             }
     491          240 :             if ((group_id == map.group_id) && (keyset_id == map.keyset_id))
     492              :             {
     493              :                 // Match found
     494            9 :                 return true;
     495              :             }
     496          231 :             max_id = std::max(id, max_id);
     497          231 :             first  = false;
     498          231 :             prev   = id;
     499          231 :             id     = next;
     500          231 :             index++;
     501              :         }
     502              : 
     503          213 :         id = static_cast<uint16_t>(max_id + 1);
     504          213 :         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, PersistableData<kPersistentBufferMax>
     540              : {
     541          527 :     static constexpr TLV::Tag TagEndpoint() { return TLV::ContextTag(1); }
     542          527 :     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          289 :     EndpointData() = default;
     551           94 :     EndpointData(chip::FabricIndex fabric, chip::GroupId group = kUndefinedGroupId,
     552           94 :                  chip::EndpointId endpoint = kInvalidEndpointId) :
     553              :         GroupEndpoint(group, endpoint),
     554           94 :         fabric_index(fabric)
     555           94 :     {}
     556              : 
     557          568 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
     558              :     {
     559          568 :         VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX);
     560          568 :         key = DefaultStorageKeyAllocator::FabricGroupEndpoint(fabric_index, group_id, endpoint_id);
     561          568 :         return CHIP_NO_ERROR;
     562              :     }
     563              : 
     564          244 :     void Clear() override { next = kInvalidEndpointId; }
     565              : 
     566          288 :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
     567              :     {
     568              :         TLV::TLVType container;
     569          288 :         ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
     570              : 
     571          288 :         ReturnErrorOnFailure(writer.Put(TagEndpoint(), static_cast<uint16_t>(endpoint_id)));
     572          288 :         ReturnErrorOnFailure(writer.Put(TagNext(), static_cast<uint16_t>(next)));
     573              : 
     574          288 :         return writer.EndContainer(container);
     575              :     }
     576          239 :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override
     577              :     {
     578          239 :         ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     579          239 :         VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     580              : 
     581              :         TLV::TLVType container;
     582          239 :         ReturnErrorOnFailure(reader.EnterContainer(container));
     583              : 
     584              :         // endpoint_id
     585          239 :         ReturnErrorOnFailure(reader.Next(TagEndpoint()));
     586          239 :         ReturnErrorOnFailure(reader.Get(endpoint_id));
     587              :         // next
     588          239 :         ReturnErrorOnFailure(reader.Next(TagNext()));
     589          239 :         ReturnErrorOnFailure(reader.Get(next));
     590              : 
     591          239 :         return reader.ExitContainer(container);
     592              :     }
     593              : 
     594          277 :     bool Find(PersistentStorageDelegate * storage, const FabricData & fabric, const GroupData & group, chip::EndpointId target_id)
     595              :     {
     596          277 :         fabric_index = fabric.fabric_index;
     597          277 :         group_id     = group.group_id;
     598          277 :         endpoint_id  = group.first_endpoint;
     599          277 :         index        = 0;
     600          277 :         first        = true;
     601              : 
     602          371 :         while (index < group.endpoint_count)
     603              :         {
     604          288 :             if (CHIP_NO_ERROR != Load(storage))
     605              :             {
     606            0 :                 break;
     607              :             }
     608          144 :             if (this->endpoint_id == target_id)
     609              :             {
     610              :                 // Match found
     611           50 :                 return true;
     612              :             }
     613              : 
     614           94 :             first       = false;
     615           94 :             prev        = endpoint_id;
     616           94 :             endpoint_id = next;
     617           94 :             index++;
     618              :         }
     619              : 
     620          227 :         return false;
     621              :     }
     622              : };
     623              : 
     624              : struct KeySetData : PersistableData<kPersistentBufferMax>
     625              : {
     626          668 :     static constexpr TLV::Tag TagPolicy() { return TLV::ContextTag(1); }
     627          668 :     static constexpr TLV::Tag TagNumKeys() { return TLV::ContextTag(2); }
     628          668 :     static constexpr TLV::Tag TagGroupCredentials() { return TLV::ContextTag(3); }
     629         2004 :     static constexpr TLV::Tag TagStartTime() { return TLV::ContextTag(4); }
     630         2004 :     static constexpr TLV::Tag TagKeyHash() { return TLV::ContextTag(5); }
     631         2004 :     static constexpr TLV::Tag TagKeyValue() { return TLV::ContextTag(6); }
     632          668 :     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          356 :     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          692 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
     651              :     {
     652          692 :         VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX);
     653          692 :         VerifyOrReturnError(kInvalidKeysetId != keyset_id, CHIP_ERROR_INVALID_KEY_ID);
     654          692 :         key = DefaultStorageKeyAllocator::FabricKeyset(fabric_index, keyset_id);
     655          692 :         return CHIP_NO_ERROR;
     656              :     }
     657              : 
     658          446 :     void Clear() override
     659              :     {
     660          446 :         policy     = GroupDataProvider::SecurityPolicy::kCacheAndSync;
     661          446 :         keys_count = 0;
     662          446 :         memset(operational_keys, 0x00, sizeof(operational_keys));
     663          446 :         next = kInvalidKeysetId;
     664          446 :     }
     665              : 
     666            4 :     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            4 :         switch (this->keys_count)
     672              :         {
     673            1 :         case 1:
     674              :         case 2:
     675            1 :             return &operational_keys[0];
     676            3 :         case 3:
     677            3 :             return &operational_keys[1];
     678            0 :         default:
     679            0 :             return nullptr;
     680              :         }
     681              :     }
     682              : 
     683          222 :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
     684              :     {
     685              :         TLV::TLVType container;
     686          222 :         ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
     687              : 
     688              :         // policy
     689          222 :         ReturnErrorOnFailure(writer.Put(TagPolicy(), static_cast<uint16_t>(policy)));
     690              :         // keys_count
     691          222 :         ReturnErrorOnFailure(writer.Put(TagNumKeys(), static_cast<uint16_t>(keys_count)));
     692              :         // operational_keys
     693              :         {
     694              :             TLV::TLVType array, item;
     695          222 :             ReturnErrorOnFailure(writer.StartContainer(TagGroupCredentials(), TLV::kTLVType_Array, array));
     696          222 :             uint8_t keyCount   = 0;
     697          222 :             uint64_t startTime = 0;
     698          222 :             uint16_t hash      = 0;
     699              :             uint8_t encryptionKey[Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES];
     700          888 :             for (auto & key : operational_keys)
     701              :             {
     702          666 :                 startTime = 0;
     703          666 :                 hash      = 0;
     704          666 :                 memset(encryptionKey, 0, sizeof(encryptionKey));
     705          666 :                 ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, item));
     706              : 
     707          666 :                 if (keyCount++ < keys_count)
     708              :                 {
     709          618 :                     startTime = key.start_time;
     710          618 :                     hash      = key.hash;
     711          618 :                     memcpy(encryptionKey, key.encryption_key, sizeof(encryptionKey));
     712              :                 }
     713          666 :                 ReturnErrorOnFailure(writer.Put(TagStartTime(), static_cast<uint64_t>(startTime)));
     714          666 :                 ReturnErrorOnFailure(writer.Put(TagKeyHash(), hash));
     715          666 :                 ReturnErrorOnFailure(writer.Put(TagKeyValue(), ByteSpan(encryptionKey)));
     716              : 
     717          666 :                 ReturnErrorOnFailure(writer.EndContainer(item));
     718              :             }
     719          222 :             ReturnErrorOnFailure(writer.EndContainer(array));
     720              :         }
     721              :         // next keyset
     722          222 :         ReturnErrorOnFailure(writer.Put(TagNext(), static_cast<uint16_t>(next)));
     723              : 
     724          222 :         return writer.EndContainer(container);
     725              :     }
     726              : 
     727          446 :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override
     728              :     {
     729          446 :         ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     730          446 :         VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     731              : 
     732              :         TLV::TLVType container;
     733          446 :         ReturnErrorOnFailure(reader.EnterContainer(container));
     734              : 
     735              :         // policy
     736          446 :         ReturnErrorOnFailure(reader.Next(TagPolicy()));
     737          446 :         ReturnErrorOnFailure(reader.Get(policy));
     738              :         // keys_count
     739          446 :         ReturnErrorOnFailure(reader.Next(TagNumKeys()));
     740          446 :         ReturnErrorOnFailure(reader.Get(keys_count));
     741              :         // TODO(#21614): Enforce maximum number of 3 keys in a keyset
     742              :         {
     743              :             // operational_keys
     744          446 :             ReturnErrorOnFailure(reader.Next(TagGroupCredentials()));
     745          446 :             VerifyOrReturnError(TLV::kTLVType_Array == reader.GetType(), CHIP_ERROR_INTERNAL);
     746              : 
     747              :             TLV::TLVType array, item;
     748          446 :             ReturnErrorOnFailure(reader.EnterContainer(array));
     749         1784 :             for (auto & key : operational_keys)
     750              :             {
     751         1338 :                 ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     752         1338 :                 VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     753              : 
     754         1338 :                 ReturnErrorOnFailure(reader.EnterContainer(item));
     755              :                 // start_time
     756         1338 :                 ReturnErrorOnFailure(reader.Next(TagStartTime()));
     757         1338 :                 ReturnErrorOnFailure(reader.Get(key.start_time));
     758              :                 // key hash
     759         1338 :                 ReturnErrorOnFailure(reader.Next(TagKeyHash()));
     760         1338 :                 ReturnErrorOnFailure(reader.Get(key.hash));
     761              :                 // key value
     762         1338 :                 ByteSpan encryption_key;
     763         1338 :                 ReturnErrorOnFailure(reader.Next(TagKeyValue()));
     764         1338 :                 ReturnErrorOnFailure(reader.Get(encryption_key));
     765         1338 :                 VerifyOrReturnError(Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES == encryption_key.size(), CHIP_ERROR_INTERNAL);
     766         1338 :                 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         1338 :                 MutableByteSpan privacy_key(key.privacy_key);
     769         1338 :                 ReturnErrorOnFailure(Crypto::DeriveGroupPrivacyKey(encryption_key, privacy_key));
     770         1338 :                 ReturnErrorOnFailure(reader.ExitContainer(item));
     771              :             }
     772          446 :             ReturnErrorOnFailure(reader.ExitContainer(array));
     773              :         }
     774              :         // next keyset
     775          446 :         ReturnErrorOnFailure(reader.Next(TagNext()));
     776          446 :         ReturnErrorOnFailure(reader.Get(next));
     777              : 
     778          446 :         return reader.ExitContainer(container);
     779              :     }
     780              : 
     781          353 :     bool Find(PersistentStorageDelegate * storage, const FabricData & fabric, size_t target_id)
     782              :     {
     783          353 :         uint16_t count = 0;
     784              : 
     785          353 :         fabric_index = fabric.fabric_index;
     786          353 :         keyset_id    = fabric.first_keyset;
     787          353 :         first        = true;
     788              : 
     789          651 :         while (count++ < fabric.keyset_count)
     790              :         {
     791          840 :             if (CHIP_NO_ERROR != Load(storage))
     792              :             {
     793            0 :                 break;
     794              :             }
     795              : 
     796          420 :             if (keyset_id == target_id)
     797              :             {
     798              :                 // Target id found
     799          122 :                 return true;
     800              :             }
     801              : 
     802          298 :             first     = false;
     803          298 :             prev      = keyset_id;
     804          298 :             keyset_id = next;
     805              :         }
     806              : 
     807          231 :         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           74 : CHIP_ERROR GroupDataProviderImpl::Init()
     819              : {
     820           74 :     if (mStorage == nullptr || mSessionKeystore == nullptr)
     821              :     {
     822            0 :         return CHIP_ERROR_INCORRECT_STATE;
     823              :     }
     824           74 :     return CHIP_NO_ERROR;
     825              : }
     826              : 
     827           70 : void GroupDataProviderImpl::Finish()
     828              : {
     829           70 :     mGroupInfoIterators.ReleaseAll();
     830           70 :     mGroupKeyIterators.ReleaseAll();
     831           70 :     mEndpointIterators.ReleaseAll();
     832           70 :     mKeySetIterators.ReleaseAll();
     833           70 :     mGroupSessionsIterator.ReleaseAll();
     834           70 :     mGroupKeyContexPool.ReleaseAll();
     835           70 : }
     836              : 
     837           74 : void GroupDataProviderImpl::SetStorageDelegate(PersistentStorageDelegate * storage)
     838              : {
     839           74 :     VerifyOrDie(storage != nullptr);
     840           74 :     mStorage = storage;
     841           74 : }
     842              : 
     843              : //
     844              : // Group Info
     845              : //
     846              : 
     847          182 : CHIP_ERROR GroupDataProviderImpl::SetGroupInfo(chip::FabricIndex fabric_index, const GroupInfo & info)
     848              : {
     849          182 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
     850              : 
     851          182 :     FabricData fabric(fabric_index);
     852          182 :     GroupData group;
     853              : 
     854              :     // Load fabric data (defaults to zero)
     855          182 :     CHIP_ERROR err = fabric.Load(mStorage);
     856          424 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
     857              : 
     858          182 :     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          181 :     group.group_id = info.group_id;
     867          181 :     group.SetName(info.name);
     868          181 :     return SetGroupInfoAt(fabric_index, fabric.group_count, group);
     869          182 : }
     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          222 : CHIP_ERROR GroupDataProviderImpl::SetGroupInfoAt(chip::FabricIndex fabric_index, size_t index, const GroupInfo & info)
     896              : {
     897          222 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
     898              : 
     899          222 :     FabricData fabric(fabric_index);
     900          222 :     GroupData group;
     901              : 
     902              :     // Load fabric, defaults to zero
     903          222 :     CHIP_ERROR err = fabric.Load(mStorage);
     904          514 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
     905              : 
     906              :     // If the group exists, the index must match
     907          222 :     bool found = group.Find(mStorage, fabric, info.group_id);
     908          222 :     VerifyOrReturnError(!found || (group.index == index), CHIP_ERROR_DUPLICATE_KEY_ID);
     909              : 
     910          218 :     group.group_id       = info.group_id;
     911          218 :     group.endpoint_count = 0;
     912          218 :     group.SetName(info.name);
     913              : 
     914          218 :     if (found)
     915              :     {
     916              :         // Update existing entry
     917            6 :         return group.Save(mStorage);
     918              :     }
     919          212 :     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          211 :         VerifyOrReturnError(fabric.group_count == index, CHIP_ERROR_INVALID_ARGUMENT);
     936          210 :         VerifyOrReturnError(fabric.group_count < mMaxGroupsPerFabric, CHIP_ERROR_INVALID_LIST_LENGTH);
     937          210 :         fabric.group_count++;
     938              :     }
     939              : 
     940          211 :     ReturnErrorOnFailure(group.Save(mStorage));
     941              : 
     942          211 :     if (group.first)
     943              :     {
     944              :         // First group, update fabric
     945           71 :         fabric.first_group = group.group_id;
     946              :     }
     947              :     else
     948              :     {
     949              :         // Second to last group, update previous
     950          140 :         GroupData prev(fabric_index, group.prev);
     951          140 :         ReturnErrorOnFailure(prev.Load(mStorage));
     952          140 :         prev.next = group.group_id;
     953          140 :         ReturnErrorOnFailure(prev.Save(mStorage));
     954          140 :     }
     955              :     // Update fabric
     956          211 :     ReturnErrorOnFailure(fabric.Save(mStorage));
     957          211 :     GroupAdded(fabric_index, group);
     958          211 :     return CHIP_NO_ERROR;
     959          222 : }
     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           32 : CHIP_ERROR GroupDataProviderImpl::RemoveGroupInfoAt(chip::FabricIndex fabric_index, size_t index)
     978              : {
     979           32 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
     980              : 
     981           32 :     FabricData fabric(fabric_index);
     982           32 :     GroupData group;
     983              : 
     984           32 :     ReturnErrorOnFailure(fabric.Load(mStorage));
     985           32 :     VerifyOrReturnError(group.Get(mStorage, fabric, index), CHIP_ERROR_NOT_FOUND);
     986              : 
     987              :     // Remove endpoints
     988           32 :     EndpointData endpoint(fabric_index, group.group_id, group.first_endpoint);
     989           32 :     size_t count = 0;
     990           58 :     while (count++ < group.endpoint_count)
     991              :     {
     992           62 :         if (CHIP_NO_ERROR != endpoint.Load(mStorage))
     993              :         {
     994            5 :             break;
     995              :         }
     996           26 :         TEMPORARY_RETURN_IGNORED endpoint.Delete(mStorage);
     997           26 :         endpoint.endpoint_id = endpoint.next;
     998              :     }
     999              : 
    1000           32 :     ReturnErrorOnFailure(group.Delete(mStorage));
    1001           32 :     if (group.first)
    1002              :     {
    1003              :         // Remove first group
    1004           13 :         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           32 :     if (fabric.group_count > 0)
    1015              :     {
    1016           32 :         fabric.group_count--;
    1017              :     }
    1018              :     // Update fabric info
    1019           32 :     ReturnErrorOnFailure(fabric.Save(mStorage));
    1020           32 :     GroupRemoved(fabric_index, group);
    1021           32 :     return CHIP_NO_ERROR;
    1022           32 : }
    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          116 :     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          227 : CHIP_ERROR GroupDataProviderImpl::AddEndpoint(chip::FabricIndex fabric_index, chip::GroupId group_id, chip::EndpointId endpoint_id)
    1038              : {
    1039          227 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1040              : 
    1041          227 :     FabricData fabric(fabric_index);
    1042          227 :     GroupData group;
    1043              : 
    1044              :     // Load fabric data (defaults to zero)
    1045          227 :     CHIP_ERROR err = fabric.Load(mStorage);
    1046          458 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
    1047              : 
    1048          227 :     if (!group.Find(mStorage, fabric, group_id))
    1049              :     {
    1050              :         // New group
    1051            9 :         VerifyOrReturnError(fabric.group_count < mMaxGroupsPerFabric, CHIP_ERROR_INVALID_LIST_LENGTH);
    1052            9 :         ReturnErrorOnFailure(EndpointData(fabric_index, group_id, endpoint_id).Save(mStorage));
    1053              :         // Save the new group into the fabric
    1054            9 :         group.group_id       = group_id;
    1055            9 :         group.name[0]        = 0;
    1056            9 :         group.first_endpoint = endpoint_id;
    1057            9 :         group.endpoint_count = 1;
    1058            9 :         group.next           = fabric.first_group;
    1059            9 :         group.prev           = kUndefinedGroupId;
    1060            9 :         ReturnErrorOnFailure(group.Save(mStorage));
    1061              :         // Update fabric
    1062            9 :         fabric.first_group = group.group_id;
    1063            9 :         fabric.group_count++;
    1064            9 :         ReturnErrorOnFailure(fabric.Save(mStorage));
    1065            9 :         GroupAdded(fabric_index, group);
    1066            9 :         return CHIP_NO_ERROR;
    1067              :     }
    1068              : 
    1069              :     // Existing group
    1070          218 :     EndpointData endpoint;
    1071          218 :     VerifyOrReturnError(!endpoint.Find(mStorage, fabric, group, endpoint_id), CHIP_NO_ERROR);
    1072              : 
    1073              :     // New endpoint, insert last
    1074          218 :     endpoint.endpoint_id = endpoint_id;
    1075          218 :     ReturnErrorOnFailure(endpoint.Save(mStorage));
    1076          218 :     if (endpoint.first)
    1077              :     {
    1078              :         // First endpoint of group
    1079          189 :         group.first_endpoint = endpoint.endpoint_id;
    1080              :     }
    1081              :     else
    1082              :     {
    1083              :         // Previous endpoint(s)
    1084           29 :         ReturnErrorOnFailure(endpoint.Save(mStorage));
    1085           29 :         EndpointData prev(fabric_index, group.group_id, endpoint.prev);
    1086           29 :         ReturnErrorOnFailure(prev.Load(mStorage));
    1087           29 :         prev.next = endpoint.endpoint_id;
    1088           29 :         ReturnErrorOnFailure(prev.Save(mStorage));
    1089           29 :     }
    1090          218 :     group.endpoint_count++;
    1091          218 :     return group.Save(mStorage);
    1092          227 : }
    1093              : 
    1094           12 : CHIP_ERROR GroupDataProviderImpl::RemoveEndpoint(chip::FabricIndex fabric_index, chip::GroupId group_id,
    1095              :                                                  chip::EndpointId endpoint_id)
    1096              : {
    1097           12 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1098              : 
    1099           12 :     FabricData fabric(fabric_index);
    1100           12 :     GroupData group;
    1101           12 :     EndpointData endpoint;
    1102              : 
    1103           12 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1104           12 :     VerifyOrReturnError(group.Find(mStorage, fabric, group_id), CHIP_ERROR_NOT_FOUND);
    1105           11 :     VerifyOrReturnError(endpoint.Find(mStorage, fabric, group, endpoint_id), CHIP_ERROR_NOT_FOUND);
    1106              : 
    1107              :     // Existing endpoint
    1108           10 :     TEMPORARY_RETURN_IGNORED endpoint.Delete(mStorage);
    1109              : 
    1110           10 :     if (endpoint.first)
    1111              :     {
    1112              :         // Remove first
    1113            7 :         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           10 :     if (group.endpoint_count > 1)
    1125              :     {
    1126            5 :         group.endpoint_count--;
    1127            5 :         return group.Save(mStorage);
    1128              :     }
    1129              : 
    1130              :     // No more endpoints, remove the group
    1131            5 :     return RemoveGroupInfoAt(fabric_index, group.index);
    1132           12 : }
    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            8 :         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            7 : GroupDataProvider::GroupInfoIterator * GroupDataProviderImpl::IterateGroupInfo(chip::FabricIndex fabric_index)
    1167              : {
    1168            7 :     VerifyOrReturnError(IsInitialized(), nullptr);
    1169            7 :     return mGroupInfoIterators.CreateObject(*this, fabric_index);
    1170              : }
    1171              : 
    1172            7 : GroupDataProviderImpl::GroupInfoIteratorImpl::GroupInfoIteratorImpl(GroupDataProviderImpl & provider,
    1173            7 :                                                                     chip::FabricIndex fabric_index) :
    1174            7 :     mProvider(provider),
    1175            7 :     mFabric(fabric_index)
    1176              : {
    1177            7 :     FabricData fabric(fabric_index);
    1178           14 :     if (CHIP_NO_ERROR == fabric.Load(provider.mStorage))
    1179              :     {
    1180            6 :         mNextId = fabric.first_group;
    1181            6 :         mTotal  = fabric.group_count;
    1182            6 :         mCount  = 0;
    1183              :     }
    1184            7 : }
    1185              : 
    1186            4 : size_t GroupDataProviderImpl::GroupInfoIteratorImpl::Count()
    1187              : {
    1188            4 :     return mTotal;
    1189              : }
    1190              : 
    1191           13 : bool GroupDataProviderImpl::GroupInfoIteratorImpl::Next(GroupInfo & output)
    1192              : {
    1193           13 :     VerifyOrReturnError(mCount < mTotal, false);
    1194              : 
    1195            9 :     GroupData group(mFabric, mNextId);
    1196           18 :     VerifyOrReturnError(CHIP_NO_ERROR == group.Load(mProvider.mStorage), false);
    1197              : 
    1198            9 :     mCount++;
    1199            9 :     mNextId         = group.next;
    1200            9 :     output.group_id = group.group_id;
    1201            9 :     output.SetName(group.name);
    1202            9 :     return true;
    1203            9 : }
    1204              : 
    1205            7 : void GroupDataProviderImpl::GroupInfoIteratorImpl::Release()
    1206              : {
    1207            7 :     mProvider.mGroupInfoIterators.ReleaseObject(this);
    1208            7 : }
    1209              : 
    1210            7 : GroupDataProvider::EndpointIterator * GroupDataProviderImpl::IterateEndpoints(chip::FabricIndex fabric_index,
    1211              :                                                                               std::optional<GroupId> group_id)
    1212              : {
    1213            7 :     VerifyOrReturnError(IsInitialized(), nullptr);
    1214            7 :     return mEndpointIterators.CreateObject(*this, fabric_index, group_id);
    1215              : }
    1216              : 
    1217            7 : GroupDataProviderImpl::EndpointIteratorImpl::EndpointIteratorImpl(GroupDataProviderImpl & provider, chip::FabricIndex fabric_index,
    1218            7 :                                                                   std::optional<GroupId> group_id) :
    1219            7 :     mProvider(provider),
    1220            7 :     mFabric(fabric_index)
    1221              : {
    1222            7 :     FabricData fabric(fabric_index);
    1223           14 :     VerifyOrReturn(CHIP_NO_ERROR == fabric.Load(provider.mStorage));
    1224              : 
    1225            6 :     if (group_id.has_value())
    1226              :     {
    1227            4 :         GroupData group(fabric_index, *group_id);
    1228            8 :         VerifyOrReturn(CHIP_NO_ERROR == group.Load(provider.mStorage));
    1229              : 
    1230            3 :         mGroup         = *group_id;
    1231            3 :         mFirstGroup    = *group_id;
    1232            3 :         mGroupCount    = 1;
    1233            3 :         mEndpoint      = group.first_endpoint;
    1234            3 :         mEndpointCount = group.endpoint_count;
    1235            4 :     }
    1236              :     else
    1237              :     {
    1238            2 :         GroupData group(fabric_index, fabric.first_group);
    1239            4 :         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            7 : }
    1248              : 
    1249            9 : size_t GroupDataProviderImpl::EndpointIteratorImpl::Count()
    1250              : {
    1251            9 :     GroupData group(mFabric, mFirstGroup);
    1252            9 :     size_t group_index    = 0;
    1253            9 :     size_t endpoint_index = 0;
    1254            9 :     size_t count          = 0;
    1255              : 
    1256           18 :     while (group_index++ < mGroupCount)
    1257              :     {
    1258           18 :         if (CHIP_NO_ERROR != group.Load(mProvider.mStorage))
    1259              :         {
    1260            0 :             break;
    1261              :         }
    1262            9 :         EndpointData endpoint(mFabric, group.group_id, group.first_endpoint);
    1263           35 :         while (endpoint_index++ < group.endpoint_count)
    1264              :         {
    1265           52 :             if (CHIP_NO_ERROR != endpoint.Load(mProvider.mStorage))
    1266              :             {
    1267            0 :                 break;
    1268              :             }
    1269           26 :             endpoint.endpoint_id = endpoint.next;
    1270           26 :             count++;
    1271              :         }
    1272            9 :         group.group_id = group.next;
    1273            9 :         endpoint_index = 0;
    1274            9 :     }
    1275           18 :     return count;
    1276            9 : }
    1277              : 
    1278           13 : bool GroupDataProviderImpl::EndpointIteratorImpl::Next(GroupEndpoint & output)
    1279              : {
    1280           16 :     while (mGroupIndex < mGroupCount)
    1281              :     {
    1282           14 :         GroupData group(mFabric, mGroup);
    1283           28 :         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           22 :             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            7 : void GroupDataProviderImpl::EndpointIteratorImpl::Release()
    1315              : {
    1316            7 :     mProvider.mEndpointIterators.ReleaseObject(this);
    1317            7 : }
    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            2 :     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 :         TEMPORARY_RETURN_IGNORED 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          222 : CHIP_ERROR GroupDataProviderImpl::SetGroupKeyAt(chip::FabricIndex fabric_index, size_t index, const GroupKey & in_map)
    1350              : {
    1351          222 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1352              : 
    1353          222 :     FabricData fabric(fabric_index);
    1354          222 :     KeyMapData map(fabric_index);
    1355              : 
    1356              :     // Load fabric, defaults to zero
    1357          222 :     CHIP_ERROR err = fabric.Load(mStorage);
    1358          452 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
    1359              : 
    1360              :     // If the group exists, the index must match
    1361          222 :     bool found = map.Find(mStorage, fabric, in_map);
    1362          222 :     VerifyOrReturnError(!found || (map.index == index), CHIP_ERROR_DUPLICATE_KEY_ID);
    1363              : 
    1364          217 :     found         = map.Get(mStorage, fabric, index);
    1365          217 :     map.group_id  = in_map.group_id;
    1366          217 :     map.keyset_id = in_map.keyset_id;
    1367              : 
    1368          217 :     if (found)
    1369              :     {
    1370              :         // Update existing map
    1371            6 :         return map.Save(mStorage);
    1372              :     }
    1373              : 
    1374              :     // Insert last
    1375          211 :     VerifyOrReturnError(fabric.map_count == index, CHIP_ERROR_INVALID_ARGUMENT);
    1376          210 :     VerifyOrReturnError(fabric.map_count < mMaxGroupsPerFabric, CHIP_ERROR_INVALID_LIST_LENGTH);
    1377              : 
    1378          209 :     map.next = 0;
    1379          209 :     ReturnErrorOnFailure(map.Save(mStorage));
    1380              : 
    1381          209 :     if (map.first)
    1382              :     {
    1383              :         // First map, update fabric
    1384           70 :         fabric.first_map = map.id;
    1385              :     }
    1386              :     else
    1387              :     {
    1388              :         // Last map, update previous
    1389          139 :         KeyMapData prev(fabric_index, map.prev);
    1390          139 :         ReturnErrorOnFailure(prev.Load(mStorage));
    1391          139 :         prev.next = map.id;
    1392          139 :         ReturnErrorOnFailure(prev.Save(mStorage));
    1393          139 :     }
    1394              :     // Update fabric
    1395          209 :     fabric.map_count++;
    1396          209 :     return fabric.Save(mStorage);
    1397          222 : }
    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            4 : CHIP_ERROR GroupDataProviderImpl::RemoveGroupKeys(chip::FabricIndex fabric_index)
    1448              : {
    1449            4 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1450              : 
    1451            4 :     FabricData fabric(fabric_index);
    1452            8 :     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            6 :         if (CHIP_NO_ERROR != map.Load(mStorage))
    1459              :         {
    1460            0 :             break;
    1461              :         }
    1462            3 :         TEMPORARY_RETURN_IGNORED 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            4 : }
    1471              : 
    1472            5 : GroupDataProvider::GroupKeyIterator * GroupDataProviderImpl::IterateGroupKeys(chip::FabricIndex fabric_index)
    1473              : {
    1474            5 :     VerifyOrReturnError(IsInitialized(), nullptr);
    1475            5 :     return mGroupKeyIterators.CreateObject(*this, fabric_index);
    1476              : }
    1477              : 
    1478            5 : GroupDataProviderImpl::GroupKeyIteratorImpl::GroupKeyIteratorImpl(GroupDataProviderImpl & provider,
    1479            5 :                                                                   chip::FabricIndex fabric_index) :
    1480            5 :     mProvider(provider),
    1481            5 :     mFabric(fabric_index)
    1482              : {
    1483            5 :     FabricData fabric(fabric_index);
    1484           10 :     if (CHIP_NO_ERROR == fabric.Load(provider.mStorage))
    1485              :     {
    1486            5 :         mNextId = fabric.first_map;
    1487            5 :         mTotal  = fabric.map_count;
    1488            5 :         mCount  = 0;
    1489              :     }
    1490            5 : }
    1491              : 
    1492            7 : size_t GroupDataProviderImpl::GroupKeyIteratorImpl::Count()
    1493              : {
    1494            7 :     return mTotal;
    1495              : }
    1496              : 
    1497           19 : bool GroupDataProviderImpl::GroupKeyIteratorImpl::Next(GroupKey & output)
    1498              : {
    1499           19 :     VerifyOrReturnError(mCount < mTotal, false);
    1500              : 
    1501           14 :     KeyMapData map(mFabric, mNextId);
    1502           28 :     VerifyOrReturnError(CHIP_NO_ERROR == map.Load(mProvider.mStorage), false);
    1503              : 
    1504           14 :     mCount++;
    1505           14 :     mNextId          = map.next;
    1506           14 :     output.group_id  = map.group_id;
    1507           14 :     output.keyset_id = map.keyset_id;
    1508           14 :     return true;
    1509           14 : }
    1510              : 
    1511            5 : void GroupDataProviderImpl::GroupKeyIteratorImpl::Release()
    1512              : {
    1513            5 :     mProvider.mGroupKeyIterators.ReleaseObject(this);
    1514            5 : }
    1515              : 
    1516              : //
    1517              : // Key Sets
    1518              : //
    1519              : 
    1520              : constexpr size_t GroupDataProvider::EpochKey::kLengthBytes;
    1521              : 
    1522          219 : CHIP_ERROR GroupDataProviderImpl::SetKeySet(chip::FabricIndex fabric_index, const ByteSpan & compressed_fabric_id,
    1523              :                                             const KeySet & in_keyset)
    1524              : {
    1525          219 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1526              : 
    1527          219 :     FabricData fabric(fabric_index);
    1528          219 :     KeySetData keyset;
    1529              : 
    1530              :     // Load fabric, defaults to zero
    1531          219 :     CHIP_ERROR err = fabric.Load(mStorage);
    1532          448 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
    1533              : 
    1534              :     // Search existing keyset
    1535          219 :     bool found = keyset.Find(mStorage, fabric, in_keyset.keyset_id);
    1536              : 
    1537          219 :     keyset.keyset_id  = in_keyset.keyset_id;
    1538          219 :     keyset.policy     = in_keyset.policy;
    1539          219 :     keyset.keys_count = in_keyset.num_keys_used;
    1540          219 :     memset(keyset.operational_keys, 0x00, sizeof(keyset.operational_keys));
    1541          219 :     keyset.operational_keys[0].start_time = in_keyset.epoch_keys[0].start_time;
    1542          219 :     keyset.operational_keys[1].start_time = in_keyset.epoch_keys[1].start_time;
    1543          219 :     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          829 :     for (size_t i = 0; i < in_keyset.num_keys_used; ++i)
    1547              :     {
    1548          610 :         ByteSpan epoch_key(in_keyset.epoch_keys[i].key, Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES);
    1549          610 :         ReturnErrorOnFailure(
    1550              :             Crypto::DeriveGroupOperationalCredentials(epoch_key, compressed_fabric_id, keyset.operational_keys[i]));
    1551              :     }
    1552              : 
    1553          219 :     if (found)
    1554              :     {
    1555              :         // Update existing keyset info, keep next
    1556            5 :         return keyset.Save(mStorage);
    1557              :     }
    1558              : 
    1559              :     // New keyset
    1560          214 :     VerifyOrReturnError(fabric.keyset_count < mMaxGroupKeysPerFabric, CHIP_ERROR_INVALID_LIST_LENGTH);
    1561              : 
    1562              :     // Insert first
    1563          213 :     keyset.next = fabric.first_keyset;
    1564          213 :     ReturnErrorOnFailure(keyset.Save(mStorage));
    1565              :     // Update fabric
    1566          213 :     fabric.keyset_count++;
    1567          213 :     fabric.first_keyset = in_keyset.keyset_id;
    1568          213 :     return fabric.Save(mStorage);
    1569          219 : }
    1570              : 
    1571           38 : CHIP_ERROR GroupDataProviderImpl::GetKeySet(chip::FabricIndex fabric_index, uint16_t target_id, KeySet & out_keyset)
    1572              : {
    1573           38 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1574              : 
    1575           38 :     FabricData fabric(fabric_index);
    1576           38 :     KeySetData keyset;
    1577              : 
    1578           38 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1579           35 :     VerifyOrReturnError(keyset.Find(mStorage, fabric, target_id), CHIP_ERROR_NOT_FOUND);
    1580              : 
    1581              :     // Target keyset found
    1582           24 :     out_keyset.ClearKeys();
    1583           24 :     out_keyset.keyset_id     = keyset.keyset_id;
    1584           24 :     out_keyset.policy        = keyset.policy;
    1585           24 :     out_keyset.num_keys_used = keyset.keys_count;
    1586              :     // Epoch keys are not read back, only start times
    1587           24 :     out_keyset.epoch_keys[0].start_time = keyset.operational_keys[0].start_time;
    1588           24 :     out_keyset.epoch_keys[1].start_time = keyset.operational_keys[1].start_time;
    1589           24 :     out_keyset.epoch_keys[2].start_time = keyset.operational_keys[2].start_time;
    1590              : 
    1591           24 :     return CHIP_NO_ERROR;
    1592           38 : }
    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 :         TEMPORARY_RETURN_IGNORED 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 :         TEMPORARY_RETURN_IGNORED 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            4 :     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           14 :     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           50 :     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 :         TEMPORARY_RETURN_IGNORED 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 :         TEMPORARY_RETURN_IGNORED 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           30 :         if (CHIP_NO_ERROR != keyset.Load(mStorage))
    1728              :         {
    1729            0 :             break;
    1730              :         }
    1731           15 :         TEMPORARY_RETURN_IGNORED 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            4 : Crypto::SymmetricKeyContext * GroupDataProviderImpl::GetKeyContext(FabricIndex fabric_index, GroupId group_id)
    1745              : {
    1746            4 :     FabricData fabric(fabric_index);
    1747            8 :     VerifyOrReturnError(CHIP_NO_ERROR == fabric.Load(mStorage), nullptr);
    1748              : 
    1749            4 :     KeyMapData mapping(fabric.fabric_index, fabric.first_map);
    1750              : 
    1751              :     // Look for the target group in the fabric's keyset-group pairs
    1752            4 :     for (uint16_t i = 0; i < fabric.map_count; ++i, mapping.id = mapping.next)
    1753              :     {
    1754            8 :         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            4 :         if (mapping.keyset_id > 0 && mapping.group_id == group_id)
    1758              :         {
    1759              :             // Group found, get the keyset
    1760            4 :             KeySetData keyset;
    1761            4 :             VerifyOrReturnError(keyset.Find(mStorage, fabric, mapping.keyset_id), nullptr);
    1762            4 :             Crypto::GroupOperationalCredentials * creds = keyset.GetCurrentGroupCredentials();
    1763            4 :             if (nullptr != creds)
    1764              :             {
    1765            4 :                 return mGroupKeyContexPool.CreateObject(*this, creds->encryption_key, creds->hash, creds->privacy_key);
    1766              :             }
    1767            4 :         }
    1768              :     }
    1769            0 :     return nullptr;
    1770            4 : }
    1771              : 
    1772           30 : CHIP_ERROR GroupDataProviderImpl::GetIpkKeySet(FabricIndex fabric_index, KeySet & out_keyset)
    1773              : {
    1774           30 :     FabricData fabric(fabric_index);
    1775           60 :     VerifyOrReturnError(CHIP_NO_ERROR == fabric.Load(mStorage), CHIP_ERROR_NOT_FOUND);
    1776              : 
    1777           29 :     KeyMapData mapping(fabric.fabric_index, fabric.first_map);
    1778              : 
    1779              :     // Fabric found, get the keyset
    1780           29 :     KeySetData keyset;
    1781           29 :     VerifyOrReturnError(keyset.Find(mStorage, fabric, kIdentityProtectionKeySetId), CHIP_ERROR_NOT_FOUND);
    1782              : 
    1783              :     // If the keyset ID doesn't match, we have a ... problem.
    1784           27 :     VerifyOrReturnError(keyset.keyset_id == kIdentityProtectionKeySetId, CHIP_ERROR_INTERNAL);
    1785              : 
    1786           27 :     out_keyset.keyset_id     = keyset.keyset_id;
    1787           27 :     out_keyset.num_keys_used = keyset.keys_count;
    1788           27 :     out_keyset.policy        = keyset.policy;
    1789              : 
    1790          108 :     for (size_t key_idx = 0; key_idx < MATTER_ARRAY_SIZE(out_keyset.epoch_keys); ++key_idx)
    1791              :     {
    1792           81 :         out_keyset.epoch_keys[key_idx].Clear();
    1793           81 :         if (key_idx < keyset.keys_count)
    1794              :         {
    1795           27 :             out_keyset.epoch_keys[key_idx].start_time = keyset.operational_keys[key_idx].start_time;
    1796           27 :             memcpy(&out_keyset.epoch_keys[key_idx].key[0], keyset.operational_keys[key_idx].encryption_key, EpochKey::kLengthBytes);
    1797              :         }
    1798              :     }
    1799              : 
    1800           27 :     return CHIP_NO_ERROR;
    1801           30 : }
    1802              : 
    1803            4 : void GroupDataProviderImpl::GroupKeyContext::Release()
    1804              : {
    1805            4 :     ReleaseKeys();
    1806            4 :     mProvider.mGroupKeyContexPool.ReleaseObject(this);
    1807            4 : }
    1808              : 
    1809            4 : CHIP_ERROR GroupDataProviderImpl::GroupKeyContext::MessageEncrypt(const ByteSpan & plaintext, const ByteSpan & aad,
    1810              :                                                                   const ByteSpan & nonce, MutableByteSpan & mic,
    1811              :                                                                   MutableByteSpan & ciphertext) const
    1812              : {
    1813            4 :     uint8_t * output = ciphertext.data();
    1814            4 :     return Crypto::AES_CCM_encrypt(plaintext.data(), plaintext.size(), aad.data(), aad.size(), mEncryptionKey, nonce.data(),
    1815            4 :                                    nonce.size(), output, mic.data(), mic.size());
    1816              : }
    1817              : 
    1818            8 : CHIP_ERROR GroupDataProviderImpl::GroupKeyContext::MessageDecrypt(const ByteSpan & ciphertext, const ByteSpan & aad,
    1819              :                                                                   const ByteSpan & nonce, const ByteSpan & mic,
    1820              :                                                                   MutableByteSpan & plaintext) const
    1821              : {
    1822            8 :     uint8_t * output = plaintext.data();
    1823           16 :     return Crypto::AES_CCM_decrypt(ciphertext.data(), ciphertext.size(), aad.data(), aad.size(), mic.data(), mic.size(),
    1824           16 :                                    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            9 : GroupDataProviderImpl::GroupSessionIterator * GroupDataProviderImpl::IterateGroupSessions(uint16_t session_id)
    1840              : {
    1841            9 :     VerifyOrReturnError(IsInitialized(), nullptr);
    1842            9 :     return mGroupSessionsIterator.CreateObject(*this, session_id);
    1843              : }
    1844              : 
    1845            9 : GroupDataProviderImpl::GroupSessionIteratorImpl::GroupSessionIteratorImpl(GroupDataProviderImpl & provider, uint16_t session_id) :
    1846            9 :     mProvider(provider), mSessionId(session_id), mGroupKeyContext(provider)
    1847              : {
    1848            9 :     FabricList fabric_list;
    1849            9 :     ReturnOnFailure(fabric_list.Load(provider.mStorage));
    1850            9 :     mFirstFabric = fabric_list.first_entry;
    1851            9 :     mFabric      = fabric_list.first_entry;
    1852            9 :     mFabricCount = 0;
    1853            9 :     mFabricTotal = fabric_list.entry_count;
    1854            9 :     mMapCount    = 0;
    1855            9 :     mFirstMap    = true;
    1856            9 : }
    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            4 :         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           12 :             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           11 : bool GroupDataProviderImpl::GroupSessionIteratorImpl::Next(GroupSession & output)
    1900              : {
    1901           37 :     while (mFabricCount < mFabricTotal)
    1902              :     {
    1903           35 :         FabricData fabric(mFabric);
    1904           70 :         VerifyOrReturnError(CHIP_NO_ERROR == fabric.Load(mProvider.mStorage), false);
    1905              : 
    1906           35 :         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           32 :         if (mFirstMap)
    1917              :         {
    1918           10 :             mMapping  = fabric.first_map;
    1919           10 :             mFirstMap = false;
    1920              :         }
    1921              : 
    1922           32 :         KeyMapData mapping(mFabric, mMapping);
    1923           64 :         VerifyOrReturnError(CHIP_NO_ERROR == mapping.Load(mProvider.mStorage), false);
    1924              : 
    1925              :         // Group found, get the keyset
    1926           32 :         KeySetData keyset;
    1927           32 :         VerifyOrReturnError(keyset.Find(mProvider.mStorage, fabric, mapping.keyset_id), false);
    1928              : 
    1929           32 :         if (mKeyIndex >= keyset.keys_count || (mKeyIndex >= KeySet::kEpochKeysMax))
    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           25 :         Crypto::GroupOperationalCredentials & creds = keyset.operational_keys[mKeyIndex++];
    1939           25 :         if (creds.hash == mSessionId)
    1940              :         {
    1941            9 :             TEMPORARY_RETURN_IGNORED mGroupKeyContext.Initialize(creds.encryption_key, mSessionId, creds.privacy_key);
    1942            9 :             output.fabric_index    = fabric.fabric_index;
    1943            9 :             output.group_id        = mapping.group_id;
    1944            9 :             output.security_policy = keyset.policy;
    1945            9 :             output.keyContext      = &mGroupKeyContext;
    1946            9 :             return true;
    1947              :         }
    1948           67 :     }
    1949              : 
    1950            2 :     return false;
    1951              : }
    1952              : 
    1953            9 : void GroupDataProviderImpl::GroupSessionIteratorImpl::Release()
    1954              : {
    1955            9 :     mGroupKeyContext.ReleaseKeys();
    1956            9 :     mProvider.mGroupSessionsIterator.ReleaseObject(this);
    1957            9 : }
    1958              : 
    1959              : namespace {
    1960              : 
    1961              : GroupDataProvider * gGroupsProvider = nullptr;
    1962              : 
    1963              : } // namespace
    1964              : 
    1965           93 : GroupDataProvider * GetGroupDataProvider()
    1966              : {
    1967           93 :     return gGroupsProvider;
    1968              : }
    1969              : 
    1970          128 : void SetGroupDataProvider(GroupDataProvider * provider)
    1971              : {
    1972          128 :     gGroupsProvider = provider;
    1973          128 : }
    1974              : 
    1975              : } // namespace Credentials
    1976              : } // namespace chip
        

Generated by: LCOV version 2.0-1