Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2023 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file defines objects for a CHIP ICD handler which handles unsolicited check-in messages.
22 : *
23 : */
24 :
25 : #include <app/AppConfig.h>
26 : #include <app/InteractionModelEngine.h>
27 : #include <app/InteractionModelTimeout.h>
28 : #include <app/icd/client/CheckInHandler.h>
29 : #include <app/icd/client/RefreshKeySender.h>
30 :
31 : #include <cinttypes>
32 :
33 : #include <lib/core/Global.h>
34 : #include <lib/support/CodeUtils.h>
35 : #include <messaging/Flags.h>
36 : #include <protocols/Protocols.h>
37 :
38 : #include <protocols/secure_channel/Constants.h>
39 :
40 : using namespace chip::Protocols::SecureChannel;
41 :
42 : namespace chip {
43 : namespace app {
44 :
45 : inline constexpr uint64_t kCheckInCounterMax = (1ULL << 32);
46 : inline constexpr uint32_t kKeyRefreshLimit = (1U << 31);
47 :
48 1 : CheckInHandler::CheckInHandler() {}
49 :
50 1 : CHIP_ERROR CheckInHandler::Init(Messaging::ExchangeManager * exchangeManager, ICDClientStorage * clientStorage,
51 : CheckInDelegate * delegate, InteractionModelEngine * engine)
52 : {
53 1 : VerifyOrReturnError(exchangeManager != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
54 1 : VerifyOrReturnError(clientStorage != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
55 1 : VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
56 1 : VerifyOrReturnError(engine != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
57 1 : VerifyOrReturnError(mpExchangeManager == nullptr, CHIP_ERROR_INCORRECT_STATE);
58 1 : VerifyOrReturnError(mpICDClientStorage == nullptr, CHIP_ERROR_INCORRECT_STATE);
59 1 : VerifyOrReturnError(mpCheckInDelegate == nullptr, CHIP_ERROR_INCORRECT_STATE);
60 1 : VerifyOrReturnError(mpImEngine == nullptr, CHIP_ERROR_INCORRECT_STATE);
61 :
62 1 : mpExchangeManager = exchangeManager;
63 1 : mpICDClientStorage = clientStorage;
64 1 : mpCheckInDelegate = delegate;
65 1 : mpImEngine = engine;
66 1 : return mpExchangeManager->RegisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::ICD_CheckIn, this);
67 : }
68 :
69 1 : void CheckInHandler::Shutdown()
70 : {
71 1 : mpICDClientStorage = nullptr;
72 1 : mpCheckInDelegate = nullptr;
73 1 : if (mpExchangeManager)
74 : {
75 1 : TEMPORARY_RETURN_IGNORED mpExchangeManager->UnregisterUnsolicitedMessageHandlerForType(
76 : Protocols::SecureChannel::MsgType::ICD_CheckIn);
77 1 : mpExchangeManager = nullptr;
78 : }
79 1 : }
80 :
81 0 : CHIP_ERROR CheckInHandler::OnUnsolicitedMessageReceived(const PayloadHeader & payloadHeader, ExchangeDelegate *& newDelegate)
82 : {
83 : // Return error for wrong message type
84 0 : VerifyOrReturnError(payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::ICD_CheckIn),
85 : CHIP_ERROR_INVALID_MESSAGE_TYPE);
86 :
87 0 : newDelegate = this;
88 0 : return CHIP_NO_ERROR;
89 : }
90 :
91 8 : CHIP_ERROR CheckInHandler::OnMessageReceived(Messaging::ExchangeContext * ec, const PayloadHeader & payloadHeader,
92 : System::PacketBufferHandle && payload)
93 : {
94 : // If the message type is not ICD_CheckIn, return CHIP_NO_ERROR and exit
95 8 : VerifyOrReturnError(payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::ICD_CheckIn), CHIP_NO_ERROR);
96 :
97 8 : ByteSpan payloadByteSpan{ payload->Start(), payload->DataLength() };
98 8 : ICDClientInfo clientInfo;
99 8 : CounterType counter = 0;
100 : // If the check-in message processing fails, return CHIP_NO_ERROR and exit.
101 8 : CHIP_ERROR err = mpICDClientStorage->ProcessCheckInPayload(payloadByteSpan, clientInfo, counter);
102 16 : if (CHIP_NO_ERROR != err)
103 : {
104 1 : ChipLogError(ICD, "ProcessCheckInPayload failed: %" CHIP_ERROR_FORMAT, err.Format());
105 1 : return CHIP_NO_ERROR;
106 : }
107 7 : CounterType receivedCheckInCounterOffset = (counter - clientInfo.start_icd_counter) % kCheckInCounterMax;
108 :
109 : // Detect duplicate check-in messages and return CHIP_NO_ERROR on receiving a duplicate message
110 7 : if (receivedCheckInCounterOffset <= clientInfo.offset)
111 : {
112 1 : ChipLogError(ICD, "A duplicate check-in message was received and discarded");
113 1 : return CHIP_NO_ERROR;
114 : }
115 :
116 6 : clientInfo.offset = receivedCheckInCounterOffset;
117 6 : bool refreshKey = (receivedCheckInCounterOffset > kKeyRefreshLimit);
118 :
119 6 : if (refreshKey)
120 : {
121 1 : ChipLogProgress(ICD, "Key Refresh is required");
122 1 : RefreshKeySender * refreshKeySender = mpCheckInDelegate->OnKeyRefreshNeeded(clientInfo, mpICDClientStorage);
123 1 : if (refreshKeySender == nullptr)
124 : {
125 0 : ChipLogError(ICD, "Key Refresh failed for node ID:" ChipLogFormatScopedNodeId,
126 : ChipLogValueScopedNodeId(clientInfo.peer_node));
127 0 : return CHIP_NO_ERROR;
128 : }
129 1 : err = refreshKeySender->EstablishSessionToPeer();
130 2 : if (CHIP_NO_ERROR != err)
131 : {
132 1 : ChipLogError(ICD, "CASE session establishment failed with error : %" CHIP_ERROR_FORMAT, err.Format());
133 1 : mpCheckInDelegate->OnKeyRefreshDone(refreshKeySender, err);
134 1 : return CHIP_NO_ERROR;
135 : }
136 : }
137 : else
138 : {
139 5 : TEMPORARY_RETURN_IGNORED mpICDClientStorage->StoreEntry(clientInfo);
140 5 : mpCheckInDelegate->OnCheckInComplete(clientInfo);
141 : #if CHIP_CONFIG_ENABLE_READ_CLIENT
142 5 : mpImEngine->OnActiveModeNotification(clientInfo.peer_node, clientInfo.monitored_subject);
143 : #endif // CHIP_CONFIG_ENABLE_READ_CLIENT
144 : }
145 :
146 5 : return CHIP_NO_ERROR;
147 8 : }
148 :
149 0 : void CheckInHandler::OnResponseTimeout(Messaging::ExchangeContext * ec) {}
150 :
151 : } // namespace app
152 : } // namespace chip
|