blob: 16b52711bd59572d9d0ac96da22a78cbe4baf348 [file] [log] [blame]
/*
* Copyright (c) 2016, Nest Labs, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements IEEE 802.15.4 header generation and processing.
*/
#include <common/code_utils.hpp>
#include <common/debug.hpp>
#include <mac/mac_frame.hpp>
#include <net/ip6_address.hpp>
namespace Thread {
namespace Mac {
void ExtAddress::Set(const Ip6::Address &aIpAddress)
{
memcpy(m8, aIpAddress.GetIid(), sizeof(m8));
m8[0] ^= 0x02;
}
ThreadError Frame::InitMacHeader(uint16_t aFcf, uint8_t aSecurityControl)
{
uint8_t *bytes = GetPsdu();
uint8_t length = 0;
// Frame Control Field
bytes[0] = aFcf;
bytes[1] = aFcf >> 8;
length += kFcfSize;
// Sequence Number
length += kDsnSize;
// Destinatino PAN + Address
switch (aFcf & Frame::kFcfDstAddrMask)
{
case Frame::kFcfDstAddrNone:
break;
case Frame::kFcfDstAddrShort:
length += sizeof(PanId) + sizeof(ShortAddress);
break;
case Frame::kFcfDstAddrExt:
length += sizeof(PanId) + sizeof(ExtAddress);
break;
default:
assert(false);
}
// Source PAN + Address
switch (aFcf & Frame::kFcfSrcAddrMask)
{
case Frame::kFcfSrcAddrNone:
break;
case Frame::kFcfSrcAddrShort:
if ((aFcf & Frame::kFcfPanidCompression) == 0)
{
length += sizeof(PanId);
}
length += sizeof(ShortAddress);
break;
case Frame::kFcfSrcAddrExt:
if ((aFcf & Frame::kFcfPanidCompression) == 0)
{
length += sizeof(PanId);
}
length += sizeof(ExtAddress);
break;
default:
assert(false);
}
// Security Header
if (aFcf & Frame::kFcfSecurityEnabled)
{
bytes[length] = aSecurityControl;
if (aSecurityControl & kSecLevelMask)
{
length += 5;
}
switch (aSecurityControl & kKeyIdModeMask)
{
case kKeyIdMode0:
length += kKeyIdLengthMode0;
break;
case kKeyIdMode1:
length += kKeyIdLengthMode1;
break;
case kKeyIdMode2:
length += kKeyIdLengthMode2;
break;
case kKeyIdMode3:
length += kKeyIdLengthMode3;
break;
}
}
// Command ID
if ((aFcf & kFcfFrameTypeMask) == kFcfFrameMacCmd)
{
length += kCommandIdSize;
}
SetPsduLength(length + GetFooterLength());
return kThreadError_None;
}
uint8_t Frame::GetType(void)
{
return GetPsdu()[0] & Frame::kFcfFrameTypeMask;
}
bool Frame::GetSecurityEnabled(void)
{
return (GetPsdu()[0] & Frame::kFcfSecurityEnabled) != 0;
}
bool Frame::GetAckRequest(void)
{
return (GetPsdu()[0] & Frame::kFcfAckRequest) != 0;
}
void Frame::SetAckRequest(bool aAckRequest)
{
if (aAckRequest)
{
GetPsdu()[0] |= Frame::kFcfAckRequest;
}
else
{
GetPsdu()[0] &= ~Frame::kFcfAckRequest;
}
}
bool Frame::GetFramePending(void)
{
return (GetPsdu()[0] & Frame::kFcfFramePending) != 0;
}
void Frame::SetFramePending(bool aFramePending)
{
if (aFramePending)
{
GetPsdu()[0] |= Frame::kFcfFramePending;
}
else
{
GetPsdu()[0] &= ~Frame::kFcfFramePending;
}
}
uint8_t *Frame::FindSequence(void)
{
uint8_t *cur = GetPsdu();
// Frame Control Field
cur += kFcfSize;
return cur;
}
uint8_t Frame::GetSequence(void)
{
uint8_t *buf = FindSequence();
return buf[0];
}
void Frame::SetSequence(uint8_t aSequence)
{
uint8_t *buf = FindSequence();
buf[0] = aSequence;
}
uint8_t *Frame::FindDstPanId(void)
{
uint8_t *cur = GetPsdu();
uint16_t fcf = (static_cast<uint16_t>(GetPsdu()[1]) << 8) | GetPsdu()[0];
VerifyOrExit((fcf & Frame::kFcfDstAddrMask) != Frame::kFcfDstAddrNone, cur = NULL);
// Frame Control Field
cur += kFcfSize;
// Sequence Number
cur += kDsnSize;
exit:
return cur;
}
ThreadError Frame::GetDstPanId(PanId &aPanId)
{
ThreadError error = kThreadError_None;
uint8_t *buf;
VerifyOrExit((buf = FindDstPanId()) != NULL, error = kThreadError_Parse);
aPanId = (static_cast<uint16_t>(buf[1]) << 8) | buf[0];
exit:
return error;
}
ThreadError Frame::SetDstPanId(PanId aPanId)
{
uint8_t *buf;
buf = FindDstPanId();
assert(buf != NULL);
buf[0] = aPanId;
buf[1] = aPanId >> 8;
return kThreadError_None;
}
uint8_t *Frame::FindDstAddr(void)
{
uint8_t *cur = GetPsdu();
// Frame Control Field
cur += kFcfSize;
// Sequence Number
cur += kDsnSize;
// Destination PAN
cur += sizeof(PanId);
return cur;
}
ThreadError Frame::GetDstAddr(Address &aAddress)
{
ThreadError error = kThreadError_None;
uint8_t *buf;
uint16_t fcf = (static_cast<uint16_t>(GetPsdu()[1]) << 8) | GetPsdu()[0];
VerifyOrExit(buf = FindDstAddr(), error = kThreadError_Parse);
switch (fcf & Frame::kFcfDstAddrMask)
{
case Frame::kFcfDstAddrShort:
aAddress.mLength = sizeof(ShortAddress);
aAddress.mShortAddress = (static_cast<uint16_t>(buf[1]) << 8) | buf[0];
break;
case Frame::kFcfDstAddrExt:
aAddress.mLength = sizeof(ExtAddress);
for (unsigned int i = 0; i < sizeof(ExtAddress); i++)
{
aAddress.mExtAddress.m8[i] = buf[sizeof(ExtAddress) - 1 - i];
}
break;
default:
aAddress.mLength = 0;
break;
}
exit:
return error;
}
ThreadError Frame::SetDstAddr(ShortAddress aShortAddress)
{
uint8_t *buf;
uint16_t fcf = (static_cast<uint16_t>(GetPsdu()[1]) << 8) | GetPsdu()[0];
assert((fcf & Frame::kFcfDstAddrMask) == Frame::kFcfDstAddrShort);
buf = FindDstAddr();
assert(buf != NULL);
buf[0] = aShortAddress;
buf[1] = aShortAddress >> 8;
return kThreadError_None;
}
ThreadError Frame::SetDstAddr(const ExtAddress &aExtAddress)
{
uint8_t *buf;
uint16_t fcf = (static_cast<uint16_t>(GetPsdu()[1]) << 8) | GetPsdu()[0];
assert((fcf & Frame::kFcfDstAddrMask) == Frame::kFcfDstAddrExt);
buf = FindDstAddr();
assert(buf != NULL);
for (unsigned int i = 0; i < sizeof(ExtAddress); i++)
{
buf[i] = aExtAddress.m8[sizeof(ExtAddress) - 1 - i];
}
return kThreadError_None;
}
uint8_t *Frame::FindSrcPanId(void)
{
uint8_t *cur = GetPsdu();
uint16_t fcf = (static_cast<uint16_t>(GetPsdu()[1]) << 8) | GetPsdu()[0];
VerifyOrExit((fcf & Frame::kFcfDstAddrMask) != Frame::kFcfDstAddrNone ||
(fcf & Frame::kFcfSrcAddrMask) != Frame::kFcfSrcAddrNone, cur = NULL);
// Frame Control Field
cur += kFcfSize;
// Sequence Number
cur += kDsnSize;
if ((fcf & Frame::kFcfPanidCompression) == 0)
{
// Destination PAN + Address
switch (fcf & Frame::kFcfDstAddrMask)
{
case Frame::kFcfDstAddrShort:
cur += sizeof(PanId) + sizeof(ShortAddress);
break;
case Frame::kFcfDstAddrExt:
cur += sizeof(PanId) + sizeof(ExtAddress);
break;
}
}
exit:
return cur;
}
ThreadError Frame::GetSrcPanId(PanId &aPanId)
{
ThreadError error = kThreadError_None;
uint8_t *buf;
VerifyOrExit((buf = FindSrcPanId()) != NULL, error = kThreadError_Parse);
aPanId = (static_cast<uint16_t>(buf[1]) << 8) | buf[0];
exit:
return error;
}
ThreadError Frame::SetSrcPanId(PanId aPanId)
{
uint8_t *buf;
buf = FindSrcPanId();
assert(buf != NULL);
buf[0] = aPanId;
buf[1] = aPanId >> 8;
return kThreadError_None;
}
uint8_t *Frame::FindSrcAddr(void)
{
uint8_t *cur = GetPsdu();
uint16_t fcf = (static_cast<uint16_t>(GetPsdu()[1]) << 8) | GetPsdu()[0];
// Frame Control Field
cur += kFcfSize;
// Sequence Number
cur += kDsnSize;
// Destination PAN + Address
switch (fcf & Frame::kFcfDstAddrMask)
{
case Frame::kFcfDstAddrShort:
cur += sizeof(PanId) + sizeof(ShortAddress);
break;
case Frame::kFcfDstAddrExt:
cur += sizeof(PanId) + sizeof(ExtAddress);
break;
}
// Source PAN
if ((fcf & Frame::kFcfPanidCompression) == 0)
{
cur += sizeof(PanId);
}
return cur;
}
ThreadError Frame::GetSrcAddr(Address &address)
{
ThreadError error = kThreadError_None;
uint8_t *buf;
uint16_t fcf = (static_cast<uint16_t>(GetPsdu()[1]) << 8) | GetPsdu()[0];
VerifyOrExit((buf = FindSrcAddr()) != NULL, error = kThreadError_Parse);
switch (fcf & Frame::kFcfSrcAddrMask)
{
case Frame::kFcfSrcAddrShort:
address.mLength = sizeof(ShortAddress);
address.mShortAddress = (static_cast<uint16_t>(buf[1]) << 8) | buf[0];;
break;
case Frame::kFcfSrcAddrExt:
address.mLength = sizeof(ExtAddress);
for (unsigned int i = 0; i < sizeof(ExtAddress); i++)
{
address.mExtAddress.m8[i] = buf[sizeof(ExtAddress) - 1 - i];
}
break;
default:
address.mLength = 0;
break;
}
exit:
return error;
}
ThreadError Frame::SetSrcAddr(ShortAddress aShortAddress)
{
uint8_t *buf;
uint16_t fcf = (static_cast<uint16_t>(GetPsdu()[1]) << 8) | GetPsdu()[0];
assert((fcf & Frame::kFcfSrcAddrMask) == Frame::kFcfSrcAddrShort);
buf = FindSrcAddr();
assert(buf != NULL);
buf[0] = aShortAddress;
buf[1] = aShortAddress >> 8;
return kThreadError_None;
}
ThreadError Frame::SetSrcAddr(const ExtAddress &aExtAddress)
{
uint8_t *buf;
uint16_t fcf = (static_cast<uint16_t>(GetPsdu()[1]) << 8) | GetPsdu()[0];
assert((fcf & Frame::kFcfSrcAddrMask) == Frame::kFcfSrcAddrExt);
buf = FindSrcAddr();
assert(buf != NULL);
for (unsigned int i = 0; i < sizeof(aExtAddress); i++)
{
buf[i] = aExtAddress.m8[sizeof(aExtAddress) - 1 - i];
}
return kThreadError_None;
}
uint8_t *Frame::FindSecurityHeader(void)
{
uint8_t *cur = GetPsdu();
uint16_t fcf = (static_cast<uint16_t>(GetPsdu()[1]) << 8) | GetPsdu()[0];
VerifyOrExit((fcf & Frame::kFcfSecurityEnabled) != 0, cur = NULL);
// Frame Control Field
cur += kFcfSize;
// Sequence Number
cur += kDsnSize;
// Destination PAN + Address
switch (fcf & Frame::kFcfDstAddrMask)
{
case Frame::kFcfDstAddrShort:
cur += sizeof(PanId) + sizeof(ShortAddress);
break;
case Frame::kFcfDstAddrExt:
cur += sizeof(PanId) + sizeof(ExtAddress);
break;
}
// Source PAN + Address
switch (fcf & Frame::kFcfSrcAddrMask)
{
case Frame::kFcfSrcAddrShort:
if ((fcf & Frame::kFcfPanidCompression) == 0)
{
cur += sizeof(PanId);
}
cur += sizeof(ShortAddress);
break;
case Frame::kFcfSrcAddrExt:
if ((fcf & Frame::kFcfPanidCompression) == 0)
{
cur += sizeof(PanId);
}
cur += sizeof(ExtAddress);
break;
}
exit:
return cur;
}
ThreadError Frame::GetSecurityLevel(uint8_t &aSecurityLevel)
{
ThreadError error = kThreadError_None;
uint8_t *buf;
VerifyOrExit((buf = FindSecurityHeader()) != NULL, error = kThreadError_Parse);
aSecurityLevel = buf[0] & kSecLevelMask;
exit:
return error;
}
ThreadError Frame::GetFrameCounter(uint32_t &aFrameCounter)
{
ThreadError error = kThreadError_None;
uint8_t *buf;
VerifyOrExit((buf = FindSecurityHeader()) != NULL, error = kThreadError_Parse);
// Security Control
buf += kSecurityControlSize;
aFrameCounter = ((static_cast<uint32_t>(buf[3]) << 24) |
(static_cast<uint32_t>(buf[2]) << 16) |
(static_cast<uint32_t>(buf[1]) << 8) |
(static_cast<uint32_t>(buf[0])));
exit:
return error;
}
ThreadError Frame::SetFrameCounter(uint32_t aFrameCounter)
{
uint8_t *buf;
buf = FindSecurityHeader();
assert(buf != NULL);
// Security Control
buf += kSecurityControlSize;
buf[0] = aFrameCounter;
buf[1] = aFrameCounter >> 8;
buf[2] = aFrameCounter >> 16;
buf[3] = aFrameCounter >> 24;
return kThreadError_None;
}
ThreadError Frame::GetKeyId(uint8_t &aKeyId)
{
ThreadError error = kThreadError_None;
uint8_t *buf;
VerifyOrExit((buf = FindSecurityHeader()) != NULL, error = kThreadError_Parse);
// Security Control + Frame Counter
buf += kSecurityControlSize + kFrameCounterSize;
aKeyId = buf[0];
exit:
return error;
}
ThreadError Frame::SetKeyId(uint8_t aKeyId)
{
uint8_t *buf;
buf = FindSecurityHeader();
assert(buf != NULL);
// Security Control + Frame Counter
buf += kSecurityControlSize + kFrameCounterSize;
buf[0] = aKeyId;
return kThreadError_None;
}
ThreadError Frame::GetCommandId(uint8_t &aCommandId)
{
ThreadError error = kThreadError_None;
uint8_t *buf;
VerifyOrExit((buf = GetPayload()) != NULL, error = kThreadError_Parse);
aCommandId = buf[-1];
exit:
return error;
}
ThreadError Frame::SetCommandId(uint8_t aCommandId)
{
ThreadError error = kThreadError_None;
uint8_t *buf;
VerifyOrExit((buf = GetPayload()) != NULL, error = kThreadError_Parse);
buf[-1] = aCommandId;
exit:
return error;
}
uint8_t Frame::GetLength() const
{
return GetPsduLength();
}
ThreadError Frame::SetLength(uint8_t aLength)
{
SetPsduLength(aLength);
return kThreadError_None;
}
uint8_t Frame::GetHeaderLength(void)
{
return GetPayload() - GetPsdu();
}
uint8_t Frame::GetFooterLength(void)
{
uint8_t footerLength = 0;
uint8_t *cur;
VerifyOrExit((cur = FindSecurityHeader()) != NULL, ;);
switch (cur[0] & kSecLevelMask)
{
case kSecNone:
case kSecEnc:
footerLength += kMic0Size;
break;
case kSecMic32:
case kSecEncMic32:
footerLength += kMic32Size;
break;
case kSecMic64:
case kSecEncMic64:
footerLength += kMic64Size;
break;
case kSecMic128:
case kSecEncMic128:
footerLength += kMic128Size;
break;
}
exit:
// Frame Check Sequence
footerLength += kFcsSize;
return footerLength;
}
uint8_t Frame::GetMaxPayloadLength(void)
{
return kMTU - (GetHeaderLength() + GetFooterLength());
}
uint8_t Frame::GetPayloadLength(void)
{
return GetPsduLength() - (GetHeaderLength() + GetFooterLength());
}
ThreadError Frame::SetPayloadLength(uint8_t aLength)
{
SetPsduLength(GetHeaderLength() + GetFooterLength() + aLength);
return kThreadError_None;
}
uint8_t *Frame::GetHeader(void)
{
return GetPsdu();
}
uint8_t *Frame::GetPayload(void)
{
uint8_t *cur = GetPsdu();
uint16_t fcf = (static_cast<uint16_t>(GetPsdu()[1]) << 8) | GetPsdu()[0];
uint8_t securityControl;
// Frame Control
cur += kFcfSize;
// Sequence Number
cur += kDsnSize;
// Destination PAN + Address
switch (fcf & Frame::kFcfDstAddrMask)
{
case Frame::kFcfDstAddrNone:
break;
case Frame::kFcfDstAddrShort:
cur += sizeof(PanId) + sizeof(ShortAddress);
break;
case Frame::kFcfDstAddrExt:
cur += sizeof(PanId) + sizeof(ExtAddress);
break;
default:
ExitNow(cur = NULL);
}
// Source PAN + Address
switch (fcf & Frame::kFcfSrcAddrMask)
{
case Frame::kFcfSrcAddrNone:
break;
case Frame::kFcfSrcAddrShort:
if ((fcf & Frame::kFcfPanidCompression) == 0)
{
cur += sizeof(PanId);
}
cur += sizeof(ShortAddress);
break;
case Frame::kFcfSrcAddrExt:
if ((fcf & Frame::kFcfPanidCompression) == 0)
{
cur += sizeof(PanId);
}
cur += sizeof(ExtAddress);
break;
default:
ExitNow(cur = NULL);
}
// Security Control + Frame Counter + Key Identifier
if ((fcf & Frame::kFcfSecurityEnabled) != 0)
{
securityControl = *cur;
if (securityControl & kSecLevelMask)
{
cur += kSecurityControlSize + kFrameCounterSize;
}
switch (securityControl & kKeyIdModeMask)
{
case kKeyIdMode0:
cur += kKeyIdLengthMode0;
break;
case kKeyIdMode1:
cur += kKeyIdLengthMode1;
break;
case kKeyIdMode2:
cur += kKeyIdLengthMode2;
break;
case kKeyIdMode3:
cur += kKeyIdLengthMode3;
break;
}
}
// Command ID
if ((fcf & kFcfFrameTypeMask) == kFcfFrameMacCmd)
{
cur += kCommandIdSize;
}
exit:
return cur;
}
uint8_t *Frame::GetFooter(void)
{
return GetPsdu() + GetPsduLength() - GetFooterLength();
}
} // namespace Mac
} // namespace Thread