2 * Routines for EtherNet/IP (Industrial Protocol) dissection
3 * EtherNet/IP Home: www.odva.org
6 * Magnus Hansson <mah@hms.se>
7 * Joakim Wiberg <jow@hms.se>
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
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.
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.
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.
40 #include <epan/packet.h>
41 #include <epan/emem.h>
43 #include "packet-tcp.h"
44 #include "packet-cip.h"
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 */
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
56 /* EtherNet/IP function codes */
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
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
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
89 /* Initialize the protocol and registered fields */
90 static int proto_enip = -1;
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;
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;
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;
111 static int hf_enip_lsr_tcp = -1;
112 static int hf_enip_lsr_udp = -1;
114 static int hf_enip_srrd_ifacehnd = -1;
116 static int hf_enip_sud_ifacehnd = -1;
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;
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;
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;
135 static gboolean enip_desegment = TRUE;
137 /* Translate function to string - Encapsulation commands */
138 static const value_string encap_cmd_vals[] = {
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" },
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" },
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" },
182 /* Translate function to string - True/False */
183 static const value_string enip_true_false_vals[] = {
191 /* Translate interface handle to string */
192 static const value_string enip_interface_handle_vals[] = {
200 add_byte_array_text_to_proto_tree( proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char* str )
203 char *tmp2, *tmp2start;
205 int i,tmp_length,tmp2_length;
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' };
218 if( ( length * 2 ) > 32 )
226 tmp2_length = ( length * 2 ) + 1;
229 tmp = (const char *)tvb_get_ptr( tvb, start, tmp_length );
230 tmp2 = (char *)ep_alloc( tmp2_length );
234 for( i = 0; i < tmp_length; i++ )
238 *tmp2++ = my_hex_digits[octet&0xF];
240 *tmp2++ = my_hex_digits[octet&0xF];
243 if( tmp_length != length )
252 pi = proto_tree_add_text( tree, tvb, start, length, "%s%s", str, tmp2start );
256 } /* end of add_byte_array_text_to_proto_tree() */
258 /* Disssect Common Packet Format */
260 dissect_cpf( int command, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint32 ifacehndl )
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;
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 );
273 while( item_count-- )
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 );
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 ) );
282 item = tvb_get_letohs( tvb, offset+2 );
283 item_length = tvb_get_letohs( tvb, offset+4 );
287 /* Add item data field */
291 case CONNECTION_BASED:
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 ) );
296 /* Add Connection ID to Info col */
297 if(check_col(pinfo->cinfo, COL_INFO))
299 col_append_fstr(pinfo->cinfo, COL_INFO,
301 tvb_get_letohl( tvb, offset+6 ) );
306 case UNCONNECTED_MSG:
308 /* Call dissector for interface */
309 next_tvb = tvb_new_subset( tvb, offset+6, item_length, item_length );
311 if( tvb_length_remaining(next_tvb, 0) == 0 || !dissector_try_port(subdissector_srrd_table, ifacehndl, next_tvb, pinfo, g_tree) )
313 /* Show the undissected payload */
314 if( tvb_length_remaining(tvb, offset) > 0 )
315 call_dissector( data_handle, next_tvb, pinfo, g_tree );
320 case CONNECTION_TRANSPORT:
322 if( command == SEND_UNIT_DATA )
325 ** If the encapsulation service is SendUnit Data, this is a
326 ** encapsulated connected message
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 ) );
332 /* Call dissector for interface */
333 next_tvb = tvb_new_subset (tvb, offset+8, item_length-2, item_length-2);
335 if( tvb_length_remaining(next_tvb, 0) == 0 || !dissector_try_port(subdissector_sud_table, ifacehndl, next_tvb, pinfo, g_tree) )
337 /* Show the undissected payload */
338 if( tvb_length_remaining(tvb, offset) > 0 )
339 call_dissector( data_handle, next_tvb, pinfo, g_tree );
346 add_byte_array_text_to_proto_tree( item_tree, tvb, offset+6, item_length, "Data: " );
348 } /* End of if send unit data */
353 case LIST_IDENTITY_RESP:
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 );
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 );
363 /* Socket address struct - sin_family */
364 proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinfamily,
365 tvb, offset+8, 2, FALSE );
367 /* Socket address struct - sin_port */
368 proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinport,
369 tvb, offset+10, 2, FALSE );
371 /* Socket address struct - sin_address */
372 proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinaddr,
373 tvb, offset+12, 4, FALSE );
375 /* Socket address struct - sin_zero */
376 proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinzero,
377 tvb, offset+16, 8, FALSE );
380 proto_tree_add_item(item_tree, hf_enip_lir_vendor,
381 tvb, offset+24, 2, TRUE );
384 proto_tree_add_item(item_tree, hf_enip_lir_devtype,
385 tvb, offset+26, 2, TRUE );
388 proto_tree_add_item(item_tree, hf_enip_lir_prodcode,
389 tvb, offset+28, 2, TRUE );
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 );
396 proto_tree_add_item(item_tree, hf_enip_lir_status,
397 tvb, offset+32, 2, TRUE );
400 proto_tree_add_item(item_tree, hf_enip_lir_serial,
401 tvb, offset+34, 4, TRUE );
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 );
408 proto_tree_add_item(item_tree, hf_enip_lir_name,
409 tvb, offset+39, name_length, TRUE );
411 /* Append product name to info column */
412 if(check_col(pinfo->cinfo, COL_INFO))
414 col_append_fstr( pinfo->cinfo, COL_INFO, ", %s",
415 tvb_format_text(tvb, offset+39, name_length));
419 proto_tree_add_item(item_tree, hf_enip_lir_state,
420 tvb, offset+name_length+39, 1, TRUE );
424 case SOCK_ADR_INFO_OT:
425 case SOCK_ADR_INFO_TO:
427 /* Socket address struct - sin_family */
428 proto_tree_add_item(item_tree, hf_enip_lir_sinfamily,
429 tvb, offset+6, 2, FALSE );
431 /* Socket address struct - sin_port */
432 proto_tree_add_item(item_tree, hf_enip_lir_sinport,
433 tvb, offset+8, 2, FALSE );
435 /* Socket address struct - sin_address */
436 proto_tree_add_item(item_tree, hf_enip_lir_sinaddr,
437 tvb, offset+10, 4, FALSE );
439 /* Socket address struct - sin_zero */
440 proto_tree_add_item( item_tree, hf_enip_lir_sinzero,
441 tvb, offset+14, 8, FALSE );
446 proto_tree_add_item(item_tree, hf_enip_cpf_sai_connid,
447 tvb, offset+6, 4, TRUE );
449 proto_tree_add_item(item_tree, hf_enip_cpf_sai_seqnum,
450 tvb, offset+10, 4, TRUE );
452 /* Add info to column */
454 if(check_col(pinfo->cinfo, COL_INFO))
456 col_clear(pinfo->cinfo, COL_INFO);
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 ) );
466 case LIST_SERVICES_RESP:
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 );
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);
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 );
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) );
486 /* Append service name to info column */
487 if(check_col(pinfo->cinfo, COL_INFO))
489 col_append_fstr( pinfo->cinfo, COL_INFO, ", %s",
490 tvb_format_stringzpad(tvb, offset+10, 16) );
498 add_byte_array_text_to_proto_tree( item_tree, tvb, offset+6, item_length, "Data: " );
501 } /* end of switch( item type ) */
503 } /* end of if( item length ) */
505 offset = offset + item_length + 4;
507 } /* end of while( item count ) */
509 } /* end of dissect_cpf() */
514 classify_packet(packet_info *pinfo)
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;
525 /* else, cannot classify */
526 return CANNOT_CLASSIFY;
530 get_enip_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
535 * Get the length of the data from the encapsulation header.
537 plen = tvb_get_letohs(tvb, offset + 2);
540 * That length doesn't include the encapsulation header itself;
546 /* Code to actually dissect the packets */
548 dissect_enip_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
551 guint16 encap_cmd, encap_data_length;
552 const char *pkt_type_str = "";
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;
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);
565 encap_cmd = tvb_get_letohs( tvb, 0 );
567 if( check_col(pinfo->cinfo, COL_INFO) )
569 packet_type = classify_packet(pinfo);
571 switch ( packet_type )
577 case RESPONSE_PACKET:
585 /* Add service and request/response to info column */
586 col_add_fstr(pinfo->cinfo, COL_INFO,
588 val_to_str(encap_cmd, encap_cmd_vals, "Unknown (0x%04x)"),
592 } /* end of if( col exists ) */
594 /* In the interest of speed, if "tree" is NULL, don't do any work not
595 necessary to generate protocol tree items. */
598 /* create display subtree for the protocol */
599 ti = proto_tree_add_item(tree, proto_enip, tvb, 0, -1, FALSE);
601 enip_tree = proto_item_add_subtree(ti, ett_enip);
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);
607 /* Add EtherNet/IP encapsulation header */
608 proto_tree_add_item( header_tree, hf_enip_command, tvb, 0, 2, TRUE );
610 encap_data_length = tvb_get_letohs( tvb, 2 );
611 proto_tree_add_text( header_tree, tvb, 2, 2, "Length: %u", encap_data_length );
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 );
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)" ) );
623 ** For some commands we want to add some info to the info column
626 if( check_col( pinfo->cinfo, COL_INFO ) )
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 ) );
636 } /* end of switch() */
638 } /* end of id info column */
640 /* Command specific data - create tree */
641 if( encap_data_length )
643 /* The packet have some command specific data, buid a sub tree for it */
645 csf = proto_tree_add_text( enip_tree, tvb, 24, encap_data_length,
646 "Command Specific Data");
648 csftree = proto_item_add_subtree(csf, ett_command_tree);
656 dissect_cpf( encap_cmd, tvb, pinfo, csftree, 24, 0 );
660 dissect_cpf( encap_cmd, tvb, pinfo, csftree, 24, 0 );
663 case LIST_INTERFACES:
664 dissect_cpf( encap_cmd, tvb, pinfo, csftree, 24, 0 );
667 case REGISTER_SESSION:
668 proto_tree_add_text( csftree, tvb, 24, 2, "Protocol Version: 0x%04X",
669 tvb_get_letohs( tvb, 24 ) );
671 proto_tree_add_text( csftree, tvb, 26, 2, "Option Flags: 0x%04X",
672 tvb_get_letohs( tvb, 26 ) );
676 case UNREGISTER_SESSION:
680 proto_tree_add_item(csftree, hf_enip_srrd_ifacehnd, tvb, 24, 4, TRUE);
682 proto_tree_add_text( csftree, tvb, 28, 2, "Timeout: %u",
683 tvb_get_letohs( tvb, 28 ) );
685 ifacehndl = tvb_get_letohl( tvb, 24 );
686 dissect_cpf( encap_cmd, tvb, pinfo, csftree, 30, ifacehndl );
690 proto_tree_add_item(csftree, hf_enip_sud_ifacehnd, tvb, 24, 4, TRUE);
692 proto_tree_add_text( csftree, tvb, 28, 2, "Timeout: %u",
693 tvb_get_letohs( tvb, 28 ) );
695 ifacehndl = tvb_get_letohl( tvb, 24 );
696 dissect_cpf( encap_cmd, tvb, pinfo, csftree, 30, ifacehndl );
699 case INDICATE_STATUS:
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: " );
707 } /* end of switch() */
709 } /* end of if( encapsulated data ) */
712 } /* end of dissect_enip_pdu() */
715 dissect_enip_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
721 /* An ENIP packet is at least 4 bytes long - we need the command type. */
722 if (!tvb_bytes_exist(tvb, 0, 4))
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 */
730 dissect_enip_pdu(tvb, pinfo, tree);
731 return tvb_length(tvb);
735 dissect_enip_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
741 /* An ENIP packet is at least 4 bytes long - we need the command type. */
742 if (!tvb_bytes_exist(tvb, 0, 4))
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 */
750 tcp_dissect_pdus(tvb, pinfo, tree, enip_desegment, 4,
751 get_enip_pdu_len, dissect_enip_pdu);
752 return tvb_length(tvb);
755 /* Code to actually dissect the io packets*/
757 dissect_enipio(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
759 /* Set up structures needed to add the protocol subtree and manage it */
761 proto_tree *enip_tree;
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");
769 /* In the interest of speed, if "tree" is NULL, don't do any work not
770 necessary to generate protocol tree items. */
773 /* create display subtree for the protocol */
774 ti = proto_tree_add_item(tree, proto_enip, tvb, 0, -1, FALSE);
776 enip_tree = proto_item_add_subtree(ti, ett_enip);
778 dissect_cpf( 0xFFFF, tvb, pinfo, enip_tree, 0, 0 );
781 } /* end of dissect_enipio() */
784 /* Register the protocol with Wireshark */
786 /* this format is require because a script is used to build the C function
787 that calls all the protocol registration.
791 proto_register_enip(void)
793 /* Setup list of header fields */
794 static hf_register_info hf[] = {
796 { "Command", "enip.command",
797 FT_UINT16, BASE_HEX, VALS(encap_cmd_vals), 0,
798 "Encapsulation command", HFILL }
801 { "Session Handle", "enip.session",
802 FT_UINT32, BASE_HEX, NULL, 0,
803 "Session identification", HFILL }
806 { "Status", "enip.status",
807 FT_UINT32, BASE_HEX, VALS(encap_status_vals), 0,
808 "Status code", HFILL }
810 { &hf_enip_sendercontex,
811 { "Sender Context", "enip.context",
812 FT_BYTES, BASE_HEX, NULL, 0,
813 "Information pertient to the sender", HFILL }
816 { "Options", "enip.options",
817 FT_UINT32, BASE_HEX, NULL, 0,
818 "Options flags", HFILL }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
873 { &hf_enip_lir_prodcode,
874 { "Product Code", "enip.lir.prodcode",
875 FT_UINT16, BASE_DEC, NULL, 0,
876 "ListIdentity Reply: Product Code", HFILL }
878 { &hf_enip_lir_status,
879 { "Status", "enip.lir.status",
880 FT_UINT16, BASE_HEX, NULL, 0,
881 "ListIdentity Reply: Status", HFILL }
883 { &hf_enip_lir_serial,
884 { "Serial Number", "enip.lir.serial",
885 FT_UINT32, BASE_HEX, NULL, 0,
886 "ListIdentity Reply: Serial Number", HFILL }
889 { "Product Name", "enip.lir.name",
890 FT_STRING, BASE_NONE, NULL, 0,
891 "ListIdentity Reply: Product Name", HFILL }
893 { &hf_enip_lir_state,
894 { "State", "enip.lir.state",
895 FT_UINT8, BASE_HEX, NULL, 0,
896 "ListIdentity Reply: State", HFILL }
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 }
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 }
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 }
918 /* Setup protocol subtree array */
919 static gint *ett[] = {
927 module_t *enip_module;
929 /* Register the protocol name and description */
930 proto_enip = proto_register_protocol("EtherNet/IP (Industrial Protocol)",
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));
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",
943 subdissector_sud_table = register_dissector_table("enip.sud.iface",
944 "SendUnitData.Interface Handle", FT_UINT32, BASE_HEX);
946 subdissector_srrd_table = register_dissector_table("enip.srrd.iface",
947 "SendRequestReplyData.Interface Handle", FT_UINT32, BASE_HEX);
949 } /* end of proto_register_enip() */
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.
957 proto_reg_handoff_enip(void)
959 dissector_handle_t enip_udp_handle, enip_tcp_handle;
960 dissector_handle_t enipio_handle;
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);
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);
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);
974 /* Find dissector for data packet */
975 data_handle = find_dissector("data");
977 } /* end of proto_reg_handoff_enip() */