1 /* packet-epl.c
2  * Routines for "Ethernet POWERLINK 2.0" dissection
3  * (Ethernet POWERLINK V2.0 Communication Profile Specification Draft Standard Version 1.2.0)
4  *
5  * Copyright (c) 2006: Zurich University of Applied Sciences Winterthur (ZHW)
6  *                     Institute of Embedded Systems (InES)
7  *                     http://ines.zhwin.ch
8  *
9  *                     - Dominic Bechaz <bdo[AT]zhwin.ch>
10  *                     - Damir Bursic <bum[AT]zhwin.ch>
11  *                     - David Buechi <bhd[AT]zhwin.ch>
12  *
13  * Copyright (c) 2007: SYS TEC electronic GmbH
14  *                     http://www.systec-electronic.com
get_credentials()15  *                     - Daniel Krueger <daniel.krueger[AT]systec-electronic.com>
16  *
17  * Copyright (c) 2013: B&R Industrieelektronik GmbH
18  *                     http://www.br-automation.com
19  *
20  *                     - Christoph Schlosser <christoph.schlosser[AT]br-automation.com>
21  *                     - Lukas Emersberger <lukas.emersberger[AT]br-automation.com>
22  *                     - Josef Baumgartner <josef.baumgartner[AT]br-automation.com>
23  *                     - Roland Knall <roland.knall[AT]br-automation.com>
24  *                       - Extended to be similair in handling as to B&R plugin
25  *                       - Multiple SOD Read/Write dissection
26  *                       - Include AInv message type
27  *                       - Straighten text formatting
28  *                       - Remove unneccessary if(tree) checks
29  *
30  * Copyright (c) 2017: Karlsruhe Institute of Technology (KIT)
31  *                     Institute for Anthropomatics and Robotics (IAR)
32  *                     Intelligent Process Control and Robotics (IPR)
33  *                     http://rob.ipr.kit.edu/
34  *
35  *                     - Ahmad Fatoum <ahmad[AT]a3f.at>
36  *                       - ObjectMappings now used for dissecting PDOs
37  *                       - XDD/EDS files can be read for name/type information
38  *
39  * Copyright (c) 2020: B&R Industrial Automation GmbH
40  *                     http://www.br-automation.com
41  *
42  *                     - Christian Krump <christian.krump[AT]br-automation.com>
43  *                       - extended decoding of ring redundancy flags in the SOA frame
44  *                       - put a boolean hotfield to all available EPL message types
45  *                       - modified timestamp format of errorcodelist entries
46  *                       - append summary info with additional flag information
47  *                       - usage of segment size during sdo (write by index) payload decoding process
48  *                       - set mapping-sections of sdo objects one level lower
49  *                       - dissect some additional (cable redundancy specific) flags
50  *
51  * A dissector for:
52  * Wireshark - Network traffic analyzer
53  * By Gerald Combs <gerald@wireshark.org>
54  * Copyright 1999 Gerald Combs
55  *
56  * SPDX-License-Identifier: GPL-2.0-or-later
57  */
58 
59 #include "config.h"
60 
61 #include "packet-epl.h"
62 
63 #include <epan/conversation.h>
64 #include <epan/packet.h>
65 #include <epan/etypes.h>
66 #include <epan/prefs.h>
67 #include <epan/expert.h>
68 #include <epan/reassemble.h>
69 #include <epan/proto_data.h>
70 #include <epan/uat.h>
71 #include <wsutil/strtoi.h>
72 #include <wsutil/file_util.h>
73 #include <wsutil/report_message.h>
74 #include <wsutil/wslog.h>
75 #include <string.h>
76 
77 #ifdef HAVE_LIBXML2
78 	#define IF_LIBXML(x) x
79 #else
80 	#define IF_LIBXML(x)
81 #endif
82 
83 void proto_register_epl(void);
84 void proto_reg_handoff_epl(void);
85 
86 #ifndef UDP_PORT_EPL
87 #define UDP_PORT_EPL            3819
88 #endif
89 
90 /* Allow heuristic dissection and ASND manufacturer dissection */
91 static heur_dissector_list_t heur_epl_subdissector_list;
92 static heur_dissector_list_t heur_epl_data_subdissector_list;
93 static dissector_table_t     epl_asnd_dissector_table;
94 #if 0
95 /* Container for tapping relevant data */
96 typedef struct _epl_info_t {
97 	unsigned char epl_mtyp;
98 } epl_info_t;
99 #endif
100 
101 /*EPL Addressing*/
102 #define EPL_DYNAMIC_NODEID                        0
103 #define EPL_MN_NODEID                           240
104 #define EPL_DIAGNOSTIC_DEVICE_NODEID            253
105 #define EPL_TO_LEGACY_ETHERNET_ROUTER_NODEID    254
106 #define EPL_BROADCAST_NODEID                    255
107 #define EPL_IS_CN_NODEID(nodeid) (EPL_DYNAMIC_NODEID < (nodeid) && (nodeid) < EPL_MN_NODEID)
108 
109 static const value_string addr_str_vals[] = {
110 	{EPL_DYNAMIC_NODEID,                    " (Dynamically assigned)"           },
111 	{EPL_MN_NODEID,                         " (Managing Node)"                  },
112 	{EPL_DIAGNOSTIC_DEVICE_NODEID,          " (Diagnostic Device)"              },
113 	{EPL_TO_LEGACY_ETHERNET_ROUTER_NODEID,  " (POWERLINK to legacy Ethernet Router)"  },
114 	{EPL_BROADCAST_NODEID,                  " (broadcast)"                      },
115 	{0,NULL}
116 };
117 
118 static const value_string addr_str_abbr_vals[] _U_ = {
119 	{EPL_DYNAMIC_NODEID,                    " (dyn.)"   },
120 	{EPL_MN_NODEID,                         " (MN)"     },
121 	{EPL_DIAGNOSTIC_DEVICE_NODEID,          " (diag.)"  },
122 	{EPL_TO_LEGACY_ETHERNET_ROUTER_NODEID,  " (router)" },
123 	{EPL_BROADCAST_NODEID,                  " (bc)"     },
124 	{0,NULL}
125 };
126 /*
127 static const gchar* addr_str_abbr_cn  = " (CN)";
128 static const gchar* addr_str_abbr_res = " (res.)";
129 */
130 
131 
132 
133 /* Offsets of fields within an EPL packet. */
134 #define EPL_MTYP_OFFSET             0   /* same offset for all message types*/
135 #define EPL_DEST_OFFSET             1   /* same offset for all message types*/
136 #define EPL_SRC_OFFSET              2   /* same offset for all message types*/
137 
138 #define EPL_SOA_SVID_OFFSET         6
139 #define EPL_SOA_SVTG_OFFSET         7
140 #define EPL_SOA_EPLV_OFFSET         8
141 /* SyncRequest */
142 #define EPL_SOA_SYNC_OFFSET         10
143 #define EPL_SOA_PRFE_OFFSET         14
144 #define EPL_SOA_PRSE_OFFSET         18
145 #define EPL_SOA_MNDF_OFFSET         22
146 #define EPL_SOA_MNDS_OFFSET         26
147 #define EPL_SOA_PRTO_OFFSET         30
148 #define EPL_SOA_DEST_OFFSET         34
149 
150 #define EPL_ASND_SVID_OFFSET        3
151 #define EPL_ASND_DATA_OFFSET        4
152 /* NMT Command DNA size */
153 #define EPL_SIZEOF_NMTCOMMAND_DNA   27
154 
155 /* EPL message types */
156 #define EPL_SOC     0x01
157 #define EPL_PREQ    0x03
158 #define EPL_PRES    0x04
159 #define EPL_SOA     0x05
160 #define EPL_ASND    0x06
161 #define EPL_AMNI    0x07
162 #define EPL_AINV    0x0D
163 
164 static const value_string mtyp_vals[] = {
165 	{EPL_SOC,  "Start of Cycle (SoC)"         },
166 	{EPL_PREQ, "PollRequest (PReq)"           },
167 	{EPL_PRES, "PollResponse (PRes)"          },
168 	{EPL_SOA,  "Start of Asynchronous (SoA)"  },
169 	{EPL_ASND, "Asynchronous Send (ASnd)"     },
170 	{EPL_AINV, "Asynchronous Invite (AInv)"   },
171 	{EPL_AMNI, "ActiveManagingNodeIndication (AMNI)" },
172 	{0,NULL}
173 };
174 
175 /* flags/masks */
176 #define EPL_SOC_MC_MASK              0x80
177 #define EPL_SOC_PS_MASK              0x40
178 #define EPL_SOC_AN_MASK              0x08
179 #define EPL_PDO_RD_MASK              0x01
180 #define EPL_PDO_EA_MASK              0x04
181 #define EPL_PDO_EN_MASK              0x10
182 #define EPL_PDO_RS_MASK              0x07
183 #define EPL_PDO_PR_MASK              0x38
184 #define EPL_PDO_SLS_MASK             0x40
185 #define EPL_PDO_FLS_MASK             0x80
186 #define EPL_SOA_EA_MASK              0x04
187 #define EPL_SOA_ER_MASK              0x02
188 #define EPL_ASND_EN_MASK             0x10
189 #define EPL_ASND_EC_MASK             0x08
190 #define EPL_ASND_RS_MASK             0x07
191 #define EPL_ASND_PR_MASK             0x38
192 #define EPL_ASND_SLS_MASK            0x40
193 #define EPL_ASND_FLS_MASK            0x80
194 
195 /* RequestedServiceID s for EPL message type "SoA" */
196 #define EPL_SOA_NOSERVICE               0
197 #define EPL_SOA_IDENTREQUEST            1
198 #define EPL_SOA_STATUSREQUEST           2
199 #define EPL_SOA_NMTREQUESTINVITE        3
200 #define EPL_SOA_SYNCREQUEST             6
201 #define EPL_SOA_UNSPECIFIEDINVITE     255
202 
203 #define EPL_SOA_SYNC_PRES_FIRST         0x01
204 #define EPL_SOA_SYNC_PRES_SECOND        0x02
205 #define EPL_SOA_SYNC_MND_FIRST          0x04
206 #define EPL_SOA_SYNC_MND_SECOND         0x08
207 #define EPL_SOA_SYNC_PRES_TIMEOUT       0x10
208 #define EPL_SOA_SYNC_MAC_VALID          0x20
209 #define EPL_SOA_SYNC_PRES_RESET         0x40
210 #define EPL_SOA_SYNC_PRES_SET           0x80
211 
212 static const range_string soa_svid_vals[] = {
213 	{EPL_SOA_NOSERVICE,         EPL_SOA_NOSERVICE,          "NoService"},
214 	{EPL_SOA_IDENTREQUEST,      EPL_SOA_IDENTREQUEST,       "IdentRequest"},
215 	{EPL_SOA_STATUSREQUEST,     EPL_SOA_STATUSREQUEST,      "StatusRequest"},
216 	{EPL_SOA_NMTREQUESTINVITE,  EPL_SOA_NMTREQUESTINVITE,   "NMTRequestInvite"},
217 	{0x04,                      0x05,                       "Reserved"},
218 	{EPL_SOA_SYNCREQUEST,       EPL_SOA_SYNCREQUEST,        "SyncRequest"},
219 	{0x07,                      0x9F,                       "Reserved"},
220 	{0xA0,                      0xFE,                       "Manufacturer Specific"},
221 	{EPL_SOA_UNSPECIFIEDINVITE, EPL_SOA_UNSPECIFIEDINVITE,  "UnspecifiedInvite"},
222 	{0,                         0,                          NULL}
223 };
224 
225 /* ServiceID values for EPL message type "ASnd" */
226 #define EPL_ASND_IDENTRESPONSE          1
227 #define EPL_ASND_STATUSRESPONSE         2
228 #define EPL_ASND_NMTREQUEST             3
229 #define EPL_ASND_NMTCOMMAND             4
230 #define EPL_ASND_SDO                    5
231 #define EPL_ASND_SYNCRESPONSE           6
232 
233 #define EPL_ASND_SYNCRESPONSE_FST_VALID    0x01
234 #define EPL_ASND_SYNCRESPONSE_SEC_VALID    0x02
235 #define EPL_ASND_SYNCRESPONSE_MODE         0x80
236 
237 static const range_string soa_svid_id_vals[] = {
238 	{EPL_SOA_NOSERVICE,         EPL_SOA_NOSERVICE,          "NO_SERVICE"},
239 	{EPL_SOA_IDENTREQUEST,      EPL_SOA_IDENTREQUEST,       "IDENT_REQUEST"},
240 	{EPL_SOA_STATUSREQUEST,     EPL_SOA_STATUSREQUEST,      "STATUS_REQUEST"},
241 	{EPL_SOA_NMTREQUESTINVITE,  EPL_SOA_NMTREQUESTINVITE,   "NMT_REQUEST_INV"},
242 	{0x04,                      0x05,                       "RESERVED"},
243 	{EPL_SOA_SYNCREQUEST,       EPL_SOA_SYNCREQUEST,        "SYNC_REQUEST"},
244 	{0x07,                      0x9F,                       "RESERVED"},
245 	{0xA0,                      0xFE,                       "MANUFACTURER SPECIFIC"},
246 	{EPL_SOA_UNSPECIFIEDINVITE, EPL_SOA_UNSPECIFIEDINVITE,  "UNSPEC_INVITE"},
247 	{0,                         0,                          NULL}
248 };
249 
250 static const range_string asnd_svid_vals[] = {
251 	{0,                       0,                       "Reserved"},
252 	{EPL_ASND_IDENTRESPONSE,  EPL_ASND_IDENTRESPONSE,  "IdentResponse"},
253 	{EPL_ASND_STATUSRESPONSE, EPL_ASND_STATUSRESPONSE, "StatusResponse"},
254 	{EPL_ASND_NMTREQUEST,     EPL_ASND_NMTREQUEST,     "NMTRequest"},
255 	{EPL_ASND_NMTCOMMAND,     EPL_ASND_NMTCOMMAND,     "NMTCommand"},
256 	{EPL_ASND_SDO,            EPL_ASND_SDO,            "SDO"},
257 	{EPL_ASND_SYNCRESPONSE,   EPL_ASND_SYNCRESPONSE,   "SyncResponse"},
258 	{0x07,                    0x9F,                    "Reserved"},
259 	{0xA0,                    0xFE,                    "Manufacturer Specific"},
260 	{0xFF,                    0xFF,                    "Reserved"},
261 	{0,                       0,                        NULL}
262 };
263 
264 static const range_string asnd_svid_id_vals[] = {
265 	{0,                       0,                       "RESERVED"},
266 	{EPL_ASND_IDENTRESPONSE,  EPL_ASND_IDENTRESPONSE,  "IDENT_RESPONSE"},
267 	{EPL_ASND_STATUSRESPONSE, EPL_ASND_STATUSRESPONSE, "STATUS_RESPONSE"},
268 	{EPL_ASND_NMTREQUEST,     EPL_ASND_NMTREQUEST,     "NMT_REQUEST"},
269 	{EPL_ASND_NMTCOMMAND,     EPL_ASND_NMTCOMMAND,     "NMT_COMMAND"},
270 	{EPL_ASND_SDO,            EPL_ASND_SDO,            "SDO"},
271 	{EPL_ASND_SYNCRESPONSE,   EPL_ASND_SYNCRESPONSE,   "SYNC_RESPONSE"},
272 	{0x07,                    0x9F,                    "RESERVED"},
273 	{0xA0,                    0xFE,                    "MANUFACTURER SPECIFIC"},
274 	{0xFF,                    0xFF,                    "RESERVED"},
275 	{0,                       0,                        NULL}
276 };
277 
278 /* NMTCommand values for EPL message type "ASnd" */
279 #define EPL_ASND_NMTCOMMAND_NMTSTARTNODE                0x21
280 #define EPL_ASND_NMTCOMMAND_NMTSTOPNODE                 0x22
281 #define EPL_ASND_NMTCOMMAND_NMTENTERPREOPERATIONAL2     0x23
282 #define EPL_ASND_NMTCOMMAND_NMTENABLEREADYTOOPERATE     0x24
283 #define EPL_ASND_NMTCOMMAND_NMTRESETNODE                0x28
284 #define EPL_ASND_NMTCOMMAND_NMTRESETCOMMUNICATION       0x29
285 #define EPL_ASND_NMTCOMMAND_NMTRESETCONFIGURATION       0x2A
286 #define EPL_ASND_NMTCOMMAND_NMTSWRESET                  0x2B
287 #define EPL_ASND_NMTCOMMAND_NMTDNA                      0x2D
288 
289 #define EPL_ASND_NMTCOMMAND_NMTSTARTNODEEX              0x41
290 #define EPL_ASND_NMTCOMMAND_NMTSTOPNODEEX               0x42
291 #define EPL_ASND_NMTCOMMAND_NMTENTERPREOPERATIONAL2EX   0x43
292 #define EPL_ASND_NMTCOMMAND_NMTENABLEREADYTOOPERATEEX   0x44
293 #define EPL_ASND_NMTCOMMAND_NMTRESETNODEEX              0x48
294 #define EPL_ASND_NMTCOMMAND_NMTRESETCOMMUNICATIONEX     0x49
295 #define EPL_ASND_NMTCOMMAND_NMTRESETCONFIGURATIONEX     0x4A
296 #define EPL_ASND_NMTCOMMAND_NMTSWRESETEX                0x4B
297 
298 #define EPL_ASND_NMTCOMMAND_NMTNETHOSTNAMESET           0x62
299 #define EPL_ASND_NMTCOMMAND_NMTFLUSHARPENTRY            0x63
300 #define EPL_ASND_NMTCOMMAND_NMTPUBLISHCONFIGUREDNODES   0x80
301 #define EPL_ASND_NMTCOMMAND_NMTPUBLISHACTIVENODES       0x90
302 #define EPL_ASND_NMTCOMMAND_NMTPUBLISHPREOPERATIONAL1   0x91
303 #define EPL_ASND_NMTCOMMAND_NMTPUBLISHPREOPERATIONAL2   0x92
304 #define EPL_ASND_NMTCOMMAND_NMTPUBLISHREADYTOOPERATE    0x93
305 #define EPL_ASND_NMTCOMMAND_NMTPUBLISHOPERATIONAL       0x94
306 #define EPL_ASND_NMTCOMMAND_NMTPUBLISHSTOPPED           0x95
307 #define EPL_ASND_NMTCOMMAND_NMTPUBLISHEMERGENCYNEW      0xA0
308 #define EPL_ASND_NMTCOMMAND_NMTPUBLISHTIME              0XB0
309 #define EPL_ASND_NMTCOMMAND_NMTINVALIDSERVICE           0xFF
310 
311 static const value_string asnd_cid_vals[] = {
312 	/* "special" values to cover all possibilities of CommandID in NMTRequests */
313 	{EPL_ASND_IDENTRESPONSE,                          "IdentResponse"             },
314 	{EPL_ASND_STATUSRESPONSE,                         "StatusResponse"            },
315 	/* ... */
316 	{EPL_ASND_NMTCOMMAND_NMTSTARTNODE,                "NMTStartNode"              },
317 	{EPL_ASND_NMTCOMMAND_NMTSTOPNODE,                 "NMTStopNode"               },
318 	{EPL_ASND_NMTCOMMAND_NMTENTERPREOPERATIONAL2,     "NMTEnterPreOperational2"   },
319 	{EPL_ASND_NMTCOMMAND_NMTENABLEREADYTOOPERATE,     "NMTEnableReadyToOperate"   },
320 	{EPL_ASND_NMTCOMMAND_NMTRESETNODE,                "NMTResetNode"              },
321 	{EPL_ASND_NMTCOMMAND_NMTRESETCOMMUNICATION,       "NMTResetCommunication"     },
322 	{EPL_ASND_NMTCOMMAND_NMTRESETCONFIGURATION,       "NMTResetConfiguration"     },
323 	{EPL_ASND_NMTCOMMAND_NMTSWRESET,                  "NMTSwReset"                },
324 	{EPL_ASND_NMTCOMMAND_NMTDNA,                      "NMTDNA"                    },
325 	{EPL_ASND_NMTCOMMAND_NMTSTARTNODEEX,              "NMTStartNodeEx"            },
326 	{EPL_ASND_NMTCOMMAND_NMTSTOPNODEEX,               "NMTStopNodeEx"             },
327 	{EPL_ASND_NMTCOMMAND_NMTENTERPREOPERATIONAL2EX,   "NMTEnterPreOperational2Ex" },
328 	{EPL_ASND_NMTCOMMAND_NMTENABLEREADYTOOPERATEEX,   "NMTEnableReadyToOperateEx" },
329 	{EPL_ASND_NMTCOMMAND_NMTRESETNODEEX,              "NMTResetNodeEx"            },
330 	{EPL_ASND_NMTCOMMAND_NMTRESETCOMMUNICATIONEX,     "NMTCommunicationEx"        },
331 	{EPL_ASND_NMTCOMMAND_NMTRESETCONFIGURATIONEX,     "NMTResetConfigurationEx"   },
332 	{EPL_ASND_NMTCOMMAND_NMTSWRESETEX,                "NMTSwResetEx"              },
333 	{EPL_ASND_NMTCOMMAND_NMTNETHOSTNAMESET,           "NMTNetHostNameSet"         },
334 	{EPL_ASND_NMTCOMMAND_NMTFLUSHARPENTRY,            "NMTFlushArpEntry"          },
335 	{EPL_ASND_NMTCOMMAND_NMTPUBLISHCONFIGUREDNODES,   "NMTPublishConfiguredNodes" },
336 	{EPL_ASND_NMTCOMMAND_NMTPUBLISHACTIVENODES,       "NMTPublishActiveNodes"     },
337 	{EPL_ASND_NMTCOMMAND_NMTPUBLISHPREOPERATIONAL1,   "NMTPublishPreOperational1" },
338 	{EPL_ASND_NMTCOMMAND_NMTPUBLISHPREOPERATIONAL2,   "NMTPublishPreOperational2" },
339 	{EPL_ASND_NMTCOMMAND_NMTPUBLISHREADYTOOPERATE,    "NMTPublishReadyToOperate"  },
340 	{EPL_ASND_NMTCOMMAND_NMTPUBLISHOPERATIONAL,       "NMTPublishOperational"     },
341 	{EPL_ASND_NMTCOMMAND_NMTPUBLISHSTOPPED,           "NMTPublishStopped"         },
342 	{EPL_ASND_NMTCOMMAND_NMTPUBLISHEMERGENCYNEW,      "NMTPublishEmergencyNew"    },
343 	{EPL_ASND_NMTCOMMAND_NMTPUBLISHTIME,              "NMTPublishTime"            },
344 	{EPL_ASND_NMTCOMMAND_NMTINVALIDSERVICE,           "NMTInvalidService"         },
345 	{0,NULL}
346 };
347 static value_string_ext asnd_cid_vals_ext = VALUE_STRING_EXT_INIT(asnd_cid_vals);
348 
349 /* Maximal Sequence */
350 #define EPL_MAX_SEQUENCE      0x40
351 #define EPL_MAX_ADDRESSES     0xF1
352 /* SCON and RCON values*/
353 #define EPL_NO_CONNECTION     0x00
354 #define EPL_INITIALIZATION    0x01
355 #define EPL_VALID             0x02
356 #define EPL_ACKREQ            0x03
357 #define EPL_RETRANSMISSION    0x03
358 /* MAX Frame offset */
359 #define EPL_MAX_FRAME_OFFSET  0x64
360 
361 /* error codes */
362 #define E_NO_ERROR                          0x0000
363 #define E_NMT_NO_IDENT_RES                  0xF001
364 #define E_NMT_NO_STATUS_RES                 0xF002
365 #define E_DLL_BAD_PHYS_MODE                 0x8161
366 #define E_DLL_COLLISION                     0x8162
367 #define E_DLL_COLLISION_TH                  0x8163
368 #define E_DLL_CRC_TH                        0x8164
369 #define E_DLL_LOSS_OF_LINK                  0x8165
370 #define E_DLL_MAC_BUFFER                    0x8166
371 #define E_DLL_ADDRESS_CONFLICT              0x8201
372 #define E_DLL_MULTIPLE_MN                   0x8202
373 #define E_PDO_SHORT_RX                      0x8210
374 #define E_PDO_MAP_VERS                      0x8211
375 #define E_NMT_ASND_MTU_DIF                  0x8212
376 #define E_NMT_ASND_MTU_LIM                  0x8213
377 #define E_NMT_ASND_TX_LIM                   0x8214
378 #define E_NMT_CYCLE_LEN                     0x8231
379 #define E_DLL_CYCLE_EXCEED                  0x8232
380 #define E_DLL_CYCLE_EXCEED_TH               0x8233
381 #define E_NMT_IDLE_LIM                      0x8234
382 #define E_DLL_JITTER_TH                     0x8235
383 #define E_DLL_LATE_PRES_TH                  0x8236
384 #define E_NMT_PREQ_CN                       0x8237
385 #define E_NMT_PREQ_LIM                      0x8238
386 #define E_NMT_PRES_CN                       0x8239
387 #define E_NMT_PRES_RX_LIM                   0x823A
388 #define E_NMT_PRES_TX_LIM                   0x823B
389 #define E_DLL_INVALID_FORMAT                0x8241
390 #define E_DLL_LOSS_PREQ_TH                  0x8242
391 #define E_DLL_LOSS_PRES_TH                  0x8243
392 #define E_DLL_LOSS_SOA_TH                   0x8244
393 #define E_DLL_LOSS_SOC_TH                   0x8245
394 #define E_NMT_BA1                           0x8410
395 #define E_NMT_BA1_NO_MN_SUPPORT             0x8411
396 #define E_NMT_BPO1                          0x8420
397 #define E_NMT_BPO1_GET_IDENT                0x8421
398 #define E_NMT_BPO1_DEVICE_TYPE              0x8422
399 #define E_NMT_BPO1_VENDOR_ID                0x8423
400 #define E_NMT_BPO1_PRODUCT_CODE             0x8424
401 #define E_NMT_BPO1_REVISION_NO              0x8425
402 #define E_NMT_BPO1_SERIAL_NO                0x8426
403 #define E_NMT_BPO1_CF_VERIFY                0x8428
404 #define E_NMT_BPO2                          0x8430
405 #define E_NMT_BRO                           0x8440
406 #define E_NMT_WRONG_STATE                   0x8480
407 
408 static const value_string errorcode_vals[] = {
409 	{ E_NO_ERROR,               "E_NO_ERROR" },
410 	{ E_DLL_BAD_PHYS_MODE,      "E_DLL_BAD_PHYS_MODE" },
411 	{ E_DLL_COLLISION,          "E_DLL_COLLISION" },
412 	{ E_DLL_COLLISION_TH,       "E_DLL_COLLISION_TH" },
413 	{ E_DLL_CRC_TH,             "E_DLL_CRC_TH" },
414 	{ E_DLL_LOSS_OF_LINK,       "E_DLL_LOSS_OF_LINK" },
415 	{ E_DLL_MAC_BUFFER,         "E_DLL_MAC_BUFFER" },
416 	{ E_DLL_ADDRESS_CONFLICT,   "E_DLL_ADDRESS_CONFLICT" },
417 	{ E_DLL_MULTIPLE_MN,        "E_DLL_MULTIPLE_MN" },
418 	{ E_PDO_SHORT_RX,           "E_PDO_SHORT_RX" },
419 	{ E_PDO_MAP_VERS,           "E_PDO_MAP_VERS" },
420 	{ E_NMT_ASND_MTU_DIF,       "E_NMT_ASND_MTU_DIF" },
421 	{ E_NMT_ASND_MTU_LIM,       "E_NMT_ASND_MTU_LIM" },
422 	{ E_NMT_ASND_TX_LIM,        "E_NMT_ASND_TX_LIM" },
423 	{ E_NMT_CYCLE_LEN,          "E_NMT_CYCLE_LEN" },
424 	{ E_DLL_CYCLE_EXCEED,       "E_DLL_CYCLE_EXCEED" },
425 	{ E_DLL_CYCLE_EXCEED_TH,    "E_DLL_CYCLE_EXCEED_TH" },
426 	{ E_NMT_IDLE_LIM,           "E_NMT_IDLE_LIM" },
427 	{ E_DLL_JITTER_TH,          "E_DLL_JITTER_TH" },
428 	{ E_DLL_LATE_PRES_TH,       "E_DLL_LATE_PRES_TH" },
429 	{ E_NMT_PREQ_CN,            "E_NMT_PREQ_CN" },
430 	{ E_NMT_PREQ_LIM,           "E_NMT_PREQ_LIM" },
431 	{ E_NMT_PRES_CN,            "E_NMT_PRES_CN" },
432 	{ E_NMT_PRES_RX_LIM,        "E_NMT_PRES_RX_LIM" },
433 	{ E_NMT_PRES_TX_LIM,        "E_NMT_PRES_TX_LIM" },
434 	{ E_DLL_INVALID_FORMAT,     "E_DLL_INVALID_FORMAT" },
435 	{ E_DLL_LOSS_PREQ_TH,       "E_DLL_LOSS_PREQ_TH" },
436 	{ E_DLL_LOSS_PRES_TH,       "E_DLL_LOSS_PRES_TH" },
437 	{ E_DLL_LOSS_SOA_TH,        "E_DLL_LOSS_SOA_TH" },
438 	{ E_DLL_LOSS_SOC_TH,        "E_DLL_LOSS_SOC_TH" },
439 	{ E_NMT_BA1,                "E_NMT_BA1" },
440 	{ E_NMT_BA1_NO_MN_SUPPORT,  "E_NMT_BA1_NO_MN_SUPPORT" },
441 	{ E_NMT_BPO1,               "E_NMT_BPO1" },
442 	{ E_NMT_BPO1_GET_IDENT,     "E_NMT_BPO1_GET_IDENT" },
443 	{ E_NMT_BPO1_DEVICE_TYPE,   "E_NMT_BPO1_DEVICE_TYPE" },
444 	{ E_NMT_BPO1_VENDOR_ID,     "E_NMT_BPO1_VENDOR_ID" },
445 	{ E_NMT_BPO1_PRODUCT_CODE,  "E_NMT_BPO1_PRODUCT_CODE" },
446 	{ E_NMT_BPO1_REVISION_NO,   "E_NMT_BPO1_REVISION_NO" },
447 	{ E_NMT_BPO1_SERIAL_NO,     "E_NMT_BPO1_SERIAL_NO" },
448 	{ E_NMT_BPO1_CF_VERIFY,     "E_NMT_BPO1_CF_VERIFY" },
449 	{ E_NMT_BPO2,               "E_NMT_BPO2" },
450 	{ E_NMT_BRO,                "E_NMT_BRO" },
451 	{ E_NMT_WRONG_STATE,        "E_NMT_WRONG_STATE" },
452 	{ E_NMT_NO_IDENT_RES,       "E_NMT_NO_IDENT_RES" },
453 	{ E_NMT_NO_STATUS_RES,      "E_NMT_NO_STATUS_RES" },
454 	{0,NULL}
455 };
456 
457 static value_string_ext errorcode_vals_ext = VALUE_STRING_EXT_INIT(errorcode_vals);
458 
459 /* duplication table key */
460 typedef struct {
461 	guint8 src;
462 	guint8 dest;
463 	guint8 seq_send;
464 	guint8 seq_recv;
465 } duplication_key;
466 
467 /* duplication table value */
468 typedef struct {
469 	guint32 frame;
470 } duplication_data;
471 
472 static guint32 ct = 0;
473 static guint32 count = 0;
474 
475 typedef struct _epl_sdo_reassembly
476 {
477 	guint32 frame[EPL_MAX_SEQUENCE][EPL_MAX_SEQUENCE];
478 } epl_sdo_reassembly;
479 
480 static struct _epl_segmentation{
481 	guint8 src;
482 	guint8 dest;
483 	guint8 recv;
484 	guint8 send;
485 } epl_segmentation;
486 
487 static epl_sdo_reassembly epl_asnd_sdo_reassembly_write;
488 static epl_sdo_reassembly epl_asnd_sdo_reassembly_read;
489 static gboolean first_read = TRUE;
490 static gboolean first_write = TRUE;
491 
492 /* Priority values for EPL message type "ASnd", "", "", field PR */
493 #define EPL_PR_GENERICREQUEST   0x03
494 #define EPL_PR_NMTREQUEST       0x07
495 
496 static const value_string epl_pr_vals[] = {
497 	{0,                       "lowest"},
498 	{1,                       "lower"},
499 	{2,                       "below generic"},
500 	{EPL_PR_GENERICREQUEST,   "GenericRequest"},
501 	{4,                       "above generic"},
502 	{5,                       "higher"},
503 	{6,                       "below NMTRequest"},
504 	{EPL_PR_NMTREQUEST,       "NMTRequest"},
505 	{0,NULL}
506 };
507 
508 /* NMT State values (for CN)*/
509 #define EPL_NMT_GS_OFF                  0x00
510 #define EPL_NMT_GS_INITIALIZING         0x19
511 #define EPL_NMT_GS_RESET_APPLICATION    0x29
512 #define EPL_NMT_GS_RESET_COMMUNICATION  0x39
513 #define EPL_NMT_CS_NOT_ACTIVE           0x1C
514 #define EPL_NMT_CS_PRE_OPERATIONAL_1    0x1D
515 #define EPL_NMT_CS_PRE_OPERATIONAL_2    0x5D
516 #define EPL_NMT_CS_READY_TO_OPERATE     0x6D
517 #define EPL_NMT_CS_OPERATIONAL          0xFD
518 #define EPL_NMT_CS_STOPPED              0x4D
519 #define EPL_NMT_CS_BASIC_ETHERNET       0x1E
520 
521 static const value_string epl_nmt_cs_vals[] = {
522 	{EPL_NMT_GS_OFF,                  "NMT_GS_OFF"                },
523 	{EPL_NMT_GS_INITIALIZING,         "NMT_GS_INITIALIZING"       },
524 	{EPL_NMT_GS_RESET_APPLICATION,    "NMT_GS_RESET_APPLICATION"  },
525 	{EPL_NMT_GS_RESET_COMMUNICATION,  "NMT_GS_RESET_COMMUNICATION"},
526 	{EPL_NMT_CS_NOT_ACTIVE,           "NMT_CS_NOT_ACTIVE"         },
527 	{EPL_NMT_CS_PRE_OPERATIONAL_1,    "NMT_CS_PRE_OPERATIONAL_1"  },
528 	{EPL_NMT_CS_PRE_OPERATIONAL_2,    "NMT_CS_PRE_OPERATIONAL_2"  },
529 	{EPL_NMT_CS_READY_TO_OPERATE,     "NMT_CS_READY_TO_OPERATE"   },
530 	{EPL_NMT_CS_OPERATIONAL,          "NMT_CS_OPERATIONAL"        },
531 	{EPL_NMT_CS_STOPPED,              "NMT_CS_STOPPED"            },
532 	{EPL_NMT_CS_BASIC_ETHERNET,       "NMT_CS_BASIC_ETHERNET"     },
533 	{0,NULL}
534 };
535 
536 /* NMT State values (for MN)*/
537 #define EPL_NMT_GS_OFF                  0x00
538 #define EPL_NMT_GS_INITIALIZING         0x19
539 #define EPL_NMT_GS_RESET_APPLICATION    0x29
540 #define EPL_NMT_GS_RESET_COMMUNICATION  0x39
541 #define EPL_NMT_MS_NOT_ACTIVE           0x1C
542 #define EPL_NMT_MS_PRE_OPERATIONAL_1    0x1D
543 #define EPL_NMT_MS_PRE_OPERATIONAL_2    0x5D
544 #define EPL_NMT_MS_READY_TO_OPERATE     0x6D
545 #define EPL_NMT_MS_OPERATIONAL          0xFD
546 #define EPL_NMT_MS_BASIC_ETHERNET       0x1E
547 
548 static const value_string epl_nmt_ms_vals[] = {
549 	{EPL_NMT_GS_OFF,                  "NMT_GS_OFF"                },
550 	{EPL_NMT_GS_INITIALIZING,         "NMT_GS_INITIALIZING"       },
551 	{EPL_NMT_GS_RESET_APPLICATION,    "NMT_GS_RESET_APPLICATION"  },
552 	{EPL_NMT_GS_RESET_COMMUNICATION,  "NMT_GS_RESET_COMMUNICATION"},
553 	{EPL_NMT_MS_NOT_ACTIVE,           "NMT_MS_NOT_ACTIVE"         },
554 	{EPL_NMT_MS_PRE_OPERATIONAL_1,    "NMT_MS_PRE_OPERATIONAL_1"  },
555 	{EPL_NMT_MS_PRE_OPERATIONAL_2,    "NMT_MS_PRE_OPERATIONAL_2"  },
556 	{EPL_NMT_MS_READY_TO_OPERATE,     "NMT_MS_READY_TO_OPERATE"   },
557 	{EPL_NMT_MS_OPERATIONAL,          "NMT_MS_OPERATIONAL"        },
558 	{EPL_NMT_MS_BASIC_ETHERNET,       "NMT_MS_BASIC_ETHERNET"     },
559 	{0,NULL}
560 };
561 
562 /* EPL Device Profiles according to CANopen */
563 #define EPL_PROFILE_NO              0
564 #define EPL_PROFILE_GENERIC_IO      401
565 #define EPL_PROFILE_DRIVE           402
566 #define EPL_PROFILE_HMI             403
567 #define EPL_PROFILE_MEASURING       404
568 #define EPL_PROFILE_PLC             405
569 #define EPL_PROFILE_ENCODER         406
570 
571 static const value_string epl_device_profiles[] = {
572 	{EPL_PROFILE_NO,         "No Standard Device"},
573 	{EPL_PROFILE_GENERIC_IO, "Generic I/O module"},
574 	{EPL_PROFILE_DRIVE,      "Drive and motion control"},
575 	{EPL_PROFILE_HMI,        "Human Machine Interface"},
576 	{EPL_PROFILE_MEASURING,  "Measuring device"},
577 	{EPL_PROFILE_PLC,        "IEC 61131-3 PLC"},
578 	{EPL_PROFILE_ENCODER,    "Encoder"},
579 	{0,NULL}
580 };
581 
582 /* EPL Device Profiles loading */
583 /* User Access Table Checkers */
584 static gboolean epl_profile_uat_fld_fileopen_check_cb(void *, const char *, unsigned, const void *, const void *, char **);
585 static gboolean epl_uat_fld_cn_check_cb(void *, const char *, unsigned, const void *, const void *, char **);
586 static gboolean epl_uat_fld_uint16dec_check_cb(void *, const char *, unsigned, const void *, const void *, char **);
587 static gboolean epl_uat_fld_uint32hex_check_cb(void *, const char *, unsigned, const void *, const void *, char **);
588 
589 /* DeviceType:Path User Access Table */
590 struct device_profile_uat_assoc {
591 	char *path;
592 
593 	guint device_type;
594 	guint vendor_id;
595 	guint product_code;
596 };
597 
598 static uat_t *device_profile_uat = NULL;
599 static struct device_profile_uat_assoc *device_profile_list_uats = NULL;
600 static guint ndevice_profile_uat = 0;
601 
602 static void *device_profile_uat_copy_cb(void *, const void *, size_t);
603 static void device_profile_uat_free_cb(void *);
604 static gboolean device_profile_uat_update_record(void *, char **);
605 static void device_profile_parse_uat(void);
606 
607 UAT_DEC_CB_DEF(device_profile_list_uats, device_type, struct device_profile_uat_assoc)
608 UAT_HEX_CB_DEF(device_profile_list_uats, vendor_id, struct device_profile_uat_assoc)
609 UAT_HEX_CB_DEF(device_profile_list_uats, product_code, struct device_profile_uat_assoc)
610 UAT_FILENAME_CB_DEF(device_profile_list_uats, path, struct device_profile_uat_assoc)
611 
612 static uat_field_t device_profile_list_uats_flds[] = {
613 	UAT_FLD_CSTRING_OTHER(device_profile_list_uats, device_type, "DeviceType", epl_uat_fld_uint16dec_check_cb, "e.g. 401"),
614 	UAT_FLD_CSTRING_OTHER(device_profile_list_uats, vendor_id, "VendorId", epl_uat_fld_uint32hex_check_cb, "e.g. DEADBEEF"),
615 	UAT_FLD_CSTRING_OTHER(device_profile_list_uats, product_code, "ProductCode", epl_uat_fld_uint32hex_check_cb, "e.g. 8BADFOOD"),
616 
617 	UAT_FLD_FILENAME_OTHER(device_profile_list_uats, path, "Profile Path", epl_profile_uat_fld_fileopen_check_cb, "Path to the EDS" IF_LIBXML("/XDD/XDC")),
618 
619 	UAT_END_FIELDS
620 };
621 
622 /* NodeID:Path User Access Table */
623 struct nodeid_profile_uat_assoc {
624 	char *path;
625 
626 	guint8 is_nodeid:1;
627 
628 	union {
629 		guint8 id;
630 		address addr;
631 	} node;
632 
633 	char *id_str;
634 };
635 
636 static uat_t *nodeid_profile_uat = NULL;
637 static struct nodeid_profile_uat_assoc *nodeid_profile_list_uats = NULL;
638 static guint nnodeid_profile_uat = 0;
639 
640 
641 static void nodeid_profile_list_uats_nodeid_set_cb(void *, const char *, unsigned, const void*, const void*);
642 static void nodeid_profile_list_uats_nodeid_tostr_cb(void *, char **, unsigned *, const void*, const void*);
643 static void *nodeid_profile_uat_copy_cb(void *, const void *, size_t);
644 static void nodeid_profile_uat_free_cb(void *);
645 static gboolean nodeid_profile_uat_update_record(void *, char **);
646 static void nodeid_profile_parse_uat(void);
647 
648 UAT_FILENAME_CB_DEF(nodeid_profile_list_uats, path, struct nodeid_profile_uat_assoc)
649 
650 static uat_field_t nodeid_profile_list_uats_flds[] = {
651 	UAT_FLD_CSTRING_OTHER(nodeid_profile_list_uats, nodeid, "Node ID", epl_uat_fld_cn_check_cb, "e.g. 1 or 00-00-5E-00-53-00"),
652 
653 	UAT_FLD_FILENAME_OTHER(nodeid_profile_list_uats, path, "Profile Path", epl_profile_uat_fld_fileopen_check_cb, "Path to the EDS" IF_LIBXML("/XDD/XDC")),
654 
655 	UAT_END_FIELDS
656 };
657 
658 
659 
660 /* SDO SequenceLayer */
661 #define EPL_ASND_SDO_SEQ_RECEIVE_SEQUENCE_NUMBER_OFFSET        4
662 #define EPL_ASND_SDO_SEQ_RECEIVE_CON_OFFSET                    4
663 
664 #define EPL_ASND_SDO_SEQ_SEND_SEQUENCE_NUMBER_OFFSET           5
665 #define EPL_ASND_SDO_SEQ_SEND_CON_OFFSET                       5
666 
667 #define EPL_ASND_SDO_SEQ_RECEIVE_CON_NO_CONNECTION          0x00
668 #define EPL_ASND_SDO_SEQ_RECEIVE_CON_INITIALIZATION         0x01
669 #define EPL_ASND_SDO_SEQ_RECEIVE_CON_CONNECTION_VALID       0x02
670 #define EPL_ASND_SDO_SEQ_RECEIVE_CON_ERROR_RESPONSE         0x03
671 #define EPL_ASND_SDO_SEQ_CON_MASK                           0x03
672 #define EPL_ASND_SDO_SEQ_MASK                               0x02
673 
674 static const value_string epl_sdo_receive_con_vals[] = {
675 	{EPL_ASND_SDO_SEQ_RECEIVE_CON_NO_CONNECTION,      "No connection"                          },
676 	{EPL_ASND_SDO_SEQ_RECEIVE_CON_INITIALIZATION,     "Initialization"                         },
677 	{EPL_ASND_SDO_SEQ_RECEIVE_CON_CONNECTION_VALID,   "Connection valid"                       },
678 	{EPL_ASND_SDO_SEQ_RECEIVE_CON_ERROR_RESPONSE,     "Error Response (retransmission request)"},
679 	{0,NULL}
680 };
681 
682 #define EPL_ASND_SDO_SEQ_SEND_CON_NO_CONNECTION             0x00
683 #define EPL_ASND_SDO_SEQ_SEND_CON_INITIALIZATION            0x01
684 #define EPL_ASND_SDO_SEQ_SEND_CON_CONNECTION_VALID          0x02
685 #define EPL_ASND_SDO_SEQ_SEND_CON_ERROR_VALID_ACK_REQ       0x03
686 
687 static const value_string epl_sdo_init_abbr_vals[] = {
688 	{EPL_ASND_SDO_SEQ_RECEIVE_CON_NO_CONNECTION,      "n" },
689 	{EPL_ASND_SDO_SEQ_RECEIVE_CON_INITIALIZATION,     "i" },
690 	{EPL_ASND_SDO_SEQ_RECEIVE_CON_CONNECTION_VALID,   "c" },
691 	{EPL_ASND_SDO_SEQ_RECEIVE_CON_ERROR_RESPONSE,     "e" },
692 	{0,NULL}
693 };
694 
695 static const value_string epl_sdo_send_con_vals[] = {
696 	{EPL_ASND_SDO_SEQ_SEND_CON_NO_CONNECTION,         "No connection"                             },
697 	{EPL_ASND_SDO_SEQ_SEND_CON_INITIALIZATION,        "Initialization"                            },
698 	{EPL_ASND_SDO_SEQ_SEND_CON_CONNECTION_VALID,      "Connection valid"                          },
699 	{EPL_ASND_SDO_SEQ_SEND_CON_ERROR_VALID_ACK_REQ,   "Connection valid with acknowledge request" },
700 	{0,NULL}
701 };
702 
703 #define EPL_SDO_INIT_REQUEST    ((EPL_NO_CONNECTION << 8) | EPL_INITIALIZATION)
704 #define EPL_SDO_INIT_ACK        ((EPL_INITIALIZATION << 8) | EPL_INITIALIZATION)
705 #define EPL_SDO_INIT_RESPONSE   ((EPL_INITIALIZATION << 8) | EPL_VALID)
706 #define EPL_SDO_VALID           ((EPL_VALID << 8) | EPL_VALID)
707 #define EPL_SDO_RETRANSMISSION  ((EPL_RETRANSMISSION << 8) | EPL_VALID)
708 #define EPL_SDO_ACKREQ          ((EPL_VALID << 8) | EPL_ACKREQ)
709 #define EPL_SDO_CLOSE           ((EPL_NO_CONNECTION << 8) | EPL_NO_CONNECTION)
710 
711 static const value_string epl_sdo_init_con_vals[] = {
712 	{EPL_SDO_INIT_REQUEST,         "InitReq"        },
713 	{EPL_SDO_INIT_ACK,             "InitAck"        },
714 	{EPL_SDO_INIT_RESPONSE,        "InitResp"       },
715 	{EPL_SDO_VALID,                "Valid"          },
716 	{EPL_SDO_RETRANSMISSION,       "Retrans"        },
717 	{EPL_SDO_ACKREQ,               "AckReq"         },
718 	{EPL_SDO_CLOSE,                "Close"          },
719 	{0,NULL}
720 };
721 
722 
723 /* SDO Command Layer Protocol */
724 #define EPL_ASND_SDO_CMD_ABORT_FILTER                    0x40
725 #define EPL_ASND_SDO_CMD_SEGMENTATION_FILTER             0x30
726 #define EPL_ASND_SDO_CMD_RESPONSE_FILTER                 0x80
727 
728 #define EPL_ASND_SDO_CMD_RESPONSE_RESPONSE                  0
729 #define EPL_ASND_SDO_CMD_RESPONSE_REQUEST                   1
730 
731 #define EPL_ASND_SDO_CMD_ABORT_TRANSFER_OK                  0
732 #define EPL_ASND_SDO_CMD_ABORT_ABORT_TRANSFER               1
733 
734 #define EPL_ASND_SDO_CMD_SEGMENTATION_EPEDITED_TRANSFER     0
735 #define EPL_ASND_SDO_CMD_SEGMENTATION_INITIATE_TRANSFER     1
736 #define EPL_ASND_SDO_CMD_SEGMENTATION_SEGMENT               2
737 #define EPL_ASND_SDO_CMD_SEGMENTATION_TRANSFER_COMPLETE     3
738 
739 #define EPL_ASND_SDO_COMMAND_NOT_IN_LIST                        0x00
740 #define EPL_ASND_SDO_COMMAND_WRITE_BY_INDEX                     0x01
741 #define EPL_ASND_SDO_COMMAND_READ_BY_INDEX                      0x02
742 #define EPL_ASND_SDO_COMMAND_WRITE_ALL_BY_INDEX                 0x03
743 #define EPL_ASND_SDO_COMMAND_READ_ALL_BY_INDEX                  0x04
744 #define EPL_ASND_SDO_COMMAND_WRITE_BY_NAME                      0x05
745 #define EPL_ASND_SDO_COMMAND_READ_BY_NAME                       0x06
746 #define EPL_ASND_SDO_COMMAND_FILE_WRITE                         0x20
747 #define EPL_ASND_SDO_COMMAND_FILE_READ                          0x21
748 #define EPL_ASND_SDO_COMMAND_WRITE_MULTIPLE_PARAMETER_BY_INDEX  0x31
749 #define EPL_ASND_SDO_COMMAND_READ_MULTIPLE_PARAMETER_BY_INDEX   0x32
750 #define EPL_ASND_SDO_COMMAND_MAXIMUM_SEGMENT_SIZE               0x70
751 #define EPL_ASND_SDO_COMMAND_LINK_NAME_TO_INDEX                 0x71
752 
753 /* OD indexes */
754 #define EPL_SOD_CYLE_LEN        0x1006
755 #define EPL_SOD_PDO_RX_COMM     0x1400
756 #define EPL_SOD_PDO_RX_MAPP     0x1600
757 #define EPL_SOD_PDO_TX_COMM     0x1800
758 #define EPL_SOD_PDO_TX_MAPP     0x1A00
759 #define EPL_SDO_SERVER_CONT     0x1200
760 #define EPL_SDO_CLIENT_CONT     0x1280
761 #define EPL_SOD_ERR_HISTORY     0x1003
762 #define EPL_SOD_STORE_PARAM     0x1010
763 #define EPL_SOD_RESTORE_PARAM   0x1011
764 #define EPL_SOD_HEARTBEAT_TMN   0x1016
765 #define EPL_SOD_IDENTITY_OBJECT 0x1018
766 #define EPL_SOD_VERIFY_CONF     0x1020
767 #define EPL_SOD_INT_GRP         0x1030
768 #define EPL_SOD_RLATENCY_DIFF   0x1050
769 #define EPL_SOD_TELEG_Count     0x1101
770 #define EPL_SOD_ERR_STAT        0x1102
771 #define EPL_SOD_STORE_DCF_LST   0x1F20
772 #define EPL_SOD_STORE_CFM_FMT   0x1F21
773 #define EPL_SOD_STORE_CON_LST   0x1F22
774 #define EPL_SOD_STORE_DEV_FILE  0x1F23
775 #define EPL_SOD_STORE_DEV_FMT   0x1F24
776 #define EPL_SOD_CONF_REQ        0x1F25
777 #define EPL_SOD_CONF_DATE       0x1F26
778 #define EPL_SOD_CONF_TIME       0x1F27
779 #define EPL_SOD_CONF_ID         0x1F28
780 #define EPL_SOD_DL_PROG_DATA    0x1F50
781 #define EPL_SOD_DL_PROG_CTRL    0x1F51
782 #define EPL_SOD_LOC_SW          0x1F52
783 #define EPL_SOD_MN_SW_DATE      0x1F53
784 #define EPL_SOD_MN_SW_TIME      0x1F54
785 #define EPL_SOD_PROC_IMG        0x1F70
786 #define EPL_SOD_NMT_NODE        0x1F81
787 #define EPL_SOD_DEVICE_TYPE_LST 0x1F84
788 #define EPL_SOD_VENDORID_LST    0x1F85
789 #define EPL_SOD_PRODUCTEC_LST   0x1F86
790 #define EPL_SOD_REVISION_NO_LST 0x1F87
791 #define EPL_SOD_SERIAL_NO_LST   0x1F88
792 #define EPL_SOD_BOOT_TIME       0x1F89
793 #define EPL_SOD_CYCLE_TIME      0x1F8A
794 #define EPL_SOD_PREQ_PAYLOAD    0x1F8B
795 #define EPL_SOD_PRES_PAYLOAD    0x1F8D
796 #define EPL_SOD_NODE_STATE      0x1F8E
797 #define EPL_SOD_NODE_EXP_STATE  0x1F8F
798 #define EPL_SOD_CNRES_TMOUT     0x1F92
799 #define EPL_SOD_MULT_CYCL       0x1F9B
800 #define EPL_SOD_ISO_SLOT_ASSIGN 0x1F9C
801 #define EPL_SOD_NAT_TABLE       0x1D00
802 #define EPL_SOD_IP_ADD_TABLE    0x1E40
803 #define EPL_SOD_ROUTING_TABLE   0x1E90
804 #define EPL_SOD_ACL_IN_TABLE    0x1ED0
805 #define EPL_SOD_ACL_OUT_TABLE   0x1EE0
806 #define EPL_SOD_CYLE_LEN        0x1006
807 #define EPL_NMT_DEVICE_TYPE     0x1000
808 #define EPL_ERR_ERROR_REGISTER  0x1001
809 #define EPL_MANUFACT_DEV_NAME   0x1008
810 #define EPL_MANUFACT_HW_VERS    0x1009
811 #define EPL_MANUFACT_SW_VERS    0x100A
812 #define EPL_STORE_DEV_FILE      0x1021
813 #define EPL_STORE_DEV_FORMAT    0x1022
814 #define EPL_INT_GROUP           0x1300
815 #define EPL_INT_INDEX           0x1301
816 #define EPL_INT_DESC            0x1302
817 #define EPL_VERSION             0x1F83
818 #define EPL_CN_ETH_TIMEOUT      0x1F99
819 #define EPL_HOST_NAME           0x1F9A
820 #define EPL_CN_LINK_CUM         0x1C10
821 #define EPL_CN_JITTER           0x1C13
822 #define EPL_LOSS_OF_FRAME       0x1C14
823 
824 static const range_string sod_cmd_str[] = {
825 	{EPL_SOD_PDO_RX_COMM,   0x14FF,   "0x1400"},
826 	{EPL_SOD_PDO_RX_MAPP,   0x16FF,   "0x1600"},
827 	{EPL_SOD_PDO_TX_COMM,   0x18FF,   "0x1800"},
828 	{EPL_SOD_PDO_TX_MAPP,   0x1AFF,   "0x1A00"},
829 	{EPL_SDO_SERVER_CONT,   0x1279,   "0x1200"},
830 	{EPL_SDO_CLIENT_CONT,   0x12FF,   "0x1280"},
831 	{EPL_SOD_NAT_TABLE,     0x1DFF,   "0x1D00"},
832 	{EPL_SOD_IP_ADD_TABLE,  0x1E49,   "0x1E40"},
833 	{EPL_SOD_ROUTING_TABLE, 0x1ECF,   "0x1E90"},
834 	{EPL_SOD_ACL_IN_TABLE,  0x1EDF,   "0x1ED0"},
835 	{EPL_SOD_ACL_OUT_TABLE, 0x1EEF,   "0x1EE0"},
836 	{0,0,NULL}
837 };
838 
839 static const value_string sod_cmd_str_val[] = {
840 	{EPL_SOD_PDO_RX_COMM,   "0x1400"},
841 	{EPL_SOD_PDO_RX_MAPP,   "0x1600"},
842 	{EPL_SOD_PDO_TX_COMM,   "0x1800"},
843 	{EPL_SOD_PDO_TX_MAPP,   "0x1A00"},
844 	{EPL_SDO_SERVER_CONT,   "0x1200"},
845 	{EPL_SDO_CLIENT_CONT,   "0x1280"},
846 	{EPL_SOD_NAT_TABLE,     "0x1D00"},
847 	{EPL_SOD_IP_ADD_TABLE,  "0x1E40"},
848 	{EPL_SOD_ROUTING_TABLE, "0x1E90"},
849 	{EPL_SOD_ACL_IN_TABLE,  "0x1ED0"},
850 	{EPL_SOD_ACL_OUT_TABLE, "0x1EE0"},
851 	{0,NULL}
852 };
853 
854 static const value_string sod_cmd_sub_str_val[] = {
855 	{EPL_SOD_ERR_HISTORY,    "0x1003"},
856 	{EPL_SOD_HEARTBEAT_TMN,  "0x1016"},
857 	{EPL_SOD_STORE_DCF_LST,  "0x1F20"},
858 	{EPL_SOD_STORE_CFM_FMT,  "0x1F21"},
859 	{EPL_SOD_STORE_CON_LST,  "0x1F22"},
860 	{EPL_SOD_STORE_DEV_FILE, "0x1F23"},
861 	{EPL_SOD_STORE_DEV_FMT,  "0x1F24"},
862 	{EPL_SOD_CONF_REQ,       "0x1F25"},
863 	{EPL_SOD_CONF_DATE,      "0x1F26"},
864 	{EPL_SOD_CONF_TIME,      "0x1F27"},
865 	{EPL_SOD_CONF_ID,        "0x1F28"},
866 	{EPL_SOD_DL_PROG_DATA,   "0x1F50"},
867 	{EPL_SOD_DL_PROG_CTRL,   "0x1F51"},
868 	{EPL_SOD_MN_SW_DATE,     "0x1F53"},
869 	{EPL_SOD_MN_SW_TIME,     "0x1F54"},
870 	{EPL_SOD_NMT_NODE,       "0x1F81"},
871 	{EPL_SOD_DEVICE_TYPE_LST,"0x1F84"},
872 	{EPL_SOD_VENDORID_LST,   "0x1F85"},
873 	{EPL_SOD_PRODUCTEC_LST,  "0x1F86"},
874 	{EPL_SOD_REVISION_NO_LST,"0x1F87"},
875 	{EPL_SOD_SERIAL_NO_LST,  "0x1F88"},
876 	{EPL_SOD_PREQ_PAYLOAD,   "0x1F8B"},
877 	{EPL_SOD_PRES_PAYLOAD,   "0x1F8D"},
878 	{EPL_SOD_NODE_STATE,     "0x1F8E"},
879 	{EPL_SOD_NODE_EXP_STATE, "0x1F8F"},
880 	{EPL_SOD_CNRES_TMOUT,    "0x1F92"},
881 	{EPL_SOD_MULT_CYCL,      "0x1F9B"},
882 	{EPL_SOD_ISO_SLOT_ASSIGN,"0x1F9C"},
883 	{0,NULL}
884 };
885 
886 static value_string_ext sod_cmd_sub_str = VALUE_STRING_EXT_INIT(sod_cmd_sub_str_val);
887 
888 static const value_string sod_cmd_str_no_sub[] = {
889 	{EPL_NMT_DEVICE_TYPE,    "0x1000"},
890 	{EPL_ERR_ERROR_REGISTER, "0x1001"},
891 	{EPL_SOD_CYLE_LEN,       "0x1006"},
892 	{EPL_MANUFACT_DEV_NAME,  "0x1008"},
893 	{EPL_MANUFACT_HW_VERS,   "0x1009"},
894 	{EPL_MANUFACT_SW_VERS,   "0x100A"},
895 	{EPL_STORE_DEV_FILE,     "0x1021"},
896 	{EPL_STORE_DEV_FORMAT,   "0x1022"},
897 	{EPL_INT_GROUP,          "0x1300"},
898 	{EPL_INT_INDEX,          "0x1301"},
899 	{EPL_INT_DESC,           "0x1302"},
900 	{EPL_CN_LINK_CUM,        "0x1C10"},
901 	{EPL_CN_JITTER,          "0x1C13"},
902 	{EPL_LOSS_OF_FRAME,      "0x1C14"},
903 	{EPL_VERSION,            "0x1F83"},
904 	{EPL_CN_ETH_TIMEOUT,     "0x1F99"},
905 	{EPL_HOST_NAME,          "0x1F9A"},
906 	{0,NULL}
907 };
908 
909 static value_string_ext sod_cmd_no_sub = VALUE_STRING_EXT_INIT(sod_cmd_str_no_sub);
910 
911 static const value_string sod_idx_names[] = {
912 	/* SDO directory names */
913 	{0x10000000, "NMT_DeviceType_U32"},
914 	{0x10010000, "ERR_ErrorRegister_U8"},
915 	{0x10030000, "ERR_History_ADOM"},
916 	{0x10030001, "ErrorEntry_DOM"},
917 	{0x10060000, "NMT_CycleLen_U32"},
918 	{0x10080000, "NMT_ManufactDevName_VS"},
919 	{0x10090000, "NMT_ManufactHwVers_VS"},
920 	{0x100A0000, "NMT_ManufactSwVers_VS"},
921 	{0x10100000, "NMT_StoreParam_REC"},
922 	{0x10100001, "AllParam_U32"},
923 	{0x10100002, "CommunicationParam_U32"},
924 	{0x10100003, "ApplicationParam_U32"},
925 	{0x10100004, "ManufacturerParam_XXh_U32"},
926 
927 	{0x10110000, "NMT_RestoreDefParam_REC"},
928 	{0x10110001, "AllParam_U32"},
929 	{0x10110002, "CommunicationParam_U32"},
930 	{0x10110003, "ApplicationParam_U32"},
931 	{0x10110004, "ManufacturerParam_XXh_U32"},
932 
933 	{0x10160000, "NMT_ConsumerHeartbeatTime_AU32"},
934 	{0x10160001, "HeartbeatDescription"},
935 
936 	{0x10180000, "NMT_IdentityObject_REC" },
937 	{0x10180001, "VendorId_U32" },
938 	{0x10180002, "ProductCode_U32" },
939 	{0x10180003, "RevisionNo_U32" },
940 	{0x10180004, "SerialNo_U32" },
941 
942 	{0x10200000, "CFM_VerifyConfiguration_REC"},
943 	{0x10200001, "ConfDate_U32"},
944 	{0x10200002, "ConfTime_U32"},
945 	{0x10200003, "ConfId_U32"},
946 	{0x10200004, "VerifyConfInvalid_BOOL"},
947 
948 	{0x10210000, "CFM_StoreDevDescrFile_DOM"},
949 	{0x10220000, "CFM_StoreDevDescrFormat_U16"},
950 
951 	{0x10300000, "NMT_InterfaceGroup_XX_REC"},
952 	{0x10300001, "InterfaceIndex_U16"},
953 	{0x10300002, "InterfaceDescription_VSTR"},
954 	{0x10300003, "InterfaceType_U8"},
955 	{0x10300004, "InterfaceMtu_U16"},
956 	{0x10300005, "InterfacePhysAddress_OSTR"},
957 	{0x10300006, "InterfaceName_VSTR"},
958 	{0x10300007, "InterfaceOperStatus_U8"},
959 	{0x10300008, "InterfaceAdminState_U8"},
960 	{0x10300009, "Valid_BOOL"},
961 
962 	{0x10500000, "NMT_RelativeLatencyDiff_AU32"},
963 	{0x10500000, "RelativeLatencyDiff"},
964 
965 	{0x11010000, "DIA_NMTTelegrCount_REC"},
966 	{0x11010001, "IsochrCyc_U32"},
967 	{0x11010002, "IsochrRx_U32"},
968 	{0x11010003, "IsochrTx_U32"},
969 	{0x11010004, "AsyncRx_U32"},
970 	{0x11010005, "AsyncTx_U32"},
971 	{0x11010006, "SdoRx_U32"},
972 	{0x11010007, "SdoTx_U32"},
973 	{0x11010008, "Status_U32"},
974 
975 	{0x11020000, "DIA_ERRStatistics_REC"},
976 	{0x11020001, "HistoryEntryWrite_U32"},
977 	{0x11020002, "EmergencyQueueWrite_U32"},
978 	{0x11020003, "EmergencyQueueOverflow_U32"},
979 	{0x11020004, "StatusEntryChanged_U32"},
980 	{0x11020005, "StaticErrorBitFieldChanged_U32"},
981 	{0x11020006, "ExceptionResetEdgePos_U32"},
982 	{0x11020007, "ExceptionNewEdge_U32"},
983 
984 	{0x12000000, "SDO_ServerContainerParam"},
985 	{0x12000001, "ClientNodeID_U8"},
986 	{0x12000002, "ServerNodeID_U8"},
987 	{0x12000003, "ContainerLen_U8"},
988 	{0x12000004, "HistorySize_U8"},
989 
990 	{0x12800000, "SDO_ClientContainerParam"},
991 	{0x12800001, "ClientNodeID_U8"},
992 	{0x12800002, "ServerNodeID_U8"},
993 	{0x12800003, "ContainerLen_U8"},
994 	{0x12800004, "HistorySize_U8"},
995 	{0x12800005, "Reserved"},
996 
997 	{0x13000000, "SDO_SequLayerTimeout_U32"},
998 	{0x13010000, "SDO_CmdLayerTimeout_U32"},
999 	{0x13020000, "SDO_SequLayerNoAck_U32"},
1000 
1001 	{0x14000000, "PDO_RxCommParam"},
1002 	{0x14000001, "NodeID_U8"},
1003 	{0x14000002, "MappingVersion_U8"},
1004 
1005 	{0x16000000, "PDO_RxMappParam"},
1006 	{0x16000001, "ObjectMapping"},
1007 
1008 	{0x18000000, "PDO_TxCommParam"},
1009 	{0x18000001, "NodeID_U8"},
1010 	{0x18000002, "MappingVersion"},
1011 
1012 	{0x1A000000, "PDO_TxMappParam"},
1013 	{0x1A000001, "ObjectMapping"},
1014 
1015 	{0x1C0A0000, "DLL_CNCollision_REC"},
1016 	{0x1C0A0001, "CumulativeCnt_U32"},
1017 	{0x1C0A0002, "ThresholdCnt_U32"},
1018 	{0x1C0A0003, "Threshold_U32"},
1019 
1020 	{0x1C0B0000, "DLL_CNLossSoC_REC"},
1021 	{0x1C0B0001, "CumulativeCnt_U32"},
1022 	{0x1C0B0002, "ThresholdCnt_U32"},
1023 	{0x1C0B0003, "Threshold_U32"},
1024 
1025 	{0x1C0C0000, "DLL_CNLossSoA_REC"},
1026 	{0x1C0C0001, "CumulativeCnt_U32"},
1027 	{0x1C0C0002, "ThresholdCnt_U32"},
1028 	{0x1C0C0003, "Threshold_U32"},
1029 
1030 	{0x1C0D0000, "DLL_CNLossPReq_REC"},
1031 	{0x1C0D0001, "CumulativeCnt_U32"},
1032 	{0x1C0D0002, "ThresholdCnt_U32"},
1033 	{0x1C0D0003, "Threshold_U32"},
1034 
1035 	{0x1C0E0000, "DLL_CNSoCJitter_REC"},
1036 	{0x1C0E0001, "CumulativeCnt_U32"},
1037 	{0x1C0E0002, "ThresholdCnt_U32"},
1038 	{0x1C0E0003, "Threshold_U32"},
1039 
1040 	{0x1C0F0000, "DLL_CNCRCError_REC"},
1041 	{0x1C0F0001, "CumulativeCnt_U32"},
1042 	{0x1C0F0002, "ThresholdCnt_U32"},
1043 	{0x1C0F0003, "Threshold_U32"},
1044 
1045 	{0x1C100000, "DLL_CNLossOfLinkCum_U32"},
1046 	{0x1C130000, "DLL_CNSoCJitterRange_U32"},
1047 	{0x1C140000, "DLL_LossOfFrameTolerance_U32"},
1048 
1049 	{0x1D000000, "RT1_NatTable"},
1050 	{0x1D000001, "EplIpAddr_IPAD"},
1051 	{0x1D000002, "ExtIpAddr_IPAD"},
1052 	{0x1D000003, "Mask_IPAD"},
1053 	{0x1D000004, "Type_U8"},
1054 
1055 	{0x1E400000, "NWL_IpAddrTable"},
1056 	{0x1E400001, "IfIndex_U16"},
1057 	{0x1E400002, "Addr_IPAD"},
1058 	{0x1E400003, "NetMask_IPAD"},
1059 	{0x1E400004, "ReasmMaxSize_U16"},
1060 	{0x1E400005, "DefaultGateway_IPAD"},
1061 	{0x1E4A0000, "NWL_IpGroup_REC"},
1062 	{0x1E4A0001, "Forwarding_BOOL"},
1063 	{0x1E4A0002, "DefaultTTL_U16"},
1064 	{0x1E4A0003, "ForwardDatagrams_U32"},
1065 	{0x1E800000, "RT1_EplRouter_REC"},
1066 	{0x1E800001, "EnableNat_BOOL"},
1067 	{0x1E800002, "EnablePacketFiltering_BOOL"},
1068 	{0x1E810000, "RT1_SecurityGroup_REC"},
1069 	{0x1E810001, "FwdTablePolicy_U8"},
1070 	{0x1E810002, "InTablePolicy_U8"},
1071 	{0x1E810003, "OutTablePolicy_U8"},
1072 
1073 	{0x1E900000, "RT1_IpRoutingTable"},
1074 	{0x1E900001, "IpForwardDest_IPAD"},
1075 	{0x1E900002, "IpForwardMask_IPAD"},
1076 	{0x1E900003, "IpForwardNextHop_IPAD"},
1077 	{0x1E900004, "IpForwardType_U8"},
1078 	{0x1E900005, "IpForwardAge_U32"},
1079 	{0x1E900006, "IpForwardItfIndex_U16"},
1080 	{0x1E900007, "IpForwardMetric1_S32"},
1081 
1082 	{0x1ED00000, "RT1_AclInTable"},
1083 	{0x1ED00001, "SrcIp_IPAD"},
1084 	{0x1ED00002, "SrcMask_IPAD"},
1085 	{0x1ED00003, "DstIp_IPAD"},
1086 	{0x1ED00004, "DstMask_IPAD"},
1087 	{0x1ED00005, "Protocol_U8"},
1088 	{0x1ED00006, "SrcPort_U16"},
1089 	{0x1ED00007, "DstPort_U16"},
1090 	{0x1ED00008, "SrcMac_MAC"},
1091 	{0x1ED00009, "Target_U8"},
1092 
1093 	{0x1EE00000, "RT1_AclOutTable"},
1094 	{0x1EE00001, "SrcIp_IPAD"},
1095 	{0x1EE00002, "SrcMask_IPAD"},
1096 	{0x1EE00003, "DstIp_IPAD"},
1097 	{0x1EE00004, "DstMask_IPAD"},
1098 	{0x1EE00005, "Protocol_U8"},
1099 	{0x1EE00006, "SrcPort_U16"},
1100 	{0x1EE00007, "DstPort_U16"},
1101 	{0x1EE00008, "SrcMac_MAC"},
1102 	{0x1EE00009, "Target_U8"},
1103 
1104 	{0x1F200000, "CFM_StoreDcfList_ADOM"},
1105 	{0x1F200001, "CNDcf"},
1106 	{0x1F210000, "CFM_DcfStorageFormatList_AU8"},
1107 	{0x1F210001, "CNDcfFormat"},
1108 	{0x1F220000, "CFM_ConciseDcfList_ADOM"},
1109 	{0x1F220001, "CNConciseDcfData"},
1110 	{0x1F230000, "CFM_StoreDevDescrFileList_ADOM"},
1111 	{0x1F230001, "CNDevDescrFile"},
1112 	{0x1F240000, "CFM_DevDescrFileFormatList_AU8"},
1113 	{0x1F240001, "CNDevDescrFileFormat"},
1114 	{0x1F250000, "CFM_ConfCNRequest_AU32"},
1115 	{0x1F250001, "CNConfigurationRequest"},
1116 	{0x1F260000, "CFM_ExpConfDateList_AU32"},
1117 	{0x1F260001, "CNConfigurationDate"},
1118 	{0x1F270000, "CFM_ExpConfTimeList_AU32"},
1119 	{0x1F270001, "CNConfigurationTime"},
1120 	{0x1F280000, "CFM_ExpConfIdList_AU32"},
1121 	{0x1F280001, "CNConfigurationId"},
1122 
1123 	{0x1F500000, "PDL_DownloadProgData_ADOM"},
1124 	{0x1F500001, "Program"},
1125 	{0x1F510000, "PDL_ProgCtrl_AU8"},
1126 	{0x1F510001, "ProgCtrl"},
1127 	{0x1F520000, "PDL_LocVerApplSw_REC"},
1128 	{0x1F520001, "ApplSwDate_U32"},
1129 	{0x1F520002, "ApplSwTime_U32"},
1130 	{0x1F530000, "PDL_MnExpAppSwDateList_AU32"},
1131 	{0x1F530001, "AppSwDate"},
1132 	{0x1F540000, "PDL_MnExpAppSwTimeList_AU32"},
1133 	{0x1F540001, "AppSwTime"},
1134 
1135 	{0x1F700000, "INP_ProcessImage_REC"},
1136 	{0x1F700001, "SelectedRange_U32"},
1137 	{0x1F700002, "ProcessImageDomain_DOM"},
1138 
1139 	{0x1F800000, "NMT_StartUp_U32"},
1140 	{0x1F810000, "NMT_NodeAssignment_AU32"},
1141 	{0x1F810001, "NodeAssignment"},
1142 	{0x1F820000, "NMT_FeatureFlags_U32"},
1143 	{0x1F830000, "NMT_EPLVersion_U8"},
1144 	{0x1F840000, "NMT_MNDeviceTypeIdList_AU32"},
1145 	{0x1F840001, "CNDeviceTypeId"},
1146 	{0x1F850000, "NMT_MNVendorIdList_AU32"},
1147 	{0x1F850001, "CNVendorId"},
1148 	{0x1F860000, "NMT_MNProductCodeList_AU32"},
1149 	{0x1F860001, "CNProductCode"},
1150 	{0x1F870000, "NMT_MNRevisionNoList_AU32"},
1151 	{0x1F870001, "CNRevisionNo"},
1152 	{0x1F880000, "NMT_MNSerialNoList_AU32"},
1153 	{0x1F880001, "CNSerialNo"},
1154 
1155 	{0x1F890000, "NMT_BootTime_REC"},
1156 	{0x1F890001, "MNWaitNotAct_U32"},
1157 	{0x1F890002, "MNTimeoutPreOp1_U32"},
1158 	{0x1F890003, "MNWaitPreOp1_U32"},
1159 	{0x1F890004, "MNTimeoutPreOp2_U32"},
1160 	{0x1F890005, "MNTimeoutReadyToOp_U32"},
1161 	{0x1F890006, "MNIdentificationTimeout_U32"},
1162 	{0x1F890007, "MNSoftwareTimeout_U32"},
1163 	{0x1F890008, "MNConfigurationTimeout_U32"},
1164 	{0x1F890009, "MNStartCNTimeout_U32"},
1165 	{0x1F89000A, "MNSwitchOverPriority_U32"},
1166 	{0x1F89000B, "MNSwitchOverDelay_U32"},
1167 	{0x1F89000C, "MNSwitchOverCycleDivider_U32"},
1168 
1169 	{0x1F8A0000, "NMT_MNCycleTiming_REC"},
1170 	{0x1F8A0001, "WaitSoCPReq_U32"},
1171 	{0x1F8A0002, "AsyncSlotTimeout_U32"},
1172 	{0x1F8A0003, "ASndMaxNumber"},
1173 
1174 	{0x1F8B0000, "NMT_MNPReqPayloadLimitList_AU16"},
1175 	{0x1F8B0001, "CNPReqPayload"},
1176 	{0x1F8C0000, "NMT_CurrNMTState_U8"},
1177 	{0x1F8D0000, "NMT_PResPayloadLimitList_AU16"},
1178 	{0x1F8D0001, "PResPayloadLimit"},
1179 	{0x1F8E0000, "NMT_MNNodeCurrState_AU8"},
1180 	{0x1F8E0001, "CurrState"},
1181 	{0x1F8F0000, "NMT_MNNodeExpState_AU8"},
1182 	{0x1F8F0001, "ExpState"},
1183 
1184 	{0x1F920000, "NMT_MNCNPResTimeout_AU32"},
1185 	{0x1F920001, "CNResTimeout"},
1186 
1187 	{0x1F930000, "NMT_EPLNodeID_REC"},
1188 	{0x1F930001, "NodeID_U8"},
1189 	{0x1F930002, "NodeIDByHW_BOOL"},
1190 	{0x1F930003, "SWNodeID_U8"},
1191 
1192 	{0x1F980000, "NMT_CycleTiming_REC"},
1193 	{0x1F980001, "IsochrTxMaxPayload_U16"},
1194 	{0x1F980002, "IsochrRxMaxPayload_U16"},
1195 	{0x1F980003, "PResMaxLatency_U32"},
1196 	{0x1F980004, "PReqActPayloadLimit_U16"},
1197 	{0x1F980005, "PResActPayloadLimit_U16"},
1198 	{0x1F980006, "ASndMaxLatency_U32"},
1199 	{0x1F980007, "MultiplCycleCnt_U8"},
1200 	{0x1F980008, "AsyncMTU_U16"},
1201 	{0x1F980009, "Prescaler_U16"},
1202 	{0x1F98000A, "PResMode_U8"},
1203 	{0x1F98000B, "PResTimeFirst_U32"},
1204 	{0x1F98000C, "PResTimeSecond_U32"},
1205 	{0x1F98000D, "SyncMNDelayFirst_U32"},
1206 	{0x1F98000E, "SyncMNDelaySecond_U32"},
1207 
1208 	{0x1F990000, "NMT_CNBasicEthernetTimeout_U32"},
1209 	{0x1F9A0000, "NMT_HostName_VSTR"},
1210 	{0x1F9B0000, "NMT_MultiplCycleAssign_AU8"},
1211 	{0x1F9B0001, "CycleNo"},
1212 	{0x1F9C0000, "NMT_IsochrSlotAssign_AU8"},
1213 	{0x1F9C0001, "NodeId"},
1214 	{0x1F9E0000, "NMT_ResetCmd_U8"},
1215 	{0x1F9F0000, "NMT_RequestCmd_REC"},
1216 	{0x1F9F0001, "Release_BOOL"},
1217 	{0x1F9F0002, "CmdID_U8"},
1218 	{0x1F9F0003, "CmdTarget_U8"},
1219 	{0x1F9F0004, "CmdData_DOM"},
1220 
1221 	{0,NULL}
1222 };
1223 
1224 static value_string_ext sod_index_names = VALUE_STRING_EXT_INIT(sod_idx_names);
1225 
1226 /* SDO - Abort Transfer */
1227 static const value_string sdo_cmd_abort_code[] = {
1228 	{0x05030000, "reserved" },
1229 	{0x05040000, "SDO protocol timed out." },
1230 	{0x05040001, "Client/server Command ID not valid or unknown." },
1231 	{0x05040002, "Invalid block size." },
1232 	{0x05040003, "Invalid sequence number." },
1233 	{0x05040004, "reserved" },
1234 	{0x05040005, "Out of memory." },
1235 	{0x06010000, "Unsupported access to an object." },
1236 	{0x06010001, "Attempt to read a write-only object." },
1237 	{0x06010002, "Attempt to write a read-only object." },
1238 	{0x06020000, "Object does not exist in the object dictionary." },
1239 	{0x06040041, "Object cannot be mapped to the PDO." },
1240 	{0x06040042, "The number and length of the objects to be mapped would exceed PDO length." },
1241 	{0x06040043, "General parameter incompatibility." },
1242 	{0x06040047, "General internal incompatibility in the device." },
1243 	{0x06060000, "Access failed due to a hardware error." },
1244 	{0x06070010, "Data type does not match, length of service parameter does not match." },
1245 	{0x06070012, "Data type does not match, length of service parameter too high." },
1246 	{0x06070013, "Data type does not match, length of service parameter too low." },
1247 	{0x06090011, "Sub-index does not exist." },
1248 	{0x06090030, "Value range of parameter exceeded (only for write access)." },
1249 	{0x06090031, "Value of parameter written too high." },
1250 	{0x06090032, "Value of parameter written too low." },
1251 	{0x06090036, "Maximum value is less then minimum value." },
1252 	{0x08000000, "General error" },
1253 	{0x08000020, "Data cannot be transferred or stored to the application." },
1254 	{0x08000021, "Data cannot be transferred or stored to the application because of local control." },
1255 	{0x08000022, "Data cannot be transferred or stored to the application because of the present device state." },
1256 	{0x08000023, "Object dictionary dynamic generation fails or no object dictionary is present." },
1257 	{0x08000024, "EDS, DCF or Concise DCF Data set empty." },
1258 	{0,NULL}
1259 };
1260 static value_string_ext sdo_cmd_abort_code_ext = VALUE_STRING_EXT_INIT(sdo_cmd_abort_code);
1261 
1262 static const value_string epl_sdo_asnd_cmd_response[] = {
1263 	{EPL_ASND_SDO_CMD_RESPONSE_RESPONSE,                    "Request"   },
1264 	{EPL_ASND_SDO_CMD_RESPONSE_REQUEST,                     "Response"  },
1265 	{0,NULL}
1266 };
1267 
1268 static const value_string epl_sdo_asnd_cmd_abort[] = {
1269 	{EPL_ASND_SDO_CMD_ABORT_TRANSFER_OK,                    "Transfer OK"    },
1270 	{EPL_ASND_SDO_CMD_ABORT_ABORT_TRANSFER,                 "Abort Transfer" },
1271 	{0,NULL}
1272 };
1273 
1274 static const value_string epl_sdo_asnd_cmd_segmentation[] = {
1275 	{EPL_ASND_SDO_CMD_SEGMENTATION_EPEDITED_TRANSFER,       "Expedited Transfer" },
1276 	{EPL_ASND_SDO_CMD_SEGMENTATION_INITIATE_TRANSFER,       "Initiate Transfer"  },
1277 	{EPL_ASND_SDO_CMD_SEGMENTATION_SEGMENT,                 "Segment"            },
1278 	{EPL_ASND_SDO_CMD_SEGMENTATION_TRANSFER_COMPLETE,       "Transfer Complete"  },
1279 	{0,NULL}
1280 };
1281 
1282 static const value_string epl_sdo_asnd_cmd_segmentation_abbr[] = {
1283 	{EPL_ASND_SDO_CMD_SEGMENTATION_EPEDITED_TRANSFER,       "EX" },
1284 	{EPL_ASND_SDO_CMD_SEGMENTATION_INITIATE_TRANSFER,       "SI"  },
1285 	{EPL_ASND_SDO_CMD_SEGMENTATION_SEGMENT,                 "ST"            },
1286 	{EPL_ASND_SDO_CMD_SEGMENTATION_TRANSFER_COMPLETE,       "SC"  },
1287 	{0,NULL}
1288 };
1289 
1290 static const value_string epl_sdo_asnd_commands[] = {
1291 	{EPL_ASND_SDO_COMMAND_NOT_IN_LIST                      , "Not in List"                       },
1292 	{EPL_ASND_SDO_COMMAND_WRITE_BY_INDEX                   , "Write by Index"                    },
1293 	{EPL_ASND_SDO_COMMAND_READ_BY_INDEX                    , "Read by Index"                     },
1294 	{EPL_ASND_SDO_COMMAND_WRITE_ALL_BY_INDEX               , "Write All by Index"                },
1295 	{EPL_ASND_SDO_COMMAND_READ_ALL_BY_INDEX                , "Read All by Index"                 },
1296 	{EPL_ASND_SDO_COMMAND_WRITE_BY_NAME                    , "Write by Name"                     },
1297 	{EPL_ASND_SDO_COMMAND_READ_BY_NAME                     , "Read by Name"                      },
1298 	{EPL_ASND_SDO_COMMAND_FILE_WRITE                       , "File Write"                        },
1299 	{EPL_ASND_SDO_COMMAND_FILE_READ                        , "File Read"                         },
1300 	{EPL_ASND_SDO_COMMAND_WRITE_MULTIPLE_PARAMETER_BY_INDEX, "Write Multiple Parameter by Index" },
1301 	{EPL_ASND_SDO_COMMAND_READ_MULTIPLE_PARAMETER_BY_INDEX , "Read Multiple Parameter by Index"  },
1302 	{EPL_ASND_SDO_COMMAND_MAXIMUM_SEGMENT_SIZE             , "Maximum Segment Size"              },
1303 	{EPL_ASND_SDO_COMMAND_LINK_NAME_TO_INDEX               , "Link objects only accessible via name to an index/sub-index"},
1304 	{0,NULL}
1305 };
1306 
1307 static value_string_ext epl_sdo_asnd_commands_ext = VALUE_STRING_EXT_INIT(epl_sdo_asnd_commands);
1308 
1309 static const value_string epl_sdo_asnd_commands_short[] = {
1310 	{EPL_ASND_SDO_COMMAND_NOT_IN_LIST                      , "NotInList"                        },
1311 	{EPL_ASND_SDO_COMMAND_WRITE_BY_INDEX                   , "WriteByIndex"                     },
1312 	{EPL_ASND_SDO_COMMAND_READ_BY_INDEX                    , "ReadByIndex"                      },
1313 	{EPL_ASND_SDO_COMMAND_WRITE_ALL_BY_INDEX               , "WriteAllByIndex"                  },
1314 	{EPL_ASND_SDO_COMMAND_READ_ALL_BY_INDEX                , "ReadAllByIndex"                   },
1315 	{EPL_ASND_SDO_COMMAND_WRITE_BY_NAME                    , "WriteByName"                      },
1316 	{EPL_ASND_SDO_COMMAND_READ_BY_NAME                     , "ReadByName"                       },
1317 	{EPL_ASND_SDO_COMMAND_FILE_WRITE                       , "FileWrite"                        },
1318 	{EPL_ASND_SDO_COMMAND_FILE_READ                        , "FileRead"                         },
1319 	{EPL_ASND_SDO_COMMAND_WRITE_MULTIPLE_PARAMETER_BY_INDEX, "WriteMultipleParam"               },
1320 	{EPL_ASND_SDO_COMMAND_READ_MULTIPLE_PARAMETER_BY_INDEX , "ReadMultipleParam"                },
1321 	{0,NULL}
1322 };
1323 
1324 
1325 static value_string_ext epl_sdo_asnd_commands_short_ext = VALUE_STRING_EXT_INIT(epl_sdo_asnd_commands_short);
1326 
1327 
1328 static const gchar* addr_str_cn  = " (Controlled Node)";
1329 static const gchar* addr_str_res = " (reserved)";
1330 
1331 struct object_mapping {
1332 	struct {
1333 		guint16 idx;
1334 		guint8 subindex;
1335 	} pdo,   /* The PDO to be mapped */
1336 	  param; /* The ObjectMapping OD entry that mapped it */
1337 
1338 	guint16 bit_offset;
1339 	guint16 no_of_bits;
1340 	int ett;
1341 	/* info */
1342 	struct {
1343 		guint32 first, last;
1344 	} frame; /* frames for which object_mapping applies */
1345 	const struct od_entry *info;
1346 	const char *index_name;
1347 	char title[32];
1348 };
1349 #define OBJECT_MAPPING_INITIALIZER { { 0, 0 }, { 0, 0 }, 0, 0, 0, { 0, 0 }, 0, 0, { 0 } }
1350 
1351 #define CONVO_FOR_RESPONSE  1
1352 #define CONVO_FOR_REQUEST   2
1353 #define CONVO_ALWAYS_CREATE 4
1354 
1355 struct read_req {
1356 	guint16 idx;
1357 	guint8 subindex;
1358 
1359 	guint8 sendsequence;
1360 
1361 	const char *index_name;
1362 	const struct od_entry *info;
1363 };
1364 
1365 struct epl_convo {
1366 	guint8 CN;
1367 
1368 	guint16 device_type;
1369 	guint32 response_time;
1370 	guint32 vendor_id;
1371 	guint32 product_code;
1372 
1373 	guint generation; /* FIXME remove */
1374 	wmem_array_t *TPDO; /* CN->MN */
1375 	wmem_array_t *RPDO; /* MN->CN */
1376 
1377 	struct profile *profile;
1378 
1379 	guint32 last_frame;
1380 	guint8 next_read_req;
1381 	guint8 seq_send;
1382 
1383 	struct read_req read_reqs[4];
1384 
1385 	/* In lieu of allocating an unknown number of read requests, we'll keep a ring
1386 	 * buff of the 4 most recent ones and when a response comes we add them as packet
1387 	 * data
1388 	 */
1389 };
1390 
1391 
1392 static gint dissect_epl_payload(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, gint len, const struct epl_datatype *type, guint8 msgType);
1393 static gint dissect_epl_soc(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset);
1394 static gint dissect_epl_preq(struct epl_convo *convo, proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset);
1395 static gint dissect_epl_pres(struct epl_convo *convo, proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset);
1396 static gint dissect_epl_soa(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset);
1397 
1398 static gint dissect_epl_asnd_ires(struct epl_convo *convo, proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset);
1399 static gint dissect_epl_asnd_sres(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset);
1400 static gint dissect_epl_asnd_nmtcmd(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset);
1401 static gint dissect_epl_asnd_nmtreq(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset);
1402 static gint dissect_epl_asnd_nmtdna(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset);
1403 static gint dissect_epl_asnd(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset);
1404 static gint dissect_epl_ainv(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset);
1405 
1406 static gint dissect_epl_asnd_sdo(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset);
1407 static gint dissect_epl_asnd_resp(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset);
1408 static gint dissect_epl_sdo_sequence(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, guint8 *seq);
1409 static gint dissect_epl_sdo_command(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, guint8 seq);
1410 static gint dissect_epl_sdo_command_write_by_index(struct epl_convo *convo, proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, guint8 segmented, gboolean response, guint16 segment_size);
1411 static gint dissect_epl_sdo_command_write_multiple_by_index(struct epl_convo *convo, proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, guint8 segmented, gboolean response, guint16 segment_size);
1412 static gint dissect_epl_sdo_command_read_by_index(struct epl_convo *convo, proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, guint8 segmented, gboolean response, guint16 segment_size);
1413 static gint dissect_epl_sdo_command_read_multiple_by_index(struct epl_convo *convo, proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, guint8 segmented, gboolean response, guint16 segment_size);
1414 static gint dissect_object_mapping(struct profile *profile, wmem_array_t *mappings, proto_tree *epl_tree, tvbuff_t *tvb, guint32 framenum, gint offset, guint16 idx, guint8 subindex);
1415 
1416 static const gchar* decode_epl_address(guchar adr);
1417 
1418 /* Initialize the protocol and registered fields */
1419 static gint proto_epl            = -1;
1420 
1421 static gint hf_epl_mtyp          = -1;
1422 static gint hf_epl_node          = -1;
1423 static gint hf_epl_dest          = -1;
1424 static gint hf_epl_src           = -1;
1425 static gint hf_epl_payload_real  = -1;
1426 
1427 /* available epl message types */
1428 static gint hf_epl_soc           = -1;
1429 static gint hf_epl_preq          = -1;
1430 static gint hf_epl_pres          = -1;
1431 static gint hf_epl_soa           = -1;
1432 static gint hf_epl_asnd          = -1;
1433 static gint hf_epl_amni          = -1;
1434 static gint hf_epl_ainv          = -1;
1435 
1436 static gint hf_epl_soc_flags     = -1;
1437 static gint hf_epl_soc_mc        = -1;
1438 static gint hf_epl_soc_ps        = -1;
1439 static gint hf_epl_soc_dna_an    = -1;
1440 static gint hf_epl_soc_nettime   = -1;
1441 static gint hf_epl_soc_relativetime = -1;
1442 
1443 static gint hf_epl_preq_flags    = -1;
1444 static gint hf_epl_preq_ms       = -1;
1445 static gint hf_epl_preq_ea       = -1;
1446 static gint hf_epl_preq_rd       = -1;
1447 static gint hf_epl_preq_sls      = -1;
1448 static gint hf_epl_preq_fls      = -1;
1449 static gint hf_epl_preq_pdov     = -1;
1450 static gint hf_epl_preq_size     = -1;
1451 
1452 static gint hf_epl_pres_stat_ms  = -1;
1453 static gint hf_epl_pres_stat_cs  = -1;
1454 static gint hf_epl_pres_flags    = -1;
1455 static gint hf_epl_pres_ms       = -1;
1456 static gint hf_epl_pres_en       = -1;
1457 static gint hf_epl_pres_rd       = -1;
1458 static gint hf_epl_pres_pr       = -1;
1459 static gint hf_epl_pres_rs       = -1;
1460 static gint hf_epl_pres_sls      = -1;
1461 static gint hf_epl_pres_fls      = -1;
1462 static gint hf_epl_pres_pdov     = -1;
1463 static gint hf_epl_pres_size     = -1;
1464 
1465 static gint hf_epl_soa_stat_ms   = -1;
1466 static gint hf_epl_soa_stat_cs   = -1;
1467 static gint hf_epl_soa_ea        = -1;
1468 static gint hf_epl_soa_er        = -1;
1469 static gint hf_epl_soa_svid      = -1;
1470 static gint hf_epl_soa_svtg      = -1;
1471 static gint hf_epl_soa_eplv      = -1;
1472 static gint hf_epl_soa_rrflags          = -1;
1473 static gint hf_epl_soa_rrflags_mnred    = -1;
1474 static gint hf_epl_soa_rrflags_cblred   = -1;
1475 static gint hf_epl_soa_rrflags_ringred  = -1;
1476 static gint hf_epl_soa_rrflags_ringstat = -1;
1477 
1478 /*SyncRequest*/
1479 static gint hf_epl_soa_sync      = -1;
1480 static gint hf_epl_soa_mac       = -1;
1481 static gint hf_epl_soa_pre_fst   = -1;
1482 static gint hf_epl_soa_pre_sec   = -1;
1483 static gint hf_epl_soa_mnd_fst   = -1;
1484 static gint hf_epl_soa_mnd_sec   = -1;
1485 static gint hf_epl_soa_pre_tm    = -1;
1486 static gint hf_epl_soa_pre_set   = -1;
1487 static gint hf_epl_soa_pre_res   = -1;
1488 static gint hf_epl_soa_mac_end   = -1;
1489 static gint hf_epl_soa_pre_fst_end   = -1;
1490 static gint hf_epl_soa_pre_sec_end   = -1;
1491 static gint hf_epl_soa_mnd_fst_end   = -1;
1492 static gint hf_epl_soa_mnd_sec_end   = -1;
1493 static gint hf_epl_soa_pre_tm_end    = -1;
1494 static gint hf_epl_soa_dna_an_glb    = -1;
1495 static gint hf_epl_soa_dna_an_lcl    = -1;
1496 
1497 /*SyncResponse*/
1498 static gint hf_epl_asnd_syncResponse_sync           = -1;
1499 static gint hf_epl_asnd_syncResponse_latency        = -1;
1500 static gint hf_epl_asnd_syncResponse_node           = -1;
1501 static gint hf_epl_asnd_syncResponse_delay          = -1;
1502 static gint hf_epl_asnd_syncResponse_pre_fst        = -1;
1503 static gint hf_epl_asnd_syncResponse_pre_sec        = -1;
1504 static gint hf_epl_asnd_syncResponse_fst_val        = -1;
1505 static gint hf_epl_asnd_syncResponse_sec_val        = -1;
1506 static gint hf_epl_asnd_syncResponse_mode           = -1;
1507 
1508 static gint hf_epl_asnd_svid      = -1;
1509 static gint hf_epl_asnd_svtg      = -1;
1510 /* static gint hf_epl_asnd_data     = -1; */
1511 
1512 /*IdentResponse*/
1513 static gint hf_epl_asnd_identresponse_en             = -1;
1514 static gint hf_epl_asnd_identresponse_ec             = -1;
1515 static gint hf_epl_asnd_identresponse_pr             = -1;
1516 static gint hf_epl_asnd_identresponse_rs             = -1;
1517 static gint hf_epl_asnd_identresponse_sls            = -1;
1518 static gint hf_epl_asnd_identresponse_fls            = -1;
1519 static gint hf_epl_asnd_identresponse_stat_ms        = -1;
1520 static gint hf_epl_asnd_identresponse_stat_cs        = -1;
1521 static gint hf_epl_asnd_identresponse_ever           = -1;
1522 static gint hf_epl_asnd_identresponse_feat           = -1;
1523 static gint hf_epl_asnd_identresponse_feat_bit0      = -1;
1524 static gint hf_epl_asnd_identresponse_feat_bit1      = -1;
1525 static gint hf_epl_asnd_identresponse_feat_bit2      = -1;
1526 static gint hf_epl_asnd_identresponse_feat_bit3      = -1;
1527 static gint hf_epl_asnd_identresponse_feat_bit4      = -1;
1528 static gint hf_epl_asnd_identresponse_feat_bit5      = -1;
1529 static gint hf_epl_asnd_identresponse_feat_bit6      = -1;
1530 static gint hf_epl_asnd_identresponse_feat_bit7      = -1;
1531 static gint hf_epl_asnd_identresponse_feat_bit8      = -1;
1532 static gint hf_epl_asnd_identresponse_feat_bit9      = -1;
1533 static gint hf_epl_asnd_identresponse_feat_bitA      = -1;
1534 static gint hf_epl_asnd_identresponse_feat_bitB      = -1;
1535 static gint hf_epl_asnd_identresponse_feat_bitC      = -1;
1536 static gint hf_epl_asnd_identresponse_feat_bitD      = -1;
1537 static gint hf_epl_asnd_identresponse_feat_bitE      = -1;
1538 static gint hf_epl_asnd_identresponse_feat_bitF      = -1;
1539 static gint hf_epl_asnd_identresponse_feat_bit10     = -1;
1540 static gint hf_epl_asnd_identresponse_feat_bit11     = -1;
1541 static gint hf_epl_asnd_identresponse_feat_bit12     = -1;
1542 static gint hf_epl_asnd_identresponse_feat_bit13     = -1;
1543 static gint hf_epl_asnd_identresponse_feat_bit14     = -1;
1544 static gint hf_epl_asnd_identresponse_feat_bit21     = -1;
1545 static gint hf_epl_asnd_identresponse_mtu            = -1;
1546 static gint hf_epl_asnd_identresponse_pis            = -1;
1547 static gint hf_epl_asnd_identresponse_pos            = -1;
1548 static gint hf_epl_asnd_identresponse_rst            = -1;
1549 static gint hf_epl_asnd_identresponse_dt             = -1;
1550 static gint hf_epl_asnd_identresponse_dt_add         = -1;
1551 static gint hf_epl_asnd_identresponse_vid            = -1;
1552 static gint hf_epl_asnd_identresponse_productcode    = -1;
1553 static gint hf_epl_asnd_identresponse_rno            = -1;
1554 static gint hf_epl_asnd_identresponse_sno            = -1;
1555 static gint hf_epl_asnd_identresponse_vex1           = -1;
1556 static gint hf_epl_asnd_identresponse_vcd            = -1;
1557 static gint hf_epl_asnd_identresponse_vct            = -1;
1558 static gint hf_epl_asnd_identresponse_ad             = -1;
1559 static gint hf_epl_asnd_identresponse_at             = -1;
1560 static gint hf_epl_asnd_identresponse_ipa            = -1;
1561 static gint hf_epl_asnd_identresponse_snm            = -1;
1562 static gint hf_epl_asnd_identresponse_gtw            = -1;
1563 static gint hf_epl_asnd_identresponse_hn             = -1;
1564 static gint hf_epl_asnd_identresponse_vex2           = -1;
1565 
1566 /*StatusResponse*/
1567 static gint hf_epl_asnd_statusresponse_en            = -1;
1568 static gint hf_epl_asnd_statusresponse_ec            = -1;
1569 static gint hf_epl_asnd_statusresponse_pr            = -1;
1570 static gint hf_epl_asnd_statusresponse_rs            = -1;
1571 static gint hf_epl_asnd_statusresponse_sls           = -1;
1572 static gint hf_epl_asnd_statusresponse_fls           = -1;
1573 static gint hf_epl_asnd_statusresponse_stat_ms       = -1;
1574 static gint hf_epl_asnd_statusresponse_stat_cs       = -1;
1575 /* static gint hf_epl_asnd_statusresponse_seb           = -1; */
1576 
1577 /*StaticErrorBitField */
1578 static gint hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit0 = -1;
1579 static gint hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit1 = -1;
1580 static gint hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit2 = -1;
1581 static gint hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit3 = -1;
1582 static gint hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit4 = -1;
1583 static gint hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit5 = -1;
1584 static gint hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit7 = -1;
1585 static gint hf_epl_asnd_statusresponse_seb_devicespecific_err        = -1;
1586 
1587 /*List of Errors/Events*/
1588 /* static gint hf_epl_asnd_statusresponse_el                    = -1; */
1589 /* static gint hf_epl_asnd_statusresponse_el_entry              = -1; */
1590 static gint hf_epl_asnd_statusresponse_el_entry_type         = -1;
1591 static gint hf_epl_asnd_statusresponse_el_entry_type_profile = -1;
1592 static gint hf_epl_asnd_statusresponse_el_entry_type_mode    = -1;
1593 static gint hf_epl_asnd_statusresponse_el_entry_type_bit14   = -1;
1594 static gint hf_epl_asnd_statusresponse_el_entry_type_bit15   = -1;
1595 static gint hf_epl_asnd_statusresponse_el_entry_code         = -1;
1596 static gint hf_epl_asnd_statusresponse_el_entry_time         = -1;
1597 static gint hf_epl_asnd_statusresponse_el_entry_add          = -1;
1598 
1599 /*NMTRequest*/
1600 static gint hf_epl_asnd_nmtrequest_rcid                      = -1;
1601 static gint hf_epl_asnd_nmtrequest_rct                       = -1;
1602 static gint hf_epl_asnd_nmtrequest_rcd                       = -1;
1603 
1604 /*NMTCommand*/
1605 static gint hf_epl_asnd_nmtcommand_cid                       = -1;
1606 static gint hf_epl_asnd_nmtcommand_cdat                      = -1;
1607 static gint hf_epl_asnd_nmtcommand_resetnode_reason           = -1;
1608 /*static gint hf_epl_asnd_nmtcommand_nmtnetparameterset_mtu    = -1;*/
1609 static gint hf_epl_asnd_nmtcommand_nmtnethostnameset_hn      = -1;
1610 static gint hf_epl_asnd_nmtcommand_nmtflusharpentry_nid      = -1;
1611 static gint hf_epl_asnd_nmtcommand_nmtpublishtime_dt         = -1;
1612 static gint hf_epl_asnd_nmtcommand_nmtdna                    = -1;
1613 static gint hf_epl_asnd_nmtcommand_nmtdna_flags              = -1;
1614 static gint hf_epl_asnd_nmtcommand_nmtdna_ltv                = -1;
1615 static gint hf_epl_asnd_nmtcommand_nmtdna_hpm                = -1;
1616 static gint hf_epl_asnd_nmtcommand_nmtdna_nnn                = -1;
1617 static gint hf_epl_asnd_nmtcommand_nmtdna_mac                = -1;
1618 static gint hf_epl_asnd_nmtcommand_nmtdna_cnn                = -1;
1619 static gint hf_epl_asnd_nmtcommand_nmtdna_currmac            = -1;
1620 static gint hf_epl_asnd_nmtcommand_nmtdna_hubenmsk           = -1;
1621 static gint hf_epl_asnd_nmtcommand_nmtdna_currnn             = -1;
1622 static gint hf_epl_asnd_nmtcommand_nmtdna_newnn              = -1;
1623 static gint hf_epl_asnd_nmtcommand_nmtdna_leasetime          = -1;
1624 
1625 
1626 /*Asynchronuous SDO Sequence Layer*/
1627 static gint hf_epl_asnd_sdo_seq                              = -1;
1628 static gint hf_epl_asnd_sdo_seq_receive_sequence_number      = -1;
1629 static gint hf_epl_asnd_sdo_seq_receive_con                  = -1;
1630 static gint hf_epl_asnd_sdo_seq_send_sequence_number         = -1;
1631 static gint hf_epl_asnd_sdo_seq_send_con                     = -1;
1632 
1633 /*Asynchronuous SDO Command Layer*/
1634 static gint hf_epl_asnd_sdo_cmd                              = -1;
1635 static gint hf_epl_asnd_sdo_cmd_transaction_id               = -1;
1636 static gint hf_epl_asnd_sdo_cmd_response                     = -1;
1637 
1638 #if 0
1639 static gint hf_epl_asnd_sdo_resp_in                          = -1;
1640 static gint hf_epl_asnd_sdo_no_resp                          = -1;
1641 static gint hf_epl_asnd_sdo_resp_to                          = -1;
1642 #endif
1643 
1644 static gint hf_epl_asnd_sdo_cmd_abort                        = -1;
1645 static gint hf_epl_asnd_sdo_cmd_sub_abort                    = -1;
1646 static gint hf_epl_asnd_sdo_cmd_segmentation                 = -1;
1647 static gint hf_epl_asnd_sdo_cmd_command_id                   = -1;
1648 static gint hf_epl_asnd_sdo_cmd_segment_size                 = -1;
1649 
1650 static gint hf_epl_asnd_sdo_cmd_data_size                    = -1;
1651 static gint hf_epl_asnd_sdo_cmd_data_padding                 = -1;
1652 static gint hf_epl_asnd_sdo_cmd_data_index                   = -1;
1653 static gint hf_epl_asnd_sdo_cmd_data_subindex                = -1;
1654 static gint hf_epl_asnd_sdo_cmd_data_mapping                 = -1;
1655 static gint hf_epl_asnd_sdo_cmd_data_mapping_index           = -1;
1656 static gint hf_epl_asnd_sdo_cmd_data_mapping_subindex        = -1;
1657 static gint hf_epl_asnd_sdo_cmd_data_mapping_offset          = -1;
1658 static gint hf_epl_asnd_sdo_cmd_data_mapping_length          = -1;
1659 /*static gint hf_epl_asnd_sdo_cmd_data_response      = -1;*/
1660 
1661 static gint hf_epl_asnd_sdo_cmd_reassembled                  = -1;
1662 static gint hf_epl_fragments                                 = -1;
1663 static gint hf_epl_fragment                                  = -1;
1664 static gint hf_epl_fragment_overlap                          = -1;
1665 static gint hf_epl_fragment_overlap_conflicts                = -1;
1666 static gint hf_epl_fragment_multiple_tails                   = -1;
1667 static gint hf_epl_fragment_too_long_fragment                = -1;
1668 static gint hf_epl_fragment_error                            = -1;
1669 static gint hf_epl_fragment_count                            = -1;
1670 static gint hf_epl_reassembled_in                            = -1;
1671 static gint hf_epl_reassembled_length                        = -1;
1672 static gint hf_epl_reassembled_data                          = -1;
1673 static gint hf_epl_sdo_multi_param_sub_abort                 = -1;
1674 
1675 static gint hf_epl_asnd_identresponse_profile_path = -1;
1676 
1677 /* EPL OD Data Types */
1678 static gint hf_epl_pdo                = -1;
1679 static gint hf_epl_pdo_index          = -1;
1680 static gint hf_epl_pdo_subindex       = -1;
1681 
1682 static gint hf_epl_od_meta                  = -1;
1683 static gint hf_epl_od_meta_mapping_index    = -1;
1684 static gint hf_epl_od_meta_mapping_subindex = -1;
1685 static gint hf_epl_od_meta_lifetime_start   = -1;
1686 static gint hf_epl_od_meta_lifetime_end     = -1;
1687 static gint hf_epl_od_meta_offset           = -1;
1688 static gint hf_epl_od_meta_length           = -1;
1689 
1690 static gint hf_epl_od_boolean      = -1;
1691 static gint hf_epl_od_int          = -1;
1692 static gint hf_epl_od_uint         = -1;
1693 static gint hf_epl_od_real         = -1;
1694 static gint hf_epl_od_string       = -1;
1695 static gint hf_epl_od_octet_string = -1;
1696 static gint hf_epl_od_time         = -1;
1697 #if 0
1698 static gint hf_epl_od_time_difference = -1;
1699 static gint hf_epl_od_domain     = -1;
1700 #endif
1701 static gint hf_epl_od_mac        = -1;
1702 static gint hf_epl_od_ipv4       = -1;
1703 
1704 #define EPL_PDO_TYPE_COUNT 8
1705 
1706 static const struct epl_datatype {
1707 	const char *name;
1708 	gint *hf;
1709 	guint encoding;
1710 	guint8 len;
1711 } epl_datatype[] = {
1712 	{ "Boolean",    &hf_epl_od_boolean, ENC_LITTLE_ENDIAN , 1 },
1713 	/* integer types */
1714 	{ "Integer8",   &hf_epl_od_int, ENC_LITTLE_ENDIAN, 1 },
1715 	{ "Integer16",  &hf_epl_od_int, ENC_LITTLE_ENDIAN, 2 },
1716 	{ "Integer24",  &hf_epl_od_int, ENC_LITTLE_ENDIAN, 3 },
1717 	{ "Integer32",  &hf_epl_od_int, ENC_LITTLE_ENDIAN, 4 },
1718 	{ "Integer40",  &hf_epl_od_int, ENC_LITTLE_ENDIAN, 5 },
1719 	{ "Integer48",  &hf_epl_od_int, ENC_LITTLE_ENDIAN, 6 },
1720 	{ "Integer56",  &hf_epl_od_int, ENC_LITTLE_ENDIAN, 7 },
1721 	{ "Integer64",  &hf_epl_od_int, ENC_LITTLE_ENDIAN, 8 },
1722 
1723 	{ "Unsigned8",  &hf_epl_od_uint, ENC_LITTLE_ENDIAN, 1 },
1724 	{ "Unsigned16", &hf_epl_od_uint, ENC_LITTLE_ENDIAN, 2 },
1725 	{ "Unsigned24", &hf_epl_od_uint, ENC_LITTLE_ENDIAN, 3 },
1726 	{ "Unsigned32", &hf_epl_od_uint, ENC_LITTLE_ENDIAN, 4 },
1727 	{ "Unsigned40", &hf_epl_od_uint, ENC_LITTLE_ENDIAN, 5 },
1728 	{ "Unsigned48", &hf_epl_od_uint, ENC_LITTLE_ENDIAN, 6 },
1729 	{ "Unsigned56", &hf_epl_od_uint, ENC_LITTLE_ENDIAN, 7 },
1730 	{ "Unsigned64", &hf_epl_od_uint, ENC_LITTLE_ENDIAN, 8 },
1731 
1732 	/* non-integer types */
1733 	{ "Real32",         &hf_epl_od_real,    ENC_LITTLE_ENDIAN, 4 },
1734 	{ "Real64",         &hf_epl_od_real,    ENC_LITTLE_ENDIAN, 8 },
1735 	{ "Visible_String", &hf_epl_od_string,  ENC_ASCII, 0 },
1736 	{ "Octet_String",   &hf_epl_od_octet_string,    ENC_NA, 0 },
1737 	{ "Unicode_String", &hf_epl_od_string,  ENC_UCS_2 | ENC_LITTLE_ENDIAN, 0 },
1738 
1739 	{ "MAC_ADDRESS",    &hf_epl_od_mac,    ENC_BIG_ENDIAN, 6 },
1740 	{ "IP_ADDRESS",     &hf_epl_od_ipv4,   ENC_BIG_ENDIAN, 4 },
1741 #if 0
1742 	{ "Domain",         &hf_epl_od_domain, ENC_NA  },
1743 
1744 	{ "Time_of_Day",    &hf_epl_od_time,    ENC_NA },
1745 	{ "Time_Diff",      &hf_epl_od_time_difference, ENC_NA  },
1746 #endif
1747 	{ "NETTIME",        &hf_epl_od_time, ENC_TIME_SECS_NSECS, 8 },
1748 
1749 	{ 0, 0, 0, 0 }
1750 };
1751 
1752 
1753 static gint ett_epl_fragment                                 = -1;
1754 static gint ett_epl_fragments                                = -1;
1755 
1756 static const fragment_items epl_frag_items = {
1757 	/* Fragment subtrees */
1758 	&ett_epl_fragment,
1759 	&ett_epl_fragments,
1760 	/* Fragment fields */
1761 	&hf_epl_fragments,
1762 	&hf_epl_fragment,
1763 	&hf_epl_fragment_overlap,
1764 	&hf_epl_fragment_overlap_conflicts,
1765 	&hf_epl_fragment_multiple_tails,
1766 	&hf_epl_fragment_too_long_fragment,
1767 	&hf_epl_fragment_error,
1768 	&hf_epl_fragment_count,
1769 	/* Reassembled in field */
1770 	&hf_epl_reassembled_in,
1771 	/* Reassembled length field */
1772 	&hf_epl_reassembled_length,
1773 	/* Reassembled data */
1774 	&hf_epl_reassembled_data,
1775 	/* Tag */
1776 	"Message fragments"
1777 };
1778 
1779 static gint hf_epl_asnd_sdo_cmd_abort_code                   = -1;
1780 #if 0
1781 static gint hf_epl_asnd_sdo_cmd_abort_flag                   = -1;
1782 static gint hf_epl_asnd_sdo_cmd_segmentation_flag            = -1;
1783 static gint hf_epl_asnd_sdo_cmd_cmd_valid_test               = -1;
1784 
1785 static gint hf_epl_asnd_sdo_actual_command_id                = -1;
1786 
1787 static gint hf_epl_asnd_sdo_actual_segment_size              = -1;
1788 static gint hf_epl_asnd_sdo_actual_payload_size_read         = -1;
1789 #endif
1790 
1791 /* Initialize the subtree pointers */
1792 static gint ett_epl                 = -1;
1793 static gint ett_epl_soc             = -1;
1794 static gint ett_epl_preq            = -1;
1795 static gint ett_epl_pres            = -1;
1796 static gint ett_epl_feat            = -1;
1797 static gint ett_epl_seb             = -1;
1798 static gint ett_epl_el              = -1;
1799 static gint ett_epl_el_entry        = -1;
1800 static gint ett_epl_el_entry_type   = -1;
1801 static gint ett_epl_sdo_entry_type  = -1;
1802 static gint ett_epl_asnd_nmt_dna    = -1;
1803 
1804 static gint ett_epl_sdo                       = -1;
1805 static gint ett_epl_sdo_sequence_layer        = -1;
1806 static gint ett_epl_sdo_command_layer         = -1;
1807 static gint ett_epl_sdo_data                  = -1;
1808 static gint ett_epl_asnd_sdo_cmd_data_mapping = -1;
1809 static gint ett_epl_soa_sync                  = -1;
1810 static gint ett_epl_asnd_sync                 = -1;
1811 
1812 static gint ett_epl_pdo_meta                  = -1;
1813 
1814 static expert_field ei_duplicated_frame       = EI_INIT;
1815 static expert_field ei_recvseq_value          = EI_INIT;
1816 static expert_field ei_sendseq_value          = EI_INIT;
1817 static expert_field ei_real_length_differs    = EI_INIT;
1818 
1819 static dissector_handle_t epl_handle;
1820 
1821 static gboolean show_cmd_layer_for_duplicated = FALSE;
1822 static gboolean show_pdo_meta_info = FALSE;
1823 static gboolean use_xdc_mappings = TRUE;
1824 static gboolean interpret_untyped_as_le = TRUE;
1825 static gboolean use_sdo_mappings = TRUE;
1826 
1827 static gint ett_epl_asnd_sdo_data_reassembled = -1;
1828 
1829 static reassembly_table epl_reassembly_table;
1830 static GHashTable *epl_duplication_table = NULL;
1831 
1832 const struct
1833 epl_datatype *epl_type_to_hf(const char *name)
1834 {
1835 	const struct epl_datatype *entry;
1836 	for (entry = epl_datatype; entry->name; entry++)
1837 	{
1838 		if (strcmp(name, entry->name) == 0)
1839 			return entry;
1840 	}
1841 	return NULL;
1842 }
1843 
1844 static guint
1845 epl_address_hash(gconstpointer a)
1846 {
1847 	return add_address_to_hash(0, (const address*)a);
1848 }
1849 static gboolean
1850 epl_address_equal(gconstpointer a, gconstpointer b)
1851 {
1852 	return addresses_equal((const address*)a, (const address*)b);
1853 }
1854 
1855 /* FIXME
1856  * PDO Mappings store object/subobjct pointers and thus need to be
1857  * updated after a profile change. We purge them by resetting the
1858  * memory pool. As PDO Mappings are refereneced via Conversations,
1859  * we need to fix up those too. I didn't figure out how to clear
1860  * conversations yet, so till now, we keep a variable to tell us
1861  * if we have dangling pointers. Courtesy of Peter Wu.
1862  */
1863 
1864 guint current_convo_generation = 0; /* FIXME remove */
1865 static wmem_allocator_t *pdo_mapping_scope;
1866 static struct object_mapping *
1867 get_object_mappings(wmem_array_t *arr, guint *len)
1868 {
1869 	*len = wmem_array_get_count(arr);
1870 	return (struct object_mapping*)wmem_array_get_raw(arr);
1871 }
1872 static int
1873 object_mapping_cmp(const void *_a, const void *_b)
1874 {
1875 	const struct object_mapping *a = (const struct object_mapping*)_a;
1876 	const struct object_mapping *b = (const struct object_mapping*)_b;
1877 
1878 	if (a->bit_offset < b->bit_offset) return -1;
1879 	if (a->bit_offset > b->bit_offset) return +1;
1880 	return 0;
1881 }
1882 static gboolean
1883 object_mapping_eq(struct object_mapping *a, struct object_mapping *b)
1884 {
1885 	return a->pdo.idx == b->pdo.idx
1886 	    && a->pdo.subindex == b->pdo.subindex
1887 	    && a->frame.first == b->frame.first
1888 	    && a->param.idx == b->param.idx
1889 	    && a->param.subindex == b->param.subindex;
1890 }
1891 static guint
1892 add_object_mapping(wmem_array_t *arr, struct object_mapping *mapping)
1893 {
1894 	/* let's check if this overwrites an existing mapping */
1895 	guint i, len;
1896 	/* A bit ineffecient (looping backwards would be better), but it's acyclic anyway */
1897 	struct object_mapping *old = get_object_mappings(arr, &len);
1898 	for (i = 0; i < len; i++)
1899 	{
1900 		if (object_mapping_eq(&old[i], mapping))
1901 			return len;
1902 
1903 		if (old[i].frame.first < mapping->frame.first
1904 		  && (CHECK_OVERLAP_LENGTH(old[i].bit_offset, old[i].no_of_bits, mapping->bit_offset, mapping->no_of_bits)
1905 		  || (old[i].param.idx == mapping->param.idx && old[i].param.subindex == mapping->param.subindex
1906 		  && CHECK_OVERLAP_ENDS(old[i].frame.first, old[i].frame.last, mapping->frame.first, mapping->frame.last))))
1907 		{
1908 			old[i].frame.last = mapping->frame.first;
1909 		}
1910 	}
1911 
1912 	wmem_array_append(arr, mapping, 1);
1913 	wmem_array_sort(arr, object_mapping_cmp);
1914 	return len + 1;
1915 }
1916 
1917 static wmem_map_t *epl_profiles_by_device, *epl_profiles_by_nodeid, *epl_profiles_by_address;
1918 static struct profile *epl_default_profile;
1919 static const char *epl_default_profile_path = NULL, *epl_default_profile_path_last = NULL;
1920 
1921 static gboolean
1922 profile_del_cb(wmem_allocator_t *pool _U_, wmem_cb_event_t event _U_, void *_profile)
1923 {
1924 	struct profile *profile = (struct profile*)_profile;
1925 	if (profile->parent_map)
1926 		wmem_map_remove(profile->parent_map, profile->data);
1927 	wmem_destroy_allocator(profile->scope);
1928 	return FALSE;
1929 }
1930 
1931 static void
1932 profile_del(struct profile *profile)
1933 {
1934 	if (!profile) return;
1935 	wmem_unregister_callback(profile->parent_scope, profile->cb_id);
1936 	profile_del_cb(NULL, WMEM_CB_DESTROY_EVENT, profile);
1937 }
1938 
1939 static struct profile *
1940 profile_new(wmem_allocator_t *parent_pool)
1941 {
1942 	wmem_allocator_t *pool;
1943 	struct profile *profile;
1944 
1945 	pool = wmem_allocator_new(WMEM_ALLOCATOR_SIMPLE);
1946 	profile = wmem_new0(pool, struct profile);
1947 	profile->cb_id = wmem_register_callback(parent_pool, profile_del_cb, profile);
1948 
1949 	profile->scope        = pool;
1950 	profile->parent_scope = parent_pool;
1951 	profile->parent_map   = NULL;
1952 	profile->objects      = wmem_map_new(pool, g_direct_hash, g_direct_equal);
1953 	profile->name         = NULL;
1954 	profile->path         = NULL;
1955 	profile->RPDO         = wmem_array_new(pool, sizeof (struct object_mapping));
1956 	profile->TPDO         = wmem_array_new(pool, sizeof (struct object_mapping));
1957 	profile->next         = NULL;
1958 
1959 	return profile;
1960 }
1961 
1962 static struct object *object_lookup(struct profile *profile, guint16 idx);
1963 static const struct subobject *subobject_lookup(struct object *obj, guint8 subindex);
1964 
1965 struct object *
1966 epl_profile_object_add(struct profile *profile, guint16 idx)
1967 {
1968 	struct object *object = wmem_new0(profile->scope, struct object);
1969 
1970 	object->info.idx = idx;
1971 
1972 	wmem_map_insert(profile->objects, GUINT_TO_POINTER(object->info.idx), object);
1973 	return object;
1974 }
1975 
1976 struct object *
1977 epl_profile_object_lookup_or_add(struct profile *profile, guint16 idx)
1978 {
1979 	struct object *obj = object_lookup(profile, idx);
1980 	return obj ? obj : epl_profile_object_add(profile, idx);
1981 }
1982 
1983 
1984 gboolean
1985  epl_profile_object_mapping_add(struct profile *profile, guint16 idx, guint8 subindex, guint64 mapping)
1986 {
1987 	wmem_array_t *mappings;
1988 	tvbuff_t *tvb;
1989 	guint64 mapping_le;
1990 
1991 	if (!use_xdc_mappings)
1992 		return FALSE;
1993 
1994 	if(idx == EPL_SOD_PDO_RX_MAPP && subindex >= 0x01 && subindex <= 0xfe)
1995 		mappings = profile->RPDO;
1996 	else if (idx == EPL_SOD_PDO_TX_MAPP && subindex >= 0x01 && subindex <= 0xfe)
1997 		mappings = profile->TPDO;
1998 	else
1999 		return FALSE;
2000 
2001 	mapping_le = GUINT64_TO_LE(mapping);
2002 	tvb = tvb_new_real_data((guint8*)&mapping_le, sizeof mapping_le, sizeof mapping_le);
2003 
2004 	return dissect_object_mapping(profile, mappings, NULL, tvb, 0, 0, idx, subindex) == EPL_OBJECT_MAPPING_SIZE;
2005 }
2006 
2007 gboolean
2008 epl_profile_object_mappings_update(struct profile *profile)
2009 {
2010 	gboolean updated_any = FALSE;
2011 	struct object_mapping *mappings;
2012 	wmem_array_t *PDOs[3], **PDO;
2013 
2014 	if (!use_xdc_mappings)
2015 		return FALSE;
2016 
2017 
2018 	PDOs[0] = profile->RPDO;
2019 	PDOs[1] = profile->TPDO;
2020 	PDOs[2] = NULL;
2021 
2022 	for (PDO = PDOs; *PDO; PDO++)
2023 	{
2024 		guint i, len;
2025 		len = wmem_array_get_count(*PDO);
2026 		mappings = (struct object_mapping*)wmem_array_get_raw(*PDO);
2027 
2028 		for (i = 0; i < len; i++)
2029 		{
2030 			struct object_mapping *map = &mappings[i];
2031 			struct object *mapping_obj;
2032 			const struct subobject *mapping_subobj;
2033 
2034 			if (!(mapping_obj = object_lookup(profile, map->pdo.idx)))
2035 				continue;
2036 			map->info = &mapping_obj->info;
2037 			map->index_name = map->info->name;
2038 			updated_any = TRUE;
2039 			if (!(mapping_subobj = subobject_lookup(mapping_obj, map->pdo.subindex)))
2040 				continue;
2041 			map->info = &mapping_subobj->info;
2042 		}
2043 	}
2044 
2045 	return updated_any;
2046 }
2047 
2048 static struct read_req *
2049 convo_read_req_get(struct epl_convo *convo, packet_info *pinfo, guint8 SendSequenceNumber)
2050 {
2051 	guint i;
2052 	guint32 seq_p_key = (ETHERTYPE_EPL_V2 << 16) | convo->seq_send;
2053 	struct read_req *req = (struct read_req*)p_get_proto_data(wmem_file_scope(), pinfo, proto_epl, seq_p_key);
2054 
2055 	if (req)
2056 		return req;
2057 
2058 	for (i = 0; i < array_length(convo->read_reqs); i++)
2059 	{
2060 		if(convo->read_reqs[i].sendsequence == SendSequenceNumber)
2061 		{
2062 			req = wmem_new(wmem_file_scope(), struct read_req);
2063 			*req = convo->read_reqs[i];
2064 			p_add_proto_data(wmem_file_scope(), pinfo, proto_epl, seq_p_key, req);
2065 			return req;
2066 		}
2067 	}
2068 
2069 	return NULL;
2070 }
2071 static struct read_req *
2072 convo_read_req_set(struct epl_convo *convo, guint8 SendSequenceNumber)
2073 {
2074 	struct read_req *slot = &convo->read_reqs[convo->next_read_req++];
2075 	convo->next_read_req %= array_length(convo->read_reqs);
2076 	slot->sendsequence = SendSequenceNumber;
2077 	return slot;
2078 }
2079 
2080 
2081 static int
2082 dissect_epl_pdo(struct epl_convo *convo, proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, guint offset, guint len, guint8 msgType)
2083 {
2084 	wmem_array_t *mapping = msgType == EPL_PRES ? convo->TPDO : convo->RPDO;
2085 	tvbuff_t *payload_tvb;
2086 	guint rem_len, payload_len, payload_len_bits;
2087 	heur_dtbl_entry_t *hdtbl_entry = NULL;
2088 	proto_item *item;
2089 	guint i, maps_count;
2090 	guint off = 0;
2091 
2092 	struct object_mapping *mappings = get_object_mappings(mapping, &maps_count);
2093 
2094 	if (len <= 0)
2095 		return offset;
2096 
2097 	rem_len = tvb_captured_length_remaining(tvb, offset);
2098 	payload_tvb = tvb_new_subset_length(tvb, offset, MIN(len, rem_len));
2099 	payload_len = tvb_captured_length_remaining(payload_tvb, 0);
2100 	payload_len_bits = payload_len * 8;
2101 	if ( payload_len < len )
2102 	{
2103 		item = proto_tree_add_uint(epl_tree, hf_epl_payload_real, tvb, offset, payload_len, payload_len);
2104 		proto_item_set_generated(item);
2105 		expert_add_info(pinfo, item, &ei_real_length_differs );
2106 	}
2107 
2108 	if ( dissector_try_heuristic(heur_epl_data_subdissector_list, payload_tvb, pinfo, epl_tree, &hdtbl_entry, &msgType))
2109 		return offset + payload_len;
2110 
2111 
2112 	for (i = 0; i < maps_count; i++)
2113 	{
2114 		proto_tree *pdo_tree;
2115 		struct object_mapping *map = &mappings[i];
2116 		guint willbe_offset_bits = map->bit_offset + map->no_of_bits;
2117 
2118 		if (!(map->frame.first < pinfo->num && pinfo->num < map->frame.last))
2119 			continue;
2120 
2121 		if (willbe_offset_bits > payload_len_bits)
2122 			break;
2123 
2124 		item = proto_tree_add_string_format(epl_tree, hf_epl_pdo, payload_tvb, 0, 0, "", "%s", map->title);
2125 		pdo_tree = proto_item_add_subtree(item, map->ett);
2126 
2127 		item = proto_tree_add_uint_format_value(pdo_tree, hf_epl_pdo_index, payload_tvb, 0, 0, map->pdo.idx, "%04X", map->pdo.idx);
2128 		proto_item_set_generated(item);
2129 		if (map->info)
2130 			proto_item_append_text (item, " (%s)", map->index_name);
2131 
2132 		item = proto_tree_add_uint_format_value(pdo_tree, hf_epl_pdo_subindex, payload_tvb, 0, 0, map->pdo.subindex, "%02X", map->pdo.subindex);
2133 		proto_item_set_generated(item);
2134 
2135 		if (map->info && map->info->name != map->index_name)
2136 			proto_item_append_text (item, " (%s)", map->info->name);
2137 
2138 		if (show_pdo_meta_info)
2139 		{
2140 			proto_tree *meta_tree;
2141 			proto_item *meta_item = proto_tree_add_item(pdo_tree, hf_epl_od_meta, tvb, offset, 0, ENC_NA);
2142 			meta_tree = proto_item_add_subtree(meta_item, ett_epl_pdo_meta);
2143 
2144 			proto_tree_add_uint(meta_tree, hf_epl_od_meta_mapping_index, tvb, 0, 0, map->param.idx);
2145 			proto_tree_add_uint(meta_tree, hf_epl_od_meta_mapping_subindex, tvb, 0, 0, map->param.subindex);
2146 			proto_tree_add_uint(meta_tree, hf_epl_od_meta_lifetime_start, tvb, 0, 0, map->frame.first);
2147 
2148 			if (map->frame.last != G_MAXUINT32)
2149 				proto_tree_add_uint(meta_tree, hf_epl_od_meta_lifetime_end, tvb, 0, 0, map->frame.last);
2150 
2151 			item = proto_tree_add_uint(meta_tree, hf_epl_od_meta_offset, tvb, 0, 0, map->bit_offset);
2152 			proto_item_append_text (item, " bits");
2153 			item = proto_tree_add_uint(meta_tree, hf_epl_od_meta_length, tvb, 0, 0, map->no_of_bits);
2154 			proto_item_append_text (item, " bits");
2155 
2156 
2157 			proto_item_set_generated(meta_item);
2158 		}
2159 
2160 		dissect_epl_payload(
2161 				pdo_tree,
2162 				tvb_new_octet_aligned(payload_tvb, map->bit_offset, map->no_of_bits),
2163 				pinfo, 0, map->no_of_bits / 8, map->info ? map->info->type : NULL, msgType
2164 		);
2165 
2166 		payload_len -= map->no_of_bits / 8;
2167 
2168 		off = willbe_offset_bits / 8;
2169 	}
2170 
2171 	/* If we don't have more information, resort to data dissector */
2172 	if (tvb_captured_length_remaining(payload_tvb, off))
2173 	{
2174 		return dissect_epl_payload(epl_tree, payload_tvb, pinfo, off, payload_len, NULL, msgType);
2175 	}
2176 	return offset + payload_len;
2177 }
2178 
2179 static guint8 epl_placeholder_mac_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
2180 static address epl_placeholder_mac = ADDRESS_INIT(AT_ETHER, 6, epl_placeholder_mac_addr);
2181 
2182 static struct epl_convo *
2183 epl_get_convo(packet_info *pinfo, int opts)
2184 {
2185 	struct epl_convo *convo;
2186 	conversation_t * epan_convo;
2187 	guint32 node_port;
2188 	address *node_addr = &epl_placeholder_mac;
2189 	address *node_dl_addr = &epl_placeholder_mac;
2190 
2191 	if (opts & CONVO_FOR_REQUEST)
2192 	{
2193 		node_port = pinfo->destport;
2194 
2195 #if 0
2196 		if (pinfo->dst.type == AT_IPv4 || pinfo->dst.type == AT_ETHER)
2197 			node_addr = &pinfo->dst;
2198 #endif
2199 		if (pinfo->dl_dst.type == AT_ETHER)
2200 			node_dl_addr = &pinfo->dl_dst;
2201 	}
2202 	else
2203 	{
2204 		node_port = pinfo->srcport;
2205 
2206 #if 0
2207 		if (pinfo->src.type == AT_IPv4 || pinfo->src.type == AT_ETHER)
2208 			node_addr = &pinfo->src;
2209 #endif
2210 		if (pinfo->dl_src.type == AT_ETHER)
2211 			node_dl_addr = &pinfo->dl_src;
2212 	}
2213 	/* It'd be better to consult the Ethernet or IP address when matching conversations,
2214 	 * but an ASnd request is targeted at a Multicast MAC address, so we'll use
2215 	 * a constant address for lookup
2216 	 * TODO: If you, the reader, figure out a way to lookup a conversation by port only
2217 	 * remove the following assignment
2218 	 */
2219 	node_addr = &epl_placeholder_mac;
2220 
2221 	if ((epan_convo = find_conversation(pinfo->num, node_addr, node_addr,
2222 				conversation_pt_to_endpoint_type(pinfo->ptype), node_port, node_port, NO_ADDR_B|NO_PORT_B)))
2223 	{
2224 		/* XXX Do I need to check setup_frame != pinfo->num in order to not
2225 		 * create unnecessary new conversations?
2226 		 * if not, move the CONVO_ALWAYS_CREATE check up into the if and drop
2227 		 * the goto
2228 		 */
2229 		if ((opts & CONVO_ALWAYS_CREATE) && epan_convo->setup_frame != pinfo->num)
2230 			goto new_convo_creation;
2231 
2232 		if (pinfo->num > epan_convo->last_frame)
2233 			epan_convo->last_frame = pinfo->num;
2234 	}
2235 	else
2236 	{
2237 new_convo_creation:
2238 		epan_convo = conversation_new(pinfo->num, node_addr, node_addr,
2239 				conversation_pt_to_endpoint_type(pinfo->ptype), node_port, node_port, NO_ADDR2|NO_PORT2);
2240 	}
2241 
2242 	convo = (struct epl_convo*)conversation_get_proto_data(epan_convo, proto_epl);
2243 
2244 	if (convo == NULL)
2245 	{
2246 		convo = wmem_new0(wmem_file_scope(), struct epl_convo);
2247 		convo->CN = (guint8)node_port;
2248 
2249 		convo->generation = current_convo_generation; /* FIXME remove */
2250 		convo->TPDO = wmem_array_new(pdo_mapping_scope, sizeof (struct object_mapping));
2251 		convo->RPDO = wmem_array_new(pdo_mapping_scope, sizeof (struct object_mapping));
2252 
2253 		convo->profile = (struct profile*)wmem_map_lookup(epl_profiles_by_address, node_dl_addr);
2254 		if (!convo->profile)
2255 			convo->profile = (struct profile*)wmem_map_lookup(epl_profiles_by_nodeid, GUINT_TO_POINTER(convo->CN));
2256 
2257 		if (!convo->profile)
2258 			convo->profile = epl_default_profile;
2259 
2260 		convo->seq_send = 0x00;
2261 		conversation_add_proto_data(epan_convo, proto_epl, (void *)convo);
2262 	}
2263 
2264 	if (convo->generation != current_convo_generation)
2265 	{ /* FIXME remove */
2266 		convo->TPDO = wmem_array_new(pdo_mapping_scope, sizeof (struct object_mapping));
2267 		convo->RPDO = wmem_array_new(pdo_mapping_scope, sizeof (struct object_mapping));
2268 		convo->generation = current_convo_generation;
2269 	}
2270 
2271 
2272 	return convo;
2273 }
2274 
2275 static gboolean
2276 epl_update_convo_cn_profile(struct epl_convo *convo)
2277 {
2278 	struct profile *candidate; /* Best matching profile */
2279 	if ((candidate = (struct profile*)wmem_map_lookup(epl_profiles_by_device, GUINT_TO_POINTER(convo->device_type))))
2280 	{
2281 		struct profile *iter = candidate;
2282 		do {
2283 			if ((iter->vendor_id == 0 && convo->product_code == 0 && !candidate->vendor_id)
2284 			|| (iter->vendor_id == convo->vendor_id && !candidate->product_code)
2285 			|| (iter->vendor_id == convo->vendor_id &&  iter->product_code == convo->product_code))
2286 			{
2287 				candidate = iter;
2288 			}
2289 
2290 		} while ((iter = iter->next));
2291 
2292 
2293 		convo->profile = candidate;
2294 
2295 		if (!wmem_array_get_count(convo->RPDO))
2296 		{
2297 			wmem_array_append(convo->RPDO,
2298 				wmem_array_get_raw(candidate->RPDO),
2299 				wmem_array_get_count(candidate->RPDO)
2300 			);
2301 		}
2302 		if (!wmem_array_get_count(convo->TPDO))
2303 		{
2304 			wmem_array_append(convo->TPDO,
2305 				wmem_array_get_raw(candidate->TPDO),
2306 				wmem_array_get_count(candidate->TPDO)
2307 			);
2308 		}
2309 		return TRUE;
2310 	}
2311 	return FALSE;
2312 }
2313 
2314 static struct object *
2315 object_lookup(struct profile *profile, guint16 idx)
2316 {
2317 	if (profile == NULL)
2318 		return NULL;
2319 
2320 	return (struct object*)wmem_map_lookup(profile->objects, GUINT_TO_POINTER(idx));
2321 }
2322 
2323 static const struct subobject *
2324 subobject_lookup(struct object *obj, guint8 subindex)
2325 {
2326 	if (!obj || !obj->subindices) return NULL;
2327 	return (const struct subobject*)epl_wmem_iarray_find(obj->subindices, subindex);
2328 }
2329 
2330 /* epl duplication table hash function */
2331 static guint
2332 epl_duplication_hash(gconstpointer k)
2333 {
2334 	const duplication_key *key = (const duplication_key*)k;
2335 	guint hash;
2336 
2337 	hash = ((key->src)<<24) | ((key->dest)<<16)|
2338 		((key->seq_recv)<<8)|(key->seq_send);
2339 
2340 	return hash;
2341 }
2342 
2343 /* epl duplication table equal function */
2344 static gint
2345 epl_duplication_equal(gconstpointer k1, gconstpointer k2)
2346 {
2347 	const duplication_key *key1 = (const duplication_key*)k1;
2348 	const duplication_key *key2 = (const duplication_key*)k2;
2349 	gint hash;
2350 
2351 	hash = (key1->src == key2->src)&&(key1->dest == key2->dest)&&
2352 		(key1->seq_recv == key2->seq_recv)&&(key1->seq_send == key2->seq_send);
2353 
2354 	return hash;
2355 }
2356 
2357 /* free the permanent key */
2358 static void
2359 free_key(gpointer ptr)
2360 {
2361 	duplication_key *key = (duplication_key *)ptr;
2362 	g_slice_free(duplication_key, key);
2363 }
2364 
2365 /* removes the table entries of a specific transfer */
2366 static void
2367 epl_duplication_remove(GHashTable* table, guint8 src, guint8 dest)
2368 {
2369 	GHashTableIter iter;
2370 	gpointer pkey;
2371 	duplication_key *key;
2372 
2373 	g_hash_table_iter_init(&iter, table);
2374 
2375 	while(g_hash_table_iter_next(&iter, &pkey, NULL))
2376 	{
2377 		key = (duplication_key *)pkey;
2378 
2379 		if((src == key->src) && (dest == key->dest))
2380 		{
2381 			/* remove the key + value from the hash table */
2382 			g_hash_table_iter_remove(&iter);
2383 		}
2384 	}
2385 }
2386 
2387 /* insert function */
2388 static void
2389 epl_duplication_insert(GHashTable* table, gpointer ptr, guint32 frame)
2390 {
2391 	duplication_data *data = NULL;
2392 	duplication_key *key = NULL;
2393 	gpointer pdata;
2394 
2395 	/* check if the values are stored */
2396 	if(g_hash_table_lookup_extended(table, ptr, NULL, &pdata))
2397 	{
2398 		data = (duplication_data *)pdata;
2399 		data->frame = frame;
2400 	}
2401 	/* insert the data struct into the table */
2402 	else
2403 	{
2404 		key = (duplication_key *)wmem_memdup(wmem_file_scope(), ptr,sizeof(duplication_key));
2405 		/* create memory */
2406 		data = wmem_new0(wmem_file_scope(), duplication_data);
2407 		data->frame = frame;
2408 		g_hash_table_insert(table,(gpointer)key, data);
2409 	}
2410 }
2411 
2412 /* create a key*/
2413 static gpointer
2414 epl_duplication_key(guint8 src, guint8 dest, guint8 seq_recv, guint8 seq_send)
2415 {
2416 	duplication_key *key = g_slice_new(duplication_key);
2417 
2418 	key->src = src;
2419 	key->dest = dest;
2420 	key->seq_recv = seq_recv;
2421 	key->seq_send = seq_send;
2422 
2423 	return (gpointer)key;
2424 }
2425 
2426 /* get the saved data */
2427 static guint32
2428 epl_duplication_get(GHashTable* table, gpointer ptr)
2429 {
2430 	duplication_data *data = NULL;
2431 	gpointer pdata;
2432 
2433 	if(g_hash_table_lookup_extended(table, ptr, NULL, &pdata))
2434 	{
2435 		data = (duplication_data *)pdata;
2436 		if(data->frame == 0x00)
2437 			return 0x00;
2438 	}
2439 	if(data != NULL)
2440 		return data->frame;
2441 	else
2442 		return 0x00;
2443 }
2444 
2445 static void
2446 setup_dissector(void)
2447 {
2448 	/* init duplication hash table */
2449 	epl_duplication_table = g_hash_table_new(epl_duplication_hash, epl_duplication_equal);
2450 
2451 	/* create memory block for upload/download */
2452 	memset(&epl_asnd_sdo_reassembly_write, 0, sizeof(epl_sdo_reassembly));
2453 	memset(&epl_asnd_sdo_reassembly_read, 0, sizeof(epl_sdo_reassembly));
2454 
2455 	/* free object mappings in one swoop */
2456 	pdo_mapping_scope = wmem_allocator_new(WMEM_ALLOCATOR_SIMPLE);
2457 }
2458 
2459 static void
2460 cleanup_dissector(void)
2461 {
2462 	wmem_destroy_allocator(pdo_mapping_scope);
2463 	pdo_mapping_scope = NULL;
2464 
2465 	g_hash_table_destroy(epl_duplication_table);
2466 	count = 0;
2467 	ct = 0;
2468 	first_read = TRUE;
2469 	first_write = TRUE;
2470 }
2471 
2472 /* preference whether or not display the SoC flags in info column */
2473 gboolean show_soc_flags = FALSE;
2474 
2475 /* Define the tap for epl */
2476 /*static gint epl_tap = -1;*/
2477 
2478 static guint16
2479 epl_get_sequence_nr(packet_info *pinfo)
2480 {
2481 	guint16 seqnum = 0x00;
2482 	gpointer data = NULL;
2483 
2484 	if ( ( data = p_get_proto_data ( wmem_file_scope(), pinfo, proto_epl, ETHERTYPE_EPL_V2 ) ) == NULL )
2485 		p_add_proto_data ( wmem_file_scope(), pinfo, proto_epl, ETHERTYPE_EPL_V2, GUINT_TO_POINTER((guint)seqnum) );
2486 	else
2487 		seqnum = GPOINTER_TO_UINT(data);
2488 
2489 	return seqnum;
2490 }
2491 
2492 static void
2493 epl_set_sequence_nr(packet_info *pinfo, guint16 seqnum)
2494 {
2495 	if ( p_get_proto_data ( wmem_file_scope(), pinfo, proto_epl, ETHERTYPE_EPL_V2 ) != NULL )
2496 		p_remove_proto_data( wmem_file_scope(), pinfo, proto_epl, ETHERTYPE_EPL_V2 );
2497 
2498 	p_add_proto_data ( wmem_file_scope(), pinfo, proto_epl, ETHERTYPE_EPL_V2, GUINT_TO_POINTER((guint)seqnum) );
2499 }
2500 
2501 static void
2502 elp_version( gchar *result, guint32 version )
2503 {
2504 	g_snprintf( result, ITEM_LABEL_LENGTH, "%d.%d", hi_nibble(version), lo_nibble(version));
2505 }
2506 /* Code to actually dissect the packets */
2507 static int
2508 dissect_eplpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean udpencap)
2509 {
2510 	guint8 epl_mtyp;
2511 	const  gchar *src_str, *dest_str;
2512 	/* static epl_info_t mi; */
2513 	/* Set up structures needed to add the protocol subtree and manage it */
2514 	proto_item *ti;
2515 	proto_tree *epl_tree = NULL, *epl_src_item, *epl_dest_item;
2516 	gint offset = 0, size = 0;
2517 	heur_dtbl_entry_t *hdtbl_entry;
2518 	struct epl_convo *convo;
2519 	proto_item *msg_typ_hidden = NULL;
2520 
2521 	if (tvb_reported_length(tvb) < 3)
2522 	{
2523 		/* Not enough data for an EPL header; don't try to interpret it */
2524 		return FALSE;
2525 	}
2526 
2527 	/* Make entries in Protocol column and Info column on summary display */
2528 	col_set_str(pinfo->cinfo, COL_PROTOCOL, udpencap ? "POWERLINK/UDP" : "POWERLINK");
2529 
2530 	/* Get message type */
2531 	epl_mtyp = tvb_get_guint8(tvb, EPL_MTYP_OFFSET) & 0x7F;
2532 
2533 	/*
2534 	* In case the packet is a protocol encoded in the basic EPL transport stream,
2535 	* give that protocol a chance to make a heuristic dissection, before we continue
2536 	* to dissect it as a normal EPL packet.
2537 	*/
2538 	if (dissector_try_heuristic(heur_epl_subdissector_list, tvb, pinfo, tree, &hdtbl_entry, &epl_mtyp))
2539 		return TRUE;
2540 
2541 	/* tap */
2542 	/*  mi.epl_mtyp = epl_mtyp;
2543 	tap_queue_packet(epl_tap, pinfo, &mi);
2544 	*/
2545 
2546 	/* IP addresses are always in 192.168.100.0/24
2547 	 * with last octet being the node id
2548 	 * The original src/dest node ids are reserved
2549 	 */
2550 
2551 	pinfo->ptype = PT_NONE;
2552 
2553 	/* Get Destination and Source */
2554 	if (udpencap)
2555 	{
2556 		/* The dissector may be invoked without an IP layer,
2557 		 * so we need to check we can actually index into the buffer
2558 		 */
2559 		if (pinfo->net_dst.type == AT_IPv4)
2560 			pinfo->destport = ((const guint8*)pinfo->net_dst.data)[3];
2561 		if (pinfo->net_src.type == AT_IPv4)
2562 			pinfo->srcport  = ((const guint8*)pinfo->net_src.data)[3];
2563 	}
2564 	else
2565 	{
2566 		pinfo->destport = tvb_get_guint8(tvb, EPL_DEST_OFFSET);
2567 		pinfo->srcport  = tvb_get_guint8(tvb, EPL_SRC_OFFSET);
2568 	}
2569 
2570 	epl_segmentation.dest = pinfo->destport;
2571 	dest_str = decode_epl_address(pinfo->destport);
2572 
2573 	epl_segmentation.src = pinfo->srcport;
2574 	src_str = decode_epl_address(pinfo->srcport);
2575 
2576 	col_clear(pinfo->cinfo, COL_INFO);
2577 
2578 	/* Choose the right string for "Info" column (message type) */
2579 	switch (epl_mtyp)
2580 	{
2581 		case EPL_SOC:
2582 			col_add_fstr(pinfo->cinfo, COL_INFO, "%3d->%3d SoC    ", pinfo->srcport, pinfo->destport);
2583 			break;
2584 
2585 		case EPL_PREQ:
2586 			col_add_fstr(pinfo->cinfo, COL_INFO, "%3d->%3d  PReq ", pinfo->srcport, pinfo->destport);
2587 			break;
2588 
2589 		case EPL_PRES:
2590 			col_add_fstr(pinfo->cinfo, COL_INFO, "%3d->%3d  PRes ", pinfo->srcport, pinfo->destport);
2591 			break;
2592 
2593 		case EPL_SOA:
2594 			col_add_fstr(pinfo->cinfo, COL_INFO, "%3d->%3d  SoA  ", pinfo->srcport, pinfo->destport);
2595 			break;
2596 
2597 		case EPL_ASND:
2598 			col_add_fstr(pinfo->cinfo, COL_INFO, "%3d->%3d  ASnd ", pinfo->srcport, pinfo->destport);
2599 			break;
2600 
2601 		case EPL_AINV:
2602 			col_add_fstr(pinfo->cinfo, COL_INFO, "%3d->%3d  AInv ", pinfo->srcport, pinfo->destport);
2603 			break;
2604 
2605 		case EPL_AMNI:
2606 			col_add_fstr(pinfo->cinfo, COL_INFO, "%3d->%3d AMNI   ", pinfo->srcport, pinfo->destport);
2607 			break;
2608 
2609 		default:    /* no valid EPL packet */
2610 			return FALSE;
2611 	}
2612 
2613 	if (tree)
2614 	{
2615 		/* create display subtree for the protocol */
2616 		ti = proto_tree_add_item(tree, proto_epl, tvb, 0, -1, ENC_NA);
2617 		epl_tree = proto_item_add_subtree(ti, ett_epl);
2618 
2619 		/* create a hidden field for filtering all EPL message types with simple syntax (epl.soc, epl.soa,...) */
2620 		switch(epl_mtyp)
2621 		{
2622 			case EPL_SOC:
2623 				msg_typ_hidden = proto_tree_add_boolean(epl_tree, hf_epl_soc, tvb, offset, 1, epl_mtyp);
2624 				break;
2625 
2626 			case EPL_PREQ:
2627 				msg_typ_hidden = proto_tree_add_boolean(epl_tree, hf_epl_preq, tvb, offset, 1, epl_mtyp);
2628 				break;
2629 
2630 			case EPL_PRES:
2631 				msg_typ_hidden = proto_tree_add_boolean(epl_tree, hf_epl_pres, tvb, offset, 1, epl_mtyp);
2632 				break;
2633 
2634 			case EPL_SOA:
2635 				msg_typ_hidden = proto_tree_add_boolean(epl_tree, hf_epl_soa, tvb, offset, 1, epl_mtyp);
2636 				break;
2637 
2638 			case EPL_ASND:
2639 				msg_typ_hidden = proto_tree_add_boolean(epl_tree, hf_epl_asnd, tvb, offset, 1, epl_mtyp);
2640 				break;
2641 
2642 			case EPL_AMNI:
2643 				msg_typ_hidden = proto_tree_add_boolean(epl_tree, hf_epl_amni, tvb, offset, 1, epl_mtyp);
2644 				break;
2645 
2646 			case EPL_AINV:
2647 				msg_typ_hidden = proto_tree_add_boolean(epl_tree, hf_epl_ainv, tvb, offset, 1, epl_mtyp);
2648 				break;
2649 		}
2650 		proto_item_set_hidden(msg_typ_hidden);
2651 
2652 		proto_tree_add_item(epl_tree,
2653 			hf_epl_mtyp, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2654 	}
2655 	offset += 1;
2656 
2657 	if (tree && !udpencap)
2658 	{
2659 		epl_dest_item = proto_tree_add_item(epl_tree, hf_epl_node, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2660 		proto_item_set_hidden(epl_dest_item);
2661 		epl_dest_item = proto_tree_add_item(epl_tree, hf_epl_dest, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2662 		proto_item_append_text (epl_dest_item, "%s", dest_str);
2663 		offset += 1;
2664 
2665 		epl_src_item = proto_tree_add_item(epl_tree, hf_epl_node, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2666 		proto_item_set_hidden(epl_src_item);
2667 		epl_src_item = proto_tree_add_item(epl_tree, hf_epl_src, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2668 		proto_item_append_text (epl_src_item, "%s", src_str);
2669 		offset += 1;
2670 	}
2671 	else
2672 	{
2673 		offset += 2;
2674 	}
2675 
2676 	/* The rest of the EPL dissector depends on the message type  */
2677 	switch (epl_mtyp)
2678 	{
2679 		case EPL_SOC:
2680 			offset = dissect_epl_soc(epl_tree, tvb, pinfo, offset);
2681 			break;
2682 
2683 		case EPL_PREQ:
2684 			convo = epl_get_convo(pinfo, CONVO_FOR_REQUEST);
2685 			offset = dissect_epl_preq(convo, epl_tree, tvb, pinfo, offset);
2686 			break;
2687 
2688 		case EPL_PRES:
2689 			convo = epl_get_convo(pinfo, CONVO_FOR_RESPONSE);
2690 			offset = dissect_epl_pres(convo, epl_tree, tvb, pinfo, offset);
2691 			break;
2692 
2693 		case EPL_SOA:
2694 			offset = dissect_epl_soa(epl_tree, tvb, pinfo, offset);
2695 			break;
2696 
2697 		case EPL_ASND:
2698 			offset = dissect_epl_asnd(epl_tree, tvb, pinfo, offset);
2699 			break;
2700 
2701 		case EPL_AINV:
2702 			offset = dissect_epl_ainv(epl_tree, tvb, pinfo, offset);
2703 			break;
2704 
2705 		case EPL_AMNI:
2706 			/* Currently all fields in the AMNI frame are reserved. Therefore
2707 			 * there's nothing to dissect! Everything is given to the heuristic,
2708 			 * which will dissect as data, if no heuristic dissector uses it. */
2709 			size = tvb_captured_length_remaining(tvb, offset);
2710 			offset = dissect_epl_payload(epl_tree, tvb, pinfo, offset, size, NULL, EPL_AMNI);
2711 			break;
2712 
2713 	           /* Switch cases are exhaustive. Default case never occurs */
2714 	}
2715 
2716 
2717 	return offset;
2718 }
2719 
2720 static int
2721 dissect_epl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2722 {
2723 	return dissect_eplpdu(tvb, pinfo, tree, FALSE);
2724 }
2725 
2726 static int
2727 dissect_epludp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2728 {
2729 	return dissect_eplpdu(tvb, pinfo, tree, TRUE);
2730 }
2731 
2732 
2733 static const gchar*
2734 decode_epl_address (guchar adr)
2735 {
2736 	const gchar *addr_str;
2737 
2738 	addr_str = try_val_to_str(adr, addr_str_vals);
2739 
2740 	if (addr_str != NULL)
2741 	{
2742 		return addr_str;
2743 	}
2744 	else
2745 	{
2746 		if (EPL_IS_CN_NODEID(adr))
2747 		{
2748 			return addr_str_cn;
2749 		}
2750 		else
2751 		{
2752 			return addr_str_res;
2753 		}
2754 	}
2755 }
2756 
2757 static gint
2758 dissect_epl_payload(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, gint len, const struct epl_datatype *type, guint8 msgType)
2759 {
2760 	gint rem_len = 0, payload_len = 0;
2761 	tvbuff_t *payload_tvb = NULL;
2762 	heur_dtbl_entry_t *hdtbl_entry = NULL;
2763 	proto_item *item = NULL;
2764 
2765 	if (len <= 0)
2766 		return offset;
2767 
2768 	rem_len = tvb_captured_length_remaining(tvb, offset);
2769 	payload_tvb = tvb_new_subset_length(tvb, offset, MIN(len, rem_len));
2770 	payload_len = tvb_captured_length_remaining(payload_tvb, 0);
2771 
2772 	if ( payload_len < len )
2773 	{
2774 		item = proto_tree_add_uint(epl_tree, hf_epl_payload_real, tvb, offset, payload_len, payload_len);
2775 		proto_item_set_generated(item);
2776 		expert_add_info(pinfo, item, &ei_real_length_differs );
2777 	}
2778 
2779 	/* To satisfy heurstic dissectors, we need to pass then the whole PDO payload as-is,
2780 	 * so we check whether we were called from dissect_epl_pdo and skip trying heuristic
2781 	 * dissectors for the PDO's components
2782 	 */
2783 	if (msgType != EPL_PREQ && msgType != EPL_PRES)
2784 	{
2785 		if ( dissector_try_heuristic(heur_epl_data_subdissector_list, payload_tvb, pinfo, epl_tree, &hdtbl_entry, &msgType))
2786 			return offset + payload_len;
2787 	}
2788 
2789 	if (type && (!type->len || type->len == payload_len))
2790 	{
2791 		if (*type->hf != hf_epl_od_uint)
2792 		{
2793 			proto_tree_add_item(epl_tree, *type->hf, tvb, offset, type->len, type->encoding);
2794 		}
2795 		else
2796 		{
2797 			/* proto_tree_add_item would zero-pad our hex representation
2798 			 * to full 64 bit, which looks kind of ugly, so we add the
2799 			 * HEX part of BASE_DEC_HEX ourselves
2800 			 */
2801 			guint64 val;
2802 			item = proto_tree_add_item_ret_uint64(epl_tree, *type->hf,
2803 						tvb, offset, type->len, type->encoding, &val);
2804 			proto_item_append_text(item, " (0x%.*" G_GINT64_MODIFIER "x)", 2*type->len, val);
2805 		}
2806 	}
2807 	/* If a mapping uses a type of fixed width that's not equal to
2808 	 * the function argument's length, fallback to raw data dissector
2809 	 */
2810 	else
2811 	{
2812 		/* We don't know the type, so let's use appropriate unsignedX */
2813 		if (payload_len < (int)sizeof (guint64) && interpret_untyped_as_le)
2814 		{
2815 			guint64 val;
2816 			item = proto_tree_add_item_ret_uint64(epl_tree, hf_epl_od_uint,
2817 						payload_tvb, 0, payload_len, ENC_LITTLE_ENDIAN, &val);
2818 			proto_item_append_text(item, " (0x%.*" G_GINT64_MODIFIER "x)", 2*payload_len, val);
2819 		}
2820 		else
2821 		{
2822 			call_data_dissector(payload_tvb, pinfo, epl_tree);
2823 		}
2824 	}
2825 
2826 	return offset + payload_len;
2827 }
2828 
2829 static gint
2830 dissect_epl_soc(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
2831 {
2832 	guint8  flags;
2833 	static int * const soc_flags[] = {
2834 		&hf_epl_soc_mc,
2835 		&hf_epl_soc_ps,
2836 		&hf_epl_soc_dna_an,
2837 		NULL
2838 	};
2839 
2840 	offset += 1;
2841 
2842 	flags = tvb_get_guint8(tvb, offset);
2843 	proto_tree_add_bitmask(epl_tree, tvb, offset, hf_epl_soc_flags, ett_epl_soc, soc_flags, ENC_NA);
2844 
2845 	offset += 2;
2846 
2847 	if (show_soc_flags)
2848 	{
2849 		col_append_fstr(pinfo->cinfo, COL_INFO, "F:MC=%d,PS=%d",
2850 				((EPL_SOC_MC_MASK & flags) >> 7), ((EPL_SOC_PS_MASK & flags) >> 6));
2851 	}
2852 
2853 	proto_tree_add_item(epl_tree, hf_epl_soc_nettime, tvb, offset, 8, ENC_TIME_SECS_NSECS|ENC_LITTLE_ENDIAN);
2854 	offset += 8;
2855 
2856 	proto_tree_add_item(epl_tree, hf_epl_soc_relativetime, tvb, offset, 8, ENC_TIME_SECS_NSECS|ENC_LITTLE_ENDIAN);
2857 	offset += 8;
2858 
2859 	return offset;
2860 }
2861 
2862 
2863 
2864 static gint
2865 dissect_epl_preq(struct epl_convo *convo, proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
2866 {
2867 	guint16 len;
2868 	guint8  pdoversion;
2869 	guint8  flags;
2870 	static int * const req_flags[] = {
2871 		&hf_epl_preq_ms,
2872 		&hf_epl_preq_ea,
2873 		&hf_epl_preq_rd,
2874 		NULL
2875 	};
2876 
2877 	offset += 1;
2878 
2879 	flags = tvb_get_guint8(tvb, offset);
2880 	proto_tree_add_bitmask(epl_tree, tvb, offset, hf_epl_preq_flags, ett_epl_preq, req_flags, ENC_NA);
2881 	offset += 1;
2882 
2883 	/* dissect 2nd flag field */
2884 	proto_tree_add_item(epl_tree, hf_epl_preq_fls, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2885 	proto_tree_add_item(epl_tree, hf_epl_preq_sls, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2886 	offset += 1;
2887 
2888 	pdoversion = tvb_get_guint8(tvb, offset);
2889 	proto_tree_add_item(epl_tree, hf_epl_preq_pdov, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2890 	offset += 2;
2891 
2892 	/* get size of payload */
2893 	len = tvb_get_letohs(tvb, offset);
2894 	proto_tree_add_uint(epl_tree, hf_epl_preq_size, tvb, offset, 2, len);
2895 
2896 	col_append_fstr(pinfo->cinfo, COL_INFO, "[%4d]  F:RD=%d,EA=%d  V:%d.%d", len,
2897 			((EPL_PDO_RD_MASK & flags) >> 0), ((EPL_PDO_EA_MASK & flags) >> 2), hi_nibble(pdoversion), lo_nibble(pdoversion));
2898 
2899 	offset += 2;
2900 	offset = dissect_epl_pdo(convo, epl_tree, tvb, pinfo, offset, len, EPL_PREQ );
2901 
2902 	return offset;
2903 }
2904 
2905 
2906 
2907 static gint
2908 dissect_epl_pres(struct epl_convo *convo, proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
2909 {
2910 	guint16  len;
2911 	guint8  pdoversion;
2912 	guint8  state, flags, flags2;
2913 	static int * const res_flags[] = {
2914 		&hf_epl_pres_ms,
2915 		&hf_epl_pres_en,
2916 		&hf_epl_pres_rd,
2917 		NULL
2918 	};
2919 
2920 	state = tvb_get_guint8(tvb, offset);
2921 	if (pinfo->srcport != EPL_MN_NODEID)   /* check if the sender is CN or MN */
2922 	{
2923 		proto_tree_add_item(epl_tree, hf_epl_pres_stat_cs, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2924 	}
2925 	else /* MN */
2926 	{
2927 		proto_tree_add_item(epl_tree, hf_epl_pres_stat_ms, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2928 	}
2929 	offset += 1;
2930 
2931 	flags = tvb_get_guint8(tvb, offset);
2932 	proto_tree_add_bitmask(epl_tree, tvb, offset, hf_epl_pres_flags, ett_epl_pres, res_flags, ENC_NA);
2933 	offset += 1;
2934 
2935 	flags2 = tvb_get_guint8(tvb, offset);
2936 
2937 	proto_tree_add_item(epl_tree, hf_epl_pres_fls, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2938 	proto_tree_add_item(epl_tree, hf_epl_pres_sls, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2939 	proto_tree_add_item(epl_tree, hf_epl_pres_pr, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2940 	proto_tree_add_item(epl_tree, hf_epl_pres_rs, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2941 	offset += 1;
2942 
2943 	pdoversion = tvb_get_guint8(tvb, offset);
2944 	proto_tree_add_item(epl_tree, hf_epl_pres_pdov, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2945 	offset += 2;
2946 
2947 	/* get size of payload */
2948 	len = tvb_get_letohs(tvb, offset);
2949 	proto_tree_add_uint(epl_tree, hf_epl_pres_size, tvb, offset, 2, len);
2950 
2951 	col_append_fstr(pinfo->cinfo, COL_INFO, "[%4d]", len);
2952 
2953 	col_append_fstr(pinfo->cinfo, COL_INFO, "  F:RD=%d,EN=%d,RS=%d,PR=%d  V=%d.%d",
2954 			((EPL_PDO_RD_MASK & flags) >> 0), ((EPL_PDO_EN_MASK & flags) >> 4), (EPL_PDO_RS_MASK & flags2), (EPL_PDO_PR_MASK & flags2) >> 3,
2955 			hi_nibble(pdoversion), lo_nibble(pdoversion));
2956 
2957 	if (pinfo->srcport != EPL_MN_NODEID)   /* check if the sender is CN or MN */
2958 	{
2959 		col_append_fstr(pinfo->cinfo, COL_INFO, "  %s",
2960 						val_to_str(state, epl_nmt_cs_vals, "Unknown(%d)"));
2961 	}
2962 	else /* MN */
2963 	{
2964 		col_append_fstr(pinfo->cinfo, COL_INFO, "  %s",
2965 						val_to_str(state, epl_nmt_ms_vals, "Unknown(%d)"));
2966 	}
2967 
2968 
2969 	offset += 2;
2970 	offset = dissect_epl_pdo(convo, epl_tree, tvb, pinfo, offset, len, EPL_PRES );
2971 
2972 	return offset;
2973 }
2974 
2975 
2976 static gint
2977 dissect_epl_soa(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
2978 {
2979 	guint8 svid, target;
2980 	guint8 state, flags;
2981 	proto_item *psf_item = NULL;
2982 	proto_tree *psf_tree  = NULL;
2983 
2984 	state = tvb_get_guint8(tvb, offset);
2985 	if (pinfo->srcport != EPL_MN_NODEID)   /* check if CN or MN */
2986 	{
2987 		proto_tree_add_item(epl_tree, hf_epl_soa_stat_cs, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2988 	}
2989 	else /* MN */
2990 	{
2991 		proto_tree_add_item(epl_tree, hf_epl_soa_stat_ms, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2992 	}
2993 
2994 	offset += 1;
2995 
2996 	flags = tvb_get_guint8(tvb, offset);
2997 	svid = tvb_get_guint8(tvb, offset + 2);
2998 	if (svid == EPL_SOA_IDENTREQUEST)
2999 	{
3000 		proto_tree_add_item(epl_tree, hf_epl_soa_dna_an_lcl, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3001 	}
3002 	proto_tree_add_item(epl_tree, hf_epl_soa_dna_an_glb, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3003 	proto_tree_add_item(epl_tree, hf_epl_soa_ea, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3004 	proto_tree_add_item(epl_tree, hf_epl_soa_er, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3005 	offset += 2;
3006 
3007 	proto_tree_add_uint(epl_tree, hf_epl_soa_svid, tvb, offset, 1, svid);
3008 	offset += 1;
3009 
3010 	target = tvb_get_guint8(tvb, offset);
3011 	proto_tree_add_uint(epl_tree, hf_epl_soa_svtg, tvb, offset, 1, target);
3012 	offset += 1;
3013 
3014 	col_append_fstr(pinfo->cinfo, COL_INFO, "(%s)->%3d",
3015 					rval_to_str(svid, soa_svid_id_vals, "Unknown"), target);
3016 
3017 	/* append info entry with flag information */
3018 	col_append_fstr(pinfo->cinfo, COL_INFO, "  F:EA=%d,ER=%d  ",
3019 			((EPL_SOA_EA_MASK & flags) >> 2), ((EPL_SOA_ER_MASK & flags) >> 1));
3020 
3021 	if (pinfo->srcport != EPL_MN_NODEID)   /* check if CN or MN */
3022 	{
3023 		col_append_fstr(pinfo->cinfo, COL_INFO, "  %s",
3024 						val_to_str(state, epl_nmt_cs_vals, "Unknown(%d)"));
3025 	}
3026 	else /* MN */
3027 	{
3028 		col_append_fstr(pinfo->cinfo, COL_INFO, "  %s",
3029 						val_to_str(state, epl_nmt_ms_vals, "Unknown(%d)"));
3030 	}
3031 
3032 	proto_tree_add_item(epl_tree, hf_epl_soa_eplv, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3033 	offset += 1;
3034 
3035 	/* decode redundancy flags */
3036 	proto_tree_add_item(epl_tree, hf_epl_soa_rrflags, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3037 	proto_tree_add_item(epl_tree, hf_epl_soa_rrflags_ringstat, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3038 	proto_tree_add_item(epl_tree, hf_epl_soa_rrflags_ringred, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3039 	proto_tree_add_item(epl_tree, hf_epl_soa_rrflags_cblred, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3040 	proto_tree_add_item(epl_tree, hf_epl_soa_rrflags_mnred, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3041 	offset += 1;
3042 
3043 	if (svid == EPL_SOA_SYNCREQUEST)
3044 	{
3045 		/* SyncControl bit0-7 */
3046 		psf_item = proto_tree_add_item(epl_tree, hf_epl_soa_sync, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3047 		proto_item_append_text(psf_item, " (Bits 0..7)");
3048 		psf_tree = proto_item_add_subtree(psf_item, ett_epl_soa_sync);
3049 		proto_tree_add_item(psf_tree, hf_epl_soa_mac, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3050 		proto_tree_add_item(psf_tree, hf_epl_soa_pre_tm, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3051 		proto_tree_add_item(psf_tree, hf_epl_soa_mnd_sec, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3052 		proto_tree_add_item(psf_tree, hf_epl_soa_mnd_fst, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3053 		proto_tree_add_item(psf_tree, hf_epl_soa_pre_sec, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3054 		proto_tree_add_item(psf_tree, hf_epl_soa_pre_fst, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3055 		offset += 1;
3056 		/* SyncControl 2 - reserved */
3057 		psf_item = proto_tree_add_item(epl_tree, hf_epl_soa_sync, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3058 		proto_item_append_text(psf_item, " (Bits 8..15)");
3059 #if 0
3060 		psf_tree = proto_item_add_subtree(psf_item, ett_epl_soa_sync);
3061 #endif
3062 		offset += 1;
3063 		/* SyncControl 3 - reserved */
3064 		psf_item = proto_tree_add_item(epl_tree, hf_epl_soa_sync, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3065 		proto_item_append_text(psf_item, " (Bits 16..23)");
3066 #if 0
3067 		psf_tree = proto_item_add_subtree(psf_item, ett_epl_soa_sync);
3068 #endif
3069 		offset += 1;
3070 		/* SyncControl 4 */
3071 		psf_item = proto_tree_add_item(epl_tree, hf_epl_soa_sync, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3072 		proto_item_append_text(psf_item, " (Bits 24..31)");
3073 		psf_tree = proto_item_add_subtree(psf_item, ett_epl_soa_sync);
3074 		proto_tree_add_item(psf_tree, hf_epl_soa_pre_set, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3075 		proto_tree_add_item(psf_tree, hf_epl_soa_pre_res, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3076 		offset += 1;
3077 		/* PResTimeFirst */
3078 		proto_tree_add_item(epl_tree, hf_epl_soa_pre_fst_end, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3079 		offset += 4;
3080 		/* PResTimeSecond */
3081 		proto_tree_add_item(epl_tree, hf_epl_soa_pre_sec_end, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3082 		offset += 4;
3083 		/* SyncMNDelayFirst */
3084 		proto_tree_add_item(epl_tree, hf_epl_soa_mnd_fst_end, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3085 		offset += 4;
3086 		/* SyncMNDelaySecond */
3087 		proto_tree_add_item(epl_tree, hf_epl_soa_mnd_sec_end, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3088 		offset += 4;
3089 		/* PResFallBackTimeout */
3090 		proto_tree_add_item(epl_tree, hf_epl_soa_pre_tm_end, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3091 		offset += 4;
3092 		/* DestMacAddress */
3093 		proto_tree_add_item(epl_tree, hf_epl_soa_mac_end, tvb, offset, 6, ENC_NA);
3094 		offset += 6;
3095 	}
3096 
3097 	return offset;
3098 }
3099 
3100 
3101 
3102 static gint
3103 dissect_epl_asnd(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
3104 {
3105 	guint8  svid;
3106 	guint8 flags, flags2;
3107 	gint size, reported_len;
3108 	tvbuff_t *next_tvb;
3109 	proto_item *item;
3110 	proto_tree *subtree;
3111 	struct epl_convo *convo;
3112 
3113 	/* get ServiceID of payload */
3114 	svid = tvb_get_guint8(tvb, offset);
3115 	item = proto_tree_add_uint(epl_tree, hf_epl_asnd_svid, tvb, offset, 1, svid );
3116 
3117 	offset += 1;
3118 
3119 	flags = tvb_get_guint8(tvb, offset);
3120 	flags2 = tvb_get_guint8(tvb, offset + 1);
3121 
3122 	col_append_fstr(pinfo->cinfo, COL_INFO, "(%s) ",
3123 			rval_to_str(svid, asnd_svid_id_vals, "Unknown"));
3124 
3125 	/* append info entry with flag information for sres/ires frames */
3126 	if ((svid == EPL_ASND_IDENTRESPONSE) || (svid == EPL_ASND_STATUSRESPONSE))
3127 	{
3128 		col_append_fstr(pinfo->cinfo, COL_INFO, "  F:EC=%d,EN=%d,RS=%d,PR=%d  ",
3129 				((EPL_ASND_EC_MASK & flags) >> 3), ((EPL_ASND_EN_MASK & flags) >> 4), (EPL_ASND_RS_MASK & flags2), (EPL_ASND_PR_MASK & flags2) >> 3);
3130 
3131 	}
3132 
3133 	switch (svid)
3134 	{
3135 		case EPL_ASND_IDENTRESPONSE:
3136 			convo = epl_get_convo(pinfo, CONVO_FOR_RESPONSE);
3137 			offset = dissect_epl_asnd_ires(convo, epl_tree, tvb, pinfo, offset);
3138 			break;
3139 
3140 		case EPL_ASND_STATUSRESPONSE:
3141 			offset = dissect_epl_asnd_sres(epl_tree, tvb, pinfo, offset);
3142 			break;
3143 
3144 		case EPL_ASND_NMTREQUEST:
3145 			offset = dissect_epl_asnd_nmtreq(epl_tree, tvb, pinfo, offset);
3146 			break;
3147 
3148 		case EPL_ASND_NMTCOMMAND:
3149 			offset = dissect_epl_asnd_nmtcmd(epl_tree, tvb, pinfo, offset);
3150 			break;
3151 
3152 		case EPL_ASND_SDO:
3153 			subtree = proto_item_add_subtree ( item, ett_epl_sdo );
3154 			offset = dissect_epl_asnd_sdo(subtree, tvb, pinfo, offset);
3155 			break;
3156 		case EPL_ASND_SYNCRESPONSE:
3157 			offset = dissect_epl_asnd_resp(epl_tree, tvb, pinfo, offset);
3158 			break;
3159 		default:
3160 			size = tvb_captured_length_remaining(tvb, offset);
3161 			reported_len = tvb_reported_length_remaining(tvb, offset);
3162 
3163 			next_tvb = tvb_new_subset_length_caplen(tvb, offset, size, reported_len);
3164 			/* Manufacturer specific entries for ASND services */
3165 			if (svid >= 0xA0 && svid < 0xFF && dissector_try_uint(epl_asnd_dissector_table,
3166 				svid, next_tvb, pinfo, ( epl_tree ? epl_tree->parent : NULL ))) {
3167 				break;
3168 			}
3169 
3170 			dissect_epl_payload(epl_tree, tvb, pinfo, offset, size, NULL, EPL_ASND);
3171 	}
3172 
3173 	return offset;
3174 }
3175 
3176 static gint
3177 dissect_epl_ainv(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
3178 {
3179 	guint8 svid;
3180 	proto_item *item;
3181 	proto_tree *subtree;
3182 	struct epl_convo *convo;
3183 
3184 	if (pinfo->srcport != EPL_MN_NODEID)   /* check if CN or MN */
3185 	{
3186 		proto_tree_add_item(epl_tree, hf_epl_soa_stat_cs, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3187 	}
3188 	else /* MN */
3189 	{
3190 		proto_tree_add_item(epl_tree, hf_epl_soa_stat_ms, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3191 	}
3192 
3193 	offset += 2;
3194 
3195 	proto_tree_add_item(epl_tree, hf_epl_soa_ea, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3196 	proto_tree_add_item(epl_tree, hf_epl_soa_er, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3197 	offset += 1;
3198 
3199 	svid = tvb_get_guint8(tvb, offset);
3200 
3201 	col_append_fstr(pinfo->cinfo, COL_INFO, "(%s)  ", rval_to_str(svid, asnd_svid_id_vals, "UNKNOWN(%d)"));
3202 
3203 	item = proto_tree_add_uint(epl_tree, hf_epl_asnd_svid, tvb, offset, 1, svid );
3204 	offset += 1;
3205 
3206 	switch (svid)
3207 	{
3208 		case EPL_ASND_IDENTRESPONSE:
3209 			convo = epl_get_convo(pinfo, CONVO_FOR_RESPONSE);
3210 			offset = dissect_epl_asnd_ires(convo, epl_tree, tvb, pinfo, offset);
3211 			break;
3212 
3213 		case EPL_ASND_STATUSRESPONSE:
3214 			offset = dissect_epl_asnd_sres(epl_tree, tvb, pinfo, offset);
3215 			break;
3216 
3217 		case EPL_ASND_NMTREQUEST:
3218 			offset = dissect_epl_asnd_nmtreq(epl_tree, tvb, pinfo, offset);
3219 			break;
3220 
3221 		case EPL_ASND_NMTCOMMAND:
3222 			offset = dissect_epl_asnd_nmtcmd(epl_tree, tvb, pinfo, offset);
3223 			break;
3224 
3225 		case EPL_SOA_UNSPECIFIEDINVITE:
3226 			proto_tree_add_item(epl_tree, hf_epl_asnd_svtg, tvb, offset, 1, ENC_LITTLE_ENDIAN );
3227 			offset += 1;
3228 			proto_tree_add_item(epl_tree, hf_epl_soa_eplv, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3229 			break;
3230 
3231 		case EPL_ASND_SDO:
3232 			subtree = proto_item_add_subtree ( item, ett_epl_sdo );
3233 			offset = dissect_epl_asnd_sdo(subtree, tvb, pinfo, offset);
3234 			break;
3235 	}
3236 
3237 	return offset;
3238 }
3239 
3240 
3241 static gint
3242 dissect_epl_asnd_nmtreq(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
3243 {
3244 	guint8 rcid;
3245 
3246 	rcid = tvb_get_guint8(tvb, offset);
3247 
3248 	proto_tree_add_uint(epl_tree, hf_epl_asnd_nmtrequest_rcid, tvb, offset, 1, rcid);
3249 	proto_tree_add_item(epl_tree, hf_epl_asnd_nmtrequest_rct, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
3250 	proto_tree_add_item(epl_tree, hf_epl_asnd_nmtrequest_rcd, tvb, offset+2, -1, ENC_NA);
3251 
3252 	offset += 2;
3253 
3254 	col_append_str(pinfo->cinfo, COL_INFO,
3255 						val_to_str_ext(rcid, &asnd_cid_vals_ext, "Unknown (%d)"));
3256 
3257 	return offset;
3258 }
3259 
3260 static gint
3261 dissect_epl_asnd_nmtdna(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
3262 {
3263 	proto_item  *ti_dna;
3264 	proto_tree  *epl_dna_tree;
3265 	guint32     curr_node_num;
3266 	guint32     new_node_num;
3267 	guint32     lease_time;
3268 	guint32     lease_time_s;
3269 	nstime_t    us;
3270 	static int * const dna_flags[] = {
3271 		&hf_epl_asnd_nmtcommand_nmtdna_ltv,
3272 		&hf_epl_asnd_nmtcommand_nmtdna_hpm,
3273 		&hf_epl_asnd_nmtcommand_nmtdna_nnn,
3274 		&hf_epl_asnd_nmtcommand_nmtdna_mac,
3275 		&hf_epl_asnd_nmtcommand_nmtdna_cnn,
3276 		NULL
3277 	};
3278 
3279 	ti_dna = proto_tree_add_item(epl_tree, hf_epl_asnd_nmtcommand_nmtdna, tvb, offset, EPL_SIZEOF_NMTCOMMAND_DNA, ENC_NA);
3280 	epl_dna_tree = proto_item_add_subtree(ti_dna, ett_epl_feat);
3281 
3282 	proto_tree_add_bitmask(epl_dna_tree, tvb, offset, hf_epl_asnd_nmtcommand_nmtdna_flags, ett_epl_asnd_nmt_dna, dna_flags, ENC_NA);
3283 	offset += 1;
3284 
3285 	proto_tree_add_item(epl_dna_tree, hf_epl_asnd_nmtcommand_nmtdna_currmac, tvb, offset, 6, ENC_NA);
3286 	offset += 6;
3287 
3288 	/* 64-bit mask specifying which hub ports are active (1) or inactive (0) */
3289 	proto_tree_add_item(epl_dna_tree, hf_epl_asnd_nmtcommand_nmtdna_hubenmsk, tvb, offset, 8, ENC_LITTLE_ENDIAN);
3290 	offset += 8;
3291 
3292 	proto_tree_add_item_ret_uint(epl_dna_tree, hf_epl_asnd_nmtcommand_nmtdna_currnn, tvb, offset, 4, ENC_LITTLE_ENDIAN, &curr_node_num);
3293 	offset += 4;
3294 
3295 	proto_tree_add_item_ret_uint (epl_dna_tree, hf_epl_asnd_nmtcommand_nmtdna_newnn, tvb, offset, 4, ENC_LITTLE_ENDIAN, &new_node_num);
3296 	offset += 4;
3297 
3298 	lease_time = tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN);
3299 	lease_time_s = lease_time / 1000000; /* us->s */
3300 	us.nsecs = (lease_time - lease_time_s * 1000000) * 1000; /* us->ns */
3301 	us.secs = lease_time_s;
3302 	proto_tree_add_time(epl_dna_tree, hf_epl_asnd_nmtcommand_nmtdna_leasetime, tvb, offset, 4, &us);
3303 	offset += 4;
3304 
3305 	col_append_fstr(pinfo->cinfo, COL_INFO, ": %4d -> %4d", curr_node_num, new_node_num);
3306 
3307 	return offset;
3308 }
3309 
3310 
3311 static gint
3312 dissect_epl_asnd_nmtcmd(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
3313 {
3314 	guint8  epl_asnd_nmtcommand_cid;
3315 	guint16 errorcode;
3316 
3317 	epl_asnd_nmtcommand_cid = tvb_get_guint8(tvb, offset);
3318 	proto_tree_add_uint(epl_tree, hf_epl_asnd_nmtcommand_cid, tvb, offset, 1, epl_asnd_nmtcommand_cid);
3319 	offset += 2;
3320 
3321 	col_append_str(pinfo->cinfo, COL_INFO, val_to_str_ext(epl_asnd_nmtcommand_cid, &asnd_cid_vals_ext, "Unknown(%d)"));
3322 
3323 	switch (epl_asnd_nmtcommand_cid)
3324 	{
3325 		case EPL_ASND_NMTCOMMAND_NMTNETHOSTNAMESET:
3326 			proto_tree_add_item(epl_tree, hf_epl_asnd_nmtcommand_nmtnethostnameset_hn, tvb, offset, 32, ENC_NA);
3327 			offset += 32;
3328 			break;
3329 
3330 		case EPL_ASND_NMTCOMMAND_NMTFLUSHARPENTRY:
3331 			proto_tree_add_item(epl_tree, hf_epl_asnd_nmtcommand_nmtflusharpentry_nid, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3332 			offset += 1;
3333 			break;
3334 
3335 		case EPL_ASND_NMTCOMMAND_NMTPUBLISHTIME:
3336 			proto_tree_add_item(epl_tree, hf_epl_asnd_nmtcommand_nmtpublishtime_dt, tvb, offset, 6, ENC_NA);
3337 			offset += 6;
3338 			break;
3339 
3340 		case EPL_ASND_NMTCOMMAND_NMTDNA:
3341 			/* This byte is reserved for the other NMT commands but some flags are placed in it for DNA */
3342 			offset -= 1;
3343 			offset = dissect_epl_asnd_nmtdna(epl_tree, tvb, pinfo, offset);
3344 			break;
3345 
3346 		case EPL_ASND_NMTCOMMAND_NMTRESETNODE:
3347 			errorcode = tvb_get_letohs(tvb, offset);
3348 			if (errorcode != 0)
3349 			{
3350 				col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", val_to_str(errorcode, errorcode_vals, "Unknown Error(0x%04x"));
3351 				proto_tree_add_item(epl_tree, hf_epl_asnd_nmtcommand_resetnode_reason, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3352 			}
3353 			else
3354 				proto_tree_add_item(epl_tree, hf_epl_asnd_nmtcommand_cdat, tvb, offset, -1, ENC_NA);
3355 			break;
3356 
3357 		default:
3358 			proto_tree_add_item(epl_tree, hf_epl_asnd_nmtcommand_cdat, tvb, offset, -1, ENC_NA);
3359 	}
3360 
3361 	return offset;
3362 }
3363 
3364 
3365 
3366 static gint
3367 dissect_epl_asnd_ires(struct epl_convo *convo, proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
3368 {
3369 	guint32 epl_asnd_identresponse_ipa, epl_asnd_identresponse_snm, epl_asnd_identresponse_gtw;
3370 	proto_item  *ti_feat, *ti;
3371 	proto_tree  *epl_feat_tree;
3372 	guint16 device_type;
3373 	const char *profile_name = NULL;
3374 	guint32 response_time;
3375 
3376 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_en, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3377 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_ec, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3378 	offset += 1;
3379 
3380 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_fls, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3381 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_sls, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3382 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_pr, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3383 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_rs, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3384 	offset += 1;
3385 
3386 	if (pinfo->srcport != EPL_MN_NODEID)   /* check if CN or MN */
3387 	{
3388 		proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_stat_cs, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3389 	}
3390 	else /* MN */
3391 	{
3392 		proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_stat_ms, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3393 	}
3394 	offset += 2;
3395 
3396 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_ever, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3397 	offset += 2;
3398 
3399 	/* decode FeatureFlags */
3400 	ti_feat = proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_feat, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3401 	epl_feat_tree = proto_item_add_subtree(ti_feat, ett_epl_feat);
3402 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit0, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3403 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit1, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3404 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit2, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3405 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit3, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3406 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit4, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3407 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit5, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3408 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit6, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3409 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit7, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3410 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit8, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3411 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit9, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3412 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bitA, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3413 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bitB, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3414 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bitC, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3415 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bitD, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3416 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bitE, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3417 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bitF, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3418 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit10, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3419 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit11, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3420 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit12, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3421 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit13, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3422 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit14, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3423 	proto_tree_add_item(epl_feat_tree, hf_epl_asnd_identresponse_feat_bit21, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3424 	offset += 4;
3425 
3426 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_mtu, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3427 	offset += 2;
3428 
3429 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_pis, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3430 	offset += 2;
3431 
3432 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_pos, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3433 	offset += 2;
3434 
3435 	response_time = tvb_get_letohl(tvb, offset);
3436 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_rst, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3437 	offset += 6;
3438 
3439 	device_type = tvb_get_letohs(tvb, offset);
3440 
3441 	if (device_type != convo->device_type)
3442 		convo = epl_get_convo(pinfo, CONVO_FOR_RESPONSE | CONVO_ALWAYS_CREATE);
3443 
3444 	convo->response_time = response_time;
3445 	convo->device_type   = device_type;
3446 
3447 	ti = proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_dt, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3448 
3449 	if (!convo->profile || !convo->profile->nodeid)
3450 		epl_update_convo_cn_profile(convo);
3451 	if (convo->profile && convo->profile->name)
3452 		profile_name = convo->profile->name;
3453 	if (!profile_name)
3454 		profile_name = val_to_str_const(convo->device_type, epl_device_profiles, "Unknown Profile");
3455 
3456 	proto_item_append_text(ti, " (%s)", profile_name);
3457 
3458 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_dt_add, tvb, offset+2, 2, ENC_LITTLE_ENDIAN);
3459 
3460 	if (convo->profile && convo->profile->path)
3461 	{
3462 		ti = proto_tree_add_string(epl_tree, hf_epl_asnd_identresponse_profile_path, tvb, offset, 2, convo->profile->path);
3463 		proto_item_set_generated(ti);
3464 	}
3465 
3466 	offset += 4;
3467 
3468 	convo->vendor_id = tvb_get_letohl(tvb, offset);
3469 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_vid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3470 	offset += 4;
3471 
3472 	convo->product_code = tvb_get_letohl(tvb, offset);
3473 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_productcode, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3474 	offset += 4;
3475 
3476 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_rno, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3477 	offset += 4;
3478 
3479 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_sno, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3480 	offset += 4;
3481 
3482 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_vex1, tvb, offset, 8, ENC_LITTLE_ENDIAN);
3483 	offset += 8;
3484 
3485 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_vcd, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3486 	offset += 4;
3487 
3488 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_vct, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3489 	offset += 4;
3490 
3491 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_ad, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3492 	offset += 4;
3493 
3494 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_at, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3495 	offset += 4;
3496 
3497 	epl_asnd_identresponse_ipa = tvb_get_ntohl(tvb, offset);
3498 	proto_tree_add_ipv4(epl_tree , hf_epl_asnd_identresponse_ipa, tvb, offset, 4, epl_asnd_identresponse_ipa);
3499 	offset += 4;
3500 
3501 	epl_asnd_identresponse_snm = tvb_get_ntohl(tvb, offset);
3502 	proto_tree_add_ipv4(epl_tree , hf_epl_asnd_identresponse_snm, tvb, offset, 4, epl_asnd_identresponse_snm);
3503 	offset += 4;
3504 
3505 	epl_asnd_identresponse_gtw = tvb_get_ntohl(tvb, offset);
3506 	proto_tree_add_ipv4(epl_tree , hf_epl_asnd_identresponse_gtw, tvb, offset, 4, epl_asnd_identresponse_gtw);
3507 	offset += 4;
3508 
3509 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_hn, tvb, offset, 32, ENC_ASCII|ENC_NA);
3510 	offset += 32;
3511 
3512 	proto_tree_add_item(epl_tree, hf_epl_asnd_identresponse_vex2, tvb, offset, 48, ENC_NA);
3513 	offset += 48;
3514 
3515 	col_append_str(pinfo->cinfo, COL_INFO, val_to_str(convo->device_type, epl_device_profiles, "Device Profile %d"));
3516 
3517 	return offset;
3518 }
3519 
3520 static gint
3521 dissect_epl_asnd_resp(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint offset)
3522 {
3523 	proto_item *psf_item = NULL;
3524 	proto_tree *psf_tree  = NULL;
3525 
3526 	/* reserved 2 byte*/
3527 	offset +=2;
3528 	/* SyncStatus bit 0 - 7 */
3529 	psf_item = proto_tree_add_item(epl_tree, hf_epl_asnd_syncResponse_sync, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3530 	proto_item_append_text(psf_item, " (Bits 0..7)");
3531 	psf_tree = proto_item_add_subtree(psf_item, ett_epl_asnd_sync);
3532 	proto_tree_add_item(psf_tree, hf_epl_asnd_syncResponse_sec_val, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3533 	proto_tree_add_item(psf_tree, hf_epl_asnd_syncResponse_fst_val, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3534 	offset += 1;
3535 	/* SyncStatus bit 8 - 15 reserved */
3536 	psf_item = proto_tree_add_item(epl_tree, hf_epl_asnd_syncResponse_sync, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3537 	proto_item_append_text(psf_item, " (Bits 8..15)");
3538 #if 0
3539 	psf_tree = proto_item_add_subtree(psf_item, ett_epl_asnd_sync);
3540 #endif
3541 	offset += 1;
3542 	/* SyncStatus bit 16 - 23 reserved */
3543 	psf_item = proto_tree_add_item(epl_tree, hf_epl_asnd_syncResponse_sync, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3544 	proto_item_append_text(psf_item, " (Bits 16..23)");
3545 #if 0
3546 	psf_tree = proto_item_add_subtree(psf_item, ett_epl_asnd_sync);
3547 #endif
3548 	offset += 1;
3549 	/* SyncStatus bit 24 - 31 reserved */
3550 	psf_item = proto_tree_add_item(epl_tree, hf_epl_asnd_syncResponse_sync, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3551 	proto_item_append_text(psf_item, " (Bits 24..31)");
3552 	psf_tree = proto_item_add_subtree(psf_item, ett_epl_asnd_sync);
3553 	proto_tree_add_item(psf_tree, hf_epl_asnd_syncResponse_mode, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3554 	offset += 1;
3555 	/* Latency */
3556 	proto_tree_add_item(epl_tree, hf_epl_asnd_syncResponse_latency, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3557 	offset += 4;
3558 	/* SyncDelayStation */
3559 	proto_tree_add_item(epl_tree, hf_epl_asnd_syncResponse_node, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3560 	offset += 4;
3561 	/* SyncDelay */
3562 	proto_tree_add_item(epl_tree, hf_epl_asnd_syncResponse_delay, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3563 	offset += 4;
3564 	/* PResTimeFirst */
3565 	proto_tree_add_item(epl_tree, hf_epl_asnd_syncResponse_pre_fst, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3566 	offset += 4;
3567 	/* PResTimeSecond */
3568 	proto_tree_add_item(epl_tree, hf_epl_asnd_syncResponse_pre_sec, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3569 	offset += 4;
3570 	return offset;
3571 }
3572 
3573 static gint
3574 dissect_epl_asnd_sres(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
3575 {
3576 	proto_item  *ti_el_entry, *ti_el_entry_type;
3577 	proto_tree  *epl_seb_tree, *epl_el_tree, *epl_el_entry_tree, *epl_el_entry_type_tree;
3578 	guint       number_of_entries, cnt;    /* used for dissection of ErrorCodeList */
3579 	guint8      nmt_state;
3580 
3581 	proto_tree_add_item(epl_tree, hf_epl_asnd_statusresponse_en, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3582 	proto_tree_add_item(epl_tree, hf_epl_asnd_statusresponse_ec, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3583 	offset += 1;
3584 
3585 	proto_tree_add_item(epl_tree, hf_epl_asnd_statusresponse_fls, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3586 	proto_tree_add_item(epl_tree, hf_epl_asnd_statusresponse_sls, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3587 	proto_tree_add_item(epl_tree, hf_epl_asnd_statusresponse_pr, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3588 	proto_tree_add_item(epl_tree, hf_epl_asnd_statusresponse_rs, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3589 	offset += 1;
3590 
3591 	nmt_state = tvb_get_guint8(tvb, offset);
3592 	col_append_fstr(pinfo->cinfo, COL_INFO, "%s   ", val_to_str(nmt_state, epl_nmt_cs_vals, "Unknown (%d)"));
3593 
3594 	if (pinfo->srcport != EPL_MN_NODEID)   /* check if CN or MN */
3595 	{
3596 		proto_tree_add_uint(epl_tree, hf_epl_asnd_statusresponse_stat_cs, tvb, offset, 1, nmt_state);
3597 	}
3598 	else /* MN */
3599 	{
3600 		proto_tree_add_uint(epl_tree, hf_epl_asnd_statusresponse_stat_ms, tvb, offset, 1, nmt_state);
3601 	}
3602 	offset += 4;
3603 
3604 	/* Subtree for the static error bitfield */
3605 	epl_seb_tree = proto_tree_add_subtree(epl_tree, tvb, offset, 8, ett_epl_seb, NULL, "StaticErrorBitfield");
3606 
3607 	proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit0, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3608 	proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit1, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3609 	proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit2, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3610 	proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit3, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3611 	proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit4, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3612 	proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit5, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3613 	proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit7, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3614 	offset += 2;
3615 
3616 	proto_tree_add_item(epl_seb_tree, hf_epl_asnd_statusresponse_seb_devicespecific_err, tvb,offset, 6, ENC_NA);
3617 	offset += 6;
3618 
3619 	/* List of errors / events */
3620 	/* get the number of entries in the error code list*/
3621 	number_of_entries = (tvb_reported_length(tvb)-offset)/20;
3622 
3623 	epl_el_tree = proto_tree_add_subtree_format(epl_tree, tvb, offset, -1, ett_epl_el, NULL, "ErrorCodeList: %d entries", number_of_entries);
3624 
3625 	/*Dissect the whole Error List (display each entry)*/
3626 	for (cnt = 0; cnt<number_of_entries; cnt++)
3627 	{
3628 		epl_el_entry_tree = proto_tree_add_subtree_format(epl_el_tree, tvb, offset, 20, ett_epl_el_entry, &ti_el_entry, "Entry %d", cnt+1);
3629 
3630 		/*Entry Type*/
3631 		ti_el_entry_type = proto_tree_add_item(ti_el_entry,
3632 							hf_epl_asnd_statusresponse_el_entry_type, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3633 
3634 		epl_el_entry_type_tree = proto_item_add_subtree(ti_el_entry_type,
3635 								ett_epl_el_entry_type);
3636 
3637 		proto_tree_add_item(epl_el_entry_type_tree,
3638 					hf_epl_asnd_statusresponse_el_entry_type_profile, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3639 
3640 		proto_tree_add_item(epl_el_entry_type_tree,
3641 					hf_epl_asnd_statusresponse_el_entry_type_mode, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3642 
3643 		proto_tree_add_item(epl_el_entry_type_tree,
3644 					hf_epl_asnd_statusresponse_el_entry_type_bit14, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3645 
3646 		proto_tree_add_item(epl_el_entry_type_tree,
3647 					hf_epl_asnd_statusresponse_el_entry_type_bit15, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3648 		offset += 2;
3649 
3650 		proto_tree_add_item(epl_el_entry_tree, hf_epl_asnd_statusresponse_el_entry_code, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3651 		offset += 2;
3652 
3653 		proto_tree_add_item(epl_el_entry_tree, hf_epl_asnd_statusresponse_el_entry_time, tvb, offset, 8, ENC_TIME_SECS_NSECS|ENC_LITTLE_ENDIAN);
3654 		offset += 8;
3655 
3656 		proto_tree_add_item(epl_el_entry_tree, hf_epl_asnd_statusresponse_el_entry_add, tvb, offset, 8, ENC_LITTLE_ENDIAN);
3657 		offset += 8;
3658 	}
3659 
3660 	return offset;
3661 }
3662 
3663 static gint
3664 dissect_epl_asnd_sdo(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset)
3665 {
3666 	guint16 seqnum = 0x00;
3667 	guint8 seq_read;
3668 	offset = dissect_epl_sdo_sequence(epl_tree, tvb, pinfo, offset, &seq_read);
3669 
3670 	seqnum = epl_get_sequence_nr(pinfo);
3671 
3672 	/* if a frame is duplicated don't show the command layer */
3673 	if(seqnum == 0x00 || show_cmd_layer_for_duplicated == TRUE )
3674 	{
3675 		if (tvb_reported_length_remaining(tvb, offset) > 0)
3676 		{
3677 			offset = dissect_epl_sdo_command(epl_tree, tvb, pinfo, offset, seq_read);
3678 		}
3679 		else col_append_str(pinfo->cinfo, COL_INFO, "Empty CommandLayer");
3680 	}
3681 	return offset;
3682 }
3683 
3684 static gint
3685 dissect_epl_sdo_sequence(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, guint8* seq)
3686 {
3687 	guint8 seq_recv = 0x00, seq_send = 0x00, rcon = 0x00, scon = 0x00;
3688 	guint32 frame = 0x00;
3689 	proto_tree *sod_seq_tree;
3690 	proto_item *item;
3691 	guint8 duplication = 0x00;
3692 	gpointer key;
3693 	guint32 saved_frame;
3694 	guint16 seqnum = 0;
3695 
3696 	/* read buffer */
3697 	seq_recv = tvb_get_guint8(tvb, offset);
3698 	/* get rcon */
3699 	rcon = seq_recv & EPL_ASND_SDO_SEQ_CON_MASK;
3700 	/* get seq_recv */
3701 	seq_recv = seq_recv >> EPL_ASND_SDO_SEQ_MASK;
3702 	epl_segmentation.recv = seq_recv;
3703 	/* read buffer */
3704 	seq_send = tvb_get_guint8(tvb, offset+1);
3705 	/* get scon */
3706 	scon = seq_send & EPL_ASND_SDO_SEQ_CON_MASK;
3707 	/* get seq_send */
3708 	seq_send = seq_send >> EPL_ASND_SDO_SEQ_MASK;
3709 	epl_segmentation.send = seq_send;
3710 	/* get the current frame-number */
3711 	frame = pinfo->num;
3712 
3713 	/* Create a key */
3714 	key = epl_duplication_key(epl_segmentation.src,epl_segmentation.dest,seq_recv,seq_send);
3715 
3716 	/* Get the saved data */
3717 	saved_frame = epl_duplication_get(epl_duplication_table, key);
3718 
3719 	/* clear array at the start Sequence */
3720 	if((rcon < EPL_VALID && scon < EPL_VALID)
3721 		||(rcon == EPL_VALID && scon < EPL_VALID)
3722 		||(rcon < EPL_VALID && scon == EPL_VALID))
3723 	{
3724 		/* remove all the keys of the specified src and dest address*/
3725 		epl_duplication_remove(epl_duplication_table,epl_segmentation.src,epl_segmentation.dest);
3726 		/* There is no cmd layer */
3727 		epl_set_sequence_nr(pinfo, 0x02);
3728 	}
3729 	/* if cooked/fuzzed capture*/
3730 	else if(seq_recv >= EPL_MAX_SEQUENCE || seq_send >= EPL_MAX_SEQUENCE
3731 			||rcon > EPL_RETRANSMISSION || scon > EPL_RETRANSMISSION )
3732 	{
3733 		if(seq_recv >= EPL_MAX_SEQUENCE)
3734 		{
3735 			expert_add_info(pinfo, epl_tree, &ei_recvseq_value);
3736 		}
3737 		if(seq_send >= EPL_MAX_SEQUENCE)
3738 		{
3739 			expert_add_info(pinfo, epl_tree, &ei_sendseq_value);
3740 		}
3741 		duplication = 0x00;
3742 		epl_set_sequence_nr(pinfo, 0x00);
3743 	}
3744 	else
3745 	{
3746 		/* if retransmission request or connection valid with acknowledge request */
3747 		if((rcon == EPL_VALID && scon == EPL_RETRANSMISSION) || (rcon == EPL_RETRANSMISSION && scon == EPL_VALID))
3748 		{
3749 			/* replace the saved frame with the new frame */
3750 			epl_duplication_insert(epl_duplication_table, key, frame);
3751 		}
3752 		/* if connection valid */
3753 		else
3754 		{
3755 			/* store the new frame in the hash table */
3756 			if(saved_frame == 0x00)
3757 			{
3758 				/* store the new frame in the hash table */
3759 				epl_duplication_insert(epl_duplication_table,key,frame);
3760 			}
3761 			/* if the frame is bigger than the stored frame + the max frame offset
3762 			   or the saved frame is bigger that the current frame then store the current
3763 			   frame */
3764 			else if(((frame > (saved_frame + EPL_MAX_FRAME_OFFSET))
3765 				||(saved_frame > frame)))
3766 			{
3767 				/* store the new frame in the hash table */
3768 				epl_duplication_insert(epl_duplication_table,key,frame);
3769 			}
3770 			else if((frame < (saved_frame + EPL_MAX_FRAME_OFFSET))
3771 				&&(frame > saved_frame))
3772 			{
3773 				duplication = 0x01;
3774 			}
3775 		}
3776 	}
3777 	/* if the frame is a duplicated frame */
3778 	seqnum = epl_get_sequence_nr(pinfo);
3779 	if((duplication == 0x01 && seqnum == 0x00)||(seqnum == 0x01))
3780 	{
3781 		seqnum = 0x01;
3782 		epl_set_sequence_nr(pinfo, seqnum);
3783 		expert_add_info_format(pinfo, epl_tree, &ei_duplicated_frame,
3784 			"Duplication of Frame: %d ReceiveSequenceNumber: %d and SendSequenceNumber: %d ",
3785 			saved_frame,seq_recv,seq_send );
3786 	}
3787 	/* if the last frame in the ReceiveSequence is sent get new memory */
3788 	if(seq_recv == 0x3f && seq_send <= 0x3f)
3789 	{
3790 		/* reset all entries of the transfer */
3791 		epl_duplication_remove(epl_duplication_table,epl_segmentation.src,epl_segmentation.dest);
3792 	}
3793 	free_key(key);
3794 	item = proto_tree_add_item(epl_tree, hf_epl_asnd_sdo_seq, tvb,  offset, 5, ENC_NA);
3795 	sod_seq_tree = proto_item_add_subtree(item, ett_epl_sdo_sequence_layer);
3796 	/* Asynchronuous SDO Sequence Layer */
3797 	seq_recv = tvb_get_guint8(tvb, offset);
3798 
3799 	proto_tree_add_uint(sod_seq_tree, hf_epl_asnd_sdo_seq_receive_sequence_number, tvb, offset, 1, seq_recv);
3800 	proto_tree_add_uint(sod_seq_tree, hf_epl_asnd_sdo_seq_receive_con,             tvb, offset, 1, seq_recv);
3801 	offset += 1;
3802 
3803 	*seq = seq_send = tvb_get_guint8(tvb, offset);
3804 
3805 	proto_tree_add_uint(sod_seq_tree, hf_epl_asnd_sdo_seq_send_sequence_number, tvb, offset, 1, seq_send);
3806 	proto_tree_add_uint(sod_seq_tree, hf_epl_asnd_sdo_seq_send_con, tvb, offset, 1, seq_send);
3807 	offset += 3;
3808 
3809 	col_append_fstr(pinfo->cinfo, COL_INFO, "Seq:%02d%s,%02d%s",
3810 					seq_recv >> EPL_ASND_SDO_SEQ_MASK, val_to_str(seq_recv & EPL_ASND_SDO_SEQ_CON_MASK, epl_sdo_init_abbr_vals, "x"),
3811 					seq_send >> EPL_ASND_SDO_SEQ_MASK, val_to_str(seq_send & EPL_ASND_SDO_SEQ_CON_MASK, epl_sdo_init_abbr_vals, "x"));
3812 
3813 	seq_recv &= EPL_ASND_SDO_SEQ_CON_MASK;
3814 	seq_send &= EPL_ASND_SDO_SEQ_CON_MASK;
3815 
3816 	col_append_fstr(pinfo->cinfo, COL_INFO, "(%s) ", val_to_str((seq_recv << 8) | seq_send, epl_sdo_init_con_vals, "Invalid"));
3817 
3818 	return offset;
3819 }
3820 
3821 static gint
3822 dissect_epl_sdo_command(proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, guint8 seq)
3823 {
3824 	gint    payload_length;
3825 	guint8  segmented, command_id, transaction_id;
3826 	gboolean response, abort_flag;
3827 	guint32 abort_code = 0;
3828 	guint32 fragmentId = 0, remlength = 0;
3829 	guint16 segment_size = 0;
3830 	proto_tree *sdo_cmd_tree = NULL;
3831 	proto_item *item;
3832 	guint8 sendCon = 0;
3833 	guint is_response = 0;
3834 
3835 	offset += 1;
3836 
3837 	sendCon = tvb_get_guint8(tvb, 5) & EPL_ASND_SDO_SEQ_SEND_CON_ERROR_VALID_ACK_REQ;
3838 
3839 	command_id = tvb_get_guint8(tvb, offset + 2);
3840 	abort_flag = tvb_get_guint8(tvb, offset + 1) & EPL_ASND_SDO_CMD_ABORT_FILTER;
3841 
3842 	/* test if CommandField == empty */
3843 	if (command_id != 0 || abort_flag)
3844 	{
3845 		item = proto_tree_add_item(epl_tree, hf_epl_asnd_sdo_cmd, tvb,  offset, 0, ENC_NA);
3846 		sdo_cmd_tree = proto_item_add_subtree(item, ett_epl_sdo_command_layer);
3847 
3848 		transaction_id = tvb_get_guint8(tvb, offset);
3849 		response   = tvb_get_guint8(tvb, offset + 1) & EPL_ASND_SDO_CMD_RESPONSE_FILTER;
3850 		segmented  = (tvb_get_guint8(tvb, offset + 1) & EPL_ASND_SDO_CMD_SEGMENTATION_FILTER) >> 4;
3851 
3852 		segment_size = tvb_get_letohs(tvb, offset + 3);
3853 
3854 		col_append_fstr(pinfo->cinfo, COL_INFO, "Cmd:%s,TID=%02d ",
3855 						val_to_str(segmented, epl_sdo_asnd_cmd_segmentation_abbr, " Inv(%d)"), transaction_id);
3856 
3857 		proto_tree_add_item(sdo_cmd_tree, hf_epl_asnd_sdo_cmd_transaction_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3858 		offset += 1;
3859 
3860 		proto_tree_add_item_ret_uint(sdo_cmd_tree, hf_epl_asnd_sdo_cmd_response, tvb, offset, 1, ENC_LITTLE_ENDIAN, &is_response);
3861 		proto_tree_add_item(sdo_cmd_tree, hf_epl_asnd_sdo_cmd_abort,    tvb, offset, 1, ENC_LITTLE_ENDIAN);
3862 
3863 		proto_tree_add_item(sdo_cmd_tree, hf_epl_asnd_sdo_cmd_segmentation, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3864 
3865 		if (segment_size != 0)
3866 		{
3867 			offset += 1;
3868 			proto_tree_add_item(sdo_cmd_tree, hf_epl_asnd_sdo_cmd_command_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3869 			offset += 1;
3870 
3871 			item = proto_tree_add_item(sdo_cmd_tree, hf_epl_asnd_sdo_cmd_segment_size, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3872 			offset += 4;
3873 			if ( tvb_reported_length_remaining(tvb, offset) < segment_size )
3874 				expert_add_info_format(pinfo, item, &ei_real_length_differs,
3875 								"Captured length differs, only %d octets will be displayed", tvb_reported_length_remaining(tvb, offset) - 4 );
3876 		}
3877 
3878 		if (segmented == EPL_ASND_SDO_CMD_SEGMENTATION_INITIATE_TRANSFER)
3879 		{
3880 			if((command_id == EPL_ASND_SDO_COMMAND_WRITE_BY_INDEX) || (command_id == EPL_ASND_SDO_COMMAND_READ_BY_INDEX))
3881 			{
3882 				if (sendCon != EPL_ASND_SDO_SEQ_SEND_CON_ERROR_VALID_ACK_REQ)
3883 				{
3884 					/* if download => reset counter */
3885 					if(command_id == EPL_ASND_SDO_COMMAND_WRITE_BY_INDEX)
3886 						ct = 0x00;
3887 					/* if upload => reset counter */
3888 					else if(command_id == EPL_ASND_SDO_COMMAND_READ_BY_INDEX)
3889 						count = 0x00;
3890 				}
3891 				/* payload length */
3892 				payload_length = tvb_reported_length_remaining(tvb, offset);
3893 				/* create a key for reassembly => first 16 bit are src-address and
3894 				last 16 bit are the dest-address */
3895 				fragmentId = (guint32)((((guint32)epl_segmentation.src)<<16)+epl_segmentation.dest);
3896 				/* set fragmented flag */
3897 				pinfo->fragmented = TRUE;
3898 				fragment_add_seq_check(&epl_reassembly_table, tvb, offset, pinfo,
3899 												fragmentId, NULL, 0, payload_length, TRUE );
3900 				fragment_add_seq_offset ( &epl_reassembly_table, pinfo, fragmentId, NULL, 0 );
3901 				if (command_id == EPL_ASND_SDO_COMMAND_WRITE_BY_INDEX)
3902 				{
3903 					first_write = FALSE;
3904 				}
3905 				else
3906 				{
3907 					first_read = FALSE;
3908 				}
3909 				/* if Segmentation = Initiate then print DataSize */
3910 				proto_tree_add_item(sdo_cmd_tree, hf_epl_asnd_sdo_cmd_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3911 				segmented = TRUE;
3912 
3913 				offset += 4;
3914 			}
3915 			else
3916 			{
3917 				/* if Segmentation = Initiate then print DataSize */
3918 				proto_tree_add_item(sdo_cmd_tree, hf_epl_asnd_sdo_cmd_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3919 				segmented = TRUE;
3920 				offset += 4;
3921 			}
3922 		}
3923 		if (abort_flag)
3924 		{
3925 			remlength = tvb_captured_length_remaining(tvb, offset);
3926 			if (command_id == EPL_ASND_SDO_COMMAND_WRITE_MULTIPLE_PARAMETER_BY_INDEX && response)
3927 			{
3928 				/* the SDO response can contain several abort codes for multiple transfers */
3929 				while (remlength > 0)
3930 				{
3931 					/* TODO enchance Index and SubIndex with string representation */
3932 					proto_tree_add_item(sdo_cmd_tree, hf_epl_asnd_sdo_cmd_data_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3933 					offset += 2;
3934 
3935 					proto_tree_add_item(sdo_cmd_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3936 					offset += 1;
3937 
3938 					proto_tree_add_item(sdo_cmd_tree, hf_epl_asnd_sdo_cmd_sub_abort, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3939 					offset += 1;
3940 
3941 					abort_code = tvb_get_letohl(tvb, offset);
3942 					/* if AbortBit is set then print AbortMessage */
3943 					proto_tree_add_uint(sdo_cmd_tree, hf_epl_asnd_sdo_cmd_abort_code, tvb, offset, 4, abort_code);
3944 					col_append_fstr(pinfo->cinfo, COL_INFO, "Abort:0x%08X (%s)", abort_code, val_to_str_ext_const(abort_code, &sdo_cmd_abort_code_ext, "Unknown"));
3945 					offset += 4;
3946 
3947 					remlength = tvb_captured_length_remaining(tvb, offset);
3948 				}
3949 			}
3950 			else
3951 			{
3952 				abort_code = tvb_get_letohl(tvb, offset);
3953 				/* if AbortBit is set then print AbortMessage */
3954 				proto_tree_add_uint(sdo_cmd_tree, hf_epl_asnd_sdo_cmd_abort_code, tvb, offset, 4, abort_code);
3955 				col_append_fstr(pinfo->cinfo, COL_INFO, "Abort:0x%08X (%s)", abort_code, val_to_str_ext_const(abort_code, &sdo_cmd_abort_code_ext, "Unknown"));
3956 			}
3957 		}
3958 		else
3959 		{
3960 			int opts = is_response ? CONVO_FOR_RESPONSE : CONVO_FOR_REQUEST;
3961 			struct epl_convo *convo = epl_get_convo(pinfo, opts);
3962 			convo->seq_send = seq;
3963 
3964 			switch (command_id)
3965 			{
3966 			case EPL_ASND_SDO_COMMAND_WRITE_BY_INDEX:
3967 				offset = dissect_epl_sdo_command_write_by_index(convo, sdo_cmd_tree, tvb, pinfo, offset, segmented, response, segment_size);
3968 				break;
3969 
3970 			case EPL_ASND_SDO_COMMAND_WRITE_MULTIPLE_PARAMETER_BY_INDEX:
3971 				offset = dissect_epl_sdo_command_write_multiple_by_index(convo, sdo_cmd_tree, tvb, pinfo, offset, segmented, response, segment_size);
3972 				break;
3973 
3974 			case EPL_ASND_SDO_COMMAND_READ_MULTIPLE_PARAMETER_BY_INDEX:
3975 				offset = dissect_epl_sdo_command_read_multiple_by_index(convo, sdo_cmd_tree, tvb, pinfo, offset, segmented, response, segment_size);
3976 				break;
3977 
3978 			case EPL_ASND_SDO_COMMAND_READ_BY_INDEX:
3979 				offset = dissect_epl_sdo_command_read_by_index(convo, sdo_cmd_tree, tvb, pinfo, offset, segmented, response, segment_size);
3980 				break;
3981 
3982 			default:
3983 				return FALSE;
3984 			}
3985 		}
3986 	}
3987 	return offset;
3988 }
3989 
3990 static gint
3991 dissect_epl_sdo_command_write_by_index(struct epl_convo *convo, proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, guint8 segmented, gboolean response, guint16 segment_size)
3992 {
3993 	gint size, payload_length, rem_size = 0;
3994 	guint16 idx = 0x00, sod_index = 0xFF, error = 0xFF, sub_val = 0x00;
3995 	gboolean nosub = FALSE;
3996 	guint8 subindex = 0x00;
3997 	guint32 fragmentId = 0;
3998 	guint32 frame = 0;
3999 	gboolean end_segment = FALSE;
4000 	proto_item *psf_item, *cmd_payload;
4001 	proto_tree *payload_tree;
4002 	const gchar *index_str, *sub_str, *sub_index_str;
4003 	fragment_head *frag_msg = NULL;
4004 	struct object *obj = NULL;
4005 	const struct subobject *subobj = NULL;
4006 
4007 	/* get the current frame number */
4008 	frame = pinfo->num;
4009 
4010 	if (!response)
4011 	{   /* request */
4012 
4013 		if (segmented <= EPL_ASND_SDO_CMD_SEGMENTATION_INITIATE_TRANSFER)
4014 		{
4015 			/* get index offset */
4016 			idx = tvb_get_letohs(tvb, offset);
4017 			/* add index item */
4018 			psf_item = proto_tree_add_item(epl_tree, hf_epl_asnd_sdo_cmd_data_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
4019 			/* look up index in registered profile */
4020 			obj = object_lookup(convo->profile, idx);
4021 			if (!obj)
4022 			{
4023 				/* value to string */
4024 				index_str = rval_to_str_const(idx, sod_cmd_str, "unknown");
4025 				/* get index string value */
4026 				sod_index = str_to_val(index_str, sod_cmd_str_val, error);
4027 
4028 				/* get subindex string */
4029 				sub_index_str = val_to_str_ext_const(idx, &sod_cmd_no_sub, "unknown");
4030 				/* get subindex string value */
4031 				nosub = str_to_val(sub_index_str, sod_cmd_str_no_sub, 0xFF) != 0xFF;
4032 			}
4033 			offset += 2;
4034 
4035 			/* get subindex offset */
4036 			subindex = tvb_get_guint8(tvb, offset);
4037 			subobj = subobject_lookup(obj, subindex);
4038 
4039 
4040 			/* get subindex string */
4041 			sub_str = val_to_str_ext_const(subindex, &sod_cmd_sub_str, "unknown");
4042 			/* get string value */
4043 			sub_val = str_to_val(sub_str, sod_cmd_sub_str_val, error);
4044 
4045 			col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%d]: (0x%04X/%d)",
4046 							val_to_str_ext(EPL_ASND_SDO_COMMAND_WRITE_BY_INDEX, &epl_sdo_asnd_commands_short_ext, "Command(%02X)"),
4047 							segment_size, idx, subindex);
4048 
4049 			if (obj || sod_index == error)
4050 			{
4051 				const char *name = obj ? obj->info.name : val_to_str_ext_const(((guint32)(idx<<16)), &sod_index_names, "User Defined");
4052 				proto_item_append_text(psf_item, " (%s)", name);
4053 				col_append_fstr(pinfo->cinfo, COL_INFO, " (%s", name);
4054 				if (obj) nosub = obj->info.type_class == OD_ENTRY_SCALAR;
4055 			}
4056 			else /* string is in list */
4057 			{
4058 				/* add index string to index item */
4059 				proto_item_append_text(psf_item," (%s", val_to_str_ext_const(((guint32)(sod_index<<16)), &sod_index_names, "User Defined"));
4060 				proto_item_append_text(psf_item,"_%02Xh", (idx-sod_index));
4061 				if(sod_index == EPL_SOD_PDO_RX_MAPP || sod_index == EPL_SOD_PDO_TX_MAPP)
4062 				{
4063 					proto_item_append_text(psf_item,"_AU64)");
4064 				}
4065 				else
4066 				{
4067 					proto_item_append_text(psf_item,"_REC)");
4068 				}
4069 				/* info text */
4070 				col_append_fstr(pinfo->cinfo, COL_INFO, " (%s", val_to_str_ext_const(((guint32)(sod_index << 16)), &sod_index_names, "User Defined"));
4071 				col_append_fstr(pinfo->cinfo, COL_INFO, "_%02Xh", (idx-sod_index));
4072 				if(sod_index == EPL_SOD_PDO_RX_MAPP || sod_index == EPL_SOD_PDO_TX_MAPP)
4073 				{
4074 					col_append_fstr(pinfo->cinfo, COL_INFO, "_AU64");
4075 				}
4076 				else
4077 				{
4078 					col_append_fstr(pinfo->cinfo, COL_INFO, "_REC");
4079 				}
4080 				idx = sod_index;
4081 			}
4082 
4083 			if(sub_val != error)
4084 				idx = sub_val;
4085 
4086 			if (subobj)
4087 			{
4088 				psf_item = proto_tree_add_item(epl_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4089 				proto_item_append_text(psf_item, " (%s)", subobj->info.name);
4090 				col_append_fstr(pinfo->cinfo, COL_INFO, "/%s)", subobj->info.name);
4091 			}
4092 			/* if the subindex is a EPL_SOD_STORE_PARAM */
4093 			/* if the subindex is a EPL_SOD_RESTORE_PARAM */
4094 			else if((idx == EPL_SOD_STORE_PARAM && subindex <= 0x7F && subindex >= 0x04) ||
4095 					(idx == EPL_SOD_RESTORE_PARAM && subindex <= 0x7F && subindex >= 0x04))
4096 			{
4097 				psf_item = proto_tree_add_item(epl_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4098 				proto_item_append_text(psf_item, " (ManufacturerParam_%02Xh_U32)", subindex);
4099 				col_append_fstr(pinfo->cinfo, COL_INFO, "/ManufacturerParam_%02Xh_U32)", subindex);
4100 			}
4101 			/* if the subindex is a EPL_SOD_PDO_RX_MAPP */
4102 			/* if the subindex is a EPL_SOD_PDO_TX_MAPP */
4103 			else if((idx == EPL_SOD_PDO_RX_MAPP && subindex >= 0x01 && subindex <= 0xfe) ||
4104 					(idx == EPL_SOD_PDO_TX_MAPP && subindex >= 0x01 && subindex <= 0xfe))
4105 			{
4106 				psf_item = proto_tree_add_item(epl_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4107 				proto_item_append_text(psf_item, " (ObjectMapping)");
4108 				col_append_fstr(pinfo->cinfo, COL_INFO, "/ObjectMapping)");
4109 			}
4110 			/* no subindex */
4111 			else if(nosub)
4112 			{
4113 				col_append_fstr(pinfo->cinfo, COL_INFO, ")");
4114 			}
4115 			else if(subindex == 0x00)
4116 			{
4117 				psf_item = proto_tree_add_item(epl_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4118 				proto_item_append_text(psf_item, " (NumberOfEntries)");
4119 				col_append_fstr(pinfo->cinfo, COL_INFO, "/NumberOfEntries)");
4120 			}
4121 			else
4122 			{
4123 				psf_item = proto_tree_add_item(epl_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4124 				proto_item_append_text(psf_item, " (%s)", val_to_str_ext_const((subindex | (idx << 16)), &sod_index_names, "User Defined"));
4125 				col_append_fstr(pinfo->cinfo, COL_INFO, "/%s)",val_to_str_ext_const((subindex | (idx << 16)), &sod_index_names, "User Defined"));
4126 			}
4127 			offset += 2;
4128 		}
4129 		/* Download */
4130 		else if((segmented == EPL_ASND_SDO_CMD_SEGMENTATION_TRANSFER_COMPLETE) ||
4131 			(segmented == EPL_ASND_SDO_CMD_SEGMENTATION_SEGMENT))
4132 		{
4133 			/* get the fragmentId */
4134 			fragmentId = (guint32)((((guint32)epl_segmentation.src)<<16)+epl_segmentation.dest);
4135 			/* set the fragmented flag */
4136 			pinfo->fragmented = TRUE;
4137 
4138 			/* get payloade size */
4139 			payload_length = tvb_reported_length_remaining(tvb, offset);
4140 			/* if the frame is the last frame */
4141 			if(segmented == EPL_ASND_SDO_CMD_SEGMENTATION_TRANSFER_COMPLETE)
4142 				end_segment = TRUE;
4143 
4144 			/* if the send-sequence-number is at the end or the beginning of a sequence */
4145 			if(epl_segmentation.send == 0x3f || epl_segmentation.send <= 0x01 )
4146 			{
4147 				/* reset memory */
4148 				memset(&epl_asnd_sdo_reassembly_write,0,sizeof(epl_sdo_reassembly));
4149 				/* save the current frame and increase the counter */
4150 				epl_asnd_sdo_reassembly_write.frame[epl_segmentation.recv][epl_segmentation.send] = frame;
4151 				ct += 1;
4152 				/* add the frame to reassembly_table */
4153 				frag_msg = fragment_add_seq_check(&epl_reassembly_table, tvb, offset, pinfo,
4154 							  fragmentId, NULL, ct, payload_length, end_segment ? FALSE : TRUE );
4155 			}
4156 			else
4157 			{
4158 				if(epl_asnd_sdo_reassembly_write.frame[epl_segmentation.recv][epl_segmentation.send] == 0x00)
4159 				{
4160 					/* save the current frame and increase counter */
4161 					epl_asnd_sdo_reassembly_write.frame[epl_segmentation.recv][epl_segmentation.send] = frame;
4162 					ct += 1;
4163 					/* add the frame to reassembly_table */
4164 					if (first_write)
4165 					{
4166 						frag_msg = fragment_add_seq_check(&epl_reassembly_table, tvb, offset, pinfo,
4167 							fragmentId, NULL, 0, payload_length, end_segment ? FALSE : TRUE );
4168 						fragment_add_seq_offset(&epl_reassembly_table, pinfo, fragmentId, NULL, ct);
4169 
4170 						first_write = FALSE;
4171 					}
4172 					else
4173 					{
4174 						frag_msg = fragment_add_seq_check(&epl_reassembly_table, tvb, offset, pinfo,
4175 							fragmentId, NULL, ct, payload_length, end_segment ? FALSE : TRUE );
4176 					}
4177 				}
4178 				else
4179 				{
4180 					frag_msg = fragment_add_seq_check(&epl_reassembly_table, tvb, offset, pinfo,
4181 						fragmentId, NULL, 0, payload_length, end_segment ? FALSE : TRUE);
4182 					epl_asnd_sdo_reassembly_write.frame[epl_segmentation.recv][epl_segmentation.send] = frame;
4183 				}
4184 			}
4185 
4186 			/* if the reassembly_table is not Null and the frame stored is the same as the current frame */
4187 			if(frag_msg != NULL && (epl_asnd_sdo_reassembly_write.frame[epl_segmentation.recv][epl_segmentation.send] == frame))
4188 			{
4189 				/* if the frame is the last frame */
4190 				if(end_segment)
4191 				{
4192 					cmd_payload = proto_tree_add_uint_format(epl_tree, hf_epl_asnd_sdo_cmd_reassembled, tvb, offset, payload_length,0,
4193 															"Reassembled: %d bytes total (%d bytes in this frame)",frag_msg->len,payload_length);
4194 					payload_tree = proto_item_add_subtree(cmd_payload, ett_epl_asnd_sdo_data_reassembled);
4195 					/* add the reassembley fields */
4196 					process_reassembled_data(tvb, 0, pinfo, "Reassembled Message", frag_msg, &epl_frag_items, NULL, payload_tree );
4197 					proto_tree_add_uint_format_value(payload_tree, hf_epl_asnd_sdo_cmd_reassembled, tvb, 0, 0,
4198 									payload_length, "%d bytes (over all fragments)", frag_msg->len);
4199 					col_append_str(pinfo->cinfo, COL_INFO, " (Message Reassembled)" );
4200 				}
4201 				else
4202 				{
4203 					cmd_payload = proto_tree_add_uint_format(epl_tree, hf_epl_asnd_sdo_cmd_reassembled, tvb, offset, payload_length,0,
4204 														"Reassembled: %d bytes total (%d bytes in this frame)",frag_msg->len,payload_length);
4205 					payload_tree = proto_item_add_subtree(cmd_payload, ett_epl_asnd_sdo_data_reassembled);
4206 					/* add reassemble field => Reassembled in: */
4207 					process_reassembled_data(tvb, 0, pinfo, "Reassembled Message", frag_msg, &epl_frag_items, NULL, payload_tree );
4208 				}
4209 				ct = 0;
4210 			}
4211 		}
4212 
4213 		/* determine remaining SDO payload size (depends on segment size of current command) */
4214 		size = tvb_reported_length_remaining(tvb, offset);
4215 		if(size > (segment_size - 4))
4216 		{
4217 			rem_size = (segment_size - 4);
4218 		}
4219 		else
4220 		{
4221 			rem_size = size;
4222 		}
4223 
4224 		/* if the frame is a PDO Mapping and the subindex is bigger than 0x00 */
4225 		if((idx == EPL_SOD_PDO_TX_MAPP && subindex > 0x00) || (idx == EPL_SOD_PDO_RX_MAPP && subindex > 0x00))
4226 		{
4227 			wmem_array_t *mappings = NULL;
4228 			if (use_sdo_mappings)
4229 				mappings = idx == EPL_SOD_PDO_TX_MAPP ? convo->TPDO : convo->RPDO;
4230 
4231 			offset = dissect_object_mapping(convo->profile, mappings, epl_tree, tvb, pinfo->num, offset, idx, subindex);
4232 		}
4233 		else
4234 		{
4235 			/* dissect the payload */
4236 			const struct epl_datatype *type = NULL;
4237 			if (subobj)
4238 				type = subobj->info.type;
4239 			else if (obj)
4240 				type = obj->info.type;
4241 
4242 			offset = dissect_epl_payload(epl_tree, tvb, pinfo, offset, rem_size, type, EPL_ASND);
4243 		}
4244 	}
4245 	else
4246 	{
4247 		/* response, no payload */
4248 		col_append_str(pinfo->cinfo, COL_INFO, "Response");
4249 	}
4250 	return offset;
4251 }
4252 
4253 /* epl_tree may be null here, when this function is called from the profile parser */
4254 static gint
4255 dissect_object_mapping(struct profile *profile, wmem_array_t *mappings, proto_tree *epl_tree, tvbuff_t *tvb, guint32 framenum, gint offset, guint16 idx, guint8 subindex)
4256 {
4257 	proto_item *ti_obj, *ti_subobj, *psf_item;
4258 	proto_tree *psf_tree;
4259 	struct object_mapping map = OBJECT_MAPPING_INITIALIZER;
4260 	struct object *mapping_obj;
4261 	int *ett;
4262 	const struct subobject *mapping_subobj;
4263 	gboolean nosub = FALSE;
4264 
4265 	/* If we don't populate the tree or record mappings, skip over it */
4266 	if (!epl_tree && !mappings)
4267 		return offset + EPL_OBJECT_MAPPING_SIZE;
4268 
4269 	map.param.idx = idx;
4270 	map.param.subindex = subindex;
4271 	map.frame.first = framenum;
4272 	map.frame.last  = G_MAXUINT32;
4273 
4274 	psf_item = proto_tree_add_item(epl_tree, hf_epl_asnd_sdo_cmd_data_mapping, tvb, offset, 1, ENC_NA);
4275 	psf_tree = proto_item_add_subtree(psf_item, ett_epl_asnd_sdo_cmd_data_mapping);
4276 
4277 	map.pdo.idx = tvb_get_letohs(tvb, offset);
4278 	ti_obj = proto_tree_add_uint_format(psf_tree, hf_epl_asnd_sdo_cmd_data_mapping_index, tvb, offset, 2, map.pdo.idx,"Index: 0x%04X", map.pdo.idx);
4279 	offset += 2;
4280 
4281 	map.pdo.subindex = tvb_get_guint8(tvb, offset);
4282 	ti_subobj = proto_tree_add_uint_format(psf_tree, hf_epl_asnd_sdo_cmd_data_mapping_subindex, tvb, offset, 1, map.pdo.subindex, "SubIndex: 0x%02X", map.pdo.subindex);
4283 	offset += 2;
4284 
4285 	/* look up index in registered profiles */
4286 	if ((mapping_obj = object_lookup(profile, map.pdo.idx)))
4287 	{
4288 		if (!map.pdo.subindex && mapping_obj->info.type_class == OD_ENTRY_SCALAR)
4289 			nosub = TRUE;
4290 
4291 		map.info = &mapping_obj->info;
4292 		map.index_name = map.info->name;
4293 		proto_item_append_text (ti_obj, " (%s)", map.info->name);
4294 
4295 		mapping_subobj = subobject_lookup(mapping_obj, map.pdo.subindex);
4296 		if (mapping_subobj)
4297 		{
4298 			map.info = &mapping_subobj->info;
4299 			proto_item_append_text (ti_subobj, " (%s)", map.info->name);
4300 		}
4301 		else
4302 		{
4303 			proto_item_set_hidden(ti_subobj);
4304 		}
4305 	}
4306 
4307 	map.bit_offset = tvb_get_letohs(tvb, offset);
4308 	proto_tree_add_uint_format(psf_tree, hf_epl_asnd_sdo_cmd_data_mapping_offset, tvb, offset, 2, map.bit_offset,"Offset: 0x%04X", map.bit_offset);
4309 	offset += 2;
4310 
4311 	map.no_of_bits = tvb_get_guint8(tvb, offset);
4312 	psf_item = proto_tree_add_item(psf_tree, hf_epl_asnd_sdo_cmd_data_mapping_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
4313 	proto_item_append_text(psf_item, " bits");
4314 	offset += 2;
4315 
4316 	map.ett = -1;
4317 	ett = &map.ett;
4318 	/* We leak an ett entry every time we destruct a mapping
4319 	 * Not sure what to do about that
4320 	 */
4321 	proto_register_subtree_array(&ett, 1);
4322 
4323 	if (mappings)
4324 	{
4325 		/* TODO One could think of a better string here? */
4326 		if (nosub)
4327 			g_snprintf(map.title, sizeof(map.title), "PDO - %04X", map.pdo.idx);
4328 		else
4329 			g_snprintf(map.title, sizeof(map.title), "PDO - %04X:%02X", map.pdo.idx, map.pdo.subindex);
4330 
4331 		add_object_mapping(mappings, &map);
4332 	}
4333 
4334 	return offset;
4335 }
4336 
4337 static gint
4338 dissect_epl_sdo_command_write_multiple_by_index(struct epl_convo *convo, proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, guint8 segmented, gboolean response, guint16 segment_size)
4339 {
4340 	gint dataoffset;
4341 	guint8 subindex = 0x00,  padding = 0x00;
4342 	guint16 idx = 0x00, error = 0xFF, sub_val = 0x00;
4343 	gboolean nosub = FALSE;
4344 	guint32 size, offsetincrement, datalength, remlength, objectcnt, abort_code = 0;
4345 	gboolean lastentry = FALSE, is_abort = FALSE;
4346 	const gchar *index_str, *sub_str, *sub_index_str;
4347 	proto_item *psf_item;
4348 	proto_tree *psf_od_tree;
4349 	struct object *obj = NULL;
4350 	const struct subobject *subobj = NULL;
4351 	guint16 segment_restsize = segment_size;
4352 
4353 
4354 	/* Offset is calculated simply by only applying EPL payload offset, not packet offset.
4355 	* The packet offset is 16, as this is the number of bytes trailing the SDO payload.
4356 	* EPL_SOA_EPLV_OFFSET has to be recognized, because the increment of PLK SDO payloads
4357 	* is calculated, starting with the byte position AFTER the Sequence Layer.
4358 	*/
4359 	if (!response)
4360 	{   /* request */
4361 
4362 		col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%d]:",
4363 				val_to_str_ext(EPL_ASND_SDO_COMMAND_WRITE_MULTIPLE_PARAMETER_BY_INDEX,
4364 				&epl_sdo_asnd_commands_short_ext, "Command(%02X)"),
4365 				segment_size);
4366 
4367 		remlength = (guint32)tvb_reported_length_remaining(tvb, offset);
4368 		objectcnt = 0;
4369 
4370 		/* As long as no lastentry has been detected, and we have still bytes left,
4371 		 * we start the loop. lastentry is probably not necessary anymore, since
4372 		 * we now use length_remaining, but it is kept to be on the safe side. */
4373 		while ( !lastentry && remlength > 0 )
4374 		{
4375 			guint16 sod_index = error;
4376 
4377 			offsetincrement = tvb_get_letohl(tvb, offset);
4378 
4379 			/* the data is aligned in 4-byte increments, therfore maximum padding is 3 */
4380 			padding = tvb_get_guint8 ( tvb, offset + 7 ) & 0x03;
4381 
4382 			/* An offset increment of zero usually indicates, that we are at the end
4383 			 * of the payload. But we cannot ignore the end, because packages are
4384 			 * stacked up until the last byte */
4385 			if (offsetincrement == 0)
4386 			{
4387 				datalength = segment_restsize;
4388 				lastentry = TRUE;
4389 			}
4390 			else
4391 			{
4392 				datalength = offsetincrement - (offset - EPL_SOA_EPLV_OFFSET);
4393 			}
4394 			/* decrease restsize */
4395 			segment_restsize -= datalength;
4396 
4397 			/* Possible guint overflow */
4398 			if ( datalength > remlength )
4399 				break;
4400 
4401 			/* Each entry has a header size of 8, based on the following calculation:
4402 			*   - 4 byte for byte position of next data set
4403 			*   - 2 byte for index
4404 			*   - 1 byte for subindex
4405 			*   - 1 byte for reserved and padding */
4406 
4407 			/* Guarding against readout of padding. Probability is nearly zero, as
4408 			 * padding was checked above, but to be sure, this remains here */
4409 			if ((guint32)(padding + 8) >= datalength)
4410 				break;
4411 
4412 			/* size of data is datalength - ( entry header size and padding ) */
4413 			size = datalength - 8 - padding;
4414 
4415 			dataoffset = offset + 4;
4416 
4417 			/* add object subtree */
4418 			psf_od_tree = proto_tree_add_subtree(epl_tree, tvb, offset+4, 4+size, 0, NULL , "OD");
4419 
4420 			if (segmented <= EPL_ASND_SDO_CMD_SEGMENTATION_INITIATE_TRANSFER)
4421 			{
4422 				/* get SDO index value */
4423 				idx = tvb_get_letohs(tvb, dataoffset);
4424 				/* add index item */
4425 				psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_index, tvb, offset+4, 2, ENC_LITTLE_ENDIAN);
4426 				/* Check profile for name */
4427 				obj = object_lookup(convo->profile, idx);
4428 				if (!obj)
4429 				{
4430 					/* value to string */
4431 					index_str = rval_to_str_const(idx, sod_cmd_str, "unknown");
4432 					/* get index string value */
4433 					sod_index = str_to_val(index_str, sod_cmd_str_val, error);
4434 
4435 					/* get subindex string */
4436 					sub_index_str = val_to_str_ext_const(idx, &sod_cmd_no_sub, "unknown");
4437 					/* get subindex string value*/
4438 					nosub = str_to_val(sub_index_str, sod_cmd_str_no_sub, 0xFF) != 0xFF;
4439 				}
4440 
4441 				if(sod_index == error)
4442 				{
4443 					const char *name = obj ? obj->info.name :val_to_str_ext_const(((guint32)(idx<<16)), &sod_index_names, "User Defined");
4444 					proto_item_append_text(psf_item," (%s)", name);
4445 				}
4446 				else
4447 				{
4448 					/* add index string */
4449 					proto_item_append_text(psf_item," (%s", val_to_str_ext_const(((guint32)(sod_index<<16)), &sod_index_names, "User Defined"));
4450 					proto_item_append_text(psf_item,"_%02Xh", (idx-sod_index));
4451 					if(sod_index == EPL_SOD_PDO_RX_MAPP || sod_index == EPL_SOD_PDO_TX_MAPP)
4452 					{
4453 						proto_item_append_text(psf_item,"_AU64)");
4454 					}
4455 					else
4456 					{
4457 						proto_item_append_text(psf_item,"_REC)");
4458 					}
4459 				}
4460 
4461 				if (objectcnt < 8)
4462 					col_append_fstr(pinfo->cinfo, COL_INFO, " (0x%04X", idx);
4463 				else
4464 					col_append_str(pinfo->cinfo, COL_INFO, ".");
4465 
4466 				dataoffset += 2;
4467 
4468 				proto_item_append_text(psf_od_tree, " Idx: 0x%04X", idx);
4469 
4470 				if (sod_index != error)
4471 					idx = sod_index;
4472 
4473 				/* get subindex offset */
4474 				subindex = tvb_get_guint8(tvb, dataoffset);
4475 				subobj = subobject_lookup(obj, subindex);
4476 				proto_item_append_text(psf_od_tree, " SubIdx: 0x%02X", subindex);
4477 				/* get subindex string */
4478 				sub_str = val_to_str_ext_const(idx, &sod_cmd_sub_str, "unknown");
4479 				/* get string value */
4480 				sub_val = str_to_val(sub_str, sod_cmd_sub_str_val,error);
4481 
4482 				if(sub_val != error)
4483 					idx = sub_val;
4484 
4485 				if (subobj)
4486 				{
4487 					psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, dataoffset, 1, ENC_LITTLE_ENDIAN);
4488 					proto_item_append_text(psf_item, " (%s)", subobj->info.name);
4489 				}
4490 				/* if the subindex is a EPL_SOD_STORE_PARAM */
4491 				else if(idx == EPL_SOD_STORE_PARAM && subindex <= 0x7F && subindex >= 0x04)
4492 				{
4493 					psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, dataoffset, 1, ENC_LITTLE_ENDIAN);
4494 					proto_item_append_text(psf_item, " (ManufacturerParam_%02Xh_U32)", subindex);
4495 				}
4496 				/* if the subindex is a EPL_SOD_RESTORE_PARAM */
4497 				else if(idx == EPL_SOD_RESTORE_PARAM && subindex <= 0x7F && subindex >= 0x04)
4498 				{
4499 					psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, dataoffset, 1, ENC_LITTLE_ENDIAN);
4500 					proto_item_append_text(psf_item, " (ManufacturerParam_%02Xh_U32)", subindex);
4501 				}
4502 				/* if the subindex is a EPL_SOD_PDO_RX_MAPP */
4503 				else if(idx == EPL_SOD_PDO_RX_MAPP && subindex >= 0x01 && subindex <= 0xfe)
4504 				{
4505 					psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, dataoffset, 1, ENC_LITTLE_ENDIAN);
4506 					proto_item_append_text(psf_item, " (ObjectMapping)");
4507 				}
4508 				/* if the subindex is a EPL_SOD_PDO_TX_MAPP */
4509 				else if(idx == EPL_SOD_PDO_TX_MAPP && subindex >= 0x01 && subindex <= 0xfe)
4510 				{
4511 					psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, dataoffset, 1, ENC_LITTLE_ENDIAN);
4512 					proto_item_append_text(psf_item, " (ObjectMapping)");
4513 				}
4514 				/* if the subindex has the value 0x00 */
4515 				else if(subindex == 0x00)
4516 				{
4517 					psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, dataoffset, 1, ENC_LITTLE_ENDIAN);
4518 					proto_item_append_text(psf_item, " (NumberOfEntries)");
4519 				}
4520 				/* subindex */
4521 				else
4522 				{
4523 					psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, dataoffset, 1, ENC_LITTLE_ENDIAN);
4524 					proto_item_append_text(psf_item, " (%s)", val_to_str_ext_const((subindex | (idx << 16)), &sod_index_names, "User Defined"));
4525 				}
4526 
4527 				/* info text */
4528 				if (objectcnt < 8)
4529 				{
4530 					if (nosub)
4531 						/* no subindex */
4532 						col_append_fstr(pinfo->cinfo, COL_INFO, ")");
4533 					else
4534 						col_append_fstr(pinfo->cinfo, COL_INFO, "/%d)", subindex);
4535 				}
4536 
4537 
4538 				dataoffset += 1;
4539 				proto_tree_add_uint(psf_od_tree, hf_epl_asnd_sdo_cmd_data_padding, tvb, dataoffset, 1, padding);
4540 				dataoffset += 1;
4541 				objectcnt++;
4542 			}
4543 
4544 			/* size of embedded data */
4545 			psf_item = proto_tree_add_uint_format(psf_od_tree, hf_epl_asnd_sdo_cmd_data_size, tvb, dataoffset, size, size, "Data size: %d byte", size);
4546 			proto_item_set_generated(psf_item);
4547 
4548 			/* if the frame is a PDO Mapping and the subindex is bigger than 0x00 */
4549 			if((idx == EPL_SOD_PDO_TX_MAPP && subindex > 0x00) ||(idx == EPL_SOD_PDO_RX_MAPP && subindex > 0x00))
4550 			{
4551 				wmem_array_t *mappings = NULL;
4552 				if (use_sdo_mappings)
4553 					mappings = idx == EPL_SOD_PDO_TX_MAPP ? convo->TPDO : convo->RPDO;
4554 				dissect_object_mapping(convo->profile, mappings, psf_od_tree, tvb, pinfo->num, dataoffset, idx, subindex);
4555 			}
4556 			else /* dissect the payload */
4557 			{
4558 				const struct epl_datatype *type = NULL;
4559 				if (subobj)
4560 					type = subobj->info.type;
4561 				else if (obj)
4562 					type = obj->info.type;
4563 
4564 				dissect_epl_payload(psf_od_tree, tvb, pinfo, dataoffset, size, type, EPL_ASND);
4565 			}
4566 
4567 			offset += datalength;
4568 
4569 			/* calculating the remaining length, based on the current offset */
4570 			remlength = (guint32)tvb_reported_length_remaining(tvb, offset);
4571 		}
4572 
4573 		col_append_fstr(pinfo->cinfo, COL_INFO, " (%d)", objectcnt);
4574 	}
4575 	else
4576 	{
4577 		col_append_fstr(pinfo->cinfo, COL_INFO, "Response %s[%d]:",
4578 				val_to_str_ext(EPL_ASND_SDO_COMMAND_WRITE_MULTIPLE_PARAMETER_BY_INDEX,
4579 				&epl_sdo_asnd_commands_short_ext, "Command(%02X)"),
4580 				segment_size);
4581 
4582 		remlength = (guint32)tvb_reported_length_remaining(tvb, offset);
4583 		objectcnt = 0;
4584 
4585 		dataoffset = offset;
4586 
4587 		/* As long as no lastentry has been detected, and we have still bytes left,
4588 		 * we start the loop. */
4589 		while ( remlength > 0 )
4590 		{
4591 			guint16 sod_index;
4592 			if ((tvb_get_guint8 ( tvb, offset + 3 ) & 0x80) == 0x80)
4593 				is_abort = TRUE;
4594 
4595 			/* add object subtree */
4596 			psf_od_tree = proto_tree_add_subtree(epl_tree, tvb, offset, 8, 0, NULL , "OD");
4597 
4598 			if (segmented <= EPL_ASND_SDO_CMD_SEGMENTATION_INITIATE_TRANSFER)
4599 			{
4600 				/* get SDO index value */
4601 				idx = tvb_get_letohs(tvb, dataoffset);
4602 				/* value to string */
4603 				index_str = rval_to_str_const(idx, sod_cmd_str, "unknown");
4604 				/* get index string value */
4605 				sod_index = str_to_val(index_str, sod_cmd_str_val, error);
4606 				/* get subindex string */
4607 				sub_index_str = val_to_str_ext_const(idx, &sod_cmd_no_sub, "unknown");
4608 				/* get subindex string value*/
4609 				nosub = str_to_val(sub_index_str, sod_cmd_str_no_sub,error);
4610 
4611 				if (objectcnt < 8)
4612 					col_append_fstr(pinfo->cinfo, COL_INFO, " (0x%04X", idx);
4613 				else
4614 					col_append_str(pinfo->cinfo, COL_INFO, ".");
4615 
4616 				proto_tree_add_uint_format(psf_od_tree, hf_epl_asnd_sdo_cmd_data_mapping_index, tvb, dataoffset, 2, idx,"Index: 0x%04X", idx);
4617 				proto_item_append_text(psf_od_tree, " Idx: 0x%04X", idx);
4618 
4619 				if (sod_index != error)
4620 					idx = sod_index;
4621 
4622 				dataoffset += 2;
4623 
4624 				/* get subindex offset */
4625 				subindex = tvb_get_guint8(tvb, dataoffset);
4626 				proto_item_append_text(psf_od_tree, " SubIdx: 0x%02X", subindex);
4627 				proto_tree_add_uint_format(psf_od_tree, hf_epl_asnd_sdo_cmd_data_mapping_subindex, tvb, dataoffset, 1, idx,"SubIndex: 0x%02X", subindex);
4628 
4629 				/* info text */
4630 				if (objectcnt < 8)
4631 				{
4632 					if (nosub)
4633 						/* no subindex */
4634 						col_append_fstr(pinfo->cinfo, COL_INFO, ")");
4635 					else
4636 						col_append_fstr(pinfo->cinfo, COL_INFO, "/%d)", subindex);
4637 				}
4638 
4639 				dataoffset += 1;
4640 
4641 				proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_sub_abort, tvb, dataoffset, 1, ENC_LITTLE_ENDIAN);
4642 
4643 				dataoffset += 1;
4644 
4645 				if (is_abort)
4646 				{
4647 					abort_code = tvb_get_letohl(tvb, dataoffset);
4648 
4649 					proto_item_append_text(psf_od_tree, " - %s", "Aborted");
4650 
4651 					psf_item = proto_tree_add_item(psf_od_tree, hf_epl_sdo_multi_param_sub_abort, tvb, dataoffset, 4, ENC_LITTLE_ENDIAN);
4652 					proto_item_append_text(psf_item," (%s)", val_to_str_ext_const(abort_code, &sdo_cmd_abort_code_ext, "Unknown"));
4653 
4654 					is_abort = FALSE;
4655 				}
4656 
4657 				objectcnt++;
4658 			}
4659 
4660 			/* each sub response is 8 bytes */
4661 			offset += 8;
4662 
4663 			/* calculating the remaining length, based on the current offset */
4664 			remlength = (guint32)tvb_reported_length_remaining(tvb, offset);
4665 		}
4666 
4667 		col_append_fstr(pinfo->cinfo, COL_INFO, " (%d)", objectcnt);
4668 	}
4669 	return offset;
4670 }
4671 static gint
4672 dissect_epl_sdo_command_read_multiple_by_index(struct epl_convo *convo, proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, guint8 segmented, gboolean response, guint16 segment_size)
4673 {
4674 	gint dataoffset;
4675 	guint8 subindex = 0x00,  padding = 0x00;
4676 	guint16 idx = 0x00, error = 0xFF, sub_val = 0x00;
4677 	gboolean nosub = FALSE;
4678 	guint32 size, offsetincrement, datalength, remlength, objectcnt, abort_code;
4679 	gboolean lastentry = FALSE, is_abort = FALSE;
4680 	const gchar *index_str, *sub_str, *sub_index_str;
4681 	proto_item *psf_item, *psf_od_item;
4682 	proto_tree *psf_tree, *psf_od_tree;
4683 	struct object *obj = NULL;
4684 	const struct subobject *subobj = NULL;
4685 	const char *name;
4686 	guint16 segment_restsize = segment_size;
4687 
4688 	/* Offset is calculated simply by only applying EPL payload offset, not packet offset.
4689 	* The packet offset is 16, as this is the number of bytes trailing the SDO payload.
4690 	* EPL_SOA_EPLV_OFFSET has to be recognized, because the increment of PLK SDO payloads
4691 	* is calculated, starting with the byte position AFTER the Sequence Layer.
4692 	*/
4693 	if (response)
4694 	{
4695 		col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%d]:",
4696 				val_to_str_ext(EPL_ASND_SDO_COMMAND_READ_MULTIPLE_PARAMETER_BY_INDEX,
4697 				&epl_sdo_asnd_commands_short_ext, "Command(%02X)"),
4698 				segment_size);
4699 
4700 		remlength = (guint32)tvb_reported_length_remaining(tvb, offset);
4701 		objectcnt = 0;
4702 
4703 		/* As long as no lastentry has been detected, and we have still bytes left,
4704 		 * we start the loop. lastentry is probably not necessary anymore, since
4705 		 * we now use length_remaining, but it is kept to be on the safe side. */
4706 		while ( !lastentry && remlength > 0 )
4707 		{
4708 			guint16 sod_index = error;
4709 
4710 			offsetincrement = tvb_get_letohl(tvb, offset);
4711 
4712 			/* the data is aligned in 4-byte increments, therefor maximum padding is 3 */
4713 			padding = tvb_get_guint8 ( tvb, offset + 7 ) & 0x03;
4714 
4715 			if ((tvb_get_guint8 ( tvb, offset + 7 ) & 0x80) == 0x80)
4716 				is_abort = TRUE;
4717 
4718 			 /* An offset increment of zero usually indicates, that we are at the end
4719 			  * of the payload. But we cannot ignore the end, because packages are
4720 			  * stacked up until the last byte */
4721 			if (offsetincrement == 0)
4722 			{
4723 				datalength = segment_restsize;
4724 				lastentry = TRUE;
4725 			}
4726 			else
4727 			{
4728 				datalength = offsetincrement - (offset - EPL_SOA_EPLV_OFFSET);
4729 			}
4730 			/* decrease restsize */
4731 			segment_restsize -= datalength;
4732 
4733 			/* Possible guint overflow */
4734 			if (datalength > remlength)
4735 				break;
4736 
4737 			/* Each entry has a header size of 8, based on the following calculation:
4738 			*   - 4 byte for byte position of next data set
4739 			*   - 2 byte for index
4740 			*   - 1 byte for subindex
4741 			*   - 1 byte for reserved and padding */
4742 
4743 			/* Guarding against readout of padding. Probability is nearly zero, as
4744 			 * padding was checked above, but to be sure, this remains here */
4745 			if ((guint32)(padding + 8) >= datalength)
4746 				break;
4747 
4748 			/* size of data is datalength - ( entry header size and padding ) */
4749 			size = datalength - 8 - padding;
4750 
4751 			dataoffset = offset + 4;
4752 
4753 			/* add object subtree */
4754 			psf_od_tree = proto_tree_add_subtree(epl_tree, tvb, offset+4, 4+size, 0, NULL , "OD");
4755 
4756 			if (segmented <= EPL_ASND_SDO_CMD_SEGMENTATION_INITIATE_TRANSFER)
4757 			{
4758 				/* get SDO index value */
4759 				idx = tvb_get_letohs(tvb, dataoffset);
4760 				obj = object_lookup(convo->profile, idx);
4761 				if (!obj)
4762 				{
4763 					/* value to string */
4764 					index_str = rval_to_str_const(idx, sod_cmd_str, "unknown");
4765 					/* get index string value */
4766 					sod_index = str_to_val(index_str, sod_cmd_str_val, error);
4767 					/* get subindex string */
4768 					sub_index_str = val_to_str_ext_const(idx, &sod_cmd_no_sub, "unknown");
4769 					/* get subindex string value*/
4770 					nosub = str_to_val(sub_index_str, sod_cmd_str_no_sub, 0xFF) != 0xFF;
4771 				}
4772 				/* add index item */
4773 				psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_index, tvb, offset+4, 2, ENC_LITTLE_ENDIAN);
4774 
4775 				if(obj)
4776 				{
4777 					proto_item_append_text(psf_item, " (%s)", obj->info.name);
4778 					nosub = obj->info.type_class == OD_ENTRY_SCALAR;
4779 				}
4780 				else if(sod_index == error)
4781 				{
4782 					proto_item_append_text(psf_item," (%s)", val_to_str_ext_const(((guint32)(idx<<16)), &sod_index_names, "User Defined"));
4783 				}
4784 				else
4785 				{
4786 					/* add index string */
4787 					proto_item_append_text(psf_item," (%s", val_to_str_ext_const(((guint32)(sod_index<<16)), &sod_index_names, "User Defined"));
4788 					proto_item_append_text(psf_item,"_%02Xh", (idx-sod_index));
4789 					if(sod_index == EPL_SOD_PDO_RX_MAPP || sod_index == EPL_SOD_PDO_TX_MAPP)
4790 					{
4791 						proto_item_append_text(psf_item,"_AU64)");
4792 					}
4793 					else
4794 					{
4795 						proto_item_append_text(psf_item,"_REC)");
4796 					}
4797 				}
4798 
4799 				if (objectcnt < 8)
4800 					col_append_fstr(pinfo->cinfo, COL_INFO, " (0x%04X", idx);
4801 				else
4802 					col_append_str(pinfo->cinfo, COL_INFO, ".");
4803 
4804 				if (sod_index != error)
4805 					idx = sod_index;
4806 
4807 				proto_item_append_text(psf_od_tree, " Idx: 0x%04X", idx);
4808 
4809 				dataoffset += 2;
4810 
4811 				/* get subindex offset */
4812 				subindex = tvb_get_guint8(tvb, dataoffset);
4813 				subobj = subobject_lookup(obj, subindex);
4814 				proto_item_append_text(psf_od_tree, " SubIdx: 0x%02X", subindex);
4815 				/* get subindex string */
4816 				sub_str = val_to_str_ext_const(idx, &sod_cmd_sub_str, "unknown");
4817 				/* get string value */
4818 				sub_val = str_to_val(sub_str, sod_cmd_sub_str_val,error);
4819 
4820 				if(sub_val != error)
4821 					idx = sub_val;
4822 
4823 				if (subobj)
4824 				{
4825 					psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, dataoffset, 1, ENC_LITTLE_ENDIAN);
4826 					proto_item_append_text(psf_item, " (%s)", subobj->info.name);
4827 				}
4828 				/* if the subindex is a EPL_SOD_STORE_PARAM */
4829 				else if(idx == EPL_SOD_STORE_PARAM && subindex <= 0x7F && subindex >= 0x04)
4830 				{
4831 					psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, dataoffset, 1, ENC_LITTLE_ENDIAN);
4832 					proto_item_append_text(psf_item, " (ManufacturerParam_%02Xh_U32)", subindex);
4833 				}
4834 				/* if the subindex is a EPL_SOD_RESTORE_PARAM */
4835 				else if(idx == EPL_SOD_RESTORE_PARAM && subindex <= 0x7F && subindex >= 0x04)
4836 				{
4837 					psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, dataoffset, 1, ENC_LITTLE_ENDIAN);
4838 					proto_item_append_text(psf_item, " (ManufacturerParam_%02Xh_U32)", subindex);
4839 				}
4840 				/* if the subindex is a EPL_SOD_PDO_RX_MAPP */
4841 				else if(idx == EPL_SOD_PDO_RX_MAPP && subindex >= 0x01 && subindex <= 0xfe)
4842 				{
4843 					psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, dataoffset, 1, ENC_LITTLE_ENDIAN);
4844 					proto_item_append_text(psf_item, " (ObjectMapping)");
4845 				}
4846 				/* if the subindex is a EPL_SOD_PDO_TX_MAPP */
4847 				else if(idx == EPL_SOD_PDO_TX_MAPP && subindex >= 0x01 && subindex <= 0xfe)
4848 				{
4849 					psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, dataoffset, 1, ENC_LITTLE_ENDIAN);
4850 					proto_item_append_text(psf_item, " (ObjectMapping)");
4851 				}
4852 				else if(subindex == 0x00)
4853 				{
4854 					psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, dataoffset, 1, ENC_LITTLE_ENDIAN);
4855 					proto_item_append_text(psf_item, " (NumberOfEntries)");
4856 				}
4857 				/* subindex */
4858 				else
4859 				{
4860 					psf_item = proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, dataoffset, 1, ENC_LITTLE_ENDIAN);
4861 					proto_item_append_text(psf_item, " (%s)", val_to_str_ext_const((subindex | (idx << 16)), &sod_index_names, "User Defined"));
4862 				}
4863 
4864 				/* info text */
4865 				if (objectcnt < 8)
4866 				{
4867 					if (nosub)
4868 						/* no subindex */
4869 						col_append_fstr(pinfo->cinfo, COL_INFO, ")");
4870 					else
4871 						col_append_fstr(pinfo->cinfo, COL_INFO, "/%d)", subindex);
4872 				}
4873 
4874 
4875 				dataoffset += 1;
4876 				proto_tree_add_uint(psf_od_tree, hf_epl_asnd_sdo_cmd_data_padding, tvb, dataoffset, 1, padding);
4877 				dataoffset += 1;
4878 				objectcnt++;
4879 			}
4880 
4881 
4882 			if (is_abort)
4883 			{
4884 				proto_tree_add_item(psf_od_tree, hf_epl_asnd_sdo_cmd_sub_abort, tvb, dataoffset - 1, 1, ENC_LITTLE_ENDIAN);
4885 
4886 				abort_code = tvb_get_letohl(tvb, dataoffset);
4887 
4888 				proto_item_append_text(psf_od_tree, " - %s", "Aborted");
4889 
4890 				psf_item = proto_tree_add_item(psf_od_tree, hf_epl_sdo_multi_param_sub_abort, tvb, dataoffset, 4, ENC_LITTLE_ENDIAN);
4891 				proto_item_append_text(psf_item," (%s)", val_to_str_ext_const(abort_code, &sdo_cmd_abort_code_ext, "Unknown"));
4892 
4893 				is_abort = FALSE;
4894 			}
4895 			else
4896 			{
4897 				/* if the frame is a PDO Mapping and the subindex is bigger than 0x00 */
4898 				if((idx == EPL_SOD_PDO_TX_MAPP && subindex > 0x00) ||(idx == EPL_SOD_PDO_RX_MAPP && subindex > 0x00))
4899 				{
4900 					psf_item = proto_tree_add_item(epl_tree, hf_epl_asnd_sdo_cmd_data_mapping, tvb, dataoffset, 1, ENC_NA);
4901 					psf_tree = proto_item_add_subtree(psf_item, ett_epl_asnd_sdo_cmd_data_mapping);
4902 					idx = tvb_get_letohs(tvb, dataoffset);
4903 					proto_tree_add_uint_format(psf_tree, hf_epl_asnd_sdo_cmd_data_mapping_index, tvb, dataoffset, 2, idx,"Index: 0x%04X", idx);
4904 					dataoffset += 2;
4905 					idx = tvb_get_letohs(tvb, dataoffset);
4906 					proto_tree_add_uint_format(psf_tree, hf_epl_asnd_sdo_cmd_data_mapping_subindex, tvb, dataoffset, 1, idx,"SubIndex: 0x%02X", idx);
4907 					dataoffset += 2;
4908 					idx = tvb_get_letohs(tvb, dataoffset);
4909 					proto_tree_add_uint_format(psf_tree, hf_epl_asnd_sdo_cmd_data_mapping_offset, tvb, dataoffset, 2, idx,"Offset: 0x%04X", idx);
4910 					dataoffset += 2;
4911 					proto_tree_add_item(psf_tree, hf_epl_asnd_sdo_cmd_data_mapping_length, tvb, dataoffset, 2, ENC_LITTLE_ENDIAN);
4912 				}
4913 				else
4914 				{
4915 					/* dissect the payload */
4916 					const struct epl_datatype *type = NULL;
4917 					if (subobj)
4918 						type = subobj->info.type;
4919 					else if (obj)
4920 						type = obj->info.type;
4921 
4922 					dissect_epl_payload ( psf_od_tree, tvb, pinfo, dataoffset, size, type, EPL_ASND);
4923 				}
4924 			}
4925 
4926 			offset += datalength;
4927 
4928 			/* calculating the remaining length, based on the current offset */
4929 			remlength = (guint32)tvb_reported_length_remaining(tvb, offset);
4930 		}
4931 
4932 		col_append_fstr(pinfo->cinfo, COL_INFO, " (%d)", objectcnt);
4933 	}
4934 	else
4935 	{
4936 		col_append_fstr(pinfo->cinfo, COL_INFO, "Request %s[%d]:",
4937 				val_to_str_ext(EPL_ASND_SDO_COMMAND_READ_MULTIPLE_PARAMETER_BY_INDEX,
4938 				&epl_sdo_asnd_commands_short_ext, "Command(%02X)"),
4939 				segment_size);
4940 
4941 		remlength = (guint32)tvb_reported_length_remaining(tvb, offset);
4942 		objectcnt = 0;
4943 
4944 		dataoffset = offset;
4945 
4946 		/* As long as no lastentry has been detected, and we have still bytes left,
4947 		 * we start the loop. */
4948 		while ( remlength > 0 )
4949 		{
4950 			guint16 sod_index = error;
4951 			proto_tree *psf_entry;
4952 			/* add object subtree */
4953 			psf_od_item = proto_tree_add_subtree(epl_tree, tvb, offset, 4, 0, NULL, "OD");
4954 
4955 			if (segmented <= EPL_ASND_SDO_CMD_SEGMENTATION_INITIATE_TRANSFER)
4956 			{
4957 				/* get SDO index value */
4958 				idx = tvb_get_letohs(tvb, dataoffset);
4959 				obj = object_lookup(convo->profile, idx);
4960 				if (!obj)
4961 				{
4962 					/* value to string */
4963 					index_str = rval_to_str_const(idx, sod_cmd_str, "unknown");
4964 					/* get index string value */
4965 					sod_index = str_to_val(index_str, sod_cmd_str_val, error);
4966 					/* get subindex string */
4967 					sub_index_str = val_to_str_ext_const(idx, &sod_cmd_no_sub, "unknown");
4968 					/* get subindex string value*/
4969 					nosub = str_to_val(sub_index_str, sod_cmd_str_no_sub,0xFF) != 0xFF;
4970 				}
4971 
4972 				if (objectcnt < 8)
4973 					col_append_fstr(pinfo->cinfo, COL_INFO, " (0x%04X", idx);
4974 				else
4975 					col_append_str(pinfo->cinfo, COL_INFO, ".");
4976 
4977 				if (sod_index != error)
4978 					idx = sod_index;
4979 
4980 				proto_item_append_text(psf_od_item, " Idx: 0x%04X", idx);
4981 				psf_entry = proto_tree_add_uint_format(psf_od_item, hf_epl_asnd_sdo_cmd_data_mapping_index, tvb, dataoffset, 2, idx,"Index: 0x%04X", idx);
4982 
4983 				if(obj)
4984 				{
4985 					proto_item_append_text(psf_entry, " (%s)", obj->info.name);
4986 					nosub = obj->info.type_class == OD_ENTRY_SCALAR;
4987 				}
4988 				else if(sod_index == error)
4989 				{
4990 					name = val_to_str_ext_const(((guint32)(idx<<16)), &sod_index_names, "User Defined");
4991 					proto_item_append_text(psf_entry," (%s)", name);
4992 				}
4993 				else
4994 				{
4995 					/* add index string */
4996 					proto_item_append_text(psf_entry," (%s", val_to_str_ext_const(((guint32)(sod_index<<16)), &sod_index_names, "User Defined"));
4997 					proto_item_append_text(psf_entry,"_%02Xh", (idx-sod_index));
4998 					if(sod_index == EPL_SOD_PDO_RX_MAPP || sod_index == EPL_SOD_PDO_TX_MAPP)
4999 					{
5000 						proto_item_append_text(psf_entry,"_AU64)");
5001 					}
5002 					else
5003 					{
5004 						proto_item_append_text(psf_entry,"_REC)");
5005 					}
5006 				}
5007 
5008 
5009 				dataoffset += 2;
5010 
5011 				/* get subindex offset */
5012 				subindex = tvb_get_guint8(tvb, dataoffset);
5013 				proto_item_append_text(psf_od_item, " SubIdx: 0x%02X", subindex);
5014 				psf_item = proto_tree_add_uint_format(psf_od_item, hf_epl_asnd_sdo_cmd_data_mapping_subindex, tvb, dataoffset, 1, subindex,"SubIndex: 0x%02X", subindex);
5015 				subobj = subobject_lookup(obj, subindex);
5016 				name = subobj ? subobj->info.name
5017 					      : val_to_str_ext_const((subindex|(idx<<16)), &sod_index_names, "User Defined");
5018 				proto_item_append_text(psf_item, " (%s)", name);
5019 
5020 				/* info text */
5021 				if (objectcnt < 8)
5022 				{
5023 					if (nosub)
5024 						/* no subindex */
5025 						col_append_fstr(pinfo->cinfo, COL_INFO, ")");
5026 					else
5027 						col_append_fstr(pinfo->cinfo, COL_INFO, "/%d)", subindex);
5028 				}
5029 
5030 
5031 				dataoffset += 2;
5032 				objectcnt++;
5033 			}
5034 
5035 			/* each sub request is 4 bytes */
5036 			offset += 4;
5037 
5038 			/* calculating the remaining length, based on the current offset */
5039 			remlength = (guint32)tvb_reported_length_remaining(tvb, offset);
5040 		}
5041 
5042 		col_append_fstr(pinfo->cinfo, COL_INFO, " (%d)", objectcnt);
5043 	}
5044 	return offset;
5045 }
5046 
5047 static gint
5048 dissect_epl_sdo_command_read_by_index(struct epl_convo *convo, proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, guint8 segmented, gboolean response, guint16 segment_size)
5049 {
5050 	gint size, payload_length, rem_size = 0;
5051 	guint16 idx = 0x00;
5052 	guint8 subindex = 0x00;
5053 	guint32 fragmentId, frame;
5054 	proto_item *psf_item, *cmd_payload;
5055 	proto_tree *payload_tree;
5056 	gboolean end_segment = FALSE;
5057 	fragment_head *frag_msg = NULL;
5058 	struct object *obj = NULL;
5059 	const struct subobject *subobj = NULL;
5060 	struct read_req *req;
5061 	const struct epl_datatype *type = NULL;
5062 
5063 	/* get the current frame number */
5064 	frame = pinfo->num;
5065 
5066 	if (!response)
5067 	{   /* request */
5068 		const char *name;
5069 		idx = tvb_get_letohs(tvb, offset);
5070 		psf_item = proto_tree_add_item(epl_tree, hf_epl_asnd_sdo_cmd_data_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
5071 		obj = object_lookup(convo->profile, idx);
5072 
5073 		name = obj ? obj->info.name : val_to_str_ext_const(((guint32)(idx<<16)), &sod_index_names, "User Defined");
5074 		proto_item_append_text(psf_item," (%s)", name);
5075 		offset += 2;
5076 
5077 
5078 		subindex = tvb_get_guint8(tvb, offset);
5079 		psf_item = proto_tree_add_item(epl_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, offset, 1, ENC_LITTLE_ENDIAN);
5080 		subobj = subobject_lookup(obj, subindex);
5081 
5082 		name = subobj ? subobj->info.name
5083 		              : val_to_str_ext_const((subindex|(idx<<16)), &sod_index_names, "User Defined");
5084 		proto_item_append_text(psf_item, " (%s)", name);
5085 
5086 		offset += 1;
5087 
5088 		col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%d]: (0x%04X/%d)",
5089 						 val_to_str_ext(EPL_ASND_SDO_COMMAND_READ_BY_INDEX, &epl_sdo_asnd_commands_short_ext, "Command(%02X)"),
5090 						 segment_size, idx, subindex);
5091 		col_append_fstr(pinfo->cinfo, COL_INFO, " (%s", val_to_str_ext_const(((guint32) (idx << 16)), &sod_index_names, "User Defined"));
5092 		col_append_fstr(pinfo->cinfo, COL_INFO, "/%s)",val_to_str_ext_const((subindex|(idx<<16)), &sod_index_names, "User Defined"));
5093 
5094 		/* Cache object for read in next response */
5095 		req = convo_read_req_set(convo, convo->seq_send);
5096 		req->idx = idx;
5097 		req->subindex = subindex;
5098 		if (obj)
5099 		{
5100 			req->info = subobj ? &subobj->info : &obj->info;
5101 			req->index_name = obj->info.name;
5102 		}
5103 		else
5104 		{
5105 			req->info = NULL;
5106 			req->index_name = NULL;
5107 		}
5108 	}
5109 	else
5110 	{
5111 		/* upload and no response */
5112 		if(segmented > 0x01 && segment_size != 0)
5113 		{
5114 			/* get the fragmentId */
5115 			fragmentId = (guint32)((((guint32)epl_segmentation.src)<<16)+epl_segmentation.dest);
5116 			/* set the fragmented flag */
5117 			pinfo->fragmented = TRUE;
5118 			/* get payloade size */
5119 			payload_length = tvb_reported_length_remaining(tvb, offset);
5120 			/* if the frame is the last frame */
5121 			if(segmented == EPL_ASND_SDO_CMD_SEGMENTATION_TRANSFER_COMPLETE)
5122 				end_segment = TRUE;
5123 
5124 			if(epl_asnd_sdo_reassembly_read.frame[epl_segmentation.recv][epl_segmentation.send] == 0x00 ||
5125 				epl_asnd_sdo_reassembly_read.frame[epl_segmentation.recv][epl_segmentation.send] == frame)
5126 			{
5127 				if (epl_asnd_sdo_reassembly_read.frame[epl_segmentation.recv][epl_segmentation.send] == 0x00)
5128 					count += 1;
5129 				/* store the current frame and increase the counter */
5130 				epl_asnd_sdo_reassembly_read.frame[epl_segmentation.recv][epl_segmentation.send] = frame;
5131 
5132 				/* add the frame to reassembly_table */
5133 				if (first_read)
5134 				{
5135 					frag_msg = fragment_add_seq_check(&epl_reassembly_table, tvb, offset, pinfo,
5136 							fragmentId, NULL, 0, payload_length, end_segment ? FALSE : TRUE );
5137 					fragment_add_seq_offset(&epl_reassembly_table, pinfo, fragmentId, NULL, count);
5138 
5139 					first_read = FALSE;
5140 				}
5141 				else
5142 				{
5143 					frag_msg = fragment_add_seq_check(&epl_reassembly_table, tvb, offset, pinfo,
5144 							fragmentId, NULL, count, payload_length, end_segment ? FALSE : TRUE );
5145 				}
5146 			}
5147 
5148 			/* if the reassembly_table is not Null and the frame stored is the same as the current frame */
5149 			if(frag_msg != NULL && (epl_asnd_sdo_reassembly_read.frame[epl_segmentation.recv][epl_segmentation.send] == frame))
5150 			{
5151 				if(end_segment || payload_length > 0)
5152 				{
5153 					cmd_payload = proto_tree_add_uint_format(epl_tree, hf_epl_asnd_sdo_cmd_reassembled, tvb, offset, payload_length,0,
5154 															"Reassembled: %d bytes total (%d bytes in this frame)",frag_msg->len,payload_length);
5155 					payload_tree = proto_item_add_subtree(cmd_payload, ett_epl_asnd_sdo_data_reassembled);
5156 					/* add the reassembley fields */
5157 					process_reassembled_data(tvb, 0, pinfo, "Reassembled Message", frag_msg, &epl_frag_items, NULL, payload_tree );
5158 					proto_tree_add_uint_format_value(payload_tree, hf_epl_asnd_sdo_cmd_reassembled, tvb, 0, 0,
5159 									payload_length, "%d bytes (over all fragments)", frag_msg->len);
5160 					if (frag_msg->reassembled_in == frame)
5161 						col_append_str(pinfo->cinfo, COL_INFO, " (Message Reassembled)" );
5162 					/* reset memory */
5163 					memset(&epl_asnd_sdo_reassembly_read.frame[epl_segmentation.recv], 0, sizeof(guint32) * EPL_MAX_SEQUENCE);
5164 				}
5165 				else
5166 				{
5167 					cmd_payload = proto_tree_add_uint_format(epl_tree, hf_epl_asnd_sdo_cmd_reassembled, tvb, offset, payload_length,0,
5168 															"Reassembled: %d bytes total (%d bytes in this frame)",frag_msg->len,payload_length);
5169 					payload_tree = proto_item_add_subtree(cmd_payload, ett_epl_asnd_sdo_data_reassembled);
5170 					/* add reassemble field => Reassembled in: */
5171 					process_reassembled_data(tvb, 0, pinfo, "Reassembled Message", frag_msg, &epl_frag_items, NULL, payload_tree );
5172 				}
5173 				count = 0;
5174 			}
5175 		}
5176 		/* response */
5177 		col_append_str(pinfo->cinfo, COL_INFO, "Response");
5178 
5179 		size = tvb_reported_length_remaining(tvb, offset);
5180 
5181 		/* Did we register the read req? */
5182 
5183 		if ((req = convo_read_req_get(convo, pinfo, convo->seq_send)))
5184 		{
5185 			proto_item *ti;
5186 			ti = proto_tree_add_uint_format_value(epl_tree, hf_epl_asnd_sdo_cmd_data_index, tvb, 0, 0, req->idx, "%04X", req->idx);
5187 			proto_item_set_generated(ti);
5188 			if (req->info)
5189 			{
5190 				proto_item_append_text (ti, " (%s)", req->index_name);
5191 				type = req->info->type;
5192 			}
5193 
5194 			ti = proto_tree_add_uint_format_value(epl_tree, hf_epl_asnd_sdo_cmd_data_subindex, tvb, 0, 0, req->subindex, "%02X", req->subindex);
5195 			proto_item_set_generated(ti);
5196 
5197 			if (req->info && req->info->name != req->index_name)
5198 				proto_item_append_text (ti, " (%s)", req->info->name);
5199 
5200 		}
5201 
5202 		/* determine remaining SDO payload size (depends on segment size of current command) */
5203 		if (size > segment_size)
5204 		{
5205 			rem_size = segment_size;
5206 		}
5207 		else
5208 		{
5209 			rem_size = size;
5210 		}
5211 
5212 		offset = dissect_epl_payload(epl_tree, tvb, pinfo, offset, rem_size, type, EPL_ASND);
5213 	}
5214 
5215 	return offset;
5216 }
5217 
5218 static struct profile *profile_load(wmem_allocator_t *allocator, const char *path)
5219 {
5220 	struct profile *profile = NULL;
5221 	char *err;
5222 	if (!epl_profile_uat_fld_fileopen_check_cb(NULL, path, (unsigned)strlen(path), NULL, NULL, &err))
5223 	{
5224 		report_failure("%s", err);
5225 		g_free(err);
5226 		return NULL;
5227 	}
5228 
5229 	if (g_str_has_suffix(path, ".eds"))
5230 	{
5231 		profile = profile_new(allocator);
5232 		if (!epl_eds_load(profile, path))
5233 			profile_del(profile);
5234 	}
5235 #if HAVE_LIBXML2
5236 	else if (g_str_has_suffix(path, ".xdd") || g_str_has_suffix(path, ".xdc"))
5237 	{
5238 		profile = profile_new(allocator);
5239 		if (!epl_xdd_load(profile, path))
5240 			profile_del(profile);
5241 	}
5242 #endif
5243 	if (!profile)
5244 		report_failure("Profile '%s' couldn't be parsed", path);
5245 
5246 	return profile;
5247 }
5248 
5249 static void apply_prefs(void)
5250 {
5251 	/* This gets called for all preferences, so we only load profile if path changes */
5252 	if (epl_default_profile_path != epl_default_profile_path_last
5253 	&& epl_default_profile_path && *epl_default_profile_path)
5254 	{
5255 		profile_del(epl_default_profile);
5256 		epl_default_profile = profile_load(wmem_epan_scope(), epl_default_profile_path);
5257 
5258 		epl_default_profile_path_last = epl_default_profile_path;
5259 		/* TODO we could use something like UAT_AFFECTS_DISSECTION */
5260 	}
5261 }
5262 
5263 
5264 /* Register the protocol with Wireshark */
5265 void
5266 proto_register_epl(void)
5267 {
5268 	static hf_register_info hf[] = {
5269 		/* Common data fields (same for all message types) */
5270 		{ &hf_epl_mtyp,
5271 			{ "MessageType", "epl.mtyp",
5272 				FT_UINT8, BASE_DEC, VALS(mtyp_vals), 0x7F, NULL, HFILL }
5273 		},
5274 		{ &hf_epl_node,
5275 			{ "Node", "epl.node",
5276 				FT_UINT8, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }
5277 		},
5278 		{ &hf_epl_dest,
5279 			{ "Destination", "epl.dest",
5280 				FT_UINT8, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }
5281 		},
5282 		{ &hf_epl_src,
5283 			{ "Source", "epl.src",
5284 				FT_UINT8, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }
5285 		},
5286 		{ &hf_epl_payload_real,
5287 			{ "Captured Size", "epl.payload.capture_size",
5288 				FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
5289 		},
5290 
5291 		/* hotfields for all available EPL message types (depends on EPL MessageType) */
5292 		{ &hf_epl_soc,
5293 			{ "SoC", "epl.soc",
5294 				FT_BOOLEAN, BASE_DEC, NULL, 0x00, NULL, HFILL }
5295 		},
5296 		{ &hf_epl_preq,
5297 			{ "PReq", "epl.preq",
5298 				FT_BOOLEAN, BASE_DEC, NULL, 0x00, NULL, HFILL }
5299 		},
5300 		{ &hf_epl_pres,
5301 			{ "PRes", "epl.pres",
5302 				FT_BOOLEAN, BASE_DEC, NULL, 0x00, NULL, HFILL }
5303 		},
5304 		{ &hf_epl_soa,
5305 			{ "SoA", "epl.soa",
5306 				FT_BOOLEAN, BASE_DEC, NULL, 0x00, NULL, HFILL }
5307 		},
5308 		{ &hf_epl_asnd,
5309 			{ "ASnd", "epl.asnd",
5310 				FT_BOOLEAN, BASE_DEC, NULL, 0x00, NULL, HFILL }
5311 		},
5312 		{ &hf_epl_amni,
5313 			{ "AMNI", "epl.amni",
5314 				FT_BOOLEAN, BASE_DEC, NULL, 0x00, NULL, HFILL }
5315 		},
5316 		{ &hf_epl_ainv,
5317 			{ "AInv", "epl.ainv",
5318 				FT_BOOLEAN, BASE_DEC, NULL, 0x00, NULL, HFILL }
5319 		},
5320 
5321 		/* SoC data fields*/
5322 		{ &hf_epl_soc_flags,
5323 			{ "Flags", "epl.soc.flags",
5324 				FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
5325 		},
5326 		{ &hf_epl_soc_mc,
5327 			{ "MC (Multiplexed Cycle Completed)", "epl.soc.mc",
5328 				FT_BOOLEAN, 8, NULL, EPL_SOC_MC_MASK, NULL, HFILL }
5329 		},
5330 		{ &hf_epl_soc_ps,
5331 			{ "PS (Prescaled Slot)", "epl.soc.ps",
5332 				FT_BOOLEAN, 8, NULL, EPL_SOC_PS_MASK, NULL, HFILL }
5333 		},
5334 		{ &hf_epl_soc_dna_an,
5335 			{ "AN (Global)", "epl.soc.an",
5336 				FT_BOOLEAN, 8, NULL, EPL_SOC_AN_MASK, NULL, HFILL }
5337 		},
5338 		{ &hf_epl_soc_nettime,
5339 			{ "NetTime", "epl.soc.nettime",
5340 				FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }
5341 		},
5342 		{ &hf_epl_soc_relativetime,
5343 			{ "RelativeTime", "epl.soc.relativetime",
5344 				FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
5345 		},
5346 
5347 		/* PReq data fields*/
5348 		{ &hf_epl_preq_flags,
5349 			{ "Flags", "epl.preq.flags",
5350 				FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
5351 		},
5352 		{ &hf_epl_preq_ms,
5353 			{ "MS (Multiplexed Slot)", "epl.preq.ms",
5354 				FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }
5355 		},
5356 		{ &hf_epl_preq_ea,
5357 			{ "EA (Exception Acknowledge)", "epl.preq.ea",
5358 				FT_BOOLEAN, 8, NULL, EPL_PDO_EA_MASK, NULL, HFILL }
5359 		},
5360 		{ &hf_epl_preq_rd,
5361 			{ "RD (Ready)", "epl.preq.rd",
5362 				FT_BOOLEAN, 8, NULL, EPL_PDO_RD_MASK, NULL, HFILL }
5363 		},
5364 		{ &hf_epl_preq_sls,
5365 			{ "SLS (Second Link Status)", "epl.preq.sls",
5366 				FT_BOOLEAN, 8, NULL, EPL_PDO_SLS_MASK, NULL, HFILL }
5367 		},
5368 		{ &hf_epl_preq_fls,
5369 			{ "FLS (First Link Status)", "epl.preq.fls",
5370 				FT_BOOLEAN, 8, NULL, EPL_PDO_FLS_MASK, NULL, HFILL }
5371 		},
5372 		{ &hf_epl_preq_pdov,
5373 			{ "PDOVersion", "epl.preq.pdov",
5374 				FT_UINT8, BASE_CUSTOM, CF_FUNC(elp_version), 0x00, NULL, HFILL }
5375 		},
5376 		{ &hf_epl_preq_size,
5377 			{ "Size", "epl.preq.size",
5378 				FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
5379 		},
5380 
5381 		/* PRes data fields*/
5382 		{ &hf_epl_pres_stat_ms,
5383 			{ "NMTStatus", "epl.pres.stat",
5384 				FT_UINT8, BASE_HEX, VALS(epl_nmt_ms_vals), 0x00, NULL, HFILL }
5385 		},
5386 		{ &hf_epl_pres_stat_cs,
5387 			{ "NMTStatus", "epl.pres.stat",
5388 				FT_UINT8, BASE_HEX, VALS(epl_nmt_cs_vals), 0x00, NULL, HFILL }
5389 		},
5390 		{ &hf_epl_pres_flags,
5391 			{ "Flags", "epl.pres.flags",
5392 				FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
5393 		},
5394 		{ &hf_epl_pres_ms,
5395 			{ "MS (Multiplexed Slot)", "epl.pres.ms",
5396 				FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }
5397 		},
5398 		{ &hf_epl_pres_en,
5399 			{ "EN (Exception New)", "epl.pres.en",
5400 				FT_BOOLEAN, 8, NULL, EPL_PDO_EN_MASK, NULL, HFILL }
5401 		},
5402 		{ &hf_epl_pres_rd,
5403 			{ "RD (Ready)", "epl.pres.rd",
5404 				FT_BOOLEAN, 8, NULL, EPL_PDO_RD_MASK, NULL, HFILL }
5405 		},
5406 		{ &hf_epl_pres_pr,
5407 			{ "PR (Priority)", "epl.pres.pr",
5408 				FT_UINT8, BASE_DEC, VALS(epl_pr_vals), 0x38, NULL, HFILL }
5409 		},
5410 		{ &hf_epl_pres_rs,
5411 			{ "RS (RequestToSend)", "epl.pres.rs",
5412 				FT_UINT8, BASE_DEC, NULL, EPL_PDO_RS_MASK, NULL, HFILL }
5413 		},
5414 		{ &hf_epl_pres_sls,
5415 			{ "SLS (Second Link Status)", "epl.pres.sls",
5416 				FT_BOOLEAN, 8, NULL, EPL_PDO_SLS_MASK, NULL, HFILL }
5417 		},
5418 		{ &hf_epl_pres_fls,
5419 			{ "FLS (First Link Status)", "epl.pres.fls",
5420 				FT_BOOLEAN, 8, NULL, EPL_PDO_FLS_MASK, NULL, HFILL }
5421 		},
5422 		{ &hf_epl_pres_pdov,
5423 			{ "PDOVersion", "epl.pres.pdov",
5424 				FT_UINT8, BASE_CUSTOM, CF_FUNC(elp_version), 0x00, NULL, HFILL }
5425 		},
5426 		{ &hf_epl_pres_size,
5427 			{ "Size", "epl.pres.size",
5428 				FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
5429 		},
5430 
5431 		/* SoA data fields*/
5432 		{ &hf_epl_soa_stat_ms,
5433 			{ "NMTStatus", "epl.soa.stat",
5434 				FT_UINT8, BASE_HEX, VALS(epl_nmt_ms_vals), 0x00, NULL, HFILL }
5435 		},
5436 		{ &hf_epl_soa_stat_cs,
5437 			{ "NMTStatus", "epl.soa.stat",
5438 				FT_UINT8, BASE_HEX, VALS(epl_nmt_cs_vals), 0x00, NULL, HFILL }
5439 		},
5440 		{ &hf_epl_soa_ea,
5441 			{ "EA (Exception Acknowledge)", "epl.soa.ea",
5442 				FT_BOOLEAN, 8, NULL, EPL_SOA_EA_MASK, NULL, HFILL }
5443 		},
5444 		{ &hf_epl_soa_er,
5445 			{ "ER (Exception Reset)", "epl.soa.er",
5446 				FT_BOOLEAN, 8, NULL, EPL_SOA_ER_MASK, NULL, HFILL }
5447 		},
5448 		{ &hf_epl_soa_svid,
5449 			{ "RequestedServiceID", "epl.soa.svid",
5450 				FT_UINT8, BASE_DEC|BASE_RANGE_STRING, RVALS(soa_svid_vals), 0x00, NULL, HFILL }
5451 		},
5452 		{ &hf_epl_soa_svtg,
5453 			{ "RequestedServiceTarget", "epl.soa.svtg",
5454 				FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL }
5455 		},
5456 		{ &hf_epl_soa_eplv,
5457 			{ "EPLVersion", "epl.soa.eplv",
5458 				FT_UINT8, BASE_CUSTOM, CF_FUNC(elp_version), 0x00, NULL, HFILL }
5459 		},
5460 		{ &hf_epl_soa_rrflags,
5461 			{ "RedundancyFlags", "epl.soa.rrFlags",
5462 				FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL }
5463 		},
5464 		{ &hf_epl_soa_rrflags_mnred,
5465 			{ "MR - MN Redundancy", "epl.soa.rrFlags.mnred",
5466 				FT_BOOLEAN, 8, TFS(&tfs_active_inactive), 0x01, NULL, HFILL }
5467 		},
5468 		{ &hf_epl_soa_rrflags_cblred,
5469 			{ "CR - Cable Redundancy", "epl.soa.rrFlags.cblred",
5470 				FT_BOOLEAN, 8, TFS(&tfs_active_inactive), 0x02, NULL, HFILL }
5471 		},
5472 		{ &hf_epl_soa_rrflags_ringred,
5473 			{ "RR - Ring Redundancy", "epl.soa.rrFlags.ringred",
5474 				FT_BOOLEAN, 8, TFS(&tfs_active_inactive), 0x04, NULL, HFILL }
5475 		},
5476 		{ &hf_epl_soa_rrflags_ringstat,
5477 			{ "RR - Ring Status", "epl.soa.rrFlags.ringstat",
5478 				FT_BOOLEAN, 8, TFS(&tfs_open_closed), 0x08, NULL, HFILL }
5479 		},
5480 		{ &hf_epl_soa_sync,
5481 			{ "SyncControl", "epl.soa.sync",
5482 				FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL }
5483 		},
5484 		{ &hf_epl_soa_mac,
5485 			{ "DestMacAddressValid", "epl.soa.adva",
5486 				FT_BOOLEAN, 8, NULL, EPL_SOA_SYNC_MAC_VALID, NULL, HFILL }
5487 		},
5488 
5489 		{ &hf_epl_soa_pre_tm,
5490 			{ "PResFallBackTimeoutValid", "epl.soa.tm",
5491 				FT_BOOLEAN, 8, NULL, EPL_SOA_SYNC_PRES_TIMEOUT, NULL, HFILL }
5492 		},
5493 		{ &hf_epl_soa_mnd_sec,
5494 			{ "SyncMNDelaySecondValid", "epl.soa.mnsc",
5495 				FT_BOOLEAN, 8, NULL, EPL_SOA_SYNC_MND_SECOND, NULL, HFILL }
5496 		},
5497 		{ &hf_epl_soa_mnd_fst,
5498 			{ "SyncMNDelayFirstValid", "epl.soa.mnft",
5499 				FT_BOOLEAN, 8, NULL, EPL_SOA_SYNC_MND_FIRST, NULL, HFILL }
5500 		},
5501 		{ &hf_epl_soa_pre_sec,
5502 			{ "PResTimeSecondValid", "epl.soa.prsc",
5503 				FT_BOOLEAN, 8, NULL, EPL_SOA_SYNC_PRES_SECOND, NULL, HFILL }
5504 		},
5505 		{ &hf_epl_soa_pre_fst,
5506 			{ "PResTimeFirstValid", "epl.soa.prft",
5507 				FT_BOOLEAN, 8, NULL, EPL_SOA_SYNC_PRES_FIRST, NULL, HFILL }
5508 		},
5509 		{ &hf_epl_soa_pre_set ,
5510 			{ "PResModeSet", "epl.soa.prmst",
5511 				FT_BOOLEAN, 8, NULL, EPL_SOA_SYNC_PRES_SET, NULL, HFILL }
5512 		},
5513 		{ &hf_epl_soa_pre_res,
5514 			{ "PResModeReset", "epl.soa.prmrst",
5515 				FT_BOOLEAN, 8, NULL, EPL_SOA_SYNC_PRES_RESET, NULL, HFILL }
5516 		},
5517 		{ &hf_epl_soa_mac_end,
5518 			{ "DestMacAddress", "epl.soa.adva.end",
5519 				FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL }
5520 		},
5521 		{ &hf_epl_soa_pre_tm_end,
5522 			{ "PResFallBackTimeoutValid", "epl.soa.tm.end",
5523 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
5524 		},
5525 		{ &hf_epl_soa_mnd_sec_end,
5526 			{ "SyncMNDelaySecondValid", "epl.soa.mnsc.end",
5527 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
5528 		},
5529 		{ &hf_epl_soa_mnd_fst_end,
5530 			{ "SyncMNDelayFirstValid", "epl.soa.mnft.end",
5531 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
5532 		},
5533 		{ &hf_epl_soa_pre_sec_end,
5534 			{ "PResTimeSecondValid", "epl.soa.prsc.end",
5535 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
5536 		},
5537 		{ &hf_epl_soa_pre_fst_end,
5538 			{ "PResTimeFirstValid", "epl.soa.prft.end",
5539 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
5540 		},
5541 		{ &hf_epl_soa_dna_an_glb,
5542 			{ "AN (Global)", "epl.soa.an.global",
5543 				FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }
5544 		},
5545 		{ &hf_epl_soa_dna_an_lcl,
5546 			{ "AN (Local)", "epl.soa.an.local",
5547 				FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }
5548 		},
5549 		/* ASnd header */
5550 		{ &hf_epl_asnd_svid,
5551 			{ "Requested Service ID", "epl.asnd.svid",
5552 				FT_UINT8, BASE_HEX|BASE_RANGE_STRING, RVALS(asnd_svid_vals), 0x00, NULL, HFILL }
5553 		},
5554 		{ &hf_epl_asnd_svtg,
5555 			{ "Requested Service Target", "epl.asnd.svtg",
5556 				FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL }
5557 		},
5558 #if 0
5559 		{ &hf_epl_asnd_data,
5560 			{ "Data", "epl.asnd.data",
5561 				FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
5562 		},
5563 #endif
5564 
5565 		/* ASnd-->IdentResponse */
5566 		{ &hf_epl_asnd_identresponse_en,
5567 			{ "EN (Exception New)", "epl.asnd.ires.en",
5568 				FT_BOOLEAN, 8, NULL, EPL_ASND_EN_MASK, NULL, HFILL }
5569 		},
5570 		{ &hf_epl_asnd_identresponse_ec,
5571 			{ "EC (Exception Clear)", "epl.asnd.ires.ec",
5572 				FT_BOOLEAN, 8, NULL, EPL_ASND_EC_MASK, NULL, HFILL }
5573 		},
5574 		{ &hf_epl_asnd_identresponse_pr,
5575 			{ "PR (Priority)", "epl.asnd.ires.pr",
5576 				FT_UINT8, BASE_DEC, VALS(epl_pr_vals), 0x38, NULL, HFILL }
5577 		},
5578 		{ &hf_epl_asnd_identresponse_rs,
5579 			{ "RS (RequestToSend)", "epl.asnd.ires.rs",
5580 				FT_UINT8, BASE_DEC, NULL, EPL_ASND_RS_MASK, NULL, HFILL }
5581 		},
5582 		{ &hf_epl_asnd_identresponse_sls,
5583 			{ "SLS (Second Link Status)", "epl.asnd.ires.sls",
5584 				FT_BOOLEAN, 8, NULL, EPL_ASND_SLS_MASK, NULL, HFILL }
5585 		},
5586 		{ &hf_epl_asnd_identresponse_fls,
5587 			{ "FLS (First Link Status)", "epl.asnd.ires.fls",
5588 				FT_BOOLEAN, 8, NULL, EPL_ASND_FLS_MASK, NULL, HFILL }
5589 		},
5590 		{ &hf_epl_asnd_identresponse_stat_ms,
5591 			{ "NMTStatus", "epl.asnd.ires.state",
5592 				FT_UINT8, BASE_HEX, VALS(epl_nmt_ms_vals), 0x00, NULL, HFILL }
5593 		},
5594 		{ &hf_epl_asnd_identresponse_stat_cs,
5595 			{ "NMTStatus", "epl.asnd.ires.state",
5596 				FT_UINT8, BASE_HEX, VALS(epl_nmt_cs_vals), 0x00, NULL, HFILL }
5597 		},
5598 		{ &hf_epl_asnd_identresponse_ever,
5599 			{ "EPLVersion", "epl.asnd.ires.eplver",
5600 				FT_UINT8, BASE_CUSTOM, CF_FUNC(elp_version), 0x00, NULL, HFILL }
5601 		},
5602 		{ &hf_epl_asnd_identresponse_feat,
5603 			{ "FeatureFlags", "epl.asnd.ires.features",
5604 				FT_UINT32, BASE_HEX, NULL, 0x00, NULL, HFILL }
5605 		},
5606 		{ &hf_epl_asnd_identresponse_feat_bit0,
5607 			{ "Isochronous", "epl.asnd.ires.features.bit0",
5608 				FT_BOOLEAN, 32, NULL, 0x0001, NULL, HFILL }
5609 		},
5610 		{ &hf_epl_asnd_identresponse_feat_bit1,
5611 			{ "SDO by UDP/IP", "epl.asnd.ires.features.bit1",
5612 				FT_BOOLEAN, 32, NULL, 0x0002, NULL, HFILL }
5613 		},
5614 		{ &hf_epl_asnd_identresponse_feat_bit2,
5615 			{ "SDO by ASnd", "epl.asnd.ires.features.bit2",
5616 				FT_BOOLEAN, 32, NULL, 0x0004, NULL, HFILL }
5617 		},
5618 		{ &hf_epl_asnd_identresponse_feat_bit3,
5619 			{ "SDO by PDO", "epl.asnd.ires.features.bit3",
5620 				FT_BOOLEAN, 32, NULL, 0x0008, NULL, HFILL }
5621 		},
5622 		{ &hf_epl_asnd_identresponse_feat_bit4,
5623 			{ "NMT Info Services", "epl.asnd.ires.features.bit4",
5624 				FT_BOOLEAN, 32, NULL, 0x0010, NULL, HFILL }
5625 		},
5626 		{ &hf_epl_asnd_identresponse_feat_bit5,
5627 			{ "Ext. NMT State Commands", "epl.asnd.ires.features.bit5",
5628 				FT_BOOLEAN, 32, NULL, 0x0020, NULL, HFILL }
5629 		},
5630 		{ &hf_epl_asnd_identresponse_feat_bit6,
5631 			{ "Dynamic PDO Mapping", "epl.asnd.ires.features.bit6",
5632 				FT_BOOLEAN, 32, NULL, 0x0040, NULL, HFILL }
5633 		},
5634 		{ &hf_epl_asnd_identresponse_feat_bit7,
5635 			{ "NMT Service by UDP/IP", "epl.asnd.ires.features.bit7",
5636 				FT_BOOLEAN, 32, NULL, 0x0080, NULL, HFILL }
5637 		},
5638 		{ &hf_epl_asnd_identresponse_feat_bit8,
5639 			{ "Configuration Manager", "epl.asnd.ires.features.bit8",
5640 				FT_BOOLEAN, 32, NULL, 0x0100, NULL, HFILL }
5641 		},
5642 		{ &hf_epl_asnd_identresponse_feat_bit9,
5643 			{ "Multiplexed Access", "epl.asnd.ires.features.bit9",
5644 				FT_BOOLEAN, 32, NULL, 0x0200, NULL, HFILL }
5645 		},
5646 		{ &hf_epl_asnd_identresponse_feat_bitA,
5647 			{ "NodeID setup by SW", "epl.asnd.ires.features.bitA",
5648 				FT_BOOLEAN, 32, NULL, 0x0400, NULL, HFILL }
5649 		},
5650 		{ &hf_epl_asnd_identresponse_feat_bitB,
5651 			{ "MN Basic Ethernet Mode", "epl.asnd.ires.features.bitB",
5652 				FT_BOOLEAN, 32, NULL, 0x0800, NULL, HFILL }
5653 		},
5654 		{ &hf_epl_asnd_identresponse_feat_bitC,
5655 			{ "Routing Type 1 Support", "epl.asnd.ires.features.bitC",
5656 				FT_BOOLEAN, 32, NULL, 0x1000, NULL, HFILL }
5657 		},
5658 		{ &hf_epl_asnd_identresponse_feat_bitD,
5659 			{ "Routing Type 2 Support", "epl.asnd.ires.features.bitD",
5660 				FT_BOOLEAN, 32, NULL, 0x2000, NULL, HFILL }
5661 		},
5662 		{ &hf_epl_asnd_identresponse_feat_bitE,
5663 			{ "SDO Read/Write All", "epl.asnd.ires.features.bitE",
5664 				FT_BOOLEAN, 32, NULL, 0x4000, NULL, HFILL }
5665 		},
5666 		{ &hf_epl_asnd_identresponse_feat_bitF,
5667 			{ "SDO Read/Write Multiple", "epl.asnd.ires.features.bitF",
5668 				FT_BOOLEAN, 32, NULL, 0x8000, NULL, HFILL }
5669 		},
5670 		{ &hf_epl_asnd_identresponse_feat_bit10,
5671 			{ "Multiple-ASend Support", "epl.asnd.ires.features.bit10",
5672 				FT_BOOLEAN, 32, NULL, 0x010000, NULL, HFILL }
5673 		},
5674 		{ &hf_epl_asnd_identresponse_feat_bit11,
5675 			{ "Ring Redundancy", "epl.asnd.ires.features.bit11",
5676 				FT_BOOLEAN, 32, NULL, 0x020000, NULL, HFILL }
5677 		},
5678 		{ &hf_epl_asnd_identresponse_feat_bit12,
5679 			{ "PResChaining", "epl.asnd.ires.features.bit12",
5680 				FT_BOOLEAN, 32, NULL, 0x040000, NULL, HFILL }
5681 		},
5682 		{ &hf_epl_asnd_identresponse_feat_bit13,
5683 			{ "Multiple PReq/PRes", "epl.asnd.ires.features.bit13",
5684 				FT_BOOLEAN, 32, NULL, 0x080000, NULL, HFILL }
5685 		},
5686 		{ &hf_epl_asnd_identresponse_feat_bit14,
5687 			{ "Dynamic Node Allocation", "epl.asnd.ires.features.bit14",
5688 				FT_BOOLEAN, 32, NULL, 0x100000, NULL, HFILL }
5689 		},
5690 		{ &hf_epl_asnd_identresponse_feat_bit21,
5691 			{ "Modular Device", "epl.asnd.ires.features.bit21",
5692 				FT_BOOLEAN, 32, NULL, 0x00200000, NULL, HFILL }
5693 		},
5694 		{ &hf_epl_asnd_identresponse_mtu,
5695 			{ "MTU", "epl.asnd.ires.mtu",
5696 				FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
5697 		},
5698 		{ &hf_epl_asnd_identresponse_pis,
5699 			{ "PollInSize", "epl.asnd.ires.pollinsize",
5700 				FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
5701 		},
5702 		{ &hf_epl_asnd_identresponse_pos,
5703 			{ "PollOutSize", "epl.asnd.ires.polloutsizes",
5704 				FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
5705 		},
5706 		{ &hf_epl_asnd_identresponse_rst,
5707 			{ "ResponseTime", "epl.asnd.ires.resptime",
5708 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
5709 		},
5710 		{ &hf_epl_asnd_identresponse_dt,
5711 			{ "DeviceType", "epl.asnd.ires.devicetype",
5712 				FT_UINT16, BASE_HEX, NULL, 0x00, NULL, HFILL }
5713 		},
5714 		{ &hf_epl_asnd_identresponse_dt_add,
5715 			{ "DeviceType additional info", "epl.asnd.ires.devicetype.add",
5716 				FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
5717 		},
5718 		{ &hf_epl_asnd_identresponse_profile_path,
5719 			{ "Profile Path", "epl.asnd.ires.profilepath",
5720 				FT_STRING, STR_UNICODE, NULL, 0x00, NULL, HFILL }
5721 		},
5722 		{ &hf_epl_asnd_identresponse_vid,
5723 			{ "VendorId", "epl.asnd.ires.vendorid",
5724 				FT_UINT32, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }
5725 		},
5726 		{ &hf_epl_asnd_identresponse_productcode,
5727 			{ "ProductCode", "epl.asnd.ires.productcode",
5728 				FT_UINT32, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }
5729 		},
5730 		{ &hf_epl_asnd_identresponse_rno,
5731 			{ "RevisionNumber", "epl.asnd.ires.revisionno",
5732 				FT_UINT32, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }
5733 		},
5734 		{ &hf_epl_asnd_identresponse_sno,
5735 			{ "SerialNumber", "epl.asnd.ires.serialno",
5736 				FT_UINT32, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }
5737 		},
5738 		{ &hf_epl_asnd_identresponse_vex1,
5739 			{ "VendorSpecificExtension1", "epl.asnd.ires.vendorext1",
5740 				FT_UINT64, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }
5741 		},
5742 		{ &hf_epl_asnd_identresponse_vcd,
5743 			{ "VerifyConfigurationDate", "epl.asnd.ires.confdate",
5744 				FT_UINT32, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }
5745 		},
5746 		{ &hf_epl_asnd_identresponse_vct,
5747 			{ "VerifyConfigurationTime", "epl.asnd.ires.conftime",
5748 				FT_UINT32, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }
5749 		},
5750 		{ &hf_epl_asnd_identresponse_ad,
5751 			{ "ApplicationSwDate", "epl.asnd.ires.appswdate",
5752 				FT_UINT32, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }
5753 		},
5754 		{ &hf_epl_asnd_identresponse_at,
5755 			{ "ApplicationSwTime", "epl.asnd.ires.appswtime",
5756 				FT_UINT32, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }
5757 		},
5758 		{ &hf_epl_asnd_identresponse_ipa,
5759 			{ "IPAddress", "epl.asnd.ires.ip",
5760 				FT_IPv4, BASE_NONE, NULL, 0x00, NULL, HFILL }
5761 		},
5762 		{ &hf_epl_asnd_identresponse_snm,
5763 			{ "SubnetMask", "epl.asnd.ires.subnet",
5764 				FT_IPv4, BASE_NETMASK, NULL, 0x00, NULL, HFILL }
5765 		},
5766 		{ &hf_epl_asnd_identresponse_gtw,
5767 			{ "DefaultGateway", "epl.asnd.ires.gateway",
5768 				FT_IPv4, BASE_NONE, NULL, 0x00, NULL, HFILL }
5769 		},
5770 		{ &hf_epl_asnd_identresponse_hn,
5771 			{ "HostName", "epl.asnd.ires.hostname",
5772 				FT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }
5773 		},
5774 		{ &hf_epl_asnd_identresponse_vex2,
5775 			{ "VendorSpecificExtension2", "epl.asnd.ires.vendorext2",
5776 				FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
5777 		},
5778 
5779 		/* ASnd-->StatusResponse */
5780 		{ &hf_epl_asnd_statusresponse_en,
5781 			{ "EN (Exception New)", "epl.asnd.sres.en",
5782 				FT_BOOLEAN, 8, NULL, EPL_ASND_EN_MASK, NULL, HFILL }
5783 		},
5784 		{ &hf_epl_asnd_statusresponse_ec,
5785 			{ "EC (Exception Clear)", "epl.asnd.sres.ec",
5786 				FT_BOOLEAN, 8, NULL, EPL_ASND_EC_MASK, NULL, HFILL }
5787 		},
5788 		{ &hf_epl_asnd_statusresponse_pr,
5789 			{ "PR (Priority)", "epl.asnd.sres.pr",
5790 				FT_UINT8, BASE_DEC, VALS(epl_pr_vals), 0x38, NULL, HFILL }
5791 		},
5792 		{ &hf_epl_asnd_statusresponse_rs,
5793 			{ "RS (RequestToSend)", "epl.asnd.sres.rs",
5794 				FT_UINT8, BASE_DEC, NULL, EPL_ASND_RS_MASK, NULL, HFILL }
5795 		},
5796 		{ &hf_epl_asnd_statusresponse_sls,
5797 			{ "SLS (Second Link Status)", "epl.asnd.sres.sls",
5798 				FT_BOOLEAN, 8, NULL, EPL_ASND_SLS_MASK, NULL, HFILL }
5799 		},
5800 		{ &hf_epl_asnd_statusresponse_fls,
5801 			{ "FLS (First Link Status)", "epl.asnd.sres.fls",
5802 				FT_BOOLEAN, 8, NULL, EPL_ASND_FLS_MASK, NULL, HFILL }
5803 		},
5804 		{ &hf_epl_asnd_statusresponse_stat_ms,
5805 			{ "NMTStatus", "epl.asnd.sres.stat",
5806 				FT_UINT8, BASE_HEX, VALS(epl_nmt_ms_vals), 0x00, NULL, HFILL }
5807 		},
5808 		{ &hf_epl_asnd_statusresponse_stat_cs,
5809 			{ "NMTStatus", "epl.asnd.sres.stat",
5810 				FT_UINT8, BASE_HEX, VALS(epl_nmt_cs_vals), 0x00, NULL, HFILL }
5811 		},
5812 		/* ASnd-->SyncResponse */
5813 		{ &hf_epl_asnd_syncResponse_sync,
5814 			{ "SyncResponse", "epl.asnd.syncresponse.sync",
5815 				FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL }
5816 		},
5817 		{ &hf_epl_asnd_syncResponse_fst_val,
5818 			{ "PResTimeFirstValid", "epl.asnd.syncresponse.fst.val",
5819 				FT_BOOLEAN, 8, NULL, EPL_ASND_SYNCRESPONSE_FST_VALID, NULL, HFILL }
5820 		},
5821 		{ &hf_epl_asnd_syncResponse_sec_val,
5822 			{ "PResTimeSecondValid", "epl.asnd.syncresponse.sec.val",
5823 				FT_BOOLEAN, 8, NULL, EPL_ASND_SYNCRESPONSE_SEC_VALID, NULL, HFILL }
5824 		},
5825 		{ &hf_epl_asnd_syncResponse_mode,
5826 			{ "PResModeStatus", "epl.asnd.syncresponse.mode",
5827 				FT_BOOLEAN, 8, NULL, EPL_ASND_SYNCRESPONSE_MODE, NULL, HFILL }
5828 		},
5829 		{ &hf_epl_asnd_syncResponse_latency,
5830 			{ "Latency", "epl.asnd.syncresponse.latency",
5831 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
5832 		},
5833 		{ &hf_epl_asnd_syncResponse_node,
5834 			{ "SyncDelayStation", "epl.asnd.syncresponse.delay.station",
5835 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
5836 		},
5837 		{ &hf_epl_asnd_syncResponse_delay,
5838 			{ "SyncDelay", "epl.asnd.syncresponse.delay",
5839 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
5840 		},
5841 		{ &hf_epl_asnd_syncResponse_pre_fst,
5842 			{ "PResTimeFirst", "epl.asnd.syncresponse.pres.fst",
5843 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
5844 		},
5845 		{ &hf_epl_asnd_syncResponse_pre_sec,
5846 			{ "PResTimeSecond", "epl.asnd.syncresponse.pres.sec",
5847 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
5848 		},
5849 #if 0
5850 		{ &hf_epl_asnd_statusresponse_seb,
5851 			{ "StaticErrorBitField", "epl.asnd.sres.seb",
5852 				FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
5853 		},
5854 #endif
5855 
5856 		/*StaticErrorBitField */
5857 		{ &hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit0,
5858 			{ "Generic error", "epl.asnd.res.seb.bit0",
5859 				FT_UINT8, BASE_DEC, NULL, 0x01, NULL, HFILL }
5860 		},
5861 		{ &hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit1,
5862 			{ "Current", "epl.asnd.res.seb.bit1",
5863 				FT_UINT8, BASE_DEC, NULL, 0x02, NULL, HFILL }
5864 		},
5865 		{ &hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit2,
5866 			{ "Voltage", "epl.asnd.res.seb.bit2",
5867 				FT_UINT8, BASE_DEC, NULL, 0x04, NULL, HFILL }
5868 		},
5869 		{ &hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit3,
5870 			{ "Temperature", "epl.asnd.res.seb.bit3",
5871 				FT_UINT8, BASE_DEC, NULL, 0x08, NULL, HFILL }
5872 		},
5873 		{ &hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit4,
5874 			{ "Communication error", "epl.asnd.res.seb.bit4",
5875 				FT_UINT8, BASE_DEC, NULL, 0x10, NULL, HFILL }
5876 		},
5877 		{ &hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit5,
5878 			{ "Device Profile Spec", "epl.asnd.res.seb.bit5",
5879 				FT_UINT8, BASE_DEC, NULL, 0x20, NULL, HFILL }
5880 		},
5881 		{ &hf_epl_asnd_statusresponse_seb_err_errorregister_u8_bit7,
5882 			{ "Manufacturer Spec", "epl.asnd.res.seb.bit7",
5883 				FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL }
5884 		},
5885 		{ &hf_epl_asnd_statusresponse_seb_devicespecific_err,
5886 			{ "Device Profile Spec", "epl.asnd.res.seb.devicespecific_err",
5887 				FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
5888 		},
5889 
5890 #if 0
5891 		{ &hf_epl_asnd_statusresponse_el,
5892 			{ "ErrorCodesList", "epl.asnd.sres.el",
5893 				FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
5894 		},
5895 		{ &hf_epl_asnd_statusresponse_el_entry,
5896 			{ "Entry", "epl.asnd.sres.el.entry",
5897 				FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
5898 		},
5899 #endif
5900 
5901 		/*List of Errors/Events*/
5902 		{ &hf_epl_asnd_statusresponse_el_entry_type,
5903 			{ "Entry Type", "epl.asnd.sres.el.entry.type",
5904 				FT_UINT16, BASE_HEX, NULL, 0x00, NULL, HFILL }
5905 		},
5906 		{ &hf_epl_asnd_statusresponse_el_entry_type_profile,
5907 			{ "Profile", "epl.asnd.sres.el.entry.type.profile",
5908 				FT_UINT16, BASE_DEC, NULL, 0x0FFF, NULL, HFILL }
5909 		},
5910 		{ &hf_epl_asnd_statusresponse_el_entry_type_mode,
5911 			{ "Mode", "epl.asnd.sres.el.entry.type.mode",
5912 				FT_UINT16, BASE_DEC, NULL, 0x3000, NULL, HFILL }
5913 		},
5914 		{ &hf_epl_asnd_statusresponse_el_entry_type_bit14,
5915 			{ "Bit14", "epl.asnd.sres.el.entry.type.bit14",
5916 				FT_UINT16, BASE_DEC, NULL, 0x4000, NULL, HFILL }
5917 		},
5918 		{ &hf_epl_asnd_statusresponse_el_entry_type_bit15,
5919 			{ "Bit15", "epl.asnd.sres.el.entry.type.bit15",
5920 				FT_UINT16, BASE_DEC, NULL, 0x8000, NULL, HFILL }
5921 		},
5922 		{ &hf_epl_asnd_statusresponse_el_entry_code,
5923 			{ "Error Code", "epl.asnd.sres.el.entry.code",
5924 				FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
5925 		},
5926 		{ &hf_epl_asnd_statusresponse_el_entry_time,
5927 			{ "Time Stamp", "epl.asnd.sres.el.entry.time",
5928 				FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00, NULL, HFILL }
5929 		},
5930 		{ &hf_epl_asnd_statusresponse_el_entry_add,
5931 			{ "Additional Information", "epl.asnd.sres.el.entry.add",
5932 				FT_UINT64, BASE_DEC, NULL, 0x00, NULL, HFILL }
5933 		},
5934 
5935 
5936 		/* ASnd-->NMTRequest */
5937 		{ &hf_epl_asnd_nmtrequest_rcid,
5938 			{ "NMTRequestedCommandID", "epl.asnd.nmtrequest.rcid",
5939 				FT_UINT8, BASE_HEX_DEC, NULL, 0x00, NULL, HFILL }
5940 		},
5941 		{ &hf_epl_asnd_nmtrequest_rct,
5942 			{ "NMTRequestedCommandTarget", "epl.asnd.nmtrequest.rct",
5943 				FT_UINT8, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }
5944 		},
5945 		{ &hf_epl_asnd_nmtrequest_rcd,
5946 			{ "NMTRequestedCommandData", "epl.asnd.nmtrequest.rcd",
5947 				FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
5948 		},
5949 
5950 		/* ASnd-->NMTCommand */
5951 		{ &hf_epl_asnd_nmtcommand_cid,
5952 			{ "NMTCommandId", "epl.asnd.nmtcommand.cid",
5953 				FT_UINT8, BASE_HEX_DEC | BASE_EXT_STRING,
5954 				&asnd_cid_vals_ext, 0x00, NULL, HFILL }
5955 		},
5956 		{ &hf_epl_asnd_nmtcommand_resetnode_reason,
5957 			{ "Reset Reason", "epl.asnd.nmtcommand.resetnode_reason",
5958 				FT_UINT16, BASE_HEX | BASE_EXT_STRING,
5959 				&errorcode_vals_ext, 0x00, NULL, HFILL }
5960 		},
5961 		{ &hf_epl_asnd_nmtcommand_cdat,
5962 			{ "NMTCommandData", "epl.asnd.nmtcommand.cdat",
5963 				FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
5964 		},
5965 
5966 		{ &hf_epl_asnd_nmtcommand_nmtnethostnameset_hn,
5967 			{ "HostName", "epl.asnd.nmtcommand.nmtnethostnameset.hn",
5968 				FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
5969 		},
5970 		{ &hf_epl_asnd_nmtcommand_nmtflusharpentry_nid,
5971 			{ "NodeID", "epl.asnd.nmtcommand.nmtflusharpentry.nid",
5972 				FT_UINT8, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }
5973 		},
5974 		{ &hf_epl_asnd_nmtcommand_nmtpublishtime_dt,
5975 			{ "DateTime", "epl.asnd.nmtcommand.nmtpublishtime.dt",
5976 				FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
5977 		},
5978 		{ &hf_epl_asnd_nmtcommand_nmtdna,
5979 			{ "DNA", "epl.asnd.nmtcommand.dna",
5980 				FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
5981 		},
5982 		{ &hf_epl_asnd_nmtcommand_nmtdna_flags,
5983 			{ "Valid flags", "epl.asnd.nmtcommand.dna.flags",
5984 				FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
5985 		},
5986 		{ &hf_epl_asnd_nmtcommand_nmtdna_ltv,
5987 			{ "Lease time valid", "epl.asnd.nmtcommand.dna.ltv",
5988 				FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }
5989 		},
5990 		{ &hf_epl_asnd_nmtcommand_nmtdna_hpm,
5991 			{ "Hub port enable mask valid", "epl.asnd.nmtcommand.dna.hpm",
5992 				FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }
5993 		},
5994 		{ &hf_epl_asnd_nmtcommand_nmtdna_nnn,
5995 			{ "Set new node number", "epl.asnd.nmtcommand.dna.nnn",
5996 				FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }
5997 		},
5998 		{ &hf_epl_asnd_nmtcommand_nmtdna_mac,
5999 			{ "Compare current MAC ID", "epl.asnd.nmtcommand.dna.mac",
6000 				FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }
6001 		},
6002 		{ &hf_epl_asnd_nmtcommand_nmtdna_cnn,
6003 			{ "Compare current node number", "epl.asnd.nmtcommand.dna.cnn",
6004 				FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }
6005 		},
6006 		{ &hf_epl_asnd_nmtcommand_nmtdna_currmac,
6007 			{ "Current MAC ID", "epl.asnd.nmtcommand.dna.currmac",
6008 				FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL }
6009 		},
6010 		{ &hf_epl_asnd_nmtcommand_nmtdna_hubenmsk,
6011 			{ "Hub port enable mask", "epl.asnd.nmtcommand.dna.hubenmsk",
6012 				FT_UINT64, BASE_HEX, NULL, 0x00, NULL, HFILL }
6013 		},
6014 		{ &hf_epl_asnd_nmtcommand_nmtdna_currnn,
6015 			{ "Current node number", "epl.asnd.nmtcommand.dna.currnn",
6016 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
6017 		},
6018 		{ &hf_epl_asnd_nmtcommand_nmtdna_newnn,
6019 			{ "New node number", "epl.asnd.nmtcommand.dna.newnn",
6020 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
6021 		},
6022 		{ &hf_epl_asnd_nmtcommand_nmtdna_leasetime,
6023 			{ "Lease Time", "epl.asnd.nmtcommand.dna.leasetime",
6024 				FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00, NULL, HFILL }
6025 		},
6026 
6027 		/* ASnd-->SDO */
6028 		{ &hf_epl_asnd_sdo_seq,
6029 			{ "Sequence Layer", "epl.asnd.sdo.seq",
6030 				FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }
6031 		},
6032 		{ &hf_epl_asnd_sdo_seq_receive_sequence_number,
6033 			{ "ReceiveSequenceNumber", "epl.asnd.sdo.seq.receive.sequence.number",
6034 				FT_UINT8, BASE_DEC, NULL, 0xfc, NULL, HFILL }
6035 		},
6036 		{ &hf_epl_asnd_sdo_seq_receive_con,
6037 			{ "ReceiveCon", "epl.asnd.sdo.seq.receive.con",
6038 				FT_UINT8, BASE_DEC,
6039 				VALS(epl_sdo_receive_con_vals), 0x03, NULL, HFILL }
6040 		},
6041 		{ &hf_epl_asnd_sdo_seq_send_sequence_number,
6042 			{ "SendSequenceNumber", "epl.asnd.sdo.seq.send.sequence.number",
6043 				FT_UINT8, BASE_DEC, NULL, 0xfc, NULL, HFILL }
6044 		},
6045 		{ &hf_epl_asnd_sdo_seq_send_con,
6046 			{ "SendCon", "epl.asnd.sdo.seq.send.con",
6047 				FT_UINT8, BASE_DEC, VALS(epl_sdo_send_con_vals),
6048 				0x03, NULL, HFILL }
6049 		},
6050 		{ &hf_epl_asnd_sdo_cmd_transaction_id,
6051 			{ "SDO Transaction ID", "epl.asnd.sdo.cmd.transaction.id",
6052 				FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL }
6053 		},
6054 		{ &hf_epl_asnd_sdo_cmd_response,
6055 			{ "SDO Response", "epl.asnd.sdo.cmd.response",
6056 				FT_UINT8, BASE_DEC,
6057 				VALS(epl_sdo_asnd_cmd_response), 0x80, NULL, HFILL }
6058 		},
6059 #if 0
6060 		{ &hf_epl_asnd_sdo_resp_in,
6061 			{ "Response frame", "epl.asnd.sdo.resp_in",
6062 				FT_FRAMENUM, BASE_NONE,
6063 				FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
6064 				"The frame number of the corresponding response", HFILL }
6065 		},
6066 		{ &hf_epl_asnd_sdo_no_resp,
6067 			{ "No response seen", "epl.asnd.sdo.no_resp",
6068 				FT_NONE, BASE_NONE,
6069 				NULL, 0x0,
6070 				"No corresponding response frame was seen", HFILL }
6071 		},
6072 		{ &hf_epl_asnd_sdo_resp_to,
6073 			{ "Request frame", "epl.asnd.sdo.resp_to",
6074 				FT_FRAMENUM, BASE_NONE,
6075 				FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
6076 				"The frame number of the corresponding request", HFILL }
6077 		},
6078 #endif
6079 		{ &hf_epl_asnd_sdo_cmd,
6080 			{ "Command Layer", "epl.asnd.sdo.cmd",
6081 				FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }
6082 		},
6083 		{ &hf_epl_asnd_sdo_cmd_abort,
6084 			{ "SDO Abort", "epl.asnd.sdo.cmd.abort",
6085 				FT_UINT8, BASE_DEC,
6086 				VALS(epl_sdo_asnd_cmd_abort), 0x40, NULL, HFILL }
6087 		},
6088 		{ &hf_epl_asnd_sdo_cmd_sub_abort,
6089 			{ "SDO Sub Transfer", "epl.asnd.sdo.cmd.sub.abort",
6090 				FT_UINT8, BASE_DEC,
6091 				VALS(epl_sdo_asnd_cmd_abort), 0x80, NULL, HFILL }
6092 		},
6093 		{ &hf_epl_asnd_sdo_cmd_segmentation,
6094 			{ "SDO Segmentation", "epl.asnd.sdo.cmd.segmentation",
6095 				FT_UINT8, BASE_DEC,
6096 				VALS(epl_sdo_asnd_cmd_segmentation), 0x30, NULL, HFILL }
6097 		},
6098 		{ &hf_epl_asnd_sdo_cmd_command_id,
6099 			{ "SDO Command ID", "epl.asnd.sdo.cmd.command.id",
6100 				FT_UINT8, BASE_DEC | BASE_EXT_STRING,
6101 				&epl_sdo_asnd_commands_ext, 0x00, NULL, HFILL }
6102 		},
6103 		{ &hf_epl_asnd_sdo_cmd_segment_size,
6104 			{ "SDO Segment size", "epl.asnd.sdo.cmd.segment.size",
6105 				FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
6106 		},
6107 		{ &hf_epl_asnd_sdo_cmd_data_size,
6108 			{ "SDO Data size", "epl.asnd.sdo.cmd.data.size",
6109 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
6110 		},
6111 		{ &hf_epl_asnd_sdo_cmd_data_padding,
6112 			{ "SDO Data Padding", "epl.asnd.sdo.cmd.data.padding",
6113 				FT_UINT8, BASE_DEC, NULL, 0x03, NULL, HFILL }
6114 		},
6115 		{ &hf_epl_asnd_sdo_cmd_abort_code,
6116 			{ "SDO Transfer Abort", "epl.asnd.sdo.cmd.abort.code",
6117 				FT_UINT8, BASE_HEX | BASE_EXT_STRING,
6118 				&sdo_cmd_abort_code_ext, 0x00, NULL, HFILL }
6119 		},
6120 		{ &hf_epl_asnd_sdo_cmd_data_index,
6121 			{ "OD Index", "epl.asnd.sdo.cmd.data.index",
6122 				FT_UINT16, BASE_HEX, NULL, 0x00, NULL, HFILL }
6123 		},
6124 		{ &hf_epl_asnd_sdo_cmd_data_subindex,
6125 			{ "OD SubIndex", "epl.asnd.sdo.cmd.data.subindex",
6126 				FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL }
6127 		},
6128 		{ &hf_epl_asnd_sdo_cmd_data_mapping,
6129 			{ "Mapping", "epl.asnd.sdo.cmd.data.mapping",
6130 				FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }
6131 		},
6132 		{ &hf_epl_asnd_sdo_cmd_data_mapping_index,
6133 			{ "Index", "epl.asnd.sdo.cmd.data.mapping.index",
6134 				FT_UINT16, BASE_HEX, NULL, 0x00, NULL, HFILL }
6135 		},
6136 		{ &hf_epl_asnd_sdo_cmd_data_mapping_subindex,
6137 			{ "SubIndex", "epl.asnd.sdo.cmd.data.mapping.subindex",
6138 				FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL }
6139 		},
6140 		{ &hf_epl_asnd_sdo_cmd_data_mapping_offset,
6141 			{ "Offset", "epl.asnd.sdo.cmd.data.mapping.offset",
6142 				FT_UINT16, BASE_HEX, NULL, 0x00, NULL, HFILL }
6143 		},
6144 		{ &hf_epl_asnd_sdo_cmd_data_mapping_length,
6145 			{ "Length", "epl.asnd.sdo.cmd.data.mapping.length",
6146 				FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
6147 		},
6148 		{ &hf_epl_fragments,
6149 			{ "Message fragments", "epl.asnd.sdo.cmd.fragments",
6150 				FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }
6151 		},
6152 		{ &hf_epl_fragment,
6153 			{ "Message fragment", "epl.asnd.sdo.cmd.fragment",
6154 				FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }
6155 		},
6156 		{ &hf_epl_fragment_overlap,
6157 			{ "Message fragment overlap", "epl.asnd.sdo.cmd.fragment.overlap",
6158 				FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL }
6159 		},
6160 		{ &hf_epl_fragment_overlap_conflicts,
6161 			{ "Message fragment overlapping with conflicting data",
6162 			"epl.asnd.sdo.cmd.fragment.overlap.conflicts",
6163 				FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL }
6164 		},
6165 		{ &hf_epl_fragment_multiple_tails,
6166 			{ "Message has multiple tail fragments", "epl.asnd.sdo.cmd.fragment.multiple_tails",
6167 				FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL }
6168 		},
6169 		{ &hf_epl_fragment_too_long_fragment,
6170 			{ "Message fragment too long", "epl.asnd.sdo.cmd.fragment.too_long_fragment",
6171 				FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL }
6172 		},
6173 		{ &hf_epl_fragment_error,
6174 			{ "Message defragmentation error", "epl.asnd.sdo.cmd.fragment.error",
6175 				FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }
6176 		},
6177 		{ &hf_epl_fragment_count,
6178 			{ "Message fragment count", "epl.asnd.sdo.cmd.fragment.count",
6179 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
6180 		},
6181 		{ &hf_epl_asnd_sdo_cmd_reassembled,
6182 			{ "Reassembled", "epl.asnd.sdo.cmd.reassembled",
6183 				FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL }
6184 		},
6185 		{ &hf_epl_reassembled_in,
6186 			{ "Reassembled in", "epl.asnd.sdo.cmd.reassembled.in",
6187 				FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }
6188 		},
6189 		{ &hf_epl_reassembled_length,
6190 			{ "Reassembled length", "epl.asnd.sdo.cmd.reassembled.length",
6191 				FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
6192 		},
6193 		{ &hf_epl_reassembled_data,
6194 			{ "Reassembled Data", "epl.asnd.sdo.cmd.reassembled.data",
6195 				FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
6196 		},
6197 		{ &hf_epl_sdo_multi_param_sub_abort,
6198 			{ "Sub Abort Code", "epl.asnd.sdo.od.multiparam.abort",
6199 				FT_UINT32, BASE_HEX, NULL, 0x00, NULL, HFILL }
6200 		},
6201 
6202 		/* EPL Data types */
6203 		{ &hf_epl_pdo,
6204 			{ "PDO", "epl.pdo",
6205 				FT_STRING, STR_ASCII, NULL, 0x00, NULL, HFILL }
6206 		},
6207 		{ &hf_epl_pdo_index,
6208 			{ "Index", "epl.pdo.index",
6209 				FT_UINT16, BASE_HEX, NULL, 0x00, NULL, HFILL }
6210 		},
6211 		{ &hf_epl_pdo_subindex,
6212 			{ "SubIndex", "epl.pdo.subindex",
6213 				FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL }
6214 		},
6215 		{ &hf_epl_od_meta,
6216 			{ "PDO meta info", "epl.od.meta",
6217 				FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }
6218 		},
6219 		{ &hf_epl_od_meta_mapping_index,
6220 			{ "Mapped by index", "epl.od.meta.index",
6221 				FT_UINT16, BASE_HEX, NULL, 0x00, NULL, HFILL }
6222 		},
6223 		{ &hf_epl_od_meta_mapping_subindex,
6224 			{ "Mapped by subindex", "epl.od.meta.subindex",
6225 				FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL }
6226 		},
6227 		{ &hf_epl_od_meta_lifetime_start,
6228 			{ "Lifetime start", "epl.od.meta.lifetime.start",
6229 				FT_FRAMENUM, FT_NONE, NULL, 0x00, NULL, HFILL }
6230 		},
6231 		{ &hf_epl_od_meta_lifetime_end,
6232 			{ "Lifetime end", "epl.od.meta.lifetime.end",
6233 				FT_FRAMENUM, FT_NONE, NULL, 0x00, NULL, HFILL }
6234 		},
6235 		{ &hf_epl_od_meta_offset,
6236 			{ "Offset", "epl.od.meta.offset",
6237 				FT_UINT16, BASE_HEX, NULL, 0x00, NULL, HFILL }
6238 		},
6239 		{ &hf_epl_od_meta_length,
6240 			{ "Length", "epl.od.meta.length",
6241 				FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
6242 		},
6243 		{ &hf_epl_od_boolean,
6244 			{ "Data", "epl.od.data.boolean",
6245 				FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }
6246 		},
6247 		{ &hf_epl_od_int,
6248 			{ "Data", "epl.od.data.int",
6249 				FT_INT64, BASE_DEC, NULL, 0x00, NULL, HFILL }
6250 		},
6251 		{ &hf_epl_od_uint,
6252 			{ "Data", "epl.od.data.uint",
6253 		/* We can't use BASE_DEC_HEX directly, because a FT_UINT8
6254 		 * would then have 15 leading zeroes */
6255 				FT_UINT64, BASE_DEC, NULL, 0x00, NULL, HFILL }
6256 		},
6257 		{ &hf_epl_od_real,
6258 			{ "Data", "epl.od.data.real",
6259 				FT_FLOAT, BASE_NONE, NULL, 0x00, NULL, HFILL }
6260 		},
6261 		{ &hf_epl_od_string,
6262 			{ "Data", "epl.od.data.string",
6263 				FT_STRING, STR_UNICODE, NULL, 0x00, NULL, HFILL }
6264 		},
6265 		{ &hf_epl_od_octet_string,
6266 			{ "Data", "epl.od.data.bytestring",
6267 				FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
6268 		},
6269 		{ &hf_epl_od_mac,
6270 			{ "Data", "epl.od.data.ethaddr",
6271 				FT_ETHER, BASE_NONE, NULL, 0x00, NULL, HFILL }
6272 		},
6273 		{ &hf_epl_od_ipv4,
6274 			{ "Data", "epl.od.data.ipv4",
6275 				FT_IPv4, BASE_NONE, NULL, 0x00, NULL, HFILL }
6276 		},
6277 #if 0
6278 		{ &hf_epl_od_domain,
6279 			{ "Data", "epl.od.data.domain",
6280 				FT_BYTES, BASE_ALLOW_ZERO, NULL, 0x00, NULL, HFILL }
6281 		},
6282 
6283 		{ &hf_epl_od_time_difference, /* not 1:1 */
6284 			{ "Data", "epl.od.data.time",
6285 				FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00, NULL, HFILL }
6286 		},
6287 #endif
6288 		{ &hf_epl_od_time,
6289 			{ "Data", "epl.od.data.time",
6290 				FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }
6291 		},
6292 	};
6293 
6294 	/* Setup protocol subtree array */
6295 	static gint *ett[] = {
6296 		&ett_epl,
6297 		&ett_epl_soc,
6298 		&ett_epl_preq,
6299 		&ett_epl_pres,
6300 		&ett_epl_feat,
6301 		&ett_epl_seb,
6302 		&ett_epl_el,
6303 		&ett_epl_el_entry,
6304 		&ett_epl_el_entry_type,
6305 		&ett_epl_sdo_entry_type,
6306 		&ett_epl_sdo,
6307 		&ett_epl_sdo_data,
6308 		&ett_epl_asnd_sdo_cmd_data_mapping,
6309 		&ett_epl_sdo_sequence_layer,
6310 		&ett_epl_sdo_command_layer,
6311 		&ett_epl_soa_sync,
6312 		&ett_epl_asnd_sync,
6313 		&ett_epl_fragment,
6314 		&ett_epl_fragments,
6315 		&ett_epl_asnd_sdo_data_reassembled,
6316 		&ett_epl_asnd_nmt_dna,
6317 		&ett_epl_pdo_meta
6318 	};
6319 
6320 	static ei_register_info ei[] = {
6321 		{ &ei_duplicated_frame,
6322 			{ "epl.asnd.sdo.duplication", PI_PROTOCOL, PI_NOTE,
6323 				"Duplicated Frame", EXPFILL }
6324 		},
6325 		{ &ei_recvseq_value,
6326 			{ "epl.error.value.receive.sequence", PI_PROTOCOL, PI_ERROR,
6327 				"Invalid Value for ReceiveSequenceNumber", EXPFILL }
6328 		},
6329 		{ &ei_sendseq_value,
6330 			{ "epl.error.value.send.sequence", PI_PROTOCOL, PI_ERROR,
6331 				"Invalid Value for SendSequenceNumber", EXPFILL }
6332 		},
6333 		{ &ei_real_length_differs,
6334 			{ "epl.error.payload.length.differs", PI_PROTOCOL, PI_ERROR,
6335 				"Captured length differs from header information", EXPFILL }
6336 		}
6337 	};
6338 
6339 	module_t *epl_module;
6340 	expert_module_t *expert_epl;
6341 
6342 	/* Register the protocol name and description */
6343 	proto_epl = proto_register_protocol("Ethernet POWERLINK", "EPL", "epl");
6344 
6345 	/* subdissector code */
6346 	heur_epl_subdissector_list = register_heur_dissector_list("epl", proto_epl);
6347 	heur_epl_data_subdissector_list = register_heur_dissector_list("epl_data", proto_epl);
6348 	epl_asnd_dissector_table = register_dissector_table("epl.asnd",
6349 		"Manufacturer specific ASND service", proto_epl, FT_UINT8, BASE_DEC /*, DISSECTOR_TABLE_NOT_ALLOW_DUPLICATE*/);
6350 
6351 	/* Registering protocol to be called by another dissector */
6352 	epl_handle = register_dissector("epl", dissect_epl, proto_epl);
6353 
6354 	/* Required function calls to register the header fields and subtrees used */
6355 	proto_register_field_array(proto_epl, hf, array_length(hf));
6356 
6357 	proto_register_subtree_array(ett, array_length(ett));
6358 
6359 	/* Register expert information field */
6360 	expert_epl = expert_register_protocol ( proto_epl );
6361 	expert_register_field_array ( expert_epl, ei, array_length (ei ) );
6362 
6363 	/* register preferences */
6364 	epl_module = prefs_register_protocol(proto_epl, apply_prefs);
6365 
6366 	prefs_register_bool_preference(epl_module, "show_soc_flags", "Show flags of SoC frame in Info column",
6367 		"If you are capturing in networks with multiplexed or slow nodes, this can be useful", &show_soc_flags);
6368 
6369 	prefs_register_bool_preference(epl_module, "show_duplicated_command_layer", "Show command-layer in duplicated frames",
6370 		"For analysis purposes one might want to show the command layer even if the dissector assumes a duplicated frame", &show_cmd_layer_for_duplicated);
6371 
6372 	prefs_register_bool_preference(epl_module, "show_pdo_meta_info", "Show life times and origin PDO Tx/Rx params for PDO entries",
6373 		"For analysis purposes one might want to see how long the current mapping has been active for and what OD write caused it", &show_pdo_meta_info);
6374 
6375 	prefs_register_bool_preference(epl_module, "use_sdo_mappings", "Use SDO ObjectMappings for PDO dissection",
6376 		"Partition PDOs according to ObjectMappings sent via SDO", &use_sdo_mappings);
6377 
6378 #ifdef HAVE_LIBXML2
6379 	prefs_register_bool_preference(epl_module, "use_xdc_mappings", "Use XDC ObjectMappings for PDO dissection",
6380 		"If you want to parse the defaultValue (XDD) and actualValue (XDC) attributes for ObjectMappings in order to detect default PDO mappings, which may not be sent over SDO ", &use_xdc_mappings);
6381 #endif
6382 
6383 	prefs_register_bool_preference(epl_module, "interpret_untyped_as_le", "Interpret short (<64bit) data as little endian integers",
6384 		"If a data field has untyped data under 8 byte long, interpret it as unsigned little endian integer and show decimal and hexadecimal representation thereof. Otherwise use stock data dissector", &interpret_untyped_as_le);
6385 
6386 	/* init device profiles support */
6387 	epl_profiles_by_device = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal);
6388 	epl_profiles_by_nodeid = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal);
6389 	epl_profiles_by_address = wmem_map_new(wmem_epan_scope(), epl_address_hash, epl_address_equal);
6390 
6391 	epl_eds_init();
6392 
6393 	prefs_register_filename_preference(epl_module, "default_profile", "Default Profile to use if no specific profiles exist",
6394 			"If you have a capture without IdentResponse and many nodes, it's easier to set a default profile here than to add entries for all MAC address or Node IDs",
6395 			&epl_default_profile_path, FALSE);
6396 
6397 	device_profile_uat = uat_new("Device-Specific Profiles",
6398 			sizeof (struct device_profile_uat_assoc),
6399 			"epl_device_profiles",     /* filename */
6400 			TRUE,                      /* from_profile */
6401 			&device_profile_list_uats, /* data_ptr */
6402 			&ndevice_profile_uat,      /* numitems_ptr */
6403 			UAT_AFFECTS_DISSECTION,    /* affects dissection of packets, but not set of named fields */
6404 			NULL,                      /* Help section (currently a wiki page) */
6405 			device_profile_uat_copy_cb,
6406 			device_profile_uat_update_record,
6407 			device_profile_uat_free_cb,
6408 			device_profile_parse_uat,
6409 			NULL,
6410 			device_profile_list_uats_flds);
6411 
6412 	prefs_register_uat_preference(epl_module, "device_profiles",
6413 			"Device-Specific Profiles",
6414 			"Add vendor-provided EDS" IF_LIBXML("/XDD") " profiles here",
6415 			device_profile_uat
6416 			);
6417 
6418 
6419 	nodeid_profile_uat = uat_new("NodeID-Specific Profiles",
6420 			sizeof (struct nodeid_profile_uat_assoc),
6421 			"epl_nodeid_profiles",     /* filename */
6422 			TRUE,                      /* from_profile */
6423 			&nodeid_profile_list_uats, /* data_ptr */
6424 			&nnodeid_profile_uat,      /* numitems_ptr */
6425 			UAT_AFFECTS_DISSECTION,    /* affects dissection of packets, but not set of named fields */
6426 			NULL,                      /* Help section (currently a wiki page) */
6427 			nodeid_profile_uat_copy_cb,
6428 			nodeid_profile_uat_update_record,
6429 			nodeid_profile_uat_free_cb,
6430 			nodeid_profile_parse_uat,
6431 			NULL,
6432 			nodeid_profile_list_uats_flds);
6433 
6434 	prefs_register_uat_preference(epl_module, "nodeid_profiles",
6435 			"Node-Specific Profiles",
6436 			"Assign vendor-provided EDS" IF_LIBXML("/XDD") " profiles to CN IDs here",
6437 			nodeid_profile_uat
6438 			);
6439 
6440 	/* tap-registration */
6441 	/*  epl_tap = register_tap("epl");*/
6442 }
6443 
6444 void
6445 proto_reg_handoff_epl(void)
6446 {
6447 	dissector_handle_t epl_udp_handle = create_dissector_handle(dissect_epludp, proto_epl);
6448 
6449 	dissector_add_uint("ethertype", ETHERTYPE_EPL_V2, epl_handle);
6450 	dissector_add_uint_with_preference("udp.port", UDP_PORT_EPL, epl_udp_handle);
6451         apply_prefs();
6452 
6453 	/* register frame init routine */
6454 	register_init_routine( setup_dissector );
6455 	register_cleanup_routine( cleanup_dissector );
6456 	/* register reassembly table */
6457 	reassembly_table_register(&epl_reassembly_table, &addresses_reassembly_table_functions);
6458 }
6459 
6460 
6461 static gboolean
6462 epl_uat_fld_uint16dec_check_cb(void *_record _U_, const char *str, guint len _U_, const void *chk_data _U_, const void *fld_data _U_, char **err)
6463 {
6464 	guint16 val;
6465 	if (!ws_strtou16(str, NULL, &val))
6466 	{
6467 		*err = g_strdup("Invalid argument. Expected a decimal between [0-65535]");
6468 		return FALSE;
6469 	}
6470 	return TRUE;
6471 }
6472 
6473 static gboolean
6474 epl_uat_fld_uint32hex_check_cb(void *_record _U_, const char *str, guint len _U_, const void *chk_data _U_, const void *fld_data _U_, char **err)
6475 {
6476 	guint32 val;
6477 	if (!ws_hexstrtou32(str, NULL, &val))
6478 	{
6479 		*err = g_strdup("Invalid argument. Expected a hexadecimal between [0-ffffffff]");
6480 		return FALSE;
6481 	}
6482 	return TRUE;
6483 }
6484 
6485 static gboolean
6486 epl_profile_uat_fld_fileopen_check_cb(void *record _U_, const char *path, guint len, const void *chk_data _U_, const void *fld_data _U_, char **err)
6487 {
6488 	const char *supported = "Only" IF_LIBXML(" *.xdd, *.xdc and") " *.eds profiles supported.";
6489 	ws_statb64 st;
6490 
6491 
6492 	if (!path || !len)
6493 	{
6494 		*err = g_strdup("No filename given.");
6495 		return FALSE;
6496 	}
6497 
6498 	if (ws_stat64(path, &st) != 0)
6499 	{
6500 		*err = g_strdup_printf("File '%s' does not exist or access was denied.", path);
6501 		return FALSE;
6502 	}
6503 
6504 
6505 	if (g_str_has_suffix(path, ".eds"))
6506 	{
6507 		*err = NULL;
6508 		return TRUE;
6509 	}
6510 
6511 	if (g_str_has_suffix(path, ".xdd") || g_str_has_suffix(path, ".xdc"))
6512 	{
6513 #ifdef HAVE_LIBXML2
6514 		*err = NULL;
6515 		return TRUE;
6516 #else
6517 		*err = g_strdup_printf("*.xdd and *.xdc support not compiled in. %s", supported);
6518 		return FALSE;
6519 #endif
6520 	}
6521 
6522 	*err = g_strdup(supported);
6523 	return FALSE;
6524 }
6525 
6526 
6527 static void
6528 drop_profiles(void *key _U_, void *value, void *user_data _U_)
6529 {
6530 	struct profile *head = (struct profile*)value, *curr;
6531 	while ((curr = head))
6532 	{
6533 		head = head->next;
6534 		profile_del(curr);
6535 	}
6536 }
6537 
6538 static void
6539 device_profile_parse_uat(void)
6540 {
6541 	guint i;
6542 	struct profile *profile = NULL;
6543 	wmem_map_foreach(epl_profiles_by_device, drop_profiles, NULL);
6544 
6545 	/* PDO Mappings will have stale pointers after a profile change
6546 	 * so we reset the memory pool. As PDO Mappings are refereneced
6547 	 * via Conversations, we need to fixup those too to avoid a use
6548 	 * after free, preferably by clearing them.
6549 	 * This generation++ is a temporary workaround
6550 	 */
6551 
6552 
6553 	if (pdo_mapping_scope)
6554 	{
6555 		wmem_free_all(pdo_mapping_scope);
6556 		current_convo_generation++; /* FIXME remove */
6557 	}
6558 
6559 	for (i = 0; i < ndevice_profile_uat; i++)
6560 	{
6561 		struct device_profile_uat_assoc *uat = &(device_profile_list_uats[i]);
6562 
6563 		profile = (struct profile*)wmem_map_lookup(epl_profiles_by_device, GUINT_TO_POINTER(uat->device_type));
6564 
6565 		/* do a shallow copy, we can't use the original because we need different
6566 		 * ->next pointer for each. May be we should've used Glib's non-intrusive
6567 		 * linked list to begin with
6568 		 */
6569 		if (profile)
6570 		{
6571 			struct profile *clone = wmem_new0(profile->scope, struct profile);
6572 			*clone = *profile;
6573 			profile = clone;
6574 		}
6575 
6576 		if (!profile)
6577 			profile = profile_load(wmem_epan_scope(), uat->path);
6578 
6579 		if (!profile)
6580 			continue;
6581 
6582 		struct profile *profile_head;
6583 		if ((profile_head = (struct profile*)wmem_map_lookup(epl_profiles_by_device, GUINT_TO_POINTER(profile->id))))
6584 		{
6585 			wmem_map_remove(epl_profiles_by_device, GUINT_TO_POINTER(profile_head->id));
6586 			profile->next = profile_head;
6587 		}
6588 
6589 		profile->id = uat->device_type;
6590 		profile->data = GUINT_TO_POINTER(profile->id);
6591 		profile->vendor_id = uat->vendor_id;
6592 		profile->product_code = uat->product_code;
6593 
6594 		wmem_map_insert(epl_profiles_by_device, GUINT_TO_POINTER(profile->id), profile);
6595 		profile->parent_map = epl_profiles_by_device;
6596 
6597 		ws_log(NULL, LOG_LEVEL_INFO, "Loading %s\n", profile->path);
6598 	}
6599 }
6600 
6601 static gboolean
6602 device_profile_uat_update_record(void *_record _U_, char **err _U_)
6603 {
6604 	return TRUE;
6605 }
6606 
6607 static void
6608 device_profile_uat_free_cb(void *_r)
6609 {
6610 	struct device_profile_uat_assoc *r = (struct device_profile_uat_assoc *)_r;
6611 	g_free(r->path);
6612 }
6613 
6614 static void*
6615 device_profile_uat_copy_cb(void *dst_, const void *src_, size_t len _U_)
6616 {
6617 	const struct device_profile_uat_assoc *src = (const struct device_profile_uat_assoc *)src_;
6618 	struct device_profile_uat_assoc       *dst = (struct device_profile_uat_assoc *)dst_;
6619 
6620 	dst->path        = g_strdup(src->path);
6621 	dst->device_type  = src->device_type;
6622 	dst->vendor_id    = src->vendor_id;
6623 	dst->product_code = src->product_code;
6624 
6625 	return dst;
6626 }
6627 
6628 static void
6629 nodeid_profile_parse_uat(void)
6630 {
6631 	guint i;
6632 	struct profile *profile = NULL;
6633 	wmem_map_foreach(epl_profiles_by_nodeid, drop_profiles, NULL);
6634 	wmem_map_foreach(epl_profiles_by_address, drop_profiles, NULL);
6635 
6636 
6637 	/* PDO Mappings will have stale pointers after a profile change
6638 	 * so we reset the memory pool. As PDO Mappings are refereneced
6639 	 * via Conversations, we need to fixup those too to avoid a use
6640 	 * after free, preferably by clearing them.
6641 	 * This generation++ is a temporary workaround
6642 	 */
6643 
6644 	if (pdo_mapping_scope)
6645 	{
6646 		wmem_free_all(pdo_mapping_scope);
6647 		current_convo_generation++; /* FIXME remove */
6648 	}
6649 
6650 	for (i = 0; i < nnodeid_profile_uat; i++)
6651 	{
6652 		struct nodeid_profile_uat_assoc *uat = &(nodeid_profile_list_uats[i]);
6653 
6654 		profile = uat->is_nodeid ? (struct profile*)wmem_map_lookup(epl_profiles_by_nodeid, GUINT_TO_POINTER(uat->node.id))
6655 		                         : (struct profile*)wmem_map_lookup(epl_profiles_by_address, &uat->node.addr);
6656 
6657 		if (!profile)
6658 			profile = profile_load(wmem_epan_scope(), uat->path);
6659 
6660 		if (!profile)
6661 			continue;
6662 
6663 		if (uat->is_nodeid)
6664 		{
6665 			profile->nodeid = uat->node.id;
6666 			profile->data = GUINT_TO_POINTER(profile->nodeid);
6667 
6668 			wmem_map_insert(epl_profiles_by_nodeid, GUINT_TO_POINTER(profile->nodeid), profile);
6669 			profile->parent_map = epl_profiles_by_nodeid;
6670 
6671 		}
6672 		else
6673 		{
6674 			copy_address_wmem(profile->scope, &profile->node_addr, &uat->node.addr);
6675 			profile->data = &profile->node_addr;
6676 
6677 			wmem_map_insert(epl_profiles_by_address, &profile->node_addr, profile);
6678 			profile->parent_map = epl_profiles_by_address;
6679 		}
6680 		ws_log(NULL, LOG_LEVEL_INFO, "Loading %s\n", profile->path);
6681 	}
6682 }
6683 
6684 
6685 static gboolean
6686 nodeid_profile_uat_update_record(void *_record _U_, char **err _U_)
6687 {
6688 	return TRUE;
6689 }
6690 
6691 static void
6692 nodeid_profile_uat_free_cb(void *_r)
6693 {
6694 	struct nodeid_profile_uat_assoc *r = (struct nodeid_profile_uat_assoc *)_r;
6695 	if (!r->is_nodeid)
6696 		free_address(&r->node.addr);
6697 	g_free(r->path);
6698 }
6699 
6700 static void*
6701 nodeid_profile_uat_copy_cb(void *dst_, const void *src_, size_t len _U_)
6702 {
6703 	const struct nodeid_profile_uat_assoc *src = (const struct nodeid_profile_uat_assoc *)src_;
6704 	struct nodeid_profile_uat_assoc       *dst = (struct nodeid_profile_uat_assoc *)dst_;
6705 
6706 	dst->path   = g_strdup(src->path);
6707 	dst->id_str = g_strdup(src->id_str);
6708 	if ((dst->is_nodeid = src->is_nodeid))
6709 		dst->node.id = src->node.id;
6710 	else
6711 		copy_address(&dst->node.addr, &src->node.addr);
6712 
6713 	return dst;
6714 }
6715 
6716 static void
6717 nodeid_profile_list_uats_nodeid_tostr_cb(void *_rec, char **out_ptr, unsigned *out_len, const void *u1 _U_, const void *u2 _U_)
6718 {
6719 	struct nodeid_profile_uat_assoc *rec = (struct nodeid_profile_uat_assoc*)_rec;
6720 	if (rec->id_str)
6721 	{
6722 		*out_ptr = g_strdup(rec->id_str);
6723 		*out_len = (unsigned)strlen(rec->id_str);
6724 	}
6725 	else
6726 	{
6727 		*out_ptr = g_strdup("");
6728 		*out_len = 0;
6729 	}
6730 }
6731 
6732 static gboolean
6733 epl_uat_fld_cn_check_cb(void *record _U_, const char *str, guint len _U_, const void *u1 _U_, const void *u2 _U_, char **err)
6734 {
6735 	unsigned int c;
6736 	guint8 nodeid;
6737 
6738 	if (ws_strtou8(str, NULL, &nodeid) && EPL_IS_CN_NODEID(nodeid))
6739 		return TRUE;
6740 
6741 	if (sscanf(str, "%*02x%*c%*02x%*c%*02x%*c%*02x%*c%*02x%*c%02x", &c) > 0)
6742 		return TRUE;
6743 
6744 	*err = g_strdup("Invalid argument. Expected either a CN ID [1-239] or a MAC address");
6745 	return FALSE;
6746 }
6747 
6748 static void
6749 nodeid_profile_list_uats_nodeid_set_cb(void *_rec, const char *str, unsigned len, const void *set_data _U_, const void *fld_data _U_)
6750 {
6751 	struct nodeid_profile_uat_assoc *rec = (struct nodeid_profile_uat_assoc*)_rec;
6752 	guint8 addr[6];
6753 
6754 	if (ws_strtou8(str, NULL, &addr[0]))
6755 	{
6756 		rec->is_nodeid = TRUE;
6757 		rec->node.id = addr[0];
6758 	}
6759 	else
6760 	{
6761 		unsigned i;
6762 		const char *endptr = str;
6763 		for (i = 0; i < 6; i++)
6764 		{
6765 			ws_hexstrtou8(endptr, &endptr, &addr[i]);
6766 			endptr++;
6767 		}
6768 
6769 		alloc_address_wmem(NULL, &rec->node.addr, AT_ETHER, 6, addr);
6770 		rec->is_nodeid = FALSE;
6771 	}
6772 
6773 	g_free(rec->id_str);
6774 	rec->id_str = g_strndup(str, len);
6775 }
6776 
6777 
6778 /*
6779  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
6780  *
6781  * Local variables:
6782  * c-basic-offset: 8
6783  * tab-width: 8
6784  * indent-tabs-mode: t
6785  * End:
6786  *
6787  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
6788  * :indentSize=8:tabSize=8:noTabs=false:
6789  */
6790