#define LOG_MODULE PacketLogModuleMplsLayer
#include "MplsLayer.h"
#include "IPv4Layer.h"
#include "IPv6Layer.h"
#include "PayloadLayer.h"
#include "Logger.h"
#include <string.h>
#include <sstream>
#include "EndianPortable.h"
namespace pcpp
{
MplsLayer::MplsLayer(uint32_t mplsLabel, uint8_t ttl, uint8_t experimentalUseValue, bool bottomOfStack)
{
const size_t headerLen = sizeof(mpls_header);
m_DataLen = headerLen;
m_Data = new uint8_t[headerLen];
memset(m_Data, 0, headerLen);
m_Protocol = MPLS;
setMplsLabel(mplsLabel);
setTTL(ttl);
setExperimentalUseValue(experimentalUseValue);
setBottomOfStack(bottomOfStack);
}
bool MplsLayer::isBottomOfStack() const
{
return (getMplsHeader()->misc & 0x01);
}
void MplsLayer::setBottomOfStack(bool val)
{
if (!val)
getMplsHeader()->misc &= 0xFE;
else
getMplsHeader()->misc |= 0x1;
}
uint8_t MplsLayer::getExperimentalUseValue() const
{
return ((getMplsHeader()->misc & 0x0E) >> 1);
}
bool MplsLayer::setExperimentalUseValue(uint8_t val)
{
if (val > 7)
{
PCPP_LOG_ERROR("Set ExperimentalUse value got an illegal value: " << (int)val << ". Value must be lower than 8");
return false;
}
mpls_header* hdr = getMplsHeader();
hdr->misc &= 0xF1;
val = val << 1;
hdr->misc |= val;
return true;
}
uint32_t MplsLayer::getMplsLabel() const
{
return (htobe16(getMplsHeader()->hiLabel) << 4) | ((getMplsHeader()->misc & 0xF0) >> 4);
}
bool MplsLayer::setMplsLabel(uint32_t label)
{
if (label > 0xFFFFF)
{
PCPP_LOG_ERROR("MPLS label mustn't exceed 20 bits which is the value 0xffff. Got a parameter with the value 0x" << std::hex << label);
return false;
}
mpls_header* hdr = getMplsHeader();
hdr->misc &= 0x0F;
uint8_t miscVal = (label & 0x0F) << 4;
hdr->misc |= miscVal;
label = label >> 4;
hdr->hiLabel = (uint16_t)htobe16(label);
return true;
}
void MplsLayer::parseNextLayer()
{
size_t headerLen = getHeaderLen();
if (m_DataLen < headerLen + 1)
return;
uint8_t* payload = m_Data + sizeof(mpls_header);
size_t payloadLen = m_DataLen - sizeof(mpls_header);
if (!isBottomOfStack())
{
m_NextLayer = new MplsLayer(payload, payloadLen, this, m_Packet);
return;
}
uint8_t nextNibble = (*((uint8_t*)(m_Data + headerLen)) & 0xF0) >> 4;
switch (nextNibble)
{
case 4:
m_NextLayer = IPv4Layer::isDataValid(payload, payloadLen)
? static_cast<Layer*>(new IPv4Layer(payload, payloadLen, this, m_Packet))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, m_Packet));
break;
case 6:
m_NextLayer = IPv6Layer::isDataValid(payload, payloadLen)
? static_cast<Layer*>(new IPv6Layer(payload, payloadLen, this, m_Packet))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, m_Packet));
break;
default:
m_NextLayer = new PayloadLayer(payload, payloadLen, this, m_Packet);
}
}
void MplsLayer::computeCalculateFields()
{
Layer* nextLayer = getNextLayer();
if (nextLayer != nullptr)
{
setBottomOfStack((nextLayer->getProtocol() != MPLS));
}
}
std::string MplsLayer::toString() const
{
std::ostringstream labelStream;
labelStream << getMplsLabel();
std::ostringstream expStream;
expStream << (int)getExperimentalUseValue();
std::ostringstream ttlStream;
ttlStream << (int)getTTL();
std::string bottomOfStack = isBottomOfStack() ? "true" : "false";
return "MPLS Layer, Label: " + labelStream.str() + ", Exp: " + expStream.str() + ", TTL: " + ttlStream.str() +
", Bottom of stack: " + bottomOfStack;
}
}