1 /* packet-uds.c
2 * Routines for uds protocol packet disassembly
3 *
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "config.h"
12
13 #include <epan/packet.h>
14 #include <epan/uat.h>
15 #include <wsutil/bits_ctz.h>
16 #include <epan/dissectors/packet-doip.h>
17 #include <epan/dissectors/packet-iso10681.h>
18 #include <epan/dissectors/packet-iso15765.h>
19
20 void proto_register_uds(void);
21 void proto_reg_handoff_uds(void);
22
23 #define DATAFILE_UDS_ROUTINE_IDS "UDS_routine_identifiers"
24 #define DATAFILE_UDS_DATA_IDS "UDS_data_identifiers"
25
26 #define UDS_SERVICES_DSC 0x10
27 #define UDS_SERVICES_ER 0x11
28 #define UDS_SERVICES_CDTCI 0x14
29 #define UDS_SERVICES_RDTCI 0x19
30 #define UDS_SERVICES_RDBI 0x22
31 #define UDS_SERVICES_RMBA 0x23
32 #define UDS_SERVICES_RSDBI 0x24
33 #define UDS_SERVICES_SA 0x27
34 #define UDS_SERVICES_CC 0x28
35 #define UDS_SERVICES_RDBPI 0x2A
36 #define UDS_SERVICES_DDDI 0x2C
37 #define UDS_SERVICES_WDBI 0x2E
38 #define UDS_SERVICES_IOCBI 0x2F
39 #define UDS_SERVICES_RC 0x31
40 #define UDS_SERVICES_RD 0x34
41 #define UDS_SERVICES_RU 0x35
42 #define UDS_SERVICES_TD 0x36
43 #define UDS_SERVICES_RTE 0x37
44 #define UDS_SERVICES_RFT 0x38
45 #define UDS_SERVICES_WMBA 0x3D
46 #define UDS_SERVICES_TP 0x3E
47 #define UDS_SERVICES_ERR 0x3F
48 #define UDS_SERVICES_CDTCS 0x85
49
50 #define UDS_RESPONSE_CODES_GR 0x10
51 #define UDS_RESPONSE_CODES_SNS 0x11
52 #define UDS_RESPONSE_CODES_SFNS 0x12
53 #define UDS_RESPONSE_CODES_IMLOIF 0x13
54 #define UDS_RESPONSE_CODES_RTL 0x14
55 #define UDS_RESPONSE_CODES_BRR 0x21
56 #define UDS_RESPONSE_CODES_CNC 0x22
57 #define UDS_RESPONSE_CODES_RSE 0x24
58 #define UDS_RESPONSE_CODES_NRFSC 0x25
59 #define UDS_RESPONSE_CODES_FPEORA 0x26
60 #define UDS_RESPONSE_CODES_ROOR 0x31
61 #define UDS_RESPONSE_CODES_SAD 0x33
62 #define UDS_RESPONSE_CODES_IK 0x35
63 #define UDS_RESPONSE_CODES_ENOA 0x36
64 #define UDS_RESPONSE_CODES_RTDNE 0x37
65 #define UDS_RESPONSE_CODES_UDNA 0x70
66 #define UDS_RESPONSE_CODES_TDS 0x71
67 #define UDS_RESPONSE_CODES_GPF 0x72
68 #define UDS_RESPONSE_CODES_WBSC 0x73
69 #define UDS_RESPONSE_CODES_RCRRP 0x78
70 #define UDS_RESPONSE_CODES_SFNSIAS 0x7E
71 #define UDS_RESPONSE_CODES_SNSIAS 0x7F
72
73
74 #define UDS_SID_MASK 0xBF
75 #define UDS_REPLY_MASK 0x40
76 #define UDS_SID_OFFSET 0
77 #define UDS_SID_LEN 1
78 #define UDS_DATA_OFFSET 1
79
80 #define UDS_DSC_TYPE_OFFSET (UDS_DATA_OFFSET + 0)
81 #define UDS_DSC_TYPE_LEN 1
82 #define UDS_DSC_PARAMETER_RECORD_OFFSET (UDS_DSC_TYPE_OFFSET + UDS_DSC_TYPE_LEN)
83
84 #define UDS_DSC_TYPES_DEFAULT_SESSION 1
85 #define UDS_DSC_TYPES_PROGRAMMING_SESSION 2
86 #define UDS_DSC_TYPES_EXTENDED_DIAGNOSTIC_SESSION 3
87 #define UDS_DSC_TYPES_SAFETY_SYSTEM_DIAGNOSTIC_SESSION 4
88
89 #define UDS_ER_TYPE_OFFSET (UDS_DATA_OFFSET + 0)
90 #define UDS_ER_TYPE_LEN 1
91
92 #define UDS_ER_TYPES_HARD_RESET 1
93 #define UDS_ER_TYPES_KEY_ON_OFF_RESET 2
94 #define UDS_ER_TYPES_SOFT_RESET 3
95 #define UDS_ER_TYPES_ENABLE_RAPID_POWER_SHUTDOWN 4
96 #define UDS_ER_TYPES_DISABLE_RAPID_POWER_SHUTDOWN 5
97
98 #define UDS_RDTCI_TYPE_OFFSET (UDS_DATA_OFFSET + 0)
99 #define UDS_RDTCI_TYPE_LEN 1
100 #define UDS_RDTCI_RECORD_OFFSET (UDS_RDTCI_TYPE_OFFSET + UDS_RDTCI_TYPE_LEN)
101
102 #define UDS_RDTCI_TYPES_NUMBER_BY_STATUS_MASK 0x1
103 #define UDS_RDTCI_TYPES_BY_STATUS_MASK 0x2
104 #define UDS_RDTCI_TYPES_SNAPSHOT_IDENTIFICATION 0x3
105 #define UDS_RDTCI_TYPES_SNAPSHOT_RECORD_BY_DTC 0x4
106 #define UDS_RDTCI_TYPES_SNAPSHOT_RECORD_BY_RECORD 0x5
107 #define UDS_RDTCI_TYPES_EXTENDED_RECARD_BY_DTC 0x6
108 #define UDS_RDTCI_TYPES_SUPPORTED_DTC 0xA
109
110 #define UDS_RDBI_DATA_IDENTIFIER_OFFSET (UDS_DATA_OFFSET + 0)
111 #define UDS_RDBI_DATA_IDENTIFIER_LEN 2
112 #define UDS_RDBI_DATA_RECORD_OFFSET (UDS_RDBI_DATA_IDENTIFIER_OFFSET + UDS_RDBI_DATA_IDENTIFIER_LEN)
113
114 #define UDS_SA_TYPE_OFFSET (UDS_DATA_OFFSET + 0)
115 #define UDS_SA_TYPE_LEN 1
116 #define UDS_SA_KEY_OFFSET (UDS_SA_TYPE_OFFSET + UDS_SA_TYPE_LEN)
117 #define UDS_SA_SEED_OFFSET (UDS_SA_TYPE_OFFSET + UDS_SA_TYPE_LEN)
118
119 #define UDS_SA_TYPES_SEED 1
120 #define UDS_SA_TYPES_KEY 2
121 #define UDS_SA_TYPES_SEED_2 3
122 #define UDS_SA_TYPES_KEY_2 4
123
124 #define UDS_WDBI_DATA_IDENTIFIER_OFFSET (UDS_DATA_OFFSET + 0)
125 #define UDS_WDBI_DATA_IDENTIFIER_LEN 2
126 #define UDS_WDBI_DATA_RECORD_OFFSET (UDS_WDBI_DATA_IDENTIFIER_OFFSET + UDS_WDBI_DATA_IDENTIFIER_LEN)
127
128 #define UDS_IOCBI_DATA_IDENTIFIER_OFFSET (UDS_DATA_OFFSET + 0)
129 #define UDS_IOCBI_DATA_IDENTIFIER_LEN 2
130 #define UDS_IOCBI_PARAMETER_OFFSET (UDS_IOCBI_DATA_IDENTIFIER_OFFSET + UDS_IOCBI_DATA_IDENTIFIER_LEN)
131 #define UDS_IOCBI_PARAMETER_LEN 1
132 #define UDS_IOCBI_STATE_OFFSET (UDS_IOCBI_PARAMETER_OFFSET + UDS_IOCBI_PARAMETER_LEN)
133
134 #define UDS_IOCBI_PARAMETERS_RETURN_CONTROL_TO_ECU 0
135 #define UDS_IOCBI_PARAMETERS_RESET_TO_DEFAULT 1
136 #define UDS_IOCBI_PARAMETERS_FREEZE_CURRENT_STATE 2
137 #define UDS_IOCBI_PARAMETERS_SHORT_TERM_ADJUSTMENT 3
138
139 #define UDS_RC_TYPE_OFFSET (UDS_DATA_OFFSET + 0)
140 #define UDS_RC_TYPE_LEN 1
141 #define UDS_RC_ROUTINE_OFFSET (UDS_RC_TYPE_OFFSET + UDS_RC_TYPE_LEN)
142 #define UDS_RC_ROUTINE_LEN 2
143 #define UDS_RC_OPTION_RECORD_OFFSET (UDS_RC_ROUTINE_OFFSET + UDS_RC_ROUTINE_LEN)
144 #define UDS_RC_INFO_OFFSET (UDS_RC_ROUTINE_OFFSET + UDS_RC_ROUTINE_LEN)
145 #define UDS_RC_INFO_LEN 1
146 #define UDS_RC_STATUS_RECORD_OFFSET (UDS_RC_INFO_OFFSET + UDS_RC_INFO_LEN)
147
148 #define UDS_RC_TYPES_START 1
149 #define UDS_RC_TYPES_STOP 2
150 #define UDS_RC_TYPES_REQUEST 3
151
152 #define UDS_RD_DATA_FORMAT_IDENTIFIER_OFFSET (UDS_DATA_OFFSET + 0)
153 #define UDS_RD_DATA_FORMAT_IDENTIFIER_LEN 1
154 #define UDS_RD_COMPRESSION_METHOD_MASK 0xF0
155 #define UDS_RD_ENCRYPTING_METHOD_MASK 0x0F
156 #define UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_OFFSET (UDS_RD_DATA_FORMAT_IDENTIFIER_OFFSET + UDS_RD_DATA_FORMAT_IDENTIFIER_LEN)
157 #define UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_LEN 1
158 #define UDS_RD_MEMORY_SIZE_LENGTH_MASK 0xF0
159 #define UDS_RD_MEMORY_ADDRESS_LENGTH_MASK 0x0F
160 #define UDS_RD_MEMORY_ADDRESS_OFFSET (UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_OFFSET + UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_LEN)
161 #define UDS_RD_LENGTH_FORMAT_IDENTIFIER_OFFSET (UDS_DATA_OFFSET + 0)
162 #define UDS_RD_LENGTH_FORMAT_IDENTIFIER_LEN 1
163 #define UDS_RD_MAX_NUMBER_OF_BLOCK_LENGTH_LENGTH_MASK 0xF0
164 #define UDS_RD_MAX_NUMBER_OF_BLOCK_LENGTH_OFFSET (UDS_RD_LENGTH_FORMAT_IDENTIFIER_OFFSET + UDS_RD_LENGTH_FORMAT_IDENTIFIER_LEN)
165
166 #define UDS_TD_SEQUENCE_COUNTER_OFFSET (UDS_DATA_OFFSET + 0)
167 #define UDS_TD_SEQUENCE_COUNTER_LEN 1
168
169 #define UDS_TP_SUB_FUNCTION_OFFSET (UDS_DATA_OFFSET + 0)
170 #define UDS_TP_SUB_FUNCTION_LEN 1
171 #define UDS_TP_SUB_FUNCTION_MASK 0x7f
172 #define UDS_TP_SUPPRESS_POS_RSP_MSG_INDIFICATION_MASK 0x80
173
174 #define UDS_ERR_SID_OFFSET (UDS_DATA_OFFSET + 0)
175 #define UDS_ERR_SID_LEN 1
176 #define UDS_ERR_CODE_OFFSET (UDS_ERR_SID_OFFSET + UDS_ERR_SID_LEN)
177 #define UDS_ERR_CODE_LEN 1
178
179 #define UDS_CDTCS_TYPE_OFFSET (UDS_DATA_OFFSET + 0)
180 #define UDS_CDTCS_TYPE_LEN 1
181
182 #define UDS_CDTCS_ACTIONS_ON 1
183 #define UDS_CDTCS_ACTIONS_OFF 2
184
185 /*
186 * Enums
187 */
188
189 /* Services */
190 static const value_string uds_services[]= {
191 {UDS_SERVICES_DSC, "Diagnostic Session Control"},
192 {UDS_SERVICES_ER, "ECU Reset"},
193 {UDS_SERVICES_CDTCI, "Clear Diagnostic Information"},
194 {UDS_SERVICES_RDTCI, "Read DTC Information"},
195 {UDS_SERVICES_RDBI, "Read Data By Identifier"},
196 {UDS_SERVICES_RMBA, "Read Memory By Address"},
197 {UDS_SERVICES_RSDBI, "Read Scaling Data By Identifier"},
198 {UDS_SERVICES_SA, "Security Access"},
199 {UDS_SERVICES_CC, "Communication Control"},
200 {UDS_SERVICES_RDBPI, "Read Data By Periodic Identifier"},
201 {UDS_SERVICES_DDDI, "Dynamically Define Data Identifier"},
202 {UDS_SERVICES_WDBI, "Write Data By Identifier"},
203 {UDS_SERVICES_IOCBI, "Input Output Control By Identifier"},
204 {UDS_SERVICES_RC, "Routine Control"},
205 {UDS_SERVICES_RD, "Request Download"},
206 {UDS_SERVICES_RU, "Request Upload"},
207 {UDS_SERVICES_TD, "Transfer Data"},
208 {UDS_SERVICES_RTE, "Request Transfer Exit"},
209 {UDS_SERVICES_RFT, "Request File Transfer"},
210 {UDS_SERVICES_WMBA, "Write Memory By Address"},
211 {UDS_SERVICES_TP, "Tester Present"},
212 {UDS_SERVICES_ERR, "Error"},
213 {UDS_SERVICES_CDTCS, "Control DTC Setting"},
214 {0, NULL}
215 };
216 /* Response code */
217 static const value_string uds_response_codes[]= {
218 {UDS_RESPONSE_CODES_GR, "General reject"},
219 {UDS_RESPONSE_CODES_SNS, "Service not supported"},
220 {UDS_RESPONSE_CODES_SFNS, "Sub-Function Not Supported"},
221 {UDS_RESPONSE_CODES_IMLOIF, "Incorrect Message Length or Invalid Format"},
222 {UDS_RESPONSE_CODES_RTL, "Response too long"},
223 {UDS_RESPONSE_CODES_BRR, "Busy repeat request"},
224 {UDS_RESPONSE_CODES_CNC, "Conditions Not Correct"},
225 {UDS_RESPONSE_CODES_RSE, "Request Sequence Error"},
226 {UDS_RESPONSE_CODES_NRFSC, "No response from sub-net component"},
227 {UDS_RESPONSE_CODES_FPEORA, "Failure prevents execution of requested action"},
228 {UDS_RESPONSE_CODES_ROOR, "Request Out of Range"},
229 {UDS_RESPONSE_CODES_SAD, "Security Access Denied"},
230 {UDS_RESPONSE_CODES_IK, "Invalid Key"},
231 {UDS_RESPONSE_CODES_ENOA, "Exceeded Number Of Attempts"},
232 {UDS_RESPONSE_CODES_RTDNE, "Required Time Delay Not Expired"},
233 {UDS_RESPONSE_CODES_UDNA, "Upload/Download not accepted"},
234 {UDS_RESPONSE_CODES_TDS, "Transfer data suspended"},
235 {UDS_RESPONSE_CODES_GPF, "General Programming Failure"},
236 {UDS_RESPONSE_CODES_WBSC, "Wrong Block Sequence Counter"},
237 {UDS_RESPONSE_CODES_RCRRP, "Request correctly received, but response is pending"},
238 {UDS_RESPONSE_CODES_SFNSIAS, "Sub-Function not supported in active session"},
239 {UDS_RESPONSE_CODES_SNSIAS, "Service not supported in active session"},
240 {0, NULL}
241 };
242
243 /* DSC */
244 static const value_string uds_dsc_types[] = {
245 {0, "Reserved"},
246 {UDS_DSC_TYPES_DEFAULT_SESSION, "Default Session"},
247 {UDS_DSC_TYPES_PROGRAMMING_SESSION, "Programming Session"},
248 {UDS_DSC_TYPES_EXTENDED_DIAGNOSTIC_SESSION, "Extended Diagnostic Session"},
249 {UDS_DSC_TYPES_SAFETY_SYSTEM_DIAGNOSTIC_SESSION, "Safety System Diagnostic Session"},
250 {0, NULL}
251 };
252
253 /* ER */
254 static const value_string uds_er_types[] = {
255 {0, "Reserved"},
256 {UDS_ER_TYPES_HARD_RESET, "Hard Reset"},
257 {UDS_ER_TYPES_KEY_ON_OFF_RESET, "Key On Off Reset"},
258 {UDS_ER_TYPES_SOFT_RESET, "Soft Reset"},
259 {UDS_ER_TYPES_ENABLE_RAPID_POWER_SHUTDOWN, "Enable Rapid Power Shutdown"},
260 {UDS_ER_TYPES_DISABLE_RAPID_POWER_SHUTDOWN, "Disable Rapid Power Shutdown"},
261 {0, NULL}
262 };
263
264 /* SA */
265 static const value_string uds_sa_types[] = {
266 {UDS_SA_TYPES_SEED, "Request Seed"},
267 {UDS_SA_TYPES_KEY, "Send Key"},
268 {UDS_SA_TYPES_SEED_2, "Request Seed"},
269 {UDS_SA_TYPES_KEY_2, "Send Key"},
270 {0, NULL}
271 };
272
273 /* RDTCI */
274 static const value_string uds_rdtci_types[] = {
275 {UDS_RDTCI_TYPES_NUMBER_BY_STATUS_MASK, "Report Number of DTC by Status Mask"},
276 {UDS_RDTCI_TYPES_BY_STATUS_MASK, "Report DTC by Status Mask"},
277 {UDS_RDTCI_TYPES_SNAPSHOT_IDENTIFICATION, "Report DTC Snapshot Identification"},
278 {UDS_RDTCI_TYPES_SNAPSHOT_RECORD_BY_DTC, "Report DTC Snapshot Record by DTC Number"},
279 {UDS_RDTCI_TYPES_SNAPSHOT_RECORD_BY_RECORD, "Report DTC Snapshot Record by Record Number"},
280 {UDS_RDTCI_TYPES_EXTENDED_RECARD_BY_DTC, "Report DTC Extended Data Record by DTC Number"},
281 {UDS_RDTCI_TYPES_SUPPORTED_DTC, "Report Supported DTC"},
282 {0, NULL}
283 };
284
285 /* IOCBI */
286 static const value_string uds_iocbi_parameters[] = {
287 {UDS_IOCBI_PARAMETERS_RETURN_CONTROL_TO_ECU, "Return Control To ECU"},
288 {UDS_IOCBI_PARAMETERS_RESET_TO_DEFAULT, "Reset To Default"},
289 {UDS_IOCBI_PARAMETERS_FREEZE_CURRENT_STATE, "Freeze Current State"},
290 {UDS_IOCBI_PARAMETERS_SHORT_TERM_ADJUSTMENT, "Short Term Adjustment"},
291 {0, NULL}
292 };
293
294 /* RC */
295 static const value_string uds_rc_types[] = {
296 {0, "Reserved"},
297 {UDS_RC_TYPES_START, "Start routine"},
298 {UDS_RC_TYPES_STOP, "Stop routine"},
299 {UDS_RC_TYPES_REQUEST, "Request routine result"},
300 {0, NULL}
301 };
302
303 /* CDTCS */
304 static const value_string uds_cdtcs_types[] = {
305 {0, "Reserved"},
306 {UDS_CDTCS_ACTIONS_ON, "On"},
307 {UDS_CDTCS_ACTIONS_OFF, "Off"},
308 {0, NULL}
309 };
310
311 /*
312 * Fields
313 */
314 static int hf_uds_service = -1;
315 static int hf_uds_reply = -1;
316
317 static int hf_uds_dsc_type = -1;
318 static int hf_uds_dsc_parameter_record = -1;
319
320 static int hf_uds_er_type = -1;
321
322 static int hf_uds_rdtci_type = -1;
323 static int hf_uds_rdtci_record = -1;
324
325 static int hf_uds_rdbi_data_identifier = -1;
326 static int hf_uds_rdbi_data_record = -1;
327
328 static int hf_uds_sa_type = -1;
329 static int hf_uds_sa_key = -1;
330 static int hf_uds_sa_seed = -1;
331
332 static int hf_uds_wdbi_data_identifier = -1;
333 static int hf_uds_wdbi_data_record = -1;
334
335 static int hf_uds_iocbi_data_identifier = -1;
336 static int hf_uds_iocbi_parameter = -1;
337 static int hf_uds_iocbi_state = -1;
338
339 static int hf_uds_rc_type = -1;
340 static int hf_uds_rc_identifier = -1;
341 static int hf_uds_rc_option_record = -1;
342 static int hf_uds_rc_info = -1;
343 static int hf_uds_rc_status_record = -1;
344
345 static int hf_uds_rd_compression_method = -1;
346 static int hf_uds_rd_encrypting_method = -1;
347 static int hf_uds_rd_memory_size_length = -1;
348 static int hf_uds_rd_memory_address_length = -1;
349 static int hf_uds_rd_memory_address = -1;
350 static int hf_uds_rd_memory_size = -1;
351 static int hf_uds_rd_max_number_of_block_length_length = -1;
352 static int hf_uds_rd_max_number_of_block_length = -1;
353
354 static int hf_uds_td_sequence_counter = -1;
355
356 static int hf_uds_tp_sub_function = -1;
357 static int hf_uds_tp_suppress_pos_rsp_msg_indification = -1;
358
359 static int hf_uds_err_sid = -1;
360 static int hf_uds_err_code = -1;
361
362 static int hf_uds_cdtcs_type = -1;
363
364 /*
365 * Trees
366 */
367 static gint ett_uds = -1;
368 static gint ett_uds_dsc = -1;
369 static gint ett_uds_er = -1;
370 static gint ett_uds_rdtci = -1;
371 static gint ett_uds_rdbi = -1;
372 static gint ett_uds_sa = -1;
373 static gint ett_uds_wdbi = -1;
374 static gint ett_uds_iocbi = -1;
375 static gint ett_uds_rc = -1;
376 static gint ett_uds_rd = -1;
377 static gint ett_uds_td = -1;
378 static gint ett_uds_tp = -1;
379 static gint ett_uds_err = -1;
380 static gint ett_uds_cdtcs = -1;
381
382 static int proto_uds = -1;
383
384 static dissector_handle_t uds_handle;
385 static dissector_handle_t uds_handle_doip;
386 static dissector_handle_t uds_handle_iso10681;
387 static dissector_handle_t uds_handle_iso15765;
388
389
390 /*** Configuration ***/
391 typedef struct _generic_addr_id_string {
392 guint32 address;
393 guint id;
394 gchar *name;
395 } generic_addr_id_string_t;
396
397 static void *
copy_generic_one_id_string_cb(void * n,const void * o,size_t size _U_)398 copy_generic_one_id_string_cb(void *n, const void *o, size_t size _U_) {
399 generic_addr_id_string_t *new_rec = (generic_addr_id_string_t *)n;
400 const generic_addr_id_string_t *old_rec = (const generic_addr_id_string_t *)o;
401
402 new_rec->name = g_strdup(old_rec->name);
403 new_rec->id = old_rec->id;
404 new_rec->address = old_rec->address;
405 return new_rec;
406 }
407
408 static gboolean
update_generic_addr_id_16bit(void * r,char ** err)409 update_generic_addr_id_16bit(void *r, char **err) {
410 generic_addr_id_string_t *rec = (generic_addr_id_string_t *)r;
411
412 if (rec->id > 0xffff) {
413 *err = g_strdup_printf("We currently only support 16 bit identifiers (Addr: %x ID: %i Name: %s)", rec->address, rec->id, rec->name);
414 return FALSE;
415 }
416
417 if (rec->address > 0xffff && rec->address != G_MAXUINT32) {
418 *err = g_strdup_printf("We currently only support 16 bit addresses with 0xffffffff = \"don't care\" (Addr: %x ID: %i Name: %s)",
419 rec->address, rec->id, rec->name);
420 return FALSE;
421 }
422
423 if (rec->name == NULL || rec->name[0] == 0) {
424 *err = g_strdup("Name cannot be empty");
425 return FALSE;
426 }
427
428 return TRUE;
429 }
430
431 static void
free_generic_one_id_string_cb(void * r)432 free_generic_one_id_string_cb(void *r) {
433 generic_addr_id_string_t *rec = (generic_addr_id_string_t *)r;
434
435 /* freeing result of g_strdup */
436 g_free(rec->name);
437 rec->name = NULL;
438 }
439
440 static gint64
calc_key(guint32 addr,guint16 id)441 calc_key(guint32 addr, guint16 id) {
442 return ((gint64)id << 32) | (gint64)addr;
443 }
444
445 static void
post_update_one_id_string_template_cb(generic_addr_id_string_t * data,guint data_num,GHashTable * ht)446 post_update_one_id_string_template_cb(generic_addr_id_string_t *data, guint data_num, GHashTable *ht) {
447 guint i;
448 gint64 *key = NULL;
449
450 for (i = 0; i < data_num; i++) {
451 key = wmem_new(wmem_epan_scope(), gint64);
452 *key = calc_key(data[i].address, data[i].id);
453
454 g_hash_table_insert(ht, key, g_strdup(data[i].name));
455 }
456 }
457
458 static char *
generic_lookup_addr_id(guint32 addr,guint16 id,GHashTable * ht)459 generic_lookup_addr_id(guint32 addr, guint16 id, GHashTable *ht) {
460 char *ret = NULL;
461
462 /* we only currently allow 16bit + MAXUINT32 as any */
463 if (addr > G_MAXUINT16 && addr != G_MAXUINT32) {
464 addr = G_MAXUINT32;
465 }
466
467 guint64 tmp = calc_key(addr, id);
468
469 if (ht == NULL) {
470 return NULL;
471 }
472
473 ret = (char *)g_hash_table_lookup(ht, &tmp);
474 if (ret == NULL) {
475 tmp = calc_key(G_MAXUINT32, id);
476 return (char *)g_hash_table_lookup(ht, &tmp);
477 }
478
479 return ret;
480 }
481
482 static void
simple_free_key(gpointer key)483 simple_free_key(gpointer key) {
484 wmem_free(wmem_epan_scope(), key);
485 }
486
487 static void
simple_free(gpointer data)488 simple_free(gpointer data) {
489 /* we need to free because of the g_strdup in post_update*/
490 g_free(data);
491 }
492
493
494 /* Routine IDs */
495 static generic_addr_id_string_t *uds_uat_routine_ids = NULL;
496 static guint uds_uat_routine_id_num = 0;
497 static GHashTable *uds_ht_routine_ids = NULL;
498
UAT_HEX_CB_DEF(uds_uat_routine_ids,address,generic_addr_id_string_t)499 UAT_HEX_CB_DEF(uds_uat_routine_ids, address, generic_addr_id_string_t)
500 UAT_HEX_CB_DEF(uds_uat_routine_ids, id, generic_addr_id_string_t)
501 UAT_CSTRING_CB_DEF(uds_uat_routine_ids, name, generic_addr_id_string_t)
502
503 static void
504 post_update_uds_routine_cb(void) {
505 /* destroy old hash table, if it exists */
506 if (uds_ht_routine_ids) {
507 g_hash_table_destroy(uds_ht_routine_ids);
508 }
509
510 /* create new hash table */
511 uds_ht_routine_ids = g_hash_table_new_full(g_int64_hash, g_int64_equal, &simple_free_key, &simple_free);
512 post_update_one_id_string_template_cb(uds_uat_routine_ids, uds_uat_routine_id_num, uds_ht_routine_ids);
513 }
514
515 static char *
uds_lookup_routine_name(guint32 addr,guint16 id)516 uds_lookup_routine_name(guint32 addr, guint16 id) {
517 return generic_lookup_addr_id(addr, id, uds_ht_routine_ids);
518 }
519
520 static void
protoitem_append_routine_name(proto_item * ti,guint32 addr,guint16 data_identifier)521 protoitem_append_routine_name(proto_item *ti, guint32 addr, guint16 data_identifier) {
522 gchar *routine_name = uds_lookup_routine_name(addr, data_identifier);
523 if (routine_name != NULL) {
524 proto_item_append_text(ti, " (%s)", routine_name);
525 }
526 }
527
528 static void
infocol_append_routine_name(packet_info * pinfo,guint32 addr,guint16 routine_identifier)529 infocol_append_routine_name(packet_info *pinfo, guint32 addr, guint16 routine_identifier) {
530 gchar *routine_name = uds_lookup_routine_name(addr, routine_identifier);
531 if (routine_name != NULL) {
532 col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", routine_name);
533 }
534 }
535
536
537 /* Data IDs */
538 static generic_addr_id_string_t *uds_uat_data_ids = NULL;
539 static guint uds_uat_data_id_num = 0;
540 static GHashTable *uds_ht_data_ids = NULL;
541
UAT_HEX_CB_DEF(uds_uat_data_ids,address,generic_addr_id_string_t)542 UAT_HEX_CB_DEF(uds_uat_data_ids, address, generic_addr_id_string_t)
543 UAT_HEX_CB_DEF(uds_uat_data_ids, id, generic_addr_id_string_t)
544 UAT_CSTRING_CB_DEF(uds_uat_data_ids, name, generic_addr_id_string_t)
545
546 static void
547 post_update_uds_data_cb(void) {
548 /* destroy old hash table, if it exists */
549 if (uds_ht_data_ids) {
550 g_hash_table_destroy(uds_ht_data_ids);
551 }
552
553 /* create new hash table */
554 uds_ht_data_ids = g_hash_table_new_full(g_int64_hash, g_int64_equal, &simple_free_key, &simple_free);
555 post_update_one_id_string_template_cb(uds_uat_data_ids, uds_uat_data_id_num, uds_ht_data_ids);
556 }
557
558 static char *
uds_lookup_data_name(guint32 addr,guint16 id)559 uds_lookup_data_name(guint32 addr, guint16 id) {
560 return generic_lookup_addr_id(addr, id, uds_ht_data_ids);
561 }
562
563 static void
protoitem_append_data_name(proto_item * ti,guint32 addr,guint16 data_identifier)564 protoitem_append_data_name(proto_item *ti, guint32 addr, guint16 data_identifier) {
565 gchar *data_name = uds_lookup_data_name(addr, data_identifier);
566 if (data_name != NULL) {
567 proto_item_append_text(ti, " (%s)", data_name);
568 }
569 }
570
571 static void
infocol_append_data_name(packet_info * pinfo,guint32 addr,guint16 data_identifier)572 infocol_append_data_name(packet_info *pinfo, guint32 addr, guint16 data_identifier) {
573 gchar *data_name = uds_lookup_data_name(addr, data_identifier);
574 if (data_name != NULL) {
575 col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", data_name);
576 }
577 }
578
579 /*** Configuration End ***/
580
581
582 static
masked_guint8_value(const guint8 value,const guint8 mask)583 guint8 masked_guint8_value(const guint8 value, const guint8 mask)
584 {
585 return (value & mask) >> ws_ctz(mask);
586 }
587
588 static guint64
tvb_get_guintX(tvbuff_t * tvb,const gint offset,const gint size,const guint encoding)589 tvb_get_guintX(tvbuff_t *tvb, const gint offset, const gint size, const guint encoding) {
590 switch (size) {
591 case 1:
592 return tvb_get_guint8(tvb, offset);
593 case 2:
594 return tvb_get_guint16(tvb, offset, encoding);
595 case 3:
596 return tvb_get_guint24(tvb, offset, encoding);
597 case 4:
598 return tvb_get_guint32(tvb, offset, encoding);
599 case 5:
600 return tvb_get_guint40(tvb, offset, encoding);
601 case 6:
602 return tvb_get_guint48(tvb, offset, encoding);
603 case 7:
604 return tvb_get_guint56(tvb, offset, encoding);
605 case 8:
606 return tvb_get_guint64(tvb, offset, encoding);
607 }
608
609 return 0;
610 }
611
612 static int
dissect_uds_internal(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,guint16 source_address,guint16 target_address,guint8 number_of_addresses_valid)613 dissect_uds_internal(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint16 source_address, guint16 target_address, guint8 number_of_addresses_valid)
614 {
615 proto_tree *uds_tree, *subtree;
616 proto_item *ti;
617 guint8 sid, service;
618 guint32 enum_val;
619 const char *service_name;
620 guint32 ecu_address;
621 guint32 data_length = tvb_reported_length(tvb);
622
623 col_set_str(pinfo->cinfo, COL_PROTOCOL, "UDS");
624 col_clear(pinfo->cinfo,COL_INFO);
625
626 sid = tvb_get_guint8(tvb, UDS_SID_OFFSET);
627 service = sid & UDS_SID_MASK;
628 service_name = val_to_str(service, uds_services, "Unknown (0x%02x)");
629
630 col_add_fstr(pinfo->cinfo, COL_INFO, "%-7s %-36s", (sid & UDS_REPLY_MASK)? "Reply": "Request", service_name);
631
632 ti = proto_tree_add_item(tree, proto_uds, tvb, 0, -1, ENC_NA);
633 uds_tree = proto_item_add_subtree(ti, ett_uds);
634 proto_tree_add_item(uds_tree, hf_uds_service, tvb, UDS_SID_OFFSET, UDS_SID_LEN, ENC_BIG_ENDIAN);
635 proto_tree_add_item(uds_tree, hf_uds_reply, tvb, UDS_SID_OFFSET, UDS_SID_LEN, ENC_BIG_ENDIAN);
636
637 if (sid & UDS_REPLY_MASK) {
638 ecu_address = source_address;
639 } else {
640 ecu_address = target_address;
641 }
642
643 switch (number_of_addresses_valid) {
644 case 0:
645 ecu_address = G_MAXUINT32;
646 break;
647 case 1:
648 proto_item_append_text(ti, ", Address: 0x%04x", source_address);
649 break;
650 case 2:
651 proto_item_append_text(ti, ", Source: 0x%04x, Target: 0x%04x", source_address, target_address);
652 break;
653 }
654
655 switch (service) {
656 case UDS_SERVICES_DSC:
657 subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_dsc, NULL, service_name);
658 proto_tree_add_item_ret_uint(subtree, hf_uds_dsc_type, tvb, UDS_DSC_TYPE_OFFSET, UDS_DSC_TYPE_LEN,
659 ENC_BIG_ENDIAN, &enum_val);
660 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(enum_val, uds_dsc_types, "Unknown (0x%02x)"));
661
662 if (sid & UDS_REPLY_MASK) {
663 guint32 parameter_record_length = data_length - UDS_DSC_PARAMETER_RECORD_OFFSET;
664 proto_tree_add_item(subtree, hf_uds_dsc_parameter_record, tvb,
665 UDS_DSC_PARAMETER_RECORD_OFFSET, parameter_record_length, ENC_NA);
666 col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
667 tvb_bytes_to_str_punct(pinfo->pool, tvb, UDS_DSC_PARAMETER_RECORD_OFFSET,
668 parameter_record_length, ' '));
669 }
670 break;
671
672 case UDS_SERVICES_ER:
673 subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_er, NULL, service_name);
674 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);
675 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(enum_val, uds_er_types, "Unknown (0x%02x)"));
676 break;
677
678 case UDS_SERVICES_RDTCI: {
679 guint32 record_length = data_length - UDS_RDTCI_RECORD_OFFSET;
680
681 subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_rdtci, NULL, service_name);
682 proto_tree_add_item_ret_uint(subtree, hf_uds_rdtci_type, tvb, UDS_RDTCI_TYPE_OFFSET,
683 UDS_RDTCI_TYPE_LEN, ENC_BIG_ENDIAN, &enum_val);
684 proto_tree_add_item(subtree, hf_uds_rdtci_record, tvb,
685 UDS_RDTCI_RECORD_OFFSET, record_length, ENC_NA);
686 col_append_fstr(pinfo->cinfo, COL_INFO, " %s %s", val_to_str(enum_val, uds_rdtci_types, "Unknown (0x%02x)"),
687 tvb_bytes_to_str_punct(pinfo->pool, tvb, UDS_RDTCI_RECORD_OFFSET, record_length, ' '));
688 break;
689 }
690 case UDS_SERVICES_RDBI:
691 subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_rdbi, NULL, service_name);
692 if (sid & UDS_REPLY_MASK) {
693 /* Can't know the size of the data for each identifier, Decode like if there is only one idenfifier */
694 guint32 record_length = data_length - UDS_RDBI_DATA_RECORD_OFFSET;
695 guint32 data_identifier;
696 ti = proto_tree_add_item_ret_uint(subtree, hf_uds_rdbi_data_identifier, tvb,
697 UDS_RDBI_DATA_IDENTIFIER_OFFSET, UDS_RDBI_DATA_IDENTIFIER_LEN,
698 ENC_BIG_ENDIAN, &data_identifier);
699 protoitem_append_data_name(ti, ecu_address, (guint16)data_identifier);
700
701 proto_tree_add_item(subtree, hf_uds_rdbi_data_record, tvb, UDS_RDBI_DATA_RECORD_OFFSET,
702 record_length, ENC_NA);
703 col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x", data_identifier);
704 infocol_append_data_name(pinfo, ecu_address, data_identifier);
705 col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
706 tvb_bytes_to_str_punct(pinfo->pool, tvb, UDS_RDBI_DATA_RECORD_OFFSET,
707 record_length, ' '));
708 } else {
709 guint32 identifier_length = data_length - UDS_RDBI_DATA_IDENTIFIER_OFFSET;
710 guint32 offset = UDS_RDBI_DATA_IDENTIFIER_OFFSET;
711 while (identifier_length > 0) {
712 guint32 data_identifier;
713 ti = proto_tree_add_item_ret_uint(subtree, hf_uds_rdbi_data_identifier, tvb, offset,
714 UDS_RDBI_DATA_IDENTIFIER_LEN, ENC_BIG_ENDIAN, &data_identifier);
715 protoitem_append_data_name(ti, ecu_address, (guint16)data_identifier);
716
717 col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x", data_identifier);
718 infocol_append_data_name(pinfo, ecu_address, data_identifier);
719 offset += UDS_RDBI_DATA_IDENTIFIER_LEN;
720 identifier_length -= UDS_RDBI_DATA_IDENTIFIER_LEN;
721 }
722 }
723 break;
724
725 case UDS_SERVICES_SA:
726 subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_sa, NULL, service_name);
727 proto_tree_add_item_ret_uint(subtree, hf_uds_sa_type, tvb, UDS_SA_TYPE_OFFSET,
728 UDS_SA_TYPE_LEN, ENC_BIG_ENDIAN, &enum_val);
729 col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
730 val_to_str(enum_val, uds_sa_types, "Unknown (0x%02x)"));
731
732 if (sid & UDS_REPLY_MASK) {
733 guint32 seed_length = data_length - UDS_SA_SEED_OFFSET;
734 if (seed_length > 0) {
735 proto_tree_add_item(subtree, hf_uds_sa_seed, tvb, UDS_SA_SEED_OFFSET, seed_length, ENC_NA);
736 col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
737 tvb_bytes_to_str_punct(pinfo->pool, tvb, UDS_SA_SEED_OFFSET, seed_length,
738 ' '));
739 }
740 } else {
741 guint32 key_length = data_length - UDS_SA_KEY_OFFSET;
742 if (key_length > 0) {
743 proto_tree_add_item(subtree, hf_uds_sa_key, tvb, UDS_SA_KEY_OFFSET, key_length, ENC_NA);
744 col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
745 tvb_bytes_to_str_punct(pinfo->pool, tvb, UDS_SA_KEY_OFFSET, key_length,
746 ' '));
747 }
748 }
749 break;
750
751 case UDS_SERVICES_WDBI:
752 subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_wdbi, NULL, service_name);
753 ti = proto_tree_add_item_ret_uint(subtree, hf_uds_wdbi_data_identifier, tvb,
754 UDS_WDBI_DATA_IDENTIFIER_OFFSET, UDS_WDBI_DATA_IDENTIFIER_LEN,
755 ENC_BIG_ENDIAN, &enum_val);
756 protoitem_append_data_name(ti, ecu_address, (guint16)enum_val);
757 if (sid & UDS_REPLY_MASK) {
758 col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x", enum_val);
759 infocol_append_data_name(pinfo, ecu_address, enum_val);
760 } else {
761 guint32 record_length = data_length - UDS_WDBI_DATA_RECORD_OFFSET;
762 proto_tree_add_item(subtree, hf_uds_wdbi_data_record, tvb, UDS_WDBI_DATA_RECORD_OFFSET,
763 record_length, ENC_NA);
764 col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x", enum_val);
765 infocol_append_data_name(pinfo, ecu_address, enum_val);
766 col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
767 tvb_bytes_to_str_punct(pinfo->pool, tvb, UDS_WDBI_DATA_RECORD_OFFSET,
768 record_length, ' '));
769 }
770 break;
771
772 case UDS_SERVICES_IOCBI: {
773 guint32 data_identifier;
774 guint32 state_length = data_length - UDS_IOCBI_STATE_OFFSET;
775
776 subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_iocbi, NULL, service_name);
777 ti = proto_tree_add_item_ret_uint(subtree, hf_uds_iocbi_data_identifier, tvb,
778 UDS_IOCBI_DATA_IDENTIFIER_OFFSET, UDS_IOCBI_DATA_IDENTIFIER_LEN,
779 ENC_BIG_ENDIAN, &data_identifier);
780 protoitem_append_data_name(ti, ecu_address, (guint16)data_identifier);
781
782 proto_tree_add_item_ret_uint(subtree, hf_uds_iocbi_parameter, tvb, UDS_IOCBI_PARAMETER_OFFSET,
783 UDS_IOCBI_PARAMETER_LEN, ENC_BIG_ENDIAN, &enum_val);
784
785 proto_tree_add_item(subtree, hf_uds_iocbi_state, tvb, UDS_IOCBI_STATE_OFFSET,
786 state_length, ENC_NA);
787 col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x", data_identifier);
788 infocol_append_data_name(pinfo, ecu_address, data_identifier);
789 col_append_fstr(pinfo->cinfo, COL_INFO, " %s %s",
790 val_to_str(enum_val, uds_iocbi_parameters, "Unknown (0x%02x)"),
791 tvb_bytes_to_str_punct(pinfo->pool, tvb, UDS_IOCBI_STATE_OFFSET,
792 state_length, ' '));
793 break;
794 }
795 case UDS_SERVICES_RC: {
796 guint32 identifier;
797
798 subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_rc, NULL, service_name);
799 proto_tree_add_item_ret_uint(subtree, hf_uds_rc_type, tvb, UDS_RC_TYPE_OFFSET,
800 UDS_RC_TYPE_LEN, ENC_BIG_ENDIAN, &enum_val);
801
802 ti = proto_tree_add_item_ret_uint(subtree, hf_uds_rc_identifier, tvb, UDS_RC_ROUTINE_OFFSET,
803 UDS_RC_ROUTINE_LEN, ENC_BIG_ENDIAN, &identifier);
804 protoitem_append_routine_name(ti, ecu_address, identifier);
805
806 col_append_fstr(pinfo->cinfo, COL_INFO, " %s 0x%04x",
807 val_to_str(enum_val, uds_rc_types, "Unknown (0x%02x)"), identifier);
808 infocol_append_routine_name(pinfo, ecu_address, identifier);
809 if (sid & UDS_REPLY_MASK) {
810 guint32 rc_data_len = data_length - UDS_RC_INFO_OFFSET;
811 if (rc_data_len > 0) {
812 guint8 info = tvb_get_guint8(tvb, UDS_RC_INFO_OFFSET);
813 proto_tree_add_item(subtree, hf_uds_rc_info, tvb,
814 UDS_RC_INFO_OFFSET, UDS_RC_INFO_LEN, ENC_BIG_ENDIAN);
815 col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%x", info);
816 if (rc_data_len > 1) {
817 guint32 status_record_len = data_length - UDS_RC_STATUS_RECORD_OFFSET;
818 proto_tree_add_item(subtree, hf_uds_rc_status_record, tvb,
819 UDS_RC_STATUS_RECORD_OFFSET, status_record_len, ENC_NA);
820 col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
821 tvb_bytes_to_str_punct(pinfo->pool, tvb,
822 UDS_RC_STATUS_RECORD_OFFSET, status_record_len, ' '));
823 }
824 }
825 } else {
826 guint32 option_record_len = data_length - UDS_RC_OPTION_RECORD_OFFSET;
827 if (option_record_len > 0) {
828 proto_tree_add_item(subtree, hf_uds_rc_option_record, tvb,
829 UDS_RC_OPTION_RECORD_OFFSET, option_record_len, ENC_NA);
830 col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
831 tvb_bytes_to_str_punct(pinfo->pool, tvb,
832 UDS_RC_OPTION_RECORD_OFFSET, option_record_len, ' '));
833 }
834 }
835 break;
836 }
837 case UDS_SERVICES_RD:
838 subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_rd, NULL, service_name);
839 if (sid & UDS_REPLY_MASK) {
840 guint8 length_format_identifier, max_number_of_block_length_length;
841 guint64 max_number_of_block_length;
842
843 length_format_identifier = tvb_get_guint8(tvb, UDS_RD_LENGTH_FORMAT_IDENTIFIER_OFFSET);
844 max_number_of_block_length_length = masked_guint8_value(length_format_identifier,
845 UDS_RD_MAX_NUMBER_OF_BLOCK_LENGTH_LENGTH_MASK);
846 proto_tree_add_item(subtree, hf_uds_rd_max_number_of_block_length_length, tvb,
847 UDS_RD_LENGTH_FORMAT_IDENTIFIER_OFFSET,
848 UDS_RD_LENGTH_FORMAT_IDENTIFIER_LEN, ENC_BIG_ENDIAN);
849
850 max_number_of_block_length = tvb_get_guintX(tvb, UDS_RD_MAX_NUMBER_OF_BLOCK_LENGTH_OFFSET,
851 max_number_of_block_length_length, ENC_BIG_ENDIAN);
852 proto_tree_add_item(subtree, hf_uds_rd_max_number_of_block_length, tvb,
853 UDS_RD_MAX_NUMBER_OF_BLOCK_LENGTH_OFFSET,
854 max_number_of_block_length_length, ENC_BIG_ENDIAN);
855
856 col_append_fstr(pinfo->cinfo, COL_INFO, " Max Number Of Block Length 0x%" G_GINT64_MODIFIER "x",
857 max_number_of_block_length);
858 } else {
859 guint8 data_format_identifier, compression, encryting;
860 guint8 address_and_length_format_idenfifier, memory_size_length, memory_address_length;
861 guint64 memory_size, memory_address;
862
863 data_format_identifier = tvb_get_guint8(tvb, UDS_RD_DATA_FORMAT_IDENTIFIER_OFFSET);
864
865 compression = masked_guint8_value(data_format_identifier, UDS_RD_COMPRESSION_METHOD_MASK);
866 proto_tree_add_item(subtree, hf_uds_rd_compression_method, tvb,
867 UDS_RD_DATA_FORMAT_IDENTIFIER_OFFSET,
868 UDS_RD_DATA_FORMAT_IDENTIFIER_LEN, ENC_BIG_ENDIAN);
869
870 encryting = masked_guint8_value(data_format_identifier, UDS_RD_ENCRYPTING_METHOD_MASK);
871 proto_tree_add_item(subtree, hf_uds_rd_encrypting_method, tvb, UDS_RD_DATA_FORMAT_IDENTIFIER_OFFSET,
872 UDS_RD_DATA_FORMAT_IDENTIFIER_LEN, ENC_BIG_ENDIAN);
873
874 address_and_length_format_idenfifier = tvb_get_guint8(tvb, UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_OFFSET);
875
876 memory_size_length = masked_guint8_value(address_and_length_format_idenfifier,
877 UDS_RD_COMPRESSION_METHOD_MASK);
878 proto_tree_add_item(subtree, hf_uds_rd_memory_size_length, tvb,
879 UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_OFFSET,
880 UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_LEN, ENC_BIG_ENDIAN);
881
882 memory_address_length = masked_guint8_value(address_and_length_format_idenfifier,
883 UDS_RD_ENCRYPTING_METHOD_MASK);
884 proto_tree_add_item(subtree, hf_uds_rd_memory_address_length, tvb,
885 UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_OFFSET,
886 UDS_RD_ADDRESS_AND_LENGTH_FORMAT_IDENTIFIER_LEN, ENC_BIG_ENDIAN);
887
888 memory_address = tvb_get_guintX(tvb, UDS_RD_MEMORY_ADDRESS_OFFSET, memory_address_length,
889 ENC_BIG_ENDIAN);
890 proto_tree_add_item(subtree, hf_uds_rd_memory_address, tvb, UDS_RD_MEMORY_ADDRESS_OFFSET,
891 memory_address_length, ENC_BIG_ENDIAN);
892 memory_size = tvb_get_guintX(tvb, UDS_RD_MEMORY_ADDRESS_OFFSET + memory_address_length,
893 memory_size_length, ENC_BIG_ENDIAN);
894 proto_tree_add_item(subtree, hf_uds_rd_memory_size, tvb,
895 UDS_RD_MEMORY_ADDRESS_OFFSET + memory_address_length,
896 memory_size_length, ENC_BIG_ENDIAN);
897
898 col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%" G_GINT64_MODIFIER "x bytes at 0x%" G_GINT64_MODIFIER "x", memory_size, memory_address);
899
900 col_append_fstr(pinfo->cinfo, COL_INFO, " (Compression:0x%x Encrypting:0x%x)", compression,
901 encryting);
902 }
903 break;
904
905 case UDS_SERVICES_TD: {
906 guint32 sequence_no;
907 subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_td, NULL, service_name);
908
909 proto_tree_add_item_ret_uint(subtree, hf_uds_td_sequence_counter, tvb,
910 UDS_TD_SEQUENCE_COUNTER_OFFSET, UDS_TD_SEQUENCE_COUNTER_LEN, ENC_NA, &sequence_no);
911 col_append_fstr(pinfo->cinfo, COL_INFO, " Block Sequence Counter %d", sequence_no);
912 break;
913 }
914 case UDS_SERVICES_TP: {
915 guint8 sub_function_a, sub_function;
916 subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_tp, NULL, service_name);
917
918 sub_function_a = tvb_get_guint8(tvb, UDS_TP_SUB_FUNCTION_OFFSET);
919 sub_function = masked_guint8_value(sub_function_a, UDS_TP_SUB_FUNCTION_MASK);
920 proto_tree_add_item(subtree, hf_uds_tp_sub_function, tvb,
921 UDS_TP_SUB_FUNCTION_OFFSET, UDS_TP_SUB_FUNCTION_LEN, ENC_BIG_ENDIAN);
922
923 col_append_fstr(pinfo->cinfo, COL_INFO, " Sub-function %x", sub_function);
924
925 if (!(sid & UDS_REPLY_MASK)) {
926 guint8 suppress = masked_guint8_value(sub_function_a, UDS_TP_SUPPRESS_POS_RSP_MSG_INDIFICATION_MASK);
927
928 proto_tree_add_item(subtree, hf_uds_tp_suppress_pos_rsp_msg_indification, tvb,
929 UDS_TP_SUB_FUNCTION_OFFSET, UDS_TP_SUB_FUNCTION_LEN, ENC_BIG_ENDIAN);
930
931 if (suppress) {
932 col_append_fstr(pinfo->cinfo, COL_INFO, " (Reply suppressed)");
933 }
934 }
935 break;
936 }
937 case UDS_SERVICES_ERR: {
938 subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_err, NULL, service_name);
939
940 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);
941 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(enum_val, uds_services, "Unknown (0x%02x)"));
942 proto_tree_add_item_ret_uint(subtree, hf_uds_err_code, tvb, UDS_ERR_CODE_OFFSET, UDS_ERR_CODE_LEN,
943 ENC_BIG_ENDIAN, &enum_val);
944 col_append_fstr(pinfo->cinfo, COL_INFO, " (SID: %s)", val_to_str(enum_val, uds_response_codes, "Unknown (0x%02x)"));
945 break;
946 }
947 case UDS_SERVICES_CDTCS: {
948 subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_cdtcs, NULL, service_name);
949 proto_tree_add_item_ret_uint(subtree, hf_uds_cdtcs_type, tvb,
950 UDS_CDTCS_TYPE_OFFSET, UDS_CDTCS_TYPE_LEN, ENC_BIG_ENDIAN, &enum_val);
951 col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
952 val_to_str(enum_val, uds_cdtcs_types, "Unknown (0x%02x)"));
953 break;
954 }
955 }
956
957 return tvb_captured_length(tvb);
958 }
959
960 static int
dissect_uds_no_data(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree _U_,void * data _U_)961 dissect_uds_no_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void *data _U_) {
962 return dissect_uds_internal(tvb, pinfo, tree, 0, 0, 0);
963 }
964
965 static int
dissect_uds_doip(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree _U_,void * data)966 dissect_uds_doip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void *data) {
967 DISSECTOR_ASSERT(data);
968
969 doip_info_t *doip_info = (doip_info_t *)data;
970 return dissect_uds_internal(tvb, pinfo, tree, doip_info->source_address, doip_info->target_address, 2);
971 }
972
973 static int
dissect_uds_iso15765(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree _U_,void * data)974 dissect_uds_iso15765(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void *data) {
975 DISSECTOR_ASSERT(data);
976
977 iso15765_info_t *info = (iso15765_info_t *)data;
978 return dissect_uds_internal(tvb, pinfo, tree, info->source_address, info->target_address, info->number_of_addresses_valid);
979 }
980
981 static int
dissect_uds_iso10681(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree _U_,void * data)982 dissect_uds_iso10681(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void *data) {
983 DISSECTOR_ASSERT(data);
984
985 iso10681_info_t *info = (iso10681_info_t *)data;
986 return dissect_uds_internal(tvb, pinfo, tree, info->source_address, info->target_address, 2);
987 }
988
989 static void
pref_update_uds(void)990 pref_update_uds(void) {
991 if (uds_ht_routine_ids && uds_uat_routine_id_num == 0) {
992 g_hash_table_destroy(uds_ht_routine_ids);
993 uds_ht_routine_ids = NULL;
994 }
995
996 if (uds_ht_data_ids && uds_uat_data_id_num == 0) {
997 g_hash_table_destroy(uds_ht_data_ids);
998 uds_ht_data_ids = NULL;
999 }
1000 }
1001
1002 void
proto_register_uds(void)1003 proto_register_uds(void)
1004 {
1005 module_t* uds_module;
1006 static hf_register_info hf[] = {
1007 {
1008 &hf_uds_service,
1009 {
1010 "Service Identifier", "uds.sid",
1011 FT_UINT8, BASE_HEX,
1012 VALS(uds_services), UDS_SID_MASK,
1013 NULL, HFILL
1014 }
1015 },
1016 {
1017 &hf_uds_reply,
1018 {
1019 "Reply Flag", "uds.reply",
1020 FT_UINT8, BASE_HEX,
1021 NULL, UDS_REPLY_MASK,
1022 NULL, HFILL
1023 }
1024 },
1025
1026
1027 {
1028 &hf_uds_dsc_type,
1029 {
1030 "Type", "uds.dsc.type",
1031 FT_UINT8, BASE_HEX,
1032 VALS(uds_dsc_types), 0x0,
1033 NULL, HFILL
1034 }
1035 },
1036 {
1037 &hf_uds_dsc_parameter_record,
1038 {
1039 "Parameter Record", "uds.dsc.parameter_record",
1040 FT_BYTES, BASE_NONE,
1041 NULL, 0x0,
1042 NULL, HFILL
1043 }
1044 },
1045
1046 {
1047 &hf_uds_er_type,
1048 {
1049 "Type", "uds.er.type",
1050 FT_UINT8, BASE_HEX,
1051 VALS(uds_er_types), 0x0,
1052 NULL, HFILL
1053 }
1054 },
1055
1056
1057 {
1058 &hf_uds_rdtci_type,
1059 {
1060 "Type", "uds.rdtci.type",
1061 FT_UINT8, BASE_HEX,
1062 VALS(uds_rdtci_types), 0x0,
1063 NULL, HFILL
1064 }
1065 },
1066 {
1067 &hf_uds_rdtci_record,
1068 {
1069 "Record", "uds.rdtci.record",
1070 FT_BYTES, BASE_NONE,
1071 NULL, 0x0,
1072 NULL, HFILL
1073 }
1074 },
1075
1076
1077 {
1078 &hf_uds_rdbi_data_identifier,
1079 {
1080 "Data Identifier", "uds.rdbi.data_identifier",
1081 FT_UINT16, BASE_HEX,
1082 NULL, 0x0,
1083 NULL, HFILL
1084 }
1085 },
1086 {
1087 &hf_uds_rdbi_data_record,
1088 {
1089 "Data Record", "uds.rdbi.data_record",
1090 FT_BYTES, BASE_NONE,
1091 NULL, 0x0,
1092 NULL, HFILL
1093 }
1094 },
1095
1096
1097 {
1098 &hf_uds_sa_type,
1099 {
1100 "Type", "uds.sa.type",
1101 FT_UINT8, BASE_HEX,
1102 NULL, 0x0,
1103 NULL, HFILL
1104 }
1105 },
1106 {
1107 &hf_uds_sa_key,
1108 {
1109 "Key", "uds.sa.key",
1110 FT_BYTES, BASE_NONE,
1111 NULL, 0x0,
1112 NULL, HFILL
1113 }
1114 },
1115 {
1116 &hf_uds_sa_seed,
1117 {
1118 "Seed", "uds.sa.seed",
1119 FT_BYTES, BASE_NONE,
1120 NULL, 0x0,
1121 NULL, HFILL
1122 }
1123 },
1124
1125
1126 {
1127 &hf_uds_wdbi_data_identifier,
1128 {
1129 "Data Identifier", "uds.wdbi.data_identifier",
1130 FT_UINT8, BASE_HEX,
1131 NULL, 0x0,
1132 NULL, HFILL
1133 }
1134 },
1135 {
1136 &hf_uds_wdbi_data_record,
1137 {
1138 "Data Record", "uds.wdbi.data_record",
1139 FT_BYTES, BASE_NONE,
1140 NULL, 0x0,
1141 NULL, HFILL
1142 }
1143 },
1144
1145 {
1146 &hf_uds_iocbi_data_identifier,
1147 {
1148 "Data Identifier", "uds.iocbi.data_identifier",
1149 FT_UINT8, BASE_HEX,
1150 NULL, 0x0,
1151 NULL, HFILL
1152 }
1153 },
1154 {
1155 &hf_uds_iocbi_parameter,
1156 {
1157 "Parameter", "uds.iocbi.parameter",
1158 FT_UINT8, BASE_HEX,
1159 VALS(uds_iocbi_parameters), 0x0,
1160 NULL, HFILL
1161 }
1162 },
1163 {
1164 &hf_uds_iocbi_state,
1165 {
1166 "State", "uds.iocbi.state",
1167 FT_BYTES, BASE_NONE,
1168 NULL, 0x0,
1169 NULL, HFILL
1170 }
1171 },
1172
1173 {
1174 &hf_uds_rc_type,
1175 {
1176 "Type", "uds.rc.type",
1177 FT_UINT8, BASE_HEX,
1178 VALS(uds_rc_types), 0x0,
1179 NULL, HFILL
1180 }
1181 },
1182 {
1183 &hf_uds_rc_identifier,
1184 {
1185 "Identifier", "uds.rc.identifier",
1186 FT_UINT16, BASE_HEX,
1187 NULL, 0x0,
1188 NULL, HFILL
1189 }
1190 },
1191 {
1192 &hf_uds_rc_option_record,
1193 {
1194 "Option record", "uds.rc.option_record",
1195 FT_BYTES, BASE_NONE,
1196 NULL, 0x0,
1197 NULL, HFILL
1198 }
1199 },
1200 {
1201 &hf_uds_rc_info,
1202 {
1203 "Info", "uds.rc.info",
1204 FT_UINT8, BASE_HEX,
1205 NULL, 0x0,
1206 NULL, HFILL
1207 }
1208 },
1209 {
1210 &hf_uds_rc_status_record,
1211 {
1212 "Status Record", "uds.rc.status_record",
1213 FT_BYTES, BASE_NONE,
1214 NULL, 0x0,
1215 NULL, HFILL
1216 }
1217 },
1218
1219 {
1220 &hf_uds_rd_compression_method,
1221 {
1222 "Compression Method", "uds.rd.compression_method",
1223 FT_UINT8, BASE_HEX,
1224 NULL, UDS_RD_COMPRESSION_METHOD_MASK,
1225 NULL, HFILL
1226 }
1227 },
1228 {
1229 &hf_uds_rd_encrypting_method,
1230 {
1231 "Encrypting Method", "uds.rd.encrypting_method",
1232 FT_UINT8, BASE_HEX,
1233 NULL, UDS_RD_ENCRYPTING_METHOD_MASK,
1234 NULL, HFILL
1235 }
1236 },
1237 {
1238 &hf_uds_rd_memory_size_length,
1239 {
1240 "Memory size length", "uds.rd.memory_size_length",
1241 FT_UINT8, BASE_HEX,
1242 NULL, UDS_RD_MEMORY_SIZE_LENGTH_MASK,
1243 NULL, HFILL
1244 }
1245 },
1246 {
1247 &hf_uds_rd_memory_address_length,
1248 {
1249 "Memory address length", "uds.rd.memory_address_length",
1250 FT_UINT8, BASE_HEX,
1251 NULL, UDS_RD_MEMORY_ADDRESS_LENGTH_MASK,
1252 NULL, HFILL
1253 }
1254 },
1255 {
1256 &hf_uds_rd_memory_address,
1257 {
1258 "Memory Address", "uds.rd.memory_address",
1259 FT_UINT64, BASE_HEX,
1260 NULL, 0x0,
1261 NULL, HFILL
1262 }
1263 },
1264 {
1265 &hf_uds_rd_memory_size,
1266 {
1267 "Memory Size", "uds.rd.memory_size",
1268 FT_UINT64, BASE_HEX,
1269 NULL, 0x0,
1270 NULL, HFILL
1271 }
1272 },
1273 {
1274 &hf_uds_rd_max_number_of_block_length_length,
1275 {
1276 "Memory address length", "uds.rd.max_number_of_block_length_length",
1277 FT_UINT8, BASE_HEX,
1278 NULL, UDS_RD_MAX_NUMBER_OF_BLOCK_LENGTH_LENGTH_MASK,
1279 NULL, HFILL
1280 }
1281 },
1282 {
1283 &hf_uds_rd_max_number_of_block_length,
1284 {
1285 "Memory Size", "uds.rd.max_number_of_block_length",
1286 FT_UINT64, BASE_HEX,
1287 NULL, 0x0,
1288 NULL, HFILL
1289 }
1290 },
1291
1292
1293 {
1294 &hf_uds_td_sequence_counter,
1295 {
1296 "Block Sequence Counter", "uds.td.block_sequence_counter",
1297 FT_UINT8, BASE_DEC,
1298 NULL, 0x0,
1299 NULL, HFILL
1300 }
1301 },
1302
1303 {
1304 &hf_uds_tp_sub_function,
1305 {
1306 "Suppress reply", "uds.tp.suppress_reply",
1307 FT_UINT8, BASE_HEX,
1308 NULL, UDS_TP_SUB_FUNCTION_MASK,
1309 NULL, HFILL
1310 }
1311 },
1312 {
1313 &hf_uds_tp_suppress_pos_rsp_msg_indification,
1314 {
1315 "Suppress reply", "uds.tp.suppress_reply.indification",
1316 FT_BOOLEAN, 8,
1317 NULL, UDS_TP_SUPPRESS_POS_RSP_MSG_INDIFICATION_MASK,
1318 NULL, HFILL
1319 }
1320 },
1321
1322 {
1323 &hf_uds_err_sid,
1324 {
1325 "Service Identifier", "uds.err.sid",
1326 FT_UINT8, BASE_HEX,
1327 VALS(uds_services), 0x0,
1328 NULL, HFILL
1329 }
1330 },
1331 {
1332 &hf_uds_err_code,
1333 {
1334 "Code", "uds.err.code",
1335 FT_UINT8, BASE_HEX,
1336 VALS(uds_response_codes), 0x0,
1337 NULL, HFILL
1338 }
1339 },
1340
1341 {
1342 &hf_uds_cdtcs_type,
1343 {
1344 "Type", "uds.cdtcs.type",
1345 FT_UINT8, BASE_HEX,
1346 VALS(uds_cdtcs_types), 0x0,
1347 NULL, HFILL
1348 }
1349 },
1350 };
1351
1352 uat_t* uds_routine_ids_uat;
1353 uat_t* uds_data_ids_uat;
1354
1355 /* Setup protocol subtree array */
1356 static gint *ett[] =
1357 {
1358 &ett_uds,
1359 &ett_uds_dsc,
1360 &ett_uds_er,
1361 &ett_uds_rdtci,
1362 &ett_uds_rdbi,
1363 &ett_uds_sa,
1364 &ett_uds_wdbi,
1365 &ett_uds_iocbi,
1366 &ett_uds_rc,
1367 &ett_uds_rd,
1368 &ett_uds_td,
1369 &ett_uds_tp,
1370 &ett_uds_err,
1371 &ett_uds_cdtcs,
1372 };
1373
1374 proto_uds = proto_register_protocol (
1375 "Unified Diagnostic Services", /* name */
1376 "UDS", /* short name */
1377 "uds" /* abbrev */
1378 );
1379
1380 proto_register_field_array(proto_uds, hf, array_length(hf));
1381 proto_register_subtree_array(ett, array_length(ett));
1382
1383 uds_handle = register_dissector("uds", dissect_uds_no_data, proto_uds);
1384 uds_handle_doip = register_dissector("uds_over_doip", dissect_uds_doip, proto_uds);
1385 uds_handle_iso10681 = register_dissector("uds_over_iso10681", dissect_uds_iso10681, proto_uds);
1386 uds_handle_iso15765 = register_dissector("uds_over_iso15765", dissect_uds_iso15765, proto_uds);
1387
1388 /* Register preferences */
1389 uds_module = prefs_register_protocol(proto_uds, &pref_update_uds);
1390
1391 /* UATs for user_data fields */
1392 static uat_field_t uds_routine_id_uat_fields[] = {
1393 UAT_FLD_HEX(uds_uat_routine_ids, address, "Address", "Address (16bit hex without leading 0x, 0xffffffff for 'any')"),
1394 UAT_FLD_HEX(uds_uat_routine_ids, id, "Routine ID", "Routine Identifier (16bit hex without leading 0x)"),
1395 UAT_FLD_CSTRING(uds_uat_routine_ids, name, "Routine Name", "Name of the Routine ID (string)"),
1396 UAT_END_FIELDS
1397 };
1398
1399 /* UATs */
1400 uds_routine_ids_uat = uat_new("UDS Routine Identifier List",
1401 sizeof(generic_addr_id_string_t), /* record size */
1402 DATAFILE_UDS_ROUTINE_IDS, /* filename */
1403 TRUE, /* from profile */
1404 (void**)&uds_uat_routine_ids, /* data_ptr */
1405 &uds_uat_routine_id_num, /* numitems_ptr */
1406 UAT_AFFECTS_DISSECTION, /* but not fields */
1407 NULL, /* help */
1408 copy_generic_one_id_string_cb, /* copy callback */
1409 update_generic_addr_id_16bit, /* update callback */
1410 free_generic_one_id_string_cb, /* free callback */
1411 post_update_uds_routine_cb, /* post update callback */
1412 NULL, /* reset callback */
1413 uds_routine_id_uat_fields /* UAT field definitions */
1414 );
1415
1416 prefs_register_uat_preference(uds_module, "_uds_routine_id_list", "UDS Routine Identifier List",
1417 "A table to define names of UDS Routines", uds_routine_ids_uat);
1418
1419 static uat_field_t uds_data_id_uat_fields[] = {
1420 UAT_FLD_HEX(uds_uat_data_ids, address, "Address", "Address (16bit hex without leading 0x, 0xffffffff for 'any')"),
1421 UAT_FLD_HEX(uds_uat_data_ids, id, "Data ID", "Data Identifier (16bit hex without leading 0x)"),
1422 UAT_FLD_CSTRING(uds_uat_data_ids, name, "Data Name", "Name of the Data ID (string)"),
1423 UAT_END_FIELDS
1424 };
1425
1426 uds_data_ids_uat = uat_new("UDS Data Identifier List",
1427 sizeof(generic_addr_id_string_t), /* record size */
1428 DATAFILE_UDS_DATA_IDS, /* filename */
1429 TRUE, /* from profile */
1430 (void**)&uds_uat_data_ids, /* data_ptr */
1431 &uds_uat_data_id_num, /* numitems_ptr */
1432 UAT_AFFECTS_DISSECTION, /* but not fields */
1433 NULL, /* help */
1434 copy_generic_one_id_string_cb, /* copy callback */
1435 update_generic_addr_id_16bit, /* update callback */
1436 free_generic_one_id_string_cb, /* free callback */
1437 post_update_uds_data_cb, /* post update callback */
1438 NULL, /* reset callback */
1439 uds_data_id_uat_fields /* UAT field definitions */
1440 );
1441
1442 prefs_register_uat_preference(uds_module, "_uds_data_id_list", "UDS Data Identifier List",
1443 "A table to define names of UDS Data Identifier", uds_data_ids_uat);
1444 }
1445
1446 void
proto_reg_handoff_uds(void)1447 proto_reg_handoff_uds(void)
1448 {
1449 dissector_add_for_decode_as("iso10681.subdissector", uds_handle_iso10681);
1450 dissector_add_for_decode_as("iso15765.subdissector", uds_handle_iso15765);
1451 }
1452
1453 /*
1454 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1455 *
1456 * Local variables:
1457 * c-basic-offset: 4
1458 * tab-width: 8
1459 * indent-tabs-mode: nil
1460 * End:
1461 *
1462 * vi: set shiftwidth=4 tabstop=8 expandtab:
1463 * :indentSize=4:tabSize=8:noTabs=true:
1464 */
1465