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

Generated by: LCOV version 2.0-1