epan/dissectors/pidl/ C99 drsuapi
[wireshark-sm.git] / epan / dissectors / packet-enttec.c
blob00b1b4c8699ff0795d75107f113e96c4e1c728dd
1 /* packet-enttec.c
2 * Routines for ENTTEC packet disassembly
4 * Copyright (c) 2003,2004 by Erwin Rol <erwin@erwinrol.com>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1999 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 /* Include files */
15 #include "config.h"
17 #include <epan/packet.h>
18 #include <epan/prefs.h>
20 * See
22 * http://www.enttec.com/docs/enttec_protocol.pdf
25 /* Define UDP/TCP ports for ENTTEC */
27 #define UDP_PORT_ENTTEC 0x0D05 /* Not IANA registered */
28 #define TCP_PORT_ENTTEC 0x0D05 /* Not IANA registered */
31 #define ENTTEC_HEAD_ESPR 0x45535052
32 #define ENTTEC_HEAD_ESPP 0x45535050
33 #define ENTTEC_HEAD_ESAP 0x45534150
34 #define ENTTEC_HEAD_ESDD 0x45534444
35 #define ENTTEC_HEAD_ESNC 0x45534E43
36 #define ENTTEC_HEAD_ESZZ 0x45535A5A
38 static const value_string enttec_head_vals[] = {
39 { ENTTEC_HEAD_ESPR, "Poll Reply" },
40 { ENTTEC_HEAD_ESPP, "Poll" },
41 { ENTTEC_HEAD_ESAP, "Ack/nAck" },
42 { ENTTEC_HEAD_ESDD, "DMX Data" },
43 { ENTTEC_HEAD_ESNC, "Config" },
44 { ENTTEC_HEAD_ESZZ, "Reset" },
45 { 0, NULL }
48 #define ENTTEC_DATA_TYPE_DMX 0x01
49 #define ENTTEC_DATA_TYPE_CHAN_VAL 0x02
50 #define ENTTEC_DATA_TYPE_RLE 0x04
52 static const value_string enttec_data_type_vals[] = {
53 { ENTTEC_DATA_TYPE_DMX, "Uncompressed DMX" },
54 { ENTTEC_DATA_TYPE_CHAN_VAL, "Channel+Value" },
55 { ENTTEC_DATA_TYPE_RLE, "RLE Compressed DMX" },
56 { 0, NULL }
59 void proto_register_enttec(void);
60 void proto_reg_handoff_enttec(void);
62 static dissector_handle_t enttec_udp_handle, enttec_tcp_handle;
64 /* Define the enttec proto */
65 static int proto_enttec;
67 /* general */
68 static int hf_enttec_head;
70 /* poll */
71 static int hf_enttec_poll_type;
73 /* poll reply */
74 static int hf_enttec_poll_reply_mac;
75 static int hf_enttec_poll_reply_node_type;
76 static int hf_enttec_poll_reply_version;
77 static int hf_enttec_poll_reply_switch;
78 static int hf_enttec_poll_reply_name;
79 static int hf_enttec_poll_reply_option;
80 static int hf_enttec_poll_reply_tos;
81 static int hf_enttec_poll_reply_ttl;
83 /* dmx data */
84 static int hf_enttec_dmx_data_universe;
85 static int hf_enttec_dmx_data_start_code;
86 static int hf_enttec_dmx_data_type;
87 static int hf_enttec_dmx_data_size;
88 static int hf_enttec_dmx_data_data;
89 static int hf_enttec_dmx_data_data_filter;
90 static int hf_enttec_dmx_data_dmx_data;
92 /* Define the tree for enttec */
93 static int ett_enttec;
96 * Here are the global variables associated with the preferences
97 * for enttec
100 static int global_disp_chan_val_type;
101 static int global_disp_col_count = 16;
102 static int global_disp_chan_nr_type;
104 static int
105 dissect_enttec_poll_reply(tvbuff_t *tvb, unsigned offset, proto_tree *tree)
107 proto_tree_add_item(tree, hf_enttec_poll_reply_mac, tvb,
108 offset, 6, ENC_NA);
109 offset += 6;
111 proto_tree_add_item(tree, hf_enttec_poll_reply_node_type, tvb,
112 offset, 2, ENC_BIG_ENDIAN);
113 offset += 2;
115 proto_tree_add_item(tree, hf_enttec_poll_reply_version, tvb,
116 offset, 1, ENC_BIG_ENDIAN);
117 offset += 1;
119 proto_tree_add_item(tree, hf_enttec_poll_reply_switch, tvb,
120 offset, 1, ENC_BIG_ENDIAN);
121 offset += 1;
123 proto_tree_add_item(tree, hf_enttec_poll_reply_name, tvb,
124 offset, 10, ENC_ASCII);
125 offset += 10;
127 proto_tree_add_item(tree, hf_enttec_poll_reply_option, tvb,
128 offset, 1, ENC_BIG_ENDIAN);
129 offset += 1;
131 proto_tree_add_item(tree, hf_enttec_poll_reply_tos, tvb,
132 offset, 1, ENC_BIG_ENDIAN);
133 offset += 1;
135 proto_tree_add_item(tree, hf_enttec_poll_reply_ttl, tvb,
136 offset, 1, ENC_BIG_ENDIAN);
137 offset += 1;
139 /* data */
141 return offset;
144 static int
145 dissect_enttec_poll(tvbuff_t *tvb, unsigned offset, proto_tree *tree)
147 proto_tree_add_item(tree, hf_enttec_poll_type, tvb,
148 offset, 1, ENC_BIG_ENDIAN);
149 offset += 1;
151 return offset;
154 static int
155 dissect_enttec_ack(tvbuff_t *tvb _U_, unsigned offset, proto_tree *tree _U_)
158 return offset;
161 static int
162 dissect_enttec_dmx_data(tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *tree)
164 static const char* chan_format[] = {
165 "%2u ",
166 "%02x ",
167 "%3u "
169 static const char* string_format[] = {
170 "%03x: %s",
171 "%3u: %s"
174 uint8_t *dmx_data = (uint8_t *)wmem_alloc(pinfo->pool, 512 * sizeof(uint8_t));
175 uint16_t *dmx_data_offset = (uint16_t *)wmem_alloc(pinfo->pool, 513 * sizeof(uint16_t)); /* 1 extra for last offset */
176 wmem_strbuf_t *dmx_epstr;
178 proto_tree *hi,*si;
179 proto_item *item;
180 uint16_t length,r,c,row_count;
181 uint8_t v,type,count;
182 uint16_t ci,ui,i,start_offset,end_offset;
184 proto_tree_add_item(tree, hf_enttec_dmx_data_universe, tvb,
185 offset, 1, ENC_BIG_ENDIAN);
186 offset += 1;
188 proto_tree_add_item(tree, hf_enttec_dmx_data_start_code, tvb,
189 offset, 1, ENC_BIG_ENDIAN);
190 offset += 1;
192 type = tvb_get_uint8(tvb, offset);
193 proto_tree_add_item(tree, hf_enttec_dmx_data_type, tvb,
194 offset, 1, ENC_BIG_ENDIAN);
195 offset += 1;
197 length = tvb_get_ntohs(tvb, offset);
198 proto_tree_add_item(tree, hf_enttec_dmx_data_size, tvb,
199 offset, 2, ENC_BIG_ENDIAN);
200 offset += 2;
203 * XXX - we should handle a too-long length better.
205 if (length > 512)
206 length = 512;
208 if (type == ENTTEC_DATA_TYPE_RLE) {
209 /* uncompress the DMX data */
210 ui = 0;
211 ci = 0;
212 while (ci < length && ui < 512) {
213 v = tvb_get_uint8(tvb, offset+ci);
214 if (v == 0xFE) {
215 ci++;
216 count = tvb_get_uint8(tvb, offset+ci);
217 ci++;
218 v = tvb_get_uint8(tvb, offset+ci);
219 ci++;
220 for (i=0;i < count && ui < 512;i++) {
221 dmx_data[ui] = v;
222 dmx_data_offset[ui] = ci-3;
223 ui++;
225 } else if (v == 0xFD) {
226 ci++;
227 v = tvb_get_uint8(tvb, offset+ci);
228 dmx_data[ui] = v;
229 dmx_data_offset[ui] = ci;
230 ci++;
231 ui++;
232 } else {
233 dmx_data[ui] = v;
234 dmx_data_offset[ui] = ci;
235 ui++;
236 ci++;
239 dmx_data_offset[ui] = ci;
240 } else {
241 for (ui=0; ui < length;ui++) {
242 dmx_data[ui] = tvb_get_uint8(tvb, offset+ui);
243 dmx_data_offset[ui] = ui;
245 dmx_data_offset[ui] = ui;
249 if ((type == ENTTEC_DATA_TYPE_DMX || type == ENTTEC_DATA_TYPE_RLE) && global_disp_col_count > 0) {
250 hi = proto_tree_add_item(tree,
251 hf_enttec_dmx_data_data,
252 tvb,
253 offset,
254 length,
255 ENC_NA);
257 si = proto_item_add_subtree(hi, ett_enttec);
259 row_count = (ui/global_disp_col_count) + ((ui%global_disp_col_count) == 0 ? 0 : 1);
260 dmx_epstr = wmem_strbuf_create(pinfo->pool);
261 for (r=0; r < row_count;r++) {
262 for (c=0;(c < global_disp_col_count) && (((r*global_disp_col_count)+c) < ui);c++) {
263 if ((global_disp_col_count > 1) && (c % (global_disp_col_count/2)) == 0) {
264 wmem_strbuf_append_c(dmx_epstr, ' ');
266 v = dmx_data[(r*global_disp_col_count)+c];
267 if (global_disp_chan_val_type == 0) {
268 v = (v * 100) / 255;
269 if (v == 100) {
270 wmem_strbuf_append(dmx_epstr, "FL ");
271 } else {
272 wmem_strbuf_append_printf(dmx_epstr, chan_format[global_disp_chan_val_type], v);
274 } else {
275 wmem_strbuf_append_printf(dmx_epstr, chan_format[global_disp_chan_val_type], v);
279 start_offset = dmx_data_offset[(r*global_disp_col_count)];
280 end_offset = dmx_data_offset[(r*global_disp_col_count)+c];
282 proto_tree_add_none_format(si,hf_enttec_dmx_data_dmx_data, tvb,
283 offset+start_offset,
284 end_offset-start_offset,
285 string_format[global_disp_chan_nr_type], (r*global_disp_col_count)+1,
286 wmem_strbuf_get_str(dmx_epstr));
287 wmem_strbuf_truncate(dmx_epstr, 0);
290 item = proto_tree_add_item(si, hf_enttec_dmx_data_data_filter, tvb,
291 offset, length, ENC_NA );
292 proto_item_set_hidden(item);
294 offset += length;
296 else {
297 proto_tree_add_item(tree, hf_enttec_dmx_data_data_filter, tvb,
298 offset, length, ENC_NA);
299 offset += length;
304 return offset;
307 static int
308 dissect_enttec_reset(tvbuff_t *tvb _U_, unsigned offset, proto_tree *tree _U_)
311 return offset;
314 static int
315 dissect_enttec_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
317 int offset = 0;
318 uint32_t head = 0;
319 proto_tree *ti, *enttec_tree;
322 * If not enough bytes for the header word, not an ENTTEC packet.
324 if (!tvb_bytes_exist(tvb, offset, 4))
325 return 0;
327 head = tvb_get_ntohl(tvb, offset);
328 switch (head) {
330 case ENTTEC_HEAD_ESPR:
331 case ENTTEC_HEAD_ESPP:
332 case ENTTEC_HEAD_ESAP:
333 case ENTTEC_HEAD_ESDD:
334 case ENTTEC_HEAD_ESZZ:
336 * Valid packet type.
338 break;
340 default:
342 * Not a known DMX-over-UDP packet type, so probably not ENTTEC.
344 return 0;
347 /* Set the protocol column */
348 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENTTEC");
350 /* Clear out stuff in the info column */
351 col_add_str(pinfo->cinfo, COL_INFO,
352 val_to_str(head, enttec_head_vals, "Unknown (0x%08x)"));
354 ti = proto_tree_add_item(tree, proto_enttec, tvb, offset, -1, ENC_NA);
355 enttec_tree = proto_item_add_subtree(ti, ett_enttec);
357 proto_tree_add_item(enttec_tree, hf_enttec_head, tvb,
358 offset, 4, ENC_BIG_ENDIAN );
359 offset += 4;
361 switch (head) {
362 case ENTTEC_HEAD_ESPR:
363 offset = dissect_enttec_poll_reply( tvb, offset, enttec_tree);
364 break;
366 case ENTTEC_HEAD_ESPP:
367 offset = dissect_enttec_poll( tvb, offset, enttec_tree);
368 break;
370 case ENTTEC_HEAD_ESAP:
371 offset = dissect_enttec_ack( tvb, offset, enttec_tree);
372 break;
374 case ENTTEC_HEAD_ESDD:
375 offset = dissect_enttec_dmx_data( tvb, pinfo, offset, enttec_tree);
376 break;
378 case ENTTEC_HEAD_ESZZ:
379 offset = dissect_enttec_reset( tvb, offset, enttec_tree);
380 break;
383 return offset;
386 static int
387 dissect_enttec_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
389 int offset = 0;
390 uint32_t head = 0;
391 proto_tree *ti,*enttec_tree;
394 * If not enough bytes for the header word, don't try to
395 * reassemble to get 4 bytes of header word, as we don't
396 * know whether this will be an ENTTEC Config packet.
398 if (!tvb_bytes_exist(tvb, offset, 4))
399 return 0;
401 head = tvb_get_ntohl(tvb, offset);
402 if (head != ENTTEC_HEAD_ESNC) {
404 * Not a config packet, so probably not ENTTEC.
406 return 0;
409 /* XXX - reassemble to end of connection? */
411 /* Set the protocol column */
412 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENTTEC");
414 /* Clear out stuff in the info column */
415 col_add_str(pinfo->cinfo, COL_INFO,
416 val_to_str(head, enttec_head_vals, "Unknown (0x%08x)"));
418 ti = proto_tree_add_item(tree, proto_enttec, tvb, offset, -1, ENC_NA);
419 enttec_tree = proto_item_add_subtree(ti, ett_enttec);
421 proto_tree_add_item(enttec_tree, hf_enttec_head, tvb,
422 offset, 4, ENC_BIG_ENDIAN );
423 /* XXX - dissect the rest of the packet */
425 return tvb_captured_length(tvb);
428 void
429 proto_register_enttec(void)
431 static hf_register_info hf[] = {
432 /* General */
433 { &hf_enttec_head,
434 { "Head", "enttec.head",
435 FT_UINT32, BASE_HEX, VALS(enttec_head_vals), 0x0,
436 NULL, HFILL } },
437 { &hf_enttec_poll_reply_mac,
438 { "MAC", "enttec.poll_reply.mac",
439 FT_ETHER, BASE_NONE, NULL, 0x0,
440 NULL, HFILL } },
441 { &hf_enttec_poll_reply_node_type,
442 { "Node Type", "enttec.poll_reply.node_type",
443 FT_UINT16, BASE_HEX, NULL, 0x0,
444 NULL, HFILL } },
445 { &hf_enttec_poll_reply_version,
446 { "Version", "enttec.poll_reply.version",
447 FT_UINT8, BASE_DEC, NULL, 0x0,
448 NULL, HFILL } },
449 { &hf_enttec_poll_reply_switch,
450 { "Switch settings", "enttec.poll_reply.switch_settings",
451 FT_UINT8, BASE_HEX, NULL, 0x0,
452 NULL, HFILL } },
453 { &hf_enttec_poll_reply_name,
454 { "Name", "enttec.poll_reply.name",
455 FT_STRING, BASE_NONE, NULL, 0x0,
456 NULL, HFILL } },
457 { &hf_enttec_poll_reply_option,
458 { "Option Field", "enttec.poll_reply.option_field",
459 FT_UINT8, BASE_HEX, NULL, 0x0,
460 NULL, HFILL } },
461 { &hf_enttec_poll_reply_tos,
462 { "TOS", "enttec.poll_reply.tos",
463 FT_UINT8, BASE_HEX, NULL, 0x0,
464 NULL, HFILL } },
465 { &hf_enttec_poll_reply_ttl,
466 { "TTL", "enttec.poll_reply.ttl",
467 FT_UINT8, BASE_DEC, NULL, 0x0,
468 NULL, HFILL } },
469 { &hf_enttec_dmx_data_universe,
470 { "Universe", "enttec.dmx_data.universe",
471 FT_UINT8, BASE_DEC, NULL, 0x0,
472 NULL, HFILL } },
473 { &hf_enttec_dmx_data_start_code,
474 { "Start Code", "enttec.dmx_data.start_code",
475 FT_UINT8, BASE_DEC, NULL, 0x0,
476 NULL, HFILL } },
477 { &hf_enttec_dmx_data_type,
478 { "Data Type", "enttec.dmx_data.type",
479 FT_UINT8, BASE_HEX, VALS(enttec_data_type_vals), 0x0,
480 NULL, HFILL } },
481 { &hf_enttec_dmx_data_size,
482 { "Data Size", "enttec.dmx_data.size",
483 FT_UINT16, BASE_DEC, NULL, 0x0,
484 NULL, HFILL } },
485 { &hf_enttec_dmx_data_data,
486 { "DMX Data", "enttec.dmx_data.data",
487 FT_NONE, BASE_NONE, NULL, 0x0,
488 NULL, HFILL } },
489 { &hf_enttec_dmx_data_data_filter,
490 { "DMX Data", "enttec.dmx_data.data_filter",
491 FT_BYTES, BASE_NONE, NULL, 0x0,
492 NULL, HFILL } },
493 { &hf_enttec_dmx_data_dmx_data,
494 { "DMX Data", "enttec.dmx_data.dmx_data",
495 FT_NONE, BASE_NONE, NULL, 0x0,
496 NULL, HFILL } },
497 { &hf_enttec_poll_type,
498 { "Reply Type", "enttec.poll.reply_type",
499 FT_UINT8, BASE_DEC, NULL, 0x0,
500 NULL, HFILL } }
503 static int *ett[] = {
504 &ett_enttec,
507 module_t *enttec_module;
509 static const enum_val_t disp_chan_val_types[] = {
510 { "pro", "Percent", 0 },
511 { "hex", "Hexadecimal", 1 },
512 { "dec", "Decimal", 2 },
513 { NULL, NULL, 0 }
516 static const enum_val_t disp_chan_nr_types[] = {
517 { "hex", "Hexadecimal", 0 },
518 { "dec", "Decimal", 1 },
519 { NULL, NULL, 0 }
522 static const enum_val_t col_count[] = {
523 { "6", "6", 6 },
524 { "10", "10", 10 },
525 { "12", "12", 12 },
526 { "16", "16", 16 },
527 { "24", "24", 24 },
528 { NULL, NULL, 0 }
531 proto_enttec = proto_register_protocol("ENTTEC", "ENTTEC","enttec");
532 proto_register_field_array(proto_enttec,hf,array_length(hf));
533 proto_register_subtree_array(ett,array_length(ett));
535 enttec_udp_handle = register_dissector("enttec.udp", dissect_enttec_udp,proto_enttec);
536 enttec_tcp_handle = register_dissector("enttec.tcp", dissect_enttec_tcp,proto_enttec);
538 enttec_module = prefs_register_protocol(proto_enttec, NULL);
540 prefs_register_enum_preference(enttec_module, "dmx_disp_chan_val_type",
541 "DMX Display channel value type",
542 "The way DMX values are displayed",
543 &global_disp_chan_val_type,
544 disp_chan_val_types, false);
546 prefs_register_enum_preference(enttec_module, "dmx_disp_chan_nr_type",
547 "DMX Display channel nr. type",
548 "The way DMX channel numbers are displayed",
549 &global_disp_chan_nr_type,
550 disp_chan_nr_types, false);
552 prefs_register_enum_preference(enttec_module, "dmx_disp_col_count",
553 "DMX Display Column Count",
554 "The number of columns for the DMX display",
555 &global_disp_col_count,
556 col_count, false);
559 /* The registration hand-off routing */
560 void
561 proto_reg_handoff_enttec(void) {
562 dissector_add_uint_with_preference("tcp.port",TCP_PORT_ENTTEC,enttec_tcp_handle);
563 dissector_add_uint_with_preference("udp.port",UDP_PORT_ENTTEC,enttec_udp_handle);
567 * Editor modelines - https://www.wireshark.org/tools/modelines.html
569 * Local variables:
570 * c-basic-offset: 8
571 * tab-width: 8
572 * indent-tabs-mode: t
573 * End:
575 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
576 * :indentSize=8:tabSize=8:noTabs=false: