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