diff --git a/include/platform/radio.h b/include/platform/radio.h index 32450f2fb..fccaecfcf 100644 --- a/include/platform/radio.h +++ b/include/platform/radio.h @@ -102,6 +102,7 @@ typedef struct RadioPacket int8_t mPower; ///< Transmit/receive power in dBm. uint8_t mLqi; ///< Link Quality Indicator for received frames. bool mSecurityValid; ///< Security Enabled flag is set and frame passes security checks. + uint16_t mFcs; ///< Final checksum (optional) } RadioPacket; /** diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index d7a77e682..750a0d824 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -648,6 +648,11 @@ void Mac::HandleBeginTransmit(void) otLogDebgMac("ack timer start\n"); } + if (mPcapCallback) + { + mPcapCallback(&sendFrame, mPcapCallbackContext); + } + exit: if (error != kThreadError_None) diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 7e756daed..182fe75fb 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -101,6 +101,7 @@ const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = { SPINEL_PROP_MAC_15_4_PANID, &NcpBase::GetPropertyHandler_MAC_15_4_PANID }, { SPINEL_PROP_MAC_15_4_LADDR, &NcpBase::GetPropertyHandler_MAC_15_4_LADDR }, { SPINEL_PROP_MAC_15_4_SADDR, &NcpBase::GetPropertyHandler_MAC_15_4_SADDR }, + { SPINEL_PROP_MAC_RAW_STREAM_ENABLED, &NcpBase::GetPropertyHandler_MAC_RAW_STREAM_ENABLED }, { SPINEL_PROP_MAC_FILTER_MODE, &NcpBase::GetPropertyHandler_MAC_FILTER_MODE }, { SPINEL_PROP_NET_IF_UP, &NcpBase::GetPropertyHandler_NET_IF_UP }, @@ -198,6 +199,7 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = { SPINEL_PROP_MAC_SCAN_STATE, &NcpBase::SetPropertyHandler_MAC_SCAN_STATE }, { SPINEL_PROP_MAC_SCAN_PERIOD, &NcpBase::SetPropertyHandler_MAC_SCAN_PERIOD }, { SPINEL_PROP_MAC_15_4_PANID, &NcpBase::SetPropertyHandler_MAC_15_4_PANID }, + { SPINEL_PROP_MAC_RAW_STREAM_ENABLED, &NcpBase::SetPropertyHandler_MAC_RAW_STREAM_ENABLED }, { SPINEL_PROP_NET_IF_UP, &NcpBase::SetPropertyHandler_NET_IF_UP }, { SPINEL_PROP_NET_STACK_UP, &NcpBase::SetPropertyHandler_NET_STACK_UP }, @@ -419,6 +421,7 @@ NcpBase::NcpBase(otInstance *aInstance): mChangedFlags = NCP_PLAT_RESET_REASON; mAllowLocalNetworkDataChange = false; mRequireJoinExistingNetwork = false; + mIsRawStreamEnabled = false; mFramingErrorCounter = 0; mRxSpinelFrameCounter = 0; @@ -432,11 +435,14 @@ NcpBase::NcpBase(otInstance *aInstance): otSetStateChangedCallback(mInstance, &NcpBase::HandleNetifStateChanged, this); otSetReceiveIp6DatagramCallback(mInstance, &NcpBase::HandleDatagramFromStack, this); + otSetLinkPcapCallback(mInstance, &NcpBase::HandleRawFrame, static_cast(this)); otSetIcmpEchoEnabled(mInstance, false); mUpdateChangedPropsTask.Post(); } + + // ---------------------------------------------------------------------------- // MARK: Outbound Datagram Handling // ---------------------------------------------------------------------------- @@ -501,6 +507,72 @@ exit: } } +// ---------------------------------------------------------------------------- +// MARK: Raw frame handling +// ---------------------------------------------------------------------------- + +void NcpBase::HandleRawFrame(const RadioPacket *aFrame, void *aContext) +{ + static_cast(aContext)->HandleRawFrame(aFrame); +} + +void NcpBase::HandleRawFrame(const RadioPacket *aFrame) +{ + ThreadError errorCode = kThreadError_None; + + if (!mIsRawStreamEnabled) + { + goto exit; + } + + SuccessOrExit(errorCode = OutboundFrameBegin()); + + // Append frame header and frame length + + SuccessOrExit( + errorCode = OutboundFrameFeedPacked( + "CiiS", + SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, + SPINEL_CMD_PROP_VALUE_IS, + SPINEL_PROP_STREAM_RAW, + aFrame->mLength + 2 // +2 for FCS + ) + ); + + // Append the frame contents + + SuccessOrExit( + errorCode = OutboundFrameFeedData( + aFrame->mPsdu, + aFrame->mLength + ) + ); + + // Append the FCS + SuccessOrExit( + errorCode = OutboundFrameFeedPacked( + "CC", + (aFrame->mFcs >> 0) & 0xFF, + (aFrame->mFcs >> 8) & 0xFF + ) + ); + + // Append metadata (rssi, etc) + + SuccessOrExit( + errorCode = OutboundFrameFeedPacked( + "c", + aFrame->mPower + ) + ); + + SuccessOrExit(errorCode = OutboundFrameSend()); + +exit: + return; +} + + // ---------------------------------------------------------------------------- // MARK: Scan Results Glue // ---------------------------------------------------------------------------- @@ -1573,6 +1645,17 @@ ThreadError NcpBase::GetPropertyHandler_MAC_15_4_SADDR(uint8_t header, spinel_pr ); } +ThreadError NcpBase::GetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t header, spinel_prop_key_t key) +{ + return SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_IS, + key, + SPINEL_DATATYPE_BOOL_S, + mIsRawStreamEnabled + ); +} + ThreadError NcpBase::GetPropertyHandler_NET_IF_UP(uint8_t header, spinel_prop_key_t key) { return SendPropertyUpdate( @@ -2842,6 +2925,40 @@ ThreadError NcpBase::SetPropertyHandler_MAC_15_4_PANID(uint8_t header, spinel_pr return errorCode; } +ThreadError NcpBase::SetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr,uint16_t value_len) +{ + bool value = false; + spinel_ssize_t parsedLength; + ThreadError errorCode = kThreadError_None; + + parsedLength = spinel_datatype_unpack( + value_ptr, + value_len, + SPINEL_DATATYPE_BOOL_S, + &value + ); + + if (parsedLength > 0) + { + mIsRawStreamEnabled = value; + } + else + { + errorCode = kThreadError_Parse; + } + + if (errorCode == kThreadError_None) + { + errorCode = HandleCommandPropertyGet(header, key); + } + else + { + errorCode = SendLastStatus(header, ThreadErrorToSpinelStatus(errorCode)); + } + + return errorCode; +} + ThreadError NcpBase::SetPropertyHandler_NET_IF_UP(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len) { diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index 48e0c261e..297b41b26 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -144,6 +144,13 @@ private: void HandleDatagramFromStack(Message &aMessage); + /** + * Trampoline for HandleRawFrame(). + */ + static void HandleRawFrame(const RadioPacket *aFrame, void *aContext); + + void HandleRawFrame(const RadioPacket *aFrame); + /** * Trampoline for HandleActiveScanResult(). */ @@ -284,6 +291,7 @@ private: ThreadError GetPropertyHandler_MAC_15_4_PANID(uint8_t header, spinel_prop_key_t key); ThreadError GetPropertyHandler_MAC_15_4_LADDR(uint8_t header, spinel_prop_key_t key); ThreadError GetPropertyHandler_MAC_15_4_SADDR(uint8_t header, spinel_prop_key_t key); + ThreadError GetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t header, spinel_prop_key_t key); ThreadError GetPropertyHandler_NET_IF_UP(uint8_t header, spinel_prop_key_t key); ThreadError GetPropertyHandler_NET_STACK_UP(uint8_t header, spinel_prop_key_t key); ThreadError GetPropertyHandler_NET_ROLE(uint8_t header, spinel_prop_key_t key); @@ -343,6 +351,8 @@ private: uint16_t value_len); ThreadError SetPropertyHandler_MAC_15_4_PANID(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); + ThreadError SetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, + uint16_t value_len); ThreadError SetPropertyHandler_NET_IF_UP(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); ThreadError SetPropertyHandler_NET_STACK_UP(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, @@ -447,6 +457,7 @@ private: bool mAllowLocalNetworkDataChange; bool mRequireJoinExistingNetwork; + bool mIsRawStreamEnabled; uint32_t mFramingErrorCounter; // Number of improperly formed received spinel frames. uint32_t mRxSpinelFrameCounter; // Number of received (inbound) spinel frames.