ThreadError Mac::ProcessReceiveSecurity(const Address &aSrcAddr, Neighbor *aNeighbor) { ThreadError error = kThreadError_None; uint8_t securityLevel; uint32_t frameCounter; uint8_t nonce[kNonceSize]; uint8_t tag[Frame::kMaxMicSize]; uint8_t tagLength; uint8_t keyid; uint32_t keySequence; const uint8_t *macKey; Crypto::AesCcm aesCcm; mReceiveFrame.SetSecurityValid(false); if (mReceiveFrame.GetSecurityEnabled() == false) { ExitNow(); } VerifyOrExit(aNeighbor != NULL, error = kThreadError_Security); mReceiveFrame.GetSecurityLevel(securityLevel); mReceiveFrame.GetFrameCounter(frameCounter); GenerateNonce(aSrcAddr.mExtAddress, frameCounter, securityLevel, nonce); tagLength = mReceiveFrame.GetFooterLength() - Frame::kFcsSize; mReceiveFrame.GetKeyId(keyid); keyid--; if (keyid == (mKeyManager.GetCurrentKeySequence() & 0x7f)) { // same key index keySequence = mKeyManager.GetCurrentKeySequence(); macKey = mKeyManager.GetCurrentMacKey(); VerifyOrExit(aNeighbor->mPreviousKey == true || frameCounter >= aNeighbor->mValid.mLinkFrameCounter, error = kThreadError_Security); } else if (aNeighbor->mPreviousKey && mKeyManager.IsPreviousKeyValid() && keyid == (mKeyManager.GetPreviousKeySequence() & 0x7f)) { // previous key index keySequence = mKeyManager.GetPreviousKeySequence(); macKey = mKeyManager.GetPreviousMacKey(); VerifyOrExit(frameCounter >= aNeighbor->mValid.mLinkFrameCounter, error = kThreadError_Security); } else if (keyid == ((mKeyManager.GetCurrentKeySequence() + 1) & 0x7f)) { // next key index keySequence = mKeyManager.GetCurrentKeySequence() + 1; macKey = mKeyManager.GetTemporaryMacKey(keySequence); } else { for (Receiver *receiver = mReceiveHead; receiver; receiver = receiver->mNext) { receiver->HandleReceivedFrame(mReceiveFrame, kThreadError_Security); } ExitNow(error = kThreadError_Security); } aesCcm.SetKey(macKey, 16); aesCcm.Init(mReceiveFrame.GetHeaderLength(), mReceiveFrame.GetPayloadLength(), tagLength, nonce, sizeof(nonce)); aesCcm.Header(mReceiveFrame.GetHeader(), mReceiveFrame.GetHeaderLength()); aesCcm.Payload(mReceiveFrame.GetPayload(), mReceiveFrame.GetPayload(), mReceiveFrame.GetPayloadLength(), false); aesCcm.Finalize(tag, &tagLength); VerifyOrExit(memcmp(tag, mReceiveFrame.GetFooter(), tagLength) == 0, error = kThreadError_Security); if (keySequence > mKeyManager.GetCurrentKeySequence()) { mKeyManager.SetCurrentKeySequence(keySequence); } if (keySequence == mKeyManager.GetCurrentKeySequence()) { aNeighbor->mPreviousKey = false; } aNeighbor->mValid.mLinkFrameCounter = frameCounter + 1; mReceiveFrame.SetSecurityValid(true); exit: return error; }