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 * Utility functions for working with OpenThread.
25 #include "OpenThreadUtils.h"
27 #include <lib/core/CHIPEncoding.h>
28 #include <lib/support/ErrorStr.h>
29 #include <lib/support/logging/CHIPLogging.h>
30 #include <platform/internal/CHIPDeviceLayerInternal.h>
32 #include <openthread/error.h>
37 namespace DeviceLayer {
41 * Map an OpenThread error into the OpenChip error space.
43 CHIP_ERROR MapOpenThreadError(otError otErr)
45 return (otErr == OT_ERROR_NONE) ? CHIP_NO_ERROR : CHIP_CONFIG_OPENTHREAD_ERROR_MIN + (CHIP_ERROR) otErr;
49 * Given an OpenChip error value that represents an OpenThread error, returns a
50 * human-readable NULL-terminated C string describing the error.
52 * @param[in] buf Buffer into which the error string will be placed.
53 * @param[in] bufSize Size of the supplied buffer in bytes.
54 * @param[in] err The error to be described.
56 * @return true If a description string was written into the supplied buffer.
57 * @return false If the supplied error was not an OpenThread error.
60 bool FormatOpenThreadError(char * buf, uint16_t bufSize, int32_t err)
62 if (err < CHIP_CONFIG_OPENTHREAD_ERROR_MIN || err > CHIP_CONFIG_OPENTHREAD_ERROR_MAX)
67 #if CHIP_CONFIG_SHORT_ERROR_STR
68 const char * desc = NULL;
69 #else // CHIP_CONFIG_SHORT_ERROR_STR
70 otError otErr = (otError)(err - CHIP_CONFIG_OPENTHREAD_ERROR_MIN);
71 const char * desc = otThreadErrorToString(otErr);
72 #endif // CHIP_CONFIG_SHORT_ERROR_STR
74 chip::FormatError(buf, bufSize, "OpenThread", err, desc);
80 * Register a text error formatter for OpenThread errors.
82 void RegisterOpenThreadErrorFormatter(void)
84 static ErrorFormatter sOpenThreadErrorFormatter = { FormatOpenThreadError, NULL };
86 RegisterErrorFormatter(&sOpenThreadErrorFormatter);
90 * Log information related to a state change in the OpenThread stack.
92 * NB: This function *must* be called with the Thread stack lock held.
94 void LogOpenThreadStateChange(otInstance * otInst, uint32_t flags)
96 #if CHIP_DETAIL_LOGGING
98 const uint32_t kParamsChanged = (OT_CHANGED_THREAD_NETWORK_NAME | OT_CHANGED_THREAD_PANID | OT_CHANGED_THREAD_EXT_PANID |
99 OT_CHANGED_THREAD_CHANNEL | OT_CHANGED_MASTER_KEY | OT_CHANGED_PSKC);
101 static char strBuf[64];
103 ChipLogDetail(DeviceLayer, "OpenThread State Changed (Flags: 0x%08x)", flags);
104 if ((flags & OT_CHANGED_THREAD_ROLE) != 0)
106 ChipLogDetail(DeviceLayer, " Device Role: %s", OpenThreadRoleToStr(otThreadGetDeviceRole(otInst)));
108 if ((flags & kParamsChanged) != 0)
110 ChipLogDetail(DeviceLayer, " Network Name: %s", otThreadGetNetworkName(otInst));
111 ChipLogDetail(DeviceLayer, " PAN Id: 0x%04X", otLinkGetPanId(otInst));
113 const otExtendedPanId * exPanId = otThreadGetExtendedPanId(otInst);
114 snprintf(strBuf, sizeof(strBuf), "0x%02X%02X%02X%02X%02X%02X%02X%02X", exPanId->m8[0], exPanId->m8[1], exPanId->m8[2],
115 exPanId->m8[3], exPanId->m8[4], exPanId->m8[5], exPanId->m8[6], exPanId->m8[7]);
116 ChipLogDetail(DeviceLayer, " Extended PAN Id: %s", strBuf);
118 ChipLogDetail(DeviceLayer, " Channel: %d", otLinkGetChannel(otInst));
120 const otMeshLocalPrefix * otMeshPrefix = otThreadGetMeshLocalPrefix(otInst);
121 chip::Inet::IPAddress meshPrefix;
122 memset(meshPrefix.Addr, 0, sizeof(meshPrefix.Addr));
123 memcpy(meshPrefix.Addr, otMeshPrefix->m8, sizeof(otMeshPrefix->m8));
124 meshPrefix.ToString(strBuf);
125 ChipLogDetail(DeviceLayer, " Mesh Prefix: %s/64", strBuf);
127 #if CHIP_CONFIG_SECURITY_TEST_MODE
129 const otMasterKey * otKey = otThreadGetMasterKey(otInst);
130 for (int i = 0; i < OT_MASTER_KEY_SIZE; i++)
131 snprintf(&strBuf[i * 2], 3, "%02X", otKey->m8[i]);
132 ChipLogDetail(DeviceLayer, " Master Key: %s", strBuf);
134 #endif // CHIP_CONFIG_SECURITY_TEST_MODE
136 if ((flags & OT_CHANGED_THREAD_PARTITION_ID) != 0)
138 ChipLogDetail(DeviceLayer, " Partition Id: 0x%" PRIX32, otThreadGetPartitionId(otInst));
140 if ((flags & (OT_CHANGED_IP6_ADDRESS_ADDED | OT_CHANGED_IP6_ADDRESS_REMOVED)) != 0)
142 ChipLogDetail(DeviceLayer, " Thread Unicast Addresses:");
143 for (const otNetifAddress * addr = otIp6GetUnicastAddresses(otInst); addr != NULL; addr = addr->mNext)
145 chip::Inet::IPAddress ipAddr;
146 memcpy(ipAddr.Addr, addr->mAddress.mFields.m32, sizeof(ipAddr.Addr));
148 ipAddr.ToString(strBuf);
150 ChipLogDetail(DeviceLayer, " %s/%d%s%s%s", strBuf, addr->mPrefixLength, addr->mValid ? " valid" : "",
151 addr->mPreferred ? " preferred" : "", addr->mRloc ? " rloc" : "");
155 #endif // CHIP_DETAIL_LOGGING
158 void LogOpenThreadPacket(const char * titleStr, otMessage * pkt)
160 #if CHIP_DETAIL_LOGGING
162 char srcStr[50], destStr[50], typeBuf[20];
163 const char * type = typeBuf;
165 uint8_t headerData[44];
168 const uint8_t & IPv6_NextHeader = headerData[6];
169 const uint8_t * const IPv6_SrcAddr = headerData + 8;
170 const uint8_t * const IPv6_DestAddr = headerData + 24;
171 const uint8_t * const IPv6_SrcPort = headerData + 40;
172 const uint8_t * const IPv6_DestPort = headerData + 42;
173 const uint8_t & ICMPv6_Type = headerData[40];
174 const uint8_t & ICMPv6_Code = headerData[41];
176 constexpr uint8_t kIPProto_UDP = 17;
177 constexpr uint8_t kIPProto_TCP = 6;
178 constexpr uint8_t kIPProto_ICMPv6 = 58;
180 constexpr uint8_t kICMPType_EchoRequest = 128;
181 constexpr uint8_t kICMPType_EchoResponse = 129;
183 pktLen = otMessageGetLength(pkt);
185 if (pktLen >= sizeof(headerData))
187 otMessageRead(pkt, 0, headerData, sizeof(headerData));
189 memcpy(addr.Addr, IPv6_SrcAddr, 16);
190 addr.ToString(srcStr);
192 memcpy(addr.Addr, IPv6_DestAddr, 16);
193 addr.ToString(destStr);
195 if (IPv6_NextHeader == kIPProto_UDP)
199 else if (IPv6_NextHeader == kIPProto_TCP)
203 else if (IPv6_NextHeader == kIPProto_ICMPv6)
205 if (ICMPv6_Type == kICMPType_EchoRequest)
207 type = "ICMPv6 Echo Request";
209 else if (ICMPv6_Type == kICMPType_EchoResponse)
211 type = "ICMPv6 Echo Response";
215 snprintf(typeBuf, sizeof(typeBuf), "ICMPv6 %" PRIu8 ",%" PRIu8, ICMPv6_Type, ICMPv6_Code);
220 snprintf(typeBuf, sizeof(typeBuf), "IP proto %" PRIu8, IPv6_NextHeader);
223 if (IPv6_NextHeader == kIPProto_UDP || IPv6_NextHeader == kIPProto_TCP)
225 snprintf(srcStr + strlen(srcStr), 13, ", port %" PRIu16, Encoding::BigEndian::Get16(IPv6_SrcPort));
226 snprintf(destStr + strlen(destStr), 13, ", port %" PRIu16, Encoding::BigEndian::Get16(IPv6_DestPort));
229 ChipLogDetail(DeviceLayer, "%s: %s, len %" PRIu16, titleStr, type, pktLen);
230 ChipLogDetail(DeviceLayer, " src %s", srcStr);
231 ChipLogDetail(DeviceLayer, " dest %s", destStr);
235 ChipLogDetail(DeviceLayer, "%s: %s, len %" PRIu16, titleStr, "(decode error)", pktLen);
238 #endif // CHIP_DETAIL_LOGGING
241 bool IsOpenThreadMeshLocalAddress(otInstance * otInst, const IPAddress & addr)
243 const otMeshLocalPrefix * otMeshPrefix = otThreadGetMeshLocalPrefix(otInst);
245 return otMeshPrefix != NULL && memcmp(otMeshPrefix->m8, addr.Addr, OT_MESH_LOCAL_PREFIX_SIZE) == 0;
248 const char * OpenThreadRoleToStr(otDeviceRole role)
252 case OT_DEVICE_ROLE_DISABLED:
254 case OT_DEVICE_ROLE_DETACHED:
256 case OT_DEVICE_ROLE_CHILD:
258 case OT_DEVICE_ROLE_ROUTER:
260 case OT_DEVICE_ROLE_LEADER:
267 } // namespace Internal
268 } // namespace DeviceLayer