2 * Routines for ISObus dissection (Based on CANOpen Dissector)
3 * Copyright 2016, Jeroen Sack <jeroen@jeroensack.nl>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <epan/packet.h>
16 #include <epan/reassemble.h>
17 #include "packet-socketcan.h"
18 #include <epan/wmem_scopes.h>
19 #include "packet-isobus.h"
20 #include "packet-isobus-parameters.h"
22 void proto_register_isobus(void);
23 void proto_reg_handoff_isobus(void);
25 static dissector_handle_t isobus_handle
;
26 static dissector_table_t subdissector_table_pdu_format
;
27 static dissector_table_t subdissector_table_pgn
;
29 /* Initialize the protocol and registered fields */
30 static int proto_isobus
;
31 static int hf_isobus_can_id
;
32 static int hf_isobus_priority
;
33 static int hf_isobus_ext_data_page
;
34 static int hf_isobus_data_page
;
35 static int hf_isobus_pdu_format_dp0
;
36 static int hf_isobus_pdu_format_dp1
;
37 static int hf_isobus_group_extension
;
38 static int hf_isobus_src_addr
;
39 static int hf_isobus_dst_addr
;
40 static int hf_isobus_pgn
;
41 static int hf_isobus_payload
;
43 static int hf_isobus_req_requested_pgn
;
44 static int hf_isobus_ac_name
;
45 static int hf_isobus_ac_name_id_number
;
46 static int hf_isobus_ac_name_manufacturer
;
47 static int hf_isobus_ac_name_ecu_instance
;
48 static int hf_isobus_ac_name_function_instance
;
49 static int hf_isobus_ac_name_function
;
50 static int hf_isobus_ac_name_reserved
;
51 static int hf_isobus_ac_name_vehicle_system
;
52 static int hf_isobus_ac_name_vehicle_system_instance
;
53 static int hf_isobus_ac_name_industry_group
;
54 static int hf_isobus_ac_name_arbitrary_address_capable
;
56 static int hf_isobus_transportprotocol_controlbyte
;
57 static int hf_isobus_transportprotocol_requesttosend_totalsize
;
58 static int hf_isobus_transportprotocol_requesttosend_numberofpackets
;
59 static int hf_isobus_transportprotocol_requesttosend_maximumpackets
;
60 static int hf_isobus_transportprotocol_requesttosend_pgn
;
61 static int hf_isobus_transportprotocol_cleartosend_numberofpacketscanbesent
;
62 static int hf_isobus_transportprotocol_cleartosend_nextpacketnumber
;
63 static int hf_isobus_transportprotocol_cleartosend_pgn
;
64 static int hf_isobus_transportprotocol_endofmsgack_totalsize
;
65 static int hf_isobus_transportprotocol_endofmsgack_numberofpackets
;
66 static int hf_isobus_transportprotocol_endofmsgack_pgn
;
67 static int hf_isobus_transportprotocol_connabort_abortreason
;
68 static int hf_isobus_transportprotocol_connabort_pgn
;
69 static int hf_isobus_transportprotocol_broadcastannouncemessage_totalsize
;
70 static int hf_isobus_transportprotocol_broadcastannouncemessage_numberofpackets
;
71 static int hf_isobus_transportprotocol_broadcastannouncemessage_pgn
;
72 static int hf_isobus_transportprotocol_reserved
;
74 static int hf_msg_fragments
;
75 static int hf_msg_fragment
;
76 static int hf_msg_fragment_overlap
;
77 static int hf_msg_fragment_overlap_conflicts
;
78 static int hf_msg_fragment_multiple_tails
;
79 static int hf_msg_fragment_too_long_fragment
;
80 static int hf_msg_fragment_error
;
81 static int hf_msg_fragment_count
;
82 static int hf_msg_reassembled_in
;
83 static int hf_msg_reassembled_length
;
84 static int hf_msg_reassembled_data
;
86 /* Desegmentation of isobus transport protocol streams */
87 static reassembly_table isobus_reassembly_table
;
88 static unsigned int reassembly_total_size
;
89 static unsigned int reassembly_current_size
;
94 #define ADDRESS_CLAIM 238
95 #define ETP_DATA_TRANSFER 199
96 #define ETP_DATA_MANAGEMENT 200
97 #define TP_DATA_TRANSFER 235
98 #define TP_DATA_MANAGEMENT 236
100 static const value_string pdu_format_dp0
[] = {
101 { 7 , "General-purpose valve load sense pressure" },
102 { 147, "NAME management" },
103 { 170, "Client to File Server" },
104 { 171, "File Server to Client" },
105 { 172, "Guidance machine status" },
106 { 173, "Guidance system command" },
107 { 196, "General-purpose valve command" },
108 { 197, "General-purpose valve measured flow" },
109 { 198, "General-purpose valve estimated flow" },
110 { ETP_DATA_TRANSFER
, "EXTENDED TRANSPORT PROTOCOL - DATA TRANSFER" },
111 { ETP_DATA_MANAGEMENT
, "EXTENDED TRANSPORT PROTOCOL - CONNECTION MANAGEMENT" },
114 { VT_TO_ECU
, "VT to ECU" },
115 { ECU_TO_VT
, "ECU to VT" },
116 { 232, "ACKNOWLEDGEMENT" },
117 { REQUEST
, "REQUEST" },
118 { TP_DATA_TRANSFER
, "TRANSPORT PROTOCOL - DATA TRANSFER" },
119 { TP_DATA_MANAGEMENT
, "TRANSPORT PROTOCOL - CONNECTION MANAGEMENT" },
120 { ADDRESS_CLAIM
, "ADDRESS CLAIM" },
121 { 239, "PROPRIETARY A" },
122 { 253, "Certification / Operating state" },
123 { 254, "Parameter groups" },
124 { 255, "PROPRIETARY B" },
128 static const value_string pdu_format_dp0_short
[] = {
138 { ETP_DATA_TRANSFER
, "ETP.DT" },
139 { ETP_DATA_MANAGEMENT
, "ETP.CM" },
142 { VT_TO_ECU
, "VT2ECU" },
143 { ECU_TO_VT
, "ECU2VT" },
146 { TP_DATA_TRANSFER
, "TP.DT" },
147 { TP_DATA_MANAGEMENT
, "TP.CM" },
148 { ADDRESS_CLAIM
, "AC" },
156 static const value_string pdu_format_dp1
[] = {
157 { 239, "PROPRIETARY A2" },
161 static const value_string pdu_format_dp1_short
[] = {
166 static const range_string address_range
[] = {
167 { 0 , 127, "Preferred Address" },
168 { 128, 247, "Self-configurable Address" },
169 { 248, 253, "Preferred Address" },
170 { 254, 254, "NULL Address" },
171 { 255, 255, "Global Address" },
175 static const range_string connection_abort_reasons
[] = {
176 { 1, 1, "Already in one or more connection-managed sessions and cannot support another" },
177 { 2, 2, "System resources were needed for another task so this connection managed session was terminated" },
178 { 3, 3, "A timeout occurred and this is the connection abort to close the session" },
179 { 4, 4, "CTS messages received when data transfer is in progress" },
180 { 5, 5, "Maximum retransmit request limit reached" },
181 { 6, 6, "Unexpected data transfer packet" },
182 { 7, 7, "Bad sequence number (and software is not able to recover)" },
183 { 8, 8, "Duplicate sequence number (and software is not able to recover)" },
184 { 9, 250, "Reserved for assignment in a future International Standard" },
185 { 251, 255, "According to ISO 11783-7 definitions" },
189 static const value_string transport_protocol_control_byte
[] = {
190 { 16, "Request To Send" },
191 { 17, "Clear To Send" },
192 { 19, "End of Message Acknowledgment" },
193 { 255, "Connection Abort" },
194 { 32, "Broadcast Announce Message" },
199 static int ett_isobus
;
200 static int ett_isobus_can_id
;
201 static int ett_isobus_name
;
202 static int ett_isobus_fragment
;
203 static int ett_isobus_fragments
;
205 static const fragment_items isobus_frag_items
= {
206 &ett_isobus_fragment
,
207 &ett_isobus_fragments
,
208 /* Fragment fields */
211 &hf_msg_fragment_overlap
,
212 &hf_msg_fragment_overlap_conflicts
,
213 &hf_msg_fragment_multiple_tails
,
214 &hf_msg_fragment_too_long_fragment
,
215 &hf_msg_fragment_error
,
216 &hf_msg_fragment_count
,
217 /* Reassembled in field */
218 &hf_msg_reassembled_in
,
219 /* Reassembled length field */
220 &hf_msg_reassembled_length
,
221 &hf_msg_reassembled_data
,
226 struct address_combination
{
231 struct reassemble_identifier
{
232 uint32_t startFrameId
;
237 struct address_reassemble_table
{
238 wmem_list_t
*reassembleIdentifierTable
;
239 uint32_t identifierCounter
;
242 static wmem_map_t
*addressIdentifierTable
;
244 static struct reassemble_identifier
* findIdentifierFor(wmem_list_t
*reassembleIdentifierTable
, uint32_t frameIndex
) {
245 wmem_list_frame_t
*currentItem
= wmem_list_head(reassembleIdentifierTable
);
247 while (currentItem
!= NULL
) {
248 struct reassemble_identifier
*currentData
= (struct reassemble_identifier
*)wmem_list_frame_data(currentItem
);
249 if (frameIndex
<= currentData
->endFrameId
&& frameIndex
>= currentData
->startFrameId
)
253 currentItem
= wmem_list_frame_next(currentItem
);
260 address_combination_equal(const void *p1
, const void *p2
) {
261 const struct address_combination
*addr_combi1
= (const struct address_combination
*)p1
;
262 const struct address_combination
*addr_combi2
= (const struct address_combination
*)p2
;
264 if (addr_combi1
->src_address
== addr_combi2
->src_address
&& addr_combi1
->dst_address
== addr_combi2
->dst_address
) {
272 address_combination_hash(const void *p
) {
273 const struct address_combination
*addr_combi
= (const struct address_combination
*)p
;
274 return (addr_combi
->src_address
* 256) + (addr_combi
->dst_address
);
277 static struct address_reassemble_table
* findAddressIdentifierFor(uint8_t src_address
, uint8_t dst_address
) {
278 struct address_combination
*addrCombi
= wmem_new(wmem_file_scope(), struct address_combination
);
279 struct address_reassemble_table
*foundItem
;
281 addrCombi
->src_address
= src_address
;
282 addrCombi
->dst_address
= dst_address
;
284 foundItem
= (struct address_reassemble_table
*)wmem_map_lookup(addressIdentifierTable
, addrCombi
);
286 if (foundItem
!= NULL
) {
289 /* nothing found so create a new one */
290 struct address_reassemble_table
*newItem
;
291 newItem
= wmem_new(wmem_file_scope(), struct address_reassemble_table
);
292 newItem
->identifierCounter
= 0;
293 newItem
->reassembleIdentifierTable
= wmem_list_new(wmem_file_scope());
294 wmem_map_insert(addressIdentifierTable
, addrCombi
, newItem
);
300 isobus_lookup_function(uint32_t industry_group
, uint32_t vehicle_system
, uint32_t function
) {
301 if (function
< 128) {
302 return try_val_to_str_ext((uint32_t)function
, &isobus_global_name_functions_ext
);
305 uint32_t new_id
= industry_group
<< 16 | vehicle_system
<< 8 | function
;
306 return try_val_to_str_ext((uint32_t)new_id
, &isobus_ig_specific_name_functions_ext
);
310 isobus_lookup_pgn(uint32_t pgn
) {
311 /* TODO: add configuration option via UAT? */
313 return try_val_to_str_ext(pgn
, &isobus_pgn_names_ext
);
317 proto_item_append_conditional(proto_item
*ti
, const char *str
) {
318 if (str
!= NULL
&& ti
!= NULL
) {
319 proto_item_append_text(ti
, " (%s)", str
);
324 call_isobus_subdissector(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, const bool add_proto_name
,
325 uint8_t priority
, uint8_t pdu_format
, unsigned pgn
, uint8_t source_addr
, void *data
) {
326 can_info_t
*can_info
= (can_info_t
*)data
;
328 isobus_info_t isobus_info
;
329 isobus_info
.can_id
= can_info
->id
;
330 isobus_info
.bus_id
= can_info
->bus_id
;
331 isobus_info
.pdu_format
= pdu_format
;
332 isobus_info
.pgn
= pgn
;
333 isobus_info
.priority
= priority
;
334 isobus_info
.source_addr
= source_addr
;
337 int ret
= dissector_try_uint_with_data(subdissector_table_pgn
, pgn
, tvb
, pinfo
, tree
, add_proto_name
, &isobus_info
);
343 return dissector_try_uint_with_data(subdissector_table_pdu_format
, pdu_format
, tvb
, pinfo
, tree
, add_proto_name
, &isobus_info
);
346 /* Code to actually dissect the packets */
348 dissect_isobus(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
) {
350 /* unsigned ext_data_page; */
354 uint8_t pdu_specific
;
356 struct can_info can_info
;
360 static unsigned seqnr
= 0;
364 proto_item
*ti
, *can_id_ti
;
365 proto_tree
*isobus_tree
;
366 proto_tree
*isobus_can_id_tree
;
368 struct reassemble_identifier
*identifier
= NULL
;
369 struct address_reassemble_table
*address_reassemble_table_item
= NULL
;
371 DISSECTOR_ASSERT(data
);
372 can_info
= *((struct can_info
*)data
);
374 if ((can_info
.id
& (CAN_ERR_FLAG
| CAN_RTR_FLAG
)) || !(can_info
.id
& CAN_EFF_FLAG
)) {
375 /* Error, RTR and frames with standard ids are not for us. */
379 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "ISObus");
380 col_clear(pinfo
->cinfo
, COL_INFO
);
382 priority
= (can_info
.id
>> 26) & 0x07;
383 /*ext_data_page = (can_info.id >> 25) & 0x01;*/
384 data_page
= (can_info
.id
>> 24) & 0x01;
385 pdu_format
= (can_info
.id
>> 16) & 0xff;
386 pdu_specific
= (can_info
.id
>> 8) & 0xff;
387 src_addr
= (can_info
.id
>> 0 ) & 0xff;
389 if (pdu_format
< 240) {
390 pgn
= (can_info
.id
>> 8) & 0x03ff00;
392 pgn
= (can_info
.id
>> 8) & 0x03ffff;
395 ti
= proto_tree_add_item(tree
, proto_isobus
, tvb
, 0, tvb_reported_length(tvb
), ENC_NA
);
396 isobus_tree
= proto_item_add_subtree(ti
, ett_isobus
);
398 /* add COB-ID with function code and node id */
399 can_id_ti
= proto_tree_add_uint(isobus_tree
, hf_isobus_can_id
, tvb
, 0, 0, can_info
.id
);
400 isobus_can_id_tree
= proto_item_add_subtree(can_id_ti
, ett_isobus_can_id
);
403 ti
= proto_tree_add_uint(isobus_can_id_tree
, hf_isobus_priority
, tvb
, 0, 0, can_info
.id
);
404 proto_item_set_generated(ti
);
406 /* add extended data page */
407 ti
= proto_tree_add_uint(isobus_can_id_tree
, hf_isobus_ext_data_page
, tvb
, 0, 0, can_info
.id
);
408 proto_item_set_generated(ti
);
411 ti
= proto_tree_add_uint(isobus_can_id_tree
, hf_isobus_data_page
, tvb
, 0, 0, can_info
.id
);
412 proto_item_set_generated(ti
);
417 ti
= proto_tree_add_uint(isobus_can_id_tree
, hf_isobus_pdu_format_dp0
, tvb
, 0, 0, can_info
.id
);
418 proto_item_set_generated(ti
);
421 ti
= proto_tree_add_uint(isobus_can_id_tree
, hf_isobus_pdu_format_dp1
, tvb
, 0, 0, can_info
.id
);
422 proto_item_set_generated(ti
);
426 /* add pdu specific */
427 if (pdu_format
<= 239) {
428 ti
= proto_tree_add_uint(isobus_can_id_tree
, hf_isobus_dst_addr
, tvb
, 0, 0, can_info
.id
);
429 proto_item_set_generated(ti
);
431 ti
= proto_tree_add_uint(isobus_can_id_tree
, hf_isobus_group_extension
, tvb
, 0, 0, can_info
.id
);
432 proto_item_set_generated(ti
);
435 /* add source address */
436 ti
= proto_tree_add_uint(isobus_can_id_tree
, hf_isobus_src_addr
, tvb
, 0, 0, can_info
.id
);
437 proto_item_set_generated(ti
);
439 /* put source address in source field */
440 snprintf(str_src
, 4, "%d", src_addr
);
441 alloc_address_wmem(pinfo
->pool
, &pinfo
->src
, AT_STRINGZ
, (int)strlen(str_src
) + 1, str_src
);
443 if (pdu_format
<= 239) {
444 /* put destination address in address field */
445 snprintf(str_dst
, 4, "%d", pdu_specific
);
446 alloc_address_wmem(pinfo
->pool
, &pinfo
->dst
, AT_STRINGZ
, (int)strlen(str_dst
) + 1, str_dst
);
448 /* put group destination address in address field and add (grp) to it */
449 snprintf(str_dst
, 10, "%d (grp)", pdu_specific
);
450 alloc_address_wmem(pinfo
->pool
, &pinfo
->dst
, AT_STRINGZ
, (int)strlen(str_dst
) + 1, str_dst
);
453 proto_tree_add_uint(isobus_tree
, hf_isobus_pgn
, tvb
, 0, 0, pgn
);
457 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "[%s] ", val_to_str_const(pdu_format
, pdu_format_dp0_short
, "Unknown"));
460 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "[%s] ", val_to_str_const(pdu_format
, pdu_format_dp1_short
, "Unknown"));
464 if (pdu_format
== TP_DATA_MANAGEMENT
|| pdu_format
== TP_DATA_TRANSFER
|| pdu_format
== ETP_DATA_MANAGEMENT
|| pdu_format
== ETP_DATA_TRANSFER
) {
465 bool isReply
= false;
467 if (pdu_format
== TP_DATA_MANAGEMENT
) {
468 uint8_t control_byte
= tvb_get_uint8(tvb
, data_offset
);
469 switch(control_byte
) {
482 address_reassemble_table_item
= findAddressIdentifierFor(pdu_specific
, src_addr
);
484 address_reassemble_table_item
= findAddressIdentifierFor(src_addr
, pdu_specific
);
487 identifier
= findIdentifierFor(address_reassemble_table_item
->reassembleIdentifierTable
, pinfo
->num
);
490 if (pdu_format
== TP_DATA_MANAGEMENT
) {
491 uint32_t control_byte
;
492 proto_tree_add_item_ret_uint(tree
, hf_isobus_transportprotocol_controlbyte
, tvb
, data_offset
, 1, ENC_LITTLE_ENDIAN
, &control_byte
);
495 if (control_byte
== 16) {
496 uint32_t total_size
, number_of_packets
;
498 proto_tree_add_item_ret_uint(tree
, hf_isobus_transportprotocol_requesttosend_totalsize
, tvb
, data_offset
, 2, ENC_LITTLE_ENDIAN
, &total_size
);
501 proto_tree_add_item_ret_uint(tree
, hf_isobus_transportprotocol_requesttosend_numberofpackets
, tvb
, data_offset
, 1, ENC_LITTLE_ENDIAN
, &number_of_packets
);
504 proto_tree_add_item(tree
, hf_isobus_transportprotocol_requesttosend_maximumpackets
, tvb
, data_offset
, 1, ENC_LITTLE_ENDIAN
);
507 proto_tree_add_item(tree
, hf_isobus_transportprotocol_requesttosend_pgn
, tvb
, data_offset
, 3, ENC_LITTLE_ENDIAN
);
510 seqnr
= identifier
->identifier
;
512 struct reassemble_identifier
*reassembleIdentifierTableEntry
= wmem_new(wmem_file_scope(), struct reassemble_identifier
);
513 seqnr
= ++address_reassemble_table_item
->identifierCounter
;
514 reassembleIdentifierTableEntry
->identifier
= seqnr
;
515 reassembleIdentifierTableEntry
->startFrameId
= pinfo
->num
;
516 reassembleIdentifierTableEntry
->endFrameId
= pinfo
->num
;
518 wmem_list_append(address_reassemble_table_item
->reassembleIdentifierTable
, reassembleIdentifierTableEntry
);
521 fragment_add_seq(&isobus_reassembly_table
, tvb
, 5, pinfo
, seqnr
, NULL
, 0, 3, true, 0);
522 fragment_set_tot_len(&isobus_reassembly_table
, pinfo
, seqnr
, NULL
, number_of_packets
);
523 reassembly_current_size
= 3;
524 reassembly_total_size
= total_size
+ 3;
526 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "Request to send message of %u bytes in %u fragments", total_size
, number_of_packets
);
527 } else if (control_byte
== 17) {
528 uint32_t number_of_packets_can_be_sent
, next_packet_number
;
530 proto_tree_add_item_ret_uint(tree
, hf_isobus_transportprotocol_cleartosend_numberofpacketscanbesent
, tvb
, data_offset
, 1, ENC_LITTLE_ENDIAN
, &number_of_packets_can_be_sent
);
533 proto_tree_add_item_ret_uint(tree
, hf_isobus_transportprotocol_cleartosend_nextpacketnumber
, tvb
, data_offset
, 1, ENC_LITTLE_ENDIAN
, &next_packet_number
);
536 proto_tree_add_item(tree
, hf_isobus_transportprotocol_reserved
, tvb
, data_offset
, 2, ENC_NA
);
539 proto_tree_add_item(tree
, hf_isobus_transportprotocol_cleartosend_pgn
, tvb
, data_offset
, 3, ENC_LITTLE_ENDIAN
);
541 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "Clear to send, can receive %u packets, next packet is %u", number_of_packets_can_be_sent
, next_packet_number
);
542 } else if (control_byte
== 19) {
543 uint32_t total_size
, number_of_packets
;
545 proto_tree_add_item_ret_uint(tree
, hf_isobus_transportprotocol_endofmsgack_totalsize
, tvb
, data_offset
, 2, ENC_LITTLE_ENDIAN
, &total_size
);
548 proto_tree_add_item_ret_uint(tree
, hf_isobus_transportprotocol_endofmsgack_numberofpackets
, tvb
, data_offset
, 1, ENC_LITTLE_ENDIAN
, &number_of_packets
);
551 proto_tree_add_item(tree
, hf_isobus_transportprotocol_reserved
, tvb
, data_offset
, 1, ENC_NA
);
554 proto_tree_add_item(tree
, hf_isobus_transportprotocol_endofmsgack_pgn
, tvb
, data_offset
, 3, ENC_LITTLE_ENDIAN
);
556 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "End of Message Acknowledgment, %u bytes sent in %u packets", total_size
, number_of_packets
);
557 } else if (control_byte
== 255) {
558 uint32_t connection_abort_reason
;
560 proto_tree_add_item_ret_uint(tree
, hf_isobus_transportprotocol_connabort_abortreason
, tvb
, data_offset
, 1, ENC_LITTLE_ENDIAN
, &connection_abort_reason
);
563 proto_tree_add_item(tree
, hf_isobus_transportprotocol_reserved
, tvb
, data_offset
, 3, ENC_NA
);
566 proto_tree_add_item(tree
, hf_isobus_transportprotocol_connabort_pgn
, tvb
, data_offset
, 3, ENC_LITTLE_ENDIAN
);
568 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "Connection Abort, %s", rval_to_str_const(connection_abort_reason
, connection_abort_reasons
, "unknown reason"));
569 } else if (control_byte
== 32) {
570 uint32_t total_size
, number_of_packets
;
572 proto_tree_add_item_ret_uint(tree
, hf_isobus_transportprotocol_broadcastannouncemessage_totalsize
, tvb
, data_offset
, 2, ENC_LITTLE_ENDIAN
, &total_size
);
575 proto_tree_add_item_ret_uint(tree
, hf_isobus_transportprotocol_broadcastannouncemessage_numberofpackets
, tvb
, data_offset
, 1, ENC_LITTLE_ENDIAN
, &number_of_packets
);
578 proto_tree_add_item(tree
, hf_isobus_transportprotocol_reserved
, tvb
, data_offset
, 1, ENC_NA
);
581 proto_tree_add_item(tree
, hf_isobus_transportprotocol_broadcastannouncemessage_pgn
, tvb
, data_offset
, 3, ENC_LITTLE_ENDIAN
);
583 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "Broadcast Announcement Message, %u bytes sent in %u packets", total_size
, number_of_packets
);
587 /* if reassemble has not started yet don't parse the message */
588 else if (pdu_format
== TP_DATA_TRANSFER
&& address_reassemble_table_item
->reassembleIdentifierTable
!= NULL
)
590 tvbuff_t
*reassembled_data
;
591 uint16_t fragment_size
= 0;
593 uint8_t sequenceId
= tvb_get_uint8(tvb
, 0);
594 fragment_head
*fg_head
;
596 if (identifier
== NULL
) {
597 wmem_list_frame_t
*lastItem
= wmem_list_tail(address_reassemble_table_item
->reassembleIdentifierTable
);
599 if (lastItem
!= NULL
) {
600 struct reassemble_identifier
*lastIdentifier
= (struct reassemble_identifier
*)wmem_list_frame_data(lastItem
);
601 lastIdentifier
->endFrameId
= pinfo
->num
;
602 identifier
= lastIdentifier
;
606 if (identifier
!= NULL
) {
607 if (reassembly_total_size
> reassembly_current_size
+ 7) {
611 fragment_size
= reassembly_total_size
- reassembly_current_size
;
615 fg_head
= fragment_add_seq(&isobus_reassembly_table
, tvb
, 1, pinfo
, identifier
->identifier
, NULL
, sequenceId
, fragment_size
, !lastPacket
, 0);
616 reassembly_current_size
+= fragment_size
;
618 reassembled_data
= process_reassembled_data(tvb
, 0, pinfo
, "Reassembled data", fg_head
, &isobus_frag_items
, NULL
, isobus_tree
);
620 if (reassembled_data
) {
621 uint32_t id_reassembled
= tvb_get_uint24(reassembled_data
, 0, ENC_BIG_ENDIAN
);
622 uint8_t pdu_format_reassembled
= (uint8_t)((id_reassembled
>> 8) & 0xff);
624 uint32_t pgn_reassembled
;
625 if (pdu_format
< 240) {
626 pgn_reassembled
= id_reassembled
& 0x03ff00;
628 pgn_reassembled
= id_reassembled
& 0x03ffff;
631 proto_tree_add_uint(isobus_tree
, hf_isobus_pgn
, reassembled_data
, 0, 3, pgn_reassembled
);
633 if (call_isobus_subdissector(tvb_new_subset_remaining(reassembled_data
, 3), pinfo
, isobus_tree
, false, 0, pdu_format_reassembled
,
634 pgn_reassembled
, src_addr
, data
) == 0) {
635 col_append_str(pinfo
->cinfo
, COL_INFO
, "Protocol not yet supported");
638 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "Fragment number %u", sequenceId
);
641 col_append_str(pinfo
->cinfo
, COL_INFO
, "ERROR: Transport protocol was not initialized");
643 } else if (pdu_format
== REQUEST
) {
645 proto_tree_add_item_ret_uint(isobus_tree
, hf_isobus_req_requested_pgn
, tvb
, 0, 3, ENC_LITTLE_ENDIAN
, &req_pgn
);
646 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "Requesting PGN: %u", req_pgn
);
647 const char *tmp
= isobus_lookup_pgn(req_pgn
);
650 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " (%s)", tmp
);
652 } else if (pdu_format
== ADDRESS_CLAIM
) {
653 proto_tree
*name_tree
;
654 ti
= proto_tree_add_item(isobus_tree
, hf_isobus_ac_name
, tvb
, 0, 8, ENC_NA
);
655 name_tree
= proto_item_add_subtree(ti
, ett_isobus_name
);
657 /* we cannot directly use the value strings as they depend on other parameters */
658 uint64_t industry_group
, vehicle_system
, function
, manufacturer
;
659 proto_tree_add_item(name_tree
, hf_isobus_ac_name_arbitrary_address_capable
, tvb
, 0, 8, ENC_LITTLE_ENDIAN
);
660 ti
= proto_tree_add_item_ret_uint64(name_tree
, hf_isobus_ac_name_industry_group
, tvb
, 0, 8, ENC_LITTLE_ENDIAN
, &industry_group
);
661 proto_item_append_conditional(ti
, try_val_to_str_ext((uint32_t)industry_group
, &isobus_industry_groups_ext
));
663 proto_tree_add_item(name_tree
, hf_isobus_ac_name_vehicle_system_instance
, tvb
, 0, 8, ENC_LITTLE_ENDIAN
);
664 ti
= proto_tree_add_item_ret_uint64(name_tree
, hf_isobus_ac_name_vehicle_system
, tvb
, 0, 8, ENC_LITTLE_ENDIAN
, &vehicle_system
);
665 proto_item_append_conditional(ti
, try_val_to_str_ext((uint16_t)industry_group
* 256 + (uint8_t)vehicle_system
, &isobus_vehicle_systems_ext
));
667 proto_tree_add_item(name_tree
, hf_isobus_ac_name_reserved
, tvb
, 0, 8, ENC_LITTLE_ENDIAN
);
668 ti
= proto_tree_add_item_ret_uint64(name_tree
, hf_isobus_ac_name_function
, tvb
, 0, 8, ENC_LITTLE_ENDIAN
, &function
);
669 proto_item_append_conditional(ti
, isobus_lookup_function((uint32_t)industry_group
, (uint32_t)vehicle_system
, (uint32_t)function
));
671 proto_tree_add_item(name_tree
, hf_isobus_ac_name_function_instance
, tvb
, 0, 8, ENC_LITTLE_ENDIAN
);
673 proto_tree_add_item(name_tree
, hf_isobus_ac_name_ecu_instance
, tvb
, 0, 8, ENC_LITTLE_ENDIAN
);
674 ti
= proto_tree_add_item_ret_uint64(name_tree
, hf_isobus_ac_name_manufacturer
, tvb
, 0, 8, ENC_LITTLE_ENDIAN
, &manufacturer
);
675 proto_item_append_conditional(ti
, try_val_to_str_ext((uint32_t)manufacturer
, &isobus_manufacturers_ext
));
677 proto_tree_add_item(name_tree
, hf_isobus_ac_name_id_number
, tvb
, 0, 8, ENC_LITTLE_ENDIAN
);
679 unsigned address_claimed
= can_info
.id
& 0xff;
680 switch (address_claimed
) {
682 /* This seems to be not allowed. Create ticket, if this is not correct. */
683 col_append_str(pinfo
->cinfo
, COL_INFO
, "Trying to claim global destination address!? This seems wrong!");
686 col_append_str(pinfo
->cinfo
, COL_INFO
, "Cannot claim address");
689 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "Address claimed %u", address_claimed
);
691 } else if (call_isobus_subdissector(tvb
, pinfo
, isobus_tree
, false, priority
, pdu_format
, pgn
, src_addr
, data
) == 0) {
692 col_append_str(pinfo
->cinfo
, COL_INFO
, "Protocol not yet supported");
693 proto_tree_add_item(isobus_tree
, hf_isobus_payload
, tvb
, 0, tvb_captured_length(tvb
), ENC_NA
);
696 return tvb_reported_length(tvb
);
701 reassembly_table_init(&isobus_reassembly_table
, &addresses_reassembly_table_functions
);
705 isobus_cleanup(void) {
706 reassembly_table_destroy(&isobus_reassembly_table
);
709 /* Register the protocol with Wireshark */
711 proto_register_isobus(void) {
712 static hf_register_info hf
[] = {
713 { &hf_isobus_can_id
, {
714 "CAN-ID", "isobus.can_id", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
715 { &hf_isobus_priority
, {
716 "Priority", "isobus.priority", FT_UINT32
, BASE_HEX
, NULL
, 0x1C000000, NULL
, HFILL
} },
717 { &hf_isobus_ext_data_page
, {
718 "Ext data page", "isobus.edp", FT_UINT32
, BASE_HEX
, NULL
, 0x02000000, NULL
, HFILL
} },
719 { &hf_isobus_data_page
, {
720 "Data page", "isobus.datapage", FT_UINT32
, BASE_HEX
, NULL
, 0x01000000, NULL
, HFILL
} },
721 { &hf_isobus_pdu_format_dp0
, {
722 "PDU Format", "isobus.pdu_format", FT_UINT32
, BASE_DEC
, VALS(pdu_format_dp0
), 0xff0000, NULL
, HFILL
} },
723 { &hf_isobus_pdu_format_dp1
, {
724 "PDU Format", "isobus.pdu_format", FT_UINT32
, BASE_DEC
, VALS(pdu_format_dp1
), 0xff0000, NULL
, HFILL
} },
725 { &hf_isobus_group_extension
, {
726 "Group Extension", "isobus.grp_ext", FT_UINT32
, BASE_DEC
, NULL
, 0xff00, NULL
, HFILL
} },
727 { &hf_isobus_dst_addr
, {
728 "Destination Address", "isobus.dst_addr", FT_UINT32
, BASE_DEC
| BASE_RANGE_STRING
, RVALS(address_range
), 0xff00, NULL
, HFILL
} },
729 { &hf_isobus_src_addr
, {
730 "Source Address", "isobus.src_addr", FT_UINT32
, BASE_DEC
| BASE_RANGE_STRING
, RVALS(address_range
), 0xff, NULL
, HFILL
} },
732 "PGN", "isobus.pgn", FT_UINT24
, BASE_DEC_HEX
| BASE_EXT_STRING
, VALS_EXT_PTR(&isobus_pgn_names_ext
), 0x0, NULL
, HFILL
} },
733 { &hf_isobus_payload
, {
734 "Payload", "isobus.payload", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
736 { &hf_isobus_req_requested_pgn
, {
737 "Requested PGN", "isobus.req.requested_pgn", FT_UINT24
, BASE_HEX
| BASE_EXT_STRING
, VALS_EXT_PTR(&isobus_pgn_names_ext
), 0x0, NULL
, HFILL
} },
739 { &hf_isobus_ac_name
, {
740 "Name", "isobus.ac.name", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
741 { &hf_isobus_ac_name_id_number
, {
742 "Identity Number", "isobus.ac.name.identity_number", FT_UINT64
, BASE_DEC
, NULL
, 0x00000000001fffff, NULL
, HFILL
} },
743 { &hf_isobus_ac_name_manufacturer
, {
744 "Manufacturer", "isobus.ac.name.manufacturer", FT_UINT64
, BASE_DEC
, NULL
, 0x00000000ffe00000, NULL
, HFILL
} },
745 { &hf_isobus_ac_name_function_instance
, {
746 "Function Instance", "isobus.ac.name.function_instance", FT_UINT64
, BASE_DEC
, NULL
, 0x000000f000000000, NULL
, HFILL
} },
747 { &hf_isobus_ac_name_ecu_instance
, {
748 "ECU Instance", "isobus.ac.name.ecu_instance", FT_UINT64
, BASE_DEC
, NULL
, 0x0000000f00000000, NULL
, HFILL
} },
749 { &hf_isobus_ac_name_function
, {
750 "Function", "isobus.ac.name.function", FT_UINT64
, BASE_DEC
, NULL
, 0x0000ff0000000000, NULL
, HFILL
} },
751 { &hf_isobus_ac_name_reserved
, {
752 "Reserved", "isobus.ac.name.reserved", FT_UINT64
, BASE_HEX
, NULL
, 0x0001000000000000, NULL
, HFILL
} },
753 { &hf_isobus_ac_name_vehicle_system
,
754 { "Vehicle System", "isobus.ac.name.vehicle_system", FT_UINT64
, BASE_DEC
, NULL
, 0x00fe000000000000, NULL
, HFILL
} },
755 { &hf_isobus_ac_name_vehicle_system_instance
, {
756 "System Instance", "isobus.ac.name.system_instance", FT_UINT64
, BASE_DEC
, NULL
, 0x0f00000000000000, NULL
, HFILL
} },
757 { &hf_isobus_ac_name_industry_group
, {
758 "Industry Group", "isobus.ac.name.industry_group", FT_UINT64
, BASE_DEC
, NULL
, 0x7000000000000000, NULL
, HFILL
} },
759 { &hf_isobus_ac_name_arbitrary_address_capable
, {
760 "Arbitrary Address Capable", "isobus.ac.name.arbitrary_address_capable", FT_UINT64
, BASE_DEC
, NULL
, 0x8000000000000000, NULL
, HFILL
} },
762 { &hf_isobus_transportprotocol_controlbyte
, {
763 "Control Byte", "isobus.transport_protocol.control_byte", FT_UINT8
, BASE_DEC
, VALS(transport_protocol_control_byte
), 0x0, NULL
, HFILL
} },
764 { &hf_isobus_transportprotocol_requesttosend_totalsize
, {
765 "Total message size", "isobus.transport_protocol.request_to_send.total_size", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
766 { &hf_isobus_transportprotocol_requesttosend_numberofpackets
, {
767 "Number of Packets", "isobus.transport_protocol.request_to_send.number_of_packets", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
768 { &hf_isobus_transportprotocol_requesttosend_maximumpackets
, {
769 "Maximum Packets", "isobus.transport_protocol.request_to_send.maximum_packets", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
770 { &hf_isobus_transportprotocol_requesttosend_pgn
, {
771 "PGN", "isobus.transport_protocol.request_to_send.pgn", FT_UINT24
, BASE_HEX
| BASE_EXT_STRING
, VALS_EXT_PTR(&isobus_pgn_names_ext
), 0x0, NULL
, HFILL
} },
772 { &hf_isobus_transportprotocol_cleartosend_numberofpacketscanbesent
, {
773 "Number of packets that can be sent", "isobus.transport_protocol.request_to_send.number_of_packets_that_can_be_sent", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
774 { &hf_isobus_transportprotocol_cleartosend_nextpacketnumber
, {
775 "Next packet number", "isobus.transport_protocol.request_to_send.next_packet_number", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
776 { &hf_isobus_transportprotocol_cleartosend_pgn
, {
777 "PGN", "isobus.transport_protocol.clear_to_send.pgn", FT_UINT24
, BASE_HEX
| BASE_EXT_STRING
, VALS_EXT_PTR(&isobus_pgn_names_ext
), 0x0, NULL
, HFILL
} },
778 { &hf_isobus_transportprotocol_endofmsgack_totalsize
, {
779 "Total Size", "isobus.transport_protocol.end_of_message_acknowledgement.total_size", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
780 { &hf_isobus_transportprotocol_endofmsgack_numberofpackets
, {
781 "Number of Packets", "isobus.transport_protocol.end_of_message_acknowledgement.number_of_packets", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
782 { &hf_isobus_transportprotocol_endofmsgack_pgn
, {
783 "PGN", "isobus.transport_protocol.end_of_message_acknowledgement.pgn", FT_UINT24
, BASE_HEX
| BASE_EXT_STRING
, VALS_EXT_PTR(&isobus_pgn_names_ext
), 0x0, NULL
, HFILL
} },
784 { &hf_isobus_transportprotocol_connabort_abortreason
, {
785 "Connection Abort reason", "isobus.transport_protocol.connection_abort.abort_reason", FT_UINT8
, BASE_DEC
| BASE_RANGE_STRING
, RVALS(connection_abort_reasons
), 0x0, NULL
, HFILL
} },
786 { &hf_isobus_transportprotocol_connabort_pgn
, {
787 "PGN", "isobus.transport_protocol.connection_abort.pgn", FT_UINT24
, BASE_HEX
| BASE_EXT_STRING
, VALS_EXT_PTR(&isobus_pgn_names_ext
), 0x0, NULL
, HFILL
} },
788 { &hf_isobus_transportprotocol_broadcastannouncemessage_totalsize
, {
789 "Total Message Size", "isobus.transport_protocol.broadcast_announce_message.total_message_size", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
790 { &hf_isobus_transportprotocol_broadcastannouncemessage_numberofpackets
, {
791 "Total Number of Packets", "isobus.transport_protocol.broadcast_announce_message.total_number_of_packets", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
792 { &hf_isobus_transportprotocol_broadcastannouncemessage_pgn
, {
793 "PGN", "isobus.transport_protocol.broadcast_announce_message.pgn", FT_UINT24
, BASE_HEX
| BASE_EXT_STRING
, VALS_EXT_PTR(&isobus_pgn_names_ext
), 0x0, NULL
, HFILL
} },
794 { &hf_isobus_transportprotocol_reserved
, {
795 "Reserved", "isobus.transport_protocol.reserved", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
797 { &hf_msg_fragments
, {
798 "Message fragments", "isobus.fragments", FT_NONE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
799 { &hf_msg_fragment
, {
800 "Message fragment", "isobus.fragment", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
801 { &hf_msg_fragment_overlap
, {
802 "Message fragment overlap", "isobus.fragment.overlap", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
803 { &hf_msg_fragment_overlap_conflicts
, {
804 "Message fragment overlapping with conflicting data", "isobus.fragment.overlap.conflicts", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
805 { &hf_msg_fragment_multiple_tails
, {
806 "Message has multiple tail fragments", "isobus.fragment.multiple_tails", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
807 { &hf_msg_fragment_too_long_fragment
, {
808 "Message fragment too long", "isobus.fragment.too_long_fragment", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
809 { &hf_msg_fragment_error
, {
810 "Message defragmentation error", "isobus.fragment.error", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
811 { &hf_msg_fragment_count
, {
812 "Message fragment count", "isobus.fragment.count", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
813 { &hf_msg_reassembled_in
, {
814 "Reassembled in", "isobus.reassembled.in", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
815 { &hf_msg_reassembled_length
, {
816 "Reassembled length", "isobus.reassembled.length", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
817 { &hf_msg_reassembled_data
, {
818 "Reassembled data", "isobus.reassembled.data", FT_BYTES
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} }
821 static int *ett
[] = {
825 &ett_isobus_fragment
,
826 &ett_isobus_fragments
829 /* Register protocol init routine */
830 register_init_routine(&isobus_init
);
831 register_cleanup_routine(&isobus_cleanup
);
833 proto_isobus
= proto_register_protocol("ISObus", "ISOBUS", "isobus");
835 proto_register_field_array(proto_isobus
, hf
, array_length(hf
));
836 proto_register_subtree_array(ett
, array_length(ett
));
838 addressIdentifierTable
= wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), address_combination_hash
, address_combination_equal
);
840 subdissector_table_pdu_format
= register_dissector_table("isobus.pdu_format", "PDU format", proto_isobus
, FT_UINT8
, BASE_DEC
);
841 subdissector_table_pgn
= register_dissector_table("isobus.pgn", "PGN", proto_isobus
, FT_UINT32
, BASE_DEC
);
843 isobus_handle
= register_dissector("isobus", dissect_isobus
, proto_isobus
);
847 proto_reg_handoff_isobus(void) {
848 dissector_add_for_decode_as("can.subdissector", isobus_handle
);
852 * Editor modelines - https://www.wireshark.org/tools/modelines.html
857 * indent-tabs-mode: nil
860 * vi: set shiftwidth=4 tabstop=8 expandtab:
861 * :indentSize=4:tabSize=8:noTabs=true: