Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 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 : * @file
20 : * A 'Fail Safe Context' SHALL be created on the receiver, to track fail-safe
21 : * state information while the fail-safe is armed.
22 : */
23 :
24 : #pragma once
25 :
26 : #include <lib/core/CHIPError.h>
27 : #include <lib/core/DataModelTypes.h>
28 : #include <lib/support/BitFlags.h>
29 : #include <platform/internal/CHIPDeviceLayerInternal.h>
30 : #include <system/SystemClock.h>
31 :
32 : namespace chip {
33 : namespace app {
34 :
35 : class FailSafeContext
36 : {
37 : public:
38 : // ===== Members for internal use by other Device Layer components.
39 :
40 : /**
41 : * @brief
42 : * Only a single fail-safe timer is started on the device, if this function is called again
43 : * when the fail-safe timer is currently armed, the currently-running fail-safe timer will
44 : * first be cancelled, then the fail-safe timer will be re-armed.
45 : */
46 : CHIP_ERROR ArmFailSafe(FabricIndex accessingFabricIndex, System::Clock::Seconds16 expiryLengthSeconds);
47 :
48 : /**
49 : * @brief Cleanly disarm failsafe timer, such as on CommissioningComplete
50 : */
51 : void DisarmFailSafe();
52 1 : void SetAddNocCommandInvoked(FabricIndex nocFabricIndex)
53 : {
54 1 : mContextFlags.Set(ContextFlags::kAddNocCommandInvoked);
55 1 : mFabricIndex = nocFabricIndex;
56 1 : }
57 1 : void SetUpdateNocCommandInvoked() { mContextFlags.Set(ContextFlags::kUpdateNocCommandInvoked); }
58 1 : void SetAddTrustedRootCertInvoked() { mContextFlags.Set(ContextFlags::kAddTrustedRootCertInvoked); }
59 3 : void SetCsrRequestForUpdateNoc(bool isForUpdateNoc)
60 : {
61 3 : mContextFlags.Set(ContextFlags::kIsCsrRequestForUpdateNoc, isForUpdateNoc);
62 3 : }
63 1 : void SetUpdateTermsAndConditionsHasBeenInvoked() { mContextFlags.Set(ContextFlags::kUpdateTermsAndConditionsInvoked); }
64 1 : void RecordSetVidVerificationStatementHasBeenInvoked() { mContextFlags.Set(ContextFlags::kSetVidVerificationStatementInvoked); }
65 : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
66 : void SetAddICACHasBeenInvoked() { mContextFlags.Set(ContextFlags::kAddICACInvoked); }
67 : #endif
68 :
69 : /**
70 : * @brief
71 : * Schedules a work to cleanup the FailSafe Context asynchronously after various cleanup work
72 : * has completed.
73 : */
74 : void ScheduleFailSafeCleanup(FabricIndex fabricIndex, bool addNocCommandInvoked, bool updateNocCommandInvoked);
75 :
76 2 : bool IsFailSafeArmed(FabricIndex accessingFabricIndex) const
77 : {
78 2 : return IsFailSafeArmed() && MatchesFabricIndex(accessingFabricIndex);
79 : }
80 :
81 : // Returns true if the fail-safe is in a state where commands that require an armed
82 : // fail-safe can no longer execute, but a new fail-safe can't be armed yet.
83 11 : bool IsFailSafeBusy() const { return mFailSafeBusy; }
84 :
85 24 : bool IsFailSafeArmed() const { return mFailSafeArmed; }
86 :
87 : // True if it is possible to do an initial arming of the failsafe if needed.
88 : // To be used in places where some action should take place only if the
89 : // fail-safe could be armed after that action.
90 7 : bool IsFailSafeFullyDisarmed() const { return !IsFailSafeArmed() && !IsFailSafeBusy(); }
91 :
92 2 : bool MatchesFabricIndex(FabricIndex accessingFabricIndex) const
93 : {
94 2 : VerifyOrDie(IsFailSafeArmed());
95 2 : return (accessingFabricIndex == mFabricIndex);
96 : }
97 :
98 4 : bool NocCommandHasBeenInvoked() const { return AddNocCommandHasBeenInvoked() || UpdateNocCommandHasBeenInvoked(); }
99 8 : bool AddNocCommandHasBeenInvoked() const { return mContextFlags.Has(ContextFlags::kAddNocCommandInvoked); }
100 6 : bool UpdateNocCommandHasBeenInvoked() const { return mContextFlags.Has(ContextFlags::kUpdateNocCommandInvoked); }
101 7 : bool AddTrustedRootCertHasBeenInvoked() const { return mContextFlags.Has(ContextFlags::kAddTrustedRootCertInvoked); }
102 7 : bool IsCsrRequestForUpdateNoc() const { return mContextFlags.Has(ContextFlags::kIsCsrRequestForUpdateNoc); }
103 8 : bool UpdateTermsAndConditionsHasBeenInvoked() const
104 : {
105 8 : return mContextFlags.Has(ContextFlags::kUpdateTermsAndConditionsInvoked);
106 : }
107 8 : bool HasSetVidVerificationStatementHasBeenInvoked() const
108 : {
109 8 : return mContextFlags.Has(ContextFlags::kSetVidVerificationStatementInvoked);
110 : }
111 : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
112 : bool AddICACCommandHasBeenInvoked() const { return mContextFlags.Has(ContextFlags::kAddICACInvoked); }
113 : #endif
114 :
115 3 : FabricIndex GetFabricIndex() const
116 : {
117 3 : VerifyOrDie(IsFailSafeArmed());
118 3 : return mFabricIndex;
119 : }
120 :
121 : // Immediately disarms the timer and schedules a failsafe timer expiry.
122 : // If the failsafe is not armed, this is a no-op.
123 : void ForceFailSafeTimerExpiry();
124 :
125 : private:
126 : enum class ContextFlags : uint8_t
127 : {
128 : kAddNocCommandInvoked = 0x01,
129 : kUpdateNocCommandInvoked = 0x02,
130 : kAddTrustedRootCertInvoked = 0x04,
131 : kIsCsrRequestForUpdateNoc = 0x08, /* Whether a CSR request occurred at all is stored elsewhere. */
132 : kUpdateTermsAndConditionsInvoked = 0x10,
133 : kSetVidVerificationStatementInvoked = 0x20,
134 : kAddICACInvoked = 0x40, /* Used only by Joint Fabric*/
135 : };
136 :
137 : BitFlags<ContextFlags> mContextFlags;
138 : FabricIndex mFabricIndex = kUndefinedFabricIndex;
139 :
140 : // These bools track the state of the fail-safe and are intentionally separate from mContextFlags, which records command/context
141 : // history.
142 : bool mFailSafeArmed = false;
143 : bool mFailSafeBusy = false;
144 :
145 : /**
146 : * @brief
147 : * The callback function to be called when "fail-safe timer" expires.
148 : */
149 : static void HandleArmFailSafeTimer(System::Layer * layer, void * aAppState);
150 :
151 : /**
152 : * @brief
153 : * The callback function to be called when max cumulative time expires.
154 : */
155 : static void HandleMaxCumulativeFailSafeTimer(System::Layer * layer, void * aAppState);
156 :
157 : /**
158 : * @brief
159 : * The callback function to be called asynchronously after various cleanup work has completed
160 : * to actually disarm the fail-safe.
161 : */
162 : static void HandleDisarmFailSafe(intptr_t arg);
163 :
164 : void SetFailSafeArmed(bool armed);
165 :
166 : /**
167 : * @brief Reset to unarmed basic state
168 : */
169 4 : void ResetState()
170 : {
171 4 : SetFailSafeArmed(false);
172 :
173 4 : mFailSafeBusy = false;
174 4 : mContextFlags.ClearAll();
175 4 : }
176 :
177 : void FailSafeTimerExpired();
178 : };
179 :
180 : } // namespace app
181 : } // namespace chip
|