Line data Source code
1 : /*
2 : * Copyright (c) 2026 Project CHIP Authors
3 : * All rights reserved.
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : *
17 : */
18 :
19 : #include "ThreadMeshcopCommissionProxy.h"
20 :
21 : #include <lib/core/CHIPEncoding.h>
22 : #include <lib/dnssd/TxtFields.h>
23 : #include <lib/dnssd/minimal_mdns/core/QNameString.h> // nogncheck
24 : #include <lib/support/BytesToHex.h>
25 : #include <lib/support/CHIPMemString.h>
26 : #include <lib/support/CodeUtils.h>
27 : #include <lib/support/logging/CHIPLogging.h>
28 : #include <transport/raw/MessageHeader.h>
29 :
30 : #include <json/json.h>
31 :
32 : #include <errno.h>
33 : #include <inttypes.h>
34 : #include <netinet/in.h>
35 : #include <sys/socket.h>
36 : #include <unistd.h>
37 :
38 : #include <chrono>
39 : #include <thread>
40 :
41 : using namespace chip;
42 :
43 : namespace {
44 : /**
45 : * Internal OT Commissioner Logger implementation.
46 : */
47 : class CommissionerLogger : public ot::commissioner::Logger
48 : {
49 : public:
50 0 : void Log(ot::commissioner::LogLevel level, const std::string & region, const std::string & message) override
51 : {
52 0 : ChipLogProgress(Controller, "[ot-commissioner][%u][%s] %s", static_cast<unsigned>(level), region.c_str(), message.c_str());
53 0 : }
54 : };
55 :
56 : constexpr char kMatterCServiceSuffix[] = "_matterc._udp.local";
57 :
58 0 : uint64_t JoinerIdFromBytes(const std::vector<uint8_t> & bytes)
59 : {
60 0 : const uint8_t * buffer = bytes.data();
61 0 : return Encoding::BigEndian::Read64(buffer);
62 : }
63 :
64 0 : std::vector<uint8_t> DiscoveryCodeToVector(Thread::DiscoveryCode code)
65 : {
66 : uint8_t bytes[sizeof(uint64_t)];
67 0 : Encoding::BigEndian::Put64(bytes, code.AsUInt64());
68 0 : return std::vector<uint8_t>(bytes, bytes + sizeof(bytes));
69 : }
70 :
71 : } // namespace
72 :
73 : namespace chip {
74 : namespace Controller {
75 :
76 13 : ThreadMeshcopCommissionProxy::ThreadMeshcopCommissionProxy() : mState(State::kConnecting), mPromiseFulfilled(false)
77 : {
78 13 : mCommissioner = ot::commissioner::Commissioner::Create(*this);
79 13 : }
80 :
81 13 : ThreadMeshcopCommissionProxy::~ThreadMeshcopCommissionProxy()
82 : {
83 13 : std::unique_lock<std::recursive_mutex> lock(mMutex);
84 13 : if (mProxyFd != -1)
85 : {
86 0 : if (shutdown(mProxyFd, SHUT_RDWR) == 0 || errno != EBADF)
87 : {
88 0 : close(mProxyFd);
89 : }
90 :
91 0 : mProxyFd = -1;
92 : }
93 :
94 13 : if (mProxyThread.joinable())
95 : {
96 0 : lock.unlock();
97 0 : mProxyThread.join();
98 : }
99 13 : }
100 :
101 0 : void ThreadMeshcopCommissionProxy::ResetCommissionerForDiscovery()
102 : {
103 0 : std::unique_lock<std::recursive_mutex> lock(mMutex);
104 0 : if (mProxyFd != -1)
105 : {
106 0 : if (shutdown(mProxyFd, SHUT_RDWR) == 0 || errno != EBADF)
107 : {
108 0 : close(mProxyFd);
109 : }
110 0 : mProxyFd = -1;
111 : }
112 :
113 0 : if (mProxyThread.joinable())
114 : {
115 0 : lock.unlock();
116 0 : mProxyThread.join();
117 0 : lock.lock();
118 : }
119 :
120 0 : mServicePort = 0;
121 0 : mCommissioner = ot::commissioner::Commissioner::Create(*this);
122 0 : }
123 :
124 0 : void ThreadMeshcopCommissionProxy::SetState(State state)
125 : {
126 0 : mState = state;
127 0 : }
128 :
129 0 : void ThreadMeshcopCommissionProxy::OnHeader(mdns::Minimal::ConstHeaderRef & header)
130 : {
131 0 : ChipLogDetail(Controller, "mDNS Response: ID=%u, Answers=%u, Additional=%u", header.GetMessageId(), header.GetAnswerCount(),
132 : header.GetAdditionalCount());
133 0 : }
134 :
135 0 : void ThreadMeshcopCommissionProxy::OnQuery(const mdns::Minimal::QueryData & data)
136 : {
137 0 : if (mState != State::kDiscovering)
138 : {
139 0 : ChipLogProgress(Controller, "Received mDNS query but proxy is not in discovery state");
140 : }
141 :
142 0 : ChipLogDetail(Controller, "mDNS query: %s", mdns::Minimal::QNameString(data.GetName()).c_str());
143 0 : mNodeData.Set<Dnssd::CommissionNodeData>();
144 0 : }
145 :
146 0 : void ThreadMeshcopCommissionProxy::OnResource(mdns::Minimal::ResourceType section, const mdns::Minimal::ResourceData & data)
147 : {
148 0 : if (mState != State::kDiscovering)
149 : {
150 0 : return;
151 : }
152 :
153 0 : auto name = mdns::Minimal::QNameString(data.GetName());
154 0 : auto & commissionData = mNodeData.Get<Dnssd::CommissionNodeData>();
155 :
156 0 : commissionData.threadMeshcop = true;
157 :
158 0 : switch (data.GetType())
159 : {
160 0 : case mdns::Minimal::QType::A:
161 : case mdns::Minimal::QType::AAAA:
162 0 : Platform::CopyString(commissionData.hostName, name.c_str());
163 0 : break;
164 :
165 0 : case mdns::Minimal::QType::SRV: {
166 0 : mdns::Minimal::SrvRecord srv;
167 0 : if (!srv.Parse(data.GetData(), mDnsPacket))
168 : {
169 0 : ChipLogError(Controller, "Failed to parse mDNS SRV record");
170 0 : return;
171 : }
172 :
173 0 : if (!name.EndsWith(kMatterCServiceSuffix))
174 : {
175 0 : ChipLogDetail(Controller, "Ignoring non-Matter service: %s", name.c_str());
176 0 : return;
177 : }
178 :
179 : // Extract the instance label (portion before "._matterc._udp.local") for CommissionNodeData::instanceName.
180 0 : std::string fullName(name.c_str());
181 0 : constexpr size_t kMatterCServiceSuffixLen = sizeof(kMatterCServiceSuffix) - 1; // exclude null terminator
182 0 : if (fullName.length() >= kMatterCServiceSuffixLen)
183 : {
184 0 : fullName.erase(fullName.length() - kMatterCServiceSuffixLen);
185 : }
186 0 : Platform::CopyString(commissionData.instanceName, fullName.c_str());
187 :
188 0 : mServicePort = srv.GetPort();
189 :
190 0 : if (mProxyFd == -1)
191 : {
192 0 : CHIP_ERROR err = CreateProxySocket(commissionData);
193 0 : if (err != CHIP_NO_ERROR)
194 : {
195 0 : ChipLogError(Controller, "Failed to setup proxy socket: %" CHIP_ERROR_FORMAT, err.Format());
196 0 : SetState(State::kAborted);
197 : }
198 : }
199 0 : break;
200 0 : }
201 :
202 0 : case mdns::Minimal::QType::TXT:
203 0 : mdns::Minimal::ParseTxtRecord(data.GetData(), this);
204 0 : break;
205 :
206 0 : default:
207 0 : break;
208 : }
209 : }
210 :
211 0 : CHIP_ERROR ThreadMeshcopCommissionProxy::CreateProxySocket(chip::Dnssd::CommissionNodeData & commissionData)
212 : {
213 0 : mProxyFd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
214 0 : VerifyOrReturnError(mProxyFd >= 0, CHIP_ERROR_POSIX(errno));
215 :
216 0 : sockaddr_in6 addr = {};
217 0 : addr.sin6_family = AF_INET6;
218 0 : addr.sin6_port = 0;
219 0 : addr.sin6_addr = in6addr_loopback;
220 :
221 0 : if (bind(mProxyFd, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)) != 0)
222 : {
223 0 : close(mProxyFd);
224 0 : mProxyFd = -1;
225 0 : return CHIP_ERROR_POSIX(errno);
226 : }
227 :
228 0 : socklen_t addr_len = sizeof(addr);
229 0 : if (getsockname(mProxyFd, reinterpret_cast<struct sockaddr *>(&addr), &addr_len) == -1)
230 : {
231 0 : close(mProxyFd);
232 0 : mProxyFd = -1;
233 0 : return CHIP_ERROR_POSIX(errno);
234 : }
235 :
236 0 : commissionData.numIPs = 1;
237 0 : commissionData.port = ntohs(addr.sin6_port);
238 0 : commissionData.ipAddress[0] = Inet::IPAddress::FromSockAddr(addr);
239 0 : commissionData.interfaceId = Inet::InterfaceId::FromIPAddress(commissionData.ipAddress[0]);
240 :
241 0 : ChipLogProgress(Controller, "Proxy socket created on port %u", commissionData.port);
242 0 : return CHIP_NO_ERROR;
243 : }
244 :
245 0 : std::string ThreadMeshcopCommissionProxy::GetLastDiscoveryDiagnosticJson()
246 : {
247 0 : DiscoveryDiagnostic diagnostic;
248 : {
249 0 : std::lock_guard<std::recursive_mutex> lock(mMutex);
250 0 : diagnostic = mLastDiscoveryDiagnostic;
251 0 : }
252 :
253 0 : Json::Value root(Json::objectValue);
254 0 : Json::StreamWriterBuilder writerBuilder;
255 :
256 : char steeringDataHex[ot::commissioner::kMaxSteeringDataLength * 2 + 1];
257 : char rotatingIdHex[Dnssd::kMaxRotatingIdLen * 2 + 1];
258 0 : if (Encoding::BytesToUppercaseHexString(diagnostic.steeringData.data(), diagnostic.steeringData.size(), steeringDataHex,
259 0 : sizeof(steeringDataHex)) != CHIP_NO_ERROR)
260 : {
261 0 : diagnostic.valid = false;
262 : }
263 0 : if (Encoding::BytesToUppercaseHexString(diagnostic.commissionData.rotatingId, diagnostic.commissionData.rotatingIdLen,
264 0 : rotatingIdHex, sizeof(rotatingIdHex)) != CHIP_NO_ERROR)
265 : {
266 0 : diagnostic.valid = false;
267 : }
268 0 : root["valid"] = diagnostic.valid;
269 0 : if (!diagnostic.valid)
270 : {
271 0 : return Json::writeString(writerBuilder, root);
272 : }
273 :
274 0 : root["requested_discriminator_type"] = diagnostic.requestedShort ? "short" : "long";
275 0 : root["requested_discriminator"] = static_cast<Json::Value::UInt>(diagnostic.requestedValue);
276 0 : root["expected_long_discriminator"] = static_cast<Json::Value::UInt>(diagnostic.expectedLongValue);
277 0 : root["discovery_code"] = static_cast<Json::Value::UInt64>(diagnostic.discoveryCode);
278 0 : root["steering_data_hex"] = steeringDataHex;
279 0 : root["joiner_id"] = static_cast<Json::Value::UInt64>(diagnostic.joinerId);
280 0 : root["joiner_udp_port"] = static_cast<Json::Value::UInt>(diagnostic.joinerUdpPort);
281 :
282 0 : Json::Value dnsAnnouncement(Json::objectValue);
283 0 : dnsAnnouncement["long_discriminator"] = static_cast<Json::Value::UInt>(diagnostic.commissionData.longDiscriminator);
284 0 : dnsAnnouncement["commissioning_mode"] = static_cast<Json::Value::UInt>(diagnostic.commissionData.commissioningMode);
285 0 : dnsAnnouncement["device_type"] = static_cast<Json::Value::UInt>(diagnostic.commissionData.deviceType);
286 0 : dnsAnnouncement["vendor_id"] = static_cast<Json::Value::UInt>(diagnostic.commissionData.vendorId);
287 0 : dnsAnnouncement["product_id"] = static_cast<Json::Value::UInt>(diagnostic.commissionData.productId);
288 0 : dnsAnnouncement["pairing_hint"] = static_cast<Json::Value::UInt>(diagnostic.commissionData.pairingHint);
289 0 : dnsAnnouncement["service_port"] = static_cast<Json::Value::UInt>(diagnostic.matterUdpPort);
290 0 : dnsAnnouncement["thread_meshcop"] = diagnostic.commissionData.threadMeshcop;
291 0 : dnsAnnouncement["supports_commissioner_generated_passcode"] = diagnostic.commissionData.supportsCommissionerGeneratedPasscode;
292 0 : dnsAnnouncement["instance_name"] = diagnostic.commissionData.instanceName;
293 0 : dnsAnnouncement["hostname"] = diagnostic.commissionData.hostName;
294 0 : dnsAnnouncement["rotating_id_hex"] = rotatingIdHex;
295 0 : root["dns_announcement"] = dnsAnnouncement;
296 :
297 0 : return Json::writeString(writerBuilder, root);
298 0 : }
299 :
300 0 : void ThreadMeshcopCommissionProxy::OnRecord(const mdns::Minimal::BytesRange & name, const mdns::Minimal::BytesRange & value)
301 : {
302 0 : ByteSpan key(name.Start(), name.Size());
303 0 : ByteSpan val(value.Start(), value.Size());
304 :
305 0 : Dnssd::FillNodeDataFromTxt(key, val, mNodeData.Get<Dnssd::CommissionNodeData>());
306 0 : }
307 :
308 0 : void ThreadMeshcopCommissionProxy::ProcessAnnouncement(const std::vector<uint8_t> & joinerIdBytes, uint16_t joinerPort,
309 : const std::vector<uint8_t> & payload)
310 : {
311 0 : std::lock_guard<std::recursive_mutex> lock(mMutex);
312 :
313 0 : if (mPromiseFulfilled)
314 : {
315 0 : return;
316 : }
317 :
318 0 : mNodeData.Set<Dnssd::CommissionNodeData>();
319 0 : mDnsPacket = mdns::Minimal::BytesRange(payload.data(), payload.data() + payload.size());
320 :
321 0 : if (!mdns::Minimal::ParsePacket(mDnsPacket, this))
322 : {
323 0 : ChipLogError(Controller, "Failed to parse joiner mDNS announcement");
324 0 : return;
325 : }
326 :
327 0 : uint32_t discoveredDiscriminator = mNodeData.Get<Dnssd::CommissionNodeData>().longDiscriminator;
328 0 : ChipLogProgress(Controller, "Discovered joiner with discriminator: %u", discoveredDiscriminator);
329 :
330 0 : if (!mExpectedDiscriminator.MatchesLongDiscriminator(static_cast<uint16_t>(discoveredDiscriminator)))
331 : {
332 0 : ChipLogProgress(Controller, "Discriminator mismatch (Expected %u, Got %u). Ignoring announcement.",
333 : mExpectedDiscriminator.GetLongValue(), discoveredDiscriminator);
334 0 : return;
335 : }
336 :
337 0 : mDiscoveredNodePromise.set_value(mNodeData);
338 0 : mPromiseFulfilled = true;
339 :
340 0 : mLastDiscoveryDiagnostic.valid = true;
341 0 : mLastDiscoveryDiagnostic.joinerId = JoinerIdFromBytes(joinerIdBytes);
342 0 : mLastDiscoveryDiagnostic.joinerUdpPort = joinerPort;
343 0 : mLastDiscoveryDiagnostic.matterUdpPort = mServicePort;
344 0 : mLastDiscoveryDiagnostic.commissionData = mNodeData.Get<Dnssd::CommissionNodeData>();
345 :
346 0 : SetState(State::kDiscovered);
347 :
348 0 : if (mProxyThread.joinable())
349 : {
350 0 : mProxyThread.join();
351 : }
352 :
353 0 : mProxyThread = std::thread([id = joinerIdBytes, this]() {
354 : struct sockaddr_storage addr;
355 0 : socklen_t len = sizeof(addr);
356 : uint8_t buf[chip::detail::kMaxIPPacketSizeBytes];
357 : ssize_t received;
358 :
359 0 : while ((received = recvfrom(mProxyFd, buf, sizeof(buf), 0, reinterpret_cast<struct sockaddr *>(&addr), &len)) > 0)
360 : {
361 0 : switch (mState)
362 : {
363 0 : case State::kDiscovered: {
364 0 : int rval = connect(mProxyFd, reinterpret_cast<struct sockaddr *>(&addr), len);
365 0 : if (rval < 0)
366 : {
367 0 : ChipLogError(Controller, "Failed to connect to Matter Commissioner: %s", strerror(errno));
368 0 : continue;
369 : }
370 0 : SetState(State::kCommissioning);
371 : FALLTHROUGH;
372 : }
373 :
374 0 : case State::kCommissioning: {
375 0 : std::vector<uint8_t> pkt(buf, buf + received);
376 :
377 0 : auto error = mCommissioner->SendToJoiner(id, mServicePort, pkt);
378 0 : if (error != ot::commissioner::ErrorCode::kNone)
379 : {
380 0 : ChipLogError(Controller, "Failed to send packet to joiner: %s", error.GetMessage().c_str());
381 0 : return;
382 : }
383 0 : break;
384 0 : }
385 0 : default:
386 0 : ChipLogError(Controller, "Invalid CommissionProxy state: %d", static_cast<int>(mState.load()));
387 0 : return;
388 : }
389 : }
390 0 : });
391 0 : }
392 :
393 0 : void ThreadMeshcopCommissionProxy::OnJoinerMessage(const std::vector<uint8_t> & joinerIdBytes, uint16_t joinerPort,
394 : const std::vector<uint8_t> & payload)
395 : {
396 0 : std::lock_guard<std::recursive_mutex> lock(mMutex);
397 :
398 0 : if (joinerIdBytes.size() != sizeof(uint64_t) || mState == State::kAborted)
399 : {
400 0 : return;
401 : }
402 :
403 0 : uint64_t joinerId = JoinerIdFromBytes(joinerIdBytes);
404 0 : ChipLogDetail(Controller, "Message from joiner 0x%" PRIx64 " on port %u", joinerId, joinerPort);
405 :
406 0 : if (mJoinerId == 0)
407 : {
408 0 : mJoinerId = joinerId;
409 : }
410 0 : else if (mJoinerId != joinerId)
411 : {
412 0 : ChipLogProgress(Controller, "Ignoring message from unexpected joiner 0x%" PRIx64, joinerId);
413 0 : return;
414 : }
415 :
416 0 : switch (mState)
417 : {
418 0 : case State::kCommissioning:
419 0 : if (mProxyFd != -1)
420 : {
421 0 : if (send(mProxyFd, payload.data(), payload.size(), 0) < 0)
422 : {
423 0 : ChipLogError(Controller, "Failed to forward packet to local proxy: %s", strerror(errno));
424 0 : SetState(State::kAborted);
425 : }
426 : }
427 0 : break;
428 0 : case State::kAborted:
429 0 : break;
430 0 : case State::kConnecting:
431 : // First message from joiner is usually the mDNS announcement
432 0 : SetState(State::kDiscovering);
433 : FALLTHROUGH;
434 0 : case State::kDiscovering:
435 0 : ProcessAnnouncement(joinerIdBytes, joinerPort, payload);
436 0 : break;
437 0 : case State::kDiscovered:
438 0 : ChipLogProgress(Controller, "WARNING ignore unsolicited messages after joiner is already discovered");
439 0 : break;
440 : }
441 0 : }
442 :
443 0 : ot::commissioner::CommissionerDataset ThreadMeshcopCommissionProxy::MakeCommissionerDataset(Thread::DiscoveryCode code)
444 : {
445 0 : ot::commissioner::CommissionerDataset dataset;
446 :
447 0 : dataset.mJoinerUdpPort = ot::commissioner::kDefaultJoinerUdpPort;
448 0 : dataset.mPresentFlags |= ot::commissioner::CommissionerDataset::kJoinerUdpPortBit;
449 0 : dataset.mPresentFlags &=
450 : ~(ot::commissioner::CommissionerDataset::kSessionIdBit | ot::commissioner::CommissionerDataset::kBorderAgentLocatorBit);
451 :
452 0 : if (code.IsAny())
453 : {
454 0 : dataset.mSteeringData = std::vector<uint8_t>{ 0xff };
455 : }
456 : else
457 : {
458 0 : std::vector<uint8_t> steeringData(ot::commissioner::kMaxSteeringDataLength);
459 0 : ot::commissioner::Commissioner::AddJoiner(steeringData, DiscoveryCodeToVector(code));
460 0 : dataset.mSteeringData = steeringData;
461 0 : }
462 :
463 0 : dataset.mPresentFlags |= ot::commissioner::CommissionerDataset::kSteeringDataBit;
464 0 : return dataset;
465 : }
466 0 : CHIP_ERROR ThreadMeshcopCommissionProxy::InitializeCommissioner(ByteSpan & pskc)
467 : {
468 0 : VerifyOrReturnError(pskc.size() == Thread::kSizePSKc, CHIP_ERROR_INVALID_ARGUMENT);
469 0 : ot::commissioner::Config config;
470 0 : config.mLogger = std::make_shared<CommissionerLogger>();
471 0 : config.mEnableCcm = false;
472 0 : config.mProxyMode = true;
473 0 : config.mPSKc = std::vector<uint8_t>(pskc.begin(), pskc.end());
474 :
475 0 : auto error = mCommissioner->Init(config);
476 0 : if (error != ot::commissioner::ErrorCode::kNone)
477 : {
478 0 : ChipLogError(Controller, "OT Commissioner Init failed: %s", error.GetMessage().c_str());
479 0 : return CHIP_ERROR_INTERNAL;
480 : }
481 0 : return CHIP_NO_ERROR;
482 0 : }
483 :
484 0 : CHIP_ERROR ThreadMeshcopCommissionProxy::Discover(ByteSpan & pskc, const Transport::PeerAddress & peerAddr,
485 : const Thread::DiscoveryCode code, SetupDiscriminator expectedDiscriminator,
486 : Dnssd::DiscoveredNodeData & nodeData, uint16_t timeout)
487 : {
488 : using ot::commissioner::Error;
489 :
490 0 : Error error;
491 0 : ResetCommissionerForDiscovery();
492 :
493 : // Reset the promise and state for a new discovery session
494 0 : std::future<Dnssd::DiscoveredNodeData> future;
495 : {
496 0 : std::lock_guard<std::recursive_mutex> lock(mMutex);
497 0 : mExpectedDiscriminator = expectedDiscriminator;
498 0 : SetState(State::kConnecting);
499 0 : mDiscoveredNodePromise = std::promise<Dnssd::DiscoveredNodeData>();
500 0 : future = mDiscoveredNodePromise.get_future();
501 0 : mPromiseFulfilled = false;
502 0 : mJoinerId = 0;
503 0 : mLastDiscoveryDiagnostic = DiscoveryDiagnostic();
504 0 : mLastDiscoveryDiagnostic.requestedShort = expectedDiscriminator.IsShortDiscriminator();
505 0 : mLastDiscoveryDiagnostic.requestedValue =
506 0 : mLastDiscoveryDiagnostic.requestedShort ? expectedDiscriminator.GetShortValue() : expectedDiscriminator.GetLongValue();
507 0 : mLastDiscoveryDiagnostic.expectedLongValue =
508 0 : expectedDiscriminator.IsShortDiscriminator() ? 0 : expectedDiscriminator.GetLongValue();
509 0 : mLastDiscoveryDiagnostic.discoveryCode = code.AsUInt64();
510 0 : }
511 :
512 0 : ReturnErrorOnFailure(InitializeCommissioner(pskc));
513 :
514 : {
515 0 : std::string id;
516 : char host[Inet::IPAddress::kMaxStringLength];
517 0 : peerAddr.GetIPAddress().ToString(host);
518 :
519 0 : ChipLogProgress(Controller, "Petitioning Thread Border Agent at %s:%u", host, peerAddr.GetPort());
520 0 : error = mCommissioner->Petition(id, std::string(host), peerAddr.GetPort());
521 0 : if (error != ot::commissioner::ErrorCode::kNone)
522 : {
523 0 : ChipLogError(Controller, "Petition failed: %s", error.GetMessage().c_str());
524 0 : SetState(State::kAborted);
525 0 : return CHIP_ERROR_INTERNAL;
526 : }
527 :
528 0 : ChipLogProgress(Controller, "Thread Commissioner active with ID: %s", id.c_str());
529 0 : }
530 :
531 0 : auto commissionerDataset = MakeCommissionerDataset(code);
532 : {
533 0 : std::lock_guard<std::recursive_mutex> lock(mMutex);
534 0 : mLastDiscoveryDiagnostic.steeringData = commissionerDataset.mSteeringData;
535 0 : }
536 :
537 0 : error = mCommissioner->SetCommissionerDataset(commissionerDataset);
538 0 : if (error != ot::commissioner::ErrorCode::kNone)
539 : {
540 0 : ChipLogError(Controller, "Failed to set Steering Data: %s", error.GetMessage().c_str());
541 0 : SetState(State::kAborted);
542 0 : return CHIP_ERROR_INTERNAL;
543 : }
544 :
545 0 : ChipLogProgress(Controller, "Waiting for mDNS announcement from joiner...");
546 0 : auto waitDuration = std::chrono::seconds(timeout);
547 0 : if (future.wait_for(waitDuration) == std::future_status::timeout)
548 : {
549 0 : ChipLogError(Controller, "Timed out waiting for joiner mDNS announcement after %u seconds", timeout);
550 0 : SetState(State::kAborted);
551 0 : return CHIP_ERROR_TIMEOUT;
552 : }
553 0 : nodeData = future.get();
554 0 : return CHIP_NO_ERROR;
555 0 : }
556 : } // namespace Controller
557 : } // namespace chip
|