1 /* packet-netanalyzer.c
2 * Dissector for Hilscher netANALYZER frames.
3 * Copyright 2008-2016, Hilscher GmbH, Holger Pfrommer hpfrommer[AT]hilscher.com
6 * +---------------------------+
9 * +---------------------------+
16 * The header field contains a 32-bit value in little-endian byte order.
17 * The low-order 8 bits are a set of error flags for the packet:
18 * 0x00000001 - MII RX_ER
19 * 0x00000002 - alignment error
20 * 0x00000004 - FCS error
21 * 0x00000008 - frame too long
22 * 0x00000010 - SFD error
23 * 0x00000020 - frame shorter than 64 bytes
24 * 0x00000040 - preamble shorter than 7 bytes
25 * 0x00000080 - preamble longer than 7 bytes/li>
26 * The next bit, 0x00000100, is set if the packet arrived on the GPIO port rather tha the Ethernet port.
27 * The next bit, 0x00000200, is set if the packet was received in transparent capture mode.
28 * That should never be set for LINKTYPE_NETANALYZER and should always be set for LINKTYPE_NETANALYZER_TRANSPARENT.
29 * The next 4 bits, 0x00003C00, are a bitfield giving the version of the header field; version can be 1 or 2.
30 * The next 2 bits, 0x0000C000, are the capture port/GPIO number, from 0 to 3.
31 * The next 12 bits, 0x0FFF0000, are the frame length, in bytes.
32 * The topmost 4 bits, 0xF0000000, for version 2 header, these bits are the type of the following packet
33 * (0: Ethernet, 1: PROFIBUS, 2: buffer state entry, 3: timetick, 4..15: reserved).
34 * The payload is an Ethernet frame, beginning with the MAC header and ending with the FCS, for LINKTYPE_NETANALYZER,
35 * and an Ethernet frame, beginning with the preamble and ending with the FCS, for LINKTYPE_NETANALYZER_TRANSPARENT.
38 * Wireshark - Network traffic analyzer
39 * By Gerald Combs <gerald[AT]wireshark.org>
40 * Copyright 1999 Gerald Combs
42 * SPDX-License-Identifier: GPL-2.0-or-later
48 #include <epan/packet.h>
49 #include <epan/expert.h>
50 #include <wiretap/wtap.h>
52 void proto_register_netanalyzer(void);
53 void proto_reg_handoff_netanalyzer(void);
55 static dissector_handle_t netana_handle
;
56 static dissector_handle_t netana_handle_transparent
;
59 #define INFO_TYPE_OFFSET 18
61 #define MSK_RX_ERR 0x01
62 #define MSK_ALIGN_ERR 0x02
63 #define MSK_FCS_ERROR 0x04
64 #define MSK_TOO_LONG 0x08
65 #define MSK_SFD_ERROR 0x10
66 #define MSK_SHORT_FRAME 0x20
67 #define MSK_SHORT_PREAMBLE 0x40
68 #define MSK_LONG_PREAMBLE 0x80
70 static const char *msk_strings
[] = {
71 "MII RX_ER error", /* 0x01 */
72 "Alignment error", /* 0x02 */
73 "FCS error", /* 0x04 */
74 "Frame too long", /* 0x08 */
75 "No valid SFD found", /* 0x10 */
76 "Frame smaller 64 bytes", /* 0x20 */
77 "Preamble shorter than 7 bytes", /* 0x40 */
78 "Preamble longer than 7 bytes" /* 0x80 */
82 #define SRT_PORT_NUM 6
84 #define SRT_GPIO_FLAG 0
85 #define MSK_PACKET_STATUS 0xff
86 #define MSK_LENGTH 0x0fff
87 #define MSK_TRANSPARENT_MODE 0x02
89 #define MSK_BUF_STATE 0x1
91 #define MSK_BUF_ID 0xf0
93 #define VAL_TYPE_ETH 0
95 #define VAL_TYPE_BUF 2
96 #define VAL_TYPE_TICK 3
99 static const value_string gpio_number
[] = {
107 static const value_string gpio_edge_vals
[] = {
108 { 0x0, "Rising edge" },
109 { 0x1, "Falling edge" },
113 static const value_string buf_state_vals
[] = {
114 { 0x0, "Buffer overflow, frames will be dropped until next buffer recovery" },
115 { 0x1, "Buffer recovery, frame reception has recovered" },
119 static const value_string buf_source_vals
[] = {
120 { 0x0, "Backend RX FIFO" },
121 { 0x1, "netX URX FIFO" },
122 { 0x2, "netX INTRAM buffer" },
123 { 0x3, "Host buffer" },
124 { 0x4, "Capture driver (WinPcap)" },
129 static dissector_handle_t eth_dissector_handle
;
131 static int proto_netanalyzer
;
133 static int hf_netanalyzer_gpio
;
134 static int hf_netanalyzer_gpio_number
;
135 static int hf_netanalyzer_gpio_edge
;
136 static int hf_netanalyzer_eth
;
137 static int hf_netanalyzer_port
;
138 static int hf_netanalyzer_length
;
139 static int hf_netanalyzer_status
;
140 static int hf_netanalyzer_status_rx_err
;
141 static int hf_netanalyzer_status_align_err
;
142 static int hf_netanalyzer_status_fcs
;
143 static int hf_netanalyzer_status_too_long
;
144 static int hf_netanalyzer_status_sfd_error
;
145 static int hf_netanalyzer_status_short_frame
;
146 static int hf_netanalyzer_status_short_preamble
;
147 static int hf_netanalyzer_status_long_preamble
;
148 static int hf_netanalyzer_buf
;
149 static int hf_netanalyzer_buf_state
;
150 static int hf_netanalyzer_buf_source
;
151 static int hf_netanalyzer_timetick
;
153 static int * const hfx_netanalyzer_status
[] = {
154 &hf_netanalyzer_status_rx_err
,
155 &hf_netanalyzer_status_align_err
,
156 &hf_netanalyzer_status_fcs
,
157 &hf_netanalyzer_status_too_long
,
158 &hf_netanalyzer_status_sfd_error
,
159 &hf_netanalyzer_status_short_frame
,
160 &hf_netanalyzer_status_short_preamble
,
161 &hf_netanalyzer_status_long_preamble
,
165 static int ett_netanalyzer
;
166 static int ett_netanalyzer_gpio
;
167 static int ett_netanalyzer_status
;
168 static int ett_netanalyzer_transparent
;
169 static int ett_netanalyzer_buf
;
171 static expert_field ei_netanalyzer_header_wrong
;
172 static expert_field ei_netanalyzer_gpio_def_none
;
173 static expert_field ei_netanalyzer_header_none
;
174 static expert_field ei_netanalyzer_transparent_frame
;
175 static expert_field ei_netanalyzer_alignment_error
;
176 static expert_field ei_netanalyzer_not_implemented
;
178 /* common routine for Ethernet and transparent mode */
180 dissect_netanalyzer_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
182 proto_item
*ti
= NULL
;
183 proto_tree
*netanalyzer_header_tree
= NULL
;
184 uint32_t packet_status
;
186 uint32_t frame_length
;
199 /* generate netANALYZER tree */
200 ti
= proto_tree_add_item(tree
, proto_netanalyzer
, tvb
, 0, HEADER_SIZE
, ENC_NA
);
201 netanalyzer_header_tree
= proto_item_add_subtree(ti
, ett_netanalyzer
);
203 is_gpio
= (tvb_get_uint8(tvb
, 1) >> SRT_GPIO_FLAG
) & 0x1;
207 /* normal packet, no GPIO */
210 version
= (tvb_get_uint8(tvb
, 1) >> SRT_VERSION
) & 0xf;
211 type
= (tvb_get_uint32(tvb
, 0, ENC_LITTLE_ENDIAN
) >> SRT_TYPE
) & 0xf;
213 if ((version
== 1) || ((version
== 2) && (type
== VAL_TYPE_ETH
)))
215 proto_tree_add_none_format(netanalyzer_header_tree
, hf_netanalyzer_eth
, tvb
, 0, 0, "Ethernet frame");
218 port_num
= (tvb_get_uint8(tvb
, 1) >> SRT_PORT_NUM
) & 0x3;
219 proto_tree_add_uint(netanalyzer_header_tree
, hf_netanalyzer_port
, tvb
, 0, 4, port_num
);
220 proto_item_append_text(ti
, " (Port: %u, ", port_num
);
223 frame_length
= tvb_get_letohs(tvb
, 2) & MSK_LENGTH
;
224 proto_tree_add_uint(netanalyzer_header_tree
, hf_netanalyzer_length
, tvb
, 0, 4, frame_length
);
225 proto_item_append_text(ti
, "Length: %u byte%s, ", frame_length
, (frame_length
== 1) ? "" : "s");
228 proto_item_append_text(ti
, "Status: ");
229 packet_status
= tvb_get_uint8(tvb
, 0);
230 if (packet_status
== 0)
232 proto_tree_add_uint_format_value(netanalyzer_header_tree
, hf_netanalyzer_status
, tvb
, 0, 1,
233 packet_status
, "No Error");
234 proto_item_append_text(ti
, "No Error)");
238 wmem_strbuf_t
*strbuf
;
241 proto_tree_add_bitmask(netanalyzer_header_tree
, tvb
, 0, hf_netanalyzer_status
, ett_netanalyzer_status
, hfx_netanalyzer_status
, ENC_LITTLE_ENDIAN
);
243 strbuf
= wmem_strbuf_create(pinfo
->pool
);
244 for (idx
= 0; idx
< 8; idx
++)
246 if (packet_status
& (1 << idx
))
254 wmem_strbuf_append(strbuf
, ", ");
256 wmem_strbuf_append(strbuf
, msk_strings
[idx
]);
259 proto_item_append_text(ti
, "%s)", wmem_strbuf_get_str(strbuf
));
262 /* decode transparent mode */
263 if (tvb_get_uint8(tvb
, 1) & MSK_TRANSPARENT_MODE
)
265 proto_tree_add_expert(netanalyzer_header_tree
, pinfo
, &ei_netanalyzer_transparent_frame
, tvb
, 0, 4);
266 proto_item_append_text(ti
, ", Transparent Mode");
268 if (packet_status
& MSK_ALIGN_ERR
)
270 proto_tree_add_expert(netanalyzer_header_tree
, pinfo
, &ei_netanalyzer_alignment_error
, tvb
, tvb_captured_length(tvb
) - 1, 1);
274 else if ((version
== 2) && (type
== VAL_TYPE_PB
))
276 /* currently not implemented */
277 expert_add_info(pinfo
, ti
, &ei_netanalyzer_not_implemented
);
280 else if ((version
== 2) && (type
== VAL_TYPE_BUF
))
282 proto_tree_add_none_format(netanalyzer_header_tree
, hf_netanalyzer_buf
, tvb
, 0, 0, "Buffer state entry");
283 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "netANALYZER");
285 buf_state
= tvb_get_uint8(tvb
, 0) & MSK_BUF_STATE
;
288 col_set_str(pinfo
->cinfo
, COL_INFO
, "Buffer overflow");
292 col_set_str(pinfo
->cinfo
, COL_INFO
, "Buffer recovery");
294 proto_item_append_text(ti
, " (%s)", buf_state_vals
[buf_state
].strptr
);
296 /* decode buffer state */
297 proto_tree_add_uint(ti
, hf_netanalyzer_buf_state
, tvb
, 0, 1, buf_state
);
298 port_num
= (tvb_get_uint8(tvb
, 1) >> SRT_PORT_NUM
) & 0x3;
299 proto_tree_add_uint(ti
, hf_netanalyzer_port
, tvb
, 0, 4, port_num
);
300 buf_source
= (tvb_get_uint8(tvb
, 0) & MSK_BUF_ID
) >> SRT_BUF_ID
;
301 proto_tree_add_uint(ti
, hf_netanalyzer_buf_source
, tvb
, 0, 1, buf_source
);
305 else if ((version
== 2) && (type
== VAL_TYPE_TICK
))
307 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "netANALYZER");
308 col_set_str(pinfo
->cinfo
, COL_INFO
, "Time tick");
309 proto_item_append_text(ti
, " (Time tick)");
310 proto_tree_add_none_format(netanalyzer_header_tree
, hf_netanalyzer_timetick
, tvb
, 0, 0, "Time tick");
315 /* something is wrong */
316 expert_add_info(pinfo
, ti
, &ei_netanalyzer_header_wrong
);
322 unsigned char *szTemp
;
324 /* check consistency */
325 if ( (tvb_get_uint8(tvb
, 10) == 0x00) &&
326 (tvb_get_uint8(tvb
, 11) == 0x02) &&
327 (tvb_get_uint8(tvb
, 12) == 0xa2) &&
328 (tvb_get_uint8(tvb
, 13) == 0xff) &&
329 (tvb_get_uint8(tvb
, 14) == 0xff) &&
330 (tvb_get_uint8(tvb
, 15) == 0xff) &&
331 (tvb_get_uint8(tvb
, 16) == 0x88) &&
332 (tvb_get_uint8(tvb
, 17) == 0xff) &&
333 (tvb_get_uint8(tvb
, INFO_TYPE_OFFSET
) == 0x00) )
335 #define MAX_BUFFER 255
336 szTemp
=(unsigned char *)wmem_alloc(wmem_epan_scope(), MAX_BUFFER
);
339 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "netANALYZER");
340 offset
= INFO_TYPE_OFFSET
;
341 proto_tree_add_none_format(netanalyzer_header_tree
, hf_netanalyzer_gpio
, tvb
, 0, 0, "GPIO event");
342 proto_item_append_text(ti
, " (GPIO event)");
346 proto_tree_add_item (netanalyzer_header_tree
, hf_netanalyzer_gpio_number
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
347 gpio_num
= (tvb_get_uint8(tvb
, offset
) & 0x03);
351 ti
= proto_tree_add_item (netanalyzer_header_tree
, hf_netanalyzer_gpio_edge
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
352 gpio_edge
= (tvb_get_uint8(tvb
, offset
) & 0x01);
354 snprintf(szTemp
, MAX_BUFFER
,
355 "GPIO event on GPIO %d (%sing edge)", gpio_num
, (gpio_edge
== 0x00) ? "ris" : "fall");
357 col_add_str(pinfo
->cinfo
, COL_INFO
, szTemp
);
358 proto_item_append_text(ti
, " %s", szTemp
);
362 /* something is wrong */
363 expert_add_info(pinfo
, ti
, &ei_netanalyzer_gpio_def_none
);
372 /* Ethernet capture mode */
374 dissect_netanalyzer(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
378 if (tvb_reported_length(tvb
) >= 4)
380 /* generate tvb subset for Ethernet frame */
381 if (dissect_netanalyzer_common(tvb
, pinfo
, tree
))
383 /* hand off to eth dissector with the new tvb subset */
384 next_tvb
= tvb_new_subset_remaining(tvb
, 4);
385 call_dissector(eth_dissector_handle
, next_tvb
, pinfo
, tree
);
390 /* something is wrong */
391 proto_tree_add_expert_format(tree
, pinfo
, &ei_netanalyzer_header_none
, tvb
, 4, -1,
392 "netANALYZER - No netANALYZER header found");
394 return tvb_captured_length(tvb
);
398 /* Transparent capture mode */
400 dissect_netanalyzer_transparent(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
402 proto_tree
*transparent_payload_tree
= NULL
;
405 if (tvb_reported_length(tvb
) >= 4)
407 /* generate tvb subset for Ethernet frame */
408 if (dissect_netanalyzer_common(tvb
, pinfo
, tree
))
410 /* do not hand off transparent packet for further Ethernet dissectors
411 * as normally the transparent mode is used for low level analysis
412 * where dissecting the frame's content wouldn't make much sense
413 * use data dissector instead */
414 transparent_payload_tree
= proto_tree_add_subtree(tree
, tvb
, 4, tvb_captured_length(tvb
)-4,
415 ett_netanalyzer_transparent
, NULL
, "Raw packet data");
416 next_tvb
= tvb_new_subset_remaining(tvb
, 4);
417 call_data_dissector(next_tvb
, pinfo
, transparent_payload_tree
);
419 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "netANALYZER");
420 col_set_str(pinfo
->cinfo
, COL_INFO
, "Frame captured in transparent mode");
425 /* something is wrong */
426 proto_tree_add_expert_format(tree
, pinfo
, &ei_netanalyzer_header_none
, tvb
, 4, -1,
427 "netANALYZER transparent mode - No netANALYZER header found");
429 return tvb_captured_length(tvb
);
433 void proto_register_netanalyzer(void)
435 static hf_register_info hf
[] = {
436 { &hf_netanalyzer_gpio
,
437 { "GPIO event", "netanalyzer.gpio_event",
438 FT_NONE
, BASE_NONE
, NULL
, 0x0,
439 "Shows the occurrence of an digital switching event", HFILL
}
441 { &hf_netanalyzer_gpio_number
,
442 { "GPIO event on", "netanalyzer.gpio_event.gpio_number",
443 FT_UINT8
, BASE_HEX
, VALS(gpio_number
), 0x0,
444 "GPIO event on GPIO number", HFILL
}
446 { &hf_netanalyzer_gpio_edge
,
447 { "GPIO event type", "netanalyzer.gpio_event.gpio_edge",
448 FT_UINT8
, BASE_HEX
, VALS(gpio_edge_vals
), 0x0,
449 "GPIO edge of GPIO event", HFILL
}
451 { &hf_netanalyzer_eth
,
452 { "Ethernet frame", "netanalyzer.eth",
453 FT_NONE
, BASE_NONE
, NULL
, 0x0,
454 "This is an Ethernet frame", HFILL
}
456 { &hf_netanalyzer_port
,
457 { "Reception Port", "netanalyzer.port",
458 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
459 "netANALYZER reception port", HFILL
}
461 { &hf_netanalyzer_length
,
462 { "Ethernet frame length", "netanalyzer.framelen",
463 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
464 "Actual Ethernet frame length", HFILL
}
466 { &hf_netanalyzer_status
,
467 { "Status", "netanalyzer.packetstatus",
468 FT_UINT8
, BASE_HEX
, NULL
, MSK_PACKET_STATUS
,
469 "Status of Ethernet frame", HFILL
}
471 { &hf_netanalyzer_status_rx_err
,
472 { "MII RX_ER error", "netanalyzer.packetstatus.rx_er",
473 FT_BOOLEAN
, 8, NULL
, MSK_RX_ERR
,
474 "RX_ER detected in frame", HFILL
}
476 { &hf_netanalyzer_status_align_err
,
477 { "Alignment error", "netanalyzer.packetstatus.alignment_error",
478 FT_BOOLEAN
, 8, NULL
, MSK_ALIGN_ERR
,
481 { &hf_netanalyzer_status_fcs
,
482 { "FCS error", "netanalyzer.packetstatus.fcs_error",
483 FT_BOOLEAN
, 8, NULL
, MSK_FCS_ERROR
,
486 { &hf_netanalyzer_status_too_long
,
487 { "Frame too long", "netanalyzer.packetstatus.too_long",
488 FT_BOOLEAN
, 8, NULL
, MSK_TOO_LONG
,
489 "Frame too long (capture truncated)", HFILL
}
491 { &hf_netanalyzer_status_sfd_error
,
492 { "No valid SFD found", "netanalyzer.packetstatus.sfd_error",
493 FT_BOOLEAN
, 8, NULL
, MSK_SFD_ERROR
,
494 "SDF error detected in frame", HFILL
}
496 { &hf_netanalyzer_status_short_frame
,
497 { "Frame smaller 64 bytes", "netanalyzer.packetstatus.short_frame",
498 FT_BOOLEAN
, 8, NULL
, MSK_SHORT_FRAME
,
501 { &hf_netanalyzer_status_short_preamble
,
502 { "Preamble shorter than 7 bytes", "netanalyzer.packetstatus.short_preamble",
503 FT_BOOLEAN
, 8, NULL
, MSK_SHORT_PREAMBLE
,
506 { &hf_netanalyzer_status_long_preamble
,
507 { "Preamble longer than 7 bytes", "netanalyzer.packetstatus.long_preamble",
508 FT_BOOLEAN
, 8, NULL
, MSK_LONG_PREAMBLE
,
511 { &hf_netanalyzer_buf
,
512 { "Buffer state entry", "netanalyzer.buffer",
513 FT_NONE
, BASE_NONE
, NULL
, 0x0,
514 "Info about reception buffer conditions", HFILL
}
516 { &hf_netanalyzer_buf_state
,
517 { "Buffer state", "netanalyzer.buffer.state",
518 FT_UINT8
, BASE_DEC
, VALS(buf_state_vals
), 0x0,
519 "State of receive buffers", HFILL
}
521 { &hf_netanalyzer_buf_source
,
522 { "Buffer source", "netanalyzer.buffer.source",
523 FT_UINT8
, BASE_DEC
, VALS(buf_source_vals
), 0x0,
524 "Source of buffer error", HFILL
}
526 { &hf_netanalyzer_timetick
,
527 { "Time tick", "netanalyzer.timetick",
528 FT_NONE
, BASE_NONE
, NULL
, 0x0,
529 "Cyclic time tick of netANALYZER device", HFILL
}
533 static int *ett
[] = {
535 &ett_netanalyzer_gpio
,
536 &ett_netanalyzer_status
,
537 &ett_netanalyzer_transparent
,
538 &ett_netanalyzer_buf
,
541 static ei_register_info ei
[] = {
542 { &ei_netanalyzer_header_wrong
, { "netanalyzer.header.wrong", PI_PROTOCOL
, PI_ERROR
, "Wrong netANALYZER header", EXPFILL
}},
543 { &ei_netanalyzer_gpio_def_none
, { "netanalyzer.gpio_def_none", PI_MALFORMED
, PI_ERROR
, "No valid netANALYZER GPIO definition found", EXPFILL
}},
544 { &ei_netanalyzer_header_none
, { "netanalyzer.header.none", PI_MALFORMED
, PI_ERROR
, "No netANALYZER header found", EXPFILL
}},
545 { &ei_netanalyzer_transparent_frame
, { "netanalyzer.transparent_frame", PI_PROTOCOL
, PI_NOTE
, "This frame was captured in transparent mode", EXPFILL
}},
546 { &ei_netanalyzer_alignment_error
, { "netanalyzer.alignment_error", PI_PROTOCOL
, PI_WARN
, "Displayed frame data contains additional nibble due to alignment error (upper nibble is not valid)", EXPFILL
}},
547 { &ei_netanalyzer_not_implemented
,{ "netanalyzer.not_implemented", PI_PROTOCOL
, PI_ERROR
, "This feature is currently not implemented in Wireshark", EXPFILL
} },
550 expert_module_t
* expert_netanalyzer
;
552 proto_netanalyzer
= proto_register_protocol (
553 "netANALYZER", /* name */
554 "netANALYZER", /* short name */
555 "netanalyzer" ); /* abbrev */
557 proto_register_field_array(proto_netanalyzer
, hf
, array_length(hf
));
558 proto_register_subtree_array(ett
, array_length(ett
));
559 expert_netanalyzer
= expert_register_protocol(proto_netanalyzer
);
560 expert_register_field_array(expert_netanalyzer
, ei
, array_length(ei
));
562 netana_handle
= register_dissector("netanalyzer", dissect_netanalyzer
, proto_netanalyzer
);
563 netana_handle_transparent
= register_dissector("netanalyzer_transparent", dissect_netanalyzer_transparent
, proto_netanalyzer
);
567 void proto_reg_handoff_netanalyzer(void)
569 eth_dissector_handle
= find_dissector_add_dependency("eth_withfcs", proto_netanalyzer
);
570 dissector_add_uint("wtap_encap", WTAP_ENCAP_NETANALYZER
, netana_handle
);
571 dissector_add_uint("wtap_encap", WTAP_ENCAP_NETANALYZER_TRANSPARENT
, netana_handle_transparent
);
575 * Editor modelines - https://www.wireshark.org/tools/modelines.html
580 * indent-tabs-mode: nil
583 * ex: set shiftwidth=2 tabstop=8 expandtab:
584 * :indentSize=2:tabSize=8:noTabs=true: