2 * Routines for YAMI dissection
3 * Copyright 2010, Pawel Korbut
4 * Copyright 2012, Jakub Zawadzki <darkjames-ws@darkjames.pl>
6 * Protocol documentation available at http://www.inspirel.com/yami4/book/B-2.html
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * SPDX-License-Identifier: GPL-2.0-or-later
16 #include <epan/packet.h>
17 #include <epan/prefs.h>
18 #include <epan/to_str.h>
19 #include <wsutil/ws_roundup.h>
20 #include "packet-tcp.h"
22 void proto_reg_handoff_yami(void);
23 void proto_register_yami(void);
25 static bool yami_desegment
= true;
27 static dissector_handle_t yami_handle
;
29 #define YAMI_TYPE_BOOLEAN 1
30 #define YAMI_TYPE_INTEGER 2
31 #define YAMI_TYPE_LONGLONG 3
32 #define YAMI_TYPE_DOUBLE 4
33 #define YAMI_TYPE_STRING 5
34 #define YAMI_TYPE_BINARY 6
35 #define YAMI_TYPE_BOOLEAN_ARRAY 7
36 #define YAMI_TYPE_INTEGER_ARRAY 8
37 #define YAMI_TYPE_LONGLONG_ARRAY 9
38 #define YAMI_TYPE_DOUBLE_ARRAY 10
39 #define YAMI_TYPE_STRING_ARRAY 11
40 #define YAMI_TYPE_BINARY_ARRAY 12
41 #define YAMI_TYPE_NESTED 13
43 static const value_string yami_param_type_vals
[] = {
44 { YAMI_TYPE_BOOLEAN
, "boolean" },
45 { YAMI_TYPE_INTEGER
, "integer" },
46 { YAMI_TYPE_LONGLONG
, "long long" },
47 { YAMI_TYPE_DOUBLE
, "double" },
48 { YAMI_TYPE_STRING
, "string" },
49 { YAMI_TYPE_BINARY
, "binary" },
50 { YAMI_TYPE_BOOLEAN_ARRAY
, "boolean array" },
51 { YAMI_TYPE_INTEGER_ARRAY
, "integer array" },
52 { YAMI_TYPE_LONGLONG_ARRAY
, "long long array" },
53 { YAMI_TYPE_DOUBLE_ARRAY
, "double array" },
54 { YAMI_TYPE_STRING_ARRAY
, "string array" },
55 { YAMI_TYPE_BINARY_ARRAY
, "binary array" },
56 { YAMI_TYPE_NESTED
, "nested parameters" },
60 static int proto_yami
;
62 static int hf_yami_frame_number
;
63 static int hf_yami_frame_payload_size
;
64 static int hf_yami_items_count
;
65 static int hf_yami_message_data
;
66 static int hf_yami_message_hdr
;
67 static int hf_yami_message_header_size
;
68 static int hf_yami_message_id
;
69 static int hf_yami_param
;
70 static int hf_yami_param_name
;
71 static int hf_yami_param_type
;
72 static int hf_yami_param_value_bin
;
73 static int hf_yami_param_value_bool
;
74 static int hf_yami_param_value_double
;
75 static int hf_yami_param_value_int
;
76 static int hf_yami_param_value_long
;
77 static int hf_yami_param_value_str
;
78 static int hf_yami_params_count
;
81 static int ett_yami_msg_hdr
;
82 static int ett_yami_msg_data
;
83 static int ett_yami_param
;
86 // NOLINTNEXTLINE(misc-no-recursion)
87 dissect_yami_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
, proto_item
*par_ti
)
89 const int orig_offset
= offset
;
91 proto_tree
*yami_param
;
100 ti
= proto_tree_add_item(tree
, hf_yami_param
, tvb
, offset
, 0, ENC_NA
);
101 yami_param
= proto_item_add_subtree(ti
, ett_yami_param
);
103 name_offset
= offset
;
104 name_len
= tvb_get_letohl(tvb
, offset
);
107 name
= tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, name_len
, ENC_ASCII
| ENC_NA
);
108 proto_item_append_text(ti
, ": %s", name
);
109 proto_item_append_text(par_ti
, "%s, ", name
);
110 offset
+= WS_ROUNDUP_4(name_len
);
111 proto_tree_add_string(yami_param
, hf_yami_param_name
, tvb
, name_offset
, offset
- name_offset
, name
);
113 type
= tvb_get_letohl(tvb
, offset
);
114 proto_tree_add_item(yami_param
, hf_yami_param_type
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
118 case YAMI_TYPE_BOOLEAN
:
120 uint32_t val
= tvb_get_letohl(tvb
, offset
);
121 proto_item_append_text(ti
, ", Type: boolean, Value: %s", val
? "True" : "False");
122 proto_tree_add_item(yami_param
, hf_yami_param_value_bool
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
127 case YAMI_TYPE_INTEGER
:
129 int32_t val
= tvb_get_letohl(tvb
, offset
);
130 proto_item_append_text(ti
, ", Type: integer, Value: %d", val
);
131 proto_tree_add_item(yami_param
, hf_yami_param_value_int
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
136 case YAMI_TYPE_LONGLONG
:
138 int64_t val
= tvb_get_letoh64(tvb
, offset
);
139 proto_item_append_text(ti
, ", Type: long, Value: %" PRId64
, val
);
140 proto_tree_add_item(yami_param
, hf_yami_param_value_long
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
145 case YAMI_TYPE_DOUBLE
:
147 double val
= tvb_get_letohieee_double(tvb
, offset
);
148 proto_item_append_text(ti
, ", Type: double, Value: %g", val
);
149 proto_tree_add_item(yami_param
, hf_yami_param_value_double
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
154 case YAMI_TYPE_STRING
:
156 const int val_offset
= offset
;
160 val_len
= tvb_get_letohl(tvb
, offset
);
163 val
= tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, val_len
, ENC_ASCII
| ENC_NA
);
165 proto_item_append_text(ti
, ", Type: string, Value: \"%s\"", val
);
166 offset
+= WS_ROUNDUP_4(val_len
);
167 proto_tree_add_string(yami_param
, hf_yami_param_value_str
, tvb
, val_offset
, offset
- val_offset
, val
);
171 case YAMI_TYPE_BINARY
:
173 const int val_offset
= offset
;
178 val_len
= tvb_get_letohl(tvb
, offset
);
181 val
= tvb_get_ptr(tvb
, offset
, val_len
);
182 repr
= bytes_to_str(pinfo
->pool
, val
, val_len
);
184 proto_item_append_text(ti
, ", Type: binary, Value: %s", repr
);
185 offset
+= WS_ROUNDUP_4(val_len
);
186 proto_tree_add_bytes_format_value(yami_param
, hf_yami_param_value_bin
, tvb
, val_offset
, offset
- val_offset
, val
, "%s", repr
);
190 case YAMI_TYPE_BOOLEAN_ARRAY
:
196 count
= tvb_get_letohl(tvb
, offset
);
197 proto_tree_add_item(yami_param
, hf_yami_items_count
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
200 proto_item_append_text(ti
, ", Type: boolean[], %u items: {", count
);
202 for (i
= 0; i
< count
/32; i
++) {
203 uint32_t val
= tvb_get_letohl(tvb
, offset
);
205 for (j
= 0; j
< 32; j
++) {
206 int r
= !!(val
& (1U << j
));
208 proto_item_append_text(ti
, "%s, ", r
? "T" : "F");
209 proto_tree_add_boolean(yami_param
, hf_yami_param_value_bool
, tvb
, offset
+(j
/8), 1, r
);
215 uint32_t val
= tvb_get_letohl(tvb
, offset
);
216 int tmp
= count
% 32;
218 for (j
= 0; j
< tmp
; j
++) {
219 int r
= !!(val
& (1 << j
));
221 proto_item_append_text(ti
, "%s, ", r
? "T" : "F");
222 proto_tree_add_boolean(yami_param
, hf_yami_param_value_bool
, tvb
, offset
+(j
/8), 1, r
);
227 proto_item_append_text(ti
, "}");
231 case YAMI_TYPE_INTEGER_ARRAY
:
236 count
= tvb_get_letohl(tvb
, offset
);
237 proto_tree_add_item(yami_param
, hf_yami_items_count
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
240 proto_item_append_text(ti
, ", Type: integer[], %u items: {", count
);
241 for (i
= 0; i
< count
; i
++) {
242 int32_t val
= tvb_get_letohl(tvb
, offset
);
244 proto_item_append_text(ti
, "%d, ", val
);
245 proto_tree_add_item(yami_param
, hf_yami_param_value_int
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
248 proto_item_append_text(ti
, "}");
252 case YAMI_TYPE_LONGLONG_ARRAY
:
257 count
= tvb_get_letohl(tvb
, offset
);
258 proto_tree_add_item(yami_param
, hf_yami_items_count
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
261 proto_item_append_text(ti
, ", Type: long long[], %u items: {", count
);
263 for (i
= 0; i
< count
; i
++) {
264 int64_t val
= tvb_get_letoh64(tvb
, offset
);
266 proto_item_append_text(ti
, "%" PRId64
", ", val
);
267 proto_tree_add_item(yami_param
, hf_yami_param_value_long
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
270 proto_item_append_text(ti
, "}");
274 case YAMI_TYPE_DOUBLE_ARRAY
:
279 count
= tvb_get_letohl(tvb
, offset
);
280 proto_tree_add_item(yami_param
, hf_yami_items_count
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
283 proto_item_append_text(ti
, ", Type: double[], %u items: {", count
);
285 for (i
= 0; i
< count
; i
++) {
286 double val
= tvb_get_letohieee_double(tvb
, offset
);
288 proto_item_append_text(ti
, "%g, ", val
);
289 proto_tree_add_item(yami_param
, hf_yami_param_value_double
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
292 proto_item_append_text(ti
, "}");
296 case YAMI_TYPE_STRING_ARRAY
:
301 count
= tvb_get_letohl(tvb
, offset
);
302 proto_tree_add_item(yami_param
, hf_yami_items_count
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
305 proto_item_append_text(ti
, ", Type: string[], %u items: {", count
);
307 for (i
= 0; i
< count
; i
++) {
308 const int val_offset
= offset
;
312 val_len
= tvb_get_letohl(tvb
, offset
);
315 val
= tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, val_len
, ENC_ASCII
| ENC_NA
);
317 proto_item_append_text(ti
, "\"%s\", ", val
);
318 proto_tree_add_string(yami_param
, hf_yami_param_value_str
, tvb
, val_offset
, offset
- val_offset
, val
);
319 offset
+= WS_ROUNDUP_4(val_len
);
321 proto_item_append_text(ti
, "}");
325 case YAMI_TYPE_BINARY_ARRAY
:
330 count
= tvb_get_letohl(tvb
, offset
);
331 proto_tree_add_item(yami_param
, hf_yami_items_count
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
334 proto_item_append_text(ti
, ", Type: binary[], %u items: {", count
);
336 for (i
= 0; i
< count
; i
++) {
337 const int val_offset
= offset
;
342 val_len
= tvb_get_letohl(tvb
, offset
);
345 val
= tvb_get_ptr(tvb
, offset
, val_len
);
346 repr
= bytes_to_str(pinfo
->pool
, val
, val_len
);
348 proto_item_append_text(ti
, "%s, ", repr
);
349 offset
+= WS_ROUNDUP_4(val_len
);
350 proto_tree_add_bytes_format_value(yami_param
, hf_yami_param_value_bin
, tvb
, val_offset
, offset
- val_offset
, val
, "%s", repr
);
352 proto_item_append_text(ti
, "}");
356 case YAMI_TYPE_NESTED
:
361 count
= tvb_get_letohl(tvb
, offset
);
362 proto_tree_add_item(yami_param
, hf_yami_params_count
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
365 proto_item_append_text(ti
, ", Type: nested, %u parameters: ", count
);
367 for (i
= 0; i
< count
; i
++) {
368 increment_dissection_depth(pinfo
);
369 offset
= dissect_yami_parameter(tvb
, pinfo
, yami_param
, offset
, ti
);
370 decrement_dissection_depth(pinfo
);
371 /* smth went wrong */
379 proto_item_append_text(ti
, ", Type: unknown (%d)!", type
);
383 proto_item_set_len(ti
, offset
- orig_offset
);
388 dissect_yami_data(tvbuff_t
*tvb
, packet_info
*pinfo
, bool data
, proto_tree
*tree
, int offset
)
390 const int orig_offset
= offset
;
392 proto_tree
*yami_data_tree
;
398 ti
= proto_tree_add_item(tree
, (data
) ? hf_yami_message_data
: hf_yami_message_hdr
, tvb
, offset
, 0, ENC_NA
);
399 yami_data_tree
= proto_item_add_subtree(ti
, (data
) ? ett_yami_msg_data
: ett_yami_msg_hdr
);
401 count
= tvb_get_letohl(tvb
, offset
);
402 proto_tree_add_item(yami_data_tree
, hf_yami_params_count
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
405 proto_item_append_text(ti
, ", %u parameters: ", count
);
407 for (i
= 0; i
< count
; i
++) {
408 offset
= dissect_yami_parameter(tvb
, pinfo
, yami_data_tree
, offset
, ti
);
409 /* smth went wrong */
414 proto_item_set_len(ti
, offset
- orig_offset
);
420 dissect_yami_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
422 proto_tree
*yami_tree
;
426 int message_header_size
;
427 int frame_payload_size
;
431 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "YAMI");
432 col_clear(pinfo
->cinfo
, COL_INFO
);
434 ti
= proto_tree_add_item(tree
, proto_yami
, tvb
, 0, -1, ENC_NA
);
435 yami_tree
= proto_item_add_subtree(ti
, ett_yami
);
439 proto_tree_add_item(yami_tree
, hf_yami_message_id
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
442 frame_number
= tvb_get_letohl(tvb
, offset
);
443 ti
= proto_tree_add_item(yami_tree
, hf_yami_frame_number
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
445 proto_item_append_text(ti
, "%s", " (last frame)");
448 message_header_size
= tvb_get_letohl(tvb
, offset
);
449 proto_tree_add_item(yami_tree
, hf_yami_message_header_size
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
450 if (message_header_size
< 4) {
451 /* XXX, expert info */
455 frame_payload_size
= tvb_get_letohl(tvb
, offset
);
456 ti
= proto_tree_add_item(yami_tree
, hf_yami_frame_payload_size
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
457 frame_size
= frame_payload_size
+ 16;
458 proto_item_append_text(ti
, ", (YAMI Frame Size: %d)", frame_size
);
461 if (frame_number
== 1 || frame_number
== -1) {
462 if (message_header_size
<= frame_payload_size
) {
463 const int orig_offset
= offset
;
465 offset
= dissect_yami_data(tvb
, pinfo
, false, yami_tree
, offset
);
466 if (offset
!= orig_offset
+ message_header_size
) {
467 /* XXX, expert info */
468 offset
= orig_offset
+ message_header_size
;
471 dissect_yami_data(tvb
, pinfo
, true, yami_tree
, offset
);
475 return tvb_captured_length(tvb
);
478 #define FRAME_HEADER_LEN 16
481 get_yami_message_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
,
482 int offset
, void *data _U_
)
484 uint32_t len
= tvb_get_letohl(tvb
, offset
+ 12);
486 return len
+ FRAME_HEADER_LEN
;
490 dissect_yami(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
492 tcp_dissect_pdus(tvb
, pinfo
, tree
, yami_desegment
, FRAME_HEADER_LEN
, get_yami_message_len
, dissect_yami_pdu
, data
);
493 return tvb_captured_length(tvb
);
497 proto_register_yami(void)
499 static hf_register_info hf
[] = {
500 { &hf_yami_message_id
,
501 { "Message ID", "yami.message_id",
502 FT_INT32
, BASE_DEC
, NULL
, 0x00,
505 { &hf_yami_frame_number
,
506 { "Frame Number", "yami.frame_number",
507 FT_INT32
, BASE_DEC
, NULL
, 0x00,
510 { &hf_yami_message_header_size
,
511 { "Message Header Size", "yami.message_header_size",
512 FT_INT32
, BASE_DEC
, NULL
, 0x00,
515 { &hf_yami_frame_payload_size
,
516 { "Frame Payload Size", "yami.frame_payload_size",
517 FT_INT32
, BASE_DEC
, NULL
, 0x00,
520 { &hf_yami_message_hdr
,
521 { "Header message", "yami.msg_hdr",
522 FT_NONE
, BASE_NONE
, NULL
, 0x00,
525 { &hf_yami_message_data
,
526 { "Data message", "yami.msg_data",
527 FT_NONE
, BASE_NONE
, NULL
, 0x00,
531 { "Parameter", "yami.param",
532 FT_NONE
, BASE_NONE
, NULL
, 0x00,
535 { &hf_yami_param_name
,
536 { "Name", "yami.param.name",
537 FT_STRING
, BASE_NONE
, NULL
, 0x00,
538 "Parameter name", HFILL
}
540 { &hf_yami_param_type
,
541 { "Type", "yami.param.type",
542 FT_INT32
, BASE_DEC
, VALS(yami_param_type_vals
), 0x00,
543 "Parameter type", HFILL
}
545 { &hf_yami_param_value_bool
,
546 { "Value", "yami.param.value_bool",
547 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00,
548 "Parameter value (bool)", HFILL
}
550 { &hf_yami_param_value_int
,
551 { "Value", "yami.param.value_int",
552 FT_INT32
, BASE_DEC
, NULL
, 0x00,
553 "Parameter value (int)", HFILL
}
555 { &hf_yami_param_value_long
,
556 { "Value", "yami.param.value_long",
557 FT_INT64
, BASE_DEC
, NULL
, 0x00,
558 "Parameter value (long)", HFILL
}
560 { &hf_yami_param_value_double
,
561 { "Value", "yami.param.value_double",
562 FT_DOUBLE
, BASE_NONE
, NULL
, 0x00,
563 "Parameter value (double)", HFILL
}
565 { &hf_yami_param_value_str
,
566 { "Value", "yami.param.value_str",
567 FT_STRING
, BASE_NONE
, NULL
, 0x00,
568 "Parameter value (string)", HFILL
}
570 { &hf_yami_param_value_bin
,
571 { "Value", "yami.param.value_bin",
572 FT_BYTES
, BASE_NONE
, NULL
, 0x00,
573 "Parameter value (binary)", HFILL
}
575 { &hf_yami_params_count
,
576 { "Parameters count", "yami.params_count",
577 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
580 { &hf_yami_items_count
,
581 { "Items count", "yami.items_count",
582 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
587 static int *ett
[] = {
594 module_t
*yami_module
;
596 proto_yami
= proto_register_protocol("YAMI Protocol", "YAMI", "yami");
598 proto_register_field_array(proto_yami
, hf
, array_length(hf
));
599 proto_register_subtree_array(ett
, array_length(ett
));
601 yami_module
= prefs_register_protocol(proto_yami
, NULL
);
602 prefs_register_bool_preference(yami_module
, "desegment",
603 "Reassemble YAMI messages spanning multiple TCP segments",
604 "Whether the YAMI dissector should reassemble messages spanning multiple TCP segments."
605 "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
608 yami_handle
= register_dissector("yami", dissect_yami
, proto_yami
);
612 proto_reg_handoff_yami(void)
614 dissector_add_for_decode_as_with_preference("tcp.port", yami_handle
);
615 dissector_add_for_decode_as_with_preference("udp.port", yami_handle
);
619 * Editor modelines - https://www.wireshark.org/tools/modelines.html
624 * indent-tabs-mode: t
627 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
628 * :indentSize=8:tabSize=8:noTabs=false: