From Magnus Hansson:
[obnox/wireshark/wip.git] / epan / dissectors / packet-enip.c
1 /* packet-enip.c
2  * Routines for EtherNet/IP (Industrial Protocol) dissection
3  * EtherNet/IP Home: www.odva.org
4  *
5  * Copyright 2003-2004
6  * Magnus Hansson <mah@hms.se>
7  * Joakim Wiberg <jow@hms.se>
8  *
9  * $Id$
10  *
11  * Ethereal - Network traffic analyzer
12  * By Gerald Combs <gerald@ethereal.com>
13  * Copyright 1998 Gerald Combs
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include <glib.h>
39
40 #ifdef NEED_SNPRINTF_H
41 # include "snprintf.h"
42 #endif
43
44 #include <epan/packet.h>
45 #include <prefs.h>
46 #include "packet-tcp.h"
47 #include "packet-cip.h"
48
49
50 /* Communication Ports */
51 #define ENIP_ENCAP_PORT         44818   /* EtherNet/IP located on port 44818    */
52 #define ENIP_IO_PORT               2222 /* EtherNet/IP IO located on port 2222  */
53
54 /* Return codes of function classifying packets as query/response */
55 #define REQUEST_PACKET     0
56 #define RESPONSE_PACKET         1
57 #define CANNOT_CLASSIFY         2
58
59 /* EtherNet/IP function codes */
60 #define NOP                0x0000
61 #define LIST_SERVICES      0x0004
62 #define LIST_IDENTITY      0x0063
63 #define LIST_INTERFACES    0x0064
64 #define REGISTER_SESSION   0x0065
65 #define UNREGISTER_SESSION 0x0066
66 #define SEND_RR_DATA       0x006F
67 #define SEND_UNIT_DATA     0x0070
68 #define INDICATE_STATUS    0x0072
69 #define CANCEL             0x0073
70
71 /* EtherNet/IP status codes */
72 #define SUCCESS               0x0000
73 #define INVALID_CMD           0x0001
74 #define NO_RESOURCES          0x0002
75 #define INCORRECT_DATA        0x0003
76 #define INVALID_SESSION       0x0064
77 #define INVALID_LENGTH        0x0065
78 #define UNSUPPORTED_PROT_REV  0x0069
79
80 /* EtherNet/IP Common Data Format Type IDs */
81 #define CDF_NULL              0x0000
82 #define LIST_IDENTITY_RESP    0x000C
83 #define CONNECTION_BASED      0x00A1
84 #define CONNECTION_TRANSPORT  0x00B1
85 #define UNCONNECTED_MSG       0x00B2
86 #define LIST_SERVICES_RESP    0x0100
87 #define SOCK_ADR_INFO_OT      0x8000
88 #define SOCK_ADR_INFO_TO      0x8001
89 #define SEQ_ADDRESS           0x8002
90
91
92 /* Initialize the protocol and registered fields */
93 static int proto_enip              = -1;
94
95 static int hf_enip_command         = -1;
96 static int hf_enip_options         = -1;
97 static int hf_enip_sendercontex    = -1;
98 static int hf_enip_status          = -1;
99 static int hf_enip_session         = -1;
100
101 static int hf_enip_lir_sinfamily   = -1;
102 static int hf_enip_lir_sinport     = -1;
103 static int hf_enip_lir_sinaddr     = -1;
104 static int hf_enip_lir_sinzero     = -1;
105
106 static int hf_enip_lir_vendor     = -1;
107 static int hf_enip_lir_devtype     = -1;
108 static int hf_enip_lir_prodcode    = -1;
109 static int hf_enip_lir_status      = -1;
110 static int hf_enip_lir_serial      = -1;
111 static int hf_enip_lir_name        = -1;
112 static int hf_enip_lir_state       = -1;
113
114 static int hf_enip_lsr_tcp         = -1;
115 static int hf_enip_lsr_udp         = -1;
116
117 static int hf_enip_srrd_ifacehnd   = -1;
118
119 static int hf_enip_sud_ifacehnd    = -1;
120
121 static int hf_enip_cpf_typeid      = -1;
122 static int hf_enip_cpf_sai_connid  = -1;
123 static int hf_enip_cpf_sai_seqnum  = -1;
124
125 /* Initialize the subtree pointers */
126 static gint ett_enip          = -1;
127 static gint ett_count_tree    = -1;
128 static gint ett_type_tree     = -1;
129 static gint ett_command_tree  = -1;
130 static gint ett_sockadd       = -1;
131 static gint ett_lsrcf         = -1;
132
133 static proto_tree          *g_tree;
134 static dissector_table_t   subdissector_srrd_table;
135 static dissector_table_t   subdissector_sud_table;
136 static dissector_handle_t  data_handle;
137
138 static gboolean enip_desegment = TRUE;
139
140 /* Translate function to string - Encapsulation commands */
141 static const value_string encap_cmd_vals[] = {
142         { NOP,                        "NOP"                },
143         { LIST_SERVICES,           "List Services"      },
144         { LIST_IDENTITY,                "List Identity"      },
145         { LIST_INTERFACES,      "List Interfaces"    },
146         { REGISTER_SESSION,     "Register Session"   },
147         { UNREGISTER_SESSION,"Unregister Session" },
148         { SEND_RR_DATA,         "Send RR Data"       },
149         { SEND_UNIT_DATA,               "Send Unit Data"     },
150         { INDICATE_STATUS,      "Indicate Status"    },
151         { CANCEL,                     "Cancel"             },
152
153         { 0,                                  NULL                 }
154 };
155
156 /* Translate function to string - Encapsulation status */
157 static const value_string encap_status_vals[] = {
158         { SUCCESS,                            "Success" },
159         { INVALID_CMD,           "Invalid Command" },
160         { NO_RESOURCES,            "No Memory Resources" },
161         { INCORRECT_DATA,             "Incorrect Data" },
162         { INVALID_SESSION,         "Invalid Session Handle" },
163         { INVALID_LENGTH,       "Invalid Length" },
164         { UNSUPPORTED_PROT_REV, "Unsupported Protocol Revision" },
165
166         { 0,                                     NULL }
167 };
168
169 /* Translate function to Common data format values */
170 static const value_string cdf_type_vals[] = {
171         { CDF_NULL,                           "Null Address Item" },
172         { LIST_IDENTITY_RESP,   "List Identity Response" },
173         { CONNECTION_BASED,             "Connected Address Item" },
174         { CONNECTION_TRANSPORT, "Connected Data Item" },
175         { UNCONNECTED_MSG,         "Unconnected Data Item" },
176         { LIST_SERVICES_RESP,   "List Services Response" },
177         { SOCK_ADR_INFO_OT,        "Socket Address Info O->T" },
178         { SOCK_ADR_INFO_TO,        "Socket Address Info T->O" },
179         { SEQ_ADDRESS,           "Sequenced Address Item" },
180
181         { 0,                                     NULL }
182 };
183
184
185 /* Translate function to string - True/False */
186 static const value_string enip_true_false_vals[] = {
187         { 0,          "False"       },
188         { 1,          "True"        },
189
190         { 0,        NULL          }
191 };
192
193
194 /* Translate interface handle to string */
195 static const value_string enip_interface_handle_vals[] = {
196         { 0,          "CIP" },
197
198         { 0,        NULL  }
199 };
200
201
202 static proto_item*
203 add_byte_array_text_to_proto_tree( proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char* str )
204 {
205   const char *tmp;
206   char       *tmp2, *tmp2start;
207   proto_item *pi;
208   int         i,tmp_length,tmp2_length;
209   guint32     octet;
210   /* At least one version of Apple's C compiler/linker is buggy, causing
211      a complaint from the linker about the "literal C string section"
212      not ending with '\0' if we initialize a 16-element "char" array with
213      a 16-character string, the fact that initializing such an array with
214      such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
215      '\0' byte in the string nonwithstanding. */
216   static const char my_hex_digits[16] =
217       { '0', '1', '2', '3', '4', '5', '6', '7',
218         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
219
220
221    if( ( length * 2 ) > 32 )
222    {
223       tmp_length = 16;
224       tmp2_length = 36;
225    }
226    else
227    {
228       tmp_length = length;
229       tmp2_length = ( length * 2 ) + 1;
230    }
231
232    tmp = tvb_get_ptr( tvb, start, tmp_length );
233    tmp2 = (char*)g_malloc( tmp2_length );
234
235    tmp2start = tmp2;
236
237    for( i = 0; i < tmp_length; i++ )
238    {
239       octet = tmp[i];
240       octet >>= 4;
241       *tmp2++ = my_hex_digits[octet&0xF];
242       octet = tmp[i];
243       *tmp2++ = my_hex_digits[octet&0xF];
244    }
245
246    if( tmp_length != length )
247    {
248       *tmp2++ = '.';
249       *tmp2++ = '.';
250       *tmp2++ = '.';
251    }
252
253    *tmp2 = 0;
254
255    pi = proto_tree_add_text( tree, tvb, start, length, "%s%s", str, tmp2start );
256
257    g_free( tmp2start );
258
259    return( pi );
260
261 } /* end of add_byte_array_text_to_proto_tree() */
262
263 /* Disssect Common Packet Format */
264 static void
265 dissect_cpf( int command, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint32 ifacehndl )
266 {
267    proto_item *temp_item, *count_item, *type_item, *sockaddr_item;
268         proto_tree *temp_tree, *count_tree, *item_tree, *sockaddr_tree;
269         int temp_data, item_count, item_length, item;
270         unsigned char name_length;
271         tvbuff_t *next_tvb;
272
273         /* Create item count tree */
274         item_count = tvb_get_letohs( tvb, offset );
275    count_item  = proto_tree_add_text( tree, tvb, offset, 2, "Item Count: %d", item_count );
276         count_tree  = proto_item_add_subtree( count_item, ett_count_tree );
277
278         while( item_count-- )
279         {
280                 /* Add item type tree to item count tree*/
281                 type_item = proto_tree_add_item( count_tree, hf_enip_cpf_typeid, tvb, offset+2, 2, TRUE );
282                 item_tree = proto_item_add_subtree( type_item, ett_type_tree );
283
284                 /* Add length field to item type tree*/
285       proto_tree_add_text( item_tree, tvb, offset+4, 2, "Length: %d", tvb_get_letohs( tvb, offset+4 ) );
286
287                 item        = tvb_get_letohs( tvb, offset+2 );
288                 item_length = tvb_get_letohs( tvb, offset+4 );
289
290                 if( item_length )
291                 {
292                    /* Add item data field */
293
294                         switch( item )
295                         {
296                            case CONNECTION_BASED:
297
298                               /* Add Connection identifier */
299                               proto_tree_add_text( item_tree, tvb, offset+6, 4, "Connection Identifier: 0x%08X", tvb_get_letohl( tvb, offset + 6 )  );
300
301                               /* Add Connection ID to Info col */
302                               if(check_col(pinfo->cinfo, COL_INFO))
303                     {
304                   col_append_fstr(pinfo->cinfo, COL_INFO,
305                                          ", CONID: 0x%08X",
306                                          tvb_get_letohl( tvb, offset+6 ) );
307                                    }
308
309                               break;
310
311                            case UNCONNECTED_MSG:
312
313                                         /* Call dissector for interface */
314                                         next_tvb = tvb_new_subset( tvb, offset+6, item_length, item_length );
315
316                if( tvb_length_remaining(next_tvb, 0) == 0 || !dissector_try_port(subdissector_srrd_table, ifacehndl, next_tvb, pinfo, g_tree) )
317                {
318                   /* Show the undissected payload */
319                    if( tvb_length_remaining(tvb, offset) > 0 )
320                      call_dissector( data_handle, next_tvb, pinfo, g_tree );
321                }
322
323                                         break;
324
325             case CONNECTION_TRANSPORT:
326
327                if( command == SEND_UNIT_DATA )
328                {
329                   /*
330                   ** If the encapsulation service is SendUnit Data, this is a
331                   ** encapsulated connected message
332                   */
333
334                   /* Add sequence count ( Transport Class 1,2,3 )*/
335                   proto_tree_add_text( item_tree, tvb, offset+6, 2, "Sequence Count: 0x%04X", tvb_get_letohs( tvb, offset+6 ) );
336
337                   /* Call dissector for interface */
338                   next_tvb = tvb_new_subset (tvb, offset+8, item_length-2, item_length-2);
339
340                   if( tvb_length_remaining(next_tvb, 0) == 0 || !dissector_try_port(subdissector_sud_table, ifacehndl, next_tvb, pinfo, g_tree) )
341                   {
342                      /* Show the undissected payload */
343                       if( tvb_length_remaining(tvb, offset) > 0 )
344                         call_dissector( data_handle, next_tvb, pinfo, g_tree );
345                   }
346
347                }
348                else
349                {
350                   /* Display data */
351                   add_byte_array_text_to_proto_tree( item_tree, tvb, offset+6, item_length, "Data: " );
352
353                } /* End of if send unit data */
354
355                break;
356
357
358             case LIST_IDENTITY_RESP:
359
360                /* Encapsulation version */
361                temp_data = tvb_get_letohs( tvb, offset+6 );
362                proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation Version: %d", temp_data );
363
364                /* Socket Address */
365                sockaddr_item = proto_tree_add_text( item_tree, tvb, offset+8, 16, "Socket Address");
366                sockaddr_tree = proto_item_add_subtree( sockaddr_item, ett_sockadd );
367
368                /* Socket address struct - sin_family */
369                proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinfamily,
370                                                         tvb, offset+8, 2, FALSE );
371
372                /* Socket address struct - sin_port */
373                proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinport,
374                                                         tvb, offset+10, 2, FALSE );
375
376                /* Socket address struct - sin_address */
377                proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinaddr,
378                                                         tvb, offset+12, 4, FALSE );
379
380                /* Socket address struct - sin_zero */
381                proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinzero,
382                                                         tvb, offset+16, 8, FALSE );
383
384                /* Vendor ID */
385                proto_tree_add_item(item_tree, hf_enip_lir_vendor,
386                                                         tvb, offset+24, 2, TRUE );
387
388                /* Device Type */
389                proto_tree_add_item(item_tree, hf_enip_lir_devtype,
390                                                         tvb, offset+26, 2, TRUE );
391
392                /* Product Code */
393                proto_tree_add_item(item_tree, hf_enip_lir_prodcode,
394                                                         tvb, offset+28, 2, TRUE );
395
396                /* Revision */
397                temp_data = tvb_get_letohs( tvb, offset+30 );
398                proto_tree_add_text( item_tree, tvb, offset+30, 2, "Revision: %d.%02d", temp_data & 0xFF, ( temp_data & 0xFF00 ) >> 8 );
399
400                /* Status */
401                proto_tree_add_item(item_tree, hf_enip_lir_status,
402                                                         tvb, offset+32, 2, TRUE );
403
404                /* Serial Number */
405                proto_tree_add_item(item_tree, hf_enip_lir_serial,
406                                                         tvb, offset+34, 4, TRUE );
407
408                /* Product Name Length */
409                name_length = tvb_get_guint8( tvb, offset+38 );
410                proto_tree_add_text( item_tree, tvb, offset+38, 1, "Product Name Length: %d", name_length );
411
412                /* Product Name */
413                proto_tree_add_item(item_tree, hf_enip_lir_name,
414                                                         tvb, offset+39, name_length, TRUE );
415
416                /* Append product name to info column */
417                if(check_col(pinfo->cinfo, COL_INFO))
418                {
419                   col_append_fstr( pinfo->cinfo, COL_INFO, ", %s",
420                       tvb_format_text(tvb, offset+39, name_length));
421                }
422
423                /* State */
424                proto_tree_add_item(item_tree, hf_enip_lir_state,
425                                                         tvb, offset+name_length+39, 1, TRUE );
426                break;
427
428
429             case SOCK_ADR_INFO_OT:
430             case SOCK_ADR_INFO_TO:
431
432                /* Socket address struct - sin_family */
433                proto_tree_add_item(item_tree, hf_enip_lir_sinfamily,
434                                                         tvb, offset+6, 2, FALSE );
435
436                /* Socket address struct - sin_port */
437                proto_tree_add_item(item_tree, hf_enip_lir_sinport,
438                                                         tvb, offset+8, 2, FALSE );
439
440                /* Socket address struct - sin_address */
441                proto_tree_add_item(item_tree, hf_enip_lir_sinaddr,
442                                                         tvb, offset+10, 4, FALSE );
443
444                /* Socket address struct - sin_zero */
445                proto_tree_add_item( item_tree, hf_enip_lir_sinzero,
446                                                         tvb, offset+14, 8, FALSE );
447                                    break;
448
449
450             case SEQ_ADDRESS:
451                proto_tree_add_item(item_tree, hf_enip_cpf_sai_connid,
452                                                         tvb, offset+6, 4, TRUE );
453
454                proto_tree_add_item(item_tree, hf_enip_cpf_sai_seqnum,
455                                                         tvb, offset+10, 4, TRUE );
456
457                /* Add info to column */
458
459                if(check_col(pinfo->cinfo, COL_INFO))
460                     {
461                        col_clear(pinfo->cinfo, COL_INFO);
462
463                   col_add_fstr(pinfo->cinfo, COL_INFO,
464                                          "Connection:  ID=0x%08X, SEQ=%010d",
465                                          tvb_get_letohl( tvb, offset+6 ),
466                                          tvb_get_letohl( tvb, offset+10 ) );
467                                    }
468
469                                    break;
470
471             case LIST_SERVICES_RESP:
472
473                /* Encapsulation version */
474                temp_data = tvb_get_letohs( tvb, offset+6 );
475                proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation Version: %d", temp_data );
476
477                /* Capability flags */
478                temp_data = tvb_get_letohs( tvb, offset+8 );
479                temp_item = proto_tree_add_text(item_tree, tvb, offset+8, 2, "Capability Flags: 0x%04X", temp_data );
480                temp_tree = proto_item_add_subtree(temp_item, ett_lsrcf);
481
482                proto_tree_add_item(temp_tree, hf_enip_lsr_tcp,
483                   tvb, offset+8, 2, TRUE );
484                    proto_tree_add_item(temp_tree, hf_enip_lsr_udp,
485                            tvb, offset+8, 2, TRUE );
486
487                /* Name of service */
488                temp_item = proto_tree_add_text( item_tree, tvb, offset+10, 16, "Name of Service: %s",
489                    tvb_format_stringzpad(tvb, offset+10, 16) );
490
491                /* Append service name to info column */
492                if(check_col(pinfo->cinfo, COL_INFO))
493                {
494                   col_append_fstr( pinfo->cinfo, COL_INFO, ", %s",
495                       tvb_format_stringzpad(tvb, offset+10, 16) );
496                }
497
498                break;
499
500
501                                 default:
502
503                add_byte_array_text_to_proto_tree( item_tree, tvb, offset+6, item_length, "Data: " );
504                break;
505
506                         } /* end of switch( item type ) */
507
508                 } /* end of if( item length ) */
509
510                 offset = offset + item_length + 4;
511
512         } /* end of while( item count ) */
513
514 } /* end of dissect_cpf() */
515
516
517
518 static int
519 classify_packet(packet_info *pinfo)
520 {
521         /* see if nature of packets can be derived from src/dst ports */
522         /* if so, return as found */
523         if ( ( ENIP_ENCAP_PORT == pinfo->srcport && ENIP_ENCAP_PORT != pinfo->destport ) ||
524                  ( ENIP_ENCAP_PORT != pinfo->srcport && ENIP_ENCAP_PORT == pinfo->destport ) ) {
525                 if ( ENIP_ENCAP_PORT == pinfo->srcport )
526                         return RESPONSE_PACKET;
527                 else if ( ENIP_ENCAP_PORT == pinfo->destport )
528                         return REQUEST_PACKET;
529         }
530         /* else, cannot classify */
531         return CANNOT_CLASSIFY;
532 }
533
534 static guint
535 get_enip_pdu_len(tvbuff_t *tvb, int offset)
536 {
537    guint16 plen;
538
539    /*
540     * Get the length of the data from the encapsulation header.
541     */
542    plen = tvb_get_letohs(tvb, offset + 2);
543
544    /*
545     * That length doesn't include the encapsulation header itself;
546     * add that in.
547     */
548    return plen + 24;
549 }
550
551 /* Code to actually dissect the packets */
552 static void
553 dissect_enip_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
554 {
555    int     packet_type;
556    guint16  encap_cmd, encap_data_length;
557    char     pkt_type_str[9] = "";
558    guint32  ifacehndl;
559
560    /* Set up structures needed to add the protocol subtree and manage it */
561    proto_item *ti, *encaph, *csf;
562    proto_tree *enip_tree, *header_tree, *csftree;
563
564    /* Make entries in Protocol column and Info column on summary display */
565    if (check_col(pinfo->cinfo, COL_PROTOCOL))
566       col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENIP");
567    if (check_col(pinfo->cinfo, COL_INFO))
568       col_clear(pinfo->cinfo, COL_INFO);
569
570    encap_cmd = tvb_get_letohs( tvb, 0 );
571
572    if( check_col(pinfo->cinfo, COL_INFO) )
573    {
574       packet_type = classify_packet(pinfo);
575
576       switch ( packet_type )
577       {
578          case REQUEST_PACKET:
579             strcpy(pkt_type_str, "Req");
580             break;
581
582          case RESPONSE_PACKET:
583             strcpy(pkt_type_str, "Rsp");
584             break;
585
586          default:
587             strcpy(pkt_type_str, "?");
588       }
589
590       /* Add service and request/response to info column */
591       col_add_fstr(pinfo->cinfo, COL_INFO,
592                 "%s (%s)",
593               val_to_str(encap_cmd, encap_cmd_vals, "Unknown (0x%04x)"),
594               pkt_type_str );
595
596
597    } /* end of if( col exists ) */
598
599    /* In the interest of speed, if "tree" is NULL, don't do any work not
600       necessary to generate protocol tree items. */
601    if (tree) {
602
603       /* create display subtree for the protocol */
604       ti = proto_tree_add_item(tree, proto_enip, tvb, 0, -1, FALSE);
605
606       enip_tree = proto_item_add_subtree(ti, ett_enip);
607
608       /* Add encapsulation header tree */
609       encaph     = proto_tree_add_text( enip_tree, tvb, 0, 24, "Encapsulation Header");
610       header_tree = proto_item_add_subtree(encaph, ett_enip);
611
612       /* Add EtherNet/IP encapsulation header */
613       proto_tree_add_item( header_tree, hf_enip_command, tvb, 0, 2, TRUE );
614
615       encap_data_length = tvb_get_letohs( tvb, 2 );
616       proto_tree_add_text( header_tree, tvb, 2, 2, "Length: %u", encap_data_length );
617
618       proto_tree_add_item( header_tree, hf_enip_session, tvb, 4, 4, TRUE );
619       proto_tree_add_item( header_tree, hf_enip_status, tvb, 8, 4, TRUE );
620       proto_tree_add_item( header_tree, hf_enip_sendercontex, tvb, 12, 8, TRUE );
621       proto_tree_add_item( header_tree, hf_enip_options, tvb, 20, 4, TRUE );
622
623       /* Append session and command to the protocol tree */
624       proto_item_append_text( ti, ", Session: 0x%08X, %s", tvb_get_letohl( tvb, 4 ),
625          val_to_str( encap_cmd, encap_cmd_vals, "Unknown (0x%04x)" ) );
626
627       /*
628       ** For some commands we want to add some info to the info column
629       */
630
631       if( check_col( pinfo->cinfo, COL_INFO ) )
632       {
633
634          switch( encap_cmd )
635          {
636             case REGISTER_SESSION:
637             case UNREGISTER_SESSION:
638                   col_append_fstr( pinfo->cinfo, COL_INFO, ", Session: 0x%08X",
639                                    tvb_get_letohl( tvb, 4 ) );
640
641          } /* end of switch() */
642
643       } /* end of id info column */
644
645       /* Command specific data - create tree */
646       if( encap_data_length )
647       {
648          /* The packet have some command specific data, buid a sub tree for it */
649
650          csf = proto_tree_add_text( enip_tree, tvb, 24, encap_data_length,
651                                    "Command Specific Data");
652
653          csftree = proto_item_add_subtree(csf, ett_command_tree);
654
655          switch( encap_cmd )
656          {
657             case NOP:
658                break;
659
660             case LIST_SERVICES:
661                dissect_cpf( encap_cmd, tvb, pinfo, csftree, 24, 0 );
662                break;
663
664             case LIST_IDENTITY:
665                dissect_cpf( encap_cmd, tvb, pinfo, csftree, 24, 0 );
666                break;
667
668             case LIST_INTERFACES:
669                dissect_cpf( encap_cmd, tvb, pinfo, csftree, 24, 0 );
670                break;
671
672             case REGISTER_SESSION:
673                proto_tree_add_text( csftree, tvb, 24, 2, "Protocol Version: 0x%04X",
674                                    tvb_get_letohs( tvb, 24 ) );
675
676                proto_tree_add_text( csftree, tvb, 26, 2, "Option Flags: 0x%04X",
677                                    tvb_get_letohs( tvb, 26 ) );
678
679                break;
680
681             case UNREGISTER_SESSION:
682                break;
683
684             case SEND_RR_DATA:
685                proto_tree_add_item(csftree, hf_enip_srrd_ifacehnd, tvb, 24, 4, TRUE);
686
687                proto_tree_add_text( csftree, tvb, 28, 2, "Timeout: %u",
688                                    tvb_get_letohs( tvb, 28 ) );
689
690                ifacehndl = tvb_get_letohl( tvb, 24 );
691                dissect_cpf( encap_cmd, tvb, pinfo, csftree, 30, ifacehndl );
692                break;
693
694             case SEND_UNIT_DATA:
695                proto_tree_add_item(csftree, hf_enip_sud_ifacehnd, tvb, 24, 4, TRUE);
696
697                proto_tree_add_text( csftree, tvb, 28, 2, "Timeout: %u",
698                                    tvb_get_letohs( tvb, 28 ) );
699
700                ifacehndl = tvb_get_letohl( tvb, 24 );
701                dissect_cpf( encap_cmd, tvb, pinfo, csftree, 30, ifacehndl );
702                break;
703
704             case INDICATE_STATUS:
705             case CANCEL:
706             default:
707
708                /* Can not decode - Just show the data */
709                add_byte_array_text_to_proto_tree( header_tree, tvb, 24, encap_data_length, "Encap Data: " );
710                break;
711
712          } /* end of switch() */
713
714       } /* end of if( encapsulated data ) */
715
716    }
717 } /* end of dissect_enip_pdu() */
718
719 static int
720 dissect_enip_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
721 {
722    guint16  encap_cmd;
723
724    g_tree = tree;
725
726    /* An ENIP packet is at least 4 bytes long - we need the command type. */
727    if (!tvb_bytes_exist(tvb, 0, 4))
728       return 0;
729
730    /* Get the command type and see if it's valid. */
731    encap_cmd = tvb_get_letohs( tvb, 0 );
732    if (match_strval(encap_cmd, encap_cmd_vals) == NULL)
733       return 0; /* not a known command */
734
735    dissect_enip_pdu(tvb, pinfo, tree);
736    return tvb_length(tvb);
737 }
738
739 static int
740 dissect_enip_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
741 {
742    guint16  encap_cmd;
743
744    g_tree = tree;
745
746    /* An ENIP packet is at least 4 bytes long - we need the command type. */
747    if (!tvb_bytes_exist(tvb, 0, 4))
748       return 0;
749
750    /* Get the command type and see if it's valid. */
751    encap_cmd = tvb_get_letohs( tvb, 0 );
752    if (match_strval(encap_cmd, encap_cmd_vals) == NULL)
753       return 0; /* not a known command */
754
755    tcp_dissect_pdus(tvb, pinfo, tree, enip_desegment, 4,
756         get_enip_pdu_len, dissect_enip_pdu);
757    return tvb_length(tvb);
758 }
759
760 /* Code to actually dissect the io packets*/
761 static void
762 dissect_enipio(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
763 {
764    /* Set up structures needed to add the protocol subtree and manage it */
765         proto_item *ti;
766         proto_tree *enip_tree;
767
768         g_tree = tree;
769
770    /* Make entries in Protocol column and Info column on summary display */
771         if (check_col(pinfo->cinfo, COL_PROTOCOL))
772                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENIP");
773
774    /* In the interest of speed, if "tree" is NULL, don't do any work not
775    necessary to generate protocol tree items. */
776         if (tree)
777         {
778       /* create display subtree for the protocol */
779                 ti = proto_tree_add_item(tree, proto_enip, tvb, 0, -1, FALSE);
780
781                 enip_tree = proto_item_add_subtree(ti, ett_enip);
782
783       dissect_cpf( 0xFFFF, tvb, pinfo, enip_tree, 0, 0 );
784         }
785
786 } /* end of dissect_enipio() */
787
788
789 /* Register the protocol with Ethereal */
790
791 /* this format is require because a script is used to build the C function
792    that calls all the protocol registration.
793 */
794
795 void
796 proto_register_enip(void)
797 {
798    /* Setup list of header fields */
799         static hf_register_info hf[] = {
800                 { &hf_enip_command,
801                         { "Command", "enip.command",
802                         FT_UINT16, BASE_HEX, VALS(encap_cmd_vals), 0,
803                         "Encapsulation command", HFILL }
804                 },
805                 { &hf_enip_session,
806                         { "Session Handle", "enip.session",
807                         FT_UINT32, BASE_HEX, NULL, 0,
808                         "Session identification", HFILL }
809                 },
810                 { &hf_enip_status,
811                         { "Status", "enip.status",
812                         FT_UINT32, BASE_HEX, VALS(encap_status_vals), 0,
813                         "Status code", HFILL }
814                 },
815                 { &hf_enip_sendercontex,
816                         { "Sender Context", "enip.context",
817                         FT_BYTES, BASE_HEX, NULL, 0,
818                         "Information pertient to the sender", HFILL }
819                 },
820                 { &hf_enip_options,
821                         { "Options", "enip.options",
822                         FT_UINT32, BASE_HEX, NULL, 0,
823                         "Options flags", HFILL }
824                 },
825                 { &hf_enip_lsr_tcp,
826                         { "Supports CIP Encapsulation via TCP", "enip.lsr.capaflags.tcp",
827                         FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0020,
828                         "ListServices Reply: Supports CIP Encapsulation via TCP", HFILL }
829                 },
830                 { &hf_enip_lsr_udp,
831                         { "Supports CIP Class 0 or 1 via UDP", "enip.lsr.capaflags.udp",
832                         FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0100,
833                         "ListServices Reply: Supports CIP Class 0 or 1 via UDP", HFILL }
834                 },
835                 /* Send Request/Reply Data */
836                 { &hf_enip_srrd_ifacehnd,
837                         { "Interface Handle",           "enip.srrd.iface",
838                         FT_UINT32, BASE_HEX, VALS(enip_interface_handle_vals), 0,
839                         "SendRRData: Interface handle", HFILL }
840                 },
841                 /* Send Unit Data */
842                 { &hf_enip_sud_ifacehnd,
843                         { "Interface Handle",           "enip.sud.iface",
844                         FT_UINT32, BASE_HEX, VALS(enip_interface_handle_vals), 0,
845                         "SendUnitData: Interface handle", HFILL }
846                 },
847                 /* List identity reply */
848       { &hf_enip_lir_sinfamily,
849                         { "sin_family", "enip.lir.sa.sinfamily",
850                         FT_UINT16, BASE_DEC, NULL, 0,
851                         "ListIdentity Reply: Socket Address.Sin Family", HFILL }
852                 },
853       { &hf_enip_lir_sinport,
854                         { "sin_port", "enip.lir.sa.sinport",
855                         FT_UINT16, BASE_DEC, NULL, 0,
856                         "ListIdentity Reply: Socket Address.Sin Port", HFILL }
857                 },
858       { &hf_enip_lir_sinaddr,
859                         { "sin_addr", "enip.lir.sa.sinaddr",
860                         FT_IPv4, BASE_HEX, NULL, 0,
861                         "ListIdentity Reply: Socket Address.Sin Addr", HFILL }
862                 },
863       { &hf_enip_lir_sinzero,
864                         { "sin_zero", "enip.lir.sa.sinzero",
865                         FT_BYTES, BASE_HEX, NULL, 0,
866                         "ListIdentity Reply: Socket Address.Sin Zero", HFILL }
867                 },
868                 { &hf_enip_lir_vendor,
869                         { "Vendor ID", "enip.lir.vendor",
870                         FT_UINT16, BASE_HEX, VALS(cip_vendor_vals), 0,
871                         "ListIdentity Reply: Vendor ID", HFILL }
872                 },
873       { &hf_enip_lir_devtype,
874                         { "Device Type", "enip.lir.devtype",
875                         FT_UINT16, BASE_DEC, VALS(cip_devtype_vals), 0,
876                         "ListIdentity Reply: Device Type", HFILL }
877                 },
878       { &hf_enip_lir_prodcode,
879                         { "Product Code", "enip.lir.prodcode",
880                         FT_UINT16, BASE_DEC, NULL, 0,
881                         "ListIdentity Reply: Product Code", HFILL }
882                 },
883       { &hf_enip_lir_status,
884                         { "Status", "enip.lir.status",
885                         FT_UINT16, BASE_HEX, NULL, 0,
886                         "ListIdentity Reply: Status", HFILL }
887                 },
888       { &hf_enip_lir_serial,
889                         { "Serial Number", "enip.lir.serial",
890                         FT_UINT32, BASE_HEX, NULL, 0,
891                         "ListIdentity Reply: Serial Number", HFILL }
892                 },
893       { &hf_enip_lir_name,
894                         { "Product Name", "enip.lir.name",
895                         FT_STRING, BASE_NONE, NULL, 0,
896                         "ListIdentity Reply: Product Name", HFILL }
897                 },
898       { &hf_enip_lir_state,
899                         { "State", "enip.lir.state",
900                         FT_UINT8, BASE_HEX, NULL, 0,
901                         "ListIdentity Reply: State", HFILL }
902                 },
903                 /* Common Packet Format */
904                 { &hf_enip_cpf_typeid,
905                         { "Type ID",          "enip.cpf.typeid",
906                         FT_UINT16, BASE_HEX, VALS(cdf_type_vals), 0,
907                         "Common Packet Format: Type of encapsulated item", HFILL }
908                 },
909                 /* Sequenced Address Type */
910       { &hf_enip_cpf_sai_connid,
911                         { "Connection ID", "enip.cpf.sai.connid",
912                         FT_UINT32, BASE_HEX, NULL, 0,
913                         "Common Packet Format: Sequenced Address Item, Connection Identifier", HFILL }
914                 },
915       { &hf_enip_cpf_sai_seqnum,
916                         { "Sequence Number", "enip.cpf.sai.seq",
917                         FT_UINT32, BASE_DEC, NULL, 0,
918                         "Common Packet Format: Sequenced Address Item, Sequence Number", HFILL }
919                 }
920    };
921
922
923 /* Setup protocol subtree array */
924         static gint *ett[] = {
925                 &ett_enip,
926                 &ett_count_tree,
927                 &ett_type_tree,
928         &ett_command_tree,
929                 &ett_sockadd,
930                 &ett_lsrcf,
931         };
932         module_t *enip_module;
933
934 /* Register the protocol name and description */
935         proto_enip = proto_register_protocol("EtherNet/IP (Industrial Protocol)",
936             "ENIP", "enip");
937
938 /* Required function calls to register the header fields and subtrees used */
939         proto_register_field_array(proto_enip, hf, array_length(hf));
940         proto_register_subtree_array(ett, array_length(ett));
941
942         enip_module = prefs_register_protocol(proto_enip, NULL);
943         prefs_register_bool_preference(enip_module, "desegment",
944             "Desegment all EtherNet/IP messages spanning multiple TCP segments",
945             "Whether the EtherNet/IP dissector should desegment all messages spanning multiple TCP segments",
946             &enip_desegment);
947
948    subdissector_sud_table = register_dissector_table("enip.sud.iface",
949                 "SendUnitData.Interface Handle", FT_UINT32, BASE_HEX);
950
951    subdissector_srrd_table = register_dissector_table("enip.srrd.iface",
952                 "SendRequestReplyData.Interface Handle", FT_UINT32, BASE_HEX);
953
954 } /* end of proto_register_enip() */
955
956
957 /* If this dissector uses sub-dissector registration add a registration routine.
958    This format is required because a script is used to find these routines and
959    create the code that calls these routines.
960 */
961 void
962 proto_reg_handoff_enip(void)
963 {
964         dissector_handle_t enip_udp_handle, enip_tcp_handle;
965         dissector_handle_t enipio_handle;
966
967         /* Register for EtherNet/IP, using TCP */
968         enip_tcp_handle = new_create_dissector_handle(dissect_enip_tcp, proto_enip);
969         dissector_add("tcp.port", ENIP_ENCAP_PORT, enip_tcp_handle);
970
971         /* Register for EtherNet/IP, using UDP */
972         enip_udp_handle = new_create_dissector_handle(dissect_enip_udp, proto_enip);
973         dissector_add("udp.port", ENIP_ENCAP_PORT, enip_udp_handle);
974
975         /* Register for EtherNet/IP IO data (UDP) */
976         enipio_handle = create_dissector_handle(dissect_enipio, proto_enip);
977         dissector_add("udp.port", ENIP_IO_PORT, enipio_handle);
978
979         /* Find dissector for data packet */
980         data_handle = find_dissector("data");
981
982 } /* end of proto_reg_handoff_enip() */