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