Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-hcrt.c
blob92e1811e68ceba6e19eb55bed431391b9db46687
1 /* packet-hcrt.c
3 * Routines for Hotline Command-Response Transaction (HCrt)
4 * Protocol specifications (draft) are available here
5 * https://github.com/ShepardSiegel/hotline/tree/master/doc
7 * Copyright 2013 Dario Lombardo (lomato@gmail.com)
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * SPDX-License-Identifier: GPL-2.0-or-later
16 #include "config.h"
17 #include <epan/packet.h>
18 #include <epan/prefs.h>
19 #include <epan/expert.h>
20 #include <epan/tfs.h>
22 static int proto_hcrt;
24 #define HCRT_UDP_PORTS_DEFAULT "47000"
26 static unsigned ethertype_pref = 0xf052;
28 static int hf_hcrt_header;
29 static int hf_hcrt_message_tag;
30 static int hf_hcrt_message_type;
31 static int hf_hcrt_am;
32 static int hf_hcrt_do;
33 static int hf_hcrt_1st_dword_enable;
34 static int hf_hcrt_last_dword_enable;
35 static int hf_hcrt_resp_code;
36 static int hf_hcrt_adl;
37 static int hf_hcrt_last;
38 static int hf_hcrt_body;
39 static int hf_hcrt_addr_32;
40 static int hf_hcrt_addr_64;
41 static int hf_hcrt_data_32;
42 static int hf_hcrt_data_64;
43 static int hf_hcrt_command_nop;
45 static int ett_hcrt;
46 static int ett_hcrt_msg;
47 static int ett_hcrt_hdr;
48 static int ett_hcrt_body;
50 static expert_field ei_hcrt_error;
52 void proto_reg_handoff_hcrt(void);
53 void proto_register_hcrt(void);
55 static dissector_handle_t hcrt_handle;
57 #define HCRT_HDR_LEN 4
59 #define HCRT_NOP 0x0
60 #define HCRT_WRITE 0x1
61 #define HCRT_READ 0x2
62 #define HCRT_RESPONSE 0x3
64 #define ADDR_MODE_32 1
65 #define ADDR_MODE_64 2
67 /* Message types */
68 static const value_string hcrt_message_types[] = {
69 {0x00, "NOP"},
70 {0x01, "Write"},
71 {0x02, "Read"},
72 {0x03, "Response"},
73 {0, NULL}
76 /* Addressing modes */
77 static const value_string hcrt_ams[] = {
78 {0x0, "32 bit"},
79 {0x1, "64 bit"},
80 {0, NULL}
83 /* Discovery operations */
84 static const true_false_string hcrt_dos = {
85 "DO",
86 "not DO",
89 static const value_string dword_enable_vals[] = {
90 {0xF, "4B"},
91 {0xC, "2B (MS)"},
92 {0x3, "2B (LS)"},
93 {0x8, "1B (B3)"},
94 {0x4, "1B (B2)"},
95 {0x2, "1B (B1)"},
96 {0x1, "1B (B0)"},
97 {0, NULL}
100 static const value_string response_codes[] = {
101 {0x0, "OK"},
102 {0x1, "Timeout"},
103 {0x2, "Error"},
104 {0x3, "Reserved"},
105 {0x4, "Reserved"},
106 {0x5, "Reserved"},
107 {0x6, "Reserved"},
108 {0x7, "Reserved"},
109 {0x8, "Reserved"},
110 {0x9, "Reserved"},
111 {0xa, "Reserved"},
112 {0xb, "Reserved"},
113 {0xc, "Reserved"},
114 {0xd, "Reserved"},
115 {0xe, "Reserved"},
116 {0xf, "Reserved"},
117 {0, NULL}
121 static void dissect_hcrt_body(tvbuff_t* tvb, proto_tree* tree , unsigned* offset,
122 int type, int addr_mode, int adl, int body_len)
124 proto_item* ti_body;
125 proto_tree* hcrt_body_tree;
126 int i;
128 ti_body = proto_tree_add_item(tree, hf_hcrt_body, tvb, *offset, body_len, ENC_NA);
129 hcrt_body_tree = proto_item_add_subtree(ti_body, ett_hcrt_body);
131 switch (type) {
132 case HCRT_NOP:
133 proto_tree_add_item(hcrt_body_tree, hf_hcrt_command_nop, tvb, *offset,
134 body_len, ENC_NA);
135 break;
136 case HCRT_WRITE:
137 if (addr_mode == ADDR_MODE_32) {
138 /* Address (32) */
139 proto_tree_add_item(hcrt_body_tree, hf_hcrt_addr_32, tvb, *offset,
140 4, ENC_LITTLE_ENDIAN);
142 /* Data */
143 for (i = 1; i <= adl; i++) {
144 proto_tree_add_item(hcrt_body_tree, hf_hcrt_data_32, tvb,
145 *offset + i * 4, 4, ENC_LITTLE_ENDIAN);
147 } else {
148 /* Address (64) */
149 proto_tree_add_item(hcrt_body_tree, hf_hcrt_addr_64, tvb, *offset,
150 8, ENC_LITTLE_ENDIAN);
152 /* Data */
153 for (i = 1; i <= adl; i++)
154 proto_tree_add_item(hcrt_body_tree, hf_hcrt_data_64, tvb,
155 *offset + i * 8, 8, ENC_LITTLE_ENDIAN);
157 break;
158 case HCRT_READ:
159 if (addr_mode == ADDR_MODE_32) {
160 /* Address (32) */
161 proto_tree_add_item(hcrt_body_tree, hf_hcrt_addr_32, tvb, *offset, 4,
162 ENC_LITTLE_ENDIAN);
163 } else {
164 /* Address (64) */
165 proto_tree_add_item(hcrt_body_tree, hf_hcrt_addr_64, tvb, *offset, 8,
166 ENC_LITTLE_ENDIAN);
168 break;
169 case HCRT_RESPONSE:
170 if (body_len > 0) {
171 proto_tree_add_item(hcrt_body_tree, hf_hcrt_command_nop, tvb, *offset,
172 body_len, ENC_NA);
174 break;
175 default:
176 DISSECTOR_ASSERT_NOT_REACHED();
177 break;
180 (*offset) += body_len;
183 /* Returns true if this is the last message */
184 static bool dissect_hcrt_header(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree,
185 unsigned* offset, uint8_t b0_first, uint8_t b0_current)
187 proto_item* ti_hdr;
188 proto_tree* hcrt_hdr_tree;
189 bool last;
190 uint8_t type;
192 ti_hdr = proto_tree_add_item(tree, hf_hcrt_header, tvb, *offset, 4, ENC_NA);
193 hcrt_hdr_tree = proto_item_add_subtree(ti_hdr, ett_hcrt_hdr);
195 if (b0_first != b0_current) {
196 expert_add_info_format(pinfo, hcrt_hdr_tree, &ei_hcrt_error,
197 "Invalid Byte 0 in Header. Must be equal in all HCrt messages. "
198 "Expected: %.2X, got: %.2X", b0_first, b0_current);
201 type = (b0_current & 0x30) >> 4;
203 /* == Byte 0 == */
204 /* TAG */
205 proto_tree_add_item(hcrt_hdr_tree, hf_hcrt_message_tag, tvb,
206 *offset, 1, ENC_NA);
207 /* Message Type */
208 proto_tree_add_item(hcrt_hdr_tree, hf_hcrt_message_type, tvb,
209 *offset, 1, ENC_NA);
210 /* Addressing Mode */
211 proto_tree_add_item(hcrt_hdr_tree, hf_hcrt_am, tvb,
212 *offset, 1, ENC_NA);
213 /* Discovery Operation */
214 proto_tree_add_item(hcrt_hdr_tree, hf_hcrt_do, tvb,
215 *offset, 1, ENC_NA);
216 (*offset)++;
218 /* == Byte 1 == */
219 if (type != HCRT_RESPONSE) {
220 /* 1st DWORD enable */
221 proto_tree_add_item(hcrt_hdr_tree, hf_hcrt_1st_dword_enable, tvb,
222 *offset, 1, ENC_NA);
223 } else {
224 /* Response Code */
225 proto_tree_add_item(hcrt_hdr_tree, hf_hcrt_resp_code, tvb,
226 *offset, 1, ENC_NA);
229 if (type != HCRT_RESPONSE) {
230 /* Last DWORD enable */
231 proto_tree_add_item(hcrt_hdr_tree, hf_hcrt_last_dword_enable, tvb,
232 *offset, 1, ENC_NA);
234 (*offset)++;
236 /* == Byte 2 & 3 == */
237 /* ADL */
238 proto_tree_add_item(hcrt_hdr_tree, hf_hcrt_adl, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
239 /* Last */
240 proto_tree_add_item(hcrt_hdr_tree, hf_hcrt_last, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
242 /* last */
243 last = (tvb_get_letohs(tvb, *offset) & 0x8000) != 0;
244 (*offset) += 2;
245 return last;
248 /* Return true if this is the last message */
249 static bool dissect_hcrt_message(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree,
250 unsigned* offset, uint8_t b0_first, int i)
252 bool last;
253 unsigned adl;
254 unsigned addr_mode;
255 unsigned body_len;
256 proto_tree* hcrt_msg_tree;
257 uint8_t b0_current;
258 int type;
260 /* Save byte 0 of current packet */
261 b0_current = tvb_get_uint8(tvb, *offset);
263 /* Get details from header */
264 adl = tvb_get_letohs(tvb, *offset + 2) & 0x0FFF;
265 addr_mode = (1 + ((b0_current & 0x40) >> 6));
266 type = (b0_current & 0x30) >> 4;
268 switch (type) {
269 case HCRT_NOP:
270 body_len = 4 * addr_mode * adl;
271 break;
272 case HCRT_WRITE:
273 body_len = 4 * addr_mode * (adl + 1);
274 break;
275 case HCRT_READ:
276 body_len = 4 * addr_mode;
277 break;
278 case HCRT_RESPONSE:
279 body_len = 4 * addr_mode * adl;
280 break;
281 default:
282 DISSECTOR_ASSERT_NOT_REACHED();
283 break;
286 hcrt_msg_tree = proto_tree_add_subtree_format(tree, tvb, *offset,
287 HCRT_HDR_LEN + body_len, ett_hcrt_msg, NULL, "Message %d", i);
289 last = dissect_hcrt_header(tvb, pinfo, hcrt_msg_tree, offset, b0_first, b0_current);
290 dissect_hcrt_body(tvb, hcrt_msg_tree, offset, type, addr_mode, adl, body_len);
292 return last;
295 static int dissect_hcrt(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data _U_)
297 uint8_t type;
298 proto_item* ti;
299 proto_tree* hcrt_tree;
300 unsigned offset;
301 int i = 1;
302 uint8_t b0_first;
303 uint8_t tag;
304 unsigned adl;
306 col_set_str(pinfo->cinfo, COL_PROTOCOL, "HCrt");
307 col_clear(pinfo->cinfo, COL_INFO);
309 /* Save byte 0 of first message. Will be checked against byte 0 of other messages */
310 b0_first = tvb_get_uint8(tvb, 0);
312 tag = b0_first & 0x0F;
313 type = (b0_first & 0x30) >> 4;
314 adl = tvb_get_letohs(tvb, 2) & 0x0FFF;
316 col_add_fstr(pinfo->cinfo, COL_INFO, "Type: %s, Tag: 0x%X, ADL: %u",
317 val_to_str(type, hcrt_message_types, "Unknown (0x%02x)"), tag, adl);
319 if (adl == 1) {
320 if (type == HCRT_READ || type == HCRT_WRITE) {
321 col_append_fstr(pinfo->cinfo, COL_INFO, ", Address: 0x%.8X", tvb_get_letohl(tvb, 4));
323 if (type == HCRT_WRITE) {
324 col_append_fstr(pinfo->cinfo, COL_INFO, ", Data: 0x%.8X", tvb_get_letohl(tvb, 8));
328 offset = 0;
329 ti = proto_tree_add_item(tree, proto_hcrt, tvb, 0, -1, ENC_NA);
330 hcrt_tree = proto_item_add_subtree(ti, ett_hcrt);
332 while (!dissect_hcrt_message(tvb, pinfo, hcrt_tree, &offset, b0_first, i)) {
333 i++;
335 return tvb_captured_length(tvb);
338 void proto_register_hcrt(void)
340 expert_module_t* expert_hcrt;
341 module_t* hcrt_module;
343 static hf_register_info hf[] = {
344 { &hf_hcrt_header,
345 { "Header", "hcrt.hdr",
346 FT_NONE, BASE_NONE,
347 NULL, 0x00,
348 NULL, HFILL }
350 { &hf_hcrt_message_tag,
351 { "Tag", "hcrt.tag",
352 FT_UINT8, BASE_HEX,
353 NULL, 0x0F,
354 NULL, HFILL }
356 { &hf_hcrt_message_type,
357 { "Type", "hcrt.type",
358 FT_UINT8, BASE_DEC,
359 VALS(hcrt_message_types), 0x30,
360 NULL, HFILL }
362 { &hf_hcrt_am,
363 { "Addressing Mode", "hcrt.am",
364 FT_UINT8, BASE_DEC,
365 VALS(hcrt_ams), 0x40,
366 NULL, HFILL }
368 { &hf_hcrt_do,
369 { "Discovery Operation", "hcrt.do",
370 FT_BOOLEAN, 8,
371 TFS(&hcrt_dos), 0x80,
372 NULL, HFILL }
374 { &hf_hcrt_1st_dword_enable,
375 { "1st DWORD enable", "hcrt.first_dword_enable",
376 FT_UINT8, BASE_HEX,
377 VALS(dword_enable_vals), 0xF0,
378 NULL, HFILL }
380 { &hf_hcrt_last_dword_enable,
381 { "Last DWORD enable", "hcrt.last_dword_enable",
382 FT_UINT8, BASE_HEX,
383 VALS(dword_enable_vals), 0x0F,
384 NULL, HFILL }
386 { &hf_hcrt_resp_code,
387 { "Response code", "hcrt.response_code",
388 FT_UINT8, BASE_HEX,
389 VALS(response_codes), 0xF0,
390 NULL, HFILL }
392 { &hf_hcrt_adl,
393 { "ADL", "hcrt.adl",
394 FT_UINT16, BASE_DEC,
395 NULL, 0x0FFF,
396 NULL, HFILL }
398 { &hf_hcrt_last,
399 { "Last message", "hcrt.last",
400 FT_BOOLEAN, 16,
401 NULL, 0x8000,
402 NULL, HFILL }
404 { &hf_hcrt_body,
405 { "Body", "hcrt.body",
406 FT_NONE, BASE_NONE,
407 NULL, 0x00,
408 NULL, HFILL }
410 { &hf_hcrt_addr_32,
411 { "Address", "hcrt.address32",
412 FT_UINT32, BASE_HEX,
413 NULL, 0x0,
414 NULL, HFILL }
416 { &hf_hcrt_addr_64,
417 { "Address", "hcrt.address64",
418 FT_UINT64, BASE_HEX,
419 NULL, 0x0,
420 NULL, HFILL }
422 { &hf_hcrt_data_32,
423 { "Data", "hcrt.data32",
424 FT_UINT32, BASE_HEX,
425 NULL, 0x0,
426 NULL, HFILL }
428 { &hf_hcrt_data_64,
429 { "Data", "hcrt.data64",
430 FT_UINT64, BASE_HEX,
431 NULL, 0x0,
432 NULL, HFILL }
434 { &hf_hcrt_command_nop,
435 { "Command", "hcrt.command_nop",
436 FT_BYTES, BASE_NONE,
437 NULL, 0x0,
438 NULL, HFILL }
442 static ei_register_info ei[] = {
443 { &ei_hcrt_error, { "hcrt.error", PI_MALFORMED, PI_ERROR, "Unusual error code", EXPFILL }}
446 /* Setup protocol subtree array */
447 static int* ett[] = {
448 &ett_hcrt,
449 &ett_hcrt_msg,
450 &ett_hcrt_hdr,
451 &ett_hcrt_body,
454 proto_hcrt = proto_register_protocol ("Hotline Command-Response Transaction protocol", "HCrt", "hcrt");
456 proto_register_field_array(proto_hcrt, hf, array_length(hf));
457 proto_register_subtree_array(ett, array_length(ett));
458 expert_hcrt = expert_register_protocol(proto_hcrt);
459 expert_register_field_array(expert_hcrt, ei, array_length(ei));
461 hcrt_module = prefs_register_protocol(proto_hcrt, proto_reg_handoff_hcrt);
462 prefs_register_uint_preference(hcrt_module,
463 "dissector_ethertype",
464 "Ethernet type",
465 "The ethernet type used for L2 communications",
466 10, &ethertype_pref);
468 hcrt_handle = register_dissector("hcrt", dissect_hcrt, proto_hcrt);
471 void proto_reg_handoff_hcrt(void)
473 static bool hcrt_prefs_initialized = false;
474 static int hcrt_ethertype;
476 if (!hcrt_prefs_initialized) {
477 /* Also register as a dissector that can be selected by a TCP port number via
478 "decode as" */
479 dissector_add_for_decode_as_with_preference("tcp.port", hcrt_handle);
480 dissector_add_uint_range_with_preference("udp.port", HCRT_UDP_PORTS_DEFAULT, hcrt_handle);
481 hcrt_prefs_initialized = true;
482 } else {
483 dissector_delete_uint("ethertype", hcrt_ethertype, hcrt_handle);
486 hcrt_ethertype = ethertype_pref;
488 dissector_add_uint("ethertype", hcrt_ethertype, hcrt_handle);
492 * Editor modelines - https://www.wireshark.org/tools/modelines.html
494 * Local variables:
495 * c-basic-offset: 4
496 * tab-width: 8
497 * indent-tabs-mode: nil
498 * End:
500 * vi: set shiftwidth=4 tabstop=8 expandtab:
501 * :indentSize=4:tabSize=8:noTabs=true: