Preparations for dropping the old plugin api.
[obnox/wireshark/wip.git] / plugins / enttec / packet-enttec.c
1 /* packet-enttec.c
2  * Routines for ENTTEC packet disassembly
3  *
4  * $Id$
5  *
6  * Copyright (c) 2003,2004 by Erwin Rol <erwin@erwinrol.com>
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1999 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 /* Include files */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include "moduleinfo.h"
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <gmodule.h>
38 #include <ctype.h>
39 #include <time.h>
40 #include <string.h>
41 #include <epan/packet.h>
42 #include <epan/addr_resolv.h>
43 #include <epan/prefs.h>
44 #include <epan/strutil.h>
45
46 /* Define version if we are not building ethereal statically */
47
48 #ifndef ENABLE_STATIC
49 G_MODULE_EXPORT const gchar version[] = VERSION;
50 #endif
51
52 /*
53  * See
54  *
55  *      http://www.enttec.com/docs/enttec_protocol.pdf
56  */
57
58 /* Define UDP/TCP ports for ENTTEC */
59
60 #define UDP_PORT_ENTTEC 0x0D05
61 #define TCP_PORT_ENTTEC 0x0D05
62
63
64 #define ENTTEC_HEAD_ESPR 0x45535052
65 #define ENTTEC_HEAD_ESPP 0x45535050
66 #define ENTTEC_HEAD_ESAP 0x45534150
67 #define ENTTEC_HEAD_ESDD 0x45534444
68 #define ENTTEC_HEAD_ESNC 0x45534E43
69 #define ENTTEC_HEAD_ESZZ 0x45535A5A
70
71 static const value_string enttec_head_vals[] = {
72         { ENTTEC_HEAD_ESPR,     "Poll Reply" },
73         { ENTTEC_HEAD_ESPP,     "Poll" },
74         { ENTTEC_HEAD_ESAP,     "Ack/nAck" },
75         { ENTTEC_HEAD_ESDD,     "DMX Data" },
76         { ENTTEC_HEAD_ESNC,     "Config" },
77         { ENTTEC_HEAD_ESZZ,     "Reset" },
78         { 0,                    NULL }
79 };
80
81 #define ENTTEC_DATA_TYPE_DMX            0x01
82 #define ENTTEC_DATA_TYPE_CHAN_VAL       0x02
83 #define ENTTEC_DATA_TYPE_RLE            0x04
84
85 static const value_string enttec_data_type_vals[] = {
86         { ENTTEC_DATA_TYPE_DMX,         "Uncompressed DMX" },
87         { ENTTEC_DATA_TYPE_CHAN_VAL,    "Channel+Value" },
88         { ENTTEC_DATA_TYPE_RLE,         "RLE Compressed DMX" },
89         { 0,                            NULL }
90 };
91
92 void proto_reg_handoff_enttec(void);
93
94 /* Define the enttec proto */
95 static int proto_enttec = -1;
96
97 /* general */
98 static int hf_enttec_head = -1;
99
100 /* poll */
101 static int hf_enttec_poll_type = -1;
102
103 /* poll reply */
104 static int hf_enttec_poll_reply_mac = -1;
105 static int hf_enttec_poll_reply_node_type = -1;
106 static int hf_enttec_poll_reply_version = -1;
107 static int hf_enttec_poll_reply_switch = -1;
108 static int hf_enttec_poll_reply_name = -1;
109 static int hf_enttec_poll_reply_option = -1;
110 static int hf_enttec_poll_reply_tos = -1;
111 static int hf_enttec_poll_reply_ttl = -1;
112
113 /* dmx data */
114 static int hf_enttec_dmx_data_universe = -1;
115 static int hf_enttec_dmx_data_start_code = -1;
116 static int hf_enttec_dmx_data_type = -1;
117 static int hf_enttec_dmx_data_size = -1;
118 static int hf_enttec_dmx_data_data = -1;
119 static int hf_enttec_dmx_data_data_filter = -1;
120 static int hf_enttec_dmx_data_dmx_data = -1;
121
122 /* Define the tree for enttec */
123 static int ett_enttec = -1;
124
125 /*
126  * Here are the global variables associated with the preferences
127  * for enttec
128  */
129
130 static guint global_udp_port_enttec = UDP_PORT_ENTTEC;
131 static guint udp_port_enttec = UDP_PORT_ENTTEC;
132
133 static guint global_tcp_port_enttec = TCP_PORT_ENTTEC;
134 static guint tcp_port_enttec = TCP_PORT_ENTTEC;
135
136 static guint global_disp_chan_val_type = 0;
137 static guint global_disp_col_count = 16;
138 static guint global_disp_chan_nr_type = 0;
139
140
141 /* A static handle for the ip dissector */
142 static dissector_handle_t ip_handle;
143 static dissector_handle_t rdm_handle;
144
145 static gint
146 dissect_enttec_poll_reply(tvbuff_t *tvb, guint offset, proto_tree *tree)
147 {
148         proto_tree_add_item(tree, hf_enttec_poll_reply_mac, tvb,
149                                         offset, 6, FALSE);
150         offset += 6;
151
152         proto_tree_add_item(tree, hf_enttec_poll_reply_node_type, tvb,
153                                         offset, 2, FALSE);
154         offset += 2;
155
156         proto_tree_add_item(tree, hf_enttec_poll_reply_version, tvb,
157                                         offset, 1, FALSE);
158         offset += 1;
159
160         proto_tree_add_item(tree, hf_enttec_poll_reply_switch, tvb,
161                                         offset, 1, FALSE);
162         offset += 1;
163         
164         proto_tree_add_item(tree, hf_enttec_poll_reply_name, tvb,
165                                         offset, 10, FALSE);
166         offset += 10;
167
168         proto_tree_add_item(tree, hf_enttec_poll_reply_option, tvb,
169                                         offset, 1, FALSE);
170         offset += 1;
171         
172         proto_tree_add_item(tree, hf_enttec_poll_reply_tos, tvb,
173                                         offset, 1, FALSE);
174         offset += 1;
175         
176         proto_tree_add_item(tree, hf_enttec_poll_reply_ttl, tvb,
177                                         offset, 1, FALSE);
178         offset += 1;
179
180         /* data */
181
182         return offset;
183 }
184
185 static gint
186 dissect_enttec_poll(tvbuff_t *tvb, guint offset, proto_tree *tree)
187 {
188         proto_tree_add_item(tree, hf_enttec_poll_type, tvb,
189                                         offset, 1, FALSE);
190         offset += 1;
191
192         return offset;
193 }
194
195 static gint
196 dissect_enttec_ack(tvbuff_t *tvb _U_, guint offset, proto_tree *tree _U_)
197 {
198
199         return offset;
200 }
201
202 static gint
203 dissect_enttec_dmx_data(tvbuff_t *tvb, guint offset, proto_tree *tree)
204 {
205         const char* chan_format[] = {
206                 "%2u ",
207                 "%02x ",
208                 "%3u "
209         };
210         const char* string_format[] = {
211                 "%03x: %s",
212                 "%3u: %s"
213         };
214
215         static guint8 dmx_data[512];
216         static guint16 dmx_data_offset[513]; /* 1 extra for last offset */
217         static char string[255];
218
219         proto_tree *hi,*si;
220         guint16 length,r,c,row_count;
221         guint8 v,type,count;
222         guint16 ci,ui,i,start_offset,end_offset;
223         char* ptr;
224
225         proto_tree_add_item(tree, hf_enttec_dmx_data_universe, tvb,
226                                         offset, 1, FALSE);
227         offset += 1;
228
229         proto_tree_add_item(tree, hf_enttec_dmx_data_start_code, tvb,
230                                         offset, 1, FALSE);
231         offset += 1;
232
233         type = tvb_get_guint8(tvb, offset);     
234         proto_tree_add_item(tree, hf_enttec_dmx_data_type, tvb,
235                                         offset, 1, FALSE);
236         offset += 1;
237
238         length = tvb_get_ntohs(tvb, offset);
239         proto_tree_add_item(tree, hf_enttec_dmx_data_size, tvb,
240                                         offset, 2, FALSE);
241         offset += 2;
242
243         if (length > 512)
244                 length = 512;
245
246         if (type == ENTTEC_DATA_TYPE_RLE) {
247                 /* uncompres the DMX data */
248                 ui = 0;
249                 ci = 0;
250                 while (ci < length) {
251                         v = tvb_get_guint8(tvb, offset+ci);
252                         if (v == 0xFE) {
253                                 ci++;
254                                 count = tvb_get_guint8(tvb, offset+ci);
255                                 ci++;
256                                 v = tvb_get_guint8(tvb, offset+ci);
257                                 ci++;
258                                 for (i=0;i < count;i++) {
259                                         dmx_data[ui] = v;
260                                         dmx_data_offset[ui] = ci-3;
261                                         ui++;
262                                 }
263                         } else if (v == 0xFD) {
264                                 ci++;
265                                 v = tvb_get_guint8(tvb, offset+ci);                             
266                                 dmx_data[ui] = v;
267                                 dmx_data_offset[ui] = ci;
268                                 ci++;
269                                 ui++;
270                         } else {
271                                 dmx_data[ui] = v;
272                                 dmx_data_offset[ui] = ci;
273                                 ui++;
274                                 ci++;
275                         }
276                 }
277                 dmx_data_offset[ui] = ci;
278         } else {
279                 for (ui=0; ui < length;ui++) {
280                         dmx_data[ui] =  tvb_get_guint8(tvb, offset+ui);
281                         dmx_data_offset[ui] = ui;
282                 }
283                 dmx_data_offset[ui] = ui;
284         } 
285
286
287         if (type == ENTTEC_DATA_TYPE_DMX || type == ENTTEC_DATA_TYPE_RLE) {
288                 hi = proto_tree_add_item(tree,
289                                         hf_enttec_dmx_data_data,
290                                         tvb,
291                                         offset,
292                                         length,
293                                         FALSE);
294
295                 si = proto_item_add_subtree(hi, ett_enttec);
296                         
297                 row_count = (ui/global_disp_col_count) + ((ui%global_disp_col_count) == 0 ? 0 : 1);
298                 ptr = string;
299                 for (r=0; r < row_count;r++) {
300                         for (c=0;(c < global_disp_col_count) && (((r*global_disp_col_count)+c) < ui);c++) {
301                                 if ((c % (global_disp_col_count/2)) == 0) {
302                                         sprintf(ptr, " ");
303                                         ptr++;
304                                 }
305                                 v = dmx_data[(r*global_disp_col_count)+c];
306                                 if (global_disp_chan_val_type == 0) {
307                                         v = (v * 100) / 255;
308                                         if (v == 100) {
309                                                 sprintf(ptr, "FL ");
310                                         } else {
311                                                 sprintf(ptr, chan_format[global_disp_chan_val_type], v);
312                                         }
313                                 } else {
314                                         sprintf(ptr, chan_format[global_disp_chan_val_type], v);
315                                 }
316                                 ptr += strlen(ptr);
317                         }
318
319                         start_offset = dmx_data_offset[(r*global_disp_col_count)];
320                         end_offset = dmx_data_offset[(r*global_disp_col_count)+c];              
321
322                         proto_tree_add_none_format(si,hf_enttec_dmx_data_dmx_data, tvb,
323                                                 offset+start_offset, 
324                                                 end_offset-start_offset,
325                                                 string_format[global_disp_chan_nr_type], (r*global_disp_col_count)+1, string);
326                         ptr = string;
327                 }
328                 
329                 proto_tree_add_item_hidden(si, hf_enttec_dmx_data_data_filter, tvb,
330                                 offset, length, FALSE );
331                 
332                 offset += length;
333         } else if (type == ENTTEC_DATA_TYPE_CHAN_VAL) {
334                 proto_tree_add_item(tree, hf_enttec_dmx_data_data_filter, tvb,
335                                         offset, length, FALSE);
336                 offset += length;
337         } else {
338                 proto_tree_add_item(tree, hf_enttec_dmx_data_data_filter, tvb,
339                                         offset, length, FALSE);
340                 offset += length;
341         }               
342
343         
344                 
345         return offset;
346 }
347
348 static gint
349 dissect_enttec_config(tvbuff_t *tvb _U_, guint offset, proto_tree *tree _U_)
350 {
351
352         return offset;
353 }
354
355 static gint
356 dissect_enttec_reset(tvbuff_t *tvb _U_, guint offset, proto_tree *tree _U_)
357 {
358
359         return offset;
360 }
361
362 static void
363 dissect_enttec(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 
364 {
365         gint offset = 0;
366         guint32 head = 0;
367         proto_tree *ti,*enttec_tree=NULL;
368
369         /* Set the protocol column */
370         if (check_col(pinfo->cinfo,COL_PROTOCOL)) {
371                 col_set_str(pinfo->cinfo,COL_PROTOCOL,"ENTTEC");
372         }
373
374         head = tvb_get_ntohl(tvb, offset);
375
376         /* Clear out stuff in the info column */
377         if (check_col(pinfo->cinfo,COL_INFO)) {
378                 col_clear(pinfo->cinfo,COL_INFO);
379                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s",
380                                 val_to_str(head, enttec_head_vals, "Unknown (0x%08x)"));
381         }
382
383         if (tree) {
384                 ti = proto_tree_add_item(tree, proto_enttec, tvb, offset, -1, FALSE);
385                 enttec_tree = proto_item_add_subtree(ti, ett_enttec);
386         }
387
388         if (enttec_tree) {
389                 proto_tree_add_item(enttec_tree, hf_enttec_head, tvb,
390                                         offset, 4, FALSE );
391                 offset += 4;
392
393                 switch (head) {
394                         case ENTTEC_HEAD_ESPR:
395                                 offset = dissect_enttec_poll_reply( tvb, offset, enttec_tree);
396                                 break;
397
398                         case ENTTEC_HEAD_ESPP:
399                                 offset = dissect_enttec_poll( tvb, offset, enttec_tree);
400                                 break;
401
402                         case ENTTEC_HEAD_ESAP:
403                                 offset = dissect_enttec_ack( tvb, offset, enttec_tree);
404                                 break;
405
406                         case ENTTEC_HEAD_ESDD:
407                                 offset = dissect_enttec_dmx_data( tvb, offset, enttec_tree);
408                                 break;
409
410                         case ENTTEC_HEAD_ESNC:
411                                 offset = dissect_enttec_config( tvb, offset, enttec_tree);
412                                 break;
413
414                         case ENTTEC_HEAD_ESZZ:
415                                 offset = dissect_enttec_reset( tvb, offset, enttec_tree);
416                                 break;
417                 }
418
419         }
420 }
421
422 void
423 proto_register_enttec(void) 
424 {
425         static hf_register_info hf[] = {
426                 /* General */
427                 { &hf_enttec_head,
428                         { "Head", "enttec.head",
429                           FT_UINT32, BASE_HEX, VALS(enttec_head_vals), 0x0,
430                           "Head", HFILL } },
431                 { &hf_enttec_poll_reply_mac,
432                         { "MAC", "enttec.poll_reply.mac",
433                           FT_ETHER, BASE_HEX, NULL, 0x0,
434                           "MAC", HFILL } },
435                 { &hf_enttec_poll_reply_node_type,
436                         { "Node Type", "enttec.poll_reply.node_type",
437                           FT_UINT16, BASE_HEX, NULL, 0x0,
438                           "Node Type", HFILL } },
439                 { &hf_enttec_poll_reply_version,
440                         { "Version", "enttec.poll_reply.version",
441                           FT_UINT8, BASE_DEC, NULL, 0x0,
442                           "Version", HFILL } },
443                 { &hf_enttec_poll_reply_switch,
444                         { "Switch settings", "enttec.poll_reply.switch_settings",
445                           FT_UINT8, BASE_HEX, NULL, 0x0,
446                           "Switch settings", HFILL } },
447                 { &hf_enttec_poll_reply_name,
448                         { "Name", "enttec.poll_reply.name",
449                           FT_STRING, BASE_DEC, NULL, 0x0,
450                           "Name", HFILL } },
451                 { &hf_enttec_poll_reply_option,
452                         { "Option Field", "enttec.poll_reply.option_field",
453                           FT_UINT8, BASE_HEX, NULL, 0x0,
454                           "Option Field", HFILL } },
455                 { &hf_enttec_poll_reply_tos,
456                         { "TOS", "enttec.poll_reply.tos",
457                           FT_UINT8, BASE_HEX, NULL, 0x0,
458                           "TOS", HFILL } },
459                 { &hf_enttec_poll_reply_ttl,
460                         { "TTL", "enttec.poll_reply.ttl",
461                           FT_UINT8, BASE_DEC, NULL, 0x0,
462                           "TTL", HFILL } },
463                 { &hf_enttec_dmx_data_universe,
464                         { "Universe", "enttec.dmx_data.universe",
465                           FT_UINT8, BASE_DEC, NULL, 0x0,
466                           "Universe", HFILL } },
467                 { &hf_enttec_dmx_data_start_code,
468                         { "Start Code", "enttec.dmx_data.start_code",
469                           FT_UINT8, BASE_DEC, NULL, 0x0,
470                           "Start Code", HFILL } },
471                 { &hf_enttec_dmx_data_type,
472                         { "Data Type", "enttec.dmx_data.type",
473                           FT_UINT8, BASE_HEX, VALS(enttec_data_type_vals), 0x0,
474                           "Data Type", HFILL } },
475                 { &hf_enttec_dmx_data_size,
476                         { "Data Size", "enttec.dmx_data.size",
477                           FT_UINT16, BASE_DEC, NULL, 0x0,
478                           "Data Size", HFILL } },
479                 { &hf_enttec_dmx_data_data,
480                         { "DMX Data", "enttec.dmx_data.data",
481                           FT_NONE, BASE_DEC, NULL, 0x0,
482                           "DMX Data", HFILL } },
483                 { &hf_enttec_dmx_data_data_filter,
484                         { "DMX Data", "enttec.dmx_data.data_filter",
485                           FT_BYTES, BASE_DEC, NULL, 0x0,
486                           "DMX Data", HFILL } },
487                 { &hf_enttec_dmx_data_dmx_data,
488                         { "DMX Data", "enttec.dmx_data.dmx_data",
489                           FT_NONE, BASE_DEC, NULL, 0x0,
490                           "DMX Data", HFILL } },
491                 { &hf_enttec_poll_type,
492                         { "Reply Type", "enttec.poll.reply_type",
493                           FT_UINT8, BASE_DEC, NULL, 0x0,
494                           "Reply Type", HFILL } }
495         };
496
497         static gint *ett[] = {
498                 &ett_enttec,
499         };
500
501         module_t *enttec_module;
502
503         static enum_val_t disp_chan_val_types[] = {
504                 { "pro", "Percent", 0 },
505                 { "hex", "Hexadecimal", 1 },
506                 { "dec", "Decimal", 2 },
507                 { NULL, NULL, 0 }
508         };
509
510         static enum_val_t disp_chan_nr_types[] = {
511                 { "hex", "Hexadecimal", 0 },
512                 { "dec", "Decimal", 1 },
513                 { NULL, NULL, 0 }
514         };
515
516         static enum_val_t col_count[] = {
517                 { "6", "6", 6 },
518                 { "10", "10", 10 },
519                 { "12", "12", 12 },
520                 { "16", "16", 16 },
521                 { "24", "24", 24 },
522                 { NULL, NULL, 0 }
523         };
524
525         proto_enttec = proto_register_protocol("ENTTEC", "ENTTEC","enttec");
526         proto_register_field_array(proto_enttec,hf,array_length(hf));
527         proto_register_subtree_array(ett,array_length(ett));
528
529         enttec_module = prefs_register_protocol(proto_enttec,
530                                                 proto_reg_handoff_enttec);
531         prefs_register_uint_preference(enttec_module, "udp_port",
532                                         "ENTTEC UDP Port",
533                                         "The UDP port on which ENTTEC packets will be sent",
534                                         10,&global_udp_port_enttec);
535
536         prefs_register_uint_preference(enttec_module, "tcp_port",
537                                         "ENTTEC TCP Port",
538                                         "The TCP port on which ENTTEC packets will be sent",
539                                         10,&global_tcp_port_enttec);
540
541         prefs_register_enum_preference(enttec_module, "dmx_disp_chan_val_type",
542                                 "DMX Display channel value type",
543                                 "The way DMX values are displayed",
544                                 &global_disp_chan_val_type,
545                                 disp_chan_val_types, FALSE);
546
547         prefs_register_enum_preference(enttec_module, "dmx_disp_chan_nr_type",
548                                 "DMX Display channel nr. type",
549                                 "The way DMX channel numbers are displayed",
550                                 &global_disp_chan_nr_type,
551                                 disp_chan_nr_types, FALSE);
552
553         prefs_register_enum_preference(enttec_module, "dmx_disp_col_count",
554                                 "DMX Display Column Count",
555                                 "The number of columns for the DMX display",
556                                 &global_disp_col_count,
557                                 col_count, FALSE);
558 }
559
560 /* The registration hand-off routing */
561 void
562 proto_reg_handoff_enttec(void) {
563         static int enttec_initialized = FALSE;
564         static dissector_handle_t enttec_handle;
565
566         ip_handle = find_dissector("ip");
567         rdm_handle = find_dissector("rdm");
568
569
570         if(!enttec_initialized) {
571                 enttec_handle = create_dissector_handle(dissect_enttec,proto_enttec);
572                 enttec_initialized = TRUE;
573         } else {
574                 dissector_delete("udp.port",udp_port_enttec,enttec_handle);
575                 dissector_delete("tcp.port",tcp_port_enttec,enttec_handle);
576         }
577
578         udp_port_enttec = global_udp_port_enttec;
579         tcp_port_enttec = global_tcp_port_enttec;  
580
581         dissector_add("udp.port",global_udp_port_enttec,enttec_handle);
582         dissector_add("tcp.port",global_tcp_port_enttec,enttec_handle);
583 }
584
585 /* Start the functions we need for the plugin stuff */
586
587 #ifndef ENABLE_STATIC
588
589 G_MODULE_EXPORT void
590 plugin_reg_handoff(void){
591         proto_reg_handoff_enttec();
592 }
593
594 G_MODULE_EXPORT void
595 new_plugin_init(void)
596 {
597         /* register the new protocol, protocol fields, and subtrees */
598         if (proto_enttec == -1) { /* execute protocol initialization only once */
599                 proto_register_enttec();
600         }
601 }
602
603 #endif
604
605 /* End the functions we need for plugin stuff */
606