Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021-2022 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 implements an object for a Matter User Directed Commissioning unsolicited
22 : * recipient (server).
23 : *
24 : */
25 :
26 : #include "UserDirectedCommissioning.h"
27 : #include <lib/core/CHIPSafeCasts.h>
28 : #include <system/TLVPacketBufferBackingStore.h>
29 :
30 : #include <unistd.h>
31 :
32 : namespace chip {
33 : namespace Protocols {
34 : namespace UserDirectedCommissioning {
35 :
36 0 : void UserDirectedCommissioningServer::OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msg)
37 : {
38 : char addrBuffer[chip::Transport::PeerAddress::kMaxToStringSize];
39 0 : source.ToString(addrBuffer);
40 0 : ChipLogProgress(AppServer, "UserDirectedCommissioningServer::OnMessageReceived from %s", addrBuffer);
41 :
42 0 : PacketHeader packetHeader;
43 :
44 0 : ReturnOnFailure(packetHeader.DecodeAndConsume(msg));
45 :
46 0 : if (packetHeader.IsEncrypted())
47 : {
48 0 : ChipLogError(AppServer, "UDC encryption flag set - ignoring");
49 0 : return;
50 : }
51 :
52 0 : PayloadHeader payloadHeader;
53 0 : ReturnOnFailure(payloadHeader.DecodeAndConsume(msg));
54 :
55 0 : ChipLogProgress(AppServer, "IdentityDeclaration DataLength()=%d", msg->DataLength());
56 :
57 : uint8_t udcPayload[IdentificationDeclaration::kUdcTLVDataMaxBytes];
58 0 : size_t udcPayloadLength = std::min<size_t>(msg->DataLength(), sizeof(udcPayload));
59 0 : msg->Read(udcPayload, udcPayloadLength);
60 :
61 0 : IdentificationDeclaration id;
62 0 : id.ReadPayload(udcPayload, sizeof(udcPayload));
63 :
64 0 : char * instanceName = (char *) id.GetInstanceName();
65 :
66 0 : ChipLogProgress(AppServer, "UDC instance=%s ", id.GetInstanceName());
67 :
68 0 : UDCClientState * client = mUdcClients.FindUDCClientState(instanceName);
69 0 : if (client == nullptr)
70 : {
71 0 : ChipLogProgress(AppServer, "UDC new instance state received");
72 :
73 0 : id.DebugLog();
74 :
75 : CHIP_ERROR err;
76 0 : err = mUdcClients.CreateNewUDCClientState(instanceName, &client);
77 0 : if (err != CHIP_NO_ERROR)
78 : {
79 0 : ChipLogError(AppServer, "UDC error creating new connection state");
80 0 : return;
81 : }
82 :
83 0 : if (id.HasDiscoveryInfo())
84 : {
85 : // if we received mDNS info, skip the commissionable lookup
86 0 : ChipLogDetail(AppServer, "UDC discovery info provided");
87 0 : mUdcClients.MarkUDCClientActive(client);
88 :
89 0 : client->SetUDCClientProcessingState(UDCClientProcessingState::kPromptingUser);
90 0 : client->SetPeerAddress(source);
91 :
92 0 : id.UpdateClientState(client);
93 :
94 : // TEST: send reply
95 0 : if (id.GetCdPort() != 0)
96 : {
97 0 : CommissionerDeclaration cd;
98 0 : cd.SetErrorCode(CommissionerDeclaration::CdError::kAppInstallConsentPending);
99 0 : cd.SetNeedsPasscode(true);
100 0 : SendCDCMessage(cd, chip::Transport::PeerAddress::UDP(source.GetIPAddress(), id.GetCdPort()));
101 : }
102 :
103 : // Call the registered mUserConfirmationProvider, if any.
104 0 : if (mUserConfirmationProvider != nullptr)
105 : {
106 0 : mUserConfirmationProvider->OnUserDirectedCommissioningRequest(*client);
107 : }
108 0 : return;
109 : }
110 :
111 : // Call the registered InstanceNameResolver, if any.
112 0 : if (mInstanceNameResolver != nullptr)
113 : {
114 0 : mInstanceNameResolver->FindCommissionableNode(instanceName);
115 : }
116 : else
117 : {
118 0 : ChipLogError(AppServer, "UserDirectedCommissioningServer::OnMessageReceived no mInstanceNameResolver registered");
119 : }
120 : }
121 :
122 0 : mUdcClients.MarkUDCClientActive(client);
123 0 : }
124 :
125 0 : CHIP_ERROR UserDirectedCommissioningServer::SendCDCMessage(CommissionerDeclaration cd, chip::Transport::PeerAddress peerAddress)
126 : {
127 0 : if (mTransportMgr == nullptr)
128 : {
129 0 : ChipLogError(AppServer, "CDC: No transport manager\n");
130 0 : return CHIP_ERROR_INCORRECT_STATE;
131 : }
132 : uint8_t idBuffer[IdentificationDeclaration::kUdcTLVDataMaxBytes];
133 0 : uint32_t length = cd.WritePayload(idBuffer, sizeof(idBuffer));
134 0 : if (length == 0)
135 : {
136 0 : ChipLogError(AppServer, "CDC: error writing payload\n");
137 0 : return CHIP_ERROR_INTERNAL;
138 : }
139 :
140 0 : chip::System::PacketBufferHandle payload = chip::MessagePacketBuffer::NewWithData(idBuffer, length);
141 0 : if (payload.IsNull())
142 : {
143 0 : ChipLogError(AppServer, "Unable to allocate packet buffer\n");
144 0 : return CHIP_ERROR_NO_MEMORY;
145 : }
146 0 : ReturnErrorOnFailure(EncodeUDCMessage(payload));
147 :
148 0 : cd.DebugLog();
149 0 : ChipLogProgress(Inet, "Sending CDC msg");
150 :
151 0 : auto err = mTransportMgr->SendMessage(peerAddress, std::move(payload));
152 0 : if (err != CHIP_NO_ERROR)
153 : {
154 0 : ChipLogError(AppServer, "CDC SendMessage failed: %" CHIP_ERROR_FORMAT, err.Format());
155 0 : return err;
156 : }
157 :
158 0 : ChipLogProgress(Inet, "CDC msg sent");
159 0 : return CHIP_NO_ERROR;
160 0 : }
161 :
162 0 : CHIP_ERROR UserDirectedCommissioningServer::EncodeUDCMessage(const System::PacketBufferHandle & payload)
163 : {
164 0 : PayloadHeader payloadHeader;
165 0 : PacketHeader packetHeader;
166 :
167 0 : payloadHeader.SetMessageType(MsgType::IdentificationDeclaration).SetInitiator(true).SetNeedsAck(false);
168 :
169 0 : VerifyOrReturnError(!payload.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
170 0 : VerifyOrReturnError(!payload->HasChainedBuffer(), CHIP_ERROR_INVALID_MESSAGE_LENGTH);
171 0 : VerifyOrReturnError(payload->TotalLength() <= kMaxAppMessageLen, CHIP_ERROR_MESSAGE_TOO_LONG);
172 :
173 0 : ReturnErrorOnFailure(payloadHeader.EncodeBeforeData(payload));
174 :
175 0 : ReturnErrorOnFailure(packetHeader.EncodeBeforeData(payload));
176 :
177 0 : return CHIP_NO_ERROR;
178 0 : }
179 :
180 1 : CHIP_ERROR IdentificationDeclaration::ReadPayload(uint8_t * udcPayload, size_t payloadBufferSize)
181 : {
182 1 : size_t i = 0;
183 12 : while (i < std::min<size_t>(sizeof(mInstanceName), payloadBufferSize) && udcPayload[i] != '\0')
184 : {
185 11 : mInstanceName[i] = (char) udcPayload[i];
186 11 : i++;
187 : }
188 1 : mInstanceName[i] = '\0';
189 :
190 1 : if (payloadBufferSize <= sizeof(mInstanceName))
191 : {
192 0 : ChipLogProgress(AppServer, "UDC - No TLV information in Identification Declaration");
193 0 : return CHIP_NO_ERROR;
194 : }
195 : // advance i to the end of the fixed length block containing instance name
196 1 : i = sizeof(mInstanceName);
197 :
198 : CHIP_ERROR err;
199 :
200 : TLV::TLVReader reader;
201 1 : reader.Init(udcPayload + i, payloadBufferSize - i);
202 :
203 : // read the envelope
204 1 : ReturnErrorOnFailure(reader.Next(chip::TLV::kTLVType_Structure, chip::TLV::AnonymousTag()));
205 :
206 1 : chip::TLV::TLVType outerContainerType = chip::TLV::kTLVType_Structure;
207 1 : ReturnErrorOnFailure(reader.EnterContainer(outerContainerType));
208 :
209 14 : while ((err = reader.Next()) == CHIP_NO_ERROR)
210 : {
211 13 : chip::TLV::Tag containerTag = reader.GetTag();
212 13 : if (!TLV::IsContextTag(containerTag))
213 : {
214 0 : ChipLogError(AppServer, "Unexpected non-context TLV tag.");
215 0 : return CHIP_ERROR_INVALID_TLV_TAG;
216 : }
217 13 : uint8_t tagNum = static_cast<uint8_t>(chip::TLV::TagNumFromTag(containerTag));
218 :
219 13 : switch (tagNum)
220 : {
221 1 : case kVendorIdTag:
222 : // vendorId
223 1 : err = reader.Get(mVendorId);
224 1 : break;
225 1 : case kProductIdTag:
226 : // productId
227 1 : err = reader.Get(mProductId);
228 1 : break;
229 1 : case kCdPortTag:
230 : // port
231 1 : err = reader.Get(mCdPort);
232 1 : break;
233 1 : case kDeviceNameTag:
234 : // deviceName
235 1 : err = reader.GetString(mDeviceName, sizeof(mDeviceName));
236 1 : break;
237 1 : case kPairingInstTag:
238 : // pairingInst
239 1 : err = reader.GetString(mPairingInst, sizeof(mPairingInst));
240 1 : break;
241 1 : case kPairingHintTag:
242 : // pairingHint
243 1 : err = reader.Get(mPairingHint);
244 1 : break;
245 1 : case kRotatingIdTag:
246 : // rotatingId
247 1 : mRotatingIdLen = reader.GetLength();
248 1 : err = reader.GetBytes(mRotatingId, sizeof(mRotatingId));
249 1 : break;
250 1 : case kTargetAppListTag:
251 : // app vendor list
252 : {
253 1 : ChipLogProgress(AppServer, "TLV found an applist");
254 1 : chip::TLV::TLVType listContainerType = chip::TLV::kTLVType_List;
255 1 : ReturnErrorOnFailure(reader.EnterContainer(listContainerType));
256 :
257 4 : while ((err = reader.Next()) == CHIP_NO_ERROR && mNumTargetAppInfos < sizeof(mTargetAppInfos))
258 : {
259 3 : containerTag = reader.GetTag();
260 3 : if (!TLV::IsContextTag(containerTag))
261 : {
262 0 : ChipLogError(AppServer, "Unexpected non-context TLV tag.");
263 0 : return CHIP_ERROR_INVALID_TLV_TAG;
264 : }
265 3 : tagNum = static_cast<uint8_t>(chip::TLV::TagNumFromTag(containerTag));
266 3 : if (tagNum == kTargetAppTag)
267 : {
268 3 : ReturnErrorOnFailure(reader.EnterContainer(outerContainerType));
269 3 : uint16_t appVendorId = 0;
270 3 : uint16_t appProductId = 0;
271 :
272 9 : while ((err = reader.Next()) == CHIP_NO_ERROR)
273 : {
274 6 : containerTag = reader.GetTag();
275 6 : if (!TLV::IsContextTag(containerTag))
276 : {
277 0 : ChipLogError(AppServer, "Unexpected non-context TLV tag.");
278 0 : return CHIP_ERROR_INVALID_TLV_TAG;
279 : }
280 6 : tagNum = static_cast<uint8_t>(chip::TLV::TagNumFromTag(containerTag));
281 6 : if (tagNum == kAppVendorIdTag)
282 : {
283 3 : err = reader.Get(appVendorId);
284 : }
285 3 : else if (tagNum == kAppProductIdTag)
286 : {
287 3 : err = reader.Get(appProductId);
288 : }
289 : }
290 3 : if (err == CHIP_END_OF_TLV)
291 : {
292 3 : ChipLogProgress(AppServer, "TLV end of struct TLV");
293 3 : ReturnErrorOnFailure(reader.ExitContainer(outerContainerType));
294 : }
295 3 : if (appVendorId != 0)
296 : {
297 3 : mTargetAppInfos[mNumTargetAppInfos].vendorId = appVendorId;
298 3 : mTargetAppInfos[mNumTargetAppInfos].productId = appProductId;
299 3 : mNumTargetAppInfos++;
300 : }
301 : }
302 : else
303 : {
304 0 : ChipLogError(AppServer, "unrecognized tag %d", tagNum);
305 : }
306 : }
307 1 : if (err == CHIP_END_OF_TLV)
308 : {
309 1 : ChipLogProgress(AppServer, "TLV end of array");
310 1 : ReturnErrorOnFailure(reader.ExitContainer(listContainerType));
311 : }
312 : }
313 1 : break;
314 1 : case kNoPasscodeTag:
315 1 : err = reader.Get(mNoPasscode);
316 1 : break;
317 1 : case kCdUponPasscodeDialogTag:
318 1 : err = reader.Get(mCdUponPasscodeDialog);
319 1 : break;
320 1 : case kCommissionerPasscodeTag:
321 1 : err = reader.Get(mCommissionerPasscode);
322 1 : break;
323 1 : case kCommissionerPasscodeReadyTag:
324 1 : err = reader.Get(mCommissionerPasscodeReady);
325 1 : break;
326 1 : case kCancelPasscodeTag:
327 1 : err = reader.Get(mCancelPasscode);
328 1 : break;
329 : }
330 13 : if (err != CHIP_NO_ERROR)
331 : {
332 1 : ChipLogError(AppServer, "IdentificationDeclaration::ReadPayload read error %" CHIP_ERROR_FORMAT, err.Format());
333 : }
334 : }
335 :
336 1 : if (err == CHIP_END_OF_TLV)
337 : {
338 : // Exiting container
339 1 : ReturnErrorOnFailure(reader.ExitContainer(outerContainerType));
340 : }
341 : else
342 : {
343 0 : ChipLogError(AppServer, "IdentificationDeclaration::ReadPayload exiting early error %" CHIP_ERROR_FORMAT, err.Format());
344 : }
345 :
346 1 : ChipLogProgress(AppServer, "UDC TLV parse complete");
347 1 : return CHIP_NO_ERROR;
348 : }
349 :
350 : /**
351 : * Reset the connection state to a completely uninitialized status.
352 : */
353 1 : uint32_t CommissionerDeclaration::WritePayload(uint8_t * payloadBuffer, size_t payloadBufferSize)
354 : {
355 : CHIP_ERROR err;
356 :
357 1 : chip::TLV::TLVWriter writer;
358 :
359 1 : writer.Init(payloadBuffer, payloadBufferSize);
360 :
361 1 : chip::TLV::TLVType outerContainerType = chip::TLV::kTLVType_Structure;
362 1 : VerifyOrExit(CHIP_NO_ERROR ==
363 : (err = writer.StartContainer(chip::TLV::AnonymousTag(), chip::TLV::kTLVType_Structure, outerContainerType)),
364 : LogErrorOnFailure(err));
365 :
366 1 : VerifyOrExit(CHIP_NO_ERROR == (err = writer.Put(chip::TLV::ContextTag(kErrorCodeTag), GetErrorCode())), LogErrorOnFailure(err));
367 1 : VerifyOrExit(CHIP_NO_ERROR == (err = writer.PutBoolean(chip::TLV::ContextTag(kNeedsPasscodeTag), mNeedsPasscode)),
368 : LogErrorOnFailure(err));
369 1 : VerifyOrExit(CHIP_NO_ERROR == (err = writer.PutBoolean(chip::TLV::ContextTag(kNoAppsFoundTag), mNoAppsFound)),
370 : LogErrorOnFailure(err));
371 1 : VerifyOrExit(CHIP_NO_ERROR ==
372 : (err = writer.PutBoolean(chip::TLV::ContextTag(kPasscodeDialogDisplayedTag), mPasscodeDialogDisplayed)),
373 : LogErrorOnFailure(err));
374 1 : VerifyOrExit(CHIP_NO_ERROR == (err = writer.PutBoolean(chip::TLV::ContextTag(kCommissionerPasscodeTag), mCommissionerPasscode)),
375 : LogErrorOnFailure(err));
376 1 : VerifyOrExit(CHIP_NO_ERROR == (err = writer.PutBoolean(chip::TLV::ContextTag(kQRCodeDisplayedTag), mQRCodeDisplayed)),
377 : LogErrorOnFailure(err));
378 :
379 1 : VerifyOrExit(CHIP_NO_ERROR == (err = writer.EndContainer(outerContainerType)), LogErrorOnFailure(err));
380 1 : VerifyOrExit(CHIP_NO_ERROR == (err = writer.Finalize()), LogErrorOnFailure(err));
381 :
382 1 : ChipLogProgress(AppServer, "TLV write done");
383 :
384 1 : return writer.GetLengthWritten();
385 :
386 0 : exit:
387 0 : return 0;
388 : }
389 :
390 6 : void UserDirectedCommissioningServer::SetUDCClientProcessingState(char * instanceName, UDCClientProcessingState state)
391 : {
392 6 : UDCClientState * client = mUdcClients.FindUDCClientState(instanceName);
393 6 : if (client == nullptr)
394 : {
395 : CHIP_ERROR err;
396 3 : err = mUdcClients.CreateNewUDCClientState(instanceName, &client);
397 3 : if (err != CHIP_NO_ERROR)
398 : {
399 0 : ChipLogError(AppServer,
400 : "UserDirectedCommissioningServer::SetUDCClientProcessingState error creating new connection state");
401 0 : return;
402 : }
403 : }
404 :
405 6 : ChipLogDetail(AppServer, "SetUDCClientProcessingState instance=%s new state=%d", StringOrNullMarker(instanceName), (int) state);
406 :
407 6 : client->SetUDCClientProcessingState(state);
408 :
409 6 : mUdcClients.MarkUDCClientActive(client);
410 : }
411 :
412 6 : void UserDirectedCommissioningServer::OnCommissionableNodeFound(const Dnssd::DiscoveredNodeData & nodeData)
413 : {
414 6 : if (nodeData.resolutionData.numIPs == 0)
415 : {
416 0 : ChipLogError(AppServer, "OnCommissionableNodeFound no IP addresses returned for instance name=%s",
417 : nodeData.commissionData.instanceName);
418 0 : return;
419 : }
420 6 : if (nodeData.resolutionData.port == 0)
421 : {
422 0 : ChipLogError(AppServer, "OnCommissionableNodeFound no port returned for instance name=%s",
423 : nodeData.commissionData.instanceName);
424 0 : return;
425 : }
426 :
427 6 : UDCClientState * client = mUdcClients.FindUDCClientState(nodeData.commissionData.instanceName);
428 6 : if (client != nullptr && client->GetUDCClientProcessingState() == UDCClientProcessingState::kDiscoveringNode)
429 : {
430 2 : ChipLogDetail(AppServer, "OnCommissionableNodeFound instance: name=%s old_state=%d new_state=%d", client->GetInstanceName(),
431 : (int) client->GetUDCClientProcessingState(), (int) UDCClientProcessingState::kPromptingUser);
432 2 : client->SetUDCClientProcessingState(UDCClientProcessingState::kPromptingUser);
433 :
434 : #if INET_CONFIG_ENABLE_IPV4
435 : // prefer IPv4 if its an option
436 2 : bool foundV4 = false;
437 2 : for (unsigned i = 0; i < nodeData.resolutionData.numIPs; ++i)
438 : {
439 2 : if (nodeData.resolutionData.ipAddress[i].IsIPv4())
440 : {
441 2 : foundV4 = true;
442 2 : client->SetPeerAddress(
443 2 : chip::Transport::PeerAddress::UDP(nodeData.resolutionData.ipAddress[i], nodeData.resolutionData.port));
444 2 : break;
445 : }
446 : }
447 : // use IPv6 as last resort
448 2 : if (!foundV4)
449 : {
450 0 : client->SetPeerAddress(
451 0 : chip::Transport::PeerAddress::UDP(nodeData.resolutionData.ipAddress[0], nodeData.resolutionData.port));
452 : }
453 : #else // INET_CONFIG_ENABLE_IPV4
454 : // if we only support V6, then try to find a v6 address
455 : bool foundV6 = false;
456 : for (unsigned i = 0; i < nodeData.resolutionData.numIPs; ++i)
457 : {
458 : if (nodeData.resolutionData.ipAddress[i].IsIPv6())
459 : {
460 : foundV6 = true;
461 : client->SetPeerAddress(
462 : chip::Transport::PeerAddress::UDP(nodeData.resolutionData.ipAddress[i], nodeData.resolutionData.port));
463 : break;
464 : }
465 : }
466 : // last resort, try with what we have
467 : if (!foundV6)
468 : {
469 : ChipLogError(AppServer, "OnCommissionableNodeFound no v6 returned for instance name=%s",
470 : nodeData.commissionData.instanceName);
471 : client->SetPeerAddress(
472 : chip::Transport::PeerAddress::UDP(nodeData.resolutionData.ipAddress[0], nodeData.resolutionData.port));
473 : }
474 : #endif // INET_CONFIG_ENABLE_IPV4
475 :
476 2 : client->SetDeviceName(nodeData.commissionData.deviceName);
477 2 : client->SetLongDiscriminator(nodeData.commissionData.longDiscriminator);
478 2 : client->SetVendorId(nodeData.commissionData.vendorId);
479 2 : client->SetProductId(nodeData.commissionData.productId);
480 2 : client->SetRotatingId(nodeData.commissionData.rotatingId, nodeData.commissionData.rotatingIdLen);
481 :
482 : // Call the registered mUserConfirmationProvider, if any.
483 2 : if (mUserConfirmationProvider != nullptr)
484 : {
485 1 : mUserConfirmationProvider->OnUserDirectedCommissioningRequest(*client);
486 : }
487 : }
488 : }
489 :
490 0 : void UserDirectedCommissioningServer::PrintUDCClients()
491 : {
492 0 : for (uint8_t i = 0; i < kMaxUDCClients; i++)
493 : {
494 0 : UDCClientState * state = GetUDCClients().GetUDCClientState(i);
495 0 : if (state == nullptr)
496 : {
497 0 : ChipLogProgress(AppServer, "UDC Client[%d] null", i);
498 : }
499 : else
500 : {
501 : char addrBuffer[chip::Transport::PeerAddress::kMaxToStringSize];
502 0 : state->GetPeerAddress().ToString(addrBuffer);
503 :
504 0 : char rotatingIdString[chip::Dnssd::kMaxRotatingIdLen * 2 + 1] = "";
505 0 : Encoding::BytesToUppercaseHexString(state->GetRotatingId(), chip::Dnssd::kMaxRotatingIdLen, rotatingIdString,
506 : sizeof(rotatingIdString));
507 :
508 0 : ChipLogProgress(AppServer, "UDC Client[%d] instance=%s deviceName=%s address=%s, vid/pid=%d/%d disc=%d rid=%s", i,
509 : state->GetInstanceName(), state->GetDeviceName(), addrBuffer, state->GetVendorId(),
510 : state->GetProductId(), state->GetLongDiscriminator(), rotatingIdString);
511 : }
512 : }
513 0 : }
514 :
515 : } // namespace UserDirectedCommissioning
516 : } // namespace Protocols
517 : } // namespace chip
|