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