| /* |
| * |
| * 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 |