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>
42 #include "packet-tcp.h"
43 #include "packet-cip.h"
46 /* Communication Ports */
47 #define ENIP_ENCAP_PORT 44818 /* EtherNet/IP located on port 44818 */
48 #define ENIP_IO_PORT 2222 /* EtherNet/IP IO located on port 2222 */
50 /* Return codes of function classifying packets as query/response */
51 #define REQUEST_PACKET 0
52 #define RESPONSE_PACKET 1
53 #define CANNOT_CLASSIFY 2
55 /* EtherNet/IP function codes */
57 #define LIST_SERVICES 0x0004
58 #define LIST_IDENTITY 0x0063
59 #define LIST_INTERFACES 0x0064
60 #define REGISTER_SESSION 0x0065
61 #define UNREGISTER_SESSION 0x0066
62 #define SEND_RR_DATA 0x006F
63 #define SEND_UNIT_DATA 0x0070
64 #define INDICATE_STATUS 0x0072
67 /* EtherNet/IP status codes */
68 #define SUCCESS 0x0000
69 #define INVALID_CMD 0x0001
70 #define NO_RESOURCES 0x0002
71 #define INCORRECT_DATA 0x0003
72 #define INVALID_SESSION 0x0064
73 #define INVALID_LENGTH 0x0065
74 #define UNSUPPORTED_PROT_REV 0x0069
76 /* EtherNet/IP Common Data Format Type IDs */
77 #define CDF_NULL 0x0000
78 #define LIST_IDENTITY_RESP 0x000C
79 #define CONNECTION_BASED 0x00A1
80 #define CONNECTION_TRANSPORT 0x00B1
81 #define UNCONNECTED_MSG 0x00B2
82 #define LIST_SERVICES_RESP 0x0100
83 #define SOCK_ADR_INFO_OT 0x8000
84 #define SOCK_ADR_INFO_TO 0x8001
85 #define SEQ_ADDRESS 0x8002
88 /* Initialize the protocol and registered fields */
89 static int proto_enip = -1;
91 static int hf_enip_command = -1;
92 static int hf_enip_options = -1;
93 static int hf_enip_sendercontex = -1;
94 static int hf_enip_status = -1;
95 static int hf_enip_session = -1;
97 static int hf_enip_lir_sinfamily = -1;
98 static int hf_enip_lir_sinport = -1;
99 static int hf_enip_lir_sinaddr = -1;
100 static int hf_enip_lir_sinzero = -1;
102 static int hf_enip_lir_vendor = -1;
103 static int hf_enip_lir_devtype = -1;
104 static int hf_enip_lir_prodcode = -1;
105 static int hf_enip_lir_status = -1;
106 static int hf_enip_lir_serial = -1;
107 static int hf_enip_lir_name = -1;
108 static int hf_enip_lir_state = -1;
110 static int hf_enip_lsr_tcp = -1;
111 static int hf_enip_lsr_udp = -1;
113 static int hf_enip_srrd_ifacehnd = -1;
115 static int hf_enip_sud_ifacehnd = -1;
117 static int hf_enip_cpf_typeid = -1;
118 static int hf_enip_cpf_sai_connid = -1;
119 static int hf_enip_cpf_sai_seqnum = -1;
121 /* Initialize the subtree pointers */
122 static gint ett_enip = -1;
123 static gint ett_count_tree = -1;
124 static gint ett_type_tree = -1;
125 static gint ett_command_tree = -1;
126 static gint ett_sockadd = -1;
127 static gint ett_lsrcf = -1;
129 static proto_tree *g_tree;
130 static dissector_table_t subdissector_srrd_table;
131 static dissector_table_t subdissector_sud_table;
132 static dissector_handle_t data_handle;
134 static gboolean enip_desegment = TRUE;
136 /* Translate function to string - Encapsulation commands */
137 static const value_string encap_cmd_vals[] = {
139 { LIST_SERVICES, "List Services" },
140 { LIST_IDENTITY, "List Identity" },
141 { LIST_INTERFACES, "List Interfaces" },
142 { REGISTER_SESSION, "Register Session" },
143 { UNREGISTER_SESSION,"Unregister Session" },
144 { SEND_RR_DATA, "Send RR Data" },
145 { SEND_UNIT_DATA, "Send Unit Data" },
146 { INDICATE_STATUS, "Indicate Status" },
147 { CANCEL, "Cancel" },
152 /* Translate function to string - Encapsulation status */
153 static const value_string encap_status_vals[] = {
154 { SUCCESS, "Success" },
155 { INVALID_CMD, "Invalid Command" },
156 { NO_RESOURCES, "No Memory Resources" },
157 { INCORRECT_DATA, "Incorrect Data" },
158 { INVALID_SESSION, "Invalid Session Handle" },
159 { INVALID_LENGTH, "Invalid Length" },
160 { UNSUPPORTED_PROT_REV, "Unsupported Protocol Revision" },
165 /* Translate function to Common data format values */
166 static const value_string cdf_type_vals[] = {
167 { CDF_NULL, "Null Address Item" },
168 { LIST_IDENTITY_RESP, "List Identity Response" },
169 { CONNECTION_BASED, "Connected Address Item" },
170 { CONNECTION_TRANSPORT, "Connected Data Item" },
171 { UNCONNECTED_MSG, "Unconnected Data Item" },
172 { LIST_SERVICES_RESP, "List Services Response" },
173 { SOCK_ADR_INFO_OT, "Socket Address Info O->T" },
174 { SOCK_ADR_INFO_TO, "Socket Address Info T->O" },
175 { SEQ_ADDRESS, "Sequenced Address Item" },
181 /* Translate function to string - True/False */
182 static const value_string enip_true_false_vals[] = {
190 /* Translate interface handle to string */
191 static const value_string enip_interface_handle_vals[] = {
198 /* Disssect Common Packet Format */
200 dissect_cpf( int command, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint32 ifacehndl )
202 proto_item *temp_item, *count_item, *type_item, *sockaddr_item;
203 proto_tree *temp_tree, *count_tree, *item_tree, *sockaddr_tree;
204 int temp_data, item_count, item_length, item;
205 unsigned char name_length;
208 /* Create item count tree */
209 item_count = tvb_get_letohs( tvb, offset );
210 count_item = proto_tree_add_text( tree, tvb, offset, 2, "Item Count: %d", item_count );
211 count_tree = proto_item_add_subtree( count_item, ett_count_tree );
213 while( item_count-- )
215 /* Add item type tree to item count tree*/
216 type_item = proto_tree_add_item( count_tree, hf_enip_cpf_typeid, tvb, offset+2, 2, TRUE );
217 item_tree = proto_item_add_subtree( type_item, ett_type_tree );
219 /* Add length field to item type tree*/
220 proto_tree_add_text( item_tree, tvb, offset+4, 2, "Length: %d", tvb_get_letohs( tvb, offset+4 ) );
222 item = tvb_get_letohs( tvb, offset+2 );
223 item_length = tvb_get_letohs( tvb, offset+4 );
227 /* Add item data field */
231 case CONNECTION_BASED:
233 /* Add Connection identifier */
234 proto_tree_add_text( item_tree, tvb, offset+6, 4, "Connection Identifier: 0x%08X", tvb_get_letohl( tvb, offset + 6 ) );
236 /* Add Connection ID to Info col */
237 if(check_col(pinfo->cinfo, COL_INFO))
239 col_append_fstr(pinfo->cinfo, COL_INFO,
241 tvb_get_letohl( tvb, offset+6 ) );
246 case UNCONNECTED_MSG:
248 /* Call dissector for interface */
249 next_tvb = tvb_new_subset( tvb, offset+6, item_length, item_length );
251 if( tvb_length(next_tvb) == 0 || !dissector_try_port(subdissector_srrd_table, ifacehndl, next_tvb, pinfo, g_tree) )
253 /* Show the undissected payload */
254 if( tvb_length_remaining(tvb, offset) > 0 )
255 call_dissector( data_handle, next_tvb, pinfo, g_tree );
260 case CONNECTION_TRANSPORT:
262 if( command == SEND_UNIT_DATA )
265 ** If the encapsulation service is SendUnit Data, this is a
266 ** encapsulated connected message
269 /* Add sequence count ( Transport Class 1,2,3 )*/
270 proto_tree_add_text( item_tree, tvb, offset+6, 2, "Sequence Count: 0x%04X", tvb_get_letohs( tvb, offset+6 ) );
272 /* Call dissector for interface */
273 next_tvb = tvb_new_subset (tvb, offset+8, item_length-2, item_length-2);
275 if( tvb_length(next_tvb) == 0 || !dissector_try_port(subdissector_sud_table, ifacehndl, next_tvb, pinfo, g_tree) )
277 /* Show the undissected payload */
278 if( tvb_length_remaining(tvb, offset) > 0 )
279 call_dissector( data_handle, next_tvb, pinfo, g_tree );
286 if (tvb_length_remaining(tvb, offset+6) > 0)
288 next_tvb = tvb_new_subset(tvb, offset+6, item_length, item_length);
289 call_dissector(data_handle, next_tvb, pinfo, item_tree);
291 } /* End of if send unit data */
296 case LIST_IDENTITY_RESP:
298 /* Encapsulation version */
299 temp_data = tvb_get_letohs( tvb, offset+6 );
300 proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation Version: %d", temp_data );
303 sockaddr_item = proto_tree_add_text( item_tree, tvb, offset+8, 16, "Socket Address");
304 sockaddr_tree = proto_item_add_subtree( sockaddr_item, ett_sockadd );
306 /* Socket address struct - sin_family */
307 proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinfamily,
308 tvb, offset+8, 2, FALSE );
310 /* Socket address struct - sin_port */
311 proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinport,
312 tvb, offset+10, 2, FALSE );
314 /* Socket address struct - sin_address */
315 proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinaddr,
316 tvb, offset+12, 4, FALSE );
318 /* Socket address struct - sin_zero */
319 proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinzero,
320 tvb, offset+16, 8, FALSE );
323 proto_tree_add_item(item_tree, hf_enip_lir_vendor,
324 tvb, offset+24, 2, TRUE );
327 proto_tree_add_item(item_tree, hf_enip_lir_devtype,
328 tvb, offset+26, 2, TRUE );
331 proto_tree_add_item(item_tree, hf_enip_lir_prodcode,
332 tvb, offset+28, 2, TRUE );
335 temp_data = tvb_get_letohs( tvb, offset+30 );
336 proto_tree_add_text( item_tree, tvb, offset+30, 2, "Revision: %d.%02d", temp_data & 0xFF, ( temp_data & 0xFF00 ) >> 8 );
339 proto_tree_add_item(item_tree, hf_enip_lir_status,
340 tvb, offset+32, 2, TRUE );
343 proto_tree_add_item(item_tree, hf_enip_lir_serial,
344 tvb, offset+34, 4, TRUE );
346 /* Product Name Length */
347 name_length = tvb_get_guint8( tvb, offset+38 );
348 proto_tree_add_text( item_tree, tvb, offset+38, 1, "Product Name Length: %d", name_length );
351 proto_tree_add_item(item_tree, hf_enip_lir_name,
352 tvb, offset+39, name_length, TRUE );
354 /* Append product name to info column */
355 if(check_col(pinfo->cinfo, COL_INFO))
357 col_append_fstr( pinfo->cinfo, COL_INFO, ", %s",
358 tvb_format_text(tvb, offset+39, name_length));
362 proto_tree_add_item(item_tree, hf_enip_lir_state,
363 tvb, offset+name_length+39, 1, TRUE );
367 case SOCK_ADR_INFO_OT:
368 case SOCK_ADR_INFO_TO:
370 /* Socket address struct - sin_family */
371 proto_tree_add_item(item_tree, hf_enip_lir_sinfamily,
372 tvb, offset+6, 2, FALSE );
374 /* Socket address struct - sin_port */
375 proto_tree_add_item(item_tree, hf_enip_lir_sinport,
376 tvb, offset+8, 2, FALSE );
378 /* Socket address struct - sin_address */
379 proto_tree_add_item(item_tree, hf_enip_lir_sinaddr,
380 tvb, offset+10, 4, FALSE );
382 /* Socket address struct - sin_zero */
383 proto_tree_add_item( item_tree, hf_enip_lir_sinzero,
384 tvb, offset+14, 8, FALSE );
389 proto_tree_add_item(item_tree, hf_enip_cpf_sai_connid,
390 tvb, offset+6, 4, TRUE );
392 proto_tree_add_item(item_tree, hf_enip_cpf_sai_seqnum,
393 tvb, offset+10, 4, TRUE );
395 /* Add info to column */
397 if(check_col(pinfo->cinfo, COL_INFO))
399 col_clear(pinfo->cinfo, COL_INFO);
401 col_add_fstr(pinfo->cinfo, COL_INFO,
402 "Connection: ID=0x%08X, SEQ=%010d",
403 tvb_get_letohl( tvb, offset+6 ),
404 tvb_get_letohl( tvb, offset+10 ) );
409 case LIST_SERVICES_RESP:
411 /* Encapsulation version */
412 temp_data = tvb_get_letohs( tvb, offset+6 );
413 proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation Version: %d", temp_data );
415 /* Capability flags */
416 temp_data = tvb_get_letohs( tvb, offset+8 );
417 temp_item = proto_tree_add_text(item_tree, tvb, offset+8, 2, "Capability Flags: 0x%04X", temp_data );
418 temp_tree = proto_item_add_subtree(temp_item, ett_lsrcf);
420 proto_tree_add_item(temp_tree, hf_enip_lsr_tcp,
421 tvb, offset+8, 2, TRUE );
422 proto_tree_add_item(temp_tree, hf_enip_lsr_udp,
423 tvb, offset+8, 2, TRUE );
425 /* Name of service */
426 temp_item = proto_tree_add_text( item_tree, tvb, offset+10, 16, "Name of Service: %s",
427 tvb_format_stringzpad(tvb, offset+10, 16) );
429 /* Append service name to info column */
430 if(check_col(pinfo->cinfo, COL_INFO))
432 col_append_fstr( pinfo->cinfo, COL_INFO, ", %s",
433 tvb_format_stringzpad(tvb, offset+10, 16) );
440 if (tvb_length_remaining(tvb, offset+6) > 0)
442 next_tvb = tvb_new_subset(tvb, offset+6, item_length, item_length);
443 call_dissector(data_handle, next_tvb, pinfo, item_tree);
447 } /* end of switch( item type ) */
449 } /* end of if( item length ) */
451 offset = offset + item_length + 4;
453 } /* end of while( item count ) */
455 } /* end of dissect_cpf() */
460 classify_packet(packet_info *pinfo)
462 /* see if nature of packets can be derived from src/dst ports */
463 /* if so, return as found */
464 if ( ( ENIP_ENCAP_PORT == pinfo->srcport && ENIP_ENCAP_PORT != pinfo->destport ) ||
465 ( ENIP_ENCAP_PORT != pinfo->srcport && ENIP_ENCAP_PORT == pinfo->destport ) ) {
466 if ( ENIP_ENCAP_PORT == pinfo->srcport )
467 return RESPONSE_PACKET;
468 else if ( ENIP_ENCAP_PORT == pinfo->destport )
469 return REQUEST_PACKET;
471 /* else, cannot classify */
472 return CANNOT_CLASSIFY;
476 get_enip_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
481 * Get the length of the data from the encapsulation header.
483 plen = tvb_get_letohs(tvb, offset + 2);
486 * That length doesn't include the encapsulation header itself;
492 /* Code to actually dissect the packets */
494 dissect_enip_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
497 guint16 encap_cmd, encap_data_length;
498 const char *pkt_type_str = "";
502 /* Set up structures needed to add the protocol subtree and manage it */
503 proto_item *ti, *encaph, *csf;
504 proto_tree *enip_tree = NULL;
505 proto_tree *header_tree = NULL;
508 /* Make entries in Protocol column and Info column on summary display */
509 if (check_col(pinfo->cinfo, COL_PROTOCOL))
510 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENIP");
511 if (check_col(pinfo->cinfo, COL_INFO))
512 col_clear(pinfo->cinfo, COL_INFO);
514 encap_cmd = tvb_get_letohs( tvb, 0 );
515 encap_data_length = tvb_get_letohs( tvb, 2 );
517 if( check_col(pinfo->cinfo, COL_INFO) )
519 packet_type = classify_packet(pinfo);
521 switch ( packet_type )
527 case RESPONSE_PACKET:
535 /* Add service and request/response to info column */
536 col_add_fstr(pinfo->cinfo, COL_INFO,
538 val_to_str(encap_cmd, encap_cmd_vals, "Unknown (0x%04x)"),
541 } /* end of if( col exists ) */
543 /* In the interest of speed, if "tree" is NULL, don't do any work not
544 necessary to generate protocol tree items. */
547 /* create display subtree for the protocol */
548 ti = proto_tree_add_item(tree, proto_enip, tvb, 0, -1, FALSE);
550 enip_tree = proto_item_add_subtree(ti, ett_enip);
552 /* Add encapsulation header tree */
553 encaph = proto_tree_add_text( enip_tree, tvb, 0, 24, "Encapsulation Header");
554 header_tree = proto_item_add_subtree(encaph, ett_enip);
556 /* Add EtherNet/IP encapsulation header */
557 proto_tree_add_item( header_tree, hf_enip_command, tvb, 0, 2, TRUE );
559 proto_tree_add_text( header_tree, tvb, 2, 2, "Length: %u", encap_data_length );
561 proto_tree_add_item( header_tree, hf_enip_session, tvb, 4, 4, TRUE );
562 proto_tree_add_item( header_tree, hf_enip_status, tvb, 8, 4, TRUE );
563 proto_tree_add_item( header_tree, hf_enip_sendercontex, tvb, 12, 8, TRUE );
564 proto_tree_add_item( header_tree, hf_enip_options, tvb, 20, 4, TRUE );
566 /* Append session and command to the protocol tree */
567 proto_item_append_text( ti, ", Session: 0x%08X, %s", tvb_get_letohl( tvb, 4 ),
568 val_to_str( encap_cmd, encap_cmd_vals, "Unknown (0x%04x)" ) );
570 } /* end of if (tree) */
573 ** For some commands we want to add some info to the info column
576 if( check_col( pinfo->cinfo, COL_INFO ) )
581 case REGISTER_SESSION:
582 case UNREGISTER_SESSION:
583 col_append_fstr( pinfo->cinfo, COL_INFO, ", Session: 0x%08X",
584 tvb_get_letohl( tvb, 4 ) );
586 } /* end of switch() */
588 } /* end of id info column */
590 /* Command specific data - create tree */
591 if( encap_data_length )
593 /* The packet have some command specific data, buid a sub tree for it */
595 csf = proto_tree_add_text( enip_tree, tvb, 24, encap_data_length,
596 "Command Specific Data");
598 csftree = proto_item_add_subtree(csf, ett_command_tree);
606 dissect_cpf( encap_cmd, tvb, pinfo, csftree, 24, 0 );
610 dissect_cpf( encap_cmd, tvb, pinfo, csftree, 24, 0 );
613 case LIST_INTERFACES:
614 dissect_cpf( encap_cmd, tvb, pinfo, csftree, 24, 0 );
617 case REGISTER_SESSION:
618 proto_tree_add_text( csftree, tvb, 24, 2, "Protocol Version: 0x%04X",
619 tvb_get_letohs( tvb, 24 ) );
621 proto_tree_add_text( csftree, tvb, 26, 2, "Option Flags: 0x%04X",
622 tvb_get_letohs( tvb, 26 ) );
626 case UNREGISTER_SESSION:
630 proto_tree_add_item(csftree, hf_enip_srrd_ifacehnd, tvb, 24, 4, TRUE);
632 proto_tree_add_text( csftree, tvb, 28, 2, "Timeout: %u",
633 tvb_get_letohs( tvb, 28 ) );
635 ifacehndl = tvb_get_letohl( tvb, 24 );
636 dissect_cpf( encap_cmd, tvb, pinfo, csftree, 30, ifacehndl );
640 proto_tree_add_item(csftree, hf_enip_sud_ifacehnd, tvb, 24, 4, TRUE);
642 proto_tree_add_text( csftree, tvb, 28, 2, "Timeout: %u",
643 tvb_get_letohs( tvb, 28 ) );
645 ifacehndl = tvb_get_letohl( tvb, 24 );
646 dissect_cpf( encap_cmd, tvb, pinfo, csftree, 30, ifacehndl );
649 case INDICATE_STATUS:
652 /* Can not decode - Just show the data */
653 if (tvb_length_remaining(tvb, 24) > 0)
655 next_tvb = tvb_new_subset(tvb, 24, encap_data_length, encap_data_length);
656 call_dissector(data_handle, next_tvb, pinfo, header_tree);
660 } /* end of switch() */
662 } /* end of if( encapsulated data ) */
664 } /* end of dissect_enip_pdu() */
667 dissect_enip_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
673 /* An ENIP packet is at least 4 bytes long - we need the command type. */
674 if (tvb_length(tvb) < 4)
677 /* Get the command type and see if it's valid. */
678 encap_cmd = tvb_get_letohs( tvb, 0 );
679 if (match_strval(encap_cmd, encap_cmd_vals) == NULL)
680 return 0; /* not a known command */
682 dissect_enip_pdu(tvb, pinfo, tree);
683 return tvb_length(tvb);
687 dissect_enip_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
693 /* An ENIP packet is at least 4 bytes long - we need the command type. */
694 if (tvb_length(tvb) < 4)
697 /* Get the command type and see if it's valid. */
698 encap_cmd = tvb_get_letohs( tvb, 0 );
699 if (match_strval(encap_cmd, encap_cmd_vals) == NULL)
700 return 0; /* not a known command */
702 tcp_dissect_pdus(tvb, pinfo, tree, enip_desegment, 4,
703 get_enip_pdu_len, dissect_enip_pdu);
704 return tvb_length(tvb);
707 /* Code to actually dissect the io packets*/
709 dissect_enipio(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
711 /* Set up structures needed to add the protocol subtree and manage it */
713 proto_tree *enip_tree = NULL;
718 /* Verify that the packet belongs to this dissector */
719 if (tvb_length(tvb) < 4)
722 type_id = tvb_get_letohs( tvb, 2 );
723 if (match_strval(type_id, cdf_type_vals) == NULL)
724 return 0; /* not a known type id */
726 /* Make entries in Protocol column and Info column on summary display */
727 if (check_col(pinfo->cinfo, COL_PROTOCOL))
728 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENIP");
730 /* In the interest of speed, if "tree" is NULL, don't do any work not
731 necessary to generate protocol tree items. */
734 /* create display subtree for the protocol */
735 ti = proto_tree_add_item(tree, proto_enip, tvb, 0, -1, FALSE);
737 enip_tree = proto_item_add_subtree(ti, ett_enip);
740 dissect_cpf( 0xFFFF, tvb, pinfo, enip_tree, 0, 0 );
742 return tvb_length(tvb);
743 } /* end of dissect_enipio() */
746 /* Register the protocol with Wireshark */
748 /* this format is require because a script is used to build the C function
749 that calls all the protocol registration.
753 proto_register_enip(void)
755 /* Setup list of header fields */
756 static hf_register_info hf[] = {
758 { "Command", "enip.command",
759 FT_UINT16, BASE_HEX, VALS(encap_cmd_vals), 0,
760 "Encapsulation command", HFILL }
763 { "Session Handle", "enip.session",
764 FT_UINT32, BASE_HEX, NULL, 0,
765 "Session identification", HFILL }
768 { "Status", "enip.status",
769 FT_UINT32, BASE_HEX, VALS(encap_status_vals), 0,
770 "Status code", HFILL }
772 { &hf_enip_sendercontex,
773 { "Sender Context", "enip.context",
774 FT_BYTES, BASE_HEX, NULL, 0,
775 "Information pertient to the sender", HFILL }
778 { "Options", "enip.options",
779 FT_UINT32, BASE_HEX, NULL, 0,
780 "Options flags", HFILL }
783 { "Supports CIP Encapsulation via TCP", "enip.lsr.capaflags.tcp",
784 FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0020,
785 "ListServices Reply: Supports CIP Encapsulation via TCP", HFILL }
788 { "Supports CIP Class 0 or 1 via UDP", "enip.lsr.capaflags.udp",
789 FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0100,
790 "ListServices Reply: Supports CIP Class 0 or 1 via UDP", HFILL }
792 /* Send Request/Reply Data */
793 { &hf_enip_srrd_ifacehnd,
794 { "Interface Handle", "enip.srrd.iface",
795 FT_UINT32, BASE_HEX, VALS(enip_interface_handle_vals), 0,
796 "SendRRData: Interface handle", HFILL }
799 { &hf_enip_sud_ifacehnd,
800 { "Interface Handle", "enip.sud.iface",
801 FT_UINT32, BASE_HEX, VALS(enip_interface_handle_vals), 0,
802 "SendUnitData: Interface handle", HFILL }
804 /* List identity reply */
805 { &hf_enip_lir_sinfamily,
806 { "sin_family", "enip.lir.sa.sinfamily",
807 FT_UINT16, BASE_DEC, NULL, 0,
808 "ListIdentity Reply: Socket Address.Sin Family", HFILL }
810 { &hf_enip_lir_sinport,
811 { "sin_port", "enip.lir.sa.sinport",
812 FT_UINT16, BASE_DEC, NULL, 0,
813 "ListIdentity Reply: Socket Address.Sin Port", HFILL }
815 { &hf_enip_lir_sinaddr,
816 { "sin_addr", "enip.lir.sa.sinaddr",
817 FT_IPv4, BASE_HEX, NULL, 0,
818 "ListIdentity Reply: Socket Address.Sin Addr", HFILL }
820 { &hf_enip_lir_sinzero,
821 { "sin_zero", "enip.lir.sa.sinzero",
822 FT_BYTES, BASE_HEX, NULL, 0,
823 "ListIdentity Reply: Socket Address.Sin Zero", HFILL }
825 { &hf_enip_lir_vendor,
826 { "Vendor ID", "enip.lir.vendor",
827 FT_UINT16, BASE_HEX, VALS(cip_vendor_vals), 0,
828 "ListIdentity Reply: Vendor ID", HFILL }
830 { &hf_enip_lir_devtype,
831 { "Device Type", "enip.lir.devtype",
832 FT_UINT16, BASE_DEC, VALS(cip_devtype_vals), 0,
833 "ListIdentity Reply: Device Type", HFILL }
835 { &hf_enip_lir_prodcode,
836 { "Product Code", "enip.lir.prodcode",
837 FT_UINT16, BASE_DEC, NULL, 0,
838 "ListIdentity Reply: Product Code", HFILL }
840 { &hf_enip_lir_status,
841 { "Status", "enip.lir.status",
842 FT_UINT16, BASE_HEX, NULL, 0,
843 "ListIdentity Reply: Status", HFILL }
845 { &hf_enip_lir_serial,
846 { "Serial Number", "enip.lir.serial",
847 FT_UINT32, BASE_HEX, NULL, 0,
848 "ListIdentity Reply: Serial Number", HFILL }
851 { "Product Name", "enip.lir.name",
852 FT_STRING, BASE_NONE, NULL, 0,
853 "ListIdentity Reply: Product Name", HFILL }
855 { &hf_enip_lir_state,
856 { "State", "enip.lir.state",
857 FT_UINT8, BASE_HEX, NULL, 0,
858 "ListIdentity Reply: State", HFILL }
860 /* Common Packet Format */
861 { &hf_enip_cpf_typeid,
862 { "Type ID", "enip.cpf.typeid",
863 FT_UINT16, BASE_HEX, VALS(cdf_type_vals), 0,
864 "Common Packet Format: Type of encapsulated item", HFILL }
866 /* Sequenced Address Type */
867 { &hf_enip_cpf_sai_connid,
868 { "Connection ID", "enip.cpf.sai.connid",
869 FT_UINT32, BASE_HEX, NULL, 0,
870 "Common Packet Format: Sequenced Address Item, Connection Identifier", HFILL }
872 { &hf_enip_cpf_sai_seqnum,
873 { "Sequence Number", "enip.cpf.sai.seq",
874 FT_UINT32, BASE_DEC, NULL, 0,
875 "Common Packet Format: Sequenced Address Item, Sequence Number", HFILL }
880 /* Setup protocol subtree array */
881 static gint *ett[] = {
889 module_t *enip_module;
891 /* Register the protocol name and description */
892 proto_enip = proto_register_protocol("EtherNet/IP (Industrial Protocol)",
895 /* Required function calls to register the header fields and subtrees used */
896 proto_register_field_array(proto_enip, hf, array_length(hf));
897 proto_register_subtree_array(ett, array_length(ett));
899 enip_module = prefs_register_protocol(proto_enip, NULL);
900 prefs_register_bool_preference(enip_module, "desegment",
901 "Desegment all EtherNet/IP messages spanning multiple TCP segments",
902 "Whether the EtherNet/IP dissector should desegment all messages spanning multiple TCP segments",
905 subdissector_sud_table = register_dissector_table("enip.sud.iface",
906 "SendUnitData.Interface Handle", FT_UINT32, BASE_HEX);
908 subdissector_srrd_table = register_dissector_table("enip.srrd.iface",
909 "SendRequestReplyData.Interface Handle", FT_UINT32, BASE_HEX);
911 } /* end of proto_register_enip() */
914 /* If this dissector uses sub-dissector registration add a registration routine.
915 This format is required because a script is used to find these routines and
916 create the code that calls these routines.
919 proto_reg_handoff_enip(void)
921 dissector_handle_t enip_udp_handle, enip_tcp_handle;
922 dissector_handle_t enipio_handle;
924 /* Register for EtherNet/IP, using TCP */
925 enip_tcp_handle = new_create_dissector_handle(dissect_enip_tcp, proto_enip);
926 dissector_add("tcp.port", ENIP_ENCAP_PORT, enip_tcp_handle);
928 /* Register for EtherNet/IP, using UDP */
929 enip_udp_handle = new_create_dissector_handle(dissect_enip_udp, proto_enip);
930 dissector_add("udp.port", ENIP_ENCAP_PORT, enip_udp_handle);
932 /* Register for EtherNet/IP IO data (UDP) */
933 enipio_handle = new_create_dissector_handle(dissect_enipio, proto_enip);
934 dissector_add("udp.port", ENIP_IO_PORT, enipio_handle);
936 /* Find dissector for data packet */
937 data_handle = find_dissector("data");
939 } /* end of proto_reg_handoff_enip() */