1 /*
2  *    Copyright (c) 2016-2017, 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 implements raw link required Spinel interface to the OpenThread stack.
31  */
32 
33 #include "ncp_base.hpp"
34 
35 #include <openthread/link.h>
36 #include <openthread/link_raw.h>
37 #include <openthread/ncp.h>
38 #include <openthread/platform/misc.h>
39 #include <openthread/platform/multipan.h>
40 #include <openthread/platform/radio.h>
41 #include <openthread/platform/time.h>
42 
43 #include "common/code_utils.hpp"
44 #include "common/debug.hpp"
45 #include "instance/instance.hpp"
46 #include "mac/mac_frame.hpp"
47 
48 #if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE
49 
50 namespace ot {
51 namespace Ncp {
52 
53 #if OPENTHREAD_RADIO
HandlePropertyGet(void)54 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_RCP_API_VERSION>(void)
55 {
56     return mEncoder.WriteUintPacked(SPINEL_RCP_API_VERSION);
57 }
58 
HandlePropertyGet(void)59 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_RCP_MIN_HOST_API_VERSION>(void)
60 {
61     return mEncoder.WriteUintPacked(SPINEL_MIN_HOST_SUPPORTED_RCP_API_VERSION);
62 }
63 #endif
64 
65 // ----------------------------------------------------------------------------
66 // MARK: Raw Link-Layer Datapath Glue
67 // ----------------------------------------------------------------------------
68 
PackRadioFrame(otRadioFrame * aFrame,otError aError)69 otError NcpBase::PackRadioFrame(otRadioFrame *aFrame, otError aError)
70 {
71     otError  error = OT_ERROR_FAILED;
72     uint16_t flags = 0;
73 
74     if (aFrame != nullptr && aError == OT_ERROR_NONE)
75     {
76         // Append the frame contents
77         SuccessOrExit(mEncoder.WriteDataWithLen(aFrame->mPsdu, aFrame->mLength));
78     }
79     else
80     {
81         // Append length
82         SuccessOrExit(mEncoder.WriteUint16(0));
83     }
84 
85     // Append metadata (rssi, etc)
86     SuccessOrExit(mEncoder.WriteInt8(aFrame ? aFrame->mInfo.mRxInfo.mRssi : 0)); // RSSI
87     SuccessOrExit(mEncoder.WriteInt8(-128));                                     // Noise Floor (Currently unused)
88 
89     if (aFrame != nullptr)
90     {
91         if (aFrame->mInfo.mRxInfo.mAckedWithFramePending)
92         {
93             flags |= SPINEL_MD_FLAG_ACKED_FP;
94         }
95 
96         if (aFrame->mInfo.mRxInfo.mAckedWithSecEnhAck)
97         {
98             flags |= SPINEL_MD_FLAG_ACKED_SEC;
99         }
100     }
101 
102     SuccessOrExit(mEncoder.WriteUint16(flags)); // Flags
103 
104     SuccessOrExit(mEncoder.OpenStruct());                              // PHY-data
105     SuccessOrExit(mEncoder.WriteUint8(aFrame ? aFrame->mChannel : 0)); // 802.15.4 channel (Receive channel)
106     SuccessOrExit(mEncoder.WriteUint8(aFrame ? aFrame->mInfo.mRxInfo.mLqi
107                                              : static_cast<uint8_t>(OT_RADIO_LQI_NONE))); // 802.15.4 LQI
108 
109     SuccessOrExit(mEncoder.WriteUint64(aFrame ? aFrame->mInfo.mRxInfo.mTimestamp : 0)); // The timestamp in microseconds
110     SuccessOrExit(mEncoder.CloseStruct());
111 
112     SuccessOrExit(mEncoder.OpenStruct());            // Vendor-data
113     SuccessOrExit(mEncoder.WriteUintPacked(aError)); // Receive error
114     SuccessOrExit(mEncoder.CloseStruct());
115 
116     SuccessOrExit(mEncoder.OpenStruct());                                             // MAC-data
117     SuccessOrExit(mEncoder.WriteUint8(aFrame ? aFrame->mInfo.mRxInfo.mAckKeyId : 0)); // The ACK auxiliary key ID
118     SuccessOrExit(
119         mEncoder.WriteUint32(aFrame ? aFrame->mInfo.mRxInfo.mAckFrameCounter : 0)); // The ACK auxiliary frame counter
120     SuccessOrExit(mEncoder.CloseStruct());
121 
122     error = OT_ERROR_NONE;
123 
124 exit:
125     return error;
126 }
127 
128 #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
NotifySwitchoverDone(otInstance * aInstance,bool aSuccess)129 void NcpBase::NotifySwitchoverDone(otInstance *aInstance, bool aSuccess)
130 {
131     OT_UNUSED_VARIABLE(aInstance);
132     NotifySwitchoverDone(aSuccess);
133 }
134 
NotifySwitchoverDone(bool aSuccess)135 void NcpBase::NotifySwitchoverDone(bool aSuccess)
136 {
137     uint8_t         header = SPINEL_HEADER_FLAG | SPINEL_HEADER_TX_NOTIFICATION_IID;
138     spinel_status_t result = aSuccess ? SPINEL_STATUS_SWITCHOVER_DONE : SPINEL_STATUS_SWITCHOVER_FAILED;
139 
140     IgnoreError(WriteLastStatusFrame(header, result));
141 }
142 #endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
143 
LinkRawReceiveDone(otInstance * aInstance,otRadioFrame * aFrame,otError aError)144 void NcpBase::LinkRawReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
145 {
146     sNcpInstance->LinkRawReceiveDone(GetNcpBaseIid(aInstance), aFrame, aError);
147 }
148 
LinkRawReceiveDone(uint8_t aIid,otRadioFrame * aFrame,otError aError)149 void NcpBase::LinkRawReceiveDone(uint8_t aIid, otRadioFrame *aFrame, otError aError)
150 {
151     uint8_t header = SPINEL_HEADER_FLAG;
152 
153     header |= SPINEL_HEADER_IID(aIid);
154     // Append frame header
155     SuccessOrExit(mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_STREAM_RAW));
156 
157     SuccessOrExit(PackRadioFrame(aFrame, aError));
158     SuccessOrExit(mEncoder.EndFrame());
159 
160 exit:
161     return;
162 }
163 
LinkRawTransmitDone(otInstance * aInstance,otRadioFrame * aFrame,otRadioFrame * aAckFrame,otError aError)164 void NcpBase::LinkRawTransmitDone(otInstance *aInstance, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
165 {
166     sNcpInstance->LinkRawTransmitDone(GetNcpBaseIid(aInstance), aFrame, aAckFrame, aError);
167 }
168 
LinkRawTransmitDone(uint8_t aIid,otRadioFrame * aFrame,otRadioFrame * aAckFrame,otError aError)169 void NcpBase::LinkRawTransmitDone(uint8_t aIid, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
170 {
171     OT_UNUSED_VARIABLE(aFrame);
172     OT_ASSERT(aIid < kSpinelInterfaceCount);
173 
174     if (mCurTransmitTID[aIid])
175     {
176         uint8_t header        = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID(aIid) | mCurTransmitTID[aIid];
177         bool    framePending  = (aAckFrame != nullptr && static_cast<Mac::RxFrame *>(aAckFrame)->GetFramePending());
178         bool    headerUpdated = static_cast<Mac::TxFrame *>(aFrame)->IsHeaderUpdated();
179 
180         // Clear cached transmit TID
181         mCurTransmitTID[aIid] = 0;
182 
183         SuccessOrExit(mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_LAST_STATUS));
184         SuccessOrExit(mEncoder.WriteUintPacked(ThreadErrorToSpinelStatus(aError)));
185         SuccessOrExit(mEncoder.WriteBool(framePending));
186         SuccessOrExit(mEncoder.WriteBool(headerUpdated));
187 
188         if (aError == OT_ERROR_NONE)
189         {
190             SuccessOrExit(PackRadioFrame(aAckFrame, aError));
191         }
192 
193         if (static_cast<Mac::TxFrame *>(aFrame)->GetSecurityEnabled() && headerUpdated)
194         {
195             uint8_t  keyId;
196             uint32_t frameCounter;
197 
198             // Transmit frame auxiliary key index and frame counter
199             SuccessOrExit(static_cast<Mac::TxFrame *>(aFrame)->GetKeyId(keyId));
200             SuccessOrExit(static_cast<Mac::TxFrame *>(aFrame)->GetFrameCounter(frameCounter));
201 
202             SuccessOrExit(mEncoder.WriteUint8(keyId));
203             SuccessOrExit(mEncoder.WriteUint32(frameCounter));
204         }
205 
206         SuccessOrExit(mEncoder.EndFrame());
207     }
208 
209 exit:
210     return;
211 }
212 
LinkRawEnergyScanDone(otInstance * aInstance,int8_t aEnergyScanMaxRssi)213 void NcpBase::LinkRawEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi)
214 {
215     sNcpInstance->LinkRawEnergyScanDone(GetNcpBaseIid(aInstance), aEnergyScanMaxRssi);
216 }
217 
LinkRawEnergyScanDone(uint8_t aIid,int8_t aEnergyScanMaxRssi)218 void NcpBase::LinkRawEnergyScanDone(uint8_t aIid, int8_t aEnergyScanMaxRssi)
219 {
220     OT_ASSERT(aIid < kSpinelInterfaceCount);
221     int8_t scanChannel = mCurScanChannel[aIid];
222 
223     // Clear current scan channel
224     mCurScanChannel[aIid] = kInvalidScanChannel;
225 
226     // Make sure we are back listening on the original receive channel,
227     // since the energy scan could have been on a different channel.
228     IgnoreError(otLinkRawReceive(IidToInstance(aIid)));
229 
230     SuccessOrExit(mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID(aIid), SPINEL_CMD_PROP_VALUE_IS,
231                                       SPINEL_PROP_MAC_ENERGY_SCAN_RESULT));
232 
233     SuccessOrExit(mEncoder.WriteUint8(static_cast<uint8_t>(scanChannel)));
234     SuccessOrExit(mEncoder.WriteInt8(aEnergyScanMaxRssi));
235     SuccessOrExit(mEncoder.EndFrame());
236 
237     // We are finished with the scan, so send out
238     // a property update indicating such.
239     SuccessOrExit(mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID(aIid), SPINEL_CMD_PROP_VALUE_IS,
240                                       SPINEL_PROP_MAC_SCAN_STATE));
241 
242     SuccessOrExit(mEncoder.WriteUint8(SPINEL_SCAN_STATE_IDLE));
243     SuccessOrExit(mEncoder.EndFrame());
244 
245 exit:
246     return;
247 }
248 
HandlePropertyGet(void)249 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_RADIO_CAPS>(void)
250 {
251     return mEncoder.WriteUintPacked(otLinkRawGetCaps(mInstance));
252 }
253 
HandlePropertyGet(void)254 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_SRC_MATCH_ENABLED>(void)
255 {
256     // TODO: Would be good to add an `otLinkRaw` API to give the status of source match.
257     return mEncoder.WriteBool(mSrcMatchEnabled[mCurCommandIid]);
258 }
259 
HandlePropertyGet(void)260 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_RCP_TIMESTAMP>(void)
261 {
262     otError error = OT_ERROR_NONE;
263 
264     SuccessOrExit(error = mEncoder.WriteUint64(otLinkRawGetRadioTime(mInstance)));
265 
266 exit:
267     return error;
268 }
269 
HandlePropertySet(void)270 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_SRC_MATCH_ENABLED>(void)
271 {
272     otError error = OT_ERROR_NONE;
273 
274     SuccessOrExit(error = mDecoder.ReadBool(mSrcMatchEnabled[mCurCommandIid]));
275 
276     error = otLinkRawSrcMatchEnable(mInstance, mSrcMatchEnabled[mCurCommandIid]);
277 
278 exit:
279     return error;
280 }
281 
HandlePropertySet(void)282 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES>(void)
283 {
284     otError error = OT_ERROR_NONE;
285 
286     // Clear the list first
287     SuccessOrExit(error = otLinkRawSrcMatchClearShortEntries(mInstance));
288 
289     // Loop through the addresses and add them
290     while (mDecoder.GetRemainingLengthInStruct() >= sizeof(uint16_t))
291     {
292         uint16_t shortAddress;
293 
294         SuccessOrExit(error = mDecoder.ReadUint16(shortAddress));
295 
296         SuccessOrExit(error = otLinkRawSrcMatchAddShortEntry(mInstance, shortAddress));
297     }
298 
299 exit:
300     return error;
301 }
302 
HandlePropertySet(void)303 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES>(void)
304 {
305     otError error = OT_ERROR_NONE;
306 
307     // Clear the list first
308     SuccessOrExit(error = otLinkRawSrcMatchClearExtEntries(mInstance));
309 
310     // Loop through the addresses and add them
311     while (mDecoder.GetRemainingLengthInStruct() >= sizeof(otExtAddress))
312     {
313         const otExtAddress *extAddress;
314 
315         SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
316 
317         SuccessOrExit(error = otLinkRawSrcMatchAddExtEntry(mInstance, extAddress));
318     }
319 
320 exit:
321     return error;
322 }
323 
HandlePropertyRemove(void)324 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES>(void)
325 {
326     otError  error = OT_ERROR_NONE;
327     uint16_t shortAddress;
328 
329     SuccessOrExit(error = mDecoder.ReadUint16(shortAddress));
330 
331     error = otLinkRawSrcMatchClearShortEntry(mInstance, shortAddress);
332 
333 exit:
334     return error;
335 }
336 
HandlePropertyRemove(void)337 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES>(void)
338 {
339     otError             error = OT_ERROR_NONE;
340     const otExtAddress *extAddress;
341 
342     SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
343     ;
344 
345     error = otLinkRawSrcMatchClearExtEntry(mInstance, extAddress);
346 
347 exit:
348     return error;
349 }
350 
HandlePropertyInsert(void)351 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES>(void)
352 {
353     otError  error = OT_ERROR_NONE;
354     uint16_t shortAddress;
355 
356     SuccessOrExit(error = mDecoder.ReadUint16(shortAddress));
357 
358     error = otLinkRawSrcMatchAddShortEntry(mInstance, shortAddress);
359 
360 exit:
361     return error;
362 }
363 
HandlePropertyInsert(void)364 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES>(void)
365 {
366     otError             error      = OT_ERROR_NONE;
367     const otExtAddress *extAddress = nullptr;
368 
369     SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
370 
371     error = otLinkRawSrcMatchAddExtEntry(mInstance, extAddress);
372 
373 exit:
374     return error;
375 }
376 
HandlePropertySet(void)377 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_PHY_ENABLED>(void)
378 {
379     bool    value = false;
380     otError error = OT_ERROR_NONE;
381 
382     SuccessOrExit(error = mDecoder.ReadBool(value));
383 
384     if (!value)
385     {
386         error = otLinkRawSetReceiveDone(mInstance, nullptr);
387     }
388     else
389     {
390         error = otLinkRawSetReceiveDone(mInstance, &NcpBase::LinkRawReceiveDone);
391     }
392 
393 exit:
394     return error;
395 }
396 
HandlePropertySet(void)397 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_15_4_SADDR>(void)
398 {
399     uint16_t shortAddress;
400     otError  error = OT_ERROR_NONE;
401 
402     SuccessOrExit(error = mDecoder.ReadUint16(shortAddress));
403 
404     error = otLinkRawSetShortAddress(mInstance, shortAddress);
405 
406 exit:
407     return error;
408 }
409 
410 #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
HandlePropertySet(void)411 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MULTIPAN_ACTIVE_INTERFACE>(void)
412 {
413     uint8_t   interface;
414     Instance *instance;
415     bool      softSwitch;
416     otError   error = OT_ERROR_NONE;
417 
418     SuccessOrExit(error = mDecoder.ReadUint8(interface));
419     softSwitch = (interface & SPINEL_MULTIPAN_INTERFACE_SOFT_SWITCH_MASK) != 0;
420     instance   = IidToInstance(interface & SPINEL_MULTIPAN_INTERFACE_ID_MASK);
421     VerifyOrExit(instance != nullptr, error = OT_ERROR_NOT_IMPLEMENTED); // Instance out of range
422     SuccessOrExit(error = otPlatMultipanSetActiveInstance(instance, softSwitch));
423 
424 exit:
425     return error;
426 }
427 #endif /* OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE */
428 
DecodeStreamRawTxRequest(otRadioFrame & aFrame)429 otError NcpBase::DecodeStreamRawTxRequest(otRadioFrame &aFrame)
430 {
431     otError        error;
432     const uint8_t *payloadPtr;
433     uint16_t       payloadLen;
434     bool           csmaEnable;
435     bool           isARetx;
436     bool           isHeaderUpdated;
437     bool           isSecurityProcessed;
438 
439     SuccessOrExit(error = mDecoder.ReadDataWithLen(payloadPtr, payloadLen));
440     VerifyOrExit(payloadLen <= OT_RADIO_FRAME_MAX_SIZE, error = OT_ERROR_PARSE);
441 
442     aFrame.mLength = static_cast<uint8_t>(payloadLen);
443     memcpy(aFrame.mPsdu, payloadPtr, aFrame.mLength);
444 
445     // Parse the meta data
446 
447     // Channel is a required parameter in meta data.
448     SuccessOrExit(error = mDecoder.ReadUint8(aFrame.mChannel));
449 
450     // Set the default value for all optional parameters.
451     aFrame.mInfo.mTxInfo.mRxChannelAfterTxDone = aFrame.mChannel;
452     aFrame.mInfo.mTxInfo.mMaxCsmaBackoffs      = OPENTHREAD_CONFIG_MAC_MAX_CSMA_BACKOFFS_DIRECT;
453     aFrame.mInfo.mTxInfo.mMaxFrameRetries      = OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_DIRECT;
454     aFrame.mInfo.mTxInfo.mCsmaCaEnabled        = true;
455     aFrame.mInfo.mTxInfo.mIsHeaderUpdated      = false;
456     aFrame.mInfo.mTxInfo.mIsARetx              = false;
457     aFrame.mInfo.mTxInfo.mIsSecurityProcessed  = false;
458     aFrame.mInfo.mTxInfo.mTxDelay              = 0;
459     aFrame.mInfo.mTxInfo.mTxDelayBaseTime      = 0;
460 
461     // All the next parameters are optional. Note that even if the
462     // decoder fails to parse any of optional parameters we still want to
463     // return `OT_ERROR_NONE` (so `error` is not updated after this
464     // point).
465 
466     SuccessOrExit(mDecoder.ReadUint8(aFrame.mInfo.mTxInfo.mMaxCsmaBackoffs));
467     SuccessOrExit(mDecoder.ReadUint8(aFrame.mInfo.mTxInfo.mMaxFrameRetries));
468 
469     SuccessOrExit(mDecoder.ReadBool(csmaEnable));
470     aFrame.mInfo.mTxInfo.mCsmaCaEnabled = csmaEnable;
471 
472     SuccessOrExit(mDecoder.ReadBool(isHeaderUpdated));
473     aFrame.mInfo.mTxInfo.mIsHeaderUpdated = isHeaderUpdated;
474 
475     SuccessOrExit(mDecoder.ReadBool(isARetx));
476     aFrame.mInfo.mTxInfo.mIsARetx = isARetx;
477 
478     SuccessOrExit(mDecoder.ReadBool(isSecurityProcessed));
479     aFrame.mInfo.mTxInfo.mIsSecurityProcessed = isSecurityProcessed;
480 
481     SuccessOrExit(mDecoder.ReadUint32(aFrame.mInfo.mTxInfo.mTxDelay));
482     SuccessOrExit(mDecoder.ReadUint32(aFrame.mInfo.mTxInfo.mTxDelayBaseTime));
483     SuccessOrExit(mDecoder.ReadUint8(aFrame.mInfo.mTxInfo.mRxChannelAfterTxDone));
484 
485 exit:
486     return error;
487 }
488 
HandlePropertySet_SPINEL_PROP_STREAM_RAW(uint8_t aHeader)489 otError NcpBase::HandlePropertySet_SPINEL_PROP_STREAM_RAW(uint8_t aHeader)
490 {
491     otError       error = OT_ERROR_NONE;
492     uint8_t       iid   = SPINEL_HEADER_GET_IID(aHeader);
493     otRadioFrame *frame;
494 
495     OT_ASSERT(iid < kSpinelInterfaceCount);
496 
497     VerifyOrExit(otLinkRawIsEnabled(mInstance), error = OT_ERROR_INVALID_STATE);
498 
499     frame = otLinkRawGetTransmitBuffer(mInstance);
500     VerifyOrExit(frame != nullptr, error = OT_ERROR_NO_BUFS);
501 
502     SuccessOrExit(error = DecodeStreamRawTxRequest(*frame));
503 
504     // Pass frame to the radio layer. Note, this fails if we
505     // haven't enabled raw stream or are already transmitting.
506     SuccessOrExit(error = otLinkRawTransmit(mInstance, &NcpBase::LinkRawTransmitDone));
507 
508     // Cache the transaction ID for async response
509     mCurTransmitTID[iid] = SPINEL_HEADER_GET_TID(aHeader);
510 
511 exit:
512 
513     if (error == OT_ERROR_NONE)
514     {
515         // Don't do anything here yet. We will complete the transaction when we get a transmit done callback
516     }
517     else
518     {
519         error = WriteLastStatusFrame(aHeader, ThreadErrorToSpinelStatus(error));
520     }
521 
522     return error;
523 }
524 
HandlePropertySet(void)525 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_RCP_MAC_KEY>(void)
526 {
527     otError        error = OT_ERROR_NONE;
528     uint8_t        keyIdMode;
529     uint8_t        keyId;
530     uint16_t       keySize;
531     const uint8_t *prevKey;
532     const uint8_t *currKey;
533     const uint8_t *nextKey;
534 
535     SuccessOrExit(error = mDecoder.ReadUint8(keyIdMode));
536     VerifyOrExit(keyIdMode == Mac::Frame::kKeyIdMode1, error = OT_ERROR_INVALID_ARGS);
537 
538     SuccessOrExit(error = mDecoder.ReadUint8(keyId));
539 
540     SuccessOrExit(error = mDecoder.ReadDataWithLen(prevKey, keySize));
541     VerifyOrExit(keySize == sizeof(otMacKey), error = OT_ERROR_INVALID_ARGS);
542 
543     SuccessOrExit(error = mDecoder.ReadDataWithLen(currKey, keySize));
544     VerifyOrExit(keySize == sizeof(otMacKey), error = OT_ERROR_INVALID_ARGS);
545 
546     SuccessOrExit(error = mDecoder.ReadDataWithLen(nextKey, keySize));
547     VerifyOrExit(keySize == sizeof(otMacKey), error = OT_ERROR_INVALID_ARGS);
548 
549     error =
550         otLinkRawSetMacKey(mInstance, keyIdMode, keyId, reinterpret_cast<const otMacKey *>(prevKey),
551                            reinterpret_cast<const otMacKey *>(currKey), reinterpret_cast<const otMacKey *>(nextKey));
552 
553 exit:
554     return error;
555 }
556 
HandlePropertySet(void)557 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_RCP_MAC_FRAME_COUNTER>(void)
558 {
559     otError  error = OT_ERROR_NONE;
560     uint32_t frameCounter;
561     bool     setIfLarger = false;
562 
563     SuccessOrExit(error = mDecoder.ReadUint32(frameCounter));
564 
565     if (!mDecoder.IsAllReadInStruct())
566     {
567         SuccessOrExit(error = mDecoder.ReadBool(setIfLarger));
568     }
569 
570     if (setIfLarger)
571     {
572         error = otLinkRawSetMacFrameCounterIfLarger(mInstance, frameCounter);
573     }
574     else
575     {
576         error = otLinkRawSetMacFrameCounter(mInstance, frameCounter);
577     }
578 
579 exit:
580     return error;
581 }
582 
583 #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
HandlePropertyGet(void)584 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MULTIPAN_ACTIVE_INTERFACE>(void)
585 {
586     otInstance  *instance;
587     spinel_iid_t iid;
588     otError      error = OT_ERROR_NONE;
589 
590     SuccessOrExit(error = otPlatMultipanGetActiveInstance(&instance));
591     iid = InstanceToIid(static_cast<Instance *>(instance));
592     SuccessOrExit(error = mEncoder.WriteUint8(static_cast<uint8_t>(iid)));
593 
594 exit:
595     return error;
596 }
597 #endif /* OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE */
598 
599 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
HandlePropertySet(void)600 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_RCP_ENH_ACK_PROBING>(void)
601 {
602     otError             error = OT_ERROR_NONE;
603     uint16_t            shortAddress;
604     const otExtAddress *extAddress;
605     otLinkMetrics       linkMetrics = {false, false, false, false, false};
606 
607     SuccessOrExit(error = mDecoder.ReadUint16(shortAddress));
608     SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
609     SuccessOrExit(error = DecodeLinkMetrics(&linkMetrics, /* aAllowPduCount */ true));
610 
611     error = otPlatRadioConfigureEnhAckProbing(mInstance, linkMetrics, shortAddress, extAddress);
612 
613 exit:
614     return error;
615 }
616 #endif
617 
618 #if OPENTHREAD_CONFIG_PLATFORM_LOG_CRASH_DUMP_ENABLE
HandlePropertySet(void)619 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_RCP_LOG_CRASH_DUMP>(void) { return otPlatLogCrashDump(); }
620 #endif
621 
622 } // namespace Ncp
623 } // namespace ot
624 
625 #endif // OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE
626