Matter SDK Coverage Report
Current view: top level - credentials - LastKnownGoodTime.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 96.8 % 93 90
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 8 8

            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              : 
      18              : /**
      19              :  * @brief Defines a table of fabrics that have provisioned the device.
      20              :  */
      21              : 
      22              : #include "LastKnownGoodTime.h"
      23              : 
      24              : #include <lib/support/BufferWriter.h>
      25              : #include <lib/support/DefaultStorageKeyAllocator.h>
      26              : #include <lib/support/SafeInt.h>
      27              : #include <platform/ConfigurationManager.h>
      28              : 
      29              : namespace chip {
      30              : 
      31              : namespace {
      32              : // Tags for Last Known Good Time.
      33              : constexpr TLV::Tag kLastKnownGoodChipEpochSecondsTag = TLV::ContextTag(0);
      34              : } // anonymous namespace
      35              : 
      36         3433 : void LastKnownGoodTime::LogTime(const char * msg, System::Clock::Seconds32 chipEpochTime)
      37              : {
      38              : #if CHIP_PROGRESS_LOGGING
      39         3433 :     char buf[26] = { 0 }; // strlen("00000-000-000T000:000:000") == 25
      40              :     uint16_t year;
      41              :     uint8_t month;
      42              :     uint8_t day;
      43              :     uint8_t hour;
      44              :     uint8_t minute;
      45              :     uint8_t second;
      46         3433 :     ChipEpochToCalendarTime(chipEpochTime.count(), year, month, day, hour, minute, second);
      47         3433 :     snprintf(buf, sizeof(buf), "%04u-%02u-%02uT%02u:%02u:%02u", year, month, day, hour, minute, second);
      48         3433 :     ChipLogProgress(TimeService, "%s%s", StringOrNullMarker(msg), buf);
      49              : #else
      50              :     IgnoreUnusedVariable(msg);
      51              :     IgnoreUnusedVariable(chipEpochTime);
      52              : #endif
      53         3433 : }
      54              : 
      55          835 : CHIP_ERROR LastKnownGoodTime::LoadLastKnownGoodChipEpochTime(System::Clock::Seconds32 & lastKnownGoodChipEpochTime) const
      56              : {
      57              :     uint8_t buf[LastKnownGoodTimeTLVMaxSize()];
      58          835 :     uint16_t size = sizeof(buf);
      59              :     uint32_t seconds;
      60          835 :     ReturnErrorOnFailure(mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::LastKnownGoodTimeKey().KeyName(), buf, size));
      61          445 :     TLV::ContiguousBufferTLVReader reader;
      62          445 :     reader.Init(buf, size);
      63          445 :     ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag()));
      64              :     TLV::TLVType containerType;
      65          445 :     ReturnErrorOnFailure(reader.EnterContainer(containerType));
      66          445 :     ReturnErrorOnFailure(reader.Next(kLastKnownGoodChipEpochSecondsTag));
      67          445 :     ReturnErrorOnFailure(reader.Get(seconds));
      68          445 :     lastKnownGoodChipEpochTime = System::Clock::Seconds32(seconds);
      69          445 :     return CHIP_NO_ERROR;
      70              : }
      71              : 
      72         1096 : CHIP_ERROR LastKnownGoodTime::StoreLastKnownGoodChipEpochTime(System::Clock::Seconds32 lastKnownGoodChipEpochTime) const
      73              : {
      74              :     uint8_t buf[LastKnownGoodTimeTLVMaxSize()];
      75         1096 :     TLV::TLVWriter writer;
      76         1096 :     writer.Init(buf);
      77              :     TLV::TLVType outerType;
      78         1096 :     ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerType));
      79         1096 :     ReturnErrorOnFailure(writer.Put(kLastKnownGoodChipEpochSecondsTag, lastKnownGoodChipEpochTime.count()));
      80         1096 :     ReturnErrorOnFailure(writer.EndContainer(outerType));
      81         1096 :     const auto length = writer.GetLengthWritten();
      82         1096 :     VerifyOrReturnError(CanCastTo<uint16_t>(length), CHIP_ERROR_BUFFER_TOO_SMALL);
      83         1096 :     ReturnErrorOnFailure(mStorage->SyncSetKeyValue(DefaultStorageKeyAllocator::LastKnownGoodTimeKey().KeyName(), buf,
      84              :                                                    static_cast<uint16_t>(length)));
      85         1096 :     return CHIP_NO_ERROR;
      86              : }
      87              : 
      88          407 : CHIP_ERROR LastKnownGoodTime::Init(PersistentStorageDelegate * storage)
      89              : {
      90          407 :     CHIP_ERROR err = CHIP_NO_ERROR;
      91          407 :     mStorage       = storage;
      92              :     // 3.5.6.1 Last Known Good UTC Time:
      93              :     //
      94              :     // "A Node’s initial out-of-box Last Known Good UTC time SHALL be the
      95              :     // compile-time of the firmware."
      96              :     System::Clock::Seconds32 buildTime;
      97          407 :     SuccessOrExit(err = DeviceLayer::ConfigurationMgr().GetFirmwareBuildChipEpochTime(buildTime));
      98              :     System::Clock::Seconds32 storedLastKnownGoodChipEpochTime;
      99          407 :     err = LoadLastKnownGoodChipEpochTime(storedLastKnownGoodChipEpochTime);
     100          407 :     VerifyOrExit(err == CHIP_NO_ERROR || err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND, ;);
     101          407 :     if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
     102              :     {
     103          388 :         ChipLogProgress(TimeService, "Last Known Good Time: [unknown]");
     104              :     }
     105              :     else
     106              :     {
     107           19 :         LogTime("Last Known Good Time: ", storedLastKnownGoodChipEpochTime);
     108              :     }
     109          407 :     if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND || buildTime > storedLastKnownGoodChipEpochTime)
     110              :     {
     111              :         // If we have no value in persistence, or the firmware build time is
     112              :         // later than the value in persistence, set last known good time to the
     113              :         // firmware build time and write back.
     114          388 :         LogTime("Setting Last Known Good Time to firmware build time ", buildTime);
     115          388 :         mLastKnownGoodChipEpochTime.SetValue(buildTime);
     116          388 :         SuccessOrExit(err = StoreLastKnownGoodChipEpochTime(buildTime));
     117              :     }
     118              :     else
     119              :     {
     120           19 :         mLastKnownGoodChipEpochTime.SetValue(storedLastKnownGoodChipEpochTime);
     121              :     }
     122          407 : exit:
     123          407 :     if (err != CHIP_NO_ERROR)
     124              :     {
     125            0 :         ChipLogError(TimeService, "Failed to init Last Known Good Time: %" CHIP_ERROR_FORMAT, err.Format());
     126              :     }
     127          407 :     return err;
     128              : }
     129              : 
     130            8 : CHIP_ERROR LastKnownGoodTime::SetLastKnownGoodChipEpochTime(System::Clock::Seconds32 lastKnownGoodChipEpochTime,
     131              :                                                             System::Clock::Seconds32 notBefore)
     132              : {
     133            8 :     CHIP_ERROR err = CHIP_NO_ERROR;
     134            8 :     VerifyOrExit(mLastKnownGoodChipEpochTime.HasValue(), err = CHIP_ERROR_INCORRECT_STATE);
     135            8 :     LogTime("Last Known Good Time: ", mLastKnownGoodChipEpochTime.Value());
     136            8 :     LogTime("New proposed Last Known Good Time: ", lastKnownGoodChipEpochTime);
     137              : 
     138              :     // Verify that the passed value is not earlier than the firmware build time.
     139              :     System::Clock::Seconds32 buildTime;
     140            8 :     SuccessOrExit(err = DeviceLayer::ConfigurationMgr().GetFirmwareBuildChipEpochTime(buildTime));
     141            8 :     VerifyOrExit(lastKnownGoodChipEpochTime >= buildTime, err = CHIP_ERROR_INVALID_ARGUMENT);
     142              :     // Verify that the passed value is not earlier than the passed NotBefore time.
     143            5 :     VerifyOrExit(lastKnownGoodChipEpochTime >= notBefore, err = CHIP_ERROR_INVALID_ARGUMENT);
     144              : 
     145              :     // Passed value is valid.  Capture it and write back to persistence.
     146              :     //
     147              :     // Note that we are purposefully overwriting any previous last known
     148              :     // good time that may have been stored as part of a fail-safe context.
     149              :     // This is intentional: we don't promise not to change last known good
     150              :     // time during the fail-safe timer.  For instance, if the platform has a
     151              :     // new, better time source, it is legal to capture it.  If we do, we should
     152              :     // both overwrite last known good time and discard the previous value stored
     153              :     // for fail safe recovery, as together these comprise a transaction.  By
     154              :     // overwriting both, we are fully superseding that transaction with our
     155              :     // own, which does not to have a revert feature.
     156            4 :     SuccessOrExit(err = StoreLastKnownGoodChipEpochTime(lastKnownGoodChipEpochTime));
     157            4 :     mLastKnownGoodChipEpochTime.SetValue(lastKnownGoodChipEpochTime);
     158            8 : exit:
     159            8 :     if (err != CHIP_NO_ERROR)
     160              :     {
     161            4 :         ChipLogError(TimeService, "Failed to update Last Known Good Time: %" CHIP_ERROR_FORMAT, err.Format());
     162              :     }
     163              :     else
     164              :     {
     165            4 :         LogTime("Updating Last Known Good Time to ", lastKnownGoodChipEpochTime);
     166              :     }
     167            8 :     return err;
     168              : }
     169              : 
     170          715 : CHIP_ERROR LastKnownGoodTime::UpdatePendingLastKnownGoodChipEpochTime(System::Clock::Seconds32 lastKnownGoodChipEpochTime)
     171              : {
     172          715 :     CHIP_ERROR err = CHIP_NO_ERROR;
     173          715 :     VerifyOrExit(mLastKnownGoodChipEpochTime.HasValue(), err = CHIP_ERROR_INCORRECT_STATE);
     174          715 :     LogTime("Last Known Good Time: ", mLastKnownGoodChipEpochTime.Value());
     175          715 :     LogTime("New proposed Last Known Good Time: ", lastKnownGoodChipEpochTime);
     176          715 :     if (lastKnownGoodChipEpochTime > mLastKnownGoodChipEpochTime.Value())
     177              :     {
     178           18 :         LogTime("Updating pending Last Known Good Time to ", lastKnownGoodChipEpochTime);
     179           18 :         mLastKnownGoodChipEpochTime.SetValue(lastKnownGoodChipEpochTime);
     180              :     }
     181              :     else
     182              :     {
     183          697 :         ChipLogProgress(TimeService, "Retaining current Last Known Good Time");
     184              :     }
     185            0 : exit:
     186          715 :     return err;
     187              : }
     188              : 
     189          704 : CHIP_ERROR LastKnownGoodTime::CommitPendingLastKnownGoodChipEpochTime()
     190              : {
     191          704 :     CHIP_ERROR err = CHIP_NO_ERROR;
     192          704 :     VerifyOrExit(mLastKnownGoodChipEpochTime.HasValue(), err = CHIP_ERROR_INCORRECT_STATE);
     193          704 :     LogTime("Committing Last Known Good Time to storage: ", mLastKnownGoodChipEpochTime.Value());
     194          704 :     SuccessOrExit(err = StoreLastKnownGoodChipEpochTime(mLastKnownGoodChipEpochTime.Value()));
     195          704 : exit:
     196          704 :     if (err != CHIP_NO_ERROR)
     197              :     {
     198            0 :         ChipLogError(TimeService, "Failed to commit Last Known Good Time: %" CHIP_ERROR_FORMAT, err.Format());
     199              :     }
     200          704 :     return err;
     201              : }
     202              : 
     203          428 : CHIP_ERROR LastKnownGoodTime::RevertPendingLastKnownGoodChipEpochTime()
     204              : {
     205          428 :     CHIP_ERROR err = CHIP_NO_ERROR;
     206              :     System::Clock::Seconds32 storedLastKnownGoodChipEpochTime;
     207          428 :     VerifyOrExit(mLastKnownGoodChipEpochTime.HasValue(), err = CHIP_ERROR_INCORRECT_STATE);
     208          428 :     LogTime("Pending Last Known Good Time: ", mLastKnownGoodChipEpochTime.Value());
     209          428 :     SuccessOrExit(err = LoadLastKnownGoodChipEpochTime(storedLastKnownGoodChipEpochTime));
     210          426 :     LogTime("Previous Last Known Good Time: ", storedLastKnownGoodChipEpochTime);
     211          426 :     mLastKnownGoodChipEpochTime.SetValue(storedLastKnownGoodChipEpochTime);
     212          428 : exit:
     213          428 :     if (err != CHIP_NO_ERROR)
     214              :     {
     215              :         // We do not expect to arrive here unless the kvstore broke or some
     216              :         // other code removed our value from persistence.  However, clearing the
     217              :         // in-memory value is the right thing to do for all cases.  This will
     218              :         // prevent other code from consuming an invalid time.
     219            2 :         ChipLogError(TimeService,
     220              :                      "Clearing Last Known Good Time; failed to load a previous value from persistence: %" CHIP_ERROR_FORMAT,
     221              :                      err.Format());
     222            2 :         mLastKnownGoodChipEpochTime.ClearValue();
     223              :     }
     224              :     else
     225              :     {
     226          426 :         ChipLogProgress(TimeService, "Reverted Last Known Good Time to previous value");
     227              :     }
     228          428 :     return err;
     229              : }
     230              : 
     231              : } // namespace chip
        

Generated by: LCOV version 2.0-1