3 * Copyright (c) 2020 Project CHIP Authors
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * This file contains definitions for 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.
29 #include <app/CommandSender.h>
30 #include <app/InteractionModelEngine.h>
31 #include <app/util/CHIPDeviceCallbacksMgr.h>
32 #include <app/util/basic-types.h>
33 #include <core/CHIPCallback.h>
34 #include <core/CHIPCore.h>
35 #include <setup_payload/SetupPayload.h>
36 #include <support/Base64.h>
37 #include <support/DLLUtil.h>
38 #include <transport/PASESession.h>
39 #include <transport/SecureSessionMgr.h>
40 #include <transport/TransportMgr.h>
41 #include <transport/raw/MessageHeader.h>
42 #include <transport/raw/UDP.h>
45 namespace Controller {
47 class DeviceController;
48 class DeviceStatusDelegate;
49 struct SerializedDevice;
51 using DeviceTransportMgr = TransportMgr<Transport::UDP /* IPv6 */
52 #if INET_CONFIG_ENABLE_IPV4
54 Transport::UDP /* IPv4 */
58 struct ControllerDeviceInitParams
60 DeviceTransportMgr * transportMgr = nullptr;
61 SecureSessionMgr * sessionMgr = nullptr;
62 Inet::InetLayer * inetLayer = nullptr;
65 class DLL_EXPORT Device
70 if (mCommandSender != nullptr)
72 mCommandSender->Shutdown();
73 mCommandSender = nullptr;
77 enum class PairingWindowOption
81 kTokenWithProvidedPIN,
86 * Set the delegate object which will be called when a message is received.
87 * The user of this Device object must reset the delegate (by calling
88 * SetDelegate(nullptr)) before releasing their delegate object.
90 * @param[in] delegate The pointer to the delegate object.
92 void SetDelegate(DeviceStatusDelegate * delegate) { mStatusDelegate = delegate; }
94 // ----- Messaging -----
97 * Send the provided message to the device
99 * @param[in] message The message to be sent.
101 * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error
103 CHIP_ERROR SendMessage(System::PacketBufferHandle message);
107 * Send the command in internal command sender.
109 CHIP_ERROR SendCommands();
113 * Initialize internal command sender, required for sending commands over interaction model.
115 void InitCommandSender()
117 if (mCommandSender != nullptr)
119 mCommandSender->Shutdown();
120 mCommandSender = nullptr;
122 #if CHIP_ENABLE_INTERACTION_MODEL
123 chip::app::InteractionModelEngine::GetInstance()->NewCommandSender(&mCommandSender);
126 app::CommandSender * GetCommandSender() { return mCommandSender; }
129 * @brief Get the IP address and port assigned to the device.
131 * @param[out] addr IP address of the device.
132 * @param[out] port Port number of the device.
134 * @return true, if the IP address and port were filled in the out parameters, false otherwise
136 bool GetAddress(Inet::IPAddress & addr, uint16_t & port) const;
140 * Initialize the device object with secure session manager and inet layer object
141 * references. This variant of function is typically used when the device object
142 * is created from a serialized device information. The other parameters (address, port,
143 * interface etc) are part of the serialized device, so those are not required to be
146 * Note: The lifetime of session manager and inet layer objects must be longer than
147 * that of this device object. If these objects are freed, while the device object is
148 * still using them, it can lead to unknown behavior and crashes.
150 * @param[in] params Wrapper object for transport manager etc.
151 * @param[in] listenPort Port on which controller is listening (typically CHIP_PORT)
152 * @param[in] admin Local administrator that's initializing this device object
154 void Init(ControllerDeviceInitParams params, uint16_t listenPort, Transport::AdminId admin)
156 mTransportMgr = params.transportMgr;
157 mSessionManager = params.sessionMgr;
158 mInetLayer = params.inetLayer;
159 mListenPort = listenPort;
165 * Initialize a new device object with secure session manager, inet layer object,
166 * and other device specific parameters. This variant of function is typically used when
167 * a new device is paired, and the corresponding device object needs to updated with
168 * all device specifc parameters (address, port, interface etc).
170 * This is not done as part of constructor so that the controller can have a list of
171 * uninitialzed/unpaired device objects. The object is initialized only when the device
172 * is actually paired.
174 * @param[in] params Wrapper object for transport manager etc.
175 * @param[in] listenPort Port on which controller is listening (typically CHIP_PORT)
176 * @param[in] deviceId Node ID of the device
177 * @param[in] peerAddress The location of the peer. MUST be of type Transport::Type::kUdp
178 * @param[in] admin Local administrator that's initializing this device object
180 void Init(ControllerDeviceInitParams params, uint16_t listenPort, NodeId deviceId, const Transport::PeerAddress & peerAddress,
181 Transport::AdminId admin)
183 Init(params, mListenPort, admin);
184 mDeviceId = deviceId;
185 mState = ConnectionState::Connecting;
187 if (peerAddress.GetTransportType() != Transport::Type::kUdp)
189 ChipLogError(Controller, "Invalid peer address received in chip device initialization. Expected a UDP address.");
194 mDeviceUdpAddress = peerAddress;
198 /** @brief Serialize the Pairing Session to a string. It's guaranteed that the string
199 * will be null terminated, and there won't be any embedded null characters.
201 * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
203 CHIP_ERROR Serialize(SerializedDevice & output);
205 /** @brief Deserialize the Pairing Session from the string. It's expected that the string
206 * will be null terminated, and there won't be any embedded null characters.
208 * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
210 CHIP_ERROR Deserialize(const SerializedDevice & input);
214 * Called when a new pairing is being established
216 * @param session A handle to the secure session
217 * @param mgr A pointer to the SecureSessionMgr
219 void OnNewConnection(SecureSessionHandle session, SecureSessionMgr * mgr);
223 * Called when a connection is closing.
225 * The receiver should release all resources associated with the connection.
227 * @param session A handle to the secure session
228 * @param mgr A pointer to the SecureSessionMgr
230 void OnConnectionExpired(SecureSessionHandle session, SecureSessionMgr * mgr);
234 * This function is called when a message is received from the corresponding CHIP
235 * device. The message ownership is transferred to the function, and it is expected
236 * to release the message buffer before returning.
238 * @param[in] header Reference to common packet header of the received message
239 * @param[in] payloadHeader Reference to payload header in the message
240 * @param[in] session A handle to the secure session
241 * @param[in] msgBuf The message buffer
242 * @param[in] mgr Pointer to secure session manager which received the message
244 void OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader, SecureSessionHandle session,
245 System::PacketBufferHandle msgBuf, SecureSessionMgr * mgr);
249 * Trigger a paired device to re-enter the pairing mode. If an onboarding token is provided, the device will use
250 * the provided setup PIN code and the discriminator to advertise itself for pairing availability. If the token
251 * is not provided, the device will use the manufacturer assigned setup PIN code and discriminator.
253 * The device will exit the pairing mode after a successful pairing, or after the given `timeout` time.
255 * @param[in] timeout The pairing mode should terminate after this much time.
256 * @param[in] option The pairing window can be opened using the original setup code, or an
257 * onboarding token can be generated using a random setup PIN code (or with
258 * the PIN code provied in the setupPayload). This argument selects one of these
260 * @param[out] setupPayload The setup payload corresponding to the generated onboarding token.
262 * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error
264 CHIP_ERROR OpenPairingWindow(uint32_t timeout, PairingWindowOption option, SetupPayload & setupPayload);
268 * Update address of the device.
270 * This function will set new IP address and port of the device. Since the device settings might
271 * have been moved from RAM to the persistent storage, the function will load the device settings
272 * first, before making the changes.
274 * @param[in] addr Address of the device to be set.
276 * @return CHIP_NO_ERROR if the address has been updated, an error code otherwise.
278 CHIP_ERROR UpdateAddress(const Transport::PeerAddress & addr);
281 * Return whether the current device object is actively associated with a paired CHIP
282 * device. An active object can be used to communicate with the corresponding device.
284 bool IsActive() const { return mActive; }
286 void SetActive(bool active) { mActive = active; }
288 bool IsSecureConnected() const { return IsActive() && mState == ConnectionState::SecureConnected; }
293 mState = ConnectionState::NotConnected;
294 mSessionManager = nullptr;
295 mStatusDelegate = nullptr;
296 mInetLayer = nullptr;
299 NodeId GetDeviceId() const { return mDeviceId; }
301 bool MatchesSession(SecureSessionHandle session) const { return mSecureSession == session; }
303 void SetAddress(const Inet::IPAddress & deviceAddr) { mDeviceUdpAddress.SetIPAddress(deviceAddr); }
305 PASESessionSerializable & GetPairing() { return mPairing; }
307 uint8_t GetNextSequenceNumber() { return mSequenceNumber++; };
308 void AddResponseHandler(uint8_t seqNum, Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback);
309 void AddReportHandler(EndpointId endpoint, ClusterId cluster, AttributeId attribute, Callback::Cancelable * onReportCallback);
312 enum class ConnectionState
319 enum class ResetTransport
324 /* Node ID assigned to the CHIP device */
327 /** Address used to communicate with the device. MUST be Type::kUDP
328 * in the current implementation.
330 Transport::PeerAddress mDeviceUdpAddress = Transport::PeerAddress::UDP(Inet::IPAddress::Any);
332 Inet::InetLayer * mInetLayer = nullptr;
334 bool mActive = false;
335 ConnectionState mState = ConnectionState::NotConnected;
337 PASESessionSerializable mPairing;
339 DeviceStatusDelegate * mStatusDelegate = nullptr;
341 SecureSessionMgr * mSessionManager = nullptr;
343 DeviceTransportMgr * mTransportMgr = nullptr;
345 app::CommandSender * mCommandSender = nullptr;
347 SecureSessionHandle mSecureSession = {};
349 uint8_t mSequenceNumber = 0;
351 app::CHIPDeviceCallbacksMgr & mCallbacksMgr = app::CHIPDeviceCallbacksMgr::GetInstance();
355 * This function loads the secure session object from the serialized operational
356 * credentials corresponding to the device. This is typically done when the device
357 * does not have an active secure channel.
359 * @param[in] resetNeeded Does the underlying network socket require a reset
361 CHIP_ERROR LoadSecureSessionParameters(ResetTransport resetNeeded);
365 * This function loads the secure session object from the serialized operational
366 * credentials corresponding if needed, based on the current state of the device and
367 * underlying transport object.
369 * @param[out] didLoad Were the secure session params loaded by the call to this function.
371 CHIP_ERROR LoadSecureSessionParametersIfNeeded(bool & didLoad);
373 CHIP_ERROR SendMessage(System::PacketBufferHandle message, PayloadHeader & payloadHeader);
375 uint16_t mListenPort;
377 Transport::AdminId mAdminId = Transport::kUndefinedAdminId;
381 * This class defines an interface for an object that the user of Device
382 * can register as a delegate. The delegate object will be called by the
383 * Device when a new message or status update is received from the corresponding
386 class DLL_EXPORT DeviceStatusDelegate
389 virtual ~DeviceStatusDelegate() {}
393 * Called when a message is received from the device.
395 * @param[in] msg Received message buffer.
397 virtual void OnMessage(System::PacketBufferHandle msg) = 0;
401 * Called when response to OpenPairingWindow is received from the device.
403 * @param[in] status CHIP_NO_ERROR on success, or corresponding error.
405 virtual void OnPairingWindowOpenStatus(CHIP_ERROR status){};
409 * Called when device status is updated.
412 virtual void OnStatusChange(void){};
416 constexpr uint16_t kMaxInterfaceName = IFNAMSIZ;
418 constexpr uint16_t kMaxInterfaceName = 32;
421 typedef struct SerializableDevice
423 PASESessionSerializable mOpsCreds;
424 uint64_t mDeviceId; /* This field is serialized in LittleEndian byte order */
425 uint8_t mDeviceAddr[INET6_ADDRSTRLEN];
426 uint16_t mDevicePort; /* This field is serialized in LittleEndian byte order */
427 uint16_t mAdminId; /* This field is serialized in LittleEndian byte order */
428 uint8_t mInterfaceName[kMaxInterfaceName];
429 } SerializableDevice;
431 typedef struct SerializedDevice
433 // Extra uint64_t to account for padding bytes (NULL termination, and some decoding overheads)
434 // The encoder may not include a NULL character, and there are maximum 2 bytes of padding.
435 // So extra 8 bytes should be sufficient to absorb this overhead.
436 uint8_t inner[BASE64_ENCODED_LEN(sizeof(SerializableDevice) + sizeof(uint64_t))];
439 } // namespace Controller