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