Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-iso15765.c
blob5bbf078f203b83b742c9318efef9047da845ff4e
1 /* packet-iso15765.c
2 * Routines for iso15765 protocol packet disassembly
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
12 * CAN ID Mapping
14 * When using ISO15765 to transport UDS and others, the diagnostic addresses might be
15 * determined by mapping the underlaying CAN ID (29bit or 11bit).
17 * Option 1: Two Addresses can be determined (Source and Target Address.
18 * Option 2: One Address can be determined (ECU Address).
19 * Option 3: No Address can be determined.
21 * For Option 1 and 2 the ISO15765_can_id_mappings table can be used to determine the addresses:
22 * - Ext Addr determines, if the CAN ID is 29bit (true) or 11bit (false)
23 * - CAN ID and CAN ID Mask determined how to know if a CAN ID should be mapped
24 * - Source Addr Mask and Target Addr Mask show the bits used to determine the addresses of Option 1
25 * - ECU Addr Mask defines the bits for the address of Option 2
27 * Example:
28 * - ISO15765 is applicable to all 29bit CAN IDs 0x9988TTSS, with TT the target address and SS the source address.
29 * - Ext Addr: true
30 * - CAN ID: 0x99880000
31 * - CAN ID Mask: 0xffff0000
32 * - Target Addr Mask: 0x0000ff00
33 * - Source Addr Mask: 0x000000ff
35 * The addresses are passed via iso15765data_t to the next dissector (e.g., UDS).
39 * Support for FlexRay variant, see: https://www.autosar.org/fileadmin/standards/R20-11/CP/AUTOSAR_SWS_FlexRayARTransportLayer.pdf
42 #include "config.h"
44 #include <epan/packet.h>
45 #include <epan/prefs.h>
46 #include <epan/decode_as.h>
47 #include <epan/reassemble.h>
48 #include <epan/expert.h>
49 #include <epan/proto_data.h>
50 #include <epan/uat.h>
51 #include <wsutil/bits_ctz.h>
52 #include <wsutil/bits_count_ones.h>
53 #include <wiretap/wtap.h>
55 #include "packet-socketcan.h"
56 #include "packet-lin.h"
57 #include "packet-flexray.h"
58 #include "packet-iso15765.h"
59 #include "packet-autosar-ipdu-multiplexer.h"
60 #include "packet-pdu-transport.h"
62 void proto_register_iso15765(void);
63 void proto_reg_handoff_iso15765(void);
65 #define ISO15765_MESSAGE_TYPE_MASK 0xF0
66 #define ISO15765_MESSAGE_TYPES_SINGLE_FRAME 0
67 #define ISO15765_MESSAGE_TYPES_FIRST_FRAME 1
68 #define ISO15765_MESSAGE_TYPES_CONSECUTIVE_FRAME 2
69 #define ISO15765_MESSAGE_TYPES_FLOW_CONTROL 3
70 #define ISO15765_MESSAGE_TYPES_FR_SINGLE_FRAME_EXT 4
71 #define ISO15765_MESSAGE_TYPES_FR_FIRST_FRAME_EXT 5
72 #define ISO15765_MESSAGE_TYPES_FR_CONSECUTIVE_FRAME_2 6
73 #define ISO15765_MESSAGE_TYPES_FR_ACK_FRAME 7
75 #define ISO15765_MESSAGE_DATA_LENGTH_MASK 0x0F
76 #define ISO15765_MESSAGE_SEQUENCE_NUMBER_MASK 0x0F
77 #define ISO15765_MESSAGE_FLOW_STATUS_MASK 0x0F
79 #define ISO15765_MESSAGE_FIRST_FRAME_DATA_LENGTH_MASK 0x0FFF
81 #define ISO15765_MESSAGE_AUTOSAR_ACK_MASK 0xF0
82 #define ISO15765_AUTOSAR_ACK_OFFSET 3
84 #define ISO15765_ADDR_INVALID 0xffffffff
86 typedef struct iso15765_identifier {
87 uint32_t id;
88 uint32_t seq;
89 uint16_t frag_id;
90 bool last;
91 uint32_t bytes_used;
92 } iso15765_identifier_t;
94 typedef struct iso15765_frame {
95 uint32_t seq;
96 uint32_t last_byte_seen;
97 uint32_t len;
98 uint32_t bytes_in_cf;
99 bool error;
100 bool ff_seen;
101 uint16_t last_frag_id;
102 uint8_t frag_id_high[16];
103 } iso15765_frame_t;
105 typedef struct iso15765_seq_key {
106 uint32_t bus_type;
107 uint32_t frame_id;
108 uint32_t iface_id;
109 } iso15765_seq_key_t;
111 static unsigned
112 iso15765_seq_hash_func(const void *v) {
113 const iso15765_seq_key_t *key = (const iso15765_seq_key_t *)v;
114 return (key->frame_id ^ key->bus_type);
117 static int
118 iso15765_seq_equal_func(const void *v1, const void *v2) {
119 const iso15765_seq_key_t *key1 = (const iso15765_seq_key_t *)v1;
120 const iso15765_seq_key_t *key2 = (const iso15765_seq_key_t *)v2;
122 return (key1->bus_type == key2->bus_type &&
123 key1->frame_id == key2->frame_id &&
124 key1->iface_id == key2->iface_id);
127 static const value_string iso15765_message_types[] = {
128 {ISO15765_MESSAGE_TYPES_SINGLE_FRAME, "Single Frame"},
129 {ISO15765_MESSAGE_TYPES_FIRST_FRAME, "First Frame"},
130 {ISO15765_MESSAGE_TYPES_CONSECUTIVE_FRAME, "Consecutive Frame"},
131 {ISO15765_MESSAGE_TYPES_FLOW_CONTROL, "Flow control"},
132 {ISO15765_MESSAGE_TYPES_FR_SINGLE_FRAME_EXT, "Single Frame Ext"},
133 {ISO15765_MESSAGE_TYPES_FR_FIRST_FRAME_EXT, "First Frame Ext"},
134 {ISO15765_MESSAGE_TYPES_FR_CONSECUTIVE_FRAME_2, "Consecutive Frame 2"},
135 {ISO15765_MESSAGE_TYPES_FR_ACK_FRAME, "Ack Frame"},
136 {0, NULL}
139 static const value_string iso15765_flow_status_types[] = {
140 {0, "Continue to Send"},
141 {1, "Wait"},
142 {2, "Overflow"},
143 {0, NULL}
146 #define NORMAL_ADDRESSING 1
147 #define EXTENDED_ADDRESSING 2
149 #define ZERO_BYTE_ADDRESSING 0
150 #define ONE_BYTE_ADDRESSING 1
151 #define TWO_BYTE_ADDRESSING 2
153 static int addressing = NORMAL_ADDRESSING;
154 static int flexray_addressing = ONE_BYTE_ADDRESSING;
155 static unsigned flexray_segment_size_limit;
156 static unsigned window = 8;
157 static range_t *configured_can_ids;
158 static range_t *configured_ext_can_ids;
159 static bool register_lin_diag_frames = true;
160 static range_t *configured_ipdum_pdu_ids;
161 static int ipdum_addressing = ZERO_BYTE_ADDRESSING;
163 /* Encoding */
164 static const enum_val_t enum_addressing[] = {
165 {"normal", "Normal addressing", NORMAL_ADDRESSING},
166 {"extended", "Extended addressing", EXTENDED_ADDRESSING},
167 {NULL, NULL, 0}
170 /* Encoding */
171 static const enum_val_t enum_flexray_addressing[] = {
172 {"1", "1 byte addressing", ONE_BYTE_ADDRESSING},
173 {"2", "2 byte addressing", TWO_BYTE_ADDRESSING},
174 {NULL, NULL, 0}
177 static const enum_val_t enum_ipdum_addressing[] = {
178 {"0", "0 byte addressing", ZERO_BYTE_ADDRESSING},
179 {"1", "1 byte addressing", ONE_BYTE_ADDRESSING},
180 {"2", "2 byte addressing", TWO_BYTE_ADDRESSING},
181 {NULL, NULL, 0}
184 static int hf_iso15765_address;
185 static int hf_iso15765_target_address;
186 static int hf_iso15765_source_address;
187 static int hf_iso15765_message_type;
188 static int hf_iso15765_data_length_8bit;
189 static int hf_iso15765_data_length_4bit;
190 static int hf_iso15765_frame_length_32bit;
191 static int hf_iso15765_frame_length_12bit;
192 static int hf_iso15765_sequence_number;
193 static int hf_iso15765_flow_status;
194 static int hf_iso15765_segment_data;
195 static int hf_iso15765_padding;
197 static int hf_iso15765_fc_bs;
198 static int hf_iso15765_fc_stmin;
199 static int hf_iso15765_fc_stmin_in_us;
201 static int hf_iso15765_autosar_ack;
203 static int ett_iso15765;
205 static expert_field ei_iso15765_message_type_bad;
207 static int proto_iso15765;
208 static dissector_handle_t iso15765_handle_can;
209 static dissector_handle_t iso15765_handle_lin;
210 static dissector_handle_t iso15765_handle_flexray;
211 static dissector_handle_t iso15765_handle_ipdum;
212 static dissector_handle_t iso15765_handle_pdu_transport;
214 static dissector_table_t subdissector_table;
216 static reassembly_table iso15765_reassembly_table;
217 static wmem_map_t* iso15765_seq_table;
218 static wmem_map_t *iso15765_frame_table;
220 static int hf_iso15765_fragments;
221 static int hf_iso15765_fragment;
222 static int hf_iso15765_fragment_overlap;
223 static int hf_iso15765_fragment_overlap_conflicts;
224 static int hf_iso15765_fragment_multiple_tails;
225 static int hf_iso15765_fragment_too_long_fragment;
226 static int hf_iso15765_fragment_error;
227 static int hf_iso15765_fragment_count;
228 static int hf_iso15765_reassembled_in;
229 static int hf_iso15765_reassembled_length;
231 static int ett_iso15765_fragment;
232 static int ett_iso15765_fragments;
234 static const fragment_items iso15765_frag_items = {
235 /* Fragment subtrees */
236 &ett_iso15765_fragment,
237 &ett_iso15765_fragments,
238 /* Fragment fields */
239 &hf_iso15765_fragments,
240 &hf_iso15765_fragment,
241 &hf_iso15765_fragment_overlap,
242 &hf_iso15765_fragment_overlap_conflicts,
243 &hf_iso15765_fragment_multiple_tails,
244 &hf_iso15765_fragment_too_long_fragment,
245 &hf_iso15765_fragment_error,
246 &hf_iso15765_fragment_count,
247 /* Reassembled in field */
248 &hf_iso15765_reassembled_in,
249 /* Reassembled length field */
250 &hf_iso15765_reassembled_length,
251 /* Reassembled data field */
252 NULL,
253 "ISO15765 fragments"
256 /* UAT for address encoded into CAN IDs */
257 typedef struct config_can_addr_mapping {
258 bool extended_address;
259 uint32_t can_id;
260 uint32_t can_id_mask;
261 uint32_t source_addr_mask;
262 uint32_t target_addr_mask;
263 uint32_t ecu_addr_mask;
264 } config_can_addr_mapping_t;
266 static config_can_addr_mapping_t *config_can_addr_mappings;
267 static unsigned config_can_addr_mappings_num;
268 #define DATAFILE_CAN_ADDR_MAPPING "ISO15765_can_id_mappings"
270 UAT_BOOL_CB_DEF(config_can_addr_mappings, extended_address, config_can_addr_mapping_t)
271 UAT_HEX_CB_DEF(config_can_addr_mappings, can_id, config_can_addr_mapping_t)
272 UAT_HEX_CB_DEF(config_can_addr_mappings, can_id_mask, config_can_addr_mapping_t)
273 UAT_HEX_CB_DEF(config_can_addr_mappings, source_addr_mask, config_can_addr_mapping_t)
274 UAT_HEX_CB_DEF(config_can_addr_mappings, target_addr_mask, config_can_addr_mapping_t)
275 UAT_HEX_CB_DEF(config_can_addr_mappings, ecu_addr_mask, config_can_addr_mapping_t)
277 static void *
278 copy_config_can_addr_mapping_cb(void *n, const void *o, size_t size _U_) {
279 config_can_addr_mapping_t *new_rec = (config_can_addr_mapping_t *)n;
280 const config_can_addr_mapping_t *old_rec = (const config_can_addr_mapping_t *)o;
282 new_rec->extended_address = old_rec->extended_address;
283 new_rec->can_id = old_rec->can_id;
284 new_rec->can_id_mask = old_rec->can_id_mask;
285 new_rec->source_addr_mask = old_rec->source_addr_mask;
286 new_rec->target_addr_mask = old_rec->target_addr_mask;
287 new_rec->ecu_addr_mask = old_rec->ecu_addr_mask;
289 return new_rec;
292 static bool
293 update_config_can_addr_mappings(void *r, char **err) {
294 config_can_addr_mapping_t *rec = (config_can_addr_mapping_t *)r;
296 if (rec->source_addr_mask == 0 && rec->target_addr_mask == 0 && rec->ecu_addr_mask == 0) {
297 *err = ws_strdup_printf("You need to define the ECU Mask OR Source Mask/Target Mask!");
298 return false;
301 if ((rec->source_addr_mask != 0 || rec->target_addr_mask != 0) && rec->ecu_addr_mask != 0) {
302 *err = ws_strdup_printf("You can only use Source Address Mask/Target Address Mask OR ECU Address Mask! Not both at the same time!");
303 return false;
306 if ((rec->source_addr_mask == 0 || rec->target_addr_mask == 0) && rec->ecu_addr_mask == 0) {
307 *err = ws_strdup_printf("You can only use Source Address Mask and Target Address Mask in combination!");
308 return false;
311 if (rec->extended_address) {
312 if ((rec->source_addr_mask & ~CAN_EFF_MASK) != 0) {
313 *err = ws_strdup_printf("Source Address Mask covering bits not allowed for extended IDs (29bit)!");
314 return false;
316 if ((rec->target_addr_mask & ~CAN_EFF_MASK) != 0) {
317 *err = ws_strdup_printf("Target Address Mask covering bits not allowed for extended IDs (29bit)!");
318 return false;
320 if ((rec->ecu_addr_mask & ~CAN_EFF_MASK) != 0) {
321 *err = ws_strdup_printf("ECU Address Mask covering bits not allowed for extended IDs (29bit)!");
322 return false;
324 } else {
325 if ((rec->source_addr_mask & ~CAN_SFF_MASK) != 0) {
326 *err = ws_strdup_printf("Source Address Mask covering bits not allowed for standard IDs (11bit)!");
327 return false;
329 if ((rec->target_addr_mask & ~CAN_SFF_MASK) != 0) {
330 *err = ws_strdup_printf("Target Address Mask covering bits not allowed for standard IDs (11bit)!");
331 return false;
333 if ((rec->ecu_addr_mask & ~CAN_SFF_MASK) != 0) {
334 *err = ws_strdup_printf("ECU Address Mask covering bits not allowed for standard IDs (11bit)!");
335 return false;
339 return true;
342 static void
343 free_config_can_addr_mappings(void *r _U_) {
344 /* do nothing right now */
347 static void
348 post_update_config_can_addr_mappings_cb(void) {
349 /* do nothing right now */
352 static uint16_t
353 masked_uint16_value(const uint16_t value, const uint16_t mask) {
354 return (value & mask) >> ws_ctz(mask);
357 static uint32_t
358 masked_uint32_value(const uint32_t value, const uint32_t mask) {
359 return (value & mask) >> ws_ctz(mask);
363 * returning number of addresses (0:none, 1:ecu (both addr same), 2:source+target)
365 static uint8_t
366 find_config_can_addr_mapping(bool ext_id, uint32_t can_id, uint16_t *source_addr, uint16_t *target_addr, uint8_t *addr_len) {
367 config_can_addr_mapping_t *tmp = NULL;
368 uint32_t i;
370 if (source_addr == NULL || target_addr == NULL || config_can_addr_mappings == NULL) {
371 return 0;
374 for (i = 0; i < config_can_addr_mappings_num; i++) {
375 if (config_can_addr_mappings[i].extended_address == ext_id &&
376 (config_can_addr_mappings[i].can_id & config_can_addr_mappings[i].can_id_mask) ==
377 (can_id & config_can_addr_mappings[i].can_id_mask)) {
378 tmp = &(config_can_addr_mappings[i]);
379 break;
383 *addr_len = 0;
385 if (tmp != NULL) {
386 if (tmp->ecu_addr_mask != 0) {
387 *source_addr = masked_uint32_value(can_id, tmp->ecu_addr_mask);
388 *target_addr = *source_addr;
389 *addr_len = (7 + ws_count_ones(tmp->ecu_addr_mask)) / 8;
390 return 1;
392 if (tmp->source_addr_mask != 0 && tmp->target_addr_mask != 0) {
393 *source_addr = masked_uint32_value(can_id, tmp->source_addr_mask);
394 *target_addr = masked_uint32_value(can_id, tmp->target_addr_mask);
395 uint8_t tmp_len = ws_count_ones(tmp->source_addr_mask);
396 if (ws_count_ones(tmp->target_addr_mask) > tmp_len) {
397 tmp_len = ws_count_ones(tmp->target_addr_mask);
399 *addr_len = (7 + tmp_len) / 8;
400 return 2;
404 return 0;
408 /* UAT for PDU Transport config */
409 typedef struct config_pdu_tranport_config {
410 uint32_t pdu_id;
411 uint32_t source_address_size;
412 uint32_t source_address_fixed;
413 uint32_t target_address_size;
414 uint32_t target_address_fixed;
415 uint32_t ecu_address_size;
416 uint32_t ecu_address_fixed;
417 } config_pdu_transport_config_t;
419 static config_pdu_transport_config_t *config_pdu_transport_config_items;
420 static unsigned config_pdu_transport_config_items_num;
421 #define DATAFILE_PDU_TRANSPORT_CONFIG "ISO15765_pdu_transport_config"
423 UAT_HEX_CB_DEF(config_pdu_transport_config_items, pdu_id, config_pdu_transport_config_t)
424 UAT_DEC_CB_DEF(config_pdu_transport_config_items, source_address_size, config_pdu_transport_config_t)
425 UAT_HEX_CB_DEF(config_pdu_transport_config_items, source_address_fixed, config_pdu_transport_config_t)
426 UAT_DEC_CB_DEF(config_pdu_transport_config_items, target_address_size, config_pdu_transport_config_t)
427 UAT_HEX_CB_DEF(config_pdu_transport_config_items, target_address_fixed, config_pdu_transport_config_t)
428 UAT_DEC_CB_DEF(config_pdu_transport_config_items, ecu_address_size, config_pdu_transport_config_t)
429 UAT_HEX_CB_DEF(config_pdu_transport_config_items, ecu_address_fixed, config_pdu_transport_config_t)
432 static void *
433 copy_config_pdu_transport_config_cb(void *n, const void *o, size_t size _U_) {
434 config_pdu_transport_config_t *new_rec = (config_pdu_transport_config_t *)n;
435 const config_pdu_transport_config_t *old_rec = (const config_pdu_transport_config_t *)o;
437 new_rec->pdu_id = old_rec->pdu_id;
438 new_rec->source_address_size = old_rec->source_address_size;
439 new_rec->source_address_fixed = old_rec->source_address_fixed;
440 new_rec->target_address_size = old_rec->target_address_size;
441 new_rec->target_address_fixed = old_rec->target_address_fixed;
442 new_rec->ecu_address_size = old_rec->ecu_address_size;
443 new_rec->ecu_address_fixed = old_rec->ecu_address_fixed;
445 return new_rec;
448 static bool
449 update_config_pdu_transport_config_item(void *r, char **err) {
450 config_pdu_transport_config_t *rec = (config_pdu_transport_config_t *)r;
452 bool source_address_configured = rec->source_address_size != 0 || rec->source_address_fixed != ISO15765_ADDR_INVALID;
453 bool target_address_configured = rec->target_address_size != 0 || rec->target_address_fixed != ISO15765_ADDR_INVALID;
454 bool ecu_address_configured = rec->ecu_address_size != 0 || rec->ecu_address_fixed != ISO15765_ADDR_INVALID;
456 if (rec->source_address_size != 0 && rec->source_address_fixed != ISO15765_ADDR_INVALID) {
457 *err = ws_strdup_printf("You can either set the size of the source address or configure a fixed value!");
458 return false;
461 if (rec->target_address_size != 0 && rec->target_address_fixed != ISO15765_ADDR_INVALID) {
462 *err = ws_strdup_printf("You can either set the size of the target address or configure a fixed value!");
463 return false;
466 if (rec->ecu_address_size != 0 && rec->ecu_address_fixed != ISO15765_ADDR_INVALID) {
467 *err = ws_strdup_printf("You can either set the size of the ecu address or configure a fixed value!");
468 return false;
471 if (ecu_address_configured && (source_address_configured || target_address_configured)) {
472 *err = ws_strdup_printf("You cannot configure an ecu address and a source or target address at the same time!");
473 return false;
476 if ((source_address_configured && !target_address_configured) || (!source_address_configured && target_address_configured)) {
477 *err = ws_strdup_printf("You can only configure source and target address at the same time but not only one of them!");
478 return false;
481 return true;
484 static void
485 free_config_pdu_transport_config(void *r _U_) {
486 /* do nothing for now */
489 static void
490 reset_config_pdu_transport_config_cb(void) {
491 /* do nothing for now */
494 static void
495 post_update_config_pdu_transport_config_cb(void) {
496 dissector_delete_all("pdu_transport.id", iso15765_handle_pdu_transport);
498 config_pdu_transport_config_t *tmp;
499 unsigned i;
500 for (i = 0; i < config_pdu_transport_config_items_num; i++) {
501 tmp = &(config_pdu_transport_config_items[i]);
502 dissector_add_uint("pdu_transport.id", tmp->pdu_id, iso15765_handle_pdu_transport);
506 static config_pdu_transport_config_t *
507 find_pdu_transport_config(uint32_t pdu_id) {
508 unsigned i;
509 for (i = 0; i < config_pdu_transport_config_items_num; i++) {
510 if (config_pdu_transport_config_items[i].pdu_id == pdu_id) {
511 return &(config_pdu_transport_config_items[i]);
515 return NULL;
518 static int
519 handle_pdu_transport_addresses(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset_orig, uint32_t pdu_id, iso15765_info_t *iso15765data) {
520 int offset = offset_orig;
521 config_pdu_transport_config_t *config = find_pdu_transport_config(pdu_id);
523 iso15765data->number_of_addresses_valid = 0;
524 iso15765data->source_address = 0xffff;
525 iso15765data->target_address = 0xffff;
527 if (config == NULL) {
528 return offset - offset_orig;
531 uint32_t tmp;
532 /* single address, in payload */
533 if (config->ecu_address_size != 0) {
534 proto_tree_add_item_ret_uint(tree, hf_iso15765_address, tvb, offset, config->ecu_address_size, ENC_BIG_ENDIAN, &tmp);
535 offset += config->ecu_address_size;
536 iso15765data->number_of_addresses_valid = 1;
537 iso15765data->source_address = (uint16_t)tmp;
538 iso15765data->target_address = (uint16_t)tmp;
539 iso15765data->address_length = config->ecu_address_size;
540 return offset - offset_orig;
543 /* single address, fixed */
544 if (config->ecu_address_fixed != ISO15765_ADDR_INVALID) {
545 iso15765data->number_of_addresses_valid = 1;
546 iso15765data->source_address = config->ecu_address_fixed;
547 iso15765data->target_address = config->ecu_address_fixed;
548 iso15765data->address_length = 2; /* could be also 1 Byte but we cannot know for sure */
549 return offset - offset_orig;
552 /* no address possible */
553 if (config->source_address_size == 0 && config->source_address_fixed == ISO15765_ADDR_INVALID && config->target_address_size == 0 && config->target_address_fixed == ISO15765_ADDR_INVALID) {
554 iso15765data->address_length = 0;
555 return offset - offset_orig;
558 /* now we can only have two addresses! */
559 iso15765data->number_of_addresses_valid = 2;
560 iso15765data->address_length = config->source_address_size;
561 if (config->target_address_size > iso15765data->address_length) {
562 iso15765data->address_length = config->target_address_size;
565 if (config->source_address_size != 0) {
566 proto_tree_add_item_ret_uint(tree, hf_iso15765_source_address, tvb, offset, config->source_address_size, ENC_BIG_ENDIAN, &tmp);
567 offset += config->source_address_size;
568 iso15765data->source_address = tmp;
569 } else if (config->source_address_fixed != ISO15765_ADDR_INVALID) {
570 iso15765data->source_address = config->source_address_fixed;
571 iso15765data->address_length = 2; /* could be also 1 Byte but we cannot know for sure */
574 if (config->target_address_size != 0) {
575 proto_tree_add_item_ret_uint(tree, hf_iso15765_target_address, tvb, offset, config->target_address_size, ENC_BIG_ENDIAN, &tmp);
576 offset += config->target_address_size;
577 iso15765data->target_address = tmp;
578 } else if (config->target_address_fixed != ISO15765_ADDR_INVALID) {
579 iso15765data->target_address = config->target_address_fixed;
580 iso15765data->address_length = 2; /* could be also 1 Byte but we cannot know for sure */
583 return offset - offset_orig;
586 static int
587 dissect_iso15765(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t bus_type, uint32_t frame_id, uint32_t frame_length) {
588 static uint32_t msg_seqid = 0;
590 proto_tree *iso15765_tree;
591 proto_item *ti;
592 proto_item *message_type_item;
593 tvbuff_t* next_tvb = NULL;
594 uint16_t pci;
595 uint32_t message_type;
596 iso15765_identifier_t* iso15765_info;
597 /* LIN is always extended addressing */
598 uint8_t ae = (addressing == NORMAL_ADDRESSING && bus_type != ISO15765_TYPE_LIN) ? 0 : 1;
599 uint16_t frag_id_low = 0;
600 uint32_t offset, pci_offset;
601 uint32_t data_length;
602 uint32_t full_len;
603 bool fragmented = false;
604 bool complete = false;
605 uint32_t iface_id = (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID) ? pinfo->rec->rec_header.packet_header.interface_id : 0;
607 iso15765_info_t iso15765data;
609 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISO15765");
610 col_clear(pinfo->cinfo, COL_INFO);
612 iso15765_info = (iso15765_identifier_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_iso15765, 0);
614 if (!iso15765_info) {
615 iso15765_info = wmem_new0(wmem_file_scope(), iso15765_identifier_t);
616 iso15765_info->id = frame_id;
617 iso15765_info->last = false;
618 iso15765_info->bytes_used = 0;
619 p_add_proto_data(wmem_file_scope(), pinfo, proto_iso15765, 0, iso15765_info);
622 ti = proto_tree_add_item(tree, proto_iso15765, tvb, 0, -1, ENC_NA);
623 iso15765_tree = proto_item_add_subtree(ti, ett_iso15765);
625 iso15765data.bus_type = bus_type;
626 iso15765data.id = frame_id;
627 iso15765data.number_of_addresses_valid = 0;
628 iso15765data.address_length = 0;
630 if (bus_type == ISO15765_TYPE_FLEXRAY) {
631 uint32_t tmp;
632 proto_tree_add_item_ret_uint(iso15765_tree, hf_iso15765_source_address, tvb, 0, flexray_addressing, ENC_BIG_ENDIAN, &tmp);
633 iso15765data.source_address = (uint16_t)tmp;
634 proto_tree_add_item_ret_uint(iso15765_tree, hf_iso15765_target_address, tvb, flexray_addressing, flexray_addressing, ENC_BIG_ENDIAN, &tmp);
635 iso15765data.target_address = (uint16_t)tmp;
636 iso15765data.number_of_addresses_valid = 2;
637 iso15765data.address_length = flexray_addressing;
638 pci_offset = 2 * flexray_addressing;
639 } else if (bus_type == ISO15765_TYPE_IPDUM && ipdum_addressing > 0) {
640 uint32_t tmp;
641 proto_tree_add_item_ret_uint(iso15765_tree, hf_iso15765_source_address, tvb, 0, ipdum_addressing, ENC_BIG_ENDIAN, &tmp);
642 iso15765data.source_address = (uint16_t)tmp;
643 proto_tree_add_item_ret_uint(iso15765_tree, hf_iso15765_target_address, tvb, ipdum_addressing, ipdum_addressing, ENC_BIG_ENDIAN, &tmp);
644 iso15765data.target_address = (uint16_t)tmp;
645 iso15765data.number_of_addresses_valid = 2;
646 iso15765data.address_length = ipdum_addressing;
647 pci_offset = 2 * ipdum_addressing;
648 } else if (bus_type == ISO15765_TYPE_PDU_TRANSPORT) {
649 pci_offset = handle_pdu_transport_addresses(tvb, pinfo, iso15765_tree, 0, frame_id, &iso15765data);
650 } else {
651 if (ae != 0) {
652 uint32_t tmp;
653 iso15765data.number_of_addresses_valid = 1;
654 iso15765data.address_length = ae;
655 proto_tree_add_item_ret_uint(iso15765_tree, hf_iso15765_address, tvb, 0, ae, ENC_NA, &tmp);
656 iso15765data.source_address = (uint16_t)tmp;
657 iso15765data.target_address = (uint16_t)tmp;
658 pci_offset = ae;
659 } else {
660 /* Address implicitly encoded? */
661 if (bus_type == ISO15765_TYPE_CAN || bus_type == ISO15765_TYPE_CAN_FD) {
662 bool ext_id = (CAN_EFF_FLAG & frame_id) == CAN_EFF_FLAG;
663 uint32_t can_id = ext_id ? frame_id & CAN_EFF_MASK : frame_id & CAN_SFF_MASK;
664 iso15765data.number_of_addresses_valid = find_config_can_addr_mapping(ext_id, can_id, &(iso15765data.source_address), &(iso15765data.target_address), &(iso15765data.address_length));
666 pci_offset = 0;
670 offset = pci_offset;
671 pci = tvb_get_uint8(tvb, offset);
672 message_type_item = proto_tree_add_item_ret_uint(iso15765_tree, hf_iso15765_message_type, tvb, offset, 1, ENC_NA, &message_type);
673 col_add_str(pinfo->cinfo, COL_INFO, val_to_str(message_type, iso15765_message_types, "Unknown (0x%02x)"));
675 switch(message_type) {
676 case ISO15765_MESSAGE_TYPES_SINGLE_FRAME: {
677 if (frame_length > 8 && (pci & ISO15765_MESSAGE_DATA_LENGTH_MASK) == 0) {
678 /* Single Frame with CAN_DL > 8 Bytes: TTTT0000 LLLLLLLL, Type, Length */
680 /* This is always zero but still we need to dissect... */
681 proto_tree_add_item(iso15765_tree, hf_iso15765_data_length_4bit, tvb, offset, 1, ENC_NA);
682 offset += 1;
684 proto_tree_add_item_ret_uint(iso15765_tree, hf_iso15765_data_length_8bit, tvb, offset, 1, ENC_NA, &data_length);
685 offset += 1;
686 } else {
687 /* Single Frame with CAN_DL <= 8 Bytes: TTTTLLLL, Type, Length */
688 proto_tree_add_item_ret_uint(iso15765_tree, hf_iso15765_data_length_4bit, tvb, offset, 1, ENC_NA, &data_length);
689 offset += 1;
692 next_tvb = tvb_new_subset_length(tvb, offset, data_length);
693 complete = true;
695 col_append_fstr(pinfo->cinfo, COL_INFO, "(Len: %d)", data_length);
696 break;
698 case ISO15765_MESSAGE_TYPES_FIRST_FRAME: {
699 pci = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
700 if (pci == 0x1000) {
701 /* First Frame with CAN_DL > 4095 Bytes: TTTT0000 00000000 LLLLLLLL LLLLLLLL LLLLLLLL LLLLLLLL, Type, Length */
703 /* This is always zero but still we need to dissect... */
704 proto_tree_add_item(iso15765_tree, hf_iso15765_frame_length_12bit, tvb, offset, 2, ENC_BIG_ENDIAN);
705 offset += 2;
707 proto_tree_add_item_ret_uint(iso15765_tree, hf_iso15765_frame_length_32bit, tvb, offset, 4, ENC_BIG_ENDIAN, &full_len);
708 offset += 4;
709 } else {
710 /* First Frame with CAN_DL <= 4095 Bytes: TTTTLLLL LLLLLLLL, Type, Length */
711 full_len = pci & ISO15765_MESSAGE_FIRST_FRAME_DATA_LENGTH_MASK;
712 proto_tree_add_item(iso15765_tree, hf_iso15765_frame_length_12bit, tvb, offset, 2, ENC_BIG_ENDIAN);
713 offset += 2;
716 /* we need to assume that all following bytes are of the first frame data */
717 data_length = tvb_reported_length(tvb) - offset;
719 /* FlexRay data_length cut off, if configured */
720 if (bus_type == ISO15765_TYPE_FLEXRAY && flexray_segment_size_limit != 0 && (uint32_t)data_length > flexray_segment_size_limit - (offset - pci_offset)) {
721 data_length = flexray_segment_size_limit - (offset - pci_offset);
724 fragmented = true;
725 frag_id_low = 0;
727 /* Save information */
728 if (!(pinfo->fd->visited)) {
729 iso15765_seq_key_t* key;
730 void* old_value;
731 iso15765_seq_key_t temp_key = { bus_type, frame_id, iface_id };
732 msg_seqid++;
733 if (!wmem_map_lookup_extended(iso15765_seq_table, &temp_key, (const void**)&key, &old_value)) {
734 key = wmem_new(wmem_file_scope(), iso15765_seq_key_t);
735 *key = temp_key;
737 wmem_map_insert(iso15765_seq_table, key, GUINT_TO_POINTER(msg_seqid));
739 iso15765_frame_t *iso15765_frame = wmem_new0(wmem_file_scope(), iso15765_frame_t);
740 iso15765_frame->seq = iso15765_info->seq = msg_seqid;
741 iso15765_frame->len = full_len;
742 iso15765_frame->bytes_in_cf = MAX(8, tvb_reported_length(tvb)) - pci_offset - 1;
744 wmem_map_insert(iso15765_frame_table, GUINT_TO_POINTER(iso15765_info->seq), iso15765_frame);
747 col_append_fstr(pinfo->cinfo, COL_INFO, "(Frame Len: %d)", full_len);
748 break;
750 case ISO15765_MESSAGE_TYPES_FR_CONSECUTIVE_FRAME_2:
751 case ISO15765_MESSAGE_TYPES_CONSECUTIVE_FRAME: {
752 /* Consecutive Frame (DF): TTTTSSSS, Type, SeqNo */
753 proto_tree_add_item(iso15765_tree, hf_iso15765_sequence_number, tvb, offset, 1, ENC_NA);
754 col_append_fstr(pinfo->cinfo, COL_INFO, "(Seq: %d)", (pci & ISO15765_MESSAGE_DATA_LENGTH_MASK));
755 offset += 1;
757 /* we need to assume that all following bytes are of the first frame data */
758 data_length = tvb_reported_length(tvb) - offset;
760 frag_id_low = masked_uint16_value(pci, ISO15765_MESSAGE_SEQUENCE_NUMBER_MASK);
761 fragmented = true;
763 /* FlexRay data_length cut off, if configured */
764 if (bus_type == ISO15765_TYPE_FLEXRAY && flexray_segment_size_limit != 0 && (uint32_t)data_length > flexray_segment_size_limit - (offset - pci_offset)) {
765 data_length = flexray_segment_size_limit - (offset - pci_offset);
768 /* Save information */
769 if (!(pinfo->fd->visited)) {
770 iso15765_seq_key_t temp_key = { bus_type, frame_id, iface_id };
771 void* old_value = wmem_map_lookup(iso15765_seq_table, &temp_key);
772 iso15765_info->seq = old_value ? GPOINTER_TO_UINT(old_value) : 0;
774 break;
776 case ISO15765_MESSAGE_TYPES_FR_ACK_FRAME:
777 case ISO15765_MESSAGE_TYPES_FLOW_CONTROL: {
778 /* Flow Control Frame (FC): TTTTFFFF, BBBBBBBB, SSSSSSSS, Type, Flow status, Block size, Separation time */
779 uint32_t status = 0;
780 uint32_t bs = 0;
781 uint32_t stmin = 0;
782 bool stmin_in_us = false;
783 data_length = 0;
785 proto_tree_add_item_ret_uint(iso15765_tree, hf_iso15765_flow_status, tvb, offset, 1, ENC_NA, &status);
786 offset += 1;
788 proto_tree_add_item_ret_uint(iso15765_tree, hf_iso15765_fc_bs, tvb, offset, 1, ENC_NA, &bs);
789 offset += 1;
791 stmin = tvb_get_uint8(tvb, offset);
792 if (stmin >= 0xF1 && stmin <= 0xF9) {
793 stmin_in_us = true;
794 stmin = (stmin - 0xF0) * 100U;
795 proto_tree_add_uint(iso15765_tree, hf_iso15765_fc_stmin_in_us, tvb, offset, 1, stmin);
796 } else {
797 proto_tree_add_uint(iso15765_tree, hf_iso15765_fc_stmin, tvb, offset, 1, stmin);
799 offset += 1;
801 if (message_type == ISO15765_MESSAGE_TYPES_FR_ACK_FRAME) {
802 uint32_t ack = 0;
803 uint32_t sn = 0;
805 proto_tree_add_item_ret_uint(iso15765_tree, hf_iso15765_autosar_ack, tvb, offset, 1, ENC_NA, &ack);
806 proto_tree_add_item_ret_uint(iso15765_tree, hf_iso15765_sequence_number, tvb, offset, 1, ENC_NA, &sn);
807 offset += 1;
809 col_append_fstr(pinfo->cinfo, COL_INFO, "(Status: %d, Block size: 0x%x, Separation time minimum: %d %s, Ack: %d, Seq: %d)",
810 status, bs, stmin, stmin_in_us ? "µs" : "ms", ack, sn);
811 } else {
812 col_append_fstr(pinfo->cinfo, COL_INFO, "(Status: %d, Block size: 0x%x, Separation time minimum: %d %s)",
813 status, bs, stmin, stmin_in_us ? "µs" : "ms");
815 break;
817 case ISO15765_MESSAGE_TYPES_FR_SINGLE_FRAME_EXT: {
818 offset += 1;
820 data_length = tvb_get_uint8(tvb, offset);
821 proto_tree_add_item(iso15765_tree, hf_iso15765_data_length_8bit, tvb, offset, 1, ENC_NA);
822 offset += 1;
824 next_tvb = tvb_new_subset_length(tvb, offset, data_length);
825 complete = true;
827 col_append_fstr(pinfo->cinfo, COL_INFO, "(Len: %d)", data_length);
828 break;
830 case ISO15765_MESSAGE_TYPES_FR_FIRST_FRAME_EXT: {
831 offset += 1;
833 full_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
834 proto_tree_add_item(iso15765_tree, hf_iso15765_frame_length_32bit, tvb, offset, 4, ENC_BIG_ENDIAN);
835 offset += 4;
837 data_length = tvb_reported_length(tvb) - offset;
838 if (bus_type == ISO15765_TYPE_FLEXRAY && flexray_segment_size_limit != 0 && (uint32_t)data_length > flexray_segment_size_limit - (offset - pci_offset)) {
839 data_length = flexray_segment_size_limit - (offset - pci_offset);
842 fragmented = true;
843 frag_id_low = 0;
845 /* Save information */
846 if (!(pinfo->fd->visited)) {
847 iso15765_seq_key_t* key;
848 void* old_value;
849 iso15765_seq_key_t temp_key = { bus_type, frame_id, iface_id };
850 msg_seqid++;
851 if (!wmem_map_lookup_extended(iso15765_seq_table, &temp_key, (const void **)&key, &old_value)) {
852 key = wmem_new(wmem_file_scope(), iso15765_seq_key_t);
853 *key = temp_key;
855 wmem_map_insert(iso15765_seq_table, key, GUINT_TO_POINTER(msg_seqid));
857 iso15765_frame_t *iso15765_frame = wmem_new0(wmem_file_scope(), iso15765_frame_t);
858 iso15765_frame->seq = iso15765_info->seq = msg_seqid;
859 iso15765_frame->len = full_len;
860 iso15765_frame->bytes_in_cf = MAX(8, tvb_reported_length(tvb)) - pci_offset - 1;
862 wmem_map_insert(iso15765_frame_table, GUINT_TO_POINTER(iso15765_info->seq), iso15765_frame);
865 col_append_fstr(pinfo->cinfo, COL_INFO, "(Frame Len: %d)", full_len);
866 break;
868 default:
869 expert_add_info_format(pinfo, message_type_item, &ei_iso15765_message_type_bad, "Bad Message Type value %u!", message_type);
870 return offset;
873 /* Show data */
874 if (data_length > 0) {
875 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", tvb_bytes_to_str_punct(pinfo->pool, tvb, offset, data_length, ' '));
878 if (fragmented) {
879 tvbuff_t *new_tvb = NULL;
880 iso15765_frame_t *iso15765_frame;
881 uint16_t frag_id = frag_id_low;
882 /* Get frame information */
883 iso15765_frame = (iso15765_frame_t *)wmem_map_lookup(iso15765_frame_table, GUINT_TO_POINTER(iso15765_info->seq));
885 if (iso15765_frame != NULL) {
886 if (!(pinfo->fd->visited)) {
887 DISSECTOR_ASSERT(frag_id < 16);
888 uint16_t tmp = iso15765_frame->frag_id_high[frag_id]++;
889 /* Make sure that we assert on using more than 4096 (16*255) segments.*/
890 DISSECTOR_ASSERT(iso15765_frame->frag_id_high[frag_id] != 0);
891 frag_id += tmp * 16;
893 /* Save the frag_id for subsequent dissection */
894 iso15765_info->frag_id = frag_id;
896 /* Check if there is an error in conversation */
897 if (iso15765_info->frag_id + window < iso15765_frame->last_frag_id) {
898 /* Error in conversation */
899 iso15765_frame->error = true;
903 if (!iso15765_frame->error) {
904 bool save_fragmented = pinfo->fragmented;
905 uint32_t len = data_length;
906 uint32_t missing_bytes = 0;
907 fragment_head *frag_msg;
909 /* Check if it's the last packet */
910 if (!(pinfo->fd->visited)) {
911 iso15765_info->bytes_used = data_length;
913 if (frag_id > iso15765_frame->last_frag_id || !iso15765_frame->ff_seen) {
914 if (frag_id > iso15765_frame->last_frag_id + 1) {
915 missing_bytes = (frag_id - iso15765_frame->last_frag_id - 1) * iso15765_frame->bytes_in_cf;
917 /* Update the last_frag_id */
918 iso15765_frame->ff_seen = true;
919 iso15765_frame->last_frag_id = frag_id;
922 /* Here we use iso15765_frame->last_byte_seen to make sure that we correctly detect
923 * the last Consecutive Frame, even if some frames were missing in the middle.
924 * Note that the last Consecutive Frame might not be the last packet,
925 * as it might arrive out of order.
927 iso15765_frame->last_byte_seen += missing_bytes;
928 iso15765_frame->last_byte_seen += len;
929 if (iso15765_frame->last_byte_seen >= iso15765_frame->len) {
930 iso15765_info->last = true;
931 len -= (iso15765_frame->last_byte_seen - iso15765_frame->len);
933 /* Determine how many bytes were needed to calculate padding latter. */
934 iso15765_info->bytes_used = data_length - (iso15765_frame->last_byte_seen - iso15765_frame->len);
939 pinfo->fragmented = true;
941 /* Add fragment to fragment table */
942 frag_msg = fragment_add_seq_check(&iso15765_reassembly_table, tvb, offset, pinfo, iso15765_info->seq, NULL,
943 iso15765_info->frag_id, len, !iso15765_info->last);
945 new_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled Message", frag_msg,
946 &iso15765_frag_items, NULL, iso15765_tree);
948 if (frag_msg && frag_msg->reassembled_in != pinfo->num) {
949 col_append_frame_number(pinfo, COL_INFO, " [Reassembled in #%u]", frag_msg->reassembled_in);
952 pinfo->fragmented = save_fragmented;
955 if (new_tvb) {
956 /* This is a complete TVB to dissect */
957 next_tvb = new_tvb;
958 complete = true;
963 /* Let us correct bytes used for last segment to identify padding. */
964 if (iso15765_info != NULL && iso15765_info->last) {
965 data_length = iso15765_info->bytes_used;
968 if (message_type == ISO15765_MESSAGE_TYPES_FIRST_FRAME || message_type == ISO15765_MESSAGE_TYPES_CONSECUTIVE_FRAME ||
969 message_type == ISO15765_MESSAGE_TYPES_FR_FIRST_FRAME_EXT || message_type == ISO15765_MESSAGE_TYPES_FR_CONSECUTIVE_FRAME_2) {
970 proto_tree_add_item(iso15765_tree, hf_iso15765_segment_data, tvb, offset, data_length, ENC_NA);
973 offset += data_length;
975 if (offset < tvb_captured_length(tvb)) {
976 /* Unused bytes should be filled with 0xCC padding. */
977 proto_tree_add_item(iso15765_tree, hf_iso15765_padding, tvb, offset, tvb_captured_length(tvb) - offset, ENC_NA);
980 if (next_tvb) {
981 iso15765data.len = frame_length;
983 if (!complete || !dissector_try_payload_with_data(subdissector_table, next_tvb, pinfo, tree, true, &iso15765data)) {
984 call_data_dissector(next_tvb, pinfo, tree);
988 return tvb_captured_length(tvb);
991 static int
992 dissect_iso15765_can(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) {
993 can_info_t can_info;
995 DISSECTOR_ASSERT(data);
996 can_info = *((can_info_t*)data);
998 if (can_info.id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) {
999 /* Error and RTR frames are not for us. */
1000 return 0;
1003 switch (can_info.fd) {
1005 case CAN_TYPE_CAN_FD:
1006 return dissect_iso15765(tvb, pinfo, tree, ISO15765_TYPE_CAN_FD, can_info.id, can_info.len);
1008 case CAN_TYPE_CAN_CLASSIC:
1009 return dissect_iso15765(tvb, pinfo, tree, ISO15765_TYPE_CAN, can_info.id, can_info.len);
1011 default:
1012 DISSECTOR_ASSERT_NOT_REACHED();
1013 return tvb_captured_length(tvb);
1017 static int
1018 dissect_iso15765_lin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) {
1019 DISSECTOR_ASSERT(data);
1021 lin_info_t *lininfo = (lin_info_t *)data;
1023 return dissect_iso15765(tvb, pinfo, tree, ISO15765_TYPE_LIN, lininfo->id, lininfo->len);
1026 static int
1027 dissect_iso15765_flexray(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) {
1028 DISSECTOR_ASSERT(data);
1030 flexray_info_t *flexray_id = (flexray_info_t *)data;
1032 uint32_t id = (((uint32_t)flexray_id->id) << 16) | (((uint32_t)flexray_id->cc) << 8) | flexray_id->ch;
1034 return dissect_iso15765(tvb, pinfo, tree, ISO15765_TYPE_FLEXRAY, id, tvb_captured_length(tvb));
1037 static int
1038 dissect_iso15765_ipdum(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) {
1039 DISSECTOR_ASSERT(data);
1041 autosar_ipdu_multiplexer_info_t *ipdum_data = (autosar_ipdu_multiplexer_info_t *)data;
1043 return dissect_iso15765(tvb, pinfo, tree, ISO15765_TYPE_IPDUM, ipdum_data->pdu_id, tvb_captured_length(tvb));
1046 static int
1047 dissect_iso15765_pdu_transport(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) {
1048 DISSECTOR_ASSERT(data);
1050 pdu_transport_info_t *pdu_transport_data = (pdu_transport_info_t *)data;
1052 return dissect_iso15765(tvb, pinfo, tree, ISO15765_TYPE_PDU_TRANSPORT, pdu_transport_data->id, tvb_captured_length(tvb));
1055 static void
1056 update_config(void) {
1057 if (iso15765_handle_lin != NULL) {
1058 dissector_delete_all("lin.frame_id", iso15765_handle_lin);
1059 if (register_lin_diag_frames) {
1060 /* LIN specification states that 0x3c and 0x3d are for diagnostics */
1061 dissector_add_uint("lin.frame_id", LIN_DIAG_MASTER_REQUEST_FRAME, iso15765_handle_lin);
1062 dissector_add_uint("lin.frame_id", LIN_DIAG_SLAVE_RESPONSE_FRAME, iso15765_handle_lin);
1066 if (iso15765_handle_can != NULL) {
1067 dissector_delete_all("can.id", iso15765_handle_can);
1068 dissector_delete_all("can.extended_id", iso15765_handle_can);
1069 dissector_add_uint_range("can.id", configured_can_ids, iso15765_handle_can);
1070 dissector_add_uint_range("can.extended_id", configured_ext_can_ids, iso15765_handle_can);
1073 if (iso15765_handle_ipdum != NULL) {
1074 dissector_delete_all("ipdum.pdu.id", iso15765_handle_ipdum);
1075 dissector_add_uint_range("ipdum.pdu.id", configured_ipdum_pdu_ids, iso15765_handle_ipdum);
1079 void
1080 proto_register_iso15765(void) {
1081 uat_t *config_can_addr_mapping_uat;
1082 uat_t *config_pdu_transport_config_uat;
1084 static hf_register_info hf[] = {
1085 { &hf_iso15765_address, {
1086 "Address", "iso15765.address", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
1087 { &hf_iso15765_target_address, {
1088 "Target Address", "iso15765.target_address", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
1089 { &hf_iso15765_source_address, {
1090 "Source Address", "iso15765.source_address", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
1091 { &hf_iso15765_message_type, {
1092 "Message Type", "iso15765.message_type", FT_UINT8, BASE_HEX, VALS(iso15765_message_types), ISO15765_MESSAGE_TYPE_MASK, NULL, HFILL } },
1093 { &hf_iso15765_data_length_8bit, {
1094 "Data length (8bit)", "iso15765.data_length_8bit", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
1095 { &hf_iso15765_data_length_4bit, {
1096 "Data length (4bit)", "iso15765.data_length_4bit", FT_UINT8, BASE_DEC, NULL, ISO15765_MESSAGE_DATA_LENGTH_MASK, NULL, HFILL } },
1097 { &hf_iso15765_frame_length_32bit, {
1098 "Frame length (32bit)", "iso15765.frame_length_32bit", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
1099 { &hf_iso15765_frame_length_12bit, {
1100 "Frame length (12bit)", "iso15765.frame_length_12bit", FT_UINT16, BASE_DEC, NULL, ISO15765_MESSAGE_FIRST_FRAME_DATA_LENGTH_MASK, NULL, HFILL } },
1101 { &hf_iso15765_sequence_number, {
1102 "Sequence number", "iso15765.sequence_number", FT_UINT8, BASE_HEX, NULL, ISO15765_MESSAGE_SEQUENCE_NUMBER_MASK, NULL, HFILL } },
1103 { &hf_iso15765_flow_status, {
1104 "Flow status", "iso15765.flow_status", FT_UINT8, BASE_HEX, VALS(iso15765_flow_status_types), ISO15765_MESSAGE_FLOW_STATUS_MASK, NULL, HFILL } },
1106 { &hf_iso15765_fc_bs, {
1107 "Block size", "iso15765.flow_control.bs", FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL } },
1108 { &hf_iso15765_fc_stmin, {
1109 "Separation time minimum (ms)", "iso15765.flow_control.stmin", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL } },
1110 { &hf_iso15765_fc_stmin_in_us, {
1111 "Separation time minimum (µs)", "iso15765.flow_control.stmin", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL } },
1112 { &hf_iso15765_autosar_ack, {
1113 "Acknowledgment", "iso15765.autosar_ack.ack", FT_UINT8, BASE_HEX, NULL, ISO15765_MESSAGE_AUTOSAR_ACK_MASK, NULL, HFILL } },
1114 { &hf_iso15765_segment_data, {
1115 "Segment Data", "iso15765.segment_data", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL } },
1116 { &hf_iso15765_padding, {
1117 "Padding", "iso15765.padding", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL } },
1119 { &hf_iso15765_fragments, {
1120 "Message fragments", "iso15765.fragments", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }, },
1121 { &hf_iso15765_fragment, {
1122 "Message fragment", "iso15765.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
1123 { &hf_iso15765_fragment_overlap, {
1124 "Message fragment overlap", "iso15765.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
1125 { &hf_iso15765_fragment_overlap_conflicts, {
1126 "Message fragment overlapping with conflicting data", "iso15765.fragment.overlap.conflicts", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
1127 { &hf_iso15765_fragment_multiple_tails, {
1128 "Message has multiple tail fragments", "iso15765.fragment.multiple_tails", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
1129 { &hf_iso15765_fragment_too_long_fragment, {
1130 "Message fragment too long", "iso15765.fragment.too_long_fragment", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
1131 { &hf_iso15765_fragment_error, {
1132 "Message defragmentation error", "iso15765.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
1133 { &hf_iso15765_fragment_count, {
1134 "Message fragment count", "iso15765.fragment.count", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
1135 { &hf_iso15765_reassembled_in, {
1136 "Reassembled in", "iso15765.reassembled.in", FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
1137 { &hf_iso15765_reassembled_length, {
1138 "Reassembled length", "iso15765.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
1141 /* Setup protocol subtree array */
1142 static int *ett[] = {
1143 &ett_iso15765,
1144 &ett_iso15765_fragment,
1145 &ett_iso15765_fragments,
1148 static ei_register_info ei[] = {
1149 { &ei_iso15765_message_type_bad, {
1150 "iso15765.message_type.bad", PI_MALFORMED, PI_ERROR, "Bad Message Type value", EXPFILL } },
1153 module_t *iso15765_module;
1154 expert_module_t* expert_iso15765;
1156 proto_iso15765 = proto_register_protocol ( "ISO15765 Protocol", "ISO 15765", "iso15765");
1157 register_dissector("iso15765", dissect_iso15765_lin, proto_iso15765);
1158 expert_iso15765 = expert_register_protocol(proto_iso15765);
1160 proto_register_field_array(proto_iso15765, hf, array_length(hf));
1161 proto_register_subtree_array(ett, array_length(ett));
1163 expert_register_field_array(expert_iso15765, ei, array_length(ei));
1165 iso15765_module = prefs_register_protocol(proto_iso15765, update_config);
1167 prefs_register_enum_preference(iso15765_module, "addressing",
1168 "Addressing",
1169 "Addressing of ISO 15765. Normal or Extended",
1170 &addressing,
1171 enum_addressing, true);
1173 prefs_register_uint_preference(iso15765_module, "window",
1174 "Window",
1175 "Window of ISO 15765 fragments",
1176 10, &window);
1178 prefs_register_static_text_preference(iso15765_module, "empty_can", "", NULL);
1180 range_convert_str(wmem_epan_scope(), &configured_can_ids, "", 0x7ff);
1181 prefs_register_range_preference(iso15765_module, "can.ids",
1182 "CAN IDs (standard)",
1183 "ISO15765 bound standard CAN IDs",
1184 &configured_can_ids, 0x7ff);
1186 range_convert_str(wmem_epan_scope(), &configured_ext_can_ids, "", 0x1fffffff);
1187 prefs_register_range_preference(iso15765_module, "can.extended_ids",
1188 "CAN IDs (extended)",
1189 "ISO15765 bound extended CAN IDs",
1190 &configured_ext_can_ids, 0x1fffffff);
1192 /* UATs for config_can_addr_mapping_uat */
1193 static uat_field_t config_can_addr_mapping_uat_fields[] = {
1194 UAT_FLD_BOOL(config_can_addr_mappings, extended_address, "Ext Addr (29bit)", "29bit Addressing (true), 11bit Addressing (false)"),
1195 UAT_FLD_HEX(config_can_addr_mappings, can_id, "CAN ID", "CAN ID (hex)"),
1196 UAT_FLD_HEX(config_can_addr_mappings, can_id_mask, "CAN ID Mask", "CAN ID Mask (hex)"),
1197 UAT_FLD_HEX(config_can_addr_mappings, source_addr_mask, "Source Addr Mask", "Bitmask to specify location of Source Address (hex)"),
1198 UAT_FLD_HEX(config_can_addr_mappings, target_addr_mask, "Target Addr Mask", "Bitmask to specify location of Target Address (hex)"),
1199 UAT_FLD_HEX(config_can_addr_mappings, ecu_addr_mask, "ECU Addr Mask", "Bitmask to specify location of ECU Address (hex)"),
1200 UAT_END_FIELDS
1203 config_can_addr_mapping_uat = uat_new("ISO15765 CAN ID Mapping",
1204 sizeof(config_can_addr_mapping_t), /* record size */
1205 DATAFILE_CAN_ADDR_MAPPING, /* filename */
1206 true, /* from profile */
1207 (void**)&config_can_addr_mappings, /* data_ptr */
1208 &config_can_addr_mappings_num, /* numitems_ptr */
1209 UAT_AFFECTS_DISSECTION, /* but not fields */
1210 NULL, /* help */
1211 copy_config_can_addr_mapping_cb, /* copy callback */
1212 update_config_can_addr_mappings, /* update callback */
1213 free_config_can_addr_mappings, /* free callback */
1214 post_update_config_can_addr_mappings_cb, /* post update callback */
1215 NULL, /* reset callback */
1216 config_can_addr_mapping_uat_fields /* UAT field definitions */
1219 prefs_register_uat_preference(iso15765_module, "_iso15765_can_id_mappings", "CAN ID Mappings",
1220 "A table to define mappings rules for CAN IDs", config_can_addr_mapping_uat);
1222 prefs_register_static_text_preference(iso15765_module, "empty_lin", "", NULL);
1223 prefs_register_bool_preference(iso15765_module, "lin_diag",
1224 "Handle LIN Diagnostic Frames",
1225 "Handle LIN Diagnostic Frames",
1226 &register_lin_diag_frames);
1228 prefs_register_static_text_preference(iso15765_module, "empty_fr", "", NULL);
1229 prefs_register_enum_preference(iso15765_module, "flexray_addressing",
1230 "FlexRay Addressing",
1231 "Addressing of FlexRay TP. 1 Byte or 2 Byte",
1232 &flexray_addressing,
1233 enum_flexray_addressing, true);
1235 prefs_register_uint_preference(iso15765_module, "flexray_segment_size_limit",
1236 "FlexRay Segment Cutoff",
1237 "Segment Size Limit for first and consecutive frames of FlexRay (bytes after addresses)",
1238 10, &flexray_segment_size_limit);
1241 prefs_register_static_text_preference(iso15765_module, "empty_ipdum", "", NULL);
1242 range_convert_str(wmem_epan_scope(), &configured_ipdum_pdu_ids, "", 0xffffffff);
1243 prefs_register_range_preference(iso15765_module, "ipdum.pdu.id",
1244 "I-PduM PDU-IDs",
1245 "I-PduM PDU-IDs",
1246 &configured_ipdum_pdu_ids, 0xffffffff);
1248 prefs_register_enum_preference(iso15765_module, "ipdum_addressing",
1249 "I-PduM Addressing",
1250 "Addressing of I-PduM TP. 0, 1, or 2 Bytes",
1251 &ipdum_addressing,
1252 enum_ipdum_addressing, true);
1254 prefs_register_static_text_preference(iso15765_module, "empty_pdu_transport", "", NULL);
1256 /* UATs for config_pdu_transport_uat */
1257 static uat_field_t config_pdu_transport_uat_fields[] = {
1258 UAT_FLD_HEX(config_pdu_transport_config_items, pdu_id, "PDU ID", "PDU ID (hex)"),
1259 UAT_FLD_DEC(config_pdu_transport_config_items, source_address_size, "Source Addr. Size", "Size of encoded source address (0, 1, 2 bytes)"),
1260 UAT_FLD_HEX(config_pdu_transport_config_items, source_address_fixed, "Source Addr. Fixed", "Fixed source address for this PDU ID (hex), 0xffffffff is invalid"),
1261 UAT_FLD_DEC(config_pdu_transport_config_items, target_address_size, "Target Addr. Size", "Size of encoded target address (0, 1, 2 bytes)"),
1262 UAT_FLD_HEX(config_pdu_transport_config_items, target_address_fixed, "Target Addr. Fixed", "Fixed target address for this PDU ID (hex), 0xffffffff is invalid"),
1263 UAT_FLD_DEC(config_pdu_transport_config_items, ecu_address_size, "Single Addr. Size", "Size of encoded address (0, 1, 2 bytes)"),
1264 UAT_FLD_HEX(config_pdu_transport_config_items, ecu_address_fixed, "Single Addr. Fixed", "Fixed address for this PDU ID (hex), 0xffffffff is invalid"),
1265 UAT_END_FIELDS
1268 config_pdu_transport_config_uat = uat_new("ISO15765 PDU Transport Config",
1269 sizeof(config_pdu_transport_config_t), /* record size */
1270 DATAFILE_PDU_TRANSPORT_CONFIG, /* filename */
1271 true, /* from profile */
1272 (void**)&config_pdu_transport_config_items, /* data_ptr */
1273 &config_pdu_transport_config_items_num, /* numitems_ptr */
1274 UAT_AFFECTS_DISSECTION, /* but not fields */
1275 NULL, /* help */
1276 copy_config_pdu_transport_config_cb, /* copy callback */
1277 update_config_pdu_transport_config_item, /* update callback */
1278 free_config_pdu_transport_config, /* free callback */
1279 post_update_config_pdu_transport_config_cb, /* post update callback */
1280 reset_config_pdu_transport_config_cb, /* reset callback */
1281 config_pdu_transport_uat_fields /* UAT field definitions */
1284 prefs_register_uat_preference(iso15765_module, "_iso15765_pdu_transport_config", "PDU Transport Config",
1285 "A table to define the PDU Transport Config", config_pdu_transport_config_uat);
1288 iso15765_seq_table = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), iso15765_seq_hash_func, iso15765_seq_equal_func);
1289 iso15765_frame_table = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), g_direct_hash, g_direct_equal);
1291 reassembly_table_register(&iso15765_reassembly_table, &addresses_reassembly_table_functions);
1293 subdissector_table = register_decode_as_next_proto(proto_iso15765, "iso15765.subdissector", "ISO15765 next level dissector", NULL);
1296 void
1297 proto_reg_handoff_iso15765(void) {
1298 iso15765_handle_can = create_dissector_handle(dissect_iso15765_can, proto_iso15765);
1299 iso15765_handle_lin = create_dissector_handle(dissect_iso15765_lin, proto_iso15765);
1300 iso15765_handle_flexray = create_dissector_handle(dissect_iso15765_flexray, proto_iso15765);
1301 iso15765_handle_ipdum = create_dissector_handle(dissect_iso15765_ipdum, proto_iso15765);
1302 iso15765_handle_pdu_transport = create_dissector_handle(dissect_iso15765_pdu_transport, proto_iso15765);
1303 dissector_add_for_decode_as("can.subdissector", iso15765_handle_can);
1304 dissector_add_for_decode_as("flexray.subdissector", iso15765_handle_flexray);
1305 update_config();
1309 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1311 * Local variables:
1312 * c-basic-offset: 4
1313 * tab-width: 8
1314 * indent-tabs-mode: nil
1315 * End:
1317 * vi: set shiftwidth=4 tabstop=8 expandtab:
1318 * :indentSize=4:tabSize=8:noTabs=true: