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