1 /*
2 * Copyright (c) 2024, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "logger.hpp"
30
31 #include <assert.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34
35 #include <openthread/error.h>
36 #include <openthread/logging.h>
37 #include <openthread/platform/radio.h>
38
39 #include "common/code_utils.hpp"
40 #include "common/num_utils.hpp"
41 #include "lib/spinel/spinel.h"
42
43 namespace ot {
44 namespace Spinel {
45
Logger(const char * aModuleName)46 Logger::Logger(const char *aModuleName)
47 : mModuleName(aModuleName)
48 {
49 }
50
LogIfFail(const char * aText,otError aError)51 void Logger::LogIfFail(const char *aText, otError aError)
52 {
53 OT_UNUSED_VARIABLE(aText);
54
55 if (aError != OT_ERROR_NONE && aError != OT_ERROR_NO_ACK)
56 {
57 LogWarn("%s: %s", aText, otThreadErrorToString(aError));
58 }
59 }
60
LogCrit(const char * aFormat,...)61 void Logger::LogCrit(const char *aFormat, ...)
62 {
63 va_list args;
64
65 va_start(args, aFormat);
66 otLogPlatArgs(OT_LOG_LEVEL_CRIT, mModuleName, aFormat, args);
67 va_end(args);
68 }
69
LogWarn(const char * aFormat,...)70 void Logger::LogWarn(const char *aFormat, ...)
71 {
72 va_list args;
73
74 va_start(args, aFormat);
75 otLogPlatArgs(OT_LOG_LEVEL_WARN, mModuleName, aFormat, args);
76 va_end(args);
77 }
78
LogNote(const char * aFormat,...)79 void Logger::LogNote(const char *aFormat, ...)
80 {
81 va_list args;
82
83 va_start(args, aFormat);
84 otLogPlatArgs(OT_LOG_LEVEL_NOTE, mModuleName, aFormat, args);
85 va_end(args);
86 }
87
LogInfo(const char * aFormat,...)88 void Logger::LogInfo(const char *aFormat, ...)
89 {
90 va_list args;
91
92 va_start(args, aFormat);
93 otLogPlatArgs(OT_LOG_LEVEL_INFO, mModuleName, aFormat, args);
94 va_end(args);
95 }
96
LogDebg(const char * aFormat,...)97 void Logger::LogDebg(const char *aFormat, ...)
98 {
99 va_list args;
100
101 va_start(args, aFormat);
102 otLogPlatArgs(OT_LOG_LEVEL_DEBG, mModuleName, aFormat, args);
103 va_end(args);
104 }
105
Snprintf(char * aDest,uint32_t aSize,const char * aFormat,...)106 uint32_t Logger::Snprintf(char *aDest, uint32_t aSize, const char *aFormat, ...)
107 {
108 int len;
109 va_list args;
110
111 va_start(args, aFormat);
112 len = vsnprintf(aDest, static_cast<size_t>(aSize), aFormat, args);
113 va_end(args);
114
115 return (len < 0) ? 0 : Min(static_cast<uint32_t>(len), aSize - 1);
116 }
117
LogSpinelFrame(const uint8_t * aFrame,uint16_t aLength,bool aTx)118 void Logger::LogSpinelFrame(const uint8_t *aFrame, uint16_t aLength, bool aTx)
119 {
120 otError error = OT_ERROR_NONE;
121 char buf[OPENTHREAD_CONFIG_LOG_MAX_SIZE] = {0};
122 spinel_ssize_t unpacked;
123 uint8_t header;
124 uint32_t cmd;
125 spinel_prop_key_t key;
126 uint8_t *data;
127 spinel_size_t len;
128 const char *prefix = nullptr;
129 char *start = buf;
130 char *end = buf + sizeof(buf);
131
132 VerifyOrExit(otLoggingGetLevel() >= OT_LOG_LEVEL_DEBG);
133
134 prefix = aTx ? "Sent spinel frame" : "Received spinel frame";
135 unpacked = spinel_datatype_unpack(aFrame, aLength, "CiiD", &header, &cmd, &key, &data, &len);
136 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
137
138 start += Snprintf(start, static_cast<uint32_t>(end - start), "%s, flg:0x%x, iid:%d, tid:%u, cmd:%s", prefix,
139 SPINEL_HEADER_GET_FLAG(header), SPINEL_HEADER_GET_IID(header), SPINEL_HEADER_GET_TID(header),
140 spinel_command_to_cstr(cmd));
141 VerifyOrExit(cmd != SPINEL_CMD_RESET);
142
143 start += Snprintf(start, static_cast<uint32_t>(end - start), ", key:%s", spinel_prop_key_to_cstr(key));
144 VerifyOrExit(cmd != SPINEL_CMD_PROP_VALUE_GET);
145
146 switch (key)
147 {
148 case SPINEL_PROP_LAST_STATUS:
149 {
150 spinel_status_t status;
151
152 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT_PACKED_S, &status);
153 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
154 start += Snprintf(start, static_cast<uint32_t>(end - start), ", status:%s", spinel_status_to_cstr(status));
155 }
156 break;
157
158 case SPINEL_PROP_MAC_RAW_STREAM_ENABLED:
159 case SPINEL_PROP_MAC_SRC_MATCH_ENABLED:
160 case SPINEL_PROP_PHY_ENABLED:
161 case SPINEL_PROP_RADIO_COEX_ENABLE:
162 {
163 bool enabled;
164
165 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_BOOL_S, &enabled);
166 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
167 start += Snprintf(start, static_cast<uint32_t>(end - start), ", enabled:%u", enabled);
168 }
169 break;
170
171 case SPINEL_PROP_PHY_CCA_THRESHOLD:
172 case SPINEL_PROP_PHY_FEM_LNA_GAIN:
173 case SPINEL_PROP_PHY_RX_SENSITIVITY:
174 case SPINEL_PROP_PHY_RSSI:
175 case SPINEL_PROP_PHY_TX_POWER:
176 {
177 const char *name = nullptr;
178 int8_t value;
179
180 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_INT8_S, &value);
181 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
182
183 switch (key)
184 {
185 case SPINEL_PROP_PHY_TX_POWER:
186 name = "power";
187 break;
188 case SPINEL_PROP_PHY_CCA_THRESHOLD:
189 name = "threshold";
190 break;
191 case SPINEL_PROP_PHY_FEM_LNA_GAIN:
192 name = "gain";
193 break;
194 case SPINEL_PROP_PHY_RX_SENSITIVITY:
195 name = "sensitivity";
196 break;
197 case SPINEL_PROP_PHY_RSSI:
198 name = "rssi";
199 break;
200 }
201
202 start += Snprintf(start, static_cast<uint32_t>(end - start), ", %s:%d", name, value);
203 }
204 break;
205
206 case SPINEL_PROP_MAC_PROMISCUOUS_MODE:
207 case SPINEL_PROP_MAC_SCAN_STATE:
208 case SPINEL_PROP_PHY_CHAN:
209 case SPINEL_PROP_RCP_CSL_ACCURACY:
210 case SPINEL_PROP_RCP_CSL_UNCERTAINTY:
211 {
212 const char *name = nullptr;
213 uint8_t value;
214
215 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT8_S, &value);
216 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
217
218 switch (key)
219 {
220 case SPINEL_PROP_MAC_SCAN_STATE:
221 name = "state";
222 break;
223 case SPINEL_PROP_RCP_CSL_ACCURACY:
224 name = "accuracy";
225 break;
226 case SPINEL_PROP_RCP_CSL_UNCERTAINTY:
227 name = "uncertainty";
228 break;
229 case SPINEL_PROP_MAC_PROMISCUOUS_MODE:
230 name = "mode";
231 break;
232 case SPINEL_PROP_PHY_CHAN:
233 name = "channel";
234 break;
235 }
236
237 start += Snprintf(start, static_cast<uint32_t>(end - start), ", %s:%u", name, value);
238 }
239 break;
240
241 case SPINEL_PROP_MAC_15_4_PANID:
242 case SPINEL_PROP_MAC_15_4_SADDR:
243 case SPINEL_PROP_MAC_SCAN_PERIOD:
244 case SPINEL_PROP_PHY_REGION_CODE:
245 {
246 const char *name = nullptr;
247 uint16_t value;
248
249 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT16_S, &value);
250 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
251
252 switch (key)
253 {
254 case SPINEL_PROP_MAC_SCAN_PERIOD:
255 name = "period";
256 break;
257 case SPINEL_PROP_PHY_REGION_CODE:
258 name = "region";
259 break;
260 case SPINEL_PROP_MAC_15_4_SADDR:
261 name = "saddr";
262 break;
263 case SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES:
264 name = "saddr";
265 break;
266 case SPINEL_PROP_MAC_15_4_PANID:
267 name = "panid";
268 break;
269 }
270
271 start += Snprintf(start, static_cast<uint32_t>(end - start), ", %s:0x%04x", name, value);
272 }
273 break;
274
275 case SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES:
276 {
277 uint16_t saddr;
278
279 start += Snprintf(start, static_cast<uint32_t>(end - start), ", saddr:");
280
281 if (len < sizeof(saddr))
282 {
283 start += Snprintf(start, static_cast<uint32_t>(end - start), "none");
284 }
285 else
286 {
287 while (len >= sizeof(saddr))
288 {
289 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT16_S, &saddr);
290 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
291 data += unpacked;
292 len -= static_cast<spinel_size_t>(unpacked);
293 start += Snprintf(start, static_cast<uint32_t>(end - start), "0x%04x ", saddr);
294 }
295 }
296 }
297 break;
298
299 case SPINEL_PROP_RCP_MAC_FRAME_COUNTER:
300 case SPINEL_PROP_RCP_TIMESTAMP:
301 {
302 const char *name;
303 uint32_t value;
304
305 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT32_S, &value);
306 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
307
308 name = (key == SPINEL_PROP_RCP_TIMESTAMP) ? "timestamp" : "counter";
309 start += Snprintf(start, static_cast<uint32_t>(end - start), ", %s:%u", name, value);
310 }
311 break;
312
313 case SPINEL_PROP_RADIO_CAPS:
314 case SPINEL_PROP_RCP_API_VERSION:
315 case SPINEL_PROP_RCP_MIN_HOST_API_VERSION:
316 {
317 const char *name;
318 unsigned int value;
319
320 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT_PACKED_S, &value);
321 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
322
323 switch (key)
324 {
325 case SPINEL_PROP_RADIO_CAPS:
326 name = "caps";
327 break;
328 case SPINEL_PROP_RCP_API_VERSION:
329 name = "version";
330 break;
331 case SPINEL_PROP_RCP_MIN_HOST_API_VERSION:
332 name = "min-host-version";
333 break;
334 default:
335 name = "";
336 break;
337 }
338
339 start += Snprintf(start, static_cast<uint32_t>(end - start), ", %s:%u", name, value);
340 }
341 break;
342
343 case SPINEL_PROP_RCP_LOG_CRASH_DUMP:
344 {
345 const char *name;
346 name = "log-crash-dump";
347
348 start += Snprintf(start, static_cast<uint32_t>(end - start), ", %s", name);
349 }
350 break;
351
352 case SPINEL_PROP_MAC_ENERGY_SCAN_RESULT:
353 case SPINEL_PROP_PHY_CHAN_MAX_POWER:
354 {
355 const char *name;
356 uint8_t channel;
357 int8_t value;
358
359 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT8_S, &channel, &value);
360 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
361
362 name = (key == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT) ? "rssi" : "power";
363 start += Snprintf(start, static_cast<uint32_t>(end - start), ", channel:%u, %s:%d", channel, name, value);
364 }
365 break;
366
367 case SPINEL_PROP_CAPS:
368 {
369 unsigned int capability;
370
371 start += Snprintf(start, static_cast<uint32_t>(end - start), ", caps:");
372
373 while (len > 0)
374 {
375 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT_PACKED_S, &capability);
376 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
377 data += unpacked;
378 len -= static_cast<spinel_size_t>(unpacked);
379 start += Snprintf(start, static_cast<uint32_t>(end - start), "%s ", spinel_capability_to_cstr(capability));
380 }
381 }
382 break;
383
384 case SPINEL_PROP_PROTOCOL_VERSION:
385 {
386 unsigned int major;
387 unsigned int minor;
388
389 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_UINT_PACKED_S,
390 &major, &minor);
391 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
392 start += Snprintf(start, static_cast<uint32_t>(end - start), ", major:%u, minor:%u", major, minor);
393 }
394 break;
395
396 case SPINEL_PROP_PHY_CHAN_PREFERRED:
397 case SPINEL_PROP_PHY_CHAN_SUPPORTED:
398 {
399 uint8_t maskBuffer[kChannelMaskBufferSize];
400 uint32_t channelMask = 0;
401 const uint8_t *maskData = maskBuffer;
402 spinel_size_t maskLength = sizeof(maskBuffer);
403
404 unpacked = spinel_datatype_unpack_in_place(data, len, SPINEL_DATATYPE_DATA_S, maskBuffer, &maskLength);
405 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
406
407 while (maskLength > 0)
408 {
409 uint8_t channel;
410
411 unpacked = spinel_datatype_unpack(maskData, maskLength, SPINEL_DATATYPE_UINT8_S, &channel);
412 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
413 VerifyOrExit(channel < kChannelMaskBufferSize, error = OT_ERROR_PARSE);
414 channelMask |= (1UL << channel);
415
416 maskData += unpacked;
417 maskLength -= static_cast<spinel_size_t>(unpacked);
418 }
419
420 start += Snprintf(start, static_cast<uint32_t>(end - start), ", channelMask:0x%08x", channelMask);
421 }
422 break;
423
424 case SPINEL_PROP_NCP_VERSION:
425 {
426 const char *version;
427
428 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UTF8_S, &version);
429 VerifyOrExit(unpacked >= 0, error = OT_ERROR_PARSE);
430 start += Snprintf(start, static_cast<uint32_t>(end - start), ", version:%s", version);
431 }
432 break;
433
434 case SPINEL_PROP_STREAM_RAW:
435 {
436 otRadioFrame frame;
437
438 if (cmd == SPINEL_CMD_PROP_VALUE_IS)
439 {
440 uint16_t flags;
441 int8_t noiseFloor;
442 unsigned int receiveError;
443
444 unpacked = spinel_datatype_unpack(data, len,
445 SPINEL_DATATYPE_DATA_WLEN_S // Frame
446 SPINEL_DATATYPE_INT8_S // RSSI
447 SPINEL_DATATYPE_INT8_S // Noise Floor
448 SPINEL_DATATYPE_UINT16_S // Flags
449 SPINEL_DATATYPE_STRUCT_S( // PHY-data
450 SPINEL_DATATYPE_UINT8_S // 802.15.4 channel
451 SPINEL_DATATYPE_UINT8_S // 802.15.4 LQI
452 SPINEL_DATATYPE_UINT64_S // Timestamp (us).
453 ) SPINEL_DATATYPE_STRUCT_S( // Vendor-data
454 SPINEL_DATATYPE_UINT_PACKED_S // Receive error
455 ),
456 &frame.mPsdu, &frame.mLength, &frame.mInfo.mRxInfo.mRssi, &noiseFloor,
457 &flags, &frame.mChannel, &frame.mInfo.mRxInfo.mLqi,
458 &frame.mInfo.mRxInfo.mTimestamp, &receiveError);
459 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
460 start += Snprintf(start, static_cast<uint32_t>(end - start), ", len:%u, rssi:%d ...", frame.mLength,
461 frame.mInfo.mRxInfo.mRssi);
462 OT_UNUSED_VARIABLE(start); // Avoid static analysis error
463 LogDebg("%s", buf);
464
465 start = buf;
466 start += Snprintf(start, static_cast<uint32_t>(end - start),
467 "... noise:%d, flags:0x%04x, channel:%u, lqi:%u, timestamp:%lu, rxerr:%u", noiseFloor,
468 flags, frame.mChannel, frame.mInfo.mRxInfo.mLqi,
469 static_cast<unsigned long>(frame.mInfo.mRxInfo.mTimestamp), receiveError);
470 }
471 else if (cmd == SPINEL_CMD_PROP_VALUE_SET)
472 {
473 bool csmaCaEnabled;
474 bool isHeaderUpdated;
475 bool isARetx;
476 bool skipAes;
477
478 unpacked = spinel_datatype_unpack(
479 data, len,
480 SPINEL_DATATYPE_DATA_WLEN_S // Frame data
481 SPINEL_DATATYPE_UINT8_S // Channel
482 SPINEL_DATATYPE_UINT8_S // MaxCsmaBackoffs
483 SPINEL_DATATYPE_UINT8_S // MaxFrameRetries
484 SPINEL_DATATYPE_BOOL_S // CsmaCaEnabled
485 SPINEL_DATATYPE_BOOL_S // IsHeaderUpdated
486 SPINEL_DATATYPE_BOOL_S // IsARetx
487 SPINEL_DATATYPE_BOOL_S // SkipAes
488 SPINEL_DATATYPE_UINT32_S // TxDelay
489 SPINEL_DATATYPE_UINT32_S, // TxDelayBaseTime
490 &frame.mPsdu, &frame.mLength, &frame.mChannel, &frame.mInfo.mTxInfo.mMaxCsmaBackoffs,
491 &frame.mInfo.mTxInfo.mMaxFrameRetries, &csmaCaEnabled, &isHeaderUpdated, &isARetx, &skipAes,
492 &frame.mInfo.mTxInfo.mTxDelay, &frame.mInfo.mTxInfo.mTxDelayBaseTime);
493
494 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
495 start += Snprintf(start, static_cast<uint32_t>(end - start),
496 ", len:%u, channel:%u, maxbackoffs:%u, maxretries:%u ...", frame.mLength, frame.mChannel,
497 frame.mInfo.mTxInfo.mMaxCsmaBackoffs, frame.mInfo.mTxInfo.mMaxFrameRetries);
498 OT_UNUSED_VARIABLE(start); // Avoid static analysis error
499 LogDebg("%s", buf);
500
501 start = buf;
502 start += Snprintf(start, static_cast<uint32_t>(end - start),
503 "... csmaCaEnabled:%u, isHeaderUpdated:%u, isARetx:%u, skipAes:%u"
504 ", txDelay:%u, txDelayBase:%u",
505 csmaCaEnabled, isHeaderUpdated, isARetx, skipAes, frame.mInfo.mTxInfo.mTxDelay,
506 frame.mInfo.mTxInfo.mTxDelayBaseTime);
507 }
508 }
509 break;
510
511 case SPINEL_PROP_STREAM_DEBUG:
512 {
513 char debugString[OPENTHREAD_CONFIG_NCP_SPINEL_LOG_MAX_SIZE + 1];
514 spinel_size_t stringLength = sizeof(debugString);
515
516 unpacked = spinel_datatype_unpack_in_place(data, len, SPINEL_DATATYPE_DATA_S, debugString, &stringLength);
517 assert(stringLength < sizeof(debugString));
518 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
519 debugString[stringLength] = '\0';
520 start += Snprintf(start, static_cast<uint32_t>(end - start), ", debug:%s", debugString);
521 }
522 break;
523
524 case SPINEL_PROP_STREAM_LOG:
525 {
526 const char *logString;
527 uint8_t logLevel;
528
529 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UTF8_S, &logString);
530 VerifyOrExit(unpacked >= 0, error = OT_ERROR_PARSE);
531 data += unpacked;
532 len -= static_cast<spinel_size_t>(unpacked);
533
534 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT8_S, &logLevel);
535 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
536 start += Snprintf(start, static_cast<uint32_t>(end - start), ", level:%u, log:%s", logLevel, logString);
537 }
538 break;
539
540 case SPINEL_PROP_NEST_STREAM_MFG:
541 {
542 const char *output;
543 size_t outputLen;
544
545 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UTF8_S, &output, &outputLen);
546 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
547 start += Snprintf(start, static_cast<uint32_t>(end - start), ", diag:%s", output);
548 }
549 break;
550
551 case SPINEL_PROP_RCP_MAC_KEY:
552 {
553 uint8_t keyIdMode;
554 uint8_t keyId;
555 otMacKey prevKey;
556 unsigned int prevKeyLen = sizeof(otMacKey);
557 otMacKey currKey;
558 unsigned int currKeyLen = sizeof(otMacKey);
559 otMacKey nextKey;
560 unsigned int nextKeyLen = sizeof(otMacKey);
561
562 unpacked = spinel_datatype_unpack(data, len,
563 SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_DATA_WLEN_S
564 SPINEL_DATATYPE_DATA_WLEN_S SPINEL_DATATYPE_DATA_WLEN_S,
565 &keyIdMode, &keyId, prevKey.m8, &prevKeyLen, currKey.m8, &currKeyLen,
566 nextKey.m8, &nextKeyLen);
567 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
568 start += Snprintf(start, static_cast<uint32_t>(end - start),
569 ", keyIdMode:%u, keyId:%u, prevKey:***, currKey:***, nextKey:***", keyIdMode, keyId);
570 }
571 break;
572
573 case SPINEL_PROP_HWADDR:
574 case SPINEL_PROP_MAC_15_4_LADDR:
575 {
576 const char *name = nullptr;
577 uint8_t m8[OT_EXT_ADDRESS_SIZE] = {0};
578
579 unpacked = spinel_datatype_unpack_in_place(data, len, SPINEL_DATATYPE_EUI64_S, &m8[0]);
580 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
581
582 name = (key == SPINEL_PROP_HWADDR) ? "eui64" : "laddr";
583 start += Snprintf(start, static_cast<uint32_t>(end - start), ", %s:%02x%02x%02x%02x%02x%02x%02x%02x", name,
584 m8[0], m8[1], m8[2], m8[3], m8[4], m8[5], m8[6], m8[7]);
585 }
586 break;
587
588 case SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES:
589 {
590 uint8_t m8[OT_EXT_ADDRESS_SIZE];
591
592 start += Snprintf(start, static_cast<uint32_t>(end - start), ", extaddr:");
593
594 if (len < sizeof(m8))
595 {
596 start += Snprintf(start, static_cast<uint32_t>(end - start), "none");
597 }
598 else
599 {
600 while (len >= sizeof(m8))
601 {
602 unpacked = spinel_datatype_unpack_in_place(data, len, SPINEL_DATATYPE_EUI64_S, m8);
603 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
604 data += unpacked;
605 len -= static_cast<spinel_size_t>(unpacked);
606 start += Snprintf(start, static_cast<uint32_t>(end - start), "%02x%02x%02x%02x%02x%02x%02x%02x ", m8[0],
607 m8[1], m8[2], m8[3], m8[4], m8[5], m8[6], m8[7]);
608 }
609 }
610 }
611 break;
612
613 case SPINEL_PROP_RADIO_COEX_METRICS:
614 {
615 otRadioCoexMetrics metrics;
616 unpacked = spinel_datatype_unpack(
617 data, len,
618 SPINEL_DATATYPE_STRUCT_S( // Tx Coex Metrics Structure
619 SPINEL_DATATYPE_UINT32_S // NumTxRequest
620 SPINEL_DATATYPE_UINT32_S // NumTxGrantImmediate
621 SPINEL_DATATYPE_UINT32_S // NumTxGrantWait
622 SPINEL_DATATYPE_UINT32_S // NumTxGrantWaitActivated
623 SPINEL_DATATYPE_UINT32_S // NumTxGrantWaitTimeout
624 SPINEL_DATATYPE_UINT32_S // NumTxGrantDeactivatedDuringRequest
625 SPINEL_DATATYPE_UINT32_S // NumTxDelayedGrant
626 SPINEL_DATATYPE_UINT32_S // AvgTxRequestToGrantTime
627 ) SPINEL_DATATYPE_STRUCT_S( // Rx Coex Metrics Structure
628 SPINEL_DATATYPE_UINT32_S // NumRxRequest
629 SPINEL_DATATYPE_UINT32_S // NumRxGrantImmediate
630 SPINEL_DATATYPE_UINT32_S // NumRxGrantWait
631 SPINEL_DATATYPE_UINT32_S // NumRxGrantWaitActivated
632 SPINEL_DATATYPE_UINT32_S // NumRxGrantWaitTimeout
633 SPINEL_DATATYPE_UINT32_S // NumRxGrantDeactivatedDuringRequest
634 SPINEL_DATATYPE_UINT32_S // NumRxDelayedGrant
635 SPINEL_DATATYPE_UINT32_S // AvgRxRequestToGrantTime
636 SPINEL_DATATYPE_UINT32_S // NumRxGrantNone
637 ) SPINEL_DATATYPE_BOOL_S // Stopped
638 SPINEL_DATATYPE_UINT32_S, // NumGrantGlitch
639 &metrics.mNumTxRequest, &metrics.mNumTxGrantImmediate, &metrics.mNumTxGrantWait,
640 &metrics.mNumTxGrantWaitActivated, &metrics.mNumTxGrantWaitTimeout,
641 &metrics.mNumTxGrantDeactivatedDuringRequest, &metrics.mNumTxDelayedGrant,
642 &metrics.mAvgTxRequestToGrantTime, &metrics.mNumRxRequest, &metrics.mNumRxGrantImmediate,
643 &metrics.mNumRxGrantWait, &metrics.mNumRxGrantWaitActivated, &metrics.mNumRxGrantWaitTimeout,
644 &metrics.mNumRxGrantDeactivatedDuringRequest, &metrics.mNumRxDelayedGrant,
645 &metrics.mAvgRxRequestToGrantTime, &metrics.mNumRxGrantNone, &metrics.mStopped, &metrics.mNumGrantGlitch);
646
647 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
648
649 LogDebg("%s ...", buf);
650 LogDebg(" txRequest:%lu", ToUlong(metrics.mNumTxRequest));
651 LogDebg(" txGrantImmediate:%lu", ToUlong(metrics.mNumTxGrantImmediate));
652 LogDebg(" txGrantWait:%lu", ToUlong(metrics.mNumTxGrantWait));
653 LogDebg(" txGrantWaitActivated:%lu", ToUlong(metrics.mNumTxGrantWaitActivated));
654 LogDebg(" txGrantWaitTimeout:%lu", ToUlong(metrics.mNumTxGrantWaitTimeout));
655 LogDebg(" txGrantDeactivatedDuringRequest:%lu", ToUlong(metrics.mNumTxGrantDeactivatedDuringRequest));
656 LogDebg(" txDelayedGrant:%lu", ToUlong(metrics.mNumTxDelayedGrant));
657 LogDebg(" avgTxRequestToGrantTime:%lu", ToUlong(metrics.mAvgTxRequestToGrantTime));
658 LogDebg(" rxRequest:%lu", ToUlong(metrics.mNumRxRequest));
659 LogDebg(" rxGrantImmediate:%lu", ToUlong(metrics.mNumRxGrantImmediate));
660 LogDebg(" rxGrantWait:%lu", ToUlong(metrics.mNumRxGrantWait));
661 LogDebg(" rxGrantWaitActivated:%lu", ToUlong(metrics.mNumRxGrantWaitActivated));
662 LogDebg(" rxGrantWaitTimeout:%lu", ToUlong(metrics.mNumRxGrantWaitTimeout));
663 LogDebg(" rxGrantDeactivatedDuringRequest:%lu", ToUlong(metrics.mNumRxGrantDeactivatedDuringRequest));
664 LogDebg(" rxDelayedGrant:%lu", ToUlong(metrics.mNumRxDelayedGrant));
665 LogDebg(" avgRxRequestToGrantTime:%lu", ToUlong(metrics.mAvgRxRequestToGrantTime));
666 LogDebg(" rxGrantNone:%lu", ToUlong(metrics.mNumRxGrantNone));
667 LogDebg(" stopped:%u", metrics.mStopped);
668
669 start = buf;
670 start += Snprintf(start, static_cast<uint32_t>(end - start), " grantGlitch:%u", metrics.mNumGrantGlitch);
671 }
672 break;
673
674 case SPINEL_PROP_MAC_SCAN_MASK:
675 {
676 constexpr uint8_t kNumChannels = 16;
677 uint8_t channels[kNumChannels];
678 spinel_size_t size;
679
680 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_DATA_S, channels, &size);
681 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
682 start += Snprintf(start, static_cast<uint32_t>(end - start), ", channels:");
683
684 for (spinel_size_t i = 0; i < size; i++)
685 {
686 start += Snprintf(start, static_cast<uint32_t>(end - start), "%u ", channels[i]);
687 }
688 }
689 break;
690
691 case SPINEL_PROP_RCP_ENH_ACK_PROBING:
692 {
693 uint16_t saddr;
694 uint8_t m8[OT_EXT_ADDRESS_SIZE];
695 uint8_t flags;
696
697 unpacked = spinel_datatype_unpack(
698 data, len, SPINEL_DATATYPE_UINT16_S SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_UINT8_S, &saddr, m8, &flags);
699
700 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
701 start += Snprintf(start, static_cast<uint32_t>(end - start),
702 ", saddr:%04x, extaddr:%02x%02x%02x%02x%02x%02x%02x%02x, flags:0x%02x", saddr, m8[0], m8[1],
703 m8[2], m8[3], m8[4], m8[5], m8[6], m8[7], flags);
704 }
705 break;
706
707 case SPINEL_PROP_PHY_CALIBRATED_POWER:
708 {
709 if (cmd == SPINEL_CMD_PROP_VALUE_INSERT)
710 {
711 uint8_t channel;
712 int16_t actualPower;
713 uint8_t *rawPowerSetting;
714 unsigned int rawPowerSettingLength;
715
716 unpacked = spinel_datatype_unpack(
717 data, len, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT16_S SPINEL_DATATYPE_DATA_WLEN_S, &channel,
718 &actualPower, &rawPowerSetting, &rawPowerSettingLength);
719 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
720
721 start += Snprintf(start, static_cast<uint32_t>(end - start),
722 ", ch:%u, actualPower:%d, rawPowerSetting:", channel, actualPower);
723 for (unsigned int i = 0; i < rawPowerSettingLength; i++)
724 {
725 start += Snprintf(start, static_cast<uint32_t>(end - start), "%02x", rawPowerSetting[i]);
726 }
727 }
728 }
729 break;
730
731 case SPINEL_PROP_PHY_CHAN_TARGET_POWER:
732 {
733 uint8_t channel;
734 int16_t targetPower;
735
736 unpacked =
737 spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT16_S, &channel, &targetPower);
738 VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
739 start += Snprintf(start, static_cast<uint32_t>(end - start), ", ch:%u, targetPower:%d", channel, targetPower);
740 }
741 break;
742 }
743
744 exit:
745 OT_UNUSED_VARIABLE(start); // Avoid static analysis error
746 if (error == OT_ERROR_NONE)
747 {
748 LogDebg("%s", buf);
749 }
750 else if (prefix != nullptr)
751 {
752 LogDebg("%s, failed to parse spinel frame !", prefix);
753 }
754 }
755
756 } // namespace Spinel
757 } // namespace ot
758