#ifndef PACKETPP_SOMEIP_LAYER #define PACKETPP_SOMEIP_LAYER #include "Layer.h" #include /// @file /** * \namespace pcpp * \brief The main namespace for the PcapPlusPlus lib */ namespace pcpp { /** * @class SomeIpLayer * Represents a SOME/IP protocol layer */ class SomeIpLayer : public Layer { public: /** * SOME/IP message types */ enum class MsgType : uint8_t { /** A request expecting a response (even void) */ REQUEST = 0x00, /** Acknowledgment for REQUEST(optional) */ REQUEST_ACK = 0x40, /** A fire&forget request */ REQUEST_NO_RETURN = 0x01, /** Acknowledgment for REQUEST_NO_RETURN(informational) */ REQUEST_NO_RETURN_ACK = 0x41, /** A request of a notification expecting no response */ NOTIFICATION = 0x02, /** Acknowledgment for NOTIFICATION(informational) */ NOTIFICATION_ACK = 0x42, /** The response message */ RESPONSE = 0x80, /** The Acknowledgment for RESPONSE(informational) */ RESPONSE_ACK = 0xC0, /** The response containing an error */ ERRORS = 0x81, /** Acknowledgment for ERROR(informational) */ ERROR_ACK = 0xC1, /** A TP request expecting a response (even void) */ TP_REQUEST = 0x20, /** A TP fire&forget request */ TP_REQUEST_NO_RETURN = 0x21, /** A TP request of a notification/event callback expecting no response */ TP_NOTIFICATION = 0x22, /** The TP response message */ TP_RESPONSE = 0xa0, /** The TP response containing an error */ TP_ERROR = 0xa1, }; /** * @struct someiphdr * Represents a SOME/IP protocol header */ #pragma pack(push, 1) struct someiphdr { /** Service ID */ uint16_t serviceID; /** Method ID. Most significant bit 0 when E2E communication. 1 when SOME/IP event */ uint16_t methodID; /** Length. Also covers payload. Excludes serviceID, methodID and length field itself */ uint32_t length; /** Client ID */ uint16_t clientID; /** Session ID */ uint16_t sessionID; /** Protocol Version */ uint8_t protocolVersion; /** Interface Version */ uint8_t interfaceVersion; /** Message Type */ uint8_t msgType; /** Return Code */ uint8_t returnCode; }; #pragma pack(pop) /** * 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 someiphdr) * @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 */ SomeIpLayer(uint8_t *data, size_t dataLen, Layer *prevLayer, Packet *packet) : Layer(data, dataLen, prevLayer, packet) { m_Protocol = SomeIP; } /** * Construct a new layer object * @param[in] serviceID Service ID * @param[in] methodID Method ID * @param[in] clientID Client ID * @param[in] sessionID Session ID * @param[in] interfaceVersion Interface Version * @param[in] type Type of the message * @param[in] returnCode Return Code * @param[in] data A pointer to the raw data * @param[in] dataLen Size of the data in bytes * holds the reference to a data buffer. This option can be used to reduce the number of copies to generate packets. */ SomeIpLayer(uint16_t serviceID, uint16_t methodID, uint16_t clientID, uint16_t sessionID, uint8_t interfaceVersion, MsgType type, uint8_t returnCode, const uint8_t *const data = nullptr, size_t dataLen = 0); /** * Destroy the layer object */ ~SomeIpLayer() {} /** * A static method that creates a SOME/IP or SOME/IP-TP layer from packet raw data. Returns PayloadLayer if data is * not valid. * @param[in] data A pointer to the raw data * @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 * @return Layer* A newly allocated layer */ static Layer* parseSomeIpLayer(uint8_t *data, size_t dataLen, Layer* prevLayer, Packet* packet); /** * Get a pointer to the basic SOME/IP header. Notice this points directly to the data, so every change will change * the actual packet data * @return A pointer to the someiphdr */ someiphdr *getSomeIpHeader() const { return (someiphdr *)m_Data; } /** * Checks if given port is a SOME/IP protocol port (only Service Discovery ports are checked for now) * @param[in] port Port to check * @return true if SOME/IP protocol port, false if not */ static bool isSomeIpPort(uint16_t port); /** * Adds port to a list of ports where pcap checks for SOME/IP communication. * Each port must be removed at the end in order to have no memory leak. * @param[in] port Port to add */ static void addSomeIpPort(uint16_t port); /** * Removes port from a list of ports where pcap checks for SOME/IP communication. * @param[in] port Port to remove */ static void removeSomeIpPort(uint16_t port); /** * Removes all ports from a list of ports where pcap checks for SOME/IP communication. */ static void removeAllSomeIpPorts(); /** * Get the messageID * @return uint32_t returned in host endian */ uint32_t getMessageID() const; /** * Set the Message ID * @param[in] messageID messageID to set */ void setMessageID(uint32_t messageID); /** * Get the serviceID * @return uint16_t returned in host endian */ uint16_t getServiceID() const; /** * Set the Service ID * @param[in] serviceID serviceID to set */ void setServiceID(uint16_t serviceID); /** * Get the methodID * @return uint16_t returned in host endian */ uint16_t getMethodID() const; /** * Set the Method ID * @param[in] methodID methodID to set */ void setMethodID(uint16_t methodID); /** * Get the Length Field of the SOME/IP header * @return uint32_t The length field of the SOME/IP header */ uint32_t getLengthField() const; /** * Get the requestID * @return uint32_t returned in host endian */ uint32_t getRequestID() const; /** * Set the Request ID * @param[in] requestID requestID to set */ void setRequestID(uint32_t requestID); /** * Get the sessionID * @return uint16_t returned in host endian */ uint16_t getSessionID() const; /** * Set the Session ID * @param[in] sessionID sessionID to set */ void setSessionID(uint16_t sessionID); /** * Get the clientID * @return uint16_t returned in host endian */ uint16_t getClientID() const; /** * Set the Client ID * @param[in] clientID clientID to set */ void setClientID(uint16_t clientID); /** * Get the protocolVersion * @return uint8_t */ uint8_t getProtocolVersion() const; /** * Set the Protocol Version * @param[in] version version to set */ void setProtocolVersion(uint8_t version); /** * Get the interfaceVersion * @return uint8_t */ uint8_t getInterfaceVersion() const; /** * Set the Interface Version * @param[in] version version to set */ void setInterfaceVersion(uint8_t version); /** * Get the message type * @return uint8_t */ uint8_t getMessageTypeAsInt() const; /** * Get the message type * @return SomeIpLayer::MsgType */ SomeIpLayer::MsgType getMessageType() const; /** * Set the Message Type * @param[in] type Type to set */ void setMessageType(MsgType type); /** * Set the Message Type * @param[in] type Type to set */ void setMessageType(uint8_t type); /** * Get the returnCode * @return uint8_t */ uint8_t getReturnCode() const; /** * Set the returnCode * @param[in] returnCode ReturnCode to set */ void setReturnCode(uint8_t returnCode); /** * Set the length field of the SOME/IP header * @param[in] payloadLength Length of the payload */ void setPayloadLength(uint32_t payloadLength); /** * @return A pointer for the layer payload, meaning the first byte after the header */ uint8_t *getPduPayload() const { return m_Data + getSomeIpHeaderLen(); } /** * @return The size in bytes of the payload */ size_t getPduPayloadSize() const { return getHeaderLen() - getSomeIpHeaderLen(); } /** * Get the Length of the SOME/IP header inc payload * @return size_t */ size_t getHeaderLen() const { return sizeof(uint32_t) * 2 + getLengthField(); } /** * Does nothing for this layer */ virtual void computeCalculateFields() {} /** * Identifies the following next layers: SomeIpLayer, SomeIpTpLayer, SomeIpSdLayer. Otherwise sets PayloadLayer */ void parseNextLayer(); /** * @return The string representation of the SOME/IP layer */ virtual std::string toString() const; /** * @return The OSI model layer of this layer */ OsiModelLayer getOsiModelLayer() const { return OsiModelApplicationLayer; } protected: SomeIpLayer() {} private: static const uint8_t SOMEIP_PROTOCOL_VERSION = 1; virtual size_t getSomeIpHeaderLen() const { return sizeof(someiphdr); } /* Using unordered_set since insertion and search should be almost constant time */ static std::unordered_set m_SomeIpPorts; }; /** * @class SomeIpTpLayer * Represents an SOME/IP Transport Protocol Layer */ class SomeIpTpLayer : public SomeIpLayer { public: /** * @struct someiptphdr * Represents an SOME/IP-TP protocol header. */ #pragma pack(push, 1) struct someiptphdr : someiphdr { /** Contains the offset and the more segments flag. 28 bit offset field measured in 16 bytes + 3 bit reserved + * 1 bit more segments flag */ uint32_t offsetAndFlag; }; #pragma pack(pop) /** * 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 someiptphdr) * @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 */ SomeIpTpLayer(uint8_t *data, size_t dataLen, Layer *prevLayer, Packet *packet) : SomeIpLayer(data, dataLen, prevLayer, packet) {} /** * A constructor that creates empty layer and sets values * @param[in] serviceID Service ID * @param[in] methodID Method ID * @param[in] clientID Client ID * @param[in] sessionID Session ID * @param[in] interfaceVersion Interface Version * @param[in] type Type of the message * @param[in] returnCode Return Code * @param[in] offset Offset indicating the data offset in increments of 16 bytes * @param[in] moreSegmentsFlag Flag indicating whether more SOME/IP-TP Packets will follow * @param[in] data A pointer to the raw data * @param[in] dataLen Size of the data in bytes */ SomeIpTpLayer(uint16_t serviceID, uint16_t methodID, uint16_t clientID, uint16_t sessionID, uint8_t interfaceVersion, MsgType type, uint8_t returnCode, uint32_t offset, bool moreSegmentsFlag, const uint8_t *const data = nullptr, size_t dataLen = 0); /** * Destroy the layer object */ ~SomeIpTpLayer() {} /** * Get a pointer to the basic SOME/IP-TP header. Notice this points directly to the data, so every change will * change the actual packet data * @return A pointer to the @ref someiptphdr */ someiptphdr *getSomeIpTpHeader() const { return (someiptphdr *)m_Data; } /** * Get the Offset. Offset is returned in multiple of 16 bytes. * @return The offset value */ uint32_t getOffset() const; /** * Set the Offset. Already has to be in multiples of 16 bytes. * If 32 bytes have already been transmitted, the offset has to be set to 2. * @param[in] offset Offset to set. Already has to be in multiples of 16 bytes. */ void setOffset(uint32_t offset); /** * Get the More Segments Flag * @return true if the More Segments Flag is set, false if it is not set */ bool getMoreSegmentsFlag() const; /** * Set the More Segments Flag * @param[in] flag True if the More Segments Flag shall be set, false for resetting */ void setMoreSegmentsFlag(bool flag); /** * Sets the message type in this layer with enabling the TP flag */ void computeCalculateFields(); /** * @return The string representation of the SOME/IP-TP layer */ std::string toString() const; private: static const uint32_t SOMEIP_TP_MORE_FLAG_MASK = 0x01; static const uint32_t SOMEIP_TP_OFFSET_MASK = 0xFFFFFFF0; size_t getSomeIpHeaderLen() const { return sizeof(someiptphdr); } static uint8_t setTpFlag(uint8_t messageType); }; } // namespace pcpp #endif /* PACKETPP_SOMEIP_LAYER */