blob: 37c885e9139b218b4df2573625b4668d6a2534e3 [file] [log] [blame]
/*
*
* Copyright (c) 2022 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* Provides the implementation of the FailSafeContext object.
*/
#include <platform/FailSafeContext.h>
#include <lib/support/DefaultStorageKeyAllocator.h>
#include <lib/support/SafeInt.h>
#include <platform/ConfigurationManager.h>
namespace chip {
namespace DeviceLayer {
namespace {
constexpr TLV::Tag kFabricIndexTag = TLV::ContextTag(0);
constexpr TLV::Tag kAddNocCommandTag = TLV::ContextTag(1);
constexpr TLV::Tag kUpdateNocCommandTag = TLV::ContextTag(2);
} // anonymous namespace
void FailSafeContext::HandleArmFailSafeTimer(System::Layer * layer, void * aAppState)
{
FailSafeContext * context = reinterpret_cast<FailSafeContext *>(aAppState);
context->FailSafeTimerExpired();
}
void FailSafeContext::HandleDisarmFailSafe(intptr_t arg)
{
FailSafeContext * this_ = reinterpret_cast<FailSafeContext *>(arg);
this_->mFailSafeBusy = false;
if (ConfigurationMgr().SetFailSafeArmed(false) != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "Failed to set FailSafeArmed config to false");
}
if (DeleteFromStorage() != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "Failed to delete FailSafeContext from configuration");
}
}
void FailSafeContext::FailSafeTimerExpired()
{
ScheduleFailSafeCleanup(mFabricIndex, mAddNocCommandHasBeenInvoked, mUpdateNocCommandHasBeenInvoked);
}
void FailSafeContext::ScheduleFailSafeCleanup(FabricIndex fabricIndex, bool addNocCommandInvoked, bool updateNocCommandInvoked)
{
mFailSafeArmed = false;
mAddNocCommandHasBeenInvoked = false;
mUpdateNocCommandHasBeenInvoked = false;
mFailSafeBusy = true;
ChipDeviceEvent event;
event.Type = DeviceEventType::kFailSafeTimerExpired;
event.FailSafeTimerExpired.PeerFabricIndex = fabricIndex;
event.FailSafeTimerExpired.AddNocCommandHasBeenInvoked = addNocCommandInvoked;
event.FailSafeTimerExpired.UpdateNocCommandHasBeenInvoked = updateNocCommandInvoked;
CHIP_ERROR status = PlatformMgr().PostEvent(&event);
if (status != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "Failed to post fail-safe timer expired: %" CHIP_ERROR_FORMAT, status.Format());
}
PlatformMgr().ScheduleWork(HandleDisarmFailSafe, reinterpret_cast<intptr_t>(this));
}
CHIP_ERROR FailSafeContext::ArmFailSafe(FabricIndex accessingFabricIndex, System::Clock::Timeout expiryLength)
{
mFailSafeArmed = true;
mFabricIndex = accessingFabricIndex;
ReturnErrorOnFailure(DeviceLayer::SystemLayer().StartTimer(expiryLength, HandleArmFailSafeTimer, this));
ReturnErrorOnFailure(CommitToStorage());
ReturnErrorOnFailure(ConfigurationMgr().SetFailSafeArmed(true));
return CHIP_NO_ERROR;
}
CHIP_ERROR FailSafeContext::DisarmFailSafe()
{
mFailSafeArmed = false;
mAddNocCommandHasBeenInvoked = false;
mUpdateNocCommandHasBeenInvoked = false;
DeviceLayer::SystemLayer().CancelTimer(HandleArmFailSafeTimer, this);
ReturnErrorOnFailure(ConfigurationMgr().SetFailSafeArmed(false));
ReturnErrorOnFailure(DeleteFromStorage());
return CHIP_NO_ERROR;
}
CHIP_ERROR FailSafeContext::SetAddNocCommandInvoked(FabricIndex nocFabricIndex)
{
mAddNocCommandHasBeenInvoked = true;
mFabricIndex = nocFabricIndex;
ReturnErrorOnFailure(CommitToStorage());
return CHIP_NO_ERROR;
}
CHIP_ERROR FailSafeContext::SetUpdateNocCommandInvoked()
{
mUpdateNocCommandHasBeenInvoked = true;
ReturnErrorOnFailure(CommitToStorage());
return CHIP_NO_ERROR;
}
CHIP_ERROR FailSafeContext::CommitToStorage()
{
DefaultStorageKeyAllocator keyAlloc;
uint8_t buf[FailSafeContextTLVMaxSize()];
TLV::TLVWriter writer;
writer.Init(buf);
TLV::TLVType outerType;
ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerType));
ReturnErrorOnFailure(writer.Put(kFabricIndexTag, mFabricIndex));
ReturnErrorOnFailure(writer.Put(kAddNocCommandTag, mAddNocCommandHasBeenInvoked));
ReturnErrorOnFailure(writer.Put(kUpdateNocCommandTag, mUpdateNocCommandHasBeenInvoked));
ReturnErrorOnFailure(writer.EndContainer(outerType));
const auto failSafeContextTLVLength = writer.GetLengthWritten();
VerifyOrReturnError(CanCastTo<uint16_t>(failSafeContextTLVLength), CHIP_ERROR_BUFFER_TOO_SMALL);
return PersistedStorage::KeyValueStoreMgr().Put(keyAlloc.FailSafeContextKey(), buf,
static_cast<uint16_t>(failSafeContextTLVLength));
}
CHIP_ERROR FailSafeContext::LoadFromStorage(FabricIndex & fabricIndex, bool & addNocCommandInvoked, bool & updateNocCommandInvoked)
{
DefaultStorageKeyAllocator keyAlloc;
uint8_t buf[FailSafeContextTLVMaxSize()];
ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Get(keyAlloc.FailSafeContextKey(), buf, sizeof(buf)));
TLV::ContiguousBufferTLVReader reader;
reader.Init(buf, sizeof(buf));
ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag()));
TLV::TLVType containerType;
ReturnErrorOnFailure(reader.EnterContainer(containerType));
ReturnErrorOnFailure(reader.Next(kFabricIndexTag));
ReturnErrorOnFailure(reader.Get(fabricIndex));
ReturnErrorOnFailure(reader.Next(kAddNocCommandTag));
ReturnErrorOnFailure(reader.Get(addNocCommandInvoked));
ReturnErrorOnFailure(reader.Next(kUpdateNocCommandTag));
ReturnErrorOnFailure(reader.Get(updateNocCommandInvoked));
ReturnErrorOnFailure(reader.VerifyEndOfContainer());
ReturnErrorOnFailure(reader.ExitContainer(containerType));
return CHIP_NO_ERROR;
}
CHIP_ERROR FailSafeContext::DeleteFromStorage()
{
DefaultStorageKeyAllocator keyAlloc;
return PersistedStorage::KeyValueStoreMgr().Delete(keyAlloc.FailSafeContextKey());
}
void FailSafeContext::ForceFailSafeTimerExpiry()
{
if (!IsFailSafeArmed())
{
return;
}
DeviceLayer::SystemLayer().CancelTimer(HandleArmFailSafeTimer, this);
FailSafeTimerExpired();
}
} // namespace DeviceLayer
} // namespace chip