wireshark/epan/dissectors/packet-doip.c

1011 lines
36 KiB
C

/* packet-doip.c
* Routines for DoIP (ISO13400) protocol packet disassembly
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <epan/packet.h>
#include <epan/dissectors/packet-tcp.h>
void proto_register_doip(void);
void proto_reg_handoff_doip(void);
#define DOIP_PORT 13400
#define DOIP_GENERIC_NACK 0x0000
#define DOIP_VEHICLE_IDENTIFICATION_REQ 0x0001
#define DOIP_VEHICLE_IDENTIFICATION_REQ_EID 0x0002
#define DOIP_VEHICLE_IDENTIFICATION_REQ_VIN 0x0003
#define DOIP_VEHICLE_ANNOUNCEMENT_MESSAGE 0x0004
#define DOIP_ROUTING_ACTIVATION_REQUEST 0x0005
#define DOIP_ROUTING_ACTIVATION_RESPONSE 0x0006
#define DOIP_ALIVE_CHECK_REQUEST 0x0007
#define DOIP_ALIVE_CHECK_RESPONSE 0x0008
#define DOIP_ENTITY_STATUS_REQUEST 0x4001
#define DOIP_ENTITY_STATUS_RESPONSE 0x4002
#define DOIP_POWER_INFORMATION_REQUEST 0x4003
#define DOIP_POWER_INFORMATION_RESPONSE 0x4004
#define DOIP_DIAGNOSTIC_MESSAGE 0x8001
#define DOIP_DIAGNOSTIC_MESSAGE_ACK 0x8002
#define DOIP_DIAGNOSTIC_MESSAGE_NACK 0x8003
/* Header */
#define DOIP_VERSION_OFFSET 0
#define DOIP_VERSION_LEN 1
#define DOIP_INV_VERSION_OFFSET (DOIP_VERSION_OFFSET + DOIP_VERSION_LEN)
#define DOIP_INV_VERSION_LEN 1
#define DOIP_TYPE_OFFSET (DOIP_INV_VERSION_OFFSET + DOIP_INV_VERSION_LEN)
#define DOIP_TYPE_LEN 2
#define DOIP_LENGTH_OFFSET (DOIP_TYPE_OFFSET + DOIP_TYPE_LEN)
#define DOIP_LENGTH_LEN 4
#define DOIP_HEADER_LEN (DOIP_LENGTH_OFFSET + DOIP_LENGTH_LEN)
#define RESERVED_VER 0x00
#define ISO13400_2010 0x01
#define ISO13400_2012 0x02
#define ISO13400_2019 0x03
#define DEFAULT_VALUE 0xFF
/* Generic NACK */
#define DOIP_GENERIC_NACK_OFFSET DOIP_HEADER_LEN
#define DOIP_GENERIC_NACK_LEN 1
/* Common */
#define DOIP_COMMON_VIN_LEN 17
#define DOIP_COMMON_EID_LEN 6
/* Vehicle identifcation request */
#define DOIP_VEHICLE_IDENTIFICATION_EID_OFFSET DOIP_HEADER_LEN
#define DOIP_VEHICLE_IDENTIFICATION_VIN_OFFSET DOIP_HEADER_LEN
/* Routing activation request */
#define DOIP_ROUTING_ACTIVATION_REQ_SRC_OFFSET DOIP_HEADER_LEN
#define DOIP_ROUTING_ACTIVATION_REQ_SRC_LEN 2
#define DOIP_ROUTING_ACTIVATION_REQ_TYPE_OFFSET (DOIP_ROUTING_ACTIVATION_REQ_SRC_OFFSET + DOIP_ROUTING_ACTIVATION_REQ_SRC_LEN)
#define DOIP_ROUTING_ACTIVATION_REQ_TYPE_LEN_V1 2
#define DOIP_ROUTING_ACTIVATION_REQ_TYPE_LEN_V2 1
#define DOIP_ROUTING_ACTIVATION_REQ_ISO_OFFSET_V1 (DOIP_ROUTING_ACTIVATION_REQ_TYPE_OFFSET + DOIP_ROUTING_ACTIVATION_REQ_TYPE_LEN_V1)
#define DOIP_ROUTING_ACTIVATION_REQ_ISO_OFFSET_V2 (DOIP_ROUTING_ACTIVATION_REQ_TYPE_OFFSET + DOIP_ROUTING_ACTIVATION_REQ_TYPE_LEN_V2)
#define DOIP_ROUTING_ACTIVATION_REQ_ISO_LEN 4
#define DOIP_ROUTING_ACTIVATION_REQ_OEM_OFFSET_V1 (DOIP_ROUTING_ACTIVATION_REQ_ISO_OFFSET_V1 + DOIP_ROUTING_ACTIVATION_REQ_ISO_LEN)
#define DOIP_ROUTING_ACTIVATION_REQ_OEM_OFFSET_V2 (DOIP_ROUTING_ACTIVATION_REQ_ISO_OFFSET_V2 + DOIP_ROUTING_ACTIVATION_REQ_ISO_LEN)
#define DOIP_ROUTING_ACTIVATION_REQ_OEM_LEN 4
/* Routing activation response */
#define DOIP_ROUTING_ACTIVATION_RES_TESTER_OFFSET DOIP_HEADER_LEN
#define DOIP_ROUTING_ACTIVATION_RES_TESTER_LEN 2
#define DOIP_ROUTING_ACTIVATION_RES_ENTITY_OFFSET (DOIP_ROUTING_ACTIVATION_RES_TESTER_OFFSET + DOIP_ROUTING_ACTIVATION_RES_TESTER_LEN)
#define DOIP_ROUTING_ACTIVATION_RES_ENTITY_LEN 2
#define DOIP_ROUTING_ACTIVATION_RES_CODE_OFFSET (DOIP_ROUTING_ACTIVATION_RES_ENTITY_OFFSET + DOIP_ROUTING_ACTIVATION_RES_ENTITY_LEN)
#define DOIP_ROUTING_ACTIVATION_RES_CODE_LEN 1
#define DOIP_ROUTING_ACTIVATION_RES_ISO_OFFSET (DOIP_ROUTING_ACTIVATION_RES_CODE_OFFSET + DOIP_ROUTING_ACTIVATION_RES_CODE_LEN)
#define DOIP_ROUTING_ACTIVATION_RES_ISO_LEN 4
#define DOIP_ROUTING_ACTIVATION_RES_OEM_OFFSET (DOIP_ROUTING_ACTIVATION_RES_ISO_OFFSET + DOIP_ROUTING_ACTIVATION_RES_ISO_LEN)
#define DOIP_ROUTING_ACTIVATION_RES_OEM_LEN 4
/* Vehicle announcement message */
#define DOIP_VEHICLE_ANNOUNCEMENT_VIN_OFFSET DOIP_HEADER_LEN
#define DOIP_VEHICLE_ANNOUNCEMENT_ADDRESS_OFFSET (DOIP_VEHICLE_ANNOUNCEMENT_VIN_OFFSET + DOIP_COMMON_VIN_LEN)
#define DOIP_VEHICLE_ANNOUNCEMENT_ADDRESS_LEN 2
#define DOIP_VEHICLE_ANNOUNCEMENT_EID_OFFSET (DOIP_VEHICLE_ANNOUNCEMENT_ADDRESS_OFFSET + DOIP_VEHICLE_ANNOUNCEMENT_ADDRESS_LEN)
#define DOIP_VEHICLE_ANNOUNCEMENT_GID_OFFSET (DOIP_VEHICLE_ANNOUNCEMENT_EID_OFFSET + DOIP_COMMON_EID_LEN)
#define DOIP_VEHICLE_ANNOUNCEMENT_GID_LEN 6
#define DOIP_VEHICLE_ANNOUNCEMENT_ACTION_OFFSET (DOIP_VEHICLE_ANNOUNCEMENT_GID_OFFSET + DOIP_VEHICLE_ANNOUNCEMENT_GID_LEN)
#define DOIP_VEHICLE_ANNOUNCEMENT_ACTION_LEN 1
#define DOIP_VEHICLE_ANNOUNCEMENT_SYNC_OFFSET (DOIP_VEHICLE_ANNOUNCEMENT_ACTION_OFFSET + DOIP_VEHICLE_ANNOUNCEMENT_ACTION_LEN)
#define DOIP_VEHICLE_ANNOUNCEMENT_SYNC_LEN 1
/* Alive check response */
#define DOIP_ALIVE_CHECK_RESPONSE_SOURCE_OFFSET DOIP_HEADER_LEN
#define DOIP_ALIVE_CHECK_RESPONSE_SOURCE_LEN 2
/* Entity status response */
#define DOIP_ENTITY_STATUS_RESPONSE_NODE_OFFSET DOIP_HEADER_LEN
#define DOIP_ENTITY_STATUS_RESPONSE_NODE_LEN 1
#define DOIP_ENTITY_STATUS_RESPONSE_MCTS_OFFSET (DOIP_ENTITY_STATUS_RESPONSE_NODE_OFFSET + DOIP_ENTITY_STATUS_RESPONSE_NODE_LEN)
#define DOIP_ENTITY_STATUS_RESPONSE_MCTS_LEN 1
#define DOIP_ENTITY_STATUS_RESPONSE_NCTS_OFFSET (DOIP_ENTITY_STATUS_RESPONSE_MCTS_OFFSET + DOIP_ENTITY_STATUS_RESPONSE_MCTS_LEN)
#define DOIP_ENTITY_STATUS_RESPONSE_NCTS_LEN 1
#define DOIP_ENTITY_STATUS_RESPONSE_MDS_OFFSET (DOIP_ENTITY_STATUS_RESPONSE_NCTS_OFFSET + DOIP_ENTITY_STATUS_RESPONSE_NCTS_LEN)
#define DOIP_ENTITY_STATUS_RESPONSE_MDS_LEN 4
/* Diagnostic power mode information response */
#define DOIP_POWER_MODE_OFFSET DOIP_HEADER_LEN
#define DOIP_POWER_MODE_LEN 1
/* Common */
#define DOIP_DIAG_COMMON_SOURCE_OFFSET DOIP_HEADER_LEN
#define DOIP_DIAG_COMMON_SOURCE_LEN 2
#define DOIP_DIAG_COMMON_TARGET_OFFSET (DOIP_DIAG_COMMON_SOURCE_OFFSET + DOIP_DIAG_COMMON_SOURCE_LEN)
#define DOIP_DIAG_COMMON_TARGET_LEN 2
/* Diagnostic message */
#define DOIP_DIAG_MESSAGE_DATA_OFFSET (DOIP_DIAG_COMMON_TARGET_OFFSET + DOIP_DIAG_COMMON_TARGET_LEN)
/* Diagnostic message ACK */
#define DOIP_DIAG_MESSAGE_ACK_CODE_OFFSET (DOIP_DIAG_COMMON_TARGET_OFFSET + DOIP_DIAG_COMMON_TARGET_LEN)
#define DOIP_DIAG_MESSAGE_ACK_CODE_LEN 1
#define DOIP_DIAG_MESSAGE_ACK_PREVIOUS_OFFSET (DOIP_DIAG_MESSAGE_ACK_CODE_OFFSET + DOIP_DIAG_MESSAGE_ACK_CODE_LEN)
/* Diagnostic message NACK */
#define DOIP_DIAG_MESSAGE_NACK_CODE_OFFSET (DOIP_DIAG_COMMON_TARGET_OFFSET + DOIP_DIAG_COMMON_TARGET_LEN)
#define DOIP_DIAG_MESSAGE_NACK_CODE_LEN 1
#define DOIP_DIAG_MESSAGE_NACK_PREVIOUS_OFFSET (DOIP_DIAG_MESSAGE_NACK_CODE_OFFSET + DOIP_DIAG_MESSAGE_NACK_CODE_LEN)
/*
* Enums
*/
/* Header */
/* Protocol version */
static const value_string doip_versions[] = {
{ RESERVED_VER, "Reserved" },
{ ISO13400_2010, "DoIP ISO/DIS 13400-2:2010" },
{ ISO13400_2012, "DoIP ISO 13400-2:2012" },
{ ISO13400_2019, "DoIP ISO 13400-2:2019" },
{ DEFAULT_VALUE, "Default value for vehicle identification request messages" },
{ 0, NULL }
};
/* Payload type */
static const value_string doip_payloads[] = {
{ DOIP_GENERIC_NACK, "Generic DoIP header NACK" },
{ DOIP_VEHICLE_IDENTIFICATION_REQ, "Vehicle identification request" },
{ DOIP_VEHICLE_IDENTIFICATION_REQ_EID, "Vehicle identification request with EID" },
{ DOIP_VEHICLE_IDENTIFICATION_REQ_VIN, "Vehicle identification request with VIN" },
{ DOIP_VEHICLE_ANNOUNCEMENT_MESSAGE, "Vehicle announcement message/vehicle identification response message" },
{ DOIP_ROUTING_ACTIVATION_REQUEST, "Routing activation request" },
{ DOIP_ROUTING_ACTIVATION_RESPONSE, "Routing activation response" },
{ DOIP_ALIVE_CHECK_REQUEST, "Alive check request" },
{ DOIP_ALIVE_CHECK_RESPONSE, "Alive check response" },
{ DOIP_ENTITY_STATUS_REQUEST, "DoIP entity status request" },
{ DOIP_ENTITY_STATUS_RESPONSE, "DoIP entity status response" },
{ DOIP_POWER_INFORMATION_REQUEST, "Diagnostic power mode information request" },
{ DOIP_POWER_INFORMATION_RESPONSE, "Diagnostic power mode information response" },
{ DOIP_DIAGNOSTIC_MESSAGE, "Diagnostic message" },
{ DOIP_DIAGNOSTIC_MESSAGE_ACK, "Diagnostic message ACK" },
{ DOIP_DIAGNOSTIC_MESSAGE_NACK, "Diagnostic message NACK" },
{ 0, NULL }
};
/* Generic NACK */
static const value_string nack_codes[] = {
{ 0x00, "Incorrect pattern format" },
{ 0x01, "Unknown payload type" },
{ 0x02, "Message too large" },
{ 0x03, "Out of memory" },
{ 0x04, "Invalid payload length" },
{ 0, NULL }
};
/* Routing activation request */
static const value_string activation_types[] = {
{ 0x00, "Default" },
{ 0x01, "WWH-OBD" },
{ 0xE0, "Central security" },
{ 0, NULL }
};
/* Routing activation response */
static const value_string activation_codes[] = {
{ 0x00, "Routing activation denied due to unknown source address." },
{ 0x01, "Routing activation denied because all concurrently supported TCP_DATA sockets are registered and active." },
{ 0x02, "Routing activation denied because an SA different from the table connection entry was received on the already activated TCP_DATA socket." },
{ 0x03, "Routing activation denied because the SA is already registered and active on a different TCP_DATA socket." },
{ 0x04, "Routing activation denied due to missing authentication." },
{ 0x05, "Routing activation denied due to rejected confirmation." },
{ 0x06, "Routing activation denied due to unsupported routing activation type." },
{ 0x07, "Reserved by ISO 13400." },
{ 0x08, "Reserved by ISO 13400." },
{ 0x09, "Reserved by ISO 13400." },
{ 0x0A, "Reserved by ISO 13400." },
{ 0x0B, "Reserved by ISO 13400." },
{ 0x0C, "Reserved by ISO 13400." },
{ 0x0D, "Reserved by ISO 13400." },
{ 0x0E, "Reserved by ISO 13400." },
{ 0x0F, "Reserved by ISO 13400." },
{ 0x10, "Routing successfully activated." },
{ 0x11, "Routing will be activated; confirmation required." },
{ 0, NULL }
};
/* Vehicle announcement message */
/* Action code */
static const value_string action_codes[] = {
{ 0x00, "No further action required" },
{ 0x01, "Reserved by ISO 13400" },
{ 0x02, "Reserved by ISO 13400" },
{ 0x03, "Reserved by ISO 13400" },
{ 0x04, "Reserved by ISO 13400" },
{ 0x05, "Reserved by ISO 13400" },
{ 0x06, "Reserved by ISO 13400" },
{ 0x07, "Reserved by ISO 13400" },
{ 0x08, "Reserved by ISO 13400" },
{ 0x09, "Reserved by ISO 13400" },
{ 0x0A, "Reserved by ISO 13400" },
{ 0x0B, "Reserved by ISO 13400" },
{ 0x0C, "Reserved by ISO 13400" },
{ 0x0D, "Reserved by ISO 13400" },
{ 0x0E, "Reserved by ISO 13400" },
{ 0x0F, "Reserved by ISO 13400" },
{ 0x10, "Routing activation required to initiate central security" },
{ 0, NULL }
};
/* Sync status */
static const value_string sync_status[] = {
{ 0x00, "VIN and/or GID are synchronized" },
{ 0x01, "Reserved by ISO 13400" },
{ 0x02, "Reserved by ISO 13400" },
{ 0x03, "Reserved by ISO 13400" },
{ 0x04, "Reserved by ISO 13400" },
{ 0x05, "Reserved by ISO 13400" },
{ 0x06, "Reserved by ISO 13400" },
{ 0x07, "Reserved by ISO 13400" },
{ 0x08, "Reserved by ISO 13400" },
{ 0x09, "Reserved by ISO 13400" },
{ 0x0A, "Reserved by ISO 13400" },
{ 0x0B, "Reserved by ISO 13400" },
{ 0x0C, "Reserved by ISO 13400" },
{ 0x0D, "Reserved by ISO 13400" },
{ 0x0E, "Reserved by ISO 13400" },
{ 0x0F, "Reserved by ISO 13400" },
{ 0x10, "Incomplete: VIN and GID are NOT synchronized" },
{ 0, NULL }
};
/* Entity status response */
/* Node type */
static const value_string node_types[] = {
{ 0x00, "DoIP gateway" },
{ 0x01, "DoIp node" },
{ 0, NULL }
};
/* Diagnostic power mode information response */
/* Power mode */
static const value_string power_modes[] = {
{ 0x00, "not ready" },
{ 0x01, "ready" },
{ 0x02, "not supported" },
{ 0, NULL }
};
/* Diagnostic message ACK */
static const value_string diag_ack_codes[] = {
{ 0x00, "ACK" },
{ 0, NULL }
};
/* Diagnostic message NACK */
static const value_string diag_nack_codes[] = {
{ 0x00, "Reserved by ISO 13400" },
{ 0x01, "Reserved by ISO 13400" },
{ 0x02, "Invalid source address" },
{ 0x03, "Unknown target address" },
{ 0x04, "Diagnostic message too large" },
{ 0x05, "Out of memory" },
{ 0x06, "Target unreachable" },
{ 0x07, "Unknown network" },
{ 0x08, "Transport protocol error" },
{ 0, NULL }
};
/*
* Fields
*/
/* DoIP header */
static int hf_doip_version = -1;
static int hf_doip_inv_version = -1;
static int hf_doip_type = -1;
static int hf_doip_length = -1;
/* Generic NACK */
static int hf_generic_nack_code = -1;
/* Common */
static int hf_reserved_iso = -1;
static int hf_reserved_oem = -1;
/* Routing activation request */
static int hf_activation_type_v1 = -1;
static int hf_activation_type_v2 = -1;
/* Routing activation response */
static int hf_tester_logical_address = -1;
static int hf_response_code = -1;
/* Vehicle announcement message */
static int hf_logical_address = -1;
static int hf_gid = -1;
static int hf_futher_action = -1;
static int hf_sync_status = -1;
/* Diagnostic power mode information response */
static int hf_power_mode = -1;
/* Entity status response */
static int hf_node_type = -1;
static int hf_max_sockets = -1;
static int hf_current_sockets = -1;
static int hf_max_data_size = -1;
/* Common */
static int hf_vin = -1;
static int hf_eid = -1;
static int hf_source_address = -1;
static int hf_target_address = -1;
static int hf_previous = -1;
/* Diagnostic message */
static int hf_data = -1;
/* Diagnostic message ACK */
static int hf_ack_code = -1;
/* Diagnostic message NACK */
static int hf_nack_code = -1;
/*
* Trees
*/
static gint ett_doip = -1;
/* DoIP header */
static gint ett_header = -1;
/* Misc */
static dissector_handle_t doip_handle;
static dissector_handle_t uds_handle;
static gint proto_doip = -1;
static void
add_header(proto_tree *doip_tree, tvbuff_t *tvb)
{
proto_tree *subtree = proto_tree_add_subtree(doip_tree, tvb, DOIP_VERSION_OFFSET, DOIP_HEADER_LEN, ett_header, NULL, "Header");
proto_tree_add_item(subtree, hf_doip_version, tvb, DOIP_VERSION_OFFSET, DOIP_VERSION_LEN, ENC_BIG_ENDIAN);
proto_tree_add_item(subtree, hf_doip_inv_version, tvb, DOIP_INV_VERSION_OFFSET, DOIP_INV_VERSION_LEN, ENC_BIG_ENDIAN);
proto_tree_add_item(subtree, hf_doip_type, tvb, DOIP_TYPE_OFFSET, DOIP_TYPE_LEN, ENC_BIG_ENDIAN);
proto_tree_add_item(subtree, hf_doip_length, tvb, DOIP_LENGTH_OFFSET, DOIP_LENGTH_LEN, ENC_BIG_ENDIAN);
}
static void
add_generic_header_nack_fields(proto_tree *doip_tree, tvbuff_t *tvb)
{
proto_tree_add_item(doip_tree, hf_generic_nack_code, tvb, DOIP_GENERIC_NACK_OFFSET, DOIP_GENERIC_NACK_LEN, ENC_NA);
}
static void
add_vehicle_identification_eid_fields(proto_tree *doip_tree, tvbuff_t *tvb)
{
proto_tree_add_item(doip_tree, hf_eid, tvb, DOIP_VEHICLE_IDENTIFICATION_EID_OFFSET, DOIP_COMMON_EID_LEN, ENC_NA);
}
static void
add_vehicle_identification_vin_fields(proto_tree *doip_tree, tvbuff_t *tvb)
{
proto_tree_add_item(doip_tree, hf_vin, tvb, DOIP_VEHICLE_IDENTIFICATION_VIN_OFFSET, DOIP_COMMON_VIN_LEN, ENC_ASCII | ENC_NA);
}
static void
add_routing_activation_request_fields(proto_tree *doip_tree, tvbuff_t *tvb, guint8 version)
{
proto_tree_add_item(doip_tree, hf_source_address, tvb, DOIP_ROUTING_ACTIVATION_REQ_SRC_OFFSET, DOIP_ROUTING_ACTIVATION_REQ_SRC_LEN, ENC_BIG_ENDIAN);
if (version == ISO13400_2010) {
proto_tree_add_item(doip_tree, hf_activation_type_v1, tvb, DOIP_ROUTING_ACTIVATION_REQ_TYPE_OFFSET, DOIP_ROUTING_ACTIVATION_REQ_TYPE_LEN_V1, ENC_NA);
proto_tree_add_item(doip_tree, hf_reserved_iso, tvb, DOIP_ROUTING_ACTIVATION_REQ_ISO_OFFSET_V1, DOIP_ROUTING_ACTIVATION_REQ_ISO_LEN, ENC_BIG_ENDIAN);
if ( tvb_bytes_exist(tvb, DOIP_ROUTING_ACTIVATION_REQ_OEM_OFFSET_V1, DOIP_ROUTING_ACTIVATION_REQ_OEM_LEN) ) {
proto_tree_add_item(doip_tree, hf_reserved_oem, tvb, DOIP_ROUTING_ACTIVATION_REQ_OEM_OFFSET_V1, DOIP_ROUTING_ACTIVATION_REQ_OEM_LEN, ENC_BIG_ENDIAN);
}
} else if ((version == ISO13400_2012) || (version == ISO13400_2019)) {
proto_tree_add_item(doip_tree, hf_activation_type_v2, tvb, DOIP_ROUTING_ACTIVATION_REQ_TYPE_OFFSET, DOIP_ROUTING_ACTIVATION_REQ_TYPE_LEN_V2, ENC_NA);
proto_tree_add_item(doip_tree, hf_reserved_iso, tvb, DOIP_ROUTING_ACTIVATION_REQ_ISO_OFFSET_V2, DOIP_ROUTING_ACTIVATION_REQ_ISO_LEN, ENC_BIG_ENDIAN);
if ( tvb_bytes_exist(tvb, DOIP_ROUTING_ACTIVATION_REQ_OEM_OFFSET_V2, DOIP_ROUTING_ACTIVATION_REQ_OEM_LEN) ) {
proto_tree_add_item(doip_tree, hf_reserved_oem, tvb, DOIP_ROUTING_ACTIVATION_REQ_OEM_OFFSET_V2, DOIP_ROUTING_ACTIVATION_REQ_OEM_LEN, ENC_BIG_ENDIAN);
}
}
}
static void
add_routing_activation_response_fields(proto_tree *doip_tree, tvbuff_t *tvb)
{
proto_tree_add_item(doip_tree, hf_tester_logical_address, tvb, DOIP_ROUTING_ACTIVATION_RES_TESTER_OFFSET, DOIP_ROUTING_ACTIVATION_RES_TESTER_LEN, ENC_BIG_ENDIAN);
proto_tree_add_item(doip_tree, hf_source_address, tvb, DOIP_ROUTING_ACTIVATION_RES_ENTITY_OFFSET, DOIP_ROUTING_ACTIVATION_RES_ENTITY_LEN, ENC_BIG_ENDIAN);
proto_tree_add_item(doip_tree, hf_response_code, tvb, DOIP_ROUTING_ACTIVATION_RES_CODE_OFFSET, DOIP_ROUTING_ACTIVATION_RES_CODE_LEN, ENC_NA);
proto_tree_add_item(doip_tree, hf_reserved_iso, tvb, DOIP_ROUTING_ACTIVATION_RES_ISO_OFFSET, DOIP_ROUTING_ACTIVATION_RES_ISO_LEN, ENC_BIG_ENDIAN);
if ( tvb_bytes_exist(tvb, DOIP_ROUTING_ACTIVATION_RES_OEM_OFFSET, DOIP_ROUTING_ACTIVATION_RES_OEM_LEN) ) {
proto_tree_add_item(doip_tree, hf_reserved_oem, tvb, DOIP_ROUTING_ACTIVATION_RES_OEM_OFFSET, DOIP_ROUTING_ACTIVATION_RES_OEM_LEN, ENC_BIG_ENDIAN);
}
}
static void
add_vehicle_announcement_message_fields(proto_tree *doip_tree, tvbuff_t *tvb)
{
proto_tree_add_item(doip_tree, hf_vin, tvb, DOIP_VEHICLE_ANNOUNCEMENT_VIN_OFFSET, DOIP_COMMON_VIN_LEN, ENC_ASCII | ENC_NA);
proto_tree_add_item(doip_tree, hf_logical_address, tvb, DOIP_VEHICLE_ANNOUNCEMENT_ADDRESS_OFFSET, DOIP_VEHICLE_ANNOUNCEMENT_ADDRESS_LEN, ENC_BIG_ENDIAN);
proto_tree_add_item(doip_tree, hf_eid, tvb, DOIP_VEHICLE_ANNOUNCEMENT_EID_OFFSET, DOIP_COMMON_EID_LEN, ENC_NA);
proto_tree_add_item(doip_tree, hf_gid, tvb, DOIP_VEHICLE_ANNOUNCEMENT_GID_OFFSET, DOIP_VEHICLE_ANNOUNCEMENT_GID_LEN, ENC_NA);
proto_tree_add_item(doip_tree, hf_futher_action, tvb, DOIP_VEHICLE_ANNOUNCEMENT_ACTION_OFFSET, DOIP_VEHICLE_ANNOUNCEMENT_ACTION_LEN, ENC_BIG_ENDIAN);
if ( tvb_bytes_exist(tvb, DOIP_VEHICLE_ANNOUNCEMENT_SYNC_OFFSET, DOIP_VEHICLE_ANNOUNCEMENT_SYNC_LEN) ) {
/* Not part of version 1 and optional in version 2. */
proto_tree_add_item(doip_tree, hf_sync_status, tvb, DOIP_VEHICLE_ANNOUNCEMENT_SYNC_OFFSET, DOIP_VEHICLE_ANNOUNCEMENT_SYNC_LEN, ENC_BIG_ENDIAN);
}
}
static void
add_alive_check_response_fields(proto_tree *doip_tree, tvbuff_t *tvb)
{
proto_tree_add_item(doip_tree, hf_source_address, tvb, DOIP_ALIVE_CHECK_RESPONSE_SOURCE_OFFSET, DOIP_ALIVE_CHECK_RESPONSE_SOURCE_LEN, ENC_BIG_ENDIAN);
}
static void
add_entity_status_response_fields(proto_tree *doip_tree, tvbuff_t *tvb)
{
proto_tree_add_item(doip_tree, hf_node_type, tvb, DOIP_ENTITY_STATUS_RESPONSE_NODE_OFFSET, DOIP_ENTITY_STATUS_RESPONSE_NODE_LEN, ENC_NA);
proto_tree_add_item(doip_tree, hf_max_sockets, tvb, DOIP_ENTITY_STATUS_RESPONSE_MCTS_OFFSET, DOIP_ENTITY_STATUS_RESPONSE_MCTS_LEN, ENC_NA);
proto_tree_add_item(doip_tree, hf_current_sockets, tvb, DOIP_ENTITY_STATUS_RESPONSE_NCTS_OFFSET, DOIP_ENTITY_STATUS_RESPONSE_NCTS_LEN, ENC_NA);
if ( tvb_bytes_exist(tvb, DOIP_ENTITY_STATUS_RESPONSE_MDS_OFFSET, DOIP_ENTITY_STATUS_RESPONSE_MDS_LEN) ) {
proto_tree_add_item(doip_tree, hf_max_data_size, tvb, DOIP_ENTITY_STATUS_RESPONSE_MDS_OFFSET, DOIP_ENTITY_STATUS_RESPONSE_MDS_LEN, ENC_BIG_ENDIAN);
}
}
static void
add_power_mode_information_response_fields(proto_tree *doip_tree, tvbuff_t *tvb)
{
proto_tree_add_item(doip_tree, hf_power_mode, tvb, DOIP_POWER_MODE_OFFSET, DOIP_POWER_MODE_LEN, ENC_NA);
}
static void
add_diagnostic_message_fields(proto_tree *doip_tree, tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
{
proto_tree_add_item(doip_tree, hf_source_address, tvb, DOIP_DIAG_COMMON_SOURCE_OFFSET, DOIP_DIAG_COMMON_SOURCE_LEN, ENC_BIG_ENDIAN);
proto_tree_add_item(doip_tree, hf_target_address, tvb, DOIP_DIAG_COMMON_TARGET_OFFSET, DOIP_DIAG_COMMON_TARGET_LEN, ENC_BIG_ENDIAN);
if (uds_handle != 0) {
call_dissector(uds_handle, tvb_new_subset_length_caplen(tvb, DOIP_DIAG_MESSAGE_DATA_OFFSET, -1, -1), pinfo, parent_tree);
} else if (tvb_reported_length_remaining(tvb, DOIP_DIAG_MESSAGE_DATA_OFFSET) > 0) {
proto_tree_add_item(doip_tree, hf_data, tvb, DOIP_DIAG_MESSAGE_DATA_OFFSET, tvb_reported_length_remaining(tvb, DOIP_DIAG_MESSAGE_DATA_OFFSET), ENC_NA);
}
}
static void
add_diagnostic_message_ack_fields(proto_tree *doip_tree, tvbuff_t *tvb)
{
proto_tree_add_item(doip_tree, hf_source_address, tvb, DOIP_DIAG_COMMON_SOURCE_OFFSET, DOIP_DIAG_COMMON_SOURCE_LEN, ENC_BIG_ENDIAN);
proto_tree_add_item(doip_tree, hf_target_address, tvb, DOIP_DIAG_COMMON_TARGET_OFFSET, DOIP_DIAG_COMMON_TARGET_LEN, ENC_BIG_ENDIAN);
proto_tree_add_item(doip_tree, hf_ack_code, tvb, DOIP_DIAG_MESSAGE_ACK_CODE_OFFSET, DOIP_DIAG_MESSAGE_ACK_CODE_LEN, ENC_NA);
if (tvb_captured_length_remaining(tvb, DOIP_DIAG_MESSAGE_ACK_PREVIOUS_OFFSET) > 0) {
proto_tree_add_item(doip_tree, hf_previous, tvb, DOIP_DIAG_MESSAGE_ACK_PREVIOUS_OFFSET, tvb_captured_length_remaining(tvb, DOIP_DIAG_MESSAGE_ACK_PREVIOUS_OFFSET), ENC_NA);
}
}
static void
add_diagnostic_message_nack_fields(proto_tree *doip_tree, tvbuff_t *tvb)
{
proto_tree_add_item(doip_tree, hf_source_address, tvb, DOIP_DIAG_COMMON_SOURCE_OFFSET, DOIP_DIAG_COMMON_SOURCE_LEN, ENC_BIG_ENDIAN);
proto_tree_add_item(doip_tree, hf_target_address, tvb, DOIP_DIAG_COMMON_TARGET_OFFSET, DOIP_DIAG_COMMON_TARGET_LEN, ENC_BIG_ENDIAN);
proto_tree_add_item(doip_tree, hf_nack_code, tvb, DOIP_DIAG_MESSAGE_NACK_CODE_OFFSET, DOIP_DIAG_MESSAGE_NACK_CODE_LEN, ENC_NA);
if (tvb_captured_length_remaining(tvb, DOIP_DIAG_MESSAGE_NACK_PREVIOUS_OFFSET) > 0) {
proto_tree_add_item(doip_tree, hf_previous, tvb, DOIP_DIAG_MESSAGE_NACK_PREVIOUS_OFFSET, tvb_captured_length_remaining(tvb, DOIP_DIAG_MESSAGE_NACK_PREVIOUS_OFFSET), ENC_NA);
}
}
/* DoIP protocol dissector */
static void
dissect_doip_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
guint8 version = tvb_get_guint8(tvb, DOIP_VERSION_OFFSET);
guint16 payload_type = tvb_get_ntohs(tvb, DOIP_TYPE_OFFSET);
/* Set protocol and clear information columns */
col_set_str(pinfo->cinfo, COL_PROTOCOL, "DoIP");
col_clear(pinfo->cinfo, COL_INFO);
if (
version == ISO13400_2010 ||
version == ISO13400_2012 ||
version == ISO13400_2019 ||
(version == DEFAULT_VALUE && (payload_type >= DOIP_VEHICLE_IDENTIFICATION_REQ && payload_type <= DOIP_VEHICLE_IDENTIFICATION_REQ_EID))
) {
col_add_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str(payload_type, doip_payloads, "0x%04x Unknown payload"));
} else {
col_set_str(pinfo->cinfo, COL_INFO, "Invalid DoIP version");
return;
}
if (tree) {
proto_item *ti = NULL;
proto_tree *doip_tree = NULL;
ti = proto_tree_add_item(tree, proto_doip, tvb, 0, -1, ENC_NA);
doip_tree = proto_item_add_subtree(ti, ett_doip);
add_header(doip_tree, tvb);
switch (payload_type) {
case DOIP_GENERIC_NACK:
add_generic_header_nack_fields(doip_tree, tvb);
break;
case DOIP_VEHICLE_IDENTIFICATION_REQ:
break;
case DOIP_VEHICLE_IDENTIFICATION_REQ_EID:
add_vehicle_identification_eid_fields(doip_tree, tvb);
break;
case DOIP_VEHICLE_IDENTIFICATION_REQ_VIN:
add_vehicle_identification_vin_fields(doip_tree, tvb);
break;
case DOIP_ROUTING_ACTIVATION_REQUEST:
add_routing_activation_request_fields(doip_tree, tvb, version);
break;
case DOIP_ROUTING_ACTIVATION_RESPONSE:
add_routing_activation_response_fields(doip_tree, tvb);
break;
case DOIP_VEHICLE_ANNOUNCEMENT_MESSAGE:
add_vehicle_announcement_message_fields(doip_tree, tvb);
break;
case DOIP_ALIVE_CHECK_REQUEST:
break;
case DOIP_ALIVE_CHECK_RESPONSE:
add_alive_check_response_fields(doip_tree, tvb);
break;
case DOIP_ENTITY_STATUS_REQUEST:
break;
case DOIP_ENTITY_STATUS_RESPONSE:
add_entity_status_response_fields(doip_tree, tvb);
break;
case DOIP_POWER_INFORMATION_REQUEST:
break;
case DOIP_POWER_INFORMATION_RESPONSE:
add_power_mode_information_response_fields(doip_tree, tvb);
break;
case DOIP_DIAGNOSTIC_MESSAGE:
add_diagnostic_message_fields(doip_tree, tvb, pinfo, tree);
break;
case DOIP_DIAGNOSTIC_MESSAGE_ACK:
add_diagnostic_message_ack_fields(doip_tree, tvb);
break;
case DOIP_DIAGNOSTIC_MESSAGE_NACK:
add_diagnostic_message_nack_fields(doip_tree, tvb);
break;
}
} else if (payload_type == DOIP_DIAGNOSTIC_MESSAGE) {
/* Show UDS details in info column */
if (uds_handle != 0) {
call_dissector(uds_handle, tvb_new_subset_length_caplen(tvb, DOIP_DIAG_MESSAGE_DATA_OFFSET, -1, -1), pinfo, NULL);
}
}
}
/* determine PDU length of protocol DoIP */
static guint
get_doip_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *p _U_)
{
guint8 ver1 = tvb_get_guint8(tvb, DOIP_VERSION_OFFSET);
guint8 ver2 = tvb_get_guint8(tvb, DOIP_INV_VERSION_OFFSET);
if (ver1 != ((~ver2) & 0xff)) {
/* if ver2 is not the inverse of ver1, we are not at the start of a DoIP message! */
/* bounds_error: (0 < return < DOIP_HEADER_LEN) */
return 1;
}
/* PDU Length = length field value + header length */
return (guint)tvb_get_ntohl(tvb, offset + DOIP_LENGTH_OFFSET) + DOIP_HEADER_LEN;
}
static int
dissect_doip_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
dissect_doip_message(tvb, pinfo, tree);
return tvb_captured_length(tvb);
}
static int
dissect_doip(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_, void* data)
{
tcp_dissect_pdus(tvb, pinfo, tree, TRUE, DOIP_HEADER_LEN, get_doip_message_len, dissect_doip_pdu, data);
return tvb_captured_length(tvb);
}
/* Register DoIP Protocol */
void
proto_register_doip(void)
{
static hf_register_info hf[] = {
/* Header */
{ &hf_doip_version,
{ "Version", "doip.version",
FT_UINT8, BASE_HEX,
VALS(doip_versions), 0x0,
NULL, HFILL }
},
{ &hf_doip_inv_version,
{ "Inverse version", "doip.inverse",
FT_UINT8, BASE_HEX,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_doip_type,
{ "Type", "doip.type",
FT_UINT16, BASE_HEX,
VALS(doip_payloads), 0x0,
NULL, HFILL }
},
{ &hf_doip_length,
{ "Length", "doip.length",
FT_UINT32, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
/* Generic NACK */
{
&hf_generic_nack_code,
{
"DoIP Header NACK code", "doip.nack_code",
FT_UINT8, BASE_HEX,
VALS(nack_codes), 0x00,
NULL, HFILL
}
},
/* Vehicle announcement message */
{
&hf_vin,
{
"VIN", "doip.vin",
FT_STRING, BASE_NONE,
NULL, 0x00,
NULL, HFILL
}
},
{
&hf_logical_address,
{
"Logical Address", "doip.logical_address",
FT_UINT16, BASE_HEX,
NULL, 0x00,
NULL, HFILL
}
},
{
&hf_eid,
{
"EID", "doip.eid",
FT_BYTES, BASE_NONE,
NULL, 0x00,
NULL, HFILL
}
},
{
&hf_gid,
{
"GID", "doip.gid",
FT_BYTES, BASE_NONE,
NULL, 0x00,
NULL, HFILL
}
},
{
&hf_futher_action,
{
"Further action required", "doip.futher_action",
FT_UINT8, BASE_HEX,
VALS(action_codes), 0x00,
NULL, HFILL
}
},
{
&hf_sync_status,
{
"VIN/GID sync. status", "doip.sync_status",
FT_UINT8, BASE_HEX,
VALS(sync_status), 0x00,
NULL, HFILL
}
},
/* Diagnostic power mode information response */
{
&hf_power_mode,
{
"Diagnostic power mode", "doip.power_mode",
FT_UINT8, BASE_HEX,
VALS(power_modes), 0x00,
NULL, HFILL
}
},
/* Entity status response */
{
&hf_node_type,
{
"Node type", "doip.node_type",
FT_UINT8, BASE_HEX,
VALS(node_types), 0x00,
NULL, HFILL
}
},
{
&hf_max_sockets,
{
"Max concurrent sockets", "doip.max_sockets",
FT_UINT8, BASE_DEC,
NULL, 0x00,
NULL, HFILL
}
},
{
&hf_current_sockets,
{
"Currently open sockets", "doip.sockets",
FT_UINT8, BASE_DEC,
NULL, 0x00,
NULL, HFILL
}
},
{
&hf_max_data_size,
{
"Max data size", "doip.max_data_size",
FT_UINT32, BASE_DEC,
NULL, 0x00,
NULL, HFILL
}
},
/* Common */
{
&hf_source_address,
{
"Source Address", "doip.source_address",
FT_UINT16, BASE_HEX,
NULL, 0x00,
NULL, HFILL
}
},
{
&hf_target_address,
{
"Target Address", "doip.target_address",
FT_UINT16, BASE_HEX,
NULL, 0x00,
NULL, HFILL
}
},
/* Routing activation request */
{
&hf_activation_type_v1,
{
"Activation type", "doip.activation_type_v1",
FT_UINT16, BASE_HEX,
NULL, 0x00,
NULL, HFILL
}
},
{
&hf_activation_type_v2,
{
"Activation type", "doip.activation_type",
FT_UINT8, BASE_HEX,
VALS(activation_types), 0x00,
NULL, HFILL
}
},
/* Routing activation response */
{
&hf_tester_logical_address,
{
"Logical address of external tester", "doip.tester_logical_address",
FT_UINT16, BASE_HEX,
NULL, 0x00,
NULL, HFILL
}
},
{
&hf_response_code,
{
"Routing activation response code", "doip.response_code",
FT_UINT8, BASE_HEX,
VALS(activation_codes), 0x00,
NULL, HFILL
}
},
/* Common */
{
&hf_reserved_iso,
{
"Reserved by ISO", "doip.reserved_iso",
FT_UINT32, BASE_HEX,
NULL, 0x00,
NULL, HFILL
}
},
{
&hf_reserved_oem,
{
"Reserved by OEM", "doip.reserved_oem",
FT_UINT32, BASE_HEX,
NULL, 0x00,
NULL, HFILL
}
},
/* Diagnostic message */
{
&hf_data,
{
"User data", "doip.data",
FT_BYTES, BASE_NONE,
NULL, 0x00,
NULL, HFILL
}
},
/* Diagnostic message ACK */
{
&hf_ack_code,
{
"ACK code", "doip.diag_ack_code",
FT_UINT8, BASE_HEX,
VALS(diag_ack_codes), 0x00,
NULL, HFILL
}
},
/* Diagnostic message NACK */
{
&hf_nack_code,
{
"NACK code", "doip.diag_nack_code",
FT_UINT8, BASE_HEX,
VALS(diag_nack_codes), 0x00,
NULL, HFILL
}
},
/* Common */
{
&hf_previous,
{
"Previous message", "doip.previous",
FT_BYTES, BASE_NONE,
NULL, 0x00,
NULL, HFILL
}
}
};
/* Setup protocol subtree array */
static gint *ett[] = {
&ett_doip,
&ett_header
};
proto_doip = proto_register_protocol (
"DoIP (ISO13400) Protocol", /* name */
"DoIP", /* short name */
"doip" /* abbrev */
);
proto_register_field_array(proto_doip, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
doip_handle = register_dissector("doip", dissect_doip, proto_doip);
}
void
proto_reg_handoff_doip(void)
{
dissector_add_uint("udp.port", DOIP_PORT, doip_handle);
dissector_add_uint("tcp.port", DOIP_PORT, doip_handle);
uds_handle = find_dissector("uds");
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/