#define LOG_MODULE PacketLogModuleStpLayer
#include "StpLayer.h"
#include "PayloadLayer.h"
#include "EndianPortable.h"
#include "Logger.h"
namespace pcpp
{
MacAddress StpLayer::StpMulticastDstMAC("01:80:C2:00:00:00");
MacAddress StpLayer::StpUplinkFastMulticastDstMAC("01:00:0C:CD:CD:CD");
MacAddress StpLayer::IDtoMacAddress(uint64_t id)
{
return MacAddress((id >> 40) & 0xFF, (id >> 32) & 0xFF, (id >> 24) & 0xFF, (id >> 16) & 0xFF, (id >> 8) & 0xFF,
id & 0xFF);
}
uint64_t StpLayer::macAddressToID(const pcpp::MacAddress &addr)
{
uint8_t value[6];
addr.copyTo(value);
return ((uint64_t(value[0]) << 40) | (uint64_t(value[1]) << 32) | (uint64_t(value[2]) << 24) |
(uint64_t(value[3]) << 16) | (uint64_t(value[4]) << 8) | (uint64_t(value[5])));
}
bool StpLayer::isDataValid(const uint8_t *data, size_t dataLen) { return data && dataLen; }
StpLayer *StpLayer::parseStpLayer(uint8_t *data, size_t dataLen, Layer *prevLayer, Packet *packet)
{
if (dataLen >= sizeof(stp_tcn_bpdu))
{
stp_tcn_bpdu *ptr = (stp_tcn_bpdu *)data;
switch (ptr->type)
{
case 0x00:
return StpConfigurationBPDULayer::isDataValid(data, dataLen)
? new StpConfigurationBPDULayer(data, dataLen, prevLayer, packet)
: nullptr;
case 0x02:
if (ptr->version == 0x2)
return RapidStpLayer::isDataValid(data, dataLen)
? new RapidStpLayer(data, dataLen, prevLayer, packet)
: nullptr;
if (ptr->version == 0x3)
return MultipleStpLayer::isDataValid(data, dataLen)
? new MultipleStpLayer(data, dataLen, prevLayer, packet)
: nullptr;
PCPP_LOG_DEBUG("Unknown Spanning Tree Version");
return nullptr;
case 0x80:
return StpTopologyChangeBPDULayer::isDataValid(data, dataLen)
? new StpTopologyChangeBPDULayer(data, dataLen, prevLayer, packet)
: nullptr;
default:
PCPP_LOG_DEBUG("Unknown Spanning Tree Protocol type");
return nullptr;
}
}
PCPP_LOG_DEBUG("Data length is less than any STP header");
return nullptr;
}
StpTopologyChangeBPDULayer::StpTopologyChangeBPDULayer() : StpLayer(sizeof(stp_tcn_bpdu))
{
setProtoId(0x0);
setVersion(0x0);
setType(0x80);
}
void StpTopologyChangeBPDULayer::parseNextLayer()
{
if (m_DataLen > sizeof(stp_tcn_bpdu))
m_NextLayer = new PayloadLayer(m_Data, m_DataLen - sizeof(stp_tcn_bpdu), this, m_Packet);
}
StpConfigurationBPDULayer::StpConfigurationBPDULayer() : StpTopologyChangeBPDULayer(sizeof(stp_conf_bpdu))
{
setProtoId(0x0);
setVersion(0x0);
setType(0x0);
}
uint64_t StpConfigurationBPDULayer::getRootId() const { return be64toh(getStpConfHeader()->rootId); }
void StpConfigurationBPDULayer::setRootId(uint64_t value) { getStpConfHeader()->rootId = htobe64(value); }
uint16_t StpConfigurationBPDULayer::getRootPriority() const { return be16toh(getStpConfHeader()->rootId) & 0xf000; }
void StpConfigurationBPDULayer::setRootPriority(uint16_t value)
{
getStpConfHeader()->rootId = (getStpConfHeader()->rootId & ~htobe16(0xf000)) | htobe16(value & 0xf000);
}
uint16_t StpConfigurationBPDULayer::getRootSystemIDExtension() const
{
return be16toh(getStpConfHeader()->rootId) & 0x0fff;
}
void StpConfigurationBPDULayer::setRootSystemIDExtension(uint16_t value)
{
getStpConfHeader()->rootId = (getStpConfHeader()->rootId & ~htobe16(0x0fff)) | htobe16(value & 0x0fff);
}
void StpConfigurationBPDULayer::setRootSystemID(const pcpp::MacAddress &value)
{
setRootId((getRootId() & (uint64_t(0xffff) << 48)) | macAddressToID(value));
};
uint32_t StpConfigurationBPDULayer::getPathCost() const { return be32toh(getStpConfHeader()->pathCost); }
void StpConfigurationBPDULayer::setPathCost(uint32_t value) { getStpConfHeader()->pathCost = htobe32(value); }
uint64_t StpConfigurationBPDULayer::getBridgeId() const { return be64toh(getStpConfHeader()->bridgeId); }
void StpConfigurationBPDULayer::setBridgeId(uint64_t value) { getStpConfHeader()->bridgeId = htobe64(value); }
uint16_t StpConfigurationBPDULayer::getBridgePriority() const
{
return be16toh(getStpConfHeader()->bridgeId) & 0xf000;
}
void StpConfigurationBPDULayer::setBridgePriority(uint16_t value)
{
getStpConfHeader()->bridgeId = (getStpConfHeader()->bridgeId & ~htobe16(0xf000)) | htobe16(value & 0xf000);
}
uint16_t StpConfigurationBPDULayer::getBridgeSystemIDExtension() const
{
return be16toh(getStpConfHeader()->bridgeId) & 0x0fff;
}
void StpConfigurationBPDULayer::setBridgeSystemIDExtension(uint16_t value)
{
getStpConfHeader()->bridgeId = (getStpConfHeader()->bridgeId & ~htobe16(0x0fff)) | htobe16(value & 0x0fff);
}
void StpConfigurationBPDULayer::setBridgeSystemID(const pcpp::MacAddress &value)
{
setBridgeId((getBridgeId() & (uint64_t(0xffff) << 48)) | macAddressToID(value));
}
uint16_t StpConfigurationBPDULayer::getPortId() const { return be16toh(getStpConfHeader()->portId); }
void StpConfigurationBPDULayer::setPortId(uint16_t value) { getStpConfHeader()->portId = htobe16(value); }
double StpConfigurationBPDULayer::getMessageAge() const { return getStpConfHeader()->msgAge; }
void StpConfigurationBPDULayer::setMessageAge(double value) { getStpConfHeader()->msgAge = value; }
double StpConfigurationBPDULayer::getMaximumAge() const { return getStpConfHeader()->maxAge; }
void StpConfigurationBPDULayer::setMaximumAge(double value) { getStpConfHeader()->maxAge = value; }
double StpConfigurationBPDULayer::getTransmissionInterval() const { return getStpConfHeader()->helloTime; }
void StpConfigurationBPDULayer::setTransmissionInterval(double value) { getStpConfHeader()->helloTime = value; }
double StpConfigurationBPDULayer::getForwardDelay() const { return getStpConfHeader()->forwardDelay; }
void StpConfigurationBPDULayer::setForwardDelay(double value) { getStpConfHeader()->forwardDelay = value; }
void StpConfigurationBPDULayer::parseNextLayer()
{
if (m_DataLen > sizeof(stp_conf_bpdu))
m_NextLayer = new PayloadLayer(m_Data, m_DataLen - sizeof(stp_conf_bpdu), this, m_Packet);
}
RapidStpLayer::RapidStpLayer() : StpConfigurationBPDULayer(sizeof(rstp_conf_bpdu))
{
setProtoId(0x0);
setVersion(0x2);
setType(0x2);
}
void RapidStpLayer::parseNextLayer()
{
if (m_DataLen > sizeof(rstp_conf_bpdu))
m_NextLayer = new PayloadLayer(m_Data, m_DataLen - sizeof(rstp_conf_bpdu), this, m_Packet);
}
MultipleStpLayer::MultipleStpLayer() : RapidStpLayer(sizeof(mstp_conf_bpdu))
{
setProtoId(0x0);
setVersion(0x3);
setType(0x2);
}
uint16_t MultipleStpLayer::getVersion3Len() const { return be16toh(getMstpHeader()->version3Len); }
void MultipleStpLayer::setVersion3Len(uint16_t value) { getMstpHeader()->version3Len = htobe16(value); }
uint32_t MultipleStpLayer::getCISTIrpc() const { return be32toh(getMstpHeader()->irpc); }
void MultipleStpLayer::setCISTIrpc(uint32_t value) { getMstpHeader()->irpc = htobe32(value); }
uint64_t MultipleStpLayer::getCISTBridgeId() const { return be64toh(getMstpHeader()->cistBridgeId); }
void MultipleStpLayer::setCISTBridgeId(uint64_t value) { getMstpHeader()->cistBridgeId = htobe64(value); }
uint16_t MultipleStpLayer::getCISTBridgePriority() const { return be16toh(getMstpHeader()->cistBridgeId) & 0xf000; }
void MultipleStpLayer::setCISTBridgePriority(uint16_t value)
{
getMstpHeader()->cistBridgeId = (getMstpHeader()->cistBridgeId & ~htobe16(0xf000)) | htobe16(value & 0xf000);
}
uint16_t MultipleStpLayer::getCISTBridgeSystemIDExtension() const
{
return be16toh(getMstpHeader()->cistBridgeId) & 0x0fff;
}
void MultipleStpLayer::setCISTBridgeSystemIDExtension(uint16_t value)
{
getMstpHeader()->cistBridgeId = (getMstpHeader()->cistBridgeId & ~htobe16(0x0fff)) | htobe16(value & 0x0fff);
}
void MultipleStpLayer::setCISTBridgeSystemID(const pcpp::MacAddress &value)
{
setCISTBridgeId((getCISTBridgeId() & (uint64_t(0xffff) << 48)) | macAddressToID(value));
}
std::string MultipleStpLayer::getMstConfigurationName() const
{
std::string str = std::string((char *)(getMstpHeader()->mstConfigName), 32);
str.erase(std::find(str.begin(), str.end(), '\0'), str.end());
return str;
}
uint16_t MultipleStpLayer::getMstConfigRevision() const
{
return be16toh(getMstpHeader()->mstConfigRevision);
}
void MultipleStpLayer::setMstConfigRevision(uint16_t value)
{
getMstpHeader()->mstConfigRevision = htobe16(value);
}
void MultipleStpLayer::setMstConfigDigest(const uint8_t *value, uint8_t len)
{
memset(getMstpHeader()->mstConfigDigest, 0, 16);
memcpy(getMstpHeader()->mstConfigDigest, value, std::min<size_t>(len, 16));
}
void MultipleStpLayer::setMstConfigurationName(const std::string &value)
{
memset(getMstpHeader()->mstConfigName, 0, 32);
memcpy(getMstpHeader()->mstConfigName, value.c_str(), std::min<size_t>(value.size(), 32));
}
msti_conf_msg *MultipleStpLayer::getMstiConfMessages() const
{
if (getNumberOfMSTIConfMessages())
return (msti_conf_msg *)(m_Data + sizeof(mstp_conf_bpdu));
return nullptr;
}
}