Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / controller / CHIPDevice.cpp
1 /*
2  *
3  *    Copyright (c) 2020 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 contains implementation of Device class. The objects of this
22  *    class will be used by Controller applications to interact with CHIP
23  *    devices. The class provides mechanism to construct, send and receive
24  *    messages to and from the corresponding CHIP devices.
25  */
26
27 #include <controller/CHIPDevice.h>
28
29 #if CONFIG_DEVICE_LAYER
30 #include <platform/CHIPDeviceLayer.h>
31 #endif
32
33 #if CHIP_SYSTEM_CONFIG_USE_LWIP
34 #include <lwip/tcp.h>
35 #include <lwip/tcpip.h>
36 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
37
38 #include <app/CommandSender.h>
39 #include <app/server/DataModelHandler.h>
40 #include <core/CHIPCore.h>
41 #include <core/CHIPEncoding.h>
42 #include <core/CHIPSafeCasts.h>
43 #include <support/Base64.h>
44 #include <support/CHIPMem.h>
45 #include <support/CodeUtils.h>
46 #include <support/ErrorStr.h>
47 #include <support/SafeInt.h>
48 #include <support/logging/CHIPLogging.h>
49 #include <system/TLVPacketBufferBackingStore.h>
50
51 using namespace chip::Inet;
52 using namespace chip::System;
53 using namespace chip::Callback;
54
55 namespace chip {
56 namespace Controller {
57
58 CHIP_ERROR Device::SendMessage(System::PacketBufferHandle buffer, PayloadHeader & payloadHeader)
59 {
60     System::PacketBufferHandle resend;
61     bool loadedSecureSession = false;
62
63     VerifyOrReturnError(mSessionManager != nullptr, CHIP_ERROR_INCORRECT_STATE);
64     VerifyOrReturnError(!buffer.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
65
66     ReturnErrorOnFailure(LoadSecureSessionParametersIfNeeded(loadedSecureSession));
67
68     if (!loadedSecureSession)
69     {
70         // Secure connection already existed
71         // Hold on to the buffer, in case session resumption and resend is needed
72         // Cloning data, instead of increasing the ref count, as the original
73         // buffer might get modified by lower layers before the send fails. So,
74         // that buffer cannot be used for resends.
75         resend = buffer.CloneData();
76     }
77
78     CHIP_ERROR err = mSessionManager->SendMessage(mSecureSession, payloadHeader, std::move(buffer));
79
80     buffer = nullptr;
81     ChipLogDetail(Controller, "SendMessage returned %d", err);
82
83     // The send could fail due to network timeouts (e.g. broken pipe)
84     // Try session resumption if needed
85     if (err != CHIP_NO_ERROR && !resend.IsNull() && mState == ConnectionState::SecureConnected)
86     {
87         mState = ConnectionState::NotConnected;
88
89         ReturnErrorOnFailure(LoadSecureSessionParameters(ResetTransport::kYes));
90
91         err = mSessionManager->SendMessage(mSecureSession, std::move(resend));
92         ChipLogDetail(Controller, "Re-SendMessage returned %d", err);
93         ReturnErrorOnFailure(err);
94     }
95
96     return CHIP_NO_ERROR;
97 }
98
99 CHIP_ERROR Device::LoadSecureSessionParametersIfNeeded(bool & didLoad)
100 {
101     didLoad = false;
102
103     // If there is no secure connection to the device, try establishing it
104     if (mState != ConnectionState::SecureConnected)
105     {
106         ReturnErrorOnFailure(LoadSecureSessionParameters(ResetTransport::kNo));
107         didLoad = true;
108     }
109     else
110     {
111         Transport::PeerConnectionState * connectionState = nullptr;
112         connectionState                                  = mSessionManager->GetPeerConnectionState(mSecureSession);
113
114         // Check if the connection state has the correct transport information
115         if (connectionState == nullptr || connectionState->GetPeerAddress().GetTransportType() == Transport::Type::kUndefined ||
116             connectionState->GetTransport() != nullptr)
117         {
118             mState = ConnectionState::NotConnected;
119             ReturnErrorOnFailure(LoadSecureSessionParameters(ResetTransport::kNo));
120             didLoad = true;
121         }
122     }
123
124     return CHIP_NO_ERROR;
125 }
126
127 CHIP_ERROR Device::SendCommands()
128 {
129     bool loadedSecureSession = false;
130     ReturnErrorOnFailure(LoadSecureSessionParametersIfNeeded(loadedSecureSession));
131     VerifyOrReturnError(mCommandSender != nullptr, CHIP_ERROR_INCORRECT_STATE);
132     return mCommandSender->SendCommandRequest(mDeviceId, mAdminId);
133 }
134
135 CHIP_ERROR Device::SendMessage(System::PacketBufferHandle buffer)
136 {
137     PayloadHeader unusedHeader;
138     return SendMessage(std::move(buffer), unusedHeader);
139 }
140
141 CHIP_ERROR Device::Serialize(SerializedDevice & output)
142 {
143     CHIP_ERROR error       = CHIP_NO_ERROR;
144     uint16_t serializedLen = 0;
145     SerializableDevice serializable;
146
147     static_assert(BASE64_ENCODED_LEN(sizeof(serializable)) <= sizeof(output.inner),
148                   "Size of serializable should be <= size of output");
149
150     CHIP_ZERO_AT(serializable);
151
152     serializable.mOpsCreds   = mPairing;
153     serializable.mDeviceId   = Encoding::LittleEndian::HostSwap64(mDeviceId);
154     serializable.mDevicePort = Encoding::LittleEndian::HostSwap16(mDeviceUdpAddress.GetPort());
155     serializable.mAdminId    = Encoding::LittleEndian::HostSwap16(mAdminId);
156     SuccessOrExit(error = Inet::GetInterfaceName(mDeviceUdpAddress.GetInterface(), Uint8::to_char(serializable.mInterfaceName),
157                                                  sizeof(serializable.mInterfaceName)));
158     static_assert(sizeof(serializable.mDeviceAddr) <= INET6_ADDRSTRLEN, "Size of device address must fit within INET6_ADDRSTRLEN");
159     mDeviceUdpAddress.GetIPAddress().ToString(Uint8::to_char(serializable.mDeviceAddr), sizeof(serializable.mDeviceAddr));
160
161     serializedLen = chip::Base64Encode(Uint8::to_const_uchar(reinterpret_cast<uint8_t *>(&serializable)),
162                                        static_cast<uint16_t>(sizeof(serializable)), Uint8::to_char(output.inner));
163     VerifyOrExit(serializedLen > 0, error = CHIP_ERROR_INVALID_ARGUMENT);
164     VerifyOrExit(serializedLen < sizeof(output.inner), error = CHIP_ERROR_INVALID_ARGUMENT);
165     output.inner[serializedLen] = '\0';
166
167 exit:
168     return error;
169 }
170
171 CHIP_ERROR Device::Deserialize(const SerializedDevice & input)
172 {
173     CHIP_ERROR error = CHIP_NO_ERROR;
174     SerializableDevice serializable;
175     size_t maxlen            = BASE64_ENCODED_LEN(sizeof(serializable));
176     size_t len               = strnlen(Uint8::to_const_char(&input.inner[0]), maxlen);
177     uint16_t deserializedLen = 0;
178
179     VerifyOrExit(len < sizeof(SerializedDevice), error = CHIP_ERROR_INVALID_ARGUMENT);
180     VerifyOrExit(CanCastTo<uint16_t>(len), error = CHIP_ERROR_INVALID_ARGUMENT);
181
182     CHIP_ZERO_AT(serializable);
183     deserializedLen = Base64Decode(Uint8::to_const_char(input.inner), static_cast<uint16_t>(len),
184                                    Uint8::to_uchar(reinterpret_cast<uint8_t *>(&serializable)));
185
186     VerifyOrExit(deserializedLen > 0, error = CHIP_ERROR_INVALID_ARGUMENT);
187     VerifyOrExit(deserializedLen <= sizeof(serializable), error = CHIP_ERROR_INVALID_ARGUMENT);
188
189     Inet::IPAddress ipAddress;
190     uint16_t port;
191     Inet::InterfaceId interfaceId;
192
193     // The second parameter to FromString takes the strlen value. We are subtracting 1
194     // from the sizeof(serializable.mDeviceAddr) to account for null termination, since
195     // strlen doesn't include null character in the size.
196     VerifyOrExit(
197         IPAddress::FromString(Uint8::to_const_char(serializable.mDeviceAddr), sizeof(serializable.mDeviceAddr) - 1, ipAddress),
198         error = CHIP_ERROR_INVALID_ADDRESS);
199
200     mPairing  = serializable.mOpsCreds;
201     mDeviceId = Encoding::LittleEndian::HostSwap64(serializable.mDeviceId);
202     port      = Encoding::LittleEndian::HostSwap16(serializable.mDevicePort);
203     mAdminId  = Encoding::LittleEndian::HostSwap16(serializable.mAdminId);
204
205     // The InterfaceNameToId() API requires initialization of mInterface, and lock/unlock of
206     // LwIP stack.
207     interfaceId = INET_NULL_INTERFACEID;
208     if (serializable.mInterfaceName[0] != '\0')
209     {
210 #if CHIP_SYSTEM_CONFIG_USE_LWIP
211         LOCK_TCPIP_CORE();
212 #endif
213         INET_ERROR inetErr = Inet::InterfaceNameToId(Uint8::to_const_char(serializable.mInterfaceName), interfaceId);
214 #if CHIP_SYSTEM_CONFIG_USE_LWIP
215         UNLOCK_TCPIP_CORE();
216 #endif
217         VerifyOrExit(CHIP_NO_ERROR == inetErr, error = CHIP_ERROR_INTERNAL);
218     }
219
220     mDeviceUdpAddress = Transport::PeerAddress::UDP(ipAddress, port, interfaceId);
221
222 exit:
223     return error;
224 }
225
226 void Device::OnNewConnection(SecureSessionHandle session, SecureSessionMgr * mgr)
227 {
228     mState         = ConnectionState::SecureConnected;
229     mSecureSession = session;
230 }
231
232 void Device::OnConnectionExpired(SecureSessionHandle session, SecureSessionMgr * mgr)
233 {
234     mState         = ConnectionState::NotConnected;
235     mSecureSession = SecureSessionHandle{};
236 }
237
238 void Device::OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader, SecureSessionHandle session,
239                                System::PacketBufferHandle msgBuf, SecureSessionMgr * mgr)
240 {
241     if (mState == ConnectionState::SecureConnected)
242     {
243         if (mStatusDelegate != nullptr)
244         {
245             mStatusDelegate->OnMessage(std::move(msgBuf));
246         }
247         else
248         {
249             HandleDataModelMessage(mDeviceId, std::move(msgBuf));
250         }
251     }
252 }
253
254 CHIP_ERROR Device::OpenPairingWindow(uint32_t timeout, PairingWindowOption option, SetupPayload & setupPayload)
255 {
256     // TODO: This code is temporary, and must be updated to use the Cluster API.
257     // Issue: https://github.com/project-chip/connectedhomeip/issues/4725
258
259     // Construct and send "open pairing window" message to the device
260     System::PacketBufferHandle buf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize);
261     System::PacketBufferTLVWriter writer;
262
263     writer.Init(std::move(buf));
264     writer.ImplicitProfileId = chip::Protocols::ServiceProvisioning::Id.ToTLVProfileId();
265
266     ReturnErrorOnFailure(writer.Put(TLV::ProfileTag(writer.ImplicitProfileId, 1), timeout));
267
268     if (option != PairingWindowOption::kOriginalSetupCode)
269     {
270         ReturnErrorOnFailure(writer.Put(TLV::ProfileTag(writer.ImplicitProfileId, 2), setupPayload.discriminator));
271
272         PASEVerifier verifier;
273         bool randomSetupPIN = (option == PairingWindowOption::kTokenWithRandomPIN);
274         ReturnErrorOnFailure(PASESession::GeneratePASEVerifier(verifier, randomSetupPIN, setupPayload.setUpPINCode));
275         ReturnErrorOnFailure(writer.PutBytes(TLV::ProfileTag(writer.ImplicitProfileId, 3),
276                                              reinterpret_cast<const uint8_t *>(verifier), sizeof(verifier)));
277     }
278
279     System::PacketBufferHandle outBuffer;
280     ReturnErrorOnFailure(writer.Finalize(&outBuffer));
281
282     PayloadHeader header;
283
284     header.SetMessageType(chip::Protocols::ServiceProvisioning::Id, 0);
285
286     ReturnErrorOnFailure(SendMessage(std::move(outBuffer), header));
287
288     setupPayload.version               = 0;
289     setupPayload.rendezvousInformation = RendezvousInformationFlags::kBLE;
290
291     return CHIP_NO_ERROR;
292 }
293
294 CHIP_ERROR Device::UpdateAddress(const Transport::PeerAddress & addr)
295 {
296     bool didLoad;
297
298     VerifyOrReturnError(addr.GetTransportType() == Transport::Type::kUdp, CHIP_ERROR_INVALID_ADDRESS);
299     ReturnErrorOnFailure(LoadSecureSessionParametersIfNeeded(didLoad));
300
301     Transport::PeerConnectionState * connectionState = mSessionManager->GetPeerConnectionState(mSecureSession);
302     VerifyOrReturnError(connectionState != nullptr, CHIP_ERROR_INCORRECT_STATE);
303
304     mDeviceUdpAddress = addr;
305     connectionState->SetPeerAddress(addr);
306
307     return CHIP_NO_ERROR;
308 }
309
310 CHIP_ERROR Device::LoadSecureSessionParameters(ResetTransport resetNeeded)
311 {
312     CHIP_ERROR err = CHIP_NO_ERROR;
313     PASESession pairingSession;
314
315     if (mSessionManager == nullptr || mState == ConnectionState::SecureConnected)
316     {
317         ExitNow(err = CHIP_ERROR_INCORRECT_STATE);
318     }
319
320     err = pairingSession.FromSerializable(mPairing);
321     SuccessOrExit(err);
322
323     if (resetNeeded == ResetTransport::kYes)
324     {
325         err = mTransportMgr->ResetTransport(
326             Transport::UdpListenParameters(mInetLayer).SetAddressType(kIPAddressType_IPv6).SetListenPort(mListenPort)
327 #if INET_CONFIG_ENABLE_IPV4
328                 ,
329             Transport::UdpListenParameters(mInetLayer).SetAddressType(kIPAddressType_IPv4).SetListenPort(mListenPort)
330 #endif
331         );
332         SuccessOrExit(err);
333     }
334
335     err = mSessionManager->NewPairing(Optional<Transport::PeerAddress>::Value(mDeviceUdpAddress), mDeviceId, &pairingSession,
336                                       SecureSessionMgr::PairingDirection::kInitiator, mAdminId);
337     SuccessOrExit(err);
338
339 exit:
340
341     if (err != CHIP_NO_ERROR)
342     {
343         ChipLogError(Controller, "LoadSecureSessionParameters returning error %d\n", err);
344     }
345     return err;
346 }
347
348 bool Device::GetAddress(Inet::IPAddress & addr, uint16_t & port) const
349 {
350     if (mState == ConnectionState::NotConnected)
351         return false;
352
353     addr = mDeviceUdpAddress.GetIPAddress();
354     port = mDeviceUdpAddress.GetPort();
355     return true;
356 }
357
358 void Device::AddResponseHandler(uint8_t seqNum, Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback)
359 {
360     mCallbacksMgr.AddResponseCallback(mDeviceId, seqNum, onSuccessCallback, onFailureCallback);
361 }
362
363 void Device::AddReportHandler(EndpointId endpoint, ClusterId cluster, AttributeId attribute,
364                               Callback::Cancelable * onReportCallback)
365 {
366     mCallbacksMgr.AddReportCallback(mDeviceId, endpoint, cluster, attribute, onReportCallback);
367 }
368
369 } // namespace Controller
370 } // namespace chip