diff --git a/3rdParty/json/include/json.hpp b/3rdParty/json/include/json.hpp index 8b72ea6539..f7859fdc29 100644 --- a/3rdParty/json/include/json.hpp +++ b/3rdParty/json/include/json.hpp @@ -3406,7 +3406,7 @@ NLOHMANN_JSON_NAMESPACE_END template class AllocatorType = std::allocator, template class JSONSerializer = adl_serializer, - class BinaryType = std::vector, // cppcheck-suppress syntaxError + class BinaryType = std::vector, class CustomBaseClass = void> class basic_json; @@ -4251,7 +4251,6 @@ inline std::size_t concat_length(const char /*c*/, const Args& ... rest) template inline std::size_t concat_length(const char* cstr, const Args& ... rest) { - // cppcheck-suppress ignoredReturnValue return ::strlen(cstr) + concat_length(rest...); } @@ -19991,7 +19990,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec #if JSON_DIAGNOSTICS JSON_TRY { - // cppcheck-suppress assertWithSideEffect JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j) { return j.m_parent == this; diff --git a/Common++/header/Logger.h b/Common++/header/Logger.h index 2b5ec3954f..f3a440810e 100644 --- a/Common++/header/Logger.h +++ b/Common++/header/Logger.h @@ -110,7 +110,8 @@ namespace pcpp PcapLogModuleKniDevice, ///< KniDevice module (Pcap++) PcapLogModuleXdpDevice, ///< XdpDevice module (Pcap++) NetworkUtils, ///< NetworkUtils module (Pcap++) - NumOfLogModules + PacketLogModuleDoIpLayer, ///< DoipLayer module (Packet++) + NumOfLogModules, }; /// Cross-platform and thread-safe version of strerror diff --git a/Packet++/CMakeLists.txt b/Packet++/CMakeLists.txt index 2bae131ebd..c5266cbb1c 100644 --- a/Packet++/CMakeLists.txt +++ b/Packet++/CMakeLists.txt @@ -10,6 +10,8 @@ add_library( src/DnsLayer.cpp src/DnsResource.cpp src/DnsResourceData.cpp + src/DoIpLayer.cpp + src/DoIpLayerData.cpp src/EthDot3Layer.cpp src/EthLayer.cpp src/FtpLayer.cpp @@ -80,6 +82,10 @@ set( header/DnsLayer.h header/DnsResourceData.h header/DnsResource.h + header/DoIpEnums.h + header/DoIpEnumToString.h + header/DoIpLayer.h + header/DoIpLayerData.h header/EthDot3Layer.h header/EthLayer.h header/FtpLayer.h diff --git a/Packet++/header/DoIpEnumToString.h b/Packet++/header/DoIpEnumToString.h new file mode 100644 index 0000000000..5f0965e6c3 --- /dev/null +++ b/Packet++/header/DoIpEnumToString.h @@ -0,0 +1,226 @@ +#pragma once + +#include +#include "DoIpEnums.h" + +/// @file + +/** + * @namespace pcpp + * @brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * @brief Mapping of DoIP Protocol Versions to their respective string descriptions. + * + * This unordered map provides human-readable descriptions for each version of the + * DoIP protocol as defined in ISO 13400. It maps the `DoIpProtocolVersion` enum values + * to their corresponding descriptions. + */ + static const std::unordered_map DoIpEnumToStringProtocolVersion{ + { DoIpProtocolVersion::defaultVersion, "Default value for vehicle identification request messages" }, + { DoIpProtocolVersion::version01Iso2010, "DoIP ISO/DIS 13400-2:2010" }, + { DoIpProtocolVersion::version02Iso2012, "DoIP ISO 13400-2:2012" }, + { DoIpProtocolVersion::version03Iso2019, "DoIP ISO 13400-2:2019" }, + { DoIpProtocolVersion::version04Iso2019_AMD1, "DoIP ISO 13400-2:2012 AMD1" }, + { DoIpProtocolVersion::reservedVersion, "Reserved" }, + }; + + /** + * @brief Mapping of DoIP Payload Types to their respective string descriptions. + * + * This unordered map provides human-readable descriptions for each payload type + * defined in the DoIP protocol as per ISO 13400. It maps the `DoIpPayloadTypes` enum values + * to their corresponding descriptions. + */ + static const std::unordered_map DoIpEnumToStringPayloadType{ + { DoIpPayloadTypes::GENERIC_HEADER_NEG_ACK, "Generic DOIP header Nack" }, + { DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST, "Vehicle identification request" }, + { DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_EID, "Vehicle identification request with EID" }, + { DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_VIN, "Vehicle identification request with VIN" }, + { DoIpPayloadTypes::ANNOUNCEMENT_MESSAGE, + "Vehicle announcement message / vehicle identification response message" }, + { DoIpPayloadTypes::ROUTING_ACTIVATION_REQUEST, "Routing activation request" }, + { DoIpPayloadTypes::ROUTING_ACTIVATION_RESPONSE, "Routing activation response" }, + { DoIpPayloadTypes::ALIVE_CHECK_REQUEST, "Alive check request" }, + { DoIpPayloadTypes::ALIVE_CHECK_RESPONSE, "Alive check response" }, + { DoIpPayloadTypes::ENTITY_STATUS_REQUEST, "DOIP entity status request" }, + { DoIpPayloadTypes::ENTITY_STATUS_RESPONSE, "DOIP entity status response" }, + { DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_REQUEST, "Diagnostic power mode request information" }, + { DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_RESPONSE, "Diagnostic power mode response information" }, + { DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_TYPE, "Diagnostic message" }, + { DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_POS_ACK, "Diagnostic message Ack" }, + { DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_NEG_ACK, "Diagnostic message Nack" } + }; + + /** + * @brief Mapping of DoIP Activation Types to their respective string descriptions. + * + * This unordered map provides human-readable descriptions for each activation type + * defined in the DoIP protocol as per ISO 13400. It maps the `DoIpActivationTypes` enum values + * to their corresponding descriptions. + */ + static const std::unordered_map DoIpEnumToStringActivationTypes{ + { DoIpActivationTypes::Default, "Default" }, + { DoIpActivationTypes::WWH_OBD, "WWH-OBD" }, + { DoIpActivationTypes::CENTRAL_SECURITY, "Central security" }, + }; + + /** + * @brief Mapping of DoIP Generic Header Nack Codes to their respective string descriptions. + * + * This unordered map provides human-readable descriptions for each Nack code related to + * the DoIP Generic Header as per ISO 13400. It maps the `DoIpGenericHeaderNackCodes` enum + * values to their corresponding descriptions. + */ + static const std::unordered_map DoIpEnumToStringGenericHeaderNackCodes{ + { DoIpGenericHeaderNackCodes::INCORRECT_PATTERN, "Incorrect pattern format" }, + { DoIpGenericHeaderNackCodes::INKNOWN_PAYLOAD_TYPE, "Unknown payload type" }, + { DoIpGenericHeaderNackCodes::INVALID_PAYLOAD_LENGTH, "Invalid payload length" }, + { DoIpGenericHeaderNackCodes::MESSAGE_TOO_LARGE, "Message too large" }, + { DoIpGenericHeaderNackCodes::OUT_OF_MEMORY, "Out of memory" }, + }; + + /** + * @brief Mapping of DoIP Action Codes to their respective string descriptions. + * + * This unordered map provides human-readable descriptions for each action code related to + * the DoIP announcement message, as per ISO 13400. It maps the `DoIpActionCodes` enum + * values to their corresponding descriptions. + */ + static const std::unordered_map DoIpEnumToStringActionCodes{ + { DoIpActionCodes::NO_FURTHER_ACTION_REQUIRED, "No further action required" }, + { DoIpActionCodes::RESERVED_ISO_0x01, "Reserved by ISO 13400" }, + { DoIpActionCodes::RESERVED_ISO_0x02, "Reserved by ISO 13400" }, + { DoIpActionCodes::RESERVED_ISO_0x03, "Reserved by ISO 13400" }, + { DoIpActionCodes::RESERVED_ISO_0x04, "Reserved by ISO 13400" }, + { DoIpActionCodes::RESERVED_ISO_0x05, "Reserved by ISO 13400" }, + { DoIpActionCodes::RESERVED_ISO_0x06, "Reserved by ISO 13400" }, + { DoIpActionCodes::RESERVED_ISO_0x07, "Reserved by ISO 13400" }, + { DoIpActionCodes::RESERVED_ISO_0x08, "Reserved by ISO 13400" }, + { DoIpActionCodes::RESERVED_ISO_0x09, "Reserved by ISO 13400" }, + { DoIpActionCodes::RESERVED_ISO_0x0A, "Reserved by ISO 13400" }, + { DoIpActionCodes::RESERVED_ISO_0x0B, "Reserved by ISO 13400" }, + { DoIpActionCodes::RESERVED_ISO_0x0C, "Reserved by ISO 13400" }, + { DoIpActionCodes::RESERVED_ISO_0x0D, "Reserved by ISO 13400" }, + { DoIpActionCodes::RESERVED_ISO_0x0E, "Reserved by ISO 13400" }, + { DoIpActionCodes::RESERVED_ISO_0x0F, "Reserved by ISO 13400" }, + { DoIpActionCodes::ROUTING_ACTIVATION_REQUIRED, "Routing activation required to initiate central security" } + }; + + /** + * @brief Mapping of DoIP Routing Response Codes to their respective string descriptions. + * + * This unordered map provides human-readable descriptions for each routing response code + * related to the DoIP routing activation process, as per ISO 13400. It maps the `DoIpRoutingResponseCodes` enum + * values to their corresponding descriptions. + */ + static const std::unordered_map DoIpEnumToStringRoutingResponseCodes{ + { DoIpRoutingResponseCodes::UNKNOWN_SOURCE_ADDRESS, "Routing activation denied due to unknown source address" }, + { DoIpRoutingResponseCodes::NO_FREE_SOCKET, + "Routing activation denied because all concurrently supported TCP_DATA sockets are registered and active" }, + { DoIpRoutingResponseCodes::WRONG_SOURCE_ADDRESS, + "Routing activation denied because an SA different from the table connection entry was received on the already activated TCP_DATA socket" }, + { DoIpRoutingResponseCodes::SOURCE_ADDRESS_ALREADY_REGISTERED, + "Routing activation denied because the SA is already registered and active on a different TCP_DATA socket" }, + { DoIpRoutingResponseCodes::MISSING_AUTHENTICATION, "Routing activation denied due to missing authentication" }, + { DoIpRoutingResponseCodes::REJECTED_CONFIRMATION, "Routing activation denied due to rejected confirmation" }, + { DoIpRoutingResponseCodes::UNSUPPORTED_ACTIVATION_TYPE, + "Routing activation denied due to unsupported routing activation type" }, + { DoIpRoutingResponseCodes::ENCRYPTED_CONNECTION_TLS, + "Routing activation denied due to request for encrypted connection via TLS" }, + { DoIpRoutingResponseCodes::RESERVED_ISO_0x08, "Reserved by ISO 13400" }, + { DoIpRoutingResponseCodes::RESERVED_ISO_0x09, "Reserved by ISO 13400" }, + { DoIpRoutingResponseCodes::RESERVED_ISO_0x0A, "Reserved by ISO 13400" }, + { DoIpRoutingResponseCodes::RESERVED_ISO_0x0B, "Reserved by ISO 13400" }, + { DoIpRoutingResponseCodes::RESERVED_ISO_0x0C, "Reserved by ISO 13400" }, + { DoIpRoutingResponseCodes::RESERVED_ISO_0x0D, "Reserved by ISO 13400" }, + { DoIpRoutingResponseCodes::RESERVED_ISO_0x0E, "Reserved by ISO 13400" }, + { DoIpRoutingResponseCodes::RESERVED_ISO_0x0F, "Reserved by ISO 13400" }, + { DoIpRoutingResponseCodes::ROUTING_SUCCESSFULLY_ACTIVATED, "Routing successfully activated" }, + { DoIpRoutingResponseCodes::CONFIRMATION_REQUIRED, "Routing will be activated; confirmation required" } + }; + + /** + * @brief Mapping of DoIP Diagnostic Message Nack Codes to their respective string descriptions. + * + * This unordered map provides human-readable descriptions for each NACK (negative acknowledgment) code + * related to DoIP diagnostic messages, as per ISO 13400. It maps the `DoIpDiagnosticMessageNackCodes` enum + * values to their corresponding descriptions. + */ + static const std::unordered_map DoIpEnumToStringDiagnosticNackCodes{ + { DoIpDiagnosticMessageNackCodes::RESERVED_ISO_0x00, "Reserved by ISO 13400" }, + { DoIpDiagnosticMessageNackCodes::RESERVED_ISO_0x01, "Reserved by ISO 13400" }, + { DoIpDiagnosticMessageNackCodes::INVALID_SOURCE_ADDRESS, "Invalid source address" }, + { DoIpDiagnosticMessageNackCodes::INVALID_TARGET_ADDRESS, "Unknown target address" }, + { DoIpDiagnosticMessageNackCodes::MESSAGE_TOO_LARGE, "Diagnostic message too large" }, + { DoIpDiagnosticMessageNackCodes::OUT_OF_MEMORY, "Out of memory" }, + { DoIpDiagnosticMessageNackCodes::TARGET_UNREACHABLE, "Target unreachable" }, + { DoIpDiagnosticMessageNackCodes::UNKNOWN_NETWORK, "Unknown network" }, + { DoIpDiagnosticMessageNackCodes::TRANSPORT_PROTOCOL_ERROR, "Transport protocol error" }, + }; + + /** + * @brief Mapping of DoIP Diagnostic Power Mode Codes to their respective string descriptions. + * + * This unordered map provides human-readable descriptions for each power mode code + * related to DoIP diagnostics, as per ISO 13400. It maps the `DoIpDiagnosticPowerMode` enum + * values to their corresponding descriptions. + */ + static const std::unordered_map DoIpEnumToStringDiagnosticPowerModeCodes{ + { DoIpDiagnosticPowerModeCodes::NOT_READY, "not ready" }, + { DoIpDiagnosticPowerModeCodes::READY, "ready" }, + { DoIpDiagnosticPowerModeCodes::NOT_SUPPORTED, "not supported" }, + }; + + /** + * @brief Mapping of DoIP Entity Status Codes to their respective string descriptions. + * + * This unordered map provides human-readable descriptions for the entity status codes + * in the context of DoIP (Diagnostic over IP). It maps the `DoIpEntityStatus` enum values + * to their corresponding descriptions, distinguishing between a "DoIP node" and a "DoIP gateway." + */ + static const std::unordered_map DoIpEnumToStringEntityStatusNodeTypes{ + { DoIpEntityStatus::NODE, "DoIp node" }, + { DoIpEntityStatus::GATEWAY, "DoIP gateway" }, + }; + + /** + * @brief Mapping of DoIP Acknowledgement Codes to their string representations. + * + * This unordered map provides a human-readable description for the DoIP acknowledgement + * code `ACK`, which is used to confirm the successful reception or processing of a message. + */ + static const std::unordered_map DoIpEnumToStringAckCode{ + { DoIpDiagnosticAckCodes::ACK, "ACK" }, + }; + + /** + * @brief A mapping of DoIP synchronization statuses to their corresponding string descriptions. + * + * This unordered map provides a human-readable string for each synchronization status + * defined in the `DoIpSyncStatus` enumeration. It is used to convert synchronization status + * values to their respective descriptions for logging or display purposes. + */ + static const std::unordered_map DoIpEnumToStringSyncStatus{ + { DoIpSyncStatus::VIN_AND_OR_GID_ARE_SINCHRONIZED, "VIN and/or GID are synchronized" }, + { DoIpSyncStatus::RESERVED_ISO_0x01, "Reserved by ISO 13400" }, + { DoIpSyncStatus::RESERVED_ISO_0x02, "Reserved by ISO 13400" }, + { DoIpSyncStatus::RESERVED_ISO_0x03, "Reserved by ISO 13400" }, + { DoIpSyncStatus::RESERVED_ISO_0x04, "Reserved by ISO 13400" }, + { DoIpSyncStatus::RESERVED_ISO_0x05, "Reserved by ISO 13400" }, + { DoIpSyncStatus::RESERVED_ISO_0x06, "Reserved by ISO 13400" }, + { DoIpSyncStatus::RESERVED_ISO_0x07, "Reserved by ISO 13400" }, + { DoIpSyncStatus::RESERVED_ISO_0x08, "Reserved by ISO 13400" }, + { DoIpSyncStatus::RESERVED_ISO_0x09, "Reserved by ISO 13400" }, + { DoIpSyncStatus::RESERVED_ISO_0x0A, "Reserved by ISO 13400" }, + { DoIpSyncStatus::RESERVED_ISO_0x0B, "Reserved by ISO 13400" }, + { DoIpSyncStatus::RESERVED_ISO_0x0C, "Reserved by ISO 13400" }, + { DoIpSyncStatus::RESERVED_ISO_0x0D, "Reserved by ISO 13400" }, + { DoIpSyncStatus::RESERVED_ISO_0x0E, "Reserved by ISO 13400" }, + { DoIpSyncStatus::RESERVED_ISO_0x0F, "Reserved by ISO 13400" }, + { DoIpSyncStatus::VIN_AND_OR_GID_ARE_NOT_SINCHRONIZED, "VIN and/or GID are not synchronized" }, + { DoIpSyncStatus::NON_INITIALIZED, "NULL" } + }; +} // namespace pcpp diff --git a/Packet++/header/DoIpEnums.h b/Packet++/header/DoIpEnums.h new file mode 100644 index 0000000000..43c20aa1e2 --- /dev/null +++ b/Packet++/header/DoIpEnums.h @@ -0,0 +1,706 @@ +#pragma once + +#include +#include + +/// @file + +/** + * @namespace pcpp + * @brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * @brief Represents the DoIP (Diagnostics over IP) protocol versions. + */ + enum class DoIpProtocolVersion : uint8_t + { + /** + * @brief Reserved protocol version. + * This value is used when the version is not specified or invalid. + */ + reservedVersion = 0x00U, + + /** + * @brief Protocol version 1, based on ISO 2010 specification. + */ + version01Iso2010 = 0x01U, + + /** + * @brief Protocol version 2, based on ISO 2012 specification. + */ + version02Iso2012 = 0x02U, + + /** + * @brief Protocol version 3, based on ISO 2019 specification. + */ + version03Iso2019 = 0x03U, + + /** + * @brief Protocol version 4, based on ISO 2019 AMD1 (Amendment 1) specification. + */ + version04Iso2019_AMD1 = 0x04U, + + /** + * @brief Default protocol version. + * Used for broadcast Vehicle Identification Request Messages. + */ + defaultVersion = 0xFFU + }; + + /** + * @brief Enum representing DoIP routing activation types. + * These values specify the type of routing activation used in DoIP (Diagnostic over IP). + */ + enum class DoIpActivationTypes : uint8_t + { + /** + * Default routing activation type. + * Used when no specific type is required. + */ + Default = 0x00U, + + /** + * WWH-OBD (Worldwide Harmonized On-Board Diagnostics) routing activation type. + * Used for vehicle diagnostics in compliance with WWH-OBD standards. + */ + WWH_OBD = 0x01U, + + /** + * Central security routing activation type. + * Used for secure communications involving a central security system. + */ + CENTRAL_SECURITY = 0xE0U + }; + + /** + * @brief Enum representing DoIP payload types. + * + * These payload types are defined as part of the DoIP (Diagnostic over IP) protocol + * and specify the type of message being transmitted. + */ + enum class DoIpPayloadTypes : uint16_t + { + /** + * Generic header negative acknowledgment. + * Indicates a failure or error in processing the generic header. + */ + GENERIC_HEADER_NEG_ACK = 0x0000U, + + /** + * Vehicle identification request. + * Used to request identification details of a vehicle. + */ + VEHICLE_IDENTIFICATION_REQUEST = 0x0001U, + + /** + * Vehicle identification request with EID. + * Requests identification using an external identifier (EID). + */ + VEHICLE_IDENTIFICATION_REQUEST_WITH_EID = 0x0002U, + + /** + * Vehicle identification request with VIN. + * Requests identification using the vehicle's VIN (Vehicle Identification Number). + */ + VEHICLE_IDENTIFICATION_REQUEST_WITH_VIN = 0x0003U, + + /** + * Announcement message. + * Sent to announce the availability of a DoIP entity. + */ + ANNOUNCEMENT_MESSAGE = 0x0004U, + + /** + * Routing activation request. + * Initiates a routing activation procedure. + */ + ROUTING_ACTIVATION_REQUEST = 0x0005U, + + /** + * Routing activation response. + * Response to a routing activation request. + */ + ROUTING_ACTIVATION_RESPONSE = 0x0006U, + + /** + * Alive check request. + * Sent to verify that a DoIP entity is still operational. + */ + ALIVE_CHECK_REQUEST = 0x0007U, + + /** + * Alive check response. + * Response to an alive check request. + */ + ALIVE_CHECK_RESPONSE = 0x0008U, + + /** + * Entity status request. + * Used to request the status of a DoIP entity. + */ + ENTITY_STATUS_REQUEST = 0x4001U, + + /** + * Entity status response. + * Response to an entity status request. + */ + ENTITY_STATUS_RESPONSE = 0x4002U, + + /** + * Diagnostic power mode request. + * Requests the current power mode of a DoIP entity. + */ + DIAGNOSTIC_POWER_MODE_REQUEST = 0x4003U, + + /** + * Diagnostic power mode response. + * Response to a diagnostic power mode request. + */ + DIAGNOSTIC_POWER_MODE_RESPONSE = 0x4004U, + + /** + * Diagnostic message type. + * Represents a generic diagnostic message. + */ + DIAGNOSTIC_MESSAGE_TYPE = 0x8001U, + + /** + * Diagnostic message positive acknowledgment. + * Indicates successful processing of a diagnostic message. + */ + DIAGNOSTIC_MESSAGE_POS_ACK = 0x8002U, + + /** + * Diagnostic message negative acknowledgment. + * Indicates an error in processing a diagnostic message. + */ + DIAGNOSTIC_MESSAGE_NEG_ACK = 0x8003U, + }; + + /** + * @brief Enum representing DoIP Generic Header NACK codes (ISO 13400). + * + * These codes are used to indicate specific errors in the DoIP Generic Header. + */ + enum class DoIpGenericHeaderNackCodes : uint8_t + { + /** + * Incorrect pattern detected in the header. + * Indicates that the header does not follow the expected pattern. + */ + INCORRECT_PATTERN = 0x00U, + + /** + * Unknown payload type. + * The payload type in the message is not recognized. + */ + INKNOWN_PAYLOAD_TYPE = 0x01U, + + /** + * Message too large. + * The message size exceeds the allowed limit. + */ + MESSAGE_TOO_LARGE = 0x02U, + + /** + * Out of memory. + * There is insufficient memory available to process the message. + */ + OUT_OF_MEMORY = 0x03U, + + /** + * Invalid payload length. + * The payload length specified in the header is invalid. + */ + INVALID_PAYLOAD_LENGTH = 0x04U, + }; + + /** + * @brief Enum representing DoIP action codes for DoIP announcement messages (ISO 13400). + * + * These action codes specify the next steps required after receiving a DoIP announcement message. + * Some codes are reserved for future use by ISO standards. + */ + enum class DoIpActionCodes : uint8_t + { + /** + * No further action required. + * Indicates that no additional steps are needed after the announcement. + */ + NO_FURTHER_ACTION_REQUIRED = 0x00U, + + /** + * Reserved for ISO (0x01). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x01 = 0x01U, + + /** + * Reserved for ISO (0x02). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x02 = 0x02U, + + /** + * Reserved for ISO (0x03). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x03 = 0x03U, + + /** + * Reserved for ISO (0x04). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x04 = 0x04U, + + /** + * Reserved for ISO (0x05). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x05 = 0x05U, + + /** + * Reserved for ISO (0x06). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x06 = 0x06U, + + /** + * Reserved for ISO (0x07). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x07 = 0x07U, + + /** + * Reserved for ISO (0x08). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x08 = 0x08U, + + /** + * Reserved for ISO (0x09). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x09 = 0x09U, + + /** + * Reserved for ISO (0x0A). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0A = 0x0AU, + + /** + * Reserved for ISO (0x0B). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0B = 0x0BU, + + /** + * Reserved for ISO (0x0C). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0C = 0x0CU, + + /** + * Reserved for ISO (0x0D). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0D = 0x0DU, + + /** + * Reserved for ISO (0x0E). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0E = 0x0EU, + + /** + * Reserved for ISO (0x0F). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0F = 0x0FU, + + /** + * Routing activation required. + * Indicates that routing activation is needed after the announcement message. + */ + ROUTING_ACTIVATION_REQUIRED = 0x10U, + }; + + /** + * @brief Enum representing DoIP routing activation response codes (ISO 13400). + * + * These codes are used in response to routing activation requests, providing status + * or error information related to the request. + */ + enum class DoIpRoutingResponseCodes : uint8_t + { + /** + * Unknown source address. + * The source address provided in the request is not recognized. + */ + UNKNOWN_SOURCE_ADDRESS = 0x00U, + + /** + * No free socket. + * There are no available sockets to establish the connection. + */ + NO_FREE_SOCKET = 0x01U, + + /** + * Wrong source address. + * The source address provided in the request is invalid. + */ + WRONG_SOURCE_ADDRESS = 0x02U, + + /** + * Source address already registered. + * The provided source address has already been activated. + */ + SOURCE_ADDRESS_ALREADY_REGISTERED = 0x03U, + + /** + * Missing authentication. + * The request is missing required authentication credentials. + */ + MISSING_AUTHENTICATION = 0x04U, + + /** + * Rejected confirmation. + * The confirmation of routing activation was rejected. + */ + REJECTED_CONFIRMATION = 0x05U, + + /** + * Unsupported activation type. + * The requested routing activation type is not supported. + */ + UNSUPPORTED_ACTIVATION_TYPE = 0x06U, + + /** + * Encrypted connection required (TLS). + * Indicates that the routing activation requires a secure TLS connection. + */ + ENCRYPTED_CONNECTION_TLS = 0x07U, + + /** + * Reserved for ISO (0x08). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x08 = 0x08U, + + /** + * Reserved for ISO (0x09). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x09 = 0x09U, + + /** + * Reserved for ISO (0x0A). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0A = 0x0AU, + + /** + * Reserved for ISO (0x0B). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0B = 0x0BU, + + /** + * Reserved for ISO (0x0C). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0C = 0x0CU, + + /** + * Reserved for ISO (0x0D). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0D = 0x0DU, + + /** + * Reserved for ISO (0x0E). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0E = 0x0EU, + + /** + * Reserved for ISO (0x0F). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0F = 0x0FU, + + /** + * Routing successfully activated. + * The routing activation request was processed successfully. + */ + ROUTING_SUCCESSFULLY_ACTIVATED = 0x10U, + + /** + * Confirmation required. + * Additional confirmation is required to complete the routing activation. + */ + CONFIRMATION_REQUIRED = 0x11U, + }; + + /** + * @brief Enum representing DoIP diagnostic message NACK codes (ISO 13400). + * + * These codes indicate reasons for rejecting or failing to process a diagnostic message + * in the DoIP protocol. + */ + enum class DoIpDiagnosticMessageNackCodes : uint8_t + { + /** + * Reserved for ISO (0x00). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x00 = 0x00U, + + /** + * Reserved for ISO (0x01). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x01 = 0x01U, + + /** + * Invalid source address. + * The source address specified in the message is invalid. + */ + INVALID_SOURCE_ADDRESS = 0x02U, + + /** + * Invalid target address. + * The target address specified in the message is invalid. + */ + INVALID_TARGET_ADDRESS = 0x03U, + + /** + * Message too large. + * The size of the message exceeds the maximum allowed limit. + */ + MESSAGE_TOO_LARGE = 0x04U, + + /** + * Out of memory. + * There is insufficient memory available to process the message. + */ + OUT_OF_MEMORY = 0x05U, + + /** + * Target unreachable. + * The specified target address cannot be reached. + */ + TARGET_UNREACHABLE = 0x06U, + + /** + * Unknown network. + * The message references a network that is not recognized or supported. + */ + UNKNOWN_NETWORK = 0x07U, + + /** + * Transport protocol error. + * An error occurred at the transport protocol level, preventing the message from being processed. + */ + TRANSPORT_PROTOCOL_ERROR = 0x08U, + }; + + /** + * @brief Enum representing DoIP diagnostic power mode codes (ISO 13400). + * + * These codes indicate the diagnostic power mode status of a DoIP entity, + * providing information about its readiness for diagnostic operations. + */ + enum class DoIpDiagnosticPowerModeCodes : uint8_t + { + /** + * Not ready. + * The DoIP entity is not ready to perform diagnostic operations. + */ + NOT_READY = 0x00U, + + /** + * Ready. + * The DoIP entity is ready to perform diagnostic operations. + */ + READY = 0x01U, + + /** + * Not supported. + * The DoIP entity does not support diagnostic power mode reporting. + */ + NOT_SUPPORTED = 0x02U + }; + + /** + * @brief Enum representing DoIP diagnostic acknowledgment codes (ISO 13400). + * + * These codes are used to acknowledge the receipt or processing of diagnostic messages + * in the DoIP protocol. + */ + enum class DoIpDiagnosticAckCodes : uint8_t + { + /** + * Acknowledgment. + * Indicates successful receipt or acknowledgment of a diagnostic message. + */ + ACK = 0x00U + }; + + /** + * @brief Enum representing DoIP entity status response codes (ISO 13400). + * + * These codes are used to indicate the role or type of a DoIP entity in the network. + */ + enum class DoIpEntityStatus : uint8_t + { + /** + * Gateway. + * The entity functions as a gateway, facilitating communication between networks. + */ + GATEWAY = 0x00U, + + /** + * Node. + * The entity functions as an individual node within the DoIP network. + */ + NODE = 0x01U + }; + + enum class DoIpSyncStatus : uint8_t + { + /** + * VIN and/or GID are synchronized. + */ + VIN_AND_OR_GID_ARE_SINCHRONIZED = 0x00, + + /** + * Reserved for ISO (0x01). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x01 = 0x01U, + + /** + * Reserved for ISO (0x02). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x02 = 0x02U, + + /** + * Reserved for ISO (0x03). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x03 = 0x03U, + + /** + * Reserved for ISO (0x04). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x04 = 0x04U, + + /** + * Reserved for ISO (0x05). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x05 = 0x05U, + + /** + * Reserved for ISO (0x06). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x06 = 0x06U, + + /** + * Reserved for ISO (0x07). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x07 = 0x07U, + + /** + * Reserved for ISO (0x08). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x08 = 0x08U, + + /** + * Reserved for ISO (0x09). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x09 = 0x09U, + + /** + * Reserved for ISO (0x0A). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0A = 0x0AU, + + /** + * Reserved for ISO (0x0B). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0B = 0x0BU, + /** + * Reserved for ISO (0x0C). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0C = 0x0CU, + + /** + * Reserved for ISO (0x0D). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0D = 0x0DU, + + /** + * Reserved for ISO (0x0E). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0E = 0x0EU, + + /** + * Reserved for ISO (0x08). + * Reserved for future use as per ISO standards. + */ + RESERVED_ISO_0x0F = 0x0FU, + + /** + * VIN and/or GID are not synchronized. + */ + VIN_AND_OR_GID_ARE_NOT_SINCHRONIZED = 0x10U, + + /** + * Check whether this field is initialised or not + */ + NON_INITIALIZED + }; + + /** + * @brief Enum representing DoIP diagnostic ports (ISO 13400). + * + * These ports are used for communication in the DoIP protocol over different transport layers. + */ + enum class DoIpPorts : uint16_t + { + /** + * UDP Port. + * The standard port for DoIP communication over UDP. + */ + UDP_PORT = 13400U, + + /** + * TCP Port. + * The standard port for DoIP communication over TCP. + */ + TCP_PORT = 13400U, + + /** + * TLS Port. + * The standard port for DoIP communication over a secure TLS connection. + */ + TLS_PORT = 3496U + }; + +} // namespace pcpp diff --git a/Packet++/header/DoIpLayer.h b/Packet++/header/DoIpLayer.h new file mode 100644 index 0000000000..8128286ca0 --- /dev/null +++ b/Packet++/header/DoIpLayer.h @@ -0,0 +1,250 @@ +#pragma once + +#include +#include +#include "Layer.h" +#include "IpAddress.h" +#include "MacAddress.h" +#include "Logger.h" +#include "GeneralUtils.h" +#include "DoIpLayerData.h" + +/// @file + +/** + * @namespace pcpp + * @brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * @struct doiphdr + * Represents an DoIP protocol header + */ +#pragma pack(push, 1) + struct doiphdr + { + /** DoIP version (DOIPV) */ + uint8_t protocolVersion; + /** DoIP invert version (DOIPIV). Inverse of protocol version */ + uint8_t invertProtocolVersion; + /** DoIP payload type (DOIPT)*/ + uint16_t payloadType; + /** DoIP content payload length (DOIPL)*/ + uint32_t payloadLength; + }; +#pragma pack(pop) + + /** + * @class DoIpLayer + * Represents an DoIP protocol layer. Currently only IPv4 DoIP messages are supported + */ + class DoIpLayer : public Layer + { + // class DoIpLayerData; + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to @ref doiphdr) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + DoIpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, DOIP) + {} + + /** + * A constructor that creates an generic doip layer and set header and payload fields + * @param[in] Fields DoIpMessageFields contains all doipMessage specification based on its payload type + */ + DoIpLayer(DoIpProtocolVersion version, DoIpPayloadTypes type, const IDoIpMessageData* data = nullptr); + + /** + * A constructor that create a doip announcement message with all + * zeros for vin, eid, gid and no further action required + */ + DoIpLayer(); + + /** + * init doip layer with all zeros with size of doip header + */ + void initLayer(); + + /** + * A destructor for DoIpLayer class + */ + ~DoIpLayer() override {}; + + /** + * Get a pointer to the DoIP header. Notice this points directly to the data, so every change will change the + * actual packet data + * @return A pointer to the @ref doiphdr + */ + doiphdr* getDoIpHeader() const + { + return reinterpret_cast(m_Data); + } + /** + * Check the integrity of protocol version in doip header + * @return true if version has no integration errors + */ + bool resolveProtocolVersion() const; + + /** + * Check the integrity of length field in doip header + * @return true if length represent the exact payload arg struct size + */ + bool resolvePayloadLength() const; + + /** + * Get the version of DOIP protocol + * @return DoIpProtocolVersion presenting the used protocol version (DOIPV) + */ + DoIpProtocolVersion getProtocolVersion() const; + + /** + * Get the version of DOIP protocol + * @return string presentation the used protocol version (DOIPV) + */ + std::string getProtocolVersionAsStr() const; + + /** + * Set the version of DOIP protocol + * @param[in] version the version of DOIP protocol to set, restricted to existent doip version + */ + void setProtocolVersion(DoIpProtocolVersion version); + + /** + * Get the invert version of DOIP protocol + * @return A uint8_t presenting the used protocol invert version (DOIPV) + */ + uint8_t getInvertProtocolVersion() const; + + /** + * Set the invert protocol version of DOIP protocol + * @param[in] version the invert version of DOIP protocol to set + */ + void setInvertProtocolVersion(uint8_t iVersion); + + /** + * Get the doip payload type + * @return DoIpPayloadTypes presenting the message doip payload type + */ + DoIpPayloadTypes getPayloadType() const; + + /** + * Get the doip payload type as string + * @return uint16_t presenting the message doip payload type as string + */ + std::string getPayloadTypeAsStr() const; + + /** + * Set the doip payload type + * @param[in] payloadType the payload type to set + */ + void setPayloadType(DoIpPayloadTypes payloadType); + + /** + * Get the doip payload length + * @return uint32_t presenting the length of doip paylad not including the header + */ + uint32_t getPayloadLength() const; + + /** + * Set the doip payload length + * @param[in] length the doip payload length to set + */ + void setPayloadLength(uint32_t length); + + /** + * copy data from msgFields to dest + * @param[in] dest pointer to where start copying + * @param[in] msgFields the doip Fields to copy + */ + void serializeData(uint8_t* dest, std::vector data); + + /** + * A static method that checks whether a port is considered as a DOIP port + * @param[in] port The port number to check + * @return True if this is a DOIP port number, false otherwise + */ + static inline bool isDoIpPort(uint16_t port); + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of an DOIP layer + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent an DOIP layer + */ + static inline bool isDataValid(const uint8_t* data, size_t dataLen); + + /** + * @brief Builds the DoIP layer based on the payload type and provided data. + * + * This function configures the DoIP layer with the appropriate payload type, payload length, + * and data, depending on the specified payload type. If the payload type does not require + * additional data, the payload length is set to zero. For payloads that require data, the data + * is serialized and added to the layer. + * + * @param type The DoIP payload type to set for this layer. + * @param data Pointer to the message data (of type IDoIpMessageData) to be serialized into the layer. + * This parameter can be nullptr for payload types that do not require additional data. + * + * @note If the payload type requires data and the `data` parameter is `nullptr`, an error message + * is logged, and the function does not build the layer. + */ + void buildLayer(DoIpPayloadTypes type, const IDoIpMessageData* data = nullptr); + + /** + * @brief Resolves and validates the DoIP layer. + * + * This function validates the protocol version and payload length of the DoIP layer. + * If either validation fails, an error is logged, and the function returns `false`. + * + * @return `true` if both the protocol version and payload length are valid; + * otherwise, `false`. + * + * @note This function is typically used to ensure the integrity of the DoIP layer + * before further processing or transmission. + */ + bool resolveLayer() const; + + // implement abstract methods + + /** + * TODO, parse UDS layer + */ + void parseNextLayer() override + {} + + /** + * @return The size of @ref doiphdr + attached fields length + */ + size_t getHeaderLen() const override + { + return m_DataLen; + } + + std::string toString() const override; + + void computeCalculateFields() override {}; + + OsiModelLayer getOsiModelLayer() const override + { + return OsiModelTransportLayer; + } + }; + + // inline methods definition + inline bool DoIpLayer::isDoIpPort(uint16_t port) + { + return ((DoIpPorts)port == DoIpPorts::UDP_PORT || (DoIpPorts)port == DoIpPorts::TCP_PORT || + (DoIpPorts)port == DoIpPorts::TLS_PORT); + } + + inline bool DoIpLayer::isDataValid(const uint8_t* data, size_t dataLen) + { + return (data && dataLen >= sizeof(doiphdr)); + } +} // namespace pcpp diff --git a/Packet++/header/DoIpLayerData.h b/Packet++/header/DoIpLayerData.h new file mode 100644 index 0000000000..8c88d0ab04 --- /dev/null +++ b/Packet++/header/DoIpLayerData.h @@ -0,0 +1,857 @@ +#pragma once + +#include +#include +#include +#include "EndianPortable.h" +#include "Logger.h" +#include "GeneralUtils.h" +#include "DoIpEnumToString.h" + +/// @file + +/** + * @namespace pcpp + * @brief The main namespace for the PcapPlusPlus library + */ +namespace pcpp +{ +/** + * @brief Length of the External Identifier (EID) field. + */ +#define DOIP_EID_LEN 6 + +/** + * @brief Length of the Group Identifier (GID) field. + */ +#define DOIP_GID_LEN 6 + +/** + * @brief Length of the Vehicle Identification Number (VIN) field. + */ +#define DOIP_VIN_LEN 17 + +/** + * @brief Length of the Reserved ISO field. + */ +#define DOIP_RESERVED_ISO_LEN 4 + +/** + * @brief Length of the Reserved OEM field. + */ +#define DOIP_RESERVED_OEM_LEN 4 + + // forward declaration for DoIpLayer class + class DoIpLayer; + + /** + * @brief A pure abstract class representing the basic structure of DoIP messages. + * + * This interface defines methods to retrieve the type, string representation, + * and binary data of DoIP messages. All DoIP message classes must implement this interface. + */ + class IDoIpMessageData + { + public: + virtual ~IDoIpMessageData() = default; + + /** + * @brief Returns the type of the DoIP message. + * @return The type of the message as a `DoIpPayloadTypes` enum. + */ + virtual DoIpPayloadTypes getType() const = 0; + + /** + * @brief Converts the message data to a human-readable string. + * @return The string representation of the message. + */ + virtual std::string toString() const = 0; + + /** + * @brief Retrieves the raw binary data of the message. + * @return The message data as a vector of bytes. + */ + virtual std::vector getData() const = 0; + + /** + * @brief build IDoIpMessageData from DoIpLayer + * @param[in] doipLayer pointer to doipLayer to retrieve data from + * @return true if encapsulating process is done successufly else false. + * + * @exception Logs an error and returns `false` if: + * - The input layer is null. + * - The payload type of doipLayer does not match the expected type for IDoIpMessageData. + * - The input data length is insufficient for parsing all required fields. + */ + virtual bool buildFromLayer(DoIpLayer* doipLayer) = 0; + }; + + /** + * @class RoutingActivationRequestData + * @brief Represents a Routing Activation Request message in DoIP. + * + * This class encapsulates data for a Routing Activation Request message, + * including source address, activation type, and reserved fields. + */ + class RoutingActivationRequestData : public IDoIpMessageData + { + public: + /** + * @brief Default constructor for the RoutingActivationRequestData class. + * + * Initializes a `RoutingActivationRequestData` instance with default values: + * - `sourceAddress` is set to `0x0000`. + * - `activationType` is set to `DoIpActivationTypes::Default`. + * - `reservedIso` and `reservedOem` fields are zero-initialized. + * This constructor provides a default initialization state for routing activation request + * data, ensuring compliance with the DoIP protocol requirements. + */ + RoutingActivationRequestData(); + + uint16_t sourceAddress; /**< Source address of the message. */ + DoIpActivationTypes activationType; /**< The activation type (e.g., activate, deactivate). */ + std::array reservedIso; /**< Reserved ISO bytes. */ + std::unique_ptr> reservedOem; /**< Reserved OEM bytes. */ + + /** + * @brief Returns the type of the message. + * @return `DoIpPayloadTypes::ROUTING_ACTIVATION_REQUEST`. + */ + DoIpPayloadTypes getType() const override; + + /** + * @brief Converts the message data to a human-readable string. + * @return A string representation of the Routing Activation Request message. + */ + std::string toString() const override; + + /** + * @brief Retrieves the raw binary data of the message. + * @return A vector of bytes representing the message data. + */ + std::vector getData() const override; + + /** + * @brief Parses and initializes the Routing Activation Request data from a DoIpLayer. + * + * This method validates the provided DoIpLayer to ensure it corresponds to the + * Routing Activation Request payload type. It extracts the source address, activation + * type, reserved ISO bytes, and optionally reserved OEM bytes if present. + * + * @param[in] doipLayer Pointer to the DoIpLayer containing the Routing Activation Request data. + * @return `true` if parsing and initialization were successful, `false` otherwise. + * + * @note This method overrides the base class implementation and adds specific parsing + * logic for the Routing Activation Request message. + * + * The following fields are parsed: + * - `sourceAddress`: The source address of the message. + * - `activationType`: The type of activation requested. + * - `reservedIso`: Reserved bytes as defined by ISO specifications. + * - `reservedOem`: Reserved bytes as defined by OEM specifications, only if present. + */ + bool buildFromLayer(DoIpLayer* doipLayer) override; + }; + + /** + * @class RoutingActivationResponseData + * @brief Represents a Routing Activation Response message in DoIP. + * + * This class encapsulates data for a Routing Activation Response message, + * including logical address, source address, response code, and reserved fields. + */ + class RoutingActivationResponseData : public IDoIpMessageData + { + public: + /** + * @brief Default constructor for the RoutingActivationResponseData class. + * Initializes a `RoutingActivationResponseData` instance with default values: + * - `logicalAddressExternalTester` is set to `0x0000`. + * - `sourceAddress` is set to `0x0000`. + * - `responseCode` is set to DoIpRoutingResponseCodes::CONFIRMATION_REQUIRED. + * - `reservedIso` fields is zero-initialized. + * This constructor provides a default initialization state for routing activation response + * data, ensuring compliance with the DoIP protocol requirements. + */ + RoutingActivationResponseData(); + + uint16_t logicalAddressExternalTester; /**< Logical address of the external tester. */ + uint16_t sourceAddress; /**< Source address of the message. */ + DoIpRoutingResponseCodes responseCode; /**< Response code indicating success or failure. */ + std::array reservedIso; /**< Reserved ISO bytes. */ + std::unique_ptr> reservedOem; /**< Reserved OEM bytes. */ + + /** + * @brief Returns the type of the message. + * @return `DoIpPayloadTypes::ROUTING_ACTIVATION_RESPONSE`. + */ + DoIpPayloadTypes getType() const override; + + /** + * @brief Converts the message data to a human-readable string. + * @return A string representation of the Routing Activation Response message. + */ + std::string toString() const override; + + /** + * @brief Retrieves the raw binary data of the message. + * @return A vector of bytes representing the message data. + */ + std::vector getData() const override; + + /** + * @brief Parses the Routing Activation Response data from a DoIpLayer. + * + * This method validates and extracts the necessary fields from the provided + * DoIpLayer. It ensures the layer corresponds to the Routing Activation Response + * payload type and parses fields including the logical tester address, source + * address, response code, and reserved fields. + * + * @param[in] doipLayer Pointer to the DoIpLayer containing the Routing Activation Response data. + * @return `true` if parsing was successful, `false` otherwise. + */ + bool buildFromLayer(DoIpLayer* doipLayer) override; + }; + + /** + * @class GenericHeaderNackData + * @brief Represents a Generic Header Negative Acknowledgment message in DoIP. + * + * This class encapsulates data for a Generic Header NACK message, including + * the NACK code to indicate the failure. + */ + class GenericHeaderNackData : public IDoIpMessageData + { + public: + /** + * @brief Default constructor for the GenericHeaderNackData class. + * + * This constructor initializes a `GenericHeaderNackData` instance with default values: + * - `genericNackCode` is set to `DoIpGenericHeaderNackCodes::INVALID_PAYLOAD_LENGTH`. + */ + GenericHeaderNackData(); + + DoIpGenericHeaderNackCodes genericNackCode; /**< The NACK code indicating the error. */ + + /** + * @brief Returns the type of the message. + * @return `DoIpPayloadTypes::GENERIC_HEADER_NEG_ACK`. + */ + DoIpPayloadTypes getType() const override; + + /** + * @brief Converts the message data to a human-readable string. + * @return A string representation of the Generic Header NACK message. + */ + std::string toString() const override; + + /** + * @brief Retrieves the raw binary data of the message. + * @return A vector of bytes representing the message data. + */ + std::vector getData() const override; + + /** + * @brief Parses and initializes the Generic Header NACK data from a DoIpLayer. + * + * This method validates the provided DoIpLayer to ensure it corresponds to the + * Generic Header NACK payload type. It extracts the `genericNackCode` field from the layer. + * + * @param[in] doipLayer Pointer to the DoIpLayer containing the Generic Header NACK data. + * @return `true` if parsing and initialization were successful, `false` otherwise. + * + * @note The method checks for null pointers and verifies that the payload type matches + * `DoIpPayloadTypes::GENERIC_HEADER_NEG_ACK`. Logs an error in case of invalid data. + * + * The following field is parsed: + * - `genericNackCode`: The NACK code indicating the type of error. + */ + bool buildFromLayer(DoIpLayer* doipLayer) override; + }; + + /** + * @class VehicleIdentificationRequestEIDData + * @brief Represents a Vehicle Identification Request with EID message in DoIP. + * + * This class encapsulates data for a Vehicle Identification Request message + * that includes the Electronic Identifier (EID). + */ + class VehicleIdentificationRequestEIDData : public IDoIpMessageData + { + public: + /** + * @brief Default constructor for the VehicleIdentificationRequestEIDData class. + * + * This constructor initializes a `VehicleIdentificationRequestEIDData` instance with default values: + * - `eid` (Entity Identifier) is initialized to all zeros. + */ + VehicleIdentificationRequestEIDData(); + + std::array eid; /**< Electronic Identifier (EID). */ + + /** + * @brief Returns the type of the message. + * @return `DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_EID`. + */ + DoIpPayloadTypes getType() const override; + + /** + * @brief Converts the message data to a human-readable string. + * @return A string representation of the Vehicle Identification Request EID message. + */ + std::string toString() const override; + + /** + * @brief Retrieves the raw binary data of the message. + * @return A vector of bytes representing the message data. + */ + std::vector getData() const override; + + /** + * @brief Parses and initializes the Vehicle Identification Request with EID data from a DoIpLayer. + * + * This method validates the provided DoIpLayer to ensure it corresponds to the + * Vehicle Identification Request with EID payload type. It extracts the EID field from the layer. + * + * @param[in] doipLayer Pointer to the DoIpLayer containing the Vehicle Identification Request with EID data. + * @return `true` if parsing and initialization were successful, `false` otherwise. + * + * @note The method checks for null pointers and verifies that the payload type matches + * `DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_EID`. Logs an error if the data is invalid. + * + * The following field is parsed: + * - `eid`: The EID (Extended Identifier), extracted as a byte array of length `DOIP_EID_LEN`. + */ + bool buildFromLayer(DoIpLayer* doipLayer) override; + }; + + /** + * @class VehicleIdentificationRequestVINData + * @brief Represents a Vehicle Identification Request with VIN message in DoIP. + * + * This class encapsulates data for a Vehicle Identification Request message + * that includes the Vehicle Identification Number (VIN). + */ + class VehicleIdentificationRequestVINData : public IDoIpMessageData + { + public: + /** + * @brief Default constructor for the VehicleIdentificationRequestVINData class. + * + * This constructor initializes a `VehicleIdentificationRequestVINData` instance with default values: + * - `vin` (Vehicle Identification Number) is initialized to all zeros. + */ + VehicleIdentificationRequestVINData(); + + std::array vin; /**< Vehicle Identification Number (VIN). */ + + /** + * @brief Returns the type of the message. + * @return `DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_VIN`. + */ + DoIpPayloadTypes getType() const override; + + /** + * @brief Converts the message data to a human-readable string. + * @return A string representation of the Vehicle Identification Request VIN message. + */ + std::string toString() const override; + + /** + * @brief Retrieves the raw binary data of the message. + * @return A vector of bytes representing the message data. + */ + std::vector getData() const override; + + /** + * @brief Parses and initializes the Vehicle Identification Request with VIN data from a DoIpLayer. + * + * This method validates the provided DoIpLayer to ensure it corresponds to the + * Vehicle Identification Request with VIN payload type. It extracts the VIN (Vehicle Identification Number) + * field from the payload data and populates the class instance. + * + * @param[in] doipLayer Pointer to the DoIpLayer containing the Vehicle Identification Request with VIN data. + * @return `true` if parsing and initialization were successful, `false` otherwise. + * + * @note The method performs the following checks: + * - Ensures the `doipLayer` is not null. + * - Validates that the payload type matches `DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_VIN`. + * - Checks that the data length is sufficient to extract the VIN field. + * + * Logs errors if the data is invalid or the payload is incompatible. + * + * The following field is parsed: + * - `vin`: The Vehicle Identification Number (VIN), extracted as a byte array of length `DOIP_VIN_LEN`. + */ + bool buildFromLayer(DoIpLayer* doipLayer) override; + }; + + /** + * @class VehicleAnnouncementData + * @brief Represents a Vehicle Announcement message in DoIP. + * + * This class encapsulates data for a Vehicle Announcement message, including + * VIN, logical address, EID, GID, and further action required. + */ + class VehicleAnnouncementData : public IDoIpMessageData + { + public: + /** + * @brief Default constructor for the VehicleAnnouncementData class. + * + * This constructor initializes a `VehicleAnnouncementData` instance with default values: + * - `vin` is initialized to all zeros. + * - `logicalAddress` is set to `0`. + * - `eid` (Entity Identifier) is initialized to all zeros. + * - `gid` (Group Identifier) is initialized to all zeros. + * - `furtherActionRequired` is set to `DoIpActionCodes::NO_FURTHER_ACTION_REQUIRED`. + * - `syncStatus` is set to `DoIpSyncStatus::NON_INITIALIZED`, indicating that the sync status is uninitialized. + */ + VehicleAnnouncementData(); + + std::array vin; /**< Vehicle Identification Number (VIN). */ + uint16_t logicalAddress; /**< Logical address of the vehicle. */ + std::array eid; /**< Electronic Identifier (EID). */ + std::array gid; /**< Group Identifier (GID). */ + DoIpActionCodes furtherActionRequired; /**< Action required after the announcement. */ + DoIpSyncStatus syncStatus; /**< version and invert version are synchronized. */ + + /** + * @brief Returns the type of the message. + * @return `DoIpPayloadTypes::ANNOUNCEMENT_MESSAGE`. + */ + DoIpPayloadTypes getType() const override; + + /** + * @brief Converts the message data to a human-readable string. + * @return A string representation of the Vehicle Announcement message. + */ + std::string toString() const override; + + /** + * @brief Retrieves the raw binary data of the message. + * @return A vector of bytes representing the message data. + */ + std::vector getData() const override; + + /** + * @brief Parses and initializes the Vehicle Announcement data from a DoIpLayer. + * + * This method validates the provided DoIpLayer to ensure it corresponds to the + * Announcement Message payload type. It extracts fields such as VIN, logical address, EID, GID, + * further action required, and synchronization status from the payload data. + * + * @param[in] doipLayer Pointer to the DoIpLayer containing the Vehicle Announcement data. + * @return `true` if parsing and initialization were successful, `false` otherwise. + * + * @note The method performs the following checks: + * - Ensures the `doipLayer` is not null. + * - Validates that the payload type matches `DoIpPayloadTypes::ANNOUNCEMENT_MESSAGE`. + * - Checks that the data length is sufficient to extract all required fields. + * + * Logs errors if the data is invalid or the payload is incompatible. + * + * The following fields are parsed: + * - `vin`: Vehicle Identification Number (VIN). + * - `logicalAddress`: Logical address of the vehicle. + * - `eid`: End Identifier. + * - `gid`: Group Identifier. + * - `furtherActionRequired`: Further action required code. + * - `syncStatus`: VIN/GID synchronization status (if present). + */ + bool buildFromLayer(DoIpLayer* doipLayer) override; + }; + + /** + * @class AliveCheckResponseData + * @brief Represents an Alive Check Response message in DoIP. + * + * This class encapsulates data for an Alive Check Response message, + * including the source address. + */ + class AliveCheckResponseData : public IDoIpMessageData + { + public: + /** + * @brief Default constructor for the AliveCheckResponseData class. + * + * This constructor initializes an `AliveCheckResponseData` instance with default values: + * - `sourceAddress` is set to `0x0000`. + */ + AliveCheckResponseData(); + + uint16_t sourceAddress; /**< Source address of the Alive Check Response message. */ + + /** + * @brief Returns the type of the message. + * @return `DoIpPayloadTypes::ALIVE_CHECK_RESPONSE`. + */ + DoIpPayloadTypes getType() const override; + + /** + * @brief Converts the message data to a human-readable string. + * @return A string representation of the Alive Check Response message. + */ + std::string toString() const override; + + /** + * @brief Retrieves the raw binary data of the message. + * @return A vector of bytes representing the message data. + */ + std::vector getData() const override; + + /** + * @brief Parses and initializes the Alive Check Response data from a DoIpLayer. + * + * This method validates the provided DoIpLayer to ensure it corresponds to the + * Alive Check Response payload type. It extracts the `sourceAddress` field from the payload data. + * + * @param[in] doipLayer Pointer to the DoIpLayer containing the Alive Check Response data. + * @return `true` if parsing and initialization were successful, `false` otherwise. + * + * @note The method performs the following checks: + * - Ensures the `doipLayer` is not null. + * - Validates that the payload type matches `DoIpPayloadTypes::ALIVE_CHECK_RESPONSE`. + * - Checks that the data length is sufficient to extract the `sourceAddress`. + * + * Logs errors if the data is invalid or the payload is incompatible. + * + * The following field is parsed: + * - `sourceAddress`: The source address of the response. + */ + bool buildFromLayer(DoIpLayer* doipLayer) override; + }; + + /** + * @class DiagnosticPowerModeResponseData + * @brief Represents a Diagnostic Power Mode Response message in DoIP. + * + * This class encapsulates data for a Diagnostic Power Mode Response message, + * including a power mode code indicating the current power mode. + */ + class DiagnosticPowerModeResponseData : public IDoIpMessageData + { + public: + /** @brief Default constructor for the DiagnosticPowerModeResponseData class. + * + * Initializes a DiagnosticPowerModeResponseData instance with the power mode + * response code set to `NOT_READY`. This indicates that the system is not yet + * ready to respond to diagnostic power mode requests. + */ + DiagnosticPowerModeResponseData(); + + DoIpDiagnosticPowerModeCodes powerModeCode; /**< Code representing the power mode. */ + + /** + * @brief Returns the type of the message. + * @return `DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_RESPONSE`. + */ + DoIpPayloadTypes getType() const override; + + /** + * @brief Converts the message data to a human-readable string. + * @return A string representation of the Diagnostic Power Mode Response message. + */ + std::string toString() const override; + + /** + * @brief Retrieves the raw binary data of the message. + * @return A vector of bytes representing the message data. + */ + std::vector getData() const override; + + /** + * @brief Parses and initializes the Diagnostic Power Mode Response data from a DoIpLayer. + * + * This method validates the provided DoIpLayer to ensure it corresponds to the + * Diagnostic Power Mode Response payload type. It extracts the `powerModeCode` field from the payload data. + * + * @param[in] doipLayer Pointer to the DoIpLayer containing the Diagnostic Power Mode Response data. + * @return `true` if parsing and initialization were successful, `false` otherwise. + * + * @note The method performs the following checks: + * - Ensures the `doipLayer` is not null. + * - Validates that the payload type matches `DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_RESPONSE`. + * - Checks that the data length is sufficient to extract the `powerModeCode`. + * + * Logs errors if the data is invalid or the payload is incompatible. + * + * The following field is parsed: + * - `powerModeCode`: The diagnostic power mode response code. + */ + bool buildFromLayer(DoIpLayer* doipLayer) override; + }; + + /** + * @class EntityStatusResponseData + * @brief Represents an Entity Status Response message in DoIP. + * + * This class encapsulates data for an Entity Status Response message, + * including status, maximum concurrent sockets, open sockets, and maximum data size. + */ + class EntityStatusResponseData : public IDoIpMessageData + { + public: + /** + * @brief Default constructor for the EntityStatusResponseData class. + * + * Initializes an `EntityStatusResponseData` instance with the following default values: + * - `status`: Set to `DoIpEntityStatus::GATEWAY`, indicating the entity is acting as a gateway. + * - `maxConcurrentSockets`: Set to `0`, meaning no concurrent sockets are allowed by default. + * - `currentlyOpenSockets`: Set to `0`, indicating no sockets are currently open. + * - `maxDataSize`: Set to `nullptr`, meaning no data for this field. can be assigned after object creation. + * + * @code + * EntityStatusResponseData data; + * data.maxDataSize = std::unique_ptr>(new std::array {0x00, 0x01, 0x02, + * 0x03}); + * @endcode + */ + EntityStatusResponseData(); + + DoIpEntityStatus nodeType; /**< Status of the entity. */ + uint8_t maxConcurrentSockets; /**< Maximum number of concurrent sockets. */ + uint8_t currentlyOpenSockets; /**< Number of currently open sockets. */ + std::unique_ptr> + maxDataSize; /**< Maximum data size that can be handled (4 bytes optional). */ + + /** + * @brief Returns the type of the message. + * @return `DoIpPayloadTypes::ENTITY_STATUS_RESPONSE`. + */ + DoIpPayloadTypes getType() const override; + + /** + * @brief Converts the message data to a human-readable string. + * @return A string representation of the Entity Status Response message. + */ + std::string toString() const override; + + /** + * @brief Retrieves the raw binary data of the message. + * @return A vector of bytes representing the message data. + */ + std::vector getData() const override; + + /** + * @brief Parses and initializes the Entity Status Response data from a DoIpLayer. + * + * This method validates the provided DoIpLayer to ensure it corresponds to the + * Entity Status Response payload type. It extracts fields such as `nodeType`, + * `maxConcurrentSockets`, `currentlyOpenSockets`, and optionally `maxDataSize` from the payload data. + * + * @param[in] doipLayer Pointer to the DoIpLayer containing the Entity Status Response data. + * @return `true` if parsing and initialization were successful, `false` otherwise. + * + * @note The method performs the following checks: + * - Ensures the `doipLayer` is not null. + * - Validates that the payload type matches `DoIpPayloadTypes::ENTITY_STATUS_RESPONSE`. + * - Checks that the data length is sufficient for the fixed fields and optional `maxDataSize`. + * + * Logs errors if the data is invalid or the payload is incompatible. + * + * The following fields are parsed: + * - `nodeType`: Entity status indicating the role of the entity. + * - `maxConcurrentSockets`: Maximum allowed concurrent sockets. + * - `currentlyOpenSockets`: Number of currently open sockets. + * - `maxDataSize` (optional): Maximum data size supported (4 bytes). + */ + bool buildFromLayer(DoIpLayer* doipLayer) override; + }; + + /** + * @class DiagnosticMessageData + * @brief Represents a Diagnostic Message in DoIP. + * This class encapsulates data for a Diagnostic Message, including source + * and target addresses, as well as diagnostic data. + */ + class DiagnosticMessageData : public IDoIpMessageData + { + public: + /** + * @brief Default constructor for the DiagnosticMessageData class. + * + * Initializes a `DiagnosticMessageData` instance with the following default values: + * - `sourceAddress`: Set to `0x0000`. + * - `targetAddress`: Set to `0x0000`. + * - `diagnosticData`: Initialized to `{0x22, 0xf1, 0x68}` as a default diagnostic payload. + */ + DiagnosticMessageData(); + + uint16_t sourceAddress; /**< Source address of the message. */ + uint16_t targetAddress; /**< Target address for the diagnostic message. */ + std::vector diagnosticData; /**< Diagnostic message data with dynamic length. */ + + /** + * @brief Returns the type of the message. + * @return `DoIpPayloadTypes::DIAGNOSTIC_MESSAGE`. + */ + DoIpPayloadTypes getType() const override; + + /** + * @brief Converts the message data to a human-readable string. + * @return A string representation of the Diagnostic Message. + */ + std::string toString() const override; + + /** + * @brief Retrieves the raw binary data of the message. + * @return A vector of bytes representing the message data. + */ + std::vector getData() const override; + + /** + * @brief Parses and initializes the Diagnostic Message data from a DoIpLayer. + * + * This method validates the provided DoIpLayer to ensure it corresponds to the + * Diagnostic Message payload type. It extracts fields such as `sourceAddress`, + * `targetAddress`, and `diagnosticData` from the payload data. + * + * @param[in] doipLayer Pointer to the DoIpLayer containing the Diagnostic Message data. + * @return `true` if parsing and initialization were successful, `false` otherwise. + * + * @note The method performs the following checks: + * - Ensures the `doipLayer` is not null. + * - Validates that the payload type matches `DoIpPayloadTypes::DIAGNOSTIC_MESSAGE`. + * - Checks that the data length is sufficient for the fixed fields and dynamic `diagnosticData`. + * + * Logs errors if the data is invalid or the payload is incompatible. + * + * The following fields are parsed: + * - `sourceAddress`: Source address of the diagnostic message (2 bytes). + * - `targetAddress`: Target address of the diagnostic message (2 bytes). + * - `diagnosticData`: Variable length data representing the diagnostic payload. + */ + bool buildFromLayer(DoIpLayer* doipLayer) override; + }; + + /** + * @class DiagnosticAckMessageData + * @brief Represents a Diagnostic Acknowledgment Message in DoIP. + * + * This class encapsulates data for a Diagnostic Acknowledgment Message, + * including source and target addresses, as well as the acknowledgment code. + */ + class DiagnosticAckMessageData : public IDoIpMessageData + { + public: + /** + * @brief Default constructor for the DiagnosticAckMessageData class. + * + * Initializes a `DiagnosticAckMessageData` instance with the following default values: + * - `sourceAddress`: Set to `0x0000`. + * - `targetAddress`: Set to `0x0000`. + * - `ackCode`: Set to `DoIpDiagnosticAckCodes::ACK`. + * - `previousMessage`: Initialized to `{0x22, 0xf1, 0x01, 0x02}`. + */ + DiagnosticAckMessageData(); + + uint16_t sourceAddress; /**< Source address of the acknowledgment message. */ + uint16_t targetAddress; /**< Target address of the acknowledgment message. */ + DoIpDiagnosticAckCodes ackCode; /**< Acknowledgment code. */ + std::vector previousMessage; /**< Previous acknowlged message. */ + + /** + * @brief Returns the type of the message. + * @return `DoIpPayloadTypes::DIAGNOSTIC_ACK_MESSAGE`. + */ + DoIpPayloadTypes getType() const override; + + /** + * @brief Converts the message data to a human-readable string. + * @return A string representation of the Diagnostic Acknowledgment Message. + */ + std::string toString() const override; + + /** + * @brief Retrieves the raw binary data of the message. + * @return A vector of bytes representing the message data. + */ + std::vector getData() const override; + + /** + * @brief Parses and initializes the Diagnostic Acknowledgment Message data from a DoIpLayer. + * + * This method validates the provided DoIpLayer to ensure it corresponds to the + * Diagnostic Acknowledgment Message payload type. It extracts fields such as `sourceAddress`, + * `targetAddress`, `ackCode`, and `previousMessage` from the payload data. + * + * @param[in] doipLayer Pointer to the DoIpLayer containing the Diagnostic Acknowledgment Message data. + * @return `true` if parsing and initialization were successful, `false` otherwise. + * + * @note The method performs the following checks: + * - Ensures the `doipLayer` is not null. + * - Validates that the payload type matches `DoIpPayloadTypes::DIAGNOSTIC_ACK_MESSAGE`. + * - Checks that the data length is sufficient for the fixed fields and the dynamic `previousMessage`. + * + * Logs errors if the data is invalid or the payload is incompatible. + * + * The following fields are parsed: + * - `sourceAddress`: Source address of the acknowledgment message (2 bytes). + * - `targetAddress`: Target address of the acknowledgment message (2 bytes). + * - `ackCode`: Acknowledgment code (1 byte, converted from enum). + * - `previousMessage`: std::vector representing the previous message. + */ + bool buildFromLayer(DoIpLayer* doipLayer) override; + }; + + /** + * @class DiagnosticNackMessageData + * @brief Represents a Diagnostic Negative Acknowledgment Message in DoIP. + * + * This class encapsulates data for a Diagnostic Negative Acknowledgment + * Message, including source and target addresses, as well as the NACK code. + */ + class DiagnosticNackMessageData : public IDoIpMessageData + { + public: + /** + * @brief Default constructor for the DiagnosticNackMessageData class. + * + * Initializes a `DiagnosticNackMessageData` instance with default values: + * - `sourceAddress` is set to `0x0000`. + * - `targetAddress` is set to `0x0000`. + * - `nackCode` is set to `DoIpDiagnosticMessageNackCodes::INVALID_SOURCE_ADDRESS`. + * - `previousMessage` is set to {0x22, 0xf1, 01, 0x02} as the non acknowledged diagnostic + * message starts with these four bytes + */ + DiagnosticNackMessageData(); + + uint16_t sourceAddress; /**< Source address of the NACK message. */ + uint16_t targetAddress; /**< Target address of the NACK message. */ + DoIpDiagnosticMessageNackCodes nackCode; /**< Negative acknowledgment code. */ + std::vector previousMessage; /**< Previous acknowlged message. */ + + /** + * @brief Returns the type of the message. + * @return `DoIpPayloadTypes::DIAGNOSTIC_NACK_MESSAGE`. + */ + DoIpPayloadTypes getType() const override; + + /** + * @brief Converts the message data to a human-readable string. + * @return A string representation of the Diagnostic Negative Acknowledgment Message. + */ + std::string toString() const override; + + /** + * @brief Retrieves the raw binary data of the message. + * @return A vector of bytes representing the message data. + */ + std::vector getData() const override; + + /** + * @brief Builds the message data from the given DoIpLayer. + * + * This method parses the `DoIpLayer` to extract the relevant message data, including: + * - sourceAddress + * - targetAddress + * - nackCode + * - previousMessage (optional) + * + * @param doipLayer The layer containing the message data to be parsed. + * @return `true` if the message was successfully built from the layer, `false` otherwise. + */ + bool buildFromLayer(DoIpLayer* doipLayer) override; + }; +} // namespace pcpp diff --git a/Packet++/header/HttpLayer.h b/Packet++/header/HttpLayer.h index cc22499b44..c9682a9901 100644 --- a/Packet++/header/HttpLayer.h +++ b/Packet++/header/HttpLayer.h @@ -437,7 +437,6 @@ namespace pcpp HttpResponseStatusCode() = default; - // cppcheck-suppress noExplicitConstructor /** * @brief Construct HttpResponseStatusCode from Value enum * @param[in] statusCode the status code enum diff --git a/Packet++/header/ProtocolType.h b/Packet++/header/ProtocolType.h index f853b63f88..86747b957e 100644 --- a/Packet++/header/ProtocolType.h +++ b/Packet++/header/ProtocolType.h @@ -357,6 +357,11 @@ namespace pcpp */ const ProtocolType GTPv2 = 57; + /** + * Diagnostic over IP protocol (DOIP) + */ + const ProtocolType DOIP = 58; + /** * An enum representing OSI model layers */ diff --git a/Packet++/src/DoIpLayer.cpp b/Packet++/src/DoIpLayer.cpp new file mode 100644 index 0000000000..e5fa22c7d1 --- /dev/null +++ b/Packet++/src/DoIpLayer.cpp @@ -0,0 +1,212 @@ +#define LOG_MODULE PacketLogModuleDoipLayer + +#include "DoIpLayer.h" +#include "Packet.h" +#include "PayloadLayer.h" +#include "EndianPortable.h" +#include +#include +#include + +namespace pcpp +{ + DoIpLayer::DoIpLayer(DoIpProtocolVersion version, DoIpPayloadTypes type, const IDoIpMessageData* data) + { + initLayer(); + setProtocolVersion(version); + setInvertProtocolVersion(~(static_cast(version))); + buildLayer(type, data); + } + DoIpLayer::DoIpLayer() + { + VehicleAnnouncementData data; + initLayer(); + setProtocolVersion(DoIpProtocolVersion::version03Iso2019); + setInvertProtocolVersion(~(static_cast(DoIpProtocolVersion::version03Iso2019))); + buildLayer(DoIpPayloadTypes::ANNOUNCEMENT_MESSAGE, &data); + } + + DoIpProtocolVersion DoIpLayer::getProtocolVersion() const + { + return static_cast(getDoIpHeader()->protocolVersion); + } + + std::string DoIpLayer::getProtocolVersionAsStr() const + { + auto it = DoIpEnumToStringProtocolVersion.find(getProtocolVersion()); + if (it != DoIpEnumToStringProtocolVersion.end()) + { + return it->second; + } + else + { + return "Unknown Protocol Version"; + } + } + + void DoIpLayer::setProtocolVersion(DoIpProtocolVersion version) + { + getDoIpHeader()->protocolVersion = static_cast(version); + } + + uint8_t DoIpLayer::getInvertProtocolVersion() const + { + return getDoIpHeader()->invertProtocolVersion; + } + + void DoIpLayer::setInvertProtocolVersion(uint8_t iVersion) + { + getDoIpHeader()->invertProtocolVersion = iVersion; + } + + DoIpPayloadTypes DoIpLayer::getPayloadType() const + { + return static_cast(be16toh(getDoIpHeader()->payloadType)); + } + + void DoIpLayer::setPayloadType(DoIpPayloadTypes type) + { + getDoIpHeader()->payloadType = htobe16(static_cast(type)); + } + + std::string DoIpLayer::getPayloadTypeAsStr() const + { + auto it = DoIpEnumToStringPayloadType.find(getPayloadType()); + if (it != DoIpEnumToStringPayloadType.end()) + { + return it->second; + } + else + { + return "Unknown Payload type"; + } + } + + uint32_t DoIpLayer::getPayloadLength() const + { + return htobe32(getDoIpHeader()->payloadLength); + } + + void DoIpLayer::setPayloadLength(uint32_t Payloadength) + { + getDoIpHeader()->payloadLength = be32toh(Payloadength); + } + + bool DoIpLayer::resolveProtocolVersion() const + { + DoIpProtocolVersion version = getProtocolVersion(); + uint8_t inVersion = getInvertProtocolVersion(); + DoIpPayloadTypes type = getPayloadType(); + + // Idea is token from wireshark + if (!(version == DoIpProtocolVersion::version01Iso2010 || version == DoIpProtocolVersion::version02Iso2012 || + version == DoIpProtocolVersion::version03Iso2019 || + version == DoIpProtocolVersion::version04Iso2019_AMD1 || + (version == DoIpProtocolVersion::defaultVersion && + (type >= DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST && + type <= DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_VIN)))) + { + PCPP_LOG_ERROR("Invalid/unsupported DoIP version!"); + return false; + } + if ((uint8_t)(version) != (uint8_t)~(inVersion)) + { + PCPP_LOG_ERROR("Version and invert version are not synchronised !"); + return false; + } + return true; + } + + bool DoIpLayer::resolvePayloadLength() const + { + uint32_t length = getPayloadLength(); + + if (m_DataLen < sizeof(doiphdr)) + { + PCPP_LOG_ERROR("Payload length is smaller than the minimum header size"); + return false; + } + + if (length != (m_DataLen - sizeof(doiphdr))) + { + PCPP_LOG_ERROR("Payload length does not match expected size"); + return false; + } + + return true; + } + bool DoIpLayer::resolveLayer() const + { + // Validate the protocol version and payload length + if (!resolveProtocolVersion() || !resolvePayloadLength()) + { + PCPP_LOG_ERROR("Failed to Parse DoIP layer"); + return false; + } + return true; + } + + std::string DoIpLayer::toString() const + { + if (!resolveLayer()) + { + return "Malformed doip Packet"; + } + std::stringstream os; + DoIpProtocolVersion version = getProtocolVersion(); + DoIpPayloadTypes type = getPayloadType(); + uint32_t length = getPayloadLength(); + + os << "DOIP Layer:" << "\n"; + os << "Protocol Version: " << getProtocolVersionAsStr() << std::hex << " (0x" << unsigned((uint8_t)version) + << ")" << "\n"; + os << "Payload Type: " << getPayloadTypeAsStr() << std::hex << " (0x" << std::setw(4) << std::setfill('0') + << (uint16_t)type << ")" << "\n"; + os << std::dec << "Payload Length: " << length << "\n"; + + return os.str(); + } + + void DoIpLayer::serializeData(uint8_t* dest, std::vector data) + { + memcpy(dest, data.data(), data.size()); + } + + void DoIpLayer::initLayer() + { + m_DataLen = sizeof(doiphdr); + m_Protocol = DOIP; + m_Data = new uint8_t[m_DataLen]{}; + } + + void DoIpLayer::buildLayer(DoIpPayloadTypes type, const IDoIpMessageData* data) + { + switch (type) + { + case DoIpPayloadTypes::ALIVE_CHECK_REQUEST: + case DoIpPayloadTypes::ENTITY_STATUS_REQUEST: + case DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_REQUEST: + case DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST: + setPayloadType(type); + setPayloadLength(0); + break; + default: + // Payload handling for rest of types + { + if (data == nullptr) + { + PCPP_LOG_ERROR("Cannot build Layer with empty Data"); + break; + } + size_t payloadSize = data->getData().size(); + size_t headerLength = sizeof(doiphdr); + + setPayloadType(data->getType()); + setPayloadLength(payloadSize); + extendLayer(headerLength, payloadSize); + serializeData(m_Data + headerLength, data->getData()); + break; + } + } + } +} // namespace pcpp diff --git a/Packet++/src/DoIpLayerData.cpp b/Packet++/src/DoIpLayerData.cpp new file mode 100644 index 0000000000..3bbadf9672 --- /dev/null +++ b/Packet++/src/DoIpLayerData.cpp @@ -0,0 +1,857 @@ +#include "DoIpLayerData.h" +#include "DoIpLayer.h" +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + RoutingActivationRequestData::RoutingActivationRequestData() + : sourceAddress(0x0000), activationType(DoIpActivationTypes::Default), reservedIso{}, reservedOem(nullptr) {}; + + DoIpPayloadTypes RoutingActivationRequestData::getType() const + { + return DoIpPayloadTypes::ROUTING_ACTIVATION_REQUEST; + } + + std::string RoutingActivationRequestData::toString() const + { + std::stringstream os; + os << "sourceAddress: " << std::hex << "0x" << htobe16(sourceAddress) << "\n"; + os << "activation type: " << DoIpEnumToStringActivationTypes.at(activationType) << std::hex << " (0x" + << unsigned(activationType) << ")" << "\n"; + os << "reserved by ISO: " << pcpp::byteArrayToHexString(reservedIso.data(), DOIP_RESERVED_ISO_LEN) << "\n"; + if (reservedOem) + { + os << "Reserved by OEM: " << pcpp::byteArrayToHexString(reservedOem->data(), DOIP_RESERVED_OEM_LEN) << '\n'; + } + return os.str(); + } + + std::vector RoutingActivationRequestData::getData() const + { + std::vector data; + // Copy each field's data into the vector + data.insert(data.end(), reinterpret_cast(&sourceAddress), + reinterpret_cast(&sourceAddress) + sizeof(sourceAddress)); + data.push_back(static_cast(activationType)); // Convert enum to byte + data.insert(data.end(), reservedIso.begin(), reservedIso.end()); + if (reservedOem) + { + data.insert(data.end(), reservedOem->begin(), reservedOem->end()); + } + return data; + } + + // buildFromLayer implementation + bool RoutingActivationRequestData::buildFromLayer(DoIpLayer* doipLayer) + { + if (!doipLayer) + { + PCPP_LOG_ERROR("Input data buffer is null"); + return false; + } + + if (doipLayer->getPayloadType() != getType()) + { + PCPP_LOG_ERROR("Cannot retrieve routing activation request data from " + doipLayer->getPayloadTypeAsStr()); + return false; + } + uint8_t* dataPtr = doipLayer->getDataPtr(sizeof(doiphdr)); + sourceAddress = static_cast(dataPtr[1] << 8 | dataPtr[0]); + activationType = static_cast(dataPtr[2]); + std::copy(dataPtr + 3, dataPtr + 3 + DOIP_RESERVED_ISO_LEN, reservedIso.begin()); + if (doipLayer->getDataLen() - sizeof(doiphdr) >= + sizeof(sourceAddress) + sizeof(activationType) + DOIP_RESERVED_ISO_LEN + DOIP_RESERVED_OEM_LEN) + { + reservedOem = std::unique_ptr>( + new std::array()); + std::copy(dataPtr + 3 + DOIP_RESERVED_ISO_LEN, dataPtr + 3 + DOIP_RESERVED_ISO_LEN + DOIP_RESERVED_OEM_LEN, + reservedOem->begin()); + } + else + { + PCPP_LOG_DEBUG("Reserved OEM field is empty or has invalid size !"); + reservedOem.reset(); + } + return true; + } + + // Routing Response function definition + RoutingActivationResponseData::RoutingActivationResponseData() + : logicalAddressExternalTester(0x0000), sourceAddress(0x0000), + responseCode(DoIpRoutingResponseCodes::CONFIRMATION_REQUIRED), reservedIso{}, reservedOem(nullptr) + {} + + DoIpPayloadTypes RoutingActivationResponseData::getType() const + { + return DoIpPayloadTypes::ROUTING_ACTIVATION_RESPONSE; + } + + std::string RoutingActivationResponseData::toString() const + { + std::stringstream os; + os << "logical address of external tester: " << std::hex << "0x" << htobe16(logicalAddressExternalTester) + << "\n"; + os << "source address: " << std::hex << "0x" << htobe16(sourceAddress) << "\n"; + os << "routing activation response code: " << DoIpEnumToStringRoutingResponseCodes.at(responseCode) << std::hex + << " (0x" << unsigned(responseCode) << ")" << "\n"; + os << "reserved by ISO: " << pcpp::byteArrayToHexString(reservedIso.data(), DOIP_RESERVED_ISO_LEN) << "\n"; + if (reservedOem) + { + os << "Reserved by OEM: " << pcpp::byteArrayToHexString(reservedOem->data(), DOIP_RESERVED_OEM_LEN) << "\n"; + } + return os.str(); + } + std::vector RoutingActivationResponseData::getData() const + { + std::vector data; + // Copy each field's data into the vector + data.insert(data.end(), reinterpret_cast(&logicalAddressExternalTester), + reinterpret_cast(&logicalAddressExternalTester) + + sizeof(logicalAddressExternalTester)); + data.insert(data.end(), reinterpret_cast(&sourceAddress), + reinterpret_cast(&sourceAddress) + sizeof(sourceAddress)); + data.push_back(static_cast(responseCode)); // Convert enum to byte + data.insert(data.end(), reservedIso.begin(), reservedIso.end()); + if (reservedOem) + { + data.insert(data.end(), reservedOem->begin(), reservedOem->end()); + } + return data; + } + + bool RoutingActivationResponseData::buildFromLayer(DoIpLayer* doipLayer) + { + if (!doipLayer) + { + PCPP_LOG_ERROR("Input data buffer is null"); + return false; + } + + if (doipLayer->getPayloadType() != getType()) + { + PCPP_LOG_ERROR("Cannot retrieve routing activation response data from " + doipLayer->getPayloadTypeAsStr()); + return false; + } + + uint8_t* dataPtr = doipLayer->getDataPtr(sizeof(doiphdr)); + if (!dataPtr) + { + PCPP_LOG_ERROR("Data pointer is null"); + return false; + } + + logicalAddressExternalTester = static_cast(dataPtr[1] << 8 | dataPtr[0]); + sourceAddress = static_cast(dataPtr[3] << 8 | dataPtr[2]); + responseCode = static_cast(dataPtr[4]); + + std::copy(dataPtr + 5, dataPtr + 5 + DOIP_RESERVED_ISO_LEN, reservedIso.begin()); + + if (doipLayer->getDataLen() - sizeof(doiphdr) >= 5 + DOIP_RESERVED_ISO_LEN + DOIP_RESERVED_OEM_LEN) + { + reservedOem = std::unique_ptr>( + new std::array()); + std::copy(dataPtr + 5 + DOIP_RESERVED_ISO_LEN, dataPtr + 5 + DOIP_RESERVED_ISO_LEN + DOIP_RESERVED_OEM_LEN, + reservedOem->begin()); + } + else + { + PCPP_LOG_DEBUG("Reserved OEM field is empty or has invalid size !"); + reservedOem.reset(); // Clear reservedOem if not present + } + + return true; + } + + // Generic header nack function definition + GenericHeaderNackData::GenericHeaderNackData() : genericNackCode(DoIpGenericHeaderNackCodes::INVALID_PAYLOAD_LENGTH) + {} + + DoIpPayloadTypes GenericHeaderNackData::getType() const + { + return DoIpPayloadTypes::GENERIC_HEADER_NEG_ACK; + } + + std::string GenericHeaderNackData::toString() const + { + std::stringstream os; + os << "generic header nack code: " << DoIpEnumToStringGenericHeaderNackCodes.at(genericNackCode) << std::hex + << " (0x" << unsigned(genericNackCode) << ")" << "\n"; + ; + return os.str(); + } + std::vector GenericHeaderNackData::getData() const + { + std::vector data; + // Copy each field's data into the vector + data.push_back(static_cast(genericNackCode)); // Convert enum to byte + return data; + } + + // buildFromLayer fun implementation + bool GenericHeaderNackData::buildFromLayer(DoIpLayer* doipLayer) + { + if (!doipLayer) + { + PCPP_LOG_ERROR("Input DoIpLayer is null"); + return false; + } + + if (doipLayer->getPayloadType() != getType()) + { + PCPP_LOG_ERROR("Cannot retrieve Generic Header NACK data from " + doipLayer->getPayloadTypeAsStr()); + return false; + } + + // Validate data length (1 byte is expected for genericNackCode) + if (doipLayer->getDataLen() - sizeof(doiphdr) < 1) + { + PCPP_LOG_ERROR("Insufficient data length for Generic Header NACK payload"); + return false; + } + + // Extract the NACK code (1 byte) + uint8_t* dataPtr = doipLayer->getDataPtr(sizeof(doiphdr)); + genericNackCode = static_cast(dataPtr[0]); + + return true; + } + + // vehicle ideentification with EID functions definition + VehicleIdentificationRequestEIDData::VehicleIdentificationRequestEIDData() : eid{} + {} + DoIpPayloadTypes VehicleIdentificationRequestEIDData::getType() const + { + return DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_EID; + } + std::string VehicleIdentificationRequestEIDData::toString() const + { + std::stringstream os; + os << "EID: " << pcpp::byteArrayToHexString(eid.data(), DOIP_EID_LEN) << "\n"; + return os.str(); + } + std::vector VehicleIdentificationRequestEIDData::getData() const + { + std::vector data; + // Copy each field's data into the vector + data.insert(data.end(), eid.begin(), eid.end()); + return data; + } + + bool VehicleIdentificationRequestEIDData::buildFromLayer(DoIpLayer* doipLayer) + { + if (!doipLayer) + { + PCPP_LOG_ERROR("Input DoIpLayer is null"); + return false; + } + + if (doipLayer->getPayloadType() != getType()) + { + PCPP_LOG_ERROR("Cannot retrieve Vehicle Identification Request with EID data from " + + doipLayer->getPayloadTypeAsStr()); + return false; + } + + // Validate data length (must at least accommodate EID length) + if (doipLayer->getDataLen() - sizeof(doiphdr) < DOIP_EID_LEN) + { + PCPP_LOG_ERROR("Insufficient data length for Vehicle Identification Request with EID payload"); + return false; + } + + // Extract the EID + uint8_t* dataPtr = doipLayer->getDataPtr(sizeof(doiphdr)); + std::copy(dataPtr, dataPtr + DOIP_EID_LEN, eid.begin()); + + return true; + } + + // vehicle ideentification with VIN functions definition + VehicleIdentificationRequestVINData::VehicleIdentificationRequestVINData() : vin{} + {} + DoIpPayloadTypes VehicleIdentificationRequestVINData::getType() const + { + return DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_VIN; + } + std::string VehicleIdentificationRequestVINData::toString() const + { + std::stringstream os; + os << "VIN: " << std::string(reinterpret_cast(vin.data()), vin.size()) << "\n"; + return os.str(); + } + std::vector VehicleIdentificationRequestVINData::getData() const + { + std::vector data; + // Copy each field's data into the vector + data.insert(data.end(), vin.begin(), vin.end()); + return data; + } + + bool VehicleIdentificationRequestVINData::buildFromLayer(DoIpLayer* doipLayer) + { + if (!doipLayer) + { + PCPP_LOG_ERROR("Input DoIpLayer is null"); + return false; + } + + if (doipLayer->getPayloadType() != getType()) + { + PCPP_LOG_ERROR("Cannot retrieve Vehicle Identification Request with VIN data from " + + doipLayer->getPayloadTypeAsStr()); + return false; + } + + // Validate data length (must at least accommodate VIN length) + if (doipLayer->getDataLen() - sizeof(doiphdr) < DOIP_VIN_LEN) + { + PCPP_LOG_ERROR("Insufficient data length for Vehicle Identification Request with EID payload"); + return false; + } + + // Extract the VIN + uint8_t* dataPtr = doipLayer->getDataPtr(sizeof(doiphdr)); + std::copy(dataPtr, dataPtr + DOIP_VIN_LEN, vin.begin()); + + return true; + } + + // vehicle announcement functions definition + VehicleAnnouncementData::VehicleAnnouncementData() + : vin{}, // Initialize VIN to all zeros + logicalAddress(0), // Set logical address to 0 + eid{}, // Initialize EID to all zeros + gid{}, // Initialize GID to all zeros + furtherActionRequired(DoIpActionCodes::NO_FURTHER_ACTION_REQUIRED), // No further action required + syncStatus(DoIpSyncStatus::NON_INITIALIZED) // not initialized sync status field + {}; + + DoIpPayloadTypes VehicleAnnouncementData::getType() const + { + return DoIpPayloadTypes::ANNOUNCEMENT_MESSAGE; + } + + std::string VehicleAnnouncementData::toString() const + { + std::stringstream os; + os << "VIN: " << std::string(reinterpret_cast(vin.data()), vin.size()) << "\n"; + os << "logical address: " << std::hex << "0x" << htobe16(logicalAddress) << "\n"; + os << "EID: " << pcpp::byteArrayToHexString(eid.data(), DOIP_EID_LEN) << "\n"; + os << "GID: " << pcpp::byteArrayToHexString(gid.data(), DOIP_GID_LEN) << "\n"; + os << "further action required:" << DoIpEnumToStringActionCodes.at(furtherActionRequired) << std::hex << " (0x" + << unsigned(furtherActionRequired) << ")" << "\n"; + os << "VIN/GID sync status: " << DoIpEnumToStringSyncStatus.at(syncStatus) << "\n"; // Convert enum to byte + return os.str(); + } + + std::vector VehicleAnnouncementData::getData() const + { + std::vector data; + // Copy each field's data into the vector + data.insert(data.end(), vin.begin(), vin.end()); + data.insert(data.end(), reinterpret_cast(&logicalAddress), + reinterpret_cast(&logicalAddress) + sizeof(logicalAddress)); + data.insert(data.end(), eid.begin(), eid.end()); + data.insert(data.end(), gid.begin(), gid.end()); + data.push_back(static_cast(furtherActionRequired)); // Convert enum to byte + // optional field can be non-initialised + if (syncStatus != DoIpSyncStatus::NON_INITIALIZED) + { + data.push_back(static_cast(syncStatus)); // Convert enum to byte + } + return data; + } + + bool VehicleAnnouncementData::buildFromLayer(DoIpLayer* doipLayer) + { + if (!doipLayer) + { + PCPP_LOG_ERROR("Input DoIpLayer is null"); + return false; + } + + if (doipLayer->getPayloadType() != getType()) + { + PCPP_LOG_ERROR("Cannot retrieve Vehicle Announcement data from " + doipLayer->getPayloadTypeAsStr()); + return false; + } + + // Validate minimum data length + size_t expectedMinLength = + DOIP_VIN_LEN + sizeof(logicalAddress) + DOIP_EID_LEN + DOIP_GID_LEN + 1; // 1 for furtherActionRequired + if (doipLayer->getDataLen() - sizeof(doiphdr) < expectedMinLength) + { + PCPP_LOG_ERROR("Insufficient data length for Vehicle Announcement payload"); + return false; + } + + // Parse fields from payload + uint8_t* dataPtr = doipLayer->getDataPtr(sizeof(doiphdr)); + + // VIN + std::copy(dataPtr, dataPtr + DOIP_VIN_LEN, vin.begin()); + dataPtr += DOIP_VIN_LEN; + + // Logical Address + logicalAddress = static_cast(dataPtr[1] << 8 | dataPtr[0]); + dataPtr += sizeof(logicalAddress); + + // EID + std::copy(dataPtr, dataPtr + DOIP_EID_LEN, eid.begin()); + dataPtr += DOIP_EID_LEN; + + // GID + std::copy(dataPtr, dataPtr + DOIP_GID_LEN, gid.begin()); + dataPtr += DOIP_GID_LEN; + + // Further Action Required + furtherActionRequired = static_cast(*dataPtr); + dataPtr += 1; + + // Optional Sync Status + if (doipLayer->getDataLen() - sizeof(doiphdr) > expectedMinLength) + { + syncStatus = static_cast(*dataPtr); + } + else + { + syncStatus = DoIpSyncStatus::NON_INITIALIZED; + } + + return true; + } + + // alive check response functions definition + AliveCheckResponseData::AliveCheckResponseData() : sourceAddress(0x0000) + {} + DoIpPayloadTypes AliveCheckResponseData::getType() const + { + return DoIpPayloadTypes::ALIVE_CHECK_RESPONSE; + } + std::string AliveCheckResponseData::toString() const + { + std::stringstream os; + os << "source address: " << std::hex << "0x" << htobe16(sourceAddress) << "\n"; + return os.str(); + } + std::vector AliveCheckResponseData::getData() const + { + std::vector data; + // Copy each field's data into the vector + data.insert(data.end(), reinterpret_cast(&sourceAddress), + reinterpret_cast(&sourceAddress) + sizeof(sourceAddress)); + return data; + } + + bool AliveCheckResponseData::buildFromLayer(DoIpLayer* doipLayer) + { + if (!doipLayer) + { + PCPP_LOG_ERROR("Input DoIpLayer is null"); + return false; + } + + if (doipLayer->getPayloadType() != getType()) + { + PCPP_LOG_ERROR("Cannot retrieve Alive Check Response data from " + doipLayer->getPayloadTypeAsStr()); + return false; + } + + // Validate minimum data length + constexpr size_t requiredLength = sizeof(sourceAddress); + if (doipLayer->getDataLen() - sizeof(doiphdr) < requiredLength) + { + PCPP_LOG_ERROR("Insufficient data length for Alive Check Response payload"); + return false; + } + + // Parse sourceAddress from payload + uint8_t* dataPtr = doipLayer->getDataPtr(sizeof(doiphdr)); + sourceAddress = *reinterpret_cast(dataPtr); + + return true; + } + + // Diagnostic Power Mode Response functions definition + DiagnosticPowerModeResponseData::DiagnosticPowerModeResponseData() + : powerModeCode(DoIpDiagnosticPowerModeCodes::NOT_READY) + {} + + DoIpPayloadTypes DiagnosticPowerModeResponseData::getType() const + { + return DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_RESPONSE; + } + + std::string DiagnosticPowerModeResponseData::toString() const + { + std::stringstream os; + os << "diagnostic power mode: " << DoIpEnumToStringDiagnosticPowerModeCodes.at(powerModeCode) << std::hex + << " (0x" << unsigned(powerModeCode) << ")" << "\n"; + return os.str(); + } + + std::vector DiagnosticPowerModeResponseData::getData() const + { + std::vector data; + // Copy each field's data into the vector + data.push_back(static_cast(powerModeCode)); // Convert enum to byte + return data; + } + + bool DiagnosticPowerModeResponseData::buildFromLayer(DoIpLayer* doipLayer) + { + if (!doipLayer) + { + PCPP_LOG_ERROR("Input DoIpLayer is null"); + return false; + } + + if (doipLayer->getPayloadType() != getType()) + { + PCPP_LOG_ERROR("Cannot retrieve Diagnostic Power Mode Response data from " + + doipLayer->getPayloadTypeAsStr()); + return false; + } + + // Validate minimum data length + constexpr size_t requiredLength = sizeof(powerModeCode); + if (doipLayer->getDataLen() - sizeof(doiphdr) < requiredLength) + { + PCPP_LOG_ERROR("Insufficient data length for Diagnostic Power Mode Response payload"); + return false; + } + + // Parse powerModeCode from payload + uint8_t* dataPtr = doipLayer->getDataPtr(sizeof(doiphdr)); + powerModeCode = static_cast(dataPtr[0]); + + return true; + } + + // Entity status response functions definitions + EntityStatusResponseData::EntityStatusResponseData() + : nodeType(DoIpEntityStatus::GATEWAY), maxConcurrentSockets(0), currentlyOpenSockets(0), maxDataSize(nullptr) + {} + + DoIpPayloadTypes EntityStatusResponseData::getType() const + { + return DoIpPayloadTypes::ENTITY_STATUS_RESPONSE; + } + + std::string EntityStatusResponseData::toString() const + { + std::stringstream os; + os << "Entity status: " << DoIpEnumToStringEntityStatusNodeTypes.at(nodeType) << std::hex << " (0x" + << unsigned(nodeType) << ")" << "\n"; + os << "maximum Concurrent Socket: " << unsigned(maxConcurrentSockets) << "\n"; + os << "currently Opened Socket: " << unsigned(currentlyOpenSockets) << "\n"; + if (maxDataSize) + { + os << "maximum Data Size: " + << "0x" << pcpp::byteArrayToHexString(maxDataSize->data(), 4) << "\n"; + } + + return os.str(); + } + + std::vector EntityStatusResponseData::getData() const + { + std::vector data; + // Copy each field's data into the vector + data.push_back(static_cast(nodeType)); // Convert enum to byte + data.push_back(static_cast(maxConcurrentSockets)); + data.push_back(static_cast(currentlyOpenSockets)); + // optional field + if (maxDataSize) + { + data.insert(data.end(), maxDataSize->begin(), maxDataSize->end()); + } + return data; + } + + bool EntityStatusResponseData::buildFromLayer(DoIpLayer* doipLayer) + { + if (!doipLayer) + { + PCPP_LOG_ERROR("Input DoIpLayer is null"); + return false; + } + + if (doipLayer->getPayloadType() != getType()) + { + PCPP_LOG_ERROR("Cannot retrieve Entity Status Response data from " + doipLayer->getPayloadTypeAsStr()); + return false; + } + + constexpr size_t fixedFieldLength = + sizeof(nodeType) + sizeof(maxConcurrentSockets) + sizeof(currentlyOpenSockets); + constexpr size_t optionalFieldLength = 4; // Length of maxDataSize field + size_t totalDataLength = doipLayer->getDataLen() - sizeof(doiphdr); + + if (totalDataLength < fixedFieldLength) + { + PCPP_LOG_ERROR("Insufficient data length for Entity Status Response fixed fields"); + return false; + } + + // Parse fixed fields + uint8_t* dataPtr = doipLayer->getDataPtr(sizeof(doiphdr)); + nodeType = static_cast(dataPtr[0]); + maxConcurrentSockets = dataPtr[1]; + currentlyOpenSockets = dataPtr[2]; + + // Parse optional maxDataSize field if present + if (totalDataLength >= fixedFieldLength + optionalFieldLength) + { + maxDataSize = std::unique_ptr>( + new std::array()); + std::copy(dataPtr + fixedFieldLength, dataPtr + fixedFieldLength + optionalFieldLength, + maxDataSize->begin()); + } + else + { + maxDataSize = nullptr; // Optional field not present + } + + return true; + } + + // Diagnostic Message functions definitions + DiagnosticMessageData::DiagnosticMessageData() + : sourceAddress(0x0000), targetAddress(0x0000), diagnosticData{ 0x22, 0xf1, 0x68 } + {} + DoIpPayloadTypes DiagnosticMessageData::getType() const + { + return DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_TYPE; + } + std::string DiagnosticMessageData::toString() const + { + std::stringstream os; + os << "source address: " << std::hex << "0x" << htobe16(sourceAddress) << "\n"; + os << "target address: " << std::hex << "0x" << htobe16(targetAddress) << "\n"; + return os.str(); + } + std::vector DiagnosticMessageData::getData() const + { + std::vector data; + // Copy each field's data into the vector + data.insert(data.end(), reinterpret_cast(&sourceAddress), + reinterpret_cast(&sourceAddress) + sizeof(sourceAddress)); + data.insert(data.end(), reinterpret_cast(&targetAddress), + reinterpret_cast(&targetAddress) + sizeof(targetAddress)); + data.insert(data.end(), diagnosticData.data(), diagnosticData.data() + diagnosticData.size()); + return data; + } + + bool DiagnosticMessageData::buildFromLayer(DoIpLayer* doipLayer) + { + if (!doipLayer) + { + PCPP_LOG_ERROR("Input DoIpLayer is null"); + return false; + } + + if (doipLayer->getPayloadType() != getType()) + { + PCPP_LOG_ERROR("Cannot retrieve Diagnostic Message data from " + doipLayer->getPayloadTypeAsStr()); + return false; + } + + constexpr size_t fixedFieldLength = sizeof(sourceAddress) + sizeof(targetAddress) + 2; // SI + DID + size_t totalDataLength = doipLayer->getDataLen() - sizeof(doiphdr); + + if (totalDataLength < fixedFieldLength) + { + PCPP_LOG_ERROR("Insufficient data length for Diagnostic Message fixed fields"); + return false; + } + + // Parse fixed fields + uint8_t* dataPtr = doipLayer->getDataPtr(sizeof(doiphdr)); + sourceAddress = *reinterpret_cast(dataPtr); + targetAddress = *reinterpret_cast(dataPtr + sizeof(sourceAddress)); + + // Parse diagnosticData field (remaining data after fixed fields) + size_t diagnosticDataLength = totalDataLength - fixedFieldLength; + diagnosticData.resize(diagnosticDataLength); + std::copy(dataPtr + fixedFieldLength, dataPtr + fixedFieldLength + diagnosticDataLength, + diagnosticData.begin()); + + return true; + } + + // Diagnostic Ack Message functions definitions + DiagnosticAckMessageData::DiagnosticAckMessageData() + : sourceAddress(0x0000), targetAddress(0x0000), ackCode(DoIpDiagnosticAckCodes::ACK), + previousMessage{ 0x22, 0xf1, 0x01, 0x02 } + {} + DoIpPayloadTypes DiagnosticAckMessageData::getType() const + { + return DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_POS_ACK; + } + std::string DiagnosticAckMessageData::toString() const + { + std::stringstream os; + os << "source address: " << std::hex << "0x" << htobe16(sourceAddress) << "\n"; + os << "target address: " << std::hex << "0x" << htobe16(targetAddress) << "\n"; + os << "ack code: " << DoIpEnumToStringAckCode.at(ackCode) << " (0x" << unsigned(ackCode) << ")" << "\n"; + if (!previousMessage.empty()) + { + os << "previous message: " << pcpp::byteArrayToHexString(previousMessage.data(), previousMessage.size()) + << "\n"; + } + return os.str(); + } + std::vector DiagnosticAckMessageData::getData() const + { + std::vector data; + // Copy each field's data into the vector + data.insert(data.end(), reinterpret_cast(&sourceAddress), + reinterpret_cast(&sourceAddress) + sizeof(sourceAddress)); + data.insert(data.end(), reinterpret_cast(&targetAddress), + reinterpret_cast(&targetAddress) + sizeof(targetAddress)); + data.push_back(static_cast(ackCode)); + if (!previousMessage.empty()) + { + data.insert(data.end(), previousMessage.begin(), previousMessage.end()); + } + return data; + } + + bool DiagnosticAckMessageData::buildFromLayer(DoIpLayer* doipLayer) + { + if (!doipLayer) + { + PCPP_LOG_ERROR("Input DoIpLayer is null"); + return false; + } + + if (doipLayer->getPayloadType() != getType()) + { + PCPP_LOG_ERROR("Cannot retrieve Diagnostic Acknowledgment Message data from " + + doipLayer->getPayloadTypeAsStr()); + return false; + } + + constexpr size_t fixedFieldLength = sizeof(sourceAddress) + sizeof(targetAddress) + sizeof(ackCode); + size_t totalDataLength = doipLayer->getDataLen() - sizeof(doiphdr); + + if (totalDataLength < fixedFieldLength) + { + PCPP_LOG_ERROR("Insufficient data length for Diagnostic Acknowledgment Message fixed fields"); + return false; + } + + // Parse fixed fields + uint8_t* dataPtr = doipLayer->getDataPtr(sizeof(doiphdr)); + sourceAddress = (*reinterpret_cast(dataPtr)); + targetAddress = (*reinterpret_cast(dataPtr + sizeof(sourceAddress))); + ackCode = static_cast( + *reinterpret_cast(dataPtr + sizeof(sourceAddress) + sizeof(targetAddress))); + + // Check if there is any data left for the optional previousMessage field + size_t remainingDataLength = totalDataLength - fixedFieldLength; + if (remainingDataLength > 0) + { + previousMessage.resize(remainingDataLength); + std::copy(dataPtr + fixedFieldLength, dataPtr + fixedFieldLength + remainingDataLength, + previousMessage.begin()); + } + else + { + previousMessage.clear(); // Ensure previousMessage is empty when not provided + } + return true; + } + + // Diagnostic Nack Message functions definitions + DiagnosticNackMessageData::DiagnosticNackMessageData() + : sourceAddress(0x0000), targetAddress(0x0000), + nackCode(DoIpDiagnosticMessageNackCodes::INVALID_SOURCE_ADDRESS), previousMessage{ 0x22, 0xf1, 0x01, 0x02 } + {} + DoIpPayloadTypes DiagnosticNackMessageData::getType() const + { + return DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_NEG_ACK; + } + std::string DiagnosticNackMessageData::toString() const + { + std::stringstream os; + os << "source address: " << std::hex << "0x" << htobe16(sourceAddress) << "\n"; + os << "target address: " << std::hex << "0x" << htobe16(targetAddress) << "\n"; + os << "nack code: " << DoIpEnumToStringDiagnosticNackCodes.at(nackCode) << std::hex << " (0x" + << unsigned(nackCode) << ")" << "\n"; + if (!previousMessage.empty()) + { + os << "previous message: " << pcpp::byteArrayToHexString(previousMessage.data(), previousMessage.size()) + << "\n"; + } + return os.str(); + } + std::vector DiagnosticNackMessageData::getData() const + { + std::vector data; + // Copy each field's data into the vector + data.insert(data.end(), reinterpret_cast(&sourceAddress), + reinterpret_cast(&sourceAddress) + sizeof(sourceAddress)); + data.insert(data.end(), reinterpret_cast(&targetAddress), + reinterpret_cast(&targetAddress) + sizeof(targetAddress)); + data.push_back(static_cast(nackCode)); + if (!previousMessage.empty()) + { + data.insert(data.end(), reinterpret_cast(&previousMessage), + reinterpret_cast(&previousMessage) + sizeof(previousMessage)); + } + return data; + } + + bool DiagnosticNackMessageData::buildFromLayer(DoIpLayer* doipLayer) + { + if (!doipLayer) + { + PCPP_LOG_ERROR("Input DoIpLayer is null"); + return false; + } + + if (doipLayer->getPayloadType() != getType()) + { + PCPP_LOG_ERROR("Cannot retrieve Diagnostic NACK Message data from " + doipLayer->getPayloadTypeAsStr()); + return false; + } + + constexpr size_t fixedFieldLength = sizeof(sourceAddress) + sizeof(targetAddress) + sizeof(nackCode); + size_t totalDataLength = doipLayer->getDataLen() - sizeof(doiphdr); + + if (totalDataLength < fixedFieldLength) + { + PCPP_LOG_ERROR("Insufficient data length for Diagnostic NACK Message fixed fields"); + return false; + } + + // Parse fixed fields + uint8_t* dataPtr = doipLayer->getDataPtr(sizeof(doiphdr)); + sourceAddress = (*reinterpret_cast(dataPtr)); + targetAddress = (*reinterpret_cast(dataPtr + sizeof(sourceAddress))); + nackCode = static_cast( + *reinterpret_cast(dataPtr + sizeof(sourceAddress) + sizeof(targetAddress))); + + // Check if there is any data left for the optional previousMessage field + size_t remainingDataLength = totalDataLength - fixedFieldLength; + if (remainingDataLength > 0) + { + previousMessage.resize(remainingDataLength); + std::copy(dataPtr + fixedFieldLength, dataPtr + fixedFieldLength + remainingDataLength, + previousMessage.begin()); + } + else + { + previousMessage.clear(); // Ensure previousMessage is empty when not provided + } + + return true; + } + +} // namespace pcpp diff --git a/Packet++/src/TcpLayer.cpp b/Packet++/src/TcpLayer.cpp index 45d1a1e140..d480f8f878 100644 --- a/Packet++/src/TcpLayer.cpp +++ b/Packet++/src/TcpLayer.cpp @@ -11,6 +11,7 @@ #include "BgpLayer.h" #include "SSHLayer.h" #include "DnsLayer.h" +#include "DoIpLayer.h" #include "TelnetLayer.h" #include "TpktLayer.h" #include "FtpLayer.h" @@ -366,8 +367,11 @@ namespace pcpp const uint16_t portSrc = getSrcPort(); const char* payloadChar = reinterpret_cast(payload); - if (HttpMessage::isHttpPort(portDst) && - HttpRequestFirstLine::parseMethod(payloadChar, payloadLen) != HttpRequestLayer::HttpMethodUnknown) + if ((DoIpLayer::isDoIpPort(portSrc) || DoIpLayer::isDoIpPort(portDst)) && + (DoIpLayer::isDataValid(payload, payloadLen))) + m_NextLayer = new DoIpLayer(payload, payloadLen, this, m_Packet); + else if (HttpMessage::isHttpPort(portDst) && + HttpRequestFirstLine::parseMethod(payloadChar, payloadLen) != HttpRequestLayer::HttpMethodUnknown) m_NextLayer = new HttpRequestLayer(payload, payloadLen, this, m_Packet); else if (HttpMessage::isHttpPort(portSrc) && HttpResponseFirstLine::parseVersion(payloadChar, payloadLen) != HttpVersion::HttpVersionUnknown && diff --git a/Packet++/src/UdpLayer.cpp b/Packet++/src/UdpLayer.cpp index 9cfaa2cbe0..9b91337d8c 100644 --- a/Packet++/src/UdpLayer.cpp +++ b/Packet++/src/UdpLayer.cpp @@ -8,6 +8,7 @@ #include "DnsLayer.h" #include "DhcpLayer.h" #include "DhcpV6Layer.h" +#include "DoIpLayer.h" #include "VxlanLayer.h" #include "SipLayer.h" #include "RadiusLayer.h" @@ -130,6 +131,9 @@ namespace pcpp else if ((DhcpV6Layer::isDhcpV6Port(portSrc) || DhcpV6Layer::isDhcpV6Port(portDst)) && (DhcpV6Layer::isDataValid(udpData, udpDataLen))) m_NextLayer = new DhcpV6Layer(udpData, udpDataLen, this, m_Packet); + else if ((DoIpLayer::isDoIpPort(portSrc) || DoIpLayer::isDoIpPort(portDst)) && + (DoIpLayer::isDataValid(udpData, udpDataLen))) + m_NextLayer = new DoIpLayer(udpData, udpDataLen, this, m_Packet); else if ((NtpLayer::isNTPPort(portSrc) || NtpLayer::isNTPPort(portDst)) && NtpLayer::isDataValid(udpData, udpDataLen)) m_NextLayer = new NtpLayer(udpData, udpDataLen, this, m_Packet); diff --git a/Pcap++/src/PcapRemoteDeviceList.cpp b/Pcap++/src/PcapRemoteDeviceList.cpp index 01791d6dde..37d0a8f3d7 100644 --- a/Pcap++/src/PcapRemoteDeviceList.cpp +++ b/Pcap++/src/PcapRemoteDeviceList.cpp @@ -107,7 +107,6 @@ namespace pcpp auto pNewRemoteDevice = std::unique_ptr( new PcapRemoteDevice(currInterface, pRemoteAuthCopy, ipAddress, port)); // Release is called after pushback to prevent memory leaks if vector reallocation fails. - // cppcheck-suppress danglingLifetime devices.push_back(pNewRemoteDevice.get()); pNewRemoteDevice.release(); } diff --git a/Tests/Packet++Test/CMakeLists.txt b/Tests/Packet++Test/CMakeLists.txt index 082fb9c51b..db8aec802e 100644 --- a/Tests/Packet++Test/CMakeLists.txt +++ b/Tests/Packet++Test/CMakeLists.txt @@ -7,6 +7,7 @@ add_executable( Tests/DhcpTests.cpp Tests/DhcpV6Tests.cpp Tests/DnsTests.cpp + Tests/DoIpTests.cpp Tests/EthAndArpTests.cpp Tests/FtpTests.cpp Tests/GreTests.cpp diff --git a/Tests/Packet++Test/PacketExamples/DoIpAliveCheckRequestPacket.dat b/Tests/Packet++Test/PacketExamples/DoIpAliveCheckRequestPacket.dat new file mode 100644 index 0000000000..02633241b4 --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpAliveCheckRequestPacket.dat @@ -0,0 +1 @@ +001a37bfee7454e1ad6bac150800450000240001000040113aeea9fe75efa9fe75eeff1434580010898202fd000700000000 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/DoIpAliveCheckResponsePacket.dat b/Tests/Packet++Test/PacketExamples/DoIpAliveCheckResponsePacket.dat new file mode 100644 index 0000000000..150f3bac9e --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpAliveCheckResponsePacket.dat @@ -0,0 +1 @@ +001a37bfee7454e1ad6bac150800450000260001000040113aeca9fe75efa9fe75eeff1434580012897b02fd0008000000020000 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/DoIpDiagnosticAckMessagePacket.dat b/Tests/Packet++Test/PacketExamples/DoIpDiagnosticAckMessagePacket.dat new file mode 100644 index 0000000000..8e33eb555f --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpDiagnosticAckMessagePacket.dat @@ -0,0 +1 @@ +54e1ad6bac15001a37bfee740800450000384de80000ff062dfda9fe75eea9fe75ef3458d25e00191aa0ab87803d5018164f49a2000002fd80020000000840100e800022f101 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/DoIpDiagnosticMessagePacket.dat b/Tests/Packet++Test/PacketExamples/DoIpDiagnosticMessagePacket.dat new file mode 100644 index 0000000000..0190992a5c --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpDiagnosticMessagePacket.dat @@ -0,0 +1 @@ +001a37bfee7454e1ad6bac15080045000036c274400040063873a9fe75efa9fe75eed25e3458ab87802f00191aa05018fadf4003000002fd8001000000060e8040101003 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/DoIpDiagnosticNackMessagePacket.dat b/Tests/Packet++Test/PacketExamples/DoIpDiagnosticNackMessagePacket.dat new file mode 100644 index 0000000000..a77cf20b32 --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpDiagnosticNackMessagePacket.dat @@ -0,0 +1 @@ +54e1ad6bac15001a37bfee740800450000384de80000ff062dfda9fe75eea9fe75ef3458d25e00191aa0ab87803d5018164f47a1000002fd80030000000840100e800222f101 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/DoIpEntityStatusRequestPacket.dat b/Tests/Packet++Test/PacketExamples/DoIpEntityStatusRequestPacket.dat new file mode 100644 index 0000000000..56d6b5f811 --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpEntityStatusRequestPacket.dat @@ -0,0 +1 @@ +001a37bfee7454e1ad6bac150800450000240001000040113aeea9fe75efa9fe75eeff1434580010498802fd400100000000 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/DoIpEntityStatusResponsePacket.dat b/Tests/Packet++Test/PacketExamples/DoIpEntityStatusResponsePacket.dat new file mode 100644 index 0000000000..3f5fd4c76f --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpEntityStatusResponsePacket.dat @@ -0,0 +1 @@ +54e1ad6bac15001a37bfee7408004500002b4db00000ff112e37a9fe75eea9fe75ef3458ff1400174a6102fd40020000000700010000000fff000000 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/DoIpGenericHeaderNackPacket.dat b/Tests/Packet++Test/PacketExamples/DoIpGenericHeaderNackPacket.dat new file mode 100644 index 0000000000..2a603d53c8 --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpGenericHeaderNackPacket.dat @@ -0,0 +1 @@ +54e1ad6bac15001a37bfee740800450000254dc10000ff112e2ca9fe75eea9fe75ef3458ff140011888602fd00000000000101000000000000000000 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/DoIpPowerModeRequestPacket.dat b/Tests/Packet++Test/PacketExamples/DoIpPowerModeRequestPacket.dat new file mode 100644 index 0000000000..76cccfe64b --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpPowerModeRequestPacket.dat @@ -0,0 +1 @@ +001a37bfee7454e1ad6bac150800450000240001000040113aeea9fe75efa9fe75eeff1434580010498602fd400300000000 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/DoIpPowerModeResponsePacket.dat b/Tests/Packet++Test/PacketExamples/DoIpPowerModeResponsePacket.dat new file mode 100644 index 0000000000..6b70489e04 --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpPowerModeResponsePacket.dat @@ -0,0 +1 @@ +54e1ad6bac15001a37bfee740800450000254dc30000ff112e2aa9fe75eea9fe75ef3458ff140011498202fd40040000000100000000000000000000 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/DoIpRoutingActivationRequestPacket.dat b/Tests/Packet++Test/PacketExamples/DoIpRoutingActivationRequestPacket.dat new file mode 100644 index 0000000000..daf6bcd5e3 --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpRoutingActivationRequestPacket.dat @@ -0,0 +1 @@ +001a37bfee7454e1ad6bac1508004500003bf0e44000400609fea9fe75efa9fe75eed25a345849689c4200186ab95018faf04008000002fd00050000000b0e80000000000000000000 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/DoIpRoutingActivationResponsePacket.dat b/Tests/Packet++Test/PacketExamples/DoIpRoutingActivationResponsePacket.dat new file mode 100644 index 0000000000..5bf7a68d79 --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpRoutingActivationResponsePacket.dat @@ -0,0 +1 @@ +54e1ad6bac15001a37bfee740800450000394dd20000ff062e12a9fe75eea9fe75ef3458d25a00186ab949689c555018165da0a5000002fd0006000000090e8040101000000000 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/DoIpVehicleAnnouncementPacket.dat b/Tests/Packet++Test/PacketExamples/DoIpVehicleAnnouncementPacket.dat new file mode 100644 index 0000000000..541bc2c052 --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpVehicleAnnouncementPacket.dat @@ -0,0 +1 @@ +ffffffffffff001a37bfee740800450000444d7c0000ff11a441a9fe75eea9feffff345834580030df5e02fd0004000000204241554e4545344d5a31373034323430334010001a37bfee74001a37bfee7400 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/DoIpVehicleIdentificationRequestEIDPacket.dat b/Tests/Packet++Test/PacketExamples/DoIpVehicleIdentificationRequestEIDPacket.dat new file mode 100644 index 0000000000..275dbdd4f7 --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpVehicleIdentificationRequestEIDPacket.dat @@ -0,0 +1 @@ +00e0b149390200137225facd08004500002a000000008011c8c8ac16b2ea0a0a08f0ff14345800167a8002fd0002000000064241554e4545 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/DoIpVehicleIdentificationRequestPacket.dat b/Tests/Packet++Test/PacketExamples/DoIpVehicleIdentificationRequestPacket.dat new file mode 100644 index 0000000000..6e9951bb7e --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpVehicleIdentificationRequestPacket.dat @@ -0,0 +1 @@ +001a37bfee7454e1ad6bac150800450000240001000040113aeea9fe75efa9fe75eeff1434580010898802fd000100000000 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/DoIpVehicleIdentificationRequestVINPacket.dat b/Tests/Packet++Test/PacketExamples/DoIpVehicleIdentificationRequestVINPacket.dat new file mode 100644 index 0000000000..975980797d --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/DoIpVehicleIdentificationRequestVINPacket.dat @@ -0,0 +1 @@ +001a37bfee7454e1ad6bac150800450000350001000040113adda9fe75efa9fe75eeff14345800214b6d02fd0003000000114241554e4545344d5a3137303432343033 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/doipPackets.pcapng b/Tests/Packet++Test/PacketExamples/doipPackets.pcapng new file mode 100644 index 0000000000..f7c5b3de21 Binary files /dev/null and b/Tests/Packet++Test/PacketExamples/doipPackets.pcapng differ diff --git a/Tests/Packet++Test/TestDefinition.h b/Tests/Packet++Test/TestDefinition.h index 9047e2682d..7cb9d555f7 100644 --- a/Tests/Packet++Test/TestDefinition.h +++ b/Tests/Packet++Test/TestDefinition.h @@ -88,6 +88,40 @@ PTF_TEST_CASE(DnsOverTcpParsingTest); PTF_TEST_CASE(DnsOverTcpCreationTest); PTF_TEST_CASE(DnsLayerAddDnsKeyTest); +// Implemented in DoIpTests.cpp +PTF_TEST_CASE(DoIpGenericHeaderNackPacketParsing); +PTF_TEST_CASE(DoIpGenericHeaderNackPacketCreation); +PTF_TEST_CASE(DoIpVehicleIdentificationRequestPacketParsing); +PTF_TEST_CASE(DoIpVehicleIdentificationRequestPacketCreation); +PTF_TEST_CASE(DoIpVehicleIdentificationRequestVINPacketParsing); +PTF_TEST_CASE(DoIpVehicleIdentificationRequestVINPacketCreation); +PTF_TEST_CASE(DoIpVehicleIdentificationRequestEIDPacketParsing); +PTF_TEST_CASE(DoIpVehicleIdentificationRequestEIDPacketCreation); +PTF_TEST_CASE(DoIpVehicleAnnouncementPacketParsing); +PTF_TEST_CASE(DoIpVehicleAnnouncementPacketCreation); +PTF_TEST_CASE(DoIpRoutingActivationRequestPacketParsing); +PTF_TEST_CASE(DoIpRoutingActivationRequestPacketCreation); +PTF_TEST_CASE(DoIpRoutingActivationResponsePacketParsing); +PTF_TEST_CASE(DoIpRoutingActivationResponsePacketCreation); +PTF_TEST_CASE(DoIpAliveCheckRequestPacketParsing); +PTF_TEST_CASE(DoIpAliveCheckRequestPacketCreation); +PTF_TEST_CASE(DoIpAliveCheckResponsePacketParsing); +PTF_TEST_CASE(DoIpAliveCheckResponsePacketCreation); +PTF_TEST_CASE(DoIpEntityStatusRequestPacketParsing); +PTF_TEST_CASE(DoIpEntityStatusRequestPacketCreation); +PTF_TEST_CASE(DoIpEntityStatusResponsePacketParsing); +PTF_TEST_CASE(DoIpEntityStatusResponsePacketCreation); +PTF_TEST_CASE(DoIpPowerModeRequestPacketParsing); +PTF_TEST_CASE(DoIpPowerModeRequestPacketCreation); +PTF_TEST_CASE(DoIpPowerModeResponsePacketParsing); +PTF_TEST_CASE(DoIpPowerModeResponsePacketCreation); +PTF_TEST_CASE(DoIpDiagnosticMessagePacketParsing); +PTF_TEST_CASE(DoIpDiagnosticMessagePacketCreation); +PTF_TEST_CASE(DoIpDiagnosticAckMessagePacketParsing); +PTF_TEST_CASE(DoIpDiagnosticAckMessagePacketCreation); +PTF_TEST_CASE(DoIpDiagnosticNackMessagePacketParsing); +PTF_TEST_CASE(DoIpDiagnosticNackMessagePacketCreation); + // Implemented in IcmpTests.cpp PTF_TEST_CASE(IcmpParsingTest); PTF_TEST_CASE(IcmpCreationTest); diff --git a/Tests/Packet++Test/Tests/DoIpTests.cpp b/Tests/Packet++Test/Tests/DoIpTests.cpp new file mode 100644 index 0000000000..22d7bff69c --- /dev/null +++ b/Tests/Packet++Test/Tests/DoIpTests.cpp @@ -0,0 +1,1379 @@ +#include "../TestDefinition.h" +#include "../Utils/TestUtils.h" +#include "EndianPortable.h" +#include "Packet.h" +#include "EthLayer.h" +#include "IPv4Layer.h" +#include "TcpLayer.h" +#include "UdpLayer.h" +#include "PayloadLayer.h" +#include "SystemUtils.h" +#include "PacketUtils.h" +#include "DeprecationUtils.h" +#include "DoIpLayer.h" +#include + +// ------------------ +// GenericHeaderNackPacket +PTF_TEST_CASE(DoIpGenericHeaderNackPacketParsing) +{ + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpGenericHeaderNackPacket.dat"); + + pcpp::Packet GenericHeaderNack(&rawPacket1); + PTF_ASSERT_TRUE(GenericHeaderNack.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(GenericHeaderNack.isPacketOfType(pcpp::UDP)); + PTF_ASSERT_TRUE(GenericHeaderNack.isPacketOfType(pcpp::DOIP)); + + pcpp::UdpLayer* udpLayer = GenericHeaderNack.getLayerOfType(); + PTF_ASSERT_NOT_NULL(udpLayer); + + PTF_ASSERT_EQUAL(udpLayer->getDstPort(), 65300); + PTF_ASSERT_EQUAL(udpLayer->getSrcPort(), pcpp::DoIpPorts::UDP_PORT); + PTF_ASSERT_EQUAL(udpLayer->getUdpHeader()->headerChecksum, be16toh(0x8886)); + + pcpp::DoIpLayer* doipLayer = GenericHeaderNack.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + // build doipData from existent layer + pcpp::GenericHeaderNackData data; + if (data.buildFromLayer(doipLayer)) + // std::cout << data.toString(); + PTF_ASSERT_EQUAL(data.toString(), "generic header nack code: Unknown payload type (0x1)\n"); + // wrong build + PTF_ASSERT_FALSE(data.buildFromLayer(nullptr)); + pcpp::RoutingActivationRequestData routingData; + PTF_ASSERT_FALSE(routingData.buildFromLayer(doipLayer)); + + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::GENERIC_HEADER_NEG_ACK, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), "Generic DOIP header Nack"); + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 1); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Generic DOIP header Nack (0x0000)\nPayload Length: 1\n") +} + +PTF_TEST_CASE(DoIpGenericHeaderNackPacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + pcpp::UdpLayer udpLayer((uint16_t)13400, (uint16_t)13400); + + ipLayer.getIPv4Header()->timeToLive = 128; + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&udpLayer)); + doIpPacket.computeCalculateFields(); + + unsigned char bytes[] = { 0x2, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1 }; + pcpp::GenericHeaderNackData data; + data.genericNackCode = pcpp::DoIpGenericHeaderNackCodes::INKNOWN_PAYLOAD_TYPE; + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::GENERIC_HEADER_NEG_ACK, &data); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + doIpPacket.computeCalculateFields(); + + // std::cout << + // pcpp::byteArrayToHexString(doIpPacket.getRawPacket()->getRawData(),doIpPacket.getRawPacket()->getRawDataLen()) << + // std::endl; + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 51); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (51 - 9), bytes, 9); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::GENERIC_HEADER_NEG_ACK, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), "Generic DOIP header Nack"); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 1); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Generic DOIP header Nack (0x0000)\nPayload Length: 1\n") +} +// DoIpVehicleIdentificationRequestPacketParsing +PTF_TEST_CASE(DoIpVehicleIdentificationRequestPacketParsing) +{ + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpVehicleIdentificationRequestPacket.dat"); + + pcpp::Packet vehicleIdentificationRequest(&rawPacket1); + PTF_ASSERT_TRUE(vehicleIdentificationRequest.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(vehicleIdentificationRequest.isPacketOfType(pcpp::UDP)); + PTF_ASSERT_TRUE(vehicleIdentificationRequest.isPacketOfType(pcpp::DOIP)); + + pcpp::UdpLayer* udpLayer = vehicleIdentificationRequest.getLayerOfType(); + PTF_ASSERT_NOT_NULL(udpLayer); + + PTF_ASSERT_EQUAL(udpLayer->getDstPort(), pcpp::DoIpPorts::UDP_PORT); + PTF_ASSERT_EQUAL(udpLayer->getSrcPort(), 65300); + PTF_ASSERT_EQUAL(udpLayer->getUdpHeader()->headerChecksum, be16toh(0x8988)); + PTF_ASSERT_EQUAL(udpLayer->getUdpHeader()->length, be16toh(0x10)); + + // DOIP fields for vehicle identification request + pcpp::DoIpLayer* doipLayer = vehicleIdentificationRequest.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + // PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012); + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), "Vehicle identification request"); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Vehicle identification request (0x0001)\nPayload Length: 0\n") + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 0x0); + +} // DoIpVehicleIdentificationRequestPacketParsing + +PTF_TEST_CASE(DoIpVehicleIdentificationRequestPacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + + ipLayer.getIPv4Header()->ipId = htobe16(20370); + ipLayer.getIPv4Header()->timeToLive = 128; + pcpp::UdpLayer udpLayer((uint16_t)65300, (uint16_t)13400); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&udpLayer)); + + unsigned char bytes[] = { 0x2, 0xfd, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0 }; + + // vehIdentificationRequestArgs.args = std::monostate{}; + + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 50); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (50 - 8), bytes, 8); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), "Vehicle identification request"); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Vehicle identification request (0x0001)\nPayload Length: 0\n") + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 0x0); +} +// VehicleIdentificationWithVIN +PTF_TEST_CASE(DoIpVehicleIdentificationRequestVINPacketParsing) +{ + // Dissect Vehicle identification Request with VIN + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpVehicleIdentificationRequestVINPacket.dat"); + + pcpp::Packet VehicleIdentificationRequestVIN(&rawPacket1); + PTF_ASSERT_TRUE(VehicleIdentificationRequestVIN.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(VehicleIdentificationRequestVIN.isPacketOfType(pcpp::UDP)); + PTF_ASSERT_TRUE(VehicleIdentificationRequestVIN.isPacketOfType(pcpp::DOIP)); + + pcpp::UdpLayer* udpLayer = VehicleIdentificationRequestVIN.getLayerOfType(); + PTF_ASSERT_NOT_NULL(udpLayer); + + PTF_ASSERT_EQUAL(udpLayer->getDstPort(), pcpp::DoIpPorts::UDP_PORT); + PTF_ASSERT_EQUAL(udpLayer->getSrcPort(), 65300); + PTF_ASSERT_EQUAL(udpLayer->getUdpHeader()->headerChecksum, be16toh(0x4b6d)); + PTF_ASSERT_EQUAL(udpLayer->getUdpHeader()->length, be16toh(33)); + + // DOIP fields for vehicle identification request + pcpp::DoIpLayer* doipLayer = VehicleIdentificationRequestVIN.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + // build doipData from existent layer + pcpp::VehicleIdentificationRequestVINData data; + if (data.buildFromLayer(doipLayer)) + // std::cout << data.toString(); + PTF_ASSERT_EQUAL(data.toString(), "VIN: BAUNEE4MZ17042403\n"); + // wrong build + PTF_ASSERT_FALSE(data.buildFromLayer(nullptr)); + pcpp::RoutingActivationRequestData routingData; + PTF_ASSERT_FALSE(routingData.buildFromLayer(doipLayer)); + + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_VIN, + enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), "Vehicle identification request with VIN"); + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 0x11); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Vehicle identification request with VIN (0x0003)\nPayload Length: 17\n") + +} // DoIpVehicleIdentificationRequestVINPacketParsing + +PTF_TEST_CASE(DoIpVehicleIdentificationRequestVINPacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + pcpp::UdpLayer udpLayer((uint16_t)65300, (uint16_t)13400); + + ipLayer.getIPv4Header()->timeToLive = 128; + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&udpLayer)); + doIpPacket.computeCalculateFields(); + + unsigned char bytes[] = { 0x2, 0xfd, 0x0, 0x3, 0x0, 0x0, 0x0, 0x11, 0x42, 0x41, 0x55, 0x4e, 0x45, + 0x45, 0x34, 0x4d, 0x5a, 0x31, 0x37, 0x30, 0x34, 0x32, 0x34, 0x30, 0x33 }; + std::array vin{ 0x42, 0x41, 0x55, 0x4e, 0x45, 0x45, 0x34, 0x4d, 0x5a, + 0x31, 0x37, 0x30, 0x34, 0x32, 0x34, 0x30, 0x33 }; + + pcpp::VehicleIdentificationRequestVINData withVin; + withVin.vin = vin; + + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_VIN, &withVin); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + doIpPacket.computeCalculateFields(); + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 67); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (67 - 25), bytes, 25); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_VIN, + enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), "Vehicle identification request with VIN"); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 17); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Vehicle identification request with VIN (0x0003)\nPayload Length: 17\n") +} +// VehicleIdentificationWithEID +PTF_TEST_CASE(DoIpVehicleIdentificationRequestEIDPacketParsing) +{ + // Dissect Vehicle identification Request with EID + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpVehicleIdentificationRequestEIDPacket.dat"); + + pcpp::Packet VehicleIdentificationRequestEID(&rawPacket1); + PTF_ASSERT_TRUE(VehicleIdentificationRequestEID.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(VehicleIdentificationRequestEID.isPacketOfType(pcpp::UDP)); + PTF_ASSERT_TRUE(VehicleIdentificationRequestEID.isPacketOfType(pcpp::DOIP)); + + pcpp::UdpLayer* udpLayer = VehicleIdentificationRequestEID.getLayerOfType(); + PTF_ASSERT_NOT_NULL(udpLayer); + + PTF_ASSERT_EQUAL(udpLayer->getDstPort(), pcpp::DoIpPorts::UDP_PORT); + PTF_ASSERT_EQUAL(udpLayer->getSrcPort(), 65300); + PTF_ASSERT_EQUAL(udpLayer->getUdpHeader()->headerChecksum, be16toh(0x7a80)); + PTF_ASSERT_EQUAL(udpLayer->getUdpHeader()->length, be16toh(0x16)); + + // DOIP fields for vehicle identification request + pcpp::DoIpLayer* doipLayer = VehicleIdentificationRequestEID.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + // build doipData from existent layer + pcpp::VehicleIdentificationRequestEIDData data; + if (data.buildFromLayer(doipLayer)) + // std::cout << data.toString(); + PTF_ASSERT_EQUAL(data.toString(), "EID: 4241554e4545\n"); + // wrong build + PTF_ASSERT_FALSE(data.buildFromLayer(nullptr)); + pcpp::RoutingActivationRequestData routingData; + PTF_ASSERT_FALSE(routingData.buildFromLayer(doipLayer)); + + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_EID, + enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), "Vehicle identification request with EID"); + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 0x6); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Vehicle identification request with EID (0x0002)\nPayload Length: 6\n") + +} // DoIpVehicleIdentificationRequestVINPacketParsing + +PTF_TEST_CASE(DoIpVehicleIdentificationRequestEIDPacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + pcpp::UdpLayer udpLayer((uint16_t)65300, (uint16_t)13400); + + ipLayer.getIPv4Header()->timeToLive = 128; + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&udpLayer)); + doIpPacket.computeCalculateFields(); + + unsigned char bytes[] = { 0x2, 0xfd, 0x0, 0x2, 0x0, 0x0, 0x0, 0x6, 0x42, 0x41, 0x55, 0x4e, 0x45, 0x45 }; + std::array eid{ 0x42, 0x41, 0x55, 0x4e, 0x45, 0x45 }; + + pcpp::VehicleIdentificationRequestEIDData withEID; + withEID.eid = eid; + + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_VIN, &withEID); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + doIpPacket.computeCalculateFields(); + + // std::cout << + // pcpp::byteArrayToHexString(doIpPacket.getRawPacket()->getRawData(),doIpPacket.getRawPacket()->getRawDataLen()) << + // std::endl; + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 56); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (56 - 14), bytes, 14); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::VEHICLE_IDENTIFICATION_REQUEST_WITH_EID, + enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), "Vehicle identification request with EID"); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 6); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Vehicle identification request with EID (0x0002)\nPayload Length: 6\n") +} +// VehicleAnnouncement +PTF_TEST_CASE(DoIpVehicleAnnouncementPacketParsing) +{ + // Dissect Vehicle Announcement message + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpVehicleAnnouncementPacket.dat"); + + pcpp::Packet VehicleAnnouncement(&rawPacket1); + PTF_ASSERT_TRUE(VehicleAnnouncement.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(VehicleAnnouncement.isPacketOfType(pcpp::UDP)); + PTF_ASSERT_TRUE(VehicleAnnouncement.isPacketOfType(pcpp::DOIP)); + + pcpp::UdpLayer* udpLayer = VehicleAnnouncement.getLayerOfType(); + PTF_ASSERT_NOT_NULL(udpLayer); + + PTF_ASSERT_EQUAL(udpLayer->getDstPort(), pcpp::DoIpPorts::UDP_PORT); + PTF_ASSERT_EQUAL(udpLayer->getSrcPort(), 13400); + PTF_ASSERT_EQUAL(udpLayer->getUdpHeader()->headerChecksum, be16toh(0xdf5e)); + PTF_ASSERT_EQUAL(udpLayer->getUdpHeader()->length, be16toh(0x30)); + + // DOIP fields for vehicle identification request + pcpp::DoIpLayer* doipLayer = VehicleAnnouncement.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + // build doipData from existent layer + pcpp::VehicleAnnouncementData data; + if (data.buildFromLayer(doipLayer)) + // std::cout << data.toString(); + PTF_ASSERT_EQUAL( + data.toString(), + "VIN: BAUNEE4MZ17042403\nlogical address: 0x4010\nEID: 001a37bfee74\nGID: 001a37bfee74\nfurther action required:No further action required (0x0)\nVIN/GID sync status: NULL\n"); + // wrong build + PTF_ASSERT_FALSE(data.buildFromLayer(nullptr)); + pcpp::RoutingActivationRequestData routingData; + PTF_ASSERT_FALSE(routingData.buildFromLayer(doipLayer)); + + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::ANNOUNCEMENT_MESSAGE, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), + "Vehicle announcement message / vehicle identification response message"); + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 32); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Vehicle announcement message / vehicle identification response message (0x0004)\nPayload Length: 32\n") + +} // DoIpVehicleAnnouncementPacketParsing + +PTF_TEST_CASE(DoIpVehicleAnnouncementPacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + pcpp::UdpLayer udpLayer((uint16_t)13400, (uint16_t)13400); + + ipLayer.getIPv4Header()->timeToLive = 128; + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&udpLayer)); + doIpPacket.computeCalculateFields(); + + unsigned char bytes[] = { 0x2, 0xfd, 0x0, 0x4, 0x0, 0x0, 0x0, 0x21, 0x42, 0x41, 0x55, 0x4e, 0x45, 0x45, + 0x34, 0x4d, 0x5a, 0x31, 0x37, 0x30, 0x34, 0x32, 0x34, 0x30, 0x33, 0x40, 0x10, 0x0, + 0x1a, 0x37, 0xbf, 0xee, 0x74, 0x0, 0x1a, 0x37, 0xbf, 0xee, 0x74, 0x0, 0x0 }; + std::array eid{ 0x0, 0x1a, 0x37, 0xbf, 0xee, 0x74 }; + std::array gid{ 0x0, 0x1a, 0x37, 0xbf, 0xee, 0x74 }; + std::array vin{ 0x42, 0x41, 0x55, 0x4e, 0x45, 0x45, 0x34, 0x4d, 0x5a, + 0x31, 0x37, 0x30, 0x34, 0x32, 0x34, 0x30, 0x33 }; + + pcpp::VehicleAnnouncementData ann; + ann.gid = gid; + ann.eid = eid; + ann.vin = vin; + ann.logicalAddress = be16toh(0x4010); + ann.syncStatus = pcpp::DoIpSyncStatus::VIN_AND_OR_GID_ARE_SINCHRONIZED; + ann.furtherActionRequired = pcpp::DoIpActionCodes::NO_FURTHER_ACTION_REQUIRED; + + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::ANNOUNCEMENT_MESSAGE, &ann); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + doIpPacket.computeCalculateFields(); + + // std::cout << + // pcpp::byteArrayToHexString(doIpPacket.getRawPacket()->getRawData(),doIpPacket.getRawPacket()->getRawDataLen()) << + // std::endl; + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 83); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (83 - 41), bytes, 41); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::ANNOUNCEMENT_MESSAGE, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), + "Vehicle announcement message / vehicle identification response message"); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 33); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Vehicle announcement message / vehicle identification response message (0x0004)\nPayload Length: 33\n") +} +// RoutingActivationRequest +PTF_TEST_CASE(DoIpRoutingActivationRequestPacketParsing) +{ + // Dissect Vehicle Announcement message + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpRoutingActivationRequestPacket.dat"); + + pcpp::Packet RoutingActivationRequest(&rawPacket1); + PTF_ASSERT_TRUE(RoutingActivationRequest.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(RoutingActivationRequest.isPacketOfType(pcpp::TCP)); + PTF_ASSERT_TRUE(RoutingActivationRequest.isPacketOfType(pcpp::DOIP)); + + pcpp::TcpLayer* tcpLayer = RoutingActivationRequest.getLayerOfType(); + PTF_ASSERT_NOT_NULL(tcpLayer); + + PTF_ASSERT_EQUAL(tcpLayer->getDstPort(), pcpp::DoIpPorts::TCP_PORT); + PTF_ASSERT_EQUAL(tcpLayer->getSrcPort(), 53850); + PTF_ASSERT_EQUAL(tcpLayer->getTcpHeader()->headerChecksum, be16toh(0x4008)); + + pcpp::DoIpLayer* doipLayer = RoutingActivationRequest.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + // build doipData from existent layer + pcpp::RoutingActivationRequestData data; + if (data.buildFromLayer(doipLayer)) + // std::cout << data.toString(); + + PTF_ASSERT_EQUAL( + data.toString(), + "sourceAddress: 0xe80\nactivation type: Default (0x0)\nreserved by ISO: 00000000\nReserved by OEM: 00000000\n"); + // wrong build + PTF_ASSERT_FALSE(data.buildFromLayer(nullptr)); + pcpp::RoutingActivationResponseData routingData; + PTF_ASSERT_FALSE(routingData.buildFromLayer(doipLayer)); + + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::ROUTING_ACTIVATION_REQUEST, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), "Routing activation request"); + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 11); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Routing activation request (0x0005)\nPayload Length: 11\n") +} + +PTF_TEST_CASE(DoIpRoutingActivationRequestPacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + pcpp::TcpLayer tcpLayer((uint16_t)13400, (uint16_t)13400); + + tcpLayer.getTcpHeader()->windowSize = 64240; + ipLayer.getIPv4Header()->timeToLive = 128; + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&tcpLayer)); + doIpPacket.computeCalculateFields(); + + unsigned char bytes[] = { 0x2, 0xfd, 0x0, 0x5, 0x0, 0x0, 0x0, 0xb, 0xe, 0x80, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + pcpp::RoutingActivationRequestData routingData; + routingData.sourceAddress = be16toh(0x0e80); + routingData.activationType = pcpp::DoIpActivationTypes::Default; + routingData.reservedIso = { 0x0, 0x0, 0x0, 0x0 }; + routingData.reservedOem = std::unique_ptr>(new std::array()); + + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::ROUTING_ACTIVATION_REQUEST, &routingData); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + doIpPacket.computeCalculateFields(); + + // std::cout << + // pcpp::byteArrayToHexString(doIpPacket.getRawPacket()->getRawData(),doIpPacket.getRawPacket()->getRawDataLen()) << + // std::endl; + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 73); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (73 - 19), bytes, 19); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::ROUTING_ACTIVATION_REQUEST, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), "Routing activation request"); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 11); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Routing activation request (0x0005)\nPayload Length: 11\n") +} +// RoutingActivationResponse +PTF_TEST_CASE(DoIpRoutingActivationResponsePacketParsing) +{ + // Dissect Vehicle Announcement message + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpRoutingActivationResponsePacket.dat"); + + pcpp::Packet RoutingActivationResponse(&rawPacket1); + PTF_ASSERT_TRUE(RoutingActivationResponse.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(RoutingActivationResponse.isPacketOfType(pcpp::TCP)); + PTF_ASSERT_TRUE(RoutingActivationResponse.isPacketOfType(pcpp::DOIP)); + + pcpp::TcpLayer* tcpLayer = RoutingActivationResponse.getLayerOfType(); + PTF_ASSERT_NOT_NULL(tcpLayer); + + PTF_ASSERT_EQUAL(tcpLayer->getDstPort(), 53850); + PTF_ASSERT_EQUAL(tcpLayer->getSrcPort(), pcpp::DoIpPorts::TCP_PORT); + PTF_ASSERT_EQUAL(tcpLayer->getTcpHeader()->headerChecksum, be16toh(0xa0a5)); + + pcpp::DoIpLayer* doipLayer = RoutingActivationResponse.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + pcpp::RoutingActivationResponseData data; + if (data.buildFromLayer(doipLayer)) + // std::cout << data.toString(); + PTF_ASSERT_EQUAL( + data.toString(), + "logical address of external tester: 0xe80\nsource address: 0x4010\nrouting activation response code: Routing successfully activated (0x10)\nreserved by ISO: 00000000\n"); + // wrong build + PTF_ASSERT_FALSE(data.buildFromLayer(nullptr)); + pcpp::RoutingActivationRequestData routingData; + PTF_ASSERT_FALSE(routingData.buildFromLayer(doipLayer)); + + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::ROUTING_ACTIVATION_RESPONSE, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), "Routing activation response"); + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 9); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Routing activation response (0x0006)\nPayload Length: 9\n") +} + +PTF_TEST_CASE(DoIpRoutingActivationResponsePacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + pcpp::TcpLayer tcpLayer((uint16_t)13400, (uint16_t)13400); + + tcpLayer.getTcpHeader()->windowSize = 64240; + ipLayer.getIPv4Header()->timeToLive = 128; + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&tcpLayer)); + doIpPacket.computeCalculateFields(); + + unsigned char bytes[] = { 0x2, 0xfd, 0x0, 0x6, 0x0, 0x0, 0x0, 0xd, 0xe, 0x80, 0x40, + 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + pcpp::RoutingActivationResponseData routingData; + routingData.logicalAddressExternalTester = be16toh(0x0e80); + routingData.sourceAddress = be16toh(0x4010); + routingData.responseCode = pcpp::DoIpRoutingResponseCodes::ROUTING_SUCCESSFULLY_ACTIVATED; + routingData.reservedIso = { 0x0, 0x0, 0x0, 0x0 }; + routingData.reservedOem = std::unique_ptr>(new std::array()); + + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::ROUTING_ACTIVATION_RESPONSE, &routingData); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + doIpPacket.computeCalculateFields(); + + // std::cout << + // pcpp::byteArrayToHexString(doIpPacket.getRawPacket()->getRawData(),doIpPacket.getRawPacket()->getRawDataLen()) << + // std::endl; + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 75); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (75 - 21), bytes, 21); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::ROUTING_ACTIVATION_RESPONSE, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), "Routing activation response"); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 13); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Routing activation response (0x0006)\nPayload Length: 13\n") +} +// --------------- +// AliveCheckRequestPacket +PTF_TEST_CASE(DoIpAliveCheckRequestPacketParsing) +{ + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpAliveCheckRequestPacket.dat"); + + pcpp::Packet AliveCheckRequest(&rawPacket1); + PTF_ASSERT_TRUE(AliveCheckRequest.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(AliveCheckRequest.isPacketOfType(pcpp::UDP)); + PTF_ASSERT_TRUE(AliveCheckRequest.isPacketOfType(pcpp::DOIP)); + + pcpp::UdpLayer* udpLayer = AliveCheckRequest.getLayerOfType(); + PTF_ASSERT_NOT_NULL(udpLayer); + + PTF_ASSERT_EQUAL(udpLayer->getDstPort(), pcpp::DoIpPorts::UDP_PORT); + PTF_ASSERT_EQUAL(udpLayer->getSrcPort(), 65300); + PTF_ASSERT_EQUAL(udpLayer->getUdpHeader()->headerChecksum, be16toh(0x8982)); + + pcpp::DoIpLayer* doipLayer = AliveCheckRequest.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::ALIVE_CHECK_REQUEST, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), "Alive check request"); + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 0); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Alive check request (0x0007)\nPayload Length: 0\n") +} + +PTF_TEST_CASE(DoIpAliveCheckRequestPacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + pcpp::UdpLayer udpLayer((uint16_t)13400, (uint16_t)13400); + + ipLayer.getIPv4Header()->timeToLive = 128; + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&udpLayer)); + doIpPacket.computeCalculateFields(); + + unsigned char bytes[] = { 0x2, 0xfd, 0x0, 0x7, 0x0, 0x0, 0x0, 0x0 }; + + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::ALIVE_CHECK_REQUEST); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + doIpPacket.computeCalculateFields(); + + // std::cout << + // pcpp::byteArrayToHexString(doIpPacket.getRawPacket()->getRawData(),doIpPacket.getRawPacket()->getRawDataLen()) << + // std::endl; + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 50); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (50 - 8), bytes, 8); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::ALIVE_CHECK_REQUEST, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), "Alive check request"); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 0); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Alive check request (0x0007)\nPayload Length: 0\n") +} +// --------------- +// AliveCheckResponsePacket +PTF_TEST_CASE(DoIpAliveCheckResponsePacketParsing) +{ + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpAliveCheckResponsePacket.dat"); + + pcpp::Packet AliveCheckResponse(&rawPacket1); + PTF_ASSERT_TRUE(AliveCheckResponse.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(AliveCheckResponse.isPacketOfType(pcpp::UDP)); + PTF_ASSERT_TRUE(AliveCheckResponse.isPacketOfType(pcpp::DOIP)); + + pcpp::UdpLayer* udpLayer = AliveCheckResponse.getLayerOfType(); + PTF_ASSERT_NOT_NULL(udpLayer); + + PTF_ASSERT_EQUAL(udpLayer->getDstPort(), pcpp::DoIpPorts::UDP_PORT); + PTF_ASSERT_EQUAL(udpLayer->getSrcPort(), 65300); + PTF_ASSERT_EQUAL(udpLayer->getUdpHeader()->headerChecksum, be16toh(0x897b)); + + pcpp::DoIpLayer* doipLayer = AliveCheckResponse.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + // build doipData from existent layer + pcpp::AliveCheckResponseData data; + if (data.buildFromLayer(doipLayer)) + // std::cout << data.toString(); + PTF_ASSERT_EQUAL(data.toString(), "source address: 0x0\n"); + // wrong build + PTF_ASSERT_FALSE(data.buildFromLayer(nullptr)); + pcpp::RoutingActivationRequestData routingData; + PTF_ASSERT_FALSE(routingData.buildFromLayer(doipLayer)); + + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::ALIVE_CHECK_RESPONSE, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), "Alive check response"); + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 2); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Alive check response (0x0008)\nPayload Length: 2\n") +} + +PTF_TEST_CASE(DoIpAliveCheckResponsePacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + pcpp::UdpLayer udpLayer((uint16_t)13400, (uint16_t)13400); + + ipLayer.getIPv4Header()->timeToLive = 128; + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&udpLayer)); + doIpPacket.computeCalculateFields(); + + unsigned char bytes[] = { 0x2, 0xfd, 0x0, 0x8, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0 }; + pcpp::AliveCheckResponseData aliveCheckRespData; + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::ALIVE_CHECK_RESPONSE, &aliveCheckRespData); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + doIpPacket.computeCalculateFields(); + + // std::cout << + // pcpp::byteArrayToHexString(doIpPacket.getRawPacket()->getRawData(),doIpPacket.getRawPacket()->getRawDataLen()) << + // std::endl; + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 52); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (52 - 10), bytes, 10); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::ALIVE_CHECK_RESPONSE, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), "Alive check response"); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 2); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Alive check response (0x0008)\nPayload Length: 2\n") +} +// ------------------ +// EntityStatusRequestPacket +PTF_TEST_CASE(DoIpEntityStatusRequestPacketParsing) +{ + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpEntityStatusRequestPacket.dat"); + + pcpp::Packet EntityStatusRequest(&rawPacket1); + PTF_ASSERT_TRUE(EntityStatusRequest.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(EntityStatusRequest.isPacketOfType(pcpp::UDP)); + PTF_ASSERT_TRUE(EntityStatusRequest.isPacketOfType(pcpp::DOIP)); + + pcpp::UdpLayer* udpLayer = EntityStatusRequest.getLayerOfType(); + PTF_ASSERT_NOT_NULL(udpLayer); + + PTF_ASSERT_EQUAL(udpLayer->getDstPort(), pcpp::DoIpPorts::UDP_PORT); + PTF_ASSERT_EQUAL(udpLayer->getSrcPort(), 65300); + PTF_ASSERT_EQUAL(udpLayer->getUdpHeader()->headerChecksum, be16toh(0x4988)); + + pcpp::DoIpLayer* doipLayer = EntityStatusRequest.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::ENTITY_STATUS_REQUEST, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), "DOIP entity status request"); + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 0); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: DOIP entity status request (0x4001)\nPayload Length: 0\n") +} + +PTF_TEST_CASE(DoIpEntityStatusRequestPacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + pcpp::UdpLayer udpLayer((uint16_t)13400, (uint16_t)13400); + + ipLayer.getIPv4Header()->timeToLive = 128; + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&udpLayer)); + doIpPacket.computeCalculateFields(); + + unsigned char bytes[] = { 0x2, 0xfd, 0x40, 0x1, 0x0, 0x0, 0x0, 0x0 }; + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::ENTITY_STATUS_REQUEST); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + doIpPacket.computeCalculateFields(); + + // std::cout << + // pcpp::byteArrayToHexString(doIpPacket.getRawPacket()->getRawData(),doIpPacket.getRawPacket()->getRawDataLen()) << + // std::endl; + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 50); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (50 - 8), bytes, 8); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::ENTITY_STATUS_REQUEST, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), "DOIP entity status request"); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 0); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: DOIP entity status request (0x4001)\nPayload Length: 0\n") +} +// ------------------ +// EntityStatusResponsePacket +PTF_TEST_CASE(DoIpEntityStatusResponsePacketParsing) +{ + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpEntityStatusResponsePacket.dat"); + + pcpp::Packet EntityStatusResponse(&rawPacket1); + PTF_ASSERT_TRUE(EntityStatusResponse.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(EntityStatusResponse.isPacketOfType(pcpp::UDP)); + PTF_ASSERT_TRUE(EntityStatusResponse.isPacketOfType(pcpp::DOIP)); + + pcpp::UdpLayer* udpLayer = EntityStatusResponse.getLayerOfType(); + PTF_ASSERT_NOT_NULL(udpLayer); + + PTF_ASSERT_EQUAL(udpLayer->getDstPort(), 65300); + PTF_ASSERT_EQUAL(udpLayer->getSrcPort(), pcpp::DoIpPorts::UDP_PORT); + PTF_ASSERT_EQUAL(udpLayer->getUdpHeader()->headerChecksum, be16toh(0x4a61)); + + pcpp::DoIpLayer* doipLayer = EntityStatusResponse.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + pcpp::EntityStatusResponseData data; + if (data.buildFromLayer(doipLayer)) + // std::cout << data.toString(); + PTF_ASSERT_EQUAL( + data.toString(), + "Entity status: DoIP gateway (0x0)\nmaximum Concurrent Socket: 1\ncurrently Opened Socket: 0\nmaximum Data Size: 0x00000fff\n"); + // wrong build + PTF_ASSERT_FALSE(data.buildFromLayer(nullptr)); + pcpp::RoutingActivationRequestData routingData; + PTF_ASSERT_FALSE(routingData.buildFromLayer(doipLayer)); + + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::ENTITY_STATUS_RESPONSE, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), "DOIP entity status response"); + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 7); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: DOIP entity status response (0x4002)\nPayload Length: 7\n") +} + +PTF_TEST_CASE(DoIpEntityStatusResponsePacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + pcpp::UdpLayer udpLayer((uint16_t)13400, (uint16_t)13400); + + ipLayer.getIPv4Header()->timeToLive = 128; + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&udpLayer)); + doIpPacket.computeCalculateFields(); + + unsigned char bytes[] = { 0x2, 0xfd, 0x40, 0x2, 0x0, 0x0, 0x0, 0x7, 0x0, 0x2, 0x2, 0x0, 0x0, 0xf, 0xff }; + pcpp::EntityStatusResponseData entityResponseData; + entityResponseData.currentlyOpenSockets = 2; + entityResponseData.maxConcurrentSockets = 2; + entityResponseData.maxDataSize = + std::unique_ptr>(new std::array{ 0x0, 0x0, 0xf, 0xff }); + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::ENTITY_STATUS_RESPONSE, &entityResponseData); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + doIpPacket.computeCalculateFields(); + + // std::cout << + // pcpp::byteArrayToHexString(doIpPacket.getRawPacket()->getRawData(),doIpPacket.getRawPacket()->getRawDataLen()) << + // std::endl; + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 57); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (57 - 15), bytes, 15); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::ENTITY_STATUS_RESPONSE, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), "DOIP entity status response"); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 7); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: DOIP entity status response (0x4002)\nPayload Length: 7\n") +} +// ------------------ +// PowerModeRequestPacket +PTF_TEST_CASE(DoIpPowerModeRequestPacketParsing) +{ + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpPowerModeRequestPacket.dat"); + + pcpp::Packet PowerModeRequest(&rawPacket1); + PTF_ASSERT_TRUE(PowerModeRequest.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(PowerModeRequest.isPacketOfType(pcpp::UDP)); + PTF_ASSERT_TRUE(PowerModeRequest.isPacketOfType(pcpp::DOIP)); + + pcpp::UdpLayer* udpLayer = PowerModeRequest.getLayerOfType(); + PTF_ASSERT_NOT_NULL(udpLayer); + + PTF_ASSERT_EQUAL(udpLayer->getDstPort(), pcpp::DoIpPorts::UDP_PORT); + PTF_ASSERT_EQUAL(udpLayer->getSrcPort(), 65300); + PTF_ASSERT_EQUAL(udpLayer->getUdpHeader()->headerChecksum, be16toh(0x4986)); + + pcpp::DoIpLayer* doipLayer = PowerModeRequest.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_REQUEST, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), "Diagnostic power mode request information"); + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 0); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Diagnostic power mode request information (0x4003)\nPayload Length: 0\n") +} + +PTF_TEST_CASE(DoIpPowerModeRequestPacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + pcpp::UdpLayer udpLayer((uint16_t)13400, (uint16_t)13400); + + ipLayer.getIPv4Header()->timeToLive = 128; + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&udpLayer)); + doIpPacket.computeCalculateFields(); + + unsigned char bytes[] = { 0x2, 0xfd, 0x40, 0x3, 0x0, 0x0, 0x0, 0x0 }; + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_REQUEST); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + doIpPacket.computeCalculateFields(); + + // std::cout << + // pcpp::byteArrayToHexString(doIpPacket.getRawPacket()->getRawData(),doIpPacket.getRawPacket()->getRawDataLen()) << + // std::endl; + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 50); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (50 - 8), bytes, 8); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_REQUEST, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), "Diagnostic power mode request information"); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 0); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Diagnostic power mode request information (0x4003)\nPayload Length: 0\n") +} +// ------------------ +// PowerModeResponsePacket +PTF_TEST_CASE(DoIpPowerModeResponsePacketParsing) +{ + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpPowerModeResponsePacket.dat"); + + pcpp::Packet PowerModeResponse(&rawPacket1); + PTF_ASSERT_TRUE(PowerModeResponse.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(PowerModeResponse.isPacketOfType(pcpp::UDP)); + PTF_ASSERT_TRUE(PowerModeResponse.isPacketOfType(pcpp::DOIP)); + + pcpp::UdpLayer* udpLayer = PowerModeResponse.getLayerOfType(); + PTF_ASSERT_NOT_NULL(udpLayer); + + PTF_ASSERT_EQUAL(udpLayer->getDstPort(), 65300); + PTF_ASSERT_EQUAL(udpLayer->getSrcPort(), pcpp::DoIpPorts::UDP_PORT); + // PTF_ASSERT_EQUAL(udpLayer->getUdpHeader()->headerChecksum, be16toh(0x2e2a)); + + pcpp::DoIpLayer* doipLayer = PowerModeResponse.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + pcpp::DiagnosticPowerModeResponseData data; + if (data.buildFromLayer(doipLayer)) + // std::cout << data.toString(); + PTF_ASSERT_EQUAL(data.toString(), "diagnostic power mode: not ready (0x0)\n"); + // wrong build + PTF_ASSERT_FALSE(data.buildFromLayer(nullptr)); + pcpp::RoutingActivationRequestData routingData; + PTF_ASSERT_FALSE(routingData.buildFromLayer(doipLayer)); + + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_RESPONSE, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), "Diagnostic power mode response information"); + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 1); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Diagnostic power mode response information (0x4004)\nPayload Length: 1\n") +} + +PTF_TEST_CASE(DoIpPowerModeResponsePacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + pcpp::UdpLayer udpLayer((uint16_t)13400, (uint16_t)13400); + + ipLayer.getIPv4Header()->timeToLive = 128; + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&udpLayer)); + doIpPacket.computeCalculateFields(); + + unsigned char bytes[] = { 0x2, 0xfd, 0x40, 0x4, 0x0, 0x0, 0x0, 0x1, 0x0 }; + pcpp::DiagnosticPowerModeResponseData data; + data.powerModeCode = pcpp::DoIpDiagnosticPowerModeCodes::NOT_READY; + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_RESPONSE, &data); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + doIpPacket.computeCalculateFields(); + + // std::cout << + // pcpp::byteArrayToHexString(doIpPacket.getRawPacket()->getRawData(),doIpPacket.getRawPacket()->getRawDataLen()) << + // std::endl; + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 51); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (51 - 9), bytes, 9); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::DIAGNOSTIC_POWER_MODE_RESPONSE, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), "Diagnostic power mode response information"); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 1); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Diagnostic power mode response information (0x4004)\nPayload Length: 1\n") +} +// ------------------ +// DiagnosticMessagePacket +PTF_TEST_CASE(DoIpDiagnosticMessagePacketParsing) +{ + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpDiagnosticMessagePacket.dat"); + + pcpp::Packet DiagnosticMessagePacket(&rawPacket1); + PTF_ASSERT_TRUE(DiagnosticMessagePacket.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(DiagnosticMessagePacket.isPacketOfType(pcpp::TCP)); + PTF_ASSERT_TRUE(DiagnosticMessagePacket.isPacketOfType(pcpp::DOIP)); + + pcpp::TcpLayer* tcpLayer = DiagnosticMessagePacket.getLayerOfType(); + PTF_ASSERT_NOT_NULL(tcpLayer); + + PTF_ASSERT_EQUAL(tcpLayer->getDstPort(), pcpp::DoIpPorts::TCP_PORT); + PTF_ASSERT_EQUAL(tcpLayer->getSrcPort(), 53854); + PTF_ASSERT_EQUAL(tcpLayer->getTcpHeader()->headerChecksum, be16toh(0x4003)); + + pcpp::DoIpLayer* doipLayer = DiagnosticMessagePacket.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + pcpp::DiagnosticMessageData data; + if (data.buildFromLayer(doipLayer)) + // std::cout << data.toString(); + PTF_ASSERT_EQUAL(data.toString(), "source address: 0xe80\ntarget address: 0x4010\n"); + // wrong build + PTF_ASSERT_FALSE(data.buildFromLayer(nullptr)); + pcpp::RoutingActivationRequestData routingData; + PTF_ASSERT_FALSE(routingData.buildFromLayer(doipLayer)); + + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_TYPE, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), "Diagnostic message"); + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 6); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Diagnostic message (0x8001)\nPayload Length: 6\n") +} + +PTF_TEST_CASE(DoIpDiagnosticMessagePacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + pcpp::TcpLayer tcpLayer((uint16_t)13400, (uint16_t)13400); + + ipLayer.getIPv4Header()->timeToLive = 128; + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&tcpLayer)); + doIpPacket.computeCalculateFields(); + + unsigned char bytes[] = { 0x2, 0xfd, 0x80, 0x1, 0x0, 0x0, 0x0, 0x6, 0xe, 0x80, 0x40, 0x10, 0x10, 0x3 }; + std::vector diagnosticData{ 0x10, 0x03 }; + + pcpp::DiagnosticMessageData data; + data.sourceAddress = be16toh(0x0e80); + data.targetAddress = be16toh(0x4010); + data.diagnosticData = diagnosticData; + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_TYPE, &data); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + doIpPacket.computeCalculateFields(); + + // std::cout << + // pcpp::byteArrayToHexString(doIpPacket.getRawPacket()->getRawData(),doIpPacket.getRawPacket()->getRawDataLen()) << + // std::endl; + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 68); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (68 - 14), bytes, 14); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_TYPE, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), "Diagnostic message"); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 6); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Diagnostic message (0x8001)\nPayload Length: 6\n"); +} +// ------------------ +// DiagnosticAckMessagePacket +PTF_TEST_CASE(DoIpDiagnosticAckMessagePacketParsing) +{ + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpDiagnosticAckMessagePacket.dat"); + + pcpp::Packet DiagnosticAckMessage(&rawPacket1); + PTF_ASSERT_TRUE(DiagnosticAckMessage.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(DiagnosticAckMessage.isPacketOfType(pcpp::TCP)); + PTF_ASSERT_TRUE(DiagnosticAckMessage.isPacketOfType(pcpp::DOIP)); + + pcpp::TcpLayer* tcpLayer = DiagnosticAckMessage.getLayerOfType(); + PTF_ASSERT_NOT_NULL(tcpLayer); + + PTF_ASSERT_EQUAL(tcpLayer->getDstPort(), 53854); + PTF_ASSERT_EQUAL(tcpLayer->getSrcPort(), pcpp::DoIpPorts::TCP_PORT); + PTF_ASSERT_EQUAL(tcpLayer->getTcpHeader()->headerChecksum, be16toh(0x49a2)); + + pcpp::DoIpLayer* doipLayer = DiagnosticAckMessage.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + pcpp::DiagnosticAckMessageData data; + if (data.buildFromLayer(doipLayer)) + // std::cout << data.toString(); + PTF_ASSERT_EQUAL( + data.toString(), + "source address: 0x4010\ntarget address: 0xe80\nack code: ACK (0x0)\nprevious message: 22f101\n"); + // wrong build + PTF_ASSERT_FALSE(data.buildFromLayer(nullptr)); + pcpp::RoutingActivationRequestData routingData; + PTF_ASSERT_FALSE(routingData.buildFromLayer(doipLayer)); + + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_POS_ACK, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), "Diagnostic message Ack"); + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 8); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Diagnostic message Ack (0x8002)\nPayload Length: 8\n") +} + +PTF_TEST_CASE(DoIpDiagnosticAckMessagePacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + pcpp::TcpLayer tcpLayer((uint16_t)13400, (uint16_t)13400); + + ipLayer.getIPv4Header()->timeToLive = 128; + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&tcpLayer)); + doIpPacket.computeCalculateFields(); + + unsigned char bytes[] = { 0x2, 0xfd, 0x80, 0x2, 0x0, 0x0, 0x0, 0x5, 0x40, 0x10, 0xe, 0x80, 0x0 }; + + pcpp::DiagnosticAckMessageData data; + data.sourceAddress = be16toh(0x4010); + data.targetAddress = be16toh(0x0e80); + data.ackCode = pcpp::DoIpDiagnosticAckCodes::ACK; + // dont use previous message + data.previousMessage.clear(); + + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_POS_ACK, &data); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + doIpPacket.computeCalculateFields(); + + // std::cout << + // pcpp::byteArrayToHexString(doIpPacket.getRawPacket()->getRawData(),doIpPacket.getRawPacket()->getRawDataLen()) << + // std::endl; + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 67); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (67 - 13), bytes, 13); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_POS_ACK, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), "Diagnostic message Ack"); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 5); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Diagnostic message Ack (0x8002)\nPayload Length: 5\n"); +} +// ------------------ +// DiagnosticNackMessagePacket +PTF_TEST_CASE(DoIpDiagnosticNackMessagePacketParsing) +{ + timeval time; + gettimeofday(&time, nullptr); + + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/DoIpDiagnosticNackMessagePacket.dat"); + + pcpp::Packet DiagnosticNackMessage(&rawPacket1); + PTF_ASSERT_TRUE(DiagnosticNackMessage.isPacketOfType(pcpp::IPv4)); + PTF_ASSERT_TRUE(DiagnosticNackMessage.isPacketOfType(pcpp::TCP)); + PTF_ASSERT_TRUE(DiagnosticNackMessage.isPacketOfType(pcpp::DOIP)); + + pcpp::TcpLayer* tcpLayer = DiagnosticNackMessage.getLayerOfType(); + PTF_ASSERT_NOT_NULL(tcpLayer); + + PTF_ASSERT_EQUAL(tcpLayer->getDstPort(), 53854); + PTF_ASSERT_EQUAL(tcpLayer->getSrcPort(), pcpp::DoIpPorts::TCP_PORT); + PTF_ASSERT_EQUAL(tcpLayer->getTcpHeader()->headerChecksum, be16toh(0x47a1)); + + pcpp::DoIpLayer* doipLayer = DiagnosticNackMessage.getLayerOfType(); + PTF_ASSERT_NOT_NULL(doipLayer); + + pcpp::DiagnosticNackMessageData data; + if (data.buildFromLayer(doipLayer)) + // std::cout << data.toString(); + PTF_ASSERT_EQUAL( + data.toString(), + "source address: 0x4010\ntarget address: 0xe80\nnack code: Invalid source address (0x2)\nprevious message: 22f101\n"); + // wrong build + PTF_ASSERT_FALSE(data.buildFromLayer(nullptr)); + pcpp::RoutingActivationRequestData routingData; + PTF_ASSERT_FALSE(routingData.buildFromLayer(doipLayer)); + + PTF_ASSERT_EQUAL(doipLayer->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(doipLayer->getPayloadType(), pcpp::DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_NEG_ACK, enumclass); + PTF_ASSERT_EQUAL(doipLayer->getPayloadTypeAsStr(), "Diagnostic message Nack"); + PTF_ASSERT_EQUAL(doipLayer->getPayloadLength(), 8); + PTF_ASSERT_EQUAL( + doipLayer->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Diagnostic message Nack (0x8003)\nPayload Length: 8\n") +} + +PTF_TEST_CASE(DoIpDiagnosticNackMessagePacketCreation) +{ + pcpp::Packet doIpPacket(100); + pcpp::EthLayer ethLayer(pcpp::MacAddress("00:13:72:25:fa:cd"), pcpp::MacAddress("00:e0:b1:49:39:02")); + pcpp::IPv4Layer ipLayer(pcpp::IPv4Address("172.22.178.234"), pcpp::IPv4Address("10.10.8.240")); + pcpp::TcpLayer tcpLayer((uint16_t)13400, (uint16_t)13400); + + ipLayer.getIPv4Header()->timeToLive = 128; + + PTF_ASSERT_TRUE(doIpPacket.addLayer(ðLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&ipLayer)); + PTF_ASSERT_TRUE(doIpPacket.addLayer(&tcpLayer)); + doIpPacket.computeCalculateFields(); + + unsigned char bytes[] = { 0x2, 0xfd, 0x80, 0x3, 0x0, 0x0, 0x0, 0x5, 0x40, 0x10, 0xe, 0x80, 0x2 }; + + pcpp::DiagnosticNackMessageData data; + data.sourceAddress = be16toh(0x4010); + data.targetAddress = be16toh(0x0e80); + data.nackCode = pcpp::DoIpDiagnosticMessageNackCodes::INVALID_SOURCE_ADDRESS; + // dont use previous message + data.previousMessage.clear(); + + pcpp::DoIpLayer doipLayer_2(pcpp::DoIpProtocolVersion::version02Iso2012, + pcpp::DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_NEG_ACK, &data); + + PTF_ASSERT_TRUE(doIpPacket.addLayer(&doipLayer_2)); + doIpPacket.computeCalculateFields(); + + PTF_ASSERT_EQUAL(doIpPacket.getRawPacket()->getRawDataLen(), 67); + PTF_ASSERT_BUF_COMPARE(doIpPacket.getRawPacket()->getRawData() + (67 - 13), bytes, 13); + pcpp::DoIpLayer* _doipLayer2 = doIpPacket.getLayerOfType(); + + PTF_ASSERT_EQUAL(_doipLayer2->getProtocolVersion(), pcpp::DoIpProtocolVersion::version02Iso2012, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getInvertProtocolVersion(), 0xFD); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadType(), pcpp::DoIpPayloadTypes::DIAGNOSTIC_MESSAGE_NEG_ACK, enumclass); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadTypeAsStr(), "Diagnostic message Nack"); + PTF_ASSERT_EQUAL(_doipLayer2->getPayloadLength(), 5); + PTF_ASSERT_EQUAL( + _doipLayer2->toString(), + "DOIP Layer:\nProtocol Version: DoIP ISO 13400-2:2012 (0x2)\nPayload Type: Diagnostic message Nack (0x8003)\nPayload Length: 5\n"); +} +DISABLE_WARNING_POP diff --git a/Tests/Packet++Test/main.cpp b/Tests/Packet++Test/main.cpp index 4163780110..dc3af60625 100644 --- a/Tests/Packet++Test/main.cpp +++ b/Tests/Packet++Test/main.cpp @@ -186,6 +186,39 @@ int main(int argc, char* argv[]) PTF_RUN_TEST(DnsOverTcpCreationTest, "dns"); PTF_RUN_TEST(DnsLayerAddDnsKeyTest, "dns"); + PTF_RUN_TEST(DoIpGenericHeaderNackPacketParsing, "doip"); + PTF_RUN_TEST(DoIpGenericHeaderNackPacketCreation, "doip"); + PTF_RUN_TEST(DoIpVehicleIdentificationRequestPacketParsing, "doip"); + PTF_RUN_TEST(DoIpVehicleIdentificationRequestPacketCreation, "doip"); + PTF_RUN_TEST(DoIpVehicleIdentificationRequestVINPacketParsing, "doip"); + PTF_RUN_TEST(DoIpVehicleIdentificationRequestVINPacketCreation, "doip"); + PTF_RUN_TEST(DoIpVehicleIdentificationRequestEIDPacketParsing, "doip"); + PTF_RUN_TEST(DoIpVehicleIdentificationRequestEIDPacketCreation, "doip"); + PTF_RUN_TEST(DoIpVehicleAnnouncementPacketParsing, "doip"); + PTF_RUN_TEST(DoIpVehicleAnnouncementPacketCreation, "doip"); + PTF_RUN_TEST(DoIpRoutingActivationRequestPacketParsing, "doip"); + PTF_RUN_TEST(DoIpRoutingActivationRequestPacketCreation, "doip"); + PTF_RUN_TEST(DoIpRoutingActivationResponsePacketParsing, "doip"); + PTF_RUN_TEST(DoIpRoutingActivationResponsePacketCreation, "doip"); + PTF_RUN_TEST(DoIpAliveCheckRequestPacketParsing, "doip"); + PTF_RUN_TEST(DoIpAliveCheckRequestPacketCreation, "doip"); + PTF_RUN_TEST(DoIpAliveCheckResponsePacketParsing, "doip"); + PTF_RUN_TEST(DoIpAliveCheckResponsePacketCreation, "doip"); + PTF_RUN_TEST(DoIpEntityStatusRequestPacketParsing, "doip"); + PTF_RUN_TEST(DoIpEntityStatusRequestPacketCreation, "doip"); + PTF_RUN_TEST(DoIpEntityStatusResponsePacketParsing, "doip"); + PTF_RUN_TEST(DoIpEntityStatusResponsePacketCreation, "doip"); + PTF_RUN_TEST(DoIpPowerModeRequestPacketParsing, "doip"); + PTF_RUN_TEST(DoIpPowerModeRequestPacketCreation, "doip"); + PTF_RUN_TEST(DoIpPowerModeResponsePacketParsing, "doip"); + PTF_RUN_TEST(DoIpPowerModeResponsePacketCreation, "doip"); + PTF_RUN_TEST(DoIpDiagnosticMessagePacketParsing, "doip"); + PTF_RUN_TEST(DoIpDiagnosticMessagePacketCreation, "doip"); + PTF_RUN_TEST(DoIpDiagnosticAckMessagePacketParsing, "doip"); + PTF_RUN_TEST(DoIpDiagnosticAckMessagePacketCreation, "doip"); + PTF_RUN_TEST(DoIpDiagnosticNackMessagePacketParsing, "doip"); + PTF_RUN_TEST(DoIpDiagnosticNackMessagePacketCreation, "doip"); + PTF_RUN_TEST(IcmpParsingTest, "icmp"); PTF_RUN_TEST(IcmpCreationTest, "icmp"); PTF_RUN_TEST(IcmpEditTest, "icmp");