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 57 #include "changed_props_set.hpp" 58 #include "common/instance.hpp" 59 #include "common/tasklet.hpp" 60 #include "lib/spinel/spinel.h" 61 #include "lib/spinel/spinel_buffer.hpp" 62 #include "lib/spinel/spinel_decoder.hpp" 63 #include "lib/spinel/spinel_encoder.hpp" 64 65 namespace ot { 66 namespace Ncp { 67 68 class NcpBase 69 { 70 public: 71 enum 72 { 73 kSpinelCmdHeaderSize = 2, ///< Size of spinel command header (in bytes). 74 kSpinelPropIdSize = 3, ///< Size of spinel property identifier (in bytes). 75 }; 76 77 /** 78 * Creates and initializes an NcpBase instance. 79 * 80 * @param[in] aInstance The OpenThread instance structure. 81 * 82 */ 83 explicit NcpBase(Instance *aInstance); 84 85 /** 86 * Returns the pointer to the single NCP instance. 87 * 88 * @returns Pointer to the single NCP instance. 89 * 90 */ 91 static NcpBase *GetNcpInstance(void); 92 93 /** 94 * Sends data to host via specific stream. 95 * 96 * 97 * @param[in] aStreamId A numeric identifier for the stream to write to. 98 * If set to '0', will default to the debug stream. 99 * @param[in] aDataPtr A pointer to the data to send on the stream. 100 * If aDataLen is non-zero, this param MUST NOT be nullptr. 101 * @param[in] aDataLen The number of bytes of data from aDataPtr to send. 102 * 103 * @retval OT_ERROR_NONE The data was queued for delivery to the host. 104 * @retval OT_ERROR_BUSY There are not enough resources to complete this 105 * request. This is usually a temporary condition. 106 * @retval OT_ERROR_INVALID_ARGS The given aStreamId was invalid. 107 * 108 */ 109 otError StreamWrite(int aStreamId, const uint8_t *aDataPtr, int aDataLen); 110 111 /** 112 * Send an OpenThread log message to host via `SPINEL_PROP_STREAM_LOG` property. 113 * 114 * @param[in] aLogLevel The log level 115 * @param[in] aLogRegion The log region 116 * @param[in] aLogString The log string 117 * 118 */ 119 void Log(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aLogString); 120 121 #if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE 122 /** 123 * Registers peek/poke delegate functions with NCP module. 124 * 125 * @param[in] aAllowPeekDelegate Delegate function pointer for peek operation. 126 * @param[in] aAllowPokeDelegate Delegate function pointer for poke operation. 127 * 128 */ 129 void RegisterPeekPokeDelegates(otNcpDelegateAllowPeekPoke aAllowPeekDelegate, 130 otNcpDelegateAllowPeekPoke aAllowPokeDelegate); 131 #endif 132 133 /** 134 * Is called by the framer whenever a framing error is detected. 135 */ 136 void IncrementFrameErrorCounter(void); 137 138 /** 139 * Called by the subclass to indicate when a frame has been received. 140 */ 141 void HandleReceive(const uint8_t *aBuf, uint16_t aBufLength); 142 143 /** 144 * Called by the subclass to learn when the host wake operation must be issued. 145 */ 146 bool ShouldWakeHost(void); 147 148 /** 149 * Called by the subclass to learn when the transfer to the host should be deferred. 150 */ 151 bool ShouldDeferHostSend(void); 152 153 protected: 154 typedef otError (NcpBase::*PropertyHandler)(void); 155 156 /** 157 * Represents the `ResponseEntry` type. 158 * 159 */ 160 enum ResponseType 161 { 162 kResponseTypeGet = 0, ///< Response entry is for a `VALUE_GET` command. 163 kResponseTypeSet, ///< Response entry is for a `VALUE_SET` command. 164 kResponseTypeLastStatus, ///< Response entry is a `VALUE_IS(LAST_STATUS)`. 165 }; 166 167 /** 168 * Represents a spinel response entry. 169 * 170 */ 171 struct ResponseEntry 172 { 173 uint8_t mTid : 4; ///< Spinel transaction id. 174 bool mIsInUse : 1; ///< `true` if this entry is in use, `false` otherwise. 175 ResponseType mType : 2; ///< Response type. 176 uint32_t mPropKeyOrStatus : 24; ///< 3 bytes for either property key or spinel status. 177 }; 178 179 struct HandlerEntry 180 { 181 spinel_prop_key_t mKey; 182 NcpBase::PropertyHandler mHandler; 183 }; 184 185 Spinel::Buffer::FrameTag GetLastOutboundFrameTag(void); 186 187 otError HandleCommand(uint8_t aHeader); 188 189 #if __cplusplus >= 201103L 190 static constexpr bool AreHandlerEntriesSorted(const HandlerEntry *aHandlerEntries, size_t aSize); 191 #endif 192 193 static PropertyHandler FindPropertyHandler(const HandlerEntry *aHandlerEntries, 194 size_t aSize, 195 spinel_prop_key_t aKey); 196 static PropertyHandler FindGetPropertyHandler(spinel_prop_key_t aKey); 197 static PropertyHandler FindSetPropertyHandler(spinel_prop_key_t aKey); 198 static PropertyHandler FindInsertPropertyHandler(spinel_prop_key_t aKey); 199 static PropertyHandler FindRemovePropertyHandler(spinel_prop_key_t aKey); 200 201 bool HandlePropertySetForSpecialProperties(uint8_t aHeader, spinel_prop_key_t aKey, otError &aError); 202 otError HandleCommandPropertySet(uint8_t aHeader, spinel_prop_key_t aKey); 203 otError HandleCommandPropertyInsertRemove(uint8_t aHeader, spinel_prop_key_t aKey, unsigned int aCommand); 204 205 otError WriteLastStatusFrame(uint8_t aHeader, spinel_status_t aLastStatus); 206 otError WritePropertyValueIsFrame(uint8_t aHeader, spinel_prop_key_t aPropKey, bool aIsGetResponse = true); 207 otError WritePropertyValueInsertedRemovedFrame(uint8_t aHeader, 208 unsigned int aResponseCommand, 209 spinel_prop_key_t aPropKey, 210 const uint8_t *aValuePtr, 211 uint16_t aValueLen); 212 213 otError SendQueuedResponses(void); IsResponseQueueEmpty(void) const214 bool IsResponseQueueEmpty(void) const { return (mResponseQueueHead == mResponseQueueTail); } 215 otError EnqueueResponse(uint8_t aHeader, ResponseType aType, unsigned int aPropKeyOrStatus); 216 PrepareGetResponse(uint8_t aHeader,spinel_prop_key_t aPropKey)217 otError PrepareGetResponse(uint8_t aHeader, spinel_prop_key_t aPropKey) 218 { 219 return EnqueueResponse(aHeader, kResponseTypeGet, aPropKey); 220 } PrepareSetResponse(uint8_t aHeader,spinel_prop_key_t aPropKey)221 otError PrepareSetResponse(uint8_t aHeader, spinel_prop_key_t aPropKey) 222 { 223 return EnqueueResponse(aHeader, kResponseTypeSet, aPropKey); 224 } PrepareLastStatusResponse(uint8_t aHeader,spinel_status_t aStatus)225 otError PrepareLastStatusResponse(uint8_t aHeader, spinel_status_t aStatus) 226 { 227 return EnqueueResponse(aHeader, kResponseTypeLastStatus, aStatus); 228 } 229 230 static uint8_t GetWrappedResponseQueueIndex(uint8_t aPosition); 231 232 static void UpdateChangedProps(Tasklet &aTasklet); 233 void UpdateChangedProps(void); 234 235 static void HandleFrameRemovedFromNcpBuffer(void *aContext, 236 Spinel::Buffer::FrameTag aFrameTag, 237 Spinel::Buffer::Priority aPriority, 238 Spinel::Buffer *aNcpBuffer); 239 void HandleFrameRemovedFromNcpBuffer(Spinel::Buffer::FrameTag aFrameTag); 240 241 otError EncodeChannelMask(uint32_t aChannelMask); 242 otError DecodeChannelMask(uint32_t &aChannelMask); 243 244 #if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE 245 otError PackRadioFrame(otRadioFrame *aFrame, otError aError); 246 247 static void LinkRawReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError); 248 void LinkRawReceiveDone(otRadioFrame *aFrame, otError aError); 249 250 static void LinkRawTransmitDone(otInstance *aInstance, 251 otRadioFrame *aFrame, 252 otRadioFrame *aAckFrame, 253 otError aError); 254 void LinkRawTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError); 255 256 static void LinkRawEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi); 257 void LinkRawEnergyScanDone(int8_t aEnergyScanMaxRssi); 258 259 #endif // OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE 260 261 #if OPENTHREAD_MTD || OPENTHREAD_FTD 262 static void HandleStateChanged(otChangedFlags aFlags, void *aContext); 263 void ProcessThreadChangedFlags(void); 264 265 static void HandlePcapFrame(const otRadioFrame *aFrame, bool aIsTx, void *aContext); 266 void HandlePcapFrame(const otRadioFrame *aFrame, bool aIsTx); 267 268 static void HandleTimeSyncUpdate(void *aContext); 269 void HandleTimeSyncUpdate(void); 270 271 #if OPENTHREAD_FTD 272 static void HandleNeighborTableChanged(otNeighborTableEvent aEvent, const otNeighborTableEntryInfo *aEntry); 273 void HandleNeighborTableChanged(otNeighborTableEvent aEvent, const otNeighborTableEntryInfo &aEntry); 274 275 #if OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE 276 static void HandleParentResponseInfo(otThreadParentResponseInfo *aInfo, void *aContext); 277 void HandleParentResponseInfo(const otThreadParentResponseInfo &aInfo); 278 #endif 279 #endif 280 281 static void HandleDatagramFromStack(otMessage *aMessage, void *aContext); 282 void HandleDatagramFromStack(otMessage *aMessage); 283 284 otError SendQueuedDatagramMessages(void); 285 otError SendDatagramMessage(otMessage *aMessage); 286 287 static void HandleActiveScanResult_Jump(otActiveScanResult *aResult, void *aContext); 288 void HandleActiveScanResult(otActiveScanResult *aResult); 289 290 static void HandleEnergyScanResult_Jump(otEnergyScanResult *aResult, void *aContext); 291 void HandleEnergyScanResult(otEnergyScanResult *aResult); 292 293 static void HandleJamStateChange_Jump(bool aJamState, void *aContext); 294 void HandleJamStateChange(bool aJamState); 295 296 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE 297 static void HandleCommissionerEnergyReport_Jump(uint32_t aChannelMask, 298 const uint8_t *aEnergyData, 299 uint8_t aLength, 300 void *aContext); 301 void HandleCommissionerEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyData, uint8_t aLength); 302 303 static void HandleCommissionerPanIdConflict_Jump(uint16_t aPanId, uint32_t aChannelMask, void *aContext); 304 void HandleCommissionerPanIdConflict(uint16_t aPanId, uint32_t aChannelMask); 305 #endif 306 307 #if OPENTHREAD_CONFIG_JOINER_ENABLE 308 static void HandleJoinerCallback_Jump(otError aError, void *aContext); 309 void HandleJoinerCallback(otError aError); 310 #endif 311 312 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 313 static void HandleLinkMetricsReport_Jump(const otIp6Address *aSource, 314 const otLinkMetricsValues *aMetricsValues, 315 otLinkMetricsStatus aStatus, 316 void *aContext); 317 318 void HandleLinkMetricsReport(const otIp6Address *aSource, 319 const otLinkMetricsValues *aMetricsValues, 320 otLinkMetricsStatus aStatus); 321 322 static void HandleLinkMetricsMgmtResponse_Jump(const otIp6Address *aSource, 323 otLinkMetricsStatus aStatus, 324 void *aContext); 325 326 void HandleLinkMetricsMgmtResponse(const otIp6Address *aSource, otLinkMetricsStatus aStatus); 327 328 static void HandleLinkMetricsEnhAckProbingIeReport_Jump(otShortAddress aShortAddress, 329 const otExtAddress *aExtAddress, 330 const otLinkMetricsValues *aMetricsValues, 331 void *aContext); 332 333 void HandleLinkMetricsEnhAckProbingIeReport(otShortAddress aShortAddress, 334 const otExtAddress *aExtAddress, 335 const otLinkMetricsValues *aMetricsValues); 336 #endif 337 338 static void HandleMlrRegResult_Jump(void *aContext, 339 otError aError, 340 uint8_t aMlrStatus, 341 const otIp6Address *aFailedAddresses, 342 uint8_t aFailedAddressNum); 343 void HandleMlrRegResult(otError aError, 344 uint8_t aMlrStatus, 345 const otIp6Address *aFailedAddresses, 346 uint8_t aFailedAddressNum); 347 348 otError EncodeOperationalDataset(const otOperationalDataset &aDataset); 349 350 otError DecodeOperationalDataset(otOperationalDataset &aDataset, 351 const uint8_t **aTlvs = nullptr, 352 uint8_t *aTlvsLength = nullptr, 353 const otIp6Address **aDestIpAddress = nullptr, 354 bool aAllowEmptyValues = false); 355 356 otError EncodeNeighborInfo(const otNeighborInfo &aNeighborInfo); 357 #if OPENTHREAD_CONFIG_MULTI_RADIO 358 otError EncodeNeighborMultiRadioInfo(uint32_t aSpinelRadioLink, const otRadioLinkInfo &aInfo); 359 #endif 360 361 #if OPENTHREAD_FTD 362 otError EncodeChildInfo(const otChildInfo &aChildInfo); 363 #endif 364 365 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 366 otError EncodeLinkMetricsValues(const otLinkMetricsValues *aMetricsValues); 367 #endif 368 369 #if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE 370 static void HandleUdpForwardStream(otMessage *aMessage, 371 uint16_t aPeerPort, 372 otIp6Address *aPeerAddr, 373 uint16_t aSockPort, 374 void *aContext); 375 void HandleUdpForwardStream(otMessage *aMessage, uint16_t aPeerPort, otIp6Address &aPeerAddr, uint16_t aPort); 376 #endif // OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE 377 #endif // OPENTHREAD_MTD || OPENTHREAD_FTD 378 379 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 380 otError DecodeLinkMetrics(otLinkMetrics *aMetrics, bool aAllowPduCount); 381 #endif 382 383 otError CommandHandler_NOOP(uint8_t aHeader); 384 otError CommandHandler_RESET(uint8_t aHeader); 385 // Combined command handler for `VALUE_GET`, `VALUE_SET`, `VALUE_INSERT` and `VALUE_REMOVE`. 386 otError CommandHandler_PROP_VALUE_update(uint8_t aHeader, unsigned int aCommand); 387 #if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE 388 otError CommandHandler_PEEK(uint8_t aHeader); 389 otError CommandHandler_POKE(uint8_t aHeader); 390 #endif 391 #if OPENTHREAD_MTD || OPENTHREAD_FTD 392 otError CommandHandler_NET_CLEAR(uint8_t aHeader); 393 #endif 394 395 // ---------------------------------------------------------------------------- 396 // Property Handlers 397 // ---------------------------------------------------------------------------- 398 // 399 // There are 4 types of property handlers for "get", "set", "insert", and 400 // "remove" commands. 401 // 402 // "Get" handlers should get/retrieve the property value and then encode and 403 // write the value into the NCP buffer. If the "get" operation itself fails, 404 // "get" handler should write a `LAST_STATUS` with the error status into the NCP 405 // buffer. The `otError` returned from a "get" handler is the error of writing 406 // into the NCP buffer (e.g., running out buffer), and not of the "get" operation 407 // itself. 408 // 409 // "Set/Insert/Remove" handlers should first decode/parse the value from the 410 // input Spinel frame and then perform the corresponding set/insert/remove 411 // operation. They are not responsible for preparing the Spinel response and 412 // therefore should not write anything to the NCP buffer. The `otError` returned 413 // from a "set/insert/remove" handler indicates the error in either parsing of 414 // the input or the error of set/insert/remove operation. 415 // 416 // The corresponding command handler (e.g., `HandleCommandPropertySet()` for 417 // `VALUE_SET` command) will take care of preparing the Spinel response after 418 // invoking the "set/insert/remove" handler for a given property. For example, 419 // for a `VALUE_SET` command, if the "set" handler returns an error, then a 420 // `LAST_STATUS` update response is prepared, otherwise on success the "get" 421 // handler for the property is used to prepare a `VALUE_IS` Spinel response (in 422 // cases where there is no "get" handler for the property, the input value is 423 // echoed in the response). 424 // 425 // Few properties require special treatment where the response needs to be 426 // prepared directly in the "set" handler (e.g., `HOST_POWER_STATE` or 427 // `NEST_STREAM_MFG`). These properties have a different handler method format 428 // (they expect `aHeader` as an input argument) and are processed separately in 429 // `HandleCommandPropertySet()`. 430 431 template <spinel_prop_key_t aKey> otError HandlePropertyGet(void); 432 template <spinel_prop_key_t aKey> otError HandlePropertySet(void); 433 template <spinel_prop_key_t aKey> otError HandlePropertyInsert(void); 434 template <spinel_prop_key_t aKey> otError HandlePropertyRemove(void); 435 436 // -------------------------------------------------------------------------- 437 // Property "set" handlers for special properties for which the spinel 438 // response needs to be created from within the set handler. 439 440 otError HandlePropertySet_SPINEL_PROP_HOST_POWER_STATE(uint8_t aHeader); 441 442 #if OPENTHREAD_CONFIG_DIAG_ENABLE 443 static_assert(OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE <= 444 OPENTHREAD_CONFIG_NCP_TX_BUFFER_SIZE - kSpinelCmdHeaderSize - kSpinelPropIdSize, 445 "diag output buffer should be smaller than NCP HDLC tx buffer"); 446 447 otError HandlePropertySet_SPINEL_PROP_NEST_STREAM_MFG(uint8_t aHeader); 448 #endif 449 450 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE 451 otError HandlePropertySet_SPINEL_PROP_MESHCOP_COMMISSIONER_GENERATE_PSKC(uint8_t aHeader); 452 otError HandlePropertySet_SPINEL_PROP_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader); 453 #endif // OPENTHREAD_FTD 454 455 #if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE 456 otError DecodeStreamRawTxRequest(otRadioFrame &aFrame); 457 otError HandlePropertySet_SPINEL_PROP_STREAM_RAW(uint8_t aHeader); 458 #endif 459 460 void ResetCounters(void); 461 462 static uint8_t ConvertLogLevel(otLogLevel aLogLevel); 463 static unsigned int ConvertLogRegion(otLogRegion aLogRegion); 464 465 #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK 466 /** 467 * Defines a vendor "command handler" hook to process vendor-specific spinel commands. 468 * 469 * @param[in] aHeader The spinel frame header. 470 * @param[in] aCommand The spinel command key. 471 * 472 * @retval OT_ERROR_NONE The response is prepared. 473 * @retval OT_ERROR_NO_BUFS Out of buffer while preparing the response. 474 * 475 */ 476 otError VendorCommandHandler(uint8_t aHeader, unsigned int aCommand); 477 478 /** 479 * Is a callback which mirrors `NcpBase::HandleFrameRemovedFromNcpBuffer()`. It is called when a 480 * spinel frame is sent and removed from NCP buffer. 481 * 482 * (a) This can be used to track and verify that a vendor spinel frame response is delivered to the host (tracking 483 * the frame using its tag). 484 * 485 * (b) It indicates that NCP buffer space is now available (since a spinel frame is removed). This can be used to 486 * implement mechanisms to re-send a failed/pending response or an async spinel frame. 487 * 488 * @param[in] aFrameTag The tag of the frame removed from NCP buffer. 489 * 490 */ 491 void VendorHandleFrameRemovedFromNcpBuffer(Spinel::Buffer::FrameTag aFrameTag); 492 493 /** 494 * Defines a vendor "get property handler" hook to process vendor spinel properties. 495 * 496 * The vendor handler should return `OT_ERROR_NOT_FOUND` status if it does not support "get" operation for the 497 * given property key. Otherwise, the vendor handler should behave like other property get handlers, i.e., it 498 * should retrieve the property value and then encode and write the value into the NCP buffer. If the "get" 499 * operation itself fails, handler should write a `LAST_STATUS` with the error status into the NCP buffer. 500 * 501 * @param[in] aPropKey The spinel property key. 502 * 503 * @retval OT_ERROR_NONE Successfully retrieved the property value and prepared the response. 504 * @retval OT_ERROR_NOT_FOUND Does not support the given property key. 505 * @retval OT_ERROR_NO_BUFS Out of buffer while preparing the response. 506 * 507 */ 508 otError VendorGetPropertyHandler(spinel_prop_key_t aPropKey); 509 510 /** 511 * Defines a vendor "set property handler" hook to process vendor spinel properties. 512 * 513 * The vendor handler should return `OT_ERROR_NOT_FOUND` status if it does not support "set" operation for the 514 * given property key. Otherwise, the vendor handler should behave like other property set handlers, i.e., it 515 * should first decode the value from the input spinel frame and then perform the corresponding set operation. The 516 * handler should not prepare the spinel response and therefore should not write anything to the NCP buffer. The 517 * `otError` returned from handler (other than `OT_ERROR_NOT_FOUND`) indicates the error in either parsing of the 518 * input or the error of the set operation. In case of a successful "set", `NcpBase` set command handler will call 519 * the `VendorGetPropertyHandler()` for the same property key to prepare the response. 520 * 521 * @param[in] aPropKey The spinel property key. 522 * 523 * @returns OT_ERROR_NOT_FOUND if it does not support the given property key, otherwise the error in either parsing 524 * of the input or the "set" operation. 525 * 526 */ 527 otError VendorSetPropertyHandler(spinel_prop_key_t aPropKey); 528 529 #endif // OPENTHREAD_ENABLE_NCP_VENDOR_HOOK 530 531 protected: 532 static NcpBase *sNcpInstance; 533 static spinel_status_t ThreadErrorToSpinelStatus(otError aError); 534 static uint8_t LinkFlagsToFlagByte(bool aRxOnWhenIdle, bool aDeviceType, bool aNetworkData); 535 Instance *mInstance; 536 Spinel::Buffer mTxFrameBuffer; 537 Spinel::Encoder mEncoder; 538 Spinel::Decoder mDecoder; 539 bool mHostPowerStateInProgress; 540 541 enum 542 { 543 kTxBufferSize = OPENTHREAD_CONFIG_NCP_TX_BUFFER_SIZE, // Tx Buffer size (used by mTxFrameBuffer). 544 kResponseQueueSize = OPENTHREAD_CONFIG_NCP_SPINEL_RESPONSE_QUEUE_SIZE, 545 kInvalidScanChannel = -1, // Invalid scan channel. 546 }; 547 548 spinel_status_t mLastStatus; 549 uint32_t mScanChannelMask; 550 uint16_t mScanPeriod; 551 bool mDiscoveryScanJoinerFlag; 552 bool mDiscoveryScanEnableFiltering; 553 uint16_t mDiscoveryScanPanId; 554 555 Tasklet mUpdateChangedPropsTask; 556 uint32_t mThreadChangedFlags; 557 ChangedPropsSet mChangedPropsSet; 558 559 spinel_host_power_state_t mHostPowerState; 560 Spinel::Buffer::FrameTag mHostPowerReplyFrameTag; 561 uint8_t mHostPowerStateHeader; 562 563 #if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE 564 otNcpDelegateAllowPeekPoke mAllowPeekDelegate; 565 otNcpDelegateAllowPeekPoke mAllowPokeDelegate; 566 #endif 567 568 uint8_t mTxBuffer[kTxBufferSize]; 569 570 spinel_tid_t mNextExpectedTid; 571 572 uint8_t mResponseQueueHead; 573 uint8_t mResponseQueueTail; 574 ResponseEntry mResponseQueue[kResponseQueueSize]; 575 576 bool mAllowLocalNetworkDataChange; 577 bool mRequireJoinExistingNetwork; 578 bool mIsRawStreamEnabled; 579 bool mPcapEnabled; 580 bool mDisableStreamWrite; 581 bool mShouldEmitChildTableUpdate; 582 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 583 bool mAllowLocalServerDataChange; 584 #endif 585 586 #if OPENTHREAD_FTD 587 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE 588 otExtAddress mSteeringDataAddress; 589 #endif 590 uint8_t mPreferredRouteId; 591 #endif 592 593 #if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE 594 uint8_t mCurTransmitTID; 595 int8_t mCurScanChannel; 596 bool mSrcMatchEnabled; 597 #endif // OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE 598 599 #if OPENTHREAD_MTD || OPENTHREAD_FTD 600 otMessageQueue mMessageQueue; 601 602 uint32_t mInboundSecureIpFrameCounter; // Number of secure inbound data/IP frames. 603 uint32_t mInboundInsecureIpFrameCounter; // Number of insecure inbound data/IP frames. 604 uint32_t mOutboundSecureIpFrameCounter; // Number of secure outbound data/IP frames. 605 uint32_t mOutboundInsecureIpFrameCounter; // Number of insecure outbound data/IP frames. 606 uint32_t mDroppedOutboundIpFrameCounter; // Number of dropped outbound data/IP frames. 607 uint32_t mDroppedInboundIpFrameCounter; // Number of dropped inbound data/IP frames. 608 609 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 610 enum : uint8_t 611 { 612 kSrpClientMaxHostAddresses = OPENTHREAD_CONFIG_SRP_CLIENT_BUFFERS_MAX_HOST_ADDRESSES, 613 }; 614 615 otError EncodeSrpClientHostInfo(const otSrpClientHostInfo &aHostInfo); 616 otError EncodeSrpClientServices(const otSrpClientService *aServices); 617 618 static void HandleSrpClientCallback(otError aError, 619 const otSrpClientHostInfo *aHostInfo, 620 const otSrpClientService *aServices, 621 const otSrpClientService *aRemovedServices, 622 void *aContext); 623 void HandleSrpClientCallback(otError aError, 624 const otSrpClientHostInfo *aHostInfo, 625 const otSrpClientService *aServices, 626 const otSrpClientService *aRemovedServices); 627 628 bool mSrpClientCallbackEnabled; 629 #endif // OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 630 631 #endif // OPENTHREAD_MTD || OPENTHREAD_FTD 632 633 uint32_t mFramingErrorCounter; // Number of improperly formed received spinel frames. 634 uint32_t mRxSpinelFrameCounter; // Number of received (inbound) spinel frames. 635 uint32_t mRxSpinelOutOfOrderTidCounter; // Number of out of order received spinel frames (tid increase > 1). 636 uint32_t mTxSpinelFrameCounter; // Number of sent (outbound) spinel frames. 637 638 bool mDidInitialUpdates; 639 640 uint64_t mLogTimestampBase; // Timestamp base used for logging 641 }; 642 643 } // namespace Ncp 644 } // namespace ot 645 646 #endif // NCP_BASE_HPP_ 647