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