diff --git a/include/openthread-types.h b/include/openthread-types.h index 233f0567b..0f2f5af66 100644 --- a/include/openthread-types.h +++ b/include/openthread-types.h @@ -81,6 +81,36 @@ typedef enum ThreadError */ kThreadError_Detached = 18, + /** + * FCS check failure while receiving. + */ + kThreadError_FcsErr = 19, + + /** + * No frame received. + */ + kThreadError_NoFrameReceived = 20, + + /** + * Received a frame from an unknown neighbor. + */ + kThreadError_UnknownNeighbor = 21, + + /** + * Received a frame from an invalid source address. + */ + kThreadError_InvalidSourceAddress = 22, + + /** + * Received a frame filtered by the whitelist. + */ + kThreadError_WhitelistFiltered = 23, + + /** + * Received a frame filtered by the destination address check. + */ + kThreadError_DestinationAddressFiltered = 24, + kThreadError_Error = 255, } ThreadError; @@ -341,6 +371,38 @@ typedef enum kDeviceRoleLeader, ///< The Thread Leader role. } otDeviceRole; +/** + * This structure represents the MAC layer counters. + */ +typedef struct otMacCounters +{ + uint32_t mTxTotal; ///< The total number of transmissions. + uint32_t mTxAckRequested; ///< The number of transmissions with ack request. + uint32_t mTxAcked; ///< The number of transmissions that were acked. + uint32_t mTxNoAckRequested; ///< The number of transmissions without ack request. + uint32_t mTxData; ///< The number of transmitted data. + uint32_t mTxDataPoll; ///< The number of transmitted data poll. + uint32_t mTxBeacon; ///< The number of transmitted beacon. + uint32_t mTxBeaconRequest; ///< The number of transmitted beacon request. + uint32_t mTxOther; ///< The number of transmitted other types of frames. + uint32_t mTxRetry; ///< The number of retransmission times. + uint32_t mTxErrCca; ///< The number of CCA failure times. + uint32_t mRxTotal; ///< The total number of received packets. + uint32_t mRxData; ///< The number of received data. + uint32_t mRxDataPoll; ///< The number of received data poll. + uint32_t mRxBeacon; ///< The number of received beacon. + uint32_t mRxBeaconRequest; ///< The number of received beacon request. + uint32_t mRxOther; ///< The number of received other types of frames. + uint32_t mRxWhitelistFiltered; ///< The number of received packets filtered by whitelist. + uint32_t mRxDestAddrFiltered; ///< The number of received packets filtered by destination check. + uint32_t mRxErrNoFrame; ///< The number of received packets that do not contain contents. + uint32_t mRxErrUnknownNeighbor; ///< The number of recevied packets from unknown neighbor. + uint32_t mRxErrInvalidSrcAddr; ///< The number of received packets whose source address is invalid. + uint32_t mRxErrSec; ///< The number of recevied packets with security error. + uint32_t mRxErrFcs; ///< The number of recevied packets with FCS error. + uint32_t mRxErrOther; ///< The number of received packets with other error. +} otMacCounters; + /** * @} * diff --git a/include/openthread.h b/include/openthread.h index 9091cb479..b285e28c5 100644 --- a/include/openthread.h +++ b/include/openthread.h @@ -901,6 +901,13 @@ bool otIsLinkPromiscuous(void); */ ThreadError otSetLinkPromiscuous(bool aPromiscuous); +/** + * Get the MAC layer counters. + * + * @returns A pointer to the MAC layer counters. + */ +const otMacCounters *otGetMacCounters(void); + /** * @} * diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index e32a8180f..aa268448e 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -52,6 +52,7 @@ const struct Command Interpreter::sCommands[] = { "channel", &ProcessChannel }, { "childtimeout", &ProcessChildTimeout }, { "contextreusedelay", &ProcessContextIdReuseDelay }, + { "counter", &ProcessCounters }, { "extaddr", &ProcessExtAddress }, { "extpanid", &ProcessExtPanId }, { "ipaddr", &ProcessIpAddr }, @@ -217,6 +218,47 @@ exit: AppendResult(error); } +void Interpreter::ProcessCounters(int argc, char *argv[]) +{ + if (argc == 0) + { + sServer->OutputFormat("mac\r\n"); + sServer->OutputFormat("Done\r\n"); + } + else + { + if (strcmp(argv[0], "mac") == 0) + { + const otMacCounters *counters = otGetMacCounters(); + sServer->OutputFormat("TxTotal: %d\r\n", counters->mTxTotal); + sServer->OutputFormat(" TxAckRequested: %d\r\n", counters->mTxAckRequested); + sServer->OutputFormat(" TxAcked: %d\r\n", counters->mTxAcked); + sServer->OutputFormat(" TxNoAckRequested: %d\r\n", counters->mTxNoAckRequested); + sServer->OutputFormat(" TxData: %d\r\n", counters->mTxData); + sServer->OutputFormat(" TxDataPoll: %d\r\n", counters->mTxDataPoll); + sServer->OutputFormat(" TxBeacon: %d\r\n", counters->mTxBeacon); + sServer->OutputFormat(" TxBeaconRequest: %d\r\n", counters->mTxBeaconRequest); + sServer->OutputFormat(" TxOther: %d\r\n", counters->mTxOther); + sServer->OutputFormat(" TxRetry: %d\r\n", counters->mTxRetry); + sServer->OutputFormat(" TxErrCca: %d\r\n", counters->mTxErrCca); + sServer->OutputFormat("RxTotal: %d\r\n", counters->mRxTotal); + sServer->OutputFormat(" RxData: %d\r\n", counters->mRxData); + sServer->OutputFormat(" RxDataPoll: %d\r\n", counters->mRxDataPoll); + sServer->OutputFormat(" RxBeacon: %d\r\n", counters->mRxBeacon); + sServer->OutputFormat(" RxBeaconRequest: %d\r\n", counters->mRxBeaconRequest); + sServer->OutputFormat(" RxOther: %d\r\n", counters->mRxOther); + sServer->OutputFormat(" RxWhitelistFiltered: %d\r\n", counters->mRxWhitelistFiltered); + sServer->OutputFormat(" RxDestAddrFiltered: %d\r\n", counters->mRxDestAddrFiltered); + sServer->OutputFormat(" RxErrNoFrame: %d\r\n", counters->mRxErrNoFrame); + sServer->OutputFormat(" RxErrNoUnknownNeighbor: %d\r\n", counters->mRxErrUnknownNeighbor); + sServer->OutputFormat(" RxErrInvalidSrcAddr: %d\r\n", counters->mRxErrInvalidSrcAddr); + sServer->OutputFormat(" RxErrSec: %d\r\n", counters->mRxErrSec); + sServer->OutputFormat(" RxErrFcs: %d\r\n", counters->mRxErrFcs); + sServer->OutputFormat(" RxErrOther: %d\r\n", counters->mRxErrOther); + } + } +} + void Interpreter::ProcessExtAddress(int argc, char *argv[]) { const uint8_t *extAddress = otGetExtendedAddress(); diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index e27c806ca..113608d8a 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -89,6 +89,7 @@ private: static void ProcessChannel(int argc, char *argv[]); static void ProcessChildTimeout(int argc, char *argv[]); static void ProcessContextIdReuseDelay(int argc, char *argv[]); + static void ProcessCounters(int argc, char *argv[]); static void ProcessExtAddress(int argc, char *argv[]); static void ProcessExtPanId(int argc, char *argv[]); static void ProcessIpAddr(int argc, char *argv[]); diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index 812097845..9000ce108 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -105,6 +105,8 @@ Mac::Mac(ThreadNetif &aThreadNetif): mExtAddress.m8[i] = otPlatRandomGet(); } + memset(&mCounters, 0, sizeof(otMacCounters)); + SetExtendedPanId(sExtendedPanidInit); SetNetworkName(sNetworkNameInit); SetPanId(kPanIdBroadcast); @@ -486,11 +488,16 @@ void Mac::TransmitDoneTask(bool aRxPending, ThreadError aError) { mAckTimer.Stop(); + mCounters.mTxTotal++; + if (aError == kThreadError_ChannelAccessFailure && mCsmaAttempts < kMaxCSMABackoffs) { mCsmaAttempts++; StartCsmaBackoff(); + + mCounters.mTxErrCca++; + ExitNow(); } @@ -498,14 +505,6 @@ void Mac::TransmitDoneTask(bool aRxPending, ThreadError aError) switch (mState) { - case kStateActiveScan: - mAckTimer.Start(mScanDuration); - break; - - case kStateTransmitBeacon: - SentFrame(true); - break; - case kStateTransmitData: if (aRxPending) { @@ -516,6 +515,8 @@ void Mac::TransmitDoneTask(bool aRxPending, ThreadError aError) mReceiveTimer.Stop(); } + case kStateActiveScan: + case kStateTransmitBeacon: SentFrame(aError == kThreadError_None); break; @@ -560,6 +561,7 @@ void Mac::HandleAckTimer(void) case kStateTransmitData: otLogDebgMac("ack timer fired\n"); + mCounters.mTxTotal++; SentFrame(false); break; @@ -591,37 +593,65 @@ void Mac::SentFrame(bool aAcked) Neighbor *neighbor; Sender *sender; + if (sendFrame.GetAckRequest() && !aAcked) + { + otDumpDebgMac("NO ACK", sendFrame.GetHeader(), 16); + + if (mTransmitAttempts < kMaxFrameAttempts) + { + mTransmitAttempts++; + StartCsmaBackoff(); + + mCounters.mTxRetry++; + + ExitNow(); + } + + sendFrame.GetDstAddr(destination); + + if ((neighbor = mMle.GetNeighbor(destination)) != NULL) + { + neighbor->mState = Neighbor::kStateInvalid; + } + } + + mTransmitAttempts = 0; + + if (sendFrame.GetAckRequest()) + { + mCounters.mTxAckRequested++; + + if (aAcked) + { + mCounters.mTxAcked++; + } + } + else + { + mCounters.mTxNoAckRequested++; + } + switch (mState) { case kStateActiveScan: + mCounters.mTxBeaconRequest++; mAckTimer.Start(mScanDuration); break; case kStateTransmitBeacon: + mCounters.mTxBeacon++; ScheduleNextTransmission(); break; case kStateTransmitData: - if (sendFrame.GetAckRequest() && !aAcked) + if (mReceiveTimer.IsRunning()) { - otDumpDebgMac("NO ACK", sendFrame.GetHeader(), 16); - - if (mTransmitAttempts < kMaxFrameAttempts) - { - mTransmitAttempts++; - StartCsmaBackoff(); - ExitNow(); - } - - sendFrame.GetDstAddr(destination); - - if ((neighbor = mMle.GetNeighbor(destination)) != NULL) - { - neighbor->mState = Neighbor::kStateInvalid; - } + mCounters.mTxDataPoll++; + } + else + { + mCounters.mTxData++; } - - mTransmitAttempts = 0; sender = mSendHead; mSendHead = mSendHead->mNext; @@ -750,8 +780,12 @@ void Mac::ReceiveDoneTask(Frame *aFrame, ThreadError aError) Neighbor *neighbor; Whitelist::Entry *entry; int8_t rssi; + ThreadError error = aError; - VerifyOrExit(aError == kThreadError_None && aFrame != NULL, ;); + mCounters.mRxTotal++; + + VerifyOrExit(error == kThreadError_None, ;); + VerifyOrExit(aFrame != NULL, error = kThreadError_NoFrameReceived); aFrame->mSecurityValid = false; @@ -769,7 +803,12 @@ void Mac::ReceiveDoneTask(Frame *aFrame, ThreadError aError) break; case sizeof(ShortAddress): - VerifyOrExit(neighbor != NULL, otLogDebgMac("drop not neighbor\n")); + if (neighbor == NULL) + { + otLogDebgMac("drop not neighbor\n"); + ExitNow(error = kThreadError_UnknownNeighbor); + } + srcaddr.mLength = sizeof(srcaddr.mExtAddress); memcpy(&srcaddr.mExtAddress, &neighbor->mMacAddr, sizeof(srcaddr.mExtAddress)); break; @@ -778,13 +817,13 @@ void Mac::ReceiveDoneTask(Frame *aFrame, ThreadError aError) break; default: - ExitNow(); + ExitNow(error = kThreadError_InvalidSourceAddress); } // Source Whitelist Processing if (srcaddr.mLength != 0 && mWhitelist.IsEnabled()) { - VerifyOrExit((entry = mWhitelist.Find(srcaddr.mExtAddress)) != NULL, ;); + VerifyOrExit((entry = mWhitelist.Find(srcaddr.mExtAddress)) != NULL, error = kThreadError_WhitelistFiltered); if (mWhitelist.GetConstantRssi(*entry, rssi) == kThreadError_None) { @@ -804,26 +843,32 @@ void Mac::ReceiveDoneTask(Frame *aFrame, ThreadError aError) aFrame->GetDstPanId(panid); VerifyOrExit((panid == kShortAddrBroadcast || panid == mPanId) && ((mRxOnWhenIdle && dstaddr.mShortAddress == kShortAddrBroadcast) || - dstaddr.mShortAddress == mShortAddress), ;); + dstaddr.mShortAddress == mShortAddress), error = kThreadError_DestinationAddressFiltered); break; case sizeof(ExtAddress): aFrame->GetDstPanId(panid); VerifyOrExit(panid == mPanId && - memcmp(&dstaddr.mExtAddress, &mExtAddress, sizeof(dstaddr.mExtAddress)) == 0, ;); + memcmp(&dstaddr.mExtAddress, &mExtAddress, sizeof(dstaddr.mExtAddress)) == 0, + error = kThreadError_DestinationAddressFiltered); break; } // Security Processing - SuccessOrExit(ProcessReceiveSecurity(*aFrame, srcaddr, neighbor)); + SuccessOrExit(error = ProcessReceiveSecurity(*aFrame, srcaddr, neighbor)); switch (mState) { case kStateActiveScan: if (aFrame->GetType() == Frame::kFcfFrameBeacon) { + mCounters.mRxBeacon++; mActiveScanHandler(mActiveScanContext, aFrame); } + else + { + mCounters.mRxOther++; + } break; @@ -833,9 +878,27 @@ void Mac::ReceiveDoneTask(Frame *aFrame, ThreadError aError) mReceiveTimer.Stop(); } - if (aFrame->GetType() == Frame::kFcfFrameMacCmd) + switch (aFrame->GetType()) { - SuccessOrExit(HandleMacCommand(*aFrame)); + case Frame::kFcfFrameMacCmd: + if (HandleMacCommand(*aFrame) == kThreadError_Drop) + { + ExitNow(error = kThreadError_None); + } + + break; + + case Frame::kFcfFrameBeacon: + mCounters.mRxBeacon++; + break; + + case Frame::kFcfFrameData: + mCounters.mRxData++; + break; + + default: + mCounters.mRxOther++; + break; } for (Receiver *receiver = mReceiveHead; receiver; receiver = receiver->mNext) @@ -847,6 +910,45 @@ void Mac::ReceiveDoneTask(Frame *aFrame, ThreadError aError) } exit: + + if (error != kThreadError_None) + { + switch (error) + { + case kThreadError_Security: + mCounters.mRxErrSec++; + break; + + case kThreadError_FcsErr: + mCounters.mRxErrFcs++; + break; + + case kThreadError_NoFrameReceived: + mCounters.mRxErrNoFrame++; + break; + + case kThreadError_UnknownNeighbor: + mCounters.mRxErrUnknownNeighbor++; + break; + + case kThreadError_InvalidSourceAddress: + mCounters.mRxErrInvalidSrcAddr++; + break; + + case kThreadError_WhitelistFiltered: + mCounters.mRxWhitelistFiltered++; + break; + + case kThreadError_DestinationAddressFiltered: + mCounters.mRxDestAddrFiltered++; + break; + + default: + mCounters.mRxErrOther++; + break; + } + } + NextOperation(); } @@ -857,9 +959,12 @@ ThreadError Mac::HandleMacCommand(Frame &aFrame) aFrame.GetCommandId(commandId); - if (commandId == Frame::kMacCmdBeaconRequest) + switch (commandId) { + case Frame::kMacCmdBeaconRequest: + mCounters.mRxBeaconRequest++; otLogInfoMac("Received Beacon Request\n"); + mTransmitBeacon = true; if (mState == kStateIdle) @@ -870,6 +975,14 @@ ThreadError Mac::HandleMacCommand(Frame &aFrame) } ExitNow(error = kThreadError_Drop); + + case Frame::kMacCmdDataRequest: + mCounters.mRxDataPoll++; + break; + + default: + mCounters.mRxOther++; + break; } exit: @@ -902,5 +1015,10 @@ Whitelist &Mac::GetWhitelist(void) return mWhitelist; } +otMacCounters &Mac::GetCounters(void) +{ + return mCounters; +} + } // namespace Mac } // namespace Thread diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index 99742e40b..2bf43e498 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -419,6 +419,14 @@ public: */ void SetPromiscuous(bool aPromiscuous); + /** + * This method returns the MAC counter. + * + * @returns A reference to the MAC counter. + * + */ + otMacCounters &GetCounters(void); + private: void GenerateNonce(const ExtAddress &aAddress, uint32_t aFrameCounter, uint8_t aSecurityLevel, uint8_t *aNonce); void NextOperation(void); @@ -484,6 +492,8 @@ private: otLinkPcapCallback mPcapCallback; Whitelist mWhitelist; + + otMacCounters mCounters; }; /** diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index 6d96a61f6..859d9b9ef 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -515,6 +515,11 @@ exit: return error; } +const otMacCounters *otGetMacCounters(void) +{ + return &sThreadNetif->GetMac().GetCounters(); +} + bool otIsIp6AddressEqual(const otIp6Address *a, const otIp6Address *b) { return *static_cast(a) == *static_cast(b);