blob: a276648cd37f46561b14f1ab60aca5cf2819ea78 [file] [log] [blame]
/*
* Copyright (c) 2016, The OpenThread Authors.
* 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 <openthread/config.h>
#include "mac_frame.hpp"
#include <stdio.h>
#include "utils/wrap_string.h"
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "net/ip6_address.hpp"
namespace ot {
namespace Mac {
void ExtAddress::Set(const Ip6::Address &aIpAddress)
{
memcpy(m8, aIpAddress.GetIid(), sizeof(m8));
m8[0] ^= 0x02;
}
const char *Address::ToString(char *aBuf, uint16_t aSize) const
{
switch (mLength)
{
case sizeof(ShortAddress):
snprintf(aBuf, aSize, "0x%04x", mShortAddress);
break;
case sizeof(ExtAddress):
snprintf(aBuf, aSize, "%02x%02x%02x%02x%02x%02x%02x%02x",
mExtAddress.m8[0], mExtAddress.m8[1], mExtAddress.m8[2], mExtAddress.m8[3],
mExtAddress.m8[4], mExtAddress.m8[5], mExtAddress.m8[6], mExtAddress.m8[7]);
break;
default:
snprintf(aBuf, aSize, "None");
break;
}
return aBuf;
}
otError Frame::InitMacHeader(uint16_t aFcf, uint8_t aSecurityControl)
{
uint8_t *bytes = GetPsdu();
uint8_t length = 0;
// Frame Control Field
bytes[0] = aFcf & 0xff;
bytes[1] = aFcf >> 8;
length += kFcfSize;
// Sequence Number
length += kDsnSize;
// Destinatinon 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 += kSecurityControlSize + kFrameCounterSize;
}
switch (aSecurityControl & kKeyIdModeMask)
{
case kKeyIdMode0:
length += kKeySourceSizeMode0;
break;
case kKeyIdMode1:
length += kKeySourceSizeMode1 + kKeyIndexSize;
break;
case kKeyIdMode2:
length += kKeySourceSizeMode2 + kKeyIndexSize;
break;
case kKeyIdMode3:
length += kKeySourceSizeMode3 + kKeyIndexSize;
break;
}
}
// Command ID
if ((aFcf & kFcfFrameTypeMask) == kFcfFrameMacCmd)
{
length += kCommandIdSize;
}
SetPsduLength(length + GetFooterLength());
return OT_ERROR_NONE;
}
otError Frame::ValidatePsdu(void)
{
otError error = OT_ERROR_PARSE;
uint8_t offset = 0;
uint16_t fcf;
uint8_t footerLength = kFcsSize;
VerifyOrExit((offset += kFcfSize + kDsnSize) <= GetPsduLength());
fcf = static_cast<uint16_t>((GetPsdu()[1] << 8) | GetPsdu()[0]);
// Destinatinon PAN + Address
switch (fcf & Frame::kFcfDstAddrMask)
{
case Frame::kFcfDstAddrNone:
break;
case Frame::kFcfDstAddrShort:
offset += sizeof(PanId) + sizeof(ShortAddress);
break;
case Frame::kFcfDstAddrExt:
offset += sizeof(PanId) + sizeof(ExtAddress);
break;
default:
goto exit;
}
// Source PAN + Address
switch (fcf & Frame::kFcfSrcAddrMask)
{
case Frame::kFcfSrcAddrNone:
break;
case Frame::kFcfSrcAddrShort:
if ((fcf & Frame::kFcfPanidCompression) == 0)
{
offset += sizeof(PanId);
}
offset += sizeof(ShortAddress);
break;
case Frame::kFcfSrcAddrExt:
if ((fcf & Frame::kFcfPanidCompression) == 0)
{
offset += sizeof(PanId);
}
offset += sizeof(ExtAddress);
break;
default:
goto exit;
}
// Security Header
if (fcf & Frame::kFcfSecurityEnabled)
{
uint8_t secControl = GetPsdu()[offset];
offset += kSecurityControlSize + kFrameCounterSize;
switch (secControl & kKeyIdModeMask)
{
case kKeyIdMode0:
offset += kKeySourceSizeMode0;
break;
case kKeyIdMode1:
offset += kKeySourceSizeMode1 + kKeyIndexSize;
break;
case kKeyIdMode2:
offset += kKeySourceSizeMode2 + kKeyIndexSize;
break;
case kKeyIdMode3:
offset += kKeySourceSizeMode3 + kKeyIndexSize;
break;
}
switch (secControl & 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;
}
}
// Command ID
if ((fcf & kFcfFrameTypeMask) == kFcfFrameMacCmd)
{
offset += kCommandIdSize;
}
VerifyOrExit((offset + footerLength) <= GetPsduLength());
error = OT_ERROR_NONE;
exit:
return error;
}
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;
}
otError Frame::GetDstPanId(PanId &aPanId)
{
otError error = OT_ERROR_NONE;
uint8_t *buf;
VerifyOrExit((buf = FindDstPanId()) != NULL, error = OT_ERROR_PARSE);
aPanId = static_cast<uint16_t>((buf[1] << 8) | buf[0]);
exit:
return error;
}
otError Frame::SetDstPanId(PanId aPanId)
{
uint8_t *buf;
buf = FindDstPanId();
assert(buf != NULL);
buf[0] = aPanId & 0xff;
buf[1] = aPanId >> 8;
return OT_ERROR_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;
}
otError Frame::GetDstAddr(Address &aAddress)
{
otError error = OT_ERROR_NONE;
uint8_t *buf;
uint16_t fcf = static_cast<uint16_t>((GetPsdu()[1] << 8) | GetPsdu()[0]);
VerifyOrExit(buf = FindDstAddr(), error = OT_ERROR_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;
}
otError 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 & 0xff;
buf[1] = aShortAddress >> 8;
return OT_ERROR_NONE;
}
otError 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 OT_ERROR_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;
}
otError Frame::GetSrcPanId(PanId &aPanId)
{
otError error = OT_ERROR_NONE;
uint8_t *buf;
VerifyOrExit((buf = FindSrcPanId()) != NULL, error = OT_ERROR_PARSE);
aPanId = static_cast<uint16_t>((buf[1] << 8) | buf[0]);
exit:
return error;
}
otError Frame::SetSrcPanId(PanId aPanId)
{
otError error = OT_ERROR_NONE;
uint8_t *buf;
VerifyOrExit((buf = FindSrcPanId()) != NULL, error = OT_ERROR_PARSE);
buf[0] = aPanId & 0xff;
buf[1] = aPanId >> 8;
exit:
return error;
}
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;
}
otError Frame::GetSrcAddr(Address &address)
{
otError error = OT_ERROR_NONE;
uint8_t *buf;
uint16_t fcf = static_cast<uint16_t>((GetPsdu()[1] << 8) | GetPsdu()[0]);
VerifyOrExit((buf = FindSrcAddr()) != NULL, error = OT_ERROR_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;
}
otError 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 & 0xff;
buf[1] = aShortAddress >> 8;
return OT_ERROR_NONE;
}
otError 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 OT_ERROR_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;
}
otError Frame::GetSecurityLevel(uint8_t &aSecurityLevel)
{
otError error = OT_ERROR_NONE;
uint8_t *buf;
VerifyOrExit((buf = FindSecurityHeader()) != NULL, error = OT_ERROR_PARSE);
aSecurityLevel = buf[0] & kSecLevelMask;
exit:
return error;
}
otError Frame::GetKeyIdMode(uint8_t &aKeyIdMode)
{
otError error = OT_ERROR_NONE;
uint8_t *buf;
VerifyOrExit((buf = FindSecurityHeader()) != NULL, error = OT_ERROR_PARSE);
aKeyIdMode = buf[0] & kKeyIdModeMask;
exit:
return error;
}
otError Frame::GetFrameCounter(uint32_t &aFrameCounter)
{
otError error = OT_ERROR_NONE;
uint8_t *buf;
VerifyOrExit((buf = FindSecurityHeader()) != NULL, error = OT_ERROR_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;
}
otError Frame::SetFrameCounter(uint32_t aFrameCounter)
{
uint8_t *buf;
buf = FindSecurityHeader();
assert(buf != NULL);
// Security Control
buf += kSecurityControlSize;
buf[0] = aFrameCounter & 0xff;
buf[1] = (aFrameCounter >> 8) & 0xff;
buf[2] = (aFrameCounter >> 16) & 0xff;
buf[3] = (aFrameCounter >> 24) & 0xff;
return OT_ERROR_NONE;
}
const uint8_t *Frame::GetKeySource(void)
{
uint8_t *buf;
buf = FindSecurityHeader();
assert(buf != NULL);
// Security Control
buf += kSecurityControlSize + kFrameCounterSize;
return buf;
}
uint8_t Frame::GetKeySourceLength(uint8_t aKeyIdMode)
{
uint8_t rval = 0;
switch (aKeyIdMode)
{
case kKeyIdMode0:
rval = kKeySourceSizeMode0;
break;
case kKeyIdMode1:
rval = kKeySourceSizeMode1;
break;
case kKeyIdMode2:
rval = kKeySourceSizeMode2;
break;
case kKeyIdMode3:
rval = kKeySourceSizeMode3;
break;
}
return rval;
}
void Frame::SetKeySource(const uint8_t *aKeySource)
{
uint8_t keySourceLength;
uint8_t *buf;
buf = FindSecurityHeader();
assert(buf != NULL);
keySourceLength = GetKeySourceLength(buf[0] & kKeyIdModeMask);
buf += kSecurityControlSize + kFrameCounterSize;
memcpy(buf, aKeySource, keySourceLength);
}
otError Frame::GetKeyId(uint8_t &aKeyId)
{
otError error = OT_ERROR_NONE;
uint8_t keySourceLength;
uint8_t *buf;
VerifyOrExit((buf = FindSecurityHeader()) != NULL, error = OT_ERROR_PARSE);
keySourceLength = GetKeySourceLength(buf[0] & kKeyIdModeMask);
buf += kSecurityControlSize + kFrameCounterSize + keySourceLength;
aKeyId = buf[0];
exit:
return error;
}
otError Frame::SetKeyId(uint8_t aKeyId)
{
uint8_t keySourceLength;
uint8_t *buf;
buf = FindSecurityHeader();
assert(buf != NULL);
keySourceLength = GetKeySourceLength(buf[0] & kKeyIdModeMask);
buf += kSecurityControlSize + kFrameCounterSize + keySourceLength;
buf[0] = aKeyId;
return OT_ERROR_NONE;
}
otError Frame::GetCommandId(uint8_t &aCommandId)
{
otError error = OT_ERROR_NONE;
uint8_t *buf;
VerifyOrExit((buf = GetPayload()) != NULL, error = OT_ERROR_PARSE);
aCommandId = buf[-1];
exit:
return error;
}
otError Frame::SetCommandId(uint8_t aCommandId)
{
otError error = OT_ERROR_NONE;
uint8_t *buf;
VerifyOrExit((buf = GetPayload()) != NULL, error = OT_ERROR_PARSE);
buf[-1] = aCommandId;
exit:
return error;
}
uint8_t Frame::GetHeaderLength(void)
{
return static_cast<uint8_t>(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());
}
otError Frame::SetPayloadLength(uint8_t aLength)
{
SetPsduLength(GetHeaderLength() + GetFooterLength() + aLength);
return OT_ERROR_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;
cur += kSecurityControlSize + kFrameCounterSize;
switch (securityControl & kKeyIdModeMask)
{
case kKeyIdMode0:
cur += kKeySourceSizeMode0;
break;
case kKeyIdMode1:
cur += kKeySourceSizeMode1 + kKeyIndexSize;
break;
case kKeyIdMode2:
cur += kKeySourceSizeMode2 + kKeyIndexSize;
break;
case kKeyIdMode3:
cur += kKeySourceSizeMode3 + kKeyIndexSize;
break;
}
}
// Command ID
if ((fcf & kFcfFrameTypeMask) == kFcfFrameMacCmd)
{
cur += kCommandIdSize;
}
exit:
return cur;
}
uint8_t *Frame::GetFooter(void)
{
return GetPsdu() + GetPsduLength() - GetFooterLength();
}
const char *Frame::ToInfoString(char *aBuf, uint16_t aSize)
{
uint8_t type, commandId;
Address src, dst;
const char *typeStr;
char stringBuffer[10];
char srcStringBuffer[Address::kAddressStringSize];
char dstStringBuffer[Address::kAddressStringSize];
type = GetType();
switch (type)
{
case kFcfFrameBeacon:
typeStr = "Beacon";
break;
case kFcfFrameData:
typeStr = "Data";
break;
case kFcfFrameAck:
typeStr = "Ack";
break;
case kFcfFrameMacCmd:
if (GetCommandId(commandId) != OT_ERROR_NONE)
{
commandId = 0xff;
}
switch (commandId)
{
case kMacCmdDataRequest:
typeStr = "Cmd(DataReq)";
break;
case kMacCmdBeaconRequest:
typeStr = "Cmd(BeaconReq)";
break;
default:
snprintf(stringBuffer, sizeof(stringBuffer), "Cmd(%d)", commandId);
typeStr = stringBuffer;
break;
}
break;
default:
snprintf(stringBuffer, sizeof(stringBuffer), "%d", type);
typeStr = stringBuffer;
break;
}
if (GetSrcAddr(src) != OT_ERROR_NONE)
{
src.mLength = 0;
}
if (GetDstAddr(dst) != OT_ERROR_NONE)
{
dst.mLength = 0;
}
snprintf(aBuf, aSize, "len:%d, seqnum:%d, type:%s, src:%s, dst:%s, sec:%s, ackreq:%s", GetLength(), GetSequence(),
typeStr, src.ToString(srcStringBuffer, sizeof(srcStringBuffer)),
dst.ToString(dstStringBuffer, sizeof(dstStringBuffer)), GetSecurityEnabled() ? "yes" : "no",
GetAckRequest() ? "yes" : "no");
return aBuf;
}
const char *BeaconPayload::ToInfoString(char *aBuf, uint16_t aSize)
{
const uint8_t *xpanid = GetExtendedPanId();
snprintf(aBuf, aSize, "name:%s, xpanid:%02x%02x%02x%02x%02x%02x%02x%02x, id:%d ver:%d, joinable:%s, native:%s",
GetNetworkName(), xpanid[0], xpanid[1], xpanid[2], xpanid[3], xpanid[4], xpanid[5], xpanid[6], xpanid[7],
GetProtocolId(), GetProtocolVersion(), IsJoiningPermitted() ? "yes" : "no", IsNative() ? "yes" : "no");
return aBuf;
}
} // namespace Mac
} // namespace ot