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 EncodeLinkMetricsValues(const otLinkMetricsValues *aMetricsValues); 393 #endif 394 395 #if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE 396 static void HandleUdpForwardStream(otMessage * aMessage, 397 uint16_t aPeerPort, 398 otIp6Address *aPeerAddr, 399 uint16_t aSockPort, 400 void * aContext); 401 void HandleUdpForwardStream(otMessage *aMessage, uint16_t aPeerPort, otIp6Address &aPeerAddr, uint16_t aPort); 402 #endif // OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE 403 #endif // OPENTHREAD_MTD || OPENTHREAD_FTD 404 405 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 406 otError DecodeLinkMetrics(otLinkMetrics *aMetrics, bool aAllowPduCount); 407 #endif 408 409 otError CommandHandler_NOOP(uint8_t aHeader); 410 otError CommandHandler_RESET(uint8_t aHeader); 411 // Combined command handler for `VALUE_GET`, `VALUE_SET`, `VALUE_INSERT` and `VALUE_REMOVE`. 412 otError CommandHandler_PROP_VALUE_update(uint8_t aHeader, unsigned int aCommand); 413 #if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE 414 otError CommandHandler_PEEK(uint8_t aHeader); 415 otError CommandHandler_POKE(uint8_t aHeader); 416 #endif 417 #if OPENTHREAD_MTD || OPENTHREAD_FTD 418 otError CommandHandler_NET_CLEAR(uint8_t aHeader); 419 #endif 420 421 // ---------------------------------------------------------------------------- 422 // Property Handlers 423 // ---------------------------------------------------------------------------- 424 // 425 // There are 4 types of property handlers for "get", "set", "insert", and 426 // "remove" commands. 427 // 428 // "Get" handlers should get/retrieve the property value and then encode and 429 // write the value into the NCP buffer. If the "get" operation itself fails, 430 // "get" handler should write a `LAST_STATUS` with the error status into the NCP 431 // buffer. The `otError` returned from a "get" handler is the error of writing 432 // into the NCP buffer (e.g., running out buffer), and not of the "get" operation 433 // itself. 434 // 435 // "Set/Insert/Remove" handlers should first decode/parse the value from the 436 // input Spinel frame and then perform the corresponding set/insert/remove 437 // operation. They are not responsible for preparing the Spinel response and 438 // therefore should not write anything to the NCP buffer. The `otError` returned 439 // from a "set/insert/remove" handler indicates the error in either parsing of 440 // the input or the error of set/insert/remove operation. 441 // 442 // The corresponding command handler (e.g., `HandleCommandPropertySet()` for 443 // `VALUE_SET` command) will take care of preparing the Spinel response after 444 // invoking the "set/insert/remove" handler for a given property. For example, 445 // for a `VALUE_SET` command, if the "set" handler returns an error, then a 446 // `LAST_STATUS` update response is prepared, otherwise on success the "get" 447 // handler for the property is used to prepare a `VALUE_IS` Spinel response (in 448 // cases where there is no "get" handler for the property, the input value is 449 // echoed in the response). 450 // 451 // Few properties require special treatment where the response needs to be 452 // prepared directly in the "set" handler (e.g., `HOST_POWER_STATE` or 453 // `NEST_STREAM_MFG`). These properties have a different handler method format 454 // (they expect `aHeader` as an input argument) and are processed separately in 455 // `HandleCommandPropertySet()`. 456 457 template <spinel_prop_key_t aKey> otError HandlePropertyGet(void); 458 template <spinel_prop_key_t aKey> otError HandlePropertySet(void); 459 template <spinel_prop_key_t aKey> otError HandlePropertyInsert(void); 460 template <spinel_prop_key_t aKey> otError HandlePropertyRemove(void); 461 462 // -------------------------------------------------------------------------- 463 // Property "set" handlers for special properties for which the spinel 464 // response needs to be created from within the set handler. 465 466 otError HandlePropertySet_SPINEL_PROP_HOST_POWER_STATE(uint8_t aHeader); 467 468 #if OPENTHREAD_CONFIG_DIAG_ENABLE 469 static_assert(OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE <= 470 OPENTHREAD_CONFIG_NCP_TX_BUFFER_SIZE - kSpinelCmdHeaderSize - kSpinelPropIdSize, 471 "diag output buffer should be smaller than NCP HDLC tx buffer"); 472 473 otError HandlePropertySet_SPINEL_PROP_NEST_STREAM_MFG(uint8_t aHeader); 474 #endif 475 476 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE 477 otError HandlePropertySet_SPINEL_PROP_MESHCOP_COMMISSIONER_GENERATE_PSKC(uint8_t aHeader); 478 otError HandlePropertySet_SPINEL_PROP_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader); 479 #endif // OPENTHREAD_FTD 480 481 #if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE 482 otError DecodeStreamRawTxRequest(otRadioFrame &aFrame); 483 otError HandlePropertySet_SPINEL_PROP_STREAM_RAW(uint8_t aHeader); 484 #endif 485 486 void ResetCounters(void); 487 488 #if OPENTHREAD_CONFIG_LEGACY_ENABLE 489 void StartLegacy(void); 490 void StopLegacy(void); 491 #else StartLegacy(void)492 void StartLegacy(void) {} StopLegacy(void)493 void StopLegacy(void) {} 494 #endif 495 496 static uint8_t ConvertLogLevel(otLogLevel aLogLevel); 497 static unsigned int ConvertLogRegion(otLogRegion aLogRegion); 498 499 #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK 500 /** 501 * This method defines a vendor "command handler" hook to process vendor-specific spinel commands. 502 * 503 * @param[in] aHeader The spinel frame header. 504 * @param[in] aCommand The spinel command key. 505 * 506 * @retval OT_ERROR_NONE The response is prepared. 507 * @retval OT_ERROR_NO_BUFS Out of buffer while preparing the response. 508 * 509 */ 510 otError VendorCommandHandler(uint8_t aHeader, unsigned int aCommand); 511 512 /** 513 * This method is a callback which mirrors `NcpBase::HandleFrameRemovedFromNcpBuffer()`. It is called when a 514 * spinel frame is sent and removed from NCP buffer. 515 * 516 * (a) This can be used to track and verify that a vendor spinel frame response is delivered to the host (tracking 517 * the frame using its tag). 518 * 519 * (b) It indicates that NCP buffer space is now available (since a spinel frame is removed). This can be used to 520 * implement mechanisms to re-send a failed/pending response or an async spinel frame. 521 * 522 * @param[in] aFrameTag The tag of the frame removed from NCP buffer. 523 * 524 */ 525 void VendorHandleFrameRemovedFromNcpBuffer(Spinel::Buffer::FrameTag aFrameTag); 526 527 /** 528 * This method defines a vendor "get property handler" hook to process vendor spinel properties. 529 * 530 * The vendor handler should return `OT_ERROR_NOT_FOUND` status if it does not support "get" operation for the 531 * given property key. Otherwise, the vendor handler should behave like other property get handlers, i.e., it 532 * should retrieve the property value and then encode and write the value into the NCP buffer. If the "get" 533 * operation itself fails, handler should write a `LAST_STATUS` with the error status into the NCP buffer. 534 * 535 * @param[in] aPropKey The spinel property key. 536 * 537 * @retval OT_ERROR_NONE Successfully retrieved the property value and prepared the response. 538 * @retval OT_ERROR_NOT_FOUND Does not support the given property key. 539 * @retval OT_ERROR_NO_BUFS Out of buffer while preparing the response. 540 * 541 */ 542 otError VendorGetPropertyHandler(spinel_prop_key_t aPropKey); 543 544 /** 545 * This method defines a vendor "set property handler" hook to process vendor spinel properties. 546 * 547 * The vendor handler should return `OT_ERROR_NOT_FOUND` status if it does not support "set" operation for the 548 * given property key. Otherwise, the vendor handler should behave like other property set handlers, i.e., it 549 * should first decode the value from the input spinel frame and then perform the corresponding set operation. The 550 * handler should not prepare the spinel response and therefore should not write anything to the NCP buffer. The 551 * `otError` returned from handler (other than `OT_ERROR_NOT_FOUND`) indicates the error in either parsing of the 552 * input or the error of the set operation. In case of a successful "set", `NcpBase` set command handler will call 553 * the `VendorGetPropertyHandler()` for the same property key to prepare the response. 554 * 555 * @param[in] aPropKey The spinel property key. 556 * 557 * @returns OT_ERROR_NOT_FOUND if it does not support the given property key, otherwise the error in either parsing 558 * of the input or the "set" operation. 559 * 560 */ 561 otError VendorSetPropertyHandler(spinel_prop_key_t aPropKey); 562 563 #endif // OPENTHREAD_ENABLE_NCP_VENDOR_HOOK 564 565 protected: 566 static NcpBase * sNcpInstance; 567 static spinel_status_t ThreadErrorToSpinelStatus(otError aError); 568 static uint8_t LinkFlagsToFlagByte(bool aRxOnWhenIdle, bool aDeviceType, bool aNetworkData); 569 Instance * mInstance; 570 Spinel::Buffer mTxFrameBuffer; 571 Spinel::Encoder mEncoder; 572 Spinel::Decoder mDecoder; 573 bool mHostPowerStateInProgress; 574 575 enum 576 { 577 kTxBufferSize = OPENTHREAD_CONFIG_NCP_TX_BUFFER_SIZE, // Tx Buffer size (used by mTxFrameBuffer). 578 kResponseQueueSize = OPENTHREAD_CONFIG_NCP_SPINEL_RESPONSE_QUEUE_SIZE, 579 kInvalidScanChannel = -1, // Invalid scan channel. 580 }; 581 582 spinel_status_t mLastStatus; 583 uint32_t mScanChannelMask; 584 uint16_t mScanPeriod; 585 bool mDiscoveryScanJoinerFlag; 586 bool mDiscoveryScanEnableFiltering; 587 uint16_t mDiscoveryScanPanId; 588 589 Tasklet mUpdateChangedPropsTask; 590 uint32_t mThreadChangedFlags; 591 ChangedPropsSet mChangedPropsSet; 592 593 spinel_host_power_state_t mHostPowerState; 594 Spinel::Buffer::FrameTag mHostPowerReplyFrameTag; 595 uint8_t mHostPowerStateHeader; 596 597 #if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE 598 otNcpDelegateAllowPeekPoke mAllowPeekDelegate; 599 otNcpDelegateAllowPeekPoke mAllowPokeDelegate; 600 #endif 601 602 uint8_t mTxBuffer[kTxBufferSize]; 603 604 spinel_tid_t mNextExpectedTid; 605 606 uint8_t mResponseQueueHead; 607 uint8_t mResponseQueueTail; 608 ResponseEntry mResponseQueue[kResponseQueueSize]; 609 610 bool mAllowLocalNetworkDataChange; 611 bool mRequireJoinExistingNetwork; 612 bool mIsRawStreamEnabled; 613 bool mPcapEnabled; 614 bool mDisableStreamWrite; 615 bool mShouldEmitChildTableUpdate; 616 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 617 bool mAllowLocalServerDataChange; 618 #endif 619 620 #if OPENTHREAD_FTD 621 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE 622 otExtAddress mSteeringDataAddress; 623 #endif 624 uint8_t mPreferredRouteId; 625 #endif 626 627 #if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE 628 uint8_t mCurTransmitTID; 629 int8_t mCurScanChannel; 630 bool mSrcMatchEnabled; 631 #endif // OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE 632 633 #if OPENTHREAD_MTD || OPENTHREAD_FTD 634 otMessageQueue mMessageQueue; 635 636 uint32_t mInboundSecureIpFrameCounter; // Number of secure inbound data/IP frames. 637 uint32_t mInboundInsecureIpFrameCounter; // Number of insecure inbound data/IP frames. 638 uint32_t mOutboundSecureIpFrameCounter; // Number of secure outbound data/IP frames. 639 uint32_t mOutboundInsecureIpFrameCounter; // Number of insecure outbound data/IP frames. 640 uint32_t mDroppedOutboundIpFrameCounter; // Number of dropped outbound data/IP frames. 641 uint32_t mDroppedInboundIpFrameCounter; // Number of dropped inbound data/IP frames. 642 643 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 644 enum : uint8_t 645 { 646 kSrpClientMaxHostAddresses = OPENTHREAD_CONFIG_SRP_CLIENT_BUFFERS_MAX_HOST_ADDRESSES, 647 }; 648 649 otError EncodeSrpClientHostInfo(const otSrpClientHostInfo &aHostInfo); 650 otError EncodeSrpClientServices(const otSrpClientService *aServices); 651 652 static void HandleSrpClientCallback(otError aError, 653 const otSrpClientHostInfo *aHostInfo, 654 const otSrpClientService * aServices, 655 const otSrpClientService * aRemovedServices, 656 void * aContext); 657 void HandleSrpClientCallback(otError aError, 658 const otSrpClientHostInfo *aHostInfo, 659 const otSrpClientService * aServices, 660 const otSrpClientService * aRemovedServices); 661 662 bool mSrpClientCallbackEnabled; 663 #endif // OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 664 665 #if OPENTHREAD_CONFIG_LEGACY_ENABLE 666 const otNcpLegacyHandlers *mLegacyHandlers; 667 uint8_t mLegacyUlaPrefix[OT_NCP_LEGACY_ULA_PREFIX_LENGTH]; 668 otExtAddress mLegacyLastJoinedNode; 669 bool mLegacyNodeDidJoin; 670 #endif 671 #endif // OPENTHREAD_MTD || OPENTHREAD_FTD 672 673 uint32_t mFramingErrorCounter; // Number of improperly formed received spinel frames. 674 uint32_t mRxSpinelFrameCounter; // Number of received (inbound) spinel frames. 675 uint32_t mRxSpinelOutOfOrderTidCounter; // Number of out of order received spinel frames (tid increase > 1). 676 uint32_t mTxSpinelFrameCounter; // Number of sent (outbound) spinel frames. 677 678 bool mDidInitialUpdates; 679 680 uint64_t mLogTimestampBase; // Timestamp base used for logging 681 }; 682 683 } // namespace Ncp 684 } // namespace ot 685 686 #endif // NCP_BASE_HPP_ 687