1 /* packet-busmirroring.c
2 * Routines for BusMirroring protocol packet disassembly
3 * Copyright 2023, Haiyun Liu <liu0hy@gmail.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
11 * Bus Mirroring is an AUTOSAR Basic Software module. Its purpose is the replication of
12 * the traffic and the state of internal buses to an external bus, such that a tester
13 * connected to that external bus can monitor internal buses for debugging purposes.
14 * When mirroring to an IP destination bus like Ethernet, the Bus Mirroring module applies
15 * a protocol to pack several smaller frames (e.g. CAN, LIN or FlexRay) into one large
16 * frame of the destination bus.
17 * For more information, see AUTOSAR "Specification of Bus Mirroring", Section 7.4
18 * "Mirroring to FlexRay, IP, and CDD":
19 * https://www.autosar.org/fileadmin/standards/R22-11/CP/AUTOSAR_SWS_BusMirroring.pdf
23 #include <epan/packet.h>
24 #include <epan/expert.h>
27 #define BUSMIRRORING_UDP_PORT 30511
31 NETWORK_TYPE_INVALID
= 0x00,
32 NETWORK_TYPE_CAN
= 0x01,
33 NETWORK_TYPE_LIN
= 0x02,
34 NETWORK_TYPE_FLEXRAY
= 0x03,
35 NETWORK_TYPE_ETHERNET
= 0x04
38 static int proto_busmirroring
;
39 static int hf_protocol_version
;
40 static int hf_sequence_number
;
41 static int hf_header_timestamp
;
42 static int hf_seconds
;
43 static int hf_nanoseconds
;
44 static int hf_data_length
;
45 static int hf_timestamp
;
46 static int hf_network_state_available
;
47 static int hf_frame_id_available
;
48 static int hf_payload_available
;
49 static int hf_network_type
;
50 static int hf_frames_lost
;
51 static int hf_bus_online
;
52 static int hf_can_error_passive
;
53 static int hf_can_bus_off
;
54 static int hf_can_tx_error_count
;
55 static int hf_lin_header_tx_error
;
56 static int hf_lin_tx_error
;
57 static int hf_lin_rx_error
;
58 static int hf_lin_rx_no_response
;
59 static int hf_flexray_bus_synchronous
;
60 static int hf_flexray_normal_active
;
61 static int hf_flexray_syntax_error
;
62 static int hf_flexray_content_error
;
63 static int hf_flexray_boundary_violation
;
64 static int hf_flexray_tx_conflict
;
65 static int hf_network_id
;
66 static int hf_network_state
;
67 static int hf_frame_id
;
68 static int hf_can_id_type
;
69 static int hf_can_frame_type
;
71 static int hf_lin_pid
;
72 static int hf_flexray_channel_b
;
73 static int hf_flexray_channel_a
;
74 static int hf_flexray_slot_valid
;
75 static int hf_flexray_slot_id
;
76 static int hf_flexray_cycle
;
77 static int hf_payload_length
;
78 static int hf_payload
;
79 static int ett_busmirroring
;
80 static int ett_header_timestamp
;
81 static int ett_data_item
;
82 static int ett_network_state
;
83 static int ett_frame_id
;
84 static expert_field ei_data_incomplete
;
85 static expert_field ei_data_item_incomplete
;
86 static expert_field ei_network_type_invalid
;
87 static expert_field ei_can_id_invalid
;
88 static expert_field ei_lin_pid_invalid
;
89 static expert_field ei_can_length_invalid
;
90 static expert_field ei_lin_length_invalid
;
92 static const uint8_t pid_table
[] = {
93 0x80, 0xC1, 0x42, 0x03, 0xC4, 0x85, 0x06, 0x47,
94 0x08, 0x49, 0xCA, 0x8B, 0x4C, 0x0D, 0x8E, 0xCF,
95 0x50, 0x11, 0x92, 0xD3, 0x14, 0x55, 0xD6, 0x97,
96 0xD8, 0x99, 0x1A, 0x5B, 0x9C, 0xDD, 0x5E, 0x1F,
97 0x20, 0x61, 0xE2, 0xA3, 0x64, 0x25, 0xA6, 0xE7,
98 0xA8, 0xE9, 0x6A, 0x2B, 0xEC, 0xAD, 0x2E, 0x6F,
99 0xF0, 0xB1, 0x32, 0x73, 0xB4, 0xF5, 0x76, 0x37,
100 0x78, 0x39, 0xBA, 0xFB, 0x3C, 0x7D, 0xFE, 0xBF
103 static bool is_lin_pid_valid(uint8_t pid
) {
104 return pid
== pid_table
[pid
& 0x3F];
108 dissect_busmirroring(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree _U_
, void *data _U_
)
110 static const uint32_t header_size
= 14;
111 uint32_t buffer_length
= tvb_captured_length(tvb
);
112 if (buffer_length
< header_size
)
116 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "BUSMIRRORING");
118 proto_item
*ti
= proto_tree_add_item(tree
, proto_busmirroring
, tvb
, 0, -1, ENC_NA
);
119 proto_tree
*busmirroring_tree
= proto_item_add_subtree(ti
, ett_busmirroring
);
120 proto_tree_add_item(busmirroring_tree
, hf_protocol_version
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
121 proto_tree_add_item(busmirroring_tree
, hf_sequence_number
, tvb
, 1, 1, ENC_BIG_ENDIAN
);
122 nstime_t header_timestamp
= {0, 0};
123 header_timestamp
.secs
= tvb_get_uint48(tvb
, 2, ENC_BIG_ENDIAN
);
124 header_timestamp
.nsecs
= tvb_get_uint32(tvb
, 8, ENC_BIG_ENDIAN
);
125 proto_item
*ht_item
= proto_tree_add_time(busmirroring_tree
, hf_header_timestamp
, tvb
, 2, 10, &header_timestamp
);
126 proto_tree
*ht_tree
= proto_item_add_subtree(ht_item
, ett_header_timestamp
);
127 proto_tree_add_item(ht_tree
, hf_seconds
, tvb
, 2, 6, ENC_BIG_ENDIAN
);
128 proto_tree_add_item(ht_tree
, hf_nanoseconds
, tvb
, 8, 4, ENC_BIG_ENDIAN
);
129 uint32_t data_length
= 0;
130 proto_tree_add_item_ret_uint(busmirroring_tree
, hf_data_length
, tvb
, 12, 2, ENC_BIG_ENDIAN
, &data_length
);
131 if (header_size
+ data_length
> buffer_length
) {
132 expert_add_info(pinfo
, ti
, &ei_data_incomplete
);
135 int data_item_index
= 0;
136 uint32_t offset
= header_size
;
137 while (offset
< buffer_length
)
139 int data_item_start
= offset
;
140 proto_item
*data_item
= proto_tree_add_item(busmirroring_tree
, proto_busmirroring
, tvb
, offset
, 0, ENC_NA
);
141 proto_item_set_text(data_item
, "Data Item #%d", data_item_index
);
143 col_clear(pinfo
->cinfo
, COL_INFO
);
144 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Busmirroring Seq=%u Len=%u DataItem=%u",
145 tvb_get_uint8(tvb
, 1), tvb_get_uint16(tvb
, 12, ENC_BIG_ENDIAN
), data_item_index
);
146 if (offset
+ 2 > buffer_length
) {
147 expert_add_info(pinfo
, data_item
, &ei_data_item_incomplete
);
148 return buffer_length
;
150 proto_tree
*data_tree
= proto_item_add_subtree(data_item
, ett_data_item
);
151 proto_tree_add_item(data_tree
, hf_timestamp
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
153 proto_item_set_len(data_item
, offset
- data_item_start
);
155 if (offset
+ 1 > buffer_length
) {
156 expert_add_info(pinfo
, data_item
, &ei_data_item_incomplete
);
157 return buffer_length
;
159 uint8_t flags
= tvb_get_uint8(tvb
, offset
);
160 proto_tree_add_item(data_tree
, hf_network_state_available
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
161 proto_tree_add_item(data_tree
, hf_frame_id_available
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
162 proto_tree_add_item(data_tree
, hf_payload_available
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
163 proto_tree_add_item(data_tree
, hf_network_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
165 proto_item_set_len(data_item
, offset
- data_item_start
);
167 if (offset
+ 1 > buffer_length
) {
168 expert_add_info(pinfo
, data_item
, &ei_data_item_incomplete
);
169 return buffer_length
;
171 proto_tree_add_item(data_tree
, hf_network_id
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
173 proto_item_set_len(data_item
, offset
- data_item_start
);
175 bool is_can_fd
= false;
176 uint8_t type
= flags
& 0x1F;
179 case NETWORK_TYPE_CAN
:
181 proto_item_append_text(data_item
, ": CAN");
184 case NETWORK_TYPE_LIN
:
186 proto_item_append_text(data_item
, ": LIN");
189 case NETWORK_TYPE_FLEXRAY
:
191 proto_item_append_text(data_item
, ": FlexRay");
195 expert_add_info(pinfo
, data_item
, &ei_network_type_invalid
);
198 uint8_t has_network_state
= flags
& 0x80;
199 if (has_network_state
)
201 if (offset
+ 1 > buffer_length
) {
202 expert_add_info(pinfo
, data_item
, &ei_data_item_incomplete
);
203 return buffer_length
;
205 proto_item
*ns_item
= proto_tree_add_item(data_item
, hf_network_state
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
206 proto_tree
*ns_tree
= proto_item_add_subtree(ns_item
, ett_network_state
);
207 proto_tree_add_item(ns_tree
, hf_frames_lost
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
208 proto_tree_add_item(ns_tree
, hf_bus_online
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
211 case NETWORK_TYPE_CAN
:
213 proto_tree_add_item(ns_tree
, hf_can_error_passive
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
214 proto_tree_add_item(ns_tree
, hf_can_bus_off
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
215 proto_tree_add_item(ns_tree
, hf_can_tx_error_count
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
218 case NETWORK_TYPE_LIN
:
220 proto_tree_add_item(ns_tree
, hf_lin_header_tx_error
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
221 proto_tree_add_item(ns_tree
, hf_lin_tx_error
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
222 proto_tree_add_item(ns_tree
, hf_lin_rx_error
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
223 proto_tree_add_item(ns_tree
, hf_lin_rx_no_response
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
226 case NETWORK_TYPE_FLEXRAY
:
228 proto_tree_add_item(ns_tree
, hf_flexray_bus_synchronous
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
229 proto_tree_add_item(ns_tree
, hf_flexray_normal_active
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
230 proto_tree_add_item(ns_tree
, hf_flexray_syntax_error
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
231 proto_tree_add_item(ns_tree
, hf_flexray_content_error
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
232 proto_tree_add_item(ns_tree
, hf_flexray_boundary_violation
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
233 proto_tree_add_item(ns_tree
, hf_flexray_tx_conflict
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
239 proto_item_set_len(data_item
, offset
- data_item_start
);
241 uint8_t has_frame_id
= flags
& 0x40;
246 case NETWORK_TYPE_CAN
:
248 if (offset
+ 4 > buffer_length
) {
249 expert_add_info(pinfo
, data_item
, &ei_data_item_incomplete
);
250 return buffer_length
;
252 proto_item
*frame_id_item
= proto_tree_add_item(data_item
, hf_frame_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
253 proto_tree
*frame_id_tree
= proto_item_add_subtree(frame_id_item
, ett_frame_id
);
254 uint8_t can_id_type
= tvb_get_uint8(tvb
, offset
) & 0x80;
255 is_can_fd
= tvb_get_uint8(tvb
, offset
) & 0x40;
256 proto_tree_add_item(frame_id_tree
, hf_can_id_type
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
257 proto_tree_add_item(frame_id_tree
, hf_can_frame_type
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
259 proto_tree_add_item_ret_uint(frame_id_tree
, hf_can_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &can_id
);
260 if (can_id_type
== 0 && can_id
> 0x7FF) {
261 expert_add_info(pinfo
, frame_id_item
, &ei_can_id_invalid
);
264 proto_item_set_len(data_item
, offset
- data_item_start
);
267 case NETWORK_TYPE_LIN
:
269 if (offset
+ 1 > buffer_length
) {
270 expert_add_info(pinfo
, data_item
, &ei_data_item_incomplete
);
271 return buffer_length
;
273 proto_item
*frame_id_item
= proto_tree_add_item(data_item
, hf_frame_id
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
274 proto_tree
*frame_id_tree
= proto_item_add_subtree(frame_id_item
, ett_frame_id
);
275 proto_tree_add_item(frame_id_tree
, hf_lin_pid
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
276 uint8_t pid
= tvb_get_uint8(tvb
, offset
);
277 if (!is_lin_pid_valid(pid
)) {
278 expert_add_info(pinfo
, frame_id_item
, &ei_lin_pid_invalid
);
281 proto_item_set_len(data_item
, offset
- data_item_start
);
284 case NETWORK_TYPE_FLEXRAY
:
286 if (offset
+ 3 > buffer_length
) {
287 expert_add_info(pinfo
, data_item
, &ei_data_item_incomplete
);
288 return buffer_length
;
290 proto_item
* frame_id_item
= proto_tree_add_item(data_item
, hf_frame_id
, tvb
, offset
, 3, ENC_BIG_ENDIAN
);
291 proto_tree
*frame_id_tree
= proto_item_add_subtree(frame_id_item
, ett_frame_id
);
292 proto_tree_add_item(frame_id_tree
, hf_flexray_channel_b
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
293 proto_tree_add_item(frame_id_tree
, hf_flexray_channel_a
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
294 proto_tree_add_item(frame_id_tree
, hf_flexray_slot_valid
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
295 proto_tree_add_item(frame_id_tree
, hf_flexray_slot_id
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
297 proto_tree_add_item(frame_id_tree
, hf_flexray_cycle
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
299 proto_item_set_len(data_item
, offset
- data_item_start
);
306 uint8_t has_payload
= flags
& 0x20;
309 if (offset
+ 1 > buffer_length
) {
310 expert_add_info(pinfo
, data_item
, &ei_data_item_incomplete
);
311 return buffer_length
;
314 proto_item
* pi
= proto_tree_add_item_ret_uint(data_item
, hf_payload_length
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &length
);
317 case NETWORK_TYPE_CAN
:
320 if (length
> 8 && length
!=12 && length
!=16 && length
!=20 &&
321 length
!=24 && length
!= 32 && length
!=48 && length
!=64 ) {
322 expert_add_info(pinfo
, pi
, &ei_can_length_invalid
);
326 expert_add_info(pinfo
, pi
, &ei_can_length_invalid
);
331 case NETWORK_TYPE_LIN
:
334 expert_add_info(pinfo
, pi
, &ei_lin_length_invalid
);
342 proto_item_set_len(data_item
, offset
- data_item_start
);
343 if (offset
+ length
> buffer_length
) {
344 expert_add_info(pinfo
, data_item
, &ei_data_item_incomplete
);
345 return buffer_length
;
347 proto_tree_add_item(data_item
, hf_payload
, tvb
, offset
, length
, ENC_NA
);
349 proto_item_set_len(data_item
, offset
- data_item_start
);
354 return buffer_length
;
357 void proto_register_busmirroring(void)
359 static const true_false_string can_id_type_names
= {"Extended", "Standard"};
360 static const true_false_string can_frame_type_names
= {"CAN FD", "CAN 2.0"};
361 static const value_string network_type_names
[] = {
367 static hf_register_info hf
[] = {
368 {&hf_protocol_version
,
369 {"Protocol Version", "busmirroring.protocol_version",
373 {&hf_sequence_number
,
374 {"Sequence Number", "busmirroring.sequence_number",
378 {&hf_header_timestamp
,
379 {"Timestamp", "busmirroring.header_timestamp",
380 FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_UTC
,
384 {"Seconds", "busmirroring.seconds",
389 {"Nanoseconds", "busmirroring.nanoseconds",
394 {"Data Length", "busmirroring.data_length",
399 {"Timestamp(10 µs)", "busmirroring.timestamp",
403 {&hf_network_state_available
,
404 {"Network State", "busmirroring.network_state_available",
406 TFS(&tfs_available_not_available
), 0x80,
408 {&hf_frame_id_available
,
409 {"Frame ID", "busmirroring.frame_id_available",
411 TFS(&tfs_available_not_available
), 0x40,
413 {&hf_payload_available
,
414 {"Payload", "busmirroring.payload_available",
416 TFS(&tfs_available_not_available
), 0x20,
419 {"Network Type", "busmirroring.network_type",
421 VALS(network_type_names
), 0x1F,
424 {"Network ID", "busmirroring.network_id",
429 {"Network State", "busmirroring.network_state",
434 {"Frames Lost", "busmirroring.frames_lost",
439 {"Bus Online", "busmirroring.bus_online",
443 {&hf_can_error_passive
,
444 {"Error-Passive", "busmirroring.can_error_passive",
449 {"Bus-Off", "busmirroring.can_bus_off",
453 {&hf_can_tx_error_count
,
454 {"Tx Error Count(divided by 8)", "busmirroring.can_tx_error_count",
458 {&hf_lin_header_tx_error
,
459 {"Header Tx Error", "busmirroring.lin_header_tx_error",
464 {"Tx Error", "busmirroring.lin_tx_error",
469 {"Rx Error", "busmirroring.lin_rx_error",
473 {&hf_lin_rx_no_response
,
474 {"Rx No Response", "busmirroring.lin_rx_no_response",
478 {&hf_flexray_bus_synchronous
,
479 {"Bus Synchronous", "busmirroring.flexray_bus_synchronous",
483 {&hf_flexray_normal_active
,
484 {"Normal Active", "busmirroring.flexray_normal_active",
488 {&hf_flexray_syntax_error
,
489 {"Syntax Error", "busmirroring.flexray_syntax_error",
493 {&hf_flexray_content_error
,
494 {"Content Error", "busmirroring.flexray_content_error",
498 {&hf_flexray_boundary_violation
,
499 {"Boundary Violation", "busmirroring.flexray_boundary_violation",
503 {&hf_flexray_tx_conflict
,
504 {"Tx Conflict", "busmirroring.flexray_tx_conflict",
509 {"Frame ID", "busmirroring.frame_id",
514 {"CAN ID Type", "busmirroring.can_id_type",
516 TFS(&can_id_type_names
), 0x80000000,
519 {"CAN Frame Type", "busmirroring.can_frame_type",
521 TFS(&can_frame_type_names
), 0x40000000,
524 {"CAN ID", "busmirroring.can_id",
525 FT_UINT32
, BASE_HEX_DEC
,
529 {"LIN PID", "busmirroring.lin_pid",
530 FT_UINT8
, BASE_HEX_DEC
,
533 {&hf_flexray_channel_b
,
534 {"Channel B", "busmirroring.flexray_channel_b",
536 TFS(&tfs_available_not_available
), 0x8000,
538 {&hf_flexray_channel_a
,
539 {"Channel A", "busmirroring.flexray_channel_a",
541 TFS(&tfs_available_not_available
), 0x4000,
543 {&hf_flexray_slot_valid
,
544 {"Slot", "busmirroring.flexray_slot_valid",
546 TFS(&tfs_valid_not_valid
), 0x0800,
548 {&hf_flexray_slot_id
,
549 {"Slot ID", "busmirroring.flexray_slot_id",
550 FT_UINT16
, BASE_HEX_DEC
,
554 {"Cycle", "busmirroring.flexray_cycle",
559 {"Payload Length", "busmirroring.payload_length",
564 {"Payload", "busmirroring.payload",
569 /* Setup protocol subtree array */
570 static int *ett
[] = {
572 &ett_header_timestamp
,
577 proto_busmirroring
= proto_register_protocol("Bus Mirroring Protocol", "BusMirroring", "busmirroring");
579 proto_register_field_array(proto_busmirroring
, hf
, array_length(hf
));
580 proto_register_subtree_array(ett
, array_length(ett
));
582 static ei_register_info ei
[] = {
585 { "busmirroring.data_incomplete", PI_UNDECODED
, PI_WARN
,
586 "Data is incomplete", EXPFILL
}
589 &ei_data_item_incomplete
,
590 { "busmirroring.data_item_incomplete", PI_UNDECODED
, PI_WARN
,
591 "Data item is incomplete", EXPFILL
}
594 &ei_network_type_invalid
,
595 { "busmirroring.network_type_invalid", PI_PROTOCOL
, PI_WARN
,
596 "Network type is invalid", EXPFILL
}
600 { "busmirroring.can_id_invalid", PI_PROTOCOL
, PI_WARN
,
601 "ID of CAN frame is invalid", EXPFILL
}
605 { "busmirroring.lin_pid_invalid", PI_PROTOCOL
, PI_WARN
,
606 "PID of LIN frame is invalid", EXPFILL
}
609 &ei_can_length_invalid
,
610 { "busmirroring.can_length_invalid", PI_PROTOCOL
, PI_WARN
,
611 "Length of CAN frame is invalid", EXPFILL
}
614 &ei_lin_length_invalid
,
615 { "busmirroring.lin_length_invalid", PI_PROTOCOL
, PI_WARN
,
616 "Length of LIN frame is invalid", EXPFILL
}
620 expert_module_t
* expert_busmirroring
= expert_register_protocol(proto_busmirroring
);
621 expert_register_field_array(expert_busmirroring
, ei
, array_length(ei
));
624 void proto_reg_handoff_busmirroring(void)
626 static dissector_handle_t busmirroring_handle
;
628 busmirroring_handle
= create_dissector_handle(dissect_busmirroring
, proto_busmirroring
);
629 dissector_add_uint_with_preference("udp.port", BUSMIRRORING_UDP_PORT
, busmirroring_handle
);
630 dissector_add_for_decode_as("udp.port", busmirroring_handle
);
634 * Editor modelines - https://www.wireshark.org/tools/modelines.html
639 * indent-tabs-mode: nil
642 * ex: set shiftwidth=2 tabstop=8 expandtab:
643 * :indentSize=2:tabSize=8:noTabs=true: