3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2019 Nest Labs, Inc.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
22 * Contains non-inline method definitions for the
23 * GenericThreadStackManagerImpl_OpenThread<> template.
26 #ifndef GENERIC_THREAD_STACK_MANAGER_IMPL_OPENTHREAD_IPP
27 #define GENERIC_THREAD_STACK_MANAGER_IMPL_OPENTHREAD_IPP
29 #include <openthread/cli.h>
30 #include <openthread/dataset.h>
31 #include <openthread/joiner.h>
32 #include <openthread/link.h>
33 #include <openthread/netdata.h>
34 #include <openthread/tasklet.h>
35 #include <openthread/thread.h>
37 #if CHIP_DEVICE_CONFIG_THREAD_FTD
38 #include <openthread/dataset_ftd.h>
39 #include <openthread/thread_ftd.h>
42 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT
43 #include <openthread/srp_client.h>
46 #include <core/CHIPEncoding.h>
47 #include <platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h>
48 #include <platform/OpenThread/OpenThreadUtils.h>
49 #include <platform/ThreadStackManager.h>
50 #include <platform/internal/CHIPDeviceLayerInternal.h>
51 #include <platform/internal/DeviceNetworkInfo.h>
52 #include <support/CodeUtils.h>
53 #include <support/ReturnMacros.h>
54 #include <support/logging/CHIPLogging.h>
56 extern "C" void otSysProcessDrivers(otInstance * aInstance);
59 namespace DeviceLayer {
62 // Fully instantiate the generic implementation class in whatever compilation unit includes this file.
63 template class GenericThreadStackManagerImpl_OpenThread<ThreadStackManagerImpl>;
66 * Called by OpenThread to alert the ThreadStackManager of a change in the state of the Thread stack.
68 * By default, applications never need to call this method directly. However, applications that
69 * wish to receive OpenThread state change call-backs directly from OpenThread (e.g. by calling
70 * otSetStateChangedCallback() with their own callback function) can call this method to pass
71 * state change events to the ThreadStackManager.
73 template <class ImplClass>
74 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::OnOpenThreadStateChange(uint32_t flags, void * context)
76 ChipDeviceEvent event;
77 event.Type = DeviceEventType::kThreadStateChange;
78 event.ThreadStateChange.RoleChanged = (flags & OT_CHANGED_THREAD_ROLE) != 0;
79 event.ThreadStateChange.AddressChanged = (flags & (OT_CHANGED_IP6_ADDRESS_ADDED | OT_CHANGED_IP6_ADDRESS_REMOVED)) != 0;
80 event.ThreadStateChange.NetDataChanged = (flags & OT_CHANGED_THREAD_NETDATA) != 0;
81 event.ThreadStateChange.ChildNodesChanged = (flags & (OT_CHANGED_THREAD_CHILD_ADDED | OT_CHANGED_THREAD_CHILD_REMOVED)) != 0;
82 event.ThreadStateChange.OpenThread.Flags = flags;
84 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT
85 if (event.ThreadStateChange.AddressChanged)
87 const otSrpClientHostInfo * hostInfo =
88 otSrpClientGetHostInfo(static_cast<GenericThreadStackManagerImpl_OpenThread *>(context)->Impl()->OTInstance());
89 if (hostInfo && hostInfo->mName)
91 static_cast<GenericThreadStackManagerImpl_OpenThread *>(context)->Impl()->_SetupSrpHost(hostInfo->mName);
96 PlatformMgr().PostEvent(&event);
99 template <class ImplClass>
100 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::_ProcessThreadActivity(void)
102 otTaskletsProcess(mOTInst);
103 otSysProcessDrivers(mOTInst);
106 template <class ImplClass>
107 bool GenericThreadStackManagerImpl_OpenThread<ImplClass>::_HaveRouteToAddress(const IPAddress & destAddr)
112 Impl()->LockThreadStack();
114 // No routing of IPv4 over Thread.
115 VerifyOrExit(!destAddr.IsIPv4(), res = false);
117 // If the device is attached to a Thread network...
118 if (IsThreadAttachedNoLock())
120 // Link-local addresses are always presumed to be routable, provided the device is attached.
121 if (destAddr.IsIPv6LinkLocal())
126 // Iterate over the routes known to the OpenThread stack looking for a route that covers the
127 // destination address. If found, consider the address routable.
128 // Ignore any routes advertised by this device.
129 // If the destination address is a ULA, ignore default routes. Border routers advertising
130 // default routes are not expected to be capable of routing CHIP fabric ULAs unless they
131 // advertise those routes specifically.
134 otNetworkDataIterator routeIter = OT_NETWORK_DATA_ITERATOR_INIT;
135 otExternalRouteConfig routeConfig;
136 const bool destIsULA = destAddr.IsIPv6ULA();
138 while ((otErr = otNetDataGetNextRoute(Impl()->OTInstance(), &routeIter, &routeConfig)) == OT_ERROR_NONE)
140 const IPPrefix prefix = ToIPPrefix(routeConfig.mPrefix);
142 prefix.IPAddr.ToString(addrStr);
143 if (!routeConfig.mNextHopIsThisDevice && (!destIsULA || routeConfig.mPrefix.mLength > 0) &&
144 ToIPPrefix(routeConfig.mPrefix).MatchAddress(destAddr))
155 Impl()->UnlockThreadStack();
160 template <class ImplClass>
161 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::_OnPlatformEvent(const ChipDeviceEvent * event)
163 if (event->Type == DeviceEventType::kThreadStateChange)
165 Impl()->LockThreadStack();
167 #if CHIP_DETAIL_LOGGING
169 LogOpenThreadStateChange(mOTInst, event->ThreadStateChange.OpenThread.Flags);
171 #endif // CHIP_DETAIL_LOGGING
173 Impl()->UnlockThreadStack();
177 template <class ImplClass>
178 bool GenericThreadStackManagerImpl_OpenThread<ImplClass>::_IsThreadEnabled(void)
180 otDeviceRole curRole;
182 Impl()->LockThreadStack();
183 curRole = otThreadGetDeviceRole(mOTInst);
184 Impl()->UnlockThreadStack();
186 return (curRole != OT_DEVICE_ROLE_DISABLED);
189 template <class ImplClass>
190 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_SetThreadEnabled(bool val)
192 otError otErr = OT_ERROR_NONE;
194 Impl()->LockThreadStack();
196 bool isEnabled = (otThreadGetDeviceRole(mOTInst) != OT_DEVICE_ROLE_DISABLED);
197 bool isIp6Enabled = otIp6IsEnabled(mOTInst);
199 if (val && !isIp6Enabled)
201 otErr = otIp6SetEnabled(mOTInst, val);
202 VerifyOrExit(otErr == OT_ERROR_NONE, );
205 if (val != isEnabled)
207 otErr = otThreadSetEnabled(mOTInst, val);
208 VerifyOrExit(otErr == OT_ERROR_NONE, );
211 if (!val && isIp6Enabled)
213 otErr = otIp6SetEnabled(mOTInst, val);
214 VerifyOrExit(otErr == OT_ERROR_NONE, );
218 Impl()->UnlockThreadStack();
220 return MapOpenThreadError(otErr);
223 template <class ImplClass>
224 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_SetThreadProvision(const DeviceNetworkInfo & netInfo)
226 otError otErr = OT_ERROR_FAILED;
227 otOperationalDataset newDataset;
229 // Form a Thread operational dataset from the given network parameters.
230 memset(&newDataset, 0, sizeof(newDataset));
232 if (netInfo.ThreadNetworkName[0] != 0)
234 strncpy((char *) newDataset.mNetworkName.m8, netInfo.ThreadNetworkName, sizeof(newDataset.mNetworkName.m8));
235 newDataset.mComponents.mIsNetworkNamePresent = true;
238 if (netInfo.FieldPresent.ThreadExtendedPANId)
240 memcpy(newDataset.mExtendedPanId.m8, netInfo.ThreadExtendedPANId, sizeof(newDataset.mExtendedPanId.m8));
241 newDataset.mComponents.mIsExtendedPanIdPresent = true;
244 if (netInfo.FieldPresent.ThreadMeshPrefix)
246 memcpy(newDataset.mMeshLocalPrefix.m8, netInfo.ThreadMeshPrefix, sizeof(newDataset.mMeshLocalPrefix.m8));
247 newDataset.mComponents.mIsMeshLocalPrefixPresent = true;
250 memcpy(newDataset.mMasterKey.m8, netInfo.ThreadMasterKey, sizeof(newDataset.mMasterKey.m8));
251 newDataset.mComponents.mIsMasterKeyPresent = true;
253 if (netInfo.FieldPresent.ThreadPSKc)
255 memcpy(newDataset.mPskc.m8, netInfo.ThreadPSKc, sizeof(newDataset.mPskc.m8));
256 newDataset.mComponents.mIsPskcPresent = true;
259 if (netInfo.ThreadPANId != kThreadPANId_NotSpecified)
261 newDataset.mPanId = netInfo.ThreadPANId;
262 newDataset.mComponents.mIsPanIdPresent = true;
265 if (netInfo.ThreadChannel != kThreadChannel_NotSpecified)
267 newDataset.mChannel = netInfo.ThreadChannel;
268 newDataset.mComponents.mIsChannelPresent = true;
271 if (netInfo.ThreadDatasetTimestamp != 0)
273 newDataset.mActiveTimestamp = netInfo.ThreadDatasetTimestamp;
274 newDataset.mComponents.mIsActiveTimestampPresent = true;
277 // Set the dataset as the active dataset for the node.
278 Impl()->LockThreadStack();
279 otErr = otDatasetSetActive(mOTInst, &newDataset);
280 Impl()->UnlockThreadStack();
282 // post an event alerting other subsystems about change in provisioning state
283 ChipDeviceEvent event;
284 event.Type = DeviceEventType::kServiceProvisioningChange;
285 event.ServiceProvisioningChange.IsServiceProvisioned = true;
286 PlatformMgr().PostEvent(&event);
288 return MapOpenThreadError(otErr);
291 template <class ImplClass>
292 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_SetThreadProvision(const uint8_t * operationalDataset,
293 size_t operationalDatasetLen)
295 otError otErr = OT_ERROR_FAILED;
296 otOperationalDatasetTlvs datasetTlv;
298 VerifyOrReturnError(operationalDatasetLen <= sizeof(datasetTlv.mTlvs), CHIP_ERROR_MESSAGE_TOO_LONG);
299 // A compile time check to avoid misbehavior if the openthread implementation changed over time.
300 static_assert(sizeof(datasetTlv.mTlvs) <= UINT8_MAX);
301 memcpy(datasetTlv.mTlvs, operationalDataset, operationalDatasetLen);
302 datasetTlv.mLength = static_cast<uint8_t>(operationalDatasetLen);
304 // Set the dataset as the active dataset for the node.
305 Impl()->LockThreadStack();
306 otErr = otDatasetSetActiveTlvs(mOTInst, &datasetTlv);
307 Impl()->UnlockThreadStack();
309 // post an event alerting other subsystems about change in provisioning state
310 ChipDeviceEvent event;
311 event.Type = DeviceEventType::kServiceProvisioningChange;
312 event.ServiceProvisioningChange.IsServiceProvisioned = true;
313 PlatformMgr().PostEvent(&event);
315 return MapOpenThreadError(otErr);
318 template <class ImplClass>
319 bool GenericThreadStackManagerImpl_OpenThread<ImplClass>::_IsThreadProvisioned(void)
323 Impl()->LockThreadStack();
324 provisioned = otDatasetIsCommissioned(mOTInst);
325 Impl()->UnlockThreadStack();
330 template <class ImplClass>
331 bool GenericThreadStackManagerImpl_OpenThread<ImplClass>::_IsThreadAttached(void)
333 otDeviceRole curRole;
335 Impl()->LockThreadStack();
336 curRole = otThreadGetDeviceRole(mOTInst);
337 Impl()->UnlockThreadStack();
339 return (curRole != OT_DEVICE_ROLE_DISABLED && curRole != OT_DEVICE_ROLE_DETACHED);
342 template <class ImplClass>
343 ConnectivityManager::ThreadDeviceType GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetThreadDeviceType(void)
345 ConnectivityManager::ThreadDeviceType deviceType;
347 Impl()->LockThreadStack();
349 const otLinkModeConfig linkMode = otThreadGetLinkMode(mOTInst);
351 #if CHIP_DEVICE_CONFIG_THREAD_FTD
352 if (linkMode.mDeviceType && otThreadIsRouterEligible(mOTInst))
353 ExitNow(deviceType = ConnectivityManager::kThreadDeviceType_Router);
354 if (linkMode.mDeviceType)
355 ExitNow(deviceType = ConnectivityManager::kThreadDeviceType_FullEndDevice);
357 if (linkMode.mRxOnWhenIdle)
358 ExitNow(deviceType = ConnectivityManager::kThreadDeviceType_MinimalEndDevice);
360 ExitNow(deviceType = ConnectivityManager::kThreadDeviceType_SleepyEndDevice);
363 Impl()->UnlockThreadStack();
368 template <class ImplClass>
370 GenericThreadStackManagerImpl_OpenThread<ImplClass>::_SetThreadDeviceType(ConnectivityManager::ThreadDeviceType deviceType)
372 CHIP_ERROR err = CHIP_NO_ERROR;
373 otLinkModeConfig linkMode;
377 #if CHIP_DEVICE_CONFIG_THREAD_FTD
378 case ConnectivityManager::kThreadDeviceType_Router:
379 case ConnectivityManager::kThreadDeviceType_FullEndDevice:
381 case ConnectivityManager::kThreadDeviceType_MinimalEndDevice:
382 case ConnectivityManager::kThreadDeviceType_SleepyEndDevice:
385 ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
388 #if CHIP_PROGRESS_LOGGING
391 const char * deviceTypeStr;
394 case ConnectivityManager::kThreadDeviceType_Router:
395 deviceTypeStr = "ROUTER";
397 case ConnectivityManager::kThreadDeviceType_FullEndDevice:
398 deviceTypeStr = "FULL END DEVICE";
400 case ConnectivityManager::kThreadDeviceType_MinimalEndDevice:
401 deviceTypeStr = "MINIMAL END DEVICE";
403 case ConnectivityManager::kThreadDeviceType_SleepyEndDevice:
404 deviceTypeStr = "SLEEPY END DEVICE";
407 deviceTypeStr = "(unknown)";
410 ChipLogProgress(DeviceLayer, "Setting OpenThread device type to %s", deviceTypeStr);
413 #endif // CHIP_PROGRESS_LOGGING
415 Impl()->LockThreadStack();
417 linkMode = otThreadGetLinkMode(mOTInst);
421 #if CHIP_DEVICE_CONFIG_THREAD_FTD
422 case ConnectivityManager::kThreadDeviceType_Router:
423 case ConnectivityManager::kThreadDeviceType_FullEndDevice:
424 linkMode.mDeviceType = true;
425 linkMode.mRxOnWhenIdle = true;
426 otThreadSetRouterEligible(mOTInst, deviceType == ConnectivityManager::kThreadDeviceType_Router);
429 case ConnectivityManager::kThreadDeviceType_MinimalEndDevice:
430 linkMode.mDeviceType = false;
431 linkMode.mRxOnWhenIdle = true;
433 case ConnectivityManager::kThreadDeviceType_SleepyEndDevice:
434 linkMode.mDeviceType = false;
435 linkMode.mRxOnWhenIdle = false;
441 otThreadSetLinkMode(mOTInst, linkMode);
443 Impl()->UnlockThreadStack();
449 template <class ImplClass>
450 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetThreadPollingConfig(
451 ConnectivityManager::ThreadPollingConfig & pollingConfig)
453 pollingConfig = mPollingConfig;
456 template <class ImplClass>
457 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_SetThreadPollingConfig(
458 const ConnectivityManager::ThreadPollingConfig & pollingConfig)
460 mPollingConfig = pollingConfig;
461 return Impl()->AdjustPollingInterval();
464 template <class ImplClass>
465 bool GenericThreadStackManagerImpl_OpenThread<ImplClass>::_HaveMeshConnectivity(void)
468 otDeviceRole curRole;
470 Impl()->LockThreadStack();
472 // Get the current Thread role.
473 curRole = otThreadGetDeviceRole(mOTInst);
475 // If Thread is disabled, or the node is detached, then the node has no mesh connectivity.
476 if (curRole == OT_DEVICE_ROLE_DISABLED || curRole == OT_DEVICE_ROLE_DETACHED)
481 // If the node is a child, that implies the existence of a parent node which provides connectivity
483 else if (curRole == OT_DEVICE_ROLE_CHILD)
488 // Otherwise, if the node is acting as a router, scan the Thread neighbor table looking for at least
489 // one other node that is also acting as router.
492 otNeighborInfoIterator neighborIter = OT_NEIGHBOR_INFO_ITERATOR_INIT;
493 otNeighborInfo neighborInfo;
497 while (otThreadGetNextNeighborInfo(mOTInst, &neighborIter, &neighborInfo) == OT_ERROR_NONE)
499 if (!neighborInfo.mIsChild)
507 Impl()->UnlockThreadStack();
512 template <class ImplClass>
513 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::_OnMessageLayerActivityChanged(bool messageLayerIsActive)
515 Impl()->AdjustPollingInterval();
518 template <class ImplClass>
519 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetAndLogThreadStatsCounters(void)
521 CHIP_ERROR err = CHIP_NO_ERROR;
523 const otMacCounters * macCounters;
524 const otIpCounters * ipCounters;
525 otOperationalDataset activeDataset;
528 Impl()->LockThreadStack();
530 role = otThreadGetDeviceRole(mOTInst);
531 ChipLogProgress(DeviceLayer, "Thread Role: %d\n", role);
533 if (otDatasetIsCommissioned(mOTInst))
535 otErr = otDatasetGetActive(mOTInst, &activeDataset);
536 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
538 if (activeDataset.mComponents.mIsChannelPresent)
540 ChipLogProgress(DeviceLayer, "Thread Channel: %d\n", activeDataset.mChannel);
544 macCounters = otLinkGetCounters(mOTInst);
546 ChipLogProgress(DeviceLayer,
549 "MAC Rx Unicast: %d\n"
550 "MAC Rx Broadcast: %d\n"
552 "MAC Rx Data Polls: %d\n"
553 "MAC Rx Beacons: %d\n"
554 "MAC Rx Beacon Reqs: %d\n"
556 "MAC Rx Filtered Whitelist: %d\n"
557 "MAC Rx Filtered DestAddr: %d\n",
558 macCounters->mRxTotal, macCounters->mRxUnicast, macCounters->mRxBroadcast, macCounters->mRxData,
559 macCounters->mRxDataPoll, macCounters->mRxBeacon, macCounters->mRxBeaconRequest, macCounters->mRxOther,
560 macCounters->mRxAddressFiltered, macCounters->mRxDestAddrFiltered);
562 ChipLogProgress(DeviceLayer,
565 "MAC Tx Unicast: %d\n"
566 "MAC Tx Broadcast: %d\n"
568 "MAC Tx Data Polls: %d\n"
569 "MAC Tx Beacons: %d\n"
570 "MAC Tx Beacon Reqs: %d\n"
573 "MAC Tx CCA Fail: %d\n",
574 macCounters->mTxTotal, macCounters->mTxUnicast, macCounters->mTxBroadcast, macCounters->mTxData,
575 macCounters->mTxDataPoll, macCounters->mTxBeacon, macCounters->mTxBeaconRequest, macCounters->mTxOther,
576 macCounters->mTxRetry, macCounters->mTxErrCca);
578 ChipLogProgress(DeviceLayer,
579 "Failure Counters:\n"
580 "MAC Rx Decrypt Fail: %d\n"
581 "MAC Rx No Frame Fail: %d\n"
582 "MAC Rx Unknown Neighbor Fail: %d\n"
583 "MAC Rx Invalid Src Addr Fail: %d\n"
584 "MAC Rx FCS Fail: %d\n"
585 "MAC Rx Other Fail: %d\n",
586 macCounters->mRxErrSec, macCounters->mRxErrNoFrame, macCounters->mRxErrUnknownNeighbor,
587 macCounters->mRxErrInvalidSrcAddr, macCounters->mRxErrFcs, macCounters->mRxErrOther);
589 ipCounters = otThreadGetIp6Counters(mOTInst);
591 ChipLogProgress(DeviceLayer,
593 "IP Tx Success: %d\n"
594 "IP Rx Success: %d\n"
597 ipCounters->mTxSuccess, ipCounters->mRxSuccess, ipCounters->mTxFailure, ipCounters->mRxFailure);
599 Impl()->UnlockThreadStack();
605 template <class ImplClass>
606 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetAndLogThreadTopologyMinimal(void)
608 CHIP_ERROR err = CHIP_NO_ERROR;
610 const otExtAddress * extAddress;
613 uint16_t leaderRouterId;
614 uint32_t partitionId;
615 int8_t parentAverageRssi;
616 int8_t parentLastRssi;
619 Impl()->LockThreadStack();
621 rloc16 = otThreadGetRloc16(mOTInst);
623 // Router ID is the top 6 bits of the RLOC
624 routerId = (rloc16 >> 10) & 0x3f;
626 leaderRouterId = otThreadGetLeaderRouterId(mOTInst);
628 otErr = otThreadGetParentAverageRssi(mOTInst, &parentAverageRssi);
629 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
631 otErr = otThreadGetParentLastRssi(mOTInst, &parentLastRssi);
632 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
634 partitionId = otThreadGetPartitionId(mOTInst);
636 extAddress = otLinkGetExtendedAddress(mOTInst);
638 instantRssi = otPlatRadioGetRssi(mOTInst);
640 ChipLogProgress(DeviceLayer,
644 "Leader Router ID: %u\n"
645 "Parent Avg RSSI: %d\n"
646 "Parent Last RSSI: %d\n"
648 "Extended Address: %02X%02X:%02X%02X:%02X%02X:%02X%02X\n"
649 "Instant RSSI: %d\n",
650 rloc16, routerId, leaderRouterId, parentAverageRssi, parentLastRssi, partitionId, extAddress->m8[0],
651 extAddress->m8[1], extAddress->m8[2], extAddress->m8[3], extAddress->m8[4], extAddress->m8[5],
652 extAddress->m8[6], extAddress->m8[7], instantRssi);
654 Impl()->UnlockThreadStack();
657 if (err != CHIP_NO_ERROR)
659 ChipLogError(DeviceLayer, "GetAndLogThreadTopologyMinimul failed: %d", err);
665 #define TELEM_NEIGHBOR_TABLE_SIZE (64)
666 #define TELEM_PRINT_BUFFER_SIZE (64)
668 #if CHIP_DEVICE_CONFIG_THREAD_FTD
669 template <class ImplClass>
670 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetAndLogThreadTopologyFull()
672 CHIP_ERROR err = CHIP_NO_ERROR;
674 otIp6Address * leaderAddr = NULL;
675 uint8_t * networkData = NULL;
676 uint8_t * stableNetworkData = NULL;
677 uint8_t networkDataLen = 0;
678 uint8_t stableNetworkDataLen = 0;
679 const otExtAddress * extAddress;
680 otNeighborInfo neighborInfo[TELEM_NEIGHBOR_TABLE_SIZE];
681 otNeighborInfoIterator iter;
682 otNeighborInfoIterator iterCopy;
683 char printBuf[TELEM_PRINT_BUFFER_SIZE];
686 uint16_t leaderRouterId;
687 uint8_t leaderWeight;
688 uint8_t leaderLocalWeight;
689 uint32_t partitionId;
691 uint8_t networkDataVersion;
692 uint8_t stableNetworkDataVersion;
693 uint16_t neighborTableSize = 0;
694 uint16_t childTableSize = 0;
696 Impl()->LockThreadStack();
698 rloc16 = otThreadGetRloc16(mOTInst);
700 // Router ID is the top 6 bits of the RLOC
701 routerId = (rloc16 >> 10) & 0x3f;
703 leaderRouterId = otThreadGetLeaderRouterId(mOTInst);
705 otErr = otThreadGetLeaderRloc(mOTInst, leaderAddr);
706 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
708 leaderWeight = otThreadGetLeaderWeight(mOTInst);
710 leaderLocalWeight = otThreadGetLocalLeaderWeight(mOTInst);
712 otErr = otNetDataGet(mOTInst, false, networkData, &networkDataLen);
713 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
715 networkDataVersion = otNetDataGetVersion(mOTInst);
717 otErr = otNetDataGet(mOTInst, true, stableNetworkData, &stableNetworkDataLen);
718 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
720 stableNetworkDataVersion = otNetDataGetStableVersion(mOTInst);
722 extAddress = otLinkGetExtendedAddress(mOTInst);
724 partitionId = otThreadGetPartitionId(mOTInst);
726 instantRssi = otPlatRadioGetRssi(mOTInst);
728 iter = OT_NEIGHBOR_INFO_ITERATOR_INIT;
729 iterCopy = OT_NEIGHBOR_INFO_ITERATOR_INIT;
730 neighborTableSize = 0;
733 while (otThreadGetNextNeighborInfo(mOTInst, &iter, &neighborInfo[iter]) == OT_ERROR_NONE)
736 if (neighborInfo[iterCopy].mIsChild)
743 ChipLogProgress(DeviceLayer,
747 "Leader Router ID: %u\n"
748 "Leader Address: %02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X\n"
749 "Leader Weight: %d\n"
750 "Local Leader Weight: %d\n"
751 "Network Data Len: %d\n"
752 "Network Data Version: %d\n"
753 "Stable Network Data Version: %d\n"
754 "Extended Address: %02X%02X:%02X%02X:%02X%02X:%02X%02X\n"
757 "Neighbor Table Length: %d\n"
758 "Child Table Length: %d\n",
759 rloc16, routerId, leaderRouterId, leaderAddr->mFields.m8[0], leaderAddr->mFields.m8[1],
760 leaderAddr->mFields.m8[2], leaderAddr->mFields.m8[3], leaderAddr->mFields.m8[4], leaderAddr->mFields.m8[5],
761 leaderAddr->mFields.m8[6], leaderAddr->mFields.m8[7], leaderAddr->mFields.m8[8], leaderAddr->mFields.m8[9],
762 leaderAddr->mFields.m8[10], leaderAddr->mFields.m8[11], leaderAddr->mFields.m8[12], leaderAddr->mFields.m8[13],
763 leaderAddr->mFields.m8[14], leaderAddr->mFields.m8[15], leaderWeight, leaderLocalWeight, networkDataLen,
764 networkDataVersion, stableNetworkDataVersion, extAddress->m8[0], extAddress->m8[1], extAddress->m8[2],
765 extAddress->m8[3], extAddress->m8[4], extAddress->m8[5], extAddress->m8[6], extAddress->m8[7], partitionId,
766 instantRssi, neighborTableSize, childTableSize);
768 // Handle each neighbor event seperatly.
769 for (uint32_t i = 0; i < neighborTableSize; i++)
771 otNeighborInfo * neighbor = &neighborInfo[i];
773 if (neighbor->mIsChild)
775 otChildInfo * child = NULL;
776 otErr = otThreadGetChildInfoById(mOTInst, neighbor->mRloc16, child);
777 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
779 snprintf(printBuf, TELEM_PRINT_BUFFER_SIZE, ", Timeout: %10" PRIu32 " NetworkDataVersion: %3" PRIu8, child->mTimeout,
780 child->mNetworkDataVersion);
787 ChipLogProgress(DeviceLayer,
788 "TopoEntry[%u]: %02X%02X:%02X%02X:%02X%02X:%02X%02X\n"
794 "LinkFrameCounter: %10d\n"
795 "MleFrameCounter: %10d\n"
798 "FullNetworkData: %c\n"
800 i, neighbor->mExtAddress.m8[0], neighbor->mExtAddress.m8[1], neighbor->mExtAddress.m8[2],
801 neighbor->mExtAddress.m8[3], neighbor->mExtAddress.m8[4], neighbor->mExtAddress.m8[5],
802 neighbor->mExtAddress.m8[6], neighbor->mExtAddress.m8[7], neighbor->mRloc16, neighbor->mAge,
803 neighbor->mLinkQualityIn, neighbor->mAverageRssi, neighbor->mLastRssi, neighbor->mLinkFrameCounter,
804 neighbor->mMleFrameCounter, neighbor->mRxOnWhenIdle ? 'Y' : 'n', neighbor->mFullThreadDevice ? 'Y' : 'n',
805 neighbor->mFullNetworkData ? 'Y' : 'n', neighbor->mIsChild ? 'Y' : 'n', printBuf);
808 Impl()->UnlockThreadStack();
811 if (err != CHIP_NO_ERROR)
813 ChipLogError(DeviceLayer, "GetAndLogThreadTopologyFull failed: %s", err);
817 #else // CHIP_DEVICE_CONFIG_THREAD_FTD
818 template <class ImplClass>
819 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetAndLogThreadTopologyFull()
821 return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
825 template <class ImplClass>
826 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetPrimary802154MACAddress(uint8_t * buf)
828 const otExtAddress * extendedAddr = otLinkGetExtendedAddress(mOTInst);
829 memcpy(buf, extendedAddr, sizeof(otExtAddress));
830 return CHIP_NO_ERROR;
833 template <class ImplClass>
834 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetFactoryAssignedEUI64(uint8_t (&buf)[8])
836 otExtAddress extendedAddr;
837 otLinkGetFactoryAssignedIeeeEui64(mOTInst, &extendedAddr);
838 memcpy(buf, extendedAddr.m8, sizeof(extendedAddr.m8));
839 return CHIP_NO_ERROR;
842 template <class ImplClass>
843 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetExternalIPv6Address(chip::Inet::IPAddress & addr)
845 const otNetifAddress * otAddresses = otIp6GetUnicastAddresses(mOTInst);
847 // Look only for the global unicast addresses, not internally assigned by Thread.
848 for (const otNetifAddress * otAddress = otAddresses; otAddress != nullptr; otAddress = otAddress->mNext)
850 if (otAddress->mValid)
852 switch (otAddress->mAddressOrigin)
854 case OT_ADDRESS_ORIGIN_THREAD:
856 case OT_ADDRESS_ORIGIN_SLAAC:
857 case OT_ADDRESS_ORIGIN_DHCPV6:
858 case OT_ADDRESS_ORIGIN_MANUAL:
859 addr = ToIPAddress(otAddress->mAddress);
860 return CHIP_NO_ERROR;
867 return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
870 template <class ImplClass>
871 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::DoInit(otInstance * otInst)
873 CHIP_ERROR err = CHIP_NO_ERROR;
874 otError otErr = OT_ERROR_NONE;
876 // Arrange for OpenThread errors to be translated to text.
877 RegisterOpenThreadErrorFormatter();
880 mPollingConfig.Clear();
882 // If an OpenThread instance hasn't been supplied, call otInstanceInitSingle() to
883 // create or acquire a singleton instance of OpenThread.
886 otInst = otInstanceInitSingle();
887 VerifyOrExit(otInst != NULL, err = MapOpenThreadError(OT_ERROR_FAILED));
890 #if !defined(__ZEPHYR__) && !defined(ENABLE_CHIP_SHELL) && !defined(PW_RPC_ENABLED)
891 otCliUartInit(otInst);
896 // Arrange for OpenThread to call the OnOpenThreadStateChange method whenever a
897 // state change occurs. Note that we reference the OnOpenThreadStateChange method
898 // on the concrete implementation class so that that class can override the default
899 // method implementation if it chooses to.
900 otErr = otSetStateChangedCallback(otInst, ImplClass::OnOpenThreadStateChange, this);
901 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
903 // Enable automatic assignment of Thread advertised addresses.
904 #if OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE
905 otIp6SetSlaacEnabled(otInst, true);
908 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT
909 otSrpClientSetCallback(mOTInst, &OnSrpClientNotification, nullptr);
910 otSrpClientEnableAutoStartMode(mOTInst, &OnSrpClientStateChange, nullptr);
911 memset(&mSrpClient, 0, sizeof(mSrpClient));
912 #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT
914 // If the Thread stack has been provisioned, but is not currently enabled, enable it now.
915 if (otThreadGetDeviceRole(mOTInst) == OT_DEVICE_ROLE_DISABLED && otDatasetIsCommissioned(otInst))
917 // Enable the Thread IPv6 interface.
918 otErr = otIp6SetEnabled(otInst, true);
919 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
921 otErr = otThreadSetEnabled(otInst, true);
922 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
924 ChipLogProgress(DeviceLayer, "OpenThread ifconfig up and thread start");
928 ChipLogProgress(DeviceLayer, "OpenThread started: %s", otThreadErrorToString(otErr));
932 template <class ImplClass>
933 bool GenericThreadStackManagerImpl_OpenThread<ImplClass>::IsThreadAttachedNoLock(void)
935 otDeviceRole curRole = otThreadGetDeviceRole(mOTInst);
936 return (curRole != OT_DEVICE_ROLE_DISABLED && curRole != OT_DEVICE_ROLE_DETACHED);
939 template <class ImplClass>
940 bool GenericThreadStackManagerImpl_OpenThread<ImplClass>::IsThreadInterfaceUpNoLock(void)
942 return otIp6IsEnabled(mOTInst);
945 template <class ImplClass>
946 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::AdjustPollingInterval(void)
948 CHIP_ERROR err = CHIP_NO_ERROR;
950 uint32_t newPollingIntervalMS = mPollingConfig.InactivePollingIntervalMS;
952 if (newPollingIntervalMS != 0)
954 Impl()->LockThreadStack();
956 uint32_t curPollingIntervalMS = otLinkGetPollPeriod(mOTInst);
958 if (newPollingIntervalMS != curPollingIntervalMS)
960 otError otErr = otLinkSetPollPeriod(mOTInst, newPollingIntervalMS);
961 err = MapOpenThreadError(otErr);
964 Impl()->UnlockThreadStack();
966 if (newPollingIntervalMS != curPollingIntervalMS)
968 ChipLogProgress(DeviceLayer, "OpenThread polling interval set to %" PRId32 "ms", newPollingIntervalMS);
975 template <class ImplClass>
976 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::_ErasePersistentInfo(void)
978 ChipLogProgress(DeviceLayer, "Erasing Thread persistent info...");
979 Impl()->LockThreadStack();
980 otThreadSetEnabled(mOTInst, false);
981 otInstanceErasePersistentInfo(mOTInst);
982 Impl()->UnlockThreadStack();
985 template <class ImplClass>
986 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::OnJoinerComplete(otError aError, void * aContext)
988 static_cast<GenericThreadStackManagerImpl_OpenThread *>(aContext)->OnJoinerComplete(aError);
991 template <class ImplClass>
992 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::OnJoinerComplete(otError aError)
994 ChipLogProgress(DeviceLayer, "Join Thread network: %s", otThreadErrorToString(aError));
996 if (aError == OT_ERROR_NONE)
998 otError error = otThreadSetEnabled(mOTInst, true);
1000 ChipLogProgress(DeviceLayer, "Start Thread network: %s", otThreadErrorToString(error));
1004 template <class ImplClass>
1005 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_JoinerStart(void)
1007 CHIP_ERROR error = CHIP_NO_ERROR;
1009 Impl()->LockThreadStack();
1010 VerifyOrExit(!otDatasetIsCommissioned(mOTInst) && otThreadGetDeviceRole(mOTInst) == OT_DEVICE_ROLE_DISABLED,
1011 error = MapOpenThreadError(OT_ERROR_INVALID_STATE));
1012 VerifyOrExit(otJoinerGetState(mOTInst) == OT_JOINER_STATE_IDLE, error = MapOpenThreadError(OT_ERROR_BUSY));
1014 if (!otIp6IsEnabled(mOTInst))
1016 SuccessOrExit(error = MapOpenThreadError(otIp6SetEnabled(mOTInst, true)));
1020 otJoinerDiscerner discerner;
1021 uint16_t discriminator;
1023 SuccessOrExit(error = ConfigurationMgr().GetSetupDiscriminator(discriminator));
1024 discerner.mLength = 12;
1025 discerner.mValue = discriminator;
1027 ChipLogProgress(DeviceLayer, "Joiner Discerner: %u", discriminator);
1028 otJoinerSetDiscerner(mOTInst, &discerner);
1035 SuccessOrExit(error = ConfigurationMgr().GetSetupPinCode(pincode));
1036 snprintf(pskd.m8, sizeof(pskd.m8) - 1, "%09" PRIu32, pincode);
1038 ChipLogProgress(DeviceLayer, "Joiner PSKd: %s", pskd.m8);
1039 error = MapOpenThreadError(otJoinerStart(mOTInst, pskd.m8, NULL, NULL, NULL, NULL, NULL,
1040 &GenericThreadStackManagerImpl_OpenThread::OnJoinerComplete, this));
1044 Impl()->UnlockThreadStack();
1046 ChipLogProgress(DeviceLayer, "Joiner start: %s", chip::ErrorStr(error));
1051 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT
1053 static_assert(OPENTHREAD_API_VERSION >= 80, "SRP Client requires a more recent OpenThread version");
1055 template <class ImplClass>
1056 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::OnSrpClientNotification(otError aError,
1057 const otSrpClientHostInfo * aHostInfo,
1058 const otSrpClientService * aServices,
1059 const otSrpClientService * aRemovedServices,
1064 case OT_ERROR_NONE: {
1065 ChipLogProgress(DeviceLayer, "OnSrpClientNotification: Last requested operation completed successfully");
1067 if (aRemovedServices)
1069 otSrpClientService * otService = const_cast<otSrpClientService *>(aRemovedServices);
1070 otSrpClientService * next = nullptr;
1071 using Service = typename SrpClient::Service;
1073 // Free memory for all removed services.
1076 next = otService->mNext;
1077 auto service = reinterpret_cast<Service *>(reinterpret_cast<size_t>(otService) - offsetof(Service, mService));
1078 memset(service, 0, sizeof(Service));
1080 } while (otService);
1084 case OT_ERROR_PARSE:
1085 ChipLogError(DeviceLayer, "OnSrpClientNotification: Parsing operaton failed");
1087 case OT_ERROR_NOT_FOUND:
1088 ChipLogError(DeviceLayer, "OnSrpClientNotification: Domain name or RRset does not exist");
1090 case OT_ERROR_NOT_IMPLEMENTED:
1091 ChipLogError(DeviceLayer, "OnSrpClientNotification: Server does not support query type");
1093 case OT_ERROR_SECURITY:
1094 ChipLogError(DeviceLayer, "OnSrpClientNotification: Operation refused for security reasons");
1096 case OT_ERROR_DUPLICATED:
1097 ChipLogError(DeviceLayer, "OnSrpClientNotification: Domain name or RRset is duplicated");
1099 case OT_ERROR_RESPONSE_TIMEOUT:
1100 ChipLogError(DeviceLayer, "OnSrpClientNotification: Timed out waiting on server response");
1102 case OT_ERROR_INVALID_ARGS:
1103 ChipLogError(DeviceLayer, "OnSrpClientNotification: Invalid service structure detected");
1105 case OT_ERROR_NO_BUFS:
1106 ChipLogError(DeviceLayer, "OnSrpClientNotification: Insufficient buffer to handle message");
1108 case OT_ERROR_FAILED:
1109 ChipLogError(DeviceLayer, "OnSrpClientNotification: Internal server error occurred");
1112 ChipLogError(DeviceLayer, "OnSrpClientNotification: Unknown error occurred");
1117 template <class ImplClass>
1118 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::OnSrpClientStateChange(const otSockAddr * aServerSockAddr,
1121 if (aServerSockAddr)
1123 ChipLogProgress(DeviceLayer, "SRP Client was started, as detected server addressed: %x:%x:%x:%x:%x:%x:%x:%x",
1124 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[0]),
1125 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[1]),
1126 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[2]),
1127 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[3]),
1128 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[4]),
1129 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[5]),
1130 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[6]),
1131 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[7]));
1135 ChipLogProgress(DeviceLayer, "SRP Client was stopped, because current server is no longer detected.");
1139 template <class ImplClass>
1140 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_AddSrpService(const char * aInstanceName, const char * aName,
1141 uint16_t aPort, chip::Mdns::TextEntry * aTxtEntries,
1142 size_t aTxtEntiresSize, uint32_t aLeaseInterval,
1143 uint32_t aKeyLeaseInterval)
1145 CHIP_ERROR error = CHIP_NO_ERROR;
1146 typename SrpClient::Service * srpService = nullptr;
1148 Impl()->LockThreadStack();
1150 VerifyOrExit(aInstanceName, error = CHIP_ERROR_INVALID_ARGUMENT);
1151 VerifyOrExit(strlen(aInstanceName) < SrpClient::kMaxInstanceNameSize, error = CHIP_ERROR_INVALID_STRING_LENGTH);
1152 VerifyOrExit(aName, error = CHIP_ERROR_INVALID_ARGUMENT);
1153 VerifyOrExit(strlen(aName) < SrpClient::kMaxNameSize, error = CHIP_ERROR_INVALID_STRING_LENGTH);
1155 // Check if service with desired instance name already exists and try to find empty slot in array for new service
1156 for (typename SrpClient::Service & service : mSrpClient.mServices)
1158 if (strcmp(service.mInstanceName, "") == 0)
1160 // Assign first empty slot in array for a new service.
1161 srpService = srpService ? srpService : &service;
1165 VerifyOrExit((strcmp(service.mInstanceName, aInstanceName) != 0) || (strcmp(service.mName, aName) != 0),
1166 error = MapOpenThreadError(OT_ERROR_DUPLICATED));
1170 // Verify is there an empty place for new service.
1171 VerifyOrExit(srpService, error = MapOpenThreadError(OT_ERROR_NO_BUFS));
1173 otSrpClientSetLeaseInterval(mOTInst, aLeaseInterval);
1174 otSrpClientSetKeyLeaseInterval(mOTInst, aKeyLeaseInterval);
1176 memcpy(srpService->mInstanceName, aInstanceName, strlen(aInstanceName) + 1);
1177 srpService->mService.mInstanceName = srpService->mInstanceName;
1179 memcpy(srpService->mName, aName, strlen(aName) + 1);
1180 srpService->mService.mName = srpService->mName;
1182 srpService->mService.mPort = aPort;
1184 // Check if there are some optional text entries to add.
1185 if (aTxtEntries && aTxtEntiresSize != 0)
1187 VerifyOrExit(aTxtEntiresSize <= SrpClient::kMaxTxtEntriesNumber, error = CHIP_ERROR_INVALID_LIST_LENGTH);
1189 srpService->mService.mNumTxtEntries = static_cast<uint8_t>(aTxtEntiresSize);
1191 for (uint8_t entryId = 0; entryId < aTxtEntiresSize; entryId++)
1193 VerifyOrExit(aTxtEntries[entryId].mDataSize <= SrpClient::kMaxTxtValueSize, error = CHIP_ERROR_BUFFER_TOO_SMALL);
1194 VerifyOrExit((strlen(aTxtEntries[entryId].mKey) + 1) <= SrpClient::kMaxTxtKeySize, error = CHIP_ERROR_BUFFER_TOO_SMALL);
1196 srpService->mTxtEntries[entryId].mValueLength = static_cast<uint8_t>(aTxtEntries[entryId].mDataSize);
1197 memcpy(&(srpService->mTxtValueBuffers[entryId][0]), aTxtEntries[entryId].mData, aTxtEntries[entryId].mDataSize);
1198 srpService->mTxtEntries[entryId].mValue = &(srpService->mTxtValueBuffers[entryId][0]);
1200 memcpy(&(srpService->mTxtKeyBuffers[entryId][0]), aTxtEntries[entryId].mKey, strlen(aTxtEntries[entryId].mKey) + 1);
1201 srpService->mTxtEntries[entryId].mKey = &(srpService->mTxtKeyBuffers[entryId][0]);
1204 srpService->mService.mTxtEntries = srpService->mTxtEntries;
1207 error = MapOpenThreadError(otSrpClientAddService(mOTInst, &(srpService->mService)));
1210 Impl()->UnlockThreadStack();
1215 template <class ImplClass>
1216 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_RemoveSrpService(const char * aInstanceName, const char * aName)
1218 CHIP_ERROR error = CHIP_NO_ERROR;
1219 typename SrpClient::Service * srpService = nullptr;
1221 Impl()->LockThreadStack();
1223 VerifyOrExit(aInstanceName, error = CHIP_ERROR_INVALID_ARGUMENT);
1224 VerifyOrExit(strlen(aInstanceName) < SrpClient::kMaxInstanceNameSize, error = CHIP_ERROR_INVALID_STRING_LENGTH);
1225 VerifyOrExit(aName, error = CHIP_ERROR_INVALID_ARGUMENT);
1226 VerifyOrExit(strlen(aName) < SrpClient::kMaxNameSize, error = CHIP_ERROR_INVALID_STRING_LENGTH);
1228 // Check if service to remove exists.
1229 for (typename SrpClient::Service & service : mSrpClient.mServices)
1231 if ((strcmp(service.mInstanceName, aInstanceName) == 0) && (strcmp(service.mName, aName) == 0))
1233 srpService = &service;
1238 VerifyOrExit(srpService, error = MapOpenThreadError(OT_ERROR_NOT_FOUND));
1240 error = MapOpenThreadError(otSrpClientRemoveService(mOTInst, &(srpService->mService)));
1243 Impl()->UnlockThreadStack();
1248 template <class ImplClass>
1249 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_SetupSrpHost(const char * aHostName)
1251 CHIP_ERROR error = CHIP_NO_ERROR;
1252 Inet::IPAddress hostAddress;
1254 Impl()->LockThreadStack();
1256 VerifyOrExit(aHostName, error = CHIP_ERROR_INVALID_ARGUMENT);
1257 VerifyOrExit(strlen(aHostName) < SrpClient::kMaxHostNameSize, error = CHIP_ERROR_INVALID_STRING_LENGTH);
1259 memcpy(mSrpClient.mHostName, aHostName, strlen(aHostName) + 1);
1260 error = MapOpenThreadError(otSrpClientSetHostName(mOTInst, aHostName));
1261 SuccessOrExit(error);
1263 // Check if device has any external IPv6 assigned. If not, host will be set without IPv6 addresses
1264 // and updated later on.
1265 if (ThreadStackMgr().GetExternalIPv6Address(hostAddress) == CHIP_NO_ERROR)
1267 memcpy(&mSrpClient.mHostAddress.mFields.m32, hostAddress.Addr, sizeof(hostAddress.Addr));
1268 error = MapOpenThreadError(otSrpClientSetHostAddresses(mOTInst, &mSrpClient.mHostAddress, 1));
1272 Impl()->UnlockThreadStack();
1277 #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT
1279 } // namespace Internal
1280 } // namespace DeviceLayer
1283 #endif // GENERIC_THREAD_STACK_MANAGER_IMPL_OPENTHREAD_IPP