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 : mpExchangeManager->UnregisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::ICD_CheckIn);
76 1 : mpExchangeManager = nullptr;
77 : }
78 1 : }
79 :
80 0 : CHIP_ERROR CheckInHandler::OnUnsolicitedMessageReceived(const PayloadHeader & payloadHeader, ExchangeDelegate *& newDelegate)
81 : {
82 : // Return error for wrong message type
83 0 : VerifyOrReturnError(payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::ICD_CheckIn),
84 : CHIP_ERROR_INVALID_MESSAGE_TYPE);
85 :
86 0 : newDelegate = this;
87 0 : return CHIP_NO_ERROR;
88 : }
89 :
90 8 : CHIP_ERROR CheckInHandler::OnMessageReceived(Messaging::ExchangeContext * ec, const PayloadHeader & payloadHeader,
91 : System::PacketBufferHandle && payload)
92 : {
93 : // If the message type is not ICD_CheckIn, return CHIP_NO_ERROR and exit
94 8 : VerifyOrReturnError(payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::ICD_CheckIn), CHIP_NO_ERROR);
95 :
96 8 : ByteSpan payloadByteSpan{ payload->Start(), payload->DataLength() };
97 8 : ICDClientInfo clientInfo;
98 8 : CounterType counter = 0;
99 : // If the check-in message processing fails, return CHIP_NO_ERROR and exit.
100 8 : CHIP_ERROR err = mpICDClientStorage->ProcessCheckInPayload(payloadByteSpan, clientInfo, counter);
101 8 : if (CHIP_NO_ERROR != err)
102 : {
103 1 : ChipLogError(ICD, "ProcessCheckInPayload failed: %" CHIP_ERROR_FORMAT, err.Format());
104 1 : return CHIP_NO_ERROR;
105 : }
106 7 : CounterType receivedCheckInCounterOffset = (counter - clientInfo.start_icd_counter) % kCheckInCounterMax;
107 :
108 : // Detect duplicate check-in messages and return CHIP_NO_ERROR on receiving a duplicate message
109 7 : if (receivedCheckInCounterOffset <= clientInfo.offset)
110 : {
111 1 : ChipLogError(ICD, "A duplicate check-in message was received and discarded");
112 1 : return CHIP_NO_ERROR;
113 : }
114 :
115 6 : clientInfo.offset = receivedCheckInCounterOffset;
116 6 : bool refreshKey = (receivedCheckInCounterOffset > kKeyRefreshLimit);
117 :
118 6 : if (refreshKey)
119 : {
120 1 : ChipLogProgress(ICD, "Key Refresh is required");
121 1 : RefreshKeySender * refreshKeySender = mpCheckInDelegate->OnKeyRefreshNeeded(clientInfo, mpICDClientStorage);
122 1 : if (refreshKeySender == nullptr)
123 : {
124 0 : ChipLogError(ICD, "Key Refresh failed for node ID:" ChipLogFormatScopedNodeId,
125 : ChipLogValueScopedNodeId(clientInfo.peer_node));
126 0 : return CHIP_NO_ERROR;
127 : }
128 1 : err = refreshKeySender->EstablishSessionToPeer();
129 1 : if (CHIP_NO_ERROR != err)
130 : {
131 1 : ChipLogError(ICD, "CASE session establishment failed with error : %" CHIP_ERROR_FORMAT, err.Format());
132 1 : mpCheckInDelegate->OnKeyRefreshDone(refreshKeySender, err);
133 1 : return CHIP_NO_ERROR;
134 : }
135 : }
136 : else
137 : {
138 5 : mpICDClientStorage->StoreEntry(clientInfo);
139 5 : mpCheckInDelegate->OnCheckInComplete(clientInfo);
140 : #if CHIP_CONFIG_ENABLE_READ_CLIENT
141 5 : mpImEngine->OnActiveModeNotification(clientInfo.peer_node);
142 : #endif // CHIP_CONFIG_ENABLE_READ_CLIENT
143 : }
144 :
145 5 : return CHIP_NO_ERROR;
146 8 : }
147 :
148 0 : void CheckInHandler::OnResponseTimeout(Messaging::ExchangeContext * ec) {}
149 :
150 : } // namespace app
151 : } // namespace chip
|