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>
9 * $Id: packet-enip.c,v 1.7 2003/10/06 08:10:32 guy Exp $
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>
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 /* CIP Encapsulation 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 /* CIP Encapsulation 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 /* CIP 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
87 /* CIP Service Codes */
88 #define SC_GET_ATT_ALL 0x01
89 #define SC_SET_ATT_ALL 0x02
90 #define SC_GET_ATT_LIST 0x03
91 #define SC_SET_ATT_LIST 0x04
95 #define SC_CREATE 0x08
96 #define SC_DELETE 0x09
97 #define SC_MULT_SERV_PACK 0x0A
98 #define SC_APPLY_ATTRIBUTES 0x0D
99 #define SC_GET_ATT_SINGLE 0x0E
100 #define SC_SET_ATT_SINGLE 0x10
101 #define SC_FIND_NEXT_OBJ_INST 0x11
102 #define SC_RESTOR 0x15
104 #define SC_NO_OP 0x17
105 #define SC_GET_MEMBER 0x18
106 #define SC_SET_MEMBER 0x19
108 #define SC_FWD_CLOSE 0x4E
109 #define SC_UNCON_SEND 0x52
110 #define SC_FWD_OPEN 0x54
114 /* CIP Genral status codes */
115 #define CI_GRC_SUCCESS 0x00
116 #define CI_GRC_FAILURE 0x01
117 #define CI_GRC_NO_RESOURCE 0x02
118 #define CI_GRC_BAD_DATA 0x03
119 #define CI_GRC_BAD_PATH 0x04
120 #define CI_GRC_BAD_CLASS_INSTANCE 0x05
121 #define CI_GRC_PARTIAL_DATA 0x06
122 #define CI_GRC_CONN_LOST 0x07
123 #define CI_GRC_BAD_SERVICE 0x08
124 #define CI_GRC_BAD_ATTR_DATA 0x09
125 #define CI_GRC_ATTR_LIST_ERROR 0x0A
126 #define CI_GRC_ALREADY_IN_MODE 0x0B
127 #define CI_GRC_BAD_OBJ_MODE 0x0C
128 #define CI_GRC_OBJ_ALREADY_EXISTS 0x0D
129 #define CI_GRC_ATTR_NOT_SETTABLE 0x0E
130 #define CI_GRC_PERMISSION_DENIED 0x0F
131 #define CI_GRC_DEV_IN_WRONG_STATE 0x10
132 #define CI_GRC_REPLY_DATA_TOO_LARGE 0x11
133 #define CI_GRC_FRAGMENT_PRIMITIVE 0x12
134 #define CI_GRC_CONFIG_TOO_SMALL 0x13
135 #define CI_GRC_UNDEFINED_ATTR 0x14
136 #define CI_GRC_CONFIG_TOO_BIG 0x15
137 #define CI_GRC_OBJ_DOES_NOT_EXIST 0x16
138 #define CI_GRC_NO_FRAGMENTATION 0x17
139 #define CI_GRC_DATA_NOT_SAVED 0x18
140 #define CI_GRC_DATA_WRITE_FAILURE 0x19
141 #define CI_GRC_REQUEST_TOO_LARGE 0x1A
142 #define CI_GRC_RESPONSE_TOO_LARGE 0x1B
143 #define CI_GRC_MISSING_LIST_DATA 0x1C
144 #define CI_GRC_INVALID_LIST_STATUS 0x1D
145 #define CI_GRC_SERVICE_ERROR 0x1E
146 #define CI_GRC_CONN_RELATED_FAILURE 0x1F
147 #define CI_GRC_INVALID_PARAMETER 0x20
148 #define CI_GRC_WRITE_ONCE_FAILURE 0x21
149 #define CI_GRC_INVALID_REPLY 0x22
150 #define CI_GRC_BAD_KEY_IN_PATH 0x25
151 #define CI_GRC_BAD_PATH_SIZE 0x26
152 #define CI_GRC_UNEXPECTED_ATTR 0x27
153 #define CI_GRC_INVALID_MEMBER 0x28
154 #define CI_GRC_MEMBER_NOT_SETTABLE 0x29
156 #define CI_GRC_STILL_PROCESSING 0xFF
160 #define CI_SEGMENT_TYPE_MASK 0xE0
162 #define CI_PATH_SEGMENT 0x00
163 #define CI_LOGICAL_SEGMENT 0x20
164 #define CI_NETWORK_SEGMENT 0x40
165 #define CI_SYMBOLIC_SEGMENT 0x60
166 #define CI_DATA_SEGMENT 0x80
168 #define CI_LOGICAL_SEG_TYPE_MASK 0x1C
169 #define CI_LOGICAL_SEG_CLASS_ID 0x00
170 #define CI_LOGICAL_SEG_INST_ID 0x04
171 #define CI_LOGICAL_SEG_MBR_ID 0x08
172 #define CI_LOGICAL_SEG_CON_POINT 0x0C
173 #define CI_LOGICAL_SEG_ATTR_ID 0x10
174 #define CI_LOGICAL_SEG_SPECIAL 0x14
175 #define CI_LOGICAL_SEG_SERV_ID 0x18
176 #define CI_LOGICAL_SEG_RES_1 0x1C
178 #define CI_LOGICAL_SEG_FORMAT_MASK 0x03
179 #define CI_LOGICAL_SEG_8_BIT 0x00
180 #define CI_LOGICAL_SEG_16_BIT 0x01
181 #define CI_LOGICAL_SEG_32_BIT 0x02
182 #define CI_LOGICAL_SEG_RES_2 0x03
183 #define CI_LOGICAL_SEG_E_KEY 0x00
185 #define CI_E_KEY_FORMAT_VAL 0x04
187 #define CI_DATA_SEG_SIMPLE 0x80
188 #define CI_DATA_SEG_SYMBOL 0x91
191 /* Device Profile:s */
192 #define DP_GEN_DEV 0x00
193 #define DP_AC_DRIVE 0x02
194 #define DP_MOTOR_OVERLOAD 0x03
195 #define DP_LIMIT_SWITCH 0x04
196 #define DP_IND_PROX_SWITCH 0x05
197 #define DP_PHOTO_SENSOR 0x06
198 #define DP_GENP_DISC_IO 0x07
199 #define DP_RESOLVER 0x09
200 #define DP_COM_ADAPTER 0x0C
201 #define DP_POS_CNT 0x10
202 #define DP_DC_DRIVE 0x13
203 #define DP_CONTACTOR 0x15
204 #define DP_MOTOR_STARTER 0x16
205 #define DP_SOFT_START 0x17
207 #define DP_MASS_FLOW_CNT 0x1A
208 #define DP_PNEUM_VALVE 0x1B
209 #define DP_VACUUM_PRES_GAUGE 0x1C
213 /* Initialize the protocol and registered fields */
214 static int proto_cipencap = -1;
215 static int hf_enip_command = -1;
216 static int hf_enip_ifacehnd = -1;
218 static int hf_enip_cpf_typeid = -1;
220 static int hf_enip_ucm_sc = -1;
221 static int hf_enip_ucm_rr = -1;
222 static int hf_enip_ucm_path = -1;
223 static int hf_enip_ucm_genstat = -1;
224 static int hf_enip_cpf_lir_sinfamily = -1;
225 static int hf_enip_cpf_lir_sinport = -1;
226 static int hf_enip_cpf_lir_sinaddr = -1;
227 static int hf_enip_cpf_lir_sinzero = -1;
228 static int hf_enip_cpf_lir_devtype = -1;
229 static int hf_enip_cpf_lir_prodcode = -1;
230 static int hf_enip_cpf_lir_status = -1;
231 static int hf_enip_cpf_lir_sernbr = -1;
232 static int hf_enip_cpf_lir_namelength = -1;
233 static int hf_enip_cpf_lir_name = -1;
234 static int hf_enip_cpf_lir_state = -1;
236 static int hf_enip_cpf_sat_connid = -1;
237 static int hf_enip_cpf_sat_seqnum = -1;
239 static int hf_enip_vendors = -1;
241 static int hf_enip_ucm_fwo_comp = -1;
242 static int hf_enip_ucm_fwo_mrev = -1;
244 static int hf_enip_ucm_fwo_con_size = -1;
245 static int hf_enip_ucm_fwo_fixed_var = -1;
246 static int hf_enip_ucm_fwo_prio = -1;
247 static int hf_enip_ucm_fwo_typ = -1;
248 static int hf_enip_ucm_fwo_own = -1;
250 static int hf_enip_cpf_lsr_tcp = -1;
251 static int hf_enip_cpf_lsr_udp = -1;
254 /* Initialize the subtree pointers */
255 static gint ett_cipencap = -1;
256 static gint ett_cip = -1;
257 static gint ett_cpf = -1;
258 static gint ett_path = -1;
259 static gint ett_ekey_path = -1;
260 static gint ett_cia_path = -1;
261 static gint ett_data_seg = -1;
263 static gint ett_cipencaph = -1;
264 static gint ett_csf = -1;
265 static gint ett_rrsc = -1;
266 static gint ett_sockadd = -1;
267 static gint ett_mcsc = -1;
268 static gint ett_ncp = -1;
269 static gint ett_lsrcf = -1;
270 static gint ett_mes_req = -1;
271 static gint ett_cmd_data = -1;
272 static gint ett_port_path = -1;
273 static gint ett_mult_ser = -1;
277 /* Translate function to string - Encapsulation commands */
278 static const value_string encap_cmd_vals[] = {
280 { LIST_SERVICES, "List Services" },
281 { LIST_IDENTITY, "List Identity" },
282 { LIST_INTERFACES, "List Interfaces" },
283 { REGISTER_SESSION, "Register Session" },
284 { UNREGISTER_SESSION,"Unregister Session" },
285 { SEND_RR_DATA, "Send RR Data" },
286 { SEND_UNIT_DATA, "Send Unit Data" },
287 { INDICATE_STATUS, "Indicate Status" },
288 { CANCEL, "Cancel" },
294 /* Translate function to string - Encapsulation status */
295 static const value_string encap_status_vals[] = {
296 { SUCCESS, "Success" },
297 { INVALID_CMD, "Invalid Command" },
298 { NO_RESOURCES, "No Memory Resources" },
299 { INCORRECT_DATA, "Incorrect Data" },
300 { INVALID_SESSION, "Invalid Session Handle" },
301 { INVALID_LENGTH, "Invalid Length" },
302 { UNSUPPORTED_PROT_REV, "Unsupported Protocol Revision" },
307 /* Translate function to Common data format values */
308 static const value_string cdf_type_vals[] = {
309 { CDF_NULL, "Null Address Item" },
310 { LIST_IDENTITY_RESP, "List Identity Response" },
311 { CONNECTION_BASED, "Connected Address Item" },
312 { CONNECTION_TRANSPORT, "Connected Data Item" },
313 { UNCONNECTED_MSG, "Unconnected Data Item" },
314 { LIST_SERVICES_RESP, "List Services Response" },
315 { SOCK_ADR_INFO_OT, "Socket Address Info O->T" },
316 { SOCK_ADR_INFO_TO, "Socket Address Info T->O" },
317 { SEQ_ADDRESS, "Sequenced Address Item" },
322 /* Translate function to string - CIP Service codes */
323 static const value_string encap_sc_vals[] = {
324 { SC_GET_ATT_ALL, "Get Attribute All" },
325 { SC_SET_ATT_ALL, "Set Attribute All" },
326 { SC_GET_ATT_LIST, "Get Attribute List" },
327 { SC_SET_ATT_LIST, "Set Attribute List" },
328 { SC_RESET, "Reset" },
329 { SC_START, "Start" },
331 { SC_CREATE, "Create" },
332 { SC_DELETE, "Delete" },
333 { SC_APPLY_ATTRIBUTES, "Apply Attributes" },
334 { SC_GET_ATT_SINGLE, "Get Attribute Single" },
335 { SC_SET_ATT_SINGLE, "Set Attribute Single" },
336 { SC_FIND_NEXT_OBJ_INST, "Find Next Object Instance" },
337 { SC_RESTOR, "Restore" },
340 { SC_GET_MEMBER, "Get Member" },
341 { SC_SET_MEMBER, "Set Member" },
342 { SC_MULT_SERV_PACK, "Multiple Service Packet" },
344 /* Some class specific services */
345 { SC_FWD_CLOSE, "Forward Close" },
346 { SC_FWD_OPEN, "Forward Open" },
347 { SC_UNCON_SEND, "Unconnected Send" },
352 /* Translate function to string - CIP Request/Response */
353 static const value_string encap_sc_rr[] = {
361 /* Translate function to string - Compatibility */
362 static const value_string enip_com_bit_vals[] = {
363 { 0, "Bit Cleared" },
369 /* Translate function to string - True/False */
370 static const value_string enip_true_false_vals[] = {
378 /* Translate function to string - Connection priority */
379 static const value_string enip_con_prio_vals[] = {
380 { 0, "Low Priority" },
381 { 1, "High Priority" },
389 /* Translate function to string - Connection size fixed or variable */
390 static const value_string enip_con_fw_vals[] = {
398 /* Translate function to string - Connection owner */
399 static const value_string enip_con_owner_vals[] = {
407 /* Translate function to string - Connection type */
408 static const value_string enip_con_type_vals[] = {
411 { 2, "Point to Point" },
417 /* Translate function to string - Timeout Multiplier */
418 static const value_string enip_con_time_mult_vals[] = {
432 /* Translate function to string - CIP General Status codes */
433 static const value_string encap_cip_gs_vals[] = {
434 { CI_GRC_SUCCESS, "Success" },
435 { CI_GRC_FAILURE, "Connection failure" },
436 { CI_GRC_NO_RESOURCE, "Resource(s) unavailable" },
437 { CI_GRC_BAD_DATA, "Obj specific data bad" },
438 { CI_GRC_BAD_PATH, "Bad path segment" },
439 { CI_GRC_BAD_CLASS_INSTANCE, "Class/Instance unknown" },
440 { CI_GRC_PARTIAL_DATA, "Not all expected data sent" },
441 { CI_GRC_CONN_LOST, "Messaging connection lost" },
442 { CI_GRC_BAD_SERVICE, "Unimplemented service code" },
443 { CI_GRC_BAD_ATTR_DATA, "Bad attribute data value" },
444 { CI_GRC_ATTR_LIST_ERROR, "Get/Set attr list failed" },
445 { CI_GRC_ALREADY_IN_MODE, "Obj already in requested mode" },
446 { CI_GRC_BAD_OBJ_MODE, "Obj not in proper mode" },
447 { CI_GRC_OBJ_ALREADY_EXISTS, "Object already created" },
448 { CI_GRC_ATTR_NOT_SETTABLE, "Set of get only attr tried" },
449 { CI_GRC_PERMISSION_DENIED, "Insufficient access permission" },
450 { CI_GRC_DEV_IN_WRONG_STATE, "Device not in proper mode" },
451 { CI_GRC_REPLY_DATA_TOO_LARGE,"Response packet too large" },
452 { CI_GRC_FRAGMENT_PRIMITIVE, "Primitive value will fragment" },
453 { CI_GRC_CONFIG_TOO_SMALL, "Configuration too small" },
454 { CI_GRC_UNDEFINED_ATTR, "Attribute is undefined" },
455 { CI_GRC_CONFIG_TOO_BIG, "Configuration too big" },
456 { CI_GRC_OBJ_DOES_NOT_EXIST, "Non-existant object specified" },
457 { CI_GRC_NO_FRAGMENTATION, "Fragmentation not active" },
458 { CI_GRC_DATA_NOT_SAVED, "Attr data not previously saved" },
459 { CI_GRC_DATA_WRITE_FAILURE, "Attr data not saved this time" },
460 { CI_GRC_REQUEST_TOO_LARGE, "Routing failure on request" },
461 { CI_GRC_RESPONSE_TOO_LARGE, "Routing failure on response" },
462 { CI_GRC_MISSING_LIST_DATA, "Attr data not found in list" },
463 { CI_GRC_INVALID_LIST_STATUS, "Returned list of attr w/status" },
464 { CI_GRC_SERVICE_ERROR, "Embedded service failed" },
465 { CI_GRC_CONN_RELATED_FAILURE,"Error in conn processing" },
466 { CI_GRC_INVALID_PARAMETER, "Param associated with req inv" },
467 { CI_GRC_WRITE_ONCE_FAILURE, "Write once previously done" },
468 { CI_GRC_INVALID_REPLY, "Invalid reply received" },
469 { CI_GRC_BAD_KEY_IN_PATH, "Electronic key in path failed" },
470 { CI_GRC_BAD_PATH_SIZE, "Invalid path size" },
471 { CI_GRC_UNEXPECTED_ATTR, "Cannot set attr at this time" },
472 { CI_GRC_INVALID_MEMBER, "Member ID in list nonexistant" },
473 { CI_GRC_MEMBER_NOT_SETTABLE, "Cannot set value of member" },
479 /* Translate Vendor ID:s */
480 static const value_string encap_cip_vendor_vals[] = {
481 { 1, "Rockwell Automation/Allen-Bradley" },
482 { 5, "Rockwell Automation/Reliance Electric" },
483 { 40, "WAGO Corporation" },
484 { 49, "Grayhill Inc." },
485 { 50, "Real Time Automation (C&ID)" },
486 { 52, "Numatics, Inc." },
487 { 57, "Pepperl + Fuchs" },
488 { 81, "IXXAT Automation GmbH" },
489 { 90, "HMS Industrial Networks AB" },
490 { 96, "Digital Electronics Corp" },
491 { 133, "Balogh T.A.G., Corporation" },
492 { 170, "Pyramid Solutions, Inc." },
493 { 256, "InterlinkBT LLC" },
494 { 258, "Hardy Instruments, Inc." },
495 { 283, "Hilscher GmbH" },
496 { 287, "Bosch Rexroth Corporation, Indramat" },
497 { 356, "Fanuc Robotics America" },
498 { 579, "Applicom international" },
499 { 588, "West Instruments Limited" },
500 { 590, "Delta Computer Systems Inc." },
501 { 596, "Wire-Pro, Inc." },
502 { 635, "The Siemon Company" },
503 { 638, "Woodhead Connectivity" },
504 { 651, "Fife Corporation" },
505 { 668, "Rockwell Automation/Entek IRD Intl." },
506 { 678, "Cognex Corporation" },
507 { 734, "Hakko Electronics Co., Ltd" },
508 { 735, "Tang & Associates" },
509 { 743, "Linux Network Services" },
510 { 748, "DVT Corporation" },
511 { 759, "FLS Automation A/S" },
512 { 768, "CSIRO Mining Automation" },
513 { 778, "Harting, Inc. NA" },
514 { 784, "Ci Technologies Pty Ltd (for Pelamos Industries)" },
515 { 796, "Siemens Energy & Automation, Inc." },
516 { 798, "Tyco Electronics" },
517 { 803, "ICP DAS Co., LTD" },
518 { 805, "Digi International, Inc." },
519 { 812, "Process Control Corporation" },
520 { 832, "Quest Technical Solutions, Inc." },
521 { 841, "Panduit Corporation" },
522 { 850, "Datalogic, Inc." },
523 { 851, "SoftPLC Corporation" },
525 { 859, "Tennessee Rand Automation" },
530 /* Translate Device Profile:s */
531 static const value_string encap_cip_devtype_vals[] = {
532 { DP_GEN_DEV, "Generic Device" },
533 { DP_AC_DRIVE, "AC Drive" },
534 { DP_MOTOR_OVERLOAD, "Motor Overload" },
535 { DP_LIMIT_SWITCH, "Limit Switch" },
536 { DP_IND_PROX_SWITCH, "Inductive Proximity Switch" },
537 { DP_PHOTO_SENSOR, "Photoelectric Sensor" },
538 { DP_GENP_DISC_IO, "General Purpose Dicrete I/O" },
539 { DP_RESOLVER, "Resolver" },
540 { DP_COM_ADAPTER, "Communications Adapter" },
541 { DP_POS_CNT, "Position Controller", },
542 { DP_DC_DRIVE, "DC Drive" },
543 { DP_CONTACTOR, "Contactor", },
544 { DP_MOTOR_STARTER, "Motor Starter", },
545 { DP_SOFT_START, "Soft Start", },
546 { DP_HMI, "Human-Machine Interface" },
547 { DP_MASS_FLOW_CNT, "Mass Flow Controller" },
548 { DP_PNEUM_VALVE, "Pneumatic Valve" },
549 { DP_VACUUM_PRES_GAUGE, "Vaccuum Pressure Gauge" },
555 /* Translate class names */
556 static const value_string enip_class_names_vals[] = {
557 { 0x01, "Identity Object" },
558 { 0x02, "Message Router" },
559 { 0x03, "DeviceNet Object" },
560 { 0x04, "Assembly Object" },
561 { 0x05, "Connection Object" },
562 { 0x06, "Connection Manager" },
563 { 0x07, "Register Object" },
564 { 0x08, "Discrete Input Point Object" },
565 { 0x09, "Discrete Output Point Object" },
566 { 0x0A, "Analog Input Point Object" },
567 { 0x0B, "Analog Output Point Object" },
568 { 0x0E, "Presence Sensing Object" },
569 { 0x0F, "Parameter Object" },
570 { 0x10, "Parameter Group Object" },
571 { 0x12, "Group Object" },
572 { 0x1D, "Discrete Input Group Object" },
573 { 0x1E, "Discrete Output Group Object" },
574 { 0x1F, "Discrete Group Object" },
575 { 0x20, "Analog Input Group Object" },
576 { 0x21, "Analog Output Group Object" },
577 { 0x22, "Analog Group Object" },
578 { 0x23, "Position Sensor Object" },
579 { 0x24, "Position Controller Supervisor Object" },
580 { 0x25, "Position Controller Object" },
581 { 0x26, "Block Sequencer Object" },
582 { 0x27, "Command Block Object" },
583 { 0x28, "Motor Data Object" },
584 { 0x29, "Control Supervisor Object" },
585 { 0x2A, "AC/DC Drive Object" },
586 { 0x2B, "Acknowledge Handler Object" },
587 { 0x2C, "Overload Object" },
588 { 0x2D, "Softstart Object" },
589 { 0x2E, "Selection Object" },
590 { 0x30, "S-Device Supervisor Object" },
591 { 0x31, "S-Analog Sensor Object" },
592 { 0x32, "S-Analog Actuator Object" },
593 { 0x33, "S-Single Stage Controller Object" },
594 { 0x34, "S-Gas Calibration Object" },
595 { 0x35, "Trip Point Object" },
596 { 0xF0, "ControlNet Object" },
597 { 0xF1, "ControlNet Keeper Object" },
598 { 0xF2, "ControlNet Scheduling Object" },
599 { 0xF3, "Connection Configuration Object" },
600 { 0xF4, "Port Object" },
601 { 0xF5, "TCP/IP Interface Object" },
602 { 0xF6, "EtherNet Link Object" },
610 add_byte_array_text_to_proto_tree( proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char* str )
612 char *tmp, *tmp2, *tmp2start;
616 /* At least one version of Apple's C compiler/linker is buggy, causing
617 a complaint from the linker about the "literal C string section"
618 not ending with '\0' if we initialize a 16-element "char" array with
619 a 16-character string, the fact that initializing such an array with
620 such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
621 '\0' byte in the string nonwithstanding. */
622 static const char my_hex_digits[16] =
623 { '0', '1', '2', '3', '4', '5', '6', '7',
624 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
628 if( ( length * 2 ) > 32 )
630 tmp2 = (char*)g_malloc( 36 );
635 tmp2 = (char*)g_malloc( ( length * 2 ) + 1 );
641 tmp = (char*)g_malloc( tmp_length );
642 tvb_memcpy( tvb, tmp, start, tmp_length );
644 for( i = 0; i < tmp_length; i++ )
648 *tmp2++ = my_hex_digits[octet&0xF];
650 *tmp2++ = my_hex_digits[octet&0xF];
653 if( tmp_length != length )
662 pi = proto_tree_add_text( tree, tvb, start, length, "%s%s", str, tmp2start );
669 } /* end of add_byte_array_text_to_proto_tree() */
673 /* Decode and add epath to tree */
675 show_epath( tvbuff_t *tvb, proto_item *pi, int offset, int path_length )
680 unsigned char segment_type, temp_byte, opt_link_size;
681 proto_tree *path_tree, *port_tree;
682 proto_item *qi, *cia_item, *ds_item;
683 proto_tree *e_key_tree, *cia_tree, *ds_tree;
684 proto_item *mcpi, *temp_item, *port_item, *ext_link_item;
686 int seg_size, i, temp_word;
689 /* Create a sub tree for the epath */
690 path_tree = proto_item_add_subtree( pi, ett_path );
692 proto_tree_add_item_hidden(path_tree, hf_enip_ucm_path,
693 tvb, offset, path_length, TRUE );
697 while( pathpos < path_length )
699 /* Get segement type */
700 segment_type = tvb_get_guint8( tvb, offset + pathpos );
702 /* Determine the segment type */
704 switch( segment_type & CI_SEGMENT_TYPE_MASK )
706 case CI_PATH_SEGMENT:
708 port_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 0, "Port Segment (0x00)" );
709 port_tree = proto_item_add_subtree( port_item, ett_port_path );
711 /* Add Extended Link Address Size */
712 temp_item = proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Extended Link Address: " );
714 if( segment_type & 0x10 )
716 proto_item_append_text(temp_item, "TRUE");
717 opt_link_size = tvb_get_guint8( tvb, offset + pathpos + 1 );
719 proto_tree_add_text( port_tree, tvb, offset+pathpos+1, 1, "Link Address Size: %d", opt_link_size );
720 ext_link_item = proto_tree_add_text( port_tree, tvb, offset+pathpos+2, opt_link_size, "Link Address: " );
722 /* Add extended link address */
723 for( i=0; i < opt_link_size; i++ )
725 temp_byte = tvb_get_guint8( tvb, offset + pathpos+2+i );
726 proto_item_append_text(ext_link_item, "%c", temp_byte );
730 if( opt_link_size % 2 )
732 pathpos = pathpos + 3 + opt_link_size;
733 proto_item_set_len(port_item, 3+opt_link_size);
737 pathpos = pathpos + 2 + opt_link_size;
738 proto_item_set_len(port_item, 2+opt_link_size);
744 proto_item_append_text(temp_item, "FALSE");
745 proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Port Identifier: %d", (segment_type & 0x0F) );
746 proto_tree_add_text( port_tree, tvb, offset+pathpos+1, 1, "Link Address: %d", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
747 proto_item_set_len(port_item, 2);
753 case CI_LOGICAL_SEGMENT:
755 /* Logical segment, determin the logical type */
757 switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK )
759 case CI_LOGICAL_SEG_CLASS_ID:
761 /* Logical Class ID, do a format check */
763 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
765 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
766 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Class Segment (0x%02X)", segment_type );
768 /* Create a sub tree for the class */
769 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
771 /* Display the 8-bit class number */
772 proto_tree_add_text( cia_tree, tvb, offset + pathpos + 1, 1, "Class: %s (0x%02X)", val_to_str( temp_data, enip_class_names_vals , "Unknown class" ), temp_data );
774 temp_string = match_strval( temp_data, enip_class_names_vals );
778 proto_item_append_text(pi, "%s", temp_string );
782 proto_item_append_text(pi, "Class: 0x%02X", temp_data );
785 /* 2 bytes of path used */
788 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
790 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
791 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Class Segment (0x%02X)", segment_type );
793 /* Create a sub tree for the class */
794 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
796 /* Display the 16-bit class number */
797 proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 2, "Class: %s (0x%04X)", val_to_str( temp_data, enip_class_names_vals , "Unknown class" ), temp_data );
798 temp_string = match_strval( temp_data, enip_class_names_vals );
802 proto_item_append_text(pi, "%s", temp_string );
806 proto_item_append_text(pi, "Class: 0x%04X", temp_data );
809 /* 4 bytes of path used */
812 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
814 temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
815 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
817 /* Create a sub tree for the class */
818 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
820 /* Display the 32-bit instance number */
821 proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 4, "Class: %s (0x%08X)", val_to_str( temp_data, enip_class_names_vals , "Unknown class" ), temp_data );
822 temp_string = match_strval( temp_data, enip_class_names_vals );
826 proto_item_append_text(pi, "%s", temp_string );
830 proto_item_append_text(pi, "Class: 0x%08X", temp_data );
833 /* 6 bytes of path used */
838 /* Unsupported logical segment format */
839 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
845 case CI_LOGICAL_SEG_INST_ID:
847 /* Logical Instance ID, do a format check */
849 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
851 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
852 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Instance Segment (0x%02X)", segment_type );
854 /* Create a sub tree for the instance */
855 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
857 /* Display the 8-bit instance number */
858 proto_tree_add_text( cia_tree, tvb, offset + pathpos + 1, 1, "Instance: 0x%02X", temp_data );
859 proto_item_append_text(pi, ", Inst: 0x%02X", temp_data );
861 /* 2 bytes of path used */
864 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
866 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
867 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Instance Segment (0x%02X)", segment_type );
869 /* Create a sub tree for the instance */
870 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
872 /* Display the 16-bit instance number */
873 proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 2, "Instance: 0x%04X", temp_data );
874 proto_item_append_text(pi, ", Inst: 0x%04X", temp_data );
876 /* 4 bytes of path used */
879 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
881 temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
882 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
884 /* Create a sub tree for the instance */
885 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
887 /* Display the 16-bit instance number */
888 proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 4, "Instance: 0x%08X", temp_data );
889 proto_item_append_text(pi, ", Inst: 0x%08X", temp_data );
891 /* 6 bytes of path used */
896 /* Unsupported logical segment format */
897 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
903 case CI_LOGICAL_SEG_ATTR_ID:
905 /* Logical Attribute ID, do a format check */
907 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
909 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
910 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Attribute Segment (0x%02X)", segment_type );
912 /* Create a sub tree for the attribute */
913 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
915 /* Display the 8-bit instance number */
916 proto_tree_add_text( cia_tree, tvb, offset + pathpos + 1, 1, "Attribute: 0x%02X", temp_data );
917 proto_item_append_text(pi, ", Att: 0x%02X", temp_data );
919 /* 2 bytes of path used */
922 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
924 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
925 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Attribute Segment (0x%02X)", segment_type );
927 /* Create a sub tree for the attribute */
928 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
930 /* Display the 16-bit instance number */
931 proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 2, "Attribute: 0x%04X", temp_data );
932 proto_item_append_text(pi, ", Att: 0x%04X", temp_data );
934 /* 4 bytes of path used */
937 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
939 temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
940 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Attribute Segment (0x%02X)", segment_type );
942 /* Create a sub tree for the attribute */
943 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
945 /* Display the 16-bit instance number */
946 proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 4, "Attribute: 0x%08X", temp_data );
947 proto_item_append_text(pi, ", Att: 0x%08X", temp_data );
949 /* 6 bytes of path used */
954 /* Unsupported logical segment format */
955 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
961 case CI_LOGICAL_SEG_CON_POINT:
963 /* Logical Connection point , do a format check */
965 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
967 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
968 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Connection Point Segment (0x%02X)", segment_type );
970 /* Create a sub tree for the connection point */
971 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
973 /* Display the 8-bit instance number */
974 proto_tree_add_text( cia_tree, tvb, offset + pathpos + 1, 1, "Connection Point: 0x%02X", temp_data );
975 proto_item_append_text(pi, ", ConPnt: 0x%02X", temp_data );
977 /* 2 bytes of path used */
980 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
982 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
983 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Connection Point Segment (0x%02X)", segment_type );
985 /* Create a sub tree for the connection point */
986 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
988 /* Display the 16-bit instance number */
989 proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 2, "Connection Point: 0x%04X", temp_data );
990 proto_item_append_text(pi, ", ConPnt: 0x%04X", temp_data );
992 /* 4 bytes of path used */
995 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
997 temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
998 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Connection Point Segment (0x%02X)", segment_type );
1000 /* Create a sub tree for the connection point */
1001 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
1003 /* Display the 16-bit instance number */
1004 proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 4, "Connection Point (0x%08X)", temp_data );
1005 proto_item_append_text(pi, ", ConPnt: 0x%08X", temp_data );
1007 /* 6 bytes of path used */
1012 /* Unsupported logical segment format */
1013 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
1019 case CI_LOGICAL_SEG_SPECIAL:
1021 /* Logical Special ID, the only logical format sepcifyed is electronic key */
1023 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_E_KEY )
1026 /* Get the Key Format */
1028 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
1030 if( temp_data == CI_E_KEY_FORMAT_VAL )
1032 qi = proto_tree_add_text( path_tree, tvb, offset + pathpos, 10, "Electronic Key Segment (0x%02X): ",segment_type );
1034 /* Create a sub tree for the IOI */
1035 e_key_tree = proto_item_add_subtree( qi, ett_ekey_path );
1037 /* Print the key type */
1038 proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 1, 1, "Key Format: 0x%02X", temp_data );
1040 /* Get the Vendor ID */
1041 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
1042 proto_tree_add_item( e_key_tree, hf_enip_vendors, tvb, offset + pathpos + 2, 2, TRUE);
1043 proto_item_append_text( qi, "VendorID: 0x%04X", temp_data );
1045 /* Get Device Type */
1046 temp_data = tvb_get_letohs( tvb, offset + pathpos + 4 );
1047 proto_tree_add_item( e_key_tree, hf_enip_cpf_lir_devtype, tvb, offset + pathpos + 4, 2, TRUE);
1048 proto_item_append_text( qi, ", DevTyp: 0x%04X", temp_data );
1051 temp_data = tvb_get_letohs( tvb, offset + pathpos + 6 );
1052 proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 6, 2, "Product Code: 0x%04X", temp_data );
1054 /* Major revision/Compatibility */
1055 temp_data = tvb_get_guint8( tvb, offset + pathpos + 8 );
1057 /* Add Major revision/Compatibility tree */
1058 mcpi = proto_tree_add_text(e_key_tree, tvb, offset + pathpos + 8, 1, "Compatibility ");
1059 mc_tree = proto_item_add_subtree(mcpi, ett_mcsc);
1061 /* Add Compatibility bit info */
1062 proto_tree_add_item(mc_tree, hf_enip_ucm_fwo_comp,
1063 tvb, offset + pathpos + 8, 1, TRUE );
1065 proto_item_append_text( mcpi, "%s, Major Revision: %d",
1066 val_to_str( ( temp_data & 0x80 )>>7, enip_com_bit_vals , "" ),
1069 /* Major revision */
1070 proto_tree_add_item(mc_tree, hf_enip_ucm_fwo_mrev,
1071 tvb, offset + pathpos + 8, 1, TRUE );
1073 /* Minor revision */
1074 temp_data2 = tvb_get_guint8( tvb, offset + pathpos + 9 );
1075 proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 9, 1, "Minor Revision: %d", temp_data2 );
1077 proto_item_append_text( qi, ", V.%d.%d", ( temp_data & 0x7F ), temp_data2 );
1079 /* Increment the path pointer */
1085 /* Unsupported electronic key format */
1086 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Electronic Key Format" );
1093 /* Unsupported special segment format */
1094 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Special Segment Format" );
1102 /* Unsupported logical segment type */
1103 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Type" );
1106 } /* end of switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK ) */
1110 case CI_DATA_SEGMENT:
1112 /* Data segment, determin the logical type */
1114 switch( segment_type )
1117 case CI_DATA_SEG_SIMPLE:
1119 /* Simple data segment */
1120 ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Simple Data Segment (0x%02X)", segment_type );
1122 /* Create a sub tree */
1123 ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
1126 seg_size = tvb_get_guint8( tvb, offset + pathpos+1 )*2;
1127 proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d (words)", seg_size/2 );
1132 qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos+2, 0, "Data: " );
1134 for( i=0; i < seg_size/2; i ++ )
1136 temp_word = tvb_get_letohs( tvb, offset + pathpos+2+(i*2) );
1137 proto_item_append_text(qi, " 0x%04X", temp_word );
1140 proto_item_set_len(qi, seg_size);
1143 proto_item_set_len( ds_item, 2 + seg_size );
1144 pathpos = pathpos + 2 + seg_size;
1148 case CI_DATA_SEG_SYMBOL:
1150 /* ANSI extended symbol segment */
1151 ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Extended Symbol Segment (0x%02X)", segment_type );
1153 /* Create a sub tree */
1154 ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
1157 seg_size = tvb_get_guint8( tvb, offset + pathpos+1 );
1158 proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d", seg_size );
1163 qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos+2, 0, "Data: " );
1165 for( i=0; i < seg_size; i++ )
1167 temp_byte = tvb_get_guint8( tvb, offset + pathpos+2+i );
1168 proto_item_append_text(qi, "%c", temp_byte );
1171 proto_item_set_len(qi, seg_size);
1175 /* We have a PAD BYTE */
1176 proto_tree_add_text( ds_tree, tvb, offset + pathpos+2+i, 1, "Pad Byte (0x%02X)",
1177 tvb_get_guint8( tvb, offset + pathpos+2+i ) );
1183 proto_item_set_len( ds_item, 2 + seg_size );
1184 pathpos = pathpos + 2 + seg_size;
1189 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
1192 } /* End of switch sub-type */
1198 /* Unsupported segment type */
1199 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Segment Type" );
1202 } /* end of switch( segment_type & CI_SEGMENT_TYPE_MASK ) */
1204 } /* end of while( pathpos < path_length ) */
1206 } /* end of show_epath() */
1211 add_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length )
1213 proto_item *pi, *rrsci, *ncppi, *ar_item, *temp_item, *temp_item2;
1214 proto_tree *temp_tree;
1215 proto_tree *rrsci_tree;
1216 proto_tree *ncp_tree;
1217 proto_tree *cmd_data_tree;
1218 int req_path_size, conn_path_size, mr_req_path_size;
1220 unsigned char gen_stat;
1221 unsigned char add_stat_size;
1222 unsigned char temp_byte, route_path_size;
1223 unsigned char app_rep_size, i;
1224 int msg_req_siz, num_services, serv_offset;
1227 /* Add Service code & Request/Response tree */
1228 rrsci = proto_tree_add_text(item_tree, tvb, offset, 1, "Service: ");
1229 rrsci_tree = proto_item_add_subtree(rrsci, ett_rrsc);
1231 /* Add Request/Response */
1232 proto_tree_add_item(rrsci_tree, hf_enip_ucm_rr,
1233 tvb, offset, 1, TRUE );
1235 proto_item_append_text( rrsci, "%s (%s)",
1236 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
1237 encap_sc_vals , "Unknown Service Code (%x)"),
1238 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x80 )>>7,
1241 /* Add Service code */
1242 proto_tree_add_item(rrsci_tree, hf_enip_ucm_sc,
1243 tvb, offset, 1, TRUE );
1246 if( tvb_get_guint8( tvb, offset ) & 0x80 )
1248 /* Response message */
1250 /* Add general status */
1251 gen_stat = tvb_get_guint8( tvb, offset+2 );
1253 proto_tree_add_item(item_tree, hf_enip_ucm_genstat,
1254 tvb, offset+2, 1, TRUE );
1256 /* Add additional status size */
1257 temp_data = tvb_get_guint8( tvb, offset+3 );
1258 proto_tree_add_text( item_tree, tvb, offset+3, 1, "Additional Status Size: %d (word)", temp_data );
1260 add_stat_size = tvb_get_guint8( tvb, offset+3 )*2;
1264 /* Add additional status */
1265 pi = proto_tree_add_text( item_tree, tvb, offset+4, add_stat_size, "Additional Status:" );
1267 for( i=0; i < add_stat_size/2; i ++ )
1269 proto_item_append_text( pi, " 0x%04X", tvb_get_letohs( tvb, offset+4+(i*2) ) );
1273 /* If there is any command specific data create a sub-tree for it */
1274 if( ( item_length-4-add_stat_size ) != 0 )
1276 pi = proto_tree_add_text( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Command Specific data" );
1277 cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
1279 if( gen_stat == CI_GRC_SUCCESS )
1281 /* Success responses */
1283 if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_OPEN )
1285 /* Forward open Response (Success) */
1287 /* Display originator to target connection ID */
1288 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size );
1289 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 4, "O->T Network Connection ID: 0x%08X", temp_data );
1291 /* Display target to originator connection ID */
1292 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1293 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "T->O Network Connection ID: 0x%08X", temp_data );
1295 /* Display connection serial number */
1296 temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size+8 );
1297 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 2, "Connection Serial Number: 0x%04X", temp_data );
1299 /* Display the originator vendor id */
1300 proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+4+add_stat_size+10, 2, TRUE);
1302 /* Display the originator serial number */
1303 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+12 );
1304 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+12, 4, "Originator Serial Number: 0x%08X", temp_data );
1306 /* Display originator to target actual packet interval */
1307 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+16 );
1308 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+16, 4, "O->T API: %dms (0x%08X)", temp_data / 1000, temp_data );
1310 /* Display originator to target actual packet interval */
1311 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+20 );
1312 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+20, 4, "T->O API: %dms (0x%08X)", temp_data / 1000, temp_data );
1314 /* Display the application reply size */
1315 app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+24 ) * 2;
1316 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+24, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
1318 /* Display the Reserved byte */
1319 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+25 );
1320 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+25, 1, "Reserved: 0x%02X", temp_byte );
1322 if( app_rep_size != 0 )
1324 /* Display application Reply data */
1325 ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+26, app_rep_size, "Application Reply:" );
1327 for( i=0; i < app_rep_size; i++ )
1329 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+26+i );
1330 proto_item_append_text(ar_item, " 0x%02X", temp_byte );
1333 } /* End of if reply data */
1335 } /* End of if forward open response */
1336 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_CLOSE )
1338 /* Forward close response (Success) */
1340 /* Display connection serial number */
1341 temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size );
1342 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", temp_data );
1344 /* Display the originator vendor id */
1345 proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+4+add_stat_size+2, 2, TRUE);
1347 /* Display the originator serial number */
1348 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1349 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", temp_data );
1351 /* Display the application reply size */
1352 app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+8 ) * 2;
1353 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
1355 /* Display the Reserved byte */
1356 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
1357 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_byte );
1359 if( app_rep_size != 0 )
1361 /* Display application Reply data */
1362 ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+10, app_rep_size, "Application Reply:" );
1364 for( i=0; i < app_rep_size; i ++ )
1366 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+10+i );
1367 proto_item_append_text(ar_item, " 0x%02X", temp_byte );
1370 } /* End of if reply data */
1372 } /* End of if forward close response */
1373 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_UNCON_SEND )
1375 /* Unconnected send response (Success) */
1377 /* Display service response data */
1378 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1380 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_MULT_SERV_PACK )
1382 /* Multiple Service Reply (Success)*/
1384 /* Add number of replies */
1385 num_services = tvb_get_letohs( tvb, offset+4+add_stat_size );
1386 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Number of Replies: %d", num_services );
1389 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+add_stat_size+4, num_services*2, "Offsets: " );
1391 for( i=0; i < num_services; i++ )
1395 serv_offset = tvb_get_letohs( tvb, offset+6+add_stat_size+(i*2) );
1397 if( i == (num_services-1) )
1399 /* Last service to add */
1400 proto_item_append_text(temp_item, "%d", serv_offset );
1401 serv_length = item_length-add_stat_size-serv_offset-4;
1405 proto_item_append_text(temp_item, "%d, ", serv_offset );
1406 serv_length = tvb_get_letohs( tvb, offset+6+add_stat_size+((i+1)*2) ) - serv_offset;
1409 temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+4, serv_length, "Service Reply #%d", i+1 );
1410 temp_tree = proto_item_add_subtree( temp_item2, ett_mult_ser );
1411 add_cip_data( temp_tree, tvb, offset+serv_offset+4, serv_length );
1413 } /* End if Multiple service Packet */
1414 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_GET_ATT_LIST )
1416 /* Get Attribute List Reply (Success)*/
1420 /* Add Attribute Count */
1421 att_count = tvb_get_letohs( tvb, offset+4+add_stat_size );
1422 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Attribute Count: %d", att_count );
1425 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+6+add_stat_size, item_length-6-add_stat_size, "Data: " );
1427 } /* End if Multiple service Packet */
1431 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1432 } /* end of check service code */
1437 /* Error responses */
1439 if( ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_OPEN ) ||
1440 ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_CLOSE ) )
1442 /* Forward open and forward close error response look the same */
1444 /* Display connection serial number */
1445 temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size );
1446 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", temp_data );
1448 /* Display the originator vendor id */
1449 proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+4+add_stat_size+2, 2, TRUE);
1451 /* Display the originator serial number */
1452 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1453 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", temp_data );
1455 /* Display remaining path size */
1456 temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+8 );
1457 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Remaining Path Size: %d", temp_data );
1459 /* Display reserved data */
1460 temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
1461 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_data );
1463 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_UNCON_SEND )
1465 /* Unconnected send response (Unsuccess) */
1467 /* Display remaining path size */
1468 temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size);
1469 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 1, "Remaining Path Size: %d", temp_data );
1474 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1477 } /* end of if-else( CI_CRC_SUCCESS ) */
1479 } /* End of if command-specific data present */
1481 } /* End of if reply */
1487 req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
1488 proto_tree_add_text( item_tree, tvb, offset+1, 1, "Request Path Size: %d (words)", req_path_size/2 );
1491 pi = proto_tree_add_text(item_tree, tvb, offset+2, req_path_size, "Request Path: ");
1492 show_epath( tvb, pi, offset+2, req_path_size );
1494 /* If there is any command specific data creat a sub-tree for it */
1495 if( (item_length-req_path_size-2) != 0 )
1498 pi = proto_tree_add_text( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Command Specific Data" );
1499 cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
1501 /* Check what service code that recived */
1503 if( tvb_get_guint8( tvb, offset ) == SC_FWD_OPEN )
1505 /* Forward open Request*/
1507 /* Display the priority/tick timer */
1508 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
1509 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
1511 /* Display the time-out ticks */
1512 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
1513 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
1515 /* Display the actual time out */
1516 temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
1517 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
1519 /* Display originator to taget connection ID */
1520 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+2 );
1521 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 4, "O->T Network Connection ID: 0x%08X", temp_data );
1523 /* Display target to originator connection ID */
1524 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
1525 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "T->O Network Connection ID: 0x%08X", temp_data );
1527 /* Display connection serial number */
1528 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+10 );
1529 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 2, "Connection Serial Number: 0x%04X", temp_data );
1531 /* Display the originator vendor id */
1532 proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+2+req_path_size+12, 2, TRUE);
1534 /* Display the originator serial number */
1535 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+14 );
1536 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+14, 4, "Originator Serial Number: 0x%08X", temp_data );
1538 /* Display the timeout multiplier */
1539 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+18 );
1540 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+18, 1, "Connection Timeout Multiplier: %s (%d)", val_to_str( temp_data, enip_con_time_mult_vals , "Reserved" ), temp_data );
1542 /* Put out an indicator for the reserved bytes */
1543 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+19, 3, "Reserved Data" );
1545 /* Display originator to target requested packet interval */
1546 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+22 );
1547 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+22, 4, "O->T RPI: %dms (0x%08X)", temp_data / 1000, temp_data );
1549 /* Display originator to target network connection patameterts, in a tree */
1550 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+26 );
1551 ncppi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+26, 2, "O->T Network Connection Parameters: 0x%04X", temp_data );
1552 ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
1554 /* Add the data to the tree */
1555 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_own,
1556 tvb, offset+2+req_path_size+26, 2, TRUE );
1557 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_typ,
1558 tvb, offset+2+req_path_size+26, 2, TRUE );
1559 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_prio,
1560 tvb, offset+2+req_path_size+26, 2, TRUE );
1561 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_fixed_var,
1562 tvb, offset+2+req_path_size+26, 2, TRUE );
1563 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_con_size,
1564 tvb, offset+2+req_path_size+26, 2, TRUE );
1566 /* Display target to originator requested packet interval */
1567 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+28 );
1568 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+28, 4, "T->O RPI: %dms (0x%08X)", temp_data / 1000, temp_data );
1570 /* Display target to originator network connection patameterts, in a tree */
1571 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+32 );
1572 ncppi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+32, 2, "T->O Network Connection Parameters: 0x%04X", temp_data );
1573 ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
1575 /* Add the data to the tree */
1576 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_own,
1577 tvb, offset+2+req_path_size+32, 2, TRUE );
1578 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_typ,
1579 tvb, offset+2+req_path_size+32, 2, TRUE );
1580 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_prio,
1581 tvb, offset+2+req_path_size+32, 2, TRUE );
1582 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_fixed_var,
1583 tvb, offset+2+req_path_size+32, 2, TRUE );
1584 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_con_size,
1585 tvb, offset+2+req_path_size+32, 2, TRUE );
1587 /* Transport type/trigger */
1588 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+34 );
1589 proto_tree_add_text( cmd_data_tree, tvb, offset+6+req_path_size+34, 1, "Transport Type/Trigger: 0x%02X", temp_data );
1592 conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+35 )*2;
1593 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+35, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
1596 pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+36, conn_path_size, "Connection Path: ");
1597 show_epath( tvb, pi, offset+2+req_path_size+36, conn_path_size );
1599 else if( tvb_get_guint8( tvb, offset ) == SC_FWD_CLOSE )
1601 /* Forward Close Request */
1603 /* Display the priority/tick timer */
1604 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
1605 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
1607 /* Display the time-out ticks */
1608 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
1609 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
1611 /* Display connection serial number */
1612 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
1613 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Connection Serial Number: 0x%04X", temp_data );
1615 /* Display the originator vendor id */
1616 proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+2+req_path_size+4, 2, TRUE);
1618 /* Display the originator serial number */
1619 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
1620 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "Originator Serial Number: 0x%08X", temp_data );
1622 /* Add the path size */
1623 conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+10 )*2;
1624 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
1626 /* Add the reserved byte */
1627 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size+11 );
1628 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+11, 1, "Reserved: 0x%02X", temp_byte );
1631 pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+12, conn_path_size, "Connection Path: ");
1632 show_epath( tvb, pi, offset+2+req_path_size+12, conn_path_size );
1634 } /* End of forward close */
1635 else if( tvb_get_guint8( tvb, offset ) == SC_UNCON_SEND )
1637 /* Unconnected send */
1639 /* Display the priority/tick timer */
1640 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
1641 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
1643 /* Display the time-out ticks */
1644 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
1645 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
1647 /* Message request size */
1648 msg_req_siz = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
1649 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Message Request Size: 0x%04X", msg_req_siz );
1651 /* Message Request */
1652 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4, msg_req_siz, "Message Request" );
1653 temp_tree = proto_item_add_subtree(temp_item, ett_mes_req );
1656 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+4 );
1657 proto_tree_add_text( temp_tree, tvb, offset+2+req_path_size+4, 1, "Service: %s (0x%02X)", val_to_str( temp_data, encap_sc_vals , "" ), temp_data );
1659 /* MR - Request path Size */
1660 mr_req_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+5 )*2;
1661 proto_tree_add_text( temp_tree, tvb, offset+2+req_path_size+5, 1, "Request Path Size: %d (words)", mr_req_path_size/2 );
1664 temp_item = proto_tree_add_text(temp_tree, tvb, offset+2+req_path_size+6, mr_req_path_size, "Request Path: ");
1665 show_epath( tvb, temp_item, offset+2+req_path_size+6, mr_req_path_size );
1667 /* MR - Request data */
1668 if( ( msg_req_siz-2-mr_req_path_size ) != 0 )
1670 add_byte_array_text_to_proto_tree( temp_tree, tvb, offset+2+req_path_size+6+mr_req_path_size, msg_req_siz-2-mr_req_path_size, "Request Data: " );
1673 if( msg_req_siz % 2 )
1676 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4+msg_req_siz, 1, "Pad Byte (0x%02X)",
1677 tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz ) );
1678 msg_req_siz++; /* include the padding */
1681 /* Route Path Size */
1682 route_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz )*2;
1683 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4+msg_req_siz, 1, "Route Path Size: %d (words)", route_path_size/2 );
1686 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+5+msg_req_siz, 1, "Reserved (0x%02X)",
1687 tvb_get_guint8( tvb, offset+2+req_path_size+5+msg_req_siz ) );
1690 temp_item = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+6+msg_req_siz, route_path_size, "Route Path");
1691 show_epath( tvb, temp_item, offset+2+req_path_size+6+msg_req_siz, route_path_size );
1693 } /* End if unconnected send */
1694 else if( tvb_get_guint8( tvb, offset ) == SC_MULT_SERV_PACK )
1696 /* Multiple service packet */
1698 /* Add number of services */
1699 num_services = tvb_get_letohs( tvb, offset+2+req_path_size );
1700 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Number of Services: %d", num_services );
1703 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, num_services*2, "Offsets: " );
1705 for( i=0; i < num_services; i++ )
1709 serv_offset = tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) );
1711 if( i == (num_services-1) )
1713 /* Last service to add */
1714 serv_length = item_length-2-req_path_size-serv_offset;
1715 proto_item_append_text(temp_item, "%d", serv_offset );
1719 serv_length = tvb_get_letohs( tvb, offset+4+req_path_size+((i+1)*2) ) - serv_offset;
1720 proto_item_append_text(temp_item, "%d, ", serv_offset );
1723 temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+6, serv_length, "Service Packet #%d", i+1 );
1724 temp_tree = proto_item_add_subtree( temp_item2, ett_mult_ser );
1725 add_cip_data( temp_tree, tvb, offset+serv_offset+6, serv_length );
1727 } /* End if Multiple service Packet */
1728 else if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
1730 /* Get attribute list request */
1734 /* Add number of services */
1735 att_count = tvb_get_letohs( tvb, offset+2+req_path_size );
1736 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Attribute Count: %d", att_count );
1738 /* Add Attribute List */
1739 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, att_count*2, "Attribute List: " );
1741 for( i=0; i < att_count; i++ )
1743 if( i == (att_count-1) )
1744 proto_item_append_text(temp_item, "%d",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
1746 proto_item_append_text(temp_item, "%d, ",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
1749 } /* End of Get attribute list request */
1753 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Data: " );
1754 } /* End of check service code */
1756 } /* End of if command-specific data present */
1758 } /* end of if-else( request ) */
1760 } /* end of add_cip_data() */
1765 show_cdf( int encap_service, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset )
1767 proto_item *temp_item, *ri, *ci;
1768 proto_item *sockaddr_item;
1769 proto_tree *temp_tree, *cip_tree, *item_tree, *sockaddr_tree;
1770 int temp_data, item_count, item_length, item, i;
1772 unsigned char name_length;
1774 /* Show Common Data Format sub tree */
1775 item_count = tvb_get_letohs( tvb, offset );
1776 ri = proto_tree_add_text( tree, tvb, offset, 2, "Item Count: %d", item_count );
1777 cip_tree = proto_item_add_subtree(ri, ett_cip);
1779 while( item_count-- )
1781 /* Add item type tree */
1782 ci = proto_tree_add_item(cip_tree, hf_enip_cpf_typeid, tvb, offset+2, 2, TRUE );
1783 item_tree = proto_item_add_subtree(ci, ett_cpf);
1785 /* Add length field */
1786 temp_data = tvb_get_letohs( tvb, offset+4 );
1787 proto_tree_add_text( item_tree, tvb, offset+4, 2, "Length: %d", temp_data );
1789 item = tvb_get_letohs( tvb, offset+2 );
1790 item_length = tvb_get_letohs( tvb, offset+4 );
1794 /* Add item data field */
1798 case CONNECTION_BASED:
1800 /* Add Connection identifier */
1801 proto_tree_add_text( item_tree, tvb, offset+6, 4, "Connection Identifier: 0x%04X", tvb_get_letohl( tvb, offset + 6 ) );
1804 case UNCONNECTED_MSG:
1806 /* Add CIP data tree*/
1807 add_cip_data( item_tree, tvb, offset+6, item_length );
1811 case CONNECTION_TRANSPORT:
1813 if( encap_service == SEND_UNIT_DATA )
1816 ** If the encapsulation service is SendUnit Data, this is a
1817 ** encapsulated connected message
1820 /* Add sequence count ( Transport Class 1,2,3 )*/
1821 proto_tree_add_text( item_tree, tvb, offset+6, 2, "Sequence Count: 0x%04X", tvb_get_letohs( tvb, offset+6 ) );
1823 /* Add CIP data tree */
1824 add_cip_data( item_tree, tvb, offset+8, item_length-2 );
1829 add_byte_array_text_to_proto_tree( item_tree, tvb, offset+6, item_length, "Data: " );
1831 } /* End of if send unit data */
1836 case LIST_IDENTITY_RESP:
1838 /* Encapsulation version */
1839 temp_data = tvb_get_letohs( tvb, offset+6 );
1840 proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation Version: %d", temp_data );
1842 /* Socket Address */
1843 sockaddr_item = proto_tree_add_text( item_tree, tvb, offset+8, 16, "Socket Address");
1844 sockaddr_tree = proto_item_add_subtree( sockaddr_item, ett_sockadd );
1846 /* Socket address struct - sin_family */
1847 proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinfamily,
1848 tvb, offset+8, 2, FALSE );
1850 /* Socket address struct - sin_port */
1851 proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinport,
1852 tvb, offset+10, 2, FALSE );
1854 /* Socket address struct - sin_address */
1855 proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinaddr,
1856 tvb, offset+12, 4, FALSE );
1858 /* Socket address struct - sin_zero */
1859 proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinzero,
1860 tvb, offset+16, 8, FALSE );
1863 proto_tree_add_item(item_tree, hf_enip_vendors,
1864 tvb, offset+24, 2, TRUE );
1867 proto_tree_add_item(item_tree, hf_enip_cpf_lir_devtype,
1868 tvb, offset+26, 2, TRUE );
1871 proto_tree_add_item(item_tree, hf_enip_cpf_lir_prodcode,
1872 tvb, offset+28, 2, TRUE );
1875 temp_data = tvb_get_letohs( tvb, offset+30 );
1876 proto_tree_add_text( item_tree, tvb, offset+30, 2, "Revision: v.%d.%02d", temp_data & 0xFF, ( temp_data & 0xFF00 ) >> 8 );
1879 proto_tree_add_item(item_tree, hf_enip_cpf_lir_status,
1880 tvb, offset+32, 2, TRUE );
1883 proto_tree_add_item(item_tree, hf_enip_cpf_lir_sernbr,
1884 tvb, offset+34, 4, TRUE );
1886 /* Product Name Length */
1887 proto_tree_add_item(item_tree, hf_enip_cpf_lir_namelength,
1888 tvb, offset+38, 1, TRUE );
1890 /* Get the lenth of the name */
1891 name_length = tvb_get_guint8( tvb, offset+38 );
1893 /* Product Name Length */
1894 proto_tree_add_item(item_tree, hf_enip_cpf_lir_name,
1895 tvb, offset+39, name_length, TRUE );
1897 /* Product Name Length */
1898 proto_tree_add_item(item_tree, hf_enip_cpf_lir_state,
1899 tvb, offset+name_length+39, 1, TRUE );
1903 case SOCK_ADR_INFO_OT:
1904 case SOCK_ADR_INFO_TO:
1906 /* Socket address struct - sin_family */
1907 proto_tree_add_item(item_tree, hf_enip_cpf_lir_sinfamily,
1908 tvb, offset+6, 2, FALSE );
1910 /* Socket address struct - sin_port */
1911 proto_tree_add_item(item_tree, hf_enip_cpf_lir_sinport,
1912 tvb, offset+8, 2, FALSE );
1914 /* Socket address struct - sin_address */
1915 proto_tree_add_item(item_tree, hf_enip_cpf_lir_sinaddr,
1916 tvb, offset+10, 4, FALSE );
1918 /* Socket address struct - sin_zero */
1919 proto_tree_add_item( item_tree, hf_enip_cpf_lir_sinzero,
1920 tvb, offset+14, 8, FALSE );
1925 proto_tree_add_item(item_tree, hf_enip_cpf_sat_connid,
1926 tvb, offset+6, 4, TRUE );
1928 proto_tree_add_item(item_tree, hf_enip_cpf_sat_seqnum,
1929 tvb, offset+10, 4, TRUE );
1931 /* Add info to column */
1933 if(check_col(pinfo->cinfo, COL_INFO))
1935 col_clear(pinfo->cinfo, COL_INFO);
1937 col_add_fstr(pinfo->cinfo, COL_INFO,
1938 "Connection: ID=0x%08X, SEQ=%010d",
1939 tvb_get_letohl( tvb, offset+6 ),
1940 tvb_get_letohl( tvb, offset+10 ) );
1945 case LIST_SERVICES_RESP:
1947 /* Encapsulation version */
1948 temp_data = tvb_get_letohs( tvb, offset+6 );
1949 proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation Version: %d", temp_data );
1951 /* Capability flags */
1952 temp_data = tvb_get_letohs( tvb, offset+8 );
1953 temp_item = proto_tree_add_text(item_tree, tvb, offset+8, 2, "Capability Flags: 0x%04X", temp_data );
1954 temp_tree = proto_item_add_subtree(temp_item, ett_lsrcf);
1956 proto_tree_add_item(temp_tree, hf_enip_cpf_lsr_tcp,
1957 tvb, offset+8, 2, TRUE );
1958 proto_tree_add_item(temp_tree, hf_enip_cpf_lsr_udp,
1959 tvb, offset+8, 2, TRUE );
1961 /* Name of service */
1962 temp_item = proto_tree_add_text( item_tree, tvb, offset+10, 16, "Name Of Service: " );
1964 for( i=0; i<16; i++ )
1966 temp_char = tvb_get_guint8( tvb, offset+10+i );
1968 if( temp_char == 0 )
1971 proto_item_append_text(temp_item, "%c", temp_char );
1978 add_byte_array_text_to_proto_tree( item_tree, tvb, offset+6, item_length, "Data: " );
1981 } /* end of switch( item type ) */
1983 } /* end of if( item length ) */
1985 offset = offset + item_length + 4;
1987 } /* end of while( item count ) */
1989 } /* end of show_cdf() */
1994 classify_packet(packet_info *pinfo)
1996 /* see if nature of packets can be derived from src/dst ports */
1997 /* if so, return as found */
1998 if ( ( ENIP_ENCAP_PORT == pinfo->srcport && ENIP_ENCAP_PORT != pinfo->destport ) ||
1999 ( ENIP_ENCAP_PORT != pinfo->srcport && ENIP_ENCAP_PORT == pinfo->destport ) ) {
2000 if ( ENIP_ENCAP_PORT == pinfo->srcport )
2001 return RESPONSE_PACKET;
2002 else if ( ENIP_ENCAP_PORT == pinfo->destport )
2003 return REQUEST_PACKET;
2005 /* else, cannot classify */
2006 return CANNOT_CLASSIFY;
2011 /* Code to actually dissect the packets */
2013 dissect_cipencap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2016 guint16 encap_cmd, encap_data_length;
2018 char pkt_type_str[9] = "";
2021 /* Set up structures needed to add the protocol subtree and manage it */
2022 proto_item *ti, *encaph, *csf;
2023 proto_tree *cipencap_tree, *headertree, *csftree;
2025 /* An ENIP packet is at least 4 bytes long - we need the command type. */
2026 if (!tvb_bytes_exist(tvb, 0, 4))
2029 /* Get the command type and see if it's valid. */
2030 encap_cmd = tvb_get_letohs( tvb, 0 );
2031 cmd_string = match_strval(encap_cmd, encap_cmd_vals);
2032 if (cmd_string == NULL)
2033 return 0; /* not a known command */
2035 /* Make entries in Protocol column and Info column on summary display */
2036 if (check_col(pinfo->cinfo, COL_PROTOCOL))
2037 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENIP");
2039 if(check_col(pinfo->cinfo, COL_INFO))
2041 packet_type = classify_packet(pinfo);
2043 switch ( packet_type )
2045 case REQUEST_PACKET:
2046 strcpy(pkt_type_str, "Request");
2049 case RESPONSE_PACKET:
2050 strcpy(pkt_type_str, "Response");
2054 strcpy(pkt_type_str, "Unknown");
2057 col_add_fstr(pinfo->cinfo, COL_INFO,
2058 "%s: %s, Session=0x%08X",
2059 pkt_type_str, cmd_string, tvb_get_letohl( tvb, 4 ) );
2060 } /* end of if( col exists ) */
2062 /* In the interest of speed, if "tree" is NULL, don't do any work not
2063 necessary to generate protocol tree items. */
2066 /* create display subtree for the protocol */
2067 ti = proto_tree_add_item(tree, proto_cipencap, tvb, 0, -1, FALSE);
2069 cipencap_tree = proto_item_add_subtree(ti, ett_cipencap);
2071 /* Add encapsulation header tree */
2072 encaph = proto_tree_add_text( cipencap_tree, tvb, 0, 24, "Encapsulation Header");
2073 headertree = proto_item_add_subtree(encaph, ett_cipencaph);
2075 /* CIP header information */
2076 proto_tree_add_uint(headertree, hf_enip_command, tvb, 0, 2, encap_cmd);
2078 encap_data_length = tvb_get_letohs( tvb, 2 );
2079 proto_tree_add_text( headertree, tvb, 2, 2, "Length: %u", encap_data_length );
2081 proto_tree_add_text( headertree, tvb, 4, 4, "Session Handle: 0x%08X",
2082 tvb_get_letohl( tvb, 4 ) );
2084 status = tvb_get_letohl( tvb, 8 );
2085 proto_tree_add_text( headertree, tvb, 8, 4, "Status: %s (0x%08X)",
2086 val_to_str( status, encap_status_vals,
2087 "Unknown Status Code" ),
2090 add_byte_array_text_to_proto_tree( headertree, tvb, 12, 8, "Sender context: " );
2092 proto_tree_add_text( headertree, tvb, 20, 4, "Options: 0x%08X",
2093 tvb_get_letohl( tvb, 20 ) );
2095 /* Command specific data - create tree */
2096 if( encap_data_length )
2098 /* The packet have some command specific data, buid a sub tree for it */
2100 csf = proto_tree_add_text( cipencap_tree, tvb, 24, encap_data_length,
2101 "Command Specific Data");
2103 csftree = proto_item_add_subtree(csf, ett_csf);
2108 show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
2112 show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
2116 show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
2119 case LIST_INTERFACES:
2120 show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
2123 case REGISTER_SESSION:
2124 proto_tree_add_text( csftree, tvb, 24, 2, "Protocol Version: 0x%04X",
2125 tvb_get_letohs( tvb, 24 ) );
2127 proto_tree_add_text( csftree, tvb, 26, 2, "Option Flags: 0x%04X",
2128 tvb_get_letohs( tvb, 26 ) );
2132 case UNREGISTER_SESSION:
2136 case SEND_UNIT_DATA:
2137 proto_tree_add_item(csftree, hf_enip_ifacehnd, tvb, 24, 4, TRUE);
2139 proto_tree_add_text( csftree, tvb, 28, 2, "Timeout: %u",
2140 tvb_get_letohs( tvb, 28 ) );
2142 show_cdf( encap_cmd, tvb, pinfo, csftree, 30 );
2145 case INDICATE_STATUS:
2149 /* Can not decode - Just show the data */
2150 add_byte_array_text_to_proto_tree( headertree, tvb, 24, encap_data_length, "Encap Data: " );
2153 } /* end of switch() */
2155 } /* end of if( encapsulated data ) */
2159 return tvb_length(tvb);
2160 } /* end of dissect_cipencap() */
2163 /* Code to actually dissect the io packets*/
2165 dissect_enipio(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2167 /* Set up structures needed to add the protocol subtree and manage it */
2169 proto_tree *cipencap_tree;
2171 /* Make entries in Protocol column and Info column on summary display */
2172 if (check_col(pinfo->cinfo, COL_PROTOCOL))
2173 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENIP");
2175 /* In the interest of speed, if "tree" is NULL, don't do any work not
2176 necessary to generate protocol tree items. */
2179 /* create display subtree for the protocol */
2180 ti = proto_tree_add_item(tree, proto_cipencap, tvb, 0, -1, FALSE);
2182 cipencap_tree = proto_item_add_subtree(ti, ett_cipencap);
2184 show_cdf( 0xFFFF, tvb, pinfo, cipencap_tree, 0 );
2187 } /* end of dissect_enipio() */
2190 /* Register the protocol with Ethereal */
2192 /* this format is require because a script is used to build the C function
2193 that calls all the protocol registration.
2197 proto_register_cipencap(void)
2200 /* Setup list of header fields lengthSee Section 1.6.1 for details*/
2201 static hf_register_info hf[] = {
2203 { "Command", "enip.command",
2204 FT_UINT16, BASE_HEX, VALS(encap_cmd_vals), 0,
2205 "Encapsulation command", HFILL }
2208 /* Encapsulated data headers */
2209 /* Common Packet Format */
2210 { &hf_enip_cpf_typeid,
2211 { "Type ID", "enip.cpf.typeid",
2212 FT_UINT16, BASE_HEX, VALS(cdf_type_vals), 0,
2213 "Type of encapsulated item", HFILL }
2217 { &hf_enip_ifacehnd,
2218 { "Interface Handle", "enip.cpf.rr.ifacehnd",
2219 FT_UINT32, BASE_HEX, NULL, 0,
2220 "Interface handle", HFILL }
2223 /* Unconnected message */
2225 { "Request/Response", "enip.cip.rr",
2226 FT_UINT8, BASE_HEX, VALS(encap_sc_rr), 0x80,
2227 "Request or Response message", HFILL }
2230 { "Service", "enip.cip.sc",
2231 FT_UINT8, BASE_HEX, VALS(encap_sc_vals), 0x7F,
2232 "CIP Service code", HFILL }
2234 { &hf_enip_ucm_path,
2235 { "Request Path", "enip.cip.path",
2236 FT_BYTES, BASE_HEX, NULL, 0,
2237 "Request path", HFILL }
2239 { &hf_enip_ucm_genstat,
2240 { "General Status", "enip.cip.genstat",
2241 FT_UINT8, BASE_HEX, VALS(encap_cip_gs_vals), 0,
2242 "General Status", HFILL }
2245 /* List identity response */
2246 { &hf_enip_cpf_lir_sinfamily,
2247 { "sin_family", "enip.lir.sinfamily",
2248 FT_UINT16, BASE_DEC, NULL, 0,
2249 "Socket Address Sin Family", HFILL }
2251 { &hf_enip_cpf_lir_sinport,
2252 { "sin_port", "enip.lir.sinport",
2253 FT_UINT16, BASE_DEC, NULL, 0,
2254 "Socket Address Sin Port", HFILL }
2256 { &hf_enip_cpf_lir_sinaddr,
2257 { "sin_addr", "enip.lir.sinaddr",
2258 FT_IPv4, BASE_HEX, NULL, 0,
2259 "Socket Address Sin Addr", HFILL }
2261 { &hf_enip_cpf_lir_sinzero,
2262 { "sin_zero", "enip.lir.sinzero",
2263 FT_BYTES, BASE_HEX, NULL, 0,
2264 "Socket Address Sin Zero", HFILL }
2266 { &hf_enip_cpf_lir_devtype,
2267 { "Device Type", "enip.lir.devtype",
2268 FT_UINT16, BASE_DEC, VALS(encap_cip_devtype_vals), 0,
2269 "Device Type", HFILL }
2271 { &hf_enip_cpf_lir_prodcode,
2272 { "Product Code", "enip.lir.prodcode",
2273 FT_UINT16, BASE_DEC, NULL, 0,
2274 "Product Code", HFILL }
2276 { &hf_enip_cpf_lir_status,
2277 { "Status", "enip.lir.status",
2278 FT_UINT16, BASE_HEX, NULL, 0,
2281 { &hf_enip_cpf_lir_sernbr,
2282 { "Serial Number", "enip.lir.ser",
2283 FT_UINT32, BASE_HEX, NULL, 0,
2284 "Serial Number", HFILL }
2286 { &hf_enip_cpf_lir_namelength,
2287 { "Product Name Length", "enip.lir.namelength",
2288 FT_UINT8, BASE_DEC, NULL, 0,
2289 "Product Name Length", HFILL }
2291 { &hf_enip_cpf_lir_name,
2292 { "Product Name", "enip.lir.name",
2293 FT_STRING, BASE_NONE, NULL, 0,
2294 "Product Name", HFILL }
2296 { &hf_enip_cpf_lir_state,
2297 { "State", "enip.lir.state",
2298 FT_UINT8, BASE_HEX, NULL, 0,
2301 /* Vendor ID number */
2303 { "Vendor ID", "enip.vnd",
2304 FT_UINT16, BASE_HEX, VALS(encap_cip_vendor_vals), 0,
2305 "Vendor ID number", HFILL }
2307 { &hf_enip_ucm_fwo_comp,
2308 { "Compatibility", "enip.cip.fwo.cmp",
2309 FT_UINT8, BASE_HEX, VALS(enip_com_bit_vals), 0x80,
2310 "Compatibility bit", HFILL }
2312 { &hf_enip_ucm_fwo_mrev,
2313 { "Major Revision", "enip.cip.fwo.mrev",
2314 FT_UINT8, BASE_DEC, NULL, 0x7F,
2315 "Major Revision", HFILL }
2317 { &hf_enip_ucm_fwo_con_size,
2318 { "Connection Size", "enip.cip.fwo.consize",
2319 FT_UINT16, BASE_DEC, NULL, 0x01FF,
2320 "Connection size", HFILL }
2322 { &hf_enip_ucm_fwo_fixed_var,
2323 { "Connection Size Type", "enip.cip.fwo.f_v",
2324 FT_UINT16, BASE_DEC, VALS(enip_con_fw_vals), 0x0200,
2325 "Fixed or variable connection size", HFILL }
2327 { &hf_enip_ucm_fwo_prio,
2328 { "Priority", "enip.cip.fwo.prio",
2329 FT_UINT16, BASE_DEC, VALS(enip_con_prio_vals), 0x0C00,
2330 "Connection priority", HFILL }
2332 { &hf_enip_ucm_fwo_typ,
2333 { "Connection Type", "enip.cip.fwo.typ",
2334 FT_UINT16, BASE_DEC, VALS(enip_con_type_vals), 0x6000,
2335 "Connection type", HFILL }
2337 { &hf_enip_ucm_fwo_own,
2338 { "Owner", "enip.cip.fwo.own",
2339 FT_UINT16, BASE_DEC, VALS(enip_con_owner_vals), 0x8000,
2340 "Redundant owner bit", HFILL }
2342 /* Sequenced Address Type */
2343 { &hf_enip_cpf_sat_connid,
2344 { "Connection ID", "enip.sat.connid",
2345 FT_UINT32, BASE_HEX, NULL, 0,
2346 "Connection ID from forward open reply", HFILL }
2348 { &hf_enip_cpf_sat_seqnum,
2349 { "Sequence Number", "enip.sat.seq",
2350 FT_UINT32, BASE_DEC, NULL, 0,
2351 "Sequence Number", HFILL }
2353 { &hf_enip_cpf_lsr_tcp,
2354 { "Supports CIP Encapsultion via TCP", "enip.ls.tcp",
2355 FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0020,
2356 "Supports CIP Encapsultion via TCP", HFILL }
2358 { &hf_enip_cpf_lsr_udp,
2359 { "Supports CIP Class 0 or 1 via UDP", "enip.ls.udp",
2360 FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0100,
2361 "Supports CIP Class 0 or 1 via UDP", HFILL }
2367 /* Setup protocol subtree array */
2368 static gint *ett[] = {
2389 /* Register the protocol name and description */
2390 proto_cipencap = proto_register_protocol("EtherNet/IP (Industrial Protocol)",
2393 /* Required function calls to register the header fields and subtrees used */
2394 proto_register_field_array(proto_cipencap, hf, array_length(hf));
2395 proto_register_subtree_array(ett, array_length(ett));
2397 } /* end of proto_register_cipencap() */
2400 /* If this dissector uses sub-dissector registration add a registration routine.
2401 This format is required because a script is used to find these routines and
2402 create the code that calls these routines.
2405 proto_reg_handoff_cipencap(void)
2407 dissector_handle_t cipencap_handle;
2408 dissector_handle_t enipio_handle;
2410 /* Register for encapsulated CIP data, using both TCP/UDP */
2411 cipencap_handle = new_create_dissector_handle(dissect_cipencap, proto_cipencap);
2412 dissector_add("tcp.port", ENIP_ENCAP_PORT, cipencap_handle);
2413 dissector_add("udp.port", ENIP_ENCAP_PORT, cipencap_handle);
2415 /* Register for IO data over UDP */
2416 enipio_handle = create_dissector_handle(dissect_enipio, proto_cipencap);
2417 dissector_add("udp.port", ENIP_IO_PORT, enipio_handle);
2419 } /* end of proto_reg_handoff_cipencap() */