#define LOG_MODULE PacketLogModuleVlanLayer
#include "VlanLayer.h"
#include "IPv4Layer.h"
#include "IPv6Layer.h"
#include "PayloadLayer.h"
#include "ArpLayer.h"
#include "PPPoELayer.h"
#include "MplsLayer.h"
#include "LLCLayer.h"
#include <string.h>
#include <sstream>
#include "EndianPortable.h"
namespace pcpp
{
VlanLayer::VlanLayer(const uint16_t vlanID, bool cfi, uint8_t priority, uint16_t etherType)
{
const size_t headerLen = sizeof(vlan_header);
m_DataLen = headerLen;
m_Data = new uint8_t[headerLen];
memset(m_Data, 0, headerLen);
m_Protocol = VLAN;
vlan_header* vlanHeader = getVlanHeader();
setVlanID(vlanID);
setCFI(cfi);
setPriority(priority);
vlanHeader->etherType = htobe16(etherType);
}
uint16_t VlanLayer::getVlanID() const
{
return be16toh(getVlanHeader()->vlan) & 0xFFF;
}
uint8_t VlanLayer::getCFI() const
{
return ((be16toh(getVlanHeader()->vlan) >> 12) & 1);
}
uint8_t VlanLayer::getPriority() const
{
return (be16toh(getVlanHeader()->vlan) >> 13) & 7;
}
void VlanLayer::setVlanID(uint16_t id)
{
getVlanHeader()->vlan = htobe16((be16toh(getVlanHeader()->vlan) & (~0xFFF)) | (id & 0xFFF));
}
void VlanLayer::setCFI(bool cfi)
{
getVlanHeader()->vlan = htobe16((be16toh(getVlanHeader()->vlan) & (~(1 << 12))) | ((cfi & 1) << 12));
}
void VlanLayer::setPriority(uint8_t priority)
{
getVlanHeader()->vlan = htobe16((be16toh(getVlanHeader()->vlan) & (~(7 << 13))) | ((priority & 7) << 13));
}
void VlanLayer::parseNextLayer()
{
if (m_DataLen <= sizeof(vlan_header))
return;
uint8_t* payload = m_Data + sizeof(vlan_header);
size_t payloadLen = m_DataLen - sizeof(vlan_header);
vlan_header* hdr = getVlanHeader();
switch (be16toh(hdr->etherType))
{
case PCPP_ETHERTYPE_IP:
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 PCPP_ETHERTYPE_IPV6:
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;
case PCPP_ETHERTYPE_ARP:
m_NextLayer = new ArpLayer(payload, payloadLen, this, m_Packet);
break;
case PCPP_ETHERTYPE_VLAN:
case PCPP_ETHERTYPE_IEEE_802_1AD:
m_NextLayer = new VlanLayer(payload, payloadLen, this, m_Packet);
break;
case PCPP_ETHERTYPE_PPPOES:
m_NextLayer = PPPoESessionLayer::isDataValid(payload, payloadLen)
? static_cast<Layer*>(new PPPoESessionLayer(payload, payloadLen, this, m_Packet))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, m_Packet));
break;
case PCPP_ETHERTYPE_PPPOED:
m_NextLayer = PPPoEDiscoveryLayer::isDataValid(payload, payloadLen)
? static_cast<Layer*>(new PPPoEDiscoveryLayer(payload, payloadLen, this, m_Packet))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, m_Packet));
break;
case PCPP_ETHERTYPE_MPLS:
m_NextLayer = new MplsLayer(payload, payloadLen, this, m_Packet);
break;
default:
m_NextLayer = (be16toh(hdr->etherType) < 1500 && LLCLayer::isDataValid(payload, payloadLen))
? static_cast<Layer *>(new LLCLayer(payload, payloadLen, this, m_Packet))
: static_cast<Layer *>(new PayloadLayer(payload, payloadLen, this, m_Packet));
}
}
void VlanLayer::computeCalculateFields()
{
if (m_NextLayer == nullptr)
return;
switch (m_NextLayer->getProtocol())
{
case IPv4:
getVlanHeader()->etherType = htobe16(PCPP_ETHERTYPE_IP);
break;
case IPv6:
getVlanHeader()->etherType = htobe16(PCPP_ETHERTYPE_IPV6);
break;
case ARP:
getVlanHeader()->etherType = htobe16(PCPP_ETHERTYPE_ARP);
break;
case VLAN:
getVlanHeader()->etherType = htobe16(PCPP_ETHERTYPE_VLAN);
break;
default:
return;
}
}
std::string VlanLayer::toString() const
{
std::ostringstream cfiStream;
cfiStream << (int)getCFI();
std::ostringstream priStream;
priStream << (int)getPriority();
std::ostringstream idStream;
idStream << getVlanID();
return "VLAN Layer, Priority: " + priStream.str() + ", Vlan ID: " + idStream.str() + ", CFI: " + cfiStream.str();
}
}