From 87e95082329835d9dd7714e1266132346d317022 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Sat, 11 Jun 2016 12:44:40 -0700 Subject: [PATCH] Add ability to capture all received IEEE 802.15.4 frames. (#120) * Add API to register a callback for providing received IEEE 802.15.4 frames. * Add API to enable/disable promiscuous mode. --- include/openthread.h | 45 +++++++++++++++++++++++++++++++++++++++++ src/core/mac/mac.cpp | 35 +++++++++++++++++++++++++++++--- src/core/mac/mac.hpp | 30 +++++++++++++++++++++++++++ src/core/openthread.cpp | 33 +++++++++++++++++++++++++++++- 4 files changed, 139 insertions(+), 4 deletions(-) diff --git a/include/openthread.h b/include/openthread.h index b01a4fd02..9091cb479 100644 --- a/include/openthread.h +++ b/include/openthread.h @@ -39,6 +39,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -856,6 +857,50 @@ uint8_t otGetRouterIdSequence(void); */ uint8_t otGetStableNetworkDataVersion(void); +/** + * This function pointer is called when an IEEE 802.15.4 frame is received. + * + * @note This callback is called after FCS processing and @p aFrame may not contain the actual FCS that was received. + * + * @note This callback is called before IEEE 802.15.4 security processing and mSecurityValid in @p aFrame will + * always be false. + * + * @param[in] aFrame A pointer to the received IEEE 802.15.4 frame. + * + */ +typedef void (*otLinkPcapCallback)(const RadioPacket *aFrame); + +/** + * This function registers a callback to provide received raw IEEE 802.15.4 frames. + * + * @param[in] aPcapCallback A pointer to a function that is called when receiving an IEEE 802.15.4 link frame or + * NULL to disable the callback. + * + */ +void otSetLinkPcapCallback(otLinkPcapCallback aPcapCallback); + +/** + * This function indicates whether or not promiscuous mode is enabled at the link layer. + * + * @retval true Promiscuous mode is enabled. + * @retval false Promiscuous mode is not enabled. + * + */ +bool otIsLinkPromiscuous(void); + +/** + * This function enables or disables the link layer promiscuous mode. + * + * @note Promiscuous mode may only be enabled when the Thread interface is disabled. + * + * @param[in] aPromiscuous true to enable promiscuous mode, or false otherwise. + * + * @retval kThreadError_None Successfully enabled promiscuous mode. + * @retval kThreadError_Busy Could not enable promiscuous mode because the Thread interface is enabled. + * + */ +ThreadError otSetLinkPromiscuous(bool aPromiscuous); + /** * @} * diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index 695845f42..812097845 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -79,7 +79,7 @@ Mac::Mac(ThreadNetif &aThreadNetif): mState = kStateIdle; - mRxOnWhenIdle = true; + mRxOnWhenIdle = false; mCsmaAttempts = 0; mTransmitAttempts = 0; mTransmitBeacon = false; @@ -114,6 +114,8 @@ Mac::Mac(ThreadNetif &aThreadNetif): mBeaconSequence = otPlatRandomGet(); mDataSequence = otPlatRandomGet(); + mPcapCallback = NULL; + otPlatRadioEnable(); } @@ -155,7 +157,6 @@ bool Mac::IsActiveScanInProgress(void) return (mState == kStateActiveScan) || mActiveScanRequest; } - ThreadError Mac::RegisterReceiver(Receiver &aReceiver) { assert(mReceiveTail != &aReceiver && aReceiver.mNext == NULL); @@ -293,7 +294,7 @@ void Mac::NextOperation(void) break; default: - if (mRxOnWhenIdle || mReceiveTimer.IsRunning()) + if (mRxOnWhenIdle || mReceiveTimer.IsRunning() || otPlatRadioGetPromiscuous()) { otPlatRadioReceive(mChannel); } @@ -752,6 +753,13 @@ void Mac::ReceiveDoneTask(Frame *aFrame, ThreadError aError) VerifyOrExit(aError == kThreadError_None && aFrame != NULL, ;); + aFrame->mSecurityValid = false; + + if (mPcapCallback) + { + mPcapCallback(aFrame); + } + aFrame->GetSrcAddr(srcaddr); neighbor = mMle.GetNeighbor(srcaddr); @@ -868,6 +876,27 @@ exit: return error; } +void Mac::SetPcapCallback(otLinkPcapCallback aPcapCallback) +{ + mPcapCallback = aPcapCallback; +} + +bool Mac::IsPromiscuous(void) +{ + return otPlatRadioGetPromiscuous(); +} + +void Mac::SetPromiscuous(bool aPromiscuous) +{ + otPlatRadioSetPromiscuous(aPromiscuous); + + SuccessOrExit(otPlatRadioIdle()); + NextOperation(); + +exit: + return; +} + Whitelist &Mac::GetWhitelist(void) { return mWhitelist; diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index 9b2527507..99742e40b 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -391,6 +391,34 @@ public: */ bool IsActiveScanInProgress(void); + /** + * This function registers a callback to provide received raw IEEE 802.15.4 frames. + * + * @param[in] aPcapCallback A pointer to a function that is called when receiving an IEEE 802.15.4 link frame or + * NULL to disable the callback. + * + */ + void SetPcapCallback(otLinkPcapCallback aPcapCallback); + + /** + * This function indicates whether or not promiscuous mode is enabled at the link layer. + * + * @retval true Promiscuous mode is enabled. + * @retval false Promiscuous mode is not enabled. + * + */ + bool IsPromiscuous(void); + + /** + * This function enables or disables the link layer promiscuous mode. + * + * Promiscuous mode keeps the receiver enabled, overriding the value of mRxOnWhenIdle. + * + * @param[in] aPromiscuous true to enable promiscuous mode, or false otherwise. + * + */ + void SetPromiscuous(bool aPromiscuous); + private: void GenerateNonce(const ExtAddress &aAddress, uint32_t aFrameCounter, uint8_t aSecurityLevel, uint8_t *aNonce); void NextOperation(void); @@ -453,6 +481,8 @@ private: ActiveScanHandler mActiveScanHandler; void *mActiveScanContext; + otLinkPcapCallback mPcapCallback; + Whitelist mWhitelist; }; diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index 8f25f0b13..6d96a61f6 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -492,6 +492,29 @@ uint8_t otGetStableNetworkDataVersion(void) return sThreadNetif->GetMle().GetLeaderDataTlv().GetStableDataVersion(); } +void otSetLinkPcapCallback(otLinkPcapCallback aPcapCallback) +{ + sThreadNetif->GetMac().SetPcapCallback(aPcapCallback); +} + +bool otIsLinkPromiscuous(void) +{ + return sThreadNetif->GetMac().IsPromiscuous(); +} + +ThreadError otSetLinkPromiscuous(bool aPromiscuous) +{ + ThreadError error = kThreadError_None; + + // cannot enable IEEE 802.15.4 promiscuous mode if the Thread interface is enabled + VerifyOrExit(sThreadNetif->IsUp() == false, error = kThreadError_Busy); + + sThreadNetif->GetMac().SetPromiscuous(aPromiscuous); + +exit: + return error; +} + bool otIsIp6AddressEqual(const otIp6Address *a, const otIp6Address *b) { return *static_cast(a) == *static_cast(b); @@ -519,7 +542,15 @@ ThreadError otRemoveUnicastAddress(otNetifAddress *address) ThreadError otEnable(void) { - return sThreadNetif->Up(); + ThreadError error = kThreadError_None; + + // cannot enable the Thread stack if IEEE 802.15.4 promiscuous mode is enabled + VerifyOrExit(otPlatRadioGetPromiscuous() == false, error = kThreadError_Busy); + + SuccessOrExit(error = sThreadNetif->Up()); + +exit: + return error; } ThreadError otDisable(void)