/* packet-uds.c * Routines for uds protocol packet disassembly * * Wireshark - Network traffic analyzer * By Gerald Combs * 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 #include void proto_register_uds(void); void proto_reg_handoff_uds(void); #define UDS_SERVICES_DSC 0x10 #define UDS_SERVICES_ER 0x11 #define UDS_SERVICES_CDTCI 0x14 #define UDS_SERVICES_RDTCI 0x19 #define UDS_SERVICES_RDBI 0x22 #define UDS_SERVICES_RMBA 0x23 #define UDS_SERVICES_RSDBI 0x24 #define UDS_SERVICES_SA 0x27 #define UDS_SERVICES_CC 0x28 #define UDS_SERVICES_RDBPI 0x2A #define UDS_SERVICES_DDDI 0x2C #define UDS_SERVICES_WDBI 0x2E #define UDS_SERVICES_IOCBI 0x2F #define UDS_SERVICES_RC 0x31 #define UDS_SERVICES_RD 0x34 #define UDS_SERVICES_RU 0x35 #define UDS_SERVICES_TD 0x36 #define UDS_SERVICES_RTE 0x37 #define UDS_SERVICES_RFT 0x38 #define UDS_SERVICES_WMBA 0x3D #define UDS_SERVICES_TP 0x3E #define UDS_SERVICES_ERR 0x3F #define UDS_SERVICES_CDTCS 0x85 #define UDS_RESPONSE_CODES_GR 0x10 #define UDS_RESPONSE_CODES_SNS 0x11 #define UDS_RESPONSE_CODES_SFNS 0x12 #define UDS_RESPONSE_CODES_IMLOIF 0x13 #define UDS_RESPONSE_CODES_RTL 0x14 #define UDS_RESPONSE_CODES_BRR 0x21 #define UDS_RESPONSE_CODES_CNC 0x22 #define UDS_RESPONSE_CODES_RSE 0x24 #define UDS_RESPONSE_CODES_NRFSC 0x25 #define UDS_RESPONSE_CODES_FPEORA 0x26 #define UDS_RESPONSE_CODES_ROOR 0x31 #define UDS_RESPONSE_CODES_SAD 0x33 #define UDS_RESPONSE_CODES_IK 0x35 #define UDS_RESPONSE_CODES_ENOA 0x36 #define UDS_RESPONSE_CODES_RTDNE 0x37 #define UDS_RESPONSE_CODES_UDNA 0x70 #define UDS_RESPONSE_CODES_TDS 0x71 #define UDS_RESPONSE_CODES_GPF 0x72 #define UDS_RESPONSE_CODES_WBSC 0x73 #define UDS_RESPONSE_CODES_RCRRP 0x78 #define UDS_RESPONSE_CODES_SFNSIAS 0x7E #define UDS_RESPONSE_CODES_SNSIAS 0x7F #define UDS_SID_MASK 0xBF #define UDS_REPLY_MASK 0x40 #define UDS_SID_OFFSET 0 #define UDS_SID_LEN 1 #define UDS_DATA_OFFSET 1 #define UDS_DSC_TYPE_OFFSET (UDS_DATA_OFFSET + 0) #define UDS_DSC_TYPE_LEN 1 #define UDS_DSC_PARAMETER_RECORD_OFFSET (UDS_DSC_TYPE_OFFSET + UDS_DSC_TYPE_LEN) #define UDS_DSC_TYPES_DEFAULT_SESSION 1 #define UDS_DSC_TYPES_PROGRAMMING_SESSION 2 #define UDS_DSC_TYPES_EXTENDED_DIAGNOSTIC_SESSION 3 #define UDS_DSC_TYPES_SAFETY_SYSTEM_DIAGNOSTIC_SESSION 4 #define UDS_ER_TYPE_OFFSET (UDS_DATA_OFFSET + 0) #define UDS_ER_TYPE_LEN 1 #define UDS_ER_TYPES_HARD_RESET 1 #define UDS_ER_TYPES_KEY_ON_OFF_RESET 2 #define UDS_ER_TYPES_SOFT_RESET 3 #define UDS_ER_TYPES_ENABLE_RAPID_POWER_SHUTDOWN 4 #define UDS_ER_TYPES_DISABLE_RAPID_POWER_SHUTDOWN 5 #define UDS_RDTCI_TYPE_OFFSET (UDS_DATA_OFFSET + 0) #define UDS_RDTCI_TYPE_LEN 1 #define UDS_RDTCI_RECORD_OFFSET (UDS_RDTCI_TYPE_OFFSET + UDS_RDTCI_TYPE_LEN) #define UDS_RDTCI_TYPES_NUMBER_BY_STATUS_MASK 0x1 #define UDS_RDTCI_TYPES_BY_STATUS_MASK 0x2 #define UDS_RDTCI_TYPES_SNAPSHOT_IDENTIFICATION 0x3 #define UDS_RDTCI_TYPES_SNAPSHOT_RECORD_BY_DTC 0x4 #define UDS_RDTCI_TYPES_SNAPSHOT_RECORD_BY_RECORD 0x5 #define UDS_RDTCI_TYPES_EXTENDED_RECARD_BY_DTC 0x6 #define UDS_RDTCI_TYPES_SUPPORTED_DTC 0xA #define UDS_RDBI_DATA_IDENTIFIER_OFFSET (UDS_DATA_OFFSET + 0) #define UDS_RDBI_DATA_IDENTIFIER_LEN 2 #define UDS_RDBI_DATA_RECORD_OFFSET (UDS_RDBI_DATA_IDENTIFIER_OFFSET + UDS_RDBI_DATA_IDENTIFIER_LEN) #define UDS_SA_TYPE_OFFSET (UDS_DATA_OFFSET + 0) #define UDS_SA_TYPE_LEN 1 #define UDS_SA_KEY_OFFSET (UDS_SA_TYPE_OFFSET + UDS_SA_TYPE_LEN) #define UDS_SA_SEED_OFFSET (UDS_SA_TYPE_OFFSET + UDS_SA_TYPE_LEN) #define UDS_SA_TYPES_SEED 1 #define UDS_SA_TYPES_KEY 2 #define UDS_SA_TYPES_SEED_2 3 #define UDS_SA_TYPES_KEY_2 4 #define UDS_WDBI_DATA_IDENTIFIER_OFFSET (UDS_DATA_OFFSET + 0) #define UDS_WDBI_DATA_IDENTIFIER_LEN 2 #define UDS_WDBI_DATA_RECORD_OFFSET (UDS_WDBI_DATA_IDENTIFIER_OFFSET + UDS_WDBI_DATA_IDENTIFIER_LEN) #define UDS_IOCBI_DATA_IDENTIFIER_OFFSET (UDS_DATA_OFFSET + 0) #define UDS_IOCBI_DATA_IDENTIFIER_LEN 2 #define UDS_IOCBI_PARAMETER_OFFSET (UDS_IOCBI_DATA_IDENTIFIER_OFFSET + UDS_IOCBI_DATA_IDENTIFIER_LEN) #define UDS_IOCBI_PARAMETER_LEN 1 #define UDS_IOCBI_STATE_OFFSET (UDS_IOCBI_PARAMETER_OFFSET + UDS_IOCBI_PARAMETER_LEN) #define UDS_IOCBI_PARAMETERS_RETURN_CONTROL_TO_ECU 0 #define UDS_IOCBI_PARAMETERS_RESET_TO_DEFAULT 1 #define UDS_IOCBI_PARAMETERS_FREEZE_CURRENT_STATE 2 #define UDS_IOCBI_PARAMETERS_SHORT_TERM_ADJUSTMENT 3 #define UDS_RC_TYPE_OFFSET (UDS_DATA_OFFSET + 0) #define UDS_RC_TYPE_LEN 1 #define UDS_RC_ROUTINE_OFFSET (UDS_RC_TYPE_OFFSET + UDS_RC_TYPE_LEN) #define UDS_RC_ROUTINE_LEN 2 #define UDS_RC_OPTION_RECORD_OFFSET (UDS_RC_ROUTINE_OFFSET + UDS_RC_ROUTINE_LEN) #define UDS_RC_INFO_OFFSET (UDS_RC_ROUTINE_OFFSET + UDS_RC_ROUTINE_LEN) #define UDS_RC_INFO_LEN 1 #define UDS_RC_STATUS_RECORD_OFFSET (UDS_RC_INFO_OFFSET + UDS_RC_INFO_LEN) #define UDS_RC_TYPES_START 1 #define UDS_RC_TYPES_STOP 2 #define UDS_RC_TYPES_REQUEST 3 #define UDS_RD_DATA_FORMAT_IDENTIFIER_OFFSET (UDS_DATA_OFFSET + 0) #define UDS_RD_DATA_FORMAT_IDENTIFIER_LEN 1 #define UDS_RD_COMPRESSION_METHOD_MASK 0xF0 #define UDS_RD_ENCRYPTING_METHOD_MASK 0x0F #define UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_OFFSET (UDS_RD_DATA_FORMAT_IDENTIFIER_OFFSET + UDS_RD_DATA_FORMAT_IDENTIFIER_LEN) #define UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_LEN 1 #define UDS_RD_MEMORY_SIZE_LENGTH_MASK 0xF0 #define UDS_RD_MEMORY_ADDRESS_LENGTH_MASK 0x0F #define UDS_RD_MEMORY_ADDRESS_OFFSET (UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_OFFSET + UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_LEN) #define UDS_RD_LENGTH_FORMAT_IDENTIFIER_OFFSET (UDS_DATA_OFFSET + 0) #define UDS_RD_LENGTH_FORMAT_IDENTIFIER_LEN 1 #define UDS_RD_MAX_NUMBER_OF_BLOCK_LENGTH_LENGTH_MASK 0xF0 #define UDS_RD_MAX_NUMBER_OF_BLOCK_LENGTH_OFFSET (UDS_RD_LENGTH_FORMAT_IDENTIFIER_OFFSET + UDS_RD_LENGTH_FORMAT_IDENTIFIER_LEN) #define UDS_TP_SUB_FUNCTION_OFFSET (UDS_DATA_OFFSET + 0) #define UDS_TP_SUB_FUNCTION_LEN 1 #define UDS_TP_SUB_FUNCTION_MASK 0x7f #define UDS_TP_SUPPRESS_POS_RSP_MSG_INDIFICATION_MASK 0x80 #define UDS_ERR_SID_OFFSET (UDS_DATA_OFFSET + 0) #define UDS_ERR_SID_LEN 1 #define UDS_ERR_CODE_OFFSET (UDS_ERR_SID_OFFSET + UDS_ERR_SID_LEN) #define UDS_ERR_CODE_LEN 1 #define UDS_CDTCS_TYPE_OFFSET (UDS_DATA_OFFSET + 0) #define UDS_CDTCS_TYPE_LEN 1 #define UDS_CDTCS_ACTIONS_ON 1 #define UDS_CDTCS_ACTIONS_OFF 2 /* * Enums */ /* Services */ static const value_string uds_services[]= { {UDS_SERVICES_DSC, "Diagnostic Session Control"}, {UDS_SERVICES_ER, "ECU Reset"}, {UDS_SERVICES_CDTCI, "Clear Diagnostic Information"}, {UDS_SERVICES_RDTCI, "Read DTC Information"}, {UDS_SERVICES_RDBI, "Read Data By Identifier"}, {UDS_SERVICES_RMBA, "Read Memory By Address"}, {UDS_SERVICES_RSDBI, "Read Scaling Data By Identifier"}, {UDS_SERVICES_SA, "Security Access"}, {UDS_SERVICES_CC, "Communication Control"}, {UDS_SERVICES_RDBPI, "Read Data By Periodic Identifier"}, {UDS_SERVICES_DDDI, "Dynamically Define Data Identifier"}, {UDS_SERVICES_WDBI, "Write Data By Identifier"}, {UDS_SERVICES_IOCBI, "Input Output Control By Identifier"}, {UDS_SERVICES_RC, "Routine Control"}, {UDS_SERVICES_RD, "Request Download"}, {UDS_SERVICES_RU, "Request Upload"}, {UDS_SERVICES_TD, "Transfer Data"}, {UDS_SERVICES_RTE, "Request Transfer Exit"}, {UDS_SERVICES_RFT, "Request File Transfer"}, {UDS_SERVICES_WMBA, "Write Memory By Address"}, {UDS_SERVICES_TP, "Tester Present"}, {UDS_SERVICES_ERR, "Error"}, {UDS_SERVICES_CDTCS, "Control DTC Setting"}, {0, NULL} }; /* Response code */ static const value_string uds_response_codes[]= { {UDS_RESPONSE_CODES_GR, "General reject"}, {UDS_RESPONSE_CODES_SNS, "Service not supported"}, {UDS_RESPONSE_CODES_SFNS, "Sub-Function Not Supported"}, {UDS_RESPONSE_CODES_IMLOIF, "Incorrect Message Length or Invalid Format"}, {UDS_RESPONSE_CODES_RTL, "Response too long"}, {UDS_RESPONSE_CODES_BRR, "Busy repeat request"}, {UDS_RESPONSE_CODES_CNC, "Conditions Not Correct"}, {UDS_RESPONSE_CODES_RSE, "Request Sequence Error"}, {UDS_RESPONSE_CODES_NRFSC, "No response from sub-net component"}, {UDS_RESPONSE_CODES_FPEORA, "Failure prevents execution of requested action"}, {UDS_RESPONSE_CODES_ROOR, "Request Out of Range"}, {UDS_RESPONSE_CODES_SAD, "Security Access Denied"}, {UDS_RESPONSE_CODES_IK, "Invalid Key"}, {UDS_RESPONSE_CODES_ENOA, "Exceeded Number Of Attempts"}, {UDS_RESPONSE_CODES_RTDNE, "Required Time Delay Not Expired"}, {UDS_RESPONSE_CODES_UDNA, "Upload/Download not accepted"}, {UDS_RESPONSE_CODES_TDS, "Transfer data suspended"}, {UDS_RESPONSE_CODES_GPF, "General Programming Failure"}, {UDS_RESPONSE_CODES_WBSC, "Wrong Block Sequence Counter"}, {UDS_RESPONSE_CODES_RCRRP, "Request correctly received, but response is pending"}, {UDS_RESPONSE_CODES_SFNSIAS, "Sub-Function not supported in active session"}, {UDS_RESPONSE_CODES_SNSIAS, "Service not supported in active session"}, {0, NULL} }; /* DSC */ static const value_string uds_dsc_types[] = { {0, "Reserved"}, {UDS_DSC_TYPES_DEFAULT_SESSION, "Default Session"}, {UDS_DSC_TYPES_PROGRAMMING_SESSION, "Programming Session"}, {UDS_DSC_TYPES_EXTENDED_DIAGNOSTIC_SESSION, "Extended Diagnostic Session"}, {UDS_DSC_TYPES_SAFETY_SYSTEM_DIAGNOSTIC_SESSION, "Safety System Diagnostic Session"}, {0, NULL} }; /* ER */ static const value_string uds_er_types[] = { {0, "Reserved"}, {UDS_ER_TYPES_HARD_RESET, "Hard Reset"}, {UDS_ER_TYPES_KEY_ON_OFF_RESET, "Key On Off Reset"}, {UDS_ER_TYPES_SOFT_RESET, "Soft Reset"}, {UDS_ER_TYPES_ENABLE_RAPID_POWER_SHUTDOWN, "Enable Rapid Power Shutdown"}, {UDS_ER_TYPES_DISABLE_RAPID_POWER_SHUTDOWN, "Disable Rapid Power Shutdown"}, {0, NULL} }; /* SA */ static const value_string uds_sa_types[] = { {UDS_SA_TYPES_SEED, "Request Seed"}, {UDS_SA_TYPES_KEY, "Send Key"}, {UDS_SA_TYPES_SEED_2, "Request Seed"}, {UDS_SA_TYPES_KEY_2, "Send Key"}, {0, NULL} }; /* RDTCI */ static const value_string uds_rdtci_types[] = { {UDS_RDTCI_TYPES_NUMBER_BY_STATUS_MASK, "Report Number of DTC by Status Mask"}, {UDS_RDTCI_TYPES_BY_STATUS_MASK, "Report DTC by Status Mask"}, {UDS_RDTCI_TYPES_SNAPSHOT_IDENTIFICATION, "Report DTC Snapshot Identification"}, {UDS_RDTCI_TYPES_SNAPSHOT_RECORD_BY_DTC, "Report DTC Snapshot Record by DTC Number"}, {UDS_RDTCI_TYPES_SNAPSHOT_RECORD_BY_RECORD, "Report DTC Snapshot Record by Record Number"}, {UDS_RDTCI_TYPES_EXTENDED_RECARD_BY_DTC, "Report DTC Extended Data Record by DTC Number"}, {UDS_RDTCI_TYPES_SUPPORTED_DTC, "Report Supported DTC"}, {0, NULL} }; /* IOCBI */ static const value_string uds_iocbi_parameters[] = { {UDS_IOCBI_PARAMETERS_RETURN_CONTROL_TO_ECU, "Return Control To ECU"}, {UDS_IOCBI_PARAMETERS_RESET_TO_DEFAULT, "Reset To Default"}, {UDS_IOCBI_PARAMETERS_FREEZE_CURRENT_STATE, "Freeze Current State"}, {UDS_IOCBI_PARAMETERS_SHORT_TERM_ADJUSTMENT, "Short Term Adjustment"}, {0, NULL} }; /* RC */ static const value_string uds_rc_types[] = { {0, "Reserved"}, {UDS_RC_TYPES_START, "Start routine"}, {UDS_RC_TYPES_STOP, "Stop routine"}, {UDS_RC_TYPES_REQUEST, "Request routine result"}, {0, NULL} }; /* CDTCS */ static const value_string uds_cdtcs_types[] = { {0, "Reserved"}, {UDS_CDTCS_ACTIONS_ON, "On"}, {UDS_CDTCS_ACTIONS_OFF, "Off"}, {0, NULL} }; /* * Fields */ static int hf_uds_service = -1; static int hf_uds_reply = -1; static int hf_uds_dsc_type = -1; static int hf_uds_dsc_parameter_record = -1; static int hf_uds_er_type = -1; static int hf_uds_rdtci_type = -1; static int hf_uds_rdtci_record = -1; static int hf_uds_rdbi_data_identifier = -1; static int hf_uds_rdbi_data_record = -1; static int hf_uds_sa_type = -1; static int hf_uds_sa_key = -1; static int hf_uds_sa_seed = -1; static int hf_uds_wdbi_data_identifier = -1; static int hf_uds_wdbi_data_record = -1; static int hf_uds_iocbi_data_identifier = -1; static int hf_uds_iocbi_parameter = -1; static int hf_uds_iocbi_state = -1; static int hf_uds_rc_type = -1; static int hf_uds_rc_identifier = -1; static int hf_uds_rc_option_record = -1; static int hf_uds_rc_info = -1; static int hf_uds_rc_status_record = -1; static int hf_uds_rd_compression_method = -1; static int hf_uds_rd_encrypting_method = -1; static int hf_uds_rd_memory_size_length = -1; static int hf_uds_rd_memory_address_length = -1; static int hf_uds_rd_memory_address = -1; static int hf_uds_rd_memory_size = -1; static int hf_uds_rd_max_number_of_block_length_length = -1; static int hf_uds_rd_max_number_of_block_length = -1; static int hf_uds_tp_sub_function = -1; static int hf_uds_tp_suppress_pos_rsp_msg_indification = -1; static int hf_uds_err_sid = -1; static int hf_uds_err_code = -1; static int hf_uds_cdtcs_type = -1; /* * Trees */ static gint ett_uds = -1; static gint ett_uds_dsc = -1; static gint ett_uds_er = -1; static gint ett_uds_rdtci = -1; static gint ett_uds_rdbi = -1; static gint ett_uds_sa = -1; static gint ett_uds_wdbi = -1; static gint ett_uds_iocbi = -1; static gint ett_uds_rc = -1; static gint ett_uds_rd = -1; static gint ett_uds_tp = -1; static gint ett_uds_err = -1; static gint ett_uds_cdtcs = -1; static int proto_uds = -1; static guint8 masked_guint8_value(const guint8 value, const guint8 mask) { return (value & mask) >> ws_ctz(mask); } static guint64 tvb_get_guintX(tvbuff_t *tvb, const gint offset, const gint size, const guint encoding) { switch (size) { case 1: return tvb_get_guint8(tvb, offset); case 2: return tvb_get_guint16(tvb, offset, encoding); case 3: return tvb_get_guint24(tvb, offset, encoding); case 4: return tvb_get_guint32(tvb, offset, encoding); case 5: return tvb_get_guint40(tvb, offset, encoding); case 6: return tvb_get_guint48(tvb, offset, encoding); case 7: return tvb_get_guint56(tvb, offset, encoding); case 8: return tvb_get_guint64(tvb, offset, encoding); } return 0; } static int dissect_uds(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void* data _U_) { proto_tree *uds_tree, *subtree; proto_item *ti; guint8 sid, service; guint32 enum_val; const char *service_name; guint32 data_length = tvb_reported_length(tvb); col_set_str(pinfo->cinfo, COL_PROTOCOL, "UDS"); col_clear(pinfo->cinfo,COL_INFO); sid = tvb_get_guint8(tvb, UDS_SID_OFFSET); service = sid & UDS_SID_MASK; service_name = val_to_str(service, uds_services, "Unknown (0x%02x)"); col_add_fstr(pinfo->cinfo, COL_INFO, "%-7s %-36s", (sid & UDS_REPLY_MASK)? "Reply": "Request", service_name); ti = proto_tree_add_item(tree, proto_uds, tvb, 0, -1, ENC_NA); uds_tree = proto_item_add_subtree(ti, ett_uds); proto_tree_add_item(uds_tree, hf_uds_service, tvb, UDS_SID_OFFSET, UDS_SID_LEN, ENC_BIG_ENDIAN); proto_tree_add_item(uds_tree, hf_uds_reply, tvb, UDS_SID_OFFSET, UDS_SID_LEN, ENC_BIG_ENDIAN); switch (service) { case UDS_SERVICES_DSC: subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_dsc, NULL, service_name); proto_tree_add_item_ret_uint(subtree, hf_uds_dsc_type, tvb, UDS_DSC_TYPE_OFFSET, UDS_DSC_TYPE_LEN, ENC_BIG_ENDIAN, &enum_val); col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(enum_val, uds_dsc_types, "Unknown (0x%02x)")); if (sid & UDS_REPLY_MASK) { guint32 parameter_record_length = data_length - UDS_DSC_PARAMETER_RECORD_OFFSET; proto_tree_add_item(subtree, hf_uds_dsc_parameter_record, tvb, UDS_DSC_PARAMETER_RECORD_OFFSET, parameter_record_length, ENC_NA); col_append_fstr(pinfo->cinfo, COL_INFO, " %s", tvb_bytes_to_str_punct(wmem_packet_scope(), tvb, UDS_DSC_PARAMETER_RECORD_OFFSET, parameter_record_length, ' ')); } break; case UDS_SERVICES_ER: subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_er, NULL, service_name); proto_tree_add_item_ret_uint(subtree, hf_uds_er_type, tvb, UDS_ER_TYPE_OFFSET, UDS_ER_TYPE_LEN, ENC_BIG_ENDIAN, &enum_val); col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(enum_val, uds_er_types, "Unknown (0x%02x)")); break; case UDS_SERVICES_RDTCI: { guint32 record_length = data_length - UDS_RDTCI_RECORD_OFFSET; subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_rdtci, NULL, service_name); proto_tree_add_item_ret_uint(subtree, hf_uds_rdtci_type, tvb, UDS_RDTCI_TYPE_OFFSET, UDS_RDTCI_TYPE_LEN, ENC_BIG_ENDIAN, &enum_val); proto_tree_add_item(subtree, hf_uds_rdtci_record, tvb, UDS_RDTCI_RECORD_OFFSET, record_length, ENC_NA); col_append_fstr(pinfo->cinfo, COL_INFO, " %s %s", val_to_str(enum_val, uds_rdtci_types, "Unknown (0x%02x)"), tvb_bytes_to_str_punct(wmem_packet_scope(), tvb, UDS_RDTCI_RECORD_OFFSET, record_length, ' ')); break; } case UDS_SERVICES_RDBI: subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_rdbi, NULL, service_name); if (sid & UDS_REPLY_MASK) { /* Can't know the size of the data for each identifier, Decode like if there is only one idenfifier */ guint32 record_length = data_length - UDS_RDBI_DATA_RECORD_OFFSET; guint32 data_identifier; proto_tree_add_item_ret_uint(subtree, hf_uds_rdbi_data_identifier, tvb, UDS_RDBI_DATA_IDENTIFIER_OFFSET, UDS_RDBI_DATA_IDENTIFIER_LEN, ENC_BIG_ENDIAN, &data_identifier); proto_tree_add_item(subtree, hf_uds_rdbi_data_record, tvb, UDS_RDBI_DATA_RECORD_OFFSET, record_length, ENC_NA); col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x %s", data_identifier, tvb_bytes_to_str_punct(wmem_packet_scope(), tvb, UDS_RDBI_DATA_RECORD_OFFSET, record_length, ' ')); } else { guint32 identifier_length = data_length - UDS_RDBI_DATA_IDENTIFIER_OFFSET; guint32 offset = UDS_RDBI_DATA_IDENTIFIER_OFFSET; while (identifier_length > 0) { guint32 data_identifier; proto_tree_add_item_ret_uint(subtree, hf_uds_rdbi_data_identifier, tvb, offset, UDS_RDBI_DATA_IDENTIFIER_LEN, ENC_BIG_ENDIAN, &data_identifier); col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x", data_identifier); offset += UDS_RDBI_DATA_IDENTIFIER_LEN; identifier_length -= UDS_RDBI_DATA_IDENTIFIER_LEN; } } break; case UDS_SERVICES_SA: subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_sa, NULL, service_name); proto_tree_add_item_ret_uint(subtree, hf_uds_sa_type, tvb, UDS_SA_TYPE_OFFSET, UDS_SA_TYPE_LEN, ENC_BIG_ENDIAN, &enum_val); col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(enum_val, uds_sa_types, "Unknown (0x%02x)")); if (sid & UDS_REPLY_MASK) { guint32 seed_length = data_length - UDS_SA_SEED_OFFSET; if (seed_length > 0) { proto_tree_add_item(subtree, hf_uds_sa_seed, tvb, UDS_SA_SEED_OFFSET, seed_length, ENC_NA); col_append_fstr(pinfo->cinfo, COL_INFO, " %s", tvb_bytes_to_str_punct(wmem_packet_scope(), tvb, UDS_SA_SEED_OFFSET, seed_length, ' ')); } } else { guint32 key_length = data_length - UDS_SA_KEY_OFFSET; if (key_length > 0) { proto_tree_add_item(subtree, hf_uds_sa_key, tvb, UDS_SA_KEY_OFFSET, key_length, ENC_NA); col_append_fstr(pinfo->cinfo, COL_INFO, " %s", tvb_bytes_to_str_punct(wmem_packet_scope(), tvb, UDS_SA_KEY_OFFSET, key_length, ' ')); } } break; case UDS_SERVICES_WDBI: subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_wdbi, NULL, service_name); proto_tree_add_item_ret_uint(subtree, hf_uds_wdbi_data_identifier, tvb, UDS_WDBI_DATA_IDENTIFIER_OFFSET, UDS_WDBI_DATA_IDENTIFIER_LEN, ENC_BIG_ENDIAN, &enum_val); if (sid & UDS_REPLY_MASK) { col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x", enum_val); } else { guint32 record_length = data_length - UDS_WDBI_DATA_RECORD_OFFSET; proto_tree_add_item(subtree, hf_uds_wdbi_data_record, tvb, UDS_WDBI_DATA_RECORD_OFFSET, record_length, ENC_NA); col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x %s", enum_val, tvb_bytes_to_str_punct(wmem_packet_scope(), tvb, UDS_WDBI_DATA_RECORD_OFFSET, record_length, ' ')); } break; case UDS_SERVICES_IOCBI: { guint32 data_identifier; guint32 state_length = data_length - UDS_IOCBI_STATE_OFFSET; subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_iocbi, NULL, service_name); proto_tree_add_item_ret_uint(subtree, hf_uds_iocbi_data_identifier, tvb, UDS_IOCBI_DATA_IDENTIFIER_OFFSET, UDS_IOCBI_DATA_IDENTIFIER_LEN, ENC_BIG_ENDIAN, &data_identifier); proto_tree_add_item_ret_uint(subtree, hf_uds_iocbi_parameter, tvb, UDS_IOCBI_PARAMETER_OFFSET, UDS_IOCBI_PARAMETER_LEN, ENC_BIG_ENDIAN, &enum_val); proto_tree_add_item(subtree, hf_uds_iocbi_state, tvb, UDS_IOCBI_STATE_OFFSET, state_length, ENC_NA); col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x %s %s", data_identifier, val_to_str(enum_val, uds_iocbi_parameters, "Unknown (0x%02x)"), tvb_bytes_to_str_punct(wmem_packet_scope(), tvb, UDS_IOCBI_STATE_OFFSET, state_length, ' ')); break; } case UDS_SERVICES_RC: { guint32 identifier; subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_rc, NULL, service_name); proto_tree_add_item_ret_uint(subtree, hf_uds_rc_type, tvb, UDS_RC_TYPE_OFFSET, UDS_RC_TYPE_LEN, ENC_BIG_ENDIAN, &enum_val); proto_tree_add_item_ret_uint(subtree, hf_uds_rc_identifier, tvb, UDS_RC_ROUTINE_OFFSET, UDS_RC_ROUTINE_LEN, ENC_BIG_ENDIAN, &identifier); col_append_fstr(pinfo->cinfo, COL_INFO, " %s 0x%04x", val_to_str(enum_val, uds_rc_types, "Unknown (0x%02x)"), identifier); if (sid & UDS_REPLY_MASK) { guint32 rc_data_len = data_length - UDS_RC_INFO_OFFSET; if (rc_data_len > 0) { guint8 info = tvb_get_guint8(tvb, UDS_RC_INFO_OFFSET); proto_tree_add_item(subtree, hf_uds_rc_info, tvb, UDS_RC_INFO_OFFSET, UDS_RC_INFO_LEN, ENC_BIG_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%x", info); if (rc_data_len > 1) { guint32 status_record_len = data_length - UDS_RC_STATUS_RECORD_OFFSET; proto_tree_add_item(subtree, hf_uds_rc_status_record, tvb, UDS_RC_STATUS_RECORD_OFFSET, status_record_len, ENC_NA); col_append_fstr(pinfo->cinfo, COL_INFO, " %s", tvb_bytes_to_str_punct(wmem_packet_scope(), tvb, UDS_RC_STATUS_RECORD_OFFSET, status_record_len, ' ')); } } } else { guint32 option_record_len = data_length - UDS_RC_OPTION_RECORD_OFFSET; if (option_record_len > 0) { proto_tree_add_item(subtree, hf_uds_rc_option_record, tvb, UDS_RC_OPTION_RECORD_OFFSET, option_record_len, ENC_NA); col_append_fstr(pinfo->cinfo, COL_INFO, " %s", tvb_bytes_to_str_punct(wmem_packet_scope(), tvb, UDS_RC_OPTION_RECORD_OFFSET, option_record_len, ' ')); } } break; } case UDS_SERVICES_RD: subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_rd, NULL, service_name); if (sid & UDS_REPLY_MASK) { guint8 length_format_identifier, max_number_of_block_length_length; guint64 max_number_of_block_length; length_format_identifier = tvb_get_guint8(tvb, UDS_RD_LENGTH_FORMAT_IDENTIFIER_OFFSET); max_number_of_block_length_length = masked_guint8_value(length_format_identifier, UDS_RD_MAX_NUMBER_OF_BLOCK_LENGTH_LENGTH_MASK); proto_tree_add_item(subtree, hf_uds_rd_max_number_of_block_length_length, tvb, UDS_RD_LENGTH_FORMAT_IDENTIFIER_OFFSET, UDS_RD_LENGTH_FORMAT_IDENTIFIER_LEN, ENC_BIG_ENDIAN); max_number_of_block_length = tvb_get_guintX(tvb, UDS_RD_MAX_NUMBER_OF_BLOCK_LENGTH_OFFSET, max_number_of_block_length_length, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_uds_rd_max_number_of_block_length, tvb, UDS_RD_MAX_NUMBER_OF_BLOCK_LENGTH_OFFSET, max_number_of_block_length_length, ENC_BIG_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, " Max Number Of Block Length 0x%" G_GINT64_MODIFIER "x", max_number_of_block_length); } else { guint8 data_format_identifier, compression, encryting; guint8 address_and_length_format_idenfifier, memory_size_length, memory_address_length; guint64 memory_size, memory_address; data_format_identifier = tvb_get_guint8(tvb, UDS_RD_DATA_FORMAT_IDENTIFIER_OFFSET); compression = masked_guint8_value(data_format_identifier, UDS_RD_COMPRESSION_METHOD_MASK); proto_tree_add_item(subtree, hf_uds_rd_compression_method, tvb, UDS_RD_DATA_FORMAT_IDENTIFIER_OFFSET, UDS_RD_DATA_FORMAT_IDENTIFIER_LEN, ENC_BIG_ENDIAN); encryting = masked_guint8_value(data_format_identifier, UDS_RD_ENCRYPTING_METHOD_MASK); proto_tree_add_item(subtree, hf_uds_rd_encrypting_method, tvb, UDS_RD_DATA_FORMAT_IDENTIFIER_OFFSET, UDS_RD_DATA_FORMAT_IDENTIFIER_LEN, ENC_BIG_ENDIAN); address_and_length_format_idenfifier = tvb_get_guint8(tvb, UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_OFFSET); memory_size_length = masked_guint8_value(address_and_length_format_idenfifier, UDS_RD_COMPRESSION_METHOD_MASK); proto_tree_add_item(subtree, hf_uds_rd_memory_size_length, tvb, UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_OFFSET, UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_LEN, ENC_BIG_ENDIAN); memory_address_length = masked_guint8_value(address_and_length_format_idenfifier, UDS_RD_ENCRYPTING_METHOD_MASK); proto_tree_add_item(subtree, hf_uds_rd_memory_address_length, tvb, UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_OFFSET, UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_LEN, ENC_BIG_ENDIAN); memory_address = tvb_get_guintX(tvb, UDS_RD_MEMORY_ADDRESS_OFFSET, memory_address_length, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_uds_rd_memory_address, tvb, UDS_RD_MEMORY_ADDRESS_OFFSET, memory_address_length, ENC_BIG_ENDIAN); memory_size = tvb_get_guintX(tvb, UDS_RD_MEMORY_ADDRESS_OFFSET + memory_address_length, memory_size_length, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_uds_rd_memory_size, tvb, UDS_RD_MEMORY_ADDRESS_OFFSET + memory_address_length, memory_size_length, ENC_BIG_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%" G_GINT64_MODIFIER "x bytes at 0x%" G_GINT64_MODIFIER "x", memory_size, memory_address); col_append_fstr(pinfo->cinfo, COL_INFO, " (Compression:0x%x Encrypting:0x%x)", compression, encryting); } break; case UDS_SERVICES_TP: { guint8 sub_function_a, sub_function; subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_tp, NULL, service_name); sub_function_a = tvb_get_guint8(tvb, UDS_TP_SUB_FUNCTION_OFFSET); sub_function = masked_guint8_value(sub_function_a, UDS_TP_SUB_FUNCTION_MASK); proto_tree_add_item(subtree, hf_uds_tp_sub_function, tvb, UDS_TP_SUB_FUNCTION_OFFSET, UDS_TP_SUB_FUNCTION_LEN, ENC_BIG_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, " Sub-function %x", sub_function); if (!(sid & UDS_REPLY_MASK)) { guint8 suppress = masked_guint8_value(sub_function_a, UDS_TP_SUPPRESS_POS_RSP_MSG_INDIFICATION_MASK); proto_tree_add_item(subtree, hf_uds_tp_suppress_pos_rsp_msg_indification, tvb, UDS_TP_SUB_FUNCTION_OFFSET, UDS_TP_SUB_FUNCTION_LEN, ENC_BIG_ENDIAN); if (suppress) { col_append_fstr(pinfo->cinfo, COL_INFO, " (Reply suppressed)"); } } break; } case UDS_SERVICES_ERR: { subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_err, NULL, service_name); proto_tree_add_item_ret_uint(subtree, hf_uds_err_sid, tvb, UDS_ERR_SID_OFFSET, UDS_ERR_SID_LEN, ENC_BIG_ENDIAN, &enum_val); col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(enum_val, uds_services, "Unknown (0x%02x)")); proto_tree_add_item_ret_uint(subtree, hf_uds_err_code, tvb, UDS_ERR_CODE_OFFSET, UDS_ERR_CODE_LEN, ENC_BIG_ENDIAN, &enum_val); col_append_fstr(pinfo->cinfo, COL_INFO, " (SID: %s)", val_to_str(enum_val, uds_response_codes, "Unknown (0x%02x)")); break; } case UDS_SERVICES_CDTCS: { subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_cdtcs, NULL, service_name); proto_tree_add_item_ret_uint(subtree, hf_uds_cdtcs_type, tvb, UDS_CDTCS_TYPE_OFFSET, UDS_CDTCS_TYPE_LEN, ENC_BIG_ENDIAN, &enum_val); col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(enum_val, uds_cdtcs_types, "Unknown (0x%02x)")); break; } } return tvb_captured_length(tvb); } void proto_register_uds(void) { static hf_register_info hf[] = { { &hf_uds_service, { "Service Identifier", "uds.sid", FT_UINT8, BASE_HEX, VALS(uds_services), UDS_SID_MASK, NULL, HFILL } }, { &hf_uds_reply, { "Reply Flag", "uds.reply", FT_UINT8, BASE_HEX, NULL, UDS_REPLY_MASK, NULL, HFILL } }, { &hf_uds_dsc_type, { "Type", "uds.dsc.type", FT_UINT8, BASE_HEX, VALS(uds_dsc_types), 0x0, NULL, HFILL } }, { &hf_uds_dsc_parameter_record, { "Parameter Record", "uds.dsc.paramter_record", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_uds_er_type, { "Type", "uds.er.type", FT_UINT8, BASE_HEX, VALS(uds_er_types), 0x0, NULL, HFILL } }, { &hf_uds_rdtci_type, { "Type", "uds.rdtci.type", FT_UINT8, BASE_HEX, VALS(uds_rdtci_types), 0x0, NULL, HFILL } }, { &hf_uds_rdtci_record, { "Record", "uds.rdtci.record", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_uds_rdbi_data_identifier, { "Data Identifier", "uds.rdbi.data_identifier", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_uds_rdbi_data_record, { "Data Record", "uds.rdbi.data_record", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_uds_sa_type, { "Type", "uds.sa.type", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_uds_sa_key, { "Key", "uds.sa.key", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_uds_sa_seed, { "Seed", "uds.sa.seed", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_uds_wdbi_data_identifier, { "Data Identifier", "uds.wdbi.data_identifier", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_uds_wdbi_data_record, { "Data Record", "uds.wdbi.data_record", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_uds_iocbi_data_identifier, { "Data Identifier", "uds.iocbi.data_identifier", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_uds_iocbi_parameter, { "Parameter", "uds.iocbi.parameter", FT_UINT8, BASE_HEX, VALS(uds_iocbi_parameters), 0x0, NULL, HFILL } }, { &hf_uds_iocbi_state, { "State", "uds.iocbi.state", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_uds_rc_type, { "Type", "uds.rc.type", FT_UINT8, BASE_HEX, VALS(uds_rc_types), 0x0, NULL, HFILL } }, { &hf_uds_rc_identifier, { "Identifier", "uds.rc.identifier", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_uds_rc_option_record, { "Option record", "uds.rc.option_record", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_uds_rc_info, { "Info", "uds.rc.info", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_uds_rc_status_record, { "Status Record", "uds.rc.status_record", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_uds_rd_compression_method, { "Compression Method", "uds.rd.compression_method", FT_UINT8, BASE_HEX, NULL, UDS_RD_COMPRESSION_METHOD_MASK, NULL, HFILL } }, { &hf_uds_rd_encrypting_method, { "Encrypting Method", "uds.rd.encrypting_method", FT_UINT8, BASE_HEX, NULL, UDS_RD_ENCRYPTING_METHOD_MASK, NULL, HFILL } }, { &hf_uds_rd_memory_size_length, { "Memory size length", "uds.rd.memory_size_length", FT_UINT8, BASE_HEX, NULL, UDS_RD_MEMORY_SIZE_LENGTH_MASK, NULL, HFILL } }, { &hf_uds_rd_memory_address_length, { "Memory address length", "uds.rd.memory_address_length", FT_UINT8, BASE_HEX, NULL, UDS_RD_MEMORY_ADDRESS_LENGTH_MASK, NULL, HFILL } }, { &hf_uds_rd_memory_address, { "Memory Address", "uds.rd.memory_address", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_uds_rd_memory_size, { "Memory Size", "uds.rd.memory_size", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_uds_rd_max_number_of_block_length_length, { "Memory address length", "uds.rd.max_number_of_block_length_length", FT_UINT8, BASE_HEX, NULL, UDS_RD_MAX_NUMBER_OF_BLOCK_LENGTH_LENGTH_MASK, NULL, HFILL } }, { &hf_uds_rd_max_number_of_block_length, { "Memory Size", "uds.rd.max_number_of_block_length", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_uds_tp_sub_function, { "Suppress reply", "uds.tp.suppress_reply", FT_UINT8, BASE_HEX, NULL, UDS_TP_SUB_FUNCTION_MASK, NULL, HFILL } }, { &hf_uds_tp_suppress_pos_rsp_msg_indification, { "Suppress reply", "uds.tp.suppress_reply.indification", FT_BOOLEAN, 8, NULL, UDS_TP_SUPPRESS_POS_RSP_MSG_INDIFICATION_MASK, NULL, HFILL } }, { &hf_uds_err_sid, { "Service Identifier", "uds.err.sid", FT_UINT8, BASE_HEX, VALS(uds_services), 0x0, NULL, HFILL } }, { &hf_uds_err_code, { "Code", "uds.err.code", FT_UINT8, BASE_HEX, VALS(uds_response_codes), 0x0, NULL, HFILL } }, { &hf_uds_cdtcs_type, { "Type", "uds.cdtcs.type", FT_UINT8, BASE_HEX, VALS(uds_cdtcs_types), 0x0, NULL, HFILL } }, }; /* Setup protocol subtree array */ static gint *ett[] = { &ett_uds, &ett_uds_dsc, &ett_uds_er, &ett_uds_rdtci, &ett_uds_rdbi, &ett_uds_sa, &ett_uds_wdbi, &ett_uds_iocbi, &ett_uds_rc, &ett_uds_rd, &ett_uds_tp, &ett_uds_err, &ett_uds_cdtcs, }; proto_uds = proto_register_protocol ( "Unified Diagnostic Services", /* name */ "UDS", /* short name */ "uds" /* abbrev */ ); proto_register_field_array(proto_uds, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); } void proto_reg_handoff_uds(void) { static dissector_handle_t uds_handle; uds_handle = create_dissector_handle(dissect_uds, proto_uds); dissector_add_for_decode_as("iso15765.subdissector", uds_handle); } /* * Editor modelines - http://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: */