From Juha Takala:
[obnox/wireshark/wip.git] / epan / dissectors / packet-elcom.c
1 /* packet-elcom.c
2  * Routines for elcom packet dissection
3  * Copyright 2008, 2011 juha.takala@iki.fi (Juha Takala)
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from packet-imap.c
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  *
27  * I found the protocol specification at
28  *  http://www.sintef.no/upload/Energiforskning/Energisystemer/ELCOM 90.pdf
29  */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <epan/packet.h>
36
37 #define TCP_PORT_ELCOM          5997
38
39 /* Application level: */
40 #define A_CONRQ 0x04
41 #define A_CONRS 0x05
42
43 /* Presentation level: */
44 #define P_CONRQ 0x00
45 #define P_CONRS 0x10
46 #define P_RELRQ 0x20
47 #define P_RELRS 0x30
48 #define P_DATRQ 0x80
49
50 #define TC_REQ 0x40
51 #define TC_RSP 0x41
52
53 #define LOWADR_LEN 17
54 #define SUFFIX_LEN 2
55 #define TOTAL_LEN (LOWADR_LEN + SUFFIX_LEN + 2)
56
57 #define ELCOM_UNKNOWN_ENDIAN 0
58 #define ELCOM_LITTLE_ENDIAN 1
59 #define ELCOM_BIG_ENDIAN 2
60
61 static int proto_elcom = -1;
62 static int hf_elcom_response = -1;
63 static int hf_elcom_request = -1;
64
65 static int hf_elcom_length = -1;
66 static int hf_elcom_type = -1;
67
68 static int hf_elcom_initiator_endian = -1;
69 static int hf_elcom_initiator_ip = -1;
70 static int hf_elcom_initiator_port = -1;
71 static int hf_elcom_initiator_suff = -1;
72
73 static int hf_elcom_responder_endian = -1;
74 static int hf_elcom_responder_ip = -1;
75 static int hf_elcom_responder_port = -1;
76 static int hf_elcom_responder_suff = -1;
77
78 static int hf_elcom_userdata_length = -1;
79 static int hf_elcom_userdata_pduid = -1;
80 static int hf_elcom_userdata_version = -1;
81 static int hf_elcom_userdata_result = -1;
82 static int hf_elcom_userdata_restmark = -1;
83 static int hf_elcom_userdata_cf = -1;
84
85 static int hf_elcom_datarequest_grouptype = -1;
86 static int hf_elcom_datarequest_result = -1;
87 static int hf_elcom_datarequest_groupnumber = -1;
88 static int hf_elcom_datarequest_grouppriority = -1;
89 static int hf_elcom_datarequest_groupsize = -1;
90 static int hf_elcom_datarequest_groupindex1 = -1;
91 static int hf_elcom_datarequest_groupindex2 = -1;
92 static int hf_elcom_datarequest_oid = -1;
93
94 static int hf_elcom_release_reason = -1;
95 static int hf_elcom_release_result = -1;
96
97 static gint ett_elcom = -1;
98 static gint ett_elcom_initiator = -1;
99 static gint ett_elcom_responder = -1;
100 static gint ett_elcom_userdata = -1;
101 static gint ett_elcom_datarequest = -1;
102
103 static gboolean elcom_show_hex = TRUE;
104
105
106 static gint
107 dissect_lower_address(proto_item *ti_arg, gint ett_arg,
108                       tvbuff_t *tvb, gint arg_offset,
109                       int hf_endian, int hf_ip, int hf_port, int hf_suff)
110 {
111         gint offset = arg_offset;
112         gint endian = ELCOM_UNKNOWN_ENDIAN;
113         guint8 len1, len2;
114         guint8 *suffix;
115         proto_tree *tree;
116         proto_item *ti;
117
118         tree = proto_item_add_subtree(ti_arg, ett_arg);
119         
120         /* 
121          * Coding of address:
122          * ELCOM-90 TRA3825.02 User Element conventions, p. 5-2 and Appendix G
123          */
124         len1 = tvb_get_guint8(tvb, offset);
125         if (tvb_length_remaining(tvb, offset+len1+1) <= 0)
126                 return offset;
127         len2 = tvb_get_guint8(tvb, offset+len1+1);
128         if (tvb_length_remaining(tvb, offset+len1+len2+2) <= 0)
129                 return offset;
130         if ((len1 != LOWADR_LEN) || (len2 != SUFFIX_LEN)) {
131                 proto_item_append_text(tree, " Invalid structure");
132                 return offset;
133         }
134
135
136         /* Show pre stuff */
137         if (0x82 != tvb_get_guint8(tvb, offset+1)) {
138                 proto_item_append_text(tree, " Not IPV4 address");
139                 return offset;
140         }
141         offset += 2;
142
143         if ((0x02 == tvb_get_guint8(tvb, offset)) &&
144             (0x00 == tvb_get_guint8(tvb, offset+1))) {
145                 endian = ELCOM_LITTLE_ENDIAN;
146         } else if ((0x00 == tvb_get_guint8(tvb, offset)) &&
147                    (0x02 == tvb_get_guint8(tvb, offset+1))) {
148                 endian = ELCOM_BIG_ENDIAN;
149         }
150
151         /* endian */
152         ti = proto_tree_add_uint(tree, hf_endian, tvb, offset, 2, tvb_get_ntohs(tvb, offset));
153         if (endian == ELCOM_LITTLE_ENDIAN)
154                 proto_item_append_text(ti, " Little");
155         else if (endian == ELCOM_BIG_ENDIAN)
156                 proto_item_append_text(ti, " Big");
157         else
158                 proto_item_append_text(ti, " Unknown");
159         offset += 2;
160
161         /* port */
162         proto_tree_add_uint(tree, hf_port, tvb, offset, 2, tvb_get_ntohs(tvb, offset));
163         offset += 2;
164
165         /* ip-addr */
166         proto_tree_add_ipv4(tree, hf_ip, tvb, offset, 4, tvb_get_ipv4(tvb, offset));
167         offset += 4;
168
169         offset += 8;            /* skip the zero bytes */
170
171         /* SUFFIX */
172         suffix = tvb_get_string(tvb, offset+1, len2);
173         ti = proto_tree_add_item(tree, hf_suff, tvb, offset, 1, TRUE);
174         offset += len2+1;
175
176         if (!(suffix[0] == 'A' || suffix[0] == 'B')) {
177                 g_free(suffix);
178                 proto_item_append_text(ti, "  (invalid)");
179                 return offset;
180         }
181         proto_item_append_text(ti, "  (%s)",
182                                suffix[1] == 'A' ? "Control" :
183                                suffix[1] == 'B' ? "Unsolicited" :
184                                suffix[1] == 'C' ? "Periodic" :
185                                suffix[1] == 'D' ? "Requested, scheduling" :
186                                suffix[1] == 'E' ? "Requested, present/archived" :
187                                suffix[1] == 'G' ? "Supervisory" :
188                                suffix[1] == 'F' ? "Test" :
189                                "<<-- WHAT?");
190
191         g_free(suffix);
192         return offset;
193 }
194
195 static gint
196 dissect_userdata(proto_item *ti_arg, gint ett_arg, tvbuff_t *tvb, gint arg_offset)
197 {
198         gint offset = arg_offset;
199         guint8 flen, pduid, version, result, lenbytes, restmark;
200         guint8 year, month, day, hour, min, sec;
201         guint16 msec;
202         proto_tree *tree;
203         proto_item *ti;
204
205         tree = proto_item_add_subtree(ti_arg, ett_arg);
206
207         /* length of User Data, should be 1 byte field ... */
208         flen = tvb_get_guint8(tvb, offset);
209         lenbytes = 1;
210         
211         /* ... but sometimes it seems to be 2 bytes; try to be clever */
212         if (flen == 0) {
213                 flen = tvb_get_guint8(tvb, offset+1);
214                 lenbytes = 2;
215         }
216         if (flen == 0 || flen > 79) /* invalid */
217                 return offset;
218
219         ti = proto_tree_add_uint(tree, hf_elcom_userdata_length, tvb, offset, lenbytes, flen);
220         offset += lenbytes;
221         if (lenbytes == 2) {
222                 proto_item_append_text(ti, " (2 bytes, should be 1 byte)");
223         }
224
225         if (tvb_length_remaining(tvb, offset) <= 0)
226                 return offset;
227
228         pduid = tvb_get_guint8(tvb, offset);
229         ti = proto_tree_add_uint(tree, hf_elcom_userdata_pduid, tvb, offset, 1, pduid);
230         offset++;
231         switch (pduid) {
232         case 0x04: proto_item_append_text(ti, " (connect request)"); break;
233         case 0x05: proto_item_append_text(ti, " (connect response)"); break;
234         default:   proto_item_append_text(ti, " (unknown)"); return offset;
235         }
236
237         if (tvb_length_remaining(tvb, offset) <= 0)
238                 return offset;
239
240         version = tvb_get_guint8(tvb, offset);
241         ti = proto_tree_add_uint(tree, hf_elcom_userdata_version, tvb, offset, 1, version);
242         offset++;
243         switch (version) {
244         case 0x00: proto_item_append_text(ti, " (class 0, v0)"); break;
245         case 0x01: proto_item_append_text(ti, " (class 1, v0)"); break;
246         case 0x02: proto_item_append_text(ti, " (class 2, v0)"); break;
247         case 0x12: proto_item_append_text(ti, " (class 2, v1)"); break;
248         case 0x13: proto_item_append_text(ti, " (class 3, v1)"); break;
249         default:   proto_item_append_text(ti, " (unknown)"); return offset;
250         }
251
252         if (tvb_length_remaining(tvb, offset) <= 0)
253                 return offset;
254
255         result = tvb_get_guint8(tvb, offset);
256         ti = proto_tree_add_uint(tree, hf_elcom_userdata_result, tvb, offset, 1, result);
257         offset++;
258         switch (result) {
259         case 0x00: proto_item_append_text(ti, " (OK)"); break;
260         default:   proto_item_append_text(ti, " (unknown)"); return offset;
261         }
262
263         /* show the rest */
264         /*      tree2 = proto_tree_add_text(tree, tvb, offset, -1, "User Data"); */
265         
266         if (tvb_length_remaining(tvb, offset) <= 0)
267                 return offset;
268         restmark = tvb_get_guint8(tvb, offset);
269         ti = proto_tree_add_uint(tree, hf_elcom_userdata_restmark, tvb, offset, 1, restmark);
270         proto_item_append_text(ti, " <-- '0' = no restart etc.");
271         offset +=1;
272
273         if (tvb_length_remaining(tvb, offset+8) <= 0)
274                 return offset;
275         year  = tvb_get_guint8(tvb, offset);
276         month = tvb_get_guint8(tvb, offset+1);
277         day   = tvb_get_guint8(tvb, offset+2);
278         hour  = tvb_get_guint8(tvb, offset+3);
279         min   = tvb_get_guint8(tvb, offset+4);
280         sec   = tvb_get_guint8(tvb, offset+5);
281         msec  = tvb_get_ntohs(tvb, offset+6);
282
283         proto_tree_add_none_format(tree, hf_elcom_userdata_cf, tvb, offset, 8,
284                                    "Control Field: %4d-%02d-%02d %02d:%02d:%02d.%d",
285                                    year+1900, month, day, hour, min, sec, msec);
286
287         offset += 12;
288         if (tvb_length_remaining(tvb, offset+12) > 0) {
289                 proto_item_append_text(ti, " Security info: ");
290         }
291         /* security info field, if present */
292         while (tvb_length_remaining(tvb, offset) > 0) {
293                 proto_item_append_text(ti, elcom_show_hex ? " %02x" : " %03o",
294                                        tvb_get_guint8(tvb, offset));
295                 offset++;
296         }
297
298         return offset;
299 }
300
301 static gint
302 dissect_datarequest(proto_item *ti_arg, gint ett_arg, tvbuff_t *tvb, gint arg_offset)
303 {
304         gint offset = arg_offset;
305         guint8 gtype,  gnr, prio, gsize, oidlen, result;
306         guint16 index1, index2;
307         proto_tree *tree, *tree2;
308         proto_item *ti;
309
310         tree = proto_item_add_subtree(ti_arg, ett_arg);
311         if (tvb_length_remaining(tvb, offset) <= 0)
312                 return offset;
313
314         gtype = tvb_get_guint8(tvb, offset);
315         ti = proto_tree_add_uint(tree, hf_elcom_datarequest_grouptype,
316                                  tvb, offset, 1, gtype);
317         offset += 1;
318
319         switch (gtype) {
320         case TC_REQ:
321                 proto_item_append_text(ti, " = Test Connection Request");
322                 break;
323
324         case TC_RSP:
325                 proto_item_append_text(ti, " = Test Connection Response");
326
327                 result = tvb_get_guint8(tvb, offset);
328                 ti = proto_tree_add_uint(tree, hf_elcom_datarequest_result,
329                                          tvb, offset, 1, result);
330                 offset++;
331
332                 break;
333
334         default:
335                 proto_item_append_text(ti, " <<--- meaning WHAT?");
336                 return offset;
337         }
338         if (tvb_length_remaining(tvb, offset) <= 0)
339                 return offset;
340
341         gnr = tvb_get_guint8(tvb, offset);
342         proto_tree_add_uint(tree, hf_elcom_datarequest_groupnumber, tvb, offset, 1, gnr);
343         offset += 1;
344         if (tvb_length_remaining(tvb, offset) <= 0)
345                 return offset;
346
347         prio = tvb_get_guint8(tvb, offset);
348         proto_tree_add_uint(tree, hf_elcom_datarequest_grouppriority, tvb, offset, 1, prio);
349         offset += 1;
350         if (tvb_length_remaining(tvb, offset) <= 0)
351                 return offset;
352
353         gsize = tvb_get_guint8(tvb, offset);
354         proto_tree_add_uint(tree, hf_elcom_datarequest_groupsize, tvb, offset, 1, gsize);
355         offset += 1;
356         if (tvb_length_remaining(tvb, offset) <= 0)
357                 return offset;
358
359         index1 = tvb_get_ntohs(tvb, offset);
360         proto_tree_add_uint(tree, hf_elcom_datarequest_groupindex1, tvb, offset, 2, index1);
361         offset += 2;
362         if (tvb_length_remaining(tvb, offset) <= 0)
363                 return offset;
364
365         index2 = tvb_get_ntohs(tvb, offset);
366         proto_tree_add_uint(tree, hf_elcom_datarequest_groupindex2, tvb, offset, 2, index2);
367         offset += 2;
368         if (tvb_length_remaining(tvb, offset) <= 0)
369                 return offset;
370
371         while (1) {
372                 oidlen = tvb_get_guint8(tvb, offset);
373                 if (oidlen == 0) /* normal termination */
374                         break;
375                 if (tvb_length_remaining(tvb, offset+oidlen+1) <= 0)
376                         return offset;
377                 proto_tree_add_item(tree, hf_elcom_datarequest_oid, tvb, offset, 1, TRUE);
378                 offset += oidlen+1;
379         }
380         offset += 1;            /* the loop exited at the 0 length byte */
381         if (tvb_length_remaining(tvb, offset) <= 0)
382                 return offset;
383
384         /* show the rest */
385         tree2 = proto_tree_add_text(tree, tvb, offset, -1, "leftover =");
386         while (tvb_length_remaining(tvb, offset) > 0) {
387                 proto_item_append_text(tree2, elcom_show_hex ? " %02x" : " %03o",
388                                        tvb_get_guint8(tvb, offset));
389                 offset++;
390         }
391         
392         return offset;
393 }
394
395 static void
396 dissect_elcom(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
397 {
398         gboolean        is_request, length_ok;
399         proto_tree      *elcom_tree;
400         proto_item      *ti, *hidden_item;
401         gint            offset = 0;
402         guint16         elcom_len;
403         guint8          elcom_msg_type, result;
404         guint8          *suffix;
405
406         /* Check that there's enough data */
407         if (tvb_length(tvb) < 3)
408                 return;
409
410         if (check_col(pinfo->cinfo, COL_PROTOCOL))
411                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ELCOM");
412         if (check_col(pinfo->cinfo, COL_INFO))
413                 col_clear(pinfo->cinfo, COL_INFO);
414
415         is_request = (pinfo->match_port == pinfo->destport);
416         elcom_len = tvb_get_ntohs(tvb, 0);
417         length_ok = (tvb_length(tvb) == (guint16)(elcom_len+2));
418         if (check_col(pinfo->cinfo, COL_INFO)) {
419                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s Len=%d%s",
420                              is_request ? "Request" : "Response",
421                              elcom_len,
422                              length_ok ? "" : " (incorrect)");
423
424                 elcom_msg_type = tvb_get_guint8(tvb, 2);
425                 switch (elcom_msg_type) {
426                 case P_CONRQ:
427                 case P_CONRS:
428                         /* starting after elcom_len and elcom_msg_type,
429                            initiator + responder + userdata fields must be there */
430                         if (tvb_length_remaining(tvb, 3+TOTAL_LEN+TOTAL_LEN+3) < 0) return;
431                         /* check also that those field lengths are valid */
432                         if (tvb_get_guint8(tvb, 3)  != LOWADR_LEN) return;
433                         if (tvb_get_guint8(tvb, 3+1+LOWADR_LEN) != SUFFIX_LEN) return;
434                         if (tvb_get_guint8(tvb, 3+TOTAL_LEN) != LOWADR_LEN) return;
435                         if (tvb_get_guint8(tvb, 3+1+TOTAL_LEN+LOWADR_LEN) != SUFFIX_LEN) return;
436                         /* finally believe that there is valid suffix */
437                         suffix = tvb_get_string(tvb, 3+2+LOWADR_LEN, 2);
438                         col_append_fstr(pinfo->cinfo, COL_INFO, " %s Connect", suffix);
439                         g_free(suffix);
440                         break;
441                         
442                 case P_RELRQ:
443                 case P_RELRS:
444                         col_append_str(pinfo->cinfo, COL_INFO, " Release");
445                         break;
446                         
447                 case P_DATRQ:
448                         col_append_str(pinfo->cinfo, COL_INFO, " Data");
449                         break;
450                 }
451
452                 switch (elcom_msg_type) {
453                 case P_CONRQ:
454                 case P_RELRQ:
455                         col_append_str(pinfo->cinfo, COL_INFO, " Request");
456                         break;
457                         
458                 case P_CONRS:
459                 case P_RELRS:
460                         col_append_str(pinfo->cinfo, COL_INFO, " Response");
461                         break;
462                 }
463                 
464                 return;
465         }
466
467         if (!tree)
468                 return;
469
470         ti = proto_tree_add_item(tree, proto_elcom, tvb, offset, -1, FALSE);
471         elcom_tree = proto_item_add_subtree(ti, ett_elcom);
472         
473         hidden_item = proto_tree_add_boolean(elcom_tree,
474                                              is_request ? hf_elcom_request : hf_elcom_response,
475                                              tvb, 0, 0, TRUE);
476         PROTO_ITEM_SET_HIDDEN(hidden_item);
477
478         /* 2 first bytes are the frame length */
479         offset = 0;
480         ti = proto_tree_add_uint(elcom_tree, hf_elcom_length, tvb, offset, 2, elcom_len);
481         offset = +2;
482         if (! length_ok) {
483                 proto_item_append_text(ti, " (incorrect)");
484         }
485
486         elcom_msg_type = tvb_get_guint8(tvb, offset);
487         ti = proto_tree_add_uint(elcom_tree, hf_elcom_type, tvb, offset, 1, elcom_msg_type);
488         offset++;
489         if (tvb_length_remaining(tvb, offset) <= 0)
490                 return;
491
492         switch (elcom_msg_type) {
493         case P_CONRQ:
494         case P_CONRS:
495                 /*
496                  * Connection request/release assiciated PDU's,
497                  * /ELCOM-90 P Protocol spec/ p. 85...
498                  */
499                 proto_item_append_text(elcom_tree, "  (Connect %s)", 
500                                        ((elcom_msg_type == P_CONRQ)
501                                         ? "Request" : "Response"));
502                 proto_item_append_text(ti, "  (Connect %s)", 
503                                        ((elcom_msg_type == P_CONRQ)
504                                         ? "Request" : "Response"));
505                 
506                 /* We need the lenght here, hardcode the LOWADR_LEN = 21 */
507                 ti = proto_tree_add_text(elcom_tree, tvb, offset, TOTAL_LEN, "Initiator");
508                 offset = dissect_lower_address(ti, ett_elcom_initiator, tvb, offset,
509                                                hf_elcom_initiator_endian,
510                                                hf_elcom_initiator_ip,
511                                                hf_elcom_initiator_port,
512                                                hf_elcom_initiator_suff);
513                 if (tvb_length_remaining(tvb, offset) <= 0)
514                         return;
515                 
516                 ti = proto_tree_add_text(elcom_tree, tvb, offset, TOTAL_LEN, "Responder");
517                 offset = dissect_lower_address(ti, ett_elcom_responder, tvb, offset,
518                                                hf_elcom_responder_endian,
519                                                hf_elcom_responder_ip,
520                                                hf_elcom_responder_port,
521                                                hf_elcom_responder_suff);
522                 if (tvb_length_remaining(tvb, offset) <= 0)
523                         return;
524                 
525                 /* Rest of the payload is USER-DATA, 0..82 bytes */
526                 ti = proto_tree_add_text(elcom_tree, tvb, offset, -1, "User Data");
527                 offset = dissect_userdata(ti, ett_elcom_userdata, tvb, offset);
528
529                 break;
530
531         case P_RELRQ:
532         case P_RELRS:
533                 proto_item_append_text(elcom_tree, " (Release %s)", 
534                                        ((elcom_msg_type == P_RELRQ)
535                                         ? "Request" : "Response"));
536
537                 proto_item_append_text(ti, "  (Release %s)", 
538                                        ((elcom_msg_type == P_RELRQ)
539                                         ? "Request" : "Response"));
540
541                 result = tvb_get_guint8(tvb, offset);
542                 ti = proto_tree_add_uint(elcom_tree,
543                                          (elcom_msg_type == P_RELRQ)
544                                          ? hf_elcom_release_reason
545                                          : hf_elcom_release_result,
546                                          tvb, offset, 1, result);
547                 offset += 1;
548                 
549                 break;
550
551         case P_DATRQ:
552                 proto_item_append_text(ti, "  (Data Request)");
553                 proto_item_append_text(elcom_tree, " (Data request)");
554                 ti = proto_tree_add_text(elcom_tree, tvb, offset, -1, "Data Request");
555                 offset = dissect_datarequest(ti, ett_elcom_datarequest, tvb, offset);
556                 break;
557
558         default:
559                 proto_item_append_text(ti, " <<--- meaning WHAT??");
560                 break;
561         }
562         
563
564         if (tvb_length_remaining(tvb, offset) <= 0)
565                 return;
566
567         /* We should not get here, but if we do, show what is left over: */
568         ti = proto_tree_add_text(elcom_tree, tvb, offset, -1, "Strange leftover");
569         while (tvb_length_remaining(tvb, offset) > 0) {
570                 proto_item_append_text(ti, elcom_show_hex ? " %02x" : " %03o",
571                                        tvb_get_guint8(tvb, offset));
572                 offset++;
573         }
574 }
575
576 void
577 proto_register_elcom(void)
578 {
579         /* Setup list of header fields  See Section 1.6.1 for details*/
580         static hf_register_info hf[] = {
581                 { &hf_elcom_response,
582                   { "Response",         "elcom.response",
583                     FT_BOOLEAN, BASE_NONE, NULL, 0, NULL, HFILL }
584                 },              
585
586                 { &hf_elcom_request,
587                   { "Request",          "elcom.request",
588                     FT_BOOLEAN, BASE_NONE, NULL, 0, NULL, HFILL }
589                 },
590
591                 { &hf_elcom_length,
592                   { "Lenght",           "elcom.length",
593                     FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
594                 },
595
596                 { &hf_elcom_type,
597                   { "Type",             "elcom.type",
598                     FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }
599                 },
600
601                 { &hf_elcom_initiator_endian,
602                   { "Endian",           "elcom.initiator.endian",
603                     FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }
604                 },
605
606                 { &hf_elcom_initiator_ip,
607                   { "IP",               "elcom.initiator.ip",
608                     FT_IPv4, BASE_NONE, NULL, 0, NULL, HFILL }
609                 },
610
611                 { &hf_elcom_initiator_port,
612                   { "Port",             "elcom.initiator.port",
613                     FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
614                 },
615
616                 { &hf_elcom_initiator_suff,
617                   { "Suffix",           "elcom.initiator.suffix",
618                     FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
619                 },
620
621                 { &hf_elcom_responder_endian,
622                   { "Endian",           "elcom.responder.endian",
623                     FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }
624                 },
625
626                 { &hf_elcom_responder_ip,
627                   { "IP",               "elcom.responder.ip",
628                     FT_IPv4, BASE_NONE, NULL, 0, NULL, HFILL }
629                 },
630
631                 { &hf_elcom_responder_port,
632                   { "Port",             "elcom.responder.port",
633                     FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
634                 },
635
636                 { &hf_elcom_responder_suff,
637                   { "Suffix",           "elcom.responder.suffix",
638                     FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
639                 },
640
641                 { &hf_elcom_userdata_length,
642                   { "Lenght",           "elcom.userdata.length",
643                     FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
644                 },
645
646                 { &hf_elcom_userdata_pduid,
647                   { "PDU-ID",           "elcom.userdata.pduid",
648                     FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
649                 },
650
651                 { &hf_elcom_userdata_version,
652                   { "Version",          "elcom.userdata.version",
653                     FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
654                 },
655
656                 { &hf_elcom_userdata_result,
657                   { "Result",           "elcom.userdata.result",
658                     FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
659                 },
660
661                 { &hf_elcom_userdata_restmark,
662                   { "Restart marking",  "elcom.userdata.response.restartcode",
663                     FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
664                 },
665
666                 { &hf_elcom_userdata_cf,
667                   { "Control Field",    "elcom.userdata.response.controlfield",
668                     FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }
669                 },
670
671                 { &hf_elcom_release_reason,
672                   { "Reason",   "elcom.release.reason",
673                     FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
674                 },
675
676                 { &hf_elcom_release_result,
677                   { "Result",   "elcom.release.result",
678                     FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
679                 },
680
681                 { &hf_elcom_datarequest_grouptype,
682                   { "Group Type",       "elcom.datarequest.grouptype",
683                     FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
684                 },
685
686                 { &hf_elcom_datarequest_result,
687                   { "Result",   "elcom.datarequest.result",
688                     FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
689                 },
690
691                 { &hf_elcom_datarequest_groupnumber,
692                   { "Group Number",     "elcom.datarequest.groupnumber",
693                     FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
694                 },
695
696                 { &hf_elcom_datarequest_grouppriority,
697                   { "Group Priority",   "elcom.datarequest.grouppriority",
698                     FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
699                 },
700
701                 { &hf_elcom_datarequest_groupsize,
702                   { "Group Size",       "elcom.datarequest.groupsize",
703                     FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
704                 },
705
706                 { &hf_elcom_datarequest_groupindex1,
707                   { "Group Index1",     "elcom.datarequest.groupindex1",
708                     FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
709                 },
710
711                 { &hf_elcom_datarequest_groupindex2,
712                   { "Group Index2",     "elcom.datarequest.groupindex2",
713                     FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
714                 },
715
716                 { &hf_elcom_datarequest_oid,
717                   { "Obkect Name",      "elcom.datarequest.oid",
718                     FT_UINT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
719                 }
720
721         };
722
723         /* Setup protocol subtree array */
724         static gint *ett[] = {
725                 &ett_elcom,
726                 &ett_elcom_initiator,
727                 &ett_elcom_responder,
728                 &ett_elcom_userdata,
729                 &ett_elcom_datarequest
730         };
731
732         /* Register the protocol name and description */
733         proto_elcom = proto_register_protocol (
734                                                "ELCOM Communication Protocol",
735                                                "ELCOM",
736                                                "elcom"
737                                                );
738
739         /* Required function calls to register the header fields and subtrees used */
740         proto_register_field_array(proto_elcom, hf, array_length(hf));
741         proto_register_subtree_array(ett, array_length(ett));
742
743 }
744
745 void
746 proto_reg_handoff_elcom(void)
747 {
748         dissector_handle_t elcom_handle;
749
750         elcom_handle = create_dissector_handle(dissect_elcom, proto_elcom);
751         dissector_add_uint("tcp.port", TCP_PORT_ELCOM, elcom_handle);
752 }
753
754 /*
755  * Local variables:
756  * c-basic-offset: 8
757  * tab-width: 8
758  * indent-tabs-mode: t
759  * End:
760  */