2 * Routines for Robot Operating System TCP protocol (TCPROS)
3 * Copyright 2015, Guillaume Autran (see AUTHORS file)
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
14 #include <epan/packet.h>
15 #include <epan/etypes.h>
16 #include <epan/prefs.h>
18 #include "packet-tcp.h"
21 #define SIZE_OF_LENGTH_FIELD 4
22 #define SIZE_OF_LENGTH_STAMP (4 + 4)
24 void proto_register_tcpros(void);
25 void proto_reg_handoff_tcpros(void);
28 static int proto_tcpros
;
29 static dissector_handle_t tcpros_handle
;
31 /** desegmentation of TCPROS over TCP */
32 static bool tcpros_desegment
= true;
35 static int hf_tcpros_connection_header
;
36 static int hf_tcpros_connection_header_length
;
37 static int hf_tcpros_connection_header_content
;
38 static int hf_tcpros_connection_header_field
;
39 static int hf_tcpros_connection_header_field_length
;
40 static int hf_tcpros_connection_header_field_data
;
41 static int hf_tcpros_connection_header_field_name
;
42 static int hf_tcpros_connection_header_field_value
;
43 static int hf_tcpros_clock
;
44 static int hf_tcpros_clock_length
;
45 static int hf_tcpros_message
;
46 static int hf_tcpros_message_length
;
47 static int hf_tcpros_message_body
;
48 static int hf_tcpros_message_header
;
49 static int hf_tcpros_message_header_seq
;
50 static int hf_tcpros_message_header_stamp
;
51 static int hf_tcpros_message_header_stamp_sec
;
52 static int hf_tcpros_message_header_stamp_nsec
;
53 static int hf_tcpros_message_header_frame
;
54 static int hf_tcpros_message_header_frame_length
;
55 static int hf_tcpros_message_header_frame_value
;
56 static int hf_tcpros_message_payload
;
58 static int ett_tcpros
;
61 * This is the ROS connection header dissector. The general packet format is described
62 * here: http://wiki.ros.org/ROS/TCPROS
63 * In short, a connection header looks like such: '4-byte length + [4-byte field length + "field=value" ]*'
66 dissect_ros_connection_header_field(tvbuff_t
*tvb
, proto_tree
*tree
, packet_info
*pinfo
, int offset
)
69 proto_tree
*field_tree
;
74 /** Do we have enough for a length field? (ie: 4 bytes) */
75 if( tvb_reported_length_remaining(tvb
, offset
) > SIZE_OF_LENGTH_FIELD
) {
76 /** Get the length of the next field */
77 fLen
= tvb_get_letohl(tvb
, offset
);
79 /** Display the field as a utf-8 string */
80 ti
= proto_tree_add_item(tree
, hf_tcpros_connection_header_field
, tvb
, offset
, SIZE_OF_LENGTH_FIELD
, ENC_UTF_8
|ENC_LITTLE_ENDIAN
);
81 field_tree
= proto_item_add_subtree(ti
, ett_tcpros
);
84 proto_tree_add_item(field_tree
, hf_tcpros_connection_header_field_length
, tvb
, offset
, SIZE_OF_LENGTH_FIELD
, ENC_LITTLE_ENDIAN
);
85 offset
+= SIZE_OF_LENGTH_FIELD
;
86 ti
= proto_tree_add_item(field_tree
, hf_tcpros_connection_header_field_data
, tvb
, offset
, fLen
, ENC_UTF_8
);
88 /** Look for the '=' separator */
89 sep
= (tvb_find_uint8(tvb
, offset
, fLen
, '=') - offset
);
91 /** If we find a separator, then split field name and value */
94 field_tree
= proto_item_add_subtree(ti
, ett_tcpros
);
95 proto_tree_add_item_ret_string(field_tree
, hf_tcpros_connection_header_field_name
, tvb
, offset
, sep
, ENC_UTF_8
|ENC_NA
, pinfo
->pool
, &field
);
96 proto_tree_add_item(field_tree
, hf_tcpros_connection_header_field_value
, tvb
, offset
+sep
+1, fLen
- sep
- 1, ENC_UTF_8
);
98 col_append_str(pinfo
->cinfo
, COL_INFO
, field
);
100 ret
= fLen
+ SIZE_OF_LENGTH_FIELD
;
107 dissect_ros_connection_header(tvbuff_t
*tvb
, proto_tree
*root_tree
, packet_info
*pinfo
, int offset
)
110 proto_tree
*sub_tree
;
112 int consumed_len
= 0;
113 uint32_t header_len
= tvb_get_letohl(tvb
, offset
);
115 col_append_str(pinfo
->cinfo
, COL_INFO
, "[ROS Conn] Metadata: [");
117 /** We got a connection header */
118 ti
= proto_tree_add_item(root_tree
, hf_tcpros_connection_header
, tvb
, offset
, SIZE_OF_LENGTH_FIELD
, ENC_NA
|ENC_LITTLE_ENDIAN
);
119 sub_tree
= proto_item_add_subtree(ti
, ett_tcpros
);
121 proto_tree_add_item(sub_tree
, hf_tcpros_connection_header_length
, tvb
, offset
+ consumed_len
, SIZE_OF_LENGTH_FIELD
, ENC_LITTLE_ENDIAN
);
122 consumed_len
+= SIZE_OF_LENGTH_FIELD
;
124 ti
= proto_tree_add_item(sub_tree
, hf_tcpros_connection_header_content
, tvb
, offset
+ consumed_len
, header_len
, ENC_NA
);
125 sub_tree
= proto_item_add_subtree(ti
, ett_tcpros
);
127 header_len
+= SIZE_OF_LENGTH_FIELD
;
129 while( consumed_len
< (int)header_len
) {
130 int len
= dissect_ros_connection_header_field(tvb
, sub_tree
, pinfo
, offset
+ consumed_len
);
135 if( consumed_len
< (int)header_len
) {
136 col_append_str(pinfo
->cinfo
, COL_INFO
, ",");
139 col_append_str(pinfo
->cinfo
, COL_INFO
, "]");
146 dissect_ros_message_header_stamp(tvbuff_t
*tvb
, proto_tree
*root_tree
, packet_info
*pinfo
, int offset
)
149 proto_tree
*sub_tree
;
151 int consumed_len
= 0;
154 ti
= proto_tree_add_item(root_tree
, hf_tcpros_message_header_stamp
, tvb
, offset
+ consumed_len
, SIZE_OF_LENGTH_STAMP
, ENC_LITTLE_ENDIAN
);
155 sub_tree
= proto_item_add_subtree(ti
, ett_tcpros
);
158 proto_tree_add_item(sub_tree
, hf_tcpros_message_header_stamp_sec
, tvb
, offset
+ consumed_len
, SIZE_OF_LENGTH_FIELD
, ENC_LITTLE_ENDIAN
);
159 sec
= tvb_get_letohl(tvb
, offset
+ consumed_len
);
160 consumed_len
+= SIZE_OF_LENGTH_FIELD
;
163 proto_tree_add_item(sub_tree
, hf_tcpros_message_header_stamp_nsec
, tvb
, offset
+ consumed_len
, SIZE_OF_LENGTH_FIELD
, ENC_LITTLE_ENDIAN
);
164 nsec
= tvb_get_letohl(tvb
, offset
+ consumed_len
);
165 consumed_len
+= SIZE_OF_LENGTH_FIELD
;
168 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "Timestamp: %d.%09d ", sec
, nsec
);
174 dissect_ros_clock(tvbuff_t
*tvb
, proto_tree
*root_tree
, packet_info
*pinfo
, int offset
)
177 proto_tree
*sub_tree
;
179 int consumed_len
= 0;
181 col_append_str(pinfo
->cinfo
, COL_INFO
, "[ROS Clock] ");
183 /** We got a ROS Clock msg */
184 ti
= proto_tree_add_item(root_tree
, hf_tcpros_clock
, tvb
, offset
, SIZE_OF_LENGTH_FIELD
, ENC_LITTLE_ENDIAN
);
185 sub_tree
= proto_item_add_subtree(ti
, ett_tcpros
);
187 proto_tree_add_item(sub_tree
, hf_tcpros_clock_length
, tvb
, offset
, SIZE_OF_LENGTH_FIELD
, ENC_LITTLE_ENDIAN
);
188 consumed_len
+= SIZE_OF_LENGTH_FIELD
;
190 consumed_len
+= dissect_ros_message_header_stamp(tvb
, sub_tree
, pinfo
, offset
+ consumed_len
);
196 dissect_ros_message_header(tvbuff_t
*tvb
, proto_tree
*root_tree
, packet_info
*pinfo
, int offset
)
199 proto_tree
*sub_tree
;
201 int consumed_len
= 0;
202 uint32_t frame_id_len
;
205 const uint8_t* frame_str
;
208 frame_id_len
= tvb_get_letohl(tvb
, offset
+ consumed_len
+ SIZE_OF_LENGTH_FIELD
+ SIZE_OF_LENGTH_STAMP
);
209 header_len
= SIZE_OF_LENGTH_FIELD
+ SIZE_OF_LENGTH_STAMP
+ SIZE_OF_LENGTH_FIELD
+ frame_id_len
;
212 ti
= proto_tree_add_item(root_tree
, hf_tcpros_message_header
, tvb
, offset
+ consumed_len
, header_len
, ENC_NA
);
213 sub_tree
= proto_item_add_subtree(ti
, ett_tcpros
);
215 /** Sequence number */
216 proto_tree_add_item(sub_tree
, hf_tcpros_message_header_seq
, tvb
, offset
+ consumed_len
, SIZE_OF_LENGTH_FIELD
, ENC_LITTLE_ENDIAN
);
217 seq
= tvb_get_letohl(tvb
, offset
+ consumed_len
);
218 consumed_len
+= SIZE_OF_LENGTH_FIELD
;
219 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "Seq: %d ", seq
);
222 consumed_len
+= dissect_ros_message_header_stamp(tvb
, sub_tree
, pinfo
, offset
+ consumed_len
);
225 ti
= proto_tree_add_item(sub_tree
, hf_tcpros_message_header_frame
, tvb
, offset
+ consumed_len
, SIZE_OF_LENGTH_FIELD
, ENC_UTF_8
|ENC_LITTLE_ENDIAN
);
226 sub_tree
= proto_item_add_subtree(ti
, ett_tcpros
);
228 proto_tree_add_item(sub_tree
, hf_tcpros_message_header_frame_length
, tvb
, offset
+ consumed_len
, SIZE_OF_LENGTH_FIELD
, ENC_LITTLE_ENDIAN
);
229 consumed_len
+= SIZE_OF_LENGTH_FIELD
;
231 proto_tree_add_item_ret_string(sub_tree
, hf_tcpros_message_header_frame_value
, tvb
, offset
+ consumed_len
, frame_id_len
, ENC_UTF_8
|ENC_NA
, pinfo
->pool
, &frame_str
);
232 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "Frame ID: '%s' ", frame_str
);
233 consumed_len
+= frame_id_len
;
240 * This is the ROS message dissector. A ROS message contains two parts: a msg header; a msg payload.
241 * Because the packet is all in binary format, we don't really know the payload format (we don't know the payload type either).
242 * However, every packet has the same header as defined here: http://docs.ros.org/api/std_msgs/html/msg/Header.html
243 * So, we can break this one down and display it.
246 dissect_ros_message(tvbuff_t
*tvb
, proto_tree
*root_tree
, packet_info
*pinfo
, int offset
)
249 proto_tree
*sub_tree
;
251 int consumed_len
= 0;
252 uint32_t total_len
= tvb_get_letohl(tvb
, offset
);
253 unsigned payload_len
;
255 col_append_str(pinfo
->cinfo
, COL_INFO
, "[ROS Msg] ");
257 /** We got a ROS msg */
258 ti
= proto_tree_add_item(root_tree
, hf_tcpros_message
, tvb
, offset
+ consumed_len
, SIZE_OF_LENGTH_FIELD
, ENC_NA
| ENC_LITTLE_ENDIAN
);
259 sub_tree
= proto_item_add_subtree(ti
, ett_tcpros
);
261 proto_tree_add_item(sub_tree
, hf_tcpros_message_length
, tvb
, offset
+ consumed_len
, SIZE_OF_LENGTH_FIELD
, ENC_LITTLE_ENDIAN
);
262 consumed_len
+= SIZE_OF_LENGTH_FIELD
;
265 ti
= proto_tree_add_item(sub_tree
, hf_tcpros_message_body
, tvb
, offset
+ consumed_len
, total_len
, ENC_NA
);
266 sub_tree
= proto_item_add_subtree(ti
, ett_tcpros
);
269 consumed_len
+= dissect_ros_message_header(tvb
, sub_tree
, pinfo
, offset
+ consumed_len
);
272 payload_len
= (total_len
+ SIZE_OF_LENGTH_FIELD
) - consumed_len
;
273 proto_tree_add_item(sub_tree
, hf_tcpros_message_payload
, tvb
, offset
+ consumed_len
, payload_len
, ENC_NA
);
274 consumed_len
+= payload_len
;
282 * This is the poor man's way to differentiate between a connection header packet and a message packet.
285 is_connection_header(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, unsigned offset
)
287 bool is_con_header
= false;
288 uint32_t len1
= tvb_get_letohl(tvb
, offset
);
289 uint32_t len2
= tvb_get_letohl(tvb
, offset
+ SIZE_OF_LENGTH_FIELD
);
293 is_con_header
= true;
297 return is_con_header
;
301 is_rosheaderfield(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, unsigned offset
)
303 /** ROS Header Field:
304 4-byte len + string */
305 int available
= tvb_reported_length_remaining(tvb
, offset
);
306 uint32_t string_len
= 0;
312 string_len
= tvb_get_letohl(tvb
, offset
);
314 /** If we don't have enough data for the whole string, assume its not */
315 if( (unsigned)available
< (string_len
+ 4) )
317 /** Check for a valid ascii character and not nil */
318 for( i
= 0; i
< string_len
; i
++ ) {
319 int8_t ch
= tvb_get_uint8(tvb
, offset
+ 4 + i
);
320 if( !g_ascii_isalnum(ch
) || 0x00 == ch
)
329 is_rosconnection_header(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, unsigned offset
)
331 /** ROS Connection Headers: http://wiki.ros.org/ROS/Connection%20Header
332 4-byte length + [4-byte length + string] */
333 int available
= tvb_reported_length_remaining(tvb
, offset
);
334 uint32_t msg_len
= 0;
336 if( available
< 8+1 )
339 msg_len
= tvb_get_letohl(tvb
, offset
);
343 /** Check first header field */
344 if( !is_rosheaderfield(tvb
, pinfo
, offset
+ 4) )
352 is_rosclock(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, unsigned offset
)
354 /** ROS Clock message: http://docs.ros.org/api/rosgraph_msgs/html/msg/Clock.html
355 4-byte length + 8-byte timestamp == 12 bytes exactly */
356 int available
= tvb_reported_length_remaining(tvb
, offset
);
357 if( available
!= 12 )
360 if( tvb_get_letohl(tvb
, offset
) != 8 )
363 /** This is highly likely a clock message. */
368 is_rosmsg(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, unsigned offset
)
370 /** Most ROS messages start with a header: http://docs.ros.org/jade/api/std_msgs/html/msg/Header.html
371 4-byte size + 4-byte sequence id + 8-byte timestamp + 4-byte frame id length + frame id */
372 int available
= tvb_reported_length_remaining(tvb
, offset
);
373 uint32_t string_len
= 0;
374 uint32_t msg_len
= 0;
379 msg_len
= tvb_get_letohl(tvb
, offset
);
383 /** Check to see if the frame id length is reasonable */
384 string_len
= tvb_get_letohl(tvb
, offset
+ 4 + 4 + 8);
385 if( string_len
> (msg_len
- (4 + 8 + 4)) )
388 /** If we don't have enough data for the whole string, assume its not */
389 if( (unsigned)available
< (string_len
+ 4) )
392 /** This is highly likely a ROS message. */
397 dissect_ros_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, bool is_tcp _U_
)
400 proto_tree
*root_tree
;
405 /** Clear out stuff in the info column */
406 col_clear(pinfo
->cinfo
, COL_INFO
);
408 ti
= proto_tree_add_item(tree
, proto_tcpros
, tvb
, 0, -1, ENC_NA
);
409 root_tree
= proto_item_add_subtree(ti
, ett_tcpros
);
413 while(offset
< tvb_reported_length(tvb
)) {
414 int available
= tvb_reported_length_remaining(tvb
, offset
);
416 if( (available
< SIZE_OF_LENGTH_FIELD
) || ((unsigned)available
< tvb_get_letohl(tvb
, offset
)) ) {
417 /** we ran out of data: ask for more */
418 pinfo
->desegment_offset
= offset
;
419 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
422 /** There are two types of packet: Connection Headers and ROS Message. Which one is it? */
423 if( is_rosclock(tvb
, pinfo
, offset
) ) {
424 /** This is a ROS Clock message. */
425 offset
+= dissect_ros_clock(tvb
, root_tree
, pinfo
, offset
);
426 } else if( is_rosmsg(tvb
, pinfo
, offset
) ) {
427 /** We have a ROS message. */
428 offset
+= dissect_ros_message(tvb
, root_tree
, pinfo
, offset
);
429 } else if( is_rosconnection_header(tvb
, pinfo
, offset
) ) {
430 /** Check for a connection header */
431 offset
+= dissect_ros_connection_header(tvb
, root_tree
, pinfo
, offset
);
432 } else if( is_connection_header(tvb
, pinfo
, offset
) ) {
433 /** We have a ROS connection header. */
434 offset
+= dissect_ros_connection_header(tvb
, root_tree
, pinfo
, offset
);
436 /** We have a ROS message. */
437 offset
+= dissect_ros_message(tvb
, root_tree
, pinfo
, offset
);
445 get_tcpros_pdu_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
, void *data _U_
)
450 * Get the length of the TCPROS packet.
452 plen
= tvb_get_letohl(tvb
, offset
);
455 * That length doesn't include the length field itself; add that in.
457 return plen
+ SIZE_OF_LENGTH_FIELD
;
462 dissect_tcpros_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
464 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "TCPROS");
466 dissect_ros_common(tvb
, pinfo
, tree
, true);
467 return tvb_reported_length(tvb
);
471 dissect_tcpros(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
)
473 tcp_dissect_pdus(tvb
, pinfo
, tree
, tcpros_desegment
, SIZE_OF_LENGTH_FIELD
, get_tcpros_pdu_len
,
474 dissect_tcpros_pdu
, data
);
475 return tvb_reported_length(tvb
);
480 proto_register_tcpros(void)
482 static hf_register_info hf
[] = {
483 { &hf_tcpros_connection_header
, { "ROS Connection", "tcpros.header",
484 FT_UINT_BYTES
, BASE_NONE
, NULL
, 0,
485 "Message Header", HFILL
} },
486 { &hf_tcpros_connection_header_length
, { "Header Length", "tcpros.header_length",
487 FT_UINT32
, BASE_DEC
, NULL
, 0,
488 "Message Header Length", HFILL
} },
489 { &hf_tcpros_connection_header_content
, { "Header Content", "tcpros.header_content",
490 FT_BYTES
, BASE_NONE
, NULL
, 0,
491 "Message Header Content", HFILL
} },
493 { &hf_tcpros_connection_header_field
, { "Field", "tcpros.header_field",
494 FT_UINT_STRING
, BASE_NONE
, NULL
, 0,
495 "Message Header Field", HFILL
} },
496 { &hf_tcpros_connection_header_field_length
, { "Field Length", "tcpros.header_field_length",
497 FT_UINT32
, BASE_DEC
, NULL
, 0,
498 "Message Header Field Length", HFILL
} },
499 { &hf_tcpros_connection_header_field_data
, { "Field Content", "tcpros.header_field_data",
500 FT_STRING
, BASE_NONE
, NULL
, 0,
501 "Message Header Field Content", HFILL
} },
502 { &hf_tcpros_connection_header_field_name
, { "Name", "tcpros.header_field_name",
503 FT_STRING
, BASE_NONE
, NULL
, 0,
504 "Message Header Field Name", HFILL
} },
505 { &hf_tcpros_connection_header_field_value
, { "Value", "tcpros.header_field_value",
506 FT_STRING
, BASE_NONE
, NULL
, 0,
507 "Message Header Field Value", HFILL
} },
509 { &hf_tcpros_clock
, { "ROS Clock", "tcpros.clock",
510 FT_UINT_BYTES
, BASE_NONE
, NULL
, 0,
511 "ROS Clock Packet", HFILL
} },
512 { &hf_tcpros_clock_length
, { "Clock Length", "tcpros.clock.length",
513 FT_UINT32
, BASE_DEC
, NULL
, 0,
514 "ROS Clock Packet length", HFILL
} },
516 { &hf_tcpros_message
, { "ROS Message", "tcpros.message",
517 FT_UINT_BYTES
, BASE_NONE
, NULL
, 0,
518 "ROS Message Packet", HFILL
} },
519 { &hf_tcpros_message_length
, { "Message Length", "tcpros.message.length",
520 FT_UINT32
, BASE_DEC
, NULL
, 0,
521 "ROS Message Packet length", HFILL
} },
522 { &hf_tcpros_message_body
, { "Message Content", "tcpros.message.body",
523 FT_BYTES
, BASE_NONE
, NULL
, 0,
524 "ROS Message Packet Body", HFILL
} },
526 { &hf_tcpros_message_header
, { "Header", "tcpros.message.header",
527 FT_BYTES
, BASE_NONE
, NULL
, 0,
528 "ROS Message Header", HFILL
} },
529 { &hf_tcpros_message_header_seq
, { "Sequence ID", "tcpros.message.header.seq",
530 FT_UINT32
, BASE_DEC
, NULL
, 0,
531 "ROS Message Header Sequence", HFILL
} },
532 { &hf_tcpros_message_header_stamp
, { "Timestamp", "tcpros.message.header.stamp",
533 FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
, NULL
, 0,
534 "ROS Message Header Stamp", HFILL
} },
535 { &hf_tcpros_message_header_stamp_sec
, { "Seconds", "tcpros.message.header.stamp.sec",
536 FT_UINT32
, BASE_DEC
, NULL
, 0,
537 "ROS Message Header Stamp Sec", HFILL
} },
538 { &hf_tcpros_message_header_stamp_nsec
, { "Nanoseconds", "tcpros.message.header.stamp.nsec",
539 FT_UINT32
, BASE_DEC
, NULL
, 0,
540 "ROS Message Header Stamp NSec", HFILL
} },
542 { &hf_tcpros_message_header_frame
, { "Frame ID", "tcpros.message.header.frame",
543 FT_UINT_STRING
, BASE_NONE
, NULL
, 0,
544 "ROS Message Header Frame ID", HFILL
} },
545 { &hf_tcpros_message_header_frame_length
, { "Length", "tcpros.message.header.frame.len",
546 FT_UINT32
, BASE_DEC
, NULL
, 0,
547 "ROS Message Header Frame ID Length", HFILL
} },
548 { &hf_tcpros_message_header_frame_value
, { "Value", "tcpros.message.header.frame.value",
549 FT_STRING
, BASE_NONE
, NULL
, 0,
550 "ROS Message Header Frame ID Value", HFILL
} },
552 { &hf_tcpros_message_payload
, { "Payload", "tcpros.message.payload",
553 FT_BYTES
, BASE_NONE
, NULL
, 0,
554 "ROS Message Packet Payload", HFILL
} },
558 static int *ett
[] = {
562 module_t
*tcpros_module
;
564 proto_tcpros
= proto_register_protocol("TCP based Robot Operating System protocol (TCPROS)", "TCPROS", "tcpros");
566 proto_register_field_array(proto_tcpros
, hf
, array_length(hf
));
567 proto_register_subtree_array(ett
, array_length(ett
));
569 tcpros_handle
= register_dissector("tcpros", dissect_tcpros
, proto_tcpros
);
571 tcpros_module
= prefs_register_protocol(proto_tcpros
, NULL
);
573 prefs_register_bool_preference(tcpros_module
, "desegment_tcpros_messages",
574 "Reassemble TCPROS messages spanning multiple TCP segments",
575 "Whether the TCPROS dissector should reassemble messages spanning multiple TCP segments."
576 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
582 /* Heuristics test */
584 test_tcpros(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, void *data _U_
)
586 if (tvb_captured_length(tvb
) < 8)
589 if( is_rosclock(tvb
, pinfo
, offset
) )
591 if( is_rosmsg(tvb
, pinfo
, offset
) )
593 if( is_rosconnection_header(tvb
, pinfo
, offset
) )
600 dissect_tcpros_heur_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
602 conversation_t
*conversation
;
604 if (!test_tcpros(pinfo
, tvb
, 0, data
))
607 conversation
= find_or_create_conversation(pinfo
);
608 conversation_set_dissector(conversation
, tcpros_handle
);
610 dissect_tcpros(tvb
, pinfo
, tree
, data
);
618 proto_reg_handoff_tcpros(void)
620 dissector_add_for_decode_as_with_preference("tcp.port", tcpros_handle
); /* for "decode-as" */
622 /* register as heuristic dissector */
623 heur_dissector_add("tcp", dissect_tcpros_heur_tcp
, "TCPROS over TCP",
624 "tcpros_tcp", proto_tcpros
, HEURISTIC_DISABLE
);
630 * Editor modelines - https://www.wireshark.org/tools/modelines.html
635 * indent-tabs-mode: t
638 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
639 * :indentSize=8:tabSize=8:noTabs=false: