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 * Ethereal - Network traffic analyzer
12 * By Gerald Combs <gerald@ethereal.com>
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 #ifdef NEED_SNPRINTF_H
41 # include "snprintf.h"
44 #include <epan/packet.h>
46 #include "packet-tcp.h"
47 #include "packet-cip.h"
50 /* Communication Ports */
51 #define ENIP_ENCAP_PORT 44818 /* EtherNet/IP located on port 44818 */
52 #define ENIP_IO_PORT 2222 /* EtherNet/IP IO located on port 2222 */
54 /* Return codes of function classifying packets as query/response */
55 #define REQUEST_PACKET 0
56 #define RESPONSE_PACKET 1
57 #define CANNOT_CLASSIFY 2
59 /* EtherNet/IP function codes */
61 #define LIST_SERVICES 0x0004
62 #define LIST_IDENTITY 0x0063
63 #define LIST_INTERFACES 0x0064
64 #define REGISTER_SESSION 0x0065
65 #define UNREGISTER_SESSION 0x0066
66 #define SEND_RR_DATA 0x006F
67 #define SEND_UNIT_DATA 0x0070
68 #define INDICATE_STATUS 0x0072
71 /* EtherNet/IP status codes */
72 #define SUCCESS 0x0000
73 #define INVALID_CMD 0x0001
74 #define NO_RESOURCES 0x0002
75 #define INCORRECT_DATA 0x0003
76 #define INVALID_SESSION 0x0064
77 #define INVALID_LENGTH 0x0065
78 #define UNSUPPORTED_PROT_REV 0x0069
80 /* EtherNet/IP Common Data Format Type IDs */
81 #define CDF_NULL 0x0000
82 #define LIST_IDENTITY_RESP 0x000C
83 #define CONNECTION_BASED 0x00A1
84 #define CONNECTION_TRANSPORT 0x00B1
85 #define UNCONNECTED_MSG 0x00B2
86 #define LIST_SERVICES_RESP 0x0100
87 #define SOCK_ADR_INFO_OT 0x8000
88 #define SOCK_ADR_INFO_TO 0x8001
89 #define SEQ_ADDRESS 0x8002
92 /* Initialize the protocol and registered fields */
93 static int proto_enip = -1;
95 static int hf_enip_command = -1;
96 static int hf_enip_options = -1;
97 static int hf_enip_sendercontex = -1;
98 static int hf_enip_status = -1;
99 static int hf_enip_session = -1;
101 static int hf_enip_lir_sinfamily = -1;
102 static int hf_enip_lir_sinport = -1;
103 static int hf_enip_lir_sinaddr = -1;
104 static int hf_enip_lir_sinzero = -1;
106 static int hf_enip_lir_vendor = -1;
107 static int hf_enip_lir_devtype = -1;
108 static int hf_enip_lir_prodcode = -1;
109 static int hf_enip_lir_status = -1;
110 static int hf_enip_lir_serial = -1;
111 static int hf_enip_lir_name = -1;
112 static int hf_enip_lir_state = -1;
114 static int hf_enip_lsr_tcp = -1;
115 static int hf_enip_lsr_udp = -1;
117 static int hf_enip_srrd_ifacehnd = -1;
119 static int hf_enip_sud_ifacehnd = -1;
121 static int hf_enip_cpf_typeid = -1;
122 static int hf_enip_cpf_sai_connid = -1;
123 static int hf_enip_cpf_sai_seqnum = -1;
125 /* Initialize the subtree pointers */
126 static gint ett_enip = -1;
127 static gint ett_count_tree = -1;
128 static gint ett_type_tree = -1;
129 static gint ett_command_tree = -1;
130 static gint ett_sockadd = -1;
131 static gint ett_lsrcf = -1;
133 static proto_tree *g_tree;
134 static dissector_table_t subdissector_srrd_table;
135 static dissector_table_t subdissector_sud_table;
136 static dissector_handle_t data_handle;
138 static gboolean enip_desegment = TRUE;
140 /* Translate function to string - Encapsulation commands */
141 static const value_string encap_cmd_vals[] = {
143 { LIST_SERVICES, "List Services" },
144 { LIST_IDENTITY, "List Identity" },
145 { LIST_INTERFACES, "List Interfaces" },
146 { REGISTER_SESSION, "Register Session" },
147 { UNREGISTER_SESSION,"Unregister Session" },
148 { SEND_RR_DATA, "Send RR Data" },
149 { SEND_UNIT_DATA, "Send Unit Data" },
150 { INDICATE_STATUS, "Indicate Status" },
151 { CANCEL, "Cancel" },
156 /* Translate function to string - Encapsulation status */
157 static const value_string encap_status_vals[] = {
158 { SUCCESS, "Success" },
159 { INVALID_CMD, "Invalid Command" },
160 { NO_RESOURCES, "No Memory Resources" },
161 { INCORRECT_DATA, "Incorrect Data" },
162 { INVALID_SESSION, "Invalid Session Handle" },
163 { INVALID_LENGTH, "Invalid Length" },
164 { UNSUPPORTED_PROT_REV, "Unsupported Protocol Revision" },
169 /* Translate function to Common data format values */
170 static const value_string cdf_type_vals[] = {
171 { CDF_NULL, "Null Address Item" },
172 { LIST_IDENTITY_RESP, "List Identity Response" },
173 { CONNECTION_BASED, "Connected Address Item" },
174 { CONNECTION_TRANSPORT, "Connected Data Item" },
175 { UNCONNECTED_MSG, "Unconnected Data Item" },
176 { LIST_SERVICES_RESP, "List Services Response" },
177 { SOCK_ADR_INFO_OT, "Socket Address Info O->T" },
178 { SOCK_ADR_INFO_TO, "Socket Address Info T->O" },
179 { SEQ_ADDRESS, "Sequenced Address Item" },
185 /* Translate function to string - True/False */
186 static const value_string enip_true_false_vals[] = {
194 /* Translate interface handle to string */
195 static const value_string enip_interface_handle_vals[] = {
203 add_byte_array_text_to_proto_tree( proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char* str )
206 char *tmp2, *tmp2start;
208 int i,tmp_length,tmp2_length;
210 /* At least one version of Apple's C compiler/linker is buggy, causing
211 a complaint from the linker about the "literal C string section"
212 not ending with '\0' if we initialize a 16-element "char" array with
213 a 16-character string, the fact that initializing such an array with
214 such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
215 '\0' byte in the string nonwithstanding. */
216 static const char my_hex_digits[16] =
217 { '0', '1', '2', '3', '4', '5', '6', '7',
218 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
221 if( ( length * 2 ) > 32 )
229 tmp2_length = ( length * 2 ) + 1;
232 tmp = tvb_get_ptr( tvb, start, tmp_length );
233 tmp2 = (char*)g_malloc( tmp2_length );
237 for( i = 0; i < tmp_length; i++ )
241 *tmp2++ = my_hex_digits[octet&0xF];
243 *tmp2++ = my_hex_digits[octet&0xF];
246 if( tmp_length != length )
255 pi = proto_tree_add_text( tree, tvb, start, length, "%s%s", str, tmp2start );
261 } /* end of add_byte_array_text_to_proto_tree() */
263 /* Disssect Common Packet Format */
265 dissect_cpf( int command, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint32 ifacehndl )
267 proto_item *temp_item, *count_item, *type_item, *sockaddr_item;
268 proto_tree *temp_tree, *count_tree, *item_tree, *sockaddr_tree;
269 int temp_data, item_count, item_length, item;
270 unsigned char name_length;
273 /* Create item count tree */
274 item_count = tvb_get_letohs( tvb, offset );
275 count_item = proto_tree_add_text( tree, tvb, offset, 2, "Item Count: %d", item_count );
276 count_tree = proto_item_add_subtree( count_item, ett_count_tree );
278 while( item_count-- )
280 /* Add item type tree to item count tree*/
281 type_item = proto_tree_add_item( count_tree, hf_enip_cpf_typeid, tvb, offset+2, 2, TRUE );
282 item_tree = proto_item_add_subtree( type_item, ett_type_tree );
284 /* Add length field to item type tree*/
285 proto_tree_add_text( item_tree, tvb, offset+4, 2, "Length: %d", tvb_get_letohs( tvb, offset+4 ) );
287 item = tvb_get_letohs( tvb, offset+2 );
288 item_length = tvb_get_letohs( tvb, offset+4 );
292 /* Add item data field */
296 case CONNECTION_BASED:
298 /* Add Connection identifier */
299 proto_tree_add_text( item_tree, tvb, offset+6, 4, "Connection Identifier: 0x%08X", tvb_get_letohl( tvb, offset + 6 ) );
301 /* Add Connection ID to Info col */
302 if(check_col(pinfo->cinfo, COL_INFO))
304 col_append_fstr(pinfo->cinfo, COL_INFO,
306 tvb_get_letohl( tvb, offset+6 ) );
311 case UNCONNECTED_MSG:
313 /* Call dissector for interface */
314 next_tvb = tvb_new_subset( tvb, offset+6, item_length, item_length );
316 if( tvb_length_remaining(next_tvb, 0) == 0 || !dissector_try_port(subdissector_srrd_table, ifacehndl, next_tvb, pinfo, g_tree) )
318 /* Show the undissected payload */
319 if( tvb_length_remaining(tvb, offset) > 0 )
320 call_dissector( data_handle, next_tvb, pinfo, g_tree );
325 case CONNECTION_TRANSPORT:
327 if( command == SEND_UNIT_DATA )
330 ** If the encapsulation service is SendUnit Data, this is a
331 ** encapsulated connected message
334 /* Add sequence count ( Transport Class 1,2,3 )*/
335 proto_tree_add_text( item_tree, tvb, offset+6, 2, "Sequence Count: 0x%04X", tvb_get_letohs( tvb, offset+6 ) );
337 /* Call dissector for interface */
338 next_tvb = tvb_new_subset (tvb, offset+8, item_length-2, item_length-2);
340 if( tvb_length_remaining(next_tvb, 0) == 0 || !dissector_try_port(subdissector_sud_table, ifacehndl, next_tvb, pinfo, g_tree) )
342 /* Show the undissected payload */
343 if( tvb_length_remaining(tvb, offset) > 0 )
344 call_dissector( data_handle, next_tvb, pinfo, g_tree );
351 add_byte_array_text_to_proto_tree( item_tree, tvb, offset+6, item_length, "Data: " );
353 } /* End of if send unit data */
358 case LIST_IDENTITY_RESP:
360 /* Encapsulation version */
361 temp_data = tvb_get_letohs( tvb, offset+6 );
362 proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation Version: %d", temp_data );
365 sockaddr_item = proto_tree_add_text( item_tree, tvb, offset+8, 16, "Socket Address");
366 sockaddr_tree = proto_item_add_subtree( sockaddr_item, ett_sockadd );
368 /* Socket address struct - sin_family */
369 proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinfamily,
370 tvb, offset+8, 2, FALSE );
372 /* Socket address struct - sin_port */
373 proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinport,
374 tvb, offset+10, 2, FALSE );
376 /* Socket address struct - sin_address */
377 proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinaddr,
378 tvb, offset+12, 4, FALSE );
380 /* Socket address struct - sin_zero */
381 proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinzero,
382 tvb, offset+16, 8, FALSE );
385 proto_tree_add_item(item_tree, hf_enip_lir_vendor,
386 tvb, offset+24, 2, TRUE );
389 proto_tree_add_item(item_tree, hf_enip_lir_devtype,
390 tvb, offset+26, 2, TRUE );
393 proto_tree_add_item(item_tree, hf_enip_lir_prodcode,
394 tvb, offset+28, 2, TRUE );
397 temp_data = tvb_get_letohs( tvb, offset+30 );
398 proto_tree_add_text( item_tree, tvb, offset+30, 2, "Revision: %d.%02d", temp_data & 0xFF, ( temp_data & 0xFF00 ) >> 8 );
401 proto_tree_add_item(item_tree, hf_enip_lir_status,
402 tvb, offset+32, 2, TRUE );
405 proto_tree_add_item(item_tree, hf_enip_lir_serial,
406 tvb, offset+34, 4, TRUE );
408 /* Product Name Length */
409 name_length = tvb_get_guint8( tvb, offset+38 );
410 proto_tree_add_text( item_tree, tvb, offset+38, 1, "Product Name Length: %d", name_length );
413 proto_tree_add_item(item_tree, hf_enip_lir_name,
414 tvb, offset+39, name_length, TRUE );
416 /* Append product name to info column */
417 if(check_col(pinfo->cinfo, COL_INFO))
419 col_append_fstr( pinfo->cinfo, COL_INFO, ", %s",
420 tvb_format_text(tvb, offset+39, name_length));
424 proto_tree_add_item(item_tree, hf_enip_lir_state,
425 tvb, offset+name_length+39, 1, TRUE );
429 case SOCK_ADR_INFO_OT:
430 case SOCK_ADR_INFO_TO:
432 /* Socket address struct - sin_family */
433 proto_tree_add_item(item_tree, hf_enip_lir_sinfamily,
434 tvb, offset+6, 2, FALSE );
436 /* Socket address struct - sin_port */
437 proto_tree_add_item(item_tree, hf_enip_lir_sinport,
438 tvb, offset+8, 2, FALSE );
440 /* Socket address struct - sin_address */
441 proto_tree_add_item(item_tree, hf_enip_lir_sinaddr,
442 tvb, offset+10, 4, FALSE );
444 /* Socket address struct - sin_zero */
445 proto_tree_add_item( item_tree, hf_enip_lir_sinzero,
446 tvb, offset+14, 8, FALSE );
451 proto_tree_add_item(item_tree, hf_enip_cpf_sai_connid,
452 tvb, offset+6, 4, TRUE );
454 proto_tree_add_item(item_tree, hf_enip_cpf_sai_seqnum,
455 tvb, offset+10, 4, TRUE );
457 /* Add info to column */
459 if(check_col(pinfo->cinfo, COL_INFO))
461 col_clear(pinfo->cinfo, COL_INFO);
463 col_add_fstr(pinfo->cinfo, COL_INFO,
464 "Connection: ID=0x%08X, SEQ=%010d",
465 tvb_get_letohl( tvb, offset+6 ),
466 tvb_get_letohl( tvb, offset+10 ) );
471 case LIST_SERVICES_RESP:
473 /* Encapsulation version */
474 temp_data = tvb_get_letohs( tvb, offset+6 );
475 proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation Version: %d", temp_data );
477 /* Capability flags */
478 temp_data = tvb_get_letohs( tvb, offset+8 );
479 temp_item = proto_tree_add_text(item_tree, tvb, offset+8, 2, "Capability Flags: 0x%04X", temp_data );
480 temp_tree = proto_item_add_subtree(temp_item, ett_lsrcf);
482 proto_tree_add_item(temp_tree, hf_enip_lsr_tcp,
483 tvb, offset+8, 2, TRUE );
484 proto_tree_add_item(temp_tree, hf_enip_lsr_udp,
485 tvb, offset+8, 2, TRUE );
487 /* Name of service */
488 temp_item = proto_tree_add_text( item_tree, tvb, offset+10, 16, "Name of Service: %s",
489 tvb_format_stringzpad(tvb, offset+10, 16) );
491 /* Append service name to info column */
492 if(check_col(pinfo->cinfo, COL_INFO))
494 col_append_fstr( pinfo->cinfo, COL_INFO, ", %s",
495 tvb_format_stringzpad(tvb, offset+10, 16) );
503 add_byte_array_text_to_proto_tree( item_tree, tvb, offset+6, item_length, "Data: " );
506 } /* end of switch( item type ) */
508 } /* end of if( item length ) */
510 offset = offset + item_length + 4;
512 } /* end of while( item count ) */
514 } /* end of dissect_cpf() */
519 classify_packet(packet_info *pinfo)
521 /* see if nature of packets can be derived from src/dst ports */
522 /* if so, return as found */
523 if ( ( ENIP_ENCAP_PORT == pinfo->srcport && ENIP_ENCAP_PORT != pinfo->destport ) ||
524 ( ENIP_ENCAP_PORT != pinfo->srcport && ENIP_ENCAP_PORT == pinfo->destport ) ) {
525 if ( ENIP_ENCAP_PORT == pinfo->srcport )
526 return RESPONSE_PACKET;
527 else if ( ENIP_ENCAP_PORT == pinfo->destport )
528 return REQUEST_PACKET;
530 /* else, cannot classify */
531 return CANNOT_CLASSIFY;
535 get_enip_pdu_len(tvbuff_t *tvb, int offset)
540 * Get the length of the data from the encapsulation header.
542 plen = tvb_get_letohs(tvb, offset + 2);
545 * That length doesn't include the encapsulation header itself;
551 /* Code to actually dissect the packets */
553 dissect_enip_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
556 guint16 encap_cmd, encap_data_length;
557 char pkt_type_str[9] = "";
560 /* Set up structures needed to add the protocol subtree and manage it */
561 proto_item *ti, *encaph, *csf;
562 proto_tree *enip_tree, *header_tree, *csftree;
564 /* Make entries in Protocol column and Info column on summary display */
565 if (check_col(pinfo->cinfo, COL_PROTOCOL))
566 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENIP");
567 if (check_col(pinfo->cinfo, COL_INFO))
568 col_clear(pinfo->cinfo, COL_INFO);
570 encap_cmd = tvb_get_letohs( tvb, 0 );
572 if( check_col(pinfo->cinfo, COL_INFO) )
574 packet_type = classify_packet(pinfo);
576 switch ( packet_type )
579 strcpy(pkt_type_str, "Req");
582 case RESPONSE_PACKET:
583 strcpy(pkt_type_str, "Rsp");
587 strcpy(pkt_type_str, "?");
590 /* Add service and request/response to info column */
591 col_add_fstr(pinfo->cinfo, COL_INFO,
593 val_to_str(encap_cmd, encap_cmd_vals, "Unknown (0x%04x)"),
597 } /* end of if( col exists ) */
599 /* In the interest of speed, if "tree" is NULL, don't do any work not
600 necessary to generate protocol tree items. */
603 /* create display subtree for the protocol */
604 ti = proto_tree_add_item(tree, proto_enip, tvb, 0, -1, FALSE);
606 enip_tree = proto_item_add_subtree(ti, ett_enip);
608 /* Add encapsulation header tree */
609 encaph = proto_tree_add_text( enip_tree, tvb, 0, 24, "Encapsulation Header");
610 header_tree = proto_item_add_subtree(encaph, ett_enip);
612 /* Add EtherNet/IP encapsulation header */
613 proto_tree_add_item( header_tree, hf_enip_command, tvb, 0, 2, TRUE );
615 encap_data_length = tvb_get_letohs( tvb, 2 );
616 proto_tree_add_text( header_tree, tvb, 2, 2, "Length: %u", encap_data_length );
618 proto_tree_add_item( header_tree, hf_enip_session, tvb, 4, 4, TRUE );
619 proto_tree_add_item( header_tree, hf_enip_status, tvb, 8, 4, TRUE );
620 proto_tree_add_item( header_tree, hf_enip_sendercontex, tvb, 12, 8, TRUE );
621 proto_tree_add_item( header_tree, hf_enip_options, tvb, 20, 4, TRUE );
623 /* Append session and command to the protocol tree */
624 proto_item_append_text( ti, ", Session: 0x%08X, %s", tvb_get_letohl( tvb, 4 ),
625 val_to_str( encap_cmd, encap_cmd_vals, "Unknown (0x%04x)" ) );
628 ** For some commands we want to add some info to the info column
631 if( check_col( pinfo->cinfo, COL_INFO ) )
636 case REGISTER_SESSION:
637 case UNREGISTER_SESSION:
638 col_append_fstr( pinfo->cinfo, COL_INFO, ", Session: 0x%08X",
639 tvb_get_letohl( tvb, 4 ) );
641 } /* end of switch() */
643 } /* end of id info column */
645 /* Command specific data - create tree */
646 if( encap_data_length )
648 /* The packet have some command specific data, buid a sub tree for it */
650 csf = proto_tree_add_text( enip_tree, tvb, 24, encap_data_length,
651 "Command Specific Data");
653 csftree = proto_item_add_subtree(csf, ett_command_tree);
661 dissect_cpf( encap_cmd, tvb, pinfo, csftree, 24, 0 );
665 dissect_cpf( encap_cmd, tvb, pinfo, csftree, 24, 0 );
668 case LIST_INTERFACES:
669 dissect_cpf( encap_cmd, tvb, pinfo, csftree, 24, 0 );
672 case REGISTER_SESSION:
673 proto_tree_add_text( csftree, tvb, 24, 2, "Protocol Version: 0x%04X",
674 tvb_get_letohs( tvb, 24 ) );
676 proto_tree_add_text( csftree, tvb, 26, 2, "Option Flags: 0x%04X",
677 tvb_get_letohs( tvb, 26 ) );
681 case UNREGISTER_SESSION:
685 proto_tree_add_item(csftree, hf_enip_srrd_ifacehnd, tvb, 24, 4, TRUE);
687 proto_tree_add_text( csftree, tvb, 28, 2, "Timeout: %u",
688 tvb_get_letohs( tvb, 28 ) );
690 ifacehndl = tvb_get_letohl( tvb, 24 );
691 dissect_cpf( encap_cmd, tvb, pinfo, csftree, 30, ifacehndl );
695 proto_tree_add_item(csftree, hf_enip_sud_ifacehnd, tvb, 24, 4, TRUE);
697 proto_tree_add_text( csftree, tvb, 28, 2, "Timeout: %u",
698 tvb_get_letohs( tvb, 28 ) );
700 ifacehndl = tvb_get_letohl( tvb, 24 );
701 dissect_cpf( encap_cmd, tvb, pinfo, csftree, 30, ifacehndl );
704 case INDICATE_STATUS:
708 /* Can not decode - Just show the data */
709 add_byte_array_text_to_proto_tree( header_tree, tvb, 24, encap_data_length, "Encap Data: " );
712 } /* end of switch() */
714 } /* end of if( encapsulated data ) */
717 } /* end of dissect_enip_pdu() */
720 dissect_enip_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
726 /* An ENIP packet is at least 4 bytes long - we need the command type. */
727 if (!tvb_bytes_exist(tvb, 0, 4))
730 /* Get the command type and see if it's valid. */
731 encap_cmd = tvb_get_letohs( tvb, 0 );
732 if (match_strval(encap_cmd, encap_cmd_vals) == NULL)
733 return 0; /* not a known command */
735 dissect_enip_pdu(tvb, pinfo, tree);
736 return tvb_length(tvb);
740 dissect_enip_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
746 /* An ENIP packet is at least 4 bytes long - we need the command type. */
747 if (!tvb_bytes_exist(tvb, 0, 4))
750 /* Get the command type and see if it's valid. */
751 encap_cmd = tvb_get_letohs( tvb, 0 );
752 if (match_strval(encap_cmd, encap_cmd_vals) == NULL)
753 return 0; /* not a known command */
755 tcp_dissect_pdus(tvb, pinfo, tree, enip_desegment, 4,
756 get_enip_pdu_len, dissect_enip_pdu);
757 return tvb_length(tvb);
760 /* Code to actually dissect the io packets*/
762 dissect_enipio(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
764 /* Set up structures needed to add the protocol subtree and manage it */
766 proto_tree *enip_tree;
770 /* Make entries in Protocol column and Info column on summary display */
771 if (check_col(pinfo->cinfo, COL_PROTOCOL))
772 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENIP");
774 /* In the interest of speed, if "tree" is NULL, don't do any work not
775 necessary to generate protocol tree items. */
778 /* create display subtree for the protocol */
779 ti = proto_tree_add_item(tree, proto_enip, tvb, 0, -1, FALSE);
781 enip_tree = proto_item_add_subtree(ti, ett_enip);
783 dissect_cpf( 0xFFFF, tvb, pinfo, enip_tree, 0, 0 );
786 } /* end of dissect_enipio() */
789 /* Register the protocol with Ethereal */
791 /* this format is require because a script is used to build the C function
792 that calls all the protocol registration.
796 proto_register_enip(void)
798 /* Setup list of header fields */
799 static hf_register_info hf[] = {
801 { "Command", "enip.command",
802 FT_UINT16, BASE_HEX, VALS(encap_cmd_vals), 0,
803 "Encapsulation command", HFILL }
806 { "Session Handle", "enip.session",
807 FT_UINT32, BASE_HEX, NULL, 0,
808 "Session identification", HFILL }
811 { "Status", "enip.status",
812 FT_UINT32, BASE_HEX, VALS(encap_status_vals), 0,
813 "Status code", HFILL }
815 { &hf_enip_sendercontex,
816 { "Sender Context", "enip.context",
817 FT_BYTES, BASE_HEX, NULL, 0,
818 "Information pertient to the sender", HFILL }
821 { "Options", "enip.options",
822 FT_UINT32, BASE_HEX, NULL, 0,
823 "Options flags", HFILL }
826 { "Supports CIP Encapsulation via TCP", "enip.lsr.capaflags.tcp",
827 FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0020,
828 "ListServices Reply: Supports CIP Encapsulation via TCP", HFILL }
831 { "Supports CIP Class 0 or 1 via UDP", "enip.lsr.capaflags.udp",
832 FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0100,
833 "ListServices Reply: Supports CIP Class 0 or 1 via UDP", HFILL }
835 /* Send Request/Reply Data */
836 { &hf_enip_srrd_ifacehnd,
837 { "Interface Handle", "enip.srrd.iface",
838 FT_UINT32, BASE_HEX, VALS(enip_interface_handle_vals), 0,
839 "SendRRData: Interface handle", HFILL }
842 { &hf_enip_sud_ifacehnd,
843 { "Interface Handle", "enip.sud.iface",
844 FT_UINT32, BASE_HEX, VALS(enip_interface_handle_vals), 0,
845 "SendUnitData: Interface handle", HFILL }
847 /* List identity reply */
848 { &hf_enip_lir_sinfamily,
849 { "sin_family", "enip.lir.sa.sinfamily",
850 FT_UINT16, BASE_DEC, NULL, 0,
851 "ListIdentity Reply: Socket Address.Sin Family", HFILL }
853 { &hf_enip_lir_sinport,
854 { "sin_port", "enip.lir.sa.sinport",
855 FT_UINT16, BASE_DEC, NULL, 0,
856 "ListIdentity Reply: Socket Address.Sin Port", HFILL }
858 { &hf_enip_lir_sinaddr,
859 { "sin_addr", "enip.lir.sa.sinaddr",
860 FT_IPv4, BASE_HEX, NULL, 0,
861 "ListIdentity Reply: Socket Address.Sin Addr", HFILL }
863 { &hf_enip_lir_sinzero,
864 { "sin_zero", "enip.lir.sa.sinzero",
865 FT_BYTES, BASE_HEX, NULL, 0,
866 "ListIdentity Reply: Socket Address.Sin Zero", HFILL }
868 { &hf_enip_lir_vendor,
869 { "Vendor ID", "enip.lir.vendor",
870 FT_UINT16, BASE_HEX, VALS(cip_vendor_vals), 0,
871 "ListIdentity Reply: Vendor ID", HFILL }
873 { &hf_enip_lir_devtype,
874 { "Device Type", "enip.lir.devtype",
875 FT_UINT16, BASE_DEC, VALS(cip_devtype_vals), 0,
876 "ListIdentity Reply: Device Type", HFILL }
878 { &hf_enip_lir_prodcode,
879 { "Product Code", "enip.lir.prodcode",
880 FT_UINT16, BASE_DEC, NULL, 0,
881 "ListIdentity Reply: Product Code", HFILL }
883 { &hf_enip_lir_status,
884 { "Status", "enip.lir.status",
885 FT_UINT16, BASE_HEX, NULL, 0,
886 "ListIdentity Reply: Status", HFILL }
888 { &hf_enip_lir_serial,
889 { "Serial Number", "enip.lir.serial",
890 FT_UINT32, BASE_HEX, NULL, 0,
891 "ListIdentity Reply: Serial Number", HFILL }
894 { "Product Name", "enip.lir.name",
895 FT_STRING, BASE_NONE, NULL, 0,
896 "ListIdentity Reply: Product Name", HFILL }
898 { &hf_enip_lir_state,
899 { "State", "enip.lir.state",
900 FT_UINT8, BASE_HEX, NULL, 0,
901 "ListIdentity Reply: State", HFILL }
903 /* Common Packet Format */
904 { &hf_enip_cpf_typeid,
905 { "Type ID", "enip.cpf.typeid",
906 FT_UINT16, BASE_HEX, VALS(cdf_type_vals), 0,
907 "Common Packet Format: Type of encapsulated item", HFILL }
909 /* Sequenced Address Type */
910 { &hf_enip_cpf_sai_connid,
911 { "Connection ID", "enip.cpf.sai.connid",
912 FT_UINT32, BASE_HEX, NULL, 0,
913 "Common Packet Format: Sequenced Address Item, Connection Identifier", HFILL }
915 { &hf_enip_cpf_sai_seqnum,
916 { "Sequence Number", "enip.cpf.sai.seq",
917 FT_UINT32, BASE_DEC, NULL, 0,
918 "Common Packet Format: Sequenced Address Item, Sequence Number", HFILL }
923 /* Setup protocol subtree array */
924 static gint *ett[] = {
932 module_t *enip_module;
934 /* Register the protocol name and description */
935 proto_enip = proto_register_protocol("EtherNet/IP (Industrial Protocol)",
938 /* Required function calls to register the header fields and subtrees used */
939 proto_register_field_array(proto_enip, hf, array_length(hf));
940 proto_register_subtree_array(ett, array_length(ett));
942 enip_module = prefs_register_protocol(proto_enip, NULL);
943 prefs_register_bool_preference(enip_module, "desegment",
944 "Desegment all EtherNet/IP messages spanning multiple TCP segments",
945 "Whether the EtherNet/IP dissector should desegment all messages spanning multiple TCP segments",
948 subdissector_sud_table = register_dissector_table("enip.sud.iface",
949 "SendUnitData.Interface Handle", FT_UINT32, BASE_HEX);
951 subdissector_srrd_table = register_dissector_table("enip.srrd.iface",
952 "SendRequestReplyData.Interface Handle", FT_UINT32, BASE_HEX);
954 } /* end of proto_register_enip() */
957 /* If this dissector uses sub-dissector registration add a registration routine.
958 This format is required because a script is used to find these routines and
959 create the code that calls these routines.
962 proto_reg_handoff_enip(void)
964 dissector_handle_t enip_udp_handle, enip_tcp_handle;
965 dissector_handle_t enipio_handle;
967 /* Register for EtherNet/IP, using TCP */
968 enip_tcp_handle = new_create_dissector_handle(dissect_enip_tcp, proto_enip);
969 dissector_add("tcp.port", ENIP_ENCAP_PORT, enip_tcp_handle);
971 /* Register for EtherNet/IP, using UDP */
972 enip_udp_handle = new_create_dissector_handle(dissect_enip_udp, proto_enip);
973 dissector_add("udp.port", ENIP_ENCAP_PORT, enip_udp_handle);
975 /* Register for EtherNet/IP IO data (UDP) */
976 enipio_handle = create_dissector_handle(dissect_enipio, proto_enip);
977 dissector_add("udp.port", ENIP_IO_PORT, enipio_handle);
979 /* Find dissector for data packet */
980 data_handle = find_dissector("data");
982 } /* end of proto_reg_handoff_enip() */