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
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
28 * - ISO15765 is applicable to all 29bit CAN IDs 0x9988TTSS, with TT the target address and SS the source address.
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
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>
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
{
92 } iso15765_identifier_t
;
94 typedef struct iso15765_frame
{
96 uint32_t last_byte_seen
;
101 uint16_t last_frag_id
;
102 uint8_t frag_id_high
[16];
105 typedef struct iso15765_seq_key
{
109 } iso15765_seq_key_t
;
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
);
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"},
139 static const value_string iso15765_flow_status_types
[] = {
140 {0, "Continue to Send"},
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
;
164 static const enum_val_t enum_addressing
[] = {
165 {"normal", "Normal addressing", NORMAL_ADDRESSING
},
166 {"extended", "Extended addressing", EXTENDED_ADDRESSING
},
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
},
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
},
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 */
256 /* UAT for address encoded into CAN IDs */
257 typedef struct config_can_addr_mapping
{
258 bool extended_address
;
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
)
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
;
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!");
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!");
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!");
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)!");
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)!");
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)!");
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)!");
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)!");
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)!");
343 free_config_can_addr_mappings(void *r _U_
) {
344 /* do nothing right now */
348 post_update_config_can_addr_mappings_cb(void) {
349 /* do nothing right now */
353 masked_uint16_value(const uint16_t value
, const uint16_t mask
) {
354 return (value
& mask
) >> ws_ctz(mask
);
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)
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
;
370 if (source_addr
== NULL
|| target_addr
== NULL
|| config_can_addr_mappings
== NULL
) {
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
]);
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;
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;
408 /* UAT for PDU Transport config */
409 typedef struct config_pdu_tranport_config
{
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
)
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
;
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!");
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!");
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!");
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!");
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!");
485 free_config_pdu_transport_config(void *r _U_
) {
486 /* do nothing for now */
490 reset_config_pdu_transport_config_cb(void) {
491 /* do nothing for now */
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
;
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
) {
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
]);
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
;
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
;
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
;
592 proto_item
*message_type_item
;
593 tvbuff_t
* next_tvb
= NULL
;
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
;
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
) {
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) {
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
);
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
;
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
));
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
);
684 proto_tree_add_item_ret_uint(iso15765_tree
, hf_iso15765_data_length_8bit
, tvb
, offset
, 1, ENC_NA
, &data_length
);
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
);
692 next_tvb
= tvb_new_subset_length(tvb
, offset
, data_length
);
695 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "(Len: %d)", data_length
);
698 case ISO15765_MESSAGE_TYPES_FIRST_FRAME
: {
699 pci
= tvb_get_uint16(tvb
, offset
, ENC_BIG_ENDIAN
);
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
);
707 proto_tree_add_item_ret_uint(iso15765_tree
, hf_iso15765_frame_length_32bit
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &full_len
);
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
);
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
);
727 /* Save information */
728 if (!(pinfo
->fd
->visited
)) {
729 iso15765_seq_key_t
* key
;
731 iso15765_seq_key_t temp_key
= { bus_type
, frame_id
, iface_id
};
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
);
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
);
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
));
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
);
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;
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 */
782 bool stmin_in_us
= false;
785 proto_tree_add_item_ret_uint(iso15765_tree
, hf_iso15765_flow_status
, tvb
, offset
, 1, ENC_NA
, &status
);
788 proto_tree_add_item_ret_uint(iso15765_tree
, hf_iso15765_fc_bs
, tvb
, offset
, 1, ENC_NA
, &bs
);
791 stmin
= tvb_get_uint8(tvb
, offset
);
792 if (stmin
>= 0xF1 && stmin
<= 0xF9) {
794 stmin
= (stmin
- 0xF0) * 100U;
795 proto_tree_add_uint(iso15765_tree
, hf_iso15765_fc_stmin_in_us
, tvb
, offset
, 1, stmin
);
797 proto_tree_add_uint(iso15765_tree
, hf_iso15765_fc_stmin
, tvb
, offset
, 1, stmin
);
801 if (message_type
== ISO15765_MESSAGE_TYPES_FR_ACK_FRAME
) {
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
);
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
);
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");
817 case ISO15765_MESSAGE_TYPES_FR_SINGLE_FRAME_EXT
: {
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
);
824 next_tvb
= tvb_new_subset_length(tvb
, offset
, data_length
);
827 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "(Len: %d)", data_length
);
830 case ISO15765_MESSAGE_TYPES_FR_FIRST_FRAME_EXT
: {
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
);
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
);
845 /* Save information */
846 if (!(pinfo
->fd
->visited
)) {
847 iso15765_seq_key_t
* key
;
849 iso15765_seq_key_t temp_key
= { bus_type
, frame_id
, iface_id
};
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
);
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
);
869 expert_add_info_format(pinfo
, message_type_item
, &ei_iso15765_message_type_bad
, "Bad Message Type value %u!", message_type
);
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
, ' '));
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);
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
;
956 /* This is a complete TVB to dissect */
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
);
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
);
992 dissect_iso15765_can(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
) {
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. */
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
);
1012 DISSECTOR_ASSERT_NOT_REACHED();
1013 return tvb_captured_length(tvb
);
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
);
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
));
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
));
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
));
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
);
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
[] = {
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",
1169 "Addressing of ISO 15765. Normal or Extended",
1171 enum_addressing
, true);
1173 prefs_register_uint_preference(iso15765_module
, "window",
1175 "Window of ISO 15765 fragments",
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)"),
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 */
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 ®ister_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",
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",
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"),
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 */
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
);
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
);
1309 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1314 * indent-tabs-mode: nil
1317 * vi: set shiftwidth=4 tabstop=8 expandtab:
1318 * :indentSize=4:tabSize=8:noTabs=true: