1 /* 2 * Copyright (c) 2016, 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" AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /** 29 * @file 30 * This file contains definitions a spinel interface to the OpenThread stack. 31 */ 32 33 #ifndef NCP_BASE_HPP_ 34 #define NCP_BASE_HPP_ 35 36 #include "openthread-core-config.h" 37 38 #include "ncp/ncp_config.h" 39 40 #if OPENTHREAD_MTD || OPENTHREAD_FTD 41 #include <openthread/ip6.h> 42 #else 43 #include <openthread/platform/radio.h> 44 #endif 45 #if OPENTHREAD_FTD 46 #include <openthread/thread_ftd.h> 47 #endif 48 #include <openthread/message.h> 49 #include <openthread/ncp.h> 50 #if OPENTHREAD_CONFIG_MULTI_RADIO 51 #include <openthread/multi_radio.h> 52 #endif 53 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 54 #include <openthread/srp_client.h> 55 #endif 56 #include <openthread/platform/dnssd.h> 57 58 #include "changed_props_set.hpp" 59 #include "common/tasklet.hpp" 60 #include "instance/instance.hpp" 61 #include "lib/spinel/spinel.h" 62 #include "lib/spinel/spinel_buffer.hpp" 63 #include "lib/spinel/spinel_decoder.hpp" 64 #include "lib/spinel/spinel_encoder.hpp" 65 #include "lib/spinel/spinel_prop_codec.hpp" 66 67 #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE 68 #define SPINEL_HEADER_IID_BROADCAST OPENTHREAD_SPINEL_CONFIG_BROADCAST_IID 69 #else 70 #define SPINEL_HEADER_IID_BROADCAST SPINEL_HEADER_IID_0 71 #endif 72 73 // In case of host<->ncp<->rcp configuration, notifications shall be 74 // received on broadcast iid on ncp, but transmitted on IID 0 to host. 75 #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE && OPENTHREAD_RADIO 76 #define SPINEL_HEADER_TX_NOTIFICATION_IID SPINEL_HEADER_IID_BROADCAST 77 #else 78 #define SPINEL_HEADER_TX_NOTIFICATION_IID SPINEL_HEADER_IID_0 79 #endif 80 81 namespace ot { 82 namespace Ncp { 83 84 class NcpBase 85 { 86 public: 87 enum 88 { 89 kSpinelCmdHeaderSize = 2, ///< Size of spinel command header (in bytes). 90 kSpinelPropIdSize = 3, ///< Size of spinel property identifier (in bytes). 91 #if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE && OPENTHREAD_RADIO 92 kSpinelInterfaceCount = SPINEL_HEADER_IID_MAX + 1, // Number of supported spinel interfaces 93 #else 94 kSpinelInterfaceCount = 1, // Only one interface supported in single instance configuration 95 #endif 96 }; 97 98 /** 99 * Creates and initializes an NcpBase instance. 100 * 101 * @param[in] aInstance The OpenThread instance structure. 102 */ 103 explicit NcpBase(Instance *aInstance); 104 105 #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE && OPENTHREAD_RADIO 106 /** 107 * Creates and initializes an NcpBase instance. 108 * 109 * @param[in] aInstances The OpenThread instances structure pointer array. 110 * @param[in] aCount Number of the instances in the array. 111 */ 112 explicit NcpBase(Instance **aInstances, uint8_t aCount); 113 114 #endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE && OPENTHREAD_RADIO 115 116 /** 117 * Returns the pointer to the single NCP instance. 118 * 119 * @returns Pointer to the single NCP instance. 120 */ 121 static NcpBase *GetNcpInstance(void); 122 123 /** 124 * Returns an IID for the given instance 125 * 126 * Returned IID is an integer value that must be shifted by SPINEL_HEADER_IID_SHIFT before putting into spinel 127 * header. If multipan interface is not enabled or build is not for RCP IID=0 is returned. If nullptr is passed it 128 * matches broadcast IID in current implementation. Broadcast IID is also returned in case no match was found. 129 * 130 * @param[in] aInstance Instance pointer to match with IID 131 * 132 * @returns Spinel Interface Identifier to use for communication for this instance 133 */ 134 uint8_t InstanceToIid(Instance *aInstance); 135 136 /** 137 * Returns an OT instance for the given IID 138 * 139 * Returns an OpenThread instance object associated to the given IID. 140 * If multipan interface is not enabled or build is not for RCP returned value is the same instance object 141 * regardless of the aIid parameter In current implementation nullptr is returned for broadcast IID and values 142 * exceeding the instances count but lower than kSpinelInterfaceCount. 143 * 144 * @param[in] aIid IID used in the Spinel communication 145 * 146 * @returns OpenThread instance object associated with the given IID 147 */ 148 Instance *IidToInstance(uint8_t aIid); 149 150 #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE 151 /** 152 * Called to send notification to host about switchower results. 153 */ 154 void NotifySwitchoverDone(otInstance *aInstance, bool aSuccess); 155 #endif 156 157 /** 158 * This method returns the IID of the current spinel command. 159 * 160 * @returns IID. 161 */ 162 spinel_iid_t GetCurCommandIid(void) const; 163 164 /** 165 * Sends data to host via specific stream. 166 * 167 * 168 * @param[in] aStreamId A numeric identifier for the stream to write to. 169 * If set to '0', will default to the debug stream. 170 * @param[in] aDataPtr A pointer to the data to send on the stream. 171 * If aDataLen is non-zero, this param MUST NOT be nullptr. 172 * @param[in] aDataLen The number of bytes of data from aDataPtr to send. 173 * 174 * @retval OT_ERROR_NONE The data was queued for delivery to the host. 175 * @retval OT_ERROR_BUSY There are not enough resources to complete this 176 * request. This is usually a temporary condition. 177 * @retval OT_ERROR_INVALID_ARGS The given aStreamId was invalid. 178 */ 179 otError StreamWrite(int aStreamId, const uint8_t *aDataPtr, int aDataLen); 180 181 /** 182 * Send an OpenThread log message to host via `SPINEL_PROP_STREAM_LOG` property. 183 * 184 * @param[in] aLogLevel The log level 185 * @param[in] aLogRegion The log region 186 * @param[in] aLogString The log string 187 */ 188 void Log(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aLogString); 189 190 #if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE 191 /** 192 * Registers peek/poke delegate functions with NCP module. 193 * 194 * @param[in] aAllowPeekDelegate Delegate function pointer for peek operation. 195 * @param[in] aAllowPokeDelegate Delegate function pointer for poke operation. 196 */ 197 void RegisterPeekPokeDelegates(otNcpDelegateAllowPeekPoke aAllowPeekDelegate, 198 otNcpDelegateAllowPeekPoke aAllowPokeDelegate); 199 #endif 200 201 /** 202 * Is called by the framer whenever a framing error is detected. 203 */ 204 void IncrementFrameErrorCounter(void); 205 206 /** 207 * Called by the subclass to indicate when a frame has been received. 208 */ 209 void HandleReceive(const uint8_t *aBuf, uint16_t aBufLength); 210 211 /** 212 * Called by the subclass to learn when the host wake operation must be issued. 213 */ 214 bool ShouldWakeHost(void); 215 216 /** 217 * Called by the subclass to learn when the transfer to the host should be deferred. 218 */ 219 bool ShouldDeferHostSend(void); 220 221 /** 222 * Check if the infrastructure interface has an IPv6 address. 223 * 224 * @param[in] aInfraIfIndex The index of the instructure interface to query. 225 * @param[in] aAddress The IPv6 address to query. 226 */ 227 bool InfraIfHasAddress(uint32_t aInfraIfIndex, const otIp6Address *aAddress); 228 229 /** 230 * Send a ICMP6 ND message through the Infrastructure interface on the host. 231 * 232 * @param[in] aInfraIfIndex The index of the infrastructure interface this message is sent to. 233 * @param[in] aDestAddress The destination address this message is sent to. 234 * @param[in] aBuffer The ICMPv6 message buffer. The ICMPv6 checksum is left zero and the 235 * platform should do the checksum calculate. 236 * @param[in] aBufferLength The length of the message buffer. 237 * 238 * @note Per RFC 4861, the implementation should send the message with IPv6 link-local source address 239 * of interface @p aInfraIfIndex and IP Hop Limit 255. 240 * 241 * @retval OT_ERROR_NONE Successfully sent the ICMPv6 message. 242 * @retval OT_ERROR_FAILED Failed to send the ICMPv6 message. 243 */ 244 otError InfraIfSendIcmp6Nd(uint32_t aInfraIfIndex, 245 const otIp6Address *aDestAddress, 246 const uint8_t *aBuffer, 247 uint16_t aBufferLength); 248 249 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE 250 /** 251 * Registers or updates a host on the infrastructure network's DNS-SD module (on host). 252 * 253 * @param[in] aHost Information about the host to register. 254 * @param[in] aRequestId The ID associated with this request. 255 * @param[in] aCallback The callback function pointer to report the outcome (may be NULL if no callback needed). 256 */ 257 void DnssdRegisterHost(const otPlatDnssdHost *aHost, 258 otPlatDnssdRequestId aRequestId, 259 otPlatDnssdRegisterCallback aCallback); 260 261 /** 262 * Unregisters a host on the infrastructure network's DNS-SD module (on host). 263 * 264 * @param[in] aHost Information about the host to register. 265 * @param[in] aRequestId The ID associated with this request. 266 * @param[in] aCallback The callback function pointer to report the outcome (may be NULL if no callback needed). 267 */ 268 void DnssdUnregisterHost(const otPlatDnssdHost *aHost, 269 otPlatDnssdRequestId aRequestId, 270 otPlatDnssdRegisterCallback aCallback); 271 272 /** 273 * Registers or updates a service on the infrastructure network's DNS-SD module (on host). 274 * 275 * @param[in] aService Information about the service to register. 276 * @param[in] aRequestId The ID associated with this request. 277 * @param[in] aCallback The callback function pointer to report the outcome (may be NULL if no callback needed). 278 */ 279 void DnssdRegisterService(const otPlatDnssdService *aService, 280 otPlatDnssdRequestId aRequestId, 281 otPlatDnssdRegisterCallback aCallback); 282 283 /** 284 * Unregisters a service on the infrastructure network's DNS-SD module (on host). 285 * 286 * @param[in] aService Information about the service to unregister. 287 * @param[in] aRequestId The ID associated with this request. 288 * @param[in] aCallback The callback function pointer to report the outcome (may be NULL if no callback needed). 289 */ 290 void DnssdUnregisterService(const otPlatDnssdService *aService, 291 otPlatDnssdRequestId aRequestId, 292 otPlatDnssdRegisterCallback aCallback); 293 294 /** 295 * Registers or updates a key record on the infrastructure network's DNS-SD module (on host). 296 * 297 * @param[in] aKey Information about the key record to register. 298 * @param[in] aRequestId The ID associated with this request. 299 * @param[in] aCallback The callback function pointer to report the outcome (may be NULL if no callback needed). 300 */ 301 void DnssdRegisterKey(const otPlatDnssdKey *aKey, 302 otPlatDnssdRequestId aRequestId, 303 otPlatDnssdRegisterCallback aCallback); 304 305 /** 306 * Unregisters a key record on the infrastructure network's DNS-SD module (on host). 307 * 308 * @param[in] aKey Information about the key record to register. 309 * @param[in] aRequestId The ID associated with this request. 310 * @param[in] aCallback The callback function pointer to report the outcome (may be NULL if no callback needed). 311 */ 312 void DnssdUnregisterKey(const otPlatDnssdKey *aKey, 313 otPlatDnssdRequestId aRequestId, 314 otPlatDnssdRegisterCallback aCallback); 315 316 /** 317 * Gets the Dnssd state. 318 * 319 * Returns the platform dnssd state. 320 */ 321 otPlatDnssdState DnssdGetState(void); 322 #endif 323 324 protected: 325 static constexpr uint8_t kBitsPerByte = 8; ///< Number of bits in a byte. 326 327 typedef otError (NcpBase::*PropertyHandler)(void); 328 329 /** 330 * Represents the `ResponseEntry` type. 331 */ 332 enum ResponseType 333 { 334 kResponseTypeGet = 0, ///< Response entry is for a `VALUE_GET` command. 335 kResponseTypeSet, ///< Response entry is for a `VALUE_SET` command. 336 kResponseTypeLastStatus, ///< Response entry is a `VALUE_IS(LAST_STATUS)`. 337 }; 338 339 /** 340 * Represents a spinel response entry. 341 */ 342 struct ResponseEntry 343 { 344 uint8_t mIid : 2; ///< Spinel interface id. 345 uint8_t mTid : 4; ///< Spinel transaction id. 346 bool mIsInUse : 1; ///< `true` if this entry is in use, `false` otherwise. 347 ResponseType mType : 2; ///< Response type. 348 uint32_t mPropKeyOrStatus : 24; ///< 3 bytes for either property key or spinel status. 349 }; 350 351 struct HandlerEntry 352 { 353 spinel_prop_key_t mKey; 354 NcpBase::PropertyHandler mHandler; 355 }; 356 357 Spinel::Buffer::FrameTag GetLastOutboundFrameTag(void); 358 359 otError HandleCommand(uint8_t aHeader); 360 361 #if __cplusplus >= 201103L 362 static constexpr bool AreHandlerEntriesSorted(const HandlerEntry *aHandlerEntries, size_t aSize); 363 #endif 364 365 static PropertyHandler FindPropertyHandler(const HandlerEntry *aHandlerEntries, 366 size_t aSize, 367 spinel_prop_key_t aKey); 368 static PropertyHandler FindGetPropertyHandler(spinel_prop_key_t aKey); 369 static PropertyHandler FindSetPropertyHandler(spinel_prop_key_t aKey); 370 static PropertyHandler FindInsertPropertyHandler(spinel_prop_key_t aKey); 371 static PropertyHandler FindRemovePropertyHandler(spinel_prop_key_t aKey); 372 373 bool HandlePropertySetForSpecialProperties(uint8_t aHeader, spinel_prop_key_t aKey, otError &aError); 374 otError HandleCommandPropertySet(uint8_t aHeader, spinel_prop_key_t aKey); 375 otError HandleCommandPropertyInsertRemove(uint8_t aHeader, spinel_prop_key_t aKey, unsigned int aCommand); 376 377 otError WriteLastStatusFrame(uint8_t aHeader, spinel_status_t aLastStatus); 378 otError WritePropertyValueIsFrame(uint8_t aHeader, spinel_prop_key_t aPropKey, bool aIsGetResponse = true); 379 otError WritePropertyValueInsertedRemovedFrame(uint8_t aHeader, 380 unsigned int aResponseCommand, 381 spinel_prop_key_t aPropKey, 382 const uint8_t *aValuePtr, 383 uint16_t aValueLen); 384 385 otError SendQueuedResponses(void); IsResponseQueueEmpty(void) const386 bool IsResponseQueueEmpty(void) const { return (mResponseQueueHead == mResponseQueueTail); } 387 otError EnqueueResponse(uint8_t aHeader, ResponseType aType, unsigned int aPropKeyOrStatus); 388 PrepareGetResponse(uint8_t aHeader,spinel_prop_key_t aPropKey)389 otError PrepareGetResponse(uint8_t aHeader, spinel_prop_key_t aPropKey) 390 { 391 return EnqueueResponse(aHeader, kResponseTypeGet, aPropKey); 392 } PrepareSetResponse(uint8_t aHeader,spinel_prop_key_t aPropKey)393 otError PrepareSetResponse(uint8_t aHeader, spinel_prop_key_t aPropKey) 394 { 395 return EnqueueResponse(aHeader, kResponseTypeSet, aPropKey); 396 } PrepareLastStatusResponse(uint8_t aHeader,spinel_status_t aStatus)397 otError PrepareLastStatusResponse(uint8_t aHeader, spinel_status_t aStatus) 398 { 399 return EnqueueResponse(aHeader, kResponseTypeLastStatus, aStatus); 400 } 401 402 static uint8_t GetWrappedResponseQueueIndex(uint8_t aPosition); 403 404 static void UpdateChangedProps(Tasklet &aTasklet); 405 void UpdateChangedProps(void); 406 407 static void HandleFrameRemovedFromNcpBuffer(void *aContext, 408 Spinel::Buffer::FrameTag aFrameTag, 409 Spinel::Buffer::Priority aPriority, 410 Spinel::Buffer *aNcpBuffer); 411 void HandleFrameRemovedFromNcpBuffer(Spinel::Buffer::FrameTag aFrameTag); 412 413 otError EncodeChannelMask(uint32_t aChannelMask); 414 otError DecodeChannelMask(uint32_t &aChannelMask); 415 416 #if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE 417 otError PackRadioFrame(otRadioFrame *aFrame, otError aError); 418 419 #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE 420 void NotifySwitchoverDone(bool aSuccess); 421 #endif 422 423 static void LinkRawReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError); 424 void LinkRawReceiveDone(uint8_t aIid, otRadioFrame *aFrame, otError aError); 425 426 static void LinkRawTransmitDone(otInstance *aInstance, 427 otRadioFrame *aFrame, 428 otRadioFrame *aAckFrame, 429 otError aError); 430 void LinkRawTransmitDone(uint8_t aIid, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError); 431 432 static void LinkRawEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi); 433 void LinkRawEnergyScanDone(uint8_t aIid, int8_t aEnergyScanMaxRssi); 434 GetNcpBaseIid(otInstance * aInstance)435 static inline uint8_t GetNcpBaseIid(otInstance *aInstance) 436 { 437 return sNcpInstance->InstanceToIid(static_cast<Instance *>(aInstance)); 438 } 439 440 #endif // OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE 441 442 #if OPENTHREAD_MTD || OPENTHREAD_FTD 443 static void HandleStateChanged(otChangedFlags aFlags, void *aContext); 444 void ProcessThreadChangedFlags(void); 445 446 static void HandlePcapFrame(const otRadioFrame *aFrame, bool aIsTx, void *aContext); 447 void HandlePcapFrame(const otRadioFrame *aFrame, bool aIsTx); 448 449 static void HandleTimeSyncUpdate(void *aContext); 450 void HandleTimeSyncUpdate(void); 451 452 #if OPENTHREAD_FTD 453 static void HandleNeighborTableChanged(otNeighborTableEvent aEvent, const otNeighborTableEntryInfo *aEntry); 454 void HandleNeighborTableChanged(otNeighborTableEvent aEvent, const otNeighborTableEntryInfo &aEntry); 455 456 #if OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE 457 static void HandleParentResponseInfo(otThreadParentResponseInfo *aInfo, void *aContext); 458 void HandleParentResponseInfo(const otThreadParentResponseInfo &aInfo); 459 #endif 460 #endif 461 462 static void HandleDatagramFromStack(otMessage *aMessage, void *aContext); 463 void HandleDatagramFromStack(otMessage *aMessage); 464 465 otError SendQueuedDatagramMessages(void); 466 otError SendDatagramMessage(otMessage *aMessage); 467 468 static void HandleActiveScanResult_Jump(otActiveScanResult *aResult, void *aContext); 469 void HandleActiveScanResult(otActiveScanResult *aResult); 470 471 static void HandleEnergyScanResult_Jump(otEnergyScanResult *aResult, void *aContext); 472 void HandleEnergyScanResult(otEnergyScanResult *aResult); 473 474 static void HandleJamStateChange_Jump(bool aJamState, void *aContext); 475 void HandleJamStateChange(bool aJamState); 476 477 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE 478 static void HandleCommissionerEnergyReport_Jump(uint32_t aChannelMask, 479 const uint8_t *aEnergyData, 480 uint8_t aLength, 481 void *aContext); 482 void HandleCommissionerEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyData, uint8_t aLength); 483 484 static void HandleCommissionerPanIdConflict_Jump(uint16_t aPanId, uint32_t aChannelMask, void *aContext); 485 void HandleCommissionerPanIdConflict(uint16_t aPanId, uint32_t aChannelMask); 486 #endif 487 488 #if OPENTHREAD_CONFIG_JOINER_ENABLE 489 static void HandleJoinerCallback_Jump(otError aError, void *aContext); 490 void HandleJoinerCallback(otError aError); 491 #endif 492 493 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 494 static void HandleLinkMetricsReport_Jump(const otIp6Address *aSource, 495 const otLinkMetricsValues *aMetricsValues, 496 otLinkMetricsStatus aStatus, 497 void *aContext); 498 499 void HandleLinkMetricsReport(const otIp6Address *aSource, 500 const otLinkMetricsValues *aMetricsValues, 501 otLinkMetricsStatus aStatus); 502 503 static void HandleLinkMetricsMgmtResponse_Jump(const otIp6Address *aSource, 504 otLinkMetricsStatus aStatus, 505 void *aContext); 506 507 void HandleLinkMetricsMgmtResponse(const otIp6Address *aSource, otLinkMetricsStatus aStatus); 508 509 static void HandleLinkMetricsEnhAckProbingIeReport_Jump(otShortAddress aShortAddress, 510 const otExtAddress *aExtAddress, 511 const otLinkMetricsValues *aMetricsValues, 512 void *aContext); 513 514 void HandleLinkMetricsEnhAckProbingIeReport(otShortAddress aShortAddress, 515 const otExtAddress *aExtAddress, 516 const otLinkMetricsValues *aMetricsValues); 517 #endif 518 519 static void HandleMlrRegResult_Jump(void *aContext, 520 otError aError, 521 uint8_t aMlrStatus, 522 const otIp6Address *aFailedAddresses, 523 uint8_t aFailedAddressNum); 524 void HandleMlrRegResult(otError aError, 525 uint8_t aMlrStatus, 526 const otIp6Address *aFailedAddresses, 527 uint8_t aFailedAddressNum); 528 529 otError EncodeOperationalDataset(const otOperationalDataset &aDataset); 530 531 otError DecodeOperationalDataset(otOperationalDataset &aDataset, 532 const uint8_t **aTlvs = nullptr, 533 uint8_t *aTlvsLength = nullptr, 534 const otIp6Address **aDestIpAddress = nullptr, 535 bool aAllowEmptyValues = false); 536 537 otError EncodeNeighborInfo(const otNeighborInfo &aNeighborInfo); 538 #if OPENTHREAD_CONFIG_MULTI_RADIO 539 otError EncodeNeighborMultiRadioInfo(uint32_t aSpinelRadioLink, const otRadioLinkInfo &aInfo); 540 #endif 541 542 #if OPENTHREAD_FTD 543 otError EncodeChildInfo(const otChildInfo &aChildInfo); 544 #endif 545 546 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 547 otError EncodeLinkMetricsValues(const otLinkMetricsValues *aMetricsValues); 548 #endif 549 550 #if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE 551 static void HandleUdpForwardStream(otMessage *aMessage, 552 uint16_t aPeerPort, 553 otIp6Address *aPeerAddr, 554 uint16_t aSockPort, 555 void *aContext); 556 void HandleUdpForwardStream(otMessage *aMessage, uint16_t aPeerPort, otIp6Address &aPeerAddr, uint16_t aPort); 557 #endif // OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE 558 #endif // OPENTHREAD_MTD || OPENTHREAD_FTD 559 560 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 561 otError DecodeLinkMetrics(otLinkMetrics *aMetrics, bool aAllowPduCount); 562 #endif 563 564 otError CommandHandler_NOOP(uint8_t aHeader); 565 otError CommandHandler_RESET(uint8_t aHeader); 566 // Combined command handler for `VALUE_GET`, `VALUE_SET`, `VALUE_INSERT` and `VALUE_REMOVE`. 567 otError CommandHandler_PROP_VALUE_update(uint8_t aHeader, unsigned int aCommand); 568 #if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE 569 otError CommandHandler_PEEK(uint8_t aHeader); 570 otError CommandHandler_POKE(uint8_t aHeader); 571 #endif 572 #if OPENTHREAD_MTD || OPENTHREAD_FTD 573 otError CommandHandler_NET_CLEAR(uint8_t aHeader); 574 #endif 575 576 // ---------------------------------------------------------------------------- 577 // Property Handlers 578 // ---------------------------------------------------------------------------- 579 // 580 // There are 4 types of property handlers for "get", "set", "insert", and 581 // "remove" commands. 582 // 583 // "Get" handlers should get/retrieve the property value and then encode and 584 // write the value into the NCP buffer. If the "get" operation itself fails, 585 // "get" handler should write a `LAST_STATUS` with the error status into the NCP 586 // buffer. The `otError` returned from a "get" handler is the error of writing 587 // into the NCP buffer (e.g., running out buffer), and not of the "get" operation 588 // itself. 589 // 590 // "Set/Insert/Remove" handlers should first decode/parse the value from the 591 // input Spinel frame and then perform the corresponding set/insert/remove 592 // operation. They are not responsible for preparing the Spinel response and 593 // therefore should not write anything to the NCP buffer. The `otError` returned 594 // from a "set/insert/remove" handler indicates the error in either parsing of 595 // the input or the error of set/insert/remove operation. 596 // 597 // The corresponding command handler (e.g., `HandleCommandPropertySet()` for 598 // `VALUE_SET` command) will take care of preparing the Spinel response after 599 // invoking the "set/insert/remove" handler for a given property. For example, 600 // for a `VALUE_SET` command, if the "set" handler returns an error, then a 601 // `LAST_STATUS` update response is prepared, otherwise on success the "get" 602 // handler for the property is used to prepare a `VALUE_IS` Spinel response (in 603 // cases where there is no "get" handler for the property, the input value is 604 // echoed in the response). 605 // 606 // Few properties require special treatment where the response needs to be 607 // prepared directly in the "set" handler (e.g., `HOST_POWER_STATE` or 608 // `NEST_STREAM_MFG`). These properties have a different handler method format 609 // (they expect `aHeader` as an input argument) and are processed separately in 610 // `HandleCommandPropertySet()`. 611 612 template <spinel_prop_key_t aKey> otError HandlePropertyGet(void); 613 template <spinel_prop_key_t aKey> otError HandlePropertySet(void); 614 template <spinel_prop_key_t aKey> otError HandlePropertyInsert(void); 615 template <spinel_prop_key_t aKey> otError HandlePropertyRemove(void); 616 617 // -------------------------------------------------------------------------- 618 // Property "set" handlers for special properties for which the spinel 619 // response needs to be created from within the set handler. 620 621 otError HandlePropertySet_SPINEL_PROP_HOST_POWER_STATE(uint8_t aHeader); 622 623 #if OPENTHREAD_CONFIG_DIAG_ENABLE 624 static_assert(OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE <= 625 OPENTHREAD_CONFIG_NCP_TX_BUFFER_SIZE - kSpinelCmdHeaderSize - kSpinelPropIdSize, 626 "diag output buffer should be smaller than NCP HDLC tx buffer"); 627 628 otError HandlePropertySet_SPINEL_PROP_NEST_STREAM_MFG(uint8_t aHeader); 629 #endif 630 631 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE 632 otError HandlePropertySet_SPINEL_PROP_MESHCOP_COMMISSIONER_GENERATE_PSKC(uint8_t aHeader); 633 otError HandlePropertySet_SPINEL_PROP_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader); 634 #endif // OPENTHREAD_FTD 635 636 #if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE 637 otError DecodeStreamRawTxRequest(otRadioFrame &aFrame); 638 otError HandlePropertySet_SPINEL_PROP_STREAM_RAW(uint8_t aHeader); 639 #endif 640 641 void ResetCounters(void); 642 643 static uint8_t ConvertLogLevel(otLogLevel aLogLevel); 644 static unsigned int ConvertLogRegion(otLogRegion aLogRegion); 645 646 #if OPENTHREAD_CONFIG_DIAG_ENABLE 647 static void HandleDiagOutput_Jump(const char *aFormat, va_list aArguments, void *aContext); 648 void HandleDiagOutput(const char *aFormat, va_list aArguments); 649 #endif 650 651 #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK 652 /** 653 * Defines a vendor "command handler" hook to process vendor-specific spinel commands. 654 * 655 * @param[in] aHeader The spinel frame header. 656 * @param[in] aCommand The spinel command key. 657 * 658 * @retval OT_ERROR_NONE The response is prepared. 659 * @retval OT_ERROR_NO_BUFS Out of buffer while preparing the response. 660 */ 661 otError VendorCommandHandler(uint8_t aHeader, unsigned int aCommand); 662 663 /** 664 * Is a callback which mirrors `NcpBase::HandleFrameRemovedFromNcpBuffer()`. It is called when a 665 * spinel frame is sent and removed from NCP buffer. 666 * 667 * (a) This can be used to track and verify that a vendor spinel frame response is delivered to the host (tracking 668 * the frame using its tag). 669 * 670 * (b) It indicates that NCP buffer space is now available (since a spinel frame is removed). This can be used to 671 * implement mechanisms to re-send a failed/pending response or an async spinel frame. 672 * 673 * @param[in] aFrameTag The tag of the frame removed from NCP buffer. 674 */ 675 void VendorHandleFrameRemovedFromNcpBuffer(Spinel::Buffer::FrameTag aFrameTag); 676 677 /** 678 * Defines a vendor "get property handler" hook to process vendor spinel properties. 679 * 680 * The vendor handler should return `OT_ERROR_NOT_FOUND` status if it does not support "get" operation for the 681 * given property key. Otherwise, the vendor handler should behave like other property get handlers, i.e., it 682 * should retrieve the property value and then encode and write the value into the NCP buffer. If the "get" 683 * operation itself fails, handler should write a `LAST_STATUS` with the error status into the NCP buffer. 684 * 685 * @param[in] aPropKey The spinel property key. 686 * 687 * @retval OT_ERROR_NONE Successfully retrieved the property value and prepared the response. 688 * @retval OT_ERROR_NOT_FOUND Does not support the given property key. 689 * @retval OT_ERROR_NO_BUFS Out of buffer while preparing the response. 690 */ 691 otError VendorGetPropertyHandler(spinel_prop_key_t aPropKey); 692 693 /** 694 * Defines a vendor "set property handler" hook to process vendor spinel properties. 695 * 696 * The vendor handler should return `OT_ERROR_NOT_FOUND` status if it does not support "set" operation for the 697 * given property key. Otherwise, the vendor handler should behave like other property set handlers, i.e., it 698 * should first decode the value from the input spinel frame and then perform the corresponding set operation. The 699 * handler should not prepare the spinel response and therefore should not write anything to the NCP buffer. The 700 * `otError` returned from handler (other than `OT_ERROR_NOT_FOUND`) indicates the error in either parsing of the 701 * input or the error of the set operation. In case of a successful "set", `NcpBase` set command handler will call 702 * the `VendorGetPropertyHandler()` for the same property key to prepare the response. 703 * 704 * @param[in] aPropKey The spinel property key. 705 * 706 * @returns OT_ERROR_NOT_FOUND if it does not support the given property key, otherwise the error in either parsing 707 * of the input or the "set" operation. 708 */ 709 otError VendorSetPropertyHandler(spinel_prop_key_t aPropKey); 710 711 #endif // OPENTHREAD_ENABLE_NCP_VENDOR_HOOK 712 713 static void ThreadDetachGracefullyHandler(void *aContext); 714 715 void ThreadDetachGracefullyHandler(void); 716 717 static void DatasetSendMgmtPendingSetHandler(otError aResult, void *aContext); 718 719 void DatasetSendMgmtPendingSetHandler(otError aResult); 720 721 protected: 722 static NcpBase *sNcpInstance; 723 static spinel_status_t ThreadErrorToSpinelStatus(otError aError); 724 static uint8_t LinkFlagsToFlagByte(bool aRxOnWhenIdle, bool aDeviceType, bool aNetworkData); 725 726 enum 727 { 728 kTxBufferSize = OPENTHREAD_CONFIG_NCP_TX_BUFFER_SIZE, // Tx Buffer size (used by mTxFrameBuffer). 729 kResponseQueueSize = OPENTHREAD_CONFIG_NCP_SPINEL_RESPONSE_QUEUE_SIZE, 730 kInvalidScanChannel = -1, // Invalid scan channel. 731 }; 732 733 Instance *mInstance; 734 #if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE && OPENTHREAD_RADIO 735 Instance *mInstances[kSpinelInterfaceCount]; 736 #endif 737 Spinel::Buffer mTxFrameBuffer; 738 Spinel::Encoder mEncoder; 739 Spinel::Decoder mDecoder; 740 bool mHostPowerStateInProgress; 741 742 spinel_status_t mLastStatus; 743 uint32_t mScanChannelMask; 744 uint16_t mScanPeriod; 745 bool mDiscoveryScanJoinerFlag; 746 bool mDiscoveryScanEnableFiltering; 747 uint16_t mDiscoveryScanPanId; 748 749 Tasklet mUpdateChangedPropsTask; 750 uint32_t mThreadChangedFlags; 751 ChangedPropsSet mChangedPropsSet; 752 753 spinel_host_power_state_t mHostPowerState; 754 Spinel::Buffer::FrameTag mHostPowerReplyFrameTag; 755 uint8_t mHostPowerStateHeader; 756 757 #if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE 758 otNcpDelegateAllowPeekPoke mAllowPeekDelegate; 759 otNcpDelegateAllowPeekPoke mAllowPokeDelegate; 760 #endif 761 762 uint8_t mTxBuffer[kTxBufferSize]; 763 764 spinel_tid_t mNextExpectedTid[kSpinelInterfaceCount]; 765 766 uint8_t mResponseQueueHead; 767 uint8_t mResponseQueueTail; 768 ResponseEntry mResponseQueue[kResponseQueueSize]; 769 770 bool mAllowLocalNetworkDataChange; 771 bool mRequireJoinExistingNetwork; 772 bool mIsRawStreamEnabled[kSpinelInterfaceCount]; 773 bool mPcapEnabled; 774 bool mDisableStreamWrite; 775 bool mShouldEmitChildTableUpdate; 776 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 777 bool mAllowLocalServerDataChange; 778 #endif 779 780 #if OPENTHREAD_FTD 781 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE 782 otExtAddress mSteeringDataAddress; 783 #endif 784 uint8_t mPreferredRouteId; 785 #endif 786 uint8_t mCurCommandIid; 787 788 #if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE 789 uint8_t mCurTransmitTID[kSpinelInterfaceCount]; 790 int8_t mCurScanChannel[kSpinelInterfaceCount]; 791 bool mSrcMatchEnabled[kSpinelInterfaceCount]; 792 #endif // OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE 793 794 #if OPENTHREAD_MTD || OPENTHREAD_FTD 795 otMessageQueue mMessageQueue; 796 797 uint32_t mInboundSecureIpFrameCounter; // Number of secure inbound data/IP frames. 798 uint32_t mInboundInsecureIpFrameCounter; // Number of insecure inbound data/IP frames. 799 uint32_t mOutboundSecureIpFrameCounter; // Number of secure outbound data/IP frames. 800 uint32_t mOutboundInsecureIpFrameCounter; // Number of insecure outbound data/IP frames. 801 uint32_t mDroppedOutboundIpFrameCounter; // Number of dropped outbound data/IP frames. 802 uint32_t mDroppedInboundIpFrameCounter; // Number of dropped inbound data/IP frames. 803 804 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 805 enum : uint8_t 806 { 807 kSrpClientMaxHostAddresses = OPENTHREAD_CONFIG_SRP_CLIENT_BUFFERS_MAX_HOST_ADDRESSES, 808 }; 809 810 otError EncodeSrpClientHostInfo(const otSrpClientHostInfo &aHostInfo); 811 otError EncodeSrpClientServices(const otSrpClientService *aServices); 812 813 static void HandleSrpClientCallback(otError aError, 814 const otSrpClientHostInfo *aHostInfo, 815 const otSrpClientService *aServices, 816 const otSrpClientService *aRemovedServices, 817 void *aContext); 818 void HandleSrpClientCallback(otError aError, 819 const otSrpClientHostInfo *aHostInfo, 820 const otSrpClientService *aServices, 821 const otSrpClientService *aRemovedServices); 822 823 bool mSrpClientCallbackEnabled; 824 #endif // OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 825 826 #endif // OPENTHREAD_MTD || OPENTHREAD_FTD 827 828 uint32_t mFramingErrorCounter; // Number of improperly formed received spinel frames. 829 uint32_t mRxSpinelFrameCounter; // Number of received (inbound) spinel frames. 830 uint32_t mRxSpinelOutOfOrderTidCounter; // Number of out of order received spinel frames (tid increase > 1). 831 uint32_t mTxSpinelFrameCounter; // Number of sent (outbound) spinel frames. 832 833 bool mDidInitialUpdates; 834 835 spinel_status_t mDatasetSendMgmtPendingSetResult; 836 837 uint64_t mLogTimestampBase; // Timestamp base used for logging 838 839 #if OPENTHREAD_FTD 840 #if OPENTHREAD_CONFIG_NCP_INFRA_IF_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE 841 otError InfraIfAddAddress(const otIp6Address &aAddress); 842 bool InfraIfContainsAddress(const otIp6Address &aAddress); 843 844 static constexpr uint8_t kMaxInfraIfAddrs = 10; 845 otIp6Address mInfraIfAddrs[kMaxInfraIfAddrs]; 846 uint8_t mInfraIfAddrCount; 847 uint32_t mInfraIfIndex; 848 #endif 849 850 #if OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE 851 852 template <typename DnssdObjType> DnssdUpdate(const DnssdObjType * aObj,otPlatDnssdRequestId aRequestId,otPlatDnssdRegisterCallback aCallback,bool aRegister)853 void DnssdUpdate(const DnssdObjType *aObj, 854 otPlatDnssdRequestId aRequestId, 855 otPlatDnssdRegisterCallback aCallback, 856 bool aRegister) 857 { 858 otError error = OT_ERROR_NONE; 859 uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_TX_NOTIFICATION_IID; 860 spinel_command_t cmd = aRegister ? SPINEL_CMD_PROP_VALUE_INSERTED : SPINEL_CMD_PROP_VALUE_REMOVED; 861 862 VerifyOrExit(aObj != nullptr, error = OT_ERROR_INVALID_ARGS); 863 VerifyOrExit(mDnssdState == OT_PLAT_DNSSD_READY, error = OT_ERROR_INVALID_STATE); 864 865 SuccessOrExit(error = mEncoder.BeginFrame(header, cmd)); 866 SuccessOrExit(error = Spinel::EncodeDnssd(mEncoder, *aObj, aRequestId, aCallback)); 867 SuccessOrExit(error = mEncoder.EndFrame()); 868 869 exit: 870 if (error != OT_ERROR_NONE) 871 { 872 aCallback(mInstance, aRequestId, error); 873 } 874 } 875 876 otPlatDnssdState mDnssdState; 877 #endif // OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE 878 #endif // OPENTHREAD_FTD 879 880 #if OPENTHREAD_CONFIG_DIAG_ENABLE 881 char *mDiagOutput; 882 uint16_t mDiagOutputLen; 883 #endif 884 }; 885 886 } // namespace Ncp 887 } // namespace ot 888 889 #endif // NCP_BASE_HPP_ 890