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