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/logging/CHIPLogging.h>
55 extern "C" void otSysProcessDrivers(otInstance * aInstance);
58 namespace DeviceLayer {
61 // Fully instantiate the generic implementation class in whatever compilation unit includes this file.
62 template class GenericThreadStackManagerImpl_OpenThread<ThreadStackManagerImpl>;
65 * Called by OpenThread to alert the ThreadStackManager of a change in the state of the Thread stack.
67 * By default, applications never need to call this method directly. However, applications that
68 * wish to receive OpenThread state change call-backs directly from OpenThread (e.g. by calling
69 * otSetStateChangedCallback() with their own callback function) can call this method to pass
70 * state change events to the ThreadStackManager.
72 template <class ImplClass>
73 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::OnOpenThreadStateChange(uint32_t flags, void * context)
75 ChipDeviceEvent event;
76 event.Type = DeviceEventType::kThreadStateChange;
77 event.ThreadStateChange.RoleChanged = (flags & OT_CHANGED_THREAD_ROLE) != 0;
78 event.ThreadStateChange.AddressChanged = (flags & (OT_CHANGED_IP6_ADDRESS_ADDED | OT_CHANGED_IP6_ADDRESS_REMOVED)) != 0;
79 event.ThreadStateChange.NetDataChanged = (flags & OT_CHANGED_THREAD_NETDATA) != 0;
80 event.ThreadStateChange.ChildNodesChanged = (flags & (OT_CHANGED_THREAD_CHILD_ADDED | OT_CHANGED_THREAD_CHILD_REMOVED)) != 0;
81 event.ThreadStateChange.OpenThread.Flags = flags;
83 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT
84 if (event.ThreadStateChange.AddressChanged)
86 const otSrpClientHostInfo * hostInfo =
87 otSrpClientGetHostInfo(static_cast<GenericThreadStackManagerImpl_OpenThread *>(context)->Impl()->OTInstance());
88 if (hostInfo && hostInfo->mName)
90 static_cast<GenericThreadStackManagerImpl_OpenThread *>(context)->Impl()->_SetupSrpHost(hostInfo->mName);
95 PlatformMgr().PostEvent(&event);
98 template <class ImplClass>
99 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::_ProcessThreadActivity(void)
101 otTaskletsProcess(mOTInst);
102 otSysProcessDrivers(mOTInst);
105 template <class ImplClass>
106 bool GenericThreadStackManagerImpl_OpenThread<ImplClass>::_HaveRouteToAddress(const IPAddress & destAddr)
111 Impl()->LockThreadStack();
113 // No routing of IPv4 over Thread.
114 VerifyOrExit(!destAddr.IsIPv4(), res = false);
116 // If the device is attached to a Thread network...
117 if (IsThreadAttachedNoLock())
119 // Link-local addresses are always presumed to be routable, provided the device is attached.
120 if (destAddr.IsIPv6LinkLocal())
125 // Iterate over the routes known to the OpenThread stack looking for a route that covers the
126 // destination address. If found, consider the address routable.
127 // Ignore any routes advertised by this device.
128 // If the destination address is a ULA, ignore default routes. Border routers advertising
129 // default routes are not expected to be capable of routing CHIP fabric ULAs unless they
130 // advertise those routes specifically.
133 otNetworkDataIterator routeIter = OT_NETWORK_DATA_ITERATOR_INIT;
134 otExternalRouteConfig routeConfig;
135 const bool destIsULA = destAddr.IsIPv6ULA();
137 while ((otErr = otNetDataGetNextRoute(Impl()->OTInstance(), &routeIter, &routeConfig)) == OT_ERROR_NONE)
139 const IPPrefix prefix = ToIPPrefix(routeConfig.mPrefix);
141 prefix.IPAddr.ToString(addrStr);
142 if (!routeConfig.mNextHopIsThisDevice && (!destIsULA || routeConfig.mPrefix.mLength > 0) &&
143 ToIPPrefix(routeConfig.mPrefix).MatchAddress(destAddr))
154 Impl()->UnlockThreadStack();
159 template <class ImplClass>
160 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::_OnPlatformEvent(const ChipDeviceEvent * event)
162 if (event->Type == DeviceEventType::kThreadStateChange)
164 Impl()->LockThreadStack();
166 #if CHIP_DETAIL_LOGGING
168 LogOpenThreadStateChange(mOTInst, event->ThreadStateChange.OpenThread.Flags);
170 #endif // CHIP_DETAIL_LOGGING
172 Impl()->UnlockThreadStack();
176 template <class ImplClass>
177 bool GenericThreadStackManagerImpl_OpenThread<ImplClass>::_IsThreadEnabled(void)
179 otDeviceRole curRole;
181 Impl()->LockThreadStack();
182 curRole = otThreadGetDeviceRole(mOTInst);
183 Impl()->UnlockThreadStack();
185 return (curRole != OT_DEVICE_ROLE_DISABLED);
188 template <class ImplClass>
189 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_SetThreadEnabled(bool val)
191 otError otErr = OT_ERROR_NONE;
193 Impl()->LockThreadStack();
195 bool isEnabled = (otThreadGetDeviceRole(mOTInst) != OT_DEVICE_ROLE_DISABLED);
196 bool isIp6Enabled = otIp6IsEnabled(mOTInst);
198 if (val && !isIp6Enabled)
200 otErr = otIp6SetEnabled(mOTInst, val);
201 VerifyOrExit(otErr == OT_ERROR_NONE, );
204 if (val != isEnabled)
206 otErr = otThreadSetEnabled(mOTInst, val);
207 VerifyOrExit(otErr == OT_ERROR_NONE, );
210 if (!val && isIp6Enabled)
212 otErr = otIp6SetEnabled(mOTInst, val);
213 VerifyOrExit(otErr == OT_ERROR_NONE, );
217 Impl()->UnlockThreadStack();
219 return MapOpenThreadError(otErr);
222 template <class ImplClass>
223 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_SetThreadProvision(const DeviceNetworkInfo & netInfo)
225 otError otErr = OT_ERROR_FAILED;
226 otOperationalDataset newDataset;
228 // Form a Thread operational dataset from the given network parameters.
229 memset(&newDataset, 0, sizeof(newDataset));
231 if (netInfo.ThreadNetworkName[0] != 0)
233 strncpy((char *) newDataset.mNetworkName.m8, netInfo.ThreadNetworkName, sizeof(newDataset.mNetworkName.m8));
234 newDataset.mComponents.mIsNetworkNamePresent = true;
237 if (netInfo.FieldPresent.ThreadExtendedPANId)
239 memcpy(newDataset.mExtendedPanId.m8, netInfo.ThreadExtendedPANId, sizeof(newDataset.mExtendedPanId.m8));
240 newDataset.mComponents.mIsExtendedPanIdPresent = true;
243 if (netInfo.FieldPresent.ThreadMeshPrefix)
245 memcpy(newDataset.mMeshLocalPrefix.m8, netInfo.ThreadMeshPrefix, sizeof(newDataset.mMeshLocalPrefix.m8));
246 newDataset.mComponents.mIsMeshLocalPrefixPresent = true;
249 memcpy(newDataset.mMasterKey.m8, netInfo.ThreadMasterKey, sizeof(newDataset.mMasterKey.m8));
250 newDataset.mComponents.mIsMasterKeyPresent = true;
252 if (netInfo.FieldPresent.ThreadPSKc)
254 memcpy(newDataset.mPskc.m8, netInfo.ThreadPSKc, sizeof(newDataset.mPskc.m8));
255 newDataset.mComponents.mIsPskcPresent = true;
258 if (netInfo.ThreadPANId != kThreadPANId_NotSpecified)
260 newDataset.mPanId = netInfo.ThreadPANId;
261 newDataset.mComponents.mIsPanIdPresent = true;
264 if (netInfo.ThreadChannel != kThreadChannel_NotSpecified)
266 newDataset.mChannel = netInfo.ThreadChannel;
267 newDataset.mComponents.mIsChannelPresent = true;
270 if (netInfo.ThreadDatasetTimestamp != 0)
272 newDataset.mActiveTimestamp = netInfo.ThreadDatasetTimestamp;
273 newDataset.mComponents.mIsActiveTimestampPresent = true;
276 // Set the dataset as the active dataset for the node.
277 Impl()->LockThreadStack();
278 otErr = otDatasetSetActive(mOTInst, &newDataset);
279 Impl()->UnlockThreadStack();
281 // post an event alerting other subsystems about change in provisioning state
282 ChipDeviceEvent event;
283 event.Type = DeviceEventType::kServiceProvisioningChange;
284 event.ServiceProvisioningChange.IsServiceProvisioned = true;
285 PlatformMgr().PostEvent(&event);
287 return MapOpenThreadError(otErr);
290 template <class ImplClass>
291 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_SetThreadProvision(const uint8_t * operationalDataset,
292 size_t operationalDatasetLen)
294 otError otErr = OT_ERROR_FAILED;
295 otOperationalDatasetTlvs datasetTlv;
297 VerifyOrReturnError(operationalDatasetLen <= sizeof(datasetTlv.mTlvs), CHIP_ERROR_MESSAGE_TOO_LONG);
298 // A compile time check to avoid misbehavior if the openthread implementation changed over time.
299 static_assert(sizeof(datasetTlv.mTlvs) <= UINT8_MAX);
300 memcpy(datasetTlv.mTlvs, operationalDataset, operationalDatasetLen);
301 datasetTlv.mLength = static_cast<uint8_t>(operationalDatasetLen);
303 // Set the dataset as the active dataset for the node.
304 Impl()->LockThreadStack();
305 otErr = otDatasetSetActiveTlvs(mOTInst, &datasetTlv);
306 Impl()->UnlockThreadStack();
308 // post an event alerting other subsystems about change in provisioning state
309 ChipDeviceEvent event;
310 event.Type = DeviceEventType::kServiceProvisioningChange;
311 event.ServiceProvisioningChange.IsServiceProvisioned = true;
312 PlatformMgr().PostEvent(&event);
314 return MapOpenThreadError(otErr);
317 template <class ImplClass>
318 bool GenericThreadStackManagerImpl_OpenThread<ImplClass>::_IsThreadProvisioned(void)
322 Impl()->LockThreadStack();
323 provisioned = otDatasetIsCommissioned(mOTInst);
324 Impl()->UnlockThreadStack();
329 template <class ImplClass>
330 bool GenericThreadStackManagerImpl_OpenThread<ImplClass>::_IsThreadAttached(void)
332 otDeviceRole curRole;
334 Impl()->LockThreadStack();
335 curRole = otThreadGetDeviceRole(mOTInst);
336 Impl()->UnlockThreadStack();
338 return (curRole != OT_DEVICE_ROLE_DISABLED && curRole != OT_DEVICE_ROLE_DETACHED);
341 template <class ImplClass>
342 ConnectivityManager::ThreadDeviceType GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetThreadDeviceType(void)
344 ConnectivityManager::ThreadDeviceType deviceType;
346 Impl()->LockThreadStack();
348 const otLinkModeConfig linkMode = otThreadGetLinkMode(mOTInst);
350 #if CHIP_DEVICE_CONFIG_THREAD_FTD
351 if (linkMode.mDeviceType && otThreadIsRouterEligible(mOTInst))
352 ExitNow(deviceType = ConnectivityManager::kThreadDeviceType_Router);
353 if (linkMode.mDeviceType)
354 ExitNow(deviceType = ConnectivityManager::kThreadDeviceType_FullEndDevice);
356 if (linkMode.mRxOnWhenIdle)
357 ExitNow(deviceType = ConnectivityManager::kThreadDeviceType_MinimalEndDevice);
359 ExitNow(deviceType = ConnectivityManager::kThreadDeviceType_SleepyEndDevice);
362 Impl()->UnlockThreadStack();
367 template <class ImplClass>
369 GenericThreadStackManagerImpl_OpenThread<ImplClass>::_SetThreadDeviceType(ConnectivityManager::ThreadDeviceType deviceType)
371 CHIP_ERROR err = CHIP_NO_ERROR;
372 otLinkModeConfig linkMode;
376 #if CHIP_DEVICE_CONFIG_THREAD_FTD
377 case ConnectivityManager::kThreadDeviceType_Router:
378 case ConnectivityManager::kThreadDeviceType_FullEndDevice:
380 case ConnectivityManager::kThreadDeviceType_MinimalEndDevice:
381 case ConnectivityManager::kThreadDeviceType_SleepyEndDevice:
384 ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
387 #if CHIP_PROGRESS_LOGGING
390 const char * deviceTypeStr;
393 case ConnectivityManager::kThreadDeviceType_Router:
394 deviceTypeStr = "ROUTER";
396 case ConnectivityManager::kThreadDeviceType_FullEndDevice:
397 deviceTypeStr = "FULL END DEVICE";
399 case ConnectivityManager::kThreadDeviceType_MinimalEndDevice:
400 deviceTypeStr = "MINIMAL END DEVICE";
402 case ConnectivityManager::kThreadDeviceType_SleepyEndDevice:
403 deviceTypeStr = "SLEEPY END DEVICE";
406 deviceTypeStr = "(unknown)";
409 ChipLogProgress(DeviceLayer, "Setting OpenThread device type to %s", deviceTypeStr);
412 #endif // CHIP_PROGRESS_LOGGING
414 Impl()->LockThreadStack();
416 linkMode = otThreadGetLinkMode(mOTInst);
420 #if CHIP_DEVICE_CONFIG_THREAD_FTD
421 case ConnectivityManager::kThreadDeviceType_Router:
422 case ConnectivityManager::kThreadDeviceType_FullEndDevice:
423 linkMode.mDeviceType = true;
424 linkMode.mRxOnWhenIdle = true;
425 otThreadSetRouterEligible(mOTInst, deviceType == ConnectivityManager::kThreadDeviceType_Router);
428 case ConnectivityManager::kThreadDeviceType_MinimalEndDevice:
429 linkMode.mDeviceType = false;
430 linkMode.mRxOnWhenIdle = true;
432 case ConnectivityManager::kThreadDeviceType_SleepyEndDevice:
433 linkMode.mDeviceType = false;
434 linkMode.mRxOnWhenIdle = false;
440 otThreadSetLinkMode(mOTInst, linkMode);
442 Impl()->UnlockThreadStack();
448 template <class ImplClass>
449 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetThreadPollingConfig(
450 ConnectivityManager::ThreadPollingConfig & pollingConfig)
452 pollingConfig = mPollingConfig;
455 template <class ImplClass>
456 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_SetThreadPollingConfig(
457 const ConnectivityManager::ThreadPollingConfig & pollingConfig)
459 mPollingConfig = pollingConfig;
460 return Impl()->AdjustPollingInterval();
463 template <class ImplClass>
464 bool GenericThreadStackManagerImpl_OpenThread<ImplClass>::_HaveMeshConnectivity(void)
467 otDeviceRole curRole;
469 Impl()->LockThreadStack();
471 // Get the current Thread role.
472 curRole = otThreadGetDeviceRole(mOTInst);
474 // If Thread is disabled, or the node is detached, then the node has no mesh connectivity.
475 if (curRole == OT_DEVICE_ROLE_DISABLED || curRole == OT_DEVICE_ROLE_DETACHED)
480 // If the node is a child, that implies the existence of a parent node which provides connectivity
482 else if (curRole == OT_DEVICE_ROLE_CHILD)
487 // Otherwise, if the node is acting as a router, scan the Thread neighbor table looking for at least
488 // one other node that is also acting as router.
491 otNeighborInfoIterator neighborIter = OT_NEIGHBOR_INFO_ITERATOR_INIT;
492 otNeighborInfo neighborInfo;
496 while (otThreadGetNextNeighborInfo(mOTInst, &neighborIter, &neighborInfo) == OT_ERROR_NONE)
498 if (!neighborInfo.mIsChild)
506 Impl()->UnlockThreadStack();
511 template <class ImplClass>
512 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::_OnMessageLayerActivityChanged(bool messageLayerIsActive)
514 Impl()->AdjustPollingInterval();
517 template <class ImplClass>
518 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetAndLogThreadStatsCounters(void)
520 CHIP_ERROR err = CHIP_NO_ERROR;
522 const otMacCounters * macCounters;
523 const otIpCounters * ipCounters;
524 otOperationalDataset activeDataset;
527 Impl()->LockThreadStack();
529 role = otThreadGetDeviceRole(mOTInst);
530 ChipLogProgress(DeviceLayer, "Thread Role: %d\n", role);
532 if (otDatasetIsCommissioned(mOTInst))
534 otErr = otDatasetGetActive(mOTInst, &activeDataset);
535 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
537 if (activeDataset.mComponents.mIsChannelPresent)
539 ChipLogProgress(DeviceLayer, "Thread Channel: %d\n", activeDataset.mChannel);
543 macCounters = otLinkGetCounters(mOTInst);
545 ChipLogProgress(DeviceLayer,
548 "MAC Rx Unicast: %d\n"
549 "MAC Rx Broadcast: %d\n"
551 "MAC Rx Data Polls: %d\n"
552 "MAC Rx Beacons: %d\n"
553 "MAC Rx Beacon Reqs: %d\n"
555 "MAC Rx Filtered Whitelist: %d\n"
556 "MAC Rx Filtered DestAddr: %d\n",
557 macCounters->mRxTotal, macCounters->mRxUnicast, macCounters->mRxBroadcast, macCounters->mRxData,
558 macCounters->mRxDataPoll, macCounters->mRxBeacon, macCounters->mRxBeaconRequest, macCounters->mRxOther,
559 macCounters->mRxAddressFiltered, macCounters->mRxDestAddrFiltered);
561 ChipLogProgress(DeviceLayer,
564 "MAC Tx Unicast: %d\n"
565 "MAC Tx Broadcast: %d\n"
567 "MAC Tx Data Polls: %d\n"
568 "MAC Tx Beacons: %d\n"
569 "MAC Tx Beacon Reqs: %d\n"
572 "MAC Tx CCA Fail: %d\n",
573 macCounters->mTxTotal, macCounters->mTxUnicast, macCounters->mTxBroadcast, macCounters->mTxData,
574 macCounters->mTxDataPoll, macCounters->mTxBeacon, macCounters->mTxBeaconRequest, macCounters->mTxOther,
575 macCounters->mTxRetry, macCounters->mTxErrCca);
577 ChipLogProgress(DeviceLayer,
578 "Failure Counters:\n"
579 "MAC Rx Decrypt Fail: %d\n"
580 "MAC Rx No Frame Fail: %d\n"
581 "MAC Rx Unknown Neighbor Fail: %d\n"
582 "MAC Rx Invalid Src Addr Fail: %d\n"
583 "MAC Rx FCS Fail: %d\n"
584 "MAC Rx Other Fail: %d\n",
585 macCounters->mRxErrSec, macCounters->mRxErrNoFrame, macCounters->mRxErrUnknownNeighbor,
586 macCounters->mRxErrInvalidSrcAddr, macCounters->mRxErrFcs, macCounters->mRxErrOther);
588 ipCounters = otThreadGetIp6Counters(mOTInst);
590 ChipLogProgress(DeviceLayer,
592 "IP Tx Success: %d\n"
593 "IP Rx Success: %d\n"
596 ipCounters->mTxSuccess, ipCounters->mRxSuccess, ipCounters->mTxFailure, ipCounters->mRxFailure);
598 Impl()->UnlockThreadStack();
604 template <class ImplClass>
605 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetAndLogThreadTopologyMinimal(void)
607 CHIP_ERROR err = CHIP_NO_ERROR;
609 const otExtAddress * extAddress;
612 uint16_t leaderRouterId;
613 uint32_t partitionId;
614 int8_t parentAverageRssi;
615 int8_t parentLastRssi;
618 Impl()->LockThreadStack();
620 rloc16 = otThreadGetRloc16(mOTInst);
622 // Router ID is the top 6 bits of the RLOC
623 routerId = (rloc16 >> 10) & 0x3f;
625 leaderRouterId = otThreadGetLeaderRouterId(mOTInst);
627 otErr = otThreadGetParentAverageRssi(mOTInst, &parentAverageRssi);
628 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
630 otErr = otThreadGetParentLastRssi(mOTInst, &parentLastRssi);
631 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
633 partitionId = otThreadGetPartitionId(mOTInst);
635 extAddress = otLinkGetExtendedAddress(mOTInst);
637 instantRssi = otPlatRadioGetRssi(mOTInst);
639 ChipLogProgress(DeviceLayer,
643 "Leader Router ID: %u\n"
644 "Parent Avg RSSI: %d\n"
645 "Parent Last RSSI: %d\n"
647 "Extended Address: %02X%02X:%02X%02X:%02X%02X:%02X%02X\n"
648 "Instant RSSI: %d\n",
649 rloc16, routerId, leaderRouterId, parentAverageRssi, parentLastRssi, partitionId, extAddress->m8[0],
650 extAddress->m8[1], extAddress->m8[2], extAddress->m8[3], extAddress->m8[4], extAddress->m8[5],
651 extAddress->m8[6], extAddress->m8[7], instantRssi);
653 Impl()->UnlockThreadStack();
656 if (err != CHIP_NO_ERROR)
658 ChipLogError(DeviceLayer, "GetAndLogThreadTopologyMinimul failed: %d", err);
664 #define TELEM_NEIGHBOR_TABLE_SIZE (64)
665 #define TELEM_PRINT_BUFFER_SIZE (64)
667 #if CHIP_DEVICE_CONFIG_THREAD_FTD
668 template <class ImplClass>
669 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetAndLogThreadTopologyFull()
671 CHIP_ERROR err = CHIP_NO_ERROR;
673 otIp6Address * leaderAddr = NULL;
674 uint8_t * networkData = NULL;
675 uint8_t * stableNetworkData = NULL;
676 uint8_t networkDataLen = 0;
677 uint8_t stableNetworkDataLen = 0;
678 const otExtAddress * extAddress;
679 otNeighborInfo neighborInfo[TELEM_NEIGHBOR_TABLE_SIZE];
680 otNeighborInfoIterator iter;
681 otNeighborInfoIterator iterCopy;
682 char printBuf[TELEM_PRINT_BUFFER_SIZE];
685 uint16_t leaderRouterId;
686 uint8_t leaderWeight;
687 uint8_t leaderLocalWeight;
688 uint32_t partitionId;
690 uint8_t networkDataVersion;
691 uint8_t stableNetworkDataVersion;
692 uint16_t neighborTableSize = 0;
693 uint16_t childTableSize = 0;
695 Impl()->LockThreadStack();
697 rloc16 = otThreadGetRloc16(mOTInst);
699 // Router ID is the top 6 bits of the RLOC
700 routerId = (rloc16 >> 10) & 0x3f;
702 leaderRouterId = otThreadGetLeaderRouterId(mOTInst);
704 otErr = otThreadGetLeaderRloc(mOTInst, leaderAddr);
705 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
707 leaderWeight = otThreadGetLeaderWeight(mOTInst);
709 leaderLocalWeight = otThreadGetLocalLeaderWeight(mOTInst);
711 otErr = otNetDataGet(mOTInst, false, networkData, &networkDataLen);
712 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
714 networkDataVersion = otNetDataGetVersion(mOTInst);
716 otErr = otNetDataGet(mOTInst, true, stableNetworkData, &stableNetworkDataLen);
717 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
719 stableNetworkDataVersion = otNetDataGetStableVersion(mOTInst);
721 extAddress = otLinkGetExtendedAddress(mOTInst);
723 partitionId = otThreadGetPartitionId(mOTInst);
725 instantRssi = otPlatRadioGetRssi(mOTInst);
727 iter = OT_NEIGHBOR_INFO_ITERATOR_INIT;
728 iterCopy = OT_NEIGHBOR_INFO_ITERATOR_INIT;
729 neighborTableSize = 0;
732 while (otThreadGetNextNeighborInfo(mOTInst, &iter, &neighborInfo[iter]) == OT_ERROR_NONE)
735 if (neighborInfo[iterCopy].mIsChild)
742 ChipLogProgress(DeviceLayer,
746 "Leader Router ID: %u\n"
747 "Leader Address: %02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X\n"
748 "Leader Weight: %d\n"
749 "Local Leader Weight: %d\n"
750 "Network Data Len: %d\n"
751 "Network Data Version: %d\n"
752 "Stable Network Data Version: %d\n"
753 "Extended Address: %02X%02X:%02X%02X:%02X%02X:%02X%02X\n"
756 "Neighbor Table Length: %d\n"
757 "Child Table Length: %d\n",
758 rloc16, routerId, leaderRouterId, leaderAddr->mFields.m8[0], leaderAddr->mFields.m8[1],
759 leaderAddr->mFields.m8[2], leaderAddr->mFields.m8[3], leaderAddr->mFields.m8[4], leaderAddr->mFields.m8[5],
760 leaderAddr->mFields.m8[6], leaderAddr->mFields.m8[7], leaderAddr->mFields.m8[8], leaderAddr->mFields.m8[9],
761 leaderAddr->mFields.m8[10], leaderAddr->mFields.m8[11], leaderAddr->mFields.m8[12], leaderAddr->mFields.m8[13],
762 leaderAddr->mFields.m8[14], leaderAddr->mFields.m8[15], leaderWeight, leaderLocalWeight, networkDataLen,
763 networkDataVersion, stableNetworkDataVersion, extAddress->m8[0], extAddress->m8[1], extAddress->m8[2],
764 extAddress->m8[3], extAddress->m8[4], extAddress->m8[5], extAddress->m8[6], extAddress->m8[7], partitionId,
765 instantRssi, neighborTableSize, childTableSize);
767 // Handle each neighbor event seperatly.
768 for (uint32_t i = 0; i < neighborTableSize; i++)
770 otNeighborInfo * neighbor = &neighborInfo[i];
772 if (neighbor->mIsChild)
774 otChildInfo * child = NULL;
775 otErr = otThreadGetChildInfoById(mOTInst, neighbor->mRloc16, child);
776 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
778 snprintf(printBuf, TELEM_PRINT_BUFFER_SIZE, ", Timeout: %10" PRIu32 " NetworkDataVersion: %3" PRIu8, child->mTimeout,
779 child->mNetworkDataVersion);
786 ChipLogProgress(DeviceLayer,
787 "TopoEntry[%u]: %02X%02X:%02X%02X:%02X%02X:%02X%02X\n"
793 "LinkFrameCounter: %10d\n"
794 "MleFrameCounter: %10d\n"
797 "FullNetworkData: %c\n"
799 i, neighbor->mExtAddress.m8[0], neighbor->mExtAddress.m8[1], neighbor->mExtAddress.m8[2],
800 neighbor->mExtAddress.m8[3], neighbor->mExtAddress.m8[4], neighbor->mExtAddress.m8[5],
801 neighbor->mExtAddress.m8[6], neighbor->mExtAddress.m8[7], neighbor->mRloc16, neighbor->mAge,
802 neighbor->mLinkQualityIn, neighbor->mAverageRssi, neighbor->mLastRssi, neighbor->mLinkFrameCounter,
803 neighbor->mMleFrameCounter, neighbor->mRxOnWhenIdle ? 'Y' : 'n', neighbor->mFullThreadDevice ? 'Y' : 'n',
804 neighbor->mFullNetworkData ? 'Y' : 'n', neighbor->mIsChild ? 'Y' : 'n', printBuf);
807 Impl()->UnlockThreadStack();
810 if (err != CHIP_NO_ERROR)
812 ChipLogError(DeviceLayer, "GetAndLogThreadTopologyFull failed: %s", err);
816 #else // CHIP_DEVICE_CONFIG_THREAD_FTD
817 template <class ImplClass>
818 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetAndLogThreadTopologyFull()
820 return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
824 template <class ImplClass>
825 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetPrimary802154MACAddress(uint8_t * buf)
827 const otExtAddress * extendedAddr = otLinkGetExtendedAddress(mOTInst);
828 memcpy(buf, extendedAddr, sizeof(otExtAddress));
829 return CHIP_NO_ERROR;
832 template <class ImplClass>
833 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetFactoryAssignedEUI64(uint8_t (&buf)[8])
835 otExtAddress extendedAddr;
836 otLinkGetFactoryAssignedIeeeEui64(mOTInst, &extendedAddr);
837 memcpy(buf, extendedAddr.m8, sizeof(extendedAddr.m8));
838 return CHIP_NO_ERROR;
841 template <class ImplClass>
842 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_GetExternalIPv6Address(chip::Inet::IPAddress & addr)
844 const otNetifAddress * otAddresses = otIp6GetUnicastAddresses(mOTInst);
846 // Look only for the global unicast addresses, not internally assigned by Thread.
847 for (const otNetifAddress * otAddress = otAddresses; otAddress != nullptr; otAddress = otAddress->mNext)
849 if (otAddress->mValid)
851 switch (otAddress->mAddressOrigin)
853 case OT_ADDRESS_ORIGIN_THREAD:
855 case OT_ADDRESS_ORIGIN_SLAAC:
856 case OT_ADDRESS_ORIGIN_DHCPV6:
857 case OT_ADDRESS_ORIGIN_MANUAL:
858 addr = ToIPAddress(otAddress->mAddress);
859 return CHIP_NO_ERROR;
866 return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
869 template <class ImplClass>
870 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::DoInit(otInstance * otInst)
872 CHIP_ERROR err = CHIP_NO_ERROR;
873 otError otErr = OT_ERROR_NONE;
875 // Arrange for OpenThread errors to be translated to text.
876 RegisterOpenThreadErrorFormatter();
879 mPollingConfig.Clear();
881 // If an OpenThread instance hasn't been supplied, call otInstanceInitSingle() to
882 // create or acquire a singleton instance of OpenThread.
885 otInst = otInstanceInitSingle();
886 VerifyOrExit(otInst != NULL, err = MapOpenThreadError(OT_ERROR_FAILED));
889 #if !defined(__ZEPHYR__) && !defined(ENABLE_CHIP_SHELL) && !defined(PW_RPC_ENABLED)
890 otCliUartInit(otInst);
895 // Arrange for OpenThread to call the OnOpenThreadStateChange method whenever a
896 // state change occurs. Note that we reference the OnOpenThreadStateChange method
897 // on the concrete implementation class so that that class can override the default
898 // method implementation if it chooses to.
899 otErr = otSetStateChangedCallback(otInst, ImplClass::OnOpenThreadStateChange, this);
900 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
902 // Enable automatic assignment of Thread advertised addresses.
903 #if OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE
904 otIp6SetSlaacEnabled(otInst, true);
907 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT
908 otSrpClientSetCallback(mOTInst, &OnSrpClientNotification, nullptr);
909 otSrpClientEnableAutoStartMode(mOTInst, &OnSrpClientStateChange, nullptr);
910 memset(&mSrpClient, 0, sizeof(mSrpClient));
911 #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT
913 // If the Thread stack has been provisioned, but is not currently enabled, enable it now.
914 if (otThreadGetDeviceRole(mOTInst) == OT_DEVICE_ROLE_DISABLED && otDatasetIsCommissioned(otInst))
916 // Enable the Thread IPv6 interface.
917 otErr = otIp6SetEnabled(otInst, true);
918 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
920 otErr = otThreadSetEnabled(otInst, true);
921 VerifyOrExit(otErr == OT_ERROR_NONE, err = MapOpenThreadError(otErr));
923 ChipLogProgress(DeviceLayer, "OpenThread ifconfig up and thread start");
927 ChipLogProgress(DeviceLayer, "OpenThread started: %s", otThreadErrorToString(otErr));
931 template <class ImplClass>
932 bool GenericThreadStackManagerImpl_OpenThread<ImplClass>::IsThreadAttachedNoLock(void)
934 otDeviceRole curRole = otThreadGetDeviceRole(mOTInst);
935 return (curRole != OT_DEVICE_ROLE_DISABLED && curRole != OT_DEVICE_ROLE_DETACHED);
938 template <class ImplClass>
939 bool GenericThreadStackManagerImpl_OpenThread<ImplClass>::IsThreadInterfaceUpNoLock(void)
941 return otIp6IsEnabled(mOTInst);
944 template <class ImplClass>
945 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::AdjustPollingInterval(void)
947 CHIP_ERROR err = CHIP_NO_ERROR;
949 uint32_t newPollingIntervalMS = mPollingConfig.InactivePollingIntervalMS;
951 if (newPollingIntervalMS != 0)
953 Impl()->LockThreadStack();
955 uint32_t curPollingIntervalMS = otLinkGetPollPeriod(mOTInst);
957 if (newPollingIntervalMS != curPollingIntervalMS)
959 otError otErr = otLinkSetPollPeriod(mOTInst, newPollingIntervalMS);
960 err = MapOpenThreadError(otErr);
963 Impl()->UnlockThreadStack();
965 if (newPollingIntervalMS != curPollingIntervalMS)
967 ChipLogProgress(DeviceLayer, "OpenThread polling interval set to %" PRId32 "ms", newPollingIntervalMS);
974 template <class ImplClass>
975 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::_ErasePersistentInfo(void)
977 ChipLogProgress(DeviceLayer, "Erasing Thread persistent info...");
978 Impl()->LockThreadStack();
979 otThreadSetEnabled(mOTInst, false);
980 otInstanceErasePersistentInfo(mOTInst);
981 Impl()->UnlockThreadStack();
984 template <class ImplClass>
985 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::OnJoinerComplete(otError aError, void * aContext)
987 static_cast<GenericThreadStackManagerImpl_OpenThread *>(aContext)->OnJoinerComplete(aError);
990 template <class ImplClass>
991 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::OnJoinerComplete(otError aError)
993 ChipLogProgress(DeviceLayer, "Join Thread network: %s", otThreadErrorToString(aError));
995 if (aError == OT_ERROR_NONE)
997 otError error = otThreadSetEnabled(mOTInst, true);
999 ChipLogProgress(DeviceLayer, "Start Thread network: %s", otThreadErrorToString(error));
1003 template <class ImplClass>
1004 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_JoinerStart(void)
1006 CHIP_ERROR error = CHIP_NO_ERROR;
1008 Impl()->LockThreadStack();
1009 VerifyOrExit(!otDatasetIsCommissioned(mOTInst) && otThreadGetDeviceRole(mOTInst) == OT_DEVICE_ROLE_DISABLED,
1010 error = MapOpenThreadError(OT_ERROR_INVALID_STATE));
1011 VerifyOrExit(otJoinerGetState(mOTInst) == OT_JOINER_STATE_IDLE, error = MapOpenThreadError(OT_ERROR_BUSY));
1013 if (!otIp6IsEnabled(mOTInst))
1015 SuccessOrExit(error = MapOpenThreadError(otIp6SetEnabled(mOTInst, true)));
1019 otJoinerDiscerner discerner;
1020 uint16_t discriminator;
1022 SuccessOrExit(error = ConfigurationMgr().GetSetupDiscriminator(discriminator));
1023 discerner.mLength = 12;
1024 discerner.mValue = discriminator;
1026 ChipLogProgress(DeviceLayer, "Joiner Discerner: %u", discriminator);
1027 otJoinerSetDiscerner(mOTInst, &discerner);
1034 SuccessOrExit(error = ConfigurationMgr().GetSetupPinCode(pincode));
1035 snprintf(pskd.m8, sizeof(pskd.m8) - 1, "%09" PRIu32, pincode);
1037 ChipLogProgress(DeviceLayer, "Joiner PSKd: %s", pskd.m8);
1038 error = MapOpenThreadError(otJoinerStart(mOTInst, pskd.m8, NULL, NULL, NULL, NULL, NULL,
1039 &GenericThreadStackManagerImpl_OpenThread::OnJoinerComplete, this));
1043 Impl()->UnlockThreadStack();
1045 ChipLogProgress(DeviceLayer, "Joiner start: %s", chip::ErrorStr(error));
1050 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT
1052 static_assert(OPENTHREAD_API_VERSION >= 80, "SRP Client requires a more recent OpenThread version");
1054 template <class ImplClass>
1055 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::OnSrpClientNotification(otError aError,
1056 const otSrpClientHostInfo * aHostInfo,
1057 const otSrpClientService * aServices,
1058 const otSrpClientService * aRemovedServices,
1063 case OT_ERROR_NONE: {
1064 ChipLogProgress(DeviceLayer, "OnSrpClientNotification: Last requested operation completed successfully");
1066 if (aRemovedServices)
1068 otSrpClientService * otService = const_cast<otSrpClientService *>(aRemovedServices);
1069 otSrpClientService * next = nullptr;
1070 using Service = typename SrpClient::Service;
1072 // Free memory for all removed services.
1075 next = otService->mNext;
1076 auto service = reinterpret_cast<Service *>(reinterpret_cast<size_t>(otService) - offsetof(Service, mService));
1077 memset(service, 0, sizeof(Service));
1079 } while (otService);
1083 case OT_ERROR_PARSE:
1084 ChipLogError(DeviceLayer, "OnSrpClientNotification: Parsing operaton failed");
1086 case OT_ERROR_NOT_FOUND:
1087 ChipLogError(DeviceLayer, "OnSrpClientNotification: Domain name or RRset does not exist");
1089 case OT_ERROR_NOT_IMPLEMENTED:
1090 ChipLogError(DeviceLayer, "OnSrpClientNotification: Server does not support query type");
1092 case OT_ERROR_SECURITY:
1093 ChipLogError(DeviceLayer, "OnSrpClientNotification: Operation refused for security reasons");
1095 case OT_ERROR_DUPLICATED:
1096 ChipLogError(DeviceLayer, "OnSrpClientNotification: Domain name or RRset is duplicated");
1098 case OT_ERROR_RESPONSE_TIMEOUT:
1099 ChipLogError(DeviceLayer, "OnSrpClientNotification: Timed out waiting on server response");
1101 case OT_ERROR_INVALID_ARGS:
1102 ChipLogError(DeviceLayer, "OnSrpClientNotification: Invalid service structure detected");
1104 case OT_ERROR_NO_BUFS:
1105 ChipLogError(DeviceLayer, "OnSrpClientNotification: Insufficient buffer to handle message");
1107 case OT_ERROR_FAILED:
1108 ChipLogError(DeviceLayer, "OnSrpClientNotification: Internal server error occurred");
1111 ChipLogError(DeviceLayer, "OnSrpClientNotification: Unknown error occurred");
1116 template <class ImplClass>
1117 void GenericThreadStackManagerImpl_OpenThread<ImplClass>::OnSrpClientStateChange(const otSockAddr * aServerSockAddr,
1120 if (aServerSockAddr)
1122 ChipLogProgress(DeviceLayer, "SRP Client was started, as detected server addressed: %x:%x:%x:%x:%x:%x:%x:%x",
1123 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[0]),
1124 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[1]),
1125 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[2]),
1126 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[3]),
1127 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[4]),
1128 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[5]),
1129 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[6]),
1130 Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[7]));
1134 ChipLogProgress(DeviceLayer, "SRP Client was stopped, because current server is no longer detected.");
1138 template <class ImplClass>
1139 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_AddSrpService(const char * aInstanceName, const char * aName,
1140 uint16_t aPort, chip::Mdns::TextEntry * aTxtEntries,
1141 size_t aTxtEntiresSize, uint32_t aLeaseInterval,
1142 uint32_t aKeyLeaseInterval)
1144 CHIP_ERROR error = CHIP_NO_ERROR;
1145 typename SrpClient::Service * srpService = nullptr;
1147 Impl()->LockThreadStack();
1149 VerifyOrExit(aInstanceName, error = CHIP_ERROR_INVALID_ARGUMENT);
1150 VerifyOrExit(strlen(aInstanceName) < SrpClient::kMaxInstanceNameSize, error = CHIP_ERROR_INVALID_STRING_LENGTH);
1151 VerifyOrExit(aName, error = CHIP_ERROR_INVALID_ARGUMENT);
1152 VerifyOrExit(strlen(aName) < SrpClient::kMaxNameSize, error = CHIP_ERROR_INVALID_STRING_LENGTH);
1154 // Check if service with desired instance name already exists and try to find empty slot in array for new service
1155 for (typename SrpClient::Service & service : mSrpClient.mServices)
1157 if (strcmp(service.mInstanceName, "") == 0)
1159 // Assign first empty slot in array for a new service.
1160 srpService = srpService ? srpService : &service;
1164 VerifyOrExit((strcmp(service.mInstanceName, aInstanceName) != 0) || (strcmp(service.mName, aName) != 0),
1165 error = MapOpenThreadError(OT_ERROR_DUPLICATED));
1169 // Verify is there an empty place for new service.
1170 VerifyOrExit(srpService, error = MapOpenThreadError(OT_ERROR_NO_BUFS));
1172 otSrpClientSetLeaseInterval(mOTInst, aLeaseInterval);
1173 otSrpClientSetKeyLeaseInterval(mOTInst, aKeyLeaseInterval);
1175 memcpy(srpService->mInstanceName, aInstanceName, strlen(aInstanceName) + 1);
1176 srpService->mService.mInstanceName = srpService->mInstanceName;
1178 memcpy(srpService->mName, aName, strlen(aName) + 1);
1179 srpService->mService.mName = srpService->mName;
1181 srpService->mService.mPort = aPort;
1183 // Check if there are some optional text entries to add.
1184 if (aTxtEntries && aTxtEntiresSize != 0)
1186 VerifyOrExit(aTxtEntiresSize <= SrpClient::kMaxTxtEntriesNumber, error = CHIP_ERROR_INVALID_LIST_LENGTH);
1188 srpService->mService.mNumTxtEntries = static_cast<uint8_t>(aTxtEntiresSize);
1190 for (uint8_t entryId = 0; entryId < aTxtEntiresSize; entryId++)
1192 VerifyOrExit(aTxtEntries[entryId].mDataSize <= SrpClient::kMaxTxtValueSize, error = CHIP_ERROR_BUFFER_TOO_SMALL);
1193 VerifyOrExit((strlen(aTxtEntries[entryId].mKey) + 1) <= SrpClient::kMaxTxtKeySize, error = CHIP_ERROR_BUFFER_TOO_SMALL);
1195 srpService->mTxtEntries[entryId].mValueLength = static_cast<uint8_t>(aTxtEntries[entryId].mDataSize);
1196 memcpy(&(srpService->mTxtValueBuffers[entryId][0]), aTxtEntries[entryId].mData, aTxtEntries[entryId].mDataSize);
1197 srpService->mTxtEntries[entryId].mValue = &(srpService->mTxtValueBuffers[entryId][0]);
1199 memcpy(&(srpService->mTxtKeyBuffers[entryId][0]), aTxtEntries[entryId].mKey, strlen(aTxtEntries[entryId].mKey) + 1);
1200 srpService->mTxtEntries[entryId].mKey = &(srpService->mTxtKeyBuffers[entryId][0]);
1203 srpService->mService.mTxtEntries = srpService->mTxtEntries;
1206 error = MapOpenThreadError(otSrpClientAddService(mOTInst, &(srpService->mService)));
1209 Impl()->UnlockThreadStack();
1214 template <class ImplClass>
1215 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_RemoveSrpService(const char * aInstanceName, const char * aName)
1217 CHIP_ERROR error = CHIP_NO_ERROR;
1218 typename SrpClient::Service * srpService = nullptr;
1220 Impl()->LockThreadStack();
1222 VerifyOrExit(aInstanceName, error = CHIP_ERROR_INVALID_ARGUMENT);
1223 VerifyOrExit(strlen(aInstanceName) < SrpClient::kMaxInstanceNameSize, error = CHIP_ERROR_INVALID_STRING_LENGTH);
1224 VerifyOrExit(aName, error = CHIP_ERROR_INVALID_ARGUMENT);
1225 VerifyOrExit(strlen(aName) < SrpClient::kMaxNameSize, error = CHIP_ERROR_INVALID_STRING_LENGTH);
1227 // Check if service to remove exists.
1228 for (typename SrpClient::Service & service : mSrpClient.mServices)
1230 if ((strcmp(service.mInstanceName, aInstanceName) == 0) && (strcmp(service.mName, aName) == 0))
1232 srpService = &service;
1237 VerifyOrExit(srpService, error = MapOpenThreadError(OT_ERROR_NOT_FOUND));
1239 error = MapOpenThreadError(otSrpClientRemoveService(mOTInst, &(srpService->mService)));
1242 Impl()->UnlockThreadStack();
1247 template <class ImplClass>
1248 CHIP_ERROR GenericThreadStackManagerImpl_OpenThread<ImplClass>::_SetupSrpHost(const char * aHostName)
1250 CHIP_ERROR error = CHIP_NO_ERROR;
1251 Inet::IPAddress hostAddress;
1253 Impl()->LockThreadStack();
1255 VerifyOrExit(aHostName, error = CHIP_ERROR_INVALID_ARGUMENT);
1256 VerifyOrExit(strlen(aHostName) < SrpClient::kMaxHostNameSize, error = CHIP_ERROR_INVALID_STRING_LENGTH);
1258 // Avoid adding the same host name multiple times
1259 if (strcmp(mSrpClient.mHostName, aHostName) != 0)
1261 strcpy(mSrpClient.mHostName, aHostName);
1262 error = MapOpenThreadError(otSrpClientSetHostName(mOTInst, aHostName));
1263 SuccessOrExit(error);
1266 // Check if device has any external IPv6 assigned. If not, host will be set without IPv6 addresses
1267 // and updated later on.
1268 if (ThreadStackMgr().GetExternalIPv6Address(hostAddress) == CHIP_NO_ERROR)
1270 memcpy(&mSrpClient.mHostAddress.mFields.m32, hostAddress.Addr, sizeof(hostAddress.Addr));
1271 error = MapOpenThreadError(otSrpClientSetHostAddresses(mOTInst, &mSrpClient.mHostAddress, 1));
1275 Impl()->UnlockThreadStack();
1280 #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT
1282 } // namespace Internal
1283 } // namespace DeviceLayer
1286 #endif // GENERIC_THREAD_STACK_MANAGER_IMPL_OPENTHREAD_IPP