Matter SDK Coverage Report
Current view: top level - credentials - LastKnownGoodTime.cpp (source / functions) Coverage Total Hit
Test: SHA:1560a87972ec2c7a76cec101927a563a6862bc2a Lines: 96.8 % 93 90
Test Date: 2025-03-30 07:08:27 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         3538 : void LastKnownGoodTime::LogTime(const char * msg, System::Clock::Seconds32 chipEpochTime)
      37              : {
      38              : #if CHIP_PROGRESS_LOGGING
      39         3538 :     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         3538 :     ChipEpochToCalendarTime(chipEpochTime.count(), year, month, day, hour, minute, second);
      47         3538 :     snprintf(buf, sizeof(buf), "%04u-%02u-%02uT%02u:%02u:%02u", year, month, day, hour, minute, second);
      48         3538 :     ChipLogProgress(TimeService, "%s%s", StringOrNullMarker(msg), buf);
      49              : #else
      50              :     IgnoreUnusedVariable(msg);
      51              :     IgnoreUnusedVariable(chipEpochTime);
      52              : #endif
      53         3538 : }
      54              : 
      55          871 : CHIP_ERROR LastKnownGoodTime::LoadLastKnownGoodChipEpochTime(System::Clock::Seconds32 & lastKnownGoodChipEpochTime) const
      56              : {
      57              :     uint8_t buf[LastKnownGoodTimeTLVMaxSize()];
      58          871 :     uint16_t size = sizeof(buf);
      59              :     uint32_t seconds;
      60          871 :     ReturnErrorOnFailure(mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::LastKnownGoodTimeKey().KeyName(), buf, size));
      61          464 :     TLV::ContiguousBufferTLVReader reader;
      62          464 :     reader.Init(buf, size);
      63          464 :     ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag()));
      64              :     TLV::TLVType containerType;
      65          464 :     ReturnErrorOnFailure(reader.EnterContainer(containerType));
      66          464 :     ReturnErrorOnFailure(reader.Next(kLastKnownGoodChipEpochSecondsTag));
      67          464 :     ReturnErrorOnFailure(reader.Get(seconds));
      68          464 :     lastKnownGoodChipEpochTime = System::Clock::Seconds32(seconds);
      69          464 :     return CHIP_NO_ERROR;
      70              : }
      71              : 
      72         1129 : CHIP_ERROR LastKnownGoodTime::StoreLastKnownGoodChipEpochTime(System::Clock::Seconds32 lastKnownGoodChipEpochTime) const
      73              : {
      74              :     uint8_t buf[LastKnownGoodTimeTLVMaxSize()];
      75         1129 :     TLV::TLVWriter writer;
      76         1129 :     writer.Init(buf);
      77              :     TLV::TLVType outerType;
      78         1129 :     ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerType));
      79         1129 :     ReturnErrorOnFailure(writer.Put(kLastKnownGoodChipEpochSecondsTag, lastKnownGoodChipEpochTime.count()));
      80         1129 :     ReturnErrorOnFailure(writer.EndContainer(outerType));
      81         1129 :     const auto length = writer.GetLengthWritten();
      82         1129 :     VerifyOrReturnError(CanCastTo<uint16_t>(length), CHIP_ERROR_BUFFER_TOO_SMALL);
      83         1129 :     ReturnErrorOnFailure(mStorage->SyncSetKeyValue(DefaultStorageKeyAllocator::LastKnownGoodTimeKey().KeyName(), buf,
      84              :                                                    static_cast<uint16_t>(length)));
      85         1129 :     return CHIP_NO_ERROR;
      86              : }
      87              : 
      88          425 : CHIP_ERROR LastKnownGoodTime::Init(PersistentStorageDelegate * storage)
      89              : {
      90          425 :     CHIP_ERROR err = CHIP_NO_ERROR;
      91          425 :     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          425 :     SuccessOrExit(err = DeviceLayer::ConfigurationMgr().GetFirmwareBuildChipEpochTime(buildTime));
      98              :     System::Clock::Seconds32 storedLastKnownGoodChipEpochTime;
      99          425 :     err = LoadLastKnownGoodChipEpochTime(storedLastKnownGoodChipEpochTime);
     100          425 :     VerifyOrExit(err == CHIP_NO_ERROR || err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND, ;);
     101          425 :     if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
     102              :     {
     103          405 :         ChipLogProgress(TimeService, "Last Known Good Time: [unknown]");
     104              :     }
     105              :     else
     106              :     {
     107           20 :         LogTime("Last Known Good Time: ", storedLastKnownGoodChipEpochTime);
     108              :     }
     109          425 :     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          405 :         LogTime("Setting Last Known Good Time to firmware build time ", buildTime);
     115          405 :         mLastKnownGoodChipEpochTime.SetValue(buildTime);
     116          405 :         SuccessOrExit(err = StoreLastKnownGoodChipEpochTime(buildTime));
     117              :     }
     118              :     else
     119              :     {
     120           20 :         mLastKnownGoodChipEpochTime.SetValue(storedLastKnownGoodChipEpochTime);
     121              :     }
     122          425 : exit:
     123          425 :     if (err != CHIP_NO_ERROR)
     124              :     {
     125            0 :         ChipLogError(TimeService, "Failed to init Last Known Good Time: %" CHIP_ERROR_FORMAT, err.Format());
     126              :     }
     127          425 :     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          732 : CHIP_ERROR LastKnownGoodTime::UpdatePendingLastKnownGoodChipEpochTime(System::Clock::Seconds32 lastKnownGoodChipEpochTime)
     171              : {
     172          732 :     CHIP_ERROR err = CHIP_NO_ERROR;
     173          732 :     VerifyOrExit(mLastKnownGoodChipEpochTime.HasValue(), err = CHIP_ERROR_INCORRECT_STATE);
     174          732 :     LogTime("Last Known Good Time: ", mLastKnownGoodChipEpochTime.Value());
     175          732 :     LogTime("New proposed Last Known Good Time: ", lastKnownGoodChipEpochTime);
     176          732 :     if (lastKnownGoodChipEpochTime > mLastKnownGoodChipEpochTime.Value())
     177              :     {
     178           19 :         LogTime("Updating pending Last Known Good Time to ", lastKnownGoodChipEpochTime);
     179           19 :         mLastKnownGoodChipEpochTime.SetValue(lastKnownGoodChipEpochTime);
     180              :     }
     181              :     else
     182              :     {
     183          713 :         ChipLogProgress(TimeService, "Retaining current Last Known Good Time");
     184              :     }
     185            0 : exit:
     186          732 :     return err;
     187              : }
     188              : 
     189          720 : CHIP_ERROR LastKnownGoodTime::CommitPendingLastKnownGoodChipEpochTime()
     190              : {
     191          720 :     CHIP_ERROR err = CHIP_NO_ERROR;
     192          720 :     VerifyOrExit(mLastKnownGoodChipEpochTime.HasValue(), err = CHIP_ERROR_INCORRECT_STATE);
     193          720 :     LogTime("Committing Last Known Good Time to storage: ", mLastKnownGoodChipEpochTime.Value());
     194          720 :     SuccessOrExit(err = StoreLastKnownGoodChipEpochTime(mLastKnownGoodChipEpochTime.Value()));
     195          720 : exit:
     196          720 :     if (err != CHIP_NO_ERROR)
     197              :     {
     198            0 :         ChipLogError(TimeService, "Failed to commit Last Known Good Time: %" CHIP_ERROR_FORMAT, err.Format());
     199              :     }
     200          720 :     return err;
     201              : }
     202              : 
     203          447 : CHIP_ERROR LastKnownGoodTime::RevertPendingLastKnownGoodChipEpochTime()
     204              : {
     205          447 :     CHIP_ERROR err = CHIP_NO_ERROR;
     206              :     System::Clock::Seconds32 storedLastKnownGoodChipEpochTime;
     207          447 :     VerifyOrExit(mLastKnownGoodChipEpochTime.HasValue(), err = CHIP_ERROR_INCORRECT_STATE);
     208          446 :     LogTime("Pending Last Known Good Time: ", mLastKnownGoodChipEpochTime.Value());
     209          446 :     SuccessOrExit(err = LoadLastKnownGoodChipEpochTime(storedLastKnownGoodChipEpochTime));
     210          444 :     LogTime("Previous Last Known Good Time: ", storedLastKnownGoodChipEpochTime);
     211          444 :     mLastKnownGoodChipEpochTime.SetValue(storedLastKnownGoodChipEpochTime);
     212          447 : exit:
     213          447 :     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            3 :         ChipLogError(TimeService,
     220              :                      "Clearing Last Known Good Time; failed to load a previous value from persistence: %" CHIP_ERROR_FORMAT,
     221              :                      err.Format());
     222            3 :         mLastKnownGoodChipEpochTime.ClearValue();
     223              :     }
     224              :     else
     225              :     {
     226          444 :         ChipLogProgress(TimeService, "Reverted Last Known Good Time to previous value");
     227              :     }
     228          447 :     return err;
     229              : }
     230              : 
     231              : } // namespace chip
        

Generated by: LCOV version 2.0-1