diff --git a/CMakeLists.txt b/CMakeLists.txt index 76b03d6..5368268 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,7 +195,6 @@ set(SRC_FILES communication/message/tc10statusmessage.cpp communication/message/gptpstatusmessage.cpp communication/message/ethernetstatusmessage.cpp - communication/message/macsecmessage.cpp communication/message/networkmutexmessage.cpp communication/message/clientidmessage.cpp communication/message/transmitmessage.cpp @@ -226,8 +225,9 @@ set(SRC_FILES communication/communication.cpp communication/driver.cpp communication/livedata.cpp - communication/ringbuffer.cpp - communication/crc32.cpp + core/ringbuffer.cpp + core/crc32.cpp + core/macseccfg.cpp device/extensions/flexray/extension.cpp device/extensions/flexray/controller.cpp device/idevicesettings.cpp diff --git a/api/icsneocpp/event.cpp b/api/icsneocpp/event.cpp index 53984e2..f2e1621 100644 --- a/api/icsneocpp/event.cpp +++ b/api/icsneocpp/event.cpp @@ -156,6 +156,16 @@ static constexpr const char* VSA_BYTE_PARSE_FAILURE = "Failure to parse record b static constexpr const char* VSA_EXTENDED_MESSAGE_ERROR = "Failure to parse extended message record sequence"; static constexpr const char* VSA_OTHER_ERROR = "Unknown error in VSA read API."; +// MACSEC +static constexpr const char* MACSEC_SECY_LIMIT = "Attempted to exceed the limit of SecY additions to this port"; +static constexpr const char* MACSEC_RULE_LIMIT = "Attempted to exceed the limit of rule additions to this port"; +static constexpr const char* MACSEC_SA_LIMIT = "Attempted to exceed the limit of SA additions to this port"; +static constexpr const char* MACSEC_INVALID_SECY_INDEX = "Attempted to access an invalid SecY index"; +static constexpr const char* MACSEC_INVALID_SA_INDEX = "Attempted to access an invalid SA index"; +static constexpr const char* MACSEC_INVALID_RULE_INDEX = "Attempted to access an invalid rule index"; +static constexpr const char* MACSEC_REKEY_NOT_ENABLED = "Attempted to set rekey SA when rekey was not enabled"; +static constexpr const char* MACSEC_NOT_SUPPORTED = "MACsec is not supported on this device"; +static constexpr const char* MACSEC_CONFIG_MISMATCH = "Attempted to configure device with a macsec configuration for a different device"; // Servd static constexpr const char* SERVD_BIND_ERROR = "Error binding socket for Servd communication"; static constexpr const char* SERVD_NONBLOCK_ERROR = "Error setting non-blocking mode for Servd socket"; @@ -371,6 +381,25 @@ const char* APIEvent::DescriptionForType(Type type) { case Type::VSAOtherError: return VSA_OTHER_ERROR; + // MACSEC + case Type::MACsecSecYLimit: + return MACSEC_SECY_LIMIT; + case Type::MACsecSaLimit: + return MACSEC_SA_LIMIT; + case Type::MACsecRuleLimit: + return MACSEC_RULE_LIMIT; + case Type::MACsecInvalidSecYIndex: + return MACSEC_INVALID_SECY_INDEX; + case Type::MACsecInvalidSaIndex: + return MACSEC_INVALID_SA_INDEX; + case Type::MACsecInvalidRuleIndex: + return MACSEC_INVALID_RULE_INDEX; + case Type::MACsecRekeyNotEnabled: + return MACSEC_REKEY_NOT_ENABLED; + case Type::MACsecNotSupported: + return MACSEC_NOT_SUPPORTED; + case Type::MACsecConfigMismatch: + return MACSEC_CONFIG_MISMATCH; // Servd case Type::ServdBindError: return SERVD_BIND_ERROR; diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt index 0691eab..1bbdee3 100644 --- a/bindings/python/CMakeLists.txt +++ b/bindings/python/CMakeLists.txt @@ -32,11 +32,11 @@ pybind11_add_module(icsneopy icsneopy/communication/message/gptpstatusmessage.cpp icsneopy/communication/message/ethernetstatusmessage.cpp icsneopy/communication/message/spimessage.cpp - icsneopy/communication/message/macsecmessage.cpp icsneopy/communication/message/scriptstatusmessage.cpp icsneopy/communication/message/ethphymessage.cpp icsneopy/communication/message/callback/messagecallback.cpp icsneopy/communication/message/filter/messagefilter.cpp + icsneopy/core/macseccfg.cpp icsneopy/flexray/flexray.cpp icsneopy/disk/diskdriver.cpp icsneopy/device/chipid.cpp diff --git a/bindings/python/icsneopy/communication/message/gptpstatusmessage.cpp b/bindings/python/icsneopy/communication/message/gptpstatusmessage.cpp index 1355227..27b2441 100644 --- a/bindings/python/icsneopy/communication/message/gptpstatusmessage.cpp +++ b/bindings/python/icsneopy/communication/message/gptpstatusmessage.cpp @@ -15,64 +15,65 @@ void init_gptpstatusmessage(pybind11::module_& m) { .def("to_seconds", &GPTPStatus::Timestamp::toSeconds, pybind11::call_guard()); pybind11::class_(gptpStatus, "ScaledNanoSeconds") - .def_readonly("nanosecondsMSB", &GPTPStatus::ScaledNanoSeconds::nanosecondsMSB) - .def_readonly("nanosecondsLSB", &GPTPStatus::ScaledNanoSeconds::nanosecondsLSB) - .def_readonly("fractionalNanoseconds", &GPTPStatus::ScaledNanoSeconds::fractionalNanoseconds); + .def_readonly("nanoseconds_msb", &GPTPStatus::ScaledNanoSeconds::nanosecondsMSB) + .def_readonly("nanoseconds_lsb", &GPTPStatus::ScaledNanoSeconds::nanosecondsLSB) + .def_readonly("fractional_nanoseconds", &GPTPStatus::ScaledNanoSeconds::fractionalNanoseconds); pybind11::class_(gptpStatus, "PortID") - .def_readonly("clockIdentity", &GPTPStatus::PortID::clockIdentity) - .def_readonly("portNumber", &GPTPStatus::PortID::portNumber); + .def_readonly("clock_identity", &GPTPStatus::PortID::clockIdentity) + .def_readonly("port_number", &GPTPStatus::PortID::portNumber); pybind11::class_(gptpStatus, "ClockQuality") - .def_readonly("clockClass", &GPTPStatus::ClockQuality::clockClass) - .def_readonly("clockAccuracy", &GPTPStatus::ClockQuality::clockAccuracy) - .def_readonly("offsetScaledLogVariance", &GPTPStatus::ClockQuality::offsetScaledLogVariance); + .def_readonly("clock_class", &GPTPStatus::ClockQuality::clockClass) + .def_readonly("clock_accuracy", &GPTPStatus::ClockQuality::clockAccuracy) + .def_readonly("offset_scaled_log_variance", &GPTPStatus::ClockQuality::offsetScaledLogVariance); pybind11::class_(gptpStatus, "SystemID") .def_readonly("priority1", &GPTPStatus::SystemID::priority1) - .def_readonly("clockQuality", &GPTPStatus::SystemID::clockQuality) + .def_readonly("clock_quality", &GPTPStatus::SystemID::clockQuality) .def_readonly("priority2", &GPTPStatus::SystemID::priority2) - .def_readonly("clockID", &GPTPStatus::SystemID::clockID); + .def_readonly("clock_id", &GPTPStatus::SystemID::clockID); pybind11::class_(gptpStatus, "PriorityVector") - .def_readonly("sysID", &GPTPStatus::PriorityVector::sysID) - .def_readonly("stepsRemoved", &GPTPStatus::PriorityVector::stepsRemoved) - .def_readonly("portID", &GPTPStatus::PriorityVector::portID) - .def_readonly("portNumber", &GPTPStatus::PriorityVector::portNumber); + .def_readonly("sys_id", &GPTPStatus::PriorityVector::sysID) + .def_readonly("steps_removed", &GPTPStatus::PriorityVector::stepsRemoved) + .def_readonly("port_id", &GPTPStatus::PriorityVector::portID) + .def_readonly("port_number", &GPTPStatus::PriorityVector::portNumber); pybind11::class_(gptpStatus, "ParentDS") - .def_readonly("parentPortIdentity", &GPTPStatus::ParentDS::parentPortIdentity) - .def_readonly("cumulativeRateRatio", &GPTPStatus::ParentDS::cumulativeRateRatio) - .def_readonly("grandmasterIdentity", &GPTPStatus::ParentDS::grandmasterIdentity) - .def_readonly("gmClockQualityClockClass", &GPTPStatus::ParentDS::gmClockQualityClockClass) - .def_readonly("gmClockQualityClockAccuracy", &GPTPStatus::ParentDS::gmClockQualityClockAccuracy) - .def_readonly("gmClockQualityOffsetScaledLogVariance", &GPTPStatus::ParentDS::gmClockQualityOffsetScaledLogVariance) - .def_readonly("gmPriority1", &GPTPStatus::ParentDS::gmPriority1) - .def_readonly("gmPriority2", &GPTPStatus::ParentDS::gmPriority2); + .def_readonly("parent_port_identity", &GPTPStatus::ParentDS::parentPortIdentity) + .def_readonly("cumulative_rate_ratio", &GPTPStatus::ParentDS::cumulativeRateRatio) + .def_readonly("grandmaster_identity", &GPTPStatus::ParentDS::grandmasterIdentity) + .def_readonly("gm_clock_quality_clock_class", &GPTPStatus::ParentDS::gmClockQualityClockClass) + .def_readonly("gm_clock_quality_clock_accuracy", &GPTPStatus::ParentDS::gmClockQualityClockAccuracy) + .def_readonly("gm_clock_quality_offset_scaled_log_variance", &GPTPStatus::ParentDS::gmClockQualityOffsetScaledLogVariance) + .def_readonly("gm_priority1", &GPTPStatus::ParentDS::gmPriority1) + .def_readonly("gm_priority2", &GPTPStatus::ParentDS::gmPriority2); pybind11::class_(gptpStatus, "CurrentDS") - .def_readonly("stepsRemoved", &GPTPStatus::CurrentDS::stepsRemoved) - .def_readonly("offsetFromMaster", &GPTPStatus::CurrentDS::offsetFromMaster) - .def_readonly("lastgmPhaseChange", &GPTPStatus::CurrentDS::lastgmPhaseChange) - .def_readonly("lastgmFreqChange", &GPTPStatus::CurrentDS::lastgmFreqChange) - .def_readonly("gmTimeBaseIndicator", &GPTPStatus::CurrentDS::gmTimeBaseIndicator) - .def_readonly("gmChangeCount", &GPTPStatus::CurrentDS::gmChangeCount) - .def_readonly("timeOfLastgmChangeEvent", &GPTPStatus::CurrentDS::timeOfLastgmChangeEvent) - .def_readonly("timeOfLastgmPhaseChangeEvent", &GPTPStatus::CurrentDS::timeOfLastgmPhaseChangeEvent) - .def_readonly("timeOfLastgmFreqChangeEvent", &GPTPStatus::CurrentDS::timeOfLastgmFreqChangeEvent); + .def_readonly("steps_removed", &GPTPStatus::CurrentDS::stepsRemoved) + .def_readonly("offset_from_master", &GPTPStatus::CurrentDS::offsetFromMaster) + .def_readonly("lastgm_phase_change", &GPTPStatus::CurrentDS::lastgmPhaseChange) + .def_readonly("lastgm_freq_change", &GPTPStatus::CurrentDS::lastgmFreqChange) + .def_readonly("gm_time_base_indicator", &GPTPStatus::CurrentDS::gmTimeBaseIndicator) + .def_readonly("gm_change_count", &GPTPStatus::CurrentDS::gmChangeCount) + .def_readonly("time_of_lastgm_change_event", &GPTPStatus::CurrentDS::timeOfLastgmChangeEvent) + .def_readonly("time_of_lastgm_phase_change_event", &GPTPStatus::CurrentDS::timeOfLastgmPhaseChangeEvent) + .def_readonly("time_of_lastgm_freq_change_event", &GPTPStatus::CurrentDS::timeOfLastgmFreqChangeEvent); - gptpStatus.def_readonly("currentTime", &GPTPStatus::currentTime) - .def_readonly("gmPriority", &GPTPStatus::gmPriority) - .def_readonly("msOffsetNs", &GPTPStatus::msOffsetNs) - .def_readonly("isSync", &GPTPStatus::isSync) - .def_readonly("linkStatus", &GPTPStatus::linkStatus) - .def_readonly("linkDelayNS", &GPTPStatus::linkDelayNS) - .def_readonly("selectedRole", &GPTPStatus::selectedRole) - .def_readonly("asCapable", &GPTPStatus::asCapable) - .def_readonly("isSyntonized", &GPTPStatus::isSyntonized) - .def_readonly("lastRXSyncTS", &GPTPStatus::lastRXSyncTS) - .def_readonly("currentDS", &GPTPStatus::currentDS) - .def_readonly("parentDS", &GPTPStatus::parentDS); + gptpStatus.def_readonly("current_time", &GPTPStatus::currentTime) + .def_readonly("gm_priority", &GPTPStatus::gmPriority) + .def_readonly("ms_offset_ns", &GPTPStatus::msOffsetNs) + .def_readonly("is_sync", &GPTPStatus::isSync) + .def_readonly("link_status", &GPTPStatus::linkStatus) + .def_readonly("link_delay_ns", &GPTPStatus::linkDelayNS) + .def_readonly("selected_role", &GPTPStatus::selectedRole) + .def_readonly("as_capable", &GPTPStatus::asCapable) + .def_readonly("is_syntonized", &GPTPStatus::isSyntonized) + .def_readonly("last_rx_sync_ts", &GPTPStatus::lastRXSyncTS) + .def_readonly("current_ds", &GPTPStatus::currentDS) + .def_readonly("parent_ds", &GPTPStatus::parentDS) + .def_readonly("short_format", &GPTPStatus::shortFormat); } diff --git a/bindings/python/icsneopy/communication/message/macsecmessage.cpp b/bindings/python/icsneopy/communication/message/macsecmessage.cpp deleted file mode 100644 index b2ef80d..0000000 --- a/bindings/python/icsneopy/communication/message/macsecmessage.cpp +++ /dev/null @@ -1,160 +0,0 @@ -#include -#include -#include - -#include "icsneo/communication/message/macsecmessage.h" - -namespace icsneo { - -void init_macsecmessage(pybind11::module_ & m) -{ - pybind11::enum_(m, "MACsecPacketType") - .value("NoVLAN_OrMPLS", MACsecPacketType::NoVLANOrMPLS) - .value("SingleVLAN", MACsecPacketType::SingleVLAN) - .value("DualVLAN", MACsecPacketType::DualVLAN) - .value("MPLS", MACsecPacketType::MPLS) - .value("SingleVLAN_FollowByMPLS", MACsecPacketType::SingleVLANFollowedByMPLS) - .value("DualVLAN_FollowByMPLS", MACsecPacketType::DualVLANFollowedByMPLS) - .value("Unsupported", MACsecPacketType::Unsupported); - - pybind11::enum_(m, "MACsecValidateFrameType") - .value("Disabled", MACsecValidateFrameType::Disabled) - .value("Check", MACsecValidateFrameType::Check) - .value("Strict", MACsecValidateFrameType::Strict) - .value("NA", MACsecValidateFrameType::NA); - - pybind11::enum_(m, "MACsecSecTagIcvStripType") - .value("StripBoth", MACsecSecTagIcvStripType::StripBoth) - .value("StripSecTagPreserveICV", MACsecSecTagIcvStripType::StripSecTagPreserveICV) - .value("PreserveSecTagStripICV", MACsecSecTagIcvStripType::PreserveSecTagStripICV) - .value("PreserveBoth", MACsecSecTagIcvStripType::PreserveBoth); - - pybind11::enum_(m, "MACsecCipherSuiteType") - .value("AES_128", MACsecCipherSuiteType::GcmAes128) - .value("AES_256", MACsecCipherSuiteType::GcmAes256) - .value("AES_128_XPN", MACsecCipherSuiteType::GcmAes128Xpn) - .value("AES_256_XPN", MACsecCipherSuiteType::GcmAes256Xpn); - - pybind11::class_>(m, "MACsecVLANTag") - .def(pybind11::init()) - .def_readwrite("vid", &MACsecVLANTag::vid) - .def_readwrite("pri_cfi", &MACsecVLANTag::priCfi); - - pybind11::class_>(m, "MACsecMPLSOuter") - .def(pybind11::init()) - .def_readwrite("mpls_label", &MACsecMPLSOuter::mplsLabel) - .def_readwrite("exp", &MACsecMPLSOuter::exp); - - pybind11::class_>(m, "MACsecRule") - .def(pybind11::init()) - .def_readwrite("index", &MACsecRule::index) - .def_readwrite("keyMacDa", &MACsecRule::keyMacDa) - .def_readwrite("maskMacDa", &MACsecRule::maskMacDa) - .def_readwrite("keyMacSa", &MACsecRule::keyMacSa) - .def_readwrite("maskMacSa", &MACsecRule::maskMacSa) - .def_readwrite("keyEthertype", &MACsecRule::keyEthertype) - .def_readwrite("maskEthertype", &MACsecRule::maskEthertype) - .def_readwrite("keyVlanTagOuter1", &MACsecRule::keyVlanTagOuter1) - .def_readwrite("keyMplsOuter1", &MACsecRule::keyMplsOuter1) - .def_readwrite("maskVlanTagOuter1", &MACsecRule::maskVlanTagOuter1) - .def_readwrite("maskMplsOuter1", &MACsecRule::maskMplsOuter1) - .def_readwrite("keyVlanTagOuter2", &MACsecRule::keyVlanTagOuter2) - .def_readwrite("keyMplsOuter2", &MACsecRule::keyMplsOuter2) - .def_readwrite("maskVlanTagOuter2", &MACsecRule::maskVlanTagOuter2) - .def_readwrite("maskMplsOuter2", &MACsecRule::maskMplsOuter2) - .def_readwrite("keyBonusData", &MACsecRule::keyBonusData) - .def_readwrite("maskBonusData", &MACsecRule::maskBonusData) - .def_readwrite("keyTagMatchBitmap", &MACsecRule::keyTagMatchBitmap) - .def_readwrite("maskTagMatchBitmap", &MACsecRule::maskTagMatchBitmap) - .def_readwrite("keyPacketType", &MACsecRule::keyPacketType) - .def_readwrite("maskPacketType", &MACsecRule::maskPacketType) - .def_readwrite("keyInnerVlanType", &MACsecRule::keyInnerVlanType) - .def_readwrite("maskInnerVlanType", &MACsecRule::maskInnerVlanType) - .def_readwrite("keyOuterVlanType", &MACsecRule::keyOuterVlanType) - .def_readwrite("maskOuterVlanType", &MACsecRule::maskOuterVlanType) - .def_readwrite("keyNumTags", &MACsecRule::keyNumTags) - .def_readwrite("maskNumTags", &MACsecRule::maskNumTags) - .def_readwrite("keyExpress", &MACsecRule::keyExpress) - .def_readwrite("maskExpress", &MACsecRule::maskExpress) - .def_readwrite("isMpls", &MACsecRule::isMpls) - .def_readwrite("enable", &MACsecRule::enable); - - pybind11::class_>(m, "MACsecMap") - .def(pybind11::init()) - .def_readwrite("index", &MACsecMap::index) - .def_readwrite("secTagSci", &MACsecMap::secTagSci) - .def_readwrite("secYIndex", &MACsecMap::secYIndex) - .def_readwrite("isControlPacket", &MACsecMap::isControlPacket) - .def_readwrite("scIndex", &MACsecMap::scIndex) - .def_readwrite("auxiliaryPlcy", &MACsecMap::auxiliaryPlcy) - .def_readwrite("ruleId", &MACsecMap::ruleId) - .def_readwrite("enable", &MACsecMap::enable); - - pybind11::class_>(m, "MACsecSecY") - .def(pybind11::init()) - .def_readwrite("index", &MACsecSecY::index) - .def_readwrite("controlledPortEnabled", &MACsecSecY::controlledPortEnabled) - .def_readwrite("frameValidationType", &MACsecSecY::frameValidationType) - .def_readwrite("secTagIcvStripType", &MACsecSecY::secTagIcvStripType) - .def_readwrite("cipher", &MACsecSecY::cipher) - .def_readwrite("confidentialOffset", &MACsecSecY::confidentialOffset) - .def_readwrite("icvIncludesDaSa", &MACsecSecY::icvIncludesDaSa) - .def_readwrite("replayProtect", &MACsecSecY::replayProtect) - .def_readwrite("replayWindow", &MACsecSecY::replayWindow) - .def_readwrite("protectFrames", &MACsecSecY::protectFrames) - .def_readwrite("secTagOffset", &MACsecSecY::secTagOffset) - .def_readwrite("secTagTci", &MACsecSecY::secTagTci) - .def_readwrite("mtu", &MACsecSecY::mtu) - .def_readwrite("enable", &MACsecSecY::enable); - - pybind11::class_>(m, "MACsecSc") - .def(pybind11::init()) - .def_readwrite("index", &MACsecSc::index) - .def_readwrite("secYIndex", &MACsecSc::secYIndex) - .def_readwrite("sci", &MACsecSc::sci) - .def_readwrite("saIndex0", &MACsecSc::saIndex0) - .def_readwrite("saIndex1", &MACsecSc::saIndex1) - .def_readwrite("saIndex0InUse", &MACsecSc::saIndex0InUse) - .def_readwrite("saIndex1InUse", &MACsecSc::saIndex1InUse) - .def_readwrite("enableAutoRekey", &MACsecSc::enableAutoRekey) - .def_readwrite("isActiveSa1", &MACsecSc::isActiveSa1) - .def_readwrite("enable", &MACsecSc::enable); - - pybind11::class_>(m, "MACsecSa") - .def(pybind11::init()) - .def_readwrite("index", &MACsecSa::index) - .def_readwrite("sak", &MACsecSa::sak) - .def_readwrite("hashKey", &MACsecSa::hashKey) - .def_readwrite("salt", &MACsecSa::salt) - .def_readwrite("ssci", &MACsecSa::ssci) - .def_readwrite("an", &MACsecSa::an) - .def_readwrite("nextPn", &MACsecSa::nextPn) - .def_readwrite("enable", &MACsecSa::enable); - - pybind11::class_>(m, "MACSecFlags") - .def(pybind11::init()) - .def_readwrite("en", &MACSecFlags::en); - - pybind11::class_>(m, "MACsecConfig") - .def(pybind11::init()) - .def_readwrite("flags", &MACsecConfig::flags) - .def_readwrite("rule", &MACsecConfig::rule) - .def_readwrite("map", &MACsecConfig::map) - .def_readwrite("secy", &MACsecConfig::secy) - .def_readwrite("sc", &MACsecConfig::sc) - .def_readwrite("sa", &MACsecConfig::sa); - - pybind11::class_>(m, "MACSecGlobalFlags") - .def(pybind11::init()) - .def_readwrite("en", &MACSecGlobalFlags::en) - .def_readwrite("nvm", &MACSecGlobalFlags::nvm); - - pybind11::class_>(m, "MACsecMessage") - .def(pybind11::init()) - .def_readwrite("flags", &MACsecMessage::flags) - .def_readwrite("rx", &MACsecMessage::rx) - .def_readwrite("tx", &MACsecMessage::tx); -} - -} // namespace icsneo - diff --git a/bindings/python/icsneopy/core/macseccfg.cpp b/bindings/python/icsneopy/core/macseccfg.cpp new file mode 100644 index 0000000..1470d82 --- /dev/null +++ b/bindings/python/icsneopy/core/macseccfg.cpp @@ -0,0 +1,166 @@ +#include +#include +#include + +#include "icsneo/core/macseccfg.h" + +namespace icsneo { + +void init_macsecconfig(pybind11::module_ & m) +{ + pybind11::enum_(m, "MACsecPacketType") + .value("DEFAULT", MACsecPacketType::Default) + .value("SINGLE_VLAN", MACsecPacketType::SingleVLAN) + .value("DUAL_VLAN", MACsecPacketType::DualVLAN) + .value("MPLS", MACsecPacketType::MPLS) + .value("SINGLE_VLAN_FOLLOWED_BY_MPLS", MACsecPacketType::SingleVLANFollowedByMPLS) + .value("DUAL_VLAN_FOLLOWED_BY_MPLS", MACsecPacketType::DualVLANFollowedByMPLS) + .value("UNSUPPORTED", MACsecPacketType::Unsupported); + + pybind11::enum_(m, "MACsecValidation") + .value("DISABLED", MACsecValidation::Disabled) + .value("CHECK", MACsecValidation::Check) + .value("STRICT", MACsecValidation::Strict) + .value("NA", MACsecValidation::NA); + + pybind11::enum_(m, "MACsecStrip") + .value("STRIP_SECTAG_AND_ICV", MACsecStrip::StripSecTagAndIcv) + .value("STRIP_SECTAG_PRESERVE_ICV", MACsecStrip::StripSecTagPreserveICV) + .value("PRESERVE_SECTAG_STRIP_ICV", MACsecStrip::PreserveSecTagStripICV) + .value("NO_STRIP", MACsecStrip::NoStrip); + + pybind11::enum_(m, "MACsecCipherSuite") + .value("GCM_AES_128", MACsecCipherSuite::GcmAes128) + .value("GCM_AES_256", MACsecCipherSuite::GcmAes256) + .value("GCM_AES_128_XPN", MACsecCipherSuite::GcmAes128Xpn) + .value("GCM_AES_256_XPN", MACsecCipherSuite::GcmAes256Xpn); + + pybind11::class_>(m, "MACsecVLANTag") + .def(pybind11::init()) + .def_readwrite("vid", &MACsecVLANTag::vid) + .def_readwrite("pri_cfi", &MACsecVLANTag::priCfi); + + pybind11::class_>(m, "MACsecMPLSOuter") + .def(pybind11::init()) + .def_readwrite("mpls_label", &MACsecMPLSOuter::mplsLabel) + .def_readwrite("exp", &MACsecMPLSOuter::exp); + + pybind11::class_>(m, "MACsecTci") + .def(pybind11::init()) + .def_readwrite("es", &MACsecTci::es) + .def_readwrite("sc", &MACsecTci::sc) + .def_readwrite("scb", &MACsecTci::scb) + .def_readwrite("e", &MACsecTci::e) + .def_readwrite("c", &MACsecTci::c); + + pybind11::class_>(m, "MACsecRxRule") + .def(pybind11::init()) + .def_readwrite("key_mac_da", &MACsecRxRule::keyMacDa) + .def_readwrite("mask_mac_da", &MACsecRxRule::maskMacDa) + .def_readwrite("key_mask_sa", &MACsecRxRule::keyMacSa) + .def_readwrite("mask_mac_sa", &MACsecRxRule::maskMacSa) + .def_readwrite("key_ether_type", &MACsecRxRule::keyEthertype) + .def_readwrite("mask_ether_type", &MACsecRxRule::maskEthertype) + .def_readwrite("key_vlan_tag_outer1", &MACsecRxRule::keyVlanTagOuter1) + .def_readwrite("key_mpls_outer1", &MACsecRxRule::keyMplsOuter1) + .def_readwrite("mask_vlan_tag_outer1", &MACsecRxRule::maskVlanTagOuter1) + .def_readwrite("mask_mpls_outer1", &MACsecRxRule::maskMplsOuter1) + .def_readwrite("key_vlan_tag_outer2", &MACsecRxRule::keyVlanTagOuter2) + .def_readwrite("key_mpls_outer2", &MACsecRxRule::keyMplsOuter2) + .def_readwrite("mask_vlan_tag_outer2", &MACsecRxRule::maskVlanTagOuter2) + .def_readwrite("mask_mpls_outer2", &MACsecRxRule::maskMplsOuter2) + .def_readwrite("key_bonus_data", &MACsecRxRule::keyBonusData) + .def_readwrite("mask_bonus_data", &MACsecRxRule::maskBonusData) + .def_readwrite("key_tag_match_bitmap", &MACsecRxRule::keyTagMatchBitmap) + .def_readwrite("mask_tag_match_bitmap", &MACsecRxRule::maskTagMatchBitmap) + .def_readwrite("key_packet_type", &MACsecRxRule::keyPacketType) + .def_readwrite("mask_packet_type", &MACsecRxRule::maskPacketType) + .def_readwrite("key_inner_vlan_type", &MACsecRxRule::keyInnerVlanType) + .def_readwrite("mask_inner_vlan_type", &MACsecRxRule::maskInnerVlanType) + .def_readwrite("key_outer_vlan_type", &MACsecRxRule::keyOuterVlanType) + .def_readwrite("mask_outer_vlan_type", &MACsecRxRule::maskOuterVlanType) + .def_readwrite("key_num_tags", &MACsecRxRule::keyNumTags) + .def_readwrite("mask_num_tags", &MACsecRxRule::maskNumTags) + .def_readwrite("key_express", &MACsecRxRule::keyExpress) + .def_readwrite("mask_express", &MACsecRxRule::maskExpress) + .def_readwrite("is_mpls", &MACsecRxRule::isMpls); + + pybind11::class_>(m, "MACsecTxSecY") + .def(pybind11::init()) + .def_readwrite("enable_control_port", &MACsecTxSecY::enableControlPort) + .def_readwrite("cipher", &MACsecTxSecY::cipher) + .def_readwrite("confidentiality_offset", &MACsecTxSecY::confidentialityOffset) + .def_readwrite("icv_includes_da_sa", &MACsecTxSecY::icvIncludesDaSa) + .def_readwrite("protect_frames", &MACsecTxSecY::protectFrames) + .def_readwrite("sec_tag_offset", &MACsecTxSecY::secTagOffset) + .def_readwrite("sec_tag_tci", &MACsecTxSecY::tci) + .def_readwrite("mtu", &MACsecTxSecY::mtu) + .def_readwrite("is_control_packet", &MACsecTxSecY::isControlPacket) + .def_readwrite("auxiliary_policy", &MACsecTxSecY::auxiliaryPolicy) + .def_readwrite("sci", &MACsecTxSecY::sci); + + pybind11::class_>(m, "MACsecRxSecY") + .def(pybind11::init()) + .def_readwrite("enable_control_port", &MACsecRxSecY::enableControlPort) + .def_readwrite("frame_validation", &MACsecRxSecY::frameValidation) + .def_readwrite("frame_strip", &MACsecRxSecY::frameStrip) + .def_readwrite("cipher", &MACsecRxSecY::cipher) + .def_readwrite("confidentiality_offset", &MACsecRxSecY::confidentialityOffset) + .def_readwrite("icv_includes_da_sa", &MACsecRxSecY::icvIncludesDaSa) + .def_readwrite("replay_protect", &MACsecRxSecY::replayProtect) + .def_readwrite("replay_window", &MACsecRxSecY::replayWindow) + .def_readwrite("is_control_packet", &MACsecRxSecY::isControlPacket) + .def_readwrite("sci", &MACsecRxSecY::sci); + + pybind11::class_>(m, "MACsecTxSa") + .def(pybind11::init()) + .def_readwrite("sak", &MACsecTxSa::sak) + .def_readwrite("hash_key", &MACsecTxSa::hashKey) + .def_readwrite("salt", &MACsecTxSa::salt) + .def_readwrite("ssci", &MACsecTxSa::ssci) + .def_readwrite("next_pn", &MACsecTxSa::nextPn) + .def_readwrite("an", &MACsecTxSa::an); + + pybind11::class_>(m, "MACsecRxSa") + .def(pybind11::init()) + .def_readwrite("sak", &MACsecRxSa::sak) + .def_readwrite("hash_key", &MACsecRxSa::hashKey) + .def_readwrite("salt", &MACsecRxSa::salt) + .def_readwrite("ssci", &MACsecRxSa::ssci) + .def_readwrite("next_pn", &MACsecRxSa::nextPn); + + pybind11::class_>(m, "MACsecConfig") + .def(pybind11::init()) + .def("add_rx_secy", &MACsecConfig::addRxSecY, pybind11::call_guard()) + .def("add_tx_secY", &MACsecConfig::addTxSecY, pybind11::call_guard()) + .def("add_rx_rule", &MACsecConfig::addRxRule, pybind11::call_guard()) + .def("add_rx_sa", &MACsecConfig::addRxSa, pybind11::call_guard()) + .def("add_tx_sa", &MACsecConfig::addTxSa, pybind11::call_guard()) + .def("get_rx_secy", [](MACsecConfig& cfg, uint8_t index) -> MACsecRxSecY& { return cfg.getRxSecY(index); }, pybind11::call_guard()) + .def("get_tx_secy", [](MACsecConfig& cfg, uint8_t index) -> MACsecTxSecY& { return cfg.getTxSecY(index); }, pybind11::call_guard()) + .def("get_rx_sa", [](MACsecConfig& cfg, uint8_t index) -> MACsecRxSa& { return cfg.getRxSa(index); }, pybind11::call_guard()) + .def("get_tx_sa", [](MACsecConfig& cfg, uint8_t index) -> MACsecTxSa& { return cfg.getTxSa(index); }, pybind11::call_guard()) + .def("get_rx_rule", [](MACsecConfig& cfg, uint8_t index) -> MACsecRxRule& { return cfg.getRxRule(index); }, pybind11::call_guard()) + .def("set_tx_sa_index", &MACsecConfig::setTxSaIndex, pybind11::call_guard()) + .def("enable_tx_rekey", &MACsecConfig::enableTxRekey, pybind11::call_guard()) + .def("set_tx_sa_rekey_index", &MACsecConfig::setTxSaRekeyIndex, pybind11::call_guard()) + .def("disable_tx_rekey", &MACsecConfig::disableTxRekey, pybind11::call_guard()) + .def("set_rx_sa_index", &MACsecConfig::setRxSaIndex, pybind11::call_guard()) + .def("enable_rx_rekey", &MACsecConfig::enableRxRekey, pybind11::call_guard()) + .def("set_rx_sa_rekey_index", &MACsecConfig::setRxSaRekeyIndex, pybind11::call_guard()) + .def("disable_rx_rekey", &MACsecConfig::disableRxRekey, pybind11::call_guard()) + .def("set_rx_enable", &MACsecConfig::setRxEnable, pybind11::call_guard()) + .def("set_tx_enable", &MACsecConfig::setTxEnable, pybind11::call_guard()) + .def("set_storage", &MACsecConfig::setStorage, pybind11::call_guard()) + .def("clear", &MACsecConfig::clear, pybind11::call_guard()) + .def("serialize", &MACsecConfig::serialize, pybind11::call_guard()) + .def("get_bin_index", &MACsecConfig::getBinIndex, pybind11::call_guard()) + .def("get_type", &MACsecConfig::getType, pybind11::call_guard()) + .def("get_max_num_rule", &MACsecConfig::getMaxNumRule, pybind11::call_guard()) + .def("get_max_num_secy", &MACsecConfig::getMaxNumSecY, pybind11::call_guard()) + .def("get_max_num_sa", &MACsecConfig::getMaxNumSa, pybind11::call_guard()); + +} + +} // namespace icsneo + diff --git a/bindings/python/icsneopy/icsneocpp.cpp b/bindings/python/icsneopy/icsneocpp.cpp index e99ea98..329f884 100644 --- a/bindings/python/icsneopy/icsneocpp.cpp +++ b/bindings/python/icsneopy/icsneocpp.cpp @@ -22,7 +22,7 @@ void init_gptpstatusmessage(pybind11::module_&); void init_mdiomessage(pybind11::module_&); void init_spimessage(pybind11::module_&); void init_ethernetstatusmessage(pybind11::module_&); -void init_macsecmessage(pybind11::module_&); +void init_macsecconfig(pybind11::module_&); void init_scriptstatusmessage(pybind11::module_&); void init_diskdriver(pybind11::module_&); void init_deviceextension(pybind11::module_&); @@ -57,7 +57,7 @@ PYBIND11_MODULE(icsneopy, m) { init_gptpstatusmessage(m); init_mdiomessage(m); init_ethernetstatusmessage(m); - init_macsecmessage(m); + init_macsecconfig(m); init_scriptstatusmessage(m); init_spimessage(m); init_messagefilter(m); diff --git a/communication/message/macsecmessage.cpp b/communication/message/macsecmessage.cpp deleted file mode 100644 index 218242c..0000000 --- a/communication/message/macsecmessage.cpp +++ /dev/null @@ -1,531 +0,0 @@ -#include "icsneo/communication/message/macsecmessage.h" - -#include "icsneo/communication/crc32.h" -#include -#include -#include -#include - -namespace icsneo -{ - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4201) // nameless struct/union -#endif - -#pragma pack(push, 1) -/* MACsec Rule */ -/** - * @brief Structure of Vlan tag - * - */ -typedef struct -{ - uint16_t vid; /*!< 12 bits */ - uint8_t priCfi; /*!< PRI - 3 bits, CFI - 1bit */ -} MACSEC_VLANTAG_t; -/** - * @brief Structure of MPLS - * - */ -typedef struct -{ - uint32_t mplsLabel; /*!< 20 bits */ - uint8_t exp; /*!< 3 bits */ -} MACSEC_MPLS_OUTER_t; -/** - * @brief Define Encoded Packet Type from the parser - * - */ -static constexpr int MACSEC_SETTINGS_RULE_SIZE = 88; -typedef union _MACSecRule -{ - struct - { - uint8_t index; - uint8_t keyMacDa[6]; /*!< MAC DA field extracted from the packet */ - uint8_t maskMacDa[6]; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - uint8_t keyMacSa[6]; /*!< MAC SA field extracted from the packet */ - uint8_t maskMacSa[6]; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - uint16_t keyEthertype; /*!< First E-Type found in the packet that doesn't match one of the preconfigured custom tag. */ - uint16_t maskEthertype; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - MACSEC_VLANTAG_t keyVlanTagOuter1; /*!< outermost/1st VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */ - MACSEC_MPLS_OUTER_t keyMplsOuter1; - MACSEC_VLANTAG_t maskVlanTagOuter1; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - MACSEC_MPLS_OUTER_t maskMplsOuter1; - MACSEC_VLANTAG_t keyVlanTagOuter2; /*!< 2nd outermost VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */ - MACSEC_MPLS_OUTER_t keyMplsOuter2; - MACSEC_VLANTAG_t maskVlanTagOuter2; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - MACSEC_MPLS_OUTER_t maskMplsOuter2; - uint16_t keyBonusData; /*!< 2 bytes of additional bonus data extracted from one of the custom tags. */ - uint16_t maskBonusData; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - uint8_t - keyTagMatchBitmap; /*!< 8 bits total. Maps 1 to 1 bitwise with the set of custom tags. (set bit[N]=1 if check Nth custom tag) */ - uint8_t maskTagMatchBitmap; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - uint8_t keyPacketType; /*!< Encoded Packet Type, see MACSEC_PACKET_TYPE */ - uint8_t maskPacketType; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - uint16_t - keyInnerVlanType; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the second outermost VLAN Tag. */ - uint16_t maskInnerVlanType; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - uint16_t keyOuterVlanType; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the outermost VLAN Tag. */ - uint16_t maskOuterVlanType; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - uint8_t - keyNumTags; /*!< 7 bits total. Number of VLAN/custom tags or MPLS lables detected. Ingress: before SecTag; Egress: total detected. Exclude MCS header tags. i.e. Bit 2: 2 tags/labels before SecTAG...Bit 6: 6 or more tags/labels before SecTAG. */ - uint8_t maskNumTags; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - uint8_t keyExpress; /*!< 1 bits. Express packet. */ - uint8_t maskExpress; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - uint8_t isMpls; - uint8_t rsvd[5]; - uint8_t enable; - }; - uint8_t byte[MACSEC_SETTINGS_RULE_SIZE]; -} MACSecRule_t; -/* MACsec Map */ -static constexpr int MACSEC_SETTINGS_MAP_SIZE = 20; -typedef union _MACSecMap -{ - struct - { - uint8_t index; - uint64_t secTagSci; /*!< Identifies the SecTAG SCI for this Flow. */ - uint8_t secYIndex; /*!< index for entry in Egress secY Policy */ - uint8_t isControlPacket; /*!< Identifies all packets matching this index lookup as control packets. */ - uint8_t scIndex; /*!< Identifies the SC for this Flow. */ - uint8_t auxiliaryPlcy; /*!< Auxiliary policy bits. */ - uint8_t ruleId; /*!< Identifies the Rule for this Flow. */ - uint8_t rsvd[5]; - uint8_t enable; - }; - uint8_t byte[MACSEC_SETTINGS_MAP_SIZE]; -} MACSecMap_t; -/* MACsec SecY */ -/** - * @brief Define the permit police for frames as defined in 802.1ae - * - */ -static constexpr int MACSEC_SETTINGS_SECY_SIZE = 24; -typedef union _MACSecSecY -{ - struct - { - uint8_t index; /*!< Identifies the SecY for this Flow. */ - uint8_t controlledPortEnabled; /*!< Enable (or disable) operation of the Controlled port associated with this SecY */ - uint8_t frameValidationType; /*!< see MACSEC_VALIDATEFRAME */ - uint8_t secTagIcvStripType; /*!< see MACSEC_STRIP_SECTAG_ICV */ - uint8_t cipher; /*!< Define the cipher suite to use for this SecY see MACSEC_CIPHER_SUITE */ - uint8_t confidentialOffset; /*!< Define the number of bytes that are unencrypted following the SecTag. */ - uint8_t icvIncludesDaSa; /*!< When set, the outer DA/SA bytes are included in the authentication GHASH calculation */ - uint8_t replayProtect; /*!< Enables Anti-Replay protection */ - uint32_t replayWindow; /*!< Unsigned value indicating the size of the anti-replay window. */ - uint8_t - protectFrames; /*!< 0 = do not encrypt or authenticate this packet; 1 = always Authenticate frame and if SecTag.TCI.E = 1 encrypt the packet as well. */ - uint8_t - secTagOffset; /*!< Define the offset in bytes from either the start of the packet or a matching Etype depending on SecTag_Insertion_Mode. */ - uint8_t secTagTci; /*!< Tag Control Information excluding the AN field which originates from the SA Policy table */ - uint16_t mtu; /*!< Specifies the outgoing MTU for this SecY */ - uint8_t rsvd[6]; - uint8_t enable; - }; - uint8_t byte[MACSEC_SETTINGS_SECY_SIZE]; -} MACSecSecY_t; -/* MACsec SC */ -static constexpr int MACSEC_SETTINGS_SC_SIZE = 24; -typedef union _MACSecSc -{ - struct - { - uint8_t index; /*!< SC index. */ - uint8_t secYIndex; /*!< SecY associated with this packet. */ - uint64_t sci; /*!< The Secure Channel Identifier. */ - uint8_t saIndex0; /*!< Define the 1st SA to use */ - uint8_t saIndex1; /*!< Define the 2nd SA to use */ - uint8_t saIndex0InUse; /*!< Specifies whether 1st SA is in use or not. */ - uint8_t saIndex1InUse; /*!< Specifies whether 2nd SA is in use or not. */ - uint8_t enableAutoRekey; /*!< If enabled, then once the pn_threshold is reached, auto rekey will happen. */ - uint8_t - isActiveSa1; /*!< If set, then sa_index1 is the currently active SA index. If cleared, the sa_index0 is the currently active SA index). */ - uint8_t rsvd[7]; - uint8_t enable; - }; - uint8_t byte[MACSEC_SETTINGS_SC_SIZE]; -} MACSecSc_t; -/* MACsec SA */ -static constexpr int MACSEC_SETTINGS_SA_SIZE = 80; -typedef union _MACSecSa -{ - struct - { - uint8_t index; /*!< SA index */ - uint8_t - sak[32]; /*!< 256b SAK: Define the encryption key to be used to encrypte this packet. The lower 128 bits are used for 128-bit ciphers. */ - uint8_t hashKey[16]; /*!< 128b Hash Key: Key used for authentication. */ - uint8_t salt[12]; /*!< 96b Salt value: Salt value used in XPN ciphers. */ - uint32_t ssci; /*!< 32b SSCI value: Short Secure Channel Identifier, used in XPN ciphers. */ - uint8_t an; /*!< 2b SecTag Association Number (AN) */ - uint64_t nextPn; /*!< 64b next_pn value: Next packet number to insert into outgoing packet on a particular SA. */ - uint8_t rsvd[5]; - uint8_t enable; - }; - uint8_t byte[MACSEC_SETTINGS_SA_SIZE]; -} MACSecSa_t; -/* MACsec Flags */ -typedef union _MACSecFlags -{ - struct - { - uint32_t en : 1; // '1' = enable; '0' = disable - uint32_t reserved : 31; - }; - uint32_t flags_32b; -} MACSecFlags_t; -#define MACSEC_SETTINGS_FLAGS_SIZE (4) -/* MACSec Settings for 1 port/phy */ -typedef struct MACSEC_CONFIG_t -{ - MACSecFlags_t flags; - MACSecRule_t rule[MACsecConfig::NumRules]; - MACSecMap_t map[MACsecConfig::NumMaps]; - MACSecSecY_t secy[MACsecConfig::NumSecY]; - MACSecSc_t sc[MACsecConfig::NumSc]; - MACSecSa_t sa[MACsecConfig::NumSa]; -} MACSEC_CONFIG; -typedef union _MACSecGlobalFlags -{ - struct - { - uint32_t en : 1; // '1' = enable; '0' = disable - uint32_t nvm : 1; // store macsec config in non-volatile memory - uint32_t reserved : 30; - }; - uint32_t flags_32b; -} MACSecGlobalFlags_t; -#define MACSEC_SETTINGS_SIZE (2040) // leave space for expansion and keep nicely aligned for flashing -typedef union _MACSEC_SETTINGS -{ - struct - { - MACSecGlobalFlags_t flags; - MACSEC_CONFIG rx; - MACSEC_CONFIG tx; - }; - uint8_t byte[MACSEC_SETTINGS_SIZE]; -} MACSEC_SETTINGS; - -#define MACSEC_SETTINGS_VERSION 1 -struct MACSEC_SETTINGS_W_HDR -{ - uint16_t version; - uint16_t len; - uint32_t crc32; - MACSEC_SETTINGS macsec; -}; - -#pragma pack(pop) - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -std::shared_ptr MACsecMessage::DecodeToMessage(const std::vector& bytestream, const device_eventhandler_t& report) -{ - if (bytestream.empty() || (bytestream.size() < sizeof(MACSEC_SETTINGS_W_HDR))) - { - report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error); - return nullptr; - } - - MACSEC_SETTINGS_W_HDR* macsecArgs = (MACSEC_SETTINGS_W_HDR*)bytestream.data(); - if (macsecArgs->version != MACSEC_SETTINGS_VERSION) - { - report(APIEvent::Type::SettingsVersionError, APIEvent::Severity::Error); - return nullptr; - } - if (macsecArgs->len != sizeof(MACSEC_SETTINGS)) - { - report(APIEvent::Type::SettingsLengthError, APIEvent::Severity::Error); - return nullptr; - } - const auto crcCalculted = crc32(0, (uint8_t*)&macsecArgs->macsec, macsecArgs->len); - if (macsecArgs->crc32 != crcCalculted) - { - report(APIEvent::Type::SettingsChecksumError, APIEvent::Severity::Error); - return nullptr; - } - - auto msg = std::make_shared(); - - const auto& copyConfig = [](const MACSEC_CONFIG& source, MACsecConfig& dest) - { - dest.flags.en = source.flags.en; - for (int index = 0; index < MACsecConfig::NumRules; index++) - { - if(!source.rule[index].enable) continue; -#undef __COPY_ITEM -#define __COPY_ITEM(___name__) dest.rule[index].___name__ = (decltype(dest.rule[index].___name__))source.rule[index].___name__ -#undef __COPY_ARR -#define __COPY_ARR(___name__) (void)memcpy(dest.rule[index].___name__.data(), source.rule[index].___name__, dest.rule[index].___name__.size()) - __COPY_ITEM(index); - __COPY_ARR(keyMacDa); - __COPY_ARR(maskMacDa); - __COPY_ARR(keyMacSa); - __COPY_ARR(maskMacSa); - __COPY_ITEM(keyVlanTagOuter1.vid); - __COPY_ITEM(keyVlanTagOuter1.priCfi); - __COPY_ITEM(keyMplsOuter1.mplsLabel); - __COPY_ITEM(keyMplsOuter1.exp); - __COPY_ITEM(maskVlanTagOuter1.vid); - __COPY_ITEM(maskVlanTagOuter1.priCfi); - __COPY_ITEM(maskMplsOuter1.mplsLabel); - __COPY_ITEM(maskMplsOuter1.exp); - __COPY_ITEM(keyVlanTagOuter2.vid); - __COPY_ITEM(keyVlanTagOuter2.priCfi); - __COPY_ITEM(keyMplsOuter2.mplsLabel); - __COPY_ITEM(keyMplsOuter2.exp); - __COPY_ITEM(maskVlanTagOuter2.vid); - __COPY_ITEM(maskVlanTagOuter2.priCfi); - __COPY_ITEM(maskMplsOuter2.mplsLabel); - __COPY_ITEM(maskMplsOuter2.exp); - __COPY_ITEM(keyEthertype); - __COPY_ITEM(maskEthertype); - __COPY_ITEM(keyBonusData); - __COPY_ITEM(maskBonusData); - __COPY_ITEM(keyTagMatchBitmap); - __COPY_ITEM(maskTagMatchBitmap); - __COPY_ITEM(keyPacketType); - __COPY_ITEM(maskPacketType); - __COPY_ITEM(keyInnerVlanType); - __COPY_ITEM(maskInnerVlanType); - __COPY_ITEM(keyOuterVlanType); - __COPY_ITEM(maskOuterVlanType); - __COPY_ITEM(keyNumTags); - __COPY_ITEM(maskNumTags); - __COPY_ITEM(keyExpress); - __COPY_ITEM(maskExpress); - __COPY_ITEM(isMpls); - __COPY_ITEM(enable); - } - - for (int index = 0; index < MACsecConfig::NumMaps; index++) - { - if(!source.map[index].enable) continue; -#undef __COPY_ITEM -#define __COPY_ITEM(___name__) dest.map[index].___name__ = source.map[index].___name__ - __COPY_ITEM(index); - __COPY_ITEM(secTagSci); - __COPY_ITEM(secYIndex); - __COPY_ITEM(isControlPacket); - __COPY_ITEM(scIndex); - __COPY_ITEM(auxiliaryPlcy); - __COPY_ITEM(ruleId); - __COPY_ITEM(enable); - } - - for (int index = 0; index < MACsecConfig::NumSecY; index++) - { - if(!source.secy[index].enable) continue; -#undef __COPY_ITEM -#define __COPY_ITEM(___name__) dest.secy[index].___name__ = (decltype(dest.secy[index].___name__))source.secy[index].___name__ - __COPY_ITEM(index); - __COPY_ITEM(controlledPortEnabled); - __COPY_ITEM(frameValidationType); - __COPY_ITEM(secTagIcvStripType); - __COPY_ITEM(cipher); - __COPY_ITEM(confidentialOffset); - __COPY_ITEM(icvIncludesDaSa); - __COPY_ITEM(replayProtect); - __COPY_ITEM(replayWindow); - __COPY_ITEM(protectFrames); - __COPY_ITEM(secTagOffset); - __COPY_ITEM(secTagTci); - __COPY_ITEM(mtu); - __COPY_ITEM(enable); - } - - for (int index = 0; index < MACsecConfig::NumSc; index++) - { - if(!source.sc[index].enable) continue; -#undef __COPY_ITEM -#define __COPY_ITEM(___name__) dest.sc[index].___name__ = source.sc[index].___name__ - __COPY_ITEM(index); - __COPY_ITEM(secYIndex); - __COPY_ITEM(sci); - __COPY_ITEM(saIndex0); - __COPY_ITEM(saIndex1); - __COPY_ITEM(saIndex0InUse); - __COPY_ITEM(saIndex1InUse); - __COPY_ITEM(enableAutoRekey); - __COPY_ITEM(isActiveSa1); - __COPY_ITEM(enable); - } - - for (int index = 0; index < MACsecConfig::NumSa; index++) - { - if(!source.sa[index].enable) continue; -#undef __COPY_ITEM -#define __COPY_ITEM(___name__) dest.sa[index].___name__ = source.sa[index].___name__ -#undef __COPY_ARR -#define __COPY_ARR(___name__) (void)memcpy(dest.sa[index].___name__.data(), source.sa[index].___name__, dest.sa[index].___name__.size()) - __COPY_ITEM(index); - __COPY_ARR(sak); - __COPY_ARR(hashKey); - __COPY_ARR(salt); - __COPY_ITEM(ssci); - __COPY_ITEM(an); - __COPY_ITEM(nextPn); - __COPY_ITEM(enable); - } - }; - - msg->flags.en = macsecArgs->macsec.flags.en; - copyConfig(macsecArgs->macsec.rx, msg->rx); - copyConfig(macsecArgs->macsec.tx, msg->tx); - - return msg; -} - -bool MACsecMessage::EncodeFromMessage(std::vector& bytestream, const device_eventhandler_t& report) const -{ - MACSEC_SETTINGS_W_HDR* macsecArgs; - - bytestream.resize(sizeof(MACSEC_SETTINGS_W_HDR), 0); - macsecArgs = (MACSEC_SETTINGS_W_HDR*)bytestream.data(); - - macsecArgs->version = MACSEC_SETTINGS_VERSION; - macsecArgs->len = sizeof(MACSEC_SETTINGS_W_HDR); - - const auto& copyConfig = [](const MACsecConfig& source, MACSEC_CONFIG& dest) - { - dest.flags.en = (uint8_t)source.flags.en; - for (int index = 0; index < MACsecConfig::NumRules; index++) - { - if(!source.rule[index].enable) continue; -#undef __COPY_ITEM -#define __COPY_ITEM(___name__) dest.rule[index].___name__ = (decltype(dest.rule[index].___name__))source.rule[index].___name__ -#undef __COPY_ARR -#define __COPY_ARR(___name__) (void)memcpy(dest.rule[index].___name__, source.rule[index].___name__.data(), source.rule[index].___name__.size()) - __COPY_ITEM(index); - __COPY_ARR(keyMacDa); - __COPY_ARR(maskMacDa); - __COPY_ARR(keyMacSa); - __COPY_ARR(maskMacSa); - __COPY_ITEM(keyVlanTagOuter1.vid); - __COPY_ITEM(keyVlanTagOuter1.priCfi); - __COPY_ITEM(keyMplsOuter1.mplsLabel); - __COPY_ITEM(keyMplsOuter1.exp); - __COPY_ITEM(maskVlanTagOuter1.vid); - __COPY_ITEM(maskVlanTagOuter1.priCfi); - __COPY_ITEM(maskMplsOuter1.mplsLabel); - __COPY_ITEM(maskMplsOuter1.exp); - __COPY_ITEM(keyVlanTagOuter2.vid); - __COPY_ITEM(keyVlanTagOuter2.priCfi); - __COPY_ITEM(keyMplsOuter2.mplsLabel); - __COPY_ITEM(keyMplsOuter2.exp); - __COPY_ITEM(maskVlanTagOuter2.vid); - __COPY_ITEM(maskVlanTagOuter2.priCfi); - __COPY_ITEM(maskMplsOuter2.mplsLabel); - __COPY_ITEM(maskMplsOuter2.exp); - __COPY_ITEM(keyEthertype); - __COPY_ITEM(maskEthertype); - __COPY_ITEM(keyBonusData); - __COPY_ITEM(maskBonusData); - __COPY_ITEM(keyTagMatchBitmap); - __COPY_ITEM(maskTagMatchBitmap); - __COPY_ITEM(keyPacketType); - __COPY_ITEM(maskPacketType); - __COPY_ITEM(keyInnerVlanType); - __COPY_ITEM(maskInnerVlanType); - __COPY_ITEM(keyOuterVlanType); - __COPY_ITEM(maskOuterVlanType); - __COPY_ITEM(keyNumTags); - __COPY_ITEM(maskNumTags); - __COPY_ITEM(keyExpress); - __COPY_ITEM(maskExpress); - __COPY_ITEM(isMpls); - __COPY_ITEM(enable); - } - - for (int index = 0; index < MACsecConfig::NumMaps; index++) - { - if(!source.map[index].enable) continue; -#undef __COPY_ITEM -#define __COPY_ITEM(___name__) dest.map[index].___name__ = source.map[index].___name__ - __COPY_ITEM(index); - __COPY_ITEM(secTagSci); - __COPY_ITEM(secYIndex); - __COPY_ITEM(isControlPacket); - __COPY_ITEM(scIndex); - __COPY_ITEM(auxiliaryPlcy); - __COPY_ITEM(ruleId); - __COPY_ITEM(enable); - } - - for (int index = 0; index < MACsecConfig::NumSecY; index++) - { - if(!source.secy[index].enable) continue; -#undef __COPY_ITEM -#define __COPY_ITEM(___name__) dest.secy[index].___name__ = (decltype(dest.secy[index].___name__))source.secy[index].___name__ - __COPY_ITEM(index); - __COPY_ITEM(controlledPortEnabled); - __COPY_ITEM(frameValidationType); - __COPY_ITEM(secTagIcvStripType); - __COPY_ITEM(cipher); - __COPY_ITEM(confidentialOffset); - __COPY_ITEM(icvIncludesDaSa); - __COPY_ITEM(replayProtect); - __COPY_ITEM(replayWindow); - __COPY_ITEM(protectFrames); - __COPY_ITEM(secTagOffset); - __COPY_ITEM(secTagTci); - __COPY_ITEM(mtu); - __COPY_ITEM(enable); - } - - for (int index = 0; index < MACsecConfig::NumSc; index++) - { - if(!source.sc[index].enable) continue; -#undef __COPY_ITEM -#define __COPY_ITEM(___name__) dest.sc[index].___name__ = source.sc[index].___name__ - __COPY_ITEM(index); - __COPY_ITEM(secYIndex); - __COPY_ITEM(sci); - __COPY_ITEM(saIndex0); - __COPY_ITEM(saIndex1); - __COPY_ITEM(saIndex0InUse); - __COPY_ITEM(saIndex1InUse); - __COPY_ITEM(enableAutoRekey); - __COPY_ITEM(isActiveSa1); - __COPY_ITEM(enable); - } - - for (int index = 0; index < MACsecConfig::NumSa; index++) - { - if(!source.sa[index].enable) continue; -#undef __COPY_ITEM -#define __COPY_ITEM(___name__) dest.sa[index].___name__ = source.sa[index].___name__ -#undef __COPY_ARR -#define __COPY_ARR(___name__) (void)memcpy(dest.sa[index].___name__, source.sa[index].___name__.data(), source.sa[index].___name__.size()) - __COPY_ITEM(index); - __COPY_ARR(sak); - __COPY_ARR(hashKey); - __COPY_ARR(salt); - __COPY_ITEM(ssci); - __COPY_ITEM(an); - __COPY_ITEM(nextPn); - __COPY_ITEM(enable); - } - }; - macsecArgs->macsec.flags.en = this->flags.en; - macsecArgs->macsec.flags.nvm = this->flags.nvm; - - copyConfig(this->rx, macsecArgs->macsec.rx); - copyConfig(this->tx, macsecArgs->macsec.tx); - - macsecArgs->crc32 = crc32(0, (uint8_t*)&macsecArgs->macsec, sizeof(MACSEC_SETTINGS)); - - (void)report; - - return true; -} - -} // namespace icsneo diff --git a/communication/ringbuffer.cpp b/communication/ringbuffer.cpp deleted file mode 100644 index be73f7d..0000000 --- a/communication/ringbuffer.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "icsneo/communication/ringbuffer.h" -#include - -namespace icsneo { - -RingBuffer::RingBuffer(size_t bufferSize) : readCursor(0), writeCursor(0) { - // round the buffer size to the nearest power of 2 - bufferSize = RoundUp(bufferSize); - mask = bufferSize - 1; - buf = new uint8_t[bufferSize]; -} - -RingBuffer::~RingBuffer() { - delete[] buf; - buf = nullptr; -} - -const uint8_t& RingBuffer::operator[](size_t offset) const { - return get(offset); -} - -size_t RingBuffer::size() const { - // The values in the cursors are monotonic, i.e. they only ever increment. They can be considered to be the total number of elements ever written or read - auto currentWriteCursor = writeCursor.load(std::memory_order_relaxed); - auto currentReadCursor = readCursor.load(std::memory_order_relaxed); - // Using unmasked values, writeCursor is guaranteed to be >= readCursor. If they are equal that means the buffer is empty - return currentWriteCursor - currentReadCursor; -} - -void RingBuffer::pop_front() { - pop(1); -} - -void RingBuffer::pop(size_t count) { - if (size() < count) { - throw std::runtime_error("RingBuffer: Underflow"); - } - readCursor.fetch_add(count, std::memory_order_release); -} - -const uint8_t& RingBuffer::get(size_t offset) const { - if (offset >= size()) { - throw std::runtime_error("RingBuffer: Index out of range"); - } - auto currentReadCursor = readCursor.load(std::memory_order_acquire); - return *resolve(currentReadCursor, offset); -} - -bool RingBuffer::write(const uint8_t* addr, size_t length) { - const auto freeSpace = (capacity() - size()); - if (length > freeSpace) { - return false; - } - auto currentWriteCursor = writeCursor.load(std::memory_order_relaxed); - auto spaceAtEnd = std::min(freeSpace, capacity() - (currentWriteCursor & mask)); // number of bytes from (masked) writeCursor to the end of the writable space (i.e. we reach the masked read cursor or the end of the buffer) - auto firstCopySize = std::min(spaceAtEnd, length); - (void)memcpy(resolve(currentWriteCursor, 0), addr, firstCopySize); - if (firstCopySize < length) - { - (void)memcpy(buf, &addr[firstCopySize], length - firstCopySize); - } - - writeCursor.store(currentWriteCursor + length, std::memory_order_release); - return true; -} - -bool RingBuffer::write(const std::vector& source) { - return write(source.data(), source.size()); -} - -bool RingBuffer::read(uint8_t* dest, size_t startIndex, size_t length) const { - auto currentSize = size(); - if ((startIndex >= currentSize) || ((startIndex + length) > size())) { - return false; - } - auto currentReadCursor = readCursor.load(std::memory_order_relaxed); - auto bytesAtEnd = std::min(capacity() - ((currentReadCursor + startIndex) & mask), length); - const auto bytesAtStart = (length - bytesAtEnd); - - (void)memcpy(dest, resolve(currentReadCursor, startIndex), bytesAtEnd); - if (bytesAtStart > 0) { - (void)memcpy(&dest[bytesAtEnd], buf, bytesAtStart); - } - return true; -} - -void RingBuffer::clear() { - pop(size()); -} - -} \ No newline at end of file diff --git a/communication/crc32.cpp b/core/crc32.cpp similarity index 91% rename from communication/crc32.cpp rename to core/crc32.cpp index 7e51383..e3ccb06 100644 --- a/communication/crc32.cpp +++ b/core/crc32.cpp @@ -4,8 +4,7 @@ * Created on: Jun 22, 2020 * Author: BJones */ -#include "icsneo/communication/crc32.h" -#include +#include "icsneo/core/crc32.h" static const unsigned long crc32_table[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, @@ -32,7 +31,7 @@ static const unsigned long crc32_table[256] = { 0x00000000, 0x77073096, 0xEE0E61 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; -uint32_t crc32(uint32_t crc, const unsigned char* buf, uint32_t len) +uint32_t icsneo::crc32(uint32_t crc, const unsigned char* buf, uint32_t len) { unsigned char octet; const unsigned char* p = buf; @@ -50,13 +49,13 @@ static unsigned char rev_crc32_table[256]; static void revgen(void) { - size_t k; + uint16_t k; for (k = 0; k < 256; k++) - rev_crc32_table[crc32_table[k] >> 24] = (uint8_t)k; + rev_crc32_table[crc32_table[k] >> 24] = (unsigned char)k; } -uint32_t revcrc32(uint32_t crc, const unsigned char* buf, uint32_t len) +uint32_t icsneo::revcrc32(uint32_t crc, const unsigned char* buf, uint32_t len) { unsigned char k; revgen(); diff --git a/core/macseccfg.cpp b/core/macseccfg.cpp new file mode 100644 index 0000000..40a9764 --- /dev/null +++ b/core/macseccfg.cpp @@ -0,0 +1,776 @@ +#include "icsneo/core/macseccfg.h" +#include "icsneo/api/eventmanager.h" +#include "icsneo/core/crc32.h" +#include + +namespace icsneo { + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4201) // nameless struct/union +#endif + +#pragma pack(push, 1) + +typedef struct +{ + uint16_t VID; /*!< 12 bits */ + uint8_t PRI_CFI; /*!< PRI - 3 bits, CFI - 1bit */ +} MACSEC_VLANTAG_t; +/** + * @brief Structure of MPLS + * + */ +typedef struct +{ + uint32_t MPLS_label; /*!< 20 bits */ + uint8_t exp; /*!< 3 bits */ +} MACSEC_MPLS_OUTER_t; + +#define MACSEC_SETTINGS_RULE_SIZE (88) +typedef union _MACSecRule +{ + struct + { + uint8_t index; + uint8_t key_MAC_DA[6]; /*!< MAC DA field extracted from the packet */ + uint8_t mask_MAC_DA[6]; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + uint8_t key_MAC_SA[6]; /*!< MAC SA field extracted from the packet */ + uint8_t mask_MAC_SA[6]; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + uint16_t key_Ethertype; /*!< First E-Type found in the packet that doesn't match one of the preconfigured custom tag. */ + uint16_t mask_Ethertype; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + MACSEC_VLANTAG_t key_vlantag_outer1; /*!< outermost/1st VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */ + MACSEC_MPLS_OUTER_t key_MPLS_outer1; + MACSEC_VLANTAG_t mask_vlantag_outer1; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + MACSEC_MPLS_OUTER_t mask_MPLS_outer1; + MACSEC_VLANTAG_t key_vlantag_outer2; /*!< 2nd outermost VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */ + MACSEC_MPLS_OUTER_t key_MPLS_outer2; + MACSEC_VLANTAG_t mask_vlantag_outer2; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + MACSEC_MPLS_OUTER_t mask_MPLS_outer2; + uint16_t key_bonus_data; /*!< 2 bytes of additional bonus data extracted from one of the custom tags. */ + uint16_t mask_bonus_data; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + uint8_t + key_tag_match_bitmap; /*!< 8 bits total. Maps 1 to 1 bitwise with the set of custom tags. (set bit[N]=1 if check Nth custom tag) */ + uint8_t mask_tag_match_bitmap; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + MACsecPacketType key_packet_type; /*!< Encoded Packet Type, see MACSEC_PACKET_TYPE */ + uint8_t mask_packet_type; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + uint16_t + key_inner_vlan_type; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the second outermost VLAN Tag. */ + uint16_t mask_inner_vlan_type; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + uint16_t key_outer_vlan_type; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the outermost VLAN Tag. */ + uint16_t mask_outer_vlan_type; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + uint8_t + key_num_tags; /*!< 7 bits total. Number of VLAN/custom tags or MPLS lables detected. Ingress: before SecTag; Egress: total detected. Exclude MCS header tags. i.e. Bit 2: 2 tags/labels before SecTAG...Bit 6: 6 or more tags/labels before SecTAG. */ + uint8_t mask_num_tags; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + uint8_t key_express; /*!< 1 bits. Express packet. */ + uint8_t mask_express; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + uint8_t isMPLS; + uint8_t rsvd[5]; + uint8_t enable; + }; + uint8_t byte[MACSEC_SETTINGS_RULE_SIZE]; +} MACSecRule_t; +/* MACsec Map */ +#define MACSEC_SETTINGS_MAP_SIZE (20) +typedef union _MACSecMap +{ + struct + { + uint8_t index; + uint64_t sectag_sci; /*!< Identifies the SecTAG SCI for this Flow. */ + uint8_t secYIndex; /*!< index for entry in Egress secY Policy */ + uint8_t isControlPacket; /*!< Identifies all packets matching this index lookup as control packets. */ + uint8_t scIndex; /*!< Identifies the SC for this Flow. */ + uint8_t auxiliary_plcy; /*!< Auxiliary policy bits. */ + uint8_t ruleId; /*!< Identifies the Rule for this Flow. */ + uint8_t rsvd[5]; + uint8_t enable; + }; + uint8_t byte[MACSEC_SETTINGS_MAP_SIZE]; +} MACSecMap_t; +/* MACsec SecY */ + +#define MACSEC_SETTINGS_SECY_SIZE (24) +typedef union _MACSecSecY +{ + struct + { + uint8_t index; /*!< Identifies the SecY for this Flow. */ + uint8_t controlled_port_enabled; /*!< Enable (or disable) operation of the Controlled port associated with this SecY */ + MACsecValidation validate_frames; /*!< see MACSEC_VALIDATEFRAME */ + MACsecStrip strip_sectag_icv; /*!< see MACSEC_STRIP_SECTAG_ICV */ + MACsecCipherSuite cipher; /*!< Define the cipher suite to use for this SecY */ + uint8_t confidential_offset; /*!< Define the number of bytes that are unencrypted following the SecTag. */ + uint8_t icv_includes_da_sa; /*!< When set, the outer DA/SA bytes are included in the authentication GHASH calculation */ + uint8_t replay_protect; /*!< Enables Anti-Replay protection */ + uint32_t replay_window; /*!< Unsigned value indicating the size of the anti-replay window. */ + uint8_t + protect_frames; /*!< 0 = do not encrypt or authenticate this packet; 1 = always Authenticate frame and if SecTag.TCI.E = 1 encrypt the packet as well. */ + uint8_t + sectag_offset; /*!< Define the offset in bytes from either the start of the packet or a matching Etype depending on SecTag_Insertion_Mode. */ + uint8_t sectag_tci; /*!< Tag Control Information excluding the AN field which originates from the SA Policy table */ + uint16_t mtu; /*!< Specifies the outgoing MTU for this SecY */ + uint8_t rsvd[6]; + uint8_t enable; + }; + uint8_t byte[MACSEC_SETTINGS_SECY_SIZE]; +} MACSecSecY_t; +/* MACsec SC */ +#define MACSEC_SETTINGS_SC_SIZE (24) +typedef union _MACSecSc +{ + struct + { + uint8_t index; /*!< SC index. */ + uint8_t secYIndex; /*!< SecY associated with this packet. */ + uint64_t sci; /*!< The Secure Channel Identifier. */ + uint8_t sa_index0; /*!< Define the 1st SA to use */ + uint8_t sa_index1; /*!< Define the 2nd SA to use */ + uint8_t sa_index0_in_use; /*!< Specifies whether 1st SA is in use or not. */ + uint8_t sa_index1_in_use; /*!< Specifies whether 2nd SA is in use or not. */ + uint8_t enable_auto_rekey; /*!< If enabled, then once the pn_threshold is reached, auto rekey will happen. */ + uint8_t + isActiveSA1; /*!< If set, then sa_index1 is the currently active SA index. If cleared, the sa_index0 is the currently active SA index). */ + uint8_t rsvd[7]; + uint8_t enable; + }; + uint8_t byte[MACSEC_SETTINGS_SC_SIZE]; +} MACSecSc_t; +/* MACsec SA */ +#define MACSEC_SETTINGS_SA_SIZE (80) +typedef union _MACSecSa +{ + struct + { + uint8_t index; /*!< SA index */ + uint8_t + sak[32]; /*!< 256b SAK: Define the encryption key to be used to encrypte this packet. The lower 128 bits are used for 128-bit ciphers. */ + uint8_t hashKey[16]; /*!< 128b Hash Key: Key used for authentication. */ + uint8_t salt[12]; /*!< 96b Salt value: Salt value used in XPN ciphers. */ + uint32_t ssci; /*!< 32b SSCI value: Short Secure Channel Identifier, used in XPN ciphers. */ + uint8_t AN; /*!< 2b SecTag Association Number (AN) */ + uint64_t nextPN; /*!< 64b next_pn value: Next packet number to insert into outgoing packet on a particular SA. */ + uint8_t rsvd[5]; + uint8_t enable; + }; + uint8_t byte[MACSEC_SETTINGS_SA_SIZE]; +} MACSecSa_t; +/* MACsec Flags */ +#define MACSEC_SETTINGS_FLAGS_SIZE (4) +typedef union _MACSecFlags +{ + struct + { + uint32_t en : 1; // '1' = enable; '0' = disable + uint32_t reserved : 31; + }; + uint32_t flags_32b; +} MACSecFlags_t; +/* MACSec Settings for 1 port/phy */ +#define MACSEC_NUM_FLAGS_PER_CONFIG (1) +#define MACSEC_NUM_RULES_PER_CONFIG (2) +#define MACSEC_NUM_MAPS_PER_CONFIG (2) +#define MACSEC_NUM_SECY_PER_CONFIG (2) +#define MACSEC_NUM_SC_PER_CONFIG (2) +#define MACSEC_NUM_SA_PER_CONFIG (4) +typedef struct MACSEC_CONFIG_t +{ + MACSecFlags_t flags; + MACSecRule_t rule[MACSEC_NUM_RULES_PER_CONFIG]; + MACSecMap_t map[MACSEC_NUM_MAPS_PER_CONFIG]; + MACSecSecY_t secy[MACSEC_NUM_SECY_PER_CONFIG]; + MACSecSc_t sc[MACSEC_NUM_SC_PER_CONFIG]; + MACSecSa_t sa[MACSEC_NUM_SA_PER_CONFIG]; +} MACSEC_CONFIG; +typedef union _MACSecGlobalFlags +{ + struct + { + uint32_t en : 1; // '1' = enable; '0' = disable + uint32_t nvm : 1; // store macsec config in non-volatile memory + uint32_t reserved : 30; + }; + uint32_t flags_32b; +} MACSecGlobalFlags_t; +#define MACSEC_SETTINGS_SIZE (2040) // leave space for expansion and keep nicely aligned for flashing +typedef union _MACSEC_SETTINGS +{ + struct + { + MACSecGlobalFlags_t flags; + MACSEC_CONFIG rx; + MACSEC_CONFIG tx; + }; + uint8_t byte[MACSEC_SETTINGS_SIZE]; +} MACSEC_SETTINGS; + +#define MACSEC_SETTINGS_VERSION 1 +typedef struct MACSEC_SETTINGS_W_HDR +{ + uint16_t version; + uint16_t len; + uint32_t crc32; + MACSEC_SETTINGS macsec; +} MACSEC_SETTINGS_W_HDR; +#define MACSEC_SETTINGS_W_HDR_SIZE (2048) + +#pragma pack(pop) + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +static void ReportEvent(APIEvent::Type event, APIEvent::Severity severity) { + auto& em = EventManager::GetInstance(); + em.add(APIEvent(event, severity)); +} + +MACsecConfig::MACsecConfig(const DeviceType& deviceType) : type(deviceType) { + switch(deviceType.getDeviceType()) { + case icsneo::DeviceType::Enum::RADMoon2: + case icsneo::DeviceType::Enum::RADMoon3: + case icsneo::DeviceType::Enum::RADEpsilon: + maxSecY = 2; + maxRule = 2; + maxSa = 4; + binIndex = 0; + break; + default: + maxSecY = 0; + maxSa = 0; + maxRule = 0; + binIndex = 0; + ReportEvent(APIEvent::Type::MACsecNotSupported, APIEvent::Severity::Error); + return; + } +} + +int MACsecConfig::addRxSecY(const MACsecRxSecY& secY, uint8_t saIndex) { + if(rxSecY.size() >= maxSecY) { + ReportEvent(APIEvent::Type::MACsecSecYLimit, APIEvent::Severity::Error); + return -1; + } + + if(saIndex >= rxSa.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error); + return -1; + } + + int ret = static_cast(rxSecY.size()); + rxSecY.emplace_back(secY); + rxSecYSaIndices.emplace_back(saIndex, saIndex + 1); + rxSecYRekey.emplace_back(false); + rxRuleIndices.emplace_back(0); + + return ret; +} + +int MACsecConfig::addTxSecY(const MACsecTxSecY& secY, uint8_t saIndex) { + if(txSecY.size() >= maxSecY) { + ReportEvent(APIEvent::Type::MACsecSecYLimit, APIEvent::Severity::Error); + return -1; + } + + if(saIndex >= txSa.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error); + return -1; + } + + int ret = static_cast(txSecY.size()); + txSecY.emplace_back(secY); + txSecYSaIndices.emplace_back(saIndex, saIndex + 1); + txSecYRekey.emplace_back(false); + + return ret; +} + +int MACsecConfig::addRxSa(const MACsecRxSa& sa) { + if(rxSa.size() >= maxSa) { + ReportEvent(APIEvent::Type::MACsecSaLimit, APIEvent::Severity::Error); + return -1; + } + + int ret = static_cast(rxSa.size()); + rxSa.emplace_back(sa); + return ret; +} + +int MACsecConfig::addTxSa(const MACsecTxSa& sa) { + if(txSa.size() >= maxSa) { + ReportEvent(APIEvent::Type::MACsecSaLimit, APIEvent::Severity::Error); + return -1; + } + + int ret = static_cast(txSa.size()); + txSa.emplace_back(sa); + return ret; +} + +int MACsecConfig::addRxRule(const MACsecRxRule& rule, uint8_t secYIndex) { + if(rxRule.size() >= maxRule) { + ReportEvent(APIEvent::Type::MACsecSaLimit, APIEvent::Severity::Error); + return -1; + } + + if(maxSecY >= rxRule.size()) { + ReportEvent(APIEvent::Type::MACsecSecYLimit, APIEvent::Severity::Error); + return -1; + } + + int ret = static_cast(rxRule.size()); + rxRuleIndices[secYIndex] = static_cast(rxRule.size()); + rxRule.emplace_back(rule); + return ret; +} + +MACsecRxRule& MACsecConfig::getRxRule(uint8_t ruleIndex) { + return rxRule[ruleIndex]; +} + +const MACsecRxRule& MACsecConfig::getRxRule(uint8_t ruleIndex) const { + return rxRule[ruleIndex]; +} + +MACsecRxSecY& MACsecConfig::getRxSecY(uint8_t secYIndex) { + return rxSecY[secYIndex]; +} + +const MACsecRxSecY& MACsecConfig::getRxSecY(uint8_t secYIndex) const { + return rxSecY[secYIndex]; +} + +MACsecTxSecY& MACsecConfig::getTxSecY(uint8_t secYIndex) { + return txSecY[secYIndex]; +} + +const MACsecTxSecY& MACsecConfig::getTxSecY(uint8_t secYIndex) const { + return txSecY[secYIndex]; +} + +MACsecRxSa& MACsecConfig::getRxSa(uint8_t saIndex) { + return rxSa[saIndex]; +} + +const MACsecRxSa& MACsecConfig::getRxSa(uint8_t saIndex) const { + return rxSa[saIndex]; +} + +MACsecTxSa& MACsecConfig::getTxSa(uint8_t saIndex) { + return txSa[saIndex]; +} + +const MACsecTxSa& MACsecConfig::getTxSa(uint8_t saIndex) const { + return txSa[saIndex]; +} + +bool MACsecConfig::setTxSaIndex(uint8_t secYIndex, uint8_t saIndex) { + if(secYIndex >= txSecY.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::Error); + return false; + } + if(saIndex >= txSa.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error); + return false; + } + + txSecYSaIndices[secYIndex].first = saIndex; + return true; +} + +bool MACsecConfig::enableTxRekey(uint8_t secYIndex, uint8_t rekeySaIndex) { + if(secYIndex >= txSecY.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::Error); + return false; + } + if(rekeySaIndex >= txSa.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error); + return false; + } + + txSecYSaIndices[secYIndex].second = rekeySaIndex; + txSecYRekey[secYIndex] = true; + return true; +} + +bool MACsecConfig::setTxSaRekeyIndex(uint8_t secYIndex, uint8_t saIndex) { + if(secYIndex >= txSecY.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::Error); + return false; + } + if(saIndex >= txSa.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error); + return false; + } + + txSecYSaIndices[secYIndex].second = saIndex; + return true; +} + +void MACsecConfig::disableTxRekey(uint8_t secYIndex) { + if(secYIndex >= txSecY.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::EventWarning); + return; + } + txSecYRekey[secYIndex] = false; +} + +bool MACsecConfig::setRxSaIndex(uint8_t secYIndex, uint8_t saIndex) { + if(secYIndex >= rxSecY.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::Error); + return false; + } + if(saIndex >= rxSa.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error); + return false; + } + + rxSecYSaIndices[secYIndex].first = saIndex; + return true; +} + +bool MACsecConfig::enableRxRekey(uint8_t secYIndex, uint8_t rekeySaIndex) { + if(secYIndex >= rxSecY.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::Error); + return false; + } + if(rekeySaIndex >= rxSa.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error); + return false; + } + + rxSecYSaIndices[secYIndex].second = rekeySaIndex; + rxSecYRekey[secYIndex] = true; + return true; +} + +bool MACsecConfig::setRxSaRekeyIndex(uint8_t secYIndex, uint8_t saIndex) { + if(secYIndex >= rxSecY.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::Error); + return false; + } + if(saIndex >= rxSa.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error); + return false; + } + + rxSecYSaIndices[secYIndex].second = saIndex; + return true; +} + +void MACsecConfig::disableRxRekey(uint8_t secYIndex) { + if(secYIndex >= rxSecY.size()) { + ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::EventWarning); + return; + } + rxSecYRekey[secYIndex] = false; +} + +void MACsecConfig::setRxEnable(bool newRxEnable) { + enableRx = newRxEnable; +} + +void MACsecConfig::setTxEnable(bool newTxEnable) { + enableTx = newTxEnable; +} + +void MACsecConfig::setStorage(bool temporary) { + nvm = !temporary; +} + + +void MACsecConfig::clear() { + // Set everything back to default, except device maximums + rxSecY.clear(); + txSecY.clear(); + rxSa.clear(); + txSa.clear(); + rxRule.clear(); + rxSecYRekey.clear(); + txSecYRekey.clear(); + rxSecYSaIndices.clear(); + txSecYSaIndices.clear(); + rxRuleIndices.clear(); + enableRx = false; + enableTx = false; + nvm = false; +} + +MACsecConfig::operator bool() const { + return (maxSa != 0) || (maxSecY != 0) || (maxRule != 0); +} + +uint16_t MACsecConfig::getBinIndex() const { + return binIndex; +} + +DeviceType MACsecConfig::getType() const { + return type; +} + +uint8_t MACsecConfig::getMaxNumRule() const { + return maxRule; +} + +uint8_t MACsecConfig::getMaxNumSecY() const { + return maxSecY; +} + +uint8_t MACsecConfig::getMaxNumSa() const { + return maxSa; +} + + +static uint8_t TCItoInt(const MACsecTci& tci) { + uint8_t res = 0; + res |= tci.c ? 0x01u : 0; + res |= tci.e ? 0x02u : 0; + res |= tci.scb ? 0x04u : 0; + res |= tci.sc ? 0x08u : 0; + res |= tci.es ? 0x10u : 0; + return res; +} + +static void SetHardwareTxSecY( + MACSEC_SETTINGS_W_HDR* hwSettings, + const MACsecTxSecY& secY, + bool rekeyEnabled, + const std::pair& saIndices, + uint8_t index +) { + + MACSecSecY_t* hwSecY = &hwSettings->macsec.tx.secy[index]; + MACSecSc_t* hwSc = &hwSettings->macsec.tx.sc[index]; + MACSecMap_t* hwMap = &hwSettings->macsec.tx.map[index]; + + hwSecY->index = index; + hwSecY->enable = true; + hwSecY->controlled_port_enabled = secY.enableControlPort ? 0x1u : 0x0u; + hwSecY->cipher = secY.cipher; + hwSecY->confidential_offset = secY.confidentialityOffset; + hwSecY->icv_includes_da_sa = secY.icvIncludesDaSa ? 0x1u : 0x0u; + hwSecY->mtu = secY.mtu; + hwSecY->sectag_tci = TCItoInt(secY.tci); + hwSecY->sectag_offset = secY.secTagOffset; + hwSecY->protect_frames = secY.protectFrames; + + hwSc->index = index; + hwSc->enable = true; + hwSc->secYIndex = index; + hwSc->enable_auto_rekey = rekeyEnabled ? 0x1u : 0x0u; + hwSc->sa_index0 = saIndices.first; + hwSc->sa_index1 = saIndices.second; + hwSc->sa_index0_in_use = true; + hwSc->sa_index1_in_use = rekeyEnabled ? true : false; + hwSc->isActiveSA1 = rekeyEnabled ? true : false; + hwSc->sci = secY.sci; + + hwMap->index = index; + hwMap->enable = true; + hwMap->auxiliary_plcy = secY.auxiliaryPolicy; + hwMap->secYIndex = index; + hwMap->isControlPacket = secY.isControlPacket ? 0x1u : 0x0u; + hwMap->scIndex = index; + hwMap->sectag_sci = secY.sci; + +} + +static void SetHardwareRxSecY( + MACSEC_SETTINGS_W_HDR* hwSettings, + const MACsecRxSecY& secY, + bool rekeyEnabled, + uint8_t ruleIndex, + const std::pair& saIndices, + uint8_t index +) { + + MACSecSecY_t* hwSecY = &hwSettings->macsec.rx.secy[index]; + MACSecSc_t* hwSc = &hwSettings->macsec.rx.sc[index]; + MACSecMap_t* hwMap = &hwSettings->macsec.rx.map[index]; + + hwSecY->index = index; + hwSecY->enable = 0x1u; + hwSecY->controlled_port_enabled = secY.enableControlPort ? 0x1u : 0x0u; + hwSecY->cipher = secY.cipher; + hwSecY->confidential_offset = secY.confidentialityOffset; + hwSecY->icv_includes_da_sa = secY.icvIncludesDaSa ? 0x1u : 0x0u; + hwSecY->replay_protect = secY.replayProtect ? 0x1u : 0x0u; + hwSecY->replay_window = secY.replayWindow; + hwSecY->validate_frames = secY.frameValidation; + hwSecY->strip_sectag_icv = secY.frameStrip; + hwSecY->sectag_offset = 12; + + hwSc->index = index; + hwSc->enable = 0x1u; + hwSc->secYIndex = index; + hwSc->enable_auto_rekey = rekeyEnabled ? 0x1u : 0x0u; + hwSc->sa_index0 = saIndices.first; + hwSc->sa_index1 = saIndices.second; + hwSc->sa_index0_in_use = 0x1u; + hwSc->sa_index1_in_use = rekeyEnabled ? 0x1u : 0x0u; + hwSc->isActiveSA1 = rekeyEnabled ? 0x1u : 0x0u; + hwSc->sci = secY.sci; + + hwMap->index = index; + hwMap->enable = 0x1u; + hwMap->secYIndex = index; + hwMap->ruleId = ruleIndex; + hwMap->isControlPacket = secY.isControlPacket ? 0x1u : 0x0u; + hwMap->scIndex = index; + hwMap->sectag_sci = secY.sci; + +} + +static void SetHardwareTxSa(MACSEC_SETTINGS_W_HDR* hwSettings, const MACsecTxSa& sa, uint8_t index) { + MACSecSa_t* hwSa = &hwSettings->macsec.tx.sa[index]; + + hwSa->index = index; + hwSa->enable = 0x1u; + memcpy(hwSa->sak, sa.sak.data(), 32); + memcpy(hwSa->hashKey, sa.hashKey.data(), 16); + memcpy(hwSa->salt, sa.salt.data(), 12); + hwSa->ssci = sa.ssci; + hwSa->AN = sa.an; + hwSa->nextPN = sa.nextPn; + +} + +static void SetHardwareRxSa(MACSEC_SETTINGS_W_HDR* hwSettings, const MACsecRxSa& sa, uint8_t index) { + MACSecSa_t* hwSa = &hwSettings->macsec.rx.sa[index]; + + hwSa->index = index; + hwSa->enable = 0x1u; + memcpy(hwSa->sak, sa.sak.data(), 32); + memcpy(hwSa->hashKey, sa.hashKey.data(), 16); + memcpy(hwSa->salt, sa.salt.data(), 12); + hwSa->ssci = sa.ssci; + hwSa->nextPN = sa.nextPn; + +} + +static void SetHardwareRxRule(MACSecRule_t* hwRule, const MACsecRxRule& rule, uint8_t index) { + + hwRule->enable = 0x1u; + hwRule->index = index; + memcpy(hwRule->key_MAC_DA, rule.keyMacDa.data(), 6); + memcpy(hwRule->mask_MAC_DA, rule.maskMacDa.data(), 6); + memcpy(hwRule->key_MAC_SA, rule.keyMacSa.data(), 6); + memcpy(hwRule->mask_MAC_SA, rule.maskMacSa.data(), 6); + hwRule->key_Ethertype = rule.keyEthertype; + hwRule->mask_Ethertype = rule.maskEthertype; + hwRule->key_vlantag_outer1.PRI_CFI = rule.keyVlanTagOuter1.priCfi; + hwRule->key_vlantag_outer1.VID = rule.keyVlanTagOuter1.vid; + hwRule->key_MPLS_outer1.exp = rule.keyMplsOuter1.exp; + hwRule->key_MPLS_outer1.MPLS_label = rule.keyMplsOuter1.mplsLabel; + hwRule->mask_vlantag_outer1.PRI_CFI = rule.maskVlanTagOuter1.priCfi; + hwRule->mask_vlantag_outer1.VID = rule.maskVlanTagOuter1.vid; + hwRule->mask_MPLS_outer1.exp = rule.maskMplsOuter1.exp; + hwRule->mask_MPLS_outer1.MPLS_label = rule.maskMplsOuter1.mplsLabel; + hwRule->key_vlantag_outer2.PRI_CFI = rule.keyVlanTagOuter2.priCfi; + hwRule->key_vlantag_outer2.VID = rule.keyVlanTagOuter2.vid; + hwRule->key_MPLS_outer2.exp = rule.keyMplsOuter2.exp; + hwRule->key_MPLS_outer2.MPLS_label = rule.keyMplsOuter2.mplsLabel; + hwRule->mask_vlantag_outer2.PRI_CFI = rule.maskVlanTagOuter2.priCfi; + hwRule->mask_vlantag_outer2.VID = rule.maskVlanTagOuter2.vid; + hwRule->mask_MPLS_outer2.exp = rule.maskMplsOuter2.exp; + hwRule->mask_MPLS_outer2.MPLS_label = rule.maskMplsOuter2.mplsLabel; + hwRule->key_bonus_data = rule.keyBonusData; + hwRule->mask_bonus_data = rule.maskBonusData; + hwRule->key_tag_match_bitmap = rule.keyTagMatchBitmap; + hwRule->mask_tag_match_bitmap = rule.maskTagMatchBitmap; + hwRule->key_packet_type = rule.keyPacketType; + hwRule->mask_packet_type = rule.maskPacketType; + hwRule->key_inner_vlan_type = rule.keyInnerVlanType; + hwRule->mask_inner_vlan_type = rule.maskInnerVlanType; + hwRule->key_outer_vlan_type = rule.keyOuterVlanType; + hwRule->mask_outer_vlan_type = rule.maskOuterVlanType; + hwRule->key_num_tags = rule.keyNumTags; + hwRule->mask_num_tags = rule.maskNumTags; + hwRule->key_express = rule.keyExpress ? 0x1u : 0x0u; + hwRule->mask_express = rule.maskExpress ? 0x1u : 0x0u; + hwRule->isMPLS = rule.isMpls ? 0x1u : 0x0u; + +} + +std::vector MACsecConfig::serialize() const { + std::vector res(sizeof(MACSEC_SETTINGS_W_HDR), 0); + MACSEC_SETTINGS_W_HDR* hwSettings = (MACSEC_SETTINGS_W_HDR*)(res.data()); + + for(uint8_t i = 0; i < maxSecY; i++) { + if(i < rxSecY.size()) { + SetHardwareRxSecY( + hwSettings, + rxSecY[i], + rxSecYRekey[i], + rxRuleIndices[i], + rxSecYSaIndices[i], + i + ); + } else { + hwSettings->macsec.rx.secy[i].enable = false; + hwSettings->macsec.rx.map[i].enable = false; + hwSettings->macsec.rx.sc[i].enable = false; + } + + if(i < txSecY.size()) { + SetHardwareTxSecY( + hwSettings, + txSecY[i], + txSecYRekey[i], + txSecYSaIndices[i], + i + ); + } else { + hwSettings->macsec.tx.secy[i].enable = false; + hwSettings->macsec.tx.map[i].enable = false; + hwSettings->macsec.tx.sc[i].enable = false; + } + } + + for(uint8_t i = 0; i < maxSa; i++) { + if(i < rxSa.size()) { + SetHardwareRxSa(hwSettings, rxSa[i], i); + } else { + hwSettings->macsec.rx.sa[i].enable = false; + } + + if(i < txSa.size()) { + SetHardwareTxSa(hwSettings, txSa[i], i); + } else { + hwSettings->macsec.tx.sa[i].enable = false; + } + } + + if(rxRule.size() == 0) { + MACsecRxRule defaultRule; + MACSecRule_t* hwRxRule = &hwSettings->macsec.rx.rule[0]; + MACSecRule_t* hwTxRule = &hwSettings->macsec.tx.rule[0]; + SetHardwareRxRule(hwRxRule, defaultRule, 0); + SetHardwareRxRule(hwTxRule, defaultRule, 0); + //hwSettings->macsec.tx.rule[0].enable = false; + for(uint8_t i = 1; i < maxRule; i++) { + hwSettings->macsec.rx.rule[i].enable = false; + hwSettings->macsec.tx.rule[i].enable = false; + } + } else { + for(uint8_t i = 0; i < maxRule; i++) { + if(i < rxRule.size()) { + auto* hwRxRule = &hwSettings->macsec.rx.rule[i]; + SetHardwareRxRule(hwRxRule, rxRule[i], i); + } else { + hwSettings->macsec.rx.rule[i].enable = false; + hwSettings->macsec.tx.rule[i].enable = false; + } + } + } + + hwSettings->len = sizeof(MACSEC_SETTINGS_W_HDR); + hwSettings->version = MACSEC_SETTINGS_VERSION; + hwSettings->macsec.flags.en = (enableRx || enableTx) ? 1u : 0u; + hwSettings->macsec.flags.nvm = nvm ? 1u : 0u; + hwSettings->macsec.rx.flags.en = enableRx ? 1u : 0u; + hwSettings->macsec.tx.flags.en = enableTx ? 1u : 0u; + hwSettings->crc32 = crc32(0, (uint8_t*)&hwSettings->macsec, sizeof(MACSEC_SETTINGS)); + + return res; +} +} diff --git a/core/ringbuffer.cpp b/core/ringbuffer.cpp new file mode 100644 index 0000000..d4dc769 --- /dev/null +++ b/core/ringbuffer.cpp @@ -0,0 +1,91 @@ +#include "icsneo/core/ringbuffer.h" +#include + +namespace icsneo { + +RingBuffer::RingBuffer(size_t bufferSize) : readCursor(0), writeCursor(0) { + // round the buffer size to the nearest power of 2 + bufferSize = RoundUp(bufferSize); + mask = bufferSize - 1; + buf = new uint8_t[bufferSize]; +} + +RingBuffer::~RingBuffer() { + delete[] buf; + buf = nullptr; +} + +const uint8_t& RingBuffer::operator[](size_t offset) const { + return get(offset); +} + +size_t RingBuffer::size() const { + // The values in the cursors are monotonic, i.e. they only ever increment. They can be considered to be the total number of elements ever written or read + auto currentWriteCursor = writeCursor.load(std::memory_order_relaxed); + auto currentReadCursor = readCursor.load(std::memory_order_relaxed); + // Using unmasked values, writeCursor is guaranteed to be >= readCursor. If they are equal that means the buffer is empty + return currentWriteCursor - currentReadCursor; +} + +void RingBuffer::pop_front() { + pop(1); +} + +void RingBuffer::pop(size_t count) { + if (size() < count) { + throw std::runtime_error("RingBuffer: Underflow"); + } + readCursor.fetch_add(count, std::memory_order_release); +} + +const uint8_t& RingBuffer::get(size_t offset) const { + if (offset >= size()) { + throw std::runtime_error("RingBuffer: Index out of range"); + } + auto currentReadCursor = readCursor.load(std::memory_order_acquire); + return *resolve(currentReadCursor, offset); +} + +bool RingBuffer::write(const uint8_t* addr, size_t length) { + const auto freeSpace = (capacity() - size()); + if (length > freeSpace) { + return false; + } + auto currentWriteCursor = writeCursor.load(std::memory_order_relaxed); + auto spaceAtEnd = std::min(freeSpace, capacity() - (currentWriteCursor & mask)); // number of bytes from (masked) writeCursor to the end of the writable space (i.e. we reach the masked read cursor or the end of the buffer) + auto firstCopySize = std::min(spaceAtEnd, length); + (void)memcpy(resolve(currentWriteCursor, 0), addr, firstCopySize); + if (firstCopySize < length) + { + (void)memcpy(buf, &addr[firstCopySize], length - firstCopySize); + } + + writeCursor.store(currentWriteCursor + length, std::memory_order_release); + return true; +} + +bool RingBuffer::write(const std::vector& source) { + return write(source.data(), source.size()); +} + +bool RingBuffer::read(uint8_t* dest, size_t startIndex, size_t length) const { + auto currentSize = size(); + if ((startIndex >= currentSize) || ((startIndex + length) > size())) { + return false; + } + auto currentReadCursor = readCursor.load(std::memory_order_relaxed); + auto bytesAtEnd = std::min(capacity() - ((currentReadCursor + startIndex) & mask), length); + const auto bytesAtStart = (length - bytesAtEnd); + + (void)memcpy(dest, resolve(currentReadCursor, startIndex), bytesAtEnd); + if (bytesAtStart > 0) { + (void)memcpy(&dest[bytesAtEnd], buf, bytesAtStart); + } + return true; +} + +void RingBuffer::clear() { + pop(size()); +} + +} \ No newline at end of file diff --git a/device/device.cpp b/device/device.cpp index 17ea651..16501f3 100644 --- a/device/device.cpp +++ b/device/device.cpp @@ -3745,13 +3745,19 @@ std::optional Device::getGPTPStatus(std::chrono::milliseconds timeou return *retMsg; } -bool Device::writeMACsecConfig(const MACsecMessage& message, uint16_t binaryIndex) -{ - std::vector raw; +bool Device::writeMACsecConfig(const MACsecConfig& cfg) { + if(!cfg) { + report(APIEvent::Type::MACsecNotSupported, APIEvent::Severity::Error); + return false; + } - message.EncodeFromMessage(raw, report); + if(getType() != cfg.getType()) { + report(APIEvent::Type::MACsecConfigMismatch, APIEvent::Severity::Error); + return false; + } - return writeBinaryFile(raw, binaryIndex); + std::vector raw = cfg.serialize(); + return writeBinaryFile(raw, cfg.getBinIndex()); } bool Device::enableNetworkCommunication(bool enable, uint32_t timeout) { diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e889b95..2403265 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -10,6 +10,7 @@ option(LIBICSNEO_BUILD_CPP_COREMINI_EXAMPLE "Build the Coremini example." ON) option(LIBICSNEO_BUILD_CPP_MDIO_EXAMPLE "Build the MDIO example." ON) option(LIBICSNEO_BUILD_CPP_VSA_EXAMPLE "Build the VSA example." ON) option(LIBICSNEO_BUILD_CPP_APP_ERROR_EXAMPLE "Build the app error example." ON) +option(LIBICSNEO_BUILD_CPP_APP_ERROR_EXAMPLE "Build the macsec example" ON) option(LIBICSNEO_BUILD_CPP_FLEXRAY_EXAMPLE "Build the FlexRay example." ON) option(LIBICSNEO_BUILD_CPP_SPI_EXAMPLE "Build the SPI example." ON) option(LIBICSNEO_BUILD_CPP_MUTEX_EXAMPLE "Build the NetworkMutex example." ON) @@ -64,6 +65,13 @@ if(LIBICSNEO_BUILD_CPP_APP_ERROR_EXAMPLE) add_subdirectory(cpp/apperror) endif() +if(LIBICSNEO_BUILD_CPP_APP_ERROR_EXAMPLE) + add_subdirectory(cpp/macsec) +endif() + +# if(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE) +# add_subdirectory(csharp) +# endif() if(LIBICSNEO_BUILD_CPP_FLEXRAY_EXAMPLE) add_subdirectory(cpp/flexray) endif() diff --git a/examples/cpp/coremini/src/coremini.cpp b/examples/cpp/coremini/src/coremini.cpp index 193216e..53f3fc4 100644 --- a/examples/cpp/coremini/src/coremini.cpp +++ b/examples/cpp/coremini/src/coremini.cpp @@ -44,12 +44,6 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } - if(!device->goOnline()) { - std::cout << "Failed to go online." << std::endl; - std::cout << icsneo::GetLastError() << std::endl; - return EXIT_FAILURE; - } - std::string memTypeString = arguments[3]; icsneo::Disk::MemoryType type; @@ -75,7 +69,6 @@ int main(int argc, char** argv) { std::cout << icsneo::GetLastError() << std::endl; } - device->goOffline(); device->close(); return 0; } \ No newline at end of file diff --git a/examples/cpp/macsec/CMakeLists.txt b/examples/cpp/macsec/CMakeLists.txt new file mode 100644 index 0000000..03b3e3d --- /dev/null +++ b/examples/cpp/macsec/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(libicsneocpp-macsec src/macsec.cpp) +target_link_libraries(libicsneocpp-macsec icsneocpp) \ No newline at end of file diff --git a/examples/cpp/macsec/src/macsec.cpp b/examples/cpp/macsec/src/macsec.cpp new file mode 100644 index 0000000..0e93023 --- /dev/null +++ b/examples/cpp/macsec/src/macsec.cpp @@ -0,0 +1,86 @@ +#include +#include "icsneo/icsneocpp.h" + +int main(int, char**) { + // Hash calculated by encrypting 16 zero bytes with AES ecb using the SAK + // The device uses this hash to authenticate the key + std::array sak = {0x01u, 0x02u, 0x03u, 0x04u, 0x01u, 0x02u, 0x03u, 0x04u, 0x01u, 0x02u, 0x03u, 0x04u, 0x01u, 0x02u, 0x03u, 0x04u}; + std::array hash = {0xDAu, 0x80u, 0xF2u, 0x20u, 0x8Bu, 0x59u, 0x88u, 0x12u, 0x94u, 0x4Eu, 0xEA, 0xB0, 0x52u, 0xDEu, 0xDEu, 0x66u}; + + auto devices = icsneo::FindAllDevices(); + + if(devices.size() == 0) { + std::cout << "No device found" << std::endl; + return -1; + } + + std::shared_ptr device = devices[0]; + + if(!device->open()) { + std::cout << "Failed to open device" << std::endl; + std::cout << icsneo::GetLastError() << std::endl; + return -1; + } + + icsneo::MACsecConfig cfg(device->getType()); + + if(!cfg) { + std::cout << "Failed to initialize config" << std::endl; + std::cout << icsneo::GetLastError() << std::endl; + return -1; + } + + // Fill out secure association information for each rx/tx port + icsneo::MACsecRxSa rxSa; + std::copy(sak.begin(), sak.end(), rxSa.sak.begin()); + std::copy(hash.begin(), hash.end(), rxSa.hashKey.begin()); + + icsneo::MACsecTxSa txSa; + std::copy(sak.begin(), sak.end(), txSa.sak.begin()); + std::copy(hash.begin(), hash.end(), txSa.hashKey.begin()); + + // Add the secure associations to the config + int rxSaHandle = cfg.addRxSa(rxSa); + int txSaHandle = cfg.addTxSa(txSa); + + // Verify secure associations were configured properly + if(rxSaHandle < 0 || txSaHandle < 0) { + std::cout << "Failed to verify secure associations" << std::endl; + std::cout << icsneo::GetLastError() << std::endl; + return -1; + } + + // Fill out security entity information for each rx/tx port + icsneo::MACsecRxSecY rxSecY; + rxSecY.cipher = icsneo::MACsecCipherSuite::GcmAes128; + rxSecY.sci = 0x1122334455660001ull; + + icsneo::MACsecTxSecY txSecY; + txSecY.cipher = icsneo::MACsecCipherSuite::GcmAes128; + txSecY.sci = 0x1122334455660001ull; + + // Add security entites to the config + int rxSecYHandle = cfg.addRxSecY(rxSecY, static_cast(rxSaHandle)); + int txSecYHandle = cfg.addTxSecY(txSecY, static_cast(txSaHandle)); + + // Verify security entities were configured properly + if(rxSecYHandle < 0 || txSecYHandle < 0) { + std::cout << "Failed to verify security entities" << std::endl; + std::cout << icsneo::GetLastError() << std::endl; + return -1; + } + + // Enable communication directions + cfg.setRxEnable(true); + cfg.setTxEnable(true); + + // Write config to the device + if(!device->writeMACsecConfig(cfg)) { + std::cout << "Failed to write MACsec config" << std::endl; + std::cout << icsneo::GetLastError() << std::endl; + return -1; + } + + device->close(); + return 0; +} \ No newline at end of file diff --git a/include/icsneo/api/event.h b/include/icsneo/api/event.h index 7b45c87..29a2839 100644 --- a/include/icsneo/api/event.h +++ b/include/icsneo/api/event.h @@ -54,7 +54,16 @@ public: FixedPointOverflow = 0x1018, FixedPointPrecision = 0x1019, SyscallError = 0x1020, // check errno/GetLastError() for details - + MACsecSecYLimit = 0x1021, + MACsecSaLimit = 0x1022, + MACsecRuleLimit = 0x1023, + MACsecInvalidSecYIndex = 0x1024, + MACsecInvalidSaIndex = 0x1025, + MACsecInvalidRuleIndex = 0x1026, + MACsecRekeyNotEnabled = 0x1027, + MACsecNotSupported = 0x1028, + MACsecConfigMismatch = 0x1029, + // Device Events PollingMessageOverflow = 0x2000, NoSerialNumber = 0x2001, // api diff --git a/include/icsneo/communication/driver.h b/include/icsneo/communication/driver.h index 8fcebc3..3b4e4cb 100644 --- a/include/icsneo/communication/driver.h +++ b/include/icsneo/communication/driver.h @@ -11,7 +11,7 @@ #include #include "icsneo/api/eventmanager.h" #include "icsneo/third-party/concurrentqueue/blockingconcurrentqueue.h" -#include "icsneo/communication/ringbuffer.h" +#include "icsneo/core/ringbuffer.h" #include "icsneo/device/founddevice.h" namespace icsneo { diff --git a/include/icsneo/communication/message/macsecmessage.h b/include/icsneo/communication/message/macsecmessage.h deleted file mode 100644 index 2255500..0000000 --- a/include/icsneo/communication/message/macsecmessage.h +++ /dev/null @@ -1,200 +0,0 @@ -#ifndef __MACSECMESSAGE_H__ -#define __MACSECMESSAGE_H__ - -#ifdef __cplusplus - -#include "icsneo/communication/message/message.h" -#include "icsneo/communication/packet.h" -#include "icsneo/api/eventmanager.h" -#include -#include -#include -#include - -namespace icsneo { - -struct MACsecVLANTag -{ - uint16_t vid; /*!< 12 bits */ - uint8_t priCfi; /*!< PRI - 3 bits, CFI - 1bit */ -}; - -struct MACsecMPLSOuter -{ - uint32_t mplsLabel; /*!< 20 bits */ - uint8_t exp; /*!< 3 bits */ -}; - -enum class MACsecPacketType : uint8_t -{ - NoVLANOrMPLS = 0, - SingleVLAN = 1, - DualVLAN = 2, - MPLS = 3, - SingleVLANFollowedByMPLS = 4, - DualVLANFollowedByMPLS = 5, - Unsupported = 6, -}; - -struct MACsecRule -{ - uint8_t index; - std::array keyMacDa; /*!< MAC DA field extracted from the packet */ - std::array maskMacDa; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - std::array keyMacSa; /*!< MAC SA field extracted from the packet */ - std::array maskMacSa; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - uint16_t keyEthertype; /*!< First E-Type found in the packet that doesn't match one of the preconfigured custom tag. */ - uint16_t maskEthertype; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - MACsecVLANTag keyVlanTagOuter1; /*!< outermost/1st VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */ - MACsecMPLSOuter keyMplsOuter1; - MACsecVLANTag maskVlanTagOuter1; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - MACsecMPLSOuter maskMplsOuter1; - MACsecVLANTag keyVlanTagOuter2; /*!< 2nd outermost VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */ - MACsecMPLSOuter keyMplsOuter2; - MACsecVLANTag maskVlanTagOuter2; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - MACsecMPLSOuter maskMplsOuter2; - uint16_t keyBonusData; /*!< 2 bytes of additional bonus data extracted from one of the custom tags. */ - uint16_t maskBonusData; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - uint8_t keyTagMatchBitmap; /*!< 8 bits total. Maps 1 to 1 bitwise with the set of custom tags. (set bit[N]=1 if check Nth custom tag) */ - uint8_t maskTagMatchBitmap; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - MACsecPacketType keyPacketType; /*!< Encoded Packet Type, see MACSEC_PACKET_TYPE */ - uint8_t maskPacketType; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - uint16_t keyInnerVlanType; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the second outermost VLAN Tag. */ - uint16_t maskInnerVlanType; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - uint16_t keyOuterVlanType; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the outermost VLAN Tag. */ - uint16_t maskOuterVlanType; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - uint8_t keyNumTags; /*!< 7 bits total. Number of VLAN/custom tags or MPLS lables detected. Ingress: before SecTag; Egress: total detected. Exclude MCS header tags. i.e. Bit 2: 2 tags/labels before SecTAG...Bit 6: 6 or more tags/labels before SecTAG. */ - uint8_t maskNumTags; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - bool keyExpress; /*!< 1 bits. Express packet. */ - uint8_t maskExpress; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ - bool isMpls; - bool enable; -}; - -struct MACsecMap -{ - uint8_t index; - uint64_t secTagSci; /*!< Identifies the SecTAG SCI for this Flow. */ - uint8_t secYIndex; /*!< index for entry in Egress secY Policy */ - bool isControlPacket; /*!< Identifies all packets matching this index lookup as control packets. */ - uint8_t scIndex; /*!< Identifies the SC for this Flow. */ - uint8_t auxiliaryPlcy; /*!< Auxiliary policy bits. */ - uint8_t ruleId; /*!< Identifies the Rule for this Flow. */ - bool enable; -}; - -enum class MACsecValidateFrameType : uint8_t -{ - Disabled = 0, /*!< Disable validation */ - Check = 1, /*!< Enable validation, do not discard invalid frames*/ - Strict = 2, /*!< Enable validation and discard invalid frames */ - NA = 3 /*!< No processing or accounting */ -}; - -enum class MACsecSecTagIcvStripType : uint8_t -{ - StripBoth = 0, /*!< Strip both SecTag and ICV from packet */ - StripSecTagPreserveICV = 1, - PreserveSecTagStripICV = 2, /*!< Preserve SecTag, Strip ICV */ - PreserveBoth = 3 /*!< Preserve both SecTag and ICV */ -}; - -enum class MACsecCipherSuiteType : uint8_t -{ - GcmAes128 = 0, - GcmAes256 = 1, - GcmAes128Xpn = 2, - GcmAes256Xpn = 3 -}; - -struct MACsecSecY -{ - uint8_t index; /*!< Identifies the SecY for this Flow. */ - bool controlledPortEnabled; /*!< Enable (or disable) operation of the Controlled port associated with this SecY */ - MACsecValidateFrameType frameValidationType; /*!< see MACSEC_VALIDATEFRAME */ - MACsecSecTagIcvStripType secTagIcvStripType; /*!< see MACSEC_STRIP_SECTAG_ICV */ - MACsecCipherSuiteType cipher; /*!< Define the cipher suite to use for this SecY see MACSEC_CIPHER_SUITE */ - uint8_t confidentialOffset; /*!< Define the number of bytes that are unencrypted following the SecTag. */ - bool icvIncludesDaSa; /*!< When set, the outer DA/SA bytes are included in the authentication GHASH calculation */ - bool replayProtect; /*!< Enables Anti-Replay protection */ - uint32_t replayWindow; /*!< Unsigned value indicating the size of the anti-replay window. */ - bool protectFrames; /*!< 0 = do not encrypt or authenticate this packet; 1 = always Authenticate frame and if SecTag.TCI.E = 1 encrypt the packet as well. */ - uint8_t secTagOffset; /*!< Define the offset in bytes from either the start of the packet or a matching Etype depending on SecTag_Insertion_Mode. */ - uint8_t secTagTci; /*!< Tag Control Information excluding the AN field which originates from the SA Policy table */ - uint16_t mtu; /*!< Specifies the outgoing MTU for this SecY */ - bool enable; -}; - -struct MACsecSc -{ - uint8_t index; /*!< SC index. */ - uint8_t secYIndex; /*!< SecY associated with this packet. */ - uint64_t sci; /*!< The Secure Channel Identifier. */ - uint8_t saIndex0; /*!< Define the 1st SA to use */ - uint8_t saIndex1; /*!< Define the 2nd SA to use */ - bool saIndex0InUse; /*!< Specifies whether 1st SA is in use or not. */ - bool saIndex1InUse; /*!< Specifies whether 2nd SA is in use or not. */ - bool enableAutoRekey; /*!< If enabled, then once the pn_threshold is reached, auto rekey will happen. */ - bool isActiveSa1; /*!< If set, then sa_index1 is the currently active SA index. If cleared, the sa_index0 is the currently active SA index). */ - bool enable; -}; - -struct MACsecSa -{ - uint8_t index; /*!< SA index */ - std::array sak; /*!< 256b SAK: Define the encryption key to be used to encrypte this packet. The lower 128 bits are used for 128-bit ciphers. */ - std::array hashKey; /*!< 128b Hash Key: Key used for authentication. */ - std::array salt; /*!< 96b Salt value: Salt value used in XPN ciphers. */ - uint32_t ssci; /*!< 32b SSCI value: Short Secure Channel Identifier, used in XPN ciphers. */ - uint8_t an; /*!< 2b SecTag Association Number (AN) */ - uint64_t nextPn; /*!< 64b next_pn value: Next packet number to insert into outgoing packet on a particular SA. */ - bool enable; -}; - -struct MACSecFlags -{ - bool en; // '1' = enable; '0' = disable -}; - -/* MACSec Settings for 1 port/phy */ -struct MACsecConfig -{ - static constexpr int NumFlags = 1; - static constexpr int NumRules = 2; - static constexpr int NumMaps = 2; - static constexpr int NumSecY = 2; - static constexpr int NumSc = 2; - static constexpr int NumSa = 4; - - MACSecFlags flags; - std::array rule; - std::array map; - std::array secy; - std::array sc; - std::array sa; -}; - -struct MACSecGlobalFlags -{ - bool en; // '1' = enable; '0' = disable - bool nvm; // store macsec config in non-volatile memory -}; - -class MACsecMessage : public Message -{ -public: - MACsecMessage(void) : Message(Message::Type::RawMessage) {} - - MACSecGlobalFlags flags; - MACsecConfig rx; - MACsecConfig tx; - - static std::shared_ptr DecodeToMessage(const std::vector& bytestream, const device_eventhandler_t& report); - bool EncodeFromMessage(std::vector& bytestream, const device_eventhandler_t& report) const; -}; - -} - -#endif // __cplusplus - -#endif \ No newline at end of file diff --git a/include/icsneo/communication/packetizer.h b/include/icsneo/communication/packetizer.h index abc8778..01cc8c3 100644 --- a/include/icsneo/communication/packetizer.h +++ b/include/icsneo/communication/packetizer.h @@ -4,7 +4,7 @@ #ifdef __cplusplus #include "icsneo/communication/packet.h" -#include "icsneo/communication/ringbuffer.h" +#include "icsneo/core/ringbuffer.h" #include "icsneo/api/eventmanager.h" #include #include diff --git a/include/icsneo/communication/ringbuffer.h b/include/icsneo/communication/ringbuffer.h deleted file mode 100644 index 3b9c5c8..0000000 --- a/include/icsneo/communication/ringbuffer.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef _RINGBUFFER_H_ -#define _RINGBUFFER_H_ - -#include -#include -#include -#include -#include -#include -#include -#if __cplusplus >= 202002L -#include -#endif -namespace icsneo { - -class RingBuffer -{ -private: - static constexpr size_t RoundUp(size_t size) { - if (size == 0) { - // Avoid underflow when decrementing later - return 1; - } else if (size >= SIZE_MAX) { - // overflow case - resolve to max size - return MaxSize; - } -#if __cplusplus >= 202002L - // c++20 gives us countl_zero which should be more effecient on most platforms - auto lzero = std::countl_zero(size - 1); - auto shift = (sizeof(size_t) * 8) - lzero; - return 1ull << shift; -#else - // Bit twiddling magic! See http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 - --size; - size |= size >> 1; - size |= size >> 2; - size |= size >> 4; - for (size_t i = 1; i < sizeof(size_t); i <<= 1) { - size |= size >> (i << 3); - } - ++size; - return size; -#endif - } - //static_assert(std::atomic::is_always_lock_free, "RingBuffer cursor types are not lock-free"); - std::atomic readCursor; - std::atomic writeCursor; - // Use this to mask the cursor values to the buffer size. This is set to capacity - 1 where capacity is always an integral power of 2 (2, 4, 8, 16, etc) - size_t mask; - uint8_t* buf; - -public: - static constexpr auto MaxSize = 1ull << ((8 * sizeof(size_t)) - 1); - RingBuffer(size_t bufferSize); - ~RingBuffer(); - const uint8_t& operator[](size_t offset) const; - size_t size() const; - void pop_front(); - void pop(size_t count); - const uint8_t& get(size_t offset) const; - bool write(const uint8_t* addr, size_t count); - bool write(const std::vector& source); - bool read(uint8_t* dest, size_t startIndex, size_t length) const; - void clear(); - constexpr size_t capacity() const { - return mask + 1; - } - -protected: - inline uint8_t* resolve(size_t cursor, size_t offset) const { - return &buf[(cursor + offset) & mask]; - } -}; -} -#endif \ No newline at end of file diff --git a/include/icsneo/communication/crc32.h b/include/icsneo/core/crc32.h similarity index 86% rename from include/icsneo/communication/crc32.h rename to include/icsneo/core/crc32.h index 66c95d0..9199166 100644 --- a/include/icsneo/communication/crc32.h +++ b/include/icsneo/core/crc32.h @@ -5,13 +5,12 @@ * Author: BJones */ -#pragma once - -#ifndef CRC32_H_ -#define CRC32_H_ +#ifndef __CRC32_H_ +#define __CRC32_H_ #include +namespace icsneo { /* * When any data/buffer is run through calCRC(), then the resulting CRC value * is appended to the end of the data/buffer and the data/buffer is rerun @@ -24,4 +23,6 @@ uint32_t crc32(uint32_t crc, const unsigned char* buf, uint32_t len); uint32_t revcrc32(uint32_t crc, const unsigned char* buf, uint32_t len); +} + #endif // CRC32_H_ diff --git a/include/icsneo/core/macseccfg.h b/include/icsneo/core/macseccfg.h new file mode 100644 index 0000000..2548922 --- /dev/null +++ b/include/icsneo/core/macseccfg.h @@ -0,0 +1,217 @@ +#ifndef __MACSEC_CONFIG_H_ +#define __MACSEC_CONFIG_H_ + +#include +#include +#include +#include "icsneo/device/devicetype.h" + +namespace icsneo { + + +struct MACsecVLANTag { + uint16_t vid = 0xFFFFu; /*!< 12 bits */ + uint8_t priCfi = 0xFFu; /*!< PRI - 3 bits, CFI - 1bit */ +}; + +struct MACsecMPLSOuter { + uint32_t mplsLabel = 0xFFFFFFFFu; /*!< 20 bits */ + uint8_t exp = 0xFFu; /*!< 3 bits */ +}; + +enum class MACsecPacketType : uint8_t { + Default = 0, + SingleVLAN = 1, + DualVLAN = 2, + MPLS = 3, + SingleVLANFollowedByMPLS = 4, + DualVLANFollowedByMPLS = 5, + Unsupported = 6, +}; + +// Tell the MACsec phy which packets to accept +struct MACsecRxRule { + std::array keyMacDa = {0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu}; /*!< MAC DA field extracted from the packet */ + std::array maskMacDa = {0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu}; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + std::array keyMacSa = {0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu}; /*!< MAC SA field extracted from the packet */ + std::array maskMacSa = {0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu}; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + uint16_t keyEthertype = 0xFFFFu; /*!< First E-Type found in the packet that doesn't match one of the preconfigured custom tag. */ + uint16_t maskEthertype = 0xFFFFu; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + MACsecVLANTag keyVlanTagOuter1; /*!< outermost/1st VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */ + MACsecMPLSOuter keyMplsOuter1; + MACsecVLANTag maskVlanTagOuter1; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + MACsecMPLSOuter maskMplsOuter1; + MACsecVLANTag keyVlanTagOuter2; /*!< 2nd outermost VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */ + MACsecMPLSOuter keyMplsOuter2; + MACsecVLANTag maskVlanTagOuter2; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + MACsecMPLSOuter maskMplsOuter2; + uint16_t keyBonusData = 0xFFFFu; /*!< 2 bytes of additional bonus data extracted from one of the custom tags. */ + uint16_t maskBonusData = 0xFFFFu; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + uint8_t keyTagMatchBitmap = 0xFFu; /*!< 8 bits total. Maps 1 to 1 bitwise with the set of custom tags. (set bit[N]=1 if check Nth custom tag) */ + uint8_t maskTagMatchBitmap = 0xFFu; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + MACsecPacketType keyPacketType = MACsecPacketType::Default; /*!< Encoded Packet Type, see MACSEC_PACKET_TYPE */ + uint8_t maskPacketType = 0xFFu; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + uint16_t keyInnerVlanType = 0xFFFFu; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the second outermost VLAN Tag. */ + uint16_t maskInnerVlanType = 0xFFFFu; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + uint16_t keyOuterVlanType = 0xFFFFu; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the outermost VLAN Tag. */ + uint16_t maskOuterVlanType = 0xFFFFu; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + uint8_t keyNumTags = 0xFFu; /*!< 7 bits total. Number of VLAN/custom tags or MPLS lables detected. Ingress: before SecTag; Egress: total detected. Exclude MCS header tags. i.e. Bit 2: 2 tags/labels before SecTAG...Bit 6: 6 or more tags/labels before SecTAG. */ + uint8_t maskNumTags = 0xFFu; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + bool keyExpress = true; /*!< 1 bits. Express packet. */ + bool maskExpress = true; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */ + bool isMpls = false; +}; + +enum class MACsecValidation : uint8_t { + Disabled = 0, /*!< Disable validation */ + Check = 1, /*!< Enable validation, do not discard invalid frames*/ + Strict = 2, /*!< Enable validation and discard invalid frames */ + NA = 3 /*!< No processing or accounting */ +}; + +enum class MACsecStrip : uint8_t { + StripSecTagAndIcv = 0, /*!< Strip both SecTag and ICV from packet */ + StripSecTagPreserveICV = 1, + PreserveSecTagStripICV = 2, /*!< Preserve SecTag, Strip ICV */ + NoStrip = 3 /*!< Preserve both SecTag and ICV */ +}; + +enum class MACsecCipherSuite : uint8_t { + GcmAes128 = 0, + GcmAes256 = 1, + GcmAes128Xpn = 2, + GcmAes256Xpn = 3 +}; + +// Tag control information +struct MACsecTci { + bool es = false; // End station bit + bool sc = true; // SCI included bit + bool scb = false; // Single Copy Broadcast + bool e = false; // Encryption bit + bool c = false; // Changed text bit +}; + + +struct MACsecRxSecY { + bool enableControlPort = true; /*!< Enable (or disable) operation of the Controlled port associated with this SecY */ + MACsecValidation frameValidation = MACsecValidation::Strict; /*!< see MACSEC_VALIDATEFRAME */ + MACsecStrip frameStrip = MACsecStrip::NoStrip; /*!< see MACSEC_STRIP_SECTAG_ICV */ + MACsecCipherSuite cipher = MACsecCipherSuite::GcmAes128; /*!< Define the cipher suite to use for this SecY see MACSEC_CIPHER_SUITE */ + uint8_t confidentialityOffset = 0; /*!< Define the number of bytes that are unencrypted following the SecTag. */ + bool icvIncludesDaSa = true; /*!< When set, the outer DA/SA bytes are included in the authentication GHASH calculation */ + bool replayProtect = true; /*!< Enables Anti-Replay protection */ + uint32_t replayWindow = 1; /*!< Unsigned value indicating the size of the anti-replay window. */ + bool isControlPacket = false; /*!< Identifies all packets matching this index lookup as control packets. */ + uint64_t sci; /** The SCI of this secY */ +}; + +struct MACsecTxSecY { + bool enableControlPort = true; /*!< Enable (or disable) operation of the Controlled port associated with this SecY */ + MACsecCipherSuite cipher = MACsecCipherSuite::GcmAes128; /*!< Define the cipher suite to use for this SecY see MACSEC_CIPHER_SUITE */ + uint8_t confidentialityOffset = 0; /*!< Define the number of bytes that are unencrypted following the SecTag. */ + bool icvIncludesDaSa = true; /*!< When set, the outer DA/SA bytes are included in the authentication GHASH calculation */ + bool protectFrames = true; /*!< 0 = do not encrypt or authenticate this packet; 1 = always Authenticate frame and if SecTag.TCI.E = 1 encrypt the packet as well. */ + uint8_t secTagOffset = 12; /*!< Define the offset in bytes from either the start of the packet or a matching Etype depending on SecTag_Insertion_Mode. */ + MACsecTci tci; /*!< Tag Control Information excluding the AN field which originates from the SA Policy table */ + uint16_t mtu = 0xFFFFu; /*!< Specifies the outgoing MTU for this SecY */ + bool isControlPacket = false; /*!< Identifies all packets matching this index lookup as control packets. */ + uint8_t auxiliaryPolicy = 0u; /*!< Auxiliary policy bits. */ + uint64_t sci = 0x1122334455660001u; +}; + +struct MACsecTxSa { + std::array sak = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; /*!< 256b SAK: Define the encryption key to be used to encrypte this packet. The lower 128 bits are used for 128-bit ciphers. */ + std::array hashKey = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; /*!< 128b Hash Key: Key used for authentication. */ + std::array salt = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; /*!< 96b Salt value: Salt value used in XPN ciphers. */ + uint32_t ssci = 0x01u; /*!< 32b SSCI value: Short Secure Channel Identifier, used in XPN ciphers. */ + uint8_t an = 0x00;; /*!< 2b SecTag Association Number (AN) */ + uint64_t nextPn = 0x01u; /*!< 64b next_pn value: Next packet number to insert into outgoing packet on a particular SA. */ +}; + +struct MACsecRxSa { + std::array sak = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; /*!< 256b SAK: Define the encryption key to be used to encrypte this packet. The lower 128 bits are used for 128-bit ciphers. */ + std::array hashKey = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; /*!< 128b Hash Key: Key used for authentication. */ + std::array salt = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; /*!< 96b Salt value: Salt value used in XPN ciphers. */ + uint32_t ssci = 0x01u; /*!< 32b SSCI value: Short Secure Channel Identifier, used in XPN ciphers. */ + uint64_t nextPn = 0x01u; /*!< 64b next_pn value: Next packet number to insert into outgoing packet on a particular SA. */ +}; + +class MACsecConfig { +private: + bool enableRx = false; + bool enableTx = false; + bool nvm = false; + + uint8_t maxSecY; + uint8_t maxSa; + uint8_t maxRule; + uint16_t binIndex; + DeviceType type; + + std::vector rxRule; + std::vector rxSecY; + std::vector txSecY; + std::vector txSa; + std::vector rxSa; + std::vector> txSecYSaIndices; + std::vector> rxSecYSaIndices; + std::vector rxSecYRekey; + std::vector txSecYRekey; + std::vector rxRuleIndices; +public: + MACsecConfig() = delete; + MACsecConfig(const DeviceType& deviceType); + + int addRxSecY(const MACsecRxSecY& secY, uint8_t saIndex); + int addTxSecY(const MACsecTxSecY& secY, uint8_t saIndex); + + int addRxRule(const MACsecRxRule& rule, uint8_t secYIndex); + + int addRxSa(const MACsecRxSa& sa); + int addTxSa(const MACsecTxSa& sa); + + MACsecRxSecY& getRxSecY(uint8_t secYIndex); + const MACsecRxSecY& getRxSecY(uint8_t secYIndex) const; + MACsecTxSecY& getTxSecY(uint8_t secYIndex); + const MACsecTxSecY& getTxSecY(uint8_t secYIndex) const; + + MACsecRxSa& getRxSa(uint8_t saIndex); + const MACsecRxSa& getRxSa(uint8_t saIndex) const; + MACsecTxSa& getTxSa(uint8_t saIndex); + const MACsecTxSa& getTxSa(uint8_t saIndex) const; + + MACsecRxRule& getRxRule(uint8_t ruleIndex); + const MACsecRxRule& getRxRule(uint8_t ruleIndex) const; + + bool setTxSaIndex(uint8_t secYIndex, uint8_t saIndex); + bool enableTxRekey(uint8_t secYIndex, uint8_t rekeySaIndex); + bool setTxSaRekeyIndex(uint8_t secYIndex, uint8_t saIndex); + void disableTxRekey(uint8_t secYIndex); + + bool setRxSaIndex(uint8_t secYIndex, uint8_t saIndex); + bool enableRxRekey(uint8_t secYIndex, uint8_t rekeySaIndex); + bool setRxSaRekeyIndex(uint8_t secYIndex, uint8_t saIndex); + void disableRxRekey(uint8_t secYIndex); + + void setRxEnable(bool rxEnable); + void setTxEnable(bool txEnable); + void setStorage(bool temporary); + + void clear(); + std::vector serialize() const; + operator bool() const; + uint16_t getBinIndex() const; + DeviceType getType() const; + uint8_t getMaxNumRule() const; + uint8_t getMaxNumSecY() const; + uint8_t getMaxNumSa() const; +}; + +} + +#endif + + diff --git a/include/icsneo/core/ringbuffer.h b/include/icsneo/core/ringbuffer.h new file mode 100644 index 0000000..9f20e16 --- /dev/null +++ b/include/icsneo/core/ringbuffer.h @@ -0,0 +1,75 @@ +#ifndef _RINGBUFFER_H_ +#define _RINGBUFFER_H_ + +#include +#include +#include +#include +#include +#include +#include +#if __cplusplus >= 202002L +#include +#endif +namespace icsneo { + +class RingBuffer +{ +private: + static constexpr size_t RoundUp(size_t size) { + if (size == 0) { + // Avoid underflow when decrementing later + return 1; + } else if (size >= SIZE_MAX) { + // overflow case - resolve to max size + return MaxSize; + } +#if __cplusplus >= 202002L + // c++20 gives us countl_zero which should be more effecient on most platforms + auto lzero = std::countl_zero(size - 1); + auto shift = (sizeof(size_t) * 8) - lzero; + return 1ull << shift; +#else + // Bit twiddling magic! See http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 + --size; + size |= size >> 1; + size |= size >> 2; + size |= size >> 4; + for (size_t i = 1; i < sizeof(size_t); i <<= 1) { + size |= size >> (i << 3); + } + ++size; + return size; +#endif + } + //static_assert(std::atomic::is_always_lock_free, "RingBuffer cursor types are not lock-free"); + std::atomic readCursor; + std::atomic writeCursor; + // Use this to mask the cursor values to the buffer size. This is set to capacity - 1 where capacity is always an integral power of 2 (2, 4, 8, 16, etc) + size_t mask; + uint8_t* buf; + +public: + static constexpr auto MaxSize = 1ull << ((8 * sizeof(size_t)) - 1); + RingBuffer(size_t bufferSize); + ~RingBuffer(); + const uint8_t& operator[](size_t offset) const; + size_t size() const; + void pop_front(); + void pop(size_t count); + const uint8_t& get(size_t offset) const; + bool write(const uint8_t* addr, size_t count); + bool write(const std::vector& source); + bool read(uint8_t* dest, size_t startIndex, size_t length) const; + void clear(); + constexpr size_t capacity() const { + return mask + 1; + } + +protected: + inline uint8_t* resolve(size_t cursor, size_t offset) const { + return &buf[(cursor + offset) & mask]; + } +}; +} +#endif \ No newline at end of file diff --git a/include/icsneo/device/device.h b/include/icsneo/device/device.h index a5c57c7..2d6b836 100644 --- a/include/icsneo/device/device.h +++ b/include/icsneo/device/device.h @@ -46,7 +46,7 @@ #include "icsneo/communication/message/extendeddatamessage.h" #include "icsneo/communication/message/livedatamessage.h" #include "icsneo/communication/message/tc10statusmessage.h" -#include "icsneo/communication/message/macsecmessage.h" +#include "icsneo/core/macseccfg.h" #include "icsneo/communication/packet/genericbinarystatuspacket.h" #include "icsneo/communication/packet/livedatapacket.h" #include "icsneo/device/extensions/flexray/controller.h" @@ -855,7 +855,7 @@ public: std::optional getGPTPStatus(std::chrono::milliseconds timeout = std::chrono::milliseconds(100)); /* MACsec support */ - virtual bool writeMACsecConfig(const MACsecMessage& message, uint16_t binaryIndex); + virtual bool writeMACsecConfig(const MACsecConfig& cfg); std::shared_ptr getExtension(const std::string& name) const; diff --git a/platform/windows/pcap.cpp b/platform/windows/pcap.cpp index 1436d92..26d408b 100644 --- a/platform/windows/pcap.cpp +++ b/platform/windows/pcap.cpp @@ -10,7 +10,7 @@ #include "icsneo/communication/ethernetpacketizer.h" #include "icsneo/communication/packetizer.h" #include "icsneo/communication/decoder.h" -#include "icsneo/communication/ringbuffer.h" +#include "icsneo/core/ringbuffer.h" #include #include #pragma comment(lib, "IPHLPAPI.lib") diff --git a/test/unit/a2bencoderdecodertest.cpp b/test/unit/a2bencoderdecodertest.cpp index feed7c1..ae71116 100644 --- a/test/unit/a2bencoderdecodertest.cpp +++ b/test/unit/a2bencoderdecodertest.cpp @@ -3,7 +3,7 @@ #include "icsneo/communication/packet/a2bpacket.h" #include "icsneo/communication/message/a2bmessage.h" #include "icsneo/communication/packetizer.h" -#include "icsneo/communication/ringbuffer.h" +#include "icsneo/core/ringbuffer.h" #include "icsneo/api/eventmanager.h" #include "gtest/gtest.h" #include diff --git a/test/unit/i2cencoderdecodertest.cpp b/test/unit/i2cencoderdecodertest.cpp index 0cc6a6a..98f8e0b 100644 --- a/test/unit/i2cencoderdecodertest.cpp +++ b/test/unit/i2cencoderdecodertest.cpp @@ -3,7 +3,7 @@ #include "icsneo/communication/packet/i2cpacket.h" #include "icsneo/communication/message/i2cmessage.h" #include "icsneo/communication/packetizer.h" -#include "icsneo/communication/ringbuffer.h" +#include "icsneo/core/ringbuffer.h" #include "icsneo/api/eventmanager.h" #include "gtest/gtest.h" #include diff --git a/test/unit/linencoderdecodertest.cpp b/test/unit/linencoderdecodertest.cpp index 64ab71f..9a8d365 100644 --- a/test/unit/linencoderdecodertest.cpp +++ b/test/unit/linencoderdecodertest.cpp @@ -3,7 +3,7 @@ #include "icsneo/communication/packet/linpacket.h" #include "icsneo/communication/message/linmessage.h" #include "icsneo/communication/packetizer.h" -#include "icsneo/communication/ringbuffer.h" +#include "icsneo/core/ringbuffer.h" #include "icsneo/api/eventmanager.h" #include "gtest/gtest.h" #include diff --git a/test/unit/livedataencoderdecodertest.cpp b/test/unit/livedataencoderdecodertest.cpp index 3f04ad2..195f1e1 100644 --- a/test/unit/livedataencoderdecodertest.cpp +++ b/test/unit/livedataencoderdecodertest.cpp @@ -3,7 +3,7 @@ #include "icsneo/communication/packet/livedatapacket.h" #include "icsneo/communication/message/livedatamessage.h" #include "icsneo/communication/packetizer.h" -#include "icsneo/communication/ringbuffer.h" +#include "icsneo/core/ringbuffer.h" #include "icsneo/api/eventmanager.h" #include "gtest/gtest.h" #include diff --git a/test/unit/mdioencoderdecodertest.cpp b/test/unit/mdioencoderdecodertest.cpp index 05173aa..45a87ce 100644 --- a/test/unit/mdioencoderdecodertest.cpp +++ b/test/unit/mdioencoderdecodertest.cpp @@ -3,7 +3,7 @@ #include "icsneo/communication/packet/mdiopacket.h" #include "icsneo/communication/message/mdiomessage.h" #include "icsneo/communication/packetizer.h" -#include "icsneo/communication/ringbuffer.h" +#include "icsneo/core/ringbuffer.h" #include "icsneo/api/eventmanager.h" #include "gtest/gtest.h" #include diff --git a/test/unit/ringbuffertest.cpp b/test/unit/ringbuffertest.cpp index 4a89213..4b87efa 100644 --- a/test/unit/ringbuffertest.cpp +++ b/test/unit/ringbuffertest.cpp @@ -1,4 +1,4 @@ -#include "icsneo/communication/ringbuffer.h" +#include "icsneo/core/ringbuffer.h" #include "gtest/gtest.h" using namespace icsneo;